内核版本: 2.6.32.2
仍在修改中 2018.12.21
需进一步了解内核启动过程中start_kernel以及module_init调用
module_init(serial8250_init);
module_init(tty_init);
console_init在start_kernel中调用
Register
serial8250_init(void): drivers/serial/8250.c
- 调用uart_register_driver(&serial8250_reg),serial8250_reg为struct
uart_driver,
其没有fops结构,uart port才有具体的uart_ops结构
- serial8250_isa_devs=platform_device_alloc(“serial8250”,-1);
platform_device_add(serial8250_isa_devs - serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);
- platform_driver_register(&serial8250_isa_driver);
uart_register_driver(struct uart_driver *drv):drivers/serial/serial_core.c
drv传入参数&serial8250_reg
- struct tty_driver normal = alloc_tty_driver(drv->nr);
drv->tty_driver = normal; 将serial8250_reg的参数传给normal
- tty_set_operations(normal, &uart_ops);
- 调用tty_port_init, UART_NR个port, 由CONFIG决定
- tty_register_driver(normal)
tty_register_driver(struct tty_driver *driver): drivers/char/tty_io.c
driver传入参数normal
- register_chrdev_region(dev, driver->num, driver->name); dev_t dev为空
- cdev_init(&driver->cdev, &tty_fops): cdev原为空,
初始化cdev,将fops和cdev联合,为cdev_add作准备。 - cdev_add(&driver->cdev, dev, driver->num): 调用kobj_map()函数向系统中添加设备
tty_init在这个过程中没被调用? 什么时候调用?
- 内核编译时就会调用tty_init等module_init函数对tty终端进行cdev_init和cdev_add,以及生成/dev/tty文件
- 若作为模块编译时, 什么时候调用?
busybox的insmod会调用新编译的.ko中所有的module_init函数?比如8250其会调用8250和tty的init函数
write调用过程:
系统调用write(), 操作系统sys_write()调用, 进一步tty_write(), 下从此开始分析调用, 系统调用部分未了解
tty还有line discpline, 调用write, read, ioctl等会调用line discpline.
tty_wirte(), 调用do_tty_write()
do_tty_write(ld->ops->write, tty, file, buf, count): drivers/char/tty_io.c
- ld = tty_ldisc_ref_wait(tty);
- 调用ld = tty_ldisc_try(tty)
- 调用ld = get_ldisc(tty->ldisc);
- ld为返回的struct tty_ldisc, 见ld->ops和tty_ldisc_N_TTY部分分析,
得知ld->ops应该为tty_ldisc_N_TTY
- ld->ops->write对应n_tty_write(drivers/char/n_tty.c), 旧版内核为write_chan
- 调用write(tty, file, tty->write_buf, size), 即调用n_tty_write(tty, file,
tty->write_buf, size)
n_tty_write(tty, file, tty->write_buf, size)
- 调用tty->ops->flush_chars(tty)
- 调用uart_flush_chars(tty)
uart_flush_chars(tty)
- 调用uart_start(tty)
uart_start(tty)
- 先后调用__uart_start和port->ops->start_tx(port)
- port=tty->driver_data->uart_port
- 即执行tty->driver_data->uart_port->start_tx(port) port和uart关系见下
- 实际执行具体芯片如serial8250_start_tx
- serial8250_start_tx调用serial_icr_write(up, UART_ACR, up->acr)和serial_out
- Up->port.serial_out在early_serial_setup(struct uart_port *port)中设置p->serial_out = port->serial_out;
*int __init early_serial_setup(struct uart_port port)
初始化时参数port怎么传入??
ld->ops和tty_ldisc_N_TTY
console_init(void): drivers/char/tty_io.c, console_init什么时候调用? Start_kernel调用很多初始化函数
- 开机初始化控制台, 调用tty_ldisc_begin, line discpline在控制台初始化同时初始化
- 调用tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); N_TTY=0
*tty_register_ldisc(int disc, struct tty_ldisc_ops new_ldisc) - tty_ldiscs[disc] = new_ldisc; 即绑定tty_ldisc_N_TTY为line discpline的operations
*struct tty_ldisc_ops get_ldops(int disc) - 获得operation
*tty_ldisc tty_ldisc_get(int disc) - 调用ldops = get_ldops(disc);
- ld->ops = ldops;
- return ld
回到tty_write()函数中 - tty = (struct tty_struct *)file->private_data;
- file->private_data在tty_open时设立file->private_data=tty, 调用tty_init_dev后调用tty_ldisc_setup后调用initialize_tty_struct后调用tty_ldisc_init进一步调用tty_ldisc_get(N_TTY)实现N_TTY和operation的绑定
- 结论: tty->ldisc->ops为tty_ldisc_N_TTY
uart和port之间的关系
serial8250_console_init开始
待更新