块设备驱动架构分析

1. 块设备概念:块设备是指只能以块为单位进行访问的设备,块的大小一般是512个字节的整数倍。常见的块设备包括硬件,SD卡,光盘等。</span>

上边是通过一个编写好的块设备驱动,然后安装块设备驱动以及一些相关操作来体会块设备驱动!(此处省略)

2. 块设备驱动的系统架构

2.1 系统架构---VFS

VFS是对各种具体文件系统的一种封装,用户程序访问文件提供统一的接口。

2.2 系统架构---Cache

当用户发起文件访问请求的时候,首先回到Disk Cache中寻址文件是否被缓存了,如果在Cache,则直接从cache中读取。如果数据不在缓存中,就必须要到具体的文件系统中读取数据了。

2.3 Mapping Layer

    2.3.1 首先确定文件系统的block size,然后计算所请求的 数据包含多少个block.

    2.3.2 调用具体文件系统的函数来访问文件的inode结构,确定所请求的数据在磁盘上的地址。

2.4 Generic Block Layer

Linux内核把块设备看做是由若干个扇区组成的数据空间,上层的读写请求在通用块层被构造成一个或多个bio结构。

2.5 I/O Scheduler Layer I/O调度层负责采用某种算法(如:电梯调度算法)将I/O操作进行排序。

电梯调度算法的基本原则:如果电梯现在朝上运动,如果当前楼层的上方和下方都有请求,则先响应所有上方的请求,然后才向下响应下方的请求;如果电梯向下运动,则刚好相反。

2.6 块设备驱动

在块系统架构的最底层,由块设备驱动根据排序好的请求,对硬件进行数据访问。

块设备驱动流程分析:

1.6 注册块设备---add_disk

2. 实现读写请求函数

    2.1 取出一个要处理的请求---blk_fetch_request

    2.2 更具请求里的信息访问硬件,获取数据

    2.3 利用__blk_end_request_cur判读请求队列里是否还有剩余的请求要处理,如果有按照1、2来处理

一个最简单的块设备驱动程序:

 
  1. #include<linux/module.h>

  2. #include<linux/init.h>

  3. #include<linux/blkdev.h>

  4. #include<linux/bio.h>

  5.  
  6. #include <linux/sched.h>

  7. #include <linux/kernel.h> /* printk() */

  8. #include <linux/slab.h> /* kmalloc() */

  9. #include <linux/fs.h> /* everything... */

  10. #include <linux/errno.h> /* error codes */

  11. #include <linux/timer.h>

  12. #include <linux/types.h> /* size_t */

  13. #include <linux/fcntl.h> /* O_ACCMODE */

  14. #include <linux/hdreg.h> /* HDIO_GETGEO */

  15. #include <linux/kdev_t.h>

  16. #include <linux/vmalloc.h>

  17. #include <linux/genhd.h>

  18. #include <linux/blkdev.h>

  19. #include <linux/buffer_head.h> /* invalidate_bdev */

  20. #include <linux/bio.h>

  21.  
  22. static int major = 0;

  23.  
  24. static int sect_size = 512;//定义每个扇区的大小为512字节

  25. static int nsectors = 1024;//扇区数目

  26.  
  27. struct blk_dev{

  28. int size;

  29. u8 *data;

  30. struct request_queue *queue;

  31. struct gendisk *gd;

  32. };

  33.  
  34. struct blk_dev *dev;

  35.  
  36. static struct block_device_operations blk_ops = {

  37. .owner = THIS_MODULE,

  38. };

  39. //static void blk_transfer(struct blk_dev *dev, unsigned long sector,unsigned long nsect, char *buffer, int write)

  40. static void blk_transfer(struct blk_dev *dev, unsigned long sector, unsigned long nsect, char *buffer, int write)

  41. {

  42. unsigned long offset = sector * sect_size;

  43. unsigned long nbytes = nsect * sector;

  44.  
  45. if(write)//如果是写操作 将用户空间的数据写到磁盘上去

  46. memcpy(dev->data + offset, buffer, nbytes);

  47.  
  48. else

  49. memcpy(buffer, dev->data + offset, nbytes);

  50.  
  51.  
  52. }

  53.  
  54. static void blk_request(struct request_queue *q)

  55. {

  56. struct request *req;//保存取出的请求

  57.  
  58. req = blk_fetch_request(q);//从请求队列中取出一个请求

  59.  
  60. while(req != NULL)

  61. {

  62. //处理该请求

  63.  
  64. //操作的起始扇区 请求操作扇区的数目 数据读出来放到哪里, 或写数据来自哪里

  65. blk_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req), req->buffer, rq_data_dir(req));

  66. //blk_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req), req->buffer, rq_data_dir(req));

  67.  
  68. if( !__blk_end_request_cur(req, 0) )//判读如果不是最后一个请求

  69. req = blk_fetch_request(q);//再去取一个请求

  70. }

  71. }

  72.  
  73. void setup_device(void)

  74. {

  75. dev->size = nsectors * sect_size;

  76.  
  77. dev->data = vmalloc(dev->size);

  78.  
  79. dev->queue = blk_init_queue(blk_request, NULL);//初始化请求队列

  80.  
  81. blk_queue_logical_block_size(dev->queue, sect_size);//设置扇区尺寸

  82.  
  83. dev->gd = alloc_disk(1);//分配块设备结构

  84.  
  85. dev->gd->major = major;

  86. dev->gd->first_minor = 0;

  87. dev->gd->fops = &blk_ops;

  88. dev->gd->queue = dev->queue;

  89. dev->gd->private_data = dev;

  90. sprintf(dev->gd->disk_name, "simp_blk%d", 0);//设备名为simp_blk0

  91. set_capacity(dev->gd, nsectors);//设置扇区数

  92.  
  93. add_disk(dev->gd);

  94.  
  95. }

  96.  
  97. int blk_init(void)

  98. {

  99. //两个参数 第一个参数为0表示为动态分配设备号 返回主设备号

  100. major = register_blkdev(0, "blk");//注册块设备驱动程序

  101.  
  102. if( major <= 0 )

  103. {

  104. printk("register blk dev fail!\n");

  105.  
  106. return -EBUSY;

  107. }

  108.  
  109. dev = kmalloc(sizeof(struct blk_dev),GFP_KERNEL);

  110.  
  111. setup_device();

  112.  
  113. return 0;

  114. }

  115.  
  116. void blk_exit(void)

  117. {

  118. del_gendisk(dev->gd);

  119.  
  120. blk_cleanup_queue(dev->queue);

  121.  
  122. vfree(dev->data);

  123.  
  124. unregister_blkdev(major, "blk");

  125.  
  126. kfree(dev);

  127. }

  128.  
  129. module_init(blk_init);

  130. module_exit(blk_exit);


编译安装 格式化成ext3的时候虚拟机直接重启了!原来驱动的BUG动不动就把系统搞挂!

这个是可以运行的:

 
  1. #include <linux/module.h>

  2. #include <linux/moduleparam.h>

  3. #include <linux/init.h>

  4.  
  5. #include <linux/sched.h>

  6. #include <linux/kernel.h> /* printk() */

  7. #include <linux/slab.h> /* kmalloc() */

  8. #include <linux/fs.h> /* everything... */

  9. #include <linux/errno.h> /* error codes */

  10. #include <linux/timer.h>

  11. #include <linux/types.h> /* size_t */

  12. #include <linux/fcntl.h> /* O_ACCMODE */

  13. #include <linux/hdreg.h> /* HDIO_GETGEO */

  14. #include <linux/kdev_t.h>

  15. #include <linux/vmalloc.h>

  16. #include <linux/genhd.h>

  17. #include <linux/blkdev.h>

  18. #include <linux/buffer_head.h> /* invalidate_bdev */

  19. #include <linux/bio.h>

  20.  
  21. MODULE_LICENSE("Dual BSD/GPL");

  22.  
  23. static int major = 0;

  24.  
  25. static int sect_size = 512;

  26.  
  27. static int nsectors = 1024;

  28.  
  29. /*

  30. * The internal representation of our device.

  31. */

  32. struct blk_dev{

  33. int size; /* Device size in sectors */

  34. u8 *data; /* The data array */

  35. struct request_queue *queue; /* The device request queue */

  36. struct gendisk *gd; /* The gendisk structure */

  37. };

  38.  
  39. struct blk_dev *dev;

  40.  
  41.  
  42. /*

  43. * Handle an I/O request, in sectors.

  44. */

  45. static void blk_transfer(struct blk_dev *dev, unsigned long sector,

  46. unsigned long nsect, char *buffer, int write)

  47. {

  48. unsigned long offset = sector*sect_size;

  49. unsigned long nbytes = nsect*sect_size;

  50.  
  51. if ((offset + nbytes) > dev->size) {

  52. printk (KERN_NOTICE "Beyond-end write (%ld %ld)\n", offset, nbytes);

  53. return;

  54. }

  55. if (write)

  56. memcpy(dev->data + offset, buffer, nbytes);

  57. else

  58. memcpy(buffer, dev->data + offset, nbytes);

  59. }

  60.  
  61. /*

  62. * The simple form of the request function.

  63. */

  64. static void blk_request(struct request_queue *q)

  65. {

  66. struct request *req;

  67.  
  68. req = blk_fetch_request(q);

  69. while (req != NULL) {

  70. struct blk_dev *dev = req->rq_disk->private_data;

  71.  
  72. blk_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req), req->buffer, rq_data_dir(req));

  73.  
  74. if(!__blk_end_request_cur(req, 0))

  75. {

  76. req = blk_fetch_request(q);

  77. }

  78. }

  79. }

  80.  
  81.  
  82. /*

  83. * Transfer a single BIO.

  84. */

  85. static int blk_xfer_bio(struct blk_dev *dev, struct bio *bio)

  86. {

  87. int i;

  88. struct bio_vec *bvec;

  89. sector_t sector = bio->bi_sector;

  90.  
  91. /* Do each segment independently. */

  92. bio_for_each_segment(bvec, bio, i) {

  93. char *buffer = __bio_kmap_atomic(bio, i, KM_USER0);

  94. blk_transfer(dev, sector, bio_cur_bytes(bio)>>9 /* in sectors */,

  95. buffer, bio_data_dir(bio) == WRITE);

  96. sector += bio_cur_bytes(bio)>>9; /* in sectors */

  97. __bio_kunmap_atomic(bio, KM_USER0);

  98. }

  99. return 0; /* Always "succeed" */

  100. }

  101.  
  102. /*

  103. * Transfer a full request.

  104. */

  105. static int blk_xfer_request(struct blk_dev *dev, struct request *req)

  106. {

  107. struct bio *bio;

  108. int nsect = 0;

  109.  
  110. __rq_for_each_bio(bio, req) {

  111. blk_xfer_bio(dev, bio);

  112. nsect += bio->bi_size/sect_size;

  113. }

  114. return nsect;

  115. }

  116.  
  117.  
  118.  
  119. /*

  120. * The device operations structure.

  121. */

  122. static struct block_device_operations blk_ops = {

  123. .owner = THIS_MODULE,

  124. };

  125.  
  126.  
  127. /*

  128. * Set up our internal device.

  129. */

  130. static void setup_device()

  131. {

  132. /*

  133. * Get some memory.

  134. */

  135. dev->size = nsectors*sect_size;

  136. dev->data = vmalloc(dev->size);

  137. if (dev->data == NULL) {

  138. printk (KERN_NOTICE "vmalloc failure.\n");

  139. return;

  140. }

  141.  
  142. dev->queue = blk_init_queue(blk_request, NULL);

  143. if (dev->queue == NULL)

  144. goto out_vfree;

  145.  
  146. blk_queue_logical_block_size(dev->queue, sect_size);

  147. dev->queue->queuedata = dev;

  148. /*

  149. * And the gendisk structure.

  150. */

  151. dev->gd = alloc_disk(1);

  152. if (! dev->gd) {

  153. printk (KERN_NOTICE "alloc_disk failure\n");

  154. goto out_vfree;

  155. }

  156. dev->gd->major = major;

  157. dev->gd->first_minor = 0;

  158. dev->gd->fops = &blk_ops;

  159. dev->gd->queue = dev->queue;

  160. dev->gd->private_data = dev;

  161. sprintf (dev->gd->disk_name, "simp_blk%d", 0);

  162. set_capacity(dev->gd, nsectors*(sect_size/sect_size));

  163. add_disk(dev->gd);

  164. return;

  165.  
  166. out_vfree:

  167. if (dev->data)

  168. vfree(dev->data);

  169. }

  170.  
  171. static int __init blk_init(void)

  172. {

  173. /*

  174. * Get registered.

  175. */

  176. major = register_blkdev(major, "blk");

  177. if (major <= 0) {

  178. printk(KERN_WARNING "blk: unable to get major number\n");

  179. return -EBUSY;

  180. }

  181.  
  182. dev = kmalloc(sizeof(struct blk_dev), GFP_KERNEL);

  183. if (dev == NULL)

  184. goto out_unregister;

  185.  
  186. setup_device();

  187.  
  188. return 0;

  189.  
  190. out_unregister:

  191. unregister_blkdev(major, "sbd");

  192. return -ENOMEM;

  193. }

  194.  
  195. static void blk_exit(void)

  196. {

  197.  
  198. if (dev->gd) {

  199. del_gendisk(dev->gd);

  200. put_disk(dev->gd);

  201. }

  202. if (dev->queue)

  203. blk_cleanup_queue(dev->queue);

  204. if (dev->data)

  205. vfree(dev->data);

  206.  
  207. unregister_blkdev(major, "blk");

  208. kfree(dev);

  209. }

  210.  
  211. module_init(blk_init);

  212. module_exit(blk_exit);

makefile:

 
  1. ifneq ($(KERNELRELEASE),)

  2.  
  3. obj-m := simple-blk.o

  4.  
  5. else

  6.  
  7. KDIR := /lib/modules/2.6.32-279.el6.i686/build

  8. all:

  9. make -C $(KDIR) M=$(PWD) modules

  10. clean:

  11. rm -f *.ko *.o *.mod.o *.mod.c *.symvers

  12.  
  13. endif

这个块设备驱动的测试上面也有步骤!重点是理解块设备驱动的大体流程!对块设备驱动又个大体印象!

下面来介绍一个和下面即将要出场的flash驱动相关的知识!

MTD

MTD设备体验:Flash在嵌入式系统中是必不可少,它是bootloader、linux内核和文件系统的最佳载体。在linux内核中引入了MTD子系统为NOR FLASH和NAND FLASH设备提供统一的接口,从而使得FLASH驱动的设计大为简化。

块设备驱动系统架构:




先过一遍流程!额 ,徒手撸驱动代码这难度还真不是一般大!后边边学边提高吧!

猜你喜欢

转载自blog.csdn.net/ds1130071727/article/details/82761028
今日推荐