UART 驱动的注册过程主要由 uart_register_driver 和 uart_add_one_port两个函数来完成
uart_register_driver 流程分析
1,分配 uart_state 结构体
drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
2,分配tty_driver 结构体
normal = alloc_tty_driver(drv->nr);
struct tty_driver *ret = tty_alloc_driver(lines, 0);
__tty_alloc_driver(lines, THIS_MODULE, flags)
driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
driver->ttys = kcalloc(lines, sizeof(*driver->ttys),GFP_KERNEL);
driver->termios = kcalloc(lines, sizeof(*driver->termios),
GFP_KERNEL);
driver->ports = kcalloc(lines, sizeof(*driver->ports),
GFP_KERNEL);
driver->cdevs = kcalloc(cdevs, sizeof(*driver->cdevs),
GFP_KERNEL);
3,设置 tty_driver 结构体
normal->driver_name = drv->driver_name;
normal->name = drv->dev_name;
normal->major = drv->major;
normal->minor_start = drv->minor;
normal->type = TTY_DRIVER_TYPE_SERIAL;
normal->subtype = SERIAL_TYPE_NORMAL;
normal->init_termios = tty_std_termios;
normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
normal->driver_state = drv;
tty_set_operations(normal, &uart_ops);
关键是设置操作函数为 uart_ops:
4,创建字符设备
retval = tty_register_driver(normal);
uart_add_one_port 流程分析
在注册port 之前,会先根据设备树设置port,主要是设置操作函数
port->ops = &serial8250_pops;
uart_add_one_port
tty_dev = tty_port_register_device_attr(port, drv->tty_driver,
uport->line, uport->dev, port, uport->tty_groups);
tty_register_device_attr(driver, index, device, drvdata,
attr_grp);
1,创建字符设备节点的名字
tty_line_name(driver, index, name);
2,创建字符设备,并设置操作函数为tty_fops
retval = tty_cdev_add(driver, devt, index, 1);
driver->cdevs[index]->ops = &tty_fops;
注册过程流程分析图
当 APP调用 open/read/write 函数时,会调用驱动程序tty_ops 中对应的函数:tty_open/tty_read/tty_write