#ifndef IVTV_H
#define IVTV_H

/* Header for ivtv project:
 * Driver for the iTVC15 chip.
 * Author: Kevin Thayer (nufan_wfk at yahoo.com)
 * License: GPL
 * http://www.sourceforge.net/projects/ivtv/
 */

#ifndef MODULE
 #define MODULE
#endif

#include <linux/module.h>
#include <linux/init.h>
#include <linux/config.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/video_decoder.h>
#include <linux/i2c.h>
#include <linux/videodev.h>
#include <linux/list.h>
#include <linux/unistd.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
#include <asm/system.h>
#include "msp3400.h"
/* If you don't want to patch to v4l2, grab a copy of
 * videodev2.h and put it in the same dir as this file */ 
#ifndef HAVE_V4L2
 #define HAVE_V4L2 1 
 #include "videodev2.h"
#endif
#include <linux/i2c-algo-bit.h>
#include <linux/byteorder/swab.h>
#include "tuner.h"

#ifndef CONFIG_PCI
#  error "This driver requires kernel PCI support."
#endif

#define IVTV_ENCODER_OFFSET	0x00000000
#define IVTV_ENCODER_SIZE	0x01000000

#define IVTV_DECODER_OFFSET	0x01000000
#define IVTV_DECODER_SIZE	0x01000000

#define IVTV_ENCDEC_SIZE	(IVTV_ENCODER_SIZE + IVTV_DECODER_SIZE)

#define IVTV_REG_OFFSET 	0x02000000
#define IVTV_REG_SIZE		0x00010000

#define IVTV_IOREMAP_SIZE	(IVTV_ENCDEC_SIZE + IVTV_REG_SIZE)

#define IVTV_IOREMAP_ERROR	"ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h " \
				"or disabling CONFIG_HIMEM4G into the kernel would help"

/* General */
#define IVTV_DRIVER_NAME "ivtv"
#define IVTV_DRIVER_VERSION KERNEL_VERSION(0,0,1)
#define IVTV_MAX_CARDS 9
#define IVTV_MAX_YUV_BUFFERS 500
#define IVTV_MIN_YUV_BUFFERS 40
#define IVTV_MAX_MPG_BUFFERS 100
#define IVTV_MIN_MPG_BUFFERS 15
#define IVTV_MAX_DEC_YUV_BUFFERS 500
#define IVTV_MIN_DEC_YUV_BUFFERS 17
#define IVTV_MAX_DEC_MPG_BUFFERS 100
#define IVTV_MIN_DEC_MPG_BUFFERS 5
#define IVTV_MAX_VBI_BUFFERS 100
#define IVTV_MIN_VBI_BUFFERS 3
#define IVTV_PCI_ID_250_V1 0x4001 /* subsystem id */
#define IVTV_PCI_ID_250_V2 0x4009
#define IVTV_PCI_ID_350_V1 0x4000
#define IVTV_250_V1 0 /* wintv pvr 250, encoder and decoder */
#define IVTV_250_V2 1 /* pvr 250, encoder only */
#define IVTV_350_V1 2 /* encoder, decoder, tv-out */
#define IVTV_250_V1_STREAMS 3
#define IVTV_250_V2_STREAMS 3
#define IVTV_350_V1_STREAMS 5
#define IVTV_V4L2_DEC_OFFSET 16 /* offset from 0 to register dec. v4l2 minors on */
#define IVTV_V4L2_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */

#define IVTV_ENC_STREAM_TYPE_MPG 0
#define IVTV_ENC_STREAM_TYPE_YUV 1
#define IVTV_ENC_STREAM_TYPE_VBI 2
#define IVTV_DEC_STREAM_TYPE_MPG 3
#define IVTV_DEC_STREAM_TYPE_YUV 4

#define IVTV_ENC_MEM_START 0x00000000
#define IVTV_DEC_MEM_START 0x01000000
#define PCI_VENDOR_ID_ICOMP  0x4444
#define PCI_DEVICE_ID_IVTV15 0x0803
#define PCI_DEVICE_ID_IVTV16 0x0016
#define IVTV_DEVNAME "ivtv: iTVC15/16 mpg2 encoder chip"
#define IVTV_MBOX_MAX_BOXES 20
#define IVTV_MBOX_API_BOXES 6
#define IVTV_MBOX_DMA_START 6
#define IVTV_MBOX_DMA_END 8
#define IVTV_MBOX_MAX_DATA 16
#define IVTV_MBOX_DMA 9
#define IVTV_MBOX_FIELD_DISPLAYED 8
#define IVTV_MBOX_SIZE 80
#define IVTV_SAA7115_I2C_ADDR 0x21
#define IVTV_TUNER_I2C_ADDR 0x61
#define IVTV_MSP3400_I2C_ADDR 0x40
#define IVTV_DMA_BUF_SIZE 34560 /* 0x8000 = 32kbytes, 0x20000 = 128kbytes */
#define IVTV_DMA_DEC_BUF_SIZE 32768 /* 0x8000 = 32kbytes, 0x20000 = 128kbytes */
//#define IVTV_DMA_BUF_SIZE 65536 /* 0x8000 = 32kbytes, 0x20000 = 128kbytes */
//#define IVTV_DMA_DEC_BUF_SIZE 65536 /* 0x8000 = 32kbytes, 0x20000 = 128kbytes */

