Linux驱动分析之Uart驱动架构
Uart体系结构
UART设备驱动可以使用tty驱动的框架来实现,但是因为串口之间有共性,所以Linux在tty接口上封装了一层(serial core)。后面我们再拿一篇文章来解释tty驱动,tty其实就是各种终端设备,串口其实也是终端设备。
驱动工程师没必要关心上层的流程,只需注册一个uart_driver,并按硬件规范将对应接口函数完成就可以了。
上图我们只需要实现xxx_uart.c , 而我们实现所需要的结构体和函数接口就是由serial_core.c提供。接下来我们来看一下对应的结构体和接口函数。
重要结构体
内核版本:4.20.12
uart_driver
struct uart_driver {struct module *owner;const char *driver_name;const char *dev_name; //设备名,即dev下的节点名int major;int minor;int nr;struct console *cons;//console配置,串口作为console时才需要//私有的,底层驱动把它初始化为NULL即可struct uart_state *state;struct tty_driver *tty_driver;
};
串口设备也是字符设备,所以看到很多字符设备相关的,console就是控制台,我们平常所使用的debug口就是console。
uart_port
//描述一个UART端口
struct uart_port {spinlock_t lock; /* port lock */unsigned long iobase; /* in/out[bwl] */unsigned char __iomem *membase; /* read/write[bwl] */unsigned int (*serial_in)(struct uart_port *, int);void (*serial_out)(struct uart_port *, int, int);void (*set_termios)(struct uart_port *,struct ktermios *new,struct ktermios *old);void (*set_ldisc)(struct uart_port *,struct ktermios *);unsigned int (*get_mctrl)(struct uart_port *);void (*set_mctrl)(struct uart_port *, unsigned int);unsigned int (*get_divisor)(struct uart_port *,unsigned int baud,unsigned int *frac);void (*set_divisor)(struct uart_port *,unsigned int baud,unsigned int quot,unsigned int quot_frac);int (*startup)(struct uart_port *port);void (*shutdown)(struct uart_port *port);void (*throttle)(struct uart_port *port);void (*unthrottle)(struct uart_port *port);//中断处理int (*handle_irq)(struct uart_port *);void (*pm)(struct uart_port *, unsigned int state,unsigned int old); //电源管理void (*handle_break)(struct uart_port *);//485配置int (*rs485_config)(struct uart_port *,struct serial_rs485 *rs485);int (*iso7816_config)(struct uart_port *,struct serial_iso7816 *iso7816);unsigned int irq; /* 中断号 */unsigned long irqflags; /* 中断标志 */unsigned int uartclk; /* 串口时钟 */unsigned int fifosize; /* tx fifo size */unsigned char x_char; /* xon/xoff char */unsigned char regshift; /* reg offset shift */unsigned char iotype; /* io access style */unsigned char quirks; /* internal quirks *///省略宏定义....unsigned int read_status_mask; /* driver specific */unsigned int ignore_status_mask; /* driver specific */struct uart_state *state; /* pointer to parent state */struct uart_icount icount; /* statistics */struct console *cons; /* struct console, if any */
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)unsigned long sysrq; /* sysrq timeout */
#endif/* flags must be updated while holding port mutex */upf_t flags;
//省略宏定义....upstat_t status;
//省略宏定义....int hw_stopped; /* sw-assisted CTS flow state */unsigned int mctrl; /* current modem ctrl settings */unsigned int timeout; /* character-based timeout */unsigned int type; /* port type */const struct uart_ops *ops; //串口操作函数unsigned int custom_divisor;unsigned int line; /* port index */unsigned int minor;resource_size_t mapbase; /* for ioremap */resource_size_t mapsize;struct device *dev; /* parent device */unsigned char hub6; /* this should be in the 8250 driver */unsigned char suspended;unsigned char unused[2];const char *name; /* port name */struct attribute_group *attr_group; /* port specific attributes */const struct attribute_group **tty_groups; /* all attributes (serial core use only) */struct serial_rs485 rs485;struct serial_iso7816 iso7816;void *private_data; /* generic platform data pointer */
};
uart_port用于描述一个UART端口的I/O端口或I/O内存地址、FIFO大小、端口类型等信息。这个结构体参数很多,还有很多对串口进行配置的函数。
uart_ops
//物理硬件的所有操作
struct uart_ops {//一些操作函数unsigned int (*tx_empty)(struct uart_port *);//判断发送FIFO是否为空void (*set_mctrl)(struct uart_port *, unsigned int mctrl); //设置控制信息unsigned int (*get_mctrl)(struct uart_port *); //获取当前控制信息void (*stop_tx)(struct uart_port *); //停止txvoid (*start_tx)(struct uart_port *);//启动txvoid (*throttle)(struct uart_port *);//通知串口驱动,线路规程输入缓冲区接近满了void (*unthrottle)(struct uart_port *);//通知串口驱动可以将字符发送到线路规程输入缓冲区void (*send_xchar)(struct uart_port *, char ch); //传输高优先级字符,即使端口已停止。void (*stop_rx)(struct uart_port *); //停止Rxvoid (*enable_ms)(struct uart_port *); //使能modem状态中断void (*break_ctl)(struct uart_port *, int ctl); //控制中断信号的传输int (*startup)(struct uart_port *); //启动串口void (*shutdown)(struct uart_port *); //关闭串口void (*flush_buffer)(struct uart_port *); //刷新写buffer,复位DMAvoid (*set_termios)(struct uart_port *, struct ktermios *new,struct ktermios *old); //改变串口参数,包括字长,奇偶校验,停止位。void (*set_ldisc)(struct uart_port *, struct ktermios *); //通知线路规程改变void (*pm)(struct uart_port *, unsigned int state,unsigned int oldstate); //电源管理//返回一个描述串口类型的字符串const char *(*type)(struct uart_port *);//释放IO和内存资源void (*release_port)(struct uart_port *);//申请IO和内存资源int (*request_port)(struct uart_port *);//配置串口void (*config_port)(struct uart_port *, int);int (*verify_port)(struct uart_port *, struct serial_struct *);int (*ioctl)(struct uart_port *, unsigned int, unsigned long);
#ifdef CONFIG_CONSOLE_POLLint (*poll_init)(struct uart_port *);void (*poll_put_char)(struct uart_port *, unsigned char);int (*poll_get_char)(struct uart_port *);
#endif
};
uart_driver是对tty_driver的封装,uart_driver和platform_driver还是有区别的,因为它并没有probe回调函数。它主要是一些字符设备的信息。
uart_port用来描述具体的串口,主要是一些串口参数。
uart_ops就是一些串口的操作函数,和字符设备中的file_operations差不多。
API函数
//注册/注销uart_driver到串口核心层
int uart_register_driver(struct uart_driver *drv)
void uart_unregister_driver(struct uart_driver *drv)//关联具体串口和驱动
int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
//移除串口和驱动的管理
int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
我们使用到的接口函数很少,所以其实蛮简单的,Linux封装完之后就是填充结构体,然后调用接口注册一下。
总结
首先我们要清楚,在底层,Uart驱动是为每个port都分配了缓存空间的。所以应用层读取的都是缓存空间中的。然后uart_driver不能和platform_driver混淆。后面我们分析实例时会发现Uart的驱动是由platform_driver来回调probe的。之前说过,控制器都是使用platform_driver, 串口对于芯片而言,也是一个控制器。
分析一大堆代码是不是看着很累,所以千万别全部看,挑重点看,理清思路即可。
![](/assets/blank.gif)
Linux驱动分析之Uart驱动架构相关推荐
- Linux spi驱动分析----SPI设备驱动(W25Q32BV)
转载地址:http://blog.chinaunix.net/uid-25445243-id-4026974.html 一.W25Q32BV芯片简介 W25X是一系列SPI接口Flash芯片的简称,它 ...
- Linux RS232/485/GPS 驱动实验(2)-UART 驱动分析
1.UART 的 platform 驱动框架 打开 imx6ull.dtsi 文件,找到 UART3 对应的子节点,子节点内容如下所示: 1 uart3: serial@021ec000 { 2 co ...
- usb serial port 驱动_tty初探 — uart驱动框架分析
写在前面: 我们没有讲UART驱动,不过我们认为,只要系统学习了第2期,应该具备分析UART驱动的能力,小编做答疑几年以来,陆陆续续有不少人问到UART驱动怎么写,所以今天就分享一篇深度长文(1700 ...
- linux 网卡驱动分析,LINUX_网卡驱动分析
LINUX_网卡驱动分析 (36页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 19.9 积分 Linux DM9000网卡驱动程序完全分析说明仁 本文分 ...
- linux下camera驱动分析_LINUX设备驱动模型分析之三 驱动模块相关(DRIVER)接口分析...
本系列前几篇文章链接如下: <LINUX设备驱动模型分析之一 总体概念说明> <LINUX设备驱动模型分析之二 总线(BUS)接口分析> 上一章我们分析了bus-driver- ...
- linux pl320 mbox控制器驱动分析-(3) pl320驱动代码分析
linux pl320 mbox控制器驱动分析-(3)pl320驱动代码分析 1 pl320 mbox控制器宏定义 2 初始化接口 3 ipc_handler mbox中断处理函数 4 数据的收发 4 ...
- android 触摸屏驱动分析,Android 触摸屏驱动代码分析(ADC 类型触摸屏 CPU:s3c
Android 2.1 farsight version for s5pc100 File Name: s3c-ts.c 1 简介 1.1 本例基于s5pc100 ...
- 触摸屏驱动分析: (本机驱动)
触摸屏驱动为本机驱动,由微软提供有通用层 MDD,我们只需要编写PDD层就可以了.触摸屏驱动由GWES 加载,GWES 通过MDD层的DDI设备驱动程序接口函数(Device Driver Inter ...
- linux设备模型之tty驱动架构分析,linux设备模型之uart驱动架构分析
五: uart_add_one_port()操作本文引用地址:http://www.eepw.com.cn/article/201610/305916.htm 在前面提到.在对uart设备文件过程中. ...
最新文章
- 手绘线条一直画不直_我学素描,线条画不直怎么办啊?
- [hypervisor]-ARMV8的hypervisor技术介绍–InProgress
- 编程开发使用的软件大全
- 二面蚂蚁金服(交叉面),已拿offer,Java岗定级阿里P6
- vim匹配特定的行并删除它
- 看从小自带BUFF的他,如何用代码降低万物互联的门槛
- html的定位属性,CSS之定位属性
- catkin_make:Project ‘cv_bridge‘ specifies ‘/usr/include/opencv‘ as an include dir, which is not fo
- Kotlin 区间的一些小注意
- 有关学习Android资料的一些网站
- C语言函数库之字符串连接函数(string.h)
- 第三方Banner制作轮播图的具体方法
- 电脑重装win10系统bios不会设置?用这种方法可以轻松重装系统
- 基于Java毕业设计服务管理系统源码+系统+mysql+lw文档+部署软件
- 跨模态行人重识别:Deep Learning for Person Re-identification:A Survey and Outlook(行人重识别综述)
- 030 | 广西趣海有限责任公司创业计划书 | 大学生创新训练项目申请书 | 极致技术工厂
- 《阿凡达》的元宇宙帝国多久抵达现实?
- Cris 的Python笔记(十一):面向对象三大特征之多态
- 教你删除鼠标右键菜单,清理“新建”菜单的方法!
- 筑泰防务受邀参加公安无线通信与移动警务技术应用研讨会
热门文章
- [易飞]没做采购变更单,采购单被指定结束了?
- 智慧工地安全帽识别检测算法 yolov5
- [CNN]|CNN与Transformer区别
- 读曾仕强的《易经的奥秘》简摘
- 上最全!无线路由器常见问题大集合
- ScanNet数据集讲解与点云数据下载
- python可以写什么视觉特效_星球大战视觉特效背后的功臣——Python
- 如何设计一个优雅健壮的Android WebView?(上)
- EIS防抖-电子防抖技术
- [天龙/汉威]可变信息标志通信协议-向可变信息标志上载文件(JAVA版)