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