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