------------------------------------------
本文系本站原创,欢迎转载!
------------------------------------------我们上一节分析了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)部分了。:)呵呵,是不是联系起来了呢?!
阅读(2184) | 评论(0) | 转发(2) |