in host/jmb38x_ms.c [366:464]
static int jmb38x_ms_issue_cmd(struct memstick_host *msh)
{
struct jmb38x_ms_host *host = memstick_priv(msh);
unsigned int data_len, cmd, t_val;
if (!(STATUS_HAS_MEDIA & readl(host->addr + STATUS))) {
dev_dbg(&msh->dev, "no media status\n");
host->req->error = -ETIME;
return host->req->error;
}
dev_dbg(&msh->dev, "control %08x\n", readl(host->addr + HOST_CONTROL));
dev_dbg(&msh->dev, "status %08x\n", readl(host->addr + INT_STATUS));
dev_dbg(&msh->dev, "hstatus %08x\n", readl(host->addr + STATUS));
host->cmd_flags = 0;
host->block_pos = 0;
host->io_pos = 0;
host->io_word[0] = 0;
host->io_word[1] = 0;
cmd = host->req->tpc << 16;
cmd |= TPC_DATA_SEL;
if (host->req->data_dir == READ)
cmd |= TPC_DIR;
if (host->req->need_card_int) {
if (host->ifmode == MEMSTICK_SERIAL)
cmd |= TPC_GET_INT;
else
cmd |= TPC_WAIT_INT;
}
if (!no_dma)
host->cmd_flags |= DMA_DATA;
if (host->req->long_data) {
data_len = host->req->sg.length;
} else {
data_len = host->req->data_len;
host->cmd_flags &= ~DMA_DATA;
}
if (data_len <= 8) {
cmd &= ~(TPC_DATA_SEL | 0xf);
host->cmd_flags |= REG_DATA;
cmd |= data_len & 0xf;
host->cmd_flags &= ~DMA_DATA;
}
if (host->cmd_flags & DMA_DATA) {
if (1 != dma_map_sg(&host->chip->pdev->dev, &host->req->sg, 1,
host->req->data_dir == READ
? DMA_FROM_DEVICE
: DMA_TO_DEVICE)) {
host->req->error = -ENOMEM;
return host->req->error;
}
data_len = sg_dma_len(&host->req->sg);
writel(sg_dma_address(&host->req->sg),
host->addr + DMA_ADDRESS);
writel(((1 << 16) & BLOCK_COUNT_MASK)
| (data_len & BLOCK_SIZE_MASK),
host->addr + BLOCK);
writel(DMA_CONTROL_ENABLE, host->addr + DMA_CONTROL);
} else if (!(host->cmd_flags & REG_DATA)) {
writel(((1 << 16) & BLOCK_COUNT_MASK)
| (data_len & BLOCK_SIZE_MASK),
host->addr + BLOCK);
t_val = readl(host->addr + INT_STATUS_ENABLE);
t_val |= host->req->data_dir == READ
? INT_STATUS_FIFO_RRDY
: INT_STATUS_FIFO_WRDY;
writel(t_val, host->addr + INT_STATUS_ENABLE);
writel(t_val, host->addr + INT_SIGNAL_ENABLE);
} else {
cmd &= ~(TPC_DATA_SEL | 0xf);
host->cmd_flags |= REG_DATA;
cmd |= data_len & 0xf;
if (host->req->data_dir == WRITE) {
jmb38x_ms_transfer_data(host);
writel(host->io_word[0], host->addr + TPC_P0);
writel(host->io_word[1], host->addr + TPC_P1);
}
}
mod_timer(&host->timer, jiffies + host->timeout_jiffies);
writel(HOST_CONTROL_LED | readl(host->addr + HOST_CONTROL),
host->addr + HOST_CONTROL);
host->req->error = 0;
writel(cmd, host->addr + TPC);
dev_dbg(&msh->dev, "executing TPC %08x, len %x\n", cmd, data_len);
return 0;
}