1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
4 * Separated from fs stuff by Arnd Bergmann <arnd@arndb.de>
5 *
6 * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
7 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
8 * Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
9 * Copyright (C) 2003 Pavel Machek (pavel@ucw.cz)
10 * Copyright (C) 2005 Philippe De Muyter (phdm@macqel.be)
11 * Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
12 *
13 * These routines maintain argument size conversion between 32bit and 64bit
14 * ioctls.
15 */
16
17 #include <linux/compat.h>
18 #include <linux/module.h>
19 #include <linux/videodev2.h>
20 #include <linux/v4l2-subdev.h>
21 #include <media/v4l2-dev.h>
22 #include <media/v4l2-fh.h>
23 #include <media/v4l2-ctrls.h>
24 #include <media/v4l2-ioctl.h>
25
26 /*
27 * Per-ioctl data copy handlers.
28 *
29 * Those come in pairs, with a get_v4l2_foo() and a put_v4l2_foo() routine,
30 * where "v4l2_foo" is the name of the V4L2 struct.
31 *
32 * They basically get two __user pointers, one with a 32-bits struct that
33 * came from the userspace call and a 64-bits struct, also allocated as
34 * userspace, but filled internally by do_video_ioctl().
35 *
36 * For ioctls that have pointers inside it, the functions will also
37 * receive an ancillary buffer with extra space, used to pass extra
38 * data to the routine.
39 */
40
41 struct v4l2_window32 {
42 struct v4l2_rect w;
43 __u32 field; /* enum v4l2_field */
44 __u32 chromakey;
45 compat_caddr_t clips; /* always NULL */
46 __u32 clipcount; /* always 0 */
47 compat_caddr_t bitmap; /* always NULL */
48 __u8 global_alpha;
49 };
50
get_v4l2_window32(struct v4l2_window * p64,struct v4l2_window32 __user * p32)51 static int get_v4l2_window32(struct v4l2_window *p64,
52 struct v4l2_window32 __user *p32)
53 {
54 struct v4l2_window32 w32;
55
56 if (copy_from_user(&w32, p32, sizeof(w32)))
57 return -EFAULT;
58
59 *p64 = (struct v4l2_window) {
60 .w = w32.w,
61 .field = w32.field,
62 .chromakey = w32.chromakey,
63 .clips = NULL,
64 .clipcount = 0,
65 .bitmap = NULL,
66 .global_alpha = w32.global_alpha,
67 };
68
69 return 0;
70 }
71
put_v4l2_window32(struct v4l2_window * p64,struct v4l2_window32 __user * p32)72 static int put_v4l2_window32(struct v4l2_window *p64,
73 struct v4l2_window32 __user *p32)
74 {
75 struct v4l2_window32 w32;
76
77 memset(&w32, 0, sizeof(w32));
78 w32 = (struct v4l2_window32) {
79 .w = p64->w,
80 .field = p64->field,
81 .chromakey = p64->chromakey,
82 .clips = 0,
83 .clipcount = 0,
84 .bitmap = 0,
85 .global_alpha = p64->global_alpha,
86 };
87
88 if (copy_to_user(p32, &w32, sizeof(w32)))
89 return -EFAULT;
90
91 return 0;
92 }
93
94 struct v4l2_format32 {
95 __u32 type; /* enum v4l2_buf_type */
96 union {
97 struct v4l2_pix_format pix;
98 struct v4l2_pix_format_mplane pix_mp;
99 struct v4l2_window32 win;
100 struct v4l2_vbi_format vbi;
101 struct v4l2_sliced_vbi_format sliced;
102 struct v4l2_sdr_format sdr;
103 struct v4l2_meta_format meta;
104 __u8 raw_data[200]; /* user-defined */
105 } fmt;
106 };
107
108 /**
109 * struct v4l2_create_buffers32 - VIDIOC_CREATE_BUFS32 argument
110 * @index: on return, index of the first created buffer
111 * @count: entry: number of requested buffers,
112 * return: number of created buffers
113 * @memory: buffer memory type
114 * @format: frame format, for which buffers are requested
115 * @capabilities: capabilities of this buffer type.
116 * @flags: additional buffer management attributes (ignored unless the
117 * queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability and
118 * configured for MMAP streaming I/O).
119 * @reserved: future extensions
120 */
121 struct v4l2_create_buffers32 {
122 __u32 index;
123 __u32 count;
124 __u32 memory; /* enum v4l2_memory */
125 struct v4l2_format32 format;
126 __u32 capabilities;
127 __u32 flags;
128 __u32 reserved[6];
129 };
130
get_v4l2_format32(struct v4l2_format * p64,struct v4l2_format32 __user * p32)131 static int get_v4l2_format32(struct v4l2_format *p64,
132 struct v4l2_format32 __user *p32)
133 {
134 if (get_user(p64->type, &p32->type))
135 return -EFAULT;
136
137 switch (p64->type) {
138 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
139 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
140 return copy_from_user(&p64->fmt.pix, &p32->fmt.pix,
141 sizeof(p64->fmt.pix)) ? -EFAULT : 0;
142 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
143 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
144 return copy_from_user(&p64->fmt.pix_mp, &p32->fmt.pix_mp,
145 sizeof(p64->fmt.pix_mp)) ? -EFAULT : 0;
146 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
147 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
148 return get_v4l2_window32(&p64->fmt.win, &p32->fmt.win);
149 case V4L2_BUF_TYPE_VBI_CAPTURE:
150 case V4L2_BUF_TYPE_VBI_OUTPUT:
151 return copy_from_user(&p64->fmt.vbi, &p32->fmt.vbi,
152 sizeof(p64->fmt.vbi)) ? -EFAULT : 0;
153 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
154 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
155 return copy_from_user(&p64->fmt.sliced, &p32->fmt.sliced,
156 sizeof(p64->fmt.sliced)) ? -EFAULT : 0;
157 case V4L2_BUF_TYPE_SDR_CAPTURE:
158 case V4L2_BUF_TYPE_SDR_OUTPUT:
159 return copy_from_user(&p64->fmt.sdr, &p32->fmt.sdr,
160 sizeof(p64->fmt.sdr)) ? -EFAULT : 0;
161 case V4L2_BUF_TYPE_META_CAPTURE:
162 case V4L2_BUF_TYPE_META_OUTPUT:
163 return copy_from_user(&p64->fmt.meta, &p32->fmt.meta,
164 sizeof(p64->fmt.meta)) ? -EFAULT : 0;
165 default:
166 return -EINVAL;
167 }
168 }
169
get_v4l2_create32(struct v4l2_create_buffers * p64,struct v4l2_create_buffers32 __user * p32)170 static int get_v4l2_create32(struct v4l2_create_buffers *p64,
171 struct v4l2_create_buffers32 __user *p32)
172 {
173 if (copy_from_user(p64, p32,
174 offsetof(struct v4l2_create_buffers32, format)))
175 return -EFAULT;
176 if (copy_from_user(&p64->flags, &p32->flags, sizeof(p32->flags)))
177 return -EFAULT;
178 return get_v4l2_format32(&p64->format, &p32->format);
179 }
180
put_v4l2_format32(struct v4l2_format * p64,struct v4l2_format32 __user * p32)181 static int put_v4l2_format32(struct v4l2_format *p64,
182 struct v4l2_format32 __user *p32)
183 {
184 switch (p64->type) {
185 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
186 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
187 return copy_to_user(&p32->fmt.pix, &p64->fmt.pix,
188 sizeof(p64->fmt.pix)) ? -EFAULT : 0;
189 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
190 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
191 return copy_to_user(&p32->fmt.pix_mp, &p64->fmt.pix_mp,
192 sizeof(p64->fmt.pix_mp)) ? -EFAULT : 0;
193 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
194 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
195 return put_v4l2_window32(&p64->fmt.win, &p32->fmt.win);
196 case V4L2_BUF_TYPE_VBI_CAPTURE:
197 case V4L2_BUF_TYPE_VBI_OUTPUT:
198 return copy_to_user(&p32->fmt.vbi, &p64->fmt.vbi,
199 sizeof(p64->fmt.vbi)) ? -EFAULT : 0;
200 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
201 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
202 return copy_to_user(&p32->fmt.sliced, &p64->fmt.sliced,
203 sizeof(p64->fmt.sliced)) ? -EFAULT : 0;
204 case V4L2_BUF_TYPE_SDR_CAPTURE:
205 case V4L2_BUF_TYPE_SDR_OUTPUT:
206 return copy_to_user(&p32->fmt.sdr, &p64->fmt.sdr,
207 sizeof(p64->fmt.sdr)) ? -EFAULT : 0;
208 case V4L2_BUF_TYPE_META_CAPTURE:
209 case V4L2_BUF_TYPE_META_OUTPUT:
210 return copy_to_user(&p32->fmt.meta, &p64->fmt.meta,
211 sizeof(p64->fmt.meta)) ? -EFAULT : 0;
212 default:
213 return -EINVAL;
214 }
215 }
216
put_v4l2_create32(struct v4l2_create_buffers * p64,struct v4l2_create_buffers32 __user * p32)217 static int put_v4l2_create32(struct v4l2_create_buffers *p64,
218 struct v4l2_create_buffers32 __user *p32)
219 {
220 if (copy_to_user(p32, p64,
221 offsetof(struct v4l2_create_buffers32, format)) ||
222 put_user(p64->capabilities, &p32->capabilities) ||
223 put_user(p64->flags, &p32->flags) ||
224 copy_to_user(p32->reserved, p64->reserved, sizeof(p64->reserved)))
225 return -EFAULT;
226 return put_v4l2_format32(&p64->format, &p32->format);
227 }
228
229 struct v4l2_standard32 {
230 __u32 index;
231 compat_u64 id;
232 __u8 name[24];
233 struct v4l2_fract frameperiod; /* Frames, not fields */
234 __u32 framelines;
235 __u32 reserved[4];
236 };
237
get_v4l2_standard32(struct v4l2_standard * p64,struct v4l2_standard32 __user * p32)238 static int get_v4l2_standard32(struct v4l2_standard *p64,
239 struct v4l2_standard32 __user *p32)
240 {
241 /* other fields are not set by the user, nor used by the driver */
242 return get_user(p64->index, &p32->index);
243 }
244
put_v4l2_standard32(struct v4l2_standard * p64,struct v4l2_standard32 __user * p32)245 static int put_v4l2_standard32(struct v4l2_standard *p64,
246 struct v4l2_standard32 __user *p32)
247 {
248 if (put_user(p64->index, &p32->index) ||
249 put_user(p64->id, &p32->id) ||
250 copy_to_user(p32->name, p64->name, sizeof(p32->name)) ||
251 copy_to_user(&p32->frameperiod, &p64->frameperiod,
252 sizeof(p32->frameperiod)) ||
253 put_user(p64->framelines, &p32->framelines) ||
254 copy_to_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
255 return -EFAULT;
256 return 0;
257 }
258
259 struct v4l2_plane32 {
260 __u32 bytesused;
261 __u32 length;
262 union {
263 __u32 mem_offset;
264 compat_long_t userptr;
265 __s32 fd;
266 } m;
267 __u32 data_offset;
268 __u32 reserved[11];
269 };
270
271 /*
272 * This is correct for all architectures including i386, but not x32,
273 * which has different alignment requirements for timestamp
274 */
275 struct v4l2_buffer32 {
276 __u32 index;
277 __u32 type; /* enum v4l2_buf_type */
278 __u32 bytesused;
279 __u32 flags;
280 __u32 field; /* enum v4l2_field */
281 struct {
282 compat_s64 tv_sec;
283 compat_s64 tv_usec;
284 } timestamp;
285 struct v4l2_timecode timecode;
286 __u32 sequence;
287
288 /* memory location */
289 __u32 memory; /* enum v4l2_memory */
290 union {
291 __u32 offset;
292 compat_long_t userptr;
293 compat_caddr_t planes;
294 __s32 fd;
295 } m;
296 __u32 length;
297 __u32 reserved2;
298 __s32 request_fd;
299 };
300
301 #ifdef CONFIG_COMPAT_32BIT_TIME
302 struct v4l2_buffer32_time32 {
303 __u32 index;
304 __u32 type; /* enum v4l2_buf_type */
305 __u32 bytesused;
306 __u32 flags;
307 __u32 field; /* enum v4l2_field */
308 struct old_timeval32 timestamp;
309 struct v4l2_timecode timecode;
310 __u32 sequence;
311
312 /* memory location */
313 __u32 memory; /* enum v4l2_memory */
314 union {
315 __u32 offset;
316 compat_long_t userptr;
317 compat_caddr_t planes;
318 __s32 fd;
319 } m;
320 __u32 length;
321 __u32 reserved2;
322 __s32 request_fd;
323 };
324 #endif
325
get_v4l2_plane32(struct v4l2_plane * p64,struct v4l2_plane32 __user * p32,enum v4l2_memory memory)326 static int get_v4l2_plane32(struct v4l2_plane *p64,
327 struct v4l2_plane32 __user *p32,
328 enum v4l2_memory memory)
329 {
330 struct v4l2_plane32 plane32;
331 typeof(p64->m) m = {};
332
333 if (copy_from_user(&plane32, p32, sizeof(plane32)))
334 return -EFAULT;
335
336 switch (memory) {
337 case V4L2_MEMORY_MMAP:
338 case V4L2_MEMORY_OVERLAY:
339 m.mem_offset = plane32.m.mem_offset;
340 break;
341 case V4L2_MEMORY_USERPTR:
342 m.userptr = (unsigned long)compat_ptr(plane32.m.userptr);
343 break;
344 case V4L2_MEMORY_DMABUF:
345 m.fd = plane32.m.fd;
346 break;
347 }
348
349 memset(p64, 0, sizeof(*p64));
350 *p64 = (struct v4l2_plane) {
351 .bytesused = plane32.bytesused,
352 .length = plane32.length,
353 .m = m,
354 .data_offset = plane32.data_offset,
355 };
356
357 return 0;
358 }
359
put_v4l2_plane32(struct v4l2_plane * p64,struct v4l2_plane32 __user * p32,enum v4l2_memory memory)360 static int put_v4l2_plane32(struct v4l2_plane *p64,
361 struct v4l2_plane32 __user *p32,
362 enum v4l2_memory memory)
363 {
364 struct v4l2_plane32 plane32;
365
366 memset(&plane32, 0, sizeof(plane32));
367 plane32 = (struct v4l2_plane32) {
368 .bytesused = p64->bytesused,
369 .length = p64->length,
370 .data_offset = p64->data_offset,
371 };
372
373 switch (memory) {
374 case V4L2_MEMORY_MMAP:
375 case V4L2_MEMORY_OVERLAY:
376 plane32.m.mem_offset = p64->m.mem_offset;
377 break;
378 case V4L2_MEMORY_USERPTR:
379 plane32.m.userptr = (uintptr_t)(p64->m.userptr);
380 break;
381 case V4L2_MEMORY_DMABUF:
382 plane32.m.fd = p64->m.fd;
383 break;
384 }
385
386 if (copy_to_user(p32, &plane32, sizeof(plane32)))
387 return -EFAULT;
388
389 return 0;
390 }
391
get_v4l2_buffer32(struct v4l2_buffer * vb,struct v4l2_buffer32 __user * arg)392 static int get_v4l2_buffer32(struct v4l2_buffer *vb,
393 struct v4l2_buffer32 __user *arg)
394 {
395 struct v4l2_buffer32 vb32;
396
397 if (copy_from_user(&vb32, arg, sizeof(vb32)))
398 return -EFAULT;
399
400 memset(vb, 0, sizeof(*vb));
401 *vb = (struct v4l2_buffer) {
402 .index = vb32.index,
403 .type = vb32.type,
404 .bytesused = vb32.bytesused,
405 .flags = vb32.flags,
406 .field = vb32.field,
407 .timestamp.tv_sec = vb32.timestamp.tv_sec,
408 .timestamp.tv_usec = vb32.timestamp.tv_usec,
409 .timecode = vb32.timecode,
410 .sequence = vb32.sequence,
411 .memory = vb32.memory,
412 .m.offset = vb32.m.offset,
413 .length = vb32.length,
414 .request_fd = vb32.request_fd,
415 };
416
417 switch (vb->memory) {
418 case V4L2_MEMORY_MMAP:
419 case V4L2_MEMORY_OVERLAY:
420 vb->m.offset = vb32.m.offset;
421 break;
422 case V4L2_MEMORY_USERPTR:
423 vb->m.userptr = (unsigned long)compat_ptr(vb32.m.userptr);
424 break;
425 case V4L2_MEMORY_DMABUF:
426 vb->m.fd = vb32.m.fd;
427 break;
428 }
429
430 if (V4L2_TYPE_IS_MULTIPLANAR(vb->type))
431 vb->m.planes = (void __force *)
432 compat_ptr(vb32.m.planes);
433
434 return 0;
435 }
436
437 #ifdef CONFIG_COMPAT_32BIT_TIME
get_v4l2_buffer32_time32(struct v4l2_buffer * vb,struct v4l2_buffer32_time32 __user * arg)438 static int get_v4l2_buffer32_time32(struct v4l2_buffer *vb,
439 struct v4l2_buffer32_time32 __user *arg)
440 {
441 struct v4l2_buffer32_time32 vb32;
442
443 if (copy_from_user(&vb32, arg, sizeof(vb32)))
444 return -EFAULT;
445
446 *vb = (struct v4l2_buffer) {
447 .index = vb32.index,
448 .type = vb32.type,
449 .bytesused = vb32.bytesused,
450 .flags = vb32.flags,
451 .field = vb32.field,
452 .timestamp.tv_sec = vb32.timestamp.tv_sec,
453 .timestamp.tv_usec = vb32.timestamp.tv_usec,
454 .timecode = vb32.timecode,
455 .sequence = vb32.sequence,
456 .memory = vb32.memory,
457 .m.offset = vb32.m.offset,
458 .length = vb32.length,
459 .request_fd = vb32.request_fd,
460 };
461 switch (vb->memory) {
462 case V4L2_MEMORY_MMAP:
463 case V4L2_MEMORY_OVERLAY:
464 vb->m.offset = vb32.m.offset;
465 break;
466 case V4L2_MEMORY_USERPTR:
467 vb->m.userptr = (unsigned long)compat_ptr(vb32.m.userptr);
468 break;
469 case V4L2_MEMORY_DMABUF:
470 vb->m.fd = vb32.m.fd;
471 break;
472 }
473
474 if (V4L2_TYPE_IS_MULTIPLANAR(vb->type))
475 vb->m.planes = (void __force *)
476 compat_ptr(vb32.m.planes);
477
478 return 0;
479 }
480 #endif
481
put_v4l2_buffer32(struct v4l2_buffer * vb,struct v4l2_buffer32 __user * arg)482 static int put_v4l2_buffer32(struct v4l2_buffer *vb,
483 struct v4l2_buffer32 __user *arg)
484 {
485 struct v4l2_buffer32 vb32;
486
487 memset(&vb32, 0, sizeof(vb32));
488 vb32 = (struct v4l2_buffer32) {
489 .index = vb->index,
490 .type = vb->type,
491 .bytesused = vb->bytesused,
492 .flags = vb->flags,
493 .field = vb->field,
494 .timestamp.tv_sec = vb->timestamp.tv_sec,
495 .timestamp.tv_usec = vb->timestamp.tv_usec,
496 .timecode = vb->timecode,
497 .sequence = vb->sequence,
498 .memory = vb->memory,
499 .m.offset = vb->m.offset,
500 .length = vb->length,
501 .request_fd = vb->request_fd,
502 };
503
504 switch (vb->memory) {
505 case V4L2_MEMORY_MMAP:
506 case V4L2_MEMORY_OVERLAY:
507 vb32.m.offset = vb->m.offset;
508 break;
509 case V4L2_MEMORY_USERPTR:
510 vb32.m.userptr = (uintptr_t)(vb->m.userptr);
511 break;
512 case V4L2_MEMORY_DMABUF:
513 vb32.m.fd = vb->m.fd;
514 break;
515 }
516
517 if (V4L2_TYPE_IS_MULTIPLANAR(vb->type))
518 vb32.m.planes = (uintptr_t)vb->m.planes;
519
520 if (copy_to_user(arg, &vb32, sizeof(vb32)))
521 return -EFAULT;
522
523 return 0;
524 }
525
526 #ifdef CONFIG_COMPAT_32BIT_TIME
put_v4l2_buffer32_time32(struct v4l2_buffer * vb,struct v4l2_buffer32_time32 __user * arg)527 static int put_v4l2_buffer32_time32(struct v4l2_buffer *vb,
528 struct v4l2_buffer32_time32 __user *arg)
529 {
530 struct v4l2_buffer32_time32 vb32;
531
532 memset(&vb32, 0, sizeof(vb32));
533 vb32 = (struct v4l2_buffer32_time32) {
534 .index = vb->index,
535 .type = vb->type,
536 .bytesused = vb->bytesused,
537 .flags = vb->flags,
538 .field = vb->field,
539 .timestamp.tv_sec = vb->timestamp.tv_sec,
540 .timestamp.tv_usec = vb->timestamp.tv_usec,
541 .timecode = vb->timecode,
542 .sequence = vb->sequence,
543 .memory = vb->memory,
544 .m.offset = vb->m.offset,
545 .length = vb->length,
546 .request_fd = vb->request_fd,
547 };
548 switch (vb->memory) {
549 case V4L2_MEMORY_MMAP:
550 case V4L2_MEMORY_OVERLAY:
551 vb32.m.offset = vb->m.offset;
552 break;
553 case V4L2_MEMORY_USERPTR:
554 vb32.m.userptr = (uintptr_t)(vb->m.userptr);
555 break;
556 case V4L2_MEMORY_DMABUF:
557 vb32.m.fd = vb->m.fd;
558 break;
559 }
560
561 if (V4L2_TYPE_IS_MULTIPLANAR(vb->type))
562 vb32.m.planes = (uintptr_t)vb->m.planes;
563
564 if (copy_to_user(arg, &vb32, sizeof(vb32)))
565 return -EFAULT;
566
567 return 0;
568 }
569 #endif
570
571 struct v4l2_framebuffer32 {
572 __u32 capability;
573 __u32 flags;
574 compat_caddr_t base;
575 struct {
576 __u32 width;
577 __u32 height;
578 __u32 pixelformat;
579 __u32 field;
580 __u32 bytesperline;
581 __u32 sizeimage;
582 __u32 colorspace;
583 __u32 priv;
584 } fmt;
585 };
586
get_v4l2_framebuffer32(struct v4l2_framebuffer * p64,struct v4l2_framebuffer32 __user * p32)587 static int get_v4l2_framebuffer32(struct v4l2_framebuffer *p64,
588 struct v4l2_framebuffer32 __user *p32)
589 {
590 if (get_user(p64->capability, &p32->capability) ||
591 get_user(p64->flags, &p32->flags) ||
592 copy_from_user(&p64->fmt, &p32->fmt, sizeof(p64->fmt)))
593 return -EFAULT;
594 p64->base = NULL;
595
596 return 0;
597 }
598
put_v4l2_framebuffer32(struct v4l2_framebuffer * p64,struct v4l2_framebuffer32 __user * p32)599 static int put_v4l2_framebuffer32(struct v4l2_framebuffer *p64,
600 struct v4l2_framebuffer32 __user *p32)
601 {
602 if (put_user((uintptr_t)p64->base, &p32->base) ||
603 put_user(p64->capability, &p32->capability) ||
604 put_user(p64->flags, &p32->flags) ||
605 copy_to_user(&p32->fmt, &p64->fmt, sizeof(p64->fmt)))
606 return -EFAULT;
607
608 return 0;
609 }
610
611 struct v4l2_input32 {
612 __u32 index; /* Which input */
613 __u8 name[32]; /* Label */
614 __u32 type; /* Type of input */
615 __u32 audioset; /* Associated audios (bitfield) */
616 __u32 tuner; /* Associated tuner */
617 compat_u64 std;
618 __u32 status;
619 __u32 capabilities;
620 __u32 reserved[3];
621 };
622
623 /*
624 * The 64-bit v4l2_input struct has extra padding at the end of the struct.
625 * Otherwise it is identical to the 32-bit version.
626 */
get_v4l2_input32(struct v4l2_input * p64,struct v4l2_input32 __user * p32)627 static inline int get_v4l2_input32(struct v4l2_input *p64,
628 struct v4l2_input32 __user *p32)
629 {
630 if (copy_from_user(p64, p32, sizeof(*p32)))
631 return -EFAULT;
632 return 0;
633 }
634
put_v4l2_input32(struct v4l2_input * p64,struct v4l2_input32 __user * p32)635 static inline int put_v4l2_input32(struct v4l2_input *p64,
636 struct v4l2_input32 __user *p32)
637 {
638 if (copy_to_user(p32, p64, sizeof(*p32)))
639 return -EFAULT;
640 return 0;
641 }
642
643 struct v4l2_ext_controls32 {
644 __u32 which;
645 __u32 count;
646 __u32 error_idx;
647 __s32 request_fd;
648 __u32 reserved[1];
649 compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
650 };
651
652 struct v4l2_ext_control32 {
653 __u32 id;
654 __u32 size;
655 __u32 reserved2[1];
656 union {
657 __s32 value;
658 __s64 value64;
659 compat_caddr_t string; /* actually char * */
660 };
661 } __attribute__ ((packed));
662
663 /* Return true if this control is a pointer type. */
ctrl_is_pointer(struct file * file,u32 id)664 static inline bool ctrl_is_pointer(struct file *file, u32 id)
665 {
666 struct video_device *vdev = video_devdata(file);
667 struct v4l2_fh *fh = NULL;
668 struct v4l2_ctrl_handler *hdl = NULL;
669 struct v4l2_query_ext_ctrl qec = { id };
670 const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops;
671
672 if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
673 fh = file->private_data;
674
675 if (fh && fh->ctrl_handler)
676 hdl = fh->ctrl_handler;
677 else if (vdev->ctrl_handler)
678 hdl = vdev->ctrl_handler;
679
680 if (hdl) {
681 struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id);
682
683 return ctrl && ctrl->is_ptr;
684 }
685
686 if (!ops || !ops->vidioc_query_ext_ctrl)
687 return false;
688
689 return !ops->vidioc_query_ext_ctrl(file, fh, &qec) &&
690 (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD);
691 }
692
get_v4l2_ext_controls32(struct v4l2_ext_controls * p64,struct v4l2_ext_controls32 __user * p32)693 static int get_v4l2_ext_controls32(struct v4l2_ext_controls *p64,
694 struct v4l2_ext_controls32 __user *p32)
695 {
696 struct v4l2_ext_controls32 ec32;
697
698 if (copy_from_user(&ec32, p32, sizeof(ec32)))
699 return -EFAULT;
700
701 *p64 = (struct v4l2_ext_controls) {
702 .which = ec32.which,
703 .count = ec32.count,
704 .error_idx = ec32.error_idx,
705 .request_fd = ec32.request_fd,
706 .reserved[0] = ec32.reserved[0],
707 .controls = (void __force *)compat_ptr(ec32.controls),
708 };
709
710 return 0;
711 }
712
put_v4l2_ext_controls32(struct v4l2_ext_controls * p64,struct v4l2_ext_controls32 __user * p32)713 static int put_v4l2_ext_controls32(struct v4l2_ext_controls *p64,
714 struct v4l2_ext_controls32 __user *p32)
715 {
716 struct v4l2_ext_controls32 ec32;
717
718 memset(&ec32, 0, sizeof(ec32));
719 ec32 = (struct v4l2_ext_controls32) {
720 .which = p64->which,
721 .count = p64->count,
722 .error_idx = p64->error_idx,
723 .request_fd = p64->request_fd,
724 .reserved[0] = p64->reserved[0],
725 .controls = (uintptr_t)p64->controls,
726 };
727
728 if (copy_to_user(p32, &ec32, sizeof(ec32)))
729 return -EFAULT;
730
731 return 0;
732 }
733
734 #ifdef CONFIG_X86_64
735 /*
736 * x86 is the only compat architecture with different struct alignment
737 * between 32-bit and 64-bit tasks.
738 */
739 struct v4l2_event32 {
740 __u32 type;
741 union {
742 compat_s64 value64;
743 __u8 data[64];
744 } u;
745 __u32 pending;
746 __u32 sequence;
747 struct {
748 compat_s64 tv_sec;
749 compat_s64 tv_nsec;
750 } timestamp;
751 __u32 id;
752 __u32 reserved[8];
753 };
754
put_v4l2_event32(struct v4l2_event * p64,struct v4l2_event32 __user * p32)755 static int put_v4l2_event32(struct v4l2_event *p64,
756 struct v4l2_event32 __user *p32)
757 {
758 if (put_user(p64->type, &p32->type) ||
759 copy_to_user(&p32->u, &p64->u, sizeof(p64->u)) ||
760 put_user(p64->pending, &p32->pending) ||
761 put_user(p64->sequence, &p32->sequence) ||
762 put_user(p64->timestamp.tv_sec, &p32->timestamp.tv_sec) ||
763 put_user(p64->timestamp.tv_nsec, &p32->timestamp.tv_nsec) ||
764 put_user(p64->id, &p32->id) ||
765 copy_to_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
766 return -EFAULT;
767 return 0;
768 }
769
770 #endif
771
772 #ifdef CONFIG_COMPAT_32BIT_TIME
773 struct v4l2_event32_time32 {
774 __u32 type;
775 union {
776 compat_s64 value64;
777 __u8 data[64];
778 } u;
779 __u32 pending;
780 __u32 sequence;
781 struct old_timespec32 timestamp;
782 __u32 id;
783 __u32 reserved[8];
784 };
785
put_v4l2_event32_time32(struct v4l2_event * p64,struct v4l2_event32_time32 __user * p32)786 static int put_v4l2_event32_time32(struct v4l2_event *p64,
787 struct v4l2_event32_time32 __user *p32)
788 {
789 if (put_user(p64->type, &p32->type) ||
790 copy_to_user(&p32->u, &p64->u, sizeof(p64->u)) ||
791 put_user(p64->pending, &p32->pending) ||
792 put_user(p64->sequence, &p32->sequence) ||
793 put_user(p64->timestamp.tv_sec, &p32->timestamp.tv_sec) ||
794 put_user(p64->timestamp.tv_nsec, &p32->timestamp.tv_nsec) ||
795 put_user(p64->id, &p32->id) ||
796 copy_to_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
797 return -EFAULT;
798 return 0;
799 }
800 #endif
801
802 struct v4l2_edid32 {
803 __u32 pad;
804 __u32 start_block;
805 __u32 blocks;
806 __u32 reserved[5];
807 compat_caddr_t edid;
808 };
809
get_v4l2_edid32(struct v4l2_edid * p64,struct v4l2_edid32 __user * p32)810 static int get_v4l2_edid32(struct v4l2_edid *p64,
811 struct v4l2_edid32 __user *p32)
812 {
813 compat_uptr_t edid;
814
815 if (copy_from_user(p64, p32, offsetof(struct v4l2_edid32, edid)) ||
816 get_user(edid, &p32->edid))
817 return -EFAULT;
818
819 p64->edid = (void __force *)compat_ptr(edid);
820 return 0;
821 }
822
put_v4l2_edid32(struct v4l2_edid * p64,struct v4l2_edid32 __user * p32)823 static int put_v4l2_edid32(struct v4l2_edid *p64,
824 struct v4l2_edid32 __user *p32)
825 {
826 if (copy_to_user(p32, p64, offsetof(struct v4l2_edid32, edid)))
827 return -EFAULT;
828 return 0;
829 }
830
831 /*
832 * List of ioctls that require 32-bits/64-bits conversion
833 *
834 * The V4L2 ioctls that aren't listed there don't have pointer arguments
835 * and the struct size is identical for both 32 and 64 bits versions, so
836 * they don't need translations.
837 */
838
839 #define VIDIOC_G_FMT32 _IOWR('V', 4, struct v4l2_format32)
840 #define VIDIOC_S_FMT32 _IOWR('V', 5, struct v4l2_format32)
841 #define VIDIOC_QUERYBUF32 _IOWR('V', 9, struct v4l2_buffer32)
842 #define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32)
843 #define VIDIOC_S_FBUF32 _IOW ('V', 11, struct v4l2_framebuffer32)
844 #define VIDIOC_QBUF32 _IOWR('V', 15, struct v4l2_buffer32)
845 #define VIDIOC_DQBUF32 _IOWR('V', 17, struct v4l2_buffer32)
846 #define VIDIOC_ENUMSTD32 _IOWR('V', 25, struct v4l2_standard32)
847 #define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32)
848 #define VIDIOC_G_EDID32 _IOWR('V', 40, struct v4l2_edid32)
849 #define VIDIOC_S_EDID32 _IOWR('V', 41, struct v4l2_edid32)
850 #define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32)
851 #define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32)
852 #define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32)
853 #define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32)
854 #define VIDIOC_DQEVENT32 _IOR ('V', 89, struct v4l2_event32)
855 #define VIDIOC_CREATE_BUFS32 _IOWR('V', 92, struct v4l2_create_buffers32)
856 #define VIDIOC_PREPARE_BUF32 _IOWR('V', 93, struct v4l2_buffer32)
857
858 #ifdef CONFIG_COMPAT_32BIT_TIME
859 #define VIDIOC_QUERYBUF32_TIME32 _IOWR('V', 9, struct v4l2_buffer32_time32)
860 #define VIDIOC_QBUF32_TIME32 _IOWR('V', 15, struct v4l2_buffer32_time32)
861 #define VIDIOC_DQBUF32_TIME32 _IOWR('V', 17, struct v4l2_buffer32_time32)
862 #define VIDIOC_DQEVENT32_TIME32 _IOR ('V', 89, struct v4l2_event32_time32)
863 #define VIDIOC_PREPARE_BUF32_TIME32 _IOWR('V', 93, struct v4l2_buffer32_time32)
864 #endif
865
v4l2_compat_translate_cmd(unsigned int cmd)866 unsigned int v4l2_compat_translate_cmd(unsigned int cmd)
867 {
868 switch (cmd) {
869 case VIDIOC_G_FMT32:
870 return VIDIOC_G_FMT;
871 case VIDIOC_S_FMT32:
872 return VIDIOC_S_FMT;
873 case VIDIOC_TRY_FMT32:
874 return VIDIOC_TRY_FMT;
875 case VIDIOC_G_FBUF32:
876 return VIDIOC_G_FBUF;
877 case VIDIOC_S_FBUF32:
878 return VIDIOC_S_FBUF;
879 #ifdef CONFIG_COMPAT_32BIT_TIME
880 case VIDIOC_QUERYBUF32_TIME32:
881 return VIDIOC_QUERYBUF;
882 case VIDIOC_QBUF32_TIME32:
883 return VIDIOC_QBUF;
884 case VIDIOC_DQBUF32_TIME32:
885 return VIDIOC_DQBUF;
886 case VIDIOC_PREPARE_BUF32_TIME32:
887 return VIDIOC_PREPARE_BUF;
888 #endif
889 case VIDIOC_QUERYBUF32:
890 return VIDIOC_QUERYBUF;
891 case VIDIOC_QBUF32:
892 return VIDIOC_QBUF;
893 case VIDIOC_DQBUF32:
894 return VIDIOC_DQBUF;
895 case VIDIOC_CREATE_BUFS32:
896 return VIDIOC_CREATE_BUFS;
897 case VIDIOC_G_EXT_CTRLS32:
898 return VIDIOC_G_EXT_CTRLS;
899 case VIDIOC_S_EXT_CTRLS32:
900 return VIDIOC_S_EXT_CTRLS;
901 case VIDIOC_TRY_EXT_CTRLS32:
902 return VIDIOC_TRY_EXT_CTRLS;
903 case VIDIOC_PREPARE_BUF32:
904 return VIDIOC_PREPARE_BUF;
905 case VIDIOC_ENUMSTD32:
906 return VIDIOC_ENUMSTD;
907 case VIDIOC_ENUMINPUT32:
908 return VIDIOC_ENUMINPUT;
909 case VIDIOC_G_EDID32:
910 return VIDIOC_G_EDID;
911 case VIDIOC_S_EDID32:
912 return VIDIOC_S_EDID;
913 #ifdef CONFIG_X86_64
914 case VIDIOC_DQEVENT32:
915 return VIDIOC_DQEVENT;
916 #endif
917 #ifdef CONFIG_COMPAT_32BIT_TIME
918 case VIDIOC_DQEVENT32_TIME32:
919 return VIDIOC_DQEVENT;
920 #endif
921 }
922 return cmd;
923 }
924
v4l2_compat_get_user(void __user * arg,void * parg,unsigned int cmd)925 int v4l2_compat_get_user(void __user *arg, void *parg, unsigned int cmd)
926 {
927 switch (cmd) {
928 case VIDIOC_G_FMT32:
929 case VIDIOC_S_FMT32:
930 case VIDIOC_TRY_FMT32:
931 return get_v4l2_format32(parg, arg);
932
933 case VIDIOC_S_FBUF32:
934 return get_v4l2_framebuffer32(parg, arg);
935 #ifdef CONFIG_COMPAT_32BIT_TIME
936 case VIDIOC_QUERYBUF32_TIME32:
937 case VIDIOC_QBUF32_TIME32:
938 case VIDIOC_DQBUF32_TIME32:
939 case VIDIOC_PREPARE_BUF32_TIME32:
940 return get_v4l2_buffer32_time32(parg, arg);
941 #endif
942 case VIDIOC_QUERYBUF32:
943 case VIDIOC_QBUF32:
944 case VIDIOC_DQBUF32:
945 case VIDIOC_PREPARE_BUF32:
946 return get_v4l2_buffer32(parg, arg);
947
948 case VIDIOC_G_EXT_CTRLS32:
949 case VIDIOC_S_EXT_CTRLS32:
950 case VIDIOC_TRY_EXT_CTRLS32:
951 return get_v4l2_ext_controls32(parg, arg);
952
953 case VIDIOC_CREATE_BUFS32:
954 return get_v4l2_create32(parg, arg);
955
956 case VIDIOC_ENUMSTD32:
957 return get_v4l2_standard32(parg, arg);
958
959 case VIDIOC_ENUMINPUT32:
960 return get_v4l2_input32(parg, arg);
961
962 case VIDIOC_G_EDID32:
963 case VIDIOC_S_EDID32:
964 return get_v4l2_edid32(parg, arg);
965 }
966 return 0;
967 }
968
v4l2_compat_put_user(void __user * arg,void * parg,unsigned int cmd)969 int v4l2_compat_put_user(void __user *arg, void *parg, unsigned int cmd)
970 {
971 switch (cmd) {
972 case VIDIOC_G_FMT32:
973 case VIDIOC_S_FMT32:
974 case VIDIOC_TRY_FMT32:
975 return put_v4l2_format32(parg, arg);
976
977 case VIDIOC_G_FBUF32:
978 return put_v4l2_framebuffer32(parg, arg);
979 #ifdef CONFIG_COMPAT_32BIT_TIME
980 case VIDIOC_QUERYBUF32_TIME32:
981 case VIDIOC_QBUF32_TIME32:
982 case VIDIOC_DQBUF32_TIME32:
983 case VIDIOC_PREPARE_BUF32_TIME32:
984 return put_v4l2_buffer32_time32(parg, arg);
985 #endif
986 case VIDIOC_QUERYBUF32:
987 case VIDIOC_QBUF32:
988 case VIDIOC_DQBUF32:
989 case VIDIOC_PREPARE_BUF32:
990 return put_v4l2_buffer32(parg, arg);
991
992 case VIDIOC_G_EXT_CTRLS32:
993 case VIDIOC_S_EXT_CTRLS32:
994 case VIDIOC_TRY_EXT_CTRLS32:
995 return put_v4l2_ext_controls32(parg, arg);
996
997 case VIDIOC_CREATE_BUFS32:
998 return put_v4l2_create32(parg, arg);
999
1000 case VIDIOC_ENUMSTD32:
1001 return put_v4l2_standard32(parg, arg);
1002
1003 case VIDIOC_ENUMINPUT32:
1004 return put_v4l2_input32(parg, arg);
1005
1006 case VIDIOC_G_EDID32:
1007 case VIDIOC_S_EDID32:
1008 return put_v4l2_edid32(parg, arg);
1009 #ifdef CONFIG_X86_64
1010 case VIDIOC_DQEVENT32:
1011 return put_v4l2_event32(parg, arg);
1012 #endif
1013 #ifdef CONFIG_COMPAT_32BIT_TIME
1014 case VIDIOC_DQEVENT32_TIME32:
1015 return put_v4l2_event32_time32(parg, arg);
1016 #endif
1017 }
1018 return 0;
1019 }
1020
v4l2_compat_get_array_args(struct file * file,void * mbuf,void __user * user_ptr,size_t array_size,unsigned int cmd,void * arg)1021 int v4l2_compat_get_array_args(struct file *file, void *mbuf,
1022 void __user *user_ptr, size_t array_size,
1023 unsigned int cmd, void *arg)
1024 {
1025 int err = 0;
1026
1027 memset(mbuf, 0, array_size);
1028
1029 switch (cmd) {
1030 #ifdef CONFIG_COMPAT_32BIT_TIME
1031 case VIDIOC_QUERYBUF32_TIME32:
1032 case VIDIOC_QBUF32_TIME32:
1033 case VIDIOC_DQBUF32_TIME32:
1034 case VIDIOC_PREPARE_BUF32_TIME32:
1035 #endif
1036 case VIDIOC_QUERYBUF32:
1037 case VIDIOC_QBUF32:
1038 case VIDIOC_DQBUF32:
1039 case VIDIOC_PREPARE_BUF32: {
1040 struct v4l2_buffer *b64 = arg;
1041 struct v4l2_plane *p64 = mbuf;
1042 struct v4l2_plane32 __user *p32 = user_ptr;
1043
1044 if (V4L2_TYPE_IS_MULTIPLANAR(b64->type)) {
1045 u32 num_planes = b64->length;
1046
1047 if (num_planes == 0)
1048 return 0;
1049
1050 while (num_planes--) {
1051 err = get_v4l2_plane32(p64, p32, b64->memory);
1052 if (err)
1053 return err;
1054 ++p64;
1055 ++p32;
1056 }
1057 }
1058 break;
1059 }
1060 case VIDIOC_G_EXT_CTRLS32:
1061 case VIDIOC_S_EXT_CTRLS32:
1062 case VIDIOC_TRY_EXT_CTRLS32: {
1063 struct v4l2_ext_controls *ecs64 = arg;
1064 struct v4l2_ext_control *ec64 = mbuf;
1065 struct v4l2_ext_control32 __user *ec32 = user_ptr;
1066 int n;
1067
1068 for (n = 0; n < ecs64->count; n++) {
1069 if (copy_from_user(ec64, ec32, sizeof(*ec32)))
1070 return -EFAULT;
1071
1072 if (ctrl_is_pointer(file, ec64->id)) {
1073 compat_uptr_t p;
1074
1075 if (get_user(p, &ec32->string))
1076 return -EFAULT;
1077 ec64->string = compat_ptr(p);
1078 }
1079 ec32++;
1080 ec64++;
1081 }
1082 break;
1083 }
1084 default:
1085 if (copy_from_user(mbuf, user_ptr, array_size))
1086 err = -EFAULT;
1087 break;
1088 }
1089
1090 return err;
1091 }
1092
v4l2_compat_put_array_args(struct file * file,void __user * user_ptr,void * mbuf,size_t array_size,unsigned int cmd,void * arg)1093 int v4l2_compat_put_array_args(struct file *file, void __user *user_ptr,
1094 void *mbuf, size_t array_size,
1095 unsigned int cmd, void *arg)
1096 {
1097 int err = 0;
1098
1099 switch (cmd) {
1100 #ifdef CONFIG_COMPAT_32BIT_TIME
1101 case VIDIOC_QUERYBUF32_TIME32:
1102 case VIDIOC_QBUF32_TIME32:
1103 case VIDIOC_DQBUF32_TIME32:
1104 case VIDIOC_PREPARE_BUF32_TIME32:
1105 #endif
1106 case VIDIOC_QUERYBUF32:
1107 case VIDIOC_QBUF32:
1108 case VIDIOC_DQBUF32:
1109 case VIDIOC_PREPARE_BUF32: {
1110 struct v4l2_buffer *b64 = arg;
1111 struct v4l2_plane *p64 = mbuf;
1112 struct v4l2_plane32 __user *p32 = user_ptr;
1113
1114 if (V4L2_TYPE_IS_MULTIPLANAR(b64->type)) {
1115 u32 num_planes = b64->length;
1116
1117 if (num_planes == 0)
1118 return 0;
1119
1120 while (num_planes--) {
1121 err = put_v4l2_plane32(p64, p32, b64->memory);
1122 if (err)
1123 return err;
1124 ++p64;
1125 ++p32;
1126 }
1127 }
1128 break;
1129 }
1130 case VIDIOC_G_EXT_CTRLS32:
1131 case VIDIOC_S_EXT_CTRLS32:
1132 case VIDIOC_TRY_EXT_CTRLS32: {
1133 struct v4l2_ext_controls *ecs64 = arg;
1134 struct v4l2_ext_control *ec64 = mbuf;
1135 struct v4l2_ext_control32 __user *ec32 = user_ptr;
1136 int n;
1137
1138 for (n = 0; n < ecs64->count; n++) {
1139 unsigned int size = sizeof(*ec32);
1140 /*
1141 * Do not modify the pointer when copying a pointer
1142 * control. The contents of the pointer was changed,
1143 * not the pointer itself.
1144 * The structures are otherwise compatible.
1145 */
1146 if (ctrl_is_pointer(file, ec64->id))
1147 size -= sizeof(ec32->value64);
1148
1149 if (copy_to_user(ec32, ec64, size))
1150 return -EFAULT;
1151
1152 ec32++;
1153 ec64++;
1154 }
1155 break;
1156 }
1157 default:
1158 if (copy_to_user(user_ptr, mbuf, array_size))
1159 err = -EFAULT;
1160 break;
1161 }
1162
1163 return err;
1164 }
1165
1166 /**
1167 * v4l2_compat_ioctl32() - Handles a compat32 ioctl call
1168 *
1169 * @file: pointer to &struct file with the file handler
1170 * @cmd: ioctl to be called
1171 * @arg: arguments passed from/to the ioctl handler
1172 *
1173 * This function is meant to be used as .compat_ioctl fops at v4l2-dev.c
1174 * in order to deal with 32-bit calls on a 64-bits Kernel.
1175 *
1176 * This function calls do_video_ioctl() for non-private V4L2 ioctls.
1177 * If the function is a private one it calls vdev->fops->compat_ioctl32
1178 * instead.
1179 */
v4l2_compat_ioctl32(struct file * file,unsigned int cmd,unsigned long arg)1180 long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
1181 {
1182 struct video_device *vdev = video_devdata(file);
1183 long ret = -ENOIOCTLCMD;
1184
1185 if (!file->f_op->unlocked_ioctl)
1186 return ret;
1187
1188 if (!video_is_registered(vdev))
1189 return -ENODEV;
1190
1191 if (_IOC_TYPE(cmd) == 'V' && _IOC_NR(cmd) < BASE_VIDIOC_PRIVATE)
1192 ret = file->f_op->unlocked_ioctl(file, cmd,
1193 (unsigned long)compat_ptr(arg));
1194 else if (vdev->fops->compat_ioctl32)
1195 ret = vdev->fops->compat_ioctl32(file, cmd, arg);
1196
1197 if (ret == -ENOIOCTLCMD)
1198 pr_debug("compat_ioctl32: unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
1199 _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd);
1200 return ret;
1201 }
1202 EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32);
1203