linux uart驱动分析(phy3250开发板)

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的方式发送完所有的数据后再开中断.



你可能感兴趣的:(linux uart驱动分析(phy3250开发板))