summaryrefslogtreecommitdiff
path: root/drivers/media/usb/uvc/uvc_ctrl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/usb/uvc/uvc_ctrl.c')
-rw-r--r--drivers/media/usb/uvc/uvc_ctrl.c120
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)