简单的结构流程图
简单的结构框图
uart_register_driver 浅析
/**
这个函数主要做了一下事情:
1 : 分配tty_driver,初始化.
2 : 初始化 tty_port
3 : 注册tty_driver到设备驱动模型中(其实就是注册字符设备)
将tty_driver 添加到全局链表tty_drivers上
*/
int uart_register_driver(struct uart_driver *drv)
{
/**
tty_driver
还是那个固定模式,分配内存、赋值初始化、然后注册到系统中,最后挂接到链表中
下面详细的说明这个生命周期,有实验验证!
alloc_tty_driver() 分配
-->tty_alloc_driver()
-->__tty_alloc_driver()
-->kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
.... 赋值初始化
tty_register_driver() 注册
-->alloc_chrdev_region()
-->tty_cdev_add()
--->cdev_init(...,&tty_fops) // tty_fops 向VFS层提供的函数操作接口集.
--->cdev_add()
-->list_add(&driver->tty_drivers, &tty_drivers);
看到了把,注册一个uart_driver 最终是变成了 注册一个tty_dirver. 哈哈!
作者为什么要这样做 ?
*/
struct tty_driver *normal;
int i, retval;
/**
#ifndef HAVE_ARCH_BUG_ON
#define BUG_ON(condition)
do\
{\ 不太可能会执行
if (unlikely(condition))\
BUG();\
} while(0)
#endif
#endif
被调用的时候,它们会引发oops,导致栈的回溯和错误信息的打印
用户不需要提供struct uart_state 内核下面的代码会 分配内存空间,并且初始化uart_port
如果用户为uart_driver 提供了 uart_state,那么BUG()就会被调用了...........
源码中也说了,这个是私有的,别动
struct uart_driver{
* these are private; the low level driver should not
* touch these; they should be initialised to NULL
*
struct uart_state *state;
struct tty_driver *tty_driver;
}
*/
BUG_ON(drv->state);
/*
这个 uart_state 很重要 !
申请 nr个 uart_state 空间 ,参见上图
struct uart_state {
....
struct circ_buf xmit; 要发送数据的缓冲区
struct uart_port *uart_port; 串口的物理信息
};
作者说 这里分配的时候 应该用一个slab 来分配内存 :
Maybe we should be using a slab cache for this,
especially if we have a large number of ports to handle.
*/
drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
if (!drv->state)
goto out;
/**
底层调用kzalloc()来分配内存
static inline struct tty_driver *alloc_tty_driver(unsigned int lines)
{
struct tty_driver *ret = tty_alloc_driver(lines, 0);
{
#define tty_alloc_driver(lines, flags) \
__tty_alloc_driver(lines, THIS_MODULE, flags)
{
struct tty_driver *driver;
...
driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
...
driver->cdevs = kcalloc(cdevs, sizeof(*driver->cdevs), GFP_KERNEL);
}
}
}
并且还给cdev分配了内存
driver->cdevs = kcalloc(cdevs, sizeof(*driver->cdevs), GFP_KERNEL);
看到这里,那么下面 cdev_init()、cdev_add()这些注册字符设备的函数 被调用也不远了把
他们是在下面的 tty_register_driver()函数中被调用的,下面详细说
*/
normal = alloc_tty_driver(drv->nr);
if (!normal)
goto out_kfree;
/*
uart_driver 与 tty_driver 进行关联
*/
drv->tty_driver = normal;
/*
对 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; // 输入速度
/*
这个flags这块,比如 u_serial.c中在
gs_tty_driver = alloc_tty_driver(MAX_U_SERIAL_PORTS);
....
gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
....
status = tty_register_driver(gs_tty_driver);
上面的这个tty_register_dirver后,并没有 注册字符设备、创建设备节点、在/proc创建文件.
只是简单的申请了一个主设备是250的设备号
*/
normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
normal->driver_state = drv; // uart_state 在这里给tty_driver进行赋值
/*
ops赋值,不知道这里的uart_ops 在什么时候 会被调用 ?
normal->ops = &uart_ops;
*/
tty_set_operations(normal, &uart_ops);
/*
看完这个for之后,你会发现,他就是为了初始化tty_port
*/
for (i = 0; i < drv->nr; i++)
{
/*
见上图
上面已经为drv->state分配了内存空间,现在它指向一块内存空间,
空间大小是 sizeof(struct uart_state) * nr
*/
struct uart_state *state = drv->state + i;
/*
获取tty_port,下面就是为他赋值初始化了,
*/
struct tty_port *port = &state->port;
/*
三个等待队列的初始化 open_wait close_wait delta_msr_wait
二个互斥锁 + 一个自旋锁的初始化
三个等待队列有什么用,下面说
*/
tty_port_init(port);
port->ops = &uart_port_ops;
port->close_delay = HZ / 2;
port->closing_wait = 30 * HZ;
}
/**
1 :设备号的申请 alloc_chrdev_region()
2 : 字符设备的注册
3 : 将tty_driver 添加到 全局链表tty_drivers上去
int tty_register_driver(struct tty_driver *driver)
{
if (!driver->major) {
alloc_chrdev_region()
}else{
register_chrdev_region()
}
...
error = tty_cdev_add(driver, dev, 0, driver->num);
{
用户空间opne、poll,下面对应的函数会被首先调用
在这些函数中,会调用对应线路规程提供的对应函数
static const struct file_operations tty_fops = {
.llseek = no_llseek,
.read = tty_read,
.write = tty_write,
.poll = tty_poll,
.unlocked_ioctl = tty_ioctl,
.compat_ioctl = tty_compat_ioctl,
.open = tty_open,
.release = tty_release,
.fasync = tty_fasync,
};
cdev_init(&driver->cdevs[index], &tty_fops); //字符设备的注册
cdev_add();
}
...
list_add(&driver->tty_drivers, &tty_drivers); 添加到全局链表上
...
proc_tty_register_driver(driver);
}
如果这个函数调用成功,在这里就返回了,
*/
retval = tty_register_driver(normal);
if (retval >= 0)
return retval;
/**
这行代码被执行的是在
1 : drv->state = kzalloc()失败
2 : tty_register_driver()调用失败的时候 执行的代码
正常的流程 不会执行下面的代码
*/
for (i = 0; i < drv->nr; i++)
tty_port_destroy(&drv->state[i].port);
put_tty_driver(normal);
}
整个函数的结构