/* * This function translates the V4L2 menu index @idx, as exposed to userspace as * the V4L2 control value, to the corresponding UVC control value used by the * device. The custom menu_mapping in the control @mapping is used when * available, otherwise the function assumes that the V4L2 and UVC values are * identical. * * For controls of type UVC_CTRL_DATA_TYPE_BITMASK, the UVC control value is * expressed as a bitmask and is thus guaranteed to have a single bit set. * * The function returns -EINVAL if the V4L2 menu index @idx isn't valid for the * control, which includes all controls whose type isn't UVC_CTRL_DATA_TYPE_ENUM * or UVC_CTRL_DATA_TYPE_BITMASK.
*/ staticint uvc_mapping_get_menu_value(conststruct uvc_control_mapping *mapping,
u32 idx)
{ if (!test_bit(idx, &mapping->menu_mask)) return -EINVAL;
if (mapping->menu_mapping) return mapping->menu_mapping[idx];
buf = kmalloc(sizeof(*buf), GFP_KERNEL); if (!buf) return NULL;
/* Save the current PLF value, so we can restore it. */
ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id,
chain->dev->intfnum, ctrl->info.selector,
buf, sizeof(*buf)); /* If we cannot read the control skip it. */ if (ret) return NULL;
init_val = *buf;
/* If PLF value cannot be set to off, it is limited. */
*buf = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED;
ret = uvc_query_ctrl(chain->dev, UVC_SET_CUR, ctrl->entity->id,
chain->dev->intfnum, ctrl->info.selector,
buf, sizeof(*buf)); if (ret) return &uvc_ctrl_power_line_mapping_limited;
/* UVC 1.1 does not define auto, we can exit. */ if (chain->dev->uvc_version < 0x150) goto end;
/* Check if the device supports auto. */
*buf = V4L2_CID_POWER_LINE_FREQUENCY_AUTO;
ret = uvc_query_ctrl(chain->dev, UVC_SET_CUR, ctrl->entity->id,
chain->dev->intfnum, ctrl->info.selector,
buf, sizeof(*buf)); if (!ret)
out_mapping = &uvc_ctrl_power_line_mapping_uvc15;
end: /* Restore initial value and add mapping. */
*buf = init_val;
uvc_query_ctrl(chain->dev, UVC_SET_CUR, ctrl->entity->id,
chain->dev->intfnum, ctrl->info.selector,
buf, sizeof(*buf));
/* * 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.
*/ staticint uvc_get_le_value(struct uvc_control_mapping *mapping,
u8 query, constvoid *uvc_in, size_t v4l2_size, void *v4l2_out)
{ int offset = mapping->offset; int bits = mapping->size; const u8 *data = uvc_in;
s32 *out = v4l2_out;
s32 value = 0;
u8 mask;
if (WARN_ON(v4l2_size != sizeof(s32))) return -EINVAL;
/* Sign-extend the value if needed. */ if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED)
value |= -(value & (1 << (mapping->size - 1)));
/* If it is a menu, convert from uvc to v4l2. */ if (mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) {
*out = value; return 0;
}
switch (query) { case UVC_GET_CUR: case UVC_GET_DEF:
*out = uvc_menu_to_v4l2_menu(mapping, value); return 0;
}
*out = value; return 0;
}
/* * Set the bit string specified by mapping->offset and mapping->size * in the little-endian data stored at 'data' to the value 'value'.
*/ staticint uvc_set_le_value(struct uvc_control_mapping *mapping,
size_t v4l2_size, constvoid *v4l2_in, void *uvc_out)
{ int offset = mapping->offset; int bits = mapping->size;
u8 *data = uvc_out;
s32 value;
u8 mask;
if (WARN_ON(v4l2_size != sizeof(s32))) return -EINVAL;
value = *(s32 *)v4l2_in;
switch (mapping->v4l2_type) { case V4L2_CTRL_TYPE_MENU:
value = uvc_mapping_get_menu_value(mapping, value); break; case V4L2_CTRL_TYPE_BUTTON: /* * 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.
*/
value = -1; break; default: break;
}
if (!ctrl && !next && !next_compound)
uvc_dbg(chain->dev, CONTROL, "Control 0x%08x not found\n",
v4l2_id);
return ctrl;
}
staticint uvc_ctrl_populate_cache(struct uvc_video_chain *chain, struct uvc_control *ctrl)
{ int ret;
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
chain->dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
ctrl->info.size); if (ret < 0) return ret;
}
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) {
ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
chain->dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
ctrl->info.size); if (ret < 0) return ret;
} if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) {
ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
chain->dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
ctrl->info.size); if (ret < 0) return ret;
} if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) {
ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
chain->dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
ctrl->info.size); if (ret < 0) { if (UVC_ENTITY_TYPE(ctrl->entity) !=
UVC_VC_EXTENSION_UNIT) return ret;
/* * GET_RES is mandatory for XU controls, but some * cameras still choke on it. Ignore errors and set the * resolution value to zero.
*/
uvc_warn_once(chain->dev, UVC_WARN_XU_GET_RES, "UVC non compliance - GET_RES failed on " "an XU control. Enabling workaround.\n");
memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES), 0,
ctrl->info.size);
}
}
if (which == V4L2_CTRL_WHICH_DEF_VAL) return !!(ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF);
/* Types with implicit boundaries. */ switch (mapping->v4l2_type) { case V4L2_CTRL_TYPE_MENU: case V4L2_CTRL_TYPE_BOOLEAN: case V4L2_CTRL_TYPE_BUTTON: returntrue; case V4L2_CTRL_TYPE_BITMASK: return (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) ||
(ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX); default: break;
}
if (which == V4L2_CTRL_WHICH_MIN_VAL) return !!(ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN);
if (which == V4L2_CTRL_WHICH_MAX_VAL) return !!(ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX);
returnfalse;
}
/* * Check if control @v4l2_id can be accessed by the given control @ioctl * (VIDIOC_G_EXT_CTRLS, VIDIOC_TRY_EXT_CTRLS or VIDIOC_S_EXT_CTRLS). * * For set operations on slave controls, check if the master's value is set to * manual, either in the others controls set in the same ioctl call, or from * the master's current value. This catches VIDIOC_S_EXT_CTRLS calls that set * both the master and slave control, such as for instance setting * auto_exposure=1, exposure_time_absolute=251.
*/ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id, conststruct v4l2_ext_controls *ctrls, unsignedlong ioctl)
{ struct uvc_control_mapping *master_map = NULL; struct uvc_control *master_ctrl = NULL; struct uvc_control_mapping *mapping; struct uvc_control *ctrl;
s32 val; int ret; int i;
if (__uvc_query_v4l2_class(chain, v4l2_id, 0) >= 0) return -EACCES;
ctrl = uvc_find_control(chain, v4l2_id, &mapping); if (!ctrl) return -EINVAL;
if (ioctl == VIDIOC_G_EXT_CTRLS) return uvc_ctrl_is_readable(ctrls->which, ctrl, mapping);
if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) return -EACCES;
if (ioctl != VIDIOC_S_EXT_CTRLS || !mapping->master_id) return 0;
/* * Iterate backwards in cases where the master control is accessed * multiple times in the same ioctl. We want the last value.
*/ for (i = ctrls->count - 1; i >= 0; i--) { if (ctrls->controls[i].id == mapping->master_id) return ctrls->controls[i].value ==
mapping->master_manual ? 0 : -EACCES;
}
name = v4l2_ctrl_get_name(map->id); if (name) return name;
return"Unknown Control";
}
static u32 uvc_get_ctrl_bitmap(struct uvc_control *ctrl, struct uvc_control_mapping *mapping)
{ /* * Some controls, like CT_AE_MODE_CONTROL, use GET_RES to represent * the number of bits supported. Those controls do not list GET_MAX * as supported.
*/ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) return uvc_mapping_get_s32(mapping, UVC_GET_RES,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) return uvc_mapping_get_s32(mapping, UVC_GET_MAX,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
return ~0;
}
/* * Maximum retry count to avoid spurious errors with controls. Increasing this * value does no seem to produce better results in the tested hardware.
*/ #define MAX_QUERY_RETRIES 2
ret = __uvc_queryctrl_boundaries(chain, ctrl, mapping, v4l2_ctrl); if (ret && !mapping->disabled) {
dev_warn(&chain->dev->udev->dev, "UVC non compliance: permanently disabling control %x (%s), due to error %d\n",
mapping->id, uvc_map_get_name(mapping), ret);
mapping->disabled = true;
}
if (mapping->disabled)
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
return 0;
}
int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, struct v4l2_query_ext_ctrl *v4l2_ctrl)
{ struct uvc_control *ctrl; struct uvc_control_mapping *mapping; int ret;
ret = mutex_lock_interruptible(&chain->ctrl_mutex); if (ret < 0) return -ERESTARTSYS;
/* Check if the ctrl is a know class */ if (!(v4l2_ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL)) {
ret = uvc_query_v4l2_class(chain, v4l2_ctrl->id, 0, v4l2_ctrl); if (!ret) goto done;
}
ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping); if (ctrl == NULL) {
ret = -EINVAL; goto done;
}
/* * If we're enumerating control with V4L2_CTRL_FLAG_NEXT_CTRL, check if * a class should be inserted between the previous control and the one * we have just found.
*/ if (v4l2_ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
ret = uvc_query_v4l2_class(chain, v4l2_ctrl->id, mapping->id,
v4l2_ctrl); if (!ret) goto done;
}
/* * Mapping V4L2 controls to UVC controls can be straightforward if done well. * Most of the UVC controls exist in V4L2, and can be mapped directly. Some * must be grouped (for instance the Red Balance, Blue Balance and Do White * Balance V4L2 controls use the White Balance Component UVC control) or * otherwise translated. The approach we take here is to use a translation * table for the controls that can be mapped directly, and handle the others * manually.
*/ int uvc_query_v4l2_menu(struct uvc_video_chain *chain, struct v4l2_querymenu *query_menu)
{ struct uvc_control_mapping *mapping; struct uvc_control *ctrl;
u32 index = query_menu->index;
u32 id = query_menu->id; constchar *name; int ret;
/* * Send control change events to all subscribers for the @ctrl control. By * default the subscriber that generated the event, as identified by @handle, * is not notified unless it has set the V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK flag. * @handle can be NULL for asynchronous events related to auto-update controls, * in which case all subscribers are notified.
*/ staticvoid uvc_ctrl_send_event(struct uvc_video_chain *chain, struct uvc_fh *handle, struct uvc_control *ctrl, struct uvc_control_mapping *mapping, s32 value, u32 changes)
{ struct v4l2_fh *originator = handle ? &handle->vfh : NULL; struct v4l2_subscribed_event *sev; struct v4l2_event ev;
/* * Send control change events for the slave of the @master control identified * by the V4L2 ID @slave_id. The @handle identifies the event subscriber that * generated the event and may be NULL for auto-update events.
*/ staticvoid uvc_ctrl_send_slave_event(struct uvc_video_chain *chain, struct uvc_fh *handle, struct uvc_control *master, u32 slave_id)
{ struct uvc_control_mapping *mapping = NULL; struct uvc_control *ctrl = NULL;
u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
s32 val = 0;
if (uvc_ctrl_mapping_is_compound(mapping))
value = 0; else
value = uvc_mapping_get_s32(mapping, UVC_GET_CUR, data);
/* * handle may be NULL here if the device sends auto-update * events without a prior related control set from userspace.
*/ for (i = 0; i < ARRAY_SIZE(mapping->slave_ids); ++i) { if (!mapping->slave_ids[i]) break;
/* The barrier is needed to synchronize with uvc_status_stop(). */ if (smp_load_acquire(&dev->flush_status)) return;
/* Resubmit the URB. */
w->urb->interval = dev->int_ep->desc.bInterval;
ret = usb_submit_urb(w->urb, GFP_KERNEL); if (ret < 0)
dev_err(&dev->udev->dev, "Failed to resubmit status URB (%d).\n", ret);
}
/* * We can skip sending an event for the slave if the * slave is being modified in the same transaction.
*/ if (uvc_ctrl_xctrls_has_control(xctrls, xctrls_count,
slave_id)) continue;
if (uvc_ctrl_mapping_is_compound(mapping))
value = 0; else
value = xctrls[i].value; /* * If the master is being modified in the same transaction * flags may change too.
*/ if (mapping->master_id &&
uvc_ctrl_xctrls_has_control(xctrls, xctrls_count,
mapping->master_id))
changes |= V4L2_EVENT_CTRL_CH_FLAGS;
/* -------------------------------------------------------------------------- * Control transactions * * To make extended set operations as atomic as the hardware allows, controls * are handled using begin/commit/rollback operations. * * At the beginning of a set request, uvc_ctrl_begin should be called to * initialize the request. This function acquires the control lock. * * When setting a control, the new value is stored in the control data field * at position UVC_CTRL_DATA_CURRENT. The control is then marked as dirty for * later processing. If the UVC and V4L2 control sizes differ, the current * value is loaded from the hardware before storing the new value in the data * field. * * After processing all controls in the transaction, uvc_ctrl_commit or * uvc_ctrl_rollback must be called to apply the pending changes to the * hardware or revert them. When applying changes, all controls marked as * dirty will be modified in the UVC device, and the dirty flag will be * cleared. When reverting controls, the control data field * UVC_CTRL_DATA_CURRENT is reverted to its previous value * (UVC_CTRL_DATA_BACKUP) for all dirty controls. Both functions release the * control lock.
*/ int uvc_ctrl_begin(struct uvc_video_chain *chain)
{ return mutex_lock_interruptible(&chain->ctrl_mutex) ? -ERESTARTSYS : 0;
}
/* * Returns the number of uvc controls that have been correctly set, or a * negative number if there has been an error.
*/ staticint uvc_ctrl_commit_entity(struct uvc_device *dev, struct uvc_fh *handle, struct uvc_entity *entity, int rollback, struct uvc_control **err_ctrl)
{ unsignedint processed_ctrls = 0; struct uvc_control *ctrl; unsignedint i; int ret = 0;
if (entity == NULL) return 0;
for (i = 0; i < entity->ncontrols; ++i) {
ctrl = &entity->controls[i]; if (!ctrl->initialized) continue;
/* * 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 * explicitly set by the user.
*/ if (ctrl->info.flags & UVC_CTRL_FLAG_AUTO_UPDATE ||
!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
ctrl->loaded = 0;
if (!ctrl->dirty) continue;
if (!rollback)
ret = uvc_query_ctrl(dev, UVC_SET_CUR, ctrl->entity->id,
dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
ctrl->info.size);
if (!ret)
processed_ctrls++;
if (rollback || ret < 0)
memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
ctrl->info.size);
ctrl->dirty = 0;
if (!rollback && handle && !ret &&
ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
ret = uvc_ctrl_set_handle(ctrl, handle);
if (ret < 0 && !rollback) { if (err_ctrl)
*err_ctrl = ctrl; /* * If we fail to set a control, we need to rollback * the next ones.
*/
rollback = 1;
}
}
for (i = 0; i < ctrls->count; i++) {
__uvc_find_control(entity, ctrls->controls[i].id, &mapping,
&ctrl_found, 0, 0); if (uvc_control == ctrl_found) return i;
}
return ctrls->count;
}
int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback, struct v4l2_ext_controls *ctrls)
{ struct uvc_video_chain *chain = handle->chain; struct uvc_control *err_ctrl; struct uvc_entity *entity; int ret_out = 0; int ret;
/* Find the control. */
list_for_each_entry(entity, &chain->entities, chain) {
ret = uvc_ctrl_commit_entity(chain->dev, handle, entity,
rollback, &err_ctrl); if (ret < 0) { if (ctrls)
ctrls->error_idx =
uvc_ctrl_find_ctrl_idx(entity, ctrls,
err_ctrl); /* * When we fail to commit an entity, we need to * restore the UVC_CTRL_DATA_BACKUP for all the * controls in the other entities, otherwise our cache * and the hardware will be out of sync.
*/
rollback = 1;
data = kmalloc(size, GFP_KERNEL); if (!data) return -ENOMEM;
if (which == V4L2_CTRL_WHICH_CUR_VAL)
ret = __uvc_ctrl_load_cur(chain, ctrl); else
ret = uvc_ctrl_populate_cache(chain, ctrl);
if (ret < 0) return ret;
ret = mapping->get(mapping, query, uvc_ctrl_data(ctrl, id), size, data); if (ret < 0) return ret;
/* * v4l2_ext_control does not have enough room to fit a compound control. * Instead, the value is in the user memory at xctrl->ptr. The v4l2 * ioctl helper does not copy it for us.
*/ return copy_to_user(xctrl->ptr, data, size) ? -EFAULT : 0;
}
switch (mapping->v4l2_type) { case V4L2_CTRL_TYPE_INTEGER: if (!ctrl->cached) {
ret = uvc_ctrl_populate_cache(chain, ctrl); if (ret < 0) return ret;
}
min = uvc_mapping_get_s32(mapping, UVC_GET_MIN,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
max = uvc_mapping_get_s32(mapping, UVC_GET_MAX,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
step = uvc_mapping_get_s32(mapping, UVC_GET_RES,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); if (step == 0)
step = 1;
value = min + DIV_ROUND_CLOSEST((u32)(value - min), step) * step; if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED)
value = clamp(value, min, max); else
value = clamp_t(u32, value, min, max);
*value_in_out = value; return 0;
case V4L2_CTRL_TYPE_BITMASK: if (!ctrl->cached) {
ret = uvc_ctrl_populate_cache(chain, ctrl); if (ret < 0) return ret;
}
value &= uvc_get_ctrl_bitmap(ctrl, mapping);
*value_in_out = value; return 0;
case V4L2_CTRL_TYPE_BOOLEAN:
*value_in_out = clamp(value, 0, 1); return 0;
case V4L2_CTRL_TYPE_MENU: if (value < (ffs(mapping->menu_mask) - 1) ||
value > (fls(mapping->menu_mask) - 1)) return -ERANGE;
if (!test_bit(value, &mapping->menu_mask)) return -EINVAL;
/* * 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) { int val = uvc_mapping_get_menu_value(mapping, value); if (!ctrl->cached) {
ret = uvc_ctrl_populate_cache(chain, ctrl); if (ret < 0) return ret;
}
if (!(uvc_get_ctrl_bitmap(ctrl, mapping) & val)) return -EINVAL;
} return 0;
/* * v4l2_ext_control does not have enough room to fit a compound control. * Instead, the value is in the user memory at xctrl->ptr. The v4l2 * ioctl helper does not copy it for us.
*/
data = memdup_user(xctrl->ptr, size); if (IS_ERR(data)) return PTR_ERR(data);
if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0) return -EACCES;
ctrl = uvc_find_control(chain, xctrl->id, &mapping); if (!ctrl) return -EINVAL; if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) return -EACCES;
ret = uvc_ctrl_clamp(chain, ctrl, mapping, &xctrl->value); if (ret) return ret; /* * 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.
*/ if ((ctrl->info.size * 8) != mapping->size) {
ret = __uvc_ctrl_load_cur(chain, ctrl); if (ret < 0) return ret;
}
/* Backup the current value in case we need to rollback later. */ if (!ctrl->dirty) {
memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
ctrl->info.size);
}
ret = uvc_mapping_set_xctrl(ctrl, mapping, xctrl); if (ret) return ret;
/* * Retrieve flags for a given control
*/ staticint uvc_ctrl_get_flags(struct uvc_device *dev, conststruct uvc_control *ctrl, struct uvc_control_info *info)
{
u8 *data; int ret;
data = kmalloc(1, GFP_KERNEL); if (data == NULL) return -ENOMEM;
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);
ret = uvc_ctrl_get_flags(dev, ctrl, info); if (ret < 0) {
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_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);
ret = uvc_ctrl_fill_xu_info(dev, ctrl, &info); if (ret < 0) return ret;
ret = uvc_ctrl_add_info(dev, ctrl, &info); if (ret < 0)
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);
/* Find the extension unit. */
entity = NULL;
list_for_each_entry(iter, &chain->entities, chain) { if (UVC_ENTITY_TYPE(iter) == UVC_VC_EXTENSION_UNIT &&
iter->id == xqry->unit) {
entity = iter; break;
}
}
if (!entity) {
uvc_dbg(chain->dev, CONTROL, "Extension unit %u not found\n",
xqry->unit); return -ENOENT;
}
/* Find the control and perform delayed initialization if needed. */
found = false; for (i = 0; i < entity->ncontrols; ++i) {
ctrl = &entity->controls[i]; if (ctrl->index == xqry->selector - 1) {
found = true; break;
}
}
if (!found) {
uvc_dbg(chain->dev, CONTROL, "Control %pUl/%u not found\n",
entity->guid, xqry->selector); return -ENOENT;
}
if (mutex_lock_interruptible(&chain->ctrl_mutex)) return -ERESTARTSYS;
ret = uvc_ctrl_init_xu_ctrl(chain->dev, ctrl); if (ret < 0) {
ret = -ENOENT; goto done;
}
/* Validate the required buffer size and flags for the request */
reqflags = 0;
size = ctrl->info.size;
switch (xqry->query) { case UVC_GET_CUR:
reqflags = UVC_CTRL_FLAG_GET_CUR; break; case UVC_GET_MIN:
reqflags = UVC_CTRL_FLAG_GET_MIN; break; case UVC_GET_MAX:
reqflags = UVC_CTRL_FLAG_GET_MAX; break; case UVC_GET_DEF:
reqflags = UVC_CTRL_FLAG_GET_DEF; break; case UVC_GET_RES:
reqflags = UVC_CTRL_FLAG_GET_RES; break; case UVC_SET_CUR:
reqflags = UVC_CTRL_FLAG_SET_CUR; break; case UVC_GET_LEN:
size = 2; break; case UVC_GET_INFO:
size = 1; break; default:
ret = -EINVAL; goto done;
}
if (size != xqry->size) {
ret = -ENOBUFS; goto done;
}
if (reqflags && !(ctrl->info.flags & reqflags)) {
ret = -EBADRQC; goto done;
}
data = kmalloc(size, GFP_KERNEL); if (data == NULL) {
ret = -ENOMEM; goto done;
}
if (xqry->query == UVC_SET_CUR &&
copy_from_user(data, xqry->data, size)) {
ret = -EFAULT; goto done;
}
ret = uvc_query_ctrl(chain->dev, xqry->query, xqry->unit,
chain->dev->intfnum, xqry->selector, data, size); if (ret < 0) goto done;
if (xqry->query != UVC_SET_CUR &&
copy_to_user(xqry->data, data, size))
ret = -EFAULT;
done:
kfree(data);
mutex_unlock(&chain->ctrl_mutex); return ret;
}
/* * Restore control values after resume, skipping controls that haven't been * changed. * * TODO * - Don't restore modified controls that are back to their default value. * - Handle restore order (Auto-Exposure Mode should be restored before * Exposure Time).
*/ int uvc_ctrl_restore_values(struct uvc_device *dev)
{ struct uvc_control *ctrl; struct uvc_entity *entity; unsignedint i; int ret;
/* Walk the entities list and restore controls when possible. */
list_for_each_entry(entity, &dev->entities, list) {
for (i = 0; i < entity->ncontrols; ++i) {
ctrl = &entity->controls[i];
ret = uvc_ctrl_commit_entity(dev, NULL, entity, 0, NULL); if (ret < 0) return ret;
}
return 0;
}
/* -------------------------------------------------------------------------- * Control and mapping handling
*/
/* * Add control information to a given control.
*/ staticint uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl, conststruct uvc_control_info *info)
{
ctrl->info = *info;
INIT_LIST_HEAD(&ctrl->info.mappings);
/* Allocate an array to save control values (cur, def, max, etc.) */
ctrl->uvc_data = kzalloc(ctrl->info.size * UVC_CTRL_DATA_LAST + 1,
GFP_KERNEL); if (!ctrl->uvc_data) return -ENOMEM;
ctrl->initialized = 1;
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;
}
/* * Add a control mapping to a given control.
*/ staticint __uvc_ctrl_add_mapping(struct uvc_video_chain *chain, struct uvc_control *ctrl, conststruct uvc_control_mapping *mapping)
{ struct uvc_control_mapping *map; unsignedint size; unsignedint i; int ret;
/* * 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.
*/
map = kmemdup(mapping, sizeof(*mapping), GFP_KERNEL); if (!map) return -ENOMEM;
/* For UVCIOC_CTRL_MAP custom control */ if (mapping->name) {
map->name = kstrdup(mapping->name, GFP_KERNEL); if (!map->name) goto err_nomem;
}
INIT_LIST_HEAD(&map->ev_subs);
if (mapping->menu_mapping && mapping->menu_mask) {
size = sizeof(mapping->menu_mapping[0])
* fls(mapping->menu_mask);
map->menu_mapping = kmemdup(mapping->menu_mapping, size,
GFP_KERNEL); if (!map->menu_mapping) goto err_nomem;
} if (mapping->menu_names && mapping->menu_mask) {
size = sizeof(mapping->menu_names[0])
* fls(mapping->menu_mask);
map->menu_names = kmemdup(mapping->menu_names, size,
GFP_KERNEL); if (!map->menu_names) goto err_nomem;
}
if (uvc_ctrl_mapping_is_compound(map)) if (WARN_ON(!map->set || !map->get)) {
ret = -EIO; goto free_mem;
}
if (map->get == NULL)
map->get = uvc_get_le_value; if (map->set == NULL)
map->set = uvc_set_le_value;
for (i = 0; i < ARRAY_SIZE(uvc_control_classes); i++) { if (V4L2_CTRL_ID2WHICH(uvc_control_classes[i]) ==
V4L2_CTRL_ID2WHICH(map->id)) {
chain->ctrl_class_bitmap |= BIT(i); break;
}
}
list_add_tail(&map->list, &ctrl->info.mappings);
uvc_dbg(chain->dev, CONTROL, "Adding mapping '%s' to control %pUl/%u\n",
uvc_map_get_name(map), ctrl->info.entity,
ctrl->info.selector);
/* * Prune an entity of its bogus controls using a blacklist. Bogus controls * are currently the ones that crash the camera or unconditionally return an * error when queried.
*/ staticvoid uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity)
{ struct uvc_ctrl_blacklist { struct usb_device_id id;
u8 index;
};
for (i = 0; i < count; ++i) { if (!usb_match_one_id(dev->intf, &blacklist[i].id)) continue;
if (blacklist[i].index >= 8 * size ||
!uvc_test_bit(controls, blacklist[i].index)) continue;
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);
}
}
/* * Add control information and hardcoded stock control mappings to the given * device.
*/ staticvoid uvc_ctrl_init_ctrl(struct uvc_video_chain *chain, struct uvc_control *ctrl)
{ unsignedint i;
/* * 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.
*/ if (UVC_ENTITY_TYPE(ctrl->entity) == UVC_VC_EXTENSION_UNIT) return;
for (i = 0; i < ARRAY_SIZE(uvc_ctrls); ++i) { conststruct uvc_control_info *info = &uvc_ctrls[i];
if (uvc_entity_match_guid(ctrl->entity, info->entity) &&
ctrl->index == info->index) {
uvc_ctrl_add_info(chain->dev, ctrl, info); /* * Retrieve control flags from the device. Ignore errors * and work with default flag values from the uvc_ctrl * array when the device doesn't properly implement * GET_INFO on standard controls.
*/
uvc_ctrl_get_flags(chain->dev, ctrl, &ctrl->info); break;
}
}
if (!ctrl->initialized) return;
/* Process common mappings. */ for (i = 0; i < ARRAY_SIZE(uvc_ctrl_mappings); ++i) { conststruct uvc_control_mapping *mapping = &uvc_ctrl_mappings[i];
if (!uvc_entity_match_guid(ctrl->entity, mapping->entity) ||
ctrl->info.selector != mapping->selector) continue;
/* Let the device provide a custom mapping. */ if (mapping->filter_mapping) {
mapping = mapping->filter_mapping(chain, ctrl); if (!mapping) continue;
}
/* Can be uninitialized if we are aborting on probe error. */ if (dev->async_ctrl.work.func)
cancel_work_sync(&dev->async_ctrl.work);
/* Free controls and control mappings for all entities. */
list_for_each_entry(entity, &dev->entities, list) { for (i = 0; i < entity->ncontrols; ++i) { struct uvc_control *ctrl = &entity->controls[i];
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.