diff options
Diffstat (limited to 'drivers/media/video/videodev.c')
-rw-r--r-- | drivers/media/video/videodev.c | 1272 |
1 files changed, 1257 insertions, 15 deletions
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 5f87dd5f1d0b..2dfa7f23d0ca 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c | |||
@@ -1,20 +1,31 @@ | |||
1 | /* | 1 | /* |
2 | * Video capture interface for Linux | 2 | * Video capture interface for Linux version 2 |
3 | * | 3 | * |
4 | * A generic video device interface for the LINUX operating system | 4 | * A generic video device interface for the LINUX operating system |
5 | * using a set of device structures/vectors for low level operations. | 5 | * using a set of device structures/vectors for low level operations. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
9 | * as published by the Free Software Foundation; either version | 9 | * as published by the Free Software Foundation; either version |
10 | * 2 of the License, or (at your option) any later version. | 10 | * 2 of the License, or (at your option) any later version. |
11 | * | 11 | * |
12 | * Author: Alan Cox, <alan@redhat.com> | 12 | * Authors: Alan Cox, <alan@redhat.com> (version 1) |
13 | * Mauro Carvalho Chehab <mchehab@infradead.org> (version 2) | ||
13 | * | 14 | * |
14 | * Fixes: 20000516 Claudio Matsuoka <claudio@conectiva.com> | 15 | * Fixes: 20000516 Claudio Matsuoka <claudio@conectiva.com> |
15 | * - Added procfs support | 16 | * - Added procfs support |
16 | */ | 17 | */ |
17 | 18 | ||
19 | #define dbgarg(cmd, fmt, arg...) \ | ||
20 | if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \ | ||
21 | printk (KERN_DEBUG "%s: ", vfd->name); \ | ||
22 | v4l_printk_ioctl(cmd); \ | ||
23 | printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg); | ||
24 | |||
25 | #define dbgarg2(fmt, arg...) \ | ||
26 | if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \ | ||
27 | printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg); | ||
28 | |||
18 | #include <linux/module.h> | 29 | #include <linux/module.h> |
19 | #include <linux/types.h> | 30 | #include <linux/types.h> |
20 | #include <linux/kernel.h> | 31 | #include <linux/kernel.h> |
@@ -30,7 +41,13 @@ | |||
30 | #include <asm/uaccess.h> | 41 | #include <asm/uaccess.h> |
31 | #include <asm/system.h> | 42 | #include <asm/system.h> |
32 | 43 | ||
44 | #define __OLD_VIDIOC_ /* To allow fixing old calls*/ | ||
45 | #include <linux/videodev2.h> | ||
46 | |||
47 | #ifdef CONFIG_VIDEO_V4L1 | ||
33 | #include <linux/videodev.h> | 48 | #include <linux/videodev.h> |
49 | #endif | ||
50 | #include <media/v4l2-common.h> | ||
34 | 51 | ||
35 | #define VIDEO_NUM_DEVICES 256 | 52 | #define VIDEO_NUM_DEVICES 256 |
36 | #define VIDEO_NAME "video4linux" | 53 | #define VIDEO_NAME "video4linux" |
@@ -41,7 +58,8 @@ | |||
41 | 58 | ||
42 | static ssize_t show_name(struct class_device *cd, char *buf) | 59 | static ssize_t show_name(struct class_device *cd, char *buf) |
43 | { | 60 | { |
44 | struct video_device *vfd = container_of(cd, struct video_device, class_dev); | 61 | struct video_device *vfd = container_of(cd, struct video_device, |
62 | class_dev); | ||
45 | return sprintf(buf,"%.*s\n",(int)sizeof(vfd->name),vfd->name); | 63 | return sprintf(buf,"%.*s\n",(int)sizeof(vfd->name),vfd->name); |
46 | } | 64 | } |
47 | 65 | ||
@@ -62,7 +80,8 @@ void video_device_release(struct video_device *vfd) | |||
62 | 80 | ||
63 | static void video_release(struct class_device *cd) | 81 | static void video_release(struct class_device *cd) |
64 | { | 82 | { |
65 | struct video_device *vfd = container_of(cd, struct video_device, class_dev); | 83 | struct video_device *vfd = container_of(cd, struct video_device, |
84 | class_dev); | ||
66 | 85 | ||
67 | #if 1 | 86 | #if 1 |
68 | /* needed until all drivers are fixed */ | 87 | /* needed until all drivers are fixed */ |
@@ -90,7 +109,7 @@ struct video_device* video_devdata(struct file *file) | |||
90 | } | 109 | } |
91 | 110 | ||
92 | /* | 111 | /* |
93 | * Open a video device. | 112 | * Open a video device - FIXME: Obsoleted |
94 | */ | 113 | */ |
95 | static int video_open(struct inode *inode, struct file *file) | 114 | static int video_open(struct inode *inode, struct file *file) |
96 | { | 115 | { |
@@ -130,6 +149,7 @@ static int video_open(struct inode *inode, struct file *file) | |||
130 | * helper function -- handles userspace copying for ioctl arguments | 149 | * helper function -- handles userspace copying for ioctl arguments |
131 | */ | 150 | */ |
132 | 151 | ||
152 | #ifdef __OLD_VIDIOC_ | ||
133 | static unsigned int | 153 | static unsigned int |
134 | video_fix_command(unsigned int cmd) | 154 | video_fix_command(unsigned int cmd) |
135 | { | 155 | { |
@@ -155,7 +175,11 @@ video_fix_command(unsigned int cmd) | |||
155 | } | 175 | } |
156 | return cmd; | 176 | return cmd; |
157 | } | 177 | } |
178 | #endif | ||
158 | 179 | ||
180 | /* | ||
181 | * Obsolete usercopy function - Should be removed soon | ||
182 | */ | ||
159 | int | 183 | int |
160 | video_usercopy(struct inode *inode, struct file *file, | 184 | video_usercopy(struct inode *inode, struct file *file, |
161 | unsigned int cmd, unsigned long arg, | 185 | unsigned int cmd, unsigned long arg, |
@@ -166,8 +190,15 @@ video_usercopy(struct inode *inode, struct file *file, | |||
166 | void *mbuf = NULL; | 190 | void *mbuf = NULL; |
167 | void *parg = NULL; | 191 | void *parg = NULL; |
168 | int err = -EINVAL; | 192 | int err = -EINVAL; |
193 | int is_ext_ctrl; | ||
194 | size_t ctrls_size = 0; | ||
195 | void __user *user_ptr = NULL; | ||
169 | 196 | ||
197 | #ifdef __OLD_VIDIOC_ | ||
170 | cmd = video_fix_command(cmd); | 198 | cmd = video_fix_command(cmd); |
199 | #endif | ||
200 | is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || | ||
201 | cmd == VIDIOC_TRY_EXT_CTRLS); | ||
171 | 202 | ||
172 | /* Copy arguments into temp kernel buffer */ | 203 | /* Copy arguments into temp kernel buffer */ |
173 | switch (_IOC_DIR(cmd)) { | 204 | switch (_IOC_DIR(cmd)) { |
@@ -193,14 +224,43 @@ video_usercopy(struct inode *inode, struct file *file, | |||
193 | goto out; | 224 | goto out; |
194 | break; | 225 | break; |
195 | } | 226 | } |
227 | if (is_ext_ctrl) { | ||
228 | struct v4l2_ext_controls *p = parg; | ||
229 | |||
230 | /* In case of an error, tell the caller that it wasn't | ||
231 | a specific control that caused it. */ | ||
232 | p->error_idx = p->count; | ||
233 | user_ptr = (void __user *)p->controls; | ||
234 | if (p->count) { | ||
235 | ctrls_size = sizeof(struct v4l2_ext_control) * p->count; | ||
236 | /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */ | ||
237 | mbuf = kmalloc(ctrls_size, GFP_KERNEL); | ||
238 | err = -ENOMEM; | ||
239 | if (NULL == mbuf) | ||
240 | goto out_ext_ctrl; | ||
241 | err = -EFAULT; | ||
242 | if (copy_from_user(mbuf, user_ptr, ctrls_size)) | ||
243 | goto out_ext_ctrl; | ||
244 | p->controls = mbuf; | ||
245 | } | ||
246 | } | ||
196 | 247 | ||
197 | /* call driver */ | 248 | /* call driver */ |
198 | err = func(inode, file, cmd, parg); | 249 | err = func(inode, file, cmd, parg); |
199 | if (err == -ENOIOCTLCMD) | 250 | if (err == -ENOIOCTLCMD) |
200 | err = -EINVAL; | 251 | err = -EINVAL; |
252 | if (is_ext_ctrl) { | ||
253 | struct v4l2_ext_controls *p = parg; | ||
254 | |||
255 | p->controls = (void *)user_ptr; | ||
256 | if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size)) | ||
257 | err = -EFAULT; | ||
258 | goto out_ext_ctrl; | ||
259 | } | ||
201 | if (err < 0) | 260 | if (err < 0) |
202 | goto out; | 261 | goto out; |
203 | 262 | ||
263 | out_ext_ctrl: | ||
204 | /* Copy results into user buffer */ | 264 | /* Copy results into user buffer */ |
205 | switch (_IOC_DIR(cmd)) | 265 | switch (_IOC_DIR(cmd)) |
206 | { | 266 | { |
@@ -218,6 +278,7 @@ out: | |||
218 | 278 | ||
219 | /* | 279 | /* |
220 | * open/release helper functions -- handle exclusive opens | 280 | * open/release helper functions -- handle exclusive opens |
281 | * Should be removed soon | ||
221 | */ | 282 | */ |
222 | int video_exclusive_open(struct inode *inode, struct file *file) | 283 | int video_exclusive_open(struct inode *inode, struct file *file) |
223 | { | 284 | { |
@@ -242,6 +303,1184 @@ int video_exclusive_release(struct inode *inode, struct file *file) | |||
242 | return 0; | 303 | return 0; |
243 | } | 304 | } |
244 | 305 | ||
306 | static char *v4l2_memory_names[] = { | ||
307 | [V4L2_MEMORY_MMAP] = "mmap", | ||
308 | [V4L2_MEMORY_USERPTR] = "userptr", | ||
309 | [V4L2_MEMORY_OVERLAY] = "overlay", | ||
310 | }; | ||
311 | |||
312 | |||
313 | /* FIXME: Those stuff are replicated also on v4l2-common.c */ | ||
314 | static char *v4l2_type_names_FIXME[] = { | ||
315 | [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap", | ||
316 | [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over", | ||
317 | [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out", | ||
318 | [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", | ||
319 | [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", | ||
320 | [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", | ||
321 | [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-capture", | ||
322 | [V4L2_BUF_TYPE_PRIVATE] = "private", | ||
323 | }; | ||
324 | |||
325 | static char *v4l2_field_names_FIXME[] = { | ||
326 | [V4L2_FIELD_ANY] = "any", | ||
327 | [V4L2_FIELD_NONE] = "none", | ||
328 | [V4L2_FIELD_TOP] = "top", | ||
329 | [V4L2_FIELD_BOTTOM] = "bottom", | ||
330 | [V4L2_FIELD_INTERLACED] = "interlaced", | ||
331 | [V4L2_FIELD_SEQ_TB] = "seq-tb", | ||
332 | [V4L2_FIELD_SEQ_BT] = "seq-bt", | ||
333 | [V4L2_FIELD_ALTERNATE] = "alternate", | ||
334 | }; | ||
335 | |||
336 | #define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown" | ||
337 | |||
338 | static void dbgbuf(unsigned int cmd, struct video_device *vfd, | ||
339 | struct v4l2_buffer *p) | ||
340 | { | ||
341 | struct v4l2_timecode *tc=&p->timecode; | ||
342 | |||
343 | dbgarg (cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, " | ||
344 | "bytesused=%d, flags=0x%08d, " | ||
345 | "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx\n", | ||
346 | (p->timestamp.tv_sec/3600), | ||
347 | (int)(p->timestamp.tv_sec/60)%60, | ||
348 | (int)(p->timestamp.tv_sec%60), | ||
349 | p->timestamp.tv_usec, | ||
350 | p->index, | ||
351 | prt_names(p->type,v4l2_type_names_FIXME), | ||
352 | p->bytesused,p->flags, | ||
353 | p->field,p->sequence, | ||
354 | prt_names(p->memory,v4l2_memory_names), | ||
355 | p->m.userptr); | ||
356 | dbgarg2 ("timecode= %02d:%02d:%02d type=%d, " | ||
357 | "flags=0x%08d, frames=%d, userbits=0x%08x\n", | ||
358 | tc->hours,tc->minutes,tc->seconds, | ||
359 | tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits); | ||
360 | } | ||
361 | |||
362 | static inline void dbgrect(struct video_device *vfd, char *s, | ||
363 | struct v4l2_rect *r) | ||
364 | { | ||
365 | dbgarg2 ("%sRect start at %dx%d, size= %dx%d\n", s, r->left, r->top, | ||
366 | r->width, r->height); | ||
367 | }; | ||
368 | |||
369 | static inline void v4l_print_pix_fmt (struct video_device *vfd, | ||
370 | struct v4l2_pix_format *fmt) | ||
371 | { | ||
372 | dbgarg2 ("width=%d, height=%d, format=0x%08x, field=%s, " | ||
373 | "bytesperline=%d sizeimage=%d, colorspace=%d\n", | ||
374 | fmt->width,fmt->height,fmt->pixelformat, | ||
375 | prt_names(fmt->field,v4l2_field_names_FIXME), | ||
376 | fmt->bytesperline,fmt->sizeimage,fmt->colorspace); | ||
377 | }; | ||
378 | |||
379 | |||
380 | static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type) | ||
381 | { | ||
382 | switch (type) { | ||
383 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
384 | if (vfd->vidioc_try_fmt_cap) | ||
385 | return (0); | ||
386 | break; | ||
387 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
388 | if (vfd->vidioc_try_fmt_overlay) | ||
389 | return (0); | ||
390 | break; | ||
391 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
392 | if (vfd->vidioc_try_fmt_vbi) | ||
393 | return (0); | ||
394 | break; | ||
395 | case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: | ||
396 | if (vfd->vidioc_try_fmt_vbi_output) | ||
397 | return (0); | ||
398 | break; | ||
399 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | ||
400 | if (vfd->vidioc_try_fmt_vbi_capture) | ||
401 | return (0); | ||
402 | break; | ||
403 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | ||
404 | if (vfd->vidioc_try_fmt_video_output) | ||
405 | return (0); | ||
406 | break; | ||
407 | case V4L2_BUF_TYPE_VBI_OUTPUT: | ||
408 | if (vfd->vidioc_try_fmt_vbi_output) | ||
409 | return (0); | ||
410 | break; | ||
411 | case V4L2_BUF_TYPE_PRIVATE: | ||
412 | if (vfd->vidioc_try_fmt_type_private) | ||
413 | return (0); | ||
414 | break; | ||
415 | } | ||
416 | return (-EINVAL); | ||
417 | } | ||
418 | |||
419 | static int __video_do_ioctl(struct inode *inode, struct file *file, | ||
420 | unsigned int cmd, void *arg) | ||
421 | { | ||
422 | struct video_device *vfd = video_devdata(file); | ||
423 | void *fh = file->private_data; | ||
424 | int ret = -EINVAL; | ||
425 | |||
426 | if ( (vfd->debug & V4L2_DEBUG_IOCTL) && | ||
427 | !(vfd->debug | V4L2_DEBUG_IOCTL_ARG)) { | ||
428 | v4l_print_ioctl(vfd->name, cmd); | ||
429 | } | ||
430 | |||
431 | switch(cmd) { | ||
432 | /* --- capabilities ------------------------------------------ */ | ||
433 | case VIDIOC_QUERYCAP: | ||
434 | { | ||
435 | struct v4l2_capability *cap = (struct v4l2_capability*)arg; | ||
436 | memset(cap, 0, sizeof(*cap)); | ||
437 | |||
438 | if (!vfd->vidioc_querycap) | ||
439 | break; | ||
440 | |||
441 | ret=vfd->vidioc_querycap(file, fh, cap); | ||
442 | if (!ret) | ||
443 | dbgarg (cmd, "driver=%s, card=%s, bus=%s, " | ||
444 | "version=0x%08x, " | ||
445 | "capabilities=0x%08x\n", | ||
446 | cap->driver,cap->card,cap->bus_info, | ||
447 | cap->version, | ||
448 | cap->capabilities); | ||
449 | break; | ||
450 | } | ||
451 | |||
452 | /* --- priority ------------------------------------------ */ | ||
453 | case VIDIOC_G_PRIORITY: | ||
454 | { | ||
455 | enum v4l2_priority *p=arg; | ||
456 | |||
457 | if (!vfd->vidioc_g_priority) | ||
458 | break; | ||
459 | ret=vfd->vidioc_g_priority(file, fh, p); | ||
460 | if (!ret) | ||
461 | dbgarg(cmd, "priority is %d\n", *p); | ||
462 | break; | ||
463 | } | ||
464 | case VIDIOC_S_PRIORITY: | ||
465 | { | ||
466 | enum v4l2_priority *p=arg; | ||
467 | |||
468 | if (!vfd->vidioc_s_priority) | ||
469 | break; | ||
470 | dbgarg(cmd, "setting priority to %d\n", *p); | ||
471 | ret=vfd->vidioc_s_priority(file, fh, *p); | ||
472 | break; | ||
473 | } | ||
474 | |||
475 | /* --- capture ioctls ---------------------------------------- */ | ||
476 | case VIDIOC_ENUM_FMT: | ||
477 | { | ||
478 | struct v4l2_fmtdesc *f = arg; | ||
479 | enum v4l2_buf_type type; | ||
480 | unsigned int index; | ||
481 | |||
482 | index = f->index; | ||
483 | type = f->type; | ||
484 | memset(f,0,sizeof(*f)); | ||
485 | f->index = index; | ||
486 | f->type = type; | ||
487 | |||
488 | switch (type) { | ||
489 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
490 | if (vfd->vidioc_enum_fmt_cap) | ||
491 | ret=vfd->vidioc_enum_fmt_cap(file, fh, f); | ||
492 | break; | ||
493 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
494 | if (vfd->vidioc_enum_fmt_overlay) | ||
495 | ret=vfd->vidioc_enum_fmt_overlay(file, fh, f); | ||
496 | break; | ||
497 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
498 | if (vfd->vidioc_enum_fmt_vbi) | ||
499 | ret=vfd->vidioc_enum_fmt_vbi(file, fh, f); | ||
500 | break; | ||
501 | case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: | ||
502 | if (vfd->vidioc_enum_fmt_vbi_output) | ||
503 | ret=vfd->vidioc_enum_fmt_vbi_output(file, | ||
504 | fh, f); | ||
505 | break; | ||
506 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | ||
507 | if (vfd->vidioc_enum_fmt_vbi_capture) | ||
508 | ret=vfd->vidioc_enum_fmt_vbi_capture(file, | ||
509 | fh, f); | ||
510 | break; | ||
511 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | ||
512 | if (vfd->vidioc_enum_fmt_video_output) | ||
513 | ret=vfd->vidioc_enum_fmt_video_output(file, | ||
514 | fh, f); | ||
515 | break; | ||
516 | case V4L2_BUF_TYPE_VBI_OUTPUT: | ||
517 | if (vfd->vidioc_enum_fmt_vbi_output) | ||
518 | ret=vfd->vidioc_enum_fmt_vbi_output(file, | ||
519 | fh, f); | ||
520 | break; | ||
521 | case V4L2_BUF_TYPE_PRIVATE: | ||
522 | if (vfd->vidioc_enum_fmt_type_private) | ||
523 | ret=vfd->vidioc_enum_fmt_type_private(file, | ||
524 | fh, f); | ||
525 | break; | ||
526 | } | ||
527 | if (!ret) | ||
528 | dbgarg (cmd, "index=%d, type=%d, flags=%d, " | ||
529 | "description=%s," | ||
530 | " pixelformat=0x%8x\n", | ||
531 | f->index, f->type, f->flags, | ||
532 | f->description, | ||
533 | f->pixelformat); | ||
534 | |||
535 | break; | ||
536 | } | ||
537 | case VIDIOC_G_FMT: | ||
538 | { | ||
539 | struct v4l2_format *f = (struct v4l2_format *)arg; | ||
540 | enum v4l2_buf_type type=f->type; | ||
541 | |||
542 | memset(&f->fmt.pix,0,sizeof(f->fmt.pix)); | ||
543 | f->type=type; | ||
544 | |||
545 | /* FIXME: Should be one dump per type */ | ||
546 | dbgarg (cmd, "type=%s\n", prt_names(type, | ||
547 | v4l2_type_names_FIXME)); | ||
548 | |||
549 | switch (type) { | ||
550 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
551 | if (vfd->vidioc_g_fmt_cap) | ||
552 | ret=vfd->vidioc_g_fmt_cap(file, fh, f); | ||
553 | if (!ret) | ||
554 | v4l_print_pix_fmt(vfd,&f->fmt.pix); | ||
555 | break; | ||
556 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
557 | if (vfd->vidioc_g_fmt_overlay) | ||
558 | ret=vfd->vidioc_g_fmt_overlay(file, fh, f); | ||
559 | break; | ||
560 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
561 | if (vfd->vidioc_g_fmt_vbi) | ||
562 | ret=vfd->vidioc_g_fmt_vbi(file, fh, f); | ||
563 | break; | ||
564 | case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: | ||
565 | if (vfd->vidioc_g_fmt_vbi_output) | ||
566 | ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f); | ||
567 | break; | ||
568 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | ||
569 | if (vfd->vidioc_g_fmt_vbi_capture) | ||
570 | ret=vfd->vidioc_g_fmt_vbi_capture(file, fh, f); | ||
571 | break; | ||
572 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | ||
573 | if (vfd->vidioc_g_fmt_video_output) | ||
574 | ret=vfd->vidioc_g_fmt_video_output(file, | ||
575 | fh, f); | ||
576 | break; | ||
577 | case V4L2_BUF_TYPE_VBI_OUTPUT: | ||
578 | if (vfd->vidioc_g_fmt_vbi_output) | ||
579 | ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f); | ||
580 | break; | ||
581 | case V4L2_BUF_TYPE_PRIVATE: | ||
582 | if (vfd->vidioc_g_fmt_type_private) | ||
583 | ret=vfd->vidioc_g_fmt_type_private(file, | ||
584 | fh, f); | ||
585 | break; | ||
586 | } | ||
587 | |||
588 | break; | ||
589 | } | ||
590 | case VIDIOC_S_FMT: | ||
591 | { | ||
592 | struct v4l2_format *f = (struct v4l2_format *)arg; | ||
593 | |||
594 | /* FIXME: Should be one dump per type */ | ||
595 | dbgarg (cmd, "type=%s\n", prt_names(f->type, | ||
596 | v4l2_type_names_FIXME)); | ||
597 | |||
598 | switch (f->type) { | ||
599 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
600 | v4l_print_pix_fmt(vfd,&f->fmt.pix); | ||
601 | if (vfd->vidioc_s_fmt_cap) | ||
602 | ret=vfd->vidioc_s_fmt_cap(file, fh, f); | ||
603 | break; | ||
604 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
605 | if (vfd->vidioc_s_fmt_overlay) | ||
606 | ret=vfd->vidioc_s_fmt_overlay(file, fh, f); | ||
607 | break; | ||
608 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
609 | if (vfd->vidioc_s_fmt_vbi) | ||
610 | ret=vfd->vidioc_s_fmt_vbi(file, fh, f); | ||
611 | break; | ||
612 | case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: | ||
613 | if (vfd->vidioc_s_fmt_vbi_output) | ||
614 | ret=vfd->vidioc_s_fmt_vbi_output(file, fh, f); | ||
615 | break; | ||
616 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | ||
617 | if (vfd->vidioc_s_fmt_vbi_capture) | ||
618 | ret=vfd->vidioc_s_fmt_vbi_capture(file, fh, f); | ||
619 | break; | ||
620 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | ||
621 | if (vfd->vidioc_s_fmt_video_output) | ||
622 | ret=vfd->vidioc_s_fmt_video_output(file, | ||
623 | fh, f); | ||
624 | break; | ||
625 | case V4L2_BUF_TYPE_VBI_OUTPUT: | ||
626 | if (vfd->vidioc_s_fmt_vbi_output) | ||
627 | ret=vfd->vidioc_s_fmt_vbi_output(file, | ||
628 | fh, f); | ||
629 | break; | ||
630 | case V4L2_BUF_TYPE_PRIVATE: | ||
631 | if (vfd->vidioc_s_fmt_type_private) | ||
632 | ret=vfd->vidioc_s_fmt_type_private(file, | ||
633 | fh, f); | ||
634 | break; | ||
635 | } | ||
636 | break; | ||
637 | } | ||
638 | case VIDIOC_TRY_FMT: | ||
639 | { | ||
640 | struct v4l2_format *f = (struct v4l2_format *)arg; | ||
641 | |||
642 | /* FIXME: Should be one dump per type */ | ||
643 | dbgarg (cmd, "type=%s\n", prt_names(f->type, | ||
644 | v4l2_type_names_FIXME)); | ||
645 | switch (f->type) { | ||
646 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
647 | if (vfd->vidioc_try_fmt_cap) | ||
648 | ret=vfd->vidioc_try_fmt_cap(file, fh, f); | ||
649 | if (!ret) | ||
650 | v4l_print_pix_fmt(vfd,&f->fmt.pix); | ||
651 | break; | ||
652 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
653 | if (vfd->vidioc_try_fmt_overlay) | ||
654 | ret=vfd->vidioc_try_fmt_overlay(file, fh, f); | ||
655 | break; | ||
656 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
657 | if (vfd->vidioc_try_fmt_vbi) | ||
658 | ret=vfd->vidioc_try_fmt_vbi(file, fh, f); | ||
659 | break; | ||
660 | case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: | ||
661 | if (vfd->vidioc_try_fmt_vbi_output) | ||
662 | ret=vfd->vidioc_try_fmt_vbi_output(file, | ||
663 | fh, f); | ||
664 | break; | ||
665 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | ||
666 | if (vfd->vidioc_try_fmt_vbi_capture) | ||
667 | ret=vfd->vidioc_try_fmt_vbi_capture(file, | ||
668 | fh, f); | ||
669 | break; | ||
670 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | ||
671 | if (vfd->vidioc_try_fmt_video_output) | ||
672 | ret=vfd->vidioc_try_fmt_video_output(file, | ||
673 | fh, f); | ||
674 | break; | ||
675 | case V4L2_BUF_TYPE_VBI_OUTPUT: | ||
676 | if (vfd->vidioc_try_fmt_vbi_output) | ||
677 | ret=vfd->vidioc_try_fmt_vbi_output(file, | ||
678 | fh, f); | ||
679 | break; | ||
680 | case V4L2_BUF_TYPE_PRIVATE: | ||
681 | if (vfd->vidioc_try_fmt_type_private) | ||
682 | ret=vfd->vidioc_try_fmt_type_private(file, | ||
683 | fh, f); | ||
684 | break; | ||
685 | } | ||
686 | |||
687 | break; | ||
688 | } | ||
689 | /* FIXME: Those buf reqs could be handled here, | ||
690 | with some changes on videobuf to allow its header to be included at | ||
691 | videodev2.h or being merged at videodev2. | ||
692 | */ | ||
693 | case VIDIOC_REQBUFS: | ||
694 | { | ||
695 | struct v4l2_requestbuffers *p=arg; | ||
696 | |||
697 | if (!vfd->vidioc_reqbufs) | ||
698 | break; | ||
699 | ret = check_fmt (vfd, p->type); | ||
700 | if (ret) | ||
701 | break; | ||
702 | |||
703 | ret=vfd->vidioc_reqbufs(file, fh, p); | ||
704 | dbgarg (cmd, "count=%d, type=%s, memory=%s\n", | ||
705 | p->count, | ||
706 | prt_names(p->type,v4l2_type_names_FIXME), | ||
707 | prt_names(p->memory,v4l2_memory_names)); | ||
708 | break; | ||
709 | } | ||
710 | case VIDIOC_QUERYBUF: | ||
711 | { | ||
712 | struct v4l2_buffer *p=arg; | ||
713 | |||
714 | if (!vfd->vidioc_querybuf) | ||
715 | break; | ||
716 | ret = check_fmt (vfd, p->type); | ||
717 | if (ret) | ||
718 | break; | ||
719 | |||
720 | ret=vfd->vidioc_querybuf(file, fh, p); | ||
721 | if (!ret) | ||
722 | dbgbuf(cmd,vfd,p); | ||
723 | break; | ||
724 | } | ||
725 | case VIDIOC_QBUF: | ||
726 | { | ||
727 | struct v4l2_buffer *p=arg; | ||
728 | |||
729 | if (!vfd->vidioc_qbuf) | ||
730 | break; | ||
731 | ret = check_fmt (vfd, p->type); | ||
732 | if (ret) | ||
733 | break; | ||
734 | |||
735 | ret=vfd->vidioc_qbuf(file, fh, p); | ||
736 | if (!ret) | ||
737 | dbgbuf(cmd,vfd,p); | ||
738 | break; | ||
739 | } | ||
740 | case VIDIOC_DQBUF: | ||
741 | { | ||
742 | struct v4l2_buffer *p=arg; | ||
743 | if (!vfd->vidioc_qbuf) | ||
744 | break; | ||
745 | ret = check_fmt (vfd, p->type); | ||
746 | if (ret) | ||
747 | break; | ||
748 | |||
749 | ret=vfd->vidioc_qbuf(file, fh, p); | ||
750 | if (!ret) | ||
751 | dbgbuf(cmd,vfd,p); | ||
752 | break; | ||
753 | } | ||
754 | case VIDIOC_OVERLAY: | ||
755 | { | ||
756 | int *i = arg; | ||
757 | |||
758 | if (!vfd->vidioc_overlay) | ||
759 | break; | ||
760 | dbgarg (cmd, "value=%d\n",*i); | ||
761 | ret=vfd->vidioc_overlay(file, fh, *i); | ||
762 | break; | ||
763 | } | ||
764 | #ifdef HAVE_V4L1 | ||
765 | /* --- streaming capture ------------------------------------- */ | ||
766 | case VIDIOCGMBUF: | ||
767 | { | ||
768 | struct video_mbuf *p=arg; | ||
769 | |||
770 | memset(p,0,sizeof(p)); | ||
771 | |||
772 | if (!vfd->vidiocgmbuf) | ||
773 | break; | ||
774 | ret=vfd->vidiocgmbuf(file, fh, p); | ||
775 | if (!ret) | ||
776 | dbgarg (cmd, "size=%d, frames=%d, offsets=0x%08lx\n", | ||
777 | p->size, p->frames, | ||
778 | (unsigned long)p->offsets); | ||
779 | break; | ||
780 | } | ||
781 | #endif | ||
782 | case VIDIOC_G_FBUF: | ||
783 | { | ||
784 | struct v4l2_framebuffer *p=arg; | ||
785 | if (!vfd->vidioc_g_fbuf) | ||
786 | break; | ||
787 | ret=vfd->vidioc_g_fbuf(file, fh, arg); | ||
788 | if (!ret) { | ||
789 | dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n", | ||
790 | p->capability,p->flags, | ||
791 | (unsigned long)p->base); | ||
792 | v4l_print_pix_fmt (vfd, &p->fmt); | ||
793 | } | ||
794 | break; | ||
795 | } | ||
796 | case VIDIOC_S_FBUF: | ||
797 | { | ||
798 | struct v4l2_framebuffer *p=arg; | ||
799 | if (!vfd->vidioc_s_fbuf) | ||
800 | break; | ||
801 | |||
802 | dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n", | ||
803 | p->capability,p->flags,(unsigned long)p->base); | ||
804 | v4l_print_pix_fmt (vfd, &p->fmt); | ||
805 | ret=vfd->vidioc_s_fbuf(file, fh, arg); | ||
806 | |||
807 | break; | ||
808 | } | ||
809 | case VIDIOC_STREAMON: | ||
810 | { | ||
811 | enum v4l2_buf_type i = *(int *)arg; | ||
812 | if (!vfd->vidioc_streamon) | ||
813 | break; | ||
814 | dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME)); | ||
815 | ret=vfd->vidioc_streamon(file, fh,i); | ||
816 | break; | ||
817 | } | ||
818 | case VIDIOC_STREAMOFF: | ||
819 | { | ||
820 | enum v4l2_buf_type i = *(int *)arg; | ||
821 | |||
822 | if (!vfd->vidioc_streamoff) | ||
823 | break; | ||
824 | dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME)); | ||
825 | ret=vfd->vidioc_streamoff(file, fh, i); | ||
826 | break; | ||
827 | } | ||
828 | /* ---------- tv norms ---------- */ | ||
829 | case VIDIOC_ENUMSTD: | ||
830 | { | ||
831 | struct v4l2_standard *p = arg; | ||
832 | unsigned int index = p->index; | ||
833 | |||
834 | if (!vfd->tvnormsize) { | ||
835 | printk (KERN_WARNING "%s: no TV norms defined!\n", | ||
836 | vfd->name); | ||
837 | break; | ||
838 | } | ||
839 | |||
840 | if (index<=0 || index >= vfd->tvnormsize) { | ||
841 | ret=-EINVAL; | ||
842 | break; | ||
843 | } | ||
844 | v4l2_video_std_construct(p, vfd->tvnorms[p->index].id, | ||
845 | vfd->tvnorms[p->index].name); | ||
846 | p->index = index; | ||
847 | |||
848 | dbgarg (cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, " | ||
849 | "framelines=%d\n", p->index, | ||
850 | (unsigned long long)p->id, p->name, | ||
851 | p->frameperiod.numerator, | ||
852 | p->frameperiod.denominator, | ||
853 | p->framelines); | ||
854 | |||
855 | ret=0; | ||
856 | break; | ||
857 | } | ||
858 | case VIDIOC_G_STD: | ||
859 | { | ||
860 | v4l2_std_id *id = arg; | ||
861 | |||
862 | *id = vfd->current_norm; | ||
863 | |||
864 | dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id); | ||
865 | |||
866 | ret=0; | ||
867 | break; | ||
868 | } | ||
869 | case VIDIOC_S_STD: | ||
870 | { | ||
871 | v4l2_std_id *id = arg; | ||
872 | unsigned int i; | ||
873 | |||
874 | if (!vfd->tvnormsize) { | ||
875 | printk (KERN_WARNING "%s: no TV norms defined!\n", | ||
876 | vfd->name); | ||
877 | break; | ||
878 | } | ||
879 | |||
880 | dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id); | ||
881 | |||
882 | /* First search for exact match */ | ||
883 | for (i = 0; i < vfd->tvnormsize; i++) | ||
884 | if (*id == vfd->tvnorms[i].id) | ||
885 | break; | ||
886 | /* Then for a generic video std that contains desired std */ | ||
887 | if (i == vfd->tvnormsize) | ||
888 | for (i = 0; i < vfd->tvnormsize; i++) | ||
889 | if (*id & vfd->tvnorms[i].id) | ||
890 | break; | ||
891 | if (i == vfd->tvnormsize) { | ||
892 | break; | ||
893 | } | ||
894 | |||
895 | /* Calls the specific handler */ | ||
896 | if (vfd->vidioc_s_std) | ||
897 | ret=vfd->vidioc_s_std(file, fh, i); | ||
898 | else | ||
899 | ret=-EINVAL; | ||
900 | |||
901 | /* Updates standard information */ | ||
902 | if (!ret) | ||
903 | vfd->current_norm=*id; | ||
904 | |||
905 | break; | ||
906 | } | ||
907 | case VIDIOC_QUERYSTD: | ||
908 | { | ||
909 | v4l2_std_id *p=arg; | ||
910 | |||
911 | if (!vfd->vidioc_querystd) | ||
912 | break; | ||
913 | ret=vfd->vidioc_querystd(file, fh, arg); | ||
914 | if (!ret) | ||
915 | dbgarg (cmd, "detected std=%Lu\n", | ||
916 | (unsigned long long)*p); | ||
917 | break; | ||
918 | } | ||
919 | /* ------ input switching ---------- */ | ||
920 | /* FIXME: Inputs can be handled inside videodev2 */ | ||
921 | case VIDIOC_ENUMINPUT: | ||
922 | { | ||
923 | struct v4l2_input *p=arg; | ||
924 | int i=p->index; | ||
925 | |||
926 | if (!vfd->vidioc_enum_input) | ||
927 | break; | ||
928 | memset(p, 0, sizeof(*p)); | ||
929 | p->index=i; | ||
930 | |||
931 | ret=vfd->vidioc_enum_input(file, fh, p); | ||
932 | if (!ret) | ||
933 | dbgarg (cmd, "index=%d, name=%s, type=%d, " | ||
934 | "audioset=%d, " | ||
935 | "tuner=%d, std=%Ld, status=%d\n", | ||
936 | p->index,p->name,p->type,p->audioset, | ||
937 | p->tuner, | ||
938 | (unsigned long long)p->std, | ||
939 | p->status); | ||
940 | break; | ||
941 | } | ||
942 | case VIDIOC_G_INPUT: | ||
943 | { | ||
944 | unsigned int *i = arg; | ||
945 | |||
946 | if (!vfd->vidioc_g_input) | ||
947 | break; | ||
948 | ret=vfd->vidioc_g_input(file, fh, i); | ||
949 | if (!ret) | ||
950 | dbgarg (cmd, "value=%d\n",*i); | ||
951 | break; | ||
952 | } | ||
953 | case VIDIOC_S_INPUT: | ||
954 | { | ||
955 | unsigned int *i = arg; | ||
956 | |||
957 | if (!vfd->vidioc_s_input) | ||
958 | break; | ||
959 | dbgarg (cmd, "value=%d\n",*i); | ||
960 | ret=vfd->vidioc_s_input(file, fh, *i); | ||
961 | break; | ||
962 | } | ||
963 | |||
964 | /* ------ output switching ---------- */ | ||
965 | case VIDIOC_G_OUTPUT: | ||
966 | { | ||
967 | unsigned int *i = arg; | ||
968 | |||
969 | if (!vfd->vidioc_g_output) | ||
970 | break; | ||
971 | ret=vfd->vidioc_g_output(file, fh, i); | ||
972 | if (!ret) | ||
973 | dbgarg (cmd, "value=%d\n",*i); | ||
974 | break; | ||
975 | } | ||
976 | case VIDIOC_S_OUTPUT: | ||
977 | { | ||
978 | unsigned int *i = arg; | ||
979 | |||
980 | if (!vfd->vidioc_s_output) | ||
981 | break; | ||
982 | dbgarg (cmd, "value=%d\n",*i); | ||
983 | ret=vfd->vidioc_s_output(file, fh, *i); | ||
984 | break; | ||
985 | } | ||
986 | |||
987 | /* --- controls ---------------------------------------------- */ | ||
988 | case VIDIOC_QUERYCTRL: | ||
989 | { | ||
990 | struct v4l2_queryctrl *p=arg; | ||
991 | |||
992 | if (!vfd->vidioc_queryctrl) | ||
993 | break; | ||
994 | ret=vfd->vidioc_queryctrl(file, fh, p); | ||
995 | |||
996 | if (!ret) | ||
997 | dbgarg (cmd, "id=%d, type=%d, name=%s, " | ||
998 | "min/max=%d/%d," | ||
999 | " step=%d, default=%d, flags=0x%08x\n", | ||
1000 | p->id,p->type,p->name,p->minimum, | ||
1001 | p->maximum,p->step,p->default_value, | ||
1002 | p->flags); | ||
1003 | break; | ||
1004 | } | ||
1005 | case VIDIOC_G_CTRL: | ||
1006 | { | ||
1007 | struct v4l2_control *p = arg; | ||
1008 | |||
1009 | if (!vfd->vidioc_g_ctrl) | ||
1010 | break; | ||
1011 | dbgarg(cmd, "Enum for index=%d\n", p->id); | ||
1012 | |||
1013 | ret=vfd->vidioc_g_ctrl(file, fh, p); | ||
1014 | if (!ret) | ||
1015 | dbgarg2 ( "id=%d, value=%d\n", p->id, p->value); | ||
1016 | break; | ||
1017 | } | ||
1018 | case VIDIOC_S_CTRL: | ||
1019 | { | ||
1020 | struct v4l2_control *p = arg; | ||
1021 | |||
1022 | if (!vfd->vidioc_s_ctrl) | ||
1023 | break; | ||
1024 | dbgarg (cmd, "id=%d, value=%d\n", p->id, p->value); | ||
1025 | |||
1026 | ret=vfd->vidioc_s_ctrl(file, fh, p); | ||
1027 | break; | ||
1028 | } | ||
1029 | case VIDIOC_G_EXT_CTRLS: | ||
1030 | { | ||
1031 | struct v4l2_ext_controls *p = arg; | ||
1032 | |||
1033 | if (vfd->vidioc_g_ext_ctrls) { | ||
1034 | dbgarg(cmd, "count=%d\n", p->count); | ||
1035 | |||
1036 | ret=vfd->vidioc_g_ext_ctrls(file, fh, p); | ||
1037 | } | ||
1038 | break; | ||
1039 | } | ||
1040 | case VIDIOC_S_EXT_CTRLS: | ||
1041 | { | ||
1042 | struct v4l2_ext_controls *p = arg; | ||
1043 | |||
1044 | if (vfd->vidioc_s_ext_ctrls) { | ||
1045 | dbgarg(cmd, "count=%d\n", p->count); | ||
1046 | |||
1047 | ret=vfd->vidioc_s_ext_ctrls(file, fh, p); | ||
1048 | } | ||
1049 | break; | ||
1050 | } | ||
1051 | case VIDIOC_TRY_EXT_CTRLS: | ||
1052 | { | ||
1053 | struct v4l2_ext_controls *p = arg; | ||
1054 | |||
1055 | if (vfd->vidioc_try_ext_ctrls) { | ||
1056 | dbgarg(cmd, "count=%d\n", p->count); | ||
1057 | |||
1058 | ret=vfd->vidioc_try_ext_ctrls(file, fh, p); | ||
1059 | } | ||
1060 | break; | ||
1061 | } | ||
1062 | case VIDIOC_QUERYMENU: | ||
1063 | { | ||
1064 | struct v4l2_querymenu *p=arg; | ||
1065 | if (!vfd->vidioc_querymenu) | ||
1066 | break; | ||
1067 | ret=vfd->vidioc_querymenu(file, fh, p); | ||
1068 | if (!ret) | ||
1069 | dbgarg (cmd, "id=%d, index=%d, name=%s\n", | ||
1070 | p->id,p->index,p->name); | ||
1071 | break; | ||
1072 | } | ||
1073 | /* --- audio ---------------------------------------------- */ | ||
1074 | case VIDIOC_ENUMAUDIO: | ||
1075 | { | ||
1076 | struct v4l2_audio *p=arg; | ||
1077 | |||
1078 | if (!vfd->vidioc_enumaudio) | ||
1079 | break; | ||
1080 | dbgarg(cmd, "Enum for index=%d\n", p->index); | ||
1081 | ret=vfd->vidioc_enumaudio(file, fh, p); | ||
1082 | if (!ret) | ||
1083 | dbgarg2("index=%d, name=%s, capability=%d, " | ||
1084 | "mode=%d\n",p->index,p->name, | ||
1085 | p->capability, p->mode); | ||
1086 | break; | ||
1087 | } | ||
1088 | case VIDIOC_G_AUDIO: | ||
1089 | { | ||
1090 | struct v4l2_audio *p=arg; | ||
1091 | |||
1092 | if (!vfd->vidioc_g_audio) | ||
1093 | break; | ||
1094 | dbgarg(cmd, "Get for index=%d\n", p->index); | ||
1095 | ret=vfd->vidioc_g_audio(file, fh, p); | ||
1096 | if (!ret) | ||
1097 | dbgarg2("index=%d, name=%s, capability=%d, " | ||
1098 | "mode=%d\n",p->index, | ||
1099 | p->name,p->capability, p->mode); | ||
1100 | break; | ||
1101 | } | ||
1102 | case VIDIOC_S_AUDIO: | ||
1103 | { | ||
1104 | struct v4l2_audio *p=arg; | ||
1105 | |||
1106 | if (!vfd->vidioc_s_audio) | ||
1107 | break; | ||
1108 | dbgarg(cmd, "index=%d, name=%s, capability=%d, " | ||
1109 | "mode=%d\n", p->index, p->name, | ||
1110 | p->capability, p->mode); | ||
1111 | ret=vfd->vidioc_s_audio(file, fh, p); | ||
1112 | break; | ||
1113 | } | ||
1114 | case VIDIOC_ENUMAUDOUT: | ||
1115 | { | ||
1116 | struct v4l2_audioout *p=arg; | ||
1117 | |||
1118 | if (!vfd->vidioc_enumaudout) | ||
1119 | break; | ||
1120 | dbgarg(cmd, "Enum for index=%d\n", p->index); | ||
1121 | ret=vfd->vidioc_enumaudout(file, fh, p); | ||
1122 | if (!ret) | ||
1123 | dbgarg2("index=%d, name=%s, capability=%d, " | ||
1124 | "mode=%d\n", p->index, p->name, | ||
1125 | p->capability,p->mode); | ||
1126 | break; | ||
1127 | } | ||
1128 | case VIDIOC_G_AUDOUT: | ||
1129 | { | ||
1130 | struct v4l2_audioout *p=arg; | ||
1131 | |||
1132 | if (!vfd->vidioc_g_audout) | ||
1133 | break; | ||
1134 | dbgarg(cmd, "Enum for index=%d\n", p->index); | ||
1135 | ret=vfd->vidioc_g_audout(file, fh, p); | ||
1136 | if (!ret) | ||
1137 | dbgarg2("index=%d, name=%s, capability=%d, " | ||
1138 | "mode=%d\n", p->index, p->name, | ||
1139 | p->capability,p->mode); | ||
1140 | break; | ||
1141 | } | ||
1142 | case VIDIOC_S_AUDOUT: | ||
1143 | { | ||
1144 | struct v4l2_audioout *p=arg; | ||
1145 | |||
1146 | if (!vfd->vidioc_s_audout) | ||
1147 | break; | ||
1148 | dbgarg(cmd, "index=%d, name=%s, capability=%d, " | ||
1149 | "mode=%d\n", p->index, p->name, | ||
1150 | p->capability,p->mode); | ||
1151 | |||
1152 | ret=vfd->vidioc_s_audout(file, fh, p); | ||
1153 | break; | ||
1154 | } | ||
1155 | case VIDIOC_G_MODULATOR: | ||
1156 | { | ||
1157 | struct v4l2_modulator *p=arg; | ||
1158 | if (!vfd->vidioc_g_modulator) | ||
1159 | break; | ||
1160 | ret=vfd->vidioc_g_modulator(file, fh, p); | ||
1161 | if (!ret) | ||
1162 | dbgarg(cmd, "index=%d, name=%s, " | ||
1163 | "capability=%d, rangelow=%d," | ||
1164 | " rangehigh=%d, txsubchans=%d\n", | ||
1165 | p->index, p->name,p->capability, | ||
1166 | p->rangelow, p->rangehigh, | ||
1167 | p->txsubchans); | ||
1168 | break; | ||
1169 | } | ||
1170 | case VIDIOC_S_MODULATOR: | ||
1171 | { | ||
1172 | struct v4l2_modulator *p=arg; | ||
1173 | if (!vfd->vidioc_s_modulator) | ||
1174 | break; | ||
1175 | dbgarg(cmd, "index=%d, name=%s, capability=%d, " | ||
1176 | "rangelow=%d, rangehigh=%d, txsubchans=%d\n", | ||
1177 | p->index, p->name,p->capability,p->rangelow, | ||
1178 | p->rangehigh,p->txsubchans); | ||
1179 | ret=vfd->vidioc_s_modulator(file, fh, p); | ||
1180 | break; | ||
1181 | } | ||
1182 | case VIDIOC_G_CROP: | ||
1183 | { | ||
1184 | struct v4l2_crop *p=arg; | ||
1185 | if (!vfd->vidioc_g_crop) | ||
1186 | break; | ||
1187 | ret=vfd->vidioc_g_crop(file, fh, p); | ||
1188 | if (!ret) { | ||
1189 | dbgarg(cmd, "type=%d\n", p->type); | ||
1190 | dbgrect(vfd, "", &p->c); | ||
1191 | } | ||
1192 | break; | ||
1193 | } | ||
1194 | case VIDIOC_S_CROP: | ||
1195 | { | ||
1196 | struct v4l2_crop *p=arg; | ||
1197 | if (!vfd->vidioc_s_crop) | ||
1198 | break; | ||
1199 | dbgarg(cmd, "type=%d\n", p->type); | ||
1200 | dbgrect(vfd, "", &p->c); | ||
1201 | ret=vfd->vidioc_s_crop(file, fh, p); | ||
1202 | break; | ||
1203 | } | ||
1204 | case VIDIOC_CROPCAP: | ||
1205 | { | ||
1206 | struct v4l2_cropcap *p=arg; | ||
1207 | /*FIXME: Should also show v4l2_fract pixelaspect */ | ||
1208 | if (!vfd->vidioc_cropcap) | ||
1209 | break; | ||
1210 | dbgarg(cmd, "type=%d\n", p->type); | ||
1211 | dbgrect(vfd, "bounds ", &p->bounds); | ||
1212 | dbgrect(vfd, "defrect ", &p->defrect); | ||
1213 | ret=vfd->vidioc_cropcap(file, fh, p); | ||
1214 | break; | ||
1215 | } | ||
1216 | case VIDIOC_G_MPEGCOMP: | ||
1217 | { | ||
1218 | struct v4l2_mpeg_compression *p=arg; | ||
1219 | |||
1220 | /*FIXME: Several fields not shown */ | ||
1221 | if (!vfd->vidioc_g_mpegcomp) | ||
1222 | break; | ||
1223 | ret=vfd->vidioc_g_mpegcomp(file, fh, p); | ||
1224 | if (!ret) | ||
1225 | dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d," | ||
1226 | " ts_pid_video=%d, ts_pid_pcr=%d, " | ||
1227 | "ps_size=%d, au_sample_rate=%d, " | ||
1228 | "au_pesid=%c, vi_frame_rate=%d, " | ||
1229 | "vi_frames_per_gop=%d, " | ||
1230 | "vi_bframes_count=%d, vi_pesid=%c\n", | ||
1231 | p->ts_pid_pmt,p->ts_pid_audio, | ||
1232 | p->ts_pid_video,p->ts_pid_pcr, | ||
1233 | p->ps_size, p->au_sample_rate, | ||
1234 | p->au_pesid, p->vi_frame_rate, | ||
1235 | p->vi_frames_per_gop, | ||
1236 | p->vi_bframes_count, p->vi_pesid); | ||
1237 | break; | ||
1238 | } | ||
1239 | case VIDIOC_S_MPEGCOMP: | ||
1240 | { | ||
1241 | struct v4l2_mpeg_compression *p=arg; | ||
1242 | /*FIXME: Several fields not shown */ | ||
1243 | if (!vfd->vidioc_s_mpegcomp) | ||
1244 | break; | ||
1245 | dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d, " | ||
1246 | "ts_pid_video=%d, ts_pid_pcr=%d, ps_size=%d, " | ||
1247 | "au_sample_rate=%d, au_pesid=%c, " | ||
1248 | "vi_frame_rate=%d, vi_frames_per_gop=%d, " | ||
1249 | "vi_bframes_count=%d, vi_pesid=%c\n", | ||
1250 | p->ts_pid_pmt,p->ts_pid_audio, p->ts_pid_video, | ||
1251 | p->ts_pid_pcr, p->ps_size, p->au_sample_rate, | ||
1252 | p->au_pesid, p->vi_frame_rate, | ||
1253 | p->vi_frames_per_gop, p->vi_bframes_count, | ||
1254 | p->vi_pesid); | ||
1255 | ret=vfd->vidioc_s_mpegcomp(file, fh, p); | ||
1256 | break; | ||
1257 | } | ||
1258 | case VIDIOC_G_JPEGCOMP: | ||
1259 | { | ||
1260 | struct v4l2_jpegcompression *p=arg; | ||
1261 | if (!vfd->vidioc_g_jpegcomp) | ||
1262 | break; | ||
1263 | ret=vfd->vidioc_g_jpegcomp(file, fh, p); | ||
1264 | if (!ret) | ||
1265 | dbgarg (cmd, "quality=%d, APPn=%d, " | ||
1266 | "APP_len=%d, COM_len=%d, " | ||
1267 | "jpeg_markers=%d\n", | ||
1268 | p->quality,p->APPn,p->APP_len, | ||
1269 | p->COM_len,p->jpeg_markers); | ||
1270 | break; | ||
1271 | } | ||
1272 | case VIDIOC_S_JPEGCOMP: | ||
1273 | { | ||
1274 | struct v4l2_jpegcompression *p=arg; | ||
1275 | if (!vfd->vidioc_g_jpegcomp) | ||
1276 | break; | ||
1277 | dbgarg (cmd, "quality=%d, APPn=%d, APP_len=%d, " | ||
1278 | "COM_len=%d, jpeg_markers=%d\n", | ||
1279 | p->quality,p->APPn,p->APP_len, | ||
1280 | p->COM_len,p->jpeg_markers); | ||
1281 | ret=vfd->vidioc_s_jpegcomp(file, fh, p); | ||
1282 | break; | ||
1283 | } | ||
1284 | case VIDIOC_G_PARM: | ||
1285 | { | ||
1286 | struct v4l2_streamparm *p=arg; | ||
1287 | if (!vfd->vidioc_g_parm) | ||
1288 | break; | ||
1289 | ret=vfd->vidioc_g_parm(file, fh, p); | ||
1290 | dbgarg (cmd, "type=%d\n", p->type); | ||
1291 | break; | ||
1292 | } | ||
1293 | case VIDIOC_S_PARM: | ||
1294 | { | ||
1295 | struct v4l2_streamparm *p=arg; | ||
1296 | if (!vfd->vidioc_s_parm) | ||
1297 | break; | ||
1298 | dbgarg (cmd, "type=%d\n", p->type); | ||
1299 | ret=vfd->vidioc_s_parm(file, fh, p); | ||
1300 | break; | ||
1301 | } | ||
1302 | case VIDIOC_G_TUNER: | ||
1303 | { | ||
1304 | struct v4l2_tuner *p=arg; | ||
1305 | if (!vfd->vidioc_g_tuner) | ||
1306 | break; | ||
1307 | ret=vfd->vidioc_g_tuner(file, fh, p); | ||
1308 | if (!ret) | ||
1309 | dbgarg (cmd, "index=%d, name=%s, type=%d, " | ||
1310 | "capability=%d, rangelow=%d, " | ||
1311 | "rangehigh=%d, signal=%d, afc=%d, " | ||
1312 | "rxsubchans=%d, audmode=%d\n", | ||
1313 | p->index, p->name, p->type, | ||
1314 | p->capability, p->rangelow, | ||
1315 | p->rangehigh, p->rxsubchans, | ||
1316 | p->audmode, p->signal, p->afc); | ||
1317 | break; | ||
1318 | } | ||
1319 | case VIDIOC_S_TUNER: | ||
1320 | { | ||
1321 | struct v4l2_tuner *p=arg; | ||
1322 | if (!vfd->vidioc_s_tuner) | ||
1323 | break; | ||
1324 | dbgarg (cmd, "index=%d, name=%s, type=%d, " | ||
1325 | "capability=%d, rangelow=%d, rangehigh=%d, " | ||
1326 | "signal=%d, afc=%d, rxsubchans=%d, " | ||
1327 | "audmode=%d\n",p->index, p->name, p->type, | ||
1328 | p->capability, p->rangelow,p->rangehigh, | ||
1329 | p->rxsubchans, p->audmode, p->signal, | ||
1330 | p->afc); | ||
1331 | ret=vfd->vidioc_s_tuner(file, fh, p); | ||
1332 | break; | ||
1333 | } | ||
1334 | case VIDIOC_G_FREQUENCY: | ||
1335 | { | ||
1336 | struct v4l2_frequency *p=arg; | ||
1337 | if (!vfd->vidioc_g_frequency) | ||
1338 | break; | ||
1339 | ret=vfd->vidioc_g_frequency(file, fh, p); | ||
1340 | if (!ret) | ||
1341 | dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n", | ||
1342 | p->tuner,p->type,p->frequency); | ||
1343 | break; | ||
1344 | } | ||
1345 | case VIDIOC_S_FREQUENCY: | ||
1346 | { | ||
1347 | struct v4l2_frequency *p=arg; | ||
1348 | if (!vfd->vidioc_s_frequency) | ||
1349 | break; | ||
1350 | dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n", | ||
1351 | p->tuner,p->type,p->frequency); | ||
1352 | ret=vfd->vidioc_s_frequency(file, fh, p); | ||
1353 | break; | ||
1354 | } | ||
1355 | case VIDIOC_G_SLICED_VBI_CAP: | ||
1356 | { | ||
1357 | struct v4l2_sliced_vbi_cap *p=arg; | ||
1358 | if (!vfd->vidioc_g_sliced_vbi_cap) | ||
1359 | break; | ||
1360 | ret=vfd->vidioc_g_sliced_vbi_cap(file, fh, p); | ||
1361 | if (!ret) | ||
1362 | dbgarg (cmd, "service_set=%d\n", p->service_set); | ||
1363 | break; | ||
1364 | } | ||
1365 | case VIDIOC_LOG_STATUS: | ||
1366 | { | ||
1367 | if (!vfd->vidioc_log_status) | ||
1368 | break; | ||
1369 | ret=vfd->vidioc_log_status(file, fh); | ||
1370 | break; | ||
1371 | } | ||
1372 | |||
1373 | /* --- Others --------------------------------------------- */ | ||
1374 | |||
1375 | default: | ||
1376 | ret=v4l_compat_translate_ioctl(inode,file,cmd,arg,__video_do_ioctl); | ||
1377 | } | ||
1378 | |||
1379 | if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { | ||
1380 | if (ret<0) { | ||
1381 | printk ("%s: err:\n", vfd->name); | ||
1382 | v4l_print_ioctl(vfd->name, cmd); | ||
1383 | } | ||
1384 | } | ||
1385 | |||
1386 | return ret; | ||
1387 | } | ||
1388 | |||
1389 | int video_ioctl2 (struct inode *inode, struct file *file, | ||
1390 | unsigned int cmd, unsigned long arg) | ||
1391 | { | ||
1392 | char sbuf[128]; | ||
1393 | void *mbuf = NULL; | ||
1394 | void *parg = NULL; | ||
1395 | int err = -EINVAL; | ||
1396 | int is_ext_ctrl; | ||
1397 | size_t ctrls_size = 0; | ||
1398 | void __user *user_ptr = NULL; | ||
1399 | |||
1400 | #ifdef __OLD_VIDIOC_ | ||
1401 | cmd = video_fix_command(cmd); | ||
1402 | #endif | ||
1403 | is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || | ||
1404 | cmd == VIDIOC_TRY_EXT_CTRLS); | ||
1405 | |||
1406 | /* Copy arguments into temp kernel buffer */ | ||
1407 | switch (_IOC_DIR(cmd)) { | ||
1408 | case _IOC_NONE: | ||
1409 | parg = NULL; | ||
1410 | break; | ||
1411 | case _IOC_READ: | ||
1412 | case _IOC_WRITE: | ||
1413 | case (_IOC_WRITE | _IOC_READ): | ||
1414 | if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { | ||
1415 | parg = sbuf; | ||
1416 | } else { | ||
1417 | /* too big to allocate from stack */ | ||
1418 | mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); | ||
1419 | if (NULL == mbuf) | ||
1420 | return -ENOMEM; | ||
1421 | parg = mbuf; | ||
1422 | } | ||
1423 | |||
1424 | err = -EFAULT; | ||
1425 | if (_IOC_DIR(cmd) & _IOC_WRITE) | ||
1426 | if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) | ||
1427 | goto out; | ||
1428 | break; | ||
1429 | } | ||
1430 | |||
1431 | if (is_ext_ctrl) { | ||
1432 | struct v4l2_ext_controls *p = parg; | ||
1433 | |||
1434 | /* In case of an error, tell the caller that it wasn't | ||
1435 | a specific control that caused it. */ | ||
1436 | p->error_idx = p->count; | ||
1437 | user_ptr = (void __user *)p->controls; | ||
1438 | if (p->count) { | ||
1439 | ctrls_size = sizeof(struct v4l2_ext_control) * p->count; | ||
1440 | /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */ | ||
1441 | mbuf = kmalloc(ctrls_size, GFP_KERNEL); | ||
1442 | err = -ENOMEM; | ||
1443 | if (NULL == mbuf) | ||
1444 | goto out_ext_ctrl; | ||
1445 | err = -EFAULT; | ||
1446 | if (copy_from_user(mbuf, user_ptr, ctrls_size)) | ||
1447 | goto out_ext_ctrl; | ||
1448 | p->controls = mbuf; | ||
1449 | } | ||
1450 | } | ||
1451 | |||
1452 | /* Handles IOCTL */ | ||
1453 | err = __video_do_ioctl(inode, file, cmd, parg); | ||
1454 | if (err == -ENOIOCTLCMD) | ||
1455 | err = -EINVAL; | ||
1456 | if (is_ext_ctrl) { | ||
1457 | struct v4l2_ext_controls *p = parg; | ||
1458 | |||
1459 | p->controls = (void *)user_ptr; | ||
1460 | if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size)) | ||
1461 | err = -EFAULT; | ||
1462 | goto out_ext_ctrl; | ||
1463 | } | ||
1464 | if (err < 0) | ||
1465 | goto out; | ||
1466 | |||
1467 | out_ext_ctrl: | ||
1468 | /* Copy results into user buffer */ | ||
1469 | switch (_IOC_DIR(cmd)) | ||
1470 | { | ||
1471 | case _IOC_READ: | ||
1472 | case (_IOC_WRITE | _IOC_READ): | ||
1473 | if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) | ||
1474 | err = -EFAULT; | ||
1475 | break; | ||
1476 | } | ||
1477 | |||
1478 | out: | ||
1479 | kfree(mbuf); | ||
1480 | return err; | ||
1481 | } | ||
1482 | |||
1483 | |||
245 | static struct file_operations video_fops; | 1484 | static struct file_operations video_fops; |
246 | 1485 | ||
247 | /** | 1486 | /** |
@@ -371,7 +1610,9 @@ void video_unregister_device(struct video_device *vfd) | |||
371 | mutex_unlock(&videodev_lock); | 1610 | mutex_unlock(&videodev_lock); |
372 | } | 1611 | } |
373 | 1612 | ||
374 | 1613 | /* | |
1614 | * Video fs operations | ||
1615 | */ | ||
375 | static struct file_operations video_fops= | 1616 | static struct file_operations video_fops= |
376 | { | 1617 | { |
377 | .owner = THIS_MODULE, | 1618 | .owner = THIS_MODULE, |
@@ -387,7 +1628,7 @@ static int __init videodev_init(void) | |||
387 | { | 1628 | { |
388 | int ret; | 1629 | int ret; |
389 | 1630 | ||
390 | printk(KERN_INFO "Linux video capture interface: v1.00\n"); | 1631 | printk(KERN_INFO "Linux video capture interface: v2.00\n"); |
391 | if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) { | 1632 | if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) { |
392 | printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR); | 1633 | printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR); |
393 | return -EIO; | 1634 | return -EIO; |
@@ -418,11 +1659,12 @@ EXPORT_SYMBOL(video_devdata); | |||
418 | EXPORT_SYMBOL(video_usercopy); | 1659 | EXPORT_SYMBOL(video_usercopy); |
419 | EXPORT_SYMBOL(video_exclusive_open); | 1660 | EXPORT_SYMBOL(video_exclusive_open); |
420 | EXPORT_SYMBOL(video_exclusive_release); | 1661 | EXPORT_SYMBOL(video_exclusive_release); |
1662 | EXPORT_SYMBOL(video_ioctl2); | ||
421 | EXPORT_SYMBOL(video_device_alloc); | 1663 | EXPORT_SYMBOL(video_device_alloc); |
422 | EXPORT_SYMBOL(video_device_release); | 1664 | EXPORT_SYMBOL(video_device_release); |
423 | 1665 | ||
424 | MODULE_AUTHOR("Alan Cox"); | 1666 | MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>"); |
425 | MODULE_DESCRIPTION("Device registrar for Video4Linux drivers"); | 1667 | MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2"); |
426 | MODULE_LICENSE("GPL"); | 1668 | MODULE_LICENSE("GPL"); |
427 | 1669 | ||
428 | 1670 | ||