Linux驱动开发之块设备初入门(5)

块设备驱动的第一个任务就是将他们自己注册到内核中,其函数原型如下:
   
    ☆int register_blkdev(unsigned int major, const char* name);   
    major参数是块设备要使用的主设备号,name为设备名,它会在/proc/devices中被现实.如果major为0,内核会自动分配一个新的主设备号,并由该函数返回.如果返回值为负值,则说明设备号分派失败.
    注销函数是unregister_blkdev(),原型如下:

☆int unreister_blkdev(unsigned int major, const char* name);
       
    这里unreister_blkdev与register_blkdev的参数必须匹配,否则这个函数会返回-EINVAL.    在Linux2.6中,对register_blkdev的调用是可选的.register_blkdev这个调用在Linux2.6中只完成了两件事情:
    ①如果需要,分派一个主设备号;
    ②在/proc/devices中创建一个入口.
 

8、块设备驱动程序编写模板

块驱动中相关相关模块模板

1.块设备驱动的模块加载与卸载

1)块设备驱动的模块加载完成的工作如下:

☆ 分配,初始化请求队列,绑定请求队列和请求函数

☆ 分配,初始化gendisk,给gendisk的major,fops,queue等成员赋值,最后添加gendisk.

☆ 注册块设备驱动.

代码1:使用blk_alloc_queue函数完成块设备驱动的模块加载模板

static int __init xxx_init(void){

//分配gendisk

xxx_disks = alloc_disk(1);

if(!xxx_disks){

goto out;

}

//块设备驱动注册

if(register_blkdev(xxx_MAJOR, "xxx"){

err = -EIO;

goto out;

}

//"请求队列"分配

xxx_queue = blk_alloc_queue(GFP_KERNEL);

if(!xxx_queue){

goto out_queue;

}

blk_queue_make_request(xxx_queue, &xxx_make_request);//绑定"制造请求"函数

blk_queue_hardsect_size(xxx_queue,xxx_blocksize);//告知内核硬件扇区尺寸

//gendisk初始化

xxx_disks->major = xxx_MAJOR;

xxx_disks->first_minor = 0;

xxx_disks->fops = &xxx_fop;

xxx_disks->queue = xxx_queue;

sprintf(xxx_disks->disk_name, "xxx%d", i);

set_capacity(xxx_disks, xxx_size);//设置gendisk容量为xxx_size个扇区大小

add_disk(xxx_disks);

return 0;

out_queue:unregister_blkdev(xxx_MAJOR, "xxx");

out:put_disk(xxx_disks);

blk_cleanup_queue(xxx_queue);

return -ENOMEM;

}

代码2:使用blk_init_queue函数完成块设备驱动的模块加载模板

static int __init xxx_init(void){

//块设备驱动注册

if(register_blkdev(xxx_MAJOR, "xxx"){

err = -EIO;

goto out;

}

//请求队列初始化

xxx_queue = blk_init_queue(xxx_request, xxx_lock);

if(!xxx_queue){

goto out_queue;

}

blk_queue_hardsect_size(xxx_queue, xxx_blocksize);//告知内核硬件扇区大小

//gendisk初始化

xxx_disks->major = xxx_MAJOR;

xxx_disks->first_minor = 0;

xxx_disks->fops = &xxx_fop;

xxx_disks->queue = xxx_queue;

sprintf(xxx_disks->disk_name, "xxx%d", i);

set_capacity(xxx_disks, xxx_size*2);//设置gendisk容量为xxx_size个扇区大小

add_disk(xxx_disks);

return 0;

out_queue:unregister_blkdev(xxx_MAJOR, "xxx");

out:put_disk(xxx_disks);

blk_cleanup_queue(xxx_queue);

return -ENOMEM;

}

2)块设备驱动的模块卸载完成的工作如下:

☆ 清除请求队列.

☆ 删除gendisk和gendisk的引用

☆ 删除对块设备的引用,注销块设备驱动.

代码3:块设备驱动模块卸载函数模板

static void __exit xxx_exit(void){

if(bdev){

invalidate_bdev(xxx_bdev, 1);

blkdev_put(xxx_bdev);

}

del_gendisk(xxx_disks);//删除gendisk

put_disk(xxx_disks);

blk_cleanup_queue(xxx_queue[i]);//清除请求队列

unregister_blkdev(xxx_MAJOR, "xxx");

}

2.块设备驱动的打开与释放

块设备驱动的open()和release()函数不是必须的,一个简单的块设备驱动可以不提供open()和release()函数.

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/1113f82fc69a591afa0531884adb3059.html