异步通知:
用户程序需完成两个步骤:

1、指定属主进程owner

使用fcntl系统调用的F_SETOWN,属主进程的进程ID就被保存在filp->f_owner中 2、真正启用异步通知机制

在设备中设置FASYNC标志,通过fcntl的F_SETFL

执行完这两个步骤后,输入文件就可以在新数据到达时请求发送一个SIGIO信号,该信号发送到filp->f_owner中保存的进程(负值为进程组)


不是所有设备都支持异步通知,我们也可以选择不提供异步通知功能,应用程序通常假设只有套接字和终端才有异步通知能力。当多于一个文件可以异步通知时,进程收到信号仍然必须借助poll或select来确定输入的来源。


驱动程序中的实现:

1、F_SETOWN被调用时对filp->f_owner赋值,此外什么也不做

2、在执行F_SETFL启用FASYNC时,调用驱动程序的fasync方法,只要file->f_flags中的FASYNC标志发生变化,就会调用该方法,以便把这个变化通知驱动程序,使其能正确响应。文件打开时,FASYNC标志会被默认为是清除的。

3、当数据到达时,所有注册为异步通知的进程都会被发送一个SIGIO信号。


设备数据结构中应该有异步通知列表,以下函数添加列表:

int fasync_helper(int fd, struct file *filp, int mode, struct fasync_struct **fa);


和wait_queue的实现差不多,使用以下函数在数据到来时通知异步列表中文件的属主进程:

int kill_fasync(struct fasync_struct **fa, int sig, int band);


文件关闭时需从异步通知列表中删除filp


定位设备:

llseek实现:

如果不实现llseek方法,内核默认修改filp->f_pos来执行定位。

某些设备是不能定位的,例如串口和键盘,应该在open方法中调用onseekable_open,以便通知内核设备不支持llseek:

int nonseekable_open(struct inode* inode, struct file *filp);

上述调用会把给定的filp标记为不可定位,lseek和pread、pwrite的调用会失败。