那么char_buf_ptr的数据怎样与线路规程中的read_buf关联的呢,我们看,在初始化tty_buffer的时候,也就是在tty_buffer_init函数中:
void tty_buffer_init(struct tty_struct *tty)
{
spin_lock_init(&tty->buf.lock);
tty->buf.head= NULL;
tty->buf.tail= NULL;
tty->buf.free= NULL;
tty->buf.memory_used= 0;
INIT_DELAYED_WORK(&tty->buf.work,flush_to_ldisc);
}
在函数的最后,初始化了一个工作队列。
而这个队列在什么时候调度呢,在驱动层里receive_chars的最后调用了tty_flip_buffer_push这个函数。
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);
else
schedule_delayed_work(&tty->buf.work, 1);
}
那么,在push数据到tty_buffer的时候有两种方式,一种是flush_to_ldisc,另一种就是调度tty缓冲区的工作队列。
flush_to_ldisc是队列调用的函数:
static void flush_to_ldisc(struct work_struct *work)
{
……
while((head = tty->buf.head) != NULL) {
…...
count= head->commit – head->read;
…...
char_buf= head->char_buf_ptr + head->read;
flag_buf= head->flag_buf_ptr + head->read;
head->read+= count;
disc->ops->receive_buf(tty,char_buf,
flag_buf,count);
…...
}
……
}
这个函数主要的功能是,从tty_buffer中找到数据缓冲区char_buf_ptr,并将这个缓冲区指针传递给线路规程的操作函数receive_buf。再来看receive_buf:
static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char*cp,
char *fp, int count)
{
……
if(tty->real_raw) {
…...
memcpy(tty->read_buf+ tty->read_head, cp, i);
…...
}else{
…...
switch(flags) {
caseTTY_NORMAL:
n_tty_receive_char(tty,*p);
break;
……
}
if(tty->ops->flush_chars)
tty->ops->flush_chars(tty);
…...
}
…...
}
从上面这段代码可以看到,if条件成立,明显地是拷贝数据进tty的read_buf;进入else,在正常的状态下会调用n_tty_receive_char,然后会调用put_tty_queue,在这个函数里最终还是把数据拷贝到tty的read_buf中。