Linux驱动——mmc bus浅析(五)

备注:
  1. Kernel版本:5.4
  2. 使用工具:Source Insight 4.0
  3. 参考博客:
3. [mmc subsystem] mmc core(第三章)——bus模块说明

文章目录

  • Linux驱动——mmc bus浅析(五)
    • 概述
    • API预览
      • bus相关
      • mmc card相关
    • 数据结构
      • mmc bus数据结构
      • sdio bus数据结构
    • 核心接口实现
      • mmc_register_bus实现
      • sdio_register_bus实现
      • mmc_register_driver实现
      • sdio_register_driver实现
      • mmc_alloc_card实现
      • mmc_add_card实现

概述

对应代码

drivers/mmc/core/bus.c
drivers/mmc/core/sdio_bus.c

抽象出虚拟mmc/sdio bus,实现mmc/sdio bus的操作。

API预览

bus相关

  • mmc_register_bus & mmc_unregister_bus
    用于注册和卸载mmc bus(虚拟mmc总线)到设备驱动模型中。
int mmc_register_bus(void);
void mmc_unregister_bus(void);
  • sdio_register_bus & sdio_unregister_bus
int sdio_register_bus(void);
void sdio_unregister_bus(void);

mmc card相关

  • mmc_alloc_card & mmc_release_card

用于分配或者释放一个struct mmc_card结构体,创建其于mmc host以及mmc bus之间的关联。

struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type);
static void mmc_release_card(struct device *dev);
  • mmc_add_card & mmc_remove_card
    用于注册或者卸载struct mmc_card到mmc_bus上。
int mmc_add_card(struct mmc_card *card);
void mmc_remove_card(struct mmc_card *card);

数据结构

mmc bus数据结构

mmc_bus_type代表了mmc虚拟总线。其内容如下:

static struct bus_type mmc_bus_type = {.name        = "mmc",         // 相应会在/sys/bus下生成mmc目录// bus下的device下继承的属性,// 可以看到/sys/bus/mmc/devices/mmc0:0001/type属性就是这里来的.dev_groups    = mmc_dev_groups,.match        = mmc_bus_match,   // 用于mmc bus上device和driver的匹配.uevent        = mmc_bus_uevent,.probe        = mmc_bus_probe,   // 当match成功的时候,执行的probe操作.remove     = mmc_bus_remove,.shutdown = mmc_bus_shutdown,.pm     = &mmc_bus_pm_ops,     // 挂在mmc bus上的device的电源管理操作集合
};
  • mmc bus match方法
static int mmc_bus_match(struct device *dev, struct device_driver *drv)
{// 无条件返回1,说明挂载mmc bus上的// device(mmc_card)和driver(mmc_driver)是无条件匹配的。return 1;
}
  • mmc 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);// 直接调用mmc_driver中的probe操作,// 对于block.c来说就是mmc_blk_probereturn drv->probe(card);
}

sdio bus数据结构

sdio_bus_type代表了mmc虚拟总线。其内容如下:

static struct bus_type c = {.name       = "sdio",            // 相应会在/sys/bus下生成sdio目录.dev_groups = sdio_dev_groups,.match       = sdio_bus_match,  // 用于sdio bus上device和driver的匹配.uevent       = sdio_bus_uevent,.probe       = sdio_bus_probe,  // 当match成功的时候,执行的probe操作.remove     = sdio_bus_remove,.pm      = &sdio_bus_pm_ops,        // 挂在sdio bus上的device的电源管理操作集合
};
  • sdio bus match方法
static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,const struct sdio_device_id *id)
{if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class)return NULL;if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor)return NULL;if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device)return NULL;return id;
}static const struct sdio_device_id *sdio_match_device(struct sdio_func *func,struct sdio_driver *sdrv)
{const struct sdio_device_id *ids;// 获取sdio device 的ID tableids = sdrv->id_table;if (ids) {while (ids->class || ids->vendor || ids->device) {if (sdio_match_one(func, ids))//逐一排查class、vendor、device等IDreturn ids;ids++;}}return NULL;
}static int sdio_bus_match(struct device *dev, struct device_driver *drv)
{struct sdio_func *func = dev_to_sdio_func(dev);struct sdio_driver *sdrv = to_sdio_driver(drv);// 通过id_table来匹配if (sdio_match_device(func, sdrv))return 1;return 0;
}
  • sdio bus probe方法
