# 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 nemosoft@smcc.demon.nl 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. (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 @@ -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. webcam@smcc.demon.nl +/* (C) 2001-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 @@ -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. (webcam@smcc.demon.nl) + (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff -Nru a/drivers/usb/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. (webcam@smcc.demon.nl) + (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff -Nru a/drivers/usb/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. (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 @@ -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 #include 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. (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 @@ -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);