📄 skystar2.c
字号:
/* * skystar2.c - driver for the Technisat SkyStar2 PCI DVB card * based on the FlexCopII by B2C2,Inc. * * Copyright (C) 2003 Vadim Catana, skystar@moldova.cc * * FIX: DISEQC Tone Burst in flexcop_diseqc_ioctl() * FIX: FULL soft DiSEqC for skystar2 (FlexCopII rev 130) VP310 equipped * Vincenzo Di Massa, hawk.it at tiscalinet.it * * Converted to Linux coding style * Misc reorganization, polishing, restyling * Roberto Ragusa, r.ragusa at libero.it * * Added hardware filtering support, * Niklas Peinecke, peinecke at gdv.uni-hannover.de * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * 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 Lesser 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. */#include <linux/module.h>#include <linux/delay.h>#include <linux/pci.h>#include <linux/init.h>#include <asm/io.h>#include "dvb_i2c.h"#include "dvb_frontend.h"#include <linux/dvb/frontend.h>#include <linux/dvb/dmx.h>#include "dvb_demux.h"#include "dmxdev.h"#include "dvb_filter.h"#include "dvbdev.h"#include "demux.h"#include "dvb_net.h"#include "dvb_functions.h"static int debug = 0;#define dprintk(x...) do { if (debug>=1) printk(x); } while (0)#define ddprintk(x...) do { if (debug>=2) printk(x); } while (0)static int enable_hw_filters = 2;#define SIZE_OF_BUF_DMA1 0x3ac00#define SIZE_OF_BUF_DMA2 0x758#define MAX_N_HW_FILTERS (6+32)#define N_PID_SLOTS 256struct dmaq { u32 bus_addr; u32 head; u32 tail; u32 buffer_size; u8 *buffer;};struct adapter { struct pci_dev *pdev; u8 card_revision; u32 b2c2_revision; u32 pid_filter_max; u32 mac_filter_max; u32 irq; unsigned long io_mem; unsigned long io_port; u8 mac_addr[8]; u32 dw_sram_type; struct dvb_adapter *dvb_adapter; struct dvb_demux demux; struct dmxdev dmxdev; struct dmx_frontend hw_frontend; struct dmx_frontend mem_frontend; struct dvb_i2c_bus *i2c_bus; struct dvb_net dvbnet; struct semaphore i2c_sem; struct dmaq dmaq1; struct dmaq dmaq2; u32 dma_ctrl; u32 dma_status; int capturing; spinlock_t lock; int useable_hw_filters; u16 hw_pids[MAX_N_HW_FILTERS]; u16 pid_list[N_PID_SLOTS]; int pid_rc[N_PID_SLOTS]; // ref counters for the pids int pid_count; int whole_bandwidth_count; u32 mac_filter;};#define write_reg_dw(adapter,reg,value) writel(value, adapter->io_mem + reg)#define read_reg_dw(adapter,reg) readl(adapter->io_mem + reg)static void write_reg_bitfield(struct adapter *adapter, u32 reg, u32 zeromask, u32 orvalue){ u32 tmp; tmp = read_reg_dw(adapter, reg); tmp = (tmp & ~zeromask) | orvalue; write_reg_dw(adapter, reg, tmp);}/* i2c functions */static int i2c_main_write_for_flex2(struct adapter *adapter, u32 command, u8 *buf, int retries){ int i; u32 value; write_reg_dw(adapter, 0x100, 0); write_reg_dw(adapter, 0x100, command); for (i = 0; i < retries; i++) { value = read_reg_dw(adapter, 0x100); if ((value & 0x40000000) == 0) { if ((value & 0x81000000) == 0x80000000) { if (buf != 0) *buf = (value >> 0x10) & 0xff; return 1; } } else { write_reg_dw(adapter, 0x100, 0); write_reg_dw(adapter, 0x100, command); } } return 0;}/* device = 0x10000000 for tuner, 0x20000000 for eeprom */static void i2c_main_setup(u32 device, u32 chip_addr, u8 op, u8 addr, u32 value, u32 len, u32 *command){ *command = device | ((len - 1) << 26) | (value << 16) | (addr << 8) | chip_addr; if (op != 0) *command = *command | 0x03000000; else *command = *command | 0x01000000;}static int flex_i2c_read4(struct adapter *adapter, u32 device, u32 chip_addr, u16 addr, u8 *buf, u8 len){ u32 command; u32 value; int result, i; i2c_main_setup(device, chip_addr, 1, addr, 0, len, &command); result = i2c_main_write_for_flex2(adapter, command, buf, 100000); if ((result & 0xff) != 0) { if (len > 1) { value = read_reg_dw(adapter, 0x104); for (i = 1; i < len; i++) { buf[i] = value & 0xff; value = value >> 8; } } } return result;}static int flex_i2c_write4(struct adapter *adapter, u32 device, u32 chip_addr, u32 addr, u8 *buf, u8 len){ u32 command; u32 value; int i; if (len > 1) { value = 0; for (i = len; i > 1; i--) { value = value << 8; value = value | buf[i - 1]; } write_reg_dw(adapter, 0x104, value); } i2c_main_setup(device, chip_addr, 0, addr, buf[0], len, &command); return i2c_main_write_for_flex2(adapter, command, 0, 100000);}static void fixchipaddr(u32 device, u32 bus, u32 addr, u32 *ret){ if (device == 0x20000000) *ret = bus | ((addr >> 8) & 3); *ret = bus;}static u32 flex_i2c_read(struct adapter *adapter, u32 device, u32 bus, u32 addr, u8 *buf, u32 len){ u32 chipaddr; u32 bytes_to_transfer; u8 *start; ddprintk("%s:\n", __FUNCTION__); start = buf; while (len != 0) { bytes_to_transfer = len; if (bytes_to_transfer > 4) bytes_to_transfer = 4; fixchipaddr(device, bus, addr, &chipaddr); if (flex_i2c_read4(adapter, device, chipaddr, addr, buf, bytes_to_transfer) == 0) return buf - start; buf = buf + bytes_to_transfer; addr = addr + bytes_to_transfer; len = len - bytes_to_transfer; }; return buf - start;}static u32 flex_i2c_write(struct adapter *adapter, u32 device, u32 bus, u32 addr, u8 *buf, u32 len){ u32 chipaddr; u32 bytes_to_transfer; u8 *start; ddprintk("%s:\n", __FUNCTION__); start = buf; while (len != 0) { bytes_to_transfer = len; if (bytes_to_transfer > 4) bytes_to_transfer = 4; fixchipaddr(device, bus, addr, &chipaddr); if (flex_i2c_write4(adapter, device, chipaddr, addr, buf, bytes_to_transfer) == 0) return buf - start; buf = buf + bytes_to_transfer; addr = addr + bytes_to_transfer; len = len - bytes_to_transfer; } return buf - start;}static int master_xfer(struct dvb_i2c_bus *i2c, const struct i2c_msg *msgs, int num){ struct adapter *tmp = i2c->data; int i, ret = 0; if (down_interruptible(&tmp->i2c_sem)) return -ERESTARTSYS; ddprintk("%s: %d messages to transfer\n", __FUNCTION__, num); for (i = 0; i < num; i++) { ddprintk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i, msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len); /* allow only the mt312 and stv0299 frontends to access the bus */ if ((msgs[i].addr != 0x0e) && (msgs[i].addr != 0x68) && (msgs[i].addr != 0x61)) { up(&tmp->i2c_sem); return -EREMOTEIO; } } // read command if ((num == 2) && (msgs[0].flags == 0) && (msgs[1].flags == I2C_M_RD) && (msgs[0].buf != NULL) && (msgs[1].buf != NULL)) { ret = flex_i2c_read(tmp, 0x10000000, msgs[0].addr, msgs[0].buf[0], msgs[1].buf, msgs[1].len); up(&tmp->i2c_sem); if (ret != msgs[1].len) { printk("%s: read error !\n", __FUNCTION__); for (i = 0; i < 2; i++) { printk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i, msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len); } return -EREMOTEIO; } return num; } // write command for (i = 0; i < num; i++) { if ((msgs[i].flags != 0) || (msgs[i].buf == NULL) || (msgs[i].len < 2)) return -EINVAL; ret = flex_i2c_write(tmp, 0x10000000, msgs[i].addr, msgs[i].buf[0], &msgs[i].buf[1], msgs[i].len - 1); up(&tmp->i2c_sem); if (ret != msgs[0].len - 1) { printk("%s: write error %i !\n", __FUNCTION__, ret); printk("message %d: flags=0x%x, addr=0x%x, buf[0]=0x%x, len=%d \n", i, msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len); return -EREMOTEIO; } return num; } printk("%s: unknown command format !\n", __FUNCTION__); return -EINVAL;}/* SRAM (Skystar2 rev2.3 has one "ISSI IS61LV256" chip on board, but it seems that FlexCopII can work with more than one chip) */static void sram_set_net_dest(struct adapter *adapter, u8 dest){ u32 tmp; udelay(1000); tmp = (read_reg_dw(adapter, 0x714) & 0xfffffffc) | (dest & 3); udelay(1000); write_reg_dw(adapter, 0x714, tmp); write_reg_dw(adapter, 0x714, tmp); udelay(1000); /*return value is never used? *//* return tmp; */}static void sram_set_cai_dest(struct adapter *adapter, u8 dest){ u32 tmp; udelay(1000); tmp = (read_reg_dw(adapter, 0x714) & 0xfffffff3) | ((dest & 3) << 2); udelay(1000); udelay(1000); write_reg_dw(adapter, 0x714, tmp); write_reg_dw(adapter, 0x714, tmp); udelay(1000); /*return value is never used? *//* return tmp; */}static void sram_set_cao_dest(struct adapter *adapter, u8 dest){ u32 tmp; udelay(1000); tmp = (read_reg_dw(adapter, 0x714) & 0xffffffcf) | ((dest & 3) << 4); udelay(1000); udelay(1000); write_reg_dw(adapter, 0x714, tmp); write_reg_dw(adapter, 0x714, tmp); udelay(1000); /*return value is never used? *//* return tmp; */}static void sram_set_media_dest(struct adapter *adapter, u8 dest){ u32 tmp; udelay(1000); tmp = (read_reg_dw(adapter, 0x714) & 0xffffff3f) | ((dest & 3) << 6); udelay(1000); udelay(1000); write_reg_dw(adapter, 0x714, tmp); write_reg_dw(adapter, 0x714, tmp); udelay(1000); /* return value is never used? *//* return tmp; */}/* SRAM memory is accessed through a buffer register in the FlexCop chip (0x700). This register has the following structure: bits 0-14 : address bit 15 : read/write flag bits 16-23 : 8-bit word to write bits 24-27 : = 4 bits 28-29 : memory bank selector bit 31 : busy flag*/static void flex_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len){ int i, retries; u32 command; for (i = 0; i < len; i++) { command = bank | addr | 0x04000000 | (*buf << 0x10); retries = 2; while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { mdelay(1); retries--; }; if (retries == 0) printk("%s: SRAM timeout\n", __FUNCTION__); write_reg_dw(adapter, 0x700, command); buf++; addr++; }}static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len){ int i, retries; u32 command, value; for (i = 0; i < len; i++) { command = bank | addr | 0x04008000; retries = 10000; while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { mdelay(1); retries--; }; if (retries == 0) printk("%s: SRAM timeout\n", __FUNCTION__); write_reg_dw(adapter, 0x700, command); retries = 10000; while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { mdelay(1); retries--; }; if (retries == 0) printk("%s: SRAM timeout\n", __FUNCTION__); value = read_reg_dw(adapter, 0x700) >> 0x10; *buf = (value & 0xff); addr++; buf++; }}static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len){ u32 bank; bank = 0; if (adapter->dw_sram_type == 0x20000) { bank = (addr & 0x18000) << 0x0d; } if (adapter->dw_sram_type == 0x00000) { if ((addr >> 0x0f) == 0) bank = 0x20000000; else bank = 0x10000000; } flex_sram_write(adapter, bank, addr & 0x7fff, buf, len);}static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len){ u32 bank; bank = 0; if (adapter->dw_sram_type == 0x20000) { bank = (addr & 0x18000) << 0x0d; } if (adapter->dw_sram_type == 0x00000) { if ((addr >> 0x0f) == 0) bank = 0x20000000; else bank = 0x10000000; } flex_sram_read(adapter, bank, addr & 0x7fff, buf, len);}static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len){ u32 length; while (len != 0) { length = len; // check if the address range belongs to the same // 32K memory chip. If not, the data is read from // one chip at a time. if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { length = (((addr >> 0x0f) + 1) << 0x0f) - addr; } sram_read_chunk(adapter, addr, buf, length); addr = addr + length; buf = buf + length; len = len - length; }}static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len){ u32 length; while (len != 0) { length = len; // check if the address range belongs to the same // 32K memory chip. If not, the data is written to // one chip at a time. if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { length = (((addr >> 0x0f) + 1) << 0x0f) - addr; } sram_write_chunk(adapter, addr, buf, length); addr = addr + length; buf = buf + length; len = len - length; }}static void sram_set_size(struct adapter *adapter, u32 mask){ write_reg_dw(adapter, 0x71c, (mask | (~0x30000 & read_reg_dw(adapter, 0x71c))));}static void sram_init(struct adapter *adapter){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -