aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2014-09-08 04:18:15 -0400
committerFelipe Balbi <balbi@ti.com>2014-09-08 09:49:33 -0400
commita1d27a4bf5bb4144c593358cbd7261c6c6f0a023 (patch)
tree14011001ba837d9c8da1a5d681c4525baf42a41d
parent26a029f2277bf58c72ada0a92ae44ff9dd702a2e (diff)
usb: gadget: f_uvc: Move to video_ioctl2
Simplify ioctl handling by using video_ioctl2. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r--drivers/usb/gadget/function/f_uvc.c2
-rw-r--r--drivers/usb/gadget/function/uvc_v4l2.c298
2 files changed, 159 insertions, 141 deletions
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index e9d625b35751..b347530d1dfe 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -414,7 +414,9 @@ uvc_register_video(struct uvc_device *uvc)
414 414
415 video->v4l2_dev = &uvc->v4l2_dev; 415 video->v4l2_dev = &uvc->v4l2_dev;
416 video->fops = &uvc_v4l2_fops; 416 video->fops = &uvc_v4l2_fops;
417 video->ioctl_ops = &uvc_v4l2_ioctl_ops;
417 video->release = video_device_release; 418 video->release = video_device_release;
419 video->vfl_dir = VFL_DIR_TX;
418 strlcpy(video->name, cdev->gadget->name, sizeof(video->name)); 420 strlcpy(video->name, cdev->gadget->name, sizeof(video->name));
419 421
420 uvc->vdev = video; 422 uvc->vdev = video;
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index f22b878f163a..14c3a3734b95 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -48,7 +48,7 @@ uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data)
48} 48}
49 49
50/* -------------------------------------------------------------------------- 50/* --------------------------------------------------------------------------
51 * V4L2 51 * V4L2 ioctls
52 */ 52 */
53 53
54struct uvc_format 54struct uvc_format
@@ -63,8 +63,29 @@ static struct uvc_format uvc_formats[] = {
63}; 63};
64 64
65static int 65static int
66uvc_v4l2_get_format(struct uvc_video *video, struct v4l2_format *fmt) 66uvc_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
67{
68 struct video_device *vdev = video_devdata(file);
69 struct uvc_device *uvc = video_get_drvdata(vdev);
70 struct usb_composite_dev *cdev = uvc->func.config->cdev;
71
72 strlcpy(cap->driver, "g_uvc", sizeof(cap->driver));
73 strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card));
74 strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev),
75 sizeof(cap->bus_info));
76
77 cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
78
79 return 0;
80}
81
82static int
83uvc_v4l2_get_format(struct file *file, void *fh, struct v4l2_format *fmt)
67{ 84{
85 struct video_device *vdev = video_devdata(file);
86 struct uvc_device *uvc = video_get_drvdata(vdev);
87 struct uvc_video *video = &uvc->video;
88
68 fmt->fmt.pix.pixelformat = video->fcc; 89 fmt->fmt.pix.pixelformat = video->fcc;
69 fmt->fmt.pix.width = video->width; 90 fmt->fmt.pix.width = video->width;
70 fmt->fmt.pix.height = video->height; 91 fmt->fmt.pix.height = video->height;
@@ -78,8 +99,11 @@ uvc_v4l2_get_format(struct uvc_video *video, struct v4l2_format *fmt)
78} 99}
79 100
80static int 101static int
81uvc_v4l2_set_format(struct uvc_video *video, struct v4l2_format *fmt) 102uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt)
82{ 103{
104 struct video_device *vdev = video_devdata(file);
105 struct uvc_device *uvc = video_get_drvdata(vdev);
106 struct uvc_video *video = &uvc->video;
83 struct uvc_format *format; 107 struct uvc_format *format;
84 unsigned int imagesize; 108 unsigned int imagesize;
85 unsigned int bpl; 109 unsigned int bpl;
@@ -116,192 +140,184 @@ uvc_v4l2_set_format(struct uvc_video *video, struct v4l2_format *fmt)
116} 140}
117 141
118static int 142static int
119uvc_v4l2_open(struct file *file) 143uvc_v4l2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *b)
120{ 144{
121 struct video_device *vdev = video_devdata(file); 145 struct video_device *vdev = video_devdata(file);
122 struct uvc_device *uvc = video_get_drvdata(vdev); 146 struct uvc_device *uvc = video_get_drvdata(vdev);
123 struct uvc_file_handle *handle; 147 struct uvc_video *video = &uvc->video;
124
125 handle = kzalloc(sizeof(*handle), GFP_KERNEL);
126 if (handle == NULL)
127 return -ENOMEM;
128
129 v4l2_fh_init(&handle->vfh, vdev);
130 v4l2_fh_add(&handle->vfh);
131 148
132 handle->device = &uvc->video; 149 if (b->type != video->queue.queue.type)
133 file->private_data = &handle->vfh; 150 return -EINVAL;
134 151
135 uvc_function_connect(uvc); 152 return uvc_alloc_buffers(&video->queue, b);
136 return 0;
137} 153}
138 154
139static int 155static int
140uvc_v4l2_release(struct file *file) 156uvc_v4l2_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
141{ 157{
142 struct video_device *vdev = video_devdata(file); 158 struct video_device *vdev = video_devdata(file);
143 struct uvc_device *uvc = video_get_drvdata(vdev); 159 struct uvc_device *uvc = video_get_drvdata(vdev);
144 struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data); 160 struct uvc_video *video = &uvc->video;
145 struct uvc_video *video = handle->device;
146
147 uvc_function_disconnect(uvc);
148
149 uvc_video_enable(video, 0);
150 uvc_free_buffers(&video->queue);
151
152 file->private_data = NULL;
153 v4l2_fh_del(&handle->vfh);
154 v4l2_fh_exit(&handle->vfh);
155 kfree(handle);
156 161
157 return 0; 162 return uvc_query_buffer(&video->queue, b);
158} 163}
159 164
160static long 165static int
161uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) 166uvc_v4l2_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
162{ 167{
163 struct video_device *vdev = video_devdata(file); 168 struct video_device *vdev = video_devdata(file);
164 struct uvc_device *uvc = video_get_drvdata(vdev); 169 struct uvc_device *uvc = video_get_drvdata(vdev);
165 struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
166 struct usb_composite_dev *cdev = uvc->func.config->cdev;
167 struct uvc_video *video = &uvc->video; 170 struct uvc_video *video = &uvc->video;
168 int ret = 0; 171 int ret;
169
170 switch (cmd) {
171 /* Query capabilities */
172 case VIDIOC_QUERYCAP:
173 {
174 struct v4l2_capability *cap = arg;
175
176 memset(cap, 0, sizeof *cap);
177 strlcpy(cap->driver, "g_uvc", sizeof(cap->driver));
178 strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card));
179 strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev),
180 sizeof cap->bus_info);
181 cap->version = LINUX_VERSION_CODE;
182 cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
183 break;
184 }
185
186 /* Get & Set format */
187 case VIDIOC_G_FMT:
188 {
189 struct v4l2_format *fmt = arg;
190 172
191 if (fmt->type != video->queue.queue.type) 173 ret = uvc_queue_buffer(&video->queue, b);
192 return -EINVAL; 174 if (ret < 0)
193 175 return ret;
194 return uvc_v4l2_get_format(video, fmt);
195 }
196 176
197 case VIDIOC_S_FMT: 177 return uvc_video_pump(video);
198 { 178}
199 struct v4l2_format *fmt = arg;
200 179
201 if (fmt->type != video->queue.queue.type) 180static int
202 return -EINVAL; 181uvc_v4l2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
182{
183 struct video_device *vdev = video_devdata(file);
184 struct uvc_device *uvc = video_get_drvdata(vdev);
185 struct uvc_video *video = &uvc->video;
203 186
204 return uvc_v4l2_set_format(video, fmt); 187 return uvc_dequeue_buffer(&video->queue, b, file->f_flags & O_NONBLOCK);
205 } 188}
206 189
207 /* Buffers & streaming */ 190static int
208 case VIDIOC_REQBUFS: 191uvc_v4l2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
209 { 192{
210 struct v4l2_requestbuffers *rb = arg; 193 struct video_device *vdev = video_devdata(file);
194 struct uvc_device *uvc = video_get_drvdata(vdev);
195 struct uvc_video *video = &uvc->video;
196 int ret;
211 197
212 if (rb->type != video->queue.queue.type) 198 if (type != video->queue.queue.type)
213 return -EINVAL; 199 return -EINVAL;
214 200
215 ret = uvc_alloc_buffers(&video->queue, rb); 201 /* Enable UVC video. */
216 if (ret < 0) 202 ret = uvc_video_enable(video, 1);
217 return ret; 203 if (ret < 0)
204 return ret;
218 205
219 ret = 0; 206 /*
220 break; 207 * Complete the alternate setting selection setup phase now that
221 } 208 * userspace is ready to provide video frames.
209 */
210 uvc_function_setup_continue(uvc);
211 uvc->state = UVC_STATE_STREAMING;
222 212
223 case VIDIOC_QUERYBUF: 213 return 0;
224 { 214}
225 struct v4l2_buffer *buf = arg;
226 215
227 return uvc_query_buffer(&video->queue, buf); 216static int
228 } 217uvc_v4l2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
218{
219 struct video_device *vdev = video_devdata(file);
220 struct uvc_device *uvc = video_get_drvdata(vdev);
221 struct uvc_video *video = &uvc->video;
229 222
230 case VIDIOC_QBUF: 223 if (type != video->queue.queue.type)
231 if ((ret = uvc_queue_buffer(&video->queue, arg)) < 0) 224 return -EINVAL;
232 return ret;
233 225
234 return uvc_video_pump(video); 226 return uvc_video_enable(video, 0);
227}
235 228
236 case VIDIOC_DQBUF: 229static int
237 return uvc_dequeue_buffer(&video->queue, arg, 230uvc_v4l2_subscribe_event(struct v4l2_fh *fh,
238 file->f_flags & O_NONBLOCK); 231 const struct v4l2_event_subscription *sub)
232{
233 if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
234 return -EINVAL;
239 235
240 case VIDIOC_STREAMON: 236 return v4l2_event_subscribe(fh, sub, 2, NULL);
241 { 237}
242 int *type = arg;
243 238
244 if (*type != video->queue.queue.type) 239static int
245 return -EINVAL; 240uvc_v4l2_unsubscribe_event(struct v4l2_fh *fh,
241 const struct v4l2_event_subscription *sub)
242{
243 return v4l2_event_unsubscribe(fh, sub);
244}
246 245
247 /* Enable UVC video. */ 246static long
248 ret = uvc_video_enable(video, 1); 247uvc_v4l2_ioctl_default(struct file *file, void *fh, bool valid_prio,
249 if (ret < 0) 248 unsigned int cmd, void *arg)
250 return ret; 249{
250 struct video_device *vdev = video_devdata(file);
251 struct uvc_device *uvc = video_get_drvdata(vdev);
251 252
252 /* 253 switch (cmd) {
253 * Complete the alternate setting selection setup phase now that 254 case UVCIOC_SEND_RESPONSE:
254 * userspace is ready to provide video frames. 255 return uvc_send_response(uvc, arg);
255 */
256 uvc_function_setup_continue(uvc);
257 uvc->state = UVC_STATE_STREAMING;
258 256
259 return 0; 257 default:
258 return -ENOIOCTLCMD;
260 } 259 }
260}
261 261
262 case VIDIOC_STREAMOFF: 262static const struct v4l2_ioctl_ops uvc_v4l2_ioctl_ops = {
263 { 263 .vidioc_querycap = uvc_v4l2_querycap,
264 int *type = arg; 264 .vidioc_g_fmt_vid_out = uvc_v4l2_get_format,
265 .vidioc_s_fmt_vid_out = uvc_v4l2_set_format,
266 .vidioc_reqbufs = uvc_v4l2_reqbufs,
267 .vidioc_querybuf = uvc_v4l2_querybuf,
268 .vidioc_qbuf = uvc_v4l2_qbuf,
269 .vidioc_dqbuf = uvc_v4l2_dqbuf,
270 .vidioc_streamon = uvc_v4l2_streamon,
271 .vidioc_streamoff = uvc_v4l2_streamoff,
272 .vidioc_subscribe_event = uvc_v4l2_subscribe_event,
273 .vidioc_unsubscribe_event = uvc_v4l2_unsubscribe_event,
274 .vidioc_default = uvc_v4l2_ioctl_default,
275};
265 276
266 if (*type != video->queue.queue.type) 277/* --------------------------------------------------------------------------
267 return -EINVAL; 278 * V4L2
279 */
268 280
269 return uvc_video_enable(video, 0); 281static int
270 } 282uvc_v4l2_open(struct file *file)
283{
284 struct video_device *vdev = video_devdata(file);
285 struct uvc_device *uvc = video_get_drvdata(vdev);
286 struct uvc_file_handle *handle;
271 287
272 /* Events */ 288 handle = kzalloc(sizeof(*handle), GFP_KERNEL);
273 case VIDIOC_DQEVENT: 289 if (handle == NULL)
274 return v4l2_event_dequeue(&handle->vfh, arg, 290 return -ENOMEM;
275 file->f_flags & O_NONBLOCK);
276 291
277 case VIDIOC_SUBSCRIBE_EVENT: 292 v4l2_fh_init(&handle->vfh, vdev);
278 { 293 v4l2_fh_add(&handle->vfh);
279 struct v4l2_event_subscription *sub = arg;
280 294
281 if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST) 295 handle->device = &uvc->video;
282 return -EINVAL; 296 file->private_data = &handle->vfh;
283 297
284 return v4l2_event_subscribe(&handle->vfh, arg, 2, NULL); 298 uvc_function_connect(uvc);
285 } 299 return 0;
300}
286 301
287 case VIDIOC_UNSUBSCRIBE_EVENT: 302static int
288 return v4l2_event_unsubscribe(&handle->vfh, arg); 303uvc_v4l2_release(struct file *file)
304{
305 struct video_device *vdev = video_devdata(file);
306 struct uvc_device *uvc = video_get_drvdata(vdev);
307 struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
308 struct uvc_video *video = handle->device;
289 309
290 case UVCIOC_SEND_RESPONSE: 310 uvc_function_disconnect(uvc);
291 ret = uvc_send_response(uvc, arg);
292 break;
293 311
294 default: 312 uvc_video_enable(video, 0);
295 return -ENOIOCTLCMD; 313 uvc_free_buffers(&video->queue);
296 }
297 314
298 return ret; 315 file->private_data = NULL;
299} 316 v4l2_fh_del(&handle->vfh);
317 v4l2_fh_exit(&handle->vfh);
318 kfree(handle);
300 319
301static long 320 return 0;
302uvc_v4l2_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
303{
304 return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl);
305} 321}
306 322
307static int 323static int
@@ -338,7 +354,7 @@ static struct v4l2_file_operations uvc_v4l2_fops = {
338 .owner = THIS_MODULE, 354 .owner = THIS_MODULE,
339 .open = uvc_v4l2_open, 355 .open = uvc_v4l2_open,
340 .release = uvc_v4l2_release, 356 .release = uvc_v4l2_release,
341 .ioctl = uvc_v4l2_ioctl, 357 .ioctl = video_ioctl2,
342 .mmap = uvc_v4l2_mmap, 358 .mmap = uvc_v4l2_mmap,
343 .poll = uvc_v4l2_poll, 359 .poll = uvc_v4l2_poll,
344#ifndef CONFIG_MMU 360#ifndef CONFIG_MMU