ImageVerifierCode 换一换
格式:DOCX , 页数:19 ,大小:84.31KB ,
资源ID:9071595      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/9071595.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(linux设备模型之uart驱动架构分析.docx)为本站会员(b****7)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

linux设备模型之uart驱动架构分析.docx

1、linux设备模型之uart驱动架构分析一:前言接着前面的终端控制台分析,接下来分析serial的驱动.在linux中,serial也对应着终端,通常被称为串口终端.在shell上,我们看到的/dev/ttyS*就是串口终端所对应的设备节点.在分析具体的serial驱动之前.有必要先分析uart驱动架构.uart是Universal Asynchronous Receiver and Transmitter的缩写.翻译成中文即为”通用异步收发器”.它是串口设备驱动的封装层.二:uart驱动架构概貌如下图所示:上图中红色部份标识即为uart部份的操作.从上图可以看到,uart设备是继tty_dr

2、iver的又一层封装.实际上uart_driver就是对应tty_driver.在它的操作函数中,将操作转入uart_port.在写操作的时候,先将数据放入一个叫做circ_buf的环形缓存区.然后uart_port从缓存区中取数据,将其写入到串口设备中.当uart_port从serial设备接收到数据时,会将设备放入对应line discipline的缓存区中.这样.用户在编写串口驱动的时候,只先要注册一个uart_driver.它的主要作用是定义设备节点号.然后将对设备的各项操作封装在uart_port.驱动工程师没必要关心上层的流程,只需按硬件规范将uart_port中的接口函数完成就可

3、以了.三:uart驱动中重要的数据结构及其关联我们可以自己考虑下,基于上面的架构代码应该要怎么写.首先考虑以下几点:1: 一个uart_driver通常会注册一段设备号.即在用户空间会看到uart_driver对应有多个设备节点.例如:/dev/ttyS0 /dev/ttyS1每个设备节点是对应一个具体硬件的,从上面的架构来看,每个设备文件应该对应一个uart_port.也就是说:uart_device怎么同多个uart_port关系起来?怎么去区分操作的是哪一个设备文件?2:每个uart_port对应一个circ_buf,所以uart_port必须要和这个缓存区关系起来回忆tty驱动架构中.

4、tty_driver有一个叫成员指向一个数组,即tty-ttys.每个设备文件对应设数组中的一项.而这个数组所代码的数据结构为tty_struct. 相应的tty_struct会将tty_driver和ldisc关联起来.那在uart驱动中,是否也可用相同的方式来处理呢?将uart驱动常用的数据结构表示如下:结合上面提出的疑问.可以很清楚的看懂这些结构的设计.四:uart_driver的注册操作Uart_driver注册对应的函数为: uart_register_driver()代码如下:int uart_register_driver(struct uart_driver *drv)stru

