📄 dm1105.c
字号:
/* * dm1105.c - driver for DVB cards based on SDMC DM1105 PCI chip * * Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by> * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <linux/i2c.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/proc_fs.h>#include <linux/pci.h>#include <linux/dma-mapping.h>#include <linux/input.h>#include <media/ir-common.h>#include "demux.h"#include "dmxdev.h"#include "dvb_demux.h"#include "dvb_frontend.h"#include "dvb_net.h"#include "dvbdev.h"#include "dvb-pll.h"#include "stv0299.h"#include "stv0288.h"#include "stb6000.h"#include "si21xx.h"#include "cx24116.h"#include "z0194a.h"/* ----------------------------------------------- *//* * PCI ID's */#ifndef PCI_VENDOR_ID_TRIGEM#define PCI_VENDOR_ID_TRIGEM 0x109f#endif#ifndef PCI_DEVICE_ID_DM1105#define PCI_DEVICE_ID_DM1105 0x036f#endif#ifndef PCI_DEVICE_ID_DW2002#define PCI_DEVICE_ID_DW2002 0x2002#endif#ifndef PCI_DEVICE_ID_DW2004#define PCI_DEVICE_ID_DW2004 0x2004#endif/* ----------------------------------------------- *//* sdmc dm1105 registers *//* TS Control */#define DM1105_TSCTR 0x00#define DM1105_DTALENTH 0x04/* GPIO Interface */#define DM1105_GPIOVAL 0x08#define DM1105_GPIOCTR 0x0c/* PID serial number */#define DM1105_PIDN 0x10/* Odd-even secret key select */#define DM1105_CWSEL 0x14/* Host Command Interface */#define DM1105_HOST_CTR 0x18#define DM1105_HOST_AD 0x1c/* PCI Interface */#define DM1105_CR 0x30#define DM1105_RST 0x34#define DM1105_STADR 0x38#define DM1105_RLEN 0x3c#define DM1105_WRP 0x40#define DM1105_INTCNT 0x44#define DM1105_INTMAK 0x48#define DM1105_INTSTS 0x4c/* CW Value */#define DM1105_ODD 0x50#define DM1105_EVEN 0x58/* PID Value */#define DM1105_PID 0x60/* IR Control */#define DM1105_IRCTR 0x64#define DM1105_IRMODE 0x68#define DM1105_SYSTEMCODE 0x6c#define DM1105_IRCODE 0x70/* Unknown Values */#define DM1105_ENCRYPT 0x74#define DM1105_VER 0x7c/* I2C Interface */#define DM1105_I2CCTR 0x80#define DM1105_I2CSTS 0x81#define DM1105_I2CDAT 0x82#define DM1105_I2C_RA 0x83/* ----------------------------------------------- *//* Interrupt Mask Bits */#define INTMAK_TSIRQM 0x01#define INTMAK_HIRQM 0x04#define INTMAK_IRM 0x08#define INTMAK_ALLMASK (INTMAK_TSIRQM | \ INTMAK_HIRQM | \ INTMAK_IRM)#define INTMAK_NONEMASK 0x00/* Interrupt Status Bits */#define INTSTS_TSIRQ 0x01#define INTSTS_HIRQ 0x04#define INTSTS_IR 0x08/* IR Control Bits */#define DM1105_IR_EN 0x01#define DM1105_SYS_CHK 0x02#define DM1105_REP_FLG 0x08/* EEPROM addr */#define IIC_24C01_addr 0xa0/* Max board count */#define DM1105_MAX 0x04#define DRIVER_NAME "dm1105"#define DM1105_DMA_PACKETS 47#define DM1105_DMA_PACKET_LENGTH (128*4)#define DM1105_DMA_BYTES (128 * 4 * DM1105_DMA_PACKETS)/* GPIO's for LNB power control */#define DM1105_LNB_MASK 0x00000000#define DM1105_LNB_13V 0x00010100#define DM1105_LNB_18V 0x00000100static int ir_debug;module_param(ir_debug, int, 0644);MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);static u16 ir_codes_dm1105_nec[128] = { [0x0a] = KEY_Q, /*power*/ [0x0c] = KEY_M, /*mute*/ [0x11] = KEY_1, [0x12] = KEY_2, [0x13] = KEY_3, [0x14] = KEY_4, [0x15] = KEY_5, [0x16] = KEY_6, [0x17] = KEY_7, [0x18] = KEY_8, [0x19] = KEY_9, [0x10] = KEY_0, [0x1c] = KEY_PAGEUP, /*ch+*/ [0x0f] = KEY_PAGEDOWN, /*ch-*/ [0x1a] = KEY_O, /*vol+*/ [0x0e] = KEY_Z, /*vol-*/ [0x04] = KEY_R, /*rec*/ [0x09] = KEY_D, /*fav*/ [0x08] = KEY_BACKSPACE, /*rewind*/ [0x07] = KEY_A, /*fast*/ [0x0b] = KEY_P, /*pause*/ [0x02] = KEY_ESC, /*cancel*/ [0x03] = KEY_G, /*tab*/ [0x00] = KEY_UP, /*up*/ [0x1f] = KEY_ENTER, /*ok*/ [0x01] = KEY_DOWN, /*down*/ [0x05] = KEY_C, /*cap*/ [0x06] = KEY_S, /*stop*/ [0x40] = KEY_F, /*full*/ [0x1e] = KEY_W, /*tvmode*/ [0x1b] = KEY_B, /*recall*/};/* infrared remote control */struct infrared { u16 key_map[128]; struct input_dev *input_dev; char input_phys[32]; struct tasklet_struct ir_tasklet; u32 ir_command;};struct dm1105dvb { /* pci */ struct pci_dev *pdev; u8 __iomem *io_mem; /* ir */ struct infrared ir; /* dvb */ struct dmx_frontend hw_frontend; struct dmx_frontend mem_frontend; struct dmxdev dmxdev; struct dvb_adapter dvb_adapter; struct dvb_demux demux; struct dvb_frontend *fe; struct dvb_net dvbnet; unsigned int full_ts_users; /* i2c */ struct i2c_adapter i2c_adap; /* dma */ dma_addr_t dma_addr; unsigned char *ts_buf; u32 wrp; u32 buffer_size; unsigned int PacketErrorCount; unsigned int dmarst; spinlock_t lock;};#define dm_io_mem(reg) ((unsigned long)(&dm1105dvb->io_mem[reg]))static struct dm1105dvb *dm1105dvb_local;static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num){ struct dm1105dvb *dm1105dvb ; int addr, rc, i, j, k, len, byte, data; u8 status; dm1105dvb = i2c_adap->algo_data; for (i = 0; i < num; i++) { outb(0x00, dm_io_mem(DM1105_I2CCTR)); if (msgs[i].flags & I2C_M_RD) { /* read bytes */ addr = msgs[i].addr << 1; addr |= 1; outb(addr, dm_io_mem(DM1105_I2CDAT)); for (byte = 0; byte < msgs[i].len; byte++) outb(0, dm_io_mem(DM1105_I2CDAT + byte + 1)); outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR)); for (j = 0; j < 55; j++) { mdelay(10); status = inb(dm_io_mem(DM1105_I2CSTS)); if ((status & 0xc0) == 0x40) break; } if (j >= 55) return -1; for (byte = 0; byte < msgs[i].len; byte++) { rc = inb(dm_io_mem(DM1105_I2CDAT + byte + 1)); if (rc < 0) goto err; msgs[i].buf[byte] = rc; } } else { if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) { /* prepaired for cx24116 firmware */ /* Write in small blocks */ len = msgs[i].len - 1; k = 1; do { outb(msgs[i].addr << 1, dm_io_mem(DM1105_I2CDAT)); outb(0xf7, dm_io_mem(DM1105_I2CDAT + 1)); for (byte = 0; byte < (len > 48 ? 48 : len); byte++) { data = msgs[i].buf[k+byte]; outb(data, dm_io_mem(DM1105_I2CDAT + byte + 2)); } outb(0x82 + (len > 48 ? 48 : len), dm_io_mem(DM1105_I2CCTR)); for (j = 0; j < 25; j++) { mdelay(10); status = inb(dm_io_mem(DM1105_I2CSTS)); if ((status & 0xc0) == 0x40) break; } if (j >= 25) return -1; k += 48; len -= 48; } while (len > 0); } else { /* write bytes */ outb(msgs[i].addr<<1, dm_io_mem(DM1105_I2CDAT)); for (byte = 0; byte < msgs[i].len; byte++) { data = msgs[i].buf[byte]; outb(data, dm_io_mem(DM1105_I2CDAT + byte + 1)); } outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR)); for (j = 0; j < 25; j++) { mdelay(10); status = inb(dm_io_mem(DM1105_I2CSTS)); if ((status & 0xc0) == 0x40) break; } if (j >= 25) return -1; } } } return num; err: return rc;}static u32 functionality(struct i2c_adapter *adap){ return I2C_FUNC_I2C;}static struct i2c_algorithm dm1105_algo = { .master_xfer = dm1105_i2c_xfer, .functionality = functionality,};static inline struct dm1105dvb *feed_to_dm1105dvb(struct dvb_demux_feed *feed){ return container_of(feed->demux, struct dm1105dvb, demux);}static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe){ return container_of(fe->dvb, struct dm1105dvb, dvb_adapter);}static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage){ struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe); if (voltage == SEC_VOLTAGE_18) { outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR)); outl(DM1105_LNB_18V, dm_io_mem(DM1105_GPIOVAL)); } else { /*LNB ON-13V by default!*/ outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR)); outl(DM1105_LNB_13V, dm_io_mem(DM1105_GPIOVAL)); } return 0;}static void dm1105dvb_set_dma_addr(struct dm1105dvb *dm1105dvb){ outl(cpu_to_le32(dm1105dvb->dma_addr), dm_io_mem(DM1105_STADR));}static int __devinit dm1105dvb_dma_map(struct dm1105dvb *dm1105dvb){ dm1105dvb->ts_buf = pci_alloc_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, &dm1105dvb->dma_addr);#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) return pci_dma_mapping_error(dm1105dvb->dma_addr);#else return pci_dma_mapping_error(dm1105dvb->pdev, dm1105dvb->dma_addr);#endif}static void dm1105dvb_dma_unmap(struct dm1105dvb *dm1105dvb){ pci_free_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, dm1105dvb->ts_buf, dm1105dvb->dma_addr);}static void __devinit dm1105dvb_enable_irqs(struct dm1105dvb *dm1105dvb){ outb(INTMAK_ALLMASK, dm_io_mem(DM1105_INTMAK)); outb(1, dm_io_mem(DM1105_CR));}static void dm1105dvb_disable_irqs(struct dm1105dvb *dm1105dvb){ outb(INTMAK_IRM, dm_io_mem(DM1105_INTMAK)); outb(0, dm_io_mem(DM1105_CR));}static int dm1105dvb_start_feed(struct dvb_demux_feed *f){ struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f); if (dm1105dvb->full_ts_users++ == 0) dm1105dvb_enable_irqs(dm1105dvb); return 0;}static int dm1105dvb_stop_feed(struct dvb_demux_feed *f){ struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f); if (--dm1105dvb->full_ts_users == 0) dm1105dvb_disable_irqs(dm1105dvb); return 0;}/* ir tasklet */static void dm1105_emit_key(unsigned long parm){ struct infrared *ir = (struct infrared *) parm; u32 ircom = ir->ir_command; u8 data; u16 keycode; data = (ircom >> 8) & 0x7f; input_event(ir->input_dev, EV_MSC, MSC_RAW, (0x0000f8 << 16) | data); input_event(ir->input_dev, EV_MSC, MSC_SCAN, data); keycode = ir->key_map[data]; if (!keycode) return; input_event(ir->input_dev, EV_KEY, keycode, 1); input_sync(ir->input_dev); input_event(ir->input_dev, EV_KEY, keycode, 0); input_sync(ir->input_dev);}#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)static irqreturn_t dm1105dvb_irq(int irq, void *dev_id, struct pt_regs *regs)#elsestatic irqreturn_t dm1105dvb_irq(int irq, void *dev_id)#endif{ struct dm1105dvb *dm1105dvb = dev_id; unsigned int piece; unsigned int nbpackets; u32 command; u32 nextwrp; u32 oldwrp; /* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */ unsigned int intsts = inb(dm_io_mem(DM1105_INTSTS)); outb(intsts, dm_io_mem(DM1105_INTSTS)); switch (intsts) { case INTSTS_TSIRQ: case (INTSTS_TSIRQ | INTSTS_IR): nextwrp = inl(dm_io_mem(DM1105_WRP)) - inl(dm_io_mem(DM1105_STADR)) ; oldwrp = dm1105dvb->wrp; spin_lock(&dm1105dvb->lock); if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) && (dm1105dvb->ts_buf[oldwrp + 188] == 0x47) && (dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) { dm1105dvb->PacketErrorCount++; /* bad packet found */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -