感谢支持
我们一直在努力

Linux设备模型之mmc,sd子系统<三>

####看一下重要的卡扫描函数,mmc_rescan,卡就指着他
####活着呢,


相关阅读:


Linux设备模型之mmc,sd子系统<一> http://www.linuxidc.com/Linux/2012-02/52948.htm


Linux设备模型之mmc,sd子系统<二>  http://www.linuxidc.com/Linux/2012-02/53024.htm


/driver/mmc/core/core.c


void mmc_rescan(struct work_struct *work)


{


 static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; //扫描试验的频率段


 struct mmc_host *host =


  container_of(work, struct mmc_host, detect.work);


 int i;


 if (host->rescan_disable)        //disable 直接返回
  return;



 mmc_bus_get(host);               //增加bus引用计数


 /*
  * if there is a _removable_ card registered, check whether it is
  * still present
  */
 if (host->bus_ops && host->bus_ops->detect && !host->bus_dead
     && !(host->caps & MMC_CAP_NONREMOVABLE))
  host->bus_ops->detect(host);          //存在热插拔卡,不包括emmc,调用探测函数


 /*
  * Let mmc_bus_put() free the bus/bus_ops if we’ve found that
  * the card is no longer present.
  */
 mmc_bus_put(host);                           //减少引用技术,就释放
 mmc_bus_get(host);                           //重新增加引用计数


 /* if there still is a card present, stop here */
 if (host->bus_ops != NULL) {
  mmc_bus_put(host);                   //如果卡仍然存在,减少引用计数,不必探测了
  goto out;
 }


 /*
  * Only we can add a new handler, so it’s safe to
  * release the lock here.
  */
 mmc_bus_put(host);                          //减少引用计数


 if (host->ops->get_cd && host->ops->get_cd(host) == 0)  //有卡,退出
  goto out;


 mmc_claim_host(host);                   //用于检测host是否被占用,占用则退出,否则标记成占用
 for (i = 0; i < ARRAY_SIZE(freqs); i++) {
  if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))   //利用不同的频率探测卡
   break;
  if (freqs[i] <= host->f_min)
   break;
 }
 mmc_release_host(host);


 out:


 if (host->caps & MMC_CAP_NEEDS_POLL)                   //轮询标志,设置了就会轮询


  mmc_schedule_delayed_work(&host->detect, HZ);


}


#####


/**


 * mmc_claim_host – exclusively claim a host


 * @host: mmc host to claim


 *


 * Claim a host for a set of operations.


 */


static inline void mmc_claim_host(struct mmc_host *host)


{


 __mmc_claim_host(host, NULL);


}


#####
/**
 * __mmc_claim_host – exclusively claim a host
 * @host: mmc host to claim
 * @abort: whether or not the operation should be aborted
 *
 * Claim a host for a set of operations.  If @abort is non null and
 * dereference a non-zero value then this will return prematurely with
 * that non-zero value without acquiring the lock.  Returns zero
 * with the lock held otherwise.
 */
int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
{
 DECLARE_WAITQUEUE(wait, current);                        //定义一个等待队列
 unsigned long flags;
 int stop;


 might_sleep();                                                                    //调度点
 
 add_wait_queue(&host->wq, &wait);
 spin_lock_irqsave(&host->lock, flags);
 while (1) {
  set_current_state(TASK_UNINTERRUPTIBLE);
  stop = abort ? atomic_read(abort) : 0;
  if (stop || !host->claimed || host->claimer == current)
   break;
  spin_unlock_irqrestore(&host->lock, flags);
  schedule();
  spin_lock_irqsave(&host->lock, flags);
 }                                                                                        //只有claim为空的时候还会跳出循环,否则就一直等待释放
 set_current_state(TASK_RUNNING);
 if (!stop) {
  host->claimed = 1;
  host->claimer = current;
  host->claim_cnt += 1;
 } else
  wake_up(&host->wq);
 spin_unlock_irqrestore(&host->lock, flags);
 remove_wait_queue(&host->wq, &wait);
 if (!stop)
  mmc_host_enable(host);   //使能该host
 return stop;
}



#####
mmc_host_enable函数可以做一些底电流工作


#####



/**
 * mmc_host_enable – enable a host.
 * @host: mmc host to enable
 *
 * Hosts that support power saving can use the ‘enable’ and ‘disable’
 * methods to exit and enter power saving states. For more information
 * see comments for struct mmc_host_ops.
 */
int mmc_host_enable(struct mmc_host *host)
{
 if (!(host->caps & MMC_CAP_DISABLE))
  return 0;


 if (host->en_dis_recurs)
  return 0;


 if (host->nesting_cnt++)
  return 0;


 cancel_delayed_work_sync(&host->disable);


 if (host->enabled)
  return 0;


 if (host->ops->enable) {
  int err;


  host->en_dis_recurs = 1;
  err = host->ops->enable(host);
  host->en_dis_recurs = 0;


  if (err) {
   pr_debug(“%s: enable error %d\n”,
     mmc_hostname(host), err);
   return err;
  }
 }
 host->enabled = 1;
 return 0;
}

