Chinaunix首页 | 论坛 | 博客
  • 博客访问: 112341
  • 博文数量: 19
  • 博客积分: 1716
  • 博客等级: 上尉
  • 技术积分: 275
  • 用 户 组: 普通用户
  • 注册时间: 2010-02-25 14:03
文章分类

全部博文(19)

文章存档

2011年(8)

2010年(11)

我的朋友

分类: LINUX

2010-04-28 21:41:54

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

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

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

Ø 分配,初始化gendisk,gendiskmajor,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)块设备驱动的模块卸载完成的工作如下:

Ø 清除请求队列.

Ø 删除gendiskgendisk的引用

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

代码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()和类似,都以相关inodefile结构体指针作为参数,当一个结点引用一个块设备时,inode->i_bdev->bd_disk包含一个指向关联gendisk的结构体的指针.因此类似字符设备,可将gendiskprivate_data赋给fileprivate_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;//未知命令

    }

 
阅读(2012) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~