您的位置:首页 > 运维架构 > Linux

我对linux理解之tty四

2012-08-10 14:33 176 查看
我们上一节分析了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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: