⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ivtv-streams.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    init/start/stop/exit stream functions    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>    Copyright (C) 2004  Chris Kennedy <c@groovy.org>    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA *//* License: GPL * Author: Kevin Thayer <nufan_wfk at yahoo dot com> * * This file will hold API related functions, both internal (firmware api) * and external (v4l2, etc) * * ----- * MPG600/MPG160 support by  T.Adachi <tadachi@tadachi-net.com> *                      and Takeru KOMORIYA<komoriya@paken.org> * * AVerMedia M179 GPIO info by Chris Pinkham <cpinkham@bc2va.org> *                using information provided by Jiun-Kuei Jung @ AVerMedia. */#include "ivtv-driver.h"#include "ivtv-fileops.h"#include "ivtv-queue.h"#include "ivtv-mailbox.h"#include "ivtv-ioctl.h"#include "ivtv-irq.h"#include "ivtv-yuv.h"#include "ivtv-cards.h"#include "ivtv-streams.h"static struct file_operations ivtv_v4l2_enc_fops = {      .owner = THIS_MODULE,      .read = ivtv_v4l2_read,      .write = ivtv_v4l2_write,      .open = ivtv_v4l2_open,      .ioctl = ivtv_v4l2_ioctl,      .release = ivtv_v4l2_close,      .poll = ivtv_v4l2_enc_poll,};static struct file_operations ivtv_v4l2_dec_fops = {      .owner = THIS_MODULE,      .read = ivtv_v4l2_read,      .write = ivtv_v4l2_write,      .open = ivtv_v4l2_open,      .ioctl = ivtv_v4l2_ioctl,      .release = ivtv_v4l2_close,      .poll = ivtv_v4l2_dec_poll,};#define IVTV_V4L2_DEC_MPG_OFFSET  16	/* offset from 0 to register decoder mpg v4l2 minors on */#define IVTV_V4L2_ENC_PCM_OFFSET  24	/* offset from 0 to register pcm v4l2 minors on */#define IVTV_V4L2_ENC_YUV_OFFSET  32	/* offset from 0 to register yuv v4l2 minors on */#define IVTV_V4L2_DEC_YUV_OFFSET  48	/* offset from 0 to register decoder yuv v4l2 minors on */#define IVTV_V4L2_DEC_VBI_OFFSET   8	/* offset from 0 to register decoder vbi input v4l2 minors on */#define IVTV_V4L2_DEC_VOUT_OFFSET 16	/* offset from 0 to register vbi output v4l2 minors on */static struct {	const char *name;	int vfl_type;	int minor_offset;	int dma, pio;	enum v4l2_buf_type buf_type;	const struct file_operations *fops;} ivtv_stream_info[] = {	{	/* IVTV_ENC_STREAM_TYPE_MPG */		"encoder MPG",		VFL_TYPE_GRABBER, 0,		PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE,		&ivtv_v4l2_enc_fops	},	{	/* IVTV_ENC_STREAM_TYPE_YUV */		"encoder YUV",		VFL_TYPE_GRABBER, IVTV_V4L2_ENC_YUV_OFFSET,		PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE,		&ivtv_v4l2_enc_fops	},	{	/* IVTV_ENC_STREAM_TYPE_VBI */		"encoder VBI",		VFL_TYPE_VBI, 0,		PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VBI_CAPTURE,		&ivtv_v4l2_enc_fops	},	{	/* IVTV_ENC_STREAM_TYPE_PCM */		"encoder PCM",		VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET,		PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE,		&ivtv_v4l2_enc_fops	},	{	/* IVTV_ENC_STREAM_TYPE_RAD */		"encoder radio",		VFL_TYPE_RADIO, 0,		PCI_DMA_NONE, 1, V4L2_BUF_TYPE_PRIVATE,		&ivtv_v4l2_enc_fops	},	{	/* IVTV_DEC_STREAM_TYPE_MPG */		"decoder MPG",		VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET,		PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT,		&ivtv_v4l2_dec_fops	},	{	/* IVTV_DEC_STREAM_TYPE_VBI */		"decoder VBI",		VFL_TYPE_VBI, IVTV_V4L2_DEC_VBI_OFFSET,		PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_CAPTURE,		&ivtv_v4l2_enc_fops	},	{	/* IVTV_DEC_STREAM_TYPE_VOUT */		"decoder VOUT",		VFL_TYPE_VBI, IVTV_V4L2_DEC_VOUT_OFFSET,		PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_OUTPUT,		&ivtv_v4l2_dec_fops	},	{	/* IVTV_DEC_STREAM_TYPE_YUV */		"decoder YUV",		VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET,		PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT,		&ivtv_v4l2_dec_fops	}};static void ivtv_stream_init(struct ivtv *itv, int type){	struct ivtv_stream *s = &itv->streams[type];	struct video_device *dev = s->v4l2dev;	/* we need to keep v4l2dev, so restore it afterwards */	memset(s, 0, sizeof(*s));	s->v4l2dev = dev;	/* initialize ivtv_stream fields */	s->itv = itv;	s->type = type;	s->name = ivtv_stream_info[type].name;	if (ivtv_stream_info[type].pio)		s->dma = PCI_DMA_NONE;	else		s->dma = ivtv_stream_info[type].dma;	s->buf_size = itv->stream_buf_size[type];	if (s->buf_size)		s->buffers = (itv->options.kilobytes[type] * 1024 + s->buf_size - 1) / s->buf_size;	spin_lock_init(&s->qlock);	init_waitqueue_head(&s->waitq);	s->id = -1;	s->sg_handle = IVTV_DMA_UNMAPPED;	ivtv_queue_init(&s->q_free);	ivtv_queue_init(&s->q_full);	ivtv_queue_init(&s->q_dma);	ivtv_queue_init(&s->q_predma);	ivtv_queue_init(&s->q_io);}static int ivtv_prep_dev(struct ivtv *itv, int type){	struct ivtv_stream *s = &itv->streams[type];	int minor_offset = ivtv_stream_info[type].minor_offset;	int minor;	/* These four fields are always initialized. If v4l2dev == NULL, then	   this stream is not in use. In that case no other fields but these	   four can be used. */	s->v4l2dev = NULL;	s->itv = itv;	s->type = type;	s->name = ivtv_stream_info[type].name;	/* Check whether the radio is supported */	if (type == IVTV_ENC_STREAM_TYPE_RAD && !(itv->v4l2_cap & V4L2_CAP_RADIO))		return 0;	if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))		return 0;	/* card number + user defined offset + device offset */	minor = itv->num + ivtv_first_minor + minor_offset;	/* User explicitly selected 0 buffers for these streams, so don't	   create them. */	if (ivtv_stream_info[type].dma != PCI_DMA_NONE &&	    itv->options.kilobytes[type] == 0) {		IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name);		return 0;	}	ivtv_stream_init(itv, type);	/* allocate and initialize the v4l2 video device structure */	s->v4l2dev = video_device_alloc();	if (s->v4l2dev == NULL) {		IVTV_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name);		return -ENOMEM;	}	s->v4l2dev->type = VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT |		    VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER;	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {		s->v4l2dev->type |= VID_TYPE_MPEG_DECODER;	}	snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "ivtv%d %s",			itv->num, s->name);	s->v4l2dev->minor = minor;	s->v4l2dev->dev = &itv->dev->dev;	s->v4l2dev->fops = ivtv_stream_info[type].fops;	s->v4l2dev->release = video_device_release;	return 0;}/* Initialize v4l2 variables and prepare v4l2 devices */int ivtv_streams_setup(struct ivtv *itv){	int type;	/* Setup V4L2 Devices */	for (type = 0; type < IVTV_MAX_STREAMS; type++) {		/* Prepare device */		if (ivtv_prep_dev(itv, type))			break;		if (itv->streams[type].v4l2dev == NULL)			continue;		/* Allocate Stream */		if (ivtv_stream_alloc(&itv->streams[type]))			break;	}	if (type == IVTV_MAX_STREAMS)		return 0;	/* One or more streams could not be initialized. Clean 'em all up. */	ivtv_streams_cleanup(itv);	return -ENOMEM;}static int ivtv_reg_dev(struct ivtv *itv, int type){	struct ivtv_stream *s = &itv->streams[type];	int vfl_type = ivtv_stream_info[type].vfl_type;	int minor;	if (s->v4l2dev == NULL)		return 0;	minor = s->v4l2dev->minor;	/* Register device. First try the desired minor, then any free one. */	if (video_register_device(s->v4l2dev, vfl_type, minor) &&			video_register_device(s->v4l2dev, vfl_type, -1)) {		IVTV_ERR("Couldn't register v4l2 device for %s minor %d\n",				s->name, minor);		video_device_release(s->v4l2dev);		s->v4l2dev = NULL;		return -ENOMEM;	}	switch (vfl_type) {	case VFL_TYPE_GRABBER:		IVTV_INFO("Registered device video%d for %s (%d kB)\n",			s->v4l2dev->minor, s->name, itv->options.kilobytes[type]);		break;	case VFL_TYPE_RADIO:		IVTV_INFO("Registered device radio%d for %s\n",			s->v4l2dev->minor - MINOR_VFL_TYPE_RADIO_MIN, s->name);		break;	case VFL_TYPE_VBI:		if (itv->options.kilobytes[type])			IVTV_INFO("Registered device vbi%d for %s (%d kB)\n",				s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN,				s->name, itv->options.kilobytes[type]);		else			IVTV_INFO("Registered device vbi%d for %s\n",				s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, s->name);		break;	}	return 0;}/* Register v4l2 devices */int ivtv_streams_register(struct ivtv *itv){	int type;	int err = 0;	/* Register V4L2 devices */	for (type = 0; type < IVTV_MAX_STREAMS; type++)		err |= ivtv_reg_dev(itv, type);	if (err == 0)		return 0;	/* One or more streams could not be initialized. Clean 'em all up. */	ivtv_streams_cleanup(itv);	return -ENOMEM;}/* Unregister v4l2 devices */void ivtv_streams_cleanup(struct ivtv *itv){	int type;	/* Teardown all streams */	for (type = 0; type < IVTV_MAX_STREAMS; type++) {		struct video_device *vdev = itv->streams[type].v4l2dev;		itv->streams[type].v4l2dev = NULL;		if (vdev == NULL)			continue;		ivtv_stream_free(&itv->streams[type]);		/* Unregister device */		video_unregister_device(vdev);	}}static void ivtv_vbi_setup(struct ivtv *itv){	int raw = itv->vbi.sliced_in->service_set == 0;	u32 data[CX2341X_MBOX_MAX_DATA];	int lines;	int i;	/* Reset VBI */	ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0);	/* setup VBI registers */	itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in);	/* determine number of lines and total number of VBI bytes.	   A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1	   The '- 1' byte is probably an unused U or V byte. Or something...	   A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal	   header, 42 data bytes + checksum (to be confirmed) */	if (raw) {		lines = itv->vbi.count * 2;	} else {		lines = itv->is_60hz ? 24 : 38;		if (itv->is_60hz && (itv->hw_flags & IVTV_HW_CX25840))			lines += 2;	}	itv->vbi.enc_size = lines * (raw ? itv->vbi.raw_size : itv->vbi.sliced_size);	/* Note: sliced vs raw flag doesn't seem to have any effect	   TODO: check mode (0x02) value with older ivtv versions. */	data[0] = raw | 0x02 | (0xbd << 8);	/* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */	data[1] = 1;	/* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */	data[2] = raw ? 4 : 8;	/* The start/stop codes determine which VBI lines end up in the raw VBI data area.	   The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line	   is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video)	   code. These values for raw VBI are obtained from a driver disassembly. The sliced	   start/stop codes was deduced from this, but they do not appear in the driver.	   Other code pairs that I found are: 0x250E6249/0x13545454 and 0x25256262/0x38137F54.	   However, I have no idea what these values are for. */	if (itv->hw_flags & IVTV_HW_CX25840) {		/* Setup VBI for the cx25840 digitizer */		if (raw) {			data[3] = 0x20602060;			data[4] = 0x30703070;		} else {			data[3] = 0xB0F0B0F0;			data[4] = 0xA0E0A0E0;		}		/* Lines per frame */		data[5] = lines;		/* bytes per line */		data[6] = (raw ? itv->vbi.raw_size : itv->vbi.sliced_size);	} else {		/* Setup VBI for the saa7115 digitizer */		if (raw) {			data[3] = 0x25256262;			data[4] = 0x387F7F7F;		} else {			data[3] = 0xABABECEC;			data[4] = 0xB6F1F1F1;		}		/* Lines per frame */		data[5] = lines;		/* bytes per line */		data[6] = itv->vbi.enc_size / lines;	}	IVTV_DEBUG_INFO(		"Setup VBI API header 0x%08x pkts %d buffs %d ln %d sz %d\n",			data[0], data[1], data[2], data[5], data[6]);	ivtv_api(itv, CX2341X_ENC_SET_VBI_CONFIG, 7, data);	/* returns the VBI encoder memory area. */	itv->vbi.enc_start = data[2];	itv->vbi.fpi = data[0];	if (!itv->vbi.fpi)		itv->vbi.fpi = 1;	IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d\n",		itv->vbi.enc_start, data[1], itv->vbi.fpi);	/* select VBI lines.	   Note that the sliced argument seems to have no effect. */	for (i = 2; i <= 24; i++) {		int valid;		if (itv->is_60hz) {			valid = i >= 10 && i < 22;		} else {			valid = i >= 6 && i < 24;		}		ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, i - 1,				valid, 0 , 0, 0);		ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, (i - 1) | 0x80000000,				valid, 0, 0, 0);	}	/* Remaining VBI questions:	   - Is it possible to select particular VBI lines only for inclusion in the MPEG	   stream? Currently you can only get the first X lines.	   - Is mixed raw and sliced VBI possible?	   - What's the meaning of the raw/sliced flag?	   - What's the meaning of params 2, 3 & 4 of the Select VBI command? */}int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s){	u32 data[CX2341X_MBOX_MAX_DATA];	struct ivtv *itv = s->itv;	struct cx2341x_mpeg_params *p = &itv->params;	int captype = 0, subtype = 0;	int enable_passthrough = 0;	if (s->v4l2dev == NULL)		return -EINVAL;	IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name);	switch (s->type) {	case IVTV_ENC_STREAM_TYPE_MPG:		captype = 0;		subtype = 3;		/* Stop Passthrough */		if (itv->output_mode == OUT_PASSTHROUGH) {			ivtv_passthrough_mode(itv, 0);			enable_passthrough = 1;		}		itv->mpg_data_received = itv->vbi_data_inserted = 0;		itv->dualwatch_jiffies = jiffies;		itv->dualwatch_stereo_mode = p->audio_properties & 0x0300;		itv->search_pack_header = 0;		break;	case IVTV_ENC_STREAM_TYPE_YUV:		if (itv->output_mode == OUT_PASSTHROUGH) {			captype = 2;			subtype = 11;	/* video+audio+decoder */			break;		}		captype = 1;		subtype = 1;		break;	case IVTV_ENC_STREAM_TYPE_PCM:		captype = 1;		subtype = 2;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -