Commit 2bdd29cf authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab

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: default avatarLaurent Pinchart <laurent.pinchart@skynet.be>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 0fbd8ee6
...@@ -543,11 +543,16 @@ static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id) ...@@ -543,11 +543,16 @@ static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
return ctrl->data + id * ctrl->info->size; return ctrl->data + id * ctrl->info->size;
} }
static inline int uvc_get_bit(const __u8 *data, int bit) static inline int uvc_test_bit(const __u8 *data, int bit)
{ {
return (data[bit >> 3] >> (bit & 7)) & 1; return (data[bit >> 3] >> (bit & 7)) & 1;
} }
static inline void uvc_clear_bit(__u8 *data, int bit)
{
data[bit >> 3] &= ~(1 << (bit & 7));
}
/* Extract the bit string specified by mapping->offset and mapping->size /* Extract the bit string specified by mapping->offset and mapping->size
* from the little-endian data stored at 'data' and return the result as * from the little-endian data stored at 'data' and return the result as
* a signed 32bit integer. Sign extension will be performed if the mapping * a signed 32bit integer. Sign extension will be performed if the mapping
...@@ -1305,6 +1310,51 @@ int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping) ...@@ -1305,6 +1310,51 @@ int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping)
return ret; return ret;
} }
/*
* Prune an entity of its bogus controls. This currently includes 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.
*/
static void
uvc_ctrl_prune_entity(struct uvc_entity *entity)
{
static const struct {
u8 idx_manual;
u8 idx_auto;
} blacklist[] = {
{ 2, 11 }, /* Hue */
{ 6, 12 }, /* White Balance Temperature */
{ 7, 13 }, /* White Balance Component */
};
u8 *controls;
unsigned int size;
unsigned int i;
if (UVC_ENTITY_TYPE(entity) != VC_PROCESSING_UNIT)
return;
controls = entity->processing.bmControls;
size = entity->processing.bControlSize;
for (i = 0; i < ARRAY_SIZE(blacklist); ++i) {
if (blacklist[i].idx_auto >= 8 * size ||
blacklist[i].idx_manual >= 8 * size)
continue;
if (!uvc_test_bit(controls, blacklist[i].idx_auto) ||
uvc_test_bit(controls, blacklist[i].idx_manual))
continue;
uvc_trace(UVC_TRACE_CONTROL, "Auto control %u/%u has no "
"matching manual control, removing it.\n", entity->id,
blacklist[i].idx_auto);
uvc_clear_bit(controls, blacklist[i].idx_auto);
}
}
/* /*
* Initialize device controls. * Initialize device controls.
*/ */
...@@ -1331,6 +1381,9 @@ int uvc_ctrl_init_device(struct uvc_device *dev) ...@@ -1331,6 +1381,9 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
bControlSize = entity->camera.bControlSize; bControlSize = entity->camera.bControlSize;
} }
if (dev->quirks & UVC_QUIRK_PRUNE_CONTROLS)
uvc_ctrl_prune_entity(entity);
for (i = 0; i < bControlSize; ++i) for (i = 0; i < bControlSize; ++i)
ncontrols += hweight8(bmControls[i]); ncontrols += hweight8(bmControls[i]);
...@@ -1345,7 +1398,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev) ...@@ -1345,7 +1398,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
ctrl = entity->controls; ctrl = entity->controls;
for (i = 0; i < bControlSize * 8; ++i) { for (i = 0; i < bControlSize * 8; ++i) {
if (uvc_get_bit(bmControls, i) == 0) if (uvc_test_bit(bmControls, i) == 0)
continue; continue;
ctrl->entity = entity; ctrl->entity = entity;
......
...@@ -1894,7 +1894,8 @@ static struct usb_device_id uvc_ids[] = { ...@@ -1894,7 +1894,8 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1, .bInterfaceSubClass = 1,
.bInterfaceProtocol = 0, .bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_MINMAX .driver_info = UVC_QUIRK_PROBE_MINMAX
| UVC_QUIRK_IGNORE_SELECTOR_UNIT}, | UVC_QUIRK_IGNORE_SELECTOR_UNIT
| UVC_QUIRK_PRUNE_CONTROLS },
/* Generic USB Video Class */ /* Generic USB Video Class */
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) }, { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
{} {}
......
...@@ -316,6 +316,7 @@ struct uvc_xu_control { ...@@ -316,6 +316,7 @@ struct uvc_xu_control {
#define UVC_QUIRK_BUILTIN_ISIGHT 0x00000008 #define UVC_QUIRK_BUILTIN_ISIGHT 0x00000008
#define UVC_QUIRK_STREAM_NO_FID 0x00000010 #define UVC_QUIRK_STREAM_NO_FID 0x00000010
#define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020 #define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
#define UVC_QUIRK_PRUNE_CONTROLS 0x00000040
/* Format flags */ /* Format flags */
#define UVC_FMT_FLAG_COMPRESSED 0x00000001 #define UVC_FMT_FLAG_COMPRESSED 0x00000001
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment