您的位置:首页 > 运维架构 > Linux

Linux SDIO总线驱动(二)

2016-05-06 14:28 513 查看
驱动:

以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的驱动。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: