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

📄 av7110.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * 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/config.h>#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/moduleparam.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/firmware.h>#include <linux/crc32.h>#include <linux/i2c.h>#include <asm/system.h>#include <asm/semaphore.h>#include <linux/dvb/frontend.h>#include "dvb_frontend.h"#include "ttpci-eeprom.h"#include "av7110.h"#include "av7110_hw.h"#include "av7110_av.h"#include "av7110_ca.h"#include "av7110_ipack.h"#define TS_WIDTH  376#define TS_HEIGHT 512#define TS_BUFLEN (TS_WIDTH*TS_HEIGHT)#define TS_MAX_PACKETS (TS_BUFLEN/TS_SIZE)int av7110_debug;static int vidmode = CVBS_RGB_OUT;static int pids_off;static int adac = DVB_ADAC_TI;static int hw_sections;static int rgb_on;static int volume = 255;static int budgetpatch = 0;module_param_named(debug, av7110_debug, int, 0644);MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)");module_param(vidmode, int, 0444);MODULE_PARM_DESC(vidmode,"analog video out: 0 off, 1 CVBS+RGB (default), 2 CVBS+YC, 3 YC");module_param(pids_off, int, 0444);MODULE_PARM_DESC(pids_off,"clear video/audio/PCR PID filters when demux is closed");module_param(adac, int, 0444);MODULE_PARM_DESC(adac,"audio DAC type: 0 TI, 1 CRYSTAL, 2 MSP (use if autodetection fails)");module_param(hw_sections, int, 0444);MODULE_PARM_DESC(hw_sections, "0 use software section filter, 1 use hardware");module_param(rgb_on, int, 0444);MODULE_PARM_DESC(rgb_on, "For Siemens DVB-C cards only: Enable RGB control"		" signal on SCART pin 16 to switch SCART video mode from CVBS to RGB");module_param(volume, int, 0444);MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)");module_param(budgetpatch, int, 0444);MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)");static void restart_feeds(struct av7110 *av7110);static int av7110_num = 0;#define FE_FUNC_OVERRIDE(fe_func, av7110_copy, av7110_func) \{\	if (fe_func != NULL) { \		av7110_copy = fe_func; \		fe_func = av7110_func; \	} \}static void init_av7110_av(struct av7110 *av7110){	int ret;	struct saa7146_dev *dev = av7110->dev;	/* set internal volume control to maximum */	av7110->adac_type = DVB_ADAC_TI;	ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);	if (ret < 0)		printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret);	ret = av7710_set_video_mode(av7110, vidmode);	if (ret < 0)		printk("dvb-ttpci:cannot set video mode:%d\n",ret);	/* handle different card types */	/* remaining inits according to card and frontend type */	av7110->analog_tuner_flags = 0;	av7110->current_input = 0;	if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {		printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n",			av7110->dvb_adapter.num);		av7110->adac_type = DVB_ADAC_CRYSTAL;		i2c_writereg(av7110, 0x20, 0x01, 0xd2);		i2c_writereg(av7110, 0x20, 0x02, 0x49);		i2c_writereg(av7110, 0x20, 0x03, 0x00);		i2c_writereg(av7110, 0x20, 0x04, 0x00);		/**		 * some special handling for the Siemens DVB-C cards...		 */	} else if (0 == av7110_init_analog_module(av7110)) {		/* done. */	}	else if (dev->pci->subsystem_vendor == 0x110a) {		printk("dvb-ttpci: DVB-C w/o analog module @ card %d detected\n",			av7110->dvb_adapter.num);		av7110->adac_type = DVB_ADAC_NONE;	}	else {		av7110->adac_type = adac;		printk("dvb-ttpci: adac type set to %d @ card %d\n",			av7110->dvb_adapter.num, av7110->adac_type);	}	if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP) {		// switch DVB SCART on		ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0);		if (ret < 0)			printk("dvb-ttpci:cannot switch on SCART(Main):%d\n",ret);		ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1);		if (ret < 0)			printk("dvb-ttpci:cannot switch on SCART(AD):%d\n",ret);		if (rgb_on &&		    ((av7110->dev->pci->subsystem_vendor == 0x110a) ||		     (av7110->dev->pci->subsystem_vendor == 0x13c2)) &&		     (av7110->dev->pci->subsystem_device == 0x0000)) {			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // RGB on, SCART pin 16			//saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // SCARTpin 8		}	}	if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000e)		av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, SpdifSwitch, 1, 0); // SPDIF on	ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);	if (ret < 0)		printk("dvb-ttpci:cannot set volume :%d\n",ret);}static void recover_arm(struct av7110 *av7110){	dprintk(4, "%p\n",av7110);	av7110_bootarm(av7110);	msleep(100);	restart_feeds(av7110);	av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);}static void arm_error(struct av7110 *av7110){	dprintk(4, "%p\n",av7110);	av7110->arm_errors++;	av7110->arm_ready = 0;	recover_arm(av7110);}static void av7110_arm_sync(struct av7110 *av7110){	av7110->arm_rmmod = 1;	wake_up_interruptible(&av7110->arm_wait);	while (av7110->arm_thread)		msleep(1);}static int arm_thread(void *data){	struct av7110 *av7110 = data;	u16 newloops = 0;	int timeout;	dprintk(4, "%p\n",av7110);	lock_kernel();	daemonize("arm_mon");	sigfillset(&current->blocked);	unlock_kernel();	av7110->arm_thread = current;	for (;;) {		timeout = wait_event_interruptible_timeout(av7110->arm_wait,							   av7110->arm_rmmod, 5 * HZ);		if (-ERESTARTSYS == timeout || 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 "dvb-ttpci: ARM crashed @ card %d\n",			       av7110->dvb_adapter.num);			arm_error(av7110);			av7710_set_video_mode(av7110, vidmode);			init_av7110_av(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;}/**************************************************************************** * IRQ handling ****************************************************************************/static 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){	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}#define DEBI_READ 0#define DEBI_WRITE 1static inline void start_debi_dma(struct av7110 *av7110, int dir,				  unsigned long addr, unsigned int len){	dprintk(8, "%c %08lx %u\n", dir == DEBI_READ ? 'R' : 'W', addr, len);	if (saa7146_wait_for_debi_done(av7110->dev, 0)) {		printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __FUNCTION__);		return;	}	SAA7146_ISR_CLEAR(av7110->dev, MASK_19); /* for good measure */	SAA7146_IER_ENABLE(av7110->dev, MASK_19);	if (len < 5)		len = 5; /* we want a real DEBI DMA */	if (dir == DEBI_WRITE)		iwdebi(av7110, DEBISWAB, addr, 0, (len + 3) & ~3);	else		irdebi(av7110, DEBISWAB, addr, 0, len);}static void debiirq(unsigned long data){	struct av7110 *av7110 = (struct av7110 *) data;	int type = av7110->debitype;	int handle = (type >> 8) & 0x1f;	unsigned int xfer = 0;	print_time("debi");	dprintk(4, "type 0x%04x\n", type);	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));		goto debi_done;	}	av7110->debitype = -1;	switch (type & 0xff) {	case DATA_TS_RECORD:		dvb_dmx_swfilter_packets(&av7110->demux,					 (const u8 *) av7110->debi_virt,					 av7110->debilen / 188);		xfer = RX_BUFF;		break;	case DATA_PES_RECORD:		if (av7110->demux.recording)			av7110_record_cb(&av7110->p2t[handle],					 (u8 *) av7110->debi_virt,					 av7110->debilen);		xfer = RX_BUFF;		break;	case DATA_IPMPE:	case DATA_FSECTION:	case DATA_PIPING:		if (av7110->handle2filter[handle])			DvbDmxFilterCallback((u8 *)av7110->debi_virt,					     av7110->debilen, NULL, 0,					     av7110->handle2filter[handle],					     DMX_OK, av7110);		xfer = RX_BUFF;		break;	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);		xfer = RX_BUFF;		break;	}	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		xfer = RX_BUFF;		break;	case DATA_DEBUG_MESSAGE:		((s8*)av7110->debi_virt)[Reserved_SIZE - 1] = 0;		printk("%s\n", (s8 *) av7110->debi_virt);		xfer = RX_BUFF;		break;	case DATA_CI_PUT:		dprintk(4, "debi DATA_CI_PUT\n");	case DATA_MPEG_PLAY:		dprintk(4, "debi DATA_MPEG_PLAY\n");	case DATA_BMP_LOAD:		dprintk(4, "debi DATA_BMP_LOAD\n");		xfer = TX_BUFF;		break;	default:		break;	}debi_done:	spin_lock(&av7110->debilock);	if (xfer)		iwdebi(av7110, DEBINOSWAP, xfer, 0, 2);	ARM_ClearMailBox(av7110);	spin_unlock(&av7110->debilock);}/* irq from av7110 firmware writing the mailbox register in the DPRAM */static void gpioirq(unsigned long data){	struct av7110 *av7110 = (struct av7110 *) data;	u32 rxbuf, txbuf;	int len;	if (av7110->debitype != -1)		/* we shouldn't get any irq while a debi xfer is running */		printk("dvb-ttpci: GPIO0 irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n",		       jiffies, saa7146_read(av7110->dev, PSR),		       saa7146_read(av7110->dev, SSR));	if (saa7146_wait_for_debi_done(av7110->dev, 0)) {		printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __FUNCTION__);		BUG(); /* maybe we should try resetting the debi? */	}	spin_lock(&av7110->debilock);	ARM_ClearIrq(av7110);	/* see what the av7110 wants */	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);

⌨️ 快捷键说明

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