diff options
author | Hans de Goede <hdegoede@redhat.com> | 2011-06-26 11:52:01 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-07-27 16:53:45 -0400 |
commit | 6c9cac89c009c049a9ad29cdf0f51892410fe751 (patch) | |
tree | 6558d038ec77295c7c7dca1e6627369b6575d31c /drivers/media/video | |
parent | 04613c5e600e64840e4f753bd881cd5ab96ae403 (diff) |
[media] pwc: Replace control code with v4l2-ctrls framework
Also remove all the converting from native range to 0-65535 and back
that was going on. This is no longer needed now that we no longer support
v4l1.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video')
-rw-r--r-- | drivers/media/video/pwc/pwc-ctrl.c | 729 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-if.c | 18 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-v4l.c | 1008 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc.h | 152 |
4 files changed, 823 insertions, 1084 deletions
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c index 9d800c66807..8e0cc537e1e 100644 --- a/drivers/media/video/pwc/pwc-ctrl.c +++ b/drivers/media/video/pwc/pwc-ctrl.c | |||
@@ -3,6 +3,7 @@ | |||
3 | video modes. | 3 | video modes. |
4 | (C) 1999-2003 Nemosoft Unv. | 4 | (C) 1999-2003 Nemosoft Unv. |
5 | (C) 2004-2006 Luc Saillard (luc@saillard.org) | 5 | (C) 2004-2006 Luc Saillard (luc@saillard.org) |
6 | (C) 2011 Hans de Goede <hdegoede@redhat.com> | ||
6 | 7 | ||
7 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | 8 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx |
8 | driver and thus may have bugs that are not present in the original version. | 9 | driver and thus may have bugs that are not present in the original version. |
@@ -49,55 +50,7 @@ | |||
49 | #include "pwc-dec1.h" | 50 | #include "pwc-dec1.h" |
50 | #include "pwc-dec23.h" | 51 | #include "pwc-dec23.h" |
51 | 52 | ||
52 | /* Request types: video */ | 53 | /* Selectors for status controls used only in this file */ |
53 | #define SET_LUM_CTL 0x01 | ||
54 | #define GET_LUM_CTL 0x02 | ||
55 | #define SET_CHROM_CTL 0x03 | ||
56 | #define GET_CHROM_CTL 0x04 | ||
57 | #define SET_STATUS_CTL 0x05 | ||
58 | #define GET_STATUS_CTL 0x06 | ||
59 | #define SET_EP_STREAM_CTL 0x07 | ||
60 | #define GET_EP_STREAM_CTL 0x08 | ||
61 | #define GET_XX_CTL 0x09 | ||
62 | #define SET_XX_CTL 0x0A | ||
63 | #define GET_XY_CTL 0x0B | ||
64 | #define SET_XY_CTL 0x0C | ||
65 | #define SET_MPT_CTL 0x0D | ||
66 | #define GET_MPT_CTL 0x0E | ||
67 | |||
68 | /* Selectors for the Luminance controls [GS]ET_LUM_CTL */ | ||
69 | #define AGC_MODE_FORMATTER 0x2000 | ||
70 | #define PRESET_AGC_FORMATTER 0x2100 | ||
71 | #define SHUTTER_MODE_FORMATTER 0x2200 | ||
72 | #define PRESET_SHUTTER_FORMATTER 0x2300 | ||
73 | #define PRESET_CONTOUR_FORMATTER 0x2400 | ||
74 | #define AUTO_CONTOUR_FORMATTER 0x2500 | ||
75 | #define BACK_LIGHT_COMPENSATION_FORMATTER 0x2600 | ||
76 | #define CONTRAST_FORMATTER 0x2700 | ||
77 | #define DYNAMIC_NOISE_CONTROL_FORMATTER 0x2800 | ||
78 | #define FLICKERLESS_MODE_FORMATTER 0x2900 | ||
79 | #define AE_CONTROL_SPEED 0x2A00 | ||
80 | #define BRIGHTNESS_FORMATTER 0x2B00 | ||
81 | #define GAMMA_FORMATTER 0x2C00 | ||
82 | |||
83 | /* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */ | ||
84 | #define WB_MODE_FORMATTER 0x1000 | ||
85 | #define AWB_CONTROL_SPEED_FORMATTER 0x1100 | ||
86 | #define AWB_CONTROL_DELAY_FORMATTER 0x1200 | ||
87 | #define PRESET_MANUAL_RED_GAIN_FORMATTER 0x1300 | ||
88 | #define PRESET_MANUAL_BLUE_GAIN_FORMATTER 0x1400 | ||
89 | #define COLOUR_MODE_FORMATTER 0x1500 | ||
90 | #define SATURATION_MODE_FORMATTER1 0x1600 | ||
91 | #define SATURATION_MODE_FORMATTER2 0x1700 | ||
92 | |||
93 | /* Selectors for the Status controls [GS]ET_STATUS_CTL */ | ||
94 | #define SAVE_USER_DEFAULTS_FORMATTER 0x0200 | ||
95 | #define RESTORE_USER_DEFAULTS_FORMATTER 0x0300 | ||
96 | #define RESTORE_FACTORY_DEFAULTS_FORMATTER 0x0400 | ||
97 | #define READ_AGC_FORMATTER 0x0500 | ||
98 | #define READ_SHUTTER_FORMATTER 0x0600 | ||
99 | #define READ_RED_GAIN_FORMATTER 0x0700 | ||
100 | #define READ_BLUE_GAIN_FORMATTER 0x0800 | ||
101 | #define GET_STATUS_B00 0x0B00 | 54 | #define GET_STATUS_B00 0x0B00 |
102 | #define SENSOR_TYPE_FORMATTER1 0x0C00 | 55 | #define SENSOR_TYPE_FORMATTER1 0x0C00 |
103 | #define GET_STATUS_3000 0x3000 | 56 | #define GET_STATUS_3000 0x3000 |
@@ -116,11 +69,6 @@ | |||
116 | /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */ | 69 | /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */ |
117 | #define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100 | 70 | #define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100 |
118 | 71 | ||
119 | /* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */ | ||
120 | #define PT_RELATIVE_CONTROL_FORMATTER 0x01 | ||
121 | #define PT_RESET_CONTROL_FORMATTER 0x02 | ||
122 | #define PT_STATUS_FORMATTER 0x03 | ||
123 | |||
124 | static const char *size2name[PSZ_MAX] = | 72 | static const char *size2name[PSZ_MAX] = |
125 | { | 73 | { |
126 | "subQCIF", | 74 | "subQCIF", |
@@ -160,7 +108,7 @@ static void pwc_set_image_buffer_size(struct pwc_device *pdev); | |||
160 | /****************************************************************************/ | 108 | /****************************************************************************/ |
161 | 109 | ||
162 | static int _send_control_msg(struct pwc_device *pdev, | 110 | static int _send_control_msg(struct pwc_device *pdev, |
163 | u8 request, u16 value, int index, void *buf, int buflen, int timeout) | 111 | u8 request, u16 value, int index, void *buf, int buflen) |
164 | { | 112 | { |
165 | int rc; | 113 | int rc; |
166 | void *kbuf = NULL; | 114 | void *kbuf = NULL; |
@@ -177,7 +125,7 @@ static int _send_control_msg(struct pwc_device *pdev, | |||
177 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | 125 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
178 | value, | 126 | value, |
179 | index, | 127 | index, |
180 | kbuf, buflen, timeout); | 128 | kbuf, buflen, USB_CTRL_SET_TIMEOUT); |
181 | 129 | ||
182 | kfree(kbuf); | 130 | kfree(kbuf); |
183 | return rc; | 131 | return rc; |
@@ -197,9 +145,13 @@ static int recv_control_msg(struct pwc_device *pdev, | |||
197 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | 145 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
198 | value, | 146 | value, |
199 | pdev->vcinterface, | 147 | pdev->vcinterface, |
200 | kbuf, buflen, 500); | 148 | kbuf, buflen, USB_CTRL_GET_TIMEOUT); |
201 | memcpy(buf, kbuf, buflen); | 149 | memcpy(buf, kbuf, buflen); |
202 | kfree(kbuf); | 150 | kfree(kbuf); |
151 | |||
152 | if (rc < 0) | ||
153 | PWC_ERROR("recv_control_msg error %d req %02x val %04x\n", | ||
154 | rc, request, value); | ||
203 | return rc; | 155 | return rc; |
204 | } | 156 | } |
205 | 157 | ||
@@ -210,18 +162,16 @@ static inline int send_video_command(struct pwc_device *pdev, | |||
210 | SET_EP_STREAM_CTL, | 162 | SET_EP_STREAM_CTL, |
211 | VIDEO_OUTPUT_CONTROL_FORMATTER, | 163 | VIDEO_OUTPUT_CONTROL_FORMATTER, |
212 | index, | 164 | index, |
213 | buf, buflen, 1000); | 165 | buf, buflen); |
214 | } | 166 | } |
215 | 167 | ||
216 | static inline int send_control_msg(struct pwc_device *pdev, | 168 | static inline int send_control_msg(struct pwc_device *pdev, |
217 | u8 request, u16 value, void *buf, int buflen) | 169 | u8 request, u16 value, void *buf, int buflen) |
218 | { | 170 | { |
219 | return _send_control_msg(pdev, | 171 | return _send_control_msg(pdev, |
220 | request, value, pdev->vcinterface, buf, buflen, 500); | 172 | request, value, pdev->vcinterface, buf, buflen); |
221 | } | 173 | } |
222 | 174 | ||
223 | |||
224 | |||
225 | static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) | 175 | static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) |
226 | { | 176 | { |
227 | unsigned char buf[3]; | 177 | unsigned char buf[3]; |
@@ -549,246 +499,78 @@ static void pwc_set_image_buffer_size(struct pwc_device *pdev) | |||
549 | pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; | 499 | pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; |
550 | } | 500 | } |
551 | 501 | ||
552 | /* BRIGHTNESS */ | 502 | int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) |
553 | int pwc_get_brightness(struct pwc_device *pdev) | ||
554 | { | 503 | { |
555 | char buf; | ||
556 | int ret; | 504 | int ret; |
505 | u8 buf; | ||
557 | 506 | ||
558 | ret = recv_control_msg(pdev, | 507 | ret = recv_control_msg(pdev, request, value, &buf, sizeof(buf)); |
559 | GET_LUM_CTL, BRIGHTNESS_FORMATTER, &buf, sizeof(buf)); | ||
560 | if (ret < 0) | 508 | if (ret < 0) |
561 | return ret; | 509 | return ret; |
562 | return buf; | ||
563 | } | ||
564 | |||
565 | int pwc_set_brightness(struct pwc_device *pdev, int value) | ||
566 | { | ||
567 | char buf; | ||
568 | 510 | ||
569 | if (value < 0) | 511 | *data = buf; |
570 | value = 0; | 512 | return 0; |
571 | if (value > 0xffff) | ||
572 | value = 0xffff; | ||
573 | buf = (value >> 9) & 0x7f; | ||
574 | return send_control_msg(pdev, | ||
575 | SET_LUM_CTL, BRIGHTNESS_FORMATTER, &buf, sizeof(buf)); | ||
576 | } | 513 | } |
577 | 514 | ||
578 | /* CONTRAST */ | 515 | int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data) |
579 | |||
580 | int pwc_get_contrast(struct pwc_device *pdev) | ||
581 | { | 516 | { |
582 | char buf; | ||
583 | int ret; | 517 | int ret; |
584 | 518 | ||
585 | ret = recv_control_msg(pdev, | 519 | ret = send_control_msg(pdev, request, value, &data, sizeof(data)); |
586 | GET_LUM_CTL, CONTRAST_FORMATTER, &buf, sizeof(buf)); | ||
587 | if (ret < 0) | 520 | if (ret < 0) |
588 | return ret; | 521 | return ret; |
589 | return buf; | ||
590 | } | ||
591 | 522 | ||
592 | int pwc_set_contrast(struct pwc_device *pdev, int value) | 523 | return 0; |
593 | { | ||
594 | char buf; | ||
595 | |||
596 | if (value < 0) | ||
597 | value = 0; | ||
598 | if (value > 0xffff) | ||
599 | value = 0xffff; | ||
600 | buf = (value >> 10) & 0x3f; | ||
601 | return send_control_msg(pdev, | ||
602 | SET_LUM_CTL, CONTRAST_FORMATTER, &buf, sizeof(buf)); | ||
603 | } | 524 | } |
604 | 525 | ||
605 | /* GAMMA */ | 526 | int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) |
606 | |||
607 | int pwc_get_gamma(struct pwc_device *pdev) | ||
608 | { | 527 | { |
609 | char buf; | ||
610 | int ret; | 528 | int ret; |
529 | s8 buf; | ||
611 | 530 | ||
612 | ret = recv_control_msg(pdev, | 531 | ret = recv_control_msg(pdev, request, value, &buf, sizeof(buf)); |
613 | GET_LUM_CTL, GAMMA_FORMATTER, &buf, sizeof(buf)); | ||
614 | if (ret < 0) | 532 | if (ret < 0) |
615 | return ret; | 533 | return ret; |
616 | return buf; | ||
617 | } | ||
618 | |||
619 | int pwc_set_gamma(struct pwc_device *pdev, int value) | ||
620 | { | ||
621 | char buf; | ||
622 | |||
623 | if (value < 0) | ||
624 | value = 0; | ||
625 | if (value > 0xffff) | ||
626 | value = 0xffff; | ||
627 | buf = (value >> 11) & 0x1f; | ||
628 | return send_control_msg(pdev, | ||
629 | SET_LUM_CTL, GAMMA_FORMATTER, &buf, sizeof(buf)); | ||
630 | } | ||
631 | |||
632 | |||
633 | /* SATURATION */ | ||
634 | |||
635 | /* return a value between [-100 , 100] */ | ||
636 | int pwc_get_saturation(struct pwc_device *pdev, int *value) | ||
637 | { | ||
638 | char buf; | ||
639 | int ret, saturation_register; | ||
640 | 534 | ||
641 | if (pdev->type < 675) | 535 | *data = buf; |
642 | return -EINVAL; | ||
643 | if (pdev->type < 730) | ||
644 | saturation_register = SATURATION_MODE_FORMATTER2; | ||
645 | else | ||
646 | saturation_register = SATURATION_MODE_FORMATTER1; | ||
647 | ret = recv_control_msg(pdev, | ||
648 | GET_CHROM_CTL, saturation_register, &buf, sizeof(buf)); | ||
649 | if (ret < 0) | ||
650 | return ret; | ||
651 | *value = (signed)buf; | ||
652 | return 0; | 536 | return 0; |
653 | } | 537 | } |
654 | 538 | ||
655 | /* @param value saturation color between [-100 , 100] */ | 539 | int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) |
656 | int pwc_set_saturation(struct pwc_device *pdev, int value) | ||
657 | { | ||
658 | char buf; | ||
659 | int saturation_register; | ||
660 | |||
661 | if (pdev->type < 675) | ||
662 | return -EINVAL; | ||
663 | if (value < -100) | ||
664 | value = -100; | ||
665 | if (value > 100) | ||
666 | value = 100; | ||
667 | if (pdev->type < 730) | ||
668 | saturation_register = SATURATION_MODE_FORMATTER2; | ||
669 | else | ||
670 | saturation_register = SATURATION_MODE_FORMATTER1; | ||
671 | return send_control_msg(pdev, | ||
672 | SET_CHROM_CTL, saturation_register, &buf, sizeof(buf)); | ||
673 | } | ||
674 | |||
675 | /* AGC */ | ||
676 | |||
677 | int pwc_set_agc(struct pwc_device *pdev, int mode, int value) | ||
678 | { | 540 | { |
679 | char buf; | ||
680 | int ret; | 541 | int ret; |
542 | u8 buf[2]; | ||
681 | 543 | ||
682 | if (mode) | 544 | ret = recv_control_msg(pdev, request, value, buf, sizeof(buf)); |
683 | buf = 0x0; /* auto */ | ||
684 | else | ||
685 | buf = 0xff; /* fixed */ | ||
686 | |||
687 | ret = send_control_msg(pdev, | ||
688 | SET_LUM_CTL, AGC_MODE_FORMATTER, &buf, sizeof(buf)); | ||
689 | |||
690 | if (!mode && ret >= 0) { | ||
691 | if (value < 0) | ||
692 | value = 0; | ||
693 | if (value > 0xffff) | ||
694 | value = 0xffff; | ||
695 | buf = (value >> 10) & 0x3F; | ||
696 | ret = send_control_msg(pdev, | ||
697 | SET_LUM_CTL, PRESET_AGC_FORMATTER, &buf, sizeof(buf)); | ||
698 | } | ||
699 | if (ret < 0) | 545 | if (ret < 0) |
700 | return ret; | 546 | return ret; |
547 | |||
548 | *data = (buf[1] << 8) | buf[0]; | ||
701 | return 0; | 549 | return 0; |
702 | } | 550 | } |
703 | 551 | ||
704 | int pwc_get_agc(struct pwc_device *pdev, int *value) | 552 | int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data) |
705 | { | 553 | { |
706 | unsigned char buf; | ||
707 | int ret; | 554 | int ret; |
555 | u8 buf[2]; | ||
708 | 556 | ||
709 | ret = recv_control_msg(pdev, | 557 | buf[0] = data & 0xff; |
710 | GET_LUM_CTL, AGC_MODE_FORMATTER, &buf, sizeof(buf)); | 558 | buf[1] = data >> 8; |
559 | ret = send_control_msg(pdev, request, value, buf, sizeof(buf)); | ||
711 | if (ret < 0) | 560 | if (ret < 0) |
712 | return ret; | 561 | return ret; |
713 | 562 | ||
714 | if (buf != 0) { /* fixed */ | ||
715 | ret = recv_control_msg(pdev, | ||
716 | GET_LUM_CTL, PRESET_AGC_FORMATTER, &buf, sizeof(buf)); | ||
717 | if (ret < 0) | ||
718 | return ret; | ||
719 | if (buf > 0x3F) | ||
720 | buf = 0x3F; | ||
721 | *value = (buf << 10); | ||
722 | } | ||
723 | else { /* auto */ | ||
724 | ret = recv_control_msg(pdev, | ||
725 | GET_STATUS_CTL, READ_AGC_FORMATTER, &buf, sizeof(buf)); | ||
726 | if (ret < 0) | ||
727 | return ret; | ||
728 | /* Gah... this value ranges from 0x00 ... 0x9F */ | ||
729 | if (buf > 0x9F) | ||
730 | buf = 0x9F; | ||
731 | *value = -(48 + buf * 409); | ||
732 | } | ||
733 | |||
734 | return 0; | 563 | return 0; |
735 | } | 564 | } |
736 | 565 | ||
737 | int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value) | 566 | int pwc_button_ctrl(struct pwc_device *pdev, u16 value) |
738 | { | ||
739 | char buf[2]; | ||
740 | int speed, ret; | ||
741 | |||
742 | |||
743 | if (mode) | ||
744 | buf[0] = 0x0; /* auto */ | ||
745 | else | ||
746 | buf[0] = 0xff; /* fixed */ | ||
747 | |||
748 | ret = send_control_msg(pdev, | ||
749 | SET_LUM_CTL, SHUTTER_MODE_FORMATTER, &buf, 1); | ||
750 | |||
751 | if (!mode && ret >= 0) { | ||
752 | if (value < 0) | ||
753 | value = 0; | ||
754 | if (value > 0xffff) | ||
755 | value = 0xffff; | ||
756 | |||
757 | if (DEVICE_USE_CODEC2(pdev->type)) { | ||
758 | /* speed ranges from 0x0 to 0x290 (656) */ | ||
759 | speed = (value / 100); | ||
760 | buf[1] = speed >> 8; | ||
761 | buf[0] = speed & 0xff; | ||
762 | } else if (DEVICE_USE_CODEC3(pdev->type)) { | ||
763 | /* speed seems to range from 0x0 to 0xff */ | ||
764 | buf[1] = 0; | ||
765 | buf[0] = value >> 8; | ||
766 | } | ||
767 | |||
768 | ret = send_control_msg(pdev, | ||
769 | SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, | ||
770 | &buf, sizeof(buf)); | ||
771 | } | ||
772 | return ret; | ||
773 | } | ||
774 | |||
775 | /* This function is not exported to v4l1, so output values between 0 -> 256 */ | ||
776 | int pwc_get_shutter_speed(struct pwc_device *pdev, int *value) | ||
777 | { | 567 | { |
778 | unsigned char buf[2]; | ||
779 | int ret; | 568 | int ret; |
780 | 569 | ||
781 | ret = recv_control_msg(pdev, | 570 | ret = send_control_msg(pdev, SET_STATUS_CTL, value, NULL, 0); |
782 | GET_STATUS_CTL, READ_SHUTTER_FORMATTER, &buf, sizeof(buf)); | ||
783 | if (ret < 0) | 571 | if (ret < 0) |
784 | return ret; | 572 | return ret; |
785 | *value = buf[0] + (buf[1] << 8); | 573 | |
786 | if (DEVICE_USE_CODEC2(pdev->type)) { | ||
787 | /* speed ranges from 0x0 to 0x290 (656) */ | ||
788 | *value *= 256/656; | ||
789 | } else if (DEVICE_USE_CODEC3(pdev->type)) { | ||
790 | /* speed seems to range from 0x0 to 0xff */ | ||
791 | } | ||
792 | return 0; | 574 | return 0; |
793 | } | 575 | } |
794 | 576 | ||
@@ -817,162 +599,6 @@ void pwc_camera_power(struct pwc_device *pdev, int power) | |||
817 | power ? "on" : "off", r); | 599 | power ? "on" : "off", r); |
818 | } | 600 | } |
819 | 601 | ||
820 | /* private calls */ | ||
821 | int pwc_restore_user(struct pwc_device *pdev) | ||
822 | { | ||
823 | return send_control_msg(pdev, | ||
824 | SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, NULL, 0); | ||
825 | } | ||
826 | |||
827 | int pwc_save_user(struct pwc_device *pdev) | ||
828 | { | ||
829 | return send_control_msg(pdev, | ||
830 | SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, NULL, 0); | ||
831 | } | ||
832 | |||
833 | int pwc_restore_factory(struct pwc_device *pdev) | ||
834 | { | ||
835 | return send_control_msg(pdev, | ||
836 | SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, NULL, 0); | ||
837 | } | ||
838 | |||
839 | /* ************************************************* */ | ||
840 | /* Patch by Alvarado: (not in the original version */ | ||
841 | |||
842 | /* | ||
843 | * the camera recognizes modes from 0 to 4: | ||
844 | * | ||
845 | * 00: indoor (incandescant lighting) | ||
846 | * 01: outdoor (sunlight) | ||
847 | * 02: fluorescent lighting | ||
848 | * 03: manual | ||
849 | * 04: auto | ||
850 | */ | ||
851 | int pwc_set_awb(struct pwc_device *pdev, int mode) | ||
852 | { | ||
853 | char buf; | ||
854 | int ret; | ||
855 | |||
856 | if (mode < 0) | ||
857 | mode = 0; | ||
858 | |||
859 | if (mode > 4) | ||
860 | mode = 4; | ||
861 | |||
862 | buf = mode & 0x07; /* just the lowest three bits */ | ||
863 | |||
864 | ret = send_control_msg(pdev, | ||
865 | SET_CHROM_CTL, WB_MODE_FORMATTER, &buf, sizeof(buf)); | ||
866 | |||
867 | if (ret < 0) | ||
868 | return ret; | ||
869 | return 0; | ||
870 | } | ||
871 | |||
872 | int pwc_get_awb(struct pwc_device *pdev) | ||
873 | { | ||
874 | unsigned char buf; | ||
875 | int ret; | ||
876 | |||
877 | ret = recv_control_msg(pdev, | ||
878 | GET_CHROM_CTL, WB_MODE_FORMATTER, &buf, sizeof(buf)); | ||
879 | |||
880 | if (ret < 0) | ||
881 | return ret; | ||
882 | return buf; | ||
883 | } | ||
884 | |||
885 | int pwc_set_red_gain(struct pwc_device *pdev, int value) | ||
886 | { | ||
887 | unsigned char buf; | ||
888 | |||
889 | if (value < 0) | ||
890 | value = 0; | ||
891 | if (value > 0xffff) | ||
892 | value = 0xffff; | ||
893 | /* only the msb is considered */ | ||
894 | buf = value >> 8; | ||
895 | return send_control_msg(pdev, | ||
896 | SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, | ||
897 | &buf, sizeof(buf)); | ||
898 | } | ||
899 | |||
900 | int pwc_get_red_gain(struct pwc_device *pdev, int *value) | ||
901 | { | ||
902 | unsigned char buf; | ||
903 | int ret; | ||
904 | |||
905 | ret = recv_control_msg(pdev, | ||
906 | GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, | ||
907 | &buf, sizeof(buf)); | ||
908 | if (ret < 0) | ||
909 | return ret; | ||
910 | *value = buf << 8; | ||
911 | return 0; | ||
912 | } | ||
913 | |||
914 | |||
915 | int pwc_set_blue_gain(struct pwc_device *pdev, int value) | ||
916 | { | ||
917 | unsigned char buf; | ||
918 | |||
919 | if (value < 0) | ||
920 | value = 0; | ||
921 | if (value > 0xffff) | ||
922 | value = 0xffff; | ||
923 | /* only the msb is considered */ | ||
924 | buf = value >> 8; | ||
925 | return send_control_msg(pdev, | ||
926 | SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, | ||
927 | &buf, sizeof(buf)); | ||
928 | } | ||
929 | |||
930 | int pwc_get_blue_gain(struct pwc_device *pdev, int *value) | ||
931 | { | ||
932 | unsigned char buf; | ||
933 | int ret; | ||
934 | |||
935 | ret = recv_control_msg(pdev, | ||
936 | GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, | ||
937 | &buf, sizeof(buf)); | ||
938 | if (ret < 0) | ||
939 | return ret; | ||
940 | *value = buf << 8; | ||
941 | return 0; | ||
942 | } | ||
943 | |||
944 | |||
945 | /* The following two functions are different, since they only read the | ||
946 | internal red/blue gains, which may be different from the manual | ||
947 | gains set or read above. | ||
948 | */ | ||
949 | static int pwc_read_red_gain(struct pwc_device *pdev, int *value) | ||
950 | { | ||
951 | unsigned char buf; | ||
952 | int ret; | ||
953 | |||
954 | ret = recv_control_msg(pdev, | ||
955 | GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, &buf, sizeof(buf)); | ||
956 | if (ret < 0) | ||
957 | return ret; | ||
958 | *value = buf << 8; | ||
959 | return 0; | ||
960 | } | ||
961 | |||
962 | static int pwc_read_blue_gain(struct pwc_device *pdev, int *value) | ||
963 | { | ||
964 | unsigned char buf; | ||
965 | int ret; | ||
966 | |||
967 | ret = recv_control_msg(pdev, | ||
968 | GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, &buf, sizeof(buf)); | ||
969 | if (ret < 0) | ||
970 | return ret; | ||
971 | *value = buf << 8; | ||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | |||
976 | static int pwc_set_wb_speed(struct pwc_device *pdev, int speed) | 602 | static int pwc_set_wb_speed(struct pwc_device *pdev, int speed) |
977 | { | 603 | { |
978 | unsigned char buf; | 604 | unsigned char buf; |
@@ -1070,164 +696,6 @@ static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) | |||
1070 | return 0; | 696 | return 0; |
1071 | } | 697 | } |
1072 | 698 | ||
1073 | int pwc_set_contour(struct pwc_device *pdev, int contour) | ||
1074 | { | ||
1075 | unsigned char buf; | ||
1076 | int ret; | ||
1077 | |||
1078 | if (contour < 0) | ||
1079 | buf = 0xff; /* auto contour on */ | ||
1080 | else | ||
1081 | buf = 0x0; /* auto contour off */ | ||
1082 | ret = send_control_msg(pdev, | ||
1083 | SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, &buf, sizeof(buf)); | ||
1084 | if (ret < 0) | ||
1085 | return ret; | ||
1086 | |||
1087 | if (contour < 0) | ||
1088 | return 0; | ||
1089 | if (contour > 0xffff) | ||
1090 | contour = 0xffff; | ||
1091 | |||
1092 | buf = (contour >> 10); /* contour preset is [0..3f] */ | ||
1093 | ret = send_control_msg(pdev, | ||
1094 | SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, &buf, sizeof(buf)); | ||
1095 | if (ret < 0) | ||
1096 | return ret; | ||
1097 | return 0; | ||
1098 | } | ||
1099 | |||
1100 | int pwc_get_contour(struct pwc_device *pdev, int *contour) | ||
1101 | { | ||
1102 | unsigned char buf; | ||
1103 | int ret; | ||
1104 | |||
1105 | ret = recv_control_msg(pdev, | ||
1106 | GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, &buf, sizeof(buf)); | ||
1107 | if (ret < 0) | ||
1108 | return ret; | ||
1109 | |||
1110 | if (buf == 0) { | ||
1111 | /* auto mode off, query current preset value */ | ||
1112 | ret = recv_control_msg(pdev, | ||
1113 | GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, | ||
1114 | &buf, sizeof(buf)); | ||
1115 | if (ret < 0) | ||
1116 | return ret; | ||
1117 | *contour = buf << 10; | ||
1118 | } | ||
1119 | else | ||
1120 | *contour = -1; | ||
1121 | return 0; | ||
1122 | } | ||
1123 | |||
1124 | |||
1125 | int pwc_set_backlight(struct pwc_device *pdev, int backlight) | ||
1126 | { | ||
1127 | unsigned char buf; | ||
1128 | |||
1129 | if (backlight) | ||
1130 | buf = 0xff; | ||
1131 | else | ||
1132 | buf = 0x0; | ||
1133 | return send_control_msg(pdev, | ||
1134 | SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, | ||
1135 | &buf, sizeof(buf)); | ||
1136 | } | ||
1137 | |||
1138 | int pwc_get_backlight(struct pwc_device *pdev, int *backlight) | ||
1139 | { | ||
1140 | int ret; | ||
1141 | unsigned char buf; | ||
1142 | |||
1143 | ret = recv_control_msg(pdev, | ||
1144 | GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, | ||
1145 | &buf, sizeof(buf)); | ||
1146 | if (ret < 0) | ||
1147 | return ret; | ||
1148 | *backlight = !!buf; | ||
1149 | return 0; | ||
1150 | } | ||
1151 | |||
1152 | int pwc_set_colour_mode(struct pwc_device *pdev, int colour) | ||
1153 | { | ||
1154 | unsigned char buf; | ||
1155 | |||
1156 | if (colour) | ||
1157 | buf = 0xff; | ||
1158 | else | ||
1159 | buf = 0x0; | ||
1160 | return send_control_msg(pdev, | ||
1161 | SET_CHROM_CTL, COLOUR_MODE_FORMATTER, &buf, sizeof(buf)); | ||
1162 | } | ||
1163 | |||
1164 | int pwc_get_colour_mode(struct pwc_device *pdev, int *colour) | ||
1165 | { | ||
1166 | int ret; | ||
1167 | unsigned char buf; | ||
1168 | |||
1169 | ret = recv_control_msg(pdev, | ||
1170 | GET_CHROM_CTL, COLOUR_MODE_FORMATTER, &buf, sizeof(buf)); | ||
1171 | if (ret < 0) | ||
1172 | return ret; | ||
1173 | *colour = !!buf; | ||
1174 | return 0; | ||
1175 | } | ||
1176 | |||
1177 | |||
1178 | int pwc_set_flicker(struct pwc_device *pdev, int flicker) | ||
1179 | { | ||
1180 | unsigned char buf; | ||
1181 | |||
1182 | if (flicker) | ||
1183 | buf = 0xff; | ||
1184 | else | ||
1185 | buf = 0x0; | ||
1186 | return send_control_msg(pdev, | ||
1187 | SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, &buf, sizeof(buf)); | ||
1188 | } | ||
1189 | |||
1190 | int pwc_get_flicker(struct pwc_device *pdev, int *flicker) | ||
1191 | { | ||
1192 | int ret; | ||
1193 | unsigned char buf; | ||
1194 | |||
1195 | ret = recv_control_msg(pdev, | ||
1196 | GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, &buf, sizeof(buf)); | ||
1197 | if (ret < 0) | ||
1198 | return ret; | ||
1199 | *flicker = !!buf; | ||
1200 | return 0; | ||
1201 | } | ||
1202 | |||
1203 | int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise) | ||
1204 | { | ||
1205 | unsigned char buf; | ||
1206 | |||
1207 | if (noise < 0) | ||
1208 | noise = 0; | ||
1209 | if (noise > 3) | ||
1210 | noise = 3; | ||
1211 | buf = noise; | ||
1212 | return send_control_msg(pdev, | ||
1213 | SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, | ||
1214 | &buf, sizeof(buf)); | ||
1215 | } | ||
1216 | |||
1217 | int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise) | ||
1218 | { | ||
1219 | int ret; | ||
1220 | unsigned char buf; | ||
1221 | |||
1222 | ret = recv_control_msg(pdev, | ||
1223 | GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, | ||
1224 | &buf, sizeof(buf)); | ||
1225 | if (ret < 0) | ||
1226 | return ret; | ||
1227 | *noise = buf; | ||
1228 | return 0; | ||
1229 | } | ||
1230 | |||
1231 | static int _pwc_mpt_reset(struct pwc_device *pdev, int flags) | 699 | static int _pwc_mpt_reset(struct pwc_device *pdev, int flags) |
1232 | { | 700 | { |
1233 | unsigned char buf; | 701 | unsigned char buf; |
@@ -1357,37 +825,41 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) | |||
1357 | /* copy local variable to arg */ | 825 | /* copy local variable to arg */ |
1358 | #define ARG_OUT(ARG_name) /* nothing */ | 826 | #define ARG_OUT(ARG_name) /* nothing */ |
1359 | 827 | ||
828 | /* | ||
829 | * Our ctrls use native values, but the old custom pwc ioctl interface expects | ||
830 | * values from 0 - 65535, define 2 helper functions to scale things. */ | ||
831 | static int pwc_ioctl_g_ctrl(struct v4l2_ctrl *ctrl) | ||
832 | { | ||
833 | return v4l2_ctrl_g_ctrl(ctrl) * 65535 / ctrl->maximum; | ||
834 | } | ||
835 | |||
836 | static int pwc_ioctl_s_ctrl(struct v4l2_ctrl *ctrl, int val) | ||
837 | { | ||
838 | return v4l2_ctrl_s_ctrl(ctrl, val * ctrl->maximum / 65535); | ||
839 | } | ||
840 | |||
1360 | long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) | 841 | long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) |
1361 | { | 842 | { |
1362 | long ret = 0; | 843 | long ret = 0; |
1363 | 844 | ||
1364 | switch(cmd) { | 845 | switch(cmd) { |
1365 | case VIDIOCPWCRUSER: | 846 | case VIDIOCPWCRUSER: |
1366 | { | 847 | ret = pwc_button_ctrl(pdev, RESTORE_USER_DEFAULTS_FORMATTER); |
1367 | if (pwc_restore_user(pdev)) | ||
1368 | ret = -EINVAL; | ||
1369 | break; | 848 | break; |
1370 | } | ||
1371 | 849 | ||
1372 | case VIDIOCPWCSUSER: | 850 | case VIDIOCPWCSUSER: |
1373 | { | 851 | ret = pwc_button_ctrl(pdev, SAVE_USER_DEFAULTS_FORMATTER); |
1374 | if (pwc_save_user(pdev)) | ||
1375 | ret = -EINVAL; | ||
1376 | break; | 852 | break; |
1377 | } | ||
1378 | 853 | ||
1379 | case VIDIOCPWCFACTORY: | 854 | case VIDIOCPWCFACTORY: |
1380 | { | 855 | ret = pwc_button_ctrl(pdev, RESTORE_FACTORY_DEFAULTS_FORMATTER); |
1381 | if (pwc_restore_factory(pdev)) | ||
1382 | ret = -EINVAL; | ||
1383 | break; | 856 | break; |
1384 | } | ||
1385 | 857 | ||
1386 | case VIDIOCPWCSCQUAL: | 858 | case VIDIOCPWCSCQUAL: |
1387 | { | 859 | { |
1388 | ARG_DEF(int, qual) | 860 | ARG_DEF(int, qual) |
1389 | 861 | ||
1390 | if (pdev->iso_init) { | 862 | if (vb2_is_streaming(&pdev->vb_queue)) { |
1391 | ret = -EBUSY; | 863 | ret = -EBUSY; |
1392 | break; | 864 | break; |
1393 | } | 865 | } |
@@ -1431,71 +903,59 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) | |||
1431 | case VIDIOCPWCSAGC: | 903 | case VIDIOCPWCSAGC: |
1432 | { | 904 | { |
1433 | ARG_DEF(int, agc) | 905 | ARG_DEF(int, agc) |
1434 | |||
1435 | ARG_IN(agc) | 906 | ARG_IN(agc) |
1436 | if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc))) | 907 | ret = v4l2_ctrl_s_ctrl(pdev->autogain, ARGR(agc) < 0); |
1437 | ret = -EINVAL; | 908 | if (ret == 0 && ARGR(agc) >= 0) |
909 | ret = pwc_ioctl_s_ctrl(pdev->gain, ARGR(agc)); | ||
1438 | break; | 910 | break; |
1439 | } | 911 | } |
1440 | 912 | ||
1441 | case VIDIOCPWCGAGC: | 913 | case VIDIOCPWCGAGC: |
1442 | { | 914 | { |
1443 | ARG_DEF(int, agc) | 915 | ARG_DEF(int, agc) |
1444 | 916 | if (v4l2_ctrl_g_ctrl(pdev->autogain)) | |
1445 | if (pwc_get_agc(pdev, ARGA(agc))) | 917 | ARGR(agc) = -1; |
1446 | ret = -EINVAL; | 918 | else |
919 | ARGR(agc) = pwc_ioctl_g_ctrl(pdev->gain); | ||
1447 | ARG_OUT(agc) | 920 | ARG_OUT(agc) |
1448 | break; | 921 | break; |
1449 | } | 922 | } |
1450 | 923 | ||
1451 | case VIDIOCPWCSSHUTTER: | 924 | case VIDIOCPWCSSHUTTER: |
1452 | { | 925 | { |
1453 | ARG_DEF(int, shutter_speed) | 926 | ARG_DEF(int, shutter) |
1454 | 927 | ARG_IN(shutter) | |
1455 | ARG_IN(shutter_speed) | 928 | ret = v4l2_ctrl_s_ctrl(pdev->exposure_auto, |
1456 | ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed)); | 929 | /* Menu idx 0 = auto, idx 1 = manual */ |
930 | ARGR(shutter) >= 0); | ||
931 | if (ret == 0 && ARGR(shutter) >= 0) | ||
932 | ret = pwc_ioctl_s_ctrl(pdev->exposure, ARGR(shutter)); | ||
1457 | break; | 933 | break; |
1458 | } | 934 | } |
1459 | 935 | ||
1460 | case VIDIOCPWCSAWB: | 936 | case VIDIOCPWCSAWB: |
1461 | { | 937 | { |
1462 | ARG_DEF(struct pwc_whitebalance, wb) | 938 | ARG_DEF(struct pwc_whitebalance, wb) |
1463 | |||
1464 | ARG_IN(wb) | 939 | ARG_IN(wb) |
1465 | ret = pwc_set_awb(pdev, ARGR(wb).mode); | 940 | ret = v4l2_ctrl_s_ctrl(pdev->auto_white_balance, |
1466 | if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) { | 941 | ARGR(wb).mode); |
1467 | pwc_set_red_gain(pdev, ARGR(wb).manual_red); | 942 | if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL) |
1468 | pwc_set_blue_gain(pdev, ARGR(wb).manual_blue); | 943 | ret = pwc_ioctl_s_ctrl(pdev->red_balance, |
1469 | } | 944 | ARGR(wb).manual_red); |
945 | if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL) | ||
946 | ret = pwc_ioctl_s_ctrl(pdev->blue_balance, | ||
947 | ARGR(wb).manual_blue); | ||
1470 | break; | 948 | break; |
1471 | } | 949 | } |
1472 | 950 | ||
1473 | case VIDIOCPWCGAWB: | 951 | case VIDIOCPWCGAWB: |
1474 | { | 952 | { |
1475 | ARG_DEF(struct pwc_whitebalance, wb) | 953 | ARG_DEF(struct pwc_whitebalance, wb) |
1476 | 954 | ARGR(wb).mode = v4l2_ctrl_g_ctrl(pdev->auto_white_balance); | |
1477 | memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance)); | 955 | ARGR(wb).manual_red = ARGR(wb).read_red = |
1478 | ARGR(wb).mode = pwc_get_awb(pdev); | 956 | pwc_ioctl_g_ctrl(pdev->red_balance); |
1479 | if (ARGR(wb).mode < 0) | 957 | ARGR(wb).manual_blue = ARGR(wb).read_blue = |
1480 | ret = -EINVAL; | 958 | pwc_ioctl_g_ctrl(pdev->blue_balance); |
1481 | else { | ||
1482 | if (ARGR(wb).mode == PWC_WB_MANUAL) { | ||
1483 | ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red); | ||
1484 | if (ret < 0) | ||
1485 | break; | ||
1486 | ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue); | ||
1487 | if (ret < 0) | ||
1488 | break; | ||
1489 | } | ||
1490 | if (ARGR(wb).mode == PWC_WB_AUTO) { | ||
1491 | ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red); | ||
1492 | if (ret < 0) | ||
1493 | break; | ||
1494 | ret = pwc_read_blue_gain(pdev, &ARGR(wb).read_blue); | ||
1495 | if (ret < 0) | ||
1496 | break; | ||
1497 | } | ||
1498 | } | ||
1499 | ARG_OUT(wb) | 959 | ARG_OUT(wb) |
1500 | break; | 960 | break; |
1501 | } | 961 | } |
@@ -1549,17 +1009,20 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) | |||
1549 | case VIDIOCPWCSCONTOUR: | 1009 | case VIDIOCPWCSCONTOUR: |
1550 | { | 1010 | { |
1551 | ARG_DEF(int, contour) | 1011 | ARG_DEF(int, contour) |
1552 | |||
1553 | ARG_IN(contour) | 1012 | ARG_IN(contour) |
1554 | ret = pwc_set_contour(pdev, ARGR(contour)); | 1013 | ret = v4l2_ctrl_s_ctrl(pdev->autocontour, ARGR(contour) < 0); |
1014 | if (ret == 0 && ARGR(contour) >= 0) | ||
1015 | ret = pwc_ioctl_s_ctrl(pdev->contour, ARGR(contour)); | ||
1555 | break; | 1016 | break; |
1556 | } | 1017 | } |
1557 | 1018 | ||
1558 | case VIDIOCPWCGCONTOUR: | 1019 | case VIDIOCPWCGCONTOUR: |
1559 | { | 1020 | { |
1560 | ARG_DEF(int, contour) | 1021 | ARG_DEF(int, contour) |
1561 | 1022 | if (v4l2_ctrl_g_ctrl(pdev->autocontour)) | |
1562 | ret = pwc_get_contour(pdev, ARGA(contour)); | 1023 | ARGR(contour) = -1; |
1024 | else | ||
1025 | ARGR(contour) = pwc_ioctl_g_ctrl(pdev->contour); | ||
1563 | ARG_OUT(contour) | 1026 | ARG_OUT(contour) |
1564 | break; | 1027 | break; |
1565 | } | 1028 | } |
@@ -1567,17 +1030,15 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) | |||
1567 | case VIDIOCPWCSBACKLIGHT: | 1030 | case VIDIOCPWCSBACKLIGHT: |
1568 | { | 1031 | { |
1569 | ARG_DEF(int, backlight) | 1032 | ARG_DEF(int, backlight) |
1570 | |||
1571 | ARG_IN(backlight) | 1033 | ARG_IN(backlight) |
1572 | ret = pwc_set_backlight(pdev, ARGR(backlight)); | 1034 | ret = v4l2_ctrl_s_ctrl(pdev->backlight, ARGR(backlight)); |
1573 | break; | 1035 | break; |
1574 | } | 1036 | } |
1575 | 1037 | ||
1576 | case VIDIOCPWCGBACKLIGHT: | 1038 | case VIDIOCPWCGBACKLIGHT: |
1577 | { | 1039 | { |
1578 | ARG_DEF(int, backlight) | 1040 | ARG_DEF(int, backlight) |
1579 | 1041 | ARGR(backlight) = v4l2_ctrl_g_ctrl(pdev->backlight); | |
1580 | ret = pwc_get_backlight(pdev, ARGA(backlight)); | ||
1581 | ARG_OUT(backlight) | 1042 | ARG_OUT(backlight) |
1582 | break; | 1043 | break; |
1583 | } | 1044 | } |
@@ -1585,17 +1046,15 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) | |||
1585 | case VIDIOCPWCSFLICKER: | 1046 | case VIDIOCPWCSFLICKER: |
1586 | { | 1047 | { |
1587 | ARG_DEF(int, flicker) | 1048 | ARG_DEF(int, flicker) |
1588 | |||
1589 | ARG_IN(flicker) | 1049 | ARG_IN(flicker) |
1590 | ret = pwc_set_flicker(pdev, ARGR(flicker)); | 1050 | ret = v4l2_ctrl_s_ctrl(pdev->flicker, ARGR(flicker)); |
1591 | break; | 1051 | break; |
1592 | } | 1052 | } |
1593 | 1053 | ||
1594 | case VIDIOCPWCGFLICKER: | 1054 | case VIDIOCPWCGFLICKER: |
1595 | { | 1055 | { |
1596 | ARG_DEF(int, flicker) | 1056 | ARG_DEF(int, flicker) |
1597 | 1057 | ARGR(flicker) = v4l2_ctrl_g_ctrl(pdev->flicker); | |
1598 | ret = pwc_get_flicker(pdev, ARGA(flicker)); | ||
1599 | ARG_OUT(flicker) | 1058 | ARG_OUT(flicker) |
1600 | break; | 1059 | break; |
1601 | } | 1060 | } |
@@ -1603,17 +1062,15 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) | |||
1603 | case VIDIOCPWCSDYNNOISE: | 1062 | case VIDIOCPWCSDYNNOISE: |
1604 | { | 1063 | { |
1605 | ARG_DEF(int, dynnoise) | 1064 | ARG_DEF(int, dynnoise) |
1606 | |||
1607 | ARG_IN(dynnoise) | 1065 | ARG_IN(dynnoise) |
1608 | ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise)); | 1066 | ret = v4l2_ctrl_s_ctrl(pdev->noise_reduction, ARGR(dynnoise)); |
1609 | break; | 1067 | break; |
1610 | } | 1068 | } |
1611 | 1069 | ||
1612 | case VIDIOCPWCGDYNNOISE: | 1070 | case VIDIOCPWCGDYNNOISE: |
1613 | { | 1071 | { |
1614 | ARG_DEF(int, dynnoise) | 1072 | ARG_DEF(int, dynnoise) |
1615 | 1073 | ARGR(dynnoise) = v4l2_ctrl_g_ctrl(pdev->noise_reduction); | |
1616 | ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise)); | ||
1617 | ARG_OUT(dynnoise); | 1074 | ARG_OUT(dynnoise); |
1618 | break; | 1075 | break; |
1619 | } | 1076 | } |
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 4c1c056ffdf..1d5a6db915f 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c | |||
@@ -679,6 +679,8 @@ static void pwc_video_release(struct video_device *vfd) | |||
679 | pdev->decompress_data = NULL; | 679 | pdev->decompress_data = NULL; |
680 | } | 680 | } |
681 | 681 | ||
682 | v4l2_ctrl_handler_free(&pdev->ctrl_handler); | ||
683 | |||
682 | kfree(pdev); | 684 | kfree(pdev); |
683 | } | 685 | } |
684 | 686 | ||
@@ -1224,9 +1226,14 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1224 | if (rc) | 1226 | if (rc) |
1225 | goto err_free_mem; | 1227 | goto err_free_mem; |
1226 | 1228 | ||
1227 | /* Initialize the webcam to sane values */ | 1229 | /* Register controls (and read default values from camera */ |
1228 | pwc_set_brightness(pdev, 0x7fff); | 1230 | rc = pwc_init_controls(pdev); |
1229 | pwc_set_agc(pdev, 1, 0); | 1231 | if (rc) { |
1232 | PWC_ERROR("Failed to register v4l2 controls (%d).\n", rc); | ||
1233 | goto err_free_mem; | ||
1234 | } | ||
1235 | |||
1236 | pdev->vdev.ctrl_handler = &pdev->ctrl_handler; | ||
1230 | 1237 | ||
1231 | /* And powerdown the camera until streaming starts */ | 1238 | /* And powerdown the camera until streaming starts */ |
1232 | pwc_camera_power(pdev, 0); | 1239 | pwc_camera_power(pdev, 0); |
@@ -1234,7 +1241,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1234 | rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr); | 1241 | rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr); |
1235 | if (rc < 0) { | 1242 | if (rc < 0) { |
1236 | PWC_ERROR("Failed to register as video device (%d).\n", rc); | 1243 | PWC_ERROR("Failed to register as video device (%d).\n", rc); |
1237 | goto err_free_mem; | 1244 | goto err_free_controls; |
1238 | } | 1245 | } |
1239 | rc = pwc_create_sysfs_files(pdev); | 1246 | rc = pwc_create_sysfs_files(pdev); |
1240 | if (rc) | 1247 | if (rc) |
@@ -1277,7 +1284,10 @@ err_video_unreg: | |||
1277 | if (hint < MAX_DEV_HINTS) | 1284 | if (hint < MAX_DEV_HINTS) |
1278 | device_hint[hint].pdev = NULL; | 1285 | device_hint[hint].pdev = NULL; |
1279 | video_unregister_device(&pdev->vdev); | 1286 | video_unregister_device(&pdev->vdev); |
1287 | err_free_controls: | ||
1288 | v4l2_ctrl_handler_free(&pdev->ctrl_handler); | ||
1280 | err_free_mem: | 1289 | err_free_mem: |
1290 | usb_set_intfdata(intf, NULL); | ||
1281 | kfree(pdev); | 1291 | kfree(pdev); |
1282 | return rc; | 1292 | return rc; |
1283 | } | 1293 | } |
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index 834055b71e0..986dd5d6187 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c | |||
@@ -2,6 +2,7 @@ | |||
2 | USB and Video4Linux interface part. | 2 | USB and Video4Linux interface part. |
3 | (C) 1999-2004 Nemosoft Unv. | 3 | (C) 1999-2004 Nemosoft Unv. |
4 | (C) 2004-2006 Luc Saillard (luc@saillard.org) | 4 | (C) 2004-2006 Luc Saillard (luc@saillard.org) |
5 | (C) 2011 Hans de Goede <hdegoede@redhat.com> | ||
5 | 6 | ||
6 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | 7 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx |
7 | driver and thus may have bugs that are not present in the original version. | 8 | driver and thus may have bugs that are not present in the original version. |
@@ -31,184 +32,314 @@ | |||
31 | #include <linux/module.h> | 32 | #include <linux/module.h> |
32 | #include <linux/poll.h> | 33 | #include <linux/poll.h> |
33 | #include <linux/vmalloc.h> | 34 | #include <linux/vmalloc.h> |
35 | #include <linux/jiffies.h> | ||
34 | #include <asm/io.h> | 36 | #include <asm/io.h> |
35 | 37 | ||
36 | #include "pwc.h" | 38 | #include "pwc.h" |
37 | 39 | ||
38 | static struct v4l2_queryctrl pwc_controls[] = { | 40 | #define PWC_CID_CUSTOM(ctrl) ((V4L2_CID_USER_BASE | 0xf000) + custom_ ## ctrl) |
39 | { | 41 | |
40 | .id = V4L2_CID_BRIGHTNESS, | 42 | static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl); |
41 | .type = V4L2_CTRL_TYPE_INTEGER, | 43 | static int pwc_s_ctrl(struct v4l2_ctrl *ctrl); |
42 | .name = "Brightness", | 44 | |
43 | .minimum = 0, | 45 | static const struct v4l2_ctrl_ops pwc_ctrl_ops = { |
44 | .maximum = 128, | 46 | .g_volatile_ctrl = pwc_g_volatile_ctrl, |
45 | .step = 1, | 47 | .s_ctrl = pwc_s_ctrl, |
46 | .default_value = 64, | 48 | }; |
47 | }, | 49 | |
48 | { | 50 | enum { awb_indoor, awb_outdoor, awb_fl, awb_manual, awb_auto }; |
49 | .id = V4L2_CID_CONTRAST, | 51 | enum { custom_autocontour, custom_contour, custom_noise_reduction, |
50 | .type = V4L2_CTRL_TYPE_INTEGER, | 52 | custom_save_user, custom_restore_user, custom_restore_factory }; |
51 | .name = "Contrast", | 53 | |
52 | .minimum = 0, | 54 | const char * const pwc_auto_whitebal_qmenu[] = { |
53 | .maximum = 64, | 55 | "Indoor (Incandescant Lighting) Mode", |
54 | .step = 1, | 56 | "Outdoor (Sunlight) Mode", |
55 | .default_value = 0, | 57 | "Indoor (Fluorescent Lighting) Mode", |
56 | }, | 58 | "Manual Mode", |
57 | { | 59 | "Auto Mode", |
58 | .id = V4L2_CID_SATURATION, | 60 | NULL |
59 | .type = V4L2_CTRL_TYPE_INTEGER, | 61 | }; |
60 | .name = "Saturation", | 62 | |
61 | .minimum = -100, | 63 | static const struct v4l2_ctrl_config pwc_auto_white_balance_cfg = { |
62 | .maximum = 100, | 64 | .ops = &pwc_ctrl_ops, |
63 | .step = 1, | 65 | .id = V4L2_CID_AUTO_WHITE_BALANCE, |
64 | .default_value = 0, | 66 | .type = V4L2_CTRL_TYPE_MENU, |
65 | }, | 67 | .max = awb_auto, |
66 | { | 68 | .qmenu = pwc_auto_whitebal_qmenu, |
67 | .id = V4L2_CID_GAMMA, | 69 | }; |
68 | .type = V4L2_CTRL_TYPE_INTEGER, | 70 | |
69 | .name = "Gamma", | 71 | static const struct v4l2_ctrl_config pwc_autocontour_cfg = { |
70 | .minimum = 0, | 72 | .ops = &pwc_ctrl_ops, |
71 | .maximum = 32, | 73 | .id = PWC_CID_CUSTOM(autocontour), |
72 | .step = 1, | 74 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
73 | .default_value = 0, | 75 | .name = "Auto contour", |
74 | }, | 76 | .min = 0, |
75 | { | 77 | .max = 1, |
76 | .id = V4L2_CID_RED_BALANCE, | 78 | .step = 1, |
77 | .type = V4L2_CTRL_TYPE_INTEGER, | 79 | }; |
78 | .name = "Red Gain", | 80 | |
79 | .minimum = 0, | 81 | static const struct v4l2_ctrl_config pwc_contour_cfg = { |
80 | .maximum = 256, | 82 | .ops = &pwc_ctrl_ops, |
81 | .step = 1, | 83 | .id = PWC_CID_CUSTOM(contour), |
82 | .default_value = 0, | 84 | .type = V4L2_CTRL_TYPE_INTEGER, |
83 | }, | 85 | .name = "Contour", |
84 | { | 86 | .min = 0, |
85 | .id = V4L2_CID_BLUE_BALANCE, | 87 | .max = 63, |
86 | .type = V4L2_CTRL_TYPE_INTEGER, | 88 | .step = 1, |
87 | .name = "Blue Gain", | 89 | }; |
88 | .minimum = 0, | 90 | |
89 | .maximum = 256, | 91 | static const struct v4l2_ctrl_config pwc_backlight_cfg = { |
90 | .step = 1, | 92 | .ops = &pwc_ctrl_ops, |
91 | .default_value = 0, | 93 | .id = V4L2_CID_BACKLIGHT_COMPENSATION, |
92 | }, | 94 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
93 | { | 95 | .min = 0, |
94 | .id = V4L2_CID_AUTO_WHITE_BALANCE, | 96 | .max = 1, |
95 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 97 | .step = 1, |
96 | .name = "Auto White Balance", | ||
97 | .minimum = 0, | ||
98 | .maximum = 1, | ||
99 | .step = 1, | ||
100 | .default_value = 0, | ||
101 | }, | ||
102 | { | ||
103 | .id = V4L2_CID_EXPOSURE, | ||
104 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
105 | .name = "Shutter Speed (Exposure)", | ||
106 | .minimum = 0, | ||
107 | .maximum = 256, | ||
108 | .step = 1, | ||
109 | .default_value = 200, | ||
110 | }, | ||
111 | { | ||
112 | .id = V4L2_CID_AUTOGAIN, | ||
113 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
114 | .name = "Auto Gain Enabled", | ||
115 | .minimum = 0, | ||
116 | .maximum = 1, | ||
117 | .step = 1, | ||
118 | .default_value = 1, | ||
119 | }, | ||
120 | { | ||
121 | .id = V4L2_CID_GAIN, | ||
122 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
123 | .name = "Gain Level", | ||
124 | .minimum = 0, | ||
125 | .maximum = 256, | ||
126 | .step = 1, | ||
127 | .default_value = 0, | ||
128 | }, | ||
129 | { | ||
130 | .id = V4L2_CID_PRIVATE_SAVE_USER, | ||
131 | .type = V4L2_CTRL_TYPE_BUTTON, | ||
132 | .name = "Save User Settings", | ||
133 | .minimum = 0, | ||
134 | .maximum = 0, | ||
135 | .step = 0, | ||
136 | .default_value = 0, | ||
137 | }, | ||
138 | { | ||
139 | .id = V4L2_CID_PRIVATE_RESTORE_USER, | ||
140 | .type = V4L2_CTRL_TYPE_BUTTON, | ||
141 | .name = "Restore User Settings", | ||
142 | .minimum = 0, | ||
143 | .maximum = 0, | ||
144 | .step = 0, | ||
145 | .default_value = 0, | ||
146 | }, | ||
147 | { | ||
148 | .id = V4L2_CID_PRIVATE_RESTORE_FACTORY, | ||
149 | .type = V4L2_CTRL_TYPE_BUTTON, | ||
150 | .name = "Restore Factory Settings", | ||
151 | .minimum = 0, | ||
152 | .maximum = 0, | ||
153 | .step = 0, | ||
154 | .default_value = 0, | ||
155 | }, | ||
156 | { | ||
157 | .id = V4L2_CID_PRIVATE_COLOUR_MODE, | ||
158 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
159 | .name = "Colour mode", | ||
160 | .minimum = 0, | ||
161 | .maximum = 1, | ||
162 | .step = 1, | ||
163 | .default_value = 0, | ||
164 | }, | ||
165 | { | ||
166 | .id = V4L2_CID_PRIVATE_AUTOCONTOUR, | ||
167 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
168 | .name = "Auto contour", | ||
169 | .minimum = 0, | ||
170 | .maximum = 1, | ||
171 | .step = 1, | ||
172 | .default_value = 0, | ||
173 | }, | ||
174 | { | ||
175 | .id = V4L2_CID_PRIVATE_CONTOUR, | ||
176 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
177 | .name = "Contour", | ||
178 | .minimum = 0, | ||
179 | .maximum = 63, | ||
180 | .step = 1, | ||
181 | .default_value = 0, | ||
182 | }, | ||
183 | { | ||
184 | .id = V4L2_CID_PRIVATE_BACKLIGHT, | ||
185 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
186 | .name = "Backlight compensation", | ||
187 | .minimum = 0, | ||
188 | .maximum = 1, | ||
189 | .step = 1, | ||
190 | .default_value = 0, | ||
191 | }, | ||
192 | { | ||
193 | .id = V4L2_CID_PRIVATE_FLICKERLESS, | ||
194 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
195 | .name = "Flickerless", | ||
196 | .minimum = 0, | ||
197 | .maximum = 1, | ||
198 | .step = 1, | ||
199 | .default_value = 0, | ||
200 | }, | ||
201 | { | ||
202 | .id = V4L2_CID_PRIVATE_NOISE_REDUCTION, | ||
203 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
204 | .name = "Noise reduction", | ||
205 | .minimum = 0, | ||
206 | .maximum = 3, | ||
207 | .step = 1, | ||
208 | .default_value = 0, | ||
209 | }, | ||
210 | }; | 98 | }; |
211 | 99 | ||
100 | static const struct v4l2_ctrl_config pwc_flicker_cfg = { | ||
101 | .ops = &pwc_ctrl_ops, | ||
102 | .id = V4L2_CID_BAND_STOP_FILTER, | ||
103 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
104 | .min = 0, | ||
105 | .max = 1, | ||
106 | .step = 1, | ||
107 | }; | ||
108 | |||
109 | static const struct v4l2_ctrl_config pwc_noise_reduction_cfg = { | ||
110 | .ops = &pwc_ctrl_ops, | ||
111 | .id = PWC_CID_CUSTOM(noise_reduction), | ||
112 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
113 | .name = "Dynamic Noise Reduction", | ||
114 | .min = 0, | ||
115 | .max = 3, | ||
116 | .step = 1, | ||
117 | }; | ||
118 | |||
119 | static const struct v4l2_ctrl_config pwc_save_user_cfg = { | ||
120 | .ops = &pwc_ctrl_ops, | ||
121 | .id = PWC_CID_CUSTOM(save_user), | ||
122 | .type = V4L2_CTRL_TYPE_BUTTON, | ||
123 | .name = "Save User Settings", | ||
124 | }; | ||
125 | |||
126 | static const struct v4l2_ctrl_config pwc_restore_user_cfg = { | ||
127 | .ops = &pwc_ctrl_ops, | ||
128 | .id = PWC_CID_CUSTOM(restore_user), | ||
129 | .type = V4L2_CTRL_TYPE_BUTTON, | ||
130 | .name = "Restore User Settings", | ||
131 | }; | ||
132 | |||
133 | static const struct v4l2_ctrl_config pwc_restore_factory_cfg = { | ||
134 | .ops = &pwc_ctrl_ops, | ||
135 | .id = PWC_CID_CUSTOM(restore_factory), | ||
136 | .type = V4L2_CTRL_TYPE_BUTTON, | ||
137 | .name = "Restore Factory Settings", | ||
138 | }; | ||
139 | |||
140 | int pwc_init_controls(struct pwc_device *pdev) | ||
141 | { | ||
142 | struct v4l2_ctrl_handler *hdl; | ||
143 | struct v4l2_ctrl_config cfg; | ||
144 | int r, def; | ||
145 | |||
146 | hdl = &pdev->ctrl_handler; | ||
147 | r = v4l2_ctrl_handler_init(hdl, 20); | ||
148 | if (r) | ||
149 | return r; | ||
150 | |||
151 | /* Brightness, contrast, saturation, gamma */ | ||
152 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, BRIGHTNESS_FORMATTER, &def); | ||
153 | if (r || def > 127) | ||
154 | def = 63; | ||
155 | pdev->brightness = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
156 | V4L2_CID_BRIGHTNESS, 0, 127, 1, def); | ||
157 | |||
158 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, CONTRAST_FORMATTER, &def); | ||
159 | if (r || def > 63) | ||
160 | def = 31; | ||
161 | pdev->contrast = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
162 | V4L2_CID_CONTRAST, 0, 63, 1, def); | ||
163 | |||
164 | if (pdev->type >= 675) { | ||
165 | if (pdev->type < 730) | ||
166 | pdev->saturation_fmt = SATURATION_MODE_FORMATTER2; | ||
167 | else | ||
168 | pdev->saturation_fmt = SATURATION_MODE_FORMATTER1; | ||
169 | r = pwc_get_s8_ctrl(pdev, GET_CHROM_CTL, pdev->saturation_fmt, | ||
170 | &def); | ||
171 | if (r || def < -100 || def > 100) | ||
172 | def = 0; | ||
173 | pdev->saturation = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
174 | V4L2_CID_SATURATION, -100, 100, 1, def); | ||
175 | } | ||
176 | |||
177 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, GAMMA_FORMATTER, &def); | ||
178 | if (r || def > 31) | ||
179 | def = 15; | ||
180 | pdev->gamma = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
181 | V4L2_CID_GAMMA, 0, 31, 1, def); | ||
182 | |||
183 | /* auto white balance, red gain, blue gain */ | ||
184 | r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, WB_MODE_FORMATTER, &def); | ||
185 | if (r || def > awb_auto) | ||
186 | def = awb_auto; | ||
187 | cfg = pwc_auto_white_balance_cfg; | ||
188 | cfg.name = v4l2_ctrl_get_name(cfg.id); | ||
189 | cfg.def = def; | ||
190 | pdev->auto_white_balance = v4l2_ctrl_new_custom(hdl, &cfg, NULL); | ||
191 | /* check auto controls to avoid NULL deref in v4l2_ctrl_auto_cluster */ | ||
192 | if (!pdev->auto_white_balance) | ||
193 | return hdl->error; | ||
194 | |||
195 | r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, | ||
196 | PRESET_MANUAL_RED_GAIN_FORMATTER, &def); | ||
197 | if (r) | ||
198 | def = 127; | ||
199 | pdev->red_balance = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
200 | V4L2_CID_RED_BALANCE, 0, 255, 1, def); | ||
201 | |||
202 | r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, | ||
203 | PRESET_MANUAL_BLUE_GAIN_FORMATTER, &def); | ||
204 | if (r) | ||
205 | def = 127; | ||
206 | pdev->blue_balance = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
207 | V4L2_CID_BLUE_BALANCE, 0, 255, 1, def); | ||
208 | |||
209 | v4l2_ctrl_auto_cluster(3, &pdev->auto_white_balance, awb_manual, | ||
210 | pdev->auto_white_balance->cur.val == awb_auto); | ||
211 | |||
212 | /* autogain, gain */ | ||
213 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, AGC_MODE_FORMATTER, &def); | ||
214 | if (r || (def != 0 && def != 0xff)) | ||
215 | def = 0; | ||
216 | /* Note a register value if 0 means auto gain is on */ | ||
217 | pdev->autogain = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
218 | V4L2_CID_AUTOGAIN, 0, 1, 1, def == 0); | ||
219 | if (!pdev->autogain) | ||
220 | return hdl->error; | ||
221 | |||
222 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, PRESET_AGC_FORMATTER, &def); | ||
223 | if (r || def > 63) | ||
224 | def = 31; | ||
225 | pdev->gain = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
226 | V4L2_CID_GAIN, 0, 63, 1, def); | ||
227 | |||
228 | /* auto exposure, exposure */ | ||
229 | if (DEVICE_USE_CODEC2(pdev->type)) { | ||
230 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, SHUTTER_MODE_FORMATTER, | ||
231 | &def); | ||
232 | if (r || (def != 0 && def != 0xff)) | ||
233 | def = 0; | ||
234 | /* | ||
235 | * def = 0 auto, def = ff manual | ||
236 | * menu idx 0 = auto, idx 1 = manual | ||
237 | */ | ||
238 | pdev->exposure_auto = v4l2_ctrl_new_std_menu(hdl, | ||
239 | &pwc_ctrl_ops, | ||
240 | V4L2_CID_EXPOSURE_AUTO, | ||
241 | 1, 0, def != 0); | ||
242 | if (!pdev->exposure_auto) | ||
243 | return hdl->error; | ||
244 | |||
245 | /* GET_LUM_CTL, PRESET_SHUTTER_FORMATTER is unreliable */ | ||
246 | r = pwc_get_u16_ctrl(pdev, GET_STATUS_CTL, | ||
247 | READ_SHUTTER_FORMATTER, &def); | ||
248 | if (r || def > 655) | ||
249 | def = 655; | ||
250 | pdev->exposure = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
251 | V4L2_CID_EXPOSURE, 0, 655, 1, def); | ||
252 | /* CODEC2: separate auto gain & auto exposure */ | ||
253 | v4l2_ctrl_auto_cluster(2, &pdev->autogain, 0, true); | ||
254 | v4l2_ctrl_auto_cluster(2, &pdev->exposure_auto, | ||
255 | V4L2_EXPOSURE_MANUAL, true); | ||
256 | } else if (DEVICE_USE_CODEC3(pdev->type)) { | ||
257 | /* GET_LUM_CTL, PRESET_SHUTTER_FORMATTER is unreliable */ | ||
258 | r = pwc_get_u16_ctrl(pdev, GET_STATUS_CTL, | ||
259 | READ_SHUTTER_FORMATTER, &def); | ||
260 | if (r || def > 255) | ||
261 | def = 255; | ||
262 | pdev->exposure = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
263 | V4L2_CID_EXPOSURE, 0, 255, 1, def); | ||
264 | /* CODEC3: both gain and exposure controlled by autogain */ | ||
265 | pdev->autogain_expo_cluster[0] = pdev->autogain; | ||
266 | pdev->autogain_expo_cluster[1] = pdev->gain; | ||
267 | pdev->autogain_expo_cluster[2] = pdev->exposure; | ||
268 | v4l2_ctrl_auto_cluster(3, pdev->autogain_expo_cluster, | ||
269 | 0, true); | ||
270 | } | ||
271 | |||
272 | /* color / bw setting */ | ||
273 | r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, COLOUR_MODE_FORMATTER, | ||
274 | &def); | ||
275 | if (r || (def != 0 && def != 0xff)) | ||
276 | def = 0xff; | ||
277 | /* def = 0 bw, def = ff color, menu idx 0 = color, idx 1 = bw */ | ||
278 | pdev->colorfx = v4l2_ctrl_new_std_menu(hdl, &pwc_ctrl_ops, | ||
279 | V4L2_CID_COLORFX, 1, 0, def == 0); | ||
280 | |||
281 | /* autocontour, contour */ | ||
282 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, &def); | ||
283 | if (r || (def != 0 && def != 0xff)) | ||
284 | def = 0; | ||
285 | cfg = pwc_autocontour_cfg; | ||
286 | cfg.def = def == 0; | ||
287 | pdev->autocontour = v4l2_ctrl_new_custom(hdl, &cfg, NULL); | ||
288 | if (!pdev->autocontour) | ||
289 | return hdl->error; | ||
290 | |||
291 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, &def); | ||
292 | if (r || def > 63) | ||
293 | def = 31; | ||
294 | cfg = pwc_contour_cfg; | ||
295 | cfg.def = def; | ||
296 | pdev->contour = v4l2_ctrl_new_custom(hdl, &cfg, NULL); | ||
297 | |||
298 | v4l2_ctrl_auto_cluster(2, &pdev->autocontour, 0, false); | ||
299 | |||
300 | /* backlight */ | ||
301 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, | ||
302 | BACK_LIGHT_COMPENSATION_FORMATTER, &def); | ||
303 | if (r || (def != 0 && def != 0xff)) | ||
304 | def = 0; | ||
305 | cfg = pwc_backlight_cfg; | ||
306 | cfg.name = v4l2_ctrl_get_name(cfg.id); | ||
307 | cfg.def = def == 0; | ||
308 | pdev->backlight = v4l2_ctrl_new_custom(hdl, &cfg, NULL); | ||
309 | |||
310 | /* flikker rediction */ | ||
311 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, | ||
312 | FLICKERLESS_MODE_FORMATTER, &def); | ||
313 | if (r || (def != 0 && def != 0xff)) | ||
314 | def = 0; | ||
315 | cfg = pwc_flicker_cfg; | ||
316 | cfg.name = v4l2_ctrl_get_name(cfg.id); | ||
317 | cfg.def = def == 0; | ||
318 | pdev->flicker = v4l2_ctrl_new_custom(hdl, &cfg, NULL); | ||
319 | |||
320 | /* Dynamic noise reduction */ | ||
321 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, | ||
322 | DYNAMIC_NOISE_CONTROL_FORMATTER, &def); | ||
323 | if (r || def > 3) | ||
324 | def = 2; | ||
325 | cfg = pwc_noise_reduction_cfg; | ||
326 | cfg.def = def; | ||
327 | pdev->noise_reduction = v4l2_ctrl_new_custom(hdl, &cfg, NULL); | ||
328 | |||
329 | /* Save / Restore User / Factory Settings */ | ||
330 | pdev->save_user = v4l2_ctrl_new_custom(hdl, &pwc_save_user_cfg, NULL); | ||
331 | pdev->restore_user = v4l2_ctrl_new_custom(hdl, &pwc_restore_user_cfg, | ||
332 | NULL); | ||
333 | if (pdev->restore_user) | ||
334 | pdev->restore_user->flags = V4L2_CTRL_FLAG_UPDATE; | ||
335 | pdev->restore_factory = v4l2_ctrl_new_custom(hdl, | ||
336 | &pwc_restore_factory_cfg, | ||
337 | NULL); | ||
338 | if (pdev->restore_factory) | ||
339 | pdev->restore_factory->flags = V4L2_CTRL_FLAG_UPDATE; | ||
340 | |||
341 | return hdl->error; | ||
342 | } | ||
212 | 343 | ||
213 | static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f) | 344 | static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f) |
214 | { | 345 | { |
@@ -354,14 +485,13 @@ static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) | |||
354 | 485 | ||
355 | static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) | 486 | static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) |
356 | { | 487 | { |
357 | struct video_device *vdev = video_devdata(file); | ||
358 | struct pwc_device *pdev = video_drvdata(file); | 488 | struct pwc_device *pdev = video_drvdata(file); |
359 | 489 | ||
360 | if (!pdev->udev) | 490 | if (!pdev->udev) |
361 | return -ENODEV; | 491 | return -ENODEV; |
362 | 492 | ||
363 | strcpy(cap->driver, PWC_NAME); | 493 | strcpy(cap->driver, PWC_NAME); |
364 | strlcpy(cap->card, vdev->name, sizeof(cap->card)); | 494 | strlcpy(cap->card, pdev->vdev.name, sizeof(cap->card)); |
365 | usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info)); | 495 | usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info)); |
366 | cap->capabilities = | 496 | cap->capabilities = |
367 | V4L2_CAP_VIDEO_CAPTURE | | 497 | V4L2_CAP_VIDEO_CAPTURE | |
@@ -390,261 +520,328 @@ static int pwc_s_input(struct file *file, void *fh, unsigned int i) | |||
390 | return i ? -EINVAL : 0; | 520 | return i ? -EINVAL : 0; |
391 | } | 521 | } |
392 | 522 | ||
393 | static int pwc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) | 523 | static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
394 | { | 524 | { |
395 | int i, idx; | 525 | struct pwc_device *pdev = |
396 | u32 id; | 526 | container_of(ctrl->handler, struct pwc_device, ctrl_handler); |
397 | 527 | int ret = 0; | |
398 | id = c->id; | 528 | |
399 | if (id & V4L2_CTRL_FLAG_NEXT_CTRL) { | 529 | if (!pdev->udev) |
400 | id &= V4L2_CTRL_ID_MASK; | 530 | return -ENODEV; |
401 | id++; | 531 | |
402 | idx = -1; | 532 | switch (ctrl->id) { |
403 | for (i = 0; i < ARRAY_SIZE(pwc_controls); i++) { | 533 | case V4L2_CID_AUTO_WHITE_BALANCE: |
404 | if (pwc_controls[i].id < id) | 534 | if (pdev->color_bal_valid && time_before(jiffies, |
405 | continue; | 535 | pdev->last_color_bal_update + HZ / 4)) { |
406 | if (idx >= 0 | 536 | pdev->red_balance->val = pdev->last_red_balance; |
407 | && pwc_controls[i].id > pwc_controls[idx].id) | 537 | pdev->blue_balance->val = pdev->last_blue_balance; |
408 | continue; | 538 | break; |
409 | idx = i; | ||
410 | } | 539 | } |
411 | if (idx < 0) | 540 | ret = pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, |
412 | return -EINVAL; | 541 | READ_RED_GAIN_FORMATTER, |
413 | memcpy(c, &pwc_controls[idx], sizeof pwc_controls[0]); | 542 | &pdev->red_balance->val); |
414 | return 0; | 543 | if (ret) |
415 | } | 544 | break; |
416 | for (i = 0; i < sizeof(pwc_controls) / sizeof(struct v4l2_queryctrl); i++) { | 545 | ret = pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, |
417 | if (pwc_controls[i].id == c->id) { | 546 | READ_BLUE_GAIN_FORMATTER, |
418 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n"); | 547 | &pdev->blue_balance->val); |
419 | memcpy(c, &pwc_controls[i], sizeof(struct v4l2_queryctrl)); | 548 | if (ret) |
420 | return 0; | 549 | break; |
550 | pdev->last_red_balance = pdev->red_balance->val; | ||
551 | pdev->last_blue_balance = pdev->blue_balance->val; | ||
552 | pdev->last_color_bal_update = jiffies; | ||
553 | pdev->color_bal_valid = true; | ||
554 | break; | ||
555 | case V4L2_CID_AUTOGAIN: | ||
556 | if (pdev->gain_valid && time_before(jiffies, | ||
557 | pdev->last_gain_update + HZ / 4)) { | ||
558 | pdev->gain->val = pdev->last_gain; | ||
559 | break; | ||
421 | } | 560 | } |
561 | ret = pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, | ||
562 | READ_AGC_FORMATTER, &pdev->gain->val); | ||
563 | if (ret) | ||
564 | break; | ||
565 | pdev->last_gain = pdev->gain->val; | ||
566 | pdev->last_gain_update = jiffies; | ||
567 | pdev->gain_valid = true; | ||
568 | if (!DEVICE_USE_CODEC3(pdev->type)) | ||
569 | break; | ||
570 | /* Fall through for CODEC3 where autogain also controls expo */ | ||
571 | case V4L2_CID_EXPOSURE_AUTO: | ||
572 | if (pdev->exposure_valid && time_before(jiffies, | ||
573 | pdev->last_exposure_update + HZ / 4)) { | ||
574 | pdev->exposure->val = pdev->last_exposure; | ||
575 | break; | ||
576 | } | ||
577 | ret = pwc_get_u16_ctrl(pdev, GET_STATUS_CTL, | ||
578 | READ_SHUTTER_FORMATTER, | ||
579 | &pdev->exposure->val); | ||
580 | if (ret) | ||
581 | break; | ||
582 | pdev->last_exposure = pdev->exposure->val; | ||
583 | pdev->last_exposure_update = jiffies; | ||
584 | pdev->exposure_valid = true; | ||
585 | break; | ||
586 | default: | ||
587 | ret = -EINVAL; | ||
422 | } | 588 | } |
423 | return -EINVAL; | 589 | |
590 | if (ret) | ||
591 | PWC_ERROR("g_ctrl %s error %d\n", ctrl->name, ret); | ||
592 | |||
593 | return ret; | ||
424 | } | 594 | } |
425 | 595 | ||
426 | static int pwc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) | 596 | static int pwc_set_awb(struct pwc_device *pdev) |
427 | { | 597 | { |
428 | struct pwc_device *pdev = video_drvdata(file); | 598 | int ret = 0; |
429 | int ret; | 599 | |
600 | if (pdev->auto_white_balance->is_new) { | ||
601 | ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, | ||
602 | WB_MODE_FORMATTER, | ||
603 | pdev->auto_white_balance->val); | ||
604 | if (ret) | ||
605 | return ret; | ||
606 | |||
607 | /* Update val when coming from auto or going to a preset */ | ||
608 | if (pdev->red_balance->is_volatile || | ||
609 | pdev->auto_white_balance->val == awb_indoor || | ||
610 | pdev->auto_white_balance->val == awb_outdoor || | ||
611 | pdev->auto_white_balance->val == awb_fl) { | ||
612 | if (!pdev->red_balance->is_new) | ||
613 | pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, | ||
614 | READ_RED_GAIN_FORMATTER, | ||
615 | &pdev->red_balance->val); | ||
616 | if (!pdev->blue_balance->is_new) | ||
617 | pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, | ||
618 | READ_BLUE_GAIN_FORMATTER, | ||
619 | &pdev->blue_balance->val); | ||
620 | } | ||
621 | if (pdev->auto_white_balance->val == awb_auto) { | ||
622 | pdev->red_balance->is_volatile = true; | ||
623 | pdev->blue_balance->is_volatile = true; | ||
624 | pdev->color_bal_valid = false; /* Force cache update */ | ||
625 | } else { | ||
626 | pdev->red_balance->is_volatile = false; | ||
627 | pdev->blue_balance->is_volatile = false; | ||
628 | } | ||
629 | } | ||
430 | 630 | ||
431 | if (!pdev->udev) | 631 | if (ret == 0 && pdev->red_balance->is_new) { |
432 | return -ENODEV; | 632 | if (pdev->auto_white_balance->val != awb_manual) |
633 | return -EBUSY; | ||
634 | ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, | ||
635 | PRESET_MANUAL_RED_GAIN_FORMATTER, | ||
636 | pdev->red_balance->val); | ||
637 | } | ||
433 | 638 | ||
434 | switch (c->id) { | 639 | if (ret == 0 && pdev->blue_balance->is_new) { |
435 | case V4L2_CID_BRIGHTNESS: | 640 | if (pdev->auto_white_balance->val != awb_manual) |
436 | c->value = pwc_get_brightness(pdev); | 641 | return -EBUSY; |
437 | if (c->value < 0) | 642 | ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, |
438 | return -EINVAL; | 643 | PRESET_MANUAL_BLUE_GAIN_FORMATTER, |
439 | return 0; | 644 | pdev->blue_balance->val); |
440 | case V4L2_CID_CONTRAST: | 645 | } |
441 | c->value = pwc_get_contrast(pdev); | 646 | return ret; |
442 | if (c->value < 0) | 647 | } |
443 | return -EINVAL; | ||
444 | return 0; | ||
445 | case V4L2_CID_SATURATION: | ||
446 | ret = pwc_get_saturation(pdev, &c->value); | ||
447 | if (ret < 0) | ||
448 | return -EINVAL; | ||
449 | return 0; | ||
450 | case V4L2_CID_GAMMA: | ||
451 | c->value = pwc_get_gamma(pdev); | ||
452 | if (c->value < 0) | ||
453 | return -EINVAL; | ||
454 | return 0; | ||
455 | case V4L2_CID_RED_BALANCE: | ||
456 | ret = pwc_get_red_gain(pdev, &c->value); | ||
457 | if (ret < 0) | ||
458 | return -EINVAL; | ||
459 | c->value >>= 8; | ||
460 | return 0; | ||
461 | case V4L2_CID_BLUE_BALANCE: | ||
462 | ret = pwc_get_blue_gain(pdev, &c->value); | ||
463 | if (ret < 0) | ||
464 | return -EINVAL; | ||
465 | c->value >>= 8; | ||
466 | return 0; | ||
467 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
468 | ret = pwc_get_awb(pdev); | ||
469 | if (ret < 0) | ||
470 | return -EINVAL; | ||
471 | c->value = (ret == PWC_WB_MANUAL) ? 0 : 1; | ||
472 | return 0; | ||
473 | case V4L2_CID_GAIN: | ||
474 | ret = pwc_get_agc(pdev, &c->value); | ||
475 | if (ret < 0) | ||
476 | return -EINVAL; | ||
477 | c->value >>= 8; | ||
478 | return 0; | ||
479 | case V4L2_CID_AUTOGAIN: | ||
480 | ret = pwc_get_agc(pdev, &c->value); | ||
481 | if (ret < 0) | ||
482 | return -EINVAL; | ||
483 | c->value = (c->value < 0) ? 1 : 0; | ||
484 | return 0; | ||
485 | case V4L2_CID_EXPOSURE: | ||
486 | ret = pwc_get_shutter_speed(pdev, &c->value); | ||
487 | if (ret < 0) | ||
488 | return -EINVAL; | ||
489 | return 0; | ||
490 | case V4L2_CID_PRIVATE_COLOUR_MODE: | ||
491 | ret = pwc_get_colour_mode(pdev, &c->value); | ||
492 | if (ret < 0) | ||
493 | return -EINVAL; | ||
494 | return 0; | ||
495 | case V4L2_CID_PRIVATE_AUTOCONTOUR: | ||
496 | ret = pwc_get_contour(pdev, &c->value); | ||
497 | if (ret < 0) | ||
498 | return -EINVAL; | ||
499 | c->value = (c->value == -1 ? 1 : 0); | ||
500 | return 0; | ||
501 | case V4L2_CID_PRIVATE_CONTOUR: | ||
502 | ret = pwc_get_contour(pdev, &c->value); | ||
503 | if (ret < 0) | ||
504 | return -EINVAL; | ||
505 | c->value >>= 10; | ||
506 | return 0; | ||
507 | case V4L2_CID_PRIVATE_BACKLIGHT: | ||
508 | ret = pwc_get_backlight(pdev, &c->value); | ||
509 | if (ret < 0) | ||
510 | return -EINVAL; | ||
511 | return 0; | ||
512 | case V4L2_CID_PRIVATE_FLICKERLESS: | ||
513 | ret = pwc_get_flicker(pdev, &c->value); | ||
514 | if (ret < 0) | ||
515 | return -EINVAL; | ||
516 | c->value = (c->value ? 1 : 0); | ||
517 | return 0; | ||
518 | case V4L2_CID_PRIVATE_NOISE_REDUCTION: | ||
519 | ret = pwc_get_dynamic_noise(pdev, &c->value); | ||
520 | if (ret < 0) | ||
521 | return -EINVAL; | ||
522 | return 0; | ||
523 | 648 | ||
524 | case V4L2_CID_PRIVATE_SAVE_USER: | 649 | /* For CODEC2 models which have separate autogain and auto exposure */ |
525 | case V4L2_CID_PRIVATE_RESTORE_USER: | 650 | static int pwc_set_autogain(struct pwc_device *pdev) |
526 | case V4L2_CID_PRIVATE_RESTORE_FACTORY: | 651 | { |
527 | return -EINVAL; | 652 | int ret = 0; |
653 | |||
654 | if (pdev->autogain->is_new) { | ||
655 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, | ||
656 | AGC_MODE_FORMATTER, | ||
657 | pdev->autogain->val ? 0 : 0xff); | ||
658 | if (ret) | ||
659 | return ret; | ||
660 | if (pdev->autogain->val) | ||
661 | pdev->gain_valid = false; /* Force cache update */ | ||
662 | else if (!pdev->gain->is_new) | ||
663 | pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, | ||
664 | READ_AGC_FORMATTER, | ||
665 | &pdev->gain->val); | ||
528 | } | 666 | } |
529 | return -EINVAL; | 667 | if (ret == 0 && pdev->gain->is_new) { |
668 | if (pdev->autogain->val) | ||
669 | return -EBUSY; | ||
670 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, | ||
671 | PRESET_AGC_FORMATTER, | ||
672 | pdev->gain->val); | ||
673 | } | ||
674 | return ret; | ||
530 | } | 675 | } |
531 | 676 | ||
532 | static int pwc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) | 677 | /* For CODEC2 models which have separate autogain and auto exposure */ |
678 | static int pwc_set_exposure_auto(struct pwc_device *pdev) | ||
533 | { | 679 | { |
534 | struct pwc_device *pdev = video_drvdata(file); | 680 | int ret = 0; |
535 | int ret; | 681 | int is_auto = pdev->exposure_auto->val == V4L2_EXPOSURE_AUTO; |
682 | |||
683 | if (pdev->exposure_auto->is_new) { | ||
684 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, | ||
685 | SHUTTER_MODE_FORMATTER, | ||
686 | is_auto ? 0 : 0xff); | ||
687 | if (ret) | ||
688 | return ret; | ||
689 | if (is_auto) | ||
690 | pdev->exposure_valid = false; /* Force cache update */ | ||
691 | else if (!pdev->exposure->is_new) | ||
692 | pwc_get_u16_ctrl(pdev, GET_STATUS_CTL, | ||
693 | READ_SHUTTER_FORMATTER, | ||
694 | &pdev->exposure->val); | ||
695 | } | ||
696 | if (ret == 0 && pdev->exposure->is_new) { | ||
697 | if (is_auto) | ||
698 | return -EBUSY; | ||
699 | ret = pwc_set_u16_ctrl(pdev, SET_LUM_CTL, | ||
700 | PRESET_SHUTTER_FORMATTER, | ||
701 | pdev->exposure->val); | ||
702 | } | ||
703 | return ret; | ||
704 | } | ||
705 | |||
706 | /* For CODEC3 models which have autogain controlling both gain and exposure */ | ||
707 | static int pwc_set_autogain_expo(struct pwc_device *pdev) | ||
708 | { | ||
709 | int ret = 0; | ||
710 | |||
711 | if (pdev->autogain->is_new) { | ||
712 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, | ||
713 | AGC_MODE_FORMATTER, | ||
714 | pdev->autogain->val ? 0 : 0xff); | ||
715 | if (ret) | ||
716 | return ret; | ||
717 | if (pdev->autogain->val) { | ||
718 | pdev->gain_valid = false; /* Force cache update */ | ||
719 | pdev->exposure_valid = false; /* Force cache update */ | ||
720 | } else { | ||
721 | if (!pdev->gain->is_new) | ||
722 | pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, | ||
723 | READ_AGC_FORMATTER, | ||
724 | &pdev->gain->val); | ||
725 | if (!pdev->exposure->is_new) | ||
726 | pwc_get_u16_ctrl(pdev, GET_STATUS_CTL, | ||
727 | READ_SHUTTER_FORMATTER, | ||
728 | &pdev->exposure->val); | ||
729 | } | ||
730 | } | ||
731 | if (ret == 0 && pdev->gain->is_new) { | ||
732 | if (pdev->autogain->val) | ||
733 | return -EBUSY; | ||
734 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, | ||
735 | PRESET_AGC_FORMATTER, | ||
736 | pdev->gain->val); | ||
737 | } | ||
738 | if (ret == 0 && pdev->exposure->is_new) { | ||
739 | if (pdev->autogain->val) | ||
740 | return -EBUSY; | ||
741 | ret = pwc_set_u16_ctrl(pdev, SET_LUM_CTL, | ||
742 | PRESET_SHUTTER_FORMATTER, | ||
743 | pdev->exposure->val); | ||
744 | } | ||
745 | return ret; | ||
746 | } | ||
747 | |||
748 | static int pwc_s_ctrl(struct v4l2_ctrl *ctrl) | ||
749 | { | ||
750 | struct pwc_device *pdev = | ||
751 | container_of(ctrl->handler, struct pwc_device, ctrl_handler); | ||
752 | int ret = 0; | ||
536 | 753 | ||
537 | if (!pdev->udev) | 754 | if (!pdev->udev) |
538 | return -ENODEV; | 755 | return -ENODEV; |
539 | 756 | ||
540 | switch (c->id) { | 757 | switch (ctrl->id) { |
541 | case V4L2_CID_BRIGHTNESS: | 758 | case V4L2_CID_BRIGHTNESS: |
542 | c->value <<= 9; | 759 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, |
543 | ret = pwc_set_brightness(pdev, c->value); | 760 | BRIGHTNESS_FORMATTER, ctrl->val); |
544 | if (ret < 0) | 761 | break; |
545 | return -EINVAL; | ||
546 | return 0; | ||
547 | case V4L2_CID_CONTRAST: | 762 | case V4L2_CID_CONTRAST: |
548 | c->value <<= 10; | 763 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, |
549 | ret = pwc_set_contrast(pdev, c->value); | 764 | CONTRAST_FORMATTER, ctrl->val); |
550 | if (ret < 0) | 765 | break; |
551 | return -EINVAL; | ||
552 | return 0; | ||
553 | case V4L2_CID_SATURATION: | 766 | case V4L2_CID_SATURATION: |
554 | ret = pwc_set_saturation(pdev, c->value); | 767 | ret = pwc_set_s8_ctrl(pdev, SET_CHROM_CTL, |
555 | if (ret < 0) | 768 | pdev->saturation_fmt, ctrl->val); |
556 | return -EINVAL; | 769 | break; |
557 | return 0; | ||
558 | case V4L2_CID_GAMMA: | 770 | case V4L2_CID_GAMMA: |
559 | c->value <<= 11; | 771 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, |
560 | ret = pwc_set_gamma(pdev, c->value); | 772 | GAMMA_FORMATTER, ctrl->val); |
561 | if (ret < 0) | 773 | break; |
562 | return -EINVAL; | ||
563 | return 0; | ||
564 | case V4L2_CID_RED_BALANCE: | ||
565 | c->value <<= 8; | ||
566 | ret = pwc_set_red_gain(pdev, c->value); | ||
567 | if (ret < 0) | ||
568 | return -EINVAL; | ||
569 | return 0; | ||
570 | case V4L2_CID_BLUE_BALANCE: | ||
571 | c->value <<= 8; | ||
572 | ret = pwc_set_blue_gain(pdev, c->value); | ||
573 | if (ret < 0) | ||
574 | return -EINVAL; | ||
575 | return 0; | ||
576 | case V4L2_CID_AUTO_WHITE_BALANCE: | 774 | case V4L2_CID_AUTO_WHITE_BALANCE: |
577 | c->value = (c->value == 0) ? PWC_WB_MANUAL : PWC_WB_AUTO; | 775 | ret = pwc_set_awb(pdev); |
578 | ret = pwc_set_awb(pdev, c->value); | 776 | break; |
579 | if (ret < 0) | ||
580 | return -EINVAL; | ||
581 | return 0; | ||
582 | case V4L2_CID_EXPOSURE: | ||
583 | c->value <<= 8; | ||
584 | ret = pwc_set_shutter_speed(pdev, c->value ? 0 : 1, c->value); | ||
585 | if (ret < 0) | ||
586 | return -EINVAL; | ||
587 | return 0; | ||
588 | case V4L2_CID_AUTOGAIN: | 777 | case V4L2_CID_AUTOGAIN: |
589 | /* autogain off means nothing without a gain */ | 778 | if (DEVICE_USE_CODEC2(pdev->type)) |
590 | if (c->value == 0) | 779 | ret = pwc_set_autogain(pdev); |
591 | return 0; | 780 | else if (DEVICE_USE_CODEC3(pdev->type)) |
592 | ret = pwc_set_agc(pdev, c->value, 0); | 781 | ret = pwc_set_autogain_expo(pdev); |
593 | if (ret < 0) | 782 | else |
594 | return -EINVAL; | 783 | ret = -EINVAL; |
595 | return 0; | 784 | break; |
596 | case V4L2_CID_GAIN: | 785 | case V4L2_CID_EXPOSURE_AUTO: |
597 | c->value <<= 8; | 786 | if (DEVICE_USE_CODEC2(pdev->type)) |
598 | ret = pwc_set_agc(pdev, 0, c->value); | 787 | ret = pwc_set_exposure_auto(pdev); |
599 | if (ret < 0) | 788 | else |
600 | return -EINVAL; | 789 | ret = -EINVAL; |
601 | return 0; | 790 | break; |
602 | case V4L2_CID_PRIVATE_SAVE_USER: | 791 | case V4L2_CID_COLORFX: |
603 | if (pwc_save_user(pdev)) | 792 | ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, |
604 | return -EINVAL; | 793 | COLOUR_MODE_FORMATTER, |
605 | return 0; | 794 | ctrl->val ? 0 : 0xff); |
606 | case V4L2_CID_PRIVATE_RESTORE_USER: | 795 | break; |
607 | if (pwc_restore_user(pdev)) | 796 | case PWC_CID_CUSTOM(autocontour): |
608 | return -EINVAL; | 797 | if (pdev->autocontour->is_new) { |
609 | return 0; | 798 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, |
610 | case V4L2_CID_PRIVATE_RESTORE_FACTORY: | 799 | AUTO_CONTOUR_FORMATTER, |
611 | if (pwc_restore_factory(pdev)) | 800 | pdev->autocontour->val ? 0 : 0xff); |
612 | return -EINVAL; | 801 | } |
613 | return 0; | 802 | if (ret == 0 && pdev->contour->is_new) { |
614 | case V4L2_CID_PRIVATE_COLOUR_MODE: | 803 | if (pdev->autocontour->val) { |
615 | ret = pwc_set_colour_mode(pdev, c->value); | 804 | ret = -EBUSY; |
616 | if (ret < 0) | 805 | break; |
617 | return -EINVAL; | 806 | } |
618 | return 0; | 807 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, |
619 | case V4L2_CID_PRIVATE_AUTOCONTOUR: | 808 | PRESET_CONTOUR_FORMATTER, |
620 | c->value = (c->value == 1) ? -1 : 0; | 809 | pdev->contour->val); |
621 | ret = pwc_set_contour(pdev, c->value); | 810 | } |
622 | if (ret < 0) | 811 | break; |
623 | return -EINVAL; | 812 | case V4L2_CID_BACKLIGHT_COMPENSATION: |
624 | return 0; | 813 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, |
625 | case V4L2_CID_PRIVATE_CONTOUR: | 814 | BACK_LIGHT_COMPENSATION_FORMATTER, |
626 | c->value <<= 10; | 815 | ctrl->val ? 0 : 0xff); |
627 | ret = pwc_set_contour(pdev, c->value); | 816 | break; |
628 | if (ret < 0) | 817 | case V4L2_CID_BAND_STOP_FILTER: |
629 | return -EINVAL; | 818 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, |
630 | return 0; | 819 | FLICKERLESS_MODE_FORMATTER, |
631 | case V4L2_CID_PRIVATE_BACKLIGHT: | 820 | ctrl->val ? 0 : 0xff); |
632 | ret = pwc_set_backlight(pdev, c->value); | 821 | break; |
633 | if (ret < 0) | 822 | case PWC_CID_CUSTOM(noise_reduction): |
634 | return -EINVAL; | 823 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, |
635 | return 0; | 824 | DYNAMIC_NOISE_CONTROL_FORMATTER, |
636 | case V4L2_CID_PRIVATE_FLICKERLESS: | 825 | ctrl->val); |
637 | ret = pwc_set_flicker(pdev, c->value); | 826 | break; |
638 | if (ret < 0) | 827 | case PWC_CID_CUSTOM(save_user): |
639 | return -EINVAL; | 828 | ret = pwc_button_ctrl(pdev, SAVE_USER_DEFAULTS_FORMATTER); |
640 | case V4L2_CID_PRIVATE_NOISE_REDUCTION: | 829 | break; |
641 | ret = pwc_set_dynamic_noise(pdev, c->value); | 830 | case PWC_CID_CUSTOM(restore_user): |
642 | if (ret < 0) | 831 | ret = pwc_button_ctrl(pdev, RESTORE_USER_DEFAULTS_FORMATTER); |
643 | return -EINVAL; | 832 | break; |
644 | return 0; | 833 | case PWC_CID_CUSTOM(restore_factory): |
645 | 834 | ret = pwc_button_ctrl(pdev, | |
835 | RESTORE_FACTORY_DEFAULTS_FORMATTER); | ||
836 | break; | ||
837 | default: | ||
838 | ret = -EINVAL; | ||
646 | } | 839 | } |
647 | return -EINVAL; | 840 | |
841 | if (ret) | ||
842 | PWC_ERROR("s_ctrl %s error %d\n", ctrl->name, ret); | ||
843 | |||
844 | return ret; | ||
648 | } | 845 | } |
649 | 846 | ||
650 | static int pwc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) | 847 | static int pwc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) |
@@ -835,9 +1032,6 @@ const struct v4l2_ioctl_ops pwc_ioctl_ops = { | |||
835 | .vidioc_g_fmt_vid_cap = pwc_g_fmt_vid_cap, | 1032 | .vidioc_g_fmt_vid_cap = pwc_g_fmt_vid_cap, |
836 | .vidioc_s_fmt_vid_cap = pwc_s_fmt_vid_cap, | 1033 | .vidioc_s_fmt_vid_cap = pwc_s_fmt_vid_cap, |
837 | .vidioc_try_fmt_vid_cap = pwc_try_fmt_vid_cap, | 1034 | .vidioc_try_fmt_vid_cap = pwc_try_fmt_vid_cap, |
838 | .vidioc_queryctrl = pwc_queryctrl, | ||
839 | .vidioc_g_ctrl = pwc_g_ctrl, | ||
840 | .vidioc_s_ctrl = pwc_s_ctrl, | ||
841 | .vidioc_reqbufs = pwc_reqbufs, | 1035 | .vidioc_reqbufs = pwc_reqbufs, |
842 | .vidioc_querybuf = pwc_querybuf, | 1036 | .vidioc_querybuf = pwc_querybuf, |
843 | .vidioc_qbuf = pwc_qbuf, | 1037 | .vidioc_qbuf = pwc_qbuf, |
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h index 1cfb8b475a3..601a549988b 100644 --- a/drivers/media/video/pwc/pwc.h +++ b/drivers/media/video/pwc/pwc.h | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/videodev2.h> | 36 | #include <linux/videodev2.h> |
37 | #include <media/v4l2-common.h> | 37 | #include <media/v4l2-common.h> |
38 | #include <media/v4l2-ioctl.h> | 38 | #include <media/v4l2-ioctl.h> |
39 | #include <media/v4l2-ctrls.h> | ||
39 | #include <media/videobuf2-vmalloc.h> | 40 | #include <media/videobuf2-vmalloc.h> |
40 | #ifdef CONFIG_USB_PWC_INPUT_EVDEV | 41 | #ifdef CONFIG_USB_PWC_INPUT_EVDEV |
41 | #include <linux/input.h> | 42 | #include <linux/input.h> |
@@ -128,6 +129,61 @@ | |||
128 | #define DEVICE_USE_CODEC3(x) ((x)>=700) | 129 | #define DEVICE_USE_CODEC3(x) ((x)>=700) |
129 | #define DEVICE_USE_CODEC23(x) ((x)>=675) | 130 | #define DEVICE_USE_CODEC23(x) ((x)>=675) |
130 | 131 | ||
132 | /* Request types: video */ | ||
133 | #define SET_LUM_CTL 0x01 | ||
134 | #define GET_LUM_CTL 0x02 | ||
135 | #define SET_CHROM_CTL 0x03 | ||
136 | #define GET_CHROM_CTL 0x04 | ||
137 | #define SET_STATUS_CTL 0x05 | ||
138 | #define GET_STATUS_CTL 0x06 | ||
139 | #define SET_EP_STREAM_CTL 0x07 | ||
140 | #define GET_EP_STREAM_CTL 0x08 | ||
141 | #define GET_XX_CTL 0x09 | ||
142 | #define SET_XX_CTL 0x0A | ||
143 | #define GET_XY_CTL 0x0B | ||
144 | #define SET_XY_CTL 0x0C | ||
145 | #define SET_MPT_CTL 0x0D | ||
146 | #define GET_MPT_CTL 0x0E | ||
147 | |||
148 | /* Selectors for the Luminance controls [GS]ET_LUM_CTL */ | ||
149 | #define AGC_MODE_FORMATTER 0x2000 | ||
150 | #define PRESET_AGC_FORMATTER 0x2100 | ||
151 | #define SHUTTER_MODE_FORMATTER 0x2200 | ||
152 | #define PRESET_SHUTTER_FORMATTER 0x2300 | ||
153 | #define PRESET_CONTOUR_FORMATTER 0x2400 | ||
154 | #define AUTO_CONTOUR_FORMATTER 0x2500 | ||
155 | #define BACK_LIGHT_COMPENSATION_FORMATTER 0x2600 | ||
156 | #define CONTRAST_FORMATTER 0x2700 | ||
157 | #define DYNAMIC_NOISE_CONTROL_FORMATTER 0x2800 | ||
158 | #define FLICKERLESS_MODE_FORMATTER 0x2900 | ||
159 | #define AE_CONTROL_SPEED 0x2A00 | ||
160 | #define BRIGHTNESS_FORMATTER 0x2B00 | ||
161 | #define GAMMA_FORMATTER 0x2C00 | ||
162 | |||
163 | /* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */ | ||
164 | #define WB_MODE_FORMATTER 0x1000 | ||
165 | #define AWB_CONTROL_SPEED_FORMATTER 0x1100 | ||
166 | #define AWB_CONTROL_DELAY_FORMATTER 0x1200 | ||
167 | #define PRESET_MANUAL_RED_GAIN_FORMATTER 0x1300 | ||
168 | #define PRESET_MANUAL_BLUE_GAIN_FORMATTER 0x1400 | ||
169 | #define COLOUR_MODE_FORMATTER 0x1500 | ||
170 | #define SATURATION_MODE_FORMATTER1 0x1600 | ||
171 | #define SATURATION_MODE_FORMATTER2 0x1700 | ||
172 | |||
173 | /* Selectors for the Status controls [GS]ET_STATUS_CTL */ | ||
174 | #define SAVE_USER_DEFAULTS_FORMATTER 0x0200 | ||
175 | #define RESTORE_USER_DEFAULTS_FORMATTER 0x0300 | ||
176 | #define RESTORE_FACTORY_DEFAULTS_FORMATTER 0x0400 | ||
177 | #define READ_AGC_FORMATTER 0x0500 | ||
178 | #define READ_SHUTTER_FORMATTER 0x0600 | ||
179 | #define READ_RED_GAIN_FORMATTER 0x0700 | ||
180 | #define READ_BLUE_GAIN_FORMATTER 0x0800 | ||
181 | |||
182 | /* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */ | ||
183 | #define PT_RELATIVE_CONTROL_FORMATTER 0x01 | ||
184 | #define PT_RESET_CONTROL_FORMATTER 0x02 | ||
185 | #define PT_STATUS_FORMATTER 0x03 | ||
186 | |||
131 | /* intermediate buffers with raw data from the USB cam */ | 187 | /* intermediate buffers with raw data from the USB cam */ |
132 | struct pwc_frame_buf | 188 | struct pwc_frame_buf |
133 | { | 189 | { |
@@ -220,6 +276,55 @@ struct pwc_device | |||
220 | struct input_dev *button_dev; /* webcam snapshot button input */ | 276 | struct input_dev *button_dev; /* webcam snapshot button input */ |
221 | char button_phys[64]; | 277 | char button_phys[64]; |
222 | #endif | 278 | #endif |
279 | |||
280 | /* controls */ | ||
281 | struct v4l2_ctrl_handler ctrl_handler; | ||
282 | u16 saturation_fmt; | ||
283 | struct v4l2_ctrl *brightness; | ||
284 | struct v4l2_ctrl *contrast; | ||
285 | struct v4l2_ctrl *saturation; | ||
286 | struct v4l2_ctrl *gamma; | ||
287 | struct { | ||
288 | /* awb / red-blue balance cluster */ | ||
289 | struct v4l2_ctrl *auto_white_balance; | ||
290 | struct v4l2_ctrl *red_balance; | ||
291 | struct v4l2_ctrl *blue_balance; | ||
292 | /* usb ctrl transfers are slow, so we cache things */ | ||
293 | int color_bal_valid; | ||
294 | unsigned long last_color_bal_update; /* In jiffies */ | ||
295 | s32 last_red_balance; | ||
296 | s32 last_blue_balance; | ||
297 | }; | ||
298 | struct { | ||
299 | /* autogain / gain cluster */ | ||
300 | struct v4l2_ctrl *autogain; | ||
301 | struct v4l2_ctrl *gain; | ||
302 | int gain_valid; | ||
303 | unsigned long last_gain_update; /* In jiffies */ | ||
304 | s32 last_gain; | ||
305 | }; | ||
306 | struct { | ||
307 | /* exposure_auto / exposure cluster */ | ||
308 | struct v4l2_ctrl *exposure_auto; | ||
309 | struct v4l2_ctrl *exposure; | ||
310 | int exposure_valid; | ||
311 | unsigned long last_exposure_update; /* In jiffies */ | ||
312 | s32 last_exposure; | ||
313 | }; | ||
314 | struct v4l2_ctrl *colorfx; | ||
315 | struct { | ||
316 | /* autocontour/contour cluster */ | ||
317 | struct v4l2_ctrl *autocontour; | ||
318 | struct v4l2_ctrl *contour; | ||
319 | }; | ||
320 | struct v4l2_ctrl *backlight; | ||
321 | struct v4l2_ctrl *flicker; | ||
322 | struct v4l2_ctrl *noise_reduction; | ||
323 | struct v4l2_ctrl *save_user; | ||
324 | struct v4l2_ctrl *restore_user; | ||
325 | struct v4l2_ctrl *restore_factory; | ||
326 | /* CODEC3 models have both gain and exposure controlled by autogain */ | ||
327 | struct v4l2_ctrl *autogain_expo_cluster[3]; | ||
223 | }; | 328 | }; |
224 | 329 | ||
225 | /* Global variables */ | 330 | /* Global variables */ |
@@ -238,47 +343,20 @@ void pwc_construct(struct pwc_device *pdev); | |||
238 | /* Request a certain video mode. Returns < 0 if not possible */ | 343 | /* Request a certain video mode. Returns < 0 if not possible */ |
239 | extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); | 344 | extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); |
240 | extern unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size); | 345 | extern unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size); |
241 | /* Calculate the number of bytes per image (not frame) */ | ||
242 | extern int pwc_mpt_reset(struct pwc_device *pdev, int flags); | 346 | extern int pwc_mpt_reset(struct pwc_device *pdev, int flags); |
243 | extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt); | 347 | extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt); |
244 | |||
245 | /* Various controls; should be obvious. Value 0..65535, or < 0 on error */ | ||
246 | extern int pwc_get_brightness(struct pwc_device *pdev); | ||
247 | extern int pwc_set_brightness(struct pwc_device *pdev, int value); | ||
248 | extern int pwc_get_contrast(struct pwc_device *pdev); | ||
249 | extern int pwc_set_contrast(struct pwc_device *pdev, int value); | ||
250 | extern int pwc_get_gamma(struct pwc_device *pdev); | ||
251 | extern int pwc_set_gamma(struct pwc_device *pdev, int value); | ||
252 | extern int pwc_get_saturation(struct pwc_device *pdev, int *value); | ||
253 | extern int pwc_set_saturation(struct pwc_device *pdev, int value); | ||
254 | extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); | 348 | extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); |
255 | extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); | 349 | extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); |
256 | extern int pwc_restore_user(struct pwc_device *pdev); | 350 | |
257 | extern int pwc_save_user(struct pwc_device *pdev); | 351 | /* Control get / set helpers */ |
258 | extern int pwc_restore_factory(struct pwc_device *pdev); | 352 | int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data); |
259 | 353 | int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data); | |
260 | /* exported for use by v4l2 controls */ | 354 | int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data); |
261 | extern int pwc_get_red_gain(struct pwc_device *pdev, int *value); | 355 | #define pwc_set_s8_ctrl pwc_set_u8_ctrl |
262 | extern int pwc_set_red_gain(struct pwc_device *pdev, int value); | 356 | int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *dat); |
263 | extern int pwc_get_blue_gain(struct pwc_device *pdev, int *value); | 357 | int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data); |
264 | extern int pwc_set_blue_gain(struct pwc_device *pdev, int value); | 358 | int pwc_button_ctrl(struct pwc_device *pdev, u16 value); |
265 | extern int pwc_get_awb(struct pwc_device *pdev); | 359 | int pwc_init_controls(struct pwc_device *pdev); |
266 | extern int pwc_set_awb(struct pwc_device *pdev, int mode); | ||
267 | extern int pwc_set_agc(struct pwc_device *pdev, int mode, int value); | ||
268 | extern int pwc_get_agc(struct pwc_device *pdev, int *value); | ||
269 | extern int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value); | ||
270 | extern int pwc_get_shutter_speed(struct pwc_device *pdev, int *value); | ||
271 | |||
272 | extern int pwc_set_colour_mode(struct pwc_device *pdev, int colour); | ||
273 | extern int pwc_get_colour_mode(struct pwc_device *pdev, int *colour); | ||
274 | extern int pwc_set_contour(struct pwc_device *pdev, int contour); | ||
275 | extern int pwc_get_contour(struct pwc_device *pdev, int *contour); | ||
276 | extern int pwc_set_backlight(struct pwc_device *pdev, int backlight); | ||
277 | extern int pwc_get_backlight(struct pwc_device *pdev, int *backlight); | ||
278 | extern int pwc_set_flicker(struct pwc_device *pdev, int flicker); | ||
279 | extern int pwc_get_flicker(struct pwc_device *pdev, int *flicker); | ||
280 | extern int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise); | ||
281 | extern int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise); | ||
282 | 360 | ||
283 | /* Power down or up the camera; not supported by all models */ | 361 | /* Power down or up the camera; not supported by all models */ |
284 | extern void pwc_camera_power(struct pwc_device *pdev, int power); | 362 | extern void pwc_camera_power(struct pwc_device *pdev, int power); |