读和写方法都进行类似的任务, 可以同时介绍它们:
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);
对于 2 个方法, filp 是文件指针, count 是请求的传输数据大小. buff 参数指向持有被写入数据的缓存, 或者放入新数据的空缓存. 最后, offp 是一个指针指向一个"long offset type"对象, 它指出用户正在存取的文件位置. 返回值是一个"signed size type";
read 和 write 方法的 buff 参数是用户空间指针. 因此, 它不能被内核代码直接解引用. 为安全起见这个存取必须使用特殊的, 内核提供的函数. 我们介绍几个这样的函数(定义于 ),
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);
这 2 个函数的角色不限于拷贝数据到和从用户空间: 它们还检查用户空间指针是否有效. 如果指针无效, 不进行拷贝; 如果在拷贝中遇到一个无效地址, 另一方面, 只拷贝部分数据. 在 2 种情况下, 返回值是还要拷贝的数据量. scull 代码查看这个错误返回, 并且如果它不是 0 就返回 -EFAULT 给用户.
至于实际的设备方法, read 方法的任务是从设备拷贝数据到用户空间(使用 copy_to_user), 而 write 方法必须从用户空间拷贝数据到设备(使用 copy_from_user).
read 和 write 方法都在发生错误时返回一个负值. 相反, 大于或等于 0 的返回值告知调用程序有多少字节已经成功传送. 如果一些数据成功传送接着发生错误, 返回值必须是成功传送的字节数,
- ssize_t mem_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
- {
- struct mem_dev *dev = filp->private_data; // 获得私有数据指针
- int ret = 0;
-
- if(*f_pos > dev->size) // 判断文件是否已读完
- goto out;
- if(*f_pos + count> dev->size) // 如果读的数据过大
- count = dev->size - *f_pos;
- if(copy_to_user(buf,(void*)(dev->data + *f_pos),count)) // 返回数据至用户空间
- {
- ret = -EFAULT;
- goto out;
- }
- *f_pos += count;
- ret = count;
- out:
- return ret;
- }
- ssize_t mem_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
- {
- struct mem_dev *dev = filp->private_data; // 获得私有数据指针
- int ret = 0;
-
- if(*f_pos > MEMDEV_SIZE) // 判断文件是否已到结尾
- goto out;
- if(*f_pos + count > MEMDEV_SIZE) // 如果读的数据过大
- count = MEMDEV_SIZE - *f_pos;
- if(copy_from_user(dev->data + *f_pos,buf,count))
- {
- ret = -EFAULT;
- goto out;
- }
- *f_pos += count;
- ret = count;
- if (dev->size < *f_pos)
- dev->size = *f_pos;
-
- out:
- return ret;
- }
- struct file_operations my_fops =
- {
- .owner = THIS_MODULE,
- .open = mem_open,
- .release = mem_release,
- .read = mem_read,
- .write = mem_write,
- };