Linux设备驱动子系统第二弹- SD卡 - 图文(6)

2019-08-31 13:59

... ...

if (mrq->done) mrq->done(mrq); }

这里用到了完成量completion,LDD3上是这样说的,完成量是一个任务的轻量级机制,允许一个线程告知另一个线程工作已经完成。这里的一个线程就是内部中断处理函数,它是结束主控制器与SD卡间通信的线程,通过mrq->done(mrq); 即complete(mrq->done_data);告知另一个线程-回调(*request)实现主控制器与SD卡进行通信的线程,通信已经完毕。 void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) {

DECLARE_COMPLETION_ONSTACK(complete); mrq->done_data = &complete; mrq->done = mmc_wait_done; mmc_start_request(host, mrq); wait_for_completion(&complete); }

static void mmc_wait_done(struct mmc_request *mrq) {

complete(mrq->done_data); }

2) 探测引脚引起的中断

if (host->pdata && host->pdata->init)

host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc);

该init()回调函数就是刚才提到的系统初始化时通过saar_mci_init()实现的, static int saar_mci_init(struct device *dev, irq_handler_t saar_detect_int, void *data) {

request_irq(cd_irq, saar_detect_int, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, \ ... ... }

其中,cd_irq是通过GPIO转换得到的中断号,pxamci_detect_irq便是该中断实现的函数,之前已经提到过mmc_detect_change,它将最终调用queue_delayed_work执行工作队列里的mmc_rescan函数。

static irqreturn_t pxamci_detect_irq(int irq, void *devid) {

struct pxamci_host *host = mmc_priv(devid);

mmc_detect_change(devid, host->pdata->detect_delay); return IRQ_HANDLED; }

当有SD卡插入或拔出时,硬件主控制器芯片的探测pin脚产生外部中断,进入中断处理函数,执行工作队列里的mmc_rescan,扫描SD总线,对插入或拔出SD卡作相应的处理。下文协议层将讨论mmc_rescan()。 3. 协议层

Linux在内核源码的drivers/mmc/core文件夹下为我们的提供了一系列SD卡的接口服务函数。可以查看Makefile如下,

可见,core文件夹下有针对总线的服务bus.c,针对主控制器的服务host.c,针对SD卡的服务sd.c, sd_ops.c等等。

其中,最为核心的一个函数便是之前提到的位于core.c的mmc_rescan,概括来讲,主要完成两项任务,即

? ?

扫描SD总线,插入SD卡 扫描SD总线,拔出SD卡

3.1 插入SD卡

插入SD卡,主控制器产生中断,进入中断处理函数,处理工作队列,执行mmc_rescan。

void mmc_rescan(struct work_struct *work) {

struct mmc_host *host = container_of(work, struct mmc_host, detect.work); // 得到mmc_host的数据 /*

* First we search for SDIO... */

err = mmc_send_io_op_cond(host, 0, &ocr); if (!err) {

if (mmc_attach_sdio(host, ocr)) mmc_power_off(host); goto out; } /*

* ...then normal SD... */

err = mmc_send_app_op_cond(host, 0, &ocr); if (!err) {

if (mmc_attach_sd(host, ocr)) mmc_power_off(host); goto out; } /*

* ...and finally MMC. */

err = mmc_send_op_cond(host, 0, &ocr); if (!err) {

if (mmc_attach_mmc(host, ocr)) mmc_power_off(host); goto out; } ... ...

}

插入SD卡,mmc_rescan扫描SD总线上是否存在SD卡,具体的实现方法就是通过向SD卡上电,看是否能成功,以普通SD卡为例,为普通SD卡上电的函数mmc_send_app_op_cond(host, 0, &ocr);如果上电成功,则返回0,即执行if()里的mmc_attach_sd()进行总线与SD卡的绑定。如果上电失败,则返回非0值,跳过if(),尝试其他上电的方法。那么,上电方法究竟有何不同呢?具体看看mmc_send_app_op_cond()的实现过程,

int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) {

struct mmc_command cmd;

cmd.opcode = SD_APP_OP_COND; /* #define SD_APP_OP_COND 41 */ mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES); ... ... }

int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, struct mmc_command *cmd, int retries) {

mmc_app_cmd(host, card); /* #define MMC_APP_CMD 55 */ mrq.cmd = cmd; cmd->data = NULL;

mmc_wait_for_req(host, &mrq); ... ... }

这里的指令SD_APP_OP_COND只有SD2.0的协议支持,也就是说,只有普通SD卡支持,所以也只有普通SD卡能够成功上电。

如果上电成功,就开始进行总线与SD卡的绑定,通过mmc_attach_sd(),绑定过程可分为四步,

? ? ? ?

注册SD总线上的操作函数 - struct mmc_bus_ops mmc_sd_ops 设置主控制器的时钟和总线方式 - 通过回调函数host->ops->set_ios(); 启动SD卡 - 根据协议,完成SD卡启动的各个步骤 注册SD卡设备驱动

3.1.1 注册总线上的操作函数

int mmc_attach_sd(struct mmc_host *host, u32 ocr) {

mmc_sd_attach_bus_ops(host); ... ... }

static void mmc_sd_attach_bus_ops(struct mmc_host *host) {

const struct mmc_bus_ops *bus_ops;


Linux设备驱动子系统第二弹- SD卡 - 图文(6).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:太阳能热水器控制仪使用说明书资料

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: