<commit_before>/*
   tm6000-video.c - driver for TM5600/TM6000 USB video capture devices

   Copyright (C) 2006-2007 <NAME> <<EMAIL>>

   Copyright (C) 2007 <NAME> <<EMAIL>>
	- Fixed module load/unload

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation version 2

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/random.h>
#include <linux/version.h>
#include <linux/usb.h>
#include <linux/videodev2.h>
#ifdef CONFIG_VIDEO_V4L1_COMPAT
#include <linux/videodev.h>
#endif
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/highmem.h>
#include <linux/freezer.h>

#include "tm6000-regs.h"
#include "tm6000.h"

#define BUFFER_TIMEOUT     msecs_to_jiffies(2000)  /* 2 seconds */

/* Limits minimum and default number of buffers */
#define TM6000_MIN_BUF 4
#define TM6000_DEF_BUF 8

/* Declare static vars that will be used as parameters */
static unsigned int vid_limit = 16;	/* Video memory limit, in Mb */
static int video_nr = -1;		/* /dev/videoN, -1 for autodetect */

unsigned long tm6000_devused;

/* Debug level */
int tm6000_debug;

/* supported controls */
static struct v4l2_queryctrl tm6000_qctrl[] = {
	{
		.id            = V4L2_CID_BRIGHTNESS,
		.type          = V4L2_CTRL_TYPE_INTEGER,
		.name          = "Brightness",
		.minimum       = 0,
		.maximum       = 255,
		.step          = 1,
		.default_value = 54,
		.flags         = 0,
	}, {
		.id            = V4L2_CID_CONTRAST,
		.type          = V4L2_CTRL_TYPE_INTEGER,
		.name          = "Contrast",
		.minimum       = 0,
		.maximum       = 255,
		.step          = 0x1,
		.default_value = 119,
		.flags         = 0,
	}, {
		.id            = V4L2_CID_SATURATION,
		.type          = V4L2_CTRL_TYPE_INTEGER,
		.name          = "Saturation",
		.minimum       = 0,
		.maximum       = 255,
		.step          = 0x1,
		.default_value = 112,
		.flags         = 0,
	}, {
		.id            = V4L2_CID_HUE,
		.type          = V4L2_CTRL_TYPE_INTEGER,
		.name          = "Hue",
		.minimum       = -128,
		.maximum       = 127,
		.step          = 0x1,
		.default_value = 0,		//4 ?
		.flags         = 0,
	}
};

static int qctl_regs[ARRAY_SIZE(tm6000_qctrl)];

static struct tm6000_fmt format[] = {
	{
		.name     = "4:2:2, packed, YVY2",
		.fourcc   = V4L2_PIX_FMT_YUYV,
		.depth    = 16,
	},{
		.name     = "4:2:2, packed, UYVY",
		.fourcc   = V4L2_PIX_FMT_UYVY,
		.depth    = 16,
	},{
		.name     = "A/V + VBI mux packet",
		.fourcc   = V4L2_PIX_FMT_TM6000,
		.depth    = 16,
	}
};

static LIST_HEAD(tm6000_corelist);

/* ------------------------------------------------------------------
	DMA and thread functions
   ------------------------------------------------------------------*/

#define norm_maxw(a) 720
#define norm_maxh(a) 576

//#define norm_minw(a) norm_maxw(a)
#define norm_minw(a) norm_maxw(a)
#define norm_minh(a) norm_maxh(a)

/*
 * video-buf generic routine to get the next available buffer
 */
static int inline get_next_buf (struct tm6000_dmaqueue *dma_q,
					  struct tm6000_buffer    **buf)
{
	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);

	if (list_empty(&dma_q->active)) {
		dprintk(dev, V4L2_DEBUG_QUEUE,"No active queue to serve\n");
		return 0;
	}

	*buf = list_entry(dma_q->active.next,
			struct tm6000_buffer, vb.queue);

	/* Nobody is waiting something to be done, just return */
	if (!waitqueue_active(&(*buf)->vb.done)) {
		mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
		return -1;
	}

	return 1;
}

/*
 * Announces that a buffer were filled and request the next
 */
static void inline buffer_filled (struct tm6000_core *dev,
				  struct tm6000_buffer *buf)
{
	/* Advice that buffer was filled */
	dprintk(dev, V4L2_DEBUG_ISOC, "[%p/%d] wakeup\n",buf,buf->vb.i);
	buf->vb.state = STATE_DONE;
	buf->vb.field_count++;
	do_gettimeofday(&buf->vb.ts);

	list_del(&buf->vb.queue);
	wake_up(&buf->vb.done);
}

/*
 * Macro to allow copying data into the proper memory type
 */

#define bufcpy(buf,out_ptr,in_ptr,size) 				\
	{								\
		if (__copy_to_user(out_ptr,in_ptr,size)!=0)		\
			tm6000_err("copy_to_user failed.\n");		\
	}

/*
 * Identify the tm5600/6000 buffer header type and properly handles
 */
static int copy_streams(u8 *data, u8 *out_p, unsigned long len,
			struct urb *urb, struct tm6000_buffer **buf)
{
	struct tm6000_dmaqueue  *dma_q = urb->context;
	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
	u8 *ptr=data, *endp=data+len;
	u8 c;
	unsigned int cmd, cpysize, pktsize, size, field, block, line, pos=0;
	unsigned long header;
	int rc=0;

	/* FIXME: this is the hardcoded window size
	 */
	unsigned int linesize=720*2;

//static int last_line=-2;

	for (ptr=data; ptr<endp;) {
		if (!dev->isoc_ctl.cmd) {
			/* Seek for sync */
			for (ptr+=3;ptr<endp;ptr++) {
				if (*ptr==0x47) {
					ptr-=3;
					break;
				}
			}
			if (ptr>=endp)
				return rc;

			/* Get message header */
			header=*(unsigned long *)ptr;
			ptr+=4;
			c=(header>>24) & 0xff;

			/* split the header fields */
			size  = (((header & 0x7e)<<1) -1) *4;
			block = (header>>7) & 0xf;
			field = (header>>11) & 0x1;
			line  = (header>>12) & 0x1ff;
			cmd   = (header>>21) & 0x7;

			/* FIXME: Maximum possible line is 511.
			 * This doesn't seem to be enough for PAL standards
			 */

			/* Validates header fields */
			if(size>TM6000_URB_MSG_LEN)
				size=TM6000_URB_MSG_LEN;
			if(block>=8)
				cmd = TM6000_URB_MSG_ERR;

			/* FIXME: Mounts the image as field0+field1
			 * It should, instead, check if the user selected
			 * entrelaced or non-entrelaced mode
			 */
			pos=((line<<1)+field)*linesize+
						block*TM6000_URB_MSG_LEN;



			/* Don't allow to write out of the buffer */
			if (pos+TM6000_URB_MSG_LEN > (*buf)->vb.size)
				cmd = TM6000_URB_MSG_ERR;

			/* Prints debug info */
			dprintk(dev, V4L2_DEBUG_ISOC, "size=%d, num=%d, "
					" line=%d, field=%d\n",
					size, block, line, field);

			dev->isoc_ctl.cmd  = cmd;
			dev->isoc_ctl.size = size;
			dev->isoc_ctl.pos  = pos;
			dev->isoc_ctl.pktsize = pktsize = TM6000_URB_MSG_LEN;
		} else {
			cmd = dev->isoc_ctl.cmd;
			size= dev->isoc_ctl.size;
			pos = dev->isoc_ctl.pos;
			pktsize = dev->isoc_ctl.pktsize;
		}
		cpysize=(endp-ptr>size)?size:endp-ptr;

		if (cpysize) {
			/* handles each different URB message */
			switch(cmd) {
			case TM6000_URB_MSG_VIDEO:
				/* Fills video buffer */
				bufcpy(*buf,&out_p[pos],ptr,cpysize);
			break;
			}
		}
		if (cpysize<size) {
			/* End of URB packet, but cmd processing is not
			 * complete. Preserve the state for a next packet
			 */
			dev->isoc_ctl.pos = pos+cpysize;
			dev->isoc_ctl.size= size-cpysize;
			dev->isoc_ctl.cmd = cmd;
			dev->isoc_ctl.pktsize = pktsize-cpysize;
			ptr+=cpysize;
		} else {
			dev->isoc_ctl.cmd = 0;
			ptr+=pktsize;
		}
	}

	return rc;
}
/*
 * Identify the tm5600/6000 buffer header type and properly handles
 */
static int copy_multiplexed(u8 *ptr, u8 *out_p, unsigned long len,
			struct urb *urb, struct tm6000_buffer **buf)
{
	struct tm6000_dmaqueue  *dma_q = urb->context;
	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
	unsigned int pos=dev->isoc_ctl.pos,cpysize;
	int rc=1;

	while (len>0) {
		cpysize=min(len,(*buf)->vb.size-pos);
//printk("Copying %d bytes (max=%lu) from %p to %p[%u]\n",cpysize,(*buf)->vb.size,ptr,out_p,pos);
		bufcpy(*buf,&out_p[pos],ptr,cpysize);
		pos+=cpysize;
		ptr+=cpysize;
		len-=cpysize;
		if (pos >= (*buf)->vb.size) {
			pos=0;
			/* Announces that a new buffer were filled */
			buffer_filled (dev, *buf);
			dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n");

			rc=get_next_buf (dma_q, buf);
			if (rc<=0) {
				*buf=NULL;
				printk(KERN_ERR "tm6000: buffer underrun\n");
				break;
			}
		}
	}

	dev->isoc_ctl.pos=pos;
	return rc;
}

static void inline print_err_status (struct tm6000_core *dev,
				     int packet, int status)
{
	char *errmsg = "Unknown";

	switch(status) {
	case -ENOENT:
		errmsg = "unlinked synchronuously";
		break;
	case -ECONNRESET:
		errmsg = "unlinked asynchronuously";
		break;
	case -ENOSR:
		errmsg = "Buffer error (overrun)";
		break;
	case -EPIPE:
		errmsg = "Stalled (device not responding)";
		break;
	case -EOVERFLOW:
		errmsg = "Babble (bad cable?)";
		break;
	case -EPROTO:
		errmsg = "Bit-stuff error (bad cable?)";
		break;
	case -EILSEQ:
		errmsg = "CRC/Timeout (could be anything)";
		break;
	case -ETIME:
		errmsg = "Device does not respond";
		break;
	}
	if (packet<0) {
		dprintk(dev, V4L2_DEBUG_QUEUE, "URB status %d [%s].\n",
			status, errmsg);
	} else {
		dprintk(dev, V4L2_DEBUG_QUEUE, "URB packet %d, status %d [%s].\n",
			packet, status, errmsg);
	}
}


/*
 * Controls the isoc copy of each urb packet
 */
static inline int tm6000_isoc_copy(struct urb *urb, struct tm6000_buffer **buf)
{
	struct tm6000_dmaqueue  *dma_q = urb->context;
	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
	void *outp=videobuf_to_vmalloc (&((*buf)->vb));
	int i, len=0, rc=1;
	int size=(*buf)->vb.size;
	char *p;
	unsigned long copied;

	copied=0;

	if (urb->status<0) {
		print_err_status (dev,-1,urb->status);
		return 0;
	}

	for (i = 0; i < urb->number_of_packets; i++) {
		int status = urb->iso_frame_desc[i].status;

		if (status<0) {
			print_err_status (dev,i,status);
			continue;
		}

		len=urb->iso_frame_desc[i].actual_length;

		if (len>=TM6000_URB_MSG_LEN) {
			p=urb->transfer_buffer + urb->iso_frame_desc[i].offset;
			if (!urb->iso_frame_desc[i].status) {
				if (((*buf)->fmt->fourcc)==V4L2_PIX_FMT_TM6000) {
					rc=copy_multiplexed(p,outp,len,urb,buf);
					if (rc<=0)
						return rc;
				} else {
					rc=copy_streams(p,outp,len,urb,buf);
				}
			}
			copied += len;
			if (copied>=size)
				break;
		}
	}

	if (((*buf)->fmt->fourcc)!=V4L2_PIX_FMT_TM6000) {
		buffer_filled (dev, *buf);
		dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n");
	}

	return rc;
}

/* ------------------------------------------------------------------
	URB control
   ------------------------------------------------------------------*/

/*
 * IRQ callback, called by URB callback
 */