#define IVTV_DMA_MAX_XFER 0x00080000 /* 0x8000 = 32kbytes, 0x20000 = 128kbytes */
#define IVTV_DEC_MIN_BUF  0x00050000 /* want this many bytes+ in decoder buffer */
#define IVTV_SLEEP_WAIT (HZ/10) /*100 ms*/
#define IVTV_MAX_DATA_SLEEP 30
#define DEC_DMA_TIMEOUT (HZ/10)

#define IVTV_DMA_ERR_LIST 0x00000008
#define IVTV_DMA_ERR_WRITE 0x00000004
#define IVTV_DMA_ERR_READ 0x00000002
#define IVTV_DMA_SUCCESS 0x00000001
#define IVTV_DMA_READ_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_READ)
#define IVTV_DMA_WRITE_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE)
#define IVTV_DMA_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE | IVTV_DMA_ERR_READ)

/* video related */
#define IVTV_MAX_INPUTS 9

/*ioctl's*/
#define IVTV_CTL_PRINTBOXES 0x00000001
#define IVTV_CTL_CLEANUP 0x00000002
#define IVTV_CTL_INIT_VIDCAP 0x00000003

/* Registers */
#define IVTV_REG_DMASTATUS (0x0004 /*| IVTV_REG_OFFSET*/)
#define IVTV_REG_IRQSTATUS (0x0040 /*| IVTV_REG_OFFSET*/)
#define IVTV_REG_IRQMASK (0x0048 /*| IVTV_REG_OFFSET*/)
#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8 /*| IVTV_REG_OFFSET*/)
#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC /*| IVTV_REG_OFFSET*/)
#define IVTV_REG_DEC_SDRAM_REFRESH (0x08F8 /*| IVTV_REG_OFFSET*/)
#define IVTV_REG_DEC_SDRAM_PRECHARGE (0x08FC /*| IVTV_REG_OFFSET*/)
#define IVTV_REG_VDM (0x2800 /*| IVTV_REG_OFFSET*/)
#define IVTV_REG_AO (0x2D00 /*| IVTV_REG_OFFSET*/)
#define IVTV_REG_BYTEFLUSH (0x2D24 /*| IVTV_REG_OFFSET*/)
#define IVTV_REG_SPU (0x9050 /*| IVTV_REG_OFFSET*/)
#define IVTV_REG_HW_BLOCKS (0x9054 /*| IVTV_REG_OFFSET*/)
#define IVTV_REG_VPU (0x9058 /*| IVTV_REG_OFFSET*/)
#define IVTV_REG_APU (0xA064 /*| IVTV_REG_OFFSET*/)

/* IRQ Masks */
#define IVTV_IRQ_MASK_DEFAULT 0x00000404 /*stuff to ignore*/
#define IVTV_IRQ_MASK_CAPTURE 0xFC000400 /*inverse mask, we want the high bits!*/
#define IVTV_IRQ_MASK_DECODE 0x00FC0400

#define IVTV_IRQ_ENC_START_CAP		(0x1 << 31)
#define IVTV_IRQ_ENC_EOS		(0x1 << 30)
#define IVTV_IRQ_ENC_VBI_CAP		(0x1 << 29)
#define IVTV_IRQ_ENC_VIM_RST		(0x1 << 28)
#define IVTV_IRQ_ENC_DMA_COMPLETE	(0x1 << 27)

#define IVTV_IRQ_DEC_COPY_PROTECT	(0x1 << 25)
#define IVTV_IRQ_DEC_AUD_MODE_CHG	(0x1 << 24)
#define IVTV_IRQ_DEC_DATA_REQ		(0x1 << 22)
#define IVTV_IRQ_DEC_IFRAME_DONE	(0x1 << 21)
#define IVTV_IRQ_DEC_DMA_COMPLETE	(0x1 << 20)
#define IVTV_IRQ_DEC_VBI_RE_INSERT	(0x1 << 19)
#define IVTV_IRQ_DEC_DMA_ERR		(0x1 << 18)
#define IVTV_IRQ_DEC_VSYNC		(0x1 << 10)

#define IVTV_IRQ_DEBUG_KLUGE ( IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_ENC_VIM_RST | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DEC_COPY_PROTECT | IVTV_IRQ_DEC_AUD_MODE_CHG | IVTV_IRQ_DEC_DATA_REQ | IVTV_IRQ_DEC_IFRAME_DONE | IVTV_IRQ_DEC_DMA_COMPLETE | IVTV_IRQ_DEC_VBI_RE_INSERT | IVTV_IRQ_DEC_DMA_ERR )

/* commands */
#define IVTV_MASK_SPU_ENABLE 0xFFFFFFFE
#define IVTV_MASK_VPU_ENABLE15 0xFFFFFFF6
#define IVTV_MASK_VPU_ENABLE16 0xFFFFFFFB
#define IVTV_CMD_VDM_STOP 0x00000000
#define IVTV_CMD_AO_STOP 0x00000005
#define IVTV_CMD_APU_PING 0x00000000
#define IVTV_CMD_VPU_STOP15 0xFFFFFFFE
#define IVTV_CMD_VPU_STOP16 0xFFFFFFEE
#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
#define IVTV_CMD_SPU_STOP 0x00000001
#define IVTV_CMD_SDRAM_PRECHARGE_INIT 0x0000001A
#define IVTV_CMD_SDRAM_REFRESH_INIT 0x80000640
#define IVTV_SDRAM_SLEEPTIME (60 * HZ / 100)	/* 600ms */

/*Used for locating the firmware mailboxes*/
#define IVTV_FIRM_ENC_FILENAME "/lib/modules/ivtv-fw-enc.bin" 
#define IVTV_FIRM_DEC_FILENAME "/lib/modules/ivtv-fw-dec.bin"
#define IVTV_FIRM_IMAGE_SIZE 256*1024
#define IVTV_FIRM_SEARCH_ENCODER_START IVTV_ENCODER_OFFSET
#define IVTV_FIRM_SEARCH_DECODER_START IVTV_DECODER_OFFSET
#define IVTV_FIRM_SEARCH_ENCODER_END (IVTV_ENCODER_OFFSET + IVTV_ENCODER_SIZE - 1)
#define IVTV_FIRM_SEARCH_DECODER_END (IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE - 1)
#define IVTV_FIRM_SEARCH_STEP 0x00000100
 
/* Firmware mailbox flags*/
#define IVTV_MBOX_FIRMWARE_DONE 0x00000004
#define IVTV_MBOX_DRIVER_DONE 0x00000002
#define IVTV_MBOX_IN_USE 0x00000001
#define IVTV_MBOX_FREE 0x00000000

/*Firmware API commands*/
#define IVTV_API_ENC_GETVER 0x000000C4
#define IVTV_API_DEC_GETVER 0x00000011
#define IVTV_API_ENC_HALT_FW 0x000000C3
#define IVTV_API_DEC_HALT_FW 0x0000000E
#define IVTV_API_DEC_START_PLAYBACK 0x00000001
#define IVTV_API_DEC_STOP_PLAYBACK 0x00000002
#define IVTV_API_DEC_PLAYBACK_SPEED 0x00000003
#define IVTV_API_DEC_PAUSE_PLAYBACK 0x0000000d
#define IVTV_API_DEC_DMA_BLOCKSIZE 0x00000008
#define IVTV_API_DEC_DMA_FROM_HOST 0x00000000b
#define IVTV_API_DEC_DISP_STANDARD 0x00000010
#define IVTV_API_DEC_STREAM_INPUT 0x00000014
#define IVTV_API_DEC_TIMING_INFO 0x00000015
#define IVTV_API_DEC_SELECT_AUDIO 0x00000016
#define IVTV_API_DEC_EVENT_NOTIFICATION 0x00000017
#define IVTV_API_DEC_DISPLAY_BUFFERS 0x00000018
#define IVTV_API_DEC_DECODE_SOURCE 0x0000001a
#define IVTV_API_DEC_AUDIO_OUTPUT 0x0000001b
#define IVTV_API_DEC_SET_AV_DELAY 0x0000001c
#define IVTV_API_DEC_BUFFER 0x0000001e
#define IVTV_API_DEC_DMA_STATUS 0x0000000a
#define IVTV_API_DEC_XFER_INFO 0x00000009
#define IVTV_API_STD_TIMEOUT 0x00010000 /*units??*/
#define IVTV_API_ASSIGN_DMA_BLOCKLEN 0x000000c9
#define IVTV_API_ASSIGN_PGM_INDEX_INFO 0x000000c7
#define IVTV_API_ASSIGN_STREAM_TYPE 0x000000b9
#define IVTV_API_ASSIGN_OUTPUT_PORT 0x000000bb
#define IVTV_API_ASSIGN_FRAMERATE 0x0000008f
#define IVTV_API_ASSIGN_FRAME_SIZE 0x00000091
#define IVTV_API_ASSIGN_ASPECT_RATIO 0x00000099
#define IVTV_API_ASSIGN_BITRATES 0x00000095
#define IVTV_API_ASSIGN_GOP_PROPERTIES 0x00000097
#define IVTV_API_ASSIGN_3_2_PULLDOWN 0x000000b1
#define IVTV_API_ASSIGN_GOP_CLOSURE 0x000000c5
#define IVTV_API_ASSIGN_AUDIO_PROPERTIES 0x000000bd
#define IVTV_API_ASSIGN_DNR_FILTER_MODE 0x0000009b
#define IVTV_API_ASSIGN_DNR_FILTER_PROPS 0x0000009d
#define IVTV_API_ASSIGN_CORING_LEVELS 0x0000009f
#define IVTV_API_ASSIGN_SPATIAL_FILTER_TYPE 0x000000a1
#define IVTV_API_ASSIGN_FRAME_DROP_RATE 0x000000d0
#define IVTV_API_ASSIGN_PLACEHOLDER 0x000000d8
#define IVTV_API_INITIALIZE_INPUT 0x000000cd
#define IVTV_API_ASSIGN_NUM_VSYNC_LINES 0x000000d6
#define IVTV_API_BEGIN_CAPTURE 0x00000081
#define IVTV_API_PAUSE_ENCODER 0x000000d2
#define IVTV_API_EVENT_NOTIFICATION 0x000000d5
#define IVTV_API_END_CAPTURE 0x00000082
#define IVTV_API_SCHED_DMA_TO_HOST 0x000000cc
#define IVTV_API_FB_GET_FRAMEBUFFER 0x00000041
#define IVTV_API_FB_GET_PIXEL_FORMAT 0x00000042
#define IVTV_API_FB_SET_PIXEL_FORMAT 0x00000043
#define IVTV_API_FB_GET_STATE 0x00000044
#define IVTV_API_FB_SET_STATE 0x00000045
#define IVTV_API_FB_GET_OSD_COORDS 0x00000046
#define IVTV_API_FB_SET_OSD_COORDS 0x00000047
#define IVTV_API_FB_GET_SCREEN_COORDS 0x00000048
#define IVTV_API_FB_SET_SCREEN_COORDS 0x00000049
#define IVTV_API_FB_GET_GLOBAL_ALPHA 0x0000004a
#define IVTV_API_FB_SET_GLOBAL_ALPHA 0x0000004b
#define IVTV_API_FB_SET_BLEND_COORDS 0x0000004c
// 0x4d unknown
// 0x4e unknown
#define IVTV_API_FB_GET_FLICKER_STATE 0x0000004f
#define IVTV_API_FB_SET_FLICKER_STATE 0x00000050
// 0x51 unknown
#define IVTV_API_FB_BLT_COPY 0x00000052
#define IVTV_API_FB_BLT_FILL 0x00000053
#define IVTV_API_FB_BLT_TEXT 0x00000054
// 0x55 unknown
#define IVTV_API_FB_SET_FRAMEBUFFER_WINDOW 0x00000056
// 0x57 - 0x5f unknown
#define IVTV_API_FB_SET_CHROMA_KEY 0x00000060
#define IVTV_API_FB_GET_ALPHA_CONTENT_INDEX 0x00000061
#define IVTV_API_FB_SET_ALPHA_CONTENT_INDEX 0x00000062

/* i2c stuff */
#define I2C_CLIENTS_MAX 16
#define I2C_TIMING (0x7<<4)
#define IVTV_REG_I2C_SETSCL_OFFSET (0x7000 /*| IVTV_REG_OFFSET*/)
#define IVTV_REG_I2C_SETSDA_OFFSET (0x7004 /*| IVTV_REG_OFFSET*/)
#define IVTV_REG_I2C_GETSCL_OFFSET (0x7008 /*| IVTV_REG_OFFSET*/)
#define IVTV_REG_I2C_GETSDA_OFFSET (0x700c /*| IVTV_REG_OFFSET*/)

/* debugging */
#define IVTV_DEBUG_ERR   (1 << 0)
#define IVTV_DEBUG_INFO  (1 << 1)
#define IVTV_DEBUG_API   (1 << 2)
#define IVTV_DEBUG_DMA   (1 << 3)
#define IVTV_DEBUG_IOCTL (1 << 4)
#define IVTV_DEBUG_I2C   (1 << 5)
#define IVTV_DEBUG_IRQ   (1 << 6)
#define IVTV_DEBUG(x,args...) if((x)&ivtv_debug) printk("ivtv: " args);
#define IVTV_DEBUG_FB(x,args...) if((x)&ivtv_debug) printk("ivtv-fb: " args);

/* Temp saa7115 hack FIXME */
#define DECODER_SET_SIZE    76598
#define	DECODER_GET_PICTURE 76599

/* Values for IVTV_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */
#define MPEG_FRAME_TYPE_IFRAME 1
#define MPEG_FRAME_TYPE_IFRAME_PFRAME 3
#define MPEG_FRAME_TYPE_ALL 7

/* External API stuff */
#define IVTV_IOC_FWAPI		0xFFEE7701 /*just some values i picked for now*/
#define IVTV_IOC_ZCOUNT		0xFFEE7702
#define IVTV_IOC_G_CODEC	0xFFEE7703
#define IVTV_IOC_S_CODEC	0xFFEE7704

/* allow direct access to the saa7115 registers for testing */
#define SAA7115_GET_REG         0xFFEE7705
#define SAA7115_SET_REG         0xFFEE7706


#define DECODER_SET_AUDIO       0xFFEE7707
#define DECODER_AUDIO_32_KHZ	0
#define DECODER_AUDIO_441_KHZ	1
#define DECODER_AUDIO_48_KHZ	2

#define IVTV_IOC_PLAY     	0xFFEE7781
#define IVTV_IOC_PAUSE     	0xFFEE7782
#define IVTV_IOC_FRAMESYNC	0xFFEE7783
#define IVTV_IOC_GET_TIMING	0xFFEE7784
#define IVTV_IOC_S_SLOW_FAST	0xFFEE7785
#define IVTV_IOC_S_START_DECODE 0xFFEE7786
#define IVTV_IOC_S_STOP_DECODE  0xFFEE7787
#define IVTV_IOC_S_OSD          0xFFEE7788
#define IVTV_IOC_GET_FB		0xFFEE7789

