static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *vdev = video_devdata(file); struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); struct v4l2_fh *vfh = file->private_data; #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); int rval; #endif switch (cmd) { case VIDIOC_QUERYCTRL: return v4l2_queryctrl(vfh->ctrl_handler, arg); case VIDIOC_QUERY_EXT_CTRL: return v4l2_query_ext_ctrl(vfh->ctrl_handler, arg); case VIDIOC_QUERYMENU: return v4l2_querymenu(vfh->ctrl_handler, arg); case VIDIOC_G_CTRL: return v4l2_g_ctrl(vfh->ctrl_handler, arg); case VIDIOC_S_CTRL: return v4l2_s_ctrl(vfh, vfh->ctrl_handler, arg); case VIDIOC_G_EXT_CTRLS: return v4l2_g_ext_ctrls(vfh->ctrl_handler, arg); case VIDIOC_S_EXT_CTRLS: return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, arg); case VIDIOC_TRY_EXT_CTRLS: return v4l2_try_ext_ctrls(vfh->ctrl_handler, arg); case VIDIOC_DQEVENT: if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) return -ENOIOCTLCMD; return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); case VIDIOC_SUBSCRIBE_EVENT: return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); case VIDIOC_UNSUBSCRIBE_EVENT: return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); #ifdef CONFIG_VIDEO_ADV_DEBUG case VIDIOC_DBG_G_REGISTER: { struct v4l2_dbg_register *p = arg; if (!capable(CAP_SYS_ADMIN)) return -EPERM; return v4l2_subdev_call(sd, core, g_register, p); } case VIDIOC_DBG_S_REGISTER: { struct v4l2_dbg_register *p = arg; if (!capable(CAP_SYS_ADMIN)) return -EPERM; return v4l2_subdev_call(sd, core, s_register, p); } #endif case VIDIOC_LOG_STATUS: { int ret; pr_info("%s: ================= START STATUS =================\n", sd->name); ret = v4l2_subdev_call(sd, core, log_status); pr_info("%s: ================== END STATUS ==================\n", sd->name); return ret; } #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) case VIDIOC_SUBDEV_G_FMT: { struct v4l2_subdev_format *format = arg; rval = check_format(sd, format); if (rval) return rval; return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->pad, format); } case VIDIOC_SUBDEV_S_FMT: { struct v4l2_subdev_format *format = arg; rval = check_format(sd, format); if (rval) return rval; return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format); } case VIDIOC_SUBDEV_G_CROP: { struct v4l2_subdev_crop *crop = arg; struct v4l2_subdev_selection sel; rval = check_crop(sd, crop); if (rval) return rval; memset(&sel, 0, sizeof(sel)); sel.which = crop->which; sel.pad = crop->pad; sel.target = V4L2_SEL_TGT_CROP; rval = v4l2_subdev_call( sd, pad, get_selection, subdev_fh->pad, &sel); crop->rect = sel.r; return rval; } case VIDIOC_SUBDEV_S_CROP: { struct v4l2_subdev_crop *crop = arg; struct v4l2_subdev_selection sel; rval = check_crop(sd, crop); if (rval) return rval; memset(&sel, 0, sizeof(sel)); sel.which = crop->which; sel.pad = crop->pad; sel.target = V4L2_SEL_TGT_CROP; sel.r = crop->rect; rval = v4l2_subdev_call( sd, pad, set_selection, subdev_fh->pad, &sel); crop->rect = sel.r; return rval; } case VIDIOC_SUBDEV_ENUM_MBUS_CODE: { struct v4l2_subdev_mbus_code_enum *code = arg; if (code->which != V4L2_SUBDEV_FORMAT_TRY && code->which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; if (code->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->pad, code); } case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: { struct v4l2_subdev_frame_size_enum *fse = arg; if (fse->which != V4L2_SUBDEV_FORMAT_TRY && fse->which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; if (fse->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->pad, fse); } case VIDIOC_SUBDEV_G_FRAME_INTERVAL: { struct v4l2_subdev_frame_interval *fi = arg; if (fi->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call(sd, video, g_frame_interval, arg); } case VIDIOC_SUBDEV_S_FRAME_INTERVAL: { struct v4l2_subdev_frame_interval *fi = arg; if (fi->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call(sd, video, s_frame_interval, arg); } case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: { struct v4l2_subdev_frame_interval_enum *fie = arg; if (fie->which != V4L2_SUBDEV_FORMAT_TRY && fie->which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; if (fie->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->pad, fie); } case VIDIOC_SUBDEV_G_SELECTION: { struct v4l2_subdev_selection *sel = arg; rval = check_selection(sd, sel); if (rval) return rval; return v4l2_subdev_call( sd, pad, get_selection, subdev_fh->pad, sel); } case VIDIOC_SUBDEV_S_SELECTION: { struct v4l2_subdev_selection *sel = arg; rval = check_selection(sd, sel); if (rval) return rval; return v4l2_subdev_call( sd, pad, set_selection, subdev_fh->pad, sel); } case VIDIOC_G_EDID: { struct v4l2_subdev_edid *edid = arg; rval = check_edid(sd, edid); if (rval) return rval; return v4l2_subdev_call(sd, pad, get_edid, edid); } case VIDIOC_S_EDID: { struct v4l2_subdev_edid *edid = arg; rval = check_edid(sd, edid); if (rval) return rval; return v4l2_subdev_call(sd, pad, set_edid, edid); } case VIDIOC_SUBDEV_DV_TIMINGS_CAP: { struct v4l2_dv_timings_cap *cap = arg; if (cap->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call(sd, pad, dv_timings_cap, cap); } case VIDIOC_SUBDEV_ENUM_DV_TIMINGS: { struct v4l2_enum_dv_timings *dvt = arg; if (dvt->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call(sd, pad, enum_dv_timings, dvt); } case VIDIOC_SUBDEV_QUERY_DV_TIMINGS: return v4l2_subdev_call(sd, video, query_dv_timings, arg); case VIDIOC_SUBDEV_G_DV_TIMINGS: return v4l2_subdev_call(sd, video, g_dv_timings, arg); case VIDIOC_SUBDEV_S_DV_TIMINGS: return v4l2_subdev_call(sd, video, s_dv_timings, arg); case VIDIOC_SUBDEV_G_ROUTING: return v4l2_subdev_call(sd, pad, get_routing, arg); case VIDIOC_SUBDEV_S_ROUTING: { struct v4l2_subdev_routing *route = arg; unsigned int i; if (route->num_routes > sd->entity.num_pads) return -EINVAL; for (i = 0; i < route->num_routes; ++i) { unsigned int sink = route->routes[i].sink; unsigned int source = route->routes[i].source; struct media_pad *pads = sd->entity.pads; if (sink >= sd->entity.num_pads || source >= sd->entity.num_pads) return -EINVAL; if (!(pads[sink].flags & MEDIA_PAD_FL_SINK) || !(pads[source].flags & MEDIA_PAD_FL_SOURCE)) return -EINVAL; } return v4l2_subdev_call(sd, pad, set_routing, route); } #endif default: return v4l2_subdev_call(sd, core, ioctl, cmd, arg); } return 0; }
static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *vdev = video_devdata(file); struct uvc_device *uvc = video_get_drvdata(vdev); struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data); struct usb_composite_dev *cdev = uvc->func.config->cdev; struct uvc_video *video = &uvc->video; int ret = 0; switch (cmd) { /* Query capabilities */ case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; memset(cap, 0, sizeof *cap); strncpy(cap->driver, "g_uvc", sizeof(cap->driver)); strncpy(cap->card, cdev->gadget->name, sizeof(cap->card)); strncpy(cap->bus_info, dev_name(&cdev->gadget->dev), sizeof cap->bus_info); cap->version = DRIVER_VERSION_NUMBER; cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; break; } /* Get & Set format */ case VIDIOC_G_FMT: { struct v4l2_format *fmt = arg; if (fmt->type != video->queue.type) return -EINVAL; return uvc_v4l2_get_format(video, fmt); } case VIDIOC_S_FMT: { struct v4l2_format *fmt = arg; if (fmt->type != video->queue.type) return -EINVAL; return uvc_v4l2_set_format(video, fmt); } /* Buffers & streaming */ case VIDIOC_REQBUFS: { struct v4l2_requestbuffers *rb = arg; if (rb->type != video->queue.type || rb->memory != V4L2_MEMORY_MMAP) return -EINVAL; ret = uvc_alloc_buffers(&video->queue, rb->count, video->imagesize); if (ret < 0) return ret; rb->count = ret; ret = 0; break; } case VIDIOC_QUERYBUF: { struct v4l2_buffer *buf = arg; if (buf->type != video->queue.type) return -EINVAL; return uvc_query_buffer(&video->queue, buf); } case VIDIOC_QBUF: if ((ret = uvc_queue_buffer(&video->queue, arg)) < 0) return ret; return uvc_video_pump(video); case VIDIOC_DQBUF: return uvc_dequeue_buffer(&video->queue, arg, file->f_flags & O_NONBLOCK); case VIDIOC_STREAMON: { int *type = arg; if (*type != video->queue.type) return -EINVAL; return uvc_video_enable(video, 1); } case VIDIOC_STREAMOFF: { int *type = arg; if (*type != video->queue.type) return -EINVAL; return uvc_video_enable(video, 0); } /* Events */ case VIDIOC_DQEVENT: { struct v4l2_event *event = arg; ret = v4l2_event_dequeue(&handle->vfh, event, file->f_flags & O_NONBLOCK); if (ret == 0 && event->type == UVC_EVENT_SETUP) { struct uvc_event *uvc_event = (void *)&event->u.data; /* Tell the complete callback to generate an event for * the next request that will be enqueued by * uvc_event_write. */ uvc->event_setup_out = !(uvc_event->req.bRequestType & USB_DIR_IN); uvc->event_length = uvc_event->req.wLength; } return ret; } case VIDIOC_SUBSCRIBE_EVENT: { struct v4l2_event_subscription *sub = arg; if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST) return -EINVAL; return v4l2_event_subscribe(&handle->vfh, arg); } case VIDIOC_UNSUBSCRIBE_EVENT: return v4l2_event_unsubscribe(&handle->vfh, arg); case UVCIOC_SEND_RESPONSE: ret = uvc_send_response(uvc, arg); break; default: return -ENOIOCTLCMD; } return ret; }
static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *vdev = video_devdata(file); struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); struct v4l2_fh *vfh = file->private_data; #if defined(CPTCFG_VIDEO_V4L2_SUBDEV_API) struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); #endif switch (cmd) { case VIDIOC_QUERYCTRL: return v4l2_queryctrl(vfh->ctrl_handler, arg); case VIDIOC_QUERYMENU: return v4l2_querymenu(vfh->ctrl_handler, arg); case VIDIOC_G_CTRL: return v4l2_g_ctrl(vfh->ctrl_handler, arg); case VIDIOC_S_CTRL: return v4l2_s_ctrl(vfh, vfh->ctrl_handler, arg); case VIDIOC_G_EXT_CTRLS: return v4l2_g_ext_ctrls(vfh->ctrl_handler, arg); case VIDIOC_S_EXT_CTRLS: return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, arg); case VIDIOC_TRY_EXT_CTRLS: return v4l2_try_ext_ctrls(vfh->ctrl_handler, arg); case VIDIOC_DQEVENT: if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) return -ENOIOCTLCMD; return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); case VIDIOC_SUBSCRIBE_EVENT: return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); case VIDIOC_UNSUBSCRIBE_EVENT: return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); #ifdef CPTCFG_VIDEO_ADV_DEBUG case VIDIOC_DBG_G_REGISTER: { struct v4l2_dbg_register *p = arg; if (!capable(CAP_SYS_ADMIN)) return -EPERM; return v4l2_subdev_call(sd, core, g_register, p); } case VIDIOC_DBG_S_REGISTER: { struct v4l2_dbg_register *p = arg; if (!capable(CAP_SYS_ADMIN)) return -EPERM; return v4l2_subdev_call(sd, core, s_register, p); } #endif case VIDIOC_LOG_STATUS: { int ret; pr_info("%s: ================= START STATUS =================\n", sd->name); ret = v4l2_subdev_call(sd, core, log_status); pr_info("%s: ================== END STATUS ==================\n", sd->name); return ret; } #if defined(CPTCFG_VIDEO_V4L2_SUBDEV_API) case VIDIOC_SUBDEV_G_FMT: { struct v4l2_subdev_format *format = arg; if (format->which != V4L2_SUBDEV_FORMAT_TRY && format->which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; if (format->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh, format); } case VIDIOC_SUBDEV_S_FMT: { struct v4l2_subdev_format *format = arg; if (format->which != V4L2_SUBDEV_FORMAT_TRY && format->which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; if (format->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh, format); } case VIDIOC_SUBDEV_G_CROP: { struct v4l2_subdev_crop *crop = arg; struct v4l2_subdev_selection sel; int rval; if (crop->which != V4L2_SUBDEV_FORMAT_TRY && crop->which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; if (crop->pad >= sd->entity.num_pads) return -EINVAL; rval = v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop); if (rval != -ENOIOCTLCMD) return rval; memset(&sel, 0, sizeof(sel)); sel.which = crop->which; sel.pad = crop->pad; sel.target = V4L2_SEL_TGT_CROP; rval = v4l2_subdev_call( sd, pad, get_selection, subdev_fh, &sel); crop->rect = sel.r; return rval; } case VIDIOC_SUBDEV_S_CROP: { struct v4l2_subdev_crop *crop = arg; struct v4l2_subdev_selection sel; int rval; if (crop->which != V4L2_SUBDEV_FORMAT_TRY && crop->which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; if (crop->pad >= sd->entity.num_pads) return -EINVAL; rval = v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop); if (rval != -ENOIOCTLCMD) return rval; memset(&sel, 0, sizeof(sel)); sel.which = crop->which; sel.pad = crop->pad; sel.target = V4L2_SEL_TGT_CROP; sel.r = crop->rect; rval = v4l2_subdev_call( sd, pad, set_selection, subdev_fh, &sel); crop->rect = sel.r; return rval; } case VIDIOC_SUBDEV_ENUM_MBUS_CODE: { struct v4l2_subdev_mbus_code_enum *code = arg; if (code->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh, code); } case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: { struct v4l2_subdev_frame_size_enum *fse = arg; if (fse->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh, fse); } case VIDIOC_SUBDEV_G_FRAME_INTERVAL: return v4l2_subdev_call(sd, video, g_frame_interval, arg); case VIDIOC_SUBDEV_S_FRAME_INTERVAL: return v4l2_subdev_call(sd, video, s_frame_interval, arg); case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: { struct v4l2_subdev_frame_interval_enum *fie = arg; if (fie->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh, fie); } case VIDIOC_SUBDEV_G_SELECTION: { struct v4l2_subdev_selection *sel = arg; if (sel->which != V4L2_SUBDEV_FORMAT_TRY && sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; if (sel->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call( sd, pad, get_selection, subdev_fh, sel); } case VIDIOC_SUBDEV_S_SELECTION: { struct v4l2_subdev_selection *sel = arg; if (sel->which != V4L2_SUBDEV_FORMAT_TRY && sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; if (sel->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call( sd, pad, set_selection, subdev_fh, sel); } case VIDIOC_G_EDID: return v4l2_subdev_call(sd, pad, get_edid, arg); case VIDIOC_S_EDID: return v4l2_subdev_call(sd, pad, set_edid, arg); #endif default: return v4l2_subdev_call(sd, core, ioctl, cmd, arg); } return 0; }
static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *vdev = video_devdata(file); struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); struct v4l2_fh *vfh = file->private_data; #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); #endif switch (cmd) { case VIDIOC_QUERYCTRL: return v4l2_queryctrl(vfh->ctrl_handler, arg); case VIDIOC_QUERYMENU: return v4l2_querymenu(vfh->ctrl_handler, arg); case VIDIOC_G_CTRL: return v4l2_g_ctrl(vfh->ctrl_handler, arg); case VIDIOC_S_CTRL: return v4l2_s_ctrl(vfh, vfh->ctrl_handler, arg); case VIDIOC_G_EXT_CTRLS: return v4l2_g_ext_ctrls(vfh->ctrl_handler, arg); case VIDIOC_S_EXT_CTRLS: return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, arg); case VIDIOC_TRY_EXT_CTRLS: return v4l2_try_ext_ctrls(vfh->ctrl_handler, arg); case VIDIOC_DQEVENT: if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) return -ENOIOCTLCMD; return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); case VIDIOC_SUBSCRIBE_EVENT: return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); case VIDIOC_UNSUBSCRIBE_EVENT: return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) case VIDIOC_SUBDEV_G_FMT: { struct v4l2_subdev_format *format = arg; if (format->which != V4L2_SUBDEV_FORMAT_TRY && format->which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; if (format->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh, format); } case VIDIOC_SUBDEV_S_FMT: { struct v4l2_subdev_format *format = arg; if (format->which != V4L2_SUBDEV_FORMAT_TRY && format->which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; if (format->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh, format); } case VIDIOC_SUBDEV_G_CROP: { struct v4l2_subdev_crop *crop = arg; if (crop->which != V4L2_SUBDEV_FORMAT_TRY && crop->which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; if (crop->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop); } case VIDIOC_SUBDEV_S_CROP: { struct v4l2_subdev_crop *crop = arg; if (crop->which != V4L2_SUBDEV_FORMAT_TRY && crop->which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; if (crop->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop); } case VIDIOC_SUBDEV_ENUM_MBUS_CODE: { struct v4l2_subdev_mbus_code_enum *code = arg; if (code->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh, code); } case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: { struct v4l2_subdev_frame_size_enum *fse = arg; if (fse->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh, fse); } case VIDIOC_SUBDEV_G_FRAME_INTERVAL: return v4l2_subdev_call(sd, video, g_frame_interval, arg); case VIDIOC_SUBDEV_S_FRAME_INTERVAL: return v4l2_subdev_call(sd, video, s_frame_interval, arg); case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: { struct v4l2_subdev_frame_interval_enum *fie = arg; if (fie->pad >= sd->entity.num_pads) return -EINVAL; return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh, fie); } #endif default: return v4l2_subdev_call(sd, core, ioctl, cmd, arg); } return 0; }