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