• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/media/video/pwc/
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-2006 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
45#include "pwc.h"
46#include "pwc-uncompress.h"
47#include "pwc-kiara.h"
48#include "pwc-timon.h"
49#include "pwc-dec1.h"
50#include "pwc-dec23.h"
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
61#define GET_XX_CTL			0x09
62#define SET_XX_CTL			0x0A
63#define GET_XY_CTL			0x0B
64#define SET_XY_CTL			0x0C
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
101#define GET_STATUS_B00				0x0B00
102#define SENSOR_TYPE_FORMATTER1			0x0C00
103#define GET_STATUS_3000				0x3000
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
108#define LOWLIGHT				0x3500
109#define GET_STATUS_3600				0x3600
110#define SENSOR_TYPE_FORMATTER2			0x3700
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 */
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
124static const char *size2name[PSZ_MAX] =
125{
126	"subQCIF",
127	"QSIF",
128	"QCIF",
129	"SIF",
130	"CIF",
131	"VGA",
132};
133
134/********/
135
136/* Entries for the Nala (645/646) camera; the Nala doesn't have compression
137   preferences, so you either get compressed or non-compressed streams.
138
139   An alternate value of 0 means this mode is not available at all.
140 */
141
142#define PWC_FPS_MAX_NALA 8
143
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
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] =
154{
155#include "pwc-nala.h"
156};
157
158static void pwc_set_image_buffer_size(struct pwc_device *pdev);
159
160/****************************************************************************/
161
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	}
174
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);
181
182	kfree(kbuf);
183	return rc;
184}
185
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}
205
206static inline int send_video_command(struct pwc_device *pdev,
207	int index, void *buf, int buflen)
208{
209	return _send_control_msg(pdev,
210		SET_EP_STREAM_CTL,
211		VIDEO_OUTPUT_CONTROL_FORMATTER,
212		index,
213		buf, buflen, 1000);
214}
215
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
223
224
225static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
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  */
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    */
239	};
240	int frames2table[31] =
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	};
249
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
258	memcpy(buf, pEntry->mode, 3);
259	ret = send_video_command(pdev, pdev->vendpoint, buf, 3);
260	if (ret < 0) {
261		PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret);
262		return ret;
263	}
264	if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW)
265		pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data);
266
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
292static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
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;
320	ret = send_video_command(pdev, pdev->vendpoint, buf, 13);
321	if (ret < 0)
322		return ret;
323
324	if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
325		pwc_dec23_init(pdev, pdev->type, buf);
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
345static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
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 */
359	if (size == PSZ_VGA && frames == 5 && snapshot && pdev->vpalette == VIDEO_PALETTE_RAW)
360	{
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
364		*/
365		PWC_DEBUG_SIZE("Choosing VGA/5 BAYER mode.\n");
366		pChoose = &RawEntry;
367	}
368	else
369	{
370		/* Find a supported framerate with progressively higher compression ratios
371		   if the preferred ratio is not available.
372		   Skip this step when using RAW modes.
373		*/
374		snapshot = 0;
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
385	PWC_TRACE("Using alternate setting %d.\n", pChoose->alternate);
386
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 */
393	ret = send_video_command(pdev, 4 /* pdev->vendpoint */, buf, 12);
394	if (ret < 0)
395		return ret;
396
397	if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
398		pwc_dec23_init(pdev, pdev->type, buf);
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;
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);
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{
430	int ret, size;
431
432	PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette);
433	size = pwc_decode_size(pdev, width, height);
434	if (size < 0) {
435		PWC_DEBUG_MODULE("Could not find suitable size.\n");
436		return -ERANGE;
437	}
438	PWC_TRACE("decode_size = %d.\n", size);
439
440	if (DEVICE_USE_CODEC1(pdev->type)) {
441		ret = set_video_mode_Nala(pdev, size, frames);
442
443	} else if (DEVICE_USE_CODEC3(pdev->type)) {
444		ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot);
445
446	} else {
447		ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
448	}
449	if (ret < 0) {
450		PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
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);
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);
458	return 0;
459}
460
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
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
522	/* for PALETTE_YUV420P */
523	switch(pdev->vpalette)
524	{
525	case VIDEO_PALETTE_YUV420P:
526		factor = 6;
527		break;
528	case VIDEO_PALETTE_RAW:
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
557
558/* BRIGHTNESS */
559
560int pwc_get_brightness(struct pwc_device *pdev)
561{
562	char buf;
563	int ret;
564
565	ret = recv_control_msg(pdev,
566		GET_LUM_CTL, BRIGHTNESS_FORMATTER, &buf, sizeof(buf));
567	if (ret < 0)
568		return ret;
569	return buf;
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;
581	return send_control_msg(pdev,
582		SET_LUM_CTL, BRIGHTNESS_FORMATTER, &buf, sizeof(buf));
583}
584
585/* CONTRAST */
586
587int pwc_get_contrast(struct pwc_device *pdev)
588{
589	char buf;
590	int ret;
591
592	ret = recv_control_msg(pdev,
593		GET_LUM_CTL, CONTRAST_FORMATTER, &buf, sizeof(buf));
594	if (ret < 0)
595		return ret;
596	return buf;
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;
608	return send_control_msg(pdev,
609		SET_LUM_CTL, CONTRAST_FORMATTER, &buf, sizeof(buf));
610}
611
612/* GAMMA */
613
614int pwc_get_gamma(struct pwc_device *pdev)
615{
616	char buf;
617	int ret;
618
619	ret = recv_control_msg(pdev,
620		GET_LUM_CTL, GAMMA_FORMATTER, &buf, sizeof(buf));
621	if (ret < 0)
622		return ret;
623	return buf;
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;
635	return send_control_msg(pdev,
636		SET_LUM_CTL, GAMMA_FORMATTER, &buf, sizeof(buf));
637}
638
639
640/* SATURATION */
641
642/* return a value between [-100 , 100] */
643int pwc_get_saturation(struct pwc_device *pdev, int *value)
644{
645	char buf;
646	int ret, saturation_register;
647
648	if (pdev->type < 675)
649		return -EINVAL;
650	if (pdev->type < 730)
651		saturation_register = SATURATION_MODE_FORMATTER2;
652	else
653		saturation_register = SATURATION_MODE_FORMATTER1;
654	ret = recv_control_msg(pdev,
655		GET_CHROM_CTL, saturation_register, &buf, sizeof(buf));
656	if (ret < 0)
657		return ret;
658	*value = (signed)buf;
659	return 0;
660}
661
662/* @param value saturation color between [-100 , 100] */
663int pwc_set_saturation(struct pwc_device *pdev, int value)
664{
665	char buf;
666	int saturation_register;
667
668	if (pdev->type < 675)
669		return -EINVAL;
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;
678	return send_control_msg(pdev,
679		SET_CHROM_CTL, saturation_register, &buf, sizeof(buf));
680}
681
682/* AGC */
683
684int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
685{
686	char buf;
687	int ret;
688
689	if (mode)
690		buf = 0x0; /* auto */
691	else
692		buf = 0xff; /* fixed */
693
694	ret = send_control_msg(pdev,
695		SET_LUM_CTL, AGC_MODE_FORMATTER, &buf, sizeof(buf));
696
697	if (!mode && ret >= 0) {
698		if (value < 0)
699			value = 0;
700		if (value > 0xffff)
701			value = 0xffff;
702		buf = (value >> 10) & 0x3F;
703		ret = send_control_msg(pdev,
704			SET_LUM_CTL, PRESET_AGC_FORMATTER, &buf, sizeof(buf));
705	}
706	if (ret < 0)
707		return ret;
708	return 0;
709}
710
711int pwc_get_agc(struct pwc_device *pdev, int *value)
712{
713	unsigned char buf;
714	int ret;
715
716	ret = recv_control_msg(pdev,
717		GET_LUM_CTL, AGC_MODE_FORMATTER, &buf, sizeof(buf));
718	if (ret < 0)
719		return ret;
720
721	if (buf != 0) { /* fixed */
722		ret = recv_control_msg(pdev,
723			GET_LUM_CTL, PRESET_AGC_FORMATTER, &buf, sizeof(buf));
724		if (ret < 0)
725			return ret;
726		if (buf > 0x3F)
727			buf = 0x3F;
728		*value = (buf << 10);
729	}
730	else { /* auto */
731		ret = recv_control_msg(pdev,
732			GET_STATUS_CTL, READ_AGC_FORMATTER, &buf, sizeof(buf));
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
744int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
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 */
754
755	ret = send_control_msg(pdev,
756		SET_LUM_CTL, SHUTTER_MODE_FORMATTER, &buf, 1);
757
758	if (!mode && ret >= 0) {
759		if (value < 0)
760			value = 0;
761		if (value > 0xffff)
762			value = 0xffff;
763
764		if (DEVICE_USE_CODEC2(pdev->type)) {
765			/* speed ranges from 0x0 to 0x290 (656) */
766			speed = (value / 100);
767			buf[1] = speed >> 8;
768			buf[0] = speed & 0xff;
769		} else if (DEVICE_USE_CODEC3(pdev->type)) {
770			/* speed seems to range from 0x0 to 0xff */
771			buf[1] = 0;
772			buf[0] = value >> 8;
773		}
774
775		ret = send_control_msg(pdev,
776			SET_LUM_CTL, PRESET_SHUTTER_FORMATTER,
777			&buf, sizeof(buf));
778	}
779	return ret;
780}
781
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
788	ret = recv_control_msg(pdev,
789		GET_STATUS_CTL, READ_SHUTTER_FORMATTER, &buf, sizeof(buf));
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
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 */
816	return send_control_msg(pdev,
817		SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER,
818		&buf, sizeof(buf));
819}
820
821
822
823/* private calls */
824
825int pwc_restore_user(struct pwc_device *pdev)
826{
827	return send_control_msg(pdev,
828		SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, NULL, 0);
829}
830
831int pwc_save_user(struct pwc_device *pdev)
832{
833	return send_control_msg(pdev,
834		SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, NULL, 0);
835}
836
837int pwc_restore_factory(struct pwc_device *pdev)
838{
839	return send_control_msg(pdev,
840		SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, NULL, 0);
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
854  */
855int pwc_set_awb(struct pwc_device *pdev, int mode)
856{
857	char buf;
858	int ret;
859
860	if (mode < 0)
861	    mode = 0;
862
863	if (mode > 4)
864	    mode = 4;
865
866	buf = mode & 0x07; /* just the lowest three bits */
867
868	ret = send_control_msg(pdev,
869		SET_CHROM_CTL, WB_MODE_FORMATTER, &buf, sizeof(buf));
870
871	if (ret < 0)
872		return ret;
873	return 0;
874}
875
876int pwc_get_awb(struct pwc_device *pdev)
877{
878	unsigned char buf;
879	int ret;
880
881	ret = recv_control_msg(pdev,
882		GET_CHROM_CTL, WB_MODE_FORMATTER, &buf, sizeof(buf));
883
884	if (ret < 0)
885		return ret;
886	return buf;
887}
888
889int pwc_set_red_gain(struct pwc_device *pdev, int value)
890{
891	unsigned char buf;
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;
899	return send_control_msg(pdev,
900		SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER,
901		&buf, sizeof(buf));
902}
903
904int pwc_get_red_gain(struct pwc_device *pdev, int *value)
905{
906	unsigned char buf;
907	int ret;
908
909	ret = recv_control_msg(pdev,
910		GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER,
911		&buf, sizeof(buf));
912	if (ret < 0)
913	    return ret;
914	*value = buf << 8;
915	return 0;
916}
917
918
919int pwc_set_blue_gain(struct pwc_device *pdev, int value)
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;
929	return send_control_msg(pdev,
930		SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER,
931		&buf, sizeof(buf));
932}
933
934int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
935{
936	unsigned char buf;
937	int ret;
938
939	ret = recv_control_msg(pdev,
940		GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER,
941		&buf, sizeof(buf));
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
950   internal red/blue gains, which may be different from the manual
951   gains set or read above.
952 */
953static int pwc_read_red_gain(struct pwc_device *pdev, int *value)
954{
955	unsigned char buf;
956	int ret;
957
958	ret = recv_control_msg(pdev,
959		GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, &buf, sizeof(buf));
960	if (ret < 0)
961		return ret;
962	*value = buf << 8;
963	return 0;
964}
965
966static int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
967{
968	unsigned char buf;
969	int ret;
970
971	ret = recv_control_msg(pdev,
972		GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, &buf, sizeof(buf));
973	if (ret < 0)
974		return ret;
975	*value = buf << 8;
976	return 0;
977}
978
979
980static int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
981{
982	unsigned char buf;
983
984	/* useful range is 0x01..0x20 */
985	buf = speed / 0x7f0;
986	return send_control_msg(pdev,
987		SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, &buf, sizeof(buf));
988}
989
990static int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
991{
992	unsigned char buf;
993	int ret;
994
995	ret = recv_control_msg(pdev,
996		GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, &buf, sizeof(buf));
997	if (ret < 0)
998		return ret;
999	*value = buf * 0x7f0;
1000	return 0;
1001}
1002
1003
1004static int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
1005{
1006	unsigned char buf;
1007
1008	/* useful range is 0x01..0x3F */
1009	buf = (delay >> 10);
1010	return send_control_msg(pdev,
1011		SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, &buf, sizeof(buf));
1012}
1013
1014static int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
1015{
1016	unsigned char buf;
1017	int ret;
1018
1019	ret = recv_control_msg(pdev,
1020		GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, &buf, sizeof(buf));
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
1048	return send_control_msg(pdev,
1049		SET_STATUS_CTL, LED_FORMATTER, &buf, sizeof(buf));
1050}
1051
1052static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
1053{
1054	unsigned char buf[2];
1055	int ret;
1056
1057	if (pdev->type < 730) {
1058		*on_value = -1;
1059		*off_value = -1;
1060		return 0;
1061	}
1062
1063	ret = recv_control_msg(pdev,
1064		GET_STATUS_CTL, LED_FORMATTER, &buf, sizeof(buf));
1065	if (ret < 0)
1066		return ret;
1067	*on_value = buf[0] * 100;
1068	*off_value = buf[1] * 100;
1069	return 0;
1070}
1071
1072int pwc_set_contour(struct pwc_device *pdev, int contour)
1073{
1074	unsigned char buf;
1075	int ret;
1076
1077	if (contour < 0)
1078		buf = 0xff; /* auto contour on */
1079	else
1080		buf = 0x0; /* auto contour off */
1081	ret = send_control_msg(pdev,
1082		SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, &buf, sizeof(buf));
1083	if (ret < 0)
1084		return ret;
1085
1086	if (contour < 0)
1087		return 0;
1088	if (contour > 0xffff)
1089		contour = 0xffff;
1090
1091	buf = (contour >> 10); /* contour preset is [0..3f] */
1092	ret = send_control_msg(pdev,
1093		SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, &buf, sizeof(buf));
1094	if (ret < 0)
1095		return ret;
1096	return 0;
1097}
1098
1099int pwc_get_contour(struct pwc_device *pdev, int *contour)
1100{
1101	unsigned char buf;
1102	int ret;
1103
1104	ret = recv_control_msg(pdev,
1105		GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, &buf, sizeof(buf));
1106	if (ret < 0)
1107		return ret;
1108
1109	if (buf == 0) {
1110		/* auto mode off, query current preset value */
1111		ret = recv_control_msg(pdev,
1112			GET_LUM_CTL, PRESET_CONTOUR_FORMATTER,
1113			&buf, sizeof(buf));
1114		if (ret < 0)
1115			return ret;
1116		*contour = buf << 10;
1117	}
1118	else
1119		*contour = -1;
1120	return 0;
1121}
1122
1123
1124int pwc_set_backlight(struct pwc_device *pdev, int backlight)
1125{
1126	unsigned char buf;
1127
1128	if (backlight)
1129		buf = 0xff;
1130	else
1131		buf = 0x0;
1132	return send_control_msg(pdev,
1133		SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER,
1134		&buf, sizeof(buf));
1135}
1136
1137int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
1138{
1139	int ret;
1140	unsigned char buf;
1141
1142	ret = recv_control_msg(pdev,
1143		GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER,
1144		&buf, sizeof(buf));
1145	if (ret < 0)
1146		return ret;
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;
1159	return send_control_msg(pdev,
1160		SET_CHROM_CTL, COLOUR_MODE_FORMATTER, &buf, sizeof(buf));
1161}
1162
1163int pwc_get_colour_mode(struct pwc_device *pdev, int *colour)
1164{
1165	int ret;
1166	unsigned char buf;
1167
1168	ret = recv_control_msg(pdev,
1169		GET_CHROM_CTL, COLOUR_MODE_FORMATTER, &buf, sizeof(buf));
1170	if (ret < 0)
1171		return ret;
1172	*colour = !!buf;
1173	return 0;
1174}
1175
1176
1177int pwc_set_flicker(struct pwc_device *pdev, int flicker)
1178{
1179	unsigned char buf;
1180
1181	if (flicker)
1182		buf = 0xff;
1183	else
1184		buf = 0x0;
1185	return send_control_msg(pdev,
1186		SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, &buf, sizeof(buf));
1187}
1188
1189int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
1190{
1191	int ret;
1192	unsigned char buf;
1193
1194	ret = recv_control_msg(pdev,
1195		GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, &buf, sizeof(buf));
1196	if (ret < 0)
1197		return ret;
1198	*flicker = !!buf;
1199	return 0;
1200}
1201
1202int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
1203{
1204	unsigned char buf;
1205
1206	if (noise < 0)
1207		noise = 0;
1208	if (noise > 3)
1209		noise = 3;
1210	buf = noise;
1211	return send_control_msg(pdev,
1212		SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER,
1213		&buf, sizeof(buf));
1214}
1215
1216int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
1217{
1218	int ret;
1219	unsigned char buf;
1220
1221	ret = recv_control_msg(pdev,
1222		GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER,
1223		&buf, sizeof(buf));
1224	if (ret < 0)
1225		return ret;
1226	*noise = buf;
1227	return 0;
1228}
1229
1230static int _pwc_mpt_reset(struct pwc_device *pdev, int flags)
1231{
1232	unsigned char buf;
1233
1234	buf = flags & 0x03; // only lower two bits are currently used
1235	return send_control_msg(pdev,
1236		SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, &buf, sizeof(buf));
1237}
1238
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)
1251{
1252	unsigned char buf[4];
1253
1254	/* set new relative angle; angles are expressed in degrees * 100,
1255	   but cam as .5 degree resolution, hence divide by 200. Also
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;
1265	return send_control_msg(pdev,
1266		SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, &buf, sizeof(buf));
1267}
1268
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)
1298{
1299	int ret;
1300	unsigned char buf[5];
1301
1302	ret = recv_control_msg(pdev,
1303		GET_MPT_CTL, PT_STATUS_FORMATTER, &buf, sizeof(buf));
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;
1317
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;
1324
1325	ret = recv_control_msg(pdev,
1326		GET_STATUS_CTL, request, &buf, sizeof(buf));
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
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
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
1359long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
1360{
1361	long ret = 0;
1362
1363	switch(cmd) {
1364	case VIDIOCPWCRUSER:
1365	{
1366		if (pwc_restore_user(pdev))
1367			ret = -EINVAL;
1368		break;
1369	}
1370
1371	case VIDIOCPWCSUSER:
1372	{
1373		if (pwc_save_user(pdev))
1374			ret = -EINVAL;
1375		break;
1376	}
1377
1378	case VIDIOCPWCFACTORY:
1379	{
1380		if (pwc_restore_factory(pdev))
1381			ret = -EINVAL;
1382		break;
1383	}
1384
1385	case VIDIOCPWCSCQUAL:
1386	{
1387		ARG_DEF(int, qual)
1388
1389		ARG_IN(qual)
1390		if (ARGR(qual) < 0 || ARGR(qual) > 3)
1391			ret = -EINVAL;
1392		else
1393			ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot);
1394		if (ret >= 0)
1395			pdev->vcompression = ARGR(qual);
1396		break;
1397	}
1398
1399	case VIDIOCPWCGCQUAL:
1400	{
1401		ARG_DEF(int, qual)
1402
1403		ARGR(qual) = pdev->vcompression;
1404		ARG_OUT(qual)
1405		break;
1406	}
1407
1408	case VIDIOCPWCPROBE:
1409	{
1410		ARG_DEF(struct pwc_probe, probe)
1411
1412		strcpy(ARGR(probe).name, pdev->vdev->name);
1413		ARGR(probe).type = pdev->type;
1414		ARG_OUT(probe)
1415		break;
1416	}
1417
1418	case VIDIOCPWCGSERIAL:
1419	{
1420		ARG_DEF(struct pwc_serial, serial)
1421
1422		strcpy(ARGR(serial).serial, pdev->serial);
1423		ARG_OUT(serial)
1424		break;
1425	}
1426
1427	case VIDIOCPWCSAGC:
1428	{
1429		ARG_DEF(int, agc)
1430
1431		ARG_IN(agc)
1432		if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc)))
1433			ret = -EINVAL;
1434		break;
1435	}
1436
1437	case VIDIOCPWCGAGC:
1438	{
1439		ARG_DEF(int, agc)
1440
1441		if (pwc_get_agc(pdev, ARGA(agc)))
1442			ret = -EINVAL;
1443		ARG_OUT(agc)
1444		break;
1445	}
1446
1447	case VIDIOCPWCSSHUTTER:
1448	{
1449		ARG_DEF(int, shutter_speed)
1450
1451		ARG_IN(shutter_speed)
1452		ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed));
1453		break;
1454	}
1455
1456	case VIDIOCPWCSAWB:
1457	{
1458		ARG_DEF(struct pwc_whitebalance, wb)
1459
1460		ARG_IN(wb)
1461		ret = pwc_set_awb(pdev, ARGR(wb).mode);
1462		if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) {
1463			pwc_set_red_gain(pdev, ARGR(wb).manual_red);
1464			pwc_set_blue_gain(pdev, ARGR(wb).manual_blue);
1465		}
1466		break;
1467	}
1468
1469	case VIDIOCPWCGAWB:
1470	{
1471		ARG_DEF(struct pwc_whitebalance, wb)
1472
1473		memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance));
1474		ARGR(wb).mode = pwc_get_awb(pdev);
1475		if (ARGR(wb).mode < 0)
1476			ret = -EINVAL;
1477		else {
1478			if (ARGR(wb).mode == PWC_WB_MANUAL) {
1479				ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red);
1480				if (ret < 0)
1481					break;
1482				ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue);
1483				if (ret < 0)
1484					break;
1485			}
1486			if (ARGR(wb).mode == PWC_WB_AUTO) {
1487				ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red);
1488				if (ret < 0)
1489					break;
1490				ret = pwc_read_blue_gain(pdev, &ARGR(wb).read_blue);
1491				if (ret < 0)
1492					break;
1493			}
1494		}
1495		ARG_OUT(wb)
1496		break;
1497	}
1498
1499	case VIDIOCPWCSAWBSPEED:
1500	{
1501		ARG_DEF(struct pwc_wb_speed, wbs)
1502
1503		if (ARGR(wbs).control_speed > 0) {
1504			ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed);
1505		}
1506		if (ARGR(wbs).control_delay > 0) {
1507			ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay);
1508		}
1509		break;
1510	}
1511
1512	case VIDIOCPWCGAWBSPEED:
1513	{
1514		ARG_DEF(struct pwc_wb_speed, wbs)
1515
1516		ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed);
1517		if (ret < 0)
1518			break;
1519		ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay);
1520		if (ret < 0)
1521			break;
1522		ARG_OUT(wbs)
1523		break;
1524	}
1525
1526	case VIDIOCPWCSLED:
1527	{
1528		ARG_DEF(struct pwc_leds, leds)
1529
1530		ARG_IN(leds)
1531		ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off);
1532		break;
1533	}
1534
1535
1536	case VIDIOCPWCGLED:
1537	{
1538		ARG_DEF(struct pwc_leds, leds)
1539
1540		ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off);
1541		ARG_OUT(leds)
1542		break;
1543	}
1544
1545	case VIDIOCPWCSCONTOUR:
1546	{
1547		ARG_DEF(int, contour)
1548
1549		ARG_IN(contour)
1550		ret = pwc_set_contour(pdev, ARGR(contour));
1551		break;
1552	}
1553
1554	case VIDIOCPWCGCONTOUR:
1555	{
1556		ARG_DEF(int, contour)
1557
1558		ret = pwc_get_contour(pdev, ARGA(contour));
1559		ARG_OUT(contour)
1560		break;
1561	}
1562
1563	case VIDIOCPWCSBACKLIGHT:
1564	{
1565		ARG_DEF(int, backlight)
1566
1567		ARG_IN(backlight)
1568		ret = pwc_set_backlight(pdev, ARGR(backlight));
1569		break;
1570	}
1571
1572	case VIDIOCPWCGBACKLIGHT:
1573	{
1574		ARG_DEF(int, backlight)
1575
1576		ret = pwc_get_backlight(pdev, ARGA(backlight));
1577		ARG_OUT(backlight)
1578		break;
1579	}
1580
1581	case VIDIOCPWCSFLICKER:
1582	{
1583		ARG_DEF(int, flicker)
1584
1585		ARG_IN(flicker)
1586		ret = pwc_set_flicker(pdev, ARGR(flicker));
1587		break;
1588	}
1589
1590	case VIDIOCPWCGFLICKER:
1591	{
1592		ARG_DEF(int, flicker)
1593
1594		ret = pwc_get_flicker(pdev, ARGA(flicker));
1595		ARG_OUT(flicker)
1596		break;
1597	}
1598
1599	case VIDIOCPWCSDYNNOISE:
1600	{
1601		ARG_DEF(int, dynnoise)
1602
1603		ARG_IN(dynnoise)
1604		ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise));
1605		break;
1606	}
1607
1608	case VIDIOCPWCGDYNNOISE:
1609	{
1610		ARG_DEF(int, dynnoise)
1611
1612		ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise));
1613		ARG_OUT(dynnoise);
1614		break;
1615	}
1616
1617	case VIDIOCPWCGREALSIZE:
1618	{
1619		ARG_DEF(struct pwc_imagesize, size)
1620
1621		ARGR(size).width = pdev->image.x;
1622		ARGR(size).height = pdev->image.y;
1623		ARG_OUT(size)
1624		break;
1625	}
1626
1627	case VIDIOCPWCMPTRESET:
1628	{
1629		if (pdev->features & FEATURE_MOTOR_PANTILT)
1630		{
1631			ARG_DEF(int, flags)
1632
1633			ARG_IN(flags)
1634			ret = pwc_mpt_reset(pdev, ARGR(flags));
1635		}
1636		else
1637		{
1638			ret = -ENXIO;
1639		}
1640		break;
1641	}
1642
1643	case VIDIOCPWCMPTGRANGE:
1644	{
1645		if (pdev->features & FEATURE_MOTOR_PANTILT)
1646		{
1647			ARG_DEF(struct pwc_mpt_range, range)
1648
1649			ARGR(range) = pdev->angle_range;
1650			ARG_OUT(range)
1651		}
1652		else
1653		{
1654			ret = -ENXIO;
1655		}
1656		break;
1657	}
1658
1659	case VIDIOCPWCMPTSANGLE:
1660	{
1661		int new_pan, new_tilt;
1662
1663		if (pdev->features & FEATURE_MOTOR_PANTILT)
1664		{
1665			ARG_DEF(struct pwc_mpt_angles, angles)
1666
1667			ARG_IN(angles)
1668			/* The camera can only set relative angles, so
1669			   do some calculations when getting an absolute angle .
1670			 */
1671			if (ARGR(angles).absolute)
1672			{
1673				new_pan  = ARGR(angles).pan;
1674				new_tilt = ARGR(angles).tilt;
1675			}
1676			else
1677			{
1678				new_pan  = pdev->pan_angle  + ARGR(angles).pan;
1679				new_tilt = pdev->tilt_angle + ARGR(angles).tilt;
1680			}
1681			ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
1682		}
1683		else
1684		{
1685			ret = -ENXIO;
1686		}
1687		break;
1688	}
1689
1690	case VIDIOCPWCMPTGANGLE:
1691	{
1692
1693		if (pdev->features & FEATURE_MOTOR_PANTILT)
1694		{
1695			ARG_DEF(struct pwc_mpt_angles, angles)
1696
1697			ARGR(angles).absolute = 1;
1698			ARGR(angles).pan  = pdev->pan_angle;
1699			ARGR(angles).tilt = pdev->tilt_angle;
1700			ARG_OUT(angles)
1701		}
1702		else
1703		{
1704			ret = -ENXIO;
1705		}
1706		break;
1707	}
1708
1709	case VIDIOCPWCMPTSTATUS:
1710	{
1711		if (pdev->features & FEATURE_MOTOR_PANTILT)
1712		{
1713			ARG_DEF(struct pwc_mpt_status, status)
1714
1715			ret = pwc_mpt_get_status(pdev, ARGA(status));
1716			ARG_OUT(status)
1717		}
1718		else
1719		{
1720			ret = -ENXIO;
1721		}
1722		break;
1723	}
1724
1725	case VIDIOCPWCGVIDCMD:
1726	{
1727		ARG_DEF(struct pwc_video_command, vcmd);
1728
1729		ARGR(vcmd).type = pdev->type;
1730		ARGR(vcmd).release = pdev->release;
1731		ARGR(vcmd).command_len = pdev->cmd_len;
1732		memcpy(&ARGR(vcmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
1733		ARGR(vcmd).bandlength = pdev->vbandlength;
1734		ARGR(vcmd).frame_size = pdev->frame_size;
1735		ARG_OUT(vcmd)
1736		break;
1737	}
1738	/*
1739	case VIDIOCPWCGVIDTABLE:
1740	{
1741		ARG_DEF(struct pwc_table_init_buffer, table);
1742		ARGR(table).len = pdev->cmd_len;
1743		memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size);
1744		ARG_OUT(table)
1745		break;
1746	}
1747	*/
1748
1749	default:
1750		ret = -ENOIOCTLCMD;
1751		break;
1752	}
1753
1754	if (ret > 0)
1755		return 0;
1756	return ret;
1757}
1758
1759
1760/* vim: set cinoptions= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
1761