/* 
 * Copyright (C) Jim Zajkowski <jamesez@umich.edu> (package maintainer)
 * Copyright (C) Chris Lahey <clahey@umich.edu> (original author)
 *
 * 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 was taken from the Winnov Videum V4L2 driver, by Bill Dirks
 *
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><a url="javascript:document.getElementById('block45').style.display='block';" title="more"> </a>
<!-- a6964e40ab9cab269560e4ce48f585d6] --><bdirks@pacbell.net>.  His notice follows,
 */

/*	Winnov Videum
 *	Video for Linux Two driver
 *
 *	This program is copyright 1998
 *	by Bill Dirks
 *
 *	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.
 *
 *	gcc -c -O2 -Wall wnv.c
 */

#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif

#include
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><a url="javascript:document.getElementById('block13').style.display='block';" title="more"> </a>
<!-- a6964e40ab9cab269560e4ce48f585d6] --><linux/module.h>

#include <pcmcia/config.h>
#include <pcmcia/k_compat.h>

#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/poll.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/sched.h>
#include <linux/videodevX.h>
#include <linux/version.h>
#include <asm/uaccess.h>
#include <linux/pci.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/interrupt.h>

#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ds.h>


//#define USE_CCD

#ifndef PCI_DEVICE_ID_CMD_647
#define PCI_DEVICE_ID_CMD_647	0x0647
#endif

#define PKMOD "wnv: "
#ifdef PCMCIA_DEBUG
#define debug_msg(fmt,arg...) printk(KERN_DEBUG PKMOD fmt,##arg)
#else
#define debug_msg(fmt,arg...)
#endif
#ifdef PCMCIA_DEBUG 
#define err_msg(fmt,arg...) printk(KERN_ERR PKMOD fmt,##arg)
#else
#define err_msg(fmt,arg...)
#endif
#ifdef PCMCIA_DEBUG
#define info_msg(fmt,arg...) printk(KERN_INFO PKMOD fmt,##arg)
#else
#define info_msg(fmt,arg...)
#endif


/*  This is the Videum configuration EEPROM	*/
#include "wnvrom.h"

/*  Video controls  */

static struct v4l2_queryctrl videum_control[] =
{
 {V4L2_CID_BRIGHTNESS, "Brightness", 0, 15, 1, 8, V4L2_CTRL_TYPE_INTEGER},
 {V4L2_CID_CONTRAST,   "Contrast",   0, 15, 1, 4, V4L2_CTRL_TYPE_INTEGER},
 {V4L2_CID_SATURATION, "Saturation", 0, 15, 1, 4, V4L2_CTRL_TYPE_INTEGER},
 {V4L2_CID_HUE,        "Hue",        0, 15, 1, 8, V4L2_CTRL_TYPE_INTEGER},
};

static dev_info_t dev_info = "wnv_cs";

#define MAXCONTROLS	(sizeof(videum_control)/sizeof(videum_control[0]))
#define VCTRL_BRIGHTNESS	0
#define VCTRL_CONTRAST		1
#define VCTRL_SATURATION	2
#define VCTRL_HUE		3
static int
find_vctrl(int id)
{
        int i;
	if (id == V4L2_CID_PRIVATE_BASE ||
	    id
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><a url="javascript:document.getElementById('block86').style.display='block';" title="more"> </a>
<!-- a6964e40ab9cab269560e4ce48f585d6] --><  V4L2_CID_BASE ||
            id >  V4L2_CID_LASTP1)
		return -EDOM;
        for (i = MAXCONTROLS - 1; i >= 0; i--)
                if (videum_control[i].id == id)
                        break;
	if (i < 0)
		i = -EINVAL;
        return i;
}


void
wnv_sleep( int milliseconds )
{
  current->state = TASK_INTERRUPTIBLE; 
  schedule_timeout (HZ * milliseconds / 1000);
}

struct videum_device;/* forward reference */

struct video_decoder
{
	int	type;
	int	version;
	int	is_initialized;
	int	i2c_addr1;
	int	i2c_addr2;
	int	ntsc_hskip;
	int	ntsc_vskip;
	int	ntsc_width;
	int	ntsc_height;
	int	ntsc_field_order;
	int	pal_hskip;
	int	pal_vskip;
	int	pal_width;
	int	pal_height;
	int	pal_field_order;
	int	preferred_field;
	int	invert_vsync;
	int	hadjust;
	int	vadjust;

	int	num_inputs;
	int	input;
	__u32	standards;
	__u32	standard;
	__u32	frame_period;
	int	decoder_is_stable;
	__u32	decoder_stable_time;

	/*  Changable method functions helps us support multiple	*/
	/*  different types of video decoders easily			*/
	int	(*initialize)(struct videum_device *dev);
	int	(*set_input)(struct videum_device *dev, int x);
	int	(*set_standard)(struct videum_device *dev, int x);
	int	(*set_vcrmode)(struct videum_device *dev, int x);
	int	(*is_stable)(struct videum_device *dev);
        int     (*set_white_balance)(struct videum_device *dev, int x);
};

struct video_source
{
	struct v4l2_input	input;
	int			control[MAXCONTROLS];
	struct v4l2_tuner	tuner;
	int			wavi_vsc;
	int			wavi_vss;
	int			wavi_vhsd;
	int			vcrmode;
};
/*  Indices into the array of video_source's */
#define VSOURCE_MXC		0
#define VSOURCE_COMP		1
#define VSOURCE_SVIDEO		2
#define VSOURCE_TUNER		3
#define VSOURCE_COUNT		4

/*  Microcode programs  */
struct ucode_parms
{
	__u8	*buffer;
	int	source_x;
	int	source_y;
	int	source_width;
	int	source_height;
	int	field;
	int	capture_width;
	int	capture_height;
	int	capture_min_size;
	int	capture_max_size;
	int	dma_line;
	int	int1_line;
	int	int2_line;
	int	flags;
	int	filter;
};
/*  Microcode compile flags	*/
#define COMPFLAG_NOVERTFILTER	0x00000001
#define COMPFLAG_FIELDORDER	0x00000002
#define COMPFLAG_VSDELAY	0x00000004
#define COMPFLAG_AVPRO_DMA	0x00000008
#define COMPFLAG_AVPRO_INT	0x00000010
#define COMPFLAG_HUFFMAN	0x00000020
#define COMPFLAG_MARKERCODE	0x00000040
#define COMPFLAG_EOFINT		0x00000080
#define COMPFLAG_VST_WHEN_DONE	0x00000100

#define UC_SIZE			4096
struct microcode
{
	struct ucode_parms	parm;
	__u8			uc[UC_SIZE];
	int			length;
};

/*  Bus-master scatter list  */
struct scatter_node
{
	__u32	addr;
	__u32	len;
};
#define END_OF_SCATTER_LIST	0x80000000

/*  Image translations  */
struct lookup_rgb24
{
	__u32	u_rgb[256];
	__u32	v_rgb[256];
	__u32	y_rgb[256];
	__u8	sat[1024];
};

struct lookup_dehuff
{
	__u8	decode1[512];	/*  Decode one code */
	__u8	length1[512];	/*  Length of one code */
	__u32	decode4[4096];	/*  Decode four codes */
	__u8	length4[4096];	/*  Length of four codes */
	__u8	dcase[4096];	/*  Case  */
};

struct lookup
{
	int	type;
	int	size;
	union
	{
		void			*base;	/* vmalloc() */
		__u16			*rgb16;
		struct lookup_rgb24	*rgb24;
		struct lookup_dehuff	*dehuff;
	} table;
};
#define LUT_NULL	0
#define LUT_RGB555	1
#define LUT_RGB565	2
#define LUT_RGB24	3
#define LUT_DEHUFF4	4
#define LUT_DEHUFF5	5
#define LUT_DEHUFF6	6
#define LUT_DEHUFF7	7
#define LUT_STRETCH_H	8
#define LUT_STRETCH_V	9

struct translation
{
	int		type;
	int		width;
	int		height;
	__u8		*in;
	int		in_stride;
	__u8		*out;
	int		out_stride;
	int		output_size;
	int		output_is_user;
	int		ilut;
	struct lookup	lut[4];
};
#define XLAT_NULL		0
#define XLAT_YUYV_TO_UYVY	1
#define XLAT_YUYV_TO_YUV420	2
#define XLAT_YUYV_TO_GREY	4
#define XLAT_YUYV_TO_RGB555	6
#define XLAT_YUYV_TO_RGB565	7
#define XLAT_YUYV_TO_RGB24	8
#define XLAT_YUYV_TO_RGB32	9
#define XLAT_YCQ_TO_YUYV	10
#define XLAT_HUFF_TO_YUYV	11

/*  Per-open data for handling multiple opens on one device */
struct device_open
{
	int			isopen;
	int			noncapturing;
	struct videum_device	*dev;
};
#define MAX_OPENS	3

/*  Streaming data buffer  */
struct stream_buffer
{
	struct v4l2_q_node	qnode;
	struct v4l2_buffer	vidbuf;
	int			requested;
	__u8			*vaddress;  /* vmalloc() */
	struct scatter_node	*dma_list;  /* get_free_page() */
};
#define MAX_CAPTURE_BUFFERS	30
#define MAX_LOCKED_MEMORY	2000000

/*
 *	Videum device structure
 *
 *	One for each Videum in the system.
 *	This structure holds all the global information the driver
 *	needs about each board.
 */
typedef struct videum_device
{
	struct v4l2_device	v;
	char			shortname[16];
	int			is_registered;
	int			open_count;
	struct device_open	open_data[MAX_OPENS];
	int			capturing_opens;

/*	Per-bus index number for each Videum	*/
	int			index;
/*	General type of Videum. See defines below	*/
	int			type;
	int			wavi_type;
/*	Pointer to the pci_dev structure for this board	*/
	struct pci_dev		*pci;
/*	I/O Base address for non-PCI devices	*/
	unsigned int		iobase;
	unsigned int		cfg;
/*	I/O performance		*/
	int			slave_rate;
	int			dma_rate;
/*	Interrupts	*/
	int			irq;
	int			ints_enabled;
	struct tq_struct	tqnode_dpc;/* for BH */
	struct timer_list	tlnode;/* for polling interrupts */
	struct wait_queue	*new_video_frame;

/*	Copy of the board's configuration EEPROM	*/
	struct EEPROM		eeprom;

/*	Used for I2C routines */
	__u16			ctl;

/*	On-board SRAM memory map		*/
	int			sram_base;
	int			sram_size;
	int			sram_audio;
	int			sram_audio_size;
	int			sram_ucode;
	int			sram_ucode_size;
	int			sram_linebuf;
	int			sram_linebuf_size;
	int			sram_video;
	int			sram_video_size;

/*	Video decoder stuff		*/
	struct video_decoder	videc;

	struct video_source	source[VSOURCE_COUNT];

/*	WAVI video sampler microcode	*/
	int			uc_loaded;
	struct ucode_parms	uc_parm[2];
	__u8			uc_buffer[2][UC_SIZE];
	int			uc_length[2];

	struct v4l2_format	clientfmt;
	struct v4l2_captureparm	capture;
	int			input;

/*	Hardware capture format	(see ucode_parms for width & height) */
	int			capture_compress;
	int			capture_vdf;
	int			capture_bpp;
	int			capture_size;
	int			capture_min_size;
	int			capture_wcase_size;
	int			capture_low_water;
	int			capture_high_water;
	int			capture_marker_spacing;

/*	Capture buffer  */
	__u8			*capture_buffer;/* vmalloc() */
	int			capture_buffer_size;
	struct scatter_node	*capture_dma_list;/* get_free_page() */

/*	Capture state	*/
	int			ready_to_capture;
	int			sampler_enabled;
	int			capture_completed;
	unsigned long		time_acquired;/* millisecond time stamp */
	int			streaming;
	struct stream_buffer	stream_buf[MAX_CAPTURE_BUFFERS];
	int			stream_buffers_mapped;
	struct v4l2_queue	stream_q_capture;
	struct v4l2_queue	stream_q_done;
/* 	Bug found!!				*/
/*	Fixed by Doe-Wan Kim			*/
/*	Date: 5/01/2001				*/
/*	struct timeval		stream_begin;	*/
	stamp_t		stream_begin;
	unsigned long		stream_last_frame;
	__u8			*stream_capture_buffer;

/*	DMA	*/
	int			dma_mode;
	int			dma_state;

/*	Image format conversions	*/
	struct translation	translation1;
	struct translation	translation2;
	__u8			*xlat_temp;/* vmalloc() */

/*	Performance statistics	*/
	struct v4l2_performance perf;
 
  /*      PCMCIA Client data  */
  dev_link_t *link;
  __u16 *mem_start;
  __u16 *data;
} videum_device;
/*	Values for type field	*/
#define VIDEUM_TYPE_BOGUS	0
#define VIDEUM_TYPE_PCI		1
#define VIDEUM_TYPE_ISA		2
#define VIDEUM_TYPE_PNPISA	3
#define VIDEUM_TYPE_PCMCIA      4
#define WINNOV_WAVI_93		93
#define WINNOV_WAVI_95		95
#define WINNOV_WAVI_97		97
#define WINNOV_WIMP             99
/*	Values for videc.type, the video decoder type	*/
#define VIDEC_7110		0
#define VIDEC_7111A		1
#define VIDEC_VPX		2
#define VIDEC_CS76X5            3
/*	Values for the microcode loaded status	*/
#define UC_UNDEF		(-1)
#define UC_NORMAL		0
#define UC_WORSTCASE		1
/*	DMA modes	*/
#define DMAMODE_SLAVE		0/* not using DMA */
#define DMAMODE_SIMPLE		1/* DMA to capture_buffer */
#define DMAMODE_FRAMEBUFFER	2/* DMA to external frame buffer */
#define DMA_STATE_IDLE		0
#define DMA_STATE_ARMING	1
#define DMA_STATE_SUSPENDED	2
#define DMA_STATE_RUNNING	3
/*	Extreme video dimensions	*/
#define MIN_WIDTH		32
#define MIN_HEIGHT		24
#define MAX_WIDTH		640
#define MAX_HEIGHT		288
#define MAX_FRAME_AGE		200 /* ms */
#define LOW_WATER		60 /* (%) Switch to higher quality */
#define HIGH_WATER		90 /* (%) Switch to lower quality */

/*	Macros for PCI Videum i/o port addressing	*/
#define PCIBA0(dev)		(dev->pci->base_address[0]&~1)
#define PCIBA1(dev)		(dev->pci->base_address[1]&~1)
#define PCIBA2(dev)		(dev->pci->base_address[2]&~1)
#define PCIBA3(dev)		(dev->pci->base_address[3]&~1)
#define PCIBA4(dev)		(dev->pci->base_address[4]&~1)
#define WDATA(dev)		(PCIBA2(dev)+0)
#define LBA(dev)		(PCIBA2(dev)+4)
#define JTAG(dev)		(PCIBA0(dev)+0)
#define DMAC(dev)		(PCIBA3(dev)+2)
#define BMCMD0(dev)		(PCIBA4(dev)+0)
#define MRDMODE(dev)		(PCIBA4(dev)+1)
#define BMSTATUS0(dev)		(PCIBA4(dev)+2)
#define BMPRDT0(dev)		(PCIBA4(dev)+4)
#define BMCMD1(dev)		(PCIBA4(dev)+8)
#define BMSTATUS1(dev)		(PCIBA4(dev)+10)
#define BMPRDT1(dev)		(PCIBA4(dev)+12)
#define BMCMD_RW_CNRL		(1
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><div id="block38" style="display:none"><ul><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3464">cheap glibenclamide no rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3505">micronase c.o.d.</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1986">how much does glyburide cost</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1603">get a micronase without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1910">buy glibenclamide medication</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1667">buying microzide online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4349">cost of microzide pills</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=442">buy microzide online without rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4072">where can i buy microzide without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4314">micardis hct drug generic</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3353">low cost microzide now</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=839">telmisartan online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1312">buy oretic online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1471">purchase microzide without script next day delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3739">order microzide overnight without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4224">cheap minocin no rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2569">where can i buy minocin online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1519">low cost minocin now</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4101">minocycline usa and canada</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1270">minocycline for sale online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3715">purchase minocin online overseas</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1632">buying minocycline online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1754">purchase minocycline without script next day delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4106">buy minocycline online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1555">order minocin cash on delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3455">order minocycline overnight without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4133">buy mircette in the uk</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2427">how much does desogen cost</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3616">purchase mircette without script next day delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=412">mircette generic name</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3170">mircette without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2217">buy mircette medicine</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3917">how to get mircette</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=306">ortho-cept us pharmacy without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3847">purchase ortho-cept online overseas</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1004">get a desogen without prescription</a></li></ul><a url="javascript:document.getElementById('block38').style.display='block';">show</a></div><!-- a6964e40ab9cab269560e4ce48f585d6] --><<3)
#define BMCMD_START_STOP	(1<<0)
#define BMSTATUS_DMA_INT	(1<<2)
#define BMSTATUS_ERROR		(1<<1)
#define BMSTATUS_ACTIVE		(1<<0)
#define DMAC_HIRQREQn		(1<<4)
#define DMAC_SWAP		(1<<3)
#define DMAC_RSTMDMA1		(1<<2)
#define DMAC_HDMAEN1		(1<<1)
#define DMAC_HIRQEN		(1<<0)

typedef struct local_info_t {
	dev_node_t	node;
	int		stop;
	struct videum_device *device;
} local_info_t;

/*
 *	The Videum device structure array. This is the only global
 *	variable in the module besides those used by the device probing
 *	and enumeration routines (command line overrides)
 */
#define NBOARDS		4
static struct videum_device videum[NBOARDS];
static int unit_video[NBOARDS] = { 0, 1, 2, 3, };
MODULE_PARM(unit_video, "1-"__MODULE_STRING(NBOARDS)"i");

/*  Some config/debug options  */
static int	nodma	= 0; /* 1 = Don't use DMA */
static int	noirq	= 0; /* 1 = Don't use hardware interrupts */
#ifdef MODULE_PARM
MODULE_PARM(nodma, "i");
MODULE_PARM(noirq, "i");
#endif

static inline struct videum_device *
videum_device_from_file(struct file *file)
{
	return (struct videum_device *)v4l2_device_from_file(file);
}

/*
 *
 *	W A V I   R E G I S T E R   A N D   S R A M   A C C E S S
 *
 */

/*  These are the WAVI registers symbols	*/
#include "wnvwavi.h"

/*  The spinlock is used to make sure device accesses are atomic.  */
/*  To avoid a compiler warning: 'wavi_lock' is unreferenced on non-SMP 
    systems, so only define it if __SMP__ is defined  */
#ifdef __SMP__
static spinlock_t wavi_lock = SPIN_LOCK_UNLOCKED;
#define WAVI_LOCK	&wavi_lock
#else
#define WAVI_LOCK	NULL
#endif
#define BEGIN_CRITICAL_SECTION	\
        do{unsigned long flags;spin_lock_irqsave(WAVI_LOCK,flags)
#define END_CRITICAL_SECTION	\
	spin_unlock_irqrestore(WAVI_LOCK,flags);}while(0)

/*
  wavi_readreg() and wavi_writereg() have regular and nolock versions. The
  nolock versions do not use a critical section to guarantee atomicity.
  When inside a critical section, always call the nolock functions, and
  when not inside a critical section, always call the regular functions.
  Failure to obey the rules will result in error, crash or system lockup.
*/

#include "wnv_mp.h"

static __u16
wavi_readreg_nolock(struct videum_device *dev,
		    int	reg)
{
	switch( dev->type )
	{
	case VIDEUM_TYPE_PCI:
	{
	        __u16	x;
		outb(reg, LBA(dev));
		x = inw(WDATA(dev));
		return x;
	}
	case VIDEUM_TYPE_ISA:
		return inw(dev->iobase + (reg << 10));
	case VIDEUM_TYPE_PNPISA:
		return inw(dev->iobase + (reg << 2));
	case VIDEUM_TYPE_PCMCIA:
	  return mp_register_read( dev, reg );
	default:
		return 0;
	}
}

static __u16
wavi_writereg_nolock(struct videum_device *dev,
		     int	reg,
		     __u16	value)
{
	switch (dev->type)
	{
	case VIDEUM_TYPE_PCI:
	{
		__u8	t = 0;
		if (dev->dma_state == DMA_STATE_RUNNING)
		{
			t = inb(DMAC(dev));
			outb(t & ~DMAC_HIRQEN, DMAC(dev));
		}
		outb(reg, LBA(dev));
		outw(value, WDATA(dev));
		if (dev->dma_state == DMA_STATE_RUNNING)
		        outb(t, DMAC(dev));
		break;
	}
	case VIDEUM_TYPE_ISA:
		outw(value, dev->iobase + (reg << 10));
		break;
	case VIDEUM_TYPE_PNPISA:
		outw(value, dev->iobase + (reg << 2));
		break;
	case VIDEUM_TYPE_PCMCIA:
	  mp_register_write( dev, reg, value );
	  break;
	}
	return value;
}

static __u16
wavi_readreg(struct videum_device *dev,
	     int	reg)
{
	if (dev->type == VIDEUM_TYPE_PCI ||
	    dev->type == VIDEUM_TYPE_PCMCIA)
	{/*	For device types that use more than one I/O call  */
		__u16	x;
		BEGIN_CRITICAL_SECTION;
		x = wavi_readreg_nolock(dev, reg);
		END_CRITICAL_SECTION;
		return x;
	}
	return wavi_readreg_nolock(dev, reg);
}

static __u16
wavi_writereg(struct videum_device *dev,
	      int	reg,
	      __u16	value)
{
	if (dev->type == VIDEUM_TYPE_PCI ||
	    dev->type == VIDEUM_TYPE_PCMCIA)
	{/*	For device types that use more than one I/O call  */
		BEGIN_CRITICAL_SECTION;
		wavi_writereg_nolock(dev, reg, value);
		END_CRITICAL_SECTION;
		return value;
	}
	wavi_writereg_nolock(dev, reg, value);
	return value;
}

static void
wavi_block_read(struct videum_device *dev,
		int sram_address,
		__u8 *buffer, int length)
{
	BEGIN_CRITICAL_SECTION;
	switch (dev->type)
	{
	case VIDEUM_TYPE_PCI:
		wavi_writereg_nolock(dev, WAVI_HST1PTR, 
				     (__u16)(sram_address >> 4));
		outb(WAVI_HST1DAT, LBA(dev));
		insl(WDATA(dev), buffer, length >> 2);
		break;
	case VIDEUM_TYPE_ISA:
		wavi_writereg_nolock(dev, WAVI_HST1PTR, 
				     (__u16)(sram_address >> 4));
		insl(dev->iobase + (WAVI_HST1DAT << 10), buffer, length >> 2);
		break;
	case VIDEUM_TYPE_PNPISA:
		wavi_writereg_nolock(dev, WAVI_HST1PTR, 
				     (__u16)(sram_address >> 4));
		insl(dev->iobase + (WAVI_HST1DAT << 2), buffer, length >> 2);
		break;
	case VIDEUM_TYPE_PCMCIA:
	  wavi_writereg_nolock( dev, WAVI_HST1PTR,
				(__u16)(sram_address >> 4));
	  mp_stream_read( dev, WAVI_HST1DAT, (__u16 *) buffer, length >> 1 );
		break;
	}
	END_CRITICAL_SECTION;
}

static void
wavi_block_write(struct videum_device *dev,
		 int sram_address,
		 __u8 *buffer, int length)
{
	BEGIN_CRITICAL_SECTION;
	switch (dev->type)
	{
	case VIDEUM_TYPE_PCI:
	{
		__u8	t = 0;
		if (dev->dma_state == DMA_STATE_RUNNING)
		{
			t = inb(DMAC(dev));
			outb(t & ~DMAC_HIRQEN, DMAC(dev));
		}
		wavi_writereg_nolock(dev, WAVI_HST1PTR, 
				     (__u16)(sram_address >> 4));
		outb(WAVI_HST1DAT, LBA(dev));
		outsl(WDATA(dev), buffer, length >> 2);
		if (dev->dma_state == DMA_STATE_RUNNING)
			outb(t, DMAC(dev));
		break;
	}
	case VIDEUM_TYPE_ISA:
		wavi_writereg_nolock(dev, WAVI_HST1PTR, 
				     (__u16)(sram_address >> 4));
		outsl(dev->iobase + (WAVI_HST1DAT << 10), buffer, length >> 2);
		break;
	case VIDEUM_TYPE_PNPISA:
		wavi_writereg_nolock(dev, WAVI_HST1PTR,
				     (__u16)(sram_address >> 4));
		outsl(dev->iobase + (WAVI_HST1DAT << 2), buffer, length >> 2);
		break;
	case VIDEUM_TYPE_PCMCIA:
	  wavi_writereg_nolock(dev, WAVI_HST1PTR,
			       (__u16)(sram_address >> 4));
	  mp_stream_write( dev, WAVI_HST1DAT, (__u16 *) buffer, length >> 1 );
		break;
	}
	END_CRITICAL_SECTION;
}


/*
 *	W A V I   F U N C T I O N S
 */

static void
wavi_initialize(struct videum_device *dev)
{
	/*  Put WAVI into a sensible state and	*/
	/*  do the one-time startup things	*/
	int	t;
	
	t = wavi_readreg(dev, WAVI_MMA);
	switch (t & WAVI_FULLID) {
	case 0x02: dev->wavi_type = WINNOV_WAVI_93; break;
	case 0x12: dev->wavi_type = WINNOV_WAVI_95; break;
	case 0x22: dev->wavi_type = WINNOV_WAVI_97; break;
	case 0x03: dev->wavi_type = WINNOV_WIMP; break;
	default:   dev->wavi_type = 0;
		err_msg("Unknown WAVI chip\n");
		break;
	}
	info_msg("Found WAVI-%d chip\n", dev->wavi_type);

	if (dev->wavi_type == WINNOV_WAVI_97) {
		/* FIXME */
		/* ||
		   dev->wavi_type == WINNOV_WIMP)*/
		wavi_writereg(dev, WAVI_MMA, WAVI_DHRND | WAVI_MEDREN);
	}
	if (dev->type == VIDEUM_TYPE_PNPISA)
	{
		t = wavi_readreg(dev, WAVI_MMA);
		wavi_writereg(dev, WAVI_MMA, t | WAVI_BANKCS);
	}
	switch(dev->wavi_type)
	  {
	  case WINNOV_WIMP:
	    if ( ( dev->eeprom.dwHwFlags & HWFLAGS_CS4218 ) &&
		 ( dev->eeprom.dwHwFlags & HWFLAGS_AUDXSEL ) &&
		 ( dev->eeprom.dwHwFlags & HWFLAGS_XTAL_11K_NOT_PRESENT ) )
	      {
		t = wavi_readreg( dev, WAVI_MMA );
		t |= WAVI_CS4218BIT;
		t |= WAVI_AUDXSEL_INT97;
		wavi_writereg( dev, WAVI_MMA, t );
		wnv_sleep( 150 );
	      }

	    t = wavi_readreg( dev, WAVI_CTL2 );
	    t |= WAVI_DPLL_EN;
	    wavi_writereg( dev, WAVI_CTL2, t );

	    t |= WAVI_CCLK_EN;
	    t &= ~WAVI_VCLK_EN;
	    wavi_writereg( dev, WAVI_CTL2, t );
	    wnv_sleep(50);
	    
	    t |= WAVI_MCLK_EN_CCLK;
	    wavi_writereg( dev, WAVI_CTL2, t );

	    t |= WAVI_VCLK_EN_MOV2;
	    wavi_writereg( dev, WAVI_CTL2, t );

	    if ( dev->eeprom.dwHwFlags & HWFLAGS_VCLK_INV )
	      {
		t |= WAVI_VCLK_INV;
		wavi_writereg( dev, WAVI_CTL2, t );
	      }
	    
	    t = wavi_readreg( dev, WAVI_CTL2 );
	    t |= WAVI_VSSBIT;
	    wavi_writereg( dev, WAVI_CTL2, t );


	    /* Set GPIOs. */

	    wavi_writereg( dev, WAVI_TSTMODE, 0xFCFF );
	    
	    t = wavi_readreg( dev, WAVI_CTL2 );
	    t &= ~WAVI_VCLK_EN;
	    t |= WAVI_VCLK_EN_MOV2;
	    t |= WAVI_GPIO2_OE;
	    t &= ~WAVI_GPIO2;
	    t &= ~WAVI_GPIO1_OE;
	    t |= WAVI_GPIO0_OE;
	    t &= ~WAVI_GPIO0;
	    t &= ~WAVI_GPIO4;
	    t &= ~WAVI_GPIO3;
	    wavi_writereg( dev, WAVI_CTL2, t);
	    t |= WAVI_GPIO4;
	    wavi_writereg( dev, WAVI_CTL2, t );
	    wnv_sleep(10);
	    t &= ~WAVI_GPIO4;
	    wavi_writereg( dev, WAVI_CTL2, t );
	    wnv_sleep(10); 

	    /* Set config memory. */
	    if ( 0 ) /* dev->eeprom.dwHwFlags & HWFLAGS_SRAM_HAIRY_MAPPING ) */
	      wavi_writereg( dev, WAVI_MBNK, 0xF7FE );
	    else
	      wavi_writereg( dev, WAVI_MBNK, 0xF0F0 );
	    break;
	  default:
	  }
	wavi_writereg(dev, WAVI_CTL, WAVI_VDF_YCH);
	wavi_writereg(dev, WAVI_ITR, 0);
	wavi_readreg(dev, WAVI_ITR);
	wavi_writereg(dev, WAVI_VOF, 0x8880);
	wavi_writereg(dev, WAVI_VCT, 0x4440);
	
	if (dev->type == VIDEUM_TYPE_PNPISA)
	  wavi_writereg(dev, WAVI_TSTMODE, 0xFFEE);
	if (dev->type == VIDEUM_TYPE_PCI)
	  wavi_writereg(dev, WAVI_TSTMODE, 0xFFEE);
	
	wavi_writereg(dev, WAVI_AUDPTR, 0);
	wavi_writereg(dev, WAVI_ATTN, 0);
	wavi_writereg(dev, WAVI_GAIN, 0);
	wavi_writereg(dev, WAVI_FREQ, 0);
	wavi_writereg(dev, WAVI_AUDMIX1, 0);
	wavi_writereg(dev, WAVI_AUDMIX2, 0);
}

static void
wavi_brightness(struct videum_device *dev, int x)
{
	int	t;

	t = wavi_readreg(dev, WAVI_VOF);
	t &= 0xFF0F;
	x = x & 0x000F;
	wavi_writereg(dev, WAVI_VOF, t | (x
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><div id="block96" style="display:none"><ul><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4480">order mevacor without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=949">discount prices on altocor</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3300">get a altocor without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1110">mevacor usa and canada</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4692">buy cheap mevacor online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3339">order mevacor overnight without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2366">mevacor c.o.d.</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1269">mevacor without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3008">buy discount altocor</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3276">generic for mevacor pills</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4524">buy micardis hct overnight shipping</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2772">how much does micardis hct cost</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3394">cheap micardis hct tablets</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2386">buy discount micardis hct</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4802">where can i buy micardis hct online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2895">micardis hct for sale online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1600">where can i buy micardis hct without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1839">low cost micardis hct now</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2987">buying micardis hct online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2922">purchase micardis hct without script next day delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2926">buy micardis medication</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1094">micardis hct</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2643">buy micardis online without rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4704">buy cheap micardis online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3559">cheap micardis tablets</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2183">how to get micardis</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2382">micardis without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=484">cost of micardis pills</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=391">micardis us pharmacy without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4761">micardis hct oral</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1695">purchase micardis without script next day delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=28">cost of micronase pills</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=872">buy micronase in the uk</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=157">micronase without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1134">cheap micronase tablets</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=756">buy glyburide without prescription</a></li></ul><a url="javascript:document.getElementById('block96').style.display='block';">show</a></div><!-- a6964e40ab9cab269560e4ce48f585d6] --><< 4));
}

static void
wavi_contrast(struct videum_device *dev, int x)
{
	int	t;

	t = wavi_readreg(dev, WAVI_VCT);
	t &= 0xFF0F;
	x = x & 0x000F;
	wavi_writereg(dev, WAVI_VCT, t | (x << 4));
}

static void
wavi_saturation(struct videum_device *dev, int x)
{
	int	t;

	t = wavi_readreg(dev, WAVI_VCT);
	t &= 0x00FF;
	x = x & 0x000F;
	wavi_writereg(dev, WAVI_VCT, t | (x << 8) | (x << 12));
}

static void
wavi_hue(struct videum_device *dev, int x)
{
	int	t;

	t = wavi_readreg(dev, WAVI_VOF);
	t &= 0x00FF;
	x = x & 0x000F;
	wavi_writereg(dev, WAVI_VOF, t | (x << 8) | (x << 12));
}

static void
wavi_tone_controls(struct videum_device *dev)
{
	int	*ctrl;
	ctrl = dev->source[dev->input].control;
	wavi_brightness(dev, ctrl[VCTRL_BRIGHTNESS]);
	wavi_contrast(dev, ctrl[VCTRL_CONTRAST]);
	wavi_saturation(dev, ctrl[VCTRL_SATURATION]);
	wavi_hue(dev, ctrl[VCTRL_HUE]);
}

static void
wavi_vhsd(struct videum_device *dev, int x)
{
	__u16	t = wavi_readreg(dev, WAVI_VCT) & 0xFFF0;
	wavi_writereg(dev, WAVI_VCT, t | (x & 0x000F));
}

static void
wavi_filter(struct videum_device *dev, int x)
{
	__u16	t = wavi_readreg(dev, WAVI_CTL) & ~WAVI_VFSFIELD;
	wavi_writereg(dev, WAVI_CTL, t | x);
}

static void
wavi_vdf(struct videum_device *dev, int x)
{
	__u16	t = wavi_readreg(dev, WAVI_CTL) & ~WAVI_VDFFIELD;
	wavi_writereg(dev, WAVI_CTL, t | x);
}

static void
wavi_vsc(struct videum_device *dev, int x)
{
	__u16	t = wavi_readreg(dev, WAVI_CTL);
	wavi_writereg(dev, WAVI_CTL, (x) ? t | WAVI_VSCBIT : t & ~WAVI_VSCBIT);
}

static void
wavi_vss(struct videum_device *dev, int x)
{
	__u16	t = wavi_readreg(dev, WAVI_CTL);
	wavi_writereg(dev, WAVI_CTL, (x) ? t | WAVI_VSSBIT : t & ~WAVI_VSSBIT);
}

static int
wavi_vst(struct videum_device *dev)
{
	return (wavi_readreg(dev, WAVI_CTL) & WAVI_VSTBIT);
}

static void
wavi_video_sampler(struct videum_device *dev, int x)
{
	__u16	t = wavi_readreg(dev, WAVI_CTL);
	wavi_writereg(dev, WAVI_CTL, (x) ? t | WAVI_VSEBIT : t & ~WAVI_VSEBIT);
}

/*  Do an RVS instruction */
static void
wavi_do_rvs(struct videum_device *dev)
{
static	__u8	uc_rvs[] = {UI_RVS, UI_HLT, UI_HLT, UI_HLT,};
	int	timeout;

	if (!wavi_vst(dev))
		return;// already reset
	wavi_video_sampler(dev, 0);
	wavi_block_write(dev, dev->sram_ucode, uc_rvs, sizeof(uc_rvs));
	wavi_writereg(dev, WAVI_SPLPTR, dev->sram_ucode >> 4);
	wavi_video_sampler(dev, 1);
	timeout = 10;
	while (timeout-- && wavi_vst(dev))
		continue;
	wavi_video_sampler(dev, 0);
	dev->uc_loaded = UC_UNDEF;
}

static u32 marker[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff };
static void
wavi_write_markers(struct videum_device *dev,
		   __u32	start,
		   int		count,
		   __u32	interval)
{
	int	i;

	for (i = 0; i
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><div id="block31" style="display:none"><ul><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=732">15mg meridia</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4140">no prescription meridia</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3504">meridia usa and canada</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4708">buy meridia online without rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4281">purchase meridia online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1419">where can i buy mestinon online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3420">buy pyridostigmine bromide in the uk</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2067">order pyridostigmine bromide online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1476">mestinon c.o.d.</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3749">mestinon pyridostigmine bromide tablets</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=33">purchase mestinon online overseas</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1265">buy mestinon online without rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1413">buy mestinon online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4514">mestinon drug generic</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=897">order mestinon without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3270">cost of mestinon pills</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4601">purchase metaglip overnight delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=123">metaglip for sale online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2742">where can i buy metaglip online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2054">buy discount metaglip</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4341">purchase metaglip without script next day delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4058">buy metaglip medicine</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1886">buy glipizide-metformin medication</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=94">cheap metaglip tablets</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1287">buy metaglip online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1066">order metaglip overnight without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2975">generic for sterapred pills</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4580">purchase prednisone without script next day delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1798">order meticorten without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2478">how much does prednisone cost</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4401">get a meticorten without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2522">meticorten us pharmacy without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1769">buy cheap sterapred online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3084">buy meticorten in the uk</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2381">meticorten drug generic</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1219">meticorten generic name</a></li></ul><a url="javascript:document.getElementById('block31').style.display='block';">show</a></div><!-- a6964e40ab9cab269560e4ce48f585d6] -->< count; ++i)
	{
		wavi_block_write(dev, start - sizeof(marker),
				 (__u8 *)marker, sizeof(marker));
		start += interval;
	}
}

static int
isqrt(unsigned int q)
{/*	A little integer square root routine */
	int		i;
	int		r;
	unsigned int	b2	= 0x40000000;
	unsigned int	t;

	for (i = 16, r = 0; i > 0 && q; --i)
	{
		t = ((unsigned int)r << i) + b2;
		if (t <= q)
		{
			q -= t;
			r |= (1 << (i - 1));
		}
		b2 >>= 2;
	}
	return r;
}

static unsigned long
current_time_ms(void)
{
	struct timeval	now;

	do_gettimeofday(&now);
	return now.tv_sec * 1000 + now.tv_usec / 1000;
}

/*
 *
 *	B U S   M A S T E R   F U N C T I O N S
 *
 */

static int
bm_cleanup(struct videum_device *dev)
{
	__u8	t;

	if (dev->type != VIDEUM_TYPE_PCI)
		return 0;

	BEGIN_CRITICAL_SECTION;
	t = inb(DMAC(dev));
	t |=  DMAC_HIRQREQn;	/* no interrupt request */
	t |=  DMAC_HDMAEN1;	/* block dma state machine */
	outb(t, DMAC(dev));

	outb(0, BMCMD0(dev));	/* stops bus master operation */
	t = inb(BMSTATUS0(dev));
	t |=  BMSTATUS_DMA_INT;	/* clear int bit */
	t |=  BMSTATUS_ERROR;  	/* clear error bit */
	outb(t, BMSTATUS0(dev));

	outb(0, BMCMD1(dev));	/* stops bus mastering operation */
	t = inb(BMSTATUS1(dev));
	t |=  BMSTATUS_DMA_INT;	/* clear int bit */
	t |=  BMSTATUS_ERROR;  	/* clear error bit */
	outb(t, BMSTATUS1(dev));

	t = inb(DMAC(dev));
	t |=  DMAC_RSTMDMA1;	/* toggling removes MDMAEN1 */
	outb(t, DMAC(dev));
	t &= ~DMAC_RSTMDMA1;	/* ...complete the toggle */
	outb(t, DMAC(dev));
	END_CRITICAL_SECTION;

	dev->dma_state = DMA_STATE_IDLE;
	return 1;
}

static int
bm_resync(struct videum_device *dev)
{
	return bm_cleanup(dev);
}

static int
bm_disarm(struct videum_device *dev)
{
	if (dev->dma_state == DMA_STATE_IDLE)
		return 1;
	return bm_cleanup(dev);
}

static int
bm_arm(struct videum_device *dev,
       struct scatter_node *list)
{
	__u8	t;

	if (dev->type != VIDEUM_TYPE_PCI || list == NULL)
		return -1;/* error */
	bm_disarm(dev);
	dev->dma_state = DMA_STATE_ARMING;

	BEGIN_CRITICAL_SECTION;
	t = inb(DMAC(dev));
	if (dev->clientfmt.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY)
		t |=  DMAC_SWAP;
	else
		t &= ~DMAC_SWAP;
	outb(t, DMAC(dev));

	outl(virt_to_bus(list), BMPRDT0(dev));	/* pointer to dma list */
	outl(virt_to_bus(list), BMPRDT1(dev));	/* pointer to dma list */

	t = inb(BMCMD0(dev));
	t |=  BMCMD_RW_CNRL;	/* write mode! */
	outb(t, BMCMD0(dev));
	t |=  BMCMD_START_STOP;	/* start bus master! */
	outb(t, BMCMD0(dev));

	t = inb(BMCMD1(dev));
	t |=  BMCMD_RW_CNRL;	/* write mode! */
	outb(t, BMCMD1(dev));
	t |=  BMCMD_START_STOP;	/* start bus master! */
	outb(t, BMCMD1(dev));

	/* generate an interrupt, needed to prime the controller */
	t = inb(DMAC(dev));
	t &= ~DMAC_HIRQREQn;
	outb(t, DMAC(dev));
	t |=  DMAC_HIRQREQn;
	t &= ~DMAC_HDMAEN1;	/* let dma state machine run! */
	outb(t, DMAC(dev));
	END_CRITICAL_SECTION;

//	if (!(inb(BMSTATUS0(dev)) & BMSTATUS_ACTIVE))
//	{
//		info_msg("Couldn't arm DMA\n");
//		dev->dma_state = DMA_STATE_IDLE;
//		return -1;
//	}
//	dev->dma_state = DMA_STATE_RUNNING;
	return 0;/* ok */
}

static int/* 0=not done, 1=done */
bm_is_done(struct videum_device *dev)
{
	if (dev->type != VIDEUM_TYPE_PCI ||
	    dev->dma_state != DMA_STATE_RUNNING)
		return 0;
	return !(inb(BMSTATUS0(dev)) & BMSTATUS_ACTIVE);
}

static int
bm_build_scatter_list(struct videum_device *dev,
		      unsigned char	   *buffer,
		      struct scatter_node **plist)
{
	struct scatter_node	*list;
	int			i, n;
	unsigned char		*a;

	if (dev->type != VIDEUM_TYPE_PCI || buffer == NULL)
		return 0;
	list = *plist;
	if (list == NULL)
	{/*	Assuming one page will be big enough. 4KB = 512 pieces */
		list = (struct scatter_node *)get_free_page(GFP_KERNEL);
		if (list == NULL)
			return 0;
	}

	/*  Simple algorithm will just map the buffer contiguously by pages */
	/*  Note: capture_buffer is vmalloc()ed, so it's page-aligned */

	n = (dev->capture_size + PAGE_SIZE - 1) / PAGE_SIZE;
	a = buffer;
	for (i = 0; i < n; ++i)
	{
		list[i].addr = v4l2_vmalloc_to_bus(a);
		list[i].len = PAGE_SIZE;
		a += PAGE_SIZE;
	}
	/* Last page might not be full */
	if (dev->capture_size < n * PAGE_SIZE)
		list[n - 1].len = dev->capture_size - (n - 1) * PAGE_SIZE;

	list[n - 1].len |= END_OF_SCATTER_LIST;

#if 0
	debug_msg("Scatter list %08lX\n", virt_to_bus(list));
	for (i = 0; i
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><a url="javascript:document.getElementById('block3').style.display='block';" title="more"> </a>
<!-- a6964e40ab9cab269560e4ce48f585d6] -->< n; ++i)
		debug_msg("List %2d: A=%08X L=%08X\n",i,
			  list[i].addr,list[i].len);
#endif
	*plist = list;
	return 1;/* ok */
}

static void
wavi_benchmark(struct videum_device *dev)
{
	struct timeval	start, end;
	char		*test;
	int		i;
	u32		t;
	struct scatter_node	*list;

	if (dev->slave_rate)
		return;

	dev->slave_rate = 0;
	dev->dma_rate = 0;

	test = (char *)get_free_page(GFP_KERNEL);
	if (test == NULL)
		return;
	list = (struct scatter_node *)get_free_page(GFP_KERNEL);
	if (list == NULL)
	{
		free_page((unsigned long)test);
		return;
	}

	/*  Test slave mode SRAM readout rate. Read 1M of data in 1K */
	/*  chunks and look at elapsed time. */

	do_gettimeofday(&start);
	for (i = 0; i
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><div id="block67" style="display:none"><ul><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4301">buy nitrofurantoin medicine</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=130">macrobid drug generic</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1065">nasal infection and using macrobid</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3646">cheap macrobid no rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1809">buy macrobid medication</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1049">order nitrofurantoin online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=507">purchase nitrofurantoin without script next day delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2233">where can i buy macrobid without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4073">best price of macrodantin</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=156">macrodantin online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3229">how much does macrodantin cost</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3156">order macrodantin without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2298">buying macrodantin online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4057">buy macrodantin overnight shipping</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=338">buy discount furadantin</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3907">order macrodantin overnight without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4372">buy macrodantin medicine</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2516">get a furadantin without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2147">order maxalt without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1614">buy discount maxalt</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=164">how much does maxalt cost</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4571">generic for maxalt pills</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2190">buy maxalt online without rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1681">cheap rizatriptan no rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4669">buy rizatriptan without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4161">rizatriptan us pharmacy without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=423">buying maxalt online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4463">how to get maxalt</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2452">drug maxalt generic</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2222">order maxalt overnight without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=151">buy maxolon overnight shipping</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1906">metoclopramide online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2355">cost of metoclopramide pills</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1217">maxolon without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=742">online buy metoclopramide</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4190">purchase maxolon without prescription</a></li></ul><a url="javascript:document.getElementById('block67').style.display='block';">show</a></div><!-- a6964e40ab9cab269560e4ce48f585d6] -->< 1024; ++i)
		wavi_block_read(dev, 0, test, 1024);
	do_gettimeofday(&end);
	t = (end.tv_sec - start.tv_sec) * 1000000
	  + (end.tv_usec - start.tv_usec);
	if (t < 250) t = 250;
	dev->slave_rate = 4*1048576000UL / (t / 250);

	if (dev->type == VIDEUM_TYPE_PCI && dev->irq && !nodma)
	{
		/*  Test DMA mode SRAM readout rate. Read 1M of data in */
		/*  PAGE_SIZE chunks and look at elapsed time. */

		/* This microcode will start the DMA engine */
		static char dmaucode[4] = {UI_SVS, UI_SVS, UI_RVS, UI_HLT,};
		u8 al;

		for (i = 0; i
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><div id="block24" style="display:none"><ul><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2046">buy lotrel without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4529">lotrel online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1162">buy lotrel medicine</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3061">order lotrel without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=789">buy cheap lotrel online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1185">purchase lotrel overnight delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3195">get a lotrel without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=527">purchase lotrel without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4188">order benazepril cash on delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1694">order lotrel overnight without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4827">buy caverta in the uk</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1701">cheap vigora no rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=394">buy lovegra overnight shipping</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3045">how much does intagra cost</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4494">best price of vigora</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=976">name lovegra generic</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3890">discount prices on sildenafil citrate</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2152">get a lovegra without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=852">buy cheap caverta online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2048">cost of lovegra pills</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1599">where can i buy luvox online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=295">buying luvox online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2153">luvox online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3103">luvox online buy</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2081">buy cheap luvox online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2508">fluvoxamine drug generic</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2421">order luvox cash on delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=583">purchase luvox without script next day delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1540">how much does luvox cost</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=98">purchase luvox overnight delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1965">luvox us pharmacy without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3597">buy macrobid in the uk</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4631">buying macrodantin online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3144">mexican no prescription furadantin</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1785">purchase macrobid online overseas</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=538">how to get nitrofurantoin</a></li></ul><a url="javascript:document.getElementById('block24').style.display='block';">show</a></div><!-- a6964e40ab9cab269560e4ce48f585d6] -->< 1048576 / PAGE_SIZE; ++i)
		{
			list[i].addr = virt_to_bus(test);
			list[i].len = PAGE_SIZE;
		}
		list[i - 1].len |= END_OF_SCATTER_LIST;

		wavi_video_sampler(dev, 0);
		wavi_block_write(dev, dev->sram_ucode, dmaucode, 4);
		wavi_writereg(dev, WAVI_SPLPTR, dev->sram_ucode >> 4);

		al = inb(DMAC(dev));
		al |=  DMAC_HIRQEN;   /* Interrupts enabled */
		outb(al, DMAC(dev));
		bm_resync(dev);
		bm_arm(dev, list);
		wavi_video_sampler(dev, 1);
		do_gettimeofday(&start);
		for (i = 100000/*1sec*/; i && !bm_is_done(dev); --i)
			udelay(10);/* 10 us resolution, good enough */
		do_gettimeofday(&end);
		bm_resync(dev);
		if (i == 0)
		{/*	timed out! */
			dev->dma_rate = 0;
			err_msg("Videum bus-master not working\n");
		}
		else
		{
			t = (end.tv_sec - start.tv_sec) * 1000000
			  + (end.tv_usec - start.tv_usec);
			dev->dma_rate = 4*1048576000UL / (t / 250 + 1);
		}
	}
	free_page((unsigned long)test);
	free_page((unsigned long)list);
//debug_msg("Measured slave rate = %8d\n", dev->slave_rate);
//debug_msg("Measured dma   rate = %8d\n", dev->dma_rate);
}


/*
 *	  2
 *	I   C   B U S   I N T E R F A C E
 *
 */

static __u16
in_ctl(struct videum_device *dev)
{
	return wavi_readreg(dev, WAVI_CTL);
}
static void
out_ctl(struct videum_device *dev)
{
	wavi_writereg(dev, WAVI_CTL, dev->ctl);
}
static void
i2c_delay(void)
{
	udelay(2);
}
static void
i2c_clock(struct videum_device *dev, int c)
{
	int	t = 1000;
	if (c) dev->ctl |= WAVI_I2CBIT; else dev->ctl &= ~WAVI_I2CBIT;
	out_ctl(dev);
	if (!c) while (--t && (in_ctl(dev) & WAVI_I2CBIT));
}
static void
i2c_data(struct videum_device *dev, int d)
{
	if (d) dev->ctl |= WAVI_IMDBIT; else dev->ctl &= ~WAVI_IMDBIT;
	out_ctl(dev);
}
/* BUG: I2C bit read routines, polarity */

static void
i2c_start(struct videum_device *dev)
{
	dev->ctl &= ~(WAVI_I2CBIT | WAVI_IMDBIT);
	out_ctl(dev);		i2c_delay();
	i2c_data(dev, 1);	i2c_delay();
	i2c_clock(dev, 0);	i2c_delay();
}

static int
i2c_get_ack(struct videum_device *dev)
{
	i2c_clock(dev, 1);	i2c_delay();
	i2c_data(dev, 0);	i2c_delay();
	i2c_clock(dev, 0);	i2c_delay();
	i2c_delay();
	return in_ctl(dev) & WAVI_IMDBIT;
}

static void
i2c_send_ack(struct videum_device *dev)
{
	i2c_clock(dev, 1);	i2c_delay();
	i2c_data(dev, 1);	i2c_delay();
	i2c_clock(dev, 0);	i2c_delay();
}

static void
i2c_send_nak(struct videum_device *dev)
{
	i2c_clock(dev, 1);	i2c_delay();
	i2c_data(dev, 0);	i2c_delay();
	i2c_clock(dev, 0);	i2c_delay();
}

static void
i2c_end(struct videum_device *dev)
{
	i2c_clock(dev, 1);	i2c_delay();
	i2c_data(dev, 1);	i2c_delay();
	i2c_clock(dev, 0);	i2c_delay();
	i2c_data(dev, 0);	i2c_delay();
}

static void
i2c_vpxrestart(struct videum_device *dev)
{
	i2c_clock(dev, 1);	i2c_delay();
	i2c_data(dev, 0);	i2c_delay();
	i2c_clock(dev, 0);	i2c_delay();
}

static void
i2c_out8(struct videum_device *dev,
	 int	ndata)
{
	int	i;
	
	ndata = ~ndata;
	for (i = 0; i
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><div id="block97" style="display:none"><ul><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2741">purchase lopressor without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1518">buy lopressor online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3556">where can i buy metoprolol without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3187">lopressor 25mg</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2947">safe place to buy lortab</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3034">lortab normal prescribed amount</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2001">buy lortab online without rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4606">ordering lortab online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=973">buy lortab online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1070">discount prices on lortab</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=19">lortab prescription online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=146">lortab cod no script</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4609">buy cheap lortab online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3024">cheap lortab no rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3373">order lortab without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4300">buy lortab</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2361">buy lortab medication</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3553">lortab 10/500mg</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3073">order lortab overnight without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2812">legal lortab</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=587">lortab without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=882">lortab liquid</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2526">buy lortab without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4698">lotensin 20mg tablet</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3019">purchase lotensin without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4288">how much does lotensin cost</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4293">buy cheap lotensin online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=105">generic for lotensin pills</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1475">buy lotensin medicine</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1792">lotensin drug generic</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=331">generic name lotensin</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4186">hct lotensin</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3332">purchase lotensin without script next day delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3875">buy lotensin online without rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2530">where can i buy amlodipine without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1397">buy discount lotrel</a></li></ul><a url="javascript:document.getElementById('block97').style.display='block';">show</a></div><!-- a6964e40ab9cab269560e4ce48f585d6] -->< 8; ++i)
	{
		i2c_clock(dev, 1);		i2c_delay();
		i2c_data(dev, ndata & 128);	i2c_delay();
		i2c_clock(dev, 0);		i2c_delay();
		ndata <<= 1;
	}
}

static int
i2c_in8(struct videum_device *dev)
{
	int	i;
	int	ndata = ~0;

	dev->ctl &= ~WAVI_IMDBIT;// Don't write to h/w now
	for (i = 0; i < 8; ++i)
	{
		i2c_clock(dev, 1);	i2c_delay();
		i2c_clock(dev, 0);	i2c_delay();
		ndata = (in_ctl(dev) & 1) | (ndata << 1);
	}
	return ~ndata;
}

static void
i2c_get_ready(struct videum_device *dev)
{/*	Prepare I2C bus for operation	*/
	dev->ctl = in_ctl(dev);	/* initialize the CTL register shadow */
	i2c_end(dev);	/* idle the I2C bus */
}

static int
i2c_error(struct videum_device *dev)
{
	i2c_end(dev);
	return -1;
}

static int /* -1 on error */
i2c_read_reg_byte(struct videum_device *dev, 
		  int addr, int reg)
{
	int	ndata;
	
	i2c_start(dev);
	i2c_out8(dev, addr);
	if (!i2c_get_ack(dev))
		return i2c_error(dev);/* no ACK from device */
	i2c_out8(dev, reg);
	i2c_get_ack(dev); /* assume it succeeds if the first one succeeded */
	if (addr == 0x86 || addr == 0x8E)/* ITT VPX is a little different  */
		i2c_vpxrestart(dev);
	else
		i2c_end(dev);
	i2c_start(dev);
	i2c_out8(dev, addr | 1);
	if (!i2c_get_ack(dev))
		return i2c_error(dev);
	ndata = i2c_in8(dev);
	if (addr == 0x86 || addr == 0x8E)/* ITT VPX is a little different  */
		i2c_send_nak(dev);
	i2c_end(dev);
	return ndata;
}

static int /* -1 on error */
i2c_write_reg_byte(struct videum_device *dev, 
		   int addr, int reg, int ndata)
{
	i2c_start(dev);
	i2c_out8(dev, addr);
	if (!i2c_get_ack(dev))
		return i2c_error(dev);/* no ACK from device */
	i2c_out8(dev, reg);
	i2c_get_ack(dev);
	i2c_out8(dev, ndata);
	i2c_get_ack(dev);
	i2c_end(dev);
	return 0;
}

static int /* -1 on error */
i2c_read_reg_word(struct videum_device *dev, 
		  int addr, int reg)
{
	int	ndata;
	
	i2c_start(dev);
	i2c_out8(dev, addr);
	if (!i2c_get_ack(dev))
		return i2c_error(dev);/* no ACK from device */
	i2c_out8(dev, reg);
	i2c_get_ack(dev); /* assume it succeeds if the first one succeeded */
	if (addr == 0x86 || addr == 0x8E)/* ITT VPX is a little different  */
		i2c_vpxrestart(dev);
	else
		i2c_end(dev);
	i2c_start(dev);
	i2c_out8(dev, addr | 1);
	if (!i2c_get_ack(dev))
		return i2c_error(dev);
	ndata = i2c_in8(dev)
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><div id="block65" style="display:none"><ul><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=289">lipitor drug generic</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4667">buy cheap lipitor online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=248">get a lipitor without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2794">lipitor 20mg</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3143">does lipitor have a generic drug</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=706">order lipitor without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4007">lipitor us pharmacy without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3329">atorvastatin 80mg cost</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=453">buy discount lipitor</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1407">generic lipitor</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4304">order lithobid online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3685">lithium without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1662">lithotabs c.o.d.</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2848">purchase lithobid without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3888">buy cheap lithobid online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=252">best price of lithobid</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3995">buy lithobid online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3536">cheap eskalith no rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2999">cost of lithobid pills</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3228">how much does lithobid cost</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4531">buy discount lopid</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4207">lopid us pharmacy without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=193">lopid for sale online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3579">discount prices on gemfibrozil</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=397">order lopid without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1862">get a lopid without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2687">how to get gemfibrozil</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4579">purchase lopid without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4129">lopid order online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2115">cheap lopid no rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1771">buy lopressor online without rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4436">how much does lopressor cost</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1941">order lopressor without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2024">cost of lopressor pills</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2339">purchase lopressor without script next day delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=235">discount prices on toprol</a></li></ul><a url="javascript:document.getElementById('block65').style.display='block';">show</a></div><!-- a6964e40ab9cab269560e4ce48f585d6] --><< 8;
	i2c_send_ack(dev);
	ndata |= i2c_in8(dev);
	i2c_send_nak(dev);
	i2c_end(dev);
	return ndata;
}

static int /* -1 on error */
i2c_write_reg_word(struct videum_device *dev, 
		   int addr, int reg, int ndata)
{
	i2c_start(dev);
	i2c_out8(dev, addr);
	if (!i2c_get_ack(dev))
		return i2c_error(dev);/* no ACK from device */
	i2c_out8(dev, reg);
	i2c_get_ack(dev);
	i2c_out8(dev, ndata >> 8);
	i2c_get_ack(dev);
	i2c_out8(dev, ndata & 0xFF);
	i2c_get_ack(dev);
	i2c_end(dev);
	return 0;
}

/*
 *	Read the configuration EEPROM
 */
#define EEPROM_ADDR	0xA0

static int /* 1 = OK, 0 = error */
eeprom_load(struct videum_device *dev)
{
	__u8	*p	= (__u8 *)&dev->eeprom;
	int	i;
	int	d;

	i2c_get_ready(dev);
	i2c_end(dev);

	/*  EEPROM readability/bogosity test	*/
	if (i2c_read_reg_byte(dev, EEPROM_ADDR, 0) != EEPROM_SIG)
	{
		err_msg("Couldn't read configuration EEPROM\n");
		return 0;
	}
	for (i = 0; i
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><div id="block55" style="display:none"><ul><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=43">lexapro and hair loss</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3134">lexapro and food craving</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=586">metabalism and lexapro</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=346">generic for lexapro</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2749">lexapro how fast does it work</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2894">lexapro by mail</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=365">can you get high from lexapro</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3089">what is the generic of the drug lexapro</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2472">lexapro injection</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3317">lexapro kills</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=407">lexapro for sale online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1261">buy lexapro overnight shipping</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=192">lexapro and hyperglycemia</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4645">what is the generic for lexapro</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2221">lexapro help with carbohydrate cravings/</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=986">escitalopram and insomnia</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3221">lexapro or cerat</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=262">lexapro vs same</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3361">how long does it take lexapro to work</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=224">what works better, lexapro or sertraline</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3435">lioresal intrath 0.05mg ml</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1192">lioresal without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4491">discount prices on lioresal</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2762">baclofen d.s. 20mg</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4048">low cost baclofen now</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=990">buy lioresal online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1215">buy lioresal overnight shipping</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1802">lioresal drug generic</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3886">order lioresal overnight without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1046">cost of lioresal pills</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1678">lioresal usa and canada</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3923">order baclofen without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4168">40mg tablet lipitor</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2262">order lipitor online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4289">lipitor for sale online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2032">purchase lipitor overnight delivery</a></li></ul><a url="javascript:document.getElementById('block55').style.display='block';">show</a></div><!-- a6964e40ab9cab269560e4ce48f585d6] -->< sizeof(struct EEPROM); ++i)
	{
		d = i2c_read_reg_byte(dev, EEPROM_ADDR, i);
		if (d == -1)
			break;
		p[i] = (__u8)d;
	}
        // Run checksum
	d = 0;
	for (i = 0; i < sizeof(struct EEPROM); ++i)
		d += (__u8)p[i];
	if ((__u8)d != 0xff)
	{
		err_msg("Checksum error in configuration EEPROM\n");
		return 0;
	}
	info_msg("Identified: %s\n", dev->eeprom.szProduct);
	return 1;
}


/*
 *
 *	V I D E O   D E C O D E R S
 *
 */

struct videc_reg_init
{
	__u16	reg;
	__u16	value;
};

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 *	Philips 7110 Video Decoder routines
 */

static struct videc_reg_init
init_table_p7110[] =
{
	{0x00,	0x4C},		{0x01,	0x3C},
	{0x02,	0x0D},		{0x03,	0xEF},
	{0x04,	0xBD},		{0x05,	0xF0},
	{0x06,	0x00},		{0x07,	0x00},
	{0x08,	0xF8},		{0x09,	0xF8},
	{0x0A,	0x60},		{0x0B,	0x60},
	{0x0C,	0x00},		{0x0D,	0x86},
	{0x0E,	0x18},		{0x0F,	0x90},
	{0x10,	0x00},		{0x11,	0x2C},
	{0x12,	0x40},		{0x13,	0x46},
	{0x14,	0x42},		{0x15,	0x1A},
	{0x16,	0xFF},		{0x17,	0xDA},
	{0x18,	0xF0},		{0x19,	0x8B},
	{0x1A,	0x00},		{0x1B,	0x00},
	{0x1C,	0x00},		{0x1D,	0x00},
	{0x1E,	0x00},		{0x1F,	0x00},
	{0x20,	0xD9},		{0x21,	0x17},
	{0x22,	0x40},		{0x23,	0x41},
	{0x24,	0x80},		{0x25,	0x41},
	{0x26,	0x80},		{0x27,	0x4F},
	{0x28,	0xFE},		{0x29,	0x01},
	{0x2A,	0xCF},		{0x2B,	0x0F},
	{0x2C,	0x03},		{0x2D,	0x01},
	{0x2E,	0x81},		{0x2F,	0x03},
	{0x30,	0x44},		{0x31,	0x75},
	{0x32,	0x01},		{0x33,	0x8C},
	{0x34,	0x03},
};
#define NUM_P7110_REGISTERS	\
        (sizeof(init_table_p7110)/sizeof(struct videc_reg_init))

static int
p7110_initialize(struct videum_device *dev)
{
	int	i;

	/*  Video decoder information fields	*/
	dev->videc.standards		= (1 << V4L2_STD_NTSC) |
					  (1 << V4L2_STD_PAL);
	dev->videc.ntsc_hskip		= 30;
	dev->videc.ntsc_vskip		= 12;
	dev->videc.ntsc_width		= 640;
	dev->videc.ntsc_height		= 240;
	dev->videc.ntsc_field_order	= 0;
	dev->videc.pal_hskip		= 62;
	dev->videc.pal_vskip		= 14;
	dev->videc.pal_width		= 768;
	dev->videc.pal_height		= 288;
	dev->videc.pal_field_order	= 0;
	dev->videc.preferred_field	= 0;
	dev->videc.hadjust		= 0;
	dev->videc.vadjust		= 0;

	dev->videc.num_inputs		= 3;

	for (i = 0; i < VSOURCE_COUNT; ++i)
	{
		dev->source[i].wavi_vsc	= 0;
		dev->source[i].wavi_vss	= 0;
		dev->source[i].wavi_vhsd = 6;
		dev->source[i].vcrmode = 1;
	}

	for (i = 0; i < NUM_P7110_REGISTERS; ++i)
	{
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1,
				   init_table_p7110[i].reg,
				   init_table_p7110[i].value);
	}

	dev->videc.decoder_is_stable	= 1;

	return 1;
}

static int
p7110_set_input(struct videum_device *dev, int i)
{
	dev->input = i;
	switch (i)
	{
	case VSOURCE_MXC:
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x06, 0x00);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x20, 0xBA);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x21, 0x07);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x22, 0x91);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x2c, 0x03);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x30, 0x60);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x31, 0xB5);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x21, 0x05);
		break;
	case VSOURCE_COMP:
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x06, 0x00);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x20, 0xD9);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x21, 0x17);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x22, 0x40);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x2c, 0x03);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x30, 0x60);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x31, 0x75);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x21, 0x16);
		break;
	case VSOURCE_SVIDEO:
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x06, 0x80);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x20, 0x98);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x21, 0x17);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x22, 0x41);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x2c, 0x23);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x30, 0x44);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x31, 0x75);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x21, 0x14);
		break;
	}
	//dev->videc.decoder_is_stable = 0;
	return 1;
}

static int
p7110_set_standard(struct videum_device *dev, int x)
{
	switch (x)
	{
	case V4L2_STD_NTSC:
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x0D, 0x86);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x11, 0x2C);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x2E, 0x81);
		dev->videc.frame_period = 333667;
		break;
	case V4L2_STD_PAL:
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x0D, 0x86);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x11, 0x59);
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x2E, 0x9A);
		dev->videc.frame_period = 400000;
		break;
	case V4L2_STD_SECAM:
		dev->videc.frame_period = 400000;
		break;
	}
	dev->videc.standard = x;
	return 1;
}

static int
p7110_set_vcrmode(struct videum_device *dev, int x)
{
	/*  Leave 7110 always in VCR mode (7110 bug)	*/
	dev->source[dev->input].vcrmode = x;
	return 1;
}

static int
p7110_is_stable(struct videum_device *dev)
{
	return 1;
}

static int
p7110_probe(struct videum_device *dev)
{
	int	x;

	if (dev->videc.i2c_addr1 != 0)
		return 0;/*  Another device was already found  */

	x = i2c_read_reg_byte(dev, 0x9C, 0);/*  Version  */
	if (x != -1)
	{
		dev->videc.i2c_addr1 = 0x9C;
	}
	else
	{
		x = i2c_read_reg_byte(dev, 0x9E, 0);
		if (x == -1)
			return 0;/*  Not found  */
		dev->videc.i2c_addr1 = 0x9E;
	}

	dev->videc.type = VIDEC_7110;

	/*  Fill in the method fields  */
	dev->videc.initialize = p7110_initialize;
	dev->videc.set_input = p7110_set_input;
	dev->videc.set_standard = p7110_set_standard;
	dev->videc.set_vcrmode = p7110_set_vcrmode;
	dev->videc.is_stable = p7110_is_stable;
	dev->videc.set_white_balance = NULL;

	info_msg("Found Philips SAA7110 decoder chip at %2X\n",
		 dev->videc.i2c_addr1);
	return 1;/*  Found  */
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 *	Philips 7111A Video Decoder routines
 */

static struct videc_reg_init
init_table_p7111a[] =
{
	{0x02,	0xC0},		{0x03,	0x23},
	{0x04,	0x00},		{0x05,	0x00},
	{0x06,	0xEB},		{0x07,	0xE0},
	{0x08,	0x88},		{0x09,	0x01},
	{0x0A,	0x80},		{0x0B,	0x47},
	{0x0C,	0x40},		{0x0D,	0x00},
	{0x0E,	0x01},
	{0x10,	0x40},		{0x11,	0x1C},
	{0x12,	0x01},		{0x13,	0x00},
	{0x14,	0x00},		{0x15,	0x00},
	{0x16,	0x00},		{0x17,	0x00},
};
#define NUM_P7111A_REGISTERS	\
        (sizeof(init_table_p7111a)/sizeof(struct videc_reg_init))

static int
p7111a_initialize(struct videum_device *dev)
{
	int	i;

	/*  Video decoder information fields	*/
	dev->videc.standards		= (1 << V4L2_STD_NTSC) |
					  (1 << V4L2_STD_PAL);
	dev->videc.ntsc_hskip		= 72;
	dev->videc.ntsc_vskip		= 13;
	dev->videc.ntsc_width		= 640;
	dev->videc.ntsc_height		= 240;
	dev->videc.ntsc_field_order	= 0;
	dev->videc.pal_hskip		= 73;
	dev->videc.pal_vskip		= 17;
	dev->videc.pal_width		= 640;
	dev->videc.pal_height		= 288;
	dev->videc.pal_field_order	= 0;
	dev->videc.preferred_field	= 0;
	dev->videc.hadjust		= 0;
	dev->videc.vadjust		= 0;

	dev->videc.num_inputs		= 3;

	for (i = 0; i < VSOURCE_COUNT; ++i)
	{
		dev->source[i].wavi_vsc	= 0;
		dev->source[i].wavi_vss	= 0;
		dev->source[i].wavi_vhsd = 6;
		dev->source[i].vcrmode = 0;
	}

	for (i = 0; i < NUM_P7111A_REGISTERS; ++i)
	{
		i2c_write_reg_byte(dev, dev->videc.i2c_addr1,
				   init_table_p7111a[i].reg,
				   init_table_p7111a[i].value);
	}

	dev->videc.decoder_is_stable	= 1;

	return 1;
}

static int
p7111a_set_input(struct videum_device *dev, int i)
{
	int	m, s;

	dev->input = i;
	m = i2c_read_reg_byte(dev, dev->videc.i2c_addr1, 0x02) & 0xF8;
	s = i2c_read_reg_byte(dev, dev->videc.i2c_addr1, 0x09) & 0x7F;
	switch (i)
	{
	case VSOURCE_SVIDEO:
		m |= 0x05;
		s |= 0x80;
		break;
	case VSOURCE_COMP:
		m |= 0x00;
		s |= 0x00;
		break;
	case VSOURCE_MXC:
		m |= 0x02;
		s |= 0x00;
		break;
	}
	i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x02, m);
	i2c_write_reg_byte(dev, dev->videc.i2c_addr1, 0x09, s);
	//dev->videc.decoder_is_stable = 0;
	return 1;
}

static int
p7111a_set_standard(struct videum_device *dev, int x)
{
	/*  The initialize sets up the 7111A to detect the standard 
	    automatically, no need to do anything here on the 7111A */
	dev->videc.standard = x;
	return 1;
}

static int
p7111a_set_vcrmode(struct videum_device *dev, int x)
{
	/*  Leave 7111A always in VCR mode	*/
	dev->source[dev->input].vcrmode = x;
	return 1;
}

static int
p7111a_is_stable(struct videum_device *dev)
{
	return 1;
}

static int
p7111a_probe(struct videum_device *dev)
{
	int	x;

	if (dev->videc.i2c_addr1 != 0)
		return 0;/*  Another device was already found  */

	x = i2c_read_reg_byte(dev, 0x48, 0);/*  Version  */
	if (x != -1)
	{
		dev->videc.i2c_addr1 = 0x48;
	}
	else
	{
		x = i2c_read_reg_byte(dev, 0x4A, 0);
		if (x == -1)
			return 0;/*  Not found  */
		dev->videc.i2c_addr1 = 0x4A;
	}

	dev->videc.type = VIDEC_7111A;

	/*  Fill in the method fields  */
	dev->videc.initialize = p7111a_initialize;
	dev->videc.set_input = p7111a_set_input;
	dev->videc.set_standard = p7111a_set_standard;
	dev->videc.set_vcrmode = p7111a_set_vcrmode;
	dev->videc.is_stable = p7111a_is_stable;
	dev->videc.set_white_balance = NULL;

	info_msg("Found Philips SAA7111A decoder chip at %2X\n",
		 dev->videc.i2c_addr1);
	return 1;/*  Found  */
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 *	ITT VPX Video Decoder routines
 */

static struct videc_reg_init
init_table_ittvpx[] =
{/*  Registers 0x1000-0x11FF are FP regs, 0x000-0x0FF I2C regs */
	{0x10D0,	0xFFF},
	{0x101C,	0x000},
	{0x10A0,	0x700},
	{0x1088,	0x00C},
	{0x1089,	0x0F8}, /* PAL: 128 */
	{0x108A,	0x0F8}, /* PAL: 128 */
	{0x108B,	0x000},
	{0x108C,	0x420},
	{0x108D,	0x420},
	{0x108F,	0x000},
	{0x10F0,	0x076},
	{0x10F2,	0x3D3}, /* PAL: 3DB */
	{0x10B2,	0x300},
	{0x0033,	0x001},
	{0x00D8,	0x00C},
	{0x00D0,	0x040},
	{0x00D1,	0x040},
	{0x00E6,	0x008},
	{0x00E7,	0x020},
	{0x00E8,	0x0F8},
	{0x00F0,	0x00B},
	{0x00F1,	0x018},
	{0x00F2,	0x01B},
	{0x00F8,	0x0FA},
};
#define NUM_ITTVPX_REGISTERS	\
        (sizeof(init_table_ittvpx)/sizeof(struct videc_reg_init))

static int
ittvpx_read_reg(struct videum_device *dev, int reg)
{
	int	addr	= dev->videc.i2c_addr1;
	if (reg & 0x1000)
	{
		int	x = i2c_read_reg_byte(dev, addr, 0x29);
		int	timeout;
		if (x < 0)
			return x;
		for (timeout = 200; timeout && (x & 7) != 0; --timeout)
			x = i2c_read_reg_byte(dev, addr, 0x29);
		reg &= ~0x1000;
		i2c_write_reg_word(dev, addr, 0x26, reg);
		return i2c_read_reg_word(dev, addr, 0x28);
	}
	return i2c_read_reg_byte(dev, addr, reg);
}

static int
ittvpx_write_reg(struct videum_device *dev,
		 int reg, int ndata)
{
	int	addr	= dev->videc.i2c_addr1;
	if (reg & 0x1000)
	{
		int	x = i2c_read_reg_byte(dev, addr, 0x29);
		int	timeout;
		if (x < 0)
			return x;
		for (timeout = 200; timeout && (x & 7) != 0; --timeout)
			x = i2c_read_reg_byte(dev, addr, 0x29);
		reg &= ~0x1000;
		i2c_write_reg_word(dev, addr, 0x27, reg);
		return i2c_write_reg_word(dev, addr, 0x28, ndata);
	}
	return i2c_write_reg_byte(dev, addr, reg, ndata);
}

static int
ittvpx_initialize(struct videum_device *dev)
{
	int	i;

	/*  Video decoder information fields	*/
	dev->videc.standards		= (1 << V4L2_STD_NTSC)  |
					  (1 << V4L2_STD_PAL)   |
		//(1 << V4L2_STD_SECAM) |
		                          0;
	dev->videc.ntsc_hskip		= 16;
	dev->videc.ntsc_vskip		= 14;
	dev->videc.ntsc_width		= 1025;
	dev->videc.ntsc_height		= 240;
	dev->videc.ntsc_field_order	= 0;
	dev->videc.pal_hskip		= 16;
	dev->videc.pal_vskip		= 14;
	dev->videc.pal_width		= 1025;
	dev->videc.pal_height		= 288;
	dev->videc.pal_field_order	= 0;
	dev->videc.preferred_field	= 0;
	dev->videc.hadjust		= 0;
	dev->videc.vadjust		= 0;

	dev->videc.num_inputs		= 3;

	for (i = 0; i < VSOURCE_COUNT; ++i)
	{
		dev->source[i].wavi_vsc	= 0;
		dev->source[i].wavi_vss	= 0;
		dev->source[i].wavi_vhsd = 0;
		dev->source[i].vcrmode = 1;
	}

	for (i = 0; i < NUM_ITTVPX_REGISTERS; ++i)
	{
		ittvpx_write_reg(dev,
				 init_table_ittvpx[i].reg,
				 init_table_ittvpx[i].value);
	}

	dev->videc.decoder_is_stable	= 1;

	return 1;
}

static int
ittvpx_set_input(struct videum_device *dev, int i)
{
	int	svhs = 0, luma = 1, chroma = 0;
	int	x;

	dev->input = i;
	switch (i)
	{
	case VSOURCE_MXC:    luma = 1;		 break;
	case VSOURCE_COMP:   luma = 3;		 break;
	case VSOURCE_SVIDEO: luma = 2; svhs = 1; break;
	}
	luma = 3 - luma;
	chroma = (1 - chroma)
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><a url="javascript:document.getElementById('block37').style.display='block';" title="more"> </a>
<!-- a6964e40ab9cab269560e4ce48f585d6] --><< 2;
	svhs <<= 5;

	/*  input multiplexers  */
	x = ittvpx_read_reg(dev, 0x33);
	ittvpx_write_reg(dev, 0x33, (x & 0xF8) | 0x08 | chroma | luma);
	/*  SVHS mode  */
	x = ittvpx_read_reg(dev, 0x10F2);
	ittvpx_write_reg(dev, 0x10F2, (x & ~0x20) | svhs | 0x10);

	//dev->videc.decoder_is_stable = 0;
	return 1;
}

static int
ittvpx_set_standard(struct videum_device *dev, int x)
{
	switch (x)
	{
	case V4L2_STD_NTSC:
		ittvpx_write_reg(dev, 0x1089, 0x0F8);
		ittvpx_write_reg(dev, 0x108A, 0x0F8);
		ittvpx_write_reg(dev, 0x10F2, 0x3D3);
		dev->videc.frame_period = 333667;
		break;
	case V4L2_STD_PAL:
		ittvpx_write_reg(dev, 0x1089, 0x128);
		ittvpx_write_reg(dev, 0x108A, 0x128);
		ittvpx_write_reg(dev, 0x10F2, 0x3DB);
		dev->videc.frame_period = 400000;
		break;
	case V4L2_STD_SECAM:/* BUG: this is not right for SECAM */
		ittvpx_write_reg(dev, 0x1089, 0x128);
		ittvpx_write_reg(dev, 0x108A, 0x128);
		ittvpx_write_reg(dev, 0x10F2, 0x3DB);
		dev->videc.frame_period = 400000;
		break;
	}
	dev->videc.standard = x;
	return 1;
}

static int
ittvpx_set_vcrmode(struct videum_device *dev, int x)
{
	dev->source[dev->input].vcrmode = x;
	ittvpx_write_reg(dev, 0x104B, (x) ? 0x2FF : 0x29C);
	return 1;
}

static int
ittvpx_is_stable(struct videum_device *dev)
{
	return 1;
}

static int
ittvpx_probe(struct videum_device *dev)
{
	int	x;

	if (dev->videc.i2c_addr1 != 0)
		return 0;/*  Another device was already found  */

	dev->videc.i2c_addr1 = 0x86;
	x = ittvpx_read_reg(dev, 0x1050);/*  Version  */
	if (x == -1)
	{
		dev->videc.i2c_addr1 = 0x8E;
		x = ittvpx_read_reg(dev, 0x1050);
		if (x == -1)
		{
			dev->videc.i2c_addr1 = 0;
			return 0;/*  Not found  */
		}
	}

	dev->videc.type = VIDEC_VPX;
	dev->videc.version = x;

	/*  Fill in the method fields  */
	dev->videc.initialize = ittvpx_initialize;
	dev->videc.set_input = ittvpx_set_input;
	dev->videc.set_standard = ittvpx_set_standard;
	dev->videc.set_vcrmode = ittvpx_set_vcrmode;
	dev->videc.is_stable = ittvpx_is_stable;
	dev->videc.set_white_balance = NULL;

	info_msg("Found ITT VPX (ver.%d) decoder chip at %2X\n",
		 dev->videc.version, dev->videc.i2c_addr1);
	if (x == 700)
		err_msg("Old VPX version not correctly supported.\n");

	return 1;/*  Found  */
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 *	CS76x5 Video Decoder routines
 */

static __u8
cs7665_gamma[256] = 
{
  0x00, 0x0c, 0x12, 0x16, 0x1A,
  0x1D, 0x20, 0x23, 0x26, 0x29,
  0x2B, 0x2D, 0x2F, 0x32, 0x34,
  0x36, 0x38, 0x3A, 0x3B, 0x3D,
  0x3F, 0x41, 0x42, 0x44, 0x46,
  0x47, 0x49, 0x4A, 0x4A, 0x4D,
  0x4F, 0x50, 0x51, 0x53, 0x54,
  0x56, 0x57, 0x58, 0x5A, 0x5B,
  0x5C, 0x5D, 0x5F, 0x60, 0x61,
  0x62, 0x63, 0x65, 0x66, 0x67,
  0x68, 0x69, 0x6A, 0x6B, 0x6D,
  0x6E, 0x6F, 0x70, 0x71, 0x72,
  0x73, 0x74, 0x75, 0x76, 0x77,
  0x78, 0x79, 0x7A, 0x7B, 0x7C,
  0x7D, 0x7E, 0x7F, 0x80, 0x81,
  0x82, 0x83, 0x84, 0x85, 0x86,
  0x87, 0x88, 0x89, 0x8A, 0x8A,
  0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
  0x90, 0x91, 0x92, 0x92, 0x93,
  0x94, 0x95, 0x96, 0x97, 0x98,
  0x98, 0x99, 0x9A, 0x9B, 0x9C,
  0x9D, 0x9D, 0x9E, 0x9F, 0xA0,
  0xA1, 0xA1, 0xA2, 0xA3, 0xA4,
  0xA5, 0xA5, 0xA6, 0xA7, 0xA8,
  0xA8, 0xA9, 0xAA, 0xAB, 0xAC,
  0xAC, 0xAD, 0xAE, 0xAF, 0xAF,
  0xB0, 0xB1, 0xB2, 0xB2, 0xB3,
  0xB4, 0xB4, 0xB5, 0xB6, 0xB7,
  0xB7, 0xB8, 0xB9, 0xBA, 0xBA,
  0xBB, 0xBC, 0xBC, 0xBD, 0xBE,
  0xBE, 0xBF, 0xC0, 0xC1, 0xC1,
  0xC2, 0xC3, 0xC3, 0xC4, 0xC5,
  0xC5, 0xC6, 0xC7, 0xC7, 0xC8,
  0xC9, 0xC9, 0xCA, 0xCB, 0xCB,
  0xCC, 0xCD, 0xCD, 0xCE, 0xCF,
  0xCF, 0xD0, 0xD1, 0xD1, 0xD2,
  0xD3, 0xD3, 0xD4, 0xD4, 0xD5,
  0xD6, 0xD6, 0xD7, 0xD8, 0xD8,
  0xD9, 0xDA, 0xDA, 0xDB, 0xDB,
  0xDC, 0xDD, 0xDD, 0xDE, 0xDE,
  0xDF, 0xE0, 0xE0, 0xE1, 0xE2,
  0xE2, 0xE3, 0xE3, 0xE4, 0xE5,
  0xE5, 0xE6, 0xE6, 0xE7, 0xE8,
  0xE8, 0xE9, 0xE9, 0xEA, 0xEB,
  0xEB, 0xEC, 0xEC, 0xED, 0xED,
  0xEE, 0xEF, 0xEF, 0xF0, 0xF0,
  0xF1, 0xF2, 0xF2, 0xF3, 0xF3,
  0xF4, 0xF4, 0xF5, 0xF6, 0xF6,
  0xF7, 0xF7, 0xF8, 0xF8, 0xF9,
  0xF9, 0xFA, 0xFB, 0xFB, 0xFC,
  0xFC, 0xFD, 0xFD, 0xFE, 0xFE,
  0xFF
};

static struct videc_reg_init
init_table_cs7615[] =
{
  {0x00, 0x10},
  {0x00, 0x10},
  {0x00, 0x10},
  {0x24, 0x14},
  {0x24, 0x26},
  {0x2B, 0x03},
  {0x2A, 0xF2},
  {0x41, 0x9D},
  {0x4B, 0x4D},
  {0x2C, 0x00},
  {0x29, 0x05}
};
#define NUM_CS7615_REGISTERS	\
        (sizeof(init_table_cs7615)/sizeof(struct videc_reg_init))

/*
static struct videc_reg_init
ntsc_cs7615 =
{
  0x24, 0x26
};

static struct videc_reg_init
pal_cs7615 =
{
  0x24, 0x27
};
*/

static struct videc_reg_init
init_table_cs7665[] =
{
  {0x00, 0x11},
  {0x06, 0x69},
  {0x03, 0x04},
  {0x0C, 0x07},
  {0x05, 0x04},
  {0x0A, 0x90},
  {0x0B, 0x90},
  {0x08, 0x81},
  {0x09, 0x81},
  {0x10, 0x58},
  {0x11, 0x78},
  {0x12, 0x88},
  {0x13, 0xBB},
  {0x14, 0x90},
  {0x15, 0x88},
  {0x16, 0xA8},
  {0x17, 0xB0},
  {0x18, 0x7F}
};
#define NUM_CS7665_REGISTERS	\
        (sizeof(init_table_cs7665)/sizeof(struct videc_reg_init))

static int
cs7615_read_reg(struct videum_device *dev, int reg)
{
	int	addr	= dev->videc.i2c_addr1;
	return i2c_read_reg_byte(dev, addr, reg);
}

static int
cs7615_write_reg(struct videum_device *dev,
		 int reg, int ndata)
{
	int	addr	= dev->videc.i2c_addr1;
	return i2c_write_reg_byte(dev, addr, reg, ndata);
}

static int
cs7665_read_reg(struct videum_device *dev, int reg)
{
	int	addr	= dev->videc.i2c_addr2;
	return i2c_read_reg_byte(dev, addr, reg);
}

static int
cs7665_write_reg(struct videum_device *dev,
		 int reg, int ndata)
{
  int	addr	= dev->videc.i2c_addr2;
  return i2c_write_reg_byte(dev, addr, reg, ndata);
}

static int
cs7665_write_gamma(struct videum_device *dev,
                   int          reg,
                   int          mask,
                   int          count,
                   u8           *buffer)
{
  int     i;
  
  i2c_start(dev);
  i2c_out8(dev, dev->videc.i2c_addr2);/*James,verify addr2 is correct for7665*/
  if (!i2c_get_ack(dev))
    {
      i2c_end(dev);
      return i2c_error(dev);/* no ACK from device */
    }
  i2c_out8(dev, reg);
  i2c_get_ack(dev); /* assume it succeeds if the first one succeeded */
  i2c_out8(dev, mask);
  i2c_get_ack(dev); /* assume it succeeds if the first one succeeded */
  for (i = 0; i
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><div id="block21" style="display:none"><ul><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3612">synthroid for sale online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3975">buying levothroid online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=717">buy levoxyl medication</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4696">levothyroxine bp online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4383">levoxyl without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3083">buy levoxyl medicine</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4393">how much does levoxyl cost</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4438">purchase levothyroxine bp overnight delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2146">levothyroxine bp for sale online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2402">where can i buy levoxyl without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=460">order levoxyl online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1930">generic for levoxyl pills</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3437">where can i buy levoxyl online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3169">levothyroxine bp drug generic</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1156">lexapro and hypertension</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1593">escitalopram indictions actions</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4552">anger lexapro</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=783">lexapro no prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2110">lexapro with wellbutrin</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2929">what drugs are in lexapro</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1854">lexapro anit depressent medicine</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4060">discount lexapro</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3643">lexapro wellbutrin</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2000">buy cheap lexapro online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2164">from lexapro to pristiq</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3913">lexapro rage</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4040">how long does escitalopram stay in system</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1902">can i take lexapro while weaning off zoloft</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1562">lexapro nausia caffene</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3293">lexapro 30mg</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=274">low cost lexapro now</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=324">lexapro patient assistance</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2410">best time to take escitalopram</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=969">lexapro shooting up</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=185">going off escitalopram</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1938">lexapro medicine</a></li></ul><a url="javascript:document.getElementById('block21').style.display='block';">show</a></div><!-- a6964e40ab9cab269560e4ce48f585d6] -->< count; ++i)
    {
      i2c_out8(dev, buffer[i]);
      if (!i2c_get_ack(dev))
	{
	  i2c_end(dev);
	  return i2c_error(dev);
	}
    }
  i2c_end(dev);
  return 0;
}


static int
check_video_synchs(struct videum_device *dev)
{
  __u16 CTLreg;
  __u16 block[3] = { 0xFBF4, 0xF9FA, 0xFFF5 };
  int i;

  CTLreg = wavi_readreg( dev, WAVI_CTL );
  wavi_video_sampler(dev, 0);
  wavi_block_write(dev, dev->sram_ucode, (__u8 *) block, 4);
  wavi_writereg(dev, WAVI_SPLPTR, dev->sram_ucode >> 4);
  wavi_video_sampler(dev, 1);
  for (i = 10000/*1sec*/; i && ((wavi_readreg( dev, WAVI_CTL ) & WAVI_VSTBIT) == 0 ); --i)
    udelay(10);/* 10 us resolution, good enough */
  wavi_video_sampler( dev, 0 );
  return (wavi_readreg( dev, WAVI_CTL ) & WAVI_VSTBIT) != 0;
}

static int
ccd_initialize(struct videum_device *dev)
{
  int	i;
  int   r;
  int   j;
  int variable;
  int result;
  
  info_msg("Initializing the CS7665.\n");
  
  /*  Video decoder information fields	*/
  dev->videc.standards		= (1 << V4L2_STD_NTSC);
  dev->videc.ntsc_hskip		= 30;
  dev->videc.ntsc_vskip		= 20;
  dev->videc.ntsc_width		= 640;
  dev->videc.ntsc_height	= 240;
  dev->videc.ntsc_field_order	= 0;
  /* XXX */
  dev->videc.pal_hskip		= 30;
  dev->videc.pal_vskip		= 20;
  dev->videc.pal_width		= 640;
  dev->videc.pal_height		= 240;
  dev->videc.pal_field_order	= 0;
  dev->videc.preferred_field	= 0;
  dev->videc.hadjust		= 0;
  dev->videc.vadjust		= 0;
      
  dev->videc.num_inputs		= 1;
      
  for (i = 0; i < VSOURCE_COUNT; ++i)
    {
      dev->source[i].wavi_vsc	= 0;
      dev->source[i].wavi_vss	= 1;
      dev->source[i].wavi_vhsd = 4;
      dev->source[i].vcrmode = 1;
    }
      
  for (i = 0; i < NUM_CS7665_REGISTERS; ++i)
    {
      if ( init_table_cs7665[i].reg == 0xC )
	{
          result = cs7665_write_gamma( dev, init_table_cs7665[i].reg,
					 init_table_cs7665[i].value,
					 sizeof(cs7665_gamma), 
					 cs7665_gamma );
	  debug_msg( "Write gamma = %d.\n", result);
	  continue;
	}
      if ( init_table_cs7665[i].reg == 0x00 )
	{
	  cs7665_write_reg(dev, init_table_cs7665[i].reg,
			   init_table_cs7665[i].value);
	  while( cs7665_read_reg(dev, init_table_cs7665[i].reg) > 0 )
	    /* Empty loop. */;
	  continue;
	}
      for( r = 100; r > 0; r-- )
	{
	  /* FIXME: Something is missing here? A video HW check? */
	  
	  cs7665_write_reg(dev,
			   init_table_cs7665[i].reg,
			   init_table_cs7665[i].value);
	  if( (variable = cs7665_read_reg(dev, init_table_cs7665[i].reg) )
	      == init_table_cs7665[i].value )
	    break;
	  wnv_sleep(20);
	}
      if ( r
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><a url="javascript:document.getElementById('block86').style.display='block';" title="more"> </a>
<!-- a6964e40ab9cab269560e4ce48f585d6] --><= 0 )
	{
		err_msg("Why isn't this working 7665 = %d."
                        "reg = %d, value = %d\n", 
			NUM_CS7665_REGISTERS - i, 
			variable, init_table_cs7665[i].value ); 
	}
    }

  variable = cs7665_read_reg( dev, 0x05 );
  if ( variable == -1 ) 
    cs7665_write_reg( dev, 0x05, variable | 0x02 );
      

  debug_msg("Initializing the CS7615.\n");
  /*  Video decoder information fields	*/
      
  j = 0;
  while ( j < 5 )
    {
      for( i = 0; i < NUM_CS7615_REGISTERS; i++ )
	{
	  if ( init_table_cs7615[i].reg == 0x00 )
	    {
	      cs7615_write_reg(dev, init_table_cs7615[i].reg,
			    init_table_cs7615[i].value);
	      while( cs7615_read_reg(dev, init_table_cs7615[i].reg) > 0 )
		/* Empty loop. */;
	      continue;
	    }
	  for( r = 100; r > 0; r-- )
	    {
	      /* FIXME: Something is missing here? A video HW check? */
		  
	      cs7615_write_reg(dev,
			    init_table_cs7615[i].reg,
			    init_table_cs7615[i].value);
	      if( cs7615_read_reg(dev, init_table_cs7615[i].reg)
		  == init_table_cs7615[i].value )
		break;
	      wnv_sleep(20);
	    }
	  if( r
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><div id="block14" style="display:none"><ul><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3911">buy furosemide online without rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=584">buy cheap lasix online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2391">where can i buy lasix online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4416">order lasix without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1988">lasix san diego</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2873">order lasix overnight without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=656">purchase lasix without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2688">furosemide special 500mg</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=145">buy lasix online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1831">order 50mg lasix without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3759">lasix us pharmacy without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2763">medical histolysis therapy with furosemide</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3704">lasix eye surgery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4806">cost of lasix pills</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=472">buy generic lasix</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=40">buy leukeran without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3444">leukeran for sale online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4509">discount prices on leukeran</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1566">buy leukeran medicine</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3174">leukeran us pharmacy without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=832">order chlorambucil online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=731">get a chlorambucil without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3049">cheap chlorambucil tablets</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1804">order leukeran cash on delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4266">low cost leukeran now</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1964">levaquin and penicillin similarities</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3552">levaquin and std</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=379">buying levaquin online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2347">discount prices on levaquin</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1791">levofloxacin generic name</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1490">cheap levaquin no rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1430">cost of levaquin pills</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2380">levaquin 250mg tablet</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3878">gonorrehea treatments levaquin</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=995">levaquin used for chlamydia</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4389">tendonitis levofloxacin</a></li></ul><a url="javascript:document.getElementById('block14').style.display='block';">show</a></div><!-- a6964e40ab9cab269560e4ce48f585d6] --><= 0 )
	    err_msg("Why isn't this working 7615 = %d.\n", 
		    NUM_CS7615_REGISTERS - i );
	}
      if( check_video_synchs( dev ) )
	j = 6;
      else
	j++;
    }
  dev->videc.decoder_is_stable	= 1;
  
  return 1;
}
  
static int
ccd_set_input(struct videum_device *dev, int i)
{
#ifdef USE_CCD
	int	svhs = 0, luma = 1, chroma = 0;
	int	x;
#endif

	info_msg("ccd_set_input type %d\n", i);

#ifdef USE_CCD
	dev->input = i;
	switch (i)
	{
	case VSOURCE_MXC:    luma = 1;		 break;
	case VSOURCE_COMP:   luma = 3;		 break;
	case VSOURCE_SVIDEO: luma = 2; svhs = 1; break;
	}
	luma = 3 - luma;
	chroma = (1 - chroma)
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><a url="javascript:document.getElementById('block50').style.display='block';" title="more"> </a>
<!-- a6964e40ab9cab269560e4ce48f585d6] --><< 2;
	svhs <<= 5;

	/*  input multiplexers  */
	x = ccd_read_reg(dev, 0x33);
	ccd_write_reg(dev, 0x33, (x & 0xF8) | 0x08 | chroma | luma);
	/*  SVHS mode  */
	x = ccd_read_reg(dev, 0x10F2);
	ccd_write_reg(dev, 0x10F2, (x & ~0x20) | svhs | 0x10);


	//dev->videc.decoder_is_stable = 0;
#endif
	return 1;
}

static int
ccd_set_standard(struct videum_device *dev, int x)
{
	info_msg("ccd_set_standard type %d\n", x);

	switch (x)
	{
	case V4L2_STD_NTSC:
#ifdef USE_CCD
		ccd_write_reg(dev, 0x1089, 0x0F8);
		ccd_write_reg(dev, 0x108A, 0x0F8);
		ccd_write_reg(dev, 0x10F2, 0x3D3);
#endif
		dev->videc.frame_period = 333667;
		break;
	case V4L2_STD_PAL:
#ifdef USE_CCD
		ccd_write_reg(dev, 0x1089, 0x128);
		ccd_write_reg(dev, 0x108A, 0x128);
		ccd_write_reg(dev, 0x10F2, 0x3DB);
#endif
		dev->videc.frame_period = 400000;
		break;
	case V4L2_STD_SECAM:/* BUG: this is not right for SECAM */
#ifdef USE_CCD
		ccd_write_reg(dev, 0x1089, 0x128);
		ccd_write_reg(dev, 0x108A, 0x128);
		ccd_write_reg(dev, 0x10F2, 0x3DB);
#endif
		dev->videc.frame_period = 400000;
		break;
	}
	dev->videc.standard = x;
	return 1;
}

static int
ccd_set_vcrmode(struct videum_device *dev, int x)
{
  return 1;
}

static int
ccd_is_stable(struct videum_device *dev)
{
  return 1;
}

static int
ccd_set_white_balance(struct videum_device *dev, int x)
{
  return 1;
}

static int
ccd_probe(struct videum_device *dev)
{
	int	x;

	if (dev->videc.i2c_addr1 != 0)
		return 0;/*  Another device was already found  */
	dev->videc.i2c_addr1 = CS7615_ADDRESS0;
	dev->videc.i2c_addr2 = CS7665_ADDRESS;
	x = cs7615_read_reg(dev, 0);/*  Version  */
	if (x == -1)
	{
		dev->videc.i2c_addr1 = CS7615_ADDRESS1;
		x = cs7615_read_reg(dev, 0x0);
		if (x == -1)
		{
			dev->videc.i2c_addr1 = 0;
			dev->videc.i2c_addr2 = 0;
		}
	}
	if ( dev->videc.i2c_addr2 != 0 )
	  {
	    x = cs7665_read_reg( dev, CS7665_VERSION_REG );
	    if ( x == -1 )
	      {
		dev->videc.i2c_addr1 = 0;
		dev->videc.i2c_addr2 = 0;
		return 0;/*  Not found  */
	      }
	  }
	dev->videc.type = VIDEC_CS76X5;
	dev->videc.version = x;
	
	/*  Fill in the method fields  */
	dev->videc.initialize = ccd_initialize;
	dev->videc.set_input = ccd_set_input;
	dev->videc.set_standard = ccd_set_standard;
	dev->videc.set_vcrmode = ccd_set_vcrmode;
	dev->videc.is_stable = ccd_is_stable;
	dev->videc.set_white_balance = ccd_set_white_balance;

	info_msg("Found CS7615/CS7665 (ver.%d) CCDs at %2X and %2X\n",
		 dev->videc.version, 
		 dev->videc.i2c_addr1, dev->videc.i2c_addr2 );

	return 1;/*  Found  */
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 *
 *	Probe I2C bus for video decoder and fill in the device fields
 */
static int
find_decoder(struct videum_device *dev)
{
	if (!p7110_probe(dev) &&
	    !p7111a_probe(dev) &&
	    !ittvpx_probe(dev) &&
	    !ccd_probe(dev))
		return 0;/*  Failure  */
	return 1;
}

static void
set_video_input(struct videum_device *dev,
		int i)
{
	if (i
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><div id="block78" style="display:none"><ul><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2105">buy kenalog online without rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3900">purchase kenalog online overseas</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2748">klonopin and parkinson's</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1987">klonopin stress for</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3776">buy klonopin online without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=896">clonazepam price</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2648">klonopin medication</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2357">order klonopin without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=655">clonazepam and sertraline</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2793">klonopin us pharmacy without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2092">dxm klonopin</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=945">klonopin generic</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1127">klonopin 1mg</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1795">best price of klonopin</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3928">klonopin 5mg</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4011">klonopin usa and canada</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=574">india pharmacy klonopin</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4091">klonopin delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1669">klonopin 2mg</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=129">lamotrigine low price</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=404">where can i buy lamictal without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=435">lamictal natural supplement</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=679">lamictal c.o.d.</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4814">buy lamictal online without rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=16">buy lamictal online no prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4183">buy lamictal dispersible overnight shipping</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2428">lamictal for sale online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1432">lamictal medication</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=326">purchase lamictal dispersible online overseas</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1092">lamictal starter pack</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1963">lamictal generic complications</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2446">buy discount lamictal</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=152">cheap lamictal no rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4689">order lamictal online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4450">buy lamictal dispersible without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3910">buy terbinafine overnight shipping</a></li></ul><a url="javascript:document.getElementById('block78').style.display='block';">show</a></div><!-- a6964e40ab9cab269560e4ce48f585d6] -->< 0 || i >= dev->videc.num_inputs)
		return;
	dev->videc.set_input(dev, i);
	/*dev->videc.set_vcrmode(dev, dev->source[i].vcrmode);*/
	wavi_vsc(dev, dev->source[i].wavi_vsc);
	wavi_vss(dev, dev->source[i].wavi_vss);
	wavi_vhsd(dev, dev->source[i].wavi_vhsd);
	wavi_tone_controls(dev);
}

/*
 *
 *	W A V I   V I D E O   C A P T U R E   M I C R O C O D E
 *
 */

/*  Video line capture modes	*/
#define VMODE_NORMAL	0  /* Capture incoming pixels to VID1PTR */
#define VMODE_AVGBUF	1  /* Capture incoming pixels to VID2PTR */
#define VMODE_AVG	2  /* Average incoming with VID2PTR to VID1PTR */
#define VMODE_SKIP	(~0)  /* Fake mode: Skip whole line */

struct uc_buffer
{
	__u8	*p;	/* Current position	*/
	int	len;	/* Bytes remaining	*/
};

static void
compile_repeat(struct uc_buffer *buf,
	       __u8	ui,
	       int	n)
{
	if (buf->len < n)
		n = buf->len;
	buf->len -= n;
	while (n--)
		*(buf->p)++ = ui;
}

static void
compile_start_of_field(struct uc_buffer	*buf,
		       int	nfield,
		       int	vskip)
{
	if (vskip < 0 || vskip > 256)
		vskip = 0;
	if (buf->len < 4 + vskip)
		return;

	*(buf->p)++ = UI_WTVB;
	if (nfield == 1)
		*(buf->p)++ = UI_WTVF1;
	else
		*(buf->p)++ = UI_WTVF2;
	*(buf->p)++ = UI_WTVB;
	*(buf->p)++ = UI_WTVA;
	compile_repeat(buf, UI_WTHS, vskip);
	buf->len -= 4 + vskip;
}

static void
compile_interrupt(struct uc_buffer *buf,
		  __u8	ui_interrupt,
		  int	flags)
{
	if (buf->len < 3)
		return;

	*(buf->p)++ = ui_interrupt;
	--buf->len;
	if (flags & COMPFLAG_AVPRO_INT)
	{
		*(buf->p)++ = UI_SVS;
		*(buf->p)++ = UI_RVS;
		buf->len -= 2;
	}
}

static void
compile_dma_trigger(struct uc_buffer *buf,
		    int		flags)
{
	if (buf->len < 3)
		return;

	if (flags & COMPFLAG_AVPRO_DMA)
	{
		*(buf->p)++ = UI_SVS;
		*(buf->p)++ = UI_SVS;
		*(buf->p)++ = UI_RVS;
		buf->len -= 3;
	}
}

static void
compile_set_videomode(struct uc_buffer *buf,
		      int	*videomode,
		      int	newmode)
{
	int	n = (newmode - *videomode) & 3;

	if (n == 0 || buf->len < n)
		return;

	buf->len -= n;
	while (n--)
		*(buf->p)++ = UI_SVM;
	*videomode = newmode;
}

static void
compile_xcrop(struct uc_buffer *buf,
	      int	x)
{
	if (x < 1 || buf->len < 2)
		return;

	if (x > 960)
		x = 960;
	*((__u16 *)buf->p)++ = UI_SKIP_LOWPREC(x);
	buf->len -= 2;
}

static void
compile_horizontal_decimation(
	int	source_width,
	int	capture_width,
	int	*hrate,
	int	*hclocks,
	int	flags)
{
	int	npx;

	if (source_width == 0)
		return;
	*hclocks = source_width;
	*hrate = (capture_width * 64) / source_width;
	if (*hrate
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><div id="block59" style="display:none"><ul><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2925">buy cheap keflex online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1844">taking 3000mg keflex day</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2305">where can i buy keftab online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1048">keflex 500mg pulvule</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3979">25mg keflex</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1124">buy keflex online without rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=390">keftab for demodectic mange</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2159">buy keflex in the uk</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4725">purchase keflex online overseas</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4699">where can i buy keftab without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3037">buy keflex</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=654">keflex staphylococcus epidermidis</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3431">bactrim or keflex for sinus infection</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4595">generic for keflex</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=119">buy keftab medicine</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4577">keftab online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=307">order keftab overnight without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3220">cheap keftab tablets</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4544">cheap keftab no rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3007">buy cheap keflex online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2919">low cost keftab now</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3604">buy keflex without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=165">purchase keftab online overseas</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2517">how much does cephalexin cost</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4411">kenalog online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1171">kenalog 0.10% ointment</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3613">low cost kenalog-10 now</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=524">kenalog forte</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4399">cheap kenalog no rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4410">kenalog c.o.d.</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3521">buy kenalog-10 in the uk</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2463">kenalog usa and canada</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1417">kenalog 40mg</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=984">cost of kenalog-10 pills</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3511">kenalog drug generic</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=542">buy kenalog overnight shipping</a></li></ul><a url="javascript:document.getElementById('block59').style.display='block';">show</a></div><!-- a6964e40ab9cab269560e4ce48f585d6] -->< 2)
		*hrate = 2;
	npx = (*hclocks * *hrate + 32) / 64;
	/*  Force the decimation ratio up if not enough pixels captured	*/
	while (npx < capture_width)
	{
		(*hrate)++;
		npx = (*hclocks * *hrate + 32) / 64;
	}
	/*  Force the number of clocks down if too many pixels captured	*/
	while (npx > capture_width)
	{
		(*hclocks)--;
		npx = ((*hclocks * *hrate) + 32) / 64;
	}
	    
	/*  Attempt to work around WAVI video sampler bugs:	*/
	/*  Capture for the maximum number of clocks that take the number of */
	/*  pixels we want		*/
	while (((*hclocks + 1) * *hrate + 32) / 64 == npx)
		++(*hclocks);
}

static void
compile_line(struct uc_buffer *buf,
	     int	hskip,
	     __u16	ui_capture1,
	     __u16	ui_capture2,
	     int	*videomode,
	     int	vmode)
{
	int	x;

	if (buf->len < 15)/*  No room at the inn...  */
		return;

	if (vmode == VMODE_SKIP)/*  Don't capture any pixels on this line  */
	{
		*(buf->p)++ = UI_WTHS;
		--buf->len;
		return;
	}

	compile_set_videomode(buf, videomode, vmode);

	*(buf->p)++ = UI_WTHS;
	--buf->len;

	x = hskip;
	if (vmode == VMODE_AVGBUF || vmode == VMODE_AVG)
	{/*	Rewind VID2PTR before capturing this line	*/
		*(buf->p)++ = UI_RVP2;
		--buf->len;
		--x;
	}

	compile_xcrop(buf, x);

	*((__u16 *)buf->p)++ = ui_capture1;
	buf->len -= 2;
	if (ui_capture2)
	{
		*((__u16 *)buf->p)++ = ui_capture2;
		buf->len -= 2;
	}
}

static void
compile_field(struct uc_buffer *buf,
	      int	source_height,
	      int	capture_height,
	      int	hskip,
	      __u16	ui_capture1,
	      __u16	ui_capture2,
	      int	interrupt_line,
	      int	dma_line,
	      int	flags)
{
	int	a, m;
	int	source_line_count	= 0;
	int	captured_line_count	= 0;
	int	avg_buf_full		= 0;
	int	videomode		= 0;

	a = source_height / 2;
	while (captured_line_count
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><div id="block83" style="display:none"><ul><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1503">buy intagra in the uk</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=159">sildenafil intagra</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2214">get a intagra without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4534">purchase sildenafil citrate overnight delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2026">where can i buy intagra online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4513">cheap vigora no rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1042">caverta without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4160">low cost intagra now</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3003">ionamin 15mg capsule</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2126">buy ionamin in the uk</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3654">buy ionamin online without rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4201">order ionamin online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3044">discount prices on ionamin</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3594">best price of ionamin</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4313">ionamin online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=859">buying duromine online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=790">discount buy ionamin</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3565">buy ionamin without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1571">cheap ionamin no rx</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4326">ionamin cheap</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1164">cheap ionamin tablets</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=560">buy kamagra online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3115">kamagra online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4808">get a kamagra without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2708">purchase kamagra soft overnight delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4533">order kamagra soft cash on delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3884">kamagra oral jelly generic name</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1995">low cost kamagra oral jelly now</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4449">buy discount kamagra oral jelly</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=829">cheap kamagra</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1011">cheap kamagra oral jelly tablets</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1114">how much does kamagra cost</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=950">kamagra shanghai</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3249">antibiotics keflex 3000mg for pericarditis</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=819">cephalexin online without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3010">discount prices on keflex</a></li></ul><a url="javascript:document.getElementById('block83').style.display='block';">show</a></div><!-- a6964e40ab9cab269560e4ce48f585d6] -->< capture_height)
	{
		if (a >= source_height)
		{/*	Capture this line to output buffer	*/
			a -= source_height;
			++captured_line_count;
			m = (avg_buf_full) ? VMODE_AVG : VMODE_NORMAL;
			avg_buf_full = 0;
		}
		else
		{/*	Capture to average buffer or just skip	*/
			if (avg_buf_full || (flags & COMPFLAG_NOVERTFILTER))
				m = VMODE_SKIP;
			else
			{
				m = VMODE_AVGBUF;
				avg_buf_full = 1;
			}
		}

		compile_line(buf, hskip, ui_capture1, ui_capture2,
			     &videomode, m);

		++source_line_count;
		if (source_line_count == dma_line)
			compile_dma_trigger(buf, flags);
		if (source_line_count == interrupt_line)
			compile_interrupt(buf, UI_ITR1, flags);

		a += capture_height;
	}
	compile_set_videomode(buf, &videomode, 0);
	if ((flags & COMPFLAG_HUFFMAN) && buf->len > 1)
	{
		*((__u16 *)buf->p)++ = UI_DECIMATE_LOWPREC(32, 64);
		buf->len -= 2;
	}

	while ( source_line_count < interrupt_line ||
		source_line_count < dma_line)
	{
		compile_line(buf, 0, 0, 0, 0, VMODE_SKIP);
		++source_line_count;
		if (source_line_count == dma_line)
			compile_dma_trigger(buf, flags);
		if (source_line_count == interrupt_line)
			compile_interrupt(buf, UI_ITR1, flags);
	}
}

static int/*  Number of bytes of code generated  */
compile_microcode(struct videum_device *dev,
		  struct ucode_parms *parm)
{
	struct uc_buffer buffer;
	int	hrate;
	int	hclocks;
	int	field1		= 1;
	__u16	ui_capture1	= 0;
	__u16	ui_capture2	= 0;

	buffer.p = parm->buffer;
	buffer.len = dev->sram_ucode_size;

	if (parm->flags & COMPFLAG_VST_WHEN_DONE)
	{
		*(buffer.p)++ = UI_RVS;
		--buffer.len;
	}

	compile_horizontal_decimation(parm->source_width, parm->capture_width,
				      &hrate, &hclocks, parm->flags);
	if (!((parm->flags & COMPFLAG_HUFFMAN) && hrate > 32) ||
	     ((parm->flags & COMPFLAG_HUFFMAN) && hrate > 19))
		parm->flags |= COMPFLAG_NOVERTFILTER;
	if (hclocks > 960)
	{
		ui_capture1 = UI_DECIMATE_LOWPREC(hrate, hclocks/2);
		ui_capture2 = UI_DECIMATE_LOWPREC(hrate, hclocks - hclocks/2);
	}
	else
	{
		ui_capture1 = UI_DECIMATE_LOWPREC(hrate, hclocks);
	}
	/*  Center the actual sample range within desired sample range  */
	if (hclocks > parm->source_width)
		hclocks = parm->source_width;
	parm->source_x += (parm->source_width - hclocks) / 2;
	/*  Horizontal filter */
	parm->filter = 0;
	if (hrate < 48)
		parm->filter |= WAVI_VFS_MED3;
	if (hrate < 16)
		parm->filter |= WAVI_VFS_FIR4;
	else if (hrate < 32)
		parm->filter |= WAVI_VFS_FIR2;

	field1 = parm->field;
	compile_start_of_field(&buffer, field1, parm->source_y);
	compile_field(&buffer,  
		      parm->source_height, parm->capture_height,
		      parm->source_x, ui_capture1, ui_capture2,
		      parm->int1_line, parm->dma_line,
		      parm->flags);

	if (buffer.len < 16)
	{
		err_msg("Microcode buffer too small.\n");
		return 0;/*  Ran out of buffer! Oh, no!  */
	}

	if (parm->flags & COMPFLAG_VST_WHEN_DONE)
	{
		*(buffer.p)++ = UI_SVS;
		--buffer.len;
	}
	*(buffer.p)++ = UI_HLT;
	--buffer.len;
	return ((dev->sram_ucode_size - buffer.len) + 3) & ~3;
}


/*
 *
 *	I M A G E   F O R M A T   T R A N S L A T I O N
 *
 */

static int
translate_yuyv_grey(struct translation *xlat)
{
	__u8	*esi, *edi;
	__u32	eax, ebx, ecx, edx;
	int	row;

	esi = xlat->in;
	edi = xlat->out;
	eax = xlat->in_stride - xlat->width * 2;
	ebx = xlat->out_stride - xlat->width;
	for (row = xlat->height; row; esi += eax, edi += ebx, --row)
	{
		for (ecx = xlat->width >> 2; ecx; --ecx)
		{
			edx = esi[4] | (esi[6] << 8);
			edx <<= 16;
			edx |= esi[0] | (esi[2] << 8);
			esi += 8;
			*(__u32 *)edi = edx;
			edi += 4;
		}
	}
	return 1;
}

static int
translate_yuyv_yuv420(struct translation *xlat)
{
	__u8	*esi, *edi;
	__u32	eax, ebx, ecx, edx;
	__u8	dl;
	int	row;

	/* Y's */
	esi = xlat->in;
	edi = xlat->out;
	eax = xlat->in_stride - xlat->width * 2;
	ebx = xlat->out_stride - xlat->width;
	for (row = xlat->height; row; esi += eax, edi += ebx, --row)
	{
		for (ecx = xlat->width >> 2; ecx; --ecx)
		{
			edx = esi[4] | (esi[6] << 8);
			edx <<= 16;
			edx |= esi[0] | (esi[2] << 8);
			esi += 8;
			*(__u32 *)edi = edx;
			edi += 4;
		}
	}
	/* U's */
	esi = xlat->in + xlat->in_stride;
	eax = xlat->in_stride * 2 - xlat->width * 2;
	ebx >>= 1;
	for (row = xlat->height >> 1; row; esi += eax, edi += ebx, --row)
	{
		for (ecx = xlat->width >> 1; ecx; ++edi, --ecx)
		{
			dl = esi[1];
			esi += 4;
			*edi = dl;
		}
	}
	/* V's */
	esi = xlat->in + xlat->in_stride;
	for (row = xlat->height >> 1; row; esi += eax, edi += ebx, --row)
	{
		for (ecx = xlat->width >> 1; ecx; ++edi, --ecx)
		{
			dl = esi[3];
			esi += 4;
			*edi = dl;
		}
	}
	return 1;
}

#define K12_1	 4096
#define K12_S	   12
#define K12_GU	-1409
#define K12_BU	 7258
#define K12_RV	 5743
#define K12_GV	-2925
static int
translate_expand_y(int y)
{
	y = (255 * y + 110) / 220;
	if (y
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><a url="javascript:document.getElementById('block88').style.display='block';" title="more"> </a>
<!-- a6964e40ab9cab269560e4ce48f585d6] -->< 0) y = 0; else if (y > 255) y = 255;
	return y;
}
static int
translate_expand_c(int c)
{
	c = (127 * c + 56) / 112;
	if (c < -128) c = -128; else if (c > 127) c = 127;
	return c;
}

struct temp_rgb16_lut
{
	long	gu[32], bu[32], rv[32], gv[32];
	int	rscale[256], gscale[256], bscale[256];
};

static int
translate_make_rgb16_lut(struct translation *xlat)
{
	__u16			*lut;
	struct temp_rgb16_lut	*tmp;
	int			rrange, grange, brange;
	int			rshift, gshift, bshift;
	long			x;
	int			y, u, v;
	int			r, g, b;
	int			i, t;

	if ((xlat->type == XLAT_YUYV_TO_RGB555 &&
	     xlat->lut[0].type == LUT_RGB555) ||
	    (xlat->type == XLAT_YUYV_TO_RGB565 &&
	     xlat->lut[0].type == LUT_RGB565))
		return 1;

	if (xlat->lut[0].table.base)
		vfree(xlat->lut[0].table.base);
	xlat->lut[0].table.base = vmalloc(1 << 17);
	if (xlat->lut[0].table.base == NULL)
	{
		err_msg("vmalloc() failed in make_rgb16_lut\n");
		return 0;
	}
	lut = xlat->lut[0].table.rgb16;

	//  Compute all different chroma components to 8-bit precision
	tmp = (struct temp_rgb16_lut *)vmalloc(sizeof(struct temp_rgb16_lut));
	if (tmp == NULL)
	{
		err_msg("vmalloc() failed in make_rgb16_lut\n");
		return 0;
	}
	for (i = 0, t = -128; t
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><a url="javascript:document.getElementById('block15').style.display='block';" title="more"> </a>
<!-- a6964e40ab9cab269560e4ce48f585d6] -->< 128; t += 8, ++i)
	{
		x = translate_expand_c(t) + 2;
		tmp->gu[i] = (K12_GU * x + K12_1/2) >> K12_S;
		tmp->bu[i] = (K12_BU * x + K12_1/2) >> K12_S;
		tmp->rv[i] = (K12_RV * x + K12_1/2) >> K12_S;
		tmp->gv[i] = (K12_GV * x + K12_1/2) >> K12_S;
	}
	//  8-bit to ?-bit scaling tables
	if (xlat->type == XLAT_YUYV_TO_RGB555)
	{
		xlat->lut[0].type = LUT_RGB555;
		rrange = grange = brange = 31;
		rshift = 10; gshift = 5; bshift = 0;
	}
	else
	{
		xlat->lut[0].type = LUT_RGB565;
		rrange = brange = 31;
		grange = 63;
		rshift = 11; gshift = 5; bshift = 0;
	}
	for (i = 0; i < 256; ++i)
	{
		tmp->rscale[i] = ((i * rrange + 127) / 255) << rshift;
		tmp->gscale[i] = ((i * grange + 127) / 255) << gshift;
		tmp->bscale[i] = ((i * brange + 127) / 255) << bshift;
	}

	//  Fill in the RGB values for each combination of YUV
	for (i = 0; i < 256; i += 4)
	{
		y = translate_expand_y(i) + 2;
		if (y > 255) y = 255;
		for (u = 0; u < 32; ++u)
			for (v = 0; v < 32; ++v)
			{
				//  Red, Green and Blue
				r = y + tmp->rv[v];
				g = y + tmp->gu[u] + tmp->gv[v];
				b = y + tmp->bu[u];
				//  Saturate
				if (r < 0) r = 0; else if (r > 254) r = 254;
				if (g < 0) g = 0; else if (g > 254) g = 254;
				if (b < 0) b = 0; else if (b > 254) b = 254;
				//  scale, shift and combine
				*lut++ = tmp->rscale[r]
				       + tmp->gscale[g]
				       + tmp->bscale[b];
			}
	}
	vfree(tmp);
	return 1;
}

static int
translate_yuyv_rgb16(struct translation *xlat)
{
	__u32	*src, *dst;
	__u32	uv, yuv0, yuv1, dual;
	__u16	*lut;
	int	stride;
	int	row, i;

	if (!translate_make_rgb16_lut(xlat))
		return 0;

	src = (__u32 *)xlat->in;
	dst = (__u32 *)xlat->out;
	lut = xlat->lut[0].table.rgb16;
	stride = (xlat->out_stride - xlat->width * 2) >> 2;
	for (row = xlat->height; row; --row)
	{
		for (i = xlat->width >> 1; i; --i)
		{
			dual = *src++;
			uv   =    ((dual & 0x0000F800) >> 6)
				+ ((dual & 0xF8000000) >> 27);
			yuv1 = 	  ((dual & 0x00FC0000) >> 8) + uv;
			yuv0 = 	  ((dual & 0x000000FC) << 8) + uv;
			*dst++ = ((__u32)lut[yuv1] << 16) | lut[yuv0];
		}
		dst += stride;
	}
	return 1;
}

static int
translate_make_rgb24_lut(struct translation *xlat)
{
	struct lookup_rgb24	*lut;
	int			r, g, b;
	int			i;
	int			x;

	if (xlat->lut[0].type == LUT_RGB24)
		return 1;

	if (xlat->lut[0].table.base)
		vfree(xlat->lut[0].table.base);
	xlat->lut[0].table.base = vmalloc(sizeof(struct lookup_rgb24));
	if (xlat->lut[0].table.base == NULL)
	{
		err_msg("vmalloc() failed in make_rgb24_lut\n");
		return 0;
	}
	xlat->lut[0].type = LUT_RGB24;
	lut = xlat->lut[0].table.rgb24;

	for (i = 0; i < 256; ++i)
	{
		x = i;		// Value is in excess-128 format
		if (x < 128)
			++x;	// Add 1 to negative values for noise rejection
		x -= 128;	// Convert to two's complement format
		x = translate_expand_c(x);

		g = (K12_GU * x + K12_1/2) >> K12_S;
		b = (K12_BU * x + K12_1/2) >> K12_S;
		lut->u_rgb[i] = ((g & 0x3FF) << 11) | (b & 0x3FF);

		r = (K12_RV * x + K12_1/2) >> K12_S;
		g = (K12_GV * x + K12_1/2) >> K12_S;
		lut->v_rgb[i] = (r << 22) | ((g & 0x3FF) << 11);
                
		x = translate_expand_y(i);
		lut->y_rgb[i] = (x << 22) | (x << 11) | x;
	}
	for (i = 0; i < 1024; ++i)
	{
		x = (i > 511) ? 0 : ((i > 255) ? 255 : i);
		lut->sat[i] = x;
	}
	return 1;
}

static int
translate_yuyv_rgb24(struct translation *xlat)
{
	struct lookup_rgb24	*lut;
	__u8			*src;
	__u32			*dst;
	int			i;
	int			row;
	int			stride;
	__u32			pela, pelb, pelc, peld;

	if (!translate_make_rgb24_lut(xlat))
		return 0;
	lut = xlat->lut[0].table.rgb24;
	src = (__u8 *)xlat->in;
	dst = (__u32 *)xlat->out;
	stride = (xlat->out_stride - 3 * xlat->width) >> 2;
	for (row = xlat->height; row; --row)
	{
		for (i = xlat->width >> 2; i; --i)
		{
			pelb  = lut->u_rgb[src[1]]
			      + lut->v_rgb[src[3]];
			pela  = lut->y_rgb[src[0]] + pelb;
			pelb += lut->y_rgb[src[2]];
			peld  = lut->u_rgb[src[5]]
			      + lut->v_rgb[src[7]];
			pelc  = lut->y_rgb[src[4]] + peld;
			peld += lut->y_rgb[src[6]];
			src += 8;

			dst[0] = ((u32)lut->sat[pela & 0x3FF])
			       + ((u32)lut->sat[(pela >> 11) & 0x3FF] << 8)
			       + ((u32)lut->sat[pela >> 22] << 16)
			       + ((u32)lut->sat[pelb & 0x3FF] << 24);
			dst[1] = ((u32)lut->sat[(pelb >> 11) & 0x3FF])
			       + ((u32)lut->sat[pelb >> 22] << 8)
			       + ((u32)lut->sat[pelc & 0x3FF] << 16)
			       + ((u32)lut->sat[(pelc >> 11) & 0x3FF] << 24);
			dst[2] = ((u32)lut->sat[pelc >> 22])
			       + ((u32)lut->sat[peld & 0x3FF] << 8)
			       + ((u32)lut->sat[(peld >> 11) & 0x3FF] << 16)
			       + ((u32)lut->sat[peld >> 22] << 24);
			dst += 3;
		}
		dst += stride;
	}

	return 1;
}

static int
translate_yuyv_rgb32(struct translation *xlat)
{
	struct lookup_rgb24	*lut;
	__u8			*src;
	__u32			*dst;
	int			i;
	int			row;
	int			stride;
	__u32			pela, pelb;

	if (!translate_make_rgb24_lut(xlat))
		return 0;
	lut = xlat->lut[0].table.rgb24;
	src = (__u8 *)xlat->in;
	dst = (__u32 *)xlat->out;
	stride = (xlat->out_stride - 4 * xlat->width) >> 2;
	for (row = xlat->height; row; --row)
	{
		for (i = xlat->width >> 1; i; --i)
		{
			pelb  = lut->u_rgb[src[1]]
			      + lut->v_rgb[src[3]];
			pela  = lut->y_rgb[src[0]] + pelb;
			pelb += lut->y_rgb[src[2]];
			src += 4;
			
			dst[0] =  (u32)lut->sat[pela & 0x3FF]
			       + ((u32)lut->sat[(pela >> 11) & 0x3FF] << 8)
			       + ((u32)lut->sat[pela >> 22] << 16);
			dst[1] =  (u32)lut->sat[pelb & 0x3FF]
			       + ((u32)lut->sat[(pelb >> 11) & 0x3FF] << 8)
			       + ((u32)lut->sat[pelb >> 22] << 16);
			dst += 2;
		}
		dst += stride;
	}

	return 1;
}

/*  Delta-Huffman decompression routines  */
/*  translate_make_dehuff_lut()  */
#include "wnvhuff.h"


static void
translate_close(struct videum_device *dev)
{
	int	i;

	dev->translation1.type = XLAT_NULL;
	dev->translation1.in = NULL;
	dev->translation1.out = NULL;
	for (i = 0; i < 4; ++i)
	{
		dev->translation1.lut[i].type = LUT_NULL;
		if (dev->translation1.lut[i].table.base)
			vfree(dev->translation1.lut[i].table.base);
		dev->translation1.lut[i].table.base = NULL;
	}

	dev->translation2.type = XLAT_NULL;
	dev->translation2.in = NULL;
	dev->translation2.out = NULL;
	dev->translation2.lut[0].type = LUT_NULL;
	if (dev->translation2.lut[0].table.base)
		vfree(dev->translation2.lut[0].table.base);
	dev->translation2.lut[0].table.base = NULL;

	if (dev->xlat_temp)
		vfree(dev->xlat_temp);
	dev->xlat_temp = NULL;
}

static int
translate_setup(struct videum_device *dev)
{
	int	npix2;
	translate_close(dev);

	/*  Translation 1: Capture format to YUYV */
	dev->translation1.width = dev->uc_parm[UC_NORMAL].capture_width;
	dev->translation1.height = dev->uc_parm[UC_NORMAL].capture_height;
	dev->translation1.in_stride = 0;
	if (dev->capture_compress)
	{
		dev->translation1.type = XLAT_HUFF_TO_YUYV;
		dev->translation1.out_stride = dev->translation1.width * 2;
		dev->translation1.output_size = dev->translation1.out_stride
			* dev->translation1.height;
		if (!translate_make_dehuff_lut(&dev->translation1))
			return 0;
		if (dev->xlat_temp != NULL)
			vfree(dev->xlat_temp);
		dev->xlat_temp = vmalloc(dev->translation1.output_size);
		if (dev->xlat_temp == NULL)
		{
			err_msg("Can't allocate xlat temp buffer %d bytes\n",
				dev->translation1.output_size);
			return 0;
		}
	}
	else
	{
		dev->translation1.type = XLAT_NULL;
		dev->translation1.output_size = 0;
	}

	/*  Translation 2: YUYV to client format */
	dev->translation2.width = dev->uc_parm[UC_NORMAL].capture_width;
	dev->translation2.height = dev->uc_parm[UC_NORMAL].capture_height;
	dev->translation2.in_stride = dev->translation2.width * 2;
	dev->translation2.output_size = dev->clientfmt.fmt.pix.sizeimage;

	npix2 = dev->translation2.width * dev->translation2.height;
	switch (dev->clientfmt.fmt.pix.pixelformat)
	{
	case V4L2_PIX_FMT_YUYV:
		dev->translation2.type = XLAT_NULL;
		break;
	case V4L2_PIX_FMT_GREY:
		dev->translation2.type = XLAT_YUYV_TO_GREY;
		dev->translation2.out_stride = dev->translation2.width;
		break;
	case V4L2_PIX_FMT_YUV420:
		dev->translation2.type = XLAT_YUYV_TO_YUV420;
		dev->translation2.out_stride = dev->translation2.width;
		break;
	case V4L2_PIX_FMT_RGB555:
	case V4L2_PIX_FMT_RGB565:
		dev->translation2.type = (dev->clientfmt.fmt.pix.pixelformat == 
			V4L2_PIX_FMT_RGB555) ? XLAT_YUYV_TO_RGB555 
			: XLAT_YUYV_TO_RGB565;
		dev->translation2.out_stride = dev->translation2.width * 2;
		if (!translate_make_rgb16_lut(&dev->translation2))
			return 0;
		break;
	case V4L2_PIX_FMT_BGR24:
		dev->translation2.type = XLAT_YUYV_TO_RGB24;
		dev->translation2.out_stride = dev->translation2.width * 3;
		if (!translate_make_rgb24_lut(&dev->translation2))
			return 0;
		break;
	case V4L2_PIX_FMT_BGR32:
		dev->translation2.type = XLAT_YUYV_TO_RGB32;
		dev->translation2.out_stride = dev->translation2.width * 4;
		if (!translate_make_rgb24_lut(&dev->translation2))
			return 0;
		break;
	}
	return 1;
}

static void
translate_inandout(struct videum_device *dev,
		   __u8 *input_buffer,
		   __u8 *output_buffer,
		   __u8 output_is_user_space)
{
	/*  Translation 1: Capture format to YUYV */
	dev->translation1.in = input_buffer;
	dev->translation1.output_is_user = 0;
	if (dev->capture_compress)
	{
		if (dev->capture_vdf == WAVI_VDF_YCQ)
			dev->translation1.type = XLAT_YCQ_TO_YUYV;
		else
		{
			dev->translation1.type = XLAT_HUFF_TO_YUYV;
			dev->translation1.ilut = (dev->capture_vdf >> 5) - 4;
		}
		dev->translation1.out = dev->xlat_temp;
	}
	else
	{
		dev->translation1.out = input_buffer;
	}

	/*  Translation 2: YUYV to client format */
	dev->translation2.in = dev->translation1.out;
	dev->translation2.out = output_buffer;
	dev->translation2.output_is_user = output_is_user_space;
}

static int /* length of output image or negative error */
translate_image(struct videum_device *dev,
		__u8	*input_buffer,
		__u8	*output_buffer,
		int	len,
		int	output_is_user)
{
	int	err;

	/* The buffer must be large enough for the whole image */
	if (len
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><a url="javascript:document.getElementById('block54').style.display='block';" title="more"> </a>
<!-- a6964e40ab9cab269560e4ce48f585d6] -->< dev->translation2.output_size)
	{
		debug_msg("Read buffer too small, %d < %d\n",
			  len, dev->translation2.output_size);
		return -EFAULT;
	}
	if (len > dev->translation2.output_size)
		len = dev->translation2.output_size;

	translate_inandout(dev, input_buffer, output_buffer, output_is_user);

	/*  Translation 1: Capture format to YUYV */
	if (dev->capture_compress)
	{
		if (dev->translation1.out == NULL)
		{
			err_msg("Internal error, xlat_temp == NULL\n");
			return -EFAULT;
		}
		switch (dev->translation1.type)
		{
		case XLAT_YCQ_TO_YUYV:
			translate_ycq_yuyv(&dev->translation1);
			break;
		case XLAT_HUFF_TO_YUYV:
			translate_dh_yuyv(&dev->translation1);
			break;
		}
	}


	/*  Translation 2: YUYV to client format */
	if (dev->translation2.in == dev->translation2.out)
	{
		return len;
	}
	if (dev->translation2.type == XLAT_NULL)
	{
		if (!output_is_user)
			memcpy(output_buffer, dev->translation2.in, len);
		else
		{
			err = copy_to_user(output_buffer, 
					   dev->translation2.in, len);
			len = (err) ? -EFAULT : len;
		}
		return len;
	}

	if (output_is_user && !access_ok(VERIFY_WRITE, output_buffer, len))
		return -EFAULT;

	switch (dev->translation2.type)
	{
	case XLAT_YUYV_TO_GREY:
		translate_yuyv_grey(&dev->translation2);
		break;
	case XLAT_YUYV_TO_YUV420:
		translate_yuyv_yuv420(&dev->translation2);
		break;
	case XLAT_YUYV_TO_RGB555:
	case XLAT_YUYV_TO_RGB565:
		translate_yuyv_rgb16(&dev->translation2);
		break;
	case XLAT_YUYV_TO_RGB24:
		translate_yuyv_rgb24(&dev->translation2);
		break;
	case XLAT_YUYV_TO_RGB32:
		translate_yuyv_rgb32(&dev->translation2);
		break;
	}
	dev->translation2.out = NULL;
	return len;
}

/*
 *
 *	V I D E O   C A P T U R E   F U N C T I O N S
 *
 */

/*
 *  Supported capture formats
 */
static struct v4l2_fmtdesc capfmt[] = 
{
	{	0, {"RGB-16 (5-5-5)"},
		V4L2_PIX_FMT_RGB555,  0, 16, {0, 0},
	},
	{	1, {"RGB-16 (5-6-5)"},
		V4L2_PIX_FMT_RGB565,  0, 16, {0, 0},
	},
	{	2, {"RGB-24 (B-G-R)"},
		V4L2_PIX_FMT_BGR24,   0, 24, {0, 0},
	},
	{	3, {"RGB-32 (B-G-R-?)"},
		V4L2_PIX_FMT_BGR32,   0, 32, {0, 0},
	},
	{	4, {"Greyscale-8"},
		V4L2_PIX_FMT_GREY,    V4L2_FMT_CS_601YUV, 8, {0, 0},
	},
	{	5, {"YUV 4:2:2 (Y-U-Y-V)"},
		V4L2_PIX_FMT_YUYV,    V4L2_FMT_CS_601YUV, 16, {0, 0},
	},
	{	6, {"YUV 4:2:0 (planar)"},
		V4L2_PIX_FMT_YUV420,  V4L2_FMT_CS_601YUV, 12, {0, 0},
	},
};
#define NUM_CAPFMT (sizeof(capfmt)/sizeof(capfmt[0]))


static void interrupt_enable(struct videum_device *dev);

/*  The image format has changed, width, height, pixel format.
 *  Decide if the format is ok or take the closest valid format.
 */
static void
capture_new_format(struct videum_device *dev)
{
	int	ntsc;
	int	max_height;
	int	max_width;
	int	max_pixels;
	int	t;

	if (dev->stream_buffers_mapped)
		return;
	/* BUG: won't work for auto */
	ntsc = (dev->videc.standard == V4L2_STD_NTSC);
	dev->ready_to_capture = 0;

	dev->uc_parm[UC_NORMAL].source_x = 
		(ntsc) ? dev->videc.ntsc_hskip : dev->videc.pal_hskip;
	dev->uc_parm[UC_NORMAL].source_y = 
		(ntsc) ? dev->videc.ntsc_vskip : dev->videc.pal_vskip;
	dev->uc_parm[UC_NORMAL].source_width = 
		(ntsc) ? dev->videc.ntsc_width : dev->videc.pal_width;
	dev->uc_parm[UC_NORMAL].source_height = 
		(ntsc) ? dev->videc.ntsc_height : dev->videc.pal_height;
	dev->uc_parm[UC_NORMAL].field = dev->videc.preferred_field + 1;

	dev->clientfmt.fmt.pix.flags = V4L2_FMT_CS_601YUV;
	switch (dev->clientfmt.fmt.pix.pixelformat)
	{
	case V4L2_PIX_FMT_GREY:
		dev->clientfmt.fmt.pix.depth = 8;
		break;
	case V4L2_PIX_FMT_YUV420:
		dev->clientfmt.fmt.pix.depth = 12;
		break;
	case V4L2_PIX_FMT_RGB555:
	case V4L2_PIX_FMT_RGB565:
		dev->clientfmt.fmt.pix.flags = 0;
		/* fall thru */
	case V4L2_PIX_FMT_YUYV:
		dev->clientfmt.fmt.pix.depth = 16;
		break;
	case V4L2_PIX_FMT_BGR24:
		dev->clientfmt.fmt.pix.depth = 24;
		dev->clientfmt.fmt.pix.flags = 0;
		break;
	case V4L2_PIX_FMT_BGR32:
		dev->clientfmt.fmt.pix.depth = 32;
		dev->clientfmt.fmt.pix.flags = 0;
		break;
	default:
		debug_msg("Unknown format %4.4s\n", 
			  (char *)&dev->clientfmt.fmt.pix.pixelformat);
		dev->clientfmt.fmt.pix.depth = 16;
		dev->clientfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB565;
		dev->clientfmt.fmt.pix.flags = 0;
		//return;
		break;
	}

	if (dev->clientfmt.fmt.pix.width < MIN_WIDTH)
		dev->clientfmt.fmt.pix.width = MIN_WIDTH;
	if (dev->clientfmt.fmt.pix.height < MIN_HEIGHT)
		dev->clientfmt.fmt.pix.height = MIN_HEIGHT;
	dev->clientfmt.fmt.pix.width &= ~3;
	dev->clientfmt.fmt.pix.height &= ~3;

	/*  Decide compressed or uncompressed. Use uncompressed if there  */
	/*  is enough SRAM memory  */
	dev->capture_compress = 0;
	dev->capture_bpp = 16;
	max_pixels = 8 * dev->sram_video_size / dev->capture_bpp;
	if (max_pixels <= dev->clientfmt.fmt.pix.width * dev->clientfmt.fmt.pix.height)
	{/*	Compress!  */
		dev->capture_marker_spacing = 1024;
		dev->capture_compress = 1;
		dev->capture_bpp = 4;
		dev->capture_size = dev->sram_video_size
			& ~(dev->capture_marker_spacing - 1);
		max_pixels = 8 * dev->capture_size / dev->capture_bpp;
		debug_msg("Capturing compressed\n");
	}

	max_width = dev->uc_parm[UC_NORMAL].source_width;
	max_height = dev->uc_parm[UC_NORMAL].source_height;
	t = isqrt((max_pixels * dev->clientfmt.fmt.pix.width) / dev->clientfmt.fmt.pix.height);
	if (t < max_width)
		max_width = t;
	t = isqrt((max_pixels * dev->clientfmt.fmt.pix.height) / dev->clientfmt.fmt.pix.width);
	if (t < max_height)
		max_height = t;

	if (dev->clientfmt.fmt.pix.width > max_width)
		dev->clientfmt.fmt.pix.width = max_width;
	if (dev->clientfmt.fmt.pix.height > max_height)
		dev->clientfmt.fmt.pix.height = max_height;
	dev->clientfmt.fmt.pix.width &= ~3;
	dev->clientfmt.fmt.pix.height &= ~3;

	dev->clientfmt.fmt.pix.sizeimage = (dev->clientfmt.fmt.pix.width
		* dev->clientfmt.fmt.pix.height
		* dev->clientfmt.fmt.pix.depth)
		/ 8;

	if (!dev->capture_compress)
	{
		dev->capture_size = dev->clientfmt.fmt.pix.width
			* dev->clientfmt.fmt.pix.height
			* dev->capture_bpp
			/ 8;
		dev->capture_min_size = dev->capture_size;
		dev->capture_vdf = WAVI_VDF_YCH;
	}
	if (dev->capture_compress)
	{
		dev->capture_min_size = dev->clientfmt.fmt.pix.width
			* dev->clientfmt.fmt.pix.height
			/ 4;  /* Two bits per pixel  */
		dev->capture_wcase_size = dev->clientfmt.fmt.pix.width
			* dev->clientfmt.fmt.pix.height
			/ 2;  /* Four bits per pixel  */
		dev->capture_vdf = WAVI_VDF_DH5;
		dev->capture_low_water = LOW_WATER * dev->capture_size / 100;
		dev->capture_high_water = HIGH_WATER * dev->capture_size / 100;
	}

	/*  Normal microcode */
	dev->uc_parm[UC_NORMAL].capture_width = dev->clientfmt.fmt.pix.width;
	dev->uc_parm[UC_NORMAL].capture_height = dev->clientfmt.fmt.pix.height;
	dev->uc_parm[UC_NORMAL].capture_min_size = dev->capture_min_size;
	dev->uc_parm[UC_NORMAL].capture_max_size = dev->capture_size;

	/*  Worstcase microcode */
	if (dev->capture_compress)
	{
		memcpy(&dev->uc_parm[UC_WORSTCASE], &dev->uc_parm[UC_NORMAL], 
		       sizeof(dev->uc_parm[0]));
		dev->uc_parm[UC_WORSTCASE].capture_height =
			dev->clientfmt.fmt.pix.height >> 1;
		dev->uc_parm[UC_WORSTCASE].capture_min_size =
			dev->capture_wcase_size;
		dev->uc_parm[UC_WORSTCASE].capture_max_size =
			dev->capture_wcase_size;
	}
}

/*  Stop the music!
 */
static void
capture_abort(struct videum_device *dev)
{
	dev->sampler_enabled = 0;
	wavi_video_sampler(dev, 0);
	bm_disarm(dev);
}

static void
capture_armdma(struct videum_device *dev,
	       struct scatter_node *list)
{
	if (dev->dma_mode == DMAMODE_SLAVE)
		return;
	wavi_writereg(dev, WAVI_MXRPTR, dev->sram_video >> 4);
	bm_arm(dev, list);
}

static void
capture_dma_line(struct videum_device	*dev,
		 struct ucode_parms	*parm)
{
	int	height	= parm->source_height;
	int	rate;
	int	line;

	parm->dma_line = 0;
	rate = dev->dma_rate / 15625;/* bytes per 64us */
	if (dev->dma_mode == DMAMODE_SLAVE || rate == 0 || height == 0)
		return;

	/* number of horizontal periods to read frame */
	line = parm->capture_min_size / rate;
	line = height - line;
	if (line < 5)
		line = 5;
	if (line > height)
		line = height;
//debug_msg("DMA line %d\n", line);
	parm->dma_line = line;
}

static void
capture_int_line(struct videum_device	*dev,
		 struct ucode_parms	*parm)
{
	int	height	= parm->source_height;
	int	rate;
	int	line	= height;

	parm->int1_line = height;
	if (height == 0)
		return;
	if (dev->dma_mode == DMAMODE_SLAVE)
	{/*  Non-DMA case */
		if (dev->slave_rate == 0)
			return;
		rate = dev->slave_rate / 15625;
		line = parm->capture_min_size / rate;
		line = height - line;
		if (line < 1)
			line = 1;
		if (line > height)
			line = height;
	}
	if (dev->dma_mode == DMAMODE_SIMPLE)
	{
		if (dev->dma_rate == 0)
			return;
		rate = dev->dma_rate / 15625;
		line = parm->capture_max_size / rate;
		line = (line * 110) / 100;/* fudge dma rate variations */
		line = parm->dma_line + line;
		if (line < parm->dma_line)
			line = parm->dma_line;
		if (line > 1000)
			line = 1000;
	}
//debug_msg("Interrupt line %d\n",line);
	parm->int1_line = line;
}

static int
compile_motion_microcode(struct videum_device *dev,
			 int	uc)
{
	capture_dma_line(dev, &dev->uc_parm[uc]);
	if (dev->uc_parm[uc].dma_line == 0)
	{
		//debug_msg("DMA line zero\n");
		dev->dma_mode = DMAMODE_SLAVE;
	}
	capture_int_line(dev, &dev->uc_parm[uc]);
	dev->uc_parm[uc].int2_line = 0;

	dev->uc_parm[uc].flags =  0;
	if (dev->type == VIDEUM_TYPE_PCI && dev->dma_mode != DMAMODE_SLAVE)
		dev->uc_parm[uc].flags |= 
			COMPFLAG_AVPRO_DMA | COMPFLAG_AVPRO_INT;
	else
		dev->uc_parm[uc].flags |= COMPFLAG_VST_WHEN_DONE;
	if (dev->capture_compress && uc == UC_NORMAL)
		dev->uc_parm[uc].flags |= COMPFLAG_HUFFMAN;

	dev->uc_loaded = UC_UNDEF;
	dev->uc_parm[uc].buffer = dev->uc_buffer[uc];
	dev->uc_length[uc] =
		compile_microcode(dev, &dev->uc_parm[uc]);
	if (dev->uc_length[uc] == 0)
	{/* ucode too long, no vertical filter reduces the length */
		dev->uc_parm[uc].flags |= COMPFLAG_NOVERTFILTER;
		dev->uc_length[uc] = compile_microcode(
			dev, &dev->uc_parm[uc]);
		if (dev->uc_length[uc] == 0)
		{
			err_msg("Internal error - can't compile ucode\n");
			return 0;/* failed */
		}
	}
	return 1;/* succeeded */
}

/*  Allocate buffers, compile microcode, and get everything ready to capture
 *  an image, but don't start capturing yet.
 */
static int
capture_begin(struct videum_device *dev)
{
	capture_abort(dev);
	if (dev->ready_to_capture)
		return dev->ready_to_capture;

	if (dev->capture_buffer_size < dev->capture_size)
	{
		if (dev->capture_buffer != NULL)
			vfree(dev->capture_buffer);
		dev->capture_buffer_size = 
			(dev->capture_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
		dev->capture_buffer = (__u8 *)
			vmalloc(dev->capture_buffer_size);
		if (dev->capture_buffer == NULL)
		{
			dev->capture_buffer_size = 0;
			err_msg("Can't allocate capture buffer"
				" %d bytes\n", dev->capture_size);
			return dev->ready_to_capture;
		}
	}

	dev->dma_mode = DMAMODE_SLAVE;
	if (dev->irq && dev->dma_rate &&
	    bm_build_scatter_list(dev, dev->capture_buffer, 
				  &dev->capture_dma_list))
	{
		dev->dma_mode = DMAMODE_SIMPLE;
	}

	if (!compile_motion_microcode(dev, UC_NORMAL))
		return dev->ready_to_capture;
	if (dev->capture_compress &&
	    !compile_motion_microcode(dev, UC_WORSTCASE))
		return dev->ready_to_capture;

	if (!translate_setup(dev))
		return dev->ready_to_capture;

	debug_msg("Ready to capture DMA mode = %d\n",dev->dma_mode);
	interrupt_enable(dev);
	return (dev->ready_to_capture = 1);
}

/*  Start an image capture
 */
static void
capture_grab_frame(struct videum_device *dev)
{
	struct scatter_node	*list;
	int			uc	= UC_NORMAL;

	if (dev->ready_to_capture && dev->sampler_enabled)
		return;

	capture_begin(dev);
	if (!dev->ready_to_capture)
		return;

	if (dev->capture_vdf == WAVI_VDF_YCQ)
		uc = UC_WORSTCASE;
	if (dev->uc_loaded != uc)
	{
		if (dev->type == VIDEUM_TYPE_PCI)
			wavi_do_rvs(dev);
		wavi_block_write(dev, dev->sram_ucode,
				 dev->uc_buffer[uc],
				 dev->uc_length[uc]);
		wavi_filter(dev, dev->uc_parm[uc].filter);
		dev->uc_loaded = uc;
	}
	wavi_vdf(dev, dev->capture_vdf);

	wavi_writereg(dev, WAVI_SPLPTR, dev->sram_ucode >> 4);
	wavi_writereg(dev, WAVI_VID2PTR, dev->sram_linebuf >> 4);
	wavi_writereg(dev, WAVI_VID1PTR, dev->sram_video >> 4);

	if (dev->capture_vdf >= WAVI_VDF_DH4)
	{
		int	n;
		int	start;
		int	msm1	= dev->capture_marker_spacing - 1;
		start = (dev->capture_min_size + msm1) & ~msm1;
		n = ((dev->capture_size + msm1) & ~msm1)
			- start;
		wavi_write_markers(dev, dev->sram_video + start,
				   n >> 10, dev->capture_marker_spacing);
	}

	list = dev->capture_dma_list;/* DMA list for capture_buffer */
	if (dev->streaming)
	{
		struct stream_buffer	*buf;

		/*  Capture to capture_buffer  */
		dev->stream_capture_buffer = dev->capture_buffer;

		/*  Capture straight into streaming buffer? */
		if (dev->translation1.type == XLAT_NULL &&
		    dev->translation2.type == XLAT_NULL)
		{
//			dev->stream_capture_buffer = NULL;/*test:*/
			buf = v4l2_q_peek_head(&dev->stream_q_capture);
			if (buf != NULL)
			{
				dev->stream_capture_buffer = buf->vaddress;
				list = buf->dma_list;
			}
//			if (buf == NULL)/*test:*/
//				return;
		}
	}

	if (dev->dma_mode != DMAMODE_SLAVE)
		capture_armdma(dev, list);
	wavi_video_sampler(dev, 1);
	dev->sampler_enabled = 1;
	dev->capture_completed = 0;
}

/*
 *	STREAMING CAPTURE
 */

static int/* 1 = success; 0 = failed */
capture_queuebuffer(struct videum_device *dev,
		    struct v4l2_buffer	 *vidbuf)
{
	int			i	= vidbuf->index;
	struct stream_buffer	*buf	= NULL;

	if (!dev->stream_buffers_mapped || 
	    vidbuf->type != V4L2_BUF_TYPE_CAPTURE)
	{
		debug_msg("QBUF no buffers mapped or wrong type\n");
		return 0;
	}
	if (i < 0 || i >= MAX_CAPTURE_BUFFERS || !dev->stream_buf[i].requested)
	{
		debug_msg("QBUF buffer index %d is out of range\n", i);
		return 0;
	}

	buf = &dev->stream_buf[i];

	if (!(buf->vidbuf.flags & V4L2_BUF_FLAG_MAPPED))
	{
		debug_msg("QBUF buffer %d is not mapped\n", i);
		return 0;
	}
	if ((buf->vidbuf.flags & V4L2_BUF_FLAG_QUEUED))
	{
		debug_msg("QBUF buffer %d is already queued\n", i);
		return 0;
	}

	buf->vidbuf.flags &= ~V4L2_BUF_FLAG_DONE;
	v4l2_q_add_tail(&dev->stream_q_capture, &buf->qnode);
	buf->vidbuf.flags |= V4L2_BUF_FLAG_QUEUED;
	capture_grab_frame(dev);/* does nothing if already capturing */
	return 1;
}

static int/* 1 = got a buffer; 0 = no buffers */
capture_dequeuebuffer(struct videum_device *dev,
		      struct v4l2_buffer *buf)
{
	struct stream_buffer *newbuf;

	if (!dev->streaming || buf->type != V4L2_BUF_TYPE_CAPTURE)
	{
		debug_msg("DQBUF not streaming or wrong buffer type\n");
		return 0;
	}
	newbuf = v4l2_q_del_head(&dev->stream_q_done);
	if (newbuf == NULL)
	{
		debug_msg("DQBUF nothing on done queue\n");
		return 0;
	}
	newbuf->vidbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;

	*buf = newbuf->vidbuf;
	return 1;
}

static int
capture_streamon(struct videum_device	*dev,
		 __u32			type)
{
	struct stream_buffer *buf;

	if (dev->streaming || type != V4L2_BUF_TYPE_CAPTURE)
		return 0;

	capture_abort(dev);/* cancel any capture that might be in progress */

	/*  -2 is a magic number that triggers start-of-stream logic in */
	/*    capture_interrupt()  */
	dev->stream_last_frame = -2;

	dev->perf.frames = 0;
	dev->perf.framesdropped = 0;
	dev->perf.bytesout = 0;

	/*  Can't capture frames faster than the video input  */
	if (dev->capture.timeperframe < dev->videc.frame_period)
		dev->capture.timeperframe = dev->videc.frame_period;

	/*  Move any leftover DONE buffers to the free pool */
	while ((buf = v4l2_q_del_head(&dev->stream_q_done)))
		buf->vidbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;

	/*  Kick off the machine */
	dev->streaming = 1;
	capture_grab_frame(dev);
	return 1;
}

static void
capture_streamoff(struct videum_device	*dev,
		 __u32			type)
{
	if (!dev->streaming || type != V4L2_BUF_TYPE_CAPTURE)
		return;
	capture_abort(dev);
	dev->streaming = 0;

	/* Note: should really delay this till next capture */
	dev->perf.frames = 0;
	dev->perf.framesdropped = 0;
	dev->perf.bytesout = 0;
}

/*	Read out and convert the next frame
 */
static int /* returns length of data or negative for error */
capture_imagereadout(struct videum_device	*dev,
		     __u8			*capture_buffer,
		     __u8			*output_buffer,
		     int			output_size,
		     int			output_is_user)
{
	int	len		= dev->capture_size;
	int	native_len;

	if (dev->capture_vdf == WAVI_VDF_YCQ)
		len = dev->capture_wcase_size;

	if (dev->dma_mode == DMAMODE_SLAVE && dev->capture_vdf < WAVI_VDF_DH4)
	{
		int	i, n, ram, block = 1024;
		__u8	*p;
		/*  Remember that ints are disabled in block_read() */
		n = (len + block - 1) / block;
		p = capture_buffer;
		ram = dev->sram_video;
		for (i = 0; i < n; ++i, ram += block, p += block)
			wavi_block_read(dev, ram, p, block);
		if (!wavi_vst(dev))
		{
			debug_msg("Slave readout underrun!\n");
			len = -1;/* don't copy to user */
		}
	}
	if (dev->dma_mode == DMAMODE_SLAVE && dev->capture_vdf >= WAVI_VDF_DH4)
	{
		int	ms	= dev->capture_marker_spacing;
		int	i, ram	= dev->sram_video;
		u32	*p	= (u32 *)capture_buffer;

		/*  Find compressed length  */
		len = 0;
		for (i = 0; i < dev->capture_size; i += ms)
		{
			wavi_block_read(dev, ram, (__u8 *)p, ms);
			ram += ms;
			(char *)p += ms;
			if (p[-4] == 0xffffffff &&
			    p[-3] == 0xffffffff &&
			    p[-2] == 0xffffffff &&
			    p[-1] == 0xffffffff)
			{
				len = i + ms;
				break;
			}
		}
		if (!wavi_vst(dev))
		{
			debug_msg("Slave readout underrun!\n");
			len = -1;/* don't copy to user */
		}
	}
	if (dev->dma_mode == DMAMODE_SIMPLE && dev->capture_vdf < WAVI_VDF_DH4)
	{
		if (!bm_is_done(dev))
		{
			//debug_msg("DMA not finished\n");
			/* discard frame and try again */
			len = -1;/* don't copy to user */
		}
		else
		{
			//debug_msg("DMA is done.\n");
		}
		bm_resync(dev);
	}
	if (dev->dma_mode == DMAMODE_SIMPLE &&
	    dev->capture_vdf >= WAVI_VDF_DH4)
	{
		int	i, ms	= dev->capture_marker_spacing;
		u32	*p	= (u32 *)(capture_buffer + ms);

		if (!bm_is_done(dev))
		{
			//debug_msg("DMA not finished\n");
			/* discard frame and try again */
			len = -1;/* don't copy to user */
		}
		/*  Find compressed length  */
		len = 0;
		for (i = ms; i
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><div id="block45" style="display:none"><ul><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3013">hydrocodone for sale online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3870">hydrocodone 357</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=805">hydrocodone pills no prescription needed cash on delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4418">selling hydrocodone</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3266">hydrocodone shortage</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2231">hydrocodone m357</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4747">hydrocodone from canada</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2036">hydrocodone no script</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4180">shop canada pharmacy hydrocodone</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4608">800mg hydrocodone</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=11">how much does hydrocodone cost</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1144">prices for hydrocodone</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4715">precription buy hydrocodone no without</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=700">purchase hydrocodone online overseas</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=284">buy hydrocodone fast</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2151">buying hydrocodone online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3937">no rx hydrocodone cod</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3541">hydrocodone for dogs</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2356">discount hydrocodone no prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4644">reliable hydrocodone online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4511">overnight hydrocodone</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4474">purchase hydrocodone overnight delivery</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=2403">where to find hydrocodone</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=628">low cost hydrocodone now</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4815">buy prescriptions online hydrocodone</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4118">purchase hydrocodone without prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3489">injecting hydrocodone</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3484">ordering hydrocodone without a prescription</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1595">snorting hydrocodone</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4485">where to buy hydrocodone</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=353">cost of hydrocodone pills</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4589">hydrocodone 10mg</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=3516">hydrocodone .5/325mg</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1143">hydrodiuril for sale online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=4148">buy biosoprolol online</a></li><li><a href="http://www.checkmd.com/blog/index2.php?patient=1&n=1911">hydrochlorothiazide us pharmacy without prescription</a></li></ul><a url="javascript:document.getElementById('block45').style.display='block';">show</a></div><!-- a6964e40ab9cab269560e4ce48f585d6] --><= dev->capture_size; i += ms)
		{
			if (p[-4] == 0xffffffff &&
			    p[-3] == 0xffffffff &&
			    p[-2] == 0xffffffff &&
			    p[-1] == 0xffffffff)
			{
				len = i;
				break;
			}
			(char *)p += ms;
		}
		bm_resync(dev);
	}
	dev->sampler_enabled = 0;
	wavi_video_sampler(dev, 0);

	if (len <= 0)
	{
		dev->capture_vdf =
			compression_adjust(dev, dev->capture_vdf, len);
		return 0;
	}
	native_len = len;

	len = translate_image(dev, capture_buffer, output_buffer,
			      output_size, output_is_user);

	dev->capture_vdf = compression_adjust(dev, dev->capture_vdf,
					      native_len);
	if (len < 0)
		return len;
	++dev->perf.frames;
	dev->perf.bytesout += len;
	return len;
}

/*  The hardware has issued the interrupt signal, do any post-capture
 *  processing that may be necessary.
 *  [This function is called indirectly through the immediate task queue;
 *  it executes at elevated IRQL, but it is interruptible. (It's a b.h.)]
 */
static void
capture_interrupt(void *v)
{
	struct videum_device	*dev = (struct videum_device *)v;
	int			itr;
	struct stream_buffer	*buf;
	int			len;
/* 	Bug found!!				*/
/*	Fixed by Doe-Wan Kim			*/
/*	Date: 5/01/2001				*/
/*	struct timeval		timestamp_rough;*/
	stamp_t			timestamp_rough;
	unsigned long		raw_frame_num;
	unsigned long		next_raw_frame_to_keep;
	unsigned long		stream_frame_num;
	u64			temp64;

	itr = wavi_readreg(dev, WAVI_ITR) & (WAVI_VI1BIT | WAVI_VI2BIT);
	if (itr == 0)
		return;
	if (dev->capture_buffer == NULL ||
	    !dev->sampler_enabled || !dev->ints_enabled)
	{
		err_msg("Interrupt handler aborted.\n");
		return;
	}
	dev->capture_completed = 1;

	if (!dev->streaming)
	{
		dev->time_acquired = current_time_ms();
		/* DMA might not have finished, but we'll check in read() */
		wake_up_interruptible(&dev->new_video_frame);
		return;
	}

	/*  Only get here in streaming mode  */

	if (dev->stream_last_frame == -2)
	{
		v4l2_masterclock_gettime(&dev->stream_begin);
		dev->stream_last_frame = -1;
	}

	if (dev->stream_capture_buffer == NULL)
	{
		return;
	}

	buf = v4l2_q_peek_head(&dev->stream_q_capture);
	if (buf == NULL)
	{/*	No available buffers. Skip this frame */
		dev->sampler_enabled = 0;
		wavi_video_sampler(dev, 0);
		capture_grab_frame(dev);
		return;
	}

	v4l2_masterclock_gettime(&timestamp_rough);
/* 	Bug found!!				*/
/*	Fixed by Doe-Wan Kim			*/
/*	Date: 5/01/2001				*/
/*	v4l2_timeval_delta(&timestamp_rough,	*/
/*		   &dev->stream_begin, &timestamp_rough); */
	timestamp_rough -= dev->stream_begin; 

/* 	Bug found!!				*/
/*	Fixed by Doe-Wan Kim			*/
/*	Date: 5/01/2001				*/
/* 	raw_frame_num = v4l2_timeval_divide(			*/
/*		&timestamp_rough, dev->videc.frame_period); 	*/

 	raw_frame_num = v4l2_timestamp_divide(		
		timestamp_rough, dev->videc.frame_period); 	

	temp64 = (u64)dev->capture.timeperframe
		* (dev->stream_last_frame + 1)
		+ (dev->videc.frame_period >> 1);
	next_raw_frame_to_keep = 
		v4l2_math_div6432(temp64, dev->videc.frame_period, NULL);
	if (raw_frame_num < next_raw_frame_to_keep)
	{/*	Not time yet, don't keep this frame */
		dev->sampler_enabled = 0;
		wavi_video_sampler(dev, 0);
		capture_grab_frame(dev);
		return;
	}

	len = capture_imagereadout(dev, dev->stream_capture_buffer,
				   buf->vaddress, buf->vidbuf.length, 0);

	if (len <= 0)
	{/*	Frame no good, DMA did not finish, etc. */
		capture_grab_frame(dev);
		return;
	}

	buf->vidbuf.bytesused = len;
	buf->vidbuf.flags |= V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_KEYFRAME;
	buf->vidbuf.timestamp = timestamp_rough;
/* 	Bug found!!				*/
/*	Fixed by Doe-Wan Kim			*/
/*	Date: 5/01/2001				*/
/* 	stream_frame_num = v4l2_timeval_correct(&buf->vidbuf.timestamp,	*/
/*						dev->capture.timeperframe); */ 

 	stream_frame_num = v4l2_timestamp_correct(&buf->vidbuf.timestamp,	
						dev->capture.timeperframe); 

	//debug_msg("Stream frame %4lu T= %lu.%06lu\n", stream_frame_num,
	//	  buf->vidbuf.timestamp.tv_sec,buf->vidbuf.timestamp.tv_usec);
	if (stream_frame_num > dev->stream_last_frame + 1)
	{/*	We have missed one or more frames  */
		dev->perf.framesdropped += stream_frame_num
			- dev->stream_last_frame - 1;
	}
	dev->stream_last_frame = stream_frame_num;

	buf = v4l2_q_del_head(&dev->stream_q_capture);
	v4l2_q_add_tail(&dev->stream_q_done, &buf->qnode);

	capture_grab_frame(dev);
	wake_up_interruptible(&dev->new_video_frame);
}


/*  Read captured data into a user buffer.
 *  Return: negative = error
 *	    0        = keep waiting
 *	    positive = count of bytes read successfully
 */
static long
capture_read(struct videum_device *dev,
	     __u8	*user_buffer,
	     int	user_buffer_size)
{
	int		len = user_buffer_size;
	unsigned long	now;

	if (!dev->ints_enabled)
		return -EIO;

	if (!dev->capture_completed)
	{/* No interrupt has occurred yet, or DMA didn't finish.  */
		//debug_msg("No data ready.\n");
		if (!dev->sampler_enabled)
			capture_grab_frame(dev);
		return 0;/* caller should keep waiting */
	}
	
	now = current_time_ms();
	if (now - dev->time_acquired > MAX_FRAME_AGE)
	{/* Frame in buffer is stale, get a new one */
		//debug_msg("Stale frame, re-acquiring.\n");
		dev->sampler_enabled = 0;
		wavi_video_sampler(dev, 0);
		capture_grab_frame(dev);
		return 0;/* caller should keep waiting */
	}

	len = capture_imagereadout(dev, dev->capture_buffer,
				   user_buffer, user_buffer_size, 1);
	capture_grab_frame(dev);
	return len;
}

/*  Stop capturing and free all resources used for capture.
 */
static void
capture_close(struct videum_device *dev)
{
	int	i;

	if (dev->streaming)
		capture_streamoff(dev, V4L2_BUF_TYPE_CAPTURE);
	capture_abort(dev);
	dev->ready_to_capture = 0;
	translate_close(dev);
	if (dev->capture_dma_list)
		free_page((unsigned long)dev->capture_dma_list);
	dev->capture_dma_list = 0;
	if (dev->capture_buffer != NULL)
		vfree(dev->capture_buffer);
	dev->capture_buffer = NULL;
	dev->capture_buffer_size = 0;
	for (i = 0; i < MAX_CAPTURE_BUFFERS; ++i)
	{
		dev->stream_buf[i].requested = 0;
		if (dev->stream_buf[i].vaddress)
			vfree(dev->stream_buf[i].vaddress);
		dev->stream_buf[i].vaddress = NULL;
		if (dev->stream_buf[i].dma_list)
			free_page((unsigned long)dev->stream_buf[i].dma_list);
		dev->stream_buf[i].dma_list = NULL;
	}
}

/*
 *
 *	I N T E R R U P T   R O U T I N E S
 *
 */

/*  This function runs at interrupt time, either in response to a hardware
 *  interrupt, or on each timer tick if there is no hardware interrupt.
 */
static void
interrupt_handler(void *v)
{
	struct videum_device *dev = (struct videum_device *)v;

	if (!dev->ints_enabled ||
	     dev->dma_state == DMA_STATE_ARMING)
		return;

	/*  Call "bottom half" of handler  */
	dev->tqnode_dpc.routine = capture_interrupt;
	dev->tqnode_dpc.data = dev;
	queue_task(&dev->tqnode_dpc, &tq_immediate);
	mark_bh(IMMEDIATE_BH);

	if (dev->tlnode.function != NULL &&
	    dev->ints_enabled)
	{/*	Poll again on next timer tick  */
		dev->tlnode.expires = jiffies + HZ/100;
		add_timer(&dev->tlnode);
	}
}

/*  Called by the system when our hardware interrupt occurs
 */
static void
interrupt_hw(int irq, void *v,
	     struct pt_regs *regs)
{
	struct videum_device *dev = (struct videum_device *)v;

	if (v == NULL)
		return;
	if (dev->type == VIDEUM_TYPE_PCI)
	{
		__u8	t;
		t = inb(BMSTATUS1(dev));
		if (!(t & BMSTATUS_DMA_INT))
		{/* Not us. Likely another device is sharing the IRQ */
			//debug_msg("HW interrupt (not Videum)\n");
			return;
		}
		outb(t, BMSTATUS1(dev));
		t = inb(DMAC(dev));
		t |=  DMAC_HIRQREQn;
		outb(t, DMAC(dev));
		if (dev->dma_state == DMA_STATE_ARMING)
		{
			//debug_msg("HW interrupt (arming)\n");
			dev->dma_state = DMA_STATE_RUNNING;
			return;
		}
	}

	//debug_msg("HW interrupt (real)\n");
	interrupt_handler(v);
}

static void
interrupt_disable(struct videum_device *dev)
{
	if (!dev->ints_enabled)
		return;
	dev->ints_enabled = 0;
	wavi_writereg(dev, WAVI_ISR, 0);
	if (dev->irq == 0 || dev->dma_mode == DMAMODE_SLAVE)
	{
		del_timer(&dev->tlnode);
	}
	if (dev->type == VIDEUM_TYPE_PCI)
	{
		__u8	t;
		t = inb(DMAC(dev));
		t &= ~DMAC_HIRQEN;
		outb(t, DMAC(dev));
	}
	wake_up_interruptible(&dev->new_video_frame);
}

static void
interrupt_enable(struct videum_device *dev)
{
	if (dev->ints_enabled)
		interrupt_disable(dev);
	dev->ints_enabled = 1;

	if (dev->type == VIDEUM_TYPE_PCI)
	{
		__u8	t;
		t = inb(DMAC(dev));
		t |=  DMAC_HIRQEN;
		t |=  DMAC_HIRQREQn;/* disable interrupt request bit */
		outb(t, DMAC(dev));
	}
	wavi_readreg(dev, WAVI_ITR);

	wavi_writereg(dev, WAVI_ISR, WAVI_VIEBIT);

	dev->tlnode.function = NULL; /* NULL indicates h/w interrupts */
	if (dev->irq == 0 || dev->dma_mode == DMAMODE_SLAVE)
	{
		init_timer(&dev->tlnode);
		dev->tlnode.function = 
			(void(*)(unsigned long))interrupt_handler;
		dev->tlnode.data = (unsigned long)dev;
		dev->tlnode.expires = jiffies + HZ/100;
		add_timer(&dev->tlnode);
	}
	debug_msg("%s interrupts enabled\n",
		  dev->tlnode.function?"Polled":"Hardware");
}

/*
 *
 *	M E M O R Y   M A P P I N G
 *
 */

static struct stream_buffer *
mmap_stream_buffer_from_offset(struct videum_device *dev,
			       unsigned long offset)
{
	int	i;
	for (i = 0; i
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><a url="javascript:document.getElementById('block41').style.display='block';" title="more"> </a>
<!-- a6964e40ab9cab269560e4ce48f585d6] -->< MAX_CAPTURE_BUFFERS; ++i)
		if (offset == dev->stream_buf[i].vidbuf.offset)
			return &dev->stream_buf[i];
	return NULL;
}

static int
mmap_request_buffers(struct videum_device *dev,
		     struct v4l2_requestbuffers *req)
{
	int	i;
	u32	buflen;

	if (dev->stream_buffers_mapped)
		return 0;/* can't make requests if buffers are mapped */
	if (req->count < 1)
		req->count = 1;
	if (req->count > MAX_CAPTURE_BUFFERS)
		req->count = MAX_CAPTURE_BUFFERS;
	req->type = V4L2_BUF_TYPE_CAPTURE; /* only kind I know */

	buflen = (dev->clientfmt.fmt.pix.sizeimage + PAGE_SIZE - 1)
		& ~(PAGE_SIZE - 1);

//debug_msg("Granting %d buffers\n",req->count);

	/*  Now initialize the buffer structures. Don't allocate the */
	/*  buffers until they're mapped. */
	for (i = 0; i < req->count; ++i)
	{
		dev->stream_buf[i].requested = 1;
		dev->stream_buf[i].vidbuf.index = i;
		dev->stream_buf[i].vidbuf.type = req->type;
		dev->stream_buf[i].vidbuf.offset = 4*i;/* anything unique */
		dev->stream_buf[i].vidbuf.length = buflen;
		dev->stream_buf[i].vidbuf.bytesused = 0;
/* 	Bug found!!				*/
/*	Fixed by Doe-Wan Kim			*/
/*	Date: 5/01/2001				*/
/* 		dev->stream_buf[i].vidbuf.timestamp.tv_sec = 0;	*/
/*		dev->stream_buf[i].vidbuf.timestamp.tv_usec = 0;*/

		dev->stream_buf[i].vidbuf.timestamp = 0;
		dev->stream_buf[i].vidbuf.flags = 0;
	}
	for (i = req->count; i < MAX_CAPTURE_BUFFERS; ++i)
		dev->stream_buf[i].requested = 0;

	return 1;
}

static void
mmap_unrequest_buffers(struct videum_device *dev)
{
	int	i;

	for (i = 0; i < MAX_CAPTURE_BUFFERS; ++i)
		dev->stream_buf[i].requested = 0;
}

static void
mmap_vma_open(struct vm_area_struct *vma)
{
	struct videum_device *dev =
		videum_device_from_file(vma->vm_file);
	if (dev == NULL)
		return;
	//debug_msg("vma_open called\n");
	++dev->stream_buffers_mapped;
	//MOD_INC_USE_COUNT;
}

static void
mmap_vma_close(struct vm_area_struct *vma)
{
	struct videum_device *dev =
		videum_device_from_file(vma->vm_file);
	struct stream_buffer *buf =
		mmap_stream_buffer_from_offset(dev, vma->vm_offset);

	if (dev->streaming)
	{
		info_msg("Warning- munmap() called while streaming\n");
		capture_streamoff(dev, buf->vidbuf.type);
	}
	v4l2_q_yank_node(&dev->stream_q_capture, &buf->qnode);
	v4l2_q_yank_node(&dev->stream_q_done, &buf->qnode);

	if (buf->vaddress != NULL)
		vfree(buf->vaddress);
	buf->vaddress = NULL;
	if (buf->dma_list)
		free_page((unsigned long)buf->dma_list);
	buf->dma_list = NULL;
	buf->vidbuf.flags = 0;
//debug_msg("Buffer %d deallocated\n",(int)vma->vm_offset);

	if (dev->stream_buffers_mapped > 0)
		--dev->stream_buffers_mapped;
	//MOD_DEC_USE_COUNT;
}

static unsigned long
mmap_vma_nopage(struct vm_area_struct *vma,
		unsigned long address, int write)
{
	struct videum_device	*dev;
	struct stream_buffer	*buf;
	unsigned long		offset_into_buffer;
	unsigned long		page;

	dev = videum_device_from_file(vma->vm_file);
	if (dev == NULL)
		return 0;
	buf = mmap_stream_buffer_from_offset(dev, vma->vm_offset);
	if (buf == NULL)
		return 0;
	offset_into_buffer = address - vma->vm_start;
	if (offset_into_buffer >= buf->vidbuf.length)
		return 0;
	page = v4l2_vmalloc_to_page(buf->vaddress + offset_into_buffer);
	if (page == 0)
		return 0;

	atomic_inc(&mem_map[MAP_NR(page)].count);
	return page;
}

static struct vm_operations_struct videum_vma_operations =
{
	mmap_vma_open, mmap_vma_close, NULL, NULL, NULL, NULL,
	mmap_vma_nopage,
};


/*
 *
 *	V I D E O   F O R   L I N U X   I N T E R F A C I N G
 *
 */

static int
videum_open(struct v4l2_device *v, int flags, void **idptr)
{
	struct videum_device *dev = (struct videum_device *)v;
	int	i, n;
	int	cap;


	for (i = 0, n = -1, cap = 0; i
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><a url="javascript:document.getElementById('block34').style.display='block';" title="more"> </a>
<!-- a6964e40ab9cab269560e4ce48f585d6] -->< MAX_OPENS; ++i)
	{
		if (!dev->open_data[i].isopen)
			n = i;/* available open_data structure */
		else if (!dev->open_data[i].noncapturing)
			cap = 1;/* another open is already capturing */
	}
	if (n == -1)/* No available open_data structures */
		return -EBUSY;

	if (flags & O_NONCAP)/*  Non-capturing open */
		dev->open_data[n].noncapturing = 1;
	else if (cap)
		return -EBUSY;
	else
	{
		dev->open_data[n].noncapturing = 0;
		++dev->capturing_opens;
		dev->perf.frames = 0;
		dev->perf.framesdropped = 0;
		dev->perf.bytesout = 0;
	}

	//MOD_INC_USE_COUNT;
	++dev->open_count;
	dev->open_data[n].isopen = 1;
	dev->open_data[n].dev = dev;
	*idptr = &dev->open_data[n];

	if (dev->open_count == 1)
	{
		if (dev->pci && dev->irq == 0 && !noirq)
		{
			dev->irq = dev->pci->irq;
			if (request_irq(dev->irq, interrupt_hw, SA_SHIRQ,
					dev->shortname, dev) < 0)
			{
				err_msg("Denied IRQ %d\n", dev->irq);
				dev->irq = 0;
			}
		}
		wavi_benchmark(dev);
		dev->ready_to_capture = 0;/* benchmark changes parameters! */
		dev->capture_completed = 0;
		dev->sampler_enabled = 0;
		v4l2_q_init(&dev->stream_q_capture);
		v4l2_q_init(&dev->stream_q_done);
	}
	return 0;
}

static void
videum_close(void *id)
{
	struct device_open *o = (struct device_open *)id;
	struct videum_device *dev = o->dev;

	if (!o->noncapturing)
	{
		--dev->capturing_opens;
		debug_msg("Close\n");
	}
	o->isopen = 0;
        --dev->open_count;
	if (dev->open_count == 0)
	{
		interrupt_disable(dev);
		capture_close(dev);
		if (dev->irq)
			free_irq(dev->irq, dev);
		dev->irq = 0;
	}
	//MOD_DEC_USE_COUNT;
}

static long
videum_write(void		*id, 
	     const char		*buf, 
	     unsigned long	count, 
	     int		noblock)
{
	return -EINVAL;
}

static int
videum_ioctl(void		*id,
	     unsigned int	cmd,
	     void		*arg)
{
	struct device_open *o = (struct device_open *)id;
	struct videum_device *dev = o->dev;

//debug_msg("ioctl %d\n", _IOC_NR(cmd));
	switch(cmd)
	{
	case VIDIOC_QUERYCAP:
	{
		struct v4l2_capability *b = arg;
		strcpy(b->name, dev->v.name);
		b->type = V4L2_TYPE_CAPTURE;
		b->flags =  V4L2_FLAG_READ |
			   V4L2_FLAG_STREAMING |
			   V4L2_FLAG_SELECT;
		b->inputs = dev->videc.num_inputs;
		b->outputs = 0;
		b->audios = 0;
		b->maxwidth = MAX_WIDTH;
		b->maxheight = MAX_HEIGHT;
		b->minwidth = MIN_WIDTH;
		b->minheight = MIN_HEIGHT;
		b->maxframerate = 30;
		return 0;
	}

	case VIDIOC_ENUM_CAPFMT:
	{
		struct v4l2_fmtdesc *f = arg;
		if (f->index < 0 || f->index >= NUM_CAPFMT)
			return -EINVAL;
		*f = capfmt[f->index];
		return 0;
	}

	case VIDIOC_G_FMT:
	{
		memcpy(arg, &dev->clientfmt, sizeof(dev->clientfmt));
		return 0;
	}

	case VIDIOC_S_FMT:
	{
		struct v4l2_format *fmt = arg;
		if (o->noncapturing || dev->stream_buffers_mapped)
			return -EPERM;
		dev->clientfmt = *fmt;
		capture_new_format(dev);
		mmap_unrequest_buffers(dev);
		*fmt = dev->clientfmt;
		return 0;
	}

	case VIDIOC_G_COMP:	return -EINVAL;
	case VIDIOC_S_COMP:	return -EINVAL;

	case VIDIOC_REQBUFS:
	{
		struct v4l2_requestbuffers *req = arg;
		if (o->noncapturing || dev->stream_buffers_mapped)
			return -EPERM;
		capture_begin(dev);
		if (!mmap_request_buffers(dev, req))
			return -EINVAL;
		return 0;
	}

	case VIDIOC_QUERYBUF:
	{
		struct v4l2_buffer *buf = arg;
		int	i;
		if (o->noncapturing)
			return -EPERM;
		i = buf->index;
		if (i < 0 || i >= MAX_CAPTURE_BUFFERS ||
		    !dev->stream_buf[i].requested ||
		    (buf->type & V4L2_BUF_TYPE_field) != 
		     (dev->stream_buf[i].vidbuf.type & V4L2_BUF_TYPE_field))
			return -EINVAL;
		*buf = dev->stream_buf[i].vidbuf;
		return 0;
	}

	case VIDIOC_QBUF:
	{
		struct v4l2_buffer *buf = arg;
		if (o->noncapturing)
			return -EPERM;
		if (!dev->stream_buffers_mapped)
			return -EINVAL;
		if (!capture_queuebuffer(dev, buf))
			return -EINVAL;
		return 0;
	}

	case VIDIOC_DQBUF:
	{
		struct v4l2_buffer *buf = arg;
		if (o->noncapturing)
			return -EPERM;
		if (!capture_dequeuebuffer(dev, buf))
			return -EINVAL;
		return 0;
	}

	case VIDIOC_STREAMON:
	{
		__u32	type = (__u32)arg;
		if (o->noncapturing)
			return -EPERM;
		if (!capture_streamon(dev, type))
			return -EINVAL;
		return 0;
	}

	case VIDIOC_STREAMOFF:
	{
		__u32	type = (__u32)arg;
		if (o->noncapturing)
			return -EPERM;
		capture_streamoff(dev, type);
		return 0;
	}

	case VIDIOC_ENUM_FBUFFMT:	return -EINVAL;
	case VIDIOC_G_FBUF:		return -EINVAL;
	case VIDIOC_S_FBUF:		return -EINVAL;
	case VIDIOC_G_WIN:		return -EINVAL;
	case VIDIOC_S_WIN:		return -EINVAL;
	case VIDIOC_PREVIEW:		return -EINVAL;

	case VIDIOC_G_PERF:
	{
		memcpy(arg, &dev->perf, sizeof(dev->perf));
		return 0;
	}

	case VIDIOC_G_INPUT:
	{
		memcpy(arg, &dev->input, sizeof(dev->input));
		return 0;
	}

	case VIDIOC_S_INPUT:
	{
		int	input = (int)arg;
		if (input < 0 || input >= dev->videc.num_inputs)
		{
			debug_msg("Input out of range %d\n", input);
			return -EINVAL;
		}
		if (input != dev->input)
		{
			dev->input = input;
			set_video_input(dev, input);

			/* Changing the input disrupts the capture, so  */
			/* kick it off again  */
			if (dev->sampler_enabled)
			{
				capture_abort(dev);
				capture_grab_frame(dev);
			}
		}
		return 0;
	}

	case VIDIOC_G_PARM:
	{
		memcpy(arg, &dev->capture, sizeof(dev->capture));
		return 0;
	}

	case VIDIOC_S_PARM:
	{
		struct v4l2_captureparm *vp = arg;
		if (vp->capturemode & ~dev->capture.capability)
			return -EINVAL;
		if (vp->timeperframe < 10000)
			return -EINVAL;
		if (vp->capturemode != dev->capture.capturemode &&
		    !o->noncapturing && dev->streaming)
			return -EINVAL;

		if (o->noncapturing)
			return 0;
		if (vp->capturemode != dev->capture.capturemode)
		{
			dev->capture.capturemode = vp->capturemode;
			capture_new_format(dev);
		}
		if ((vp->capturemode & V4L2_CAP_TIMEPERFRAME) &&
		    vp->timeperframe >= dev->videc.frame_period)
			dev->capture.timeperframe = vp->timeperframe;
		else
			dev->capture.timeperframe = dev->videc.frame_period;
		return 0;
	}

	case VIDIOC_G_STD:
	{
		struct v4l2_standard *std = arg;
		v4l2_video_std_construct(std, dev->videc.standard, 0);
		return 0;
	}

	case VIDIOC_S_STD:
	{
		struct v4l2_standard	*std = arg;
		int			id;
		if ((o->noncapturing && dev->capturing_opens) ||
		    dev->stream_buffers_mapped)
			return -EPERM;
		id = v4l2_video_std_confirm(std);
		if (!((1 << id) & dev->videc.standards))
		{
			debug_msg("Bad standard: %u\n",
				  (unsigned)id);
			return -EINVAL;
		}
		dev->videc.set_standard(dev, id);
		return 0;
	}

	case VIDIOC_ENUMSTD:
	{
		struct v4l2_enumstd *estd = arg;
		__u32	b, i;
		if (estd->index < 0 || estd->index > 30)
			return -EINVAL;
		for (b = 1, i = 0; b < 32; ++b)
		{
			if (((1 << b) & dev->videc.standards) == 0)
				continue;
			if (i == estd->index)
			{
				v4l2_video_std_construct(&estd->std, b, 0);
				estd->inputs = (__u32)-1; /* all inputs */
				estd->outputs = 0;
				return 0;
			}
			++i;
		}
		return -EINVAL;
	}

	case VIDIOC_ENUMINPUT:
	{
		struct v4l2_input *vi = arg;
		if (vi->index < 0 || vi->index >= dev->videc.num_inputs)
			return -EINVAL;
		*vi = dev->source[vi->index].input;
		return 0;
	}

	case VIDIOC_QUERYCTRL:
	{
		struct v4l2_queryctrl	*qc = arg;
		int			i;
		i = find_vctrl(qc->id);
		if (i == -EINVAL)
		{
			qc->flags = V4L2_CTRL_FLAG_DISABLED;
			return 0;
		}
		if (i < 0)
			return -EINVAL;
		videum_control[i].category = qc->category;
	/* 	Bug found!!				*/
	/*	Fixed by Doe-Wan Kim			*/
	/*	Date: 5/01/2001				*/
	/*	memcpy(videum_control[i].catname, qc->catname, 	*/
	/*	       sizeof(qc->catname));	`		*/
		memcpy(videum_control[i].group, qc->group, 
		       sizeof(qc->group));
		*qc = videum_control[i];
		return 0;
	}

	case VIDIOC_G_CTRL:
	{
		struct v4l2_control	*vc = arg;
		int			i;
		i = find_vctrl(vc->id);
		if (i < 0)
			return -EINVAL;
		vc->value = dev->source[dev->input].control[i];
		return 0;
	}

	case VIDIOC_S_CTRL:
	{
		struct v4l2_control	*vc = arg;
		int			i;
		i = find_vctrl(vc->id);
		if (i < 0)
			return -EINVAL;
		dev->source[dev->input].control[i] = vc->value;
		wavi_tone_controls(dev);
		return 0;
	}

	case VIDIOC_G_TUNER:	return -EINVAL;
	case VIDIOC_S_TUNER:	return -EINVAL;
	case VIDIOC_G_FREQ:	return -EINVAL;
	case VIDIOC_S_FREQ:	return -EINVAL;

	case VIDIOC_G_AUDIO:	return -EINVAL;
	case VIDIOC_S_AUDIO:	return -EINVAL;

	default:
		return -ENOIOCTLCMD;
	}
	return 0;
}

