]> git.hungrycats.org Git - linux/commitdiff
[PATCH] [PATCH] PWC 8.9
authorNemosoft Unv. <nemosoft@smcc.demon.nl>
Wed, 27 Nov 2002 01:46:14 +0000 (17:46 -0800)
committerGreg Kroah-Hartman <greg@kroah.com>
Wed, 27 Nov 2002 01:46:14 +0000 (17:46 -0800)
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'.

drivers/usb/media/Kconfig
drivers/usb/media/pwc-ctrl.c
drivers/usb/media/pwc-if.c
drivers/usb/media/pwc-misc.c
drivers/usb/media/pwc-uncompress.c
drivers/usb/media/pwc-uncompress.h
drivers/usb/media/pwc.h

index b002ead8c4be131d7c164fcb10d7d41612d27260..a179a8649c63e568ee3151602911259f6cd79c3f 100644 (file)
@@ -120,15 +120,26 @@ config USB_PWC
        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.
-
-         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
+         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 (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 <file:Documentation/usb/philips.txt> for more information and
index 71337853115d63b373e1078e319474152ce98fc2..6244117a470fc0d934ba2f8f4c51f19b9e69688f 100644 (file)
@@ -256,8 +256,10 @@ static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int fra
 
        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 @@ int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
        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 @@ int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
                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 @@ static inline int pwc_get_dynamic_noise(struct pwc_device *pdev)
        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 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 
        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;
        }
 
index f630ff649fd46b11bb53ee285c663b401f504326..2ceefe446df321ff2f6860222398e479b9097734 100644 (file)
@@ -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
    - 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 <linux/errno.h>
 #include <linux/init.h>
+#include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/poll.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/wrapper.h>
-#include <linux/mm.h>
 #include <asm/io.h>
 
 #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 @@ static struct usb_device_id pwc_device_table [] = {
        { 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_fbufs = 3;   /* Default number of frame buffers */
 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 @@ static struct video_device pwc_template = {
    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 @@ static int pwc_allocate_buffers(struct pwc_device *pdev)
        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 @@ static int pwc_allocate_buffers(struct pwc_device *pdev)
        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 @@ static void pwc_free_buffers(struct pwc_device *pdev)
                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 @@ static inline void pwc_next_image(struct pwc_device *pdev)
        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 @@ static void pwc_isoc_handler(struct urb *urb)
        }
 #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 @@ static void pwc_isoc_handler(struct urb *urb)
 #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 @@ static void pwc_isoc_handler(struct urb *urb)
                                        /* 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 @@ static void pwc_isoc_handler(struct urb *urb)
                        } /* .. 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 @@ static int pwc_isoc_init(struct pwc_device *pdev)
        int i, j, ret;
 
        struct usb_host_interface *idesc;
-       int cur_alt;
 
        if (pdev == NULL)
                return -EFAULT;
@@ -770,12 +793,11 @@ static int pwc_isoc_init(struct pwc_device *pdev)
                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 @@ static int pwc_isoc_init(struct pwc_device *pdev)
                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 @@ static int pwc_isoc_init(struct pwc_device *pdev)
                        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 @@ static int pwc_isoc_init(struct pwc_device *pdev)
                }
                return ret;
        }
-       
-       
+
        /* init URB structure */        
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                urb = pdev->sbuf[i].urb;
@@ -829,7 +857,7 @@ static int pwc_isoc_init(struct pwc_device *pdev)
                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 @@ static int pwc_isoc_init(struct pwc_device *pdev)
                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 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev)
 {
        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 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f
        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 @@ static int pwc_video_open(struct inode *inode, struct file *file)
        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 @@ static int pwc_video_open(struct inode *inode, struct file *file)
        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 @@ static int pwc_video_open(struct inode *inode, struct file *file)
                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 @@ static int pwc_video_open(struct inode *inode, struct file *file)
        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 @@ static int pwc_video_close(struct inode *inode, struct file *file)
        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 @@ static int pwc_video_close(struct inode *inode, struct file *file)
        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 @@ static int pwc_video_close(struct inode *inode, struct file *file)
        if (pdev->unplugged)
                wake_up(&pdev->remove_ok);
        file->private_data = NULL;
+       Trace(TRACE_OPEN, "<< video_close()\n");
        return 0;
 }
 
@@ -1514,7 +1566,6 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
        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 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        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 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                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 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                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 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        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 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                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 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                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 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        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 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                        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 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                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 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        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 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
        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 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
                }
                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_DESC(leds, "LED on,off time in milliseconds");
 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. <nemosoft@smcc.demon.nl>");
 MODULE_LICENSE("GPL");
 
@@ -1882,11 +1980,12 @@ static int __init usb_pwc_init(void)
        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 @@ static int __init usb_pwc_init(void)
        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 @@ static int __init usb_pwc_init(void)
                                        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);
index 254da4186dd517a917b9b8a01c7fe84d5b1b893e..ecb57de7f586f81c6f966f8a8aaa7109b2f79528 100644 (file)
@@ -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
index 69f3688359ca8613b0c918a5ebedca0de5b7854d..b34074e5d40d71b964a8fb8fbcb364d860e6ae0f 100644 (file)
@@ -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 @@ int pwc_decompress(struct pwc_device *pdev)
 {
        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 @@ int pwc_decompress(struct pwc_device *pdev)
                   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 @@ int pwc_decompress(struct pwc_device *pdev)
                                        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 */
index d6220cf828634f4fdb407441c4bd66f46d5eee81..58c32aab0792dd909b4445fdf1698fb9eef0b48e 100644 (file)
@@ -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
index 63856cb7b8a02cc439b73000f38719804cbfb4e9..913f2d4aa193fada54f3ead28b86c760f791a7f5 100644 (file)
@@ -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 @@ struct pwc_device
    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 @@ struct pwc_device
    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