[linux驱动]linux块设备学习笔记(三)——程序设计

一,块设备的注册

1,linux中默认的块设备的最大主设备号为255,调用register_blkdev(unsigned int major,const char*name)来注册块设备,如果major参数为0的时候那么从系统1到255中选择一个最大的没有使用的号作为当前设备的块设备号,name是在/proc/devices节点里显示的名字。

数组major_names[]有255个元素,每个元素都是一个指针,指向blk_major_name结构体,同一个指针指向的多个blk_major_name通过链表相连,有点类似hash表

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. static struct blk_major_name{  
  2.     struct blk_major_name *next;  
  3.     int major;  
  4.     char name[16];  
  5. }*major_names[255]  
  6.   
  7. 279 int register_blkdev(unsigned int major, const char *name)  
  8. 280 {  
  9. 281         struct blk_major_name **n, *p;  
  10. 282         int index, ret = 0;  
  11. 284         mutex_lock(&block_class_lock);285   
  12. 287         if (major == 0) {  
  13. 288                 for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) {  
  14. 289                         if (major_names[index] == NULL)  
  15. 290                                 break;  
  16. 291                 }  
  17. 293                 if (index == 0) {  
  18. 294                         printk("register_blkdev: failed to get major for %s ",  
  19. 295                                name);  
  20. 296                         ret = -EBUSY;  
  21. 297                         goto out;  
  22. 298                 }  
  23. 299                 major = index;  
  24. 300                 ret = major;  
  25. 301         }  
  26. 303         p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL);  
  27. 304         if (p == NULL) {  
  28. 305                 ret = -ENOMEM;  
  29. 306                 goto out;  
  30. 307         }  
  31. 309         p->major = major;  
  32. 310         strlcpy(p->name, name, sizeof(p->name));  
  33. 311         p->next = NULL;  
  34. 312         index = major_to_index(major);  
  35. 314         for (n = &major_names[index]; *n; n = &(*n)->next) {  
  36. 315                 if ((*n)->major == major)  
  37. 316                         break;  
  38. 317         }  
  39. 318         if (!*n)  
  40. 319                 *n = p;  
  41. 320         else  
  42. 321                 ret = -EBUSY;  
  43. 322   
  44. 323         if (ret < 0) {  
  45. 324                 printk("register_blkdev: cannot get major %d for %s ",  
  46. 325                        major, name);  
  47. 326                 kfree(p);  
  48. 327         }  
  49. 328 out:  
  50. 329         mutex_unlock(&block_class_lock);  
  51. 330         return ret;  
  52. 331 }  


 二:块设备请求队列的初始化

以下代码转自点击打开链接

调用函数blk_init_queue来初始化请求队列。当处理在队列上的请求时,必须持有队列自旋锁。初始化请求队列,

