📄 av7110.c
字号:
/* * av7110.c: driver for the SAA7146 based AV110 cards (like the Fujitsu-Siemens DVB) * and Nova/Budget DVB cards * * 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/ */#define NEW_CI 1/* for debuggin ARM communication: *///#define COM_DEBUG#define __KERNEL_SYSCALLS__#include <linux/module.h>#include <linux/init.h>#include <linux/kmod.h>#include <linux/delay.h>#include <linux/fs.h>#include <linux/timer.h>#include <linux/unistd.h>#include <linux/byteorder/swabb.h>#include <linux/poll.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <stdarg.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/in.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/pci.h>#include <asm/system.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/semaphore.h>#include <linux/init.h>#include <linux/vmalloc.h>#include <linux/netdevice.h>#include <linux/inetdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/dvb/frontend.h>#include "dvb_i2c.h"#include "dvb_frontend.h"#include "compat.h"#include "av7110.h"#include "saa7146_core.h"#include "saa7146_v4l.h"#include "saa7146_defs.h"#include "ttpci_eeprom.h"static int AV_StartPlay(av7110_t *av7110, int av);static void restart_feeds(av7110_t *av7110);static int bootarm(av7110_t *av7110);static inline int i2c_writereg(av7110_t *av7110, u8 id, u8 reg, u8 val);static inline u8 i2c_readreg(av7110_t *av7110, u8 id, u8 reg);static int outcom(av7110_t *av7110, int type, int com, int num, ...);static void SetMode(av7110_t *av7110, int mode);static void dvb_video_add_event (av7110_t *av7110, struct video_event *event);void pes_to_ts(u8 const *buf, long int length, u16 pid, p2t_t *p);void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter, struct dvb_demux_feed *feed);static u32 vidmem = 0;static u32 vidlow = 0;static int av7110_debug = 0;#define dprintk(a...) do { if (av7110_debug) printk(a); } while (0)static int vidmode=CVBS_RGB_OUT;static int pids_off;static int adac=DVB_ADAC_TI;/** * crc32 is not implemented in the av7110 firmware, section filter checksum * checks work for hw_sections=0! */static int hw_sections = 0;#define saacomm(x,y) av7110->saa->command(av7110->saa->i2c_bus, (x), (y))#define FW_CI_LL_SUPPORT(arm_app) (arm_app & 0x80000000)#define FW_VERSION(arm_app) (arm_app & 0x0000FFFF)/**************************************************************************** * General helper functions ****************************************************************************/static inline void ddelay(int i) { current->state=TASK_INTERRUPTIBLE; schedule_timeout((HZ*i)/100);}static inline intmsp_writereg(av7110_t *av7110, u8 dev, u16 reg, u16 val){ u8 msg[5]={ dev, reg>>8, reg&0xff, val>>8 , val&0xff }; struct dvb_i2c_bus *i2c = av7110->saa->i2c_bus; struct i2c_msg msgs; msgs.flags=0; msgs.addr=0x40; msgs.len=5; msgs.buf=msg; return i2c->xfer(i2c, &msgs, 1);}/**************************************************************************** * GPIO and DEBI functions ****************************************************************************/#define saaread(adr) saa7146_read(saamem,(adr))#define saawrite(dat,adr) saa7146_write(saamem,(adr),(dat))inline static void setgpio(av7110_t *av7110, int port, u32 data){ void *saamem=av7110->saa_mem; u32 val; val=saaread(GPIO_CTRL); val&=~(0xff << (8*(port))); val|=(data)<<(8*(port)); saawrite(val, GPIO_CTRL);}/* This DEBI code is based on the Stradis driver by Nathan Laredo <laredo@gnu.org> */staticint wait_for_debi_done(av7110_t *av7110){ void *saamem=av7110->saa_mem; int start; /* wait for registers to be programmed */ start = jiffies; while (1) { if (saaread(MC2) & 2) break; if (jiffies-start > HZ/20) { printk ("%s: timed out while waiting for registers " "getting programmed\n", __FUNCTION__); return -ETIMEDOUT; } } /* wait for transfer to complete */ start = jiffies; while (1) { if (!(saaread(PSR) & SPCI_DEBI_S)) break; saaread(MC2); if (jiffies-start > HZ/4) { printk ("%s: timed out while waiting for transfer " "completion\n", __FUNCTION__); return -ETIMEDOUT; } } return 0;}static int debiwrite(av7110_t *av7110, u32 config, int addr, u32 val, int count){ void *saamem=av7110->saa_mem; u32 cmd; if (count <= 0 || count > 32764) return -1; if (wait_for_debi_done(av7110) < 0) return -1; saawrite(config, DEBI_CONFIG); if (count <= 4) /* immediate transfer */ saawrite(val, DEBI_AD); else /* block transfer */ saawrite(av7110->debi_bus, DEBI_AD); saawrite((cmd = (count << 17) | (addr & 0xffff)), DEBI_COMMAND); saawrite((2 << 16) | 2, MC2); return 0;}static u32 debiread(av7110_t *av7110, u32 config, int addr, int count){ void *saamem=av7110->saa_mem; u32 result = 0; if (count > 32764 || count <= 0) return 0; if (wait_for_debi_done(av7110) < 0) return 0; saawrite(av7110->debi_bus, DEBI_AD); saawrite((count << 17) | 0x10000 | (addr & 0xffff), DEBI_COMMAND); saawrite(config, DEBI_CONFIG); saawrite((2 << 16) | 2, MC2); if (count > 4) return count; wait_for_debi_done(av7110); result = saaread(DEBI_AD); result &= (0xffffffffUL >> ((4-count)*8)); return result;}/* DEBI during interrupt */static inline void iwdebi(av7110_t *av7110, u32 config, int addr, u32 val, int count){ if (count>4 && val) memcpy(av7110->debi_virt, (char *) val, count); debiwrite(av7110, config, addr, val, count);}static inline u32 irdebi(av7110_t *av7110, u32 config, int addr, u32 val, int count){ u32 res; res=debiread(av7110, config, addr, count); if (count<=4) memcpy(av7110->debi_virt, (char *) &res, count); return res;}/* DEBI outside interrupts, only for count<=4! */static inline void wdebi(av7110_t *av7110, u32 config, int addr, u32 val, int count){ unsigned long flags; spin_lock_irqsave(&av7110->debilock, flags); debiwrite(av7110, config, addr, val, count); spin_unlock_irqrestore(&av7110->debilock, flags);}static inline u32 rdebi(av7110_t *av7110, u32 config, int addr, u32 val, int count){ unsigned long flags; u32 res; spin_lock_irqsave(&av7110->debilock, flags); res=debiread(av7110, config, addr, count); spin_unlock_irqrestore(&av7110->debilock, flags); return res;}static inline char chtrans(char c){ if (c<32 || c>126) c=0x20; return c;}/* handle mailbox registers of the dual ported RAM */static inline void ARM_ResetMailBox(av7110_t *av7110){ unsigned long flags; spin_lock_irqsave(&av7110->debilock, flags); debiread(av7110, DEBINOSWAP, IRQ_RX, 2); //printk("dvb: IRQ_RX=%d\n", debiread(av7110, DEBINOSWAP, IRQ_RX, 2)); debiwrite(av7110, DEBINOSWAP, IRQ_RX, 0, 2); spin_unlock_irqrestore(&av7110->debilock, flags);}static inline void ARM_ClearMailBox(av7110_t *av7110){ iwdebi(av7110, DEBINOSWAP, IRQ_RX, 0, 2);}static inline void ARM_ClearIrq(av7110_t *av7110){ irdebi(av7110, DEBINOSWAP, IRQ_RX, 0, 2);}static void reset_arm(av7110_t *av7110){ setgpio(av7110, RESET_LINE, GPIO_OUTLO); /* Disable DEBI and GPIO irq */ saa7146_write(av7110->saa_mem, IER, saa7146_read(av7110->saa_mem, IER) & ~(MASK_19 | MASK_03)); saa7146_write(av7110->saa_mem, ISR, (MASK_19 | MASK_03)); mdelay(800); setgpio(av7110, RESET_LINE, GPIO_OUTHI); mdelay(800); ARM_ResetMailBox(av7110); saa7146_write(av7110->saa_mem, ISR, (MASK_19 | MASK_03)); saa7146_write(av7110->saa_mem, IER, saa7146_read(av7110->saa_mem, IER) | MASK_03 ); av7110->arm_ready=1; printk("av7110: ARM RESET\n");}static void recover_arm(av7110_t *av7110){ if (current->files) bootarm(av7110); else { printk("OOPS, no current->files\n"); reset_arm(av7110); } ddelay(10); restart_feeds(av7110); outcom(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);}static void arm_error(av7110_t *av7110){ av7110->arm_errors++; av7110->arm_ready=0; recover_arm(av7110);}static int arm_thread(void *data){ av7110_t *av7110 = data; u16 newloops; lock_kernel();#if 1 daemonize(); reparent_to_init ();#else exit_mm(current); current->session=current->pgrp=1;#endif sigfillset(¤t->blocked); strncpy(current->comm, "kdvb-av7110", sizeof(current->comm)); av7110->arm_thread = current; unlock_kernel(); while (!av7110->arm_rmmod && !signal_pending(current)) { interruptible_sleep_on_timeout(&av7110->arm_wait, 5*HZ); 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->saa->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;}static intrecord_cb(dvb_filter_pes2ts_t *p2t, u8 *buf, size_t len)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -