zoukankan      html  css  js  c++  java
  • linux块设备驱动之实例

    整体过程:

    1注册register_blkdev;

    2定义设备结构体以及初始化结构图sbull_dev;

    3创建设备请求队列 dev->queue = blk_init_queue(sbull_request,  &dev->lock);

    4分配、初始化及安装相应的gendisk结构dev->gd = alloc_disk(SBULL_MINORS)。dev = ,,;

    5设置队列支持的扇区大小blk_queue_hardsect_size(dev->queue,  hardset_size);

    6实现操作函数,打开,关闭

    7处理请求操作

    1、注册:向内核注册个块设备驱动,其实就是用主设备号告诉内核这个代表块设备驱动

    [cpp] view plain copy
     
    1. sbull_major  =  register_blkdev(sbull_major, "sbull");  
    2. if (0 >=  sbull_major){  
    3.     printk(KERN_WARNING "sbull:   unable  to  get  major  number! ");  
    4.     return  -EBUSY;  
    5. }  

     

    2、定义设备结构体:

    [cpp] view plain copy
     
    1. struct sbull_dev{  
    2.      int size; // 以扇区为单位,设备的大小  
    3.      u8  *data; // 数据数组  
    4.      short users; // 用户数目  
    5.      short media_change; // 介质改变标识  
    6.      spinlock_t lock; // 用于互斥  
    7.      struct request_queue  *queue; // 设备请求队列  
    8.      struct gendisk  *gd; // gendisk结构  
    9.      struct timer_list time; // 用来模拟介质改变  
    10.  };  

     

    3、初始化设备结构体:

    [cpp] view plain copy
     
    1. memset(dev, 0, sizeof(struct sbull_dev));  
    2. dev->size  = nsectors * hardsect_size;  
    3. dev->data  = vmalloc(dev->size);  
    4. if (dev->data == NULL){  
    5.     printk(KERN_NOTICE "vmalloc failure. ");  
    6.     return;  
    7. }  
    8. spin_lock_init(&dev->lock);//初始化自旋锁,为了下一步的队列分配  


    4、创建设备的请求队列:

     dev->queue = blk_init_queue(sbull_request,  &dev->lock);

    5、分配、初始化及安装相应的gendisk结构:

    [cpp] view plain copy
     
    1. dev->gd = alloc_disk(SBULL_MINORS);  
    2. if (!dev->gd) {  
    3.     printk (KERN_NOTICE "alloc_disk failure. ");  
    4.     goto out_vfree;  
    5. }  
    6. dev->gd->major = sbull_major;  
    7. dev->gd->first_minor = which*SBULL_MINORS;  
    8. dev->gd->fops = &sbull_ops;  
    9. dev->gd->queue = dev->queue;  
    10. dev->gd->private_data= dev;  
    11. snprintf(dev->gd->disk_name, 32, "sbull%c", which + 'a');  
    12. set_capacity(dev->gd, nsectors*(hardsect_size/KERNEL_SECTOR_SIZE));//使用KERNEL_SECTOR_SIZE本地常量,进行内核512字节扇区到实际使用的扇区大小转换  
    13.   
    14. add_disk(dev->gd);  

            SBULL_MINORS是每个设备所支持的次设备号的数量,地一个设备名为 sbulla,第二个为sbullb.用户空间可以添加分区,第二个设备上的第三个分区可能是 /dev/sbullb3。

    6、设置队列支持的扇区大小

            通知内核设备所支持的扇区大小,硬件扇区大小作为一个参数放在队列中,而不是在gendisk中。当分配好队列后就要马上调用下面函数:

            blk_queue_hardsect_size(dev->queue,  hardset_size);

            调用了上面的函数后,内核就会对我们的设备使用设定的硬件扇区大小,所有的I/O请求毒定位在硬件扇区的开始位置,并且每个请求的大小都将是扇区大小的整数倍。记住:内核总是认为扇区大小是512字节,因此必须将所有的扇区数进行转换。

    7、实现操作函数:

    打开设备函数:

    [cpp] view plain copy
     
    1. static int sbull_open(struct inode *inode,  struct file *filp)  
    2. {  
    3.     struct sbull_dev  *dev = inode->i_bdev->bd_disk->private_data;  
    4.   
    5.     del_timer_sync(&dev->timer);//移除定时器  
    6.     filp->private_data = dev;  
    7.     spin_lock(&dev->lock);  
    8.   
    9.     if (!dev->users)  
    10.         check_disk_change(inode->i_bdev);//检查驱动器中的介质是否改变  
    11.     dev->users++;// 增加用户计数  
    12.     spin_unlock(&dev->lock);  
    13.     return 0;  
    14. }  

    关闭设备函数:

    [cpp] view plain copy
     
    1. static int sbull_release(struct inode *inode,  struct file *filp)  
    2. {  
    3.     struct sbull_dev  *dev = inode->i_bdev->bd_disk->private_data;  
    4.   
    5.     spin_lock(&dev->lock);  
    6.     dev->users--;  
    7.   
    8.     if (!dev->users){  
    9.         dev->timer.expires = jiffies + INVALIDATE_DELAY;//设置定时器  
    10.         add_timer(&dev->timer);  
    11.     }  
    12.   
    13.     spin_unlock(&dev->lock);  
    14.     return 0;  
    15. }  

            其他的函数也是一样实现,和字符设备驱动的类似。这里就不写了,接下来看看核心部分,对于一个块设备驱动来说核心部分就是请求,几乎所有的重心都在请求函数;

    8、处理请求操作

    [cpp] view plain copy
     
    1. dev->queue = blk_queue_init(&sbull_request, &dev->lock);  
    2.  static void sbull_request(request_queue_t *q)  
    3.  {  
    4.      struct request *req;  
    5.    
    6.      while((req = elv_next_request(q)) != NULL){//获取队列中第一个未完成的请求,没有则返回NULL。处理完后不删除该请求  
    7.          struct sbull_dev *dev = req->rq_disk->private_data;  
    8.          if (! blk_fs_request(req)){// 判断是否是一个文件系统请求,即是不是块设备请求  
    9.              printk(KERN_NOTICE "skip non-fs  request. ");  
    10.              end_request(req, 0);  
    11.              continue;  
    12.          }  
    13.          //sbull_transfer()函数是真正的处理块设备请求函数  
    14.          sbull_transfer(dev, req->sector, req->current_nr_sectors, req->buffer, rq_data_dir(req));  
    15.          end_request(req, 1);  
    16.      }  
    17.  }  
    18.    
    19.  void end_request(struct request* req, int succeeded);  
    20.    
    21. // sector开始扇区的索引号,指的是512字节的扇区,如果是2048字节的扇区,则要sector/4再传递  
    22. // nsect 表示要传递多少个扇区; buffer 数据缓存的地址指针;write 表示数据传递的方向,即:read/write;  
    23.  static void sbull_transfer(struct sbull_dev *dev, unsigned long sector, unsigned long nsect, char *buffer, int write)  
    24.  {  
    25.      unsigned long offset = sector*KERNEL_SECTOR_SIZE;  
    26.      unsigned long nbytes = nsect*KERNEL_SECTOR_SIZE;  
    27.    
    28.      if ((offset + nbytes) > dev->size){  
    29.          printk(KERN_NOTICE "Beyond-end  write (%ld %ld) ", offset, nbytes);  
    30.          return;  
    31.      }  
    32.    
    33.      if (write)  
    34.          memcpy(dev->data + offset, buffer, nbytes);  
    35.      else  
    36.          memcpy(buffer, dev->data + offset, nbytes);  
    37.  }  


            转载地址: linux块设备驱动之实例

    http://blog.csdn.net/yuzhihui_no1/article/details/46808947

  • 相关阅读:
    转:SkipList跳表
    git操作
    JAVA小工具打包
    Java数字证书操作
    mysql创建数据库和用户
    解决node-sass安装不了的问题
    vscode + angular
    ng2 quickstart-primeng
    ng2 quickstart
    使用淘宝的npm代理下载模块
  • 原文地址:https://www.cnblogs.com/Ph-one/p/6230693.html
Copyright © 2011-2022 走看看