/* Framebuffer external API */
/* NOTE: These must *exactly* match the structures and constants in driver/ivtv.h */

struct ivtvfb_ioctl_state_info {
  unsigned long status;
  unsigned long alpha;
};

struct ivtvfb_ioctl_blt_copy_args {
  int x, y, width, height, source_offset, source_stride;
};

struct ivtvfb_ioctl_dma_host_to_ivtv_args {
  void* source;
  unsigned long dest_offset;
  int count;
};

struct ivtvfb_ioctl_get_frame_buffer {
	void* mem;
	int   bytes;
	int   sizex;
	int   sizey;
};

struct ivtv_osd_coords {
  unsigned long offset;
  unsigned long max_offset;
  int pixel_stride;
  int lines;
  int x;
  int y;
};

struct rectangle {
  int x0;
  int y0;
  int x1;
  int y1;
};

#define IVTVFB_IOCTL_GET_STATE          _IOR('@', 1, struct ivtvfb_ioctl_state_info)
#define IVTVFB_IOCTL_SET_STATE          _IOW('@', 2, struct ivtvfb_ioctl_state_info)
#define IVTVFB_IOCTL_PREP_FRAME         _IOW('@', 3, struct ivtvfb_ioctl_dma_host_to_ivtv_args)
#define IVTVFB_IOCTL_BLT_COPY           _IOW('@', 4, struct ivtvfb_ioctl_blt_copy_args)
#define IVTVFB_IOCTL_GET_ACTIVE_BUFFER  _IOR('@', 5, struct ivtv_osd_coords)
#define IVTVFB_IOCTL_SET_ACTIVE_BUFFER  _IOW('@', 6, struct ivtv_osd_coords)
#define IVTVFB_IOCTL_GET_FRAME_BUFFER   _IOR('@', 7, struct ivtvfb_ioctl_get_frame_buffer)

#define IVTVFB_STATUS_ENABLED           (1 << 0)
#define IVTVFB_STATUS_GLOBAL_ALPHA      (1 << 1)
#define IVTVFB_STATUS_LOCAL_ALPHA       (1 << 2)
#define IVTVFB_STATUS_FLICKER_REDUCTION (1 << 3)

/* Stream types */
#define IVTV_STREAM_PS		0
#define IVTV_STREAM_TS		1
#define IVTV_STREAM_MPEG1	2
#define IVTV_STREAM_PES_AV	3
#define IVTV_STREAM_PES_V	5
#define IVTV_STREAM_PES_A	7
#define IVTV_STREAM_DVD		10
#define IVTV_STREAM_VCD		11
#define IVTV_STREAM_SVCD	12
#define IVTV_STREAM_DVD_S1	13
#define IVTV_STREAM_DVD_S2	14

/* Custom v4l controls */
#ifndef V4L2_CID_PRIVATE_BASE
#define V4L2_CID_PRIVATE_BASE			0x08000000
#endif

#define V4L2_CID_IVTV_FREQ	(V4L2_CID_PRIVATE_BASE)
#define V4L2_CID_IVTV_ENC	(V4L2_CID_PRIVATE_BASE + 1)
#define V4L2_CID_IVTV_BITRATE	(V4L2_CID_PRIVATE_BASE + 2)
#define V4L2_CID_IVTV_MONO	(V4L2_CID_PRIVATE_BASE + 3)
#define V4L2_CID_IVTV_JOINT	(V4L2_CID_PRIVATE_BASE + 4)
#define V4L2_CID_IVTV_EMPHASIS	(V4L2_CID_PRIVATE_BASE + 5)
#define V4L2_CID_IVTV_CRC	(V4L2_CID_PRIVATE_BASE + 6)
#define V4L2_CID_IVTV_COPYRIGHT	(V4L2_CID_PRIVATE_BASE + 7)
#define V4L2_CID_IVTV_GEN	(V4L2_CID_PRIVATE_BASE + 8)

#define IVTV_V4L2_AUDIO_MENUCOUNT 9 /* # of v4l controls */

#define IVTV_DEC_PRIVATE_BASE	(V4L2_CID_PRIVATE_BASE + IVTV_V4L2_AUDIO_MENUCOUNT)

#define V4L2_CID_IVTV_DEC_SMOOTH_FF	(IVTV_DEC_PRIVATE_BASE + 0)
#define V4L2_CID_IVTV_DEC_FR_MASK	(IVTV_DEC_PRIVATE_BASE + 1)
#define V4L2_CID_IVTV_DEC_SP_MUTE	(IVTV_DEC_PRIVATE_BASE + 2)
#define V4L2_CID_IVTV_DEC_FR_FIELD	(IVTV_DEC_PRIVATE_BASE + 3)
#define V4L2_CID_IVTV_DEC_AUD_SKIP	(IVTV_DEC_PRIVATE_BASE + 4)
#define V4L2_CID_IVTV_DEC_NUM_BUFFERS   (IVTV_DEC_PRIVATE_BASE + 5)
#define V4L2_CID_IVTV_DEC_PREBUFFER     (IVTV_DEC_PRIVATE_BASE + 6)

