1.块设备注册函数
在块设备的注册和初始化阶段,与字符设备驱动类似,块设备驱动要注册他们自己到内核,申请设备号。
int register_blkdev(unsigned int major,const char *name);
major参数是块设备要使用的主设备号;
name为设备名,他会在/proc/device中,如果major为0,内核会自动分配一个新的主设备号;
register_blkdev()函数的返回值就是这个主设备号,返回一个复制,表明发生错误了。
2.注销函数
int unregister_blkdev(unsigned int major,const char *name);
3.块设备初始化代码
在块设备驱动初始化过程中,通常需要完成分配请求队列、初始化请求队列,绑定请求队列和请求处理函数的工作,并且可能会分配gendisk,初始化gendisk,给gendisk的major,fops,queue等成员的赋值,最后添加gendisk。
如下代码演示了一个典型的块设备驱动的初始化过程,其中包含了register_blkdev(),blk_init_queue()和add_disk()的工作。
static int 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_max_hw_sector(xxx_queue,255);
blk_queue_logical_block_size(xxx_queue,512);
}
在块设备驱动的卸载过程中,完成与模块加载函数相反的工作。
(1).清除请求队列,使用blk_cleanup_queue();
(2).删除对gendisk的引用,使用put_disk();
(3).删除对块设备的引用,注销块设备驱动,使用unregister_blkdev()。
4.块设备的打开与释放
在open()中我们可以通过block_device参数bdev获取private_data,在release()函数中则通过gendisk参数disk获取。
在块设备的open()/release()函数中获取private_data。
static int xxx_open(struct block_device *bdev,fmode_t mode)
{
struct xxx_dev *dev = bdev->bd_disk->private_data;
......
return 0;
}
static void xxx_release(struct gendisk *disk,fmode_t mode)
{
struct xxx_dev *dev = disk->private_data;
......
}
5.块设备驱动的ioctl函数
高层的块设备层代码处理了绝大数I/O控制,如BLKFLSBUF、BLKROSET、BLKDISCARD、HDIO_GETGEO、BLKROGET和BLKSECTGET等,因此,在具体的块设备驱动中通常只需要实现与设备相关的特定ioctl命令。例如,源代码文件为driver/block/floppy.c实现了与软件驱动相关的命令(如FDEJECT、FDSERPRM、FDFMTTRK等);
Linux MMC子系统支持一个IOCTL命令MMC_IOC_CMD,driver/mmc/card/block.c实现了这个命令的处理。
Linux MMC块设备的ioctl()函数
static int mmc_blk_ioctl(struct block_device *bdev,fmode_t mode,unsigned int cmd,unsigned long arg)
{
int ret = EINVAL;
if(cmd == MMC_IOC_CMD)
{
ret = mmc_blk_ioctl_cmd(bdev,(struct mmc_ioc_cmd __user *)arg);
}
return ret;
}



