commented early_printk patch because of rejects.
[linux-flexiantxendom0-3.2.10.git] / drivers / usb / media / pwc-ctrl.c
1 /* Driver for Philips webcam
2    Functions that send various control messages to the webcam, including
3    video modes.
4    (C) 1999-2003 Nemosoft Unv. (webcam@smcc.demon.nl)
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 /*
22    Changes
23    2001/08/03  Alvarado   Added methods for changing white balance and 
24                           red/green gains
25  */
26
27 /* Control functions for the cam; brightness, contrast, video mode, etc. */
28
29 #ifdef __KERNEL__
30 #include <asm/uaccess.h> 
31 #endif
32 #include <asm/errno.h>
33  
34 #include "pwc.h"
35 #include "pwc-ioctl.h"
36 #include "pwc-uncompress.h"
37
38 /* Request types: video */
39 #define SET_LUM_CTL                     0x01
40 #define GET_LUM_CTL                     0x02
41 #define SET_CHROM_CTL                   0x03
42 #define GET_CHROM_CTL                   0x04
43 #define SET_STATUS_CTL                  0x05
44 #define GET_STATUS_CTL                  0x06
45 #define SET_EP_STREAM_CTL               0x07
46 #define GET_EP_STREAM_CTL               0x08
47
48 /* Selectors for the Luminance controls [GS]ET_LUM_CTL */
49 #define AGC_MODE_FORMATTER                      0x2000
50 #define PRESET_AGC_FORMATTER                    0x2100
51 #define SHUTTER_MODE_FORMATTER                  0x2200
52 #define PRESET_SHUTTER_FORMATTER                0x2300
53 #define PRESET_CONTOUR_FORMATTER                0x2400
54 #define AUTO_CONTOUR_FORMATTER                  0x2500
55 #define BACK_LIGHT_COMPENSATION_FORMATTER       0x2600
56 #define CONTRAST_FORMATTER                      0x2700
57 #define DYNAMIC_NOISE_CONTROL_FORMATTER         0x2800
58 #define FLICKERLESS_MODE_FORMATTER              0x2900
59 #define AE_CONTROL_SPEED                        0x2A00
60 #define BRIGHTNESS_FORMATTER                    0x2B00
61 #define GAMMA_FORMATTER                         0x2C00
62
63 /* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */
64 #define WB_MODE_FORMATTER                       0x1000
65 #define AWB_CONTROL_SPEED_FORMATTER             0x1100
66 #define AWB_CONTROL_DELAY_FORMATTER             0x1200
67 #define PRESET_MANUAL_RED_GAIN_FORMATTER        0x1300
68 #define PRESET_MANUAL_BLUE_GAIN_FORMATTER       0x1400
69 #define COLOUR_MODE_FORMATTER                   0x1500
70 #define SATURATION_MODE_FORMATTER1              0x1600
71 #define SATURATION_MODE_FORMATTER2              0x1700
72
73 /* Selectors for the Status controls [GS]ET_STATUS_CTL */
74 #define SAVE_USER_DEFAULTS_FORMATTER            0x0200
75 #define RESTORE_USER_DEFAULTS_FORMATTER         0x0300
76 #define RESTORE_FACTORY_DEFAULTS_FORMATTER      0x0400
77 #define READ_AGC_FORMATTER                      0x0500
78 #define READ_SHUTTER_FORMATTER                  0x0600
79 #define READ_RED_GAIN_FORMATTER                 0x0700
80 #define READ_BLUE_GAIN_FORMATTER                0x0800
81 #define SENSOR_TYPE_FORMATTER1                  0x0C00
82 #define READ_RAW_Y_MEAN_FORMATTER               0x3100
83 #define SET_POWER_SAVE_MODE_FORMATTER           0x3200
84 #define MIRROR_IMAGE_FORMATTER                  0x3300
85 #define LED_FORMATTER                           0x3400
86 #define SENSOR_TYPE_FORMATTER2                  0x3700
87
88 /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
89 #define VIDEO_OUTPUT_CONTROL_FORMATTER          0x0100
90
91 static char *size2name[PSZ_MAX] =
92 {
93         "subQCIF",
94         "QSIF",
95         "QCIF",
96         "SIF",
97         "CIF",
98         "VGA",
99 };  
100
101 /********/
102
103 /* Entries for the Nala (645/646) camera; the Nala doesn't have compression 
104    preferences, so you either get compressed or non-compressed streams.
105    
106    An alternate value of 0 means this mode is not available at all.
107  */
108
109 struct Nala_table_entry {
110         char alternate;                 /* USB alternate setting */
111         int compressed;                 /* Compressed yes/no */
112
113         unsigned char mode[3];          /* precomputed mode table */
114 };
115
116 static struct Nala_table_entry Nala_table[PSZ_MAX][8] =
117 {
118 #include "pwc_nala.h"
119 };
120
121 /* This tables contains entries for the 675/680/690 (Timon) camera, with
122    4 different qualities (no compression, low, medium, high).
123    It lists the bandwidth requirements for said mode by its alternate interface 
124    number. An alternate of 0 means that the mode is unavailable.
125    
126    There are 6 * 4 * 4 entries: 
127      6 different resolutions subqcif, qsif, qcif, sif, cif, vga
128      6 framerates: 5, 10, 15, 20, 25, 30
129      4 compression modi: none, low, medium, high
130      
131    When an uncompressed mode is not available, the next available compressed mode 
132    will be chosen (unless the decompressor is absent). Sometimes there are only
133    1 or 2 compressed modes available; in that case entries are duplicated.
134 */
135 struct Timon_table_entry 
136 {
137         char alternate;                 /* USB alternate interface */
138         unsigned short packetsize;      /* Normal packet size */
139         unsigned short bandlength;      /* Bandlength when decompressing */
140         unsigned char mode[13];         /* precomputed mode settings for cam */
141 };
142
143 static struct Timon_table_entry Timon_table[PSZ_MAX][6][4] = 
144 {
145 #include "pwc_timon.h"
146 };
147
148 /* Entries for the Kiara (730/740/750) camera */
149
150 struct Kiara_table_entry
151 {
152         char alternate;                 /* USB alternate interface */
153         unsigned short packetsize;      /* Normal packet size */
154         unsigned short bandlength;      /* Bandlength when decompressing */
155         unsigned char mode[12];         /* precomputed mode settings for cam */
156 };
157
158 static struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] =
159 {
160 #include "pwc_kiara.h"
161 };
162
163
164 /****************************************************************************/
165
166
167 #define SendControlMsg(request, value, buflen) \
168         usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \
169                 request, \
170                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
171                 value, \
172                 pdev->vcinterface, \
173                 &buf, buflen, HZ / 2)
174
175 #define RecvControlMsg(request, value, buflen) \
176         usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \
177                 request, \
178                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
179                 value, \
180                 pdev->vcinterface, \
181                 &buf, buflen, HZ / 2)
182
183
184 #if PWC_DEBUG
185 void pwc_hexdump(void *p, int len)
186 {
187         int i;
188         unsigned char *s;
189         char buf[100], *d;
190         
191         s = (unsigned char *)p;
192         d = buf;
193         *d = '\0';
194         Debug("Doing hexdump @ %p, %d bytes.\n", p, len);
195         for (i = 0; i < len; i++) {
196                 d += sprintf(d, "%02X ", *s++);
197                 if ((i & 0xF) == 0xF) {
198                         Debug("%s\n", buf);
199                         d = buf;
200                         *d = '\0';
201                 }
202         }
203         if ((i & 0xF) != 0)
204                 Debug("%s\n", buf);
205 }
206 #endif
207
208 static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen)
209 {
210         return usb_control_msg(udev,
211                 usb_sndctrlpipe(udev, 0),
212                 SET_EP_STREAM_CTL,
213                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
214                 VIDEO_OUTPUT_CONTROL_FORMATTER,
215                 index,
216                 buf, buflen, HZ);
217 }
218
219
220
221 static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
222 {
223         unsigned char buf[3];
224         int ret, fps;
225         struct Nala_table_entry *pEntry;
226         int frames2frames[31] = 
227         { /* closest match of framerate */
228            0,  0,  0,  0,  4,  /*  0-4  */
229            5,  5,  7,  7, 10,  /*  5-9  */
230           10, 10, 12, 12, 15,  /* 10-14 */
231           15, 15, 15, 20, 20,  /* 15-19 */
232           20, 20, 20, 24, 24,  /* 20-24 */
233           24, 24, 24, 24, 24,  /* 25-29 */
234           24                   /* 30    */
235         };
236         int frames2table[31] = 
237         { 0, 0, 0, 0, 0, /*  0-4  */
238           1, 1, 1, 2, 2, /*  5-9  */
239           3, 3, 4, 4, 4, /* 10-14 */
240           5, 5, 5, 5, 5, /* 15-19 */
241           6, 6, 6, 6, 7, /* 20-24 */
242           7, 7, 7, 7, 7, /* 25-29 */
243           7              /* 30    */
244         };
245         
246         if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25)
247                 return -EINVAL;
248         frames = frames2frames[frames];
249         fps = frames2table[frames];
250         pEntry = &Nala_table[size][fps];
251         if (pEntry->alternate == 0)
252                 return -EINVAL;
253
254         if (pEntry->compressed && pdev->decompressor == NULL)
255                 return -ENOENT; /* Not supported. */
256
257         memcpy(buf, pEntry->mode, 3);   
258         ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3);
259         if (ret < 0) {
260                 Debug("Failed to send video command... %d\n", ret);
261                 return ret;
262         }
263         if (pEntry->compressed && pdev->decompressor != NULL)
264                 pdev->decompressor->init(pdev->release, buf, pdev->decompress_data);
265                 
266         /* Set various parameters */
267         pdev->vframes = frames;
268         pdev->vsize = size;
269         pdev->valternate = pEntry->alternate;
270         pdev->image = pwc_image_sizes[size];
271         pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2;
272         if (pEntry->compressed) {
273                 if (pdev->release < 5) { /* 4 fold compression */
274                         pdev->vbandlength = 528;
275                         pdev->frame_size /= 4;
276                 }
277                 else {
278                         pdev->vbandlength = 704;
279                         pdev->frame_size /= 3;
280                 }
281         }
282         else
283                 pdev->vbandlength = 0;
284         return 0;
285 }
286
287
288 static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
289 {
290         unsigned char buf[13];
291         struct Timon_table_entry *pChoose;
292         int ret, fps;
293
294         if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
295                 return -EINVAL;
296         if (size == PSZ_VGA && frames > 15)
297                 return -EINVAL;
298         fps = (frames / 5) - 1;
299         
300         /* Find a supported framerate with progressively higher compression ratios
301            if the preferred ratio is not available.
302         */
303         pChoose = NULL;
304         if (pdev->decompressor == NULL) {
305 #if PWC_DEBUG   
306                 Debug("Trying to find uncompressed mode.\n");
307 #endif
308                 pChoose = &Timon_table[size][fps][0];
309         }
310         else {
311                 while (compression <= 3) {
312                         pChoose = &Timon_table[size][fps][compression];
313                         if (pChoose->alternate != 0)
314                                 break;
315                         compression++;  
316                 }
317         }
318         if (pChoose == NULL || pChoose->alternate == 0)
319                 return -ENOENT; /* Not supported. */
320
321         memcpy(buf, pChoose->mode, 13);
322         if (snapshot)
323                 buf[0] |= 0x80;
324         ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 13);
325         if (ret < 0)
326                 return ret;
327
328         if (pChoose->bandlength > 0)
329                 pdev->decompressor->init(pdev->release, buf, pdev->decompress_data);
330         
331         /* Set various parameters */
332         pdev->vframes = frames;
333         pdev->vsize = size;
334         pdev->vsnapshot = snapshot;
335         pdev->valternate = pChoose->alternate;
336         pdev->image = pwc_image_sizes[size];
337         pdev->vbandlength = pChoose->bandlength;
338         if (pChoose->bandlength > 0) 
339                 pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4;
340         else
341                 pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
342         return 0;
343 }
344
345
346 static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
347 {
348         struct Kiara_table_entry *pChoose;
349         int fps, ret;
350         unsigned char buf[12];
351         
352         if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
353                 return -EINVAL;
354         if (size == PSZ_VGA && frames > 15)
355                 return -EINVAL;
356         fps = (frames / 5) - 1;
357         
358         /* Find a supported framerate with progressively higher compression ratios
359            if the preferred ratio is not available.
360         */
361         pChoose = NULL;
362         if (pdev->decompressor == NULL) {
363 #if PWC_DEBUG   
364                 Debug("Trying to find uncompressed mode.\n");
365 #endif          
366                 pChoose = &Kiara_table[size][fps][0];
367         }
368         else {
369                 while (compression <= 3) {
370                         pChoose = &Kiara_table[size][fps][compression];
371                         if (pChoose->alternate != 0)
372                                 break;
373                         compression++;  
374                 }
375         }
376         if (pChoose == NULL || pChoose->alternate == 0)
377                 return -ENOENT; /* Not supported. */
378
379         /* usb_control_msg won't take staticly allocated arrays as argument?? */
380         memcpy(buf, pChoose->mode, 12);
381         if (snapshot)
382                 buf[0] |= 0x80;
383
384         /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */
385         ret = send_video_command(pdev->udev, 4 /* pdev->vendpoint */, buf, 12);
386         if (ret < 0)
387                 return ret;
388
389         if (pChoose->bandlength > 0)
390                 pdev->decompressor->init(pdev->release, buf, pdev->decompress_data);
391                 
392         /* All set and go */
393         pdev->vframes = frames;
394         pdev->vsize = size;
395         pdev->vsnapshot = snapshot;
396         pdev->valternate = pChoose->alternate;
397         pdev->image = pwc_image_sizes[size];
398         pdev->vbandlength = pChoose->bandlength;
399         if (pChoose->bandlength > 0)
400                 pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4;
401         else 
402                 pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
403         pdev->frame_size += (pdev->frame_header_size + pdev->frame_trailer_size);
404         return 0;
405 }
406
407
408 /**
409    @pdev: device structure
410    @width: viewport width
411    @height: viewport height
412    @frame: framerate, in fps
413    @compression: preferred compression ratio
414    @snapshot: snapshot mode or streaming
415  */
416 int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot)
417 {
418         int ret, size;
419         
420         size = pwc_decode_size(pdev, width, height);
421         if (size < 0) {
422                 Debug("Could not find suitable size.\n");
423                 return -ERANGE;
424         }
425         ret = -EINVAL;  
426         switch(pdev->type) {
427         case 645:
428         case 646:
429                 ret = set_video_mode_Nala(pdev, size, frames);
430                 break;
431
432         case 675:
433         case 680:
434         case 690:
435                 ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
436                 break;
437                 
438         case 730:
439         case 740:
440         case 750:
441                 ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot);
442                 break;
443         }
444         if (ret < 0) {
445                 if (ret == -ENOENT)
446                         Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames);
447                 else {
448                         Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
449                 }
450                 return ret;
451         }
452         pdev->view.x = width;
453         pdev->view.y = height;
454         pwc_set_image_buffer_size(pdev);
455         Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
456         return 0;
457 }
458
459
460 void pwc_set_image_buffer_size(struct pwc_device *pdev)
461 {
462         int factor, i, filler = 0;
463
464         factor = 6;
465         filler = 128;
466
467         /* Set sizes in bytes */
468         pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
469         pdev->view.size  = pdev->view.x  * pdev->view.y  * factor / 4;
470
471         /* Align offset, or you'll get some very weird results in
472            YUV420 mode... x must be multiple of 4 (to get the Y's in 
473            place), and y even (or you'll mixup U & V). This is less of a
474            problem for YUV420P.
475          */
476         pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
477         pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
478         
479         /* Fill buffers with gray or black */
480         for (i = 0; i < MAX_IMAGES; i++) {
481                 if (pdev->image_ptr[i] != NULL)
482                         memset(pdev->image_ptr[i], filler, pdev->view.size);
483         }
484 }
485
486
487
488 /* BRIGHTNESS */
489
490 int pwc_get_brightness(struct pwc_device *pdev)
491 {
492         char buf;
493         int ret;
494         
495         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
496                 GET_LUM_CTL,
497                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
498                 BRIGHTNESS_FORMATTER,
499                 pdev->vcinterface,
500                 &buf, 1, HZ / 2);
501         if (ret < 0)
502                 return ret;
503         return buf << 9;
504 }
505
506 int pwc_set_brightness(struct pwc_device *pdev, int value)
507 {
508         char buf;
509
510         if (value < 0)
511                 value = 0;
512         if (value > 0xffff)
513                 value = 0xffff;
514         buf = (value >> 9) & 0x7f;
515         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
516                 SET_LUM_CTL,
517                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
518                 BRIGHTNESS_FORMATTER,
519                 pdev->vcinterface,
520                 &buf, 1, HZ / 2);
521 }
522
523 /* CONTRAST */
524
525 int pwc_get_contrast(struct pwc_device *pdev)
526 {
527         char buf;
528         int ret;
529         
530         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
531                 GET_LUM_CTL,
532                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
533                 CONTRAST_FORMATTER,
534                 pdev->vcinterface,
535                 &buf, 1, HZ / 2);
536         if (ret < 0)
537                 return ret;
538         return buf << 10;
539 }
540
541 int pwc_set_contrast(struct pwc_device *pdev, int value)
542 {
543         char buf;
544
545         if (value < 0)
546                 value = 0;
547         if (value > 0xffff)
548                 value = 0xffff;
549         buf = (value >> 10) & 0x3f;
550         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
551                 SET_LUM_CTL,
552                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
553                 CONTRAST_FORMATTER,
554                 pdev->vcinterface,
555                 &buf, 1, HZ / 2);
556 }
557
558 /* GAMMA */
559
560 int pwc_get_gamma(struct pwc_device *pdev)
561 {
562         char buf;
563         int ret;
564         
565         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
566                 GET_LUM_CTL,
567                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
568                 GAMMA_FORMATTER,
569                 pdev->vcinterface,
570                 &buf, 1, HZ / 2);
571         if (ret < 0)
572                 return ret;
573         return buf << 11;
574 }
575
576 int pwc_set_gamma(struct pwc_device *pdev, int value)
577 {
578         char buf;
579
580         if (value < 0)
581                 value = 0;
582         if (value > 0xffff)
583                 value = 0xffff;
584         buf = (value >> 11) & 0x1f;
585         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
586                 SET_LUM_CTL,
587                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
588                 GAMMA_FORMATTER,
589                 pdev->vcinterface,
590                 &buf, 1, HZ / 2);
591 }
592
593
594 /* SATURATION */
595
596 int pwc_get_saturation(struct pwc_device *pdev)
597 {
598         char buf;
599         int ret;
600
601         if (pdev->type < 675)
602                 return -1;
603         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
604                 GET_CHROM_CTL,
605                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
606                 pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1,
607                 pdev->vcinterface,
608                 &buf, 1, HZ / 2);
609         if (ret < 0)
610                 return ret;
611         return 32768 + buf * 327;
612 }
613
614 int pwc_set_saturation(struct pwc_device *pdev, int value)
615 {
616         char buf;
617
618         if (pdev->type < 675)
619                 return -EINVAL;
620         if (value < 0)
621                 value = 0;
622         if (value > 0xffff)
623                 value = 0xffff;
624         /* saturation ranges from -100 to +100 */
625         buf = (value - 32768) / 327;
626         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
627                 SET_CHROM_CTL,
628                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
629                 pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1,
630                 pdev->vcinterface,
631                 &buf, 1, HZ / 2);
632 }
633
634 /* AGC */
635
636 static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
637 {
638         char buf;
639         int ret;
640         
641         if (mode)
642                 buf = 0x0; /* auto */
643         else
644                 buf = 0xff; /* fixed */
645
646         ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
647                 SET_LUM_CTL,
648                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
649                 AGC_MODE_FORMATTER,
650                 pdev->vcinterface,
651                 &buf, 1, HZ / 2);
652         
653         if (!mode && ret >= 0) {
654                 if (value < 0)
655                         value = 0;
656                 if (value > 0xffff)
657                         value = 0xffff;
658                 buf = (value >> 10) & 0x3F;
659                 ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
660                         SET_LUM_CTL,
661                         USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
662                         PRESET_AGC_FORMATTER,
663                         pdev->vcinterface,
664                         &buf, 1, HZ / 2);
665         }
666         if (ret < 0)
667                 return ret;
668         return 0;
669 }
670
671 static inline int pwc_get_agc(struct pwc_device *pdev, int *value)
672 {
673         unsigned char buf;
674         int ret;
675         
676         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
677                 GET_LUM_CTL,
678                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
679                 AGC_MODE_FORMATTER,
680                 pdev->vcinterface,
681                 &buf, 1, HZ / 2);
682         if (ret < 0)
683                 return ret;
684
685         if (buf != 0) { /* fixed */
686                 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
687                         GET_LUM_CTL,
688                         USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
689                         PRESET_AGC_FORMATTER,
690                         pdev->vcinterface,
691                         &buf, 1, HZ / 2);
692                 if (ret < 0)
693                         return ret;
694                 if (buf > 0x3F)
695                         buf = 0x3F;
696                 *value = (buf << 10);           
697         }
698         else { /* auto */
699                 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
700                         GET_STATUS_CTL,
701                         USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
702                         READ_AGC_FORMATTER,
703                         pdev->vcinterface,
704                         &buf, 1, HZ / 2);
705                 if (ret < 0)
706                         return ret;
707                 /* Gah... this value ranges from 0x00 ... 0x9F */
708                 if (buf > 0x9F)
709                         buf = 0x9F;
710                 *value = -(48 + buf * 409);
711         }
712
713         return 0;
714 }
715
716 static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
717 {
718         char buf[2];
719         int speed, ret;
720
721
722         if (mode)
723                 buf[0] = 0x0;   /* auto */
724         else
725                 buf[0] = 0xff; /* fixed */
726         
727         ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
728                 SET_LUM_CTL,
729                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
730                 SHUTTER_MODE_FORMATTER,
731                 pdev->vcinterface,
732                 buf, 1, HZ / 2);
733
734         if (!mode && ret >= 0) {
735                 if (value < 0)
736                         value = 0;
737                 if (value > 0xffff)
738                         value = 0xffff;
739                 switch(pdev->type) {
740                 case 675:
741                 case 680:
742                 case 690:
743                         /* speed ranges from 0x0 to 0x290 (656) */
744                         speed = (value / 100);
745                         buf[1] = speed >> 8;
746                         buf[0] = speed & 0xff;
747                         break;
748                 case 730:
749                 case 740:
750                 case 750:
751                         /* speed seems to range from 0x0 to 0xff */
752                         buf[1] = 0;
753                         buf[0] = value >> 8;
754                         break;
755                 }
756
757                 ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
758                         SET_LUM_CTL,
759                         USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
760                         PRESET_SHUTTER_FORMATTER,
761                         pdev->vcinterface,
762                         &buf, 2, HZ / 2);
763         }
764         return ret;
765 }       
766
767
768 /* POWER */
769
770 int pwc_camera_power(struct pwc_device *pdev, int power)
771 {
772         char buf;
773
774         if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6))
775                 return 0;       /* Not supported by Nala or Timon < release 6 */
776
777         if (power)
778                 buf = 0x00; /* active */
779         else
780                 buf = 0xFF; /* power save */
781         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
782                 SET_STATUS_CTL,
783                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
784                 SET_POWER_SAVE_MODE_FORMATTER,
785                 pdev->vcinterface,
786                 &buf, 1, HZ / 2);
787 }
788
789
790
791 /* private calls */
792
793 static inline int pwc_restore_user(struct pwc_device *pdev)
794 {
795         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
796                 SET_STATUS_CTL,
797                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
798                 RESTORE_USER_DEFAULTS_FORMATTER,
799                 pdev->vcinterface,
800                 NULL, 0, HZ / 2);
801 }
802
803 static inline int pwc_save_user(struct pwc_device *pdev)
804 {
805         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
806                 SET_STATUS_CTL,
807                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
808                 SAVE_USER_DEFAULTS_FORMATTER,
809                 pdev->vcinterface,
810                 NULL, 0, HZ / 2);
811 }
812
813 static inline int pwc_restore_factory(struct pwc_device *pdev)
814 {
815         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
816                 SET_STATUS_CTL,
817                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
818                 RESTORE_FACTORY_DEFAULTS_FORMATTER,
819                 pdev->vcinterface,
820                 NULL, 0, HZ / 2);
821 }
822
823  /* ************************************************* */
824  /* Patch by Alvarado: (not in the original version   */
825
826  /*
827   * the camera recognizes modes from 0 to 4:
828   *
829   * 00: indoor (incandescant lighting)
830   * 01: outdoor (sunlight)
831   * 02: fluorescent lighting
832   * 03: manual
833   * 04: auto
834   */ 
835 static inline int pwc_set_awb(struct pwc_device *pdev, int mode)
836 {
837         char buf;
838         int ret;
839         
840         if (mode < 0)
841             mode = 0;
842         
843         if (mode > 4)
844             mode = 4;
845         
846         buf = mode & 0x07; /* just the lowest three bits */
847         
848         ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
849                 SET_CHROM_CTL,
850                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
851                 WB_MODE_FORMATTER,
852                 pdev->vcinterface,
853                 &buf, 1, HZ / 2);
854         
855         if (ret < 0)
856                 return ret;
857         return 0;
858 }
859
860 static inline int pwc_get_awb(struct pwc_device *pdev)
861 {
862         unsigned char buf;
863         int ret;
864         
865         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
866                 GET_CHROM_CTL,
867                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
868                 WB_MODE_FORMATTER,
869                 pdev->vcinterface,
870                 &buf, 1, HZ / 2);
871
872         if (ret < 0) 
873                 return ret;
874         return buf;
875 }
876
877 static inline int pwc_set_red_gain(struct pwc_device *pdev, int value)
878 {
879         unsigned char buf;
880
881         if (value < 0)
882                 value = 0;
883         if (value > 0xffff)
884                 value = 0xffff;
885
886         /* only the msb are considered */
887         buf = value >> 8;
888
889         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
890                 SET_CHROM_CTL,
891                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
892                 PRESET_MANUAL_RED_GAIN_FORMATTER,
893                 pdev->vcinterface,
894                 &buf, 1, HZ / 2);
895 }
896
897 static inline int pwc_get_red_gain(struct pwc_device *pdev)
898 {
899         unsigned char buf;
900         int ret;
901         
902         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
903                 GET_CHROM_CTL, 
904                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
905                 PRESET_MANUAL_RED_GAIN_FORMATTER,
906                 pdev->vcinterface,
907                 &buf, 1, HZ / 2);
908
909         if (ret < 0)
910             return ret;
911         
912         return (buf << 8);
913 }
914
915
916 static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value)
917 {
918         unsigned char buf;
919
920         if (value < 0)
921                 value = 0;
922         if (value > 0xffff)
923                 value = 0xffff;
924
925         /* linear mapping of 0..0xffff to -0x80..0x7f */
926         buf = (value >> 8);
927
928         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
929                 SET_CHROM_CTL,
930                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
931                 PRESET_MANUAL_BLUE_GAIN_FORMATTER,
932                 pdev->vcinterface,
933                 &buf, 1, HZ / 2);
934 }
935
936 static inline int pwc_get_blue_gain(struct pwc_device *pdev)
937 {
938         unsigned char buf;
939         int ret;
940         
941         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
942                 GET_CHROM_CTL,
943                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
944                 PRESET_MANUAL_BLUE_GAIN_FORMATTER,
945                 pdev->vcinterface,
946                 &buf, 1, HZ / 2);
947
948         if (ret < 0)
949             return ret;
950         
951         return (buf << 8);
952 }
953
954
955 /* The following two functions are different, since they only read the
956    internal red/blue gains, which may be different from the manual 
957    gains set or read above.
958  */   
959 static inline int pwc_read_red_gain(struct pwc_device *pdev)
960 {
961         unsigned char buf;
962         int ret;
963         
964         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
965                 GET_STATUS_CTL, 
966                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
967                 READ_RED_GAIN_FORMATTER,
968                 pdev->vcinterface,
969                 &buf, 1, HZ / 2);
970
971         if (ret < 0)
972                 return ret;
973         
974         return (buf << 8);
975 }
976
977 static inline int pwc_read_blue_gain(struct pwc_device *pdev)
978 {
979         unsigned char buf;
980         int ret;
981         
982         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
983                 GET_STATUS_CTL,
984                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
985                 READ_BLUE_GAIN_FORMATTER,
986                 pdev->vcinterface,
987                 &buf, 1, HZ / 2);
988
989         if (ret < 0)
990                 return ret;
991         
992         return (buf << 8);
993 }
994
995
996 static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
997 {
998         unsigned char buf;
999         
1000         /* useful range is 0x01..0x20 */
1001         buf = speed / 0x7f0;
1002         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
1003                 SET_CHROM_CTL,
1004                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1005                 AWB_CONTROL_SPEED_FORMATTER,
1006                 pdev->vcinterface,
1007                 &buf, 1, HZ / 2);
1008 }
1009
1010 static inline int pwc_get_wb_speed(struct pwc_device *pdev)
1011 {
1012         unsigned char buf;
1013         int ret;
1014         
1015         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
1016                 GET_CHROM_CTL,
1017                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1018                 AWB_CONTROL_SPEED_FORMATTER,
1019                 pdev->vcinterface,
1020                 &buf, 1, HZ / 2);
1021         if (ret < 0)
1022                 return ret;
1023         return (buf * 0x7f0);
1024 }
1025
1026
1027 static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
1028 {
1029         unsigned char buf;
1030         
1031         /* useful range is 0x01..0x3F */
1032         buf = (delay >> 10);
1033         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
1034                 SET_CHROM_CTL,
1035                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1036                 AWB_CONTROL_DELAY_FORMATTER,
1037                 pdev->vcinterface,
1038                 &buf, 1, HZ / 2);
1039 }
1040
1041 static inline int pwc_get_wb_delay(struct pwc_device *pdev)
1042 {
1043         unsigned char buf;
1044         int ret;
1045         
1046         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
1047                 GET_CHROM_CTL,
1048                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1049                 AWB_CONTROL_DELAY_FORMATTER,
1050                 pdev->vcinterface,
1051                 &buf, 1, HZ / 2);
1052         if (ret < 0)
1053                 return ret;
1054         return (buf << 10);
1055 }
1056
1057
1058 int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
1059 {
1060         unsigned char buf[2];
1061
1062         if (pdev->type < 730)
1063                 return 0;
1064         on_value /= 100;
1065         off_value /= 100;
1066         if (on_value < 0)
1067                 on_value = 0;
1068         if (on_value > 0xff)
1069                 on_value = 0xff;
1070         if (off_value < 0)
1071                 off_value = 0;
1072         if (off_value > 0xff)
1073                 off_value = 0xff;
1074
1075         buf[0] = on_value;
1076         buf[1] = off_value;
1077
1078         return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2);
1079 }
1080
1081 int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
1082 {
1083         unsigned char buf[2];
1084         int ret;
1085         
1086         if (pdev->type < 730) {
1087                 *on_value = -1;
1088                 *off_value = -1;
1089                 return 0;
1090         }
1091
1092         ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2);
1093         if (ret < 0)
1094                 return ret;
1095         *on_value = buf[0] * 100;
1096         *off_value = buf[1] * 100;
1097         return 0;
1098 }
1099
1100 static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
1101 {
1102         unsigned char buf;
1103         int ret;
1104         
1105         if (contour < 0)
1106                 buf = 0xff; /* auto contour on */
1107         else
1108                 buf = 0x0; /* auto contour off */
1109         ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
1110                 SET_LUM_CTL,
1111                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1112                 AUTO_CONTOUR_FORMATTER,
1113                 pdev->vcinterface,
1114                 &buf, 1, HZ / 2);
1115         if (ret < 0)
1116                 return ret;
1117         
1118         if (contour < 0)
1119                 return 0;
1120         if (contour > 0xffff)
1121                 contour = 0xffff;
1122         
1123         buf = (contour >> 10); /* contour preset is [0..3f] */
1124         ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
1125                 SET_LUM_CTL,
1126                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1127                 PRESET_CONTOUR_FORMATTER,
1128                 pdev->vcinterface,
1129                 &buf, 1, HZ / 2);
1130         if (ret < 0)    
1131                 return ret;     
1132         return 0;
1133 }
1134
1135 static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
1136 {
1137         unsigned char buf;
1138         int ret;
1139         
1140         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
1141                 GET_LUM_CTL,
1142                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1143                 AUTO_CONTOUR_FORMATTER,
1144                 pdev->vcinterface,
1145                 &buf, 1, HZ / 2);
1146         if (ret < 0)
1147                 return ret;
1148
1149         if (buf == 0) {
1150                 /* auto mode off, query current preset value */
1151                 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
1152                         GET_LUM_CTL,
1153                         USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1154                         PRESET_CONTOUR_FORMATTER,
1155                         pdev->vcinterface,
1156                         &buf, 1, HZ / 2);
1157                 if (ret < 0)    
1158                         return ret;
1159                 *contour =  (buf << 10);
1160         }
1161         else
1162                 *contour = -1;
1163         return 0;
1164 }
1165
1166
1167 static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
1168 {
1169         unsigned char buf;
1170         
1171         if (backlight)
1172                 buf = 0xff;
1173         else
1174                 buf = 0x0;
1175         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
1176                 SET_LUM_CTL,
1177                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1178                 BACK_LIGHT_COMPENSATION_FORMATTER,
1179                 pdev->vcinterface,
1180                 &buf, 1, HZ / 2);
1181 }
1182
1183 static inline int pwc_get_backlight(struct pwc_device *pdev)
1184 {
1185         int ret;
1186         unsigned char buf;
1187         
1188         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
1189                 GET_LUM_CTL,
1190                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1191                 BACK_LIGHT_COMPENSATION_FORMATTER,
1192                 pdev->vcinterface,
1193                 &buf, 1, HZ / 2);
1194         if (ret < 0)
1195                 return ret;
1196         return buf;
1197 }
1198
1199
1200 static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
1201 {
1202         unsigned char buf;
1203         
1204         if (flicker)
1205                 buf = 0xff;
1206         else
1207                 buf = 0x0;
1208         return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
1209 }
1210
1211 static inline int pwc_get_flicker(struct pwc_device *pdev)
1212 {
1213         int ret;
1214         unsigned char buf;
1215         
1216         ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
1217         if (ret < 0)
1218                 return ret;
1219         return buf;
1220 }
1221
1222
1223 static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
1224 {
1225         unsigned char buf;
1226
1227         if (noise < 0)
1228                 noise = 0;
1229         if (noise > 3)
1230                 noise = 3;
1231         buf = noise;
1232         return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
1233 }
1234
1235 static inline int pwc_get_dynamic_noise(struct pwc_device *pdev)
1236 {
1237         int ret;
1238         unsigned char buf;
1239         
1240         ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
1241         if (ret < 0)
1242                 return ret;
1243         return buf;
1244 }
1245
1246
1247 int pwc_get_cmos_sensor(struct pwc_device *pdev)
1248 {
1249         unsigned char buf;
1250         int ret = -1, request;
1251         
1252         if (pdev->type < 675)
1253                 request = SENSOR_TYPE_FORMATTER1;
1254         else if (pdev->type < 730)
1255                 return -1; /* The Vesta series doesn't have this call */
1256         else
1257                 request = SENSOR_TYPE_FORMATTER2;
1258         
1259         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
1260                 GET_STATUS_CTL,
1261                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1262                 request,
1263                 pdev->vcinterface,
1264                 &buf, 1, HZ / 2);
1265         if (ret < 0)
1266                 return ret;
1267         if (pdev->type < 675)
1268                 return buf | 0x100;
1269         else
1270                 return buf;
1271 }
1272
1273
1274  /* End of Add-Ons                                    */
1275  /* ************************************************* */
1276
1277 int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
1278 {
1279         int ret = 0;
1280
1281         switch(cmd) {
1282         case VIDIOCPWCRUSER:
1283         {
1284                 if (pwc_restore_user(pdev))
1285                         ret = -EINVAL;
1286                 break;
1287         }
1288         
1289         case VIDIOCPWCSUSER:
1290         {
1291                 if (pwc_save_user(pdev))
1292                         ret = -EINVAL;
1293                 break;
1294         }
1295                 
1296         case VIDIOCPWCFACTORY:
1297         {
1298                 if (pwc_restore_factory(pdev))
1299                         ret = -EINVAL;
1300                 break;
1301         }
1302         
1303         case VIDIOCPWCSCQUAL:
1304         {       
1305                 int *qual = arg;
1306
1307                 if (*qual < 0 || *qual > 3)
1308                         ret = -EINVAL;
1309                 else
1310                         ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, *qual, pdev->vsnapshot);
1311                 if (ret >= 0)
1312                         pdev->vcompression = *qual;
1313                 break;
1314         }
1315         
1316         case VIDIOCPWCGCQUAL:
1317         {
1318                 int *qual = arg;
1319                 
1320                 *qual = pdev->vcompression;
1321                 break;
1322         }
1323
1324         case VIDIOCPWCPROBE:
1325         {
1326                 struct pwc_probe *probe = arg;
1327                 
1328                 strcpy(probe->name, pdev->vdev.name);
1329                 probe->type = pdev->type;
1330                 break;
1331         }
1332
1333         case VIDIOCPWCSAGC:
1334         {
1335                 int *agc = arg;
1336
1337                 if (pwc_set_agc(pdev, *agc < 0 ? 1 : 0, *agc))
1338                         ret = -EINVAL;
1339                 break;
1340         }
1341         
1342         case VIDIOCPWCGAGC:
1343         {
1344                 int *agc = arg;
1345                 
1346                 if (pwc_get_agc(pdev, agc))
1347                         ret = -EINVAL;
1348                 break;
1349         }
1350         
1351         case VIDIOCPWCSSHUTTER:
1352         {
1353                 int *shutter_speed = arg;
1354
1355                 ret = pwc_set_shutter_speed(pdev, *shutter_speed < 0 ? 1 : 0, *shutter_speed);
1356                 break;
1357         }
1358         
1359         case VIDIOCPWCSAWB:
1360         {
1361                 struct pwc_whitebalance *wb = arg;
1362                 
1363                 ret = pwc_set_awb(pdev, wb->mode);
1364                 if (ret >= 0 && wb->mode == PWC_WB_MANUAL) {
1365                         pwc_set_red_gain(pdev, wb->manual_red);
1366                         pwc_set_blue_gain(pdev, wb->manual_blue);
1367                 }
1368                 break;
1369         }
1370
1371         case VIDIOCPWCGAWB:
1372         {
1373                 struct pwc_whitebalance *wb = arg;
1374
1375                 memset(wb, 0, sizeof(*wb));
1376                 wb->mode = pwc_get_awb(pdev);
1377                 if (wb->mode < 0)
1378                         ret = -EINVAL;
1379                 else {
1380                         if (wb->mode == PWC_WB_MANUAL) {
1381                                 wb->manual_red = pwc_get_red_gain(pdev);
1382                                 wb->manual_blue = pwc_get_blue_gain(pdev);
1383                         }
1384                         if (wb->mode == PWC_WB_AUTO) {
1385                                 wb->read_red = pwc_read_red_gain(pdev);
1386                                 wb->read_blue = pwc_read_blue_gain(pdev);
1387                         }
1388                 }
1389                 break;
1390         }
1391         
1392         case VIDIOCPWCSAWBSPEED:
1393         {
1394                 struct pwc_wb_speed *wbs = arg;
1395                 
1396                 if (wbs->control_speed > 0) {
1397                         ret = pwc_set_wb_speed(pdev, wbs->control_speed);
1398                 }
1399                 if (wbs->control_delay > 0) {
1400                         ret = pwc_set_wb_delay(pdev, wbs->control_delay);
1401                 }
1402                 break;
1403         }
1404         
1405         case VIDIOCPWCGAWBSPEED:
1406         {
1407                 struct pwc_wb_speed *wbs = arg;
1408                 
1409                 ret = pwc_get_wb_speed(pdev);
1410                 if (ret < 0)
1411                         break;
1412                 wbs->control_speed = ret;
1413                 ret = pwc_get_wb_delay(pdev);
1414                 if (ret < 0)
1415                         break;
1416                 wbs->control_delay = ret;
1417                 break;
1418         }
1419
1420         case VIDIOCPWCSLED:
1421         {
1422                 struct pwc_leds *leds = arg;
1423
1424                 ret = pwc_set_leds(pdev, leds->led_on, leds->led_off);
1425                 break;
1426         }
1427
1428
1429         case VIDIOCPWCGLED:
1430         {
1431                 struct pwc_leds *leds = arg;
1432                 
1433                 ret = pwc_get_leds(pdev, &leds->led_on, &leds->led_off); 
1434                 break;
1435         }
1436
1437         case VIDIOCPWCSCONTOUR:
1438         {
1439                 int *contour = arg;
1440
1441                 ret = pwc_set_contour(pdev, *contour);
1442                 break;
1443         }
1444                         
1445         case VIDIOCPWCGCONTOUR:
1446         {
1447                 int *contour = arg;
1448                 
1449                 ret = pwc_get_contour(pdev, contour);
1450                 break;
1451         }
1452         
1453         case VIDIOCPWCSBACKLIGHT:
1454         {
1455                 int *backlight = arg;
1456                 
1457                 ret = pwc_set_backlight(pdev, *backlight);
1458                 break;
1459         }
1460
1461         case VIDIOCPWCGBACKLIGHT:
1462         {
1463                 int *backlight = arg;
1464                 
1465                 ret = pwc_get_backlight(pdev);
1466                 if (ret >= 0)
1467                         *backlight = ret;
1468                 break;
1469         }
1470         
1471         case VIDIOCPWCSFLICKER:
1472         {
1473                 int *flicker = arg;
1474                 
1475                 ret = pwc_set_flicker(pdev, *flicker);
1476                 break;
1477         }
1478
1479         case VIDIOCPWCGFLICKER:
1480         {
1481                 int *flicker = arg;
1482                 
1483                 ret = pwc_get_flicker(pdev);
1484                 if (ret >= 0)
1485                         *flicker = ret;
1486                 break;
1487         }
1488         
1489         case VIDIOCPWCSDYNNOISE:
1490         {
1491                 int *dynnoise = arg;
1492                 
1493                 ret = pwc_set_dynamic_noise(pdev, *dynnoise);
1494                 break;
1495         }
1496         
1497         case VIDIOCPWCGDYNNOISE:
1498         {
1499                 int *dynnoise = arg;
1500
1501                 ret = pwc_get_dynamic_noise(pdev);
1502                 if (ret < 0)
1503                         break;
1504                 *dynnoise = ret;
1505                 break;
1506         }
1507
1508         case VIDIOCPWCGREALSIZE:
1509         {
1510                 struct pwc_imagesize *size = arg;
1511                 
1512                 size->width = pdev->image.x;
1513                 size->height = pdev->image.y;
1514                 break;
1515         }       
1516
1517         default:
1518                 ret = -ENOIOCTLCMD;
1519                 break;
1520         }
1521         
1522         if (ret > 0)
1523                 return 0;
1524         return ret;
1525 }
1526
1527
1528