static int sdio_bus_probe(struct device *dev)
{struct sdio_driver *drv = to_sdio_driver(dev->driver);struct sdio_func *func = dev_to_sdio_func(dev);const struct sdio_device_id *id;int ret;id = sdio_match_device(func, drv);//获取sdio device idif (!id)return -ENODEV;ret = dev_pm_domain_attach(dev, false);if (ret)return ret;atomic_inc(&func->card->sdio_funcs_probed);/* Unbound SDIO functions are always suspended.* During probe, the function is set active and the usage count* is incremented.  If the driver supports runtime PM,* it should call pm_runtime_put_noidle() in its probe routine and* pm_runtime_get_noresume() in its remove routine.*/if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) {ret = pm_runtime_get_sync(dev);if (ret < 0)goto disable_runtimepm;}/* Set the default block size so the driver is sure it's something* sensible. */sdio_claim_host(func);             // 获取host使用权if (mmc_card_removed(func->card))    // 移除cardret = -ENOMEDIUM;elseret = sdio_set_block_size(func, 0);sdio_release_host(func);         // 释放host使用权if (ret)goto disable_runtimepm;ret = drv->probe(func, id);          // 调用driver probe方法if (ret)goto disable_runtimepm;return 0;disable_runtimepm:atomic_dec(&func->card->sdio_funcs_probed);if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)pm_runtime_put_noidle(dev);dev_pm_domain_detach(dev, false);return ret;
}

核心接口实现

mmc_register_bus实现

int mmc_register_bus(void)
{return bus_register(&mmc_bus_type);
}void mmc_unregister_bus(void)
{bus_unregister(&mmc_bus_type);
}

我们将mmc_bus_type的这条bus称之为mmc_bus。
相关节点:/sys/bus/mmc。

sdio_register_bus实现

int sdio_register_bus(void)
{return bus_register(&sdio_bus_type);
}void sdio_unregister_bus(void)
{bus_unregister(&sdio_bus_type);
}

我们将sdio_bus_type的这条bus称之为sdio_bus。
相关节点:/sys/bus/sdio。

mmc_register_driver实现

用于注册struct mmc_driver *drv到mmc_bus上。mmc_driver就是mmc core抽象出来的card设备driver。

/*** 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);
}EXPORT_SYMBOL(mmc_register_driver);/**C*   mmc_unregister_driver - unregister a media driver*  @drv: MMC media driver*/
void mmc_unregister_driver(struct mmc_driver *drv)
{drv->drv.bus = &mmc_bus_type;driver_unregister(&drv->drv);
}

相关节点:/sys/bus/mmc/drivers.

sdio_register_driver实现

int sdio_register_bus(void)
{return bus_register(&sdio_bus_type);
}void sdio_unregister_bus(void)
{bus_unregister(&sdio_bus_type);
}

相关节点:/sys/bus/sdio/drivers.

mmc_alloc_card实现

用于分配一个struct mmc_card结构体,创建其于mmc host以及mmc bus之间的关联。

/** Allocate and initialise a new MMC card structure.*/
struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type)
{struct mmc_card *card;// 分配一个mmc_cardcard = kzalloc(sizeof(struct mmc_card), GFP_KERNEL);if (!card)return ERR_PTR(-ENOMEM);// 关联mmc_card与mmc_hostcard->host = host;device_initialize(&card->dev);// 设置card的device的parent device为mmc_host的classdev,// 注册到设备驱动模型中之后,// 会在/sys/class/mmc_host/mmc0目录下生成相应card的节点,如mmc0:0001card->dev.parent = mmc_classdev(host);// 设置card的bus为mmc_bus_type,这样,// mmc_card注册到设备驱动模型中之后就会挂在mmc_bus下。// 会在/sys/bus/mmc/devices/目录下生成相应card的节点,如mmc0:0001card->dev.bus = &mmc_bus_type;card->dev.release = mmc_release_card;// 设置device typecard->dev.type = type;return card;
}

mmc_add_card实现

用于注册struct mmc_card到mmc_bus上。

/** Register a new MMC card with the driver model.*/
int mmc_add_card(struct mmc_card *card)
{int ret;const char *type;const char *uhs_bus_speed_mode = "";static const char *const uhs_speeds[] = {[UHS_SDR12_BUS_SPEED] = "SDR12 ",[UHS_SDR25_BUS_SPEED] = "SDR25 ",[UHS_SDR50_BUS_SPEED] = "SDR50 ",[UHS_SDR104_BUS_SPEED] = "SDR104 ",[UHS_DDR50_BUS_SPEED] = "DDR50 ",};// 配置card dev name,将体现在/sys/bus/mmc/device/mmcx:xxx上dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca);// 匹配 card 类型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";elsetype = "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_card_uhs(card) &&(card->sd_bus_speed < ARRAY_SIZE(uhs_speeds)))uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed];// 打印 card 基本信息if (mmc_host_is_spi(card->host)) {pr_info("%s: new %s%s%s card on SPI\n",mmc_hostname(card->host),mmc_card_hs(card) ? "high speed " : "",mmc_card_ddr52(card) ? "DDR " : "",type);} else {pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",mmc_hostname(card->host),mmc_card_uhs(card) ? "ultra high speed " :(mmc_card_hs(card) ? "high speed " : ""),mmc_card_hs400(card) ? "HS400 " :(mmc_card_hs200(card) ? "HS200 " : ""),mmc_card_hs400es(card) ? "Enhanced strobe " : "",mmc_card_ddr52(card) ? "DDR " : "",uhs_bus_speed_mode, type, card->rca);}#ifdef CONFIG_DEBUG_FS// 创建card对应的debug节点,对应路径例如:/sys/kernel/debug/mmc0/mmc0:0001mmc_add_card_debugfs(card);
#endifcard->dev.of_node = mmc_of_find_child_device(card->host, 0);device_enable_async_suspend(&card->dev);/* 添加到设备驱动模型中 */// 会创建/sys/bus/mmc/devices/mmc0:0001节点// 和/sys/class/mmc_host/mmc0/mmc0:0001节点ret = device_add(&card->dev);if (ret)return ret;/* 设置mmc card的state标识 */// 设置card的MMC_STATE_PRESENT状态// #define MMC_STATE_PRESENT    (1<<0)      /* present in sysfs */// 表示card已经合入到sysfs中了mmc_card_set_present(card);return 0;
}

