patch-2.4.10 linux/drivers/usb/pwc-ctrl.c
Next file: linux/drivers/usb/pwc-if.c
Previous file: linux/drivers/usb/printer.c
Back to the patch index
Back to the overall index
- Lines: 348
- Date:
Sat Sep 15 22:21:43 2001
- Orig file:
v2.4.9/linux/drivers/usb/pwc-ctrl.c
- Orig date:
Mon Aug 27 12:41:45 2001
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/pwc-ctrl.c linux/drivers/usb/pwc-ctrl.c
@@ -18,6 +18,12 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+/*
+ Changes
+ 2001/08/03 Alvarado Added methods for changing white balance and
+ red/green gains
+ */
+
/* Control functions for the cam; brightness, contrast, video mode, etc. */
#ifdef __KERNEL__
@@ -603,12 +609,12 @@
char buf;
int ret;
- if (pdev->type < 730)
+ if (pdev->type < 675)
return -1;
ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
GET_CHROM_CTL,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- SATURATION_MODE_FORMATTER1,
+ pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1,
pdev->vcinterface,
&buf, 1, HZ / 2);
if (ret < 0)
@@ -620,7 +626,7 @@
{
char buf;
- if (pdev->type < 730)
+ if (pdev->type < 675)
return -EINVAL;
if (value < 0)
value = 0;
@@ -631,7 +637,7 @@
return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
SET_CHROM_CTL,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- SATURATION_MODE_FORMATTER1,
+ pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1,
pdev->vcinterface,
&buf, 1, HZ / 2);
}
@@ -825,6 +831,218 @@
NULL, 0, HZ / 2);
}
+ /* ************************************************* */
+ /* Patch by Alvarado: (not in the original version */
+
+ /*
+ * the camera recognizes modes from 0 to 4:
+ *
+ * 00: indoor (incandescant lighting)
+ * 01: outdoor (sunlight)
+ * 02: fluorescent lighting
+ * 03: manual
+ * 04: auto
+ */
+static inline int pwc_set_awb(struct pwc_device *pdev, int mode)
+{
+ char buf;
+ int ret;
+
+ if (mode < 0)
+ mode = 0;
+
+ if (mode > 4)
+ mode = 4;
+
+ buf = mode & 0x07; /* just the lowest three bits */
+
+ ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
+ SET_CHROM_CTL,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ WB_MODE_FORMATTER,
+ pdev->vcinterface,
+ &buf, 1, HZ / 2);
+
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static inline int pwc_get_awb(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,
+ WB_MODE_FORMATTER,
+ pdev->vcinterface,
+ &buf, 1, HZ / 2);
+
+ if (ret < 0)
+ return ret;
+ return buf;
+}
+
+static inline int pwc_set_red_gain(struct pwc_device *pdev, int value)
+{
+ unsigned char buf;
+
+ if (value < 0)
+ value = 0;
+ if (value > 0xffff)
+ value = 0xffff;
+
+ /* only the msb are considered */
+ buf = value >> 8;
+
+ return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
+ SET_CHROM_CTL,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ PRESET_MANUAL_RED_GAIN_FORMATTER,
+ pdev->vcinterface,
+ &buf, 1, HZ / 2);
+}
+
+static inline int pwc_get_red_gain(struct pwc_device *pdev)
+{
+ unsigned char buf;
+ int ret;
+
+ ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
+ GET_STATUS_CTL,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ PRESET_MANUAL_RED_GAIN_FORMATTER,
+ pdev->vcinterface,
+ &buf, 1, HZ / 2);
+
+ if (ret < 0)
+ return ret;
+
+ return (buf << 8);
+}
+
+
+static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value)
+{
+ unsigned char buf;
+
+ if (value < 0)
+ value = 0;
+ if (value > 0xffff)
+ value = 0xffff;
+
+ /* linear mapping of 0..0xffff to -0x80..0x7f */
+ buf = (value >> 8);
+
+ return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
+ SET_CHROM_CTL,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ PRESET_MANUAL_BLUE_GAIN_FORMATTER,
+ pdev->vcinterface,
+ &buf, 1, HZ / 2);
+}
+
+static inline int pwc_get_blue_gain(struct pwc_device *pdev)
+{
+ unsigned char buf;
+ int ret;
+
+ ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
+ GET_STATUS_CTL,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ PRESET_MANUAL_BLUE_GAIN_FORMATTER,
+ pdev->vcinterface,
+ &buf, 1, HZ / 2);
+
+ if (ret < 0)
+ return ret;
+
+ 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.
+ */
+static inline int pwc_read_red_gain(struct pwc_device *pdev)
+{
+ unsigned char buf;
+ int ret;
+
+ ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
+ GET_STATUS_CTL,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ READ_RED_GAIN_FORMATTER,
+ pdev->vcinterface,
+ &buf, 1, HZ / 2);
+
+ if (ret < 0)
+ return ret;
+
+ return (buf << 8);
+}
+static inline int pwc_read_blue_gain(struct pwc_device *pdev)
+{
+ unsigned char buf;
+ int ret;
+
+ ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
+ GET_STATUS_CTL,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ READ_BLUE_GAIN_FORMATTER,
+ pdev->vcinterface,
+ &buf, 1, HZ / 2);
+
+ if (ret < 0)
+ return ret;
+
+ return (buf << 8);
+}
+
+/* still unused (it doesn't work yet...) */
+static inline int pwc_set_led(struct pwc_device *pdev, int value)
+{
+ unsigned char buf;
+
+ if (value < 0)
+ value = 0;
+ if (value > 0xffff)
+ value = 0xffff;
+
+ buf = (value >> 8);
+
+ 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, 1, HZ / 2);
+}
+
+/* still unused (it doesn't work yet...) */
+static inline int pwc_get_led(struct pwc_device *pdev)
+{
+ unsigned char buf;
+ int ret;
+
+ 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, 1, HZ / 2);
+
+ if (ret < 0)
+ return ret;
+
+ return (buf << 8);
+}
+
+ /* End of Add-Ons */
+ /* ************************************************* */
+
int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
{
switch(cmd) {
@@ -910,6 +1128,74 @@
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);
+ }
+ break;
+ }
+
+ case VIDIOCPWCGAWB:
+ {
+ struct pwc_whitebalance wb;
+
+ 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);
+ }
+ break;
+ }
+
+ case VIDIOCPWCSLED:
+ {
+ int led, ret;
+ if (copy_from_user(&led,arg,sizeof(led)))
+ return -EFAULT;
+ else {
+ /* ret = pwc_set_led(pdev, led); */
+ ret = 0;
+ if (ret<0)
+ return ret;
+ }
+ break;
+ }
+
+
+
+ case VIDIOCPWCGLED:
+ {
+ int led;
+
+ led = pwc_get_led(pdev);
+ if (led < 0)
+ return -EINVAL;
+ if (copy_to_user(arg, &led, sizeof(led)))
+ return -EFAULT;
+ break;
+ }
+
+ /* End of Add-Ons */
+ /* ************************************************* */
+
default:
return -ENOIOCTLCMD;
break;
@@ -918,3 +1204,7 @@
}
#endif
+
+
+
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)