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

#include "ivtv.h"

/* mini header */

/* var to keep track of the number of array elements in use */
int ivtv_cards_active;

/* Master variable for all ivtv info */
struct ivtv ivtv_cards[IVTV_MAX_CARDS];

/* for the global data */
spinlock_t ivtv_lock = SPIN_LOCK_UNLOCKED;

/* add your revision and whatnot here */
static struct pci_device_id ivtv_pci_tbl[] __devinitdata = {
		{PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV15,
		 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
		{PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV16,
		 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
		{0,}
};

static int __devinit ivtv_probe(struct pci_dev *dev,
				const struct pci_device_id *pci_id);

static void ivtv_remove(struct pci_dev *pci_dev);
static int load_fw_direct(const char *fn, char *mem);
struct ivtv_mailbox* ivtv_api_irqsafe(struct ivtv_mailbox *mbox, u32 cmd,
				      int args, const u32* data);
void ivtv_irq_dec_vsync(struct ivtv* itv);

u32 ivtv_firm_search_id[] = {0x12345678,0x34567812,0x56781234,0x78123456};

/*FIXME for testing stuff via ioctl */
unsigned int hack = 0;

/* Parameter declarations */
static int num_devices = 1;
static int yuv_buffers = 60;
static int mpg_buffers = 100;
static int vbi_buffers = 10;
static int dec_mpg_buffers = 8;
static int dec_yuv_buffers;
static int dec_mpg_qlen = 2;
static int dec_yuv_qlen;
#ifdef YUV_FIXUP
static int yuv_fixup;
#endif

int ivtv_pal = 0;


/* low debugging by default */
#if 0
int debug = ( 	IVTV_DEBUG_ERR | IVTV_DEBUG_INFO  | IVTV_DEBUG_API
		| IVTV_DEBUG_DMA | IVTV_DEBUG_IOCTL | IVTV_DEBUG_I2C 
		| IVTV_DEBUG_IRQ );
#endif
int ivtv_debug = IVTV_DEBUG_ERR;

/* tuner.h tuner type for ivtv card */
int tuner = -1;

int errno;

#ifdef YUV_FIXUP
MODULE_PARM(yuv_fixup, "i");
MODULE_PARM_DESC(yuv_fixup,
		 "\nToggles conversion of Hauppauge Macroblock NV12 to NV12\n");
#endif

MODULE_PARM(tuner, "i");
MODULE_PARM_DESC(tuner, "\nTuner type selection, see tuner.h for values\n");

MODULE_PARM(yuv_buffers, "i");
MODULE_PARM_DESC(yuv_buffers,
		 "\nNumber of 32K buffers for copying YUV. Default: 60, Min: 40\n");

MODULE_PARM(mpg_buffers, "i");
MODULE_PARM_DESC(mpg_buffers,
		 "\nNumber of 32K buffers for copying mpg. Default: 30, Min.: 10\n");

MODULE_PARM(vbi_buffers, "i");
MODULE_PARM_DESC(vbi_buffers,
		 "\nNumber of 32K buffers for copying VBI. Default: 10, Min: 3\n");

MODULE_PARM(num_devices, "i");
MODULE_PARM_DESC(num_devices, "\nNumber of supported devices (1-9). Default: 1\n");

MODULE_PARM(dec_mpg_buffers, "i");
MODULE_PARM_DESC(dec_mpg_buffers,
		 "\nNumber of 32K buffers for decoding MPG. Default: 8, Min: 7\n");

MODULE_PARM(dec_yuv_buffers, "i");
MODULE_PARM_DESC(dec_yuv_buffers,
		 "\nNumber of 32K buffers for decoding YUV. Default: 35, Min: 17, 0 to disable\n");

MODULE_PARM(dec_mpg_qlen, "i");
MODULE_PARM_DESC(dec_mpg_qlen, 
		 "\nNumber of 32K buffers to queue before dispatching to decoder\n"
		 "Default: 2, Min:0, Max: <dec_mpg_buffers>\n");

MODULE_PARM(dec_yuv_qlen, "i");
MODULE_PARM_DESC(dec_yuv_qlen, 
		 "\nNumber of 32K buffers to queue before dispatching to decoder\n"
		 "Default: 0, Min:0, Max: <dec_yuv_buffers>\n");

MODULE_PARM(ivtv_debug, "i");
MODULE_PARM_DESC(ivtv_debug, "\nDebug level (bitmask), default, errors only\n"
		             "(debug=127 gives full debuging)\n");

MODULE_PARM(ivtv_pal, "i");
MODULE_PARM_DESC(ivtv_pal, "Use PAL as default video mode instead of NTSC\n");

MODULE_AUTHOR("Kevin Thayer");
MODULE_DESCRIPTION("Alpha iTVC15 driver");
MODULE_SUPPORTED_DEVICE("iTVC15/16 mpg2 encoder (aka WinTV PVR 250/350)\n");
MODULE_LICENSE("GPL");

int SGarray_size = 0;
int DSGarray_size = 0;

void ivtv_sleep_timeout(int timeout)
{
	int sleep = timeout;

	do {
		set_current_state(TASK_UNINTERRUPTIBLE);
		sleep = schedule_timeout(sleep);
	} while (sleep);
}

/* ceiling function for ints.. */
int ivtv_ceil(int x, int y) {
        int floor = (int)(x/y);
        if( (floor * y) < x)
		return floor+1;
        return floor;
}

/* Release ioremapped memory */
static void ivtv_iounmap(struct ivtv *itv) {
    if (itv == NULL)
	return ;
    // Release io memory 
    if (itv->io_mem != NULL) {
	IVTV_DEBUG(IVTV_DEBUG_INFO, "releasing iomem\n");
        iounmap(itv->io_mem);
	itv->io_mem = NULL ;
    }
    // Release registers memory
    if (itv->reg_mem != NULL) {
	IVTV_DEBUG(IVTV_DEBUG_INFO, "releasing regmem\n");
        iounmap(itv->reg_mem);
	itv->reg_mem = NULL ;
    }
    // Release encoder mailboxes
    if (itv->enc_mbox != NULL) {
	IVTV_DEBUG(IVTV_DEBUG_INFO, "releasing encmbox\n");
	iounmap(itv->enc_mbox);
	itv->enc_mbox = NULL ;
    }
    // Release decoder mailboxes
    if (itv->dec_mbox != NULL) {
	IVTV_DEBUG(IVTV_DEBUG_INFO, "releasing decmbox\n");
	iounmap(itv->dec_mbox);
	itv->dec_mbox = NULL ;
    }
}

/* must only be used as hints, not as a definitive answer. the answer could
 * be wrong as soon as we return */
int ivtv_get_free_elements(struct ivtv *itv, struct ivtv_buffer_list *queue)
{
	unsigned long flags;
	int elements;

	spin_lock_irqsave(&itv->lock, flags);
	elements = queue->elements;
	spin_unlock_irqrestore(&itv->lock, flags);

	return elements;
}

void __ivtv_enq_buf(struct ivtv_buffer_list *queue, struct ivtv_buffer *buf) {
	list_add_tail(&buf->list, &queue->list);
	queue->elements++;
}


/* 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) {
	unsigned long flags;

	spin_lock_irqsave(&itv->lock, flags);
	__ivtv_enq_buf(queue, buf);
	spin_unlock_irqrestore(&itv->lock, flags);

	return 0;
}

inline void __ivtv_del_buf(struct ivtv_buffer_list *queue,
			   struct ivtv_buffer *buffer) {
	list_del_init(&buffer->list);
	queue->elements--;
}

/* called to remove the buffer returned by _peek_ functions */
void ivtv_del_buf(struct ivtv *itv, struct ivtv_buffer_list *queue,
		  struct ivtv_buffer *buffer) {
	unsigned long flags;

	spin_lock_irqsave(&itv->lock, flags);
	__ivtv_del_buf(queue, buffer);
	spin_unlock_irqrestore(&itv->lock, flags);
}

/* returns first item in queue, doesn't dequeue */
struct ivtv_buffer *__ivtv_deq_peek_head(struct ivtv_buffer_list *queue) {
	struct ivtv_buffer *buf;

	/* make sure list has something to DeQ */
	if (list_empty(&queue->list)) {
		IVTV_DEBUG(IVTV_DEBUG_INFO,"DeQ from empty list!\n");
		queue->elements = 0;
		return NULL;
	}

	/* grab next element of the queue */
	return list_entry(queue->list.next, struct ivtv_buffer, list);
}

struct ivtv_buffer *ivtv_deq_peek_head(struct ivtv *itv,
				       struct ivtv_buffer_list *queue) {
	unsigned long flags;
	struct ivtv_buffer *buffer;

	spin_lock_irqsave(&itv->lock, flags);
	buffer = __ivtv_deq_peek_head(queue);
	spin_unlock_irqrestore(&itv->lock, flags);

	return buffer;
}

/* removes buffer from the head */
struct ivtv_buffer *__ivtv_deq_buf(struct ivtv_buffer_list *queue) {
	struct ivtv_buffer *buf;

	/* make sure list has something to DeQ */
	if (list_empty(&queue->list)) {
		IVTV_DEBUG(IVTV_DEBUG_INFO,"DeQ from empty list!\n");
		queue->elements = 0;
		return NULL;
	}

	/* grab next element of the queue */
	buf = list_entry(queue->list.next, struct ivtv_buffer, list);
	
	/* free it from the queue */
	list_del(queue->list.next);
	
	queue->elements--;

	return buf;
}

struct ivtv_buffer *ivtv_deq_buf(struct ivtv *itv,
				 struct ivtv_buffer_list *queue) {
	struct ivtv_buffer *buf;
	unsigned long flags;

	spin_lock_irqsave(&itv->lock, flags);
	buf = __ivtv_deq_buf(queue);
	spin_unlock_irqrestore(&itv->lock, flags);

	return buf;
}

struct ivtv_buffer *ivtv_init_buffer(int gfp_mask) {
	struct ivtv_buffer *ibuf;

	ibuf = kmalloc(sizeof(struct ivtv_buffer), gfp_mask);
	if (ibuf == NULL) {
		IVTV_DEBUG(IVTV_DEBUG_ERR,"No mem on ibuf alloc!\n");
		return NULL;
	}

	(void *)ibuf->buffer.m.userptr = kmalloc(IVTV_DMA_BUF_SIZE, gfp_mask);
	if ((void *)ibuf->buffer.m.userptr == NULL) {
		kfree(ibuf);
		IVTV_DEBUG(IVTV_DEBUG_ERR,"No mem on buf alloc!\n");
		return NULL;
	}

	ibuf->buffer.length	= IVTV_DMA_BUF_SIZE;
	ibuf->buffer.bytesused	= 0;
	ibuf->readpos		= 0;

	return ibuf;
}

#define IVTV_DMA_UNMAPPED	((u32) -1)

void ivtv_free_buffer(struct ivtv *itv, struct ivtv_buffer *item) {
	if (item->dma_handle != IVTV_DMA_UNMAPPED)
		pci_unmap_single(itv->dev, item->dma_handle, IVTV_DMA_BUF_SIZE, PCI_DMA_TODEVICE);
	if (item->buffer.m.userptr) {
		IVTV_DEBUG(IVTV_DEBUG_INFO,"Freeing buf %d!\n", item->buffer.index);
		kfree((void *)item->buffer.m.userptr);
	}
	kfree(item);
}

int ivtv_free_queue(struct ivtv_buffer_list *queue) {
        struct ivtv_buffer *item;
	unsigned long flags;
	struct ivtv *itv;
	int x;

	if (queue == NULL) {
		IVTV_DEBUG(IVTV_DEBUG_ERR,"Free on NULL list!\n");
		return -EINVAL;
	}

	spin_lock_irqsave(&ivtv_lock, flags);

	/* FIXME ugly */
	/* verify ivtv before continuing */
	itv = NULL;
	for (x = 0; x < ivtv_cards_active; x++) {
		if (queue->vdev->priv == &ivtv_cards[x]) {
			itv = queue->vdev->priv;
			break;
		}
	}

	spin_unlock_irqrestore(&ivtv_lock, flags);

	if (itv == NULL)
		return -ENODEV;

	while ((item = ivtv_deq_buf(itv, queue)))
		ivtv_free_buffer(itv, item);

	return 0;
}

/* 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) {
	int x;
	struct ivtv_buffer *item;

	/* Just in case */
	INIT_LIST_HEAD(&queue->list);
	
	for (x=0;x < length; x++) {
		// allocate buffer
		item = ivtv_init_buffer(GFP_KERNEL);
		if (item == NULL) {
			IVTV_DEBUG(IVTV_DEBUG_ERR,"Buffer alloc failed!\n");
			return x;
		}
		
		// setup buffer
		item->buffer.index = x;
		item->buffer.type = type;
		item->buffer.field = V4L2_FIELD_INTERLACED;
		item->buffer.memory = V4L2_MEMORY_MMAP;
		
		// enqueue buffer
		ivtv_enq_buf(itv, queue, item);
	}

	return x;
}

int ivtv_move_queue(struct ivtv *itv, struct ivtv_buffer_list *src,
		    struct ivtv_buffer_list *dst) {
	struct ivtv_buffer *buf;
	unsigned long flags;

	spin_lock_irqsave(&itv->lock, flags);

  	while ((buf = __ivtv_deq_buf(src)))
		__ivtv_enq_buf(dst, buf);

	spin_unlock_irqrestore(&itv->lock, flags);
	return 0;
}

static int load_fw_direct(const char *fn, char *mem) {
        int fd;
        long l;
	mm_segment_t fs = get_fs();

	set_fs(get_ds());

        if ( (fd = open(fn, 0, 0)) == -1) {
                printk(KERN_INFO "Unable to open '%s'.\n", fn);
		l = -EINVAL;
		goto out;
        }
	/* the 2 means SEEK_END */
        l = lseek(fd, 0L, 2);

        if (l <= 0 || l > IVTV_FIRM_IMAGE_SIZE) {
                printk(KERN_INFO "Firmware image too large '%s'\n", fn);
		l = -ENOMEM;
		goto out;
        }

	/* the 2 means SEEK_SET */
        lseek(fd, 0L, 0);

        if (read(fd, mem, l) != l){
                printk(KERN_INFO "Failed to read '%s'.\n", fn);
		l = -ENOMEM;
        }

out:
	close(fd);
	set_fs(fs);

	return (int) l;
}

int ivtv_firmware_copy(struct ivtv *itv) {

        IVTV_DEBUG(IVTV_DEBUG_INFO, "Loading encoder image\n");

        if (load_fw_direct(IVTV_FIRM_ENC_FILENAME,
			   (char *)(itv->io_mem + IVTV_ENC_MEM_START)) !=
			   IVTV_FIRM_IMAGE_SIZE) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "failed loading encoder firmware\n");
		return -3;
	}


	if (itv->card_type != IVTV_250_V2) {
                IVTV_DEBUG(IVTV_DEBUG_INFO, "Loading decoder firmware\n");
                if (load_fw_direct(IVTV_FIRM_DEC_FILENAME,
				   (char *)(itv->io_mem + IVTV_DEC_MEM_START)) !=
				   IVTV_FIRM_IMAGE_SIZE) {
			IVTV_DEBUG(IVTV_DEBUG_ERR,
				   "failed loading decoder firmware\n");
			return -1;
		}
	}

	return 0;
}


int ivtv_stop_firmware(struct ivtv *itv) {
	u32 data[IVTV_MBOX_MAX_DATA], result;
	int x = 0;

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping firmware\n");

	if (atomic_read(&itv->capturing)) {
		x = ivtv_stop_all_captures(itv);
		if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stop_fw error 1. Code %d\n",x);
	}
		
	/*Stop decoder_playback */
	data[0] = 1; /* 0: render last frame, 1: stop NOW! :) */
	data[1] = 0; /* "low 4 bytes of stop index" */
	data[2] = 0; /* 0: stop immedeately */
        x = ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_DEC_STOP_PLAYBACK,
		&result, 3, &data[0]);
	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stop_fw error 2. Code %d\n",x);
		
	/*halt enc firmware */
        x = ivtv_api(itv->enc_mbox, &itv->sem_lock, IVTV_API_ENC_HALT_FW,
		&result, 0, &data[0]);
	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stop_fw error 3. Code %d\n",x);
		
	IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 10ms\n");
	ivtv_sleep_timeout(HZ/100);
	
	/*halt dec firmware */
	if (IVTV_250_V2 != itv->card_type) {
        	x = ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_DEC_HALT_FW,
			&result, 0, &data[0]);
		if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stop_fw error 4. Code %d\n",x);
		
		IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 10ms\n");
		ivtv_sleep_timeout(HZ/100);
	}
	
	return 0;
}

int ivtv_firmware_init(struct ivtv *itv) {
	int x;

	/* check that we're not RE-loading firmware */
	/*  a sucessful load will have detected HW  */
	/*  mailboxes. */

	/* FIXME i dont think this will ever get called */
	if (NULL != itv->enc_mbox) {
		IVTV_DEBUG(IVTV_DEBUG_INFO, "readying card for firmware upload\n");
		x = ivtv_stop_firmware(itv);
		if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "Error %d, stopping firmware\n", x);
	}

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping VDM\n");
	writel(IVTV_CMD_VDM_STOP, (IVTV_REG_VDM + itv->reg_mem));

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping AO\n");
	writel(IVTV_CMD_AO_STOP, (IVTV_REG_AO + itv->reg_mem));

	IVTV_DEBUG(IVTV_DEBUG_INFO, "pinging (?) APU\n");
	writel(IVTV_CMD_APU_PING, (IVTV_REG_APU + itv->reg_mem));

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping VPU\n");
	if (IVTV_250_V2 == itv->card_type) {
		writel(IVTV_CMD_VPU_STOP16, (IVTV_REG_VPU + itv->reg_mem));
	}
	else {
		writel(IVTV_CMD_VPU_STOP15, (IVTV_REG_VPU + itv->reg_mem));
	}

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Resetting Hw Blocks\n");
	writel(IVTV_CMD_HW_BLOCKS_RST, (IVTV_REG_HW_BLOCKS + itv->reg_mem));

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping SPU\n");
	writel(IVTV_CMD_SPU_STOP, (IVTV_REG_SPU + itv->reg_mem));

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 10ms\n");
	ivtv_sleep_timeout(HZ/100);

	IVTV_DEBUG(IVTV_DEBUG_INFO, "init Encoder SDRAM pre-charge\n");
	writel(IVTV_CMD_SDRAM_PRECHARGE_INIT,
		       (IVTV_REG_ENC_SDRAM_PRECHARGE + itv->reg_mem));
	
	IVTV_DEBUG(IVTV_DEBUG_INFO, "init Encoder SDRAM refresh to 1us\n");
	writel(IVTV_CMD_SDRAM_REFRESH_INIT,
		       (IVTV_REG_ENC_SDRAM_REFRESH + itv->reg_mem));
	
	IVTV_DEBUG(IVTV_DEBUG_INFO, "init Decoder SDRAM pre-charge\n");
	writel(IVTV_CMD_SDRAM_PRECHARGE_INIT,
		       (IVTV_REG_DEC_SDRAM_PRECHARGE + itv->reg_mem));

	IVTV_DEBUG(IVTV_DEBUG_INFO, "init Decoder SDRAM refresh to 1us\n");
	writel(IVTV_CMD_SDRAM_REFRESH_INIT,
		       (IVTV_REG_DEC_SDRAM_REFRESH + itv->reg_mem));
	
	IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for %dms (600 recommended)\n",(int)IVTV_SDRAM_SLEEPTIME);
	ivtv_sleep_timeout(IVTV_SDRAM_SLEEPTIME);

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Card ready for firmware!\n");
	x = ivtv_firmware_copy(itv);
	if (x) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Error loading firmware!\n");
		return x;
	}

	/*I guess this is read-modify-write :)*/
	writel((readl(itv->reg_mem + IVTV_REG_SPU)&IVTV_MASK_SPU_ENABLE),
			(IVTV_REG_SPU+itv->reg_mem));

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 1 sec\n");
	ivtv_sleep_timeout(HZ);
	
	/*I guess this is read-modify-write :)*/
	if (IVTV_250_V2 == itv->card_type) {
		writel((readl(itv->reg_mem + IVTV_REG_VPU)&IVTV_MASK_VPU_ENABLE16),
			(IVTV_REG_VPU+itv->reg_mem));
	}
	else {
		writel((readl(itv->reg_mem + IVTV_REG_VPU)&IVTV_MASK_VPU_ENABLE15),
			(IVTV_REG_VPU+itv->reg_mem));
	}

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 1 sec\n");
	ivtv_sleep_timeout(HZ);

	/* FIXME Send Status API commands to encoder and decoder to verify!*/

	return 0;
}

int ivtv_find_firmware_mailbox(struct ivtv *itv) {
	u32 *searchptr, *result;
	int match = 0;

	searchptr = NULL;
	result    = NULL;

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Searching for encoder mailbox\n");
	searchptr =(u32 *)(IVTV_FIRM_SEARCH_ENCODER_START + itv->io_mem);

	while (searchptr < (u32 *)(IVTV_FIRM_SEARCH_ENCODER_END + itv->io_mem)) {
		if (ivtv_firm_search_id[match] == readl(searchptr)) {
			(u32)result = (u32)searchptr+4; /* avoid pointer aritmetic */
			match++;
			while ((match > 0) && (match < 4)) {
				IVTV_DEBUG(IVTV_DEBUG_INFO, "match: 0x%08x at "
					   "0x%08x. match: %d\n", *result, 
					   (u32)result, match);
				if (ivtv_firm_search_id[match] == readl(result)) {
					match++;
					/* FIXME change to just "result++;" ? */
					(u32)result =  (u32)result + 4;
				}
				else 
					match = 0;
			}
		}
		else {
			IVTV_DEBUG(IVTV_DEBUG_INFO, ".");
		}
		if ( 4 == match ) {
			IVTV_DEBUG(IVTV_DEBUG_INFO, "found encoder mailbox!\n");
			itv->enc_mbox = (struct ivtv_mailbox *) result;
			break;
		}
		(u32)searchptr += IVTV_FIRM_SEARCH_STEP;
	}
	if (itv->enc_mbox == NULL) IVTV_DEBUG(IVTV_DEBUG_ERR, "Encoder mailbox not found\n");

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Searching for decoder mailbox\n");
	match = 0;
	searchptr = (u32 *)(IVTV_FIRM_SEARCH_DECODER_START + itv->io_mem);

	while (searchptr < (u32 *)(IVTV_FIRM_SEARCH_DECODER_END + itv->io_mem)) {
		if (ivtv_firm_search_id[match] == readl(searchptr)) {
			(u32)result = (u32)searchptr+4;  /* avoid pointer aritmetic */
			match++;
			while ((match > 0) && (match < 4)) {
				IVTV_DEBUG(IVTV_DEBUG_INFO, "match: 0x%08x at 0x%08x. match: %d\n", 
					*result, (u32)result, match);
				if (ivtv_firm_search_id[match] == readl(result)) {
					match++;
					/* FIXME change to just "result++;" ? */
					(u32)result =  (u32)result + 4;
				}
				else 
					match = 0;
			}
		}
		else {
			IVTV_DEBUG(IVTV_DEBUG_INFO, ".");
		}
		if ( 4 == match ) {
			IVTV_DEBUG(IVTV_DEBUG_INFO, "found decoder mailbox!\n");
			itv->dec_mbox = (struct ivtv_mailbox *) result;
			break;
		}
		(u32)searchptr += IVTV_FIRM_SEARCH_STEP;
	}
	if (itv->dec_mbox == 0) IVTV_DEBUG(IVTV_DEBUG_ERR, "Decoder mailbox not found\n");

	return 0;
}

int ivtv_get_free_mailbox(struct ivtv_mailbox *mbox) {
	int i = 0;
	if (NULL == mbox) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Can't get mailbox from NULL\n");
		return -ENODEV;
	}

	for (i = 0; i < IVTV_MBOX_API_BOXES; i++) {
		/* Atomic test and set */
		/* bit 0 = IVTV_MBOX_IN_USE */
		if (!test_and_set_bit(0, &mbox[i].flags)) { 
			IVTV_DEBUG(IVTV_DEBUG_API, "got free mailbox: %d\n", i);
			return i;
		}

		/* Recycle mailbox if possible (first to avoid 
		 * race conditions): */
		if (readl(&mbox[i].flags) & IVTV_MBOX_FIRMWARE_DONE) {
			writel(IVTV_MBOX_FREE, &mbox[i].flags);
			IVTV_DEBUG(IVTV_DEBUG_API, "recycled mailbox: %d\n", i);
			return i;
		}
	}

	IVTV_DEBUG(IVTV_DEBUG_ERR, "no free mailboxes!\n");
	return -ENODEV;
}

void ivtv_clear_irq_mask(struct ivtv *itv, unsigned long mask) {
	itv->irqmask &= ~mask;
	writel(itv->irqmask,(itv->reg_mem + IVTV_REG_IRQMASK));
	/* pci posting */
	readl(itv->reg_mem + IVTV_REG_IRQMASK);
}

void ivtv_set_irq_mask(struct ivtv *itv, unsigned long mask) {
	itv->irqmask |= mask;
	writel(itv->irqmask,(itv->reg_mem + IVTV_REG_IRQMASK));
	/* pci posting */
	readl(itv->reg_mem + IVTV_REG_IRQMASK);
}

/** 
 * Call ivtv api function using given mailbox, without locking sem.
 */
int __ivtv_api_call(struct ivtv_mailbox *mbox, u32 cmd,	int elements, const u32* data) {
	int x;
	writel(IVTV_MBOX_IN_USE, &mbox->flags);
	readl(&mbox->flags);
	writel(cmd, &mbox->cmd);
	writel(IVTV_API_STD_TIMEOUT, &mbox->timeout);

	for (x = 0; x < IVTV_MBOX_MAX_DATA; x++) {
		if (x < elements) {
			writel(data[x], &mbox->data[x]);
		} else {
			writel(0, &mbox->data[x]);
		}
	}

	writel((IVTV_MBOX_DRIVER_DONE | IVTV_MBOX_IN_USE), &mbox->flags);
	readl(&mbox->flags);

	return 0;
}

int ivtv_api_call(struct ivtv_mailbox *mbox, u32 cmd, struct semaphore *sem,
	       	int elements, u32 data[]) {
	
	if (NULL == mbox) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "invalid api mailbox\n");
		return -ENODEV;
	}

	if (down_interruptible(sem)) return -ERESTARTSYS;
		__ivtv_api_call(mbox, cmd, elements, data);
	up(sem);

	return 0;
}

/* This one is for stuff that can't sleep.. irq handlers, etc.. */
int ivtv_api_getresult_nosleep(struct ivtv_mailbox *mbox, u32 *result, u32 data[]) {
	u32 readdata;
	int count = 0;

	if (NULL == mbox) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "invalid api mailbox\n");
		return -ENODEV;
	}

	readdata = readl(&mbox->flags);

	*result = readl(&mbox->retval);
	for ( count=0; count < IVTV_MBOX_MAX_DATA; count++)
		data[count] = readl(&mbox->data[count]);

	return 0;
}

int __ivtv_api_getresult(struct ivtv_mailbox *mbox, u32 *result, u32 data[]) {
	u32 readdata;
	int count = 0;

	readdata = readl(&mbox->flags);

	while (!(readdata & IVTV_MBOX_FIRMWARE_DONE)) {
		/*FIXME this is a bad method*/
		IVTV_DEBUG(IVTV_DEBUG_API, "[%d]mailbox not ready, sleeping for 10ms\n", count);
		ivtv_sleep_timeout(HZ/100);
		readdata = readl(&mbox->flags);
		/*will this work? heh hope so */
		if (count++ > 100) {
			IVTV_DEBUG(IVTV_DEBUG_ERR, "timed out waiting for firmware\n");
			return -EBUSY;
		}
	}

	*result = readl(&mbox->retval);
	for ( count=0; count < IVTV_MBOX_MAX_DATA; count++)
		data[count] = readl(&mbox->data[count]);

	return 0;
}

int ivtv_api_getresult(struct ivtv_mailbox *mbox, struct semaphore *sem,
		u32 *result, u32 data[]) {

	if (down_interruptible(sem))
		return -ERESTARTSYS;

	__ivtv_api_getresult(mbox, result, data);

	up(sem);
	return 0;
}

int ivtv_api(struct ivtv_mailbox *mbox, struct semaphore *sem, int cmd,
		u32 *result, int args, u32 data[]) {
	int x=0;

	IVTV_DEBUG(IVTV_DEBUG_API, "API Call: 0x%08x\n", cmd);

	/* check args */
	if (args > IVTV_MBOX_MAX_DATA) return -EINVAL;
	
	/*grab a mailbox*/ 
	IVTV_DEBUG(IVTV_DEBUG_API, "getting mailbox\n");
	if ((x = ivtv_get_free_mailbox(mbox)) < 0 )
		return x;

	/* move to the next mailbox */
	mbox += x;
	switch (cmd) {
		/* these don't care if they complete. 
		case IVTV_API_ENC_HALT_FW:
		case IVTV_API_DEC_HALT_FW:
			x = ivtv_api_call(mbox,cmd,sem,args,&data[0]);
			break;*/
		case IVTV_API_SCHED_DMA_TO_HOST:
		case IVTV_API_DEC_DMA_FROM_HOST:
			x = ivtv_api_call(mbox,cmd,sem,args,&data[0]);
			return x;
		default:
			x = ivtv_api_call(mbox,cmd,sem,args,&data[0]);
			if (x) break;
			x = ivtv_api_getresult(mbox,sem,result,&data[0]);
			IVTV_DEBUG(IVTV_DEBUG_API, "retval: 0x%08x\n", *result);
			break;
	}
	IVTV_DEBUG(IVTV_DEBUG_API, "Releasing mailbox (before 0x%08x, ", readl(&mbox->flags));
	writel(0x00000000, &mbox->flags);
	IVTV_DEBUG(IVTV_DEBUG_API, "after 0x%08x )\n", readl(&mbox->flags));
	return x;
	
}

struct ivtv_mailbox* ivtv_api_irqsafe(struct ivtv_mailbox *mbox, u32 cmd, int args, const u32* data) {
	int mboxid = 0;	
	IVTV_DEBUG(IVTV_DEBUG_API, "API Call (non-blocking): 0x%08x\n", cmd);

	if ((mboxid = ivtv_get_free_mailbox(mbox)) < 0)
		return NULL;

	__ivtv_api_call(&mbox[mboxid], cmd, args, data);
	return &mbox[mboxid];
}

int __ivtv_api(struct ivtv_mailbox *mbox, int cmd, u32 *result, int args, u32 data[]) {
	int mboxid, rc;

	IVTV_DEBUG(IVTV_DEBUG_API, "API Call: 0x%08x\n", cmd);

	if ((mboxid = ivtv_get_free_mailbox(mbox)) < 0)
		return mboxid;

	rc = __ivtv_api_call(&mbox[mboxid], cmd, args, &data[0]);
	if (rc) return rc;

	rc = __ivtv_api_getresult(mbox, result, &data[0]);
	writel(0, &mbox->flags);
	readl(&mbox->flags);
	return rc;
}

int ivtv_firmware_versions(struct ivtv *itv) {
	u32 data[IVTV_MBOX_MAX_DATA], result;
	int x;

	/* Encoder */	
	IVTV_DEBUG(IVTV_DEBUG_INFO, "Getting encoder firmware rev.\n");
	x = ivtv_api(itv->enc_mbox, &itv->sem_lock, IVTV_API_ENC_GETVER,
			&result, 0, &data[0]);
	if (x) {
		IVTV_DEBUG(IVTV_DEBUG_ERR,
			   "error getting Encoder firmware version\n");
	}
	else	{
		IVTV_DEBUG(IVTV_DEBUG_ERR,
			   "Encoder revision: 0x%08x\n", data[0]);
	}

	if (itv->card_type != IVTV_250_V2) {
		/* Decoder */	
		IVTV_DEBUG(IVTV_DEBUG_INFO, "Getting decoder firmware rev.\n");
		x = ivtv_api(itv->dec_mbox, &itv->sem_lock, IVTV_API_DEC_GETVER,
			&result, 0, &data[0]);
		if (x) {
			IVTV_DEBUG(IVTV_DEBUG_ERR,
				   "error getting Decoder firmware version\n");
		}
		else	{
			IVTV_DEBUG(IVTV_DEBUG_ERR,
				   "Decoder revision: 0x%08x\n", data[0]);
		}
	}
	
	return 0;
}


int ivtv_stop_all_captures(struct ivtv *itv) {
	struct ivtv_open_id id;
	int x;
	id.itv = itv;

	down(&itv->sem_lock);

	for (x = 0; x < itv->v4l2.streamcount;x++) {
		if (test_bit(IVTV_F_S_CAP, &itv->v4l2.streams[x].s_flags)) {
			id.type=x;
			ivtv_stop_capture(&id);
		}
	}
	
	up(&itv->sem_lock);
	return 0;
}

int ivtv_stop_capture(struct ivtv_open_id *id) {
	struct ivtv *itv=id->itv;
	u32 data[IVTV_MBOX_MAX_DATA], result;
	DECLARE_WAITQUEUE(wait, current);
	int type,subtype;
	int x;

	/* sem_lock must be held */
	IVTV_ASSERT(ivtv_sem_count(&itv->sem_lock) <= 0);

	/* FIXME set 'die' ?? */

	type = id->type;
	if (type == 1) {
		subtype = 3; //FIXME temp
	} else {
		subtype = 3;
	}

	/* only run these if we're shutting down the last cap */
	if (atomic_read(&itv->capturing) == 0) {
		/* event notification (off)*/
		data[0] = 0; /*type: 0 = refresh */
		data[1] = 0; /*on/off: 0 = off */
		data[2] = 0x10000000; /*intr_bit: 0x10000000 = digitizer */
		data[3] = -1; /*mbox_id: -1: none */
	        x = __ivtv_api(itv->enc_mbox, IVTV_API_EVENT_NOTIFICATION,
			&result, 4, &data[0]);
		if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stopcap error 1. Code %d\n",x);

	}

	/* end_capture */
	data[0] = 0; /*when: 0 =  end of GOP */
	data[1] = type; /*type: 0 = mpeg */
	data[2] = subtype; /*subtype: 3 = video+audio */
        x = __ivtv_api(itv->enc_mbox, IVTV_API_END_CAPTURE,
		&result, 3, &data[0]);
	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stopcap error 2. Code %d\n",x);

	x = 0;
	add_wait_queue(&itv->v4l2.streams[type].waitq, &wait);
	do {
		set_current_state(TASK_UNINTERRUPTIBLE);
		/* check if DMA is pending */
		if (!test_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[type].s_flags))
			break;

		IVTV_DEBUG(IVTV_DEBUG_INFO, "dma still pending!\n");
		schedule_timeout(HZ/100);
		if (x++ > 100) {
			IVTV_DEBUG(IVTV_DEBUG_ERR, "giving up waiting for DMA pending clear\n");
			break;
		}
	} while (1);
	set_current_state(TASK_RUNNING);
	remove_wait_queue(&itv->v4l2.streams[type].waitq, &wait);

	add_wait_queue(&itv->cap_w, &wait);
	set_current_state(TASK_UNINTERRUPTIBLE);
	/* only run these if we're shutting down the last cap */
	if (atomic_read(&itv->capturing) == 0) {
		/* wait 1s for EOS interrupt */
		ivtv_sleep_timeout(HZ);

		if (!test_bit(IVTV_F_I_EOS, &itv->i_flags))
			IVTV_DEBUG(IVTV_DEBUG_ERR,
				   "EOS interrupt not received! stopping anyway.\n");
		
		/*Set the following Interrupt mask bits: 0xd8000000 */
		ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
		IVTV_DEBUG(IVTV_DEBUG_IRQ, "IRQ Mask is now: 0x%08x\n", itv->irqmask);
	}
	set_current_state(TASK_RUNNING);
	remove_wait_queue(&itv->cap_w, &wait);
	return 0;
}

int ivtv_stop_decode(struct ivtv_open_id *id) {
	struct ivtv *itv=id->itv;
	u32 data[IVTV_MBOX_MAX_DATA], result;
	struct ivtv_buffer *buf;
	int x;

	/* sem_lock must be held */
	IVTV_ASSERT(ivtv_sem_count(&itv->sem_lock) <= 0);

	/* FIXME set 'die' ?? */

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Decoder stop.\n");

	/* stop decoder interrupt timeout */
	del_timer_sync(&itv->dec_timeout);

	/* only run these if we're shutting down the last cap */
	if (atomic_read(&itv->decoding) == 0) {
		/* event notification (off)*/
	        data[0] = 0; /* Event: 0 = audio change between stereo and mono */
	        data[1] = 0; /* Enable/Disable: 0 = disabled, 1 = enabled */
	        data[2] = 0x00010000; /* Bit: interrupt bit to fire */
	        data[3] = -1; /* Mailbox to use: -1 = no mailbox needed */
	        x = __ivtv_api(itv->dec_mbox, IVTV_API_DEC_EVENT_NOTIFICATION, &result, 4, &data[0]);
		if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stopDEC error 1. Code %d\n",x);

	/* end_capture */
	data[0] = itv->dec_options.hide_last_frame; /* 0 = last frame, 1 = black */
	data[1] = itv->dec_options.pts_low; /* when: pts low */
	data[2] = itv->dec_options.pts_hi;  /* when: pts hi */
        x = __ivtv_api(itv->dec_mbox, IVTV_API_DEC_STOP_PLAYBACK, &result, 3, &data[0]);
	if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stopDEC error 2. Code %d\n",x);

	}
		
	/* FIXME turn off relevant irqmask here */
	ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE);

	/* clean up queues */
	/* move free_q to full_q to clean up partially-filled buffers */
	while ((buf = ivtv_deq_buf(itv, &itv->v4l2.streams[id->type].free_q))) {
		buf->buffer.bytesused=0;
		buf->readpos=0;
		ivtv_enq_buf(itv, &itv->v4l2.streams[id->type].full_q, buf);
	}

	while ((buf = ivtv_deq_buf(itv, &itv->v4l2.streams[id->type].full_q))) {
		buf->buffer.bytesused=0;
		buf->readpos=0;
		ivtv_enq_buf(itv, &itv->v4l2.streams[id->type].free_q, buf);
	}

	while ((buf = ivtv_deq_buf(itv, &itv->v4l2.streams[id->type].dma_q))) {
		buf->buffer.bytesused=0;
		buf->readpos=0;
		ivtv_enq_buf(itv, &itv->v4l2.streams[id->type].free_q, buf);
	}

	if (test_and_clear_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[id->type].s_flags))
		IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: clearing dma_pending\n");

	return 0;
}

void ivtv_dec_timeout(unsigned long arg) {
	struct ivtv *itv = (struct ivtv *)arg;

	/* FIXME mpg only :/ */
	struct ivtv_v4l2_stream *stream = &itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG];
	unsigned long flags;

	if (!test_bit(IVTV_F_S_DMAP, &stream->s_flags))
		return;

	IVTV_DEBUG(IVTV_DEBUG_ERR, "ivtv_dec_timeout: lost IRQ; resetting...\n");
	spin_lock_irqsave(&itv->lock, flags);
	ivtv_dec_DMA_done(itv);
	/* kick it off again! */
	set_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags);
	ivtv_dec_sched_DMA(itv);
	spin_unlock_irqrestore(&itv->lock, flags);
}

