blob: 9611c3990285d45133276f22082ec7c4fb8bf73b [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{
Trent Piephobde00cc2007-10-08 18:36:21 -030080 struct video_device *vfd = container_of(cd, struct video_device,
81 class_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
Mauro Carvalho Chehabd21838d2006-01-09 15:25:21 -020083#if 1
Michael Krufky50c25ff2006-01-09 15:25:34 -020084 /* needed until all drivers are fixed */
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 if (!vfd->release)
86 return;
87#endif
88 vfd->release(vfd);
89}
90
Kay Sievers54bd5b62007-10-08 16:26:13 -030091static struct device_attribute video_device_attrs[] = {
92 __ATTR(name, S_IRUGO, show_name, NULL),
93 __ATTR_NULL
94};
95
Linus Torvalds1da177e2005-04-16 15:20:36 -070096static struct class video_class = {
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -080097 .name = VIDEO_NAME,
Kay Sievers54bd5b62007-10-08 16:26:13 -030098 .dev_attrs = video_device_attrs,
99 .dev_release = video_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100};
101
102/*
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800103 * Active devices
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800105
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106static struct video_device *video_device[VIDEO_NUM_DEVICES];
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200107static DEFINE_MUTEX(videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
109struct video_device* video_devdata(struct file *file)
110{
Josef Sipek723731b2006-12-08 02:37:47 -0800111 return video_device[iminor(file->f_path.dentry->d_inode)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112}
113
114/*
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300115 * Open a video device - FIXME: Obsoleted
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 */
117static int video_open(struct inode *inode, struct file *file)
118{
119 unsigned int minor = iminor(inode);
120 int err = 0;
121 struct video_device *vfl;
Arjan van de Ven99ac48f2006-03-28 01:56:41 -0800122 const struct file_operations *old_fops;
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800123
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 if(minor>=VIDEO_NUM_DEVICES)
125 return -ENODEV;
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200126 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 vfl=video_device[minor];
128 if(vfl==NULL) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200129 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 request_module("char-major-%d-%d", VIDEO_MAJOR, minor);
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200131 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 vfl=video_device[minor];
133 if (vfl==NULL) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200134 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 return -ENODEV;
136 }
137 }
138 old_fops = file->f_op;
139 file->f_op = fops_get(vfl->fops);
140 if(file->f_op->open)
141 err = file->f_op->open(inode,file);
142 if (err) {
143 fops_put(file->f_op);
144 file->f_op = fops_get(old_fops);
145 }
146 fops_put(old_fops);
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200147 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 return err;
149}
150
151/*
152 * helper function -- handles userspace copying for ioctl arguments
153 */
154
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300155#ifdef __OLD_VIDIOC_
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156static unsigned int
157video_fix_command(unsigned int cmd)
158{
159 switch (cmd) {
160 case VIDIOC_OVERLAY_OLD:
161 cmd = VIDIOC_OVERLAY;
162 break;
163 case VIDIOC_S_PARM_OLD:
164 cmd = VIDIOC_S_PARM;
165 break;
166 case VIDIOC_S_CTRL_OLD:
167 cmd = VIDIOC_S_CTRL;
168 break;
169 case VIDIOC_G_AUDIO_OLD:
170 cmd = VIDIOC_G_AUDIO;
171 break;
172 case VIDIOC_G_AUDOUT_OLD:
173 cmd = VIDIOC_G_AUDOUT;
174 break;
175 case VIDIOC_CROPCAP_OLD:
176 cmd = VIDIOC_CROPCAP;
177 break;
178 }
179 return cmd;
180}
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300181#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300183/*
184 * Obsolete usercopy function - Should be removed soon
185 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186int
187video_usercopy(struct inode *inode, struct file *file,
188 unsigned int cmd, unsigned long arg,
189 int (*func)(struct inode *inode, struct file *file,
190 unsigned int cmd, void *arg))
191{
192 char sbuf[128];
193 void *mbuf = NULL;
194 void *parg = NULL;
195 int err = -EINVAL;
Hans Verkuil05976912006-06-18 13:43:28 -0300196 int is_ext_ctrl;
197 size_t ctrls_size = 0;
198 void __user *user_ptr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300200#ifdef __OLD_VIDIOC_
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 cmd = video_fix_command(cmd);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300202#endif
Hans Verkuil05976912006-06-18 13:43:28 -0300203 is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
204 cmd == VIDIOC_TRY_EXT_CTRLS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
206 /* Copy arguments into temp kernel buffer */
207 switch (_IOC_DIR(cmd)) {
208 case _IOC_NONE:
209 parg = NULL;
210 break;
211 case _IOC_READ:
212 case _IOC_WRITE:
213 case (_IOC_WRITE | _IOC_READ):
214 if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
215 parg = sbuf;
216 } else {
217 /* too big to allocate from stack */
218 mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
219 if (NULL == mbuf)
220 return -ENOMEM;
221 parg = mbuf;
222 }
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 err = -EFAULT;
225 if (_IOC_DIR(cmd) & _IOC_WRITE)
Hans Verkuil05976912006-06-18 13:43:28 -0300226 if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 goto out;
228 break;
229 }
Hans Verkuil05976912006-06-18 13:43:28 -0300230 if (is_ext_ctrl) {
231 struct v4l2_ext_controls *p = parg;
232
233 /* In case of an error, tell the caller that it wasn't
234 a specific control that caused it. */
235 p->error_idx = p->count;
236 user_ptr = (void __user *)p->controls;
237 if (p->count) {
238 ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
239 /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
240 mbuf = kmalloc(ctrls_size, GFP_KERNEL);
241 err = -ENOMEM;
242 if (NULL == mbuf)
243 goto out_ext_ctrl;
244 err = -EFAULT;
245 if (copy_from_user(mbuf, user_ptr, ctrls_size))
246 goto out_ext_ctrl;
247 p->controls = mbuf;
248 }
249 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
251 /* call driver */
252 err = func(inode, file, cmd, parg);
253 if (err == -ENOIOCTLCMD)
254 err = -EINVAL;
Hans Verkuil05976912006-06-18 13:43:28 -0300255 if (is_ext_ctrl) {
256 struct v4l2_ext_controls *p = parg;
257
258 p->controls = (void *)user_ptr;
259 if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
260 err = -EFAULT;
261 goto out_ext_ctrl;
262 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 if (err < 0)
264 goto out;
265
Hans Verkuil05976912006-06-18 13:43:28 -0300266out_ext_ctrl:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 /* Copy results into user buffer */
268 switch (_IOC_DIR(cmd))
269 {
270 case _IOC_READ:
271 case (_IOC_WRITE | _IOC_READ):
272 if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
273 err = -EFAULT;
274 break;
275 }
276
277out:
Jesper Juhl2ea75332005-11-07 01:01:31 -0800278 kfree(mbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 return err;
280}
281
282/*
283 * open/release helper functions -- handle exclusive opens
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300284 * Should be removed soon
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 */
286int video_exclusive_open(struct inode *inode, struct file *file)
287{
288 struct video_device *vfl = video_devdata(file);
289 int retval = 0;
290
Ingo Molnar3593cab2006-02-07 06:49:14 -0200291 mutex_lock(&vfl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 if (vfl->users) {
293 retval = -EBUSY;
294 } else {
295 vfl->users++;
296 }
Ingo Molnar3593cab2006-02-07 06:49:14 -0200297 mutex_unlock(&vfl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 return retval;
299}
300
301int video_exclusive_release(struct inode *inode, struct file *file)
302{
303 struct video_device *vfl = video_devdata(file);
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800304
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 vfl->users--;
306 return 0;
307}
308
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300309static char *v4l2_memory_names[] = {
310 [V4L2_MEMORY_MMAP] = "mmap",
311 [V4L2_MEMORY_USERPTR] = "userptr",
312 [V4L2_MEMORY_OVERLAY] = "overlay",
313};
314
315
316/* FIXME: Those stuff are replicated also on v4l2-common.c */
317static char *v4l2_type_names_FIXME[] = {
318 [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap",
319 [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over",
320 [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out",
321 [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap",
322 [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out",
323 [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out",
324 [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-capture",
Hans Verkuilb2787842007-04-27 12:31:02 -0300325 [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over",
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300326 [V4L2_BUF_TYPE_PRIVATE] = "private",
327};
328
329static char *v4l2_field_names_FIXME[] = {
330 [V4L2_FIELD_ANY] = "any",
331 [V4L2_FIELD_NONE] = "none",
332 [V4L2_FIELD_TOP] = "top",
333 [V4L2_FIELD_BOTTOM] = "bottom",
334 [V4L2_FIELD_INTERLACED] = "interlaced",
335 [V4L2_FIELD_SEQ_TB] = "seq-tb",
336 [V4L2_FIELD_SEQ_BT] = "seq-bt",
337 [V4L2_FIELD_ALTERNATE] = "alternate",
Hans Verkuilb2787842007-04-27 12:31:02 -0300338 [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb",
339 [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt",
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300340};
341
342#define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown"
343
344static void dbgbuf(unsigned int cmd, struct video_device *vfd,
345 struct v4l2_buffer *p)
346{
347 struct v4l2_timecode *tc=&p->timecode;
348
349 dbgarg (cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, "
350 "bytesused=%d, flags=0x%08d, "
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300351 "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n",
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300352 (p->timestamp.tv_sec/3600),
353 (int)(p->timestamp.tv_sec/60)%60,
354 (int)(p->timestamp.tv_sec%60),
355 p->timestamp.tv_usec,
356 p->index,
357 prt_names(p->type,v4l2_type_names_FIXME),
358 p->bytesused,p->flags,
359 p->field,p->sequence,
360 prt_names(p->memory,v4l2_memory_names),
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300361 p->m.userptr, p->length);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300362 dbgarg2 ("timecode= %02d:%02d:%02d type=%d, "
363 "flags=0x%08d, frames=%d, userbits=0x%08x\n",
364 tc->hours,tc->minutes,tc->seconds,
Mauro Carvalho Chehabc18cb012006-06-23 07:05:22 -0300365 tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300366}
367
368static inline void dbgrect(struct video_device *vfd, char *s,
369 struct v4l2_rect *r)
370{
371 dbgarg2 ("%sRect start at %dx%d, size= %dx%d\n", s, r->left, r->top,
372 r->width, r->height);
373};
374
375static inline void v4l_print_pix_fmt (struct video_device *vfd,
376 struct v4l2_pix_format *fmt)
377{
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300378 dbgarg2 ("width=%d, height=%d, format=%c%c%c%c, field=%s, "
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300379 "bytesperline=%d sizeimage=%d, colorspace=%d\n",
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300380 fmt->width,fmt->height,
381 (fmt->pixelformat & 0xff),
382 (fmt->pixelformat >> 8) & 0xff,
383 (fmt->pixelformat >> 16) & 0xff,
384 (fmt->pixelformat >> 24) & 0xff,
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300385 prt_names(fmt->field,v4l2_field_names_FIXME),
386 fmt->bytesperline,fmt->sizeimage,fmt->colorspace);
387};
388
389
390static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type)
391{
392 switch (type) {
393 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
394 if (vfd->vidioc_try_fmt_cap)
395 return (0);
396 break;
397 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
398 if (vfd->vidioc_try_fmt_overlay)
399 return (0);
400 break;
401 case V4L2_BUF_TYPE_VBI_CAPTURE:
402 if (vfd->vidioc_try_fmt_vbi)
403 return (0);
404 break;
405 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
406 if (vfd->vidioc_try_fmt_vbi_output)
407 return (0);
408 break;
409 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
410 if (vfd->vidioc_try_fmt_vbi_capture)
411 return (0);
412 break;
413 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
414 if (vfd->vidioc_try_fmt_video_output)
415 return (0);
416 break;
417 case V4L2_BUF_TYPE_VBI_OUTPUT:
418 if (vfd->vidioc_try_fmt_vbi_output)
419 return (0);
420 break;
Hans Verkuilb2787842007-04-27 12:31:02 -0300421 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
422 if (vfd->vidioc_try_fmt_output_overlay)
423 return (0);
424 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300425 case V4L2_BUF_TYPE_PRIVATE:
426 if (vfd->vidioc_try_fmt_type_private)
427 return (0);
428 break;
429 }
430 return (-EINVAL);
431}
432
433static int __video_do_ioctl(struct inode *inode, struct file *file,
434 unsigned int cmd, void *arg)
435{
436 struct video_device *vfd = video_devdata(file);
437 void *fh = file->private_data;
438 int ret = -EINVAL;
439
440 if ( (vfd->debug & V4L2_DEBUG_IOCTL) &&
Jiri Slaby57e45b32007-05-07 10:55:49 -0300441 !(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) {
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300442 v4l_print_ioctl(vfd->name, cmd);
443 }
444
Sam Revitch1088b132007-05-01 08:46:30 -0300445#ifdef CONFIG_VIDEO_V4L1_COMPAT
Mauro Carvalho Chehab452c0fb2007-05-01 08:55:00 -0300446 /***********************************************************
447 Handles calls to the obsoleted V4L1 API
448 Due to the nature of VIDIOCGMBUF, each driver that supports
449 V4L1 should implement its own handler for this ioctl.
450 ***********************************************************/
451
Sam Revitch1088b132007-05-01 08:46:30 -0300452 /* --- streaming capture ------------------------------------- */
453 if (cmd == VIDIOCGMBUF) {
454 struct video_mbuf *p=arg;
455
Mariusz Kozlowski473c6532007-08-06 18:05:35 -0300456 memset(p, 0, sizeof(*p));
Sam Revitch1088b132007-05-01 08:46:30 -0300457
458 if (!vfd->vidiocgmbuf)
459 return ret;
460 ret=vfd->vidiocgmbuf(file, fh, p);
461 if (!ret)
462 dbgarg (cmd, "size=%d, frames=%d, offsets=0x%08lx\n",
463 p->size, p->frames,
464 (unsigned long)p->offsets);
465 return ret;
466 }
Sam Revitch1088b132007-05-01 08:46:30 -0300467
Mauro Carvalho Chehab452c0fb2007-05-01 08:55:00 -0300468 /********************************************************
469 All other V4L1 calls are handled by v4l1_compat module.
470 Those calls will be translated into V4L2 calls, and
471 __video_do_ioctl will be called again, with one or more
472 V4L2 ioctls.
473 ********************************************************/
Mauro Carvalho Chehab207705c2006-11-20 12:13:25 -0300474 if (_IOC_TYPE(cmd)=='v')
475 return v4l_compat_translate_ioctl(inode,file,cmd,arg,
476 __video_do_ioctl);
Mauro Carvalho Chehab452c0fb2007-05-01 08:55:00 -0300477#endif
Mauro Carvalho Chehab207705c2006-11-20 12:13:25 -0300478
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300479 switch(cmd) {
480 /* --- capabilities ------------------------------------------ */
481 case VIDIOC_QUERYCAP:
482 {
483 struct v4l2_capability *cap = (struct v4l2_capability*)arg;
484 memset(cap, 0, sizeof(*cap));
485
486 if (!vfd->vidioc_querycap)
487 break;
488
489 ret=vfd->vidioc_querycap(file, fh, cap);
490 if (!ret)
491 dbgarg (cmd, "driver=%s, card=%s, bus=%s, "
492 "version=0x%08x, "
493 "capabilities=0x%08x\n",
494 cap->driver,cap->card,cap->bus_info,
495 cap->version,
496 cap->capabilities);
497 break;
498 }
499
500 /* --- priority ------------------------------------------ */
501 case VIDIOC_G_PRIORITY:
502 {
503 enum v4l2_priority *p=arg;
504
505 if (!vfd->vidioc_g_priority)
506 break;
507 ret=vfd->vidioc_g_priority(file, fh, p);
508 if (!ret)
509 dbgarg(cmd, "priority is %d\n", *p);
510 break;
511 }
512 case VIDIOC_S_PRIORITY:
513 {
514 enum v4l2_priority *p=arg;
515
516 if (!vfd->vidioc_s_priority)
517 break;
518 dbgarg(cmd, "setting priority to %d\n", *p);
519 ret=vfd->vidioc_s_priority(file, fh, *p);
520 break;
521 }
522
523 /* --- capture ioctls ---------------------------------------- */
524 case VIDIOC_ENUM_FMT:
525 {
526 struct v4l2_fmtdesc *f = arg;
527 enum v4l2_buf_type type;
528 unsigned int index;
529
530 index = f->index;
531 type = f->type;
532 memset(f,0,sizeof(*f));
533 f->index = index;
534 f->type = type;
535
536 switch (type) {
537 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
538 if (vfd->vidioc_enum_fmt_cap)
539 ret=vfd->vidioc_enum_fmt_cap(file, fh, f);
540 break;
541 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
542 if (vfd->vidioc_enum_fmt_overlay)
543 ret=vfd->vidioc_enum_fmt_overlay(file, fh, f);
544 break;
545 case V4L2_BUF_TYPE_VBI_CAPTURE:
546 if (vfd->vidioc_enum_fmt_vbi)
547 ret=vfd->vidioc_enum_fmt_vbi(file, fh, f);
548 break;
549 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
550 if (vfd->vidioc_enum_fmt_vbi_output)
551 ret=vfd->vidioc_enum_fmt_vbi_output(file,
552 fh, f);
553 break;
554 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
555 if (vfd->vidioc_enum_fmt_vbi_capture)
556 ret=vfd->vidioc_enum_fmt_vbi_capture(file,
557 fh, f);
558 break;
559 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
560 if (vfd->vidioc_enum_fmt_video_output)
561 ret=vfd->vidioc_enum_fmt_video_output(file,
562 fh, f);
563 break;
564 case V4L2_BUF_TYPE_VBI_OUTPUT:
565 if (vfd->vidioc_enum_fmt_vbi_output)
566 ret=vfd->vidioc_enum_fmt_vbi_output(file,
567 fh, f);
568 break;
Hans Verkuilb2787842007-04-27 12:31:02 -0300569 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
570 if (vfd->vidioc_enum_fmt_output_overlay)
571 ret=vfd->vidioc_enum_fmt_output_overlay(file, fh, f);
572 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300573 case V4L2_BUF_TYPE_PRIVATE:
574 if (vfd->vidioc_enum_fmt_type_private)
575 ret=vfd->vidioc_enum_fmt_type_private(file,
576 fh, f);
577 break;
578 }
579 if (!ret)
580 dbgarg (cmd, "index=%d, type=%d, flags=%d, "
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300581 "pixelformat=%c%c%c%c, description='%s'\n",
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300582 f->index, f->type, f->flags,
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300583 (f->pixelformat & 0xff),
584 (f->pixelformat >> 8) & 0xff,
585 (f->pixelformat >> 16) & 0xff,
586 (f->pixelformat >> 24) & 0xff,
587 f->description);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300588 break;
589 }
590 case VIDIOC_G_FMT:
591 {
592 struct v4l2_format *f = (struct v4l2_format *)arg;
593 enum v4l2_buf_type type=f->type;
594
595 memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
596 f->type=type;
597
598 /* FIXME: Should be one dump per type */
599 dbgarg (cmd, "type=%s\n", prt_names(type,
600 v4l2_type_names_FIXME));
601
602 switch (type) {
603 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
604 if (vfd->vidioc_g_fmt_cap)
605 ret=vfd->vidioc_g_fmt_cap(file, fh, f);
606 if (!ret)
607 v4l_print_pix_fmt(vfd,&f->fmt.pix);
608 break;
609 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
610 if (vfd->vidioc_g_fmt_overlay)
611 ret=vfd->vidioc_g_fmt_overlay(file, fh, f);
612 break;
613 case V4L2_BUF_TYPE_VBI_CAPTURE:
614 if (vfd->vidioc_g_fmt_vbi)
615 ret=vfd->vidioc_g_fmt_vbi(file, fh, f);
616 break;
617 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
618 if (vfd->vidioc_g_fmt_vbi_output)
619 ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
620 break;
621 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
622 if (vfd->vidioc_g_fmt_vbi_capture)
623 ret=vfd->vidioc_g_fmt_vbi_capture(file, fh, f);
624 break;
625 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
626 if (vfd->vidioc_g_fmt_video_output)
627 ret=vfd->vidioc_g_fmt_video_output(file,
628 fh, f);
629 break;
Hans Verkuilb2787842007-04-27 12:31:02 -0300630 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
631 if (vfd->vidioc_g_fmt_output_overlay)
632 ret=vfd->vidioc_g_fmt_output_overlay(file, fh, f);
633 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300634 case V4L2_BUF_TYPE_VBI_OUTPUT:
635 if (vfd->vidioc_g_fmt_vbi_output)
636 ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
637 break;
638 case V4L2_BUF_TYPE_PRIVATE:
639 if (vfd->vidioc_g_fmt_type_private)
640 ret=vfd->vidioc_g_fmt_type_private(file,
641 fh, f);
642 break;
643 }
644
645 break;
646 }
647 case VIDIOC_S_FMT:
648 {
649 struct v4l2_format *f = (struct v4l2_format *)arg;
650
651 /* FIXME: Should be one dump per type */
652 dbgarg (cmd, "type=%s\n", prt_names(f->type,
653 v4l2_type_names_FIXME));
654
655 switch (f->type) {
656 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
657 v4l_print_pix_fmt(vfd,&f->fmt.pix);
658 if (vfd->vidioc_s_fmt_cap)
659 ret=vfd->vidioc_s_fmt_cap(file, fh, f);
660 break;
661 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
662 if (vfd->vidioc_s_fmt_overlay)
663 ret=vfd->vidioc_s_fmt_overlay(file, fh, f);
664 break;
665 case V4L2_BUF_TYPE_VBI_CAPTURE:
666 if (vfd->vidioc_s_fmt_vbi)
667 ret=vfd->vidioc_s_fmt_vbi(file, fh, f);
668 break;
669 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
670 if (vfd->vidioc_s_fmt_vbi_output)
671 ret=vfd->vidioc_s_fmt_vbi_output(file, fh, f);
672 break;
673 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
674 if (vfd->vidioc_s_fmt_vbi_capture)
675 ret=vfd->vidioc_s_fmt_vbi_capture(file, fh, f);
676 break;
677 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
678 if (vfd->vidioc_s_fmt_video_output)
679 ret=vfd->vidioc_s_fmt_video_output(file,
680 fh, f);
681 break;
Hans Verkuilb2787842007-04-27 12:31:02 -0300682 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
683 if (vfd->vidioc_s_fmt_output_overlay)
684 ret=vfd->vidioc_s_fmt_output_overlay(file, fh, f);
685 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300686 case V4L2_BUF_TYPE_VBI_OUTPUT:
687 if (vfd->vidioc_s_fmt_vbi_output)
688 ret=vfd->vidioc_s_fmt_vbi_output(file,
689 fh, f);
690 break;
691 case V4L2_BUF_TYPE_PRIVATE:
692 if (vfd->vidioc_s_fmt_type_private)
693 ret=vfd->vidioc_s_fmt_type_private(file,
694 fh, f);
695 break;
696 }
697 break;
698 }
699 case VIDIOC_TRY_FMT:
700 {
701 struct v4l2_format *f = (struct v4l2_format *)arg;
702
703 /* FIXME: Should be one dump per type */
704 dbgarg (cmd, "type=%s\n", prt_names(f->type,
705 v4l2_type_names_FIXME));
706 switch (f->type) {
707 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
708 if (vfd->vidioc_try_fmt_cap)
709 ret=vfd->vidioc_try_fmt_cap(file, fh, f);
710 if (!ret)
711 v4l_print_pix_fmt(vfd,&f->fmt.pix);
712 break;
713 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
714 if (vfd->vidioc_try_fmt_overlay)
715 ret=vfd->vidioc_try_fmt_overlay(file, fh, f);
716 break;
717 case V4L2_BUF_TYPE_VBI_CAPTURE:
718 if (vfd->vidioc_try_fmt_vbi)
719 ret=vfd->vidioc_try_fmt_vbi(file, fh, f);
720 break;
721 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
722 if (vfd->vidioc_try_fmt_vbi_output)
723 ret=vfd->vidioc_try_fmt_vbi_output(file,
724 fh, f);
725 break;
726 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
727 if (vfd->vidioc_try_fmt_vbi_capture)
728 ret=vfd->vidioc_try_fmt_vbi_capture(file,
729 fh, f);
730 break;
731 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
732 if (vfd->vidioc_try_fmt_video_output)
733 ret=vfd->vidioc_try_fmt_video_output(file,
734 fh, f);
735 break;
Hans Verkuilb2787842007-04-27 12:31:02 -0300736 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
737 if (vfd->vidioc_try_fmt_output_overlay)
738 ret=vfd->vidioc_try_fmt_output_overlay(file, fh, f);
739 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300740 case V4L2_BUF_TYPE_VBI_OUTPUT:
741 if (vfd->vidioc_try_fmt_vbi_output)
742 ret=vfd->vidioc_try_fmt_vbi_output(file,
743 fh, f);
744 break;
745 case V4L2_BUF_TYPE_PRIVATE:
746 if (vfd->vidioc_try_fmt_type_private)
747 ret=vfd->vidioc_try_fmt_type_private(file,
748 fh, f);
749 break;
750 }
751
752 break;
753 }
754 /* FIXME: Those buf reqs could be handled here,
755 with some changes on videobuf to allow its header to be included at
756 videodev2.h or being merged at videodev2.
757 */
758 case VIDIOC_REQBUFS:
759 {
760 struct v4l2_requestbuffers *p=arg;
761
762 if (!vfd->vidioc_reqbufs)
763 break;
764 ret = check_fmt (vfd, p->type);
765 if (ret)
766 break;
767
768 ret=vfd->vidioc_reqbufs(file, fh, p);
769 dbgarg (cmd, "count=%d, type=%s, memory=%s\n",
770 p->count,
771 prt_names(p->type,v4l2_type_names_FIXME),
772 prt_names(p->memory,v4l2_memory_names));
773 break;
774 }
775 case VIDIOC_QUERYBUF:
776 {
777 struct v4l2_buffer *p=arg;
778
779 if (!vfd->vidioc_querybuf)
780 break;
781 ret = check_fmt (vfd, p->type);
782 if (ret)
783 break;
784
785 ret=vfd->vidioc_querybuf(file, fh, p);
786 if (!ret)
787 dbgbuf(cmd,vfd,p);
788 break;
789 }
790 case VIDIOC_QBUF:
791 {
792 struct v4l2_buffer *p=arg;
793
794 if (!vfd->vidioc_qbuf)
795 break;
796 ret = check_fmt (vfd, p->type);
797 if (ret)
798 break;
799
800 ret=vfd->vidioc_qbuf(file, fh, p);
801 if (!ret)
802 dbgbuf(cmd,vfd,p);
803 break;
804 }
805 case VIDIOC_DQBUF:
806 {
807 struct v4l2_buffer *p=arg;
Sascha Hauerc93a5c32006-09-11 09:49:19 -0300808 if (!vfd->vidioc_dqbuf)
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300809 break;
810 ret = check_fmt (vfd, p->type);
811 if (ret)
812 break;
813
Sascha Hauerc93a5c32006-09-11 09:49:19 -0300814 ret=vfd->vidioc_dqbuf(file, fh, p);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300815 if (!ret)
816 dbgbuf(cmd,vfd,p);
817 break;
818 }
819 case VIDIOC_OVERLAY:
820 {
821 int *i = arg;
822
823 if (!vfd->vidioc_overlay)
824 break;
825 dbgarg (cmd, "value=%d\n",*i);
826 ret=vfd->vidioc_overlay(file, fh, *i);
827 break;
828 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300829 case VIDIOC_G_FBUF:
830 {
831 struct v4l2_framebuffer *p=arg;
832 if (!vfd->vidioc_g_fbuf)
833 break;
834 ret=vfd->vidioc_g_fbuf(file, fh, arg);
835 if (!ret) {
836 dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
837 p->capability,p->flags,
838 (unsigned long)p->base);
839 v4l_print_pix_fmt (vfd, &p->fmt);
840 }
841 break;
842 }
843 case VIDIOC_S_FBUF:
844 {
845 struct v4l2_framebuffer *p=arg;
846 if (!vfd->vidioc_s_fbuf)
847 break;
848
849 dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
850 p->capability,p->flags,(unsigned long)p->base);
851 v4l_print_pix_fmt (vfd, &p->fmt);
852 ret=vfd->vidioc_s_fbuf(file, fh, arg);
853
854 break;
855 }
856 case VIDIOC_STREAMON:
857 {
858 enum v4l2_buf_type i = *(int *)arg;
859 if (!vfd->vidioc_streamon)
860 break;
861 dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME));
862 ret=vfd->vidioc_streamon(file, fh,i);
863 break;
864 }
865 case VIDIOC_STREAMOFF:
866 {
867 enum v4l2_buf_type i = *(int *)arg;
868
869 if (!vfd->vidioc_streamoff)
870 break;
871 dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME));
872 ret=vfd->vidioc_streamoff(file, fh, i);
873 break;
874 }
875 /* ---------- tv norms ---------- */
876 case VIDIOC_ENUMSTD:
877 {
878 struct v4l2_standard *p = arg;
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300879 v4l2_std_id id = vfd->tvnorms,curr_id=0;
880 unsigned int index = p->index,i;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300881
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300882 if (index<0) {
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300883 ret=-EINVAL;
884 break;
885 }
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300886
887 /* Return norm array on a canonical way */
888 for (i=0;i<= index && id; i++) {
889 if ( (id & V4L2_STD_PAL) == V4L2_STD_PAL) {
890 curr_id = V4L2_STD_PAL;
891 } else if ( (id & V4L2_STD_PAL_BG) == V4L2_STD_PAL_BG) {
892 curr_id = V4L2_STD_PAL_BG;
893 } else if ( (id & V4L2_STD_PAL_DK) == V4L2_STD_PAL_DK) {
894 curr_id = V4L2_STD_PAL_DK;
895 } else if ( (id & V4L2_STD_PAL_B) == V4L2_STD_PAL_B) {
896 curr_id = V4L2_STD_PAL_B;
897 } else if ( (id & V4L2_STD_PAL_B1) == V4L2_STD_PAL_B1) {
898 curr_id = V4L2_STD_PAL_B1;
899 } else if ( (id & V4L2_STD_PAL_G) == V4L2_STD_PAL_G) {
900 curr_id = V4L2_STD_PAL_G;
901 } else if ( (id & V4L2_STD_PAL_H) == V4L2_STD_PAL_H) {
902 curr_id = V4L2_STD_PAL_H;
903 } else if ( (id & V4L2_STD_PAL_I) == V4L2_STD_PAL_I) {
904 curr_id = V4L2_STD_PAL_I;
905 } else if ( (id & V4L2_STD_PAL_D) == V4L2_STD_PAL_D) {
906 curr_id = V4L2_STD_PAL_D;
907 } else if ( (id & V4L2_STD_PAL_D1) == V4L2_STD_PAL_D1) {
908 curr_id = V4L2_STD_PAL_D1;
909 } else if ( (id & V4L2_STD_PAL_K) == V4L2_STD_PAL_K) {
910 curr_id = V4L2_STD_PAL_K;
911 } else if ( (id & V4L2_STD_PAL_M) == V4L2_STD_PAL_M) {
912 curr_id = V4L2_STD_PAL_M;
913 } else if ( (id & V4L2_STD_PAL_N) == V4L2_STD_PAL_N) {
914 curr_id = V4L2_STD_PAL_N;
915 } else if ( (id & V4L2_STD_PAL_Nc) == V4L2_STD_PAL_Nc) {
916 curr_id = V4L2_STD_PAL_Nc;
917 } else if ( (id & V4L2_STD_PAL_60) == V4L2_STD_PAL_60) {
918 curr_id = V4L2_STD_PAL_60;
919 } else if ( (id & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
920 curr_id = V4L2_STD_NTSC;
921 } else if ( (id & V4L2_STD_NTSC_M) == V4L2_STD_NTSC_M) {
922 curr_id = V4L2_STD_NTSC_M;
923 } else if ( (id & V4L2_STD_NTSC_M_JP) == V4L2_STD_NTSC_M_JP) {
924 curr_id = V4L2_STD_NTSC_M_JP;
925 } else if ( (id & V4L2_STD_NTSC_443) == V4L2_STD_NTSC_443) {
926 curr_id = V4L2_STD_NTSC_443;
927 } else if ( (id & V4L2_STD_NTSC_M_KR) == V4L2_STD_NTSC_M_KR) {
928 curr_id = V4L2_STD_NTSC_M_KR;
929 } else if ( (id & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
930 curr_id = V4L2_STD_SECAM;
931 } else if ( (id & V4L2_STD_SECAM_DK) == V4L2_STD_SECAM_DK) {
932 curr_id = V4L2_STD_SECAM_DK;
933 } else if ( (id & V4L2_STD_SECAM_B) == V4L2_STD_SECAM_B) {
934 curr_id = V4L2_STD_SECAM_B;
935 } else if ( (id & V4L2_STD_SECAM_D) == V4L2_STD_SECAM_D) {
936 curr_id = V4L2_STD_SECAM_D;
937 } else if ( (id & V4L2_STD_SECAM_G) == V4L2_STD_SECAM_G) {
938 curr_id = V4L2_STD_SECAM_G;
939 } else if ( (id & V4L2_STD_SECAM_H) == V4L2_STD_SECAM_H) {
940 curr_id = V4L2_STD_SECAM_H;
941 } else if ( (id & V4L2_STD_SECAM_K) == V4L2_STD_SECAM_K) {
942 curr_id = V4L2_STD_SECAM_K;
943 } else if ( (id & V4L2_STD_SECAM_K1) == V4L2_STD_SECAM_K1) {
944 curr_id = V4L2_STD_SECAM_K1;
945 } else if ( (id & V4L2_STD_SECAM_L) == V4L2_STD_SECAM_L) {
946 curr_id = V4L2_STD_SECAM_L;
947 } else if ( (id & V4L2_STD_SECAM_LC) == V4L2_STD_SECAM_LC) {
948 curr_id = V4L2_STD_SECAM_LC;
949 } else {
950 break;
951 }
952 id &= ~curr_id;
953 }
954 if (i<=index)
955 return -EINVAL;
956
957 v4l2_video_std_construct(p, curr_id,v4l2_norm_to_name(curr_id));
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300958 p->index = index;
959
960 dbgarg (cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, "
961 "framelines=%d\n", p->index,
962 (unsigned long long)p->id, p->name,
963 p->frameperiod.numerator,
964 p->frameperiod.denominator,
965 p->framelines);
966
967 ret=0;
968 break;
969 }
970 case VIDIOC_G_STD:
971 {
972 v4l2_std_id *id = arg;
973
974 *id = vfd->current_norm;
975
976 dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
977
978 ret=0;
979 break;
980 }
981 case VIDIOC_S_STD:
982 {
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300983 v4l2_std_id *id = arg,norm;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300984
985 dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
986
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300987 norm = (*id) & vfd->tvnorms;
988 if ( vfd->tvnorms && !norm) /* Check if std is supported */
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300989 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300990
991 /* Calls the specific handler */
992 if (vfd->vidioc_s_std)
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300993 ret=vfd->vidioc_s_std(file, fh, &norm);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300994 else
995 ret=-EINVAL;
996
997 /* Updates standard information */
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300998 if (ret>=0)
999 vfd->current_norm=norm;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001000
1001 break;
1002 }
1003 case VIDIOC_QUERYSTD:
1004 {
1005 v4l2_std_id *p=arg;
1006
1007 if (!vfd->vidioc_querystd)
1008 break;
1009 ret=vfd->vidioc_querystd(file, fh, arg);
1010 if (!ret)
1011 dbgarg (cmd, "detected std=%Lu\n",
1012 (unsigned long long)*p);
1013 break;
1014 }
1015 /* ------ input switching ---------- */
1016 /* FIXME: Inputs can be handled inside videodev2 */
1017 case VIDIOC_ENUMINPUT:
1018 {
1019 struct v4l2_input *p=arg;
1020 int i=p->index;
1021
1022 if (!vfd->vidioc_enum_input)
1023 break;
1024 memset(p, 0, sizeof(*p));
1025 p->index=i;
1026
1027 ret=vfd->vidioc_enum_input(file, fh, p);
1028 if (!ret)
1029 dbgarg (cmd, "index=%d, name=%s, type=%d, "
1030 "audioset=%d, "
1031 "tuner=%d, std=%Ld, status=%d\n",
1032 p->index,p->name,p->type,p->audioset,
1033 p->tuner,
1034 (unsigned long long)p->std,
1035 p->status);
1036 break;
1037 }
1038 case VIDIOC_G_INPUT:
1039 {
1040 unsigned int *i = arg;
1041
1042 if (!vfd->vidioc_g_input)
1043 break;
1044 ret=vfd->vidioc_g_input(file, fh, i);
1045 if (!ret)
1046 dbgarg (cmd, "value=%d\n",*i);
1047 break;
1048 }
1049 case VIDIOC_S_INPUT:
1050 {
1051 unsigned int *i = arg;
1052
1053 if (!vfd->vidioc_s_input)
1054 break;
1055 dbgarg (cmd, "value=%d\n",*i);
1056 ret=vfd->vidioc_s_input(file, fh, *i);
1057 break;
1058 }
1059
1060 /* ------ output switching ---------- */
1061 case VIDIOC_G_OUTPUT:
1062 {
1063 unsigned int *i = arg;
1064
1065 if (!vfd->vidioc_g_output)
1066 break;
1067 ret=vfd->vidioc_g_output(file, fh, i);
1068 if (!ret)
1069 dbgarg (cmd, "value=%d\n",*i);
1070 break;
1071 }
1072 case VIDIOC_S_OUTPUT:
1073 {
1074 unsigned int *i = arg;
1075
1076 if (!vfd->vidioc_s_output)
1077 break;
1078 dbgarg (cmd, "value=%d\n",*i);
1079 ret=vfd->vidioc_s_output(file, fh, *i);
1080 break;
1081 }
1082
1083 /* --- controls ---------------------------------------------- */
1084 case VIDIOC_QUERYCTRL:
1085 {
1086 struct v4l2_queryctrl *p=arg;
1087
1088 if (!vfd->vidioc_queryctrl)
1089 break;
1090 ret=vfd->vidioc_queryctrl(file, fh, p);
1091
1092 if (!ret)
1093 dbgarg (cmd, "id=%d, type=%d, name=%s, "
1094 "min/max=%d/%d,"
1095 " step=%d, default=%d, flags=0x%08x\n",
1096 p->id,p->type,p->name,p->minimum,
1097 p->maximum,p->step,p->default_value,
1098 p->flags);
1099 break;
1100 }
1101 case VIDIOC_G_CTRL:
1102 {
1103 struct v4l2_control *p = arg;
1104
1105 if (!vfd->vidioc_g_ctrl)
1106 break;
1107 dbgarg(cmd, "Enum for index=%d\n", p->id);
1108
1109 ret=vfd->vidioc_g_ctrl(file, fh, p);
1110 if (!ret)
1111 dbgarg2 ( "id=%d, value=%d\n", p->id, p->value);
1112 break;
1113 }
1114 case VIDIOC_S_CTRL:
1115 {
1116 struct v4l2_control *p = arg;
1117
1118 if (!vfd->vidioc_s_ctrl)
1119 break;
1120 dbgarg (cmd, "id=%d, value=%d\n", p->id, p->value);
1121
1122 ret=vfd->vidioc_s_ctrl(file, fh, p);
1123 break;
1124 }
Hans Verkuil05976912006-06-18 13:43:28 -03001125 case VIDIOC_G_EXT_CTRLS:
1126 {
1127 struct v4l2_ext_controls *p = arg;
1128
1129 if (vfd->vidioc_g_ext_ctrls) {
1130 dbgarg(cmd, "count=%d\n", p->count);
1131
1132 ret=vfd->vidioc_g_ext_ctrls(file, fh, p);
1133 }
1134 break;
1135 }
1136 case VIDIOC_S_EXT_CTRLS:
1137 {
1138 struct v4l2_ext_controls *p = arg;
1139
1140 if (vfd->vidioc_s_ext_ctrls) {
1141 dbgarg(cmd, "count=%d\n", p->count);
1142
1143 ret=vfd->vidioc_s_ext_ctrls(file, fh, p);
1144 }
1145 break;
1146 }
1147 case VIDIOC_TRY_EXT_CTRLS:
1148 {
1149 struct v4l2_ext_controls *p = arg;
1150
1151 if (vfd->vidioc_try_ext_ctrls) {
1152 dbgarg(cmd, "count=%d\n", p->count);
1153
1154 ret=vfd->vidioc_try_ext_ctrls(file, fh, p);
1155 }
1156 break;
1157 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001158 case VIDIOC_QUERYMENU:
1159 {
1160 struct v4l2_querymenu *p=arg;
1161 if (!vfd->vidioc_querymenu)
1162 break;
1163 ret=vfd->vidioc_querymenu(file, fh, p);
1164 if (!ret)
1165 dbgarg (cmd, "id=%d, index=%d, name=%s\n",
1166 p->id,p->index,p->name);
1167 break;
1168 }
1169 /* --- audio ---------------------------------------------- */
1170 case VIDIOC_ENUMAUDIO:
1171 {
1172 struct v4l2_audio *p=arg;
1173
1174 if (!vfd->vidioc_enumaudio)
1175 break;
1176 dbgarg(cmd, "Enum for index=%d\n", p->index);
1177 ret=vfd->vidioc_enumaudio(file, fh, p);
1178 if (!ret)
1179 dbgarg2("index=%d, name=%s, capability=%d, "
1180 "mode=%d\n",p->index,p->name,
1181 p->capability, p->mode);
1182 break;
1183 }
1184 case VIDIOC_G_AUDIO:
1185 {
1186 struct v4l2_audio *p=arg;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001187 __u32 index=p->index;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001188
1189 if (!vfd->vidioc_g_audio)
1190 break;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001191
1192 memset(p,0,sizeof(*p));
1193 p->index=index;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001194 dbgarg(cmd, "Get for index=%d\n", p->index);
1195 ret=vfd->vidioc_g_audio(file, fh, p);
1196 if (!ret)
1197 dbgarg2("index=%d, name=%s, capability=%d, "
1198 "mode=%d\n",p->index,
1199 p->name,p->capability, p->mode);
1200 break;
1201 }
1202 case VIDIOC_S_AUDIO:
1203 {
1204 struct v4l2_audio *p=arg;
1205
1206 if (!vfd->vidioc_s_audio)
1207 break;
1208 dbgarg(cmd, "index=%d, name=%s, capability=%d, "
1209 "mode=%d\n", p->index, p->name,
1210 p->capability, p->mode);
1211 ret=vfd->vidioc_s_audio(file, fh, p);
1212 break;
1213 }
1214 case VIDIOC_ENUMAUDOUT:
1215 {
1216 struct v4l2_audioout *p=arg;
1217
1218 if (!vfd->vidioc_enumaudout)
1219 break;
1220 dbgarg(cmd, "Enum for index=%d\n", p->index);
1221 ret=vfd->vidioc_enumaudout(file, fh, p);
1222 if (!ret)
1223 dbgarg2("index=%d, name=%s, capability=%d, "
1224 "mode=%d\n", p->index, p->name,
1225 p->capability,p->mode);
1226 break;
1227 }
1228 case VIDIOC_G_AUDOUT:
1229 {
1230 struct v4l2_audioout *p=arg;
1231
1232 if (!vfd->vidioc_g_audout)
1233 break;
1234 dbgarg(cmd, "Enum for index=%d\n", p->index);
1235 ret=vfd->vidioc_g_audout(file, fh, p);
1236 if (!ret)
1237 dbgarg2("index=%d, name=%s, capability=%d, "
1238 "mode=%d\n", p->index, p->name,
1239 p->capability,p->mode);
1240 break;
1241 }
1242 case VIDIOC_S_AUDOUT:
1243 {
1244 struct v4l2_audioout *p=arg;
1245
1246 if (!vfd->vidioc_s_audout)
1247 break;
1248 dbgarg(cmd, "index=%d, name=%s, capability=%d, "
1249 "mode=%d\n", p->index, p->name,
1250 p->capability,p->mode);
1251
1252 ret=vfd->vidioc_s_audout(file, fh, p);
1253 break;
1254 }
1255 case VIDIOC_G_MODULATOR:
1256 {
1257 struct v4l2_modulator *p=arg;
1258 if (!vfd->vidioc_g_modulator)
1259 break;
1260 ret=vfd->vidioc_g_modulator(file, fh, p);
1261 if (!ret)
1262 dbgarg(cmd, "index=%d, name=%s, "
1263 "capability=%d, rangelow=%d,"
1264 " rangehigh=%d, txsubchans=%d\n",
1265 p->index, p->name,p->capability,
1266 p->rangelow, p->rangehigh,
1267 p->txsubchans);
1268 break;
1269 }
1270 case VIDIOC_S_MODULATOR:
1271 {
1272 struct v4l2_modulator *p=arg;
1273 if (!vfd->vidioc_s_modulator)
1274 break;
1275 dbgarg(cmd, "index=%d, name=%s, capability=%d, "
1276 "rangelow=%d, rangehigh=%d, txsubchans=%d\n",
1277 p->index, p->name,p->capability,p->rangelow,
1278 p->rangehigh,p->txsubchans);
1279 ret=vfd->vidioc_s_modulator(file, fh, p);
1280 break;
1281 }
1282 case VIDIOC_G_CROP:
1283 {
1284 struct v4l2_crop *p=arg;
1285 if (!vfd->vidioc_g_crop)
1286 break;
1287 ret=vfd->vidioc_g_crop(file, fh, p);
1288 if (!ret) {
1289 dbgarg(cmd, "type=%d\n", p->type);
1290 dbgrect(vfd, "", &p->c);
1291 }
1292 break;
1293 }
1294 case VIDIOC_S_CROP:
1295 {
1296 struct v4l2_crop *p=arg;
1297 if (!vfd->vidioc_s_crop)
1298 break;
1299 dbgarg(cmd, "type=%d\n", p->type);
1300 dbgrect(vfd, "", &p->c);
1301 ret=vfd->vidioc_s_crop(file, fh, p);
1302 break;
1303 }
1304 case VIDIOC_CROPCAP:
1305 {
1306 struct v4l2_cropcap *p=arg;
1307 /*FIXME: Should also show v4l2_fract pixelaspect */
1308 if (!vfd->vidioc_cropcap)
1309 break;
1310 dbgarg(cmd, "type=%d\n", p->type);
1311 dbgrect(vfd, "bounds ", &p->bounds);
1312 dbgrect(vfd, "defrect ", &p->defrect);
1313 ret=vfd->vidioc_cropcap(file, fh, p);
1314 break;
1315 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001316 case VIDIOC_G_JPEGCOMP:
1317 {
1318 struct v4l2_jpegcompression *p=arg;
1319 if (!vfd->vidioc_g_jpegcomp)
1320 break;
1321 ret=vfd->vidioc_g_jpegcomp(file, fh, p);
1322 if (!ret)
1323 dbgarg (cmd, "quality=%d, APPn=%d, "
1324 "APP_len=%d, COM_len=%d, "
1325 "jpeg_markers=%d\n",
1326 p->quality,p->APPn,p->APP_len,
1327 p->COM_len,p->jpeg_markers);
1328 break;
1329 }
1330 case VIDIOC_S_JPEGCOMP:
1331 {
1332 struct v4l2_jpegcompression *p=arg;
1333 if (!vfd->vidioc_g_jpegcomp)
1334 break;
1335 dbgarg (cmd, "quality=%d, APPn=%d, APP_len=%d, "
1336 "COM_len=%d, jpeg_markers=%d\n",
1337 p->quality,p->APPn,p->APP_len,
1338 p->COM_len,p->jpeg_markers);
1339 ret=vfd->vidioc_s_jpegcomp(file, fh, p);
1340 break;
1341 }
Hans Verkuildb6eb5b2007-02-18 14:05:02 -03001342 case VIDIOC_G_ENC_INDEX:
1343 {
1344 struct v4l2_enc_idx *p=arg;
1345
1346 if (!vfd->vidioc_g_enc_index)
1347 break;
1348 ret=vfd->vidioc_g_enc_index(file, fh, p);
1349 if (!ret)
1350 dbgarg (cmd, "entries=%d, entries_cap=%d\n",
1351 p->entries,p->entries_cap);
1352 break;
1353 }
Hans Verkuilada6ecd2007-02-18 14:56:22 -03001354 case VIDIOC_ENCODER_CMD:
1355 {
1356 struct v4l2_encoder_cmd *p=arg;
1357
1358 if (!vfd->vidioc_encoder_cmd)
1359 break;
1360 ret=vfd->vidioc_encoder_cmd(file, fh, p);
1361 if (!ret)
1362 dbgarg (cmd, "cmd=%d, flags=%d\n",
1363 p->cmd,p->flags);
1364 break;
1365 }
1366 case VIDIOC_TRY_ENCODER_CMD:
1367 {
1368 struct v4l2_encoder_cmd *p=arg;
1369
1370 if (!vfd->vidioc_try_encoder_cmd)
1371 break;
1372 ret=vfd->vidioc_try_encoder_cmd(file, fh, p);
1373 if (!ret)
1374 dbgarg (cmd, "cmd=%d, flags=%d\n",
1375 p->cmd,p->flags);
1376 break;
1377 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001378 case VIDIOC_G_PARM:
1379 {
1380 struct v4l2_streamparm *p=arg;
Mauro Carvalho Chehab2aa23422007-04-24 13:40:07 -03001381 __u32 type=p->type;
1382
1383 memset(p,0,sizeof(*p));
1384 p->type=type;
1385
Mauro Carvalho Chehab1c2d0342006-09-14 13:36:34 -03001386 if (vfd->vidioc_g_parm) {
1387 ret=vfd->vidioc_g_parm(file, fh, p);
1388 } else {
1389 struct v4l2_standard s;
Mauro Carvalho Chehab1c2d0342006-09-14 13:36:34 -03001390
1391 if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1392 return -EINVAL;
1393
Jonathan Corbet83427ac2006-10-13 07:51:16 -03001394 v4l2_video_std_construct(&s, vfd->current_norm,
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001395 v4l2_norm_to_name(vfd->current_norm));
Mauro Carvalho Chehab1c2d0342006-09-14 13:36:34 -03001396
Mauro Carvalho Chehab1c2d0342006-09-14 13:36:34 -03001397 p->parm.capture.timeperframe = s.frameperiod;
1398 ret=0;
1399 }
1400
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001401 dbgarg (cmd, "type=%d\n", p->type);
1402 break;
1403 }
1404 case VIDIOC_S_PARM:
1405 {
1406 struct v4l2_streamparm *p=arg;
1407 if (!vfd->vidioc_s_parm)
1408 break;
1409 dbgarg (cmd, "type=%d\n", p->type);
1410 ret=vfd->vidioc_s_parm(file, fh, p);
1411 break;
1412 }
1413 case VIDIOC_G_TUNER:
1414 {
1415 struct v4l2_tuner *p=arg;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001416 __u32 index=p->index;
1417
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001418 if (!vfd->vidioc_g_tuner)
1419 break;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001420
1421 memset(p,0,sizeof(*p));
1422 p->index=index;
1423
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001424 ret=vfd->vidioc_g_tuner(file, fh, p);
1425 if (!ret)
1426 dbgarg (cmd, "index=%d, name=%s, type=%d, "
1427 "capability=%d, rangelow=%d, "
1428 "rangehigh=%d, signal=%d, afc=%d, "
1429 "rxsubchans=%d, audmode=%d\n",
1430 p->index, p->name, p->type,
1431 p->capability, p->rangelow,
1432 p->rangehigh, p->rxsubchans,
1433 p->audmode, p->signal, p->afc);
1434 break;
1435 }
1436 case VIDIOC_S_TUNER:
1437 {
1438 struct v4l2_tuner *p=arg;
1439 if (!vfd->vidioc_s_tuner)
1440 break;
1441 dbgarg (cmd, "index=%d, name=%s, type=%d, "
1442 "capability=%d, rangelow=%d, rangehigh=%d, "
1443 "signal=%d, afc=%d, rxsubchans=%d, "
1444 "audmode=%d\n",p->index, p->name, p->type,
1445 p->capability, p->rangelow,p->rangehigh,
1446 p->rxsubchans, p->audmode, p->signal,
1447 p->afc);
1448 ret=vfd->vidioc_s_tuner(file, fh, p);
1449 break;
1450 }
1451 case VIDIOC_G_FREQUENCY:
1452 {
1453 struct v4l2_frequency *p=arg;
1454 if (!vfd->vidioc_g_frequency)
1455 break;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001456
1457 memset(p,0,sizeof(*p));
1458
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001459 ret=vfd->vidioc_g_frequency(file, fh, p);
1460 if (!ret)
1461 dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
1462 p->tuner,p->type,p->frequency);
1463 break;
1464 }
1465 case VIDIOC_S_FREQUENCY:
1466 {
1467 struct v4l2_frequency *p=arg;
1468 if (!vfd->vidioc_s_frequency)
1469 break;
1470 dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
1471 p->tuner,p->type,p->frequency);
1472 ret=vfd->vidioc_s_frequency(file, fh, p);
1473 break;
1474 }
1475 case VIDIOC_G_SLICED_VBI_CAP:
1476 {
1477 struct v4l2_sliced_vbi_cap *p=arg;
1478 if (!vfd->vidioc_g_sliced_vbi_cap)
1479 break;
1480 ret=vfd->vidioc_g_sliced_vbi_cap(file, fh, p);
1481 if (!ret)
1482 dbgarg (cmd, "service_set=%d\n", p->service_set);
1483 break;
1484 }
1485 case VIDIOC_LOG_STATUS:
1486 {
1487 if (!vfd->vidioc_log_status)
1488 break;
1489 ret=vfd->vidioc_log_status(file, fh);
1490 break;
1491 }
Trent Piephodbbff482007-01-22 23:31:53 -03001492#ifdef CONFIG_VIDEO_ADV_DEBUG
Trent Piepho52ebc762007-01-23 22:38:13 -03001493 case VIDIOC_DBG_G_REGISTER:
Trent Piephodbbff482007-01-22 23:31:53 -03001494 {
1495 struct v4l2_register *p=arg;
Trent Piepho62d50ad2007-01-30 23:25:41 -03001496 if (!capable(CAP_SYS_ADMIN))
1497 ret=-EPERM;
1498 else if (vfd->vidioc_g_register)
Trent Piephodbbff482007-01-22 23:31:53 -03001499 ret=vfd->vidioc_g_register(file, fh, p);
1500 break;
1501 }
Trent Piepho52ebc762007-01-23 22:38:13 -03001502 case VIDIOC_DBG_S_REGISTER:
Trent Piephodbbff482007-01-22 23:31:53 -03001503 {
1504 struct v4l2_register *p=arg;
Trent Piepho52ebc762007-01-23 22:38:13 -03001505 if (!capable(CAP_SYS_ADMIN))
1506 ret=-EPERM;
1507 else if (vfd->vidioc_s_register)
Trent Piephodbbff482007-01-22 23:31:53 -03001508 ret=vfd->vidioc_s_register(file, fh, p);
1509 break;
1510 }
1511#endif
Hans Verkuil3434eb72007-04-27 12:31:08 -03001512 case VIDIOC_G_CHIP_IDENT:
1513 {
1514 struct v4l2_chip_ident *p=arg;
1515 if (!vfd->vidioc_g_chip_ident)
1516 break;
1517 ret=vfd->vidioc_g_chip_ident(file, fh, p);
1518 if (!ret)
1519 dbgarg (cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision);
1520 break;
1521 }
Mauro Carvalho Chehab207705c2006-11-20 12:13:25 -03001522 } /* switch */
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001523
1524 if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
1525 if (ret<0) {
1526 printk ("%s: err:\n", vfd->name);
1527 v4l_print_ioctl(vfd->name, cmd);
1528 }
1529 }
1530
1531 return ret;
1532}
1533
1534int video_ioctl2 (struct inode *inode, struct file *file,
1535 unsigned int cmd, unsigned long arg)
1536{
1537 char sbuf[128];
1538 void *mbuf = NULL;
1539 void *parg = NULL;
1540 int err = -EINVAL;
Hans Verkuil05976912006-06-18 13:43:28 -03001541 int is_ext_ctrl;
1542 size_t ctrls_size = 0;
1543 void __user *user_ptr = NULL;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001544
1545#ifdef __OLD_VIDIOC_
1546 cmd = video_fix_command(cmd);
1547#endif
Hans Verkuil05976912006-06-18 13:43:28 -03001548 is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
1549 cmd == VIDIOC_TRY_EXT_CTRLS);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001550
1551 /* Copy arguments into temp kernel buffer */
1552 switch (_IOC_DIR(cmd)) {
1553 case _IOC_NONE:
1554 parg = NULL;
1555 break;
1556 case _IOC_READ:
1557 case _IOC_WRITE:
1558 case (_IOC_WRITE | _IOC_READ):
1559 if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
1560 parg = sbuf;
1561 } else {
1562 /* too big to allocate from stack */
1563 mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
1564 if (NULL == mbuf)
1565 return -ENOMEM;
1566 parg = mbuf;
1567 }
1568
1569 err = -EFAULT;
1570 if (_IOC_DIR(cmd) & _IOC_WRITE)
1571 if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
1572 goto out;
1573 break;
1574 }
1575
Hans Verkuil05976912006-06-18 13:43:28 -03001576 if (is_ext_ctrl) {
1577 struct v4l2_ext_controls *p = parg;
1578
1579 /* In case of an error, tell the caller that it wasn't
1580 a specific control that caused it. */
1581 p->error_idx = p->count;
1582 user_ptr = (void __user *)p->controls;
1583 if (p->count) {
1584 ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
1585 /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
1586 mbuf = kmalloc(ctrls_size, GFP_KERNEL);
1587 err = -ENOMEM;
1588 if (NULL == mbuf)
1589 goto out_ext_ctrl;
1590 err = -EFAULT;
1591 if (copy_from_user(mbuf, user_ptr, ctrls_size))
1592 goto out_ext_ctrl;
1593 p->controls = mbuf;
1594 }
1595 }
1596
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001597 /* Handles IOCTL */
1598 err = __video_do_ioctl(inode, file, cmd, parg);
1599 if (err == -ENOIOCTLCMD)
1600 err = -EINVAL;
Hans Verkuil05976912006-06-18 13:43:28 -03001601 if (is_ext_ctrl) {
1602 struct v4l2_ext_controls *p = parg;
1603
1604 p->controls = (void *)user_ptr;
1605 if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
1606 err = -EFAULT;
1607 goto out_ext_ctrl;
1608 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001609 if (err < 0)
1610 goto out;
1611
Hans Verkuil05976912006-06-18 13:43:28 -03001612out_ext_ctrl:
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001613 /* Copy results into user buffer */
1614 switch (_IOC_DIR(cmd))
1615 {
1616 case _IOC_READ:
1617 case (_IOC_WRITE | _IOC_READ):
1618 if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
1619 err = -EFAULT;
1620 break;
1621 }
1622
1623out:
1624 kfree(mbuf);
1625 return err;
1626}
1627
1628
Arjan van de Venfa027c22007-02-12 00:55:33 -08001629static const struct file_operations video_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630
1631/**
1632 * video_register_device - register video4linux devices
1633 * @vfd: video device structure we want to register
1634 * @type: type of device to register
1635 * @nr: which device number (0 == /dev/video0, 1 == /dev/video1, ...
1636 * -1 == first free)
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001637 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 * The registration code assigns minor numbers based on the type
1639 * requested. -ENFILE is returned in all the device slots for this
1640 * category are full. If not then the minor field is set and the
1641 * driver initialize function is called (if non %NULL).
1642 *
1643 * Zero is returned on success.
1644 *
1645 * Valid types are
1646 *
1647 * %VFL_TYPE_GRABBER - A frame grabber
1648 *
1649 * %VFL_TYPE_VTX - A teletext device
1650 *
1651 * %VFL_TYPE_VBI - Vertical blank data (undecoded)
1652 *
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001653 * %VFL_TYPE_RADIO - A radio card
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 */
1655
1656int video_register_device(struct video_device *vfd, int type, int nr)
1657{
1658 int i=0;
1659 int base;
1660 int end;
Michael Krufky3117bee2006-07-19 13:23:38 -03001661 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 char *name_base;
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001663
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 switch(type)
1665 {
1666 case VFL_TYPE_GRABBER:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02001667 base=MINOR_VFL_TYPE_GRABBER_MIN;
1668 end=MINOR_VFL_TYPE_GRABBER_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 name_base = "video";
1670 break;
1671 case VFL_TYPE_VTX:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02001672 base=MINOR_VFL_TYPE_VTX_MIN;
1673 end=MINOR_VFL_TYPE_VTX_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 name_base = "vtx";
1675 break;
1676 case VFL_TYPE_VBI:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02001677 base=MINOR_VFL_TYPE_VBI_MIN;
1678 end=MINOR_VFL_TYPE_VBI_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 name_base = "vbi";
1680 break;
1681 case VFL_TYPE_RADIO:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02001682 base=MINOR_VFL_TYPE_RADIO_MIN;
1683 end=MINOR_VFL_TYPE_RADIO_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 name_base = "radio";
1685 break;
1686 default:
Trent Piepho53dd8de2006-07-25 09:31:42 -03001687 printk(KERN_ERR "%s called with unknown type: %d\n",
1688 __FUNCTION__, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 return -1;
1690 }
1691
1692 /* pick a minor number */
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001693 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 if (nr >= 0 && nr < end-base) {
1695 /* use the one the driver asked for */
1696 i = base+nr;
1697 if (NULL != video_device[i]) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001698 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 return -ENFILE;
1700 }
1701 } else {
1702 /* use first free */
1703 for(i=base;i<end;i++)
1704 if (NULL == video_device[i])
1705 break;
1706 if (i == end) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001707 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 return -ENFILE;
1709 }
1710 }
1711 video_device[i]=vfd;
1712 vfd->minor=i;
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001713 mutex_unlock(&videodev_lock);
Ingo Molnar3593cab2006-02-07 06:49:14 -02001714 mutex_init(&vfd->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715
1716 /* sysfs class */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001717 memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 if (vfd->dev)
Kay Sievers54bd5b62007-10-08 16:26:13 -03001719 vfd->class_dev.parent = vfd->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 vfd->class_dev.class = &video_class;
Michael Krufky50c25ff2006-01-09 15:25:34 -02001721 vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
Kay Sievers54bd5b62007-10-08 16:26:13 -03001722 sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base);
1723 ret = device_register(&vfd->class_dev);
Trent Piepho8c313112006-07-25 20:37:03 -03001724 if (ret < 0) {
Kay Sievers54bd5b62007-10-08 16:26:13 -03001725 printk(KERN_ERR "%s: device_register failed\n",
Michael Krufky3117bee2006-07-19 13:23:38 -03001726 __FUNCTION__);
Trent Piephod94fc9a2006-07-29 17:18:06 -03001727 goto fail_minor;
Michael Krufky3117bee2006-07-19 13:23:38 -03001728 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729
Mauro Carvalho Chehabd21838d2006-01-09 15:25:21 -02001730#if 1
1731 /* needed until all drivers are fixed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 if (!vfd->release)
1733 printk(KERN_WARNING "videodev: \"%s\" has no release callback. "
1734 "Please fix your driver for proper sysfs support, see "
1735 "http://lwn.net/Articles/36850/\n", vfd->name);
1736#endif
1737 return 0;
Trent Piepho53dd8de2006-07-25 09:31:42 -03001738
Trent Piepho53dd8de2006-07-25 09:31:42 -03001739fail_minor:
1740 mutex_lock(&videodev_lock);
1741 video_device[vfd->minor] = NULL;
1742 vfd->minor = -1;
1743 mutex_unlock(&videodev_lock);
1744 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745}
1746
1747/**
1748 * video_unregister_device - unregister a video4linux device
1749 * @vfd: the device to unregister
1750 *
1751 * This unregisters the passed device and deassigns the minor
1752 * number. Future open calls will be met with errors.
1753 */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001754
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755void video_unregister_device(struct video_device *vfd)
1756{
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001757 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 if(video_device[vfd->minor]!=vfd)
1759 panic("videodev: bad unregister");
1760
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 video_device[vfd->minor]=NULL;
Kay Sievers54bd5b62007-10-08 16:26:13 -03001762 device_unregister(&vfd->class_dev);
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001763 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764}
1765
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001766/*
1767 * Video fs operations
1768 */
Arjan van de Venfa027c22007-02-12 00:55:33 -08001769static const struct file_operations video_fops=
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770{
1771 .owner = THIS_MODULE,
1772 .llseek = no_llseek,
1773 .open = video_open,
1774};
1775
1776/*
1777 * Initialise video for linux
1778 */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001779
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780static int __init videodev_init(void)
1781{
1782 int ret;
1783
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001784 printk(KERN_INFO "Linux video capture interface: v2.00\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) {
1786 printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR);
1787 return -EIO;
1788 }
1789
1790 ret = class_register(&video_class);
1791 if (ret < 0) {
1792 unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME);
1793 printk(KERN_WARNING "video_dev: class_register failed\n");
1794 return -EIO;
1795 }
1796
1797 return 0;
1798}
1799
1800static void __exit videodev_exit(void)
1801{
1802 class_unregister(&video_class);
1803 unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME);
1804}
1805
1806module_init(videodev_init)
1807module_exit(videodev_exit)
1808
1809EXPORT_SYMBOL(video_register_device);
1810EXPORT_SYMBOL(video_unregister_device);
1811EXPORT_SYMBOL(video_devdata);
1812EXPORT_SYMBOL(video_usercopy);
1813EXPORT_SYMBOL(video_exclusive_open);
1814EXPORT_SYMBOL(video_exclusive_release);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001815EXPORT_SYMBOL(video_ioctl2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816EXPORT_SYMBOL(video_device_alloc);
1817EXPORT_SYMBOL(video_device_release);
1818
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001819MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
1820MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821MODULE_LICENSE("GPL");
1822
1823
1824/*
1825 * Local variables:
1826 * c-basic-offset: 8
1827 * End:
1828 */