static void tm6000_irq_callback(struct urb *urb)
{
	struct tm6000_buffer    *buf;
	struct tm6000_dmaqueue  *dma_q = urb->context;
	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
	int rc,i;
	unsigned long flags;

	spin_lock_irqsave(&dev->slock,flags);

	rc=get_next_buf (dma_q, &buf);
	if (rc<=0)
		goto ret;

	/* Copy data from URB */
	rc=tm6000_isoc_copy(urb, &buf);

ret:
	/* Reset urb buffers */
	for (i = 0; i < urb->number_of_packets; i++) {
		urb->iso_frame_desc[i].status = 0;
		urb->iso_frame_desc[i].actual_length = 0;
	}
	urb->status = 0;

	if ((urb->status = usb_submit_urb(urb, GFP_ATOMIC))) {
		tm6000_err("urb resubmit failed (error=%i)\n",
			urb->status);
	}

	if (rc>=0) {
		if (!rc) {
			dprintk(dev, V4L2_DEBUG_QUEUE, "No active queue to serve\n");
			del_timer(&dma_q->timeout);
		} else {
			/* Data filled, reset watchdog */
			mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
		}
	}
	spin_unlock_irqrestore(&dev->slock,flags);
}

/*
 * Stop and Deallocate URBs
 */
static void tm6000_uninit_isoc(struct tm6000_core *dev)
{
	struct urb *urb;
	int i;

	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
		urb=dev->isoc_ctl.urb[i];
		if (urb) {
			usb_kill_urb(urb);
			usb_unlink_urb(urb);
			if (dev->isoc_ctl.transfer_buffer[i]) {
				usb_buffer_free(dev->udev,
						urb->transfer_buffer_length,
						dev->isoc_ctl.transfer_buffer[i],
						urb->transfer_dma);
			}
			usb_free_urb(urb);
			dev->isoc_ctl.urb[i] = NULL;
		}
		dev->isoc_ctl.transfer_buffer[i] = NULL;
	}

	kfree (dev->isoc_ctl.urb);
	kfree (dev->isoc_ctl.transfer_buffer);
	dev->isoc_ctl.urb=NULL;
	dev->isoc_ctl.transfer_buffer=NULL;

	dev->isoc_ctl.num_bufs=0;
}

/*
 * Stop video thread - FIXME: Can be easily removed
 */
static void tm6000_stop_thread(struct tm6000_dmaqueue  *dma_q)
{
	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);

	tm6000_uninit_isoc(dev);
}


/*
 * Allocate URBs and start IRQ
 */
static int tm6000_prepare_isoc(struct tm6000_core *dev,
		     int max_packets, int num_bufs)
{
	struct tm6000_dmaqueue *dma_q = &dev->vidq;
	int i;
	int sb_size, pipe;
	struct urb *urb;
	int j, k;

	/* De-allocates all pending stuff */
	tm6000_uninit_isoc(dev);

	dev->isoc_ctl.num_bufs=num_bufs;

	dev->isoc_ctl.urb=kmalloc(sizeof(void *)*num_bufs,
				   GFP_KERNEL);
	if (!dev->isoc_ctl.urb) {
		tm6000_err("cannot alloc memory for usb buffers\n");
		return -ENOMEM;
	}

	dev->isoc_ctl.transfer_buffer=kmalloc(sizeof(void *)*num_bufs,
				   GFP_KERNEL);
	if (!dev->isoc_ctl.urb) {
		tm6000_err("cannot allocate memory for usbtransfer\n");
		kfree(dev->isoc_ctl.urb);
		return -ENOMEM;
	}

	dev->isoc_ctl.max_pkt_size=dev->max_isoc_in;

	sb_size = max_packets * dev->isoc_ctl.max_pkt_size;


	/* allocate urbs and transfer buffers */
	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
		urb = usb_alloc_urb(max_packets, GFP_KERNEL);
		if (!urb) {
			tm6000_err("cannot alloc isoc_ctl.urb %i\n", i);
			tm6000_uninit_isoc(dev);
			return -ENOMEM;
		}
		dev->isoc_ctl.urb[i] = urb;

		dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->udev,
			sb_size, GFP_KERNEL, &urb->transfer_dma);
		if (!dev->isoc_ctl.transfer_buffer[i]) {
			tm6000_err ("unable to allocate %i bytes for transfer"
					" buffer %i\n", sb_size, i);
			tm6000_uninit_isoc(dev);
			return -ENOMEM;
		}
		memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);

		pipe=usb_rcvisocpipe(dev->udev,
					dev->isoc_in->desc.bEndpointAddress &
					USB_ENDPOINT_NUMBER_MASK);
		usb_fill_int_urb(urb, dev->udev, pipe,
					dev->isoc_ctl.transfer_buffer[i],sb_size,
					tm6000_irq_callback, dma_q,
					dev->isoc_in->desc.bInterval);

		urb->number_of_packets = max_packets;
		urb->transfer_flags = URB_ISO_ASAP;

		k = 0;
		for (j = 0; j < max_packets; j++) {
			urb->iso_frame_desc[j].offset = k;
			urb->iso_frame_desc[j].length =
						dev->isoc_ctl.max_pkt_size;
			k += dev->isoc_ctl.max_pkt_size;
		}
	}

	return 0;
}

static int tm6000_start_thread( struct tm6000_dmaqueue  *dma_q,
				struct tm6000_buffer *buf)
{
	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
	int i,rc;

	dma_q->frame=0;
	dma_q->ini_jiffies=jiffies;

	init_waitqueue_head(&dma_q->wq);

	/* submit urbs and enables IRQ */
	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
		rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
		if (rc) {
			tm6000_err("submit of urb %i failed (error=%i)\n", i,
				   rc);
			tm6000_uninit_isoc(dev);
			return rc;
		}
	}

	if (rc<0)
		return rc;

	return 0;
}

