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

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

 

2、定义设备结构体:

  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、初始化设备结构体:

  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.\n");
  6. return;
  7. }
  8. spin_lock_init(&dev->lock);//初始化自旋锁,为了下一步的队列分配

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

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

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

  1. dev->gd = alloc_disk(SBULL_MINORS);
  2. if (!dev->gd) {
  3. printk (KERN_NOTICE "alloc_disk failure.\n");
  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. add_disk(dev->gd);

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

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

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

blk_queue_hardsect_size(dev->queue,  hardset_size);

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

7、实现操作函数:

打开设备函数:

  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. del_timer_sync(&dev->timer);//移除定时器
  5. filp->private_data = dev;
  6. spin_lock(&dev->lock);
  7. if (!dev->users)
  8. check_disk_change(inode->i_bdev);//检查驱动器中的介质是否改变
  9. dev->users++;// 增加用户计数
  10. spin_unlock(&dev->lock);
  11. return 0;
  12. }

关闭设备函数:

  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. spin_lock(&dev->lock);
  5. dev->users--;
  6. if (!dev->users){
  7. dev->timer.expires = jiffies + INVALIDATE_DELAY;//设置定时器
  8. add_timer(&dev->timer);
  9. }
  10. spin_unlock(&dev->lock);
  11. return 0;
  12. }

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

8、处理请求操作

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

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

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

linux块设备驱动之实例的更多相关文章

  1. Linux块设备驱动详解

    <机械硬盘> a:磁盘结构 -----传统的机械硬盘一般为3.5英寸硬盘,并由多个圆形蝶片组成,每个蝶片拥有独立的机械臂和磁头,每个堞片的圆形平面被划分了不同的同心圆,每一个同心圆称为一个 ...

  2. Linux块设备驱动(二) _MTD驱动及其用户空间编程

    MTD(Memory Technology Device)即常说的Flash等使用存储芯片的存储设备,MTD子系统对应的是块设备驱动框架中的设备驱动层,可以说,MTD就是针对Flash设备设计的标准化 ...

  3. linux块设备驱动

    块设备驱动程序<1>.块设备和字符设备的区别1.读取数据的单元不同,块设备读写数据的基本单元是块,字符设备的基本单元是字节.2.块设备可以随机访问,字符设备只能顺序访问. 块设备的访问:当 ...

  4. linux块设备驱动---相关结构体(转)

    上回最后面介绍了相关数据结构,下面再详细介绍 块设备对象结构 block_device 内核用结构block_device实例代表一个块设备对象,如:整个硬盘或特定分区.如果该结构代表一个分区,则其成 ...

  5. linux块设备驱动---概念与框架(转)

    基本概念   块设备(blockdevice) --- 是一种具有一定结构的随机存取设备,对这种设备的读写是按块进行的,他使用缓冲区来存放暂时的数据,待条件成熟后,从缓存一次性写入设备或者从设备一次性 ...

  6. Linux 块设备驱动 (一)

    1.块设备的I/O操作特点 字符设备与块设备的区别: 块设备只能以块为单位接受输入和返回输出,而字符设备则以字符为单位. 块设备对于I/O请求有对应的缓冲区,因此它们可以选择以什么顺序进行响应,字符设 ...

  7. Linux块设备驱动(一) _驱动模型

    块设备是Linux三大设备之一,其驱动模型主要针对磁盘,Flash等存储类设备,本文以3.14为蓝本,探讨内核中的块设备驱动模型 框架 下图是Linux中的块设备模型示意图,应用层程序有两种方式访问一 ...

  8. Linux块设备驱动_WDS

    推荐书:<Linux内核源代码情景分析> 1.字符设备驱动和使用中等待某一事件的方法①查询方式②休眠唤醒,但是这种没有超时时间③poll机制,在休眠唤醒基础上加一个超时时间④异步通知,异步 ...

  9. linux 块设备驱动 (三)块设备驱动开发

    一: 块设备驱动注册与注销 块设备驱动中的第1个工作通常是注册它们自己到内核,完成这个任务的函数是 register_blkdev(),其原型为:int register_blkdev(unsigne ...

随机推荐

  1. UML之类图

    类(Class)封装了数据和行为,是具有相同属性.操作.关系的对象集合的总称. 类图(Class Dialog)使用系统中不同类来描述系统的静态结构,类图用来描述不同类和它们之间的关系. 类图由三部分 ...

  2. Sql Server海量数据插入

    目录 1.前言 2.BULK INSERT 3.简单示例 前言 由于昨天接到一个客户反馈导出数据卡死的问题,于是决定今天模拟一下千万级的数据,然后傻傻的等待插入数据了半天...... 对于海量数据,上 ...

  3. C学习笔记 知识集锦(一)

    1.标识符  2.寄存器变量 3.全局变量 4.分配内存与初始化 5.变量定义与声明 6.作用域规则 跳转语句 7.&与&&,|和||的意义与区别 8.如何选择switch c ...

  4. vim - Removing duplicate lines

    http://vim.wikia.com/wiki/Uniq_-_Removing_duplicate_lines :sort u

  5. docker 学习

    vim /usr/lib/systemd/system/docker.service ExecStart=/usr/bin/docker daemon --bip=172.18.42.1/16 --r ...

  6. Nginx location 匹配顺序整理

    Nginx location模块整理 具体的Nginx安装就不在这里描述了,这里只是为了对location的描述 Nginx环境 a. 查看当前系统cat /etc/redhat-release [r ...

  7. ZOJ 2412 Farm Irrigation

    Farm Irrigation Time Limit: 2 Seconds      Memory Limit: 65536 KB Benny has a spacious farm land to ...

  8. 服务器支持AspJpeg和JMail45_free.msi组件

     解决办法: 1.在服务器上安装上AspJpeg和JMail45_free.msi后, 2.在cmd中输入regsvr32 c:/windows/SysWOW64/aspjpeg.dll 3.把网站对 ...

  9. jsp+servlet 中文乱码问题

    一. 由于doget和dopost的处理方式不同,在做servlet的时候遇到这样一个问题:用doPost获得的参数只要加上“request.setCharacterEncoding("ut ...

  10. visual studio 两个以上sln 引用同一个project ,生成时会改变projectguid问题

    当两个以上解决方案添加现有项,选择了同一个项目,那么在 sln 文件中,会自己带一个guid. 当打开两个解决方案,一个生成时,会影响另一个的project值,导致每次都看到了签出. 解决办法,打开共 ...