luoqindong 2012-10-04
使用phy3250开发板(lpc3250 cpu)
1.uart_driver
static struct uart_driver serial8250_driver = {
.owner
= THIS_MODULE,
.driver_name
= "serial",
.dev_name
= "ttyS",
.major
= TTY_MAJOR,
.minor
= 64,
.nr
= UART_NR,
.cons
= SERIAL8250_CONSOLE, //如果serial8250_console_init能将console正确初始化,这里也可以不用
};
该结构定义设备节点的名称(ttyS),主次设备号,有多少个串口,driver_name用来干嘛就不知道了.
该结构要调用uart_register_driver函数注册,并且在要uart_port结构注册之前注册.一般在driver_init
函数里边注册.
2.uart_port
struct uart_8250_port {
struct uart_port
port;
struct timer_list
timer; /* "no irq" timer */
struct list_head
list;
/* ports on this IRQ */
unsigned short
capabilities;
/* port capabilities */
unsigned short
bugs;
/* port bugs */
unsigned int
tx_loadsz;
/* transmit fifo load size */
unsigned char
acr;
unsigned char
ier;
unsigned char
lcr;
unsigned char
mcr;
unsigned char
mcr_mask;
/* mask of user bits */
unsigned char
mcr_force;
/* mask of forced bits */
/*
* Some bits in registers are cleared on a read, so they must
* be saved whenever the register is read but the bits will not
* be immediately processed.
*/
#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
unsigned char
lsr_saved_flags;
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
unsigned char
msr_saved_flags;
/*
* We provide a per-port pm hook.
*/
void
(*pm)(struct uart_port *port,
unsigned int state, unsigned int old);
};
该结构一般嵌入到另一个结构体中,每个平台的结构体的成员变量一般都不一样.
该结构可以在driver定义的时候初始化,也可以定义在platform device中,在probe
的时候再初始化,一个uart口对应一个port,有几个uart口就需要注册几个port.
uart_port注册要在uart_driver之后注册,一般在probe函数中注册.一个platform device
probe,就注册一个uart_port.
3. uart_ops
static struct uart_ops serial8250_pops = {
.tx_empty
= serial8250_tx_empty, //检查发送fifo是否是空的.
.set_mctrl
= serial8250_set_mctrl,
.get_mctrl
= serial8250_get_mctrl,
.stop_tx
= serial8250_stop_tx, //停止发送,一般禁止发送中断
.start_tx
= serial8250_start_tx,//允许发送中断,
.stop_rx
= serial8250_stop_rx, //停止接收
.enable_ms
= serial8250_enable_ms,
.break_ctl
= serial8250_break_ctl,
.startup
= serial8250_startup, //open设备文件的时候就调用该函数,初始化fifo,注册中断处理函数.在该函数中允许接收中断,但是不允许发送中断
.shutdown
= serial8250_shutdown,//close设备文件的时候调用该函数.
.set_termios
= serial8250_set_termios, //设置buad,parity 等.
.pm
= serial8250_pm,
.type
= serial8250_type, //启动的时候打印的lpc32xx uart.0: ttyS0 at MMIO 0x40090000 (irq = 9) is a unknown, unknow是中serial8250_type返回的,
//如果type函数没有实现,那显示的就是unknow.调用过程uart_add_one_port->uart_configure_port->uart_report_port
.release_port
= serial8250_release_port,
.request_port
= serial8250_request_port, //该函数申请uart的IO资源,将IO物理地址remap到内核虚拟地址等.
.config_port
= serial8250_config_port, //该函数一般只需要初始化port.type,
uart_add_one_port
该函数调用条件:
if (port->flags & UPF_BOOT_AUTOCONF) {
port->type = PORT_UNKNOWN;
port->ops->config_port(port, flags);
}
.verify_port
= serial8250_verify_port,
#ifdef CONFIG_CONSOLE_POLL
.poll_get_char = serial8250_get_poll_char,
.poll_put_char = serial8250_put_poll_char,
#endif
};
uart_port.ops指向该结构体.
console:
注册过程:
static struct console serial8250_console = {
.name
= "ttyS", 要和uart_driver中的dev_name变量名字一样.
.device
= uart_console_device,
.flags
= CON_PRINTBUFFER,
.index
= -1, //表示用cmdline传递的uart 端口来做console,该index指的是serial8250_ports中的index
.data
= &serial8250_driver, //这个要初始化
.write
= serial8250_console_write,
.setup
= serial8250_console_setup,
//.early_setup
= serial8250_console_early_setup,
};
console上边的变量都要初始化,照着初始化就可以了.
static int __init serial8250_console_init(void)
{
if (nr_uarts > UART_NR)
nr_uarts = UART_NR;
serial8250_isa_init_ports();
register_console(&serial8250_console);
return 0;
}
console_initcall(serial8250_console_init);
该函数会在内核处理cmdline之后就初始化,该函数只要用register 初始化console就可以了.
该函数会比probe先调用,所以调用register_console的时候,port还没有初始化,所以当
register_console调用lpc32xx_console_setup设置buad,parity bits的时候,
lpc32xx_console_setup会检测port->iobase和port->membase是否是有效值,如果不是就返回,
port = &lpc32xx_ports[co->index].port;
if (!port->iobase && !port->membase){
return -ENODEV;
}
放弃初始化console,所以实际上,console不是在serial8250_console_init里边初始化,如果要
在serial8250_console_init初始化,需要将port静态初始化.
uart_driver结构里边有SERIAL8250_CONSOLE,
probe调用uart_add_one_port->uart_configure_port:
/*
* If this driver supports console, and it hasn't been
* successfully registered yet, try to re-register it.
* It may be that the port was not available.
*/
if (port->cons && !(port->cons->flags & CON_ENABLED)){
printk("%s retister console\n", __FUNCTION__);
register_console(port->cons);
}
该函数会检查console有没有初始化,如果没有初始化,则调用register_console来初始化.
所以console放在这里初始化也是比较好一些,可以将console_initcall(serial8250_console_init) comment.
register console先会调用:
if (console->early_setup)
console->early_setup();
调用serial8250_console_setup设备buad,parity bits等.
*
uart_parse_options decodes a string containing the serial console
*
options. The format of the string is <baud><parity><bits><flow>,
*
eg: 115200n8r
默认的baud 是9600
serial8250_console_write该函数禁止发送中断,用poll的方式发送完所有的数据后再开中断.