博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
串口驱动(五)
阅读量:3899 次
发布时间:2019-05-23

本文共 2300 字,大约阅读时间需要 7 分钟。

1. 用户空间read的操作实现

static ssize_t tty_read(struct file *file, char __user *buf, size_t count, loff_t *ppos){	int i;	struct tty_struct *tty = file_tty(file);	struct tty_ldisc *ld;	ld = tty_ldisc_ref_wait(tty);	/* 获取tty对应的线路规程ldisc,和tty_write是一样的,可以回看串口驱动(四) */	if (ld->ops->read)		i = (ld->ops->read)(tty, file, buf, count);   /* ld->ops->read即n_tty_read */	else		i = -EIO;	tty_ldisc_deref(ld);	return i;}static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,			 unsigned char __user *buf, size_t nr){	struct n_tty_data *ldata = tty->disc_data;	unsigned char __user *b = buf;	DECLARE_WAITQUEUE(wait, current);	if (!ldata->icanon) 		/*icanon默认为1,icanon表示标准模式*/		······	add_wait_queue(&tty->read_wait, &wait);	while (nr) {		set_current_state(TASK_INTERRUPTIBLE);		if (!input_available_p(tty, 0)) {		/*没有可读数据时会休眠*/			timeout = schedule_timeout(timeout);		/*定时休眠*/			continue;		}		__set_current_state(TASK_RUNNING);		if (ldata->icanon && !L_EXTPROC(tty)) {			while (nr && ldata->read_cnt) {				int eol;				eol = test_and_clear_bit(ldata->read_tail,						ldata->read_flags);				c = ldata->read_buf[ldata->read_tail];		/*从tty线路规程的缓冲区ldata->read_buf读数据*/				ldata->read_tail = ((ldata->read_tail+1) &						  (N_TTY_BUF_SIZE-1));				ldata->read_cnt--;								raw_spin_unlock_irqrestore(&ldata->read_lock, flags);				if (!eol || (c != __DISABLED_CHAR)) {					if (tty_put_user(tty, c, b++)) {	/*将读到的数据放入用户buffer*/						retval = -EFAULT;						b--;						raw_spin_lock_irqsave(&ldata->read_lock, flags);						break;					}					nr--;				}				raw_spin_lock_irqsave(&ldata->read_lock, flags);			}			raw_spin_unlock_irqrestore(&ldata->read_lock, flags);		} 	}	remove_wait_queue(&tty->read_wait, &wait);	return retval;}

        write的数据为什么是从tty线路规程的buffer里读取,这一点可以回看串口驱动(三)的分析线路2-3部分。

2. 总结

2.1 DMA

        关于DMA搬运地址的配置,在open时会同时配置发送消息时DMA搬运的目标地址和接收消息时DMA搬运的源地址。因为发送数据时要将数据搬运到哪个地址是确定的,但是从哪个地址搬运数据是不确定的,接收数据时则反之。

        不确定的那个地址,会在启动DMA搬运的时候进行配置。

2.2 write和read的不同

        write是SOC端主动发起的动作,所以DMA搬运的启动操作是在write函数的底层操作里调用的;而read是SOC端的被动操作,所以串口在open的时候就要启动DMA搬运,将数据搬运到tty 线路规程的一个buffer里,用户读的时候不用去底层读取,去线路规程的buffer里读取即可。

2.3 关于中断

        在IMX6d这款SOC的串口驱动中使用了DMA来搬运数据,比如串口发送数据的时候,将数据放到串口寄存器FIFO的步骤是由DMA 来完成的;但是三星的S5Pv210 这款SOC的串口驱动中并没有使用DMA来搬运数据,将数据放到串口寄存器FIFO的步骤是由中断服务程序来完成的,至于是为什么用中断服务程序来做FIFO填充的动作,我还是不太明白!我猜测是因为FIFO为空时会触发中断以唤醒上层,这得仔细研究它的数据手册了······

转载地址:http://hhuen.baihongyu.com/

你可能感兴趣的文章
【Java.Web】MVC —— Action的验证器 —— Validator
查看>>
【Java.Spring.MVC】使用Spring MVC构建Web应用程序
查看>>
【DB.PL/SQL】程序流程控制 —— 异常处理
查看>>
【Java.IO】I/O 【字节】【处理流】 - 之 - 【压缩流】 - ZipInputStream,ZipOutputStream
查看>>
【Java.JDBC/ORM】纯JDBC系统的开发随想
查看>>
【Unix/Linux】【系统】环境变量
查看>>
【Architecture】CPU-bound(计算密集型) 和I/O bound(I/O密集型)
查看>>
【MacOS】Mac 系统下类似于 apt-get 的软件包管理器 -- Homebrew
查看>>
为窗口添加鼠标HOVER和LEAVE事件
查看>>
VC小技巧20个
查看>>
MFC Feature Pack for Visual C++ 2008的BUG之一
查看>>
POJ - 2739 Sum of Consecutive Prime Numbers
查看>>
STL map映照容器(一)map创建、元素插入、元素删除和遍历访问
查看>>
Leetcode - 557反转字符串中的单词III
查看>>
Leetcode - 160相交链表
查看>>
Leetcode - 11盛最多水的容器
查看>>
Leetcode - 141环形链表
查看>>
Leetcode - 14最长公共前缀
查看>>
Leetcode - 7整数反转
查看>>
PAT---B1022. D进制的A+B (20)
查看>>