【内核&驱动】字符设备驱动程序【3】

open和release
open方法
提供给驱动程序以初始化的能力,open方法应完成以下工作
    检查设备特定的错误
    如果设备是首次打开,则对其进行初始化工作
    如有必要,更新f_op组件
    分配并填写置于filp->private_data里的数据结构


  1. int (*open)(struct inode *inode, struct file *filep);


    inode: 在其i_cdev字段中包含了我们想要的信息
    file: 文件指针

    我们指向得到包含某cdev结构体的scull_dev结构体,可以通过以下方法
   
  1. int (*open)(struct inode *inode, struct file *filep);


  1. struct scull_dev *dev;
  2. dev = container_of(inode->i_cdev, struct scull_dev, cdev);
  3. filp ->private_data = dev;


经过简化的scuall_open

  1. int scuall_open(struct inode *inode, struct file* filp)
  2. {
  3.     struct scull_dev *dev;

  4.     dev = container_of(inode->i_cdev, struct scull_dev, cdev);
  5.     filp->private_data = dev;

  6.     if ((filp->f_flags & O_ACCMODE) == O_WRONLY) {
  7.         scull_trim(dev);
  8.     }
  9.     return 0;
  10. }



release方法
任务:
释放由open分配的,保存在file->private_data中的所有内容
在最后一次关闭操作时关闭设备

  1. int scull_release(struct inode *inode, struct file* filp);



scull内存使用

  1. void *kmalloc(size_t size, int flags);

试图分配size个字节大小的内存,其返回值指向该内存的指针,分配失败的时候返回NULL
flags参数用来描述内存的分配方法

  1. void kfree(void *ptr);

释放kmalloc分配的空间

read和write

  1. ssize_t read(struct file *filp, char __user *buff,
  2.         size_t count, loff_t *offp);
  3.         /*拷贝数据到应用程序空间*/
  4. ssize_t write(struct file *filp, char __user *buff,
  5.         size_t count, loff_t *offp);
  6.         /*从应用程序空间拷贝数据*/


filp     是文件指针
count    是请求传输数据的长度
buff     是指向用户空间的缓冲区
offp    指明用户在文件中进行存取操作的位置(long offset type)

内核代码不能直接引用buff中的内容:
    用户空间的地址可能是无效的;
    内存可能不再ram中,造成oops错误
    遭到恶意程序打开后门

用户地址空间和内核地址空间数据的交换

  1. unsigned long copy_to_user(void __user *to,
  2.                const void *from,
  3.                unosigned long count);
  4. /*将数据拷贝到用户空间*/
  5. unsigned long copy_from_user(void *to,
  6.                  const void __user *from,
  7.                  unsigned long count);
  8. /*从用户空间将数据考到内核空间*/



read和write发生错误的时候将返回一个负值
如果返回一个大于等于0的值则表示成功和操作的数据的字节数

read方法
调用程序对read的返回值的解释如下
    返回值等于count,表示所请求的字节数成功并完全传输
    返回值小于count,表示部分数据传输成功,传输的字节数小于请求的字节数
    返回值等于0,表示传输达到了文件尾部
    返回值小于0,表示发生了错误,错误码在<linux/errno.h>
        -EINTR    系统调用被中断
        -EFAULT    无效地址
    或者现在还没有数据,但以后可能会有,read系统调用会被阻塞
write方法
调用程序对write的返回值的解释如下
    返回值等于count,表示所请求的字节数成功并完全传输
    返回值小于count,表示部分数据传输成功,传输的字节数小于请求的字节数
    返回值等于0,表示什么也没有写入
    返回值小于0,表示发生了错误,错误码在<linux/errno.h>
        -EINTR    系统调用被中断
        -EFAULT    无效地址

readv和writev
处理向量的函数

  1. ssize_t (*readv) (struct file *filp, const struct iovec *lov,
  2.             unsigned long count, loof_t *ppos);
  3.     /* 将指定数量的数据依次读入每个缓冲区*/
  4. ssize_t (*writev) (struct file *filp, const struct iovec *lov,
  5.             unsigned long count, loof_t *ppos);


    /* 把各个缓冲区的内容收集起来, 并将它们在第一次写入操作中进行输出 */

 
  1. struct iovec {
  2.         void __user *iov_base;
  3.         __kernel_size_t iov_len;
  4.     };

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章