diff options
Diffstat (limited to 'drivers/media/video/gspca')
-rw-r--r-- | drivers/media/video/gspca/se401.c | 184 |
1 files changed, 73 insertions, 111 deletions
diff --git a/drivers/media/video/gspca/se401.c b/drivers/media/video/gspca/se401.c index bb70092c2229..17e7f89a1122 100644 --- a/drivers/media/video/gspca/se401.c +++ b/drivers/media/video/gspca/se401.c | |||
@@ -45,15 +45,6 @@ MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); | |||
45 | MODULE_DESCRIPTION("Endpoints se401"); | 45 | MODULE_DESCRIPTION("Endpoints se401"); |
46 | MODULE_LICENSE("GPL"); | 46 | MODULE_LICENSE("GPL"); |
47 | 47 | ||
48 | /* controls */ | ||
49 | enum e_ctrl { | ||
50 | BRIGHTNESS, | ||
51 | GAIN, | ||
52 | EXPOSURE, | ||
53 | FREQ, | ||
54 | NCTRL /* number of controls */ | ||
55 | }; | ||
56 | |||
57 | /* exposure change state machine states */ | 48 | /* exposure change state machine states */ |
58 | enum { | 49 | enum { |
59 | EXPO_CHANGED, | 50 | EXPO_CHANGED, |
@@ -64,7 +55,11 @@ enum { | |||
64 | /* specific webcam descriptor */ | 55 | /* specific webcam descriptor */ |
65 | struct sd { | 56 | struct sd { |
66 | struct gspca_dev gspca_dev; /* !! must be the first item */ | 57 | struct gspca_dev gspca_dev; /* !! must be the first item */ |
67 | struct gspca_ctrl ctrls[NCTRL]; | 58 | struct { /* exposure/freq control cluster */ |
59 | struct v4l2_ctrl *exposure; | ||
60 | struct v4l2_ctrl *freq; | ||
61 | }; | ||
62 | bool has_brightness; | ||
68 | struct v4l2_pix_format fmts[MAX_MODES]; | 63 | struct v4l2_pix_format fmts[MAX_MODES]; |
69 | int pixels_read; | 64 | int pixels_read; |
70 | int packet_read; | 65 | int packet_read; |
@@ -77,60 +72,6 @@ struct sd { | |||
77 | int expo_change_state; | 72 | int expo_change_state; |
78 | }; | 73 | }; |
79 | 74 | ||
80 | static void setbrightness(struct gspca_dev *gspca_dev); | ||
81 | static void setgain(struct gspca_dev *gspca_dev); | ||
82 | static void setexposure(struct gspca_dev *gspca_dev); | ||
83 | |||
84 | static const struct ctrl sd_ctrls[NCTRL] = { | ||
85 | [BRIGHTNESS] = { | ||
86 | { | ||
87 | .id = V4L2_CID_BRIGHTNESS, | ||
88 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
89 | .name = "Brightness", | ||
90 | .minimum = 0, | ||
91 | .maximum = 255, | ||
92 | .step = 1, | ||
93 | .default_value = 15, | ||
94 | }, | ||
95 | .set_control = setbrightness | ||
96 | }, | ||
97 | [GAIN] = { | ||
98 | { | ||
99 | .id = V4L2_CID_GAIN, | ||
100 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
101 | .name = "Gain", | ||
102 | .minimum = 0, | ||
103 | .maximum = 50, /* Really 63 but > 50 is not pretty */ | ||
104 | .step = 1, | ||
105 | .default_value = 25, | ||
106 | }, | ||
107 | .set_control = setgain | ||
108 | }, | ||
109 | [EXPOSURE] = { | ||
110 | { | ||
111 | .id = V4L2_CID_EXPOSURE, | ||
112 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
113 | .name = "Exposure", | ||
114 | .minimum = 0, | ||
115 | .maximum = 32767, | ||
116 | .step = 1, | ||
117 | .default_value = 15000, | ||
118 | }, | ||
119 | .set_control = setexposure | ||
120 | }, | ||
121 | [FREQ] = { | ||
122 | { | ||
123 | .id = V4L2_CID_POWER_LINE_FREQUENCY, | ||
124 | .type = V4L2_CTRL_TYPE_MENU, | ||
125 | .name = "Light frequency filter", | ||
126 | .minimum = 0, | ||
127 | .maximum = 2, | ||
128 | .step = 1, | ||
129 | .default_value = 0, | ||
130 | }, | ||
131 | .set_control = setexposure | ||
132 | }, | ||
133 | }; | ||
134 | 75 | ||
135 | static void se401_write_req(struct gspca_dev *gspca_dev, u16 req, u16 value, | 76 | static void se401_write_req(struct gspca_dev *gspca_dev, u16 req, u16 value, |
136 | int silent) | 77 | int silent) |
@@ -224,22 +165,15 @@ static int se401_get_feature(struct gspca_dev *gspca_dev, u16 selector) | |||
224 | return gspca_dev->usb_buf[0] | (gspca_dev->usb_buf[1] << 8); | 165 | return gspca_dev->usb_buf[0] | (gspca_dev->usb_buf[1] << 8); |
225 | } | 166 | } |
226 | 167 | ||
227 | static void setbrightness(struct gspca_dev *gspca_dev) | 168 | static void setbrightness(struct gspca_dev *gspca_dev, s32 val) |
228 | { | 169 | { |
229 | struct sd *sd = (struct sd *) gspca_dev; | ||
230 | |||
231 | if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS)) | ||
232 | return; | ||
233 | |||
234 | /* HDG: this does not seem to do anything on my cam */ | 170 | /* HDG: this does not seem to do anything on my cam */ |
235 | se401_write_req(gspca_dev, SE401_REQ_SET_BRT, | 171 | se401_write_req(gspca_dev, SE401_REQ_SET_BRT, val, 0); |
236 | sd->ctrls[BRIGHTNESS].val, 0); | ||
237 | } | 172 | } |
238 | 173 | ||
239 | static void setgain(struct gspca_dev *gspca_dev) | 174 | static void setgain(struct gspca_dev *gspca_dev, s32 val) |
240 | { | 175 | { |
241 | struct sd *sd = (struct sd *) gspca_dev; | 176 | u16 gain = 63 - val; |
242 | u16 gain = 63 - sd->ctrls[GAIN].val; | ||
243 | 177 | ||
244 | /* red color gain */ | 178 | /* red color gain */ |
245 | se401_set_feature(gspca_dev, HV7131_REG_ARCG, gain); | 179 | se401_set_feature(gspca_dev, HV7131_REG_ARCG, gain); |
@@ -249,10 +183,10 @@ static void setgain(struct gspca_dev *gspca_dev) | |||
249 | se401_set_feature(gspca_dev, HV7131_REG_ABCG, gain); | 183 | se401_set_feature(gspca_dev, HV7131_REG_ABCG, gain); |
250 | } | 184 | } |
251 | 185 | ||
252 | static void setexposure(struct gspca_dev *gspca_dev) | 186 | static void setexposure(struct gspca_dev *gspca_dev, s32 val, s32 freq) |
253 | { | 187 | { |
254 | struct sd *sd = (struct sd *) gspca_dev; | 188 | struct sd *sd = (struct sd *) gspca_dev; |
255 | int integration = sd->ctrls[EXPOSURE].val << 6; | 189 | int integration = val << 6; |
256 | u8 expose_h, expose_m, expose_l; | 190 | u8 expose_h, expose_m, expose_l; |
257 | 191 | ||
258 | /* Do this before the set_feature calls, for proper timing wrt | 192 | /* Do this before the set_feature calls, for proper timing wrt |
@@ -262,9 +196,9 @@ static void setexposure(struct gspca_dev *gspca_dev) | |||
262 | through so be it */ | 196 | through so be it */ |
263 | sd->expo_change_state = EXPO_CHANGED; | 197 | sd->expo_change_state = EXPO_CHANGED; |
264 | 198 | ||
265 | if (sd->ctrls[FREQ].val == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) | 199 | if (freq == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) |
266 | integration = integration - integration % 106667; | 200 | integration = integration - integration % 106667; |
267 | if (sd->ctrls[FREQ].val == V4L2_CID_POWER_LINE_FREQUENCY_60HZ) | 201 | if (freq == V4L2_CID_POWER_LINE_FREQUENCY_60HZ) |
268 | integration = integration - integration % 88889; | 202 | integration = integration - integration % 88889; |
269 | 203 | ||
270 | expose_h = (integration >> 16); | 204 | expose_h = (integration >> 16); |
@@ -375,15 +309,12 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
375 | cam->bulk = 1; | 309 | cam->bulk = 1; |
376 | cam->bulk_size = BULK_SIZE; | 310 | cam->bulk_size = BULK_SIZE; |
377 | cam->bulk_nurbs = 4; | 311 | cam->bulk_nurbs = 4; |
378 | cam->ctrls = sd->ctrls; | ||
379 | sd->resetlevel = 0x2d; /* Set initial resetlevel */ | 312 | sd->resetlevel = 0x2d; /* Set initial resetlevel */ |
380 | 313 | ||
381 | /* See if the camera supports brightness */ | 314 | /* See if the camera supports brightness */ |
382 | se401_read_req(gspca_dev, SE401_REQ_GET_BRT, 1); | 315 | se401_read_req(gspca_dev, SE401_REQ_GET_BRT, 1); |
383 | if (gspca_dev->usb_err) { | 316 | sd->has_brightness = !!gspca_dev->usb_err; |
384 | gspca_dev->ctrl_dis = (1 << BRIGHTNESS); | 317 | gspca_dev->usb_err = 0; |
385 | gspca_dev->usb_err = 0; | ||
386 | } | ||
387 | 318 | ||
388 | return 0; | 319 | return 0; |
389 | } | 320 | } |
@@ -442,9 +373,7 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
442 | } | 373 | } |
443 | se401_set_feature(gspca_dev, SE401_OPERATINGMODE, mode); | 374 | se401_set_feature(gspca_dev, SE401_OPERATINGMODE, mode); |
444 | 375 | ||
445 | setbrightness(gspca_dev); | 376 | v4l2_ctrl_handler_setup(&gspca_dev->ctrl_handler); |
446 | setgain(gspca_dev); | ||
447 | setexposure(gspca_dev); | ||
448 | se401_set_feature(gspca_dev, HV7131_REG_ARLV, sd->resetlevel); | 377 | se401_set_feature(gspca_dev, HV7131_REG_ARLV, sd->resetlevel); |
449 | 378 | ||
450 | sd->packet_read = 0; | 379 | sd->packet_read = 0; |
@@ -666,27 +595,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, int len) | |||
666 | sd_pkt_scan_janggu(gspca_dev, data, len); | 595 | sd_pkt_scan_janggu(gspca_dev, data, len); |
667 | } | 596 | } |
668 | 597 | ||
669 | static int sd_querymenu(struct gspca_dev *gspca_dev, | ||
670 | struct v4l2_querymenu *menu) | ||
671 | { | ||
672 | switch (menu->id) { | ||
673 | case V4L2_CID_POWER_LINE_FREQUENCY: | ||
674 | switch (menu->index) { | ||
675 | case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: | ||
676 | strcpy((char *) menu->name, "NoFliker"); | ||
677 | return 0; | ||
678 | case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: | ||
679 | strcpy((char *) menu->name, "50 Hz"); | ||
680 | return 0; | ||
681 | case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: | ||
682 | strcpy((char *) menu->name, "60 Hz"); | ||
683 | return 0; | ||
684 | } | ||
685 | break; | ||
686 | } | ||
687 | return -EINVAL; | ||
688 | } | ||
689 | |||
690 | #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) | 598 | #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) |
691 | static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, int len) | 599 | static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, int len) |
692 | { | 600 | { |
@@ -714,19 +622,73 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, int len) | |||
714 | } | 622 | } |
715 | #endif | 623 | #endif |
716 | 624 | ||
625 | static int sd_s_ctrl(struct v4l2_ctrl *ctrl) | ||
626 | { | ||
627 | struct gspca_dev *gspca_dev = | ||
628 | container_of(ctrl->handler, struct gspca_dev, ctrl_handler); | ||
629 | struct sd *sd = (struct sd *)gspca_dev; | ||
630 | |||
631 | gspca_dev->usb_err = 0; | ||
632 | |||
633 | if (!gspca_dev->streaming) | ||
634 | return 0; | ||
635 | |||
636 | switch (ctrl->id) { | ||
637 | case V4L2_CID_BRIGHTNESS: | ||
638 | setbrightness(gspca_dev, ctrl->val); | ||
639 | break; | ||
640 | case V4L2_CID_GAIN: | ||
641 | setgain(gspca_dev, ctrl->val); | ||
642 | break; | ||
643 | case V4L2_CID_EXPOSURE: | ||
644 | setexposure(gspca_dev, ctrl->val, sd->freq->val); | ||
645 | break; | ||
646 | } | ||
647 | return gspca_dev->usb_err; | ||
648 | } | ||
649 | |||
650 | static const struct v4l2_ctrl_ops sd_ctrl_ops = { | ||
651 | .s_ctrl = sd_s_ctrl, | ||
652 | }; | ||
653 | |||
654 | static int sd_init_controls(struct gspca_dev *gspca_dev) | ||
655 | { | ||
656 | struct sd *sd = (struct sd *)gspca_dev; | ||
657 | struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; | ||
658 | |||
659 | gspca_dev->vdev.ctrl_handler = hdl; | ||
660 | v4l2_ctrl_handler_init(hdl, 4); | ||
661 | if (sd->has_brightness) | ||
662 | v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
663 | V4L2_CID_BRIGHTNESS, 0, 255, 1, 15); | ||
664 | /* max is really 63 but > 50 is not pretty */ | ||
665 | v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
666 | V4L2_CID_GAIN, 0, 50, 1, 25); | ||
667 | sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
668 | V4L2_CID_EXPOSURE, 0, 32767, 1, 15000); | ||
669 | sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, | ||
670 | V4L2_CID_POWER_LINE_FREQUENCY, | ||
671 | V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, 0); | ||
672 | |||
673 | if (hdl->error) { | ||
674 | pr_err("Could not initialize controls\n"); | ||
675 | return hdl->error; | ||
676 | } | ||
677 | v4l2_ctrl_cluster(2, &sd->exposure); | ||
678 | return 0; | ||
679 | } | ||
680 | |||
717 | /* sub-driver description */ | 681 | /* sub-driver description */ |
718 | static const struct sd_desc sd_desc = { | 682 | static const struct sd_desc sd_desc = { |
719 | .name = MODULE_NAME, | 683 | .name = MODULE_NAME, |
720 | .ctrls = sd_ctrls, | ||
721 | .nctrls = ARRAY_SIZE(sd_ctrls), | ||
722 | .config = sd_config, | 684 | .config = sd_config, |
723 | .init = sd_init, | 685 | .init = sd_init, |
686 | .init_controls = sd_init_controls, | ||
724 | .isoc_init = sd_isoc_init, | 687 | .isoc_init = sd_isoc_init, |
725 | .start = sd_start, | 688 | .start = sd_start, |
726 | .stopN = sd_stopN, | 689 | .stopN = sd_stopN, |
727 | .dq_callback = sd_dq_callback, | 690 | .dq_callback = sd_dq_callback, |
728 | .pkt_scan = sd_pkt_scan, | 691 | .pkt_scan = sd_pkt_scan, |
729 | .querymenu = sd_querymenu, | ||
730 | #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) | 692 | #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) |
731 | .int_pkt_scan = sd_int_pkt_scan, | 693 | .int_pkt_scan = sd_int_pkt_scan, |
732 | #endif | 694 | #endif |