<commit_before>/*
   tm6000-video.c - driver for TM5600/TM6000/TM6010 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>
#include <media/v4l2-ioctl.h>
#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

#define TM6000_MAX_ISO_PACKETS	46	/* Max number of ISO packets */

/* 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 */

/* Debug level */
int tm6000_debug;
EXPORT_SYMBOL_GPL(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,
		.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,
	}
};

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

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

#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 inline void get_next_buf(struct tm6000_dmaqueue *dma_q,
			       struct tm6000_buffer   **buf)
{
	struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
	char *outp;

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

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

	if (!buf)
		return;

	/* Cleans up buffer - Usefull for testing for frame/URB loss */
	outp = videobuf_to_vmalloc(&(*buf)->vb);
//	if (outp)
//		memset(outp, 0, (*buf)->vb.size);

	return;
}

/*
 * Announces that a buffer were filled and request the next
 */
static inline void buffer_filled(struct tm6000_core *dev,
				 struct tm6000_dmaqueue *dma_q,
				 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 = VIDEOBUF_DONE;
	buf->vb.field_count++;
	do_gettimeofday(&buf->vb.ts);

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

const char *tm6000_msg_type[] = {
	"unknown(0)",   /* 0 */
	"video",        /* 1 */
	"audio",        /* 2 */
	"vbi",          /* 3 */
	"pts",          /* 4 */
	"err",          /* 5 */
	"unknown(6)",   /* 6 */
	"unknown(7)",   /* 7 */
};

/*
 * Identify the tm5600/6000 buffer header type and properly handles
 */
static int copy_streams(u8 *data, unsigned long len,
			struct urb *urb)
{
	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, c;
	unsigned long header=0;
	int rc=0;
	unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
	struct tm6000_buffer *vbuf;
	char *voutp = NULL;
	unsigned int linewidth;

	/* get video buffer */
	get_next_buf (dma_q, &vbuf);
	if (!vbuf)
		return rc;
	voutp = videobuf_to_vmalloc(&vbuf->vb);
	if (!voutp)
		return 0;

	for (ptr = data; ptr < endp;) {
		if (!dev->isoc_ctl.cmd) {
			/* Header */
			if (dev->isoc_ctl.tmp_buf_len > 0) {
				/* from last urb or packet */
				header = dev->isoc_ctl.tmp_buf;
				if (4 - dev->isoc_ctl.tmp_buf_len > 0) {
					memcpy ((u8 *)&header +
						dev->isoc_ctl.tmp_buf_len,
						ptr,
						4 - dev->isoc_ctl.tmp_buf_len);
					ptr += 4 - dev->isoc_ctl.tmp_buf_len;
				}
				dev->isoc_ctl.tmp_buf_len = 0;
			} else {
				if (ptr + 3 >= endp) {
					/* have incomplete header */
					dev->isoc_ctl.tmp_buf_len = endp - ptr;
					memcpy (&dev->isoc_ctl.tmp_buf, ptr,
						dev->isoc_ctl.tmp_buf_len);
					return rc;
				}
				/* Seek for sync */
				for (; ptr < endp - 3; ptr++) {
					if (*(ptr + 3) == 0x47)
						break;
				}
				/* Get message header */
				header = *(unsigned long *)ptr;
				ptr += 4;
			}
			/* split the header fields */
			c = (header >> 24) & 0xff;
			size = ((header & 0x7e) << 1);
			if (size > 0)
				size -= 4;
			block = (header >> 7) & 0xf;
			field = (header >> 11) & 0x1;
			line  = (header >> 12) & 0x1ff;
			cmd   = (header >> 21) & 0x7;
			/* Validates haeder fields */
			if (size > TM6000_URB_MSG_LEN)
				size = TM6000_URB_MSG_LEN;
			pktsize = TM6000_URB_MSG_LEN;
			/* calculate position in buffer
			 * and change the buffer
			 */
			switch (cmd) {
			case TM6000_URB_MSG_VIDEO:
				if ((dev->isoc_ctl.vfield != field) &&
					(field == 1)) {
					/* Announces that a new buffer
					 * were filled
					 */
					buffer_filled (dev, dma_q, vbuf);
					dprintk (dev, V4L2_DEBUG_ISOC,
							"new buffer filled\n");
					get_next_buf (dma_q, &vbuf);
					if (!vbuf)
						return rc;
					voutp = videobuf_to_vmalloc (&vbuf->vb);
					if (!voutp)
						return rc;
				}
				linewidth = vbuf->vb.width << 1;
				pos = ((line << 1) - field - 1) * linewidth +
					block * TM6000_URB_MSG_LEN;
				/* Don't allow to write out of the buffer */
				if (pos + size > vbuf->vb.size)
					cmd = TM6000_URB_MSG_ERR;
				dev->isoc_ctl.vfield = field;
				break;
			case TM6000_URB_MSG_AUDIO:
			case TM6000_URB_MSG_VBI:
			case TM6000_URB_MSG_PTS:
				break;
			}
		} 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) {
			/* copy data in different buffers */
			switch (cmd) {
			case TM6000_URB_MSG_VIDEO:
				/* Fills video buffer */<commit_msg>V4L/DVB: tm6000: audio packet has always 180 bytes<commit_after>/*
   tm6000-video.c - driver for TM5600/TM6000/TM6010 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>
#include <media/v4l2-ioctl.h>
#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

#define TM6000_MAX_ISO_PACKETS	46	/* Max number of ISO packets */

/* 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 */

/* Debug level */
int tm6000_debug;
EXPORT_SYMBOL_GPL(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,
		.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,
	}
};

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

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

#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 inline void get_next_buf(struct tm6000_dmaqueue *dma_q,
			       struct tm6000_buffer   **buf)
{
	struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
	char *outp;

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

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

	if (!buf)
		return;

	/* Cleans up buffer - Usefull for testing for frame/URB loss */
	outp = videobuf_to_vmalloc(&(*buf)->vb);
//	if (outp)
//		memset(outp, 0, (*buf)->vb.size);

	return;
}

/*
 * Announces that a buffer were filled and request the next
 */
static inline void buffer_filled(struct tm6000_core *dev,
				 struct tm6000_dmaqueue *dma_q,
				 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 = VIDEOBUF_DONE;
	buf->vb.field_count++;
	do_gettimeofday(&buf->vb.ts);

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

const char *tm6000_msg_type[] = {
	"unknown(0)",   /* 0 */
	"video",        /* 1 */
	"audio",        /* 2 */
	"vbi",          /* 3 */
	"pts",          /* 4 */
	"err",          /* 5 */
	"unknown(6)",   /* 6 */
	"unknown(7)",   /* 7 */
};

/*
 * Identify the tm5600/6000 buffer header type and properly handles
 */
static int copy_streams(u8 *data, unsigned long len,
			struct urb *urb)
{
	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, c;
	unsigned long header=0;
	int rc=0;
	unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
	struct tm6000_buffer *vbuf;
	char *voutp = NULL;
	unsigned int linewidth;

	/* get video buffer */
	get_next_buf (dma_q, &vbuf);
	if (!vbuf)
		return rc;
	voutp = videobuf_to_vmalloc(&vbuf->vb);
	if (!voutp)
		return 0;

	for (ptr = data; ptr < endp;) {
		if (!dev->isoc_ctl.cmd) {
			/* Header */
			if (dev->isoc_ctl.tmp_buf_len > 0) {
				/* from last urb or packet */
				header = dev->isoc_ctl.tmp_buf;
				if (4 - dev->isoc_ctl.tmp_buf_len > 0) {
					memcpy ((u8 *)&header +
						dev->isoc_ctl.tmp_buf_len,
						ptr,
						4 - dev->isoc_ctl.tmp_buf_len);
					ptr += 4 - dev->isoc_ctl.tmp_buf_len;
				}
				dev->isoc_ctl.tmp_buf_len = 0;
			} else {
				if (ptr + 3 >= endp) {
					/* have incomplete header */
					dev->isoc_ctl.tmp_buf_len = endp - ptr;
					memcpy (&dev->isoc_ctl.tmp_buf, ptr,
						dev->isoc_ctl.tmp_buf_len);
					return rc;
				}
				/* Seek for sync */
				for (; ptr < endp - 3; ptr++) {
					if (*(ptr + 3) == 0x47)
						break;
				}
				/* Get message header */
				header = *(unsigned long *)ptr;
				ptr += 4;
			}

			/* split the header fields */
			c = (header >> 24) & 0xff;
			size = ((header & 0x7e) << 1);
			if (size > 0)
				size -= 4;
			block = (header >> 7) & 0xf;
			field = (header >> 11) & 0x1;
			line  = (header >> 12) & 0x1ff;
			cmd   = (header >> 21) & 0x7;
			/* Validates haeder fields */
			if (size > TM6000_URB_MSG_LEN)
				size = TM6000_URB_MSG_LEN;
			pktsize = TM6000_URB_MSG_LEN;
			/* calculate position in buffer
			 * and change the buffer
			 */
			switch (cmd) {
			case TM6000_URB_MSG_VIDEO:
				if ((dev->isoc_ctl.vfield != field) &&
					(field == 1)) {
					/* Announces that a new buffer
					 * were filled
					 */
					buffer_filled (dev, dma_q, vbuf);
					dprintk (dev, V4L2_DEBUG_ISOC,
							"new buffer filled\n");
					get_next_buf (dma_q, &vbuf);
					if (!vbuf)
						return rc;
					voutp = videobuf_to_vmalloc (&vbuf->vb);
					if (!voutp)
						return rc;
				}
				linewidth = vbuf->vb.width << 1;
				pos = ((line << 1) - field - 1) * linewidth +
					block * TM6000_URB_MSG_LEN;
				/* Don't allow to write out of the buffer */
				if (pos + size > vbuf->vb.size)
					cmd = TM6000_URB_MSG_ERR;
				dev->isoc_ctl.vfield = field;
				break;
			case TM6000_URB_MSG_VBI:
				break;
			case TM6000_URB_MSG_AUDIO:
			case TM6000_URB_MSG_PTS:
				cpysize = pktsize;	/* Size is always 180 bytes */
				break;
			}
		} 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) {
			/* copy data in different buffers */
			switch (cmd) {
			case TM6000_URB_MSG_VIDEO:
				/* Fills video buffer */
{'fraction_non_alphanumeric': 0.1508965688403549, 'fraction_numerical': 0.04312216913817708, 'mean_word_length': 2.422807390104056, 'pattern_counts': {'":': 0, '<': 69, '<?xml version=': 0, '>': 151, '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': '3502977', 'n_tokens_mistral': 7287, 'n_tokens_neox': 6101, 'n_words': 1551}