linux/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
<<
>>
Prefs
   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/* Use the same argument order as copy_in_user */
  24#define assign_in_user(to, from)                                        \
  25({                                                                      \
  26        typeof(*from) __assign_tmp;                                     \
  27                                                                        \
  28        get_user(__assign_tmp, from) || put_user(__assign_tmp, to);     \
  29})
  30
  31static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  32{
  33        long ret = -ENOIOCTLCMD;
  34
  35        if (file->f_op->unlocked_ioctl)
  36                ret = file->f_op->unlocked_ioctl(file, cmd, arg);
  37
  38        return ret;
  39}
  40
  41
  42struct v4l2_clip32 {
  43        struct v4l2_rect        c;
  44        compat_caddr_t          next;
  45};
  46
  47struct v4l2_window32 {
  48        struct v4l2_rect        w;
  49        __u32                   field;  /* enum v4l2_field */
  50        __u32                   chromakey;
  51        compat_caddr_t          clips; /* actually struct v4l2_clip32 * */
  52        __u32                   clipcount;
  53        compat_caddr_t          bitmap;
  54};
  55
  56static int get_v4l2_window32(struct v4l2_window __user *kp,
  57                             struct v4l2_window32 __user *up,
  58                             void __user *aux_buf, u32 aux_space)
  59{
  60        u32 clipcount;
  61
  62        if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) ||
  63                copy_in_user(&kp->w, &up->w, sizeof(up->w)) ||
  64                assign_in_user(&kp->field, &up->field) ||
  65                assign_in_user(&kp->chromakey, &up->chromakey) ||
  66                get_user(clipcount, &up->clipcount) ||
  67                put_user(clipcount, &kp->clipcount))
  68                        return -EFAULT;
  69        if (clipcount > 2048)
  70                return -EINVAL;
  71        if (clipcount) {
  72                struct v4l2_clip32 __user *uclips;
  73                struct v4l2_clip __user *kclips;
  74                compat_caddr_t p;
  75
  76                if (get_user(p, &up->clips))
  77                        return -EFAULT;
  78                uclips = compat_ptr(p);
  79                if (aux_space < clipcount * sizeof(*kclips))
  80                        return -EFAULT;
  81                kclips = aux_buf;
  82                if (put_user(kclips, &kp->clips))
  83                        return -EFAULT;
  84
  85                while (--clipcount >= 0) {
  86                        if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
  87                                return -EFAULT;
  88                        if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next))
  89                                return -EFAULT;
  90                        uclips += 1;
  91                        kclips += 1;
  92                }
  93        } else
  94                return put_user(NULL, &kp->clips);
  95        return 0;
  96}
  97
  98static int put_v4l2_window32(struct v4l2_window __user *kp,
  99                             struct v4l2_window32 __user *up)
 100{
 101        u32 clipcount;
 102
 103        if (copy_in_user(&up->w, &kp->w, sizeof(kp->w)) ||
 104            assign_in_user(&up->field, &kp->field) ||
 105            assign_in_user(&up->chromakey, &kp->chromakey) ||
 106            get_user(clipcount, &kp->clipcount) ||
 107            put_user(clipcount, &up->clipcount))
 108                        return -EFAULT;
 109        return 0;
 110}
 111
 112static inline int get_v4l2_pix_format(struct v4l2_pix_format __user *kp,
 113                                      struct v4l2_pix_format __user *up)
 114{
 115        if (copy_in_user(kp, up, sizeof(struct v4l2_pix_format)))
 116                return -EFAULT;
 117        return 0;
 118}
 119
 120static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane __user *kp,
 121                                             struct v4l2_pix_format_mplane __user *up)
 122{
 123        if (copy_in_user(kp, up, sizeof(struct v4l2_pix_format_mplane)))
 124                return -EFAULT;
 125        return 0;
 126}
 127
 128static inline int put_v4l2_pix_format(struct v4l2_pix_format __user *kp,
 129                                      struct v4l2_pix_format __user *up)
 130{
 131        if (copy_in_user(up, kp, sizeof(struct v4l2_pix_format)))
 132                return -EFAULT;
 133        return 0;
 134}
 135
 136static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane __user *kp,
 137                                             struct v4l2_pix_format_mplane __user *up)
 138{
 139        if (copy_in_user(up, kp, sizeof(struct v4l2_pix_format_mplane)))
 140                return -EFAULT;
 141        return 0;
 142}
 143
 144static inline int get_v4l2_vbi_format(struct v4l2_vbi_format __user *kp,
 145                                      struct v4l2_vbi_format __user *up)
 146{
 147        if (copy_in_user(kp, up, sizeof(struct v4l2_vbi_format)))
 148                return -EFAULT;
 149        return 0;
 150}
 151
 152static inline int put_v4l2_vbi_format(struct v4l2_vbi_format __user *kp,
 153                                      struct v4l2_vbi_format __user *up)
 154{
 155        if (copy_in_user(up, kp, sizeof(struct v4l2_vbi_format)))
 156                return -EFAULT;
 157        return 0;
 158}
 159
 160static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format __user *kp,
 161                                             struct v4l2_sliced_vbi_format __user *up)
 162{
 163        if (copy_in_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
 164                return -EFAULT;
 165        return 0;
 166}
 167
 168static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format __user *kp,
 169                                             struct v4l2_sliced_vbi_format __user *up)
 170{
 171        if (copy_in_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
 172                return -EFAULT;
 173        return 0;
 174}
 175
 176struct v4l2_format32 {
 177        __u32   type;   /* enum v4l2_buf_type */
 178        union {
 179                struct v4l2_pix_format  pix;
 180                struct v4l2_pix_format_mplane   pix_mp;
 181                struct v4l2_window32    win;
 182                struct v4l2_vbi_format  vbi;
 183                struct v4l2_sliced_vbi_format   sliced;
 184                __u8    raw_data[200];        /* user-defined */
 185        } fmt;
 186};
 187
 188/**
 189 * struct v4l2_create_buffers32 - VIDIOC_CREATE_BUFS32 argument
 190 * @index:      on return, index of the first created buffer
 191 * @count:      entry: number of requested buffers,
 192 *              return: number of created buffers
 193 * @memory:     buffer memory type
 194 * @format:     frame format, for which buffers are requested
 195 * @reserved:   future extensions
 196 */
 197struct v4l2_create_buffers32 {
 198        __u32                   index;
 199        __u32                   count;
 200        __u32                   memory; /* enum v4l2_memory */
 201        struct v4l2_format32    format;
 202        __u32                   reserved[8];
 203};
 204
 205static int __bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
 206{
 207        u32 type;
 208
 209        if (get_user(type, &up->type))
 210                return -EFAULT;
 211
 212        switch (type) {
 213        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 214        case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
 215                u32 clipcount;
 216
 217                if (get_user(clipcount, &up->fmt.win.clipcount))
 218                        return -EFAULT;
 219                if (clipcount > 2048)
 220                        return -EINVAL;
 221                *size = clipcount * sizeof(struct v4l2_clip);
 222                return 0;
 223        }
 224        default:
 225                *size = 0;
 226                return 0;
 227        }
 228}
 229
 230static int bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
 231{
 232        if (!access_ok(VERIFY_READ, up, sizeof(*up)))
 233                return -EFAULT;
 234        return __bufsize_v4l2_format(up, size);
 235}
 236
 237static int __get_v4l2_format32(struct v4l2_format __user *kp,
 238                               struct v4l2_format32 __user *up,
 239                               void __user *aux_buf, u32 aux_space)
 240{
 241        u32 type;
 242
 243        if (get_user(type, &up->type) || put_user(type, &kp->type))
 244                return -EFAULT;
 245
 246        switch (type) {
 247        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 248        case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 249                return get_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 get_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 get_v4l2_window32(&kp->fmt.win, &up->fmt.win,
 257                                         aux_buf, aux_space);
 258        case V4L2_BUF_TYPE_VBI_CAPTURE:
 259        case V4L2_BUF_TYPE_VBI_OUTPUT:
 260                return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
 261        case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
 262        case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
 263                return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
 264        default:
 265                printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
 266                                                                kp->type);
 267                return -EINVAL;
 268        }
 269}
 270
 271static int get_v4l2_format32(struct v4l2_format __user *kp,
 272                             struct v4l2_format32 __user *up,
 273                             void __user *aux_buf, u32 aux_space)
 274{
 275        if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) ||
 276                        get_user(kp->type, &up->type))
 277                        return -EFAULT;
 278        return __get_v4l2_format32(kp, up, aux_buf, aux_space);
 279}
 280
 281static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *up,
 282                               u32 *size)
 283{
 284        if (!access_ok(VERIFY_READ, up, sizeof(*up)))
 285                return -EFAULT;
 286        return __bufsize_v4l2_format(&up->format, size);
 287}
 288
 289static int get_v4l2_create32(struct v4l2_create_buffers __user *kp,
 290                             struct v4l2_create_buffers32 __user *up,
 291                             void __user *aux_buf, u32 aux_space)
 292{
 293        if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) ||
 294            copy_in_user(kp, up,
 295                         offsetof(struct v4l2_create_buffers32, format.fmt)))
 296                return -EFAULT;
 297        return __get_v4l2_format32(&kp->format, &up->format,
 298                                   aux_buf, aux_space);
 299}
 300
 301static int __put_v4l2_format32(struct v4l2_format __user *kp,
 302                               struct v4l2_format32 __user *up)
 303{
 304        u32 type;
 305
 306        if (get_user(type, &kp->type))
 307                return -EFAULT;
 308
 309        switch (type) {
 310        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 311        case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 312                return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
 313        case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 314        case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 315                return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
 316                                                  &up->fmt.pix_mp);
 317        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 318        case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
 319                return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
 320        case V4L2_BUF_TYPE_VBI_CAPTURE:
 321        case V4L2_BUF_TYPE_VBI_OUTPUT:
 322                return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
 323        case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
 324        case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
 325                return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
 326        default:
 327                printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
 328                                                                kp->type);
 329                return -EINVAL;
 330        }
 331}
 332
 333static int put_v4l2_format32(struct v4l2_format __user *kp,
 334                             struct v4l2_format32 __user *up)
 335{
 336        if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)))
 337                return -EFAULT;
 338        return __put_v4l2_format32(kp, up);
 339}
 340
 341static int put_v4l2_create32(struct v4l2_create_buffers __user *kp,
 342                             struct v4l2_create_buffers32 __user *up)
 343{
 344        if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) ||
 345            copy_in_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt)))
 346                return -EFAULT;
 347        return __put_v4l2_format32(&kp->format, &up->format);
 348}
 349
 350struct v4l2_standard32 {
 351        __u32                index;
 352        compat_u64           id;
 353        __u8                 name[24];
 354        struct v4l2_fract    frameperiod; /* Frames, not fields */
 355        __u32                framelines;
 356        __u32                reserved[4];
 357};
 358
 359static int get_v4l2_standard32(struct v4l2_standard __user *kp,
 360                               struct v4l2_standard32 __user *up)
 361{
 362        /* other fields are not set by the user, nor used by the driver */
 363        if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
 364            assign_in_user(&kp->index, &up->index))
 365                return -EFAULT;
 366        return 0;
 367}
 368
 369static int put_v4l2_standard32(struct v4l2_standard __user *kp,
 370                               struct v4l2_standard32 __user *up)
 371{
 372        if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
 373            assign_in_user(&up->index, &kp->index) ||
 374            assign_in_user(&up->id, &kp->id) ||
 375            copy_in_user(up->name, kp->name, sizeof(up->name)) ||
 376            copy_in_user(&up->frameperiod, &kp->frameperiod,
 377                         sizeof(up->frameperiod)) ||
 378            assign_in_user(&up->framelines, &kp->framelines) ||
 379            copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
 380                return -EFAULT;
 381        return 0;
 382}
 383
 384struct v4l2_plane32 {
 385        __u32                   bytesused;
 386        __u32                   length;
 387        union {
 388                __u32           mem_offset;
 389                compat_long_t   userptr;
 390                __s32           fd;
 391        } m;
 392        __u32                   data_offset;
 393        __u32                   reserved[11];
 394};
 395
 396struct v4l2_buffer32 {
 397        __u32                   index;
 398        __u32                   type;   /* enum v4l2_buf_type */
 399        __u32                   bytesused;
 400        __u32                   flags;
 401        __u32                   field;  /* enum v4l2_field */
 402        struct compat_timeval   timestamp;
 403        struct v4l2_timecode    timecode;
 404        __u32                   sequence;
 405
 406        /* memory location */
 407        __u32                   memory; /* enum v4l2_memory */
 408        union {
 409                __u32           offset;
 410                compat_long_t   userptr;
 411                compat_caddr_t  planes;
 412                __s32           fd;
 413        } m;
 414        __u32                   length;
 415        __u32                   reserved2;
 416        __u32                   reserved;
 417};
 418
 419static int get_v4l2_plane32(struct v4l2_plane __user *up,
 420                            struct v4l2_plane32 __user *up32,
 421                            enum v4l2_memory memory)
 422{
 423        compat_ulong_t p;
 424
 425        if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
 426                copy_in_user(&up->data_offset, &up32->data_offset,
 427                                sizeof(__u32)))
 428                return -EFAULT;
 429
 430        if (memory == V4L2_MEMORY_USERPTR) {
 431                if (get_user(p, &up32->m.userptr) ||
 432                    put_user((unsigned long)compat_ptr(p), &up->m.userptr))
 433                        return -EFAULT;
 434        } else if (memory == V4L2_MEMORY_DMABUF) {
 435                if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(int)))
 436                        return -EFAULT;
 437        } else {
 438                if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
 439                                        sizeof(__u32)))
 440                        return -EFAULT;
 441        }
 442
 443        return 0;
 444}
 445
 446static int put_v4l2_plane32(struct v4l2_plane __user *up,
 447                            struct v4l2_plane32 __user *up32,
 448                            enum v4l2_memory memory)
 449{
 450        if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
 451                copy_in_user(&up32->data_offset, &up->data_offset,
 452                                sizeof(__u32)))
 453                return -EFAULT;
 454
 455        /* For MMAP, driver might've set up the offset, so copy it back.
 456         * USERPTR stays the same (was userspace-provided), so no copying. */
 457        if (memory == V4L2_MEMORY_MMAP)
 458                if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
 459                                        sizeof(__u32)))
 460                        return -EFAULT;
 461        /* For DMABUF, driver might've set up the fd, so copy it back. */
 462        if (memory == V4L2_MEMORY_DMABUF)
 463                if (copy_in_user(&up32->m.fd, &up->m.fd, sizeof(int)))
 464                        return -EFAULT;
 465
 466        return 0;
 467}
 468
 469static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *up, u32 *size)
 470{
 471        u32 type;
 472        u32 length;
 473
 474        if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
 475            get_user(type, &up->type) ||
 476            get_user(length, &up->length))
 477                return -EFAULT;
 478
 479        if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
 480                if (length > VIDEO_MAX_PLANES)
 481                        return -EINVAL;
 482
 483                /*
 484                 * We don't really care if userspace decides to kill itself
 485                 * by passing a very big length value
 486                 */
 487                *size = length * sizeof(struct v4l2_plane);
 488        } else {
 489                *size = 0;
 490        }
 491        return 0;
 492}
 493
 494static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
 495                             struct v4l2_buffer32 __user *up,
 496                             void __user *aux_buf, u32 aux_space)
 497{
 498        u32 type;
 499        u32 length;
 500        enum v4l2_memory memory;
 501        struct v4l2_plane32 __user *uplane32;
 502        struct v4l2_plane __user *uplane;
 503        compat_caddr_t p;
 504        int ret;
 505
 506        if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
 507            assign_in_user(&kp->index, &up->index) ||
 508            get_user(type, &up->type) ||
 509            put_user(type, &kp->type) ||
 510            assign_in_user(&kp->flags, &up->flags) ||
 511            get_user(memory, &up->memory) ||
 512            put_user(memory, &kp->memory) ||
 513            get_user(length, &up->length) ||
 514            put_user(length, &kp->length))
 515                return -EFAULT;
 516
 517        if (V4L2_TYPE_IS_OUTPUT(type))
 518                if (assign_in_user(&kp->bytesused, &up->bytesused) ||
 519                    assign_in_user(&kp->field, &up->field) ||
 520                    assign_in_user(&kp->timestamp.tv_sec,
 521                                   &up->timestamp.tv_sec) ||
 522                    assign_in_user(&kp->timestamp.tv_usec,
 523                                   &up->timestamp.tv_usec))
 524                        return -EFAULT;
 525
 526        if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
 527                u32 num_planes = length;
 528
 529                if (num_planes == 0) {
 530                        /*
 531                         * num_planes == 0 is legal, e.g. when userspace doesn't
 532                         * need planes array on DQBUF
 533                         */
 534                        return put_user(NULL, &kp->m.planes);
 535                }
 536                if (num_planes > VIDEO_MAX_PLANES)
 537                        return -EINVAL;
 538
 539                if (get_user(p, &up->m.planes))
 540                        return -EFAULT;
 541
 542                uplane32 = compat_ptr(p);
 543                if (!access_ok(VERIFY_READ, uplane32,
 544                               num_planes * sizeof(struct v4l2_plane32)))
 545                        return -EFAULT;
 546
 547                /*
 548                 * We don't really care if userspace decides to kill itself
 549                 * by passing a very big num_planes value
 550                 */
 551                if (aux_space < num_planes * sizeof(*uplane))
 552                        return -EFAULT;
 553
 554                uplane = aux_buf;
 555                if (put_user((__force struct v4l2_plane *)uplane,
 556                             &kp->m.planes))
 557                        return -EFAULT;
 558
 559                while (num_planes--) {
 560                        ret = get_v4l2_plane32(uplane, uplane32, memory);
 561                        if (ret)
 562                                return ret;
 563                        uplane++;
 564                        uplane32++;
 565                }
 566        } else {
 567                switch (memory) {
 568                case V4L2_MEMORY_MMAP:
 569                        if (assign_in_user(&kp->m.offset, &up->m.offset))
 570                                return -EFAULT;
 571                        break;
 572                case V4L2_MEMORY_USERPTR: {
 573                        compat_ulong_t userptr;
 574
 575                        if (get_user(userptr, &up->m.userptr) ||
 576                            put_user((unsigned long)compat_ptr(userptr),
 577                                     &kp->m.userptr))
 578                                return -EFAULT;
 579                        }
 580                        break;
 581                case V4L2_MEMORY_OVERLAY:
 582                        if (assign_in_user(&kp->m.offset, &up->m.offset))
 583                                return -EFAULT;
 584                        break;
 585                case V4L2_MEMORY_DMABUF:
 586                        if (assign_in_user(&kp->m.fd, &up->m.fd))
 587                                return -EFAULT;
 588                        break;
 589                }
 590        }
 591
 592        return 0;
 593}
 594
 595static int put_v4l2_buffer32(struct v4l2_buffer __user *kp,
 596                             struct v4l2_buffer32 __user *up)
 597{
 598        u32 type;
 599        u32 length;
 600        enum v4l2_memory memory;
 601        struct v4l2_plane32 __user *uplane32;
 602        struct v4l2_plane __user *uplane;
 603        compat_caddr_t p;
 604        int ret;
 605
 606        if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
 607            assign_in_user(&up->index, &kp->index) ||
 608            get_user(type, &kp->type) ||
 609            put_user(type, &up->type) ||
 610            assign_in_user(&up->flags, &kp->flags) ||
 611            get_user(memory, &kp->memory) ||
 612            put_user(memory, &up->memory))
 613                return -EFAULT;
 614
 615        if (assign_in_user(&up->bytesused, &kp->bytesused) ||
 616            assign_in_user(&up->field, &kp->field) ||
 617            assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
 618            assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) ||
 619            copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) ||
 620            assign_in_user(&up->sequence, &kp->sequence) ||
 621            assign_in_user(&up->reserved2, &kp->reserved2) ||
 622            assign_in_user(&up->reserved, &kp->reserved) ||
 623            get_user(length, &kp->length) ||
 624            put_user(length, &up->length))
 625                return -EFAULT;
 626
 627        if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
 628                u32 num_planes = length;
 629
 630                if (num_planes == 0)
 631                        return 0;
 632
 633                if (get_user(uplane, ((__force struct v4l2_plane __user **)&kp->m.planes)))
 634                        return -EFAULT;
 635                if (get_user(p, &up->m.planes))
 636                        return -EFAULT;
 637                uplane32 = compat_ptr(p);
 638
 639                while (num_planes--) {
 640                        ret = put_v4l2_plane32(uplane, uplane32, memory);
 641                        if (ret)
 642                                return ret;
 643                        ++uplane;
 644                        ++uplane32;
 645                }
 646        } else {
 647                switch (memory) {
 648                case V4L2_MEMORY_MMAP:
 649                        if (assign_in_user(&up->m.offset, &kp->m.offset))
 650                                return -EFAULT;
 651                        break;
 652                case V4L2_MEMORY_USERPTR:
 653                        if (assign_in_user(&up->m.userptr, &kp->m.userptr))
 654                                return -EFAULT;
 655                        break;
 656                case V4L2_MEMORY_OVERLAY:
 657                        if (assign_in_user(&up->m.offset, &kp->m.offset))
 658                                return -EFAULT;
 659                        break;
 660                case V4L2_MEMORY_DMABUF:
 661                        if (assign_in_user(&up->m.fd, &kp->m.fd))
 662                                return -EFAULT;
 663                        break;
 664                }
 665        }
 666
 667        return 0;
 668}
 669
 670struct v4l2_framebuffer32 {
 671        __u32                   capability;
 672        __u32                   flags;
 673        compat_caddr_t          base;
 674        struct v4l2_pix_format  fmt;
 675};
 676
 677static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
 678                                  struct v4l2_framebuffer32 __user *up)
 679{
 680        compat_caddr_t tmp;
 681
 682        if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) ||
 683            get_user(tmp, &up->base) ||
 684            put_user((__force void *)compat_ptr(tmp), &kp->base) ||
 685            assign_in_user(&kp->capability, &up->capability) ||
 686            assign_in_user(&kp->flags, &up->flags) ||
 687            copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt)))
 688                return -EFAULT;
 689        return 0;
 690}
 691
 692static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
 693                                  struct v4l2_framebuffer32 __user *up)
 694{
 695        void *base;
 696
 697        if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
 698            get_user(base, &kp->base) ||
 699            put_user(ptr_to_compat(base), &up->base) ||
 700            assign_in_user(&up->capability, &kp->capability) ||
 701            assign_in_user(&up->flags, &kp->flags) ||
 702            copy_in_user(&up->fmt, &kp->fmt, sizeof(kp->fmt)))
 703                return -EFAULT;
 704        return 0;
 705}
 706
 707struct v4l2_input32 {
 708        __u32        index;             /*  Which input */
 709        __u8         name[32];          /*  Label */
 710        __u32        type;              /*  Type of input */
 711        __u32        audioset;          /*  Associated audios (bitfield) */
 712        __u32        tuner;             /*  Associated tuner */
 713        v4l2_std_id  std;
 714        __u32        status;
 715        __u32        reserved[4];
 716} __attribute__ ((packed));
 717
 718/*
 719 * The 64-bit v4l2_input struct has extra padding at the end of the struct.
 720 * Otherwise it is identical to the 32-bit version.
 721 */
 722static inline int get_v4l2_input32(struct v4l2_input __user *kp,
 723                                   struct v4l2_input32 __user *up)
 724{
 725        if (copy_in_user(kp, up, sizeof(struct v4l2_input32)))
 726                return -EFAULT;
 727        return 0;
 728}
 729
 730static inline int put_v4l2_input32(struct v4l2_input __user *kp,
 731                                   struct v4l2_input32 __user *up)
 732{
 733        if (copy_in_user(up, kp, sizeof(struct v4l2_input32)))
 734                return -EFAULT;
 735        return 0;
 736}
 737
 738struct v4l2_ext_controls32 {
 739       __u32 ctrl_class;
 740       __u32 count;
 741       __u32 error_idx;
 742       __u32 reserved[2];
 743       compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
 744};
 745
 746struct v4l2_ext_control32 {
 747        __u32 id;
 748        __u32 size;
 749        __u32 reserved2[1];
 750        union {
 751                __s32 value;
 752                __s64 value64;
 753                compat_caddr_t string; /* actually char * */
 754        };
 755} __attribute__ ((packed));
 756
 757/* The following function really belong in v4l2-common, but that causes
 758   a circular dependency between modules. We need to think about this, but
 759   for now this will do. */
 760
 761/* Return non-zero if this control is a pointer type. Currently only
 762   type STRING is a pointer type. */
 763static inline int ctrl_is_pointer(u32 id)
 764{
 765        switch (id) {
 766        case V4L2_CID_RDS_TX_PS_NAME:
 767        case V4L2_CID_RDS_TX_RADIO_TEXT:
 768                return 1;
 769        default:
 770                return 0;
 771        }
 772}
 773
 774static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *up,
 775                                     u32 *size)
 776{
 777        u32 count;
 778
 779        if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
 780            get_user(count, &up->count))
 781                return -EFAULT;
 782        if (count > V4L2_CID_MAX_CTRLS)
 783                return -EINVAL;
 784        *size = count * sizeof(struct v4l2_ext_control);
 785        return 0;
 786}
 787
 788static int get_v4l2_ext_controls32(struct v4l2_ext_controls __user *kp,
 789                                   struct v4l2_ext_controls32 __user *up,
 790                                   void __user *aux_buf, u32 aux_space)
 791{
 792        struct v4l2_ext_control32 __user *ucontrols;
 793        struct v4l2_ext_control __user *kcontrols;
 794        u32 count;
 795        u32 n;
 796        compat_caddr_t p;
 797
 798        if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
 799            assign_in_user(&kp->ctrl_class, &up->ctrl_class) ||
 800            get_user(count, &up->count) ||
 801            put_user(count, &kp->count) ||
 802            assign_in_user(&kp->error_idx, &up->error_idx) ||
 803            copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
 804                return -EFAULT;
 805
 806        if (count == 0)
 807                return put_user(NULL, &kp->controls);
 808        if (count > V4L2_CID_MAX_CTRLS)
 809                return -EINVAL;
 810        if (get_user(p, &up->controls))
 811                return -EFAULT;
 812        ucontrols = compat_ptr(p);
 813        if (!access_ok(VERIFY_READ, ucontrols,
 814                       count * sizeof(struct v4l2_ext_control32)))
 815                return -EFAULT;
 816        if (aux_space < count * sizeof(*kcontrols))
 817                return -EFAULT;
 818        kcontrols = aux_buf;
 819        if (put_user((__force struct v4l2_ext_control *)kcontrols,
 820                     &kp->controls))
 821                return -EFAULT;
 822
 823        for (n = 0; n < count; n++) {
 824                u32 id;
 825
 826                if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
 827                        return -EFAULT;
 828
 829                if (get_user(id, &kcontrols->id))
 830                        return -EFAULT;
 831
 832                if (ctrl_is_pointer(id)) {
 833                        void __user *s;
 834
 835                        if (get_user(p, &ucontrols->string))
 836                                return -EFAULT;
 837                        s = compat_ptr(p);
 838                        if (put_user(s, &kcontrols->string))
 839                                return -EFAULT;
 840                }
 841                ucontrols++;
 842                kcontrols++;
 843        }
 844        return 0;
 845}
 846
 847static int put_v4l2_ext_controls32(struct v4l2_ext_controls __user *kp,
 848                                   struct v4l2_ext_controls32 __user *up)
 849{
 850        struct v4l2_ext_control32 __user *ucontrols;
 851        struct v4l2_ext_control __user *kcontrols;
 852        u32 count;
 853        u32 n;
 854        compat_caddr_t p;
 855
 856        if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
 857            assign_in_user(&up->ctrl_class, &kp->ctrl_class) ||
 858            get_user(count, &kp->count) ||
 859            put_user(count, &up->count) ||
 860            assign_in_user(&up->error_idx, &kp->error_idx) ||
 861            copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)) ||
 862            get_user(kcontrols, &kp->controls))
 863                return -EFAULT;
 864
 865        if (!count)
 866                return 0;
 867        if (get_user(p, &up->controls))
 868                return -EFAULT;
 869        ucontrols = compat_ptr(p);
 870        if (!access_ok(VERIFY_WRITE, ucontrols,
 871                       count * sizeof(struct v4l2_ext_control32)))
 872                return -EFAULT;
 873
 874        for (n = 0; n < count; n++) {
 875                unsigned int size = sizeof(*ucontrols);
 876                u32 id;
 877
 878                if (get_user(id, &kcontrols->id) ||
 879                    put_user(id, &ucontrols->id) ||
 880                    assign_in_user(&ucontrols->size, &kcontrols->size) ||
 881                    copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
 882                                 sizeof(ucontrols->reserved2)))
 883                        return -EFAULT;
 884
 885                /*
 886                 * Do not modify the pointer when copying a pointer control.
 887                 * The contents of the pointer was changed, not the pointer
 888                 * itself.
 889                 */
 890                if (ctrl_is_pointer(id))
 891                        size -= sizeof(ucontrols->value64);
 892
 893                if (copy_in_user(ucontrols, kcontrols, size))
 894                        return -EFAULT;
 895
 896                ucontrols++;
 897                kcontrols++;
 898        }
 899        return 0;
 900}
 901
 902struct v4l2_event32 {
 903        __u32                           type;
 904        union {
 905                __u8                    data[64];
 906        } u;
 907        __u32                           pending;
 908        __u32                           sequence;
 909        struct compat_timespec          timestamp;
 910        __u32                           id;
 911        __u32                           reserved[8];
 912};
 913
 914static int put_v4l2_event32(struct v4l2_event __user *kp,
 915                            struct v4l2_event32 __user *up)
 916{
 917        if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) ||
 918            assign_in_user(&up->type, &kp->type) ||
 919            copy_in_user(&up->u, &kp->u, sizeof(kp->u)) ||
 920            assign_in_user(&up->pending, &kp->pending) ||
 921            assign_in_user(&up->sequence, &kp->sequence) ||
 922            assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
 923            assign_in_user(&up->timestamp.tv_nsec, &kp->timestamp.tv_nsec) ||
 924            assign_in_user(&up->id, &kp->id) ||
 925            copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
 926                return -EFAULT;
 927        return 0;
 928}
 929
 930struct v4l2_subdev_edid32 {
 931        __u32 pad;
 932        __u32 start_block;
 933        __u32 blocks;
 934        __u32 reserved[5];
 935        compat_caddr_t edid;
 936};
 937
 938static int get_v4l2_subdev_edid32(struct v4l2_subdev_edid __user *kp,
 939                                  struct v4l2_subdev_edid32 __user *up)
 940{
 941        compat_uptr_t tmp;
 942
 943        if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_subdev_edid32)) ||
 944            assign_in_user(&kp->pad, &up->pad) ||
 945            assign_in_user(&kp->start_block, &up->start_block) ||
 946            assign_in_user(&kp->blocks, &up->blocks) ||
 947            get_user(tmp, &up->edid) ||
 948            put_user(compat_ptr(tmp), &kp->edid) ||
 949            copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
 950                return -EFAULT;
 951        return 0;
 952}
 953
 954static int put_v4l2_subdev_edid32(struct v4l2_subdev_edid __user *kp,
 955                                  struct v4l2_subdev_edid32 __user *up)
 956{
 957        void *edid;
 958
 959        if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_subdev_edid32)) ||
 960            assign_in_user(&up->pad, &kp->pad) ||
 961            assign_in_user(&up->start_block, &kp->start_block) ||
 962            assign_in_user(&up->blocks, &kp->blocks) ||
 963            get_user(edid, &kp->edid) ||
 964            put_user(ptr_to_compat(edid), &up->edid) ||
 965            copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
 966                return -EFAULT;
 967        return 0;
 968}
 969
 970
 971#define VIDIOC_G_FMT32          _IOWR('V',  4, struct v4l2_format32)
 972#define VIDIOC_S_FMT32          _IOWR('V',  5, struct v4l2_format32)
 973#define VIDIOC_QUERYBUF32       _IOWR('V',  9, struct v4l2_buffer32)
 974#define VIDIOC_G_FBUF32         _IOR ('V', 10, struct v4l2_framebuffer32)
 975#define VIDIOC_S_FBUF32         _IOW ('V', 11, struct v4l2_framebuffer32)
 976#define VIDIOC_QBUF32           _IOWR('V', 15, struct v4l2_buffer32)
 977#define VIDIOC_DQBUF32          _IOWR('V', 17, struct v4l2_buffer32)
 978#define VIDIOC_ENUMSTD32        _IOWR('V', 25, struct v4l2_standard32)
 979#define VIDIOC_ENUMINPUT32      _IOWR('V', 26, struct v4l2_input32)
 980#define VIDIOC_SUBDEV_G_EDID32  _IOWR('V', 63, struct v4l2_subdev_edid32)
 981#define VIDIOC_SUBDEV_S_EDID32  _IOWR('V', 64, struct v4l2_subdev_edid32)
 982#define VIDIOC_TRY_FMT32        _IOWR('V', 64, struct v4l2_format32)
 983#define VIDIOC_G_EXT_CTRLS32    _IOWR('V', 71, struct v4l2_ext_controls32)
 984#define VIDIOC_S_EXT_CTRLS32    _IOWR('V', 72, struct v4l2_ext_controls32)
 985#define VIDIOC_TRY_EXT_CTRLS32  _IOWR('V', 73, struct v4l2_ext_controls32)
 986#define VIDIOC_DQEVENT32        _IOR ('V', 89, struct v4l2_event32)
 987#define VIDIOC_CREATE_BUFS32    _IOWR('V', 92, struct v4l2_create_buffers32)
 988#define VIDIOC_PREPARE_BUF32    _IOWR('V', 93, struct v4l2_buffer32)
 989
 990#define VIDIOC_OVERLAY32        _IOW ('V', 14, s32)
 991#define VIDIOC_STREAMON32       _IOW ('V', 18, s32)
 992#define VIDIOC_STREAMOFF32      _IOW ('V', 19, s32)
 993#define VIDIOC_G_INPUT32        _IOR ('V', 38, s32)
 994#define VIDIOC_S_INPUT32        _IOWR('V', 39, s32)
 995#define VIDIOC_G_OUTPUT32       _IOR ('V', 46, s32)
 996#define VIDIOC_S_OUTPUT32       _IOWR('V', 47, s32)
 997
 998static int alloc_userspace(unsigned int size, u32 aux_space,
 999                           void __user **up_native)
