diff options
-rw-r--r-- | drivers/media/video/gspca/coarse_expo_autogain.h | 116 | ||||
-rw-r--r-- | drivers/media/video/gspca/gspca.c | 2 | ||||
-rw-r--r-- | drivers/media/video/gspca/sonixb.c | 113 |
3 files changed, 193 insertions, 38 deletions
diff --git a/drivers/media/video/gspca/coarse_expo_autogain.h b/drivers/media/video/gspca/coarse_expo_autogain.h new file mode 100644 index 000000000000..1cb9d941eaf6 --- /dev/null +++ b/drivers/media/video/gspca/coarse_expo_autogain.h | |||
@@ -0,0 +1,116 @@ | |||
1 | /* | ||
2 | * Auto gain algorithm for camera's with a coarse exposure control | ||
3 | * | ||
4 | * Copyright (C) 2010 Hans de Goede <hdegoede@redhat.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | /* Autogain + exposure algorithm for cameras with a coarse exposure control | ||
22 | (usually this means we can only control the clockdiv to change exposure) | ||
23 | As changing the clockdiv so that the fps drops from 30 to 15 fps for | ||
24 | example, will lead to a huge exposure change (it effectively doubles), | ||
25 | this algorithm normally tries to only adjust the gain (between 40 and | ||
26 | 80 %) and if that does not help, only then changes exposure. This leads | ||
27 | to a much more stable image then using the knee algorithm which at | ||
28 | certain points of the knee graph will only try to adjust exposure, | ||
29 | which leads to oscilating as one exposure step is huge. | ||
30 | |||
31 | Note this assumes that the sd struct for the cam in question has | ||
32 | exp_too_high_cnt and exp_too_high_cnt int members for use by this function. | ||
33 | |||
34 | Returns 0 if no changes were made, 1 if the gain and or exposure settings | ||
35 | where changed. */ | ||
36 | static int gspca_coarse_grained_expo_autogain(struct gspca_dev *gspca_dev, | ||
37 | int avg_lum, int desired_avg_lum, int deadzone) | ||
38 | { | ||
39 | int i, steps, gain, orig_gain, exposure, orig_exposure; | ||
40 | int gain_low, gain_high; | ||
41 | const struct ctrl *gain_ctrl = NULL; | ||
42 | const struct ctrl *exposure_ctrl = NULL; | ||
43 | struct sd *sd = (struct sd *) gspca_dev; | ||
44 | int retval = 0; | ||
45 | |||
46 | for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { | ||
47 | if (gspca_dev->ctrl_dis & (1 << i)) | ||
48 | continue; | ||
49 | if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_GAIN) | ||
50 | gain_ctrl = &gspca_dev->sd_desc->ctrls[i]; | ||
51 | if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_EXPOSURE) | ||
52 | exposure_ctrl = &gspca_dev->sd_desc->ctrls[i]; | ||
53 | } | ||
54 | if (!gain_ctrl || !exposure_ctrl) { | ||
55 | PDEBUG(D_ERR, "Error: gspca_coarse_grained_expo_autogain " | ||
56 | "called on cam without gain or exposure"); | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | if (gain_ctrl->get(gspca_dev, &gain) || | ||
61 | exposure_ctrl->get(gspca_dev, &exposure)) | ||
62 | return 0; | ||
63 | |||
64 | orig_gain = gain; | ||
65 | orig_exposure = exposure; | ||
66 | gain_low = | ||
67 | (gain_ctrl->qctrl.maximum - gain_ctrl->qctrl.minimum) / 5 * 2; | ||
68 | gain_low += gain_ctrl->qctrl.minimum; | ||
69 | gain_high = | ||
70 | (gain_ctrl->qctrl.maximum - gain_ctrl->qctrl.minimum) / 5 * 4; | ||
71 | gain_high += gain_ctrl->qctrl.minimum; | ||
72 | |||
73 | /* If we are of a multiple of deadzone, do multiple steps to reach the | ||
74 | desired lumination fast (with the risc of a slight overshoot) */ | ||
75 | steps = (desired_avg_lum - avg_lum) / deadzone; | ||
76 | |||
77 | PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d", | ||
78 | avg_lum, desired_avg_lum, steps); | ||
79 | |||
80 | if ((gain + steps) > gain_high && | ||
81 | sd->exposure < exposure_ctrl->qctrl.maximum) { | ||
82 | gain = gain_high; | ||
83 | sd->exp_too_low_cnt++; | ||
84 | } else if ((gain + steps) < gain_low && | ||
85 | sd->exposure > exposure_ctrl->qctrl.minimum) { | ||
86 | gain = gain_low; | ||
87 | sd->exp_too_high_cnt++; | ||
88 | } else { | ||
89 | gain += steps; | ||
90 | if (gain > gain_ctrl->qctrl.maximum) | ||
91 | gain = gain_ctrl->qctrl.maximum; | ||
92 | else if (gain < gain_ctrl->qctrl.minimum) | ||
93 | gain = gain_ctrl->qctrl.minimum; | ||
94 | sd->exp_too_high_cnt = 0; | ||
95 | sd->exp_too_low_cnt = 0; | ||
96 | } | ||
97 | |||
98 | if (sd->exp_too_high_cnt > 3) { | ||
99 | exposure--; | ||
100 | sd->exp_too_high_cnt = 0; | ||
101 | } else if (sd->exp_too_low_cnt > 3) { | ||
102 | exposure++; | ||
103 | sd->exp_too_low_cnt = 0; | ||
104 | } | ||
105 | |||
106 | if (gain != orig_gain) { | ||
107 | gain_ctrl->set(gspca_dev, gain); | ||
108 | retval = 1; | ||
109 | } | ||
110 | if (exposure != orig_exposure) { | ||
111 | exposure_ctrl->set(gspca_dev, exposure); | ||
112 | retval = 1; | ||
113 | } | ||
114 | |||
115 | return retval; | ||
116 | } | ||
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 96a77697eb1e..2c662ed91b5b 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c | |||
@@ -2417,6 +2417,8 @@ int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum, | |||
2417 | int retval = 0; | 2417 | int retval = 0; |
2418 | 2418 | ||
2419 | for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { | 2419 | for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { |
2420 | if (gspca_dev->ctrl_dis & (1 << i)) | ||
2421 | continue; | ||
2420 | if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_GAIN) | 2422 | if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_GAIN) |
2421 | gain_ctrl = &gspca_dev->sd_desc->ctrls[i]; | 2423 | gain_ctrl = &gspca_dev->sd_desc->ctrls[i]; |
2422 | if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_EXPOSURE) | 2424 | if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_EXPOSURE) |
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index 4356423c6f99..dc2d88cdd4a2 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c | |||
@@ -54,9 +54,11 @@ struct sd { | |||
54 | struct gspca_dev gspca_dev; /* !! must be the first item */ | 54 | struct gspca_dev gspca_dev; /* !! must be the first item */ |
55 | atomic_t avg_lum; | 55 | atomic_t avg_lum; |
56 | int prev_avg_lum; | 56 | int prev_avg_lum; |
57 | int exp_too_low_cnt; | ||
58 | int exp_too_high_cnt; | ||
57 | 59 | ||
60 | unsigned short exposure; | ||
58 | unsigned char gain; | 61 | unsigned char gain; |
59 | unsigned char exposure; | ||
60 | unsigned char brightness; | 62 | unsigned char brightness; |
61 | unsigned char autogain; | 63 | unsigned char autogain; |
62 | unsigned char autogain_ignore_frames; | 64 | unsigned char autogain_ignore_frames; |
@@ -97,13 +99,15 @@ struct sensor_data { | |||
97 | /* sensor_data flags */ | 99 | /* sensor_data flags */ |
98 | #define F_GAIN 0x01 /* has gain */ | 100 | #define F_GAIN 0x01 /* has gain */ |
99 | #define F_SIF 0x02 /* sif or vga */ | 101 | #define F_SIF 0x02 /* sif or vga */ |
102 | #define F_COARSE_EXPO 0x04 /* exposure control is coarse */ | ||
100 | 103 | ||
101 | /* priv field of struct v4l2_pix_format flags (do not use low nibble!) */ | 104 | /* priv field of struct v4l2_pix_format flags (do not use low nibble!) */ |
102 | #define MODE_RAW 0x10 /* raw bayer mode */ | 105 | #define MODE_RAW 0x10 /* raw bayer mode */ |
103 | #define MODE_REDUCED_SIF 0x20 /* vga mode (320x240 / 160x120) on sif cam */ | 106 | #define MODE_REDUCED_SIF 0x20 /* vga mode (320x240 / 160x120) on sif cam */ |
104 | 107 | ||
105 | /* ctrl_dis helper macros */ | 108 | /* ctrl_dis helper macros */ |
106 | #define NO_EXPO ((1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)) | 109 | #define NO_EXPO ((1 << EXPOSURE_IDX) | (1 << COARSE_EXPOSURE_IDX) | \ |
110 | (1 << AUTOGAIN_IDX)) | ||
107 | #define NO_FREQ (1 << FREQ_IDX) | 111 | #define NO_FREQ (1 << FREQ_IDX) |
108 | #define NO_BRIGHTNESS (1 << BRIGHTNESS_IDX) | 112 | #define NO_BRIGHTNESS (1 << BRIGHTNESS_IDX) |
109 | 113 | ||
@@ -129,11 +133,10 @@ struct sensor_data { | |||
129 | } | 133 | } |
130 | 134 | ||
131 | /* We calculate the autogain at the end of the transfer of a frame, at this | 135 | /* We calculate the autogain at the end of the transfer of a frame, at this |
132 | moment a frame with the old settings is being transmitted, and a frame is | 136 | moment a frame with the old settings is being captured and transmitted. So |
133 | being captured with the old settings. So if we adjust the autogain we must | 137 | if we adjust the gain or exposure we must ignore atleast the next frame for |
134 | ignore atleast the 2 next frames for the new settings to come into effect | 138 | the new settings to come into effect before doing any other adjustments. */ |
135 | before doing any other adjustments */ | 139 | #define AUTOGAIN_IGNORE_FRAMES 1 |
136 | #define AUTOGAIN_IGNORE_FRAMES 3 | ||
137 | 140 | ||
138 | /* V4L2 controls supported by the driver */ | 141 | /* V4L2 controls supported by the driver */ |
139 | static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); | 142 | static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); |
@@ -185,10 +188,10 @@ static const struct ctrl sd_ctrls[] = { | |||
185 | .id = V4L2_CID_EXPOSURE, | 188 | .id = V4L2_CID_EXPOSURE, |
186 | .type = V4L2_CTRL_TYPE_INTEGER, | 189 | .type = V4L2_CTRL_TYPE_INTEGER, |
187 | .name = "Exposure", | 190 | .name = "Exposure", |
188 | #define EXPOSURE_DEF 16 /* 32 ms / 30 fps */ | 191 | #define EXPOSURE_DEF 33 /* 33 ms / 30 fps */ |
189 | #define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */ | 192 | #define EXPOSURE_KNEE 100 /* 100 ms / 10 fps */ |
190 | .minimum = 0, | 193 | .minimum = 0, |
191 | .maximum = 255, | 194 | .maximum = 511, |
192 | .step = 1, | 195 | .step = 1, |
193 | .default_value = EXPOSURE_DEF, | 196 | .default_value = EXPOSURE_DEF, |
194 | .flags = 0, | 197 | .flags = 0, |
@@ -196,7 +199,23 @@ static const struct ctrl sd_ctrls[] = { | |||
196 | .set = sd_setexposure, | 199 | .set = sd_setexposure, |
197 | .get = sd_getexposure, | 200 | .get = sd_getexposure, |
198 | }, | 201 | }, |
199 | #define AUTOGAIN_IDX 3 | 202 | #define COARSE_EXPOSURE_IDX 3 |
203 | { | ||
204 | { | ||
205 | .id = V4L2_CID_EXPOSURE, | ||
206 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
207 | .name = "Exposure", | ||
208 | #define COARSE_EXPOSURE_DEF 2 /* 30 fps */ | ||
209 | .minimum = 2, | ||
210 | .maximum = 15, | ||
211 | .step = 1, | ||
212 | .default_value = COARSE_EXPOSURE_DEF, | ||
213 | .flags = 0, | ||
214 | }, | ||
215 | .set = sd_setexposure, | ||
216 | .get = sd_getexposure, | ||
217 | }, | ||
218 | #define AUTOGAIN_IDX 4 | ||
200 | { | 219 | { |
201 | { | 220 | { |
202 | .id = V4L2_CID_AUTOGAIN, | 221 | .id = V4L2_CID_AUTOGAIN, |
@@ -212,7 +231,7 @@ static const struct ctrl sd_ctrls[] = { | |||
212 | .set = sd_setautogain, | 231 | .set = sd_setautogain, |
213 | .get = sd_getautogain, | 232 | .get = sd_getautogain, |
214 | }, | 233 | }, |
215 | #define FREQ_IDX 4 | 234 | #define FREQ_IDX 5 |
216 | { | 235 | { |
217 | { | 236 | { |
218 | .id = V4L2_CID_POWER_LINE_FREQUENCY, | 237 | .id = V4L2_CID_POWER_LINE_FREQUENCY, |
@@ -507,10 +526,10 @@ SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_SIF, NO_EXPO|NO_FREQ, | |||
507 | 0), | 526 | 0), |
508 | SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, 0, | 527 | SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, 0, |
509 | NO_EXPO|NO_FREQ, 0), | 528 | NO_EXPO|NO_FREQ, 0), |
510 | SENS(initTas5110c, NULL, tas5110_sensor_init, NULL, NULL, F_GAIN|F_SIF, | 529 | SENS(initTas5110c, NULL, tas5110_sensor_init, NULL, NULL, |
511 | NO_BRIGHTNESS|NO_FREQ, 0), | 530 | F_GAIN|F_SIF|F_COARSE_EXPO, NO_BRIGHTNESS|NO_FREQ, 0), |
512 | SENS(initTas5110d, NULL, tas5110_sensor_init, NULL, NULL, F_GAIN|F_SIF, | 531 | SENS(initTas5110d, NULL, tas5110_sensor_init, NULL, NULL, |
513 | NO_BRIGHTNESS|NO_FREQ, 0), | 532 | F_GAIN|F_SIF|F_COARSE_EXPO, NO_BRIGHTNESS|NO_FREQ, 0), |
514 | SENS(initTas5130, NULL, tas5130_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, | 533 | SENS(initTas5130, NULL, tas5130_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, |
515 | 0), | 534 | 0), |
516 | }; | 535 | }; |
@@ -721,16 +740,10 @@ static void setexposure(struct gspca_dev *gspca_dev) | |||
721 | switch (sd->sensor) { | 740 | switch (sd->sensor) { |
722 | case SENSOR_TAS5110C: | 741 | case SENSOR_TAS5110C: |
723 | case SENSOR_TAS5110D: { | 742 | case SENSOR_TAS5110D: { |
724 | __u8 reg; | ||
725 | |||
726 | /* register 19's high nibble contains the sn9c10x clock divider | 743 | /* register 19's high nibble contains the sn9c10x clock divider |
727 | The high nibble configures the no fps according to the | 744 | The high nibble configures the no fps according to the |
728 | formula: 60 / high_nibble. With a maximum of 30 fps */ | 745 | formula: 60 / high_nibble. With a maximum of 30 fps */ |
729 | reg = 120 * sd->exposure / 1000; | 746 | __u8 reg = sd->exposure; |
730 | if (reg < 2) | ||
731 | reg = 2; | ||
732 | else if (reg > 15) | ||
733 | reg = 15; | ||
734 | reg = (reg << 4) | 0x0b; | 747 | reg = (reg << 4) | 0x0b; |
735 | reg_w(gspca_dev, 0x19, ®, 1); | 748 | reg_w(gspca_dev, 0x19, ®, 1); |
736 | break; | 749 | break; |
@@ -766,7 +779,7 @@ static void setexposure(struct gspca_dev *gspca_dev) | |||
766 | } else | 779 | } else |
767 | reg10_max = 0x41; | 780 | reg10_max = 0x41; |
768 | 781 | ||
769 | reg11 = (60 * sd->exposure + 999) / 1000; | 782 | reg11 = (30 * sd->exposure + 999) / 1000; |
770 | if (reg11 < 1) | 783 | if (reg11 < 1) |
771 | reg11 = 1; | 784 | reg11 = 1; |
772 | else if (reg11 > 16) | 785 | else if (reg11 > 16) |
@@ -778,8 +791,8 @@ static void setexposure(struct gspca_dev *gspca_dev) | |||
778 | reg11 = 3; | 791 | reg11 = 3; |
779 | 792 | ||
780 | /* frame exposure time in ms = 1000 * reg11 / 30 -> | 793 | /* frame exposure time in ms = 1000 * reg11 / 30 -> |
781 | reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */ | 794 | reg10 = sd->exposure * reg10_max / (1000 * reg11 / 30) */ |
782 | reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11); | 795 | reg10 = (sd->exposure * 30 * reg10_max) / (1000 * reg11); |
783 | 796 | ||
784 | /* Don't allow this to get below 10 when using autogain, the | 797 | /* Don't allow this to get below 10 when using autogain, the |
785 | steps become very large (relatively) when below 10 causing | 798 | steps become very large (relatively) when below 10 causing |
@@ -839,30 +852,43 @@ static void setfreq(struct gspca_dev *gspca_dev) | |||
839 | } | 852 | } |
840 | } | 853 | } |
841 | 854 | ||
855 | #include "coarse_expo_autogain.h" | ||
856 | |||
842 | static void do_autogain(struct gspca_dev *gspca_dev) | 857 | static void do_autogain(struct gspca_dev *gspca_dev) |
843 | { | 858 | { |
844 | int deadzone, desired_avg_lum; | 859 | int deadzone, desired_avg_lum, result; |
845 | struct sd *sd = (struct sd *) gspca_dev; | 860 | struct sd *sd = (struct sd *) gspca_dev; |
846 | int avg_lum = atomic_read(&sd->avg_lum); | 861 | int avg_lum = atomic_read(&sd->avg_lum); |
847 | 862 | ||
848 | if (avg_lum == -1) | 863 | if (avg_lum == -1 || !sd->autogain) |
864 | return; | ||
865 | |||
866 | if (sd->autogain_ignore_frames > 0) { | ||
867 | sd->autogain_ignore_frames--; | ||
849 | return; | 868 | return; |
869 | } | ||
850 | 870 | ||
851 | /* SIF / VGA sensors have a different autoexposure area and thus | 871 | /* SIF / VGA sensors have a different autoexposure area and thus |
852 | different avg_lum values for the same picture brightness */ | 872 | different avg_lum values for the same picture brightness */ |
853 | if (sensor_data[sd->sensor].flags & F_SIF) { | 873 | if (sensor_data[sd->sensor].flags & F_SIF) { |
854 | deadzone = 1000; | 874 | deadzone = 500; |
855 | desired_avg_lum = 7000; | 875 | /* SIF sensors tend to overexpose, so keep this small */ |
876 | desired_avg_lum = 5000; | ||
856 | } else { | 877 | } else { |
857 | deadzone = 3000; | 878 | deadzone = 1500; |
858 | desired_avg_lum = 23000; | 879 | desired_avg_lum = 23000; |
859 | } | 880 | } |
860 | 881 | ||
861 | if (sd->autogain_ignore_frames > 0) | 882 | if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) |
862 | sd->autogain_ignore_frames--; | 883 | result = gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum, |
863 | else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, | 884 | sd->brightness * desired_avg_lum / 127, |
864 | sd->brightness * desired_avg_lum / 127, | 885 | deadzone); |
865 | deadzone, GAIN_KNEE, EXPOSURE_KNEE)) { | 886 | else |
887 | result = gspca_auto_gain_n_exposure(gspca_dev, avg_lum, | ||
888 | sd->brightness * desired_avg_lum / 127, | ||
889 | deadzone, GAIN_KNEE, EXPOSURE_KNEE); | ||
890 | |||
891 | if (result) { | ||
866 | PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d", | 892 | PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d", |
867 | (int)sd->gain, (int)sd->exposure); | 893 | (int)sd->gain, (int)sd->exposure); |
868 | sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES; | 894 | sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES; |
@@ -897,7 +923,13 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
897 | 923 | ||
898 | sd->brightness = BRIGHTNESS_DEF; | 924 | sd->brightness = BRIGHTNESS_DEF; |
899 | sd->gain = GAIN_DEF; | 925 | sd->gain = GAIN_DEF; |
900 | sd->exposure = EXPOSURE_DEF; | 926 | if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) { |
927 | sd->exposure = COARSE_EXPOSURE_DEF; | ||
928 | gspca_dev->ctrl_dis |= (1 << EXPOSURE_IDX); | ||
929 | } else { | ||
930 | sd->exposure = EXPOSURE_DEF; | ||
931 | gspca_dev->ctrl_dis |= (1 << COARSE_EXPOSURE_IDX); | ||
932 | } | ||
901 | if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX)) | 933 | if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX)) |
902 | sd->autogain = 0; /* Disable do_autogain callback */ | 934 | sd->autogain = 0; /* Disable do_autogain callback */ |
903 | else | 935 | else |
@@ -1001,6 +1033,8 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
1001 | 1033 | ||
1002 | sd->frames_to_drop = 0; | 1034 | sd->frames_to_drop = 0; |
1003 | sd->autogain_ignore_frames = 0; | 1035 | sd->autogain_ignore_frames = 0; |
1036 | sd->exp_too_high_cnt = 0; | ||
1037 | sd->exp_too_low_cnt = 0; | ||
1004 | atomic_set(&sd->avg_lum, -1); | 1038 | atomic_set(&sd->avg_lum, -1); |
1005 | return 0; | 1039 | return 0; |
1006 | } | 1040 | } |
@@ -1159,11 +1193,14 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) | |||
1159 | struct sd *sd = (struct sd *) gspca_dev; | 1193 | struct sd *sd = (struct sd *) gspca_dev; |
1160 | 1194 | ||
1161 | sd->autogain = val; | 1195 | sd->autogain = val; |
1196 | sd->exp_too_high_cnt = 0; | ||
1197 | sd->exp_too_low_cnt = 0; | ||
1198 | |||
1162 | /* when switching to autogain set defaults to make sure | 1199 | /* when switching to autogain set defaults to make sure |
1163 | we are on a valid point of the autogain gain / | 1200 | we are on a valid point of the autogain gain / |
1164 | exposure knee graph, and give this change time to | 1201 | exposure knee graph, and give this change time to |
1165 | take effect before doing autogain. */ | 1202 | take effect before doing autogain. */ |
1166 | if (sd->autogain) { | 1203 | if (sd->autogain && !(sensor_data[sd->sensor].flags & F_COARSE_EXPO)) { |
1167 | sd->exposure = EXPOSURE_DEF; | 1204 | sd->exposure = EXPOSURE_DEF; |
1168 | sd->gain = GAIN_DEF; | 1205 | sd->gain = GAIN_DEF; |
1169 | if (gspca_dev->streaming) { | 1206 | if (gspca_dev->streaming) { |