mmc驱动中的mmc_host结构体中rescan_disable变量的作用及使用

来源:互联网 发布:ds18b20数据手册pdf 编辑:程序博客网 时间:2024/06/07 15:02

一、rescan_disable的作用

该变量在mmc_host中是这样定义的:

intrescan_disable;/* disable card detection */
注释的意思:取消探测卡的操作。

作用:当为0,表示开启卡的探测开关;为非0表示关闭卡的探测。


二、被调用的地方

rescan_disable=0rescan_disable=1mmc_start_host(core.c)mmc_stop_host(core.c)mmc_pm_notify的准备挂载休眠分支mmc_pm_notify的挂载休眠分支 mmc_alloc_host(host.c)


三、重点需要说明的先后调用关系

在host初始化完成之前,由于此时host没有做好探测卡的准备,所以在初始化完成前将rescan_disable的值设置为1,下面结合代码来说明。

还是以mmci的host来说明,在mmci.c中有一个mmci的probe函数,如下:

static int mmci_probe(struct amba_device *dev,const struct amba_id *id){struct mmci_platform_data *plat = dev->dev.platform_data;struct device_node *np = dev->dev.of_node;struct variant_data *variant = id->data;struct mmci_host *host;struct mmc_host *mmc;int ret;/* Must have platform data or Device Tree. */if (!plat && !np) {dev_err(&dev->dev, "No plat data or DT found\n");return -EINVAL;}if (!plat) {plat = devm_kzalloc(&dev->dev, sizeof(*plat), GFP_KERNEL);if (!plat)return -ENOMEM;}if (np)mmci_dt_populate_generic_pdata(np, plat);ret = amba_request_regions(dev, DRIVER_NAME);if (ret)goto out;mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev);if (!mmc) {ret = -ENOMEM;goto rel_regions;}host = mmc_priv(mmc);host->mmc = mmc;host->gpio_wp = -ENOSYS;host->gpio_cd = -ENOSYS;host->gpio_cd_irq = -1;host->hw_designer = amba_manf(dev);host->hw_revision = amba_rev(dev);dev_dbg(mmc_dev(mmc), "designer ID = 0x%02x\n", host->hw_designer);dev_dbg(mmc_dev(mmc), "revision = 0x%01x\n", host->hw_revision);host->clk = devm_clk_get(&dev->dev, NULL);if (IS_ERR(host->clk)) {ret = PTR_ERR(host->clk);goto host_free;}ret = clk_prepare_enable(host->clk);if (ret)goto host_free;host->plat = plat;host->variant = variant;host->mclk = clk_get_rate(host->clk);/* * According to the spec, mclk is max 100 MHz, * so we try to adjust the clock down to this, * (if possible). */if (host->mclk > 100000000) {ret = clk_set_rate(host->clk, 100000000);if (ret < 0)goto clk_disable;host->mclk = clk_get_rate(host->clk);dev_dbg(mmc_dev(mmc), "eventual mclk rate: %u Hz\n",host->mclk);}host->phybase = dev->res.start;host->base = ioremap(dev->res.start, resource_size(&dev->res));if (!host->base) {ret = -ENOMEM;goto clk_disable;}if (variant->busy_detect) {mmci_ops.card_busy = mmci_card_busy;mmci_write_datactrlreg(host, MCI_ST_DPSM_BUSYMODE);}mmc->ops = &mmci_ops;/* * The ARM and ST versions of the block have slightly different * clock divider equations which means that the minimum divider * differs too. */if (variant->st_clkdiv)mmc->f_min = DIV_ROUND_UP(host->mclk, 257);elsemmc->f_min = DIV_ROUND_UP(host->mclk, 512);/* * If the platform data supplies a maximum operating * frequency, this takes precedence. Else, we fall back * to using the module parameter, which has a (low) * default value in case it is not specified. Either * value must not exceed the clock rate into the block, * of course. */if (plat->f_max)mmc->f_max = min(host->mclk, plat->f_max);elsemmc->f_max = min(host->mclk, fmax);dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max);/* Get regulators and the supported OCR mask */mmc_regulator_get_supply(mmc);if (!mmc->ocr_avail)mmc->ocr_avail = plat->ocr_mask;else if (plat->ocr_mask)dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n");mmc->caps = plat->capabilities;mmc->caps2 = plat->capabilities2;/* We support these PM capabilities. */mmc->pm_caps = MMC_PM_KEEP_POWER;/* * We can do SGIO */mmc->max_segs = NR_SG;/* * Since only a certain number of bits are valid in the data length * register, we must ensure that we don't exceed 2^num-1 bytes in a * single request. */mmc->max_req_size = (1 << variant->datalength_bits) - 1;/* * Set the maximum segment size.  Since we aren't doing DMA * (yet) we are only limited by the data length register. */mmc->max_seg_size = mmc->max_req_size;/* * Block size can be up to 2048 bytes, but must be a power of two. */mmc->max_blk_size = 1 << 11;/* * Limit the number of blocks transferred so that we don't overflow * the maximum request size. */mmc->max_blk_count = mmc->max_req_size >> 11;spin_lock_init(&host->lock);writel(0, host->base + MMCIMASK0);writel(0, host->base + MMCIMASK1);writel(0xfff, host->base + MMCICLEAR);if (plat->gpio_cd == -EPROBE_DEFER) {ret = -EPROBE_DEFER;goto err_gpio_cd;}if (gpio_is_valid(plat->gpio_cd)) {ret = gpio_request(plat->gpio_cd, DRIVER_NAME " (cd)");if (ret == 0)ret = gpio_direction_input(plat->gpio_cd);if (ret == 0)host->gpio_cd = plat->gpio_cd;else if (ret != -ENOSYS)goto err_gpio_cd;/* * A gpio pin that will detect cards when inserted and removed * will most likely want to trigger on the edges if it is * 0 when ejected and 1 when inserted (or mutatis mutandis * for the inverted case) so we request triggers on both * edges. */ret = request_any_context_irq(gpio_to_irq(plat->gpio_cd),mmci_cd_irq,IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,DRIVER_NAME " (cd)", host);if (ret >= 0)host->gpio_cd_irq = gpio_to_irq(plat->gpio_cd);}if (plat->gpio_wp == -EPROBE_DEFER) {ret = -EPROBE_DEFER;goto err_gpio_wp;}if (gpio_is_valid(plat->gpio_wp)) {ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)");if (ret == 0)ret = gpio_direction_input(plat->gpio_wp);if (ret == 0)host->gpio_wp = plat->gpio_wp;else if (ret != -ENOSYS)goto err_gpio_wp;}if ((host->plat->status || host->gpio_cd != -ENOSYS)    && host->gpio_cd_irq < 0)mmc->caps |= MMC_CAP_NEEDS_POLL;ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host);if (ret)goto unmap;if (!dev->irq[1])host->singleirq = true;else {ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED,  DRIVER_NAME " (pio)", host);if (ret)goto irq0_free;}writel(MCI_IRQENABLE, host->base + MMCIMASK0);amba_set_drvdata(dev, mmc);dev_info(&dev->dev, "%s: PL%03x manf %x rev%u at 0x%08llx irq %d,%d (pio)\n", mmc_hostname(mmc), amba_part(dev), amba_manf(dev), amba_rev(dev), (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]);mmci_dma_setup(host);pm_runtime_set_autosuspend_delay(&dev->dev, 50);pm_runtime_use_autosuspend(&dev->dev);pm_runtime_put(&dev->dev);mmc_add_host(mmc);return 0; irq0_free:free_irq(dev->irq[0], host); unmap:if (host->gpio_wp != -ENOSYS)gpio_free(host->gpio_wp); err_gpio_wp:if (host->gpio_cd_irq >= 0)free_irq(host->gpio_cd_irq, host);if (host->gpio_cd != -ENOSYS)gpio_free(host->gpio_cd); err_gpio_cd:iounmap(host->base); clk_disable:clk_disable_unprepare(host->clk); host_free:mmc_free_host(mmc); rel_regions:amba_release_regions(dev); out:return ret;}

第30行,有一个mmc_alloc_host的函数,通过第二节可以知道,这个函数将rescan_disable标记设置为了1;

第231行,有一个mmc_add_host的函数,其实现如下:

int mmc_add_host(struct mmc_host *host){int err;WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&!host->ops->enable_sdio_irq);err = device_add(&host->class_dev);if (err)return err;led_trigger_register_simple(dev_name(&host->class_dev), &host->led);#ifdef CONFIG_DEBUG_FSmmc_add_host_debugfs(host);#endifmmc_host_clk_sysfs_init(host);mmc_start_host(host);register_pm_notifier(&host->pm_notify);return 0;}
由此可以知道,它调用了mmc_start_host函数,通过第二节可以知道,这个函数将rescan_disable设置为了0,开启了卡的侦测。

总结:在mmci_probe中先关闭卡的侦测,初始化一个host,当host初始化完毕,则开启侦测,此时如果有卡设备接到总线上,就会调用中断函数mmci_cd_irq去完成卡的上盘操作。

0 0
原创粉丝点击