Hi,
The following is the patch applied to Debian package in order to make
linux-uvc work on both iSight and Logitech stuff. It needs re-working
since it uses a global, but this is a start.
regards,
junichi
--
[EMAIL PROTECTED],netfort.gr.jp} Debian Project
#! /bin/sh /usr/share/dpatch/dpatch-run
## 01_macbook_support.dpatch by Junichi Uekawa <[EMAIL PROTECTED]>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Mactel Linux iSight support by rbultje, rediffed against trunk
@DPATCH@
diff -urNad trunk~/Makefile trunk/Makefile
--- trunk~/Makefile 2006-07-22 21:59:17.000000000 +0900
+++ trunk/Makefile 2006-07-23 08:39:33.000000000 +0900
@@ -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 -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}
diff -urNad trunk~/extract.c trunk/extract.c
--- trunk~/extract.c 1970-01-01 09:00:00.000000000 +0900
+++ trunk/extract.c 2006-07-23 08:39:33.000000000 +0900
@@ -0,0 +1,202 @@
+/*
+ * 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 <usb.h>
+#define TIMEOUT 300
+
+static int
+read_fw (struct usb_dev_handle *dev, char *filename)
+{
+ long long int pos;
+ int fd, rd, 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, 5172, SEEK_SET) != 5172) {
+ 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 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)
+{
+ int n, total = 0;
+
+ 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;
+ }
+ printf ("Loading firmware for iSight...\n");
+ if (read_fw (h, fw_filename) == 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++)
+ total += probe_dev (dev->children[n], fw_filename);
+
+ return total;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int n, m, found = 0;
+ char command[1024];
+ struct usb_bus *bus;
+ struct usb_device *dev;
+
+ 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. */
+ snprintf (command, sizeof (command) - 1,
+ "test \"x`sha1sum %s`\" == \"x%s %s\" &> /dev/null",
+ argv[1], "86430c04f9b67c5c3d84409138a7679827025ec2",
+ argv[1]);
+ if (system (command) != 0) {
+ fprintf (stderr, "Sha1sum check on firmware file failed\n");
+ return -1;
+ }
+
+ /* 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) {
+ found += probe_dev (dev, argv[1]);
+ }
+ }
+ }
+ if (found == 0) {
+ fprintf (stderr, "No Apple iSight found!\n");
+ return -1;
+ }
+
+ return 0;
+}
diff -urNad trunk~/uvcvideo.c trunk/uvcvideo.c
--- trunk~/uvcvideo.c 2006-07-22 21:59:17.000000000 +0900
+++ trunk/uvcvideo.c 2006-07-23 08:39:33.000000000 +0900
@@ -53,7 +53,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-b"
#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 1, 0)
#define UVC_CTRL_TIMEOUT 300
@@ -77,6 +77,8 @@
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_NV12 {0x4e, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10,
0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
@@ -568,8 +570,8 @@
.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_NV12,
@@ -1275,24 +1277,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.
@@ -1338,28 +1354,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;
}
@@ -1597,7 +1618,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;
}
@@ -1887,8 +1908,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;
@@ -1946,7 +1969,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;
@@ -2218,6 +2241,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;
@@ -3590,6 +3618,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;
}
@@ -3841,6 +3876,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) },
{}
#! /bin/sh /usr/share/dpatch/dpatch-run
## 07_with_isight.dpatch Nobuhiro Iwamatsu <[EMAIL PROTECTED]>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Workaround to get iSight and normal UVC devices function.
@DPATCH@
diff -urN trunk~/uvcvideo.c trunk/uvcvideo.c
--- trunk~/uvcvideo.c 2006-09-10 23:09:20.000000000 +0900
+++ trunk/uvcvideo.c 2006-09-10 23:17:08.000000000 +0900
@@ -288,6 +288,11 @@
UVC_BUF_STATE_ERROR = 4,
};
+enum uvc_dev_type{
+ UVC_DEV_ISIGHT = 0 , /* Apple iSight */
+ UVC_DEV_QCAM_FUSION = 1 , /* Qcam Fusion */
+};
+
struct uvc_buffer {
unsigned int size;
unsigned long vma_use_count;
@@ -379,6 +384,7 @@
static void uvc_delete(struct kref *kref);
+static int dev_type ;/* device type */
/* ------------------------------------------------------------------------
* Control, formats, ...
*/
@@ -1289,14 +1295,23 @@
* - bHeaderLength value must be at least 2 bytes (see above)
* - bHeaderLength value can't be larger than the packet size.
*/
- 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)
+ if( dev_type != UVC_DEV_ISIGHT ){
+ if (len < 2 || data[0] < 2 || data[0] > len){
return -EINVAL;
- flags = (data[3] == 0x11) ? data[2] : data[1];
- is_header = 1;
+ }
+
+ hlen = data[0];
+ flags = data[1];
+ }else{
+ 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"). */
@@ -1364,7 +1379,14 @@
/* Copy the video data to the buffer. */
len -= hlen;
maxlen = buf->buf.length - buf->buf.bytesused;
- if (!is_header) { /* we skip headers, they do not contain data */
+
+ if(dev_type != UVC_DEV_ISIGHT){
+ mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
+ nbytes = min(len, maxlen);
+ memcpy(mem, data + hlen, nbytes);
+ buf->buf.bytesused += nbytes;
+ }else if((dev_type == UVC_DEV_ISIGHT)&& (!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);
@@ -1372,11 +1394,19 @@
}
/* Drop the current frame if the buffer size was exceeded. */
- 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;
+ if ( dev_type != UVC_DEV_ISIGHT ){
+ if (len > maxlen) {
+ uvc_trace(UVC_TRACE_FRAME, "Frame complete
(overflow).\n");
+ buf->state = UVC_BUF_STATE_DONE;
+ }
+ }else{
+ 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 (hlen != 0 && (flags & UVC_STREAM_EOF && buf->buf.bytesused != 0)) {
uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n");
@@ -3628,8 +3658,15 @@
}
}
- if (found)
+ if (found){
+ if (dev->udev->descriptor.idVendor == 0x05ac &&
+ dev->udev->descriptor.idProduct == 0x8300) {
+ dev_type = UVC_DEV_ISIGHT ;
+ }else{
+ dev_type = UVC_DEV_QCAM_FUSION ;
+ }
break;
+ }
}
if (!found) {
_______________________________________________
Linux-uvc-devel mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/linux-uvc-devel