这一节我们看下探测函数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); }
11-17 01:41
查看更多