static int jmb38x_ms_transfer_data()

in host/jmb38x_ms.c [299:364]


static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host)
{
	unsigned int length;
	unsigned int off;
	unsigned int t_size, p_cnt;
	unsigned char *buf;
	struct page *pg;
	unsigned long flags = 0;

	if (host->req->long_data) {
		length = host->req->sg.length - host->block_pos;
		off = host->req->sg.offset + host->block_pos;
	} else {
		length = host->req->data_len - host->block_pos;
		off = 0;
	}

	while (length) {
		unsigned int p_off;

		if (host->req->long_data) {
			pg = nth_page(sg_page(&host->req->sg),
				      off >> PAGE_SHIFT);
			p_off = offset_in_page(off);
			p_cnt = PAGE_SIZE - p_off;
			p_cnt = min(p_cnt, length);

			local_irq_save(flags);
			buf = kmap_atomic(pg) + p_off;
		} else {
			buf = host->req->data + host->block_pos;
			p_cnt = host->req->data_len - host->block_pos;
		}

		if (host->req->data_dir == WRITE)
			t_size = !(host->cmd_flags & REG_DATA)
				 ? jmb38x_ms_write_data(host, buf, p_cnt)
				 : jmb38x_ms_write_reg_data(host, buf, p_cnt);
		else
			t_size = !(host->cmd_flags & REG_DATA)
				 ? jmb38x_ms_read_data(host, buf, p_cnt)
				 : jmb38x_ms_read_reg_data(host, buf, p_cnt);

		if (host->req->long_data) {
			kunmap_atomic(buf - p_off);
			local_irq_restore(flags);
		}

		if (!t_size)
			break;
		host->block_pos += t_size;
		length -= t_size;
		off += t_size;
	}

	if (!length && host->req->data_dir == WRITE) {
		if (host->cmd_flags & REG_DATA) {
			writel(host->io_word[0], host->addr + TPC_P0);
			writel(host->io_word[1], host->addr + TPC_P1);
		} else if (host->io_pos) {
			writel(host->io_word[0], host->addr + DATA);
		}
	}

	return length;
}