static unsigned int tifm_ms_transfer_data()

in host/tifm_ms.c [180:250]


static unsigned int tifm_ms_transfer_data(struct tifm_ms *host)
{
	struct tifm_dev *sock = host->dev;
	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;
	}
	dev_dbg(&sock->dev, "fifo data transfer, %d, %d\n", length,
		host->block_pos);

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

		t_size = host->req->data_dir == WRITE
			 ? tifm_ms_write_data(host, buf, p_cnt)
			 : tifm_ms_read_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;
	}

	dev_dbg(&sock->dev, "fifo data transfer, %d remaining\n", length);
	if (!length && (host->req->data_dir == WRITE)) {
		if (host->io_pos) {
			writel(TIFM_MS_SYS_FDIR
			       | readl(sock->addr + SOCK_MS_SYSTEM),
			       sock->addr + SOCK_MS_SYSTEM);
			writel(host->io_word, sock->addr + SOCK_MS_DATA);
		}
		writel(TIFM_MS_SYS_FDIR
		       | readl(sock->addr + SOCK_MS_SYSTEM),
		       sock->addr + SOCK_MS_SYSTEM);
		writel(0, sock->addr + SOCK_MS_DATA);
	} else {
		readl(sock->addr + SOCK_MS_DATA);
	}

	return length;
}