aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2011-06-26 11:52:01 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-07-27 16:53:45 -0400
commit6c9cac89c009c049a9ad29cdf0f51892410fe751 (patch)
tree6558d038ec77295c7c7dca1e6627369b6575d31c /drivers/media/video
parent04613c5e600e64840e4f753bd881cd5ab96ae403 (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.c729
-rw-r--r--drivers/media/video/pwc/pwc-if.c18
-rw-r--r--drivers/media/video/pwc/pwc-v4l.c1008
-rw-r--r--drivers/media/video/pwc/pwc.h152
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
124static const char *size2name[PSZ_MAX] = 72static 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
162static int _send_control_msg(struct pwc_device *pdev, 110static 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
216static inline int send_control_msg(struct pwc_device *pdev, 168static 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
225static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) 175static 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 */ 502int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
553int 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
565int 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 */ 515int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data)
579
580int 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
592int 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 */ 526int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
606
607int 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
619int 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] */
636int 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] */ 539int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
656int 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
677int 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
704int pwc_get_agc(struct pwc_device *pdev, int *value) 552int 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
737int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value) 566int 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 */
776int 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 */
821int 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
827int 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
833int 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 */
851int 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
872int 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
885int 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
900int 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
915int 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
930int 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 */
949static 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
962static 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
976static int pwc_set_wb_speed(struct pwc_device *pdev, int speed) 602static 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
1073int 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
1100int 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
1125int 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
1138int 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
1152int 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
1164int 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
1178int 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
1190int 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
1203int 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
1217int 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
1231static int _pwc_mpt_reset(struct pwc_device *pdev, int flags) 699static 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. */
831static int pwc_ioctl_g_ctrl(struct v4l2_ctrl *ctrl)
832{
833 return v4l2_ctrl_g_ctrl(ctrl) * 65535 / ctrl->maximum;
834}
835
836static 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
1360long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) 841long 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);
1287err_free_controls:
1288 v4l2_ctrl_handler_free(&pdev->ctrl_handler);
1280err_free_mem: 1289err_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
38static 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, 42static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl);
41 .type = V4L2_CTRL_TYPE_INTEGER, 43static int pwc_s_ctrl(struct v4l2_ctrl *ctrl);
42 .name = "Brightness", 44
43 .minimum = 0, 45static 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 { 50enum { awb_indoor, awb_outdoor, awb_fl, awb_manual, awb_auto };
49 .id = V4L2_CID_CONTRAST, 51enum { 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, 54const 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, 63static 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", 71static 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, 81static 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, 91static 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
100static 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
109static 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
119static 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
126static 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
133static 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
140int 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
213static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f) 344static 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
355static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) 486static 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
393static int pwc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) 523static 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
426static int pwc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) 596static 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: 650static 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
532static int pwc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) 677/* For CODEC2 models which have separate autogain and auto exposure */
678static 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 */
707static 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
748static 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
650static int pwc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) 847static 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 */
132struct pwc_frame_buf 188struct 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 */
239extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); 344extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot);
240extern unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size); 345extern 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) */
242extern int pwc_mpt_reset(struct pwc_device *pdev, int flags); 346extern int pwc_mpt_reset(struct pwc_device *pdev, int flags);
243extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt); 347extern 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 */
246extern int pwc_get_brightness(struct pwc_device *pdev);
247extern int pwc_set_brightness(struct pwc_device *pdev, int value);
248extern int pwc_get_contrast(struct pwc_device *pdev);
249extern int pwc_set_contrast(struct pwc_device *pdev, int value);
250extern int pwc_get_gamma(struct pwc_device *pdev);
251extern int pwc_set_gamma(struct pwc_device *pdev, int value);
252extern int pwc_get_saturation(struct pwc_device *pdev, int *value);
253extern int pwc_set_saturation(struct pwc_device *pdev, int value);
254extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); 348extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value);
255extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); 349extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor);
256extern int pwc_restore_user(struct pwc_device *pdev); 350
257extern int pwc_save_user(struct pwc_device *pdev); 351/* Control get / set helpers */
258extern int pwc_restore_factory(struct pwc_device *pdev); 352int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data);
259 353int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data);
260/* exported for use by v4l2 controls */ 354int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data);
261extern int pwc_get_red_gain(struct pwc_device *pdev, int *value); 355#define pwc_set_s8_ctrl pwc_set_u8_ctrl
262extern int pwc_set_red_gain(struct pwc_device *pdev, int value); 356int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *dat);
263extern int pwc_get_blue_gain(struct pwc_device *pdev, int *value); 357int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data);
264extern int pwc_set_blue_gain(struct pwc_device *pdev, int value); 358int pwc_button_ctrl(struct pwc_device *pdev, u16 value);
265extern int pwc_get_awb(struct pwc_device *pdev); 359int pwc_init_controls(struct pwc_device *pdev);
266extern int pwc_set_awb(struct pwc_device *pdev, int mode);
267extern int pwc_set_agc(struct pwc_device *pdev, int mode, int value);
268extern int pwc_get_agc(struct pwc_device *pdev, int *value);
269extern int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value);
270extern int pwc_get_shutter_speed(struct pwc_device *pdev, int *value);
271
272extern int pwc_set_colour_mode(struct pwc_device *pdev, int colour);
273extern int pwc_get_colour_mode(struct pwc_device *pdev, int *colour);
274extern int pwc_set_contour(struct pwc_device *pdev, int contour);
275extern int pwc_get_contour(struct pwc_device *pdev, int *contour);
276extern int pwc_set_backlight(struct pwc_device *pdev, int backlight);
277extern int pwc_get_backlight(struct pwc_device *pdev, int *backlight);
278extern int pwc_set_flicker(struct pwc_device *pdev, int flicker);
279extern int pwc_get_flicker(struct pwc_device *pdev, int *flicker);
280extern int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise);
281extern 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 */
284extern void pwc_camera_power(struct pwc_device *pdev, int power); 362extern void pwc_camera_power(struct pwc_device *pdev, int power);