这一节我们看下探测函数tasklet中的两个函数,首先看下发现卡函数dw_mci_tasklet_card: static void dw_mci_tasklet_card(unsigned long data) { struct dw_mci *host = (struct dw_mci *)data; int i; //每个slot都执行一次,本例只有一个 for (i = 0; i num_slots; i++) { struct dw_mci_slot *slot = host->slot[i]; struct mmc_host *mmc = slot->mmc; struct mmc_request *mrq; int present; u32 ctrl; present = dw_mci_get_cd(mmc); //获取卡状态,后面讲 while (present != slot->last_detect_state) { spin_lock(&host->lock); dev_dbg(&slot->mmc->class_dev, "card %s\n", present ? "inserted" : "removed"); /* Card change detected */ slot->last_detect_state = present; /* Power up slot */ if (present != 0) { if (host->pdata->setpower) host->pdata->setpower(slot->id, mmc->ocr_avail); set_bit(DW_MMC_CARD_PRESENT, &slot->flags); //设置卡存在标志 } /* Clean up queue if present */ mrq = slot->mrq; if (mrq) { if (mrq == host->mrq) { host->data = NULL; host->cmd = NULL; switch (host->state) { case STATE_IDLE: break; case STATE_SENDING_CMD: mrq->cmd->error = -ENOMEDIUM; if (!mrq->data) break; /* fall through */ case STATE_SENDING_DATA: mrq->data->error = -ENOMEDIUM; dw_mci_stop_dma(host); //停止DMA,后面讲 break; case STATE_DATA_BUSY: case STATE_DATA_ERROR: if (mrq->data->error == -EINPROGRESS) mrq->data->error = -ENOMEDIUM; if (!mrq->stop) break; /* fall through */ case STATE_SENDING_STOP: mrq->stop->error = -ENOMEDIUM; break; } dw_mci_request_end(host, mrq); //停止请求,后面讲 } else { list_del(&slot->queue_node); mrq->cmd->error = -ENOMEDIUM; if (mrq->data) mrq->data->error = -ENOMEDIUM; if (mrq->stop) mrq->stop->error = -ENOMEDIUM; spin_unlock(&host->lock); mmc_request_done(slot->mmc, mrq); spin_lock(&host->lock); } } /* Power down slot */ if (present == 0) { if (host->pdata->setpower) host->pdata->setpower(slot->id, 0); clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); /* * Clear down the FIFO - doing so generates a * block interrupt, hence setting the * scatter-gather pointer to NULL. */ host->sg = NULL; ctrl = mci_readl(host, CTRL); ctrl |= SDMMC_CTRL_FIFO_RESET; mci_writel(host, CTRL, ctrl); //复位fifo #ifdef CONFIG_MMC_DW_IDMAC ctrl = mci_readl(host, BMOD); ctrl |= 0x01; /* Software reset of DMA */ mci_writel(host, BMOD, ctrl); #endif } spin_unlock(&host->lock); present = dw_mci_get_cd(mmc); } mmc_detect_change(slot->mmc, msecs_to_jiffies(host->pdata->detect_delay_ms)); } }获取卡状态: static int dw_mci_get_cd(struct mmc_host *mmc) { int present; struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci_board *brd = slot->host->pdata; /* Use platform get_cd function, else try onboard card detect */ if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) present = 1; else if (brd->get_cd) present = !brd->get_cd(slot->id); else present = (mci_readl(slot->host, CDETECT) & (1 id)) == 0 ? 1 : 0; //读取寄存器获取卡状态 if (present) dev_dbg(&mmc->class_dev, "card is present\n"); else dev_dbg(&mmc->class_dev, "card is not present\n"); return present; }停止DMA: /* DMA interface functions */ static void dw_mci_stop_dma(struct dw_mci *host) { //执行if,因为我们在内部DMA初始化时,已经将host->use_dma置1了 if (host->use_dma) { host->dma_ops->stop(host); host->dma_ops->cleanup(host); } else { /* Data transfer was stopped by the interrupt handler */ set_bit(EVENT_XFER_COMPLETE, &host->pending_events); } }停止请求: static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) __releases(&host->lock) __acquires(&host->lock) { struct dw_mci_slot *slot; struct mmc_host *prev_mmc = host->cur_slot->mmc; WARN_ON(host->cmd || host->data); host->cur_slot->mrq = NULL; host->mrq = NULL; if (!list_empty(&host->queue)) { slot = list_entry(host->queue.next, struct dw_mci_slot, queue_node); list_del(&slot->queue_node); dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n", mmc_hostname(slot->mmc)); host->state = STATE_SENDING_CMD; dw_mci_start_request(host, slot); //在请求中讲述 } else { dev_vdbg(&host->pdev->dev, "list empty\n"); host->state = STATE_IDLE; } spin_unlock(&host->lock); mmc_request_done(prev_mmc, mrq); spin_lock(&host->lock); } 接下来讲述tasklet另外一个函数dw_mci_tasklet_func: static void dw_mci_tasklet_func(unsigned long priv) { struct dw_mci *host = (struct dw_mci *)priv; struct mmc_data *data; struct mmc_command *cmd; enum dw_mci_state state; enum dw_mci_state prev_state; u32 status; spin_lock(&host->lock); state = host->state; data = host->data; do { prev_state = state; //host->pending_events的值都是在中断中被置的 switch (state) { case STATE_IDLE: break; case STATE_SENDING_CMD: if (!test_and_clear_bit(EVENT_CMD_COMPLETE, &host->pending_events)) break; cmd = host->cmd; host->cmd = NULL; set_bit(EVENT_CMD_COMPLETE, &host->completed_events); dw_mci_command_complete(host, host->mrq->cmd); //命令完成,后面讲 if (!host->mrq->data || cmd->error) { dw_mci_request_end(host, host->mrq); goto unlock; } prev_state = state = STATE_SENDING_DATA; /* fall through */ case STATE_SENDING_DATA: if (test_and_clear_bit(EVENT_DATA_ERROR, &host->pending_events)) { dw_mci_stop_dma(host); if (data->stop) send_stop_cmd(host, data); //发送结束命令,后面讲述 state = STATE_DATA_ERROR; break; } if (!test_and_clear_bit(EVENT_XFER_COMPLETE, &host->pending_events)) break; set_bit(EVENT_XFER_COMPLETE, &host->completed_events); prev_state = state = STATE_DATA_BUSY; /* fall through */ case STATE_DATA_BUSY: if (!test_and_clear_bit(EVENT_DATA_COMPLETE, &host->pending_events)) break; host->data = NULL; set_bit(EVENT_DATA_COMPLETE, &host->completed_events); status = host->data_status; if (status & DW_MCI_DATA_ERROR_FLAGS) { if (status & SDMMC_INT_DTO) { dev_err(&host->pdev->dev, "data timeout error\n"); data->error = -ETIMEDOUT; } else if (status & SDMMC_INT_DCRC) { dev_err(&host->pdev->dev, "data CRC error\n"); data->error = -EILSEQ; } else { dev_err(&host->pdev->dev, "data FIFO error " "(status=%08x)\n", status); data->error = -EIO; } } else { data->bytes_xfered = data->blocks * data->blksz; data->error = 0; } if (!data->stop) { dw_mci_request_end(host, host->mrq); goto unlock; } prev_state = state = STATE_SENDING_STOP; if (!data->error) send_stop_cmd(host, data); /* fall through */ case STATE_SENDING_STOP: if (!test_and_clear_bit(EVENT_CMD_COMPLETE, &host->pending_events)) break; host->cmd = NULL; dw_mci_command_complete(host, host->mrq->stop); dw_mci_request_end(host, host->mrq); goto unlock; case STATE_DATA_ERROR: if (!test_and_clear_bit(EVENT_XFER_COMPLETE, &host->pending_events)) break; state = STATE_DATA_BUSY; break; } } while (state != prev_state); host->state = state; unlock: spin_unlock(&host->lock); } 命令完成: static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd) { u32 status = host->cmd_status; host->cmd_status = 0; /* Read the response from the card (up to 16 bytes) */ if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_136) { cmd->resp[3] = mci_readl(host, RESP0); cmd->resp[2] = mci_readl(host, RESP1); cmd->resp[1] = mci_readl(host, RESP2); cmd->resp[0] = mci_readl(host, RESP3); } else { cmd->resp[0] = mci_readl(host, RESP0); cmd->resp[1] = 0; cmd->resp[2] = 0; cmd->resp[3] = 0; } } if (status & SDMMC_INT_RTO) cmd->error = -ETIMEDOUT; else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC)) cmd->error = -EILSEQ; else if (status & SDMMC_INT_RESP_ERR) cmd->error = -EIO; else cmd->error = 0; if (cmd->error) { /* newer ip versions need a delay between retries */ if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY) mdelay(20); if (cmd->data) { host->data = NULL; dw_mci_stop_dma(host); } } } 发送结束命令: static void send_stop_cmd(struct dw_mci *host, struct mmc_data *data) { dw_mci_start_command(host, data->stop, host->stop_cmdr); } static void dw_mci_start_command(struct dw_mci *host, struct mmc_command *cmd, u32 cmd_flags) { host->cmd = cmd; dev_vdbg(&host->pdev->dev, "start command: ARGR=0x%08x CMDR=0x%08x\n", cmd->arg, cmd_flags); mci_writel(host, CMDARG, cmd->arg); wmb(); if (cmd->opcode == SD_APP_SEND_SCR) mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START | SDMMC_CMD_SEND_STOP); else mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); }