blob: 110376be5d2b247921d390f5ea1e503d3c82331d [file] [log] [blame]
Philippe De Muytercf664a62006-01-09 15:24:59 -02001/*
2 * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
3 * Separated from fs stuff by Arnd Bergmann <arnd@arndb.de>
4 *
5 * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
6 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
7 * Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
8 * Copyright (C) 2003 Pavel Machek (pavel@suse.cz)
9 * Copyright (C) 2005 Philippe De Muyter (phdm@macqel.be)
Hans Verkuil92f45ba2008-12-21 10:35:25 -030010 * Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
Philippe De Muytercf664a62006-01-09 15:24:59 -020011 *
12 * These routines maintain argument size conversion between 32bit and 64bit
13 * ioctls.
14 */
15
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -020016#include <linux/compat.h>
Hans Verkuil92f45ba2008-12-21 10:35:25 -030017#define __OLD_VIDIOC_ /* To allow fixing old calls*/
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -020018#include <linux/videodev.h>
Philippe De Muytercf664a62006-01-09 15:24:59 -020019#include <linux/videodev2.h>
Nickolay V. Shmyrev133b7352006-01-09 15:24:58 -020020#include <linux/module.h>
Hans Verkuile8efb712006-01-09 15:24:59 -020021#include <linux/smp_lock.h>
Mauro Carvalho Chehab28644622008-07-20 20:26:54 -030022#include <media/v4l2-ioctl.h>
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -020023
24#ifdef CONFIG_COMPAT
Guy Martina113bc72006-01-11 23:40:51 -020025
Mauro Carvalho Chehab5bdd6cc2006-07-25 16:17:54 -030026#ifdef CONFIG_VIDEO_V4L1_COMPAT
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -020027struct video_tuner32 {
28 compat_int_t tuner;
29 char name[32];
30 compat_ulong_t rangelow, rangehigh;
31 u32 flags; /* It is really u32 in videodev.h */
32 u16 mode, signal;
33};
34
35static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
36{
Hans Verkuild1f81da2008-10-22 00:04:45 -030037 if (!access_ok(VERIFY_READ, up, sizeof(struct video_tuner32)) ||
Guy Martina113bc72006-01-11 23:40:51 -020038 get_user(kp->tuner, &up->tuner) ||
39 copy_from_user(kp->name, up->name, 32) ||
40 get_user(kp->rangelow, &up->rangelow) ||
41 get_user(kp->rangehigh, &up->rangehigh) ||
42 get_user(kp->flags, &up->flags) ||
43 get_user(kp->mode, &up->mode) ||
44 get_user(kp->signal, &up->signal))
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -020045 return -EFAULT;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -020046 return 0;
47}
48
49static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
50{
Hans Verkuild1f81da2008-10-22 00:04:45 -030051 if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_tuner32)) ||
Guy Martina113bc72006-01-11 23:40:51 -020052 put_user(kp->tuner, &up->tuner) ||
53 copy_to_user(up->name, kp->name, 32) ||
54 put_user(kp->rangelow, &up->rangelow) ||
55 put_user(kp->rangehigh, &up->rangehigh) ||
56 put_user(kp->flags, &up->flags) ||
57 put_user(kp->mode, &up->mode) ||
58 put_user(kp->signal, &up->signal))
59 return -EFAULT;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -020060 return 0;
61}
62
63struct video_buffer32 {
64 compat_caddr_t base;
65 compat_int_t height, width, depth, bytesperline;
66};
67
68static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
69{
70 u32 tmp;
71
Guy Martina113bc72006-01-11 23:40:51 -020072 if (!access_ok(VERIFY_READ, up, sizeof(struct video_buffer32)) ||
73 get_user(tmp, &up->base) ||
74 get_user(kp->height, &up->height) ||
75 get_user(kp->width, &up->width) ||
76 get_user(kp->depth, &up->depth) ||
77 get_user(kp->bytesperline, &up->bytesperline))
78 return -EFAULT;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -020079
80 /* This is actually a physical address stored
81 * as a void pointer.
82 */
83 kp->base = (void *)(unsigned long) tmp;
84
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -020085 return 0;
86}
87
88static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
89{
90 u32 tmp = (u32)((unsigned long)kp->base);
91
Hans Verkuild1f81da2008-10-22 00:04:45 -030092 if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_buffer32)) ||
Guy Martina113bc72006-01-11 23:40:51 -020093 put_user(tmp, &up->base) ||
94 put_user(kp->height, &up->height) ||
95 put_user(kp->width, &up->width) ||
96 put_user(kp->depth, &up->depth) ||
97 put_user(kp->bytesperline, &up->bytesperline))
98 return -EFAULT;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -020099 return 0;
100}
101
102struct video_clip32 {
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300103 s32 x, y, width, height; /* It's really s32 in videodev.h */
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200104 compat_caddr_t next;
105};
106
107struct video_window32 {
108 u32 x, y, width, height, chromakey, flags;
109 compat_caddr_t clips;
110 compat_int_t clipcount;
111};
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300112
113static int get_video_window32(struct video_window *kp, struct video_window32 __user *up)
114{
115 struct video_clip __user *uclips;
116 struct video_clip __user *kclips;
117 compat_caddr_t p;
118 int nclips;
119
120 if (!access_ok(VERIFY_READ, up, sizeof(struct video_window32)))
121 return -EFAULT;
122
123 if (get_user(nclips, &up->clipcount))
124 return -EFAULT;
125
126 if (!access_ok(VERIFY_READ, up, sizeof(struct video_window32)) ||
127 get_user(kp->x, &up->x) ||
128 get_user(kp->y, &up->y) ||
129 get_user(kp->width, &up->width) ||
130 get_user(kp->height, &up->height) ||
131 get_user(kp->chromakey, &up->chromakey) ||
132 get_user(kp->flags, &up->flags) ||
133 get_user(kp->clipcount, &up->clipcount))
134 return -EFAULT;
135
136 nclips = kp->clipcount;
137 kp->clips = NULL;
138
139 if (nclips == 0)
140 return 0;
141 if (get_user(p, &up->clips))
142 return -EFAULT;
143 uclips = compat_ptr(p);
144
145 /* If nclips < 0, then it is a clipping bitmap of size
146 VIDEO_CLIPMAP_SIZE */
147 if (nclips < 0) {
148 if (!access_ok(VERIFY_READ, uclips, VIDEO_CLIPMAP_SIZE))
149 return -EFAULT;
150 kp->clips = compat_alloc_user_space(VIDEO_CLIPMAP_SIZE);
151 if (copy_in_user(kp->clips, uclips, VIDEO_CLIPMAP_SIZE))
152 return -EFAULT;
153 return 0;
154 }
155
156 /* Otherwise it is an array of video_clip structs. */
157 if (!access_ok(VERIFY_READ, uclips, nclips * sizeof(struct video_clip)))
158 return -EFAULT;
159
160 kp->clips = compat_alloc_user_space(nclips * sizeof(struct video_clip));
161 kclips = kp->clips;
162 while (nclips--) {
163 int err;
164
165 err = copy_in_user(&kclips->x, &uclips->x, sizeof(kclips->x));
166 err |= copy_in_user(&kclips->y, &uclips->y, sizeof(kclips->y));
167 err |= copy_in_user(&kclips->width, &uclips->width, sizeof(kclips->width));
168 err |= copy_in_user(&kclips->height, &uclips->height, sizeof(kclips->height));
169 kclips->next = NULL;
170 if (err)
171 return -EFAULT;
172 kclips++;
173 uclips++;
174 }
175 return 0;
176}
177
178/* You get back everything except the clips... */
179static int put_video_window32(struct video_window *kp, struct video_window32 __user *up)
180{
181 if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_window32)) ||
182 put_user(kp->x, &up->x) ||
183 put_user(kp->y, &up->y) ||
184 put_user(kp->width, &up->width) ||
185 put_user(kp->height, &up->height) ||
186 put_user(kp->chromakey, &up->chromakey) ||
187 put_user(kp->flags, &up->flags) ||
188 put_user(kp->clipcount, &up->clipcount))
189 return -EFAULT;
190 return 0;
191}
192
193struct video_code32 {
194 char loadwhat[16]; /* name or tag of file being passed */
195 compat_int_t datasize;
196 unsigned char *data;
197};
198
199static int get_microcode32(struct video_code *kp, struct video_code32 __user *up)
200{
201 if (!access_ok(VERIFY_READ, up, sizeof(struct video_code32)) ||
202 copy_from_user(kp->loadwhat, up->loadwhat, sizeof(up->loadwhat)) ||
203 get_user(kp->datasize, &up->datasize) ||
204 copy_from_user(kp->data, up->data, up->datasize))
205 return -EFAULT;
206 return 0;
207}
208
209#define VIDIOCGTUNER32 _IOWR('v', 4, struct video_tuner32)
210#define VIDIOCSTUNER32 _IOW('v', 5, struct video_tuner32)
211#define VIDIOCGWIN32 _IOR('v', 9, struct video_window32)
212#define VIDIOCSWIN32 _IOW('v', 10, struct video_window32)
213#define VIDIOCGFBUF32 _IOR('v', 11, struct video_buffer32)
214#define VIDIOCSFBUF32 _IOW('v', 12, struct video_buffer32)
215#define VIDIOCGFREQ32 _IOR('v', 14, u32)
216#define VIDIOCSFREQ32 _IOW('v', 15, u32)
217#define VIDIOCSMICROCODE32 _IOW('v', 27, struct video_code32)
218
219#define VIDIOCCAPTURE32 _IOW('v', 8, s32)
220#define VIDIOCSYNC32 _IOW('v', 18, s32)
221#define VIDIOCSWRITEMODE32 _IOW('v', 25, s32)
222
Mauro Carvalho Chehab5bdd6cc2006-07-25 16:17:54 -0300223#endif
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200224
Hans Verkuil069b7472008-12-30 07:04:34 -0300225static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200226{
Hans Verkuil069b7472008-12-30 07:04:34 -0300227 long ret = -ENOIOCTLCMD;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200228
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200229 if (file->f_op->unlocked_ioctl)
230 ret = file->f_op->unlocked_ioctl(file, cmd, arg);
231 else if (file->f_op->ioctl) {
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200232 lock_kernel();
Josef Sipek723731b2006-12-08 02:37:47 -0800233 ret = file->f_op->ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200234 unlock_kernel();
235 }
236
237 return ret;
238}
239
240
Hans Verkuild1f81da2008-10-22 00:04:45 -0300241struct v4l2_clip32 {
Philippe De Muytercf664a62006-01-09 15:24:59 -0200242 struct v4l2_rect c;
243 compat_caddr_t next;
244};
245
Hans Verkuild1f81da2008-10-22 00:04:45 -0300246struct v4l2_window32 {
Philippe De Muytercf664a62006-01-09 15:24:59 -0200247 struct v4l2_rect w;
248 enum v4l2_field field;
249 __u32 chromakey;
250 compat_caddr_t clips; /* actually struct v4l2_clip32 * */
251 __u32 clipcount;
252 compat_caddr_t bitmap;
253};
254
255static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
256{
Guy Martina113bc72006-01-11 23:40:51 -0200257 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) ||
258 copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
259 get_user(kp->field, &up->field) ||
260 get_user(kp->chromakey, &up->chromakey) ||
261 get_user(kp->clipcount, &up->clipcount))
262 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200263 if (kp->clipcount > 2048)
264 return -EINVAL;
265 if (kp->clipcount) {
Al Viro5b1a43d2006-02-01 05:24:20 -0500266 struct v4l2_clip32 __user *uclips;
267 struct v4l2_clip __user *kclips;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200268 int n = kp->clipcount;
Al Viro5b1a43d2006-02-01 05:24:20 -0500269 compat_caddr_t p;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200270
Al Viro5b1a43d2006-02-01 05:24:20 -0500271 if (get_user(p, &up->clips))
272 return -EFAULT;
273 uclips = compat_ptr(p);
Philippe De Muytercf664a62006-01-09 15:24:59 -0200274 kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
275 kp->clips = kclips;
276 while (--n >= 0) {
Al Viro5b1a43d2006-02-01 05:24:20 -0500277 if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
Guy Martina113bc72006-01-11 23:40:51 -0200278 return -EFAULT;
Al Viro5b1a43d2006-02-01 05:24:20 -0500279 if (put_user(n ? kclips + 1 : NULL, &kclips->next))
280 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200281 uclips += 1;
282 kclips += 1;
283 }
284 } else
Al Viro5b1a43d2006-02-01 05:24:20 -0500285 kp->clips = NULL;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200286 return 0;
287}
288
289static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
290{
Al Viro5b1a43d2006-02-01 05:24:20 -0500291 if (copy_to_user(&up->w, &kp->w, sizeof(up->w)) ||
Guy Martina113bc72006-01-11 23:40:51 -0200292 put_user(kp->field, &up->field) ||
293 put_user(kp->chromakey, &up->chromakey) ||
294 put_user(kp->clipcount, &up->clipcount))
295 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200296 return 0;
297}
298
299static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
300{
Al Viro5b1a43d2006-02-01 05:24:20 -0500301 if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format)))
302 return -EFAULT;
Guy Martina113bc72006-01-11 23:40:51 -0200303 return 0;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200304}
305
306static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
307{
Al Viro5b1a43d2006-02-01 05:24:20 -0500308 if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
309 return -EFAULT;
Guy Martina113bc72006-01-11 23:40:51 -0200310 return 0;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200311}
312
313static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
314{
Al Viro5b1a43d2006-02-01 05:24:20 -0500315 if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
316 return -EFAULT;
Guy Martina113bc72006-01-11 23:40:51 -0200317 return 0;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200318}
319
320static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
321{
Al Viro5b1a43d2006-02-01 05:24:20 -0500322 if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format)))
323 return -EFAULT;
Guy Martina113bc72006-01-11 23:40:51 -0200324 return 0;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200325}
326
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300327static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
328{
329 if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
330 return -EFAULT;
331 return 0;
332}
333
334static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
335{
336 if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
337 return -EFAULT;
338 return 0;
339}
340
Hans Verkuild1f81da2008-10-22 00:04:45 -0300341struct v4l2_format32 {
Philippe De Muytercf664a62006-01-09 15:24:59 -0200342 enum v4l2_buf_type type;
Hans Verkuild1f81da2008-10-22 00:04:45 -0300343 union {
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300344 struct v4l2_pix_format pix;
345 struct v4l2_window32 win;
346 struct v4l2_vbi_format vbi;
347 struct v4l2_sliced_vbi_format sliced;
Hans Verkuild1f81da2008-10-22 00:04:45 -0300348 __u8 raw_data[200]; /* user-defined */
Philippe De Muytercf664a62006-01-09 15:24:59 -0200349 } fmt;
350};
351
352static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
353{
Guy Martina113bc72006-01-11 23:40:51 -0200354 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) ||
355 get_user(kp->type, &up->type))
356 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200357 switch (kp->type) {
358 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300359 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
Philippe De Muytercf664a62006-01-09 15:24:59 -0200360 return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
361 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300362 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
Philippe De Muytercf664a62006-01-09 15:24:59 -0200363 return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
364 case V4L2_BUF_TYPE_VBI_CAPTURE:
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300365 case V4L2_BUF_TYPE_VBI_OUTPUT:
Philippe De Muytercf664a62006-01-09 15:24:59 -0200366 return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300367 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
368 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
369 return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
370 case V4L2_BUF_TYPE_PRIVATE:
371 if (copy_from_user(kp, up, sizeof(kp->fmt.raw_data)))
372 return -EFAULT;
373 return 0;
374 case 0:
375 return -EINVAL;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200376 default:
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300377 printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
Philippe De Muytercf664a62006-01-09 15:24:59 -0200378 kp->type);
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300379 return -EINVAL;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200380 }
381}
382
383static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
384{
Hans Verkuild1f81da2008-10-22 00:04:45 -0300385 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
Guy Martina113bc72006-01-11 23:40:51 -0200386 put_user(kp->type, &up->type))
Philippe De Muytercf664a62006-01-09 15:24:59 -0200387 return -EFAULT;
388 switch (kp->type) {
389 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300390 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
Philippe De Muytercf664a62006-01-09 15:24:59 -0200391 return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
392 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300393 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
Philippe De Muytercf664a62006-01-09 15:24:59 -0200394 return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
395 case V4L2_BUF_TYPE_VBI_CAPTURE:
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300396 case V4L2_BUF_TYPE_VBI_OUTPUT:
Philippe De Muytercf664a62006-01-09 15:24:59 -0200397 return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300398 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
399 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
400 return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
401 case V4L2_BUF_TYPE_PRIVATE:
402 if (copy_to_user(up, kp, sizeof(up->fmt.raw_data)))
403 return -EFAULT;
404 return 0;
405 case 0:
406 return -EINVAL;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200407 default:
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300408 printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
409 kp->type);
410 return -EINVAL;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200411 }
412}
413
Hans Verkuild1f81da2008-10-22 00:04:45 -0300414struct v4l2_standard32 {
Philippe De Muytercf664a62006-01-09 15:24:59 -0200415 __u32 index;
416 __u32 id[2]; /* __u64 would get the alignment wrong */
417 __u8 name[24];
418 struct v4l2_fract frameperiod; /* Frames, not fields */
419 __u32 framelines;
420 __u32 reserved[4];
421};
422
423static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
424{
425 /* other fields are not set by the user, nor used by the driver */
Guy Martina113bc72006-01-11 23:40:51 -0200426 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
427 get_user(kp->index, &up->index))
428 return -EFAULT;
429 return 0;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200430}
431
432static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
433{
Hans Verkuild1f81da2008-10-22 00:04:45 -0300434 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
Guy Martina113bc72006-01-11 23:40:51 -0200435 put_user(kp->index, &up->index) ||
436 copy_to_user(up->id, &kp->id, sizeof(__u64)) ||
437 copy_to_user(up->name, kp->name, 24) ||
438 copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
439 put_user(kp->framelines, &up->framelines) ||
440 copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
441 return -EFAULT;
442 return 0;
443}
444
Hans Verkuild1f81da2008-10-22 00:04:45 -0300445struct v4l2_buffer32 {
Philippe De Muytercf664a62006-01-09 15:24:59 -0200446 __u32 index;
447 enum v4l2_buf_type type;
448 __u32 bytesused;
449 __u32 flags;
450 enum v4l2_field field;
451 struct compat_timeval timestamp;
452 struct v4l2_timecode timecode;
453 __u32 sequence;
454
455 /* memory location */
456 enum v4l2_memory memory;
457 union {
458 __u32 offset;
459 compat_long_t userptr;
460 } m;
461 __u32 length;
462 __u32 input;
463 __u32 reserved;
464};
465
466static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
467{
468
Guy Martina113bc72006-01-11 23:40:51 -0200469 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
470 get_user(kp->index, &up->index) ||
471 get_user(kp->type, &up->type) ||
472 get_user(kp->flags, &up->flags) ||
473 get_user(kp->memory, &up->memory) ||
474 get_user(kp->input, &up->input))
475 return -EFAULT;
Hans Verkuild1f81da2008-10-22 00:04:45 -0300476 switch (kp->memory) {
Philippe De Muytercf664a62006-01-09 15:24:59 -0200477 case V4L2_MEMORY_MMAP:
478 break;
479 case V4L2_MEMORY_USERPTR:
480 {
Al Viro5b1a43d2006-02-01 05:24:20 -0500481 compat_long_t tmp;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200482
Al Viro5b1a43d2006-02-01 05:24:20 -0500483 if (get_user(kp->length, &up->length) ||
484 get_user(tmp, &up->m.userptr))
485 return -EFAULT;
486
487 kp->m.userptr = (unsigned long)compat_ptr(tmp);
Philippe De Muytercf664a62006-01-09 15:24:59 -0200488 }
489 break;
490 case V4L2_MEMORY_OVERLAY:
Hans Verkuild1f81da2008-10-22 00:04:45 -0300491 if (get_user(kp->m.offset, &up->m.offset))
Guy Martina113bc72006-01-11 23:40:51 -0200492 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200493 break;
494 }
495 return 0;
496}
497
498static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
499{
Guy Martina113bc72006-01-11 23:40:51 -0200500 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
501 put_user(kp->index, &up->index) ||
502 put_user(kp->type, &up->type) ||
503 put_user(kp->flags, &up->flags) ||
504 put_user(kp->memory, &up->memory) ||
505 put_user(kp->input, &up->input))
506 return -EFAULT;
Hans Verkuild1f81da2008-10-22 00:04:45 -0300507 switch (kp->memory) {
Philippe De Muytercf664a62006-01-09 15:24:59 -0200508 case V4L2_MEMORY_MMAP:
Guy Martina113bc72006-01-11 23:40:51 -0200509 if (put_user(kp->length, &up->length) ||
510 put_user(kp->m.offset, &up->m.offset))
511 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200512 break;
513 case V4L2_MEMORY_USERPTR:
Guy Martina113bc72006-01-11 23:40:51 -0200514 if (put_user(kp->length, &up->length) ||
515 put_user(kp->m.userptr, &up->m.userptr))
516 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200517 break;
518 case V4L2_MEMORY_OVERLAY:
Guy Martina113bc72006-01-11 23:40:51 -0200519 if (put_user(kp->m.offset, &up->m.offset))
520 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200521 break;
522 }
Guy Martina113bc72006-01-11 23:40:51 -0200523 if (put_user(kp->bytesused, &up->bytesused) ||
524 put_user(kp->field, &up->field) ||
525 put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
526 put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
527 copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
528 put_user(kp->sequence, &up->sequence) ||
529 put_user(kp->reserved, &up->reserved))
530 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200531 return 0;
532}
533
Hans Verkuild1f81da2008-10-22 00:04:45 -0300534struct v4l2_framebuffer32 {
Philippe De Muytercf664a62006-01-09 15:24:59 -0200535 __u32 capability;
536 __u32 flags;
537 compat_caddr_t base;
538 struct v4l2_pix_format fmt;
539};
540
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200541static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
542{
543 u32 tmp;
544
Guy Martina113bc72006-01-11 23:40:51 -0200545 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) ||
546 get_user(tmp, &up->base) ||
547 get_user(kp->capability, &up->capability) ||
548 get_user(kp->flags, &up->flags))
549 return -EFAULT;
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200550 kp->base = compat_ptr(tmp);
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200551 get_v4l2_pix_format(&kp->fmt, &up->fmt);
552 return 0;
553}
554
Philippe De Muytercf664a62006-01-09 15:24:59 -0200555static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
556{
557 u32 tmp = (u32)((unsigned long)kp->base);
558
Hans Verkuild1f81da2008-10-22 00:04:45 -0300559 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
Guy Martina113bc72006-01-11 23:40:51 -0200560 put_user(tmp, &up->base) ||
561 put_user(kp->capability, &up->capability) ||
562 put_user(kp->flags, &up->flags))
563 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200564 put_v4l2_pix_format(&kp->fmt, &up->fmt);
565 return 0;
566}
567
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300568struct v4l2_input32 {
569 __u32 index; /* Which input */
570 __u8 name[32]; /* Label */
571 __u32 type; /* Type of input */
572 __u32 audioset; /* Associated audios (bitfield) */
573 __u32 tuner; /* Associated tuner */
574 v4l2_std_id std;
575 __u32 status;
576 __u32 reserved[4];
577} __attribute__ ((packed));
578
579/* The 64-bit v4l2_input struct has extra padding at the end of the struct.
580 Otherwise it is identical to the 32-bit version. */
581static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
Philippe De Muytercf664a62006-01-09 15:24:59 -0200582{
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300583 if (copy_from_user(kp, up, sizeof(struct v4l2_input32)))
Al Viro5b1a43d2006-02-01 05:24:20 -0500584 return -EFAULT;
Guy Martina113bc72006-01-11 23:40:51 -0200585 return 0;
586}
587
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300588static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
Guy Martina113bc72006-01-11 23:40:51 -0200589{
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300590 if (copy_to_user(up, kp, sizeof(struct v4l2_input32)))
Al Viro5b1a43d2006-02-01 05:24:20 -0500591 return -EFAULT;
Guy Martina113bc72006-01-11 23:40:51 -0200592 return 0;
593}
594
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300595struct v4l2_ext_controls32 {
596 __u32 ctrl_class;
597 __u32 count;
598 __u32 error_idx;
599 __u32 reserved[2];
600 compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
Mauro Carvalho Chehabeb4eecc2006-07-21 18:53:23 -0300601};
602
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300603static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
Mauro Carvalho Chehabeb4eecc2006-07-21 18:53:23 -0300604{
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300605 struct v4l2_ext_control __user *ucontrols;
606 struct v4l2_ext_control __user *kcontrols;
607 int n;
608 compat_caddr_t p;
609
610 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
611 get_user(kp->ctrl_class, &up->ctrl_class) ||
612 get_user(kp->count, &up->count) ||
613 get_user(kp->error_idx, &up->error_idx) ||
614 copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
Mauro Carvalho Chehabeb4eecc2006-07-21 18:53:23 -0300615 return -EFAULT;
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300616 n = kp->count;
617 if (n == 0) {
618 kp->controls = NULL;
619 return 0;
620 }
621 if (get_user(p, &up->controls))
622 return -EFAULT;
623 ucontrols = compat_ptr(p);
624 if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(struct v4l2_ext_control)))
625 return -EFAULT;
626 kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
627 kp->controls = kcontrols;
628 while (--n >= 0) {
629 if (copy_in_user(&kcontrols->id, &ucontrols->id, sizeof(__u32)))
630 return -EFAULT;
631 if (copy_in_user(&kcontrols->reserved2, &ucontrols->reserved2, sizeof(ucontrols->reserved2)))
632 return -EFAULT;
633 /* Note: if the void * part of the union ever becomes relevant
634 then we need to know the type of the control in order to do
635 the right thing here. Luckily, that is not yet an issue. */
636 if (copy_in_user(&kcontrols->value, &ucontrols->value, sizeof(ucontrols->value)))
637 return -EFAULT;
638 ucontrols++;
639 kcontrols++;
640 }
Mauro Carvalho Chehabeb4eecc2006-07-21 18:53:23 -0300641 return 0;
642}
643
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300644static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200645{
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300646 struct v4l2_ext_control __user *ucontrols;
647 struct v4l2_ext_control __user *kcontrols = kp->controls;
648 int n = kp->count;
649 compat_caddr_t p;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200650
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300651 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
652 put_user(kp->ctrl_class, &up->ctrl_class) ||
653 put_user(kp->count, &up->count) ||
654 put_user(kp->error_idx, &up->error_idx) ||
655 copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
656 return -EFAULT;
657 if (!kp->count)
658 return 0;
659
660 if (get_user(p, &up->controls))
661 return -EFAULT;
662 ucontrols = compat_ptr(p);
663 if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(struct v4l2_ext_control)))
Guy Martina113bc72006-01-11 23:40:51 -0200664 return -EFAULT;
665
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300666 while (--n >= 0) {
667 if (copy_in_user(&ucontrols->id, &kcontrols->id, sizeof(__u32)))
668 return -EFAULT;
669 if (copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
670 sizeof(ucontrols->reserved2)))
671 return -EFAULT;
672 /* Note: if the void * part of the union ever becomes relevant
673 then we need to know the type of the control in order to do
674 the right thing here. Luckily, that is not yet an issue. */
675 if (copy_in_user(&ucontrols->value, &kcontrols->value, sizeof(ucontrols->value)))
676 return -EFAULT;
677 ucontrols++;
678 kcontrols++;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200679 }
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300680 return 0;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200681}
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300682
683#define VIDIOC_G_FMT32 _IOWR('V', 4, struct v4l2_format32)
684#define VIDIOC_S_FMT32 _IOWR('V', 5, struct v4l2_format32)
685#define VIDIOC_QUERYBUF32 _IOWR('V', 9, struct v4l2_buffer32)
686#define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32)
687#define VIDIOC_S_FBUF32 _IOW ('V', 11, struct v4l2_framebuffer32)
688#define VIDIOC_QBUF32 _IOWR('V', 15, struct v4l2_buffer32)
689#define VIDIOC_DQBUF32 _IOWR('V', 17, struct v4l2_buffer32)
690#define VIDIOC_ENUMSTD32 _IOWR('V', 25, struct v4l2_standard32)
691#define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32)
692#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32)
693#define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32)
694#define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32)
695#define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32)
696
697#define VIDIOC_OVERLAY32 _IOW ('V', 14, s32)
Hans Verkuil15029b32008-12-21 10:44:24 -0300698#ifdef __OLD_VIDIOC_
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300699#define VIDIOC_OVERLAY32_OLD _IOWR('V', 14, s32)
Hans Verkuil15029b32008-12-21 10:44:24 -0300700#endif
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300701#define VIDIOC_STREAMON32 _IOW ('V', 18, s32)
702#define VIDIOC_STREAMOFF32 _IOW ('V', 19, s32)
703#define VIDIOC_G_INPUT32 _IOR ('V', 38, s32)
704#define VIDIOC_S_INPUT32 _IOWR('V', 39, s32)
705#define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32)
706#define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32)
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200707
Hans Verkuil069b7472008-12-30 07:04:34 -0300708static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200709{
710 union {
Mauro Carvalho Chehab5bdd6cc2006-07-25 16:17:54 -0300711#ifdef CONFIG_VIDEO_V4L1_COMPAT
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200712 struct video_tuner vt;
713 struct video_buffer vb;
714 struct video_window vw;
Mauro Carvalho Chehabeb4eecc2006-07-21 18:53:23 -0300715 struct video_code vc;
Mauro Carvalho Chehab8a36ecf2006-08-06 10:16:27 -0300716 struct video_audio va;
Mauro Carvalho Chehab5bdd6cc2006-07-25 16:17:54 -0300717#endif
Philippe De Muytercf664a62006-01-09 15:24:59 -0200718 struct v4l2_format v2f;
719 struct v4l2_buffer v2b;
720 struct v4l2_framebuffer v2fb;
Guy Martina113bc72006-01-11 23:40:51 -0200721 struct v4l2_input v2i;
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300722 struct v4l2_standard v2s;
723 struct v4l2_ext_controls v2ecs;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200724 unsigned long vx;
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300725 int vi;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200726 } karg;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200727 void __user *up = compat_ptr(arg);
Philippe De Muytercf664a62006-01-09 15:24:59 -0200728 int compatible_arg = 1;
Hans Verkuil069b7472008-12-30 07:04:34 -0300729 long err = 0;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200730
731 /* First, convert the command. */
Hans Verkuild1f81da2008-10-22 00:04:45 -0300732 switch (cmd) {
Mauro Carvalho Chehab5bdd6cc2006-07-25 16:17:54 -0300733#ifdef CONFIG_VIDEO_V4L1_COMPAT
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300734 case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
735 case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
736 case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
737 case VIDIOCSWIN32: cmd = VIDIOCSWIN; break;
738 case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
739 case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
740 case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
741 case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
742 case VIDIOCSMICROCODE32: cmd = VIDIOCSMICROCODE; break;
Mauro Carvalho Chehab5bdd6cc2006-07-25 16:17:54 -0300743#endif
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300744 case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
745 case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
746 case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
747 case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
748 case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
749 case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
750 case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
751 case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break;
752 case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break;
753 case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
754 case VIDIOC_G_EXT_CTRLS32: cmd = VIDIOC_G_EXT_CTRLS; break;
755 case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break;
756 case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break;
757 case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
Hans Verkuil15029b32008-12-21 10:44:24 -0300758#ifdef __OLD_VIDIOC_
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300759 case VIDIOC_OVERLAY32_OLD: cmd = VIDIOC_OVERLAY; break;
Hans Verkuil15029b32008-12-21 10:44:24 -0300760#endif
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300761 case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
762 case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
763 case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
764 case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
765 case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
766 case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
767 }
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200768
Hans Verkuild1f81da2008-10-22 00:04:45 -0300769 switch (cmd) {
Mauro Carvalho Chehab5bdd6cc2006-07-25 16:17:54 -0300770#ifdef CONFIG_VIDEO_V4L1_COMPAT
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200771 case VIDIOCSTUNER:
772 case VIDIOCGTUNER:
773 err = get_video_tuner32(&karg.vt, up);
Philippe De Muytercf664a62006-01-09 15:24:59 -0200774 compatible_arg = 0;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200775 break;
776
777 case VIDIOCSFBUF:
778 err = get_video_buffer32(&karg.vb, up);
Philippe De Muytercf664a62006-01-09 15:24:59 -0200779 compatible_arg = 0;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200780 break;
781
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300782 case VIDIOCSWIN:
783 err = get_video_window32(&karg.vw, up);
784 compatible_arg = 0;
785 break;
786
787 case VIDIOCGWIN:
788 case VIDIOCGFBUF:
789 case VIDIOCGFREQ:
790 compatible_arg = 0;
791 break;
792
793 case VIDIOCSMICROCODE:
794 err = get_microcode32(&karg.vc, up);
795 compatible_arg = 0;
796 break;
Mauro Carvalho Chehab8a36ecf2006-08-06 10:16:27 -0300797
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200798 case VIDIOCSFREQ:
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300799 err = get_user(karg.vx, (u32 __user *)up);
800 compatible_arg = 0;
801 break;
802
803 case VIDIOCCAPTURE:
804 case VIDIOCSYNC:
805 case VIDIOCSWRITEMODE:
Mauro Carvalho Chehab5bdd6cc2006-07-25 16:17:54 -0300806#endif
Philippe De Muytercf664a62006-01-09 15:24:59 -0200807 case VIDIOC_OVERLAY:
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200808 case VIDIOC_STREAMON:
809 case VIDIOC_STREAMOFF:
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300810 case VIDIOC_S_INPUT:
811 case VIDIOC_S_OUTPUT:
812 err = get_user(karg.vi, (s32 __user *)up);
813 compatible_arg = 0;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200814 break;
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200815
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300816 case VIDIOC_G_INPUT:
817 case VIDIOC_G_OUTPUT:
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200818 compatible_arg = 0;
819 break;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200820
821 case VIDIOC_G_FMT:
822 case VIDIOC_S_FMT:
823 case VIDIOC_TRY_FMT:
824 err = get_v4l2_format32(&karg.v2f, up);
825 compatible_arg = 0;
826 break;
827
828 case VIDIOC_QUERYBUF:
829 case VIDIOC_QBUF:
830 case VIDIOC_DQBUF:
831 err = get_v4l2_buffer32(&karg.v2b, up);
832 compatible_arg = 0;
833 break;
834
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300835 case VIDIOC_S_FBUF:
836 err = get_v4l2_framebuffer32(&karg.v2fb, up);
Guy Martina113bc72006-01-11 23:40:51 -0200837 compatible_arg = 0;
838 break;
839
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300840 case VIDIOC_G_FBUF:
841 compatible_arg = 0;
842 break;
843
844 case VIDIOC_ENUMSTD:
Philippe De Muytercf664a62006-01-09 15:24:59 -0200845 err = get_v4l2_standard32(&karg.v2s, up);
846 compatible_arg = 0;
847 break;
848
Guy Martina113bc72006-01-11 23:40:51 -0200849 case VIDIOC_ENUMINPUT:
Guy Martina113bc72006-01-11 23:40:51 -0200850 err = get_v4l2_input32(&karg.v2i, up);
851 compatible_arg = 0;
852 break;
853
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300854 case VIDIOC_G_EXT_CTRLS:
855 case VIDIOC_S_EXT_CTRLS:
856 case VIDIOC_TRY_EXT_CTRLS:
857 err = get_v4l2_ext_controls32(&karg.v2ecs, up);
Guy Martina113bc72006-01-11 23:40:51 -0200858 compatible_arg = 0;
859 break;
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300860 }
Hans Verkuild1f81da2008-10-22 00:04:45 -0300861 if (err)
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300862 return err;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200863
Hans Verkuild1f81da2008-10-22 00:04:45 -0300864 if (compatible_arg)
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300865 err = native_ioctl(file, cmd, (unsigned long)up);
Philippe De Muytercf664a62006-01-09 15:24:59 -0200866 else {
867 mm_segment_t old_fs = get_fs();
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200868
Philippe De Muytercf664a62006-01-09 15:24:59 -0200869 set_fs(KERNEL_DS);
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300870 err = native_ioctl(file, cmd, (unsigned long)&karg);
Philippe De Muytercf664a62006-01-09 15:24:59 -0200871 set_fs(old_fs);
872 }
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200873
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300874 /* Special case: even after an error we need to put the
875 results back for these ioctls since the error_idx will
876 contain information on which control failed. */
877 switch (cmd) {
878 case VIDIOC_G_EXT_CTRLS:
879 case VIDIOC_S_EXT_CTRLS:
880 case VIDIOC_TRY_EXT_CTRLS:
881 if (put_v4l2_ext_controls32(&karg.v2ecs, up))
882 err = -EFAULT;
883 break;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200884 }
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300885 if (err)
886 return err;
887
888 switch (cmd) {
889#ifdef CONFIG_VIDEO_V4L1_COMPAT
890 case VIDIOCGTUNER:
891 err = put_video_tuner32(&karg.vt, up);
892 break;
893
894 case VIDIOCGWIN:
895 err = put_video_window32(&karg.vw, up);
896 break;
897
898 case VIDIOCGFBUF:
899 err = put_video_buffer32(&karg.vb, up);
900 break;
901
902 case VIDIOCGFREQ:
903 err = put_user(((u32)karg.vx), (u32 __user *)up);
904 break;
905#endif
906 case VIDIOC_S_INPUT:
907 case VIDIOC_S_OUTPUT:
908 case VIDIOC_G_INPUT:
909 case VIDIOC_G_OUTPUT:
910 err = put_user(((s32)karg.vi), (s32 __user *)up);
911 break;
912
913 case VIDIOC_G_FBUF:
914 err = put_v4l2_framebuffer32(&karg.v2fb, up);
915 break;
916
917 case VIDIOC_G_FMT:
918 case VIDIOC_S_FMT:
919 case VIDIOC_TRY_FMT:
920 err = put_v4l2_format32(&karg.v2f, up);
921 break;
922
923 case VIDIOC_QUERYBUF:
924 case VIDIOC_QBUF:
925 case VIDIOC_DQBUF:
926 err = put_v4l2_buffer32(&karg.v2b, up);
927 break;
928
929 case VIDIOC_ENUMSTD:
930 err = put_v4l2_standard32(&karg.v2s, up);
931 break;
932
933 case VIDIOC_ENUMINPUT:
934 err = put_v4l2_input32(&karg.v2i, up);
935 break;
936 }
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200937 return err;
938}
939
Hans Verkuil9bb7cde2008-12-30 06:42:40 -0300940long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200941{
Hans Verkuil069b7472008-12-30 07:04:34 -0300942 long ret = -ENOIOCTLCMD;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200943
Hans Verkuil3ca81a52008-12-16 08:32:37 -0300944 if (!file->f_op->ioctl && !file->f_op->unlocked_ioctl)
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200945 return ret;
946
947 switch (cmd) {
Mauro Carvalho Chehab5bdd6cc2006-07-25 16:17:54 -0300948#ifdef CONFIG_VIDEO_V4L1_COMPAT
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300949 case VIDIOCGCAP:
950 case VIDIOCGCHAN:
951 case VIDIOCSCHAN:
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200952 case VIDIOCGTUNER32:
953 case VIDIOCSTUNER32:
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300954 case VIDIOCGPICT:
955 case VIDIOCSPICT:
956 case VIDIOCCAPTURE32:
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200957 case VIDIOCGWIN32:
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300958 case VIDIOCSWIN32:
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200959 case VIDIOCGFBUF32:
960 case VIDIOCSFBUF32:
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300961 case VIDIOCKEY:
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200962 case VIDIOCGFREQ32:
Nickolay V. Shmyrev133b7352006-01-09 15:24:58 -0200963 case VIDIOCSFREQ32:
Mauro Carvalho Chehab8a36ecf2006-08-06 10:16:27 -0300964 case VIDIOCGAUDIO:
965 case VIDIOCSAUDIO:
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300966 case VIDIOCSYNC32:
967 case VIDIOCMCAPTURE:
968 case VIDIOCGMBUF:
969 case VIDIOCGUNIT:
970 case VIDIOCGCAPTURE:
971 case VIDIOCSCAPTURE:
972 case VIDIOCSPLAYMODE:
973 case VIDIOCSWRITEMODE32:
974 case VIDIOCGPLAYINFO:
975 case VIDIOCSMICROCODE32:
Steven Walter7963fa42007-08-09 11:36:35 -0300976 case VIDIOCGVBIFMT:
977 case VIDIOCSVBIFMT:
Mauro Carvalho Chehab5bdd6cc2006-07-25 16:17:54 -0300978#endif
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300979#ifdef __OLD_VIDIOC_
980 case VIDIOC_OVERLAY32_OLD:
981 case VIDIOC_S_PARM_OLD:
982 case VIDIOC_S_CTRL_OLD:
983 case VIDIOC_G_AUDIO_OLD:
984 case VIDIOC_G_AUDOUT_OLD:
985 case VIDIOC_CROPCAP_OLD:
986#endif
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200987 case VIDIOC_QUERYCAP:
Hans Verkuil92f45ba2008-12-21 10:35:25 -0300988 case VIDIOC_RESERVED:
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200989 case VIDIOC_ENUM_FMT:
990 case VIDIOC_G_FMT32:
991 case VIDIOC_S_FMT32:
992 case VIDIOC_REQBUFS:
993 case VIDIOC_QUERYBUF32:
994 case VIDIOC_G_FBUF32:
995 case VIDIOC_S_FBUF32:
996 case VIDIOC_OVERLAY32:
997 case VIDIOC_QBUF32:
998 case VIDIOC_DQBUF32:
999 case VIDIOC_STREAMON32:
1000 case VIDIOC_STREAMOFF32:
1001 case VIDIOC_G_PARM:
Gregor Jasnyc7f09db2008-10-23 09:55:22 -03001002 case VIDIOC_S_PARM:
Philippe De Muyter13d133b2006-01-09 15:25:00 -02001003 case VIDIOC_G_STD:
1004 case VIDIOC_S_STD:
1005 case VIDIOC_ENUMSTD32:
1006 case VIDIOC_ENUMINPUT32:
1007 case VIDIOC_G_CTRL:
Steven Walter7963fa42007-08-09 11:36:35 -03001008 case VIDIOC_S_CTRL:
Hans Verkuil92f45ba2008-12-21 10:35:25 -03001009 case VIDIOC_G_TUNER:
1010 case VIDIOC_S_TUNER:
1011 case VIDIOC_G_AUDIO:
1012 case VIDIOC_S_AUDIO:
Philippe De Muyter13d133b2006-01-09 15:25:00 -02001013 case VIDIOC_QUERYCTRL:
Hans Verkuil92f45ba2008-12-21 10:35:25 -03001014 case VIDIOC_QUERYMENU:
Philippe De Muyter13d133b2006-01-09 15:25:00 -02001015 case VIDIOC_G_INPUT32:
1016 case VIDIOC_S_INPUT32:
Hans Verkuil92f45ba2008-12-21 10:35:25 -03001017 case VIDIOC_G_OUTPUT32:
1018 case VIDIOC_S_OUTPUT32:
1019 case VIDIOC_ENUMOUTPUT:
1020 case VIDIOC_G_AUDOUT:
1021 case VIDIOC_S_AUDOUT:
1022 case VIDIOC_G_MODULATOR:
1023 case VIDIOC_S_MODULATOR:
1024 case VIDIOC_S_FREQUENCY:
1025 case VIDIOC_G_FREQUENCY:
1026 case VIDIOC_CROPCAP:
1027 case VIDIOC_G_CROP:
1028 case VIDIOC_S_CROP:
1029 case VIDIOC_G_JPEGCOMP:
1030 case VIDIOC_S_JPEGCOMP:
1031 case VIDIOC_QUERYSTD:
Philippe De Muyter13d133b2006-01-09 15:25:00 -02001032 case VIDIOC_TRY_FMT32:
Hans Verkuil92f45ba2008-12-21 10:35:25 -03001033 case VIDIOC_ENUMAUDIO:
1034 case VIDIOC_ENUMAUDOUT:
1035 case VIDIOC_G_PRIORITY:
1036 case VIDIOC_S_PRIORITY:
1037 case VIDIOC_G_SLICED_VBI_CAP:
1038 case VIDIOC_LOG_STATUS:
1039 case VIDIOC_G_EXT_CTRLS32:
1040 case VIDIOC_S_EXT_CTRLS32:
1041 case VIDIOC_TRY_EXT_CTRLS32:
Gregor Jasnyc7f09db2008-10-23 09:55:22 -03001042 case VIDIOC_ENUM_FRAMESIZES:
1043 case VIDIOC_ENUM_FRAMEINTERVALS:
Hans Verkuil92f45ba2008-12-21 10:35:25 -03001044 case VIDIOC_G_ENC_INDEX:
1045 case VIDIOC_ENCODER_CMD:
1046 case VIDIOC_TRY_ENCODER_CMD:
1047 case VIDIOC_DBG_S_REGISTER:
1048 case VIDIOC_DBG_G_REGISTER:
Hans Verkuilaecde8b2008-12-30 07:14:19 -03001049 case VIDIOC_DBG_G_CHIP_IDENT:
1050 case VIDIOC_G_CHIP_IDENT_OLD:
Hans Verkuil92f45ba2008-12-21 10:35:25 -03001051 case VIDIOC_S_HW_FREQ_SEEK:
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -02001052 ret = do_video_ioctl(file, cmd, arg);
1053 break;
1054
Mauro Carvalho Chehab5bdd6cc2006-07-25 16:17:54 -03001055#ifdef CONFIG_VIDEO_V4L1_COMPAT
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -02001056 /* BTTV specific... */
1057 case _IOW('v', BASE_VIDIOCPRIVATE+0, char [256]):
1058 case _IOR('v', BASE_VIDIOCPRIVATE+1, char [256]):
1059 case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int):
1060 case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */
1061 case _IOR('v' , BASE_VIDIOCPRIVATE+4, int):
1062 case _IOR('v' , BASE_VIDIOCPRIVATE+5, int):
1063 case _IOR('v' , BASE_VIDIOCPRIVATE+6, int):
1064 case _IOR('v' , BASE_VIDIOCPRIVATE+7, int):
1065 ret = native_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
1066 break;
Mauro Carvalho Chehab5bdd6cc2006-07-25 16:17:54 -03001067#endif
Guy Martina113bc72006-01-11 23:40:51 -02001068 default:
Hans Verkuil7943ecf2008-12-23 14:37:43 -03001069 printk(KERN_WARNING "compat_ioctl32: "
1070 "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
1071 _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd);
Hans Verkuil7d4f0b82008-12-15 07:19:20 -03001072 break;
MishalĂ… Pytasz97e2a012006-01-09 15:24:59 -02001073 }
Hans Verkuile8efb712006-01-09 15:24:59 -02001074 return ret;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -02001075}
Hans Verkuil9bb7cde2008-12-30 06:42:40 -03001076EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32);
Hans Verkuilbec43662008-12-30 06:58:20 -03001077#endif
Ricardo Cerqueira925e6992006-01-09 15:24:57 -02001078
1079MODULE_LICENSE("GPL");