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