首页 > *nix技术, 跟踪调试 > 完全独立的串口输出代码

完全独立的串口输出代码

2012年6月20日 发表评论 阅读评论 5,146 次浏览

在内核启动的最开始,大部分设备都还没进行初始化而无法利用,但串口设备足够简单,所以下面这一段完全独立的串口输出代码对内核调试或某些特殊情况非常有益:
头文件:

/**
 * FileName: print2serial.h
 */
#ifndef _PRINT_2_SERIAL_H
#define _PRINT_2_SERIAL_H

void print2serial_init(void);
int print2serial_putc(unsigned char ch);
void print2serial_write(const char *s, unsigned n);

#endif

源文件:

/**
 * FileName: print2serial.c
 */
#include "print2serial.h"

#define DEFAULT_SERIAL_PORT 0x3f8 /* ttyS0 */
#define DEFAULT_BAUD 115200

#define XMTRDY          0x20
#define DLAB            0x80

#define TXR             0       /*  Transmit register (WRITE) */
#define RXR             0       /*  Receive register  (READ)  */
#define IER             1       /*  Interrupt Enable          */
#define IIR             2       /*  Interrupt ID              */
#define FCR             2       /*  FIFO control              */
#define LCR             3       /*  Line control              */
#define MCR             4       /*  Modem control             */
#define LSR             5       /*  Line Status               */
#define MSR             6       /*  Modem Status              */
#define DLL             0       /*  Divisor Latch Low         */
#define DLH             1       /*  Divisor latch High        */

typedef unsigned char u8;
typedef unsigned short u16;

#define cpu_relax()	asm volatile("rep; nop")

/* Basic port I/O */
static inline void outb(u8 v, u16 port)
{
	asm volatile("outb %0,%1" : : "a" (v), "dN" (port));
}

static inline u8 inb(u16 port)
{
	u8 v;
	asm volatile("inb %1,%0" : "=a" (v) : "dN" (port));
	return v;
}

void print2serial_init(void)
{
	unsigned char c;
	unsigned divisor;
	int port = DEFAULT_SERIAL_PORT;
	int baud = DEFAULT_BAUD;

	outb(0x3, port + LCR);	/* 8n1 */
	outb(0, port + IER);	/* no interrupt */
	outb(0, port + FCR);	/* no fifo */
	outb(0x3, port + MCR);	/* DTR + RTS */

	divisor	= 115200 / baud;
	c = inb(port + LCR);
	outb(c | DLAB, port + LCR);
	outb(divisor & 0xff, port + DLL);
	outb((divisor >> 8 ) & 0xff, port + DLH);
	outb(c & ~DLAB, port + LCR);

}

int print2serial_putc(unsigned char ch)
{
	unsigned timeout = 0xffff;

	while ((inb(DEFAULT_SERIAL_PORT + LSR) & XMTRDY) == 0 && --timeout)
		cpu_relax();
	outb(ch, DEFAULT_SERIAL_PORT + TXR);
	return timeout ? 0 : -1;
}

void print2serial_write(const char *s, unsigned n)
{
	while (*s && n-- > 0) {
		if (*s == '\n')
			print2serial_putc('\r');
		print2serial_putc(*s);
		s++;
	}
}

/**
static int print2serial_test(void)
{
	char tmp[10] = "123456789";

	print2serial_init();
	print2serial_write(tmp, 10);

	return 0;
}
*/

以上代码百分之百的来之linux内核源码树,仅改了一下函数名,具体是如下几个文件:
linux-2.6.38.8/arch/x86/boot/early_serial_console.c
linux-2.6.38.8/arch/x86/kernel/early_printk.c
linux-2.6.38.8/arch/x86/boot/boot.h

转载请保留地址:http://www.lenky.info/archives/2012/06/1747http://lenky.info/?p=1747


备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。

法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以Email或书面等方式告知,本站将及时删除相关内容或链接。

  1. lenky
    2012年6月21日15:28 | #1

    @flames
    记录一下点点滴滴而已 :)

  2. flames
    2012年6月20日09:50 | #2

    绝对的大牛啊,哈哈

  1. 本文目前尚无任何 trackbacks 和 pingbacks.