OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [media/] [video/] [pwc/] [pwc-v4l.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/* 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
 
39
static 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
 
214
static 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) */
246
static 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) */
288
static 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
 
340
int pwc_video_do_ioctl(struct inode *inode, struct file *file,
341
                       unsigned int cmd, void *arg)
342
{
343
        struct video_device *vdev = video_devdata(file);
344
        struct pwc_device *pdev;
345
        DECLARE_WAITQUEUE(wait, current);
346
 
347
        if (vdev == NULL)
348
                return -EFAULT;
349
        pdev = vdev->priv;
350
        if (pdev == NULL)
351
                return -EFAULT;
352
 
353
#ifdef CONFIG_USB_PWC_DEBUG
354
        if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace)
355
                v4l_printk_ioctl(cmd);
356
#endif
357
 
358
 
359
        switch (cmd) {
360
                /* Query cabapilities */
361
                case VIDIOCGCAP:
362
                {
363
                        struct video_capability *caps = arg;
364
 
365
                        strcpy(caps->name, vdev->name);
366
                        caps->type = VID_TYPE_CAPTURE;
367
                        caps->channels = 1;
368
                        caps->audios = 1;
369
                        caps->minwidth  = pdev->view_min.x;
370
                        caps->minheight = pdev->view_min.y;
371
                        caps->maxwidth  = pdev->view_max.x;
372
                        caps->maxheight = pdev->view_max.y;
373
                        break;
374
                }
375
 
376
                /* Channel functions (simulate 1 channel) */
377
                case VIDIOCGCHAN:
378
                {
379
                        struct video_channel *v = arg;
380
 
381
                        if (v->channel != 0)
382
                                return -EINVAL;
383
                        v->flags = 0;
384
                        v->tuners = 0;
385
                        v->type = VIDEO_TYPE_CAMERA;
386
                        strcpy(v->name, "Webcam");
387
                        return 0;
388
                }
389
 
390
                case VIDIOCSCHAN:
391
                {
392
                        /* The spec says the argument is an integer, but
393
                           the bttv driver uses a video_channel arg, which
394
                           makes sense becasue it also has the norm flag.
395
                         */
396
                        struct video_channel *v = arg;
397
                        if (v->channel != 0)
398
                                return -EINVAL;
399
                        return 0;
400
                }
401
 
402
 
403
                /* Picture functions; contrast etc. */
404
                case VIDIOCGPICT:
405
                {
406
                        struct video_picture *p = arg;
407
                        int val;
408
 
409
                        val = pwc_get_brightness(pdev);
410
                        if (val >= 0)
411
                                p->brightness = (val<<9);
412
                        else
413
                                p->brightness = 0xffff;
414
                        val = pwc_get_contrast(pdev);
415
                        if (val >= 0)
416
                                p->contrast = (val<<10);
417
                        else
418
                                p->contrast = 0xffff;
419
                        /* Gamma, Whiteness, what's the difference? :) */
420
                        val = pwc_get_gamma(pdev);
421
                        if (val >= 0)
422
                                p->whiteness = (val<<11);
423
                        else
424
                                p->whiteness = 0xffff;
425
                        if (pwc_get_saturation(pdev, &val)<0)
426
                                p->colour = 0xffff;
427
                        else
428
                                p->colour = 32768 + val * 327;
429
                        p->depth = 24;
430
                        p->palette = pdev->vpalette;
431
                        p->hue = 0xFFFF; /* N/A */
432
                        break;
433
                }
434
 
435
                case VIDIOCSPICT:
436
                {
437
                        struct video_picture *p = arg;
438
                        /*
439
                         *      FIXME:  Suppose we are mid read
440
                                ANSWER: No problem: the firmware of the camera
441
                                        can handle brightness/contrast/etc
442
                                        changes at _any_ time, and the palette
443
                                        is used exactly once in the uncompress
444
                                        routine.
445
                         */
446
                        pwc_set_brightness(pdev, p->brightness);
447
                        pwc_set_contrast(pdev, p->contrast);
448
                        pwc_set_gamma(pdev, p->whiteness);
449
                        pwc_set_saturation(pdev, (p->colour-32768)/327);
450
                        if (p->palette && p->palette != pdev->vpalette) {
451
                                switch (p->palette) {
452
                                        case VIDEO_PALETTE_YUV420P:
453
                                        case VIDEO_PALETTE_RAW:
454
                                                pdev->vpalette = p->palette;
455
                                                return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
456
                                                break;
457
                                        default:
458
                                                return -EINVAL;
459
                                                break;
460
                                }
461
                        }
462
                        break;
463
                }
464
 
465
                /* Window/size parameters */
466
                case VIDIOCGWIN:
467
                {
468
                        struct video_window *vw = arg;
469
 
470
                        vw->x = 0;
471
                        vw->y = 0;
472
                        vw->width = pdev->view.x;
473
                        vw->height = pdev->view.y;
474
                        vw->chromakey = 0;
475
                        vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
476
                                   (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
477
                        break;
478
                }
479
 
480
                case VIDIOCSWIN:
481
                {
482
                        struct video_window *vw = arg;
483
                        int fps, snapshot, ret;
484
 
485
                        fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
486
                        snapshot = vw->flags & PWC_FPS_SNAPSHOT;
487
                        if (fps == 0)
488
                                fps = pdev->vframes;
489
                        if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
490
                                return 0;
491
                        ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
492
                        if (ret)
493
                                return ret;
494
                        break;
495
                }
496
 
497
                /* We don't have overlay support (yet) */
498
                case VIDIOCGFBUF:
499
                {
500
                        struct video_buffer *vb = arg;
501
 
502
                        memset(vb,0,sizeof(*vb));
503
                        break;
504
                }
505
 
506
                /* mmap() functions */
507
                case VIDIOCGMBUF:
508
                {
509
                        /* Tell the user program how much memory is needed for a mmap() */
510
                        struct video_mbuf *vm = arg;
511
                        int i;
512
 
513
                        memset(vm, 0, sizeof(*vm));
514
                        vm->size = pwc_mbufs * pdev->len_per_image;
515
                        vm->frames = pwc_mbufs; /* double buffering should be enough for most applications */
516
                        for (i = 0; i < pwc_mbufs; i++)
517
                                vm->offsets[i] = i * pdev->len_per_image;
518
                        break;
519
                }
520
 
521
                case VIDIOCMCAPTURE:
522
                {
523
                        /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
524
                        struct video_mmap *vm = arg;
525
 
526
                        PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
527
                        if (vm->frame < 0 || vm->frame >= pwc_mbufs)
528
                                return -EINVAL;
529
 
530
                        /* xawtv is nasty. It probes the available palettes
531
                           by setting a very small image size and trying
532
                           various palettes... The driver doesn't support
533
                           such small images, so I'm working around it.
534
                         */
535
                        if (vm->format)
536
                        {
537
                                switch (vm->format)
538
                                {
539
                                        case VIDEO_PALETTE_YUV420P:
540
                                        case VIDEO_PALETTE_RAW:
541
                                                break;
542
                                        default:
543
                                                return -EINVAL;
544
                                                break;
545
                                }
546
                        }
547
 
548
                        if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
549
                            (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
550
                                int ret;
551
 
552
                                PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
553
                                ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
554
                                if (ret)
555
                                        return ret;
556
                        } /* ... size mismatch */
557
 
558
                        /* FIXME: should we lock here? */
559
                        if (pdev->image_used[vm->frame])
560
                                return -EBUSY;  /* buffer wasn't available. Bummer */
561
                        pdev->image_used[vm->frame] = 1;
562
 
563
                        /* Okay, we're done here. In the SYNC call we wait until a
564
                           frame comes available, then expand image into the given
565
                           buffer.
566
                           In contrast to the CPiA cam the Philips cams deliver a
567
                           constant stream, almost like a grabber card. Also,
568
                           we have separate buffers for the rawdata and the image,
569
                           meaning we can nearly always expand into the requested buffer.
570
                         */
571
                        PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
572
                        break;
573
                }
574
 
575
                case VIDIOCSYNC:
576
                {
577
                        /* The doc says: "Whenever a buffer is used it should
578
                           call VIDIOCSYNC to free this frame up and continue."
579
 
580
                           The only odd thing about this whole procedure is
581
                           that MCAPTURE flags the buffer as "in use", and
582
                           SYNC immediately unmarks it, while it isn't
583
                           after SYNC that you know that the buffer actually
584
                           got filled! So you better not start a CAPTURE in
585
                           the same frame immediately (use double buffering).
586
                           This is not a problem for this cam, since it has
587
                           extra intermediate buffers, but a hardware
588
                           grabber card will then overwrite the buffer
589
                           you're working on.
590
                         */
591
                        int *mbuf = arg;
592
                        int ret;
593
 
594
                        PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf);
595
 
596
                        /* bounds check */
597
                        if (*mbuf < 0 || *mbuf >= pwc_mbufs)
598
                                return -EINVAL;
599
                        /* check if this buffer was requested anyway */
600
                        if (pdev->image_used[*mbuf] == 0)
601
                                return -EINVAL;
602
 
603
                        /* Add ourselves to the frame wait-queue.
604
 
605
                           FIXME: needs auditing for safety.
606
                           QUESTION: In what respect? I think that using the
607
                                     frameq is safe now.
608
                         */
609
                        add_wait_queue(&pdev->frameq, &wait);
610
                        while (pdev->full_frames == NULL) {
611
                                /* Check for unplugged/etc. here */
612
                                if (pdev->error_status) {
613
                                        remove_wait_queue(&pdev->frameq, &wait);
614
                                        set_current_state(TASK_RUNNING);
615
                                        return -pdev->error_status;
616
                                }
617
 
618
                                if (signal_pending(current)) {
619
                                        remove_wait_queue(&pdev->frameq, &wait);
620
                                        set_current_state(TASK_RUNNING);
621
                                        return -ERESTARTSYS;
622
                                }
623
                                schedule();
624
                                set_current_state(TASK_INTERRUPTIBLE);
625
                        }
626
                        remove_wait_queue(&pdev->frameq, &wait);
627
                        set_current_state(TASK_RUNNING);
628
 
629
                        /* The frame is ready. Expand in the image buffer
630
                           requested by the user. I don't care if you
631
                           mmap() 5 buffers and request data in this order:
632
                           buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
633
                           Grabber hardware may not be so forgiving.
634
                         */
635
                        PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n");
636
                        pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
637
                        /* Decompress, etc */
638
                        ret = pwc_handle_frame(pdev);
639
                        pdev->image_used[*mbuf] = 0;
640
                        if (ret)
641
                                return -EFAULT;
642
                        break;
643
                }
644
 
645
                case VIDIOCGAUDIO:
646
                {
647
                        struct video_audio *v = arg;
648
 
649
                        strcpy(v->name, "Microphone");
650
                        v->audio = -1; /* unknown audio minor */
651
                        v->flags = 0;
652
                        v->mode = VIDEO_SOUND_MONO;
653
                        v->volume = 0;
654
                        v->bass = 0;
655
                        v->treble = 0;
656
                        v->balance = 0x8000;
657
                        v->step = 1;
658
                        break;
659
                }
660
 
661
                case VIDIOCSAUDIO:
662
                {
663
                        /* Dummy: nothing can be set */
664
                        break;
665
                }
666
 
667
                case VIDIOCGUNIT:
668
                {
669
                        struct video_unit *vu = arg;
670
 
671
                        vu->video = pdev->vdev->minor & 0x3F;
672
                        vu->audio = -1; /* not known yet */
673
                        vu->vbi = -1;
674
                        vu->radio = -1;
675
                        vu->teletext = -1;
676
                        break;
677
                }
678
 
679
                /* V4L2 Layer */
680
                case VIDIOC_QUERYCAP:
681
                {
682
                    struct v4l2_capability *cap = arg;
683
 
684
                    PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\
685
                                       "try to use the v4l2 layer\n");
686
                    strcpy(cap->driver,PWC_NAME);
687
                    strlcpy(cap->card, vdev->name, sizeof(cap->card));
688
                    usb_make_path(pdev->udev,cap->bus_info,sizeof(cap->bus_info));
689
                    cap->version = PWC_VERSION_CODE;
690
                    cap->capabilities =
691
                        V4L2_CAP_VIDEO_CAPTURE  |
692
                        V4L2_CAP_STREAMING      |
693
                        V4L2_CAP_READWRITE;
694
                    return 0;
695
                }
696
 
697
                case VIDIOC_ENUMINPUT:
698
                {
699
                    struct v4l2_input *i = arg;
700
 
701
                    if ( i->index )     /* Only one INPUT is supported */
702
                          return -EINVAL;
703
 
704
                    memset(i, 0, sizeof(struct v4l2_input));
705
                    strcpy(i->name, "usb");
706
                    return 0;
707
                }
708
 
709
                case VIDIOC_G_INPUT:
710
                {
711
                    int *i = arg;
712
                    *i = 0;      /* Only one INPUT is supported */
713
                    return 0;
714
                }
715
                case VIDIOC_S_INPUT:
716
                {
717
                        int *i = arg;
718
 
719
                        if ( *i ) {     /* Only one INPUT is supported */
720
                                PWC_DEBUG_IOCTL("Only one input source is"\
721
                                        " supported with this webcam.\n");
722
                                return -EINVAL;
723
                        }
724
                        return 0;
725
                }
726
 
727
                /* TODO: */
728
                case VIDIOC_QUERYCTRL:
729
                {
730
                        struct v4l2_queryctrl *c = arg;
731
                        int i;
732
 
733
                        PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c->id);
734
                        for (i=0; i<sizeof(pwc_controls)/sizeof(struct v4l2_queryctrl); i++) {
735
                                if (pwc_controls[i].id == c->id) {
736
                                        PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
737
                                        memcpy(c,&pwc_controls[i],sizeof(struct v4l2_queryctrl));
738
                                        return 0;
739
                                }
740
                        }
741
                        PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");
742
 
743
                        return -EINVAL;
744
                }
745
                case VIDIOC_G_CTRL:
746
                {
747
                        struct v4l2_control *c = arg;
748
                        int ret;
749
 
750
                        switch (c->id)
751
                        {
752
                                case V4L2_CID_BRIGHTNESS:
753
                                        c->value = pwc_get_brightness(pdev);
754
                                        if (c->value<0)
755
                                                return -EINVAL;
756
                                        return 0;
757
                                case V4L2_CID_CONTRAST:
758
                                        c->value = pwc_get_contrast(pdev);
759
                                        if (c->value<0)
760
                                                return -EINVAL;
761
                                        return 0;
762
                                case V4L2_CID_SATURATION:
763
                                        ret = pwc_get_saturation(pdev, &c->value);
764
                                        if (ret<0)
765
                                                return -EINVAL;
766
                                        return 0;
767
                                case V4L2_CID_GAMMA:
768
                                        c->value = pwc_get_gamma(pdev);
769
                                        if (c->value<0)
770
                                                return -EINVAL;
771
                                        return 0;
772
                                case V4L2_CID_RED_BALANCE:
773
                                        ret = pwc_get_red_gain(pdev, &c->value);
774
                                        if (ret<0)
775
                                                return -EINVAL;
776
                                        c->value >>= 8;
777
                                        return 0;
778
                                case V4L2_CID_BLUE_BALANCE:
779
                                        ret = pwc_get_blue_gain(pdev, &c->value);
780
                                        if (ret<0)
781
                                                return -EINVAL;
782
                                        c->value >>= 8;
783
                                        return 0;
784
                                case V4L2_CID_AUTO_WHITE_BALANCE:
785
                                        ret = pwc_get_awb(pdev);
786
                                        if (ret<0)
787
                                                return -EINVAL;
788
                                        c->value = (ret == PWC_WB_MANUAL)?0:1;
789
                                        return 0;
790
                                case V4L2_CID_GAIN:
791
                                        ret = pwc_get_agc(pdev, &c->value);
792
                                        if (ret<0)
793
                                                return -EINVAL;
794
                                        c->value >>= 8;
795
                                        return 0;
796
                                case V4L2_CID_AUTOGAIN:
797
                                        ret = pwc_get_agc(pdev, &c->value);
798
                                        if (ret<0)
799
                                                return -EINVAL;
800
                                        c->value = (c->value < 0)?1:0;
801
                                        return 0;
802
                                case V4L2_CID_EXPOSURE:
803
                                        ret = pwc_get_shutter_speed(pdev, &c->value);
804
                                        if (ret<0)
805
                                                return -EINVAL;
806
                                        return 0;
807
                                case V4L2_CID_PRIVATE_COLOUR_MODE:
808
                                        ret = pwc_get_colour_mode(pdev, &c->value);
809
                                        if (ret < 0)
810
                                                return -EINVAL;
811
                                        return 0;
812
                                case V4L2_CID_PRIVATE_AUTOCONTOUR:
813
                                        ret = pwc_get_contour(pdev, &c->value);
814
                                        if (ret < 0)
815
                                                return -EINVAL;
816
                                        c->value=(c->value == -1?1:0);
817
                                        return 0;
818
                                case V4L2_CID_PRIVATE_CONTOUR:
819
                                        ret = pwc_get_contour(pdev, &c->value);
820
                                        if (ret < 0)
821
                                                return -EINVAL;
822
                                        c->value >>= 10;
823
                                        return 0;
824
                                case V4L2_CID_PRIVATE_BACKLIGHT:
825
                                        ret = pwc_get_backlight(pdev, &c->value);
826
                                        if (ret < 0)
827
                                                return -EINVAL;
828
                                        return 0;
829
                                case V4L2_CID_PRIVATE_FLICKERLESS:
830
                                        ret = pwc_get_flicker(pdev, &c->value);
831
                                        if (ret < 0)
832
                                                return -EINVAL;
833
                                        c->value=(c->value?1:0);
834
                                        return 0;
835
                                case V4L2_CID_PRIVATE_NOISE_REDUCTION:
836
                                        ret = pwc_get_dynamic_noise(pdev, &c->value);
837
                                        if (ret < 0)
838
                                                return -EINVAL;
839
                                        return 0;
840
 
841
                                case V4L2_CID_PRIVATE_SAVE_USER:
842
                                case V4L2_CID_PRIVATE_RESTORE_USER:
843
                                case V4L2_CID_PRIVATE_RESTORE_FACTORY:
844
                                        return -EINVAL;
845
                        }
846
                        return -EINVAL;
847
                }
848
                case VIDIOC_S_CTRL:
849
                {
850
                        struct v4l2_control *c = arg;
851
                        int ret;
852
 
853
                        switch (c->id)
854
                        {
855
                                case V4L2_CID_BRIGHTNESS:
856
                                        c->value <<= 9;
857
                                        ret = pwc_set_brightness(pdev, c->value);
858
                                        if (ret<0)
859
                                                return -EINVAL;
860
                                        return 0;
861
                                case V4L2_CID_CONTRAST:
862
                                        c->value <<= 10;
863
                                        ret = pwc_set_contrast(pdev, c->value);
864
                                        if (ret<0)
865
                                                return -EINVAL;
866
                                        return 0;
867
                                case V4L2_CID_SATURATION:
868
                                        ret = pwc_set_saturation(pdev, c->value);
869
                                        if (ret<0)
870
                                          return -EINVAL;
871
                                        return 0;
872
                                case V4L2_CID_GAMMA:
873
                                        c->value <<= 11;
874
                                        ret = pwc_set_gamma(pdev, c->value);
875
                                        if (ret<0)
876
                                                return -EINVAL;
877
                                        return 0;
878
                                case V4L2_CID_RED_BALANCE:
879
                                        c->value <<= 8;
880
                                        ret = pwc_set_red_gain(pdev, c->value);
881
                                        if (ret<0)
882
                                                return -EINVAL;
883
                                        return 0;
884
                                case V4L2_CID_BLUE_BALANCE:
885
                                        c->value <<= 8;
886
                                        ret = pwc_set_blue_gain(pdev, c->value);
887
                                        if (ret<0)
888
                                                return -EINVAL;
889
                                        return 0;
890
                                case V4L2_CID_AUTO_WHITE_BALANCE:
891
                                        c->value = (c->value == 0)?PWC_WB_MANUAL:PWC_WB_AUTO;
892
                                        ret = pwc_set_awb(pdev, c->value);
893
                                        if (ret<0)
894
                                                return -EINVAL;
895
                                        return 0;
896
                                case V4L2_CID_EXPOSURE:
897
                                        c->value <<= 8;
898
                                        ret = pwc_set_shutter_speed(pdev, c->value?0:1, c->value);
899
                                        if (ret<0)
900
                                                return -EINVAL;
901
                                        return 0;
902
                                case V4L2_CID_AUTOGAIN:
903
                                        /* autogain off means nothing without a gain */
904
                                        if (c->value == 0)
905
                                                return 0;
906
                                        ret = pwc_set_agc(pdev, c->value, 0);
907
                                        if (ret<0)
908
                                                return -EINVAL;
909
                                        return 0;
910
                                case V4L2_CID_GAIN:
911
                                        c->value <<= 8;
912
                                        ret = pwc_set_agc(pdev, 0, c->value);
913
                                        if (ret<0)
914
                                                return -EINVAL;
915
                                        return 0;
916
                                case V4L2_CID_PRIVATE_SAVE_USER:
917
                                        if (pwc_save_user(pdev))
918
                                                return -EINVAL;
919
                                        return 0;
920
                                case V4L2_CID_PRIVATE_RESTORE_USER:
921
                                        if (pwc_restore_user(pdev))
922
                                                return -EINVAL;
923
                                        return 0;
924
                                case V4L2_CID_PRIVATE_RESTORE_FACTORY:
925
                                        if (pwc_restore_factory(pdev))
926
                                                return -EINVAL;
927
                                        return 0;
928
                                case V4L2_CID_PRIVATE_COLOUR_MODE:
929
                                        ret = pwc_set_colour_mode(pdev, c->value);
930
                                        if (ret < 0)
931
                                          return -EINVAL;
932
                                        return 0;
933
                                case V4L2_CID_PRIVATE_AUTOCONTOUR:
934
                                  c->value=(c->value == 1)?-1:0;
935
                                  ret = pwc_set_contour(pdev, c->value);
936
                                  if (ret < 0)
937
                                    return -EINVAL;
938
                                  return 0;
939
                                case V4L2_CID_PRIVATE_CONTOUR:
940
                                  c->value <<= 10;
941
                                  ret = pwc_set_contour(pdev, c->value);
942
                                  if (ret < 0)
943
                                    return -EINVAL;
944
                                  return 0;
945
                                case V4L2_CID_PRIVATE_BACKLIGHT:
946
                                  ret = pwc_set_backlight(pdev, c->value);
947
                                  if (ret < 0)
948
                                    return -EINVAL;
949
                                  return 0;
950
                                case V4L2_CID_PRIVATE_FLICKERLESS:
951
                                  ret = pwc_set_flicker(pdev, c->value);
952
                                  if (ret < 0)
953
                                    return -EINVAL;
954
                                case V4L2_CID_PRIVATE_NOISE_REDUCTION:
955
                                  ret = pwc_set_dynamic_noise(pdev, c->value);
956
                                  if (ret < 0)
957
                                    return -EINVAL;
958
                                  return 0;
959
 
960
                        }
961
                        return -EINVAL;
962
                }
963
 
964
                case VIDIOC_ENUM_FMT:
965
                {
966
                        struct v4l2_fmtdesc *f = arg;
967
                        int index;
968
 
969
                        if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
970
                              return -EINVAL;
971
 
972
                        /* We only support two format: the raw format, and YUV */
973
                        index = f->index;
974
                        memset(f,0,sizeof(struct v4l2_fmtdesc));
975
                        f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
976
                        f->index = index;
977
                        switch(index)
978
                        {
979
                                case 0:
980
                                        /* RAW format */
981
                                        f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2;
982
                                        f->flags = V4L2_FMT_FLAG_COMPRESSED;
983
                                        strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description));
984
                                        break;
985
                                case 1:
986
                                        f->pixelformat = V4L2_PIX_FMT_YUV420;
987
                                        strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description));
988
                                        break;
989
                                default:
990
                                        return -EINVAL;
991
                        }
992
                        return 0;
993
                }
994
 
995
                case VIDIOC_G_FMT:
996
                {
997
                        struct v4l2_format *f = arg;
998
 
999
                        PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev->image.x,pdev->image.y);
1000
                        if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1001
                              return -EINVAL;
1002
 
1003
                        pwc_vidioc_fill_fmt(pdev, f);
1004
 
1005
                        return 0;
1006
                }
1007
 
1008
                case VIDIOC_TRY_FMT:
1009
                        return pwc_vidioc_try_fmt(pdev, arg);
1010
 
1011
                case VIDIOC_S_FMT:
1012
                        return pwc_vidioc_set_fmt(pdev, arg);
1013
 
1014
                case VIDIOC_G_STD:
1015
                {
1016
                        v4l2_std_id *std = arg;
1017
                        *std = V4L2_STD_UNKNOWN;
1018
                        return 0;
1019
                }
1020
 
1021
                case VIDIOC_S_STD:
1022
                {
1023
                        v4l2_std_id *std = arg;
1024
                        if (*std != V4L2_STD_UNKNOWN)
1025
                                return -EINVAL;
1026
                        return 0;
1027
                }
1028
 
1029
                case VIDIOC_ENUMSTD:
1030
                {
1031
                        struct v4l2_standard *std = arg;
1032
                        if (std->index != 0)
1033
                                return -EINVAL;
1034
                        std->id = V4L2_STD_UNKNOWN;
1035
                        strncpy(std->name, "webcam", sizeof(std->name));
1036
                        return 0;
1037
                }
1038
 
1039
                case VIDIOC_REQBUFS:
1040
                {
1041
                        struct v4l2_requestbuffers *rb = arg;
1042
                        int nbuffers;
1043
 
1044
                        PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb->count);
