blob: 6a0e8ca7294803056cf29d11716d7ed175b35e5f [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>
33#include <linux/sched.h>
34#include <linux/smp_lock.h>
35#include <linux/mm.h>
36#include <linux/string.h>
37#include <linux/errno.h>
38#include <linux/init.h>
39#include <linux/kmod.h>
40#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <asm/uaccess.h>
42#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030044#define __OLD_VIDIOC_ /* To allow fixing old calls*/
45#include <linux/videodev2.h>
46
47#ifdef CONFIG_VIDEO_V4L1
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <linux/videodev.h>
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030049#endif
50#include <media/v4l2-common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52#define VIDEO_NUM_DEVICES 256
53#define VIDEO_NAME "video4linux"
54
55/*
56 * sysfs stuff
57 */
58
59static ssize_t show_name(struct class_device *cd, char *buf)
60{
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030061 struct video_device *vfd = container_of(cd, struct video_device,
62 class_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 return sprintf(buf,"%.*s\n",(int)sizeof(vfd->name),vfd->name);
64}
65
66static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
67
68struct video_device *video_device_alloc(void)
69{
70 struct video_device *vfd;
71
Panagiotis Issaris74081872006-01-11 19:40:56 -020072 vfd = kzalloc(sizeof(*vfd),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 return vfd;
74}
75
76void video_device_release(struct video_device *vfd)
77{
78 kfree(vfd);
79}
80
81static void video_release(struct class_device *cd)
82{
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030083 struct video_device *vfd = container_of(cd, struct video_device,
84 class_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
Mauro Carvalho Chehabd21838d2006-01-09 15:25:21 -020086#if 1
Michael Krufky50c25ff2006-01-09 15:25:34 -020087 /* needed until all drivers are fixed */
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 if (!vfd->release)
89 return;
90#endif
91 vfd->release(vfd);
92}
93
94static struct class video_class = {
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -080095 .name = VIDEO_NAME,
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 .release = video_release,
97};
98
99/*
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800100 * Active devices
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800102
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103static struct video_device *video_device[VIDEO_NUM_DEVICES];
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200104static DEFINE_MUTEX(videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
106struct video_device* video_devdata(struct file *file)
107{
Josef Sipek723731b2006-12-08 02:37:47 -0800108 return video_device[iminor(file->f_path.dentry->d_inode)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109}
110
111/*
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300112 * Open a video device - FIXME: Obsoleted
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 */
114static int video_open(struct inode *inode, struct file *file)
115{
116 unsigned int minor = iminor(inode);
117 int err = 0;
118 struct video_device *vfl;
Arjan van de Ven99ac48f2006-03-28 01:56:41 -0800119 const struct file_operations *old_fops;
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800120
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 if(minor>=VIDEO_NUM_DEVICES)
122 return -ENODEV;
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200123 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 vfl=video_device[minor];
125 if(vfl==NULL) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200126 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 request_module("char-major-%d-%d", VIDEO_MAJOR, minor);
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200128 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 vfl=video_device[minor];
130 if (vfl==NULL) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200131 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 return -ENODEV;
133 }
134 }
135 old_fops = file->f_op;
136 file->f_op = fops_get(vfl->fops);
137 if(file->f_op->open)
138 err = file->f_op->open(inode,file);
139 if (err) {
140 fops_put(file->f_op);
141 file->f_op = fops_get(old_fops);
142 }
143 fops_put(old_fops);
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200144 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 return err;
146}
147
148/*
149 * helper function -- handles userspace copying for ioctl arguments
150 */
151
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300152#ifdef __OLD_VIDIOC_
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153static unsigned int
154video_fix_command(unsigned int cmd)
155{
156 switch (cmd) {
157 case VIDIOC_OVERLAY_OLD:
158 cmd = VIDIOC_OVERLAY;
159 break;
160 case VIDIOC_S_PARM_OLD:
161 cmd = VIDIOC_S_PARM;
162 break;
163 case VIDIOC_S_CTRL_OLD:
164 cmd = VIDIOC_S_CTRL;
165 break;
166 case VIDIOC_G_AUDIO_OLD:
167 cmd = VIDIOC_G_AUDIO;
168 break;
169 case VIDIOC_G_AUDOUT_OLD:
170 cmd = VIDIOC_G_AUDOUT;
171 break;
172 case VIDIOC_CROPCAP_OLD:
173 cmd = VIDIOC_CROPCAP;
174 break;
175 }
176 return cmd;
177}
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300178#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300180/*
181 * Obsolete usercopy function - Should be removed soon
182 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183int
184video_usercopy(struct inode *inode, struct file *file,
185 unsigned int cmd, unsigned long arg,
186 int (*func)(struct inode *inode, struct file *file,
187 unsigned int cmd, void *arg))
188{
189 char sbuf[128];
190 void *mbuf = NULL;
191 void *parg = NULL;
192 int err = -EINVAL;
Hans Verkuil05976912006-06-18 13:43:28 -0300193 int is_ext_ctrl;
194 size_t ctrls_size = 0;
195 void __user *user_ptr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300197#ifdef __OLD_VIDIOC_
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 cmd = video_fix_command(cmd);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300199#endif
Hans Verkuil05976912006-06-18 13:43:28 -0300200 is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
201 cmd == VIDIOC_TRY_EXT_CTRLS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
203 /* Copy arguments into temp kernel buffer */
204 switch (_IOC_DIR(cmd)) {
205 case _IOC_NONE:
206 parg = NULL;
207 break;
208 case _IOC_READ:
209 case _IOC_WRITE:
210 case (_IOC_WRITE | _IOC_READ):
211 if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
212 parg = sbuf;
213 } else {
214 /* too big to allocate from stack */
215 mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
216 if (NULL == mbuf)
217 return -ENOMEM;
218 parg = mbuf;
219 }
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800220
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 err = -EFAULT;
222 if (_IOC_DIR(cmd) & _IOC_WRITE)
Hans Verkuil05976912006-06-18 13:43:28 -0300223 if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 goto out;
225 break;
226 }
Hans Verkuil05976912006-06-18 13:43:28 -0300227 if (is_ext_ctrl) {
228 struct v4l2_ext_controls *p = parg;
229
230 /* In case of an error, tell the caller that it wasn't
231 a specific control that caused it. */
232 p->error_idx = p->count;
233 user_ptr = (void __user *)p->controls;
234 if (p->count) {
235 ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
236 /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
237 mbuf = kmalloc(ctrls_size, GFP_KERNEL);
238 err = -ENOMEM;
239 if (NULL == mbuf)
240 goto out_ext_ctrl;
241 err = -EFAULT;
242 if (copy_from_user(mbuf, user_ptr, ctrls_size))
243 goto out_ext_ctrl;
244 p->controls = mbuf;
245 }
246 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
248 /* call driver */
249 err = func(inode, file, cmd, parg);
250 if (err == -ENOIOCTLCMD)
251 err = -EINVAL;
Hans Verkuil05976912006-06-18 13:43:28 -0300252 if (is_ext_ctrl) {
253 struct v4l2_ext_controls *p = parg;
254
255 p->controls = (void *)user_ptr;
256 if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
257 err = -EFAULT;
258 goto out_ext_ctrl;
259 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 if (err < 0)
261 goto out;
262
Hans Verkuil05976912006-06-18 13:43:28 -0300263out_ext_ctrl:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 /* Copy results into user buffer */
265 switch (_IOC_DIR(cmd))
266 {
267 case _IOC_READ:
268 case (_IOC_WRITE | _IOC_READ):
269 if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
270 err = -EFAULT;
271 break;
272 }
273
274out:
Jesper Juhl2ea75332005-11-07 01:01:31 -0800275 kfree(mbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 return err;
277}
278
279/*
280 * open/release helper functions -- handle exclusive opens
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300281 * Should be removed soon
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 */
283int video_exclusive_open(struct inode *inode, struct file *file)
284{
285 struct video_device *vfl = video_devdata(file);
286 int retval = 0;
287
Ingo Molnar3593cab2006-02-07 06:49:14 -0200288 mutex_lock(&vfl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 if (vfl->users) {
290 retval = -EBUSY;
291 } else {
292 vfl->users++;
293 }
Ingo Molnar3593cab2006-02-07 06:49:14 -0200294 mutex_unlock(&vfl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 return retval;
296}
297
298int video_exclusive_release(struct inode *inode, struct file *file)
299{
300 struct video_device *vfl = video_devdata(file);
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800301
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 vfl->users--;
303 return 0;
304}
305
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300306static char *v4l2_memory_names[] = {
307 [V4L2_MEMORY_MMAP] = "mmap",
308 [V4L2_MEMORY_USERPTR] = "userptr",
309 [V4L2_MEMORY_OVERLAY] = "overlay",
310};
311
312
313/* FIXME: Those stuff are replicated also on v4l2-common.c */
314static char *v4l2_type_names_FIXME[] = {
315 [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap",
316 [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over",
317 [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out",
318 [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap",
319 [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out",
320 [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out",
321 [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-capture",
322 [V4L2_BUF_TYPE_PRIVATE] = "private",
323};
324
325static char *v4l2_field_names_FIXME[] = {
326 [V4L2_FIELD_ANY] = "any",
327 [V4L2_FIELD_NONE] = "none",
328 [V4L2_FIELD_TOP] = "top",
329 [V4L2_FIELD_BOTTOM] = "bottom",
330 [V4L2_FIELD_INTERLACED] = "interlaced",
331 [V4L2_FIELD_SEQ_TB] = "seq-tb",
332 [V4L2_FIELD_SEQ_BT] = "seq-bt",
333 [V4L2_FIELD_ALTERNATE] = "alternate",
334};
335
336#define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown"
337
338static void dbgbuf(unsigned int cmd, struct video_device *vfd,
339 struct v4l2_buffer *p)
340{
341 struct v4l2_timecode *tc=&p->timecode;
342
343 dbgarg (cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, "
344 "bytesused=%d, flags=0x%08d, "
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300345 "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n",
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300346 (p->timestamp.tv_sec/3600),
347 (int)(p->timestamp.tv_sec/60)%60,
348 (int)(p->timestamp.tv_sec%60),
349 p->timestamp.tv_usec,
350 p->index,
351 prt_names(p->type,v4l2_type_names_FIXME),
352 p->bytesused,p->flags,
353 p->field,p->sequence,
354 prt_names(p->memory,v4l2_memory_names),
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300355 p->m.userptr, p->length);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300356 dbgarg2 ("timecode= %02d:%02d:%02d type=%d, "
357 "flags=0x%08d, frames=%d, userbits=0x%08x\n",
358 tc->hours,tc->minutes,tc->seconds,
Mauro Carvalho Chehabc18cb012006-06-23 07:05:22 -0300359 tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300360}
361
362static inline void dbgrect(struct video_device *vfd, char *s,
363 struct v4l2_rect *r)
364{
365 dbgarg2 ("%sRect start at %dx%d, size= %dx%d\n", s, r->left, r->top,
366 r->width, r->height);
367};
368
369static inline void v4l_print_pix_fmt (struct video_device *vfd,
370 struct v4l2_pix_format *fmt)
371{
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300372 dbgarg2 ("width=%d, height=%d, format=%c%c%c%c, field=%s, "
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300373 "bytesperline=%d sizeimage=%d, colorspace=%d\n",
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300374 fmt->width,fmt->height,
375 (fmt->pixelformat & 0xff),
376 (fmt->pixelformat >> 8) & 0xff,
377 (fmt->pixelformat >> 16) & 0xff,
378 (fmt->pixelformat >> 24) & 0xff,
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300379 prt_names(fmt->field,v4l2_field_names_FIXME),
380 fmt->bytesperline,fmt->sizeimage,fmt->colorspace);
381};
382
383
384static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type)
385{
386 switch (type) {
387 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
388 if (vfd->vidioc_try_fmt_cap)
389 return (0);
390 break;
391 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
392 if (vfd->vidioc_try_fmt_overlay)
393 return (0);
394 break;
395 case V4L2_BUF_TYPE_VBI_CAPTURE:
396 if (vfd->vidioc_try_fmt_vbi)
397 return (0);
398 break;
399 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
400 if (vfd->vidioc_try_fmt_vbi_output)
401 return (0);
402 break;
403 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
404 if (vfd->vidioc_try_fmt_vbi_capture)
405 return (0);
406 break;
407 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
408 if (vfd->vidioc_try_fmt_video_output)
409 return (0);
410 break;
411 case V4L2_BUF_TYPE_VBI_OUTPUT:
412 if (vfd->vidioc_try_fmt_vbi_output)
413 return (0);
414 break;
415 case V4L2_BUF_TYPE_PRIVATE:
416 if (vfd->vidioc_try_fmt_type_private)
417 return (0);
418 break;
419 }
420 return (-EINVAL);
421}
422
423static int __video_do_ioctl(struct inode *inode, struct file *file,
424 unsigned int cmd, void *arg)
425{
426 struct video_device *vfd = video_devdata(file);
427 void *fh = file->private_data;
428 int ret = -EINVAL;
429
430 if ( (vfd->debug & V4L2_DEBUG_IOCTL) &&
431 !(vfd->debug | V4L2_DEBUG_IOCTL_ARG)) {
432 v4l_print_ioctl(vfd->name, cmd);
433 }
434
Mauro Carvalho Chehab207705c2006-11-20 12:13:25 -0300435 if (_IOC_TYPE(cmd)=='v')
436 return v4l_compat_translate_ioctl(inode,file,cmd,arg,
437 __video_do_ioctl);
438
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300439 switch(cmd) {
440 /* --- capabilities ------------------------------------------ */
441 case VIDIOC_QUERYCAP:
442 {
443 struct v4l2_capability *cap = (struct v4l2_capability*)arg;
444 memset(cap, 0, sizeof(*cap));
445
446 if (!vfd->vidioc_querycap)
447 break;
448
449 ret=vfd->vidioc_querycap(file, fh, cap);
450 if (!ret)
451 dbgarg (cmd, "driver=%s, card=%s, bus=%s, "
452 "version=0x%08x, "
453 "capabilities=0x%08x\n",
454 cap->driver,cap->card,cap->bus_info,
455 cap->version,
456 cap->capabilities);
457 break;
458 }
459
460 /* --- priority ------------------------------------------ */
461 case VIDIOC_G_PRIORITY:
462 {
463 enum v4l2_priority *p=arg;
464
465 if (!vfd->vidioc_g_priority)
466 break;
467 ret=vfd->vidioc_g_priority(file, fh, p);
468 if (!ret)
469 dbgarg(cmd, "priority is %d\n", *p);
470 break;
471 }
472 case VIDIOC_S_PRIORITY:
473 {
474 enum v4l2_priority *p=arg;
475
476 if (!vfd->vidioc_s_priority)
477 break;
478 dbgarg(cmd, "setting priority to %d\n", *p);
479 ret=vfd->vidioc_s_priority(file, fh, *p);
480 break;
481 }
482
483 /* --- capture ioctls ---------------------------------------- */
484 case VIDIOC_ENUM_FMT:
485 {
486 struct v4l2_fmtdesc *f = arg;
487 enum v4l2_buf_type type;
488 unsigned int index;
489
490 index = f->index;
491 type = f->type;
492 memset(f,0,sizeof(*f));
493 f->index = index;
494 f->type = type;
495
496 switch (type) {
497 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
498 if (vfd->vidioc_enum_fmt_cap)
499 ret=vfd->vidioc_enum_fmt_cap(file, fh, f);
500 break;
501 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
502 if (vfd->vidioc_enum_fmt_overlay)
503 ret=vfd->vidioc_enum_fmt_overlay(file, fh, f);
504 break;
505 case V4L2_BUF_TYPE_VBI_CAPTURE:
506 if (vfd->vidioc_enum_fmt_vbi)
507 ret=vfd->vidioc_enum_fmt_vbi(file, fh, f);
508 break;
509 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
510 if (vfd->vidioc_enum_fmt_vbi_output)
511 ret=vfd->vidioc_enum_fmt_vbi_output(file,
512 fh, f);
513 break;
514 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
515 if (vfd->vidioc_enum_fmt_vbi_capture)
516 ret=vfd->vidioc_enum_fmt_vbi_capture(file,
517 fh, f);
518 break;
519 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
520 if (vfd->vidioc_enum_fmt_video_output)
521 ret=vfd->vidioc_enum_fmt_video_output(file,
522 fh, f);
523 break;
524 case V4L2_BUF_TYPE_VBI_OUTPUT:
525 if (vfd->vidioc_enum_fmt_vbi_output)
526 ret=vfd->vidioc_enum_fmt_vbi_output(file,
527 fh, f);
528 break;
529 case V4L2_BUF_TYPE_PRIVATE:
530 if (vfd->vidioc_enum_fmt_type_private)
531 ret=vfd->vidioc_enum_fmt_type_private(file,
532 fh, f);
533 break;
534 }
535 if (!ret)
536 dbgarg (cmd, "index=%d, type=%d, flags=%d, "
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300537 "pixelformat=%c%c%c%c, description='%s'\n",
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300538 f->index, f->type, f->flags,
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300539 (f->pixelformat & 0xff),
540 (f->pixelformat >> 8) & 0xff,
541 (f->pixelformat >> 16) & 0xff,
542 (f->pixelformat >> 24) & 0xff,
543 f->description);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300544 break;
545 }
546 case VIDIOC_G_FMT:
547 {
548 struct v4l2_format *f = (struct v4l2_format *)arg;
549 enum v4l2_buf_type type=f->type;
550
551 memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
552 f->type=type;
553
554 /* FIXME: Should be one dump per type */
555 dbgarg (cmd, "type=%s\n", prt_names(type,
556 v4l2_type_names_FIXME));
557
558 switch (type) {
559 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
560 if (vfd->vidioc_g_fmt_cap)
561 ret=vfd->vidioc_g_fmt_cap(file, fh, f);
562 if (!ret)
563 v4l_print_pix_fmt(vfd,&f->fmt.pix);
564 break;
565 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
566 if (vfd->vidioc_g_fmt_overlay)
567 ret=vfd->vidioc_g_fmt_overlay(file, fh, f);
568 break;
569 case V4L2_BUF_TYPE_VBI_CAPTURE:
570 if (vfd->vidioc_g_fmt_vbi)
571 ret=vfd->vidioc_g_fmt_vbi(file, fh, f);
572 break;
573 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
574 if (vfd->vidioc_g_fmt_vbi_output)
575 ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
576 break;
577 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
578 if (vfd->vidioc_g_fmt_vbi_capture)
579 ret=vfd->vidioc_g_fmt_vbi_capture(file, fh, f);
580 break;
581 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
582 if (vfd->vidioc_g_fmt_video_output)
583 ret=vfd->vidioc_g_fmt_video_output(file,
584 fh, f);
585 break;
586 case V4L2_BUF_TYPE_VBI_OUTPUT:
587 if (vfd->vidioc_g_fmt_vbi_output)
588 ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
589 break;
590 case V4L2_BUF_TYPE_PRIVATE:
591 if (vfd->vidioc_g_fmt_type_private)
592 ret=vfd->vidioc_g_fmt_type_private(file,
593 fh, f);
594 break;
595 }
596
597 break;
598 }
599 case VIDIOC_S_FMT:
600 {
601 struct v4l2_format *f = (struct v4l2_format *)arg;
602
603 /* FIXME: Should be one dump per type */
604 dbgarg (cmd, "type=%s\n", prt_names(f->type,
605 v4l2_type_names_FIXME));
606
607 switch (f->type) {
608 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
609 v4l_print_pix_fmt(vfd,&f->fmt.pix);
610 if (vfd->vidioc_s_fmt_cap)
611 ret=vfd->vidioc_s_fmt_cap(file, fh, f);
612 break;
613 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
614 if (vfd->vidioc_s_fmt_overlay)
615 ret=vfd->vidioc_s_fmt_overlay(file, fh, f);
616 break;
617 case V4L2_BUF_TYPE_VBI_CAPTURE:
618 if (vfd->vidioc_s_fmt_vbi)
619 ret=vfd->vidioc_s_fmt_vbi(file, fh, f);
620 break;
621 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
622 if (vfd->vidioc_s_fmt_vbi_output)
623 ret=vfd->vidioc_s_fmt_vbi_output(file, fh, f);
624 break;
625 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
626 if (vfd->vidioc_s_fmt_vbi_capture)
627 ret=vfd->vidioc_s_fmt_vbi_capture(file, fh, f);
628 break;
629 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
630 if (vfd->vidioc_s_fmt_video_output)
631 ret=vfd->vidioc_s_fmt_video_output(file,
632 fh, f);
633 break;
634 case V4L2_BUF_TYPE_VBI_OUTPUT:
635 if (vfd->vidioc_s_fmt_vbi_output)
636 ret=vfd->vidioc_s_fmt_vbi_output(file,
637 fh, f);
638 break;
639 case V4L2_BUF_TYPE_PRIVATE:
640 if (vfd->vidioc_s_fmt_type_private)
641 ret=vfd->vidioc_s_fmt_type_private(file,
642 fh, f);
643 break;
644 }
645 break;
646 }
647 case VIDIOC_TRY_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 switch (f->type) {
655 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
656 if (vfd->vidioc_try_fmt_cap)
657 ret=vfd->vidioc_try_fmt_cap(file, fh, f);
658 if (!ret)
659 v4l_print_pix_fmt(vfd,&f->fmt.pix);
660 break;
661 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
662 if (vfd->vidioc_try_fmt_overlay)
663 ret=vfd->vidioc_try_fmt_overlay(file, fh, f);
664 break;
665 case V4L2_BUF_TYPE_VBI_CAPTURE:
666 if (vfd->vidioc_try_fmt_vbi)
667 ret=vfd->vidioc_try_fmt_vbi(file, fh, f);
668 break;
669 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
670 if (vfd->vidioc_try_fmt_vbi_output)
671 ret=vfd->vidioc_try_fmt_vbi_output(file,
672 fh, f);
673 break;
674 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
675 if (vfd->vidioc_try_fmt_vbi_capture)
676 ret=vfd->vidioc_try_fmt_vbi_capture(file,
677 fh, f);
678 break;
679 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
680 if (vfd->vidioc_try_fmt_video_output)
681 ret=vfd->vidioc_try_fmt_video_output(file,
682 fh, f);
683 break;
684 case V4L2_BUF_TYPE_VBI_OUTPUT:
685 if (vfd->vidioc_try_fmt_vbi_output)
686 ret=vfd->vidioc_try_fmt_vbi_output(file,
687 fh, f);
688 break;
689 case V4L2_BUF_TYPE_PRIVATE:
690 if (vfd->vidioc_try_fmt_type_private)
691 ret=vfd->vidioc_try_fmt_type_private(file,
692 fh, f);
693 break;
694 }
695
696 break;
697 }
698 /* FIXME: Those buf reqs could be handled here,
699 with some changes on videobuf to allow its header to be included at
700 videodev2.h or being merged at videodev2.
701 */
702 case VIDIOC_REQBUFS:
703 {
704 struct v4l2_requestbuffers *p=arg;
705
706 if (!vfd->vidioc_reqbufs)
707 break;
708 ret = check_fmt (vfd, p->type);
709 if (ret)
710 break;
711
712 ret=vfd->vidioc_reqbufs(file, fh, p);
713 dbgarg (cmd, "count=%d, type=%s, memory=%s\n",
714 p->count,
715 prt_names(p->type,v4l2_type_names_FIXME),
716 prt_names(p->memory,v4l2_memory_names));
717 break;
718 }
719 case VIDIOC_QUERYBUF:
720 {
721 struct v4l2_buffer *p=arg;
722
723 if (!vfd->vidioc_querybuf)
724 break;
725 ret = check_fmt (vfd, p->type);
726 if (ret)
727 break;
728
729 ret=vfd->vidioc_querybuf(file, fh, p);
730 if (!ret)
731 dbgbuf(cmd,vfd,p);
732 break;
733 }
734 case VIDIOC_QBUF:
735 {
736 struct v4l2_buffer *p=arg;
737
738 if (!vfd->vidioc_qbuf)
739 break;
740 ret = check_fmt (vfd, p->type);
741 if (ret)
742 break;
743
744 ret=vfd->vidioc_qbuf(file, fh, p);
745 if (!ret)
746 dbgbuf(cmd,vfd,p);
747 break;
748 }
749 case VIDIOC_DQBUF:
750 {
751 struct v4l2_buffer *p=arg;
Sascha Hauerc93a5c32006-09-11 09:49:19 -0300752 if (!vfd->vidioc_dqbuf)
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300753 break;
754 ret = check_fmt (vfd, p->type);
755 if (ret)
756 break;
757
Sascha Hauerc93a5c32006-09-11 09:49:19 -0300758 ret=vfd->vidioc_dqbuf(file, fh, p);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300759 if (!ret)
760 dbgbuf(cmd,vfd,p);
761 break;
762 }
763 case VIDIOC_OVERLAY:
764 {
765 int *i = arg;
766
767 if (!vfd->vidioc_overlay)
768 break;
769 dbgarg (cmd, "value=%d\n",*i);
770 ret=vfd->vidioc_overlay(file, fh, *i);
771 break;
772 }
Mauro Carvalho Chehab0dfa9ab2006-08-08 09:10:10 -0300773#ifdef CONFIG_VIDEO_V4L1_COMPAT
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300774 /* --- streaming capture ------------------------------------- */
775 case VIDIOCGMBUF:
776 {
777 struct video_mbuf *p=arg;
778
Mauro Carvalho Chehab4ceb04e2006-06-17 08:52:30 -0300779 memset(p,0,sizeof(p));
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300780
781 if (!vfd->vidiocgmbuf)
782 break;
783 ret=vfd->vidiocgmbuf(file, fh, p);
784 if (!ret)
785 dbgarg (cmd, "size=%d, frames=%d, offsets=0x%08lx\n",
786 p->size, p->frames,
787 (unsigned long)p->offsets);
788 break;
789 }
790#endif
791 case VIDIOC_G_FBUF:
792 {
793 struct v4l2_framebuffer *p=arg;
794 if (!vfd->vidioc_g_fbuf)
795 break;
796 ret=vfd->vidioc_g_fbuf(file, fh, arg);
797 if (!ret) {
798 dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
799 p->capability,p->flags,
800 (unsigned long)p->base);
801 v4l_print_pix_fmt (vfd, &p->fmt);
802 }
803 break;
804 }
805 case VIDIOC_S_FBUF:
806 {
807 struct v4l2_framebuffer *p=arg;
808 if (!vfd->vidioc_s_fbuf)
809 break;
810
811 dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
812 p->capability,p->flags,(unsigned long)p->base);
813 v4l_print_pix_fmt (vfd, &p->fmt);
814 ret=vfd->vidioc_s_fbuf(file, fh, arg);
815
816 break;
817 }
818 case VIDIOC_STREAMON:
819 {
820 enum v4l2_buf_type i = *(int *)arg;
821 if (!vfd->vidioc_streamon)
822 break;
823 dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME));
824 ret=vfd->vidioc_streamon(file, fh,i);
825 break;
826 }
827 case VIDIOC_STREAMOFF:
828 {
829 enum v4l2_buf_type i = *(int *)arg;
830
831 if (!vfd->vidioc_streamoff)
832 break;
833 dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME));
834 ret=vfd->vidioc_streamoff(file, fh, i);
835 break;
836 }
837 /* ---------- tv norms ---------- */
838 case VIDIOC_ENUMSTD:
839 {
840 struct v4l2_standard *p = arg;
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300841 v4l2_std_id id = vfd->tvnorms,curr_id=0;
842 unsigned int index = p->index,i;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300843
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300844 if (index<0) {
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300845 ret=-EINVAL;
846 break;
847 }
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300848
849 /* Return norm array on a canonical way */
850 for (i=0;i<= index && id; i++) {
851 if ( (id & V4L2_STD_PAL) == V4L2_STD_PAL) {
852 curr_id = V4L2_STD_PAL;
853 } else if ( (id & V4L2_STD_PAL_BG) == V4L2_STD_PAL_BG) {
854 curr_id = V4L2_STD_PAL_BG;
855 } else if ( (id & V4L2_STD_PAL_DK) == V4L2_STD_PAL_DK) {
856 curr_id = V4L2_STD_PAL_DK;
857 } else if ( (id & V4L2_STD_PAL_B) == V4L2_STD_PAL_B) {
858 curr_id = V4L2_STD_PAL_B;
859 } else if ( (id & V4L2_STD_PAL_B1) == V4L2_STD_PAL_B1) {
860 curr_id = V4L2_STD_PAL_B1;
861 } else if ( (id & V4L2_STD_PAL_G) == V4L2_STD_PAL_G) {
862 curr_id = V4L2_STD_PAL_G;
863 } else if ( (id & V4L2_STD_PAL_H) == V4L2_STD_PAL_H) {
864 curr_id = V4L2_STD_PAL_H;
865 } else if ( (id & V4L2_STD_PAL_I) == V4L2_STD_PAL_I) {
866 curr_id = V4L2_STD_PAL_I;
867 } else if ( (id & V4L2_STD_PAL_D) == V4L2_STD_PAL_D) {
868 curr_id = V4L2_STD_PAL_D;
869 } else if ( (id & V4L2_STD_PAL_D1) == V4L2_STD_PAL_D1) {
870 curr_id = V4L2_STD_PAL_D1;
871 } else if ( (id & V4L2_STD_PAL_K) == V4L2_STD_PAL_K) {
872 curr_id = V4L2_STD_PAL_K;
873 } else if ( (id & V4L2_STD_PAL_M) == V4L2_STD_PAL_M) {
874 curr_id = V4L2_STD_PAL_M;
875 } else if ( (id & V4L2_STD_PAL_N) == V4L2_STD_PAL_N) {
876 curr_id = V4L2_STD_PAL_N;
877 } else if ( (id & V4L2_STD_PAL_Nc) == V4L2_STD_PAL_Nc) {
878 curr_id = V4L2_STD_PAL_Nc;
879 } else if ( (id & V4L2_STD_PAL_60) == V4L2_STD_PAL_60) {
880 curr_id = V4L2_STD_PAL_60;
881 } else if ( (id & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
882 curr_id = V4L2_STD_NTSC;
883 } else if ( (id & V4L2_STD_NTSC_M) == V4L2_STD_NTSC_M) {
884 curr_id = V4L2_STD_NTSC_M;
885 } else if ( (id & V4L2_STD_NTSC_M_JP) == V4L2_STD_NTSC_M_JP) {
886 curr_id = V4L2_STD_NTSC_M_JP;
887 } else if ( (id & V4L2_STD_NTSC_443) == V4L2_STD_NTSC_443) {
888 curr_id = V4L2_STD_NTSC_443;
889 } else if ( (id & V4L2_STD_NTSC_M_KR) == V4L2_STD_NTSC_M_KR) {
890 curr_id = V4L2_STD_NTSC_M_KR;
891 } else if ( (id & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
892 curr_id = V4L2_STD_SECAM;
893 } else if ( (id & V4L2_STD_SECAM_DK) == V4L2_STD_SECAM_DK) {
894 curr_id = V4L2_STD_SECAM_DK;
895 } else if ( (id & V4L2_STD_SECAM_B) == V4L2_STD_SECAM_B) {
896 curr_id = V4L2_STD_SECAM_B;
897 } else if ( (id & V4L2_STD_SECAM_D) == V4L2_STD_SECAM_D) {
898 curr_id = V4L2_STD_SECAM_D;
899 } else if ( (id & V4L2_STD_SECAM_G) == V4L2_STD_SECAM_G) {
900 curr_id = V4L2_STD_SECAM_G;
901 } else if ( (id & V4L2_STD_SECAM_H) == V4L2_STD_SECAM_H) {
902 curr_id = V4L2_STD_SECAM_H;
903 } else if ( (id & V4L2_STD_SECAM_K) == V4L2_STD_SECAM_K) {
904 curr_id = V4L2_STD_SECAM_K;
905 } else if ( (id & V4L2_STD_SECAM_K1) == V4L2_STD_SECAM_K1) {
906 curr_id = V4L2_STD_SECAM_K1;
907 } else if ( (id & V4L2_STD_SECAM_L) == V4L2_STD_SECAM_L) {
908 curr_id = V4L2_STD_SECAM_L;
909 } else if ( (id & V4L2_STD_SECAM_LC) == V4L2_STD_SECAM_LC) {
910 curr_id = V4L2_STD_SECAM_LC;
911 } else {
912 break;
913 }
914 id &= ~curr_id;
915 }
916 if (i<=index)
917 return -EINVAL;
918
919 v4l2_video_std_construct(p, curr_id,v4l2_norm_to_name(curr_id));
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300920 p->index = index;
921
922 dbgarg (cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, "
923 "framelines=%d\n", p->index,
924 (unsigned long long)p->id, p->name,
925 p->frameperiod.numerator,
926 p->frameperiod.denominator,
927 p->framelines);
928
929 ret=0;
930 break;
931 }
932 case VIDIOC_G_STD:
933 {
934 v4l2_std_id *id = arg;
935
936 *id = vfd->current_norm;
937
938 dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
939
940 ret=0;
941 break;
942 }
943 case VIDIOC_S_STD:
944 {
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300945 v4l2_std_id *id = arg,norm;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300946
947 dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
948
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300949 norm = (*id) & vfd->tvnorms;
950 if ( vfd->tvnorms && !norm) /* Check if std is supported */
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300951 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300952
953 /* Calls the specific handler */
954 if (vfd->vidioc_s_std)
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300955 ret=vfd->vidioc_s_std(file, fh, &norm);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300956 else
957 ret=-EINVAL;
958
959 /* Updates standard information */
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -0300960 if (ret>=0)
961 vfd->current_norm=norm;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300962
963 break;
964 }
965 case VIDIOC_QUERYSTD:
966 {
967 v4l2_std_id *p=arg;
968
969 if (!vfd->vidioc_querystd)
970 break;
971 ret=vfd->vidioc_querystd(file, fh, arg);
972 if (!ret)
973 dbgarg (cmd, "detected std=%Lu\n",
974 (unsigned long long)*p);
975 break;
976 }
977 /* ------ input switching ---------- */
978 /* FIXME: Inputs can be handled inside videodev2 */
979 case VIDIOC_ENUMINPUT:
980 {
981 struct v4l2_input *p=arg;
982 int i=p->index;
983
984 if (!vfd->vidioc_enum_input)
985 break;
986 memset(p, 0, sizeof(*p));
987 p->index=i;
988
989 ret=vfd->vidioc_enum_input(file, fh, p);
990 if (!ret)
991 dbgarg (cmd, "index=%d, name=%s, type=%d, "
992 "audioset=%d, "
993 "tuner=%d, std=%Ld, status=%d\n",
994 p->index,p->name,p->type,p->audioset,
995 p->tuner,
996 (unsigned long long)p->std,
997 p->status);
998 break;
999 }
1000 case VIDIOC_G_INPUT:
1001 {
1002 unsigned int *i = arg;
1003
1004 if (!vfd->vidioc_g_input)
1005 break;
1006 ret=vfd->vidioc_g_input(file, fh, i);
1007 if (!ret)
1008 dbgarg (cmd, "value=%d\n",*i);
1009 break;
1010 }
1011 case VIDIOC_S_INPUT:
1012 {
1013 unsigned int *i = arg;
1014
1015 if (!vfd->vidioc_s_input)
1016 break;
1017 dbgarg (cmd, "value=%d\n",*i);
1018 ret=vfd->vidioc_s_input(file, fh, *i);
1019 break;
1020 }
1021
1022 /* ------ output switching ---------- */
1023 case VIDIOC_G_OUTPUT:
1024 {
1025 unsigned int *i = arg;
1026
1027 if (!vfd->vidioc_g_output)
1028 break;
1029 ret=vfd->vidioc_g_output(file, fh, i);
1030 if (!ret)
1031 dbgarg (cmd, "value=%d\n",*i);
1032 break;
1033 }
1034 case VIDIOC_S_OUTPUT:
1035 {
1036 unsigned int *i = arg;
1037
1038 if (!vfd->vidioc_s_output)
1039 break;
1040 dbgarg (cmd, "value=%d\n",*i);
1041 ret=vfd->vidioc_s_output(file, fh, *i);
1042 break;
1043 }
1044
1045 /* --- controls ---------------------------------------------- */
1046 case VIDIOC_QUERYCTRL:
1047 {
1048 struct v4l2_queryctrl *p=arg;
1049
1050 if (!vfd->vidioc_queryctrl)
1051 break;
1052 ret=vfd->vidioc_queryctrl(file, fh, p);
1053
1054 if (!ret)
1055 dbgarg (cmd, "id=%d, type=%d, name=%s, "
1056 "min/max=%d/%d,"
1057 " step=%d, default=%d, flags=0x%08x\n",
1058 p->id,p->type,p->name,p->minimum,
1059 p->maximum,p->step,p->default_value,
1060 p->flags);
1061 break;
1062 }
1063 case VIDIOC_G_CTRL:
1064 {
1065 struct v4l2_control *p = arg;
1066
1067 if (!vfd->vidioc_g_ctrl)
1068 break;
1069 dbgarg(cmd, "Enum for index=%d\n", p->id);
1070
1071 ret=vfd->vidioc_g_ctrl(file, fh, p);
1072 if (!ret)
1073 dbgarg2 ( "id=%d, value=%d\n", p->id, p->value);
1074 break;
1075 }
1076 case VIDIOC_S_CTRL:
1077 {
1078 struct v4l2_control *p = arg;
1079
1080 if (!vfd->vidioc_s_ctrl)
1081 break;
1082 dbgarg (cmd, "id=%d, value=%d\n", p->id, p->value);
1083
1084 ret=vfd->vidioc_s_ctrl(file, fh, p);
1085 break;
1086 }
Hans Verkuil05976912006-06-18 13:43:28 -03001087 case VIDIOC_G_EXT_CTRLS:
1088 {
1089 struct v4l2_ext_controls *p = arg;
1090
1091 if (vfd->vidioc_g_ext_ctrls) {
1092 dbgarg(cmd, "count=%d\n", p->count);
1093
1094 ret=vfd->vidioc_g_ext_ctrls(file, fh, p);
1095 }
1096 break;
1097 }
1098 case VIDIOC_S_EXT_CTRLS:
1099 {
1100 struct v4l2_ext_controls *p = arg;
1101
1102 if (vfd->vidioc_s_ext_ctrls) {
1103 dbgarg(cmd, "count=%d\n", p->count);
1104
1105 ret=vfd->vidioc_s_ext_ctrls(file, fh, p);
1106 }
1107 break;
1108 }
1109 case VIDIOC_TRY_EXT_CTRLS:
1110 {
1111 struct v4l2_ext_controls *p = arg;
1112
1113 if (vfd->vidioc_try_ext_ctrls) {
1114 dbgarg(cmd, "count=%d\n", p->count);
1115
1116 ret=vfd->vidioc_try_ext_ctrls(file, fh, p);
1117 }
1118 break;
1119 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001120 case VIDIOC_QUERYMENU:
1121 {
1122 struct v4l2_querymenu *p=arg;
1123 if (!vfd->vidioc_querymenu)
1124 break;
1125 ret=vfd->vidioc_querymenu(file, fh, p);
1126 if (!ret)
1127 dbgarg (cmd, "id=%d, index=%d, name=%s\n",
1128 p->id,p->index,p->name);
1129 break;
1130 }
1131 /* --- audio ---------------------------------------------- */
1132 case VIDIOC_ENUMAUDIO:
1133 {
1134 struct v4l2_audio *p=arg;
1135
1136 if (!vfd->vidioc_enumaudio)
1137 break;
1138 dbgarg(cmd, "Enum for index=%d\n", p->index);
1139 ret=vfd->vidioc_enumaudio(file, fh, p);
1140 if (!ret)
1141 dbgarg2("index=%d, name=%s, capability=%d, "
1142 "mode=%d\n",p->index,p->name,
1143 p->capability, p->mode);
1144 break;
1145 }
1146 case VIDIOC_G_AUDIO:
1147 {
1148 struct v4l2_audio *p=arg;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001149 __u32 index=p->index;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001150
1151 if (!vfd->vidioc_g_audio)
1152 break;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001153
1154 memset(p,0,sizeof(*p));
1155 p->index=index;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001156 dbgarg(cmd, "Get for index=%d\n", p->index);
1157 ret=vfd->vidioc_g_audio(file, fh, p);
1158 if (!ret)
1159 dbgarg2("index=%d, name=%s, capability=%d, "
1160 "mode=%d\n",p->index,
1161 p->name,p->capability, p->mode);
1162 break;
1163 }
1164 case VIDIOC_S_AUDIO:
1165 {
1166 struct v4l2_audio *p=arg;
1167
1168 if (!vfd->vidioc_s_audio)
1169 break;
1170 dbgarg(cmd, "index=%d, name=%s, capability=%d, "
1171 "mode=%d\n", p->index, p->name,
1172 p->capability, p->mode);
1173 ret=vfd->vidioc_s_audio(file, fh, p);
1174 break;
1175 }
1176 case VIDIOC_ENUMAUDOUT:
1177 {
1178 struct v4l2_audioout *p=arg;
1179
1180 if (!vfd->vidioc_enumaudout)
1181 break;
1182 dbgarg(cmd, "Enum for index=%d\n", p->index);
1183 ret=vfd->vidioc_enumaudout(file, fh, p);
1184 if (!ret)
1185 dbgarg2("index=%d, name=%s, capability=%d, "
1186 "mode=%d\n", p->index, p->name,
1187 p->capability,p->mode);
1188 break;
1189 }
1190 case VIDIOC_G_AUDOUT:
1191 {
1192 struct v4l2_audioout *p=arg;
1193
1194 if (!vfd->vidioc_g_audout)
1195 break;
1196 dbgarg(cmd, "Enum for index=%d\n", p->index);
1197 ret=vfd->vidioc_g_audout(file, fh, p);
1198 if (!ret)
1199 dbgarg2("index=%d, name=%s, capability=%d, "
1200 "mode=%d\n", p->index, p->name,
1201 p->capability,p->mode);
1202 break;
1203 }
1204 case VIDIOC_S_AUDOUT:
1205 {
1206 struct v4l2_audioout *p=arg;
1207
1208 if (!vfd->vidioc_s_audout)
1209 break;
1210 dbgarg(cmd, "index=%d, name=%s, capability=%d, "
1211 "mode=%d\n", p->index, p->name,
1212 p->capability,p->mode);
1213
1214 ret=vfd->vidioc_s_audout(file, fh, p);
1215 break;
1216 }
1217 case VIDIOC_G_MODULATOR:
1218 {
1219 struct v4l2_modulator *p=arg;
1220 if (!vfd->vidioc_g_modulator)
1221 break;
1222 ret=vfd->vidioc_g_modulator(file, fh, p);
1223 if (!ret)
1224 dbgarg(cmd, "index=%d, name=%s, "
1225 "capability=%d, rangelow=%d,"
1226 " rangehigh=%d, txsubchans=%d\n",
1227 p->index, p->name,p->capability,
1228 p->rangelow, p->rangehigh,
1229 p->txsubchans);
1230 break;
1231 }
1232 case VIDIOC_S_MODULATOR:
1233 {
1234 struct v4l2_modulator *p=arg;
1235 if (!vfd->vidioc_s_modulator)
1236 break;
1237 dbgarg(cmd, "index=%d, name=%s, capability=%d, "
1238 "rangelow=%d, rangehigh=%d, txsubchans=%d\n",
1239 p->index, p->name,p->capability,p->rangelow,
1240 p->rangehigh,p->txsubchans);
1241 ret=vfd->vidioc_s_modulator(file, fh, p);
1242 break;
1243 }
1244 case VIDIOC_G_CROP:
1245 {
1246 struct v4l2_crop *p=arg;
1247 if (!vfd->vidioc_g_crop)
1248 break;
1249 ret=vfd->vidioc_g_crop(file, fh, p);
1250 if (!ret) {
1251 dbgarg(cmd, "type=%d\n", p->type);
1252 dbgrect(vfd, "", &p->c);
1253 }
1254 break;
1255 }
1256 case VIDIOC_S_CROP:
1257 {
1258 struct v4l2_crop *p=arg;
1259 if (!vfd->vidioc_s_crop)
1260 break;
1261 dbgarg(cmd, "type=%d\n", p->type);
1262 dbgrect(vfd, "", &p->c);
1263 ret=vfd->vidioc_s_crop(file, fh, p);
1264 break;
1265 }
1266 case VIDIOC_CROPCAP:
1267 {
1268 struct v4l2_cropcap *p=arg;
1269 /*FIXME: Should also show v4l2_fract pixelaspect */
1270 if (!vfd->vidioc_cropcap)
1271 break;
1272 dbgarg(cmd, "type=%d\n", p->type);
1273 dbgrect(vfd, "bounds ", &p->bounds);
1274 dbgrect(vfd, "defrect ", &p->defrect);
1275 ret=vfd->vidioc_cropcap(file, fh, p);
1276 break;
1277 }
1278 case VIDIOC_G_MPEGCOMP:
1279 {
1280 struct v4l2_mpeg_compression *p=arg;
Hans Verkuilf81cf752006-06-18 16:54:20 -03001281
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001282 /*FIXME: Several fields not shown */
1283 if (!vfd->vidioc_g_mpegcomp)
1284 break;
1285 ret=vfd->vidioc_g_mpegcomp(file, fh, p);
1286 if (!ret)
1287 dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d,"
1288 " ts_pid_video=%d, ts_pid_pcr=%d, "
1289 "ps_size=%d, au_sample_rate=%d, "
1290 "au_pesid=%c, vi_frame_rate=%d, "
1291 "vi_frames_per_gop=%d, "
1292 "vi_bframes_count=%d, vi_pesid=%c\n",
1293 p->ts_pid_pmt,p->ts_pid_audio,
1294 p->ts_pid_video,p->ts_pid_pcr,
1295 p->ps_size, p->au_sample_rate,
1296 p->au_pesid, p->vi_frame_rate,
1297 p->vi_frames_per_gop,
1298 p->vi_bframes_count, p->vi_pesid);
1299 break;
1300 }
1301 case VIDIOC_S_MPEGCOMP:
1302 {
1303 struct v4l2_mpeg_compression *p=arg;
1304 /*FIXME: Several fields not shown */
1305 if (!vfd->vidioc_s_mpegcomp)
1306 break;
1307 dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d, "
1308 "ts_pid_video=%d, ts_pid_pcr=%d, ps_size=%d, "
1309 "au_sample_rate=%d, au_pesid=%c, "
1310 "vi_frame_rate=%d, vi_frames_per_gop=%d, "
1311 "vi_bframes_count=%d, vi_pesid=%c\n",
1312 p->ts_pid_pmt,p->ts_pid_audio, p->ts_pid_video,
1313 p->ts_pid_pcr, p->ps_size, p->au_sample_rate,
1314 p->au_pesid, p->vi_frame_rate,
1315 p->vi_frames_per_gop, p->vi_bframes_count,
1316 p->vi_pesid);
1317 ret=vfd->vidioc_s_mpegcomp(file, fh, p);
1318 break;
1319 }
1320 case VIDIOC_G_JPEGCOMP:
1321 {
1322 struct v4l2_jpegcompression *p=arg;
1323 if (!vfd->vidioc_g_jpegcomp)
1324 break;
1325 ret=vfd->vidioc_g_jpegcomp(file, fh, p);
1326 if (!ret)
1327 dbgarg (cmd, "quality=%d, APPn=%d, "
1328 "APP_len=%d, COM_len=%d, "
1329 "jpeg_markers=%d\n",
1330 p->quality,p->APPn,p->APP_len,
1331 p->COM_len,p->jpeg_markers);
1332 break;
1333 }
1334 case VIDIOC_S_JPEGCOMP:
1335 {
1336 struct v4l2_jpegcompression *p=arg;
1337 if (!vfd->vidioc_g_jpegcomp)
1338 break;
1339 dbgarg (cmd, "quality=%d, APPn=%d, APP_len=%d, "
1340 "COM_len=%d, jpeg_markers=%d\n",
1341 p->quality,p->APPn,p->APP_len,
1342 p->COM_len,p->jpeg_markers);
1343 ret=vfd->vidioc_s_jpegcomp(file, fh, p);
1344 break;
1345 }
1346 case VIDIOC_G_PARM:
1347 {
1348 struct v4l2_streamparm *p=arg;
Mauro Carvalho Chehab1c2d0342006-09-14 13:36:34 -03001349 if (vfd->vidioc_g_parm) {
1350 ret=vfd->vidioc_g_parm(file, fh, p);
1351 } else {
1352 struct v4l2_standard s;
Mauro Carvalho Chehab1c2d0342006-09-14 13:36:34 -03001353
1354 if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1355 return -EINVAL;
1356
Jonathan Corbet83427ac2006-10-13 07:51:16 -03001357 v4l2_video_std_construct(&s, vfd->current_norm,
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001358 v4l2_norm_to_name(vfd->current_norm));
Mauro Carvalho Chehab1c2d0342006-09-14 13:36:34 -03001359
1360 memset(p,0,sizeof(*p));
1361
1362 p->parm.capture.timeperframe = s.frameperiod;
1363 ret=0;
1364 }
1365
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001366 dbgarg (cmd, "type=%d\n", p->type);
1367 break;
1368 }
1369 case VIDIOC_S_PARM:
1370 {
1371 struct v4l2_streamparm *p=arg;
1372 if (!vfd->vidioc_s_parm)
1373 break;
1374 dbgarg (cmd, "type=%d\n", p->type);
1375 ret=vfd->vidioc_s_parm(file, fh, p);
1376 break;
1377 }
1378 case VIDIOC_G_TUNER:
1379 {
1380 struct v4l2_tuner *p=arg;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001381 __u32 index=p->index;
1382
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001383 if (!vfd->vidioc_g_tuner)
1384 break;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001385
1386 memset(p,0,sizeof(*p));
1387 p->index=index;
1388
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001389 ret=vfd->vidioc_g_tuner(file, fh, p);
1390 if (!ret)
1391 dbgarg (cmd, "index=%d, name=%s, type=%d, "
1392 "capability=%d, rangelow=%d, "
1393 "rangehigh=%d, signal=%d, afc=%d, "
1394 "rxsubchans=%d, audmode=%d\n",
1395 p->index, p->name, p->type,
1396 p->capability, p->rangelow,
1397 p->rangehigh, p->rxsubchans,
1398 p->audmode, p->signal, p->afc);
1399 break;
1400 }
1401 case VIDIOC_S_TUNER:
1402 {
1403 struct v4l2_tuner *p=arg;
1404 if (!vfd->vidioc_s_tuner)
1405 break;
1406 dbgarg (cmd, "index=%d, name=%s, type=%d, "
1407 "capability=%d, rangelow=%d, rangehigh=%d, "
1408 "signal=%d, afc=%d, rxsubchans=%d, "
1409 "audmode=%d\n",p->index, p->name, p->type,
1410 p->capability, p->rangelow,p->rangehigh,
1411 p->rxsubchans, p->audmode, p->signal,
1412 p->afc);
1413 ret=vfd->vidioc_s_tuner(file, fh, p);
1414 break;
1415 }
1416 case VIDIOC_G_FREQUENCY:
1417 {
1418 struct v4l2_frequency *p=arg;
1419 if (!vfd->vidioc_g_frequency)
1420 break;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001421
1422 memset(p,0,sizeof(*p));
1423
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001424 ret=vfd->vidioc_g_frequency(file, fh, p);
1425 if (!ret)
1426 dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
1427 p->tuner,p->type,p->frequency);
1428 break;
1429 }
1430 case VIDIOC_S_FREQUENCY:
1431 {
1432 struct v4l2_frequency *p=arg;
1433 if (!vfd->vidioc_s_frequency)
1434 break;
1435 dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
1436 p->tuner,p->type,p->frequency);
1437 ret=vfd->vidioc_s_frequency(file, fh, p);
1438 break;
1439 }
1440 case VIDIOC_G_SLICED_VBI_CAP:
1441 {
1442 struct v4l2_sliced_vbi_cap *p=arg;
1443 if (!vfd->vidioc_g_sliced_vbi_cap)
1444 break;
1445 ret=vfd->vidioc_g_sliced_vbi_cap(file, fh, p);
1446 if (!ret)
1447 dbgarg (cmd, "service_set=%d\n", p->service_set);
1448 break;
1449 }
1450 case VIDIOC_LOG_STATUS:
1451 {
1452 if (!vfd->vidioc_log_status)
1453 break;
1454 ret=vfd->vidioc_log_status(file, fh);
1455 break;
1456 }
Mauro Carvalho Chehab207705c2006-11-20 12:13:25 -03001457 } /* switch */
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001458
1459 if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
1460 if (ret<0) {
1461 printk ("%s: err:\n", vfd->name);
1462 v4l_print_ioctl(vfd->name, cmd);
1463 }
1464 }
1465
1466 return ret;
1467}
1468
1469int video_ioctl2 (struct inode *inode, struct file *file,
1470 unsigned int cmd, unsigned long arg)
1471{
1472 char sbuf[128];
1473 void *mbuf = NULL;
1474 void *parg = NULL;
1475 int err = -EINVAL;
Hans Verkuil05976912006-06-18 13:43:28 -03001476 int is_ext_ctrl;
1477 size_t ctrls_size = 0;
1478 void __user *user_ptr = NULL;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001479
1480#ifdef __OLD_VIDIOC_
1481 cmd = video_fix_command(cmd);
1482#endif
Hans Verkuil05976912006-06-18 13:43:28 -03001483 is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
1484 cmd == VIDIOC_TRY_EXT_CTRLS);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001485
1486 /* Copy arguments into temp kernel buffer */
1487 switch (_IOC_DIR(cmd)) {
1488 case _IOC_NONE:
1489 parg = NULL;
1490 break;
1491 case _IOC_READ:
1492 case _IOC_WRITE:
1493 case (_IOC_WRITE | _IOC_READ):
1494 if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
1495 parg = sbuf;
1496 } else {
1497 /* too big to allocate from stack */
1498 mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
1499 if (NULL == mbuf)
1500 return -ENOMEM;
1501 parg = mbuf;
1502 }
1503
1504 err = -EFAULT;
1505 if (_IOC_DIR(cmd) & _IOC_WRITE)
1506 if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
1507 goto out;
1508 break;
1509 }
1510
Hans Verkuil05976912006-06-18 13:43:28 -03001511 if (is_ext_ctrl) {
1512 struct v4l2_ext_controls *p = parg;
1513
1514 /* In case of an error, tell the caller that it wasn't
1515 a specific control that caused it. */
1516 p->error_idx = p->count;
1517 user_ptr = (void __user *)p->controls;
1518 if (p->count) {
1519 ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
1520 /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
1521 mbuf = kmalloc(ctrls_size, GFP_KERNEL);
1522 err = -ENOMEM;
1523 if (NULL == mbuf)
1524 goto out_ext_ctrl;
1525 err = -EFAULT;
1526 if (copy_from_user(mbuf, user_ptr, ctrls_size))
1527 goto out_ext_ctrl;
1528 p->controls = mbuf;
1529 }
1530 }
1531
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001532 /* Handles IOCTL */
1533 err = __video_do_ioctl(inode, file, cmd, parg);
1534 if (err == -ENOIOCTLCMD)
1535 err = -EINVAL;
Hans Verkuil05976912006-06-18 13:43:28 -03001536 if (is_ext_ctrl) {
1537 struct v4l2_ext_controls *p = parg;
1538
1539 p->controls = (void *)user_ptr;
1540 if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
1541 err = -EFAULT;
1542 goto out_ext_ctrl;
1543 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001544 if (err < 0)
1545 goto out;
1546
Hans Verkuil05976912006-06-18 13:43:28 -03001547out_ext_ctrl:
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001548 /* Copy results into user buffer */
1549 switch (_IOC_DIR(cmd))
1550 {
1551 case _IOC_READ:
1552 case (_IOC_WRITE | _IOC_READ):
1553 if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
1554 err = -EFAULT;
1555 break;
1556 }
1557
1558out:
1559 kfree(mbuf);
1560 return err;
1561}
1562
1563
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564static struct file_operations video_fops;
1565
1566/**
1567 * video_register_device - register video4linux devices
1568 * @vfd: video device structure we want to register
1569 * @type: type of device to register
1570 * @nr: which device number (0 == /dev/video0, 1 == /dev/video1, ...
1571 * -1 == first free)
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001572 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 * The registration code assigns minor numbers based on the type
1574 * requested. -ENFILE is returned in all the device slots for this
1575 * category are full. If not then the minor field is set and the
1576 * driver initialize function is called (if non %NULL).
1577 *
1578 * Zero is returned on success.
1579 *
1580 * Valid types are
1581 *
1582 * %VFL_TYPE_GRABBER - A frame grabber
1583 *
1584 * %VFL_TYPE_VTX - A teletext device
1585 *
1586 * %VFL_TYPE_VBI - Vertical blank data (undecoded)
1587 *
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001588 * %VFL_TYPE_RADIO - A radio card
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 */
1590
1591int video_register_device(struct video_device *vfd, int type, int nr)
1592{
1593 int i=0;
1594 int base;
1595 int end;
Michael Krufky3117bee2006-07-19 13:23:38 -03001596 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 char *name_base;
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001598
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 switch(type)
1600 {
1601 case VFL_TYPE_GRABBER:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02001602 base=MINOR_VFL_TYPE_GRABBER_MIN;
1603 end=MINOR_VFL_TYPE_GRABBER_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 name_base = "video";
1605 break;
1606 case VFL_TYPE_VTX:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02001607 base=MINOR_VFL_TYPE_VTX_MIN;
1608 end=MINOR_VFL_TYPE_VTX_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 name_base = "vtx";
1610 break;
1611 case VFL_TYPE_VBI:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02001612 base=MINOR_VFL_TYPE_VBI_MIN;
1613 end=MINOR_VFL_TYPE_VBI_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 name_base = "vbi";
1615 break;
1616 case VFL_TYPE_RADIO:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02001617 base=MINOR_VFL_TYPE_RADIO_MIN;
1618 end=MINOR_VFL_TYPE_RADIO_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 name_base = "radio";
1620 break;
1621 default:
Trent Piepho53dd8de2006-07-25 09:31:42 -03001622 printk(KERN_ERR "%s called with unknown type: %d\n",
1623 __FUNCTION__, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 return -1;
1625 }
1626
1627 /* pick a minor number */
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001628 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 if (nr >= 0 && nr < end-base) {
1630 /* use the one the driver asked for */
1631 i = base+nr;
1632 if (NULL != video_device[i]) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001633 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 return -ENFILE;
1635 }
1636 } else {
1637 /* use first free */
1638 for(i=base;i<end;i++)
1639 if (NULL == video_device[i])
1640 break;
1641 if (i == end) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001642 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 return -ENFILE;
1644 }
1645 }
1646 video_device[i]=vfd;
1647 vfd->minor=i;
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001648 mutex_unlock(&videodev_lock);
Ingo Molnar3593cab2006-02-07 06:49:14 -02001649 mutex_init(&vfd->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650
1651 /* sysfs class */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001652 memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 if (vfd->dev)
1654 vfd->class_dev.dev = vfd->dev;
1655 vfd->class_dev.class = &video_class;
Michael Krufky50c25ff2006-01-09 15:25:34 -02001656 vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
Greg Kroah-Hartman5e483072005-06-20 21:15:16 -07001657 sprintf(vfd->class_dev.class_id, "%s%d", name_base, i - base);
Michael Krufky3117bee2006-07-19 13:23:38 -03001658 ret = class_device_register(&vfd->class_dev);
Trent Piepho8c313112006-07-25 20:37:03 -03001659 if (ret < 0) {
Michael Krufky3117bee2006-07-19 13:23:38 -03001660 printk(KERN_ERR "%s: class_device_register failed\n",
1661 __FUNCTION__);
Trent Piephod94fc9a2006-07-29 17:18:06 -03001662 goto fail_minor;
Michael Krufky3117bee2006-07-19 13:23:38 -03001663 }
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -03001664 ret = class_device_create_file(&vfd->class_dev, &class_device_attr_name);
1665 if (ret < 0) {
Trent Piephod94fc9a2006-07-29 17:18:06 -03001666 printk(KERN_ERR "%s: class_device_create_file 'name' failed\n",
1667 __FUNCTION__);
1668 goto fail_classdev;
Mauro Carvalho Chehab985bc962006-07-23 06:31:19 -03001669 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670
Mauro Carvalho Chehabd21838d2006-01-09 15:25:21 -02001671#if 1
1672 /* needed until all drivers are fixed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 if (!vfd->release)
1674 printk(KERN_WARNING "videodev: \"%s\" has no release callback. "
1675 "Please fix your driver for proper sysfs support, see "
1676 "http://lwn.net/Articles/36850/\n", vfd->name);
1677#endif
1678 return 0;
Trent Piepho53dd8de2006-07-25 09:31:42 -03001679
1680fail_classdev:
1681 class_device_unregister(&vfd->class_dev);
1682fail_minor:
1683 mutex_lock(&videodev_lock);
1684 video_device[vfd->minor] = NULL;
1685 vfd->minor = -1;
1686 mutex_unlock(&videodev_lock);
1687 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688}
1689
1690/**
1691 * video_unregister_device - unregister a video4linux device
1692 * @vfd: the device to unregister
1693 *
1694 * This unregisters the passed device and deassigns the minor
1695 * number. Future open calls will be met with errors.
1696 */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001697
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698void video_unregister_device(struct video_device *vfd)
1699{
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001700 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 if(video_device[vfd->minor]!=vfd)
1702 panic("videodev: bad unregister");
1703
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 video_device[vfd->minor]=NULL;
1705 class_device_unregister(&vfd->class_dev);
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001706 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707}
1708
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001709/*
1710 * Video fs operations
1711 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712static struct file_operations video_fops=
1713{
1714 .owner = THIS_MODULE,
1715 .llseek = no_llseek,
1716 .open = video_open,
1717};
1718
1719/*
1720 * Initialise video for linux
1721 */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001722
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723static int __init videodev_init(void)
1724{
1725 int ret;
1726
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001727 printk(KERN_INFO "Linux video capture interface: v2.00\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) {
1729 printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR);
1730 return -EIO;
1731 }
1732
1733 ret = class_register(&video_class);
1734 if (ret < 0) {
1735 unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME);
1736 printk(KERN_WARNING "video_dev: class_register failed\n");
1737 return -EIO;
1738 }
1739
1740 return 0;
1741}
1742
1743static void __exit videodev_exit(void)
1744{
1745 class_unregister(&video_class);
1746 unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME);
1747}
1748
1749module_init(videodev_init)
1750module_exit(videodev_exit)
1751
1752EXPORT_SYMBOL(video_register_device);
1753EXPORT_SYMBOL(video_unregister_device);
1754EXPORT_SYMBOL(video_devdata);
1755EXPORT_SYMBOL(video_usercopy);
1756EXPORT_SYMBOL(video_exclusive_open);
1757EXPORT_SYMBOL(video_exclusive_release);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001758EXPORT_SYMBOL(video_ioctl2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759EXPORT_SYMBOL(video_device_alloc);
1760EXPORT_SYMBOL(video_device_release);
1761
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001762MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
1763MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764MODULE_LICENSE("GPL");
1765
1766
1767/*
1768 * Local variables:
1769 * c-basic-offset: 8
1770 * End:
1771 */