Linux设备驱动子系统第二弹- SD卡 - 图文(9)

2019-08-31 13:59

插入SD卡,注册驱动成功,那么在开发板的目录/dev/block下会出现SD卡的设备节

点。

179为主设备号,定义于include/linux/major.h #define MMC_BLOCK_MAJOR 179 179:0代表这块SD卡的设备节点mmcblk0,179:1代表这块SD卡的第一个分区mmcblk0p1,即主分区,如果有第二个分区,那就是179:2,最多可以有7个分区,即179:1~179:7(定义于block.c alloc_disk(1 << 3);)。不过,SD卡一般只有一个分区。如果有第二块SD卡插入,将会建立设备节点mmcblk1(179:8)和mmcblk1p1(179:9)。

下面通过对块设备驱动block.c的分析,看看SD卡是如何在块设备层建立节点和传输数据的。 4.1 数据结构 每个驱动都会有一个数据结构。幸运的是,我们SD卡块设备驱动的数据结构相对简单,在mmc_blk_data里,主要有两个成员,struct gendisk *disk和struct mmc_queue queue。

1) struct gendisk 是general disk的缩写,代表个通用的块设备,其中包括块设备的主分区结构struct hd_struct part0, 块设备的行为函数struct block_device_operations *fops,以及请求队列struct request_queue *queue等。 2) struct request_queue 存放所有I/O调度的算法。

3) struct request 请求是I/O调度者调度的对象,其中的结构struct bio是整个请求队列的核心,具体内容请参看LDD3。

4.2 块设备驱动 首先浏览一下源码,

static int __init mmc_blk_init(void) {

register_blkdev(MMC_BLOCK_MAJOR, \// 注册主设备号(若注册成功,/proc/devices的块设备下会出现mmc) mmc_register_driver(&mmc_driver); return 0; }

static struct mmc_driver mmc_driver = { .drv = {

.name = \ },

.probe = mmc_blk_probe, .remove = mmc_blk_remove,

.suspend = mmc_blk_suspend, .resume = mmc_blk_resume, };

static int mmc_blk_probe(struct mmc_card *card) {

struct mmc_blk_data *md; md = mmc_blk_alloc(card); mmc_blk_set_blksize(md, card); mmc_set_drvdata(card, md); add_disk(md->disk); return 0; ... ... }

4.2.1 设备驱动的初始化函数

仍然可以将驱动程序的初始化mmc_blk_probe(struct mmc_card *card)归纳为以下内容,

? ? ? ?

初始化设备驱动的数据结构mmc_blk_data,并挂载到card->dev.driver_data 实现块备驱动的功能函数struct block_device_operations *fops 注册设备,即注册kobject,建立sys文件,发送uevent等 其他需求,如mmc_blk_set_blksize(md, card);

1) 初始化mmc_blk_data

static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) {

struct mmc_blk_data *md;

md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);

md->read_only = mmc_blk_readonly(card);

md->disk = alloc_disk(1 << 3); // 分配了8个可用设备

spin_lock_init(&md->lock); md->usage = 1;

ret = mmc_init_queue(&md->queue, card, &md->lock); md->queue.issue_fn = mmc_blk_issue_rq; md->queue.data = md;

md->disk->major = MMC_BLOCK_MAJOR; md->disk->first_minor = devidx << MMC_SHIFT; md->disk->fops = &mmc_bdops; md->disk->private_data = md;

md->disk->queue = md->queue.queue; md->disk->driverfs_dev = &card->dev;

blk_queue_logical_block_size(md->queue.queue, 512); ... ... return md; }

完成初始化后,通过mmc_set_drvdata(card, md);将数据挂载到card->dev.driver_data下。 2) 功能函数

static const struct block_device_operations mmc_bdops = { .open = mmc_blk_open, .release = mmc_blk_release, .getgeo = mmc_blk_getgeo, .owner = THIS_MODULE, };

static int mmc_blk_open(struct block_device *bdev, fmode_t mode) {

struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);

... ... }

struct block_device {

dev_t bd_dev; /* it's a search key */ struct inode * bd_inode; /* will die */ struct super_block * bd_super; ... ... };

与字符驱动类似,通过dev_t和inode找到设备。 3) 注册驱动

void add_disk(struct gendisk *disk) {

blk_register_region(disk_devt(disk), disk->minors, NULL, exact_match, exact_lock, disk); register_disk(disk); blk_register_queue(disk); ... ... }

blk_register_region()在linux中实现了一种利用哈希表管理设备号的机制。 register_disk()对应alloc_disk(),完成对块设备的注册,其实质是通过

register_disk()->blkdev_get()->__blkdev_get()->rescan_partitions()->add_partitions()添加

分区,建立设备节点。

blk_register_queue()对应blk_init_queue()完成对请求队列的注册,其实质是通过elv_register_queue()注册请求队列的算法。

关于块设备更为具体的代码分析可参看linux那些事。 4.2.2 请求队列

mmc_init_queue申请并初始化一个请求队列,开启负责处理这个请求队列的守护进程。


Linux设备驱动子系统第二弹- SD卡 - 图文(9).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:太阳能热水器控制仪使用说明书资料

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: