blob: 67a661cf5219bc65e225f304d5872579c034313b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03002 * Video capture interface for Linux version 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03004 * A generic video device interface for the LINUX operating system
5 * using a set of device structures/vectors for low level operations.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 *
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03007 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 *
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030012 * Authors: Alan Cox, <alan@redhat.com> (version 1)
13 * Mauro Carvalho Chehab <mchehab@infradead.org> (version 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 *
15 * Fixes: 20000516 Claudio Matsuoka <claudio@conectiva.com>
16 * - Added procfs support
17 */
18
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030019#define dbgarg(cmd, fmt, arg...) \
Enrico Scholz474ce782006-10-09 16:27:05 -030020 if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \
Mauro Carvalho Chehab5e28e002008-04-13 15:06:24 -030021 printk(KERN_DEBUG "%s: ", vfd->name); \
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030022 v4l_printk_ioctl(cmd); \
Mauro Carvalho Chehab5e28e002008-04-13 15:06:24 -030023 printk(" " fmt, ## arg); \
Enrico Scholz474ce782006-10-09 16:27:05 -030024 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030025
26#define dbgarg2(fmt, arg...) \
27 if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \
Mauro Carvalho Chehabd6849652008-04-13 15:07:16 -030028 printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030029
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/module.h>
31#include <linux/types.h>
32#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/mm.h>
34#include <linux/string.h>
35#include <linux/errno.h>
36#include <linux/init.h>
37#include <linux/kmod.h>
38#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <asm/uaccess.h>
40#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030042#define __OLD_VIDIOC_ /* To allow fixing old calls*/
43#include <linux/videodev2.h>
44
45#ifdef CONFIG_VIDEO_V4L1
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <linux/videodev.h>
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -030047#endif
48#include <media/v4l2-common.h>
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -030049#include <linux/video_decoder.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
51#define VIDEO_NUM_DEVICES 256
52#define VIDEO_NAME "video4linux"
53
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -030054struct std_descr {
55 v4l2_std_id std;
56 const char *descr;
57};
58
59static const struct std_descr standards[] = {
60 { V4L2_STD_NTSC, "NTSC" },
61 { V4L2_STD_NTSC_M, "NTSC-M" },
62 { V4L2_STD_NTSC_M_JP, "NTSC-M-JP" },
63 { V4L2_STD_NTSC_M_KR, "NTSC-M-KR" },
64 { V4L2_STD_NTSC_443, "NTSC-443" },
65 { V4L2_STD_PAL, "PAL" },
66 { V4L2_STD_PAL_BG, "PAL-BG" },
67 { V4L2_STD_PAL_B, "PAL-B" },
68 { V4L2_STD_PAL_B1, "PAL-B1" },
69 { V4L2_STD_PAL_G, "PAL-G" },
70 { V4L2_STD_PAL_H, "PAL-H" },
71 { V4L2_STD_PAL_I, "PAL-I" },
72 { V4L2_STD_PAL_DK, "PAL-DK" },
73 { V4L2_STD_PAL_D, "PAL-D" },
74 { V4L2_STD_PAL_D1, "PAL-D1" },
75 { V4L2_STD_PAL_K, "PAL-K" },
76 { V4L2_STD_PAL_M, "PAL-M" },
77 { V4L2_STD_PAL_N, "PAL-N" },
78 { V4L2_STD_PAL_Nc, "PAL-Nc" },
79 { V4L2_STD_PAL_60, "PAL-60" },
80 { V4L2_STD_SECAM, "SECAM" },
81 { V4L2_STD_SECAM_B, "SECAM-B" },
82 { V4L2_STD_SECAM_G, "SECAM-G" },
83 { V4L2_STD_SECAM_H, "SECAM-H" },
84 { V4L2_STD_SECAM_DK, "SECAM-DK" },
85 { V4L2_STD_SECAM_D, "SECAM-D" },
86 { V4L2_STD_SECAM_K, "SECAM-K" },
87 { V4L2_STD_SECAM_K1, "SECAM-K1" },
88 { V4L2_STD_SECAM_L, "SECAM-L" },
89 { V4L2_STD_SECAM_LC, "SECAM-Lc" },
90 { 0, "Unknown" }
91};
92
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -030093/* video4linux standard ID conversion to standard name
94 */
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -030095const char *v4l2_norm_to_name(v4l2_std_id id)
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -030096{
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -030097 u32 myid = id;
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -030098 int i;
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -030099
100 /* HACK: ppc32 architecture doesn't have __ucmpdi2 function to handle
101 64 bit comparations. So, on that architecture, with some gcc
102 variants, compilation fails. Currently, the max value is 30bit wide.
103 */
104 BUG_ON(myid != id);
105
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -0300106 for (i = 0; standards[i].std; i++)
107 if (myid == standards[i].std)
108 break;
109 return standards[i].descr;
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300110}
111EXPORT_SYMBOL(v4l2_norm_to_name);
112
113/* Fill in the fields of a v4l2_standard structure according to the
114 'id' and 'transmission' parameters. Returns negative on error. */
115int v4l2_video_std_construct(struct v4l2_standard *vs,
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -0300116 int id, const char *name)
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300117{
118 u32 index = vs->index;
119
120 memset(vs, 0, sizeof(struct v4l2_standard));
121 vs->index = index;
122 vs->id = id;
123 if (id & V4L2_STD_525_60) {
124 vs->frameperiod.numerator = 1001;
125 vs->frameperiod.denominator = 30000;
126 vs->framelines = 525;
127 } else {
128 vs->frameperiod.numerator = 1;
129 vs->frameperiod.denominator = 25;
130 vs->framelines = 625;
131 }
132 strlcpy(vs->name, name, sizeof(vs->name));
133 return 0;
134}
135EXPORT_SYMBOL(v4l2_video_std_construct);
136
137/* ----------------------------------------------------------------- */
138/* some arrays for pretty-printing debug messages of enum types */
139
140char *v4l2_field_names[] = {
141 [V4L2_FIELD_ANY] = "any",
142 [V4L2_FIELD_NONE] = "none",
143 [V4L2_FIELD_TOP] = "top",
144 [V4L2_FIELD_BOTTOM] = "bottom",
145 [V4L2_FIELD_INTERLACED] = "interlaced",
146 [V4L2_FIELD_SEQ_TB] = "seq-tb",
147 [V4L2_FIELD_SEQ_BT] = "seq-bt",
148 [V4L2_FIELD_ALTERNATE] = "alternate",
149 [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb",
150 [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt",
151};
152EXPORT_SYMBOL(v4l2_field_names);
153
154char *v4l2_type_names[] = {
155 [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap",
156 [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over",
157 [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out",
158 [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap",
159 [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out",
160 [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap",
161 [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out",
162 [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over",
163};
164EXPORT_SYMBOL(v4l2_type_names);
165
166static char *v4l2_memory_names[] = {
167 [V4L2_MEMORY_MMAP] = "mmap",
168 [V4L2_MEMORY_USERPTR] = "userptr",
169 [V4L2_MEMORY_OVERLAY] = "overlay",
170};
171
172#define prt_names(a, arr) ((((a) >= 0) && ((a) < ARRAY_SIZE(arr))) ? \
173 arr[a] : "unknown")
174
175/* ------------------------------------------------------------------ */
176/* debug help functions */
177
178#ifdef CONFIG_VIDEO_V4L1_COMPAT
179static const char *v4l1_ioctls[] = {
180 [_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP",
181 [_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN",
182 [_IOC_NR(VIDIOCSCHAN)] = "VIDIOCSCHAN",
183 [_IOC_NR(VIDIOCGTUNER)] = "VIDIOCGTUNER",
184 [_IOC_NR(VIDIOCSTUNER)] = "VIDIOCSTUNER",
185 [_IOC_NR(VIDIOCGPICT)] = "VIDIOCGPICT",
186 [_IOC_NR(VIDIOCSPICT)] = "VIDIOCSPICT",
187 [_IOC_NR(VIDIOCCAPTURE)] = "VIDIOCCAPTURE",
188 [_IOC_NR(VIDIOCGWIN)] = "VIDIOCGWIN",
189 [_IOC_NR(VIDIOCSWIN)] = "VIDIOCSWIN",
190 [_IOC_NR(VIDIOCGFBUF)] = "VIDIOCGFBUF",
191 [_IOC_NR(VIDIOCSFBUF)] = "VIDIOCSFBUF",
192 [_IOC_NR(VIDIOCKEY)] = "VIDIOCKEY",
193 [_IOC_NR(VIDIOCGFREQ)] = "VIDIOCGFREQ",
194 [_IOC_NR(VIDIOCSFREQ)] = "VIDIOCSFREQ",
195 [_IOC_NR(VIDIOCGAUDIO)] = "VIDIOCGAUDIO",
196 [_IOC_NR(VIDIOCSAUDIO)] = "VIDIOCSAUDIO",
197 [_IOC_NR(VIDIOCSYNC)] = "VIDIOCSYNC",
198 [_IOC_NR(VIDIOCMCAPTURE)] = "VIDIOCMCAPTURE",
199 [_IOC_NR(VIDIOCGMBUF)] = "VIDIOCGMBUF",
200 [_IOC_NR(VIDIOCGUNIT)] = "VIDIOCGUNIT",
201 [_IOC_NR(VIDIOCGCAPTURE)] = "VIDIOCGCAPTURE",
202 [_IOC_NR(VIDIOCSCAPTURE)] = "VIDIOCSCAPTURE",
203 [_IOC_NR(VIDIOCSPLAYMODE)] = "VIDIOCSPLAYMODE",
204 [_IOC_NR(VIDIOCSWRITEMODE)] = "VIDIOCSWRITEMODE",
205 [_IOC_NR(VIDIOCGPLAYINFO)] = "VIDIOCGPLAYINFO",
206 [_IOC_NR(VIDIOCSMICROCODE)] = "VIDIOCSMICROCODE",
207 [_IOC_NR(VIDIOCGVBIFMT)] = "VIDIOCGVBIFMT",
208 [_IOC_NR(VIDIOCSVBIFMT)] = "VIDIOCSVBIFMT"
209};
210#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
211#endif
212
213static const char *v4l2_ioctls[] = {
214 [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP",
215 [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED",
216 [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT",
217 [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT",
218 [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT",
219 [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS",
220 [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF",
221 [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF",
222 [_IOC_NR(VIDIOC_S_FBUF)] = "VIDIOC_S_FBUF",
223 [_IOC_NR(VIDIOC_OVERLAY)] = "VIDIOC_OVERLAY",
224 [_IOC_NR(VIDIOC_QBUF)] = "VIDIOC_QBUF",
225 [_IOC_NR(VIDIOC_DQBUF)] = "VIDIOC_DQBUF",
226 [_IOC_NR(VIDIOC_STREAMON)] = "VIDIOC_STREAMON",
227 [_IOC_NR(VIDIOC_STREAMOFF)] = "VIDIOC_STREAMOFF",
228 [_IOC_NR(VIDIOC_G_PARM)] = "VIDIOC_G_PARM",
229 [_IOC_NR(VIDIOC_S_PARM)] = "VIDIOC_S_PARM",
230 [_IOC_NR(VIDIOC_G_STD)] = "VIDIOC_G_STD",
231 [_IOC_NR(VIDIOC_S_STD)] = "VIDIOC_S_STD",
232 [_IOC_NR(VIDIOC_ENUMSTD)] = "VIDIOC_ENUMSTD",
233 [_IOC_NR(VIDIOC_ENUMINPUT)] = "VIDIOC_ENUMINPUT",
234 [_IOC_NR(VIDIOC_G_CTRL)] = "VIDIOC_G_CTRL",
235 [_IOC_NR(VIDIOC_S_CTRL)] = "VIDIOC_S_CTRL",
236 [_IOC_NR(VIDIOC_G_TUNER)] = "VIDIOC_G_TUNER",
237 [_IOC_NR(VIDIOC_S_TUNER)] = "VIDIOC_S_TUNER",
238 [_IOC_NR(VIDIOC_G_AUDIO)] = "VIDIOC_G_AUDIO",
239 [_IOC_NR(VIDIOC_S_AUDIO)] = "VIDIOC_S_AUDIO",
240 [_IOC_NR(VIDIOC_QUERYCTRL)] = "VIDIOC_QUERYCTRL",
241 [_IOC_NR(VIDIOC_QUERYMENU)] = "VIDIOC_QUERYMENU",
242 [_IOC_NR(VIDIOC_G_INPUT)] = "VIDIOC_G_INPUT",
243 [_IOC_NR(VIDIOC_S_INPUT)] = "VIDIOC_S_INPUT",
244 [_IOC_NR(VIDIOC_G_OUTPUT)] = "VIDIOC_G_OUTPUT",
245 [_IOC_NR(VIDIOC_S_OUTPUT)] = "VIDIOC_S_OUTPUT",
246 [_IOC_NR(VIDIOC_ENUMOUTPUT)] = "VIDIOC_ENUMOUTPUT",
247 [_IOC_NR(VIDIOC_G_AUDOUT)] = "VIDIOC_G_AUDOUT",
248 [_IOC_NR(VIDIOC_S_AUDOUT)] = "VIDIOC_S_AUDOUT",
249 [_IOC_NR(VIDIOC_G_MODULATOR)] = "VIDIOC_G_MODULATOR",
250 [_IOC_NR(VIDIOC_S_MODULATOR)] = "VIDIOC_S_MODULATOR",
251 [_IOC_NR(VIDIOC_G_FREQUENCY)] = "VIDIOC_G_FREQUENCY",
252 [_IOC_NR(VIDIOC_S_FREQUENCY)] = "VIDIOC_S_FREQUENCY",
253 [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP",
254 [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP",
255 [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP",
256 [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP",
257 [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP",
258 [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD",
259 [_IOC_NR(VIDIOC_TRY_FMT)] = "VIDIOC_TRY_FMT",
260 [_IOC_NR(VIDIOC_ENUMAUDIO)] = "VIDIOC_ENUMAUDIO",
261 [_IOC_NR(VIDIOC_ENUMAUDOUT)] = "VIDIOC_ENUMAUDOUT",
262 [_IOC_NR(VIDIOC_G_PRIORITY)] = "VIDIOC_G_PRIORITY",
263 [_IOC_NR(VIDIOC_S_PRIORITY)] = "VIDIOC_S_PRIORITY",
264 [_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP",
265 [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS",
266 [_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS",
267 [_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS",
268 [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS",
269#if 1
270 [_IOC_NR(VIDIOC_ENUM_FRAMESIZES)] = "VIDIOC_ENUM_FRAMESIZES",
271 [_IOC_NR(VIDIOC_ENUM_FRAMEINTERVALS)] = "VIDIOC_ENUM_FRAMEINTERVALS",
272 [_IOC_NR(VIDIOC_G_ENC_INDEX)] = "VIDIOC_G_ENC_INDEX",
273 [_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD",
274 [_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD",
275
276 [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER",
277 [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER",
278
279 [_IOC_NR(VIDIOC_G_CHIP_IDENT)] = "VIDIOC_G_CHIP_IDENT",
280#endif
281};
282#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
283
284static const char *v4l2_int_ioctls[] = {
285#ifdef CONFIG_VIDEO_V4L1_COMPAT
286 [_IOC_NR(DECODER_GET_CAPABILITIES)] = "DECODER_GET_CAPABILITIES",
287 [_IOC_NR(DECODER_GET_STATUS)] = "DECODER_GET_STATUS",
288 [_IOC_NR(DECODER_SET_NORM)] = "DECODER_SET_NORM",
289 [_IOC_NR(DECODER_SET_INPUT)] = "DECODER_SET_INPUT",
290 [_IOC_NR(DECODER_SET_OUTPUT)] = "DECODER_SET_OUTPUT",
291 [_IOC_NR(DECODER_ENABLE_OUTPUT)] = "DECODER_ENABLE_OUTPUT",
292 [_IOC_NR(DECODER_SET_PICTURE)] = "DECODER_SET_PICTURE",
293 [_IOC_NR(DECODER_SET_GPIO)] = "DECODER_SET_GPIO",
294 [_IOC_NR(DECODER_INIT)] = "DECODER_INIT",
295 [_IOC_NR(DECODER_SET_VBI_BYPASS)] = "DECODER_SET_VBI_BYPASS",
296 [_IOC_NR(DECODER_DUMP)] = "DECODER_DUMP",
297#endif
298 [_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO",
299
300 [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR",
301 [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY",
302 [_IOC_NR(TUNER_SET_CONFIG)] = "TUNER_SET_CONFIG",
303
304 [_IOC_NR(VIDIOC_INT_S_TUNER_MODE)] = "VIDIOC_INT_S_TUNER_MODE",
305 [_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET",
306 [_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ",
307 [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE",
308 [_IOC_NR(VIDIOC_INT_S_VBI_DATA)] = "VIDIOC_INT_S_VBI_DATA",
309 [_IOC_NR(VIDIOC_INT_G_VBI_DATA)] = "VIDIOC_INT_G_VBI_DATA",
310 [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ",
311 [_IOC_NR(VIDIOC_INT_S_STANDBY)] = "VIDIOC_INT_S_STANDBY",
312 [_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING",
313 [_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING",
314 [_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING",
315 [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING",
316 [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ",
317 [_IOC_NR(VIDIOC_INT_INIT)] = "VIDIOC_INT_INIT",
318 [_IOC_NR(VIDIOC_INT_G_STD_OUTPUT)] = "VIDIOC_INT_G_STD_OUTPUT",
319 [_IOC_NR(VIDIOC_INT_S_STD_OUTPUT)] = "VIDIOC_INT_S_STD_OUTPUT",
320};
321#define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
322
323/* Common ioctl debug function. This function can be used by
324 external ioctl messages as well as internal V4L ioctl */
325void v4l_printk_ioctl(unsigned int cmd)
326{
Mauro Carvalho Chehab5e28e002008-04-13 15:06:24 -0300327 char *dir, *type;
328
329 switch (_IOC_TYPE(cmd)) {
330 case 'd':
331 if (_IOC_NR(cmd) >= V4L2_INT_IOCTLS) {
332 type = "v4l2_int";
333 break;
334 }
335 printk("%s", v4l2_int_ioctls[_IOC_NR(cmd)]);
336 return;
337#ifdef CONFIG_VIDEO_V4L1_COMPAT
338 case 'v':
339 if (_IOC_NR(cmd) >= V4L1_IOCTLS) {
340 type = "v4l1";
341 break;
342 }
343 printk("%s", v4l1_ioctls[_IOC_NR(cmd)]);
344 return;
345#endif
346 case 'V':
347 if (_IOC_NR(cmd) >= V4L2_IOCTLS) {
348 type = "v4l2";
349 break;
350 }
351 printk("%s", v4l2_ioctls[_IOC_NR(cmd)]);
352 return;
353 default:
354 type = "unknown";
355 }
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300356
357 switch (_IOC_DIR(cmd)) {
358 case _IOC_NONE: dir = "--"; break;
359 case _IOC_READ: dir = "r-"; break;
360 case _IOC_WRITE: dir = "-w"; break;
361 case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
362 default: dir = "*ERR*"; break;
363 }
Mauro Carvalho Chehab5e28e002008-04-13 15:06:24 -0300364 printk("%s ioctl '%c', dir=%s, #%d (0x%08x)",
365 type, _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd);
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300366}
367EXPORT_SYMBOL(v4l_printk_ioctl);
368
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369/*
370 * sysfs stuff
371 */
372
Kay Sievers54bd5b62007-10-08 16:26:13 -0300373static ssize_t show_name(struct device *cd,
374 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375{
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300376 struct video_device *vfd = container_of(cd, struct video_device,
Kay Sievers54bd5b62007-10-08 16:26:13 -0300377 class_dev);
378 return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379}
380
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381struct video_device *video_device_alloc(void)
382{
383 struct video_device *vfd;
384
Panagiotis Issaris74081872006-01-11 19:40:56 -0200385 vfd = kzalloc(sizeof(*vfd),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 return vfd;
387}
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300388EXPORT_SYMBOL(video_device_alloc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
390void video_device_release(struct video_device *vfd)
391{
392 kfree(vfd);
393}
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300394EXPORT_SYMBOL(video_device_release);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395
Kay Sievers54bd5b62007-10-08 16:26:13 -0300396static void video_release(struct device *cd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397{
Trent Piephobde00cc2007-10-08 18:36:21 -0300398 struct video_device *vfd = container_of(cd, struct video_device,
399 class_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
Mauro Carvalho Chehabd21838d2006-01-09 15:25:21 -0200401#if 1
Michael Krufky50c25ff2006-01-09 15:25:34 -0200402 /* needed until all drivers are fixed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 if (!vfd->release)
404 return;
405#endif
406 vfd->release(vfd);
407}
408
Kay Sievers54bd5b62007-10-08 16:26:13 -0300409static struct device_attribute video_device_attrs[] = {
410 __ATTR(name, S_IRUGO, show_name, NULL),
411 __ATTR_NULL
412};
413
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414static struct class video_class = {
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800415 .name = VIDEO_NAME,
Kay Sievers54bd5b62007-10-08 16:26:13 -0300416 .dev_attrs = video_device_attrs,
417 .dev_release = video_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418};
419
420/*
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800421 * Active devices
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800423
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424static struct video_device *video_device[VIDEO_NUM_DEVICES];
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200425static DEFINE_MUTEX(videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
427struct video_device* video_devdata(struct file *file)
428{
Josef Sipek723731b2006-12-08 02:37:47 -0800429 return video_device[iminor(file->f_path.dentry->d_inode)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430}
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300431EXPORT_SYMBOL(video_devdata);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
433/*
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300434 * Open a video device - FIXME: Obsoleted
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 */
436static int video_open(struct inode *inode, struct file *file)
437{
438 unsigned int minor = iminor(inode);
439 int err = 0;
440 struct video_device *vfl;
Arjan van de Ven99ac48f2006-03-28 01:56:41 -0800441 const struct file_operations *old_fops;
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800442
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 if(minor>=VIDEO_NUM_DEVICES)
444 return -ENODEV;
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200445 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 vfl=video_device[minor];
447 if(vfl==NULL) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200448 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 request_module("char-major-%d-%d", VIDEO_MAJOR, minor);
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200450 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 vfl=video_device[minor];
452 if (vfl==NULL) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200453 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 return -ENODEV;
455 }
456 }
457 old_fops = file->f_op;
458 file->f_op = fops_get(vfl->fops);
459 if(file->f_op->open)
460 err = file->f_op->open(inode,file);
461 if (err) {
462 fops_put(file->f_op);
463 file->f_op = fops_get(old_fops);
464 }
465 fops_put(old_fops);
Ingo Molnar1e4baed2006-01-15 07:52:23 -0200466 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 return err;
468}
469
470/*
471 * helper function -- handles userspace copying for ioctl arguments
472 */
473
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300474#ifdef __OLD_VIDIOC_
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475static unsigned int
476video_fix_command(unsigned int cmd)
477{
478 switch (cmd) {
479 case VIDIOC_OVERLAY_OLD:
480 cmd = VIDIOC_OVERLAY;
481 break;
482 case VIDIOC_S_PARM_OLD:
483 cmd = VIDIOC_S_PARM;
484 break;
485 case VIDIOC_S_CTRL_OLD:
486 cmd = VIDIOC_S_CTRL;
487 break;
488 case VIDIOC_G_AUDIO_OLD:
489 cmd = VIDIOC_G_AUDIO;
490 break;
491 case VIDIOC_G_AUDOUT_OLD:
492 cmd = VIDIOC_G_AUDOUT;
493 break;
494 case VIDIOC_CROPCAP_OLD:
495 cmd = VIDIOC_CROPCAP;
496 break;
497 }
498 return cmd;
499}
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300500#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300502/*
503 * Obsolete usercopy function - Should be removed soon
504 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505int
506video_usercopy(struct inode *inode, struct file *file,
507 unsigned int cmd, unsigned long arg,
508 int (*func)(struct inode *inode, struct file *file,
509 unsigned int cmd, void *arg))
510{
511 char sbuf[128];
512 void *mbuf = NULL;
513 void *parg = NULL;
514 int err = -EINVAL;
Hans Verkuil05976912006-06-18 13:43:28 -0300515 int is_ext_ctrl;
516 size_t ctrls_size = 0;
517 void __user *user_ptr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300519#ifdef __OLD_VIDIOC_
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 cmd = video_fix_command(cmd);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300521#endif
Hans Verkuil05976912006-06-18 13:43:28 -0300522 is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
523 cmd == VIDIOC_TRY_EXT_CTRLS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
525 /* Copy arguments into temp kernel buffer */
526 switch (_IOC_DIR(cmd)) {
527 case _IOC_NONE:
528 parg = NULL;
529 break;
530 case _IOC_READ:
531 case _IOC_WRITE:
532 case (_IOC_WRITE | _IOC_READ):
533 if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
534 parg = sbuf;
535 } else {
536 /* too big to allocate from stack */
537 mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
538 if (NULL == mbuf)
539 return -ENOMEM;
540 parg = mbuf;
541 }
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800542
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 err = -EFAULT;
544 if (_IOC_DIR(cmd) & _IOC_WRITE)
Hans Verkuil05976912006-06-18 13:43:28 -0300545 if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 goto out;
547 break;
548 }
Hans Verkuil05976912006-06-18 13:43:28 -0300549 if (is_ext_ctrl) {
550 struct v4l2_ext_controls *p = parg;
551
552 /* In case of an error, tell the caller that it wasn't
553 a specific control that caused it. */
554 p->error_idx = p->count;
555 user_ptr = (void __user *)p->controls;
556 if (p->count) {
557 ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
558 /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
559 mbuf = kmalloc(ctrls_size, GFP_KERNEL);
560 err = -ENOMEM;
561 if (NULL == mbuf)
562 goto out_ext_ctrl;
563 err = -EFAULT;
564 if (copy_from_user(mbuf, user_ptr, ctrls_size))
565 goto out_ext_ctrl;
566 p->controls = mbuf;
567 }
568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
570 /* call driver */
571 err = func(inode, file, cmd, parg);
572 if (err == -ENOIOCTLCMD)
573 err = -EINVAL;
Hans Verkuil05976912006-06-18 13:43:28 -0300574 if (is_ext_ctrl) {
575 struct v4l2_ext_controls *p = parg;
576
577 p->controls = (void *)user_ptr;
578 if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
579 err = -EFAULT;
580 goto out_ext_ctrl;
581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 if (err < 0)
583 goto out;
584
Hans Verkuil05976912006-06-18 13:43:28 -0300585out_ext_ctrl:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 /* Copy results into user buffer */
587 switch (_IOC_DIR(cmd))
588 {
589 case _IOC_READ:
590 case (_IOC_WRITE | _IOC_READ):
591 if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
592 err = -EFAULT;
593 break;
594 }
595
596out:
Jesper Juhl2ea75332005-11-07 01:01:31 -0800597 kfree(mbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 return err;
599}
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300600EXPORT_SYMBOL(video_usercopy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
602/*
603 * open/release helper functions -- handle exclusive opens
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300604 * Should be removed soon
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 */
606int video_exclusive_open(struct inode *inode, struct file *file)
607{
608 struct video_device *vfl = video_devdata(file);
609 int retval = 0;
610
Ingo Molnar3593cab2006-02-07 06:49:14 -0200611 mutex_lock(&vfl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 if (vfl->users) {
613 retval = -EBUSY;
614 } else {
615 vfl->users++;
616 }
Ingo Molnar3593cab2006-02-07 06:49:14 -0200617 mutex_unlock(&vfl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 return retval;
619}
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300620EXPORT_SYMBOL(video_exclusive_open);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
622int video_exclusive_release(struct inode *inode, struct file *file)
623{
624 struct video_device *vfl = video_devdata(file);
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -0800625
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 vfl->users--;
627 return 0;
628}
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300629EXPORT_SYMBOL(video_exclusive_release);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300630
631static void dbgbuf(unsigned int cmd, struct video_device *vfd,
632 struct v4l2_buffer *p)
633{
634 struct v4l2_timecode *tc=&p->timecode;
635
636 dbgarg (cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, "
637 "bytesused=%d, flags=0x%08d, "
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300638 "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n",
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300639 (p->timestamp.tv_sec/3600),
640 (int)(p->timestamp.tv_sec/60)%60,
641 (int)(p->timestamp.tv_sec%60),
642 p->timestamp.tv_usec,
643 p->index,
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300644 prt_names(p->type, v4l2_type_names),
645 p->bytesused, p->flags,
646 p->field, p->sequence,
647 prt_names(p->memory, v4l2_memory_names),
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300648 p->m.userptr, p->length);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300649 dbgarg2 ("timecode= %02d:%02d:%02d type=%d, "
650 "flags=0x%08d, frames=%d, userbits=0x%08x\n",
651 tc->hours,tc->minutes,tc->seconds,
Mauro Carvalho Chehabc18cb012006-06-23 07:05:22 -0300652 tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300653}
654
655static inline void dbgrect(struct video_device *vfd, char *s,
656 struct v4l2_rect *r)
657{
658 dbgarg2 ("%sRect start at %dx%d, size= %dx%d\n", s, r->left, r->top,
659 r->width, r->height);
660};
661
662static inline void v4l_print_pix_fmt (struct video_device *vfd,
663 struct v4l2_pix_format *fmt)
664{
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300665 dbgarg2 ("width=%d, height=%d, format=%c%c%c%c, field=%s, "
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300666 "bytesperline=%d sizeimage=%d, colorspace=%d\n",
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300667 fmt->width,fmt->height,
668 (fmt->pixelformat & 0xff),
669 (fmt->pixelformat >> 8) & 0xff,
670 (fmt->pixelformat >> 16) & 0xff,
671 (fmt->pixelformat >> 24) & 0xff,
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300672 prt_names(fmt->field, v4l2_field_names),
673 fmt->bytesperline, fmt->sizeimage, fmt->colorspace);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300674};
675
676
677static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type)
678{
679 switch (type) {
680 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
681 if (vfd->vidioc_try_fmt_cap)
682 return (0);
683 break;
684 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
685 if (vfd->vidioc_try_fmt_overlay)
686 return (0);
687 break;
688 case V4L2_BUF_TYPE_VBI_CAPTURE:
689 if (vfd->vidioc_try_fmt_vbi)
690 return (0);
691 break;
692 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
693 if (vfd->vidioc_try_fmt_vbi_output)
694 return (0);
695 break;
696 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
697 if (vfd->vidioc_try_fmt_vbi_capture)
698 return (0);
699 break;
700 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
701 if (vfd->vidioc_try_fmt_video_output)
702 return (0);
703 break;
704 case V4L2_BUF_TYPE_VBI_OUTPUT:
705 if (vfd->vidioc_try_fmt_vbi_output)
706 return (0);
707 break;
Hans Verkuilb2787842007-04-27 12:31:02 -0300708 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
709 if (vfd->vidioc_try_fmt_output_overlay)
710 return (0);
711 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300712 case V4L2_BUF_TYPE_PRIVATE:
713 if (vfd->vidioc_try_fmt_type_private)
714 return (0);
715 break;
716 }
717 return (-EINVAL);
718}
719
720static int __video_do_ioctl(struct inode *inode, struct file *file,
721 unsigned int cmd, void *arg)
722{
723 struct video_device *vfd = video_devdata(file);
724 void *fh = file->private_data;
725 int ret = -EINVAL;
726
727 if ( (vfd->debug & V4L2_DEBUG_IOCTL) &&
Jiri Slaby57e45b32007-05-07 10:55:49 -0300728 !(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) {
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300729 v4l_print_ioctl(vfd->name, cmd);
Mauro Carvalho Chehabd6849652008-04-13 15:07:16 -0300730 printk("\n");
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300731 }
732
Sam Revitch1088b132007-05-01 08:46:30 -0300733#ifdef CONFIG_VIDEO_V4L1_COMPAT
Mauro Carvalho Chehab452c0fb2007-05-01 08:55:00 -0300734 /***********************************************************
735 Handles calls to the obsoleted V4L1 API
736 Due to the nature of VIDIOCGMBUF, each driver that supports
737 V4L1 should implement its own handler for this ioctl.
738 ***********************************************************/
739
Sam Revitch1088b132007-05-01 08:46:30 -0300740 /* --- streaming capture ------------------------------------- */
741 if (cmd == VIDIOCGMBUF) {
742 struct video_mbuf *p=arg;
743
Mariusz Kozlowski473c6532007-08-06 18:05:35 -0300744 memset(p, 0, sizeof(*p));
Sam Revitch1088b132007-05-01 08:46:30 -0300745
746 if (!vfd->vidiocgmbuf)
747 return ret;
748 ret=vfd->vidiocgmbuf(file, fh, p);
749 if (!ret)
750 dbgarg (cmd, "size=%d, frames=%d, offsets=0x%08lx\n",
751 p->size, p->frames,
752 (unsigned long)p->offsets);
753 return ret;
754 }
Sam Revitch1088b132007-05-01 08:46:30 -0300755
Mauro Carvalho Chehab452c0fb2007-05-01 08:55:00 -0300756 /********************************************************
757 All other V4L1 calls are handled by v4l1_compat module.
758 Those calls will be translated into V4L2 calls, and
759 __video_do_ioctl will be called again, with one or more
760 V4L2 ioctls.
761 ********************************************************/
Mauro Carvalho Chehab207705c2006-11-20 12:13:25 -0300762 if (_IOC_TYPE(cmd)=='v')
763 return v4l_compat_translate_ioctl(inode,file,cmd,arg,
764 __video_do_ioctl);
Mauro Carvalho Chehab452c0fb2007-05-01 08:55:00 -0300765#endif
Mauro Carvalho Chehab207705c2006-11-20 12:13:25 -0300766
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300767 switch(cmd) {
768 /* --- capabilities ------------------------------------------ */
769 case VIDIOC_QUERYCAP:
770 {
771 struct v4l2_capability *cap = (struct v4l2_capability*)arg;
772 memset(cap, 0, sizeof(*cap));
773
774 if (!vfd->vidioc_querycap)
775 break;
776
777 ret=vfd->vidioc_querycap(file, fh, cap);
778 if (!ret)
779 dbgarg (cmd, "driver=%s, card=%s, bus=%s, "
780 "version=0x%08x, "
781 "capabilities=0x%08x\n",
782 cap->driver,cap->card,cap->bus_info,
783 cap->version,
784 cap->capabilities);
785 break;
786 }
787
788 /* --- priority ------------------------------------------ */
789 case VIDIOC_G_PRIORITY:
790 {
791 enum v4l2_priority *p=arg;
792
793 if (!vfd->vidioc_g_priority)
794 break;
795 ret=vfd->vidioc_g_priority(file, fh, p);
796 if (!ret)
797 dbgarg(cmd, "priority is %d\n", *p);
798 break;
799 }
800 case VIDIOC_S_PRIORITY:
801 {
802 enum v4l2_priority *p=arg;
803
804 if (!vfd->vidioc_s_priority)
805 break;
806 dbgarg(cmd, "setting priority to %d\n", *p);
807 ret=vfd->vidioc_s_priority(file, fh, *p);
808 break;
809 }
810
811 /* --- capture ioctls ---------------------------------------- */
812 case VIDIOC_ENUM_FMT:
813 {
814 struct v4l2_fmtdesc *f = arg;
815 enum v4l2_buf_type type;
816 unsigned int index;
817
818 index = f->index;
819 type = f->type;
820 memset(f,0,sizeof(*f));
821 f->index = index;
822 f->type = type;
823
824 switch (type) {
825 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
826 if (vfd->vidioc_enum_fmt_cap)
827 ret=vfd->vidioc_enum_fmt_cap(file, fh, f);
828 break;
829 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
830 if (vfd->vidioc_enum_fmt_overlay)
831 ret=vfd->vidioc_enum_fmt_overlay(file, fh, f);
832 break;
833 case V4L2_BUF_TYPE_VBI_CAPTURE:
834 if (vfd->vidioc_enum_fmt_vbi)
835 ret=vfd->vidioc_enum_fmt_vbi(file, fh, f);
836 break;
837 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
838 if (vfd->vidioc_enum_fmt_vbi_output)
839 ret=vfd->vidioc_enum_fmt_vbi_output(file,
840 fh, f);
841 break;
842 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
843 if (vfd->vidioc_enum_fmt_vbi_capture)
844 ret=vfd->vidioc_enum_fmt_vbi_capture(file,
845 fh, f);
846 break;
847 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
848 if (vfd->vidioc_enum_fmt_video_output)
849 ret=vfd->vidioc_enum_fmt_video_output(file,
850 fh, f);
851 break;
852 case V4L2_BUF_TYPE_VBI_OUTPUT:
853 if (vfd->vidioc_enum_fmt_vbi_output)
854 ret=vfd->vidioc_enum_fmt_vbi_output(file,
855 fh, f);
856 break;
Hans Verkuilb2787842007-04-27 12:31:02 -0300857 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
858 if (vfd->vidioc_enum_fmt_output_overlay)
859 ret=vfd->vidioc_enum_fmt_output_overlay(file, fh, f);
860 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300861 case V4L2_BUF_TYPE_PRIVATE:
862 if (vfd->vidioc_enum_fmt_type_private)
863 ret=vfd->vidioc_enum_fmt_type_private(file,
864 fh, f);
865 break;
866 }
867 if (!ret)
868 dbgarg (cmd, "index=%d, type=%d, flags=%d, "
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300869 "pixelformat=%c%c%c%c, description='%s'\n",
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300870 f->index, f->type, f->flags,
Mauro Carvalho Chehabbf5dbed2006-12-01 12:39:46 -0300871 (f->pixelformat & 0xff),
872 (f->pixelformat >> 8) & 0xff,
873 (f->pixelformat >> 16) & 0xff,
874 (f->pixelformat >> 24) & 0xff,
875 f->description);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300876 break;
877 }
878 case VIDIOC_G_FMT:
879 {
880 struct v4l2_format *f = (struct v4l2_format *)arg;
881 enum v4l2_buf_type type=f->type;
882
883 memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
884 f->type=type;
885
886 /* FIXME: Should be one dump per type */
887 dbgarg (cmd, "type=%s\n", prt_names(type,
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300888 v4l2_type_names));
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300889
890 switch (type) {
891 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
892 if (vfd->vidioc_g_fmt_cap)
893 ret=vfd->vidioc_g_fmt_cap(file, fh, f);
894 if (!ret)
895 v4l_print_pix_fmt(vfd,&f->fmt.pix);
896 break;
897 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
898 if (vfd->vidioc_g_fmt_overlay)
899 ret=vfd->vidioc_g_fmt_overlay(file, fh, f);
900 break;
901 case V4L2_BUF_TYPE_VBI_CAPTURE:
902 if (vfd->vidioc_g_fmt_vbi)
903 ret=vfd->vidioc_g_fmt_vbi(file, fh, f);
904 break;
905 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
906 if (vfd->vidioc_g_fmt_vbi_output)
907 ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
908 break;
909 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
910 if (vfd->vidioc_g_fmt_vbi_capture)
911 ret=vfd->vidioc_g_fmt_vbi_capture(file, fh, f);
912 break;
913 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
914 if (vfd->vidioc_g_fmt_video_output)
915 ret=vfd->vidioc_g_fmt_video_output(file,
916 fh, f);
917 break;
Hans Verkuilb2787842007-04-27 12:31:02 -0300918 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
919 if (vfd->vidioc_g_fmt_output_overlay)
920 ret=vfd->vidioc_g_fmt_output_overlay(file, fh, f);
921 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300922 case V4L2_BUF_TYPE_VBI_OUTPUT:
923 if (vfd->vidioc_g_fmt_vbi_output)
924 ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
925 break;
926 case V4L2_BUF_TYPE_PRIVATE:
927 if (vfd->vidioc_g_fmt_type_private)
928 ret=vfd->vidioc_g_fmt_type_private(file,
929 fh, f);
930 break;
931 }
932
933 break;
934 }
935 case VIDIOC_S_FMT:
936 {
937 struct v4l2_format *f = (struct v4l2_format *)arg;
938
939 /* FIXME: Should be one dump per type */
940 dbgarg (cmd, "type=%s\n", prt_names(f->type,
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300941 v4l2_type_names));
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300942
943 switch (f->type) {
944 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
945 v4l_print_pix_fmt(vfd,&f->fmt.pix);
946 if (vfd->vidioc_s_fmt_cap)
947 ret=vfd->vidioc_s_fmt_cap(file, fh, f);
948 break;
949 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
950 if (vfd->vidioc_s_fmt_overlay)
951 ret=vfd->vidioc_s_fmt_overlay(file, fh, f);
952 break;
953 case V4L2_BUF_TYPE_VBI_CAPTURE:
954 if (vfd->vidioc_s_fmt_vbi)
955 ret=vfd->vidioc_s_fmt_vbi(file, fh, f);
956 break;
957 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
958 if (vfd->vidioc_s_fmt_vbi_output)
959 ret=vfd->vidioc_s_fmt_vbi_output(file, fh, f);
960 break;
961 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
962 if (vfd->vidioc_s_fmt_vbi_capture)
963 ret=vfd->vidioc_s_fmt_vbi_capture(file, fh, f);
964 break;
965 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
966 if (vfd->vidioc_s_fmt_video_output)
967 ret=vfd->vidioc_s_fmt_video_output(file,
968 fh, f);
969 break;
Hans Verkuilb2787842007-04-27 12:31:02 -0300970 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
971 if (vfd->vidioc_s_fmt_output_overlay)
972 ret=vfd->vidioc_s_fmt_output_overlay(file, fh, f);
973 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300974 case V4L2_BUF_TYPE_VBI_OUTPUT:
975 if (vfd->vidioc_s_fmt_vbi_output)
976 ret=vfd->vidioc_s_fmt_vbi_output(file,
977 fh, f);
978 break;
979 case V4L2_BUF_TYPE_PRIVATE:
980 if (vfd->vidioc_s_fmt_type_private)
981 ret=vfd->vidioc_s_fmt_type_private(file,
982 fh, f);
983 break;
984 }
985 break;
986 }
987 case VIDIOC_TRY_FMT:
988 {
989 struct v4l2_format *f = (struct v4l2_format *)arg;
990
991 /* FIXME: Should be one dump per type */
992 dbgarg (cmd, "type=%s\n", prt_names(f->type,
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -0300993 v4l2_type_names));
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -0300994 switch (f->type) {
995 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
996 if (vfd->vidioc_try_fmt_cap)
997 ret=vfd->vidioc_try_fmt_cap(file, fh, f);
998 if (!ret)
999 v4l_print_pix_fmt(vfd,&f->fmt.pix);
1000 break;
1001 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
1002 if (vfd->vidioc_try_fmt_overlay)
1003 ret=vfd->vidioc_try_fmt_overlay(file, fh, f);
1004 break;
1005 case V4L2_BUF_TYPE_VBI_CAPTURE:
1006 if (vfd->vidioc_try_fmt_vbi)
1007 ret=vfd->vidioc_try_fmt_vbi(file, fh, f);
1008 break;
1009 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
1010 if (vfd->vidioc_try_fmt_vbi_output)
1011 ret=vfd->vidioc_try_fmt_vbi_output(file,
1012 fh, f);
1013 break;
1014 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
1015 if (vfd->vidioc_try_fmt_vbi_capture)
1016 ret=vfd->vidioc_try_fmt_vbi_capture(file,
1017 fh, f);
1018 break;
1019 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1020 if (vfd->vidioc_try_fmt_video_output)
1021 ret=vfd->vidioc_try_fmt_video_output(file,
1022 fh, f);
1023 break;
Hans Verkuilb2787842007-04-27 12:31:02 -03001024 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
1025 if (vfd->vidioc_try_fmt_output_overlay)
1026 ret=vfd->vidioc_try_fmt_output_overlay(file, fh, f);
1027 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001028 case V4L2_BUF_TYPE_VBI_OUTPUT:
1029 if (vfd->vidioc_try_fmt_vbi_output)
1030 ret=vfd->vidioc_try_fmt_vbi_output(file,
1031 fh, f);
1032 break;
1033 case V4L2_BUF_TYPE_PRIVATE:
1034 if (vfd->vidioc_try_fmt_type_private)
1035 ret=vfd->vidioc_try_fmt_type_private(file,
1036 fh, f);
1037 break;
1038 }
1039
1040 break;
1041 }
1042 /* FIXME: Those buf reqs could be handled here,
1043 with some changes on videobuf to allow its header to be included at
1044 videodev2.h or being merged at videodev2.
1045 */
1046 case VIDIOC_REQBUFS:
1047 {
1048 struct v4l2_requestbuffers *p=arg;
1049
1050 if (!vfd->vidioc_reqbufs)
1051 break;
1052 ret = check_fmt (vfd, p->type);
1053 if (ret)
1054 break;
1055
1056 ret=vfd->vidioc_reqbufs(file, fh, p);
1057 dbgarg (cmd, "count=%d, type=%s, memory=%s\n",
1058 p->count,
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -03001059 prt_names(p->type, v4l2_type_names),
1060 prt_names(p->memory, v4l2_memory_names));
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001061 break;
1062 }
1063 case VIDIOC_QUERYBUF:
1064 {
1065 struct v4l2_buffer *p=arg;
1066
1067 if (!vfd->vidioc_querybuf)
1068 break;
1069 ret = check_fmt (vfd, p->type);
1070 if (ret)
1071 break;
1072
1073 ret=vfd->vidioc_querybuf(file, fh, p);
1074 if (!ret)
1075 dbgbuf(cmd,vfd,p);
1076 break;
1077 }
1078 case VIDIOC_QBUF:
1079 {
1080 struct v4l2_buffer *p=arg;
1081
1082 if (!vfd->vidioc_qbuf)
1083 break;
1084 ret = check_fmt (vfd, p->type);
1085 if (ret)
1086 break;
1087
1088 ret=vfd->vidioc_qbuf(file, fh, p);
1089 if (!ret)
1090 dbgbuf(cmd,vfd,p);
1091 break;
1092 }
1093 case VIDIOC_DQBUF:
1094 {
1095 struct v4l2_buffer *p=arg;
Sascha Hauerc93a5c32006-09-11 09:49:19 -03001096 if (!vfd->vidioc_dqbuf)
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001097 break;
1098 ret = check_fmt (vfd, p->type);
1099 if (ret)
1100 break;
1101
Sascha Hauerc93a5c32006-09-11 09:49:19 -03001102 ret=vfd->vidioc_dqbuf(file, fh, p);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001103 if (!ret)
1104 dbgbuf(cmd,vfd,p);
1105 break;
1106 }
1107 case VIDIOC_OVERLAY:
1108 {
1109 int *i = arg;
1110
1111 if (!vfd->vidioc_overlay)
1112 break;
1113 dbgarg (cmd, "value=%d\n",*i);
1114 ret=vfd->vidioc_overlay(file, fh, *i);
1115 break;
1116 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001117 case VIDIOC_G_FBUF:
1118 {
1119 struct v4l2_framebuffer *p=arg;
1120 if (!vfd->vidioc_g_fbuf)
1121 break;
1122 ret=vfd->vidioc_g_fbuf(file, fh, arg);
1123 if (!ret) {
1124 dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
1125 p->capability,p->flags,
1126 (unsigned long)p->base);
1127 v4l_print_pix_fmt (vfd, &p->fmt);
1128 }
1129 break;
1130 }
1131 case VIDIOC_S_FBUF:
1132 {
1133 struct v4l2_framebuffer *p=arg;
1134 if (!vfd->vidioc_s_fbuf)
1135 break;
1136
1137 dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
1138 p->capability,p->flags,(unsigned long)p->base);
1139 v4l_print_pix_fmt (vfd, &p->fmt);
1140 ret=vfd->vidioc_s_fbuf(file, fh, arg);
1141
1142 break;
1143 }
1144 case VIDIOC_STREAMON:
1145 {
1146 enum v4l2_buf_type i = *(int *)arg;
1147 if (!vfd->vidioc_streamon)
1148 break;
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -03001149 dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names));
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001150 ret=vfd->vidioc_streamon(file, fh,i);
1151 break;
1152 }
1153 case VIDIOC_STREAMOFF:
1154 {
1155 enum v4l2_buf_type i = *(int *)arg;
1156
1157 if (!vfd->vidioc_streamoff)
1158 break;
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -03001159 dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names));
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001160 ret=vfd->vidioc_streamoff(file, fh, i);
1161 break;
1162 }
1163 /* ---------- tv norms ---------- */
1164 case VIDIOC_ENUMSTD:
1165 {
1166 struct v4l2_standard *p = arg;
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -03001167 v4l2_std_id id = vfd->tvnorms, curr_id = 0;
1168 unsigned int index = p->index, i, j = 0;
1169 const char *descr = "";
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001170
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -03001171 /* Return norm array in a canonical way */
1172 for (i = 0; i <= index && id; i++) {
1173 /* last std value in the standards array is 0, so this
1174 while always ends there since (id & 0) == 0. */
1175 while ((id & standards[j].std) != standards[j].std)
1176 j++;
1177 curr_id = standards[j].std;
1178 descr = standards[j].descr;
1179 j++;
1180 if (curr_id == 0)
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001181 break;
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -03001182 if (curr_id != V4L2_STD_PAL &&
1183 curr_id != V4L2_STD_SECAM &&
1184 curr_id != V4L2_STD_NTSC)
1185 id &= ~curr_id;
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001186 }
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -03001187 if (i <= index)
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001188 return -EINVAL;
1189
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -03001190 v4l2_video_std_construct(p, curr_id, descr);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001191 p->index = index;
1192
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -03001193 dbgarg(cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, "
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001194 "framelines=%d\n", p->index,
1195 (unsigned long long)p->id, p->name,
1196 p->frameperiod.numerator,
1197 p->frameperiod.denominator,
1198 p->framelines);
1199
Hans Verkuil7fa8e6f2008-06-21 13:23:27 -03001200 ret = 0;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001201 break;
1202 }
1203 case VIDIOC_G_STD:
1204 {
1205 v4l2_std_id *id = arg;
1206
1207 *id = vfd->current_norm;
1208
Mauro Carvalho Chehab63736782007-12-13 06:34:12 -03001209 dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001210
1211 ret=0;
1212 break;
1213 }
1214 case VIDIOC_S_STD:
1215 {
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001216 v4l2_std_id *id = arg,norm;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001217
Mauro Carvalho Chehab63736782007-12-13 06:34:12 -03001218 dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001219
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001220 norm = (*id) & vfd->tvnorms;
1221 if ( vfd->tvnorms && !norm) /* Check if std is supported */
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001222 break;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001223
1224 /* Calls the specific handler */
1225 if (vfd->vidioc_s_std)
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001226 ret=vfd->vidioc_s_std(file, fh, &norm);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001227 else
1228 ret=-EINVAL;
1229
1230 /* Updates standard information */
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001231 if (ret>=0)
1232 vfd->current_norm=norm;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001233
1234 break;
1235 }
1236 case VIDIOC_QUERYSTD:
1237 {
1238 v4l2_std_id *p=arg;
1239
1240 if (!vfd->vidioc_querystd)
1241 break;
1242 ret=vfd->vidioc_querystd(file, fh, arg);
1243 if (!ret)
Mauro Carvalho Chehab63736782007-12-13 06:34:12 -03001244 dbgarg (cmd, "detected std=%08Lx\n",
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001245 (unsigned long long)*p);
1246 break;
1247 }
1248 /* ------ input switching ---------- */
1249 /* FIXME: Inputs can be handled inside videodev2 */
1250 case VIDIOC_ENUMINPUT:
1251 {
1252 struct v4l2_input *p=arg;
1253 int i=p->index;
1254
1255 if (!vfd->vidioc_enum_input)
1256 break;
1257 memset(p, 0, sizeof(*p));
1258 p->index=i;
1259
1260 ret=vfd->vidioc_enum_input(file, fh, p);
1261 if (!ret)
1262 dbgarg (cmd, "index=%d, name=%s, type=%d, "
1263 "audioset=%d, "
Mauro Carvalho Chehab63736782007-12-13 06:34:12 -03001264 "tuner=%d, std=%08Lx, status=%d\n",
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001265 p->index,p->name,p->type,p->audioset,
1266 p->tuner,
1267 (unsigned long long)p->std,
1268 p->status);
1269 break;
1270 }
1271 case VIDIOC_G_INPUT:
1272 {
1273 unsigned int *i = arg;
1274
1275 if (!vfd->vidioc_g_input)
1276 break;
1277 ret=vfd->vidioc_g_input(file, fh, i);
1278 if (!ret)
1279 dbgarg (cmd, "value=%d\n",*i);
1280 break;
1281 }
1282 case VIDIOC_S_INPUT:
1283 {
1284 unsigned int *i = arg;
1285
1286 if (!vfd->vidioc_s_input)
1287 break;
1288 dbgarg (cmd, "value=%d\n",*i);
1289 ret=vfd->vidioc_s_input(file, fh, *i);
1290 break;
1291 }
1292
1293 /* ------ output switching ---------- */
1294 case VIDIOC_G_OUTPUT:
1295 {
1296 unsigned int *i = arg;
1297
1298 if (!vfd->vidioc_g_output)
1299 break;
1300 ret=vfd->vidioc_g_output(file, fh, i);
1301 if (!ret)
1302 dbgarg (cmd, "value=%d\n",*i);
1303 break;
1304 }
1305 case VIDIOC_S_OUTPUT:
1306 {
1307 unsigned int *i = arg;
1308
1309 if (!vfd->vidioc_s_output)
1310 break;
1311 dbgarg (cmd, "value=%d\n",*i);
1312 ret=vfd->vidioc_s_output(file, fh, *i);
1313 break;
1314 }
1315
1316 /* --- controls ---------------------------------------------- */
1317 case VIDIOC_QUERYCTRL:
1318 {
1319 struct v4l2_queryctrl *p=arg;
1320
1321 if (!vfd->vidioc_queryctrl)
1322 break;
1323 ret=vfd->vidioc_queryctrl(file, fh, p);
1324
1325 if (!ret)
1326 dbgarg (cmd, "id=%d, type=%d, name=%s, "
1327 "min/max=%d/%d,"
1328 " step=%d, default=%d, flags=0x%08x\n",
1329 p->id,p->type,p->name,p->minimum,
1330 p->maximum,p->step,p->default_value,
1331 p->flags);
1332 break;
1333 }
1334 case VIDIOC_G_CTRL:
1335 {
1336 struct v4l2_control *p = arg;
1337
1338 if (!vfd->vidioc_g_ctrl)
1339 break;
1340 dbgarg(cmd, "Enum for index=%d\n", p->id);
1341
1342 ret=vfd->vidioc_g_ctrl(file, fh, p);
1343 if (!ret)
1344 dbgarg2 ( "id=%d, value=%d\n", p->id, p->value);
1345 break;
1346 }
1347 case VIDIOC_S_CTRL:
1348 {
1349 struct v4l2_control *p = arg;
1350
1351 if (!vfd->vidioc_s_ctrl)
1352 break;
1353 dbgarg (cmd, "id=%d, value=%d\n", p->id, p->value);
1354
1355 ret=vfd->vidioc_s_ctrl(file, fh, p);
1356 break;
1357 }
Hans Verkuil05976912006-06-18 13:43:28 -03001358 case VIDIOC_G_EXT_CTRLS:
1359 {
1360 struct v4l2_ext_controls *p = arg;
1361
1362 if (vfd->vidioc_g_ext_ctrls) {
1363 dbgarg(cmd, "count=%d\n", p->count);
1364
1365 ret=vfd->vidioc_g_ext_ctrls(file, fh, p);
1366 }
1367 break;
1368 }
1369 case VIDIOC_S_EXT_CTRLS:
1370 {
1371 struct v4l2_ext_controls *p = arg;
1372
1373 if (vfd->vidioc_s_ext_ctrls) {
1374 dbgarg(cmd, "count=%d\n", p->count);
1375
1376 ret=vfd->vidioc_s_ext_ctrls(file, fh, p);
1377 }
1378 break;
1379 }
1380 case VIDIOC_TRY_EXT_CTRLS:
1381 {
1382 struct v4l2_ext_controls *p = arg;
1383
1384 if (vfd->vidioc_try_ext_ctrls) {
1385 dbgarg(cmd, "count=%d\n", p->count);
1386
1387 ret=vfd->vidioc_try_ext_ctrls(file, fh, p);
1388 }
1389 break;
1390 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001391 case VIDIOC_QUERYMENU:
1392 {
1393 struct v4l2_querymenu *p=arg;
1394 if (!vfd->vidioc_querymenu)
1395 break;
1396 ret=vfd->vidioc_querymenu(file, fh, p);
1397 if (!ret)
1398 dbgarg (cmd, "id=%d, index=%d, name=%s\n",
1399 p->id,p->index,p->name);
1400 break;
1401 }
1402 /* --- audio ---------------------------------------------- */
1403 case VIDIOC_ENUMAUDIO:
1404 {
1405 struct v4l2_audio *p=arg;
1406
1407 if (!vfd->vidioc_enumaudio)
1408 break;
1409 dbgarg(cmd, "Enum for index=%d\n", p->index);
1410 ret=vfd->vidioc_enumaudio(file, fh, p);
1411 if (!ret)
1412 dbgarg2("index=%d, name=%s, capability=%d, "
1413 "mode=%d\n",p->index,p->name,
1414 p->capability, p->mode);
1415 break;
1416 }
1417 case VIDIOC_G_AUDIO:
1418 {
1419 struct v4l2_audio *p=arg;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001420 __u32 index=p->index;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001421
1422 if (!vfd->vidioc_g_audio)
1423 break;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001424
1425 memset(p,0,sizeof(*p));
1426 p->index=index;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001427 dbgarg(cmd, "Get for index=%d\n", p->index);
1428 ret=vfd->vidioc_g_audio(file, fh, p);
1429 if (!ret)
1430 dbgarg2("index=%d, name=%s, capability=%d, "
1431 "mode=%d\n",p->index,
1432 p->name,p->capability, p->mode);
1433 break;
1434 }
1435 case VIDIOC_S_AUDIO:
1436 {
1437 struct v4l2_audio *p=arg;
1438
1439 if (!vfd->vidioc_s_audio)
1440 break;
1441 dbgarg(cmd, "index=%d, name=%s, capability=%d, "
1442 "mode=%d\n", p->index, p->name,
1443 p->capability, p->mode);
1444 ret=vfd->vidioc_s_audio(file, fh, p);
1445 break;
1446 }
1447 case VIDIOC_ENUMAUDOUT:
1448 {
1449 struct v4l2_audioout *p=arg;
1450
1451 if (!vfd->vidioc_enumaudout)
1452 break;
1453 dbgarg(cmd, "Enum for index=%d\n", p->index);
1454 ret=vfd->vidioc_enumaudout(file, fh, p);
1455 if (!ret)
1456 dbgarg2("index=%d, name=%s, capability=%d, "
1457 "mode=%d\n", p->index, p->name,
1458 p->capability,p->mode);
1459 break;
1460 }
1461 case VIDIOC_G_AUDOUT:
1462 {
1463 struct v4l2_audioout *p=arg;
1464
1465 if (!vfd->vidioc_g_audout)
1466 break;
1467 dbgarg(cmd, "Enum for index=%d\n", p->index);
1468 ret=vfd->vidioc_g_audout(file, fh, p);
1469 if (!ret)
1470 dbgarg2("index=%d, name=%s, capability=%d, "
1471 "mode=%d\n", p->index, p->name,
1472 p->capability,p->mode);
1473 break;
1474 }
1475 case VIDIOC_S_AUDOUT:
1476 {
1477 struct v4l2_audioout *p=arg;
1478
1479 if (!vfd->vidioc_s_audout)
1480 break;
1481 dbgarg(cmd, "index=%d, name=%s, capability=%d, "
1482 "mode=%d\n", p->index, p->name,
1483 p->capability,p->mode);
1484
1485 ret=vfd->vidioc_s_audout(file, fh, p);
1486 break;
1487 }
1488 case VIDIOC_G_MODULATOR:
1489 {
1490 struct v4l2_modulator *p=arg;
1491 if (!vfd->vidioc_g_modulator)
1492 break;
1493 ret=vfd->vidioc_g_modulator(file, fh, p);
1494 if (!ret)
1495 dbgarg(cmd, "index=%d, name=%s, "
1496 "capability=%d, rangelow=%d,"
1497 " rangehigh=%d, txsubchans=%d\n",
1498 p->index, p->name,p->capability,
1499 p->rangelow, p->rangehigh,
1500 p->txsubchans);
1501 break;
1502 }
1503 case VIDIOC_S_MODULATOR:
1504 {
1505 struct v4l2_modulator *p=arg;
1506 if (!vfd->vidioc_s_modulator)
1507 break;
1508 dbgarg(cmd, "index=%d, name=%s, capability=%d, "
1509 "rangelow=%d, rangehigh=%d, txsubchans=%d\n",
1510 p->index, p->name,p->capability,p->rangelow,
1511 p->rangehigh,p->txsubchans);
1512 ret=vfd->vidioc_s_modulator(file, fh, p);
1513 break;
1514 }
1515 case VIDIOC_G_CROP:
1516 {
1517 struct v4l2_crop *p=arg;
1518 if (!vfd->vidioc_g_crop)
1519 break;
1520 ret=vfd->vidioc_g_crop(file, fh, p);
1521 if (!ret) {
1522 dbgarg(cmd, "type=%d\n", p->type);
1523 dbgrect(vfd, "", &p->c);
1524 }
1525 break;
1526 }
1527 case VIDIOC_S_CROP:
1528 {
1529 struct v4l2_crop *p=arg;
1530 if (!vfd->vidioc_s_crop)
1531 break;
1532 dbgarg(cmd, "type=%d\n", p->type);
1533 dbgrect(vfd, "", &p->c);
1534 ret=vfd->vidioc_s_crop(file, fh, p);
1535 break;
1536 }
1537 case VIDIOC_CROPCAP:
1538 {
1539 struct v4l2_cropcap *p=arg;
1540 /*FIXME: Should also show v4l2_fract pixelaspect */
1541 if (!vfd->vidioc_cropcap)
1542 break;
1543 dbgarg(cmd, "type=%d\n", p->type);
1544 dbgrect(vfd, "bounds ", &p->bounds);
1545 dbgrect(vfd, "defrect ", &p->defrect);
1546 ret=vfd->vidioc_cropcap(file, fh, p);
1547 break;
1548 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001549 case VIDIOC_G_JPEGCOMP:
1550 {
1551 struct v4l2_jpegcompression *p=arg;
1552 if (!vfd->vidioc_g_jpegcomp)
1553 break;
1554 ret=vfd->vidioc_g_jpegcomp(file, fh, p);
1555 if (!ret)
1556 dbgarg (cmd, "quality=%d, APPn=%d, "
1557 "APP_len=%d, COM_len=%d, "
1558 "jpeg_markers=%d\n",
1559 p->quality,p->APPn,p->APP_len,
1560 p->COM_len,p->jpeg_markers);
1561 break;
1562 }
1563 case VIDIOC_S_JPEGCOMP:
1564 {
1565 struct v4l2_jpegcompression *p=arg;
1566 if (!vfd->vidioc_g_jpegcomp)
1567 break;
1568 dbgarg (cmd, "quality=%d, APPn=%d, APP_len=%d, "
1569 "COM_len=%d, jpeg_markers=%d\n",
1570 p->quality,p->APPn,p->APP_len,
1571 p->COM_len,p->jpeg_markers);
1572 ret=vfd->vidioc_s_jpegcomp(file, fh, p);
1573 break;
1574 }
Hans Verkuildb6eb5b2007-02-18 14:05:02 -03001575 case VIDIOC_G_ENC_INDEX:
1576 {
1577 struct v4l2_enc_idx *p=arg;
1578
1579 if (!vfd->vidioc_g_enc_index)
1580 break;
1581 ret=vfd->vidioc_g_enc_index(file, fh, p);
1582 if (!ret)
1583 dbgarg (cmd, "entries=%d, entries_cap=%d\n",
1584 p->entries,p->entries_cap);
1585 break;
1586 }
Hans Verkuilada6ecd2007-02-18 14:56:22 -03001587 case VIDIOC_ENCODER_CMD:
1588 {
1589 struct v4l2_encoder_cmd *p=arg;
1590
1591 if (!vfd->vidioc_encoder_cmd)
1592 break;
1593 ret=vfd->vidioc_encoder_cmd(file, fh, p);
1594 if (!ret)
1595 dbgarg (cmd, "cmd=%d, flags=%d\n",
1596 p->cmd,p->flags);
1597 break;
1598 }
1599 case VIDIOC_TRY_ENCODER_CMD:
1600 {
1601 struct v4l2_encoder_cmd *p=arg;
1602
1603 if (!vfd->vidioc_try_encoder_cmd)
1604 break;
1605 ret=vfd->vidioc_try_encoder_cmd(file, fh, p);
1606 if (!ret)
1607 dbgarg (cmd, "cmd=%d, flags=%d\n",
1608 p->cmd,p->flags);
1609 break;
1610 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001611 case VIDIOC_G_PARM:
1612 {
1613 struct v4l2_streamparm *p=arg;
Mauro Carvalho Chehab2aa23422007-04-24 13:40:07 -03001614 __u32 type=p->type;
1615
1616 memset(p,0,sizeof(*p));
1617 p->type=type;
1618
Mauro Carvalho Chehab1c2d0342006-09-14 13:36:34 -03001619 if (vfd->vidioc_g_parm) {
1620 ret=vfd->vidioc_g_parm(file, fh, p);
1621 } else {
1622 struct v4l2_standard s;
Mauro Carvalho Chehab1c2d0342006-09-14 13:36:34 -03001623
1624 if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1625 return -EINVAL;
1626
Jonathan Corbet83427ac2006-10-13 07:51:16 -03001627 v4l2_video_std_construct(&s, vfd->current_norm,
Mauro Carvalho Chehabe75f9ce2006-11-20 13:19:20 -03001628 v4l2_norm_to_name(vfd->current_norm));
Mauro Carvalho Chehab1c2d0342006-09-14 13:36:34 -03001629
Mauro Carvalho Chehab1c2d0342006-09-14 13:36:34 -03001630 p->parm.capture.timeperframe = s.frameperiod;
1631 ret=0;
1632 }
1633
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001634 dbgarg (cmd, "type=%d\n", p->type);
1635 break;
1636 }
1637 case VIDIOC_S_PARM:
1638 {
1639 struct v4l2_streamparm *p=arg;
1640 if (!vfd->vidioc_s_parm)
1641 break;
1642 dbgarg (cmd, "type=%d\n", p->type);
1643 ret=vfd->vidioc_s_parm(file, fh, p);
1644 break;
1645 }
1646 case VIDIOC_G_TUNER:
1647 {
1648 struct v4l2_tuner *p=arg;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001649 __u32 index=p->index;
1650
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001651 if (!vfd->vidioc_g_tuner)
1652 break;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001653
1654 memset(p,0,sizeof(*p));
1655 p->index=index;
1656
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001657 ret=vfd->vidioc_g_tuner(file, fh, p);
1658 if (!ret)
1659 dbgarg (cmd, "index=%d, name=%s, type=%d, "
1660 "capability=%d, rangelow=%d, "
1661 "rangehigh=%d, signal=%d, afc=%d, "
1662 "rxsubchans=%d, audmode=%d\n",
1663 p->index, p->name, p->type,
1664 p->capability, p->rangelow,
1665 p->rangehigh, p->rxsubchans,
1666 p->audmode, p->signal, p->afc);
1667 break;
1668 }
1669 case VIDIOC_S_TUNER:
1670 {
1671 struct v4l2_tuner *p=arg;
1672 if (!vfd->vidioc_s_tuner)
1673 break;
1674 dbgarg (cmd, "index=%d, name=%s, type=%d, "
1675 "capability=%d, rangelow=%d, rangehigh=%d, "
1676 "signal=%d, afc=%d, rxsubchans=%d, "
1677 "audmode=%d\n",p->index, p->name, p->type,
1678 p->capability, p->rangelow,p->rangehigh,
1679 p->rxsubchans, p->audmode, p->signal,
1680 p->afc);
1681 ret=vfd->vidioc_s_tuner(file, fh, p);
1682 break;
1683 }
1684 case VIDIOC_G_FREQUENCY:
1685 {
1686 struct v4l2_frequency *p=arg;
1687 if (!vfd->vidioc_g_frequency)
1688 break;
Mauro Carvalho Chehab7964b1b2006-11-20 12:10:43 -03001689
1690 memset(p,0,sizeof(*p));
1691
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001692 ret=vfd->vidioc_g_frequency(file, fh, p);
1693 if (!ret)
1694 dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
1695 p->tuner,p->type,p->frequency);
1696 break;
1697 }
1698 case VIDIOC_S_FREQUENCY:
1699 {
1700 struct v4l2_frequency *p=arg;
1701 if (!vfd->vidioc_s_frequency)
1702 break;
1703 dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
1704 p->tuner,p->type,p->frequency);
1705 ret=vfd->vidioc_s_frequency(file, fh, p);
1706 break;
1707 }
1708 case VIDIOC_G_SLICED_VBI_CAP:
1709 {
1710 struct v4l2_sliced_vbi_cap *p=arg;
1711 if (!vfd->vidioc_g_sliced_vbi_cap)
1712 break;
1713 ret=vfd->vidioc_g_sliced_vbi_cap(file, fh, p);
1714 if (!ret)
1715 dbgarg (cmd, "service_set=%d\n", p->service_set);
1716 break;
1717 }
1718 case VIDIOC_LOG_STATUS:
1719 {
1720 if (!vfd->vidioc_log_status)
1721 break;
1722 ret=vfd->vidioc_log_status(file, fh);
1723 break;
1724 }
Trent Piephodbbff482007-01-22 23:31:53 -03001725#ifdef CONFIG_VIDEO_ADV_DEBUG
Trent Piepho52ebc762007-01-23 22:38:13 -03001726 case VIDIOC_DBG_G_REGISTER:
Trent Piephodbbff482007-01-22 23:31:53 -03001727 {
1728 struct v4l2_register *p=arg;
Trent Piepho62d50ad2007-01-30 23:25:41 -03001729 if (!capable(CAP_SYS_ADMIN))
1730 ret=-EPERM;
1731 else if (vfd->vidioc_g_register)
Trent Piephodbbff482007-01-22 23:31:53 -03001732 ret=vfd->vidioc_g_register(file, fh, p);
1733 break;
1734 }
Trent Piepho52ebc762007-01-23 22:38:13 -03001735 case VIDIOC_DBG_S_REGISTER:
Trent Piephodbbff482007-01-22 23:31:53 -03001736 {
1737 struct v4l2_register *p=arg;
Trent Piepho52ebc762007-01-23 22:38:13 -03001738 if (!capable(CAP_SYS_ADMIN))
1739 ret=-EPERM;
1740 else if (vfd->vidioc_s_register)
Trent Piephodbbff482007-01-22 23:31:53 -03001741 ret=vfd->vidioc_s_register(file, fh, p);
1742 break;
1743 }
1744#endif
Hans Verkuil3434eb72007-04-27 12:31:08 -03001745 case VIDIOC_G_CHIP_IDENT:
1746 {
1747 struct v4l2_chip_ident *p=arg;
1748 if (!vfd->vidioc_g_chip_ident)
1749 break;
1750 ret=vfd->vidioc_g_chip_ident(file, fh, p);
1751 if (!ret)
1752 dbgarg (cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision);
1753 break;
1754 }
Douglas Schilling Landgraf130ca942008-04-10 01:18:56 -03001755 default:
1756 {
1757 if (!vfd->vidioc_default)
1758 break;
1759 ret = vfd->vidioc_default(file, fh, cmd, arg);
1760 break;
1761 }
Mauro Carvalho Chehab207705c2006-11-20 12:13:25 -03001762 } /* switch */
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001763
1764 if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
1765 if (ret<0) {
Mauro Carvalho Chehabd6849652008-04-13 15:07:16 -03001766 printk("%s: err: on ", vfd->name);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001767 v4l_print_ioctl(vfd->name, cmd);
Mauro Carvalho Chehabd6849652008-04-13 15:07:16 -03001768 printk("\n");
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001769 }
1770 }
1771
1772 return ret;
1773}
1774
1775int video_ioctl2 (struct inode *inode, struct file *file,
1776 unsigned int cmd, unsigned long arg)
1777{
1778 char sbuf[128];
1779 void *mbuf = NULL;
1780 void *parg = NULL;
1781 int err = -EINVAL;
Hans Verkuil05976912006-06-18 13:43:28 -03001782 int is_ext_ctrl;
1783 size_t ctrls_size = 0;
1784 void __user *user_ptr = NULL;
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001785
1786#ifdef __OLD_VIDIOC_
1787 cmd = video_fix_command(cmd);
1788#endif
Hans Verkuil05976912006-06-18 13:43:28 -03001789 is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
1790 cmd == VIDIOC_TRY_EXT_CTRLS);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001791
1792 /* Copy arguments into temp kernel buffer */
1793 switch (_IOC_DIR(cmd)) {
1794 case _IOC_NONE:
1795 parg = NULL;
1796 break;
1797 case _IOC_READ:
1798 case _IOC_WRITE:
1799 case (_IOC_WRITE | _IOC_READ):
1800 if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
1801 parg = sbuf;
1802 } else {
1803 /* too big to allocate from stack */
1804 mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
1805 if (NULL == mbuf)
1806 return -ENOMEM;
1807 parg = mbuf;
1808 }
1809
1810 err = -EFAULT;
1811 if (_IOC_DIR(cmd) & _IOC_WRITE)
1812 if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
1813 goto out;
1814 break;
1815 }
1816
Hans Verkuil05976912006-06-18 13:43:28 -03001817 if (is_ext_ctrl) {
1818 struct v4l2_ext_controls *p = parg;
1819
1820 /* In case of an error, tell the caller that it wasn't
1821 a specific control that caused it. */
1822 p->error_idx = p->count;
1823 user_ptr = (void __user *)p->controls;
1824 if (p->count) {
1825 ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
1826 /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
1827 mbuf = kmalloc(ctrls_size, GFP_KERNEL);
1828 err = -ENOMEM;
1829 if (NULL == mbuf)
1830 goto out_ext_ctrl;
1831 err = -EFAULT;
1832 if (copy_from_user(mbuf, user_ptr, ctrls_size))
1833 goto out_ext_ctrl;
1834 p->controls = mbuf;
1835 }
1836 }
1837
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001838 /* Handles IOCTL */
1839 err = __video_do_ioctl(inode, file, cmd, parg);
1840 if (err == -ENOIOCTLCMD)
1841 err = -EINVAL;
Hans Verkuil05976912006-06-18 13:43:28 -03001842 if (is_ext_ctrl) {
1843 struct v4l2_ext_controls *p = parg;
1844
1845 p->controls = (void *)user_ptr;
1846 if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
1847 err = -EFAULT;
1848 goto out_ext_ctrl;
1849 }
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001850 if (err < 0)
1851 goto out;
1852
Hans Verkuil05976912006-06-18 13:43:28 -03001853out_ext_ctrl:
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001854 /* Copy results into user buffer */
1855 switch (_IOC_DIR(cmd))
1856 {
1857 case _IOC_READ:
1858 case (_IOC_WRITE | _IOC_READ):
1859 if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
1860 err = -EFAULT;
1861 break;
1862 }
1863
1864out:
1865 kfree(mbuf);
1866 return err;
1867}
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -03001868EXPORT_SYMBOL(video_ioctl2);
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03001869
Arjan van de Venfa027c22007-02-12 00:55:33 -08001870static const struct file_operations video_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871
1872/**
1873 * video_register_device - register video4linux devices
1874 * @vfd: video device structure we want to register
1875 * @type: type of device to register
1876 * @nr: which device number (0 == /dev/video0, 1 == /dev/video1, ...
1877 * -1 == first free)
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001878 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 * The registration code assigns minor numbers based on the type
1880 * requested. -ENFILE is returned in all the device slots for this
1881 * category are full. If not then the minor field is set and the
1882 * driver initialize function is called (if non %NULL).
1883 *
1884 * Zero is returned on success.
1885 *
1886 * Valid types are
1887 *
1888 * %VFL_TYPE_GRABBER - A frame grabber
1889 *
1890 * %VFL_TYPE_VTX - A teletext device
1891 *
1892 * %VFL_TYPE_VBI - Vertical blank data (undecoded)
1893 *
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001894 * %VFL_TYPE_RADIO - A radio card
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 */
1896
1897int video_register_device(struct video_device *vfd, int type, int nr)
1898{
1899 int i=0;
1900 int base;
1901 int end;
Michael Krufky3117bee2006-07-19 13:23:38 -03001902 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 char *name_base;
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001904
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 switch(type)
1906 {
1907 case VFL_TYPE_GRABBER:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02001908 base=MINOR_VFL_TYPE_GRABBER_MIN;
1909 end=MINOR_VFL_TYPE_GRABBER_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 name_base = "video";
1911 break;
1912 case VFL_TYPE_VTX:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02001913 base=MINOR_VFL_TYPE_VTX_MIN;
1914 end=MINOR_VFL_TYPE_VTX_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 name_base = "vtx";
1916 break;
1917 case VFL_TYPE_VBI:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02001918 base=MINOR_VFL_TYPE_VBI_MIN;
1919 end=MINOR_VFL_TYPE_VBI_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 name_base = "vbi";
1921 break;
1922 case VFL_TYPE_RADIO:
Mauro Carvalho Chehab4d0dddb2006-01-23 17:11:07 -02001923 base=MINOR_VFL_TYPE_RADIO_MIN;
1924 end=MINOR_VFL_TYPE_RADIO_MAX+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 name_base = "radio";
1926 break;
1927 default:
Trent Piepho53dd8de2006-07-25 09:31:42 -03001928 printk(KERN_ERR "%s called with unknown type: %d\n",
Harvey Harrison7e28adb2008-04-08 23:20:00 -03001929 __func__, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 return -1;
1931 }
1932
1933 /* pick a minor number */
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001934 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 if (nr >= 0 && nr < end-base) {
1936 /* use the one the driver asked for */
1937 i = base+nr;
1938 if (NULL != video_device[i]) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001939 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 return -ENFILE;
1941 }
1942 } else {
1943 /* use first free */
1944 for(i=base;i<end;i++)
1945 if (NULL == video_device[i])
1946 break;
1947 if (i == end) {
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001948 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 return -ENFILE;
1950 }
1951 }
1952 video_device[i]=vfd;
1953 vfd->minor=i;
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001954 mutex_unlock(&videodev_lock);
Ingo Molnar3593cab2006-02-07 06:49:14 -02001955 mutex_init(&vfd->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956
1957 /* sysfs class */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001958 memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 if (vfd->dev)
Kay Sievers54bd5b62007-10-08 16:26:13 -03001960 vfd->class_dev.parent = vfd->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 vfd->class_dev.class = &video_class;
Michael Krufky50c25ff2006-01-09 15:25:34 -02001962 vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
Kay Sievers54bd5b62007-10-08 16:26:13 -03001963 sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base);
1964 ret = device_register(&vfd->class_dev);
Trent Piepho8c313112006-07-25 20:37:03 -03001965 if (ret < 0) {
Kay Sievers54bd5b62007-10-08 16:26:13 -03001966 printk(KERN_ERR "%s: device_register failed\n",
Harvey Harrison7e28adb2008-04-08 23:20:00 -03001967 __func__);
Trent Piephod94fc9a2006-07-29 17:18:06 -03001968 goto fail_minor;
Michael Krufky3117bee2006-07-19 13:23:38 -03001969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970
Mauro Carvalho Chehabd21838d2006-01-09 15:25:21 -02001971#if 1
1972 /* needed until all drivers are fixed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 if (!vfd->release)
1974 printk(KERN_WARNING "videodev: \"%s\" has no release callback. "
1975 "Please fix your driver for proper sysfs support, see "
1976 "http://lwn.net/Articles/36850/\n", vfd->name);
1977#endif
1978 return 0;
Trent Piepho53dd8de2006-07-25 09:31:42 -03001979
Trent Piepho53dd8de2006-07-25 09:31:42 -03001980fail_minor:
1981 mutex_lock(&videodev_lock);
1982 video_device[vfd->minor] = NULL;
1983 vfd->minor = -1;
1984 mutex_unlock(&videodev_lock);
1985 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986}
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -03001987EXPORT_SYMBOL(video_register_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988
1989/**
1990 * video_unregister_device - unregister a video4linux device
1991 * @vfd: the device to unregister
1992 *
1993 * This unregisters the passed device and deassigns the minor
1994 * number. Future open calls will be met with errors.
1995 */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08001996
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997void video_unregister_device(struct video_device *vfd)
1998{
Ingo Molnar1e4baed2006-01-15 07:52:23 -02001999 mutex_lock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 if(video_device[vfd->minor]!=vfd)
2001 panic("videodev: bad unregister");
2002
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 video_device[vfd->minor]=NULL;
Kay Sievers54bd5b62007-10-08 16:26:13 -03002004 device_unregister(&vfd->class_dev);
Ingo Molnar1e4baed2006-01-15 07:52:23 -02002005 mutex_unlock(&videodev_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006}
Mauro Carvalho Chehab057596e2008-02-02 11:25:31 -03002007EXPORT_SYMBOL(video_unregister_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03002009/*
2010 * Video fs operations
2011 */
Arjan van de Venfa027c22007-02-12 00:55:33 -08002012static const struct file_operations video_fops=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013{
2014 .owner = THIS_MODULE,
2015 .llseek = no_llseek,
2016 .open = video_open,
2017};
2018
2019/*
2020 * Initialise video for linux
2021 */
Sigmund Augdal Helberg938606b2005-12-01 00:51:19 -08002022
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023static int __init videodev_init(void)
2024{
2025 int ret;
2026
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03002027 printk(KERN_INFO "Linux video capture interface: v2.00\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) {
2029 printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR);
2030 return -EIO;
2031 }
2032
2033 ret = class_register(&video_class);
2034 if (ret < 0) {
2035 unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME);
2036 printk(KERN_WARNING "video_dev: class_register failed\n");
2037 return -EIO;
2038 }
2039
2040 return 0;
2041}
2042
2043static void __exit videodev_exit(void)
2044{
2045 class_unregister(&video_class);
2046 unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME);
2047}
2048
2049module_init(videodev_init)
2050module_exit(videodev_exit)
2051
Mauro Carvalho Chehab401998f2006-06-04 10:06:18 -03002052MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
2053MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054MODULE_LICENSE("GPL");
2055
2056
2057/*
2058 * Local variables:
2059 * c-basic-offset: 8
2060 * End:
2061 */