diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2014-09-08 04:18:15 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2014-09-08 09:49:33 -0400 |
commit | a1d27a4bf5bb4144c593358cbd7261c6c6f0a023 (patch) | |
tree | 14011001ba837d9c8da1a5d681c4525baf42a41d | |
parent | 26a029f2277bf58c72ada0a92ae44ff9dd702a2e (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.c | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/function/uvc_v4l2.c | 298 |
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 | ||
54 | struct uvc_format | 54 | struct uvc_format |
@@ -63,8 +63,29 @@ static struct uvc_format uvc_formats[] = { | |||
63 | }; | 63 | }; |
64 | 64 | ||
65 | static int | 65 | static int |
66 | uvc_v4l2_get_format(struct uvc_video *video, struct v4l2_format *fmt) | 66 | uvc_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 | |||
82 | static int | ||
83 | uvc_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 | ||
80 | static int | 101 | static int |
81 | uvc_v4l2_set_format(struct uvc_video *video, struct v4l2_format *fmt) | 102 | uvc_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 | ||
118 | static int | 142 | static int |
119 | uvc_v4l2_open(struct file *file) | 143 | uvc_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 | ||
139 | static int | 155 | static int |
140 | uvc_v4l2_release(struct file *file) | 156 | uvc_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 | ||
160 | static long | 165 | static int |
161 | uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | 166 | uvc_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) | 180 | static int |
202 | return -EINVAL; | 181 | uvc_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 */ | 190 | static int |
208 | case VIDIOC_REQBUFS: | 191 | uvc_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); | 216 | static int |
228 | } | 217 | uvc_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: | 229 | static int |
237 | return uvc_dequeue_buffer(&video->queue, arg, | 230 | uvc_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) | 239 | static int |
245 | return -EINVAL; | 240 | uvc_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. */ | 246 | static long |
248 | ret = uvc_video_enable(video, 1); | 247 | uvc_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: | 262 | static 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); | 281 | static int |
270 | } | 282 | uvc_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: | 302 | static int |
288 | return v4l2_event_unsubscribe(&handle->vfh, arg); | 303 | uvc_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 | ||
301 | static long | 320 | return 0; |
302 | uvc_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 | ||
307 | static int | 323 | static 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 |