11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Driver for Philips webcam
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Functions that send various control messages to the webcam, including
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   video modes.
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   (C) 1999-2003 Nemosoft Unv.
52b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard   (C) 2004-2006 Luc Saillard (luc@saillard.org)
66c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goede   (C) 2011 Hans de Goede <hdegoede@redhat.com>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   driver and thus may have bugs that are not present in the original version.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Please send bug reports and support requests to <luc@saillard.org>.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   driver and thus may have bugs that are not present in the original version.
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Please send bug reports and support requests to <luc@saillard.org>.
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   The decompression routines have been implemented by reverse-engineering the
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Nemosoft binary pwcx module. Caveat emptor.
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This program is free software; you can redistribute it and/or modify
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   it under the terms of the GNU General Public License as published by
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   the Free Software Foundation; either version 2 of the License, or
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   (at your option) any later version.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This program is distributed in the hope that it will be useful,
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   but WITHOUT ANY WARRANTY; without even the implied warranty of
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   GNU General Public License for more details.
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   You should have received a copy of the GNU General Public License
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   along with this program; if not, write to the Free Software
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Changes
35d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab   2001/08/03  Alvarado   Added methods for changing white balance and
36d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab			  red/green gains
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Control functions for the cam; brightness, contrast, video mode, etc. */
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef __KERNEL__
42d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab#include <asm/uaccess.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/errno.h>
45d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pwc.h"
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pwc-kiara.h"
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pwc-timon.h"
492b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard#include "pwc-dec1.h"
502b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard#include "pwc-dec23.h"
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
526c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goede/* Selectors for status controls used only in this file */
532b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard#define GET_STATUS_B00				0x0B00
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SENSOR_TYPE_FORMATTER1			0x0C00
552b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard#define GET_STATUS_3000				0x3000
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define READ_RAW_Y_MEAN_FORMATTER		0x3100
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_POWER_SAVE_MODE_FORMATTER		0x3200
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MIRROR_IMAGE_FORMATTER			0x3300
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LED_FORMATTER				0x3400
602b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard#define LOWLIGHT				0x3500
612b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard#define GET_STATUS_3600				0x3600
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SENSOR_TYPE_FORMATTER2			0x3700
632b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard#define GET_STATUS_3800				0x3800
642b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard#define GET_STATUS_4000				0x4000
652b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard#define GET_STATUS_4100				0x4100	/* Get */
662b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard#define CTL_STATUS_4200				0x4200	/* [GS] 1 */
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VIDEO_OUTPUT_CONTROL_FORMATTER		0x0100
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
714c4c9432a6c916729c7296c47fe93b053a73e20cArjan van de Venstatic const char *size2name[PSZ_MAX] =
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"subQCIF",
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"QSIF",
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"QCIF",
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"SIF",
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"CIF",
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"VGA",
79d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab};
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********/
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
83d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab/* Entries for the Nala (645/646) camera; the Nala doesn't have compression
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   preferences, so you either get compressed or non-compressed streams.
85d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   An alternate value of 0 means this mode is not available at all.
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
899ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard#define PWC_FPS_MAX_NALA 8
909ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct Nala_table_entry {
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char alternate;			/* USB alternate setting */
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int compressed;			/* Compressed yes/no */
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char mode[3];		/* precomputed mode table */
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
989ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillardstatic unsigned int Nala_fps_vector[PWC_FPS_MAX_NALA] = { 4, 5, 7, 10, 12, 15, 20, 24 };
999ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard
1009ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillardstatic struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] =
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pwc-nala.h"
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/****************************************************************************/
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1076b35ca0d3d586b8ecb8396821af21186e20afaf0Martin Fuzzeystatic int recv_control_msg(struct pwc_device *pdev,
10824be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	u8 request, u16 value, int recv_count)
1096b35ca0d3d586b8ecb8396821af21186e20afaf0Martin Fuzzey{
1106b35ca0d3d586b8ecb8396821af21186e20afaf0Martin Fuzzey	int rc;
1116b35ca0d3d586b8ecb8396821af21186e20afaf0Martin Fuzzey
1126b35ca0d3d586b8ecb8396821af21186e20afaf0Martin Fuzzey	rc = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
1136b35ca0d3d586b8ecb8396821af21186e20afaf0Martin Fuzzey		request,
1146b35ca0d3d586b8ecb8396821af21186e20afaf0Martin Fuzzey		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
11524be689bfbbcd6c047d7918784ff810e97648006Hans de Goede		value, pdev->vcinterface,
11624be689bfbbcd6c047d7918784ff810e97648006Hans de Goede		pdev->ctrl_buf, recv_count, USB_CTRL_GET_TIMEOUT);
1176c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goede	if (rc < 0)
1186c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goede		PWC_ERROR("recv_control_msg error %d req %02x val %04x\n",
1196c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goede			  rc, request, value);
1206b35ca0d3d586b8ecb8396821af21186e20afaf0Martin Fuzzey	return rc;
1216b35ca0d3d586b8ecb8396821af21186e20afaf0Martin Fuzzey}
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1236b35ca0d3d586b8ecb8396821af21186e20afaf0Martin Fuzzeystatic inline int send_video_command(struct pwc_device *pdev,
12424be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	int index, const unsigned char *buf, int buflen)
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12624be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	int rc;
12724be689bfbbcd6c047d7918784ff810e97648006Hans de Goede
12824be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	memcpy(pdev->ctrl_buf, buf, buflen);
12924be689bfbbcd6c047d7918784ff810e97648006Hans de Goede
13024be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	rc = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
13124be689bfbbcd6c047d7918784ff810e97648006Hans de Goede			SET_EP_STREAM_CTL,
13224be689bfbbcd6c047d7918784ff810e97648006Hans de Goede			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
13324be689bfbbcd6c047d7918784ff810e97648006Hans de Goede			VIDEO_OUTPUT_CONTROL_FORMATTER, index,
13424be689bfbbcd6c047d7918784ff810e97648006Hans de Goede			pdev->ctrl_buf, buflen, USB_CTRL_SET_TIMEOUT);
13524be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	if (rc >= 0)
13624be689bfbbcd6c047d7918784ff810e97648006Hans de Goede		memcpy(pdev->cmd_buf, buf, buflen);
13724be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	else
13824be689bfbbcd6c047d7918784ff810e97648006Hans de Goede		PWC_ERROR("send_video_command error %d\n", rc);
13924be689bfbbcd6c047d7918784ff810e97648006Hans de Goede
14024be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	return rc;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
143294e289602d7827f1389b081535fda3b7553a651Hans de Goedeint send_control_msg(struct pwc_device *pdev,
1446b35ca0d3d586b8ecb8396821af21186e20afaf0Martin Fuzzey	u8 request, u16 value, void *buf, int buflen)
1456b35ca0d3d586b8ecb8396821af21186e20afaf0Martin Fuzzey{
14624be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
14724be689bfbbcd6c047d7918784ff810e97648006Hans de Goede			request,
14824be689bfbbcd6c047d7918784ff810e97648006Hans de Goede			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
14924be689bfbbcd6c047d7918784ff810e97648006Hans de Goede			value, pdev->vcinterface,
15024be689bfbbcd6c047d7918784ff810e97648006Hans de Goede			buf, buflen, USB_CTRL_SET_TIMEOUT);
1516b35ca0d3d586b8ecb8396821af21186e20afaf0Martin Fuzzey}
1526b35ca0d3d586b8ecb8396821af21186e20afaf0Martin Fuzzey
153d167a85c5fb45b1ecdacdb9b7733833a9af78da8Hans de Goedestatic int set_video_mode_Nala(struct pwc_device *pdev, int size, int pixfmt,
154938d5b9e7c2e20a7e609ad5874c6e7d8d391e6e9Hans de Goede			       int frames, int *compression, int send_to_cam)
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
156938d5b9e7c2e20a7e609ad5874c6e7d8d391e6e9Hans de Goede	int fps, ret = 0;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Nala_table_entry *pEntry;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int frames2frames[31] =
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ /* closest match of framerate */
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   0,  0,  0,  0,  4,  /*  0-4  */
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   5,  5,  7,  7, 10,  /*  5-9  */
162d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab	  10, 10, 12, 12, 15,  /* 10-14 */
163d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab	  15, 15, 15, 20, 20,  /* 15-19 */
164d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab	  20, 20, 20, 24, 24,  /* 20-24 */
165d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab	  24, 24, 24, 24, 24,  /* 25-29 */
166d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab	  24                   /* 30    */
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	};
168d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab	int frames2table[31] =
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0, 0, 0, 0, 0, /*  0-4  */
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  1, 1, 1, 2, 2, /*  5-9  */
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  3, 3, 4, 4, 4, /* 10-14 */
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  5, 5, 5, 5, 5, /* 15-19 */
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  6, 6, 6, 6, 7, /* 20-24 */
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  7, 7, 7, 7, 7, /* 25-29 */
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  7              /* 30    */
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	};
177d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab
17854d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede	if (size < 0 || size > PSZ_CIF)
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
18054d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede	if (frames < 4)
18154d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede		frames = 4;
18254d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede	else if (frames > 25)
18354d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede		frames = 25;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	frames = frames2frames[frames];
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fps = frames2table[frames];
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pEntry = &Nala_table[size][fps];
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pEntry->alternate == 0)
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
190938d5b9e7c2e20a7e609ad5874c6e7d8d391e6e9Hans de Goede	if (send_to_cam)
19124be689bfbbcd6c047d7918784ff810e97648006Hans de Goede		ret = send_video_command(pdev, pdev->vendpoint,
19224be689bfbbcd6c047d7918784ff810e97648006Hans de Goede					 pEntry->mode, 3);
19324be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	if (ret < 0)
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
195d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab
19624be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	if (pEntry->compressed && pixfmt == V4L2_PIX_FMT_YUV420)
19724be689bfbbcd6c047d7918784ff810e97648006Hans de Goede		pwc_dec1_init(pdev, pEntry->mode);
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set various parameters */
200d167a85c5fb45b1ecdacdb9b7733833a9af78da8Hans de Goede	pdev->pixfmt = pixfmt;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->vframes = frames;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->valternate = pEntry->alternate;
203795e6eb3262d3b7247ce450835eea6df6571d103Hans de Goede	pdev->width  = pwc_image_sizes[size][0];
204795e6eb3262d3b7247ce450835eea6df6571d103Hans de Goede	pdev->height = pwc_image_sizes[size][1];
205795e6eb3262d3b7247ce450835eea6df6571d103Hans de Goede	pdev->frame_size = (pdev->width * pdev->height * 3) / 2;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pEntry->compressed) {
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pdev->release < 5) { /* 4 fold compression */
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pdev->vbandlength = 528;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pdev->frame_size /= 4;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pdev->vbandlength = 704;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pdev->frame_size /= 3;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pdev->vbandlength = 0;
2185bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede
2195bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede	/* Let pwc-if.c:isoc_init know we don't support higher compression */
2205bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede	*compression = 3;
2215bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
226d167a85c5fb45b1ecdacdb9b7733833a9af78da8Hans de Goedestatic int set_video_mode_Timon(struct pwc_device *pdev, int size, int pixfmt,
227938d5b9e7c2e20a7e609ad5874c6e7d8d391e6e9Hans de Goede				int frames, int *compression, int send_to_cam)
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct Timon_table_entry *pChoose;
230938d5b9e7c2e20a7e609ad5874c6e7d8d391e6e9Hans de Goede	int fps, ret = 0;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23254d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede	if (size >= PSZ_MAX || *compression < 0 || *compression > 3)
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
23454d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede	if (frames < 5)
23554d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede		frames = 5;
23654d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede	else if (size == PSZ_VGA && frames > 15)
23754d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede		frames = 15;
23854d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede	else if (frames > 30)
23954d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede		frames = 30;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fps = (frames / 5) - 1;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2425bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede	/* Find a supported framerate with progressively higher compression */
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pChoose = NULL;
2445bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede	while (*compression <= 3) {
2455bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede		pChoose = &Timon_table[size][fps][*compression];
2465bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede		if (pChoose->alternate != 0)
2475bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede			break;
2485bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede		(*compression)++;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pChoose == NULL || pChoose->alternate == 0)
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOENT; /* Not supported. */
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
253938d5b9e7c2e20a7e609ad5874c6e7d8d391e6e9Hans de Goede	if (send_to_cam)
25424be689bfbbcd6c047d7918784ff810e97648006Hans de Goede		ret = send_video_command(pdev, pdev->vendpoint,
25524be689bfbbcd6c047d7918784ff810e97648006Hans de Goede					 pChoose->mode, 13);
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
259d167a85c5fb45b1ecdacdb9b7733833a9af78da8Hans de Goede	if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420)
26024be689bfbbcd6c047d7918784ff810e97648006Hans de Goede		pwc_dec23_init(pdev, pChoose->mode);
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set various parameters */
263d167a85c5fb45b1ecdacdb9b7733833a9af78da8Hans de Goede	pdev->pixfmt = pixfmt;
26454d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede	pdev->vframes = (fps + 1) * 5;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->valternate = pChoose->alternate;
266795e6eb3262d3b7247ce450835eea6df6571d103Hans de Goede	pdev->width  = pwc_image_sizes[size][0];
267795e6eb3262d3b7247ce450835eea6df6571d103Hans de Goede	pdev->height = pwc_image_sizes[size][1];
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->vbandlength = pChoose->bandlength;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pChoose->bandlength > 0)
270795e6eb3262d3b7247ce450835eea6df6571d103Hans de Goede		pdev->frame_size = (pChoose->bandlength * pdev->height) / 4;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
272795e6eb3262d3b7247ce450835eea6df6571d103Hans de Goede		pdev->frame_size = (pdev->width * pdev->height * 12) / 8;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
277d167a85c5fb45b1ecdacdb9b7733833a9af78da8Hans de Goedestatic int set_video_mode_Kiara(struct pwc_device *pdev, int size, int pixfmt,
278938d5b9e7c2e20a7e609ad5874c6e7d8d391e6e9Hans de Goede				int frames, int *compression, int send_to_cam)
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct Kiara_table_entry *pChoose = NULL;
281938d5b9e7c2e20a7e609ad5874c6e7d8d391e6e9Hans de Goede	int fps, ret = 0;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28354d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede	if (size >= PSZ_MAX || *compression < 0 || *compression > 3)
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
28554d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede	if (frames < 5)
28654d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede		frames = 5;
28754d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede	else if (size == PSZ_VGA && frames > 15)
28854d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede		frames = 15;
28954d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede	else if (frames > 30)
29054d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede		frames = 30;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fps = (frames / 5) - 1;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2935bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede	/* Find a supported framerate with progressively higher compression */
2945bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede	while (*compression <= 3) {
2955bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede		pChoose = &Kiara_table[size][fps][*compression];
296dc8a7e83aaf8bb1bcf7163bda8926a6dd29c409bHans de Goede		if (pChoose->alternate != 0)
297dc8a7e83aaf8bb1bcf7163bda8926a6dd29c409bHans de Goede			break;
2985bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede		(*compression)++;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pChoose == NULL || pChoose->alternate == 0)
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOENT; /* Not supported. */
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */
304938d5b9e7c2e20a7e609ad5874c6e7d8d391e6e9Hans de Goede	if (send_to_cam)
30524be689bfbbcd6c047d7918784ff810e97648006Hans de Goede		ret = send_video_command(pdev, 4, pChoose->mode, 12);
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
309d167a85c5fb45b1ecdacdb9b7733833a9af78da8Hans de Goede	if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420)
31024be689bfbbcd6c047d7918784ff810e97648006Hans de Goede		pwc_dec23_init(pdev, pChoose->mode);
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* All set and go */
313d167a85c5fb45b1ecdacdb9b7733833a9af78da8Hans de Goede	pdev->pixfmt = pixfmt;
31454d3fb3b11a7c38b112585e54b7af7cb3faa5c91Hans de Goede	pdev->vframes = (fps + 1) * 5;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->valternate = pChoose->alternate;
316795e6eb3262d3b7247ce450835eea6df6571d103Hans de Goede	pdev->width  = pwc_image_sizes[size][0];
317795e6eb3262d3b7247ce450835eea6df6571d103Hans de Goede	pdev->height = pwc_image_sizes[size][1];
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->vbandlength = pChoose->bandlength;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pdev->vbandlength > 0)
320795e6eb3262d3b7247ce450835eea6df6571d103Hans de Goede		pdev->frame_size = (pdev->vbandlength * pdev->height) / 4;
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
322795e6eb3262d3b7247ce450835eea6df6571d103Hans de Goede		pdev->frame_size = (pdev->width * pdev->height * 12) / 8;
323dc8a7e83aaf8bb1bcf7163bda8926a6dd29c409bHans de Goede	PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vbandlength=%d\n",
324dc8a7e83aaf8bb1bcf7163bda8926a6dd29c409bHans de Goede	    pdev->frame_size, pdev->vframes, size, pdev->vbandlength);
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
328dc8a7e83aaf8bb1bcf7163bda8926a6dd29c409bHans de Goedeint pwc_set_video_mode(struct pwc_device *pdev, int width, int height,
329938d5b9e7c2e20a7e609ad5874c6e7d8d391e6e9Hans de Goede	int pixfmt, int frames, int *compression, int send_to_cam)
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
331d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab	int ret, size;
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
33356ae24aad8f9e25dfef995c3e898e5f394cf0bebHans de Goede	PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n",
334d167a85c5fb45b1ecdacdb9b7733833a9af78da8Hans de Goede		       width, height, frames, pixfmt);
335795e6eb3262d3b7247ce450835eea6df6571d103Hans de Goede	size = pwc_get_size(pdev, width, height);
3362b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	PWC_TRACE("decode_size = %d.\n", size);
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3382b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	if (DEVICE_USE_CODEC1(pdev->type)) {
339d167a85c5fb45b1ecdacdb9b7733833a9af78da8Hans de Goede		ret = set_video_mode_Nala(pdev, size, pixfmt, frames,
340938d5b9e7c2e20a7e609ad5874c6e7d8d391e6e9Hans de Goede					  compression, send_to_cam);
3412b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	} else if (DEVICE_USE_CODEC3(pdev->type)) {
342d167a85c5fb45b1ecdacdb9b7733833a9af78da8Hans de Goede		ret = set_video_mode_Kiara(pdev, size, pixfmt, frames,
343938d5b9e7c2e20a7e609ad5874c6e7d8d391e6e9Hans de Goede					   compression, send_to_cam);
3442b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	} else {
345d167a85c5fb45b1ecdacdb9b7733833a9af78da8Hans de Goede		ret = set_video_mode_Timon(pdev, size, pixfmt, frames,
346938d5b9e7c2e20a7e609ad5874c6e7d8d391e6e9Hans de Goede					   compression, send_to_cam);
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0) {
3492b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
353795e6eb3262d3b7247ce450835eea6df6571d103Hans de Goede	PWC_DEBUG_SIZE("Set resolution to %dx%d\n", pdev->width, pdev->height);
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3579ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillardstatic unsigned int pwc_get_fps_Nala(struct pwc_device *pdev, unsigned int index, unsigned int size)
3589ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard{
3599ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard	unsigned int i;
3609ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard
3619ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard	for (i = 0; i < PWC_FPS_MAX_NALA; i++) {
3629ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard		if (Nala_table[size][i].alternate) {
3639ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard			if (index--==0) return Nala_fps_vector[i];
3649ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard		}
3659ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard	}
3669ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard	return 0;
3679ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard}
3689ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard
3699ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillardstatic unsigned int pwc_get_fps_Kiara(struct pwc_device *pdev, unsigned int index, unsigned int size)
3709ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard{
3719ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard	unsigned int i;
3729ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard
3739ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard	for (i = 0; i < PWC_FPS_MAX_KIARA; i++) {
3749ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard		if (Kiara_table[size][i][3].alternate) {
3759ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard			if (index--==0) return Kiara_fps_vector[i];
3769ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard		}
3779ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard	}
3789ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard	return 0;
3799ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard}
3809ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard
3819ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillardstatic unsigned int pwc_get_fps_Timon(struct pwc_device *pdev, unsigned int index, unsigned int size)
3829ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard{
3839ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard	unsigned int i;
3849ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard
3859ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard	for (i=0; i < PWC_FPS_MAX_TIMON; i++) {
3869ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard		if (Timon_table[size][i][3].alternate) {
3879ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard			if (index--==0) return Timon_fps_vector[i];
3889ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard		}
3899ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard	}
3909ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard	return 0;
3919ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard}
3929ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard
3939ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillardunsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size)
3949ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard{
3959ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard	unsigned int ret;
3969ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard
3979ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard	if (DEVICE_USE_CODEC1(pdev->type)) {
3989ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard		ret = pwc_get_fps_Nala(pdev, index, size);
3999ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard
4009ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard	} else if (DEVICE_USE_CODEC3(pdev->type)) {
4019ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard		ret = pwc_get_fps_Kiara(pdev, index, size);
4029ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard
4039ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard	} else {
4049ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard		ret = pwc_get_fps_Timon(pdev, index, size);
4059ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard	}
4069ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard
4079ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard	return ret;
4089ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard}
4099ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard
4106c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goedeint pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41424be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	ret = recv_control_msg(pdev, request, value, 1);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41824be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	*data = pdev->ctrl_buf[0];
4196c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goede	return 0;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4226c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goedeint pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data)
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42624be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	pdev->ctrl_buf[0] = data;
42724be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 1);
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4316c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goede	return 0;
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4346c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goedeint pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
437d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab
43824be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	ret = recv_control_msg(pdev, request, value, 1);
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44224be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	*data = ((s8 *)pdev->ctrl_buf)[0];
4432b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	return 0;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4466c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goedeint pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
449d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab
45024be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	ret = recv_control_msg(pdev, request, value, 2);
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
4536c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goede
45424be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	*data = (pdev->ctrl_buf[1] << 8) | pdev->ctrl_buf[0];
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4586c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goedeint pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data)
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
461d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab
46224be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	pdev->ctrl_buf[0] = data & 0xff;
46324be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	pdev->ctrl_buf[1] = data >> 8;
46424be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 2);
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4716c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goedeint pwc_button_ctrl(struct pwc_device *pdev, u16 value)
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4732b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	int ret;
4742b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard
4756c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goede	ret = send_control_msg(pdev, SET_STATUS_CTL, value, NULL, 0);
4762b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	if (ret < 0)
4772b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		return ret;
4786c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goede
4792b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	return 0;
4802b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard}
4812b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* POWER */
4833b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goedevoid pwc_camera_power(struct pwc_device *pdev, int power)
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4853b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede	int r;
4863b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede
4873b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede	if (!pdev->power_save)
4883b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede		return;
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6))
4913b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede		return;	/* Not supported by Nala or Timon < release 6 */
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (power)
49424be689bfbbcd6c047d7918784ff810e97648006Hans de Goede		pdev->ctrl_buf[0] = 0x00; /* active */
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
49624be689bfbbcd6c047d7918784ff810e97648006Hans de Goede		pdev->ctrl_buf[0] = 0xFF; /* power save */
49724be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	r = send_control_msg(pdev, SET_STATUS_CTL,
49824be689bfbbcd6c047d7918784ff810e97648006Hans de Goede		SET_POWER_SAVE_MODE_FORMATTER, pdev->ctrl_buf, 1);
4993b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede	if (r < 0)
5003b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede		PWC_ERROR("Failed to power %s camera (%d)\n",
5013b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede			  power ? "on" : "off", r);
5023b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede}
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5063b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede	int r;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pdev->type < 730)
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	on_value /= 100;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	off_value /= 100;
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (on_value < 0)
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		on_value = 0;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (on_value > 0xff)
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		on_value = 0xff;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (off_value < 0)
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		off_value = 0;
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (off_value > 0xff)
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		off_value = 0xff;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
52124be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	pdev->ctrl_buf[0] = on_value;
52224be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	pdev->ctrl_buf[1] = off_value;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5243b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede	r = send_control_msg(pdev,
52524be689bfbbcd6c047d7918784ff810e97648006Hans de Goede		SET_STATUS_CTL, LED_FORMATTER, pdev->ctrl_buf, 2);
5263b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede	if (r < 0)
5273b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede		PWC_ERROR("Failed to set LED on/off time (%d)\n", r);
5283b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede
5293b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede	return r;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5326eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede#ifdef CONFIG_USB_PWC_DEBUG
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = -1, request;
536d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pdev->type < 675)
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		request = SENSOR_TYPE_FORMATTER1;
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (pdev->type < 730)
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1; /* The Vesta series doesn't have this call */
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		request = SENSOR_TYPE_FORMATTER2;
543d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab
54424be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	ret = recv_control_msg(pdev, GET_STATUS_CTL, request, 1);
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pdev->type < 675)
54824be689bfbbcd6c047d7918784ff810e97648006Hans de Goede		*sensor = pdev->ctrl_buf[0] | 0x100;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
55024be689bfbbcd6c047d7918784ff810e97648006Hans de Goede		*sensor = pdev->ctrl_buf[0];
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5536eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede#endif
554