一、工作流程
mmc驱动主要文件包括
drivers/mmc/card/block.c
drivers/mmc/card/queue.c
drivers/mmc/core/core.c
drivers/mmc/core/host.c
drivers/mmc/core/
内核启动时,首先执行core/core.c的mmc_init,注册mmc、sd总线,以及一个host class设备。接着执行card/block.c中,申请一个块设备。
二、:
这里涉及三种总线
-
1. platform bus
-
driver/base/platform.c
-
struct bus_type platform_bus_type = {
-
.name = "platform",
-
.dev_attrs = platform_dev_attrs,
-
.match = platform_match,
-
.uevent = platform_uevent,
-
.pm = &platform_dev_pm_ops,
-
};
-
-
2. mmc bus type
-
drivers\mmc\core\bus.c
-
static struct bus_type mmc_bus_type = {
-
.name = "mmc",
-
.dev_attrs = mmc_dev_attrs,
-
.match = mmc_bus_match,
-
.uevent = mmc_bus_uevent,
-
.probe = mmc_bus_probe,
-
.remove = mmc_bus_remove,
-
.shutdown = mmc_bus_shutdown,
-
.pm = &mmc_bus_pm_ops,
-
};
-
-
3. sdio bus type
-
drivers\mmc\core\sdio_bus.c
-
static struct bus_type sdio_bus_type = {
-
.name = "sdio",
-
.dev_attrs = sdio_dev_attrs,
-
.match = sdio_bus_match,
-
.uevent = sdio_bus_uevent,
-
.probe = sdio_bus_probe,
-
.remove = sdio_bus_remove,
-
.pm = SDIO_PM_OPS_PTR,
-
};
其中mmc总线操作相关函数,由于mmc卡支持多种总数据线,如SPI、SDIO、8LineMMC而不同的总线的操作控制方式不尽相同,所以通过此结构与相应的总线回调函数相关联。
-
-
struct mmc_bus_ops {
-
void (*remove)(struct mmc_host *);
-
void (*detect)(struct mmc_host *);
-
int (*sysfs_add)(struct mmc_host *, struct mmc_card *card);
-
void (*sysfs_remove)(struct mmc_host *, struct mmc_card *card);
-
void (*suspend)(struct mmc_host *);
-
void (*resume)(struct mmc_host *);
-
};
-
-
static const struct mmc_bus_ops mmc_ops = {
-
.remove = mmc_remove,
-
.detect = mmc_detect,
-
.sysfs_add = mmc_sysfs_add,
-
.sysfs_remove = mmc_sysfs_remove,
-
.suspend = mmc_suspend,
-
.resume = mmc_resume,
-
};
-
-
static const struct mmc_bus_ops mmc_sd_ops = {
-
.remove = mmc_sd_remove,
-
.detect = mmc_sd_detect,
-
.sysfs_add = mmc_sd_sysfs_add,
-
.sysfs_remove = mmc_sd_sysfs_remove,
-
.suspend = mmc_sd_suspend,
-
.resume = mmc_sd_resume,
-
};
-
-
static const struct mmc_bus_ops mmc_sdio_ops = {
-
.remove = mmc_sdio_remove,
-
.detect = mmc_sdio_detect,
-
};
关于总线操作的函数:
.detect,驱动程序经常需要调用此函数去检测mmc卡的状态,具体实现是发送CMD13命令,并读回响应,如果响应错误,则依次调用.remove、detach_bus来移除卡及释放总线。
三、总体
1、kernel启动时,先后执行mmc_init()及mmc_blk_init(),以对mmc设备及mmc块模块进行初始化
-
mmc/core/core.c
-
static int __init mmc_init(void)
-
workqueue = alloc_ordered_workqueue("kmmcd", 0);
-
ret = mmc_register_bus();
-
ret = mmc_register_host_class();
-
ret = sdio_register_bus();
-
-
*******
-
mmc/card/block.c
-
static int __init mmc_blk_init(void)
-
res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
-
res = mmc_register_driver(&mmc_driver);
-
-
static struct mmc_driver mmc_driver =
-
.probe = mmc_blk_probe,
-
-
static int mmc_blk_probe(struct mmc_card *card)
-
mmc_set_bus_resume_policy(card->host, 1);
2、core部分会做两件事
a -- 取得总线
b -- 检查总线操作结构指针bus_ops,如果为空,则重新利用各总线对端口进行扫描,检测顺序依次为:SDIO、Normal SD、MMC。当检测到相应的卡类型后,就使用mmc_attach_bus()把相对应的总线操作与host连接起来
-
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
-
{
-
...
-
host->bus_ops = ops;
-
...
-
}
3、然后在挂载mmc设备驱动时,执行驱动程序中的xx_mmc_probe(),检测host设备中挂载的sd设备
-
kernel\arch\arm\configs\msm9625_defconfig
-
CONFIG_MMC_MSM=y
-
-
kernel\drivers\mmc\host\Makefile
-
obj-$(CONFIG_MMC_MSM) += msm_sdcc.o
-
-
msm_sdcc.c (drivers\mmc\host)
-
-
static int __init msmsdcc_init(void)
-
platform_driver_register(&msmsdcc_driver);
-
-
static struct platform_driver msmsdcc_driver = {
-
.probe = msmsdcc_probe,
-
.remove = msmsdcc_remove,
-
.driver = {
-
.name = "msm_sdcc",
-
.pm = &msmsdcc_dev_pm_ops,
-
.of_match_table = msmsdcc_dt_match,
-
},
-
};
-
-
-
-
-
static int msmsdcc_probe(struct platform_device *pdev)
-
{
-
-
if (pdev->dev.of_node) {
-
plat = msmsdcc_populate_pdata(&pdev->dev);
-
of_property_read_u32((&pdev->dev)->of_node,"cell-index", &pdev->id);
-
} else {
-
plat = pdev->dev.platform_data;
-
}
-
-
mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev); ---- 1
-
-
mmc->ops = &msmsdcc_ops;
-
-
ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,DRIVER_NAME " (cmd)", host);
-
-
mmc_add_host(mmc); ---- 2
-
-
ret = device_create_file(&pdev->dev, &host->auto_cmd21_attr);
-
}
4、此时probe函数会创建一个host设备,然后开启一个延时任务mmc_rescan()。
-
1:
-
core/host.c
-
-
struct mmc_host *mmc_alloc_host(int extra, struct device *dev)----创建一个 mmc_host 和 mmc_spi_host ,且mmc_host的最后一个成员指针private指向mmc_spi_host
-
-
struct mmc_host *host;
-
host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
-
-
host->parent = dev;
-
host->class_dev.parent = dev;
-
host->class_dev.class = &mmc_host_class;
-
device_initialize(&host->class_dev);
-
-
init_waitqueue_head(&host->wq);
-
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
-
-
host->max_segs = 1;
-
host->max_seg_size = PAGE_CACHE_SIZE;
-
return host;
5、驱动挂载成功后,mmc_rescan()函数被执行,然后对卡进行初始化(步骤后面详细讲述)
-
core/core.c
-
-
void mmc_rescan(struct work_struct *work)
-
if (host->bus_ops && host->bus_ops->detect && !host->bus_dead && !(host->caps & MMC_CAP_NONREMOVABLE))
-
host->bus_ops->detect(host);
-
mmc_bus_put(host);
-
mmc_bus_get(host);
-
if (host->bus_ops != NULL) {
-
mmc_bus_put(host);
-
goto out;
-
}
-
if (host->ops->get_cd && host->ops->get_cd(host) == 0)
-
goto out;
-
mmc_claim_host(host);
-
-
if (!mmc_rescan_try_freq(host, host->f_min))
初始化卡接以下流程初始化:
a、发送CMD0使卡进入IDLE状态
b、发送CMD8,检查卡是否SD2.0。SD1.1是不支持CMD8的,因此在SD2.0 Spec中提出了先发送CMD8,如响应为无效命令,则卡为SD1.1,否则就是SD2.0(请参考SD2.0 Spec)。
c、发送CMD5读取OCR寄存器。
d、发送ACMD55、CMD41,使卡进入工作状态。MMC卡并不支持ACMD55、CMD41,如果这步通过了,则证明这张卡是SD卡。
e、如果d步骤错误,则发送CMD1判断卡是否为MMC。SD卡不支持CMD1,而MMC卡支持,这就是SD和MMC类型的判断依据。
f、如果ACMD41和CMD1都不能通过,那这张卡恐怕就是无效卡了,初始化失败。
假如扫描到总线上挂有有效的设备,就调用相对应的函数把设备装到系统中,mmc_attach_sdio()、mmc_attach_sd()、mmc_attach_mmc()这三个函数分别是装载sdio设备,sd卡和mmc卡的。
在 sd卡中,驱动循环发送ACMD41、CMD55给卡,读取OCR寄存器,成功后,依次发送CMD2(读CID)、CMD3(得到RCA)、CMD9(读 CSD)、CMD7(选择卡)。后面还有几个命令分别是ACMD41&CMD51,使用CMD6切换一些功能,如切换到高速模式。
经过上述步骤,已经确定当前插入的卡是一张有效、可识别的存储卡。然后调用mmc_add_card()把存储卡加到系统中。正式与系统驱动连接在一起。
-
static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
-
host->f_init = freq;
-
mmc_power_up(host);
-
mmc_go_idle(host); ----1a
-
mmc_send_if_cond(host, host->ocr_avail);
-
if (!mmc_attach_sd(host)) ----1b
-
-
1a:
-
int mmc_go_idle(struct mmc_host *host)
-
struct mmc_command cmd = {0};
-
cmd.opcode = MMC_GO_IDLE_STATE;
-
cmd.arg = 0;
-
err = mmc_wait_for_cmd(host, &cmd, 0)
-
-
int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
-
memset(cmd->resp, 0, sizeof(cmd->resp));
-
cmd->retries = retries;
-
mrq.cmd = cmd;
-
mmc_wait_for_req(host, &mrq);
-
-
void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) ----重要函数
-
__mmc_start_req(host, mrq);
-
-
static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
-
mmc_start_request(host, mrq);
-
-
static void mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
-
host->ops->request(host, mrq);
-
-
-
1b:
-
core/mmc.c
-
int mmc_attach_sd(struct mmc_host *host)
-
err = mmc_send_app_op_cond(host, 0, &ocr); ----1b1
-
host->ocr = mmc_select_voltage(host, ocr);
-
err = mmc_init_card(host, host->ocr, NULL);
-
err = mmc_sd_init_card(host, host->ocr, NULL); ----1b2
-
err = mmc_add_card(host->card); ----1b3
-
-
-
1b1:
-
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
-
cmd.opcode = SD_APP_OP_COND;
-
-
-
-
1b2:
-
static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,struct mmc_card *oldcard)
-
err = mmc_sd_get_cid(host, ocr, cid, &rocr);
-
card = mmc_alloc_card(host, &sd_type);
-
err = mmc_send_relative_addr(host, &card->rca);
-
err = mmc_sd_get_csd(host, card); ----mmc_send_csd(card, card->raw_csd);
-
err = mmc_select_card(card);
-
err = mmc_sd_setup_card(host, card, oldcard != NULL);
-
-
int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,bool reinit)
-
mmc_app_send_scr(card, card->raw_scr);
-
if (host->ops->get_ro(host) > 0 )
-
mmc_card_set_readonly(card);
-
-
1b3:
-
core/bus.c
-
int mmc_add_card(struct mmc_card *card)
-
ret = device_add(&card->dev);
-
-
drivers/base/core.c
-
int device_add(struct device *dev)
-
dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
-
bus_probe_device(dev);
-
-
void bus_probe_device(struct device *dev)
-
if (bus->p->drivers_autoprobe)
-
ret = device_attach(dev);
-
-
-
***********
-
2:
-
-
int mmc_add_host(struct mmc_host *host)
-
err = device_add(&host->class_dev);
-
mmc_start_host(host);
-
-
-
void mmc_start_host(struct mmc_host *host)
-
mmc_power_off(host); ----2a
-
mmc_detect_change(host, 0); ----2b
-
-
2a:
-
void mmc_power_off(struct mmc_host *host)
-
host->ios.power_mode = MMC_POWER_OFF;
-
...
-
mmc_set_ios(host);
-
-
void mmc_set_ios(struct mmc_host *host)
-
host->ops->set_ios(host, ios);
-
-
2b:
-
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
-
mmc_schedule_delayed_work(&host->detect, delay);
6、卡设备加到系统中后,通知mmc块设备驱动。块设备驱动此时调用probe函数,即mmc_blk_probe()函数,mmc_blk_probe()首 先分配一个新的mmc_blk_data结构变量,然后调用mmc_init_queue,初始化blk队列。然后建立一个线程 mmc_queue_thread()。
7、然后就可以进行传输命令和数据了
-
struct mmc_host_ops {
-
-
void (*request)(struct mmc_host *host, struct mmc_request *req);
-
-
}
-
-
static const struct mmc_host_ops msmsdcc_ops = {
-
.enable = msmsdcc_enable,
-
.disable = msmsdcc_disable,
-
.pre_req = msmsdcc_pre_req,
-
.post_req = msmsdcc_post_req,
-
.request = msmsdcc_request,
-
.set_ios = msmsdcc_set_ios,
-
.get_ro = msmsdcc_get_ro,
-
.enable_sdio_irq = msmsdcc_enable_sdio_irq,
-
.start_signal_voltage_switch = msmsdcc_switch_io_voltage,
-
.execute_tuning = msmsdcc_execute_tuning,
-
.hw_reset = msmsdcc_hw_reset,
-
.stop_request = msmsdcc_stop_request,
-
.get_xfer_remain = msmsdcc_get_xfer_remain,
-
.notify_load = msmsdcc_notify_load,
-
};
-
-
-
-
static void msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
-
mmc_request_done(mmc, mrq);
-
msmsdcc_request_start(host, mrq);
-
-
static void msmsdcc_request_start (struct msmsdcc_host *host, struct mmc_request *mrq)
-
if ((mrq->data->flags & MMC_DATA_READ) ||host->curr.use_wr_data_pend)
-
msmsdcc_start_data(host, mrq->data,mrq->sbc ? mrq->sbc : mrq->cmd,0);
-
else
-
msmsdcc_start_command(host,mrq->sbc ? mrq->sbc : mrq->cmd,0);
-
-
-
static void msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,struct mmc_command *cmd, u32 c)
-
-
...
-
if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE))
-
msmsdcc_start_command_deferred(host, cmd, &c);
-
else
-
msmsdcc_start_command(host, cmd, c)
-
-
static void msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
-
{
-
msmsdcc_start_command_deferred(host, cmd, &c);
-
msmsdcc_start_command_exec(host, cmd->arg, c);
-
}
-
-
static void msmsdcc_start_command_deferred(struct msmsdcc_host *host,struct mmc_command *cmd, u32 *c)
-
cmd->opcode ----对应SD卡命令 ,如 CMD0:复位SD 卡
阅读(3026) | 评论(0) | 转发(0) |