uart_register_driver(&serial_pxa_reg);
tty_driver->fops = uart_ops; // 设置本tty_driver的方法集
tty_driver->driver_state = &serial_pxa_reg;
所以open将首先
cdev->ops = tty_fops;
tty_fops.open即tty_open==>从tty_drivers挂接的所有tty_driver中摘下管理该dev major和minor的tty_driver,这里就是
上面的tty_driver->fops = uart_ops;
同时
(tty->ldisc.open)(tty);
// ldisc线路规程就是initialize_tty_struct中由console_init==>tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
// 初始化的tty_ldisc_N_TTY[luther.gliethttp]
filp->private_data = tty; // 这里tty->driver就是tty_driver
tty->driver->open(tty, filp);
所以流程为
tty_fops.tty_open==>tty_ldisc_N_TTY.n_tty_open
==>tty_driver->fops->uart_open
之后filp->private_data = tty;
tty_fops==>tty_ldisc_N_TTY==>tty_driver->fops即uart_ops;==>tty->driver_data
即uart_state==>state->port->ops即在serial_pxa_probe()中创建的sport->port.ops = &serial_pxa_pops;
struct uart_ops serial_pxa_pops = {
.tx_empty = serial_pxa_tx_empty,
.set_mctrl = serial_pxa_set_mctrl,
.get_mctrl = serial_pxa_get_mctrl,
.stop_tx = serial_pxa_stop_tx,
.start_tx = serial_pxa_start_tx,
.stop_rx = serial_pxa_stop_rx,
.enable_ms = serial_pxa_enable_ms,
.break_ctl = serial_pxa_break_ctl,
.startup = serial_pxa_startup,
.shutdown = serial_pxa_shutdown,
.set_termios = serial_pxa_set_termios,
.pm = serial_pxa_pm,
.type = serial_pxa_type,
.release_port = serial_pxa_release_port,
.request_port = serial_pxa_request_port,
.config_port = serial_pxa_config_port,
.verify_port = serial_pxa_verify_port,
};
serial_pxa_probe
==>uart_add_one_port
==>uart_configure_port
==>register_console(port->cons); // 注册console,serial_pxa_reg的PXA_CONSOLE
void register_console(struct console *console)
{
int i;
unsigned long flags;
struct console *bootconsole = NULL;
/*
serial_pxa_reg
==>
static struct console serial_pxa_console = {
.name = "ttyS",
.write = serial_pxa_console_write,
.device = uart_console_device,
.setup = serial_pxa_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &serial_pxa_reg,
};
*/
if (console_drivers) {
if (console->flags & CON_BOOT)
return;
if (console_drivers->flags & CON_BOOT)
bootconsole = console_drivers;
}
if (preferred_console < 0 || bootconsole || !console_drivers)
preferred_console = selected_console;
if (console->early_setup)
console->early_setup();
/*
* See if we want to use this console driver. If we
* didn't select a console we take the first one
* that registers here.
*/
if (preferred_console < 0) {
if (console->index < 0)
console->index = 0;
if (console->setup == NULL ||
console->setup(console, NULL) == 0) { // 调用serial_pxa_console_setup
console->flags |= CON_ENABLED | CON_CONSDEV;
preferred_console = 0;
}
}
/*
* See if this console matches one we selected on
* the command line.
*/
for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0];
i++) {
if (strcmp(console_cmdline[i].name, console->name) != 0)
continue;
if (console->index >= 0 &&
console->index != console_cmdline[i].index)
continue;
if (console->index < 0)
console->index = console_cmdline[i].index;
if (console->setup &&
console->setup(console, console_cmdline[i].options) != 0)
break;
console->flags |= CON_ENABLED;
console->index = console_cmdline[i].index;
if (i == selected_console) {
console->flags |= CON_CONSDEV;
preferred_console = selected_console;
}
break;serial_pxa_pops
}
if (!(console->flags & CON_ENABLED))
return;
if (bootconsole && (console->flags & CON_CONSDEV)) {
printk(KERN_INFO "console handover: boot [%s%d] -> real [%s%d]\n",
bootconsole->name, bootconsole->index,
console->name, console->index);
unregister_console(bootconsole);
console->flags &= ~CON_PRINTBUFFER;
} else {
printk(KERN_INFO "console [%s%d] enabled\n",
console->name, console->index);
}
/*
* Put this console in the list - keep theserial_pxa_pops
* preferred driver at the head of the list.
*/
acquire_console_sem();
if ((console->flags & CON_CONSDEV) || console_drivers == NULL) {
// 将该console添加到console_drivers链表头[luther.gliethttp]
console->next = console_drivers;
console_drivers = console;
if (console->next)
console->next->flags &= ~CON_CONSDEV;
} else {
// 将console_drivers追加到它的后面
console->next = console_drivers->next;
console_drivers->next = console;
}
if (console->flags & CON_PRINTBUFFER) {
/*
* release_console_sem() will print out the buffered messages
* for us.
*/
spin_lock_irqsave(&logbuf_lock, flags);
con_start = log_start;
spin_unlock_irqrestore(&logbuf_lock, flags);
}
#ifdef CONFIG_DEBUG_EARLY_PRINTK
disable_early_printk = 1;
#endif
release_console_sem(); // 向console_drivers链表上的挂接的所有console发送字符串log.
}
serial_pxa_init
==>uart_register_driver(&serial_pxa_reg);
==>platform_driver_register(&serial_pxa_driver);
然后
arch\arm\mach-pxa\generic.c
arch\arm\mach-pxa\generic.c
struct platform_device pxa_device_ffuart= {
.name = "pxa2xx-uart",
.id = 0,//对应的line号,所以这个串口在/dev下的名字为ttyS0
.resource = pxa_resource_ffuart,
.num_resources = ARRAY_SIZE(pxa_resource_ffuart),
};
struct platform_device pxa_device_btuart = {
.name = "pxa2xx-uart",
.id = 1,
.resource = pxa_resource_btuart,
.num_resources = ARRAY_SIZE(pxa_resource_btuart),
};
struct platform_device pxa_device_stuart = {
.name = "pxa2xx-uart",
.id = 2,
.resource = pxa_resource_stuart,
.num_resources = ARRAY_SIZE(pxa_resource_stuart),
};
以上三个在arch\arm\mach-pxa\pxa3xx.c=>pxa3xx_init=>
static struct platform_device *devices[] __initdata = {
...
&pxa_device_ffuart,
&pxa_device_btuart,
&pxa_device_stuart,
...
};
platform_add_devices(devices, ARRAY_SIZE(devices));
//批量添加arch\arm\mach-pxa\generic.c下定义的platform_device设备
struct platform_device pxa_device_hwuart = {
.name = "pxa2xx-uart",
.id = 3,
.resource = pxa_resource_hwuart,
.num_resources = ARRAY_SIZE(pxa_resource_hwuart),
};
以上三个在arch\arm\mach-pxa\pxa3xx.c=>pxa3xx_init=>
static struct platform_device *devices[] __initdata = {
...
&pxa_device_ffuart,
&pxa_device_btuart,
&pxa_device_stuart,
...
};
platform_add_devices(devices, ARRAY_SIZE(devices));
|