162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * STK1160 driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2012 Ezequiel Garcia
662306a36Sopenharmony_ci * <elezegarcia--a.t--gmail.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Based on Easycap driver by R.M. Thomas
962306a36Sopenharmony_ci *	Copyright (C) 2010 R.M. Thomas
1062306a36Sopenharmony_ci *	<rmthomas--a.t--sciolus.org>
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/usb.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <linux/ratelimit.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "stk1160.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic unsigned int debug;
2162306a36Sopenharmony_cimodule_param(debug, int, 0644);
2262306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "enable debug messages");
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic inline void print_err_status(struct stk1160 *dev,
2562306a36Sopenharmony_ci				     int packet, int status)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	char *errmsg = "Unknown";
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	switch (status) {
3062306a36Sopenharmony_ci	case -ENOENT:
3162306a36Sopenharmony_ci		errmsg = "unlinked synchronously";
3262306a36Sopenharmony_ci		break;
3362306a36Sopenharmony_ci	case -ECONNRESET:
3462306a36Sopenharmony_ci		errmsg = "unlinked asynchronously";
3562306a36Sopenharmony_ci		break;
3662306a36Sopenharmony_ci	case -ENOSR:
3762306a36Sopenharmony_ci		errmsg = "Buffer error (overrun)";
3862306a36Sopenharmony_ci		break;
3962306a36Sopenharmony_ci	case -EPIPE:
4062306a36Sopenharmony_ci		errmsg = "Stalled (device not responding)";
4162306a36Sopenharmony_ci		break;
4262306a36Sopenharmony_ci	case -EOVERFLOW:
4362306a36Sopenharmony_ci		errmsg = "Babble (bad cable?)";
4462306a36Sopenharmony_ci		break;
4562306a36Sopenharmony_ci	case -EPROTO:
4662306a36Sopenharmony_ci		errmsg = "Bit-stuff error (bad cable?)";
4762306a36Sopenharmony_ci		break;
4862306a36Sopenharmony_ci	case -EILSEQ:
4962306a36Sopenharmony_ci		errmsg = "CRC/Timeout (could be anything)";
5062306a36Sopenharmony_ci		break;
5162306a36Sopenharmony_ci	case -ETIME:
5262306a36Sopenharmony_ci		errmsg = "Device does not respond";
5362306a36Sopenharmony_ci		break;
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	if (packet < 0)
5762306a36Sopenharmony_ci		printk_ratelimited(KERN_WARNING "URB status %d [%s].\n",
5862306a36Sopenharmony_ci				status, errmsg);
5962306a36Sopenharmony_ci	else
6062306a36Sopenharmony_ci		printk_ratelimited(KERN_INFO "URB packet %d, status %d [%s].\n",
6162306a36Sopenharmony_ci			       packet, status, errmsg);
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic inline
6562306a36Sopenharmony_cistruct stk1160_buffer *stk1160_next_buffer(struct stk1160 *dev)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	struct stk1160_buffer *buf = NULL;
6862306a36Sopenharmony_ci	unsigned long flags = 0;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/* Current buffer must be NULL when this functions gets called */
7162306a36Sopenharmony_ci	WARN_ON(dev->isoc_ctl.buf);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	spin_lock_irqsave(&dev->buf_lock, flags);
7462306a36Sopenharmony_ci	if (!list_empty(&dev->avail_bufs)) {
7562306a36Sopenharmony_ci		buf = list_first_entry(&dev->avail_bufs,
7662306a36Sopenharmony_ci				struct stk1160_buffer, list);
7762306a36Sopenharmony_ci		list_del(&buf->list);
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->buf_lock, flags);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	return buf;
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic inline
8562306a36Sopenharmony_civoid stk1160_buffer_done(struct stk1160 *dev)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	struct stk1160_buffer *buf = dev->isoc_ctl.buf;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	buf->vb.sequence = dev->sequence++;
9062306a36Sopenharmony_ci	buf->vb.field = V4L2_FIELD_INTERLACED;
9162306a36Sopenharmony_ci	buf->vb.vb2_buf.timestamp = ktime_get_ns();
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->bytesused);
9462306a36Sopenharmony_ci	vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	dev->isoc_ctl.buf = NULL;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic inline
10062306a36Sopenharmony_civoid stk1160_copy_video(struct stk1160 *dev, u8 *src, int len)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	int linesdone, lineoff, lencopy;
10362306a36Sopenharmony_ci	int bytesperline = dev->width * 2;
10462306a36Sopenharmony_ci	struct stk1160_buffer *buf = dev->isoc_ctl.buf;
10562306a36Sopenharmony_ci	u8 *dst = buf->mem;
10662306a36Sopenharmony_ci	int remain;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/*
10962306a36Sopenharmony_ci	 * TODO: These stk1160_dbg are very spammy!
11062306a36Sopenharmony_ci	 * We should check why we are getting them.
11162306a36Sopenharmony_ci	 *
11262306a36Sopenharmony_ci	 * UPDATE: One of the reasons (the only one?) for getting these
11362306a36Sopenharmony_ci	 * is incorrect standard (mismatch between expected and configured).
11462306a36Sopenharmony_ci	 * So perhaps, we could add a counter for errors. When the counter
11562306a36Sopenharmony_ci	 * reaches some value, we simply stop streaming.
11662306a36Sopenharmony_ci	 */
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	len -= 4;
11962306a36Sopenharmony_ci	src += 4;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	remain = len;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	linesdone = buf->pos / bytesperline;
12462306a36Sopenharmony_ci	lineoff = buf->pos % bytesperline; /* offset in current line */
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	if (!buf->odd)
12762306a36Sopenharmony_ci		dst += bytesperline;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* Multiply linesdone by two, to take account of the other field */
13062306a36Sopenharmony_ci	dst += linesdone * bytesperline * 2 + lineoff;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/* Copy the remaining of current line */
13362306a36Sopenharmony_ci	if (remain < (bytesperline - lineoff))
13462306a36Sopenharmony_ci		lencopy = remain;
13562306a36Sopenharmony_ci	else
13662306a36Sopenharmony_ci		lencopy = bytesperline - lineoff;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	/*
13962306a36Sopenharmony_ci	 * Check if we have enough space left in the buffer.
14062306a36Sopenharmony_ci	 * In that case, we force loop exit after copy.
14162306a36Sopenharmony_ci	 */
14262306a36Sopenharmony_ci	if (lencopy > buf->bytesused - buf->length) {
14362306a36Sopenharmony_ci		lencopy = buf->bytesused - buf->length;
14462306a36Sopenharmony_ci		remain = lencopy;
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	/* Check if the copy is done */
14862306a36Sopenharmony_ci	if (lencopy == 0 || remain == 0)
14962306a36Sopenharmony_ci		return;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	/* Let the bug hunt begin! sanity checks! */
15262306a36Sopenharmony_ci	if (lencopy < 0) {
15362306a36Sopenharmony_ci		printk_ratelimited(KERN_DEBUG "copy skipped: negative lencopy\n");
15462306a36Sopenharmony_ci		return;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if ((unsigned long)dst + lencopy >
15862306a36Sopenharmony_ci		(unsigned long)buf->mem + buf->length) {
15962306a36Sopenharmony_ci		printk_ratelimited(KERN_WARNING "stk1160: buffer overflow detected\n");
16062306a36Sopenharmony_ci		return;
16162306a36Sopenharmony_ci	}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	memcpy(dst, src, lencopy);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	buf->bytesused += lencopy;
16662306a36Sopenharmony_ci	buf->pos += lencopy;
16762306a36Sopenharmony_ci	remain -= lencopy;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	/* Copy current field line by line, interlacing with the other field */
17062306a36Sopenharmony_ci	while (remain > 0) {
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci		dst += lencopy + bytesperline;
17362306a36Sopenharmony_ci		src += lencopy;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci		/* Copy one line at a time */
17662306a36Sopenharmony_ci		if (remain < bytesperline)
17762306a36Sopenharmony_ci			lencopy = remain;
17862306a36Sopenharmony_ci		else
17962306a36Sopenharmony_ci			lencopy = bytesperline;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci		/*
18262306a36Sopenharmony_ci		 * Check if we have enough space left in the buffer.
18362306a36Sopenharmony_ci		 * In that case, we force loop exit after copy.
18462306a36Sopenharmony_ci		 */
18562306a36Sopenharmony_ci		if (lencopy > buf->bytesused - buf->length) {
18662306a36Sopenharmony_ci			lencopy = buf->bytesused - buf->length;
18762306a36Sopenharmony_ci			remain = lencopy;
18862306a36Sopenharmony_ci		}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci		/* Check if the copy is done */
19162306a36Sopenharmony_ci		if (lencopy == 0 || remain == 0)
19262306a36Sopenharmony_ci			return;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci		if (lencopy < 0) {
19562306a36Sopenharmony_ci			printk_ratelimited(KERN_WARNING "stk1160: negative lencopy detected\n");
19662306a36Sopenharmony_ci			return;
19762306a36Sopenharmony_ci		}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci		if ((unsigned long)dst + lencopy >
20062306a36Sopenharmony_ci			(unsigned long)buf->mem + buf->length) {
20162306a36Sopenharmony_ci			printk_ratelimited(KERN_WARNING "stk1160: buffer overflow detected\n");
20262306a36Sopenharmony_ci			return;
20362306a36Sopenharmony_ci		}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci		memcpy(dst, src, lencopy);
20662306a36Sopenharmony_ci		remain -= lencopy;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci		buf->bytesused += lencopy;
20962306a36Sopenharmony_ci		buf->pos += lencopy;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci/*
21462306a36Sopenharmony_ci * Controls the isoc copy of each urb packet
21562306a36Sopenharmony_ci */
21662306a36Sopenharmony_cistatic void stk1160_process_isoc(struct stk1160 *dev, struct urb *urb)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	int i, len, status;
21962306a36Sopenharmony_ci	u8 *p;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	if (!dev) {
22262306a36Sopenharmony_ci		stk1160_warn("%s called with null device\n", __func__);
22362306a36Sopenharmony_ci		return;
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	if (urb->status < 0) {
22762306a36Sopenharmony_ci		/* Print status and drop current packet (or field?) */
22862306a36Sopenharmony_ci		print_err_status(dev, -1, urb->status);
22962306a36Sopenharmony_ci		return;
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	for (i = 0; i < urb->number_of_packets; i++) {
23362306a36Sopenharmony_ci		status = urb->iso_frame_desc[i].status;
23462306a36Sopenharmony_ci		if (status < 0) {
23562306a36Sopenharmony_ci			print_err_status(dev, i, status);
23662306a36Sopenharmony_ci			continue;
23762306a36Sopenharmony_ci		}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci		/* Get packet actual length and pointer to data */
24062306a36Sopenharmony_ci		p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
24162306a36Sopenharmony_ci		len = urb->iso_frame_desc[i].actual_length;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci		/* Empty packet */
24462306a36Sopenharmony_ci		if (len <= 4)
24562306a36Sopenharmony_ci			continue;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci		/*
24862306a36Sopenharmony_ci		 * An 8-byte packet sequence means end of field.
24962306a36Sopenharmony_ci		 * So if we don't have any packet, we start receiving one now
25062306a36Sopenharmony_ci		 * and if we do have a packet, then we are done with it.
25162306a36Sopenharmony_ci		 *
25262306a36Sopenharmony_ci		 * These end of field packets are always 0xc0 or 0x80,
25362306a36Sopenharmony_ci		 * but not always 8-byte long so we don't check packet length.
25462306a36Sopenharmony_ci		 */
25562306a36Sopenharmony_ci		if (p[0] == 0xc0) {
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci			/*
25862306a36Sopenharmony_ci			 * If first byte is 0xc0 then we received
25962306a36Sopenharmony_ci			 * second field, and frame has ended.
26062306a36Sopenharmony_ci			 */
26162306a36Sopenharmony_ci			if (dev->isoc_ctl.buf != NULL)
26262306a36Sopenharmony_ci				stk1160_buffer_done(dev);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci			dev->isoc_ctl.buf = stk1160_next_buffer(dev);
26562306a36Sopenharmony_ci			if (dev->isoc_ctl.buf == NULL)
26662306a36Sopenharmony_ci				return;
26762306a36Sopenharmony_ci		}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci		/*
27062306a36Sopenharmony_ci		 * If we don't have a buffer here, then it means we
27162306a36Sopenharmony_ci		 * haven't found the start mark sequence.
27262306a36Sopenharmony_ci		 */
27362306a36Sopenharmony_ci		if (dev->isoc_ctl.buf == NULL)
27462306a36Sopenharmony_ci			continue;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci		if (p[0] == 0xc0 || p[0] == 0x80) {
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci			/* We set next packet parity and
27962306a36Sopenharmony_ci			 * continue to get next one
28062306a36Sopenharmony_ci			 */
28162306a36Sopenharmony_ci			dev->isoc_ctl.buf->odd = *p & 0x40;
28262306a36Sopenharmony_ci			dev->isoc_ctl.buf->pos = 0;
28362306a36Sopenharmony_ci			continue;
28462306a36Sopenharmony_ci		}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci		stk1160_copy_video(dev, p, len);
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci/*
29262306a36Sopenharmony_ci * IRQ callback, called by URB callback
29362306a36Sopenharmony_ci */
29462306a36Sopenharmony_cistatic void stk1160_isoc_irq(struct urb *urb)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	int i, rc;
29762306a36Sopenharmony_ci	struct stk1160_urb *stk_urb = urb->context;
29862306a36Sopenharmony_ci	struct stk1160 *dev = stk_urb->dev;
29962306a36Sopenharmony_ci	struct device *dma_dev = stk1160_get_dmadev(dev);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	switch (urb->status) {
30262306a36Sopenharmony_ci	case 0:
30362306a36Sopenharmony_ci		break;
30462306a36Sopenharmony_ci	case -ECONNRESET:   /* kill */
30562306a36Sopenharmony_ci	case -ENOENT:
30662306a36Sopenharmony_ci	case -ESHUTDOWN:
30762306a36Sopenharmony_ci		/* TODO: check uvc driver: he frees the queue here */
30862306a36Sopenharmony_ci		return;
30962306a36Sopenharmony_ci	default:
31062306a36Sopenharmony_ci		stk1160_err("urb error! status %d\n", urb->status);
31162306a36Sopenharmony_ci		return;
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	invalidate_kernel_vmap_range(stk_urb->transfer_buffer,
31562306a36Sopenharmony_ci				     urb->transfer_buffer_length);
31662306a36Sopenharmony_ci	dma_sync_sgtable_for_cpu(dma_dev, stk_urb->sgt, DMA_FROM_DEVICE);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	stk1160_process_isoc(dev, urb);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	/* Reset urb buffers */
32162306a36Sopenharmony_ci	for (i = 0; i < urb->number_of_packets; i++) {
32262306a36Sopenharmony_ci		urb->iso_frame_desc[i].status = 0;
32362306a36Sopenharmony_ci		urb->iso_frame_desc[i].actual_length = 0;
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	dma_sync_sgtable_for_device(dma_dev, stk_urb->sgt, DMA_FROM_DEVICE);
32762306a36Sopenharmony_ci	rc = usb_submit_urb(urb, GFP_ATOMIC);
32862306a36Sopenharmony_ci	if (rc)
32962306a36Sopenharmony_ci		stk1160_err("urb re-submit failed (%d)\n", rc);
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci/*
33362306a36Sopenharmony_ci * Cancel urbs
33462306a36Sopenharmony_ci * This function can't be called in atomic context
33562306a36Sopenharmony_ci */
33662306a36Sopenharmony_civoid stk1160_cancel_isoc(struct stk1160 *dev)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	int i, num_bufs = dev->isoc_ctl.num_bufs;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/*
34162306a36Sopenharmony_ci	 * This check is not necessary, but we add it
34262306a36Sopenharmony_ci	 * to avoid a spurious debug message
34362306a36Sopenharmony_ci	 */
34462306a36Sopenharmony_ci	if (!num_bufs)
34562306a36Sopenharmony_ci		return;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	stk1160_dbg("killing %d urbs...\n", num_bufs);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	for (i = 0; i < num_bufs; i++) {
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci		/*
35262306a36Sopenharmony_ci		 * To kill urbs we can't be in atomic context.
35362306a36Sopenharmony_ci		 * We don't care for NULL pointer since
35462306a36Sopenharmony_ci		 * usb_kill_urb allows it.
35562306a36Sopenharmony_ci		 */
35662306a36Sopenharmony_ci		usb_kill_urb(dev->isoc_ctl.urb_ctl[i].urb);
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	stk1160_dbg("all urbs killed\n");
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cistatic void stk_free_urb(struct stk1160 *dev, struct stk1160_urb *stk_urb)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	struct device *dma_dev = stk1160_get_dmadev(dev);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	dma_vunmap_noncontiguous(dma_dev, stk_urb->transfer_buffer);
36762306a36Sopenharmony_ci	dma_free_noncontiguous(dma_dev, stk_urb->urb->transfer_buffer_length,
36862306a36Sopenharmony_ci			       stk_urb->sgt, DMA_FROM_DEVICE);
36962306a36Sopenharmony_ci	usb_free_urb(stk_urb->urb);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	stk_urb->transfer_buffer = NULL;
37262306a36Sopenharmony_ci	stk_urb->sgt = NULL;
37362306a36Sopenharmony_ci	stk_urb->urb = NULL;
37462306a36Sopenharmony_ci	stk_urb->dev = NULL;
37562306a36Sopenharmony_ci	stk_urb->dma = 0;
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci/*
37962306a36Sopenharmony_ci * Releases urb and transfer buffers
38062306a36Sopenharmony_ci * Obviusly, associated urb must be killed before releasing it.
38162306a36Sopenharmony_ci */
38262306a36Sopenharmony_civoid stk1160_free_isoc(struct stk1160 *dev)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	int i, num_bufs = dev->isoc_ctl.num_bufs;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	stk1160_dbg("freeing %d urb buffers...\n", num_bufs);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	for (i = 0; i < num_bufs; i++)
38962306a36Sopenharmony_ci		stk_free_urb(dev, &dev->isoc_ctl.urb_ctl[i]);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	dev->isoc_ctl.num_bufs = 0;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	stk1160_dbg("all urb buffers freed\n");
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci/*
39762306a36Sopenharmony_ci * Helper for cancelling and freeing urbs
39862306a36Sopenharmony_ci * This function can't be called in atomic context
39962306a36Sopenharmony_ci */
40062306a36Sopenharmony_civoid stk1160_uninit_isoc(struct stk1160 *dev)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	stk1160_cancel_isoc(dev);
40362306a36Sopenharmony_ci	stk1160_free_isoc(dev);
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_cistatic int stk1160_fill_urb(struct stk1160 *dev, struct stk1160_urb *stk_urb,
40762306a36Sopenharmony_ci			    int sb_size, int max_packets)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	struct device *dma_dev = stk1160_get_dmadev(dev);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	stk_urb->urb = usb_alloc_urb(max_packets, GFP_KERNEL);
41262306a36Sopenharmony_ci	if (!stk_urb->urb)
41362306a36Sopenharmony_ci		return -ENOMEM;
41462306a36Sopenharmony_ci	stk_urb->sgt = dma_alloc_noncontiguous(dma_dev, sb_size,
41562306a36Sopenharmony_ci					       DMA_FROM_DEVICE, GFP_KERNEL, 0);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	/*
41862306a36Sopenharmony_ci	 * If the buffer allocation failed, we exit but return 0 since
41962306a36Sopenharmony_ci	 * we allow the driver working with less buffers
42062306a36Sopenharmony_ci	 */
42162306a36Sopenharmony_ci	if (!stk_urb->sgt)
42262306a36Sopenharmony_ci		goto free_urb;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	stk_urb->transfer_buffer = dma_vmap_noncontiguous(dma_dev, sb_size,
42562306a36Sopenharmony_ci							  stk_urb->sgt);
42662306a36Sopenharmony_ci	if (!stk_urb->transfer_buffer)
42762306a36Sopenharmony_ci		goto free_sgt;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	stk_urb->dma = stk_urb->sgt->sgl->dma_address;
43062306a36Sopenharmony_ci	stk_urb->dev = dev;
43162306a36Sopenharmony_ci	return 0;
43262306a36Sopenharmony_cifree_sgt:
43362306a36Sopenharmony_ci	dma_free_noncontiguous(dma_dev, sb_size, stk_urb->sgt, DMA_FROM_DEVICE);
43462306a36Sopenharmony_ci	stk_urb->sgt = NULL;
43562306a36Sopenharmony_cifree_urb:
43662306a36Sopenharmony_ci	usb_free_urb(stk_urb->urb);
43762306a36Sopenharmony_ci	stk_urb->urb = NULL;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	return 0;
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci/*
44262306a36Sopenharmony_ci * Allocate URBs
44362306a36Sopenharmony_ci */
44462306a36Sopenharmony_ciint stk1160_alloc_isoc(struct stk1160 *dev)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	struct urb *urb;
44762306a36Sopenharmony_ci	int i, j, k, sb_size, max_packets, num_bufs;
44862306a36Sopenharmony_ci	int ret;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	/*
45162306a36Sopenharmony_ci	 * It may be necessary to release isoc here,
45262306a36Sopenharmony_ci	 * since isoc are only released on disconnection.
45362306a36Sopenharmony_ci	 * (see new_pkt_size flag)
45462306a36Sopenharmony_ci	 */
45562306a36Sopenharmony_ci	if (dev->isoc_ctl.num_bufs)
45662306a36Sopenharmony_ci		stk1160_uninit_isoc(dev);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	stk1160_dbg("allocating urbs...\n");
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	num_bufs = STK1160_NUM_BUFS;
46162306a36Sopenharmony_ci	max_packets = STK1160_NUM_PACKETS;
46262306a36Sopenharmony_ci	sb_size = max_packets * dev->max_pkt_size;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	dev->isoc_ctl.buf = NULL;
46562306a36Sopenharmony_ci	dev->isoc_ctl.max_pkt_size = dev->max_pkt_size;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	/* allocate urbs and transfer buffers */
46862306a36Sopenharmony_ci	for (i = 0; i < num_bufs; i++) {
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci		ret = stk1160_fill_urb(dev, &dev->isoc_ctl.urb_ctl[i],
47162306a36Sopenharmony_ci				       sb_size, max_packets);
47262306a36Sopenharmony_ci		if (ret)
47362306a36Sopenharmony_ci			goto free_i_bufs;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci		urb = dev->isoc_ctl.urb_ctl[i].urb;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci		if (!urb) {
47862306a36Sopenharmony_ci			/* Not enough transfer buffers, so just give up */
47962306a36Sopenharmony_ci			if (i < STK1160_MIN_BUFS)
48062306a36Sopenharmony_ci				goto free_i_bufs;
48162306a36Sopenharmony_ci			goto nomore_tx_bufs;
48262306a36Sopenharmony_ci		}
48362306a36Sopenharmony_ci		memset(dev->isoc_ctl.urb_ctl[i].transfer_buffer, 0, sb_size);
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci		/*
48662306a36Sopenharmony_ci		 * FIXME: Where can I get the endpoint?
48762306a36Sopenharmony_ci		 */
48862306a36Sopenharmony_ci		urb->dev = dev->udev;
48962306a36Sopenharmony_ci		urb->pipe = usb_rcvisocpipe(dev->udev, STK1160_EP_VIDEO);
49062306a36Sopenharmony_ci		urb->transfer_buffer = dev->isoc_ctl.urb_ctl[i].transfer_buffer;
49162306a36Sopenharmony_ci		urb->transfer_buffer_length = sb_size;
49262306a36Sopenharmony_ci		urb->complete = stk1160_isoc_irq;
49362306a36Sopenharmony_ci		urb->context = &dev->isoc_ctl.urb_ctl[i];
49462306a36Sopenharmony_ci		urb->interval = 1;
49562306a36Sopenharmony_ci		urb->start_frame = 0;
49662306a36Sopenharmony_ci		urb->number_of_packets = max_packets;
49762306a36Sopenharmony_ci		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
49862306a36Sopenharmony_ci		urb->transfer_dma = dev->isoc_ctl.urb_ctl[i].dma;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci		k = 0;
50162306a36Sopenharmony_ci		for (j = 0; j < max_packets; j++) {
50262306a36Sopenharmony_ci			urb->iso_frame_desc[j].offset = k;
50362306a36Sopenharmony_ci			urb->iso_frame_desc[j].length =
50462306a36Sopenharmony_ci					dev->isoc_ctl.max_pkt_size;
50562306a36Sopenharmony_ci			k += dev->isoc_ctl.max_pkt_size;
50662306a36Sopenharmony_ci		}
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	stk1160_dbg("%d urbs allocated\n", num_bufs);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	/* At last we can say we have some buffers */
51262306a36Sopenharmony_ci	dev->isoc_ctl.num_bufs = num_bufs;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	return 0;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cinomore_tx_bufs:
51762306a36Sopenharmony_ci	/*
51862306a36Sopenharmony_ci	 * Failed to allocate desired buffer count. However, we may have
51962306a36Sopenharmony_ci	 * enough to work fine, so we just free the extra urb,
52062306a36Sopenharmony_ci	 * store the allocated count and keep going, fingers crossed!
52162306a36Sopenharmony_ci	 */
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	stk1160_warn("%d urbs allocated. Trying to continue...\n", i);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	dev->isoc_ctl.num_bufs = i;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	return 0;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_cifree_i_bufs:
53062306a36Sopenharmony_ci	/* Save the allocated buffers so far, so we can properly free them */
53162306a36Sopenharmony_ci	dev->isoc_ctl.num_bufs = i;
53262306a36Sopenharmony_ci	stk1160_free_isoc(dev);
53362306a36Sopenharmony_ci	return -ENOMEM;
53462306a36Sopenharmony_ci}
53562306a36Sopenharmony_ci
536