#define IVTV_V4L2_DEC_MENUCOUNT 7

#ifdef SAA7115_REGTEST
/* allow direct access to the saa7115 registers for testing */
#define SAA7115_GET_REG         0xFFEE7705
#define SAA7115_SET_REG         0xFFEE7706

struct saa7115_reg_t {
	u8 reg;
	u8 val;
};
#endif
struct saa7114 {
	int norm;
	int input;
	int enable;
	int bright;
	int contrast;
	int hue;
	int sat;
	int playback;
};


struct ivtv_cfg_start_decode {
	u32	gop_offset;		/*Frames in GOP to skip before starting */
	u32	muted_audio_frames;	/* #of audio frames to mute */
};

struct ivtv_cfg_stop_decode {
	int	hide_last; /* 1 = show black after stop, 0 = show last frame */
	u64	pts_stop; /* PTS to stop at */
};

struct ivtv_slow_fast {
	int speed; /* 0 = slow, 1 = fast */
	int scale; /* 1-?? (50 for now) */
};

struct ivtv_ioctl_fwapi {
        u32 cmd;
        u32 result;
        int args;
        u32 data[IVTV_MBOX_MAX_DATA];
};      

struct ivtv_ioctl_framesync {
  u32 frame;
  u64 pts;
  u64 scr;
};

struct ivtv_audio_meta {
	        struct v4l2_queryctrl   *ctrl;
	        struct v4l2_querymenu   *menu;
	        u32                     *table;
	        u32                     mask;
	        s32                     setting;
};

/* For use with IVTV_IOC_G_CODEC and IVTV_IOC_S_CODEC */
struct ivtv_ioctl_codec {
	u32 aspect;
	u32 audio_bitmap;
	u32 bframes;
	u32 bitrate_mode;
	u32 bitrate;
	u32 bitrate_peak;
	u32 dnr_mode;
	u32 dnr_spatial;
	u32 dnr_temporal;
	u32 dnr_type;
	u32 framerate;
	u32 framespergop;
	u32 gop_closure;
	u32 pulldown;
	u32 stream_type;
};

extern int ivtv_debug;
extern int ivtv_pal;

/* Scatter-Gather array element, used in DMA transfers */
struct ivtv_SG_element {
	u32 src;
	u32 dst;
	u32 size;
};

/* ivtv-specific mailbox template */
struct ivtv_mailbox {
	u32 flags;
	u32 cmd;
	u32 retval;
	u32 timeout;
	u32 data[IVTV_MBOX_MAX_DATA];
};

struct ivtv_state {
	unsigned long freq; /* Current tuned frequency */
	int input; /* Current digitizer input */
	u32 flags;/* tuner, audio */
	u16 type; /* tv or camera */
	u16 norm; /* Current video standard */
	/* more to come! */
};

struct ivtv_buffer {
	size_t			readpos;
	dma_addr_t		dma_handle;
	struct v4l2_buffer	buffer;
        struct list_head        list;
	unsigned long		ts;
};

struct ivtv_buffer_list {
	struct video_device	*vdev; /* to get itv from */
	int			elements;
        struct list_head        list;
};

struct ivtv_options {
	int yuv_fixup;		/* Should we re-work YUV to a standard format? */
	int yuv_buffers;	/* How many yuv buffers to allocate? */
	int mpg_buffers;	/* how many mpg buffers to allocate? */
	int vbi_buffers;	/* how many vbi buffers to allocate? */
	int dec_mpg_buffers;	/* how many decoder mpg buffers to allocate? */
	int dec_yuv_buffers;	/* How many decoder yuv buffers to allocate? */
	int dec_mpg_qlen;	/* how many decoder mpg buffers to queue? */
	int dec_yuv_qlen;	/* how many decoder yuv buffers to queue? */
	int num_devices;	/* how many cards to detect? */
};

struct ivtv_dec_options {
	int hide_last_frame;	/* 0 = display last frame on stop_decode
				 * 1 = display black */
	u32 pts_low;		/* low bits PTS to stop playback at */
	u32 pts_hi;		/* hi bits  PTS to stop playback at */
	int gop_offset;		/* on start-playback, skip this
				 *  # of frames in the GOP */
	int mute_frames;	/* # of audio frames to mute on playback start */
	int sf_mute;		/* # of audio frames to mute on playback resume */
	int aud_mute;		/* Mute audio while in slow/fast mode */
	int smooth;		/* Smooth mode when in slow/fast mode */
	int fr_mask;		/* 0 = I, 1 = I,P, 2 = I,P,B */
	int fr_field;		/* 1 = show every field, 0 = show every frame */
	int decbuffers;		/* 0 = 6 buffers, 1 = 9 buffers */
	int prebuffer;		/* 0 = no prebuffer, 1 = enabled, see docs */
};

/* per-stream, s_flags */
#define IVTV_F_S_DMAP		0
#define IVTV_F_S_OVERFLOW	1
#define IVTV_F_S_CAP		2

/* per-interface, i_flags */
#define IVTV_F_I_BUSY		0
#define IVTV_F_I_NEEDS_DATA	1
#define IVTV_F_I_EOS		2
#define IVTV_F_I_OSD_DMA	3

struct ivtv_v4l2_stream {
	int			buf_size; /* size of buffers this stream */
	long			id;
	long			seq;
	int			ubytes; /* bytes written back to user this frame */
	unsigned long		s_flags;
	int			v4l_reg_type;
	wait_queue_head_t	waitq;
	struct video_device	v4l2dev;
	struct v4l2_format	format;

	// FIXME need to make sure no read() if streaming
	struct ivtv_buffer_list free_q; /* unused buffers */
	struct ivtv_buffer_list full_q; /* filled buffers */
	struct ivtv_buffer_list dma_q;  /* awaiting dma to fill them */
					/* only updated in interrupt time! */

	int			controlcount; /* Number of elements in controls */
	struct v4l2_control	*controls;
};

struct ivtv_v4l2_table {
	int	count;
	int	active;
	union {
		struct v4l2_input	*input;
		struct v4l2_output	*output;
		struct v4l2_audio	*audio;
		struct v4l2_tuner	*tuner;
		struct v4l2_control	*control;
		struct v4l2_standard	*std;
	} table;
};
		
struct ivtv_v4l2 {
	u32			capabilities;
	struct ivtv_v4l2_table	input;
	int			audio_output;
	struct ivtv_v4l2_table	output;
	struct ivtv_v4l2_table	audio;
	struct ivtv_v4l2_table	tuner;
	struct ivtv_v4l2_table	standard;
	struct v4l2_capability	capability;
	struct v4l2_frequency   freq;
	int			streamcount; /* Number of elements in streams */
	struct ivtv_v4l2_stream	*streams;

        /* codec settings */
        struct ivtv_ioctl_codec codec;
	struct ivtv_audio_meta audio_meta[IVTV_V4L2_AUDIO_MENUCOUNT];

	/* FIXME probably should get rid of this */
	wait_queue_head_t	waitq;
};

struct ivtv_open_id {
        int                     open_id;
        int                     type;
        struct ivtv             *itv;
        struct list_head        list;
};

struct ivtvfb_user_dma_to_device {
  	int page_count;
	struct ivtv_SG_element* sglist;
	struct page **map;
	dma_addr_t sg_dma_handle;
};

/* Stuct to hold info about ivtv cards */
struct ivtv {
	int card_type; /* pvr 250 rev1, 250 rev2, 350 are options so far */
	struct pci_dev *dev;
	struct ivtv_options	options;
	struct ivtv_dec_options	dec_options;
	int num;                /* invalidate during init! */
	int first_read;		/* used to clean up stream */
	unsigned long i_flags;
	atomic_t capturing;
	atomic_t decoding;
	struct semaphore sem_lock;
	spinlock_t lock;

	long	open_id; /* incremented each time an open occurs
			    used as unique ID */

	/* FIXME should use part of v4l2_performace instead */
	unsigned long trans_id; 

	struct tasklet_struct dma_sched_tq;

	u32 enc_fw_ver, dec_fw_ver, base_addr; /*is base_addr needed? */
	u32			irqmask;

       	struct ivtv_mailbox *enc_mbox, *dec_mbox;
	unsigned char card_rev, *io_mem, *reg_mem;

	wait_queue_head_t cap_w, vsync_w;

	/*FIXME perhaps move these to the v4l2_stream struct */
	struct ivtv_SG_element *SGarray, *DSGarray;
	dma_addr_t SG_handle, DSG_handle;

	/* Decoder */
	struct ivtv_ioctl_framesync dec_timestamp;
	wait_queue_head_t dec_master_w;
	struct timer_list dec_timeout;

	/* Framebuffer DMA support */
	struct ivtvfb_user_dma_to_device* user_dma_to_device_state;
	int	fb_id;

	/* i2c */
	struct i2c_adapter         i2c_adap;
	struct i2c_algo_bit_data   i2c_algo;
	struct i2c_client          i2c_client;
	int                        i2c_state, i2c_rc, i2c_command;
	struct i2c_client         *i2c_clients[I2C_CLIENTS_MAX];

	/* v4l2 and User settings*/
	struct ivtv_state	state;
	struct ivtv_v4l2	v4l2;
	struct list_head	client_list;
};

/* Globals */
extern struct ivtv ivtv_cards[];
extern int ivtv_cards_active;
extern int dec_yuv_buffers;
extern int dec_mpg_buffers;
extern int yuv_buffers;
extern int mpg_buffers;
extern int vbi_buffers;
extern spinlock_t ivtv_lock;

/*==============Prototypes==================*/
/* FIXME some of these proably need fine-tuning 
 *  to avoid warnings
 */

/* i2c implementation */
#ifndef NEW_I2C
/* pre i2c-2.8.0 */
void ivtv_i2c_inc(struct i2c_adapter *adapter);
void ivtv_i2c_dec(struct i2c_adapter *adapter);
#else
/* i2c-2.8.0 and later */
#endif

void ivtv_setscl(void *data, int state);
void ivtv_setsda(void *data, int state);
int ivtv_getscl(void *data);
int ivtv_getsda(void *data);

void ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg);
int ivtv_i2c_direct(struct ivtv *itv, int addr, const unsigned char *regs);

void ivtv_inc(struct i2c_adapter *adapter);
void ivtv_dec(struct i2c_adapter *adapter);

/* init + register i2c algo-bit adapter */
int __devinit init_ivtv_i2c(struct ivtv *itv);
void __devexit exit_ivtv_i2c(struct ivtv *itv);

/* end i2c stuff */

/* Initialization stuff */
int  ivtv_ceil(int x, int y);
int  ivtv_firmware_copy(struct ivtv *itv);
int  ivtv_firmware_init(struct ivtv *itv);
int  ivtv_firmware_versions(struct ivtv *itv);

/* Unload stuff */
void ivtv_v4l2_cleanup(struct ivtv *itv);
int  ivtv_stop_firmware(struct ivtv *itv);
void ivtv_zero_usage_count(void);

/* API Related */
int ivtv_find_firmware_mailbox(struct ivtv *itv);
int ivtv_get_free_mailbox(struct ivtv_mailbox *mbox);
int ivtv_api_call(struct ivtv_mailbox *mbox, u32 cmd,  struct semaphore *sem,
	       	int elements, u32 data[]);
int ivtv_api_getresult_nosleep(struct ivtv_mailbox *mbox, u32 *result, u32 data[]);
int ivtv_api_getresult(struct ivtv_mailbox *mbox, struct semaphore *sem,
		u32 *result, u32 data[]);
int ivtv_api(struct ivtv_mailbox *mbox, struct semaphore *sem, int cmd,
		u32 *result, int args, u32 data[]);
extern int __ivtv_api(struct ivtv_mailbox *mbox, int cmd,
		u32 *result, int args, u32 data[]);
int ivtv_v4l2_setup(struct ivtv *itv);

/* Capture related */
int ivtv_stop_all_captures(struct ivtv *itv);
int ivtv_stop_capture(struct ivtv_open_id *id);
long ivtv_read(struct ivtv_open_id *id, char *ubuf, size_t count, int block);
int ivtv_get_timing_info(struct ivtv *itv, struct ivtv_ioctl_framesync *info);
ssize_t ivtv_write(struct ivtv_open_id *id, const char *buf, size_t count);
int ivtv_stream_has_data(struct ivtv_open_id *id);
unsigned int ivtv_poll(struct file *filp, poll_table *wait);
unsigned int ivtv_dec_poll(struct file *filp, poll_table *wait);
	/* Adds buffers to the tail, effectively making a queue */
int ivtv_enq_buf(struct ivtv *itv, struct ivtv_buffer_list *queue, struct ivtv_buffer *buf);
	/* returns first item in queue, doesn't dequeue */
struct ivtv_buffer *ivtv_deq_peek_head(struct ivtv *itv, struct ivtv_buffer_list *queue);
	/* removes buffer from the head */
struct ivtv_buffer *ivtv_deq_buf(struct ivtv *itv, struct ivtv_buffer_list *queue);
	/* allocates a buffer, returns it */
struct ivtv_buffer *ivtv_init_buffer(int gfp_flags);
	/* removes/frees all items in a queue */
int ivtv_free_queue(struct ivtv_buffer_list *queue);
	/* makes a queue complete with 'length' items */
	/* NOTE: This returns the # of buffers allocated */
int ivtv_init_queue(struct ivtv *itv,struct ivtv_buffer_list *queue, int length,
		    enum v4l2_buf_type type);
	/* moves all items in queue 'src' to queue 'dst' */
int ivtv_move_queue(struct ivtv *itv, struct ivtv_buffer_list *src, struct ivtv_buffer_list *dst);

/* Hardware/IRQ */
void ivtv_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
void ivtv_DMA_done(struct ivtv *itv);
void ivtv_sched_DMA(struct ivtv *itv);
void ivtv_dec_DMA_done(struct ivtv *itv);
void ivtv_dec_sched_DMA(struct ivtv *itv);
extern void ivtv_set_irq_mask(struct ivtv *itv, unsigned long mask);
extern void ivtv_clear_irq_mask(struct ivtv *itv, unsigned long mask);
extern void ivtv_sleep_timeout(int timeout);

/* Testing/Debugging */
int  ivtv_close(struct ivtv_open_id *id);
void ivtv_print_boxes(struct ivtv_mailbox *mbox);
int  tmk_test2(struct inode *inode, struct file *filep);
int  tmk_test1(struct inode *inode, struct file *filep);

/* debug stuff, to get the locking right */
#ifndef WARN_ON
#define WARN_ON(condition) do { \
	if (unlikely((condition)!=0)) { \
		printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \
		dump_stack(); \
	} \
} while (0)
#endif

#define IVTV_ASSERT(x)	WARN_ON(!(x))

static inline int ivtv_sem_count(struct semaphore *sem)
{
	return atomic_read(&sem->count);
}

#endif
