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@ucw.cz) 9 * Copyright (C) 2005 Philippe De Muyter (phdm@macqel.be) 10 * Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl> 11 * 12 * These routines maintain argument size conversion between 32bit and 64bit 13 * ioctls. 14 */ 15 16#include <linux/compat.h> 17#include <linux/module.h> 18#include <linux/videodev2.h> 19#include <linux/v4l2-subdev.h> 20#include <media/v4l2-dev.h> 21#include <media/v4l2-ioctl.h> 22 23static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 24{ 25 long ret = -ENOIOCTLCMD; 26 27 if (file->f_op->unlocked_ioctl) 28 ret = file->f_op->unlocked_ioctl(file, cmd, arg); 29 30 return ret; 31} 32 33 34struct v4l2_clip32 { 35 struct v4l2_rect c; 36 compat_caddr_t next; 37}; 38 39struct v4l2_window32 { 40 struct v4l2_rect w; 41 __u32 field; /* enum v4l2_field */ 42 __u32 chromakey; 43 compat_caddr_t clips; /* actually struct v4l2_clip32 * */ 44 __u32 clipcount; 45 compat_caddr_t bitmap; 46}; 47 48static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) 49{ 50 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) || 51 copy_from_user(&kp->w, &up->w, sizeof(up->w)) || 52 get_user(kp->field, &up->field) || 53 get_user(kp->chromakey, &up->chromakey) || 54 get_user(kp->clipcount, &up->clipcount)) 55 return -EFAULT; 56 if (kp->clipcount > 2048) 57 return -EINVAL; 58 if (kp->clipcount) { 59 struct v4l2_clip32 __user *uclips; 60 struct v4l2_clip __user *kclips; 61 int n = kp->clipcount; 62 compat_caddr_t p; 63 64 if (get_user(p, &up->clips)) 65 return -EFAULT; 66 uclips = compat_ptr(p); 67 kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip)); 68 kp->clips = kclips; 69 while (--n >= 0) { 70 if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) 71 return -EFAULT; 72 if (put_user(n ? kclips + 1 : NULL, &kclips->next)) 73 return -EFAULT; 74 uclips += 1; 75 kclips += 1; 76 } 77 } else 78 kp->clips = NULL; 79 return 0; 80} 81 82static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) 83{ 84 if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || 85 put_user(kp->field, &up->field) || 86 put_user(kp->chromakey, &up->chromakey) || 87 put_user(kp->clipcount, &up->clipcount)) 88 return -EFAULT; 89 return 0; 90} 91 92static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) 93{ 94 if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format))) 95 return -EFAULT; 96 return 0; 97} 98 99static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, 100 struct v4l2_pix_format_mplane __user *up) 101{ 102 if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) 103 return -EFAULT; 104 return 0; 105} 106 107static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) 108{ 109 if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) 110 return -EFAULT; 111 return 0; 112} 113 114static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, 115 struct v4l2_pix_format_mplane __user *up) 116{ 117 if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) 118 return -EFAULT; 119 return 0; 120} 121 122static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) 123{ 124 if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) 125 return -EFAULT; 126 return 0; 127} 128 129static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) 130{ 131 if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format))) 132 return -EFAULT; 133 return 0; 134} 135 136static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) 137{ 138 if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format))) 139 return -EFAULT; 140 return 0; 141} 142 143static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up) 144{ 145 if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format))) 146 return -EFAULT; 147 return 0; 148} 149 150static inline int get_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up) 151{ 152 if (copy_from_user(kp, up, sizeof(struct v4l2_sdr_format))) 153 return -EFAULT; 154 return 0; 155} 156 157static inline int put_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up) 158{ 159 if (copy_to_user(up, kp, sizeof(struct v4l2_sdr_format))) 160 return -EFAULT; 161 return 0; 162} 163 164struct v4l2_format32 { 165 __u32 type; /* enum v4l2_buf_type */ 166 union { 167 struct v4l2_pix_format pix; 168 struct v4l2_pix_format_mplane pix_mp; 169 struct v4l2_window32 win; 170 struct v4l2_vbi_format vbi; 171 struct v4l2_sliced_vbi_format sliced; 172 struct v4l2_sdr_format sdr; 173 __u8 raw_data[200]; /* user-defined */ 174 } fmt; 175}; 176 177/** 178 * struct v4l2_create_buffers32 - VIDIOC_CREATE_BUFS32 argument 179 * @index: on return, index of the first created buffer 180 * @count: entry: number of requested buffers, 181 * return: number of created buffers 182 * @memory: buffer memory type 183 * @format: frame format, for which buffers are requested 184 * @reserved: future extensions 185 */ 186struct v4l2_create_buffers32 { 187 __u32 index; 188 __u32 count; 189 __u32 memory; /* enum v4l2_memory */ 190 struct v4l2_format32 format; 191 __u32 reserved[8]; 192}; 193 194static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) 195{ 196 if (get_user(kp->type, &up->type)) 197 return -EFAULT; 198 199 switch (kp->type) { 200 case V4L2_BUF_TYPE_VIDEO_CAPTURE: 201 case V4L2_BUF_TYPE_VIDEO_OUTPUT: 202 return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); 203 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: 204 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: 205 return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp, 206 &up->fmt.pix_mp); 207 case V4L2_BUF_TYPE_VIDEO_OVERLAY: 208 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: 209 return get_v4l2_window32(&kp->fmt.win, &up->fmt.win); 210 case V4L2_BUF_TYPE_VBI_CAPTURE: 211 case V4L2_BUF_TYPE_VBI_OUTPUT: 212 return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi); 213 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: 214 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: 215 return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced); 216 case V4L2_BUF_TYPE_SDR_CAPTURE: 217 case V4L2_BUF_TYPE_SDR_OUTPUT: 218 return get_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr); 219 default: 220 pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", 221 kp->type); 222 return -EINVAL; 223 } 224} 225 226static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) 227{ 228 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32))) 229 return -EFAULT; 230 return __get_v4l2_format32(kp, up); 231} 232 233static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) 234{ 235 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) || 236 copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format))) 237 return -EFAULT; 238 return __get_v4l2_format32(&kp->format, &up->format); 239} 240 241static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) 242{ 243 if (put_user(kp->type, &up->type)) 244 return -EFAULT; 245 246 switch (kp->type) { 247 case V4L2_BUF_TYPE_VIDEO_CAPTURE: 248 case V4L2_BUF_TYPE_VIDEO_OUTPUT: 249 return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); 250 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: 251 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: 252 return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp, 253 &up->fmt.pix_mp); 254 case V4L2_BUF_TYPE_VIDEO_OVERLAY: 255 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: 256 return put_v4l2_window32(&kp->fmt.win, &up->fmt.win); 257 case V4L2_BUF_TYPE_VBI_CAPTURE: 258 case V4L2_BUF_TYPE_VBI_OUTPUT: 259 return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi); 260 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: 261 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: 262 return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced); 263 case V4L2_BUF_TYPE_SDR_CAPTURE: 264 case V4L2_BUF_TYPE_SDR_OUTPUT: 265 return put_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr); 266 default: 267 pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", 268 kp->type); 269 return -EINVAL; 270 } 271} 272 273static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) 274{ 275 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32))) 276 return -EFAULT; 277 return __put_v4l2_format32(kp, up); 278} 279 280static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) 281{ 282 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) || 283 copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) || 284 copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved))) 285 return -EFAULT; 286 return __put_v4l2_format32(&kp->format, &up->format); 287} 288 289struct v4l2_standard32 { 290 __u32 index; 291 compat_u64 id; 292 __u8 name[24]; 293 struct v4l2_fract frameperiod; /* Frames, not fields */ 294 __u32 framelines; 295 __u32 reserved[4]; 296}; 297 298static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) 299{ 300 /* other fields are not set by the user, nor used by the driver */ 301 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) || 302 get_user(kp->index, &up->index)) 303 return -EFAULT; 304 return 0; 305} 306 307static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) 308{ 309 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) || 310 put_user(kp->index, &up->index) || 311 put_user(kp->id, &up->id) || 312 copy_to_user(up->name, kp->name, 24) || 313 copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) || 314 put_user(kp->framelines, &up->framelines) || 315 copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32))) 316 return -EFAULT; 317 return 0; 318} 319 320struct v4l2_plane32 { 321 __u32 bytesused; 322 __u32 length; 323 union { 324 __u32 mem_offset; 325 compat_long_t userptr; 326 __s32 fd; 327 } m; 328 __u32 data_offset; 329 __u32 reserved[11]; 330}; 331 332struct v4l2_buffer32 { 333 __u32 index; 334 __u32 type; /* enum v4l2_buf_type */ 335 __u32 bytesused; 336 __u32 flags; 337 __u32 field; /* enum v4l2_field */ 338 struct compat_timeval timestamp; 339 struct v4l2_timecode timecode; 340 __u32 sequence; 341 342 /* memory location */ 343 __u32 memory; /* enum v4l2_memory */ 344 union { 345 __u32 offset; 346 compat_long_t userptr; 347 compat_caddr_t planes; 348 __s32 fd; 349 } m; 350 __u32 length; 351 __u32 reserved2; 352 __u32 reserved; 353}; 354 355static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, 356 enum v4l2_memory memory) 357{ 358 void __user *up_pln; 359 compat_long_t p; 360 361 if (copy_in_user(up, up32, 2 * sizeof(__u32)) || 362 copy_in_user(&up->data_offset, &up32->data_offset, 363 sizeof(__u32))) 364 return -EFAULT; 365 366 if (memory == V4L2_MEMORY_USERPTR) { 367 if (get_user(p, &up32->m.userptr)) 368 return -EFAULT; 369 up_pln = compat_ptr(p); 370 if (put_user((unsigned long)up_pln, &up->m.userptr)) 371 return -EFAULT; 372 } else if (memory == V4L2_MEMORY_DMABUF) { 373 if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(int))) 374 return -EFAULT; 375 } else { 376 if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, 377 sizeof(__u32))) 378 return -EFAULT; 379 } 380 381 return 0; 382} 383 384static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, 385 enum v4l2_memory memory) 386{ 387 if (copy_in_user(up32, up, 2 * sizeof(__u32)) || 388 copy_in_user(&up32->data_offset, &up->data_offset, 389 sizeof(__u32))) 390 return -EFAULT; 391 392 /* For MMAP, driver might've set up the offset, so copy it back. 393 * USERPTR stays the same (was userspace-provided), so no copying. */ 394 if (memory == V4L2_MEMORY_MMAP) 395 if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset, 396 sizeof(__u32))) 397 return -EFAULT; 398 /* For DMABUF, driver might've set up the fd, so copy it back. */ 399 if (memory == V4L2_MEMORY_DMABUF) 400 if (copy_in_user(&up32->m.fd, &up->m.fd, 401 sizeof(int))) 402 return -EFAULT; 403 404 return 0; 405} 406 407static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) 408{ 409 struct v4l2_plane32 __user *uplane32; 410 struct v4l2_plane __user *uplane; 411 compat_caddr_t p; 412 int num_planes; 413 int ret; 414 415 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) || 416 get_user(kp->index, &up->index) || 417 get_user(kp->type, &up->type) || 418 get_user(kp->flags, &up->flags) || 419 get_user(kp->memory, &up->memory) || 420 get_user(kp->length, &up->length)) 421 return -EFAULT; 422 423 if (V4L2_TYPE_IS_OUTPUT(kp->type)) 424 if (get_user(kp->bytesused, &up->bytesused) || 425 get_user(kp->field, &up->field) || 426 get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || 427 get_user(kp->timestamp.tv_usec, 428 &up->timestamp.tv_usec)) 429 return -EFAULT; 430 431 if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { 432 num_planes = kp->length; 433 if (num_planes == 0) { 434 kp->m.planes = NULL; 435 /* num_planes == 0 is legal, e.g. when userspace doesn't 436 * need planes array on DQBUF*/ 437 return 0; 438 } 439 440 if (get_user(p, &up->m.planes)) 441 return -EFAULT; 442 443 uplane32 = compat_ptr(p); 444 if (!access_ok(VERIFY_READ, uplane32, 445 num_planes * sizeof(struct v4l2_plane32))) 446 return -EFAULT; 447 448 /* We don't really care if userspace decides to kill itself 449 * by passing a very big num_planes value */ 450 uplane = compat_alloc_user_space(num_planes * 451 sizeof(struct v4l2_plane)); 452 kp->m.planes = (__force struct v4l2_plane *)uplane; 453 454 while (--num_planes >= 0) { 455 ret = get_v4l2_plane32(uplane, uplane32, kp->memory); 456 if (ret) 457 return ret; 458 ++uplane; 459 ++uplane32; 460 } 461 } else { 462 switch (kp->memory) { 463 case V4L2_MEMORY_MMAP: 464 if (get_user(kp->m.offset, &up->m.offset)) 465 return -EFAULT; 466 break; 467 case V4L2_MEMORY_USERPTR: 468 { 469 compat_long_t tmp; 470 471 if (get_user(tmp, &up->m.userptr)) 472 return -EFAULT; 473 474 kp->m.userptr = (unsigned long)compat_ptr(tmp); 475 } 476 break; 477 case V4L2_MEMORY_OVERLAY: 478 if (get_user(kp->m.offset, &up->m.offset)) 479 return -EFAULT; 480 break; 481 case V4L2_MEMORY_DMABUF: 482 if (get_user(kp->m.fd, &up->m.fd)) 483 return -EFAULT; 484 break; 485 } 486 } 487 488 return 0; 489} 490 491static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) 492{ 493 struct v4l2_plane32 __user *uplane32; 494 struct v4l2_plane __user *uplane; 495 compat_caddr_t p; 496 int num_planes; 497 int ret; 498 499 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) || 500 put_user(kp->index, &up->index) || 501 put_user(kp->type, &up->type) || 502 put_user(kp->flags, &up->flags) || 503 put_user(kp->memory, &up->memory)) 504 return -EFAULT; 505 506 if (put_user(kp->bytesused, &up->bytesused) || 507 put_user(kp->field, &up->field) || 508 put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || 509 put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || 510 copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) || 511 put_user(kp->sequence, &up->sequence) || 512 put_user(kp->reserved2, &up->reserved2) || 513 put_user(kp->reserved, &up->reserved) || 514 put_user(kp->length, &up->length)) 515 return -EFAULT; 516 517 if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { 518 num_planes = kp->length; 519 if (num_planes == 0) 520 return 0; 521 522 uplane = (__force struct v4l2_plane __user *)kp->m.planes; 523 if (get_user(p, &up->m.planes)) 524 return -EFAULT; 525 uplane32 = compat_ptr(p); 526 527 while (--num_planes >= 0) { 528 ret = put_v4l2_plane32(uplane, uplane32, kp->memory); 529 if (ret) 530 return ret; 531 ++uplane; 532 ++uplane32; 533 } 534 } else { 535 switch (kp->memory) { 536 case V4L2_MEMORY_MMAP: 537 if (put_user(kp->m.offset, &up->m.offset)) 538 return -EFAULT; 539 break; 540 case V4L2_MEMORY_USERPTR: 541 if (put_user(kp->m.userptr, &up->m.userptr)) 542 return -EFAULT; 543 break; 544 case V4L2_MEMORY_OVERLAY: 545 if (put_user(kp->m.offset, &up->m.offset)) 546 return -EFAULT; 547 break; 548 case V4L2_MEMORY_DMABUF: 549 if (put_user(kp->m.fd, &up->m.fd)) 550 return -EFAULT; 551 break; 552 } 553 } 554 555 return 0; 556} 557 558struct v4l2_framebuffer32 { 559 __u32 capability; 560 __u32 flags; 561 compat_caddr_t base; 562 struct { 563 __u32 width; 564 __u32 height; 565 __u32 pixelformat; 566 __u32 field; 567 __u32 bytesperline; 568 __u32 sizeimage; 569 __u32 colorspace; 570 __u32 priv; 571 } fmt; 572}; 573 574static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) 575{ 576 u32 tmp; 577 578 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) || 579 get_user(tmp, &up->base) || 580 get_user(kp->capability, &up->capability) || 581 get_user(kp->flags, &up->flags) || 582 copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt))) 583 return -EFAULT; 584 kp->base = (__force void *)compat_ptr(tmp); 585 return 0; 586} 587 588static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) 589{ 590 u32 tmp = (u32)((unsigned long)kp->base); 591 592 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) || 593 put_user(tmp, &up->base) || 594 put_user(kp->capability, &up->capability) || 595 put_user(kp->flags, &up->flags) || 596 copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt))) 597 return -EFAULT; 598 return 0; 599} 600 601struct v4l2_input32 { 602 __u32 index; /* Which input */ 603 __u8 name[32]; /* Label */ 604 __u32 type; /* Type of input */ 605 __u32 audioset; /* Associated audios (bitfield) */ 606 __u32 tuner; /* Associated tuner */ 607 compat_u64 std; 608 __u32 status; 609 __u32 reserved[4]; 610}; 611 612/* The 64-bit v4l2_input struct has extra padding at the end of the struct. 613 Otherwise it is identical to the 32-bit version. */ 614static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) 615{ 616 if (copy_from_user(kp, up, sizeof(struct v4l2_input32))) 617 return -EFAULT; 618 return 0; 619} 620 621static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up) 622{ 623 if (copy_to_user(up, kp, sizeof(struct v4l2_input32))) 624 return -EFAULT; 625 return 0; 626} 627 628struct v4l2_ext_controls32 { 629 __u32 ctrl_class; 630 __u32 count; 631 __u32 error_idx; 632 __u32 reserved[2]; 633 compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */ 634}; 635 636struct v4l2_ext_control32 { 637 __u32 id; 638 __u32 size; 639 __u32 reserved2[1]; 640 union { 641 __s32 value; 642 __s64 value64; 643 compat_caddr_t string; /* actually char * */ 644 }; 645} __attribute__ ((packed)); 646 647/* The following function really belong in v4l2-common, but that causes 648 a circular dependency between modules. We need to think about this, but 649 for now this will do. */ 650 651/* Return non-zero if this control is a pointer type. Currently only 652 type STRING is a pointer type. */ 653static inline int ctrl_is_pointer(u32 id) 654{ 655 switch (id) { 656 case V4L2_CID_RDS_TX_PS_NAME: 657 case V4L2_CID_RDS_TX_RADIO_TEXT: 658 return 1; 659 default: 660 return 0; 661 } 662} 663 664static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) 665{ 666 struct v4l2_ext_control32 __user *ucontrols; 667 struct v4l2_ext_control __user *kcontrols; 668 int n; 669 compat_caddr_t p; 670 671 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) || 672 get_user(kp->ctrl_class, &up->ctrl_class) || 673 get_user(kp->count, &up->count) || 674 get_user(kp->error_idx, &up->error_idx) || 675 copy_from_user(kp->reserved, up->reserved, 676 sizeof(kp->reserved))) 677 return -EFAULT; 678 n = kp->count; 679 if (n == 0) { 680 kp->controls = NULL; 681 return 0; 682 } 683 if (get_user(p, &up->controls)) 684 return -EFAULT; 685 ucontrols = compat_ptr(p); 686 if (!access_ok(VERIFY_READ, ucontrols, 687 n * sizeof(struct v4l2_ext_control32))) 688 return -EFAULT; 689 kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); 690 kp->controls = (__force struct v4l2_ext_control *)kcontrols; 691 while (--n >= 0) { 692 u32 id; 693 694 if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols))) 695 return -EFAULT; 696 if (get_user(id, &kcontrols->id)) 697 return -EFAULT; 698 if (ctrl_is_pointer(id)) { 699 void __user *s; 700 701 if (get_user(p, &ucontrols->string)) 702 return -EFAULT; 703 s = compat_ptr(p); 704 if (put_user(s, &kcontrols->string)) 705 return -EFAULT; 706 } 707 ucontrols++; 708 kcontrols++; 709 } 710 return 0; 711} 712 713static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) 714{ 715 struct v4l2_ext_control32 __user *ucontrols; 716 struct v4l2_ext_control __user *kcontrols = 717 (__force struct v4l2_ext_control __user *)kp->controls; 718 int n = kp->count; 719 compat_caddr_t p; 720 721 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) || 722 put_user(kp->ctrl_class, &up->ctrl_class) || 723 put_user(kp->count, &up->count) || 724 put_user(kp->error_idx, &up->error_idx) || 725 copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) 726 return -EFAULT; 727 if (!kp->count) 728 return 0; 729 730 if (get_user(p, &up->controls)) 731 return -EFAULT; 732 ucontrols = compat_ptr(p); 733 if (!access_ok(VERIFY_WRITE, ucontrols, 734 n * sizeof(struct v4l2_ext_control32))) 735 return -EFAULT; 736 737 while (--n >= 0) { 738 unsigned size = sizeof(*ucontrols); 739 u32 id; 740 741 if (get_user(id, &kcontrols->id)) 742 return -EFAULT; 743 /* Do not modify the pointer when copying a pointer control. 744 The contents of the pointer was changed, not the pointer 745 itself. */ 746 if (ctrl_is_pointer(id)) 747 size -= sizeof(ucontrols->value64); 748 if (copy_in_user(ucontrols, kcontrols, size)) 749 return -EFAULT; 750 ucontrols++; 751 kcontrols++; 752 } 753 return 0; 754} 755 756struct v4l2_event32 { 757 __u32 type; 758 union { 759 compat_s64 value64; 760 __u8 data[64]; 761 } u; 762 __u32 pending; 763 __u32 sequence; 764 struct compat_timespec timestamp; 765 __u32 id; 766 __u32 reserved[8]; 767}; 768 769static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up) 770{ 771 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) || 772 put_user(kp->type, &up->type) || 773 copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || 774 put_user(kp->pending, &up->pending) || 775 put_user(kp->sequence, &up->sequence) || 776 compat_put_timespec(&kp->timestamp, &up->timestamp) || 777 put_user(kp->id, &up->id) || 778 copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32))) 779 return -EFAULT; 780 return 0; 781} 782 783struct v4l2_edid32 { 784 __u32 pad; 785 __u32 start_block; 786 __u32 blocks; 787 __u32 reserved[5]; 788 compat_caddr_t edid; 789}; 790 791static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) 792{ 793 u32 tmp; 794 795 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) || 796 get_user(kp->pad, &up->pad) || 797 get_user(kp->start_block, &up->start_block) || 798 get_user(kp->blocks, &up->blocks) || 799 get_user(tmp, &up->edid) || 800 copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) 801 return -EFAULT; 802 kp->edid = (__force u8 *)compat_ptr(tmp); 803 return 0; 804} 805 806static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) 807{ 808 u32 tmp = (u32)((unsigned long)kp->edid); 809 810 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) || 811 put_user(kp->pad, &up->pad) || 812 put_user(kp->start_block, &up->start_block) || 813 put_user(kp->blocks, &up->blocks) || 814 put_user(tmp, &up->edid) || 815 copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) 816 return -EFAULT; 817 return 0; 818} 819 820 821#define VIDIOC_G_FMT32 _IOWR('V', 4, struct v4l2_format32) 822#define VIDIOC_S_FMT32 _IOWR('V', 5, struct v4l2_format32) 823#define VIDIOC_QUERYBUF32 _IOWR('V', 9, struct v4l2_buffer32) 824#define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32) 825#define VIDIOC_S_FBUF32 _IOW ('V', 11, struct v4l2_framebuffer32) 826#define VIDIOC_QBUF32 _IOWR('V', 15, struct v4l2_buffer32) 827#define VIDIOC_DQBUF32 _IOWR('V', 17, struct v4l2_buffer32) 828#define VIDIOC_ENUMSTD32 _IOWR('V', 25, struct v4l2_standard32) 829#define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32) 830#define VIDIOC_G_EDID32 _IOWR('V', 40, struct v4l2_edid32) 831#define VIDIOC_S_EDID32 _IOWR('V', 41, struct v4l2_edid32) 832#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32) 833#define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32) 834#define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32) 835#define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32) 836#define VIDIOC_DQEVENT32 _IOR ('V', 89, struct v4l2_event32) 837#define VIDIOC_CREATE_BUFS32 _IOWR('V', 92, struct v4l2_create_buffers32) 838#define VIDIOC_PREPARE_BUF32 _IOWR('V', 93, struct v4l2_buffer32) 839 840#define VIDIOC_OVERLAY32 _IOW ('V', 14, s32) 841#define VIDIOC_STREAMON32 _IOW ('V', 18, s32) 842#define VIDIOC_STREAMOFF32 _IOW ('V', 19, s32) 843#define VIDIOC_G_INPUT32 _IOR ('V', 38, s32) 844#define VIDIOC_S_INPUT32 _IOWR('V', 39, s32) 845#define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32) 846#define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32) 847 848static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 849{ 850 union { 851 struct v4l2_format v2f; 852 struct v4l2_buffer v2b; 853 struct v4l2_framebuffer v2fb; 854 struct v4l2_input v2i; 855 struct v4l2_standard v2s; 856 struct v4l2_ext_controls v2ecs; 857 struct v4l2_event v2ev; 858 struct v4l2_create_buffers v2crt; 859 struct v4l2_edid v2edid; 860 unsigned long vx; 861 int vi; 862 } karg; 863 void __user *up = compat_ptr(arg); 864 int compatible_arg = 1; 865 long err = 0; 866 867 /* First, convert the command. */ 868 switch (cmd) { 869 case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break; 870 case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break; 871 case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break; 872 case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break; 873 case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break; 874 case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break; 875 case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break; 876 case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break; 877 case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break; 878 case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break; 879 case VIDIOC_G_EXT_CTRLS32: cmd = VIDIOC_G_EXT_CTRLS; break; 880 case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break; 881 case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break; 882 case VIDIOC_DQEVENT32: cmd = VIDIOC_DQEVENT; break; 883 case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break; 884 case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break; 885 case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break; 886 case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break; 887 case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break; 888 case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break; 889 case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break; 890 case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break; 891 case VIDIOC_PREPARE_BUF32: cmd = VIDIOC_PREPARE_BUF; break; 892 case VIDIOC_G_EDID32: cmd = VIDIOC_G_EDID; break; 893 case VIDIOC_S_EDID32: cmd = VIDIOC_S_EDID; break; 894 } 895 896 switch (cmd) { 897 case VIDIOC_OVERLAY: 898 case VIDIOC_STREAMON: 899 case VIDIOC_STREAMOFF: 900 case VIDIOC_S_INPUT: 901 case VIDIOC_S_OUTPUT: 902 err = get_user(karg.vi, (s32 __user *)up); 903 compatible_arg = 0; 904 break; 905 906 case VIDIOC_G_INPUT: 907 case VIDIOC_G_OUTPUT: 908 compatible_arg = 0; 909 break; 910 911 case VIDIOC_G_EDID: 912 case VIDIOC_S_EDID: 913 err = get_v4l2_edid32(&karg.v2edid, up); 914 compatible_arg = 0; 915 break; 916 917 case VIDIOC_G_FMT: 918 case VIDIOC_S_FMT: 919 case VIDIOC_TRY_FMT: 920 err = get_v4l2_format32(&karg.v2f, up); 921 compatible_arg = 0; 922 break; 923 924 case VIDIOC_CREATE_BUFS: 925 err = get_v4l2_create32(&karg.v2crt, up); 926 compatible_arg = 0; 927 break; 928 929 case VIDIOC_PREPARE_BUF: 930 case VIDIOC_QUERYBUF: 931 case VIDIOC_QBUF: 932 case VIDIOC_DQBUF: 933 err = get_v4l2_buffer32(&karg.v2b, up); 934 compatible_arg = 0; 935 break; 936 937 case VIDIOC_S_FBUF: 938 err = get_v4l2_framebuffer32(&karg.v2fb, up); 939 compatible_arg = 0; 940 break; 941 942 case VIDIOC_G_FBUF: 943 compatible_arg = 0; 944 break; 945 946 case VIDIOC_ENUMSTD: 947 err = get_v4l2_standard32(&karg.v2s, up); 948 compatible_arg = 0; 949 break; 950 951 case VIDIOC_ENUMINPUT: 952 err = get_v4l2_input32(&karg.v2i, up); 953 compatible_arg = 0; 954 break; 955 956 case VIDIOC_G_EXT_CTRLS: 957 case VIDIOC_S_EXT_CTRLS: 958 case VIDIOC_TRY_EXT_CTRLS: 959 err = get_v4l2_ext_controls32(&karg.v2ecs, up); 960 compatible_arg = 0; 961 break; 962 case VIDIOC_DQEVENT: 963 compatible_arg = 0; 964 break; 965 } 966 if (err) 967 return err; 968 969 if (compatible_arg) 970 err = native_ioctl(file, cmd, (unsigned long)up); 971 else { 972 mm_segment_t old_fs = get_fs(); 973 974 set_fs(KERNEL_DS); 975 err = native_ioctl(file, cmd, (unsigned long)&karg); 976 set_fs(old_fs); 977 } 978 979 /* Special case: even after an error we need to put the 980 results back for these ioctls since the error_idx will 981 contain information on which control failed. */ 982 switch (cmd) { 983 case VIDIOC_G_EXT_CTRLS: 984 case VIDIOC_S_EXT_CTRLS: 985 case VIDIOC_TRY_EXT_CTRLS: 986 if (put_v4l2_ext_controls32(&karg.v2ecs, up)) 987 err = -EFAULT; 988 break; 989 } 990 if (err) 991 return err; 992 993 switch (cmd) { 994 case VIDIOC_S_INPUT: 995 case VIDIOC_S_OUTPUT: 996 case VIDIOC_G_INPUT: 997 case VIDIOC_G_OUTPUT: 998 err = put_user(((s32)karg.vi), (s32 __user *)up); 999 break; 1000 1001 case VIDIOC_G_FBUF: 1002 err = put_v4l2_framebuffer32(&karg.v2fb, up); 1003 break; 1004 1005 case VIDIOC_DQEVENT: 1006 err = put_v4l2_event32(&karg.v2ev, up); 1007 break; 1008 1009 case VIDIOC_G_EDID: 1010 case VIDIOC_S_EDID: 1011 err = put_v4l2_edid32(&karg.v2edid, up); 1012 break; 1013 1014 case VIDIOC_G_FMT: 1015 case VIDIOC_S_FMT: 1016 case VIDIOC_TRY_FMT: 1017 err = put_v4l2_format32(&karg.v2f, up); 1018 break; 1019 1020 case VIDIOC_CREATE_BUFS: 1021 err = put_v4l2_create32(&karg.v2crt, up); 1022 break; 1023 1024 case VIDIOC_QUERYBUF: 1025 case VIDIOC_QBUF: 1026 case VIDIOC_DQBUF: 1027 err = put_v4l2_buffer32(&karg.v2b, up); 1028 break; 1029 1030 case VIDIOC_ENUMSTD: 1031 err = put_v4l2_standard32(&karg.v2s, up); 1032 break; 1033 1034 case VIDIOC_ENUMINPUT: 1035 err = put_v4l2_input32(&karg.v2i, up); 1036 break; 1037 } 1038 return err; 1039} 1040 1041long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) 1042{ 1043 struct video_device *vdev = video_devdata(file); 1044 long ret = -ENOIOCTLCMD; 1045 1046 if (!file->f_op->unlocked_ioctl) 1047 return ret; 1048 1049 if (_IOC_TYPE(cmd) == 'V' && _IOC_NR(cmd) < BASE_VIDIOC_PRIVATE) 1050 ret = do_video_ioctl(file, cmd, arg); 1051 else if (vdev->fops->compat_ioctl32) 1052 ret = vdev->fops->compat_ioctl32(file, cmd, arg); 1053 1054 if (ret == -ENOIOCTLCMD) 1055 pr_debug("compat_ioctl32: unknown ioctl '%c', dir=%d, #%d (0x%08x)\n", 1056 _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd); 1057 return ret; 1058} 1059EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32); 1060