Chinaunix首页 | 论坛 | 博客
  • 博客访问: 318011
  • 博文数量: 68
  • 博客积分: 1501
  • 博客等级: 上尉
  • 技术积分: 1010
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-30 09:52
文章分类

全部博文(68)

文章存档

2010年(1)

2009年(67)

我的朋友

分类:

2009-01-08 14:10:51

至此,我们已经跟踪了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
阅读(1287) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~