5、ct tty_driver *normal = NULL;int i, retval;BUG_ON(drv-state);/* 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);retval = -ENOMEM;if (!drv-state)goto out;normal = alloc_tty_d

6、river(drv-nr);if (!normal)goto out;drv-tty_driver = normal;normal-owner = drv-owner;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 = t

7、ty_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);/* Initialise the UART stat

8、e(s).*/for (i = 0; i nr; i ) struct uart_state *state = drv-state i;state-close_delay = 500; /* .5 seconds */state-closing_wait = 30000; /* 30 seconds */mutex_init(&state-mutex);retval = tty_register_driver(normal);out:if (retval put_tty_driver(normal);kfree(drv-state);return retval;从上面代码可以看出.uart_d

9、river中很多数据结构其实就是tty_driver中的.将数据转换为tty_driver之后,注册tty_driver.然后初始化uart_driver-state的存储空间.这样,就会注册uart_driver-nr个设备节点.主设备号为uart_driver- major. 开始的次设备号为uart_driver- minor.值得注意的是.在这里将tty_driver的操作集统一设为了uart_ops.其次,在tty_driver- driver_state保存了这个uart_driver.这样做是为了在用户空间对设备文件的操作时,很容易转到对应的uart_driver.另外:tty_

10、driver的flags成员值为: TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV.里面包含有TTY_DRIVER_DYNAMIC_DEV标志.结合之前对tty的分析.如果包含有这个标志,是不会在初始化的时候去注册device.也就是说在/dev/下没有动态生成结点(如果是/dev下静态创建了这个结点就另当别论了_).流程图如下:五: uart_add_one_port()操作在前面提到.在对uart设备文件过程中.会将操作转换到对应的port上,这个port跟uart_driver是怎么关联起来的呢?这就是uart_add_ont_port()的主要

11、工作了.顾名思义,这个函数是在uart_driver增加一个port.代码如下:int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)struct uart_state *state;int ret = 0;struct device *tty_dev;BUG_ON(in_interrupt();if (port-line = drv-nr)return -EINVAL;state = drv-state port-line;mutex_lock(&port_mutex);mutex_lock(&state-

12、mutex);if (state-port) ret = -EINVAL;goto out;state-port = port;state-pm_state = -1;port-cons = drv-cons;port-info = state-info;/* If this port is a console, then the spinlock is already* initialised.*/if (!(uart_console(port) & (port-cons-flags & CON_ENABLED) spin_lock_init(&port-lock);lockdep_set_

13、class(&port-lock, &port_lock_key);uart_configure_port(drv, state, port);/* Register the port whether its detected or not. This allows* setserial to be used to alter this ports parameters.*/tty_dev = tty_register_device(drv-tty_driver, port-line, port-dev);if (likely(!IS_ERR(tty_dev) device_can_wakeu

14、p(tty_dev) = 1;device_set_wakeup_enable(tty_dev, 0); elseprintk(KERN_ERR Cannot register tty device on line %dn,port-line);/* Ensure UPF_DEAD is not set.*/port-flags &= UPF_DEAD;out:mutex_unlock(&state-mutex);mutex_unlock(&port_mutex);return ret;首先这个函数不能在中断环境中使用. Uart_port-line就是对uart设备文件序号.它对应的也就是u

15、art_driver-state数组中的uart_port-line项.它主要初始化对应uart_driver-state项.接着调用uart_configure_port()进行port的自动配置.然后注册tty_device.如果用户空间运行了udev或者已经配置好了hotplug.就会在/dev下自动生成设备文件了.操作流程图如下所示:六:设备节点的open操作在用户空间执行open操作的时候,就会执行uart_ops-open. Uart_ops的定义如下:static const struct tty_operations uart_ops = .open = uart_open,.

16、close = uart_close,.write = uart_write,.put_char = uart_put_char,.flush_chars = uart_flush_chars,.write_room = uart_write_room,.chars_in_buffer= uart_chars_in_buffer,.flush_buffer = uart_flush_buffer,.ioctl = uart_ioctl,.throttle = uart_throttle,.unthrottle = uart_unthrottle,.send_xchar = uart_send_

17、xchar,.set_termios = uart_set_termios,.stop = uart_stop,.start = uart_start,.hangup = uart_hangup,.break_ctl = uart_break_ctl,.wait_until_sent= uart_wait_until_sent,#ifdef CONFIG_PROC_FS.read_proc = uart_read_proc,#endif.tiocmget = uart_tiocmget,.tiocmset = uart_tiocmset,;对应open的操作接口为uart_open.代码如下:

18、static int uart_open(struct tty_struct *tty, struct file *filp)struct uart_driver *drv = (struct uart_driver *)tty-driver-driver_state;struct uart_state *state;int retval, line = tty-index;BUG_ON(!kernel_locked();pr_debug(uart_open(%d) calledn, line);/* tty-driver-num wont change, so we wont fail he

19、re with* tty-driver_data set to something non-NULL (and therefore* we wont get caught by uart_close().*/retval = -ENODEV;if (line = tty-driver-num)goto fail;/* We take the semaphore inside uart_get to guarantee that we wont* be re-entered while allocating the info structure, or while we* request any

20、 IRQs that the driver may need. This also has the nice* side-effect that it delays the action of uart_hangup, so we can* guarantee that info-tty will always contain something reasonable.*/state = uart_get(drv, line);if (IS_ERR(state) retval = PTR_ERR(state);goto fail;/* Once we set tty-driver_data h

21、ere, we are guaranteed that* uart_close() will decrement the driver module use count.* Any failures from here onwards should not touch the count.*/tty-driver_data = state;tty-low_latency = (state-port-flags & UPF_LOW_LATENCY) ? 1 : 0;tty-alt_speed = 0;state-info-tty = tty;/* If the port is in the mi

22、ddle of closing, bail out now.*/if (tty_hung_up_p(filp) retval = -EAGAIN;state-count-;mutex_unlock(&state-mutex);goto fail;/* Make sure the device is in D0 state.*/if (state-count = 1)uart_change_pm(state, 0);/* Start up the serial port.*/retval = uart_startup(state, 0);/* If we succeeded, wait unti

23、l the port is ready.*/if (retval = 0)retval = uart_block_til_ready(filp, state);mutex_unlock(&state-mutex);/* If this is the first open to succeed, adjust things to suit.*/if (retval = 0 & !(state-info-flags & UIF_NORMAL_ACTIVE) state-info-flags |= UIF_NORMAL_ACTIVE;uart_update_termios(state);fail:r

24、eturn retval;在这里函数里,继续完成操作的设备文件所对应state初始化.现在用户空间open这个设备了.即要对这个文件进行操作了.那uart_port也要开始工作了.即调用uart_startup()使其进入工作状态.当然,也需要初始化uart_port所对应的环形缓冲区circ_buf.即state-info- xmit.特别要注意,在这里将tty-driver_data = state;这是因为以后的操作只有port相关了,不需要去了解uart_driver的相关信息.跟踪看一下里面调用的两个重要的子函数. uart_get()和uart_startup().先分析uart_

25、get().代码如下:static struct uart_state *uart_get(struct uart_driver *drv, int line)struct uart_state *state;int ret = 0;state = drv-state line;if (mutex_lock_interruptible(&state-mutex) ret = -ERESTARTSYS;goto err;state-count ;if (!state-port | state-port-flags & UPF_DEAD) ret = -ENXIO;goto err_unlock;

26、if (!state-info) state-info = kzalloc(sizeof(struct uart_info), GFP_KERNEL);if (state-info) init_waitqueue_head(&state-info-open_wait);init_waitqueue_head(&state-info-delta_msr_wait);/* Link the info into the other structures.*/state-port-info = state-info;tasklet_init(&state-info-tlet, uart_tasklet

27、_action,(unsigned long)state); else ret = -ENOMEM;goto err_unlock;return state;err_unlock:state-count-;mutex_unlock(&state-mutex);err:return ERR_PTR(ret);从代码中可以看出.这里注要是操作是初始化state-info.注意port-info就是state-info的一个副本.即port直接通过port-info可以找到它要操作的缓存区.uart_startup()代码如下:static int uart_startup(struct uart_

28、state *state, int init_hw)struct uart_info *info = state-info;struct uart_port *port = state-port;unsigned long page;int retval = 0;if (info-flags & UIF_INITIALIZED)return 0;/* Set the TTY IO error marker - we will only clear this* once we have successfully opened the port. Also set* up the tty-alt_

29、speed kludge*/set_bit(TTY_IO_ERROR, &info-tty-flags);if (port-type = PORT_UNKNOWN)return 0;/* Initialise and allocate the transmit and temporary* buffer.*/if (!info-xmit.buf) page = get_zeroed_page(GFP_KERNEL);if (!page)return -ENOMEM;info-xmit.buf = (unsigned char *) page;uart_circ_clear(&info-xmit

30、);retval = port-ops-startup(port);if (retval = 0) if (init_hw) /* Initialise the hardware port settings.*/uart_change_speed(state, NULL);/* Setup the RTS and DTR signals once the* port is open and ready to respond.*/if (info-tty-termios-c_cflag & CBAUD)uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);if (info-flags & UIF_CTS_FLOW) spin_lock_irq(&port-lock);if (!(port-ops-get_mctrl(port) & TIOCM_CTS)info-tty-hw_stopped = 1;spin_unl

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1