static int restart_video_queue(struct tm6000_dmaqueue *dma_q)
{
	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);

	struct tm6000_buffer *buf, *prev;
	struct list_head *item;

	dprintk(dev, V4L2_DEBUG_QUEUE, "%s dma_q=0x%08lx\n",
					 __FUNCTION__,(unsigned long)dma_q);

	if (!list_empty(&dma_q->active)) {
		buf = list_entry(dma_q->active.next, struct tm6000_buffer, vb.queue);
		dprintk(dev, V4L2_DEBUG_QUEUE,
			"restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i);

		dprintk(dev, V4L2_DEBUG_QUEUE, "Restarting video dma\n");
		tm6000_stop_thread(dma_q);
		tm6000_start_thread(dma_q, buf);

		/* cancel all outstanding capture / vbi requests */
		list_for_each(item,&dma_q->active) {
			buf = list_entry(item, struct tm6000_buffer, vb.queue);

			list_del(&buf->vb.queue);
			buf->vb.state = STATE_ERROR;
			wake_up(&buf->vb.done);
		}
		mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);

		return 0;
	}

	prev = NULL;
	for (;;) {
		if (list_empty(&dma_q->queued))
			return 0;
		buf = list_entry(dma_q->queued.next, struct tm6000_buffer, vb.queue);
		if (NULL == prev) {
			list_del(&buf->vb.queue);
			list_add_tail(&buf->vb.queue,&dma_q->active);

			dprintk(dev, V4L2_DEBUG_QUEUE, "Restarting video dma\n");
			tm6000_stop_thread(dma_q);
			tm6000_start_thread(dma_q, buf);

			buf->vb.state = STATE_ACTIVE;
			mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
			dprintk(dev, V4L2_DEBUG_QUEUE, "[%p/%d] restart_queue -"
					" first active\n", buf, buf->vb.i);

		} else if (prev->vb.width  == buf->vb.width  &&
			   prev->vb.height == buf->vb.height &&
			   prev->fmt       == buf->fmt) {
			list_del(&buf->vb.queue);
			list_add_tail(&buf->vb.queue,&dma_q->active);
			buf->vb.state = STATE_ACTIVE;
			dprintk(dev, V4L2_DEBUG_QUEUE, "[%p/%d] restart_queue -"
					" move to active\n",buf,buf->vb.i);
		} else {
			return 0;
		}
		prev = buf;
	}
}

static void tm6000_vid_timeout(unsigned long data)
{
	struct tm6000_core      *dev  = (struct tm6000_core*)data;
	struct tm6000_dmaqueue *vidq = &dev->vidq;
	struct tm6000_buffer   *buf;
	unsigned long flags;

	spin_lock_irqsave(&dev->slock,flags);
	while (!list_empty(&vidq->active)) {
		buf = list_entry(vidq->active.next, struct tm6000_buffer,
								 vb.queue);
		list_del(&buf->vb.queue);
		buf->vb.state = STATE_ERROR;
		wake_up(&buf->vb.done);
		dprintk(dev, V4L2_DEBUG_QUEUE, "tm6000/0: [%p/%d] timeout\n",
							 buf, buf->vb.i);
	}

	restart_video_queue(vidq);
	spin_unlock_irqrestore(&dev->slock,flags);
}

/* ------------------------------------------------------------------
	Videobuf operations
   ------------------------------------------------------------------*/

static int
buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
{
	struct tm6000_fh *fh = vq->priv_data;

	*size = fh->fmt->depth * fh->width * fh->height >> 3;
	if (0 == *count)
		*count = TM6000_DEF_BUF;

	if (*count < TM6000_MIN_BUF) {
		*count=TM6000_MIN_BUF;
	}

	while (*size * *count > vid_limit * 1024 * 1024)
		(*count)--;

	return 0;
}

static void free_buffer(struct videobuf_queue *vq, struct tm6000_buffer *buf)
{
	if (in_interrupt())
		BUG();

	videobuf_waiton(&buf->vb,0,0);
	videobuf_vmalloc_free(&buf->vb);
	buf->vb.state = STATE_NEEDS_INIT;
}

static int
buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
						enum v4l2_field field)
{
	struct tm6000_fh     *fh  = vq->priv_data;
	struct tm6000_buffer *buf = container_of(vb,struct tm6000_buffer,vb);
	struct tm6000_core   *dev = fh->dev;
	int rc=0, urbsize, urb_init=0;

	BUG_ON(NULL == fh->fmt);


	/* FIXME: It assumes depth=2 */
	/* The only currently supported format is 16 bits/pixel */
	buf->vb.size = fh->fmt->depth*fh->width*fh->height >> 3;
	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
		return -EINVAL;

	if (buf->fmt       != fh->fmt    ||
	    buf->vb.width  != fh->width  ||
	    buf->vb.height != fh->height ||
	    buf->vb.field  != field) {
		buf->fmt       = fh->fmt;
		buf->vb.width  = fh->width;
		buf->vb.height = fh->height;
		buf->vb.field  = field;
		buf->vb.state = STATE_NEEDS_INIT;
	}

	if (STATE_NEEDS_INIT == buf->vb.state) {
		if (0 != (rc = videobuf_iolock(vq,&buf->vb,NULL)))
			goto fail;
		urb_init=1;
	}


	if (!dev->isoc_ctl.num_bufs)
		urb_init=1;

	if (urb_init) {
		/* memory for video
		   Should be at least
		   Vres x Vres x 2 bytes/pixel by frame */
		urbsize=buf->vb.size;

		 /* memory for audio
		    Should be at least
		    bitrate * 2 channels * 2 bytes / frame rate */
		if (dev->norm & V4L2_STD_525_60) {
			urbsize+=(dev->audio_bitrate*4+29)/30;
		} else {
			urbsize+=(dev->audio_bitrate*4+24)/25;
		}

		/* each audio frame seeems to have a frame number
		   with 2 bytes */
		urbsize+=2;

		/* Add 4 bytes by each 180 bytes frame */
		urbsize+=((urbsize+179)/180)*4;

		/* Round to an enough number of URBs */
		urbsize=(urbsize+dev->max_isoc_in-1)/dev->max_isoc_in;


printk("Allocating %d packets to handle %lu size\n",  urbsize,buf->vb.size);

		dprintk(dev, V4L2_DEBUG_QUEUE, "Allocating %d packets to handle "
					"%lu size\n", urbsize,buf->vb.size);
		rc = tm6000_prepare_isoc(dev, urbsize, 2);
<commit_msg>V4L/DVB (12798): tm6000: Split header processing from header find<commit_after>/*
   tm6000-video.c - driver for TM5600/TM6000 USB video capture devices

   Copyright (C) 2006-2007 <NAME> <<EMAIL>>

   Copyright (C) 2007 <NAME> <<EMAIL>>
	- Fixed module load/unload

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation version 2

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/random.h>
#include <linux/version.h>
#include <linux/usb.h>
#include <linux/videodev2.h>
#ifdef CONFIG_VIDEO_V4L1_COMPAT
#include <linux/videodev.h>
#endif
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/highmem.h>
#include <linux/freezer.h>

#include "tm6000-regs.h"
#include "tm6000.h"

#define BUFFER_TIMEOUT     msecs_to_jiffies(2000)  /* 2 seconds */

/* Limits minimum and default number of buffers */
#define TM6000_MIN_BUF 4
#define TM6000_DEF_BUF 8

/* Declare static vars that will be used as parameters */
static unsigned int vid_limit = 16;	/* Video memory limit, in Mb */
static int video_nr = -1;		/* /dev/videoN, -1 for autodetect */

unsigned long tm6000_devused;

/* Debug level */
int tm6000_debug;

/* supported controls */
static struct v4l2_queryctrl tm6000_qctrl[] = {
	{
		.id            = V4L2_CID_BRIGHTNESS,
		.type          = V4L2_CTRL_TYPE_INTEGER,
		.name          = "Brightness",
		.minimum       = 0,
		.maximum       = 255,
		.step          = 1,
		.default_value = 54,
		.flags         = 0,
	}, {
		.id            = V4L2_CID_CONTRAST,
		.type          = V4L2_CTRL_TYPE_INTEGER,
		.name          = "Contrast",
		.minimum       = 0,
		.maximum       = 255,
		.step          = 0x1,
		.default_value = 119,
		.flags         = 0,
	}, {
		.id            = V4L2_CID_SATURATION,
		.type          = V4L2_CTRL_TYPE_INTEGER,
		.name          = "Saturation",
		.minimum       = 0,
		.maximum       = 255,
		.step          = 0x1,
		.default_value = 112,
		.flags         = 0,
	}, {
		.id            = V4L2_CID_HUE,
		.type          = V4L2_CTRL_TYPE_INTEGER,
		.name          = "Hue",
		.minimum       = -128,
		.maximum       = 127,
		.step          = 0x1,
		.default_value = 0,		//4 ?
		.flags         = 0,
	}
};

static int qctl_regs[ARRAY_SIZE(tm6000_qctrl)];

static struct tm6000_fmt format[] = {
	{
		.name     = "4:2:2, packed, YVY2",
		.fourcc   = V4L2_PIX_FMT_YUYV,
		.depth    = 16,
	},{
		.name     = "4:2:2, packed, UYVY",
		.fourcc   = V4L2_PIX_FMT_UYVY,
		.depth    = 16,
	},{
		.name     = "A/V + VBI mux packet",
		.fourcc   = V4L2_PIX_FMT_TM6000,
		.depth    = 16,
	}
};

static LIST_HEAD(tm6000_corelist);

/* ------------------------------------------------------------------
	DMA and thread functions
   ------------------------------------------------------------------*/

#define norm_maxw(a) 720
#define norm_maxh(a) 576

//#define norm_minw(a) norm_maxw(a)
#define norm_minw(a) norm_maxw(a)
#define norm_minh(a) norm_maxh(a)

/*
 * video-buf generic routine to get the next available buffer
 */
static int inline get_next_buf (struct tm6000_dmaqueue *dma_q,
					  struct tm6000_buffer    **buf)
{
	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);

	if (list_empty(&dma_q->active)) {
		dprintk(dev, V4L2_DEBUG_QUEUE,"No active queue to serve\n");
		return 0;
	}

	*buf = list_entry(dma_q->active.next,
			struct tm6000_buffer, vb.queue);

	/* Nobody is waiting something to be done, just return */
	if (!waitqueue_active(&(*buf)->vb.done)) {
		mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
		return -1;
	}

	return 1;
}

/*
 * Announces that a buffer were filled and request the next
 */
static void inline buffer_filled (struct tm6000_core *dev,
				  struct tm6000_buffer *buf)
{
	/* Advice that buffer was filled */
	dprintk(dev, V4L2_DEBUG_ISOC, "[%p/%d] wakeup\n",buf,buf->vb.i);
	buf->vb.state = STATE_DONE;
	buf->vb.field_count++;
	do_gettimeofday(&buf->vb.ts);

	list_del(&buf->vb.queue);
	wake_up(&buf->vb.done);
}

/*
 * Macro to allow copying data into the proper memory type
 */

#define bufcpy(buf,out_ptr,in_ptr,size) 				\
	{								\
		if (__copy_to_user(out_ptr,in_ptr,size)!=0)		\
			tm6000_err("copy_to_user failed.\n");		\
	}

/*
 * Identify the tm5600/6000 buffer header type and properly handles
 */
static u8 *copy_packet (struct urb *urb, u32 header, u8 *data, u8 *endp,
			u8 *out_p, struct tm6000_buffer **buf)
{
	struct tm6000_dmaqueue  *dma_q = urb->context;
	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
	u8 *ptr=data;
	u8 c;
	unsigned int cmd, cpysize, pktsize, size, field, block, line, pos=0;

	/* FIXME: this is the hardcoded window size
	 */
	unsigned int linesize=720*2;

//static int last_line=-2;

	if (!dev->isoc_ctl.cmd) {
		c=(header>>24) & 0xff;

		/* split the header fields */
		size  = (((header & 0x7e)<<1) -1) *4;
		block = (header>>7) & 0xf;
		field = (header>>11) & 0x1;
		line  = (header>>12) & 0x1ff;
		cmd   = (header>>21) & 0x7;

		/* Validates header fields */
		if(size>TM6000_URB_MSG_LEN)
			size=TM6000_URB_MSG_LEN;
		if(block>=8)
			cmd = TM6000_URB_MSG_ERR;

		/* FIXME: Mounts the image as field0+field1
		 * It should, instead, check if the user selected
		 * entrelaced or non-entrelaced mode
		 */
		pos=((line<<1)+field)*linesize+
					block*TM6000_URB_MSG_LEN;

		/* Don't allow to write out of the buffer */
		if (pos+TM6000_URB_MSG_LEN > (*buf)->vb.size)
			cmd = TM6000_URB_MSG_ERR;

		/* Prints debug info */
		dprintk(dev, V4L2_DEBUG_ISOC, "size=%d, num=%d, "
				" line=%d, field=%d\n",
				size, block, line, field);

		pktsize = TM6000_URB_MSG_LEN;
/////////////////////////////
/// nao seria size???

	} else {
		/* Continue the last copy */
		cmd = dev->isoc_ctl.cmd;
		size= dev->isoc_ctl.size;
		pos = dev->isoc_ctl.pos;
		pktsize = dev->isoc_ctl.pktsize;
	}

	cpysize=(endp-ptr>size)?size:endp-ptr;

	if (cpysize) {
		/* handles each different URB message */
		switch(cmd) {
		case TM6000_URB_MSG_VIDEO:
			/* Fills video buffer */
			bufcpy(*buf,&out_p[pos],ptr,cpysize);
			break;
		}
	}
	if (cpysize<size) {
		/* End of URB packet, but cmd processing is not
		 * complete. Preserve the state for a next packet
		 */
		dev->isoc_ctl.pos = pos+cpysize;
		dev->isoc_ctl.size= size-cpysize;
		dev->isoc_ctl.cmd = cmd;
		dev->isoc_ctl.pktsize = pktsize-cpysize;
		ptr+=cpysize;
	} else {
		dev->isoc_ctl.cmd = 0;
		ptr+=pktsize;
	}

	return ptr;
}

static int copy_streams(u8 *data, u8 *out_p, unsigned long len,
			struct urb *urb, struct tm6000_buffer **buf)
{
	struct tm6000_dmaqueue  *dma_q = urb->context;
	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
	u8 *ptr=data, *endp=data+len;
	u32 header=0;
	int rc=0;