1000{
1001        *up_native = compat_alloc_user_space(size + aux_space);
1002        if (!*up_native)
1003                return -ENOMEM;
1004        if (clear_user(*up_native, size))
1005                return -EFAULT;
1006        return 0;
1007}
1008
1009static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1010{
1011        void __user *up = compat_ptr(arg);
1012        void __user *up_native = NULL;
1013        void __user *aux_buf;
1014        u32 aux_space;
1015        int compatible_arg = 1;
1016        long err = 0;
1017
1018        /* First, convert the command. */
1019        switch (cmd) {
1020        case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
1021        case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
1022        case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
1023        case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
1024        case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
1025        case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
1026        case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
1027        case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break;
1028        case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break;
1029        case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
1030        case VIDIOC_G_EXT_CTRLS32: cmd = VIDIOC_G_EXT_CTRLS; break;
1031        case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break;
1032        case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break;
1033        case VIDIOC_DQEVENT32: cmd = VIDIOC_DQEVENT; break;
1034        case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
1035        case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
1036        case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
1037        case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
1038        case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
1039        case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
1040        case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
1041        case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break;
1042        case VIDIOC_PREPARE_BUF32: cmd = VIDIOC_PREPARE_BUF; break;
1043        case VIDIOC_SUBDEV_G_EDID32: cmd = VIDIOC_SUBDEV_G_EDID; break;
1044        case VIDIOC_SUBDEV_S_EDID32: cmd = VIDIOC_SUBDEV_S_EDID; break;
1045        }
1046
1047        switch (cmd) {
1048        case VIDIOC_OVERLAY:
1049        case VIDIOC_STREAMON:
1050        case VIDIOC_STREAMOFF:
1051        case VIDIOC_S_INPUT:
1052        case VIDIOC_S_OUTPUT:
1053                err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
1054                if (!err && assign_in_user((unsigned int __user *)up_native,
1055                                           (compat_uint_t __user *)up))
1056                        err = -EFAULT;
1057                compatible_arg = 0;
1058                break;
1059
1060        case VIDIOC_G_INPUT:
1061        case VIDIOC_G_OUTPUT:
1062                err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
1063                compatible_arg = 0;
1064                break;
1065
1066        case VIDIOC_SUBDEV_G_EDID:
1067        case VIDIOC_SUBDEV_S_EDID:
1068                err = alloc_userspace(sizeof(struct v4l2_subdev_edid32), 0, &up_native);
1069                if (!err)
1070                        err = get_v4l2_subdev_edid32(up_native, up);
1071                compatible_arg = 0;
1072                break;
1073
1074        case VIDIOC_G_FMT:
1075        case VIDIOC_S_FMT:
1076        case VIDIOC_TRY_FMT:
1077                err = bufsize_v4l2_format(up, &aux_space);
1078                if (!err)
1079                        err = alloc_userspace(sizeof(struct v4l2_format),
1080                                              aux_space, &up_native);
1081                if (!err) {
1082                        aux_buf = up_native + sizeof(struct v4l2_format);
1083                        err = get_v4l2_format32(up_native, up,
1084                                                aux_buf, aux_space);
1085                }
1086                compatible_arg = 0;
1087                break;
1088
1089        case VIDIOC_CREATE_BUFS:
1090                err = bufsize_v4l2_create(up, &aux_space);
1091                if (!err)
1092                        err = alloc_userspace(sizeof(struct v4l2_create_buffers),
1093                                              aux_space, &up_native);
1094                if (!err) {
1095                        aux_buf = up_native + sizeof(struct v4l2_create_buffers);
1096                        err = get_v4l2_create32(up_native, up,
1097                                                aux_buf, aux_space);
1098                }
1099                compatible_arg = 0;
1100                break;
1101
1102        case VIDIOC_PREPARE_BUF:
1103        case VIDIOC_QUERYBUF:
1104        case VIDIOC_QBUF:
1105        case VIDIOC_DQBUF:
1106                err = bufsize_v4l2_buffer(up, &aux_space);
1107                if (!err)
1108                        err = alloc_userspace(sizeof(struct v4l2_buffer),
1109                                              aux_space, &up_native);
1110                if (!err) {
1111                        aux_buf = up_native + sizeof(struct v4l2_buffer);
1112                        err = get_v4l2_buffer32(up_native, up,
1113                                                aux_buf, aux_space);
1114                }
1115                compatible_arg = 0;
1116                break;
1117
1118        case VIDIOC_S_FBUF:
1119                err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
1120                                      &up_native);
1121                if (!err)
1122                        err = get_v4l2_framebuffer32(up_native, up);
1123                compatible_arg = 0;
1124                break;
1125
1126        case VIDIOC_G_FBUF:
1127                err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
1128                                      &up_native);
1129                compatible_arg = 0;
1130                break;
1131
1132        case VIDIOC_ENUMSTD:
1133                err = alloc_userspace(sizeof(struct v4l2_standard), 0,
1134                                      &up_native);
1135                if (!err)
1136                        err = get_v4l2_standard32(up_native, up);
1137                compatible_arg = 0;
1138                break;
1139
1140        case VIDIOC_ENUMINPUT:
1141                err = alloc_userspace(sizeof(struct v4l2_input), 0, &up_native);
1142                if (!err)
1143                        err = get_v4l2_input32(up_native, up);
1144                compatible_arg = 0;
1145                break;
1146
1147        case VIDIOC_G_EXT_CTRLS:
1148        case VIDIOC_S_EXT_CTRLS:
1149        case VIDIOC_TRY_EXT_CTRLS:
1150                err = bufsize_v4l2_ext_controls(up, &aux_space);
1151                if (!err)
1152                        err = alloc_userspace(sizeof(struct v4l2_ext_controls),
1153                                              aux_space, &up_native);
1154                if (!err) {
1155                        aux_buf = up_native + sizeof(struct v4l2_ext_controls);
1156                        err = get_v4l2_ext_controls32(up_native, up,
1157                                                      aux_buf, aux_space);
1158                }
1159                compatible_arg = 0;
1160                break;
1161        case VIDIOC_DQEVENT:
1162                err = alloc_userspace(sizeof(struct v4l2_event), 0, &up_native);
1163                compatible_arg = 0;
1164                break;
1165        }
1166        if (err)
1167                return err;
1168
1169        if (compatible_arg)
1170                err = native_ioctl(file, cmd, (unsigned long)up);
1171        else
1172                err = native_ioctl(file, cmd, (unsigned long)up_native);
1173
1174        if (err == -ENOTTY)
1175                return err;
1176
1177        /*
1178         * Special case: even after an error we need to put the
1179         * results back for these ioctls since the error_idx will
1180         * contain information on which control failed.
1181         */
1182        switch (cmd) {
1183        case VIDIOC_G_EXT_CTRLS:
1184        case VIDIOC_S_EXT_CTRLS:
1185        case VIDIOC_TRY_EXT_CTRLS:
1186                if (put_v4l2_ext_controls32(up_native, up))
1187                        err = -EFAULT;
1188                break;
1189        }
1190        if (err)
1191                return err;
1192
1193        switch (cmd) {
1194        case VIDIOC_S_INPUT:
1195        case VIDIOC_S_OUTPUT:
1196        case VIDIOC_G_INPUT:
1197        case VIDIOC_G_OUTPUT:
1198                if (assign_in_user((compat_uint_t __user *)up,
1199                                   ((unsigned int __user *)up_native)))
1200                        err = -EFAULT;
1201                break;
1202
1203        case VIDIOC_G_FBUF:
1204                err = put_v4l2_framebuffer32(up_native, up);
1205                break;
1206
1207        case VIDIOC_DQEVENT:
1208                err = put_v4l2_event32(up_native, up);
1209                break;
1210
1211        case VIDIOC_SUBDEV_G_EDID:
1212        case VIDIOC_SUBDEV_S_EDID:
1213                err = put_v4l2_subdev_edid32(up_native, up);
1214                break;
1215
1216        case VIDIOC_G_FMT:
1217        case VIDIOC_S_FMT:
1218        case VIDIOC_TRY_FMT:
1219                err = put_v4l2_format32(up_native, up);
1220                break;
1221
1222        case VIDIOC_CREATE_BUFS:
1223                err = put_v4l2_create32(up_native, up);
1224                break;
1225
1226        case VIDIOC_QUERYBUF:
1227        case VIDIOC_QBUF:
1228        case VIDIOC_DQBUF:
1229                err = put_v4l2_buffer32(up_native, up);
1230                break;
1231
1232        case VIDIOC_ENUMSTD:
1233                err = put_v4l2_standard32(up_native, up);
1234                break;
1235
1236        case VIDIOC_ENUMINPUT:
1237                err = put_v4l2_input32(up_native, up);
1238                break;
1239        }
1240        return err;
1241}
1242
1243long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
1244{
1245        struct video_device *vdev = video_devdata(file);
1246        long ret = -ENOIOCTLCMD;
1247
1248        if (!file->f_op->unlocked_ioctl)
1249                return ret;
1250
1251        switch (cmd) {
1252        case VIDIOC_QUERYCAP:
1253        case VIDIOC_RESERVED:
1254        case VIDIOC_ENUM_FMT:
1255        case VIDIOC_G_FMT32:
1256        case VIDIOC_S_FMT32:
1257        case VIDIOC_REQBUFS:
1258        case VIDIOC_QUERYBUF32:
1259        case VIDIOC_G_FBUF32:
1260        case VIDIOC_S_FBUF32:
1261        case VIDIOC_OVERLAY32:
1262        case VIDIOC_QBUF32:
1263        case VIDIOC_EXPBUF:
1264        case VIDIOC_DQBUF32:
1265        case VIDIOC_STREAMON32:
1266        case VIDIOC_STREAMOFF32:
1267        case VIDIOC_G_PARM:
1268        case VIDIOC_S_PARM:
1269        case VIDIOC_G_STD:
1270        case VIDIOC_S_STD:
1271        case VIDIOC_ENUMSTD32:
1272        case VIDIOC_ENUMINPUT32:
1273        case VIDIOC_G_CTRL:
1274        case VIDIOC_S_CTRL:
1275        case VIDIOC_G_TUNER:
1276        case VIDIOC_S_TUNER:
1277        case VIDIOC_G_AUDIO:
1278        case VIDIOC_S_AUDIO:
1279        case VIDIOC_QUERYCTRL:
1280        case VIDIOC_QUERYMENU:
1281        case VIDIOC_G_INPUT32:
1282        case VIDIOC_S_INPUT32:
1283        case VIDIOC_G_OUTPUT32:
1284        case VIDIOC_S_OUTPUT32:
1285        case VIDIOC_ENUMOUTPUT:
1286        case VIDIOC_G_AUDOUT:
1287        case VIDIOC_S_AUDOUT:
1288        case VIDIOC_G_MODULATOR:
1289        case VIDIOC_S_MODULATOR:
1290        case VIDIOC_S_FREQUENCY:
1291        case VIDIOC_G_FREQUENCY:
1292        case VIDIOC_CROPCAP:
1293        case VIDIOC_G_CROP:
1294        case VIDIOC_S_CROP:
1295        case VIDIOC_G_SELECTION:
1296        case VIDIOC_S_SELECTION:
1297        case VIDIOC_G_JPEGCOMP:
1298        case VIDIOC_S_JPEGCOMP:
1299        case VIDIOC_QUERYSTD:
1300        case VIDIOC_TRY_FMT32:
1301        case VIDIOC_ENUMAUDIO:
1302        case VIDIOC_ENUMAUDOUT:
1303        case VIDIOC_G_PRIORITY:
1304        case VIDIOC_S_PRIORITY:
1305        case VIDIOC_G_SLICED_VBI_CAP:
1306        case VIDIOC_LOG_STATUS:
1307        case VIDIOC_G_EXT_CTRLS32:
1308        case VIDIOC_S_EXT_CTRLS32:
1309        case VIDIOC_TRY_EXT_CTRLS32:
1310        case VIDIOC_ENUM_FRAMESIZES:
1311        case VIDIOC_ENUM_FRAMEINTERVALS:
1312        case VIDIOC_G_ENC_INDEX:
1313        case VIDIOC_ENCODER_CMD:
1314        case VIDIOC_TRY_ENCODER_CMD:
1315        case VIDIOC_DECODER_CMD:
1316        case VIDIOC_TRY_DECODER_CMD:
1317        case VIDIOC_DBG_S_REGISTER:
1318        case VIDIOC_DBG_G_REGISTER:
1319        case VIDIOC_DBG_G_CHIP_IDENT:
1320        case VIDIOC_S_HW_FREQ_SEEK:
1321        case VIDIOC_S_DV_TIMINGS:
1322        case VIDIOC_G_DV_TIMINGS:
1323        case VIDIOC_DQEVENT:
1324        case VIDIOC_DQEVENT32:
1325        case VIDIOC_SUBSCRIBE_EVENT:
1326        case VIDIOC_UNSUBSCRIBE_EVENT:
1327        case VIDIOC_CREATE_BUFS32:
1328        case VIDIOC_PREPARE_BUF32:
1329        case VIDIOC_ENUM_DV_TIMINGS:
1330        case VIDIOC_QUERY_DV_TIMINGS:
1331        case VIDIOC_DV_TIMINGS_CAP:
1332        case VIDIOC_ENUM_FREQ_BANDS:
1333        case VIDIOC_SUBDEV_G_EDID32:
1334        case VIDIOC_SUBDEV_S_EDID32:
1335                ret = do_video_ioctl(file, cmd, arg);
1336                break;
1337
1338        default:
1339                if (vdev->fops->compat_ioctl32)
1340                        ret = vdev->fops->compat_ioctl32(file, cmd, arg);
1341
1342                if (ret == -ENOIOCTLCMD)
1343                        printk(KERN_WARNING "compat_ioctl32: "
1344                                "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
1345                                _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd),
1346                                cmd);
1347                break;
1348        }
1349        return ret;
1350}
1351EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32);
1352