Uart 架构之美 -- Linux Kernel 实现浅析
2017-10-14 21:57
295 查看
一个小小的uart 蕴含了一座金矿,
uart这只麻雀虽小却五脏俱全,no !我看,它定位不是麻雀,是北冥鸿鹄. 哈哈,
以前分析的在这儿,你可以参考
http://blog.csdn.net/leesagacious/article/details/54670735
先上一幅图.
程序可以通过顺序、选择分支和循环三种方式就可以完成了,对吧, 不建议使用goto ?
也不是绝对的吧,goto在某些方面是有积极意义的
该作者可能忽略了goto更优秀的一面,Linux Kernel中 大量使用goto.且远不止是执行清理错误的工作这般,
下面是Kernel 中的例子 :
1 : USB Gadget
下面该段代码的具体分析 你看参见以前我的博文
http://blog.csdn.net/leesagacious/article/details/55804233
看一个iic的实现
具体代码分析请参见我以前的博文
http://blog.csdn.net/leesagacious/article/details/50488949
Figure 1.1
不是常说每个port都存在uart_port结构的一个实例,真正对应一个物理串口吗 ?
好,下面就看看Linux Kernel的架构实现
好,下面这个注册每个端口的函数,就是将UART驱动与kernel联系起来了,与 uart_register_driver函数一样很重要!
都是uart驱动 必须调用的 !
int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport);
欣赏这个函数之前,你必须要明白的一个结构体是 struct uart_state, 它真的太重要了.
The number of uart_state is equals to the number of hardware ports that ard accessed via the driver
1: 什么时候分配的
请移步: http://blog.csdn.net/leesagacious/article/details/54670735
先看下面的一个结构体
uart这只麻雀虽小却五脏俱全,no !我看,它定位不是麻雀,是北冥鸿鹄. 哈哈,
以前分析的在这儿,你可以参考
http://blog.csdn.net/leesagacious/article/details/54670735
先上一幅图.
goto的魔力
先来看看这个函数抛异常的 goto程序可以通过顺序、选择分支和循环三种方式就可以完成了,对吧, 不建议使用goto ?
也不是绝对的吧,goto在某些方面是有积极意义的
<<Structured Programming with go to Statements>> --高纳德 <<C程序设计新思维 P128>> 在出现错误需要执行清理工作时,它比其他替代方案更为清晰
该作者可能忽略了goto更优秀的一面,Linux Kernel中 大量使用goto.且远不止是执行清理错误的工作这般,
下面是Kernel 中的例子 :
1 : USB Gadget
下面该段代码的具体分析 你看参见以前我的博文
http://blog.csdn.net/leesagacious/article/details/55804233
/* On successful return, the gadget is ready to respond to requests from the host 该函数返回 0 ,表示gadget功能驱动层、gadget设备层、udc层已经建立好了, 一个完整的usb驱动已经可以接受主机的枚举了, 哈哈,这个函数的返回值设计的真是好,debugging的时可以直接作为切入点, 所以,有时 即使使用工具跟踪分析的再细致,也不如函数给人的直觉来的直接、准确, usb_composite_probe() { return usb_gadget_probe_driver(gadget_driver); } */ int usb_gadget_probe_driver(struct usb_gadget_driver *driver) { struct usb_udc *udc = NULL; int ret; if (!driver || !driver->bind || !driver->setup) return -EINVAL; mutex_lock(&udc_lock); list_for_each_entry(udc, &udc_list, list) { /* For now we take the first one */ if (!udc->driver) goto found; // 在这儿 } pr_debug("couldn't find an available UDC\n"); mutex_unlock(&udc_lock); return -ENODEV; found: ret = udc_bind_to_driver(udc, driver); mutex_unlock(&udc_lock); return ret; }
看一个iic的实现
具体代码分析请参见我以前的博文
http://blog.csdn.net/leesagacious/article/details/50488949
static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) { ..... if (i2c->state == STATE_READ) goto prepare_read; retry_write: if (!is_msgend(i2c)) { } else if (!is_lastmsg(i2c)) { } else { /* send stop */ s3c24xx_i2c_stop(i2c, 0); } goto retry_write; break; case STATE_READ: prepare_read: if (is_msglast(i2c)) { } else if (is_msgend(i2c)) { if (is_lastmsg(i2c)) { } else { } } break; } }
所以对于外设read、write函数的读写过程都逃逸不了goto的魔掌, 且在一些优秀的协议中读写过程利用goto与Linux Kernel休眠与唤醒机制相结合,更是让系统大放异彩 你还能说goto只是用来处理错误的吗 ?goto的魔力可见一斑!
DTS 与 Uart
dtsi文件描述的外设是怎么被加载到Linux Kernel中的,启动的时候是怎么枚举的 ?基础数据结构
uart架构围绕着 三个数据结构的对象为中心,以接口提供的功能为基础,有了原材料之后,Uart开始裂变 …Figure 1.1
struct uart_driver { struct module *owner; const char *driver_name; const char *dev_name; int major; int minor; int nr; struct console *cons; struct uart_state *state; struct tty_driver *tty_driver; };
/* 对应一个物理上真实的串口 */ struct uart_port { spinlock_t lock; unsigned long iobase; unsigned char __iomem *membase; unsigned int (*serial_in)(struct uart_port *, int); void (*serial_out)(struct uart_port *, int, int); int (*handle_irq)(struct uart_port *); .... unsigned int irq; unsigned long irqflags; unsigned int uartclk; unsigned int fifosize; .... .... }
/* 物理硬件操作的入口函数集合,每个port数据路径都是隔离的,要"串线"可修改上层的线路规程 */ struct uart_ops { unsigned int (*tx_empty)(struct uart_port *); void (*set_mctrl)(struct uart_port *, unsigned int mctrl); int (*startup)(struct uart_port *); void (*flush_buffer)(struct uart_port *); void (*set_termios)(struct uart_port *, struct ktermios *new,struct ktermios *old); void (*set_ldisc)(struct uart_port *, int new); ... };
不是常说每个port都存在uart_port结构的一个实例,真正对应一个物理串口吗 ?
好,下面就看看Linux Kernel的架构实现
你自己的驱动要想和内核连接起来形成一体,首先你必须"迎合"内核源码的思想, 随便弄上来一个cdev + 一个file_operations + read /write,简约却很简单 直接将接口暴露给kernel的系统调用,那也不是<<大教堂与集市>>中 "减少的不能再少了" 的思想吧. 在夯实的土地上建造茅草屋,那你以后得唱 "茅屋为秋风所破歌"了,亡羊补牢,也许不会再是传说了.
好,下面这个注册每个端口的函数,就是将UART驱动与kernel联系起来了,与 uart_register_driver函数一样很重要!
都是uart驱动 必须调用的 !
int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport);
欣赏这个函数之前,你必须要明白的一个结构体是 struct uart_state, 它真的太重要了.
The number of uart_state is equals to the number of hardware ports that ard accessed via the driver
1: 什么时候分配的
请移步: http://blog.csdn.net/leesagacious/article/details/54670735
先看下面的一个结构体
/* 封装了基础的uart_port. */ struct uart_8250_port { struct uart_port port; struct timer_list timer; /* "no irq" timer */ ..... }; /* 好,看 Figure 1.1 中的 * ops,就在这里进行了指向. */ serial8250_init(void) { ↓ static void __init serial8250_isa_init_ports(void) { ↓ /* 初始化封装的每一个port.*/ for (i = 0; i < nr_uarts; i++) { /* 获取每一个封装的uart_8250_port,下面进行初始化其维护的资源 */ struct uart_8250_port *up = &serial8250_ports[i]; /* 获取基础的uart_port */ struct uart_port *port = &up->port; /* 数组的下标就是它的line,这个line很重要, 遍历数组,用数组下标赋值其对象维护的成员,内核惯用的伎俩! 类似的如: 1 :字符设备的主设备号就是probes[255]数组的下标. 2 :http://blog.csdn.net/leesagacious/article/details/50418197 */ port->line = i; /* 初始化维护的自旋锁 */ spin_lock_init(&port->lock); /* 初始化维护的定时器 */ init_timer(&up->timer); /* 超时执行函数 */ up->timer.function = serial8250_timeout; .... /* 就是上面说的uart_ops,操作硬件的入口函数集, 你可能会立即联想到那个tty的那个file_operations吧,哈哈! 在uart框架中,从系统调用的read、write、poll经过 tty维护的tty_fops提供的对应方法 一直会调用到这里的ops提供的对应的方法, 一路走来,按照信息流动的过程,分散了关注、松散了耦合,每层功能清晰,专注, 虽然性能有损耗,但是可以通过缓存来减少影响, */ port->ops = &serial8250_pops; } } }
线路规程
相关文章推荐
- NetBPM工作流的架构设计及实现浅析
- 浅析Linux Kernel 哈希路由表实现(二)
- NetBPM工作流的架构设计及实现浅析
- 浅析C#中三层架构的实现
- DMA实现架构浅析
- Interrupt 架构之美 -- Linux Kernel 实现欣赏
- NetBPM工作流之架构设计及实现浅析
- NetBPM工作流的架构设计及实现浅析
- NetBPM工作流的架构设计及实现浅析
- 浅析Facebook软件架构:Tao和BLOB的实现原理
- NetBPM工作流的架构设计及实现浅析
- NetBPM工作流的架构设计及实现浅析
- 空穴来风的服务器架构实现高并发性能测试实战方案
- Spring技术内幕——深入解析Spring架构与设计原理(三)数据库的操作实现
- WeText项目:一个基于.NET实现的DDD、CQRS与微服务架构的演示案例
- 基于Spring Boot和Spring Cloud实现微服务架构学习(四)-Spring Cloud总结
- 劈开迷雾,蘑菇街电商搜索架构及搜索排序实现
- EF+WCF+MVC实现SOA架构
- 浅析微软Service Layer Guidelines和OSOA架构体系(SCA,SDO等)之间的关系(非原创)