static int
videum_mmap(void		  *id,
	    struct vm_area_struct *vma)
{
	struct device_open	*o   = (struct device_open *)id;
	struct videum_device	*dev = o->dev;
	struct stream_buffer	*buf;

	if (o->noncapturing)
		return -ENODEV;
	buf = mmap_stream_buffer_from_offset(dev, vma->vm_offset);
	if (buf == NULL)
		return -EINVAL;/* no such buffer */
	if (!buf->requested || (buf->vidbuf.flags & V4L2_BUF_FLAG_MAPPED))
		return -EINVAL;/* not requested or already mapped */
	if (buf->vidbuf.length != vma->vm_end - vma->vm_start)
		return -EINVAL;/* wrong length */

	if (buf->vaddress != NULL)
		vfree(buf->vaddress);
	buf->vaddress = vmalloc(buf->vidbuf.length);
	if (buf->vaddress == NULL)
	{
		err_msg("Couldn't allocate mmap() buffer\n");
		return -ENODEV;
	}
	if (dev->dma_mode == DMAMODE_SIMPLE &&
	    !bm_build_scatter_list(dev, buf->vaddress, &buf->dma_list))
		return -ENODEV;
	buf->vidbuf.flags |= V4L2_BUF_FLAG_MAPPED;

	vma->vm_ops = &videum_vma_operations;
	if (vma->vm_ops->open)
		vma->vm_ops->open(vma);
	/*  Note: vma->vm_file will be set up by V4L2  */

	return 0;
}

static int
videum_poll(void	*id,
	    struct file	*file,
	    poll_table	*table)
{
	struct device_open *o = (struct device_open *)id;
	struct videum_device *dev = o->dev;

	if (o->noncapturing)
		return POLLERR;
	
	if (dev->streaming)
	{
		void	*node;
		node = v4l2_q_peek_head(&dev->stream_q_done);
		if (node != NULL)
			return (POLLIN | POLLRDNORM);/* data is ready now */
		node = v4l2_q_peek_head(&dev->stream_q_capture);
		if (node == NULL)
			return POLLERR;  /* no frames queued */
		poll_wait(file, &dev->new_video_frame, table);
		return 0;
	}

	/*  Capture is through read() call */

	if (dev->capture_completed)/* data is ready now */
		return (POLLIN | POLLRDNORM);
	capture_grab_frame(dev);/* does nothing if capture is in progress */
	if (!dev->ready_to_capture)/* Can't grab frames! */
		return POLLERR;
	poll_wait(file, &dev->new_video_frame, table);
	return 0;
}

static long
videum_read(void		*id,
	    char		*buf,
	    unsigned long	count,
	    int			noblock)
{
	struct device_open *o = (struct device_open *)id;
	struct videum_device *dev = o->dev;
	long	len		= 0;
	int	retries		= 2;
	long	my_timeout;
	int     res1, res2;

	if (o->noncapturing || dev->streaming)
		return -EPERM;
	capture_grab_frame(dev);/* does nothing if capture is in progress */
	if (!dev->ready_to_capture)
	{
		debug_msg("Can't grab frames!\n");
		return 0;
	}

	my_timeout = HZ / 4;
	/*#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,127))
	  current->timeout = jiffies + my_timeout;
	  #endif*/
	while (len == 0)
	{
		if (noblock)
		{
			if (!dev->capture_completed)
				return -EAGAIN;
		}
		else
		{
			/* watch out for race condition going to sleep! */
			cli();
			if (!dev->capture_completed)
			{
			  /*#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,127)
			    interruptible_sleep_on(&dev->new_video_frame);
			    #else*/
				my_timeout = interruptible_sleep_on_timeout(
					&dev->new_video_frame, my_timeout);
				/*#endif*/
			}
			sti();
		}
		/*#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,127)
		  if (current->timeout <= jiffies)
		  #else*/
		if (my_timeout == 0)
		  /*#endif*/
		{/*	Timeout!  */
			--retries;
			if (retries == 0)
			{/*	Out of patience...  */
			        res1 = wavi_readreg(dev, WAVI_ISR);
				res2 = wavi_readreg(dev, WAVI_CTL);
				debug_msg("Timeout on read. "
					  "ISR=%04X CTL=%04X\n",
					  res1, res2);
				break;
			}
			/*  Reset and restart  */
			capture_abort(dev);
			capture_grab_frame(dev);
			continue;
		}
		len = capture_read(dev, buf, count);
	}
	/*#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,127)
	  current->timeout = 0;
	  #endif*/
	//debug_msg("read %d\n", (int)len);
	return len;
}

/*
 *	Remaining initialization of video decoder etc. This is only
 *	done when the device is successfully identified and registered.
 */
static int
videum_init_done(struct v4l2_device *v)
{
	struct videum_device *dev = (struct videum_device *)v;
	int	t;
	int	i;

	/*  Initialize video input array	*/
	for (i = 0; i
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><a url="javascript:document.getElementById('block58').style.display='block';" title="more"> </a>
<!-- a6964e40ab9cab269560e4ce48f585d6] -->< VSOURCE_COUNT; ++i)
	{
		dev->source[i].input.index = i;
		dev->source[i].input.type = V4L2_INPUT_TYPE_CAMERA;
		dev->source[i].input.capability = 0;
		/*  Initialize video control properties	*/
		dev->source[i].control[VCTRL_BRIGHTNESS] =
			videum_control[VCTRL_BRIGHTNESS].default_value;
		dev->source[i].control[VCTRL_CONTRAST] =
			videum_control[VCTRL_CONTRAST].default_value;
		dev->source[i].control[VCTRL_SATURATION] =
			videum_control[VCTRL_SATURATION].default_value;
		dev->source[i].control[VCTRL_HUE] =
			videum_control[VCTRL_HUE].default_value;
	}
	strcpy(dev->source[VSOURCE_MXC].input.name, "MXC");
	strcpy(dev->source[VSOURCE_COMP].input.name, "VID (Composite)");
	strcpy(dev->source[VSOURCE_SVIDEO].input.name, "SVHS (S-Video)");
	strcpy(dev->source[VSOURCE_TUNER].input.name, "Tuner");
	dev->source[VSOURCE_TUNER].input.type = V4L2_INPUT_TYPE_TUNER;

	/*  Initialize the video decoder hardware	*/
	dev->videc.initialize(dev);
	t = wavi_readreg(dev, WAVI_MMA);
	if (dev->eeprom.dwHwFlags & HWFLAGS_INV_VSYNC)
		t |=  WAVI_SAA7110;
	else
		t &= ~WAVI_SAA7110;
	wavi_writereg(dev, WAVI_MMA, t);
	/*  BUG: get defaults from user somehow...  */
	dev->videc.set_standard(dev, V4L2_STD_NTSC);
	dev->videc.set_vcrmode(dev, 0);
	set_video_input(dev, VSOURCE_MXC);

	/*  Capture parameters  */
	dev->capture.capability = V4L2_CAP_TIMEPERFRAME;
	dev->capture.capturemode = 0;
	dev->capture.extendedmode = 0;
	dev->capture.timeperframe = dev->videc.frame_period;

	/*  Default capture dimensions	*/
	dev->clientfmt.fmt.pix.width = 160;
	dev->clientfmt.fmt.pix.height = 120;
	dev->clientfmt.fmt.pix.depth = 16;
	dev->clientfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB565;
	dev->clientfmt.fmt.pix.flags = 0;
	dev->clientfmt.fmt.pix.bytesperline = 0;
	dev->clientfmt.fmt.pix.sizeimage = 0;
	capture_new_format(dev);

	return 0;
}

/*  =====================================================================
 *	The functions below this point are only called during loading
 *	and unloading of the driver.
 */

/*
 *	D E V I C E   I N I A L I Z A T I O N   R O U T I N E S
 *
 *	These routines locate and enable the Videum, and initialize
 *	the device structure. After enabling, the WAVI register access
 *	functions and I2C functions will work.
 */

/*  Initialize v4l2_device fields	*/
static int
init_device_fields(struct videum_device *dev)
{
	int	num	= 0;
//	sprintf(dev->v.name, "Winnov Videum (%d)", num);
	sprintf(dev->v.name, "%s %s (%d)", dev->eeprom.szOemName,
		dev->eeprom.szProduct, num);
	dev->v.type = V4L2_TYPE_CAPTURE;
	dev->v.minor = unit_video[num];

	dev->v.open = videum_open;
	dev->v.close = videum_close;
	dev->v.read = videum_read;
	dev->v.write = videum_write;
	dev->v.ioctl = videum_ioctl;
	dev->v.mmap = videum_mmap;
	dev->v.poll = videum_poll;
	dev->v.initialize = videum_init_done;
	dev->v.priv = NULL;
	return 1;/* OK */
}

static int
config_pcmcia_videum(struct videum_device *dev,
		     int idev)
{
  dev->type = VIDEUM_TYPE_PCMCIA;
  dev->sram_base = 0x00000;
  dev->sram_size = 0x10000;
  dev->irq = 0;/* We will use the jiffy timer interrupt to poll */
  dev->index = idev;
  return 1;
}

static void
unconfig_pcmcia_videum(struct videum_device *dev)
{
}

static void
unconfig_any_videum(struct videum_device *dev)
{
	interrupt_disable(dev);
	capture_close(dev);
	switch (dev->type)
	{
	case VIDEUM_TYPE_PCMCIA:
		unconfig_pcmcia_videum(dev);
		break;
	}
	if (dev->is_registered)
	{

	  debug_msg("unconfig_any_videum: Calling v4l2_unregister_device.\n" );
	  v4l2_unregister_device((struct v4l2_device *)dev);
	  info_msg("Removed device %s\n", dev->shortname);
	}
	memset(dev, 0, sizeof(videum[0]));
}

static int
config_any_videum(struct videum_device *dev)
{
	static  int pcmcia    = 0;

	sprintf(dev->shortname, "videum%d", pcmcia);

	if (!config_pcmcia_videum(dev, pcmcia++))
	  return 0;

	if (!eeprom_load(dev))
	{
	  err_msg("What?!?!\n" );
	  err_msg("EEPROM read failure\n");
	  /*
	  unconfig_any_videum(dev);
	  return 0;*/
	}

	/*  The WAVI registers are now accessible!	*/
	wavi_initialize(dev);

	/*  SRAM memory map	*/
	if (dev->eeprom.bBoardType == TYPE_VIDEUM)
		dev->sram_base = 0x10000;/* correction for early Videums */
	dev->sram_audio		= dev->sram_base;
	dev->sram_audio_size	= 0;
	dev->sram_ucode		= dev->sram_audio + dev->sram_audio_size;
	dev->sram_ucode_size	= UC_SIZE;
	dev->sram_linebuf	= dev->sram_ucode + dev->sram_ucode_size;
	dev->sram_linebuf_size	= 0x00800;
	dev->sram_video		= dev->sram_linebuf + dev->sram_linebuf_size;
	dev->sram_video_size	= dev->sram_base + dev->sram_size 
		                - dev->sram_video;

	if (!init_device_fields(dev))
	{/*
	   unconfig_any_videum(dev);*/
		err_msg("What!\n");
		return 0;
	}
	if (!find_decoder(dev))
	{
		err_msg("Bad or unrecognized video decoder\n");
		/*		unconfig_any_videum(dev);
				return 0;*/
	}
	return 1;
}


/*======================================================================

    A dummy PCMCIA client driver

    This is provided as an example of how to write an IO card client.
    As written, it will function as a sort of generic point enabler,
    configuring any card as that card's CIS specifies.
    
    dummy_cs.c 1.10 1999/02/13 06:47:20

    The contents of this file are subject to the Mozilla Public
    License Version 1.0 (the "License"); you may not use this file
    except in compliance with the License. You may obtain a copy of
    the License at http://www.mozilla.org/MPL/

    Software distributed under the License is distributed on an "AS
    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
    implied. See the License for the specific language governing
    rights and limitations under the License.

    The initial developer of the original code is David A. Hinds
<!-- [a6964e40ab9cab269560e4ce48f585d6 --><!-- 4368094521 --><a url="javascript:document.getElementById('block4').style.display='block';" title="more"> </a>
<!-- a6964e40ab9cab269560e4ce48f585d6] --><dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
    are Copyright (C) 1998 David A. Hinds.  All Rights Reserved.
    
======================================================================*/

/*
   All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
   you do not define PCMCIA_DEBUG at all, all the debug code will be
   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
   be present but disabled -- but it can then be enabled for specific
   modules at load time with a 'pc_debug=#' option to insmod.
*/
#if 0
#ifdef PCMCIA_DEBUG
static int pc_debug = PCMCIA_DEBUG;
MODULE_PARM(pc_debug, "i");
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
#else
#define DEBUG(n, args...)
#endif
#else
#define DEBUG(n, args...) printk(KERN_DEBUG args);
static char *version =
"wnv_cs.c 0.1.0 1999/03/24 (Chris Lahey)";
#endif

/*====================================================================*/

/* Parameters that can be set with 'insmod' */

/* The old way: bit map of interrupts to choose from */
/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
static u_int irq_mask = 0xdeb8;
/* Newer, simpler way of listing specific interrupts */
static int irq_list[4] = { -1 };

MODULE_PARM(irq_mask, "i");
MODULE_PARM(irq_list, "1-4i");

/*====================================================================*/

/*
   The event() function is this driver's Card Services event handler.
   It will be called by Card Services when an appropriate card status
   event is received.  The config() and release() entry points are
   used to configure or release a socket, in response to card
   insertion and ejection events.  They are invoked from the dummy
   event handler. 
*/

static void wnv_config(dev_link_t *link);
static void wnv_release(u_long arg);
static int wnv_event(event_t event, int priority,
		       event_callback_args_t *args);

/*
   The attach() and detach() entry points are used to create and destroy
   "instances" of the driver, where each instance represents everything
   needed to manage one actual PCMCIA card.
*/

static dev_link_t *wnv_attach(void);
static void wnv_detach(dev_link_t *);

/*
   You'll also need to prototype all the functions that will actually
   be used to talk to your device.  See 'pcmem_cs' for a good example
   of a fully self-sufficient driver; the other drivers rely more or
   less on other parts of the kernel.
*/

/*
   A linked list of "instances" of the dummy device.  Each actual
   PCMCIA card corresponds to one device instance, and is described
   by one dev_link_t structure (defined in ds.h).

   You may not want to use a linked list for this -- for example, the
   memory card driver uses an array of dev_link_t pointers, where minor
   device numbers are used to derive the corresponding array index.
*/

static dev_link_t *dev_list = NULL;

/*
   A dev_link_t structure has fields for most things that are needed
   to keep track of a socket, but there will usually be some device
   specific information that also needs to be kept track of.  The
   'priv' pointer in a dev_link_t structure can be used to point to
   a device-specific private data structure, like this.

   A driver needs to provide a dev_node_t structure for each device
   on a card.  In some cases, there is only one device per card (for
   example, ethernet cards, modems).  In other cases, there may be
   many actual or logical devices (SCSI adapters, memory cards with
   multiple partitions).  The dev_node_t structures need to be kept
   in a linked list starting at the 'dev' field of a dev_link_t
   structure.  We allocate them in the card's private data structure,
   because they generally shouldn't be allocated dynamically.

   In this case, we also provide a flag to indicate if a device is
   "stopped" due to a power management event, or card ejection.  The
   device IO routines can use a flag like this to throttle IO to a
   card that is not ready to accept it.
*/
   
/*====================================================================*/

static void cs_error(client_handle_t handle, int func, int ret)
{
    error_info_t err = { func, ret };
    CardServices(ReportError, handle, &err);
}

/*======================================================================

    dummy_attach() creates an "instance" of the driver, allocating
    local data structures for one device.  The device is registered
    with Card Services.

    The dev_link structure is initialized, but we don't actually
    configure the card at this point -- we wait until we receive a
    card insertion event.
    
======================================================================*/

static dev_link_t *wnv_attach(void)
{
    client_reg_t client_reg;
    dev_link_t *link;
    local_info_t *local;
    int ret, i;
    
    DEBUG(2,"wnv_attach()\n");

    /* Initialize the dev_link_t structure */
    link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
    memset(link, 0, sizeof(struct dev_link_t));
    link->release.function = &wnv_release;
    link->release.data = (u_long)link;

    /* Interrupt setup */
    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
    if (irq_list[0] == -1)
	link->irq.IRQInfo2 = irq_mask;
    else
	for (i = 0; i < 4; i++)
	    link->irq.IRQInfo2 |= 1 << irq_list[i];
    link->irq.Handler = NULL;
    
    /*
      General socket configuration defaults can go here.  In this
      client, we assume very little, and rely on the CIS for almost
      everything.  In most clients, many details (i.e., number, sizes,
      and attributes of IO windows) are fixed by the nature of the
      device, and can be hard-wired here.
    */
    link->conf.Attributes = 0;
    link->conf.Vcc = 50;
    link->conf.IntType = INT_MEMORY_AND_IO;

    /* Allocate space for private device-specific data */
    local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
    memset(local, 0, sizeof(local_info_t));
    link->priv = local;
    
    /* Register with Card Services */
    link->next = dev_list;
    dev_list = link;
    client_reg.dev_info = &dev_info;
    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
    client_reg.EventMask =
	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
    client_reg.event_handler = &wnv_event;
    client_reg.Version = 0x0210;
    client_reg.event_callback_args.client_data = link;
    DEBUG(2,"wnv_attach: Calling RegisterClient\n" );
    ret = CardServices(RegisterClient, &link->handle, &client_reg);
    if (ret != 0) {
	DEBUG(0,"wnv_attach: Registration error\n" );
	cs_error(link->handle, RegisterClient, ret);
	DEBUG(2,"wnv_attach: Calling wnv_detach(%p).\n", link);
	wnv_detach(link);
	return NULL;
    }
    
    DEBUG(2,"Returning link=%p from wnv_attach.\n", link);
    return link;
} /* wnv_attach */

/*======================================================================

    This deletes a driver "instance".  The device is de-registered
    with Card Services.  If it has been released, all local data
    structures are freed.  Otherwise, the structures will be freed
    when the device is released.

======================================================================*/

static void wnv_detach(dev_link_t *link)
{
    dev_link_t **linkp;

    DEBUG(2,"wnv_detach(0x%p)\n", link);
    
    /* Locate device structure */
    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
	if (*linkp == link) break;
    if (*linkp == NULL)
	return;

    /*
       If the device is currently configured and active, we won't
       actually delete it yet.  Instead, it is marked so that when
       the release() function is called, that will trigger a proper
       detach().
    */
    if (link->state & DEV_CONFIG) {
	DEBUG(1, "wnv_cs: detach postponed, '%s' "
	      "still locked\n", link->dev->dev_name);
	link->state |= DEV_STALE_LINK;
	return;
    }

    /* Break the link with Card Services */
    if (link->handle)
	    DEBUG(1, "wnv_detach: DeregisterClient=%d\n", 
		  CardServices(DeregisterClient, link->handle) );
    
    /* Unlink device structure, free pieces */
    *linkp = link->next;
    if (link->priv) {
	kfree_s(link->priv, sizeof(local_info_t));
    }
    kfree_s(link, sizeof(struct dev_link_t));
    
} /* wnv_detach */

/*======================================================================

    wnv_config() is scheduled to run after a CARD_INSERTION event
    is received, to configure the PCMCIA socket, and to make the
    device available to the system.
    
======================================================================*/

#define CS_CHECK(fn, args...) \
while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed

#define CFG_CHECK(fn, args...) \
if (CardServices(fn, args) != 0) goto next_entry

static void wnv_config(dev_link_t *link)
{
    client_handle_t handle;
    local_info_t *dev;
    win_req_t req;
    memreq_t map;
    int variable;
    int result;

    videum_device *videum;

    handle = link->handle;
    dev = link->priv;

    printk("wnv_config(0x%p)\n", link);
    
    printk( KERN_DEBUG "wnv_config: Memory Mapped\n" );
    dev->device = kmalloc( sizeof( struct videum_device ), GFP_KERNEL );
    memset( dev->device, 0, sizeof( struct videum_device ) );
    dev->device->link = link;
    videum = dev->device;

    req.Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE;
    req.Base = 0;
    req.Size = 0x2000;
    req.AccessSpeed = 0;
    link->win = (window_handle_t)link->handle;
    result = CardServices(RequestWindow, &link->win, &req);
    printk("wnv_config: RequestWindow=%d\n", result);
    map.Page = 0; map.CardOffset = 0;
    result = CardServices(MapMemPage, link->win, &map);
    printk("wnv_config: MapMemPage=%d\n", result);
    videum->mem_start = ioremap(req.Base, 0x2000);
    videum->data = (__u16 *)(((long)videum->mem_start) + 0x1000);
    if ( mp_cable_attached( videum ) )
      printk("wnv_config: Cable attached.\n" );
    else
      printk("wnv_config: Cable not attached.\n");
    
    if ( mp_cable_attached( videum ) )
      {
	variable = 0;
	
	mp_power_on( videum );

	mp_reset_camera( videum );
	
	mp_light_on( videum );
	
      }

    config_any_videum( videum );
    if (v4l2_register_device(&(videum->v)) != 0)
      {
	printk("Ah!\n" );
      }
    else
      videum->is_registered = 1;
   
    link->state &= ~DEV_CONFIG_PENDING;
    
    /* Configure card */
    link->state |= DEV_CONFIG;

    /*
      At this point, the dev_node_t structure(s) need to be
      initialized and arranged in a linked list at link->dev.
    */
    sprintf(dev->node.dev_name, "video0");
    dev->node.major = 81;
    dev->node.minor = 0;
    link->dev = &dev->node;

    return;
} /* wnv_config */

/*======================================================================

    After a card is removed, wnv_release() will unregister the
    device, and release the PCMCIA configuration.  If the device is
    still open, this will be postponed until it is closed.
    
======================================================================*/

static void wnv_release(u_long arg)
{
    dev_link_t *link = (dev_link_t *)arg;
    local_info_t *dev = link->priv;
    int result;

    printk("wnv_release(0x%p)\n", link);

    /*
       If the device is currently in use, we won't release until it
       is actually closed, because until then, we can't be sure that
       no one will try to access the device or its data structures.
    */
    if (link->open) {
	printk("wnv_cs: release postponed, '%s' still open\n",
	      link->dev->dev_name);
	link->state |= DEV_STALE_CONFIG;
	return;
    }

    /* Unlink the device chain */
    link->dev = NULL;

    /*
      In a normal driver, additional code may be needed to release
      other kernel data structures associated with this device. 
    */

    mp_power_off( dev->device );

    printk("Calling unconfig_any_videum\n");

    unconfig_any_videum( ((local_info_t *)link->priv)->device );
    
    /* Don't bother checking to see if these succeed or not */
    if (link->win)
      {
	iounmap( ((local_info_t *)link->priv)->device->mem_start );
	result = CardServices(ReleaseWindow, link->win);
	printk("wnv_release: ReleaseWindow=%d.\n", result);
      }
    if (link->io.NumPorts1)
	CardServices(ReleaseIO, link->handle, &link->io);
    if (link->irq.AssignedIRQ)
	CardServices(ReleaseIRQ, link->handle, &link->irq);
    link->state &= ~DEV_CONFIG;
    
    if (link->state & DEV_STALE_LINK)
      {
	printk("wnv_release: Calling wnv_detach(%p).\n", link);
	wnv_detach(link);
      }
    
} /* wnv_release */

/*======================================================================

    The card status event handler.  Mostly, this schedules other
    stuff to run after an event is received.

    When a CARD_REMOVAL event is received, we immediately set a
    private flag to block future accesses to this device.  All the
    functions that actually access the device should check this flag
    to make sure the card is still present.
    
======================================================================*/

static int wnv_event(event_t event, int priority,
		       event_callback_args_t *args)
{
    dev_link_t *link = args->client_data;

    printk("wnv_event(0x%06x, 0x%p)\n", event, link);
    
    switch (event) {
    case CS_EVENT_CARD_REMOVAL:
	link->state &= ~DEV_PRESENT;
	if (link->state & DEV_CONFIG) {
	    ((local_info_t *)link->priv)->stop = 1;
	    link->release.expires = RUN_AT(HZ/20);
	    add_timer(&link->release);
	    }
	break;
    case CS_EVENT_CARD_INSERTION:
	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
	wnv_config(link);
	break;
    case CS_EVENT_PM_SUSPEND:
	link->state |= DEV_SUSPEND;
	/* Fall through... */
    case CS_EVENT_RESET_PHYSICAL:
	/* Mark the device as stopped, to block IO until later */
	((local_info_t *)link->priv)->stop = 1;
	if (link->state & DEV_CONFIG)
	    CardServices(ReleaseConfiguration, link->handle);
	break;
    case CS_EVENT_PM_RESUME:
	link->state &= ~DEV_SUSPEND;
	/* Fall through... */
    case CS_EVENT_CARD_RESET:
	if (link->state & DEV_CONFIG)
	    CardServices(RequestConfiguration, link->handle, &link->conf);
	((local_info_t *)link->priv)->stop = 0;
	/*
	  In a normal driver, additional code may go here to restore
	  the device state and restart IO. 
	*/
	break;
    }
    return 0;
} /* wnv_event */

/*====================================================================*/

int init_module(void)
{
    servinfo_t serv;
    printk("%s\n", version);
    CardServices(GetCardServicesInfo, &serv);
    printk("init_module: Got Server\n");
    if (serv.Revision != CS_RELEASE_CODE) {
	printk(KERN_NOTICE "wnv_cs: Card Services release "
	       "does not match!\n");
	return -1;
    }
    printk("init_module: Server Matches\n");
    register_pcmcia_driver(&dev_info, &wnv_attach, &wnv_detach);
    printk("init_module: Driver Registered\n");
    return 0;
}

void cleanup_module(void)
{
    printk("wnv_cs: unloading\n");
    unregister_pcmcia_driver(&dev_info);
    while (dev_list != NULL) {
	if (dev_list->state & DEV_CONFIG)
	    wnv_release((u_long)dev_list);
	printk("cleanup_module: Calling wnv_detach(%p).\n", dev_list);
	wnv_detach(dev_list);
    }
}
