aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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