歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux設備模型之mmc,sd子系統<二>

Linux設備模型之mmc,sd子系統<二>

日期:2017/2/28 15:58:03   编辑:Linux教程
繼續上一篇文章(見 http://www.linuxidc.com/Linux/2012-02/52948.htm ),先看一個重點結構,平台相關,真正對host的設置都會回調到這裡
static struct mmc_host_ops s3cmci_ops = {
.request = s3cmci_request, //用於命令和數據的發送接收
.set_ios = s3cmci_set_ios, //用於設置io
.get_ro = s3cmci_get_ro, //用於判斷寫保護
.get_cd = s3cmci_card_present, //判斷卡是否存在
.enable_sdio_irq = s3cmci_enable_sdio_irq,
};

####先看最復雜的命令請求
static void s3cmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct s3cmci_host *host = mmc_priv(mmc);

host->status = "mmc request"; //設置狀態
host->cmd_is_stop = 0;
host->mrq = mrq; //請求結構描述

if (s3cmci_card_present(mmc) == 0) { //卡是否存在
dbg(host, dbg_err, "%s: no medium present\n", __func__);
host->mrq->cmd->error = -ENOMEDIUM;
mmc_request_done(mmc, mrq); //無卡結束
} else
s3cmci_send_request(mmc); //有卡發送
}

@繼續
static void s3cmci_send_request(struct mmc_host *mmc)
{
struct s3cmci_host *host = mmc_priv(mmc);
struct mmc_request *mrq = host->mrq;
struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd;
//只有stop和命令請求?
host->ccnt++;
prepare_dbgmsg(host, cmd, host->cmd_is_stop);

/* Clear command, data and fifo status registers
Fifo clear only necessary on 2440, but doesn't hurt on 2410
請求狀態
*/
writel(0xFFFFFFFF, host->base + S3C2410_SDICMDSTAT);
writel(0xFFFFFFFF, host->base + S3C2410_SDIDSTA);
writel(0xFFFFFFFF, host->base + S3C2410_SDIFSTA);

if (cmd->data) {
int res = s3cmci_setup_data(host, cmd->data);

host->dcnt++;

if (res) {
dbg(host, dbg_err, "setup data error %d\n", res);
cmd->error = res;
cmd->data->error = res;

mmc_request_done(mmc, mrq);
return;
}

if (s3cmci_host_usedma(host)) //是否用dma
res = s3cmci_prepare_dma(host, cmd->data);
else
res = s3cmci_prepare_pio(host, cmd->data);

if (res) {
dbg(host, dbg_err, "data prepare error %d\n", res);
cmd->error = res;
cmd->data->error = res;

mmc_request_done(mmc, mrq);
return;
}
}

/* Send command */
s3cmci_send_command(host, cmd); //發送命令

/* Enable Interrupt */
s3cmci_enable_irq(host, true); //使能中斷
}
###設置命令數據到相應寄存器
static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data)
{
u32 dcon, imsk, stoptries = 3;

/* write DCON register */

if (!data) {
writel(0, host->base + S3C2410_SDIDCON);
return 0;
}

if ((data->blksz & 3) != 0) {
/* We cannot deal with unaligned blocks with more than
* one block being transferred. */

if (data->blocks > 1) {
pr_warning("%s: can't do non-word sized block transfers (blksz %d)\n", __func__, data->blksz);
return -EINVAL;
}
}

while (readl(host->base + S3C2410_SDIDSTA) &
(S3C2410_SDIDSTA_TXDATAON | S3C2410_SDIDSTA_RXDATAON)) {

dbg(host, dbg_err,
"mci_setup_data() transfer stillin progress.\n");

writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON);
s3cmci_reset(host);

if ((stoptries--) == 0) {
dbg_dumpregs(host, "DRF");
return -EINVAL;
}
}

dcon = data->blocks & S3C2410_SDIDCON_BLKNUM_MASK;

if (s3cmci_host_usedma(host))
dcon |= S3C2410_SDIDCON_DMAEN;

if (host->bus_width == MMC_BUS_WIDTH_4)
dcon |= S3C2410_SDIDCON_WIDEBUS;

if (!(data->flags & MMC_DATA_STREAM))
dcon |= S3C2410_SDIDCON_BLOCKMODE;

if (data->flags & MMC_DATA_WRITE) {
dcon |= S3C2410_SDIDCON_TXAFTERRESP;
dcon |= S3C2410_SDIDCON_XFER_TXSTART;
}

if (data->flags & MMC_DATA_READ) {
dcon |= S3C2410_SDIDCON_RXAFTERCMD;
dcon |= S3C2410_SDIDCON_XFER_RXSTART;
}

if (host->is2440) {
dcon |= S3C2440_SDIDCON_DS_WORD;
dcon |= S3C2440_SDIDCON_DATSTART;
}

writel(dcon, host->base + S3C2410_SDIDCON);

/* write BSIZE register */

writel(data->blksz, host->base + S3C2410_SDIBSIZE);

/* add to IMASK register */
imsk = S3C2410_SDIIMSK_FIFOFAIL | S3C2410_SDIIMSK_DATACRC |
S3C2410_SDIIMSK_DATATIMEOUT | S3C2410_SDIIMSK_DATAFINISH;

enable_imask(host, imsk);

/* write TIMER register */

if (host->is2440) {
writel(0x007FFFFF, host->base + S3C2410_SDITIMER);
} else {
writel(0x0000FFFF, host->base + S3C2410_SDITIMER);

/* FIX: set slow clock to prevent timeouts on read */
if (data->flags & MMC_DATA_READ)
writel(0xFF, host->base + S3C2410_SDIPRE);
}

return 0;
}
Copyright © Linux教程網 All Rights Reserved