uclinux内核的console(2):early console

rev 0.2

快乐虾

http://blog.csdn.net/lights_joy/

[email protected]

本文适用于

ADI bf561 DSP

优视BF561EVB开发板

uclinux-2008r1.5-rc3 (smp patch)

Visual DSP++ 5.0 (update 5)

欢迎转载,但请保留作者信息

在内核启动初期,为了尽可能早地输出一些调试信息,可以在配置时选择使用early console,其选项为CONFIG_EARLY_PRINTK,然后通过earlyprintk=??传递一个参数进去。当内核检测到earlyprintk这一参数时,它将调用setup_early_printk函数初始化BF561内部的UART,然后注册一个console,这样printk的信息就可以通过串口输出。earlyprintk参数的分析参见《uclinux内核参数处理(5)earlyprintk》。

1.1 全局变量

1.1.1 bfin_serial_pops

这个全局变量用以指定对bf561内部串口进行操作的一些回调函数,其定义为:

static struct uart_ops bfin_serial_pops = {

.tx_empty = bfin_serial_tx_empty,

.set_mctrl = bfin_serial_set_mctrl,

.get_mctrl = bfin_serial_get_mctrl,

.stop_tx = bfin_serial_stop_tx,

.start_tx = bfin_serial_start_tx,

.stop_rx = bfin_serial_stop_rx,

.enable_ms = bfin_serial_enable_ms,

.break_ctl = bfin_serial_break_ctl,

.startup = bfin_serial_startup,

.shutdown = bfin_serial_shutdown,

.set_termios = bfin_serial_set_termios,

.type = bfin_serial_type,

.release_port = bfin_serial_release_port,

.request_port = bfin_serial_request_port,

.config_port = bfin_serial_config_port,

.verify_port = bfin_serial_verify_port,

};

1.1.2 bfin_serial_ports

这个全局变量的定义为:

struct bfin_serial_port bfin_serial_ports[NR_PORTS];

在这里NR_PORTS的值为1

这个全局变量的初始化由bfin_serial_init_ports函数完成,经过此函数的初始化后,此变量的值为:

struct bfin_serial_port {

struct uart_port port;

struct uart_port {

spinlock_t lock; /* port lock */

unsigned int iobase; /* in/out[bwl] */

unsigned char __iomem *membase; /*指向UART_THR(0xFFC0 0400),即UART的发送寄存器。 */

unsigned int irq; /* IRQ_UART_RX */

unsigned int uartclk; /* SCLK */

unsigned int fifosize; /* tx fifo size */

unsigned char x_char; /* xon/xoff char */

unsigned char regshift; /* reg offset shift */

unsigned char iotype; /* UPIO_MEM,以直接寄存器访问方式进行操作 */

unsigned char unused1;

unsigned int read_status_mask; /* driver specific */

unsigned int ignore_status_mask; /* driver specific */

struct uart_info *info; /* pointer to parent info */

struct uart_icount icount; /* statistics */

struct console *cons; /* struct console, if any */

upf_t flags; /* UPF_BOOT_AUTOCONF */

unsigned int mctrl; /* current modem ctrl settings */

unsigned int timeout; /* character-based timeout */

unsigned int type; /* port type */

const struct uart_ops *ops; /* 指向bfin_serial_pops */

unsigned int custom_divisor;

unsigned int line; /* 串口序号,取0 */

unsigned long mapbase; /*指向UART_THR(0xFFC0 0400),即UART的发送寄存器。 */

struct device *dev; /* parent device */

unsigned char hub6; /* this should be in the 8250 driver */

unsigned char unused[3];

void *private_data; /* generic platform data pointer */

};

unsigned int old_status;

unsigned int lsr;

#ifdef CONFIG_SERIAL_BFIN_DMA

int tx_done; /* 初始化为1 */

int tx_count; /* 初始化为0 */

struct circ_buf rx_dma_buf;

struct timer_list rx_dma_timer;

int rx_dma_nrows;

unsigned int tx_dma_channel; /* 18,即CH_UART_TX */

unsigned int rx_dma_channel; /* 17,即CH_UART_RX */

struct work_struct tx_dma_workqueue;

#endif

};

1.1.3 bfin_early_serial_console

这个就是得以使用的early console的全局变量,其定义为:

static struct __init console bfin_early_serial_console = {

.name = "early_BFuart",

.write = early_serial_write,

.device = uart_console_device,

.flags = CON_PRINTBUFFER,

.setup = bfin_serial_console_setup,

.index = -1,

.data = &bfin_serial_reg,

};

经过初始化后,flags的值将变为 CON_PRINTBUFFER | CON_BOOT

1.1.4 bfin_serial_reg

这个全局变量的定义为:

static struct uart_driver bfin_serial_reg = {

.owner = THIS_MODULE,

.driver_name = "bfin-uart",

.dev_name = BFIN_SERIAL_NAME,

.major = BFIN_SERIAL_MAJOR,

.minor = BFIN_SERIAL_MINOR,

.nr = NR_PORTS,

.cons = BFIN_SERIAL_CONSOLE,

};

1.2 初始化过程

1.2.1 setup_early_printk

当内核调用此函数时,仅仅做了一些最基本的硬件初始化工作,如CCLKEBIU等。下面看看它的实现:

int __init setup_early_printk(char *buf)

{

/* Crashing in here would be really bad, so check both the var

and the pointer before we start using it

*/

if (!buf)

return 0;

if (!*buf)

return 0;

if (early_console != NULL)

return 0;

#ifdef CONFIG_SERIAL_BFIN

/* Check for Blackfin Serial */

if (!strncmp(buf, "serial,uart", 11)) {

buf += 11;

early_console = earlyserial_init(buf);

}

#endif

#ifdef CONFIG_FB

/* TODO: add framebuffer console support */

#endif

if (likely(early_console)) {

early_console->flags |= CON_BOOT;

register_console(early_console);

printk(KERN_INFO "early printk enabled on %s%d\n",

early_console->name,

early_console->index);

}

return 0;

}

这段代码在简单判断后,有两个关键的调用。第一个是earlyserial_init,用以初始化串口的硬件参数。第二个调用是register_console,用以注册一个console结构体,同时输出printk缓冲区中的已有数据。

1.2.2 earlyserial_init

这一函数的实现为:

static struct console * __init earlyserial_init(char *buf)

{

int baud, bit;

char parity;

unsigned int serial_port = DEFAULT_PORT;

unsigned int cflag = DEFAULT_CFLAG;

serial_port = simple_strtoul(buf, &buf, 10);

buf++;

cflag = 0;

baud = simple_strtoul(buf, &buf, 10);

switch (baud) {

case 1200:

cflag |= B1200;

break;

case 2400:

cflag |= B2400;

break;

case 4800:

cflag |= B4800;

break;

case 9600:

cflag |= B9600;

break;

case 19200:

cflag |= B19200;

break;

case 38400:

cflag |= B38400;

break;

case 115200:

cflag |= B115200;

break;

default:

cflag |= B57600;

}

parity = buf[0];

buf++;

switch (parity) {

case 'e':

cflag |= PARENB;

break;

case 'o':

cflag |= PARODD;

break;

}

bit = simple_strtoul(buf, &buf, 10);

switch (bit) {

case 5:

cflag |= CS5;

break;

case 6:

cflag |= CS5;

break;

case 7:

cflag |= CS5;

break;

default:

cflag |= CS8;

}

#ifdef CONFIG_SERIAL_BFIN

return bfin_earlyserial_init(serial_port, cflag);

#else

return NULL;

#endif

}

很简单,实际上就是提取earlyprintk中的参数,将之转换为serial_portcflag两个数值,然后调用bfin_earlyserial_init函数来初始化串口。

1.2.3 bfin_earlyserial_init

此函数如下所示:

struct console __init *bfin_earlyserial_init(unsigned int port,

unsigned int cflag)

{

struct bfin_serial_port *uart;

struct ktermios t;

if (port == -1 || port >= nr_ports)

port = 0;

bfin_serial_init_ports();

bfin_early_serial_console.index = port;

uart = &bfin_serial_ports[port];

t.c_cflag = cflag;

t.c_iflag = 0;

t.c_oflag = 0;

t.c_lflag = ICANON;

t.c_line = port;

bfin_serial_set_termios(&uart->port, &t, &t);

return &bfin_early_serial_console;

}

这个函数除了初始化硬件参数之外,还要构造一个console结构体。

1.2.3.1 bfin_serial_init_ports

这个函数由bfin_earlyserial_init调用,其实现为:

static void __init bfin_serial_init_ports(void)

{

static int first = 1;

int i;

if (!first)

return;

first = 0;

for (i = 0; i < nr_ports; i++) {

bfin_serial_ports[i].port.uartclk = get_sclk();

bfin_serial_ports[i].port.ops = &bfin_serial_pops;

bfin_serial_ports[i].port.line = i;

bfin_serial_ports[i].port.iotype = UPIO_MEM;

bfin_serial_ports[i].port.membase =

(void __iomem *)bfin_serial_resource[i].uart_base_addr;

bfin_serial_ports[i].port.mapbase =

bfin_serial_resource[i].uart_base_addr;

bfin_serial_ports[i].port.irq =

bfin_serial_resource[i].uart_irq;

bfin_serial_ports[i].port.flags = UPF_BOOT_AUTOCONF;

#ifdef CONFIG_SERIAL_BFIN_DMA

bfin_serial_ports[i].tx_done = 1;

bfin_serial_ports[i].tx_count = 0;

bfin_serial_ports[i].tx_dma_channel =

bfin_serial_resource[i].uart_tx_dma_channel;

bfin_serial_ports[i].rx_dma_channel =

bfin_serial_resource[i].uart_rx_dma_channel;

init_timer(&(bfin_serial_ports[i].rx_dma_timer));

#endif

#ifdef CONFIG_SERIAL_BFIN_CTSRTS

margi

你可能感兴趣的:(数据结构,C++,c,Blog,C#)