	for (ptr=data; ptr<endp;) {
		if (!dev->isoc_ctl.cmd) {
			/* Seek for sync */
			for (ptr+=3;ptr<endp;ptr++) {
				if (*ptr==0x47) {
					ptr-=3;
					break;
				}
			}
			if (ptr>=endp)
				return rc;

			/* Get message header */
			header=*(unsigned long *)ptr;
			ptr+=4;
		}

		/* Copy or continue last copy */
		ptr=copy_packet(urb,header,ptr,endp,out_p,buf);
	}

	return rc;
}
/*
 * Identify the tm5600/6000 buffer header type and properly handles
 */
static int copy_multiplexed(u8 *ptr, u8 *out_p, unsigned long len,
			struct urb *urb, struct tm6000_buffer **buf)
{
	struct tm6000_dmaqueue  *dma_q = urb->context;
	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
	unsigned int pos=dev->isoc_ctl.pos,cpysize;
	int rc=1;

	while (len>0) {
		cpysize=min(len,(*buf)->vb.size-pos);
//printk("Copying %d bytes (max=%lu) from %p to %p[%u]\n",cpysize,(*buf)->vb.size,ptr,out_p,pos);
		bufcpy(*buf,&out_p[pos],ptr,cpysize);
		pos+=cpysize;
		ptr+=cpysize;
		len-=cpysize;
		if (pos >= (*buf)->vb.size) {
			pos=0;
			/* Announces that a new buffer were filled */
			buffer_filled (dev, *buf);
			dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n");

			rc=get_next_buf (dma_q, buf);
			if (rc<=0) {
				*buf=NULL;
				printk(KERN_ERR "tm6000: buffer underrun\n");
				break;
			}
		}
	}

	dev->isoc_ctl.pos=pos;
	return rc;
}

static void inline print_err_status (struct tm6000_core *dev,
				     int packet, int status)
{
	char *errmsg = "Unknown";

	switch(status) {
	case -ENOENT:
		errmsg = "unlinked synchronuously";
		break;
	case -ECONNRESET:
		errmsg = "unlinked asynchronuously";
		break;
	case -ENOSR:
		errmsg = "Buffer error (overrun)";
		break;
	case -EPIPE:
		errmsg = "Stalled (device not responding)";
		break;
	case -EOVERFLOW:
		errmsg = "Babble (bad cable?)";
		break;
	case -EPROTO:
		errmsg = "Bit-stuff error (bad cable?)";
		break;
	case -EILSEQ:
		errmsg = "CRC/Timeout (could be anything)";
		break;
	case -ETIME:
		errmsg = "Device does not respond";
		break;
	}
	if (packet<0) {
		dprintk(dev, V4L2_DEBUG_QUEUE, "URB status %d [%s].\n",
			status, errmsg);
	} else {
		dprintk(dev, V4L2_DEBUG_QUEUE, "URB packet %d, status %d [%s].\n",
			packet, status, errmsg);
	}
}


/*
 * Controls the isoc copy of each urb packet
 */
static inline int tm6000_isoc_copy(struct urb *urb, struct tm6000_buffer **buf)
{
	struct tm6000_dmaqueue  *dma_q = urb->context;
	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
	void *outp=videobuf_to_vmalloc (&((*buf)->vb));
	int i, len=0, rc=1;
	int size=(*buf)->vb.size;
	char *p;
	unsigned long copied;

	copied=0;

	if (urb->status<0) {
		print_err_status (dev,-1,urb->status);
		return 0;
	}

	for (i = 0; i < urb->number_of_packets; i++) {
		int status = urb->iso_frame_desc[i].status;

		if (status<0) {
			print_err_status (dev,i,status);
			continue;
		}

		len=urb->iso_frame_desc[i].actual_length;

		if (len>=TM6000_URB_MSG_LEN) {
			p=urb->transfer_buffer + urb->iso_frame_desc[i].offset;
			if (!urb->iso_frame_desc[i].status) {
				if (((*buf)->fmt->fourcc)==V4L2_PIX_FMT_TM6000) {
					rc=copy_multiplexed(p,outp,len,urb,buf);
					if (rc<=0)
						return rc;
				} else {
					rc=copy_streams(p,outp,len,urb,buf);
				}
			}
			copied += len;
			if (copied>=size)
				break;
		}
	}

	if (((*buf)->fmt->fourcc)!=V4L2_PIX_FMT_TM6000) {
		buffer_filled (dev, *buf);
		dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n");
	}

	return rc;
}

/* ------------------------------------------------------------------
	URB control
   ------------------------------------------------------------------*/

/*
 * IRQ callback, called by URB callback
 */
static void tm6000_irq_callback(struct urb *urb)
{
	struct tm6000_buffer    *buf;
	struct tm6000_dmaqueue  *dma_q = urb->context;
	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
	int rc,i;
	unsigned long flags;

	spin_lock_irqsave(&dev->slock,flags);

	rc=get_next_buf (dma_q, &buf);
	if (rc<=0)
		goto ret;

	/* Copy data from URB */
	rc=tm6000_isoc_copy(urb, &buf);

ret:
	/* Reset urb buffers */
	for (i = 0; i < urb->number_of_packets; i++) {
		urb->iso_frame_desc[i].status = 0;
		urb->iso_frame_desc[i].actual_length = 0;
	}
	urb->status = 0;

	if ((urb->status = usb_submit_urb(urb, GFP_ATOMIC))) {
		tm6000_err("urb resubmit failed (error=%i)\n",
			urb->status);
	}

	if (rc>=0) {
		if (!rc) {
			dprintk(dev, V4L2_DEBUG_QUEUE, "No active queue to serve\n");
			del_timer(&dma_q->timeout);
		} else {
			/* Data filled, reset watchdog */
			mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
		}
	}
	spin_unlock_irqrestore(&dev->slock,flags);
}

/*
 * Stop and Deallocate URBs
 */
static void tm6000_uninit_isoc(struct tm6000_core *dev)
{
	struct urb *urb;
	int i;

	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
		urb=dev->isoc_ctl.urb[i];
		if (urb) {
			usb_kill_urb(urb);
			usb_unlink_urb(urb);
			if (dev->isoc_ctl.transfer_buffer[i]) {
				usb_buffer_free(dev->udev,
						urb->transfer_buffer_length,
						dev->isoc_ctl.transfer_buffer[i],
						urb->transfer_dma);
			}
			usb_free_urb(urb);
			dev->isoc_ctl.urb[i] = NULL;
		}
		dev->isoc_ctl.transfer_buffer[i] = NULL;
	}

