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