2、read函数
驱动module的file_operations结构体中可以定义很多设备操作服务函数,但是我现在关心的是这些函数怎样与系统调用,或者说是外部应用程序交互,而不管具体的设备操作怎么实现,所以只记录read函数作为代表。
read函数的原型如下:
ssize_t read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
read函数原型中有4个参数,分别是filp,buf,count和f_pos。
其中file结构体指针参数可以用来确定我们要操作的设备,因为在open函数中,我们将代表设备的结构体保存到了filp的private_data字段中。
buf 参数是一个指向用户空间的buffer的指针(buf前面的__user表示用户空间),对于read来说,就是可以把要传送给外部应用程序的数据放入这个buffer中。当然,我们不能简单地将数据copy到这个buffer中,而是要使用Linux内核提供的一些函数,比如copy_to_user函数。
count是请求传送的数据长度。
f_pos是一个指向“long offset type”对象的指针,指明外部应用程序在文件中进行存取操作的位置。
read函数的返回值是有符号整数类型的指,一般是read操作的实际存取数。
3、release函数
release函数的作用正好与open相反,有时候release函数的实现被称为device_close,而不是device_release。但无论那种形式,这个设备方法都应该完成如下任务:
a、释放open分配的,保存在file->private_data中的所有内容。
b、在最后一次关闭操作时关闭设备。
relese函数由close系统调用引起,但并不是每一次close系统调用都会引起release函数的调用。只有那些真正释放设备数据结构的close系统调用才会引起release函数的调用。因为Linux内核为每个 file结构体维护其被引用多少次的计数器,只有当file结构体的计数器归0时,close系统调用才会引用release函数,这只在删除这个结构时才会发生,因此每次open驱动程序都只会看到一次对应的一次release调用。
四、 卸载驱动module
每个重要的模块都需要一个清除函数,该函数在模块被移除前注销接口并向系统中返回所有资源。如果一个模块未定义清除函数,则内核不允许卸载该模块。
Linux 驱动module的卸载可以用/sbin/rmmod scull.ko命令,这时Linux内核就会调用驱动程序中用module_exit(scull_cleanup_module)特殊宏定义的清除函数,也就是说,module_exit声明用来帮助Linux内核找到模块的清除函数,在scull程序中,清除函数就是 scull_cleanup_module函数。
模块的清除函数需要撤销初始化函数注册的所有资源,并且习惯上(但不是必须的)以与初始化函数注册相反的顺序进行撤销。需要注意的是,这里指的初始化函数是指用module_init宏声明的初始化函数,而不是指open函数,与open函数对应的应当是release函数。
在scull程序中,清除函数主要做了两件事:一是free了所有为scull设备分配的内存;二是收回了初始化函数所注册的设备号。
