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

📄 av7110.c

📁 h内核
💻 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){	struct saa7146_dev *dev=av7110->dev;	/* set internal volume control to maximum */	av7110->adac_type = DVB_ADAC_TI;	av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);	av7710_set_video_mode(av7110, vidmode);	/* 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		av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0);		av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1);		if (rgb_on &&		    (av7110->dev->pci->subsystem_vendor == 0x110a) && (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	}	}	av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);	av7110_setup_irc_config(av7110, 0);}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 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;}/** *  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;	dprintk(4, "%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)) {	dprintk(4, "registering %p\n", func);        irc_handler = func;}void av7110_unregister_irc_handler(void (*func)(u32)) {	dprintk(4, "unregistering %p\n", func);        irc_handler = NULL;}static void run_handlers(unsigned long ircom){        if (irc_handler != NULL)                (*irc_handler)((u32) ircom);}static DECLARE_TASKLET(irtask, run_handlers, 0);static void IR_handle(struct av7110 *av7110, u32 ircom){	dprintk(4, "ircommand = %08x\n", ircom);        irtask.data = (unsigned long) ircom;        tasklet_schedule(&irtask);}/**************************************************************************** * 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;

⌨️ 快捷键说明

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