ChangeSet 1.811.1.12, 2002/12/16 10:45:23-08:00, nemosoft@smcc.demon.nl [PATCH] USB: PWC 8.10 for 2.4.20 Well, two patches in one... These patches will bring the PWC (Philips Webcam) driver in both 2.4.20 and 2.5.51 up to version 8.10. Functionally, the two branches are the same (about 70% of the code is shared), but the differences in kernel architecture are too large to handle with a few #ifdefs. This patch fixes the following (this are only the differences between 8.9 and 8.10): * Fixed ID for QuickCam Notebook pro * Added GREALSIZE ioctl() call * Fixed bug in case PWCX was not loaded and invalid size was set diff -Nru a/drivers/usb/pwc-ctrl.c b/drivers/usb/pwc-ctrl.c --- a/drivers/usb/pwc-ctrl.c Mon Dec 16 16:33:59 2002 +++ b/drivers/usb/pwc-ctrl.c Mon Dec 16 16:33:59 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); @@ -444,8 +446,8 @@ Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames); else { Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); - return ret; } + return ret; } pdev->view.x = width; pdev->view.y = height; @@ -997,7 +999,7 @@ &buf, 1, HZ / 2); if (ret < 0) - return ret; + return ret; return (buf << 8); } @@ -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; @@ -1252,7 +1243,7 @@ int ret; unsigned char buf; - ret = RecvControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); + ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); if (ret < 0) return ret; return buf; @@ -1276,10 +1267,9 @@ int ret; unsigned char buf; - ret = RecvControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); + 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; } @@ -1595,6 +1585,16 @@ break; } + case VIDIOCPWCGREALSIZE: + { + struct pwc_imagesize size; + + size.width = pdev->image.x; + size.height = pdev->image.y; + if (copy_to_user(arg, &size, sizeof(size))) + ret = -EFAULT; + break; + } default: ret = -ENOIOCTLCMD; diff -Nru a/drivers/usb/pwc-if.c b/drivers/usb/pwc-if.c --- a/drivers/usb/pwc-if.c Mon Dec 16 16:33:59 2002 +++ b/drivers/usb/pwc-if.c Mon Dec 16 16:33:59 2002 @@ -42,11 +42,15 @@ - 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 @@ -58,10 +62,6 @@ #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 */ @@ -76,10 +76,13 @@ { USB_DEVICE(0x0471, 0x0311) }, { USB_DEVICE(0x0471, 0x0312) }, { USB_DEVICE(0x069A, 0x0001) }, /* Askey */ - { USB_DEVICE(0x046D, 0x08b0) }, /* Logitech */ + { USB_DEVICE(0x046D, 0x08b0) }, /* Logitech QuickCam Pro 3000 */ + { USB_DEVICE(0x046D, 0x08b1) }, /* Logitech QuickCam Notebook Pro */ + { 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) }, /* Creative */ + { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */ { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */ { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */ { USB_DEVICE(0x0d81, 0x1900) }, @@ -127,7 +130,7 @@ static long pwc_video_write(struct video_device *vdev, const char *buf, unsigned long count, int noblock); static unsigned int pwc_video_poll(struct video_device *vdev, struct file *file, poll_table *wait); static int pwc_video_ioctl(struct video_device *vdev, unsigned int cmd, void *arg); -static int pwc_video_mmap(struct video_device *dev, const char *adr, unsigned long size); +static int pwc_video_mmap(struct video_device *vdev, const char *adr, unsigned long size); static struct video_device pwc_template = { owner: THIS_MODULE, @@ -238,7 +241,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 +318,7 @@ kbuf = NULL; - Trace(TRACE_MEMORY, "Leaving pwc_allocate_buffers().\n"); + Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n"); return 0; } @@ -592,7 +595,7 @@ /* This gets called for the Isochronous pipe (video). This is done in * interrupt time, so it has to be fast, not crash, and not stall. Neat. */ -static void pwc_isoc_handler(struct urb *urb) +static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs) { struct pwc_device *pdev; int i, fst, flen; @@ -612,7 +615,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) { @@ -685,9 +688,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. @@ -704,7 +720,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 */ @@ -740,10 +756,14 @@ } /* .. 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) @@ -758,7 +778,6 @@ int i, j, ret; struct usb_interface_descriptor *idesc; - int cur_alt; if (pdev == NULL) return -EFAULT; @@ -766,12 +785,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; @@ -783,12 +801,18 @@ break; } - if (pdev->vmax_packet_size < 0) { + if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) { Err("Failed to find packet size for video endpoint in current alternate setting.\n"); 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); if (urb == NULL) { @@ -797,6 +821,7 @@ break; } pdev->sbuf[i].urb = urb; + Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb); } if (ret) { /* De-allocate in reverse order */ @@ -808,8 +833,7 @@ } return ret; } - - + /* init URB structure */ for (i = 0; i < MAX_ISO_BUFS; i++) { urb = pdev->sbuf[i].urb; @@ -826,7 +850,7 @@ urb->number_of_packets = ISO_FRAMES_PER_DESC; for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; - urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE; + urb->iso_frame_desc[j].length = pdev->vmax_packet_size; } } @@ -836,11 +860,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; } @@ -848,21 +873,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) @@ -876,11 +914,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 transfers in pwc_try_video_mode.\n"); + pdev->drop_frames++; /* try to avoid garbage during switch */ return ret; } @@ -915,20 +952,19 @@ int i; struct pwc_device *pdev; - Trace(TRACE_OPEN, "video_open called(0x%p, 0%o).\n", vdev, mode); + Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev); if (vdev == NULL) BUG(); pdev = (struct pwc_device *)vdev->priv; if (pdev == NULL) BUG(); + if (pdev->vopen) + return -EBUSY; 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) { @@ -948,10 +984,10 @@ 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; + default: sensor_type = "unknown type of sensor"; break; } if (sensor_type != NULL) - Info("Thes %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i); + Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i); } } @@ -1017,16 +1053,9 @@ 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); - MOD_DEC_USE_COUNT; up(&pdev->modlock); return i; } @@ -1039,7 +1068,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; } @@ -1049,15 +1078,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) @@ -1065,21 +1091,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) { - /* The device was unplugged or some other error occured */ - /* We unregister the video_device */ - Trace(TRACE_OPEN, "Delayed video device unregistered.\n"); - video_unregister_device(pdev->vdev); - } - else { - /* 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) @@ -1097,6 +1116,7 @@ /* wake up _disconnect() routine */ if (pdev->unplugged) wake_up(&pdev->remove_ok); + Trace(TRACE_OPEN, "<< video_close()\n"); } /* @@ -1495,8 +1515,8 @@ set_current_state(TASK_RUNNING); return -ERESTARTSYS; } - schedule(); set_current_state(TASK_INTERRUPTIBLE); + schedule(); } remove_wait_queue(&pdev->frameq, &wait); set_current_state(TASK_RUNNING); @@ -1574,8 +1594,6 @@ Trace(TRACE_MEMORY, "mmap(0x%p, 0x%p, %lu) called.\n", vdev, adr, size); pdev = vdev->priv; - /* FIXME - audit mmap during a read */ - /* Nemo: 9 months and 20 kernel revisions later I still don't know what you mean by this :-) */ pos = (unsigned long)pdev->image_data; while (size > 0) { page = kvirt_to_pa(pos); @@ -1691,10 +1709,25 @@ else if (vendor_id == 0x046d) { switch(product_id) { case 0x08b0: - Info("Logitech QuickCam 3000 Pro USB webcam detected.\n"); - name = "Logitech QuickCam 3000 Pro"; + 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 Notebook Pro USB webcam detected.\n"); + name = "Logitech QuickCam Notebook Pro"; + 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; /* CCD sensor */ + break; default: return NULL; break; @@ -1868,6 +1901,8 @@ pdev->unplugged = 1; if (pdev->vdev != NULL) { + Trace(TRACE_PROBE, "Unregistering video device.\n"); + video_unregister_device(pdev->vdev); if (pdev->vopen) { Info("Disconnected while device/video is open!\n"); @@ -1895,8 +1930,6 @@ } else { /* Normal disconnect; remove from available devices */ - Trace(TRACE_PROBE, "Unregistering video device normally.\n"); - video_unregister_device(pdev->vdev); kfree(pdev->vdev); pdev->vdev = NULL; } @@ -1914,7 +1947,7 @@ /* *grunt* We have to do atoi ourselves :-( */ -static int pwc_atoi(char *s) +static int pwc_atoi(const char *s) { int k = 0; @@ -1959,7 +1992,7 @@ MODULE_PARM(dev_hint, "0-10s"); MODULE_PARM_DESC(dev_hint, "Device node hints"); -MODULE_DESCRIPTION("Philips USB webcam driver"); +MODULE_DESCRIPTION("Philips USB & OEM webcam driver"); MODULE_AUTHOR("Nemosoft Unv. "); MODULE_LICENSE("GPL"); @@ -1969,7 +2002,7 @@ 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,\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) { @@ -2087,7 +2120,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/pwc-ioctl.h b/drivers/usb/pwc-ioctl.h --- a/drivers/usb/pwc-ioctl.h Mon Dec 16 16:33:59 2002 +++ b/drivers/usb/pwc-ioctl.h Mon Dec 16 16:33:59 2002 @@ -18,12 +18,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* This is pwc-ioctl.h belonging to PWC 8.6 */ +/* This is pwc-ioctl.h belonging to PWC 8.10 */ /* Changes 2001/08/03 Alvarado Added ioctl constants to access methods for changing white balance and red/blue gains + 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE */ /* These are private ioctl() commands, specific for the Philips webcams. @@ -104,7 +105,12 @@ int led_off; /* Led off-time; range = 0..25000 */ }; - +/* Image size (used with GREALSIZE) */ +struct pwc_imagesize +{ + int width; + int height; +}; /* Restore user settings */ #define VIDIOCPWCRUSER _IO('v', 192) @@ -173,4 +179,7 @@ #define VIDIOCPWCSDYNNOISE _IOW('v', 209, int) #define VIDIOCPWCGDYNNOISE _IOR('v', 209, int) + /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */ +#define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize) + #endif diff -Nru a/drivers/usb/pwc-uncompress.c b/drivers/usb/pwc-uncompress.c --- a/drivers/usb/pwc-uncompress.c Mon Dec 16 16:33:59 2002 +++ b/drivers/usb/pwc-uncompress.c Mon Dec 16 16:33:59 2002 @@ -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/pwc.h b/drivers/usb/pwc.h --- a/drivers/usb/pwc.h Mon Dec 16 16:33:59 2002 +++ b/drivers/usb/pwc.h Mon Dec 16 16:33:59 2002 @@ -60,8 +60,8 @@ /* Version block */ #define PWC_MAJOR 8 -#define PWC_MINOR 6 -#define PWC_VERSION "8.6" +#define PWC_MINOR 10 +#define PWC_VERSION "8.10" #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