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

📄 av7110_av.c

📁 linux环境下的dvb驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * av7110_av.c: audio and video MPEG decoder stuff * * Copyright (C) 1999-2002 Ralph  Metzler *                       & Marcus Metzler for convergence integrated media GmbH * * originally based on code by: * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de> * * 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. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * * the project's page is at http://www.linuxtv.org/dvb/ */#include <linux/types.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/sched.h>#include <linux/delay.h>#include <linux/byteorder/swabb.h>#include <linux/smp_lock.h>#include <linux/fs.h>#define DEBUG_VARIABLE av7110_debugextern int av7110_debug;#include "av7110.h"#include "av7110_hw.h"#include "av7110_av.h"#include "av7110_ipack.h"#include "dvb_functions.h"/* MPEG-2 (ISO 13818 / H.222.0) stream types */#define PROG_STREAM_MAP  0xBC#define PRIVATE_STREAM1  0xBD#define PADDING_STREAM	 0xBE#define PRIVATE_STREAM2  0xBF#define AUDIO_STREAM_S	 0xC0#define AUDIO_STREAM_E	 0xDF#define VIDEO_STREAM_S	 0xE0#define VIDEO_STREAM_E	 0xEF#define ECM_STREAM	 0xF0#define EMM_STREAM	 0xF1#define DSM_CC_STREAM	 0xF2#define ISO13522_STREAM  0xF3#define PROG_STREAM_DIR  0xFF#define PTS_DTS_FLAGS	 0xC0//pts_dts flags#define PTS_ONLY	 0x80#define PTS_DTS		 0xC0#define TS_SIZE		 188#define TRANS_ERROR	 0x80#define PAY_START	 0x40#define TRANS_PRIO	 0x20#define PID_MASK_HI	 0x1F//flags#define TRANS_SCRMBL1	 0x80#define TRANS_SCRMBL2	 0x40#define ADAPT_FIELD	 0x20#define PAYLOAD		 0x10#define COUNT_MASK	 0x0F// adaptation flags#define DISCON_IND	 0x80#define RAND_ACC_IND	 0x40#define ES_PRI_IND	 0x20#define PCR_FLAG	 0x10#define OPCR_FLAG	 0x08#define SPLICE_FLAG	 0x04#define TRANS_PRIV	 0x02#define ADAP_EXT_FLAG	 0x01// adaptation extension flags#define LTW_FLAG	 0x80#define PIECE_RATE	 0x40#define SEAM_SPLICE	 0x20static void p_to_t(u8 const *buf, long int length, u16 pid,		   u8 *counter, struct dvb_demux_feed *feed);int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len){	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) p2t->priv;//	DEB_EE(("struct dvb_filter_pes2ts:%p\n", p2t));	if (!(dvbdmxfeed->ts_type & TS_PACKET))		return 0;	if (buf[3] == 0xe0)	 // video PES do not have a length in TS		buf[4] = buf[5] = 0;	if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)		return dvbdmxfeed->cb.ts(buf, len, 0, 0,					 &dvbdmxfeed->feed.ts, DMX_OK);	else		return dvb_filter_pes2ts(p2t, buf, len, 1);}static int dvb_filter_pes2ts_cb(void *priv, unsigned char *data){	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) priv;//	DEB_EE(("dvb_demux_feed:%p\n", dvbdmxfeed));	dvbdmxfeed->cb.ts(data, 188, 0, 0,			  &dvbdmxfeed->feed.ts, DMX_OK);	return 0;}int av7110_av_start_record(struct av7110 *av7110, int av,			   struct dvb_demux_feed *dvbdmxfeed){	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;	DEB_EE(("av7110: %p, dvb_demux_feed:%p\n", av7110, dvbdmxfeed));	if (av7110->playing || (av7110->rec_mode & av))		return -EBUSY;	av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);	dvbdmx->recording = 1;	av7110->rec_mode |= av;	switch (av7110->rec_mode) {	case RP_AUDIO:		dvb_filter_pes2ts_init(&av7110->p2t[0],				       dvbdmx->pesfilter[0]->pid,				       dvb_filter_pes2ts_cb,				       (void *) dvbdmx->pesfilter[0]);		av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);		break;	case RP_VIDEO:		dvb_filter_pes2ts_init(&av7110->p2t[1],				       dvbdmx->pesfilter[1]->pid,				       dvb_filter_pes2ts_cb,				       (void *) dvbdmx->pesfilter[1]);		av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);		break;	case RP_AV:		dvb_filter_pes2ts_init(&av7110->p2t[0],				       dvbdmx->pesfilter[0]->pid,				       dvb_filter_pes2ts_cb,				       (void *) dvbdmx->pesfilter[0]);		dvb_filter_pes2ts_init(&av7110->p2t[1],				       dvbdmx->pesfilter[1]->pid,				       dvb_filter_pes2ts_cb,				       (void *) dvbdmx->pesfilter[1]);		av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0);		break;	}	return 0;}int av7110_av_start_play(struct av7110 *av7110, int av){	DEB_EE(("av7110: %p\n", av7110));	if (av7110->rec_mode)		return -EBUSY;	if (av7110->playing & av)		return -EBUSY;	av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);	if (av7110->playing == RP_NONE) {		av7110_ipack_reset(&av7110->ipack[0]);		av7110_ipack_reset(&av7110->ipack[1]);	}	av7110->playing |= av;	switch (av7110->playing) {	case RP_AUDIO:		av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);		break;	case RP_VIDEO:		av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);		av7110->sinfo = 0;		break;	case RP_AV:		av7110->sinfo = 0;		av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0);		break;	}	return av7110->playing;}void av7110_av_stop(struct av7110 *av7110, int av){	DEB_EE(("av7110: %p\n", av7110));	if (!(av7110->playing & av) && !(av7110->rec_mode & av))		return;	av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);	if (av7110->playing) {		av7110->playing &= ~av;		switch (av7110->playing) {		case RP_AUDIO:			av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);			break;		case RP_VIDEO:			av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);			break;		case RP_NONE:			av7110_set_vidmode(av7110, av7110->vidmode);			break;		}	} else {		av7110->rec_mode &= ~av;		switch (av7110->rec_mode) {		case RP_AUDIO:			av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);			break;		case RP_VIDEO:			av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);			break;		case RP_NONE:			break;		}	}}int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen){	int len;	u32 sync;	u16 blen;	DEB_EE(("dvb_ring_buffer_t: %p\n", buf));	if (!dlen) {		wake_up(&buf->queue);		return -1;	}	while (1) {		if ((len = dvb_ringbuffer_avail(buf)) < 6)			return -1;		sync =  DVB_RINGBUFFER_PEEK(buf, 0) << 24;		sync |= DVB_RINGBUFFER_PEEK(buf, 1) << 16;		sync |= DVB_RINGBUFFER_PEEK(buf, 2) << 8;		sync |= DVB_RINGBUFFER_PEEK(buf, 3);		if (((sync &~ 0x0f) == 0x000001e0) ||		    ((sync &~ 0x1f) == 0x000001c0) ||		    (sync == 0x000001bd))			break;		printk("resync\n");		DVB_RINGBUFFER_SKIP(buf, 1);	}	blen =  DVB_RINGBUFFER_PEEK(buf, 4) << 8;	blen |= DVB_RINGBUFFER_PEEK(buf, 5);	blen += 6;	if (len < blen || blen > dlen) {		//printk("buffer empty - avail %d blen %u dlen %d\n", len, blen, dlen);		wake_up(&buf->queue);		return -1;	}	dvb_ringbuffer_read(buf, dest, (size_t) blen, 0);	DEB_S(("pread=0x%08lx, pwrite=0x%08lx\n",	       (unsigned long) buf->pread, (unsigned long) buf->pwrite));	wake_up(&buf->queue);	return blen;}int av7110_set_volume(struct av7110 *av7110, int volleft, int volright){	int err, vol, val, balance = 0;	DEB_EE(("av7110: %p\n", av7110));	switch (av7110->adac_type) {	case DVB_ADAC_TI:		volleft = (volleft * 256) / 1036;		volright = (volright * 256) / 1036;		if (volleft > 0x3f)			volleft = 0x3f;		if (volright > 0x3f)			volright = 0x3f;		if ((err = SendDAC(av7110, 3, 0x80 + volleft)))			return err;		return SendDAC(av7110, 4, volright);	case DVB_ADAC_CRYSTAL:		volleft = 127 - volleft / 2;		volright = 127 - volright / 2;		i2c_writereg(av7110, 0x20, 0x03, volleft);		i2c_writereg(av7110, 0x20, 0x04, volright);		return 0;	case DVB_ADAC_MSP:		vol  = (volleft > volright) ? volleft : volright;		val	= (vol * 0x73 / 255) << 8;		if (vol > 0)		       balance = ((volright - volleft) * 127) / vol;		msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8);		msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */		msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */		return 0;	}	return 0;}void av7110_set_vidmode(struct av7110 *av7110, int mode){	DEB_EE(("av7110: %p\n", av7110));	av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode);	if (!av7110->playing) {		ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO],			   av7110->pids[DMX_PES_AUDIO],			   av7110->pids[DMX_PES_TELETEXT],			   0, av7110->pids[DMX_PES_PCR]);		av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);	}}static int sw2mode[16] = {	VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL,	VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL, VIDEO_MODE_NTSC,	VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL,	VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL,};static void get_video_format(struct av7110 *av7110, u8 *buf, int count){	int i;	int hsize, vsize;	int sw;	u8 *p;	DEB_EE(("av7110: %p\n", av7110));	if (av7110->sinfo)		return;	for (i = 7; i < count - 10; i++) {		p = buf + i;		if (p[0] || p[1] || p[2] != 0x01 || p[3] != 0xb3)			continue;		p += 4;		hsize = ((p[1] &0xF0) >> 4) | (p[0] << 4);		vsize = ((p[1] &0x0F) << 8) | (p[2]);		sw = (p[3] & 0x0F);		av7110_set_vidmode(av7110, sw2mode[sw]);		DEB_S(("dvb: playback %dx%d fr=%d\n", hsize, vsize, sw));		av7110->sinfo = 1;		break;	}}/**************************************************************************** * I/O buffer management and control ****************************************************************************/static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf,					 const char *buf, unsigned long count){	unsigned long todo = count;	int free;	while (todo > 0) {		if (dvb_ringbuffer_free(rbuf) < 2048) {			if (wait_event_interruptible(rbuf->queue,						     (dvb_ringbuffer_free(rbuf) >= 2048)))				return count - todo;		}		free = dvb_ringbuffer_free(rbuf);		if (free > todo)			free = todo;		dvb_ringbuffer_write(rbuf, buf, free, 0);		todo -= free;		buf += free;	}	return count - todo;}static void play_video_cb(u8 *buf, int count, void *priv){	struct av7110 *av7110 = (struct av7110 *) priv;	DEB_EE(("av7110: %p\n", av7110));	if ((buf[3] & 0xe0) == 0xe0) {		get_video_format(av7110, buf, count);		aux_ring_buffer_write(&av7110->avout, buf, count);	} else		aux_ring_buffer_write(&av7110->aout, buf, count);}static void play_audio_cb(u8 *buf, int count, void *priv){	struct av7110 *av7110 = (struct av7110 *) priv;	DEB_EE(("av7110: %p\n", av7110));	aux_ring_buffer_write(&av7110->aout, buf, count);}#define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \		   dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)static ssize_t dvb_play(struct av7110 *av7110, const u8 *buf,			unsigned long count, int nonblock, int type, int umem){	unsigned long todo = count, n;	DEB_EE(("av7110: %p\n", av7110));	if (!av7110->kbuf[type])		return -ENOBUFS;	if (nonblock && !FREE_COND)		return -EWOULDBLOCK;	while (todo > 0) {		if (!FREE_COND) {			if (nonblock)				return count - todo;			if (wait_event_interruptible(av7110->avout.queue,						     FREE_COND))				return count - todo;		}		n = todo;		if (n > IPACKS * 2)			n = IPACKS * 2;		if (umem) {			if (copy_from_user(av7110->kbuf[type], buf, n))				return -EFAULT;			av7110_ipack_instant_repack(av7110->kbuf[type], n,						    &av7110->ipack[type]);		} else {			av7110_ipack_instant_repack(buf, n,						    &av7110->ipack[type]);		}		todo -= n;		buf += n;	}	return count - todo;}static ssize_t dvb_aplay(struct av7110 *av7110, const u8 *buf,			 unsigned long count, int nonblock, int type){	unsigned long todo = count, n;	DEB_EE(("av7110: %p\n", av7110));	if (!av7110->kbuf[type])		return -ENOBUFS;	if (nonblock && dvb_ringbuffer_free(&av7110->aout) < 20 * 1024)		return -EWOULDBLOCK;	while (todo > 0) {		if (dvb_ringbuffer_free(&av7110->aout) < 20 * 1024) {			if (nonblock)				return count - todo;

⌨️ 快捷键说明

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