📄 av7110.c
字号:
/* * 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(¤t->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 + -