0001
0002
0003
0004
0005
0006
0007 #include "gspca.h"
0008
0009
0010
0011
0012
0013
0014 int gspca_expo_autogain(
0015 struct gspca_dev *gspca_dev,
0016 int avg_lum,
0017 int desired_avg_lum,
0018 int deadzone,
0019 int gain_knee,
0020 int exposure_knee)
0021 {
0022 s32 gain, orig_gain, exposure, orig_exposure;
0023 int i, steps, retval = 0;
0024
0025 if (v4l2_ctrl_g_ctrl(gspca_dev->autogain) == 0)
0026 return 0;
0027
0028 orig_gain = gain = v4l2_ctrl_g_ctrl(gspca_dev->gain);
0029 orig_exposure = exposure = v4l2_ctrl_g_ctrl(gspca_dev->exposure);
0030
0031
0032
0033 steps = abs(desired_avg_lum - avg_lum) / deadzone;
0034
0035 gspca_dbg(gspca_dev, D_FRAM, "autogain: lum: %d, desired: %d, steps: %d\n",
0036 avg_lum, desired_avg_lum, steps);
0037
0038 for (i = 0; i < steps; i++) {
0039 if (avg_lum > desired_avg_lum) {
0040 if (gain > gain_knee)
0041 gain--;
0042 else if (exposure > exposure_knee)
0043 exposure--;
0044 else if (gain > gspca_dev->gain->default_value)
0045 gain--;
0046 else if (exposure > gspca_dev->exposure->minimum)
0047 exposure--;
0048 else if (gain > gspca_dev->gain->minimum)
0049 gain--;
0050 else
0051 break;
0052 } else {
0053 if (gain < gspca_dev->gain->default_value)
0054 gain++;
0055 else if (exposure < exposure_knee)
0056 exposure++;
0057 else if (gain < gain_knee)
0058 gain++;
0059 else if (exposure < gspca_dev->exposure->maximum)
0060 exposure++;
0061 else if (gain < gspca_dev->gain->maximum)
0062 gain++;
0063 else
0064 break;
0065 }
0066 }
0067
0068 if (gain != orig_gain) {
0069 v4l2_ctrl_s_ctrl(gspca_dev->gain, gain);
0070 retval = 1;
0071 }
0072 if (exposure != orig_exposure) {
0073 v4l2_ctrl_s_ctrl(gspca_dev->exposure, exposure);
0074 retval = 1;
0075 }
0076
0077 if (retval)
0078 gspca_dbg(gspca_dev, D_FRAM, "autogain: changed gain: %d, expo: %d\n",
0079 gain, exposure);
0080 return retval;
0081 }
0082 EXPORT_SYMBOL(gspca_expo_autogain);
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096 int gspca_coarse_grained_expo_autogain(
0097 struct gspca_dev *gspca_dev,
0098 int avg_lum,
0099 int desired_avg_lum,
0100 int deadzone)
0101 {
0102 s32 gain_low, gain_high, gain, orig_gain, exposure, orig_exposure;
0103 int steps, retval = 0;
0104
0105 if (v4l2_ctrl_g_ctrl(gspca_dev->autogain) == 0)
0106 return 0;
0107
0108 orig_gain = gain = v4l2_ctrl_g_ctrl(gspca_dev->gain);
0109 orig_exposure = exposure = v4l2_ctrl_g_ctrl(gspca_dev->exposure);
0110
0111 gain_low = (s32)(gspca_dev->gain->maximum - gspca_dev->gain->minimum) /
0112 5 * 2 + gspca_dev->gain->minimum;
0113 gain_high = (s32)(gspca_dev->gain->maximum - gspca_dev->gain->minimum) /
0114 5 * 4 + gspca_dev->gain->minimum;
0115
0116
0117
0118 steps = (desired_avg_lum - avg_lum) / deadzone;
0119
0120 gspca_dbg(gspca_dev, D_FRAM, "autogain: lum: %d, desired: %d, steps: %d\n",
0121 avg_lum, desired_avg_lum, steps);
0122
0123 if ((gain + steps) > gain_high &&
0124 exposure < gspca_dev->exposure->maximum) {
0125 gain = gain_high;
0126 gspca_dev->exp_too_low_cnt++;
0127 gspca_dev->exp_too_high_cnt = 0;
0128 } else if ((gain + steps) < gain_low &&
0129 exposure > gspca_dev->exposure->minimum) {
0130 gain = gain_low;
0131 gspca_dev->exp_too_high_cnt++;
0132 gspca_dev->exp_too_low_cnt = 0;
0133 } else {
0134 gain += steps;
0135 if (gain > gspca_dev->gain->maximum)
0136 gain = gspca_dev->gain->maximum;
0137 else if (gain < gspca_dev->gain->minimum)
0138 gain = gspca_dev->gain->minimum;
0139 gspca_dev->exp_too_high_cnt = 0;
0140 gspca_dev->exp_too_low_cnt = 0;
0141 }
0142
0143 if (gspca_dev->exp_too_high_cnt > 3) {
0144 exposure--;
0145 gspca_dev->exp_too_high_cnt = 0;
0146 } else if (gspca_dev->exp_too_low_cnt > 3) {
0147 exposure++;
0148 gspca_dev->exp_too_low_cnt = 0;
0149 }
0150
0151 if (gain != orig_gain) {
0152 v4l2_ctrl_s_ctrl(gspca_dev->gain, gain);
0153 retval = 1;
0154 }
0155 if (exposure != orig_exposure) {
0156 v4l2_ctrl_s_ctrl(gspca_dev->exposure, exposure);
0157 retval = 1;
0158 }
0159
0160 if (retval)
0161 gspca_dbg(gspca_dev, D_FRAM, "autogain: changed gain: %d, expo: %d\n",
0162 gain, exposure);
0163 return retval;
0164 }
0165 EXPORT_SYMBOL(gspca_coarse_grained_expo_autogain);