diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2008-07-20 07:43:17 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-07-23 15:42:30 -0400 |
commit | 27a5e6d3fcce73ceeee8f3bdc9a30c4564233800 (patch) | |
tree | f05a6c010bb54e41e254ec6a1fad112131a255e3 | |
parent | a4e0d9af403d099e751797f6cc69e4a8e2d78ef1 (diff) |
V4L/DVB (8427): videodev: split off the ioctl handling into v4l2-ioctl.c
videodev.c became top-heavy so all the ioctl processing has been split off
into v4l2-ioctl.c. This means videodev.c is back to its original purpose:
creating and registering v4l devices.
Since videodev.c and v4l2-ioctl.c should still remain one module (as least
for now) I also had to rename videodev.c to v4l2-dev.c to prevent a
circular dependency when building a videodev.ko module. This is not a bad
thing, since the source and header now have the same name. And the v4l2-
prefix is useful to see which sources are generic v4l2 support code.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r-- | drivers/media/video/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/video/v4l2-dev.c | 424 | ||||
-rw-r--r-- | drivers/media/video/videodev.c | 2262 |
3 files changed, 426 insertions, 2262 deletions
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 45d5db5abb1e..9de1e4885246 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
@@ -10,6 +10,8 @@ msp3400-objs := msp3400-driver.o msp3400-kthreads.o | |||
10 | 10 | ||
11 | stkwebcam-objs := stk-webcam.o stk-sensor.o | 11 | stkwebcam-objs := stk-webcam.o stk-sensor.o |
12 | 12 | ||
13 | videodev-objs := v4l2-dev.o v4l2-ioctl.o | ||
14 | |||
13 | obj-$(CONFIG_VIDEO_DEV) += videodev.o compat_ioctl32.o v4l2-int-device.o | 15 | obj-$(CONFIG_VIDEO_DEV) += videodev.o compat_ioctl32.o v4l2-int-device.o |
14 | 16 | ||
15 | obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o | 17 | obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o |
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c new file mode 100644 index 000000000000..2dd82b16bc35 --- /dev/null +++ b/drivers/media/video/v4l2-dev.c | |||
@@ -0,0 +1,424 @@ | |||
1 | /* | ||
2 | * Video capture interface for Linux version 2 | ||
3 | * | ||
4 | * A generic video device interface for the LINUX operating system | ||
5 | * using a set of device structures/vectors for low level operations. | ||
6 | * | ||
7 | * 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. | ||
11 | * | ||
12 | * Authors: Alan Cox, <alan@redhat.com> (version 1) | ||
13 | * Mauro Carvalho Chehab <mchehab@infradead.org> (version 2) | ||
14 | * | ||
15 | * Fixes: 20000516 Claudio Matsuoka <claudio@conectiva.com> | ||
16 | * - Added procfs support | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/mm.h> | ||
23 | #include <linux/string.h> | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/kmod.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/smp_lock.h> | ||
29 | #include <asm/uaccess.h> | ||
30 | #include <asm/system.h> | ||
31 | |||
32 | #include <media/v4l2-common.h> | ||
33 | |||
34 | #define VIDEO_NUM_DEVICES 256 | ||
35 | #define VIDEO_NAME "video4linux" | ||
36 | |||
37 | /* | ||
38 | * sysfs stuff | ||
39 | */ | ||
40 | |||
41 | static ssize_t show_index(struct device *cd, | ||
42 | struct device_attribute *attr, char *buf) | ||
43 | { | ||
44 | struct video_device *vfd = container_of(cd, struct video_device, | ||
45 | class_dev); | ||
46 | return sprintf(buf, "%i\n", vfd->index); | ||
47 | } | ||
48 | |||
49 | static ssize_t show_name(struct device *cd, | ||
50 | struct device_attribute *attr, char *buf) | ||
51 | { | ||
52 | struct video_device *vfd = container_of(cd, struct video_device, | ||
53 | class_dev); | ||
54 | return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name); | ||
55 | } | ||
56 | |||
57 | static struct device_attribute video_device_attrs[] = { | ||
58 | __ATTR(name, S_IRUGO, show_name, NULL), | ||
59 | __ATTR(index, S_IRUGO, show_index, NULL), | ||
60 | __ATTR_NULL | ||
61 | }; | ||
62 | |||
63 | struct video_device *video_device_alloc(void) | ||
64 | { | ||
65 | struct video_device *vfd; | ||
66 | |||
67 | vfd = kzalloc(sizeof(*vfd), GFP_KERNEL); | ||
68 | return vfd; | ||
69 | } | ||
70 | EXPORT_SYMBOL(video_device_alloc); | ||
71 | |||
72 | void video_device_release(struct video_device *vfd) | ||
73 | { | ||
74 | kfree(vfd); | ||
75 | } | ||
76 | EXPORT_SYMBOL(video_device_release); | ||
77 | |||
78 | static void video_release(struct device *cd) | ||
79 | { | ||
80 | struct video_device *vfd = container_of(cd, struct video_device, | ||
81 | class_dev); | ||
82 | |||
83 | #if 1 | ||
84 | /* needed until all drivers are fixed */ | ||
85 | if (!vfd->release) | ||
86 | return; | ||
87 | #endif | ||
88 | vfd->release(vfd); | ||
89 | } | ||
90 | |||
91 | static struct class video_class = { | ||
92 | .name = VIDEO_NAME, | ||
93 | .dev_attrs = video_device_attrs, | ||
94 | .dev_release = video_release, | ||
95 | }; | ||
96 | |||
97 | /* | ||
98 | * Active devices | ||
99 | */ | ||
100 | |||
101 | static struct video_device *video_device[VIDEO_NUM_DEVICES]; | ||
102 | static DEFINE_MUTEX(videodev_lock); | ||
103 | |||
104 | struct video_device *video_devdata(struct file *file) | ||
105 | { | ||
106 | return video_device[iminor(file->f_path.dentry->d_inode)]; | ||
107 | } | ||
108 | EXPORT_SYMBOL(video_devdata); | ||
109 | |||
110 | /* | ||
111 | * Open a video device - FIXME: Obsoleted | ||
112 | */ | ||
113 | static int video_open(struct inode *inode, struct file *file) | ||
114 | { | ||
115 | unsigned int minor = iminor(inode); | ||
116 | int err = 0; | ||
117 | struct video_device *vfl; | ||
118 | const struct file_operations *old_fops; | ||
119 | |||
120 | if (minor >= VIDEO_NUM_DEVICES) | ||
121 | return -ENODEV; | ||
122 | lock_kernel(); | ||
123 | mutex_lock(&videodev_lock); | ||
124 | vfl = video_device[minor]; | ||
125 | if (vfl == NULL) { | ||
126 | mutex_unlock(&videodev_lock); | ||
127 | request_module("char-major-%d-%d", VIDEO_MAJOR, minor); | ||
128 | mutex_lock(&videodev_lock); | ||
129 | vfl = video_device[minor]; | ||
130 | if (vfl == NULL) { | ||
131 | mutex_unlock(&videodev_lock); | ||
132 | unlock_kernel(); | ||
133 | return -ENODEV; | ||
134 | } | ||
135 | } | ||
136 | old_fops = file->f_op; | ||
137 | file->f_op = fops_get(vfl->fops); | ||
138 | if (file->f_op->open) | ||
139 | err = file->f_op->open(inode, file); | ||
140 | if (err) { | ||
141 | fops_put(file->f_op); | ||
142 | file->f_op = fops_get(old_fops); | ||
143 | } | ||
144 | fops_put(old_fops); | ||
145 | mutex_unlock(&videodev_lock); | ||
146 | unlock_kernel(); | ||
147 | return err; | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * open/release helper functions -- handle exclusive opens | ||
152 | * Should be removed soon | ||
153 | */ | ||
154 | int video_exclusive_open(struct inode *inode, struct file *file) | ||
155 | { | ||
156 | struct video_device *vfl = video_devdata(file); | ||
157 | int retval = 0; | ||
158 | |||
159 | mutex_lock(&vfl->lock); | ||
160 | if (vfl->users) | ||
161 | retval = -EBUSY; | ||
162 | else | ||
163 | vfl->users++; | ||
164 | mutex_unlock(&vfl->lock); | ||
165 | return retval; | ||
166 | } | ||
167 | EXPORT_SYMBOL(video_exclusive_open); | ||
168 | |||
169 | int video_exclusive_release(struct inode *inode, struct file *file) | ||
170 | { | ||
171 | struct video_device *vfl = video_devdata(file); | ||
172 | |||
173 | vfl->users--; | ||
174 | return 0; | ||
175 | } | ||
176 | EXPORT_SYMBOL(video_exclusive_release); | ||
177 | |||
178 | /** | ||
179 | * get_index - assign stream number based on parent device | ||
180 | * @vdev: video_device to assign index number to, vdev->dev should be assigned | ||
181 | * @num: -1 if auto assign, requested number otherwise | ||
182 | * | ||
183 | * | ||
184 | * returns -ENFILE if num is already in use, a free index number if | ||
185 | * successful. | ||
186 | */ | ||
187 | static int get_index(struct video_device *vdev, int num) | ||
188 | { | ||
189 | u32 used = 0; | ||
190 | const int max_index = sizeof(used) * 8 - 1; | ||
191 | int i; | ||
192 | |||
193 | /* Currently a single v4l driver instance cannot create more than | ||
194 | 32 devices. | ||
195 | Increase to u64 or an array of u32 if more are needed. */ | ||
196 | if (num > max_index) { | ||
197 | printk(KERN_ERR "videodev: %s num is too large\n", __func__); | ||
198 | return -EINVAL; | ||
199 | } | ||
200 | |||
201 | for (i = 0; i < VIDEO_NUM_DEVICES; i++) { | ||
202 | if (video_device[i] != NULL && | ||
203 | video_device[i] != vdev && | ||
204 | video_device[i]->dev == vdev->dev) { | ||
205 | used |= 1 << video_device[i]->index; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | if (num >= 0) { | ||
210 | if (used & (1 << num)) | ||
211 | return -ENFILE; | ||
212 | return num; | ||
213 | } | ||
214 | |||
215 | i = ffz(used); | ||
216 | return i > max_index ? -ENFILE : i; | ||
217 | } | ||
218 | |||
219 | static const struct file_operations video_fops; | ||
220 | |||
221 | int video_register_device(struct video_device *vfd, int type, int nr) | ||
222 | { | ||
223 | return video_register_device_index(vfd, type, nr, -1); | ||
224 | } | ||
225 | EXPORT_SYMBOL(video_register_device); | ||
226 | |||
227 | /** | ||
228 | * video_register_device - register video4linux devices | ||
229 | * @vfd: video device structure we want to register | ||
230 | * @type: type of device to register | ||
231 | * @nr: which device number (0 == /dev/video0, 1 == /dev/video1, ... | ||
232 | * -1 == first free) | ||
233 | * | ||
234 | * The registration code assigns minor numbers based on the type | ||
235 | * requested. -ENFILE is returned in all the device slots for this | ||
236 | * category are full. If not then the minor field is set and the | ||
237 | * driver initialize function is called (if non %NULL). | ||
238 | * | ||
239 | * Zero is returned on success. | ||
240 | * | ||
241 | * Valid types are | ||
242 | * | ||
243 | * %VFL_TYPE_GRABBER - A frame grabber | ||
244 | * | ||
245 | * %VFL_TYPE_VTX - A teletext device | ||
246 | * | ||
247 | * %VFL_TYPE_VBI - Vertical blank data (undecoded) | ||
248 | * | ||
249 | * %VFL_TYPE_RADIO - A radio card | ||
250 | */ | ||
251 | |||
252 | int video_register_device_index(struct video_device *vfd, int type, int nr, | ||
253 | int index) | ||
254 | { | ||
255 | int i = 0; | ||
256 | int base; | ||
257 | int end; | ||
258 | int ret; | ||
259 | char *name_base; | ||
260 | |||
261 | switch (type) { | ||
262 | case VFL_TYPE_GRABBER: | ||
263 | base = MINOR_VFL_TYPE_GRABBER_MIN; | ||
264 | end = MINOR_VFL_TYPE_GRABBER_MAX+1; | ||
265 | name_base = "video"; | ||
266 | break; | ||
267 | case VFL_TYPE_VTX: | ||
268 | base = MINOR_VFL_TYPE_VTX_MIN; | ||
269 | end = MINOR_VFL_TYPE_VTX_MAX+1; | ||
270 | name_base = "vtx"; | ||
271 | break; | ||
272 | case VFL_TYPE_VBI: | ||
273 | base = MINOR_VFL_TYPE_VBI_MIN; | ||
274 | end = MINOR_VFL_TYPE_VBI_MAX+1; | ||
275 | name_base = "vbi"; | ||
276 | break; | ||
277 | case VFL_TYPE_RADIO: | ||
278 | base = MINOR_VFL_TYPE_RADIO_MIN; | ||
279 | end = MINOR_VFL_TYPE_RADIO_MAX+1; | ||
280 | name_base = "radio"; | ||
281 | break; | ||
282 | default: | ||
283 | printk(KERN_ERR "%s called with unknown type: %d\n", | ||
284 | __func__, type); | ||
285 | return -1; | ||
286 | } | ||
287 | |||
288 | /* pick a minor number */ | ||
289 | mutex_lock(&videodev_lock); | ||
290 | if (nr >= 0 && nr < end-base) { | ||
291 | /* use the one the driver asked for */ | ||
292 | i = base + nr; | ||
293 | if (NULL != video_device[i]) { | ||
294 | mutex_unlock(&videodev_lock); | ||
295 | return -ENFILE; | ||
296 | } | ||
297 | } else { | ||
298 | /* use first free */ | ||
299 | for (i = base; i < end; i++) | ||
300 | if (NULL == video_device[i]) | ||
301 | break; | ||
302 | if (i == end) { | ||
303 | mutex_unlock(&videodev_lock); | ||
304 | return -ENFILE; | ||
305 | } | ||
306 | } | ||
307 | video_device[i] = vfd; | ||
308 | vfd->minor = i; | ||
309 | |||
310 | ret = get_index(vfd, index); | ||
311 | vfd->index = ret; | ||
312 | |||
313 | mutex_unlock(&videodev_lock); | ||
314 | |||
315 | if (ret < 0) { | ||
316 | printk(KERN_ERR "%s: get_index failed\n", __func__); | ||
317 | goto fail_minor; | ||
318 | } | ||
319 | |||
320 | mutex_init(&vfd->lock); | ||
321 | |||
322 | /* sysfs class */ | ||
323 | memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev)); | ||
324 | vfd->class_dev.class = &video_class; | ||
325 | vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); | ||
326 | if (vfd->dev) | ||
327 | vfd->class_dev.parent = vfd->dev; | ||
328 | sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base); | ||
329 | ret = device_register(&vfd->class_dev); | ||
330 | if (ret < 0) { | ||
331 | printk(KERN_ERR "%s: device_register failed\n", __func__); | ||
332 | goto fail_minor; | ||
333 | } | ||
334 | |||
335 | #if 1 | ||
336 | /* needed until all drivers are fixed */ | ||
337 | if (!vfd->release) | ||
338 | printk(KERN_WARNING "videodev: \"%s\" has no release callback. " | ||
339 | "Please fix your driver for proper sysfs support, see " | ||
340 | "http://lwn.net/Articles/36850/\n", vfd->name); | ||
341 | #endif | ||
342 | return 0; | ||
343 | |||
344 | fail_minor: | ||
345 | mutex_lock(&videodev_lock); | ||
346 | video_device[vfd->minor] = NULL; | ||
347 | vfd->minor = -1; | ||
348 | mutex_unlock(&videodev_lock); | ||
349 | return ret; | ||
350 | } | ||
351 | EXPORT_SYMBOL(video_register_device_index); | ||
352 | |||
353 | /** | ||
354 | * video_unregister_device - unregister a video4linux device | ||
355 | * @vfd: the device to unregister | ||
356 | * | ||
357 | * This unregisters the passed device and deassigns the minor | ||
358 | * number. Future open calls will be met with errors. | ||
359 | */ | ||
360 | |||
361 | void video_unregister_device(struct video_device *vfd) | ||
362 | { | ||
363 | mutex_lock(&videodev_lock); | ||
364 | if (video_device[vfd->minor] != vfd) | ||
365 | panic("videodev: bad unregister"); | ||
366 | |||
367 | video_device[vfd->minor] = NULL; | ||
368 | device_unregister(&vfd->class_dev); | ||
369 | mutex_unlock(&videodev_lock); | ||
370 | } | ||
371 | EXPORT_SYMBOL(video_unregister_device); | ||
372 | |||
373 | /* | ||
374 | * Video fs operations | ||
375 | */ | ||
376 | static const struct file_operations video_fops = { | ||
377 | .owner = THIS_MODULE, | ||
378 | .llseek = no_llseek, | ||
379 | .open = video_open, | ||
380 | }; | ||
381 | |||
382 | /* | ||
383 | * Initialise video for linux | ||
384 | */ | ||
385 | |||
386 | static int __init videodev_init(void) | ||
387 | { | ||
388 | int ret; | ||
389 | |||
390 | printk(KERN_INFO "Linux video capture interface: v2.00\n"); | ||
391 | if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) { | ||
392 | printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR); | ||
393 | return -EIO; | ||
394 | } | ||
395 | |||
396 | ret = class_register(&video_class); | ||
397 | if (ret < 0) { | ||
398 | unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME); | ||
399 | printk(KERN_WARNING "video_dev: class_register failed\n"); | ||
400 | return -EIO; | ||
401 | } | ||
402 | |||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static void __exit videodev_exit(void) | ||
407 | { | ||
408 | class_unregister(&video_class); | ||
409 | unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME); | ||
410 | } | ||
411 | |||
412 | module_init(videodev_init) | ||
413 | module_exit(videodev_exit) | ||
414 | |||
415 | MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>"); | ||
416 | MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2"); | ||
417 | MODULE_LICENSE("GPL"); | ||
418 | |||
419 | |||
420 | /* | ||
421 | * Local variables: | ||
422 | * c-basic-offset: 8 | ||
423 | * End: | ||
424 | */ | ||
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 6616e6570557..e69de29bb2d1 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c | |||
@@ -1,2262 +0,0 @@ | |||
1 | /* | ||
2 | * Video capture interface for Linux version 2 | ||
3 | * | ||
4 | * A generic video device interface for the LINUX operating system | ||
5 | * using a set of device structures/vectors for low level operations. | ||
6 | * | ||
7 | * 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. | ||
11 | * | ||
12 | * Authors: Alan Cox, <alan@redhat.com> (version 1) | ||
13 | * Mauro Carvalho Chehab <mchehab@infradead.org> (version 2) | ||
14 | * | ||
15 | * Fixes: 20000516 Claudio Matsuoka <claudio@conectiva.com> | ||
16 | * - Added procfs support | ||
17 | */ | ||
18 | |||
19 | #define dbgarg(cmd, fmt, arg...) \ | ||
20 | do { \ | ||
21 | if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \ | ||
22 | printk(KERN_DEBUG "%s: ", vfd->name); \ | ||
23 | v4l_printk_ioctl(cmd); \ | ||
24 | printk(" " fmt, ## arg); \ | ||
25 | } \ | ||
26 | } while (0) | ||
27 | |||
28 | #define dbgarg2(fmt, arg...) \ | ||
29 | do { \ | ||
30 | if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \ | ||
31 | printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);\ | ||
32 | } while (0) | ||
33 | |||
34 | #include <linux/module.h> | ||
35 | #include <linux/types.h> | ||
36 | #include <linux/kernel.h> | ||
37 | #include <linux/mm.h> | ||
38 | #include <linux/string.h> | ||
39 | #include <linux/errno.h> | ||
40 | #include <linux/init.h> | ||
41 | #include <linux/kmod.h> | ||
42 | #include <linux/slab.h> | ||
43 | #include <linux/smp_lock.h> | ||
44 | #include <asm/uaccess.h> | ||
45 | #include <asm/system.h> | ||
46 | |||
47 | #define __OLD_VIDIOC_ /* To allow fixing old calls*/ | ||
48 | #include <linux/videodev2.h> | ||
49 | |||
50 | #ifdef CONFIG_VIDEO_V4L1 | ||
51 | #include <linux/videodev.h> | ||
52 | #endif | ||
53 | #include <media/v4l2-common.h> | ||
54 | #include <linux/video_decoder.h> | ||
55 | |||
56 | #define VIDEO_NUM_DEVICES 256 | ||
57 | #define VIDEO_NAME "video4linux" | ||
58 | |||
59 | struct std_descr { | ||
60 | v4l2_std_id std; | ||
61 | const char *descr; | ||
62 | }; | ||
63 | |||
64 | static const struct std_descr standards[] = { | ||
65 | { V4L2_STD_NTSC, "NTSC" }, | ||
66 | { V4L2_STD_NTSC_M, "NTSC-M" }, | ||
67 | { V4L2_STD_NTSC_M_JP, "NTSC-M-JP" }, | ||
68 | { V4L2_STD_NTSC_M_KR, "NTSC-M-KR" }, | ||
69 | { V4L2_STD_NTSC_443, "NTSC-443" }, | ||
70 | { V4L2_STD_PAL, "PAL" }, | ||
71 | { V4L2_STD_PAL_BG, "PAL-BG" }, | ||
72 | { V4L2_STD_PAL_B, "PAL-B" }, | ||
73 | { V4L2_STD_PAL_B1, "PAL-B1" }, | ||
74 | { V4L2_STD_PAL_G, "PAL-G" }, | ||
75 | { V4L2_STD_PAL_H, "PAL-H" }, | ||
76 | { V4L2_STD_PAL_I, "PAL-I" }, | ||
77 | { V4L2_STD_PAL_DK, "PAL-DK" }, | ||
78 | { V4L2_STD_PAL_D, "PAL-D" }, | ||
79 | { V4L2_STD_PAL_D1, "PAL-D1" }, | ||
80 | { V4L2_STD_PAL_K, "PAL-K" }, | ||
81 | { V4L2_STD_PAL_M, "PAL-M" }, | ||
82 | { V4L2_STD_PAL_N, "PAL-N" }, | ||
83 | { V4L2_STD_PAL_Nc, "PAL-Nc" }, | ||
84 | { V4L2_STD_PAL_60, "PAL-60" }, | ||
85 | { V4L2_STD_SECAM, "SECAM" }, | ||
86 | { V4L2_STD_SECAM_B, "SECAM-B" }, | ||
87 | { V4L2_STD_SECAM_G, "SECAM-G" }, | ||
88 | { V4L2_STD_SECAM_H, "SECAM-H" }, | ||
89 | { V4L2_STD_SECAM_DK, "SECAM-DK" }, | ||
90 | { V4L2_STD_SECAM_D, "SECAM-D" }, | ||
91 | { V4L2_STD_SECAM_K, "SECAM-K" }, | ||
92 | { V4L2_STD_SECAM_K1, "SECAM-K1" }, | ||
93 | { V4L2_STD_SECAM_L, "SECAM-L" }, | ||
94 | { V4L2_STD_SECAM_LC, "SECAM-Lc" }, | ||
95 | { 0, "Unknown" } | ||
96 | }; | ||
97 | |||
98 | /* video4linux standard ID conversion to standard name | ||
99 | */ | ||
100 | const char *v4l2_norm_to_name(v4l2_std_id id) | ||
101 | { | ||
102 | u32 myid = id; | ||
103 | int i; | ||
104 | |||
105 | /* HACK: ppc32 architecture doesn't have __ucmpdi2 function to handle | ||
106 | 64 bit comparations. So, on that architecture, with some gcc | ||
107 | variants, compilation fails. Currently, the max value is 30bit wide. | ||
108 | */ | ||
109 | BUG_ON(myid != id); | ||
110 | |||
111 | for (i = 0; standards[i].std; i++) | ||
112 | if (myid == standards[i].std) | ||
113 | break; | ||
114 | return standards[i].descr; | ||
115 | } | ||
116 | EXPORT_SYMBOL(v4l2_norm_to_name); | ||
117 | |||
118 | /* Fill in the fields of a v4l2_standard structure according to the | ||
119 | 'id' and 'transmission' parameters. Returns negative on error. */ | ||
120 | int v4l2_video_std_construct(struct v4l2_standard *vs, | ||
121 | int id, const char *name) | ||
122 | { | ||
123 | u32 index = vs->index; | ||
124 | |||
125 | memset(vs, 0, sizeof(struct v4l2_standard)); | ||
126 | vs->index = index; | ||
127 | vs->id = id; | ||
128 | if (id & V4L2_STD_525_60) { | ||
129 | vs->frameperiod.numerator = 1001; | ||
130 | vs->frameperiod.denominator = 30000; | ||
131 | vs->framelines = 525; | ||
132 | } else { | ||
133 | vs->frameperiod.numerator = 1; | ||
134 | vs->frameperiod.denominator = 25; | ||
135 | vs->framelines = 625; | ||
136 | } | ||
137 | strlcpy(vs->name, name, sizeof(vs->name)); | ||
138 | return 0; | ||
139 | } | ||
140 | EXPORT_SYMBOL(v4l2_video_std_construct); | ||
141 | |||
142 | /* ----------------------------------------------------------------- */ | ||
143 | /* some arrays for pretty-printing debug messages of enum types */ | ||
144 | |||
145 | const char *v4l2_field_names[] = { | ||
146 | [V4L2_FIELD_ANY] = "any", | ||
147 | [V4L2_FIELD_NONE] = "none", | ||
148 | [V4L2_FIELD_TOP] = "top", | ||
149 | [V4L2_FIELD_BOTTOM] = "bottom", | ||
150 | [V4L2_FIELD_INTERLACED] = "interlaced", | ||
151 | [V4L2_FIELD_SEQ_TB] = "seq-tb", | ||
152 | [V4L2_FIELD_SEQ_BT] = "seq-bt", | ||
153 | [V4L2_FIELD_ALTERNATE] = "alternate", | ||
154 | [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb", | ||
155 | [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt", | ||
156 | }; | ||
157 | EXPORT_SYMBOL(v4l2_field_names); | ||
158 | |||
159 | const char *v4l2_type_names[] = { | ||
160 | [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "vid-cap", | ||
161 | [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "vid-overlay", | ||
162 | [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "vid-out", | ||
163 | [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", | ||
164 | [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", | ||
165 | [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap", | ||
166 | [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", | ||
167 | [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "vid-out-overlay", | ||
168 | }; | ||
169 | EXPORT_SYMBOL(v4l2_type_names); | ||
170 | |||
171 | static const char *v4l2_memory_names[] = { | ||
172 | [V4L2_MEMORY_MMAP] = "mmap", | ||
173 | [V4L2_MEMORY_USERPTR] = "userptr", | ||
174 | [V4L2_MEMORY_OVERLAY] = "overlay", | ||
175 | }; | ||
176 | |||
177 | #define prt_names(a, arr) ((((a) >= 0) && ((a) < ARRAY_SIZE(arr))) ? \ | ||
178 | arr[a] : "unknown") | ||
179 | |||
180 | /* ------------------------------------------------------------------ */ | ||
181 | /* debug help functions */ | ||
182 | |||
183 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | ||
184 | static const char *v4l1_ioctls[] = { | ||
185 | [_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP", | ||
186 | [_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN", | ||
187 | [_IOC_NR(VIDIOCSCHAN)] = "VIDIOCSCHAN", | ||
188 | [_IOC_NR(VIDIOCGTUNER)] = "VIDIOCGTUNER", | ||
189 | [_IOC_NR(VIDIOCSTUNER)] = "VIDIOCSTUNER", | ||
190 | [_IOC_NR(VIDIOCGPICT)] = "VIDIOCGPICT", | ||
191 | [_IOC_NR(VIDIOCSPICT)] = "VIDIOCSPICT", | ||
192 | [_IOC_NR(VIDIOCCAPTURE)] = "VIDIOCCAPTURE", | ||
193 | [_IOC_NR(VIDIOCGWIN)] = "VIDIOCGWIN", | ||
194 | [_IOC_NR(VIDIOCSWIN)] = "VIDIOCSWIN", | ||
195 | [_IOC_NR(VIDIOCGFBUF)] = "VIDIOCGFBUF", | ||
196 | [_IOC_NR(VIDIOCSFBUF)] = "VIDIOCSFBUF", | ||
197 | [_IOC_NR(VIDIOCKEY)] = "VIDIOCKEY", | ||
198 | [_IOC_NR(VIDIOCGFREQ)] = "VIDIOCGFREQ", | ||
199 | [_IOC_NR(VIDIOCSFREQ)] = "VIDIOCSFREQ", | ||
200 | [_IOC_NR(VIDIOCGAUDIO)] = "VIDIOCGAUDIO", | ||
201 | [_IOC_NR(VIDIOCSAUDIO)] = "VIDIOCSAUDIO", | ||
202 | [_IOC_NR(VIDIOCSYNC)] = "VIDIOCSYNC", | ||
203 | [_IOC_NR(VIDIOCMCAPTURE)] = "VIDIOCMCAPTURE", | ||
204 | [_IOC_NR(VIDIOCGMBUF)] = "VIDIOCGMBUF", | ||
205 | [_IOC_NR(VIDIOCGUNIT)] = "VIDIOCGUNIT", | ||
206 | [_IOC_NR(VIDIOCGCAPTURE)] = "VIDIOCGCAPTURE", | ||
207 | [_IOC_NR(VIDIOCSCAPTURE)] = "VIDIOCSCAPTURE", | ||
208 | [_IOC_NR(VIDIOCSPLAYMODE)] = "VIDIOCSPLAYMODE", | ||
209 | [_IOC_NR(VIDIOCSWRITEMODE)] = "VIDIOCSWRITEMODE", | ||
210 | [_IOC_NR(VIDIOCGPLAYINFO)] = "VIDIOCGPLAYINFO", | ||
211 | [_IOC_NR(VIDIOCSMICROCODE)] = "VIDIOCSMICROCODE", | ||
212 | [_IOC_NR(VIDIOCGVBIFMT)] = "VIDIOCGVBIFMT", | ||
213 | [_IOC_NR(VIDIOCSVBIFMT)] = "VIDIOCSVBIFMT" | ||
214 | }; | ||
215 | #define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls) | ||
216 | #endif | ||
217 | |||
218 | static const char *v4l2_ioctls[] = { | ||
219 | [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP", | ||
220 | [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED", | ||
221 | [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT", | ||
222 | [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT", | ||
223 | [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT", | ||
224 | [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS", | ||
225 | [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF", | ||
226 | [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF", | ||
227 | [_IOC_NR(VIDIOC_S_FBUF)] = "VIDIOC_S_FBUF", | ||
228 | [_IOC_NR(VIDIOC_OVERLAY)] = "VIDIOC_OVERLAY", | ||
229 | [_IOC_NR(VIDIOC_QBUF)] = "VIDIOC_QBUF", | ||
230 | [_IOC_NR(VIDIOC_DQBUF)] = "VIDIOC_DQBUF", | ||
231 | [_IOC_NR(VIDIOC_STREAMON)] = "VIDIOC_STREAMON", | ||
232 | [_IOC_NR(VIDIOC_STREAMOFF)] = "VIDIOC_STREAMOFF", | ||
233 | [_IOC_NR(VIDIOC_G_PARM)] = "VIDIOC_G_PARM", | ||
234 | [_IOC_NR(VIDIOC_S_PARM)] = "VIDIOC_S_PARM", | ||
235 | [_IOC_NR(VIDIOC_G_STD)] = "VIDIOC_G_STD", | ||
236 | [_IOC_NR(VIDIOC_S_STD)] = "VIDIOC_S_STD", | ||
237 | [_IOC_NR(VIDIOC_ENUMSTD)] = "VIDIOC_ENUMSTD", | ||
238 | [_IOC_NR(VIDIOC_ENUMINPUT)] = "VIDIOC_ENUMINPUT", | ||
239 | [_IOC_NR(VIDIOC_G_CTRL)] = "VIDIOC_G_CTRL", | ||
240 | [_IOC_NR(VIDIOC_S_CTRL)] = "VIDIOC_S_CTRL", | ||
241 | [_IOC_NR(VIDIOC_G_TUNER)] = "VIDIOC_G_TUNER", | ||
242 | [_IOC_NR(VIDIOC_S_TUNER)] = "VIDIOC_S_TUNER", | ||
243 | [_IOC_NR(VIDIOC_G_AUDIO)] = "VIDIOC_G_AUDIO", | ||
244 | [_IOC_NR(VIDIOC_S_AUDIO)] = "VIDIOC_S_AUDIO", | ||
245 | [_IOC_NR(VIDIOC_QUERYCTRL)] = "VIDIOC_QUERYCTRL", | ||
246 | [_IOC_NR(VIDIOC_QUERYMENU)] = "VIDIOC_QUERYMENU", | ||
247 | [_IOC_NR(VIDIOC_G_INPUT)] = "VIDIOC_G_INPUT", | ||
248 | [_IOC_NR(VIDIOC_S_INPUT)] = "VIDIOC_S_INPUT", | ||
249 | [_IOC_NR(VIDIOC_G_OUTPUT)] = "VIDIOC_G_OUTPUT", | ||
250 | [_IOC_NR(VIDIOC_S_OUTPUT)] = "VIDIOC_S_OUTPUT", | ||
251 | [_IOC_NR(VIDIOC_ENUMOUTPUT)] = "VIDIOC_ENUMOUTPUT", | ||
252 | [_IOC_NR(VIDIOC_G_AUDOUT)] = "VIDIOC_G_AUDOUT", | ||
253 | [_IOC_NR(VIDIOC_S_AUDOUT)] = "VIDIOC_S_AUDOUT", | ||
254 | [_IOC_NR(VIDIOC_G_MODULATOR)] = "VIDIOC_G_MODULATOR", | ||
255 | [_IOC_NR(VIDIOC_S_MODULATOR)] = "VIDIOC_S_MODULATOR", | ||
256 | [_IOC_NR(VIDIOC_G_FREQUENCY)] = "VIDIOC_G_FREQUENCY", | ||
257 | [_IOC_NR(VIDIOC_S_FREQUENCY)] = "VIDIOC_S_FREQUENCY", | ||
258 | [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP", | ||
259 | [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP", | ||
260 | [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP", | ||
261 | [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP", | ||
262 | [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP", | ||
263 | [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD", | ||
264 | [_IOC_NR(VIDIOC_TRY_FMT)] = "VIDIOC_TRY_FMT", | ||
265 | [_IOC_NR(VIDIOC_ENUMAUDIO)] = "VIDIOC_ENUMAUDIO", | ||
266 | [_IOC_NR(VIDIOC_ENUMAUDOUT)] = "VIDIOC_ENUMAUDOUT", | ||
267 | [_IOC_NR(VIDIOC_G_PRIORITY)] = "VIDIOC_G_PRIORITY", | ||
268 | [_IOC_NR(VIDIOC_S_PRIORITY)] = "VIDIOC_S_PRIORITY", | ||
269 | [_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP", | ||
270 | [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS", | ||
271 | [_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS", | ||
272 | [_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS", | ||
273 | [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS", | ||
274 | #if 1 | ||
275 | [_IOC_NR(VIDIOC_ENUM_FRAMESIZES)] = "VIDIOC_ENUM_FRAMESIZES", | ||
276 | [_IOC_NR(VIDIOC_ENUM_FRAMEINTERVALS)] = "VIDIOC_ENUM_FRAMEINTERVALS", | ||
277 | [_IOC_NR(VIDIOC_G_ENC_INDEX)] = "VIDIOC_G_ENC_INDEX", | ||
278 | [_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD", | ||
279 | [_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD", | ||
280 | |||
281 | [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", | ||
282 | [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", | ||
283 | |||
284 | [_IOC_NR(VIDIOC_G_CHIP_IDENT)] = "VIDIOC_G_CHIP_IDENT", | ||
285 | [_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)] = "VIDIOC_S_HW_FREQ_SEEK", | ||
286 | #endif | ||
287 | }; | ||
288 | #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) | ||
289 | |||
290 | static const char *v4l2_int_ioctls[] = { | ||
291 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | ||
292 | [_IOC_NR(DECODER_GET_CAPABILITIES)] = "DECODER_GET_CAPABILITIES", | ||
293 | [_IOC_NR(DECODER_GET_STATUS)] = "DECODER_GET_STATUS", | ||
294 | [_IOC_NR(DECODER_SET_NORM)] = "DECODER_SET_NORM", | ||
295 | [_IOC_NR(DECODER_SET_INPUT)] = "DECODER_SET_INPUT", | ||
296 | [_IOC_NR(DECODER_SET_OUTPUT)] = "DECODER_SET_OUTPUT", | ||
297 | [_IOC_NR(DECODER_ENABLE_OUTPUT)] = "DECODER_ENABLE_OUTPUT", | ||
298 | [_IOC_NR(DECODER_SET_PICTURE)] = "DECODER_SET_PICTURE", | ||
299 | [_IOC_NR(DECODER_SET_GPIO)] = "DECODER_SET_GPIO", | ||
300 | [_IOC_NR(DECODER_INIT)] = "DECODER_INIT", | ||
301 | [_IOC_NR(DECODER_SET_VBI_BYPASS)] = "DECODER_SET_VBI_BYPASS", | ||
302 | [_IOC_NR(DECODER_DUMP)] = "DECODER_DUMP", | ||
303 | #endif | ||
304 | [_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO", | ||
305 | |||
306 | [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR", | ||
307 | [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY", | ||
308 | [_IOC_NR(TUNER_SET_CONFIG)] = "TUNER_SET_CONFIG", | ||
309 | |||
310 | [_IOC_NR(VIDIOC_INT_S_TUNER_MODE)] = "VIDIOC_INT_S_TUNER_MODE", | ||
311 | [_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET", | ||
312 | [_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ", | ||
313 | [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE", | ||
314 | [_IOC_NR(VIDIOC_INT_S_VBI_DATA)] = "VIDIOC_INT_S_VBI_DATA", | ||
315 | [_IOC_NR(VIDIOC_INT_G_VBI_DATA)] = "VIDIOC_INT_G_VBI_DATA", | ||
316 | [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ", | ||
317 | [_IOC_NR(VIDIOC_INT_S_STANDBY)] = "VIDIOC_INT_S_STANDBY", | ||
318 | [_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING", | ||
319 | [_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING", | ||
320 | [_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING", | ||
321 | [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING", | ||
322 | [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ", | ||
323 | [_IOC_NR(VIDIOC_INT_INIT)] = "VIDIOC_INT_INIT", | ||
324 | [_IOC_NR(VIDIOC_INT_G_STD_OUTPUT)] = "VIDIOC_INT_G_STD_OUTPUT", | ||
325 | [_IOC_NR(VIDIOC_INT_S_STD_OUTPUT)] = "VIDIOC_INT_S_STD_OUTPUT", | ||
326 | }; | ||
327 | #define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls) | ||
328 | |||
329 | /* Common ioctl debug function. This function can be used by | ||
330 | external ioctl messages as well as internal V4L ioctl */ | ||
331 | void v4l_printk_ioctl(unsigned int cmd) | ||
332 | { | ||
333 | char *dir, *type; | ||
334 | |||
335 | switch (_IOC_TYPE(cmd)) { | ||
336 | case 'd': | ||
337 | if (_IOC_NR(cmd) >= V4L2_INT_IOCTLS) { | ||
338 | type = "v4l2_int"; | ||
339 | break; | ||
340 | } | ||
341 | printk("%s", v4l2_int_ioctls[_IOC_NR(cmd)]); | ||
342 | return; | ||
343 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | ||
344 | case 'v': | ||
345 | if (_IOC_NR(cmd) >= V4L1_IOCTLS) { | ||
346 | type = "v4l1"; | ||
347 | break; | ||
348 | } | ||
349 | printk("%s", v4l1_ioctls[_IOC_NR(cmd)]); | ||
350 | return; | ||
351 | #endif | ||
352 | case 'V': | ||
353 | if (_IOC_NR(cmd) >= V4L2_IOCTLS) { | ||
354 | type = "v4l2"; | ||
355 | break; | ||
356 | } | ||
357 | printk("%s", v4l2_ioctls[_IOC_NR(cmd)]); | ||
358 | return; | ||
359 | default: | ||
360 | type = "unknown"; | ||
361 | } | ||
362 | |||
363 | switch (_IOC_DIR(cmd)) { | ||
364 | case _IOC_NONE: dir = "--"; break; | ||
365 | case _IOC_READ: dir = "r-"; break; | ||
366 | case _IOC_WRITE: dir = "-w"; break; | ||
367 | case _IOC_READ | _IOC_WRITE: dir = "rw"; break; | ||
368 | default: dir = "*ERR*"; break; | ||
369 | } | ||
370 | printk("%s ioctl '%c', dir=%s, #%d (0x%08x)", | ||
371 | type, _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd); | ||
372 | } | ||
373 | EXPORT_SYMBOL(v4l_printk_ioctl); | ||
374 | |||
375 | /* | ||
376 | * sysfs stuff | ||
377 | */ | ||
378 | |||
379 | static ssize_t show_index(struct device *cd, | ||
380 | struct device_attribute *attr, char *buf) | ||
381 | { | ||
382 | struct video_device *vfd = container_of(cd, struct video_device, | ||
383 | class_dev); | ||
384 | return sprintf(buf, "%i\n", vfd->index); | ||
385 | } | ||
386 | |||
387 | static ssize_t show_name(struct device *cd, | ||
388 | struct device_attribute *attr, char *buf) | ||
389 | { | ||
390 | struct video_device *vfd = container_of(cd, struct video_device, | ||
391 | class_dev); | ||
392 | return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name); | ||
393 | } | ||
394 | |||
395 | static struct device_attribute video_device_attrs[] = { | ||
396 | __ATTR(name, S_IRUGO, show_name, NULL), | ||
397 | __ATTR(index, S_IRUGO, show_index, NULL), | ||
398 | __ATTR_NULL | ||
399 | }; | ||
400 | |||
401 | struct video_device *video_device_alloc(void) | ||
402 | { | ||
403 | struct video_device *vfd; | ||
404 | |||
405 | vfd = kzalloc(sizeof(*vfd),GFP_KERNEL); | ||
406 | return vfd; | ||
407 | } | ||
408 | EXPORT_SYMBOL(video_device_alloc); | ||
409 | |||
410 | void video_device_release(struct video_device *vfd) | ||
411 | { | ||
412 | kfree(vfd); | ||
413 | } | ||
414 | EXPORT_SYMBOL(video_device_release); | ||
415 | |||
416 | static void video_release(struct device *cd) | ||
417 | { | ||
418 | struct video_device *vfd = container_of(cd, struct video_device, | ||
419 | class_dev); | ||
420 | |||
421 | #if 1 | ||
422 | /* needed until all drivers are fixed */ | ||
423 | if (!vfd->release) | ||
424 | return; | ||
425 | #endif | ||
426 | vfd->release(vfd); | ||
427 | } | ||
428 | |||
429 | static struct class video_class = { | ||
430 | .name = VIDEO_NAME, | ||
431 | .dev_attrs = video_device_attrs, | ||
432 | .dev_release = video_release, | ||
433 | }; | ||
434 | |||
435 | /* | ||
436 | * Active devices | ||
437 | */ | ||
438 | |||
439 | static struct video_device *video_device[VIDEO_NUM_DEVICES]; | ||
440 | static DEFINE_MUTEX(videodev_lock); | ||
441 | |||
442 | struct video_device* video_devdata(struct file *file) | ||
443 | { | ||
444 | return video_device[iminor(file->f_path.dentry->d_inode)]; | ||
445 | } | ||
446 | EXPORT_SYMBOL(video_devdata); | ||
447 | |||
448 | /* | ||
449 | * Open a video device - FIXME: Obsoleted | ||
450 | */ | ||
451 | static int video_open(struct inode *inode, struct file *file) | ||
452 | { | ||
453 | unsigned int minor = iminor(inode); | ||
454 | int err = 0; | ||
455 | struct video_device *vfl; | ||
456 | const struct file_operations *old_fops; | ||
457 | |||
458 | if(minor>=VIDEO_NUM_DEVICES) | ||
459 | return -ENODEV; | ||
460 | lock_kernel(); | ||
461 | mutex_lock(&videodev_lock); | ||
462 | vfl=video_device[minor]; | ||
463 | if(vfl==NULL) { | ||
464 | mutex_unlock(&videodev_lock); | ||
465 | request_module("char-major-%d-%d", VIDEO_MAJOR, minor); | ||
466 | mutex_lock(&videodev_lock); | ||
467 | vfl=video_device[minor]; | ||
468 | if (vfl==NULL) { | ||
469 | mutex_unlock(&videodev_lock); | ||
470 | unlock_kernel(); | ||
471 | return -ENODEV; | ||
472 | } | ||
473 | } | ||
474 | old_fops = file->f_op; | ||
475 | file->f_op = fops_get(vfl->fops); | ||
476 | if(file->f_op->open) | ||
477 | err = file->f_op->open(inode,file); | ||
478 | if (err) { | ||
479 | fops_put(file->f_op); | ||
480 | file->f_op = fops_get(old_fops); | ||
481 | } | ||
482 | fops_put(old_fops); | ||
483 | mutex_unlock(&videodev_lock); | ||
484 | unlock_kernel(); | ||
485 | return err; | ||
486 | } | ||
487 | |||
488 | /* | ||
489 | * helper function -- handles userspace copying for ioctl arguments | ||
490 | */ | ||
491 | |||
492 | #ifdef __OLD_VIDIOC_ | ||
493 | static unsigned int | ||
494 | video_fix_command(unsigned int cmd) | ||
495 | { | ||
496 | switch (cmd) { | ||
497 | case VIDIOC_OVERLAY_OLD: | ||
498 | cmd = VIDIOC_OVERLAY; | ||
499 | break; | ||
500 | case VIDIOC_S_PARM_OLD: | ||
501 | cmd = VIDIOC_S_PARM; | ||
502 | break; | ||
503 | case VIDIOC_S_CTRL_OLD: | ||
504 | cmd = VIDIOC_S_CTRL; | ||
505 | break; | ||
506 | case VIDIOC_G_AUDIO_OLD: | ||
507 | cmd = VIDIOC_G_AUDIO; | ||
508 | break; | ||
509 | case VIDIOC_G_AUDOUT_OLD: | ||
510 | cmd = VIDIOC_G_AUDOUT; | ||
511 | break; | ||
512 | case VIDIOC_CROPCAP_OLD: | ||
513 | cmd = VIDIOC_CROPCAP; | ||
514 | break; | ||
515 | } | ||
516 | return cmd; | ||
517 | } | ||
518 | #endif | ||
519 | |||
520 | /* | ||
521 | * Obsolete usercopy function - Should be removed soon | ||
522 | */ | ||
523 | int | ||
524 | video_usercopy(struct inode *inode, struct file *file, | ||
525 | unsigned int cmd, unsigned long arg, | ||
526 | int (*func)(struct inode *inode, struct file *file, | ||
527 | unsigned int cmd, void *arg)) | ||
528 | { | ||
529 | char sbuf[128]; | ||
530 | void *mbuf = NULL; | ||
531 | void *parg = NULL; | ||
532 | int err = -EINVAL; | ||
533 | int is_ext_ctrl; | ||
534 | size_t ctrls_size = 0; | ||
535 | void __user *user_ptr = NULL; | ||
536 | |||
537 | #ifdef __OLD_VIDIOC_ | ||
538 | cmd = video_fix_command(cmd); | ||
539 | #endif | ||
540 | is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || | ||
541 | cmd == VIDIOC_TRY_EXT_CTRLS); | ||
542 | |||
543 | /* Copy arguments into temp kernel buffer */ | ||
544 | switch (_IOC_DIR(cmd)) { | ||
545 | case _IOC_NONE: | ||
546 | parg = NULL; | ||
547 | break; | ||
548 | case _IOC_READ: | ||
549 | case _IOC_WRITE: | ||
550 | case (_IOC_WRITE | _IOC_READ): | ||
551 | if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { | ||
552 | parg = sbuf; | ||
553 | } else { | ||
554 | /* too big to allocate from stack */ | ||
555 | mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); | ||
556 | if (NULL == mbuf) | ||
557 | return -ENOMEM; | ||
558 | parg = mbuf; | ||
559 | } | ||
560 | |||
561 | err = -EFAULT; | ||
562 | if (_IOC_DIR(cmd) & _IOC_WRITE) | ||
563 | if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) | ||
564 | goto out; | ||
565 | break; | ||
566 | } | ||
567 | if (is_ext_ctrl) { | ||
568 | struct v4l2_ext_controls *p = parg; | ||
569 | |||
570 | /* In case of an error, tell the caller that it wasn't | ||
571 | a specific control that caused it. */ | ||
572 | p->error_idx = p->count; | ||
573 | user_ptr = (void __user *)p->controls; | ||
574 | if (p->count) { | ||
575 | ctrls_size = sizeof(struct v4l2_ext_control) * p->count; | ||
576 | /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */ | ||
577 | mbuf = kmalloc(ctrls_size, GFP_KERNEL); | ||
578 | err = -ENOMEM; | ||
579 | if (NULL == mbuf) | ||
580 | goto out_ext_ctrl; | ||
581 | err = -EFAULT; | ||
582 | if (copy_from_user(mbuf, user_ptr, ctrls_size)) | ||
583 | goto out_ext_ctrl; | ||
584 | p->controls = mbuf; | ||
585 | } | ||
586 | } | ||
587 | |||
588 | /* call driver */ | ||
589 | err = func(inode, file, cmd, parg); | ||
590 | if (err == -ENOIOCTLCMD) | ||
591 | err = -EINVAL; | ||
592 | if (is_ext_ctrl) { | ||
593 | struct v4l2_ext_controls *p = parg; | ||
594 | |||
595 | p->controls = (void *)user_ptr; | ||
596 | if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size)) | ||
597 | err = -EFAULT; | ||
598 | goto out_ext_ctrl; | ||
599 | } | ||
600 | if (err < 0) | ||
601 | goto out; | ||
602 | |||
603 | out_ext_ctrl: | ||
604 | /* Copy results into user buffer */ | ||
605 | switch (_IOC_DIR(cmd)) | ||
606 | { | ||
607 | case _IOC_READ: | ||
608 | case (_IOC_WRITE | _IOC_READ): | ||
609 | if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) | ||
610 | err = -EFAULT; | ||
611 | break; | ||
612 | } | ||
613 | |||
614 | out: | ||
615 | kfree(mbuf); | ||
616 | return err; | ||
617 | } | ||
618 | EXPORT_SYMBOL(video_usercopy); | ||
619 | |||
620 | /* | ||
621 | * open/release helper functions -- handle exclusive opens | ||
622 | * Should be removed soon | ||
623 | */ | ||
624 | int video_exclusive_open(struct inode *inode, struct file *file) | ||
625 | { | ||
626 | struct video_device *vfl = video_devdata(file); | ||
627 | int retval = 0; | ||
628 | |||
629 | mutex_lock(&vfl->lock); | ||
630 | if (vfl->users) { | ||
631 | retval = -EBUSY; | ||
632 | } else { | ||
633 | vfl->users++; | ||
634 | } | ||
635 | mutex_unlock(&vfl->lock); | ||
636 | return retval; | ||
637 | } | ||
638 | EXPORT_SYMBOL(video_exclusive_open); | ||
639 | |||
640 | int video_exclusive_release(struct inode *inode, struct file *file) | ||
641 | { | ||
642 | struct video_device *vfl = video_devdata(file); | ||
643 | |||
644 | vfl->users--; | ||
645 | return 0; | ||
646 | } | ||
647 | EXPORT_SYMBOL(video_exclusive_release); | ||
648 | |||
649 | static void dbgbuf(unsigned int cmd, struct video_device *vfd, | ||
650 | struct v4l2_buffer *p) | ||
651 | { | ||
652 | struct v4l2_timecode *tc=&p->timecode; | ||
653 | |||
654 | dbgarg (cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, " | ||
655 | "bytesused=%d, flags=0x%08d, " | ||
656 | "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n", | ||
657 | (p->timestamp.tv_sec/3600), | ||
658 | (int)(p->timestamp.tv_sec/60)%60, | ||
659 | (int)(p->timestamp.tv_sec%60), | ||
660 | p->timestamp.tv_usec, | ||
661 | p->index, | ||
662 | prt_names(p->type, v4l2_type_names), | ||
663 | p->bytesused, p->flags, | ||
664 | p->field, p->sequence, | ||
665 | prt_names(p->memory, v4l2_memory_names), | ||
666 | p->m.userptr, p->length); | ||
667 | dbgarg2("timecode=%02d:%02d:%02d type=%d, " | ||
668 | "flags=0x%08d, frames=%d, userbits=0x%08x\n", | ||
669 | tc->hours,tc->minutes,tc->seconds, | ||
670 | tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits); | ||
671 | } | ||
672 | |||
673 | static inline void dbgrect(struct video_device *vfd, char *s, | ||
674 | struct v4l2_rect *r) | ||
675 | { | ||
676 | dbgarg2("%sRect start at %dx%d, size=%dx%d\n", s, r->left, r->top, | ||
677 | r->width, r->height); | ||
678 | }; | ||
679 | |||
680 | static inline void v4l_print_pix_fmt (struct video_device *vfd, | ||
681 | struct v4l2_pix_format *fmt) | ||
682 | { | ||
683 | dbgarg2 ("width=%d, height=%d, format=%c%c%c%c, field=%s, " | ||
684 | "bytesperline=%d sizeimage=%d, colorspace=%d\n", | ||
685 | fmt->width,fmt->height, | ||
686 | (fmt->pixelformat & 0xff), | ||
687 | (fmt->pixelformat >> 8) & 0xff, | ||
688 | (fmt->pixelformat >> 16) & 0xff, | ||
689 | (fmt->pixelformat >> 24) & 0xff, | ||
690 | prt_names(fmt->field, v4l2_field_names), | ||
691 | fmt->bytesperline, fmt->sizeimage, fmt->colorspace); | ||
692 | }; | ||
693 | |||
694 | static inline void v4l_print_ext_ctrls(unsigned int cmd, | ||
695 | struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals) | ||
696 | { | ||
697 | __u32 i; | ||
698 | |||
699 | if (!(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) | ||
700 | return; | ||
701 | dbgarg(cmd, ""); | ||
702 | printk(KERN_CONT "class=0x%x", c->ctrl_class); | ||
703 | for (i = 0; i < c->count; i++) { | ||
704 | if (show_vals) | ||
705 | printk(KERN_CONT " id/val=0x%x/0x%x", | ||
706 | c->controls[i].id, c->controls[i].value); | ||
707 | else | ||
708 | printk(KERN_CONT " id=0x%x", c->controls[i].id); | ||
709 | } | ||
710 | printk(KERN_CONT "\n"); | ||
711 | }; | ||
712 | |||
713 | static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) | ||
714 | { | ||
715 | __u32 i; | ||
716 | |||
717 | /* zero the reserved fields */ | ||
718 | c->reserved[0] = c->reserved[1] = 0; | ||
719 | for (i = 0; i < c->count; i++) { | ||
720 | c->controls[i].reserved2[0] = 0; | ||
721 | c->controls[i].reserved2[1] = 0; | ||
722 | } | ||
723 | /* V4L2_CID_PRIVATE_BASE cannot be used as control class | ||
724 | when using extended controls. | ||
725 | Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL | ||
726 | is it allowed for backwards compatibility. | ||
727 | */ | ||
728 | if (!allow_priv && c->ctrl_class == V4L2_CID_PRIVATE_BASE) | ||
729 | return 0; | ||
730 | /* Check that all controls are from the same control class. */ | ||
731 | for (i = 0; i < c->count; i++) { | ||
732 | if (V4L2_CTRL_ID2CLASS(c->controls[i].id) != c->ctrl_class) { | ||
733 | c->error_idx = i; | ||
734 | return 0; | ||
735 | } | ||
736 | } | ||
737 | return 1; | ||
738 | } | ||
739 | |||
740 | static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type) | ||
741 | { | ||
742 | switch (type) { | ||
743 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
744 | if (vfd->vidioc_try_fmt_vid_cap) | ||
745 | return (0); | ||
746 | break; | ||
747 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
748 | if (vfd->vidioc_try_fmt_vid_overlay) | ||
749 | return (0); | ||
750 | break; | ||
751 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | ||
752 | if (vfd->vidioc_try_fmt_vid_out) | ||
753 | return (0); | ||
754 | break; | ||
755 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | ||
756 | if (vfd->vidioc_try_fmt_vid_out_overlay) | ||
757 | return (0); | ||
758 | break; | ||
759 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
760 | if (vfd->vidioc_try_fmt_vbi_cap) | ||
761 | return (0); | ||
762 | break; | ||
763 | case V4L2_BUF_TYPE_VBI_OUTPUT: | ||
764 | if (vfd->vidioc_try_fmt_vbi_out) | ||
765 | return (0); | ||
766 | break; | ||
767 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | ||
768 | if (vfd->vidioc_try_fmt_sliced_vbi_cap) | ||
769 | return (0); | ||
770 | break; | ||
771 | case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: | ||
772 | if (vfd->vidioc_try_fmt_sliced_vbi_out) | ||
773 | return (0); | ||
774 | break; | ||
775 | case V4L2_BUF_TYPE_PRIVATE: | ||
776 | if (vfd->vidioc_try_fmt_type_private) | ||
777 | return (0); | ||
778 | break; | ||
779 | } | ||
780 | return (-EINVAL); | ||
781 | } | ||
782 | |||
783 | static int __video_do_ioctl(struct inode *inode, struct file *file, | ||
784 | unsigned int cmd, void *arg) | ||
785 | { | ||
786 | struct video_device *vfd = video_devdata(file); | ||
787 | void *fh = file->private_data; | ||
788 | int ret = -EINVAL; | ||
789 | |||
790 | if ( (vfd->debug & V4L2_DEBUG_IOCTL) && | ||
791 | !(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) { | ||
792 | v4l_print_ioctl(vfd->name, cmd); | ||
793 | printk("\n"); | ||
794 | } | ||
795 | |||
796 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | ||
797 | /*********************************************************** | ||
798 | Handles calls to the obsoleted V4L1 API | ||
799 | Due to the nature of VIDIOCGMBUF, each driver that supports | ||
800 | V4L1 should implement its own handler for this ioctl. | ||
801 | ***********************************************************/ | ||
802 | |||
803 | /* --- streaming capture ------------------------------------- */ | ||
804 | if (cmd == VIDIOCGMBUF) { | ||
805 | struct video_mbuf *p=arg; | ||
806 | |||
807 | memset(p, 0, sizeof(*p)); | ||
808 | |||
809 | if (!vfd->vidiocgmbuf) | ||
810 | return ret; | ||
811 | ret=vfd->vidiocgmbuf(file, fh, p); | ||
812 | if (!ret) | ||
813 | dbgarg (cmd, "size=%d, frames=%d, offsets=0x%08lx\n", | ||
814 | p->size, p->frames, | ||
815 | (unsigned long)p->offsets); | ||
816 | return ret; | ||
817 | } | ||
818 | |||
819 | /******************************************************** | ||
820 | All other V4L1 calls are handled by v4l1_compat module. | ||
821 | Those calls will be translated into V4L2 calls, and | ||
822 | __video_do_ioctl will be called again, with one or more | ||
823 | V4L2 ioctls. | ||
824 | ********************************************************/ | ||
825 | if (_IOC_TYPE(cmd)=='v') | ||
826 | return v4l_compat_translate_ioctl(inode,file,cmd,arg, | ||
827 | __video_do_ioctl); | ||
828 | #endif | ||
829 | |||
830 | switch(cmd) { | ||
831 | /* --- capabilities ------------------------------------------ */ | ||
832 | case VIDIOC_QUERYCAP: | ||
833 | { | ||
834 | struct v4l2_capability *cap = (struct v4l2_capability*)arg; | ||
835 | memset(cap, 0, sizeof(*cap)); | ||
836 | |||
837 | if (!vfd->vidioc_querycap) | ||
838 | break; | ||
839 | |||
840 | ret=vfd->vidioc_querycap(file, fh, cap); | ||
841 | if (!ret) | ||
842 | dbgarg (cmd, "driver=%s, card=%s, bus=%s, " | ||
843 | "version=0x%08x, " | ||
844 | "capabilities=0x%08x\n", | ||
845 | cap->driver,cap->card,cap->bus_info, | ||
846 | cap->version, | ||
847 | cap->capabilities); | ||
848 | break; | ||
849 | } | ||
850 | |||
851 | /* --- priority ------------------------------------------ */ | ||
852 | case VIDIOC_G_PRIORITY: | ||
853 | { | ||
854 | enum v4l2_priority *p=arg; | ||
855 | |||
856 | if (!vfd->vidioc_g_priority) | ||
857 | break; | ||
858 | ret=vfd->vidioc_g_priority(file, fh, p); | ||
859 | if (!ret) | ||
860 | dbgarg(cmd, "priority is %d\n", *p); | ||
861 | break; | ||
862 | } | ||
863 | case VIDIOC_S_PRIORITY: | ||
864 | { | ||
865 | enum v4l2_priority *p=arg; | ||
866 | |||
867 | if (!vfd->vidioc_s_priority) | ||
868 | break; | ||
869 | dbgarg(cmd, "setting priority to %d\n", *p); | ||
870 | ret=vfd->vidioc_s_priority(file, fh, *p); | ||
871 | break; | ||
872 | } | ||
873 | |||
874 | /* --- capture ioctls ---------------------------------------- */ | ||
875 | case VIDIOC_ENUM_FMT: | ||
876 | { | ||
877 | struct v4l2_fmtdesc *f = arg; | ||
878 | enum v4l2_buf_type type; | ||
879 | unsigned int index; | ||
880 | |||
881 | index = f->index; | ||
882 | type = f->type; | ||
883 | memset(f,0,sizeof(*f)); | ||
884 | f->index = index; | ||
885 | f->type = type; | ||
886 | |||
887 | switch (type) { | ||
888 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
889 | if (vfd->vidioc_enum_fmt_vid_cap) | ||
890 | ret = vfd->vidioc_enum_fmt_vid_cap(file, fh, f); | ||
891 | break; | ||
892 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
893 | if (vfd->vidioc_enum_fmt_vid_overlay) | ||
894 | ret = vfd->vidioc_enum_fmt_vid_overlay(file, | ||
895 | fh, f); | ||
896 | break; | ||
897 | #if 1 | ||
898 | /* V4L2_BUF_TYPE_VBI_CAPTURE should not support VIDIOC_ENUM_FMT | ||
899 | * according to the spec. The bttv and saa7134 drivers support | ||
900 | * it though, so just warn that this is deprecated and will be | ||
901 | * removed in the near future. */ | ||
902 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
903 | if (vfd->vidioc_enum_fmt_vbi_cap) { | ||
904 | printk(KERN_WARNING "vidioc_enum_fmt_vbi_cap will be removed in 2.6.28!\n"); | ||
905 | ret = vfd->vidioc_enum_fmt_vbi_cap(file, fh, f); | ||
906 | } | ||
907 | break; | ||
908 | #endif | ||
909 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | ||
910 | if (vfd->vidioc_enum_fmt_vid_out) | ||
911 | ret = vfd->vidioc_enum_fmt_vid_out(file, fh, f); | ||
912 | break; | ||
913 | case V4L2_BUF_TYPE_PRIVATE: | ||
914 | if (vfd->vidioc_enum_fmt_type_private) | ||
915 | ret = vfd->vidioc_enum_fmt_type_private(file, | ||
916 | fh, f); | ||
917 | break; | ||
918 | default: | ||
919 | break; | ||
920 | } | ||
921 | if (!ret) | ||
922 | dbgarg (cmd, "index=%d, type=%d, flags=%d, " | ||
923 | "pixelformat=%c%c%c%c, description='%s'\n", | ||
924 | f->index, f->type, f->flags, | ||
925 | (f->pixelformat & 0xff), | ||
926 | (f->pixelformat >> 8) & 0xff, | ||
927 | (f->pixelformat >> 16) & 0xff, | ||
928 | (f->pixelformat >> 24) & 0xff, | ||
929 | f->description); | ||
930 | break; | ||
931 | } | ||
932 | case VIDIOC_G_FMT: | ||
933 | { | ||
934 | struct v4l2_format *f = (struct v4l2_format *)arg; | ||
935 | |||
936 | memset(f->fmt.raw_data, 0, sizeof(f->fmt.raw_data)); | ||
937 | |||
938 | /* FIXME: Should be one dump per type */ | ||
939 | dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); | ||
940 | |||
941 | switch (f->type) { | ||
942 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
943 | if (vfd->vidioc_g_fmt_vid_cap) | ||
944 | ret = vfd->vidioc_g_fmt_vid_cap(file, fh, f); | ||
945 | if (!ret) | ||
946 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | ||
947 | break; | ||
948 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
949 | if (vfd->vidioc_g_fmt_vid_overlay) | ||
950 | ret = vfd->vidioc_g_fmt_vid_overlay(file, | ||
951 | fh, f); | ||
952 | break; | ||
953 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | ||
954 | if (vfd->vidioc_g_fmt_vid_out) | ||
955 | ret = vfd->vidioc_g_fmt_vid_out(file, fh, f); | ||
956 | if (!ret) | ||
957 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | ||
958 | break; | ||
959 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | ||
960 | if (vfd->vidioc_g_fmt_vid_out_overlay) | ||
961 | ret = vfd->vidioc_g_fmt_vid_out_overlay(file, | ||
962 | fh, f); | ||
963 | break; | ||
964 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
965 | if (vfd->vidioc_g_fmt_vbi_cap) | ||
966 | ret = vfd->vidioc_g_fmt_vbi_cap(file, fh, f); | ||
967 | break; | ||
968 | case V4L2_BUF_TYPE_VBI_OUTPUT: | ||
969 | if (vfd->vidioc_g_fmt_vbi_out) | ||
970 | ret = vfd->vidioc_g_fmt_vbi_out(file, fh, f); | ||
971 | break; | ||
972 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | ||
973 | if (vfd->vidioc_g_fmt_sliced_vbi_cap) | ||
974 | ret = vfd->vidioc_g_fmt_sliced_vbi_cap(file, | ||
975 | fh, f); | ||
976 | break; | ||
977 | case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: | ||
978 | if (vfd->vidioc_g_fmt_sliced_vbi_out) | ||
979 | ret = vfd->vidioc_g_fmt_sliced_vbi_out(file, | ||
980 | fh, f); | ||
981 | break; | ||
982 | case V4L2_BUF_TYPE_PRIVATE: | ||
983 | if (vfd->vidioc_g_fmt_type_private) | ||
984 | ret = vfd->vidioc_g_fmt_type_private(file, | ||
985 | fh, f); | ||
986 | break; | ||
987 | } | ||
988 | |||
989 | break; | ||
990 | } | ||
991 | case VIDIOC_S_FMT: | ||
992 | { | ||
993 | struct v4l2_format *f = (struct v4l2_format *)arg; | ||
994 | |||
995 | /* FIXME: Should be one dump per type */ | ||
996 | dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); | ||
997 | |||
998 | switch (f->type) { | ||
999 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
1000 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | ||
1001 | if (vfd->vidioc_s_fmt_vid_cap) | ||
1002 | ret = vfd->vidioc_s_fmt_vid_cap(file, fh, f); | ||
1003 | break; | ||
1004 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
1005 | if (vfd->vidioc_s_fmt_vid_overlay) | ||
1006 | ret = vfd->vidioc_s_fmt_vid_overlay(file, | ||
1007 | fh, f); | ||
1008 | break; | ||
1009 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | ||
1010 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | ||
1011 | if (vfd->vidioc_s_fmt_vid_out) | ||
1012 | ret = vfd->vidioc_s_fmt_vid_out(file, fh, f); | ||
1013 | break; | ||
1014 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | ||
1015 | if (vfd->vidioc_s_fmt_vid_out_overlay) | ||
1016 | ret = vfd->vidioc_s_fmt_vid_out_overlay(file, | ||
1017 | fh, f); | ||
1018 | break; | ||
1019 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
1020 | if (vfd->vidioc_s_fmt_vbi_cap) | ||
1021 | ret = vfd->vidioc_s_fmt_vbi_cap(file, fh, f); | ||
1022 | break; | ||
1023 | case V4L2_BUF_TYPE_VBI_OUTPUT: | ||
1024 | if (vfd->vidioc_s_fmt_vbi_out) | ||
1025 | ret = vfd->vidioc_s_fmt_vbi_out(file, fh, f); | ||
1026 | break; | ||
1027 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | ||
1028 | if (vfd->vidioc_s_fmt_sliced_vbi_cap) | ||
1029 | ret = vfd->vidioc_s_fmt_sliced_vbi_cap(file, | ||
1030 | fh, f); | ||
1031 | break; | ||
1032 | case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: | ||
1033 | if (vfd->vidioc_s_fmt_sliced_vbi_out) | ||
1034 | ret = vfd->vidioc_s_fmt_sliced_vbi_out(file, | ||
1035 | fh, f); | ||
1036 | break; | ||
1037 | case V4L2_BUF_TYPE_PRIVATE: | ||
1038 | if (vfd->vidioc_s_fmt_type_private) | ||
1039 | ret = vfd->vidioc_s_fmt_type_private(file, | ||
1040 | fh, f); | ||
1041 | break; | ||
1042 | } | ||
1043 | break; | ||
1044 | } | ||
1045 | case VIDIOC_TRY_FMT: | ||
1046 | { | ||
1047 | struct v4l2_format *f = (struct v4l2_format *)arg; | ||
1048 | |||
1049 | /* FIXME: Should be one dump per type */ | ||
1050 | dbgarg (cmd, "type=%s\n", prt_names(f->type, | ||
1051 | v4l2_type_names)); | ||
1052 | switch (f->type) { | ||
1053 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
1054 | if (vfd->vidioc_try_fmt_vid_cap) | ||
1055 | ret = vfd->vidioc_try_fmt_vid_cap(file, fh, f); | ||
1056 | if (!ret) | ||
1057 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | ||
1058 | break; | ||
1059 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
1060 | if (vfd->vidioc_try_fmt_vid_overlay) | ||
1061 | ret = vfd->vidioc_try_fmt_vid_overlay(file, | ||
1062 | fh, f); | ||
1063 | break; | ||
1064 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | ||
1065 | if (vfd->vidioc_try_fmt_vid_out) | ||
1066 | ret = vfd->vidioc_try_fmt_vid_out(file, fh, f); | ||
1067 | if (!ret) | ||
1068 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | ||
1069 | break; | ||
1070 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | ||
1071 | if (vfd->vidioc_try_fmt_vid_out_overlay) | ||
1072 | ret = vfd->vidioc_try_fmt_vid_out_overlay(file, | ||
1073 | fh, f); | ||
1074 | break; | ||
1075 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
1076 | if (vfd->vidioc_try_fmt_vbi_cap) | ||
1077 | ret = vfd->vidioc_try_fmt_vbi_cap(file, fh, f); | ||
1078 | break; | ||
1079 | case V4L2_BUF_TYPE_VBI_OUTPUT: | ||
1080 | if (vfd->vidioc_try_fmt_vbi_out) | ||
1081 | ret = vfd->vidioc_try_fmt_vbi_out(file, fh, f); | ||
1082 | break; | ||
1083 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | ||
1084 | if (vfd->vidioc_try_fmt_sliced_vbi_cap) | ||
1085 | ret = vfd->vidioc_try_fmt_sliced_vbi_cap(file, | ||
1086 | fh, f); | ||
1087 | break; | ||
1088 | case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: | ||
1089 | if (vfd->vidioc_try_fmt_sliced_vbi_out) | ||
1090 | ret = vfd->vidioc_try_fmt_sliced_vbi_out(file, | ||
1091 | fh, f); | ||
1092 | break; | ||
1093 | case V4L2_BUF_TYPE_PRIVATE: | ||
1094 | if (vfd->vidioc_try_fmt_type_private) | ||
1095 | ret = vfd->vidioc_try_fmt_type_private(file, | ||
1096 | fh, f); | ||
1097 | break; | ||
1098 | } | ||
1099 | |||
1100 | break; | ||
1101 | } | ||
1102 | /* FIXME: Those buf reqs could be handled here, | ||
1103 | with some changes on videobuf to allow its header to be included at | ||
1104 | videodev2.h or being merged at videodev2. | ||
1105 | */ | ||
1106 | case VIDIOC_REQBUFS: | ||
1107 | { | ||
1108 | struct v4l2_requestbuffers *p=arg; | ||
1109 | |||
1110 | if (!vfd->vidioc_reqbufs) | ||
1111 | break; | ||
1112 | ret = check_fmt (vfd, p->type); | ||
1113 | if (ret) | ||
1114 | break; | ||
1115 | |||
1116 | ret=vfd->vidioc_reqbufs(file, fh, p); | ||
1117 | dbgarg (cmd, "count=%d, type=%s, memory=%s\n", | ||
1118 | p->count, | ||
1119 | prt_names(p->type, v4l2_type_names), | ||
1120 | prt_names(p->memory, v4l2_memory_names)); | ||
1121 | break; | ||
1122 | } | ||
1123 | case VIDIOC_QUERYBUF: | ||
1124 | { | ||
1125 | struct v4l2_buffer *p=arg; | ||
1126 | |||
1127 | if (!vfd->vidioc_querybuf) | ||
1128 | break; | ||
1129 | ret = check_fmt (vfd, p->type); | ||
1130 | if (ret) | ||
1131 | break; | ||
1132 | |||
1133 | ret=vfd->vidioc_querybuf(file, fh, p); | ||
1134 | if (!ret) | ||
1135 | dbgbuf(cmd,vfd,p); | ||
1136 | break; | ||
1137 | } | ||
1138 | case VIDIOC_QBUF: | ||
1139 | { | ||
1140 | struct v4l2_buffer *p=arg; | ||
1141 | |||
1142 | if (!vfd->vidioc_qbuf) | ||
1143 | break; | ||
1144 | ret = check_fmt (vfd, p->type); | ||
1145 | if (ret) | ||
1146 | break; | ||
1147 | |||
1148 | ret=vfd->vidioc_qbuf(file, fh, p); | ||
1149 | if (!ret) | ||
1150 | dbgbuf(cmd,vfd,p); | ||
1151 | break; | ||
1152 | } | ||
1153 | case VIDIOC_DQBUF: | ||
1154 | { | ||
1155 | struct v4l2_buffer *p=arg; | ||
1156 | if (!vfd->vidioc_dqbuf) | ||
1157 | break; | ||
1158 | ret = check_fmt (vfd, p->type); | ||
1159 | if (ret) | ||
1160 | break; | ||
1161 | |||
1162 | ret=vfd->vidioc_dqbuf(file, fh, p); | ||
1163 | if (!ret) | ||
1164 | dbgbuf(cmd,vfd,p); | ||
1165 | break; | ||
1166 | } | ||
1167 | case VIDIOC_OVERLAY: | ||
1168 | { | ||
1169 | int *i = arg; | ||
1170 | |||
1171 | if (!vfd->vidioc_overlay) | ||
1172 | break; | ||
1173 | dbgarg (cmd, "value=%d\n",*i); | ||
1174 | ret=vfd->vidioc_overlay(file, fh, *i); | ||
1175 | break; | ||
1176 | } | ||
1177 | case VIDIOC_G_FBUF: | ||
1178 | { | ||
1179 | struct v4l2_framebuffer *p = arg; | ||
1180 | |||
1181 | if (!vfd->vidioc_g_fbuf) | ||
1182 | break; | ||
1183 | ret = vfd->vidioc_g_fbuf(file, fh, arg); | ||
1184 | if (!ret) { | ||
1185 | dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", | ||
1186 | p->capability, p->flags, | ||
1187 | (unsigned long)p->base); | ||
1188 | v4l_print_pix_fmt(vfd, &p->fmt); | ||
1189 | } | ||
1190 | break; | ||
1191 | } | ||
1192 | case VIDIOC_S_FBUF: | ||
1193 | { | ||
1194 | struct v4l2_framebuffer *p = arg; | ||
1195 | |||
1196 | if (!vfd->vidioc_s_fbuf) | ||
1197 | break; | ||
1198 | dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", | ||
1199 | p->capability, p->flags, (unsigned long)p->base); | ||
1200 | v4l_print_pix_fmt(vfd, &p->fmt); | ||
1201 | ret = vfd->vidioc_s_fbuf(file, fh, arg); | ||
1202 | break; | ||
1203 | } | ||
1204 | case VIDIOC_STREAMON: | ||
1205 | { | ||
1206 | enum v4l2_buf_type i = *(int *)arg; | ||
1207 | if (!vfd->vidioc_streamon) | ||
1208 | break; | ||
1209 | dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); | ||
1210 | ret=vfd->vidioc_streamon(file, fh,i); | ||
1211 | break; | ||
1212 | } | ||
1213 | case VIDIOC_STREAMOFF: | ||
1214 | { | ||
1215 | enum v4l2_buf_type i = *(int *)arg; | ||
1216 | |||
1217 | if (!vfd->vidioc_streamoff) | ||
1218 | break; | ||
1219 | dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); | ||
1220 | ret=vfd->vidioc_streamoff(file, fh, i); | ||
1221 | break; | ||
1222 | } | ||
1223 | /* ---------- tv norms ---------- */ | ||
1224 | case VIDIOC_ENUMSTD: | ||
1225 | { | ||
1226 | struct v4l2_standard *p = arg; | ||
1227 | v4l2_std_id id = vfd->tvnorms, curr_id = 0; | ||
1228 | unsigned int index = p->index, i, j = 0; | ||
1229 | const char *descr = ""; | ||
1230 | |||
1231 | /* Return norm array in a canonical way */ | ||
1232 | for (i = 0; i <= index && id; i++) { | ||
1233 | /* last std value in the standards array is 0, so this | ||
1234 | while always ends there since (id & 0) == 0. */ | ||
1235 | while ((id & standards[j].std) != standards[j].std) | ||
1236 | j++; | ||
1237 | curr_id = standards[j].std; | ||
1238 | descr = standards[j].descr; | ||
1239 | j++; | ||
1240 | if (curr_id == 0) | ||
1241 | break; | ||
1242 | if (curr_id != V4L2_STD_PAL && | ||
1243 | curr_id != V4L2_STD_SECAM && | ||
1244 | curr_id != V4L2_STD_NTSC) | ||
1245 | id &= ~curr_id; | ||
1246 | } | ||
1247 | if (i <= index) | ||
1248 | return -EINVAL; | ||
1249 | |||
1250 | v4l2_video_std_construct(p, curr_id, descr); | ||
1251 | p->index = index; | ||
1252 | |||
1253 | dbgarg(cmd, "index=%d, id=0x%Lx, name=%s, fps=%d/%d, " | ||
1254 | "framelines=%d\n", p->index, | ||
1255 | (unsigned long long)p->id, p->name, | ||
1256 | p->frameperiod.numerator, | ||
1257 | p->frameperiod.denominator, | ||
1258 | p->framelines); | ||
1259 | |||
1260 | ret = 0; | ||
1261 | break; | ||
1262 | } | ||
1263 | case VIDIOC_G_STD: | ||
1264 | { | ||
1265 | v4l2_std_id *id = arg; | ||
1266 | |||
1267 | ret = 0; | ||
1268 | /* Calls the specific handler */ | ||
1269 | if (vfd->vidioc_g_std) | ||
1270 | ret = vfd->vidioc_g_std(file, fh, id); | ||
1271 | else | ||
1272 | *id = vfd->current_norm; | ||
1273 | |||
1274 | if (!ret) | ||
1275 | dbgarg(cmd, "std=0x%08Lx\n", (long long unsigned)*id); | ||
1276 | break; | ||
1277 | } | ||
1278 | case VIDIOC_S_STD: | ||
1279 | { | ||
1280 | v4l2_std_id *id = arg,norm; | ||
1281 | |||
1282 | dbgarg(cmd, "std=%08Lx\n", (long long unsigned)*id); | ||
1283 | |||
1284 | norm = (*id) & vfd->tvnorms; | ||
1285 | if ( vfd->tvnorms && !norm) /* Check if std is supported */ | ||
1286 | break; | ||
1287 | |||
1288 | /* Calls the specific handler */ | ||
1289 | if (vfd->vidioc_s_std) | ||
1290 | ret=vfd->vidioc_s_std(file, fh, &norm); | ||
1291 | else | ||
1292 | ret=-EINVAL; | ||
1293 | |||
1294 | /* Updates standard information */ | ||
1295 | if (ret>=0) | ||
1296 | vfd->current_norm=norm; | ||
1297 | |||
1298 | break; | ||
1299 | } | ||
1300 | case VIDIOC_QUERYSTD: | ||
1301 | { | ||
1302 | v4l2_std_id *p=arg; | ||
1303 | |||
1304 | if (!vfd->vidioc_querystd) | ||
1305 | break; | ||
1306 | ret=vfd->vidioc_querystd(file, fh, arg); | ||
1307 | if (!ret) | ||
1308 | dbgarg (cmd, "detected std=%08Lx\n", | ||
1309 | (unsigned long long)*p); | ||
1310 | break; | ||
1311 | } | ||
1312 | /* ------ input switching ---------- */ | ||
1313 | /* FIXME: Inputs can be handled inside videodev2 */ | ||
1314 | case VIDIOC_ENUMINPUT: | ||
1315 | { | ||
1316 | struct v4l2_input *p=arg; | ||
1317 | int i=p->index; | ||
1318 | |||
1319 | if (!vfd->vidioc_enum_input) | ||
1320 | break; | ||
1321 | memset(p, 0, sizeof(*p)); | ||
1322 | p->index=i; | ||
1323 | |||
1324 | ret=vfd->vidioc_enum_input(file, fh, p); | ||
1325 | if (!ret) | ||
1326 | dbgarg (cmd, "index=%d, name=%s, type=%d, " | ||
1327 | "audioset=%d, " | ||
1328 | "tuner=%d, std=%08Lx, status=%d\n", | ||
1329 | p->index,p->name,p->type,p->audioset, | ||
1330 | p->tuner, | ||
1331 | (unsigned long long)p->std, | ||
1332 | p->status); | ||
1333 | break; | ||
1334 | } | ||
1335 | case VIDIOC_G_INPUT: | ||
1336 | { | ||
1337 | unsigned int *i = arg; | ||
1338 | |||
1339 | if (!vfd->vidioc_g_input) | ||
1340 | break; | ||
1341 | ret=vfd->vidioc_g_input(file, fh, i); | ||
1342 | if (!ret) | ||
1343 | dbgarg (cmd, "value=%d\n",*i); | ||
1344 | break; | ||
1345 | } | ||
1346 | case VIDIOC_S_INPUT: | ||
1347 | { | ||
1348 | unsigned int *i = arg; | ||
1349 | |||
1350 | if (!vfd->vidioc_s_input) | ||
1351 | break; | ||
1352 | dbgarg (cmd, "value=%d\n",*i); | ||
1353 | ret=vfd->vidioc_s_input(file, fh, *i); | ||
1354 | break; | ||
1355 | } | ||
1356 | |||
1357 | /* ------ output switching ---------- */ | ||
1358 | case VIDIOC_ENUMOUTPUT: | ||
1359 | { | ||
1360 | struct v4l2_output *p = arg; | ||
1361 | int i = p->index; | ||
1362 | |||
1363 | if (!vfd->vidioc_enum_output) | ||
1364 | break; | ||
1365 | memset(p, 0, sizeof(*p)); | ||
1366 | p->index = i; | ||
1367 | |||
1368 | ret = vfd->vidioc_enum_output(file, fh, p); | ||
1369 | if (!ret) | ||
1370 | dbgarg(cmd, "index=%d, name=%s, type=%d, " | ||
1371 | "audioset=0x%x, " | ||
1372 | "modulator=%d, std=0x%08Lx\n", | ||
1373 | p->index, p->name, p->type, p->audioset, | ||
1374 | p->modulator, (unsigned long long)p->std); | ||
1375 | break; | ||
1376 | } | ||
1377 | case VIDIOC_G_OUTPUT: | ||
1378 | { | ||
1379 | unsigned int *i = arg; | ||
1380 | |||
1381 | if (!vfd->vidioc_g_output) | ||
1382 | break; | ||
1383 | ret=vfd->vidioc_g_output(file, fh, i); | ||
1384 | if (!ret) | ||
1385 | dbgarg (cmd, "value=%d\n",*i); | ||
1386 | break; | ||
1387 | } | ||
1388 | case VIDIOC_S_OUTPUT: | ||
1389 | { | ||
1390 | unsigned int *i = arg; | ||
1391 | |||
1392 | if (!vfd->vidioc_s_output) | ||
1393 | break; | ||
1394 | dbgarg (cmd, "value=%d\n",*i); | ||
1395 | ret=vfd->vidioc_s_output(file, fh, *i); | ||
1396 | break; | ||
1397 | } | ||
1398 | |||
1399 | /* --- controls ---------------------------------------------- */ | ||
1400 | case VIDIOC_QUERYCTRL: | ||
1401 | { | ||
1402 | struct v4l2_queryctrl *p = arg; | ||
1403 | |||
1404 | if (!vfd->vidioc_queryctrl) | ||
1405 | break; | ||
1406 | ret = vfd->vidioc_queryctrl(file, fh, p); | ||
1407 | if (!ret) | ||
1408 | dbgarg(cmd, "id=0x%x, type=%d, name=%s, min/max=%d/%d, " | ||
1409 | "step=%d, default=%d, flags=0x%08x\n", | ||
1410 | p->id, p->type, p->name, | ||
1411 | p->minimum, p->maximum, | ||
1412 | p->step, p->default_value, p->flags); | ||
1413 | else | ||
1414 | dbgarg(cmd, "id=0x%x\n", p->id); | ||
1415 | break; | ||
1416 | } | ||
1417 | case VIDIOC_G_CTRL: | ||
1418 | { | ||
1419 | struct v4l2_control *p = arg; | ||
1420 | |||
1421 | if (vfd->vidioc_g_ctrl) | ||
1422 | ret = vfd->vidioc_g_ctrl(file, fh, p); | ||
1423 | else if (vfd->vidioc_g_ext_ctrls) { | ||
1424 | struct v4l2_ext_controls ctrls; | ||
1425 | struct v4l2_ext_control ctrl; | ||
1426 | |||
1427 | ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); | ||
1428 | ctrls.count = 1; | ||
1429 | ctrls.controls = &ctrl; | ||
1430 | ctrl.id = p->id; | ||
1431 | ctrl.value = p->value; | ||
1432 | if (check_ext_ctrls(&ctrls, 1)) { | ||
1433 | ret = vfd->vidioc_g_ext_ctrls(file, fh, &ctrls); | ||
1434 | if (ret == 0) | ||
1435 | p->value = ctrl.value; | ||
1436 | } | ||
1437 | } else | ||
1438 | break; | ||
1439 | if (!ret) | ||
1440 | dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); | ||
1441 | else | ||
1442 | dbgarg(cmd, "id=0x%x\n", p->id); | ||
1443 | break; | ||
1444 | } | ||
1445 | case VIDIOC_S_CTRL: | ||
1446 | { | ||
1447 | struct v4l2_control *p = arg; | ||
1448 | struct v4l2_ext_controls ctrls; | ||
1449 | struct v4l2_ext_control ctrl; | ||
1450 | |||
1451 | if (!vfd->vidioc_s_ctrl && !vfd->vidioc_s_ext_ctrls) | ||
1452 | break; | ||
1453 | |||
1454 | dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); | ||
1455 | |||
1456 | if (vfd->vidioc_s_ctrl) { | ||
1457 | ret = vfd->vidioc_s_ctrl(file, fh, p); | ||
1458 | break; | ||
1459 | } | ||
1460 | if (!vfd->vidioc_s_ext_ctrls) | ||
1461 | break; | ||
1462 | |||
1463 | ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); | ||
1464 | ctrls.count = 1; | ||
1465 | ctrls.controls = &ctrl; | ||
1466 | ctrl.id = p->id; | ||
1467 | ctrl.value = p->value; | ||
1468 | if (check_ext_ctrls(&ctrls, 1)) | ||
1469 | ret = vfd->vidioc_s_ext_ctrls(file, fh, &ctrls); | ||
1470 | break; | ||
1471 | } | ||
1472 | case VIDIOC_G_EXT_CTRLS: | ||
1473 | { | ||
1474 | struct v4l2_ext_controls *p = arg; | ||
1475 | |||
1476 | p->error_idx = p->count; | ||
1477 | if (!vfd->vidioc_g_ext_ctrls) | ||
1478 | break; | ||
1479 | if (check_ext_ctrls(p, 0)) | ||
1480 | ret = vfd->vidioc_g_ext_ctrls(file, fh, p); | ||
1481 | v4l_print_ext_ctrls(cmd, vfd, p, !ret); | ||
1482 | break; | ||
1483 | } | ||
1484 | case VIDIOC_S_EXT_CTRLS: | ||
1485 | { | ||
1486 | struct v4l2_ext_controls *p = arg; | ||
1487 | |||
1488 | p->error_idx = p->count; | ||
1489 | if (!vfd->vidioc_s_ext_ctrls) | ||
1490 | break; | ||
1491 | v4l_print_ext_ctrls(cmd, vfd, p, 1); | ||
1492 | if (check_ext_ctrls(p, 0)) | ||
1493 | ret = vfd->vidioc_s_ext_ctrls(file, fh, p); | ||
1494 | break; | ||
1495 | } | ||
1496 | case VIDIOC_TRY_EXT_CTRLS: | ||
1497 | { | ||
1498 | struct v4l2_ext_controls *p = arg; | ||
1499 | |||
1500 | p->error_idx = p->count; | ||
1501 | if (!vfd->vidioc_try_ext_ctrls) | ||
1502 | break; | ||
1503 | v4l_print_ext_ctrls(cmd, vfd, p, 1); | ||
1504 | if (check_ext_ctrls(p, 0)) | ||
1505 | ret = vfd->vidioc_try_ext_ctrls(file, fh, p); | ||
1506 | break; | ||
1507 | } | ||
1508 | case VIDIOC_QUERYMENU: | ||
1509 | { | ||
1510 | struct v4l2_querymenu *p = arg; | ||
1511 | |||
1512 | if (!vfd->vidioc_querymenu) | ||
1513 | break; | ||
1514 | ret = vfd->vidioc_querymenu(file, fh, p); | ||
1515 | if (!ret) | ||
1516 | dbgarg(cmd, "id=0x%x, index=%d, name=%s\n", | ||
1517 | p->id, p->index, p->name); | ||
1518 | else | ||
1519 | dbgarg(cmd, "id=0x%x, index=%d\n", | ||
1520 | p->id, p->index); | ||
1521 | break; | ||
1522 | } | ||
1523 | /* --- audio ---------------------------------------------- */ | ||
1524 | case VIDIOC_ENUMAUDIO: | ||
1525 | { | ||
1526 | struct v4l2_audio *p = arg; | ||
1527 | |||
1528 | if (!vfd->vidioc_enumaudio) | ||
1529 | break; | ||
1530 | ret = vfd->vidioc_enumaudio(file, fh, p); | ||
1531 | if (!ret) | ||
1532 | dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " | ||
1533 | "mode=0x%x\n", p->index, p->name, | ||
1534 | p->capability, p->mode); | ||
1535 | else | ||
1536 | dbgarg(cmd, "index=%d\n", p->index); | ||
1537 | break; | ||
1538 | } | ||
1539 | case VIDIOC_G_AUDIO: | ||
1540 | { | ||
1541 | struct v4l2_audio *p = arg; | ||
1542 | __u32 index = p->index; | ||
1543 | |||
1544 | if (!vfd->vidioc_g_audio) | ||
1545 | break; | ||
1546 | |||
1547 | memset(p, 0, sizeof(*p)); | ||
1548 | p->index = index; | ||
1549 | ret = vfd->vidioc_g_audio(file, fh, p); | ||
1550 | if (!ret) | ||
1551 | dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " | ||
1552 | "mode=0x%x\n", p->index, | ||
1553 | p->name, p->capability, p->mode); | ||
1554 | else | ||
1555 | dbgarg(cmd, "index=%d\n", p->index); | ||
1556 | break; | ||
1557 | } | ||
1558 | case VIDIOC_S_AUDIO: | ||
1559 | { | ||
1560 | struct v4l2_audio *p = arg; | ||
1561 | |||
1562 | if (!vfd->vidioc_s_audio) | ||
1563 | break; | ||
1564 | dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " | ||
1565 | "mode=0x%x\n", p->index, p->name, | ||
1566 | p->capability, p->mode); | ||
1567 | ret = vfd->vidioc_s_audio(file, fh, p); | ||
1568 | break; | ||
1569 | } | ||
1570 | case VIDIOC_ENUMAUDOUT: | ||
1571 | { | ||
1572 | struct v4l2_audioout *p=arg; | ||
1573 | |||
1574 | if (!vfd->vidioc_enumaudout) | ||
1575 | break; | ||
1576 | dbgarg(cmd, "Enum for index=%d\n", p->index); | ||
1577 | ret=vfd->vidioc_enumaudout(file, fh, p); | ||
1578 | if (!ret) | ||
1579 | dbgarg2("index=%d, name=%s, capability=%d, " | ||
1580 | "mode=%d\n", p->index, p->name, | ||
1581 | p->capability,p->mode); | ||
1582 | break; | ||
1583 | } | ||
1584 | case VIDIOC_G_AUDOUT: | ||
1585 | { | ||
1586 | struct v4l2_audioout *p=arg; | ||
1587 | |||
1588 | if (!vfd->vidioc_g_audout) | ||
1589 | break; | ||
1590 | dbgarg(cmd, "Enum for index=%d\n", p->index); | ||
1591 | ret=vfd->vidioc_g_audout(file, fh, p); | ||
1592 | if (!ret) | ||
1593 | dbgarg2("index=%d, name=%s, capability=%d, " | ||
1594 | "mode=%d\n", p->index, p->name, | ||
1595 | p->capability,p->mode); | ||
1596 | break; | ||
1597 | } | ||
1598 | case VIDIOC_S_AUDOUT: | ||
1599 | { | ||
1600 | struct v4l2_audioout *p=arg; | ||
1601 | |||
1602 | if (!vfd->vidioc_s_audout) | ||
1603 | break; | ||
1604 | dbgarg(cmd, "index=%d, name=%s, capability=%d, " | ||
1605 | "mode=%d\n", p->index, p->name, | ||
1606 | p->capability,p->mode); | ||
1607 | |||
1608 | ret=vfd->vidioc_s_audout(file, fh, p); | ||
1609 | break; | ||
1610 | } | ||
1611 | case VIDIOC_G_MODULATOR: | ||
1612 | { | ||
1613 | struct v4l2_modulator *p=arg; | ||
1614 | if (!vfd->vidioc_g_modulator) | ||
1615 | break; | ||
1616 | ret=vfd->vidioc_g_modulator(file, fh, p); | ||
1617 | if (!ret) | ||
1618 | dbgarg(cmd, "index=%d, name=%s, " | ||
1619 | "capability=%d, rangelow=%d," | ||
1620 | " rangehigh=%d, txsubchans=%d\n", | ||
1621 | p->index, p->name,p->capability, | ||
1622 | p->rangelow, p->rangehigh, | ||
1623 | p->txsubchans); | ||
1624 | break; | ||
1625 | } | ||
1626 | case VIDIOC_S_MODULATOR: | ||
1627 | { | ||
1628 | struct v4l2_modulator *p=arg; | ||
1629 | if (!vfd->vidioc_s_modulator) | ||
1630 | break; | ||
1631 | dbgarg(cmd, "index=%d, name=%s, capability=%d, " | ||
1632 | "rangelow=%d, rangehigh=%d, txsubchans=%d\n", | ||
1633 | p->index, p->name,p->capability,p->rangelow, | ||
1634 | p->rangehigh,p->txsubchans); | ||
1635 | ret=vfd->vidioc_s_modulator(file, fh, p); | ||
1636 | break; | ||
1637 | } | ||
1638 | case VIDIOC_G_CROP: | ||
1639 | { | ||
1640 | struct v4l2_crop *p=arg; | ||
1641 | if (!vfd->vidioc_g_crop) | ||
1642 | break; | ||
1643 | dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); | ||
1644 | ret=vfd->vidioc_g_crop(file, fh, p); | ||
1645 | if (!ret) { | ||
1646 | dbgrect(vfd, "", &p->c); | ||
1647 | } | ||
1648 | break; | ||
1649 | } | ||
1650 | case VIDIOC_S_CROP: | ||
1651 | { | ||
1652 | struct v4l2_crop *p=arg; | ||
1653 | if (!vfd->vidioc_s_crop) | ||
1654 | break; | ||
1655 | dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); | ||
1656 | dbgrect(vfd, "", &p->c); | ||
1657 | ret=vfd->vidioc_s_crop(file, fh, p); | ||
1658 | break; | ||
1659 | } | ||
1660 | case VIDIOC_CROPCAP: | ||
1661 | { | ||
1662 | struct v4l2_cropcap *p = arg; | ||
1663 | |||
1664 | /*FIXME: Should also show v4l2_fract pixelaspect */ | ||
1665 | if (!vfd->vidioc_cropcap) | ||
1666 | break; | ||
1667 | dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); | ||
1668 | ret = vfd->vidioc_cropcap(file, fh, p); | ||
1669 | if (!ret) { | ||
1670 | dbgrect(vfd, "bounds ", &p->bounds); | ||
1671 | dbgrect(vfd, "defrect ", &p->defrect); | ||
1672 | } | ||
1673 | break; | ||
1674 | } | ||
1675 | case VIDIOC_G_JPEGCOMP: | ||
1676 | { | ||
1677 | struct v4l2_jpegcompression *p=arg; | ||
1678 | if (!vfd->vidioc_g_jpegcomp) | ||
1679 | break; | ||
1680 | ret=vfd->vidioc_g_jpegcomp(file, fh, p); | ||
1681 | if (!ret) | ||
1682 | dbgarg (cmd, "quality=%d, APPn=%d, " | ||
1683 | "APP_len=%d, COM_len=%d, " | ||
1684 | "jpeg_markers=%d\n", | ||
1685 | p->quality,p->APPn,p->APP_len, | ||
1686 | p->COM_len,p->jpeg_markers); | ||
1687 | break; | ||
1688 | } | ||
1689 | case VIDIOC_S_JPEGCOMP: | ||
1690 | { | ||
1691 | struct v4l2_jpegcompression *p=arg; | ||
1692 | if (!vfd->vidioc_g_jpegcomp) | ||
1693 | break; | ||
1694 | dbgarg (cmd, "quality=%d, APPn=%d, APP_len=%d, " | ||
1695 | "COM_len=%d, jpeg_markers=%d\n", | ||
1696 | p->quality,p->APPn,p->APP_len, | ||
1697 | p->COM_len,p->jpeg_markers); | ||
1698 | ret=vfd->vidioc_s_jpegcomp(file, fh, p); | ||
1699 | break; | ||
1700 | } | ||
1701 | case VIDIOC_G_ENC_INDEX: | ||
1702 | { | ||
1703 | struct v4l2_enc_idx *p=arg; | ||
1704 | |||
1705 | if (!vfd->vidioc_g_enc_index) | ||
1706 | break; | ||
1707 | ret=vfd->vidioc_g_enc_index(file, fh, p); | ||
1708 | if (!ret) | ||
1709 | dbgarg (cmd, "entries=%d, entries_cap=%d\n", | ||
1710 | p->entries,p->entries_cap); | ||
1711 | break; | ||
1712 | } | ||
1713 | case VIDIOC_ENCODER_CMD: | ||
1714 | { | ||
1715 | struct v4l2_encoder_cmd *p = arg; | ||
1716 | |||
1717 | if (!vfd->vidioc_encoder_cmd) | ||
1718 | break; | ||
1719 | memset(&p->raw, 0, sizeof(p->raw)); | ||
1720 | ret = vfd->vidioc_encoder_cmd(file, fh, p); | ||
1721 | if (!ret) | ||
1722 | dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); | ||
1723 | break; | ||
1724 | } | ||
1725 | case VIDIOC_TRY_ENCODER_CMD: | ||
1726 | { | ||
1727 | struct v4l2_encoder_cmd *p = arg; | ||
1728 | |||
1729 | if (!vfd->vidioc_try_encoder_cmd) | ||
1730 | break; | ||
1731 | memset(&p->raw, 0, sizeof(p->raw)); | ||
1732 | ret = vfd->vidioc_try_encoder_cmd(file, fh, p); | ||
1733 | if (!ret) | ||
1734 | dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); | ||
1735 | break; | ||
1736 | } | ||
1737 | case VIDIOC_G_PARM: | ||
1738 | { | ||
1739 | struct v4l2_streamparm *p=arg; | ||
1740 | __u32 type=p->type; | ||
1741 | |||
1742 | memset(p,0,sizeof(*p)); | ||
1743 | p->type=type; | ||
1744 | |||
1745 | if (vfd->vidioc_g_parm) { | ||
1746 | ret=vfd->vidioc_g_parm(file, fh, p); | ||
1747 | } else { | ||
1748 | struct v4l2_standard s; | ||
1749 | |||
1750 | if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1751 | return -EINVAL; | ||
1752 | |||
1753 | v4l2_video_std_construct(&s, vfd->current_norm, | ||
1754 | v4l2_norm_to_name(vfd->current_norm)); | ||
1755 | |||
1756 | p->parm.capture.timeperframe = s.frameperiod; | ||
1757 | ret=0; | ||
1758 | } | ||
1759 | |||
1760 | dbgarg (cmd, "type=%d\n", p->type); | ||
1761 | break; | ||
1762 | } | ||
1763 | case VIDIOC_S_PARM: | ||
1764 | { | ||
1765 | struct v4l2_streamparm *p=arg; | ||
1766 | if (!vfd->vidioc_s_parm) | ||
1767 | break; | ||
1768 | dbgarg (cmd, "type=%d\n", p->type); | ||
1769 | ret=vfd->vidioc_s_parm(file, fh, p); | ||
1770 | break; | ||
1771 | } | ||
1772 | case VIDIOC_G_TUNER: | ||
1773 | { | ||
1774 | struct v4l2_tuner *p = arg; | ||
1775 | __u32 index = p->index; | ||
1776 | |||
1777 | if (!vfd->vidioc_g_tuner) | ||
1778 | break; | ||
1779 | |||
1780 | memset(p, 0, sizeof(*p)); | ||
1781 | p->index = index; | ||
1782 | |||
1783 | ret = vfd->vidioc_g_tuner(file, fh, p); | ||
1784 | if (!ret) | ||
1785 | dbgarg(cmd, "index=%d, name=%s, type=%d, " | ||
1786 | "capability=0x%x, rangelow=%d, " | ||
1787 | "rangehigh=%d, signal=%d, afc=%d, " | ||
1788 | "rxsubchans=0x%x, audmode=%d\n", | ||
1789 | p->index, p->name, p->type, | ||
1790 | p->capability, p->rangelow, | ||
1791 | p->rangehigh, p->signal, p->afc, | ||
1792 | p->rxsubchans, p->audmode); | ||
1793 | break; | ||
1794 | } | ||
1795 | case VIDIOC_S_TUNER: | ||
1796 | { | ||
1797 | struct v4l2_tuner *p = arg; | ||
1798 | |||
1799 | if (!vfd->vidioc_s_tuner) | ||
1800 | break; | ||
1801 | dbgarg(cmd, "index=%d, name=%s, type=%d, " | ||
1802 | "capability=0x%x, rangelow=%d, " | ||
1803 | "rangehigh=%d, signal=%d, afc=%d, " | ||
1804 | "rxsubchans=0x%x, audmode=%d\n", | ||
1805 | p->index, p->name, p->type, | ||
1806 | p->capability, p->rangelow, | ||
1807 | p->rangehigh, p->signal, p->afc, | ||
1808 | p->rxsubchans, p->audmode); | ||
1809 | ret = vfd->vidioc_s_tuner(file, fh, p); | ||
1810 | break; | ||
1811 | } | ||
1812 | case VIDIOC_G_FREQUENCY: | ||
1813 | { | ||
1814 | struct v4l2_frequency *p = arg; | ||
1815 | |||
1816 | if (!vfd->vidioc_g_frequency) | ||
1817 | break; | ||
1818 | |||
1819 | memset(p->reserved, 0, sizeof(p->reserved)); | ||
1820 | |||
1821 | ret = vfd->vidioc_g_frequency(file, fh, p); | ||
1822 | if (!ret) | ||
1823 | dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", | ||
1824 | p->tuner, p->type, p->frequency); | ||
1825 | break; | ||
1826 | } | ||
1827 | case VIDIOC_S_FREQUENCY: | ||
1828 | { | ||
1829 | struct v4l2_frequency *p=arg; | ||
1830 | if (!vfd->vidioc_s_frequency) | ||
1831 | break; | ||
1832 | dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n", | ||
1833 | p->tuner,p->type,p->frequency); | ||
1834 | ret=vfd->vidioc_s_frequency(file, fh, p); | ||
1835 | break; | ||
1836 | } | ||
1837 | case VIDIOC_G_SLICED_VBI_CAP: | ||
1838 | { | ||
1839 | struct v4l2_sliced_vbi_cap *p = arg; | ||
1840 | __u32 type = p->type; | ||
1841 | |||
1842 | if (!vfd->vidioc_g_sliced_vbi_cap) | ||
1843 | break; | ||
1844 | memset(p, 0, sizeof(*p)); | ||
1845 | p->type = type; | ||
1846 | dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); | ||
1847 | ret = vfd->vidioc_g_sliced_vbi_cap(file, fh, p); | ||
1848 | if (!ret) | ||
1849 | dbgarg2("service_set=%d\n", p->service_set); | ||
1850 | break; | ||
1851 | } | ||
1852 | case VIDIOC_LOG_STATUS: | ||
1853 | { | ||
1854 | if (!vfd->vidioc_log_status) | ||
1855 | break; | ||
1856 | ret=vfd->vidioc_log_status(file, fh); | ||
1857 | break; | ||
1858 | } | ||
1859 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1860 | case VIDIOC_DBG_G_REGISTER: | ||
1861 | { | ||
1862 | struct v4l2_register *p=arg; | ||
1863 | if (!capable(CAP_SYS_ADMIN)) | ||
1864 | ret=-EPERM; | ||
1865 | else if (vfd->vidioc_g_register) | ||
1866 | ret=vfd->vidioc_g_register(file, fh, p); | ||
1867 | break; | ||
1868 | } | ||
1869 | case VIDIOC_DBG_S_REGISTER: | ||
1870 | { | ||
1871 | struct v4l2_register *p=arg; | ||
1872 | if (!capable(CAP_SYS_ADMIN)) | ||
1873 | ret=-EPERM; | ||
1874 | else if (vfd->vidioc_s_register) | ||
1875 | ret=vfd->vidioc_s_register(file, fh, p); | ||
1876 | break; | ||
1877 | } | ||
1878 | #endif | ||
1879 | case VIDIOC_G_CHIP_IDENT: | ||
1880 | { | ||
1881 | struct v4l2_chip_ident *p=arg; | ||
1882 | if (!vfd->vidioc_g_chip_ident) | ||
1883 | break; | ||
1884 | ret=vfd->vidioc_g_chip_ident(file, fh, p); | ||
1885 | if (!ret) | ||
1886 | dbgarg (cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision); | ||
1887 | break; | ||
1888 | } | ||
1889 | default: | ||
1890 | { | ||
1891 | if (!vfd->vidioc_default) | ||
1892 | break; | ||
1893 | ret = vfd->vidioc_default(file, fh, cmd, arg); | ||
1894 | break; | ||
1895 | } | ||
1896 | case VIDIOC_S_HW_FREQ_SEEK: | ||
1897 | { | ||
1898 | struct v4l2_hw_freq_seek *p = arg; | ||
1899 | if (!vfd->vidioc_s_hw_freq_seek) | ||
1900 | break; | ||
1901 | dbgarg(cmd, | ||
1902 | "tuner=%d, type=%d, seek_upward=%d, wrap_around=%d\n", | ||
1903 | p->tuner, p->type, p->seek_upward, p->wrap_around); | ||
1904 | ret = vfd->vidioc_s_hw_freq_seek(file, fh, p); | ||
1905 | break; | ||
1906 | } | ||
1907 | } /* switch */ | ||
1908 | |||
1909 | if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { | ||
1910 | if (ret < 0) { | ||
1911 | v4l_print_ioctl(vfd->name, cmd); | ||
1912 | printk(KERN_CONT " error %d\n", ret); | ||
1913 | } | ||
1914 | } | ||
1915 | |||
1916 | return ret; | ||
1917 | } | ||
1918 | |||
1919 | int video_ioctl2 (struct inode *inode, struct file *file, | ||
1920 | unsigned int cmd, unsigned long arg) | ||
1921 | { | ||
1922 | char sbuf[128]; | ||
1923 | void *mbuf = NULL; | ||
1924 | void *parg = NULL; | ||
1925 | int err = -EINVAL; | ||
1926 | int is_ext_ctrl; | ||
1927 | size_t ctrls_size = 0; | ||
1928 | void __user *user_ptr = NULL; | ||
1929 | |||
1930 | #ifdef __OLD_VIDIOC_ | ||
1931 | cmd = video_fix_command(cmd); | ||
1932 | #endif | ||
1933 | is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || | ||
1934 | cmd == VIDIOC_TRY_EXT_CTRLS); | ||
1935 | |||
1936 | /* Copy arguments into temp kernel buffer */ | ||
1937 | switch (_IOC_DIR(cmd)) { | ||
1938 | case _IOC_NONE: | ||
1939 | parg = NULL; | ||
1940 | break; | ||
1941 | case _IOC_READ: | ||
1942 | case _IOC_WRITE: | ||
1943 | case (_IOC_WRITE | _IOC_READ): | ||
1944 | if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { | ||
1945 | parg = sbuf; | ||
1946 | } else { | ||
1947 | /* too big to allocate from stack */ | ||
1948 | mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); | ||
1949 | if (NULL == mbuf) | ||
1950 | return -ENOMEM; | ||
1951 | parg = mbuf; | ||
1952 | } | ||
1953 | |||
1954 | err = -EFAULT; | ||
1955 | if (_IOC_DIR(cmd) & _IOC_WRITE) | ||
1956 | if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) | ||
1957 | goto out; | ||
1958 | break; | ||
1959 | } | ||
1960 | |||
1961 | if (is_ext_ctrl) { | ||
1962 | struct v4l2_ext_controls *p = parg; | ||
1963 | |||
1964 | /* In case of an error, tell the caller that it wasn't | ||
1965 | a specific control that caused it. */ | ||
1966 | p->error_idx = p->count; | ||
1967 | user_ptr = (void __user *)p->controls; | ||
1968 | if (p->count) { | ||
1969 | ctrls_size = sizeof(struct v4l2_ext_control) * p->count; | ||
1970 | /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */ | ||
1971 | mbuf = kmalloc(ctrls_size, GFP_KERNEL); | ||
1972 | err = -ENOMEM; | ||
1973 | if (NULL == mbuf) | ||
1974 | goto out_ext_ctrl; | ||
1975 | err = -EFAULT; | ||
1976 | if (copy_from_user(mbuf, user_ptr, ctrls_size)) | ||
1977 | goto out_ext_ctrl; | ||
1978 | p->controls = mbuf; | ||
1979 | } | ||
1980 | } | ||
1981 | |||
1982 | /* Handles IOCTL */ | ||
1983 | err = __video_do_ioctl(inode, file, cmd, parg); | ||
1984 | if (err == -ENOIOCTLCMD) | ||
1985 | err = -EINVAL; | ||
1986 | if (is_ext_ctrl) { | ||
1987 | struct v4l2_ext_controls *p = parg; | ||
1988 | |||
1989 | p->controls = (void *)user_ptr; | ||
1990 | if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size)) | ||
1991 | err = -EFAULT; | ||
1992 | goto out_ext_ctrl; | ||
1993 | } | ||
1994 | if (err < 0) | ||
1995 | goto out; | ||
1996 | |||
1997 | out_ext_ctrl: | ||
1998 | /* Copy results into user buffer */ | ||
1999 | switch (_IOC_DIR(cmd)) | ||
2000 | { | ||
2001 | case _IOC_READ: | ||
2002 | case (_IOC_WRITE | _IOC_READ): | ||
2003 | if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) | ||
2004 | err = -EFAULT; | ||
2005 | break; | ||
2006 | } | ||
2007 | |||
2008 | out: | ||
2009 | kfree(mbuf); | ||
2010 | return err; | ||
2011 | } | ||
2012 | EXPORT_SYMBOL(video_ioctl2); | ||
2013 | |||
2014 | /** | ||
2015 | * get_index - assign stream number based on parent device | ||
2016 | * @vdev: video_device to assign index number to, vdev->dev should be assigned | ||
2017 | * @num: -1 if auto assign, requested number otherwise | ||
2018 | * | ||
2019 | * | ||
2020 | * returns -ENFILE if num is already in use, a free index number if | ||
2021 | * successful. | ||
2022 | */ | ||
2023 | static int get_index(struct video_device *vdev, int num) | ||
2024 | { | ||
2025 | u32 used = 0; | ||
2026 | const int max_index = sizeof(used) * 8 - 1; | ||
2027 | int i; | ||
2028 | |||
2029 | /* Currently a single v4l driver instance cannot create more than | ||
2030 | 32 devices. | ||
2031 | Increase to u64 or an array of u32 if more are needed. */ | ||
2032 | if (num > max_index) { | ||
2033 | printk(KERN_ERR "videodev: %s num is too large\n", __func__); | ||
2034 | return -EINVAL; | ||
2035 | } | ||
2036 | |||
2037 | for (i = 0; i < VIDEO_NUM_DEVICES; i++) { | ||
2038 | if (video_device[i] != NULL && | ||
2039 | video_device[i] != vdev && | ||
2040 | video_device[i]->dev == vdev->dev) { | ||
2041 | used |= 1 << video_device[i]->index; | ||
2042 | } | ||
2043 | } | ||
2044 | |||
2045 | if (num >= 0) { | ||
2046 | if (used & (1 << num)) | ||
2047 | return -ENFILE; | ||
2048 | return num; | ||
2049 | } | ||
2050 | |||
2051 | i = ffz(used); | ||
2052 | return i > max_index ? -ENFILE : i; | ||
2053 | } | ||
2054 | |||
2055 | static const struct file_operations video_fops; | ||
2056 | |||
2057 | int video_register_device(struct video_device *vfd, int type, int nr) | ||
2058 | { | ||
2059 | return video_register_device_index(vfd, type, nr, -1); | ||
2060 | } | ||
2061 | EXPORT_SYMBOL(video_register_device); | ||
2062 | |||
2063 | /** | ||
2064 | * video_register_device - register video4linux devices | ||
2065 | * @vfd: video device structure we want to register | ||
2066 | * @type: type of device to register | ||
2067 | * @nr: which device number (0 == /dev/video0, 1 == /dev/video1, ... | ||
2068 | * -1 == first free) | ||
2069 | * | ||
2070 | * The registration code assigns minor numbers based on the type | ||
2071 | * requested. -ENFILE is returned in all the device slots for this | ||
2072 | * category are full. If not then the minor field is set and the | ||
2073 | * driver initialize function is called (if non %NULL). | ||
2074 | * | ||
2075 | * Zero is returned on success. | ||
2076 | * | ||
2077 | * Valid types are | ||
2078 | * | ||
2079 | * %VFL_TYPE_GRABBER - A frame grabber | ||
2080 | * | ||
2081 | * %VFL_TYPE_VTX - A teletext device | ||
2082 | * | ||
2083 | * %VFL_TYPE_VBI - Vertical blank data (undecoded) | ||
2084 | * | ||
2085 | * %VFL_TYPE_RADIO - A radio card | ||
2086 | */ | ||
2087 | |||
2088 | int video_register_device_index(struct video_device *vfd, int type, int nr, | ||
2089 | int index) | ||
2090 | { | ||
2091 | int i=0; | ||
2092 | int base; | ||
2093 | int end; | ||
2094 | int ret; | ||
2095 | char *name_base; | ||
2096 | |||
2097 | switch(type) | ||
2098 | { | ||
2099 | case VFL_TYPE_GRABBER: | ||
2100 | base=MINOR_VFL_TYPE_GRABBER_MIN; | ||
2101 | end=MINOR_VFL_TYPE_GRABBER_MAX+1; | ||
2102 | name_base = "video"; | ||
2103 | break; | ||
2104 | case VFL_TYPE_VTX: | ||
2105 | base=MINOR_VFL_TYPE_VTX_MIN; | ||
2106 | end=MINOR_VFL_TYPE_VTX_MAX+1; | ||
2107 | name_base = "vtx"; | ||
2108 | break; | ||
2109 | case VFL_TYPE_VBI: | ||
2110 | base=MINOR_VFL_TYPE_VBI_MIN; | ||
2111 | end=MINOR_VFL_TYPE_VBI_MAX+1; | ||
2112 | name_base = "vbi"; | ||
2113 | break; | ||
2114 | case VFL_TYPE_RADIO: | ||
2115 | base=MINOR_VFL_TYPE_RADIO_MIN; | ||
2116 | end=MINOR_VFL_TYPE_RADIO_MAX+1; | ||
2117 | name_base = "radio"; | ||
2118 | break; | ||
2119 | default: | ||
2120 | printk(KERN_ERR "%s called with unknown type: %d\n", | ||
2121 | __func__, type); | ||
2122 | return -1; | ||
2123 | } | ||
2124 | |||
2125 | /* pick a minor number */ | ||
2126 | mutex_lock(&videodev_lock); | ||
2127 | if (nr >= 0 && nr < end-base) { | ||
2128 | /* use the one the driver asked for */ | ||
2129 | i = base+nr; | ||
2130 | if (NULL != video_device[i]) { | ||
2131 | mutex_unlock(&videodev_lock); | ||
2132 | return -ENFILE; | ||
2133 | } | ||
2134 | } else { | ||
2135 | /* use first free */ | ||
2136 | for(i=base;i<end;i++) | ||
2137 | if (NULL == video_device[i]) | ||
2138 | break; | ||
2139 | if (i == end) { | ||
2140 | mutex_unlock(&videodev_lock); | ||
2141 | return -ENFILE; | ||
2142 | } | ||
2143 | } | ||
2144 | video_device[i]=vfd; | ||
2145 | vfd->minor=i; | ||
2146 | |||
2147 | ret = get_index(vfd, index); | ||
2148 | vfd->index = ret; | ||
2149 | |||
2150 | mutex_unlock(&videodev_lock); | ||
2151 | |||
2152 | if (ret < 0) { | ||
2153 | printk(KERN_ERR "%s: get_index failed\n", __func__); | ||
2154 | goto fail_minor; | ||
2155 | } | ||
2156 | |||
2157 | mutex_init(&vfd->lock); | ||
2158 | |||
2159 | /* sysfs class */ | ||
2160 | memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev)); | ||
2161 | vfd->class_dev.class = &video_class; | ||
2162 | vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); | ||
2163 | if (vfd->dev) | ||
2164 | vfd->class_dev.parent = vfd->dev; | ||
2165 | sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base); | ||
2166 | ret = device_register(&vfd->class_dev); | ||
2167 | if (ret < 0) { | ||
2168 | printk(KERN_ERR "%s: device_register failed\n", __func__); | ||
2169 | goto fail_minor; | ||
2170 | } | ||
2171 | |||
2172 | #if 1 | ||
2173 | /* needed until all drivers are fixed */ | ||
2174 | if (!vfd->release) | ||
2175 | printk(KERN_WARNING "videodev: \"%s\" has no release callback. " | ||
2176 | "Please fix your driver for proper sysfs support, see " | ||
2177 | "http://lwn.net/Articles/36850/\n", vfd->name); | ||
2178 | #endif | ||
2179 | return 0; | ||
2180 | |||
2181 | fail_minor: | ||
2182 | mutex_lock(&videodev_lock); | ||
2183 | video_device[vfd->minor] = NULL; | ||
2184 | vfd->minor = -1; | ||
2185 | mutex_unlock(&videodev_lock); | ||
2186 | return ret; | ||
2187 | } | ||
2188 | EXPORT_SYMBOL(video_register_device_index); | ||
2189 | |||
2190 | /** | ||
2191 | * video_unregister_device - unregister a video4linux device | ||
2192 | * @vfd: the device to unregister | ||
2193 | * | ||
2194 | * This unregisters the passed device and deassigns the minor | ||
2195 | * number. Future open calls will be met with errors. | ||
2196 | */ | ||
2197 | |||
2198 | void video_unregister_device(struct video_device *vfd) | ||
2199 | { | ||
2200 | mutex_lock(&videodev_lock); | ||
2201 | if(video_device[vfd->minor]!=vfd) | ||
2202 | panic("videodev: bad unregister"); | ||
2203 | |||
2204 | video_device[vfd->minor]=NULL; | ||
2205 | device_unregister(&vfd->class_dev); | ||
2206 | mutex_unlock(&videodev_lock); | ||
2207 | } | ||
2208 | EXPORT_SYMBOL(video_unregister_device); | ||
2209 | |||
2210 | /* | ||
2211 | * Video fs operations | ||
2212 | */ | ||
2213 | static const struct file_operations video_fops= | ||
2214 | { | ||
2215 | .owner = THIS_MODULE, | ||
2216 | .llseek = no_llseek, | ||
2217 | .open = video_open, | ||
2218 | }; | ||
2219 | |||
2220 | /* | ||
2221 | * Initialise video for linux | ||
2222 | */ | ||
2223 | |||
2224 | static int __init videodev_init(void) | ||
2225 | { | ||
2226 | int ret; | ||
2227 | |||
2228 | printk(KERN_INFO "Linux video capture interface: v2.00\n"); | ||
2229 | if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) { | ||
2230 | printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR); | ||
2231 | return -EIO; | ||
2232 | } | ||
2233 | |||
2234 | ret = class_register(&video_class); | ||
2235 | if (ret < 0) { | ||
2236 | unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME); | ||
2237 | printk(KERN_WARNING "video_dev: class_register failed\n"); | ||
2238 | return -EIO; | ||
2239 | } | ||
2240 | |||
2241 | return 0; | ||
2242 | } | ||
2243 | |||
2244 | static void __exit videodev_exit(void) | ||
2245 | { | ||
2246 | class_unregister(&video_class); | ||
2247 | unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME); | ||
2248 | } | ||
2249 | |||
2250 | module_init(videodev_init) | ||
2251 | module_exit(videodev_exit) | ||
2252 | |||
2253 | MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>"); | ||
2254 | MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2"); | ||
2255 | MODULE_LICENSE("GPL"); | ||
2256 | |||
2257 | |||
2258 | /* | ||
2259 | * Local variables: | ||
2260 | * c-basic-offset: 8 | ||
2261 | * End: | ||
2262 | */ | ||