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.c179
1 files changed, 99 insertions, 80 deletions
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 011e69427b7c..b3dde98499f4 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -347,6 +347,14 @@ static const struct uvc_control_info uvc_ctrls[] = {
| UVC_CTRL_FLAG_RESTORE
| UVC_CTRL_FLAG_AUTO_UPDATE,
},
+ {
+ .entity = UVC_GUID_EXT_GPIO_CONTROLLER,
+ .selector = UVC_CT_PRIVACY_CONTROL,
+ .index = 0,
+ .size = 1,
+ .flags = UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
+ },
};
static const struct uvc_menu_info power_line_frequency_controls[] = {
@@ -735,6 +743,16 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
.data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
},
+ {
+ .id = V4L2_CID_PRIVACY,
+ .name = "Privacy",
+ .entity = UVC_GUID_EXT_GPIO_CONTROLLER,
+ .selector = UVC_CT_PRIVACY_CONTROL,
+ .size = 1,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
+ .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
+ },
};
/* ------------------------------------------------------------------------
@@ -826,31 +844,10 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping,
* Terminal and unit management
*/
-static const u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING;
-static const u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA;
-static const u8 uvc_media_transport_input_guid[16] =
- UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT;
-
static int uvc_entity_match_guid(const struct uvc_entity *entity,
- const u8 guid[16])
+ const u8 guid[16])
{
- switch (UVC_ENTITY_TYPE(entity)) {
- case UVC_ITT_CAMERA:
- return memcmp(uvc_camera_guid, guid, 16) == 0;
-
- case UVC_ITT_MEDIA_TRANSPORT_INPUT:
- return memcmp(uvc_media_transport_input_guid, guid, 16) == 0;
-
- case UVC_VC_PROCESSING_UNIT:
- return memcmp(uvc_processing_guid, guid, 16) == 0;
-
- case UVC_VC_EXTENSION_UNIT:
- return memcmp(entity->extension.guidExtensionCode,
- guid, 16) == 0;
-
- default:
- return 0;
- }
+ return memcmp(entity->guid, guid, sizeof(entity->guid)) == 0;
}
/* ------------------------------------------------------------------------
@@ -909,8 +906,8 @@ static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
}
if (ctrl == NULL && !next)
- uvc_trace(UVC_TRACE_CONTROL, "Control 0x%08x not found.\n",
- v4l2_id);
+ uvc_dbg(chain->dev, CONTROL, "Control 0x%08x not found\n",
+ v4l2_id);
return ctrl;
}
@@ -1001,10 +998,20 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain,
return -EACCES;
if (!ctrl->loaded) {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info.selector,
+ if (ctrl->entity->get_cur) {
+ ret = ctrl->entity->get_cur(chain->dev,
+ ctrl->entity,
+ ctrl->info.selector,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ ctrl->info.size);
+ } else {
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR,
+ ctrl->entity->id,
+ chain->dev->intfnum,
+ ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
ctrl->info.size);
+ }
if (ret < 0)
return ret;
@@ -1275,17 +1282,12 @@ static void uvc_ctrl_send_slave_event(struct uvc_video_chain *chain,
uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes);
}
-static void uvc_ctrl_status_event_work(struct work_struct *work)
+void uvc_ctrl_status_event(struct uvc_video_chain *chain,
+ struct uvc_control *ctrl, const u8 *data)
{
- struct uvc_device *dev = container_of(work, struct uvc_device,
- async_ctrl.work);
- struct uvc_ctrl_work *w = &dev->async_ctrl;
- struct uvc_video_chain *chain = w->chain;
struct uvc_control_mapping *mapping;
- struct uvc_control *ctrl = w->ctrl;
struct uvc_fh *handle;
unsigned int i;
- int ret;
mutex_lock(&chain->ctrl_mutex);
@@ -1293,7 +1295,7 @@ static void uvc_ctrl_status_event_work(struct work_struct *work)
ctrl->handle = NULL;
list_for_each_entry(mapping, &ctrl->info.mappings, list) {
- s32 value = __uvc_ctrl_get_value(mapping, w->data);
+ s32 value = __uvc_ctrl_get_value(mapping, data);
/*
* handle may be NULL here if the device sends auto-update
@@ -1312,17 +1314,27 @@ static void uvc_ctrl_status_event_work(struct work_struct *work)
}
mutex_unlock(&chain->ctrl_mutex);
+}
+
+static void uvc_ctrl_status_event_work(struct work_struct *work)
+{
+ struct uvc_device *dev = container_of(work, struct uvc_device,
+ async_ctrl.work);
+ struct uvc_ctrl_work *w = &dev->async_ctrl;
+ int ret;
+
+ uvc_ctrl_status_event(w->chain, w->ctrl, w->data);
/* Resubmit the URB. */
w->urb->interval = dev->int_ep->desc.bInterval;
ret = usb_submit_urb(w->urb, GFP_KERNEL);
if (ret < 0)
- uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n",
- ret);
+ dev_err(&dev->udev->dev,
+ "Failed to resubmit status URB (%d).\n", ret);
}
-bool uvc_ctrl_status_event(struct urb *urb, struct uvc_video_chain *chain,
- struct uvc_control *ctrl, const u8 *data)
+bool uvc_ctrl_status_event_async(struct urb *urb, struct uvc_video_chain *chain,
+ struct uvc_control *ctrl, const u8 *data)
{
struct uvc_device *dev = chain->dev;
struct uvc_ctrl_work *w = &dev->async_ctrl;
@@ -1708,8 +1720,12 @@ static int uvc_ctrl_get_flags(struct uvc_device *dev,
if (data == NULL)
return -ENOMEM;
- ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
- info->selector, data, 1);
+ if (ctrl->entity->get_info)
+ ret = ctrl->entity->get_info(dev, ctrl->entity,
+ ctrl->info.selector, data);
+ else
+ ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id,
+ dev->intfnum, info->selector, data, 1);
if (!ret)
info->flags |= (data[0] & UVC_CONTROL_CAP_GET ?
UVC_CTRL_FLAG_GET_CUR : 0)
@@ -1776,8 +1792,7 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
if (data == NULL)
return -ENOMEM;
- memcpy(info->entity, ctrl->entity->extension.guidExtensionCode,
- sizeof(info->entity));
+ memcpy(info->entity, ctrl->entity->guid, sizeof(info->entity));
info->index = ctrl->index;
info->selector = ctrl->index + 1;
@@ -1785,9 +1800,9 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id, dev->intfnum,
info->selector, data, 2);
if (ret < 0) {
- uvc_trace(UVC_TRACE_CONTROL,
- "GET_LEN failed on control %pUl/%u (%d).\n",
- info->entity, info->selector, ret);
+ uvc_dbg(dev, CONTROL,
+ "GET_LEN failed on control %pUl/%u (%d)\n",
+ info->entity, info->selector, ret);
goto done;
}
@@ -1798,20 +1813,20 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
ret = uvc_ctrl_get_flags(dev, ctrl, info);
if (ret < 0) {
- uvc_trace(UVC_TRACE_CONTROL,
- "Failed to get flags for control %pUl/%u (%d).\n",
- info->entity, info->selector, ret);
+ uvc_dbg(dev, CONTROL,
+ "Failed to get flags for control %pUl/%u (%d)\n",
+ info->entity, info->selector, ret);
goto done;
}
uvc_ctrl_fixup_xu_info(dev, ctrl, info);
- uvc_trace(UVC_TRACE_CONTROL, "XU control %pUl/%u queried: len %u, "
- "flags { get %u set %u auto %u }.\n",
- info->entity, info->selector, info->size,
- (info->flags & UVC_CTRL_FLAG_GET_CUR) ? 1 : 0,
- (info->flags & UVC_CTRL_FLAG_SET_CUR) ? 1 : 0,
- (info->flags & UVC_CTRL_FLAG_AUTO_UPDATE) ? 1 : 0);
+ uvc_dbg(dev, CONTROL,
+ "XU control %pUl/%u queried: len %u, flags { get %u set %u auto %u }\n",
+ info->entity, info->selector, info->size,
+ (info->flags & UVC_CTRL_FLAG_GET_CUR) ? 1 : 0,
+ (info->flags & UVC_CTRL_FLAG_SET_CUR) ? 1 : 0,
+ (info->flags & UVC_CTRL_FLAG_AUTO_UPDATE) ? 1 : 0);
done:
kfree(data);
@@ -1836,9 +1851,10 @@ static int uvc_ctrl_init_xu_ctrl(struct uvc_device *dev,
ret = uvc_ctrl_add_info(dev, ctrl, &info);
if (ret < 0)
- uvc_trace(UVC_TRACE_CONTROL, "Failed to initialize control "
- "%pUl/%u on device %s entity %u\n", info.entity,
- info.selector, dev->udev->devpath, ctrl->entity->id);
+ uvc_dbg(dev, CONTROL,
+ "Failed to initialize control %pUl/%u on device %s entity %u\n",
+ info.entity, info.selector, dev->udev->devpath,
+ ctrl->entity->id);
return ret;
}
@@ -1866,7 +1882,7 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
}
if (!found) {
- uvc_trace(UVC_TRACE_CONTROL, "Extension unit %u not found.\n",
+ uvc_dbg(chain->dev, CONTROL, "Extension unit %u not found\n",
xqry->unit);
return -ENOENT;
}
@@ -1882,8 +1898,8 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
}
if (!found) {
- uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u not found.\n",
- entity->extension.guidExtensionCode, xqry->selector);
+ uvc_dbg(chain->dev, CONTROL, "Control %pUl/%u not found\n",
+ entity->guid, xqry->selector);
return -ENOENT;
}
@@ -1995,10 +2011,10 @@ int uvc_ctrl_restore_values(struct uvc_device *dev)
if (!ctrl->initialized || !ctrl->modified ||
(ctrl->info.flags & UVC_CTRL_FLAG_RESTORE) == 0)
continue;
-
- printk(KERN_INFO "restoring control %pUl/%u/%u\n",
- ctrl->info.entity, ctrl->info.index,
- ctrl->info.selector);
+ dev_info(&dev->udev->dev,
+ "restoring control %pUl/%u/%u\n",
+ ctrl->info.entity, ctrl->info.index,
+ ctrl->info.selector);
ctrl->dirty = 1;
}
@@ -2031,9 +2047,9 @@ static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
ctrl->initialized = 1;
- uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
- "entity %u\n", ctrl->info.entity, ctrl->info.selector,
- dev->udev->devpath, ctrl->entity->id);
+ uvc_dbg(dev, CONTROL, "Added control %pUl/%u to device %s entity %u\n",
+ ctrl->info.entity, ctrl->info.selector, dev->udev->devpath,
+ ctrl->entity->id);
return 0;
}
@@ -2070,8 +2086,7 @@ static int __uvc_ctrl_add_mapping(struct uvc_device *dev,
map->set = uvc_set_le_value;
list_add_tail(&map->list, &ctrl->info.mappings);
- uvc_trace(UVC_TRACE_CONTROL,
- "Adding mapping '%s' to control %pUl/%u.\n",
+ uvc_dbg(dev, CONTROL, "Adding mapping '%s' to control %pUl/%u\n",
map->name, ctrl->info.entity, ctrl->info.selector);
return 0;
@@ -2088,9 +2103,9 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
int ret;
if (mapping->id & ~V4L2_CTRL_ID_MASK) {
- uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', control "
- "id 0x%08x is invalid.\n", mapping->name,
- mapping->id);
+ uvc_dbg(dev, CONTROL,
+ "Can't add mapping '%s', control id 0x%08x is invalid\n",
+ mapping->name, mapping->id);
return -EINVAL;
}
@@ -2135,8 +2150,8 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
list_for_each_entry(map, &ctrl->info.mappings, list) {
if (mapping->id == map->id) {
- uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', "
- "control id 0x%08x already exists.\n",
+ uvc_dbg(dev, CONTROL,
+ "Can't add mapping '%s', control id 0x%08x already exists\n",
mapping->name, mapping->id);
ret = -EEXIST;
goto done;
@@ -2146,9 +2161,9 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
/* Prevent excess memory consumption */
if (atomic_inc_return(&dev->nmappings) > UVC_MAX_CONTROL_MAPPINGS) {
atomic_dec(&dev->nmappings);
- uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', maximum "
- "mappings count (%u) exceeded.\n", mapping->name,
- UVC_MAX_CONTROL_MAPPINGS);
+ uvc_dbg(dev, CONTROL,
+ "Can't add mapping '%s', maximum mappings count (%u) exceeded\n",
+ mapping->name, UVC_MAX_CONTROL_MAPPINGS);
ret = -ENOMEM;
goto done;
}
@@ -2217,8 +2232,9 @@ static void uvc_ctrl_prune_entity(struct uvc_device *dev,
!uvc_test_bit(controls, blacklist[i].index))
continue;
- uvc_trace(UVC_TRACE_CONTROL, "%u/%u control is black listed, "
- "removing it.\n", entity->id, blacklist[i].index);
+ uvc_dbg(dev, CONTROL,
+ "%u/%u control is black listed, removing it\n",
+ entity->id, blacklist[i].index);
uvc_clear_bit(controls, blacklist[i].index);
}
@@ -2294,6 +2310,9 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
} else if (UVC_ENTITY_TYPE(entity) == UVC_ITT_CAMERA) {
bmControls = entity->camera.bmControls;
bControlSize = entity->camera.bControlSize;
+ } else if (UVC_ENTITY_TYPE(entity) == UVC_EXT_GPIO_UNIT) {
+ bmControls = entity->gpio.bmControls;
+ bControlSize = entity->gpio.bControlSize;
}
/* Remove bogus/blacklisted controls */