一、 tty设备,在用户空间看来也为字符型设备,从tty_register_driver()中可以看出
int tty_register_driver(struct tty_driver * driver)
{
...
cdev_init(&driver->cdev, &tty_fops);
...
}
二、 用户空间访问的API也及这里的tty_fops,
drivers/char目录下的n_tty.c,tty_io.c等文件中
static const struct file_operations tty_fops = {
.llseek = no_llseek,
.read = tty_read,
.write = tty_write,
.poll = tty_poll,
.unlocked_ioctl = tty_ioctl,
.compat_ioctl = tty_compat_ioctl,
.open = tty_open,
.release = tty_release,
.fasync = tty_fasync,
};
三、下面来看一下tty_read的实现
static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
...
ld = tty_ldisc_ref_wait(tty);
if (ld->ops->read)
i = (ld->ops->read)(tty, file, buf, count);
//调用到了ldisc层(线路规程)的read函数
else
i = -EIO;
tty_ldisc_deref(ld);
...
}
这里调用的线路规程里的函数,
四、线路规程的实现
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,
.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_write实现
static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
const unsigned char *buf, size_t nr)
{
...
add_wait_queue(&tty->write_wait, &wait);//将当前进程放到等待队列中
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
//进入此处继续执行的原因可能是被信号打断,而不是条件得到了满足。
//只有条件得到了满足,我们才会继续,否则,直接返回!
if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
retval = -EIO;
break;
}
if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
while (nr > 0) {
ssize_t num = process_output_block(tty, b, nr);
if (num < 0) {
if (num == -EAGAIN)
break;
retval = num;
goto break_out;
}
b += num;
nr -= num;
if (nr == 0)
break;
c = *b;
if (process_output(c, tty) < 0)
break;
b++; nr--;
}
if (tty->ops->flush_chars)
tty->ops->flush_chars(tty);
} else {
while (nr > 0) {
c = tty->ops->write(tty, b, nr);
//调用到具体的驱动中的write函数
if (c < 0) {
retval = c;
goto break_out;
}
if (!c)
break;
b += c;
nr -= c;
}
}
if (!nr)
break;
//全部写入,返回
if (file->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
break;
}
/*
假如是以非阻塞的方式打开的,那么也直接返回。否则,让出cpu,等条件满足以后再继续执行。
*/
schedule();//执行到这里,当前进程才会真正让出cpu!!!
}
break_out:
__set_current_state(TASK_RUNNING);
remove_wait_queue(&tty->write_wait, &wait);
...
}
从这里看以看出线路规程里的函数最终调用tty_struct里的ops函数
五、让让我们一起看看tty_struct里的ops是何时被赋值的
tty_open -> tty_init_dev -> initialize_tty_struct
driver/char/tty_io.c
void initialize_tty_struct(struct tty_struct *tty, struct tty_driver *driver, int idx)
{
...
tty->ops = driver->ops;
...
}
大家至此是否恍然大悟,好了,tty驱动至此基本结束,细节问题还要大家自己去解决。
六、接下来,简要分析一下serial驱动架构
请看下一篇