mmc驱动中的mmc_host结构体中rescan_disable变量的作用及使用
一、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变量的作用及使用相关推荐
- 【Kernel】如何从kernel中获取cred结构体中的value
获取linux kernel cred结构体中成员变量的value时,根绝kernel版本需要做适配. linux kernel 3.5以上,获取cred需要如下处理(重点 cred->uid. ...
- 驱动下通过进程PID获得进程名 (动态获取ImageFileName在EPROCESS结构体中的相对偏移)...
思路 进程EPROCESS结构体中含有进程名ImageFileName(需求处ImageFileName在EPROCESS结构体中的相对偏移)-->获得进程EPROCESS-->通过进程句 ...
- file结构体中private_data指针的疑惑
转:http://www.360doc.com/content/12/0506/19/1299815_209093142.shtml hi all and barry, 最近在学习字符设备驱动,不太明 ...
- golang sqlx scan 到结构体中_Golang语言并发编程之定时器
上一章中对于golang的常用关键字说明如下: 1 for 和 range 2 select 3 defer 4 panic 和 recover 5 make 和 new 接下来我们来对golang的 ...
- C语言结构体中定义函数指针详解
C语言结构体中定义函数指针详解 结构体指针函数应用场景之一--驱动程序编写 结构体的一些基本用法 形式1:先定义结构体类型,再定义变量 形式2:在定义类型的同时定义变量 形式3:直接定义变量,用无名结 ...
- 获取结构体中变量的偏移量
C/C++获取结构体中变量的偏移量 1.某些特殊需求下,我们需要知道某个变量在其结构体中的偏移位置. 通常的做法就是定义一个宏变量,如下: #define OFFSET(structure, memb ...
- 结构体中定义函数指针
结构体指针变量的定义,定义结构体变量的一般形式如下: 形式1:先定义结构体类型,再定义变量 struct结构体标识符 { 成员变量列表;- }; struct 结构体标识符 *指针变量名; 变量初始化 ...
- 结构体中最后一个成员为[0]或[1]长度数组(柔性数组成员)的用法
结构体中最后一个成员为[0]长度数组的用法:这是个广泛使用的常见技巧,常用来构成缓冲区.比起指针,用空数组有这样的优势:(1).不需要初始化,数组名直接就是所在的偏移:(2).不占任何空间,指针需要占 ...
- 【C语言】宏offsetof的模拟实现 (计算结构体中某变量相对于首地址的偏移)
首先我们应该特别留意 : offsetof 是一个宏,并非是一个函数 ! 宏offsetof的介绍 : 参数:第一个是结构体类型名称,第二个是结构体成员名 返回类型:size_t无符号整形 引用的头文 ...
- Swift 中枚举、结构体、类(enum、struct、class)
Swift 中枚举.结构体.类(enum.struct.class) Swift中的枚举与OC相比不会自动分配初始值,值的类型不会限定为整数,可以给定关联值类型和具体值(整型.浮点型.字符型(Swif ...
最新文章
- Python基础18-常用模块之os、sys、json、pickle、shelve、xml、re、logging、configparse、hashlib等
- HDU2724 Tree【最小生成树】
- 【尚硅谷】大厂必备技术之JUC并发编程——笔记总结
- hdu 3303(线段树+抽屉原理)
- 7-41 PAT排名汇总 (25 分)(详解+思路+重写sort函数)兄弟们冲呀呀呀呀呀呀呀
- 看完这个故事,你就知道程序员为什么选公司就要去上升期的
- 强大的jQuery选择器之选定连续多行
- 读者教育浏览器兼容解决方法
- 铁威马NAS使用docker安装全网音乐教程
- Laravel核心概念:服务容器(ServiceContainer),服务提供者(Service Provider),门面(Facade),契约(Contracts)
- android开发塔防游戏机,上手快又耐玩 五款Android平台塔防类游戏推荐
- Java 递归实现树形菜单
- SpringBoot整合——阿里云对象存储(OSS)
- 指针--指针的创建和指针的大小
- RuntimeError: cannot release un-acquired lock
- html 中 table tr td br 什么意思 是什么的缩写
- electron-builder打包linux桌面程序(OIM-E多平台即时通讯软件)
- 上年度最受老妈欢迎滴戏言
- app式成语_成语大全四字成语下载-成语大全appv2.2.2 安卓版-腾牛安卓网
- 图解华为云需求管理工具——CodeArts Req