SDIO驱动(1)Host端驱动框架提到:
static int __devinit s3cmci_probe(struct platform_device *pdev) { struct mmc_host *mmc; // 创建mmc_host(对象),在mmc_alloc_host()中进行一些通用设置的初始化 mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev); mmc->ops = &s3cmci_ops; // operations // 其他成员初始化 // Host注册 ret = mmc_add_host(mmc); return 0; } 1、Host的创建 mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);这里创建一个host并对其某些成员进行初始化,如:
host->rescan_disable = 1; –>禁止扫描探测card
host->index = 2; –>该host的编号
host->parent = dev; –>该host的父设备,这里是注册该host的那个platform设备
host->class_dev.parent = dev; host->class_dev.class = &mmc_host_class; –>该host在设备模型class中的体现,即该设备从属于某一个class-mmc_host_class
host->clk_requests、host->clk_delay、host->clkgate_delay、host->clk_gated、host->clk_gate_work、host->clk_lock、host->clk_gate_mutex –>设置host的clk相关的参数并初始化访问这些参数需要的lock
host->slot.cd_irq = -EINVAL; –>初始化card detect中断
host->lock –>初始化自旋锁lock(lock for claim and bus ops)
host->wq –>初始化等待队列
host->detect–>关键参数!在需要的时候扫描卡(mmc_rescan),后文详述。
max_seg_size、max_segs、max_req_size、max_blk_size、max_blk_count、max_busy_timeout–>和块设备(如MMC、SD、eMMC等)有关的参数,在古老的磁盘时代,这些参数比较重要。对基于MMC技术的块设备来说,硬件的性能大大提升,这些参数就没有太大的意义了。
提供访问Host的方式,由MMC core调用:
static struct mmc_host_ops s3cmci_ops = { .request = s3cmci_request, .set_ios = s3cmci_set_ios, .get_ro = s3cmci_get_ro, .get_cd = s3cmci_card_present, .enable_sdio_irq = s3cmci_enable_sdio_irq,}; 3、卡的扫描流程系统在完成Host的添加后,要进行卡的扫描:
mmc_add_host(host)-->mmc_start_host(host)---->_mmc_detect_change(host, 0, false)------>mmc_schedule_delayed_work(&host->detect, delay);在第1小节层提到过host->detect参数,它的初始化代码:
INIT_DELAYED_WORK(&host->detect, mmc_rescan);所以,在指定delay时间后调用mmc_rescan()进行卡的扫描。
core.c (driversmmccore)static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };void mmc_rescan(struct work_struct *work){ ... mmc_claim_host(host); -------------------> a for (i = 0; i < ARRAY_SIZE(freqs); i++) { ----------> b if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) { extend_wakelock = true; break; } if (freqs[i] <= host->f_min) break; } mmc_release_host(host); -------------------> c ...}a,以独占的方式访问该host。
题外话:记得在USB通信中,使用之前也需要执行相似的操作,如:
c,相应的,用完需要release。
b,这里是进行实际scan的地方。
虽然SDIO的数据传输速率可达100Mb/s以上,但在对卡进行激活的时候,必须在Low-Speed模式(400KHz)下进行。
这里就通过400KHz、300KHz、200KHz、100KHz依次进行卡的扫描:
core.c (driversmmccore)static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq){ host->f_init = freq; /* * sdio_reset sends CMD52 to reset card. Since we do not know * if the card is being re-initialized, just send it. CMD52 * should be ignored by SD/eMMC cards. */ sdio_reset(host); mmc_go_idle(host); mmc_send_if_cond(host, host->ocr_avail); /* Order's important: probe SDIO, then SD, then MMC */ if (!mmc_attach_sdio(host)) return 0; if (!mmc_attach_sd(host)) return 0; if (!mmc_attach_mmc(host)) return 0; return -EIO;}以上是在注册Host时由Host发起的扫描过程。
卡本身在插拔时,也应该有能力启动扫描动作。这个扫描动过通过终端实现:
同样调用mmc_rescan()扫描card。