2 FreeBSD 核心( 五 )


ufs_write()则要考虑到文件大小的延伸 。




FreeBSD核心探讨.8.驱动程序篇


2.3 Device Driver
进程的io要求到这里说的差不多了 。上面也解说了对于文字型,块型的驱动程序接口,就
是dev_spec_vnodeop_opv_desc里定义的子函数那些 。参考设备驱动程序,在sys/conf.h
里定义的结构体 。block型是
struct bdevsw{
d_open_t *d_open;
d_close_t *d_close;
d_strategy_t *d_strategy;
d_ioctl_t *d_ioctl;
d_dump_t *d_dump;
d_psize_t *d_psize; /*得到容量*/
int *d_flags;
char *d_name; /*device 名*/
struct cdesw *d_cdev; /*对应的文字型*/
int d_maj; /*major号*/
}
文字型的则是
struct cdevsw{
d_open_t *d_open;
d_close_t *d_close;
d_read_t *d_read; /* rawread() */
d_write_t *d_write; /* rawwrite()*/
d_ioctl_t *d_ioctl;
d_stop_t *d_stop; /* nostop()*/
d_reset_t *d_reset; /* nullreset()*/
d_devtotty_t *d_devtotty; /* nodevtotty*/
d_select_t *d_select; /* deltrue*/
d_mmap_t *d_mmap; /* nommap*/
d_strategy_t *d_strategy
char *d_name; /*device名*/
struct bdevsw *d_bdev; /*对应block型*/
int d_may; /*major号*/
}


两方面共同的部分有
xx_open(dev_t dev,int oflags,int devtype,struct proc *p)
xx_close(dev_t dev,int fflag,int devtype,struct proc *p)
xx_ioctl(dev_t dev,int cmd,CADdr_t data,int fflag,struct proc *p)
xx_open()用于打开device号的设备 。xx_close()则用于关闭它 。xx_ioctl()则对设备的
动作状态,机能的取得,设置等进行控制,它通过int cmd命令和参数caddr_t data对之
进行处理 。xx_open()的oflags则是系统调用open()里指定的标志 。xx_close()和
xx_ioctl()的fflag是每个文件描述符设定的标志 。int devtype用来区别设备类型是文
字型的还是块型的 。struct proc *p是本次要求的进程号 。

在文字型的操作里,有这三个函数
xx_read(dev_t dev,struct uio *uio,int ioflag)
xx_write(dev_t dev,struct uio *uio,int ioflag)
xx_select(dev_t dev,int which, struct proc *p)
xx_read()/xx_write()是对device号的io,struct uio *uio 是io的buffer,int ioflag
标志io动作的option 。例如,输入data没准备好的场合不用进入等待状态也可以 。
xx_select()检查是否可以进行io要求 。
在块设备的操作中,有一个函数
xx_strategy(struct buf *bp)
它处理io要求 。struct buf *bp里面包含着device号,输入还是输出,io的buffer等 。

device号中的major号,对文字型的struct cdevsw *cdevsw[],对块型的struct
bdevsw *bdevsw[],作为配列的添加字使用 。向这些配列登记,就可以调出device driver
的登记routine 。
对cdevsw[]登记的过程在kern/kern_conf.c,它使用
int cdevsw_add(
dev_t *descrip, /*收集device号的变量的指针*/
struct cdevsw *newentry,/*设置struct cdevsw的指针*/
struct cdevsw **oldentry,/*旧的设定内容的返回领域*/
)
另一方面,对bdevsw[]的登记过程则使用
int bdevsw_add_generic(
int bdev, /*block型的major号*/
int cdev, /*文字型的major浩*/
struct bdevsw *bdevsw, /*设定struct bdevsw的指针,对应d_cdev*/
)
block型的device和char型的device有着一定的对应关系 。这些结构体相互参考 。
bdevsw_add_generic()从block的结构体开始,对作为char型的device的结构体进行初始化 。
还有,network interface的devive driver,并没有向cdevsw[]和bdevsw[]登记 。而且也没有
device号 。网络间的package流,和进程间与网络间的package流也没有特别指明 。
调用登记routine的时候,可以把文件系统的modules作为特殊设备文件参考 。登记
routine在什么地方都可以调用 。
。main()(@kern/init_mail.c)的初始化过程中登记的routine调用的时候,各个
device driver的modules里由宏SYSINIT()准备进行 。
。确认device driver里的io设备的存在的时候,调用登记routine 。

推荐阅读