至此,我们已经跟踪了mmc/sd卡驱动的注册。。我们接着来看插入拔除卡的中断处理函数:
static irqreturn_t s3cmci_irq_cd(int irq, void *dev_id) { struct s3cmci_host *host = (struct s3cmci_host *)dev_id;
dbg(host, dbg_irq, "card detect\n");
mmc_detect_change(host->mmc, 500);
return IRQ_HANDLED; }
|
可见,这里也会调用mmc_detect_change。。。我们跟着前面的分析来到mmc_setup这里,此时mmc_setup调用mmc_discover_cards。Create a mmc_card entry for each discovered card,add new card to list.同时还会调用mmc_read_switch_caps或者mmc_process_ext_csds来实现对大容量卡的支持(>4G)
跟着程序的流程我们来到
if (!mmc_card_present(card) && !mmc_card_dead(card)) {
if (mmc_register_card(card))
来看
int mmc_register_card(struct mmc_card *card) { int ret;
snprintf(card->dev.bus_id, sizeof(card->dev.bus_id), "%s:%04x", mmc_hostname(card->host), card->rca);
ret = device_add(&card->dev); if (ret == 0) { if (mmc_card_sd(card)) { ret = device_create_file(&card->dev, &mmc_dev_attr_scr); if (ret) device_del(&card->dev); } } return ret; }
|
此函数在mmc_sysfs.c中定义。 device_add(&card->dev)将到相应总线mmc_bus_type上去搜索相应驱动。找到驱动后就设置dev->driver=drv,并调用mmc_bus_type总线的probe函数被调用,即mmmc_bus_probe函数
static int mmc_bus_probe(struct device *dev) { struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = dev_to_mmc_card(dev);
return drv->probe(card); }
|
mmc_bus_probe会调用mmc_blk_probe
mmc_blk_probe()首先分配一个新的mmc_blk_data结构变量,然后调用mmc_init_queue,初始化blk队列。然后建立一个线程mmc_queue_thread()。
static int mmc_blk_probe(struct mmc_card *card) { struct mmc_blk_data *md; int err;
/* * Check that the card supports the command class(es) we need. */ if (!(card->csd.cmdclass & CCC_BLOCK_READ)) 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 "%s: %s %s %lluKiB %s\n", md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), (unsigned long long)(get_capacity(md->disk) >> 1), md->read_only ? "(ro)" : "");
mmc_set_drvdata(card, md); add_disk(md->disk); return 0;
out: mmc_blk_put(md);
return err; }
|
struct mmc_blk_data封装了struct gendisk 与 struct mmc_queue,而struct mmc_queue封装了struct mmc_card与struct request。
static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) { struct mmc_blk_data *md; int devidx, ret;
devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS); if (devidx >= MMC_NUM_MINORS) return ERR_PTR(-ENOSPC); __set_bit(devidx, dev_use);
md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL); if (!md) { ret = -ENOMEM; goto out; }
memset(md, 0, sizeof(struct mmc_blk_data));
/* * Set the read-only status based on the supported commands * and the write protect switch. */ md->read_only = mmc_blk_readonly(card);//写保护
/* * Both SD and MMC specifications state (although a bit * unclearly in the MMC case) that a block size of 512 * bytes must always be supported by the card. */ md->block_bits = 9;//块大小
md->disk = alloc_disk(1 << MMC_SHIFT); //分配struct gendist,驱动程序不能自己动态分配该结构,而是必须调用
//alloc_disk,其参数为次设备号数目,注意了,是次设备号数目,不是次设备号
if (md->disk == NULL) { ret = -ENOMEM; goto err_kfree; }
spin_lock_init(&md->lock); md->usage = 1;
ret = mmc_init_queue(&md->queue, card, &md->lock);//
if (ret) goto err_putdisk;
md->queue.prep_fn = mmc_blk_prep_rq; md->queue.issue_fn = mmc_blk_issue_rq; md->queue.data = md; //上面设置了请求队列,现在就可以初始化及安装相应的gendisk结构了
md->disk->major = 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;
/* * As discussed on lkml, GENHD_FL_REMOVABLE should: * * - be set for removable media with permanent block devices * - be unset for removable block devices with permanent media * * Since MMC block devices clearly fall under the second * case, we do not set GENHD_FL_REMOVABLE. Userspace * should use the block device creation/destruction hotplug * messages to tell when the card is present. */
sprintf(md->disk->disk_name, "mmcblk%d", devidx);
blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
/* * The CSD capacity field is in units of read_blkbits. * set_capacity takes units of 512 bytes. */ set_capacity(md->disk, card->csd.capacity << (card->csd.read_blkbits - 9)); return md;
err_putdisk: put_disk(md->disk); err_kfree: kfree(md); out: return ERR_PTR(ret); }
|
至此,驱动向系统添加了一个块设备。
请求处理过程:
mmc_request--->mmc_queue_thread----->mmc_blk_issue_rq---->mmc_wait_for_req--->mmc_start_request---->s3cmci_request
阅读(1292) | 评论(0) | 转发(0) |