request_queue_t *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock);//该函数的第1个参数是请求处理函数的指针,第2个参数是控制访问队列权限的自旋锁

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
 
    1. #include <linux/init.h>      
    2. 02. #include <linux/module.h>      
    3. 03. #include <linux/kernel.h>      
    4. 04. #include <linux/fs.h>    
    5. 05. #include <asm/uaccess.h>    
    6. 06. #include <linux/spinlock.h>    
    7. 07. #include <linux/sched.h>    
    8. 08. #include <linux/types.h>    
    9. 09. #include <linux/fcntl.h>    
    10. 10. #include <linux/hdreg.h>    
    11. 11. #include <linux/genhd.h>    
    12. 12. #include <linux/blkdev.h>    
    13. 13.     
    14. 14. #define MAXBUF 1024     
    15. 15.     
    16. 16.     
    17. 17. #define BLK_MAJOR 253    
    18. 18.     
    19. 19. char blk_dev_name[]="blk_dev";    
    20. 20. static char flash[1024*16];    
    21. 21.     
    22. 22.     
    23. 23. int major;    
    24. 24. spinlock_t lock;    
    25. 25. struct gendisk *gd;    
    26. 26.     
    27. 27.     
    28. 28.     
    29. 29. /*块设备数据传输*/    
    30. 30. static void blk_transfer(unsigned long sector, unsigned long nsect, char *buffer, int write)    
    31. 31. {    
    32. 32.     int read = !write;    
    33. 33.     if(read)    
    34. 34.     {    
    35. 35.         memcpy(buffer, flash+sector*512, nsect*512);    
    36. 36.     }    
    37. 37.     else    
    38. 38.     {    
    39. 39.         memcpy(flash+sector*512, buffer, nsect*512);    
    40. 40.     }    
    41. 41. }    
    42. 42.     
    43. 43. /*块设备请求处理函数*/    
    44. 44. static void blk_request_func(struct request_queue *q)    
    45. 45. {    
    46. 46.     struct request *req;    
    47. 47.     while((req = elv_next_request(q)) != NULL)      
    48. 48.     {    
    49. 49.         if(!blk_fs_request(req))    
    50. 50.         {    
    51. 51.             end_request(req, 0);    
    52. 52.             continue;    
    53. 53.         }    
    54. 54.             
    55. 55.         blk_transfer(req->sector, req->current_nr_sectors, req->buffer, rq_data_dir(req));    
    56. 56.         /*rq_data_dir从request获得数据传送的方向*/    
    57. 57.         /*req->current_nr_sectors 在当前段中将完成的扇区数*/    
    58. 58.         /*req->sector 将提交的下一个扇区*/    
    59. 59.         end_request(req, 1);    
    60. 60.     }    
    61. 61. }    
    62. 62.     
    63. 63. /*strcut block_device_operations*/    
    64. 64. static  int blk_ioctl(struct block_device *dev, fmode_t no, unsigned cmd, unsigned long arg)    
    65. 65. {    
    66. 66.        return -ENOTTY;    
    67. 67. }    
    68. 68.     
    69. 69. static int blk_open (struct block_device *dev , fmode_t no)    
    70. 70. {    
    71. 71.     printk("blk mount succeed ");    
    72. 72.     return 0;    
    73. 73. }    
    74. 74. static int blk_release(struct gendisk *gd , fmode_t no)    
    75. 75. {    
    76. 76.     printk("blk umount succeed ");    
    77. 77.     return 0;    
    78. 78. }    
    79. 79. struct block_device_operations blk_ops=    
    80. 80. {    
    81. 81.     .owner = THIS_MODULE,    
    82. 82.     .open = blk_open,    
    83. 83.     .release = blk_release,    
    84. 84.     .ioctl = blk_ioctl,    
    85. 85. };    
    86. 86.     
    87. 87. //-----------------------------------------------    
    88. 88.     
    89. 89. static int __init block_module_init(void)    
    90. 90. {    
    91. 91.         
    92. 92.         
    93. 93.     if(!register_blkdev(BLK_MAJOR, blk_dev_name)) //注册一个块设备    
    94. 94.     {    
    95. 95.         major = BLK_MAJOR;      
    96. 96.         printk("regiser blk dev succeed ");    
    97. 97.     }    
    98. 98.     else    
    99. 99.     {    
    100. 100.         return -EBUSY;    
    101. 101.     }    
    102. 102.     gd = alloc_disk(1);  //分配一个gendisk,分区是一个    
    103. 103.     spin_lock_init(&lock); //初始化一个自旋锁    
    104. 104.     gd->major = major;    
    105. 105.     gd->first_minor = 0;   //第一个次设备号    
    106. 106.     gd->fops = &blk_ops;   //关联操作函数    
    107. 107.     
    108. 108.     gd->queue = blk_init_queue(blk_request_func, &lock); //初始化请求队列并关联到gendisk    
    109. 109.     
    110. 110.     snprintf(gd->disk_name, 32, "blk%c", 'a');      
    111. 111.     blk_queue_hardsect_size(gd->queue, 512);  //设置扇区大小512字节    
    112. 112.     set_capacity(gd, 32);  //设置块设备大小 512*32=16K    
    113. 113.     add_disk(gd);    
    114. 114.     printk("gendisk init success! ");    
    115. 115.     return 0;    
    116. 116. }    
    117. 117. static void __exit block_module_exit(void)    
    118. 118. {    
    119. 119.     blk_cleanup_queue(gd->queue);    
    120. 120.     del_gendisk(gd);     
    121. 121.     unregister_blkdev(BLK_MAJOR, blk_dev_name);    
    122. 122.     printk("block module exit succeed! ");    
    123. 123. }    
    124. 124.     
    125. 125. module_init(block_module_init);    
    126. 126. module_exit(block_module_exit);    
    127. 127.     
    128. 128. MODULE_LICENSE("GPL");    
原文地址:https://www.cnblogs.com/zhiliao112/p/4237230.html