v2.4.8 -> v2.4.8.1
[opensuse:kernel.git] / drivers / usb / pwc-ctrl.c
1 /* Driver for Philips webcam
2    Functions that send various control messages to the webcam, including
3    video modes.
4    (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl)
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 /* Control functions for the cam; brightness, contrast, video mode, etc. */
22
23 #ifdef __KERNEL__
24 #include <asm/uaccess.h> 
25 #endif
26 #include <asm/errno.h>
27  
28 #include "pwc.h"
29 #include "pwc-ioctl.h"
30 #include "pwc-uncompress.h"
31
32 /* Request types: video */
33 #define SET_LUM_CTL                     0x01
34 #define GET_LUM_CTL                     0x02
35 #define SET_CHROM_CTL                   0x03
36 #define GET_CHROM_CTL                   0x04
37 #define SET_STATUS_CTL                  0x05
38 #define GET_STATUS_CTL                  0x06
39 #define SET_EP_STREAM_CTL               0x07
40 #define GET_EP_STREAM_CTL               0x08
41
42 /* Selectors for the Luminance controls [GS]ET_LUM_CTL */
43 #define AGC_MODE_FORMATTER                      0x2000
44 #define PRESET_AGC_FORMATTER                    0x2100
45 #define SHUTTER_MODE_FORMATTER                  0x2200
46 #define PRESET_SHUTTER_FORMATTER                0x2300
47 #define PRESET_CONTOUR_FORMATTER                0x2400
48 #define AUTO_CONTOUR_FORMATTER                  0x2500
49 #define BACK_LIGHT_COMPENSATION_FORMATTER       0x2600
50 #define CONTRAST_FORMATTER                      0x2700
51 #define DYNAMIC_NOISE_CONTROL_FORMATTER         0x2800
52 #define FLICKERLESS_MODE_FORMATTER              0x2900
53 #define AE_CONTROL_SPEED                        0x2A00
54 #define BRIGHTNESS_FORMATTER                    0x2B00
55 #define GAMMA_FORMATTER                         0x2C00
56
57 /* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */
58 #define WB_MODE_FORMATTER                       0x1000
59 #define AWB_CONTROL_SPEED_FORMATTER             0x1100
60 #define AWB_CONTROL_DELAY_FORMATTER             0x1200
61 #define PRESET_MANUAL_RED_GAIN_FORMATTER        0x1300
62 #define PRESET_MANUAL_BLUE_GAIN_FORMATTER       0x1400
63 #define COLOUR_MODE_FORMATTER                   0x1500
64 #define SATURATION_MODE_FORMATTER1              0x1600
65 #define SATURATION_MODE_FORMATTER2              0x1700
66
67 /* Selectors for the Status controls [GS]ET_STATUS_CTL */
68 #define SAVE_USER_DEFAULTS_FORMATTER            0x0200
69 #define RESTORE_USER_DEFAULTS_FORMATTER         0x0300
70 #define RESTORE_FACTORY_DEFAULTS_FORMATTER      0x0400
71 #define READ_AGC_FORMATTER                      0x0500
72 #define READ_SHUTTER_FORMATTER                  0x0600
73 #define READ_RED_GAIN_FORMATTER                 0x0700
74 #define READ_BLUE_GAIN_FORMATTER                0x0800
75 #define READ_RAW_Y_MEAN_FORMATTER               0x3100
76 #define SET_POWER_SAVE_MODE_FORMATTER           0x3200
77 #define MIRROR_IMAGE_FORMATTER                  0x3300
78 #define LED_FORMATTER                           0x3400
79
80 /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
81 #define VIDEO_OUTPUT_CONTROL_FORMATTER          0x0100
82
83 static char *size2name[PSZ_MAX] =
84 {
85         "subQCIF",
86         "QSIF",
87         "QCIF",
88         "SIF",
89         "CIF",
90         "VGA",
91 };  
92
93 /********/
94
95 /* Entries for the Nala (645/646) camera; the Nala doesn't have compression 
96    preferences, so you either get compressed or non-compressed streams.
97    
98    An alternate value of 0 means this mode is not available at all.
99  */
100
101 struct Nala_table_entry {
102         char alternate;                 /* USB alternate setting */
103         int compressed;                 /* Compressed yes/no */
104
105         unsigned char mode[3];          /* precomputed mode table */
106 };
107
108 static struct Nala_table_entry Nala_table[PSZ_MAX][8] =
109 {
110 #include "pwc_nala.h"
111 };
112
113 /* This tables contains entries for the 675/680/690 (Timon) camera, with
114    4 different qualities (no compression, low, medium, high).
115    It lists the bandwidth requirements for said mode by its alternate interface 
116    number. An alternate of 0 means that the mode is unavailable.
117    
118    There are 6 * 4 * 4 entries: 
119      6 different resolutions subqcif, qsif, qcif, sif, cif, vga
120      6 framerates: 5, 10, 15, 20, 25, 30
121      4 compression modi: none, low, medium, high
122      
123    When an uncompressed mode is not available, the next available compressed mode 
124    will be choosen (unless the decompressor is absent). Sometimes there are only
125    1 or 2 compressed modes available; in that case entries are duplicated.
126 */
127 struct Timon_table_entry 
128 {
129         char alternate;                 /* USB alternate interface */
130         unsigned short packetsize;      /* Normal packet size */
131         unsigned short bandlength;      /* Bandlength when decompressing */
132         unsigned char mode[13];         /* precomputed mode settings for cam */
133 };
134
135 static struct Timon_table_entry Timon_table[PSZ_MAX][6][4] = 
136 {
137 #include "pwc_timon.h"
138 };
139
140 /* Entries for the Kiara (730/740/750) camera */
141
142 struct Kiara_table_entry
143 {
144         char alternate;                 /* USB alternate interface */
145         unsigned short packetsize;      /* Normal packet size */
146         unsigned short bandlength;      /* Bandlength when decompressing */
147         unsigned char mode[12];         /* precomputed mode settings for cam */
148 };
149
150 static struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] =
151 {
152 #include "pwc_kiara.h"
153 };
154
155
156 /****************************************************************************/
157
158
159
160
161 #if PWC_DEBUG
162 void pwc_hexdump(void *p, int len)
163 {
164         int i;
165         unsigned char *s;
166         char buf[100], *d;
167         
168         s = (unsigned char *)p;
169         d = buf;
170         *d = '\0';
171         Debug("Doing hexdump @ %p, %d bytes.\n", p, len);
172         for (i = 0; i < len; i++) {
173                 d += sprintf(d, "%02X ", *s++);
174                 if ((i & 0xF) == 0xF) {
175                         Debug("%s\n", buf);
176                         d = buf;
177                         *d = '\0';
178                 }
179         }
180         if ((i & 0xF) != 0)
181                 Debug("%s\n", buf);
182 }
183 #endif
184
185 static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen)
186 {
187         return usb_control_msg(udev,
188                 usb_sndctrlpipe(udev, 0),
189                 SET_EP_STREAM_CTL,
190                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
191                 VIDEO_OUTPUT_CONTROL_FORMATTER,
192                 index,
193                 buf, buflen, HZ);
194 }
195
196
197
198 static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
199 {
200         unsigned char buf[3];
201         int ret, fps;
202         struct Nala_table_entry *pEntry;
203         int frames2frames[31] = 
204         { /* closest match of framerate */
205            0,  0,  0,  0,  4,  /*  0-4  */
206            5,  5,  7,  7, 10,  /*  5-9  */
207           10, 10, 12, 12, 15,  /* 10-14 */
208           15, 15, 15, 20, 20,  /* 15-19 */
209           20, 20, 20, 24, 24,  /* 20-24 */
210           24, 24, 24, 24, 24,  /* 25-29 */
211           24                   /* 30    */
212         };
213         int frames2table[31] = 
214         { 0, 0, 0, 0, 0, /*  0-4  */
215           1, 1, 1, 2, 2, /*  5-9  */
216           3, 3, 4, 4, 4, /* 10-14 */
217           5, 5, 5, 5, 5, /* 15-19 */
218           6, 6, 6, 6, 7, /* 20-24 */
219           7, 7, 7, 7, 7, /* 25-29 */
220           7              /* 30    */
221         };
222         
223         if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25)
224                 return -EINVAL;
225         frames = frames2frames[frames];
226         fps = frames2table[frames];
227         pEntry = &Nala_table[size][fps];
228         if (pEntry->alternate == 0)
229                 return -EINVAL;
230
231         if (pEntry->compressed && pdev->decompressor == NULL)
232                 return -ENOENT; /* Not supported. */
233
234         memcpy(buf, pEntry->mode, 3);   
235         ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3);
236         if (ret < 0)
237                 return ret;
238         if (pEntry->compressed)
239                 pdev->decompressor->init(pdev->release, buf, pdev->decompress_data);
240                 
241         /* Set various parameters */
242         pdev->vframes = frames;
243         pdev->vsize = size;
244         pdev->valternate = pEntry->alternate;
245         pdev->image = pwc_image_sizes[size];
246         pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2;
247         if (pEntry->compressed) {
248                 if (pdev->release < 5) { /* 4 fold compression */
249                         pdev->vbandlength = 528;
250                         pdev->frame_size /= 4;
251                 }
252                 else {
253                         pdev->vbandlength = 704;
254                         pdev->frame_size /= 3;
255                 }
256         }
257         else
258                 pdev->vbandlength = 0;
259         return 0;
260 }
261
262
263 static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
264 {
265         unsigned char buf[13];
266         struct Timon_table_entry *pChoose;
267         int ret, fps;
268
269         if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
270                 return -EINVAL;
271         if (size == PSZ_VGA && frames > 15)
272                 return -EINVAL;
273         fps = (frames / 5) - 1;
274         
275         /* Find a supported framerate with progressively higher compression ratios
276            if the preferred ratio is not available.
277         */
278         pChoose = NULL;
279         if (pdev->decompressor == NULL) {
280 #if PWC_DEBUG   
281                 Debug("Trying to find uncompressed mode.\n");
282 #endif
283                 pChoose = &Timon_table[size][fps][0];
284         }
285         else {
286                 while (compression <= 3) {
287                         pChoose = &Timon_table[size][fps][compression];
288                         if (pChoose->alternate != 0)
289                                 break;
290                         compression++;  
291                 }
292         }
293         if (pChoose == NULL || pChoose->alternate == 0)
294                 return -ENOENT; /* Not supported. */
295
296         memcpy(buf, pChoose->mode, 13);
297         if (snapshot)
298                 buf[0] |= 0x80;
299         ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 13);
300         if (ret < 0)
301                 return ret;
302
303         if (pChoose->bandlength > 0)
304                 pdev->decompressor->init(pdev->release, buf, pdev->decompress_data);
305         
306         /* Set various parameters */
307         pdev->vframes = frames;
308         pdev->vsize = size;
309         pdev->vsnapshot = snapshot;
310         pdev->valternate = pChoose->alternate;
311         pdev->image = pwc_image_sizes[size];
312         pdev->vbandlength = pChoose->bandlength;
313         if (pChoose->bandlength > 0) 
314                 pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4;
315         else
316                 pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
317         return 0;
318 }
319
320
321 static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
322 {
323         struct Kiara_table_entry *pChoose;
324         int fps, ret;
325         unsigned char buf[12];
326         
327         if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
328                 return -EINVAL;
329         if (size == PSZ_VGA && frames > 15)
330                 return -EINVAL;
331         fps = (frames / 5) - 1;
332         
333         /* Find a supported framerate with progressively higher compression ratios
334            if the preferred ratio is not available.
335         */
336         pChoose = NULL;
337         if (pdev->decompressor == NULL) {
338 #if PWC_DEBUG   
339                 Debug("Trying to find uncompressed mode.\n");
340 #endif          
341                 pChoose = &Kiara_table[size][fps][0];
342         }
343         else {
344                 while (compression <= 3) {
345                         pChoose = &Kiara_table[size][fps][compression];
346                         if (pChoose->alternate != 0)
347                                 break;
348                         compression++;  
349                 }
350         }
351         if (pChoose == NULL || pChoose->alternate == 0)
352                 return -ENOENT; /* Not supported. */
353
354         /* usb_control_msg won't take staticly allocated arrays as argument?? */
355         memcpy(buf, pChoose->mode, 12);
356         if (snapshot)
357                 buf[0] |= 0x80;
358
359         /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */
360         ret = send_video_command(pdev->udev, 4 /* pdev->vendpoint */, buf, 12);
361         if (ret < 0)
362                 return ret;
363
364         if (pChoose->bandlength > 0)
365                 pdev->decompressor->init(pdev->release, buf, pdev->decompress_data);
366                 
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 (pChoose->bandlength > 0)
375                 pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4;
376         else 
377                 pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
378         pdev->frame_size += (pdev->frame_header_size + pdev->frame_trailer_size);
379         return 0;
380 }
381
382
383 /**
384    @pdev: device structure
385    @width: viewport width
386    @height: viewport height
387    @frame: framerate, in fps
388    @compression: preferred compression ratio
389    @snapshot: snapshot mode or streaming
390  */
391 int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot)
392 {
393         int ret, size;
394         
395         size = pwc_decode_size(pdev, width, height);
396         if (size < 0) {
397                 Debug("Could not find suitable size.\n");
398                 return -ERANGE;
399         }
400         ret = -EINVAL;  
401         switch(pdev->type) {
402         case 645:
403         case 646:
404                 ret = set_video_mode_Nala(pdev, size, frames);
405                 break;
406
407         case 675:
408         case 680:
409         case 690:
410                 ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
411                 break;
412                 
413         case 730:
414         case 740:
415         case 750:
416                 ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot);
417                 break;
418         }
419         if (ret < 0) {
420                 if (ret == -ENOENT)
421                         Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames);
422                 else {
423                         Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
424                         return ret;
425                 }
426         }
427         pdev->view.x = width;
428         pdev->view.y = height;
429         pwc_set_image_buffer_size(pdev);
430         Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d, palette = %d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y, pdev->vpalette);
431         return 0;
432 }
433
434
435 void pwc_set_image_buffer_size(struct pwc_device *pdev)
436 {
437         int factor, i, filler = 0;
438
439         switch(pdev->vpalette) {
440         case VIDEO_PALETTE_RGB32 | 0x80:
441         case VIDEO_PALETTE_RGB32:
442                 factor = 16;
443                 filler = 0;
444                 break;
445         case VIDEO_PALETTE_RGB24 | 0x80:
446         case VIDEO_PALETTE_RGB24:
447                 factor = 12;
448                 filler = 0;
449                 break;
450         case VIDEO_PALETTE_YUYV:
451         case VIDEO_PALETTE_YUV422:
452                 factor = 8;
453                 filler = 128;
454                 break;
455         case VIDEO_PALETTE_YUV420:
456         case VIDEO_PALETTE_YUV420P:
457                 factor = 6;
458                 filler = 128;
459                 break;
460 #if PWC_DEBUG           
461         case VIDEO_PALETTE_RAW:
462                 pdev->image.size = pdev->frame_size;
463                 pdev->view.size = pdev->frame_size;
464                 return;
465                 break;
466 #endif  
467         default:
468                 factor = 0;
469                 break;
470         }
471
472         /* Set sizes in bytes */
473         pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
474         pdev->view.size  = pdev->view.x  * pdev->view.y  * factor / 4;
475
476         /* Align offset, or you'll get some very weird results in
477            YUV420 mode... x must be multiple of 4 (to get the Y's in 
478            place), and y even (or you'll mixup U & V). This is less of a
479            problem for YUV420P.
480          */
481         pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
482         pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
483         
484         /* Fill buffers with gray or black */
485         for (i = 0; i < MAX_IMAGES; i++) {
486                 if (pdev->image_ptr[i] != NULL)
487                         memset(pdev->image_ptr[i], filler, pdev->view.size);
488         }
489 }
490
491
492 #ifdef __KERNEL__
493 /* BRIGHTNESS */
494
495 int pwc_get_brightness(struct pwc_device *pdev)
496 {
497         char buf;
498         int ret;
499         
500         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
501                 GET_LUM_CTL,
502                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
503                 BRIGHTNESS_FORMATTER,
504                 pdev->vcinterface,
505                 &buf, 1, HZ / 2);
506         if (ret < 0)
507                 return ret;
508         return buf << 9;
509 }
510
511 int pwc_set_brightness(struct pwc_device *pdev, int value)
512 {
513         char buf;
514
515         if (value < 0)
516                 value = 0;
517         if (value > 0xffff)
518                 value = 0xffff;
519         buf = (value >> 9) & 0x7f;
520         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
521                 SET_LUM_CTL,
522                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
523                 BRIGHTNESS_FORMATTER,
524                 pdev->vcinterface,
525                 &buf, 1, HZ / 2);
526 }
527
528 /* CONTRAST */
529
530 int pwc_get_contrast(struct pwc_device *pdev)
531 {
532         char buf;
533         int ret;
534         
535         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
536                 GET_LUM_CTL,
537                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
538                 CONTRAST_FORMATTER,
539                 pdev->vcinterface,
540                 &buf, 1, HZ / 2);
541         if (ret < 0)
542                 return ret;
543         return buf << 10;
544 }
545
546 int pwc_set_contrast(struct pwc_device *pdev, int value)
547 {
548         char buf;
549
550         if (value < 0)
551                 value = 0;
552         if (value > 0xffff)
553                 value = 0xffff;
554         buf = (value >> 10) & 0x3f;
555         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
556                 SET_LUM_CTL,
557                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
558                 CONTRAST_FORMATTER,
559                 pdev->vcinterface,
560                 &buf, 1, HZ / 2);
561 }
562
563 /* GAMMA */
564
565 int pwc_get_gamma(struct pwc_device *pdev)
566 {
567         char buf;
568         int ret;
569         
570         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
571                 GET_LUM_CTL,
572                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
573                 GAMMA_FORMATTER,
574                 pdev->vcinterface,
575                 &buf, 1, HZ / 2);
576         if (ret < 0)
577                 return ret;
578         return buf << 11;
579 }
580
581 int pwc_set_gamma(struct pwc_device *pdev, int value)
582 {
583         char buf;
584
585         if (value < 0)
586                 value = 0;
587         if (value > 0xffff)
588                 value = 0xffff;
589         buf = (value >> 11) & 0x1f;
590         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
591                 SET_LUM_CTL,
592                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
593                 GAMMA_FORMATTER,
594                 pdev->vcinterface,
595                 &buf, 1, HZ / 2);
596 }
597
598
599 /* SATURATION */
600
601 int pwc_get_saturation(struct pwc_device *pdev)
602 {
603         char buf;
604         int ret;
605
606         if (pdev->type < 730)
607                 return -1;
608         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
609                 GET_CHROM_CTL,
610                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
611                 SATURATION_MODE_FORMATTER1,
612                 pdev->vcinterface,
613                 &buf, 1, HZ / 2);
614         if (ret < 0)
615                 return ret;
616         return 32768 + buf * 327;
617 }
618
619 int pwc_set_saturation(struct pwc_device *pdev, int value)
620 {
621         char buf;
622
623         if (pdev->type < 730)
624                 return -EINVAL;
625         if (value < 0)
626                 value = 0;
627         if (value > 0xffff)
628                 value = 0xffff;
629         /* saturation ranges from -100 to +100 */
630         buf = (value - 32768) / 327;
631         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
632                 SET_CHROM_CTL,
633                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
634                 SATURATION_MODE_FORMATTER1,
635                 pdev->vcinterface,
636                 &buf, 1, HZ / 2);
637 }
638
639 /* AGC */
640
641 static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
642 {
643         char buf;
644         int ret;
645         
646         if (mode)
647                 buf = 0x0; /* auto */
648         else
649                 buf = 0xff; /* fixed */
650
651         ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
652                 SET_LUM_CTL,
653                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
654                 AGC_MODE_FORMATTER,
655                 pdev->vcinterface,
656                 &buf, 1, HZ / 2);
657         
658         if (!mode && ret >= 0) {
659                 if (value < 0)
660                         value = 0;
661                 if (value > 0xffff)
662                         value = 0xffff;
663                 buf = (value >> 10) & 0x3F;
664                 ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
665                         SET_LUM_CTL,
666                         USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
667                         PRESET_AGC_FORMATTER,
668                         pdev->vcinterface,
669                         &buf, 1, HZ / 2);
670         }
671         if (ret < 0)
672                 return ret;
673         return 0;
674 }
675
676 static inline int pwc_get_agc(struct pwc_device *pdev, int *value)
677 {
678         unsigned char buf;
679         int ret;
680         
681         ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
682                 GET_LUM_CTL,
683                 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
684                 AGC_MODE_FORMATTER,
685                 pdev->vcinterface,
686                 &buf, 1, HZ / 2);
687         if (ret < 0)
688                 return ret;
689
690         if (buf != 0) { /* fixed */
691                 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
692                         GET_LUM_CTL,
693                         USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
694                         PRESET_AGC_FORMATTER,
695                         pdev->vcinterface,
696                         &buf, 1, HZ / 2);
697                 if (ret < 0)
698                         return ret;
699                 if (buf > 0x3F)
700                         buf = 0x3F;
701                 *value = (buf << 10);           
702         }
703         else { /* auto */
704                 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
705                         GET_STATUS_CTL,
706                         USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
707                         READ_AGC_FORMATTER,
708                         pdev->vcinterface,
709                         &buf, 1, HZ / 2);
710                 if (ret < 0)
711                         return ret;
712                 /* Gah... this value ranges from 0x00 ... 0x9F */
713                 if (buf > 0x9F)
714                         buf = 0x9F;
715                 *value = -(48 + buf * 409);
716         }
717
718         return 0;
719 }
720
721 static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
722 {
723         char buf[2];
724         int speed, ret;
725
726
727         if (mode)
728                 buf[0] = 0x0;   /* auto */
729         else
730                 buf[0] = 0xff; /* fixed */
731         
732         ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
733                 SET_LUM_CTL,
734                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
735                 SHUTTER_MODE_FORMATTER,
736                 pdev->vcinterface,
737                 buf, 1, HZ / 2);
738
739         if (!mode && ret >= 0) {
740                 if (value < 0)
741                         value = 0;
742                 if (value > 0xffff)
743                         value = 0xffff;
744                 switch(pdev->type) {
745                 case 675:
746                 case 680:
747                 case 690:
748                         /* speed ranges from 0x0 to 0x290 (656) */
749                         speed = (value / 100);
750                         buf[1] = speed >> 8;
751                         buf[0] = speed & 0xff;
752                         break;
753                 case 730:
754                 case 740:
755                 case 750:
756                         /* speed seems to range from 0x0 to 0xff */
757                         buf[1] = 0;
758                         buf[0] = value >> 8;
759                         break;
760                 }
761
762                 ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
763                         SET_LUM_CTL,
764                         USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
765                         PRESET_SHUTTER_FORMATTER,
766                         pdev->vcinterface,
767                         &buf, 2, HZ / 2);
768         }
769         return ret;
770 }       
771
772
773 /* POWER */
774
775 int pwc_camera_power(struct pwc_device *pdev, int power)
776 {
777         char buf;
778
779         if (pdev->type < 675 || pdev->release < 6)
780                 return 0;       /* Not supported by Nala or Timon < release 6 */
781
782         if (power)
783                 buf = 0x00; /* active */
784         else
785                 buf = 0xFF; /* power save */
786         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
787                 SET_STATUS_CTL,
788                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
789                 SET_POWER_SAVE_MODE_FORMATTER,
790                 pdev->vcinterface,
791                 &buf, 1, HZ / 2);
792 }
793
794
795
796 /* private calls */
797
798 static inline int pwc_restore_user(struct pwc_device *pdev)
799 {
800         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
801                 SET_STATUS_CTL,
802                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
803                 RESTORE_USER_DEFAULTS_FORMATTER,
804                 pdev->vcinterface,
805                 NULL, 0, HZ / 2);
806 }
807
808 static inline int pwc_save_user(struct pwc_device *pdev)
809 {
810         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
811                 SET_STATUS_CTL,
812                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
813                 SAVE_USER_DEFAULTS_FORMATTER,
814                 pdev->vcinterface,
815                 NULL, 0, HZ / 2);
816 }
817
818 static inline int pwc_restore_factory(struct pwc_device *pdev)
819 {
820         return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
821                 SET_STATUS_CTL,
822                 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
823                 RESTORE_FACTORY_DEFAULTS_FORMATTER,
824                 pdev->vcinterface,
825                 NULL, 0, HZ / 2);
826 }
827
828 int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
829 {
830         switch(cmd) {
831         case VIDIOCPWCRUSER:
832         {
833                 if (pwc_restore_user(pdev))
834                         return -EINVAL;
835                 break;
836         }
837         
838         case VIDIOCPWCSUSER:
839         {
840                 if (pwc_save_user(pdev))
841                         return -EINVAL;
842                 break;
843         }
844                 
845         case VIDIOCPWCFACTORY:
846         {
847                 if (pwc_restore_factory(pdev))
848                         return -EINVAL;
849                 break;
850         }
851         
852         case VIDIOCPWCSCQUAL:
853         {       
854                 int qual, ret;
855
856                 if (copy_from_user(&qual, arg, sizeof(int)))
857                         return -EFAULT;
858                         
859                 if (qual < 0 || qual > 3)
860                         return -EINVAL;
861                 ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, qual, pdev->vsnapshot);
862                 if (ret < 0)
863                         return ret;
864                 pdev->vcompression = qual;
865                 break;
866         }
867         
868         case VIDIOCPWCGCQUAL:
869         {
870                 if (copy_to_user(arg, &pdev->vcompression, sizeof(int)))
871                         return -EFAULT;
872                 break;
873         }
874
875         case VIDIOCPWCSAGC:
876         {
877                 int agc;
878                 
879                 if (copy_from_user(&agc, arg, sizeof(agc)))
880                         return -EFAULT; 
881                 else {
882                         if (pwc_set_agc(pdev, agc < 0 ? 1 : 0, agc))
883                                 return -EINVAL;
884                 }
885                 break;
886         }
887         
888         case VIDIOCPWCGAGC:
889         {
890                 int agc;
891                 
892                 if (pwc_get_agc(pdev, &agc))
893                         return -EINVAL;
894                 if (copy_to_user(arg, &agc, sizeof(agc)))
895                         return -EFAULT;
896                 break;
897         }
898         
899         case VIDIOCPWCSSHUTTER:
900         {
901                 int shutter_speed, ret;
902
903                 if (copy_from_user(&shutter_speed, arg, sizeof(shutter_speed)))
904                         return -EFAULT;
905                 else {
906                         ret = pwc_set_shutter_speed(pdev, shutter_speed < 0 ? 1 : 0, shutter_speed);
907                         if (ret < 0)
908                                 return ret;
909                 }
910                 break;
911         }
912         
913         default:
914                 return -ENOIOCTLCMD;
915                 break;
916         }
917         return 0;
918 }
919
920 #endif