Laurent Pinchart | c0efd23 | 2008-06-30 15:04:50 -0300 | [diff] [blame] | 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> |
Laurent Pinchart | 2c2d264 | 2009-01-03 19:12:40 -0300 | [diff] [blame] | 6 | * Copyright (C) 2008-2009 |
Laurent Pinchart | 11fc5ba | 2010-09-20 06:10:10 -0300 | [diff] [blame] | 7 | * Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
Laurent Pinchart | c0efd23 | 2008-06-30 15:04:50 -0300 | [diff] [blame] | 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->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->buf.length - buf->buf.bytesused; |
| 87 | mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused; |
| 88 | nbytes = min(len, maxlen); |
| 89 | memcpy(mem, data, nbytes); |
| 90 | buf->buf.bytesused += nbytes; |
| 91 | |
| 92 | if (len > maxlen || buf->buf.bytesused == buf->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 | |
Laurent Pinchart | 35f02a6 | 2009-06-28 08:37:50 -0300 | [diff] [blame] | 102 | void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream, |
Laurent Pinchart | c0efd23 | 2008-06-30 15:04:50 -0300 | [diff] [blame] | 103 | struct uvc_buffer *buf) |
| 104 | { |
| 105 | int ret, i; |
| 106 | |
| 107 | for (i = 0; i < urb->number_of_packets; ++i) { |
| 108 | if (urb->iso_frame_desc[i].status < 0) { |
| 109 | uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame " |
| 110 | "lost (%d).\n", |
| 111 | urb->iso_frame_desc[i].status); |
| 112 | } |
| 113 | |
| 114 | /* Decode the payload packet. |
| 115 | * uvc_video_decode is entered twice when a frame transition |
| 116 | * has been detected because the end of frame can only be |
| 117 | * reliably detected when the first packet of the new frame |
| 118 | * is processed. The first pass detects the transition and |
| 119 | * closes the previous frame's buffer, the second pass |
| 120 | * processes the data of the first payload of the new frame. |
| 121 | */ |
| 122 | do { |
Laurent Pinchart | 35f02a6 | 2009-06-28 08:37:50 -0300 | [diff] [blame] | 123 | ret = isight_decode(&stream->queue, buf, |
Laurent Pinchart | c0efd23 | 2008-06-30 15:04:50 -0300 | [diff] [blame] | 124 | urb->transfer_buffer + |
| 125 | urb->iso_frame_desc[i].offset, |
| 126 | urb->iso_frame_desc[i].actual_length); |
| 127 | |
| 128 | if (buf == NULL) |
| 129 | break; |
| 130 | |
| 131 | if (buf->state == UVC_BUF_STATE_DONE || |
| 132 | buf->state == UVC_BUF_STATE_ERROR) |
Laurent Pinchart | 35f02a6 | 2009-06-28 08:37:50 -0300 | [diff] [blame] | 133 | buf = uvc_queue_next_buffer(&stream->queue, |
| 134 | buf); |
Laurent Pinchart | c0efd23 | 2008-06-30 15:04:50 -0300 | [diff] [blame] | 135 | } while (ret == -EAGAIN); |
| 136 | } |
| 137 | } |