📄 pwc-ctrl.c
字号:
ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), GET_CHROM_CTL, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, pdev->vcinterface, &buf, 1, HZ / 2); if (ret < 0) return ret; return 32768 + buf * 327;}int pwc_set_saturation(struct pwc_device *pdev, int value){ char buf; if (pdev->type < 675) return -EINVAL; if (value < 0) value = 0; if (value > 0xffff) value = 0xffff; /* saturation ranges from -100 to +100 */ buf = (value - 32768) / 327; return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), SET_CHROM_CTL, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, pdev->vcinterface, &buf, 1, HZ / 2);}/* AGC */static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value){ char buf; int ret; if (mode) buf = 0x0; /* auto */ else buf = 0xff; /* fixed */ ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), SET_LUM_CTL, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, AGC_MODE_FORMATTER, pdev->vcinterface, &buf, 1, HZ / 2); if (!mode && ret >= 0) { if (value < 0) value = 0; if (value > 0xffff) value = 0xffff; buf = (value >> 10) & 0x3F; ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), SET_LUM_CTL, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, PRESET_AGC_FORMATTER, pdev->vcinterface, &buf, 1, HZ / 2); } if (ret < 0) return ret; return 0;}static inline int pwc_get_agc(struct pwc_device *pdev, int *value){ 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, AGC_MODE_FORMATTER, pdev->vcinterface, &buf, 1, HZ / 2); if (ret < 0) return ret; if (buf != 0) { /* fixed */ ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), GET_LUM_CTL, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, PRESET_AGC_FORMATTER, pdev->vcinterface, &buf, 1, HZ / 2); if (ret < 0) return ret; if (buf > 0x3F) buf = 0x3F; *value = (buf << 10); } else { /* auto */ ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), GET_STATUS_CTL, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, READ_AGC_FORMATTER, pdev->vcinterface, &buf, 1, HZ / 2); if (ret < 0) return ret; /* Gah... this value ranges from 0x00 ... 0x9F */ if (buf > 0x9F) buf = 0x9F; *value = -(48 + buf * 409); } return 0;}static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value){ char buf[2]; int speed, ret; if (mode) buf[0] = 0x0; /* auto */ else buf[0] = 0xff; /* fixed */ ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), SET_LUM_CTL, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, SHUTTER_MODE_FORMATTER, pdev->vcinterface, buf, 1, HZ / 2); if (!mode && ret >= 0) { if (value < 0) value = 0; if (value > 0xffff) value = 0xffff; switch(pdev->type) { case 675: case 680: case 690: /* speed ranges from 0x0 to 0x290 (656) */ speed = (value / 100); buf[1] = speed >> 8; buf[0] = speed & 0xff; break; case 730: case 740: case 750: /* speed seems to range from 0x0 to 0xff */ buf[1] = 0; buf[0] = value >> 8; break; } ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), SET_LUM_CTL, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, PRESET_SHUTTER_FORMATTER, pdev->vcinterface, &buf, 2, HZ / 2); } return ret;} /* POWER */int pwc_camera_power(struct pwc_device *pdev, int power){ char buf; if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6)) return 0; /* Not supported by Nala or Timon < release 6 */ if (power) buf = 0x00; /* active */ else buf = 0xFF; /* power save */ return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), SET_STATUS_CTL, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, SET_POWER_SAVE_MODE_FORMATTER, pdev->vcinterface, &buf, 1, HZ / 2);}/* private calls */static inline int pwc_restore_user(struct pwc_device *pdev){ return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), SET_STATUS_CTL, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, RESTORE_USER_DEFAULTS_FORMATTER, pdev->vcinterface, NULL, 0, HZ / 2);}static inline int pwc_save_user(struct pwc_device *pdev){ return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), SET_STATUS_CTL, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, SAVE_USER_DEFAULTS_FORMATTER, pdev->vcinterface, NULL, 0, HZ / 2);}static inline int pwc_restore_factory(struct pwc_device *pdev){ return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), SET_STATUS_CTL, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, RESTORE_FACTORY_DEFAULTS_FORMATTER, pdev->vcinterface, 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);}int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value){ unsigned char buf[2]; if (pdev->type < 730) return 0; on_value /= 100; off_value /= 100; if (on_value < 0) on_value = 0; if (on_value > 0xff) on_value = 0xff; if (off_value < 0) off_value = 0; if (off_value > 0xff) off_value = 0xff; 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);}int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value){ unsigned char buf[2]; int ret; if (pdev->type < 730) { *on_value = -1; *off_value = -1; 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); if (ret < 0) return ret; *on_value = buf[0] * 100; *off_value = buf[1] * 100; return 0;} /* End of Add-Ons */ /* ************************************************* */int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg){ switch(cmd) { case VIDIOCPWCRUSER: { if (pwc_restore_user(pdev)) return -EINVAL; break; } case VIDIOCPWCSUSER: { if (pwc_save_user(pdev)) return -EINVAL; break; } case VIDIOCPWCFACTORY: { if (pwc_restore_factory(pdev)) return -EINVAL; break; } case VIDIOCPWCSCQUAL: { int qual, ret; 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; break; } case VIDIOCPWCGCQUAL: { if (copy_to_user(arg, &pdev->vcompression, sizeof(int))) return -EFAULT; break; } case VIDIOCPWCSAGC: { int agc; if (copy_from_user(&agc, arg, sizeof(agc))) return -EFAULT; else { if (pwc_set_agc(pdev, agc < 0 ? 1 : 0, agc)) return -EINVAL; } break; } case VIDIOCPWCGAGC: { int agc; if (pwc_get_agc(pdev, &agc)) return -EINVAL; if (copy_to_user(arg, &agc, sizeof(agc))) return -EFAULT; break; } case VIDIOCPWCSSHUTTER: { int shutter_speed, ret; if (copy_from_user(&shutter_speed, arg, sizeof(shutter_speed))) return -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); } 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); } if (copy_to_user(arg, &wb, sizeof(wb))) return -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; } case VIDIOCPWCGLED: { int led; struct pwc_leds leds; led = pwc_get_leds(pdev, &leds.led_on, &leds.led_off); if (led < 0) return -EINVAL; if (copy_to_user(arg, &leds, sizeof(leds))) return -EFAULT; break; } /* End of Add-Ons */ /* ************************************************* */ default: return -ENOIOCTLCMD; break; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -