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