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