Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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