zoukankan      html  css  js  c++  java
  • [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");    
  • 相关阅读:
    android activity 生命周期
    Android event logcat的研究
    关于new enhancement的一些知识
    LEAVE LIST-PROCESSING和LEAVE TO LIST-PROCESSING事件的作用
    报错消息写在AT SELECTION-SCREEN OUTPUT和START-OF-SELECTION事件下的区别
    字符串的 Base64 加密和解密
    接口的学习
    IDOC
    ABAP文件上传下载 用SMW0
    获取本机信息如IP 电脑名称等类
  • 原文地址:https://www.cnblogs.com/zhiliao112/p/4237230.html
Copyright © 2011-2022 走看看