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