blob: 297c32ab51e35bdd35bc95c0a39bc0e58096cfe5 [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)
10 *
11 * These routines maintain argument size conversion between 32bit and 64bit
12 * ioctls.
13 */
14
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -020015#include <linux/config.h>
16#include <linux/compat.h>
17#include <linux/videodev.h>
Philippe De Muytercf664a62006-01-09 15:24:59 -020018#include <linux/videodev2.h>
Nickolay V. Shmyrev133b7352006-01-09 15:24:58 -020019#include <linux/module.h>
Hans Verkuile8efb712006-01-09 15:24:59 -020020#include <linux/smp_lock.h>
Guy Martina113bc72006-01-11 23:40:51 -020021#include <media/v4l2-common.h>
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -020022
23#ifdef CONFIG_COMPAT
Guy Martina113bc72006-01-11 23:40:51 -020024
25
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -020026struct video_tuner32 {
27 compat_int_t tuner;
28 char name[32];
29 compat_ulong_t rangelow, rangehigh;
30 u32 flags; /* It is really u32 in videodev.h */
31 u16 mode, signal;
32};
33
34static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
35{
Guy Martina113bc72006-01-11 23:40:51 -020036 if(!access_ok(VERIFY_READ, up, sizeof(struct video_tuner32)) ||
37 get_user(kp->tuner, &up->tuner) ||
38 copy_from_user(kp->name, up->name, 32) ||
39 get_user(kp->rangelow, &up->rangelow) ||
40 get_user(kp->rangehigh, &up->rangehigh) ||
41 get_user(kp->flags, &up->flags) ||
42 get_user(kp->mode, &up->mode) ||
43 get_user(kp->signal, &up->signal))
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -020044 return -EFAULT;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -020045 return 0;
46}
47
48static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
49{
Guy Martina113bc72006-01-11 23:40:51 -020050 if(!access_ok(VERIFY_WRITE, up, sizeof(struct video_tuner32)) ||
51 put_user(kp->tuner, &up->tuner) ||
52 copy_to_user(up->name, kp->name, 32) ||
53 put_user(kp->rangelow, &up->rangelow) ||
54 put_user(kp->rangehigh, &up->rangehigh) ||
55 put_user(kp->flags, &up->flags) ||
56 put_user(kp->mode, &up->mode) ||
57 put_user(kp->signal, &up->signal))
58 return -EFAULT;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -020059 return 0;
60}
61
62struct video_buffer32 {
63 compat_caddr_t base;
64 compat_int_t height, width, depth, bytesperline;
65};
66
67static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
68{
69 u32 tmp;
70
Guy Martina113bc72006-01-11 23:40:51 -020071 if (!access_ok(VERIFY_READ, up, sizeof(struct video_buffer32)) ||
72 get_user(tmp, &up->base) ||
73 get_user(kp->height, &up->height) ||
74 get_user(kp->width, &up->width) ||
75 get_user(kp->depth, &up->depth) ||
76 get_user(kp->bytesperline, &up->bytesperline))
77 return -EFAULT;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -020078
79 /* This is actually a physical address stored
80 * as a void pointer.
81 */
82 kp->base = (void *)(unsigned long) tmp;
83
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -020084 return 0;
85}
86
87static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
88{
89 u32 tmp = (u32)((unsigned long)kp->base);
90
Guy Martina113bc72006-01-11 23:40:51 -020091 if(!access_ok(VERIFY_WRITE, up, sizeof(struct video_buffer32)) ||
92 put_user(tmp, &up->base) ||
93 put_user(kp->height, &up->height) ||
94 put_user(kp->width, &up->width) ||
95 put_user(kp->depth, &up->depth) ||
96 put_user(kp->bytesperline, &up->bytesperline))
97 return -EFAULT;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -020098 return 0;
99}
100
101struct video_clip32 {
102 s32 x, y, width, height; /* Its really s32 in videodev.h */
103 compat_caddr_t next;
104};
105
106struct video_window32 {
107 u32 x, y, width, height, chromakey, flags;
108 compat_caddr_t clips;
109 compat_int_t clipcount;
110};
111
112static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
113{
114 int ret = -ENOIOCTLCMD;
115
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200116 if (file->f_op->unlocked_ioctl)
117 ret = file->f_op->unlocked_ioctl(file, cmd, arg);
118 else if (file->f_op->ioctl) {
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200119 lock_kernel();
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200120 ret = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, arg);
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200121 unlock_kernel();
122 }
123
124 return ret;
125}
126
127
128/* You get back everything except the clips... */
129static int put_video_window32(struct video_window *kp, struct video_window32 __user *up)
130{
Guy Martina113bc72006-01-11 23:40:51 -0200131 if(!access_ok(VERIFY_WRITE, up, sizeof(struct video_window32)) ||
132 put_user(kp->x, &up->x) ||
133 put_user(kp->y, &up->y) ||
134 put_user(kp->width, &up->width) ||
135 put_user(kp->height, &up->height) ||
136 put_user(kp->chromakey, &up->chromakey) ||
137 put_user(kp->flags, &up->flags) ||
138 put_user(kp->clipcount, &up->clipcount))
139 return -EFAULT;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200140 return 0;
141}
142
Philippe De Muytercf664a62006-01-09 15:24:59 -0200143struct v4l2_clip32
144{
145 struct v4l2_rect c;
146 compat_caddr_t next;
147};
148
149struct v4l2_window32
150{
151 struct v4l2_rect w;
152 enum v4l2_field field;
153 __u32 chromakey;
154 compat_caddr_t clips; /* actually struct v4l2_clip32 * */
155 __u32 clipcount;
156 compat_caddr_t bitmap;
157};
158
159static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
160{
Guy Martina113bc72006-01-11 23:40:51 -0200161 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) ||
162 copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
163 get_user(kp->field, &up->field) ||
164 get_user(kp->chromakey, &up->chromakey) ||
165 get_user(kp->clipcount, &up->clipcount))
166 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200167 if (kp->clipcount > 2048)
168 return -EINVAL;
169 if (kp->clipcount) {
170 struct v4l2_clip32 *uclips = compat_ptr(up->clips);
171 struct v4l2_clip *kclips;
172 int n = kp->clipcount;
173
174 kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
175 kp->clips = kclips;
176 while (--n >= 0) {
Guy Martina113bc72006-01-11 23:40:51 -0200177 if (!access_ok(VERIFY_READ, &uclips->c, sizeof(uclips->c)) ||
178 copy_from_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
179 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200180 kclips->next = n ? kclips + 1 : 0;
181 uclips += 1;
182 kclips += 1;
183 }
184 } else
185 kp->clips = 0;
186 return 0;
187}
188
189static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
190{
Guy Martina113bc72006-01-11 23:40:51 -0200191 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_window32)) ||
192 copy_to_user(&up->w, &kp->w, sizeof(up->w)) ||
193 put_user(kp->field, &up->field) ||
194 put_user(kp->chromakey, &up->chromakey) ||
195 put_user(kp->clipcount, &up->clipcount))
196 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200197 return 0;
198}
199
200static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
201{
Guy Martina113bc72006-01-11 23:40:51 -0200202 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_pix_format)) ||
203 copy_from_user(kp, up, sizeof(struct v4l2_pix_format)))
204 return -EFAULT;
205 return 0;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200206}
207
208static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
209{
Guy Martina113bc72006-01-11 23:40:51 -0200210 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_pix_format)) ||
211 copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
212 return -EFAULT;
213 return 0;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200214}
215
216static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
217{
Guy Martina113bc72006-01-11 23:40:51 -0200218 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_vbi_format)) ||
219 copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
220 return -EFAULT;
221 return 0;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200222}
223
224static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
225{
Guy Martina113bc72006-01-11 23:40:51 -0200226 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_vbi_format)) ||
227 copy_to_user(up, kp, sizeof(struct v4l2_vbi_format)))
228 return -EFAULT;
229 return 0;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200230}
231
232struct v4l2_format32
233{
234 enum v4l2_buf_type type;
235 union
236 {
237 struct v4l2_pix_format pix; // V4L2_BUF_TYPE_VIDEO_CAPTURE
238 struct v4l2_window32 win; // V4L2_BUF_TYPE_VIDEO_OVERLAY
239 struct v4l2_vbi_format vbi; // V4L2_BUF_TYPE_VBI_CAPTURE
240 __u8 raw_data[200]; // user-defined
241 } fmt;
242};
243
244static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
245{
Guy Martina113bc72006-01-11 23:40:51 -0200246 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) ||
247 get_user(kp->type, &up->type))
248 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200249 switch (kp->type) {
250 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
251 return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
252 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
253 return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
254 case V4L2_BUF_TYPE_VBI_CAPTURE:
255 return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
256 default:
257 printk("compat_ioctl : unexpected VIDIOC_FMT type %d\n",
258 kp->type);
259 return -ENXIO;
260 }
261}
262
263static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
264{
Guy Martina113bc72006-01-11 23:40:51 -0200265 if(!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
266 put_user(kp->type, &up->type))
Philippe De Muytercf664a62006-01-09 15:24:59 -0200267 return -EFAULT;
268 switch (kp->type) {
269 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
270 return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
271 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
272 return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
273 case V4L2_BUF_TYPE_VBI_CAPTURE:
274 return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
275 default:
276 return -ENXIO;
277 }
278}
279
Guy Martina113bc72006-01-11 23:40:51 -0200280static inline int get_v4l2_standard(struct v4l2_standard *kp, struct v4l2_standard __user *up)
281{
282 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard)) ||
283 copy_from_user(kp, up, sizeof(struct v4l2_standard)))
284 return -EFAULT;
285 return 0;
286
287}
288
289static inline int put_v4l2_standard(struct v4l2_standard *kp, struct v4l2_standard __user *up)
290{
291 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard)) ||
292 copy_to_user(up, kp, sizeof(struct v4l2_standard)))
293 return -EFAULT;
294 return 0;
295}
296
Philippe De Muytercf664a62006-01-09 15:24:59 -0200297struct v4l2_standard32
298{
299 __u32 index;
300 __u32 id[2]; /* __u64 would get the alignment wrong */
301 __u8 name[24];
302 struct v4l2_fract frameperiod; /* Frames, not fields */
303 __u32 framelines;
304 __u32 reserved[4];
305};
306
307static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
308{
309 /* other fields are not set by the user, nor used by the driver */
Guy Martina113bc72006-01-11 23:40:51 -0200310 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
311 get_user(kp->index, &up->index))
312 return -EFAULT;
313 return 0;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200314}
315
316static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
317{
Guy Martina113bc72006-01-11 23:40:51 -0200318 if(!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
319 put_user(kp->index, &up->index) ||
320 copy_to_user(up->id, &kp->id, sizeof(__u64)) ||
321 copy_to_user(up->name, kp->name, 24) ||
322 copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
323 put_user(kp->framelines, &up->framelines) ||
324 copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
325 return -EFAULT;
326 return 0;
327}
328
329static inline int get_v4l2_tuner(struct v4l2_tuner *kp, struct v4l2_tuner __user *up)
330{
331 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_tuner)) ||
332 copy_from_user(kp, up, sizeof(struct v4l2_tuner)))
333 return -EFAULT;
334 return 0;
335
336}
337
338static inline int put_v4l2_tuner(struct v4l2_tuner *kp, struct v4l2_tuner __user *up)
339{
340 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_tuner)) ||
341 copy_to_user(up, kp, sizeof(struct v4l2_tuner)))
342 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200343 return 0;
344}
345
346struct v4l2_buffer32
347{
348 __u32 index;
349 enum v4l2_buf_type type;
350 __u32 bytesused;
351 __u32 flags;
352 enum v4l2_field field;
353 struct compat_timeval timestamp;
354 struct v4l2_timecode timecode;
355 __u32 sequence;
356
357 /* memory location */
358 enum v4l2_memory memory;
359 union {
360 __u32 offset;
361 compat_long_t userptr;
362 } m;
363 __u32 length;
364 __u32 input;
365 __u32 reserved;
366};
367
368static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
369{
370
Guy Martina113bc72006-01-11 23:40:51 -0200371 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
372 get_user(kp->index, &up->index) ||
373 get_user(kp->type, &up->type) ||
374 get_user(kp->flags, &up->flags) ||
375 get_user(kp->memory, &up->memory) ||
376 get_user(kp->input, &up->input))
377 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200378 switch(kp->memory) {
379 case V4L2_MEMORY_MMAP:
380 break;
381 case V4L2_MEMORY_USERPTR:
382 {
383 unsigned long tmp = (unsigned long)compat_ptr(up->m.userptr);
384
Guy Martina113bc72006-01-11 23:40:51 -0200385 if(get_user(kp->length, &up->length) ||
386 get_user(kp->m.userptr, &tmp))
387 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200388 }
389 break;
390 case V4L2_MEMORY_OVERLAY:
Guy Martina113bc72006-01-11 23:40:51 -0200391 if(get_user(kp->m.offset, &up->m.offset))
392 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200393 break;
394 }
395 return 0;
396}
397
398static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
399{
Guy Martina113bc72006-01-11 23:40:51 -0200400 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
401 put_user(kp->index, &up->index) ||
402 put_user(kp->type, &up->type) ||
403 put_user(kp->flags, &up->flags) ||
404 put_user(kp->memory, &up->memory) ||
405 put_user(kp->input, &up->input))
406 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200407 switch(kp->memory) {
408 case V4L2_MEMORY_MMAP:
Guy Martina113bc72006-01-11 23:40:51 -0200409 if (put_user(kp->length, &up->length) ||
410 put_user(kp->m.offset, &up->m.offset))
411 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200412 break;
413 case V4L2_MEMORY_USERPTR:
Guy Martina113bc72006-01-11 23:40:51 -0200414 if (put_user(kp->length, &up->length) ||
415 put_user(kp->m.userptr, &up->m.userptr))
416 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200417 break;
418 case V4L2_MEMORY_OVERLAY:
Guy Martina113bc72006-01-11 23:40:51 -0200419 if (put_user(kp->m.offset, &up->m.offset))
420 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200421 break;
422 }
Guy Martina113bc72006-01-11 23:40:51 -0200423 if (put_user(kp->bytesused, &up->bytesused) ||
424 put_user(kp->field, &up->field) ||
425 put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
426 put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
427 copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
428 put_user(kp->sequence, &up->sequence) ||
429 put_user(kp->reserved, &up->reserved))
430 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200431 return 0;
432}
433
434struct v4l2_framebuffer32
435{
436 __u32 capability;
437 __u32 flags;
438 compat_caddr_t base;
439 struct v4l2_pix_format fmt;
440};
441
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200442static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
443{
444 u32 tmp;
445
Guy Martina113bc72006-01-11 23:40:51 -0200446 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) ||
447 get_user(tmp, &up->base) ||
448 get_user(kp->capability, &up->capability) ||
449 get_user(kp->flags, &up->flags))
450 return -EFAULT;
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200451 kp->base = compat_ptr(tmp);
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200452 get_v4l2_pix_format(&kp->fmt, &up->fmt);
453 return 0;
454}
455
Philippe De Muytercf664a62006-01-09 15:24:59 -0200456static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
457{
458 u32 tmp = (u32)((unsigned long)kp->base);
459
Guy Martina113bc72006-01-11 23:40:51 -0200460 if(!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
461 put_user(tmp, &up->base) ||
462 put_user(kp->capability, &up->capability) ||
463 put_user(kp->flags, &up->flags))
464 return -EFAULT;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200465 put_v4l2_pix_format(&kp->fmt, &up->fmt);
466 return 0;
467}
468
Guy Martina113bc72006-01-11 23:40:51 -0200469static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input __user *up)
Philippe De Muytercf664a62006-01-09 15:24:59 -0200470{
Guy Martina113bc72006-01-11 23:40:51 -0200471 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_input) - 4) ||
472 copy_from_user(kp, up, sizeof(struct v4l2_input) - 4))
473 return -EFAULT;
474 return 0;
475}
476
477static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input __user *up)
478{
479 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_input) - 4) ||
480 copy_to_user(up, kp, sizeof(struct v4l2_input) - 4))
481 return -EFAULT;
482 return 0;
483}
484
485static inline int get_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user *up)
486{
487 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_input)) ||
488 copy_from_user(kp, up, sizeof(struct v4l2_input)))
489 return -EFAULT;
490 return 0;
491}
492
493static inline int put_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user *up)
494{
495 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_input)) ||
496 copy_to_user(up, kp, sizeof(struct v4l2_input)))
497 return -EFAULT;
498 return 0;
499}
Philippe De Muytercf664a62006-01-09 15:24:59 -0200500
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200501#define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32)
502#define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32)
503#define VIDIOCGWIN32 _IOR('v',9, struct video_window32)
504#define VIDIOCSWIN32 _IOW('v',10, struct video_window32)
505#define VIDIOCGFBUF32 _IOR('v',11, struct video_buffer32)
506#define VIDIOCSFBUF32 _IOW('v',12, struct video_buffer32)
507#define VIDIOCGFREQ32 _IOR('v',14, u32)
508#define VIDIOCSFREQ32 _IOW('v',15, u32)
509
Guy Martina113bc72006-01-11 23:40:51 -0200510/* VIDIOC_ENUMINPUT32 is VIDIOC_ENUMINPUT minus 4 bytes of padding alignement */
511#define VIDIOC_ENUMINPUT32 VIDIOC_ENUMINPUT - _IOC(0, 0, 0, 4)
Philippe De Muytercf664a62006-01-09 15:24:59 -0200512#define VIDIOC_G_FMT32 _IOWR ('V', 4, struct v4l2_format32)
513#define VIDIOC_S_FMT32 _IOWR ('V', 5, struct v4l2_format32)
514#define VIDIOC_QUERYBUF32 _IOWR ('V', 9, struct v4l2_buffer32)
515#define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32)
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200516#define VIDIOC_S_FBUF32 _IOW ('V', 11, struct v4l2_framebuffer32)
Philippe De Muytercf664a62006-01-09 15:24:59 -0200517/* VIDIOC_OVERLAY is now _IOW, but was _IOWR */
518#define VIDIOC_OVERLAY32 _IOWR ('V', 14, compat_int_t)
519#define VIDIOC_QBUF32 _IOWR ('V', 15, struct v4l2_buffer32)
520#define VIDIOC_DQBUF32 _IOWR ('V', 17, struct v4l2_buffer32)
521#define VIDIOC_STREAMON32 _IOW ('V', 18, compat_int_t)
522#define VIDIOC_STREAMOFF32 _IOW ('V', 19, compat_int_t)
523#define VIDIOC_ENUMSTD32 _IOWR ('V', 25, struct v4l2_standard32)
Philippe De Muytercf664a62006-01-09 15:24:59 -0200524/* VIDIOC_S_CTRL is now _IOWR, but was _IOW */
525#define VIDIOC_S_CTRL32 _IOW ('V', 28, struct v4l2_control)
526#define VIDIOC_G_INPUT32 _IOR ('V', 38, compat_int_t)
527#define VIDIOC_S_INPUT32 _IOWR ('V', 39, compat_int_t)
528#define VIDIOC_TRY_FMT32 _IOWR ('V', 64, struct v4l2_format32)
529
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200530enum {
531 MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip)
532};
533
534static int do_set_window(struct file *file, unsigned int cmd, unsigned long arg)
535{
536 struct video_window32 __user *up = compat_ptr(arg);
537 struct video_window __user *vw;
538 struct video_clip __user *p;
539 int nclips;
540 u32 n;
541
Guy Martina113bc72006-01-11 23:40:51 -0200542 if (!access_ok(VERIFY_READ, up, sizeof(struct video_window32)))
543 return -EFAULT;
544
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200545 if (get_user(nclips, &up->clipcount))
546 return -EFAULT;
547
548 /* Peculiar interface... */
549 if (nclips < 0)
550 nclips = VIDEO_CLIPMAP_SIZE;
551
552 if (nclips > MaxClips)
553 return -ENOMEM;
554
555 vw = compat_alloc_user_space(sizeof(struct video_window) +
556 nclips * sizeof(struct video_clip));
557
558 p = nclips ? (struct video_clip __user *)(vw + 1) : NULL;
559
560 if (get_user(n, &up->x) || put_user(n, &vw->x) ||
561 get_user(n, &up->y) || put_user(n, &vw->y) ||
562 get_user(n, &up->width) || put_user(n, &vw->width) ||
563 get_user(n, &up->height) || put_user(n, &vw->height) ||
564 get_user(n, &up->chromakey) || put_user(n, &vw->chromakey) ||
565 get_user(n, &up->flags) || put_user(n, &vw->flags) ||
566 get_user(n, &up->clipcount) || put_user(n, &vw->clipcount) ||
567 get_user(n, &up->clips) || put_user(p, &vw->clips))
568 return -EFAULT;
569
570 if (nclips) {
571 struct video_clip32 __user *u = compat_ptr(n);
572 int i;
573 if (!u)
574 return -EINVAL;
575 for (i = 0; i < nclips; i++, u++, p++) {
576 s32 v;
Guy Martina113bc72006-01-11 23:40:51 -0200577 if (!access_ok(VERIFY_READ, u, sizeof(struct video_clip32)) ||
578 !access_ok(VERIFY_WRITE, p, sizeof(struct video_clip32)) ||
579 get_user(v, &u->x) ||
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200580 put_user(v, &p->x) ||
581 get_user(v, &u->y) ||
582 put_user(v, &p->y) ||
583 get_user(v, &u->width) ||
584 put_user(v, &p->width) ||
585 get_user(v, &u->height) ||
586 put_user(v, &p->height) ||
587 put_user(NULL, &p->next))
588 return -EFAULT;
589 }
590 }
591
Guy Martin009494e2006-01-09 15:32:45 -0200592 return native_ioctl(file, VIDIOCSWIN, (unsigned long)vw);
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200593}
594
595static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
596{
597 union {
598 struct video_tuner vt;
599 struct video_buffer vb;
600 struct video_window vw;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200601 struct v4l2_format v2f;
602 struct v4l2_buffer v2b;
603 struct v4l2_framebuffer v2fb;
604 struct v4l2_standard v2s;
Guy Martina113bc72006-01-11 23:40:51 -0200605 struct v4l2_input v2i;
606 struct v4l2_tuner v2t;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200607 unsigned long vx;
608 } karg;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200609 void __user *up = compat_ptr(arg);
Philippe De Muytercf664a62006-01-09 15:24:59 -0200610 int compatible_arg = 1;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200611 int err = 0;
Guy Martina113bc72006-01-11 23:40:51 -0200612 int realcmd = cmd;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200613
614 /* First, convert the command. */
615 switch(cmd) {
616 case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
617 case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
618 case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
619 case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
620 case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
621 case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
622 case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200623 case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
624 case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
625 case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
626 case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
627 case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
628 case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
629 case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
630 case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200631 case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200632 case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
Guy Martina113bc72006-01-11 23:40:51 -0200633 case VIDIOC_ENUMSTD32: realcmd = VIDIOC_ENUMSTD; break;
634 case VIDIOC_ENUMINPUT32: realcmd = VIDIOC_ENUMINPUT; break;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200635 case VIDIOC_S_CTRL32: cmd = VIDIOC_S_CTRL; break;
636 case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
637 case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
638 case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200639 };
640
641 switch(cmd) {
642 case VIDIOCSTUNER:
643 case VIDIOCGTUNER:
644 err = get_video_tuner32(&karg.vt, up);
Philippe De Muytercf664a62006-01-09 15:24:59 -0200645 compatible_arg = 0;
646
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200647 break;
648
649 case VIDIOCSFBUF:
650 err = get_video_buffer32(&karg.vb, up);
Philippe De Muytercf664a62006-01-09 15:24:59 -0200651 compatible_arg = 0;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200652 break;
653
654 case VIDIOCSFREQ:
Philippe De Muytercf664a62006-01-09 15:24:59 -0200655 case VIDIOC_S_INPUT:
656 case VIDIOC_OVERLAY:
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200657 case VIDIOC_STREAMON:
658 case VIDIOC_STREAMOFF:
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200659 err = get_user(karg.vx, (u32 __user *)up);
Philippe De Muytercf664a62006-01-09 15:24:59 -0200660 compatible_arg = 0;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200661 break;
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200662
663 case VIDIOC_S_FBUF:
664 err = get_v4l2_framebuffer32(&karg.v2fb, up);
665 compatible_arg = 0;
666 break;
Philippe De Muytercf664a62006-01-09 15:24:59 -0200667
668 case VIDIOC_G_FMT:
669 case VIDIOC_S_FMT:
670 case VIDIOC_TRY_FMT:
671 err = get_v4l2_format32(&karg.v2f, up);
672 compatible_arg = 0;
673 break;
674
675 case VIDIOC_QUERYBUF:
676 case VIDIOC_QBUF:
677 case VIDIOC_DQBUF:
678 err = get_v4l2_buffer32(&karg.v2b, up);
679 compatible_arg = 0;
680 break;
681
682 case VIDIOC_ENUMSTD:
Guy Martina113bc72006-01-11 23:40:51 -0200683 err = get_v4l2_standard(&karg.v2s, up);
684 compatible_arg = 0;
685 break;
686
687 case VIDIOC_ENUMSTD32:
Philippe De Muytercf664a62006-01-09 15:24:59 -0200688 err = get_v4l2_standard32(&karg.v2s, up);
689 compatible_arg = 0;
690 break;
691
Guy Martina113bc72006-01-11 23:40:51 -0200692 case VIDIOC_ENUMINPUT:
693 err = get_v4l2_input(&karg.v2i, up);
694 compatible_arg = 0;
695 break;
696
697 case VIDIOC_ENUMINPUT32:
698 err = get_v4l2_input32(&karg.v2i, up);
699 compatible_arg = 0;
700 break;
701
702 case VIDIOC_G_TUNER:
703 case VIDIOC_S_TUNER:
704 err = get_v4l2_tuner(&karg.v2t, up);
705 compatible_arg = 0;
706 break;
707
Philippe De Muytercf664a62006-01-09 15:24:59 -0200708 case VIDIOCGWIN:
709 case VIDIOCGFBUF:
710 case VIDIOCGFREQ:
711 case VIDIOC_G_FBUF:
712 case VIDIOC_G_INPUT:
713 compatible_arg = 0;
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200714 };
Philippe De Muytercf664a62006-01-09 15:24:59 -0200715
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200716 if(err)
717 goto out;
718
Philippe De Muytercf664a62006-01-09 15:24:59 -0200719 if(compatible_arg)
Guy Martina113bc72006-01-11 23:40:51 -0200720 err = native_ioctl(file, realcmd, (unsigned long)up);
Philippe De Muytercf664a62006-01-09 15:24:59 -0200721 else {
722 mm_segment_t old_fs = get_fs();
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200723
Philippe De Muytercf664a62006-01-09 15:24:59 -0200724 set_fs(KERNEL_DS);
Guy Martina113bc72006-01-11 23:40:51 -0200725 err = native_ioctl(file, realcmd, (unsigned long)&karg);
Philippe De Muytercf664a62006-01-09 15:24:59 -0200726 set_fs(old_fs);
727 }
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200728 if(err == 0) {
729 switch(cmd) {
730 case VIDIOCGTUNER:
731 err = put_video_tuner32(&karg.vt, up);
732 break;
733
734 case VIDIOCGWIN:
735 err = put_video_window32(&karg.vw, up);
736 break;
737
738 case VIDIOCGFBUF:
739 err = put_video_buffer32(&karg.vb, up);
740 break;
741
Philippe De Muytercf664a62006-01-09 15:24:59 -0200742 case VIDIOC_G_FBUF:
743 err = put_v4l2_framebuffer32(&karg.v2fb, up);
744 break;
745
746 case VIDIOC_G_FMT:
747 case VIDIOC_S_FMT:
748 case VIDIOC_TRY_FMT:
749 err = put_v4l2_format32(&karg.v2f, up);
750 break;
751
752 case VIDIOC_QUERYBUF:
753 case VIDIOC_QBUF:
754 case VIDIOC_DQBUF:
755 err = put_v4l2_buffer32(&karg.v2b, up);
756 break;
757
758 case VIDIOC_ENUMSTD:
Guy Martina113bc72006-01-11 23:40:51 -0200759 err = put_v4l2_standard(&karg.v2s, up);
760 break;
761
762 case VIDIOC_ENUMSTD32:
Philippe De Muytercf664a62006-01-09 15:24:59 -0200763 err = put_v4l2_standard32(&karg.v2s, up);
764 break;
765
Guy Martina113bc72006-01-11 23:40:51 -0200766 case VIDIOC_G_TUNER:
767 case VIDIOC_S_TUNER:
768 err = put_v4l2_tuner(&karg.v2t, up);
769 break;
770
771 case VIDIOC_ENUMINPUT:
772 err = put_v4l2_input(&karg.v2i, up);
773 break;
774
775 case VIDIOC_ENUMINPUT32:
776 err = put_v4l2_input32(&karg.v2i, up);
777 break;
778
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200779 case VIDIOCGFREQ:
Philippe De Muytercf664a62006-01-09 15:24:59 -0200780 case VIDIOC_G_INPUT:
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200781 err = put_user(((u32)karg.vx), (u32 __user *)up);
782 break;
783 };
784 }
785out:
786 return err;
787}
788
789long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
790{
791 int ret = -ENOIOCTLCMD;
792
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200793 if (!file->f_op->ioctl)
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200794 return ret;
795
796 switch (cmd) {
797 case VIDIOCSWIN32:
798 ret = do_set_window(file, cmd, arg);
799 break;
800 case VIDIOCGTUNER32:
801 case VIDIOCSTUNER32:
802 case VIDIOCGWIN32:
803 case VIDIOCGFBUF32:
804 case VIDIOCSFBUF32:
805 case VIDIOCGFREQ32:
Nickolay V. Shmyrev133b7352006-01-09 15:24:58 -0200806 case VIDIOCSFREQ32:
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200807 case VIDIOC_QUERYCAP:
808 case VIDIOC_ENUM_FMT:
809 case VIDIOC_G_FMT32:
810 case VIDIOC_S_FMT32:
811 case VIDIOC_REQBUFS:
812 case VIDIOC_QUERYBUF32:
813 case VIDIOC_G_FBUF32:
814 case VIDIOC_S_FBUF32:
815 case VIDIOC_OVERLAY32:
816 case VIDIOC_QBUF32:
817 case VIDIOC_DQBUF32:
818 case VIDIOC_STREAMON32:
819 case VIDIOC_STREAMOFF32:
820 case VIDIOC_G_PARM:
821 case VIDIOC_G_STD:
822 case VIDIOC_S_STD:
Guy Martina113bc72006-01-11 23:40:51 -0200823 case VIDIOC_G_TUNER:
824 case VIDIOC_S_TUNER:
825 case VIDIOC_ENUMSTD:
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200826 case VIDIOC_ENUMSTD32:
Guy Martina113bc72006-01-11 23:40:51 -0200827 case VIDIOC_ENUMINPUT:
Philippe De Muyter13d133b2006-01-09 15:25:00 -0200828 case VIDIOC_ENUMINPUT32:
829 case VIDIOC_G_CTRL:
830 case VIDIOC_S_CTRL32:
831 case VIDIOC_QUERYCTRL:
832 case VIDIOC_G_INPUT32:
833 case VIDIOC_S_INPUT32:
834 case VIDIOC_TRY_FMT32:
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200835 ret = do_video_ioctl(file, cmd, arg);
836 break;
837
838 /* Little v, the video4linux ioctls (conflict?) */
839 case VIDIOCGCAP:
840 case VIDIOCGCHAN:
841 case VIDIOCSCHAN:
842 case VIDIOCGPICT:
843 case VIDIOCSPICT:
844 case VIDIOCCAPTURE:
845 case VIDIOCKEY:
846 case VIDIOCGAUDIO:
847 case VIDIOCSAUDIO:
848 case VIDIOCSYNC:
849 case VIDIOCMCAPTURE:
850 case VIDIOCGMBUF:
851 case VIDIOCGUNIT:
852 case VIDIOCGCAPTURE:
853 case VIDIOCSCAPTURE:
854
855 /* BTTV specific... */
856 case _IOW('v', BASE_VIDIOCPRIVATE+0, char [256]):
857 case _IOR('v', BASE_VIDIOCPRIVATE+1, char [256]):
858 case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int):
859 case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */
860 case _IOR('v' , BASE_VIDIOCPRIVATE+4, int):
861 case _IOR('v' , BASE_VIDIOCPRIVATE+5, int):
862 case _IOR('v' , BASE_VIDIOCPRIVATE+6, int):
863 case _IOR('v' , BASE_VIDIOCPRIVATE+7, int):
864 ret = native_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
865 break;
Guy Martina113bc72006-01-11 23:40:51 -0200866 default:
867 v4l_print_ioctl("compat_ioctl32", cmd);
MishalĂ… Pytasz97e2a012006-01-09 15:24:59 -0200868 }
Hans Verkuile8efb712006-01-09 15:24:59 -0200869 return ret;
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -0200870}
871#else
872long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
873{
874 return -ENOIOCTLCMD;
875}
876#endif
877EXPORT_SYMBOL_GPL(v4l_compat_ioctl32);
Ricardo Cerqueira925e6992006-01-09 15:24:57 -0200878
879MODULE_LICENSE("GPL");