之程序设计机械设备

块设备驱动注册与注销

块设备驱动中的第1个干活一般是登记它们自己到根本,完毕那几个职务的函数是
register_blkdev(),其原型为:
int register_blkdev(unsigned int major, const char *name);

major
参数是块设备要运用的主设备号,name为设备名,它会在/proc/devices中被出示。
假设major为0,内核会自动分配一个新的主设备号register_blkdev()函数的重回值就是其一主设备号。固然回到1个负值,申明发生了一个漏洞万分多。

与register_blkdev()对应的吊销函数是unregister_blkdev(),其原型为:
int unregister_blkdev(unsigned int major, const char *name); 这里,传递给register_blkdev()的参数必须与传递给register_blkdev()的参数匹配,否则那一个函数再次回到-EINVAL。

块设备的伏乞队列操作

正式的伸手处理程序能排序请求,并联合相邻的请求,即使一个块设备希望采纳正式的乞请处理程序,那它必须调用函数blk_init_queue来开头化请求队列。当处理在队列上的请求时,必须具有队列自旋锁。早先化请求队列
request_queue_t *blk_init_queue(request_fn_proc
*rfn, spinlock_t *lock);

该函数的第1个参数是伸手处理函数的指针,第2个参数是决定访问队列权限的自旋锁,这一个函数会爆发内存分配的行事,故它恐怕会破产,函数调用成
功时,它回到指向开头化请求队列的指针,否则,重临NULL。那一个函数一般在块设备驱动的模块加载函数中调用。清除请求队列
void blk_cleanup_queue(request_queue_t * q);

本条函数已毕将请求队列重临给系统的义务,一般在块设备驱动模块卸载函数中调用。

 

领到请求
struct request *elv_next_request(request_queue_t *queue); 
上述函数用于再次回到下一个要拍卖的呼吁(由 I/O
调度器决定),假若没有请求则赶回NULL。

剔除请求
void blkdev_dequeue_request(struct request *req); 
上述函数从队列中去除1个请求。如果驱动中并且从同一个系列中操作了八个请求,它必须以如此的点子将它们从队列中除去。

 

分配“请求队列”
request_queue_t *blk_alloc_queue(int gfp_mask);
对此FLASH、RAM盘等统统自由访问的非机械设备,并不要求进行复杂的I/O调度,这么些时候,应该拔取上述函数分配1个“请求队列”,并运用如下函数来绑定“请求队列”和“创立请求”函数。 void blk_queue_make_request(request_queue_t * q, 
make_request_fn * mfn);

void blk_queue_hardsect_size(request_queue_t *queue, 
unsigned short max); 
该函数用于告知内核块设备硬件扇区的深浅,所有由基础暴发的呼吁都是其一尺寸的翻番并且被正确对界。但是,内核块设备层和驱动之间的通信依旧以512字节扇区为单位开展。

 

步骤:

在块设备驱动的模块加载函数中司空见惯须求形成如下工作:
① 分配、伊始化请求队列,绑定请求队列和请求函数。
② 分配、初始化gendisk,给gendisk的major、fops、queue等成
员赋值,最后添加gendisk。
③ 注册块设备驱动。
在块设备驱动的模块卸载函数中常见需求与模块加载函数相反的干活:
① 清除请求队列。
② 删除gendisk和对gendisk的引用。
③ 删除对块设备的引用,注销块设备驱动。

总结:

块设备的I/O操作形式与字符设备存在较大的两样,因此引入了
request_queue、request、bio等一多元数据结构。在整体块设备的I/O操作中,贯穿于始终的就是“请求”,字符设备的I/O操作则是直接举办不绕弯,
块设备的I/O操作会排队和整合。

使得的天职是处理请求,对请求的排队和组成由I/O调度算法化解,由此,块设备驱动的为主就是请求处理函数或“创建请求”函数。

即便在块设备驱动中如故存在block_device_operations结构体及其成员函数,但其不再包涵读写一类的成员函数,而只是富含打开、释放及I/O控制等
与具象读写无关的函数。块设备驱动的结构万分复杂的,但万幸的是,块设备不像字符设备那么完美,它一般就是存储设备,而且使得的主心骨已经
Linux基础提供,针对一个特定的硬件系统,驱动工程师所涉嫌到的行事很多次只是编制少量的与硬件直接互动的代码。

[cpp] view
plain
 copy

 

 print?

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

发表评论

电子邮件地址不会被公开。 必填项已用*标注