extractedLnx/linux-2.6.28/drivers/media/video/uvc/uvc_v4l2.c___uvc_v4l2_do_ioctl.c
static int __uvc_v4l2_do_ioctl(struct file *file,
unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
struct uvc_video_device *video = video_get_drvdata(vdev);
struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
int ret = 0;
if (uvc_trace_param & UVC_TRACE_IOCTL)
v4l_printk_ioctl(cmd);
switch (cmd) {
/* Query capabilities */
case VIDIOC_QUERYCAP:
{
struct v4l2_capability *cap = arg;
memset(cap, 0, sizeof *cap);
strncpy(cap->driver, "uvcvideo", sizeof cap->driver);
strncpy(cap->card, vdev->name, 32);
strncpy(cap->bus_info, video->dev->udev->bus->bus_name,
sizeof cap->bus_info);
cap->version = DRIVER_VERSION_NUMBER;
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
| V4L2_CAP_STREAMING;
break;
}
/* Get, Set & Query control */
case VIDIOC_QUERYCTRL:
return uvc_query_v4l2_ctrl(video, arg);
case VIDIOC_G_CTRL:
{
struct v4l2_control *ctrl = arg;
struct v4l2_ext_control xctrl;
memset(&xctrl, 0, sizeof xctrl);
xctrl.id = ctrl->id;
uvc_ctrl_begin(video);
ret = uvc_ctrl_get(video, &xctrl);
uvc_ctrl_rollback(video);
if (ret >= 0)
ctrl->value = xctrl.value;
break;
}
case VIDIOC_S_CTRL:
{
struct v4l2_control *ctrl = arg;
struct v4l2_ext_control xctrl;
memset(&xctrl, 0, sizeof xctrl);
xctrl.id = ctrl->id;
xctrl.value = ctrl->value;
uvc_ctrl_begin(video);
ret = uvc_ctrl_set(video, &xctrl);
if (ret < 0) {
uvc_ctrl_rollback(video);
return ret;
}
ret = uvc_ctrl_commit(video);
break;
}
case VIDIOC_QUERYMENU:
return uvc_v4l2_query_menu(video, arg);
case VIDIOC_G_EXT_CTRLS:
{
struct v4l2_ext_controls *ctrls = arg;
struct v4l2_ext_control *ctrl = ctrls->controls;
unsigned int i;
uvc_ctrl_begin(video);
for (i = 0; i < ctrls->count; ++ctrl, ++i) {
ret = uvc_ctrl_get(video, ctrl);
if (ret < 0) {
uvc_ctrl_rollback(video);
ctrls->error_idx = i;
return ret;
}
}
ctrls->error_idx = 0;
ret = uvc_ctrl_rollback(video);
break;
}
case VIDIOC_S_EXT_CTRLS:
case VIDIOC_TRY_EXT_CTRLS:
{
struct v4l2_ext_controls *ctrls = arg;
struct v4l2_ext_control *ctrl = ctrls->controls;
unsigned int i;
ret = uvc_ctrl_begin(video);
if (ret < 0)
return ret;
for (i = 0; i < ctrls->count; ++ctrl, ++i) {
ret = uvc_ctrl_set(video, ctrl);
if (ret < 0) {
uvc_ctrl_rollback(video);
ctrls->error_idx = i;
return ret;
}
}
ctrls->error_idx = 0;
if (cmd == VIDIOC_S_EXT_CTRLS)
ret = uvc_ctrl_commit(video);
else
ret = uvc_ctrl_rollback(video);
break;
}
/* Get, Set & Enum input */
case VIDIOC_ENUMINPUT:
{
const struct uvc_entity *selector = video->selector;
struct v4l2_input *input = arg;
struct uvc_entity *iterm = NULL;
u32 index = input->index;
int pin = 0;
if (selector == NULL ||
(video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
if (index != 0)
return -EINVAL;
iterm = list_first_entry(&video->iterms,
struct uvc_entity, chain);
pin = iterm->id;
} else if (pin < selector->selector.bNrInPins) {
pin = selector->selector.baSourceID[index];
list_for_each_entry(iterm, video->iterms.next, chain) {
if (iterm->id == pin)
break;
}
}
if (iterm == NULL || iterm->id != pin)
return -EINVAL;
memset(input, 0, sizeof *input);
input->index = index;
strncpy(input->name, iterm->name, sizeof input->name);
if (UVC_ENTITY_TYPE(iterm) == ITT_CAMERA)
input->type = V4L2_INPUT_TYPE_CAMERA;
break;
}
case VIDIOC_G_INPUT:
{
u8 input;
if (video->selector == NULL ||
(video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
*(int *)arg = 0;
break;
}
ret = uvc_query_ctrl(video->dev, GET_CUR, video->selector->id,
video->dev->intfnum, SU_INPUT_SELECT_CONTROL,
&input, 1);
if (ret < 0)
return ret;
*(int *)arg = input - 1;
break;
}
case VIDIOC_S_INPUT:
{
u8 input = *(u32 *)arg + 1;
if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret;
if (video->selector == NULL ||
(video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
if (input != 1)
return -EINVAL;
break;
}
if (input > video->selector->selector.bNrInPins)
return -EINVAL;
return uvc_query_ctrl(video->dev, SET_CUR, video->selector->id,
video->dev->intfnum, SU_INPUT_SELECT_CONTROL,
&input, 1);
}
/* Try, Get, Set & Enum format */
case VIDIOC_ENUM_FMT:
{
struct v4l2_fmtdesc *fmt = arg;
struct uvc_format *format;
if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
fmt->index >= video->streaming->nformats)
return -EINVAL;
format = &video->streaming->format[fmt->index];
fmt->flags = 0;
if (format->flags & UVC_FMT_FLAG_COMPRESSED)
fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
strncpy(fmt->description, format->name,
sizeof fmt->description);
fmt->description[sizeof fmt->description - 1] = 0;
fmt->pixelformat = format->fcc;
break;
}
case VIDIOC_TRY_FMT:
{
struct uvc_streaming_control probe;
if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret;
return uvc_v4l2_try_format(video, arg, &probe, NULL, NULL);
}
case VIDIOC_S_FMT:
if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret;
return uvc_v4l2_set_format(video, arg);
case VIDIOC_G_FMT:
return uvc_v4l2_get_format(video, arg);
/* Frame size enumeration */
case VIDIOC_ENUM_FRAMESIZES:
{
struct v4l2_frmsizeenum *fsize = arg;
struct uvc_format *format = NULL;
struct uvc_frame *frame;
int i;
/* Look for the given pixel format */
for (i = 0; i < video->streaming->nformats; i++) {
if (video->streaming->format[i].fcc ==
fsize->pixel_format) {
format = &video->streaming->format[i];
break;
}
}
if (format == NULL)
return -EINVAL;
if (fsize->index >= format->nframes)
return -EINVAL;
frame = &format->frame[fsize->index];
fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
fsize->discrete.width = frame->wWidth;
fsize->discrete.height = frame->wHeight;
break;
}
/* Frame interval enumeration */
case VIDIOC_ENUM_FRAMEINTERVALS:
{
struct v4l2_frmivalenum *fival = arg;
struct uvc_format *format = NULL;
struct uvc_frame *frame = NULL;
int i;
/* Look for the given pixel format and frame size */
for (i = 0; i < video->streaming->nformats; i++) {
if (video->streaming->format[i].fcc ==
fival->pixel_format) {
format = &video->streaming->format[i];
break;
}
}
if (format == NULL)
return -EINVAL;
for (i = 0; i < format->nframes; i++) {
if (format->frame[i].wWidth == fival->width &&
format->frame[i].wHeight == fival->height) {
frame = &format->frame[i];
break;
}
}
if (frame == NULL)
return -EINVAL;
if (frame->bFrameIntervalType) {
if (fival->index >= frame->bFrameIntervalType)
return -EINVAL;
fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
fival->discrete.numerator =
frame->dwFrameInterval[fival->index];
fival->discrete.denominator = 10000000;
uvc_simplify_fraction(&fival->discrete.numerator,
&fival->discrete.denominator, 8, 333);
} else {
fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
fival->stepwise.min.numerator =
frame->dwFrameInterval[0];
fival->stepwise.min.denominator = 10000000;
fival->stepwise.max.numerator =
frame->dwFrameInterval[1];
fival->stepwise.max.denominator = 10000000;
fival->stepwise.step.numerator =
frame->dwFrameInterval[2];
fival->stepwise.step.denominator = 10000000;
uvc_simplify_fraction(&fival->stepwise.min.numerator,
&fival->stepwise.min.denominator, 8, 333);
uvc_simplify_fraction(&fival->stepwise.max.numerator,
&fival->stepwise.max.denominator, 8, 333);
uvc_simplify_fraction(&fival->stepwise.step.numerator,
&fival->stepwise.step.denominator, 8, 333);
}
break;
}
/* Get & Set streaming parameters */
case VIDIOC_G_PARM:
return uvc_v4l2_get_streamparm(video, arg);
case VIDIOC_S_PARM:
if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret;
return uvc_v4l2_set_streamparm(video, arg);
/* Cropping and scaling */
case VIDIOC_CROPCAP:
{
struct v4l2_cropcap *ccap = arg;
struct uvc_frame *frame = video->streaming->cur_frame;
if (ccap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
ccap->bounds.left = 0;
ccap->bounds.top = 0;
ccap->bounds.width = frame->wWidth;
ccap->bounds.height = frame->wHeight;
ccap->defrect = ccap->bounds;
ccap->pixelaspect.numerator = 1;
ccap->pixelaspect.denominator = 1;
break;
}
case VIDIOC_G_CROP:
case VIDIOC_S_CROP:
return -EINVAL;
/* Buffers & streaming */
case VIDIOC_REQBUFS:
{
struct v4l2_requestbuffers *rb = arg;
unsigned int bufsize =
video->streaming->ctrl.dwMaxVideoFrameSize;
if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
rb->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret;
ret = uvc_alloc_buffers(&video->queue, rb->count, bufsize);
if (ret < 0)
return ret;
rb->count = ret;
ret = 0;
break;
}
case VIDIOC_QUERYBUF:
{
struct v4l2_buffer *buf = arg;
if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (!uvc_has_privileges(handle))
return -EBUSY;
return uvc_query_buffer(&video->queue, buf);
}
case VIDIOC_QBUF:
if (!uvc_has_privileges(handle))
return -EBUSY;
return uvc_queue_buffer(&video->queue, arg);
case VIDIOC_DQBUF:
if (!uvc_has_privileges(handle))
return -EBUSY;
return uvc_dequeue_buffer(&video->queue, arg,
file->f_flags & O_NONBLOCK);
case VIDIOC_STREAMON:
{
int *type = arg;
if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (!uvc_has_privileges(handle))
return -EBUSY;
if ((ret = uvc_video_enable(video, 1)) < 0)
return ret;
break;
}
case VIDIOC_STREAMOFF:
{
int *type = arg;
if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (!uvc_has_privileges(handle))
return -EBUSY;
return uvc_video_enable(video, 0);
}
/* Analog video standards make no sense for digital cameras. */
case VIDIOC_ENUMSTD:
case VIDIOC_QUERYSTD:
case VIDIOC_G_STD:
case VIDIOC_S_STD:
case VIDIOC_OVERLAY:
case VIDIOC_ENUMAUDIO:
case VIDIOC_ENUMAUDOUT:
case VIDIOC_ENUMOUTPUT:
uvc_trace(UVC_TRACE_IOCTL, "Unsupported ioctl 0x%08x\n", cmd);
return -EINVAL;
/* Dynamic controls. */
case UVCIOC_CTRL_ADD:
{
struct uvc_xu_control_info *xinfo = arg;
struct uvc_control_info *info;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
info = kmalloc(sizeof *info, GFP_KERNEL);
if (info == NULL)
return -ENOMEM;
memcpy(info->entity, xinfo->entity, sizeof info->entity);
info->index = xinfo->index;
info->selector = xinfo->selector;
info->size = xinfo->size;
info->flags = xinfo->flags;
info->flags |= UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF;
ret = uvc_ctrl_add_info(info);
if (ret < 0)
kfree(info);
break;
}
case UVCIOC_CTRL_MAP:
{
struct uvc_xu_control_mapping *xmap = arg;
struct uvc_control_mapping *map;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
map = kmalloc(sizeof *map, GFP_KERNEL);
if (map == NULL)
return -ENOMEM;
map->id = xmap->id;
memcpy(map->name, xmap->name, sizeof map->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;
ret = uvc_ctrl_add_mapping(map);
if (ret < 0)
kfree(map);
break;
}
case UVCIOC_CTRL_GET:
return uvc_xu_ctrl_query(video, arg, 0);
case UVCIOC_CTRL_SET:
return uvc_xu_ctrl_query(video, arg, 1);
default:
if ((ret = v4l_compat_translate_ioctl(file, cmd, arg,
__uvc_v4l2_do_ioctl)) == -ENOIOCTLCMD)
uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n",
cmd);
return ret;
}
return ret;
}
Generated by GNU enscript 1.6.4.