On Fri, Mar 22, 2002 at 03:59:32PM -0800, Greg KH wrote:
> [EMAIL PROTECTED], 2002-03-22 14:49:47-08:00, [EMAIL PROTECTED]
>   USB pwc driver
>     
>   Well, this driver is nearing its completion... With this latest patch,
>   nearly all of the extended features that the cameras support are available.
>   About time :)
>       
>   This is the changelog:
>       
>   * Added ID's for Visionite VCS UM100 and UC300
>   * Removed YUV420-interlaced palette altogether (was confusing)
>   * Removed MIRROR stuff as it didn't work anyway
>   * Fixed a problem with the 'leds' parameter (wouldn't blink)
>   * Added ioctl()s for advanced features: 'extended' whitebalance ioctl()s,
>     CONTOUR, BACKLIGHT, FLICKER, DYNNOISE.
>   * VIDIOCGCAP.name now contains real camera model name instead of
>     'Philips xxx webcam'
>   * Added PROBE ioctl (see previous point & API doc)
> 
>  drivers/usb/pwc-ctrl.c       |  515 +++++++++++++++++++++++++++++++++++++------
>  drivers/usb/pwc-if.c         |  113 +++++++--
>  drivers/usb/pwc-ioctl.h      |   65 ++++-
>  drivers/usb/pwc-misc.c       |    2 
>  drivers/usb/pwc-uncompress.c |    2 
>  drivers/usb/pwc-uncompress.h |    6 
>  drivers/usb/pwc.h            |    9 
>  7 files changed, 605 insertions(+), 107 deletions(-)


# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#                  ChangeSet    1.230   -> 1.231  
#       drivers/usb/pwc-uncompress.c    1.3     -> 1.4    
#          drivers/usb/pwc.h    1.10    -> 1.11   
#       drivers/usb/pwc-uncompress.h    1.2     -> 1.3    
#       drivers/usb/pwc-misc.c  1.3     -> 1.4    
#       drivers/usb/pwc-ioctl.h 1.4     -> 1.5    
#       drivers/usb/pwc-if.c    1.9     -> 1.10   
#       drivers/usb/pwc-ctrl.c  1.8     -> 1.9    
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/03/22      [EMAIL PROTECTED]  1.231
# USB pwc driver
#   
# Well, this driver is nearing its completion... With this latest patch,
# nearly all of the extended features that the cameras support are available.
# About time :)
#     
# This is the changelog:
#     
# * Added ID's for Visionite VCS UM100 and UC300
# * Removed YUV420-interlaced palette altogether (was confusing)
# * Removed MIRROR stuff as it didn't work anyway
# * Fixed a problem with the 'leds' parameter (wouldn't blink)
# * Added ioctl()s for advanced features: 'extended' whitebalance ioctl()s,
#   CONTOUR, BACKLIGHT, FLICKER, DYNNOISE.
# * VIDIOCGCAP.name now contains real camera model name instead of
#   'Philips xxx webcam'
# * Added PROBE ioctl (see previous point & API doc)
# --------------------------------------------
#
diff -Nru a/drivers/usb/pwc-ctrl.c b/drivers/usb/pwc-ctrl.c
--- a/drivers/usb/pwc-ctrl.c    Fri Mar 22 15:48:02 2002
+++ b/drivers/usb/pwc-ctrl.c    Fri Mar 22 15:48:02 2002
@@ -1,7 +1,7 @@
 /* Driver for Philips webcam
    Functions that send various control messages to the webcam, including
    video modes.
-   (C) 1999-2001 Nemosoft Unv. ([EMAIL PROTECTED])
+   (C) 1999-2002 Nemosoft Unv. ([EMAIL PROTECTED])
 
    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
@@ -78,10 +78,12 @@
 #define READ_SHUTTER_FORMATTER                 0x0600
 #define READ_RED_GAIN_FORMATTER                        0x0700
 #define READ_BLUE_GAIN_FORMATTER               0x0800
+#define SENSOR_TYPE_FORMATTER1                 0x0C00
 #define READ_RAW_Y_MEAN_FORMATTER              0x3100
 #define SET_POWER_SAVE_MODE_FORMATTER          0x3200
 #define MIRROR_IMAGE_FORMATTER                 0x3300
 #define LED_FORMATTER                          0x3400
+#define SENSOR_TYPE_FORMATTER2                 0x3700
 
 /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
 #define VIDEO_OUTPUT_CONTROL_FORMATTER         0x0100
@@ -162,6 +164,21 @@
 /****************************************************************************/
 
 
+#define SendControlMsg(request, value, buflen) \
+       usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \
+               request, \
+               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
+               value, \
+               pdev->vcinterface, \
+               &buf, buflen, HZ / 2)
+
+#define RecvControlMsg(request, value, buflen) \
+       usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \
+               request, \
+               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
+               value, \
+               pdev->vcinterface, \
+               &buf, buflen, HZ / 2)
 
 
 #if PWC_DEBUG
