分类: LINUX
2010-04-28 21:41:54
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()函数.
块设备驱动的open()函数和字符设备驱动的open()和类似,都以相关inode和file结构体指针作为参数,当一个结点引用一个块设备时,inode->i_bdev->bd_disk包含一个指向关联gendisk的结构体的指针.因此类似字符设备,可将gendisk的private_data赋给file的private_data,private_data同样最好是指向描述该设备的设备结构体xxx_dev的指针.如下面的代码:
static int xxx_open(struct inode* inode, struct file* file){
struct xxx_dev* dev = inode->i_bdev->db_disk->private_data;
file->private_data = dev;
...
return 0;
}
3.块设备驱动的ioctl
块设备可以包含一个ioctl()函数,以提供对该设备的IO控制,实际上搞成的块设备层代码处理了绝大多数ioctl(),因此具体的块设备驱动中,通常不在需要实现很多ioctl()命令.下面的代码中只实现一个命令HDIO_GETGEO,用于获得磁盘的几何信息(geometry,指CHS,即Cylinder, Head, Sector/Track).
static int xxx_ioctl(struct inode* inode, struct file* file,\
unsigned int cmd, unsigned long arg){
long size;
struct hd_geometry geo;
struct xxx_dev* dev = file->private_data;
switch(cmd){
case HDIO_GETGEO:
size = dev->size * (hardsect_size / KERNEL_SECTOR_SIZE);
geo.cylinders = (size & ~0x3f) >> 6;
geo.heads = 4;
geo.sectors = 16;
if(copy_to_user((void __user*)arg, &geo, sizeof(geo)){
return -EFAULT;
}
return 0;
}
return -ENOTTY;//未知命令
}