blob: 0fbe8a1a91b3681812216edd62880585a2f66d07 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03002 * Video capture interface for Linux version 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03004 * A generic video device interface for the LINUX operating system
5 * using a set of device structures/vectors for low level operations.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 *
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03007 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 *
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030012 * Authors: Alan Cox, <alan@redhat.com> (version 1)
13 * Mauro Carvalho Chehab <mchehab@infradead.org> (version 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 *
15 * Fixes: 20000516 Claudio Matsuoka <claudio@conectiva.com>
16 * - Added procfs support
17 */
18
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030019#define dbgarg(cmd, fmt, arg...) \
Enrico Scholz474ce782006-10-09 16:27:05 -030020 if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030021 printk (KERN_DEBUG "%s: ", vfd->name); \
22 v4l_printk_ioctl(cmd); \
Enrico Scholz474ce782006-10-09 16:27:05 -030023 printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg); \
24 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030025
26#define dbgarg2(fmt, arg...) \
27 if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \
28 printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
29
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/module.h>
31#include <linux/types.h>
32#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/mm.h>
34#include <linux/string.h>
35#include <linux/errno.h>
36#include <linux/init.h>
37#include <linux/kmod.h>
38#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <asm/uaccess.h>
40#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030042#define __OLD_VIDIOC_ /* To allow fixing old calls*/
43#include <linux/videodev2.h>
44
45#ifdef CONFIG_VIDEO_V4L1
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <linux/videodev.h>
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030047#endif
48#include <media/v4l2-common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50#define VIDEO_NUM_DEVICES 256
51#define VIDEO_NAME "video4linux"
52
53/*
54 * sysfs stuff
55 */
56
Kay Sievers54bd5b62007-10-08 16:26:13 -030057static ssize_t show_name(struct device *cd,
58 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070059{
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030060 struct video_device *vfd = container_of(cd, struct video_device,
Kay Sievers54bd5b62007-10-08 16:26:13 -030061 class_dev);
62 return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063}
64
Linus Torvalds1da177e2005-04-16 15:20:36 -070065struct video_device *video_device_alloc(void)
66{
67 struct video_device *vfd;
68
Panagiotis Issaris74081872006-01-11 19:40:56 -020069 vfd = kzalloc(sizeof(*vfd),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 return vfd;
71}
72
73void video_device_release(struct video_device *vfd)
74{
75 kfree(vfd);
76}
77
Kay Sievers54bd5b62007-10-08 16:26:13 -030078static void video_release(struct device *cd)
Linus Torvalds1da177e2005-04-16 15:20:36 -070079{
Kay Sievers54bd5b62007-10-08 16:26:13 -030080 struct video_device *vfd = container_of(cd, struct video_device, class_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
Mauro Carvalho Chehabd21838d2006-01-09 15:25:21 -020082#if 1
Michael Krufky50c25ff2006-01-09 15:25:34 -020083 /* needed until all drivers are fixed */
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 if (!vfd->release)
85 return;
86#endif
87 vfd->release(vfd);
88}
89
Kay Sievers54bd5b62007-10-08 16:26:13 -030090static struct device_attribute video_device_attrs[] = {
91 __ATTR(name, S_IRUGO, show_name, NULL),
92 __ATTR_NULL
93};
94
Linus Torvalds1da177e2005-04-16 15:20:36 -070095static struct class video_class = {
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -080096 .name = VIDEO_NAME,
Kay Sievers54bd5b62007-10-08 16:26:13 -030097 .dev_attrs = video_device_attrs,
98 .dev_release = video_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -070099};
100
101/*
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800102 * Active devices
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800104
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105static struct video_device *video_device[VIDEO_NUM_DEVICES];
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200106static DEFINE_MUTEX(videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
108struct video_device* video_devdata(struct file *file)
109{
Josef Sipek723731b2006-12-08 02:37:47 -0800110 return video_device[iminor(file->f_path.dentry->d_inode)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111}
112
113/*
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300114 * Open a video device - FIXME: Obsoleted
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 */
116static int video_open(struct inode *inode, struct file *file)
117{
118 unsigned int minor = iminor(inode);
119 int err = 0;
120 struct video_device *vfl;
Arjan van de Ven99ac48f2006-03-28 01:56:41 -0800121 const struct file_operations *old_fops;
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800122
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 if(minor>=VIDEO_NUM_DEVICES)
124 return -ENODEV;
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200125 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 vfl=video_device[minor];
127 if(vfl==NULL) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200128 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 request_module("char-major-%d-%d", VIDEO_MAJOR, minor);
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200130 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 vfl=video_device[minor];
132 if (vfl==NULL) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200133 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 return -ENODEV;
135 }
136 }
137 old_fops = file->f_op;
138 file->f_op = fops_get(vfl->fops);
139 if(file->f_op->open)
140 err = file->f_op->open(inode,file);
141 if (err) {
142 fops_put(file->f_op);
143 file->f_op = fops_get(old_fops);
144 }
145 fops_put(old_fops);
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200146 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 return err;
148}
149
150/*
151 * helper function -- handles userspace copying for ioctl arguments
152 */
153
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300154#ifdef __OLD_VIDIOC_
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155static unsigned int
156video_fix_command(unsigned int cmd)
157{
158 switch (cmd) {
159 case VIDIOC_OVERLAY_OLD:
160 cmd = VIDIOC_OVERLAY;
161 break;
162 case VIDIOC_S_PARM_OLD:
163 cmd = VIDIOC_S_PARM;
164 break;
165 case VIDIOC_S_CTRL_OLD:
166 cmd = VIDIOC_S_CTRL;
167 break;
168 case VIDIOC_G_AUDIO_OLD:
169 cmd = VIDIOC_G_AUDIO;
170 break;
171 case VIDIOC_G_AUDOUT_OLD:
172 cmd = VIDIOC_G_AUDOUT;
173 break;
174 case VIDIOC_CROPCAP_OLD:
175 cmd = VIDIOC_CROPCAP;
176 break;
177 }
178 return cmd;
179}
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300180#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300182/*
183 * Obsolete usercopy function - Should be removed soon
184 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185int
186video_usercopy(struct inode *inode, struct file *file,
187 unsigned int cmd, unsigned long arg,
188 int (*func)(struct inode *inode, struct file *file,
189 unsigned int cmd, void *arg))
190{
191 char sbuf[128];
192 void *mbuf = NULL;
193 void *parg = NULL;
194 int err = -EINVAL;
Hans Verkuil05976912006-06-18 13:43:28 -0300195 int is_ext_ctrl;
196 size_t ctrls_size = 0;
197 void __user *user_ptr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300199#ifdef __OLD_VIDIOC_
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 cmd = video_fix_command(cmd);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300201#endif
Hans Verkuil05976912006-06-18 13:43:28 -0300202 is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
203 cmd == VIDIOC_TRY_EXT_CTRLS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
205 /* Copy arguments into temp kernel buffer */
206 switch (_IOC_DIR(cmd)) {
207 case _IOC_NONE:
208 parg = NULL;
209 break;
210 case _IOC_READ:
211 case _IOC_WRITE:
212 case (_IOC_WRITE | _IOC_READ):
213 if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
214 parg = sbuf;
215 } else {
216 /* too big to allocate from stack */
217 mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
218 if (NULL == mbuf)
219 return -ENOMEM;
220 parg = mbuf;
221 }
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 err = -EFAULT;
224 if (_IOC_DIR(cmd) & _IOC_WRITE)
Hans Verkuil05976912006-06-18 13:43:28 -0300225 if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 goto out;
227 break;
228 }
Hans Verkuil05976912006-06-18 13:43:28 -0300229 if (is_ext_ctrl) {
230 struct v4l2_ext_controls *p = parg;
231
232 /* In case of an error, tell the caller that it wasn't
233 a specific control that caused it. */
234 p->error_idx = p->count;
235 user_ptr = (void __user *)p->controls;
236 if (p->count) {
237 ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
238 /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
239 mbuf = kmalloc(ctrls_size, GFP_KERNEL);
240 err = -ENOMEM;
241 if (NULL == mbuf)
242 goto out_ext_ctrl;
243 err = -EFAULT;
244 if (copy_from_user(mbuf, user_ptr, ctrls_size))
245 goto out_ext_ctrl;
246 p->controls = mbuf;
247 }
248 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
250 /* call driver */
251 err = func(inode, file, cmd, parg);
252 if (err == -ENOIOCTLCMD)
253 err = -EINVAL;
Hans Verkuil05976912006-06-18 13:43:28 -0300254 if (is_ext_ctrl) {
255 struct v4l2_ext_controls *p = parg;
256
257 p->controls = (void *)user_ptr;
258 if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
259 err = -EFAULT;
260 goto out_ext_ctrl;
261 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 if (err < 0)
263 goto out;
264
Hans Verkuil05976912006-06-18 13:43:28 -0300265out_ext_ctrl:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 /* Copy results into user buffer */
267 switch (_IOC_DIR(cmd))
268 {
269 case _IOC_READ:
270 case (_IOC_WRITE | _IOC_READ):
271 if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
272 err = -EFAULT;
273 break;
274 }
275
276out:
Jesper Juhl2ea75332005-11-07 01:01:31 -0800277 kfree(mbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 return err;
279}
280
281/*
282 * open/release helper functions -- handle exclusive opens
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300283 * Should be removed soon
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 */
285int video_exclusive_open(struct inode *inode, struct file *file)
286{
287 struct video_device *vfl = video_devdata(file);
288 int retval = 0;
289
Ingo Molnar3593cab2006-02-07 06:49:14 -0200290 mutex_lock(&vfl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 if (vfl->users) {
292 retval = -EBUSY;
293 } else {
294 vfl->users++;
295 }
Ingo Molnar3593cab2006-02-07 06:49:14 -0200296 mutex_unlock(&vfl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 return retval;
298}
299
300int video_exclusive_release(struct inode *inode, struct file *file)
301{
302 struct video_device *vfl = video_devdata(file);
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800303
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 vfl->users--;
305 return 0;
306}
307
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300308static char *v4l2_memory_names[] = {
309 [V4L2_MEMORY_MMAP] = "mmap",
310 [V4L2_MEMORY_USERPTR] = "userptr",
311 [V4L2_MEMORY_OVERLAY] = "overlay",
312};
313
314
315/* FIXME: Those stuff are replicated also on v4l2-common.c */
316static char *v4l2_type_names_FIXME[] = {
317 [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap",
318 [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over",
319 [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out",
320 [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap",
321 [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out",
322 [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out",
323 [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-capture",
Hans Verkuilb2787842007-04-27 12:31:02 -0300324 [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over",
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300325 [V4L2_BUF_TYPE_PRIVATE] = "private",
326};
327
328static char *v4l2_field_names_FIXME[] = {
329 [V4L2_FIELD_ANY] = "any",
330 [V4L2_FIELD_NONE] = "none",
331 [V4L2_FIELD_TOP] = "top",
332 [V4L2_FIELD_BOTTOM] = "bottom",
333 [V4L2_FIELD_INTERLACED] = "interlaced",
334 [V4L2_FIELD_SEQ_TB] = "seq-tb",
335 [V4L2_FIELD_SEQ_BT] = "seq-bt",
336 [V4L2_FIELD_ALTERNATE] = "alternate",
Hans Verkuilb2787842007-04-27 12:31:02 -0300337 [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb",
338 [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt",
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300339};
340
341#define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown"
342
343static void dbgbuf(unsigned int cmd, struct video_device *vfd,
344 struct v4l2_buffer *p)
345{
346 struct v4l2_timecode *tc=&p->timecode;
347
348 dbgarg (cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, "
349 "bytesused=%d, flags=0x%08d, "
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300350 "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n",
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300351 (p->timestamp.tv_sec/3600),
352 (int)(p->timestamp.tv_sec/60)%60,
353 (int)(p->timestamp.tv_sec%60),
354 p->timestamp.tv_usec,
355 p->index,
356 prt_names(p->type,v4l2_type_names_FIXME),
357 p->bytesused,p->flags,
358 p->field,p->sequence,
359 prt_names(p->memory,v4l2_memory_names),
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300360 p->m.userptr, p->length);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300361 dbgarg2 ("timecode= %02d:%02d:%02d type=%d, "
362 "flags=0x%08d, frames=%d, userbits=0x%08x\n",
363 tc->hours,tc->minutes,tc->seconds,
Mauro Carvalho Chehabc18cb012006-06-23 07:05:22 -0300364 tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300365}
366
367static inline void dbgrect(struct video_device *vfd, char *s,
368 struct v4l2_rect *r)
369{
370 dbgarg2 ("%sRect start at %dx%d, size= %dx%d\n", s, r->left, r->top,
371 r->width, r->height);
372};
373
374static inline void v4l_print_pix_fmt (struct video_device *vfd,
375 struct v4l2_pix_format *fmt)
376{
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300377 dbgarg2 ("width=%d, height=%d, format=%c%c%c%c, field=%s, "
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300378 "bytesperline=%d sizeimage=%d, colorspace=%d\n",
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300379 fmt->width,fmt->height,
380 (fmt->pixelformat & 0xff),
381 (fmt->pixelformat >> 8) & 0xff,
382 (fmt->pixelformat >> 16) & 0xff,
383 (fmt->pixelformat >> 24) & 0xff,
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300384 prt_names(fmt->field,v4l2_field_names_FIXME),
385 fmt->bytesperline,fmt->sizeimage,fmt->colorspace);
386};
387
388
389static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type)
390{
391 switch (type) {
392 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
393 if (vfd->vidioc_try_fmt_cap)
394 return (0);
395 break;
396 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
397 if (vfd->vidioc_try_fmt_overlay)
398 return (0);
399 break;
400 case V4L2_BUF_TYPE_VBI_CAPTURE:
401 if (vfd->vidioc_try_fmt_vbi)
402 return (0);
403 break;
404 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
405 if (vfd->vidioc_try_fmt_vbi_output)
406 return (0);
407 break;
408 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
409 if (vfd->vidioc_try_fmt_vbi_capture)
410 return (0);
411 break;
412 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
413 if (vfd->vidioc_try_fmt_video_output)
414 return (0);
415 break;
416 case V4L2_BUF_TYPE_VBI_OUTPUT:
417 if (vfd->vidioc_try_fmt_vbi_output)
418 return (0);
419 break;
Hans Verkuilb2787842007-04-27 12:31:02 -0300420 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
421 if (vfd->vidioc_try_fmt_output_overlay)
422 return (0);
423 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300424 case V4L2_BUF_TYPE_PRIVATE:
425 if (vfd->vidioc_try_fmt_type_private)
426 return (0);
427 break;
428 }
429 return (-EINVAL);
430}
431
432static int __video_do_ioctl(struct inode *inode, struct file *file,
433 unsigned int cmd, void *arg)
434{
435 struct video_device *vfd = video_devdata(file);
436 void *fh = file->private_data;
437 int ret = -EINVAL;
438
439 if ( (vfd->debug & V4L2_DEBUG_IOCTL) &&
Jiri Slaby57e45b32007-05-07 10:55:49 -0300440 !(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) {
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300441 v4l_print_ioctl(vfd->name, cmd);
442 }
443
Sam Revitch1088b132007-05-01 08:46:30 -0300444#ifdef CONFIG_VIDEO_V4L1_COMPAT
Mauro Carvalho Chehab452c0fb2007-05-01 08:55:00 -0300445 /***********************************************************
446 Handles calls to the obsoleted V4L1 API
447 Due to the nature of VIDIOCGMBUF, each driver that supports
448 V4L1 should implement its own handler for this ioctl.
449 ***********************************************************/
450
Sam Revitch1088b132007-05-01 08:46:30 -0300451 /* --- streaming capture ------------------------------------- */
452 if (cmd == VIDIOCGMBUF) {
453 struct video_mbuf *p=arg;
454
Mariusz Kozlowski473c6532007-08-06 18:05:35 -0300455 memset(p, 0, sizeof(*p));
Sam Revitch1088b132007-05-01 08:46:30 -0300456
457 if (!vfd->vidiocgmbuf)
458 return ret;
459 ret=vfd->vidiocgmbuf(file, fh, p);
460 if (!ret)
461 dbgarg (cmd, "size=%d, frames=%d, offsets=0x%08lx\n",
462 p->size, p->frames,
463 (unsigned long)p->offsets);
464 return ret;
465 }
Sam Revitch1088b132007-05-01 08:46:30 -0300466
Mauro Carvalho Chehab452c0fb2007-05-01 08:55:00 -0300467 /********************************************************
468 All other V4L1 calls are handled by v4l1_compat module.
469 Those calls will be translated into V4L2 calls, and
470 __video_do_ioctl will be called again, with one or more
471 V4L2 ioctls.
472 ********************************************************/
Mauro Carvalho Chehab207705c2006-11-20 12:13:25 -0300473 if (_IOC_TYPE(cmd)=='v')
474 return v4l_compat_translate_ioctl(inode,file,cmd,arg,
475 __video_do_ioctl);
Mauro Carvalho Chehab452c0fb2007-05-01 08:55:00 -0300476#endif
Mauro Carvalho Chehab207705c2006-11-20 12:13:25 -0300477
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300478 switch(cmd) {
479 /* --- capabilities ------------------------------------------ */
480 case VIDIOC_QUERYCAP:
481 {
482 struct v4l2_capability *cap = (struct v4l2_capability*)arg;
483 memset(cap, 0, sizeof(*cap));
484
485 if (!vfd->vidioc_querycap)
486 break;
487
488 ret=vfd->vidioc_querycap(file, fh, cap);
489 if (!ret)
490 dbgarg (cmd, "driver=%s, card=%s, bus=%s, "
491 "version=0x%08x, "
492 "capabilities=0x%08x\n",
493 cap->driver,cap->card,cap->bus_info,
494 cap->version,
495 cap->capabilities);
496 break;
497 }
498
499 /* --- priority ------------------------------------------ */
500 case VIDIOC_G_PRIORITY:
501 {
502 enum v4l2_priority *p=arg;
503
504 if (!vfd->vidioc_g_priority)
505 break;
506 ret=vfd->vidioc_g_priority(file, fh, p);
507 if (!ret)
508 dbgarg(cmd, "priority is %d\n", *p);
509 break;
510 }
511 case VIDIOC_S_PRIORITY:
512 {
513 enum v4l2_priority *p=arg;
514
515 if (!vfd->vidioc_s_priority)
516 break;
517 dbgarg(cmd, "setting priority to %d\n", *p);
518 ret=vfd->vidioc_s_priority(file, fh, *p);
519 break;
520 }
521
522 /* --- capture ioctls ---------------------------------------- */
523 case VIDIOC_ENUM_FMT:
524 {
525 struct v4l2_fmtdesc *f = arg;
526 enum v4l2_buf_type type;
527 unsigned int index;
528
529 index = f->index;
530 type = f->type;
531 memset(f,0,sizeof(*f));
532 f->index = index;
533 f->type = type;
534
535 switch (type) {
536 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
537 if (vfd->vidioc_enum_fmt_cap)
538 ret=vfd->vidioc_enum_fmt_cap(file, fh, f);
539 break;
540 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
541 if (vfd->vidioc_enum_fmt_overlay)
542 ret=vfd->vidioc_enum_fmt_overlay(file, fh, f);
543 break;
544 case V4L2_BUF_TYPE_VBI_CAPTURE:
545 if (vfd->vidioc_enum_fmt_vbi)
546 ret=vfd->vidioc_enum_fmt_vbi(file, fh, f);
547 break;
548 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
549 if (vfd->vidioc_enum_fmt_vbi_output)
550 ret=vfd->vidioc_enum_fmt_vbi_output(file,
551 fh, f);
552 break;
553 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
554 if (vfd->vidioc_enum_fmt_vbi_capture)
555 ret=vfd->vidioc_enum_fmt_vbi_capture(file,
556 fh, f);
557 break;
558 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
559 if (vfd->vidioc_enum_fmt_video_output)
560 ret=vfd->vidioc_enum_fmt_video_output(file,
561 fh, f);
562 break;
563 case V4L2_BUF_TYPE_VBI_OUTPUT:
564 if (vfd->vidioc_enum_fmt_vbi_output)
565 ret=vfd->vidioc_enum_fmt_vbi_output(file,
566 fh, f);
567 break;
Hans Verkuilb2787842007-04-27 12:31:02 -0300568 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
569 if (vfd->vidioc_enum_fmt_output_overlay)
570 ret=vfd->vidioc_enum_fmt_output_overlay(file, fh, f);
571 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300572 case V4L2_BUF_TYPE_PRIVATE:
573 if (vfd->vidioc_enum_fmt_type_private)
574 ret=vfd->vidioc_enum_fmt_type_private(file,
575 fh, f);
576 break;
577 }
578 if (!ret)
579 dbgarg (cmd, "index=%d, type=%d, flags=%d, "
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300580 "pixelformat=%c%c%c%c, description='%s'\n",
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300581 f->index, f->type, f->flags,
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300582 (f->pixelformat & 0xff),
583 (f->pixelformat >> 8) & 0xff,
584 (f->pixelformat >> 16) & 0xff,
585 (f->pixelformat >> 24) & 0xff,
586 f->description);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300587 break;
588 }
589 case VIDIOC_G_FMT:
590 {
591 struct v4l2_format *f = (struct v4l2_format *)arg;
592 enum v4l2_buf_type type=f->type;
593
594 memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
595 f->type=type;
596
597 /* FIXME: Should be one dump per type */
598 dbgarg (cmd, "type=%s\n", prt_names(type,
599 v4l2_type_names_FIXME));
600
601 switch (type) {
602 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
603 if (vfd->vidioc_g_fmt_cap)
604 ret=vfd->vidioc_g_fmt_cap(file, fh, f);
605 if (!ret)
606 v4l_print_pix_fmt(vfd,&f->fmt.pix);
607 break;
608 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
609 if (vfd->vidioc_g_fmt_overlay)
610 ret=vfd->vidioc_g_fmt_overlay(file, fh, f);
611 break;
612 case V4L2_BUF_TYPE_VBI_CAPTURE:
613 if (vfd->vidioc_g_fmt_vbi)
614 ret=vfd->vidioc_g_fmt_vbi(file, fh, f);
615 break;
616 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
617 if (vfd->vidioc_g_fmt_vbi_output)
618 ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
619 break;
620 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
621 if (vfd->vidioc_g_fmt_vbi_capture)
622 ret=vfd->vidioc_g_fmt_vbi_capture(file, fh, f);
623 break;
624 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
625 if (vfd->vidioc_g_fmt_video_output)
626 ret=vfd->vidioc_g_fmt_video_output(file,
627 fh, f);
628 break;
Hans Verkuilb2787842007-04-27 12:31:02 -0300629 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
630 if (vfd->vidioc_g_fmt_output_overlay)
631 ret=vfd->vidioc_g_fmt_output_overlay(file, fh, f);
632 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300633 case V4L2_BUF_TYPE_VBI_OUTPUT:
634 if (vfd->vidioc_g_fmt_vbi_output)
635 ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
636 break;
637 case V4L2_BUF_TYPE_PRIVATE:
638 if (vfd->vidioc_g_fmt_type_private)
639 ret=vfd->vidioc_g_fmt_type_private(file,
640 fh, f);
641 break;
642 }
643
644 break;
645 }
646 case VIDIOC_S_FMT:
647 {
648 struct v4l2_format *f = (struct v4l2_format *)arg;
649
650 /* FIXME: Should be one dump per type */
651 dbgarg (cmd, "type=%s\n", prt_names(f->type,
652 v4l2_type_names_FIXME));
653
654 switch (f->type) {
655 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
656 v4l_print_pix_fmt(vfd,&f->fmt.pix);
657 if (vfd->vidioc_s_fmt_cap)
658 ret=vfd->vidioc_s_fmt_cap(file, fh, f);
659 break;
660 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
661 if (vfd->vidioc_s_fmt_overlay)
662 ret=vfd->vidioc_s_fmt_overlay(file, fh, f);
663 break;
664 case V4L2_BUF_TYPE_VBI_CAPTURE:
665 if (vfd->vidioc_s_fmt_vbi)
666 ret=vfd->vidioc_s_fmt_vbi(file, fh, f);
667 break;
668 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
669 if (vfd->vidioc_s_fmt_vbi_output)
670 ret=vfd->vidioc_s_fmt_vbi_output(file, fh, f);
671 break;
672 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
673 if (vfd->vidioc_s_fmt_vbi_capture)
674 ret=vfd->vidioc_s_fmt_vbi_capture(file, fh, f);
675 break;
676 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
677 if (vfd->vidioc_s_fmt_video_output)
678 ret=vfd->vidioc_s_fmt_video_output(file,
679 fh, f);
680 break;
Hans Verkuilb2787842007-04-27 12:31:02 -0300681 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
682 if (vfd->vidioc_s_fmt_output_overlay)
683 ret=vfd->vidioc_s_fmt_output_overlay(file, fh, f);
684 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300685 case V4L2_BUF_TYPE_VBI_OUTPUT:
686 if (vfd->vidioc_s_fmt_vbi_output)
687 ret=vfd->vidioc_s_fmt_vbi_output(file,
688 fh, f);
689 break;
690 case V4L2_BUF_TYPE_PRIVATE:
691 if (vfd->vidioc_s_fmt_type_private)
692 ret=vfd->vidioc_s_fmt_type_private(file,
693 fh, f);
694 break;
695 }
696 break;
697 }
698 case VIDIOC_TRY_FMT:
699 {
700 struct v4l2_format *f = (struct v4l2_format *)arg;
701
702 /* FIXME: Should be one dump per type */
703 dbgarg (cmd, "type=%s\n", prt_names(f->type,
704 v4l2_type_names_FIXME));
705 switch (f->type) {
706 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
707 if (vfd->vidioc_try_fmt_cap)
708 ret=vfd->vidioc_try_fmt_cap(file, fh, f);
709 if (!ret)
710 v4l_print_pix_fmt(vfd,&f->fmt.pix);
711 break;
712 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
713 if (vfd->vidioc_try_fmt_overlay)
714 ret=vfd->vidioc_try_fmt_overlay(file, fh, f);
715 break;
716 case V4L2_BUF_TYPE_VBI_CAPTURE:
717 if (vfd->vidioc_try_fmt_vbi)
718 ret=vfd->vidioc_try_fmt_vbi(file, fh, f);
719 break;
720 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
721 if (vfd->vidioc_try_fmt_vbi_output)
722 ret=vfd->vidioc_try_fmt_vbi_output(file,
723 fh, f);
724 break;
725 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
726 if (vfd->vidioc_try_fmt_vbi_capture)
727 ret=vfd->vidioc_try_fmt_vbi_capture(file,
728 fh, f);
729 break;
730 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
731 if (vfd->vidioc_try_fmt_video_output)
732 ret=vfd->vidioc_try_fmt_video_output(file,
733 fh, f);
734 break;
Hans Verkuilb2787842007-04-27 12:31:02 -0300735 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
736 if (vfd->vidioc_try_fmt_output_overlay)
737 ret=vfd->vidioc_try_fmt_output_overlay(file, fh, f);
738 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300739 case V4L2_BUF_TYPE_VBI_OUTPUT:
740 if (vfd->vidioc_try_fmt_vbi_output)
741 ret=vfd->vidioc_try_fmt_vbi_output(file,
742 fh, f);
743 break;
744 case V4L2_BUF_TYPE_PRIVATE:
745 if (vfd->vidioc_try_fmt_type_private)
746 ret=vfd->vidioc_try_fmt_type_private(file,
747 fh, f);
748 break;
749 }
750
751 break;
752 }
753 /* FIXME: Those buf reqs could be handled here,
754 with some changes on videobuf to allow its header to be included at
755 videodev2.h or being merged at videodev2.
756 */
757 case VIDIOC_REQBUFS:
758 {
759 struct v4l2_requestbuffers *p=arg;
760
761 if (!vfd->vidioc_reqbufs)
762 break;
763 ret = check_fmt (vfd, p->type);
764 if (ret)
765 break;
766
767 ret=vfd->vidioc_reqbufs(file, fh, p);
768 dbgarg (cmd, "count=%d, type=%s, memory=%s\n",
769 p->count,
770 prt_names(p->type,v4l2_type_names_FIXME),
771 prt_names(p->memory,v4l2_memory_names));
772 break;
773 }
774 case VIDIOC_QUERYBUF:
775 {
776 struct v4l2_buffer *p=arg;
777
778 if (!vfd->vidioc_querybuf)
779 break;
780 ret = check_fmt (vfd, p->type);
781 if (ret)
782 break;
783
784 ret=vfd->vidioc_querybuf(file, fh, p);
785 if (!ret)
786 dbgbuf(cmd,vfd,p);
787 break;
788 }
789 case VIDIOC_QBUF:
790 {
791 struct v4l2_buffer *p=arg;
792
793 if (!vfd->vidioc_qbuf)
794 break;
795 ret = check_fmt (vfd, p->type);
796 if (ret)
797 break;
798
799 ret=vfd->vidioc_qbuf(file, fh, p);
800 if (!ret)
801 dbgbuf(cmd,vfd,p);
802 break;
803 }
804 case VIDIOC_DQBUF:
805 {
806 struct v4l2_buffer *p=arg;
Sascha Hauerc93a5c32006-09-11 09:49:19 -0300807 if (!vfd->vidioc_dqbuf)
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300808 break;
809 ret = check_fmt (vfd, p->type);
810 if (ret)
811 break;
812
Sascha Hauerc93a5c32006-09-11 09:49:19 -0300813 ret=vfd->vidioc_dqbuf(file, fh, p);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300814 if (!ret)
815 dbgbuf(cmd,vfd,p);
816 break;
817 }
818 case VIDIOC_OVERLAY:
819 {
820 int *i = arg;
821
822 if (!vfd->vidioc_overlay)
823 break;
824 dbgarg (cmd, "value=%d\n",*i);
825 ret=vfd->vidioc_overlay(file, fh, *i);
826 break;
827 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300828 case VIDIOC_G_FBUF:
829 {
830 struct v4l2_framebuffer *p=arg;
831 if (!vfd->vidioc_g_fbuf)
832 break;
833 ret=vfd->vidioc_g_fbuf(file, fh, arg);
834 if (!ret) {
835 dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
836 p->capability,p->flags,
837 (unsigned long)p->base);
838 v4l_print_pix_fmt (vfd, &p->fmt);
839 }
840 break;
841 }
842 case VIDIOC_S_FBUF:
843 {
844 struct v4l2_framebuffer *p=arg;
845 if (!vfd->vidioc_s_fbuf)
846 break;
847
848 dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
849 p->capability,p->flags,(unsigned long)p->base);
850 v4l_print_pix_fmt (vfd, &p->fmt);
851 ret=vfd->vidioc_s_fbuf(file, fh, arg);
852
853 break;
854 }
855 case VIDIOC_STREAMON:
856 {
857 enum v4l2_buf_type i = *(int *)arg;
858 if (!vfd->vidioc_streamon)
859 break;
860 dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME));
861 ret=vfd->vidioc_streamon(file, fh,i);
862 break;
863 }
864 case VIDIOC_STREAMOFF:
865 {
866 enum v4l2_buf_type i = *(int *)arg;
867
868 if (!vfd->vidioc_streamoff)
869 break;
870 dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME));
871 ret=vfd->vidioc_streamoff(file, fh, i);
872 break;
873 }
874 /* ---------- tv norms ---------- */
875 case VIDIOC_ENUMSTD:
876 {
877 struct v4l2_standard *p = arg;
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300878 v4l2_std_id id = vfd->tvnorms,curr_id=0;
879 unsigned int index = p->index,i;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300880
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300881 if (index<0) {
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300882 ret=-EINVAL;
883 break;
884 }
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300885
886 /* Return norm array on a canonical way */
887 for (i=0;i<= index && id; i++) {
888 if ( (id & V4L2_STD_PAL) == V4L2_STD_PAL) {
889 curr_id = V4L2_STD_PAL;
890 } else if ( (id & V4L2_STD_PAL_BG) == V4L2_STD_PAL_BG) {
891 curr_id = V4L2_STD_PAL_BG;
892 } else if ( (id & V4L2_STD_PAL_DK) == V4L2_STD_PAL_DK) {
893 curr_id = V4L2_STD_PAL_DK;
894 } else if ( (id & V4L2_STD_PAL_B) == V4L2_STD_PAL_B) {
895 curr_id = V4L2_STD_PAL_B;
896 } else if ( (id & V4L2_STD_PAL_B1) == V4L2_STD_PAL_B1) {
897 curr_id = V4L2_STD_PAL_B1;
898 } else if ( (id & V4L2_STD_PAL_G) == V4L2_STD_PAL_G) {
899 curr_id = V4L2_STD_PAL_G;
900 } else if ( (id & V4L2_STD_PAL_H) == V4L2_STD_PAL_H) {
901 curr_id = V4L2_STD_PAL_H;
902 } else if ( (id & V4L2_STD_PAL_I) == V4L2_STD_PAL_I) {
903 curr_id = V4L2_STD_PAL_I;
904 } else if ( (id & V4L2_STD_PAL_D) == V4L2_STD_PAL_D) {
905 curr_id = V4L2_STD_PAL_D;
906 } else if ( (id & V4L2_STD_PAL_D1) == V4L2_STD_PAL_D1) {
907 curr_id = V4L2_STD_PAL_D1;
908 } else if ( (id & V4L2_STD_PAL_K) == V4L2_STD_PAL_K) {
909 curr_id = V4L2_STD_PAL_K;
910 } else if ( (id & V4L2_STD_PAL_M) == V4L2_STD_PAL_M) {
911 curr_id = V4L2_STD_PAL_M;
912 } else if ( (id & V4L2_STD_PAL_N) == V4L2_STD_PAL_N) {
913 curr_id = V4L2_STD_PAL_N;
914 } else if ( (id & V4L2_STD_PAL_Nc) == V4L2_STD_PAL_Nc) {
915 curr_id = V4L2_STD_PAL_Nc;
916 } else if ( (id & V4L2_STD_PAL_60) == V4L2_STD_PAL_60) {
917 curr_id = V4L2_STD_PAL_60;
918 } else if ( (id & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
919 curr_id = V4L2_STD_NTSC;
920 } else if ( (id & V4L2_STD_NTSC_M) == V4L2_STD_NTSC_M) {
921 curr_id = V4L2_STD_NTSC_M;
922 } else if ( (id & V4L2_STD_NTSC_M_JP) == V4L2_STD_NTSC_M_JP) {
923 curr_id = V4L2_STD_NTSC_M_JP;
924 } else if ( (id & V4L2_STD_NTSC_443) == V4L2_STD_NTSC_443) {
925 curr_id = V4L2_STD_NTSC_443;
926 } else if ( (id & V4L2_STD_NTSC_M_KR) == V4L2_STD_NTSC_M_KR) {
927 curr_id = V4L2_STD_NTSC_M_KR;
928 } else if ( (id & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
929 curr_id = V4L2_STD_SECAM;
930 } else if ( (id & V4L2_STD_SECAM_DK) == V4L2_STD_SECAM_DK) {
931 curr_id = V4L2_STD_SECAM_DK;
932 } else if ( (id & V4L2_STD_SECAM_B) == V4L2_STD_SECAM_B) {
933 curr_id = V4L2_STD_SECAM_B;
934 } else if ( (id & V4L2_STD_SECAM_D) == V4L2_STD_SECAM_D) {
935 curr_id = V4L2_STD_SECAM_D;
936 } else if ( (id & V4L2_STD_SECAM_G) == V4L2_STD_SECAM_G) {
937 curr_id = V4L2_STD_SECAM_G;
938 } else if ( (id & V4L2_STD_SECAM_H) == V4L2_STD_SECAM_H) {
939 curr_id = V4L2_STD_SECAM_H;
940 } else if ( (id & V4L2_STD_SECAM_K) == V4L2_STD_SECAM_K) {
941 curr_id = V4L2_STD_SECAM_K;
942 } else if ( (id & V4L2_STD_SECAM_K1) == V4L2_STD_SECAM_K1) {
943 curr_id = V4L2_STD_SECAM_K1;
944 } else if ( (id & V4L2_STD_SECAM_L) == V4L2_STD_SECAM_L) {
945 curr_id = V4L2_STD_SECAM_L;
946 } else if ( (id & V4L2_STD_SECAM_LC) == V4L2_STD_SECAM_LC) {
947 curr_id = V4L2_STD_SECAM_LC;
948 } else {
949 break;
950 }
951 id &= ~curr_id;
952 }
953 if (i<=index)
954 return -EINVAL;
955
956 v4l2_video_std_construct(p, curr_id,v4l2_norm_to_name(curr_id));
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300957 p->index = index;
958
959 dbgarg (cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, "
960 "framelines=%d\n", p->index,
961 (unsigned long long)p->id, p->name,
962 p->frameperiod.numerator,
963 p->frameperiod.denominator,
964 p->framelines);
965
966 ret=0;
967 break;
968 }
969 case VIDIOC_G_STD:
970 {
971 v4l2_std_id *id = arg;
972
973 *id = vfd->current_norm;
974
975 dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
976
977 ret=0;
978 break;
979 }
980 case VIDIOC_S_STD:
981 {
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300982 v4l2_std_id *id = arg,norm;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300983
984 dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
985
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300986 norm = (*id) & vfd->tvnorms;
987 if ( vfd->tvnorms && !norm) /* Check if std is supported */
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300988 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300989
990 /* Calls the specific handler */
991 if (vfd->vidioc_s_std)
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300992 ret=vfd->vidioc_s_std(file, fh, &norm);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300993 else
994 ret=-EINVAL;
995
996 /* Updates standard information */
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300997 if (ret>=0)
998 vfd->current_norm=norm;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300999
1000 break;
1001 }
1002 case VIDIOC_QUERYSTD:
1003 {
1004 v4l2_std_id *p=arg;
1005
1006 if (!vfd->vidioc_querystd)
1007 break;
1008 ret=vfd->vidioc_querystd(file, fh, arg);
1009 if (!ret)
1010 dbgarg (cmd, "detected std=%Lu\n",
1011 (unsigned long long)*p);
1012 break;
1013 }
1014 /* ------ input switching ---------- */
1015 /* FIXME: Inputs can be handled inside videodev2 */
1016 case VIDIOC_ENUMINPUT:
1017 {
1018 struct v4l2_input *p=arg;
1019 int i=p->index;
1020
1021 if (!vfd->vidioc_enum_input)
1022 break;
1023 memset(p, 0, sizeof(*p));
1024 p->index=i;
1025
1026 ret=vfd->vidioc_enum_input(file, fh, p);
1027 if (!ret)
1028 dbgarg (cmd, "index=%d, name=%s, type=%d, "
1029 "audioset=%d, "
1030 "tuner=%d, std=%Ld, status=%d\n",
1031 p->index,p->name,p->type,p->audioset,
1032 p->tuner,
1033 (unsigned long long)p->std,
1034 p->status);
1035 break;
1036 }
1037 case VIDIOC_G_INPUT:
1038 {
1039 unsigned int *i = arg;
1040
1041 if (!vfd->vidioc_g_input)
1042 break;
1043 ret=vfd->vidioc_g_input(file, fh, i);
1044 if (!ret)
1045 dbgarg (cmd, "value=%d\n",*i);
1046 break;
1047 }
1048 case VIDIOC_S_INPUT:
1049 {
1050 unsigned int *i = arg;
1051
1052 if (!vfd->vidioc_s_input)
1053 break;
1054 dbgarg (cmd, "value=%d\n",*i);
1055 ret=vfd->vidioc_s_input(file, fh, *i);
1056 break;
1057 }
1058
1059 /* ------ output switching ---------- */
1060 case VIDIOC_G_OUTPUT:
1061 {
1062 unsigned int *i = arg;
1063
1064 if (!vfd->vidioc_g_output)
1065 break;
1066 ret=vfd->vidioc_g_output(file, fh, i);
1067 if (!ret)
1068 dbgarg (cmd, "value=%d\n",*i);
1069 break;
1070 }
1071 case VIDIOC_S_OUTPUT:
1072 {
1073 unsigned int *i = arg;
1074
1075 if (!vfd->vidioc_s_output)
1076 break;
1077 dbgarg (cmd, "value=%d\n",*i);
1078 ret=vfd->vidioc_s_output(file, fh, *i);
1079 break;
1080 }
1081
1082 /* --- controls ---------------------------------------------- */
1083 case VIDIOC_QUERYCTRL:
1084 {
1085 struct v4l2_queryctrl *p=arg;
1086
1087 if (!vfd->vidioc_queryctrl)
1088 break;
1089 ret=vfd->vidioc_queryctrl(file, fh, p);
1090
1091 if (!ret)
1092 dbgarg (cmd, "id=%d, type=%d, name=%s, "
1093 "min/max=%d/%d,"
1094 " step=%d, default=%d, flags=0x%08x\n",
1095 p->id,p->type,p->name,p->minimum,
1096 p->maximum,p->step,p->default_value,
1097 p->flags);
1098 break;
1099 }
1100 case VIDIOC_G_CTRL:
1101 {
1102 struct v4l2_control *p = arg;
1103
1104 if (!vfd->vidioc_g_ctrl)
1105 break;
1106 dbgarg(cmd, "Enum for index=%d\n", p->id);
1107
1108 ret=vfd->vidioc_g_ctrl(file, fh, p);
1109 if (!ret)
1110 dbgarg2 ( "id=%d, value=%d\n", p->id, p->value);
1111 break;
1112 }
1113 case VIDIOC_S_CTRL:
1114 {
1115 struct v4l2_control *p = arg;
1116
1117 if (!vfd->vidioc_s_ctrl)
1118 break;
1119 dbgarg (cmd, "id=%d, value=%d\n", p->id, p->value);
1120
1121 ret=vfd->vidioc_s_ctrl(file, fh, p);
1122 break;
1123 }
Hans Verkuil05976912006-06-18 13:43:28 -03001124 case VIDIOC_G_EXT_CTRLS:
1125 {
1126 struct v4l2_ext_controls *p = arg;
1127
1128 if (vfd->vidioc_g_ext_ctrls) {
1129 dbgarg(cmd, "count=%d\n", p->count);
1130
1131 ret=vfd->vidioc_g_ext_ctrls(file, fh, p);
1132 }
1133 break;
1134 }
1135 case VIDIOC_S_EXT_CTRLS:
1136 {
1137 struct v4l2_ext_controls *p = arg;
1138
1139 if (vfd->vidioc_s_ext_ctrls) {
1140 dbgarg(cmd, "count=%d\n", p->count);
1141
1142 ret=vfd->vidioc_s_ext_ctrls(file, fh, p);
1143 }
1144 break;
1145 }
1146 case VIDIOC_TRY_EXT_CTRLS:
1147 {
1148 struct v4l2_ext_controls *p = arg;
1149
1150 if (vfd->vidioc_try_ext_ctrls) {
1151 dbgarg(cmd, "count=%d\n", p->count);
1152
1153 ret=vfd->vidioc_try_ext_ctrls(file, fh, p);
1154 }
1155 break;
1156 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001157 case VIDIOC_QUERYMENU:
1158 {
1159 struct v4l2_querymenu *p=arg;
1160 if (!vfd->vidioc_querymenu)
1161 break;
1162 ret=vfd->vidioc_querymenu(file, fh, p);
1163 if (!ret)
1164 dbgarg (cmd, "id=%d, index=%d, name=%s\n",
1165 p->id,p->index,p->name);
1166 break;
1167 }
1168 /* --- audio ---------------------------------------------- */
1169 case VIDIOC_ENUMAUDIO:
1170 {
1171 struct v4l2_audio *p=arg;
1172
1173 if (!vfd->vidioc_enumaudio)
1174 break;
1175 dbgarg(cmd, "Enum for index=%d\n", p->index);
1176 ret=vfd->vidioc_enumaudio(file, fh, p);
1177 if (!ret)
1178 dbgarg2("index=%d, name=%s, capability=%d, "
1179 "mode=%d\n",p->index,p->name,
1180 p->capability, p->mode);
1181 break;
1182 }
1183 case VIDIOC_G_AUDIO:
1184 {
1185 struct v4l2_audio *p=arg;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001186 __u32 index=p->index;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001187
1188 if (!vfd->vidioc_g_audio)
1189 break;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001190
1191 memset(p,0,sizeof(*p));
1192 p->index=index;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001193 dbgarg(cmd, "Get for index=%d\n", p->index);
1194 ret=vfd->vidioc_g_audio(file, fh, p);
1195 if (!ret)
1196 dbgarg2("index=%d, name=%s, capability=%d, "
1197 "mode=%d\n",p->index,
1198 p->name,p->capability, p->mode);
1199 break;
1200 }
1201 case VIDIOC_S_AUDIO:
1202 {
1203 struct v4l2_audio *p=arg;
1204
1205 if (!vfd->vidioc_s_audio)
1206 break;
1207 dbgarg(cmd, "index=%d, name=%s, capability=%d, "
1208 "mode=%d\n", p->index, p->name,
1209 p->capability, p->mode);
1210 ret=vfd->vidioc_s_audio(file, fh, p);
1211 break;
1212 }
1213 case VIDIOC_ENUMAUDOUT:
1214 {
1215 struct v4l2_audioout *p=arg;
1216
1217 if (!vfd->vidioc_enumaudout)
1218 break;
1219 dbgarg(cmd, "Enum for index=%d\n", p->index);
1220 ret=vfd->vidioc_enumaudout(file, fh, p);
1221 if (!ret)
1222 dbgarg2("index=%d, name=%s, capability=%d, "
1223 "mode=%d\n", p->index, p->name,
1224 p->capability,p->mode);
1225 break;
1226 }
1227 case VIDIOC_G_AUDOUT:
1228 {
1229 struct v4l2_audioout *p=arg;
1230
1231 if (!vfd->vidioc_g_audout)
1232 break;
1233 dbgarg(cmd, "Enum for index=%d\n", p->index);
1234 ret=vfd->vidioc_g_audout(file, fh, p);
1235 if (!ret)
1236 dbgarg2("index=%d, name=%s, capability=%d, "
1237 "mode=%d\n", p->index, p->name,
1238 p->capability,p->mode);
1239 break;
1240 }
1241 case VIDIOC_S_AUDOUT:
1242 {
1243 struct v4l2_audioout *p=arg;
1244
1245 if (!vfd->vidioc_s_audout)
1246 break;
1247 dbgarg(cmd, "index=%d, name=%s, capability=%d, "
1248 "mode=%d\n", p->index, p->name,
1249 p->capability,p->mode);
1250
1251 ret=vfd->vidioc_s_audout(file, fh, p);
1252 break;
1253 }
1254 case VIDIOC_G_MODULATOR:
1255 {
1256 struct v4l2_modulator *p=arg;
1257 if (!vfd->vidioc_g_modulator)
1258 break;
1259 ret=vfd->vidioc_g_modulator(file, fh, p);
1260 if (!ret)
1261 dbgarg(cmd, "index=%d, name=%s, "
1262 "capability=%d, rangelow=%d,"
1263 " rangehigh=%d, txsubchans=%d\n",
1264 p->index, p->name,p->capability,
1265 p->rangelow, p->rangehigh,
1266 p->txsubchans);
1267 break;
1268 }
1269 case VIDIOC_S_MODULATOR:
1270 {
1271 struct v4l2_modulator *p=arg;
1272 if (!vfd->vidioc_s_modulator)
1273 break;
1274 dbgarg(cmd, "index=%d, name=%s, capability=%d, "
1275 "rangelow=%d, rangehigh=%d, txsubchans=%d\n",
1276 p->index, p->name,p->capability,p->rangelow,
1277 p->rangehigh,p->txsubchans);
1278 ret=vfd->vidioc_s_modulator(file, fh, p);
1279 break;
1280 }
1281 case VIDIOC_G_CROP:
1282 {
1283 struct v4l2_crop *p=arg;
1284 if (!vfd->vidioc_g_crop)
1285 break;
1286 ret=vfd->vidioc_g_crop(file, fh, p);
1287 if (!ret) {
1288 dbgarg(cmd, "type=%d\n", p->type);
1289 dbgrect(vfd, "", &p->c);
1290 }
1291 break;
1292 }
1293 case VIDIOC_S_CROP:
1294 {
1295 struct v4l2_crop *p=arg;
1296 if (!vfd->vidioc_s_crop)
1297 break;
1298 dbgarg(cmd, "type=%d\n", p->type);
1299 dbgrect(vfd, "", &p->c);
1300 ret=vfd->vidioc_s_crop(file, fh, p);
1301 break;
1302 }
1303 case VIDIOC_CROPCAP:
1304 {
1305 struct v4l2_cropcap *p=arg;
1306 /*FIXME: Should also show v4l2_fract pixelaspect */
1307 if (!vfd->vidioc_cropcap)
1308 break;
1309 dbgarg(cmd, "type=%d\n", p->type);
1310 dbgrect(vfd, "bounds ", &p->bounds);
1311 dbgrect(vfd, "defrect ", &p->defrect);
1312 ret=vfd->vidioc_cropcap(file, fh, p);
1313 break;
1314 }
1315 case VIDIOC_G_MPEGCOMP:
1316 {
1317 struct v4l2_mpeg_compression *p=arg;
Hans Verkuilf81cf752006-06-18 16:54:20 -03001318
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001319 /*FIXME: Several fields not shown */
1320 if (!vfd->vidioc_g_mpegcomp)
1321 break;
1322 ret=vfd->vidioc_g_mpegcomp(file, fh, p);
1323 if (!ret)
1324 dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d,"
1325 " ts_pid_video=%d, ts_pid_pcr=%d, "
1326 "ps_size=%d, au_sample_rate=%d, "
1327 "au_pesid=%c, vi_frame_rate=%d, "
1328 "vi_frames_per_gop=%d, "
1329 "vi_bframes_count=%d, vi_pesid=%c\n",
1330 p->ts_pid_pmt,p->ts_pid_audio,
1331 p->ts_pid_video,p->ts_pid_pcr,
1332 p->ps_size, p->au_sample_rate,
1333 p->au_pesid, p->vi_frame_rate,
1334 p->vi_frames_per_gop,
1335 p->vi_bframes_count, p->vi_pesid);
1336 break;
1337 }
1338 case VIDIOC_S_MPEGCOMP:
1339 {
1340 struct v4l2_mpeg_compression *p=arg;
1341 /*FIXME: Several fields not shown */
1342 if (!vfd->vidioc_s_mpegcomp)
1343 break;
1344 dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d, "
1345 "ts_pid_video=%d, ts_pid_pcr=%d, ps_size=%d, "
1346 "au_sample_rate=%d, au_pesid=%c, "
1347 "vi_frame_rate=%d, vi_frames_per_gop=%d, "
1348 "vi_bframes_count=%d, vi_pesid=%c\n",
1349 p->ts_pid_pmt,p->ts_pid_audio, p->ts_pid_video,
1350 p->ts_pid_pcr, p->ps_size, p->au_sample_rate,
1351 p->au_pesid, p->vi_frame_rate,
1352 p->vi_frames_per_gop, p->vi_bframes_count,
1353 p->vi_pesid);
1354 ret=vfd->vidioc_s_mpegcomp(file, fh, p);
1355 break;
1356 }
1357 case VIDIOC_G_JPEGCOMP:
1358 {
1359 struct v4l2_jpegcompression *p=arg;
1360 if (!vfd->vidioc_g_jpegcomp)
1361 break;
1362 ret=vfd->vidioc_g_jpegcomp(file, fh, p);
1363 if (!ret)
1364 dbgarg (cmd, "quality=%d, APPn=%d, "
1365 "APP_len=%d, COM_len=%d, "
1366 "jpeg_markers=%d\n",
1367 p->quality,p->APPn,p->APP_len,
1368 p->COM_len,p->jpeg_markers);
1369 break;
1370 }
1371 case VIDIOC_S_JPEGCOMP:
1372 {
1373 struct v4l2_jpegcompression *p=arg;
1374 if (!vfd->vidioc_g_jpegcomp)
1375 break;
1376 dbgarg (cmd, "quality=%d, APPn=%d, APP_len=%d, "
1377 "COM_len=%d, jpeg_markers=%d\n",
1378 p->quality,p->APPn,p->APP_len,
1379 p->COM_len,p->jpeg_markers);
1380 ret=vfd->vidioc_s_jpegcomp(file, fh, p);
1381 break;
1382 }
Hans Verkuildb6eb5b2007-02-18 14:05:02 -03001383 case VIDIOC_G_ENC_INDEX:
1384 {
1385 struct v4l2_enc_idx *p=arg;
1386
1387 if (!vfd->vidioc_g_enc_index)
1388 break;
1389 ret=vfd->vidioc_g_enc_index(file, fh, p);
1390 if (!ret)
1391 dbgarg (cmd, "entries=%d, entries_cap=%d\n",
1392 p->entries,p->entries_cap);
1393 break;
1394 }
Hans Verkuilada6ecd2007-02-18 14:56:22 -03001395 case VIDIOC_ENCODER_CMD:
1396 {
1397 struct v4l2_encoder_cmd *p=arg;
1398
1399 if (!vfd->vidioc_encoder_cmd)
1400 break;
1401 ret=vfd->vidioc_encoder_cmd(file, fh, p);
1402 if (!ret)
1403 dbgarg (cmd, "cmd=%d, flags=%d\n",
1404 p->cmd,p->flags);
1405 break;
1406 }
1407 case VIDIOC_TRY_ENCODER_CMD:
1408 {
1409 struct v4l2_encoder_cmd *p=arg;
1410
1411 if (!vfd->vidioc_try_encoder_cmd)
1412 break;
1413 ret=vfd->vidioc_try_encoder_cmd(file, fh, p);
1414 if (!ret)
1415 dbgarg (cmd, "cmd=%d, flags=%d\n",
1416 p->cmd,p->flags);
1417 break;
1418 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001419 case VIDIOC_G_PARM:
1420 {
1421 struct v4l2_streamparm *p=arg;
Mauro Carvalho Chehab2aa23422007-04-24 13:40:07 -03001422 __u32 type=p->type;
1423
1424 memset(p,0,sizeof(*p));
1425 p->type=type;
1426
Mauro Carvalho Chehab1c2d0342006-09-14 13:36:34 -03001427 if (vfd->vidioc_g_parm) {
1428 ret=vfd->vidioc_g_parm(file, fh, p);
1429 } else {
1430 struct v4l2_standard s;
Mauro Carvalho Chehab1c2d0342006-09-14 13:36:34 -03001431
1432 if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1433 return -EINVAL;
1434
Jonathan Corbet83427ac2006-10-13 07:51:16 -03001435 v4l2_video_std_construct(&s, vfd->current_norm,
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001436 v4l2_norm_to_name(vfd->current_norm));
Mauro Carvalho Chehab1c2d0342006-09-14 13:36:34 -03001437
Mauro Carvalho Chehab1c2d0342006-09-14 13:36:34 -03001438 p->parm.capture.timeperframe = s.frameperiod;
1439 ret=0;
1440 }
1441
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001442 dbgarg (cmd, "type=%d\n", p->type);
1443 break;
1444 }
1445 case VIDIOC_S_PARM:
1446 {
1447 struct v4l2_streamparm *p=arg;
1448 if (!vfd->vidioc_s_parm)
1449 break;
1450 dbgarg (cmd, "type=%d\n", p->type);
1451 ret=vfd->vidioc_s_parm(file, fh, p);
1452 break;
1453 }
1454 case VIDIOC_G_TUNER:
1455 {
1456 struct v4l2_tuner *p=arg;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001457 __u32 index=p->index;
1458
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001459 if (!vfd->vidioc_g_tuner)
1460 break;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001461
1462 memset(p,0,sizeof(*p));
1463 p->index=index;
1464
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001465 ret=vfd->vidioc_g_tuner(file, fh, p);
1466 if (!ret)
1467 dbgarg (cmd, "index=%d, name=%s, type=%d, "
1468 "capability=%d, rangelow=%d, "
1469 "rangehigh=%d, signal=%d, afc=%d, "
1470 "rxsubchans=%d, audmode=%d\n",
1471 p->index, p->name, p->type,
1472 p->capability, p->rangelow,
1473 p->rangehigh, p->rxsubchans,
1474 p->audmode, p->signal, p->afc);
1475 break;
1476 }
1477 case VIDIOC_S_TUNER:
1478 {
1479 struct v4l2_tuner *p=arg;
1480 if (!vfd->vidioc_s_tuner)
1481 break;
1482 dbgarg (cmd, "index=%d, name=%s, type=%d, "
1483 "capability=%d, rangelow=%d, rangehigh=%d, "
1484 "signal=%d, afc=%d, rxsubchans=%d, "
1485 "audmode=%d\n",p->index, p->name, p->type,
1486 p->capability, p->rangelow,p->rangehigh,
1487 p->rxsubchans, p->audmode, p->signal,
1488 p->afc);
1489 ret=vfd->vidioc_s_tuner(file, fh, p);
1490 break;
1491 }
1492 case VIDIOC_G_FREQUENCY:
1493 {
1494 struct v4l2_frequency *p=arg;
1495 if (!vfd->vidioc_g_frequency)
1496 break;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001497
1498 memset(p,0,sizeof(*p));
1499
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001500 ret=vfd->vidioc_g_frequency(file, fh, p);
1501 if (!ret)
1502 dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
1503 p->tuner,p->type,p->frequency);
1504 break;
1505 }
1506 case VIDIOC_S_FREQUENCY:
1507 {
1508 struct v4l2_frequency *p=arg;
1509 if (!vfd->vidioc_s_frequency)
1510 break;
1511 dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
1512 p->tuner,p->type,p->frequency);
1513 ret=vfd->vidioc_s_frequency(file, fh, p);
1514 break;
1515 }
1516 case VIDIOC_G_SLICED_VBI_CAP:
1517 {
1518 struct v4l2_sliced_vbi_cap *p=arg;
1519 if (!vfd->vidioc_g_sliced_vbi_cap)
1520 break;
1521 ret=vfd->vidioc_g_sliced_vbi_cap(file, fh, p);
1522 if (!ret)
1523 dbgarg (cmd, "service_set=%d\n", p->service_set);
1524 break;
1525 }
1526 case VIDIOC_LOG_STATUS:
1527 {
1528 if (!vfd->vidioc_log_status)
1529 break;
1530 ret=vfd->vidioc_log_status(file, fh);
1531 break;
1532 }
Trent Piephodbbff482007-01-22 23:31:53 -03001533#ifdef CONFIG_VIDEO_ADV_DEBUG
Trent Piepho52ebc762007-01-23 22:38:13 -03001534 case VIDIOC_DBG_G_REGISTER:
Trent Piephodbbff482007-01-22 23:31:53 -03001535 {
1536 struct v4l2_register *p=arg;
Trent Piepho62d50ad2007-01-30 23:25:41 -03001537 if (!capable(CAP_SYS_ADMIN))
1538 ret=-EPERM;
1539 else if (vfd->vidioc_g_register)
Trent Piephodbbff482007-01-22 23:31:53 -03001540 ret=vfd->vidioc_g_register(file, fh, p);
1541 break;
1542 }
Trent Piepho52ebc762007-01-23 22:38:13 -03001543 case VIDIOC_DBG_S_REGISTER:
Trent Piephodbbff482007-01-22 23:31:53 -03001544 {
1545 struct v4l2_register *p=arg;
Trent Piepho52ebc762007-01-23 22:38:13 -03001546 if (!capable(CAP_SYS_ADMIN))
1547 ret=-EPERM;
1548 else if (vfd->vidioc_s_register)
Trent Piephodbbff482007-01-22 23:31:53 -03001549 ret=vfd->vidioc_s_register(file, fh, p);
1550 break;
1551 }
1552#endif
Hans Verkuil3434eb72007-04-27 12:31:08 -03001553 case VIDIOC_G_CHIP_IDENT:
1554 {
1555 struct v4l2_chip_ident *p=arg;
1556 if (!vfd->vidioc_g_chip_ident)
1557 break;
1558 ret=vfd->vidioc_g_chip_ident(file, fh, p);
1559 if (!ret)
1560 dbgarg (cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision);
1561 break;
1562 }
Mauro Carvalho Chehab207705c2006-11-20 12:13:25 -03001563 } /* switch */
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001564
1565 if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
1566 if (ret<0) {
1567 printk ("%s: err:\n", vfd->name);
1568 v4l_print_ioctl(vfd->name, cmd);
1569 }
1570 }
1571
1572 return ret;
1573}
1574
1575int video_ioctl2 (struct inode *inode, struct file *file,
1576 unsigned int cmd, unsigned long arg)
1577{
1578 char sbuf[128];
1579 void *mbuf = NULL;
1580 void *parg = NULL;
1581 int err = -EINVAL;
Hans Verkuil05976912006-06-18 13:43:28 -03001582 int is_ext_ctrl;
1583 size_t ctrls_size = 0;
1584 void __user *user_ptr = NULL;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001585
1586#ifdef __OLD_VIDIOC_
1587 cmd = video_fix_command(cmd);
1588#endif
Hans Verkuil05976912006-06-18 13:43:28 -03001589 is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
1590 cmd == VIDIOC_TRY_EXT_CTRLS);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001591
1592 /* Copy arguments into temp kernel buffer */
1593 switch (_IOC_DIR(cmd)) {
1594 case _IOC_NONE:
1595 parg = NULL;
1596 break;
1597 case _IOC_READ:
1598 case _IOC_WRITE:
1599 case (_IOC_WRITE | _IOC_READ):
1600 if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
1601 parg = sbuf;
1602 } else {
1603 /* too big to allocate from stack */
1604 mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
1605 if (NULL == mbuf)
1606 return -ENOMEM;
1607 parg = mbuf;
1608 }
1609
1610 err = -EFAULT;
1611 if (_IOC_DIR(cmd) & _IOC_WRITE)
1612 if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
1613 goto out;
1614 break;
1615 }
1616
Hans Verkuil05976912006-06-18 13:43:28 -03001617 if (is_ext_ctrl) {
1618 struct v4l2_ext_controls *p = parg;
1619
1620 /* In case of an error, tell the caller that it wasn't
1621 a specific control that caused it. */
1622 p->error_idx = p->count;
1623 user_ptr = (void __user *)p->controls;
1624 if (p->count) {
1625 ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
1626 /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
1627 mbuf = kmalloc(ctrls_size, GFP_KERNEL);
1628 err = -ENOMEM;
1629 if (NULL == mbuf)
1630 goto out_ext_ctrl;
1631 err = -EFAULT;
1632 if (copy_from_user(mbuf, user_ptr, ctrls_size))
1633 goto out_ext_ctrl;
1634 p->controls = mbuf;
1635 }
1636 }
1637
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001638 /* Handles IOCTL */
1639 err = __video_do_ioctl(inode, file, cmd, parg);
1640 if (err == -ENOIOCTLCMD)
1641 err = -EINVAL;
Hans Verkuil05976912006-06-18 13:43:28 -03001642 if (is_ext_ctrl) {
1643 struct v4l2_ext_controls *p = parg;
1644
1645 p->controls = (void *)user_ptr;
1646 if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
1647 err = -EFAULT;
1648 goto out_ext_ctrl;
1649 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001650 if (err < 0)
1651 goto out;
1652
Hans Verkuil05976912006-06-18 13:43:28 -03001653out_ext_ctrl:
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001654 /* Copy results into user buffer */
1655 switch (_IOC_DIR(cmd))
1656 {
1657 case _IOC_READ:
1658 case (_IOC_WRITE | _IOC_READ):
1659 if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
1660 err = -EFAULT;
1661 break;
1662 }
1663
1664out:
1665 kfree(mbuf);
1666 return err;
1667}
1668
1669
Arjan van de Venfa027c22007-02-12 00:55:33 -08001670static const struct file_operations video_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
1672/**
1673 * video_register_device - register video4linux devices
1674 * @vfd: video device structure we want to register
1675 * @type: type of device to register
1676 * @nr: which device number (0 == /dev/video0, 1 == /dev/video1, ...
1677 * -1 == first free)
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001678 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 * The registration code assigns minor numbers based on the type
1680 * requested. -ENFILE is returned in all the device slots for this
1681 * category are full. If not then the minor field is set and the
1682 * driver initialize function is called (if non %NULL).
1683 *
1684 * Zero is returned on success.
1685 *
1686 * Valid types are
1687 *
1688 * %VFL_TYPE_GRABBER - A frame grabber
1689 *
1690 * %VFL_TYPE_VTX - A teletext device
1691 *
1692 * %VFL_TYPE_VBI - Vertical blank data (undecoded)
1693 *
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001694 * %VFL_TYPE_RADIO - A radio card
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 */
1696
1697int video_register_device(struct video_device *vfd, int type, int nr)
1698{
1699 int i=0;
1700 int base;
1701 int end;
Michael Krufky3117bee2006-07-19 13:23:38 -03001702 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 char *name_base;
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001704
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 switch(type)
1706 {
1707 case VFL_TYPE_GRABBER:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02001708 base=MINOR_VFL_TYPE_GRABBER_MIN;
1709 end=MINOR_VFL_TYPE_GRABBER_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 name_base = "video";
1711 break;
1712 case VFL_TYPE_VTX:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02001713 base=MINOR_VFL_TYPE_VTX_MIN;
1714 end=MINOR_VFL_TYPE_VTX_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 name_base = "vtx";
1716 break;
1717 case VFL_TYPE_VBI:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02001718 base=MINOR_VFL_TYPE_VBI_MIN;
1719 end=MINOR_VFL_TYPE_VBI_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 name_base = "vbi";
1721 break;
1722 case VFL_TYPE_RADIO:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02001723 base=MINOR_VFL_TYPE_RADIO_MIN;
1724 end=MINOR_VFL_TYPE_RADIO_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 name_base = "radio";
1726 break;
1727 default:
Trent Piepho53dd8de2006-07-25 09:31:42 -03001728 printk(KERN_ERR "%s called with unknown type: %d\n",
1729 __FUNCTION__, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 return -1;
1731 }
1732
1733 /* pick a minor number */
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001734 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 if (nr >= 0 && nr < end-base) {
1736 /* use the one the driver asked for */
1737 i = base+nr;
1738 if (NULL != video_device[i]) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001739 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 return -ENFILE;
1741 }
1742 } else {
1743 /* use first free */
1744 for(i=base;i<end;i++)
1745 if (NULL == video_device[i])
1746 break;
1747 if (i == end) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001748 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 return -ENFILE;
1750 }
1751 }
1752 video_device[i]=vfd;
1753 vfd->minor=i;
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001754 mutex_unlock(&videodev_lock);
Ingo Molnar3593cab2006-02-07 06:49:14 -02001755 mutex_init(&vfd->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756
1757 /* sysfs class */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001758 memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 if (vfd->dev)
Kay Sievers54bd5b62007-10-08 16:26:13 -03001760 vfd->class_dev.parent = vfd->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 vfd->class_dev.class = &video_class;
Michael Krufky50c25ff2006-01-09 15:25:34 -02001762 vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
Kay Sievers54bd5b62007-10-08 16:26:13 -03001763 sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base);
1764 ret = device_register(&vfd->class_dev);
Trent Piepho8c313112006-07-25 20:37:03 -03001765 if (ret < 0) {
Kay Sievers54bd5b62007-10-08 16:26:13 -03001766 printk(KERN_ERR "%s: device_register failed\n",
Michael Krufky3117bee2006-07-19 13:23:38 -03001767 __FUNCTION__);
Trent Piephod94fc9a2006-07-29 17:18:06 -03001768 goto fail_minor;
Michael Krufky3117bee2006-07-19 13:23:38 -03001769 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770
Mauro Carvalho Chehabd21838d2006-01-09 15:25:21 -02001771#if 1
1772 /* needed until all drivers are fixed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 if (!vfd->release)
1774 printk(KERN_WARNING "videodev: \"%s\" has no release callback. "
1775 "Please fix your driver for proper sysfs support, see "
1776 "http://lwn.net/Articles/36850/\n", vfd->name);
1777#endif
1778 return 0;
Trent Piepho53dd8de2006-07-25 09:31:42 -03001779
Trent Piepho53dd8de2006-07-25 09:31:42 -03001780fail_minor:
1781 mutex_lock(&videodev_lock);
1782 video_device[vfd->minor] = NULL;
1783 vfd->minor = -1;
1784 mutex_unlock(&videodev_lock);
1785 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786}
1787
1788/**
1789 * video_unregister_device - unregister a video4linux device
1790 * @vfd: the device to unregister
1791 *
1792 * This unregisters the passed device and deassigns the minor
1793 * number. Future open calls will be met with errors.
1794 */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001795
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796void video_unregister_device(struct video_device *vfd)
1797{
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001798 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 if(video_device[vfd->minor]!=vfd)
1800 panic("videodev: bad unregister");
1801
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 video_device[vfd->minor]=NULL;
Kay Sievers54bd5b62007-10-08 16:26:13 -03001803 device_unregister(&vfd->class_dev);
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001804 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805}
1806
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001807/*
1808 * Video fs operations
1809 */
Arjan van de Venfa027c22007-02-12 00:55:33 -08001810static const struct file_operations video_fops=
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811{
1812 .owner = THIS_MODULE,
1813 .llseek = no_llseek,
1814 .open = video_open,
1815};
1816
1817/*
1818 * Initialise video for linux
1819 */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001820
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821static int __init videodev_init(void)
1822{
1823 int ret;
1824
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001825 printk(KERN_INFO "Linux video capture interface: v2.00\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) {
1827 printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR);
1828 return -EIO;
1829 }
1830
1831 ret = class_register(&video_class);
1832 if (ret < 0) {
1833 unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME);
1834 printk(KERN_WARNING "video_dev: class_register failed\n");
1835 return -EIO;
1836 }
1837
1838 return 0;
1839}
1840
1841static void __exit videodev_exit(void)
1842{
1843 class_unregister(&video_class);
1844 unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME);
1845}
1846
1847module_init(videodev_init)
1848module_exit(videodev_exit)
1849
1850EXPORT_SYMBOL(video_register_device);
1851EXPORT_SYMBOL(video_unregister_device);
1852EXPORT_SYMBOL(video_devdata);
1853EXPORT_SYMBOL(video_usercopy);
1854EXPORT_SYMBOL(video_exclusive_open);
1855EXPORT_SYMBOL(video_exclusive_release);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001856EXPORT_SYMBOL(video_ioctl2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857EXPORT_SYMBOL(video_device_alloc);
1858EXPORT_SYMBOL(video_device_release);
1859
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001860MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
1861MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862MODULE_LICENSE("GPL");
1863
1864
1865/*
1866 * Local variables:
1867 * c-basic-offset: 8
1868 * End:
1869 */