@@ -241,7 +258,7 @@
        ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3);
        if (ret < 0)
                return ret;
-       if (pEntry->compressed)
+       if (pEntry->compressed && pdev->decompressor != NULL)
                pdev->decompressor->init(pdev->release, buf, pdev->decompress_data);
                
        /* Set various parameters */
@@ -911,7 +928,7 @@
        int ret;
        
        ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
-               GET_STATUS_CTL, 
+               GET_CHROM_CTL, 
                USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                PRESET_MANUAL_RED_GAIN_FORMATTER,
                pdev->vcinterface,
@@ -950,7 +967,7 @@
        int ret;
        
        ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
-               GET_STATUS_CTL,
+               GET_CHROM_CTL,
                USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                PRESET_MANUAL_BLUE_GAIN_FORMATTER,
                pdev->vcinterface,
@@ -962,6 +979,7 @@
        return (buf << 8);
 }
 
+
 /* The following two functions are different, since they only read the
    internal red/blue gains, which may be different from the manual 
    gains set or read above.
@@ -997,11 +1015,74 @@
                &buf, 1, HZ / 2);
 
        if (ret < 0)
-           return ret;
+               return ret;
        
        return (buf << 8);
 }
 
+
+static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
+{
+       unsigned char buf;
+       
+       /* useful range is 0x01..0x20 */
+       buf = speed / 0x7f0;
+       return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
+               SET_CHROM_CTL,
+               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               AWB_CONTROL_SPEED_FORMATTER,
+               pdev->vcinterface,
+               &buf, 1, HZ / 2);
+}
+
+static inline int pwc_get_wb_speed(struct pwc_device *pdev)
+{
+       unsigned char buf;
+       int ret;
+       
+       ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
+               GET_CHROM_CTL,
+               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               AWB_CONTROL_SPEED_FORMATTER,
+               pdev->vcinterface,
+               &buf, 1, HZ / 2);
+       if (ret < 0)
+               return ret;
+       return (buf * 0x7f0);
+}
+
+
+static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
+{
+       unsigned char buf;
+       
+       /* useful range is 0x01..0x3F */
+       buf = (delay >> 10);
+       return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
+               SET_CHROM_CTL,
+               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               AWB_CONTROL_DELAY_FORMATTER,
+               pdev->vcinterface,
+               &buf, 1, HZ / 2);
+}
+
+static inline int pwc_get_wb_delay(struct pwc_device *pdev)
+{
+       unsigned char buf;
+       int ret;
+       
+       ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
+               GET_CHROM_CTL,
+               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               AWB_CONTROL_DELAY_FORMATTER,
+               pdev->vcinterface,
+               &buf, 1, HZ / 2);
+       if (ret < 0)
+               return ret;
+       return (buf << 10);
+}
+
+
 int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
 {
        unsigned char buf[2];
@@ -1055,53 +1136,242 @@
        return 0;
 }
 
+static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
+{
+       unsigned char buf;
+       int ret;
+       
+       if (contour < 0)
+               buf = 0xff; /* auto contour on */
+       else
+               buf = 0x0; /* auto contour off */
+       ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
+               SET_LUM_CTL,
+               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               AUTO_CONTOUR_FORMATTER,
+               pdev->vcinterface,
+               &buf, 1, HZ / 2);
+       if (ret < 0)
+               return ret;
+       
+       if (contour < 0)
+               return 0;
+       if (contour > 0xffff)
+               contour = 0xffff;
+       
+       buf = (contour >> 10); /* contour preset is [0..3f] */
+       ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
+               SET_LUM_CTL,
+               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               PRESET_CONTOUR_FORMATTER,
+               pdev->vcinterface,
+               &buf, 1, HZ / 2);
+       if (ret < 0)    
+               return ret;     
+       return 0;
+}
+
+static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
+{
+       unsigned char buf;
+       int ret;
+       
+       ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
+               GET_LUM_CTL,
+               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               AUTO_CONTOUR_FORMATTER,
+               pdev->vcinterface,
+               &buf, 1, HZ / 2);
+       if (ret < 0)
+               return ret;
+
+       if (buf == 0) {
+               /* auto mode off, query current preset value */
+               ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
+                       GET_LUM_CTL,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       PRESET_CONTOUR_FORMATTER,
+                       pdev->vcinterface,
+                       &buf, 1, HZ / 2);
+               if (ret < 0)    
+                       return ret;
+               *contour =  (buf << 10);
+       }
+       else
+               *contour = -1;
+       return 0;
+}
+
+
+static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
+{
+       unsigned char buf;
+       
+       if (backlight)
+               buf = 0xff;
+       else
+               buf = 0x0;
+       return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
+               SET_LUM_CTL,
+               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               BACK_LIGHT_COMPENSATION_FORMATTER,
+               pdev->vcinterface,
+               &buf, 1, HZ / 2);
+}
+
+static inline int pwc_get_backlight(struct pwc_device *pdev)
+{
+       int ret;
+       unsigned char buf;
+       
+       ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
+               GET_LUM_CTL,
+               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               BACK_LIGHT_COMPENSATION_FORMATTER,
+               pdev->vcinterface,
+               &buf, 1, HZ / 2);
+       if (ret < 0)
+               return ret;
+       return buf;
+}
+
+
+static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
+{
+       unsigned char buf;
+       
+       if (flicker)
+               buf = 0xff;
+       else
+               buf = 0x0;
+       return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
+}
+
+static inline int pwc_get_flicker(struct pwc_device *pdev)
+{
+       int ret;
+       unsigned char buf;
+       
+       ret = RecvControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       return buf;
+}
+
+
+static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
+{
+       unsigned char buf;
+
+       if (noise < 0)
+               noise = 0;
+       if (noise > 3)
+               noise = 3;
+       buf = noise;
+       return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
+}
+
+static inline int pwc_get_dynamic_noise(struct pwc_device *pdev)
+{
+       int ret;
+       unsigned char buf;
+       
+       ret = RecvControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+Debug("pwc_get_dynamic_noise = %d\n", buf);
+       return buf;
+}
+
+
+int pwc_get_cmos_sensor(struct pwc_device *pdev)
+{
+       unsigned char buf;
+       int ret = -1, request;
+       
+       if (pdev->type < 675)
+               request = SENSOR_TYPE_FORMATTER1;
+       else if (pdev->type < 730)
+               return -1; /* The Vesta series doesn't have this call */
+       else
+               request = SENSOR_TYPE_FORMATTER2;
+       
+       ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
+               GET_STATUS_CTL,
+               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               request,
+               pdev->vcinterface,
+               &buf, 1, HZ / 2);
+       if (ret < 0)
+               return ret;
+       if (pdev->type < 675)
+               return buf | 0x100;
+       else
+               return buf;
+}
+
+
  /* End of Add-Ons                                    */
  /* ************************************************* */
 
 int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 {
+       int ret = 0;
+
        switch(cmd) {
        case VIDIOCPWCRUSER:
        {
                if (pwc_restore_user(pdev))
-                       return -EINVAL;
+                       ret = -EINVAL;
                break;
        }
        
        case VIDIOCPWCSUSER:
        {
                if (pwc_save_user(pdev))
-                       return -EINVAL;
+                       ret = -EINVAL;
                break;
        }
                
        case VIDIOCPWCFACTORY:
        {
                if (pwc_restore_factory(pdev))
-                       return -EINVAL;
+                       ret = -EINVAL;
                break;
        }
        
        case VIDIOCPWCSCQUAL:
        {       
-               int qual, ret;
+               int qual;
 
                if (copy_from_user(&qual, arg, sizeof(int)))
-                       return -EFAULT;
-                       
-               if (qual < 0 || qual > 3)
-                       return -EINVAL;
-               ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, 
pdev->vframes, qual, pdev->vsnapshot);
-               if (ret < 0)
-                       return ret;
-               pdev->vcompression = qual;
+                       ret = -EFAULT;
+               else {
+                       if (qual < 0 || qual > 3)
+                               ret = -EINVAL;
+                       else
+                               ret = pwc_try_video_mode(pdev, pdev->view.x, 
+pdev->view.y, pdev->vframes, qual, pdev->vsnapshot);
+                       if (ret >= 0)
+                               pdev->vcompression = qual;
+               }
                break;
        }
        
        case VIDIOCPWCGCQUAL:
        {
                if (copy_to_user(arg, &pdev->vcompression, sizeof(int)))
-                       return -EFAULT;
+                       ret = -EFAULT;
+               break;
+       }
+
+       case VIDIOCPWCPROBE:
+       {
+               struct pwc_probe probe;
+               
+               strcpy(probe.name, pdev->vdev->name);
+               probe.type = pdev->type;
+               if (copy_to_user(arg, &probe, sizeof(probe)))
+                       ret = -EFAULT;
                break;
        }
 
@@ -1110,10 +1380,10 @@
                int agc;
                
                if (copy_from_user(&agc, arg, sizeof(agc)))
-                       return -EFAULT; 
+                       ret = -EFAULT;  
                else {
                        if (pwc_set_agc(pdev, agc < 0 ? 1 : 0, agc))
-                               return -EINVAL;
+                               ret = -EINVAL;
                }
                break;
        }
@@ -1123,42 +1393,36 @@
                int agc;
                
                if (pwc_get_agc(pdev, &agc))
-                       return -EINVAL;
-               if (copy_to_user(arg, &agc, sizeof(agc)))
-                       return -EFAULT;
+                       ret = -EINVAL;
+               else
+                       if (copy_to_user(arg, &agc, sizeof(agc)))
+                               ret = -EFAULT;
                break;
        }
        
        case VIDIOCPWCSSHUTTER:
        {
-               int shutter_speed, ret;
+               int shutter_speed;
 
                if (copy_from_user(&shutter_speed, arg, sizeof(shutter_speed)))
-                       return -EFAULT;
-               else {
+                       ret = -EFAULT;
+               else
                        ret = pwc_set_shutter_speed(pdev, shutter_speed < 0 ? 1 : 0, 
shutter_speed);
-                       if (ret < 0)
-                               return ret;
-               }
                break;
        }
        
-
- /* ************************************************* */
- /* Begin of Add-Ons for color compensation           */
-
         case VIDIOCPWCSAWB:
        {
                struct pwc_whitebalance wb;
-               int ret;
                
                if (copy_from_user(&wb, arg, sizeof(wb)))
-                       return -EFAULT;
-       
-               ret = pwc_set_awb(pdev, wb.mode);
-               if (ret >= 0 && wb.mode == PWC_WB_MANUAL) {
-                       pwc_set_red_gain(pdev, wb.manual_red);
-                       pwc_set_blue_gain(pdev, wb.manual_blue);
+                       ret = -EFAULT;
+               else {
+                       ret = pwc_set_awb(pdev, wb.mode);
+                       if (ret >= 0 && wb.mode == PWC_WB_MANUAL) {
+                               pwc_set_red_gain(pdev, wb.manual_red);
+                               pwc_set_blue_gain(pdev, wb.manual_blue);
+                       }
                }
                break;
        }
@@ -1170,55 +1434,176 @@
                memset(&wb, 0, sizeof(wb));
                wb.mode = pwc_get_awb(pdev);
                if (wb.mode < 0)
-                       return -EINVAL;
-               wb.manual_red = pwc_get_red_gain(pdev);
-               wb.manual_blue = pwc_get_blue_gain(pdev);
-               if (wb.mode == PWC_WB_AUTO) {
-                       wb.read_red = pwc_read_red_gain(pdev);
-                       wb.read_blue = pwc_read_blue_gain(pdev);
+                       ret = -EINVAL;
+               else {
+                       if (wb.mode == PWC_WB_MANUAL) {
+                               wb.manual_red = pwc_get_red_gain(pdev);
+                               wb.manual_blue = pwc_get_blue_gain(pdev);
+                       }
+                       if (wb.mode == PWC_WB_AUTO) {
+                               wb.read_red = pwc_read_red_gain(pdev);
+                               wb.read_blue = pwc_read_blue_gain(pdev);
+                       }
+                       if (copy_to_user(arg, &wb, sizeof(wb)))
+                               ret= -EFAULT;
                }
-               if (copy_to_user(arg, &wb, sizeof(wb)))
-                       return -EFAULT;
+               break;
+       }
+       
+       case VIDIOCPWCSAWBSPEED:
+       {
+               struct pwc_wb_speed wbs;
+               
+               if (copy_from_user(&wbs, arg, sizeof(wbs)))
+                       ret = -EFAULT;
+               else {
+                       if (wbs.control_speed > 0) {
+                               ret = pwc_set_wb_speed(pdev, wbs.control_speed);
+                       }
+                       if (wbs.control_delay > 0) {
+                               ret = pwc_set_wb_delay(pdev, wbs.control_delay);
+                       }
+               }
+               break;
+       }
+       
+       case VIDIOCPWCGAWBSPEED:
+       {
+               struct pwc_wb_speed wbs;
+               
+               ret = pwc_get_wb_speed(pdev);
+               if (ret < 0)
+                       break;
+               wbs.control_speed = ret;
+               ret = pwc_get_wb_delay(pdev);
+               if (ret < 0)
+                       break;
+               wbs.control_delay = ret;
+               if (copy_to_user(arg, &wbs, sizeof(wbs)))
+                       ret = -EFAULT;
                break;
        }
 
         case VIDIOCPWCSLED:
        {
-               int ret;
                struct pwc_leds leds;
 
                if (copy_from_user(&leds, arg, sizeof(leds)))
-                       return -EFAULT;
-
-               ret = pwc_set_leds(pdev, leds.led_on, leds.led_off);
-               if (ret<0)
-                   return ret;
-           break;
+                       ret = -EFAULT;
+               else
+                       ret = pwc_set_leds(pdev, leds.led_on, leds.led_off);
+               break;
        }
 
 
-
        case VIDIOCPWCGLED:
        {
-               int led;
                struct pwc_leds leds;
                
-               led = pwc_get_leds(pdev, &leds.led_on, &leds.led_off); 
-               if (led < 0)
-                       return -EINVAL;
+               ret = pwc_get_leds(pdev, &leds.led_on, &leds.led_off); 
+               if (ret < 0)
+                       break;
                if (copy_to_user(arg, &leds, sizeof(leds)))
-                       return -EFAULT;
+                       ret = -EFAULT;
                break;
        }
 
- /* End of Add-Ons                                    */
- /* ************************************************* */
+       case VIDIOCPWCSCONTOUR:
+       {
+               int contour;
+               
+               if (copy_from_user(&contour, arg, sizeof(contour)))
+                       ret = -EFAULT;
+               else
+                       ret = pwc_set_contour(pdev, contour);
+               break;
+       }
+                       
+       case VIDIOCPWCGCONTOUR:
+       {
+               int contour;
+               
+               ret = pwc_get_contour(pdev, &contour);
+               if (ret < 0)
+                       break;
+                       
+               if (copy_to_user(arg, &contour, sizeof(contour)))
+                       ret = -EFAULT;
+               break;
+       }
+       
+       case VIDIOCPWCSBACKLIGHT:
+       {
+               int backlight;
+               
+               if (copy_from_user(&backlight, arg, sizeof(backlight)))
+                       ret = -EFAULT;
+               else
+                       ret = pwc_set_backlight(pdev, backlight);
+               break;
+       }
+
+       case VIDIOCPWCGBACKLIGHT:
+       {
+               ret = pwc_get_backlight(pdev);
+               if (ret < 0)
+                       break;
+               if (copy_to_user(arg, &ret, sizeof(ret)))
+                       ret = -EFAULT;
+               break;
+       }
+       
+       case VIDIOCPWCSFLICKER:
+       {
+               int flicker;
+               
+               if (copy_from_user(&flicker, arg, sizeof(flicker)))
+                       ret = -EFAULT;
+               else
+                       ret = pwc_set_flicker(pdev, flicker);
+               break;
+       }
+
+       case VIDIOCPWCGFLICKER:
+       {
+               ret = pwc_get_flicker(pdev);
+               if (ret < 0)
+                       break;
+               if (copy_to_user(arg, &ret, sizeof(ret)))
+                       ret = -EFAULT;
+               break;
+       }
+       
+       case VIDIOCPWCSDYNNOISE:
+       {
+               int dynnoise;
+               
+               if (copy_from_user(&dynnoise, arg, sizeof(dynnoise)))
+                       ret = -EFAULT;
+               else
+                       ret = pwc_set_dynamic_noise(pdev, dynnoise);
+               break;
+       }
+       
+       case VIDIOCPWCGDYNNOISE:
+       {
+               ret = pwc_get_dynamic_noise(pdev);
+               if (ret < 0)
+                       break;
+               if (copy_to_user(arg, &ret, sizeof(ret)))
+                       ret = -EFAULT;
+               break;
+       }
+       
 
        default:
-               return -ENOIOCTLCMD;
+               ret = -ENOIOCTLCMD;
                break;
        }
-       return 0;
+       
+       if (ret > 0)
+               return 0;
+       return ret;
 }
 
 
diff -Nru a/drivers/usb/pwc-if.c b/drivers/usb/pwc-if.c
--- a/drivers/usb/pwc-if.c      Fri Mar 22 15:48:02 2002
+++ b/drivers/usb/pwc-if.c      Fri Mar 22 15:48:02 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
@@ -66,7 +66,7 @@
 
 /* hotplug device table support */
 static __devinitdata 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) },
@@ -75,12 +75,14 @@
        { 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 */
+       { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */
        { USB_DEVICE(0x055D, 0x9001) },
-       { USB_DEVICE(0x041E, 0x400C) },
-       { USB_DEVICE(0x04CC, 0x8116) },
+       { USB_DEVICE(0x041E, 0x400C) }, /* Creative */
+       { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
+       { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */
+       { USB_DEVICE(0x0d81, 0x1900) },
        { }
 };
 MODULE_DEVICE_TABLE(usb, pwc_device_table);
@@ -105,7 +107,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;
@@ -163,7 +165,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.
@@ -351,6 +353,8 @@
        for (; i < MAX_IMAGES; i++)
                pdev->image_ptr[i] = NULL;
 
+       kbuf = NULL;
+         
        Trace(TRACE_MEMORY, "Leaving pwc_allocate_buffers().\n");
        return 0;
 }
@@ -405,6 +409,7 @@
                rvfree(pdev->image_data, default_mbufs * pdev->len_per_image);
        }
        pdev->image_data = NULL;
+       
        Trace(TRACE_MEMORY, "Leaving free_buffers().\n");
 }
 
