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