一、rescan_disable的作用

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

int          rescan_disable; /* disable card detection */

注释的意思:取消探测卡的操作。

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

二、被调用的地方

rescan_disable=0 rescan_disable=1
mmc_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去完成卡的上盘操作。

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

  1. 【Kernel】如何从kernel中获取cred结构体中的value

    获取linux kernel cred结构体中成员变量的value时,根绝kernel版本需要做适配. linux kernel 3.5以上,获取cred需要如下处理(重点 cred->uid. ...

  2. 驱动下通过进程PID获得进程名 (动态获取ImageFileName在EPROCESS结构体中的相对偏移)...

    思路 进程EPROCESS结构体中含有进程名ImageFileName(需求处ImageFileName在EPROCESS结构体中的相对偏移)-->获得进程EPROCESS-->通过进程句 ...

  3. file结构体中private_data指针的疑惑

    转:http://www.360doc.com/content/12/0506/19/1299815_209093142.shtml hi all and barry, 最近在学习字符设备驱动,不太明 ...

  4. golang sqlx scan 到结构体中_Golang语言并发编程之定时器

    上一章中对于golang的常用关键字说明如下: 1 for 和 range 2 select 3 defer 4 panic 和 recover 5 make 和 new 接下来我们来对golang的 ...

  5. C语言结构体中定义函数指针详解

    C语言结构体中定义函数指针详解 结构体指针函数应用场景之一--驱动程序编写 结构体的一些基本用法 形式1:先定义结构体类型,再定义变量 形式2:在定义类型的同时定义变量 形式3:直接定义变量,用无名结 ...

  6. 获取结构体中变量的偏移量

    C/C++获取结构体中变量的偏移量 1.某些特殊需求下,我们需要知道某个变量在其结构体中的偏移位置. 通常的做法就是定义一个宏变量,如下: #define OFFSET(structure, memb ...

  7. 结构体中定义函数指针

    结构体指针变量的定义,定义结构体变量的一般形式如下: 形式1:先定义结构体类型,再定义变量 struct结构体标识符 { 成员变量列表;- }; struct 结构体标识符 *指针变量名; 变量初始化 ...

  8. 结构体中最后一个成员为[0]或[1]长度数组(柔性数组成员)的用法

    结构体中最后一个成员为[0]长度数组的用法:这是个广泛使用的常见技巧,常用来构成缓冲区.比起指针,用空数组有这样的优势:(1).不需要初始化,数组名直接就是所在的偏移:(2).不占任何空间,指针需要占 ...

  9. 【C语言】宏offsetof的模拟实现 (计算结构体中某变量相对于首地址的偏移)

    首先我们应该特别留意 : offsetof 是一个宏,并非是一个函数 ! 宏offsetof的介绍 : 参数:第一个是结构体类型名称,第二个是结构体成员名 返回类型:size_t无符号整形 引用的头文 ...

  10. Swift 中枚举、结构体、类(enum、struct、class)

    Swift 中枚举.结构体.类(enum.struct.class) Swift中的枚举与OC相比不会自动分配初始值,值的类型不会限定为整数,可以给定关联值类型和具体值(整型.浮点型.字符型(Swif ...

最新文章

  1. Python基础18-常用模块之os、sys、json、pickle、shelve、xml、re、logging、configparse、hashlib等
  2. HDU2724 Tree【最小生成树】
  3. 【尚硅谷】大厂必备技术之JUC并发编程——笔记总结
  4. hdu 3303(线段树+抽屉原理)
  5. 7-41 PAT排名汇总 (25 分)(详解+思路+重写sort函数)兄弟们冲呀呀呀呀呀呀呀
  6. 看完这个故事,你就知道程序员为什么选公司就要去上升期的
  7. 强大的jQuery选择器之选定连续多行
  8. 读者教育浏览器兼容解决方法
  9. 铁威马NAS使用docker安装全网音乐教程
  10. Laravel核心概念:服务容器(ServiceContainer),服务提供者(Service Provider),门面(Facade),契约(Contracts)
  11. android开发塔防游戏机,上手快又耐玩 五款Android平台塔防类游戏推荐
  12. Java 递归实现树形菜单
  13. SpringBoot整合——阿里云对象存储(OSS)
  14. 指针--指针的创建和指针的大小
  15. RuntimeError: cannot release un-acquired lock
  16. html 中 table tr td br 什么意思 是什么的缩写
  17. electron-builder打包linux桌面程序(OIM-E多平台即时通讯软件)
  18. 上年度最受老妈欢迎滴戏言
  19. app式成语_成语大全四字成语下载-成语大全appv2.2.2 安卓版-腾牛安卓网
  20. 图解华为云需求管理工具——CodeArts Req

热门文章

  1. springboot实现微信公众号群发消息功能
  2. recv( )函数返回值说明
  3. Iredmail搭建
  4. Python和R语言的区别
  5. CSS(三)盒子模型
  6. visio流程图怎么合并线_6步轻松做Visio跨职能流程图
  7. 一篇文章带你深入了解Dart语言
  8. Dart 语言基础分步指南
  9. Tomcat创建Servlet容器
  10. 马云给阿里的礼物:90多项区块链专利,全球最多