xref: /openbmc/linux/drivers/usb/gadget/function/uvc_video.c (revision 8e1f64d44664e90bded7d4fd7097e4d8c67f2074)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
200a2430fSAndrzej Pietrasiewicz /*
300a2430fSAndrzej Pietrasiewicz  *	uvc_video.c  --  USB Video Class Gadget driver
400a2430fSAndrzej Pietrasiewicz  *
500a2430fSAndrzej Pietrasiewicz  *	Copyright (C) 2009-2010
600a2430fSAndrzej Pietrasiewicz  *	    Laurent Pinchart (laurent.pinchart@ideasonboard.com)
700a2430fSAndrzej Pietrasiewicz  */
800a2430fSAndrzej Pietrasiewicz 
900a2430fSAndrzej Pietrasiewicz #include <linux/kernel.h>
1000a2430fSAndrzej Pietrasiewicz #include <linux/device.h>
1100a2430fSAndrzej Pietrasiewicz #include <linux/errno.h>
1200a2430fSAndrzej Pietrasiewicz #include <linux/usb/ch9.h>
1300a2430fSAndrzej Pietrasiewicz #include <linux/usb/gadget.h>
143a83c16eSAndrzej Pietrasiewicz #include <linux/usb/video.h>
15fd03af27SMichael Olbrich #include <asm/unaligned.h>
1600a2430fSAndrzej Pietrasiewicz 
1700a2430fSAndrzej Pietrasiewicz #include <media/v4l2-dev.h>
1800a2430fSAndrzej Pietrasiewicz 
1900a2430fSAndrzej Pietrasiewicz #include "uvc.h"
2000a2430fSAndrzej Pietrasiewicz #include "uvc_queue.h"
2170685711SLad, Prabhakar #include "uvc_video.h"
2200a2430fSAndrzej Pietrasiewicz 
2300a2430fSAndrzej Pietrasiewicz /* --------------------------------------------------------------------------
2400a2430fSAndrzej Pietrasiewicz  * Video codecs
2500a2430fSAndrzej Pietrasiewicz  */
2600a2430fSAndrzej Pietrasiewicz 
2700a2430fSAndrzej Pietrasiewicz static int
uvc_video_encode_header(struct uvc_video * video,struct uvc_buffer * buf,u8 * data,int len)2800a2430fSAndrzej Pietrasiewicz uvc_video_encode_header(struct uvc_video *video, struct uvc_buffer *buf,
2900a2430fSAndrzej Pietrasiewicz 		u8 *data, int len)
3000a2430fSAndrzej Pietrasiewicz {
31fd03af27SMichael Olbrich 	struct uvc_device *uvc = container_of(video, struct uvc_device, video);
32fd03af27SMichael Olbrich 	struct usb_composite_dev *cdev = uvc->func.config->cdev;
33fd03af27SMichael Olbrich 	struct timespec64 ts = ns_to_timespec64(buf->buf.vb2_buf.timestamp);
34fd03af27SMichael Olbrich 	int pos = 2;
35fd03af27SMichael Olbrich 
3600a2430fSAndrzej Pietrasiewicz 	data[1] = UVC_STREAM_EOH | video->fid;
3700a2430fSAndrzej Pietrasiewicz 
38*0d52e185SMichael Grzeschik 	if (video->queue.flags & UVC_QUEUE_DROP_INCOMPLETE)
39*0d52e185SMichael Grzeschik 		data[1] |= UVC_STREAM_ERR;
40*0d52e185SMichael Grzeschik 
41fd03af27SMichael Olbrich 	if (video->queue.buf_used == 0 && ts.tv_sec) {
42fd03af27SMichael Olbrich 		/* dwClockFrequency is 48 MHz */
43fd03af27SMichael Olbrich 		u32 pts = ((u64)ts.tv_sec * USEC_PER_SEC + ts.tv_nsec / NSEC_PER_USEC) * 48;
44fd03af27SMichael Olbrich 
45fd03af27SMichael Olbrich 		data[1] |= UVC_STREAM_PTS;
46fd03af27SMichael Olbrich 		put_unaligned_le32(pts, &data[pos]);
47fd03af27SMichael Olbrich 		pos += 4;
48fd03af27SMichael Olbrich 	}
49fd03af27SMichael Olbrich 
50fd03af27SMichael Olbrich 	if (cdev->gadget->ops->get_frame) {
51fd03af27SMichael Olbrich 		u32 sof, stc;
52fd03af27SMichael Olbrich 
53fd03af27SMichael Olbrich 		sof = usb_gadget_frame_number(cdev->gadget);
54fd03af27SMichael Olbrich 		ktime_get_ts64(&ts);
55fd03af27SMichael Olbrich 		stc = ((u64)ts.tv_sec * USEC_PER_SEC + ts.tv_nsec / NSEC_PER_USEC) * 48;
56fd03af27SMichael Olbrich 
57fd03af27SMichael Olbrich 		data[1] |= UVC_STREAM_SCR;
58fd03af27SMichael Olbrich 		put_unaligned_le32(stc, &data[pos]);
59fd03af27SMichael Olbrich 		put_unaligned_le16(sof, &data[pos+4]);
60fd03af27SMichael Olbrich 		pos += 6;
61fd03af27SMichael Olbrich 	}
62fd03af27SMichael Olbrich 
63fd03af27SMichael Olbrich 	data[0] = pos;
64fd03af27SMichael Olbrich 
65fd03af27SMichael Olbrich 	if (buf->bytesused - video->queue.buf_used <= len - pos)
6600a2430fSAndrzej Pietrasiewicz 		data[1] |= UVC_STREAM_EOF;
6700a2430fSAndrzej Pietrasiewicz 
68fd03af27SMichael Olbrich 	return pos;
6900a2430fSAndrzej Pietrasiewicz }
7000a2430fSAndrzej Pietrasiewicz 
7100a2430fSAndrzej Pietrasiewicz static int
uvc_video_encode_data(struct uvc_video * video,struct uvc_buffer * buf,u8 * data,int len)7200a2430fSAndrzej Pietrasiewicz uvc_video_encode_data(struct uvc_video *video, struct uvc_buffer *buf,
7300a2430fSAndrzej Pietrasiewicz 		u8 *data, int len)
7400a2430fSAndrzej Pietrasiewicz {
7500a2430fSAndrzej Pietrasiewicz 	struct uvc_video_queue *queue = &video->queue;
7600a2430fSAndrzej Pietrasiewicz 	unsigned int nbytes;
7700a2430fSAndrzej Pietrasiewicz 	void *mem;
7800a2430fSAndrzej Pietrasiewicz 
7900a2430fSAndrzej Pietrasiewicz 	/* Copy video data to the USB buffer. */
8000a2430fSAndrzej Pietrasiewicz 	mem = buf->mem + queue->buf_used;
8100a2430fSAndrzej Pietrasiewicz 	nbytes = min((unsigned int)len, buf->bytesused - queue->buf_used);
8200a2430fSAndrzej Pietrasiewicz 
8300a2430fSAndrzej Pietrasiewicz 	memcpy(data, mem, nbytes);
8400a2430fSAndrzej Pietrasiewicz 	queue->buf_used += nbytes;
8500a2430fSAndrzej Pietrasiewicz 
8600a2430fSAndrzej Pietrasiewicz 	return nbytes;
8700a2430fSAndrzej Pietrasiewicz }
8800a2430fSAndrzej Pietrasiewicz 
8900a2430fSAndrzej Pietrasiewicz static void
uvc_video_encode_bulk(struct usb_request * req,struct uvc_video * video,struct uvc_buffer * buf)9000a2430fSAndrzej Pietrasiewicz uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video,
9100a2430fSAndrzej Pietrasiewicz 		struct uvc_buffer *buf)
9200a2430fSAndrzej Pietrasiewicz {
9300a2430fSAndrzej Pietrasiewicz 	void *mem = req->buf;
940a0a2760SDan Vacura 	struct uvc_request *ureq = req->context;
9500a2430fSAndrzej Pietrasiewicz 	int len = video->req_size;
9600a2430fSAndrzej Pietrasiewicz 	int ret;
9700a2430fSAndrzej Pietrasiewicz 
9800a2430fSAndrzej Pietrasiewicz 	/* Add a header at the beginning of the payload. */
9900a2430fSAndrzej Pietrasiewicz 	if (video->payload_size == 0) {
10000a2430fSAndrzej Pietrasiewicz 		ret = uvc_video_encode_header(video, buf, mem, len);
10100a2430fSAndrzej Pietrasiewicz 		video->payload_size += ret;
10200a2430fSAndrzej Pietrasiewicz 		mem += ret;
10300a2430fSAndrzej Pietrasiewicz 		len -= ret;
10400a2430fSAndrzej Pietrasiewicz 	}
10500a2430fSAndrzej Pietrasiewicz 
10600a2430fSAndrzej Pietrasiewicz 	/* Process video data. */
10700a2430fSAndrzej Pietrasiewicz 	len = min((int)(video->max_payload_size - video->payload_size), len);
10800a2430fSAndrzej Pietrasiewicz 	ret = uvc_video_encode_data(video, buf, mem, len);
10900a2430fSAndrzej Pietrasiewicz 
11000a2430fSAndrzej Pietrasiewicz 	video->payload_size += ret;
11100a2430fSAndrzej Pietrasiewicz 	len -= ret;
11200a2430fSAndrzej Pietrasiewicz 
11300a2430fSAndrzej Pietrasiewicz 	req->length = video->req_size - len;
11400a2430fSAndrzej Pietrasiewicz 	req->zero = video->payload_size == video->max_payload_size;
11500a2430fSAndrzej Pietrasiewicz 
11600a2430fSAndrzej Pietrasiewicz 	if (buf->bytesused == video->queue.buf_used) {
11700a2430fSAndrzej Pietrasiewicz 		video->queue.buf_used = 0;
11800a2430fSAndrzej Pietrasiewicz 		buf->state = UVC_BUF_STATE_DONE;
1199b969f93SMichael Grzeschik 		list_del(&buf->queue);
12000a2430fSAndrzej Pietrasiewicz 		video->fid ^= UVC_STREAM_FID;
1210a0a2760SDan Vacura 		ureq->last_buf = buf;
12200a2430fSAndrzej Pietrasiewicz 
12300a2430fSAndrzej Pietrasiewicz 		video->payload_size = 0;
12400a2430fSAndrzej Pietrasiewicz 	}
12500a2430fSAndrzej Pietrasiewicz 
12600a2430fSAndrzej Pietrasiewicz 	if (video->payload_size == video->max_payload_size ||
1270a0a2760SDan Vacura 	    video->queue.flags & UVC_QUEUE_DROP_INCOMPLETE ||
12800a2430fSAndrzej Pietrasiewicz 	    buf->bytesused == video->queue.buf_used)
12900a2430fSAndrzej Pietrasiewicz 		video->payload_size = 0;
13000a2430fSAndrzej Pietrasiewicz }
13100a2430fSAndrzej Pietrasiewicz 
13200a2430fSAndrzej Pietrasiewicz static void
uvc_video_encode_isoc_sg(struct usb_request * req,struct uvc_video * video,struct uvc_buffer * buf)133e81e7f9aSMichael Grzeschik uvc_video_encode_isoc_sg(struct usb_request *req, struct uvc_video *video,
134e81e7f9aSMichael Grzeschik 		struct uvc_buffer *buf)
135e81e7f9aSMichael Grzeschik {
136e81e7f9aSMichael Grzeschik 	unsigned int pending = buf->bytesused - video->queue.buf_used;
137e81e7f9aSMichael Grzeschik 	struct uvc_request *ureq = req->context;
138e81e7f9aSMichael Grzeschik 	struct scatterlist *sg, *iter;
139e81e7f9aSMichael Grzeschik 	unsigned int len = video->req_size;
140e81e7f9aSMichael Grzeschik 	unsigned int sg_left, part = 0;
141e81e7f9aSMichael Grzeschik 	unsigned int i;
142f262ce66SMichael Grzeschik 	int header_len;
143e81e7f9aSMichael Grzeschik 
144e81e7f9aSMichael Grzeschik 	sg = ureq->sgt.sgl;
145e81e7f9aSMichael Grzeschik 	sg_init_table(sg, ureq->sgt.nents);
146e81e7f9aSMichael Grzeschik 
147e81e7f9aSMichael Grzeschik 	/* Init the header. */
148f262ce66SMichael Grzeschik 	header_len = uvc_video_encode_header(video, buf, ureq->header,
149e81e7f9aSMichael Grzeschik 				      video->req_size);
150f262ce66SMichael Grzeschik 	sg_set_buf(sg, ureq->header, header_len);
151f262ce66SMichael Grzeschik 	len -= header_len;
152e81e7f9aSMichael Grzeschik 
153e81e7f9aSMichael Grzeschik 	if (pending <= len)
154e81e7f9aSMichael Grzeschik 		len = pending;
155e81e7f9aSMichael Grzeschik 
156e81e7f9aSMichael Grzeschik 	req->length = (len == pending) ?
157f262ce66SMichael Grzeschik 		len + header_len : video->req_size;
158e81e7f9aSMichael Grzeschik 
159e81e7f9aSMichael Grzeschik 	/* Init the pending sgs with payload */
160e81e7f9aSMichael Grzeschik 	sg = sg_next(sg);
161e81e7f9aSMichael Grzeschik 
162e81e7f9aSMichael Grzeschik 	for_each_sg(sg, iter, ureq->sgt.nents - 1, i) {
163b57b08e6SJeff Vanhoof 		if (!len || !buf->sg || !buf->sg->length)
164e81e7f9aSMichael Grzeschik 			break;
165e81e7f9aSMichael Grzeschik 
166b57b08e6SJeff Vanhoof 		sg_left = buf->sg->length - buf->offset;
167e81e7f9aSMichael Grzeschik 		part = min_t(unsigned int, len, sg_left);
168e81e7f9aSMichael Grzeschik 
169e81e7f9aSMichael Grzeschik 		sg_set_page(iter, sg_page(buf->sg), part, buf->offset);
170e81e7f9aSMichael Grzeschik 
171e81e7f9aSMichael Grzeschik 		if (part == sg_left) {
172e81e7f9aSMichael Grzeschik 			buf->offset = 0;
173e81e7f9aSMichael Grzeschik 			buf->sg = sg_next(buf->sg);
174e81e7f9aSMichael Grzeschik 		} else {
175e81e7f9aSMichael Grzeschik 			buf->offset += part;
176e81e7f9aSMichael Grzeschik 		}
177e81e7f9aSMichael Grzeschik 		len -= part;
178e81e7f9aSMichael Grzeschik 	}
179e81e7f9aSMichael Grzeschik 
180e81e7f9aSMichael Grzeschik 	/* Assign the video data with header. */
181e81e7f9aSMichael Grzeschik 	req->buf = NULL;
182e81e7f9aSMichael Grzeschik 	req->sg	= ureq->sgt.sgl;
183e81e7f9aSMichael Grzeschik 	req->num_sgs = i + 1;
184e81e7f9aSMichael Grzeschik 
185e81e7f9aSMichael Grzeschik 	req->length -= len;
186f262ce66SMichael Grzeschik 	video->queue.buf_used += req->length - header_len;
187e81e7f9aSMichael Grzeschik 
1880a0a2760SDan Vacura 	if (buf->bytesused == video->queue.buf_used || !buf->sg ||
1890a0a2760SDan Vacura 			video->queue.flags & UVC_QUEUE_DROP_INCOMPLETE) {
190e81e7f9aSMichael Grzeschik 		video->queue.buf_used = 0;
191e81e7f9aSMichael Grzeschik 		buf->state = UVC_BUF_STATE_DONE;
192e81e7f9aSMichael Grzeschik 		buf->offset = 0;
1939b969f93SMichael Grzeschik 		list_del(&buf->queue);
194e81e7f9aSMichael Grzeschik 		video->fid ^= UVC_STREAM_FID;
1959b969f93SMichael Grzeschik 		ureq->last_buf = buf;
196e81e7f9aSMichael Grzeschik 	}
197e81e7f9aSMichael Grzeschik }
198e81e7f9aSMichael Grzeschik 
199e81e7f9aSMichael Grzeschik static void
uvc_video_encode_isoc(struct usb_request * req,struct uvc_video * video,struct uvc_buffer * buf)20000a2430fSAndrzej Pietrasiewicz uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video,
20100a2430fSAndrzej Pietrasiewicz 		struct uvc_buffer *buf)
20200a2430fSAndrzej Pietrasiewicz {
20300a2430fSAndrzej Pietrasiewicz 	void *mem = req->buf;
2040a0a2760SDan Vacura 	struct uvc_request *ureq = req->context;
20500a2430fSAndrzej Pietrasiewicz 	int len = video->req_size;
20600a2430fSAndrzej Pietrasiewicz 	int ret;
20700a2430fSAndrzej Pietrasiewicz 
20800a2430fSAndrzej Pietrasiewicz 	/* Add the header. */
20900a2430fSAndrzej Pietrasiewicz 	ret = uvc_video_encode_header(video, buf, mem, len);
21000a2430fSAndrzej Pietrasiewicz 	mem += ret;
21100a2430fSAndrzej Pietrasiewicz 	len -= ret;
21200a2430fSAndrzej Pietrasiewicz 
21300a2430fSAndrzej Pietrasiewicz 	/* Process video data. */
21400a2430fSAndrzej Pietrasiewicz 	ret = uvc_video_encode_data(video, buf, mem, len);
21500a2430fSAndrzej Pietrasiewicz 	len -= ret;
21600a2430fSAndrzej Pietrasiewicz 
21700a2430fSAndrzej Pietrasiewicz 	req->length = video->req_size - len;
21800a2430fSAndrzej Pietrasiewicz 
2190a0a2760SDan Vacura 	if (buf->bytesused == video->queue.buf_used ||
2200a0a2760SDan Vacura 			video->queue.flags & UVC_QUEUE_DROP_INCOMPLETE) {
22100a2430fSAndrzej Pietrasiewicz 		video->queue.buf_used = 0;
22200a2430fSAndrzej Pietrasiewicz 		buf->state = UVC_BUF_STATE_DONE;
2239b969f93SMichael Grzeschik 		list_del(&buf->queue);
22400a2430fSAndrzej Pietrasiewicz 		video->fid ^= UVC_STREAM_FID;
2250a0a2760SDan Vacura 		ureq->last_buf = buf;
22600a2430fSAndrzej Pietrasiewicz 	}
22700a2430fSAndrzej Pietrasiewicz }
22800a2430fSAndrzej Pietrasiewicz 
22900a2430fSAndrzej Pietrasiewicz /* --------------------------------------------------------------------------
23000a2430fSAndrzej Pietrasiewicz  * Request handling
23100a2430fSAndrzej Pietrasiewicz  */
23200a2430fSAndrzej Pietrasiewicz 
uvcg_video_ep_queue(struct uvc_video * video,struct usb_request * req)2339d1ff5dcSLaurent Pinchart static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req)
2349d1ff5dcSLaurent Pinchart {
2359d1ff5dcSLaurent Pinchart 	int ret;
2369d1ff5dcSLaurent Pinchart 
2379d1ff5dcSLaurent Pinchart 	ret = usb_ep_queue(video->ep, req, GFP_ATOMIC);
2389d1ff5dcSLaurent Pinchart 	if (ret < 0) {
239dc0f755bSLaurent Pinchart 		uvcg_err(&video->uvc->func, "Failed to queue request (%d).\n",
240dc0f755bSLaurent Pinchart 			 ret);
241dc0f755bSLaurent Pinchart 
24238db3716SMichael Grzeschik 		/* If the endpoint is disabled the descriptor may be NULL. */
24338db3716SMichael Grzeschik 		if (video->ep->desc) {
2448dbf9c7aSLaurent Pinchart 			/* Isochronous endpoints can't be halted. */
2458dbf9c7aSLaurent Pinchart 			if (usb_endpoint_xfer_bulk(video->ep->desc))
2469d1ff5dcSLaurent Pinchart 				usb_ep_set_halt(video->ep);
2479d1ff5dcSLaurent Pinchart 		}
24838db3716SMichael Grzeschik 	}
2499d1ff5dcSLaurent Pinchart 
2509d1ff5dcSLaurent Pinchart 	return ret;
2519d1ff5dcSLaurent Pinchart }
2529d1ff5dcSLaurent Pinchart 
25300a2430fSAndrzej Pietrasiewicz static void
uvc_video_complete(struct usb_ep * ep,struct usb_request * req)25400a2430fSAndrzej Pietrasiewicz uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
25500a2430fSAndrzej Pietrasiewicz {
2569973772dSMichael Grzeschik 	struct uvc_request *ureq = req->context;
2579973772dSMichael Grzeschik 	struct uvc_video *video = ureq->video;
25800a2430fSAndrzej Pietrasiewicz 	struct uvc_video_queue *queue = &video->queue;
2595fc49d8bSMichael Grzeschik 	struct uvc_device *uvc = video->uvc;
26000a2430fSAndrzej Pietrasiewicz 	unsigned long flags;
26100a2430fSAndrzej Pietrasiewicz 
26200a2430fSAndrzej Pietrasiewicz 	switch (req->status) {
26300a2430fSAndrzej Pietrasiewicz 	case 0:
26400a2430fSAndrzej Pietrasiewicz 		break;
26500a2430fSAndrzej Pietrasiewicz 
2660a0a2760SDan Vacura 	case -EXDEV:
2670a0a2760SDan Vacura 		uvcg_dbg(&video->uvc->func, "VS request missed xfer.\n");
2680a0a2760SDan Vacura 		queue->flags |= UVC_QUEUE_DROP_INCOMPLETE;
2690a0a2760SDan Vacura 		break;
2700a0a2760SDan Vacura 
27100a2430fSAndrzej Pietrasiewicz 	case -ESHUTDOWN:	/* disconnect from host. */
272dc0f755bSLaurent Pinchart 		uvcg_dbg(&video->uvc->func, "VS request cancelled.\n");
2737ea95b11SAndrzej Pietrasiewicz 		uvcg_queue_cancel(queue, 1);
27443cd0023SMichael Grzeschik 		break;
27500a2430fSAndrzej Pietrasiewicz 
27600a2430fSAndrzej Pietrasiewicz 	default:
277a725d0f6SMichael Grzeschik 		uvcg_warn(&video->uvc->func,
278dc0f755bSLaurent Pinchart 			  "VS request completed with status %d.\n",
27900a2430fSAndrzej Pietrasiewicz 			  req->status);
2807ea95b11SAndrzej Pietrasiewicz 		uvcg_queue_cancel(queue, 0);
28100a2430fSAndrzej Pietrasiewicz 	}
28200a2430fSAndrzej Pietrasiewicz 
2839b969f93SMichael Grzeschik 	if (ureq->last_buf) {
2849b969f93SMichael Grzeschik 		uvcg_complete_buffer(&video->queue, ureq->last_buf);
2859b969f93SMichael Grzeschik 		ureq->last_buf = NULL;
2869b969f93SMichael Grzeschik 	}
2879b969f93SMichael Grzeschik 
28800a2430fSAndrzej Pietrasiewicz 	spin_lock_irqsave(&video->req_lock, flags);
28900a2430fSAndrzej Pietrasiewicz 	list_add_tail(&req->list, &video->req_free);
29000a2430fSAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&video->req_lock, flags);
29143cd0023SMichael Grzeschik 
2925fc49d8bSMichael Grzeschik 	if (uvc->state == UVC_STATE_STREAMING)
2939b91a652SMichael Grzeschik 		queue_work(video->async_wq, &video->pump);
29400a2430fSAndrzej Pietrasiewicz }
29500a2430fSAndrzej Pietrasiewicz 
29600a2430fSAndrzej Pietrasiewicz static int
uvc_video_free_requests(struct uvc_video * video)29700a2430fSAndrzej Pietrasiewicz uvc_video_free_requests(struct uvc_video *video)
29800a2430fSAndrzej Pietrasiewicz {
29900a2430fSAndrzej Pietrasiewicz 	unsigned int i;
30000a2430fSAndrzej Pietrasiewicz 
3019973772dSMichael Grzeschik 	if (video->ureq) {
3029973772dSMichael Grzeschik 		for (i = 0; i < video->uvc_num_requests; ++i) {
303e81e7f9aSMichael Grzeschik 			sg_free_table(&video->ureq[i].sgt);
304e81e7f9aSMichael Grzeschik 
3059973772dSMichael Grzeschik 			if (video->ureq[i].req) {
3069973772dSMichael Grzeschik 				usb_ep_free_request(video->ep, video->ureq[i].req);
3079973772dSMichael Grzeschik 				video->ureq[i].req = NULL;
30800a2430fSAndrzej Pietrasiewicz 			}
30900a2430fSAndrzej Pietrasiewicz 
3109973772dSMichael Grzeschik 			if (video->ureq[i].req_buffer) {
3119973772dSMichael Grzeschik 				kfree(video->ureq[i].req_buffer);
3129973772dSMichael Grzeschik 				video->ureq[i].req_buffer = NULL;
31300a2430fSAndrzej Pietrasiewicz 			}
31400a2430fSAndrzej Pietrasiewicz 		}
31500a2430fSAndrzej Pietrasiewicz 
3169973772dSMichael Grzeschik 		kfree(video->ureq);
3179973772dSMichael Grzeschik 		video->ureq = NULL;
3189973772dSMichael Grzeschik 	}
3199973772dSMichael Grzeschik 
32000a2430fSAndrzej Pietrasiewicz 	INIT_LIST_HEAD(&video->req_free);
32100a2430fSAndrzej Pietrasiewicz 	video->req_size = 0;
32200a2430fSAndrzej Pietrasiewicz 	return 0;
32300a2430fSAndrzej Pietrasiewicz }
32400a2430fSAndrzej Pietrasiewicz 
32500a2430fSAndrzej Pietrasiewicz static int
uvc_video_alloc_requests(struct uvc_video * video)32600a2430fSAndrzej Pietrasiewicz uvc_video_alloc_requests(struct uvc_video *video)
32700a2430fSAndrzej Pietrasiewicz {
32800a2430fSAndrzej Pietrasiewicz 	unsigned int req_size;
32900a2430fSAndrzej Pietrasiewicz 	unsigned int i;
33000a2430fSAndrzej Pietrasiewicz 	int ret = -ENOMEM;
33100a2430fSAndrzej Pietrasiewicz 
33200a2430fSAndrzej Pietrasiewicz 	BUG_ON(video->req_size);
33300a2430fSAndrzej Pietrasiewicz 
33400a2430fSAndrzej Pietrasiewicz 	req_size = video->ep->maxpacket
33500a2430fSAndrzej Pietrasiewicz 		 * max_t(unsigned int, video->ep->maxburst, 1)
336eaa496ffSFelipe Balbi 		 * (video->ep->mult);
33700a2430fSAndrzej Pietrasiewicz 
3389973772dSMichael Grzeschik 	video->ureq = kcalloc(video->uvc_num_requests, sizeof(struct uvc_request), GFP_KERNEL);
3399973772dSMichael Grzeschik 	if (video->ureq == NULL)
3409973772dSMichael Grzeschik 		return -ENOMEM;
3419973772dSMichael Grzeschik 
3429973772dSMichael Grzeschik 	for (i = 0; i < video->uvc_num_requests; ++i) {
3439973772dSMichael Grzeschik 		video->ureq[i].req_buffer = kmalloc(req_size, GFP_KERNEL);
3449973772dSMichael Grzeschik 		if (video->ureq[i].req_buffer == NULL)
34500a2430fSAndrzej Pietrasiewicz 			goto error;
34600a2430fSAndrzej Pietrasiewicz 
3479973772dSMichael Grzeschik 		video->ureq[i].req = usb_ep_alloc_request(video->ep, GFP_KERNEL);
3489973772dSMichael Grzeschik 		if (video->ureq[i].req == NULL)
34900a2430fSAndrzej Pietrasiewicz 			goto error;
35000a2430fSAndrzej Pietrasiewicz 
3519973772dSMichael Grzeschik 		video->ureq[i].req->buf = video->ureq[i].req_buffer;
3529973772dSMichael Grzeschik 		video->ureq[i].req->length = 0;
3539973772dSMichael Grzeschik 		video->ureq[i].req->complete = uvc_video_complete;
3549973772dSMichael Grzeschik 		video->ureq[i].req->context = &video->ureq[i];
3559973772dSMichael Grzeschik 		video->ureq[i].video = video;
3569b969f93SMichael Grzeschik 		video->ureq[i].last_buf = NULL;
35700a2430fSAndrzej Pietrasiewicz 
3589973772dSMichael Grzeschik 		list_add_tail(&video->ureq[i].req->list, &video->req_free);
359e81e7f9aSMichael Grzeschik 		/* req_size/PAGE_SIZE + 1 for overruns and + 1 for header */
360e81e7f9aSMichael Grzeschik 		sg_alloc_table(&video->ureq[i].sgt,
361859c675dSMichael Grzeschik 			       DIV_ROUND_UP(req_size - UVCG_REQUEST_HEADER_LEN,
362859c675dSMichael Grzeschik 					    PAGE_SIZE) + 2, GFP_KERNEL);
36300a2430fSAndrzej Pietrasiewicz 	}
36400a2430fSAndrzej Pietrasiewicz 
36500a2430fSAndrzej Pietrasiewicz 	video->req_size = req_size;
36600a2430fSAndrzej Pietrasiewicz 
36700a2430fSAndrzej Pietrasiewicz 	return 0;
36800a2430fSAndrzej Pietrasiewicz 
36900a2430fSAndrzej Pietrasiewicz error:
37000a2430fSAndrzej Pietrasiewicz 	uvc_video_free_requests(video);
37100a2430fSAndrzej Pietrasiewicz 	return ret;
37200a2430fSAndrzej Pietrasiewicz }
37300a2430fSAndrzej Pietrasiewicz 
37400a2430fSAndrzej Pietrasiewicz /* --------------------------------------------------------------------------
37500a2430fSAndrzej Pietrasiewicz  * Video streaming
37600a2430fSAndrzej Pietrasiewicz  */
37700a2430fSAndrzej Pietrasiewicz 
37800a2430fSAndrzej Pietrasiewicz /*
3797ea95b11SAndrzej Pietrasiewicz  * uvcg_video_pump - Pump video data into the USB requests
38000a2430fSAndrzej Pietrasiewicz  *
38100a2430fSAndrzej Pietrasiewicz  * This function fills the available USB requests (listed in req_free) with
38200a2430fSAndrzej Pietrasiewicz  * video data from the queued buffers.
38300a2430fSAndrzej Pietrasiewicz  */
uvcg_video_pump(struct work_struct * work)38443cd0023SMichael Grzeschik static void uvcg_video_pump(struct work_struct *work)
38500a2430fSAndrzej Pietrasiewicz {
38643cd0023SMichael Grzeschik 	struct uvc_video *video = container_of(work, struct uvc_video, pump);
387bd52b813SMichael Grzeschik 	struct uvc_video_queue *queue = &video->queue;
3885ae8a354SAvichal Rakesh 	/* video->max_payload_size is only set when using bulk transfer */
3895ae8a354SAvichal Rakesh 	bool is_bulk = video->max_payload_size;
390f9897ec0SMichael Grzeschik 	struct usb_request *req = NULL;
39100a2430fSAndrzej Pietrasiewicz 	struct uvc_buffer *buf;
39200a2430fSAndrzej Pietrasiewicz 	unsigned long flags;
3935ae8a354SAvichal Rakesh 	bool buf_done;
39400a2430fSAndrzej Pietrasiewicz 	int ret;
39500a2430fSAndrzej Pietrasiewicz 
396f9897ec0SMichael Grzeschik 	while (video->ep->enabled) {
397c5d337a3SLaurent Pinchart 		/*
398c5d337a3SLaurent Pinchart 		 * Retrieve the first available USB request, protected by the
39900a2430fSAndrzej Pietrasiewicz 		 * request lock.
40000a2430fSAndrzej Pietrasiewicz 		 */
40100a2430fSAndrzej Pietrasiewicz 		spin_lock_irqsave(&video->req_lock, flags);
40200a2430fSAndrzej Pietrasiewicz 		if (list_empty(&video->req_free)) {
40300a2430fSAndrzej Pietrasiewicz 			spin_unlock_irqrestore(&video->req_lock, flags);
40443cd0023SMichael Grzeschik 			return;
40500a2430fSAndrzej Pietrasiewicz 		}
40600a2430fSAndrzej Pietrasiewicz 		req = list_first_entry(&video->req_free, struct usb_request,
40700a2430fSAndrzej Pietrasiewicz 					list);
40800a2430fSAndrzej Pietrasiewicz 		list_del(&req->list);
40900a2430fSAndrzej Pietrasiewicz 		spin_unlock_irqrestore(&video->req_lock, flags);
41000a2430fSAndrzej Pietrasiewicz 
411c5d337a3SLaurent Pinchart 		/*
412c5d337a3SLaurent Pinchart 		 * Retrieve the first available video buffer and fill the
41300a2430fSAndrzej Pietrasiewicz 		 * request, protected by the video queue irqlock.
41400a2430fSAndrzej Pietrasiewicz 		 */
4156dd5b021SLaurent Pinchart 		spin_lock_irqsave(&queue->irqlock, flags);
4166dd5b021SLaurent Pinchart 		buf = uvcg_queue_head(queue);
417c3ff12a9SAvichal Rakesh 
418c3ff12a9SAvichal Rakesh 		if (buf != NULL) {
419c3ff12a9SAvichal Rakesh 			video->encode(req, video, buf);
4205ae8a354SAvichal Rakesh 			buf_done = buf->state == UVC_BUF_STATE_DONE;
421c3ff12a9SAvichal Rakesh 		} else if (!(queue->flags & UVC_QUEUE_DISCONNECTED) && !is_bulk) {
422c3ff12a9SAvichal Rakesh 			/*
423c3ff12a9SAvichal Rakesh 			 * No video buffer available; the queue is still connected and
4245ae8a354SAvichal Rakesh 			 * we're transferring over ISOC. Queue a 0 length request to
425c3ff12a9SAvichal Rakesh 			 * prevent missed ISOC transfers.
426c3ff12a9SAvichal Rakesh 			 */
427c3ff12a9SAvichal Rakesh 			req->length = 0;
4285ae8a354SAvichal Rakesh 			buf_done = false;
429c3ff12a9SAvichal Rakesh 		} else {
430c3ff12a9SAvichal Rakesh 			/*
4315ae8a354SAvichal Rakesh 			 * Either the queue has been disconnected or no video buffer
4325ae8a354SAvichal Rakesh 			 * available for bulk transfer. Either way, stop processing
433c3ff12a9SAvichal Rakesh 			 * further.
434c3ff12a9SAvichal Rakesh 			 */
4356dd5b021SLaurent Pinchart 			spin_unlock_irqrestore(&queue->irqlock, flags);
43600a2430fSAndrzej Pietrasiewicz 			break;
43700a2430fSAndrzej Pietrasiewicz 		}
43800a2430fSAndrzej Pietrasiewicz 
439c5d337a3SLaurent Pinchart 		/*
4405ae8a354SAvichal Rakesh 		 * With USB3 handling more requests at a higher speed, we can't
4415ae8a354SAvichal Rakesh 		 * afford to generate an interrupt for every request. Decide to
4425ae8a354SAvichal Rakesh 		 * interrupt:
4435ae8a354SAvichal Rakesh 		 *
4445ae8a354SAvichal Rakesh 		 * - When no more requests are available in the free queue, as
4455ae8a354SAvichal Rakesh 		 *   this may be our last chance to refill the endpoint's
4465ae8a354SAvichal Rakesh 		 *   request queue.
4475ae8a354SAvichal Rakesh 		 *
4485ae8a354SAvichal Rakesh 		 * - When this is request is the last request for the video
4495ae8a354SAvichal Rakesh 		 *   buffer, as we want to start sending the next video buffer
4505ae8a354SAvichal Rakesh 		 *   ASAP in case it doesn't get started already in the next
4515ae8a354SAvichal Rakesh 		 *   iteration of this loop.
4525ae8a354SAvichal Rakesh 		 *
4535ae8a354SAvichal Rakesh 		 * - Four times over the length of the requests queue (as
4545ae8a354SAvichal Rakesh 		 *   indicated by video->uvc_num_requests), as a trade-off
4555ae8a354SAvichal Rakesh 		 *   between latency and interrupt load.
456c5d337a3SLaurent Pinchart 		 */
4575ae8a354SAvichal Rakesh 		if (list_empty(&video->req_free) || buf_done ||
458fc78941dSMichael Grzeschik 		    !(video->req_int_count %
459fc78941dSMichael Grzeschik 		       DIV_ROUND_UP(video->uvc_num_requests, 4))) {
460fc78941dSMichael Grzeschik 			video->req_int_count = 0;
461fc78941dSMichael Grzeschik 			req->no_interrupt = 0;
462fc78941dSMichael Grzeschik 		} else {
463fc78941dSMichael Grzeschik 			req->no_interrupt = 1;
464fc78941dSMichael Grzeschik 		}
465fc78941dSMichael Grzeschik 
46600a2430fSAndrzej Pietrasiewicz 		/* Queue the USB request */
4679d1ff5dcSLaurent Pinchart 		ret = uvcg_video_ep_queue(video, req);
4686dd5b021SLaurent Pinchart 		spin_unlock_irqrestore(&queue->irqlock, flags);
4699d1ff5dcSLaurent Pinchart 
4709d1ff5dcSLaurent Pinchart 		if (ret < 0) {
4717ea95b11SAndrzej Pietrasiewicz 			uvcg_queue_cancel(queue, 0);
47200a2430fSAndrzej Pietrasiewicz 			break;
47300a2430fSAndrzej Pietrasiewicz 		}
47496163f83SDan Vacura 
47596163f83SDan Vacura 		/* Endpoint now owns the request */
47696163f83SDan Vacura 		req = NULL;
477fc78941dSMichael Grzeschik 		video->req_int_count++;
47800a2430fSAndrzej Pietrasiewicz 	}
47900a2430fSAndrzej Pietrasiewicz 
480f9897ec0SMichael Grzeschik 	if (!req)
481f9897ec0SMichael Grzeschik 		return;
482f9897ec0SMichael Grzeschik 
48300a2430fSAndrzej Pietrasiewicz 	spin_lock_irqsave(&video->req_lock, flags);
48400a2430fSAndrzej Pietrasiewicz 	list_add_tail(&req->list, &video->req_free);
48500a2430fSAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&video->req_lock, flags);
48643cd0023SMichael Grzeschik 	return;
48700a2430fSAndrzej Pietrasiewicz }
48800a2430fSAndrzej Pietrasiewicz 
48900a2430fSAndrzej Pietrasiewicz /*
49000a2430fSAndrzej Pietrasiewicz  * Enable or disable the video stream.
49100a2430fSAndrzej Pietrasiewicz  */
uvcg_video_enable(struct uvc_video * video,int enable)4923a83c16eSAndrzej Pietrasiewicz int uvcg_video_enable(struct uvc_video *video, int enable)
49300a2430fSAndrzej Pietrasiewicz {
49400a2430fSAndrzej Pietrasiewicz 	unsigned int i;
49500a2430fSAndrzej Pietrasiewicz 	int ret;
49600a2430fSAndrzej Pietrasiewicz 
49700a2430fSAndrzej Pietrasiewicz 	if (video->ep == NULL) {
498dc0f755bSLaurent Pinchart 		uvcg_info(&video->uvc->func,
499dc0f755bSLaurent Pinchart 			  "Video enable failed, device is uninitialized.\n");
50000a2430fSAndrzej Pietrasiewicz 		return -ENODEV;
50100a2430fSAndrzej Pietrasiewicz 	}
50200a2430fSAndrzej Pietrasiewicz 
50300a2430fSAndrzej Pietrasiewicz 	if (!enable) {
50443cd0023SMichael Grzeschik 		cancel_work_sync(&video->pump);
50543cd0023SMichael Grzeschik 		uvcg_queue_cancel(&video->queue, 0);
50643cd0023SMichael Grzeschik 
5079973772dSMichael Grzeschik 		for (i = 0; i < video->uvc_num_requests; ++i)
5089973772dSMichael Grzeschik 			if (video->ureq && video->ureq[i].req)
5099973772dSMichael Grzeschik 				usb_ep_dequeue(video->ep, video->ureq[i].req);
51000a2430fSAndrzej Pietrasiewicz 
51100a2430fSAndrzej Pietrasiewicz 		uvc_video_free_requests(video);
5127ea95b11SAndrzej Pietrasiewicz 		uvcg_queue_enable(&video->queue, 0);
51300a2430fSAndrzej Pietrasiewicz 		return 0;
51400a2430fSAndrzej Pietrasiewicz 	}
51500a2430fSAndrzej Pietrasiewicz 
5167ea95b11SAndrzej Pietrasiewicz 	if ((ret = uvcg_queue_enable(&video->queue, 1)) < 0)
51700a2430fSAndrzej Pietrasiewicz 		return ret;
51800a2430fSAndrzej Pietrasiewicz 
51900a2430fSAndrzej Pietrasiewicz 	if ((ret = uvc_video_alloc_requests(video)) < 0)
52000a2430fSAndrzej Pietrasiewicz 		return ret;
52100a2430fSAndrzej Pietrasiewicz 
52200a2430fSAndrzej Pietrasiewicz 	if (video->max_payload_size) {
52300a2430fSAndrzej Pietrasiewicz 		video->encode = uvc_video_encode_bulk;
52400a2430fSAndrzej Pietrasiewicz 		video->payload_size = 0;
52588c8e05eSGreg Kroah-Hartman 	} else
52688c8e05eSGreg Kroah-Hartman 		video->encode = video->queue.use_sg ?
527e81e7f9aSMichael Grzeschik 			uvc_video_encode_isoc_sg : uvc_video_encode_isoc;
52800a2430fSAndrzej Pietrasiewicz 
529fc78941dSMichael Grzeschik 	video->req_int_count = 0;
530fc78941dSMichael Grzeschik 
5319b91a652SMichael Grzeschik 	queue_work(video->async_wq, &video->pump);
53243cd0023SMichael Grzeschik 
53343cd0023SMichael Grzeschik 	return ret;
53400a2430fSAndrzej Pietrasiewicz }
53500a2430fSAndrzej Pietrasiewicz 
53600a2430fSAndrzej Pietrasiewicz /*
53700a2430fSAndrzej Pietrasiewicz  * Initialize the UVC video stream.
53800a2430fSAndrzej Pietrasiewicz  */
uvcg_video_init(struct uvc_video * video,struct uvc_device * uvc)539dc0f755bSLaurent Pinchart int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc)
54000a2430fSAndrzej Pietrasiewicz {
54100a2430fSAndrzej Pietrasiewicz 	INIT_LIST_HEAD(&video->req_free);
54200a2430fSAndrzej Pietrasiewicz 	spin_lock_init(&video->req_lock);
54343cd0023SMichael Grzeschik 	INIT_WORK(&video->pump, uvcg_video_pump);
54400a2430fSAndrzej Pietrasiewicz 
5459b91a652SMichael Grzeschik 	/* Allocate a work queue for asynchronous video pump handler. */
5469b91a652SMichael Grzeschik 	video->async_wq = alloc_workqueue("uvcgadget", WQ_UNBOUND | WQ_HIGHPRI, 0);
5479b91a652SMichael Grzeschik 	if (!video->async_wq)
5489b91a652SMichael Grzeschik 		return -EINVAL;
5499b91a652SMichael Grzeschik 
550dc0f755bSLaurent Pinchart 	video->uvc = uvc;
55100a2430fSAndrzej Pietrasiewicz 	video->fcc = V4L2_PIX_FMT_YUYV;
55200a2430fSAndrzej Pietrasiewicz 	video->bpp = 16;
55300a2430fSAndrzej Pietrasiewicz 	video->width = 320;
55400a2430fSAndrzej Pietrasiewicz 	video->height = 240;
55500a2430fSAndrzej Pietrasiewicz 	video->imagesize = 320 * 240 * 2;
55600a2430fSAndrzej Pietrasiewicz 
55700a2430fSAndrzej Pietrasiewicz 	/* Initialize the video buffers queue. */
558e81e7f9aSMichael Grzeschik 	uvcg_queue_init(&video->queue, uvc->v4l2_dev.dev->parent,
559e81e7f9aSMichael Grzeschik 			V4L2_BUF_TYPE_VIDEO_OUTPUT, &video->mutex);
56000a2430fSAndrzej Pietrasiewicz 	return 0;
56100a2430fSAndrzej Pietrasiewicz }
562