diff options
Diffstat (limited to 'drivers/media/usb/pwc')
| -rw-r--r-- | drivers/media/usb/pwc/Kconfig | 48 | ||||
| -rw-r--r-- | drivers/media/usb/pwc/Makefile | 4 | ||||
| -rw-r--r-- | drivers/media/usb/pwc/philips.txt | 236 | ||||
| -rw-r--r-- | drivers/media/usb/pwc/pwc-ctrl.c | 555 | ||||
| -rw-r--r-- | drivers/media/usb/pwc/pwc-dec1.c | 32 | ||||
| -rw-r--r-- | drivers/media/usb/pwc/pwc-dec1.h | 39 | ||||
| -rw-r--r-- | drivers/media/usb/pwc/pwc-dec23.c | 691 | ||||
| -rw-r--r-- | drivers/media/usb/pwc/pwc-dec23.h | 61 | ||||
| -rw-r--r-- | drivers/media/usb/pwc/pwc-if.c | 1169 | ||||
| -rw-r--r-- | drivers/media/usb/pwc/pwc-kiara.c | 892 | ||||
| -rw-r--r-- | drivers/media/usb/pwc/pwc-kiara.h | 48 | ||||
| -rw-r--r-- | drivers/media/usb/pwc/pwc-misc.c | 93 | ||||
| -rw-r--r-- | drivers/media/usb/pwc/pwc-nala.h | 66 | ||||
| -rw-r--r-- | drivers/media/usb/pwc/pwc-timon.c | 1448 | ||||
| -rw-r--r-- | drivers/media/usb/pwc/pwc-timon.h | 63 | ||||
| -rw-r--r-- | drivers/media/usb/pwc/pwc-uncompress.c | 107 | ||||
| -rw-r--r-- | drivers/media/usb/pwc/pwc-v4l.c | 1052 | ||||
| -rw-r--r-- | drivers/media/usb/pwc/pwc.h | 393 | 
18 files changed, 6997 insertions, 0 deletions
diff --git a/drivers/media/usb/pwc/Kconfig b/drivers/media/usb/pwc/Kconfig new file mode 100644 index 00000000000..d63d0a85003 --- /dev/null +++ b/drivers/media/usb/pwc/Kconfig @@ -0,0 +1,48 @@ +config USB_PWC +	tristate "USB Philips Cameras" +	depends on VIDEO_V4L2 +	select VIDEOBUF2_VMALLOC +	---help--- +	  Say Y or M here if you want to use one of these Philips & OEM +	  webcams: +	   * Philips PCA645, PCA646 +	   * Philips PCVC675, PCVC680, PCVC690 +	   * Philips PCVC720/40, PCVC730, PCVC740, PCVC750 +	   * Philips SPC900NC +	   * Askey VC010 +	   * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro' +	     and 'Orbit'/'Sphere' +	   * Samsung MPC-C10, MPC-C30 +	   * Creative Webcam 5, Pro Ex +	   * SOTEC Afina Eye +	   * Visionite VCS-UC300, VCS-UM100 + +	  The PCA635, PCVC665 and PCVC720/20 are not supported by this driver +	  and never will be, but the 665 and 720/20 are supported by other +	  drivers. + +	  Some newer logitech webcams are not handled by this driver but by the +	  Usb Video Class driver (linux-uvc). + +	  The built-in microphone is enabled by selecting USB Audio support. + +	  To compile this driver as a module, choose M here: the +	  module will be called pwc. + +config USB_PWC_DEBUG +	bool "USB Philips Cameras verbose debug" +	depends on USB_PWC +	help +	  Say Y here in order to have the pwc driver generate verbose debugging +	  messages. +	  A special module options 'trace' is used to control the verbosity. + +config USB_PWC_INPUT_EVDEV +	bool "USB Philips Cameras input events device support" +	default y +	depends on USB_PWC && (USB_PWC=INPUT || INPUT=y) +	---help--- +	  This option makes USB Philips cameras register the snapshot button as +	  an input device to report button events. + +	  If you are in doubt, say Y. diff --git a/drivers/media/usb/pwc/Makefile b/drivers/media/usb/pwc/Makefile new file mode 100644 index 00000000000..d7fdbcb9edd --- /dev/null +++ b/drivers/media/usb/pwc/Makefile @@ -0,0 +1,4 @@ +pwc-objs	+= pwc-if.o pwc-misc.o pwc-ctrl.o pwc-v4l.o pwc-uncompress.o +pwc-objs	+= pwc-dec1.o pwc-dec23.o pwc-kiara.o pwc-timon.o + +obj-$(CONFIG_USB_PWC) += pwc.o diff --git a/drivers/media/usb/pwc/philips.txt b/drivers/media/usb/pwc/philips.txt new file mode 100644 index 00000000000..d38dd791511 --- /dev/null +++ b/drivers/media/usb/pwc/philips.txt @@ -0,0 +1,236 @@ +This file contains some additional information for the Philips and OEM webcams. +E-mail: webcam@smcc.demon.nl                        Last updated: 2004-01-19 +Site: http://www.smcc.demon.nl/webcam/ + +As of this moment, the following cameras are supported: + * Philips PCA645 + * Philips PCA646 + * Philips PCVC675 + * Philips PCVC680 + * Philips PCVC690 + * Philips PCVC720/40 + * Philips PCVC730 + * Philips PCVC740 + * Philips PCVC750 + * Askey VC010 + * Creative Labs Webcam 5 + * Creative Labs Webcam Pro Ex + * Logitech QuickCam 3000 Pro + * Logitech QuickCam 4000 Pro + * Logitech QuickCam Notebook Pro + * Logitech QuickCam Zoom + * Logitech QuickCam Orbit + * Logitech QuickCam Sphere + * Samsung MPC-C10 + * Samsung MPC-C30 + * Sotec Afina Eye + * AME CU-001 + * Visionite VCS-UM100 + * Visionite VCS-UC300 + +The main webpage for the Philips driver is at the address above. It contains +a lot of extra information, a FAQ, and the binary plugin 'PWCX'. This plugin +contains decompression routines that allow you to use higher image sizes and +framerates; in addition the webcam uses less bandwidth on the USB bus (handy +if you want to run more than 1 camera simultaneously). These routines fall +under a NDA, and may therefore not be distributed as source; however, its use +is completely optional. + +You can build this code either into your kernel, or as a module. I recommend +the latter, since it makes troubleshooting a lot easier. The built-in +microphone is supported through the USB Audio class. + +When you load the module you can set some default settings for the +camera; some programs depend on a particular image-size or -format and +don't know how to set it properly in the driver. The options are: + +size +   Can be one of 'sqcif', 'qsif', 'qcif', 'sif', 'cif' or +   'vga', for an image size of resp. 128x96, 160x120, 176x144, +   320x240, 352x288 and 640x480 (of course, only for those cameras that +   support these resolutions). + +fps +   Specifies the desired framerate. Is an integer in the range of 4-30. + +fbufs +   This parameter specifies the number of internal buffers to use for storing +   frames from the cam. This will help if the process that reads images from +   the cam is a bit slow or momentarily busy. However, on slow machines it +   only introduces lag, so choose carefully. The default is 3, which is +   reasonable. You can set it between 2 and 5. + +mbufs +   This is an integer between 1 and 10. It will tell the module the number of +   buffers to reserve for mmap(), VIDIOCCGMBUF, VIDIOCMCAPTURE and friends. +   The default is 2, which is adequate for most applications (double +   buffering). + +   Should you experience a lot of 'Dumping frame...' messages during +   grabbing with a tool that uses mmap(), you might want to increase if. +   However, it doesn't really buffer images, it just gives you a bit more +   slack when your program is behind. But you need a multi-threaded or +   forked program to really take advantage of these buffers. + +   The absolute maximum is 10, but don't set it too high!  Every buffer takes +   up 460 KB of RAM, so unless you have a lot of memory setting this to +   something more than 4 is an absolute waste.  This memory is only +   allocated during open(), so nothing is wasted when the camera is not in +   use. + +power_save +   When power_save is enabled (set to 1), the module will try to shut down +   the cam on close() and re-activate on open(). This will save power and +   turn off the LED. Not all cameras support this though (the 645 and 646 +   don't have power saving at all), and some models don't work either (they +   will shut down, but never wake up). Consider this experimental. By +   default this option is disabled. + +compression (only useful with the plugin) +   With this option you can control the compression factor that the camera +   uses to squeeze the image through the USB bus. You can set the +   parameter between 0 and 3: +     0 = prefer uncompressed images; if the requested mode is not available +	 in an uncompressed format, the driver will silently switch to low +	 compression. +     1 = low compression. +     2 = medium compression. +     3 = high compression. + +   High compression takes less bandwidth of course, but it could also +   introduce some unwanted artefacts. The default is 2, medium compression. +   See the FAQ on the website for an overview of which modes require +   compression. + +   The compression parameter does not apply to the 645 and 646 cameras +   and OEM models derived from those (only a few). Most cams honour this +   parameter. + +leds +   This settings takes 2 integers, that define the on/off time for the LED +   (in milliseconds). One of the interesting things that you can do with +   this is let the LED blink while the camera is in use. This: + +     leds=500,500 + +   will blink the LED once every second. But with: + +     leds=0,0 + +   the LED never goes on, making it suitable for silent surveillance. + +   By default the camera's LED is on solid while in use, and turned off +   when the camera is not used anymore. + +   This parameter works only with the ToUCam range of cameras (720, 730, 740, +   750) and OEMs. For other cameras this command is silently ignored, and +   the LED cannot be controlled. + +   Finally: this parameters does not take effect UNTIL the first time you +   open the camera device. Until then, the LED remains on. + +dev_hint +   A long standing problem with USB devices is their dynamic nature: you +   never know what device a camera gets assigned; it depends on module load +   order, the hub configuration, the order in which devices are plugged in, +   and the phase of the moon (i.e. it can be random). With this option you +   can give the driver a hint as to what video device node (/dev/videoX) it +   should use with a specific camera. This is also handy if you have two +   cameras of the same model. + +   A camera is specified by its type (the number from the camera model, +   like PCA645, PCVC750VC, etc) and optionally the serial number (visible +   in /proc/bus/usb/devices). A hint consists of a string with the following +   format: + +      [type[.serialnumber]:]node + +   The square brackets mean that both the type and the serialnumber are +   optional, but a serialnumber cannot be specified without a type (which +   would be rather pointless). The serialnumber is separated from the type +   by a '.'; the node number by a ':'. + +   This somewhat cryptic syntax is best explained by a few examples: + +     dev_hint=3,5              The first detected cam gets assigned +			       /dev/video3, the second /dev/video5. Any +			       other cameras will get the first free +			       available slot (see below). + +     dev_hint=645:1,680:2      The PCA645 camera will get /dev/video1, +			       and a PCVC680 /dev/video2. + +     dev_hint=645.0123:3,645.4567:0	The PCA645 camera with serialnumber +					0123 goes to /dev/video3, the same +					camera model with the 4567 serial +					gets /dev/video0. + +     dev_hint=750:1,4,5,6       The PCVC750 camera will get /dev/video1, the +				next 3 Philips cams will use /dev/video4 +				through /dev/video6. + +   Some points worth knowing: +   - Serialnumbers are case sensitive and must be written full, including +     leading zeroes (it's treated as a string). +   - If a device node is already occupied, registration will fail and +     the webcam is not available. +   - You can have up to 64 video devices; be sure to make enough device +     nodes in /dev if you want to spread the numbers. +     After /dev/video9 comes /dev/video10 (not /dev/videoA). +   - If a camera does not match any dev_hint, it will simply get assigned +     the first available device node, just as it used to be. + +trace +   In order to better detect problems, it is now possible to turn on a +   'trace' of some of the calls the module makes; it logs all items in your +   kernel log at debug level. + +   The trace variable is a bitmask; each bit represents a certain feature. +   If you want to trace something, look up the bit value(s) in the table +   below, add the values together and supply that to the trace variable. + +   Value  Value   Description					   Default +   (dec)  (hex) +       1    0x1   Module initialization; this will log messages       On +		  while loading and unloading the module + +       2    0x2   probe() and disconnect() traces                     On + +       4    0x4   Trace open() and close() calls                      Off + +       8    0x8   read(), mmap() and associated ioctl() calls         Off + +      16   0x10   Memory allocation of buffers, etc.                  Off + +      32   0x20   Showing underflow, overflow and Dumping frame       On +		  messages + +      64   0x40   Show viewport and image sizes                       Off + +     128   0x80   PWCX debugging                                      Off + +   For example, to trace the open() & read() functions, sum 8 + 4 = 12, +   so you would supply trace=12 during insmod or modprobe. If +   you want to turn the initialization and probing tracing off, set trace=0. +   The default value for trace is 35 (0x23). + + + +Example: + +     # modprobe pwc size=cif fps=15 power_save=1 + +The fbufs, mbufs and trace parameters are global and apply to all connected +cameras. Each camera has its own set of buffers. + +size and fps only specify defaults when you open() the device; this is to +accommodate some tools that don't set the size. You can change these +settings after open() with the Video4Linux ioctl() calls. The default of +defaults is QCIF size at 10 fps. + +The compression parameter is semiglobal; it sets the initial compression +preference for all camera's, but this parameter can be set per camera with +the VIDIOCPWCSCQUAL ioctl() call. + +All parameters are optional. + diff --git a/drivers/media/usb/pwc/pwc-ctrl.c b/drivers/media/usb/pwc/pwc-ctrl.c new file mode 100644 index 00000000000..3a1618580ed --- /dev/null +++ b/drivers/media/usb/pwc/pwc-ctrl.c @@ -0,0 +1,555 @@ +/* Driver for Philips webcam +   Functions that send various control messages to the webcam, including +   video modes. +   (C) 1999-2003 Nemosoft Unv. +   (C) 2004-2006 Luc Saillard (luc@saillard.org) +   (C) 2011 Hans de Goede <hdegoede@redhat.com> + +   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +   driver and thus may have bugs that are not present in the original version. +   Please send bug reports and support requests to <luc@saillard.org>. + +   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +   driver and thus may have bugs that are not present in the original version. +   Please send bug reports and support requests to <luc@saillard.org>. +   The decompression routines have been implemented by reverse-engineering the +   Nemosoft binary pwcx module. Caveat emptor. + +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published by +   the Free Software Foundation; either version 2 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +/* +   Changes +   2001/08/03  Alvarado   Added methods for changing white balance and +			  red/green gains + */ + +/* Control functions for the cam; brightness, contrast, video mode, etc. */ + +#ifdef __KERNEL__ +#include <asm/uaccess.h> +#endif +#include <asm/errno.h> + +#include "pwc.h" +#include "pwc-kiara.h" +#include "pwc-timon.h" +#include "pwc-dec1.h" +#include "pwc-dec23.h" + +/* Selectors for status controls used only in this file */ +#define GET_STATUS_B00				0x0B00 +#define SENSOR_TYPE_FORMATTER1			0x0C00 +#define GET_STATUS_3000				0x3000 +#define READ_RAW_Y_MEAN_FORMATTER		0x3100 +#define SET_POWER_SAVE_MODE_FORMATTER		0x3200 +#define MIRROR_IMAGE_FORMATTER			0x3300 +#define LED_FORMATTER				0x3400 +#define LOWLIGHT				0x3500 +#define GET_STATUS_3600				0x3600 +#define SENSOR_TYPE_FORMATTER2			0x3700 +#define GET_STATUS_3800				0x3800 +#define GET_STATUS_4000				0x4000 +#define GET_STATUS_4100				0x4100	/* Get */ +#define CTL_STATUS_4200				0x4200	/* [GS] 1 */ + +/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */ +#define VIDEO_OUTPUT_CONTROL_FORMATTER		0x0100 + +static const char *size2name[PSZ_MAX] = +{ +	"subQCIF", +	"QSIF", +	"QCIF", +	"SIF", +	"CIF", +	"VGA", +}; + +/********/ + +/* Entries for the Nala (645/646) camera; the Nala doesn't have compression +   preferences, so you either get compressed or non-compressed streams. + +   An alternate value of 0 means this mode is not available at all. + */ + +#define PWC_FPS_MAX_NALA 8 + +struct Nala_table_entry { +	char alternate;			/* USB alternate setting */ +	int compressed;			/* Compressed yes/no */ + +	unsigned char mode[3];		/* precomputed mode table */ +}; + +static unsigned int Nala_fps_vector[PWC_FPS_MAX_NALA] = { 4, 5, 7, 10, 12, 15, 20, 24 }; + +static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] = +{ +#include "pwc-nala.h" +}; + +/****************************************************************************/ + +static int recv_control_msg(struct pwc_device *pdev, +	u8 request, u16 value, int recv_count) +{ +	int rc; + +	rc = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), +		request, +		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, +		value, pdev->vcinterface, +		pdev->ctrl_buf, recv_count, USB_CTRL_GET_TIMEOUT); +	if (rc < 0) +		PWC_ERROR("recv_control_msg error %d req %02x val %04x\n", +			  rc, request, value); +	return rc; +} + +static inline int send_video_command(struct pwc_device *pdev, +	int index, const unsigned char *buf, int buflen) +{ +	int rc; + +	memcpy(pdev->ctrl_buf, buf, buflen); + +	rc = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), +			SET_EP_STREAM_CTL, +			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, +			VIDEO_OUTPUT_CONTROL_FORMATTER, index, +			pdev->ctrl_buf, buflen, USB_CTRL_SET_TIMEOUT); +	if (rc >= 0) +		memcpy(pdev->cmd_buf, buf, buflen); +	else +		PWC_ERROR("send_video_command error %d\n", rc); + +	return rc; +} + +int send_control_msg(struct pwc_device *pdev, +	u8 request, u16 value, void *buf, int buflen) +{ +	return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), +			request, +			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, +			value, pdev->vcinterface, +			buf, buflen, USB_CTRL_SET_TIMEOUT); +} + +static int set_video_mode_Nala(struct pwc_device *pdev, int size, int pixfmt, +			       int frames, int *compression, int send_to_cam) +{ +	int fps, ret = 0; +	struct Nala_table_entry *pEntry; +	int frames2frames[31] = +	{ /* closest match of framerate */ +	   0,  0,  0,  0,  4,  /*  0-4  */ +	   5,  5,  7,  7, 10,  /*  5-9  */ +	  10, 10, 12, 12, 15,  /* 10-14 */ +	  15, 15, 15, 20, 20,  /* 15-19 */ +	  20, 20, 20, 24, 24,  /* 20-24 */ +	  24, 24, 24, 24, 24,  /* 25-29 */ +	  24                   /* 30    */ +	}; +	int frames2table[31] = +	{ 0, 0, 0, 0, 0, /*  0-4  */ +	  1, 1, 1, 2, 2, /*  5-9  */ +	  3, 3, 4, 4, 4, /* 10-14 */ +	  5, 5, 5, 5, 5, /* 15-19 */ +	  6, 6, 6, 6, 7, /* 20-24 */ +	  7, 7, 7, 7, 7, /* 25-29 */ +	  7              /* 30    */ +	}; + +	if (size < 0 || size > PSZ_CIF) +		return -EINVAL; +	if (frames < 4) +		frames = 4; +	else if (size > PSZ_QCIF && frames > 15) +		frames = 15; +	else if (frames > 25) +		frames = 25; +	frames = frames2frames[frames]; +	fps = frames2table[frames]; +	pEntry = &Nala_table[size][fps]; +	if (pEntry->alternate == 0) +		return -EINVAL; + +	if (send_to_cam) +		ret = send_video_command(pdev, pdev->vendpoint, +					 pEntry->mode, 3); +	if (ret < 0) +		return ret; + +	if (pEntry->compressed && pixfmt == V4L2_PIX_FMT_YUV420) +		pwc_dec1_init(pdev, pEntry->mode); + +	/* Set various parameters */ +	pdev->pixfmt = pixfmt; +	pdev->vframes = frames; +	pdev->valternate = pEntry->alternate; +	pdev->width  = pwc_image_sizes[size][0]; +	pdev->height = pwc_image_sizes[size][1]; +	pdev->frame_size = (pdev->width * pdev->height * 3) / 2; +	if (pEntry->compressed) { +		if (pdev->release < 5) { /* 4 fold compression */ +			pdev->vbandlength = 528; +			pdev->frame_size /= 4; +		} +		else { +			pdev->vbandlength = 704; +			pdev->frame_size /= 3; +		} +	} +	else +		pdev->vbandlength = 0; + +	/* Let pwc-if.c:isoc_init know we don't support higher compression */ +	*compression = 3; + +	return 0; +} + + +static int set_video_mode_Timon(struct pwc_device *pdev, int size, int pixfmt, +				int frames, int *compression, int send_to_cam) +{ +	const struct Timon_table_entry *pChoose; +	int fps, ret = 0; + +	if (size >= PSZ_MAX || *compression < 0 || *compression > 3) +		return -EINVAL; +	if (frames < 5) +		frames = 5; +	else if (size == PSZ_VGA && frames > 15) +		frames = 15; +	else if (frames > 30) +		frames = 30; +	fps = (frames / 5) - 1; + +	/* Find a supported framerate with progressively higher compression */ +	pChoose = NULL; +	while (*compression <= 3) { +		pChoose = &Timon_table[size][fps][*compression]; +		if (pChoose->alternate != 0) +			break; +		(*compression)++; +	} +	if (pChoose == NULL || pChoose->alternate == 0) +		return -ENOENT; /* Not supported. */ + +	if (send_to_cam) +		ret = send_video_command(pdev, pdev->vendpoint, +					 pChoose->mode, 13); +	if (ret < 0) +		return ret; + +	if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420) +		pwc_dec23_init(pdev, pChoose->mode); + +	/* Set various parameters */ +	pdev->pixfmt = pixfmt; +	pdev->vframes = (fps + 1) * 5; +	pdev->valternate = pChoose->alternate; +	pdev->width  = pwc_image_sizes[size][0]; +	pdev->height = pwc_image_sizes[size][1]; +	pdev->vbandlength = pChoose->bandlength; +	if (pChoose->bandlength > 0) +		pdev->frame_size = (pChoose->bandlength * pdev->height) / 4; +	else +		pdev->frame_size = (pdev->width * pdev->height * 12) / 8; +	return 0; +} + + +static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int pixfmt, +				int frames, int *compression, int send_to_cam) +{ +	const struct Kiara_table_entry *pChoose = NULL; +	int fps, ret = 0; + +	if (size >= PSZ_MAX || *compression < 0 || *compression > 3) +		return -EINVAL; +	if (frames < 5) +		frames = 5; +	else if (size == PSZ_VGA && frames > 15) +		frames = 15; +	else if (frames > 30) +		frames = 30; +	fps = (frames / 5) - 1; + +	/* Find a supported framerate with progressively higher compression */ +	while (*compression <= 3) { +		pChoose = &Kiara_table[size][fps][*compression]; +		if (pChoose->alternate != 0) +			break; +		(*compression)++; +	} +	if (pChoose == NULL || pChoose->alternate == 0) +		return -ENOENT; /* Not supported. */ + +	/* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ +	if (send_to_cam) +		ret = send_video_command(pdev, 4, pChoose->mode, 12); +	if (ret < 0) +		return ret; + +	if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420) +		pwc_dec23_init(pdev, pChoose->mode); + +	/* All set and go */ +	pdev->pixfmt = pixfmt; +	pdev->vframes = (fps + 1) * 5; +	pdev->valternate = pChoose->alternate; +	pdev->width  = pwc_image_sizes[size][0]; +	pdev->height = pwc_image_sizes[size][1]; +	pdev->vbandlength = pChoose->bandlength; +	if (pdev->vbandlength > 0) +		pdev->frame_size = (pdev->vbandlength * pdev->height) / 4; +	else +		pdev->frame_size = (pdev->width * pdev->height * 12) / 8; +	PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vbandlength=%d\n", +	    pdev->frame_size, pdev->vframes, size, pdev->vbandlength); +	return 0; +} + +int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, +	int pixfmt, int frames, int *compression, int send_to_cam) +{ +	int ret, size; + +	PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", +		       width, height, frames, pixfmt); +	size = pwc_get_size(pdev, width, height); +	PWC_TRACE("decode_size = %d.\n", size); + +	if (DEVICE_USE_CODEC1(pdev->type)) { +		ret = set_video_mode_Nala(pdev, size, pixfmt, frames, +					  compression, send_to_cam); +	} else if (DEVICE_USE_CODEC3(pdev->type)) { +		ret = set_video_mode_Kiara(pdev, size, pixfmt, frames, +					   compression, send_to_cam); +	} else { +		ret = set_video_mode_Timon(pdev, size, pixfmt, frames, +					   compression, send_to_cam); +	} +	if (ret < 0) { +		PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); +		return ret; +	} +	pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; +	PWC_DEBUG_SIZE("Set resolution to %dx%d\n", pdev->width, pdev->height); +	return 0; +} + +static unsigned int pwc_get_fps_Nala(struct pwc_device *pdev, unsigned int index, unsigned int size) +{ +	unsigned int i; + +	for (i = 0; i < PWC_FPS_MAX_NALA; i++) { +		if (Nala_table[size][i].alternate) { +			if (index--==0) return Nala_fps_vector[i]; +		} +	} +	return 0; +} + +static unsigned int pwc_get_fps_Kiara(struct pwc_device *pdev, unsigned int index, unsigned int size) +{ +	unsigned int i; + +	for (i = 0; i < PWC_FPS_MAX_KIARA; i++) { +		if (Kiara_table[size][i][3].alternate) { +			if (index--==0) return Kiara_fps_vector[i]; +		} +	} +	return 0; +} + +static unsigned int pwc_get_fps_Timon(struct pwc_device *pdev, unsigned int index, unsigned int size) +{ +	unsigned int i; + +	for (i=0; i < PWC_FPS_MAX_TIMON; i++) { +		if (Timon_table[size][i][3].alternate) { +			if (index--==0) return Timon_fps_vector[i]; +		} +	} +	return 0; +} + +unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size) +{ +	unsigned int ret; + +	if (DEVICE_USE_CODEC1(pdev->type)) { +		ret = pwc_get_fps_Nala(pdev, index, size); + +	} else if (DEVICE_USE_CODEC3(pdev->type)) { +		ret = pwc_get_fps_Kiara(pdev, index, size); + +	} else { +		ret = pwc_get_fps_Timon(pdev, index, size); +	} + +	return ret; +} + +int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) +{ +	int ret; + +	ret = recv_control_msg(pdev, request, value, 1); +	if (ret < 0) +		return ret; + +	*data = pdev->ctrl_buf[0]; +	return 0; +} + +int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data) +{ +	int ret; + +	pdev->ctrl_buf[0] = data; +	ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 1); +	if (ret < 0) +		return ret; + +	return 0; +} + +int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) +{ +	int ret; + +	ret = recv_control_msg(pdev, request, value, 1); +	if (ret < 0) +		return ret; + +	*data = ((s8 *)pdev->ctrl_buf)[0]; +	return 0; +} + +int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) +{ +	int ret; + +	ret = recv_control_msg(pdev, request, value, 2); +	if (ret < 0) +		return ret; + +	*data = (pdev->ctrl_buf[1] << 8) | pdev->ctrl_buf[0]; +	return 0; +} + +int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data) +{ +	int ret; + +	pdev->ctrl_buf[0] = data & 0xff; +	pdev->ctrl_buf[1] = data >> 8; +	ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 2); +	if (ret < 0) +		return ret; + +	return 0; +} + +int pwc_button_ctrl(struct pwc_device *pdev, u16 value) +{ +	int ret; + +	ret = send_control_msg(pdev, SET_STATUS_CTL, value, NULL, 0); +	if (ret < 0) +		return ret; + +	return 0; +} + +/* POWER */ +void pwc_camera_power(struct pwc_device *pdev, int power) +{ +	int r; + +	if (!pdev->power_save) +		return; + +	if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6)) +		return;	/* Not supported by Nala or Timon < release 6 */ + +	if (power) +		pdev->ctrl_buf[0] = 0x00; /* active */ +	else +		pdev->ctrl_buf[0] = 0xFF; /* power save */ +	r = send_control_msg(pdev, SET_STATUS_CTL, +		SET_POWER_SAVE_MODE_FORMATTER, pdev->ctrl_buf, 1); +	if (r < 0) +		PWC_ERROR("Failed to power %s camera (%d)\n", +			  power ? "on" : "off", r); +} + +int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) +{ +	int r; + +	if (pdev->type < 730) +		return 0; +	on_value /= 100; +	off_value /= 100; +	if (on_value < 0) +		on_value = 0; +	if (on_value > 0xff) +		on_value = 0xff; +	if (off_value < 0) +		off_value = 0; +	if (off_value > 0xff) +		off_value = 0xff; + +	pdev->ctrl_buf[0] = on_value; +	pdev->ctrl_buf[1] = off_value; + +	r = send_control_msg(pdev, +		SET_STATUS_CTL, LED_FORMATTER, pdev->ctrl_buf, 2); +	if (r < 0) +		PWC_ERROR("Failed to set LED on/off time (%d)\n", r); + +	return r; +} + +#ifdef CONFIG_USB_PWC_DEBUG +int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) +{ +	int ret = -1, request; + +	if (pdev->type < 675) +		request = SENSOR_TYPE_FORMATTER1; +	else if (pdev->type < 730) +		return -1; /* The Vesta series doesn't have this call */ +	else +		request = SENSOR_TYPE_FORMATTER2; + +	ret = recv_control_msg(pdev, GET_STATUS_CTL, request, 1); +	if (ret < 0) +		return ret; +	if (pdev->type < 675) +		*sensor = pdev->ctrl_buf[0] | 0x100; +	else +		*sensor = pdev->ctrl_buf[0]; +	return 0; +} +#endif diff --git a/drivers/media/usb/pwc/pwc-dec1.c b/drivers/media/usb/pwc/pwc-dec1.c new file mode 100644 index 00000000000..e899036aadf --- /dev/null +++ b/drivers/media/usb/pwc/pwc-dec1.c @@ -0,0 +1,32 @@ +/* Linux driver for Philips webcam +   Decompression for chipset version 1 +   (C) 2004-2006 Luc Saillard (luc@saillard.org) + +   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +   driver and thus may have bugs that are not present in the original version. +   Please send bug reports and support requests to <luc@saillard.org>. +   The decompression routines have been implemented by reverse-engineering the +   Nemosoft binary pwcx module. Caveat emptor. + +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published by +   the Free Software Foundation; either version 2 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ +#include "pwc.h" + +void pwc_dec1_init(struct pwc_device *pdev, const unsigned char *cmd) +{ +	struct pwc_dec1_private *pdec = &pdev->dec1; + +	pdec->version = pdev->release; +} diff --git a/drivers/media/usb/pwc/pwc-dec1.h b/drivers/media/usb/pwc/pwc-dec1.h new file mode 100644 index 00000000000..c565ef8f52f --- /dev/null +++ b/drivers/media/usb/pwc/pwc-dec1.h @@ -0,0 +1,39 @@ +/* Linux driver for Philips webcam +   (C) 2004-2006 Luc Saillard (luc@saillard.org) + +   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +   driver and thus may have bugs that are not present in the original version. +   Please send bug reports and support requests to <luc@saillard.org>. +   The decompression routines have been implemented by reverse-engineering the +   Nemosoft binary pwcx module. Caveat emptor. + +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published by +   the Free Software Foundation; either version 2 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef PWC_DEC1_H +#define PWC_DEC1_H + +#include <linux/mutex.h> + +struct pwc_device; + +struct pwc_dec1_private +{ +	int version; +}; + +void pwc_dec1_init(struct pwc_device *pdev, const unsigned char *cmd); + +#endif diff --git a/drivers/media/usb/pwc/pwc-dec23.c b/drivers/media/usb/pwc/pwc-dec23.c new file mode 100644 index 00000000000..3792fedff95 --- /dev/null +++ b/drivers/media/usb/pwc/pwc-dec23.c @@ -0,0 +1,691 @@ +/* Linux driver for Philips webcam +   Decompression for chipset version 2 et 3 +   (C) 2004-2006  Luc Saillard (luc@saillard.org) + +   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +   driver and thus may have bugs that are not present in the original version. +   Please send bug reports and support requests to <luc@saillard.org>. +   The decompression routines have been implemented by reverse-engineering the +   Nemosoft binary pwcx module. Caveat emptor. + +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published by +   the Free Software Foundation; either version 2 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +*/ + +#include "pwc-timon.h" +#include "pwc-kiara.h" +#include "pwc-dec23.h" + +#include <linux/string.h> +#include <linux/slab.h> + +/* + * USE_LOOKUP_TABLE_TO_CLAMP + *   0: use a C version of this tests:  {  a<0?0:(a>255?255:a) } + *   1: use a faster lookup table for cpu with a big cache (intel) + */ +#define USE_LOOKUP_TABLE_TO_CLAMP	1 +/* + * UNROLL_LOOP_FOR_COPYING_BLOCK + *   0: use a loop for a smaller code (but little slower) + *   1: when unrolling the loop, gcc produces some faster code (perhaps only + *   valid for intel processor class). Activating this option, automaticaly + *   activate USE_LOOKUP_TABLE_TO_CLAMP + */ +#define UNROLL_LOOP_FOR_COPY		1 +#if UNROLL_LOOP_FOR_COPY +# undef USE_LOOKUP_TABLE_TO_CLAMP +# define USE_LOOKUP_TABLE_TO_CLAMP 1 +#endif + +static void build_subblock_pattern(struct pwc_dec23_private *pdec) +{ +	static const unsigned int initial_values[12] = { +		-0x526500, -0x221200, 0x221200, 0x526500, +			   -0x3de200, 0x3de200, +		-0x6db480, -0x2d5d00, 0x2d5d00, 0x6db480, +			   -0x12c200, 0x12c200 + +	}; +	static const unsigned int values_derivated[12] = { +		0xa4ca, 0x4424, -0x4424, -0xa4ca, +			0x7bc4, -0x7bc4, +		0xdb69, 0x5aba, -0x5aba, -0xdb69, +			0x2584, -0x2584 +	}; +	unsigned int temp_values[12]; +	int i, j; + +	memcpy(temp_values, initial_values, sizeof(initial_values)); +	for (i = 0; i < 256; i++) { +		for (j = 0; j < 12; j++) { +			pdec->table_subblock[i][j] = temp_values[j]; +			temp_values[j] += values_derivated[j]; +		} +	} +} + +static void build_bit_powermask_table(struct pwc_dec23_private *pdec) +{ +	unsigned char *p; +	unsigned int bit, byte, mask, val; +	unsigned int bitpower = 1; + +	for (bit = 0; bit < 8; bit++) { +		mask = bitpower - 1; +		p = pdec->table_bitpowermask[bit]; +		for (byte = 0; byte < 256; byte++) { +			val = (byte & mask); +			if (byte & bitpower) +				val = -val; +			*p++ = val; +		} +		bitpower<<=1; +	} +} + + +static void build_table_color(const unsigned int romtable[16][8], +			      unsigned char p0004[16][1024], +			      unsigned char p8004[16][256]) +{ +	int compression_mode, j, k, bit, pw; +	unsigned char *p0, *p8; +	const unsigned int *r; + +	/* We have 16 compressions tables */ +	for (compression_mode = 0; compression_mode < 16; compression_mode++) { +		p0 = p0004[compression_mode]; +		p8 = p8004[compression_mode]; +		r  = romtable[compression_mode]; + +		for (j = 0; j < 8; j++, r++, p0 += 128) { + +			for (k = 0; k < 16; k++) { +				if (k == 0) +					bit = 1; +				else if (k >= 1 && k < 3) +					bit = (r[0] >> 15) & 7; +				else if (k >= 3 && k < 6) +					bit = (r[0] >> 12) & 7; +				else if (k >= 6 && k < 10) +					bit = (r[0] >> 9) & 7; +				else if (k >= 10 && k < 13) +					bit = (r[0] >> 6) & 7; +				else if (k >= 13 && k < 15) +					bit = (r[0] >> 3) & 7; +				else +					bit = (r[0]) & 7; +				if (k == 0) +					*p8++ = 8; +				else +					*p8++ = j - bit; +				*p8++ = bit; + +				pw = 1 << bit; +				p0[k + 0x00] = (1 * pw) + 0x80; +				p0[k + 0x10] = (2 * pw) + 0x80; +				p0[k + 0x20] = (3 * pw) + 0x80; +				p0[k + 0x30] = (4 * pw) + 0x80; +				p0[k + 0x40] = (-1 * pw) + 0x80; +				p0[k + 0x50] = (-2 * pw) + 0x80; +				p0[k + 0x60] = (-3 * pw) + 0x80; +				p0[k + 0x70] = (-4 * pw) + 0x80; +			}	/* end of for (k=0; k<16; k++, p8++) */ +		}	/* end of for (j=0; j<8; j++ , table++) */ +	} /* end of foreach compression_mode */ +} + +/* + * + */ +static void fill_table_dc00_d800(struct pwc_dec23_private *pdec) +{ +#define SCALEBITS 15 +#define ONE_HALF  (1UL << (SCALEBITS - 1)) +	int i; +	unsigned int offset1 = ONE_HALF; +	unsigned int offset2 = 0x0000; + +	for (i=0; i<256; i++) { +		pdec->table_dc00[i] = offset1 & ~(ONE_HALF); +		pdec->table_d800[i] = offset2; + +		offset1 += 0x7bc4; +		offset2 += 0x7bc4; +	} +} + +/* + * To decode the stream: + *   if look_bits(2) == 0:	# op == 2 in the lookup table + *      skip_bits(2) + *      end of the stream + *   elif look_bits(3) == 7:	# op == 1 in the lookup table + *      skip_bits(3) + *      yyyy = get_bits(4) + *      xxxx = get_bits(8) + *   else:			# op == 0 in the lookup table + *      skip_bits(x) + * + * For speedup processing, we build a lookup table and we takes the first 6 bits. + * + * struct { + *   unsigned char op;	    // operation to execute + *   unsigned char bits;    // bits use to perform operation + *   unsigned char offset1; // offset to add to access in the table_0004 % 16 + *   unsigned char offset2; // offset to add to access in the table_0004 + * } + * + * How to build this table ? + *   op == 2 when (i%4)==0 + *   op == 1 when (i%8)==7 + *   op == 0 otherwise + * + */ +static const unsigned char hash_table_ops[64*4] = { +	0x02, 0x00, 0x00, 0x00, +	0x00, 0x03, 0x01, 0x00, +	0x00, 0x04, 0x01, 0x10, +	0x00, 0x06, 0x01, 0x30, +	0x02, 0x00, 0x00, 0x00, +	0x00, 0x03, 0x01, 0x40, +	0x00, 0x05, 0x01, 0x20, +	0x01, 0x00, 0x00, 0x00, +	0x02, 0x00, 0x00, 0x00, +	0x00, 0x03, 0x01, 0x00, +	0x00, 0x04, 0x01, 0x50, +	0x00, 0x05, 0x02, 0x00, +	0x02, 0x00, 0x00, 0x00, +	0x00, 0x03, 0x01, 0x40, +	0x00, 0x05, 0x03, 0x00, +	0x01, 0x00, 0x00, 0x00, +	0x02, 0x00, 0x00, 0x00, +	0x00, 0x03, 0x01, 0x00, +	0x00, 0x04, 0x01, 0x10, +	0x00, 0x06, 0x02, 0x10, +	0x02, 0x00, 0x00, 0x00, +	0x00, 0x03, 0x01, 0x40, +	0x00, 0x05, 0x01, 0x60, +	0x01, 0x00, 0x00, 0x00, +	0x02, 0x00, 0x00, 0x00, +	0x00, 0x03, 0x01, 0x00, +	0x00, 0x04, 0x01, 0x50, +	0x00, 0x05, 0x02, 0x40, +	0x02, 0x00, 0x00, 0x00, +	0x00, 0x03, 0x01, 0x40, +	0x00, 0x05, 0x03, 0x40, +	0x01, 0x00, 0x00, 0x00, +	0x02, 0x00, 0x00, 0x00, +	0x00, 0x03, 0x01, 0x00, +	0x00, 0x04, 0x01, 0x10, +	0x00, 0x06, 0x01, 0x70, +	0x02, 0x00, 0x00, 0x00, +	0x00, 0x03, 0x01, 0x40, +	0x00, 0x05, 0x01, 0x20, +	0x01, 0x00, 0x00, 0x00, +	0x02, 0x00, 0x00, 0x00, +	0x00, 0x03, 0x01, 0x00, +	0x00, 0x04, 0x01, 0x50, +	0x00, 0x05, 0x02, 0x00, +	0x02, 0x00, 0x00, 0x00, +	0x00, 0x03, 0x01, 0x40, +	0x00, 0x05, 0x03, 0x00, +	0x01, 0x00, 0x00, 0x00, +	0x02, 0x00, 0x00, 0x00, +	0x00, 0x03, 0x01, 0x00, +	0x00, 0x04, 0x01, 0x10, +	0x00, 0x06, 0x02, 0x50, +	0x02, 0x00, 0x00, 0x00, +	0x00, 0x03, 0x01, 0x40, +	0x00, 0x05, 0x01, 0x60, +	0x01, 0x00, 0x00, 0x00, +	0x02, 0x00, 0x00, 0x00, +	0x00, 0x03, 0x01, 0x00, +	0x00, 0x04, 0x01, 0x50, +	0x00, 0x05, 0x02, 0x40, +	0x02, 0x00, 0x00, 0x00, +	0x00, 0x03, 0x01, 0x40, +	0x00, 0x05, 0x03, 0x40, +	0x01, 0x00, 0x00, 0x00 +}; + +/* + * + */ +static const unsigned int MulIdx[16][16] = { +	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, +	{0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,}, +	{0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,}, +	{4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4,}, +	{6, 7, 8, 9, 7, 10, 11, 8, 8, 11, 10, 7, 9, 8, 7, 6,}, +	{4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4,}, +	{1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2,}, +	{0, 3, 3, 0, 1, 2, 2, 1, 2, 1, 1, 2, 3, 0, 0, 3,}, +	{0, 1, 2, 3, 3, 2, 1, 0, 3, 2, 1, 0, 0, 1, 2, 3,}, +	{1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0, 2, 2, 2, 2,}, +	{7, 10, 11, 8, 9, 8, 7, 6, 6, 7, 8, 9, 8, 11, 10, 7,}, +	{4, 5, 5, 4, 5, 4, 4, 5, 5, 4, 4, 5, 4, 5, 5, 4,}, +	{7, 9, 6, 8, 10, 8, 7, 11, 11, 7, 8, 10, 8, 6, 9, 7,}, +	{1, 3, 0, 2, 2, 0, 3, 1, 2, 0, 3, 1, 1, 3, 0, 2,}, +	{1, 2, 2, 1, 3, 0, 0, 3, 0, 3, 3, 0, 2, 1, 1, 2,}, +	{10, 8, 7, 11, 8, 6, 9, 7, 7, 9, 6, 8, 11, 7, 8, 10} +}; + +#if USE_LOOKUP_TABLE_TO_CLAMP +#define MAX_OUTER_CROP_VALUE	(512) +static unsigned char pwc_crop_table[256 + 2*MAX_OUTER_CROP_VALUE]; +#define CLAMP(x) (pwc_crop_table[MAX_OUTER_CROP_VALUE+(x)]) +#else +#define CLAMP(x) ((x)>255?255:((x)<0?0:x)) +#endif + + +/* If the type or the command change, we rebuild the lookup table */ +void pwc_dec23_init(struct pwc_device *pdev, const unsigned char *cmd) +{ +	int flags, version, shift, i; +	struct pwc_dec23_private *pdec = &pdev->dec23; + +	mutex_init(&pdec->lock); + +	if (pdec->last_cmd_valid && pdec->last_cmd == cmd[2]) +		return; + +	if (DEVICE_USE_CODEC3(pdev->type)) { +		flags = cmd[2] & 0x18; +		if (flags == 8) +			pdec->nbits = 7;	/* More bits, mean more bits to encode the stream, but better quality */ +		else if (flags == 0x10) +			pdec->nbits = 8; +		else +			pdec->nbits = 6; + +		version = cmd[2] >> 5; +		build_table_color(KiaraRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1); +		build_table_color(KiaraRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2); + +	} else { + +		flags = cmd[2] & 6; +		if (flags == 2) +			pdec->nbits = 7; +		else if (flags == 4) +			pdec->nbits = 8; +		else +			pdec->nbits = 6; + +		version = cmd[2] >> 3; +		build_table_color(TimonRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1); +		build_table_color(TimonRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2); +	} + +	/* Informations can be coded on a variable number of bits but never less than 8 */ +	shift = 8 - pdec->nbits; +	pdec->scalebits = SCALEBITS - shift; +	pdec->nbitsmask = 0xFF >> shift; + +	fill_table_dc00_d800(pdec); +	build_subblock_pattern(pdec); +	build_bit_powermask_table(pdec); + +#if USE_LOOKUP_TABLE_TO_CLAMP +	/* Build the static table to clamp value [0-255] */ +	for (i=0;i<MAX_OUTER_CROP_VALUE;i++) +		pwc_crop_table[i] = 0; +	for (i=0; i<256; i++) +		pwc_crop_table[MAX_OUTER_CROP_VALUE+i] = i; +	for (i=0; i<MAX_OUTER_CROP_VALUE; i++) +		pwc_crop_table[MAX_OUTER_CROP_VALUE+256+i] = 255; +#endif + +	pdec->last_cmd = cmd[2]; +	pdec->last_cmd_valid = 1; +} + +/* + * Copy the 4x4 image block to Y plane buffer + */ +static void copy_image_block_Y(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits) +{ +#if UNROLL_LOOP_FOR_COPY +	const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE; +	const int *c = src; +	unsigned char *d = dst; + +	*d++ = cm[c[0] >> scalebits]; +	*d++ = cm[c[1] >> scalebits]; +	*d++ = cm[c[2] >> scalebits]; +	*d++ = cm[c[3] >> scalebits]; + +	d = dst + bytes_per_line; +	*d++ = cm[c[4] >> scalebits]; +	*d++ = cm[c[5] >> scalebits]; +	*d++ = cm[c[6] >> scalebits]; +	*d++ = cm[c[7] >> scalebits]; + +	d = dst + bytes_per_line*2; +	*d++ = cm[c[8] >> scalebits]; +	*d++ = cm[c[9] >> scalebits]; +	*d++ = cm[c[10] >> scalebits]; +	*d++ = cm[c[11] >> scalebits]; + +	d = dst + bytes_per_line*3; +	*d++ = cm[c[12] >> scalebits]; +	*d++ = cm[c[13] >> scalebits]; +	*d++ = cm[c[14] >> scalebits]; +	*d++ = cm[c[15] >> scalebits]; +#else +	int i; +	const int *c = src; +	unsigned char *d = dst; +	for (i = 0; i < 4; i++, c++) +		*d++ = CLAMP((*c) >> scalebits); + +	d = dst + bytes_per_line; +	for (i = 0; i < 4; i++, c++) +		*d++ = CLAMP((*c) >> scalebits); + +	d = dst + bytes_per_line*2; +	for (i = 0; i < 4; i++, c++) +		*d++ = CLAMP((*c) >> scalebits); + +	d = dst + bytes_per_line*3; +	for (i = 0; i < 4; i++, c++) +		*d++ = CLAMP((*c) >> scalebits); +#endif +} + +/* + * Copy the 4x4 image block to a CrCb plane buffer + * + */ +static void copy_image_block_CrCb(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits) +{ +#if UNROLL_LOOP_FOR_COPY +	/* Unroll all loops */ +	const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE; +	const int *c = src; +	unsigned char *d = dst; + +	*d++ = cm[c[0] >> scalebits]; +	*d++ = cm[c[4] >> scalebits]; +	*d++ = cm[c[1] >> scalebits]; +	*d++ = cm[c[5] >> scalebits]; +	*d++ = cm[c[2] >> scalebits]; +	*d++ = cm[c[6] >> scalebits]; +	*d++ = cm[c[3] >> scalebits]; +	*d++ = cm[c[7] >> scalebits]; + +	d = dst + bytes_per_line; +	*d++ = cm[c[12] >> scalebits]; +	*d++ = cm[c[8] >> scalebits]; +	*d++ = cm[c[13] >> scalebits]; +	*d++ = cm[c[9] >> scalebits]; +	*d++ = cm[c[14] >> scalebits]; +	*d++ = cm[c[10] >> scalebits]; +	*d++ = cm[c[15] >> scalebits]; +	*d++ = cm[c[11] >> scalebits]; +#else +	int i; +	const int *c1 = src; +	const int *c2 = src + 4; +	unsigned char *d = dst; + +	for (i = 0; i < 4; i++, c1++, c2++) { +		*d++ = CLAMP((*c1) >> scalebits); +		*d++ = CLAMP((*c2) >> scalebits); +	} +	c1 = src + 12; +	d = dst + bytes_per_line; +	for (i = 0; i < 4; i++, c1++, c2++) { +		*d++ = CLAMP((*c1) >> scalebits); +		*d++ = CLAMP((*c2) >> scalebits); +	} +#endif +} + +/* + * To manage the stream, we keep bits in a 32 bits register. + * fill_nbits(n): fill the reservoir with at least n bits + * skip_bits(n): discard n bits from the reservoir + * get_bits(n): fill the reservoir, returns the first n bits and discard the + *              bits from the reservoir. + * __get_nbits(n): faster version of get_bits(n), but asumes that the reservoir + *                 contains at least n bits. bits returned is discarded. + */ +#define fill_nbits(pdec, nbits_wanted) do { \ +   while (pdec->nbits_in_reservoir<(nbits_wanted)) \ +    { \ +      pdec->reservoir |= (*(pdec->stream)++) << (pdec->nbits_in_reservoir); \ +      pdec->nbits_in_reservoir += 8; \ +    } \ +}  while(0); + +#define skip_nbits(pdec, nbits_to_skip) do { \ +   pdec->reservoir >>= (nbits_to_skip); \ +   pdec->nbits_in_reservoir -= (nbits_to_skip); \ +}  while(0); + +#define get_nbits(pdec, nbits_wanted, result) do { \ +   fill_nbits(pdec, nbits_wanted); \ +   result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \ +   skip_nbits(pdec, nbits_wanted); \ +}  while(0); + +#define __get_nbits(pdec, nbits_wanted, result) do { \ +   result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \ +   skip_nbits(pdec, nbits_wanted); \ +}  while(0); + +#define look_nbits(pdec, nbits_wanted) \ +   ((pdec->reservoir) & ((1U<<(nbits_wanted))-1)) + +/* + * Decode a 4x4 pixel block + */ +static void decode_block(struct pwc_dec23_private *pdec, +			 const unsigned char *ptable0004, +			 const unsigned char *ptable8004) +{ +	unsigned int primary_color; +	unsigned int channel_v, offset1, op; +	int i; + +	fill_nbits(pdec, 16); +	__get_nbits(pdec, pdec->nbits, primary_color); + +	if (look_nbits(pdec,2) == 0) { +		skip_nbits(pdec, 2); +		/* Very simple, the color is the same for all pixels of the square */ +		for (i = 0; i < 16; i++) +			pdec->temp_colors[i] = pdec->table_dc00[primary_color]; + +		return; +	} + +	/* This block is encoded with small pattern */ +	for (i = 0; i < 16; i++) +		pdec->temp_colors[i] = pdec->table_d800[primary_color]; + +	__get_nbits(pdec, 3, channel_v); +	channel_v = ((channel_v & 1) << 2) | (channel_v & 2) | ((channel_v & 4) >> 2); + +	ptable0004 += (channel_v * 128); +	ptable8004 += (channel_v * 32); + +	offset1 = 0; +	do +	{ +		unsigned int htable_idx, rows = 0; +		const unsigned int *block; + +		/* [  zzzz y x x ] +		 *     xx == 00 :=> end of the block def, remove the two bits from the stream +		 *    yxx == 111 +		 *    yxx == any other value +		 * +		 */ +		fill_nbits(pdec, 16); +		htable_idx = look_nbits(pdec, 6); +		op = hash_table_ops[htable_idx * 4]; + +		if (op == 2) { +			skip_nbits(pdec, 2); + +		} else if (op == 1) { +			/* 15bits [ xxxx xxxx yyyy 111 ] +			 * yyy => offset in the table8004 +			 * xxx => offset in the tabled004 (tree) +			 */ +			unsigned int mask, shift; +			unsigned int nbits, col1; +			unsigned int yyyy; + +			skip_nbits(pdec, 3); +			/* offset1 += yyyy */ +			__get_nbits(pdec, 4, yyyy); +			offset1 += 1 + yyyy; +			offset1 &= 0x0F; +			nbits = ptable8004[offset1 * 2]; + +			/* col1 = xxxx xxxx */ +			__get_nbits(pdec, nbits+1, col1); + +			/* Bit mask table */ +			mask = pdec->table_bitpowermask[nbits][col1]; +			shift = ptable8004[offset1 * 2 + 1]; +			rows = ((mask << shift) + 0x80) & 0xFF; + +			block = pdec->table_subblock[rows]; +			for (i = 0; i < 16; i++) +				pdec->temp_colors[i] += block[MulIdx[offset1][i]]; + +		} else { +			/* op == 0 +			 * offset1 is coded on 3 bits +			 */ +			unsigned int shift; + +			offset1 += hash_table_ops [htable_idx * 4 + 2]; +			offset1 &= 0x0F; + +			rows = ptable0004[offset1 + hash_table_ops [htable_idx * 4 + 3]]; +			block = pdec->table_subblock[rows]; +			for (i = 0; i < 16; i++) +				pdec->temp_colors[i] += block[MulIdx[offset1][i]]; + +			shift = hash_table_ops[htable_idx * 4 + 1]; +			skip_nbits(pdec, shift); +		} + +	} while (op != 2); + +} + +static void DecompressBand23(struct pwc_dec23_private *pdec, +			     const unsigned char *rawyuv, +			     unsigned char *planar_y, +			     unsigned char *planar_u, +			     unsigned char *planar_v, +			     unsigned int   compressed_image_width, +			     unsigned int   real_image_width) +{ +	int compression_index, nblocks; +	const unsigned char *ptable0004; +	const unsigned char *ptable8004; + +	pdec->reservoir = 0; +	pdec->nbits_in_reservoir = 0; +	pdec->stream = rawyuv + 1;	/* The first byte of the stream is skipped */ + +	get_nbits(pdec, 4, compression_index); + +	/* pass 1: uncompress Y component */ +	nblocks = compressed_image_width / 4; + +	ptable0004 = pdec->table_0004_pass1[compression_index]; +	ptable8004 = pdec->table_8004_pass1[compression_index]; + +	/* Each block decode a square of 4x4 */ +	while (nblocks) { +		decode_block(pdec, ptable0004, ptable8004); +		copy_image_block_Y(pdec->temp_colors, planar_y, real_image_width, pdec->scalebits); +		planar_y += 4; +		nblocks--; +	} + +	/* pass 2: uncompress UV component */ +	nblocks = compressed_image_width / 8; + +	ptable0004 = pdec->table_0004_pass2[compression_index]; +	ptable8004 = pdec->table_8004_pass2[compression_index]; + +	/* Each block decode a square of 4x4 */ +	while (nblocks) { +		decode_block(pdec, ptable0004, ptable8004); +		copy_image_block_CrCb(pdec->temp_colors, planar_u, real_image_width/2, pdec->scalebits); + +		decode_block(pdec, ptable0004, ptable8004); +		copy_image_block_CrCb(pdec->temp_colors, planar_v, real_image_width/2, pdec->scalebits); + +		planar_v += 8; +		planar_u += 8; +		nblocks -= 2; +	} + +} + +/** + * + * Uncompress a pwc23 buffer. + * + * src: raw data + * dst: image output + */ +void pwc_dec23_decompress(struct pwc_device *pdev, +			  const void *src, +			  void *dst) +{ +	int bandlines_left, bytes_per_block; +	struct pwc_dec23_private *pdec = &pdev->dec23; + +	/* YUV420P image format */ +	unsigned char *pout_planar_y; +	unsigned char *pout_planar_u; +	unsigned char *pout_planar_v; +	unsigned int   plane_size; + +	mutex_lock(&pdec->lock); + +	bandlines_left = pdev->height / 4; +	bytes_per_block = pdev->width * 4; +	plane_size = pdev->height * pdev->width; + +	pout_planar_y = dst; +	pout_planar_u = dst + plane_size; +	pout_planar_v = dst + plane_size + plane_size / 4; + +	while (bandlines_left--) { +		DecompressBand23(pdec, src, +				 pout_planar_y, pout_planar_u, pout_planar_v, +				 pdev->width, pdev->width); +		src += pdev->vbandlength; +		pout_planar_y += bytes_per_block; +		pout_planar_u += pdev->width; +		pout_planar_v += pdev->width; +	} +	mutex_unlock(&pdec->lock); +} diff --git a/drivers/media/usb/pwc/pwc-dec23.h b/drivers/media/usb/pwc/pwc-dec23.h new file mode 100644 index 00000000000..c655b1c1e6a --- /dev/null +++ b/drivers/media/usb/pwc/pwc-dec23.h @@ -0,0 +1,61 @@ +/* Linux driver for Philips webcam +   (C) 2004-2006 Luc Saillard (luc@saillard.org) + +   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +   driver and thus may have bugs that are not present in the original version. +   Please send bug reports and support requests to <luc@saillard.org>. +   The decompression routines have been implemented by reverse-engineering the +   Nemosoft binary pwcx module. Caveat emptor. + +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published by +   the Free Software Foundation; either version 2 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef PWC_DEC23_H +#define PWC_DEC23_H + +struct pwc_device; + +struct pwc_dec23_private +{ +	struct mutex lock; + +	unsigned char last_cmd, last_cmd_valid; + +  unsigned int scalebits; +  unsigned int nbitsmask, nbits; /* Number of bits of a color in the compressed stream */ + +  unsigned int reservoir; +  unsigned int nbits_in_reservoir; + +  const unsigned char *stream; +  int temp_colors[16]; + +  unsigned char table_0004_pass1[16][1024]; +  unsigned char table_0004_pass2[16][1024]; +  unsigned char table_8004_pass1[16][256]; +  unsigned char table_8004_pass2[16][256]; +  unsigned int  table_subblock[256][12]; + +  unsigned char table_bitpowermask[8][256]; +  unsigned int  table_d800[256]; +  unsigned int  table_dc00[256]; + +}; + +void pwc_dec23_init(struct pwc_device *pdev, const unsigned char *cmd); +void pwc_dec23_decompress(struct pwc_device *pdev, +			  const void *src, +			  void *dst); +#endif diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c new file mode 100644 index 00000000000..a73b0bced96 --- /dev/null +++ b/drivers/media/usb/pwc/pwc-if.c @@ -0,0 +1,1169 @@ +/* Linux driver for Philips webcam +   USB and Video4Linux interface part. +   (C) 1999-2004 Nemosoft Unv. +   (C) 2004-2006 Luc Saillard (luc@saillard.org) +   (C) 2011 Hans de Goede <hdegoede@redhat.com> + +   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +   driver and thus may have bugs that are not present in the original version. +   Please send bug reports and support requests to <luc@saillard.org>. +   The decompression routines have been implemented by reverse-engineering the +   Nemosoft binary pwcx module. Caveat emptor. + +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published by +   the Free Software Foundation; either version 2 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +*/ + +/* +   This code forms the interface between the USB layers and the Philips +   specific stuff. Some adanved stuff of the driver falls under an +   NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and +   is thus not distributed in source form. The binary pwcx.o module +   contains the code that falls under the NDA. + +   In case you're wondering: 'pwc' stands for "Philips WebCam", but +   I really didn't want to type 'philips_web_cam' every time (I'm lazy as +   any Linux kernel hacker, but I don't like uncomprehensible abbreviations +   without explanation). + +   Oh yes, convention: to disctinguish between all the various pointers to +   device-structures, I use these names for the pointer variables: +   udev: struct usb_device * +   vdev: struct video_device (member of pwc_dev) +   pdev: struct pwc_devive * +*/ + +/* Contributors: +   - Alvarado: adding whitebalance code +   - Alistar Moire: QuickCam 3000 Pro device/product ID +   - Tony Hoyle: Creative Labs Webcam 5 device/product ID +   - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged +   - Jk Fang: Sotec Afina Eye ID +   - Xavier Roche: QuickCam Pro 4000 ID +   - Jens Knudsen: QuickCam Zoom ID +   - J. Debert: QuickCam for Notebooks ID +   - Pham Thanh Nam: webcam snapshot button as an event input device +*/ + +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/poll.h> +#include <linux/slab.h> +#ifdef CONFIG_USB_PWC_INPUT_EVDEV +#include <linux/usb/input.h> +#endif +#include <linux/vmalloc.h> +#include <asm/io.h> +#include <linux/kernel.h>		/* simple_strtol() */ + +#include "pwc.h" +#include "pwc-kiara.h" +#include "pwc-timon.h" +#include "pwc-dec23.h" +#include "pwc-dec1.h" + +/* Function prototypes and driver templates */ + +/* hotplug device table support */ +static const struct usb_device_id pwc_device_table [] = { +	{ USB_DEVICE(0x0471, 0x0302) }, /* Philips models */ +	{ USB_DEVICE(0x0471, 0x0303) }, +	{ USB_DEVICE(0x0471, 0x0304) }, +	{ USB_DEVICE(0x0471, 0x0307) }, +	{ USB_DEVICE(0x0471, 0x0308) }, +	{ USB_DEVICE(0x0471, 0x030C) }, +	{ USB_DEVICE(0x0471, 0x0310) }, +	{ USB_DEVICE(0x0471, 0x0311) }, /* Philips ToUcam PRO II */ +	{ USB_DEVICE(0x0471, 0x0312) }, +	{ USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */ +	{ USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */ +	{ USB_DEVICE(0x069A, 0x0001) }, /* Askey */ +	{ USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */ +	{ USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */ +	{ USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */ +	{ USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */ +	{ USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */ +	{ USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */ +	{ USB_DEVICE(0x046D, 0x08B6) }, /* Cisco VT Camera */ +	{ USB_DEVICE(0x046D, 0x08B7) }, /* Logitech ViewPort AV 100 */ +	{ USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */ +	{ USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */ +	{ USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */ +	{ USB_DEVICE(0x055D, 0x9002) },	/* Samsung SNC-35E (Ver3.0) */ +	{ USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */ +	{ USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */ +	{ USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */ +	{ USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */ +	{ USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */ +	{ USB_DEVICE(0x0d81, 0x1900) }, +	{ } +}; +MODULE_DEVICE_TABLE(usb, pwc_device_table); + +static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id); +static void usb_pwc_disconnect(struct usb_interface *intf); +static void pwc_isoc_cleanup(struct pwc_device *pdev); + +static struct usb_driver pwc_driver = { +	.name =			"Philips webcam",	/* name */ +	.id_table =		pwc_device_table, +	.probe =		usb_pwc_probe,		/* probe() */ +	.disconnect =		usb_pwc_disconnect,	/* disconnect() */ +}; + +#define MAX_DEV_HINTS	20 +#define MAX_ISOC_ERRORS	20 + +#ifdef CONFIG_USB_PWC_DEBUG +	int pwc_trace = PWC_DEBUG_LEVEL; +#endif +static int power_save = -1; +static int leds[2] = { 100, 0 }; + +/***/ + +static const struct v4l2_file_operations pwc_fops = { +	.owner =	THIS_MODULE, +	.open =		v4l2_fh_open, +	.release =	vb2_fop_release, +	.read =		vb2_fop_read, +	.poll =		vb2_fop_poll, +	.mmap =		vb2_fop_mmap, +	.unlocked_ioctl = video_ioctl2, +}; +static struct video_device pwc_template = { +	.name =		"Philips Webcam",	/* Filled in later */ +	.release =	video_device_release_empty, +	.fops =         &pwc_fops, +	.ioctl_ops =	&pwc_ioctl_ops, +}; + +/***************************************************************************/ +/* Private functions */ + +static struct pwc_frame_buf *pwc_get_next_fill_buf(struct pwc_device *pdev) +{ +	unsigned long flags = 0; +	struct pwc_frame_buf *buf = NULL; + +	spin_lock_irqsave(&pdev->queued_bufs_lock, flags); +	if (list_empty(&pdev->queued_bufs)) +		goto leave; + +	buf = list_entry(pdev->queued_bufs.next, struct pwc_frame_buf, list); +	list_del(&buf->list); +leave: +	spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags); +	return buf; +} + +static void pwc_snapshot_button(struct pwc_device *pdev, int down) +{ +	if (down) { +		PWC_TRACE("Snapshot button pressed.\n"); +	} else { +		PWC_TRACE("Snapshot button released.\n"); +	} + +#ifdef CONFIG_USB_PWC_INPUT_EVDEV +	if (pdev->button_dev) { +		input_report_key(pdev->button_dev, KEY_CAMERA, down); +		input_sync(pdev->button_dev); +	} +#endif +} + +static void pwc_frame_complete(struct pwc_device *pdev) +{ +	struct pwc_frame_buf *fbuf = pdev->fill_buf; + +	/* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus +	   frames on the USB wire after an exposure change. This conditition is +	   however detected  in the cam and a bit is set in the header. +	   */ +	if (pdev->type == 730) { +		unsigned char *ptr = (unsigned char *)fbuf->data; + +		if (ptr[1] == 1 && ptr[0] & 0x10) { +			PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n"); +			pdev->drop_frames += 2; +		} +		if ((ptr[0] ^ pdev->vmirror) & 0x01) { +			pwc_snapshot_button(pdev, ptr[0] & 0x01); +		} +		if ((ptr[0] ^ pdev->vmirror) & 0x02) { +			if (ptr[0] & 0x02) +				PWC_TRACE("Image is mirrored.\n"); +			else +				PWC_TRACE("Image is normal.\n"); +		} +		pdev->vmirror = ptr[0] & 0x03; +		/* Sometimes the trailer of the 730 is still sent as a 4 byte packet +		   after a short frame; this condition is filtered out specifically. A 4 byte +		   frame doesn't make sense anyway. +		   So we get either this sequence: +		   drop_bit set -> 4 byte frame -> short frame -> good frame +		   Or this one: +		   drop_bit set -> short frame -> good frame +		   So we drop either 3 or 2 frames in all! +		   */ +		if (fbuf->filled == 4) +			pdev->drop_frames++; +	} else if (pdev->type == 740 || pdev->type == 720) { +		unsigned char *ptr = (unsigned char *)fbuf->data; +		if ((ptr[0] ^ pdev->vmirror) & 0x01) { +			pwc_snapshot_button(pdev, ptr[0] & 0x01); +		} +		pdev->vmirror = ptr[0] & 0x03; +	} + +	/* In case we were instructed to drop the frame, do so silently. */ +	if (pdev->drop_frames > 0) { +		pdev->drop_frames--; +	} else { +		/* Check for underflow first */ +		if (fbuf->filled < pdev->frame_total_size) { +			PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);" +				       " discarded.\n", fbuf->filled); +		} else { +			fbuf->vb.v4l2_buf.field = V4L2_FIELD_NONE; +			fbuf->vb.v4l2_buf.sequence = pdev->vframe_count; +			vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE); +			pdev->fill_buf = NULL; +			pdev->vsync = 0; +		} +	} /* !drop_frames */ +	pdev->vframe_count++; +} + +/* This gets called for the Isochronous pipe (video). This is done in + * interrupt time, so it has to be fast, not crash, and not stall. Neat. + */ +static void pwc_isoc_handler(struct urb *urb) +{ +	struct pwc_device *pdev = (struct pwc_device *)urb->context; +	int i, fst, flen; +	unsigned char *iso_buf = NULL; + +	if (urb->status == -ENOENT || urb->status == -ECONNRESET || +	    urb->status == -ESHUTDOWN) { +		PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a"); +		return; +	} + +	if (pdev->fill_buf == NULL) +		pdev->fill_buf = pwc_get_next_fill_buf(pdev); + +	if (urb->status != 0) { +		const char *errmsg; + +		errmsg = "Unknown"; +		switch(urb->status) { +			case -ENOSR:		errmsg = "Buffer error (overrun)"; break; +			case -EPIPE:		errmsg = "Stalled (device not responding)"; break; +			case -EOVERFLOW:	errmsg = "Babble (bad cable?)"; break; +			case -EPROTO:		errmsg = "Bit-stuff error (bad cable?)"; break; +			case -EILSEQ:		errmsg = "CRC/Timeout (could be anything)"; break; +			case -ETIME:		errmsg = "Device does not respond"; break; +		} +		PWC_ERROR("pwc_isoc_handler() called with status %d [%s].\n", +			  urb->status, errmsg); +		/* Give up after a number of contiguous errors */ +		if (++pdev->visoc_errors > MAX_ISOC_ERRORS) +		{ +			PWC_ERROR("Too many ISOC errors, bailing out.\n"); +			if (pdev->fill_buf) { +				vb2_buffer_done(&pdev->fill_buf->vb, +						VB2_BUF_STATE_ERROR); +				pdev->fill_buf = NULL; +			} +		} +		pdev->vsync = 0; /* Drop the current frame */ +		goto handler_end; +	} + +	/* Reset ISOC error counter. We did get here, after all. */ +	pdev->visoc_errors = 0; + +	/* vsync: 0 = don't copy data +		  1 = sync-hunt +		  2 = synched +	 */ +	/* Compact data */ +	for (i = 0; i < urb->number_of_packets; i++) { +		fst  = urb->iso_frame_desc[i].status; +		flen = urb->iso_frame_desc[i].actual_length; +		iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; +		if (fst != 0) { +			PWC_ERROR("Iso frame %d has error %d\n", i, fst); +			continue; +		} +		if (flen > 0 && pdev->vsync) { +			struct pwc_frame_buf *fbuf = pdev->fill_buf; + +			if (pdev->vsync == 1) { +				v4l2_get_timestamp( +					&fbuf->vb.v4l2_buf.timestamp); +				pdev->vsync = 2; +			} + +			if (flen + fbuf->filled > pdev->frame_total_size) { +				PWC_ERROR("Frame overflow (%d > %d)\n", +					  flen + fbuf->filled, +					  pdev->frame_total_size); +				pdev->vsync = 0; /* Let's wait for an EOF */ +			} else { +				memcpy(fbuf->data + fbuf->filled, iso_buf, +				       flen); +				fbuf->filled += flen; +			} +		} +		if (flen < pdev->vlast_packet_size) { +			/* Shorter packet... end of frame */ +			if (pdev->vsync == 2) +				pwc_frame_complete(pdev); +			if (pdev->fill_buf == NULL) +				pdev->fill_buf = pwc_get_next_fill_buf(pdev); +			if (pdev->fill_buf) { +				pdev->fill_buf->filled = 0; +				pdev->vsync = 1; +			} +		} +		pdev->vlast_packet_size = flen; +	} + +handler_end: +	i = usb_submit_urb(urb, GFP_ATOMIC); +	if (i != 0) +		PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i); +} + +/* Both v4l2_lock and vb_queue_lock should be locked when calling this */ +static int pwc_isoc_init(struct pwc_device *pdev) +{ +	struct usb_device *udev; +	struct urb *urb; +	int i, j, ret; +	struct usb_interface *intf; +	struct usb_host_interface *idesc = NULL; +	int compression = 0; /* 0..3 = uncompressed..high */ + +	pdev->vsync = 0; +	pdev->vlast_packet_size = 0; +	pdev->fill_buf = NULL; +	pdev->vframe_count = 0; +	pdev->visoc_errors = 0; +	udev = pdev->udev; + +retry: +	/* We first try with low compression and then retry with a higher +	   compression setting if there is not enough bandwidth. */ +	ret = pwc_set_video_mode(pdev, pdev->width, pdev->height, pdev->pixfmt, +				 pdev->vframes, &compression, 1); + +	/* Get the current alternate interface, adjust packet size */ +	intf = usb_ifnum_to_if(udev, 0); +	if (intf) +		idesc = usb_altnum_to_altsetting(intf, pdev->valternate); +	if (!idesc) +		return -EIO; + +	/* Search video endpoint */ +	pdev->vmax_packet_size = -1; +	for (i = 0; i < idesc->desc.bNumEndpoints; i++) { +		if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) { +			pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize); +			break; +		} +	} + +	if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) { +		PWC_ERROR("Failed to find packet size for video endpoint in current alternate setting.\n"); +		return -ENFILE; /* Odd error, that should be noticeable */ +	} + +	/* Set alternate interface */ +	PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate); +	ret = usb_set_interface(pdev->udev, 0, pdev->valternate); +	if (ret == -ENOSPC && compression < 3) { +		compression++; +		goto retry; +	} +	if (ret < 0) +		return ret; + +	/* Allocate and init Isochronuous urbs */ +	for (i = 0; i < MAX_ISO_BUFS; i++) { +		urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); +		if (urb == NULL) { +			PWC_ERROR("Failed to allocate urb %d\n", i); +			pwc_isoc_cleanup(pdev); +			return -ENOMEM; +		} +		pdev->urbs[i] = urb; +		PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb); + +		urb->interval = 1; // devik +		urb->dev = udev; +		urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint); +		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; +		urb->transfer_buffer = usb_alloc_coherent(udev, +							  ISO_BUFFER_SIZE, +							  GFP_KERNEL, +							  &urb->transfer_dma); +		if (urb->transfer_buffer == NULL) { +			PWC_ERROR("Failed to allocate urb buffer %d\n", i); +			pwc_isoc_cleanup(pdev); +			return -ENOMEM; +		} +		urb->transfer_buffer_length = ISO_BUFFER_SIZE; +		urb->complete = pwc_isoc_handler; +		urb->context = pdev; +		urb->start_frame = 0; +		urb->number_of_packets = ISO_FRAMES_PER_DESC; +		for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { +			urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; +			urb->iso_frame_desc[j].length = pdev->vmax_packet_size; +		} +	} + +	/* link */ +	for (i = 0; i < MAX_ISO_BUFS; i++) { +		ret = usb_submit_urb(pdev->urbs[i], GFP_KERNEL); +		if (ret == -ENOSPC && compression < 3) { +			compression++; +			pwc_isoc_cleanup(pdev); +			goto retry; +		} +		if (ret) { +			PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret); +			pwc_isoc_cleanup(pdev); +			return ret; +		} +		PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->urbs[i]); +	} + +	/* All is done... */ +	PWC_DEBUG_OPEN("<< pwc_isoc_init()\n"); +	return 0; +} + +static void pwc_iso_stop(struct pwc_device *pdev) +{ +	int i; + +	/* Unlinking ISOC buffers one by one */ +	for (i = 0; i < MAX_ISO_BUFS; i++) { +		if (pdev->urbs[i]) { +			PWC_DEBUG_MEMORY("Unlinking URB %p\n", pdev->urbs[i]); +			usb_kill_urb(pdev->urbs[i]); +		} +	} +} + +static void pwc_iso_free(struct pwc_device *pdev) +{ +	int i; + +	/* Freeing ISOC buffers one by one */ +	for (i = 0; i < MAX_ISO_BUFS; i++) { +		if (pdev->urbs[i]) { +			PWC_DEBUG_MEMORY("Freeing URB\n"); +			if (pdev->urbs[i]->transfer_buffer) { +				usb_free_coherent(pdev->udev, +					pdev->urbs[i]->transfer_buffer_length, +					pdev->urbs[i]->transfer_buffer, +					pdev->urbs[i]->transfer_dma); +			} +			usb_free_urb(pdev->urbs[i]); +			pdev->urbs[i] = NULL; +		} +	} +} + +/* Both v4l2_lock and vb_queue_lock should be locked when calling this */ +static void pwc_isoc_cleanup(struct pwc_device *pdev) +{ +	PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n"); + +	pwc_iso_stop(pdev); +	pwc_iso_free(pdev); +	usb_set_interface(pdev->udev, 0, 0); + +	PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n"); +} + +/* Must be called with vb_queue_lock hold */ +static void pwc_cleanup_queued_bufs(struct pwc_device *pdev) +{ +	unsigned long flags = 0; + +	spin_lock_irqsave(&pdev->queued_bufs_lock, flags); +	while (!list_empty(&pdev->queued_bufs)) { +		struct pwc_frame_buf *buf; + +		buf = list_entry(pdev->queued_bufs.next, struct pwc_frame_buf, +				 list); +		list_del(&buf->list); +		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); +	} +	spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags); +} + +#ifdef CONFIG_USB_PWC_DEBUG +static const char *pwc_sensor_type_to_string(unsigned int sensor_type) +{ +	switch(sensor_type) { +		case 0x00: +			return "Hyundai CMOS sensor"; +		case 0x20: +			return "Sony CCD sensor + TDA8787"; +		case 0x2E: +			return "Sony CCD sensor + Exas 98L59"; +		case 0x2F: +			return "Sony CCD sensor + ADI 9804"; +		case 0x30: +			return "Sharp CCD sensor + TDA8787"; +		case 0x3E: +			return "Sharp CCD sensor + Exas 98L59"; +		case 0x3F: +			return "Sharp CCD sensor + ADI 9804"; +		case 0x40: +			return "UPA 1021 sensor"; +		case 0x100: +			return "VGA sensor"; +		case 0x101: +			return "PAL MR sensor"; +		default: +			return "unknown type of sensor"; +	} +} +#endif + +/***************************************************************************/ +/* Video4Linux functions */ + +static void pwc_video_release(struct v4l2_device *v) +{ +	struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev); + +	v4l2_ctrl_handler_free(&pdev->ctrl_handler); +	v4l2_device_unregister(&pdev->v4l2_dev); +	kfree(pdev->ctrl_buf); +	kfree(pdev); +} + +/***************************************************************************/ +/* Videobuf2 operations */ + +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, +				unsigned int *nbuffers, unsigned int *nplanes, +				unsigned int sizes[], void *alloc_ctxs[]) +{ +	struct pwc_device *pdev = vb2_get_drv_priv(vq); +	int size; + +	if (*nbuffers < MIN_FRAMES) +		*nbuffers = MIN_FRAMES; +	else if (*nbuffers > MAX_FRAMES) +		*nbuffers = MAX_FRAMES; + +	*nplanes = 1; + +	size = pwc_get_size(pdev, MAX_WIDTH, MAX_HEIGHT); +	sizes[0] = PAGE_ALIGN(pwc_image_sizes[size][0] * +			      pwc_image_sizes[size][1] * 3 / 2); + +	return 0; +} + +static int buffer_init(struct vb2_buffer *vb) +{ +	struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb); + +	/* need vmalloc since frame buffer > 128K */ +	buf->data = vzalloc(PWC_FRAME_SIZE); +	if (buf->data == NULL) +		return -ENOMEM; + +	return 0; +} + +static int buffer_prepare(struct vb2_buffer *vb) +{ +	struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue); + +	/* Don't allow queing new buffers after device disconnection */ +	if (!pdev->udev) +		return -ENODEV; + +	return 0; +} + +static void buffer_finish(struct vb2_buffer *vb) +{ +	struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue); +	struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb); + +	if (vb->state == VB2_BUF_STATE_DONE) { +		/* +		 * Application has called dqbuf and is getting back a buffer +		 * we've filled, take the pwc data we've stored in buf->data +		 * and decompress it into a usable format, storing the result +		 * in the vb2_buffer. +		 */ +		pwc_decompress(pdev, buf); +	} +} + +static void buffer_cleanup(struct vb2_buffer *vb) +{ +	struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb); + +	vfree(buf->data); +} + +static void buffer_queue(struct vb2_buffer *vb) +{ +	struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue); +	struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb); +	unsigned long flags = 0; + +	/* Check the device has not disconnected between prep and queuing */ +	if (!pdev->udev) { +		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); +		return; +	} + +	spin_lock_irqsave(&pdev->queued_bufs_lock, flags); +	list_add_tail(&buf->list, &pdev->queued_bufs); +	spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags); +} + +static int start_streaming(struct vb2_queue *vq, unsigned int count) +{ +	struct pwc_device *pdev = vb2_get_drv_priv(vq); +	int r; + +	if (!pdev->udev) +		return -ENODEV; + +	if (mutex_lock_interruptible(&pdev->v4l2_lock)) +		return -ERESTARTSYS; +	/* Turn on camera and set LEDS on */ +	pwc_camera_power(pdev, 1); +	pwc_set_leds(pdev, leds[0], leds[1]); + +	r = pwc_isoc_init(pdev); +	if (r) { +		/* If we failed turn camera and LEDS back off */ +		pwc_set_leds(pdev, 0, 0); +		pwc_camera_power(pdev, 0); +		/* And cleanup any queued bufs!! */ +		pwc_cleanup_queued_bufs(pdev); +	} +	mutex_unlock(&pdev->v4l2_lock); + +	return r; +} + +static void stop_streaming(struct vb2_queue *vq) +{ +	struct pwc_device *pdev = vb2_get_drv_priv(vq); + +	mutex_lock(&pdev->v4l2_lock); +	if (pdev->udev) { +		pwc_set_leds(pdev, 0, 0); +		pwc_camera_power(pdev, 0); +		pwc_isoc_cleanup(pdev); +	} + +	pwc_cleanup_queued_bufs(pdev); +	mutex_unlock(&pdev->v4l2_lock); +} + +static struct vb2_ops pwc_vb_queue_ops = { +	.queue_setup		= queue_setup, +	.buf_init		= buffer_init, +	.buf_prepare		= buffer_prepare, +	.buf_finish		= buffer_finish, +	.buf_cleanup		= buffer_cleanup, +	.buf_queue		= buffer_queue, +	.start_streaming	= start_streaming, +	.stop_streaming		= stop_streaming, +	.wait_prepare		= vb2_ops_wait_prepare, +	.wait_finish		= vb2_ops_wait_finish, +}; + +/***************************************************************************/ +/* USB functions */ + +/* This function gets called when a new device is plugged in or the usb core + * is loaded. + */ + +static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ +	struct usb_device *udev = interface_to_usbdev(intf); +	struct pwc_device *pdev = NULL; +	int vendor_id, product_id, type_id; +	int rc; +	int features = 0; +	int compression = 0; +	int my_power_save = power_save; +	char serial_number[30], *name; + +	vendor_id = le16_to_cpu(udev->descriptor.idVendor); +	product_id = le16_to_cpu(udev->descriptor.idProduct); + +	/* Check if we can handle this device */ +	PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n", +		vendor_id, product_id, +		intf->altsetting->desc.bInterfaceNumber); + +	/* the interfaces are probed one by one. We are only interested in the +	   video interface (0) now. +	   Interface 1 is the Audio Control, and interface 2 Audio itself. +	 */ +	if (intf->altsetting->desc.bInterfaceNumber > 0) +		return -ENODEV; + +	if (vendor_id == 0x0471) { +		switch (product_id) { +		case 0x0302: +			PWC_INFO("Philips PCA645VC USB webcam detected.\n"); +			name = "Philips 645 webcam"; +			type_id = 645; +			break; +		case 0x0303: +			PWC_INFO("Philips PCA646VC USB webcam detected.\n"); +			name = "Philips 646 webcam"; +			type_id = 646; +			break; +		case 0x0304: +			PWC_INFO("Askey VC010 type 2 USB webcam detected.\n"); +			name = "Askey VC010 webcam"; +			type_id = 646; +			break; +		case 0x0307: +			PWC_INFO("Philips PCVC675K (Vesta) USB webcam detected.\n"); +			name = "Philips 675 webcam"; +			type_id = 675; +			break; +		case 0x0308: +			PWC_INFO("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); +			name = "Philips 680 webcam"; +			type_id = 680; +			break; +		case 0x030C: +			PWC_INFO("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n"); +			name = "Philips 690 webcam"; +			type_id = 690; +			break; +		case 0x0310: +			PWC_INFO("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n"); +			name = "Philips 730 webcam"; +			type_id = 730; +			break; +		case 0x0311: +			PWC_INFO("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n"); +			name = "Philips 740 webcam"; +			type_id = 740; +			break; +		case 0x0312: +			PWC_INFO("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n"); +			name = "Philips 750 webcam"; +			type_id = 750; +			break; +		case 0x0313: +			PWC_INFO("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n"); +			name = "Philips 720K/40 webcam"; +			type_id = 720; +			break; +		case 0x0329: +			PWC_INFO("Philips SPC 900NC USB webcam detected.\n"); +			name = "Philips SPC 900NC webcam"; +			type_id = 740; +			break; +		default: +			return -ENODEV; +			break; +		} +	} +	else if (vendor_id == 0x069A) { +		switch(product_id) { +		case 0x0001: +			PWC_INFO("Askey VC010 type 1 USB webcam detected.\n"); +			name = "Askey VC010 webcam"; +			type_id = 645; +			break; +		default: +			return -ENODEV; +			break; +		} +	} +	else if (vendor_id == 0x046d) { +		switch(product_id) { +		case 0x08b0: +			PWC_INFO("Logitech QuickCam Pro 3000 USB webcam detected.\n"); +			name = "Logitech QuickCam Pro 3000"; +			type_id = 740; /* CCD sensor */ +			break; +		case 0x08b1: +			PWC_INFO("Logitech QuickCam Notebook Pro USB webcam detected.\n"); +			name = "Logitech QuickCam Notebook Pro"; +			type_id = 740; /* CCD sensor */ +			break; +		case 0x08b2: +			PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n"); +			name = "Logitech QuickCam Pro 4000"; +			type_id = 740; /* CCD sensor */ +			if (my_power_save == -1) +				my_power_save = 1; +			break; +		case 0x08b3: +			PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n"); +			name = "Logitech QuickCam Zoom"; +			type_id = 740; /* CCD sensor */ +			break; +		case 0x08B4: +			PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n"); +			name = "Logitech QuickCam Zoom"; +			type_id = 740; /* CCD sensor */ +			if (my_power_save == -1) +				my_power_save = 1; +			break; +		case 0x08b5: +			PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n"); +			name = "Logitech QuickCam Orbit"; +			type_id = 740; /* CCD sensor */ +			if (my_power_save == -1) +				my_power_save = 1; +			features |= FEATURE_MOTOR_PANTILT; +			break; +		case 0x08b6: +			PWC_INFO("Logitech/Cisco VT Camera webcam detected.\n"); +			name = "Cisco VT Camera"; +			type_id = 740; /* CCD sensor */ +			break; +		case 0x08b7: +			PWC_INFO("Logitech ViewPort AV 100 webcam detected.\n"); +			name = "Logitech ViewPort AV 100"; +			type_id = 740; /* CCD sensor */ +			break; +		case 0x08b8: /* Where this released? */ +			PWC_INFO("Logitech QuickCam detected (reserved ID).\n"); +			name = "Logitech QuickCam (res.)"; +			type_id = 730; /* Assuming CMOS */ +			break; +		default: +			return -ENODEV; +			break; +		} +	} +	else if (vendor_id == 0x055d) { +		/* I don't know the difference between the C10 and the C30; +		   I suppose the difference is the sensor, but both cameras +		   work equally well with a type_id of 675 +		 */ +		switch(product_id) { +		case 0x9000: +			PWC_INFO("Samsung MPC-C10 USB webcam detected.\n"); +			name = "Samsung MPC-C10"; +			type_id = 675; +			break; +		case 0x9001: +			PWC_INFO("Samsung MPC-C30 USB webcam detected.\n"); +			name = "Samsung MPC-C30"; +			type_id = 675; +			break; +		case 0x9002: +			PWC_INFO("Samsung SNC-35E (v3.0) USB webcam detected.\n"); +			name = "Samsung MPC-C30"; +			type_id = 740; +			break; +		default: +			return -ENODEV; +			break; +		} +	} +	else if (vendor_id == 0x041e) { +		switch(product_id) { +		case 0x400c: +			PWC_INFO("Creative Labs Webcam 5 detected.\n"); +			name = "Creative Labs Webcam 5"; +			type_id = 730; +			if (my_power_save == -1) +				my_power_save = 1; +			break; +		case 0x4011: +			PWC_INFO("Creative Labs Webcam Pro Ex detected.\n"); +			name = "Creative Labs Webcam Pro Ex"; +			type_id = 740; +			break; +		default: +			return -ENODEV; +			break; +		} +	} +	else if (vendor_id == 0x04cc) { +		switch(product_id) { +		case 0x8116: +			PWC_INFO("Sotec Afina Eye USB webcam detected.\n"); +			name = "Sotec Afina Eye"; +			type_id = 730; +			break; +		default: +			return -ENODEV; +			break; +		} +	} +	else if (vendor_id == 0x06be) { +		switch(product_id) { +		case 0x8116: +			/* This is essentially the same cam as the Sotec Afina Eye */ +			PWC_INFO("AME Co. Afina Eye USB webcam detected.\n"); +			name = "AME Co. Afina Eye"; +			type_id = 750; +			break; +		default: +			return -ENODEV; +			break; +		} + +	} +	else if (vendor_id == 0x0d81) { +		switch(product_id) { +		case 0x1900: +			PWC_INFO("Visionite VCS-UC300 USB webcam detected.\n"); +			name = "Visionite VCS-UC300"; +			type_id = 740; /* CCD sensor */ +			break; +		case 0x1910: +			PWC_INFO("Visionite VCS-UM100 USB webcam detected.\n"); +			name = "Visionite VCS-UM100"; +			type_id = 730; /* CMOS sensor */ +			break; +		default: +			return -ENODEV; +			break; +		} +	} +	else +		return -ENODEV; /* Not any of the know types; but the list keeps growing. */ + +	if (my_power_save == -1) +		my_power_save = 0; + +	memset(serial_number, 0, 30); +	usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); +	PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number); + +	if (udev->descriptor.bNumConfigurations > 1) +		PWC_WARNING("Warning: more than 1 configuration available.\n"); + +	/* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */ +	pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL); +	if (pdev == NULL) { +		PWC_ERROR("Oops, could not allocate memory for pwc_device.\n"); +		return -ENOMEM; +	} +	pdev->type = type_id; +	pdev->features = features; +	pwc_construct(pdev); /* set min/max sizes correct */ + +	mutex_init(&pdev->v4l2_lock); +	mutex_init(&pdev->vb_queue_lock); +	spin_lock_init(&pdev->queued_bufs_lock); +	INIT_LIST_HEAD(&pdev->queued_bufs); + +	pdev->udev = udev; +	pdev->power_save = my_power_save; + +	/* Init videobuf2 queue structure */ +	pdev->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +	pdev->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; +	pdev->vb_queue.drv_priv = pdev; +	pdev->vb_queue.buf_struct_size = sizeof(struct pwc_frame_buf); +	pdev->vb_queue.ops = &pwc_vb_queue_ops; +	pdev->vb_queue.mem_ops = &vb2_vmalloc_memops; +	pdev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; +	rc = vb2_queue_init(&pdev->vb_queue); +	if (rc < 0) { +		PWC_ERROR("Oops, could not initialize vb2 queue.\n"); +		goto err_free_mem; +	} + +	/* Init video_device structure */ +	pdev->vdev = pwc_template; +	strcpy(pdev->vdev.name, name); +	pdev->vdev.queue = &pdev->vb_queue; +	pdev->vdev.queue->lock = &pdev->vb_queue_lock; +	set_bit(V4L2_FL_USE_FH_PRIO, &pdev->vdev.flags); +	video_set_drvdata(&pdev->vdev, pdev); + +	pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); +	PWC_DEBUG_PROBE("Release: %04x\n", pdev->release); + +	/* Allocate USB command buffers */ +	pdev->ctrl_buf = kmalloc(sizeof(pdev->cmd_buf), GFP_KERNEL); +	if (!pdev->ctrl_buf) { +		PWC_ERROR("Oops, could not allocate memory for pwc_device.\n"); +		rc = -ENOMEM; +		goto err_free_mem; +	} + +#ifdef CONFIG_USB_PWC_DEBUG +	/* Query sensor type */ +	if (pwc_get_cmos_sensor(pdev, &rc) >= 0) { +		PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n", +				pdev->vdev.name, +				pwc_sensor_type_to_string(rc), rc); +	} +#endif + +	/* Set the leds off */ +	pwc_set_leds(pdev, 0, 0); + +	/* Setup initial videomode */ +	rc = pwc_set_video_mode(pdev, MAX_WIDTH, MAX_HEIGHT, +				V4L2_PIX_FMT_YUV420, 30, &compression, 1); +	if (rc) +		goto err_free_mem; + +	/* Register controls (and read default values from camera */ +	rc = pwc_init_controls(pdev); +	if (rc) { +		PWC_ERROR("Failed to register v4l2 controls (%d).\n", rc); +		goto err_free_mem; +	} + +	/* And powerdown the camera until streaming starts */ +	pwc_camera_power(pdev, 0); + +	/* Register the v4l2_device structure */ +	pdev->v4l2_dev.release = pwc_video_release; +	rc = v4l2_device_register(&intf->dev, &pdev->v4l2_dev); +	if (rc) { +		PWC_ERROR("Failed to register v4l2-device (%d).\n", rc); +		goto err_free_controls; +	} + +	pdev->v4l2_dev.ctrl_handler = &pdev->ctrl_handler; +	pdev->vdev.v4l2_dev = &pdev->v4l2_dev; +	pdev->vdev.lock = &pdev->v4l2_lock; + +	rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, -1); +	if (rc < 0) { +		PWC_ERROR("Failed to register as video device (%d).\n", rc); +		goto err_unregister_v4l2_dev; +	} +	PWC_INFO("Registered as %s.\n", video_device_node_name(&pdev->vdev)); + +#ifdef CONFIG_USB_PWC_INPUT_EVDEV +	/* register webcam snapshot button input device */ +	pdev->button_dev = input_allocate_device(); +	if (!pdev->button_dev) { +		rc = -ENOMEM; +		goto err_video_unreg; +	} + +	usb_make_path(udev, pdev->button_phys, sizeof(pdev->button_phys)); +	strlcat(pdev->button_phys, "/input0", sizeof(pdev->button_phys)); + +	pdev->button_dev->name = "PWC snapshot button"; +	pdev->button_dev->phys = pdev->button_phys; +	usb_to_input_id(pdev->udev, &pdev->button_dev->id); +	pdev->button_dev->dev.parent = &pdev->udev->dev; +	pdev->button_dev->evbit[0] = BIT_MASK(EV_KEY); +	pdev->button_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA); + +	rc = input_register_device(pdev->button_dev); +	if (rc) { +		input_free_device(pdev->button_dev); +		pdev->button_dev = NULL; +		goto err_video_unreg; +	} +#endif + +	return 0; + +err_video_unreg: +	video_unregister_device(&pdev->vdev); +err_unregister_v4l2_dev: +	v4l2_device_unregister(&pdev->v4l2_dev); +err_free_controls: +	v4l2_ctrl_handler_free(&pdev->ctrl_handler); +err_free_mem: +	kfree(pdev->ctrl_buf); +	kfree(pdev); +	return rc; +} + +/* The user yanked out the cable... */ +static void usb_pwc_disconnect(struct usb_interface *intf) +{ +	struct v4l2_device *v = usb_get_intfdata(intf); +	struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev); + +	mutex_lock(&pdev->vb_queue_lock); +	mutex_lock(&pdev->v4l2_lock); +	/* No need to keep the urbs around after disconnection */ +	if (pdev->vb_queue.streaming) +		pwc_isoc_cleanup(pdev); +	pdev->udev = NULL; +	pwc_cleanup_queued_bufs(pdev); + +	v4l2_device_disconnect(&pdev->v4l2_dev); +	video_unregister_device(&pdev->vdev); +	mutex_unlock(&pdev->v4l2_lock); +	mutex_unlock(&pdev->vb_queue_lock); + +#ifdef CONFIG_USB_PWC_INPUT_EVDEV +	if (pdev->button_dev) +		input_unregister_device(pdev->button_dev); +#endif + +	v4l2_device_put(&pdev->v4l2_dev); +} + + +/* + * Initialization code & module stuff + */ + +static unsigned int leds_nargs; + +#ifdef CONFIG_USB_PWC_DEBUG +module_param_named(trace, pwc_trace, int, 0644); +#endif +module_param(power_save, int, 0644); +module_param_array(leds, int, &leds_nargs, 0444); + +#ifdef CONFIG_USB_PWC_DEBUG +MODULE_PARM_DESC(trace, "For debugging purposes"); +#endif +MODULE_PARM_DESC(power_save, "Turn power saving for new cameras on or off"); +MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); + +MODULE_DESCRIPTION("Philips & OEM USB webcam driver"); +MODULE_AUTHOR("Luc Saillard <luc@saillard.org>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("pwcx"); +MODULE_VERSION( PWC_VERSION ); + +module_usb_driver(pwc_driver); diff --git a/drivers/media/usb/pwc/pwc-kiara.c b/drivers/media/usb/pwc/pwc-kiara.c new file mode 100644 index 00000000000..e5f4fd81712 --- /dev/null +++ b/drivers/media/usb/pwc/pwc-kiara.c @@ -0,0 +1,892 @@ +/* Linux driver for Philips webcam +   (C) 2004-2006 Luc Saillard (luc@saillard.org) + +   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +   driver and thus may have bugs that are not present in the original version. +   Please send bug reports and support requests to <luc@saillard.org>. +   The decompression routines have been implemented by reverse-engineering the +   Nemosoft binary pwcx module. Caveat emptor. + +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published by +   the Free Software Foundation; either version 2 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + + +/* This tables contains entries for the 730/740/750 (Kiara) camera, with +   4 different qualities (no compression, low, medium, high). +   It lists the bandwidth requirements for said mode by its alternate interface +   number. An alternate of 0 means that the mode is unavailable. + +   There are 6 * 4 * 4 entries: +     6 different resolutions subqcif, qsif, qcif, sif, cif, vga +     6 framerates: 5, 10, 15, 20, 25, 30 +     4 compression modi: none, low, medium, high + +   When an uncompressed mode is not available, the next available compressed mode +   will be chosen (unless the decompressor is absent). Sometimes there are only +   1 or 2 compressed modes available; in that case entries are duplicated. +*/ + + +#include "pwc-kiara.h" + +const unsigned int Kiara_fps_vector[PWC_FPS_MAX_KIARA] = { 5, 10, 15, 20, 25, 30 }; + +const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] = +{ +   /* SQCIF */ +   { +      /* 5 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +      /* 10 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +      /* 15 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +      /* 20 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +      /* 25 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +      /* 30 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +   }, +   /* QSIF */ +   { +      /* 5 fps */ +      { +	 {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, +	 {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, +	 {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, +	 {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, +      }, +      /* 10 fps */ +      { +	 {2, 291,    0, {0x1C, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0x01, 0x80}}, +	 {1, 192,  630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, +	 {1, 192,  630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, +	 {1, 192,  630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, +      }, +      /* 15 fps */ +      { +	 {3, 437,    0, {0x1B, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x01, 0x80}}, +	 {2, 292,  640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}}, +	 {2, 292,  640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}}, +	 {1, 192,  420, {0x13, 0xF4, 0x30, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x18, 0xC0, 0x00, 0x80}}, +      }, +      /* 20 fps */ +      { +	 {4, 589,    0, {0x1A, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4D, 0x02, 0x80}}, +	 {3, 448,  730, {0x12, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xC0, 0x01, 0x80}}, +	 {2, 292,  476, {0x12, 0xF4, 0x30, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0x01, 0x80}}, +	 {1, 192,  312, {0x12, 0xF4, 0x50, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0x00, 0x80}}, +      }, +      /* 25 fps */ +      { +	 {5, 703,    0, {0x19, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x02, 0x80}}, +	 {3, 447,  610, {0x11, 0xF4, 0x30, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x28, 0xBF, 0x01, 0x80}}, +	 {2, 292,  398, {0x11, 0xF4, 0x50, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x28, 0x24, 0x01, 0x80}}, +	 {1, 193,  262, {0x11, 0xF4, 0x50, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x28, 0xC1, 0x00, 0x80}}, +      }, +      /* 30 fps */ +      { +	 {8, 874,    0, {0x18, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x6A, 0x03, 0x80}}, +	 {5, 704,  730, {0x10, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x28, 0xC0, 0x02, 0x80}}, +	 {3, 448,  492, {0x10, 0xF4, 0x30, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x28, 0xC0, 0x01, 0x80}}, +	 {2, 292,  320, {0x10, 0xF4, 0x50, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x28, 0x24, 0x01, 0x80}}, +      }, +   }, +   /* QCIF */ +   { +      /* 5 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +      /* 10 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +      /* 15 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +      /* 20 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +      /* 25 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +      /* 30 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +   }, +   /* SIF */ +   { +      /* 5 fps */ +      { +	 {4, 582,    0, {0x0D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x02, 0x80}}, +	 {3, 387, 1276, {0x05, 0xF4, 0x30, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x01, 0x80}}, +	 {2, 291,  960, {0x05, 0xF4, 0x30, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0x01, 0x80}}, +	 {1, 191,  630, {0x05, 0xF4, 0x50, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x18, 0xBF, 0x00, 0x80}}, +      }, +      /* 10 fps */ +      { +	 {0, }, +	 {6, 775, 1278, {0x04, 0xF4, 0x30, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x03, 0x80}}, +	 {3, 447,  736, {0x04, 0xF4, 0x30, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x28, 0xBF, 0x01, 0x80}}, +	 {2, 292,  480, {0x04, 0xF4, 0x70, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x28, 0x24, 0x01, 0x80}}, +      }, +      /* 15 fps */ +      { +	 {0, }, +	 {9, 955, 1050, {0x03, 0xF4, 0x30, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x03, 0x80}}, +	 {4, 592,  650, {0x03, 0xF4, 0x30, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x50, 0x02, 0x80}}, +	 {3, 448,  492, {0x03, 0xF4, 0x50, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x38, 0xC0, 0x01, 0x80}}, +      }, +      /* 20 fps */ +      { +	 {0, }, +	 {9, 958,  782, {0x02, 0xF4, 0x30, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x03, 0x80}}, +	 {5, 703,  574, {0x02, 0xF4, 0x50, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x02, 0x80}}, +	 {3, 446,  364, {0x02, 0xF4, 0x90, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x38, 0xBE, 0x01, 0x80}}, +      }, +      /* 25 fps */ +      { +	 {0, }, +	 {9, 958,  654, {0x01, 0xF4, 0x30, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x03, 0x80}}, +	 {6, 776,  530, {0x01, 0xF4, 0x50, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x03, 0x80}}, +	 {4, 592,  404, {0x01, 0xF4, 0x70, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x48, 0x50, 0x02, 0x80}}, +      }, +      /* 30 fps */ +      { +	 {0, }, +	 {9, 957,  526, {0x00, 0xF4, 0x50, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x03, 0x80}}, +	 {6, 775,  426, {0x00, 0xF4, 0x70, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x03, 0x80}}, +	 {4, 590,  324, {0x00, 0x7A, 0x88, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x50, 0x4E, 0x02, 0x80}}, +      }, +   }, +   /* CIF */ +   { +      /* 5 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +      /* 10 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +      /* 15 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +      /* 20 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +      /* 25 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +      /* 30 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +   }, +   /* VGA */ +   { +      /* 5 fps */ +      { +	 {0, }, +	 {6, 773, 1272, {0x25, 0xF4, 0x30, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}, +	 {4, 592,  976, {0x25, 0xF4, 0x50, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x02, 0x80}}, +	 {3, 448,  738, {0x25, 0xF4, 0x90, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x01, 0x80}}, +      }, +      /* 10 fps */ +      { +	 {0, }, +	 {9, 956,  788, {0x24, 0xF4, 0x70, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x03, 0x80}}, +	 {6, 776,  640, {0x24, 0xF4, 0xB0, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x03, 0x80}}, +	 {4, 592,  488, {0x24, 0x7A, 0xE8, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x02, 0x80}}, +      }, +      /* 15 fps */ +      { +	 {0, }, +	 {9, 957,  526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}}, +	 {9, 957,  526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}}, +	 {8, 895,  492, {0x23, 0x7A, 0xE8, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x03, 0x80}}, +      }, +      /* 20 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +      /* 25 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +      /* 30 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +   }, +}; + + +/* + * Rom table for kiara chips + * + * 32 roms tables (one for each resolution ?) + *  2 tables per roms (one for each passes) (Y, and U&V) + * 128 bytes per passes + */ + +const unsigned int KiaraRomTable [8][2][16][8] = +{ + { /* version 0 */ +  { /* version 0, passes 0 */ +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000001,0x00000001}, +   {0x00000000,0x00000000,0x00000009,0x00000009, +    0x00000009,0x00000009,0x00000009,0x00000009}, +   {0x00000000,0x00000000,0x00000009,0x00000049, +    0x00000049,0x00000049,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000249,0x0000024a,0x00000049}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000249,0x00000249,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00000049,0x00000249, +    0x00000249,0x0000124a,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00000049,0x00000249, +    0x0000124a,0x00009252,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00009252,0x00009292,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x00009292,0x00009292,0x00009493,0x000124db}, +   {0x00000000,0x00000000,0x00000249,0x0000924a, +    0x00009492,0x0000a49b,0x0000a49b,0x000124db}, +   {0x00000000,0x00000000,0x00001249,0x00009252, +    0x0000a493,0x000124db,0x000124db,0x000126dc}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x000124db,0x000126dc,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000124db,0x000136e4,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000126dc,0x0001b724,0x0001b92d,0x0001b925}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000136e4,0x0001b925,0x0001c96e,0x0001c92d}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 0, passes 1 */ +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000}, +   {0x00000000,0x00000000,0x00000001,0x00000009, +    0x00000009,0x00000009,0x00000009,0x00000001}, +   {0x00000000,0x00000000,0x00000009,0x00000009, +    0x00000049,0x00000049,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000249,0x00000249,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00000049,0x00000249, +    0x00000249,0x00000249,0x0000024a,0x00001252}, +   {0x00000000,0x00000000,0x00000049,0x00001249, +    0x0000124a,0x0000124a,0x00001252,0x00009292}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x00009252,0x00009252,0x00009292,0x00009493}, +   {0x00000000,0x00000000,0x00000249,0x0000924a, +    0x00009292,0x00009292,0x00009292,0x00009493}, +   {0x00000000,0x00000000,0x00000249,0x00009292, +    0x00009492,0x00009493,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x0000a493,0x000124db,0x000126dc,0x000126dc}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000126dc,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x00009252,0x00009493, +    0x000126dc,0x000126dc,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000136e4,0x000136e4,0x0001b725,0x0001b724}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 1 */ +  { /* version 1, passes 0 */ +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000001}, +   {0x00000000,0x00000000,0x00000009,0x00000009, +    0x00000009,0x00000009,0x00000009,0x00000009}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000249,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00000049,0x00000249, +    0x00000249,0x00000249,0x0000024a,0x00001252}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x0000124a,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x0000124a,0x0000124a,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x0000124a,0x00009252,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x00009252,0x00009292,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x00009252,0x00009292,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x00000249,0x0000924a, +    0x00009252,0x00009493,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x00000249,0x0000924a, +    0x00009292,0x00009493,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x00000249,0x00009252, +    0x00009492,0x00009493,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x000124db,0x000124db,0x000124db}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000126dc,0x000126dc,0x000126dc}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 1, passes 1 */ +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000}, +   {0x00000000,0x00000000,0x00000049,0x00000009, +    0x00000049,0x00000009,0x00000001,0x00000000}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x00000049,0x00000000}, +   {0x00000000,0x00000000,0x00000249,0x00000049, +    0x00000249,0x00000049,0x0000024a,0x00000001}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x00000249,0x0000024a,0x00000001}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x00000249,0x0000024a,0x00000001}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x00000249,0x0000024a,0x00000009}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x0000124a,0x0000124a,0x0000024a,0x00000009}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x0000124a,0x0000124a,0x0000024a,0x00000009}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x00009252,0x00001252,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x00009292,0x00001252,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x00009292,0x00001252,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009292,0x00001252,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009292,0x00009292,0x00001252,0x0000024a}, +   {0x00000000,0x00000000,0x0000924a,0x0000924a, +    0x00009492,0x00009493,0x00009292,0x00001252}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 2 */ +  { /* version 2, passes 0 */ +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x0000124a,0x00001252,0x00009292}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x0000124a,0x00009252,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x0000124a,0x00009292,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x00009252,0x00009493,0x00009493,0x0000a49b}, +   {0x00000000,0x00000000,0x00000249,0x0000924a, +    0x00009292,0x00009493,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009292,0x00009493,0x0000a49b,0x000124db}, +   {0x00000000,0x00000000,0x00001249,0x00009252, +    0x00009492,0x0000a49b,0x0000a49b,0x000124db}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x000124db,0x000124db,0x000126dc}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x0000a493,0x000124db,0x000126dc,0x000126dc}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x000136e4}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000126dc,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0001249b,0x000126dc,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000124db,0x000136e4,0x000136e4,0x0001b724}, +   {0x00000000,0x00000000,0x00009252,0x000124db, +    0x000126dc,0x0001b724,0x0001b725,0x0001b925}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 2, passes 1 */ +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x00000249,0x0000024a,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00000249, +    0x0000124a,0x0000124a,0x00001252,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x0000124a,0x00009292,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009292,0x00009292,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009292,0x0000a49b,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009292,0x00009493,0x0000a49b,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009292,0x00009493,0x0000a49b,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009492,0x0000a49b,0x0000a49b,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x00009252, +    0x00009492,0x0000a49b,0x0000a49b,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x0000a49b,0x0000a49b,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x0000a49b,0x0000a49b,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000124db,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x00009252,0x0000a49b, +    0x0001249b,0x000126dc,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 3 */ +  { /* version 3, passes 0 */ +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x0000124a,0x0000124a,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009292,0x00009493,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009492,0x0000a49b,0x0000a49b,0x000124db}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x000124db,0x000126dc,0x000126dc}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x000126dc}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000126dc,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000126dc,0x000136e4,0x0001b724}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0001249b,0x000126dc,0x000136e4,0x0001b724}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000126dc,0x000136e4,0x0001b724}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000136e4,0x0001b725,0x0001b724}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000124db,0x000136e4,0x0001b725,0x0001b925}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000126dc,0x000136e4,0x0001b92d,0x0001b925}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, +   {0x00000000,0x00000000,0x0000a492,0x000126db, +    0x000136e4,0x0001b925,0x00025bb6,0x00024b77}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 3, passes 1 */ +   {0x00000000,0x00000000,0x00001249,0x00000249, +    0x0000124a,0x0000124a,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009292,0x00009292,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009492,0x00009493,0x0000a49b,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x00009252, +    0x00009492,0x0000a49b,0x0000a49b,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x0000a49b,0x0000a49b,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x0000a49b,0x000126dc,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x0000a49b,0x000126dc,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x0000a49b,0x000126dc,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x000124db,0x000126dc,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000124db,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x00009492,0x0000a49b, +    0x000136e4,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x0000a492,0x000124db, +    0x0001b724,0x0001b724,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 4 */ +  { /* version 4, passes 0 */ +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00000249,0x00000049, +    0x00000249,0x00000249,0x0000024a,0x00000049}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x0000124a,0x00009252,0x00001252,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009292,0x00009493,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009292,0x00009493,0x00009493,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x0000a49b,0x0000a49b,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000124db,0x000124db,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0001249b,0x000126dc,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x00009252,0x00009493, +    0x000124db,0x000136e4,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00009252,0x0000a49b, +    0x000124db,0x000136e4,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000126dc,0x000136e4,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x00009492,0x0000a49b, +    0x000126dc,0x0001b724,0x0001b725,0x0001b724}, +   {0x00000000,0x00000000,0x0000a492,0x000124db, +    0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 4, passes 1 */ +   {0x00000000,0x00000000,0x00000249,0x00000049, +    0x00000009,0x00000009,0x00000009,0x00000009}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000049,0x00000049,0x00000009,0x00000009}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x00000249,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x0000124a,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x0000124a,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009252,0x0000124a,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x00009252,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x00009292,0x00009292,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x00009292,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x00009493,0x00009493,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x0000a49b,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000124db,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000136e4,0x000126dc,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x00009252,0x000124db, +    0x0001b724,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 5 */ +  { /* version 5, passes 0 */ +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x00000249,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009292,0x00009292,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009492,0x0000a49b,0x0000a49b,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x0000a49b,0x000124db,0x00009493}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000126dc,0x000136e4,0x000124db}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000126dc,0x000136e4,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000126dc,0x000136e4,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000126dc,0x0001b724,0x0001b725,0x000136e4}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, +   {0x00000000,0x00000000,0x00009492,0x0000a49b, +    0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000136e4,0x0001b925,0x0001c96e,0x0001b925}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, +   {0x00000000,0x00000000,0x0000a492,0x000126db, +    0x0001c924,0x0002496d,0x00025bb6,0x00024b77}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 5, passes 1 */ +   {0x00000000,0x00000000,0x00001249,0x00000249, +    0x00000249,0x00000249,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x0000124a,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009252,0x00009252,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x0000a49b,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x0000a49b,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x0000a49b,0x00009292,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x0000a49b,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x0000a49b,0x00009493,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000124db,0x00009493,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000124db,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000124db,0x000124db,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000126dc,0x000126dc,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000136e4,0x000126dc,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x00009292,0x000124db, +    0x000136e4,0x000126dc,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x00009492,0x000126db, +    0x0001b724,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 6 */ +  { /* version 6, passes 0 */ +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009292,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000124db,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000126dc,0x000136e4,0x000124db}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000126dc,0x000136e4,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000126dc,0x0001b724,0x0001b725,0x000126dc}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000136e4,0x0001b724,0x0001b92d,0x000136e4}, +   {0x00000000,0x00000000,0x00009492,0x0000a49b, +    0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, +   {0x00000000,0x00000000,0x0000a492,0x000124db, +    0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d}, +   {0x00000000,0x00000000,0x0000a492,0x000124db, +    0x0001b724,0x0001c92d,0x00024b76,0x0002496e}, +   {0x00000000,0x00000000,0x00012492,0x000126db, +    0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 6, passes 1 */ +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x0000124a,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x00009252,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x00009292,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x0000a49b,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x0000a49b,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x0000a49b,0x00009493,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000124db,0x000124db,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000124db,0x000124db,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000126dc,0x000124db,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000126dc,0x000126dc,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000136e4,0x000126dc,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x00009492,0x000126db, +    0x000136e4,0x000126dc,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x00009492,0x000126db, +    0x0001b724,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x00009492,0x000126db, +    0x0001b724,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001c924,0x0001b724,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 7 */ +  { /* version 7, passes 0 */ +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009292,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x00009493}, +   {0x00000000,0x00000000,0x00001249,0x0000a49b, +    0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000126dc,0x000136e4,0x0001b725,0x000124db}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000136e4,0x0001b724,0x0001b725,0x000126dc}, +   {0x00000000,0x00000000,0x00009292,0x000124db, +    0x000136e4,0x0001b724,0x0001b725,0x000126dc}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000136e4,0x0001b724,0x0001c96e,0x000136e4}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, +   {0x00000000,0x00000000,0x0000a492,0x000124db, +    0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, +   {0x00000000,0x00000000,0x0000a492,0x000124db, +    0x0001b724,0x0001c92d,0x0001c96e,0x0001b925}, +   {0x00000000,0x00000000,0x0000a492,0x000126db, +    0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, +   {0x00000000,0x00000000,0x0000a492,0x000126db, +    0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, +   {0x00000000,0x00000000,0x0000a492,0x000126db, +    0x0001b924,0x0001c92d,0x00024b76,0x0002496e}, +   {0x00000000,0x00000000,0x00012492,0x000136db, +    0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 7, passes 1 */ +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x0000124a,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x00009492,0x00009292,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x0000a49b,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x0000a49b,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x0000a49b,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000126dc,0x0000a49b,0x00009493,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000126dc,0x000124db,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000136e4,0x000124db,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x000136db, +    0x0001b724,0x000124db,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x000136db, +    0x0001b724,0x000126dc,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x00009292,0x000136db, +    0x0001b724,0x000126dc,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x00009492,0x000136db, +    0x0001b724,0x000126dc,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001b724,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001b724,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x00012492,0x0001b6db, +    0x0001c924,0x0001b724,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + } +}; + diff --git a/drivers/media/usb/pwc/pwc-kiara.h b/drivers/media/usb/pwc/pwc-kiara.h new file mode 100644 index 00000000000..8e02b7ac213 --- /dev/null +++ b/drivers/media/usb/pwc/pwc-kiara.h @@ -0,0 +1,48 @@ +/* Linux driver for Philips webcam +   (C) 2004-2006 Luc Saillard (luc@saillard.org) + +   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +   driver and thus may have bugs that are not present in the original version. +   Please send bug reports and support requests to <luc@saillard.org>. +   The decompression routines have been implemented by reverse-engineering the +   Nemosoft binary pwcx module. Caveat emptor. + +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published by +   the Free Software Foundation; either version 2 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +/* Entries for the Kiara (730/740/750) camera */ + +#ifndef PWC_KIARA_H +#define PWC_KIARA_H + +#include "pwc.h" + +#define PWC_FPS_MAX_KIARA 6 + +struct Kiara_table_entry +{ +	char alternate;			/* USB alternate interface */ +	unsigned short packetsize;	/* Normal packet size */ +	unsigned short bandlength;	/* Bandlength when decompressing */ +	unsigned char mode[12];		/* precomputed mode settings for cam */ +}; + +extern const struct Kiara_table_entry Kiara_table[PSZ_MAX][PWC_FPS_MAX_KIARA][4]; +extern const unsigned int KiaraRomTable[8][2][16][8]; +extern const unsigned int Kiara_fps_vector[PWC_FPS_MAX_KIARA]; + +#endif + + diff --git a/drivers/media/usb/pwc/pwc-misc.c b/drivers/media/usb/pwc/pwc-misc.c new file mode 100644 index 00000000000..9be5adffa87 --- /dev/null +++ b/drivers/media/usb/pwc/pwc-misc.c @@ -0,0 +1,93 @@ +/* Linux driver for Philips webcam +   Various miscellaneous functions and tables. +   (C) 1999-2003 Nemosoft Unv. +   (C) 2004-2006 Luc Saillard (luc@saillard.org) + +   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +   driver and thus may have bugs that are not present in the original version. +   Please send bug reports and support requests to <luc@saillard.org>. +   The decompression routines have been implemented by reverse-engineering the +   Nemosoft binary pwcx module. Caveat emptor. + +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published by +   the Free Software Foundation; either version 2 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + + +#include "pwc.h" + +const int pwc_image_sizes[PSZ_MAX][2] = +{ +	{ 128,  96 }, /* sqcif */ +	{ 160, 120 }, /* qsif */ +	{ 176, 144 }, /* qcif */ +	{ 320, 240 }, /* sif */ +	{ 352, 288 }, /* cif */ +	{ 640, 480 }, /* vga */ +}; + +/* x,y -> PSZ_ */ +int pwc_get_size(struct pwc_device *pdev, int width, int height) +{ +	int i; + +	/* Find the largest size supported by the camera that fits into the +	   requested size. */ +	for (i = PSZ_MAX - 1; i >= 0; i--) { +		if (!(pdev->image_mask & (1 << i))) +			continue; + +		if (pwc_image_sizes[i][0] <= width && +		    pwc_image_sizes[i][1] <= height) +			return i; +	} + +	/* No mode found, return the smallest mode we have */ +	for (i = 0; i < PSZ_MAX; i++) { +		if (pdev->image_mask & (1 << i)) +			return i; +	} + +	/* Never reached there always is atleast one supported mode */ +	return 0; +} + +/* initialize variables depending on type and decompressor */ +void pwc_construct(struct pwc_device *pdev) +{ +	if (DEVICE_USE_CODEC1(pdev->type)) { + +		pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF; +		pdev->vcinterface = 2; +		pdev->vendpoint = 4; +		pdev->frame_header_size = 0; +		pdev->frame_trailer_size = 0; + +	} else if (DEVICE_USE_CODEC3(pdev->type)) { + +		pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA; +		pdev->vcinterface = 3; +		pdev->vendpoint = 5; +		pdev->frame_header_size = TOUCAM_HEADER_SIZE; +		pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE; + +	} else /* if (DEVICE_USE_CODEC2(pdev->type)) */ { + +		pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA; +		pdev->vcinterface = 3; +		pdev->vendpoint = 4; +		pdev->frame_header_size = 0; +		pdev->frame_trailer_size = 0; +	} +} diff --git a/drivers/media/usb/pwc/pwc-nala.h b/drivers/media/usb/pwc/pwc-nala.h new file mode 100644 index 00000000000..168c73ef75d --- /dev/null +++ b/drivers/media/usb/pwc/pwc-nala.h @@ -0,0 +1,66 @@ +   /* SQCIF */ +   { +      {0, 0, {0x04, 0x01, 0x03}}, +      {8, 0, {0x05, 0x01, 0x03}}, +      {7, 0, {0x08, 0x01, 0x03}}, +      {7, 0, {0x0A, 0x01, 0x03}}, +      {6, 0, {0x0C, 0x01, 0x03}}, +      {5, 0, {0x0F, 0x01, 0x03}}, +      {4, 0, {0x14, 0x01, 0x03}}, +      {3, 0, {0x18, 0x01, 0x03}}, +   }, +   /* QSIF */ +   { +      {0}, +      {0}, +      {0}, +      {0}, +      {0}, +      {0}, +      {0}, +      {0}, +   }, +   /* QCIF */ +   { +      {0, 0, {0x04, 0x01, 0x02}}, +      {8, 0, {0x05, 0x01, 0x02}}, +      {7, 0, {0x08, 0x01, 0x02}}, +      {6, 0, {0x0A, 0x01, 0x02}}, +      {5, 0, {0x0C, 0x01, 0x02}}, +      {4, 0, {0x0F, 0x01, 0x02}}, +      {1, 0, {0x14, 0x01, 0x02}}, +      {1, 0, {0x18, 0x01, 0x02}}, +   }, +   /* SIF */ +   { +      {0}, +      {0}, +      {0}, +      {0}, +      {0}, +      {0}, +      {0}, +      {0}, +   }, +   /* CIF */ +   { +      {4, 0, {0x04, 0x01, 0x01}}, +      {7, 1, {0x05, 0x03, 0x01}}, +      {6, 1, {0x08, 0x03, 0x01}}, +      {4, 1, {0x0A, 0x03, 0x01}}, +      {3, 1, {0x0C, 0x03, 0x01}}, +      {2, 1, {0x0F, 0x03, 0x01}}, +      {0}, +      {0}, +   }, +   /* VGA */ +   { +      {0}, +      {0}, +      {0}, +      {0}, +      {0}, +      {0}, +      {0}, +      {0}, +   }, diff --git a/drivers/media/usb/pwc/pwc-timon.c b/drivers/media/usb/pwc/pwc-timon.c new file mode 100644 index 00000000000..c56c174b161 --- /dev/null +++ b/drivers/media/usb/pwc/pwc-timon.c @@ -0,0 +1,1448 @@ +/* Linux driver for Philips webcam +   (C) 2004-2006 Luc Saillard (luc@saillard.org) + +   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +   driver and thus may have bugs that are not present in the original version. +   Please send bug reports and support requests to <luc@saillard.org>. +   The decompression routines have been implemented by reverse-engineering the +   Nemosoft binary pwcx module. Caveat emptor. + +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published by +   the Free Software Foundation; either version 2 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + + +/* This tables contains entries for the 675/680/690 (Timon) camera, with +   4 different qualities (no compression, low, medium, high). +   It lists the bandwidth requirements for said mode by its alternate interface +   number. An alternate of 0 means that the mode is unavailable. + +   There are 6 * 4 * 4 entries: +     6 different resolutions subqcif, qsif, qcif, sif, cif, vga +     6 framerates: 5, 10, 15, 20, 25, 30 +     4 compression modi: none, low, medium, high + +   When an uncompressed mode is not available, the next available compressed mode +   will be chosen (unless the decompressor is absent). Sometimes there are only +   1 or 2 compressed modes available; in that case entries are duplicated. +*/ + +#include "pwc-timon.h" + +const unsigned int Timon_fps_vector[PWC_FPS_MAX_TIMON] = { 5, 10, 15, 20, 25, 30 }; + +const struct Timon_table_entry Timon_table[PSZ_MAX][PWC_FPS_MAX_TIMON][4] = +{ +   /* SQCIF */ +   { +      /* 5 fps */ +      { +	 {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, +	 {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, +	 {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, +	 {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, +      }, +      /* 10 fps */ +      { +	 {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, +	 {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, +	 {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, +	 {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, +      }, +      /* 15 fps */ +      { +	 {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, +	 {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, +	 {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, +	 {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, +      }, +      /* 20 fps */ +      { +	 {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, +	 {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, +	 {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, +	 {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, +      }, +      /* 25 fps */ +      { +	 {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, +	 {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, +	 {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, +	 {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, +      }, +      /* 30 fps */ +      { +	 {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, +	 {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, +	 {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, +	 {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, +      }, +   }, +   /* QSIF */ +   { +      /* 5 fps */ +      { +	 {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, +	 {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, +	 {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, +	 {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, +      }, +      /* 10 fps */ +      { +	 {2, 291,    0, {0x2C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0xA1, 0xC0, 0x02}}, +	 {1, 191,  630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, +	 {1, 191,  630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, +	 {1, 191,  630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, +      }, +      /* 15 fps */ +      { +	 {3, 437,    0, {0x2B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x6D, 0xC0, 0x02}}, +	 {2, 291,  640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, +	 {2, 291,  640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, +	 {1, 191,  420, {0x2B, 0xF4, 0x0D, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, +      }, +      /* 20 fps */ +      { +	 {4, 588,    0, {0x2A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4C, 0x52, 0xC0, 0x02}}, +	 {3, 447,  730, {0x2A, 0xF4, 0x05, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, +	 {2, 292,  476, {0x2A, 0xF4, 0x0D, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, +	 {1, 192,  312, {0x2A, 0xF4, 0x1D, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}}, +      }, +      /* 25 fps */ +      { +	 {5, 703,    0, {0x29, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x42, 0xC0, 0x02}}, +	 {3, 447,  610, {0x29, 0xF4, 0x05, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, +	 {2, 292,  398, {0x29, 0xF4, 0x0D, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, +	 {1, 192,  262, {0x29, 0xF4, 0x25, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}}, +      }, +      /* 30 fps */ +      { +	 {8, 873,    0, {0x28, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x69, 0x37, 0xC0, 0x02}}, +	 {5, 704,  774, {0x28, 0xF4, 0x05, 0x18, 0x21, 0x17, 0x59, 0x0F, 0x18, 0xC0, 0x42, 0xC0, 0x02}}, +	 {3, 448,  492, {0x28, 0xF4, 0x05, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x18, 0xC0, 0x69, 0xC0, 0x02}}, +	 {2, 291,  320, {0x28, 0xF4, 0x1D, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}}, +      }, +   }, +   /* QCIF */ +   { +      /* 5 fps */ +      { +	 {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, +	 {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, +	 {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, +	 {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, +      }, +      /* 10 fps */ +      { +	 {3, 385,    0, {0x0C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x81, 0x79, 0xC0, 0x02}}, +	 {2, 291,  800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, +	 {2, 291,  800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, +	 {1, 194,  532, {0x0C, 0xF4, 0x05, 0x10, 0x9A, 0x0F, 0xBE, 0x1B, 0x08, 0xC2, 0xF0, 0xC0, 0x02}}, +      }, +      /* 15 fps */ +      { +	 {4, 577,    0, {0x0B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x41, 0x52, 0xC0, 0x02}}, +	 {3, 447,  818, {0x0B, 0xF4, 0x05, 0x19, 0x89, 0x18, 0xAD, 0x0F, 0x10, 0xBF, 0x69, 0xC0, 0x02}}, +	 {2, 292,  534, {0x0B, 0xF4, 0x05, 0x10, 0xA3, 0x0F, 0xC7, 0x19, 0x10, 0x24, 0xA1, 0xC0, 0x02}}, +	 {1, 195,  356, {0x0B, 0xF4, 0x15, 0x0B, 0x11, 0x0A, 0x35, 0x1E, 0x10, 0xC3, 0xF0, 0xC0, 0x02}}, +      }, +      /* 20 fps */ +      { +	 {6, 776,    0, {0x0A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x08, 0x3F, 0xC0, 0x02}}, +	 {4, 591,  804, {0x0A, 0xF4, 0x05, 0x19, 0x1E, 0x18, 0x42, 0x0F, 0x18, 0x4F, 0x4E, 0xC0, 0x02}}, +	 {3, 447,  608, {0x0A, 0xF4, 0x05, 0x12, 0xFD, 0x12, 0x21, 0x15, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, +	 {2, 291,  396, {0x0A, 0xF4, 0x15, 0x0C, 0x5E, 0x0B, 0x82, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}}, +      }, +      /* 25 fps */ +      { +	 {9, 928,    0, {0x09, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xA0, 0x33, 0xC0, 0x02}}, +	 {5, 703,  800, {0x09, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x10, 0x18, 0xBF, 0x42, 0xC0, 0x02}}, +	 {3, 447,  508, {0x09, 0xF4, 0x0D, 0x0F, 0xD2, 0x0E, 0xF6, 0x1B, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, +	 {2, 292,  332, {0x09, 0xF4, 0x1D, 0x0A, 0x5A, 0x09, 0x7E, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, +      }, +      /* 30 fps */ +      { +	 {0, }, +	 {9, 956,  876, {0x08, 0xF4, 0x05, 0x1B, 0x58, 0x1A, 0x7C, 0x0E, 0x20, 0xBC, 0x33, 0x10, 0x02}}, +	 {4, 592,  542, {0x08, 0xF4, 0x05, 0x10, 0xE4, 0x10, 0x08, 0x17, 0x20, 0x50, 0x4E, 0x10, 0x02}}, +	 {2, 291,  266, {0x08, 0xF4, 0x25, 0x08, 0x48, 0x07, 0x6C, 0x1E, 0x20, 0x23, 0xA1, 0x10, 0x02}}, +      }, +   }, +   /* SIF */ +   { +      /* 5 fps */ +      { +	 {4, 582,    0, {0x35, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x52, 0x60, 0x02}}, +	 {3, 387, 1276, {0x35, 0xF4, 0x05, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x79, 0x60, 0x02}}, +	 {2, 291,  960, {0x35, 0xF4, 0x0D, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0xA1, 0x60, 0x02}}, +	 {1, 191,  630, {0x35, 0xF4, 0x1D, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x08, 0xBF, 0xF4, 0x60, 0x02}}, +      }, +      /* 10 fps */ +      { +	 {0, }, +	 {6, 775, 1278, {0x34, 0xF4, 0x05, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x3F, 0x10, 0x02}}, +	 {3, 447,  736, {0x34, 0xF4, 0x15, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x18, 0xBF, 0x69, 0x10, 0x02}}, +	 {2, 291,  480, {0x34, 0xF4, 0x2D, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x18, 0x23, 0xA1, 0x10, 0x02}}, +      }, +      /* 15 fps */ +      { +	 {0, }, +	 {9, 955, 1050, {0x33, 0xF4, 0x05, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x33, 0x10, 0x02}}, +	 {4, 591,  650, {0x33, 0xF4, 0x15, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x4F, 0x4E, 0x10, 0x02}}, +	 {3, 448,  492, {0x33, 0xF4, 0x25, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x28, 0xC0, 0x69, 0x10, 0x02}}, +      }, +      /* 20 fps */ +      { +	 {0, }, +	 {9, 958,  782, {0x32, 0xF4, 0x0D, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x33, 0xD0, 0x02}}, +	 {5, 703,  574, {0x32, 0xF4, 0x1D, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x42, 0xD0, 0x02}}, +	 {3, 446,  364, {0x32, 0xF4, 0x3D, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x30, 0xBE, 0x69, 0xD0, 0x02}}, +      }, +      /* 25 fps */ +      { +	 {0, }, +	 {9, 958,  654, {0x31, 0xF4, 0x15, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x33, 0x90, 0x02}}, +	 {6, 776,  530, {0x31, 0xF4, 0x25, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x3F, 0x90, 0x02}}, +	 {4, 592,  404, {0x31, 0xF4, 0x35, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x38, 0x50, 0x4E, 0x90, 0x02}}, +      }, +      /* 30 fps */ +      { +	 {0, }, +	 {9, 957,  526, {0x30, 0xF4, 0x25, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x33, 0x60, 0x02}}, +	 {6, 775,  426, {0x30, 0xF4, 0x35, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x3F, 0x60, 0x02}}, +	 {4, 590,  324, {0x30, 0x7A, 0x4B, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x40, 0x4E, 0x52, 0x60, 0x02}}, +      }, +   }, +   /* CIF */ +   { +      /* 5 fps */ +      { +	 {6, 771,    0, {0x15, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x3F, 0x80, 0x02}}, +	 {4, 465, 1278, {0x15, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x03, 0x18, 0xD1, 0x65, 0x80, 0x02}}, +	 {2, 291,  800, {0x15, 0xF4, 0x15, 0x18, 0xF4, 0x17, 0x3C, 0x05, 0x18, 0x23, 0xA1, 0x80, 0x02}}, +	 {1, 193,  528, {0x15, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x18, 0xC1, 0xF4, 0x80, 0x02}}, +      }, +      /* 10 fps */ +      { +	 {0, }, +	 {9, 932, 1278, {0x14, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x04, 0x30, 0xA4, 0x33, 0x10, 0x02}}, +	 {4, 591,  812, {0x14, 0xF4, 0x15, 0x19, 0x56, 0x17, 0x9E, 0x06, 0x28, 0x4F, 0x4E, 0x10, 0x02}}, +	 {2, 291,  400, {0x14, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x28, 0x23, 0xA1, 0x10, 0x02}}, +      }, +      /* 15 fps */ +      { +	 {0, }, +	 {9, 956,  876, {0x13, 0xF4, 0x0D, 0x1B, 0x58, 0x19, 0xA0, 0x05, 0x38, 0xBC, 0x33, 0x60, 0x02}}, +	 {5, 703,  644, {0x13, 0xF4, 0x1D, 0x14, 0x1C, 0x12, 0x64, 0x08, 0x38, 0xBF, 0x42, 0x60, 0x02}}, +	 {3, 448,  410, {0x13, 0xF4, 0x3D, 0x0C, 0xC4, 0x0B, 0x0C, 0x0E, 0x38, 0xC0, 0x69, 0x60, 0x02}}, +      }, +      /* 20 fps */ +      { +	 {0, }, +	 {9, 956,  650, {0x12, 0xF4, 0x1D, 0x14, 0x4A, 0x12, 0x92, 0x09, 0x48, 0xBC, 0x33, 0x10, 0x03}}, +	 {6, 776,  528, {0x12, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x40, 0x08, 0x3F, 0x10, 0x03}}, +	 {4, 591,  402, {0x12, 0xF4, 0x3D, 0x0C, 0x8F, 0x0A, 0xD7, 0x0E, 0x40, 0x4F, 0x4E, 0x10, 0x03}}, +      }, +      /* 25 fps */ +      { +	 {0, }, +	 {9, 956,  544, {0x11, 0xF4, 0x25, 0x10, 0xF4, 0x0F, 0x3C, 0x0A, 0x48, 0xBC, 0x33, 0xC0, 0x02}}, +	 {7, 840,  478, {0x11, 0xF4, 0x2D, 0x0E, 0xEB, 0x0D, 0x33, 0x0B, 0x48, 0x48, 0x3B, 0xC0, 0x02}}, +	 {5, 703,  400, {0x11, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x48, 0xBF, 0x42, 0xC0, 0x02}}, +      }, +      /* 30 fps */ +      { +	 {0, }, +	 {9, 956,  438, {0x10, 0xF4, 0x35, 0x0D, 0xAC, 0x0B, 0xF4, 0x0D, 0x50, 0xBC, 0x33, 0x10, 0x02}}, +	 {7, 838,  384, {0x10, 0xF4, 0x45, 0x0B, 0xFD, 0x0A, 0x45, 0x0F, 0x50, 0x46, 0x3B, 0x10, 0x02}}, +	 {6, 773,  354, {0x10, 0x7A, 0x4B, 0x0B, 0x0C, 0x09, 0x80, 0x10, 0x50, 0x05, 0x3F, 0x10, 0x02}}, +      }, +   }, +   /* VGA */ +   { +      /* 5 fps */ +      { +	 {0, }, +	 {6, 773, 1272, {0x1D, 0xF4, 0x15, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x3F, 0x10, 0x02}}, +	 {4, 592,  976, {0x1D, 0xF4, 0x25, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x4E, 0x10, 0x02}}, +	 {3, 448,  738, {0x1D, 0xF4, 0x3D, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x69, 0x10, 0x02}}, +      }, +      /* 10 fps */ +      { +	 {0, }, +	 {9, 956,  788, {0x1C, 0xF4, 0x35, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x33, 0x10, 0x02}}, +	 {6, 776,  640, {0x1C, 0x7A, 0x53, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x3F, 0x10, 0x02}}, +	 {4, 592,  488, {0x1C, 0x7A, 0x6B, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x4E, 0x10, 0x02}}, +      }, +      /* 15 fps */ +      { +	 {0, }, +	 {9, 957,  526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}}, +	 {9, 957,  526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}}, +	 {8, 895,  492, {0x1B, 0x7A, 0x6B, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x37, 0x80, 0x02}}, +      }, +      /* 20 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +      /* 25 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +      /* 30 fps */ +      { +	 {0, }, +	 {0, }, +	 {0, }, +	 {0, }, +      }, +   }, +}; + +/* + * 16 versions: + *   2 tables  (one for Y, and one for U&V) + *   16 levels of details per tables + *   8 blocs + */ + +const unsigned int TimonRomTable [16][2][16][8] = +{ + { /* version 0 */ +  { /* version 0, passes 0 */ +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000001}, +   {0x00000000,0x00000000,0x00000001,0x00000001, +    0x00000001,0x00000001,0x00000001,0x00000001}, +   {0x00000000,0x00000000,0x00000001,0x00000001, +    0x00000001,0x00000009,0x00000009,0x00000009}, +   {0x00000000,0x00000000,0x00000009,0x00000001, +    0x00000009,0x00000009,0x00000009,0x00000009}, +   {0x00000000,0x00000000,0x00000009,0x00000009, +    0x00000009,0x00000009,0x00000049,0x00000009}, +   {0x00000000,0x00000000,0x00000009,0x00000009, +    0x00000009,0x00000049,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00000009,0x00000009, +    0x00000049,0x00000049,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00000009,0x00000049, +    0x00000049,0x00000049,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000249,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000249,0x00000249,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000249,0x00000249,0x00001252,0x0000024a}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000249,0x0000124a,0x00001252,0x0000024a}, +   {0x00000000,0x00000000,0x00000049,0x00000249, +    0x00000249,0x0000124a,0x00001252,0x0000024a}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x0000124a,0x00009252,0x00009292,0x00001252}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 0, passes 1 */ +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000}, +   {0x00000000,0x00000000,0x00000001,0x00000001, +    0x00000001,0x00000001,0x00000000,0x00000000}, +   {0x00000000,0x00000000,0x00000009,0x00000001, +    0x00000001,0x00000009,0x00000000,0x00000000}, +   {0x00000000,0x00000000,0x00000009,0x00000009, +    0x00000009,0x00000009,0x00000000,0x00000000}, +   {0x00000000,0x00000000,0x00000009,0x00000009, +    0x00000009,0x00000009,0x00000001,0x00000000}, +   {0x00000000,0x00000000,0x00000049,0x00000009, +    0x00000009,0x00000049,0x00000001,0x00000001}, +   {0x00000000,0x00000000,0x00000049,0x00000009, +    0x00000009,0x00000049,0x00000001,0x00000001}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x00000009,0x00000001}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x00000009,0x00000001}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x00000009,0x00000001}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x00000009,0x00000009}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000249,0x00000049,0x00000009}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000249,0x00000049,0x00000009}, +   {0x00000000,0x00000000,0x00000249,0x00000049, +    0x00000249,0x00000249,0x00000049,0x00000009}, +   {0x00000000,0x00000000,0x00001249,0x00000249, +    0x0000124a,0x0000124a,0x0000024a,0x00000049}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 1 */ +  { /* version 1, passes 0 */ +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000001}, +   {0x00000000,0x00000000,0x00000001,0x00000001, +    0x00000001,0x00000009,0x00000009,0x00000009}, +   {0x00000000,0x00000000,0x00000009,0x00000009, +    0x00000009,0x00000009,0x00000009,0x00000009}, +   {0x00000000,0x00000000,0x00000009,0x00000009, +    0x00000009,0x00000049,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00000009,0x00000049, +    0x00000049,0x00000049,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000249,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000249,0x00000249,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00000049,0x00000249, +    0x00000249,0x00000249,0x0000024a,0x00001252}, +   {0x00000000,0x00000000,0x00000049,0x00000249, +    0x00000249,0x0000124a,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x00000049,0x00000249, +    0x0000124a,0x0000124a,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x0000124a,0x0000124a,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x0000124a,0x00009252,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x00009252,0x00009252,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x00000249,0x0000924a, +    0x00009292,0x00009493,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x00001249,0x00009252, +    0x00009492,0x0000a49b,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 1, passes 1 */ +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000}, +   {0x00000000,0x00000000,0x00000009,0x00000009, +    0x00000009,0x00000001,0x00000001,0x00000000}, +   {0x00000000,0x00000000,0x00000009,0x00000009, +    0x00000009,0x00000009,0x00000001,0x00000000}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000009,0x00000001,0x00000000}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x00000001,0x00000001}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x00000009,0x00000001}, +   {0x00000000,0x00000000,0x00000249,0x00000049, +    0x00000049,0x00000249,0x00000009,0x00000001}, +   {0x00000000,0x00000000,0x00000249,0x00000049, +    0x00000249,0x00000249,0x00000009,0x00000009}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x00000249,0x00000049,0x00000009}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x0000124a,0x00000049,0x00000009}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x0000124a,0x00000049,0x00000009}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x0000124a,0x0000024a,0x00000049}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x0000124a,0x0000124a,0x0000024a,0x00000049}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x0000124a,0x0000124a,0x0000024a,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009252,0x00001252,0x0000024a}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 2 */ +  { /* version 2, passes 0 */ +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000001}, +   {0x00000000,0x00000000,0x00000009,0x00000009, +    0x00000009,0x00000009,0x00000009,0x00000009}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000249,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00000049,0x00000249, +    0x00000249,0x00000249,0x0000024a,0x00001252}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x0000124a,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x0000124a,0x0000124a,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x0000124a,0x00009252,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x00009252,0x00009292,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x00009252,0x00009292,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x00000249,0x0000924a, +    0x00009252,0x00009493,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x00000249,0x0000924a, +    0x00009292,0x00009493,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x00000249,0x00009252, +    0x00009492,0x00009493,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x000124db,0x000124db,0x000124db}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000126dc,0x000126dc,0x000126dc}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 2, passes 1 */ +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000}, +   {0x00000000,0x00000000,0x00000049,0x00000009, +    0x00000049,0x00000009,0x00000001,0x00000000}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x00000049,0x00000000}, +   {0x00000000,0x00000000,0x00000249,0x00000049, +    0x00000249,0x00000049,0x0000024a,0x00000001}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x00000249,0x0000024a,0x00000001}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x00000249,0x0000024a,0x00000001}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x00000249,0x0000024a,0x00000009}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x0000124a,0x0000124a,0x0000024a,0x00000009}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x0000124a,0x0000124a,0x0000024a,0x00000009}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x00009252,0x00001252,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x00009292,0x00001252,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x00009292,0x00001252,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009292,0x00001252,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009292,0x00009292,0x00001252,0x0000024a}, +   {0x00000000,0x00000000,0x0000924a,0x0000924a, +    0x00009492,0x00009493,0x00009292,0x00001252}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 3 */ +  { /* version 3, passes 0 */ +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000001}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00000049,0x00000249, +    0x00000249,0x00000249,0x00001252,0x0000024a}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x0000124a,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x0000124a,0x00009252,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x0000124a,0x00009292,0x00009292,0x00009493}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x00009252,0x00009292,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x00009292,0x00009493,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x00000249,0x00009252, +    0x00009292,0x00009493,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x00001249,0x00009252, +    0x00009292,0x0000a49b,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x00001249,0x00009252, +    0x00009492,0x0000a49b,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x0000a49b,0x000124db,0x000124db}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x0000a493,0x0000a49b,0x000124db,0x000124db}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0001249b,0x000126dc,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000124db,0x000136e4,0x0001b725,0x000136e4}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 3, passes 1 */ +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000}, +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x00000001,0x00000000}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x00000249,0x00000049,0x00000001}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x0000124a,0x00001252,0x00000001}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x0000124a,0x0000124a,0x00001252,0x00000009}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x0000124a,0x00009252,0x00009292,0x00000009}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x00009252,0x00009292,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009252,0x00009292,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009493,0x00009292,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009493,0x00009292,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009493,0x00009493,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009292,0x00009493,0x00009493,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009492,0x00009493,0x00009493,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009252, +    0x00009492,0x0000a49b,0x00009493,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x00009292, +    0x0000a493,0x000124db,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 4 */ +  { /* version 4, passes 0 */ +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x0000124a,0x00001252,0x00009292}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x0000124a,0x00009252,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x0000124a,0x00009292,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x00009252,0x00009493,0x00009493,0x0000a49b}, +   {0x00000000,0x00000000,0x00000249,0x0000924a, +    0x00009292,0x00009493,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009292,0x00009493,0x0000a49b,0x000124db}, +   {0x00000000,0x00000000,0x00001249,0x00009252, +    0x00009492,0x0000a49b,0x0000a49b,0x000124db}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x000124db,0x000124db,0x000126dc}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x0000a493,0x000124db,0x000126dc,0x000126dc}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x000136e4}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000126dc,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0001249b,0x000126dc,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000124db,0x000136e4,0x000136e4,0x0001b724}, +   {0x00000000,0x00000000,0x00009252,0x000124db, +    0x000126dc,0x0001b724,0x0001b725,0x0001b925}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 4, passes 1 */ +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x00000249,0x0000024a,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00000249, +    0x0000124a,0x0000124a,0x00001252,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x0000124a,0x00009292,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009292,0x00009292,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009292,0x0000a49b,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009292,0x00009493,0x0000a49b,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009292,0x00009493,0x0000a49b,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009492,0x0000a49b,0x0000a49b,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x00009252, +    0x00009492,0x0000a49b,0x0000a49b,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x0000a49b,0x0000a49b,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x0000a49b,0x0000a49b,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000124db,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x00009252,0x0000a49b, +    0x0001249b,0x000126dc,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 5 */ +  { /* version 5, passes 0 */ +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x0000124a,0x00001252,0x00009292}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x0000124a,0x00009292,0x00009292,0x00009493}, +   {0x00000000,0x00000000,0x00000249,0x0000924a, +    0x00009292,0x00009493,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009292,0x00009493,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009492,0x0000a49b,0x0000a49b,0x000124db}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x0000a49b,0x000124db,0x000124db}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x0000a493,0x000124db,0x000124db,0x000126dc}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x000126dc}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000126dc,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0001249b,0x000126dc,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0001249b,0x000126dc,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0001249b,0x000126dc,0x0001b725,0x0001b724}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000124db,0x000126dc,0x0001b725,0x0001b724}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000126dc,0x000136e4,0x0001b92d,0x0001b925}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000136e4,0x0001b724,0x0001c96e,0x0001c92d}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 5, passes 1 */ +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x0000124a,0x00000249,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x0000124a,0x00001252,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009292,0x00009493,0x00009493,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009292,0x00009493,0x00009493,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009292,0x00009493,0x0000a49b,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009492,0x00009493,0x000124db,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x00009493,0x000124db,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x0000a49b,0x000124db,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x0000a49b,0x000124db,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000124db,0x000124db,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000124db,0x000124db,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000124db,0x000124db,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000124db,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000124db,0x000126dc,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x00009252,0x000124db, +    0x000126dc,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 6 */ +  { /* version 6, passes 0 */ +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x0000124a,0x0000124a,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009292,0x00009493,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009492,0x0000a49b,0x0000a49b,0x000124db}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x000124db,0x000126dc,0x000126dc}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x000126dc}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000126dc,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000126dc,0x000136e4,0x0001b724}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0001249b,0x000126dc,0x000136e4,0x0001b724}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000126dc,0x000136e4,0x0001b724}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000136e4,0x0001b725,0x0001b724}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000124db,0x000136e4,0x0001b725,0x0001b925}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000126dc,0x000136e4,0x0001b92d,0x0001b925}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, +   {0x00000000,0x00000000,0x0000a492,0x000126db, +    0x000136e4,0x0001b925,0x00025bb6,0x00024b77}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 6, passes 1 */ +   {0x00000000,0x00000000,0x00001249,0x00000249, +    0x0000124a,0x0000124a,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009292,0x00009292,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009492,0x00009493,0x0000a49b,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x00009252, +    0x00009492,0x0000a49b,0x0000a49b,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x0000a49b,0x0000a49b,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x0000a49b,0x000126dc,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x0000a49b,0x000126dc,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x0000a49b,0x000126dc,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x000124db,0x000126dc,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000124db,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x00009492,0x0000a49b, +    0x000136e4,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x0000a492,0x000124db, +    0x0001b724,0x0001b724,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 7 */ +  { /* version 7, passes 0 */ +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009292,0x00009493,0x0000a49b,0x000124db}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x0000a493,0x0000a49b,0x000124db,0x000126dc}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x000136e4}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000124db,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0001249b,0x000126dc,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x00001249,0x0000a49b, +    0x0001249b,0x000126dc,0x000136e4,0x0001b724}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000126dc,0x000136e4,0x0001b724}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000124db,0x000136e4,0x0001b725,0x0001b724}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000126dc,0x000136e4,0x0001b725,0x0001b925}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000126dc,0x0001b724,0x0001b92d,0x0001b925}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, +   {0x00000000,0x00000000,0x00009292,0x000124db, +    0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000136e4,0x0001b724,0x0001c96e,0x0002496e}, +   {0x00000000,0x00000000,0x00009492,0x000126db, +    0x000136e4,0x0001b925,0x0001c96e,0x0002496e}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001b724,0x0002496d,0x00025bb6,0x00025bbf}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 7, passes 1 */ +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009292,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009492,0x00009493,0x00009493,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x0000a49b,0x0000a49b,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x0000a49b,0x000124db,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000124db,0x000124db,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x000124db,0x000136e4,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x000124db,0x000136e4,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000124db,0x000136e4,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000126dc,0x000136e4,0x000124db}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000126dc,0x000136e4,0x000136e4,0x000124db}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000126dc,0x000136e4,0x000136e4,0x000124db}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000136e4,0x000136e4,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x0000a492,0x000124db, +    0x000136e4,0x0001b724,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00012492,0x000126db, +    0x0001b724,0x0001b925,0x0001b725,0x000136e4}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 8 */ +  { /* version 8, passes 0 */ +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009292,0x00009493,0x0000a49b,0x000124db}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x0000a493,0x000124db,0x000126dc,0x000126dc}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x000136e4}, +   {0x00000000,0x00000000,0x00001249,0x0000a49b, +    0x0001249b,0x000126dc,0x000136e4,0x0001b724}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000126dc,0x000136e4,0x0001b724}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000124db,0x000136e4,0x0001b725,0x0001b724}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000126dc,0x000136e4,0x0001b725,0x0001b925}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, +   {0x00000000,0x00000000,0x00009252,0x000124db, +    0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, +   {0x00000000,0x00000000,0x00009292,0x000124db, +    0x000126dc,0x0001b925,0x0001c96e,0x0001c92d}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000136e4,0x0001b925,0x0001c96e,0x0001c92d}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000136e4,0x0001b925,0x00024b76,0x00024b77}, +   {0x00000000,0x00000000,0x00009492,0x000126db, +    0x000136e4,0x0001b925,0x00024b76,0x00025bbf}, +   {0x00000000,0x00000000,0x0000a492,0x000126db, +    0x000136e4,0x0001c92d,0x00024b76,0x00025bbf}, +   {0x00000000,0x00000000,0x00012492,0x000136db, +    0x0001b724,0x00024b6d,0x0002ddb6,0x0002efff}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 8, passes 1 */ +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009493,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x0000a49b,0x000124db,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x000124db,0x000126dc,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x000124db,0x000136e4,0x000124db}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000126dc,0x000136e4,0x000124db}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000126dc,0x000126dc,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000126dc,0x000136e4,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000126dc,0x000136e4,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000126dc,0x000136e4,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x00009292,0x000124db, +    0x000136e4,0x0001b724,0x0001b725,0x000136e4}, +   {0x00000000,0x00000000,0x00009492,0x000126db, +    0x000136e4,0x0001b925,0x0001b725,0x0001b724}, +   {0x00000000,0x00000000,0x00009492,0x000126db, +    0x000136e4,0x0001b925,0x0001b725,0x0001b724}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001b724,0x0002496d,0x0001b92d,0x0001b925}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 9 */ +  { /* version 9, passes 0 */ +   {0x00000000,0x00000000,0x00000049,0x00000049, +    0x00000049,0x00000049,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00000249,0x00000049, +    0x00000249,0x00000249,0x0000024a,0x00000049}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x0000124a,0x00009252,0x00001252,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009292,0x00009493,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009292,0x00009493,0x00009493,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x0000a49b,0x0000a49b,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000124db,0x000124db,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0001249b,0x000126dc,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x00009252,0x00009493, +    0x000124db,0x000136e4,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00009252,0x0000a49b, +    0x000124db,0x000136e4,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000126dc,0x000136e4,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x00009492,0x0000a49b, +    0x000126dc,0x0001b724,0x0001b725,0x0001b724}, +   {0x00000000,0x00000000,0x0000a492,0x000124db, +    0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 9, passes 1 */ +   {0x00000000,0x00000000,0x00000249,0x00000049, +    0x00000009,0x00000009,0x00000009,0x00000009}, +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000049,0x00000049,0x00000009,0x00000009}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x00000249,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x0000124a,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x0000124a,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009252,0x0000124a,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x00009252,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x00009292,0x00009292,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x00009292,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x00009493,0x00009493,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x0000a49b,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000124db,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000136e4,0x000126dc,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x00009252,0x000124db, +    0x0001b724,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 10 */ +  { /* version 10, passes 0 */ +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x00000249,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00000249,0x00001249, +    0x00009252,0x00009292,0x00009292,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009292,0x00009292,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009492,0x00009493,0x0000a49b,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x000124db,0x000124db,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000124db,0x000124db,0x00009493}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0001249b,0x000126dc,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000124db,0x000126dc,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00009252,0x0000a49b, +    0x000124db,0x000136e4,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000126dc,0x000136e4,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x00009492,0x0000a49b, +    0x000126dc,0x0001b724,0x0001b92d,0x0001b724}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000126dc,0x0001b925,0x0001b92d,0x0001b925}, +   {0x00000000,0x00000000,0x0000a492,0x000126db, +    0x000136e4,0x0002496d,0x0001c96e,0x0001c92d}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 10, passes 1 */ +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000049,0x00000049,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x00000249,0x00000049,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x00009252,0x0000024a,0x00000049}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009493,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00009252, +    0x00009492,0x00009493,0x00001252,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x00009493,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x00009492,0x00009493,0x00009292,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x00009493,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x0000a49b,0x00009493,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x0000a49b,0x00009493,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x000124db,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x000124db,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000136e4,0x000126dc,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000136e4,0x000126dc,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x00009252,0x000126db, +    0x0001b724,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 11 */ +  { /* version 11, passes 0 */ +   {0x00000000,0x00000000,0x00000249,0x00000249, +    0x00000249,0x00000249,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009292,0x00009292,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009492,0x0000a49b,0x0000a49b,0x00009292}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x0000a49b,0x000124db,0x00009493}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000126dc,0x000136e4,0x000124db}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000126dc,0x000136e4,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000126dc,0x000136e4,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000126dc,0x0001b724,0x0001b725,0x000136e4}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, +   {0x00000000,0x00000000,0x00009492,0x0000a49b, +    0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000136e4,0x0001b925,0x0001c96e,0x0001b925}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, +   {0x00000000,0x00000000,0x0000a492,0x000126db, +    0x0001c924,0x0002496d,0x00025bb6,0x00024b77}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 11, passes 1 */ +   {0x00000000,0x00000000,0x00001249,0x00000249, +    0x00000249,0x00000249,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x0000124a,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009252,0x00009252,0x0000024a,0x0000024a}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x0000a49b,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x0000a49b,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x0000a49b,0x00009292,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x0000a49b,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x0000a49b,0x00009493,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000124db,0x00009493,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000124db,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000124db,0x000124db,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000126dc,0x000126dc,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000136e4,0x000126dc,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x00009292,0x000124db, +    0x000136e4,0x000126dc,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x00009492,0x000126db, +    0x0001b724,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 12 */ +  { /* version 12, passes 0 */ +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009292,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000124db,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000126dc,0x000136e4,0x000124db}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000126dc,0x000136e4,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000126dc,0x0001b724,0x0001b725,0x000126dc}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000136e4,0x0001b724,0x0001b92d,0x000136e4}, +   {0x00000000,0x00000000,0x00009492,0x0000a49b, +    0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, +   {0x00000000,0x00000000,0x0000a492,0x000124db, +    0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d}, +   {0x00000000,0x00000000,0x0000a492,0x000124db, +    0x0001b724,0x0001c92d,0x00024b76,0x0002496e}, +   {0x00000000,0x00000000,0x00012492,0x000126db, +    0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 12, passes 1 */ +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x0000124a,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x00001249,0x00009292, +    0x00009492,0x00009252,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x00009292,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x0000a49b,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x0000a49b,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x0000a49b,0x00009493,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000124db,0x000124db,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000124db,0x000124db,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000126dc,0x000124db,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000126dc,0x000126dc,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000136e4,0x000126dc,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x00009492,0x000126db, +    0x000136e4,0x000126dc,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x00009492,0x000126db, +    0x0001b724,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x00009492,0x000126db, +    0x0001b724,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001c924,0x0001b724,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 13 */ +  { /* version 13, passes 0 */ +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x00009252,0x00009292,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x000124db,0x000126dc,0x00009493}, +   {0x00000000,0x00000000,0x00001249,0x0000a49b, +    0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000126dc,0x000136e4,0x0001b725,0x000124db}, +   {0x00000000,0x00000000,0x00009292,0x0000a49b, +    0x000136e4,0x0001b724,0x0001b725,0x000126dc}, +   {0x00000000,0x00000000,0x00009292,0x000124db, +    0x000136e4,0x0001b724,0x0001b725,0x000126dc}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000136e4,0x0001b724,0x0001c96e,0x000136e4}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, +   {0x00000000,0x00000000,0x0000a492,0x000124db, +    0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, +   {0x00000000,0x00000000,0x0000a492,0x000124db, +    0x0001b724,0x0001c92d,0x0001c96e,0x0001b925}, +   {0x00000000,0x00000000,0x0000a492,0x000126db, +    0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, +   {0x00000000,0x00000000,0x0000a492,0x000126db, +    0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, +   {0x00000000,0x00000000,0x0000a492,0x000126db, +    0x0001b924,0x0001c92d,0x00024b76,0x0002496e}, +   {0x00000000,0x00000000,0x00012492,0x000136db, +    0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 13, passes 1 */ +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x0000124a,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x00009492,0x00009292,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x0000a49b,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x0000a49b,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x0000a49b,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000126dc,0x0000a49b,0x00009493,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000126dc,0x000124db,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000136e4,0x000124db,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x000136db, +    0x0001b724,0x000124db,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x000136db, +    0x0001b724,0x000126dc,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x00009292,0x000136db, +    0x0001b724,0x000126dc,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x00009492,0x000136db, +    0x0001b724,0x000126dc,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001b724,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001b724,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x00012492,0x0001b6db, +    0x0001c924,0x0001b724,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 14 */ +  { /* version 14, passes 0 */ +   {0x00000000,0x00000000,0x00001249,0x0000924a, +    0x00009292,0x00009493,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x00001249,0x0000a49b, +    0x0000a493,0x000124db,0x000126dc,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000126dc,0x000136e4,0x0001b725,0x000124db}, +   {0x00000000,0x00000000,0x00009292,0x000124db, +    0x000126dc,0x0001b724,0x0001b92d,0x000126dc}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000136e4,0x0001b724,0x0001b92d,0x000126dc}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000136e4,0x0001c92d,0x0001c96e,0x000136e4}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x0001b724,0x0001c92d,0x0001c96e,0x0001b724}, +   {0x00000000,0x00000000,0x0000a492,0x000124db, +    0x0001b724,0x0001c92d,0x00024b76,0x0001b925}, +   {0x00000000,0x00000000,0x0000a492,0x000126db, +    0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, +   {0x00000000,0x00000000,0x0000a492,0x000126db, +    0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001b724,0x0001c92d,0x00024b76,0x0002496e}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001b924,0x0002496d,0x00024b76,0x00024b77}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001b924,0x00024b6d,0x0002ddb6,0x00025bbf}, +   {0x00000000,0x00000000,0x00012492,0x0001b6db, +    0x00024924,0x0002db6d,0x00036db6,0x0002efff}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 14, passes 1 */ +   {0x00000000,0x00000000,0x00001249,0x00001249, +    0x0000124a,0x0000124a,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x00009493, +    0x0000a493,0x00009292,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x0000a49b,0x00001252,0x00001252}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000136e4,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000136e4,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000136e4,0x000136e4,0x00009493,0x00009292}, +   {0x00000000,0x00000000,0x00009492,0x000136db, +    0x0001b724,0x000136e4,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x00009492,0x000136db, +    0x0001b724,0x000136e4,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x00009492,0x000136db, +    0x0001b724,0x000136e4,0x0000a49b,0x00009493}, +   {0x00000000,0x00000000,0x00009492,0x000136db, +    0x0001b724,0x000136e4,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001b724,0x000136e4,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001b724,0x000136e4,0x000124db,0x0000a49b}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001b724,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001b724,0x000136e4,0x000126dc,0x000124db}, +   {0x00000000,0x00000000,0x00012492,0x0001b6db, +    0x0001c924,0x0001b724,0x000136e4,0x000126dc}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + }, + { /* version 15 */ +  { /* version 15, passes 0 */ +   {0x00000000,0x00000000,0x00001249,0x00009493, +    0x0000a493,0x0000a49b,0x000124db,0x000124db}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0001249b,0x000126dc,0x000136e4,0x000124db}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x000126dc,0x0001b724,0x0001b725,0x000126dc}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000136e4,0x0001b724,0x0001b92d,0x000126dc}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x000136e4,0x0001b925,0x0001c96e,0x000136e4}, +   {0x00000000,0x00000000,0x00009492,0x000124db, +    0x0001b724,0x0001c92d,0x0001c96e,0x0001b724}, +   {0x00000000,0x00000000,0x0000a492,0x000124db, +    0x0001b724,0x0001c92d,0x0001c96e,0x0001b724}, +   {0x00000000,0x00000000,0x0000a492,0x000126db, +    0x0001b724,0x0001c92d,0x0001c96e,0x0001b925}, +   {0x00000000,0x00000000,0x0000a492,0x000126db, +    0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001b924,0x0002496d,0x00024b76,0x0002496e}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001c924,0x0002496d,0x00025bb6,0x00024b77}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001c924,0x00024b6d,0x00025bb6,0x00024b77}, +   {0x00000000,0x00000000,0x00012492,0x000136db, +    0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf}, +   {0x00000000,0x00000000,0x00012492,0x0001b6db, +    0x00024924,0x0002db6d,0x00036db6,0x0002efff}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  }, +  { /* version 15, passes 1 */ +   {0x00000000,0x00000000,0x0000924a,0x0000924a, +    0x00009292,0x00009292,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x0000a49b, +    0x0000a493,0x000124db,0x00009292,0x00009292}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000124db,0x0001b724,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000126dc,0x0001b724,0x00009493,0x00009493}, +   {0x00000000,0x00000000,0x0000924a,0x000124db, +    0x000136e4,0x0001b724,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x00009292,0x000136db, +    0x0001b724,0x0001b724,0x0000a49b,0x0000a49b}, +   {0x00000000,0x00000000,0x00009492,0x000136db, +    0x0001c924,0x0001b724,0x000124db,0x000124db}, +   {0x00000000,0x00000000,0x00009492,0x000136db, +    0x0001c924,0x0001b724,0x000124db,0x000124db}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001c924,0x0001b724,0x000126dc,0x000126dc}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001c924,0x0001b925,0x000126dc,0x000126dc}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001c924,0x0001b925,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001c924,0x0001b925,0x000136e4,0x000136e4}, +   {0x00000000,0x00000000,0x0000a492,0x000136db, +    0x0001c924,0x0001b925,0x0001b725,0x0001b724}, +   {0x00000000,0x00000000,0x00012492,0x000136db, +    0x0001c924,0x0001b925,0x0001b725,0x0001b724}, +   {0x00000000,0x00000000,0x00012492,0x0001b6db, +    0x00024924,0x0002496d,0x0001b92d,0x0001b925}, +   {0x00000000,0x00000000,0x00000000,0x00000000, +    0x00000000,0x00000000,0x00000000,0x00000000} +  } + } +}; diff --git a/drivers/media/usb/pwc/pwc-timon.h b/drivers/media/usb/pwc/pwc-timon.h new file mode 100644 index 00000000000..270c5b9010f --- /dev/null +++ b/drivers/media/usb/pwc/pwc-timon.h @@ -0,0 +1,63 @@ +/* Linux driver for Philips webcam +   (C) 2004-2006 Luc Saillard (luc@saillard.org) + +   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +   driver and thus may have bugs that are not present in the original version. +   Please send bug reports and support requests to <luc@saillard.org>. +   The decompression routines have been implemented by reverse-engineering the +   Nemosoft binary pwcx module. Caveat emptor. + +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published by +   the Free Software Foundation; either version 2 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + + + +/* This tables contains entries for the 675/680/690 (Timon) camera, with +   4 different qualities (no compression, low, medium, high). +   It lists the bandwidth requirements for said mode by its alternate interface +   number. An alternate of 0 means that the mode is unavailable. + +   There are 6 * 4 * 4 entries: +     6 different resolutions subqcif, qsif, qcif, sif, cif, vga +     6 framerates: 5, 10, 15, 20, 25, 30 +     4 compression modi: none, low, medium, high + +   When an uncompressed mode is not available, the next available compressed mode +   will be chosen (unless the decompressor is absent). Sometimes there are only +   1 or 2 compressed modes available; in that case entries are duplicated. +*/ + +#ifndef PWC_TIMON_H +#define PWC_TIMON_H + +#include "pwc.h" + +#define PWC_FPS_MAX_TIMON 6 + +struct Timon_table_entry +{ +	char alternate;			/* USB alternate interface */ +	unsigned short packetsize;	/* Normal packet size */ +	unsigned short bandlength;	/* Bandlength when decompressing */ +	unsigned char mode[13];		/* precomputed mode settings for cam */ +}; + +extern const struct Timon_table_entry Timon_table[PSZ_MAX][PWC_FPS_MAX_TIMON][4]; +extern const unsigned int TimonRomTable [16][2][16][8]; +extern const unsigned int Timon_fps_vector[PWC_FPS_MAX_TIMON]; + +#endif + + diff --git a/drivers/media/usb/pwc/pwc-uncompress.c b/drivers/media/usb/pwc/pwc-uncompress.c new file mode 100644 index 00000000000..b65903fbcf0 --- /dev/null +++ b/drivers/media/usb/pwc/pwc-uncompress.c @@ -0,0 +1,107 @@ +/* Linux driver for Philips webcam +   Decompression frontend. +   (C) 1999-2003 Nemosoft Unv. +   (C) 2004-2006 Luc Saillard (luc@saillard.org) + +   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +   driver and thus may have bugs that are not present in the original version. +   Please send bug reports and support requests to <luc@saillard.org>. +   The decompression routines have been implemented by reverse-engineering the +   Nemosoft binary pwcx module. Caveat emptor. + +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published by +   the Free Software Foundation; either version 2 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +   vim: set ts=8: +*/ + +#include <asm/current.h> +#include <asm/types.h> + +#include "pwc.h" +#include "pwc-dec1.h" +#include "pwc-dec23.h" + +int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf) +{ +	int n, line, col; +	void *yuv, *image; +	u16 *src; +	u16 *dsty, *dstu, *dstv; + +	image = vb2_plane_vaddr(&fbuf->vb, 0); + +	yuv = fbuf->data + pdev->frame_header_size;  /* Skip header */ + +	/* Raw format; that's easy... */ +	if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) +	{ +		struct pwc_raw_frame *raw_frame = image; +		raw_frame->type = cpu_to_le16(pdev->type); +		raw_frame->vbandlength = cpu_to_le16(pdev->vbandlength); +			/* cmd_buf is always 4 bytes, but sometimes, only the +			 * first 3 bytes is filled (Nala case). We can +			 * determine this using the type of the webcam */ +		memcpy(raw_frame->cmd, pdev->cmd_buf, 4); +		memcpy(raw_frame+1, yuv, pdev->frame_size); +		vb2_set_plane_payload(&fbuf->vb, 0, +			pdev->frame_size + sizeof(struct pwc_raw_frame)); +		return 0; +	} + +	vb2_set_plane_payload(&fbuf->vb, 0, +			      pdev->width * pdev->height * 3 / 2); + +	if (pdev->vbandlength == 0) { +		/* Uncompressed mode. +		 * +		 * We do some byte shuffling here to go from the +		 * native format to YUV420P. +		 */ +		src = (u16 *)yuv; +		n = pdev->width * pdev->height; +		dsty = (u16 *)(image); +		dstu = (u16 *)(image + n); +		dstv = (u16 *)(image + n + n / 4); + +		for (line = 0; line < pdev->height; line++) { +			for (col = 0; col < pdev->width; col += 4) { +				*dsty++ = *src++; +				*dsty++ = *src++; +				if (line & 1) +					*dstv++ = *src++; +				else +					*dstu++ = *src++; +			} +		} + +		return 0; +	} + +	/* +	 * Compressed; +	 * the decompressor routines will write the data in planar format +	 * immediately. +	 */ +	if (DEVICE_USE_CODEC1(pdev->type)) { + +		/* TODO & FIXME */ +		PWC_ERROR("This chipset is not supported for now\n"); +		return -ENXIO; /* No such device or address: missing decompressor */ + +	} else { +		pwc_dec23_decompress(pdev, yuv, image); +	} +	return 0; +} diff --git a/drivers/media/usb/pwc/pwc-v4l.c b/drivers/media/usb/pwc/pwc-v4l.c new file mode 100644 index 00000000000..aa7449eaca0 --- /dev/null +++ b/drivers/media/usb/pwc/pwc-v4l.c @@ -0,0 +1,1052 @@ +/* Linux driver for Philips webcam +   USB and Video4Linux interface part. +   (C) 1999-2004 Nemosoft Unv. +   (C) 2004-2006 Luc Saillard (luc@saillard.org) +   (C) 2011 Hans de Goede <hdegoede@redhat.com> + +   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +   driver and thus may have bugs that are not present in the original version. +   Please send bug reports and support requests to <luc@saillard.org>. +   The decompression routines have been implemented by reverse-engineering the +   Nemosoft binary pwcx module. Caveat emptor. + +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published by +   the Free Software Foundation; either version 2 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +*/ + +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/poll.h> +#include <linux/vmalloc.h> +#include <linux/jiffies.h> +#include <asm/io.h> + +#include "pwc.h" + +#define PWC_CID_CUSTOM(ctrl) ((V4L2_CID_USER_BASE | 0xf000) + custom_ ## ctrl) + +static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl); +static int pwc_s_ctrl(struct v4l2_ctrl *ctrl); + +static const struct v4l2_ctrl_ops pwc_ctrl_ops = { +	.g_volatile_ctrl = pwc_g_volatile_ctrl, +	.s_ctrl = pwc_s_ctrl, +}; + +enum { awb_indoor, awb_outdoor, awb_fl, awb_manual, awb_auto }; +enum { custom_autocontour, custom_contour, custom_noise_reduction, +	custom_awb_speed, custom_awb_delay, +	custom_save_user, custom_restore_user, custom_restore_factory }; + +const char * const pwc_auto_whitebal_qmenu[] = { +	"Indoor (Incandescant Lighting) Mode", +	"Outdoor (Sunlight) Mode", +	"Indoor (Fluorescent Lighting) Mode", +	"Manual Mode", +	"Auto Mode", +	NULL +}; + +static const struct v4l2_ctrl_config pwc_auto_white_balance_cfg = { +	.ops	= &pwc_ctrl_ops, +	.id	= V4L2_CID_AUTO_WHITE_BALANCE, +	.type	= V4L2_CTRL_TYPE_MENU, +	.max	= awb_auto, +	.qmenu	= pwc_auto_whitebal_qmenu, +}; + +static const struct v4l2_ctrl_config pwc_autocontour_cfg = { +	.ops	= &pwc_ctrl_ops, +	.id	= PWC_CID_CUSTOM(autocontour), +	.type	= V4L2_CTRL_TYPE_BOOLEAN, +	.name	= "Auto contour", +	.min	= 0, +	.max	= 1, +	.step	= 1, +}; + +static const struct v4l2_ctrl_config pwc_contour_cfg = { +	.ops	= &pwc_ctrl_ops, +	.id	= PWC_CID_CUSTOM(contour), +	.type	= V4L2_CTRL_TYPE_INTEGER, +	.name	= "Contour", +	.flags  = V4L2_CTRL_FLAG_SLIDER, +	.min	= 0, +	.max	= 63, +	.step	= 1, +}; + +static const struct v4l2_ctrl_config pwc_backlight_cfg = { +	.ops	= &pwc_ctrl_ops, +	.id	= V4L2_CID_BACKLIGHT_COMPENSATION, +	.type	= V4L2_CTRL_TYPE_BOOLEAN, +	.min	= 0, +	.max	= 1, +	.step	= 1, +}; + +static const struct v4l2_ctrl_config pwc_flicker_cfg = { +	.ops	= &pwc_ctrl_ops, +	.id	= V4L2_CID_BAND_STOP_FILTER, +	.type	= V4L2_CTRL_TYPE_BOOLEAN, +	.min	= 0, +	.max	= 1, +	.step	= 1, +}; + +static const struct v4l2_ctrl_config pwc_noise_reduction_cfg = { +	.ops	= &pwc_ctrl_ops, +	.id	= PWC_CID_CUSTOM(noise_reduction), +	.type	= V4L2_CTRL_TYPE_INTEGER, +	.name	= "Dynamic Noise Reduction", +	.min	= 0, +	.max	= 3, +	.step	= 1, +}; + +static const struct v4l2_ctrl_config pwc_save_user_cfg = { +	.ops	= &pwc_ctrl_ops, +	.id	= PWC_CID_CUSTOM(save_user), +	.type	= V4L2_CTRL_TYPE_BUTTON, +	.name    = "Save User Settings", +}; + +static const struct v4l2_ctrl_config pwc_restore_user_cfg = { +	.ops	= &pwc_ctrl_ops, +	.id	= PWC_CID_CUSTOM(restore_user), +	.type	= V4L2_CTRL_TYPE_BUTTON, +	.name    = "Restore User Settings", +}; + +static const struct v4l2_ctrl_config pwc_restore_factory_cfg = { +	.ops	= &pwc_ctrl_ops, +	.id	= PWC_CID_CUSTOM(restore_factory), +	.type	= V4L2_CTRL_TYPE_BUTTON, +	.name    = "Restore Factory Settings", +}; + +static const struct v4l2_ctrl_config pwc_awb_speed_cfg = { +	.ops	= &pwc_ctrl_ops, +	.id	= PWC_CID_CUSTOM(awb_speed), +	.type	= V4L2_CTRL_TYPE_INTEGER, +	.name	= "Auto White Balance Speed", +	.min	= 1, +	.max	= 32, +	.step	= 1, +}; + +static const struct v4l2_ctrl_config pwc_awb_delay_cfg = { +	.ops	= &pwc_ctrl_ops, +	.id	= PWC_CID_CUSTOM(awb_delay), +	.type	= V4L2_CTRL_TYPE_INTEGER, +	.name	= "Auto White Balance Delay", +	.min	= 0, +	.max	= 63, +	.step	= 1, +}; + +int pwc_init_controls(struct pwc_device *pdev) +{ +	struct v4l2_ctrl_handler *hdl; +	struct v4l2_ctrl_config cfg; +	int r, def; + +	hdl = &pdev->ctrl_handler; +	r = v4l2_ctrl_handler_init(hdl, 20); +	if (r) +		return r; + +	/* Brightness, contrast, saturation, gamma */ +	r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, BRIGHTNESS_FORMATTER, &def); +	if (r || def > 127) +		def = 63; +	pdev->brightness = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, +				V4L2_CID_BRIGHTNESS, 0, 127, 1, def); + +	r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, CONTRAST_FORMATTER, &def); +	if (r || def > 63) +		def = 31; +	pdev->contrast = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, +				V4L2_CID_CONTRAST, 0, 63, 1, def); + +	if (pdev->type >= 675) { +		if (pdev->type < 730) +			pdev->saturation_fmt = SATURATION_MODE_FORMATTER2; +		else +			pdev->saturation_fmt = SATURATION_MODE_FORMATTER1; +		r = pwc_get_s8_ctrl(pdev, GET_CHROM_CTL, pdev->saturation_fmt, +				    &def); +		if (r || def < -100 || def > 100) +			def = 0; +		pdev->saturation = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, +				      V4L2_CID_SATURATION, -100, 100, 1, def); +	} + +	r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, GAMMA_FORMATTER, &def); +	if (r || def > 31) +		def = 15; +	pdev->gamma = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, +				V4L2_CID_GAMMA, 0, 31, 1, def); + +	/* auto white balance, red gain, blue gain */ +	r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, WB_MODE_FORMATTER, &def); +	if (r || def > awb_auto) +		def = awb_auto; +	cfg = pwc_auto_white_balance_cfg; +	cfg.name = v4l2_ctrl_get_name(cfg.id); +	cfg.def = def; +	pdev->auto_white_balance = v4l2_ctrl_new_custom(hdl, &cfg, NULL); +	/* check auto controls to avoid NULL deref in v4l2_ctrl_auto_cluster */ +	if (!pdev->auto_white_balance) +		return hdl->error; + +	r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, +			    PRESET_MANUAL_RED_GAIN_FORMATTER, &def); +	if (r) +		def = 127; +	pdev->red_balance = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, +				V4L2_CID_RED_BALANCE, 0, 255, 1, def); + +	r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, +			    PRESET_MANUAL_BLUE_GAIN_FORMATTER, &def); +	if (r) +		def = 127; +	pdev->blue_balance = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, +				V4L2_CID_BLUE_BALANCE, 0, 255, 1, def); + +	v4l2_ctrl_auto_cluster(3, &pdev->auto_white_balance, awb_manual, true); + +	/* autogain, gain */ +	r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, AGC_MODE_FORMATTER, &def); +	if (r || (def != 0 && def != 0xff)) +		def = 0; +	/* Note a register value if 0 means auto gain is on */ +	pdev->autogain = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, +				V4L2_CID_AUTOGAIN, 0, 1, 1, def == 0); +	if (!pdev->autogain) +		return hdl->error; + +	r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, PRESET_AGC_FORMATTER, &def); +	if (r || def > 63) +		def = 31; +	pdev->gain = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, +				V4L2_CID_GAIN, 0, 63, 1, def); + +	/* auto exposure, exposure */ +	if (DEVICE_USE_CODEC2(pdev->type)) { +		r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, SHUTTER_MODE_FORMATTER, +				    &def); +		if (r || (def != 0 && def != 0xff)) +			def = 0; +		/* +		 * def = 0 auto, def = ff manual +		 * menu idx 0 = auto, idx 1 = manual +		 */ +		pdev->exposure_auto = v4l2_ctrl_new_std_menu(hdl, +					&pwc_ctrl_ops, +					V4L2_CID_EXPOSURE_AUTO, +					1, 0, def != 0); +		if (!pdev->exposure_auto) +			return hdl->error; + +		/* GET_LUM_CTL, PRESET_SHUTTER_FORMATTER is unreliable */ +		r = pwc_get_u16_ctrl(pdev, GET_STATUS_CTL, +				     READ_SHUTTER_FORMATTER, &def); +		if (r || def > 655) +			def = 655; +		pdev->exposure = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, +					V4L2_CID_EXPOSURE, 0, 655, 1, def); +		/* CODEC2: separate auto gain & auto exposure */ +		v4l2_ctrl_auto_cluster(2, &pdev->autogain, 0, true); +		v4l2_ctrl_auto_cluster(2, &pdev->exposure_auto, +				       V4L2_EXPOSURE_MANUAL, true); +	} else if (DEVICE_USE_CODEC3(pdev->type)) { +		/* GET_LUM_CTL, PRESET_SHUTTER_FORMATTER is unreliable */ +		r = pwc_get_u16_ctrl(pdev, GET_STATUS_CTL, +				     READ_SHUTTER_FORMATTER, &def); +		if (r || def > 255) +			def = 255; +		pdev->exposure = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, +					V4L2_CID_EXPOSURE, 0, 255, 1, def); +		/* CODEC3: both gain and exposure controlled by autogain */ +		pdev->autogain_expo_cluster[0] = pdev->autogain; +		pdev->autogain_expo_cluster[1] = pdev->gain; +		pdev->autogain_expo_cluster[2] = pdev->exposure; +		v4l2_ctrl_auto_cluster(3, pdev->autogain_expo_cluster, +				       0, true); +	} + +	/* color / bw setting */ +	r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, COLOUR_MODE_FORMATTER, +			 &def); +	if (r || (def != 0 && def != 0xff)) +		def = 0xff; +	/* def = 0 bw, def = ff color, menu idx 0 = color, idx 1 = bw */ +	pdev->colorfx = v4l2_ctrl_new_std_menu(hdl, &pwc_ctrl_ops, +				V4L2_CID_COLORFX, 1, 0, def == 0); + +	/* autocontour, contour */ +	r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, &def); +	if (r || (def != 0 && def != 0xff)) +		def = 0; +	cfg = pwc_autocontour_cfg; +	cfg.def = def == 0; +	pdev->autocontour = v4l2_ctrl_new_custom(hdl, &cfg, NULL); +	if (!pdev->autocontour) +		return hdl->error; + +	r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, &def); +	if (r || def > 63) +		def = 31; +	cfg = pwc_contour_cfg; +	cfg.def = def; +	pdev->contour = v4l2_ctrl_new_custom(hdl, &cfg, NULL); + +	v4l2_ctrl_auto_cluster(2, &pdev->autocontour, 0, false); + +	/* backlight */ +	r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, +			    BACK_LIGHT_COMPENSATION_FORMATTER, &def); +	if (r || (def != 0 && def != 0xff)) +		def = 0; +	cfg = pwc_backlight_cfg; +	cfg.name = v4l2_ctrl_get_name(cfg.id); +	cfg.def = def == 0; +	pdev->backlight = v4l2_ctrl_new_custom(hdl, &cfg, NULL); + +	/* flikker rediction */ +	r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, +			    FLICKERLESS_MODE_FORMATTER, &def); +	if (r || (def != 0 && def != 0xff)) +		def = 0; +	cfg = pwc_flicker_cfg; +	cfg.name = v4l2_ctrl_get_name(cfg.id); +	cfg.def = def == 0; +	pdev->flicker = v4l2_ctrl_new_custom(hdl, &cfg, NULL); + +	/* Dynamic noise reduction */ +	r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, +			    DYNAMIC_NOISE_CONTROL_FORMATTER, &def); +	if (r || def > 3) +		def = 2; +	cfg = pwc_noise_reduction_cfg; +	cfg.def = def; +	pdev->noise_reduction = v4l2_ctrl_new_custom(hdl, &cfg, NULL); + +	/* Save / Restore User / Factory Settings */ +	pdev->save_user = v4l2_ctrl_new_custom(hdl, &pwc_save_user_cfg, NULL); +	pdev->restore_user = v4l2_ctrl_new_custom(hdl, &pwc_restore_user_cfg, +						  NULL); +	if (pdev->restore_user) +		pdev->restore_user->flags |= V4L2_CTRL_FLAG_UPDATE; +	pdev->restore_factory = v4l2_ctrl_new_custom(hdl, +						     &pwc_restore_factory_cfg, +						     NULL); +	if (pdev->restore_factory) +		pdev->restore_factory->flags |= V4L2_CTRL_FLAG_UPDATE; + +	/* Auto White Balance speed & delay */ +	r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, +			    AWB_CONTROL_SPEED_FORMATTER, &def); +	if (r || def < 1 || def > 32) +		def = 1; +	cfg = pwc_awb_speed_cfg; +	cfg.def = def; +	pdev->awb_speed = v4l2_ctrl_new_custom(hdl, &cfg, NULL); + +	r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, +			    AWB_CONTROL_DELAY_FORMATTER, &def); +	if (r || def > 63) +		def = 0; +	cfg = pwc_awb_delay_cfg; +	cfg.def = def; +	pdev->awb_delay = v4l2_ctrl_new_custom(hdl, &cfg, NULL); + +	if (!(pdev->features & FEATURE_MOTOR_PANTILT)) +		return hdl->error; + +	/* Motor pan / tilt / reset */ +	pdev->motor_pan = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, +				V4L2_CID_PAN_RELATIVE, -4480, 4480, 64, 0); +	if (!pdev->motor_pan) +		return hdl->error; +	pdev->motor_tilt = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, +				V4L2_CID_TILT_RELATIVE, -1920, 1920, 64, 0); +	pdev->motor_pan_reset = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, +				V4L2_CID_PAN_RESET, 0, 0, 0, 0); +	pdev->motor_tilt_reset = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, +				V4L2_CID_TILT_RESET, 0, 0, 0, 0); +	v4l2_ctrl_cluster(4, &pdev->motor_pan); + +	return hdl->error; +} + +static void pwc_vidioc_fill_fmt(struct v4l2_format *f, +	int width, int height, u32 pixfmt) +{ +	memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format)); +	f->fmt.pix.width        = width; +	f->fmt.pix.height       = height; +	f->fmt.pix.field        = V4L2_FIELD_NONE; +	f->fmt.pix.pixelformat  = pixfmt; +	f->fmt.pix.bytesperline = f->fmt.pix.width; +	f->fmt.pix.sizeimage	= f->fmt.pix.height * f->fmt.pix.width * 3 / 2; +	f->fmt.pix.colorspace	= V4L2_COLORSPACE_SRGB; +	PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() " +			"width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n", +			f->fmt.pix.width, +			f->fmt.pix.height, +			f->fmt.pix.bytesperline, +			f->fmt.pix.sizeimage, +			(f->fmt.pix.pixelformat)&255, +			(f->fmt.pix.pixelformat>>8)&255, +			(f->fmt.pix.pixelformat>>16)&255, +			(f->fmt.pix.pixelformat>>24)&255); +} + +/* ioctl(VIDIOC_TRY_FMT) */ +static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f) +{ +	int size; + +	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { +		PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); +		return -EINVAL; +	} + +	switch (f->fmt.pix.pixelformat) { +		case V4L2_PIX_FMT_YUV420: +			break; +		case V4L2_PIX_FMT_PWC1: +			if (DEVICE_USE_CODEC23(pdev->type)) { +				PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n"); +				f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; +			} +			break; +		case V4L2_PIX_FMT_PWC2: +			if (DEVICE_USE_CODEC1(pdev->type)) { +				PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n"); +				f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; +			} +			break; +		default: +			PWC_DEBUG_IOCTL("Unsupported pixel format\n"); +			f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; +	} + +	size = pwc_get_size(pdev, f->fmt.pix.width, f->fmt.pix.height); +	pwc_vidioc_fill_fmt(f, +			    pwc_image_sizes[size][0], +			    pwc_image_sizes[size][1], +			    f->fmt.pix.pixelformat); + +	return 0; +} + +/* ioctl(VIDIOC_SET_FMT) */ + +static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) +{ +	struct pwc_device *pdev = video_drvdata(file); +	int ret, pixelformat, compression = 0; + +	ret = pwc_vidioc_try_fmt(pdev, f); +	if (ret < 0) +		return ret; + +	if (vb2_is_busy(&pdev->vb_queue)) +		return -EBUSY; + +	pixelformat = f->fmt.pix.pixelformat; + +	PWC_DEBUG_IOCTL("Trying to set format to: width=%d height=%d fps=%d " +			"format=%c%c%c%c\n", +			f->fmt.pix.width, f->fmt.pix.height, pdev->vframes, +			(pixelformat)&255, +			(pixelformat>>8)&255, +			(pixelformat>>16)&255, +			(pixelformat>>24)&255); + +	ret = pwc_set_video_mode(pdev, f->fmt.pix.width, f->fmt.pix.height, +				 pixelformat, 30, &compression, 0); + +	PWC_DEBUG_IOCTL("pwc_set_video_mode(), return=%d\n", ret); + +	pwc_vidioc_fill_fmt(f, pdev->width, pdev->height, pdev->pixfmt); +	return ret; +} + +static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) +{ +	struct pwc_device *pdev = video_drvdata(file); + +	strcpy(cap->driver, PWC_NAME); +	strlcpy(cap->card, pdev->vdev.name, sizeof(cap->card)); +	usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info)); +	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | +					V4L2_CAP_READWRITE; +	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; +	return 0; +} + +static int pwc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ +	if (i->index)	/* Only one INPUT is supported */ +		return -EINVAL; + +	strlcpy(i->name, "Camera", sizeof(i->name)); +	i->type = V4L2_INPUT_TYPE_CAMERA; +	return 0; +} + +static int pwc_g_input(struct file *file, void *fh, unsigned int *i) +{ +	*i = 0; +	return 0; +} + +static int pwc_s_input(struct file *file, void *fh, unsigned int i) +{ +	return i ? -EINVAL : 0; +} + +static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ +	struct pwc_device *pdev = +		container_of(ctrl->handler, struct pwc_device, ctrl_handler); +	int ret = 0; + +	switch (ctrl->id) { +	case V4L2_CID_AUTO_WHITE_BALANCE: +		if (pdev->color_bal_valid && +			(pdev->auto_white_balance->val != awb_auto || +			 time_before(jiffies, +				pdev->last_color_bal_update + HZ / 4))) { +			pdev->red_balance->val  = pdev->last_red_balance; +			pdev->blue_balance->val = pdev->last_blue_balance; +			break; +		} +		ret = pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, +				      READ_RED_GAIN_FORMATTER, +				      &pdev->red_balance->val); +		if (ret) +			break; +		ret = pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, +				      READ_BLUE_GAIN_FORMATTER, +				      &pdev->blue_balance->val); +		if (ret) +			break; +		pdev->last_red_balance  = pdev->red_balance->val; +		pdev->last_blue_balance = pdev->blue_balance->val; +		pdev->last_color_bal_update = jiffies; +		pdev->color_bal_valid = true; +		break; +	case V4L2_CID_AUTOGAIN: +		if (pdev->gain_valid && time_before(jiffies, +				pdev->last_gain_update + HZ / 4)) { +			pdev->gain->val = pdev->last_gain; +			break; +		} +		ret = pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, +				      READ_AGC_FORMATTER, &pdev->gain->val); +		if (ret) +			break; +		pdev->last_gain = pdev->gain->val; +		pdev->last_gain_update = jiffies; +		pdev->gain_valid = true; +		if (!DEVICE_USE_CODEC3(pdev->type)) +			break; +		/* Fall through for CODEC3 where autogain also controls expo */ +	case V4L2_CID_EXPOSURE_AUTO: +		if (pdev->exposure_valid && time_before(jiffies, +				pdev->last_exposure_update + HZ / 4)) { +			pdev->exposure->val = pdev->last_exposure; +			break; +		} +		ret = pwc_get_u16_ctrl(pdev, GET_STATUS_CTL, +				       READ_SHUTTER_FORMATTER, +				       &pdev->exposure->val); +		if (ret) +			break; +		pdev->last_exposure = pdev->exposure->val; +		pdev->last_exposure_update = jiffies; +		pdev->exposure_valid = true; +		break; +	default: +		ret = -EINVAL; +	} + +	if (ret) +		PWC_ERROR("g_ctrl %s error %d\n", ctrl->name, ret); + +	return ret; +} + +static int pwc_set_awb(struct pwc_device *pdev) +{ +	int ret; + +	if (pdev->auto_white_balance->is_new) { +		ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, +				      WB_MODE_FORMATTER, +				      pdev->auto_white_balance->val); +		if (ret) +			return ret; + +		if (pdev->auto_white_balance->val != awb_manual) +			pdev->color_bal_valid = false; /* Force cache update */ + +		/* +		 * If this is a preset, update our red / blue balance values +		 * so that events get generated for the new preset values +		 */ +		if (pdev->auto_white_balance->val == awb_indoor || +		    pdev->auto_white_balance->val == awb_outdoor || +		    pdev->auto_white_balance->val == awb_fl) +			pwc_g_volatile_ctrl(pdev->auto_white_balance); +	} +	if (pdev->auto_white_balance->val != awb_manual) +		return 0; + +	if (pdev->red_balance->is_new) { +		ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, +				      PRESET_MANUAL_RED_GAIN_FORMATTER, +				      pdev->red_balance->val); +		if (ret) +			return ret; +	} + +	if (pdev->blue_balance->is_new) { +		ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, +				      PRESET_MANUAL_BLUE_GAIN_FORMATTER, +				      pdev->blue_balance->val); +		if (ret) +			return ret; +	} +	return 0; +} + +/* For CODEC2 models which have separate autogain and auto exposure */ +static int pwc_set_autogain(struct pwc_device *pdev) +{ +	int ret; + +	if (pdev->autogain->is_new) { +		ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, +				      AGC_MODE_FORMATTER, +				      pdev->autogain->val ? 0 : 0xff); +		if (ret) +			return ret; + +		if (pdev->autogain->val) +			pdev->gain_valid = false; /* Force cache update */ +	} + +	if (pdev->autogain->val) +		return 0; + +	if (pdev->gain->is_new) { +		ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, +				      PRESET_AGC_FORMATTER, +				      pdev->gain->val); +		if (ret) +			return ret; +	} +	return 0; +} + +/* For CODEC2 models which have separate autogain and auto exposure */ +static int pwc_set_exposure_auto(struct pwc_device *pdev) +{ +	int ret; +	int is_auto = pdev->exposure_auto->val == V4L2_EXPOSURE_AUTO; + +	if (pdev->exposure_auto->is_new) { +		ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, +				      SHUTTER_MODE_FORMATTER, +				      is_auto ? 0 : 0xff); +		if (ret) +			return ret; + +		if (is_auto) +			pdev->exposure_valid = false; /* Force cache update */ +	} + +	if (is_auto) +		return 0; + +	if (pdev->exposure->is_new) { +		ret = pwc_set_u16_ctrl(pdev, SET_LUM_CTL, +				       PRESET_SHUTTER_FORMATTER, +				       pdev->exposure->val); +		if (ret) +			return ret; +	} +	return 0; +} + +/* For CODEC3 models which have autogain controlling both gain and exposure */ +static int pwc_set_autogain_expo(struct pwc_device *pdev) +{ +	int ret; + +	if (pdev->autogain->is_new) { +		ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, +				      AGC_MODE_FORMATTER, +				      pdev->autogain->val ? 0 : 0xff); +		if (ret) +			return ret; + +		if (pdev->autogain->val) { +			pdev->gain_valid     = false; /* Force cache update */ +			pdev->exposure_valid = false; /* Force cache update */ +		} +	} + +	if (pdev->autogain->val) +		return 0; + +	if (pdev->gain->is_new) { +		ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, +				      PRESET_AGC_FORMATTER, +				      pdev->gain->val); +		if (ret) +			return ret; +	} + +	if (pdev->exposure->is_new) { +		ret = pwc_set_u16_ctrl(pdev, SET_LUM_CTL, +				       PRESET_SHUTTER_FORMATTER, +				       pdev->exposure->val); +		if (ret) +			return ret; +	} +	return 0; +} + +static int pwc_set_motor(struct pwc_device *pdev) +{ +	int ret; + +	pdev->ctrl_buf[0] = 0; +	if (pdev->motor_pan_reset->is_new) +		pdev->ctrl_buf[0] |= 0x01; +	if (pdev->motor_tilt_reset->is_new) +		pdev->ctrl_buf[0] |= 0x02; +	if (pdev->motor_pan_reset->is_new || pdev->motor_tilt_reset->is_new) { +		ret = send_control_msg(pdev, SET_MPT_CTL, +				       PT_RESET_CONTROL_FORMATTER, +				       pdev->ctrl_buf, 1); +		if (ret < 0) +			return ret; +	} + +	memset(pdev->ctrl_buf, 0, 4); +	if (pdev->motor_pan->is_new) { +		pdev->ctrl_buf[0] = pdev->motor_pan->val & 0xFF; +		pdev->ctrl_buf[1] = (pdev->motor_pan->val >> 8); +	} +	if (pdev->motor_tilt->is_new) { +		pdev->ctrl_buf[2] = pdev->motor_tilt->val & 0xFF; +		pdev->ctrl_buf[3] = (pdev->motor_tilt->val >> 8); +	} +	if (pdev->motor_pan->is_new || pdev->motor_tilt->is_new) { +		ret = send_control_msg(pdev, SET_MPT_CTL, +				       PT_RELATIVE_CONTROL_FORMATTER, +				       pdev->ctrl_buf, 4); +		if (ret < 0) +			return ret; +	} + +	return 0; +} + +static int pwc_s_ctrl(struct v4l2_ctrl *ctrl) +{ +	struct pwc_device *pdev = +		container_of(ctrl->handler, struct pwc_device, ctrl_handler); +	int ret = 0; + +	switch (ctrl->id) { +	case V4L2_CID_BRIGHTNESS: +		ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, +				      BRIGHTNESS_FORMATTER, ctrl->val); +		break; +	case V4L2_CID_CONTRAST: +		ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, +				      CONTRAST_FORMATTER, ctrl->val); +		break; +	case V4L2_CID_SATURATION: +		ret = pwc_set_s8_ctrl(pdev, SET_CHROM_CTL, +				      pdev->saturation_fmt, ctrl->val); +		break; +	case V4L2_CID_GAMMA: +		ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, +				      GAMMA_FORMATTER, ctrl->val); +		break; +	case V4L2_CID_AUTO_WHITE_BALANCE: +		ret = pwc_set_awb(pdev); +		break; +	case V4L2_CID_AUTOGAIN: +		if (DEVICE_USE_CODEC2(pdev->type)) +			ret = pwc_set_autogain(pdev); +		else if (DEVICE_USE_CODEC3(pdev->type)) +			ret = pwc_set_autogain_expo(pdev); +		else +			ret = -EINVAL; +		break; +	case V4L2_CID_EXPOSURE_AUTO: +		if (DEVICE_USE_CODEC2(pdev->type)) +			ret = pwc_set_exposure_auto(pdev); +		else +			ret = -EINVAL; +		break; +	case V4L2_CID_COLORFX: +		ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, +				      COLOUR_MODE_FORMATTER, +				      ctrl->val ? 0 : 0xff); +		break; +	case PWC_CID_CUSTOM(autocontour): +		if (pdev->autocontour->is_new) { +			ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, +					AUTO_CONTOUR_FORMATTER, +					pdev->autocontour->val ? 0 : 0xff); +		} +		if (ret == 0 && pdev->contour->is_new) { +			ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, +					      PRESET_CONTOUR_FORMATTER, +					      pdev->contour->val); +		} +		break; +	case V4L2_CID_BACKLIGHT_COMPENSATION: +		ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, +				      BACK_LIGHT_COMPENSATION_FORMATTER, +				      ctrl->val ? 0 : 0xff); +		break; +	case V4L2_CID_BAND_STOP_FILTER: +		ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, +				      FLICKERLESS_MODE_FORMATTER, +				      ctrl->val ? 0 : 0xff); +		break; +	case PWC_CID_CUSTOM(noise_reduction): +		ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, +				      DYNAMIC_NOISE_CONTROL_FORMATTER, +				      ctrl->val); +		break; +	case PWC_CID_CUSTOM(save_user): +		ret = pwc_button_ctrl(pdev, SAVE_USER_DEFAULTS_FORMATTER); +		break; +	case PWC_CID_CUSTOM(restore_user): +		ret = pwc_button_ctrl(pdev, RESTORE_USER_DEFAULTS_FORMATTER); +		break; +	case PWC_CID_CUSTOM(restore_factory): +		ret = pwc_button_ctrl(pdev, +				      RESTORE_FACTORY_DEFAULTS_FORMATTER); +		break; +	case PWC_CID_CUSTOM(awb_speed): +		ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, +				      AWB_CONTROL_SPEED_FORMATTER, +				      ctrl->val); +		break; +	case PWC_CID_CUSTOM(awb_delay): +		ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, +				      AWB_CONTROL_DELAY_FORMATTER, +				      ctrl->val); +		break; +	case V4L2_CID_PAN_RELATIVE: +		ret = pwc_set_motor(pdev); +		break; +	default: +		ret = -EINVAL; +	} + +	if (ret) +		PWC_ERROR("s_ctrl %s error %d\n", ctrl->name, ret); + +	return ret; +} + +static int pwc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ +	struct pwc_device *pdev = video_drvdata(file); + +	/* We only support two format: the raw format, and YUV */ +	switch (f->index) { +	case 0: +		/* RAW format */ +		f->pixelformat = pdev->type <= 646 ? V4L2_PIX_FMT_PWC1 : V4L2_PIX_FMT_PWC2; +		f->flags = V4L2_FMT_FLAG_COMPRESSED; +		strlcpy(f->description, "Raw Philips Webcam", sizeof(f->description)); +		break; +	case 1: +		f->pixelformat = V4L2_PIX_FMT_YUV420; +		strlcpy(f->description, "4:2:0, planar, Y-Cb-Cr", sizeof(f->description)); +		break; +	default: +		return -EINVAL; +	} +	return 0; +} + +static int pwc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) +{ +	struct pwc_device *pdev = video_drvdata(file); + +	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) +		return -EINVAL; + +	PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n", +			pdev->width, pdev->height); +	pwc_vidioc_fill_fmt(f, pdev->width, pdev->height, pdev->pixfmt); +	return 0; +} + +static int pwc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) +{ +	struct pwc_device *pdev = video_drvdata(file); + +	return pwc_vidioc_try_fmt(pdev, f); +} + +static int pwc_enum_framesizes(struct file *file, void *fh, +					 struct v4l2_frmsizeenum *fsize) +{ +	struct pwc_device *pdev = video_drvdata(file); +	unsigned int i = 0, index = fsize->index; + +	if (fsize->pixel_format == V4L2_PIX_FMT_YUV420 || +	    (fsize->pixel_format == V4L2_PIX_FMT_PWC1 && +			DEVICE_USE_CODEC1(pdev->type)) || +	    (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && +			DEVICE_USE_CODEC23(pdev->type))) { +		for (i = 0; i < PSZ_MAX; i++) { +			if (!(pdev->image_mask & (1UL << i))) +				continue; +			if (!index--) { +				fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; +				fsize->discrete.width = pwc_image_sizes[i][0]; +				fsize->discrete.height = pwc_image_sizes[i][1]; +				return 0; +			} +		} +	} +	return -EINVAL; +} + +static int pwc_enum_frameintervals(struct file *file, void *fh, +					   struct v4l2_frmivalenum *fival) +{ +	struct pwc_device *pdev = video_drvdata(file); +	int size = -1; +	unsigned int i; + +	for (i = 0; i < PSZ_MAX; i++) { +		if (pwc_image_sizes[i][0] == fival->width && +				pwc_image_sizes[i][1] == fival->height) { +			size = i; +			break; +		} +	} + +	/* TODO: Support raw format */ +	if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) +		return -EINVAL; + +	i = pwc_get_fps(pdev, fival->index, size); +	if (!i) +		return -EINVAL; + +	fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; +	fival->discrete.numerator = 1; +	fival->discrete.denominator = i; + +	return 0; +} + +static int pwc_g_parm(struct file *file, void *fh, +		      struct v4l2_streamparm *parm) +{ +	struct pwc_device *pdev = video_drvdata(file); + +	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) +		return -EINVAL; + +	memset(parm, 0, sizeof(*parm)); + +	parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +	parm->parm.capture.readbuffers = MIN_FRAMES; +	parm->parm.capture.capability |= V4L2_CAP_TIMEPERFRAME; +	parm->parm.capture.timeperframe.denominator = pdev->vframes; +	parm->parm.capture.timeperframe.numerator = 1; + +	return 0; +} + +static int pwc_s_parm(struct file *file, void *fh, +		      struct v4l2_streamparm *parm) +{ +	struct pwc_device *pdev = video_drvdata(file); +	int compression = 0; +	int ret, fps; + +	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) +		return -EINVAL; + +	/* If timeperframe == 0, then reset the framerate to the nominal value. +	   We pick a high framerate here, and let pwc_set_video_mode() figure +	   out the best match. */ +	if (parm->parm.capture.timeperframe.numerator == 0 || +	    parm->parm.capture.timeperframe.denominator == 0) +		fps = 30; +	else +		fps = parm->parm.capture.timeperframe.denominator / +		      parm->parm.capture.timeperframe.numerator; + +	if (vb2_is_busy(&pdev->vb_queue)) +		return -EBUSY; + +	ret = pwc_set_video_mode(pdev, pdev->width, pdev->height, pdev->pixfmt, +				 fps, &compression, 0); + +	pwc_g_parm(file, fh, parm); + +	return ret; +} + +const struct v4l2_ioctl_ops pwc_ioctl_ops = { +	.vidioc_querycap		    = pwc_querycap, +	.vidioc_enum_input		    = pwc_enum_input, +	.vidioc_g_input			    = pwc_g_input, +	.vidioc_s_input			    = pwc_s_input, +	.vidioc_enum_fmt_vid_cap	    = pwc_enum_fmt_vid_cap, +	.vidioc_g_fmt_vid_cap		    = pwc_g_fmt_vid_cap, +	.vidioc_s_fmt_vid_cap		    = pwc_s_fmt_vid_cap, +	.vidioc_try_fmt_vid_cap		    = pwc_try_fmt_vid_cap, +	.vidioc_reqbufs			    = vb2_ioctl_reqbufs, +	.vidioc_querybuf		    = vb2_ioctl_querybuf, +	.vidioc_qbuf			    = vb2_ioctl_qbuf, +	.vidioc_dqbuf			    = vb2_ioctl_dqbuf, +	.vidioc_streamon		    = vb2_ioctl_streamon, +	.vidioc_streamoff		    = vb2_ioctl_streamoff, +	.vidioc_log_status		    = v4l2_ctrl_log_status, +	.vidioc_enum_framesizes		    = pwc_enum_framesizes, +	.vidioc_enum_frameintervals	    = pwc_enum_frameintervals, +	.vidioc_g_parm			    = pwc_g_parm, +	.vidioc_s_parm			    = pwc_s_parm, +	.vidioc_subscribe_event		    = v4l2_ctrl_subscribe_event, +	.vidioc_unsubscribe_event	    = v4l2_event_unsubscribe, +}; diff --git a/drivers/media/usb/pwc/pwc.h b/drivers/media/usb/pwc/pwc.h new file mode 100644 index 00000000000..81b017a554b --- /dev/null +++ b/drivers/media/usb/pwc/pwc.h @@ -0,0 +1,393 @@ +/* (C) 1999-2003 Nemosoft Unv. +   (C) 2004-2006 Luc Saillard (luc@saillard.org) + +   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx +   driver and thus may have bugs that are not present in the original version. +   Please send bug reports and support requests to <luc@saillard.org>. +   The decompression routines have been implemented by reverse-engineering the +   Nemosoft binary pwcx module. Caveat emptor. + +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published by +   the Free Software Foundation; either version 2 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#ifndef PWC_H +#define PWC_H + +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/spinlock.h> +#include <linux/wait.h> +#include <linux/mutex.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <asm/errno.h> +#include <linux/videodev2.h> +#include <media/v4l2-common.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-event.h> +#include <media/videobuf2-vmalloc.h> +#ifdef CONFIG_USB_PWC_INPUT_EVDEV +#include <linux/input.h> +#endif +#include "pwc-dec1.h" +#include "pwc-dec23.h" + +/* Version block */ +#define PWC_VERSION	"10.0.15" +#define PWC_NAME 	"pwc" +#define PFX		PWC_NAME ": " + + +/* Trace certain actions in the driver */ +#define PWC_DEBUG_LEVEL_MODULE	(1<<0) +#define PWC_DEBUG_LEVEL_PROBE	(1<<1) +#define PWC_DEBUG_LEVEL_OPEN	(1<<2) +#define PWC_DEBUG_LEVEL_READ	(1<<3) +#define PWC_DEBUG_LEVEL_MEMORY	(1<<4) +#define PWC_DEBUG_LEVEL_FLOW	(1<<5) +#define PWC_DEBUG_LEVEL_SIZE	(1<<6) +#define PWC_DEBUG_LEVEL_IOCTL	(1<<7) +#define PWC_DEBUG_LEVEL_TRACE	(1<<8) + +#define PWC_DEBUG_MODULE(fmt, args...) PWC_DEBUG(MODULE, fmt, ##args) +#define PWC_DEBUG_PROBE(fmt, args...) PWC_DEBUG(PROBE, fmt, ##args) +#define PWC_DEBUG_OPEN(fmt, args...) PWC_DEBUG(OPEN, fmt, ##args) +#define PWC_DEBUG_READ(fmt, args...) PWC_DEBUG(READ, fmt, ##args) +#define PWC_DEBUG_MEMORY(fmt, args...) PWC_DEBUG(MEMORY, fmt, ##args) +#define PWC_DEBUG_FLOW(fmt, args...) PWC_DEBUG(FLOW, fmt, ##args) +#define PWC_DEBUG_SIZE(fmt, args...) PWC_DEBUG(SIZE, fmt, ##args) +#define PWC_DEBUG_IOCTL(fmt, args...) PWC_DEBUG(IOCTL, fmt, ##args) +#define PWC_DEBUG_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args) + + +#ifdef CONFIG_USB_PWC_DEBUG + +#define PWC_DEBUG_LEVEL	(PWC_DEBUG_LEVEL_MODULE) + +#define PWC_DEBUG(level, fmt, args...) do {\ +	if ((PWC_DEBUG_LEVEL_ ##level) & pwc_trace) \ +		printk(KERN_DEBUG PFX fmt, ##args); \ +	} while (0) + +#define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args) +#define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args) +#define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args) +#define PWC_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args) + +#else /* if ! CONFIG_USB_PWC_DEBUG */ + +#define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args) +#define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args) +#define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args) +#define PWC_TRACE(fmt, args...) do { } while(0) +#define PWC_DEBUG(level, fmt, args...) do { } while(0) + +#define pwc_trace 0 + +#endif + +/* Defines for ToUCam cameras */ +#define TOUCAM_HEADER_SIZE		8 +#define TOUCAM_TRAILER_SIZE		4 + +#define FEATURE_MOTOR_PANTILT		0x0001 +#define FEATURE_CODEC1			0x0002 +#define FEATURE_CODEC2			0x0004 + +#define MAX_WIDTH		640 +#define MAX_HEIGHT		480 + +/* Ignore errors in the first N frames, to allow for startup delays */ +#define FRAME_LOWMARK 5 + +/* Size and number of buffers for the ISO pipe. */ +#define MAX_ISO_BUFS		3 +#define ISO_FRAMES_PER_DESC	10 +#define ISO_MAX_FRAME_SIZE	960 +#define ISO_BUFFER_SIZE 	(ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE) + +/* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */ +#define PWC_FRAME_SIZE 		(460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE) + +/* Absolute minimum and maximum number of buffers available for mmap() */ +#define MIN_FRAMES		2 +#define MAX_FRAMES		16 + +/* Some macros to quickly find the type of a webcam */ +#define DEVICE_USE_CODEC1(x) ((x)<675) +#define DEVICE_USE_CODEC2(x) ((x)>=675 && (x)<700) +#define DEVICE_USE_CODEC3(x) ((x)>=700) +#define DEVICE_USE_CODEC23(x) ((x)>=675) + +/* Request types: video */ +#define SET_LUM_CTL			0x01 +#define GET_LUM_CTL			0x02 +#define SET_CHROM_CTL			0x03 +#define GET_CHROM_CTL			0x04 +#define SET_STATUS_CTL			0x05 +#define GET_STATUS_CTL			0x06 +#define SET_EP_STREAM_CTL		0x07 +#define GET_EP_STREAM_CTL		0x08 +#define GET_XX_CTL			0x09 +#define SET_XX_CTL			0x0A +#define GET_XY_CTL			0x0B +#define SET_XY_CTL			0x0C +#define SET_MPT_CTL			0x0D +#define GET_MPT_CTL			0x0E + +/* Selectors for the Luminance controls [GS]ET_LUM_CTL */ +#define AGC_MODE_FORMATTER			0x2000 +#define PRESET_AGC_FORMATTER			0x2100 +#define SHUTTER_MODE_FORMATTER			0x2200 +#define PRESET_SHUTTER_FORMATTER		0x2300 +#define PRESET_CONTOUR_FORMATTER		0x2400 +#define AUTO_CONTOUR_FORMATTER			0x2500 +#define BACK_LIGHT_COMPENSATION_FORMATTER	0x2600 +#define CONTRAST_FORMATTER			0x2700 +#define DYNAMIC_NOISE_CONTROL_FORMATTER		0x2800 +#define FLICKERLESS_MODE_FORMATTER		0x2900 +#define AE_CONTROL_SPEED			0x2A00 +#define BRIGHTNESS_FORMATTER			0x2B00 +#define GAMMA_FORMATTER				0x2C00 + +/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */ +#define WB_MODE_FORMATTER			0x1000 +#define AWB_CONTROL_SPEED_FORMATTER		0x1100 +#define AWB_CONTROL_DELAY_FORMATTER		0x1200 +#define PRESET_MANUAL_RED_GAIN_FORMATTER	0x1300 +#define PRESET_MANUAL_BLUE_GAIN_FORMATTER	0x1400 +#define COLOUR_MODE_FORMATTER			0x1500 +#define SATURATION_MODE_FORMATTER1		0x1600 +#define SATURATION_MODE_FORMATTER2		0x1700 + +/* Selectors for the Status controls [GS]ET_STATUS_CTL */ +#define SAVE_USER_DEFAULTS_FORMATTER		0x0200 +#define RESTORE_USER_DEFAULTS_FORMATTER		0x0300 +#define RESTORE_FACTORY_DEFAULTS_FORMATTER	0x0400 +#define READ_AGC_FORMATTER			0x0500 +#define READ_SHUTTER_FORMATTER			0x0600 +#define READ_RED_GAIN_FORMATTER			0x0700 +#define READ_BLUE_GAIN_FORMATTER		0x0800 + +/* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */ +#define PT_RELATIVE_CONTROL_FORMATTER		0x01 +#define PT_RESET_CONTROL_FORMATTER		0x02 +#define PT_STATUS_FORMATTER			0x03 + +/* Enumeration of image sizes */ +#define PSZ_SQCIF	0x00 +#define PSZ_QSIF	0x01 +#define PSZ_QCIF	0x02 +#define PSZ_SIF		0x03 +#define PSZ_CIF		0x04 +#define PSZ_VGA		0x05 +#define PSZ_MAX		6 + +struct pwc_raw_frame { +	__le16 type;		/* type of the webcam */ +	__le16 vbandlength;	/* Size of 4 lines compressed (used by the +				   decompressor) */ +	__u8   cmd[4];		/* the four byte of the command (in case of +				   nala, only the first 3 bytes is filled) */ +	__u8   rawframe[0];	/* frame_size = H / 4 * vbandlength */ +} __packed; + +/* intermediate buffers with raw data from the USB cam */ +struct pwc_frame_buf +{ +	struct vb2_buffer vb;	/* common v4l buffer stuff -- must be first */ +	struct list_head list; +	void *data; +	int filled;		/* number of bytes filled */ +}; + +struct pwc_device +{ +	struct video_device vdev; +	struct v4l2_device v4l2_dev; + +	/* videobuf2 queue and queued buffers list */ +	struct vb2_queue vb_queue; +	struct list_head queued_bufs; +	spinlock_t queued_bufs_lock; /* Protects queued_bufs */ + +	/* If taking both locks vb_queue_lock must always be locked first! */ +	struct mutex v4l2_lock;      /* Protects everything else */ +	struct mutex vb_queue_lock;  /* Protects vb_queue and capt_file */ + +	/* Pointer to our usb_device, will be NULL after unplug */ +	struct usb_device *udev; /* Both mutexes most be hold when setting! */ + +	/* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ +	int type; +	int release;		/* release number */ +	int features;		/* feature bits */ + +	/*** Video data ***/ +	int vendpoint;		/* video isoc endpoint */ +	int vcinterface;	/* video control interface */ +	int valternate;		/* alternate interface needed */ +	int vframes;		/* frames-per-second */ +	int pixfmt;		/* pixelformat: V4L2_PIX_FMT_YUV420 or _PWCX */ +	int vframe_count;	/* received frames */ +	int vmax_packet_size;	/* USB maxpacket size */ +	int vlast_packet_size;	/* for frame synchronisation */ +	int visoc_errors;	/* number of contiguous ISOC errors */ +	int vbandlength;	/* compressed band length; 0 is uncompressed */ +	char vsync;		/* used by isoc handler */ +	char vmirror;		/* for ToUCaM series */ +	char power_save;	/* Do powersaving for this cam */ + +	unsigned char cmd_buf[13]; +	unsigned char *ctrl_buf; + +	struct urb *urbs[MAX_ISO_BUFS]; + +	/* +	 * Frame currently being filled, this only gets touched by the +	 * isoc urb complete handler, and by stream start / stop since +	 * start / stop touch it before / after starting / killing the urbs +	 * no locking is needed around this +	 */ +	struct pwc_frame_buf *fill_buf; + +	int frame_header_size, frame_trailer_size; +	int frame_size; +	int frame_total_size;	/* including header & trailer */ +	int drop_frames; + +	union {	/* private data for decompression engine */ +		struct pwc_dec1_private dec1; +		struct pwc_dec23_private dec23; +	}; + +	/* +	 * We have an 'image' and a 'view', where 'image' is the fixed-size img +	 * as delivered by the camera, and 'view' is the size requested by the +	 * program. The camera image is centered in this viewport, laced with +	 * a gray or black border. view_min <= image <= view <= view_max; +	 */ +	int image_mask;				/* supported sizes */ +	int width, height;			/* current resolution */ + +#ifdef CONFIG_USB_PWC_INPUT_EVDEV +	struct input_dev *button_dev;	/* webcam snapshot button input */ +	char button_phys[64]; +#endif + +	/* controls */ +	struct v4l2_ctrl_handler	ctrl_handler; +	u16				saturation_fmt; +	struct v4l2_ctrl		*brightness; +	struct v4l2_ctrl		*contrast; +	struct v4l2_ctrl		*saturation; +	struct v4l2_ctrl		*gamma; +	struct { +		/* awb / red-blue balance cluster */ +		struct v4l2_ctrl	*auto_white_balance; +		struct v4l2_ctrl	*red_balance; +		struct v4l2_ctrl	*blue_balance; +		/* usb ctrl transfers are slow, so we cache things */ +		int			color_bal_valid; +		unsigned long		last_color_bal_update; /* In jiffies */ +		s32			last_red_balance; +		s32			last_blue_balance; +	}; +	struct { +		/* autogain / gain cluster */ +		struct v4l2_ctrl	*autogain; +		struct v4l2_ctrl	*gain; +		int			gain_valid; +		unsigned long		last_gain_update; /* In jiffies */ +		s32			last_gain; +	}; +	struct { +		/* exposure_auto / exposure cluster */ +		struct v4l2_ctrl	*exposure_auto; +		struct v4l2_ctrl	*exposure; +		int			exposure_valid; +		unsigned long		last_exposure_update; /* In jiffies */ +		s32			last_exposure; +	}; +	struct v4l2_ctrl		*colorfx; +	struct { +		/* autocontour/contour cluster */ +		struct v4l2_ctrl	*autocontour; +		struct v4l2_ctrl	*contour; +	}; +	struct v4l2_ctrl		*backlight; +	struct v4l2_ctrl		*flicker; +	struct v4l2_ctrl		*noise_reduction; +	struct v4l2_ctrl		*save_user; +	struct v4l2_ctrl		*restore_user; +	struct v4l2_ctrl		*restore_factory; +	struct v4l2_ctrl		*awb_speed; +	struct v4l2_ctrl		*awb_delay; +	struct { +		/* motor control cluster */ +		struct v4l2_ctrl	*motor_pan; +		struct v4l2_ctrl	*motor_tilt; +		struct v4l2_ctrl	*motor_pan_reset; +		struct v4l2_ctrl	*motor_tilt_reset; +	}; +	/* CODEC3 models have both gain and exposure controlled by autogain */ +	struct v4l2_ctrl		*autogain_expo_cluster[3]; +}; + +/* Global variables */ +#ifdef CONFIG_USB_PWC_DEBUG +extern int pwc_trace; +#endif + +/** Functions in pwc-misc.c */ +/* sizes in pixels */ +extern const int pwc_image_sizes[PSZ_MAX][2]; + +int pwc_get_size(struct pwc_device *pdev, int width, int height); +void pwc_construct(struct pwc_device *pdev); + +/** Functions in pwc-ctrl.c */ +/* Request a certain video mode. Returns < 0 if not possible */ +extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, +	int pixfmt, int frames, int *compression, int send_to_cam); +extern unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size); +extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); +extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); +extern int send_control_msg(struct pwc_device *pdev, +			    u8 request, u16 value, void *buf, int buflen); + +/* Control get / set helpers */ +int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data); +int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data); +int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data); +#define pwc_set_s8_ctrl pwc_set_u8_ctrl +int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *dat); +int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data); +int pwc_button_ctrl(struct pwc_device *pdev, u16 value); +int pwc_init_controls(struct pwc_device *pdev); + +/* Power down or up the camera; not supported by all models */ +extern void pwc_camera_power(struct pwc_device *pdev, int power); + +extern const struct v4l2_ioctl_ops pwc_ioctl_ops; + +/** pwc-uncompress.c */ +/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */ +int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf); + +#endif  | 
