ChangeSet 1.842.46.15, 2002/11/27 09:46:14-08:00, nemosoft@smcc.demon.nl [PATCH] [PATCH] PWC 8.9 After a little absence, here's a patch to bring the Philips Webcam driver up to version 8.9 (skipping 8.8 which has been available as a download on my website for a while). This patch is against 2.5.49, and includes some of the following: * New USB IDs for Logitech and Visionite webcams. * Better URB link/unlink sequence when opening/closing device and switching resolutions. * Adding probe for CCD/CMOS sensor type. * Removed remnants of YUV420 palette stuff. Also updated the description in 'Kconfig'. diff -Nru a/drivers/usb/media/Kconfig b/drivers/usb/media/Kconfig --- a/drivers/usb/media/Kconfig Wed Nov 27 12:49:43 2002 +++ b/drivers/usb/media/Kconfig Wed Nov 27 12:49:43 2002 @@ -120,15 +120,26 @@ tristate "USB Philips Cameras" depends on USB && VIDEO_DEV ---help--- - Say Y or M here if you want to use one of these Philips USB webcams: - PCA645, PCA646, PCVC675, PCVC680, PCVC690, PCVC730, PCVC740, or - the Askey VC010. The PCA635, PCVC665 and PCVC720 are not supported - by this driver and never will be. + Say Y or M here if you want to use one of these Philips & OEM + webcams: + * Philips PCA645, PCA646 + * Philips PCVC675, PCVC680, PCVC690 + * Philips PCVC730, PCVC740, PCVC750 + * Askey VC010 + * Logitech QuickCam Pro 3000, 4000, 'Zoom' and 'Notebook' + * Samsung MPC-C10, MPC-C30 + * Creative Webcam 5 + * SOTECT Afina Eye + * Visionite VCS-UC300, VCS-UM100 + + The PCA635, PCVC665 and PCVC720 are not supported by this driver + and never will be, but the 665 and 720 are supported by other + drivers. - This driver has an optional plugin, which is distributed as a binary - module only. It contains code that allow you to use higher - resolutions and framerates but may not be distributed as source. - But even without this plugin you can these cams for most + This driver has an optional plugin (called PWCX), which is + distributed as a binary module only. It contains code that allow you + to use higher resolutions and framerates but may not be distributed + as source. But even without this plugin you can these cams for most applications. See for more information and diff -Nru a/drivers/usb/media/pwc-ctrl.c b/drivers/usb/media/pwc-ctrl.c --- a/drivers/usb/media/pwc-ctrl.c Wed Nov 27 12:49:43 2002 +++ b/drivers/usb/media/pwc-ctrl.c Wed Nov 27 12:49:43 2002 @@ -256,8 +256,10 @@ memcpy(buf, pEntry->mode, 3); ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3); - if (ret < 0) + if (ret < 0) { + Debug("Failed to send video command... %d\n", ret); return ret; + } if (pEntry->compressed && pdev->decompressor != NULL) pdev->decompressor->init(pdev->release, buf, pdev->decompress_data); @@ -1103,12 +1105,7 @@ buf[0] = on_value; buf[1] = off_value; - return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_STATUS_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - LED_FORMATTER, - pdev->vcinterface, - &buf, 2, HZ / 2); + return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2); } int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) @@ -1122,13 +1119,7 @@ return 0; } - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_STATUS_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - LED_FORMATTER, - pdev->vcinterface, - &buf, 2, HZ / 2); - + ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2); if (ret < 0) return ret; *on_value = buf[0] * 100; @@ -1279,7 +1270,6 @@ ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); if (ret < 0) return ret; -//Debug("pwc_get_dynamic_noise = %d\n", buf); return buf; } @@ -1363,12 +1353,10 @@ case VIDIOCPWCPROBE: { - struct pwc_probe probe; + struct pwc_probe *probe = arg; - strcpy(probe.name, pdev->vdev->name); - probe.type = pdev->type; - if (copy_to_user(arg, &probe, sizeof(probe))) - ret = -EFAULT; + strcpy(probe->name, pdev->vdev->name); + probe->type = pdev->type; break; } diff -Nru a/drivers/usb/media/pwc-if.c b/drivers/usb/media/pwc-if.c --- a/drivers/usb/media/pwc-if.c Wed Nov 27 12:49:43 2002 +++ b/drivers/usb/media/pwc-if.c Wed Nov 27 12:49:43 2002 @@ -1,6 +1,6 @@ /* Linux driver for Philips webcam USB and Video4Linux interface part. - (C) 1999-2001 Nemosoft Unv. + (C) 1999-2002 Nemosoft Unv. 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 @@ -42,32 +42,31 @@ - Alistar Moire: QuickCam 3000 Pro device/product ID - Tony Hoyle: Creative Labs Webcam 5 device/product ID - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged - - Jk Fang: SOTEC device/product ID + - Jk Fang: SOTEC Afina Eye ID + - Xavier Roche: QuickCam Pro 4000 ID + - Jens Knudsen: QuickCam Zoom ID + - J. Debert: QuickCam for Notebooks ID */ #include #include +#include #include #include #include #include #include -#include #include #include "pwc.h" #include "pwc-ioctl.h" #include "pwc-uncompress.h" -#if !defined(MAP_NR) -#define MAP_NR(a) virt_to_page(a) -#endif - /* Function prototypes and driver templates */ /* hotplug device table support */ static struct usb_device_id pwc_device_table [] = { - { USB_DEVICE(0x0471, 0x0302) }, + { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */ { USB_DEVICE(0x0471, 0x0303) }, { USB_DEVICE(0x0471, 0x0304) }, { USB_DEVICE(0x0471, 0x0307) }, @@ -76,12 +75,17 @@ { USB_DEVICE(0x0471, 0x0310) }, { USB_DEVICE(0x0471, 0x0311) }, { USB_DEVICE(0x0471, 0x0312) }, - { USB_DEVICE(0x069A, 0x0001) }, - { USB_DEVICE(0x046D, 0x08b0) }, - { USB_DEVICE(0x055D, 0x9000) }, + { USB_DEVICE(0x069A, 0x0001) }, /* Askey */ + { USB_DEVICE(0x046D, 0x08b0) }, /* Logitech QuickCam Pro 3000 */ + { USB_DEVICE(0x046D, 0x08b1) }, /* Logitech QuickCam for Notebooks */ + { USB_DEVICE(0x046D, 0x08b2) }, /* Logitech QuickCam Pro 4000 */ + { USB_DEVICE(0x046D, 0x08b3) }, /* Logitech QuickCam Zoom */ + { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */ { USB_DEVICE(0x055D, 0x9001) }, - { USB_DEVICE(0x041E, 0x400C) }, - { USB_DEVICE(0x04CC, 0x8116) }, + { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */ + { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */ + { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */ + { USB_DEVICE(0x0d81, 0x1900) }, { } }; MODULE_DEVICE_TABLE(usb, pwc_device_table); @@ -106,7 +110,7 @@ static int default_mbufs = 2; /* Default number of mmap() buffers */ int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX; static int power_save = 0; -static int led_on = 1, led_off = 0; /* defaults to LED that is on while in use */ +static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */ int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */ static struct { int type; @@ -167,7 +171,7 @@ succeeded. The pwc_device struct links back to both structures. When a device is unplugged while in use it will be removed from the - list of known USB devices; I also de-register as a V4L device, but + list of known USB devices; I also de-register it as a V4L device, but unfortunately I can't free the memory since the struct is still in use by the file descriptor. This free-ing is then deferend until the first opportunity. Crude, but it works. @@ -240,7 +244,7 @@ int i; void *kbuf; - Trace(TRACE_MEMORY, "Entering allocate_buffers(%p).\n", pdev); + Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev); if (pdev == NULL) return -ENXIO; @@ -315,7 +319,9 @@ for (; i < MAX_IMAGES; i++) pdev->image_ptr[i] = NULL; - Trace(TRACE_MEMORY, "Leaving pwc_allocate_buffers().\n"); + kbuf = NULL; + + Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n"); return 0; } @@ -369,6 +375,7 @@ rvfree(pdev->image_data, default_mbufs * pdev->len_per_image); } pdev->image_data = NULL; + Trace(TRACE_MEMORY, "Leaving free_buffers().\n"); } @@ -570,12 +577,10 @@ pdev->fill_image = (pdev->fill_image + 1) % default_mbufs; } -/* 2001-10-14: The YUV420 is still there, but you can only set it from within - a program (YUV420P being the default) */ +/* 2002-10-11: YUV420P is the only palette remaining. */ static int pwc_set_palette(struct pwc_device *pdev, int pal) { - if ( pal == VIDEO_PALETTE_YUV420 - || pal == VIDEO_PALETTE_YUV420P + if ( pal == VIDEO_PALETTE_YUV420P #if PWC_DEBUG || pal == VIDEO_PALETTE_RAW #endif @@ -613,7 +618,7 @@ } #endif if (urb->status == -ENOENT || urb->status == -ECONNRESET) { - Trace(TRACE_OPEN, "pwc_isoc_handler(): URB unlinked.\n"); + Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a"); return; } if (urb->status != -EINPROGRESS && urb->status != 0) { @@ -686,9 +691,22 @@ #if PWC_DEBUG Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence); #endif - pdev->drop_frames = 2; + pdev->drop_frames += 2; pdev->vframes_error++; } + if ((ptr[0] ^ pdev->vmirror) & 0x01) { + if (ptr[0] & 0x01) + Info("Snapshot button pressed.\n"); + else + Info("Snapshot button released.\n"); + } + if ((ptr[0] ^ pdev->vmirror) & 0x02) { + if (ptr[0] & 0x02) + Info("Image is mirrored.\n"); + else + Info("Image is normal.\n"); + } + pdev->vmirror = ptr[0] & 0x03; /* Sometimes the trailer of the 730 is still sent as a 4 byte packet after a short frame; this condition is filtered out specifically. A 4 byte frame doesn't make sense anyway. @@ -705,7 +723,7 @@ /* In case we were instructed to drop the frame, do so silently. The buffer pointers are not updated either (but the counters are reset below). */ - if (pdev->drop_frames) + if (pdev->drop_frames > 0) pdev->drop_frames--; else { /* Check for underflow first */ @@ -741,17 +759,23 @@ } /* .. flen < last_packet_size */ pdev->vlast_packet_size = flen; } /* ..status == 0 */ -#ifdef PWC_DEBUG +#if PWC_DEBUG /* This is normally not interesting to the user, unless you are really debugging something */ - else - Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst); + else { + static int iso_error = 0; + iso_error++; + if (iso_error < 20) + Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst); + } #endif } if (awake) wake_up_interruptible(&pdev->frameq); urb->dev = pdev->udev; - usb_submit_urb(urb, GFP_ATOMIC); + i = usb_submit_urb(urb, GFP_ATOMIC); + if (i != 0) + Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i); } @@ -762,7 +786,6 @@ int i, j, ret; struct usb_host_interface *idesc; - int cur_alt; if (pdev == NULL) return -EFAULT; @@ -770,12 +793,11 @@ return 0; pdev->vsync = 0; udev = pdev->udev; - + /* Get the current alternate interface, adjust packet size */ if (!udev->actconfig) return -EFAULT; - cur_alt = udev->actconfig->interface[0].act_altsetting; - idesc = &udev->actconfig->interface[0].altsetting[cur_alt]; + idesc = &udev->actconfig->interface[0].altsetting[pdev->valternate]; if (!idesc) return -EFAULT; @@ -792,7 +814,13 @@ return -ENFILE; /* Odd error, that should be noticable */ } + /* Set alternate interface */ ret = 0; + Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate); + ret = usb_set_interface(pdev->udev, 0, pdev->valternate); + if (ret < 0) + return ret; + for (i = 0; i < MAX_ISO_BUFS; i++) { urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); if (urb == NULL) { @@ -801,6 +829,7 @@ break; } pdev->sbuf[i].urb = urb; + Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb); } if (ret) { /* De-allocate in reverse order */ @@ -812,8 +841,7 @@ } return ret; } - - + /* init URB structure */ for (i = 0; i < MAX_ISO_BUFS; i++) { urb = pdev->sbuf[i].urb; @@ -829,7 +857,7 @@ urb->start_frame = 0; urb->number_of_packets = ISO_FRAMES_PER_DESC; for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { - urb->iso_frame_desc[j].offset = j * pdev->vmax_packet_size; + urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; urb->iso_frame_desc[j].length = pdev->vmax_packet_size; } } @@ -840,11 +868,12 @@ if (ret) Err("isoc_init() submit_urb %d failed with error %d\n", i, ret); else - Trace(TRACE_OPEN, "pwc_isoc_init(): URB submitted.\n"); + Trace(TRACE_OPEN, "URB 0x%p submitted.\n", pdev->sbuf[i].urb); } - /* data should stream in now */ + /* All is done... */ pdev->iso_init = 1; + Trace(TRACE_OPEN, "<< pwc_isoc_init()\n"); return 0; } @@ -852,21 +881,34 @@ { int i; + Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n"); if (pdev == NULL) return; - if (!pdev->iso_init) - return; + + /* Unlinking ISOC buffers one by one */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + struct urb *urb; + + urb = pdev->sbuf[i].urb; + if (urb != 0) { + if (pdev->iso_init) { + Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb); + usb_unlink_urb(urb); + } + Trace(TRACE_MEMORY, "Freeing URB\n"); + usb_free_urb(urb); + pdev->sbuf[i].urb = NULL; + } + } + /* Stop camera, but only if we are sure the camera is still there */ - if (!pdev->unplugged) + if (!pdev->unplugged) { + Trace(TRACE_OPEN, "Setting alternate interface 0.\n"); usb_set_interface(pdev->udev, 0, 0); - /* Unlinking ISOC buffers one by one */ - for (i = MAX_ISO_BUFS - 1; i >= 0; i--) { - //pdev->sbuf[i].urb->next = NULL; - usb_unlink_urb(pdev->sbuf[i].urb); - usb_free_urb(pdev->sbuf[i].urb); - pdev->sbuf[i].urb = NULL; } + pdev->iso_init = 0; + Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n"); } int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot) @@ -881,11 +923,10 @@ ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot); if (ret) /* That failed... restore old mode (we know that worked) */ ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); - else /* Set (new) alternate interface */ - ret = usb_set_interface(pdev->udev, 0, pdev->valternate); if (!ret) - ret = pwc_isoc_init(pdev); - pdev->drop_frames = 1; /* try to avoid garbage during switch */ + if (pwc_isoc_init(pdev) < 0) + Info("Failed to restart ISOC transfer in pwc_try_video_mode.\n"); + pdev->drop_frames++; /* try to avoid garbage during switch */ return ret; } @@ -921,7 +962,7 @@ struct video_device *vdev = video_devdata(file); struct pwc_device *pdev; - Trace(TRACE_OPEN, "video_open called(0x%p).\n", vdev); + Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev); pdev = (struct pwc_device *)vdev->priv; if (pdev == NULL) @@ -932,10 +973,30 @@ down(&pdev->modlock); if (!pdev->usb_init) { Trace(TRACE_OPEN, "Doing first time initialization.\n"); - /* Reset camera */ - if (usb_set_interface(pdev->udev, 0, 0)) - Info("Failed to set alternate interface to 0.\n"); pdev->usb_init = 1; + + if (pwc_trace & TRACE_OPEN) { + /* Query CMOS sensor type */ + const char *sensor_type = NULL; + + i = pwc_get_cmos_sensor(pdev); + switch(i) { + case -1: /* Unknown, show nothing */; break; + case 0x00: sensor_type = "Hyundai CMOS sensor"; break; + case 0x20: sensor_type = "Sony CCD sensor + TDA8787"; break; + case 0x2E: sensor_type = "Sony CCD sensor + Exas 98L59"; break; + case 0x2F: sensor_type = "Sony CCD sensor + ADI 9804"; break; + case 0x30: sensor_type = "Sharp CCD sensor + TDA8787"; break; + case 0x3E: sensor_type = "Sharp CCD sensor + Exas 98L59"; break; + case 0x3F: sensor_type = "Sharp CCD sensor + ADI 9804"; break; + case 0x40: sensor_type = "UPA 1021 sensor"; break; + case 0x100: sensor_type = "VGA sensor"; break; + case 0x101: sensor_type = "PAL MR sensor"; break; + default: sensor_type = "unknown type of sensor"; break; + } + if (sensor_type != NULL) + Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i); + } } /* Turn on camera */ @@ -1000,12 +1061,6 @@ return i; } - i = usb_set_interface(pdev->udev, 0, pdev->valternate); - if (i) { - Trace(TRACE_OPEN, "Failed to set alternate interface = %d.\n", i); - up(&pdev->modlock); - return -EINVAL; - } i = pwc_isoc_init(pdev); if (i) { Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i); @@ -1023,7 +1078,7 @@ if (pdev->decompressor != NULL) pdev->decompressor->lock(); up(&pdev->modlock); - Trace(TRACE_OPEN, "video_open() returning 0.\n"); + Trace(TRACE_OPEN, "<< video_open() returns 0.\n"); return 0; } @@ -1034,15 +1089,12 @@ struct pwc_device *pdev; int i; - Trace(TRACE_OPEN, "video_close called(0x%p).\n", vdev); + Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev); pdev = (struct pwc_device *)vdev->priv; if (pdev->vopen == 0) Info("video_close() called on closed device?\n"); - /* Free isoc URBs */ - pwc_isoc_cleanup(pdev); - /* Dump statistics, but only if a reasonable amount of frames were processed (to prevent endless log-entries in case of snap-shot programs) @@ -1050,15 +1102,14 @@ if (pdev->vframe_count > 20) Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error); - if (!pdev->unplugged) { - /* Normal close: stop isochronuous and interrupt endpoint */ - Trace(TRACE_OPEN, "Normal close(): setting interface to 0.\n"); - usb_set_interface(pdev->udev, 0, 0); + /* Free isoc URBs, stop camera */ + pwc_isoc_cleanup(pdev); + if (!pdev->unplugged) { /* Turn LEDs off */ if (pwc_set_leds(pdev, 0, 0) < 0) - Info("Failed to set LED on/off time..\n"); - /* Power down camere to save energy */ + Info("Failed to set LED on/off time.\n"); + /* Power down camera to save energy */ if (power_save) { i = pwc_camera_power(pdev, 0); if (i < 0) @@ -1077,6 +1128,7 @@ if (pdev->unplugged) wake_up(&pdev->remove_ok); file->private_data = NULL; + Trace(TRACE_OPEN, "<< video_close()\n"); return 0; } @@ -1514,7 +1566,6 @@ Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size); pdev = vdev->priv; - /* FIXME - audit mmap during a read */ pos = (unsigned long)pdev->image_data; while (size > 0) { page = kvirt_to_pa(pos); @@ -1547,14 +1598,14 @@ int vendor_id, product_id, type_id; int i, hint; int video_nr = -1; /* default: use next available device */ - char serial_number[30]; + char serial_number[30], *name; free_mem_leak(); /* Check if we can handle this device */ - Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", - udev->descriptor.idVendor, udev->descriptor.idProduct, - intf->altsetting->desc.bInterfaceNumber); + Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", + udev->descriptor.idVendor, udev->descriptor.idProduct, + intf->altsetting->desc.bInterfaceNumber); /* the interfaces are probed one by one. We are only interested in the video interface (0) now. @@ -1570,38 +1621,47 @@ switch (product_id) { case 0x0302: Info("Philips PCA645VC USB webcam detected.\n"); + name = "Philips 645 webcam"; type_id = 645; break; case 0x0303: Info("Philips PCA646VC USB webcam detected.\n"); + name = "Philips 646 webcam"; type_id = 646; break; case 0x0304: Info("Askey VC010 type 2 USB webcam detected.\n"); + name = "Askey VC010 webcam"; type_id = 646; break; case 0x0307: Info("Philips PCVC675K (Vesta) USB webcam detected.\n"); + name = "Philips 675 webcam"; type_id = 675; break; case 0x0308: Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); + name = "Philips 680 webcam"; type_id = 680; break; case 0x030C: Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n"); + name = "Philips 690 webcam"; type_id = 690; break; case 0x0310: Info("Philips PCVC730K (ToUCam Fun) USB webcam detected.\n"); + name = "Philips 730 webcam"; type_id = 730; break; case 0x0311: Info("Philips PCVC740K (ToUCam Pro) USB webcam detected.\n"); + name = "Philips 740 webcam"; type_id = 740; break; case 0x0312: Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n"); + name = "Philips 750 webcam"; type_id = 750; break; default: @@ -1613,6 +1673,7 @@ switch(product_id) { case 0x0001: Info("Askey VC010 type 1 USB webcam detected.\n"); + name = "Askey VC010 webcam"; type_id = 645; break; default: @@ -1623,9 +1684,25 @@ else if (vendor_id == 0x046d) { switch(product_id) { case 0x08b0: - Info("Logitech QuickCam 3000 Pro detected.\n"); + Info("Logitech QuickCam Pro 3000 USB webcam detected.\n"); + name = "Logitech QuickCam Pro 3000"; type_id = 730; - break; + break; + case 0x08b1: + Info("Logitech QuickCam for Noteboos USB webcam detected.\n"); + name = "Logitech QuickCam Notebook"; + type_id = 740; /* ?? unknown sensor */ + break; + case 0x08b2: + Info("Logitech QuickCam 4000 Pro USB webcam detected.\n"); + name = "Logitech QuickCam Pro 4000"; + type_id = 740; /* CCD sensor */ + break; + case 0x08b3: + Info("Logitech QuickCam Zoom USB webcam detected.\n"); + name = "Logitech QuickCam Zoom"; + type_id = 740; /* ?? unknown sensor */ + break; default: return -ENODEV; break; @@ -1639,10 +1716,12 @@ switch(product_id) { case 0x9000: Info("Samsung MPC-C10 USB webcam detected.\n"); + name = "Samsung MPC-C10"; type_id = 675; break; case 0x9001: Info("Samsung MPC-C30 USB webcam detected.\n"); + name = "Samsung MPC-C30"; type_id = 675; break; default: @@ -1654,6 +1733,7 @@ switch(product_id) { case 0x400c: Info("Creative Labs Webcam 5 detected.\n"); + name = "Creative Labs Webcam 5"; type_id = 730; break; default: @@ -1664,7 +1744,8 @@ else if (vendor_id == 0x04cc) { switch(product_id) { case 0x8116: - Info("SOTEC CMS-001 USB webcam detected.\n"); + Info("Sotec Afina Eye USB webcam detected.\n"); + name = "Sotec Afina Eye"; type_id = 730; break; default: @@ -1672,7 +1753,25 @@ break; } } - else return -ENODEV; /* Not Philips, Askey, Logitech, Samsung, Creative or SOTEC, for sure. */ + else if (vendor_id == 0x0d81) { + switch(product_id) { + case 0x1900: + Info("Visionite VCS-UC300 USB webcam detected.\n"); + name = "Visionite VCS-UC300"; + type_id = 740; /* CCD sensor */ + break; + case 0x1910: + Info("Visionite VCS-UM100 USB webcam detected.\n"); + name = "Visionite VCS-UM100"; + type_id = 730; /* CMOS sensor */ + break; + default: + return -ENODEV; + break; + } + } + else + return -ENODEV; /* Not any of the know types; but the list keeps growing. */ memset(serial_number, 0, 30); usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); @@ -1706,7 +1805,7 @@ return -ENOMEM; } memcpy(vdev, &pwc_template, sizeof(pwc_template)); - sprintf(vdev->name, "Philips %d webcam", pdev->type); + strcpy(vdev->name, name); SET_MODULE_OWNER(vdev); pdev->vdev = vdev; vdev->priv = pdev; @@ -1714,7 +1813,6 @@ pdev->release = udev->descriptor.bcdDevice; Trace(TRACE_PROBE, "Release: %04x\n", pdev->release); - /* Now search device_hint[] table for a match, so we can hint a node number. */ for (hint = 0; hint < MAX_DEV_HINTS; hint++) { if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) && @@ -1761,40 +1859,41 @@ dev_set_drvdata (&intf->dev, NULL); if (pdev == NULL) { Err("pwc_disconnect() Called without private pointer.\n"); - goto out_err; + goto disconnect_out; } if (pdev->udev == NULL) { Err("pwc_disconnect() already called for %p\n", pdev); - goto out_err; + goto disconnect_out; } if (pdev->udev != interface_to_usbdev(intf)) { Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n"); - goto out_err; + goto disconnect_out; } #ifdef PWC_MAGIC if (pdev->magic != PWC_MAGIC) { Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n"); - goto out_err; + goto disconnect_out; } -#endif - +#endif + pdev->unplugged = 1; if (pdev->vdev != NULL) { - video_unregister_device(pdev->vdev); + Trace(TRACE_PROBE, "Unregistering video device.\n"); + video_unregister_device(pdev->vdev); if (pdev->vopen) { Info("Disconnected while device/video is open!\n"); - + /* Wake up any processes that might be waiting for a frame, let them return an error condition */ wake_up(&pdev->frameq); - + /* Wait until we get a 'go' from _close(). This used to have a gigantic race condition, since we kfree() - stuff here, but we have to wait until close() - is finished. + stuff here, but we have to wait until close() + is finished. */ - + Trace(TRACE_PROBE, "Sleeping on remove_ok.\n"); add_wait_queue(&pdev->remove_ok, &wait); set_current_state(TASK_UNINTERRUPTIBLE); @@ -1808,26 +1907,25 @@ } else { /* Normal disconnect; remove from available devices */ - Trace(TRACE_PROBE, "Unregistering video device normally.\n"); kfree(pdev->vdev); pdev->vdev = NULL; } } +disconnect_out: /* search device_hint[] table if we occupy a slot, by any chance */ for (hint = 0; hint < MAX_DEV_HINTS; hint++) if (device_hint[hint].pdev == pdev) device_hint[hint].pdev = NULL; pdev->udev = NULL; -out_err: unlock_kernel(); kfree(pdev); } /* *grunt* We have to do atoi ourselves :-( */ -static int pwc_atoi(char *s) +static int pwc_atoi(const char *s) { int k = 0; @@ -1872,7 +1970,7 @@ MODULE_PARM(dev_hint, "0-10s"); MODULE_PARM_DESC(dev_hint, "Device node hints"); -MODULE_DESCRIPTION("Philips USB webcam driver"); +MODULE_DESCRIPTION("Philips & OEM USB webcam driver"); MODULE_AUTHOR("Nemosoft Unv. "); MODULE_LICENSE("GPL"); @@ -1882,11 +1980,12 @@ char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" }; Info("Philips PCA645/646 + PCVC675/680/690 + PCVC730/740/750 webcam module version " PWC_VERSION " loaded.\n"); - Info("Also supports the Askey VC010, Logitech Quickcam 3000 Pro, Samsung MPC-C10 and MPC-C30, the Creative WebCam 5 and the SOTEC CMS-001.\n"); + Info("Also supports the Askey VC010, various Logitech QuickCams, Samsung MPC-C10 and MPC-C30,\n"); + Info("the Creative WebCam 5, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n"); if (fps) { - if (fps < 5 || fps > 30) { - Err("Framerate out of bounds (5-30).\n"); + if (fps < 4 || fps > 30) { + Err("Framerate out of bounds (4-30).\n"); return -EINVAL; } default_fps = fps; @@ -1938,9 +2037,9 @@ if (power_save) Info("Enabling power save on open/close.\n"); if (leds[0] >= 0) - led_on = leds[0] / 100; + led_on = leds[0]; if (leds[1] >= 0) - led_off = leds[1] / 100; + led_off = leds[1]; /* Big device node whoopla. Basicly, it allows you to assign a device node (/dev/videoX) to a camera, based on its type @@ -1999,7 +2098,7 @@ device_hint[i].serial_number[k] = '\0'; } } -#ifdef PWC_DEBUG +#if PWC_DEBUG Debug("device_hint[%d]:\n", i); Debug(" type : %d\n", device_hint[i].type); Debug(" serial# : %s\n", device_hint[i].serial_number); diff -Nru a/drivers/usb/media/pwc-misc.c b/drivers/usb/media/pwc-misc.c --- a/drivers/usb/media/pwc-misc.c Wed Nov 27 12:49:43 2002 +++ b/drivers/usb/media/pwc-misc.c Wed Nov 27 12:49:43 2002 @@ -1,6 +1,6 @@ /* Linux driver for Philips webcam Various miscellaneous functions and tables. - (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) + (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl) 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 diff -Nru a/drivers/usb/media/pwc-uncompress.c b/drivers/usb/media/pwc-uncompress.c --- a/drivers/usb/media/pwc-uncompress.c Wed Nov 27 12:49:43 2002 +++ b/drivers/usb/media/pwc-uncompress.c Wed Nov 27 12:49:43 2002 @@ -1,6 +1,6 @@ /* Linux driver for Philips webcam Decompression frontend. - (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) + (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl) 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 @@ -77,7 +77,7 @@ { struct pwc_frame_buf *fbuf; int n, line, col, stride; - void *yuv, *image, *dst; + void *yuv, *image; u16 *src; u16 *dsty, *dstu, *dstv; @@ -114,19 +114,6 @@ to get the desired output format/size. */ switch (pdev->vpalette) { - case VIDEO_PALETTE_YUV420: - /* Calculate byte offsets per line in image & view */ - n = (pdev->image.x * 3) / 2; - col = (pdev->view.x * 3) / 2; - /* Offset into image */ - dst = image + (pdev->view.x * pdev->offset.y + pdev->offset.x) * 3 / 2; - for (line = 0; line < pdev->image.y; line++) { - memcpy(dst, yuv, n); - yuv += n; - dst += col; - } - break; - case VIDEO_PALETTE_YUV420P: /* * We do some byte shuffling here to go from the @@ -163,17 +150,20 @@ dstu += (stride >> 1); } break; + default: + Err("Unsupported palette!"); + break; } } else { /* Compressed; the decompressor routines will write the data - in interlaced or planar format immediately. + in planar format immediately. */ if (pdev->decompressor) pdev->decompressor->decompress( &pdev->image, &pdev->view, &pdev->offset, - yuv, image, - pdev->vpalette == VIDEO_PALETTE_YUV420P ? 1 : 0, + yuv, image, + 1, pdev->decompress_data, pdev->vbandlength); else return -ENXIO; /* No such device or address: missing decompressor */ diff -Nru a/drivers/usb/media/pwc-uncompress.h b/drivers/usb/media/pwc-uncompress.h --- a/drivers/usb/media/pwc-uncompress.h Wed Nov 27 12:49:43 2002 +++ b/drivers/usb/media/pwc-uncompress.h Wed Nov 27 12:49:43 2002 @@ -1,4 +1,4 @@ -/* (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) +/* (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl) 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 diff -Nru a/drivers/usb/media/pwc.h b/drivers/usb/media/pwc.h --- a/drivers/usb/media/pwc.h Wed Nov 27 12:49:43 2002 +++ b/drivers/usb/media/pwc.h Wed Nov 27 12:49:43 2002 @@ -60,8 +60,8 @@ /* Version block */ #define PWC_MAJOR 8 -#define PWC_MINOR 7 -#define PWC_VERSION "8.7" +#define PWC_MINOR 9 +#define PWC_VERSION "8.9" #define PWC_NAME "pwc" /* Turn certain features on/off */ @@ -130,7 +130,7 @@ int vcinterface; /* video control interface */ int valternate; /* alternate interface needed */ int vframes, vsize; /* frames-per-second & size (see PSZ_*) */ - int vpalette; /* YUV, RGB24, RGB32, etc */ + int vpalette; /* YUV */ int vframe_count; /* received frames */ int vframes_dumped; /* counter for dumped frames */ int vframes_error; /* frames received in error */ @@ -140,7 +140,8 @@ int vbandlength; /* compressed band length; 0 is uncompressed */ char vsnapshot; /* snapshot mode */ char vsync; /* used by isoc handler */ - + char vmirror; /* for ToUCaM series */ + /* The image acquisition requires 3 to 4 steps: 1. data is gathered in short packets from the USB controller 2. data is synchronized and packed into a frame buffer