static int jmb38x_ms_issue_cmd()

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;
}