av7110.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 1,699 行 · 第 1/4 页

C
1,699
字号
/* * 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/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 <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 = 0;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, NULL, 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);

⌨️ 快捷键说明

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