在分析了sdio,emmc驱动后,把剩余的sdio部分也学习下。
代码很多不仔细看了,看关键的
int mmc_attach_sdio(struct mmc_host *host)
{
err = mmc_send_io_op_cond(host, 0, &ocr);
mmc_attach_bus(host, &mmc_sdio_ops);
rocr = mmc_select_voltage(host, ocr);
err = mmc_sdio_init_card(host, rocr, NULL, 0);
funcs = (ocr & 0x70000000) >> 28;
card->sdio_funcs = 0;
for (i = 0; i < funcs; i++, card->sdio_funcs++) {
err = sdio_init_func(host->card, i + 1);
}
mmc_release_host(host);
for (i = 0;i < funcs;i++) {
err = sdio_add_func(host->card->sdio_func[i]);
}
mmc_claim_host(host);
}
最终在/sys/bus/sdio/devices/下生成对于的设备
看下mmc_send_io_op_cond函数
#define SD_IO_SEND_OP_COND 5 /* bcr [23:0] OCR R4 */
int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
{
struct mmc_command cmd = {};
int i, err = 0;
cmd.opcode = SD_IO_SEND_OP_COND;
cmd.arg = ocr;
cmd.flags = MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR;
for (i = 100; i; i--) {
err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
if (cmd.resp[0] & MMC_CARD_BUSY)
break;
}
*rocr = cmd.resp[mmc_host_is_spi(host) ? 1 : 0];
}
发送CMD5命令,接收R4返回的状态。
SDIO协议文档位置https://www.sdcard.org/downloads/pls/index.html,下载这一篇SDIO Simplified Specification
看下sdio总线设备和驱动的匹配
static struct bus_type sdio_bus_type = {
.match = sdio_bus_match,
};
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);
if (sdio_match_device(func, sdrv))
return 1;
return 0;
}
static const struct sdio_device_id *sdio_match_device(struct sdio_func *func,
struct sdio_driver *sdrv)
{
const struct sdio_device_id *ids;
ids = sdrv->id_table;
if (ids) {
while (ids->class || ids->vendor || ids->device) {
if (sdio_match_one(func, ids))
return ids;
ids++;
}
}
return NULL;
}
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;
}
也就是根据sdio的id跟驱动的id进行匹配,匹配后跑probe函数。
所以我们看sdio驱动时,有类似的注册方法
static const struct sdio_device_id b43_sdio_ids[] = {
{ SDIO_DEVICE(0x02d0, 0x044b) }, /* Nintendo Wii WLAN daughter card */
{ SDIO_DEVICE(0x0092, 0x0004) }, /* C-guys, Inc. EW-CG1102GC */
{ },
};
static struct sdio_driver b43_sdio_driver = {
.name = "b43-sdio",
.id_table = b43_sdio_ids,
.probe = b43_sdio_probe,
.remove = b43_sdio_remove,
};
int b43_sdio_init(void)
{
return sdio_register_driver(&b43_sdio_driver);
}
void b43_sdio_exit(void)
{
sdio_unregister_driver(&b43_sdio_driver);
}