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 , * eg: 115200n8r 默认的baud 是9600 serial8250_console_write该函数禁止发送中断,用poll的方式发送完所有的数据后再开中断.