Linux SDIO总线驱动(二)

驱动:

以SDIO为例其会采用mmc_attach_sdio来实现驱动和设备的匹配,其本质还是根据sdio_bus的匹配规则来实现匹配。在mmc_attach_sdio中首先是mmc匹配一个bus,即采用何种bus来进行mmc bus来处理host。在这里需要理解一点就是在SDIO中,对于SD卡存储器mmc为实体设备,而对于非SD卡存储器,如SDIO接口的设备,则mmc则表征为bus,这个比较重要。除了mmc bus外还存在SDIO_BUS。

/*

* Starting point for SDIO card init.

*/

int mmc_attach_sdio(struct mmc_host *host)

{

int err, i, funcs;

u32 ocr;

struct mmc_card *card;

BUG_ON(!host);

WARN_ON(!host->claimed);

err = mmc_send_io_op_cond(host, 0, &ocr);

if (err)

return err;

mmc_attach_bus(host, &mmc_sdio_ops);

if (host->ocr_avail_sdio)

host->ocr_avail = host->ocr_avail_sdio;

/*

* 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;

}

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_sdio_init_card(host, host->ocr, NULL, 0);

if (err) {

if (err == -EAGAIN) {

/*

* Retry initialization with S18R set to 0.

*/

host->ocr &= ~R4_18V_PRESENT;

err = mmc_sdio_init_card(host, host->ocr, NULL, 0);

}

if (err)

goto err;

}

card = host->card;

/*

* Enable runtime PM only if supported by host+card+board

*/

if (host->caps & MMC_CAP_POWER_OFF_CARD) {

/*

* Let runtime PM core know our card is active

*/

err = pm_runtime_set_active(&card->dev);

if (err)

goto remove;

/*

* Enable runtime PM for this card

*/

pm_runtime_enable(&card->dev);

}

/*

* The number of functions on the card is encoded inside

* the ocr.

*/

funcs = (ocr & 0x70000000) >> 28;

card->sdio_funcs = 0;

#ifdef CONFIG_MMC_EMBEDDED_SDIO

if (host->embedded_sdio_data.funcs)

card->sdio_funcs = funcs = host->embedded_sdio_data.num_funcs;

#endif

/*

* Initialize (but don‘t add) all present functions.

*/

for (i = 0; i < funcs; i++, card->sdio_funcs++) {

#ifdef CONFIG_MMC_EMBEDDED_SDIO

if (host->embedded_sdio_data.funcs) {

struct sdio_func *tmp;

tmp = sdio_alloc_func(host->card);

if (IS_ERR(tmp))

goto remove;

tmp->num = (i + 1);

card->sdio_func[i] = tmp;

tmp->class = host->embedded_sdio_data.funcs[i].f_class;

tmp->max_blksize = host->embedded_sdio_data.funcs[i].f_maxblksize;

tmp->vendor = card->cis.vendor;

tmp->device = card->cis.device;

} else {

#endif

err = sdio_init_func(host->card, i + 1);

if (err)

goto remove;

#ifdef CONFIG_MMC_EMBEDDED_SDIO

}

#endif

/*

* Enable Runtime PM for this func (if supported)

*/

if (host->caps & MMC_CAP_POWER_OFF_CARD)

pm_runtime_enable(&card->sdio_func[i]->dev);

}

/*

* First add the card to the driver model...

*/

mmc_release_host(host);

err = mmc_add_card(host->card);

if (err)

goto remove_added;

/*

* ...then the SDIO functions.

*/

for (i = 0;i < funcs;i++) {

err = sdio_add_func(host->card->sdio_func[i]);

if (err)

goto remove_added;

}

mmc_claim_host(host);

return 0;

remove_added:

/* Remove without lock if the device has been added. */

mmc_sdio_remove(host);

mmc_claim_host(host);

remove:

/* And with lock if it hasn‘t been added. */

mmc_release_host(host);

if (host->card)

mmc_sdio_remove(host);

mmc_claim_host(host);

err:

mmc_detach_bus(host);

pr_err("%s: error %d whilst initialising SDIO card\n",

mmc_hostname(host), err);

return err;

}

比较难以理解的是func,这个东东其实是一个实体设备的封装,可以认为其是一个设备。

/*

* Allocate and initialise a new SDIO function structure.

*/

struct sdio_func *sdio_alloc_func(struct mmc_card *card)

{

struct sdio_func *func;

func = kzalloc(sizeof(struct sdio_func), GFP_KERNEL);

if (!func)

return ERR_PTR(-ENOMEM);

func->card = card;

device_initialize(&func->dev);

func->dev.parent = &card->dev;//card设备为sdio设备的父设备。

func->dev.bus = &sdio_bus_type;

func->dev.release = sdio_release_func;

return func;

}

上面的code一目了然,其就是具体设备实体的封装,其bus类型为sdio_bus. sdio_init_func仅仅是初始化一个设备,而并没有register。在sdio_add_func实现设备的register,同理就是card实体,在mmc_add_card之前并没有注册,在mmc_add_card函数中才实现设备的注册。

到此设备注册也就完成了,其实sdio总线在形式上类似于usb bus,为什么呢?编写过usb驱动的童鞋们应该知道,编写usb驱动仅仅是编写驱动的加载,并没有具体加载设备实体,导致很多童鞋的困惑,为什么没有设备的加载,其实在usb设备插入时,会动态的创建一个usb设备实体,在usb设备实体创建完成后,根据不同设备id调用相匹配的驱动。而SDIO设备设备也是一样的。上面的code比较混乱,总是让人看不出具体的设备的加载。其实在上面的code中,其中包括了mmc host的驱动。

