diff options
Diffstat (limited to 'drivers/media/usb/uvc/uvc_ctrl.c')
-rw-r--r-- | drivers/media/usb/uvc/uvc_ctrl.c | 120 |
1 files changed, 95 insertions, 25 deletions
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 0e78233fc8a0..8c208db9600b 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -366,6 +366,7 @@ static const struct uvc_menu_info power_line_frequency_controls[] = { { 0, "Disabled" }, { 1, "50 Hz" }, { 2, "60 Hz" }, + { 3, "Auto" }, }; static const struct uvc_menu_info exposure_auto_controls[] = { @@ -505,17 +506,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, }, { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, - .size = 2, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_MENU, - .data_type = UVC_CTRL_DATA_TYPE_ENUM, - .menu_info = power_line_frequency_controls, - .menu_count = ARRAY_SIZE(power_line_frequency_controls), - }, - { .id = V4L2_CID_HUE_AUTO, .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_HUE_AUTO_CONTROL, @@ -730,6 +720,34 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, }; +static const struct uvc_control_mapping uvc_ctrl_mappings_uvc11[] = { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .entity = UVC_GUID_UVC_PROCESSING, + .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, + .size = 2, + .offset = 0, + .v4l2_type = V4L2_CTRL_TYPE_MENU, + .data_type = UVC_CTRL_DATA_TYPE_ENUM, + .menu_info = power_line_frequency_controls, + .menu_count = ARRAY_SIZE(power_line_frequency_controls) - 1, + }, +}; + +static const struct uvc_control_mapping uvc_ctrl_mappings_uvc15[] = { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .entity = UVC_GUID_UVC_PROCESSING, + .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, + .size = 2, + .offset = 0, + .v4l2_type = V4L2_CTRL_TYPE_MENU, + .data_type = UVC_CTRL_DATA_TYPE_ENUM, + .menu_info = power_line_frequency_controls, + .menu_count = ARRAY_SIZE(power_line_frequency_controls), + }, +}; + /* ------------------------------------------------------------------------ * Utility functions */ @@ -749,7 +767,8 @@ 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 * a signed 32bit integer. Sign extension will be performed if the mapping * references a signed data type. @@ -785,7 +804,8 @@ static s32 uvc_get_le_value(struct uvc_control_mapping *mapping, return value; } -/* Set the bit string specified by mapping->offset and mapping->size +/* + * Set the bit string specified by mapping->offset and mapping->size * in the little-endian data stored at 'data' to the value 'value'. */ static void uvc_set_le_value(struct uvc_control_mapping *mapping, @@ -795,7 +815,8 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping, int offset = mapping->offset; u8 mask; - /* According to the v4l2 spec, writing any value to a button control + /* + * According to the v4l2 spec, writing any value to a button control * should result in the action belonging to the button control being * triggered. UVC devices however want to see a 1 written -> override * value. @@ -927,7 +948,8 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain, UVC_VC_EXTENSION_UNIT) return ret; - /* GET_RES is mandatory for XU controls, but some + /* + * GET_RES is mandatory for XU controls, but some * cameras still choke on it. Ignore errors and set the * resolution value to zero. */ @@ -1522,8 +1544,10 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems) uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, val, changes); - /* Mark the queue as active, allowing this initial - event to be accepted. */ + /* + * Mark the queue as active, allowing this initial event to be + * accepted. + */ sev->elems = elems; v4l2_event_queue_fh(sev->fh, &ev); } @@ -1596,7 +1620,8 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev, if (!ctrl->initialized) continue; - /* Reset the loaded flag for auto-update controls that were + /* + * Reset the loaded flag for auto-update controls that were * marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent * uvc_ctrl_get from using the cached value, and for write-only * controls to prevent uvc_ctrl_set from setting bits not @@ -1755,7 +1780,8 @@ int uvc_ctrl_set(struct uvc_fh *handle, return -ERANGE; value = mapping->menu_info[xctrl->value].value; - /* Valid menu indices are reported by the GET_RES request for + /* + * Valid menu indices are reported by the GET_RES request for * UVC controls that support it. */ if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK && @@ -1779,7 +1805,8 @@ int uvc_ctrl_set(struct uvc_fh *handle, break; } - /* If the mapping doesn't span the whole UVC control, the current value + /* + * If the mapping doesn't span the whole UVC control, the current value * needs to be loaded from the device to perform the read-modify-write * operation. */ @@ -2180,7 +2207,8 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain, unsigned int size; unsigned int i; - /* Most mappings come from static kernel data and need to be duplicated. + /* + * Most mappings come from static kernel data and need to be duplicated. * Mappings that come from userspace will be unnecessarily duplicated, * this could be optimized. */ @@ -2385,11 +2413,11 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain, { const struct uvc_control_info *info = uvc_ctrls; const struct uvc_control_info *iend = info + ARRAY_SIZE(uvc_ctrls); - const struct uvc_control_mapping *mapping = uvc_ctrl_mappings; - const struct uvc_control_mapping *mend = - mapping + ARRAY_SIZE(uvc_ctrl_mappings); + const struct uvc_control_mapping *mapping; + const struct uvc_control_mapping *mend; - /* XU controls initialization requires querying the device for control + /* + * XU controls initialization requires querying the device for control * information. As some buggy UVC devices will crash when queried * repeatedly in a tight loop, delay XU controls initialization until * first use. @@ -2415,6 +2443,48 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain, if (!ctrl->initialized) return; + /* + * First check if the device provides a custom mapping for this control, + * used to override standard mappings for non-conformant devices. Don't + * process standard mappings if a custom mapping is found. This + * mechanism doesn't support combining standard and custom mappings for + * a single control. + */ + if (chain->dev->info->mappings) { + bool custom = false; + unsigned int i; + + for (i = 0; (mapping = chain->dev->info->mappings[i]); ++i) { + if (uvc_entity_match_guid(ctrl->entity, mapping->entity) && + ctrl->info.selector == mapping->selector) { + __uvc_ctrl_add_mapping(chain, ctrl, mapping); + custom = true; + } + } + + if (custom) + return; + } + + /* Process common mappings next. */ + mapping = uvc_ctrl_mappings; + mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings); + + for (; mapping < mend; ++mapping) { + if (uvc_entity_match_guid(ctrl->entity, mapping->entity) && + ctrl->info.selector == mapping->selector) + __uvc_ctrl_add_mapping(chain, ctrl, mapping); + } + + /* Finally process version-specific mappings. */ + if (chain->dev->uvc_version < 0x0150) { + mapping = uvc_ctrl_mappings_uvc11; + mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings_uvc11); + } else { + mapping = uvc_ctrl_mappings_uvc15; + mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings_uvc15); + } + for (; mapping < mend; ++mapping) { if (uvc_entity_match_guid(ctrl->entity, mapping->entity) && ctrl->info.selector == mapping->selector) |