--- Begin Message ---
Package: linux-uvc
http://people.freedesktop.org/~rbultje/isight.patch
Index: uvcvideo.c
===================================================================
--- uvcvideo.c (revision 40)
+++ uvcvideo.c (working copy)
@@ -49,7 +49,7 @@
#define DRIVER_AUTHOR "Laurent Pinchart <[EMAIL PROTECTED]>"
#define DRIVER_DESC "USB Video Class driver"
-#define DRIVER_VERSION "0.1.0"
+#define DRIVER_VERSION "0.1.0-c"
#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 1, 0)
#define UVC_CTRL_TIMEOUT 300
@@ -73,6 +73,10 @@
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
#define UVC_GUID_FORMAT_YUY2 {0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10,
0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YUY2A {0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10,
0x00, \
+ 0x00, 0x80, 0x71, 0x9b, 0x38, 0x00, 0xaa, 0x00}
+#define UVC_GUID_FORMAT_UYVY {0x55, 0x59, 0x56, 0x59, 0x00, 0x00, 0x10,
0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
#define UVC_GUID_FORMAT_NV12 {0x4e, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10,
0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
@@ -564,10 +568,14 @@
.fcc = V4L2_PIX_FMT_YUYV,
},
{
- .guid = UVC_GUID_FORMAT_YUY2,
- .fcc = V4L2_PIX_FMT_YUYV,
+ .guid = UVC_GUID_FORMAT_YUY2A,
+ .fcc = V4L2_PIX_FMT_UYVY,
},
{
+ .guid = UVC_GUID_FORMAT_UYVY,
+ .fcc = V4L2_PIX_FMT_UYVY,
+ },
+ {
.guid = UVC_GUID_FORMAT_NV12,
.fcc = V4L2_PIX_FMT_NV12,
},
@@ -1271,24 +1279,38 @@
struct uvc_buffer *buf, const __u8 *data, unsigned int len)
{
unsigned int maxlen, nbytes;
- void *mem;
- __u8 fid;
+ __u8 *mem;
+ __u8 fid = queue->last_fid;
+ int hlen = 0, flags = 0, is_header = 0;
+ static const __u8 hdr[] = { 0x11, 0x22, 0x33, 0x44,
+ 0xde, 0xad, 0xbe, 0xef,
+ 0xde, 0xad, 0xfa, 0xce };
/* Sanity checks:
* - packet must be at least 2 bytes long
* - bHeaderLength value must be at least 2 bytes (see above)
* - bHeaderLength value can't be larger than the packet size.
*/
- if (len < 2 || data[0] < 2 || data[0] > len)
- return -EINVAL;
+ if ((len >= 14 && memcmp (&data[3], hdr, 12) == 0) ||
+ (len >= 13 && memcmp (&data[2], hdr, 12) == 0)) {
+ uvc_trace(UVC_TRACE_FRAME, "Detecting new header");
+ hlen = (data[3] == 0x11) ? data[1] : data[0];
+ if (hlen > len - 1 || hlen < 2)
+ return -EINVAL;
+ flags = (data[3] == 0x11) ? data[2] : data[1];
+ is_header = 1;
+ }
/* Skip payloads marked with the error bit ("error frames"). */
- if (data[1] & UVC_STREAM_ERR) {
+ if (hlen != 0 && flags & UVC_STREAM_ERR) {
uvc_trace(UVC_TRACE_FRAME, "Dropping packet (error bit
set).\n");
- return 0;
+
+ //return 0;
}
- fid = data[1] & UVC_STREAM_FID;
+ if (hlen != 0) {
+ fid = flags & UVC_STREAM_FID;
+ }
/* Store the packet FID bit and return immediately when the buffer is
* NULL.
@@ -1334,28 +1356,33 @@
"toggled).\n");
buf->state = UVC_BUF_STATE_DONE;
return -EAGAIN;
+ } else if (is_header && buf->buf.bytesused > 0) {
+ buf->state = UVC_BUF_STATE_DONE;
+ return -EAGAIN;
}
queue->last_fid = fid;
/* Copy the video data to the buffer. */
- len -= data[0];
+ len -= hlen;
maxlen = buf->buf.length - buf->buf.bytesused;
- mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
- nbytes = min(len, maxlen);
- memcpy(mem, data + data[0], nbytes);
- buf->buf.bytesused += nbytes;
+ if (!is_header) { /* we skip headers, they do not contain data */
+ mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
+ nbytes = min(len - hlen, maxlen);
+ memmove(mem, data + hlen, nbytes);
+ buf->buf.bytesused += nbytes;
+ }
/* Drop the current frame if the buffer size was exceeded. */
- if (len > maxlen) {
+ if (len - hlen > maxlen || buf->buf.bytesused == buf->buf.length) {
uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n");
buf->state = UVC_BUF_STATE_DONE;
}
/* Mark the buffer as done if the EOF marker is set. */
- if (data[1] & UVC_STREAM_EOF && buf->buf.bytesused != 0) {
+ if (hlen != 0 && (flags & UVC_STREAM_EOF && buf->buf.bytesused != 0)) {
uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n");
- if (data[0] == len)
+ if (hlen != 0 && hlen == len)
printk("EOF in empty packet.\n");
buf->state = UVC_BUF_STATE_DONE;
}
@@ -1593,7 +1620,7 @@
if (ret != size) {
uvc_printk(KERN_ERR, "Failed to query (%u) UVC control %u "
- "(unit %u) : %d.\n", query, cs, unit, ret);
+ "(unit %u) : %d (exp: %u).\n", query, cs, unit, ret,
size);
return -EIO;
}
@@ -1883,8 +1910,10 @@
/* Get the minimum and maximum values for compression settings. */
if ((ret = uvc_get_video_ctrl(video, &probe_min, 1, GET_MIN)) < 0 ||
- (ret = uvc_get_video_ctrl(video, &probe_max, 1, GET_MAX)) < 0)
+ (ret = uvc_get_video_ctrl(video, &probe_max, 1, GET_MAX)) < 0) {
+ ret = 0;
goto done;
+ }
probe->wCompQuality = probe_max.wCompQuality;
@@ -1942,7 +1971,7 @@
return ret;
/* Retrieve the default format and commit it. */
- if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_DEF)) < 0)
+ if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
return ret;
if ((ret = uvc_set_video_ctrl(video, probe, 0)) < 0)
return ret;
@@ -2214,6 +2243,11 @@
if ((ret = uvc_set_video_ctrl(video, &probe, 0)) < 0)
return ret;
+ if (probe.dwMaxVideoFrameSize == 0)
+ probe.dwMaxVideoFrameSize =
+ video->streaming->format[probe.bFormatIndex - 1].
+ frame[probe.bFrameIndex -
1].dwMaxVideoFrameBufferSize;
+
memcpy(&video->streaming->ctrl, &probe, sizeof probe);
video->streaming->cur_format = format;
video->streaming->cur_frame = frame;
@@ -3506,6 +3540,13 @@
if (!found) {
uvc_printk(KERN_INFO, "No valid video chain found.\n");
+ if (dev->udev->descriptor.idVendor == 0x05ac &&
+ dev->udev->descriptor.idProduct == 0x8300) {
+ uvc_printk (KERN_ERR, "Possible an Apple iSight "
+ "without firmware loaded; please read "
+ "the documentation, load the firmware "
+ "and re-load the driver.");
+ }
return -1;
}
@@ -3757,6 +3798,19 @@
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0 },
+ /* Apple iSight (built-in in Macintels) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+ .idVendor = 0x05ac,
+ .idProduct = 0x8501 },
+ /* same, but without firmware loaded (will give useful warning)
+ * when the firmware is not loaded in the pre-instal step). */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x05ac,
+ .idProduct = 0x8300,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 0xff,
+ .bInterfaceProtocol = 0xff },
/* Generic USB Video Class */
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
{}
Index: Makefile
===================================================================
--- Makefile (revision 40)
+++ Makefile (working copy)
@@ -1,7 +1,7 @@
KERNEL_VERSION := `uname -r`
KERNEL_DIR := /lib/modules/$(KERNEL_VERSION)/build
INSTALL_MOD_DIR := usb/media
-
+DRIVER_VERSION := `grep DRIVER_VERSION uvcvideo.c | grep define | grep -v
DRIVER_VERSION_NUMBER | cut -d"\"" -f2`
PWD := $(shell pwd)
obj-m := uvcvideo.o
@@ -9,7 +9,7 @@
%.o : %.c
gcc $(TEST_CFLAGS) -c -o $@ $<
-all: uvcvideo
+all: uvcvideo extract
uvcvideo:
@echo "Building USB Video Class driver..."
@@ -24,3 +24,12 @@
-rm -f *.o *.ko .*.cmd .*.flags *.mod.c Modules.symvers
-rm -rf .tmp_versions
+extract: extract.c
+ gcc -Wall -g `pkg-config --cflags --libs libusb` -o extract extract.c
+
+dist:
+ rm -fr linux-uvc-${DRIVER_VERSION}
+ mkdir linux-uvc-${DRIVER_VERSION}
+ cp uvcvideo.[ch] Makefile extract.c linux-uvc-${DRIVER_VERSION}/
+ tar -zcf linux-uvc-${DRIVER_VERSION}.tar.gz linux-uvc-${DRIVER_VERSION}
+ rm -fr linux-uvc-${DRIVER_VERSION}
--- /dev/null 2006-05-30 21:15:07.000000000 -0400
+++ extract.c 2006-09-21 07:30:30.000000000 -0400
@@ -0,0 +1,221 @@
+/*
+ * Apple iSight (the one built in the screen of Macbooks) firmware loader
+ * Copyright (C) 2006 Ronald S. Bultje <[EMAIL PROTECTED]>
+ *
+ * Special thanks to Johannes Berg <[EMAIL PROTECTED]> for helping
+ * to find out how to load the firmware; see his website on
+ * http://johannes.sipsolutions.net/MacBook/iSight for details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#include <usb.h>
+#define TIMEOUT 300
+
+static int
+read_fw (struct usb_dev_handle *dev, char *filename, long off)
+{
+ int fd, len, req, llen, res, ret = -1;
+ unsigned char data[4], rdata[1024], *ptr;
+
+ if ((fd = open (filename, O_RDONLY)) == -1) {
+ perror ("Opening file");
+ return -1;
+ } else if (lseek (fd, off, SEEK_SET) != off) {
+ perror ("Seeking");
+ close (fd);
+ return -1;
+ }
+
+ if ((res = usb_control_msg (dev, 0x40, 0xA0, 0xe600, 0,
+ "\1", 1, TIMEOUT)) != 1) {
+ perror ("Firmware load init failed");
+ close (fd);
+ return -1;
+ }
+ while (1) {
+ if ((len = read (fd, data, 4)) != 4) {
+ if (len == 0) {
+ fprintf (stderr,
+ "Unexpected eos - corrupt driver?\n");
+ goto end;
+ } else {
+ perror("Reading firmware header chunk failed");
+ goto end;
+ }
+ }
+ len = (data[0] << 8) | data[1];
+ req = (data[2] << 8) | data[3];
+ if (len == 0x8001)
+ break; /* success */
+ else if (len == 0)
+ continue;
+ else if (len < 0 || len >= 1024) {
+ fprintf (stderr,
+ "Invalid firmware data_length %d, load
aborted\n",
+ len);
+ goto end;
+ } else if (read (fd, rdata, len) != len) {
+ perror ("Error reading firmware data");
+ goto end;
+ }
+
+ /* upload to usb bus */
+ for (ptr = rdata; len > 0; req += 50, ptr += 50) {
+ llen = len > 50 ? 50 : len;
+ len -= llen;
+
+ if ((res = usb_control_msg (dev, 0x40, 0xA0, req, 0,
+ (char *) ptr, llen,
+ TIMEOUT)) != llen) {
+ fprintf (stderr,
+ "firmware load req=0x%x failed: %s\n",
+ req, strerror (errno));
+ goto end;
+ }
+ }
+ }
+
+ ret = 0;
+end:
+ if ((res = usb_control_msg (dev, 0x40, 0xA0, 0xe600, 0,
+ "\0", 1, TIMEOUT)) != 1) {
+ perror ("Firmware finish-up failed");
+ ret = -1;
+ }
+
+ close (fd);
+
+ return ret;
+}
+
+static int
+probe_dev (struct usb_device *dev, char *fw_filename, long off)
+{
+ int n, total = 0, res;
+
+ if (dev->descriptor.idVendor == 0x05ac &&
+ dev->descriptor.idProduct == 0x8300 &&
+ dev->descriptor.bDeviceClass == 0xff &&
+ dev->descriptor.bDeviceSubClass == 0xff &&
+ dev->descriptor.bDeviceProtocol == 0xff) {
+ usb_dev_handle *h;
+
+ /* load firmware */
+ if (!(h = usb_open (dev))) {
+ perror ("Opening iSight");
+ return -1;
+ }
+ printf ("Loading firmware for iSight...\n");
+ if (read_fw (h, fw_filename, off) == 0) {
+ printf ("done\n");
+ total++;
+ }
+ usb_close (h);
+ } else if (dev->descriptor.idVendor == 0x05ac &&
+ dev->descriptor.idProduct == 0x8501) {
+ printf ("Apple iSight with firmware already loaded found\n");
+ total++;
+ }
+
+ for (n = 0; n < dev->num_children; n++) {
+ res = probe_dev (dev->children[n], fw_filename, off);
+ if (res != -1)
+ total += res;
+ }
+
+ return total;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int n, found = 0, res, err = 0;
+ char command[1024];
+ struct usb_bus *bus;
+ struct usb_device *dev;
+ static const struct {
+ char *sha1sum;
+ long off;
+ } offsets[] = {
+ { "86430c04f9b67c5c3d84409138a7679827025ec2", 5172 /* 0x1434 */
},
+ { "a14c159b176d27a6e98dcb5dea5d78b81e15ad41", 9176 /* 0x23D8 */
},
+ { NULL }
+ }, *offset;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <firmware file>\n", argv[0]);
+ fprintf(stderr, "Firmware can usually be found on your Mac "
+ "partition in /System/Library/Extensions/"
+ "IOUSBFamily.kext/Contents/PlugIns/"
+ "AppleUSBVideoSupport.kext/Contents/MacOS/"
+ "AppleUSBVideoSupport\n");
+ return -1;
+ }
+
+ /* check sha1sum on firmware, to prevent loading crap into the
+ * iSight and thus possibly damaging it. */
+ for (n = 0; offsets[n].sha1sum != NULL; n++) {
+ snprintf (command, sizeof (command) - 1,
+ "test \"x`sha1sum %s`\" == \"x%s %s\" &> /dev/null",
+ argv[1], offsets[n].sha1sum, argv[1]);
+ if (system (command) == 0)
+ break;
+ }
+ if (offsets[n].sha1sum == NULL) {
+ fprintf (stderr, "Sha1sum check on firmware file failed\n");
+ return -1;
+ }
+ offset = &offsets[n];
+
+ /* init usb */
+ usb_init ();
+ if (usb_find_busses () == 0) {
+ fprintf (stderr, "No USB busses found\n");
+ return -1;
+ } else if (usb_find_devices () == 0) {
+ fprintf (stderr, "No USB devices found\n");
+ return -1;
+ }
+
+ /* find iSight */
+ for (bus = usb_busses; bus != NULL; bus = bus->next) {
+ if (bus->devices != NULL) {
+ for (dev = bus->devices; dev != NULL;
+ dev = dev->next) {
+ res += probe_dev (dev, argv[1], offset->off);
+ if (res == -1)
+ err++;
+ else
+ found += res;
+ }
+ }
+ }
+ if (found == 0 && err == 0) {
+ fprintf (stderr, "No Apple iSight found!\n");
+ return -1;
+ }
+
+ return 0;
+}
--- End Message ---