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