#if 0
static void ivtv_show_irq_status(struct ivtv* itv, u32 irqstat, u32 irqmask, u32 dmastat) {
  struct ivtv_mailbox* mbox8 = &itv->dec_mbox[8];
  struct ivtv_mailbox* mbox9 = &itv->dec_mbox[9];

#if 0
  // Make it less verbose...
  if ((irqstat & ~4) == IVTV_IRQ_DEC_VSYNC)
    return;
#endif

  printk("ivtv: irqstat [ "
         "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s], "
         "frame %d, pts %d, scr %d, type %d, offset %08x, max %d, full %d\n", 
         (irqstat & IVTV_IRQ_ENC_START_CAP) ? "StartCap " : "",
         (irqstat & IVTV_IRQ_ENC_EOS) ? "EndOfStream " : "",
         (irqstat & IVTV_IRQ_ENC_VBI_CAP) ? "VBICap " : "",
         (irqstat & IVTV_IRQ_ENC_VIM_RST) ? "VIMReset " : "",
         (irqstat & IVTV_IRQ_ENC_DMA_COMPLETE) ? "EncDMAComplete " : "",
         (irqstat & (1<<26)) ? "26 " : "",
         (irqstat & IVTV_IRQ_DEC_COPY_PROTECT) ? "CopyProt " : "",
         (irqstat & IVTV_IRQ_DEC_AUD_MODE_CHG) ? "AudioMode " : "",
         (irqstat & (1<<23)) ? "23 " : "",
         (irqstat & IVTV_IRQ_DEC_DATA_REQ) ? "DecDataReq " : "",
         (irqstat & IVTV_IRQ_DEC_IFRAME_DONE) ? "IFrameDone " : "",
         (irqstat & IVTV_IRQ_DEC_DMA_COMPLETE) ? "DecDMAComplete " : "",
         (irqstat & IVTV_IRQ_DEC_VBI_RE_INSERT) ? "VBIReInsert " : "",
         (irqstat & IVTV_IRQ_DEC_DMA_ERR) ? "DecDMAError " : "",
         (irqstat & (1<<17)) ? "17 " : "",
         (irqstat & (1<<16)) ? "16 " : "",
         (irqstat & (1<<15)) ? "15 " : "",
         (irqstat & (1<<14)) ? "14 " : "",
         (irqstat & (1<<13)) ? "13 " : "",
         (irqstat & (1<<12)) ? "12 " : "",
         (irqstat & (1<<11)) ? "11 " : "",
         (irqstat & IVTV_IRQ_DEC_VSYNC) ? "DecVSync " : "",
         (irqstat & (1<<9)) ? "9 " : "",
         (irqstat & (1<<8)) ? "8 " : "",
         (irqstat & (1<<7)) ? "7 " : "",
         (irqstat & (1<<6)) ? "6 " : "",
         (irqstat & (1<<5)) ? "5 " : "",
         (irqstat & (1<<4)) ? "4 " : "",
         (irqstat & (1<<3)) ? "3 " : "",
         (irqstat & (1<<2)) ? "2 " : "",
         (irqstat & (1<<1)) ? "1 " : "",
         (irqstat & (1<<0)) ? "0 " : "",
         readl(&mbox8->data[0]), 
         readl(&mbox8->data[1]), 
         readl(&mbox8->data[3]), 
         readl(&mbox9->data[0]),
         readl(&mbox9->data[1]),
         readl(&mbox9->data[2]), 
         readl(&mbox9->data[3]));
}
#endif

void ivtv_irq_handler(int irq, void *dev_id, struct pt_regs *regs) {

	u32 stat  = 0;
	u32 combo = 0;
	struct ivtv *itv=(struct ivtv *)dev_id;
	
	/* get contents of irq status register*/
	stat = readl(itv->reg_mem + IVTV_REG_IRQSTATUS);

	combo=~itv->irqmask & stat;

	if (0 == combo) {
		/* wasn't for us*/
		return;
	}

	spin_lock(&itv->lock);

/*
	ivtv_show_irq_status(itv, stat, itv->irqmask,
			     readl(itv->reg_mem + IVTV_REG_DMASTATUS));
*/

	IVTV_DEBUG(IVTV_DEBUG_IRQ, "======= valid IRQ bits: 0x%08x ======\n", combo);

	writel(combo, (itv->reg_mem + IVTV_REG_IRQSTATUS));

	if (combo & IVTV_IRQ_ENC_DMA_COMPLETE) {
		ivtv_DMA_done(itv);
		IVTV_DEBUG(IVTV_DEBUG_IRQ, "Processed DMA-complete\n");
	}
	if (combo & IVTV_IRQ_ENC_START_CAP) {
		ivtv_sched_DMA(itv);
		IVTV_DEBUG(IVTV_DEBUG_IRQ, "Processed enc-startcap\n");
	}
	if (combo & IVTV_IRQ_ENC_EOS) {
		IVTV_DEBUG(IVTV_DEBUG_IRQ, "Encoder End Of Stream\n");
		set_bit(IVTV_F_I_EOS, &itv->i_flags);
		wake_up(&itv->cap_w);
	}
	if (combo & IVTV_IRQ_ENC_VBI_CAP) {
		IVTV_DEBUG(IVTV_DEBUG_IRQ, "deb3\n");
	}
	if (combo & IVTV_IRQ_ENC_VIM_RST) {
		IVTV_DEBUG(IVTV_DEBUG_IRQ, "VIM Restart\n");
	}
	if (combo & IVTV_IRQ_DEC_COPY_PROTECT) {
		IVTV_DEBUG(IVTV_DEBUG_IRQ, "deb6\n");
	}
	if (combo & IVTV_IRQ_DEC_AUD_MODE_CHG) {
		IVTV_DEBUG(IVTV_DEBUG_IRQ, "deb7\n");
	}
	if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) {
		IVTV_DEBUG(IVTV_DEBUG_IRQ, "Decoder DMA Done\n");
		ivtv_dec_DMA_done(itv);
	}
	if (combo & IVTV_IRQ_DEC_DATA_REQ) {
		IVTV_DEBUG(IVTV_DEBUG_IRQ, "Decoder Data Request\n");
		set_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags);
		ivtv_dec_sched_DMA(itv);
	}
	if (combo & IVTV_IRQ_DEC_IFRAME_DONE) {
		IVTV_DEBUG(IVTV_DEBUG_IRQ, "deb9\n");
	}
	if (combo & IVTV_IRQ_DEC_VBI_RE_INSERT) {
		IVTV_DEBUG(IVTV_DEBUG_IRQ, "deb11\n");
	}
	if (combo & IVTV_IRQ_DEC_DMA_ERR) {
		IVTV_DEBUG(IVTV_DEBUG_IRQ, "deb12\n");
	}
	if (combo & IVTV_IRQ_DEC_VSYNC) {
		ivtv_irq_dec_vsync(itv);
	}
  /*
	stat = readl(itv->reg_mem + IVTV_REG_IRQSTATUS);
        IVTV_DEBUG(IVTV_DEBUG_IRQ, "IVTV IRQ STATUS REG AFTER INTERRUPT 0x%08x", stat);
        if (combo & ~IVTV_IRQ_DEBUG_KLUGE) {
		IVTV_DEBUG(IVTV_DEBUG_ERR,
			"unknown irq 0x%08x, mask:0x%08x, combo:0x%08x\n",
					stat, itv->irqmask, combo);
	}
  */
	spin_unlock(&itv->lock);
}

void ivtv_irq_dec_vsync(struct ivtv* itv) {
  u32* data = itv->dec_mbox[IVTV_MBOX_FIELD_DISPLAYED].data;

  u32 newframe = readl(&data[0]);
  u64 newpts = ((u64)readl(&data[2]) << 32) | (u64)(readl(&data[1]));
  u64 newscr = ((u64)readl(&data[4]) << 32) | (u64)(readl(&data[3]));

  itv->dec_timestamp.pts = newpts;
  itv->dec_timestamp.scr = newscr;
  if (newframe != itv->dec_timestamp.frame) {
    itv->dec_timestamp.frame = newframe;
    wake_up(&itv->vsync_w);
  }

  IVTV_DEBUG(IVTV_DEBUG_IRQ, "ivtv_irq_dec_vsync: frames %d, pts %ld, scr %ld\n", itv->dec_timestamp.frame, (long int)itv->dec_timestamp.pts, (long int)itv->dec_timestamp.scr);
}

void ivtv_show_debug_flags(struct ivtv *itv)
{
	int y;

	printk(KERN_DEBUG "ivtv: i_flags=%lx", itv->i_flags);
	for (y=IVTV_DEC_STREAM_TYPE_MPG; y < itv->v4l2.streamcount; y++)
		printk(", %d s_sflags=%lx", y, itv->v4l2.streams[y].s_flags);
	printk("\n");
}

void ivtv_DMA_done(struct ivtv *itv) {
	u32 result;
	int y,stmtype=-1;
	struct ivtv_v4l2_stream *stream=NULL;
	struct ivtv_buffer *buf;

	IVTV_DEBUG(IVTV_DEBUG_INFO, "DMA Done tasklet\n");

	for (y=0; y < itv->v4l2.streamcount; y++) {
		if (test_and_clear_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[y].s_flags)) {
			stmtype = y;
			break;
		}
	}

	if (stmtype < 0) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Got DMA-done, but not expecting one\n");
		goto debug;
	}

	stream = &itv->v4l2.streams[stmtype];

#if 0
	/* Silently return if we're in an overflow state */
	if (test_bit(IVTV_F_S_OVERFLOW, &stream->s_flags)) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "silently returning\n");
	       	return;
	}
#else
	if (test_bit(IVTV_F_S_OVERFLOW, &stream->s_flags))
		IVTV_DEBUG(IVTV_DEBUG_ERR, "full but continuing\n");
#endif
	

	/* check DMA status register */
	result = readl(itv->reg_mem + IVTV_REG_DMASTATUS);


	if (result & IVTV_DMA_WRITE_ERR) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "DMA Error. Result: 0x%08x\n", result);
		return;
	}

	if (0 == (result & IVTV_DMA_SUCCESS)) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "DMA interrupt, but no err and no "
			   "success. odd %x -", result);
		result = readl(itv->reg_mem + IVTV_REG_DMASTATUS);
		IVTV_DEBUG(IVTV_DEBUG_ERR, "%x\n", result);
		goto debug;
	}

	/* DMA was fine if we made it this far */

	/* remove from dma_pending queue */
	while ((buf = ivtv_deq_buf(itv, &stream->dma_q))) {
		IVTV_ASSERT(buf->dma_handle != IVTV_DMA_UNMAPPED);
		pci_unmap_single(itv->dev, buf->dma_handle,
					IVTV_DMA_BUF_SIZE, PCI_DMA_TODEVICE);
		buf->dma_handle = IVTV_DMA_UNMAPPED;
		/* byteswap ABCD -> DCBA for MPG data*/
		if (stmtype == 0) {
			for (y = 0; y < buf->buffer.bytesused; y += 4) {
				swab32s( (u32 *)((u32)buf->buffer.m.userptr + y));
			}
		}
		/* put in the 'done' queue */
		__ivtv_enq_buf(&stream->full_q, buf);
	}

	/*wake up client*/
	wake_up(&stream->waitq);
	return;
debug:
	ivtv_show_debug_flags(itv);
}

/* must hold itv->lock */
int ivtv_ignore_DMA_req(struct ivtv *itv, u32 type) {
	u32 data[IVTV_MBOX_MAX_DATA];
	int ret = 0;

	set_bit(IVTV_F_S_OVERFLOW, &itv->v4l2.streams[type].s_flags);

	data[0] = type;
	data[0] = 0;
	data[1] = 0; /* ACK the DMA and continue */
       	if (ivtv_api_irqsafe(itv->enc_mbox, IVTV_API_SCHED_DMA_TO_HOST, 3, &data[0])) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "error sending DMA info\n");
		ret = -EIO;
	}

	if (!ret)
		set_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[type].s_flags);

	return ret;
}


/* FIXME this function is getting too long. split it up? */
void ivtv_sched_DMA(struct ivtv *itv) {
	u32 data[IVTV_MBOX_MAX_DATA], result;
	u32 type, size, offset;
	u32 UVsize=0, UVoffset=0, pts_stamp=0;
	int x, bufs_needed;
	int uvflag=0;
	struct ivtv_buffer *buf;
	LIST_HEAD(free_list);
	long sequence;

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Sched DMA tasklet\n");

	/* Get DMA destination and size arguments from card*/
	x = ivtv_api_getresult_nosleep(&itv->enc_mbox[9], &result, &data[0]);
	if (x) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "error:%d getting DMA info\n", x);
		return;
	}
	
	type   = data[0];

	/* FIXME should check for null on the stream element */
	if (itv->v4l2.streamcount <= type) {
		IVTV_DEBUG(IVTV_DEBUG_ERR,"No stream handler for type %d\n", type);
		ivtv_ignore_DMA_req(itv, type);
		return;
	}

	switch (type) {
		case 0:  /* MPEG */
			offset = data[1];
			size   = data[2];
			IVTV_DEBUG(IVTV_DEBUG_INFO,
				   "DMA/MPG type 0x%08x,size 0x%08x,offset 0x%08x\n",
	 			   type, size, offset);
			bufs_needed = ivtv_ceil(size, IVTV_DMA_BUF_SIZE);
			break;
		case 1: /* YUV */
			offset		= data[1];
			size		= data[2];
			UVoffset	= data[3];
			UVsize		= data[4];
			pts_stamp	= data[6];
			IVTV_DEBUG(IVTV_DEBUG_INFO,
				   "DMA/YUV type 0x%08x,Ysize 0x%08x,Yoffset 0x%08x,"
				   "UVsize 0x%08x,UVoffset 0x%08x,PTS 0x%08x\n",
	 			   type, size, offset, UVsize, UVoffset, pts_stamp);
			bufs_needed = ivtv_ceil(size, IVTV_DMA_BUF_SIZE);
			bufs_needed += ivtv_ceil(UVsize, IVTV_DMA_BUF_SIZE);
			break;

		case 2:  /* PCM (audio) */
			offset = data[1];
			size   = data[2];
			pts_stamp	= data[6];
			IVTV_DEBUG(IVTV_DEBUG_INFO,
				   "DMA/PCM type 0x%08x,size 0x%08x,offset 0x%08x "
				   "PTS 0x%08x\n", type, size, offset, pts_stamp);
			bufs_needed = ivtv_ceil(size, IVTV_DMA_BUF_SIZE);
			ivtv_ignore_DMA_req(itv, type);
			return;
		case 3:  /* VBI */
			offset = data[1];
			size   = data[2];
			bufs_needed = ivtv_ceil(size, IVTV_DMA_BUF_SIZE);
			IVTV_DEBUG(IVTV_DEBUG_ERR,
				   "DMA/VBI type 0x%08x, size 0x%08x, offset 0x%08x"
				   "EXPERIMENTAL\n", type, size, offset);
			break;
		default:
			IVTV_DEBUG(IVTV_DEBUG_ERR,
				   "DMA/UNKNOWN type 0x%08x, NOT SUPPORTED\n", type);
			ivtv_ignore_DMA_req(itv, type);
			return;
	}

	if (bufs_needed > SGarray_size) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "INTERNAL ERROR: ivtv_sched_DMA_tasklet: "
			   "bufs_needed = %d but SGarray_size = %d\n", 
			   bufs_needed, SGarray_size);
		return;
	}

	/* gather the needed buffers first, so we don't have to bail
	 * in mid-air. put them on a list on the stack */
	for (x = 0; x < bufs_needed; x++) {
		struct ivtv_v4l2_stream	*st = &itv->v4l2.streams[type];
		
		buf = __ivtv_deq_buf(&st->free_q);
		if (!buf)
			break;

		list_add_tail(&buf->list, &free_list);
	}

	/* damn, failed */
	if (x < bufs_needed) {
		struct ivtv_v4l2_stream *stream = &itv->v4l2.streams[type];

		IVTV_DEBUG(IVTV_DEBUG_ERR, "DMA buffer DeQueue failed! got %d, want %d\n", x + 1, bufs_needed + 1);
		IVTV_DEBUG(IVTV_DEBUG_ERR, "SCHED: free_q: %d elements\n", stream->free_q.elements);
		IVTV_DEBUG(IVTV_DEBUG_ERR, "SCHED: dma_q: %d elements\n", stream->dma_q.elements);
		IVTV_DEBUG(IVTV_DEBUG_ERR, "SCHED: full_q: %d elements\n", stream->full_q.elements);
		while (!list_empty(&free_list)) {
			buf = list_entry(free_list.next, struct ivtv_buffer, list);
			list_del_init(&buf->list);
			__ivtv_enq_buf(&itv->v4l2.streams[type].free_q, buf);
		}
		/* mark overflow condition, next free will restart dma req */
		set_bit(IVTV_F_S_OVERFLOW, &itv->v4l2.streams[type].s_flags);
		return;
	}

	/* increment the sequence # */
	sequence = ++itv->v4l2.streams[type].seq;

	for (x = 0; x < bufs_needed; x++) {
		IVTV_DEBUG(IVTV_DEBUG_INFO, "size: %d 0x%08x\n", size, size);

		if ((size == 0) && (type == 1) && (uvflag == 0)) { /* YUV */
			/* process the UV section */
			offset	= UVoffset;
			size	= UVsize;
			uvflag	= 1;
		}

		/* extract the buffers we procured earlier */
		buf = list_entry(free_list.next, struct ivtv_buffer, list);
		list_del_init(&buf->list);

		buf->readpos = 0;
		buf->buffer.index = x;
		buf->buffer.sequence = sequence;
		buf->ts = jiffies;

		if (size < (IVTV_DMA_BUF_SIZE & 0xffffff00)) {
			buf->buffer.bytesused = size;
			/* bytecount must be multiple of 0x100 (256) */
			itv->SGarray[x].size = 
				(0xffffff00 & (buf->buffer.bytesused + 0xFF));
			size = 0;
		}
		else {
			buf->buffer.bytesused	= IVTV_DMA_BUF_SIZE;
			itv->SGarray[x].size	= IVTV_DMA_BUF_SIZE;
			size		       -= IVTV_DMA_BUF_SIZE;
		}

		itv->SGarray[x].src = offset; 
		offset += buf->buffer.bytesused;
		
		/* unfortunately the pci dma api wasn't properly defined
		 * for handling mapping errors (running out of iommu space,
		 * for instance). 0 can be a valid bus address. */
		buf->dma_handle	= pci_map_single(itv->dev, 
						 (void *)buf->buffer.m.userptr,
						 buf->buffer.bytesused,
						 PCI_DMA_FROMDEVICE);

		itv->SGarray[x].dst = buf->dma_handle;
		
		/* FIXME need to add pts stuff, index, etc. */
		__ivtv_enq_buf(&itv->v4l2.streams[type].dma_q, buf);
	}
	
	/* This should wrap gracefully */
	/* FIXME obselete? */
	itv->trans_id++;

	itv->SGarray[bufs_needed-1].size |= 0x80000000;

	/*FIXME unlock */

	data[0] = itv->SG_handle;
	/* 3 elements * 4 bytes per element * num_elements */
	data[1] = (3 * 4 * bufs_needed);
	data[2] = type;
	data[3] = 0x0;

	for  (x = 0; x < bufs_needed; x++)
	 IVTV_DEBUG(IVTV_DEBUG_INFO, "SGarray[%d]: 0x%08x, 0x%08x 0x%08x\n",
		x, itv->SGarray[x].src, itv->SGarray[x].dst, itv->SGarray[x].size);

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Sched dma: addr: 0x%08x, array_size 0x%08x,"
		   " type 0x%08x\n", data[0], data[1], data[2]);

	set_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[type].s_flags);
	ivtv_api_irqsafe(itv->enc_mbox, IVTV_API_SCHED_DMA_TO_HOST, 4, &data[0]);
}

void ivtv_sched_DMA_tasklet(unsigned long arg) {
	struct ivtv *itv = (struct ivtv *) arg;
	unsigned long flags;

	spin_lock_irqsave(&itv->lock, flags);
	ivtv_sched_DMA(itv);
	spin_unlock_irqrestore(&itv->lock, flags);
}

/* FIXME this function does way more than it should */
static int __devinit ivtv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) {
	int retval=0;
	unsigned char pci_latency;
	struct ivtv *itv;
	struct video_channel v;
	unsigned long freq;
        u16 cmd;

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Found card #%d\n", ivtv_cards_active);

	spin_lock_irq(&ivtv_lock);

	/* Make sure we've got a place for this card */
	if (ivtv_cards_active == IVTV_MAX_CARDS) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, ":Maximum # of cards already detected (%d).\n", ivtv_cards_active);
		spin_unlock_irq(&ivtv_lock);
		return -ENOMEM;
	}

	itv	 = &ivtv_cards[ivtv_cards_active];
	itv->dev = dev;
	itv->num = ivtv_cards_active;

	ivtv_cards_active++;

	spin_unlock_irq(&ivtv_lock);

	/* always remember what you think the irq mask should be */
	itv->irqmask = 0;

#ifdef YUV_FIXUP
	itv->options.yuv_fixup   = yuv_fixup;
#endif
	itv->options.dec_yuv_buffers = dec_yuv_buffers;
	itv->options.dec_mpg_buffers = mpg_buffers;
	itv->options.yuv_buffers = yuv_buffers;
	itv->options.mpg_buffers = mpg_buffers;
	itv->options.vbi_buffers = vbi_buffers;
	itv->options.num_devices = num_devices;
	itv->options.dec_mpg_qlen = dec_mpg_qlen;
	itv->options.dec_yuv_qlen = dec_yuv_qlen;

	/* Set FrameBuffer-ID to invalid */
	itv->fb_id = -1;

	switch (dev->subsystem_device) {
	case IVTV_PCI_ID_250_V2:
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Found an iTVC16 based chip\n");
		itv->card_type = IVTV_250_V2;
		break;
	case IVTV_PCI_ID_350_V1:
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Found an iTVC15 based chip\n");
		itv->card_type = IVTV_350_V1;
		break;
	case IVTV_PCI_ID_250_V1:
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Found an iTVC15 based chip\n");
		itv->card_type = IVTV_250_V1;
		break;
	default: /* Default to 250 v1 style */
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Found an unknown chip, treating it like an iTVC15\n");
		itv->card_type = IVTV_250_V1;
		break;
	}

	init_MUTEX(&itv->sem_lock);
	spin_lock_init(&itv->lock);
	itv->base_addr=pci_resource_start(dev,0);
	itv->enc_mbox = NULL;
	itv->dec_mbox = NULL;
	itv->io_mem = NULL;
	itv->reg_mem = NULL;
	itv->i_flags = 0;
	atomic_set(&itv->capturing, 0);
	atomic_set(&itv->decoding, 0);
	itv->user_dma_to_device_state = NULL;

	/* Prepare list for action! */
	INIT_LIST_HEAD(&itv->client_list);

	init_waitqueue_head(&itv->cap_w);
	init_waitqueue_head(&itv->vsync_w);
	init_waitqueue_head(&itv->dec_master_w);
	init_timer(&itv->dec_timeout);
	itv->dec_timeout.function = ivtv_dec_timeout;
	itv->dec_timeout.data = (unsigned long)itv;

	tasklet_init(&itv->dma_sched_tq, ivtv_sched_DMA_tasklet, (unsigned long) itv);

	IVTV_DEBUG(IVTV_DEBUG_INFO, "base addr: 0x%08x\n", itv->base_addr);

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Enabling pci device\n");
	if (pci_enable_device(dev)) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Can't enable device %d!\n",itv->num);
		retval = -EIO;
		goto err;
	}
        if (pci_set_dma_mask(dev, 0xffffffff)) {
                IVTV_DEBUG(IVTV_DEBUG_ERR, KERN_WARNING "No suitable DMA available on card %d.\n",
                       itv->num);
		retval = -EIO;
		goto err;
        }
        if (!request_mem_region(pci_resource_start(dev,0), IVTV_IOREMAP_SIZE, IVTV_DEVNAME )) {
		retval = -EIO;
		goto err;
	}

        /* Check for bus mastering */
        pci_read_config_word(dev, PCI_COMMAND, &cmd);
        if (! (cmd & PCI_COMMAND_MASTER)) {
                IVTV_DEBUG(IVTV_DEBUG_ERR, "Bus Mastering is not enabled\n");
		retval = -ENXIO;
		goto free_mem;
        }
        else {
                IVTV_DEBUG(IVTV_DEBUG_INFO, "Bus Mastering Enabled.");
        }
	
	pci_read_config_byte(dev, PCI_CLASS_REVISION, &itv->card_rev);
	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);

	IVTV_DEBUG(IVTV_DEBUG_INFO, "%d (rev %d) at %02x:%02x.%x, ",
		itv->dev->device, itv->card_rev, dev->bus->number,
		PCI_SLOT(dev->devfn),PCI_FUNC(dev->devfn));
	IVTV_DEBUG(IVTV_DEBUG_INFO, "     irq: %d, latency: %d, memory: 0x%lx\n",
		itv->dev->irq, pci_latency, (unsigned long)itv->base_addr);

	/*map io memory*/
	IVTV_DEBUG(IVTV_DEBUG_INFO, "attempting ioremap at 0x%08x len 0x%08x\n",
		itv->base_addr, IVTV_ENCDEC_SIZE);
	itv->io_mem = ioremap_nocache(itv->base_addr,IVTV_ENCDEC_SIZE);
	if (!itv->io_mem) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, IVTV_IOREMAP_ERROR);
		retval = -ENOMEM;
		goto free_mem;
	}

	/*map registers memory*/
	IVTV_DEBUG(IVTV_DEBUG_INFO, "attempting ioremap at 0x%08x len 0x%08x\n",
		itv->base_addr+IVTV_REG_OFFSET, IVTV_REG_SIZE);
	itv->reg_mem = ioremap_nocache(itv->base_addr+IVTV_REG_OFFSET,IVTV_REG_SIZE);
	if (!itv->reg_mem) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, IVTV_IOREMAP_ERROR);
		retval = -ENOMEM;
		goto free_io;
	}	

	IVTV_DEBUG(IVTV_DEBUG_IRQ, "Masking interrupts\n");
	/* clear interrupt mask, effectively disabling interrupts */
	ivtv_set_irq_mask(itv, 0xffffffff);

	retval = request_irq(itv->dev->irq, ivtv_irq_handler,
			SA_SHIRQ | SA_INTERRUPT,IVTV_DEVNAME,(void *)itv);
	if (retval) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "failed to register irq %d\n", retval);
		goto free_io;
	}

	/* save itv in the pci struct for later use*/
	pci_set_drvdata(dev,itv);

	/* active i2c  */
	itv->i2c_command=(I2C_TIMING);
	IVTV_DEBUG(IVTV_DEBUG_INFO, "activating i2c..\n");
	if (init_ivtv_i2c(itv)) {
		IVTV_DEBUG(IVTV_DEBUG_INFO, "i2c died! unloading\n");
		goto free_irq;
	}
	
	IVTV_DEBUG(IVTV_DEBUG_INFO, "Active card count: %d.\n", ivtv_cards_active);
	
	/*write firmware */
	retval = ivtv_firmware_init(itv);
	if (retval) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Error initializing.\n");
		retval = -ENOMEM;
		goto free_i2c;
	}

	/*search for encoder/decoder mailboxes*/
	IVTV_DEBUG(IVTV_DEBUG_INFO, "About to search for mailboxes\n");
	ivtv_find_firmware_mailbox(itv);

	if ((itv->enc_mbox == NULL) && (itv->dec_mbox ==NULL)) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Error locating firmware.\n");
		retval = -ENOMEM;
		goto free_i2c;
	}

	/*releasing unneeded iomapped memory (encoder+decoder)*/
	//iounmap(itv->io_mem);

	/*remapping only needed io memory (mailboxes) */
	itv->enc_mbox = ioremap(itv->base_addr+((u8 *)itv->enc_mbox - (u8 *)itv->io_mem), 
	    IVTV_MBOX_MAX_BOXES * IVTV_MBOX_SIZE);
	itv->dec_mbox = ioremap(itv->base_addr+((u8 *)itv->dec_mbox - (u8 *)itv->io_mem), 
	    IVTV_MBOX_MAX_BOXES * IVTV_MBOX_SIZE);
	
	/* clearing pointers */
	//itv->io_mem = NULL ;

	/*Try and get firmware versions */
	IVTV_DEBUG(IVTV_DEBUG_INFO, "Getting firmware version..\n");
	retval = ivtv_firmware_versions(itv);
	if (retval) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "error %d getting version #!\n", retval);
		goto free_i2c;
	}

	/* Allocate scatter-gather arrays*/

  //++MTY NASTY little bug!!! If user changes dec_mpg_buffers, 
  // memory corruption results with the old way!

	/* encoder */
	itv->SGarray = (struct ivtv_SG_element *)
			kmalloc(sizeof(struct ivtv_SG_element) * 
				SGarray_size,
				GFP_KERNEL);
	if (!(itv->SGarray)) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Error allocating SGarray[].\n");
		retval = -ENOMEM;
		goto free_i2c;
	}

	itv->SG_handle = pci_map_single(itv->dev,
					(void *)&itv->SGarray[0],
					(sizeof(struct ivtv_SG_element) * 
           SGarray_size),
					PCI_DMA_TODEVICE);

	if (itv->card_type == IVTV_350_V1) {
		/* decoder */
		itv->DSGarray = (struct ivtv_SG_element *)
				 kmalloc(sizeof(struct ivtv_SG_element) * 
				 DSGarray_size, GFP_KERNEL);
		if (!(itv->DSGarray)) {
			IVTV_DEBUG(IVTV_DEBUG_ERR, "Error allocating DSGarray[].\n");
			retval = -ENOMEM;
			goto free_sg;
		}

		itv->DSG_handle = pci_map_single(itv->dev,
						(void *)&itv->DSGarray[0],
						(sizeof(struct ivtv_SG_element) * 
					        DSGarray_size),	PCI_DMA_TODEVICE);
	}
	
	/* FIXME -temporary- setup tuner */
	IVTV_DEBUG(IVTV_DEBUG_INFO, "Setting Tuner\n");

	if( tuner > -1 ) {
		ivtv_call_i2c_client(itv,
				     IVTV_TUNER_I2C_ADDR,
				     TUNER_SET_TYPE,
				     &tuner );
	}

	/* set the standard */
	if (!ivtv_pal)
		v.norm = VIDEO_MODE_NTSC;
	else
		v.norm = VIDEO_MODE_PAL;

	ivtv_call_i2c_client(itv,IVTV_TUNER_I2C_ADDR, VIDIOCSCHAN,&v);

	if (!ivtv_pal) {
		/* set the channel */
		freq = 1076; /* ch. 4 67250*16/1000 */
		ivtv_call_i2c_client(itv,IVTV_TUNER_I2C_ADDR,VIDIOCSFREQ,&freq);
	}

	retval = ivtv_v4l2_setup(itv);
	if (retval) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Problem starting v4l2\n");
		goto ivtv_v4l2_fail;
	}

	return 0;
	