@@ -606,12 +611,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) */
+/* 2001-10-14: 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
@@ -629,7 +632,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(purb_t urb)
+static void pwc_isoc_handler(struct urb *urb)
 {
        struct pwc_device *pdev;
        int i, fst, flen;
@@ -791,7 +794,7 @@
 static int pwc_isoc_init(struct pwc_device *pdev)
 {
        struct usb_device *udev;
-       purb_t urb;
+       struct urb *urb;
        int i, j, ret;
 
        struct usb_interface_descriptor *idesc;
@@ -905,7 +908,6 @@
 int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, 
int new_compression, int new_snapshot)
 {
        int ret;
-
        /* Stop isoc stuff */
        pwc_isoc_cleanup(pdev);
        /* Reset parameters */
@@ -968,6 +970,29 @@
                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("Thes %s camera is equipped with a %s (%d).\n", 
+pdev->vdev->name, sensor_type, i);
+               }
        }
 
        /* Turn on camera */
@@ -1590,6 +1615,7 @@
        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);
@@ -1621,7 +1647,7 @@
        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();
        
@@ -1642,38 +1668,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:
@@ -1685,6 +1720,7 @@
                switch(product_id) {
                case 0x0001:
                        Info("Askey VC010 type 1 USB webcam detected.\n");
+                       name = "Askey VC010 webcam";
                        type_id = 645;
                        break;
                default:
@@ -1695,7 +1731,8 @@
        else if (vendor_id == 0x046d) {
                switch(product_id) {
                case 0x08b0:
-                       Info("Logitech QuickCam 3000 Pro detected.\n");
+                       Info("Logitech QuickCam 3000 Pro USB webcam detected.\n");
+                       name = "Logitech QuickCam 3000 Pro";
                        type_id = 730;
                        break;
                default:
@@ -1711,10 +1748,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:
@@ -1726,6 +1765,7 @@
                switch(product_id) {
                case 0x400c:
                        Info("Creative Labs Webcam 5 detected.\n");
+                       name = "Creative Labs Webcam 5";
                        type_id = 730;
                        break;
                default:
@@ -1736,7 +1776,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:
@@ -1744,7 +1785,25 @@
                        break;
                }
        }
-       else return NULL; /* 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 NULL;
+                       break;
+               }
+       }
+       else 
+               return NULL; /* 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);
@@ -1778,7 +1837,7 @@
                return NULL;
        }
        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;
@@ -1786,7 +1845,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)) &&
@@ -1951,11 +2009,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, Logitech Quickcam 3000 Pro, 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;
@@ -2007,9 +2066,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 
diff -Nru a/drivers/usb/pwc-ioctl.h b/drivers/usb/pwc-ioctl.h
--- a/drivers/usb/pwc-ioctl.h   Fri Mar 22 15:48:02 2002
+++ b/drivers/usb/pwc-ioctl.h   Fri Mar 22 15:48:02 2002
@@ -1,7 +1,7 @@
 #ifndef PWC_IOCTL_H
 #define PWC_IOCTL_H
 
-/* (C) 2001 Nemosoft Unv.    [EMAIL PROTECTED]
+/* (C) 2001-2002 Nemosoft Unv.    [EMAIL PROTECTED]
    
    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
@@ -18,7 +18,9 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
-/*
+/*         This is pwc-ioctl.h belonging to PWC 8.6                        */
+
+/* 
    Changes
    2001/08/03  Alvarado   Added ioctl constants to access methods for 
                           changing white balance and red/blue gains
@@ -52,6 +54,14 @@
 #define PWC_FPS_SNAPSHOT       0x00400000
 
 
+
+struct pwc_probe
+{
+       char name[32];
+       int type;
+};
+
+
 /* pwc_whitebalance.mode values */
 #define PWC_WB_INDOOR          0
 #define PWC_WB_OUTDOOR         1
@@ -63,9 +73,9 @@
    Set mode to one of the PWC_WB_* values above.
    *red and *blue are the respective gains of these colour components inside 
    the camera; range 0..65535
-   When mode == PWC_WB_MANUAL, manual_red and manual_blue are set or read; 
+   When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; 
    otherwise undefined.
-   read_red and read_blue are read-only.
+   'read_red' and 'read_blue' are read-only.
 */   
    
 struct pwc_whitebalance
@@ -75,6 +85,17 @@
        int read_red, read_blue;        /* R/O */
 };
 
+/* 
+   'control_speed' and 'control_delay' are used in automatic whitebalance mode,
+   and tell the camera how fast it should react to changes in lighting, and 
+   with how much delay. Valid values are 0..65535.
+*/
+struct pwc_wb_speed
+{
+       int control_speed;
+       int control_delay;
+
+};
 
 /* Used with VIDIOCPWC[SG]LED */
 struct pwc_leds
@@ -104,6 +125,19 @@
  /* Get preferred compression quality */
 #define VIDIOCPWCGCQUAL                _IOR('v', 195, int)
 
+
+ /* This is a probe function; since so many devices are supported, it
+    becomes difficult to include all the names in programs that want to
+    check for the enhanced Philips stuff. So in stead, try this PROBE;
+    it returns a structure with the original name, and the corresponding 
+    Philips type.
+    To use, fill the structure with zeroes, call PROBE and if that succeeds,
+    compare the name with that returned from VIDIOCGCAP; they should be the
+    same. If so, you can be assured it is a Philips (OEM) cam and the type
+    is valid.
+ */    
+#define VIDIOCPWCPROBE         _IOR('v', 199, struct pwc_probe)
+
  /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */
 #define VIDIOCPWCSAGC          _IOW('v', 200, int)
  /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */
@@ -115,9 +149,28 @@
 #define VIDIOCPWCSAWB           _IOW('v', 202, struct pwc_whitebalance)
 #define VIDIOCPWCGAWB           _IOR('v', 202, struct pwc_whitebalance)
 
- /* Turn LED on/off ; int range 0..65535 */
+ /* Auto WB speed */
+#define VIDIOCPWCSAWBSPEED     _IOW('v', 203, struct pwc_wb_speed)
+#define VIDIOCPWCGAWBSPEED     _IOR('v', 203, struct pwc_wb_speed)
+
+ /* LEDs on/off/blink; int range 0..65535 */
 #define VIDIOCPWCSLED           _IOW('v', 205, struct pwc_leds)
- /* Get state of LED; int range 0..65535 */
 #define VIDIOCPWCGLED           _IOR('v', 205, struct pwc_leds)
+
+  /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */
+#define VIDIOCPWCSCONTOUR      _IOW('v', 206, int)
+#define VIDIOCPWCGCONTOUR      _IOR('v', 206, int)
+
+  /* Backlight compensation; 0 = off, otherwise on */
+#define VIDIOCPWCSBACKLIGHT    _IOW('v', 207, int)
+#define VIDIOCPWCGBACKLIGHT    _IOR('v', 207, int)
+
+  /* Flickerless mode; = 0 off, otherwise on */
+#define VIDIOCPWCSFLICKER      _IOW('v', 208, int)
+#define VIDIOCPWCGFLICKER      _IOR('v', 208, int)  
+
+  /* Dynamic noise reduction; 0 off, 3 = high noise reduction */
+#define VIDIOCPWCSDYNNOISE     _IOW('v', 209, int)
+#define VIDIOCPWCGDYNNOISE     _IOR('v', 209, int)
 
 #endif
diff -Nru a/drivers/usb/pwc-misc.c b/drivers/usb/pwc-misc.c
--- a/drivers/usb/pwc-misc.c    Fri Mar 22 15:48:02 2002
+++ b/drivers/usb/pwc-misc.c    Fri Mar 22 15:48:02 2002
@@ -1,6 +1,6 @@
 /* Linux driver for Philips webcam 
    Various miscellaneous functions and tables.
-   (C) 1999-2001 Nemosoft Unv. ([EMAIL PROTECTED])
+   (C) 1999-2002 Nemosoft Unv. ([EMAIL PROTECTED])
 
    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/pwc-uncompress.c b/drivers/usb/pwc-uncompress.c
--- a/drivers/usb/pwc-uncompress.c      Fri Mar 22 15:48:02 2002
+++ b/drivers/usb/pwc-uncompress.c      Fri Mar 22 15:48:02 2002
@@ -1,6 +1,6 @@
 /* Linux driver for Philips webcam 
    Decompression frontend.
-   (C) 1999-2001 Nemosoft Unv. ([EMAIL PROTECTED])
+   (C) 1999-2002 Nemosoft Unv. ([EMAIL PROTECTED])
 
    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/pwc-uncompress.h b/drivers/usb/pwc-uncompress.h
--- a/drivers/usb/pwc-uncompress.h      Fri Mar 22 15:48:02 2002
+++ b/drivers/usb/pwc-uncompress.h      Fri Mar 22 15:48:02 2002
@@ -1,4 +1,4 @@
-/* (C) 1999-2001 Nemosoft Unv. ([EMAIL PROTECTED])
+/* (C) 1999-2002 Nemosoft Unv. ([EMAIL PROTECTED])
 
    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
@@ -20,8 +20,8 @@
    significant change should be reflected by increasing the 
    pwc_decompressor_version major number.
  */
-#ifndef PWC_DEC_H
-#define PWC_DEC_H
+#ifndef PWC_UNCOMPRESS_H
+#define PWC_UNCOMPRESS_H
 
 #include <linux/config.h>
 #include <linux/list.h>
diff -Nru a/drivers/usb/pwc.h b/drivers/usb/pwc.h
--- a/drivers/usb/pwc.h Fri Mar 22 15:48:02 2002
+++ b/drivers/usb/pwc.h Fri Mar 22 15:48:02 2002
@@ -1,4 +1,4 @@
-/* (C) 1999-2001 Nemosoft Unv. ([EMAIL PROTECTED])
+/* (C) 1999-2002 Nemosoft Unv. ([EMAIL PROTECTED])
 
    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
@@ -60,8 +60,8 @@
 
 /* Version block */
 #define PWC_MAJOR      8
-#define PWC_MINOR      5
-#define PWC_VERSION    "8.5"
+#define PWC_MINOR      6
+#define PWC_VERSION    "8.6"
 #define PWC_NAME       "pwc"
 
 /* Turn certain features on/off */
@@ -96,7 +96,7 @@
        void *data;
        int  length;
        int  read;
-       purb_t urb;
+       struct urb *urb;
 };
 
 /* intermediate buffers with raw data from the USB cam */
@@ -247,6 +247,7 @@
 extern int pwc_set_saturation(struct pwc_device *pdev, int value);
 extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value);
 extern int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value);
+extern int pwc_get_cmos_sensor(struct pwc_device *pdev);
 
 /* Power down or up the camera; not supported by all models */
 extern int pwc_camera_power(struct pwc_device *pdev, int power);

_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to