1045
                        if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1046
                                return -EINVAL;
1047
                        if (rb->memory != V4L2_MEMORY_MMAP)
1048
                                return -EINVAL;
1049
 
1050
                        nbuffers = rb->count;
1051
                        if (nbuffers < 2)
1052
                                nbuffers = 2;
1053
                        else if (nbuffers > pwc_mbufs)
1054
                                nbuffers = pwc_mbufs;
1055
                        /* Force to use our # of buffers */
1056
                        rb->count = pwc_mbufs;
1057
                        return 0;
1058
                }
1059
 
1060
                case VIDIOC_QUERYBUF:
1061
                {
1062
                        struct v4l2_buffer *buf = arg;
1063
                        int index;
1064
 
1065
                        PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf->index);
1066
                        if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1067
                                PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
1068
                                return -EINVAL;
1069
                        }
1070
                        if (buf->memory != V4L2_MEMORY_MMAP) {
1071
                                PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
1072
                                return -EINVAL;
1073
                        }
1074
                        index = buf->index;
1075
                        if (index < 0 || index >= pwc_mbufs) {
1076
                                PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
1077
                                return -EINVAL;
1078
                        }
1079
 
1080
                        memset(buf, 0, sizeof(struct v4l2_buffer));
1081
                        buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1082
                        buf->index = index;
1083
                        buf->m.offset = index * pdev->len_per_image;
1084
                        if (pdev->vpalette == VIDEO_PALETTE_RAW)
1085
                                buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
1086
                        else
1087
                                buf->bytesused = pdev->view.size;
1088
                        buf->field = V4L2_FIELD_NONE;
1089
                        buf->memory = V4L2_MEMORY_MMAP;
1090
                        //buf->flags = V4L2_BUF_FLAG_MAPPED;
1091
                        buf->length = pdev->len_per_image;
1092
 
1093
                        PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf->index);
1094
                        PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf->m.offset);
1095
                        PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf->bytesused);
1096
 
1097
                        return 0;
1098
                }
1099
 
1100
                case VIDIOC_QBUF:
1101
                {
1102
                        struct v4l2_buffer *buf = arg;
1103
 
1104
                        PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf->index);
1105
                        if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1106
                                return -EINVAL;
1107
                        if (buf->memory != V4L2_MEMORY_MMAP)
1108
                                return -EINVAL;
1109
                        if (buf->index < 0 || buf->index >= pwc_mbufs)
1110
                                return -EINVAL;
1111
 
1112
                        buf->flags |= V4L2_BUF_FLAG_QUEUED;
1113
                        buf->flags &= ~V4L2_BUF_FLAG_DONE;
1114
 
1115
                        return 0;
1116
                }
1117
 
1118
                case VIDIOC_DQBUF:
