more changes on original files
[linux-2.4.git] / drivers / usb / 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 choosen (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         /* for PALETTE_YUV420P */
465         factor = 6;
466         filler = 128;
467
468         /* Set sizes in bytes */
469         pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
470         pdev->view.size  = pdev->view.x  * pdev->view.y  * factor / 4;
471
472         /* Align offset, or you'll get some very weird results in
473            YUV420 mode... x must be multiple of 4 (to get the Y's in 
474            place), and y even (or you'll mixup U & V). This is less of a
475            problem for YUV420P.
476          */
477         pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
478         pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
479         
480         /* Fill buffers with gray or black */
481         for (i = 0; i < MAX_IMAGES; i++) {
482                 if (pdev->image_ptr[i] != NULL)
483                         memset(pdev->image_ptr[i], filler, pdev->view.size);
484         }
485 }
486
487
488
489 /* BRIGHTNESS */
490
491 int pwc_get_brightness(struct pwc_device *pdev)
492 {
493         char buf;
494         int ret;
495         
496         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
497                 GET_LUM_CTL,
498                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
499                 BRIGHTNESS_FORMATTER,
500                 pdev->vcinterface,
501                 &buf, 1, HZ / 2);
502         if (ret < 0)
503                 return ret;
504         return buf << 9;
505 }
506
507 int pwc_set_brightness(struct pwc_device *pdev, int value)
508 {
509         char buf;
510
511         if (value < 0)
512                 value = 0;
513         if (value > 0xffff)
514                 value = 0xffff;
515         buf = (value >> 9) & 0x7f;
516         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
517                 SET_LUM_CTL,
518                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
519                 BRIGHTNESS_FORMATTER,
520                 pdev->vcinterface,
521                 &buf, 1, HZ / 2);
522 }
523
524 /* CONTRAST */
525
526 int pwc_get_contrast(struct pwc_device *pdev)
527 {
528         char buf;
529         int ret;
530         
531         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
532                 GET_LUM_CTL,
533                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
534                 CONTRAST_FORMATTER,
535                 pdev->vcinterface,
536                 &buf, 1, HZ / 2);
537         if (ret < 0)
538                 return ret;
539         return buf << 10;
540 }
541
542 int pwc_set_contrast(struct pwc_device *pdev, int value)
543 {
544         char buf;
545
546         if (value < 0)
547                 value = 0;
548         if (value > 0xffff)
549                 value = 0xffff;
550         buf = (value >> 10) & 0x3f;
551         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
552                 SET_LUM_CTL,
553                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
554                 CONTRAST_FORMATTER,
555                 pdev->vcinterface,
556                 &buf, 1, HZ / 2);
557 }
558
559 /* GAMMA */
560
561 int pwc_get_gamma(struct pwc_device *pdev)
562 {
563         char buf;
564         int ret;
565         
566         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
567                 GET_LUM_CTL,
568                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
569                 GAMMA_FORMATTER,
570                 pdev->vcinterface,
571                 &buf, 1, HZ / 2);
572         if (ret < 0)
573                 return ret;
574         return buf << 11;
575 }
576
577 int pwc_set_gamma(struct pwc_device *pdev, int value)
578 {
579         char buf;
580
581         if (value < 0)
582                 value = 0;
583         if (value > 0xffff)
584                 value = 0xffff;
585         buf = (value >> 11) & 0x1f;
586         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
587                 SET_LUM_CTL,
588                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
589                 GAMMA_FORMATTER,
590                 pdev->vcinterface,
591                 &buf, 1, HZ / 2);
592 }
593
594
595 /* SATURATION */
596
597 int pwc_get_saturation(struct pwc_device *pdev)
598 {
599         char buf;
600         int ret;
601
602         if (pdev->type < 675)
603                 return -1;
604         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
605                 GET_CHROM_CTL,
606                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
607                 pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1,
608                 pdev->vcinterface,
609                 &buf, 1, HZ / 2);
610         if (ret < 0)
611                 return ret;
612         return 32768 + buf * 327;
613 }
614
615 int pwc_set_saturation(struct pwc_device *pdev, int value)
616 {
617         char buf;
618
619         if (pdev->type < 675)
620                 return -EINVAL;
621         if (value < 0)
622                 value = 0;
623         if (value > 0xffff)
624                 value = 0xffff;
625         /* saturation ranges from -100 to +100 */
626         buf = (value - 32768) / 327;
627         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
628                 SET_CHROM_CTL,
629                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
630                 pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1,
631                 pdev->vcinterface,
632                 &buf, 1, HZ / 2);
633 }
634
635 /* AGC */
636
637 static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
638 {
639         char buf;
640         int ret;
641         
642         if (mode)
643                 buf = 0x0; /* auto */
644         else
645                 buf = 0xff; /* fixed */
646
647         ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
648                 SET_LUM_CTL,
649                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
650                 AGC_MODE_FORMATTER,
651                 pdev->vcinterface,
652                 &buf, 1, HZ / 2);
653         
654         if (!mode && ret >= 0) {
655                 if (value < 0)
656                         value = 0;
657                 if (value > 0xffff)
658                         value = 0xffff;
659                 buf = (value >> 10) & 0x3F;
660                 ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
661                         SET_LUM_CTL,
662                         USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
663                         PRESET_AGC_FORMATTER,
664                         pdev->vcinterface,
665                         &buf, 1, HZ / 2);
666         }
667         if (ret < 0)
668                 return ret;
669         return 0;
670 }
671
672 static inline int pwc_get_agc(struct pwc_device *pdev, int *value)
673 {
674         unsigned char buf;
675         int ret;
676         
677         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
678                 GET_LUM_CTL,
679                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
680                 AGC_MODE_FORMATTER,
681                 pdev->vcinterface,
682                 &buf, 1, HZ / 2);
683         if (ret < 0)
684                 return ret;
685
686         if (buf != 0) { /* fixed */
687                 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
688                         GET_LUM_CTL,
689                         USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
690                         PRESET_AGC_FORMATTER,
691                         pdev->vcinterface,
692                         &buf, 1, HZ / 2);
693                 if (ret < 0)
694                         return ret;
695                 if (buf > 0x3F)
696                         buf = 0x3F;
697                 *value = (buf << 10);           
698         }
699         else { /* auto */
700                 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
701                         GET_STATUS_CTL,
702                         USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
703                         READ_AGC_FORMATTER,
704                         pdev->vcinterface,
705                         &buf, 1, HZ / 2);
706                 if (ret < 0)
707                         return ret;
708                 /* Gah... this value ranges from 0x00 ... 0x9F */
709                 if (buf > 0x9F)
710                         buf = 0x9F;
711                 *value = -(48 + buf * 409);
712         }
713
714         return 0;
715 }
716
717 static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
718 {
719         char buf[2];
720         int speed, ret;
721
722
723         if (mode)
724                 buf[0] = 0x0;   /* auto */
725         else
726                 buf[0] = 0xff; /* fixed */
727         
728         ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
729                 SET_LUM_CTL,
730                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
731                 SHUTTER_MODE_FORMATTER,
732                 pdev->vcinterface,
733                 buf, 1, HZ / 2);
734
735         if (!mode && ret >= 0) {
736                 if (value < 0)
737                         value = 0;
738                 if (value > 0xffff)
739                         value = 0xffff;
740                 switch(pdev->type) {
741                 case 675:
742                 case 680:
743                 case 690:
744                         /* speed ranges from 0x0 to 0x290 (656) */
745                         speed = (value / 100);
746                         buf[1] = speed >> 8;
747                         buf[0] = speed & 0xff;
748                         break;
749                 case 730:
750                 case 740:
751                 case 750:
752                         /* speed seems to range from 0x0 to 0xff */
753                         buf[1] = 0;
754                         buf[0] = value >> 8;
755                         break;
756                 }
757
758                 ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
759                         SET_LUM_CTL,
760                         USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
761                         PRESET_SHUTTER_FORMATTER,
762                         pdev->vcinterface,
763                         &buf, 2, HZ / 2);
764         }
765         return ret;
766 }       
767
768
769 /* POWER */
770
771 int pwc_camera_power(struct pwc_device *pdev, int power)
772 {
773         char buf;
774
775         if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6))
776                 return 0;       /* Not supported by Nala or Timon < release 6 */
777
778         if (power)
779                 buf = 0x00; /* active */
780         else
781                 buf = 0xFF; /* power save */
782         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
783                 SET_STATUS_CTL,
784                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
785                 SET_POWER_SAVE_MODE_FORMATTER,
786                 pdev->vcinterface,
787                 &buf, 1, HZ / 2);
788 }
789
790
791
792 /* private calls */
793
794 static inline int pwc_restore_user(struct pwc_device *pdev)
795 {
796         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
797                 SET_STATUS_CTL,
798                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
799                 RESTORE_USER_DEFAULTS_FORMATTER,
800                 pdev->vcinterface,
801                 NULL, 0, HZ / 2);
802 }
803
804 static inline int pwc_save_user(struct pwc_device *pdev)
805 {
806         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
807                 SET_STATUS_CTL,
808                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
809                 SAVE_USER_DEFAULTS_FORMATTER,
810                 pdev->vcinterface,
811                 NULL, 0, HZ / 2);
812 }
813
814 static inline int pwc_restore_factory(struct pwc_device *pdev)
815 {
816         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
817                 SET_STATUS_CTL,
818                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
819                 RESTORE_FACTORY_DEFAULTS_FORMATTER,
820                 pdev->vcinterface,
821                 NULL, 0, HZ / 2);
822 }
823
824  /* ************************************************* */
825  /* Patch by Alvarado: (not in the original version   */
826
827  /*
828   * the camera recognizes modes from 0 to 4:
829   *
830   * 00: indoor (incandescant lighting)
831   * 01: outdoor (sunlight)
832   * 02: fluorescent lighting
833   * 03: manual
834   * 04: auto
835   */ 
836 static inline int pwc_set_awb(struct pwc_device *pdev, int mode)
837 {
838         char buf;
839         int ret;
840         
841         if (mode < 0)
842             mode = 0;
843         
844         if (mode > 4)
845             mode = 4;
846         
847         buf = mode & 0x07; /* just the lowest three bits */
848         
849         ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
850                 SET_CHROM_CTL,
851                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
852                 WB_MODE_FORMATTER,
853                 pdev->vcinterface,
854                 &buf, 1, HZ / 2);
855         
856         if (ret < 0)
857                 return ret;
858         return 0;
859 }
860
861 static inline int pwc_get_awb(struct pwc_device *pdev)
862 {
863         unsigned char buf;
864         int ret;
865         
866         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
867                 GET_CHROM_CTL,
868                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
869                 WB_MODE_FORMATTER,
870                 pdev->vcinterface,
871                 &buf, 1, HZ / 2);
872
873         if (ret < 0) 
874                 return ret;
875         return buf;
876 }
877
878 static inline int pwc_set_red_gain(struct pwc_device *pdev, int value)
879 {
880         unsigned char buf;
881
882         if (value < 0)
883                 value = 0;
884         if (value > 0xffff)
885                 value = 0xffff;
886
887         /* only the msb are considered */
888         buf = value >> 8;
889
890         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
891                 SET_CHROM_CTL,
892                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
893                 PRESET_MANUAL_RED_GAIN_FORMATTER,
894                 pdev->vcinterface,
895                 &buf, 1, HZ / 2);
896 }
897
898 static inline int pwc_get_red_gain(struct pwc_device *pdev)
899 {
900         unsigned char buf;
901         int ret;
902         
903         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
904                 GET_CHROM_CTL, 
905                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
906                 PRESET_MANUAL_RED_GAIN_FORMATTER,
907                 pdev->vcinterface,
908                 &buf, 1, HZ / 2);
909
910         if (ret < 0)
911             return ret;
912         
913         return (buf << 8);
914 }
915
916
917 static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value)
918 {
919         unsigned char buf;
920
921         if (value < 0)
922                 value = 0;
923         if (value > 0xffff)
924                 value = 0xffff;
925
926         /* linear mapping of 0..0xffff to -0x80..0x7f */
927         buf = (value >> 8);
928
929         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
930                 SET_CHROM_CTL,
931                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
932                 PRESET_MANUAL_BLUE_GAIN_FORMATTER,
933                 pdev->vcinterface,
934                 &buf, 1, HZ / 2);
935 }
936
937 static inline int pwc_get_blue_gain(struct pwc_device *pdev)
938 {
939         unsigned char buf;
940         int ret;
941         
942         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
943                 GET_CHROM_CTL,
944                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
945                 PRESET_MANUAL_BLUE_GAIN_FORMATTER,
946                 pdev->vcinterface,
947                 &buf, 1, HZ / 2);
948
949         if (ret < 0)
950             return ret;
951         
952         return (buf << 8);
953 }
954
955
956 /* The following two functions are different, since they only read the
957    internal red/blue gains, which may be different from the manual 
958    gains set or read above.
959  */   
960 static inline int pwc_read_red_gain(struct pwc_device *pdev)
961 {
962         unsigned char buf;
963         int ret;
964         
965         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
966                 GET_STATUS_CTL, 
967                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
968                 READ_RED_GAIN_FORMATTER,
969                 pdev->vcinterface,
970                 &buf, 1, HZ / 2);
971
972         if (ret < 0)
973                 return ret;
974         
975         return (buf << 8);
976 }
977
978 static inline int pwc_read_blue_gain(struct pwc_device *pdev)
979 {
980         unsigned char buf;
981         int ret;
982         
983         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
984                 GET_STATUS_CTL,
985                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
986                 READ_BLUE_GAIN_FORMATTER,
987                 pdev->vcinterface,
988                 &buf, 1, HZ / 2);
989
990         if (ret < 0)
991                 return ret;
992         
993         return (buf << 8);
994 }
995
996
997 static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
998 {
999         unsigned char buf;
1000         
1001         /* useful range is 0x01..0x20 */
1002         buf = speed / 0x7f0;
1003         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
1004                 SET_CHROM_CTL,
1005                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1006                 AWB_CONTROL_SPEED_FORMATTER,
1007                 pdev->vcinterface,
1008                 &buf, 1, HZ / 2);
1009 }
1010
1011 static inline int pwc_get_wb_speed(struct pwc_device *pdev)
1012 {
1013         unsigned char buf;
1014         int ret;
1015         
1016         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
1017                 GET_CHROM_CTL,
1018                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1019                 AWB_CONTROL_SPEED_FORMATTER,
1020                 pdev->vcinterface,
1021                 &buf, 1, HZ / 2);
1022         if (ret < 0)
1023                 return ret;
1024         return (buf * 0x7f0);
1025 }
1026
1027
1028 static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
1029 {
1030         unsigned char buf;
1031         
1032         /* useful range is 0x01..0x3F */
1033         buf = (delay >> 10);
1034         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
1035                 SET_CHROM_CTL,
1036                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1037                 AWB_CONTROL_DELAY_FORMATTER,
1038                 pdev->vcinterface,
1039                 &buf, 1, HZ / 2);
1040 }
1041
1042 static inline int pwc_get_wb_delay(struct pwc_device *pdev)
1043 {
1044         unsigned char buf;
1045         int ret;
1046         
1047         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
1048                 GET_CHROM_CTL,
1049                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1050                 AWB_CONTROL_DELAY_FORMATTER,
1051                 pdev->vcinterface,
1052                 &buf, 1, HZ / 2);
1053         if (ret < 0)
1054                 return ret;
1055         return (buf << 10);
1056 }
1057
1058
1059 int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
1060 {
1061         unsigned char buf[2];
1062
1063         if (pdev->type < 730)
1064                 return 0;
1065         on_value /= 100;
1066         off_value /= 100;
1067         if (on_value < 0)
1068                 on_value = 0;
1069         if (on_value > 0xff)
1070                 on_value = 0xff;
1071         if (off_value < 0)
1072                 off_value = 0;
1073         if (off_value > 0xff)
1074                 off_value = 0xff;
1075
1076         buf[0] = on_value;
1077         buf[1] = off_value;
1078
1079         return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2);
1080 }
1081
1082 int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
1083 {
1084         unsigned char buf[2];
1085         int ret;
1086         
1087         if (pdev->type < 730) {
1088                 *on_value = -1;
1089                 *off_value = -1;
1090                 return 0;
1091         }
1092
1093         ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2);
1094         if (ret < 0)
1095                 return ret;
1096         *on_value = buf[0] * 100;
1097         *off_value = buf[1] * 100;
1098         return 0;
1099 }
1100
1101 static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
1102 {
1103         unsigned char buf;
1104         int ret;
1105         
1106         if (contour < 0)
1107                 buf = 0xff; /* auto contour on */
1108         else
1109                 buf = 0x0; /* auto contour off */
1110         ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
1111                 SET_LUM_CTL,
1112                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1113                 AUTO_CONTOUR_FORMATTER,
1114                 pdev->vcinterface,
1115                 &buf, 1, HZ / 2);
1116         if (ret < 0)
1117                 return ret;
1118         
1119         if (contour < 0)
1120                 return 0;
1121         if (contour > 0xffff)
1122                 contour = 0xffff;
1123         
1124         buf = (contour >> 10); /* contour preset is [0..3f] */
1125         ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
1126                 SET_LUM_CTL,
1127                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1128                 PRESET_CONTOUR_FORMATTER,
1129                 pdev->vcinterface,
1130                 &buf, 1, HZ / 2);
1131         if (ret < 0)    
1132                 return ret;     
1133         return 0;
1134 }
1135
1136 static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
1137 {
1138         unsigned char buf;
1139         int ret;
1140         
1141         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
1142                 GET_LUM_CTL,
1143                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1144                 AUTO_CONTOUR_FORMATTER,
1145                 pdev->vcinterface,
1146                 &buf, 1, HZ / 2);
1147         if (ret < 0)
1148                 return ret;
1149
1150         if (buf == 0) {
1151                 /* auto mode off, query current preset value */
1152                 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
1153                         GET_LUM_CTL,
1154                         USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1155                         PRESET_CONTOUR_FORMATTER,
1156                         pdev->vcinterface,
1157                         &buf, 1, HZ / 2);
1158                 if (ret < 0)    
1159                         return ret;
1160                 *contour =  (buf << 10);
1161         }
1162         else
1163                 *contour = -1;
1164         return 0;
1165 }
1166
1167
1168 static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
1169 {
1170         unsigned char buf;
1171         
1172         if (backlight)
1173                 buf = 0xff;
1174         else
1175                 buf = 0x0;
1176         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
1177                 SET_LUM_CTL,
1178                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1179                 BACK_LIGHT_COMPENSATION_FORMATTER,
1180                 pdev->vcinterface,
1181                 &buf, 1, HZ / 2);
1182 }
1183
1184 static inline int pwc_get_backlight(struct pwc_device *pdev)
1185 {
1186         int ret;
1187         unsigned char buf;
1188         
1189         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
1190                 GET_LUM_CTL,
1191                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1192                 BACK_LIGHT_COMPENSATION_FORMATTER,
1193                 pdev->vcinterface,
1194                 &buf, 1, HZ / 2);
1195         if (ret < 0)
1196                 return ret;
1197         return buf;
1198 }
1199
1200
1201 static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
1202 {
1203         unsigned char buf;
1204         
1205         if (flicker)
1206                 buf = 0xff;
1207         else
1208                 buf = 0x0;
1209         return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
1210 }
1211
1212 static inline int pwc_get_flicker(struct pwc_device *pdev)
1213 {
1214         int ret;
1215         unsigned char buf;
1216         
1217         ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
1218         if (ret < 0)
1219                 return ret;
1220         return buf;
1221 }
1222
1223
1224 static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
1225 {
1226         unsigned char buf;
1227
1228         if (noise < 0)
1229                 noise = 0;
1230         if (noise > 3)
1231                 noise = 3;
1232         buf = noise;
1233         return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
1234 }
1235
1236 static inline int pwc_get_dynamic_noise(struct pwc_device *pdev)
1237 {
1238         int ret;
1239         unsigned char buf;
1240         
1241         ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
1242         if (ret < 0)
1243                 return ret;
1244         return buf;
1245 }
1246
1247
1248 int pwc_get_cmos_sensor(struct pwc_device *pdev)
1249 {
1250         unsigned char buf;
1251         int ret = -1, request;
1252         
1253         if (pdev->type < 675)
1254                 request = SENSOR_TYPE_FORMATTER1;
1255         else if (pdev->type < 730)
1256                 return -1; /* The Vesta series doesn't have this call */
1257         else
1258                 request = SENSOR_TYPE_FORMATTER2;
1259         
1260         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
1261                 GET_STATUS_CTL,
1262                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1263                 request,
1264                 pdev->vcinterface,
1265                 &buf, 1, HZ / 2);
1266         if (ret < 0)
1267                 return ret;
1268         if (pdev->type < 675)
1269                 return buf | 0x100;
1270         else
1271                 return buf;
1272 }
1273
1274
1275  /* End of Add-Ons                                    */
1276  /* ************************************************* */
1277
1278 int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
1279 {
1280         int ret = 0;
1281
1282         switch(cmd) {
1283         case VIDIOCPWCRUSER:
1284         {
1285                 if (pwc_restore_user(pdev))
1286                         ret = -EINVAL;
1287                 break;
1288         }
1289         
1290         case VIDIOCPWCSUSER:
1291         {
1292                 if (pwc_save_user(pdev))
1293                         ret = -EINVAL;
1294                 break;
1295         }
1296                 
1297         case VIDIOCPWCFACTORY:
1298         {
1299                 if (pwc_restore_factory(pdev))
1300                         ret = -EINVAL;
1301                 break;
1302         }
1303         
1304         case VIDIOCPWCSCQUAL:
1305         {       
1306                 int qual;
1307
1308                 if (copy_from_user(&qual, arg, sizeof(int)))
1309                         ret = -EFAULT;
1310                 else {
1311                         if (qual < 0 || qual > 3)
1312                                 ret = -EINVAL;
1313                         else
1314                                 ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, qual, pdev->vsnapshot);
1315                         if (ret >= 0)
1316                                 pdev->vcompression = qual;
1317                 }
1318                 break;
1319         }
1320         
1321         case VIDIOCPWCGCQUAL:
1322         {
1323                 if (copy_to_user(arg, &pdev->vcompression, sizeof(int)))
1324                         ret = -EFAULT;
1325                 break;
1326         }
1327
1328         case VIDIOCPWCPROBE:
1329         {
1330                 struct pwc_probe probe;
1331                 
1332                 strcpy(probe.name, pdev->vdev.name);
1333                 probe.type = pdev->type;
1334                 if (copy_to_user(arg, &probe, sizeof(probe)))
1335                         ret = -EFAULT;
1336                 break;
1337         }
1338
1339         case VIDIOCPWCSAGC:
1340         {
1341                 int agc;
1342                 
1343                 if (copy_from_user(&agc, arg, sizeof(agc)))
1344                         ret = -EFAULT;  
1345                 else {
1346                         if (pwc_set_agc(pdev, agc < 0 ? 1 : 0, agc))
1347                                 ret = -EINVAL;
1348                 }
1349                 break;
1350         }
1351         
1352         case VIDIOCPWCGAGC:
1353         {
1354                 int agc;
1355                 
1356                 if (pwc_get_agc(pdev, &agc))
1357                         ret = -EINVAL;
1358                 else
1359                         if (copy_to_user(arg, &agc, sizeof(agc)))
1360                                 ret = -EFAULT;
1361                 break;
1362         }
1363         
1364         case VIDIOCPWCSSHUTTER:
1365         {
1366                 int shutter_speed;
1367
1368                 if (copy_from_user(&shutter_speed, arg, sizeof(shutter_speed)))
1369                         ret = -EFAULT;
1370                 else
1371                         ret = pwc_set_shutter_speed(pdev, shutter_speed < 0 ? 1 : 0, shutter_speed);
1372                 break;
1373         }
1374         
1375         case VIDIOCPWCSAWB:
1376         {
1377                 struct pwc_whitebalance wb;
1378                 
1379                 if (copy_from_user(&wb, arg, sizeof(wb)))
1380                         ret = -EFAULT;
1381                 else {
1382                         ret = pwc_set_awb(pdev, wb.mode);
1383                         if (ret >= 0 && wb.mode == PWC_WB_MANUAL) {
1384                                 pwc_set_red_gain(pdev, wb.manual_red);
1385                                 pwc_set_blue_gain(pdev, wb.manual_blue);
1386                         }
1387                 }
1388                 break;
1389         }
1390
1391         case VIDIOCPWCGAWB:
1392         {
1393                 struct pwc_whitebalance wb;
1394                 
1395                 memset(&wb, 0, sizeof(wb));
1396                 wb.mode = pwc_get_awb(pdev);
1397                 if (wb.mode < 0)
1398                         ret = -EINVAL;
1399                 else {
1400                         if (wb.mode == PWC_WB_MANUAL) {
1401                                 wb.manual_red = pwc_get_red_gain(pdev);
1402                                 wb.manual_blue = pwc_get_blue_gain(pdev);
1403                         }
1404                         if (wb.mode == PWC_WB_AUTO) {
1405                                 wb.read_red = pwc_read_red_gain(pdev);
1406                                 wb.read_blue = pwc_read_blue_gain(pdev);
1407                         }
1408                         if (copy_to_user(arg, &wb, sizeof(wb)))
1409                                 ret= -EFAULT;
1410                 }
1411                 break;
1412         }
1413         
1414         case VIDIOCPWCSAWBSPEED:
1415         {
1416                 struct pwc_wb_speed wbs;
1417                 
1418                 if (copy_from_user(&wbs, arg, sizeof(wbs)))
1419                         ret = -EFAULT;
1420                 else {
1421                         if (wbs.control_speed > 0) {
1422                                 ret = pwc_set_wb_speed(pdev, wbs.control_speed);
1423                         }
1424                         if (wbs.control_delay > 0) {
1425                                 ret = pwc_set_wb_delay(pdev, wbs.control_delay);
1426                         }
1427                 }
1428                 break;
1429         }
1430         
1431         case VIDIOCPWCGAWBSPEED:
1432         {
1433                 struct pwc_wb_speed wbs;
1434                 
1435                 ret = pwc_get_wb_speed(pdev);
1436                 if (ret < 0)
1437                         break;
1438                 wbs.control_speed = ret;
1439                 ret = pwc_get_wb_delay(pdev);
1440                 if (ret < 0)
1441                         break;
1442                 wbs.control_delay = ret;
1443                 if (copy_to_user(arg, &wbs, sizeof(wbs)))
1444                         ret = -EFAULT;
1445                 break;
1446         }
1447
1448         case VIDIOCPWCSLED:
1449         {
1450                 struct pwc_leds leds;
1451
1452                 if (copy_from_user(&leds, arg, sizeof(leds)))
1453                         ret = -EFAULT;
1454                 else
1455                         ret = pwc_set_leds(pdev, leds.led_on, leds.led_off);
1456                 break;
1457         }
1458
1459
1460         case VIDIOCPWCGLED:
1461         {
1462                 struct pwc_leds leds;
1463                 
1464                 ret = pwc_get_leds(pdev, &leds.led_on, &leds.led_off); 
1465                 if (ret < 0)
1466                         break;
1467                 if (copy_to_user(arg, &leds, sizeof(leds)))
1468                         ret = -EFAULT;
1469                 break;
1470         }
1471
1472         case VIDIOCPWCSCONTOUR:
1473         {
1474                 int contour;
1475                 
1476                 if (copy_from_user(&contour, arg, sizeof(contour)))
1477                         ret = -EFAULT;
1478                 else
1479                         ret = pwc_set_contour(pdev, contour);
1480                 break;
1481         }
1482                         
1483         case VIDIOCPWCGCONTOUR:
1484         {
1485                 int contour;
1486                 
1487                 ret = pwc_get_contour(pdev, &contour);
1488                 if (ret < 0)
1489                         break;
1490                         
1491                 if (copy_to_user(arg, &contour, sizeof(contour)))
1492                         ret = -EFAULT;
1493                 break;
1494         }
1495         
1496         case VIDIOCPWCSBACKLIGHT:
1497         {
1498                 int backlight;
1499                 
1500                 if (copy_from_user(&backlight, arg, sizeof(backlight)))
1501                         ret = -EFAULT;
1502                 else
1503                         ret = pwc_set_backlight(pdev, backlight);
1504                 break;
1505         }
1506
1507         case VIDIOCPWCGBACKLIGHT:
1508         {
1509                 ret = pwc_get_backlight(pdev);
1510                 if (ret < 0)
1511                         break;
1512                 if (copy_to_user(arg, &ret, sizeof(ret)))
1513                         ret = -EFAULT;
1514                 break;
1515         }
1516         
1517         case VIDIOCPWCSFLICKER:
1518         {
1519                 int flicker;
1520                 
1521                 if (copy_from_user(&flicker, arg, sizeof(flicker)))
1522                         ret = -EFAULT;
1523                 else
1524                         ret = pwc_set_flicker(pdev, flicker);
1525                 break;
1526         }
1527
1528         case VIDIOCPWCGFLICKER:
1529         {
1530                 ret = pwc_get_flicker(pdev);
1531                 if (ret < 0)
1532                         break;
1533                 if (copy_to_user(arg, &ret, sizeof(ret)))
1534                         ret = -EFAULT;
1535                 break;
1536         }
1537         
1538         case VIDIOCPWCSDYNNOISE:
1539         {
1540                 int dynnoise;
1541                 
1542                 if (copy_from_user(&dynnoise, arg, sizeof(dynnoise)))
1543                         ret = -EFAULT;
1544                 else
1545                         ret = pwc_set_dynamic_noise(pdev, dynnoise);
1546                 break;
1547         }
1548         
1549         case VIDIOCPWCGDYNNOISE:
1550         {
1551                 ret = pwc_get_dynamic_noise(pdev);
1552                 if (ret < 0)
1553                         break;
1554                 if (copy_to_user(arg, &ret, sizeof(ret)))
1555                         ret = -EFAULT;
1556                 break;
1557         }
1558         
1559         case VIDIOCPWCGREALSIZE:
1560         {
1561                 struct pwc_imagesize size;
1562                 
1563                 size.width = pdev->image.x;
1564                 size.height = pdev->image.y;
1565                 if (copy_to_user(arg, &size, sizeof(size)))
1566                         ret = -EFAULT;
1567                 break;
1568         }       
1569
1570         default:
1571                 ret = -ENOIOCTLCMD;
1572                 break;
1573         }
1574         
1575         if (ret > 0)
1576                 return 0;
1577         return ret;
1578 }
1579
1580
1581