by cszhao1980
我们终于到达了本书的最后一章,它涉及的是慢速、面向字符外部设备的输入和输出。
同块设备一样,unix v6使用一个“设备switch” struct来进行设备操控。
4635: struct cdevsw {
4636: int (*d_open)();
4637: int (*d_close)();
4638: int (*d_read)();
4639: int (*d_write)();
4640: int (*d_sgtty)();
4641: } cdevsw[];
而cdevsw[]数组内记录整个系统的字符设备配置信息——在我们的模型里,共有5种有效的字符
设备,如下所示:
4669: int (*cdevsw[])()
4670: {
4671: &klopen, &klclose, &klread, &klwrite, &klsgtty, /* console */
4673: &pcopen, &pcclose, &pcread, &pcwrite, &nodev, /* pc */
4675: &lpopen, &lpclose, &lpread, &lpwrite, &nodev, /* lp */
4682: &nulldev, &nulldev, &mmread, &mmwrite, &nodev, /* mem */
4684: &nulldev, &nulldev, &rkread, &rkwrite, &nodev, /* rk */
……
}
(1) 第5种设备其实就是RK磁盘,但通过其配置可知,对它的读写是通过“原始io”函数进行的,
这样,在行为上,它也就变成了字符设备;
(2) 每个entry的第5个函数是settty函数,用来设置tty信息。
我们知道,unix将设备当做特殊的文件来进行处理,对设备文件,其inode中记录了特殊的信息:
(1) i_addr[0].d_major即为设备号;
(2) inode.i_mode&IFMT为设备类型,对字符设备而言,该值为IFCHR;
在上一章的读码过程中,您应该已经看到了大量的针对设备文件的代码。比如,在open文件时,
会调用到openi函数:
6710: maj = rip->i_addr[0].d_major;
6711: switch(rip->i_mode&IFMT) {
6712:
6713: case IFCHR:
6714: if(maj >= nchrdev)
6715: goto bad;
6716: (*cdevsw[maj].d_open)(dev, rw);
6717: break;
这样,在open设备文件时,就调用了实际的设备open函数。在close设备文件时,也有相似的代码:
6672: closei(ip, rw)
6682: switch(rip->i_mode&IFMT) {
6683:
6684: case IFCHR:
6685: (*cdevsw[maj].d_close)(dev, rw);
6686: break;
在读写操作时也会有类似的过程,从而能够完成实际的设备io,如下所示:
6221: readi(aip)
……
6233: if((ip->i_mode&IFMT) == IFCHR) {
6234: (*cdevsw[ip->i_addr[0].d_major].d_read)(ip->i_addr[0]);
6235: return;
6236: }
6276: writei(aip)
……
6286: if((ip->i_mode&IFMT) == IFCHR) {
6287: (*cdevsw[ip->i_addr[0].d_major].d_write)(ip->i_addr[0]);
6288: return;
6289: }
博客地址:http://blog.csdn.net/cszhao1980
博客专栏地址:http://blog.csdn.net/column/details/lions-unix.html