📄 diva.c
字号:
/* $Id: diva.c,v 1.25.6.5 2001/09/23 22:24:47 kai Exp $ * * low level stuff for Eicon.Diehl Diva Family ISDN cards * * Author Karsten Keil * Copyright by Karsten Keil <keil@isdn4linux.de> * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * * For changes and modifications please read * ../../../Documentation/isdn/HiSax.cert * * Thanks to Eicon Technology for documents and information * */#define __NO_VERSION__#include <linux/init.h>#include <linux/config.h>#include "hisax.h"#include "isac.h"#include "hscx.h"#include "ipac.h"#include "isdnl1.h"#include <linux/pci.h>extern const char *CardType[];const char *Diva_revision = "$Revision: 1.25.6.5 $";#define byteout(addr,val) outb(val,addr)#define bytein(addr) inb(addr)#define DIVA_HSCX_DATA 0#define DIVA_HSCX_ADR 4#define DIVA_ISA_ISAC_DATA 2#define DIVA_ISA_ISAC_ADR 6#define DIVA_ISA_CTRL 7#define DIVA_IPAC_ADR 0#define DIVA_IPAC_DATA 1#define DIVA_PCI_ISAC_DATA 8#define DIVA_PCI_ISAC_ADR 0xc#define DIVA_PCI_CTRL 0x10/* SUB Types */#define DIVA_ISA 1#define DIVA_PCI 2#define DIVA_IPAC_ISA 3#define DIVA_IPAC_PCI 4/* CTRL (Read) */#define DIVA_IRQ_STAT 0x01#define DIVA_EEPROM_SDA 0x02/* CTRL (Write) */#define DIVA_IRQ_REQ 0x01#define DIVA_RESET 0x08#define DIVA_EEPROM_CLK 0x40#define DIVA_PCI_LED_A 0x10#define DIVA_PCI_LED_B 0x20#define DIVA_ISA_LED_A 0x20#define DIVA_ISA_LED_B 0x40#define DIVA_IRQ_CLR 0x80/* Siemens PITA */#define PITA_MISC_REG 0x1c#ifdef __BIG_ENDIAN#define PITA_PARA_SOFTRESET 0x00000001#define PITA_PARA_MPX_MODE 0x00000004#define PITA_INT0_ENABLE 0x00000200#else#define PITA_PARA_SOFTRESET 0x01000000#define PITA_PARA_MPX_MODE 0x04000000#define PITA_INT0_ENABLE 0x00020000#endif#define PITA_INT0_STATUS 0x02static inline u_charreadreg(unsigned int ale, unsigned int adr, u_char off){ register u_char ret; long flags; save_flags(flags); cli(); byteout(ale, off); ret = bytein(adr); restore_flags(flags); return (ret);}static inline voidreadfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size){ /* fifo read without cli because it's allready done */ byteout(ale, off); insb(adr, data, size);}static inline voidwritereg(unsigned int ale, unsigned int adr, u_char off, u_char data){ long flags; save_flags(flags); cli(); byteout(ale, off); byteout(adr, data); restore_flags(flags);}static inline voidwritefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size){ /* fifo write without cli because it's allready done */ byteout(ale, off); outsb(adr, data, size);}static inline u_charmemreadreg(unsigned long adr, u_char off){ return(*((unsigned char *) (((unsigned int *)adr) + off)));}static inline voidmemwritereg(unsigned long adr, u_char off, u_char data){ register u_char *p; p = (unsigned char *)(((unsigned int *)adr) + off); *p = data;}/* Interface functions */static u_charReadISAC(struct IsdnCardState *cs, u_char offset){ return(readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset));}static voidWriteISAC(struct IsdnCardState *cs, u_char offset, u_char value){ writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset, value);}static voidReadISACfifo(struct IsdnCardState *cs, u_char *data, int size){ readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size);}static voidWriteISACfifo(struct IsdnCardState *cs, u_char *data, int size){ writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size);}static u_charReadISAC_IPAC(struct IsdnCardState *cs, u_char offset){ return (readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset+0x80));}static voidWriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value){ writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset|0x80, value);}static voidReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size){ readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, data, size);}static voidWriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size){ writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, data, size);}static u_charReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset){ return(readreg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0)));}static voidWriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value){ writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0), value);}static u_charMemReadISAC_IPAC(struct IsdnCardState *cs, u_char offset){ return (memreadreg(cs->hw.diva.cfg_reg, offset+0x80));}static voidMemWriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value){ memwritereg(cs->hw.diva.cfg_reg, offset|0x80, value);}static voidMemReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size){ while(size--) *data++ = memreadreg(cs->hw.diva.cfg_reg, 0x80);}static voidMemWriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size){ while(size--) memwritereg(cs->hw.diva.cfg_reg, 0x80, *data++);}static u_charMemReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset){ return(memreadreg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0)));}static voidMemWriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value){ memwritereg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0), value);}/* * fast interrupt HSCX stuff goes here */#define READHSCX(cs, nr, reg) readreg(cs->hw.diva.hscx_adr, \ cs->hw.diva.hscx, reg + (nr ? 0x40 : 0))#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.diva.hscx_adr, \ cs->hw.diva.hscx, reg + (nr ? 0x40 : 0), data)#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.diva.hscx_adr, \ cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt)#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.diva.hscx_adr, \ cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt)#include "hscx_irq.c"static voiddiva_interrupt(int intno, void *dev_id, struct pt_regs *regs){ struct IsdnCardState *cs = dev_id; u_char val, sval; int cnt=5; if (!cs) { printk(KERN_WARNING "Diva: Spurious interrupt!\n"); return; } while (((sval = bytein(cs->hw.diva.ctrl)) & DIVA_IRQ_REQ) && cnt) { val = readreg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_ISTA + 0x40); if (val) hscx_int_main(cs, val); val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA); if (val) isac_interrupt(cs, val); cnt--; } if (!cnt) printk(KERN_WARNING "Diva: IRQ LOOP\n"); writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0xFF); writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0xFF); writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0xFF); writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0x0); writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0x0); writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0x0);}static voiddiva_irq_ipac_isa(int intno, void *dev_id, struct pt_regs *regs){ struct IsdnCardState *cs = dev_id; u_char ista,val; int icnt=5; if (!cs) { printk(KERN_WARNING "Diva: Spurious interrupt!\n"); return; } ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA);Start_IPACISA: if (cs->debug & L1_DEB_IPAC) debugl1(cs, "IPAC ISTA %02X", ista); if (ista & 0x0f) { val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, HSCX_ISTA + 0x40); if (ista & 0x01) val |= 0x01; if (ista & 0x04) val |= 0x02; if (ista & 0x08) val |= 0x04; if (val) hscx_int_main(cs, val); } if (ista & 0x20) { val = 0xfe & readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA + 0x80); if (val) { isac_interrupt(cs, val); } } if (ista & 0x10) { val = 0x01; isac_interrupt(cs, val); } ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA); if ((ista & 0x3f) && icnt) { icnt--; goto Start_IPACISA; } if (!icnt) printk(KERN_WARNING "DIVA IPAC IRQ LOOP\n"); writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xFF); writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xC0);}static inline voidMemwaitforCEC(struct IsdnCardState *cs, int hscx){ int to = 50; while ((MemReadHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) { udelay(1); to--; } if (!to) printk(KERN_WARNING "HiSax: waitforCEC timeout\n");}static inline voidMemwaitforXFW(struct IsdnCardState *cs, int hscx){ int to = 50; while ((!(MemReadHSCX(cs, hscx, HSCX_STAR) & 0x44) == 0x40) && to) { udelay(1); to--; } if (!to) printk(KERN_WARNING "HiSax: waitforXFW timeout\n");}static inline voidMemWriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data){ long flags; save_flags(flags); cli(); MemwaitforCEC(cs, hscx); MemWriteHSCX(cs, hscx, HSCX_CMDR, data); restore_flags(flags);}static voidMemhscx_empty_fifo(struct BCState *bcs, int count){ u_char *ptr; struct IsdnCardState *cs = bcs->cs; long flags; int cnt; if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) debugl1(cs, "hscx_empty_fifo"); if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "hscx_empty_fifo: incoming packet too large"); MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); bcs->hw.hscx.rcvidx = 0; return; } save_flags(flags); cli(); ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; cnt = count; while (cnt--) *ptr++ = memreadreg(cs->hw.diva.cfg_reg, bcs->hw.hscx.hscx ? 0x40 : 0); MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; bcs->hw.hscx.rcvidx += count; restore_flags(flags); if (cs->debug & L1_DEB_HSCX_FIFO) { char *t = bcs->blog; t += sprintf(t, "hscx_empty_fifo %c cnt %d", bcs->hw.hscx.hscx ? 'B' : 'A', count); QuickHex(t, ptr, count); debugl1(cs, bcs->blog); }}static voidMemhscx_fill_fifo(struct BCState *bcs){ struct IsdnCardState *cs = bcs->cs; int more, count, cnt; int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32; u_char *ptr,*p; long flags; if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) debugl1(cs, "hscx_fill_fifo"); if (!bcs->tx_skb) return; if (bcs->tx_skb->len <= 0) return; more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; if (bcs->tx_skb->len > fifo_size) { more = !0; count = fifo_size; } else count = bcs->tx_skb->len; cnt = count; MemwaitforXFW(cs, bcs->hw.hscx.hscx); save_flags(flags); cli(); p = ptr = bcs->tx_skb->data; skb_pull(bcs->tx_skb, count); bcs->tx_cnt -= count; bcs->hw.hscx.count += count; while(cnt--) memwritereg(cs->hw.diva.cfg_reg, bcs->hw.hscx.hscx ? 0x40 : 0, *p++); MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa); restore_flags(flags); if (cs->debug & L1_DEB_HSCX_FIFO) { char *t = bcs->blog; t += sprintf(t, "hscx_fill_fifo %c cnt %d", bcs->hw.hscx.hscx ? 'B' : 'A', count); QuickHex(t, ptr, count); debugl1(cs, bcs->blog); }}static inline voidMemhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx){ u_char r; struct BCState *bcs = cs->bcs + hscx; struct sk_buff *skb; int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32; int count; if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return; if (val & 0x80) { /* RME */ r = MemReadHSCX(cs, hscx, HSCX_RSTA); if ((r & 0xf0) != 0xa0) { if (!(r & 0x80)) if (cs->debug & L1_DEB_WARN) debugl1(cs, "HSCX invalid frame"); if ((r & 0x40) && bcs->mode) if (cs->debug & L1_DEB_WARN) debugl1(cs, "HSCX RDO mode=%d", bcs->mode); if (!(r & 0x20)) if (cs->debug & L1_DEB_WARN) debugl1(cs, "HSCX CRC error"); MemWriteHSCXCMDR(cs, hscx, 0x80); } else { count = MemReadHSCX(cs, hscx, HSCX_RBCL) & ( test_bit(HW_IPAC, &cs->HW_Flags)? 0x3f: 0x1f); if (count == 0) count = fifo_size; Memhscx_empty_fifo(bcs, count); if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { if (cs->debug & L1_DEB_HSCX_FIFO) debugl1(cs, "HX Frame %d", count); if (!(skb = dev_alloc_skb(count))) printk(KERN_WARNING "HSCX: receive out of memory\n"); else { memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count); skb_queue_tail(&bcs->rqueue, skb); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -