次第设计机械设备

块设备驱动注册与注销

块设备驱动中的第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内核提供,针对一个一定的硬件系统,驱动工程师所关联到的干活屡次只是编制少量的与硬件直接互动的代码。

  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");  

 

发表评论

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