Hi Felix,
First of all, sorry for the late reply.
On Sunday 12 August 2007, Felix Möller wrote:
> Felix Möller schrieb:
> > Hi,
> >
> > > I cannot get my iSight in an early 2006 MacBook working.
There are a couple of problems with the iSight. The main issue is that the
device is not UVC compliant. It requires hacks in the driver to work
properly.
The second issue is that the webcam has no firmware memory. The host has to
upload the firmware every time the computer is started. There is a userspace
firmware loading utility called fxload that handles firmware loading, so I'm
not very keen on adding firmware loading support to the driver itself. It
seems the concensus among kernels developers is to use the fxload utility. I
could of course change my mind if I'm proven wrong :-)
I don't own any MacBook so I can't test driver hacks. A few users helped me in
creating a patch for the Linux UVC driver to support iSight webcams. I wasn't
very happy with the last version, so I asked for feedback on a revised patch.
I got no reply so far.
> > Is there anything I could try? I am willing to compile from SVN or
> > provide any needed information.
The current version of the iSight patch doesn't apply cleanly to the latest
SVN revision. You could fix the patch and test it. You will have to load the
firmware with a userspace utility.
I attached the most recent patch I have, as well as a userspace utility which
should upload the firmware.
> > Hope to get this working ...
>
> trying uvccapture I get the following:
>
> /uvccapture-0.4 # ./uvccapture -v
> Using videodevice: /dev/video0
> Saving images to: snap.jpg
> Image size: 320x240
> Taking snapshot every 0 seconds
> Taking images using mmap
> Unable to set format: 22.
> Init v4L2 failed !! exit fatal
>
> modprobing with trace=15 I get the following:
> > uvcvideo: Adding mapping Brightness to control
> > 00000000-0000-0000-0000-000000000101/2. uvcvideo: Adding mapping Contrast
> > to control 00000000-0000-0000-0000-000000000101/3. uvcvideo: Adding
> > mapping Hue to control 00000000-0000-0000-0000-000000000101/6. uvcvideo:
> > Adding mapping Saturation to control
> > 00000000-0000-0000-0000-000000000101/7. uvcvideo: Adding mapping
> > Sharpness to control 00000000-0000-0000-0000-000000000101/8. uvcvideo:
> > Adding mapping Gamma to control 00000000-0000-0000-0000-000000000101/9.
> > uvcvideo: Adding mapping Backlight Compensation to control
> > 00000000-0000-0000-0000-000000000101/1. uvcvideo: Adding mapping Gain to
> > control 00000000-0000-0000-0000-000000000101/4. uvcvideo: Adding mapping
> > Power Line Frequency to control 00000000-0000-0000-0000-000000000101/5.
> > uvcvideo: Adding mapping Hue, Auto to control
> > 00000000-0000-0000-0000-000000000101/16. uvcvideo: Adding mapping Pan
> > (relative) to control 63610682-5070-49ab-b8cc-b3855e8d2256/1. uvcvideo:
> > Adding mapping Tilt (relative) to control
> > 63610682-5070-49ab-b8cc-b3855e8d2256/1. uvcvideo: Adding mapping Pan/Tilt
> > (reset) to control 63610682-5070-49ab-b8cc-b3855e8d2256/2. uvcvideo:
> > Adding mapping Exposure, Auto to control
> > 00000000-0000-0000-0000-000000000001/2. uvcvideo: Adding mapping Exposure
> > (Absolute) to control 00000000-0000-0000-0000-000000000001/4. uvcvideo:
> > Adding mapping White Balance Temperature, Auto to control
> > 00000000-0000-0000-0000-000000000101/11. uvcvideo: Adding mapping White
> > Balance Temperature to control 00000000-0000-0000-0000-000000000101/10.
> > uvcvideo: Probing known UVC device 4 (05ac:8501)
> > uvcvideo: iSight: firmware already loaded.
> > uvcvideo: Found format YUV 4:2:2 (UYVY).
> > uvcvideo: - 640x480 (30.0 fps)
> > uvcvideo: - 352x288 (30.0 fps)
> > uvcvideo: - 320x240 (30.0 fps)
> > uvcvideo: Found a Status endpoint (addr 81).
> > uvcvideo: Found UVC 1.00 device Built-in iSight (05ac:8501)
> > uvcvideo: Added control 00000000-0000-0000-0000-000000000101/2 to device
> > 4 entity 2 uvcvideo: Added control 00000000-0000-0000-0000-000000000101/7
> > to device 4 entity 2 uvcvideo: Added control
> > 00000000-0000-0000-0000-000000000101/8 to device 4 entity 2 uvcvideo:
> > Added control 00000000-0000-0000-0000-000000000101/9 to device 4 entity 2
> > uvcvideo: Scanning UVC chain: OT 3 <- PU 2 <- IT 1
> > uvcvideo: Found a valid video chain (1 -> 3).
> > uvcvideo: Failed to query (135) UVC control 1 (unit 0) : -32 (exp. 26).
> > uvcvideo: UVC device initialized.
> > usbcore: registered new interface driver uvcvideo
> > USB Video Class driver (v0.1.0)
>
> I hope somebody has an idea what to try. ;)
Have a look at the kernel log (dmesg) after trying uvccapture. You might get
more information.
Please also note that the Linux UVC driver supplied with openSUSE includes an
old iSight patch (as well as possible other patches). I can't help you much
with that driver.
Best regards,
Laurent Pinchart
--- /dev/null 2006-05-30 21:15:07.000000000 -0400
+++ extract.c 2006-07-20 23:10:16.000000000 -0400
@@ -0,0 +1,148 @@
+#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 void
+read_fw (struct usb_dev_handle *dev, char *filename)
+{
+ long long int pos;
+ int fd = open (filename, O_RDONLY), rd, len, req, llen, res;
+ unsigned char data[4], rdata[1024], *ptr;
+ if (fd == -1) {
+ perror ("Opening file");
+ return;
+ } else if (lseek (fd, 5172, SEEK_SET) != 5172) {
+ perror ("Seeking");
+ return;
+ }
+
+ if ((res = usb_control_msg (dev, 0x40, 0xA0, 0xe600, 0,
+ "\1", 1, TIMEOUT)) != 1) {
+ fprintf (stderr, "Firmware load init failed: %s\n",
+ strerror (errno));
+ return;
+ }
+ while (1) {
+ if ((len = read (fd, data, 4)) != 4) {
+ if (len == 0) {
+ fprintf (stderr, "eos\n");
+ return;
+ } else {
+ perror("Header read");
+ return;
+ }
+ }
+ len = (data[0] << 8) | data[1];
+ req = (data[2] << 8) | data[3];
+ if (len == 0x8001)
+ break;
+ 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;
+ }
+ }
+ }
+
+end:
+ if ((res = usb_control_msg (dev, 0x40, 0xA0, 0xe600, 0,
+ "\0", 1, TIMEOUT)) != 1) {
+ fprintf (stderr, "Firmware finish failed: %s\n",
+ strerror (errno));
+ }
+}
+
+static void
+probe_dev (struct usb_device *dev, char *fw_filename)
+{
+ int n;
+
+ printf ("Once device 0x%x 0x%x\n", dev->descriptor.idVendor, dev->descriptor.idProduct);
+ 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 one iSight\n");
+ read_fw (h, fw_filename);
+ printf ("Loaded firmware for one iSight\n");
+ usb_close (h);
+ } else if (dev->descriptor.idVendor == 0x05ac &&
+ dev->descriptor.idProduct == 0x8501) {
+ printf ("One iSight with firmware already loaded found\n");
+ }
+
+ for (n = 0; n < dev->num_children; n++)
+ probe_dev (dev->children[n], fw_filename);
+}
+
+int
+main (int argc, char *argv[])
+{
+ int n, m;
+
+ 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;
+ }
+
+ /* init usb */
+ usb_init ();
+ if (usb_find_busses () == 0) {
+ fprintf (stderr, "No USB devices found\n");
+ return -1;
+ }
+ usb_find_devices ();
+
+ /* find us */
+ for (n = 0; ; n++) {
+ if (usb_busses[n].devices != NULL) for (m = 0; ; m++) {
+ probe_dev (&usb_busses[n].devices[m], argv[1]);
+
+ if (usb_busses[n].devices[m].next == NULL)
+ break;
+ }
+ if (usb_busses[n].next == NULL)
+ break;
+ }
+
+ return 0;
+}
Index: uvc_video.c
===================================================================
--- uvc_video.c (revision 106)
+++ uvc_video.c (working copy)
@@ -216,13 +216,94 @@
#define UVC_STREAM_EOF (1 << 1)
#define UVC_STREAM_FID (1 << 0)
-/*
- *
- */
-static int uvc_video_decode(struct uvc_video_queue *queue,
+static int uvc_video_decode_isight(struct uvc_video_queue *queue,
struct uvc_buffer *buf, const __u8 *data, unsigned int len)
{
+ static const __u8 hdr[] = {
+ 0x11, 0x22, 0x33, 0x44, 0xde, 0xad, 0xbe, 0xef,
+ 0xde, 0xad, 0xfa, 0xce
+ };
+
unsigned int maxlen, nbytes;
+ __u8 *mem;
+ int is_header = 0;
+
+ if (buf == NULL)
+ return 0;
+
+ /* Built-in iSight webcams are completely broken. They implement most
+ * of UVC 1.0, but the Apple engineers decided to use a completely
+ * different packet format, although the video data is in YUV. Were
+ * they on crack or just lazy ? As the hardware is 8051-based, it
+ * might be interesting to write an open-source firmware.
+ *
+ * Instead of sending a header at the beginning of each isochronous
+ * transfer payload, the webcam sends a single header per image (on
+ * its own in a packet), followed by packets containing data only.
+ *
+ * Offset Size (bytes) Description
+ * ------------------------------------------------------------------
+ * 0x00 1 Header length
+ * 0x01 1 Flags (UVC-compliant)
+ * 0x02 4 Always equal to '11223344'
+ * 0x06 8 Always equal to 'deadbeefdeadface'
+ * 0x0e 16 Unknown
+ *
+ * The header can be prefixed by an optional, unknown-purpose byte.
+ */
+
+ /* Detect the packet type. */
+ if ((len >= 14 && memcmp (&data[2], hdr, 12) == 0) ||
+ (len >= 15 && memcmp (&data[3], hdr, 12) == 0)) {
+ uvc_trace(UVC_TRACE_FRAME, "iSight header found\n");
+ is_header = 1;
+ }
+
+ /* Synchronize to the input stream by waiting for a header packet. */
+ if (buf->state != UVC_BUF_STATE_ACTIVE) {
+ if (!is_header) {
+ uvc_trace(UVC_TRACE_FRAME, "Dropping packet (out of "
+ "sync).\n");
+ return 0;
+ }
+
+ buf->state = UVC_BUF_STATE_ACTIVE;
+ }
+
+ /* Mark the buffer as done if we're at the beginning of a new frame.
+ *
+ * Empty buffers (bytesused == 0) don't trigger end of frame detection
+ * as it doesn't make sense to return an empty buffer.
+ */
+ if (is_header && buf->buf.bytesused != 0) {
+ buf->state = UVC_BUF_STATE_DONE;
+ return -EAGAIN;
+ }
+
+ /* Copy the video data to the buffer. Skip header packets, as they
+ * contain no data.
+ */
+ if (!is_header) {
+ maxlen = buf->buf.length - buf->buf.bytesused;
+ mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
+ nbytes = min(len, maxlen);
+ memcpy(mem, data, nbytes);
+ buf->buf.bytesused += nbytes;
+
+ /* Drop the current frame if the buffer size was exceeded. */
+ if (len > maxlen || buf->buf.bytesused == buf->buf.length) {
+ uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n");
+ buf->state = UVC_BUF_STATE_DONE;
+ }
+ }
+
+ return 0;
+}
+
+static int uvc_video_decode_uvc(struct uvc_video_queue *queue,
+ struct uvc_buffer *buf, const __u8 *data, unsigned int len)
+{
+ unsigned int maxlen, nbytes;
void *mem;
__u8 fid;
@@ -315,6 +396,12 @@
return 0;
}
+static int uvc_video_decode(struct uvc_video_queue *queue,
+ struct uvc_buffer *buf, const __u8 *data, unsigned int len)
+{
+ return queue->decode(queue, buf, data, len);
+}
+
/* ------------------------------------------------------------------------
* URB handling
*/
@@ -672,6 +759,7 @@
struct uvc_format *format = NULL;
struct uvc_frame *frame = NULL;
unsigned int i;
+ u16 vid, pid;
int ret;
if (video->streaming->nformats == 0) {
@@ -722,6 +810,16 @@
video->streaming->cur_frame = frame;
atomic_set(&video->active, 1);
+ /* Select the video decoder based. This might be better handled
+ * elsewhere, based on the format GUID instead of the device ID.
+ */
+ vid = le16_to_cpu(video->dev->udev->descriptor.idVendor);
+ pid = le16_to_cpu(video->dev->udev->descriptor.idVendor);
+ if (vid == 0x05ac && pid == 0x8501)
+ video->queue.decode = uvc_video_decode_isight;
+ else
+ video->queue.decode = uvc_video_decode_uvc;
+
return 0;
}
Index: uvc_driver.c
===================================================================
--- uvc_driver.c (revision 106)
+++ uvc_driver.c (working copy)
@@ -58,6 +58,14 @@
.fcc = V4L2_PIX_FMT_YUYV,
},
{
+ .guid = UVC_GUID_FORMAT_YUY2_MACOSX,
+ .fcc = V4L2_PIX_FMT_YUYV,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_UYVY,
+ .fcc = V4L2_PIX_FMT_UYVY,
+ },
+ {
.guid = UVC_GUID_FORMAT_NV12,
.fcc = V4L2_PIX_FMT_NV12,
},
@@ -1635,6 +1643,16 @@
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_EXTRAFIELDS
},
+ /* Apple iSight (built-in Macintels) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x05ac,
+ .idProduct = 0x8501,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX
+ },
/* Generic USB Video Class */
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
{}
Index: uvcvideo.h
===================================================================
--- uvcvideo.h (revision 106)
+++ uvcvideo.h (working copy)
@@ -216,6 +216,12 @@
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_YUY2_MACOSX \
+ {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}
@@ -506,6 +512,9 @@
struct list_head mainqueue;
struct list_head irqqueue;
+
+ int (*decode)(struct uvc_video_queue *queue, struct uvc_buffer *buf,
+ const __u8 *data, unsigned int len);
};
struct uvc_video_device {
_______________________________________________
Linux-uvc-devel mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/linux-uvc-devel