时间: 2024-11-06 03:43:05

Linux SDIO总线驱动(二)的相关文章

Linux SDIO总线驱动(一)

SDIO卡 SDIO卡是在SD内存卡接口的基础上发展起来的接口,SDIO接口兼容以前的SD内存卡,并且可以连接SDIO接口的设备,目前根据SDIO协议的SPEC,SDIO接口支持的设备总类有蓝牙,网卡,电视卡等. SDIO协议是由SD卡的协议演化升级而来的,很多地方保留了SD卡的读写协议,同时SDIO协议又在SD卡协议之上添加了CMD52和CMD53命令.由于这个,SDIO和SD卡规范间的一个重要区别是增加了低速标准,低速卡的目标应用是以最小的硬件开始来支持低速I/O能力.低速卡支持类似调制解调

基于MCP2515的Linux CAN总线驱动程序设计

MCP2515简介 MCP2515是一种独立的CAN总线通信控制器,是Microchip公司首批独立CAN解决方案的升级器件,其传输能力较Microchip公司原有CAN控制器(MCP2510)高两倍,最高通信速率可达到1Mbps.MCP2515能够接收和发送标准数据帧和扩展数据帧以及远程帧,通过两个接收屏蔽寄存器和六个接收过滤寄存器滤除无关报文,从而减轻CPU负担. MCP2515主要功能参数及电气特性如下: (1)支持CAN技术规范2.0A/B, 最高传输速率达到1Mbps: (2)支持标准

linux sdio wifi驱动知识总结(一)

这两周在tq imx6ul下调一个迈威88w8801sdio wifi模组,最后尴尬的发现tq imx6ul并不支持sdio wifi.至于不支持的原因会在后面简单说一下,小弟才疏学浅如果有大佬在tqimx6ul上成功移植过sdio wifi,也请多多指教,好了现在进入正题吧. 首先我们要搞清楚SDIO WIFI是什么,SDIO WIFI首先是一个网络设备,然后才是一个块设备.一个网络设备驱动程序,必须要具有的是收包发包函数.网络设备注册函数.接下来参照宋宝华<Linux设备驱动开发详解-基于最

linux PMBus总线驱动设计分析

PMBus协议规范介绍 PMBus是一套对电源进行配置.控制和监控的通讯协议标准.其最新版本为1.3,该规范还在不断演进中,比如新标准中新增的zone PMBus.AVSBus等特性.在其官网上有详细的规范文档,本节不尝试翻译规范文档,重点记录作者在了解PMBus过程中的疑问和解答. PMBus与I2C.SMBus的区别? PMBus在SMBus(System Management Bus)基础上增加了一套电源配置.控制和监控规范.SMBus最初是为电池智能管理而开发的一套标准,其基于I2C协议

Linux平台总线驱动设备模型

platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver.Linux 2.6的设备驱动模型中,把I2C.RTC.LCD等都归纳为platform_device. 总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动:相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成. Linux2.6系统中定义了一个bus_type的实例platform_bus_type [cpp] view plai

Linux按键设备驱动二

① 按键所用开关为物理机械弹性开关,当机械触点断开.闭合时,由于机械弹性作用,开关不会马上稳定的接通或者断开.因而在闭合及断开的瞬间总是伴随有一连串的抖动 ② 按键去抖的方法主要有两种 (1)硬件电路去抖 (2)软件延时去抖 * for循环等待 * 定时器延时 ③ Linux内核使用struct timer_list来描述一个定时器 struct timer_list { struct list_head entry; unsigned long expires; void (*function

Linux 下wifi 驱动开发(三)—— SDIO接口WiFi驱动浅析

SDIO-Wifi模块是基于SDIO接口的符合wifi无线网络标准的嵌入式模块,内置无线网络协议IEEE802.11协议栈以及TCP/IP协议栈.可以实现用户主平台数据通过SDIO口到无线网络之间的转换.SDIO具有数据传输快,兼容SD.MMC接口等特点. 对于SDIO接口的wifi,首先,它是一个sdio的卡的设备.然后具备了wifi的功能.所以.注冊的时候还是先以sdio的卡的设备去注冊的. 然后检測到卡之后就要驱动他的wifi功能了.显然,他是用sdio的协议,通过发命令和数据来控制的.以

Exynos4412 IIC总线驱动开发(二)—— IIC 驱动开发

前面在Exynos4412 IIC总线驱动开发(一)-- IIC 基础概念及驱动架构分析 中学习了IIC驱动的架构,下面进入我们的驱动开发过程 首先看一张代码层次图,有助于我们的理解 上面这些代码的展示是告诉我们:linux内核和芯片提供商为我们的的驱动程序提供了 i2c驱动的框架,以及框架底层与硬件相关的代码的实现.  剩下的就是针对挂载在i2c两线上的i2c设备了device,而编写的即具体设备驱动了,这里的设备就是硬件接口外挂载的设备,而非硬件接口本身(soc硬件接口本身的驱动可以理解为总

Linux usb子系统(二):USB设备驱动usb-skeleton.c

usb驱动分为通过usbfs操作设备的用户空间驱动,内核空间的内核驱动.两者不能同时进行,否则容易引发对共享资源访问的问题,死锁!使用了内核驱动,就不能在usbfs里驱动该设备. 下面转载的一篇分析usb-skeleton.c文章. 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结当然不可缺,更何况我决定为嵌入式卖命了.好,言归正传,我说一说这段时间的收获,跟大家分享一下Linux的驱动开发.但这次只先针对Linux的USB子系统作分析,因为周五研讨老板催