/* * 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);
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.