串口驱动分析-接收
来源:互联网 发布:淘宝情趣内衣模特 编辑:程序博客网 时间:2024/06/10 04:41
1.TTY数据接收
tty_read.c:
tty_ldisc_N_TTY:
n_tty_read:
copy_from_read_buf:
总结:应用APP-->TTY核心-->TTY线路规程(read_buf有就给APP,没有就阻塞);然后read_buf其实是串口驱动收到的,只是不是同时处理的。
二、串口驱动接收分析
s3c24xx_serial_rx_chars:
三、串口流控
当A向B发送数据时,B的缓冲如果满了。要向A发送一个FIFO满了的信号,这个就是流控:
分成软件(信号)、硬件(B的串口RTS设置成高电位,A的CTS就知道B已经满了)(又分成非自动、和自动)
tty_read.c:
- /**
- * tty_read - read method for tty device files
- * @file: pointer to tty file
- * @buf: user buffer
- * @count: size of user buffer
- * @ppos: unused
- *
- * Perform the read system call function on this terminal device. Checks
- * for hung up devices before calling the line discipline method.
- *
- * Locking:
- * Locks the line discipline internally while needed. Multiple
- * read calls may be outstanding in parallel.
- */
- static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos)
- {
- int i;
- struct tty_struct *tty;
- struct inode *inode;
- struct tty_ldisc *ld;
- tty = (struct tty_struct *)file->private_data;
- inode = file->f_path.dentry->d_inode;
- if (tty_paranoia_check(tty, inode, "tty_read"))
- return -EIO;
- if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
- return -EIO;
- /* We want to wait for the line discipline to sort out in this
- situation */
- ld = tty_ldisc_ref_wait(tty);
- if (ld->ops->read)
- i = (ld->ops->read)(tty, file, buf, count); //这里调用了线路规程中的read
- else
- i = -EIO;
- tty_ldisc_deref(ld);
- if (i > 0)
- inode->i_atime = current_fs_time(inode->i_sb);
- return i;
- }
- struct tty_ldisc_ops tty_ldisc_N_TTY = {
- .magic = TTY_LDISC_MAGIC,
- .name = "n_tty",
- .open = n_tty_open,
- .close = n_tty_close,
- .flush_buffer = n_tty_flush_buffer,
- .chars_in_buffer = n_tty_chars_in_buffer,
- .read = n_tty_read, //调用的read函数
- .write = n_tty_write,
- .ioctl = n_tty_ioctl,
- .set_termios = n_tty_set_termios,
- .poll = n_tty_poll,
- .receive_buf = n_tty_receive_buf,
- .write_wakeup = n_tty_write_wakeup
- };
- /**
- * n_tty_read - read function for tty
- * @tty: tty device
- * @file: file object
- * @buf: userspace buffer pointer
- * @nr: size of I/O
- *
- * Perform reads for the line discipline. We are guaranteed that the
- * line discipline will not be closed under us but we may get multiple
- * parallel readers and must handle this ourselves. We may also get
- * a hangup. Always called in user context, may sleep.
- *
- * This code must be sure never to sleep through a hangup.
- */
- static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
- unsigned char __user *buf, size_t nr)
- {
- unsigned char __user *b = buf;
- DECLARE_WAITQUEUE(wait, current);
- int c;
- int minimum, time;
- ssize_t retval = 0;
- ssize_t size;
- long timeout;
- unsigned long flags;
- int packet;
- .......
- /* This statement must be first before checking for input
- so that any interrupt will set the state back to
- TASK_RUNNING. */
- set_current_state(TASK_INTERRUPTIBLE); //设置当前进程的状态,后面调度后阻塞
- if (((minimum - (b - buf)) < tty->minimum_to_wake) &&
- ((minimum - (b - buf)) >= 1))
- tty->minimum_to_wake = (minimum - (b - buf));
- if (!input_available_p(tty, 0)) { //判断有没有数据可以读取
- if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
- retval = -EIO;
- break;
- }
- if (tty_hung_up_p(file))
- break;
- if (!timeout)
- break;
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- break;
- }
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- /* FIXME: does n_tty_set_room need locking ? */
- n_tty_set_room(tty);
- timeout = schedule_timeout(timeout); //调度,如果没有数据可读,让阻塞生效
- continue;
- }
- __set_current_state(TASK_RUNNING); //如果有数据,
- /* Deal with packet mode. */
- if (packet && b == buf) {
- if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
- retval = -EFAULT;
- b--;
- break;
- }
- nr--;
- }
- if (tty->icanon) {
- /* N.B. avoid overrun if nr == 0 */
- while (nr && tty->read_cnt) {
- int eol;
- eol = test_and_clear_bit(tty->read_tail,
- tty->read_flags);
- c = tty->read_buf[tty->read_tail];
- spin_lock_irqsave(&tty->read_lock, flags);
- tty->read_tail = ((tty->read_tail+1) &
- (N_TTY_BUF_SIZE-1));
- tty->read_cnt--;
- if (eol) {
- /* this test should be redundant:
- * we shouldn't be reading data if
- * canon_data is 0
- */
- if (--tty->canon_data < 0)
- tty->canon_data = 0;
- }
- spin_unlock_irqrestore(&tty->read_lock, flags);
- if (!eol || (c != __DISABLED_CHAR)) {
- if (tty_put_user(tty, c, b++)) {
- retval = -EFAULT;
- b--;
- break;
- }
- nr--;
- }
- if (eol) {
- tty_audit_push(tty);
- break;
- }
- }
- if (retval)
- break;
- } else {
- int uncopied;
- /* The copy function takes the read lock and handles
- locking internally for this case */
- uncopied = copy_from_read_buf(tty, &b, &nr); //从readbuf中读取shu
- uncopied += copy_from_read_buf(tty, &b, &nr);
- if (uncopied) {
- retval = -EFAULT;
- break;
- }
- }
- /* If there is enough space in the read buffer now, let the
- * low-level driver know. We use n_tty_chars_in_buffer() to
- * check the buffer, as it now knows about canonical mode.
- * Otherwise, if the driver is throttled and the line is
- * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
- * we won't get any more characters.
- */
- if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
- n_tty_set_room(tty);
- check_unthrottle(tty);
- }
- if (b - buf >= minimum)
- break;
- if (time)
- timeout = time;
- }
- mutex_unlock(&tty->atomic_read_lock);
- remove_wait_queue(&tty->read_wait, &wait);
- if (!waitqueue_active(&tty->read_wait))
- tty->minimum_to_wake = minimum;
- __set_current_state(TASK_RUNNING);
- size = b - buf;
- if (size) {
- retval = size;
- if (nr)
- clear_bit(TTY_PUSH, &tty->flags);
- } else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
- goto do_it_again;
- n_tty_set_room(tty);
- return retval;
- }
- static int copy_from_read_buf(struct tty_struct *tty,
- unsigned char __user **b,
- size_t *nr)
- {
- int retval;
- size_t n;
- unsigned long flags;
- retval = 0;
- spin_lock_irqsave(&tty->read_lock, flags);
- n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail);
- n = min(*nr, n);
- spin_unlock_irqrestore(&tty->read_lock, flags);
- if (n) {
- retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n); //read_buf就是读缓冲
- n -= retval;
- tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
- spin_lock_irqsave(&tty->read_lock, flags);
- tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
- tty->read_cnt -= n;
- spin_unlock_irqrestore(&tty->read_lock, flags);
- *b += n;
- *nr -= n;
- }
- return retval;
- }
二、串口驱动接收分析
s3c24xx_serial_rx_chars:
- static irqreturn_t
- s3c24xx_serial_rx_chars(int irq, void *dev_id)
- {
- struct s3c24xx_uart_port *ourport = dev_id;
- struct uart_port *port = &ourport->port;
- struct tty_struct *tty = port->info->port.tty;
- unsigned int ufcon, ch, flag, ufstat, uerstat;
- int max_count = 64; //一次中断最多64字符
- while (max_count-- > 0) {
- ufcon = rd_regl(port, S3C2410_UFCON); //读取了UFCON寄存器
- ufstat = rd_regl(port, S3C2410_UFSTAT); //读取UFSTAT
- if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0) //如果接收FIFO数据量为0,则退出
- break;
- uerstat = rd_regl(port, S3C2410_UERSTAT); //读取uerstat
- ch = rd_regb(port, S3C2410_URXH); //取出接收到的数据
- if (port->flags & UPF_CONS_FLOW) { //流控处理
- int txe = s3c24xx_serial_txempty_nofifo(port); //判断发送缓冲是否为空
- if (rx_enabled(port)) { //如果port接收功能是使能的
- if (!txe) { //如果txe为0
- rx_enabled(port) = 0;
- continue;
- }
- } else {
- if (txe) { //如果txe为1
- ufcon |= S3C2410_UFCON_RESETRX;
- wr_regl(port, S3C2410_UFCON, ufcon);
- rx_enabled(port) = 1;
- goto out;
- }
- continue;
- }
- }
- /* insert the character into the buffer */
- flag = TTY_NORMAL;
- port->icount.rx++;
- if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) { //根据USRSTAT寄存器的值,
- dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
- ch, uerstat);
- /* check for break */
- if (uerstat & S3C2410_UERSTAT_BREAK) {
- dbg("break!\n");
- port->icount.brk++;
- if (uart_handle_break(port))
- goto ignore_char;
- }
- if (uerstat & S3C2410_UERSTAT_FRAME)
- port->icount.frame++;
- if (uerstat & S3C2410_UERSTAT_OVERRUN)
- port->icount.overrun++;
- uerstat &= port->read_status_mask;
- if (uerstat & S3C2410_UERSTAT_BREAK)
- flag = TTY_BREAK;
- else if (uerstat & S3C2410_UERSTAT_PARITY)
- flag = TTY_PARITY;
- else if (uerstat & (S3C2410_UERSTAT_FRAME |
- S3C2410_UERSTAT_OVERRUN))
- flag = TTY_FRAME;
- }
- if (uart_handle_sysrq_char(port, ch)) //如果收到的是sysrq字符,进行特殊处理
- goto ignore_char;
- uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, //把接收到的字符送进串口驱动的buf_uart_insert_char
- ch, flag);
- ignore_char:
- continue;
- }
- tty_flip_buffer_push(tty); //把串口驱动收到的数据送进线路规程的read_buf
- out:
- return IRQ_HANDLED;
- }
三、串口流控
当A向B发送数据时,B的缓冲如果满了。要向A发送一个FIFO满了的信号,这个就是流控:
分成软件(信号)、硬件(B的串口RTS设置成高电位,A的CTS就知道B已经满了)(又分成非自动、和自动)
0
上一篇:串口驱动分析-发送
下一篇:串口驱动编程实现
相关热门文章
- SHTML是什么_SSI有什么用...
- 查看linux中某个端口(port)...
- 卡尔曼滤波的原理说明...
- shell中字符串操作
- 关于java中的“错误:找不到或...
给主人留下些什么吧!~~
评论热议
阅读全文
0 0
- 串口驱动分析-接收
- Linux串口驱动程序(5)-串口接收分析
- 串口驱动分析
- WinCE串口驱动分析
- wince串口驱动分析
- 转:串口驱动分析
- WinCE串口驱动分析
- 串口驱动分析
- wince 串口驱动分析
- WinCE串口驱动分析
- 串口驱动分析
- linux串口驱动分析
- linux串口驱动分析
- linux串口驱动分析
- linux串口驱动分析
- linux串口驱动分析
- linux串口驱动分析
- linux串口驱动分析
- 总线设备驱动模型和平台设备模型
- tty驱动程序架构
- 串口驱动分析-初始化
- 串口驱动分析-打开设备
- 串口驱动分析-发送
- 串口驱动分析-接收
- Qt学习之路(60): 创建shared library
- getWriter() has already been called for this response 的解决办法
- 怎么安装wheel
- 网卡驱动架构分析
- linux shell 数组建立及使用技巧
- 回环网卡驱动设计
- Fragment加载替换add,show,hide,replace方法
- NDK开发 从入门到放弃(七:Android Studio 2.2 CMAKE 高效NDK开发)
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
怎样拆球形锁
球形锁锁舌怎么拆
球锁安装图
球形锁安装图解
球形门锁锁芯结构图
怎么换球形门锁
球形门锁反锁
球型门锁怎么安装
球形门锁怎么拆图解
怎么安装球形门锁
球形门锁拆装
如何换球形门锁
球形门锁拆卸
球形门锁怎么拆
高级球形门锁怎么安装
如何拆球形门锁
球形门锁怎么安装图解
球镜和柱镜什么意思
球镜与度数对照表
球镜
球镜怎么换算成度数
球镜度数是什么意思
球阀门
球阀图片
球阀开关方向示意图
球阀结构图
球阀型号
不锈钢球阀批发
球阀尺寸对照表
法兰球阀
手动球阀
气源球阀
自来水球阀
电动软密封球阀
耐高温球阀
夹套保温球阀
硬密封球阀
不锈钢高温球阀
不锈钢气动球阀
丝口球阀
液压球阀