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