|
详解Linux操作系统设备驱动兼容性(3) long (*read) (struct inode *, struct fle *, char *, unsigned long); long (*write) (struct inode *, struct file *, const char *, unsigned long); int (*release) (struct inode *, struct file *); 它们在2.0中的对应者是: int (*lseek) (struct inode *, struct file *, off_t, int); int (*read) (struct inode *, struct file *, char *, int); int (*write) (struct inode *, struct file *, const char *, int); void (*release) (struct inode *, struct file *);
如你所见的,其不同在于它们的返回值(它允许了更大的范围),还有count和offset参数。头文件sysdep-2.1.h通过定义下面的宏处理这些不同:
read_write_t这个宏扩展为参数count的类型以及read和write的返回值。
lssek_t这个宏扩展为llseek的返回值类型。方法名字的改变(从lseek到llseek)并不是个问题,因为你一般在file_operations中并不用名字对域赋值,而是声明一个静态结构。
lseek_off_t lseek的offset参数。
release_t release方法的返回值;或为void或为int。
release_return( int return_value)这个宏可以用来从release方法返回。它的参数用来返回一个错误代码:0表示成
功,负值表示失败。在比2.1.31老的核心中,这个宏扩展为return,因为这个方法返回void。
用前面的宏,一个可移植的驱动程序原型是:
lseek_t my_lseek(struct inode *, struct file *, lseek_off_t, int); read_write_t my_read(struct inode *, struct file *, char *, count_t); read_write_t my_write(struct inode *, struct file *, const char *, count_t); release_t my_release(struct inode *, struct file *);
poll方法 2.1.23引入了poll系统调用,它是system V中select的对应者(由BSD Unix引入)。不幸的是不可能在select设备方法之上实现poll的功能,所以整个实现用不同的一个代替,它作为select和poll的后端。
在当前版本的核心中,file_operations中的设备方法也叫poll,与系统调用类似,因为其内部模仿这个系统调用。这个方法的原型是:unsigned int (*poll) (struct file *, poll_table *);
驱动程序中设备特定的实现主要完成两个任务:
l 在一个可能在将来唤醒它的等待队列中将当前进程排队。通常,这意味着同时在输入和输出队列中对进程排队。函数poll_wait被用于这个目的,其工作方式与select_wait非常类似(细节请看第五章“增强的字符设备驱动程序操作”中“select”一节)。
2 构造一个位掩码描述设备的状态,并将其返回给调用者。这些位的值是平台特定的,在中定义,它必须被包含在驱动程序中。在讲述位掩码的每一位前,我想给出一个典型的实现。下面的函数是v2.1/scull/pipe.c的一部分,是/dev/scullpipe的poll方法的实现。scullpipe的内部在第五章介绍过。
如你所看到的,这个代码相当简单。它比对应的select方法要容易。至于select,状态位计为“可读”、“可写”,或“发生例外”(这是select的第三个条件)。poll各位的完全列表在下面给出。“输入”位列在前面,然后是“输出”,一个“例外”位列在最后。
POLLIN如果设备可以被无阻塞地读,那么这个位必须被设置。
POLLRDNORM如果“一般”数据可以被读,这个位必须被设。一个可读设备返回(POLLIN
POLLRDNORM)。POLLRDBAND在目前的核心源码中这个位不被使用。Unix System V使用这个位报告非0优先级的数据可读。数据优先级的概念与“Streams”包相关。
POLLHUP当一个读设备的进程看到文件结尾时,驱动程序必须设置POLLHUP(挂起)。一个调用select的进程将被告知设备可读,这由select的功能说明。
POLLERR设备上发生了一个错误条件。当poll被select系统调用调用时,设备被报告为既可读又可写,因为read或write将无阻塞地返回一个错误代码。
POLLOUT如果设备可以被无阻塞地写,这个位在返回值中被设置。
POLLWRNORM这个位与POLLOUT有相同的含义,有时甚至的确为同一个数。一个可写的设备返(POLLOUT POLLWRNORM)。
POLLWRBAND与POLLRDBAND类似,这个位意味着非0优先级的数据可以被写到设备。只有poll的“数据
报”实现用到着位,因为一个数据报可以传送“无团队数据(out-of-band data)”。select报告设备是可写的。
POLLPRI高优先级的数据(“无团队的”)可以被无阻塞地读取。这个位导致select报告文件上发生了一个例外条件,因为select将无团队包作为一个例外条件报告。
poll的主要问题是它与2.0核心所使用的select方法没有任何关系。因此,处理这个不同的最好方法是使用条件编译来编译合适的函数,而且同时将它们都包含在源文件中。如果当前版本支持select而不是poll,那么头文件sysdep-2.1.h定义符号__USE_OLD_SELECT__。这将你从在源码中必须引用LINUX_VERSION_CODE中解脱出来。这两个函数用同样的名字调用,因为在结构sample_fops中sample_poll被引用,那里poll文件操作代替了select方法。
访问用户空间
|