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