diff options
-rw-r--r-- | drivers/media/video/uvc/uvc_ctrl.c | 57 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvc_driver.c | 3 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvcvideo.h | 1 |
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 | ||
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 | return (data[bit >> 3] >> (bit & 7)) & 1; | 548 | return (data[bit >> 3] >> (bit & 7)) & 1; |
549 | } | 549 | } |
550 | 550 | ||
551 | static 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 | */ | ||
1319 | static void | ||
1320 | uvc_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 | */ |
1311 | int uvc_ctrl_init_device(struct uvc_device *dev) | 1361 | int 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 |