aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@skynet.be>2008-12-06 15:43:40 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-12-30 06:38:34 -0500
commit2bdd29cf3d4d32e4371fbd6b27ea171f2c1f0836 (patch)
tree58e88b1a72db231f1a076f6f44e81e674ec33c5a
parent0fbd8ee6de6ac3d0b93c96da848c5bc3ccc1dc83 (diff)
V4L/DVB (9810): uvcvideo: Add a device quirk to prune bogus controls.
Bogus controls currently include processing unit auto controls for which no corresponding manual control is available. Such auto controls make little sense if any, and are known to crash at least the SiGma Micro webcam. Signed-off-by: Laurent Pinchart <laurent.pinchart@skynet.be> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c57
-rw-r--r--drivers/media/video/uvc/uvc_driver.c3
-rw-r--r--drivers/media/video/uvc/uvcvideo.h1
3 files changed, 58 insertions, 3 deletions
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index f16aafe9cf14..77b92e67953d 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -543,11 +543,16 @@ static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
543 return ctrl->data + id * ctrl->info->size; 543 return ctrl->data + id * ctrl->info->size;
544} 544}
545 545
546static inline int uvc_get_bit(const __u8 *data, int bit) 546static inline int uvc_test_bit(const __u8 *data, int bit)
547{ 547{
548 return (data[bit >> 3] >> (bit & 7)) & 1; 548 return (data[bit >> 3] >> (bit & 7)) & 1;
549} 549}
550 550
551static inline void uvc_clear_bit(__u8 *data, int bit)
552{
553 data[bit >> 3] &= ~(1 << (bit & 7));
554}
555
551/* Extract the bit string specified by mapping->offset and mapping->size 556/* Extract the bit string specified by mapping->offset and mapping->size
552 * from the little-endian data stored at 'data' and return the result as 557 * from the little-endian data stored at 'data' and return the result as
553 * a signed 32bit integer. Sign extension will be performed if the mapping 558 * a signed 32bit integer. Sign extension will be performed if the mapping
@@ -1306,6 +1311,51 @@ end:
1306} 1311}
1307 1312
1308/* 1313/*
1314 * Prune an entity of its bogus controls. This currently includes processing
1315 * unit auto controls for which no corresponding manual control is available.
1316 * Such auto controls make little sense if any, and are known to crash at
1317 * least the SiGma Micro webcam.
1318 */
1319static void
1320uvc_ctrl_prune_entity(struct uvc_entity *entity)
1321{
1322 static const struct {
1323 u8 idx_manual;
1324 u8 idx_auto;
1325 } blacklist[] = {
1326 { 2, 11 }, /* Hue */
1327 { 6, 12 }, /* White Balance Temperature */
1328 { 7, 13 }, /* White Balance Component */
1329 };
1330
1331 u8 *controls;
1332 unsigned int size;
1333 unsigned int i;
1334
1335 if (UVC_ENTITY_TYPE(entity) != VC_PROCESSING_UNIT)
1336 return;
1337
1338 controls = entity->processing.bmControls;
1339 size = entity->processing.bControlSize;
1340
1341 for (i = 0; i < ARRAY_SIZE(blacklist); ++i) {
1342 if (blacklist[i].idx_auto >= 8 * size ||
1343 blacklist[i].idx_manual >= 8 * size)
1344 continue;
1345
1346 if (!uvc_test_bit(controls, blacklist[i].idx_auto) ||
1347 uvc_test_bit(controls, blacklist[i].idx_manual))
1348 continue;
1349
1350 uvc_trace(UVC_TRACE_CONTROL, "Auto control %u/%u has no "
1351 "matching manual control, removing it.\n", entity->id,
1352 blacklist[i].idx_auto);
1353
1354 uvc_clear_bit(controls, blacklist[i].idx_auto);
1355 }
1356}
1357
1358/*
1309 * Initialize device controls. 1359 * Initialize device controls.
1310 */ 1360 */
1311int uvc_ctrl_init_device(struct uvc_device *dev) 1361int uvc_ctrl_init_device(struct uvc_device *dev)
@@ -1331,6 +1381,9 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
1331 bControlSize = entity->camera.bControlSize; 1381 bControlSize = entity->camera.bControlSize;
1332 } 1382 }
1333 1383
1384 if (dev->quirks & UVC_QUIRK_PRUNE_CONTROLS)
1385 uvc_ctrl_prune_entity(entity);
1386
1334 for (i = 0; i < bControlSize; ++i) 1387 for (i = 0; i < bControlSize; ++i)
1335 ncontrols += hweight8(bmControls[i]); 1388 ncontrols += hweight8(bmControls[i]);
1336 1389
@@ -1345,7 +1398,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
1345 1398
1346 ctrl = entity->controls; 1399 ctrl = entity->controls;
1347 for (i = 0; i < bControlSize * 8; ++i) { 1400 for (i = 0; i < bControlSize * 8; ++i) {
1348 if (uvc_get_bit(bmControls, i) == 0) 1401 if (uvc_test_bit(bmControls, i) == 0)
1349 continue; 1402 continue;
1350 1403
1351 ctrl->entity = entity; 1404 ctrl->entity = entity;
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index a67533f11f2e..1054c7656aef 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -1894,7 +1894,8 @@ static struct usb_device_id uvc_ids[] = {
1894 .bInterfaceSubClass = 1, 1894 .bInterfaceSubClass = 1,
1895 .bInterfaceProtocol = 0, 1895 .bInterfaceProtocol = 0,
1896 .driver_info = UVC_QUIRK_PROBE_MINMAX 1896 .driver_info = UVC_QUIRK_PROBE_MINMAX
1897 | UVC_QUIRK_IGNORE_SELECTOR_UNIT}, 1897 | UVC_QUIRK_IGNORE_SELECTOR_UNIT
1898 | UVC_QUIRK_PRUNE_CONTROLS },
1898 /* Generic USB Video Class */ 1899 /* Generic USB Video Class */
1899 { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) }, 1900 { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
1900 {} 1901 {}
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 437df60e0dae..00d593776b86 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -316,6 +316,7 @@ struct uvc_xu_control {
316#define UVC_QUIRK_BUILTIN_ISIGHT 0x00000008 316#define UVC_QUIRK_BUILTIN_ISIGHT 0x00000008
317#define UVC_QUIRK_STREAM_NO_FID 0x00000010 317#define UVC_QUIRK_STREAM_NO_FID 0x00000010
318#define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020 318#define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
319#define UVC_QUIRK_PRUNE_CONTROLS 0x00000040
319 320
320/* Format flags */ 321/* Format flags */
321#define UVC_FMT_FLAG_COMPRESSED 0x00000001 322#define UVC_FMT_FLAG_COMPRESSED 0x00000001