Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Laurent Pinchart and committed by
Mauro Carvalho Chehab
2bdd29cf 0fbd8ee6

+58 -3
+55 -2
drivers/media/video/uvc/uvc_ctrl.c
··· 543 543 return ctrl->data + id * ctrl->info->size; 544 544 } 545 545 546 - static inline int uvc_get_bit(const __u8 *data, int bit) 546 + static inline int uvc_test_bit(const __u8 *data, int bit) 547 547 { 548 548 return (data[bit >> 3] >> (bit & 7)) & 1; 549 + } 550 + 551 + static inline void uvc_clear_bit(__u8 *data, int bit) 552 + { 553 + data[bit >> 3] &= ~(1 << (bit & 7)); 549 554 } 550 555 551 556 /* Extract the bit string specified by mapping->offset and mapping->size ··· 1311 1306 } 1312 1307 1313 1308 /* 1309 + * Prune an entity of its bogus controls. This currently includes processing 1310 + * unit auto controls for which no corresponding manual control is available. 1311 + * Such auto controls make little sense if any, and are known to crash at 1312 + * least the SiGma Micro webcam. 1313 + */ 1314 + static void 1315 + uvc_ctrl_prune_entity(struct uvc_entity *entity) 1316 + { 1317 + static const struct { 1318 + u8 idx_manual; 1319 + u8 idx_auto; 1320 + } blacklist[] = { 1321 + { 2, 11 }, /* Hue */ 1322 + { 6, 12 }, /* White Balance Temperature */ 1323 + { 7, 13 }, /* White Balance Component */ 1324 + }; 1325 + 1326 + u8 *controls; 1327 + unsigned int size; 1328 + unsigned int i; 1329 + 1330 + if (UVC_ENTITY_TYPE(entity) != VC_PROCESSING_UNIT) 1331 + return; 1332 + 1333 + controls = entity->processing.bmControls; 1334 + size = entity->processing.bControlSize; 1335 + 1336 + for (i = 0; i < ARRAY_SIZE(blacklist); ++i) { 1337 + if (blacklist[i].idx_auto >= 8 * size || 1338 + blacklist[i].idx_manual >= 8 * size) 1339 + continue; 1340 + 1341 + if (!uvc_test_bit(controls, blacklist[i].idx_auto) || 1342 + uvc_test_bit(controls, blacklist[i].idx_manual)) 1343 + continue; 1344 + 1345 + uvc_trace(UVC_TRACE_CONTROL, "Auto control %u/%u has no " 1346 + "matching manual control, removing it.\n", entity->id, 1347 + blacklist[i].idx_auto); 1348 + 1349 + uvc_clear_bit(controls, blacklist[i].idx_auto); 1350 + } 1351 + } 1352 + 1353 + /* 1314 1354 * Initialize device controls. 1315 1355 */ 1316 1356 int uvc_ctrl_init_device(struct uvc_device *dev) ··· 1381 1331 bControlSize = entity->camera.bControlSize; 1382 1332 } 1383 1333 1334 + if (dev->quirks & UVC_QUIRK_PRUNE_CONTROLS) 1335 + uvc_ctrl_prune_entity(entity); 1336 + 1384 1337 for (i = 0; i < bControlSize; ++i) 1385 1338 ncontrols += hweight8(bmControls[i]); 1386 1339 ··· 1398 1345 1399 1346 ctrl = entity->controls; 1400 1347 for (i = 0; i < bControlSize * 8; ++i) { 1401 - if (uvc_get_bit(bmControls, i) == 0) 1348 + if (uvc_test_bit(bmControls, i) == 0) 1402 1349 continue; 1403 1350 1404 1351 ctrl->entity = entity;
+2 -1
drivers/media/video/uvc/uvc_driver.c
··· 1894 1894 .bInterfaceSubClass = 1, 1895 1895 .bInterfaceProtocol = 0, 1896 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 1899 /* Generic USB Video Class */ 1899 1900 { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) }, 1900 1901 {}
+1
drivers/media/video/uvc/uvcvideo.h
··· 316 316 #define UVC_QUIRK_BUILTIN_ISIGHT 0x00000008 317 317 #define UVC_QUIRK_STREAM_NO_FID 0x00000010 318 318 #define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020 319 + #define UVC_QUIRK_PRUNE_CONTROLS 0x00000040 319 320 320 321 /* Format flags */ 321 322 #define UVC_FMT_FLAG_COMPRESSED 0x00000001