Linux驱动——mmc bus浅析(五)相关推荐

  1. Linux驱动——mmc sd card初始化流程(十一)

    Linux驱动--mmc sd card初始化流程(十一) 备注:   1. Kernel版本:5.4   2. 使用工具:Source Insight 4.0   3. 参考博客:   (1)[sd ...

  2. Linux驱动——mmc host controller(九)

    Linux驱动--mmc host controller(九) 备注:   1. Kernel版本:5.4   2. 使用工具:Source Insight 4.0 文章目录 Linux驱动--mmc ...

  3. Linux驱动——mmc数据结构(二)

    Linux驱动--mmc数据结构(二) 备注:   1. Kernel版本:5.4   2. 使用工具:Source Insight 4.0   3. 参考博客: 2. [mmc subsystem] ...

  4. Linux驱动——mmc概念与框架(一)

    Linux驱动--mmc概念与框架(一) 备注:   1. Kernel版本:5.4   2. 使用工具:Source Insight 4.0   3. 参考博客: Linux MMC framewo ...

  5. Linux驱动——mmc card热插拔检测机制(十)

    Linux驱动--mmc card热插拔检测机制(十) 备注:   1. Kernel版本:5.4   2. 使用工具:Source Insight 4.0   3. 参考博客: [sd card] ...

  6. Linux驱动——mmc sd card 块设备读写流程(十三)

    Linux驱动--mmc sd card 块设备读写流程(十三) 备注:   1. Kernel版本:5.4   2. 使用工具:Source Insight 4.0   3. 参考博客:   (1) ...

  7. Linux驱动开发(十五)---如何使用内核现有驱动(显示屏)

    前文回顾 <Linux驱动开发(一)-环境搭建与hello world> <Linux驱动开发(二)-驱动与设备的分离设计> <Linux驱动开发(三)-设备树> ...

  8. Linux 驱动开发 三十五:Linux 内核时钟管理

    参考: linux时间管理,时钟中断,系统节拍_u010936265的博客-CSDN博客_系统节拍时钟中断 Linux内核时钟系统和定时器实现_anonymalias的专栏-CSDN博客_linux内 ...

  9. 嵌入式Linux驱动笔记(二十五)------Input子系统框架

    你好!这里是风筝的博客, 欢迎和我一起交流. 一.Input子系统概述 二.Input子系统架构 三.Input子系统工作机制 3.1 核心层(input.c) 3.1.1 input_init函数 ...

  10. Linux驱动编程 step-by-step (五)主要的文件操作方法实现

    主要的文件操作方法实现 文件操作函数有很多的操作接口,驱动编程需要实现这些接口,在用户编程时候系统调用时候会调用到这些操作 [cpp] view plaincopy struct file_opera ...

最新文章

  1. 实战讲解Python函数参数
  2. find your place
  3. C++输入输出流进制转换
  4. 探讨.NET Core的未来
  5. [SDOI 2010]外星千足虫
  6. java preference,Java使用Preference类保存上一次记录的方法
  7. C#反射设置属性值和获取属性值
  8. idea的setting界面怎么进_Mac版YY语音进入频道失败怎么破?
  9. Object常用方法
  10. JavaMail入门第四篇 接收邮件
  11. R读取MySQL数据出现乱码,解决该问题的方法总结
  12. Java中的关键字--volatile
  13. Ubuntu之重新安装软件
  14. FL Studio新手教程:FL Studio五大常用按钮介绍
  15. 数据可视化|用散点图进行数据分析
  16. 原生js动态添加元素
  17. 端侧智能存算一体芯片的需求、现状与挑战
  18. Copy On Write机制了解一下
  19. 1.urllib爬取数据
  20. 数字ic设计——SPI

热门文章

  1. IEEE协会首次在京举办研讨会,王飞跃称不存在AI芯片
  2. python 四象限图_Tableau技巧|制作四象限图
  3. 原生滑动选择器 html,html选择器
  4. matlab--找两条曲线交点并标注于图上的方法
  5. VS2008 开发 Sharepoint Workflow 遇到的一些细节
  6. 宏碁 AN515-51支持nvme固态接口
  7. 关于用Unity实现校区AR导航毕业设计的建议
  8. 计算机用户删除会怎样,电脑注销会删掉内容吗,电脑注销后会删除账户吗
  9. 【转】Power System 中基于 VIOS 的虚拟以太网实现
  10. 讯飞离线语音合成(语记)