	kfree (dev->isoc_ctl.urb);
	kfree (dev->isoc_ctl.transfer_buffer);
	dev->isoc_ctl.urb=NULL;
	dev->isoc_ctl.transfer_buffer=NULL;

	dev->isoc_ctl.num_bufs=0;
}

/*
 * Stop video thread - FIXME: Can be easily removed
 */
static void tm6000_stop_thread(struct tm6000_dmaqueue  *dma_q)
{
	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);

	tm6000_uninit_isoc(dev);
}


/*
 * Allocate URBs and start IRQ
 */
static int tm6000_prepare_isoc(struct tm6000_core *dev,
		     int max_packets, int num_bufs)
{
	struct tm6000_dmaqueue *dma_q = &dev->vidq;
	int i;
	int sb_size, pipe;
	struct urb *urb;
	int j, k;

	/* De-allocates all pending stuff */
	tm6000_uninit_isoc(dev);

	dev->isoc_ctl.num_bufs=num_bufs;

	dev->isoc_ctl.urb=kmalloc(sizeof(void *)*num_bufs,
				   GFP_KERNEL);
	if (!dev->isoc_ctl.urb) {
		tm6000_err("cannot alloc memory for usb buffers\n");
		return -ENOMEM;
	}

	dev->isoc_ctl.transfer_buffer=kmalloc(sizeof(void *)*num_bufs,
				   GFP_KERNEL);
	if (!dev->isoc_ctl.urb) {
		tm6000_err("cannot allocate memory for usbtransfer\n");
		kfree(dev->isoc_ctl.urb);
		return -ENOMEM;
	}

	dev->isoc_ctl.max_pkt_size=dev->max_isoc_in;

	sb_size = max_packets * dev->isoc_ctl.max_pkt_size;


	/* allocate urbs and transfer buffers */
	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
		urb = usb_alloc_urb(max_packets, GFP_KERNEL);
		if (!urb) {
			tm6000_err("cannot alloc isoc_ctl.urb %i\n", i);
			tm6000_uninit_isoc(dev);
			return -ENOMEM;
		}
		dev->isoc_ctl.urb[i] = urb;

		dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->udev,
			sb_size, GFP_KERNEL, &urb->transfer_dma);
		if (!dev->isoc_ctl.transfer_buffer[i]) {
			tm6000_err ("unable to allocate %i bytes for transfer"
					" buffer %i\n", sb_size, i);
			tm6000_uninit_isoc(dev);
			return -ENOMEM;
		}
		memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);

		pipe=usb_rcvisocpipe(dev->udev,
					dev->isoc_in->desc.bEndpointAddress &
					USB_ENDPOINT_NUMBER_MASK);
		usb_fill_int_urb(urb, dev->udev, pipe,
					dev->isoc_ctl.transfer_buffer[i],sb_size,
					tm6000_irq_callback, dma_q,
					dev->isoc_in->desc.bInterval);

		urb->number_of_packets = max_packets;
		urb->transfer_flags = URB_ISO_ASAP;

		k = 0;
		for (j = 0; j < max_packets; j++) {
			urb->iso_frame_desc[j].offset = k;
			urb->iso_frame_desc[j].length =
						dev->isoc_ctl.max_pkt_size;
			k += dev->isoc_ctl.max_pkt_size;
		}
	}

	return 0;
}

static int tm6000_start_thread( struct tm6000_dmaqueue  *dma_q,
				struct tm6000_buffer *buf)
{
	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
	int i,rc;

	dma_q->frame=0;
	dma_q->ini_jiffies=jiffies;

	init_waitqueue_head(&dma_q->wq);

	/* submit urbs and enables IRQ */
	for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
		rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
		if (rc) {
			tm6000_err("submit of urb %i failed (error=%i)\n", i,
				   rc);
			tm6000_uninit_isoc(dev);
			return rc;
		}
	}

	if (rc<0)
		return rc;

	return 0;
}

