xref: /linux/drivers/media/usb/uvc/uvc_isight.c (revision ec63e2a4897075e427c121d863bd89c44578094f)
1 /*
2  *      uvc_isight.c  --  USB Video Class driver - iSight support
3  *
4  *	Copyright (C) 2006-2007
5  *		Ivan N. Zlatev <contact@i-nz.net>
6  *	Copyright (C) 2008-2009
7  *		Laurent Pinchart <laurent.pinchart@ideasonboard.com>
8  *
9  *      This program is free software; you can redistribute it and/or modify
10  *      it under the terms of the GNU General Public License as published by
11  *      the Free Software Foundation; either version 2 of the License, or
12  *      (at your option) any later version.
13  *
14  */
15 
16 #include <linux/usb.h>
17 #include <linux/kernel.h>
18 #include <linux/mm.h>
19 
20 #include "uvcvideo.h"
21 
22 /* Built-in iSight webcams implements most of UVC 1.0 except a
23  * different packet format. Instead of sending a header at the
24  * beginning of each isochronous transfer payload, the webcam sends a
25  * single header per image (on its own in a packet), followed by
26  * packets containing data only.
27  *
28  * Offset   Size (bytes)	Description
29  * ------------------------------------------------------------------
30  * 0x00	1	Header length
31  * 0x01	1	Flags (UVC-compliant)
32  * 0x02	4	Always equal to '11223344'
33  * 0x06	8	Always equal to 'deadbeefdeadface'
34  * 0x0e	16	Unknown
35  *
36  * The header can be prefixed by an optional, unknown-purpose byte.
37  */
38 
39 static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf,
40 		const u8 *data, unsigned int len)
41 {
42 	static const u8 hdr[] = {
43 		0x11, 0x22, 0x33, 0x44,
44 		0xde, 0xad, 0xbe, 0xef,
45 		0xde, 0xad, 0xfa, 0xce
46 	};
47 
48 	unsigned int maxlen, nbytes;
49 	u8 *mem;
50 	int is_header = 0;
51 
52 	if (buf == NULL)
53 		return 0;
54 
55 	if ((len >= 14 && memcmp(&data[2], hdr, 12) == 0) ||
56 	    (len >= 15 && memcmp(&data[3], hdr, 12) == 0)) {
57 		uvc_trace(UVC_TRACE_FRAME, "iSight header found\n");
58 		is_header = 1;
59 	}
60 
61 	/* Synchronize to the input stream by waiting for a header packet. */
62 	if (buf->state != UVC_BUF_STATE_ACTIVE) {
63 		if (!is_header) {
64 			uvc_trace(UVC_TRACE_FRAME, "Dropping packet (out of "
65 				  "sync).\n");
66 			return 0;
67 		}
68 
69 		buf->state = UVC_BUF_STATE_ACTIVE;
70 	}
71 
72 	/* Mark the buffer as done if we're at the beginning of a new frame.
73 	 *
74 	 * Empty buffers (bytesused == 0) don't trigger end of frame detection
75 	 * as it doesn't make sense to return an empty buffer.
76 	 */
77 	if (is_header && buf->bytesused != 0) {
78 		buf->state = UVC_BUF_STATE_DONE;
79 		return -EAGAIN;
80 	}
81 
82 	/* Copy the video data to the buffer. Skip header packets, as they
83 	 * contain no data.
84 	 */
85 	if (!is_header) {
86 		maxlen = buf->length - buf->bytesused;
87 		mem = buf->mem + buf->bytesused;
88 		nbytes = min(len, maxlen);
89 		memcpy(mem, data, nbytes);
90 		buf->bytesused += nbytes;
91 
92 		if (len > maxlen || buf->bytesused == buf->length) {
93 			uvc_trace(UVC_TRACE_FRAME, "Frame complete "
94 				  "(overflow).\n");
95 			buf->state = UVC_BUF_STATE_DONE;
96 		}
97 	}
98 
99 	return 0;
100 }
101 
102 void uvc_video_decode_isight(struct uvc_urb *uvc_urb, struct uvc_buffer *buf,
103 			struct uvc_buffer *meta_buf)
104 {
105 	struct urb *urb = uvc_urb->urb;
106 	struct uvc_streaming *stream = uvc_urb->stream;
107 	int ret, i;
108 
109 	for (i = 0; i < urb->number_of_packets; ++i) {
110 		if (urb->iso_frame_desc[i].status < 0) {
111 			uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame "
112 				  "lost (%d).\n",
113 				  urb->iso_frame_desc[i].status);
114 		}
115 
116 		/* Decode the payload packet.
117 		 * uvc_video_decode is entered twice when a frame transition
118 		 * has been detected because the end of frame can only be
119 		 * reliably detected when the first packet of the new frame
120 		 * is processed. The first pass detects the transition and
121 		 * closes the previous frame's buffer, the second pass
122 		 * processes the data of the first payload of the new frame.
123 		 */
124 		do {
125 			ret = isight_decode(&stream->queue, buf,
126 					urb->transfer_buffer +
127 					urb->iso_frame_desc[i].offset,
128 					urb->iso_frame_desc[i].actual_length);
129 
130 			if (buf == NULL)
131 				break;
132 
133 			if (buf->state == UVC_BUF_STATE_DONE ||
134 			    buf->state == UVC_BUF_STATE_ERROR)
135 				buf = uvc_queue_next_buffer(&stream->queue,
136 							buf);
137 		} while (ret == -EAGAIN);
138 	}
139 }
140