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 + -
显示快捷键?