我对linux理解之tty四

我们上一节分析了tty_open,这一节我们分析tty_read。
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;//这open函数中有设置
    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);//从线路规程中读出数据
    else
        i = -EIO;
    tty_ldisc_deref(ld);//释放线路规程的引用
    if (i > 0)
        inode->i_atime = current_fs_time(inode->i_sb);
    return i;
}

我们看到调用线路规程的read操作,与上一节open同属一个ops,同理对应于n_tty_read:
static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
             unsigned char __user *buf, size_t 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++)) {//拷贝到user buffer里面
                        retval = -EFAULT;
                        b--;
                        break;
                    }
                    nr--;
                }
                if (eol) {
                    tty_audit_push(tty);
                    break;
                }
            }
            if (retval)
                break;
        } else {//原生数据,raw
            int uncopied;
            /* The copy function takes the read lock and handles
               locking internally for this case */
            uncopied = copy_from_read_buf(tty, &b, &nr);//拷贝read_buf数据到用户空间
            uncopied += copy_from_read_buf(tty, &b, &nr);
            if (uncopied) {
                retval = -EFAULT;
                break;
            }
        }

......
}

可以看到直接从read_buf中读取到用户空间。疑问来了,那这个read_buf的数据是怎么来的呢?还记得上一节分析的flush_to_ldisc 吗,对的,就是它。那里只是发现将buffer的值拷贝到read_buffer中。那到底源头数据是怎么来的呢?肯定是uart出来的,那它是怎么过来的呢?带着这个疑问我们去查看uart的中断函数:
static irqreturn_t mxcuart_int(int irq, void *dev_id)
{
......
        if (sr2 & MXC_UARTUSR2_RDR) {//当是读中断时,读有效的数据
            mxcuart_rx_chars(umxc);//读数据寒酸
        }

......
}
继续看mxcuart_rx_chars(umxc):
static void mxcuart_rx_chars(uart_mxc_port * umxc)
{
......
        uart_insert_char(&umxc->port, status, MXC_UARTURXD_OVRRUN, ch,
                         flag);//将接收到的字符插到tty buffer中,以备下面的刷到ldisc
          ignore_char:
        sr2 = readl(umxc->port.membase + MXC_UARTUSR2);
    }
    tty_flip_buffer_push(umxc->port.info->port.tty);//将tty buffer刷到线路规程
}
再看void tty_flip_buffer_push(struct tty_struct *tty)
{
    unsigned long flags;
    spin_lock_irqsave(&tty->buf.lock, flags);
    if (tty->buf.tail != NULL)
        tty->buf.tail->commit = tty->buf.tail->used;
    spin_unlock_irqrestore(&tty->buf.lock, flags);

    if (tty->low_latency)
        flush_to_ldisc(&tty->buf.work.work);//将buffer刷到read_buffer
    else
        schedule_delayed_work(&tty->buf.work, 1);//延时一个jiffies后执行上面flush_to_ldisc
}

那我们回到上一节INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc)部分了。:)呵呵,是不是联系起来了呢?!


http://qrsdev.com/forum.php?mod=viewthread&tid=399&extra=page%3D1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值