aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/video/compat_ioctl32.c388
1 files changed, 376 insertions, 12 deletions
diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c
index 5472d36d73ff..4b14942dd91c 100644
--- a/drivers/media/video/compat_ioctl32.c
+++ b/drivers/media/video/compat_ioctl32.c
@@ -1,6 +1,21 @@
1/*
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
1#include <linux/config.h> 15#include <linux/config.h>
2#include <linux/compat.h> 16#include <linux/compat.h>
3#include <linux/videodev.h> 17#include <linux/videodev.h>
18#include <linux/videodev2.h>
4#include <linux/module.h> 19#include <linux/module.h>
5#include <linux/smp_lock.h> 20#include <linux/smp_lock.h>
6 21
@@ -15,12 +30,9 @@ struct video_tuner32 {
15 30
16static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up) 31static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
17{ 32{
18 int i;
19
20 if(get_user(kp->tuner, &up->tuner)) 33 if(get_user(kp->tuner, &up->tuner))
21 return -EFAULT; 34 return -EFAULT;
22 for(i = 0; i < 32; i++) 35 __copy_from_user(kp->name, up->name, 32);
23 __get_user(kp->name[i], &up->name[i]);
24 __get_user(kp->rangelow, &up->rangelow); 36 __get_user(kp->rangelow, &up->rangelow);
25 __get_user(kp->rangehigh, &up->rangehigh); 37 __get_user(kp->rangehigh, &up->rangehigh);
26 __get_user(kp->flags, &up->flags); 38 __get_user(kp->flags, &up->flags);
@@ -31,12 +43,9 @@ static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user
31 43
32static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up) 44static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
33{ 45{
34 int i;
35
36 if(put_user(kp->tuner, &up->tuner)) 46 if(put_user(kp->tuner, &up->tuner))
37 return -EFAULT; 47 return -EFAULT;
38 for(i = 0; i < 32; i++) 48 __copy_to_user(up->name, kp->name, 32);
39 __put_user(kp->name[i], &up->name[i]);
40 __put_user(kp->rangelow, &up->rangelow); 49 __put_user(kp->rangelow, &up->rangelow);
41 __put_user(kp->rangehigh, &up->rangehigh); 50 __put_user(kp->rangehigh, &up->rangehigh);
42 __put_user(kp->flags, &up->flags); 51 __put_user(kp->flags, &up->flags);
@@ -123,6 +132,265 @@ static int put_video_window32(struct video_window *kp, struct video_window32 __u
123 return 0; 132 return 0;
124} 133}
125 134
135struct v4l2_clip32
136{
137 struct v4l2_rect c;
138 compat_caddr_t next;
139};
140
141struct v4l2_window32
142{
143 struct v4l2_rect w;
144 enum v4l2_field field;
145 __u32 chromakey;
146 compat_caddr_t clips; /* actually struct v4l2_clip32 * */
147 __u32 clipcount;
148 compat_caddr_t bitmap;
149};
150
151static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
152{
153 if (copy_from_user(&kp->w, &up->w, sizeof(up->w)))
154 return -EFAULT;
155 __get_user(kp->field, &up->field);
156 __get_user(kp->chromakey, &up->chromakey);
157 __get_user(kp->clipcount, &up->clipcount);
158 if (kp->clipcount > 2048)
159 return -EINVAL;
160 if (kp->clipcount) {
161 struct v4l2_clip32 *uclips = compat_ptr(up->clips);
162 struct v4l2_clip *kclips;
163 int n = kp->clipcount;
164
165 kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
166 kp->clips = kclips;
167 while (--n >= 0) {
168 copy_from_user(&kclips->c, &uclips->c, sizeof(uclips->c));
169 kclips->next = n ? kclips + 1 : 0;
170 uclips += 1;
171 kclips += 1;
172 }
173 } else
174 kp->clips = 0;
175 return 0;
176}
177
178static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
179{
180 if (copy_to_user(&up->w, &kp->w, sizeof(up->w)))
181 return -EFAULT;
182 __put_user(kp->field, &up->field);
183 __put_user(kp->chromakey, &up->chromakey);
184 __put_user(kp->clipcount, &up->clipcount);
185 return 0;
186}
187
188static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
189{
190 return copy_from_user(kp, up, sizeof(struct v4l2_pix_format));
191}
192
193static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
194{
195 return copy_to_user(up, kp, sizeof(struct v4l2_pix_format));
196}
197
198static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
199{
200 return copy_from_user(kp, up, sizeof(struct v4l2_vbi_format));
201}
202
203static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
204{
205 return copy_to_user(up, kp, sizeof(struct v4l2_vbi_format));
206}
207
208struct v4l2_format32
209{
210 enum v4l2_buf_type type;
211 union
212 {
213 struct v4l2_pix_format pix; // V4L2_BUF_TYPE_VIDEO_CAPTURE
214 struct v4l2_window32 win; // V4L2_BUF_TYPE_VIDEO_OVERLAY
215 struct v4l2_vbi_format vbi; // V4L2_BUF_TYPE_VBI_CAPTURE
216 __u8 raw_data[200]; // user-defined
217 } fmt;
218};
219
220static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
221{
222 if(get_user(kp->type, &up->type))
223 return -EFAULT;
224 switch (kp->type) {
225 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
226 return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
227 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
228 return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
229 case V4L2_BUF_TYPE_VBI_CAPTURE:
230 return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
231 default:
232 printk("compat_ioctl : unexpected VIDIOC_FMT type %d\n",
233 kp->type);
234 return -ENXIO;
235 }
236}
237
238static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
239{
240 if(put_user(kp->type, &up->type))
241 return -EFAULT;
242 switch (kp->type) {
243 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
244 return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
245 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
246 return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
247 case V4L2_BUF_TYPE_VBI_CAPTURE:
248 return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
249 default:
250 return -ENXIO;
251 }
252}
253
254struct v4l2_standard32
255{
256 __u32 index;
257 __u32 id[2]; /* __u64 would get the alignment wrong */
258 __u8 name[24];
259 struct v4l2_fract frameperiod; /* Frames, not fields */
260 __u32 framelines;
261 __u32 reserved[4];
262};
263
264static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
265{
266 /* other fields are not set by the user, nor used by the driver */
267 return get_user(kp->index, &up->index);
268}
269
270static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
271{
272 if(put_user(kp->index, &up->index))
273 return -EFAULT;
274 __copy_to_user(up->id, &kp->id, sizeof(__u64));
275 __copy_to_user(up->name, kp->name, 24);
276 __put_user(kp->frameperiod, &up->frameperiod);
277 __put_user(kp->framelines, &up->framelines);
278 __copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32));
279 return 0;
280}
281
282struct v4l2_buffer32
283{
284 __u32 index;
285 enum v4l2_buf_type type;
286 __u32 bytesused;
287 __u32 flags;
288 enum v4l2_field field;
289 struct compat_timeval timestamp;
290 struct v4l2_timecode timecode;
291 __u32 sequence;
292
293 /* memory location */
294 enum v4l2_memory memory;
295 union {
296 __u32 offset;
297 compat_long_t userptr;
298 } m;
299 __u32 length;
300 __u32 input;
301 __u32 reserved;
302};
303
304static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
305{
306
307 if (get_user(kp->index, &up->index))
308 return -EFAULT;
309 __get_user(kp->type, &up->type);
310 __get_user(kp->flags, &up->flags);
311 __get_user(kp->memory, &up->memory);
312 __get_user(kp->input, &up->input);
313 switch(kp->memory) {
314 case V4L2_MEMORY_MMAP:
315 break;
316 case V4L2_MEMORY_USERPTR:
317 {
318 unsigned long tmp = (unsigned long)compat_ptr(up->m.userptr);
319
320 __get_user(kp->length, &up->length);
321 __get_user(kp->m.userptr, &tmp);
322 }
323 break;
324 case V4L2_MEMORY_OVERLAY:
325 __get_user(kp->m.offset, &up->m.offset);
326 break;
327 }
328 return 0;
329}
330
331static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
332{
333 if (put_user(kp->index, &up->index))
334 return -EFAULT;
335 __put_user(kp->type, &up->type);
336 __put_user(kp->flags, &up->flags);
337 __put_user(kp->memory, &up->memory);
338 __put_user(kp->input, &up->input);
339 switch(kp->memory) {
340 case V4L2_MEMORY_MMAP:
341 __put_user(kp->length, &up->length);
342 __put_user(kp->m.offset, &up->m.offset);
343 break;
344 case V4L2_MEMORY_USERPTR:
345 __put_user(kp->length, &up->length);
346 __put_user(kp->m.userptr, &up->m.userptr);
347 break;
348 case V4L2_MEMORY_OVERLAY:
349 __put_user(kp->m.offset, &up->m.offset);
350 break;
351 }
352 __put_user(kp->bytesused, &up->bytesused);
353 __put_user(kp->field, &up->field);
354 __put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec);
355 __put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec);
356 __copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode));
357 __put_user(kp->sequence, &up->sequence);
358 __put_user(kp->reserved, &up->reserved);
359 return 0;
360}
361
362struct v4l2_framebuffer32
363{
364 __u32 capability;
365 __u32 flags;
366 compat_caddr_t base;
367 struct v4l2_pix_format fmt;
368};
369
370static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
371{
372 u32 tmp = (u32)((unsigned long)kp->base);
373
374 if(put_user(tmp, &up->base))
375 return -EFAULT;
376 __put_user(kp->capability, &up->capability);
377 __put_user(kp->flags, &up->flags);
378 put_v4l2_pix_format(&kp->fmt, &up->fmt);
379 return 0;
380}
381
382struct v4l2_input32 /* identical layout, but different size */
383{
384 __u32 index; /* Which input */
385 __u8 name[32]; /* Label */
386 __u32 type; /* Type of input */
387 __u32 audioset; /* Associated audios (bitfield) */
388 __u32 tuner; /* Associated tuner */
389 __u32 std[2]; /* __u64 would get the padding wrong */
390 __u32 status;
391 __u32 reserved[4];
392};
393
126#define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32) 394#define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32)
127#define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32) 395#define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32)
128#define VIDIOCGWIN32 _IOR('v',9, struct video_window32) 396#define VIDIOCGWIN32 _IOR('v',9, struct video_window32)
@@ -132,6 +400,24 @@ static int put_video_window32(struct video_window *kp, struct video_window32 __u
132#define VIDIOCGFREQ32 _IOR('v',14, u32) 400#define VIDIOCGFREQ32 _IOR('v',14, u32)
133#define VIDIOCSFREQ32 _IOW('v',15, u32) 401#define VIDIOCSFREQ32 _IOW('v',15, u32)
134 402
403#define VIDIOC_G_FMT32 _IOWR ('V', 4, struct v4l2_format32)
404#define VIDIOC_S_FMT32 _IOWR ('V', 5, struct v4l2_format32)
405#define VIDIOC_QUERYBUF32 _IOWR ('V', 9, struct v4l2_buffer32)
406#define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32)
407/* VIDIOC_OVERLAY is now _IOW, but was _IOWR */
408#define VIDIOC_OVERLAY32 _IOWR ('V', 14, compat_int_t)
409#define VIDIOC_QBUF32 _IOWR ('V', 15, struct v4l2_buffer32)
410#define VIDIOC_DQBUF32 _IOWR ('V', 17, struct v4l2_buffer32)
411#define VIDIOC_STREAMON32 _IOW ('V', 18, compat_int_t)
412#define VIDIOC_STREAMOFF32 _IOW ('V', 19, compat_int_t)
413#define VIDIOC_ENUMSTD32 _IOWR ('V', 25, struct v4l2_standard32)
414#define VIDIOC_ENUMINPUT32 _IOWR ('V', 26, struct v4l2_input32)
415/* VIDIOC_S_CTRL is now _IOWR, but was _IOW */
416#define VIDIOC_S_CTRL32 _IOW ('V', 28, struct v4l2_control)
417#define VIDIOC_G_INPUT32 _IOR ('V', 38, compat_int_t)
418#define VIDIOC_S_INPUT32 _IOWR ('V', 39, compat_int_t)
419#define VIDIOC_TRY_FMT32 _IOWR ('V', 64, struct v4l2_format32)
420
135enum { 421enum {
136 MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip) 422 MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip)
137}; 423};
@@ -198,10 +484,14 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
198 struct video_tuner vt; 484 struct video_tuner vt;
199 struct video_buffer vb; 485 struct video_buffer vb;
200 struct video_window vw; 486 struct video_window vw;
487 struct v4l2_format v2f;
488 struct v4l2_buffer v2b;
489 struct v4l2_framebuffer v2fb;
490 struct v4l2_standard v2s;
201 unsigned long vx; 491 unsigned long vx;
202 } karg; 492 } karg;
203 mm_segment_t old_fs = get_fs();
204 void __user *up = compat_ptr(arg); 493 void __user *up = compat_ptr(arg);
494 int compatible_arg = 1;
205 int err = 0; 495 int err = 0;
206 496
207 /* First, convert the command. */ 497 /* First, convert the command. */
@@ -213,29 +503,82 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
213 case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break; 503 case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
214 case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break; 504 case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
215 case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break; 505 case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
506 case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
507 case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
508 case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
509 case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
510 case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
511 case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
512 case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
513 case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
514 case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
515 case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break;
516 case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break;
517 case VIDIOC_S_CTRL32: cmd = VIDIOC_S_CTRL; break;
518 case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
519 case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
520 case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
216 }; 521 };
217 522
218 switch(cmd) { 523 switch(cmd) {
219 case VIDIOCSTUNER: 524 case VIDIOCSTUNER:
220 case VIDIOCGTUNER: 525 case VIDIOCGTUNER:
221 err = get_video_tuner32(&karg.vt, up); 526 err = get_video_tuner32(&karg.vt, up);
527 compatible_arg = 0;
528
222 break; 529 break;
223 530
224 case VIDIOCSFBUF: 531 case VIDIOCSFBUF:
225 err = get_video_buffer32(&karg.vb, up); 532 err = get_video_buffer32(&karg.vb, up);
533 compatible_arg = 0;
226 break; 534 break;
227 535
228 case VIDIOCSFREQ: 536 case VIDIOCSFREQ:
537 case VIDIOC_S_INPUT:
538 case VIDIOC_OVERLAY:
229 err = get_user(karg.vx, (u32 __user *)up); 539 err = get_user(karg.vx, (u32 __user *)up);
540 compatible_arg = 0;
230 break; 541 break;
231 }; 542 };
543
544 case VIDIOC_G_FMT:
545 case VIDIOC_S_FMT:
546 case VIDIOC_TRY_FMT:
547 err = get_v4l2_format32(&karg.v2f, up);
548 compatible_arg = 0;
549 break;
550
551 case VIDIOC_QUERYBUF:
552 case VIDIOC_QBUF:
553 case VIDIOC_DQBUF:
554 err = get_v4l2_buffer32(&karg.v2b, up);
555 compatible_arg = 0;
556 break;
557
558 case VIDIOC_ENUMSTD:
559 err = get_v4l2_standard32(&karg.v2s, up);
560 compatible_arg = 0;
561 break;
562
563 case VIDIOCGWIN:
564 case VIDIOCGFBUF:
565 case VIDIOCGFREQ:
566 case VIDIOC_G_FBUF:
567 case VIDIOC_G_INPUT:
568 compatible_arg = 0;
569
232 if(err) 570 if(err)
233 goto out; 571 goto out;
234 572
235 set_fs(KERNEL_DS); 573 if(compatible_arg)
236 err = native_ioctl(file, cmd, (unsigned long)&karg); 574 err = sys_ioctl(fd, cmd, (unsigned long)up);
237 set_fs(old_fs); 575 else {
576 mm_segment_t old_fs = get_fs();
238 577
578 set_fs(KERNEL_DS);
579 err = sys_ioctl(fd, cmd, (unsigned long)&karg);
580 set_fs(old_fs);
581 }
239 if(err == 0) { 582 if(err == 0) {
240 switch(cmd) { 583 switch(cmd) {
241 case VIDIOCGTUNER: 584 case VIDIOCGTUNER:
@@ -250,7 +593,28 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
250 err = put_video_buffer32(&karg.vb, up); 593 err = put_video_buffer32(&karg.vb, up);
251 break; 594 break;
252 595
596 case VIDIOC_G_FBUF:
597 err = put_v4l2_framebuffer32(&karg.v2fb, up);
598 break;
599
600 case VIDIOC_G_FMT:
601 case VIDIOC_S_FMT:
602 case VIDIOC_TRY_FMT:
603 err = put_v4l2_format32(&karg.v2f, up);
604 break;
605
606 case VIDIOC_QUERYBUF:
607 case VIDIOC_QBUF:
608 case VIDIOC_DQBUF:
609 err = put_v4l2_buffer32(&karg.v2b, up);
610 break;
611
612 case VIDIOC_ENUMSTD:
613 err = put_v4l2_standard32(&karg.v2s, up);
614 break;
615
253 case VIDIOCGFREQ: 616 case VIDIOCGFREQ:
617 case VIDIOC_G_INPUT:
254 err = put_user(((u32)karg.vx), (u32 __user *)up); 618 err = put_user(((u32)karg.vx), (u32 __user *)up);
255 break; 619 break;
256 }; 620 };