#####
重点的卡探测函数,

#####



static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
{
 host->f_init = freq;


#ifdef CONFIG_MMC_DEBUG
 pr_info(“%s: %s: trying to init card at %u Hz\n”,
  mmc_hostname(host), __func__, host->f_init);
#endif
 mmc_power_up(host);                                                  //电源启用


 /*
  * Some eMMCs (with VCCQ always on) may not be reset after power up, so
  * do a hardware reset if possible.
  */
 mmc_hw_reset_for_init(host);                                      //针对emmc的硬件reset


 /*
  * sdio_reset sends CMD52 to reset card.  Since we do not know
  * if the card is being re-initialized, just send it.  CMD52
  * should be ignored by SD/eMMC cards.
  */
 sdio_reset(host);
 mmc_go_idle(host);                                                      //这部分与sd协议相关,可以结合前面内容来看


 mmc_send_if_cond(host, host->ocr_avail);


 /* Order’s important: probe SDIO, then SD, then MMC */
 if (!mmc_attach_sdio(host))                                        //各种卡类型探测初始化
  return 0;
 if (!mmc_attach_sd(host))
  return 0;
 if (!mmc_attach_mmc(host))
  return 0;


 mmc_power_off(host);                                                //关电
 return -EIO;
}


####在卡类型探测初始化过程中,重要的一个环节是和块设备的关联,这部分代码大致相同,


####例如mmc_attach_sd中,会有,


/drivers/mmc/core/sd.c




/*
 * Starting point for SD card init.
 */
int mmc_attach_sd(struct mmc_host *host)
{
    int err;
    u32 ocr;

    BUG_ON(!host);
    WARN_ON(!host->claimed);

    /* Make sure we are at 3.3V signalling voltage */
    err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, false);
    if (err)
        return err;

    /* Disable preset value enable if already set since last time */
    if (host->ops->enable_preset_value)
        host->ops->enable_preset_value(host, false);

    err = mmc_send_app_op_cond(host, 0, &ocr);
    if (err)
        return err;

    mmc_sd_attach_bus_ops(host);                                  //重要,bus操作的绑定
    if (host->ocr_avail_sd)
        host->ocr_avail = host->ocr_avail_sd;

    /*
     * We need to get OCR a different way for SPI.
     */
    if (mmc_host_is_spi(host)) {
        mmc_go_idle(host);

        err = mmc_spi_read_ocr(host, 0, &ocr);
        if (err)
            goto err;
    }

    /*
     * Sanity check the voltages that the card claims to
     * support.
     */
    if (ocr & 0x7F) {
        pr_warning(“%s: card claims to support voltages “
               “below the defined range. These will be ignored.\n”,
               mmc_hostname(host));
        ocr &= ~0x7F;
    }

    if ((ocr & MMC_VDD_165_195) &&
        !(host->ocr_avail_sd & MMC_VDD_165_195)) {
        pr_warning(“%s: SD card claims to support the “
               “incompletely defined ‘low voltage range’. This “
               “will be ignored.\n”, mmc_hostname(host));
        ocr &= ~MMC_VDD_165_195;
    }

    host->ocr = mmc_select_voltage(host, ocr);

    /*
     * Can we support the voltage(s) of the card(s)?
     */
    if (!host->ocr) {
        err = -EINVAL;
        goto err;
    }

    /*
     * Detect and init the card.
     */
    err = mmc_sd_init_card(host, host->ocr, NULL);
    if (err)
        goto err;

    mmc_release_host(host);
    err = mmc_add_card(host->card);                               //将卡加入
    mmc_claim_host(host);
    if (err)
        goto remove_card;

    return 0;

remove_card:
    mmc_release_host(host);
    mmc_remove_card(host->card);
    host->card = NULL;
    mmc_claim_host(host);
err:
    mmc_detach_bus(host);

    pr_err(“%s: error %d whilst initialising SD card\n”,
        mmc_hostname(host), err);

    return err;
}



#######首先是绑定操作mmc_sd_attach_bus_ops




static void mmc_sd_attach_bus_ops(struct mmc_host *host)
{
    const struct mmc_bus_ops *bus_ops;

    if (!mmc_card_is_removable(host))              //emmc和sd区别对待
        bus_ops = &mmc_sd_ops_unsafe;
    else
        bus_ops = &mmc_sd_ops;
    mmc_attach_bus(host, bus_ops);
}

####mmc_attach_bus函数会将bus的操作绑定到host上.


####core.c中


/*
 * Assign a mmc bus handler to a host. Only one bus handler may control a
 * host at any given time.
 */
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
{
    unsigned long flags;

    BUG_ON(!host);
    BUG_ON(!ops);

    WARN_ON(!host->claimed);

    spin_lock_irqsave(&host->lock, flags);

    BUG_ON(host->bus_ops);
    BUG_ON(host->bus_refs);

    host->bus_ops = ops;                                              //指向对应的操作结构
    host->bus_refs = 1;
    host->bus_dead = 0;

    spin_unlock_irqrestore(&host->lock, flags);
}


#####再看另外一个函数mmc_add_card,


####这个函数在bus.c 中,


/*
 * Register a new MMC card with the driver model.
 */
int mmc_add_card(struct mmc_card *card)
{
    int ret;
    const char *type;

    dev_set_name(&card->dev, “%s:%04x”, mmc_hostname(card->host), card->rca);

    switch (card->type) {
    case MMC_TYPE_MMC:
        type = “MMC”;
        break;
    case MMC_TYPE_SD:
        type = “SD”;
        if (mmc_card_blockaddr(card)) {
            if (mmc_card_ext_capacity(card))
                type = “SDXC”;
            else
                type = “SDHC”;
        }
        break;
    case MMC_TYPE_SDIO:
        type = “SDIO”;
        break;
    case MMC_TYPE_SD_COMBO:
        type = “SD-combo”;
        if (mmc_card_blockaddr(card))
            type = “SDHC-combo”;
        break;
    default:
        type = “?”;
        break;
    }

    if (mmc_host_is_spi(card->host)) {
        pr_info(“%s: new %s%s%s card on SPI\n”,
            mmc_hostname(card->host),
            mmc_card_highspeed(card) ? “high speed ” : “”,
            mmc_card_ddr_mode(card) ? “DDR ” : “”,
            type);
    } else {
        printk(KERN_INFO “%s: new %s%s%s card at address %04x\n”,
            mmc_hostname(card->host),
            mmc_sd_card_uhs(card) ? “ultra high speed ” :
            (mmc_card_highspeed(card) ? “high speed ” : “”),
            mmc_card_ddr_mode(card) ? “DDR ” : “”,
            type, card->rca);
    }

#ifdef CONFIG_DEBUG_FS
    mmc_add_card_debugfs(card);
#endif

    ret = device_add(&card->dev);
    if (ret)
        return ret;

    mmc_card_set_present(card);

    return 0;
}

####关注一下device_add(&card->dev);会把卡作为一个设备注册,

####这个注册会触发到bus里的match操作,这部分不理解的可以回顾前面讲到的设备模型,


####这里的bus对应mmc,调用的match函数对应于bus.c中




static struct bus_type mmc_bus_type = {
    .name        = “mmc”,
    .dev_attrs    = mmc_dev_attrs,
    .match        = mmc_bus_match,
    .uevent        = mmc_bus_uevent,
    .probe        = mmc_bus_probe,
    .remove        = mmc_bus_remove,
    .suspend    = mmc_bus_suspend,
    .resume        = mmc_bus_resume,
    .pm        = MMC_PM_OPS_PTR,
};


/*
 * This currently matches any MMC driver to any MMC card – drivers
 * themselves make the decision whether to drive this card in their
 * probe method.
 */
static int mmc_bus_match(struct device *dev, struct device_driver *drv)
{
    return 1;
}


####总为真,那么直接会触发bus的probe操作,


####


static int mmc_bus_probe(struct device *dev)
{
    struct mmc_driver *drv = to_mmc_driver(dev->driver);
    struct mmc_card *card = mmc_dev_to_card(dev);

    return drv->probe(card);
}


####会调用mmc_driver 里的probe,


####这里的mmc_driver就指的是block.c中的mmc_driver,


####还是看一下,这个过程吧,


####drivers/mmc/card/block.c


static int __init mmc_blk_init(void)
{
    int res;

    if (perdev_minors != CONFIG_MMC_BLOCK_MINORS)
        pr_info(“mmcblk: using %d minors per device\n”, perdev_minors);

    max_devices = 256 / perdev_minors;

    res = register_blkdev(MMC_BLOCK_MAJOR, “mmc”);              //注册mmc块设备,这个后面来讲
    if (res)
        goto out;

    res = mmc_register_driver(&mmc_driver);                                      //重点是这个
    if (res)
        goto out2;

    return 0;
 out2:
    unregister_blkdev(MMC_BLOCK_MAJOR, “mmc”);
 out:
    return res;
}


#####


static struct mmc_driver mmc_driver = {
    .drv        = {
        .name    = “mmcblk”,
    },
    .probe        = mmc_blk_probe,
    .remove        = mmc_blk_remove,
    .suspend    = mmc_blk_suspend,
    .resume        = mmc_blk_resume,
};


####在bus.c中


/**
 *    mmc_register_driver – register a media driver
 *    @drv: MMC media driver
 */
int mmc_register_driver(struct mmc_driver *drv)
{
    drv->drv.bus = &mmc_bus_type;
    return driver_register(&drv->drv);
}


####bus类型被指定成了mmc,也就是挂到了mmc上,这样刚才的卡注册默认全部匹配,


####所以也就会直接触发block里的probe,mmc_blk_probe


####下面的东西块设备关联比较多,放到下一章来讲




总结:描述了卡的识别阶段,并没有深入到卡的具体探测,这部分结合前面的协议转换图就不难理解,这部分主要集中在sd到块设备部分的过度


下一篇主要是针对mmc中的块设备。 见 http://www.linuxidc.com/Linux/2012-02/53139.htm


Thanks

赞(0) 打赏
转载请注明出处:服务器评测 » Linux设备模型之mmc,sd子系统<三>
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