1119
                {
1120
                        struct v4l2_buffer *buf = arg;
1121
                        int ret;
1122
 
1123
                        PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
1124
 
1125
                        if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1126
                                return -EINVAL;
1127
 
1128
                        /* Add ourselves to the frame wait-queue.
1129
 
1130
                           FIXME: needs auditing for safety.
1131
                           QUESTION: In what respect? I think that using the
1132
                                     frameq is safe now.
1133
                         */
1134
                        add_wait_queue(&pdev->frameq, &wait);
1135
                        while (pdev->full_frames == NULL) {
1136
                                if (pdev->error_status) {
1137
                                        remove_wait_queue(&pdev->frameq, &wait);
1138
                                        set_current_state(TASK_RUNNING);
1139
                                        return -pdev->error_status;
1140
                                }
1141
 
1142
                                if (signal_pending(current)) {
1143
                                        remove_wait_queue(&pdev->frameq, &wait);
1144
                                        set_current_state(TASK_RUNNING);
1145
                                        return -ERESTARTSYS;
1146
                                }
1147
                                schedule();
1148
                                set_current_state(TASK_INTERRUPTIBLE);
1149
                        }
1150
                        remove_wait_queue(&pdev->frameq, &wait);
1151
                        set_current_state(TASK_RUNNING);
1152
 
1153
                        PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
1154
                        /* Decompress data in pdev->images[pdev->fill_image] */
1155
                        ret = pwc_handle_frame(pdev);
1156
                        if (ret)
1157
                                return -EFAULT;
1158
                        PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
1159
 
1160
                        buf->index = pdev->fill_image;
1161
                        if (pdev->vpalette == VIDEO_PALETTE_RAW)
1162
                                buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
1163
                        else
1164
                                buf->bytesused = pdev->view.size;
1165
                        buf->flags = V4L2_BUF_FLAG_MAPPED;
1166
                        buf->field = V4L2_FIELD_NONE;
1167
                        do_gettimeofday(&buf->timestamp);
1168
                        buf->sequence = 0;
1169
                        buf->memory = V4L2_MEMORY_MMAP;
1170
                        buf->m.offset = pdev->fill_image * pdev->len_per_image;
1171
                        buf->length = pdev->len_per_image;
1172
                        pwc_next_image(pdev);
1173
 
1174
                        PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index);
1175
                        PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf->length);
1176
                        PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf->m.offset);
1177
                        PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf->bytesused);
1178
                        PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
1179
                        return 0;
1180
 
1181
                }
1182
 
1183
                case VIDIOC_STREAMON:
1184
                {
1185
                        /* WARNING: pwc_try_video_mode() called pwc_isoc_init */
1186
                        pwc_isoc_init(pdev);
1187
                        return 0;
1188
                }
1189
 
1190
                case VIDIOC_STREAMOFF:
1191
                {
1192
                        pwc_isoc_cleanup(pdev);
1193
                        return 0;
1194
                }
1195
 
1196
                case VIDIOC_ENUM_FRAMESIZES:
1197
                {
1198
                        struct v4l2_frmsizeenum *fsize = arg;
1199
                        unsigned int i = 0, index = fsize->index;
1200
 
1201
                        if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) {
1202
                                for (i = 0; i < PSZ_MAX; i++) {
1203
                                        if (pdev->image_mask & (1UL << i)) {
1204
                                                if (!index--) {
1205
                                                        fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1206
                                                        fsize->discrete.width = pwc_image_sizes[i].x;
1207
                                                        fsize->discrete.height = pwc_image_sizes[i].y;
1208
                                                        return 0;
1209
                                                }
1210
                                        }
1211
                                }
1212
                        } else if (fsize->index == 0 &&
1213
                                   ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) ||
1214
                                    (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) {
1215
 
1216
                                fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1217
                                fsize->discrete.width = pdev->abs_max.x;
1218
                                fsize->discrete.height = pdev->abs_max.y;
1219
                                return 0;
1220
                        }
1221
                        return -EINVAL;
1222
                }
1223
 
1224
                case VIDIOC_ENUM_FRAMEINTERVALS:
1225
                {
1226
                        struct v4l2_frmivalenum *fival = arg;
1227
                        int size = -1;
1228
                        unsigned int i;
1229
 
1230
                        for (i = 0; i < PSZ_MAX; i++) {
1231
                                if (pwc_image_sizes[i].x == fival->width &&
1232
                                    pwc_image_sizes[i].y == fival->height) {
1233
                                        size = i;
1234
                                        break;
1235
                                }
1236
                        }
1237
 
1238
                        /* TODO: Support raw format */
1239
                        if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) {
1240
                                return -EINVAL;
1241
                        }
1242
 
1243
                        i = pwc_get_fps(pdev, fival->index, size);
1244
                        if (!i)
1245
                                return -EINVAL;
1246
 
1247
                        fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
1248
                        fival->discrete.numerator = 1;
1249
                        fival->discrete.denominator = i;
1250
 
1251
                        return 0;
1252
                }
1253
 
1254
                default:
1255
                        return pwc_ioctl(pdev, cmd, arg);
1256
        } /* ..switch */
1257
        return 0;
1258
}
1259
 
1260
/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.