linux/drivers/media/video/pwc/pwc-v4l.c
<<
>>
Prefs
   1/* Linux driver for Philips webcam
   2   USB and Video4Linux interface part.
   3   (C) 1999-2004 Nemosoft Unv.
   4   (C) 2004-2006 Luc Saillard (luc@saillard.org)
   5
   6   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
   7   driver and thus may have bugs that are not present in the original version.
   8   Please send bug reports and support requests to <luc@saillard.org>.
   9   The decompression routines have been implemented by reverse-engineering the
  10   Nemosoft binary pwcx module. Caveat emptor.
  11
  12   This program is free software; you can redistribute it and/or modify
  13   it under the terms of the GNU General Public License as published by
  14   the Free Software Foundation; either version 2 of the License, or
  15   (at your option) any later version.
  16
  17   This program is distributed in the hope that it will be useful,
  18   but WITHOUT ANY WARRANTY; without even the implied warranty of
  19   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20   GNU General Public License for more details.
  21
  22   You should have received a copy of the GNU General Public License
  23   along with this program; if not, write to the Free Software
  24   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  25
  26*/
  27
  28#include <linux/errno.h>
  29#include <linux/init.h>
  30#include <linux/mm.h>
  31#include <linux/module.h>
  32#include <linux/poll.h>
  33#include <linux/slab.h>
  34#include <linux/vmalloc.h>
  35#include <asm/io.h>
  36
  37#include "pwc.h"
  38
  39static struct v4l2_queryctrl pwc_controls[] = {
  40        {
  41            .id      = V4L2_CID_BRIGHTNESS,
  42            .type    = V4L2_CTRL_TYPE_INTEGER,
  43            .name    = "Brightness",
  44            .minimum = 0,
  45            .maximum = 128,
  46            .step    = 1,
  47            .default_value = 64,
  48        },
  49        {
  50            .id      = V4L2_CID_CONTRAST,
  51            .type    = V4L2_CTRL_TYPE_INTEGER,
  52            .name    = "Contrast",
  53            .minimum = 0,
  54            .maximum = 64,
  55            .step    = 1,
  56            .default_value = 0,
  57        },
  58        {
  59            .id      = V4L2_CID_SATURATION,
  60            .type    = V4L2_CTRL_TYPE_INTEGER,
  61            .name    = "Saturation",
  62            .minimum = -100,
  63            .maximum = 100,
  64            .step    = 1,
  65            .default_value = 0,
  66        },
  67        {
  68            .id      = V4L2_CID_GAMMA,
  69            .type    = V4L2_CTRL_TYPE_INTEGER,
  70            .name    = "Gamma",
  71            .minimum = 0,
  72            .maximum = 32,
  73            .step    = 1,
  74            .default_value = 0,
  75        },
  76        {
  77            .id      = V4L2_CID_RED_BALANCE,
  78            .type    = V4L2_CTRL_TYPE_INTEGER,
  79            .name    = "Red Gain",
  80            .minimum = 0,
  81            .maximum = 256,
  82            .step    = 1,
  83            .default_value = 0,
  84        },
  85        {
  86            .id      = V4L2_CID_BLUE_BALANCE,
  87            .type    = V4L2_CTRL_TYPE_INTEGER,
  88            .name    = "Blue Gain",
  89            .minimum = 0,
  90            .maximum = 256,
  91            .step    = 1,
  92            .default_value = 0,
  93        },
  94        {
  95            .id      = V4L2_CID_AUTO_WHITE_BALANCE,
  96            .type    = V4L2_CTRL_TYPE_BOOLEAN,
  97            .name    = "Auto White Balance",
  98            .minimum = 0,
  99            .maximum = 1,
 100            .step    = 1,
 101            .default_value = 0,
 102        },
 103        {
 104            .id      = V4L2_CID_EXPOSURE,
 105            .type    = V4L2_CTRL_TYPE_INTEGER,
 106            .name    = "Shutter Speed (Exposure)",
 107            .minimum = 0,
 108            .maximum = 256,
 109            .step    = 1,
 110            .default_value = 200,
 111        },
 112        {
 113            .id      = V4L2_CID_AUTOGAIN,
 114            .type    = V4L2_CTRL_TYPE_BOOLEAN,
 115            .name    = "Auto Gain Enabled",
 116            .minimum = 0,
 117            .maximum = 1,
 118            .step    = 1,
 119            .default_value = 1,
 120        },
 121        {
 122            .id      = V4L2_CID_GAIN,
 123            .type    = V4L2_CTRL_TYPE_INTEGER,
 124            .name    = "Gain Level",
 125            .minimum = 0,
 126            .maximum = 256,
 127            .step    = 1,
 128            .default_value = 0,
 129        },
 130        {
 131            .id      = V4L2_CID_PRIVATE_SAVE_USER,
 132            .type    = V4L2_CTRL_TYPE_BUTTON,
 133            .name    = "Save User Settings",
 134            .minimum = 0,
 135            .maximum = 0,
 136            .step    = 0,
 137            .default_value = 0,
 138        },
 139        {
 140            .id      = V4L2_CID_PRIVATE_RESTORE_USER,
 141            .type    = V4L2_CTRL_TYPE_BUTTON,
 142            .name    = "Restore User Settings",
 143            .minimum = 0,
 144            .maximum = 0,
 145            .step    = 0,
 146            .default_value = 0,
 147        },
 148        {
 149            .id      = V4L2_CID_PRIVATE_RESTORE_FACTORY,
 150            .type    = V4L2_CTRL_TYPE_BUTTON,
 151            .name    = "Restore Factory Settings",
 152            .minimum = 0,
 153            .maximum = 0,
 154            .step    = 0,
 155            .default_value = 0,
 156        },
 157        {
 158            .id      = V4L2_CID_PRIVATE_COLOUR_MODE,
 159            .type    = V4L2_CTRL_TYPE_BOOLEAN,
 160            .name    = "Colour mode",
 161            .minimum = 0,
 162            .maximum = 1,
 163            .step    = 1,
 164            .default_value = 0,
 165        },
 166        {
 167            .id      = V4L2_CID_PRIVATE_AUTOCONTOUR,
 168            .type    = V4L2_CTRL_TYPE_BOOLEAN,
 169            .name    = "Auto contour",
 170            .minimum = 0,
 171            .maximum = 1,
 172            .step    = 1,
 173            .default_value = 0,
 174        },
 175        {
 176            .id      = V4L2_CID_PRIVATE_CONTOUR,
 177            .type    = V4L2_CTRL_TYPE_INTEGER,
 178            .name    = "Contour",
 179            .minimum = 0,
 180            .maximum = 63,
 181            .step    = 1,
 182            .default_value = 0,
 183        },
 184        {
 185            .id      = V4L2_CID_PRIVATE_BACKLIGHT,
 186            .type    = V4L2_CTRL_TYPE_BOOLEAN,
 187            .name    = "Backlight compensation",
 188            .minimum = 0,
 189            .maximum = 1,
 190            .step    = 1,
 191            .default_value = 0,
 192        },
 193        {
 194          .id      = V4L2_CID_PRIVATE_FLICKERLESS,
 195            .type    = V4L2_CTRL_TYPE_BOOLEAN,
 196            .name    = "Flickerless",
 197            .minimum = 0,
 198            .maximum = 1,
 199            .step    = 1,
 200            .default_value = 0,
 201        },
 202        {
 203            .id      = V4L2_CID_PRIVATE_NOISE_REDUCTION,
 204            .type    = V4L2_CTRL_TYPE_INTEGER,
 205            .name    = "Noise reduction",
 206            .minimum = 0,
 207            .maximum = 3,
 208            .step    = 1,
 209            .default_value = 0,
 210        },
 211};
 212
 213
 214static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
 215{
 216        memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
 217        f->fmt.pix.width        = pdev->view.x;
 218        f->fmt.pix.height       = pdev->view.y;
 219        f->fmt.pix.field        = V4L2_FIELD_NONE;
 220        if (pdev->vpalette == VIDEO_PALETTE_YUV420P) {
 221                f->fmt.pix.pixelformat  = V4L2_PIX_FMT_YUV420;
 222                f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2;
 223                f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
 224        } else {
 225                /* vbandlength contains 4 lines ...  */
 226                f->fmt.pix.bytesperline = pdev->vbandlength/4;
 227                f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame);
 228                if (DEVICE_USE_CODEC1(pdev->type))
 229                        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_PWC1;
 230                else
 231                        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_PWC2;
 232        }
 233        PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() "
 234                        "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n",
 235                        f->fmt.pix.width,
 236                        f->fmt.pix.height,
 237                        f->fmt.pix.bytesperline,
 238                        f->fmt.pix.sizeimage,
 239                        (f->fmt.pix.pixelformat)&255,
 240                        (f->fmt.pix.pixelformat>>8)&255,
 241                        (f->fmt.pix.pixelformat>>16)&255,
 242                        (f->fmt.pix.pixelformat>>24)&255);
 243}
 244
 245/* ioctl(VIDIOC_TRY_FMT) */
 246static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
 247{
 248        if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
 249                PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
 250                return -EINVAL;
 251        }
 252
 253        switch (f->fmt.pix.pixelformat) {
 254                case V4L2_PIX_FMT_YUV420:
 255                        break;
 256                case V4L2_PIX_FMT_PWC1:
 257                        if (DEVICE_USE_CODEC23(pdev->type)) {
 258                                PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n");
 259                                return -EINVAL;
 260                        }
 261                        break;
 262                case V4L2_PIX_FMT_PWC2:
 263                        if (DEVICE_USE_CODEC1(pdev->type)) {
 264                                PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n");
 265                                return -EINVAL;
 266                        }
 267                        break;
 268                default:
 269                        PWC_DEBUG_IOCTL("Unsupported pixel format\n");
 270                        return -EINVAL;
 271
 272        }
 273
 274        if (f->fmt.pix.width > pdev->view_max.x)
 275                f->fmt.pix.width = pdev->view_max.x;
 276        else if (f->fmt.pix.width < pdev->view_min.x)
 277                f->fmt.pix.width = pdev->view_min.x;
 278
 279        if (f->fmt.pix.height > pdev->view_max.y)
 280                f->fmt.pix.height = pdev->view_max.y;
 281        else if (f->fmt.pix.height < pdev->view_min.y)
 282                f->fmt.pix.height = pdev->view_min.y;
 283
 284        return 0;
 285}
 286
 287/* ioctl(VIDIOC_SET_FMT) */
 288static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
 289{
 290        int ret, fps, snapshot, compression, pixelformat;
 291
 292        ret = pwc_vidioc_try_fmt(pdev, f);
 293        if (ret<0)
 294                return ret;
 295
 296        pixelformat = f->fmt.pix.pixelformat;
 297        compression = pdev->vcompression;
 298        snapshot = 0;
 299        fps = pdev->vframes;
 300        if (f->fmt.pix.priv) {
 301                compression = (f->fmt.pix.priv & PWC_QLT_MASK) >> PWC_QLT_SHIFT;
 302                snapshot = !!(f->fmt.pix.priv & PWC_FPS_SNAPSHOT);
 303                fps = (f->fmt.pix.priv & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
 304                if (fps == 0)
 305                        fps = pdev->vframes;
 306        }
 307
 308        if (pixelformat == V4L2_PIX_FMT_YUV420)
 309                pdev->vpalette = VIDEO_PALETTE_YUV420P;
 310        else
 311                pdev->vpalette = VIDEO_PALETTE_RAW;
 312
 313        PWC_DEBUG_IOCTL("Try to change format to: width=%d height=%d fps=%d "
 314                        "compression=%d snapshot=%d format=%c%c%c%c\n",
 315                        f->fmt.pix.width, f->fmt.pix.height, fps,
 316                        compression, snapshot,
 317                        (pixelformat)&255,
 318                        (pixelformat>>8)&255,
 319                        (pixelformat>>16)&255,
 320                        (pixelformat>>24)&255);
 321
 322        ret = pwc_try_video_mode(pdev,
 323                                 f->fmt.pix.width,
 324                                 f->fmt.pix.height,
 325                                 fps,
 326                                 compression,
 327                                 snapshot);
 328
 329        PWC_DEBUG_IOCTL("pwc_try_video_mode(), return=%d\n", ret);
 330
 331        if (ret)
 332                return ret;
 333
 334        pwc_vidioc_fill_fmt(pdev, f);
 335
 336        return 0;
 337
 338}
 339
 340long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 341{
 342        struct video_device *vdev = video_devdata(file);
 343        struct pwc_device *pdev;
 344        DECLARE_WAITQUEUE(wait, current);
 345
 346        if (vdev == NULL)
 347                return -EFAULT;
 348        pdev = video_get_drvdata(vdev);
 349        if (pdev == NULL)
 350                return -EFAULT;
 351
 352#ifdef CONFIG_USB_PWC_DEBUG
 353        if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace) {
 354                v4l_printk_ioctl(cmd);
 355                printk("\n");
 356        }
 357#endif
 358
 359
 360        switch (cmd) {
 361                /* Query cabapilities */
 362                case VIDIOCGCAP:
 363                {
 364                        struct video_capability *caps = arg;
 365
 366                        strcpy(caps->name, vdev->name);
 367                        caps->type = VID_TYPE_CAPTURE;
 368                        caps->channels = 1;
 369                        caps->audios = 1;
 370                        caps->minwidth  = pdev->view_min.x;
 371                        caps->minheight = pdev->view_min.y;
 372                        caps->maxwidth  = pdev->view_max.x;
 373                        caps->maxheight = pdev->view_max.y;
 374                        break;
 375                }
 376
 377                /* Channel functions (simulate 1 channel) */
 378                case VIDIOCGCHAN:
 379                {
 380                        struct video_channel *v = arg;
 381
 382                        if (v->channel != 0)
 383                                return -EINVAL;
 384                        v->flags = 0;
 385                        v->tuners = 0;
 386                        v->type = VIDEO_TYPE_CAMERA;
 387                        strcpy(v->name, "Webcam");
 388                        return 0;
 389                }
 390
 391                case VIDIOCSCHAN:
 392                {
 393                        /* The spec says the argument is an integer, but
 394                           the bttv driver uses a video_channel arg, which
 395                           makes sense becasue it also has the norm flag.
 396                         */
 397                        struct video_channel *v = arg;
 398                        if (v->channel != 0)
 399                                return -EINVAL;
 400                        return 0;
 401                }
 402
 403
 404                /* Picture functions; contrast etc. */
 405                case VIDIOCGPICT:
 406                {
 407                        struct video_picture *p = arg;
 408                        int val;
 409
 410                        val = pwc_get_brightness(pdev);
 411                        if (val >= 0)
 412                                p->brightness = (val<<9);
 413                        else
 414                                p->brightness = 0xffff;
 415                        val = pwc_get_contrast(pdev);
 416                        if (val >= 0)
 417                                p->contrast = (val<<10);
 418                        else
 419                                p->contrast = 0xffff;
 420                        /* Gamma, Whiteness, what's the difference? :) */
 421                        val = pwc_get_gamma(pdev);
 422                        if (val >= 0)
 423                                p->whiteness = (val<<11);
 424                        else
 425                                p->whiteness = 0xffff;
 426                        if (pwc_get_saturation(pdev, &val)<0)
 427                                p->colour = 0xffff;
 428                        else
 429                                p->colour = 32768 + val * 327;
 430                        p->depth = 24;
 431                        p->palette = pdev->vpalette;
 432                        p->hue = 0xFFFF; /* N/A */
 433                        break;
 434                }
 435
 436                case VIDIOCSPICT:
 437                {
 438                        struct video_picture *p = arg;
 439                        /*
 440                         *      FIXME:  Suppose we are mid read
 441                                ANSWER: No problem: the firmware of the camera
 442                                        can handle brightness/contrast/etc
 443                                        changes at _any_ time, and the palette
 444                                        is used exactly once in the uncompress
 445                                        routine.
 446                         */
 447                        pwc_set_brightness(pdev, p->brightness);
 448                        pwc_set_contrast(pdev, p->contrast);
 449                        pwc_set_gamma(pdev, p->whiteness);
 450                        pwc_set_saturation(pdev, (p->colour-32768)/327);
 451                        if (p->palette && p->palette != pdev->vpalette) {
 452                                switch (p->palette) {
 453                                        case VIDEO_PALETTE_YUV420P:
 454                                        case VIDEO_PALETTE_RAW:
 455                                                pdev->vpalette = p->palette;
 456                                                return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
 457                                                break;
 458                                        default:
 459                                                return -EINVAL;
 460                                                break;
 461                                }
 462                        }
 463                        break;
 464                }
 465
 466                /* Window/size parameters */
 467                case VIDIOCGWIN:
 468                {
 469                        struct video_window *vw = arg;
 470
 471                        vw->x = 0;
 472                        vw->y = 0;
 473                        vw->width = pdev->view.x;
 474                        vw->height = pdev->view.y;
 475                        vw->chromakey = 0;
 476                        vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
 477                                   (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
 478                        break;
 479                }
 480
 481                case VIDIOCSWIN:
 482                {
 483                        struct video_window *vw = arg;
 484                        int fps, snapshot, ret;
 485
 486                        fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
 487                        snapshot = vw->flags & PWC_FPS_SNAPSHOT;
 488                        if (fps == 0)
 489                                fps = pdev->vframes;
 490                        if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
 491                                return 0;
 492                        ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
 493                        if (ret)
 494                                return ret;
 495                        break;
 496                }
 497
 498                /* We don't have overlay support (yet) */
 499                case VIDIOCGFBUF:
 500                {
 501                        struct video_buffer *vb = arg;
 502
 503                        memset(vb,0,sizeof(*vb));
 504                        break;
 505                }
 506
 507                /* mmap() functions */
 508                case VIDIOCGMBUF:
 509                {
 510                        /* Tell the user program how much memory is needed for a mmap() */
 511                        struct video_mbuf *vm = arg;
 512                        int i;
 513
 514                        memset(vm, 0, sizeof(*vm));
 515                        vm->size = pwc_mbufs * pdev->len_per_image;
 516                        vm->frames = pwc_mbufs; /* double buffering should be enough for most applications */
 517                        for (i = 0; i < pwc_mbufs; i++)
 518                                vm->offsets[i] = i * pdev->len_per_image;
 519                        break;
 520                }
 521
 522                case VIDIOCMCAPTURE:
 523                {
 524                        /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
 525                        struct video_mmap *vm = arg;
 526
 527                        PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
 528                        if (vm->frame < 0 || vm->frame >= pwc_mbufs)
 529                                return -EINVAL;
 530
 531                        /* xawtv is nasty. It probes the available palettes
 532                           by setting a very small image size and trying
 533                           various palettes... The driver doesn't support
 534                           such small images, so I'm working around it.
 535                         */
 536                        if (vm->format)
 537                        {
 538                                switch (vm->format)
 539                                {
 540                                        case VIDEO_PALETTE_YUV420P:
 541                                        case VIDEO_PALETTE_RAW:
 542                                                break;
 543                                        default:
 544                                                return -EINVAL;
 545                                                break;
 546                                }
 547                        }
 548
 549                        if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
 550                            (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
 551                                int ret;
 552
 553                                PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
 554                                ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
 555                                if (ret)
 556                                        return ret;
 557                        } /* ... size mismatch */
 558
 559                        /* FIXME: should we lock here? */
 560                        if (pdev->image_used[vm->frame])
 561                                return -EBUSY;  /* buffer wasn't available. Bummer */
 562                        pdev->image_used[vm->frame] = 1;
 563
 564                        /* Okay, we're done here. In the SYNC call we wait until a
 565                           frame comes available, then expand image into the given
 566                           buffer.
 567                           In contrast to the CPiA cam the Philips cams deliver a
 568                           constant stream, almost like a grabber card. Also,
 569                           we have separate buffers for the rawdata and the image,
 570                           meaning we can nearly always expand into the requested buffer.
 571                         */
 572                        PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
 573                        break;
 574                }
 575
 576                case VIDIOCSYNC:
 577                {
 578                        /* The doc says: "Whenever a buffer is used it should
 579                           call VIDIOCSYNC to free this frame up and continue."
 580
 581                           The only odd thing about this whole procedure is
 582                           that MCAPTURE flags the buffer as "in use", and
 583                           SYNC immediately unmarks it, while it isn't
 584                           after SYNC that you know that the buffer actually
 585                           got filled! So you better not start a CAPTURE in
 586                           the same frame immediately (use double buffering).
 587                           This is not a problem for this cam, since it has
 588                           extra intermediate buffers, but a hardware
 589                           grabber card will then overwrite the buffer
 590                           you're working on.
 591                         */
 592                        int *mbuf = arg;
 593                        int ret;
 594
 595                        PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf);
 596
 597                        /* bounds check */
 598                        if (*mbuf < 0 || *mbuf >= pwc_mbufs)
 599                                return -EINVAL;
 600                        /* check if this buffer was requested anyway */
 601                        if (pdev->image_used[*mbuf] == 0)
 602                                return -EINVAL;
 603
 604                        /* Add ourselves to the frame wait-queue.
 605
 606                           FIXME: needs auditing for safety.
 607                           QUESTION: In what respect? I think that using the
 608                                     frameq is safe now.
 609                         */
 610                        add_wait_queue(&pdev->frameq, &wait);
 611                        while (pdev->full_frames == NULL) {
 612                                /* Check for unplugged/etc. here */
 613                                if (pdev->error_status) {
 614                                        remove_wait_queue(&pdev->frameq, &wait);
 615                                        set_current_state(TASK_RUNNING);
 616                                        return -pdev->error_status;
 617                                }
 618
 619                                if (signal_pending(current)) {
 620                                        remove_wait_queue(&pdev->frameq, &wait);
 621                                        set_current_state(TASK_RUNNING);
 622                                        return -ERESTARTSYS;
 623                                }
 624                                schedule();
 625                                set_current_state(TASK_INTERRUPTIBLE);
 626                        }
 627                        remove_wait_queue(&pdev->frameq, &wait);
 628                        set_current_state(TASK_RUNNING);
 629
 630                        /* The frame is ready. Expand in the image buffer
 631                           requested by the user. I don't care if you
 632                           mmap() 5 buffers and request data in this order:
 633                           buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
 634                           Grabber hardware may not be so forgiving.
 635                         */
 636                        PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n");
 637                        pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
 638                        /* Decompress, etc */
 639                        ret = pwc_handle_frame(pdev);
 640                        pdev->image_used[*mbuf] = 0;
 641                        if (ret)
 642                                return -EFAULT;
 643                        break;
 644                }
 645
 646                case VIDIOCGAUDIO:
 647                {
 648                        struct video_audio *v = arg;
 649
 650                        strcpy(v->name, "Microphone");
 651                        v->audio = -1; /* unknown audio minor */
 652                        v->flags = 0;
 653                        v->mode = VIDEO_SOUND_MONO;
 654                        v->volume = 0;
 655                        v->bass = 0;
 656                        v->treble = 0;
 657                        v->balance = 0x8000;
 658                        v->step = 1;
 659                        break;
 660                }
 661
 662                case VIDIOCSAUDIO:
 663                {
 664                        /* Dummy: nothing can be set */
 665                        break;
 666                }
 667
 668                case VIDIOCGUNIT:
 669                {
 670                        struct video_unit *vu = arg;
 671
 672                        vu->video = pdev->vdev->minor & 0x3F;
 673                        vu->audio = -1; /* not known yet */
 674                        vu->vbi = -1;
 675                        vu->radio = -1;
 676                        vu->teletext = -1;
 677                        break;
 678                }
 679
 680                /* V4L2 Layer */
 681                case VIDIOC_QUERYCAP:
 682                {
 683                    struct v4l2_capability *cap = arg;
 684
 685                    PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\
 686                                       "try to use the v4l2 layer\n");
 687                    strcpy(cap->driver,PWC_NAME);
 688                    strlcpy(cap->card, vdev->name, sizeof(cap->card));
 689                    usb_make_path(pdev->udev,cap->bus_info,sizeof(cap->bus_info));
 690                    cap->version = PWC_VERSION_CODE;
 691                    cap->capabilities =
 692                        V4L2_CAP_VIDEO_CAPTURE  |
 693                        V4L2_CAP_STREAMING      |
 694                        V4L2_CAP_READWRITE;
 695                    return 0;
 696                }
 697
 698                case VIDIOC_ENUMINPUT:
 699                {
 700                    struct v4l2_input *i = arg;
 701
 702                    if ( i->index )     /* Only one INPUT is supported */
 703                          return -EINVAL;
 704
 705                    memset(i, 0, sizeof(struct v4l2_input));
 706                    strcpy(i->name, "usb");
 707                    return 0;
 708                }
 709
 710                case VIDIOC_G_INPUT:
 711                {
 712                    int *i = arg;
 713                    *i = 0;     /* Only one INPUT is supported */
 714                    return 0;
 715                }
 716                case VIDIOC_S_INPUT:
 717                {
 718                        int *i = arg;
 719
 720                        if ( *i ) {     /* Only one INPUT is supported */
 721                                PWC_DEBUG_IOCTL("Only one input source is"\
 722                                        " supported with this webcam.\n");
 723                                return -EINVAL;
 724                        }
 725                        return 0;
 726                }
 727
 728                /* TODO: */
 729                case VIDIOC_QUERYCTRL:
 730                {
 731                        struct v4l2_queryctrl *c = arg;
 732                        int i;
 733
 734                        PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c->id);
 735                        for (i=0; i<sizeof(pwc_controls)/sizeof(struct v4l2_queryctrl); i++) {
 736                                if (pwc_controls[i].id == c->id) {
 737                                        PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
 738                                        memcpy(c,&pwc_controls[i],sizeof(struct v4l2_queryctrl));
 739                                        return 0;
 740                                }
 741                        }
 742                        PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");
 743
 744                        return -EINVAL;
 745                }
 746                case VIDIOC_G_CTRL:
 747                {
 748                        struct v4l2_control *c = arg;
 749                        int ret;
 750
 751                        switch (c->id)
 752                        {
 753                                case V4L2_CID_BRIGHTNESS:
 754                                        c->value = pwc_get_brightness(pdev);
 755                                        if (c->value<0)
 756                                                return -EINVAL;
 757                                        return 0;
 758                                case V4L2_CID_CONTRAST:
 759                                        c->value = pwc_get_contrast(pdev);
 760                                        if (c->value<0)
 761                                                return -EINVAL;
 762                                        return 0;
 763                                case V4L2_CID_SATURATION:
 764                                        ret = pwc_get_saturation(pdev, &c->value);
 765                                        if (ret<0)
 766                                                return -EINVAL;
 767                                        return 0;
 768                                case V4L2_CID_GAMMA:
 769                                        c->value = pwc_get_gamma(pdev);
 770                                        if (c->value<0)
 771                                                return -EINVAL;
 772                                        return 0;
 773                                case V4L2_CID_RED_BALANCE:
 774                                        ret = pwc_get_red_gain(pdev, &c->value);
 775                                        if (ret<0)
 776                                                return -EINVAL;
 777                                        c->value >>= 8;
 778                                        return 0;
 779                                case V4L2_CID_BLUE_BALANCE:
 780                                        ret = pwc_get_blue_gain(pdev, &c->value);
 781                                        if (ret<0)
 782                                                return -EINVAL;
 783                                        c->value >>= 8;
 784                                        return 0;
 785                                case V4L2_CID_AUTO_WHITE_BALANCE:
 786                                        ret = pwc_get_awb(pdev);
 787                                        if (ret<0)
 788                                                return -EINVAL;
 789                                        c->value = (ret == PWC_WB_MANUAL)?0:1;
 790                                        return 0;
 791                                case V4L2_CID_GAIN:
 792                                        ret = pwc_get_agc(pdev, &c->value);
 793                                        if (ret<0)
 794                                                return -EINVAL;
 795                                        c->value >>= 8;
 796                                        return 0;
 797                                case V4L2_CID_AUTOGAIN:
 798                                        ret = pwc_get_agc(pdev, &c->value);
 799                                        if (ret<0)
 800                                                return -EINVAL;
 801                                        c->value = (c->value < 0)?1:0;
 802                                        return 0;
 803                                case V4L2_CID_EXPOSURE:
 804                                        ret = pwc_get_shutter_speed(pdev, &c->value);
 805                                        if (ret<0)
 806                                                return -EINVAL;
 807                                        return 0;
 808                                case V4L2_CID_PRIVATE_COLOUR_MODE:
 809                                        ret = pwc_get_colour_mode(pdev, &c->value);
 810                                        if (ret < 0)
 811                                                return -EINVAL;
 812                                        return 0;
 813                                case V4L2_CID_PRIVATE_AUTOCONTOUR:
 814                                        ret = pwc_get_contour(pdev, &c->value);
 815                                        if (ret < 0)
 816                                                return -EINVAL;
 817                                        c->value=(c->value == -1?1:0);
 818                                        return 0;
 819                                case V4L2_CID_PRIVATE_CONTOUR:
 820                                        ret = pwc_get_contour(pdev, &c->value);
 821                                        if (ret < 0)
 822                                                return -EINVAL;
 823                                        c->value >>= 10;
 824                                        return 0;
 825                                case V4L2_CID_PRIVATE_BACKLIGHT:
 826                                        ret = pwc_get_backlight(pdev, &c->value);
 827                                        if (ret < 0)
 828                                                return -EINVAL;
 829                                        return 0;
 830                                case V4L2_CID_PRIVATE_FLICKERLESS:
 831                                        ret = pwc_get_flicker(pdev, &c->value);
 832                                        if (ret < 0)
 833                                                return -EINVAL;
 834                                        c->value=(c->value?1:0);
 835                                        return 0;
 836                                case V4L2_CID_PRIVATE_NOISE_REDUCTION:
 837                                        ret = pwc_get_dynamic_noise(pdev, &c->value);
 838                                        if (ret < 0)
 839                                                return -EINVAL;
 840                                        return 0;
 841
 842                                case V4L2_CID_PRIVATE_SAVE_USER:
 843                                case V4L2_CID_PRIVATE_RESTORE_USER:
 844                                case V4L2_CID_PRIVATE_RESTORE_FACTORY:
 845                                        return -EINVAL;
 846                        }
 847                        return -EINVAL;
 848                }
 849                case VIDIOC_S_CTRL:
 850                {
 851                        struct v4l2_control *c = arg;
 852                        int ret;
 853
 854                        switch (c->id)
 855                        {
 856                                case V4L2_CID_BRIGHTNESS:
 857                                        c->value <<= 9;
 858                                        ret = pwc_set_brightness(pdev, c->value);
 859                                        if (ret<0)
 860                                                return -EINVAL;
 861                                        return 0;
 862                                case V4L2_CID_CONTRAST:
 863                                        c->value <<= 10;
 864                                        ret = pwc_set_contrast(pdev, c->value);
 865                                        if (ret<0)
 866                                                return -EINVAL;
 867                                        return 0;
 868                                case V4L2_CID_SATURATION:
 869                                        ret = pwc_set_saturation(pdev, c->value);
 870                                        if (ret<0)
 871                                          return -EINVAL;
 872                                        return 0;
 873                                case V4L2_CID_GAMMA:
 874                                        c->value <<= 11;
 875                                        ret = pwc_set_gamma(pdev, c->value);
 876                                        if (ret<0)
 877                                                return -EINVAL;
 878                                        return 0;
 879                                case V4L2_CID_RED_BALANCE:
 880                                        c->value <<= 8;
 881                                        ret = pwc_set_red_gain(pdev, c->value);
 882                                        if (ret<0)
 883                                                return -EINVAL;
 884                                        return 0;
 885                                case V4L2_CID_BLUE_BALANCE:
 886                                        c->value <<= 8;
 887                                        ret = pwc_set_blue_gain(pdev, c->value);
 888                                        if (ret<0)
 889                                                return -EINVAL;
 890                                        return 0;
 891                                case V4L2_CID_AUTO_WHITE_BALANCE:
 892                                        c->value = (c->value == 0)?PWC_WB_MANUAL:PWC_WB_AUTO;
 893                                        ret = pwc_set_awb(pdev, c->value);
 894                                        if (ret<0)
 895                                                return -EINVAL;
 896                                        return 0;
 897                                case V4L2_CID_EXPOSURE:
 898                                        c->value <<= 8;
 899                                        ret = pwc_set_shutter_speed(pdev, c->value?0:1, c->value);
 900                                        if (ret<0)
 901                                                return -EINVAL;
 902                                        return 0;
 903                                case V4L2_CID_AUTOGAIN:
 904                                        /* autogain off means nothing without a gain */
 905                                        if (c->value == 0)
 906                                                return 0;
 907                                        ret = pwc_set_agc(pdev, c->value, 0);
 908                                        if (ret<0)
 909                                                return -EINVAL;
 910                                        return 0;
 911                                case V4L2_CID_GAIN:
 912                                        c->value <<= 8;
 913                                        ret = pwc_set_agc(pdev, 0, c->value);
 914                                        if (ret<0)
 915                                                return -EINVAL;
 916                                        return 0;
 917                                case V4L2_CID_PRIVATE_SAVE_USER:
 918                                        if (pwc_save_user(pdev))
 919                                                return -EINVAL;
 920                                        return 0;
 921                                case V4L2_CID_PRIVATE_RESTORE_USER:
 922                                        if (pwc_restore_user(pdev))
 923                                                return -EINVAL;
 924                                        return 0;
 925                                case V4L2_CID_PRIVATE_RESTORE_FACTORY:
 926                                        if (pwc_restore_factory(pdev))
 927                                                return -EINVAL;
 928                                        return 0;
 929                                case V4L2_CID_PRIVATE_COLOUR_MODE:
 930                                        ret = pwc_set_colour_mode(pdev, c->value);
 931                                        if (ret < 0)
 932                                          return -EINVAL;
 933                                        return 0;
 934                                case V4L2_CID_PRIVATE_AUTOCONTOUR:
 935                                  c->value=(c->value == 1)?-1:0;
 936                                  ret = pwc_set_contour(pdev, c->value);
 937                                  if (ret < 0)
 938                                    return -EINVAL;
 939                                  return 0;
 940                                case V4L2_CID_PRIVATE_CONTOUR:
 941                                  c->value <<= 10;
 942                                  ret = pwc_set_contour(pdev, c->value);
 943                                  if (ret < 0)
 944                                    return -EINVAL;
 945                                  return 0;
 946                                case V4L2_CID_PRIVATE_BACKLIGHT:
 947                                  ret = pwc_set_backlight(pdev, c->value);
 948                                  if (ret < 0)
 949                                    return -EINVAL;
 950                                  return 0;
 951                                case V4L2_CID_PRIVATE_FLICKERLESS:
 952                                  ret = pwc_set_flicker(pdev, c->value);
 953                                  if (ret < 0)
 954                                    return -EINVAL;
 955                                case V4L2_CID_PRIVATE_NOISE_REDUCTION:
 956                                  ret = pwc_set_dynamic_noise(pdev, c->value);
 957                                  if (ret < 0)
 958                                    return -EINVAL;
 959                                  return 0;
 960
 961                        }
 962                        return -EINVAL;
 963                }
 964
 965                case VIDIOC_ENUM_FMT:
 966                {
 967                        struct v4l2_fmtdesc *f = arg;
 968                        int index;
 969
 970                        if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 971                              return -EINVAL;
 972
 973                        /* We only support two format: the raw format, and YUV */
 974                        index = f->index;
 975                        memset(f,0,sizeof(struct v4l2_fmtdesc));
 976                        f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 977                        f->index = index;
 978                        switch(index)
 979                        {
 980                                case 0:
 981                                        /* RAW format */
 982                                        f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2;
 983                                        f->flags = V4L2_FMT_FLAG_COMPRESSED;
 984                                        strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description));
 985                                        break;
 986                                case 1:
 987                                        f->pixelformat = V4L2_PIX_FMT_YUV420;
 988                                        strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description));
 989                                        break;
 990                                default:
 991                                        return -EINVAL;
 992                        }
 993                        return 0;
 994                }
 995
 996                case VIDIOC_G_FMT:
 997                {
 998                        struct v4l2_format *f = arg;
 999
1000                        PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev->image.x,pdev->image.y);
1001                        if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1002                              return -EINVAL;
1003
1004                        pwc_vidioc_fill_fmt(pdev, f);
1005
1006                        return 0;
1007                }
1008
1009                case VIDIOC_TRY_FMT:
1010                        return pwc_vidioc_try_fmt(pdev, arg);
1011
1012                case VIDIOC_S_FMT:
1013                        return pwc_vidioc_set_fmt(pdev, arg);
1014
1015                case VIDIOC_G_STD:
1016                {
1017                        v4l2_std_id *std = arg;
1018                        *std = V4L2_STD_UNKNOWN;
1019                        return 0;
1020                }
1021
1022                case VIDIOC_S_STD:
1023                {
1024                        v4l2_std_id *std = arg;
1025                        if (*std != V4L2_STD_UNKNOWN)
1026                                return -EINVAL;
1027                        return 0;
1028                }
1029
1030                case VIDIOC_ENUMSTD:
1031                {
1032                        struct v4l2_standard *std = arg;
1033                        if (std->index != 0)
1034                                return -EINVAL;
1035                        std->id = V4L2_STD_UNKNOWN;
1036                        strlcpy(std->name, "webcam", sizeof(std->name));
1037                        return 0;
1038                }
1039
1040                case VIDIOC_REQBUFS:
1041                {
1042                        struct v4l2_requestbuffers *rb = arg;
1043                        int nbuffers;
1044
1045                        PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb->count);
1046                        if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1047                                return -EINVAL;
1048                        if (rb->memory != V4L2_MEMORY_MMAP)
1049                                return -EINVAL;
1050
1051                        nbuffers = rb->count;
1052                        if (nbuffers < 2)
1053                                nbuffers = 2;
1054                        else if (nbuffers > pwc_mbufs)
1055                                nbuffers = pwc_mbufs;
1056                        /* Force to use our # of buffers */
1057                        rb->count = pwc_mbufs;
1058                        return 0;
1059                }
1060
1061                case VIDIOC_QUERYBUF:
1062                {
1063                        struct v4l2_buffer *buf = arg;
1064                        int index;
1065
1066                        PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf->index);
1067                        if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1068                                PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
1069                                return -EINVAL;
1070                        }
1071                        if (buf->memory != V4L2_MEMORY_MMAP) {
1072                                PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
1073                                return -EINVAL;
1074                        }
1075                        index = buf->index;
1076                        if (index < 0 || index >= pwc_mbufs) {
1077                                PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
1078                                return -EINVAL;
1079                        }
1080
1081                        memset(buf, 0, sizeof(struct v4l2_buffer));
1082                        buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1083                        buf->index = index;
1084                        buf->m.offset = index * pdev->len_per_image;
1085                        if (pdev->vpalette == VIDEO_PALETTE_RAW)
1086                                buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
1087                        else
1088                                buf->bytesused = pdev->view.size;
1089                        buf->field = V4L2_FIELD_NONE;
1090                        buf->memory = V4L2_MEMORY_MMAP;
1091                        //buf->flags = V4L2_BUF_FLAG_MAPPED;
1092                        buf->length = pdev->len_per_image;
1093
1094                        PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf->index);
1095                        PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf->m.offset);
1096                        PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf->bytesused);
1097
1098                        return 0;
1099                }
1100
1101                case VIDIOC_QBUF:
1102                {
1103                        struct v4l2_buffer *buf = arg;
1104
1105                        PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf->index);
1106                        if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1107                                return -EINVAL;
1108                        if (buf->memory != V4L2_MEMORY_MMAP)
1109                                return -EINVAL;
1110                        if (buf->index >= pwc_mbufs)
1111                                return -EINVAL;
1112
1113                        buf->flags |= V4L2_BUF_FLAG_QUEUED;
1114                        buf->flags &= ~V4L2_BUF_FLAG_DONE;
1115
1116                        return 0;
1117                }
1118
1119                case VIDIOC_DQBUF:
1120                {
1121                        struct v4l2_buffer *buf = arg;
1122                        int ret;
1123
1124                        PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
1125
1126                        if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1127                                return -EINVAL;
1128
1129                        /* Add ourselves to the frame wait-queue.
1130
1131                           FIXME: needs auditing for safety.
1132                           QUESTION: In what respect? I think that using the
1133                                     frameq is safe now.
1134                         */
1135                        add_wait_queue(&pdev->frameq, &wait);
1136                        while (pdev->full_frames == NULL) {
1137                                if (pdev->error_status) {
1138                                        remove_wait_queue(&pdev->frameq, &wait);
1139                                        set_current_state(TASK_RUNNING);
1140                                        return -pdev->error_status;
1141                                }
1142
1143                                if (signal_pending(current)) {
1144                                        remove_wait_queue(&pdev->frameq, &wait);
1145                                        set_current_state(TASK_RUNNING);
1146                                        return -ERESTARTSYS;
1147                                }
1148                                schedule();
1149                                set_current_state(TASK_INTERRUPTIBLE);
1150                        }
1151                        remove_wait_queue(&pdev->frameq, &wait);
1152                        set_current_state(TASK_RUNNING);
1153
1154                        PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
1155                        /* Decompress data in pdev->images[pdev->fill_image] */
1156                        ret = pwc_handle_frame(pdev);
1157                        if (ret)
1158                                return -EFAULT;
1159                        PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
1160
1161                        buf->index = pdev->fill_image;
1162                        if (pdev->vpalette == VIDEO_PALETTE_RAW)
1163                                buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
1164                        else
1165                                buf->bytesused = pdev->view.size;
1166                        buf->flags = V4L2_BUF_FLAG_MAPPED;
1167                        buf->field = V4L2_FIELD_NONE;
1168                        do_gettimeofday(&buf->timestamp);
1169                        buf->sequence = 0;
1170                        buf->memory = V4L2_MEMORY_MMAP;
1171                        buf->m.offset = pdev->fill_image * pdev->len_per_image;
1172                        buf->length = pdev->len_per_image;
1173                        pwc_next_image(pdev);
1174
1175                        PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index);
1176                        PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf->length);
1177                        PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf->m.offset);
1178                        PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf->bytesused);
1179                        PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
1180                        return 0;
1181
1182                }
1183
1184                case VIDIOC_STREAMON:
1185                {
1186                        /* WARNING: pwc_try_video_mode() called pwc_isoc_init */
1187                        pwc_isoc_init(pdev);
1188                        return 0;
1189                }
1190
1191                case VIDIOC_STREAMOFF:
1192                {
1193                        pwc_isoc_cleanup(pdev);
1194                        return 0;
1195                }
1196
1197                case VIDIOC_ENUM_FRAMESIZES:
1198                {
1199                        struct v4l2_frmsizeenum *fsize = arg;
1200                        unsigned int i = 0, index = fsize->index;
1201
1202                        if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) {
1203                                for (i = 0; i < PSZ_MAX; i++) {
1204                                        if (pdev->image_mask & (1UL << i)) {
1205                                                if (!index--) {
1206                                                        fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1207                                                        fsize->discrete.width = pwc_image_sizes[i].x;
1208                                                        fsize->discrete.height = pwc_image_sizes[i].y;
1209                                                        return 0;
1210                                                }
1211                                        }
1212                                }
1213                        } else if (fsize->index == 0 &&
1214                                   ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) ||
1215                                    (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) {
1216
1217                                fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1218                                fsize->discrete.width = pdev->abs_max.x;
1219                                fsize->discrete.height = pdev->abs_max.y;
1220                                return 0;
1221                        }
1222                        return -EINVAL;
1223                }
1224
1225                case VIDIOC_ENUM_FRAMEINTERVALS:
1226                {
1227                        struct v4l2_frmivalenum *fival = arg;
1228                        int size = -1;
1229                        unsigned int i;
1230
1231                        for (i = 0; i < PSZ_MAX; i++) {
1232                                if (pwc_image_sizes[i].x == fival->width &&
1233                                    pwc_image_sizes[i].y == fival->height) {
1234                                        size = i;
1235                                        break;
1236                                }
1237                        }
1238
1239                        /* TODO: Support raw format */
1240                        if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) {
1241                                return -EINVAL;
1242                        }
1243
1244                        i = pwc_get_fps(pdev, fival->index, size);
1245                        if (!i)
1246                                return -EINVAL;
1247
1248                        fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
1249                        fival->discrete.numerator = 1;
1250                        fival->discrete.denominator = i;
1251
1252                        return 0;
1253                }
1254
1255                default:
1256                        return pwc_ioctl(pdev, cmd, arg);
1257        } /* ..switch */
1258        return 0;
1259}
1260
1261/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
1262