diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2012-05-06 08:28:29 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-05-14 08:36:34 -0400 |
commit | 63069da1c8ef0abcdb74b0ea1c461d23fb9181d9 (patch) | |
tree | ecf1cf5509b31c0e5df3aaae8107dca1d506518d | |
parent | c06ba2804a50076cc0c5a4d65466a37b8eaa4455 (diff) |
[media] gcpca_sn9c20x: Convert to the control framework
HdG: Small fix: don't register some controls for sensors which don't
have an implementation for them.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/video/gspca/sn9c20x.c | 495 |
1 files changed, 212 insertions, 283 deletions
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index 5285a519c1f3..f35f1a0d1caf 100644 --- a/drivers/media/video/gspca/sn9c20x.c +++ b/drivers/media/video/gspca/sn9c20x.c | |||
@@ -66,28 +66,32 @@ MODULE_LICENSE("GPL"); | |||
66 | #define LED_REVERSE 0x2 /* some cameras unset gpio to turn on leds */ | 66 | #define LED_REVERSE 0x2 /* some cameras unset gpio to turn on leds */ |
67 | #define FLIP_DETECT 0x4 | 67 | #define FLIP_DETECT 0x4 |
68 | 68 | ||
69 | enum e_ctrl { | ||
70 | BRIGHTNESS, | ||
71 | CONTRAST, | ||
72 | SATURATION, | ||
73 | HUE, | ||
74 | GAMMA, | ||
75 | BLUE, | ||
76 | RED, | ||
77 | VFLIP, | ||
78 | HFLIP, | ||
79 | EXPOSURE, | ||
80 | GAIN, | ||
81 | AUTOGAIN, | ||
82 | QUALITY, | ||
83 | NCTRLS /* number of controls */ | ||
84 | }; | ||
85 | |||
86 | /* specific webcam descriptor */ | 69 | /* specific webcam descriptor */ |
87 | struct sd { | 70 | struct sd { |
88 | struct gspca_dev gspca_dev; | 71 | struct gspca_dev gspca_dev; |
89 | 72 | ||
90 | struct gspca_ctrl ctrls[NCTRLS]; | 73 | struct v4l2_ctrl_handler ctrl_handler; |
74 | struct { /* color control cluster */ | ||
75 | struct v4l2_ctrl *brightness; | ||
76 | struct v4l2_ctrl *contrast; | ||
77 | struct v4l2_ctrl *saturation; | ||
78 | struct v4l2_ctrl *hue; | ||
79 | }; | ||
80 | struct { /* blue/red balance control cluster */ | ||
81 | struct v4l2_ctrl *blue; | ||
82 | struct v4l2_ctrl *red; | ||
83 | }; | ||
84 | struct { /* h/vflip control cluster */ | ||
85 | struct v4l2_ctrl *hflip; | ||
86 | struct v4l2_ctrl *vflip; | ||
87 | }; | ||
88 | struct v4l2_ctrl *gamma; | ||
89 | struct { /* autogain and exposure or gain control cluster */ | ||
90 | struct v4l2_ctrl *autogain; | ||
91 | struct v4l2_ctrl *exposure; | ||
92 | struct v4l2_ctrl *gain; | ||
93 | }; | ||
94 | struct v4l2_ctrl *jpegqual; | ||
91 | 95 | ||
92 | struct work_struct work; | 96 | struct work_struct work; |
93 | struct workqueue_struct *work_thread; | 97 | struct workqueue_struct *work_thread; |
@@ -167,175 +171,6 @@ static const struct dmi_system_id flip_dmi_table[] = { | |||
167 | {} | 171 | {} |
168 | }; | 172 | }; |
169 | 173 | ||
170 | static void set_cmatrix(struct gspca_dev *gspca_dev); | ||
171 | static void set_gamma(struct gspca_dev *gspca_dev); | ||
172 | static void set_redblue(struct gspca_dev *gspca_dev); | ||
173 | static void set_hvflip(struct gspca_dev *gspca_dev); | ||
174 | static void set_exposure(struct gspca_dev *gspca_dev); | ||
175 | static void set_gain(struct gspca_dev *gspca_dev); | ||
176 | static void set_quality(struct gspca_dev *gspca_dev); | ||
177 | |||
178 | static const struct ctrl sd_ctrls[NCTRLS] = { | ||
179 | [BRIGHTNESS] = { | ||
180 | { | ||
181 | .id = V4L2_CID_BRIGHTNESS, | ||
182 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
183 | .name = "Brightness", | ||
184 | .minimum = 0, | ||
185 | .maximum = 0xff, | ||
186 | .step = 1, | ||
187 | .default_value = 0x7f | ||
188 | }, | ||
189 | .set_control = set_cmatrix | ||
190 | }, | ||
191 | [CONTRAST] = { | ||
192 | { | ||
193 | .id = V4L2_CID_CONTRAST, | ||
194 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
195 | .name = "Contrast", | ||
196 | .minimum = 0, | ||
197 | .maximum = 0xff, | ||
198 | .step = 1, | ||
199 | .default_value = 0x7f | ||
200 | }, | ||
201 | .set_control = set_cmatrix | ||
202 | }, | ||
203 | [SATURATION] = { | ||
204 | { | ||
205 | .id = V4L2_CID_SATURATION, | ||
206 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
207 | .name = "Saturation", | ||
208 | .minimum = 0, | ||
209 | .maximum = 0xff, | ||
210 | .step = 1, | ||
211 | .default_value = 0x7f | ||
212 | }, | ||
213 | .set_control = set_cmatrix | ||
214 | }, | ||
215 | [HUE] = { | ||
216 | { | ||
217 | .id = V4L2_CID_HUE, | ||
218 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
219 | .name = "Hue", | ||
220 | .minimum = -180, | ||
221 | .maximum = 180, | ||
222 | .step = 1, | ||
223 | .default_value = 0 | ||
224 | }, | ||
225 | .set_control = set_cmatrix | ||
226 | }, | ||
227 | [GAMMA] = { | ||
228 | { | ||
229 | .id = V4L2_CID_GAMMA, | ||
230 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
231 | .name = "Gamma", | ||
232 | .minimum = 0, | ||
233 | .maximum = 0xff, | ||
234 | .step = 1, | ||
235 | .default_value = 0x10 | ||
236 | }, | ||
237 | .set_control = set_gamma | ||
238 | }, | ||
239 | [BLUE] = { | ||
240 | { | ||
241 | .id = V4L2_CID_BLUE_BALANCE, | ||
242 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
243 | .name = "Blue Balance", | ||
244 | .minimum = 0, | ||
245 | .maximum = 0x7f, | ||
246 | .step = 1, | ||
247 | .default_value = 0x28 | ||
248 | }, | ||
249 | .set_control = set_redblue | ||
250 | }, | ||
251 | [RED] = { | ||
252 | { | ||
253 | .id = V4L2_CID_RED_BALANCE, | ||
254 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
255 | .name = "Red Balance", | ||
256 | .minimum = 0, | ||
257 | .maximum = 0x7f, | ||
258 | .step = 1, | ||
259 | .default_value = 0x28 | ||
260 | }, | ||
261 | .set_control = set_redblue | ||
262 | }, | ||
263 | [HFLIP] = { | ||
264 | { | ||
265 | .id = V4L2_CID_HFLIP, | ||
266 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
267 | .name = "Horizontal Flip", | ||
268 | .minimum = 0, | ||
269 | .maximum = 1, | ||
270 | .step = 1, | ||
271 | .default_value = 0, | ||
272 | }, | ||
273 | .set_control = set_hvflip | ||
274 | }, | ||
275 | [VFLIP] = { | ||
276 | { | ||
277 | .id = V4L2_CID_VFLIP, | ||
278 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
279 | .name = "Vertical Flip", | ||
280 | .minimum = 0, | ||
281 | .maximum = 1, | ||
282 | .step = 1, | ||
283 | .default_value = 0, | ||
284 | }, | ||
285 | .set_control = set_hvflip | ||
286 | }, | ||
287 | [EXPOSURE] = { | ||
288 | { | ||
289 | .id = V4L2_CID_EXPOSURE, | ||
290 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
291 | .name = "Exposure", | ||
292 | .minimum = 0, | ||
293 | .maximum = 0x1780, | ||
294 | .step = 1, | ||
295 | .default_value = 0x33, | ||
296 | }, | ||
297 | .set_control = set_exposure | ||
298 | }, | ||
299 | [GAIN] = { | ||
300 | { | ||
301 | .id = V4L2_CID_GAIN, | ||
302 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
303 | .name = "Gain", | ||
304 | .minimum = 0, | ||
305 | .maximum = 28, | ||
306 | .step = 1, | ||
307 | .default_value = 0, | ||
308 | }, | ||
309 | .set_control = set_gain | ||
310 | }, | ||
311 | [AUTOGAIN] = { | ||
312 | { | ||
313 | .id = V4L2_CID_AUTOGAIN, | ||
314 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
315 | .name = "Auto Exposure", | ||
316 | .minimum = 0, | ||
317 | .maximum = 1, | ||
318 | .step = 1, | ||
319 | .default_value = 1, | ||
320 | }, | ||
321 | }, | ||
322 | [QUALITY] = { | ||
323 | { | ||
324 | .id = V4L2_CID_JPEG_COMPRESSION_QUALITY, | ||
325 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
326 | .name = "Compression Quality", | ||
327 | #define QUALITY_MIN 50 | ||
328 | #define QUALITY_MAX 90 | ||
329 | #define QUALITY_DEF 80 | ||
330 | .minimum = QUALITY_MIN, | ||
331 | .maximum = QUALITY_MAX, | ||
332 | .step = 1, | ||
333 | .default_value = QUALITY_DEF, | ||
334 | }, | ||
335 | .set_control = set_quality | ||
336 | }, | ||
337 | }; | ||
338 | |||
339 | static const struct v4l2_pix_format vga_mode[] = { | 174 | static const struct v4l2_pix_format vga_mode[] = { |
340 | {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, | 175 | {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, |
341 | .bytesperline = 160, | 176 | .bytesperline = 160, |
@@ -1296,8 +1131,6 @@ static void ov9655_init_sensor(struct gspca_dev *gspca_dev) | |||
1296 | if (gspca_dev->usb_err < 0) | 1131 | if (gspca_dev->usb_err < 0) |
1297 | pr_err("OV9655 sensor initialization failed\n"); | 1132 | pr_err("OV9655 sensor initialization failed\n"); |
1298 | 1133 | ||
1299 | /* disable hflip and vflip */ | ||
1300 | gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP); | ||
1301 | sd->hstart = 1; | 1134 | sd->hstart = 1; |
1302 | sd->vstart = 2; | 1135 | sd->vstart = 2; |
1303 | } | 1136 | } |
@@ -1312,9 +1145,6 @@ static void soi968_init_sensor(struct gspca_dev *gspca_dev) | |||
1312 | if (gspca_dev->usb_err < 0) | 1145 | if (gspca_dev->usb_err < 0) |
1313 | pr_err("SOI968 sensor initialization failed\n"); | 1146 | pr_err("SOI968 sensor initialization failed\n"); |
1314 | 1147 | ||
1315 | /* disable hflip and vflip */ | ||
1316 | gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP) | ||
1317 | | (1 << EXPOSURE); | ||
1318 | sd->hstart = 60; | 1148 | sd->hstart = 60; |
1319 | sd->vstart = 11; | 1149 | sd->vstart = 11; |
1320 | } | 1150 | } |
@@ -1342,8 +1172,6 @@ static void ov7670_init_sensor(struct gspca_dev *gspca_dev) | |||
1342 | if (gspca_dev->usb_err < 0) | 1172 | if (gspca_dev->usb_err < 0) |
1343 | pr_err("OV7670 sensor initialization failed\n"); | 1173 | pr_err("OV7670 sensor initialization failed\n"); |
1344 | 1174 | ||
1345 | /* disable hflip and vflip */ | ||
1346 | gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP); | ||
1347 | sd->hstart = 0; | 1175 | sd->hstart = 0; |
1348 | sd->vstart = 1; | 1176 | sd->vstart = 1; |
1349 | } | 1177 | } |
@@ -1380,9 +1208,6 @@ static void mt9v_init_sensor(struct gspca_dev *gspca_dev) | |||
1380 | pr_err("MT9V111 sensor initialization failed\n"); | 1208 | pr_err("MT9V111 sensor initialization failed\n"); |
1381 | return; | 1209 | return; |
1382 | } | 1210 | } |
1383 | gspca_dev->ctrl_dis = (1 << EXPOSURE) | ||
1384 | | (1 << AUTOGAIN) | ||
1385 | | (1 << GAIN); | ||
1386 | sd->hstart = 2; | 1211 | sd->hstart = 2; |
1387 | sd->vstart = 2; | 1212 | sd->vstart = 2; |
1388 | sd->sensor = SENSOR_MT9V111; | 1213 | sd->sensor = SENSOR_MT9V111; |
@@ -1424,8 +1249,6 @@ static void mt9m112_init_sensor(struct gspca_dev *gspca_dev) | |||
1424 | if (gspca_dev->usb_err < 0) | 1249 | if (gspca_dev->usb_err < 0) |
1425 | pr_err("MT9M112 sensor initialization failed\n"); | 1250 | pr_err("MT9M112 sensor initialization failed\n"); |
1426 | 1251 | ||
1427 | gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN) | ||
1428 | | (1 << GAIN); | ||
1429 | sd->hstart = 0; | 1252 | sd->hstart = 0; |
1430 | sd->vstart = 2; | 1253 | sd->vstart = 2; |
1431 | } | 1254 | } |
@@ -1438,8 +1261,6 @@ static void mt9m111_init_sensor(struct gspca_dev *gspca_dev) | |||
1438 | if (gspca_dev->usb_err < 0) | 1261 | if (gspca_dev->usb_err < 0) |
1439 | pr_err("MT9M111 sensor initialization failed\n"); | 1262 | pr_err("MT9M111 sensor initialization failed\n"); |
1440 | 1263 | ||
1441 | gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN) | ||
1442 | | (1 << GAIN); | ||
1443 | sd->hstart = 0; | 1264 | sd->hstart = 0; |
1444 | sd->vstart = 2; | 1265 | sd->vstart = 2; |
1445 | } | 1266 | } |
@@ -1472,8 +1293,6 @@ static void mt9m001_init_sensor(struct gspca_dev *gspca_dev) | |||
1472 | if (gspca_dev->usb_err < 0) | 1293 | if (gspca_dev->usb_err < 0) |
1473 | pr_err("MT9M001 sensor initialization failed\n"); | 1294 | pr_err("MT9M001 sensor initialization failed\n"); |
1474 | 1295 | ||
1475 | /* disable hflip and vflip */ | ||
1476 | gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP); | ||
1477 | sd->hstart = 1; | 1296 | sd->hstart = 1; |
1478 | sd->vstart = 1; | 1297 | sd->vstart = 1; |
1479 | } | 1298 | } |
@@ -1490,20 +1309,18 @@ static void hv7131r_init_sensor(struct gspca_dev *gspca_dev) | |||
1490 | sd->vstart = 1; | 1309 | sd->vstart = 1; |
1491 | } | 1310 | } |
1492 | 1311 | ||
1493 | static void set_cmatrix(struct gspca_dev *gspca_dev) | 1312 | static void set_cmatrix(struct gspca_dev *gspca_dev, |
1313 | s32 brightness, s32 contrast, s32 satur, s32 hue) | ||
1494 | { | 1314 | { |
1495 | struct sd *sd = (struct sd *) gspca_dev; | 1315 | s32 hue_coord, hue_index = 180 + hue; |
1496 | int satur; | ||
1497 | s32 hue_coord, hue_index = 180 + sd->ctrls[HUE].val; | ||
1498 | u8 cmatrix[21]; | 1316 | u8 cmatrix[21]; |
1499 | 1317 | ||
1500 | memset(cmatrix, 0, sizeof cmatrix); | 1318 | memset(cmatrix, 0, sizeof cmatrix); |
1501 | cmatrix[2] = (sd->ctrls[CONTRAST].val * 0x25 / 0x100) + 0x26; | 1319 | cmatrix[2] = (contrast * 0x25 / 0x100) + 0x26; |
1502 | cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25; | 1320 | cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25; |
1503 | cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25; | 1321 | cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25; |
1504 | cmatrix[18] = sd->ctrls[BRIGHTNESS].val - 0x80; | 1322 | cmatrix[18] = brightness - 0x80; |
1505 | 1323 | ||
1506 | satur = sd->ctrls[SATURATION].val; | ||
1507 | hue_coord = (hsv_red_x[hue_index] * satur) >> 8; | 1324 | hue_coord = (hsv_red_x[hue_index] * satur) >> 8; |
1508 | cmatrix[6] = hue_coord; | 1325 | cmatrix[6] = hue_coord; |
1509 | cmatrix[7] = (hue_coord >> 8) & 0x0f; | 1326 | cmatrix[7] = (hue_coord >> 8) & 0x0f; |
@@ -1531,11 +1348,10 @@ static void set_cmatrix(struct gspca_dev *gspca_dev) | |||
1531 | reg_w(gspca_dev, 0x10e1, cmatrix, 21); | 1348 | reg_w(gspca_dev, 0x10e1, cmatrix, 21); |
1532 | } | 1349 | } |
1533 | 1350 | ||
1534 | static void set_gamma(struct gspca_dev *gspca_dev) | 1351 | static void set_gamma(struct gspca_dev *gspca_dev, s32 val) |
1535 | { | 1352 | { |
1536 | struct sd *sd = (struct sd *) gspca_dev; | ||
1537 | u8 gamma[17]; | 1353 | u8 gamma[17]; |
1538 | u8 gval = sd->ctrls[GAMMA].val * 0xb8 / 0x100; | 1354 | u8 gval = val * 0xb8 / 0x100; |
1539 | 1355 | ||
1540 | gamma[0] = 0x0a; | 1356 | gamma[0] = 0x0a; |
1541 | gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8); | 1357 | gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8); |
@@ -1558,26 +1374,21 @@ static void set_gamma(struct gspca_dev *gspca_dev) | |||
1558 | reg_w(gspca_dev, 0x1190, gamma, 17); | 1374 | reg_w(gspca_dev, 0x1190, gamma, 17); |
1559 | } | 1375 | } |
1560 | 1376 | ||
1561 | static void set_redblue(struct gspca_dev *gspca_dev) | 1377 | static void set_redblue(struct gspca_dev *gspca_dev, s32 blue, s32 red) |
1562 | { | 1378 | { |
1563 | struct sd *sd = (struct sd *) gspca_dev; | 1379 | reg_w1(gspca_dev, 0x118c, red); |
1564 | 1380 | reg_w1(gspca_dev, 0x118f, blue); | |
1565 | reg_w1(gspca_dev, 0x118c, sd->ctrls[RED].val); | ||
1566 | reg_w1(gspca_dev, 0x118f, sd->ctrls[BLUE].val); | ||
1567 | } | 1381 | } |
1568 | 1382 | ||
1569 | static void set_hvflip(struct gspca_dev *gspca_dev) | 1383 | static void set_hvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip) |
1570 | { | 1384 | { |
1571 | u8 value, tslb, hflip, vflip; | 1385 | u8 value, tslb; |
1572 | u16 value2; | 1386 | u16 value2; |
1573 | struct sd *sd = (struct sd *) gspca_dev; | 1387 | struct sd *sd = (struct sd *) gspca_dev; |
1574 | 1388 | ||
1575 | if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) { | 1389 | if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) { |
1576 | hflip = !sd->ctrls[HFLIP].val; | 1390 | hflip = !hflip; |
1577 | vflip = !sd->ctrls[VFLIP].val; | 1391 | vflip = !vflip; |
1578 | } else { | ||
1579 | hflip = sd->ctrls[HFLIP].val; | ||
1580 | vflip = sd->ctrls[VFLIP].val; | ||
1581 | } | 1392 | } |
1582 | 1393 | ||
1583 | switch (sd->sensor) { | 1394 | switch (sd->sensor) { |
@@ -1640,17 +1451,16 @@ static void set_hvflip(struct gspca_dev *gspca_dev) | |||
1640 | } | 1451 | } |
1641 | } | 1452 | } |
1642 | 1453 | ||
1643 | static void set_exposure(struct gspca_dev *gspca_dev) | 1454 | static void set_exposure(struct gspca_dev *gspca_dev, s32 expo) |
1644 | { | 1455 | { |
1645 | struct sd *sd = (struct sd *) gspca_dev; | 1456 | struct sd *sd = (struct sd *) gspca_dev; |
1646 | u8 exp[8] = {sd->i2c_intf, sd->i2c_addr, | 1457 | u8 exp[8] = {sd->i2c_intf, sd->i2c_addr, |
1647 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; | 1458 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; |
1648 | int expo, expo2; | 1459 | int expo2; |
1649 | 1460 | ||
1650 | if (gspca_dev->streaming) | 1461 | if (gspca_dev->streaming) |
1651 | exp[7] = 0x1e; | 1462 | exp[7] = 0x1e; |
1652 | 1463 | ||
1653 | expo = sd->ctrls[EXPOSURE].val; | ||
1654 | switch (sd->sensor) { | 1464 | switch (sd->sensor) { |
1655 | case SENSOR_OV7660: | 1465 | case SENSOR_OV7660: |
1656 | case SENSOR_OV7670: | 1466 | case SENSOR_OV7670: |
@@ -1697,17 +1507,15 @@ static void set_exposure(struct gspca_dev *gspca_dev) | |||
1697 | i2c_w(gspca_dev, exp); | 1507 | i2c_w(gspca_dev, exp); |
1698 | } | 1508 | } |
1699 | 1509 | ||
1700 | static void set_gain(struct gspca_dev *gspca_dev) | 1510 | static void set_gain(struct gspca_dev *gspca_dev, s32 g) |
1701 | { | 1511 | { |
1702 | struct sd *sd = (struct sd *) gspca_dev; | 1512 | struct sd *sd = (struct sd *) gspca_dev; |
1703 | u8 gain[8] = {sd->i2c_intf, sd->i2c_addr, | 1513 | u8 gain[8] = {sd->i2c_intf, sd->i2c_addr, |
1704 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; | 1514 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; |
1705 | int g; | ||
1706 | 1515 | ||
1707 | if (gspca_dev->streaming) | 1516 | if (gspca_dev->streaming) |
1708 | gain[7] = 0x15; /* or 1d ? */ | 1517 | gain[7] = 0x15; /* or 1d ? */ |
1709 | 1518 | ||
1710 | g = sd->ctrls[GAIN].val; | ||
1711 | switch (sd->sensor) { | 1519 | switch (sd->sensor) { |
1712 | case SENSOR_OV7660: | 1520 | case SENSOR_OV7660: |
1713 | case SENSOR_OV7670: | 1521 | case SENSOR_OV7670: |
@@ -1746,11 +1554,11 @@ static void set_gain(struct gspca_dev *gspca_dev) | |||
1746 | i2c_w(gspca_dev, gain); | 1554 | i2c_w(gspca_dev, gain); |
1747 | } | 1555 | } |
1748 | 1556 | ||
1749 | static void set_quality(struct gspca_dev *gspca_dev) | 1557 | static void set_quality(struct gspca_dev *gspca_dev, s32 val) |
1750 | { | 1558 | { |
1751 | struct sd *sd = (struct sd *) gspca_dev; | 1559 | struct sd *sd = (struct sd *) gspca_dev; |
1752 | 1560 | ||
1753 | jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val); | 1561 | jpeg_set_qual(sd->jpeg_hdr, val); |
1754 | reg_w1(gspca_dev, 0x1061, 0x01); /* stop transfer */ | 1562 | reg_w1(gspca_dev, 0x1061, 0x01); /* stop transfer */ |
1755 | reg_w1(gspca_dev, 0x10e0, sd->fmt | 0x20); /* write QTAB */ | 1563 | reg_w1(gspca_dev, 0x10e0, sd->fmt | 0x20); /* write QTAB */ |
1756 | reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64); | 1564 | reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64); |
@@ -1879,13 +1687,132 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
1879 | sd->older_step = 0; | 1687 | sd->older_step = 0; |
1880 | sd->exposure_step = 16; | 1688 | sd->exposure_step = 16; |
1881 | 1689 | ||
1882 | gspca_dev->cam.ctrls = sd->ctrls; | ||
1883 | |||
1884 | INIT_WORK(&sd->work, qual_upd); | 1690 | INIT_WORK(&sd->work, qual_upd); |
1885 | 1691 | ||
1886 | return 0; | 1692 | return 0; |
1887 | } | 1693 | } |
1888 | 1694 | ||
1695 | static int sd_s_ctrl(struct v4l2_ctrl *ctrl) | ||
1696 | { | ||
1697 | struct sd *sd = container_of(ctrl->handler, struct sd, ctrl_handler); | ||
1698 | struct gspca_dev *gspca_dev = &sd->gspca_dev; | ||
1699 | |||
1700 | gspca_dev->usb_err = 0; | ||
1701 | |||
1702 | if (!gspca_dev->streaming) | ||
1703 | return 0; | ||
1704 | |||
1705 | switch (ctrl->id) { | ||
1706 | /* color control cluster */ | ||
1707 | case V4L2_CID_BRIGHTNESS: | ||
1708 | set_cmatrix(&sd->gspca_dev, sd->brightness->val, | ||
1709 | sd->contrast->val, sd->saturation->val, sd->hue->val); | ||
1710 | break; | ||
1711 | case V4L2_CID_GAMMA: | ||
1712 | set_gamma(&sd->gspca_dev, ctrl->val); | ||
1713 | break; | ||
1714 | /* blue/red balance cluster */ | ||
1715 | case V4L2_CID_BLUE_BALANCE: | ||
1716 | set_redblue(&sd->gspca_dev, sd->blue->val, sd->red->val); | ||
1717 | break; | ||
1718 | /* h/vflip cluster */ | ||
1719 | case V4L2_CID_HFLIP: | ||
1720 | set_hvflip(&sd->gspca_dev, sd->hflip->val, sd->vflip->val); | ||
1721 | break; | ||
1722 | /* standalone exposure control */ | ||
1723 | case V4L2_CID_EXPOSURE: | ||
1724 | set_exposure(&sd->gspca_dev, ctrl->val); | ||
1725 | break; | ||
1726 | /* standalone gain control */ | ||
1727 | case V4L2_CID_GAIN: | ||
1728 | set_gain(&sd->gspca_dev, ctrl->val); | ||
1729 | break; | ||
1730 | /* autogain + exposure or gain control cluster */ | ||
1731 | case V4L2_CID_AUTOGAIN: | ||
1732 | if (sd->sensor == SENSOR_SOI968) | ||
1733 | set_gain(&sd->gspca_dev, sd->gain->val); | ||
1734 | else | ||
1735 | set_exposure(&sd->gspca_dev, sd->exposure->val); | ||
1736 | break; | ||
1737 | case V4L2_CID_JPEG_COMPRESSION_QUALITY: | ||
1738 | set_quality(&sd->gspca_dev, ctrl->val); | ||
1739 | break; | ||
1740 | } | ||
1741 | return gspca_dev->usb_err; | ||
1742 | } | ||
1743 | |||
1744 | static const struct v4l2_ctrl_ops sd_ctrl_ops = { | ||
1745 | .s_ctrl = sd_s_ctrl, | ||
1746 | }; | ||
1747 | |||
1748 | static int sd_init_controls(struct gspca_dev *gspca_dev) | ||
1749 | { | ||
1750 | struct sd *sd = (struct sd *) gspca_dev; | ||
1751 | struct v4l2_ctrl_handler *hdl = &sd->ctrl_handler; | ||
1752 | |||
1753 | gspca_dev->vdev.ctrl_handler = hdl; | ||
1754 | v4l2_ctrl_handler_init(hdl, 13); | ||
1755 | |||
1756 | sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
1757 | V4L2_CID_BRIGHTNESS, 0, 255, 1, 127); | ||
1758 | sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
1759 | V4L2_CID_CONTRAST, 0, 255, 1, 127); | ||
1760 | sd->saturation = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
1761 | V4L2_CID_SATURATION, 0, 255, 1, 127); | ||
1762 | sd->hue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
1763 | V4L2_CID_HUE, -180, 180, 1, 0); | ||
1764 | v4l2_ctrl_cluster(4, &sd->brightness); | ||
1765 | |||
1766 | sd->gamma = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
1767 | V4L2_CID_GAMMA, 0, 255, 1, 0x10); | ||
1768 | |||
1769 | sd->blue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
1770 | V4L2_CID_BLUE_BALANCE, 0, 127, 1, 0x28); | ||
1771 | sd->red = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
1772 | V4L2_CID_RED_BALANCE, 0, 127, 1, 0x28); | ||
1773 | v4l2_ctrl_cluster(2, &sd->blue); | ||
1774 | |||
1775 | if (sd->sensor != SENSOR_OV9655 && sd->sensor != SENSOR_SOI968 && | ||
1776 | sd->sensor != SENSOR_OV7670 && sd->sensor != SENSOR_MT9M001 && | ||
1777 | sd->sensor != SENSOR_MT9VPRB) { | ||
1778 | sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
1779 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
1780 | sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
1781 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
1782 | v4l2_ctrl_cluster(2, &sd->hflip); | ||
1783 | } | ||
1784 | |||
1785 | if (sd->sensor != SENSOR_SOI968 && sd->sensor != SENSOR_MT9VPRB && | ||
1786 | sd->sensor != SENSOR_MT9M112 && sd->sensor != SENSOR_MT9M111 && | ||
1787 | sd->sensor != SENSOR_MT9V111) | ||
1788 | sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
1789 | V4L2_CID_EXPOSURE, 0, 0x1780, 1, 0x33); | ||
1790 | |||
1791 | if (sd->sensor != SENSOR_MT9VPRB && sd->sensor != SENSOR_MT9M112 && | ||
1792 | sd->sensor != SENSOR_MT9M111 && sd->sensor != SENSOR_MT9V111) { | ||
1793 | sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
1794 | V4L2_CID_GAIN, 0, 28, 1, 0); | ||
1795 | sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
1796 | V4L2_CID_AUTOGAIN, 0, 1, 1, 1); | ||
1797 | if (sd->sensor == SENSOR_SOI968) | ||
1798 | /* this sensor doesn't have the exposure control and | ||
1799 | autogain is clustered with gain instead. This works | ||
1800 | because sd->exposure == NULL. */ | ||
1801 | v4l2_ctrl_auto_cluster(3, &sd->autogain, 0, false); | ||
1802 | else | ||
1803 | /* Otherwise autogain is clustered with exposure. */ | ||
1804 | v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false); | ||
1805 | } | ||
1806 | |||
1807 | sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | ||
1808 | V4L2_CID_JPEG_COMPRESSION_QUALITY, 50, 90, 1, 80); | ||
1809 | if (hdl->error) { | ||
1810 | pr_err("Could not initialize controls\n"); | ||
1811 | return hdl->error; | ||
1812 | } | ||
1813 | return 0; | ||
1814 | } | ||
1815 | |||
1889 | static int sd_init(struct gspca_dev *gspca_dev) | 1816 | static int sd_init(struct gspca_dev *gspca_dev) |
1890 | { | 1817 | { |
1891 | struct sd *sd = (struct sd *) gspca_dev; | 1818 | struct sd *sd = (struct sd *) gspca_dev; |
@@ -1978,7 +1905,6 @@ static int sd_init(struct gspca_dev *gspca_dev) | |||
1978 | pr_err("Unsupported sensor\n"); | 1905 | pr_err("Unsupported sensor\n"); |
1979 | gspca_dev->usb_err = -ENODEV; | 1906 | gspca_dev->usb_err = -ENODEV; |
1980 | } | 1907 | } |
1981 | |||
1982 | return gspca_dev->usb_err; | 1908 | return gspca_dev->usb_err; |
1983 | } | 1909 | } |
1984 | 1910 | ||
@@ -2096,7 +2022,7 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
2096 | 2022 | ||
2097 | jpeg_define(sd->jpeg_hdr, height, width, | 2023 | jpeg_define(sd->jpeg_hdr, height, width, |
2098 | 0x21); | 2024 | 0x21); |
2099 | jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val); | 2025 | jpeg_set_qual(sd->jpeg_hdr, v4l2_ctrl_g_ctrl(sd->jpegqual)); |
2100 | 2026 | ||
2101 | if (mode & MODE_RAW) | 2027 | if (mode & MODE_RAW) |
2102 | fmt = 0x2d; | 2028 | fmt = 0x2d; |
@@ -2133,12 +2059,17 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
2133 | reg_w1(gspca_dev, 0x1189, scale); | 2059 | reg_w1(gspca_dev, 0x1189, scale); |
2134 | reg_w1(gspca_dev, 0x10e0, fmt); | 2060 | reg_w1(gspca_dev, 0x10e0, fmt); |
2135 | 2061 | ||
2136 | set_cmatrix(gspca_dev); | 2062 | set_cmatrix(gspca_dev, v4l2_ctrl_g_ctrl(sd->brightness), |
2137 | set_gamma(gspca_dev); | 2063 | v4l2_ctrl_g_ctrl(sd->contrast), |
2138 | set_redblue(gspca_dev); | 2064 | v4l2_ctrl_g_ctrl(sd->saturation), |
2139 | set_gain(gspca_dev); | 2065 | v4l2_ctrl_g_ctrl(sd->hue)); |
2140 | set_exposure(gspca_dev); | 2066 | set_gamma(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma)); |
2141 | set_hvflip(gspca_dev); | 2067 | set_redblue(gspca_dev, v4l2_ctrl_g_ctrl(sd->blue), |
2068 | v4l2_ctrl_g_ctrl(sd->red)); | ||
2069 | set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain)); | ||
2070 | set_exposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure)); | ||
2071 | set_hvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip), | ||
2072 | v4l2_ctrl_g_ctrl(sd->vflip)); | ||
2142 | 2073 | ||
2143 | reg_w1(gspca_dev, 0x1007, 0x20); | 2074 | reg_w1(gspca_dev, 0x1007, 0x20); |
2144 | reg_w1(gspca_dev, 0x1061, 0x03); | 2075 | reg_w1(gspca_dev, 0x1061, 0x03); |
@@ -2177,6 +2108,9 @@ static void sd_stop0(struct gspca_dev *gspca_dev) | |||
2177 | static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum) | 2108 | static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum) |
2178 | { | 2109 | { |
2179 | struct sd *sd = (struct sd *) gspca_dev; | 2110 | struct sd *sd = (struct sd *) gspca_dev; |
2111 | s32 cur_exp = v4l2_ctrl_g_ctrl(sd->exposure); | ||
2112 | s32 max = sd->exposure->maximum - sd->exposure_step; | ||
2113 | s32 min = sd->exposure->minimum + sd->exposure_step; | ||
2180 | s16 new_exp; | 2114 | s16 new_exp; |
2181 | 2115 | ||
2182 | /* | 2116 | /* |
@@ -2185,16 +2119,15 @@ static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum) | |||
2185 | * and exposure steps | 2119 | * and exposure steps |
2186 | */ | 2120 | */ |
2187 | if (avg_lum < MIN_AVG_LUM) { | 2121 | if (avg_lum < MIN_AVG_LUM) { |
2188 | if (sd->ctrls[EXPOSURE].val > 0x1770) | 2122 | if (cur_exp > max) |
2189 | return; | 2123 | return; |
2190 | 2124 | ||
2191 | new_exp = sd->ctrls[EXPOSURE].val + sd->exposure_step; | 2125 | new_exp = cur_exp + sd->exposure_step; |
2192 | if (new_exp > 0x1770) | 2126 | if (new_exp > max) |
2193 | new_exp = 0x1770; | 2127 | new_exp = max; |
2194 | if (new_exp < 0x10) | 2128 | if (new_exp < min) |
2195 | new_exp = 0x10; | 2129 | new_exp = min; |
2196 | sd->ctrls[EXPOSURE].val = new_exp; | 2130 | v4l2_ctrl_s_ctrl(sd->exposure, new_exp); |
2197 | set_exposure(gspca_dev); | ||
2198 | 2131 | ||
2199 | sd->older_step = sd->old_step; | 2132 | sd->older_step = sd->old_step; |
2200 | sd->old_step = 1; | 2133 | sd->old_step = 1; |
@@ -2205,15 +2138,14 @@ static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum) | |||
2205 | sd->exposure_step += 2; | 2138 | sd->exposure_step += 2; |
2206 | } | 2139 | } |
2207 | if (avg_lum > MAX_AVG_LUM) { | 2140 | if (avg_lum > MAX_AVG_LUM) { |
2208 | if (sd->ctrls[EXPOSURE].val < 0x10) | 2141 | if (cur_exp < min) |
2209 | return; | 2142 | return; |
2210 | new_exp = sd->ctrls[EXPOSURE].val - sd->exposure_step; | 2143 | new_exp = cur_exp - sd->exposure_step; |
2211 | if (new_exp > 0x1700) | 2144 | if (new_exp > max) |
2212 | new_exp = 0x1770; | 2145 | new_exp = max; |
2213 | if (new_exp < 0x10) | 2146 | if (new_exp < min) |
2214 | new_exp = 0x10; | 2147 | new_exp = min; |
2215 | sd->ctrls[EXPOSURE].val = new_exp; | 2148 | v4l2_ctrl_s_ctrl(sd->exposure, new_exp); |
2216 | set_exposure(gspca_dev); | ||
2217 | sd->older_step = sd->old_step; | 2149 | sd->older_step = sd->old_step; |
2218 | sd->old_step = 0; | 2150 | sd->old_step = 0; |
2219 | 2151 | ||
@@ -2227,19 +2159,12 @@ static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum) | |||
2227 | static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum) | 2159 | static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum) |
2228 | { | 2160 | { |
2229 | struct sd *sd = (struct sd *) gspca_dev; | 2161 | struct sd *sd = (struct sd *) gspca_dev; |
2162 | s32 cur_gain = v4l2_ctrl_g_ctrl(sd->gain); | ||
2230 | 2163 | ||
2231 | if (avg_lum < MIN_AVG_LUM) { | 2164 | if (avg_lum < MIN_AVG_LUM && cur_gain < sd->gain->maximum) |
2232 | if (sd->ctrls[GAIN].val + 1 <= 28) { | 2165 | v4l2_ctrl_s_ctrl(sd->gain, cur_gain + 1); |
2233 | sd->ctrls[GAIN].val++; | 2166 | if (avg_lum > MAX_AVG_LUM && cur_gain > sd->gain->minimum) |
2234 | set_gain(gspca_dev); | 2167 | v4l2_ctrl_s_ctrl(sd->gain, cur_gain - 1); |
2235 | } | ||
2236 | } | ||
2237 | if (avg_lum > MAX_AVG_LUM) { | ||
2238 | if (sd->ctrls[GAIN].val > 0) { | ||
2239 | sd->ctrls[GAIN].val--; | ||
2240 | set_gain(gspca_dev); | ||
2241 | } | ||
2242 | } | ||
2243 | } | 2168 | } |
2244 | 2169 | ||
2245 | static void sd_dqcallback(struct gspca_dev *gspca_dev) | 2170 | static void sd_dqcallback(struct gspca_dev *gspca_dev) |
@@ -2247,7 +2172,7 @@ static void sd_dqcallback(struct gspca_dev *gspca_dev) | |||
2247 | struct sd *sd = (struct sd *) gspca_dev; | 2172 | struct sd *sd = (struct sd *) gspca_dev; |
2248 | int avg_lum; | 2173 | int avg_lum; |
2249 | 2174 | ||
2250 | if (!sd->ctrls[AUTOGAIN].val) | 2175 | if (!v4l2_ctrl_g_ctrl(sd->autogain)) |
2251 | return; | 2176 | return; |
2252 | 2177 | ||
2253 | avg_lum = atomic_read(&sd->avg_lum); | 2178 | avg_lum = atomic_read(&sd->avg_lum); |
@@ -2263,10 +2188,11 @@ static void qual_upd(struct work_struct *work) | |||
2263 | { | 2188 | { |
2264 | struct sd *sd = container_of(work, struct sd, work); | 2189 | struct sd *sd = container_of(work, struct sd, work); |
2265 | struct gspca_dev *gspca_dev = &sd->gspca_dev; | 2190 | struct gspca_dev *gspca_dev = &sd->gspca_dev; |
2191 | s32 qual = v4l2_ctrl_g_ctrl(sd->jpegqual); | ||
2266 | 2192 | ||
2267 | mutex_lock(&gspca_dev->usb_lock); | 2193 | mutex_lock(&gspca_dev->usb_lock); |
2268 | PDEBUG(D_STREAM, "qual_upd %d%%", sd->ctrls[QUALITY].val); | 2194 | PDEBUG(D_STREAM, "qual_upd %d%%", qual); |
2269 | set_quality(gspca_dev); | 2195 | set_quality(gspca_dev, qual); |
2270 | mutex_unlock(&gspca_dev->usb_lock); | 2196 | mutex_unlock(&gspca_dev->usb_lock); |
2271 | } | 2197 | } |
2272 | 2198 | ||
@@ -2315,14 +2241,18 @@ static void transfer_check(struct gspca_dev *gspca_dev, | |||
2315 | if (new_qual != 0) { | 2241 | if (new_qual != 0) { |
2316 | sd->nchg += new_qual; | 2242 | sd->nchg += new_qual; |
2317 | if (sd->nchg < -6 || sd->nchg >= 12) { | 2243 | if (sd->nchg < -6 || sd->nchg >= 12) { |
2244 | /* Note: we are in interrupt context, so we can't | ||
2245 | use v4l2_ctrl_g/s_ctrl here. Access the value | ||
2246 | directly instead. */ | ||
2247 | s32 curqual = sd->jpegqual->cur.val; | ||
2318 | sd->nchg = 0; | 2248 | sd->nchg = 0; |
2319 | new_qual += sd->ctrls[QUALITY].val; | 2249 | new_qual += curqual; |
2320 | if (new_qual < QUALITY_MIN) | 2250 | if (new_qual < sd->jpegqual->minimum) |
2321 | new_qual = QUALITY_MIN; | 2251 | new_qual = sd->jpegqual->minimum; |
2322 | else if (new_qual > QUALITY_MAX) | 2252 | else if (new_qual > sd->jpegqual->maximum) |
2323 | new_qual = QUALITY_MAX; | 2253 | new_qual = sd->jpegqual->maximum; |
2324 | if (new_qual != sd->ctrls[QUALITY].val) { | 2254 | if (new_qual != curqual) { |
2325 | sd->ctrls[QUALITY].val = new_qual; | 2255 | sd->jpegqual->cur.val = new_qual; |
2326 | queue_work(sd->work_thread, &sd->work); | 2256 | queue_work(sd->work_thread, &sd->work); |
2327 | } | 2257 | } |
2328 | } | 2258 | } |
@@ -2402,10 +2332,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
2402 | /* sub-driver description */ | 2332 | /* sub-driver description */ |
2403 | static const struct sd_desc sd_desc = { | 2333 | static const struct sd_desc sd_desc = { |
2404 | .name = KBUILD_MODNAME, | 2334 | .name = KBUILD_MODNAME, |
2405 | .ctrls = sd_ctrls, | ||
2406 | .nctrls = ARRAY_SIZE(sd_ctrls), | ||
2407 | .config = sd_config, | 2335 | .config = sd_config, |
2408 | .init = sd_init, | 2336 | .init = sd_init, |
2337 | .init_controls = sd_init_controls, | ||
2409 | .isoc_init = sd_isoc_init, | 2338 | .isoc_init = sd_isoc_init, |
2410 | .start = sd_start, | 2339 | .start = sd_start, |
2411 | .stopN = sd_stopN, | 2340 | .stopN = sd_stopN, |