当前位置:   article > 正文

linux mmc 子系统,Linux设备模型之mmc,sd子系统

linux mmc 子系统,Linux设备模型之mmc,sd子系统

继续上一篇文章(见 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;

}

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号