ivtv_v4l2_fail:
	pci_unmap_single(itv->dev,
			 itv->DSG_handle,
			 (sizeof(struct ivtv_SG_element) * 
           DSGarray_size),
			 PCI_DMA_TODEVICE);
	kfree(itv->DSGarray);
free_sg:
	pci_unmap_single(itv->dev,
			 itv->SG_handle,
			 (sizeof(struct ivtv_SG_element) * 
           SGarray_size),
			 PCI_DMA_TODEVICE);
	kfree(itv->SGarray);
free_i2c:
	exit_ivtv_i2c(itv);
free_irq:
	free_irq(itv->dev->irq, (void *)itv);
free_io:
	ivtv_iounmap(itv);
free_mem:
	release_mem_region(pci_resource_start(itv->dev,0), IVTV_IOREMAP_SIZE);
err:
	IVTV_DEBUG(IVTV_DEBUG_ERR, "Error %d on init\n", retval);

	spin_lock_irq(&ivtv_lock);
	ivtv_cards_active--;
	spin_unlock_irq(&ivtv_lock);
	return retval;
}

static void ivtv_remove(struct pci_dev *pci_dev) {
	struct ivtv *itv=pci_get_drvdata(pci_dev);
	int x = 0;

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Disabling interrupts!\n");
	ivtv_set_irq_mask(itv, 0xffffffff);

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping thread\n");
	atomic_set(&itv->decoding, 0);
	
	IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping card parts\n");
	x = ivtv_stop_firmware(itv);

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Freeing buffers\n");

	for (x = 0; x < itv->v4l2.streamcount; x++) {
		IVTV_DEBUG(IVTV_DEBUG_INFO,"Freeing stream %d!\n", x);
		ivtv_free_queue(&itv->v4l2.streams[x].free_q);
		ivtv_free_queue(&itv->v4l2.streams[x].full_q);
		ivtv_free_queue(&itv->v4l2.streams[x].dma_q);
	}

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Unregistering v4l devices!\n");
	ivtv_v4l2_cleanup(itv);

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Freeing dma resources\n");

	pci_unmap_single(itv->dev, itv->SG_handle,
			 (sizeof(struct ivtv_SG_element) * SGarray_size),
			 PCI_DMA_TODEVICE);
	kfree(itv->SGarray);

	pci_unmap_single(itv->dev, itv->DSG_handle,
			 (sizeof(struct ivtv_SG_element) * DSGarray_size),
			 PCI_DMA_TODEVICE);
	kfree(itv->DSGarray);

	exit_ivtv_i2c(itv);

	IVTV_DEBUG(IVTV_DEBUG_INFO, "releasing irq\n");
	free_irq(itv->dev->irq, (void *)itv);

	if (itv->dev) {
	    ivtv_iounmap(itv);
	}

	IVTV_DEBUG(IVTV_DEBUG_INFO, "releasing mem\n");
	if (itv)
	    release_mem_region(pci_resource_start(itv->dev,0), IVTV_IOREMAP_SIZE);

	/* FIXME free v4l2 stuff! */
	/* FIXME am i leaking kernel mem? */

}

/* define a pci_driver for card detection */
static struct pci_driver ivtv_pci_driver = {
	name:	  "ivtv: iTVC15/16 mpg2 encoder card",
	id_table: ivtv_pci_tbl,
	probe:	  ivtv_probe,
	remove:	  ivtv_remove,
};

#ifdef YUV_FIXUP
static int ivtv_YUV_fixup(struct ivtv_v4l2_stream *st, int count, 
			  char *ubuf, struct ivtv_buffer *buf) {
/*  
 * int count = # of bytes to transfer to client 
 * st->ubytes = # of bytes written this frame
 * ubuf = buffer to write to (user's buffer)
 * buf = read buffer
 *
 */

 int src_width=720; /* all known formats have src width of 720 */
 int Hoff, Voff; /* collectors for offsets to read position */
 int width, height; /* resolution of the capture stream */
 int curline; /* vertical line currently being processed */
 int maxline; /* height of combined frame */
 int cur_m_block; /* current horizontal offset of working mblock in this row */
 int maxblock; /* # of macroblocks in a row */
 int Hbytes; /* # of bytes to write to user this time around */
 int retval=0; /* accumulator for total bytes written */
 int start; /* position in buf to read from */
 int buf_start; /* byte offset of first byte in this *buf */

 height = st->format.fmt.pix.height;
 width  = st->format.fmt.pix.width;
 maxblock = (width + 0xf) >> 4;
 maxline = (int)(1.5 * height); /* 1 for Y, .5 for UV */
 /* Offset is always bufsize * buffer index 
 buf_start = (st->ubytes - buf->readpos);  tested/works */

 buf_start = IVTV_DMA_BUF_SIZE * buf->buffer.index;

 /* FIXME it may not be possible to get YUV width > 720 */
// if (width > src_width) src_width=width;
 
 curline = (int) (st->ubytes / width);

 while (curline < maxline) {
// 	printk(" cl: %d, ml: %d\n", curline, maxline);
	Voff =	16 * (curline & 0xf) +		   /* Voffset within MBlock */
		  ((curline & 0xfff0) * src_width); /* Voffset of Mblock */

	cur_m_block = (st->ubytes - (curline * width)) >> 4;

/*	printk("voff %d, macroVoff %d, Voff %d, cmb %d\n", (16 * (curline & 0xf)), 
			((curline & 0xff0) * src_width), Voff, cur_m_block);
*/

	while ((cur_m_block < maxblock) && (count > 0)) {
		Hoff   = (cur_m_block * 256) +	/* mblock offset within line */
			 /* Hoffset within mblock, usually 0 */
			 ((st->ubytes - (curline * width)) & 0xf);
		Hbytes = 16 - ((st->ubytes - (curline * width)) & 0xf);

		if (Hbytes > count) Hbytes = count;

		start = Hoff + Voff;

		if (copy_to_user((char *)((u32)ubuf + retval),
				 (u32 *)((u32)buf->buffer.m.userptr +
				 (start - buf_start)),
				 Hbytes)) {
			IVTV_DEBUG(IVTV_DEBUG_ERR, "copy to user failed\n");
			return -EFAULT;
		}
		
		count -= Hbytes;
		retval += Hbytes;
		st->ubytes += Hbytes;

		cur_m_block++;
	}
	 
	/* if user can't handle anymore data or buffer empty */
	curline++;
	if ((count == 0) ) /*|| ((curline * src_width) % IVTV_DMA_BUF_SIZE) == 0)*/
		return retval;
 }
 /* FIXME i don't think you should ever get here */
 IVTV_DEBUG(IVTV_DEBUG_ERR, "You've just sailed off the edge of this function\n");
 return retval;

}

#endif

long ivtv_read(struct ivtv_open_id *id, char *ubuf, size_t count, int block) {
	int x, sleepctr, datalen, retval=0, freed=0;
	struct ivtv *itv = id->itv;
	size_t newcount;
	unsigned long tid;
	struct ivtv_buffer *buf;
	struct ivtv_v4l2_stream *st=&itv->v4l2.streams[id->type];
	DECLARE_WAITQUEUE(wait, current);

	IVTV_DEBUG(IVTV_DEBUG_INFO, " Read stream.. \n");

	if (atomic_read(&itv->capturing) == 0) {
		IVTV_DEBUG(IVTV_DEBUG_ERR,
			   "Stream not initialized before read(shouldn't happen)\n");
		return -EIO;
	}

	/* FIXME find a way to gracefully exit capture */

	sleepctr = retval = 0;
	buf = NULL;
	add_wait_queue(&st->waitq, &wait);
	do {
		if ((itv->trans_id == 0) && (sleepctr >= IVTV_MAX_DATA_SLEEP)) {
			IVTV_DEBUG(IVTV_DEBUG_ERR, "Timeout waiting for data!\n");
			retval = -EIO;
			break;
		}

		set_current_state(TASK_INTERRUPTIBLE);
		buf = ivtv_deq_peek_head(itv, &st->full_q);
		if (buf)
			break;

		if (!block) {
			retval = -EAGAIN;
			break;
		}

		ivtv_sleep_timeout(IVTV_SLEEP_WAIT);

		if (signal_pending(current))
			retval = -ERESTARTSYS;

		sleepctr++;
	} while (!retval);
	__set_current_state(TASK_RUNNING);
	remove_wait_queue(&st->waitq, &wait);

	/* an error (or signal) occured */
	if (retval)
		return retval;

	/* Skip the first 4 bytes of mpg streams to help out
	 * finicky decoders.. but not for iTVC16 */
	if ((id->type == 0) && (itv->first_read == 1) &&
	    (itv->card_type != IVTV_250_V2)) {
		for( x = 0; x < buf->buffer.bytesused-4; x++ ) {
			unsigned char *p;
			itv->first_read = 0;
			p = (unsigned char *) buf->buffer.m.userptr +
			    buf->readpos + x;
			if( !p[0] && !p[1] && p[2] == 1 ) {
				IVTV_DEBUG(IVTV_DEBUG_INFO,
					   "Stripping first 4 bytes\n");
				buf->buffer.bytesused -= x;
				buf->readpos += x;
				break;
			}
		}
	}

	/* data ready */
	/* copy it to the client */
	while ((count > 0) && (buf->buffer.bytesused > 0)) {
		newcount = count;
		datalen = buf->buffer.bytesused;

		IVTV_DEBUG(IVTV_DEBUG_INFO, "datalen 0x%08x\n", datalen);

		if (newcount > datalen)
		       	newcount = datalen;

#ifdef YUV_FIXUP
		if ((id->type == 1) && (itv->options.yuv_fixup)) {
			newcount = ivtv_YUV_fixup(st,newcount,ubuf+retval,buf);
			if (newcount < 0) {
				IVTV_DEBUG(IVTV_DEBUG_ERR, "Error fixing up YUV!\n");
				return newcount;
			}
		} else {
#endif
			if (copy_to_user((char *)((u32)ubuf+retval),
			    (u32 *)((u32)buf->buffer.m.userptr +
			    buf->readpos), newcount)) {
				IVTV_DEBUG(IVTV_DEBUG_ERR, "copy to user failed\n");
		 		return -EFAULT;
			}
#ifdef YUV_FIXUP
		}
#endif

		buf->readpos += newcount;
		retval += newcount;
		count -= newcount;
		buf->buffer.bytesused -= newcount;
		IVTV_DEBUG(IVTV_DEBUG_INFO,
			   "new datalen 0x%08x\n", buf->buffer.bytesused);

		/* if buffer is empty or we've read the whole frame */
		if ((buf->buffer.bytesused == 0)) {
			ivtv_del_buf(itv, &st->full_q, buf);
			ivtv_enq_buf(itv, &st->free_q, buf);
			freed++;

			buf = ivtv_deq_peek_head(itv, &st->full_q);
			if (buf) {
				tid = buf->buffer.sequence;
				if (buf->buffer.sequence != tid) {
					/* end of frame! */
					st->ubytes = 0;
					break;
				}
			} else {
				/* user wanted more than we had. Since
				 * queues are filled in irq time, 
				 * that means end of frame */
				st->ubytes = 0;
				break;
			}
		}
	} /* end of while */

	/* if we put some buffers back in the free queue, kick off dma
	 * scheduling if card was stopped due to overflow before */
	if (freed && test_and_clear_bit(IVTV_F_S_OVERFLOW, &st->s_flags)) {
#if 0
		tasklet_schedule(&itv->dma_sched_tq);
#else
		ivtv_sched_DMA_tasklet((unsigned long) itv);
#endif
	}

	/*FIXME unlock */
	if (retval != 0) { 
		IVTV_DEBUG(IVTV_DEBUG_INFO, "Returning %d\n", retval);
		return retval;
	}

	/* Shouldn't ever get here */
	IVTV_DEBUG(IVTV_DEBUG_ERR, "Something's weird. You shouldn't be here\n");
	return -EIO;
}

void ivtv_swap_copy(const char *buf, const char *ubuf, size_t count) {
	u32 *src,*dst;

	src=(u32 *)ubuf;
	dst=(u32 *)buf;

#ifdef CONFIG_X86
	while ((u32)src <= (u32)ubuf + count) { /* byteswap while copying */
		__asm__ __volatile__ ("bswap %0" :
				      "=r" (*dst) :
				      "0" (*src) );
		src++;dst++;
	}
#else
	{
	int y;
	/* Old slow memcpy then swab */
	memcpy((void *)buf,(void *)ubuf,count);
	for (y = 0; y < count; y += 4) {
		swab32s( (u32 *)((u32)buf + y));
	}
	}
#endif
}

int ivtv_fill_dec_buffers(struct ivtv_open_id *id, const char *ubuf, size_t count) {
	struct ivtv *itv = id->itv;
	struct ivtv_v4l2_stream *stream=&itv->v4l2.streams[id->type];
	struct ivtv_buffer *buf;
	int copybytes=0, bytesread=0, retval=0;
	
	IVTV_DEBUG(IVTV_DEBUG_INFO, "ivtv_fill_dec_buffers, %d bytes\n", count);

        /* Read what the user gives us. queue it for DMA after each buffer
	 * also enqueue partly-full buffers. */

	IVTV_DEBUG(IVTV_DEBUG_INFO,
		   "DEC: free_q: %d elements\n", stream->free_q.elements);
	IVTV_DEBUG(IVTV_DEBUG_INFO,
		   "DEC: dma_q: %d elements\n", stream->dma_q.elements);
	IVTV_DEBUG(IVTV_DEBUG_INFO,
		   "DEC: full_q: %d elements\n", stream->full_q.elements);

	/* FIXME will only do one write. Has underlying code to handle more
	 * 	than one, just need loop control logic for it, if it's 
	 * 	deemed necessary. */
	while (bytesread == 0) {
		DECLARE_WAITQUEUE(wait, current);
		unsigned long flags;

		buf = NULL;
		add_wait_queue(&stream->waitq, &wait);
		do {
			set_current_state(TASK_INTERRUPTIBLE);
			buf = ivtv_deq_peek_head(itv, &stream->free_q);
			if (buf)
				break;

			schedule();

			if (signal_pending(current)) {
				retval = -ERESTARTSYS;
				break;
			}

			spin_lock_irqsave(&itv->lock, flags);
			ivtv_dec_sched_DMA(id->itv);
			spin_unlock_irqrestore(&itv->lock, flags);
		} while (!buf);
		set_current_state(TASK_RUNNING);
		remove_wait_queue(&stream->waitq, &wait);

		if (retval)
			return retval;

		/* bytes left to send > free bytes in current buffer */
		if ((count - bytesread) >
		    (IVTV_DMA_DEC_BUF_SIZE - buf->buffer.bytesused)) {
			copybytes = IVTV_DMA_DEC_BUF_SIZE - buf->buffer.bytesused;
		} else {
			copybytes = count - bytesread;
		}

		/* copy data */
		/* FIXME */
		IVTV_DEBUG(IVTV_DEBUG_INFO, "copying %d bytes to 0x%08x"
					    " (buffer free = %d)\n",
			   copybytes,(int)(buf->buffer.m.userptr + buf->buffer.bytesused),
			   (int)(IVTV_DMA_DEC_BUF_SIZE - buf->buffer.bytesused));

		ivtv_swap_copy((char *)(buf->buffer.m.userptr+buf->buffer.bytesused),
				(char *)((u32)ubuf + bytesread),copybytes);

		bytesread += copybytes;
		buf->buffer.bytesused += copybytes;

		/* enq buffer when full */
		if (buf->buffer.bytesused == IVTV_DMA_DEC_BUF_SIZE) {
			ivtv_del_buf(itv, &stream->free_q, buf);
			ivtv_enq_buf(itv, &stream->full_q, buf);
		}
	}

	return bytesread;
}

/*
 * Schedule host -> hardware DMA of one buffer from the stream (MPEG or YUV) 
 * with the most recent request for more data, but only if dec->dec_needs_data
 * is set.
 *
 * This code can be called from both interrupt context as well as userspace;
 * it does the right things in either case. If called from userspace, it may
 * block only when the same call is in progress in interupt context (since 
 * interrupt context is not allowed to block.) 
 *
 * @returns 0 if the buffer was queued to dma_q and the DMA was initiated.
 *
 *          -EAGAIN if either the full_q queue is empty or the function is
 *                  already in progress in interrupt context.
 *
 *          -ENOSPC if there is no space remaining in the hardware's buffer.
 *                  This should never happen if proper flow control is used.
 *
 *          -EINVAL if the most recent "data needed" interrupt requested an
 *                  unknown stream type (should really never happen!)
 *
 *          -EBUSY if a DMA on the same queue is already in progress (should
 *                 never happen)
 *
 */
void ivtv_dec_sched_DMA(struct ivtv *itv) {
	int ret=0, x=0, bytes_written=0, type=0, max=2;
	struct ivtv_buffer *buf;
        struct ivtv_v4l2_stream *stream=NULL;
	u32 data[IVTV_MBOX_MAX_DATA], result;
	u32 mem_offset, mem_size, hw_stream_type, buffer_bytes;

	IVTV_DEBUG(IVTV_DEBUG_INFO, "ivtv_dec_sched_DMA\n");

	/* fancy way of saying "if (ivtv->dec_needs_data == 0)" */
	if (!test_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags)) {
		IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: no data needed\n");
		return;
	}

	/* Get Card Mem Dst address from mailbox 10 */
	ret = ivtv_api_getresult_nosleep(&itv->dec_mbox[9], &result, &data[0]);
	IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC:  Mailbox 10: 0x%08x, 0x%08x 0x%08x\n",
	           data[0], data[1],data[2]);
	
	hw_stream_type = data[0];

	switch(hw_stream_type) {
		case 0: /* MPG */
			type = IVTV_DEC_STREAM_TYPE_MPG;
			IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: mpg data\n");
			break;
		case 2: /* YUV */
			type = IVTV_DEC_STREAM_TYPE_YUV;
			IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: yuv data\n");
			break;
		default:
			IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: unknown stream type %d\n",
				   data[0]);
			max = 0;
			return;
	}

	stream = &itv->v4l2.streams[type];

	if (test_bit(IVTV_F_I_BUSY, &itv->i_flags)) {
		IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: decoder busy, delaying\n");
		set_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags);
		return;
	}

	/* If we got this far, we have data to send and it wants it */
	clear_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags);

	/* Get card mem addr and size from data array */
	mem_offset = data[1];
	mem_size   = data[2];
	buffer_bytes = data[3]; /* # bytes in card's buffer */

	while ((max > x) && (mem_size > bytes_written)) { /* send a maximum of 
							     'max' buffers */
		buf = __ivtv_deq_peek_head(&stream->full_q);
		if (buf == NULL) {
			IVTV_DEBUG(IVTV_DEBUG_INFO,
				   "DEC: No more buffers to send\n");
			break;
		}
		
#if 1
		if (mem_size < buf->buffer.bytesused) {
			itv->DSGarray[x].size = mem_size;
		} else {
			itv->DSGarray[x].size = buf->buffer.bytesused;
		}
#else
		/* just send the whole buffer */
		itv->DSGarray[x].size = buf->buffer.bytesused;
#endif
		buf->dma_handle = pci_map_single(itv->dev,
						 (void *)(buf->buffer.m.userptr +
							  buf->readpos),
						 itv->DSGarray[x].size,
						 PCI_DMA_TODEVICE);

		itv->DSGarray[x].src	= buf->dma_handle;
		itv->DSGarray[x].dst	= (mem_offset + bytes_written +
					     IVTV_FIRM_SEARCH_DECODER_START);
	
		buf->readpos 		+= itv->DSGarray[x].size;
		bytes_written		+= itv->DSGarray[x].size;
		buf->buffer.bytesused	-= itv->DSGarray[x].size;

		IVTV_DEBUG(IVTV_DEBUG_INFO, "1st 32bits of buffer %d are 0x%08x\n", 
			   buf->buffer.index, *(u32 *)buf->buffer.m.userptr);
		IVTV_DEBUG(IVTV_DEBUG_INFO, "DSGarray[%d]: 0x%08x, 0x%08x 0x%08x\n",
	        	   x, itv->DSGarray[x].src,
			   itv->DSGarray[x].dst,
			   itv->DSGarray[x].size);

		/* buffer is empty? */
		if (buf->buffer.bytesused == 0) {
			__ivtv_del_buf(&stream->full_q, buf);
			__ivtv_enq_buf(&stream->dma_q, buf);
		}
		x++;
	}

	if (x == 0) { /* no full buffers */
		IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: Nothing to send\n");
		set_bit(IVTV_F_I_NEEDS_DATA, &itv->i_flags);
		return;
	}

	//Set Last Element Bit
	itv->DSGarray[x-1].size |= 0x80000000;

	//Schedule DMA XFER
	data[0] = itv->DSG_handle;
	data[1] = bytes_written;
	data[2] = hw_stream_type;

	/* note that we're DMA'ing */
	mod_timer(&itv->dec_timeout, jiffies + DEC_DMA_TIMEOUT);
	set_bit(IVTV_F_S_DMAP, &stream->s_flags);
	set_bit(IVTV_F_I_BUSY, &itv->i_flags);

	ivtv_api_irqsafe(itv->dec_mbox, IVTV_API_DEC_DMA_FROM_HOST, 3,&data[0]);

	IVTV_DEBUG(IVTV_DEBUG_INFO,
	           "Sched DEC dma: addr: 0x%08x, array_size 0x%08x, type 0x%08x\n",
		   data[0], data[1], data[2]);
}

void ivtv_dec_DMA_done(struct ivtv *itv) {
        struct ivtv_v4l2_stream *stream=NULL;
	struct ivtv_buffer *buf;
	int y, stmtype=-1, freed=0;

	IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: DMA Done tasklet\n");

	if (!test_and_clear_bit(IVTV_F_I_BUSY, &itv->i_flags)) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "DMAP not set\n");
		ivtv_show_debug_flags(itv);
		return;
	}

#if 0
	del_timer(&itv->dec_timeout);
#else
	mod_timer(&itv->dec_timeout, jiffies + DEC_DMA_TIMEOUT);
#endif
	
	for (y=IVTV_DEC_STREAM_TYPE_MPG; y < itv->v4l2.streamcount; y++) {
		if (test_and_clear_bit(IVTV_F_S_DMAP, &itv->v4l2.streams[y].s_flags)) {
			stmtype = y;
			break;
		}
	}

	/* Handle OSD DMA */
	if (test_and_clear_bit(IVTV_F_I_OSD_DMA, &itv->i_flags)) {
		IVTV_DEBUG(IVTV_DEBUG_INFO, "OSD: DMA Done\n");
		
		/* wake all the normal streams, in case they fell asleep */
		for (y=IVTV_DEC_STREAM_TYPE_MPG; y < itv->v4l2.streamcount; y++) {
			wake_up(&itv->v4l2.streams[y].waitq);
		}

		wake_up(&itv->dec_master_w);
		return;
	}

	if (stmtype < 0) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: Got DMA-done, not expecting one\n");
		ivtv_show_debug_flags(itv);
		return;
	}

	IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: Stream %d dma-done\n", y);
	stream = &itv->v4l2.streams[y];

	while ((buf = ivtv_deq_buf(itv, &stream->dma_q)) != NULL) {
		IVTV_ASSERT(buf->dma_handle != IVTV_DMA_UNMAPPED);
		pci_unmap_single(itv->dev, buf->dma_handle,
				 IVTV_DMA_DEC_BUF_SIZE, PCI_DMA_TODEVICE);
		buf->dma_handle = IVTV_DMA_UNMAPPED;
		buf->buffer.bytesused	= 0;
		buf->readpos = 0;

		/* put in the 'done' queue */
		__ivtv_enq_buf(&stream->free_q, buf);
		freed++;
	}

	/* if we put some buffers back in the free queue, kick off dma
	 * scheduling if card was stopped due to overflow before */
	if (freed && test_and_clear_bit(IVTV_F_S_OVERFLOW, &stream->s_flags)) {
#if 0
		tasklet_schedule(&itv->dma_sched_tq);
#else
		ivtv_sched_DMA(itv);
#endif
	}

	/* wake up queue filler */
	wake_up(&stream->waitq);
	wake_up(&itv->dec_master_w);
}

int ivtv_get_timing_info(struct ivtv *itv, struct ivtv_ioctl_framesync *info) {
	u32 ret, result, data[IVTV_MBOX_MAX_DATA];

	int suicidecounter = 0;
	
	memset(info, 0x00, sizeof(struct ivtv_ioctl_framesync));

	/* Occasionally, we'll get a wierd, invalid number for 
	 * frames played. fortunately, it sets the SCR timestamp to 0
	 * in that case, which it never is otherwise. cool, huh */
	while (info->scr == 0) { /* eliminate bogus values, FIXME ugly */
		ret = ivtv_api(itv->dec_mbox, &itv->sem_lock,
				IVTV_API_DEC_TIMING_INFO,&result,0,&data[0]);
		if (ret) {
			IVTV_DEBUG(IVTV_DEBUG_ERR, "DEC: err sending timing info\n");
			return ret;
		}

		info->frame	= data[0];
		info->pts	= ((u64)data[2] << 32) | (u64)data[1];
		info->scr	= ((u64)data[4] << 32) | (u64)data[3];

		if (suicidecounter++ > 10) { /* endless loops are bad! */
			IVTV_DEBUG(IVTV_DEBUG_ERR,"Timeout getting frames played\n");
			return -1;
		}
		if (info->scr == 0)
			ivtv_sleep_timeout(HZ/50);
	}

	return 0;
}

ssize_t ivtv_write(struct ivtv_open_id *id, const char *ubuf, size_t count) {
	int bytes_written=0, ret;
	unsigned long flags;

	IVTV_DEBUG(IVTV_DEBUG_INFO, "ivtv_write\n");

	while (bytes_written < count) { /* completely use up user data 
					 * before returning */
		/* buffer the data - this may block waiting on free buffers */
		ret = ivtv_fill_dec_buffers(id, ubuf + bytes_written, 
					    (count - bytes_written));

		if (ret < 0) {
			break;
		} else {
			bytes_written += ret;
		}

		/* send it! it'll return right away if no data needed */
		spin_lock_irqsave(&id->itv->lock, flags);
		ivtv_dec_sched_DMA(id->itv);
		spin_unlock_irqrestore(&id->itv->lock, flags);
	}

	IVTV_DEBUG(IVTV_DEBUG_INFO, "DEC: returning %d\n", bytes_written);
	return bytes_written;
}

int ivtv_stream_has_data(struct ivtv_open_id *id) {
	return ivtv_get_free_elements(id->itv, &id->itv->v4l2.streams[id->type].full_q);
}

int ivtv_dec_stream_has_space(struct ivtv_open_id *id) {
	return ivtv_get_free_elements(id->itv, &id->itv->v4l2.streams[id->type].free_q);
}

unsigned int ivtv_dec_poll(struct file *filp, poll_table *wait) {
	struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
	unsigned int mask = 0;

	/* add stream's waitq to the poll list */
	poll_wait(filp, &id->itv->v4l2.streams[id->type].waitq, wait);

#if 0
	if (down_interruptible(&id->itv->sem_lock))
		return -ERESTARTSYS;

	if(ivtv_dec_stream_has_space(id)) {
		mask |= POLLOUT | POLLWRNORM; /* Writable */
	}

	up(&id->itv->sem_lock);
#else
	mask |= POLLOUT | POLLWRNORM;
#endif
	return mask;
}

unsigned int ivtv_poll(struct file *filp, poll_table *wait) {
	struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
	unsigned int mask = 0;

	/* add stream's waitq to the poll list */
	poll_wait(filp, &id->itv->v4l2.streams[id->type].waitq, wait);

#if 0
	if (down_interruptible(&id->itv->sem_lock))
		return -ERESTARTSYS;

	if(ivtv_stream_has_data(id)) {
		mask |= POLLIN | POLLRDNORM; /* readable */
	}

	up(&id->itv->sem_lock);
#else
	mask |= POLLIN | POLLRDNORM;
#endif
	return mask;
}

void ivtv_print_boxes(struct ivtv_mailbox *mbox) {

	int x,y;

	IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 10ms\n");
	ivtv_sleep_timeout(HZ/100);

	if (NULL == mbox) {
		IVTV_DEBUG(IVTV_DEBUG_IOCTL, "Mailboxes not initialized!\n");
		return;
	}

	for (x = 0; x <= IVTV_MBOX_MAX_BOXES; x++) {
		IVTV_DEBUG(IVTV_DEBUG_IOCTL, "mbox: 0x%08x, # %d\n", (u32)mbox, x);
		IVTV_DEBUG(IVTV_DEBUG_IOCTL, "flags:   0x%08x   ",(u32)readl(&mbox->flags));
		IVTV_DEBUG(IVTV_DEBUG_IOCTL, "cmd:     0x%08x\n", readl(&mbox->cmd));
		IVTV_DEBUG(IVTV_DEBUG_IOCTL, "result:  0x%08x   ", readl(&mbox->retval));
		IVTV_DEBUG(IVTV_DEBUG_IOCTL, "timeout: 0x%08x\n", readl(&mbox->timeout));
		IVTV_DEBUG(IVTV_DEBUG_IOCTL, "Data:\n");
		for (y = 0; y < IVTV_MBOX_MAX_DATA; y++) {
			IVTV_DEBUG(IVTV_DEBUG_IOCTL, "[%02d]0x%08x, ", y, readl(&mbox->data[y]));
			if (2 == y%3) IVTV_DEBUG(IVTV_DEBUG_IOCTL, "\n");
		}
		/*Since mbox has type ptr, this should step it up*/
		/* to the start of the next mbox */
		mbox++; 
		IVTV_DEBUG(IVTV_DEBUG_IOCTL, "\n");
	}
	return;
}

int tmk_test2(struct inode *inode, struct file *filep) {
	//struct ivtv *itv = filep->private_data;

	hack = 0;
	printk("Debug: 0x%08x, IRQ 0x%08x, combo: 0x%08x\n", ivtv_debug, IVTV_DEBUG_IRQ,
			(ivtv_debug & IVTV_DEBUG_IRQ));
	
	return 0;
}	

int tmk_test1(struct inode *inode, struct file *filep) {
	struct ivtv *itv = filep->private_data;
	//u32 testmask;
	//int x;
	
	printk("hack is currently %d\n", hack);
	IVTV_DEBUG(IVTV_DEBUG_ERR, "card type is %d\n",itv->card_type);
	
	return 0;
}

int ivtv_close(struct ivtv_open_id *id) {
	struct ivtv *itv=id->itv;

	/* sem_lock must be held */
	IVTV_ASSERT(ivtv_sem_count(&itv->sem_lock) <= 0);

	if( (id->type != IVTV_DEC_STREAM_TYPE_MPG) && (id->type != IVTV_DEC_STREAM_TYPE_YUV)) {
		if (atomic_read(&itv->capturing)) {
			atomic_dec(&itv->capturing);
			return ivtv_stop_capture(id);
		}
	}

	if( (id->type == IVTV_DEC_STREAM_TYPE_MPG) || (id->type == IVTV_DEC_STREAM_TYPE_YUV)) {
		if (atomic_read(&itv->decoding)) {
			atomic_dec(&itv->decoding);
			return ivtv_stop_decode(id);
		}
	}

	return 0;
}

static int module_start(void)  {
	int loop_a;

	/* Validate parameters */
	if (((yuv_buffers > IVTV_MAX_YUV_BUFFERS)
	    || (yuv_buffers < IVTV_MIN_YUV_BUFFERS))
	    && (yuv_buffers != 0)) {
		IVTV_DEBUG(IVTV_DEBUG_ERR,
			   "Error! yuv_buffers must be between 40 and 500\n");
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n");
		return -1;
	}
	
#ifdef YUV_FIXUP
	if ((yuv_fixup != 0) && (yuv_fixup != 1)) {
		IVTV_DEBUG(IVTV_DEBUG_ERR,
			   "Error! yuv_fixup must be 0 or 1\n");
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n");
		return -1;
	}
#endif
	if ((dec_mpg_buffers > IVTV_MAX_DEC_MPG_BUFFERS)
	    || (dec_mpg_buffers < IVTV_MIN_DEC_MPG_BUFFERS)) {
		IVTV_DEBUG(IVTV_DEBUG_ERR,
			   "Error! dec_mpg_buffers must be between 5 and 100\n");
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n");
		return -1;
	}

	if (((dec_yuv_buffers > IVTV_MAX_DEC_YUV_BUFFERS)
	    || (dec_yuv_buffers < IVTV_MIN_DEC_YUV_BUFFERS))
	    && (dec_yuv_buffers != 0)) {
		IVTV_DEBUG(IVTV_DEBUG_ERR,
			   "Error! dec_yuv_buffers must be between 17 and 500\n");
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n");
		return -1;
	}

	if ((mpg_buffers > IVTV_MAX_MPG_BUFFERS)
	    || (mpg_buffers < IVTV_MIN_MPG_BUFFERS)) {
		IVTV_DEBUG(IVTV_DEBUG_ERR,
			   "Error! mpg_buffers must be between 15 and 100\n");
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n");
		return -1;
	}

	if ((dec_yuv_qlen > dec_yuv_buffers) || (dec_yuv_qlen < 0)) {
		IVTV_DEBUG(IVTV_DEBUG_ERR,
			   "Error! dec_yuv_qlen must be between 0 and %d\n", 
			   dec_yuv_buffers);
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n");
		return -1;
	}

	if ((dec_mpg_qlen > dec_mpg_buffers) || (dec_mpg_qlen < 0)) {
		IVTV_DEBUG(IVTV_DEBUG_ERR,
			   "Error! dec_mpg_qlen must be between 0 and %d\n", 
			   dec_mpg_buffers);
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n");
		return -1;
	}

	if ((vbi_buffers > IVTV_MAX_VBI_BUFFERS)
	    || (vbi_buffers < IVTV_MIN_VBI_BUFFERS)) {
		IVTV_DEBUG(IVTV_DEBUG_ERR,
			   "Error! vbi_buffers must be between 3 and 100\n");
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n");
		return -1;
	}

	if ((num_devices > IVTV_MAX_CARDS) || (num_devices < 1)) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Error! num_devices must be between 1 and 9 (not working yet)\n");
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Exiting..\n");
		return -1;
	}

	if (ivtv_debug < 0) IVTV_DEBUG(IVTV_DEBUG_ERR, "debug value must be >= 0!\n");

       	IVTV_DEBUG(IVTV_DEBUG_INFO,
		   "Loading, I'll try to detect %d devices!\n", num_devices);
       	IVTV_DEBUG(IVTV_DEBUG_INFO,
		   " .. running on kernel %s\n", UTS_RELEASE);
	IVTV_DEBUG(IVTV_DEBUG_INFO,
		   "Setting some variables to invalid for detection\n");

	for (loop_a = 0; loop_a < IVTV_MAX_CARDS; loop_a++) {
		ivtv_cards[loop_a].num = -1;
		ivtv_cards[loop_a].dev = NULL;
	}

	SGarray_size = (mpg_buffers + yuv_buffers + vbi_buffers) * 2;
	DSGarray_size = (dec_mpg_buffers + dec_yuv_buffers) * 2;

	IVTV_DEBUG(IVTV_DEBUG_ERR, "SGarray_size = %d, DSGarray_size = %d\n",
			SGarray_size, DSGarray_size);

       	IVTV_DEBUG(IVTV_DEBUG_INFO, "Scanning PCI bus..\n");
	if (pci_module_init(&ivtv_pci_driver)) {
		IVTV_DEBUG(IVTV_DEBUG_ERR, "Error detecting PCI card\n");	
		return -ENODEV;
	}

       	return 0;
}

static void module_cleanup(void) {

	pci_unregister_driver(&ivtv_pci_driver);
       	IVTV_DEBUG(IVTV_DEBUG_ERR, "You've not seen the last of willy!\n"); 
}

module_init(module_start);
module_exit(module_cleanup);
