Commit a1d27a4b authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Felipe Balbi

usb: gadget: f_uvc: Move to video_ioctl2

Simplify ioctl handling by using video_ioctl2.
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: default avatarAndrzej Pietrasiewicz <andrzej.p@samsung.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent 26a029f2
...@@ -414,7 +414,9 @@ uvc_register_video(struct uvc_device *uvc) ...@@ -414,7 +414,9 @@ uvc_register_video(struct uvc_device *uvc)
video->v4l2_dev = &uvc->v4l2_dev; video->v4l2_dev = &uvc->v4l2_dev;
video->fops = &uvc_v4l2_fops; video->fops = &uvc_v4l2_fops;
video->ioctl_ops = &uvc_v4l2_ioctl_ops;
video->release = video_device_release; video->release = video_device_release;
video->vfl_dir = VFL_DIR_TX;
strlcpy(video->name, cdev->gadget->name, sizeof(video->name)); strlcpy(video->name, cdev->gadget->name, sizeof(video->name));
uvc->vdev = video; uvc->vdev = video;
......
...@@ -48,7 +48,7 @@ uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data) ...@@ -48,7 +48,7 @@ uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data)
} }
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
* V4L2 * V4L2 ioctls
*/ */
struct uvc_format struct uvc_format
...@@ -63,8 +63,29 @@ static struct uvc_format uvc_formats[] = { ...@@ -63,8 +63,29 @@ static struct uvc_format uvc_formats[] = {
}; };
static int static int
uvc_v4l2_get_format(struct uvc_video *video, struct v4l2_format *fmt) uvc_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
{
struct video_device *vdev = video_devdata(file);
struct uvc_device *uvc = video_get_drvdata(vdev);
struct usb_composite_dev *cdev = uvc->func.config->cdev;
strlcpy(cap->driver, "g_uvc", sizeof(cap->driver));
strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card));
strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev),
sizeof(cap->bus_info));
cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
return 0;
}
static int
uvc_v4l2_get_format(struct file *file, void *fh, struct v4l2_format *fmt)
{ {
struct video_device *vdev = video_devdata(file);
struct uvc_device *uvc = video_get_drvdata(vdev);
struct uvc_video *video = &uvc->video;
fmt->fmt.pix.pixelformat = video->fcc; fmt->fmt.pix.pixelformat = video->fcc;
fmt->fmt.pix.width = video->width; fmt->fmt.pix.width = video->width;
fmt->fmt.pix.height = video->height; fmt->fmt.pix.height = video->height;
...@@ -78,8 +99,11 @@ uvc_v4l2_get_format(struct uvc_video *video, struct v4l2_format *fmt) ...@@ -78,8 +99,11 @@ uvc_v4l2_get_format(struct uvc_video *video, struct v4l2_format *fmt)
} }
static int static int
uvc_v4l2_set_format(struct uvc_video *video, struct v4l2_format *fmt) uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt)
{ {
struct video_device *vdev = video_devdata(file);
struct uvc_device *uvc = video_get_drvdata(vdev);
struct uvc_video *video = &uvc->video;
struct uvc_format *format; struct uvc_format *format;
unsigned int imagesize; unsigned int imagesize;
unsigned int bpl; unsigned int bpl;
...@@ -116,192 +140,184 @@ uvc_v4l2_set_format(struct uvc_video *video, struct v4l2_format *fmt) ...@@ -116,192 +140,184 @@ uvc_v4l2_set_format(struct uvc_video *video, struct v4l2_format *fmt)
} }
static int static int
uvc_v4l2_open(struct file *file) uvc_v4l2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *b)
{ {
struct video_device *vdev = video_devdata(file); struct video_device *vdev = video_devdata(file);
struct uvc_device *uvc = video_get_drvdata(vdev); struct uvc_device *uvc = video_get_drvdata(vdev);
struct uvc_file_handle *handle; struct uvc_video *video = &uvc->video;
handle = kzalloc(sizeof(*handle), GFP_KERNEL);
if (handle == NULL)
return -ENOMEM;
v4l2_fh_init(&handle->vfh, vdev);
v4l2_fh_add(&handle->vfh);
handle->device = &uvc->video; if (b->type != video->queue.queue.type)
file->private_data = &handle->vfh; return -EINVAL;
uvc_function_connect(uvc); return uvc_alloc_buffers(&video->queue, b);
return 0;
} }
static int static int
uvc_v4l2_release(struct file *file) uvc_v4l2_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
{ {
struct video_device *vdev = video_devdata(file); struct video_device *vdev = video_devdata(file);
struct uvc_device *uvc = video_get_drvdata(vdev); struct uvc_device *uvc = video_get_drvdata(vdev);
struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data); struct uvc_video *video = &uvc->video;
struct uvc_video *video = handle->device;
uvc_function_disconnect(uvc);
uvc_video_enable(video, 0);
uvc_free_buffers(&video->queue);
file->private_data = NULL;
v4l2_fh_del(&handle->vfh);
v4l2_fh_exit(&handle->vfh);
kfree(handle);
return 0; return uvc_query_buffer(&video->queue, b);
} }
static long static int
uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) uvc_v4l2_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
{ {
struct video_device *vdev = video_devdata(file); struct video_device *vdev = video_devdata(file);
struct uvc_device *uvc = video_get_drvdata(vdev); 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; struct uvc_video *video = &uvc->video;
int ret = 0; int ret;
switch (cmd) {
/* Query capabilities */
case VIDIOC_QUERYCAP:
{
struct v4l2_capability *cap = arg;
memset(cap, 0, sizeof *cap);
strlcpy(cap->driver, "g_uvc", sizeof(cap->driver));
strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card));
strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev),
sizeof cap->bus_info);
cap->version = LINUX_VERSION_CODE;
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.queue.type) ret = uvc_queue_buffer(&video->queue, b);
return -EINVAL; if (ret < 0)
return ret;
return uvc_v4l2_get_format(video, fmt);
}
case VIDIOC_S_FMT: return uvc_video_pump(video);
{ }
struct v4l2_format *fmt = arg;
if (fmt->type != video->queue.queue.type) static int
return -EINVAL; uvc_v4l2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
{
struct video_device *vdev = video_devdata(file);
struct uvc_device *uvc = video_get_drvdata(vdev);
struct uvc_video *video = &uvc->video;
return uvc_v4l2_set_format(video, fmt); return uvc_dequeue_buffer(&video->queue, b, file->f_flags & O_NONBLOCK);
} }
/* Buffers & streaming */ static int
case VIDIOC_REQBUFS: uvc_v4l2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
{ {
struct v4l2_requestbuffers *rb = arg; struct video_device *vdev = video_devdata(file);
struct uvc_device *uvc = video_get_drvdata(vdev);
struct uvc_video *video = &uvc->video;
int ret;
if (rb->type != video->queue.queue.type) if (type != video->queue.queue.type)
return -EINVAL; return -EINVAL;
ret = uvc_alloc_buffers(&video->queue, rb); /* Enable UVC video. */
if (ret < 0) ret = uvc_video_enable(video, 1);
return ret; if (ret < 0)
return ret;
ret = 0; /*
break; * Complete the alternate setting selection setup phase now that
} * userspace is ready to provide video frames.
*/
uvc_function_setup_continue(uvc);
uvc->state = UVC_STATE_STREAMING;
case VIDIOC_QUERYBUF: return 0;
{ }
struct v4l2_buffer *buf = arg;
return uvc_query_buffer(&video->queue, buf); static int
} uvc_v4l2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
{
struct video_device *vdev = video_devdata(file);
struct uvc_device *uvc = video_get_drvdata(vdev);
struct uvc_video *video = &uvc->video;
case VIDIOC_QBUF: if (type != video->queue.queue.type)
if ((ret = uvc_queue_buffer(&video->queue, arg)) < 0) return -EINVAL;
return ret;
return uvc_video_pump(video); return uvc_video_enable(video, 0);
}
case VIDIOC_DQBUF: static int
return uvc_dequeue_buffer(&video->queue, arg, uvc_v4l2_subscribe_event(struct v4l2_fh *fh,
file->f_flags & O_NONBLOCK); const struct v4l2_event_subscription *sub)
{
if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
return -EINVAL;
case VIDIOC_STREAMON: return v4l2_event_subscribe(fh, sub, 2, NULL);
{ }
int *type = arg;
if (*type != video->queue.queue.type) static int
return -EINVAL; uvc_v4l2_unsubscribe_event(struct v4l2_fh *fh,
const struct v4l2_event_subscription *sub)
{
return v4l2_event_unsubscribe(fh, sub);
}
/* Enable UVC video. */ static long
ret = uvc_video_enable(video, 1); uvc_v4l2_ioctl_default(struct file *file, void *fh, bool valid_prio,
if (ret < 0) unsigned int cmd, void *arg)
return ret; {
struct video_device *vdev = video_devdata(file);
struct uvc_device *uvc = video_get_drvdata(vdev);
/* switch (cmd) {
* Complete the alternate setting selection setup phase now that case UVCIOC_SEND_RESPONSE:
* userspace is ready to provide video frames. return uvc_send_response(uvc, arg);
*/
uvc_function_setup_continue(uvc);
uvc->state = UVC_STATE_STREAMING;
return 0; default:
return -ENOIOCTLCMD;
} }
}
case VIDIOC_STREAMOFF: static const struct v4l2_ioctl_ops uvc_v4l2_ioctl_ops = {
{ .vidioc_querycap = uvc_v4l2_querycap,
int *type = arg; .vidioc_g_fmt_vid_out = uvc_v4l2_get_format,
.vidioc_s_fmt_vid_out = uvc_v4l2_set_format,
.vidioc_reqbufs = uvc_v4l2_reqbufs,
.vidioc_querybuf = uvc_v4l2_querybuf,
.vidioc_qbuf = uvc_v4l2_qbuf,
.vidioc_dqbuf = uvc_v4l2_dqbuf,
.vidioc_streamon = uvc_v4l2_streamon,
.vidioc_streamoff = uvc_v4l2_streamoff,
.vidioc_subscribe_event = uvc_v4l2_subscribe_event,
.vidioc_unsubscribe_event = uvc_v4l2_unsubscribe_event,
.vidioc_default = uvc_v4l2_ioctl_default,
};
if (*type != video->queue.queue.type) /* --------------------------------------------------------------------------
return -EINVAL; * V4L2
*/
return uvc_video_enable(video, 0); static int
} uvc_v4l2_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct uvc_device *uvc = video_get_drvdata(vdev);
struct uvc_file_handle *handle;
/* Events */ handle = kzalloc(sizeof(*handle), GFP_KERNEL);
case VIDIOC_DQEVENT: if (handle == NULL)
return v4l2_event_dequeue(&handle->vfh, arg, return -ENOMEM;
file->f_flags & O_NONBLOCK);
case VIDIOC_SUBSCRIBE_EVENT: v4l2_fh_init(&handle->vfh, vdev);
{ v4l2_fh_add(&handle->vfh);
struct v4l2_event_subscription *sub = arg;
if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST) handle->device = &uvc->video;
return -EINVAL; file->private_data = &handle->vfh;
return v4l2_event_subscribe(&handle->vfh, arg, 2, NULL); uvc_function_connect(uvc);
} return 0;
}
case VIDIOC_UNSUBSCRIBE_EVENT: static int
return v4l2_event_unsubscribe(&handle->vfh, arg); uvc_v4l2_release(struct file *file)
{
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 uvc_video *video = handle->device;
case UVCIOC_SEND_RESPONSE: uvc_function_disconnect(uvc);
ret = uvc_send_response(uvc, arg);
break;
default: uvc_video_enable(video, 0);
return -ENOIOCTLCMD; uvc_free_buffers(&video->queue);
}
return ret; file->private_data = NULL;
} v4l2_fh_del(&handle->vfh);
v4l2_fh_exit(&handle->vfh);
kfree(handle);
static long return 0;
uvc_v4l2_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl);
} }
static int static int
...@@ -338,7 +354,7 @@ static struct v4l2_file_operations uvc_v4l2_fops = { ...@@ -338,7 +354,7 @@ static struct v4l2_file_operations uvc_v4l2_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = uvc_v4l2_open, .open = uvc_v4l2_open,
.release = uvc_v4l2_release, .release = uvc_v4l2_release,
.ioctl = uvc_v4l2_ioctl, .ioctl = video_ioctl2,
.mmap = uvc_v4l2_mmap, .mmap = uvc_v4l2_mmap,
.poll = uvc_v4l2_poll, .poll = uvc_v4l2_poll,
#ifndef CONFIG_MMU #ifndef CONFIG_MMU
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment