blob: d54ca6c802dba873dc83b4ae854745580b6cede3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03002 * Video capture interface for Linux version 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03004 * A generic video device interface for the LINUX operating system
5 * using a set of device structures/vectors for low level operations.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 *
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03007 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 *
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030012 * Authors: Alan Cox, <alan@redhat.com> (version 1)
13 * Mauro Carvalho Chehab <mchehab@infradead.org> (version 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 *
15 * Fixes: 20000516 Claudio Matsuoka <claudio@conectiva.com>
16 * - Added procfs support
17 */
18
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030019#define dbgarg(cmd, fmt, arg...) \
Hans Verkuil21575c12008-06-22 11:55:09 -030020 do { \
21 if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \
Mauro Carvalho Chehab5e28e002008-04-13 15:06:24 -030022 printk(KERN_DEBUG "%s: ", vfd->name); \
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030023 v4l_printk_ioctl(cmd); \
Mauro Carvalho Chehab5e28e002008-04-13 15:06:24 -030024 printk(" " fmt, ## arg); \
Hans Verkuil21575c12008-06-22 11:55:09 -030025 } \
26 } while (0)
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030027
28#define dbgarg2(fmt, arg...) \
Hans Verkuil21575c12008-06-22 11:55:09 -030029 do { \
30 if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \
31 printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);\
32 } while (0)
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030033
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/module.h>
35#include <linux/types.h>
36#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#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>
Jonathan Corbet66064702008-05-16 14:28:31 -060043#include <linux/smp_lock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <asm/uaccess.h>
45#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030047#define __OLD_VIDIOC_ /* To allow fixing old calls*/
48#include <linux/videodev2.h>
49
50#ifdef CONFIG_VIDEO_V4L1
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <linux/videodev.h>
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030052#endif
53#include <media/v4l2-common.h>
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -030054#include <linux/video_decoder.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
56#define VIDEO_NUM_DEVICES 256
57#define VIDEO_NAME "video4linux"
58
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -030059struct std_descr {
60 v4l2_std_id std;
61 const char *descr;
62};
63
64static 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
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -030098/* video4linux standard ID conversion to standard name
99 */
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -0300100const char *v4l2_norm_to_name(v4l2_std_id id)
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300101{
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300102 u32 myid = id;
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -0300103 int i;
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300104
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
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -0300111 for (i = 0; standards[i].std; i++)
112 if (myid == standards[i].std)
113 break;
114 return standards[i].descr;
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300115}
116EXPORT_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. */
120int v4l2_video_std_construct(struct v4l2_standard *vs,
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -0300121 int id, const char *name)
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300122{
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}
140EXPORT_SYMBOL(v4l2_video_std_construct);
141
142/* ----------------------------------------------------------------- */
143/* some arrays for pretty-printing debug messages of enum types */
144
Hans Verkuil21575c12008-06-22 11:55:09 -0300145const char *v4l2_field_names[] = {
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300146 [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};
157EXPORT_SYMBOL(v4l2_field_names);
158
Hans Verkuil21575c12008-06-22 11:55:09 -0300159const 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",
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300163 [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",
Hans Verkuil21575c12008-06-22 11:55:09 -0300167 [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "vid-out-overlay",
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300168};
169EXPORT_SYMBOL(v4l2_type_names);
170
Hans Verkuil21575c12008-06-22 11:55:09 -0300171static const char *v4l2_memory_names[] = {
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300172 [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
184static 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
218static 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",
Tobias Lorenz1d0ba5f2008-05-26 18:40:46 -0300285 [_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)] = "VIDIOC_S_HW_FREQ_SEEK",
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300286#endif
287};
288#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
289
290static 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 */
331void v4l_printk_ioctl(unsigned int cmd)
332{
Mauro Carvalho Chehab5e28e002008-04-13 15:06:24 -0300333 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 }
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300362
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 }
Mauro Carvalho Chehab5e28e002008-04-13 15:06:24 -0300370 printk("%s ioctl '%c', dir=%s, #%d (0x%08x)",
371 type, _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd);
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300372}
373EXPORT_SYMBOL(v4l_printk_ioctl);
374
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375/*
376 * sysfs stuff
377 */
378
brandon@ifup.org539a7552008-06-20 22:58:53 -0300379static 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
Kay Sievers54bd5b62007-10-08 16:26:13 -0300387static ssize_t show_name(struct device *cd,
388 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389{
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300390 struct video_device *vfd = container_of(cd, struct video_device,
Kay Sievers54bd5b62007-10-08 16:26:13 -0300391 class_dev);
392 return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393}
394
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395struct video_device *video_device_alloc(void)
396{
397 struct video_device *vfd;
398
Panagiotis Issaris74081872006-01-11 19:40:56 -0200399 vfd = kzalloc(sizeof(*vfd),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 return vfd;
401}
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300402EXPORT_SYMBOL(video_device_alloc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
404void video_device_release(struct video_device *vfd)
405{
406 kfree(vfd);
407}
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300408EXPORT_SYMBOL(video_device_release);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
Kay Sievers54bd5b62007-10-08 16:26:13 -0300410static void video_release(struct device *cd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
Trent Piephobde00cc2007-10-08 18:36:21 -0300412 struct video_device *vfd = container_of(cd, struct video_device,
413 class_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
Mauro Carvalho Chehabd21838d2006-01-09 15:25:21 -0200415#if 1
Michael Krufky50c25ff2006-01-09 15:25:34 -0200416 /* needed until all drivers are fixed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 if (!vfd->release)
418 return;
419#endif
420 vfd->release(vfd);
421}
422
Kay Sievers54bd5b62007-10-08 16:26:13 -0300423static struct device_attribute video_device_attrs[] = {
424 __ATTR(name, S_IRUGO, show_name, NULL),
brandon@ifup.org539a7552008-06-20 22:58:53 -0300425 __ATTR(index, S_IRUGO, show_index, NULL),
Kay Sievers54bd5b62007-10-08 16:26:13 -0300426 __ATTR_NULL
427};
428
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429static struct class video_class = {
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800430 .name = VIDEO_NAME,
Kay Sievers54bd5b62007-10-08 16:26:13 -0300431 .dev_attrs = video_device_attrs,
432 .dev_release = video_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433};
434
435/*
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800436 * Active devices
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800438
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439static struct video_device *video_device[VIDEO_NUM_DEVICES];
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200440static DEFINE_MUTEX(videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
442struct video_device* video_devdata(struct file *file)
443{
Josef Sipek723731b2006-12-08 02:37:47 -0800444 return video_device[iminor(file->f_path.dentry->d_inode)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445}
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300446EXPORT_SYMBOL(video_devdata);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447
448/*
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300449 * Open a video device - FIXME: Obsoleted
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 */
451static 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;
Arjan van de Ven99ac48f2006-03-28 01:56:41 -0800456 const struct file_operations *old_fops;
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800457
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 if(minor>=VIDEO_NUM_DEVICES)
459 return -ENODEV;
Jonathan Corbet66064702008-05-16 14:28:31 -0600460 lock_kernel();
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200461 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 vfl=video_device[minor];
463 if(vfl==NULL) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200464 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 request_module("char-major-%d-%d", VIDEO_MAJOR, minor);
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200466 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 vfl=video_device[minor];
468 if (vfl==NULL) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200469 mutex_unlock(&videodev_lock);
Jonathan Corbet66064702008-05-16 14:28:31 -0600470 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 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);
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200483 mutex_unlock(&videodev_lock);
Jonathan Corbet66064702008-05-16 14:28:31 -0600484 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 return err;
486}
487
488/*
489 * helper function -- handles userspace copying for ioctl arguments
490 */
491
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300492#ifdef __OLD_VIDIOC_
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493static unsigned int
494video_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}
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300518#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300520/*
521 * Obsolete usercopy function - Should be removed soon
522 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523int
524video_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;
Hans Verkuil05976912006-06-18 13:43:28 -0300533 int is_ext_ctrl;
534 size_t ctrls_size = 0;
535 void __user *user_ptr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300537#ifdef __OLD_VIDIOC_
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 cmd = video_fix_command(cmd);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300539#endif
Hans Verkuil05976912006-06-18 13:43:28 -0300540 is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
541 cmd == VIDIOC_TRY_EXT_CTRLS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
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 }
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800560
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 err = -EFAULT;
562 if (_IOC_DIR(cmd) & _IOC_WRITE)
Hans Verkuil05976912006-06-18 13:43:28 -0300563 if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 goto out;
565 break;
566 }
Hans Verkuil05976912006-06-18 13:43:28 -0300567 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
588 /* call driver */
589 err = func(inode, file, cmd, parg);
590 if (err == -ENOIOCTLCMD)
591 err = -EINVAL;
Hans Verkuil05976912006-06-18 13:43:28 -0300592 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 if (err < 0)
601 goto out;
602
Hans Verkuil05976912006-06-18 13:43:28 -0300603out_ext_ctrl:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 /* 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
614out:
Jesper Juhl2ea75332005-11-07 01:01:31 -0800615 kfree(mbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 return err;
617}
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300618EXPORT_SYMBOL(video_usercopy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
620/*
621 * open/release helper functions -- handle exclusive opens
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300622 * Should be removed soon
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 */
624int video_exclusive_open(struct inode *inode, struct file *file)
625{
626 struct video_device *vfl = video_devdata(file);
627 int retval = 0;
628
Ingo Molnar3593cab2006-02-07 06:49:14 -0200629 mutex_lock(&vfl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 if (vfl->users) {
631 retval = -EBUSY;
632 } else {
633 vfl->users++;
634 }
Ingo Molnar3593cab2006-02-07 06:49:14 -0200635 mutex_unlock(&vfl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 return retval;
637}
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300638EXPORT_SYMBOL(video_exclusive_open);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
640int video_exclusive_release(struct inode *inode, struct file *file)
641{
642 struct video_device *vfl = video_devdata(file);
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800643
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 vfl->users--;
645 return 0;
646}
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300647EXPORT_SYMBOL(video_exclusive_release);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300648
649static 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, "
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300656 "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n",
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300657 (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,
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300662 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),
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300666 p->m.userptr, p->length);
Hans Verkuil21575c12008-06-22 11:55:09 -0300667 dbgarg2("timecode=%02d:%02d:%02d type=%d, "
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300668 "flags=0x%08d, frames=%d, userbits=0x%08x\n",
669 tc->hours,tc->minutes,tc->seconds,
Mauro Carvalho Chehabc18cb012006-06-23 07:05:22 -0300670 tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300671}
672
673static inline void dbgrect(struct video_device *vfd, char *s,
674 struct v4l2_rect *r)
675{
Hans Verkuil21575c12008-06-22 11:55:09 -0300676 dbgarg2("%sRect start at %dx%d, size=%dx%d\n", s, r->left, r->top,
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300677 r->width, r->height);
678};
679
680static inline void v4l_print_pix_fmt (struct video_device *vfd,
681 struct v4l2_pix_format *fmt)
682{
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300683 dbgarg2 ("width=%d, height=%d, format=%c%c%c%c, field=%s, "
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300684 "bytesperline=%d sizeimage=%d, colorspace=%d\n",
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300685 fmt->width,fmt->height,
686 (fmt->pixelformat & 0xff),
687 (fmt->pixelformat >> 8) & 0xff,
688 (fmt->pixelformat >> 16) & 0xff,
689 (fmt->pixelformat >> 24) & 0xff,
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300690 prt_names(fmt->field, v4l2_field_names),
691 fmt->bytesperline, fmt->sizeimage, fmt->colorspace);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300692};
693
Hans Verkuil21575c12008-06-22 11:55:09 -0300694static 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
Hans Verkuil6264c802008-06-25 06:54:05 -0300713static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
Hans Verkuild8799b42008-06-25 06:29:01 -0300714{
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
Hans Verkuil6264c802008-06-25 06:54:05 -0300724 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)
Hans Verkuild8799b42008-06-25 06:29:01 -0300729 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}
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300739
740static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type)
741{
742 switch (type) {
743 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
Hans Verkuil78b526a2008-05-28 12:16:41 -0300744 if (vfd->vidioc_try_fmt_vid_cap)
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300745 return (0);
746 break;
747 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Hans Verkuil78b526a2008-05-28 12:16:41 -0300748 if (vfd->vidioc_try_fmt_vid_overlay)
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300749 return (0);
750 break;
751 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
Hans Verkuil78b526a2008-05-28 12:16:41 -0300752 if (vfd->vidioc_try_fmt_vid_out)
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300753 return (0);
754 break;
Hans Verkuilb2787842007-04-27 12:31:02 -0300755 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
Hans Verkuil78b526a2008-05-28 12:16:41 -0300756 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)
Hans Verkuilb2787842007-04-27 12:31:02 -0300773 return (0);
774 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300775 case V4L2_BUF_TYPE_PRIVATE:
776 if (vfd->vidioc_try_fmt_type_private)
777 return (0);
778 break;
779 }
780 return (-EINVAL);
781}
782
783static 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) &&
Jiri Slaby57e45b32007-05-07 10:55:49 -0300791 !(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) {
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300792 v4l_print_ioctl(vfd->name, cmd);
Mauro Carvalho Chehabd6849652008-04-13 15:07:16 -0300793 printk("\n");
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300794 }
795
Sam Revitch1088b132007-05-01 08:46:30 -0300796#ifdef CONFIG_VIDEO_V4L1_COMPAT
Mauro Carvalho Chehab452c0fb2007-05-01 08:55:00 -0300797 /***********************************************************
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
Sam Revitch1088b132007-05-01 08:46:30 -0300803 /* --- streaming capture ------------------------------------- */
804 if (cmd == VIDIOCGMBUF) {
805 struct video_mbuf *p=arg;
806
Mariusz Kozlowski473c6532007-08-06 18:05:35 -0300807 memset(p, 0, sizeof(*p));
Sam Revitch1088b132007-05-01 08:46:30 -0300808
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 }
Sam Revitch1088b132007-05-01 08:46:30 -0300818
Mauro Carvalho Chehab452c0fb2007-05-01 08:55:00 -0300819 /********************************************************
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 ********************************************************/
Mauro Carvalho Chehab207705c2006-11-20 12:13:25 -0300825 if (_IOC_TYPE(cmd)=='v')
826 return v4l_compat_translate_ioctl(inode,file,cmd,arg,
827 __video_do_ioctl);
Mauro Carvalho Chehab452c0fb2007-05-01 08:55:00 -0300828#endif
Mauro Carvalho Chehab207705c2006-11-20 12:13:25 -0300829
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300830 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:
Hans Verkuil78b526a2008-05-28 12:16:41 -0300889 if (vfd->vidioc_enum_fmt_vid_cap)
890 ret = vfd->vidioc_enum_fmt_vid_cap(file, fh, f);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300891 break;
892 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Hans Verkuil78b526a2008-05-28 12:16:41 -0300893 if (vfd->vidioc_enum_fmt_vid_overlay)
894 ret = vfd->vidioc_enum_fmt_vid_overlay(file,
895 fh, f);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300896 break;
Hans Verkuil78b526a2008-05-28 12:16:41 -0300897#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. */
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300902 case V4L2_BUF_TYPE_VBI_CAPTURE:
Hans Verkuil78b526a2008-05-28 12:16:41 -0300903 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 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300907 break;
Hans Verkuil78b526a2008-05-28 12:16:41 -0300908#endif
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300909 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
Hans Verkuil78b526a2008-05-28 12:16:41 -0300910 if (vfd->vidioc_enum_fmt_vid_out)
911 ret = vfd->vidioc_enum_fmt_vid_out(file, fh, f);
Hans Verkuilb2787842007-04-27 12:31:02 -0300912 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300913 case V4L2_BUF_TYPE_PRIVATE:
914 if (vfd->vidioc_enum_fmt_type_private)
Hans Verkuil78b526a2008-05-28 12:16:41 -0300915 ret = vfd->vidioc_enum_fmt_type_private(file,
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300916 fh, f);
917 break;
Hans Verkuil78b526a2008-05-28 12:16:41 -0300918 default:
919 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300920 }
921 if (!ret)
922 dbgarg (cmd, "index=%d, type=%d, flags=%d, "
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300923 "pixelformat=%c%c%c%c, description='%s'\n",
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300924 f->index, f->type, f->flags,
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300925 (f->pixelformat & 0xff),
926 (f->pixelformat >> 8) & 0xff,
927 (f->pixelformat >> 16) & 0xff,
928 (f->pixelformat >> 24) & 0xff,
929 f->description);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300930 break;
931 }
932 case VIDIOC_G_FMT:
933 {
934 struct v4l2_format *f = (struct v4l2_format *)arg;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300935
Hans Verkuil7bb846a2008-05-27 21:32:08 -0300936 memset(f->fmt.raw_data, 0, sizeof(f->fmt.raw_data));
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300937
938 /* FIXME: Should be one dump per type */
Hans Verkuil7bb846a2008-05-27 21:32:08 -0300939 dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300940
Hans Verkuil7bb846a2008-05-27 21:32:08 -0300941 switch (f->type) {
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300942 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
Hans Verkuil78b526a2008-05-28 12:16:41 -0300943 if (vfd->vidioc_g_fmt_vid_cap)
944 ret = vfd->vidioc_g_fmt_vid_cap(file, fh, f);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300945 if (!ret)
Hans Verkuil21575c12008-06-22 11:55:09 -0300946 v4l_print_pix_fmt(vfd, &f->fmt.pix);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300947 break;
948 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Hans Verkuil78b526a2008-05-28 12:16:41 -0300949 if (vfd->vidioc_g_fmt_vid_overlay)
950 ret = vfd->vidioc_g_fmt_vid_overlay(file,
951 fh, f);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300952 break;
953 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
Hans Verkuil78b526a2008-05-28 12:16:41 -0300954 if (vfd->vidioc_g_fmt_vid_out)
955 ret = vfd->vidioc_g_fmt_vid_out(file, fh, f);
Hans Verkuil21575c12008-06-22 11:55:09 -0300956 if (!ret)
957 v4l_print_pix_fmt(vfd, &f->fmt.pix);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300958 break;
Hans Verkuilb2787842007-04-27 12:31:02 -0300959 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
Hans Verkuil78b526a2008-05-28 12:16:41 -0300960 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);
Hans Verkuilb2787842007-04-27 12:31:02 -0300967 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300968 case V4L2_BUF_TYPE_VBI_OUTPUT:
Hans Verkuil78b526a2008-05-28 12:16:41 -0300969 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);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300981 break;
982 case V4L2_BUF_TYPE_PRIVATE:
983 if (vfd->vidioc_g_fmt_type_private)
Hans Verkuil78b526a2008-05-28 12:16:41 -0300984 ret = vfd->vidioc_g_fmt_type_private(file,
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300985 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 */
Hans Verkuil21575c12008-06-22 11:55:09 -0300996 dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300997
998 switch (f->type) {
999 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
Hans Verkuil21575c12008-06-22 11:55:09 -03001000 v4l_print_pix_fmt(vfd, &f->fmt.pix);
Hans Verkuil78b526a2008-05-28 12:16:41 -03001001 if (vfd->vidioc_s_fmt_vid_cap)
1002 ret = vfd->vidioc_s_fmt_vid_cap(file, fh, f);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001003 break;
1004 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Hans Verkuil78b526a2008-05-28 12:16:41 -03001005 if (vfd->vidioc_s_fmt_vid_overlay)
1006 ret = vfd->vidioc_s_fmt_vid_overlay(file,
1007 fh, f);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001008 break;
1009 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
Hans Verkuil21575c12008-06-22 11:55:09 -03001010 v4l_print_pix_fmt(vfd, &f->fmt.pix);
Hans Verkuil78b526a2008-05-28 12:16:41 -03001011 if (vfd->vidioc_s_fmt_vid_out)
1012 ret = vfd->vidioc_s_fmt_vid_out(file, fh, f);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001013 break;
Hans Verkuilb2787842007-04-27 12:31:02 -03001014 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
Hans Verkuil78b526a2008-05-28 12:16:41 -03001015 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);
Hans Verkuilb2787842007-04-27 12:31:02 -03001022 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001023 case V4L2_BUF_TYPE_VBI_OUTPUT:
Hans Verkuil78b526a2008-05-28 12:16:41 -03001024 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);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001036 break;
1037 case V4L2_BUF_TYPE_PRIVATE:
1038 if (vfd->vidioc_s_fmt_type_private)
Hans Verkuil78b526a2008-05-28 12:16:41 -03001039 ret = vfd->vidioc_s_fmt_type_private(file,
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001040 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,
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -03001051 v4l2_type_names));
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001052 switch (f->type) {
1053 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
Hans Verkuil78b526a2008-05-28 12:16:41 -03001054 if (vfd->vidioc_try_fmt_vid_cap)
1055 ret = vfd->vidioc_try_fmt_vid_cap(file, fh, f);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001056 if (!ret)
Hans Verkuil21575c12008-06-22 11:55:09 -03001057 v4l_print_pix_fmt(vfd, &f->fmt.pix);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001058 break;
1059 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Hans Verkuil78b526a2008-05-28 12:16:41 -03001060 if (vfd->vidioc_try_fmt_vid_overlay)
1061 ret = vfd->vidioc_try_fmt_vid_overlay(file,
1062 fh, f);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001063 break;
1064 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
Hans Verkuil78b526a2008-05-28 12:16:41 -03001065 if (vfd->vidioc_try_fmt_vid_out)
1066 ret = vfd->vidioc_try_fmt_vid_out(file, fh, f);
Hans Verkuil21575c12008-06-22 11:55:09 -03001067 if (!ret)
1068 v4l_print_pix_fmt(vfd, &f->fmt.pix);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001069 break;
Hans Verkuilb2787842007-04-27 12:31:02 -03001070 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
Hans Verkuil78b526a2008-05-28 12:16:41 -03001071 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);
Hans Verkuilb2787842007-04-27 12:31:02 -03001078 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001079 case V4L2_BUF_TYPE_VBI_OUTPUT:
Hans Verkuil78b526a2008-05-28 12:16:41 -03001080 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,
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001091 fh, f);
1092 break;
1093 case V4L2_BUF_TYPE_PRIVATE:
1094 if (vfd->vidioc_try_fmt_type_private)
Hans Verkuil78b526a2008-05-28 12:16:41 -03001095 ret = vfd->vidioc_try_fmt_type_private(file,
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001096 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,
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -03001119 prt_names(p->type, v4l2_type_names),
1120 prt_names(p->memory, v4l2_memory_names));
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001121 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;
Sascha Hauerc93a5c32006-09-11 09:49:19 -03001156 if (!vfd->vidioc_dqbuf)
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001157 break;
1158 ret = check_fmt (vfd, p->type);
1159 if (ret)
1160 break;
1161
Sascha Hauerc93a5c32006-09-11 09:49:19 -03001162 ret=vfd->vidioc_dqbuf(file, fh, p);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001163 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 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001177 case VIDIOC_G_FBUF:
1178 {
Hans Verkuil21575c12008-06-22 11:55:09 -03001179 struct v4l2_framebuffer *p = arg;
1180
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001181 if (!vfd->vidioc_g_fbuf)
1182 break;
Hans Verkuil21575c12008-06-22 11:55:09 -03001183 ret = vfd->vidioc_g_fbuf(file, fh, arg);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001184 if (!ret) {
Hans Verkuil21575c12008-06-22 11:55:09 -03001185 dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n",
1186 p->capability, p->flags,
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001187 (unsigned long)p->base);
Hans Verkuil21575c12008-06-22 11:55:09 -03001188 v4l_print_pix_fmt(vfd, &p->fmt);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001189 }
1190 break;
1191 }
1192 case VIDIOC_S_FBUF:
1193 {
Hans Verkuil21575c12008-06-22 11:55:09 -03001194 struct v4l2_framebuffer *p = arg;
1195
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001196 if (!vfd->vidioc_s_fbuf)
1197 break;
Hans Verkuil21575c12008-06-22 11:55:09 -03001198 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);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001202 break;
1203 }
1204 case VIDIOC_STREAMON:
1205 {
1206 enum v4l2_buf_type i = *(int *)arg;
1207 if (!vfd->vidioc_streamon)
1208 break;
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -03001209 dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names));
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001210 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;
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -03001219 dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names));
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001220 ret=vfd->vidioc_streamoff(file, fh, i);
1221 break;
1222 }
1223 /* ---------- tv norms ---------- */
1224 case VIDIOC_ENUMSTD:
1225 {
1226 struct v4l2_standard *p = arg;
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -03001227 v4l2_std_id id = vfd->tvnorms, curr_id = 0;
1228 unsigned int index = p->index, i, j = 0;
1229 const char *descr = "";
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001230
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -03001231 /* 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)
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001241 break;
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -03001242 if (curr_id != V4L2_STD_PAL &&
1243 curr_id != V4L2_STD_SECAM &&
1244 curr_id != V4L2_STD_NTSC)
1245 id &= ~curr_id;
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001246 }
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -03001247 if (i <= index)
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001248 return -EINVAL;
1249
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -03001250 v4l2_video_std_construct(p, curr_id, descr);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001251 p->index = index;
1252
Hans Verkuil21575c12008-06-22 11:55:09 -03001253 dbgarg(cmd, "index=%d, id=0x%Lx, name=%s, fps=%d/%d, "
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001254 "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
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -03001260 ret = 0;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001261 break;
1262 }
1263 case VIDIOC_G_STD:
1264 {
1265 v4l2_std_id *id = arg;
1266
Hans Verkuilb2de2312008-05-28 08:27:00 -03001267 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;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001273
Hans Verkuilb2de2312008-05-28 08:27:00 -03001274 if (!ret)
Hans Verkuil21575c12008-06-22 11:55:09 -03001275 dbgarg(cmd, "std=0x%08Lx\n", (long long unsigned)*id);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001276 break;
1277 }
1278 case VIDIOC_S_STD:
1279 {
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001280 v4l2_std_id *id = arg,norm;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001281
Hans Verkuil21575c12008-06-22 11:55:09 -03001282 dbgarg(cmd, "std=%08Lx\n", (long long unsigned)*id);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001283
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001284 norm = (*id) & vfd->tvnorms;
1285 if ( vfd->tvnorms && !norm) /* Check if std is supported */
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001286 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001287
1288 /* Calls the specific handler */
1289 if (vfd->vidioc_s_std)
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001290 ret=vfd->vidioc_s_std(file, fh, &norm);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001291 else
1292 ret=-EINVAL;
1293
1294 /* Updates standard information */
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001295 if (ret>=0)
1296 vfd->current_norm=norm;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001297
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)
Mauro Carvalho Chehab63736782007-12-13 06:34:12 -03001308 dbgarg (cmd, "detected std=%08Lx\n",
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001309 (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, "
Mauro Carvalho Chehab63736782007-12-13 06:34:12 -03001328 "tuner=%d, std=%08Lx, status=%d\n",
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001329 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 ---------- */
Hans Verkuil0e3bd2b2008-05-27 22:31:43 -03001358 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, "
Hans Verkuil21575c12008-06-22 11:55:09 -03001371 "audioset=0x%x, "
1372 "modulator=%d, std=0x%08Lx\n",
Hans Verkuil0e3bd2b2008-05-27 22:31:43 -03001373 p->index, p->name, p->type, p->audioset,
1374 p->modulator, (unsigned long long)p->std);
1375 break;
1376 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001377 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 {
Hans Verkuil21575c12008-06-22 11:55:09 -03001402 struct v4l2_queryctrl *p = arg;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001403
1404 if (!vfd->vidioc_queryctrl)
1405 break;
Hans Verkuil21575c12008-06-22 11:55:09 -03001406 ret = vfd->vidioc_queryctrl(file, fh, p);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001407 if (!ret)
Hans Verkuil21575c12008-06-22 11:55:09 -03001408 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);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001415 break;
1416 }
1417 case VIDIOC_G_CTRL:
1418 {
1419 struct v4l2_control *p = arg;
1420
Hans Verkuild8799b42008-06-25 06:29:01 -03001421 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;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001426
Hans Verkuild8799b42008-06-25 06:29:01 -03001427 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;
Hans Verkuil6264c802008-06-25 06:54:05 -03001432 if (check_ext_ctrls(&ctrls, 1)) {
Hans Verkuild8799b42008-06-25 06:29:01 -03001433 ret = vfd->vidioc_g_ext_ctrls(file, fh, &ctrls);
1434 if (ret == 0)
1435 p->value = ctrl.value;
1436 }
1437 } else
1438 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001439 if (!ret)
Hans Verkuil21575c12008-06-22 11:55:09 -03001440 dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value);
1441 else
1442 dbgarg(cmd, "id=0x%x\n", p->id);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001443 break;
1444 }
1445 case VIDIOC_S_CTRL:
1446 {
1447 struct v4l2_control *p = arg;
Hans Verkuild8799b42008-06-25 06:29:01 -03001448 struct v4l2_ext_controls ctrls;
1449 struct v4l2_ext_control ctrl;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001450
Hans Verkuild8799b42008-06-25 06:29:01 -03001451 if (!vfd->vidioc_s_ctrl && !vfd->vidioc_s_ext_ctrls)
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001452 break;
Hans Verkuild8799b42008-06-25 06:29:01 -03001453
Hans Verkuil21575c12008-06-22 11:55:09 -03001454 dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001455
Hans Verkuild8799b42008-06-25 06:29:01 -03001456 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;
Hans Verkuil6264c802008-06-25 06:54:05 -03001468 if (check_ext_ctrls(&ctrls, 1))
Hans Verkuild8799b42008-06-25 06:29:01 -03001469 ret = vfd->vidioc_s_ext_ctrls(file, fh, &ctrls);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001470 break;
1471 }
Hans Verkuil05976912006-06-18 13:43:28 -03001472 case VIDIOC_G_EXT_CTRLS:
1473 {
1474 struct v4l2_ext_controls *p = arg;
1475
Hans Verkuild8799b42008-06-25 06:29:01 -03001476 p->error_idx = p->count;
Hans Verkuil21575c12008-06-22 11:55:09 -03001477 if (!vfd->vidioc_g_ext_ctrls)
1478 break;
Hans Verkuil6264c802008-06-25 06:54:05 -03001479 if (check_ext_ctrls(p, 0))
Hans Verkuild8799b42008-06-25 06:29:01 -03001480 ret = vfd->vidioc_g_ext_ctrls(file, fh, p);
Hans Verkuil21575c12008-06-22 11:55:09 -03001481 v4l_print_ext_ctrls(cmd, vfd, p, !ret);
Hans Verkuil05976912006-06-18 13:43:28 -03001482 break;
1483 }
1484 case VIDIOC_S_EXT_CTRLS:
1485 {
1486 struct v4l2_ext_controls *p = arg;
1487
Hans Verkuild8799b42008-06-25 06:29:01 -03001488 p->error_idx = p->count;
1489 if (!vfd->vidioc_s_ext_ctrls)
1490 break;
1491 v4l_print_ext_ctrls(cmd, vfd, p, 1);
Hans Verkuil6264c802008-06-25 06:54:05 -03001492 if (check_ext_ctrls(p, 0))
Hans Verkuil21575c12008-06-22 11:55:09 -03001493 ret = vfd->vidioc_s_ext_ctrls(file, fh, p);
Hans Verkuil05976912006-06-18 13:43:28 -03001494 break;
1495 }
1496 case VIDIOC_TRY_EXT_CTRLS:
1497 {
1498 struct v4l2_ext_controls *p = arg;
1499
Hans Verkuild8799b42008-06-25 06:29:01 -03001500 p->error_idx = p->count;
1501 if (!vfd->vidioc_try_ext_ctrls)
1502 break;
1503 v4l_print_ext_ctrls(cmd, vfd, p, 1);
Hans Verkuil6264c802008-06-25 06:54:05 -03001504 if (check_ext_ctrls(p, 0))
Hans Verkuil21575c12008-06-22 11:55:09 -03001505 ret = vfd->vidioc_try_ext_ctrls(file, fh, p);
Hans Verkuil05976912006-06-18 13:43:28 -03001506 break;
1507 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001508 case VIDIOC_QUERYMENU:
1509 {
Hans Verkuil21575c12008-06-22 11:55:09 -03001510 struct v4l2_querymenu *p = arg;
1511
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001512 if (!vfd->vidioc_querymenu)
1513 break;
Hans Verkuil21575c12008-06-22 11:55:09 -03001514 ret = vfd->vidioc_querymenu(file, fh, p);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001515 if (!ret)
Hans Verkuil21575c12008-06-22 11:55:09 -03001516 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);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001521 break;
1522 }
1523 /* --- audio ---------------------------------------------- */
1524 case VIDIOC_ENUMAUDIO:
1525 {
Hans Verkuil21575c12008-06-22 11:55:09 -03001526 struct v4l2_audio *p = arg;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001527
1528 if (!vfd->vidioc_enumaudio)
1529 break;
Hans Verkuil21575c12008-06-22 11:55:09 -03001530 ret = vfd->vidioc_enumaudio(file, fh, p);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001531 if (!ret)
Hans Verkuil21575c12008-06-22 11:55:09 -03001532 dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
1533 "mode=0x%x\n", p->index, p->name,
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001534 p->capability, p->mode);
Hans Verkuil21575c12008-06-22 11:55:09 -03001535 else
1536 dbgarg(cmd, "index=%d\n", p->index);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001537 break;
1538 }
1539 case VIDIOC_G_AUDIO:
1540 {
Hans Verkuil21575c12008-06-22 11:55:09 -03001541 struct v4l2_audio *p = arg;
1542 __u32 index = p->index;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001543
1544 if (!vfd->vidioc_g_audio)
1545 break;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001546
Hans Verkuil21575c12008-06-22 11:55:09 -03001547 memset(p, 0, sizeof(*p));
1548 p->index = index;
1549 ret = vfd->vidioc_g_audio(file, fh, p);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001550 if (!ret)
Hans Verkuil21575c12008-06-22 11:55:09 -03001551 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);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001556 break;
1557 }
1558 case VIDIOC_S_AUDIO:
1559 {
Hans Verkuil21575c12008-06-22 11:55:09 -03001560 struct v4l2_audio *p = arg;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001561
1562 if (!vfd->vidioc_s_audio)
1563 break;
Hans Verkuil21575c12008-06-22 11:55:09 -03001564 dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
1565 "mode=0x%x\n", p->index, p->name,
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001566 p->capability, p->mode);
Hans Verkuil21575c12008-06-22 11:55:09 -03001567 ret = vfd->vidioc_s_audio(file, fh, p);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001568 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;
Hans Verkuil21575c12008-06-22 11:55:09 -03001643 dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001644 ret=vfd->vidioc_g_crop(file, fh, p);
1645 if (!ret) {
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001646 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;
Hans Verkuil21575c12008-06-22 11:55:09 -03001655 dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001656 dbgrect(vfd, "", &p->c);
1657 ret=vfd->vidioc_s_crop(file, fh, p);
1658 break;
1659 }
1660 case VIDIOC_CROPCAP:
1661 {
Hans Verkuil21575c12008-06-22 11:55:09 -03001662 struct v4l2_cropcap *p = arg;
1663
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001664 /*FIXME: Should also show v4l2_fract pixelaspect */
1665 if (!vfd->vidioc_cropcap)
1666 break;
Hans Verkuil21575c12008-06-22 11:55:09 -03001667 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 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001673 break;
1674 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001675 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 }
Hans Verkuildb6eb5b2007-02-18 14:05:02 -03001701 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 }
Hans Verkuilada6ecd2007-02-18 14:56:22 -03001713 case VIDIOC_ENCODER_CMD:
1714 {
Hans Verkuil8bfb9b12008-06-21 08:57:42 -03001715 struct v4l2_encoder_cmd *p = arg;
Hans Verkuilada6ecd2007-02-18 14:56:22 -03001716
1717 if (!vfd->vidioc_encoder_cmd)
1718 break;
Hans Verkuil8bfb9b12008-06-21 08:57:42 -03001719 memset(&p->raw, 0, sizeof(p->raw));
1720 ret = vfd->vidioc_encoder_cmd(file, fh, p);
Hans Verkuilada6ecd2007-02-18 14:56:22 -03001721 if (!ret)
Hans Verkuil8bfb9b12008-06-21 08:57:42 -03001722 dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
Hans Verkuilada6ecd2007-02-18 14:56:22 -03001723 break;
1724 }
1725 case VIDIOC_TRY_ENCODER_CMD:
1726 {
Hans Verkuil8bfb9b12008-06-21 08:57:42 -03001727 struct v4l2_encoder_cmd *p = arg;
Hans Verkuilada6ecd2007-02-18 14:56:22 -03001728
1729 if (!vfd->vidioc_try_encoder_cmd)
1730 break;
Hans Verkuil8bfb9b12008-06-21 08:57:42 -03001731 memset(&p->raw, 0, sizeof(p->raw));
1732 ret = vfd->vidioc_try_encoder_cmd(file, fh, p);
Hans Verkuilada6ecd2007-02-18 14:56:22 -03001733 if (!ret)
Hans Verkuil8bfb9b12008-06-21 08:57:42 -03001734 dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
Hans Verkuilada6ecd2007-02-18 14:56:22 -03001735 break;
1736 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001737 case VIDIOC_G_PARM:
1738 {
1739 struct v4l2_streamparm *p=arg;
Mauro Carvalho Chehab2aa23422007-04-24 13:40:07 -03001740 __u32 type=p->type;
1741
1742 memset(p,0,sizeof(*p));
1743 p->type=type;
1744
Mauro Carvalho Chehab1c2d0342006-09-14 13:36:34 -03001745 if (vfd->vidioc_g_parm) {
1746 ret=vfd->vidioc_g_parm(file, fh, p);
1747 } else {
1748 struct v4l2_standard s;
Mauro Carvalho Chehab1c2d0342006-09-14 13:36:34 -03001749
1750 if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1751 return -EINVAL;
1752
Jonathan Corbet83427ac2006-10-13 07:51:16 -03001753 v4l2_video_std_construct(&s, vfd->current_norm,
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001754 v4l2_norm_to_name(vfd->current_norm));
Mauro Carvalho Chehab1c2d0342006-09-14 13:36:34 -03001755
Mauro Carvalho Chehab1c2d0342006-09-14 13:36:34 -03001756 p->parm.capture.timeperframe = s.frameperiod;
1757 ret=0;
1758 }
1759
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001760 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 {
Hans Verkuil21575c12008-06-22 11:55:09 -03001774 struct v4l2_tuner *p = arg;
1775 __u32 index = p->index;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001776
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001777 if (!vfd->vidioc_g_tuner)
1778 break;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001779
Hans Verkuil21575c12008-06-22 11:55:09 -03001780 memset(p, 0, sizeof(*p));
1781 p->index = index;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001782
Hans Verkuil21575c12008-06-22 11:55:09 -03001783 ret = vfd->vidioc_g_tuner(file, fh, p);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001784 if (!ret)
Hans Verkuil21575c12008-06-22 11:55:09 -03001785 dbgarg(cmd, "index=%d, name=%s, type=%d, "
1786 "capability=0x%x, rangelow=%d, "
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001787 "rangehigh=%d, signal=%d, afc=%d, "
Hans Verkuil21575c12008-06-22 11:55:09 -03001788 "rxsubchans=0x%x, audmode=%d\n",
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001789 p->index, p->name, p->type,
1790 p->capability, p->rangelow,
Hans Verkuil21575c12008-06-22 11:55:09 -03001791 p->rangehigh, p->signal, p->afc,
1792 p->rxsubchans, p->audmode);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001793 break;
1794 }
1795 case VIDIOC_S_TUNER:
1796 {
Hans Verkuil21575c12008-06-22 11:55:09 -03001797 struct v4l2_tuner *p = arg;
1798
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001799 if (!vfd->vidioc_s_tuner)
1800 break;
Hans Verkuil21575c12008-06-22 11:55:09 -03001801 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);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001810 break;
1811 }
1812 case VIDIOC_G_FREQUENCY:
1813 {
Hans Verkuil7bb846a2008-05-27 21:32:08 -03001814 struct v4l2_frequency *p = arg;
1815
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001816 if (!vfd->vidioc_g_frequency)
1817 break;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001818
Hans Verkuil7bb846a2008-05-27 21:32:08 -03001819 memset(p->reserved, 0, sizeof(p->reserved));
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001820
Hans Verkuil7bb846a2008-05-27 21:32:08 -03001821 ret = vfd->vidioc_g_frequency(file, fh, p);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001822 if (!ret)
Hans Verkuil7bb846a2008-05-27 21:32:08 -03001823 dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n",
1824 p->tuner, p->type, p->frequency);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001825 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 {
Hans Verkuil8bfb9b12008-06-21 08:57:42 -03001839 struct v4l2_sliced_vbi_cap *p = arg;
1840 __u32 type = p->type;
1841
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001842 if (!vfd->vidioc_g_sliced_vbi_cap)
1843 break;
Hans Verkuil8bfb9b12008-06-21 08:57:42 -03001844 memset(p, 0, sizeof(*p));
1845 p->type = type;
Hans Verkuil21575c12008-06-22 11:55:09 -03001846 dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
Hans Verkuil8bfb9b12008-06-21 08:57:42 -03001847 ret = vfd->vidioc_g_sliced_vbi_cap(file, fh, p);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001848 if (!ret)
Hans Verkuil21575c12008-06-22 11:55:09 -03001849 dbgarg2("service_set=%d\n", p->service_set);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001850 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 }
Trent Piephodbbff482007-01-22 23:31:53 -03001859#ifdef CONFIG_VIDEO_ADV_DEBUG
Trent Piepho52ebc762007-01-23 22:38:13 -03001860 case VIDIOC_DBG_G_REGISTER:
Trent Piephodbbff482007-01-22 23:31:53 -03001861 {
1862 struct v4l2_register *p=arg;
Trent Piepho62d50ad2007-01-30 23:25:41 -03001863 if (!capable(CAP_SYS_ADMIN))
1864 ret=-EPERM;
1865 else if (vfd->vidioc_g_register)
Trent Piephodbbff482007-01-22 23:31:53 -03001866 ret=vfd->vidioc_g_register(file, fh, p);
1867 break;
1868 }
Trent Piepho52ebc762007-01-23 22:38:13 -03001869 case VIDIOC_DBG_S_REGISTER:
Trent Piephodbbff482007-01-22 23:31:53 -03001870 {
1871 struct v4l2_register *p=arg;
Trent Piepho52ebc762007-01-23 22:38:13 -03001872 if (!capable(CAP_SYS_ADMIN))
1873 ret=-EPERM;
1874 else if (vfd->vidioc_s_register)
Trent Piephodbbff482007-01-22 23:31:53 -03001875 ret=vfd->vidioc_s_register(file, fh, p);
1876 break;
1877 }
1878#endif
Hans Verkuil3434eb72007-04-27 12:31:08 -03001879 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 }
Douglas Schilling Landgraf130ca942008-04-10 01:18:56 -03001889 default:
1890 {
1891 if (!vfd->vidioc_default)
1892 break;
1893 ret = vfd->vidioc_default(file, fh, cmd, arg);
1894 break;
1895 }
Tobias Lorenz1d0ba5f2008-05-26 18:40:46 -03001896 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 }
Mauro Carvalho Chehab207705c2006-11-20 12:13:25 -03001907 } /* switch */
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001908
1909 if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
Hans Verkuil21575c12008-06-22 11:55:09 -03001910 if (ret < 0) {
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001911 v4l_print_ioctl(vfd->name, cmd);
Hans Verkuil21575c12008-06-22 11:55:09 -03001912 printk(KERN_CONT " error %d\n", ret);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001913 }
1914 }
1915
1916 return ret;
1917}
1918
1919int 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;
Hans Verkuil05976912006-06-18 13:43:28 -03001926 int is_ext_ctrl;
1927 size_t ctrls_size = 0;
1928 void __user *user_ptr = NULL;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001929
1930#ifdef __OLD_VIDIOC_
1931 cmd = video_fix_command(cmd);
1932#endif
Hans Verkuil05976912006-06-18 13:43:28 -03001933 is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
1934 cmd == VIDIOC_TRY_EXT_CTRLS);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001935
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
Hans Verkuil05976912006-06-18 13:43:28 -03001961 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
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001982 /* Handles IOCTL */
1983 err = __video_do_ioctl(inode, file, cmd, parg);
1984 if (err == -ENOIOCTLCMD)
1985 err = -EINVAL;
Hans Verkuil05976912006-06-18 13:43:28 -03001986 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 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001994 if (err < 0)
1995 goto out;
1996
Hans Verkuil05976912006-06-18 13:43:28 -03001997out_ext_ctrl:
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001998 /* 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
2008out:
2009 kfree(mbuf);
2010 return err;
2011}
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -03002012EXPORT_SYMBOL(video_ioctl2);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03002013
brandon@ifup.org539a7552008-06-20 22:58:53 -03002014struct index_info {
2015 struct device *dev;
2016 unsigned int used[VIDEO_NUM_DEVICES];
2017};
2018
2019static int __fill_index_info(struct device *cd, void *data)
2020{
2021 struct index_info *info = data;
2022 struct video_device *vfd = container_of(cd, struct video_device,
2023 class_dev);
2024
2025 if (info->dev == vfd->dev)
2026 info->used[vfd->index] = 1;
2027
2028 return 0;
2029}
2030
2031/**
2032 * assign_index - assign stream number based on parent device
2033 * @vdev: video_device to assign index number to, vdev->dev should be assigned
2034 * @num: -1 if auto assign, requested number otherwise
2035 *
2036 *
2037 * returns -ENFILE if num is already in use, a free index number if
2038 * successful.
2039 */
2040static int get_index(struct video_device *vdev, int num)
2041{
2042 struct index_info *info;
2043 int i;
2044 int ret = 0;
2045
2046 if (num >= VIDEO_NUM_DEVICES)
2047 return -EINVAL;
2048
2049 info = kzalloc(sizeof(*info), GFP_KERNEL);
2050 if (!info)
2051 return -ENOMEM;
2052
2053 info->dev = vdev->dev;
2054
2055 ret = class_for_each_device(&video_class, info,
2056 __fill_index_info);
2057
2058 if (ret < 0)
2059 goto out;
2060
2061 if (num >= 0) {
2062 if (!info->used[num])
2063 ret = num;
2064 else
2065 ret = -ENFILE;
2066
2067 goto out;
2068 }
2069
2070 for (i = 0; i < VIDEO_NUM_DEVICES; i++) {
2071 if (info->used[i])
2072 continue;
2073 ret = i;
2074 goto out;
2075 }
2076
2077out:
2078 kfree(info);
2079 return ret;
2080}
2081
Arjan van de Venfa027c22007-02-12 00:55:33 -08002082static const struct file_operations video_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083
brandon@ifup.org539a7552008-06-20 22:58:53 -03002084int video_register_device(struct video_device *vfd, int type, int nr)
2085{
2086 return video_register_device_index(vfd, type, nr, -1);
2087}
2088EXPORT_SYMBOL(video_register_device);
2089
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090/**
2091 * video_register_device - register video4linux devices
2092 * @vfd: video device structure we want to register
2093 * @type: type of device to register
2094 * @nr: which device number (0 == /dev/video0, 1 == /dev/video1, ...
2095 * -1 == first free)
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08002096 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 * The registration code assigns minor numbers based on the type
2098 * requested. -ENFILE is returned in all the device slots for this
2099 * category are full. If not then the minor field is set and the
2100 * driver initialize function is called (if non %NULL).
2101 *
2102 * Zero is returned on success.
2103 *
2104 * Valid types are
2105 *
2106 * %VFL_TYPE_GRABBER - A frame grabber
2107 *
2108 * %VFL_TYPE_VTX - A teletext device
2109 *
2110 * %VFL_TYPE_VBI - Vertical blank data (undecoded)
2111 *
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08002112 * %VFL_TYPE_RADIO - A radio card
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 */
2114
brandon@ifup.org539a7552008-06-20 22:58:53 -03002115int video_register_device_index(struct video_device *vfd, int type, int nr,
2116 int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117{
2118 int i=0;
2119 int base;
2120 int end;
Michael Krufky3117bee2006-07-19 13:23:38 -03002121 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 char *name_base;
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08002123
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 switch(type)
2125 {
2126 case VFL_TYPE_GRABBER:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02002127 base=MINOR_VFL_TYPE_GRABBER_MIN;
2128 end=MINOR_VFL_TYPE_GRABBER_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 name_base = "video";
2130 break;
2131 case VFL_TYPE_VTX:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02002132 base=MINOR_VFL_TYPE_VTX_MIN;
2133 end=MINOR_VFL_TYPE_VTX_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 name_base = "vtx";
2135 break;
2136 case VFL_TYPE_VBI:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02002137 base=MINOR_VFL_TYPE_VBI_MIN;
2138 end=MINOR_VFL_TYPE_VBI_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 name_base = "vbi";
2140 break;
2141 case VFL_TYPE_RADIO:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02002142 base=MINOR_VFL_TYPE_RADIO_MIN;
2143 end=MINOR_VFL_TYPE_RADIO_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 name_base = "radio";
2145 break;
2146 default:
Trent Piepho53dd8de2006-07-25 09:31:42 -03002147 printk(KERN_ERR "%s called with unknown type: %d\n",
Harvey Harrison7e28adb2008-04-08 23:20:00 -03002148 __func__, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 return -1;
2150 }
2151
2152 /* pick a minor number */
Ingo Molnar1e4baed2006-01-15 07:52:23 -02002153 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 if (nr >= 0 && nr < end-base) {
2155 /* use the one the driver asked for */
2156 i = base+nr;
2157 if (NULL != video_device[i]) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -02002158 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 return -ENFILE;
2160 }
2161 } else {
2162 /* use first free */
2163 for(i=base;i<end;i++)
2164 if (NULL == video_device[i])
2165 break;
2166 if (i == end) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -02002167 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 return -ENFILE;
2169 }
2170 }
2171 video_device[i]=vfd;
2172 vfd->minor=i;
brandon@ifup.org539a7552008-06-20 22:58:53 -03002173
2174 ret = get_index(vfd, index);
2175 if (ret < 0) {
2176 printk(KERN_ERR "%s: get_index failed\n",
2177 __func__);
2178 goto fail_minor;
2179 }
2180
2181 vfd->index = ret;
2182
Ingo Molnar1e4baed2006-01-15 07:52:23 -02002183 mutex_unlock(&videodev_lock);
Ingo Molnar3593cab2006-02-07 06:49:14 -02002184 mutex_init(&vfd->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185
2186 /* sysfs class */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08002187 memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 if (vfd->dev)
Kay Sievers54bd5b62007-10-08 16:26:13 -03002189 vfd->class_dev.parent = vfd->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 vfd->class_dev.class = &video_class;
Michael Krufky50c25ff2006-01-09 15:25:34 -02002191 vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
Kay Sievers54bd5b62007-10-08 16:26:13 -03002192 sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base);
2193 ret = device_register(&vfd->class_dev);
Trent Piepho8c313112006-07-25 20:37:03 -03002194 if (ret < 0) {
Kay Sievers54bd5b62007-10-08 16:26:13 -03002195 printk(KERN_ERR "%s: device_register failed\n",
Harvey Harrison7e28adb2008-04-08 23:20:00 -03002196 __func__);
Trent Piephod94fc9a2006-07-29 17:18:06 -03002197 goto fail_minor;
Michael Krufky3117bee2006-07-19 13:23:38 -03002198 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199
Mauro Carvalho Chehabd21838d2006-01-09 15:25:21 -02002200#if 1
2201 /* needed until all drivers are fixed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 if (!vfd->release)
2203 printk(KERN_WARNING "videodev: \"%s\" has no release callback. "
2204 "Please fix your driver for proper sysfs support, see "
2205 "http://lwn.net/Articles/36850/\n", vfd->name);
2206#endif
2207 return 0;
Trent Piepho53dd8de2006-07-25 09:31:42 -03002208
Trent Piepho53dd8de2006-07-25 09:31:42 -03002209fail_minor:
2210 mutex_lock(&videodev_lock);
2211 video_device[vfd->minor] = NULL;
2212 vfd->minor = -1;
2213 mutex_unlock(&videodev_lock);
2214 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215}
brandon@ifup.org539a7552008-06-20 22:58:53 -03002216EXPORT_SYMBOL(video_register_device_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
2218/**
2219 * video_unregister_device - unregister a video4linux device
2220 * @vfd: the device to unregister
2221 *
2222 * This unregisters the passed device and deassigns the minor
2223 * number. Future open calls will be met with errors.
2224 */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08002225
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226void video_unregister_device(struct video_device *vfd)
2227{
Ingo Molnar1e4baed2006-01-15 07:52:23 -02002228 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 if(video_device[vfd->minor]!=vfd)
2230 panic("videodev: bad unregister");
2231
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 video_device[vfd->minor]=NULL;
Kay Sievers54bd5b62007-10-08 16:26:13 -03002233 device_unregister(&vfd->class_dev);
Ingo Molnar1e4baed2006-01-15 07:52:23 -02002234 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235}
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -03002236EXPORT_SYMBOL(video_unregister_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03002238/*
2239 * Video fs operations
2240 */
Arjan van de Venfa027c22007-02-12 00:55:33 -08002241static const struct file_operations video_fops=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242{
2243 .owner = THIS_MODULE,
2244 .llseek = no_llseek,
2245 .open = video_open,
2246};
2247
2248/*
2249 * Initialise video for linux
2250 */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08002251
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252static int __init videodev_init(void)
2253{
2254 int ret;
2255
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03002256 printk(KERN_INFO "Linux video capture interface: v2.00\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) {
2258 printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR);
2259 return -EIO;
2260 }
2261
2262 ret = class_register(&video_class);
2263 if (ret < 0) {
2264 unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME);
2265 printk(KERN_WARNING "video_dev: class_register failed\n");
2266 return -EIO;
2267 }
2268
2269 return 0;
2270}
2271
2272static void __exit videodev_exit(void)
2273{
2274 class_unregister(&video_class);
2275 unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME);
2276}
2277
2278module_init(videodev_init)
2279module_exit(videodev_exit)
2280
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03002281MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
2282MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283MODULE_LICENSE("GPL");
2284
2285
2286/*
2287 * Local variables:
2288 * c-basic-offset: 8
2289 * End:
2290 */