/*
* These are the response types, and correspond to valid bit * patterns of the above flags. One additional valid pattern * is all zeros, which means we don't expect a response. */
#define MMC_RSP_R1 (MMC_RSP_SHORT|MMC_RSP_CRC)
#define MMC_RSP_R1B (MMC_RSP_SHORT|MMC_RSP_CRC|MMC_RSP_BUSY) #define MMC_RSP_R2 (MMC_RSP_LONG|MMC_RSP_CRC) #define MMC_RSP_R3 (MMC_RSP_SHORT) unsigned int retries; /* max number of retries */ unsigned int error; /* command error */
#define MMC_ERR_NONE 0 #define MMC_ERR_TIMEOUT 1 #define MMC_ERR_BADCRC 2 #define MMC_ERR_FIFO 3 #define MMC_ERR_FAILED 4 #define MMC_ERR_INVALID 5 struct mmc_data *data; //与命令相关的数据片断 struct mmc_request *mrq; //与命令相关的请求 };
MMC抽象设备层MMC块设备驱动程序
(1)MMC块设备驱动程序初始化
函数mmc_blk_init注册一个MMC块设备驱动程序,它先将MMC块设备名注册到名称数组major_names中,然后,还把驱动程序注册到sysfs文件系统中的总线和设备目录中。一方面,sysfs文件系统中可显示MMC块设备相关信息,另一方面,sysfs文件系统以树形结构管理着MMC块设备驱动程序。 函数mmc_blk_init分析如下(在drivers/mmc/mmc_block.c中):
static int __init mmc_blk_init(void)
{ int res = -ENOMEM;
//将卡名字mmc和major注册到块设备的名称数组major_names中 res = register_blkdev(major, \ if (res < 0) { printk(KERN_WARNING \media: %d\\n\ major, res); goto out; } if (major == 0) major = res;
//在devfs文件系统中创建mmc目录 devfs_mk_dir(\ return mmc_register_driver(&mmc_driver);
out: return res; }
mmc_driver驱动程序实例声明如下:
static struct mmc_driver mmc_driver = { .drv = { .name = \ }, .probe = mmc_blk_probe, // MMC块设备驱动程序探测函数 .remove = mmc_blk_remove, .suspend = mmc_blk_suspend, .resume = mmc_blk_resume, };
函数mmc_register_driver 注册一个媒介层驱动程序。其中参数drv是MMC媒介层驱动程序结构。
函数mmc_register_driver分析如下(在drivers/mmc/mmc_sysfs.c中):
int mmc_register_driver(struct mmc_driver *drv) { drv->drv.bus = &mmc_bus_type; drv->drv.probe = mmc_drv_probe; drv->drv.remove = mmc_drv_remove;
//把块设备注册到sysfs文件系统中对应的总线及设备目录下 return driver_register(&drv->drv); }
(2)MMC块设备驱动程序探测函数
图 函数mmc_blk_probe调用层次图
函数mmc_blk_probe是MMC控制器探测函数,它探测MMC控制器是否存在,并初始化控制器的结构,同时,还探测MMC卡的状态并初始化。函数mmc_blk_probe调用层次图如上图。
函数mmc_blk_probe列出如下:
static int mmc_blk_probe(struct mmc_card *card) { struct mmc_blk_data *md; //每个插槽一个结构mmc_blk_data int err; if (card->csd.cmdclass & ~0x1ff) return -ENODEV;
if (card->csd.read_blkbits < 9) {//所读的块小于1扇区 printk(KERN_WARNING \(%u)\\n\ mmc_card_id(card), 1 << card->csd.read_blkbits); return -ENODEV; }
//分配每个插槽的卡的块数据结构,初始化了通用硬盘及请求队列 md = mmc_blk_alloc(card); if (IS_ERR(md)) return PTR_ERR(md);
//设置块大小,发命令设置卡为选中状态 err = mmc_blk_set_blksize(md, card); if (err) goto out; printk(KERN_INFO \ md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), (card->csd.capacity << card->csd.read_blkbits) / 1024); mmc_set_drvdata(card, md);//即card ->driver_data = md add_disk(md->disk); //向系统注册通用硬盘结构,它包括每分区信息 return 0;
out: mmc_blk_put(md); return err; }
函数*mmc_blk_alloc给每一插槽分配一个结构mmc_blk_data,并分配设置通用硬盘结构和初始了请求队列结构。
函数*mmc_blk_alloc分析如下(在drivers/mmc/mmc_block.c中):
//最大支持8个控制器,每个控制器可控制4个卡,每个卡最大8个分区。 #define MMC_SHIFT 3 //表示每个卡最大支持8个分区 #define MMC_NUM_MINORS (256 >> MMC_SHIFT) //为256/8=32
//即定义dev_use[32/(8*4)] = devuse[1],一个控制器用32位表示使用情况 static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))]; static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) { struct mmc_blk_data *md; int devidx, ret;
//查找dev_use中第一个bit为0的位序号(在MMC_NUM_MINORS位以内) //找到第个空闲的分区 devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS); if (devidx >= MMC_NUM_MINORS) return ERR_PTR(-ENOSPC); __set_bit(devidx, dev_use);//将分区对应的位设置为1,表示使用。 md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);//分配对象空间 if (md) { memset(md, 0, sizeof(struct mmc_blk_data)); //分配gendisk结构及通用硬盘的分区hd_struct结构,并初始化内核对象 md->disk = alloc_disk(1 << MMC_SHIFT); if (md->disk == NULL) { kfree(md); md = ERR_PTR(-ENOMEM); goto out; } spin_lock_init(&md->lock); md->usage = 1; //初始化请求队列 ret = mmc_init_queue(&md->queue, card, &md->lock); if (ret) { put_disk(md->disk); kfree(md); md = ERR_PTR(ret); goto out; }
//赋上各种请求队列处理函数 md->queue.prep_fn = mmc_blk_prep_rq;//准备请求 md->queue.issue_fn = mmc_blk_issue_rq;//发出请求让设备开始处理 md->queue.data = md; //初始化通用硬盘 md->disk->major = major;