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