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

📄 av7110.c

📁 linux环境下的dvb驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * driver for the SAA7146 based AV110 cards (like the Fujitsu-Siemens DVB) * av7110.c: initialization and demux 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/module.h>#include <linux/kmod.h>#include <linux/delay.h>#include <linux/fs.h>#include <linux/timer.h>#include <linux/poll.h>#include <linux/byteorder/swabb.h>#include <linux/smp_lock.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/string.h>#include <linux/pci.h>#include <linux/vmalloc.h>#include <linux/version.h>#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0))#include <linux/firmware.h>#endif#include <linux/crc32.h>#include <asm/system.h>#include <asm/semaphore.h>#include <linux/dvb/frontend.h>#include "dvb_i2c.h"#include "dvb_frontend.h"#include "dvb_functions.h"#define DEBUG_VARIABLE av7110_debug#include "ttpci-eeprom.h"#include "av7110.h"#include "av7110_hw.h"#include "av7110_av.h"#include "av7110_ca.h"#include "av7110_ipack.h"static void restart_feeds(struct av7110 *av7110);int av7110_debug = 0;static int vidmode = CVBS_RGB_OUT;static int pids_off;static int adac = DVB_ADAC_TI;static int hw_sections = 1;static int rgb_on = 0;int av7110_num = 0;static void recover_arm(struct av7110 *av7110){	DEB_EE(("av7110: %p\n",av7110));	av7110_bootarm(av7110);	dvb_delay(100);	restart_feeds(av7110);	av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);}static void arm_error(struct av7110 *av7110){	DEB_EE(("av7110: %p\n",av7110));	av7110->arm_errors++;	av7110->arm_ready = 0;	recover_arm(av7110);}static int arm_thread(void *data){	struct av7110 *av7110 = data;	unsigned long timeout;	u16 newloops = 0;	DEB_EE(("av7110: %p\n",av7110));	dvb_kernel_thread_setup("arm_mon");	av7110->arm_thread = current;	while (1) {		timeout = wait_event_interruptible_timeout(av7110->arm_wait,0 != av7110->arm_rmmod, 5*HZ);		if (-ERESTARTSYS == timeout || 0 != av7110->arm_rmmod) {			/* got signal or told to quit*/			break;		}		if (!av7110->arm_ready)			continue;		if (down_interruptible(&av7110->dcomlock))			break;		newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);		up(&av7110->dcomlock);		if (newloops == av7110->arm_loops) {			printk(KERN_ERR "av7110%d: ARM crashed!\n",			       av7110->dvb_adapter->num);			arm_error(av7110);			if (down_interruptible(&av7110->dcomlock))				break;			newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1;			up(&av7110->dcomlock);		}		av7110->arm_loops = newloops;	}	av7110->arm_thread = NULL;	return 0;}/** *  Hack! we save the last av7110 ptr. This should be ok, since *  you rarely will use more then one IR control. * *  If we want to support multiple controls we would have to do much more... */void av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config){	static struct av7110 *last;	DEB_EE(("av7110: %p\n",av7110));	if (!av7110)		av7110 = last;	else		last = av7110;	if (av7110) {		av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config);		av7110->ir_config = ir_config;	}}static void (*irc_handler)(u32);void av7110_register_irc_handler(void (*func)(u32)){	DEB_EE(("registering %p\n", func));	irc_handler = func;}void av7110_unregister_irc_handler(void (*func)(u32)){	DEB_EE(("unregistering %p\n", func));	irc_handler = NULL;}void run_handlers(unsigned long ircom){	if (irc_handler != NULL)		(*irc_handler)((u32) ircom);}DECLARE_TASKLET(irtask, run_handlers, 0);void IR_handle(struct av7110 *av7110, u32 ircom){	DEB_S(("av7110: ircommand = %08x\n", ircom));	irtask.data = (unsigned long) ircom;	tasklet_schedule(&irtask);}/**************************************************************************** * IRQ handling ****************************************************************************/static inline int DvbDmxFilterCallback(u8 * buffer1, size_t buffer1_len,		     u8 * buffer2, size_t buffer2_len,		     struct dvb_demux_filter *dvbdmxfilter,		     enum dmx_success success,		     struct av7110 *av7110){	DEB_INT(("av7110: %p\n", av7110));	if (!dvbdmxfilter->feed->demux->dmx.frontend)		return 0;	if (dvbdmxfilter->feed->demux->dmx.frontend->source == DMX_MEMORY_FE)		return 0;	switch (dvbdmxfilter->type) {	case DMX_TYPE_SEC:		if ((((buffer1[1] << 8) | buffer1[2]) & 0xfff) + 3 != buffer1_len)			return 0;		if (dvbdmxfilter->doneq) {			struct dmx_section_filter *filter = &dvbdmxfilter->filter;			int i;			u8 xor, neq = 0;			for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {				xor = filter->filter_value[i] ^ buffer1[i];				neq |= dvbdmxfilter->maskandnotmode[i] & xor;			}			if (!neq)				return 0;		}		return dvbdmxfilter->feed->cb.sec(buffer1, buffer1_len,						  buffer2, buffer2_len,						  &dvbdmxfilter->filter,						  DMX_OK);	case DMX_TYPE_TS:		if (!(dvbdmxfilter->feed->ts_type & TS_PACKET))			return 0;		if (dvbdmxfilter->feed->ts_type & TS_PAYLOAD_ONLY)			return dvbdmxfilter->feed->cb.ts(buffer1, buffer1_len,							 buffer2, buffer2_len,							 &dvbdmxfilter->feed->feed.ts,							 DMX_OK);		else			av7110_p2t_write(buffer1, buffer1_len,					 dvbdmxfilter->feed->pid,					 &av7110->p2t_filter[dvbdmxfilter->index]);	default:		return 0;	}}//#define DEBUG_TIMINGstatic inline void print_time(char *s){#ifdef DEBUG_TIMING	struct timeval tv;	do_gettimeofday(&tv);	printk("%s: %d.%d\n", s, (int)tv.tv_sec, (int)tv.tv_usec);#endif}static void debiirq (unsigned long data){	struct av7110 *av7110 = (struct av7110*) data;	int type = av7110->debitype;	int handle = (type >> 8) & 0x1f;//	DEB_EE(("av7110: %p\n",av7110));	print_time("debi");	saa7146_write(av7110->dev, IER,		      saa7146_read(av7110->dev, IER) & ~MASK_19);	saa7146_write(av7110->dev, ISR, MASK_19);	if (type == -1) {		printk("DEBI irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n",		       jiffies, saa7146_read(av7110->dev, PSR),		       saa7146_read(av7110->dev, SSR));		spin_lock(&av7110->debilock);		ARM_ClearMailBox(av7110);		ARM_ClearIrq(av7110);		spin_unlock(&av7110->debilock);		return;	}	av7110->debitype = -1;	switch (type & 0xff) {	case DATA_TS_RECORD:		dvb_dmx_swfilter_packets(&av7110->demux,					 (const u8 *) av7110->debi_virt,					 av7110->debilen / 188);		spin_lock(&av7110->debilock);		iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);		ARM_ClearMailBox(av7110);		spin_unlock(&av7110->debilock);		return;	case DATA_PES_RECORD:		if (av7110->demux.recording)			av7110_record_cb(&av7110->p2t[handle],					 (u8 *) av7110->debi_virt,					 av7110->debilen);		spin_lock(&av7110->debilock);		iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);		ARM_ClearMailBox(av7110);		spin_unlock(&av7110->debilock);		return;	case DATA_IPMPE:	case DATA_FSECTION:	case DATA_PIPING:		if (av7110->handle2filter[handle])			DvbDmxFilterCallback((u8 *)av7110->debi_virt,					     av7110->debilen, 0, 0,					     av7110->handle2filter[handle],					     DMX_OK, av7110);		spin_lock(&av7110->debilock);		iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);		ARM_ClearMailBox(av7110);		spin_unlock(&av7110->debilock);		return;	case DATA_CI_GET:	{		u8 *data = av7110->debi_virt;		if ((data[0] < 2) && data[2] == 0xff) {			int flags = 0;			if (data[5] > 0)				flags |= CA_CI_MODULE_PRESENT;			if (data[5] > 5)				flags |= CA_CI_MODULE_READY;			av7110->ci_slot[data[0]].flags = flags;		} else			ci_get_data(&av7110->ci_rbuffer,				    av7110->debi_virt,				    av7110->debilen);		spin_lock(&av7110->debilock);		iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);		ARM_ClearMailBox(av7110);		spin_unlock(&av7110->debilock);		return;	}	case DATA_COMMON_INTERFACE:		CI_handle(av7110, (u8 *)av7110->debi_virt, av7110->debilen);#if 0	{		int i;		printk("av7110%d: ", av7110->num);		printk("%02x ", *(u8 *)av7110->debi_virt);		printk("%02x ", *(1+(u8 *)av7110->debi_virt));		for (i = 2; i < av7110->debilen; i++)			printk("%02x ", (*(i+(unsigned char *)av7110->debi_virt)));		for (i = 2; i < av7110->debilen; i++)			printk("%c", chtrans(*(i+(unsigned char *)av7110->debi_virt)));		printk("\n");	}#endif		spin_lock(&av7110->debilock);		iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);		ARM_ClearMailBox(av7110);		spin_unlock(&av7110->debilock);		return;	case DATA_DEBUG_MESSAGE:		((s8*)av7110->debi_virt)[Reserved_SIZE - 1] = 0;		printk("%s\n", (s8 *) av7110->debi_virt);		spin_lock(&av7110->debilock);		iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);		ARM_ClearMailBox(av7110);		spin_unlock(&av7110->debilock);		return;	case DATA_CI_PUT:	case DATA_MPEG_PLAY:	case DATA_BMP_LOAD:		spin_lock(&av7110->debilock);		iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);		ARM_ClearMailBox(av7110);		spin_unlock(&av7110->debilock);		return;	default:		break;	}	spin_lock(&av7110->debilock);	ARM_ClearMailBox(av7110);	spin_unlock(&av7110->debilock);}static void gpioirq (unsigned long data){	struct av7110 *av7110 = (struct av7110*) data;	u32 rxbuf, txbuf;	int len;	//printk("GPIO0 irq\n");	if (av7110->debitype !=-1)		printk("GPIO0 irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n",		       jiffies, saa7146_read(av7110->dev, PSR),		       saa7146_read(av7110->dev, SSR));	spin_lock(&av7110->debilock);	ARM_ClearIrq(av7110);	saa7146_write(av7110->dev, IER,		      saa7146_read(av7110->dev, IER) & ~MASK_19);	saa7146_write(av7110->dev, ISR, MASK_19);	av7110->debitype = irdebi(av7110, DEBINOSWAP, IRQ_STATE, 0, 2);	av7110->debilen  = irdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);	rxbuf = irdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);	txbuf = irdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);	len = (av7110->debilen + 3) & ~3;//	DEB_D(("GPIO0 irq %d %d\n", av7110->debitype, av7110->debilen));	print_time("gpio");//	DEB_D(("GPIO0 irq %02x\n", av7110->debitype&0xff));	switch (av7110->debitype & 0xff) {	case DATA_TS_PLAY:	case DATA_PES_PLAY:		break;	case DATA_MPEG_VIDEO_EVENT:	{		u32 h_ar;		struct video_event event;		av7110->video_size.w = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_WIDTH, 0, 2);		h_ar = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_HEIGHT_AR, 0, 2);		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);		iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);		av7110->video_size.h = h_ar & 0xfff;		DEB_D(("GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n",				av7110->video_size.w,				av7110->video_size.h,				av7110->video_size.aspect_ratio));		event.type = VIDEO_EVENT_SIZE_CHANGED;		event.u.size.w = av7110->video_size.w;		event.u.size.h = av7110->video_size.h;		switch ((h_ar >> 12) & 0xf)		{		case 3:			av7110->video_size.aspect_ratio = VIDEO_FORMAT_16_9;			event.u.size.aspect_ratio = VIDEO_FORMAT_16_9;			av7110->videostate.video_format = VIDEO_FORMAT_16_9;			break;		case 4:			av7110->video_size.aspect_ratio = VIDEO_FORMAT_221_1;			event.u.size.aspect_ratio = VIDEO_FORMAT_221_1;			av7110->videostate.video_format = VIDEO_FORMAT_221_1;			break;		default:			av7110->video_size.aspect_ratio = VIDEO_FORMAT_4_3;			event.u.size.aspect_ratio = VIDEO_FORMAT_4_3;			av7110->videostate.video_format = VIDEO_FORMAT_4_3;		}		dvb_video_add_event(av7110, &event);		break;	}	case DATA_CI_PUT:	{		int avail;		struct dvb_ringbuffer *cibuf = &av7110->ci_wbuffer;		avail = dvb_ringbuffer_avail(cibuf);		if (avail <= 2) {			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);			break;		}		len = DVB_RINGBUFFER_PEEK(cibuf, 0) << 8;		len |= DVB_RINGBUFFER_PEEK(cibuf, 1);		if (avail < len + 2) {			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);			break;		}		DVB_RINGBUFFER_SKIP(cibuf, 2);		dvb_ringbuffer_read(cibuf, av7110->debi_virt,len, 0);		wake_up(&cibuf->queue);		iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);		saa7146_wait_for_debi_done(av7110->dev);		saa7146_write(av7110->dev, IER,			      saa7146_read(av7110->dev, IER) | MASK_19);		if (len < 5)			len = 5; /* we want a real DEBI DMA */		iwdebi(av7110, DEBISWAB, DPRAM_BASE + txbuf, 0, (len + 3) & ~3);		spin_unlock(&av7110->debilock);		return;	}	case DATA_MPEG_PLAY:		if (!av7110->playing) {			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);			break;		}		len = 0;		if (av7110->debitype & 0x100) {			spin_lock(&av7110->aout.lock);			len=av7110_pes_play(av7110->debi_virt, &av7110->aout, 2048);			spin_unlock(&av7110->aout.lock);		}		if (len <=0 && (av7110->debitype & 0x200)		    &&av7110->videostate.play_state != VIDEO_FREEZED) {			spin_lock(&av7110->avout.lock);			len=av7110_pes_play(av7110->debi_virt, &av7110->avout, 2048);			spin_unlock(&av7110->avout.lock);		}		if (len <= 0) {			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);			break;		}		DEB_D(("GPIO0 PES_PLAY len=%04x\n", len));		iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);		iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);		saa7146_wait_for_debi_done(av7110->dev);		saa7146_write(av7110->dev, IER,			      saa7146_read(av7110->dev, IER) | MASK_19);		iwdebi(av7110, DEBISWAB, DPRAM_BASE + txbuf, 0, (len + 3) & ~3);		spin_unlock(&av7110->debilock);		return;	case DATA_BMP_LOAD:		len = av7110->debilen;		if (!len) {			av7110->bmp_state = BMP_LOADED;			iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2);			iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2);			iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2);			wake_up(&av7110->bmpq);			break;		}		if (len > av7110->bmplen)			len = av7110->bmplen;		if (len > 2 * 1024)

⌨️ 快捷键说明

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