static int restart_video_queue(struct tm6000_dmaqueue *dma_q)
{
	struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);

	struct tm6000_buffer *buf, *prev;
	struct list_head *item;

	dprintk(dev, V4L2_DEBUG_QUEUE, "%s dma_q=0x%08lx\n",
					 __FUNCTION__,(unsigned long)dma_q);

	if (!list_empty(&dma_q->active)) {
		buf = list_entry(dma_q->active.next, struct tm6000_buffer, vb.queue);
		dprintk(dev, V4L2_DEBUG_QUEUE,
			"restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i);

		dprintk(dev, V4L2_DEBUG_QUEUE, "Restarting video dma\n");
		tm6000_stop_thread(dma_q);
		tm6000_start_thread(dma_q, buf);

		/* cancel all outstanding capture / vbi requests */
		list_for_each(item,&dma_q->active) {
			buf = list_entry(item, struct tm6000_buffer, vb.queue);

			list_del(&buf->vb.queue);
			buf->vb.state = STATE_ERROR;
			wake_up(&buf->vb.done);
		}
		mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);

		return 0;
	}

	prev = NULL;
	for (;;) {
		if (list_empty(&dma_q->queued))
			return 0;
		buf = list_entry(dma_q->queued.next, struct tm6000_buffer, vb.queue);
		if (NULL == prev) {
			list_del(&buf->vb.queue);
			list_add_tail(&buf->vb.queue,&dma_q->active);

			dprintk(dev, V4L2_DEBUG_QUEUE, "Restarting video dma\n");
			tm6000_stop_thread(dma_q);
			tm6000_start_thread(dma_q, buf);

			buf->vb.state = STATE_ACTIVE;
			mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
			dprintk(dev, V4L2_DEBUG_QUEUE, "[%p/%d] restart_queue -"
					" first active\n", buf, buf->vb.i);

		} else if (prev->vb.width  == buf->vb.width  &&
			   prev->vb.height == buf->vb.height &&
			   prev->fmt       == buf->fmt) {
			list_del(&buf->vb.queue);
			list_add_tail(&buf->vb.queue,&dma_q->active);
			buf->vb.state = STATE_ACTIVE;
			dprintk(dev, V4L2_DEBUG_QUEUE, "[%p/%d] restart_queue -"
					" move to active\n",buf,buf->vb.i);
		} else {
			return 0;
		}
		prev = buf;
	}
}

static void tm6000_vid_timeout(unsigned long data)
{
	struct tm6000_core      *dev  = (struct tm6000_core*)data;
	struct tm6000_dmaqueue *vidq = &dev->vidq;
	struct tm6000_buffer   *buf;
	unsigned long flags;

	spin_lock_irqsave(&dev->slock,flags);
	while (!list_empty(&vidq->active)) {
		buf = list_entry(vidq->active.next, struct tm6000_buffer,
								 vb.queue);
		list_del(&buf->vb.queue);
		buf->vb.state = STATE_ERROR;
		wake_up(&buf->vb.done);
		dprintk(dev, V4L2_DEBUG_QUEUE, "tm6000/0: [%p/%d] timeout\n",
							 buf, buf->vb.i);
	}

	restart_video_queue(vidq);
	spin_unlock_irqrestore(&dev->slock,flags);
}

/* ------------------------------------------------------------------
	Videobuf operations
   ------------------------------------------------------------------*/

static int
buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
{
	struct tm6000_fh *fh = vq->priv_data;

	*size = fh->fmt->depth * fh->width * fh->height >> 3;
	if (0 == *count)
		*count = TM6000_DEF_BUF;

	if (*count < TM6000_MIN_BUF) {
		*count=TM6000_MIN_BUF;
	}

	while (*size * *count > vid_limit * 1024 * 1024)
		(*count)--;

	return 0;
}

static void free_buffer(struct videobuf_queue *vq, struct tm6000_buffer *buf)
{
	if (in_interrupt())
		BUG();

	videobuf_waiton(&buf->vb,0,0);
	videobuf_vmalloc_free(&buf->vb);
	buf->vb.state = STATE_NEEDS_INIT;
}

static int
buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
						enum v4l2_field field)
{
	struct tm6000_fh     *fh  = vq->priv_data;
	struct tm6000_buffer *buf = container_of(vb,struct tm6000_buffer,vb);
	struct tm6000_core   *dev = fh->dev;
	int rc=0, urbsize, urb_init=0;

	BUG_ON(NULL == fh->fmt);


	/* FIXME: It assumes depth=2 */
	/* The only currently supported format is 16 bits/pixel */
	buf->vb.size = fh->fmt->depth*fh->width*fh->height >> 3;
	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
		return -EINVAL;

	if (buf->fmt       != fh->fmt    ||
	    buf->vb.width  != fh->width  ||
	    buf->vb.height != fh->height ||
	    buf->vb.field  != field) {
		buf->fmt       = fh->fmt;
		buf->vb.width  = fh->width;
		buf->vb.height = fh->height;
		buf->vb.field  = field;
		buf->vb.state = STATE_NEEDS_INIT;
	}

	if (STATE_NEEDS_INIT == buf->vb.state) {
		if (0 != (rc = videobuf_iolock(vq,&buf->vb,NULL)))
			goto fail;
		urb_init=1;
	}


	if (!dev->isoc_ctl.num_bufs)
		urb_init=1;

	if (urb_init) {
		/* memory for video
		   Should be at least
		   Vres x Vres x 2 bytes/pixel by frame */
		urbsize=buf->vb.size;

		 /* memory for audio
		    Should be at least
		    bitrate * 2 channels * 2 bytes / frame rate */
		if (dev->norm & V4L2_STD_525_60) {
			urbsize+=(dev->audio_bitrate*4+29)/30;
		} else {
			urbsize+=(dev->audio_bitrate*4+24)/25;
		}

		/* each audio frame seeems to have a frame number
		   with 2 bytes */
		urbsize+=2;

		/* Add 4 bytes by each 180 bytes frame */
		urbsize+=((urbsize+179)/180)*4;

		/* Round to an enough number of URBs */
		urbsize=(urbsize+dev->max_isoc_in-1)/dev->max_isoc_in;

printk("Allocating %d packets to handle %lu size\n",  urbsize,buf->vb.size);

		dprintk(dev, V4L2_DEBUG_QUEUE, "Allocating %d packets to handle "
					"%lu size\n", urbsize,buf->vb.size);
		rc = tm6000_prepare_isoc(dev, urbsize, 2);

{'fraction_non_alphanumeric': 0.16529146240838713, 'fraction_numerical': 0.037300393146629134, 'mean_word_length': 3.1644264780192017, 'pattern_counts': {'":': 0, '<': 97, '<?xml version=': 0, '>': 477, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3207893', 'n_tokens_mistral': 18668, 'n_tokens_neox': 16388, 'n_words': 3474}