设备驱动(6)-file_operations

设备操作函数

  • open方法
            open方法用来初始化我们的设备通常完成以下工作:
            1)检查设备特定的错误
            2)如果设备是首次打开,则对其进行初始化
            3)如有必要,更新f_op指针
            4)分配并填写置于filep->private_data里的数据结构,便于驱动程序编别同一驱动程序所对应的不同设备
    我们可以使用container_of这个宏返回包含该字段的结构指针。
int scull_open(struct inode *inode, struct file *filp)
{
	struct scull_dev *dev;
	dev=container_of(inode->i_cdev, struct scull_dev, cdev);
	filp->private_data = dev;//for other methods
	// ...
}
  • release方法
           1)释放由open分配的、保存在filp->private_data中的所有内容
           2)在最后一次关闭操作时关闭设备。
    如果出现了关闭设备文件的次数比打开它的次数多时,系统会发生什么呢?
           并不是所有的close系统调用都会引起对于release方法的调用,只有那些真正释放设备数据结构的close调用才会调用release方法。内核对于每个file结构维护其被使用多少次的计数器。无论是dup还是fork,都不会创建新的数据结构(仅由open创建),他们只是增加已有结构中的计数,只有在file结构的计数归0时,close系统调用会执行release方法,这只在删除这个结构时才会发生。release和close方法的关系保证了每open一次就只会release一次。
           flush方法在应用程序每次调用close时都会被调用。不过很少有驱动程序会去实现flush,因为在close时并没有什么操作需要进行。
    如果出现了没有关闭设备文件的操作呢?
           内核会在进程退出的时候,通过在内部使用close系统调用自动关闭所有相关的文件。
  • 内核内存管理函数
void *kmalloc(size_t size, int flags);
void kfree(void *ptr);

       对于kmalloc的调用将试图分配size个字节大小的内存;其返回值为指向该内存的指针,分配失败时返回NULL,flags参数用来描述内存的分配方法,我们目前只会用到GFP_KERNEL,由这个函数分配的内存应该通过kfree释放。我们不应该将非kmalloc返回的指针传递给kfree。但是给kfree传递一个空指针是合法的。

  • read和write方法
    ssize_t read(struct file *filp, char __user *buff, size_t count, loff_t *offp);
    ssize_t write(struct file *filp, const char __user *buff, size_t count, loff_t *offp);
           filp:文件指针
           count:请求传输的数据长度
           buff:指向用户空间的缓冲区
           offp是一个指向 long offset type对象的指针,这个对象用于指明用户在文件中进行存取操作的位置。
           返回值是signed size type类型。
           在实现过程中我们不能直接引用用户地址空间中的内容,但是我们又需要访问用户空间中的内容。因此,内核给我们提供了几个内核函数来确保在内核和用户空间之间安全、正确的交换数据。例如以下两个函数:
#include <asm/uaccess.h>
unsigned long copy_to_user(void __user *to, const void *from, unsigned long count);
unsigned long copy_from_user(void *to, const void __user  *from, unsigned long count);

       这两个函数的作用并不限于在内核空间和用户空间之间拷贝数据,他们还检查用户空间的指针是否有效。如果指针无效,就不会进行拷贝;另一方面,如果在拷贝过程中遇到无效地址,则仅仅会复制部分数据。在这两种情况下,返回值是还需要拷贝的内存数量。如果不需要检查用户空间的指针,那么建议直接使用__copy_to_user和__copy_from_user。在预先知道参数已经检查过的时候,这两个函数非常有用。
       无论read或者是write方法传输了多少数据,都应该更新offp锁代表的文件位置,以便反映在新系统调用成功之后当前文件的位置。操作系统会在恰当的时机将offp更新回file结构体的f_pos中。
       出错时,read和write方法都返回一个负值,大于等于0的返回值告诉调用程序成功传输了多少个字节。如果在正确传输部分数据之后发生了错误,则返回值必须是成功传输的字节数,但这个错误只能在下一次函数调用时才能得到报告。当然,这种实现惯例要求驱动程序必须记住错误的发生,这样才能把错误状态返回给应用程序。
       如果发生了错误,返回值要可以指明发生了什么错误,错误码在<linux/errno.h>中定义。比如:-EINTR(系统调用被中断)或-EFAULT(无效地址)。
       无论这些方法传输了多少数据,一般而言都应该更新* offp所表示的文件位置,以便反映在新系统调用成功完成之后当前的文件位置。在恰当的时候,内核会将文件位置的改变传播回file结构。

read方法的返回值

1)如果返回值等于传递给read系统调用的count参数,则说明所请求的字节数传递成功完成了,这是最理想的情况
2)如果返回值是正的,但是比count小,则说明只有部分数据成功传递。
3)如果返回值为0,则表示已经到达了文件尾
4)负值意味着发生了错误,该值指明了发生了什么错误,错误码在<linux/errno.h>中定义。
write方法的返回值
1)如果返回值等于count,则完成了所请求数据的字节传送
2)如果返回值是正的,但是小于count,则只传输了部分数据
3)如果值为0,意味着什么也没有写入,这并不是错误,而且没有理由返回一个错误码。
4)负值意味着错误

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值