size = xmap->menu_count * sizeof(*map->menu_mapping);
map->menu_mapping = kzalloc(size, GFP_KERNEL); if (!map->menu_mapping) {
ret = -ENOMEM; goto done;
}
for (i = 0; i < xmap->menu_count ; i++) { if (copy_from_user((u32 *)&map->menu_mapping[i],
&xmap->menu_info[i].value, sizeof(map->menu_mapping[i]))) {
ret = -EACCES; goto done;
}
}
/* * Always use the standard naming if available, otherwise copy the * names supplied by userspace.
*/ if (!v4l2_ctrl_get_menu(map->id)) {
size = xmap->menu_count * sizeof(map->menu_names[0]);
map->menu_names = kzalloc(size, GFP_KERNEL); if (!map->menu_names) {
ret = -ENOMEM; goto done;
}
for (i = 0; i < xmap->menu_count ; i++) { /* sizeof(names[i]) - 1: to take care of \0 */ if (copy_from_user((char *)map->menu_names[i],
xmap->menu_info[i].name, sizeof(map->menu_names[i]) - 1)) {
ret = -EACCES; goto done;
}
}
}
if (xmap->data_type > UVC_CTRL_DATA_TYPE_BITMASK) {
uvc_dbg(chain->dev, CONTROL, "Unsupported UVC data type %u\n", xmap->data_type); return -EINVAL;
}
map = kzalloc(sizeof(*map), GFP_KERNEL); if (map == NULL) return -ENOMEM;
map->id = xmap->id; /* Non standard control id. */ if (v4l2_ctrl_get_name(map->id) == NULL) { if (xmap->name[0] == '\0') {
ret = -EINVAL; goto free_map;
}
xmap->name[sizeof(xmap->name) - 1] = '\0';
map->name = xmap->name;
}
memcpy(map->entity, xmap->entity, sizeof(map->entity));
map->selector = xmap->selector;
map->size = xmap->size;
map->offset = xmap->offset;
map->v4l2_type = xmap->v4l2_type;
map->data_type = xmap->data_type;
switch (xmap->v4l2_type) { case V4L2_CTRL_TYPE_INTEGER: case V4L2_CTRL_TYPE_BOOLEAN: case V4L2_CTRL_TYPE_BUTTON:
ret = uvc_ctrl_add_mapping(chain, map); break;
case V4L2_CTRL_TYPE_MENU:
ret = uvc_control_add_xu_mapping(chain, map, xmap); break;
default:
uvc_dbg(chain->dev, CONTROL, "Unsupported V4L2 control type %u\n", xmap->v4l2_type);
ret = -ENOTTY; break;
}
/* * Find the frame interval closest to the requested frame interval for the * given frame format and size. This should be done by the device as part of * the Video Probe and Commit negotiation, but some hardware don't implement * that feature.
*/ static u32 uvc_try_frame_interval(conststruct uvc_frame *frame, u32 interval)
{ unsignedint i;
if (frame->bFrameIntervalType) {
u32 best = -1, dist;
for (i = 0; i < frame->bFrameIntervalType; ++i) {
dist = interval > frame->dwFrameInterval[i]
? interval - frame->dwFrameInterval[i]
: frame->dwFrameInterval[i] - interval;
fcc = (u8 *)&fmt->fmt.pix.pixelformat;
uvc_dbg(stream->dev, FORMAT, "Trying format 0x%08x (%c%c%c%c): %ux%u\n",
fmt->fmt.pix.pixelformat,
fcc[0], fcc[1], fcc[2], fcc[3],
fmt->fmt.pix.width, fmt->fmt.pix.height);
/* * Check if the hardware supports the requested format, use the default * format otherwise.
*/ for (i = 0; i < stream->nformats; ++i) {
format = &stream->formats[i]; if (format->fcc == fmt->fmt.pix.pixelformat) break;
}
if (i == stream->nformats) {
format = stream->def_format;
fmt->fmt.pix.pixelformat = format->fcc;
}
/* * Find the closest image size. The distance between image sizes is * the size in pixels of the non-overlapping regions between the * requested size and the frame-specified size.
*/
rw = fmt->fmt.pix.width;
rh = fmt->fmt.pix.height;
maxd = (unsignedint)-1;
for (i = 0; i < format->nframes; ++i) {
u16 w = format->frames[i].wWidth;
u16 h = format->frames[i].wHeight;
d = min(w, rw) * min(h, rh);
d = w*h + rw*rh - 2*d; if (d < maxd) {
maxd = d;
frame = &format->frames[i];
}
if (maxd == 0) break;
}
if (frame == NULL) {
uvc_dbg(stream->dev, FORMAT, "Unsupported size %ux%u\n",
fmt->fmt.pix.width, fmt->fmt.pix.height); return -EINVAL;
}
/* Use the default frame interval. */
interval = frame->dwDefaultFrameInterval;
uvc_dbg(stream->dev, FORMAT, "Using default frame interval %u.%u us (%u.%u fps)\n",
interval / 10, interval % 10, 10000000 / interval,
(100000000 / interval) % 10);
/* Set the format index, frame index and frame interval. */
memset(probe, 0, sizeof(*probe));
probe->bmHint = 1; /* dwFrameInterval */
probe->bFormatIndex = format->index;
probe->bFrameIndex = frame->bFrameIndex;
probe->dwFrameInterval = uvc_try_frame_interval(frame, interval); /* * Some webcams stall the probe control set request when the * dwMaxVideoFrameSize field is set to zero. The UVC specification * clearly states that the field is read-only from the host, so this * is a webcam bug. Set dwMaxVideoFrameSize to the value reported by * the webcam to work around the problem. * * The workaround could probably be enabled for all webcams, so the * quirk can be removed if needed. It's currently useful to detect * webcam bugs and fix them before they hit the market (providing * developers test their webcams with the Linux driver as well as with * the Windows driver).
*/
mutex_lock(&stream->mutex); if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
probe->dwMaxVideoFrameSize =
stream->ctrl.dwMaxVideoFrameSize;
/* Probe the device. */
ret = uvc_probe_video(stream, probe);
mutex_unlock(&stream->mutex); if (ret < 0) return ret;
/* * After the probe, update fmt with the values returned from * negotiation with the device. Some devices return invalid bFormatIndex * and bFrameIndex values, in which case we can only assume they have * accepted the requested format as-is.
*/ for (i = 0; i < stream->nformats; ++i) { if (probe->bFormatIndex == stream->formats[i].index) {
format = &stream->formats[i]; break;
}
}
if (i == stream->nformats)
uvc_dbg(stream->dev, FORMAT, "Unknown bFormatIndex %u, using default\n",
probe->bFormatIndex);
for (i = 0; i < format->nframes; ++i) { if (probe->bFrameIndex == format->frames[i].bFrameIndex) {
frame = &format->frames[i]; break;
}
}
if (i == format->nframes)
uvc_dbg(stream->dev, FORMAT, "Unknown bFrameIndex %u, using default\n",
probe->bFrameIndex);
switch (ctrls->which) { case V4L2_CTRL_WHICH_DEF_VAL: case V4L2_CTRL_WHICH_CUR_VAL: case V4L2_CTRL_WHICH_MAX_VAL: case V4L2_CTRL_WHICH_MIN_VAL:
which = ctrls->which; break; default:
which = V4L2_CTRL_WHICH_CUR_VAL;
}
ret = uvc_ctrl_check_access(chain, ctrls, VIDIOC_G_EXT_CTRLS); if (ret < 0) return ret;
ret = uvc_ctrl_begin(chain); if (ret < 0) return ret;
for (i = 0; i < ctrls->count; ++ctrl, ++i) {
ret = uvc_ctrl_get(chain, which, ctrl); if (ret < 0) {
uvc_ctrl_rollback(handle);
ctrls->error_idx = i; return ret;
}
}
switch (sel->target) { case V4L2_SEL_TGT_CROP_DEFAULT: case V4L2_SEL_TGT_CROP_BOUNDS: if (stream->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; break; case V4L2_SEL_TGT_COMPOSE_DEFAULT: case V4L2_SEL_TGT_COMPOSE_BOUNDS: if (stream->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) return -EINVAL; break; default: return -EINVAL;
}
/* Look for the given pixel format */ for (i = 0; i < stream->nformats; i++) { if (stream->formats[i].fcc == fsize->pixel_format) {
format = &stream->formats[i]; break;
}
} if (format == NULL) return -EINVAL;
/* Skip duplicate frame sizes */ for (i = 0, index = 0; i < format->nframes; i++) { if (frame && frame->wWidth == format->frames[i].wWidth &&
frame->wHeight == format->frames[i].wHeight) continue;
frame = &format->frames[i]; if (index == fsize->index) break;
index++;
}
/* Look for the given pixel format and frame size */ for (i = 0; i < stream->nformats; i++) { if (stream->formats[i].fcc == fival->pixel_format) {
format = &stream->formats[i]; break;
}
} if (format == NULL) return -EINVAL;
index = fival->index; for (i = 0; i < format->nframes; i++) { if (format->frames[i].wWidth == fival->width &&
format->frames[i].wHeight == fival->height) {
frame = &format->frames[i];
nintervals = frame->bFrameIntervalType ?: 1; if (index < nintervals) break;
index -= nintervals;
}
} if (i == format->nframes) return -EINVAL;
ret = uvc_pm_get(handle->stream->dev); if (ret) return ret;
switch (cmd) { case UVCIOC_CTRL_MAP32:
ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up); if (ret) break;
ret = uvc_ioctl_xu_ctrl_map(handle->chain, &karg.xmap); if (ret) break;
ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up); if (ret) break; break;
case UVCIOC_CTRL_QUERY32:
ret = uvc_v4l2_get_xu_query(&karg.xqry, up); if (ret) break;
ret = uvc_xu_ctrl_query(handle->chain, &karg.xqry); if (ret) break;
ret = uvc_v4l2_put_xu_query(&karg.xqry, up); if (ret) break; break;
/* The following IOCTLs need to turn on the camera. */ switch (converted_cmd) { case UVCIOC_CTRL_MAP: case UVCIOC_CTRL_QUERY: case VIDIOC_G_CTRL: case VIDIOC_G_EXT_CTRLS: case VIDIOC_G_INPUT: case VIDIOC_QUERYCTRL: case VIDIOC_QUERYMENU: case VIDIOC_QUERY_EXT_CTRL: case VIDIOC_S_CTRL: case VIDIOC_S_EXT_CTRLS: case VIDIOC_S_FMT: case VIDIOC_S_INPUT: case VIDIOC_S_PARM: case VIDIOC_TRY_EXT_CTRLS: case VIDIOC_TRY_FMT:
ret = uvc_pm_get(handle->stream->dev); if (ret) return ret;
ret = video_ioctl2(file, cmd, arg);
uvc_pm_put(handle->stream->dev); return ret;
}
/* The other IOCTLs can run with the camera off. */ return video_ioctl2(file, cmd, arg);
}
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.