1/* $Id: s0box.c,v 2.6.2.4 2004/01/13 23:48:39 keil Exp $ 2 * 3 * low level stuff for Creatix S0BOX 4 * 5 * Author Enrik Berkhan 6 * Copyright by Enrik Berkhan <enrik@starfleet.inka.de> 7 * 8 * This software may be used and distributed according to the terms 9 * of the GNU General Public License, incorporated herein by reference. 10 * 11 */ 12 13#include <linux/init.h> 14#include "hisax.h" 15#include "isac.h" 16#include "hscx.h" 17#include "isdnl1.h" 18 19static const char *s0box_revision = "$Revision: 2.6.2.4 $"; 20 21static inline void 22writereg(unsigned int padr, signed int addr, u_char off, u_char val) { 23 outb_p(0x1c, padr + 2); 24 outb_p(0x14, padr + 2); 25 outb_p((addr + off) & 0x7f, padr); 26 outb_p(0x16, padr + 2); 27 outb_p(val, padr); 28 outb_p(0x17, padr + 2); 29 outb_p(0x14, padr + 2); 30 outb_p(0x1c, padr + 2); 31} 32 33static u_char nibtab[] = { 1, 9, 5, 0xd, 3, 0xb, 7, 0xf, 34 0, 0, 0, 0, 0, 0, 0, 0, 35 0, 8, 4, 0xc, 2, 0xa, 6, 0xe }; 36 37static inline u_char 38readreg(unsigned int padr, signed int addr, u_char off) { 39 register u_char n1, n2; 40 41 outb_p(0x1c, padr + 2); 42 outb_p(0x14, padr + 2); 43 outb_p((addr + off) | 0x80, padr); 44 outb_p(0x16, padr + 2); 45 outb_p(0x17, padr + 2); 46 n1 = (inb_p(padr + 1) >> 3) & 0x17; 47 outb_p(0x16, padr + 2); 48 n2 = (inb_p(padr + 1) >> 3) & 0x17; 49 outb_p(0x14, padr + 2); 50 outb_p(0x1c, padr + 2); 51 return nibtab[n1] | (nibtab[n2] << 4); 52} 53 54static inline void 55read_fifo(unsigned int padr, signed int adr, u_char *data, int size) 56{ 57 int i; 58 register u_char n1, n2; 59 60 outb_p(0x1c, padr + 2); 61 outb_p(0x14, padr + 2); 62 outb_p(adr | 0x80, padr); 63 outb_p(0x16, padr + 2); 64 for (i = 0; i < size; i++) { 65 outb_p(0x17, padr + 2); 66 n1 = (inb_p(padr + 1) >> 3) & 0x17; 67 outb_p(0x16, padr + 2); 68 n2 = (inb_p(padr + 1) >> 3) & 0x17; 69 *(data++) = nibtab[n1] | (nibtab[n2] << 4); 70 } 71 outb_p(0x14, padr + 2); 72 outb_p(0x1c, padr + 2); 73 return; 74} 75 76static inline void 77write_fifo(unsigned int padr, signed int adr, u_char *data, int size) 78{ 79 int i; 80 outb_p(0x1c, padr + 2); 81 outb_p(0x14, padr + 2); 82 outb_p(adr & 0x7f, padr); 83 for (i = 0; i < size; i++) { 84 outb_p(0x16, padr + 2); 85 outb_p(*(data++), padr); 86 outb_p(0x17, padr + 2); 87 } 88 outb_p(0x14, padr + 2); 89 outb_p(0x1c, padr + 2); 90 return; 91} 92 93/* Interface functions */ 94 95static u_char 96ReadISAC(struct IsdnCardState *cs, u_char offset) 97{ 98 return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset)); 99} 100 101static void 102WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) 103{ 104 writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset, value); 105} 106 107static void 108ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) 109{ 110 read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size); 111} 112 113static void 114WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) 115{ 116 write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size); 117} 118 119static u_char 120ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) 121{ 122 return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset)); 123} 124 125static void 126WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) 127{ 128 writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset, value); 129} 130 131/* 132 * fast interrupt HSCX stuff goes here 133 */ 134 135#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg) 136#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg, data) 137#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt) 138#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt) 139 140#include "hscx_irq.c" 141 142static irqreturn_t 143s0box_interrupt(int intno, void *dev_id) 144{ 145#define MAXCOUNT 5 146 struct IsdnCardState *cs = dev_id; 147 u_char val; 148 u_long flags; 149 int count = 0; 150 151 spin_lock_irqsave(&cs->lock, flags); 152 val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA); 153Start_HSCX: 154 if (val) 155 hscx_int_main(cs, val); 156 val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA); 157Start_ISAC: 158 if (val) 159 isac_interrupt(cs, val); 160 count++; 161 val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA); 162 if (val && count < MAXCOUNT) { 163 if (cs->debug & L1_DEB_HSCX) 164 debugl1(cs, "HSCX IntStat after IntRoutine"); 165 goto Start_HSCX; 166 } 167 val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA); 168 if (val && count < MAXCOUNT) { 169 if (cs->debug & L1_DEB_ISAC) 170 debugl1(cs, "ISAC IntStat after IntRoutine"); 171 goto Start_ISAC; 172 } 173 if (count >= MAXCOUNT) 174 printk(KERN_WARNING "S0Box: more than %d loops in s0box_interrupt\n", count); 175 writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF); 176 writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF); 177 writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0xFF); 178 writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0x0); 179 writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0x0); 180 writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0x0); 181 spin_unlock_irqrestore(&cs->lock, flags); 182 return IRQ_HANDLED; 183} 184 185static void 186release_io_s0box(struct IsdnCardState *cs) 187{ 188 release_region(cs->hw.teles3.cfg_reg, 8); 189} 190 191static int 192S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg) 193{ 194 u_long flags; 195 196 switch (mt) { 197 case CARD_RESET: 198 break; 199 case CARD_RELEASE: 200 release_io_s0box(cs); 201 break; 202 case CARD_INIT: 203 spin_lock_irqsave(&cs->lock, flags); 204 inithscxisac(cs, 3); 205 spin_unlock_irqrestore(&cs->lock, flags); 206 break; 207 case CARD_TEST: 208 break; 209 } 210 return (0); 211} 212 213int setup_s0box(struct IsdnCard *card) 214{ 215 struct IsdnCardState *cs = card->cs; 216 char tmp[64]; 217 218 strcpy(tmp, s0box_revision); 219 printk(KERN_INFO "HiSax: S0Box IO driver Rev. %s\n", HiSax_getrev(tmp)); 220 if (cs->typ != ISDN_CTYPE_S0BOX) 221 return (0); 222 223 cs->hw.teles3.cfg_reg = card->para[1]; 224 cs->hw.teles3.hscx[0] = -0x20; 225 cs->hw.teles3.hscx[1] = 0x0; 226 cs->hw.teles3.isac = 0x20; 227 cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e; 228 cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e; 229 cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e; 230 cs->irq = card->para[0]; 231 if (!request_region(cs->hw.teles3.cfg_reg, 8, "S0Box parallel I/O")) { 232 printk(KERN_WARNING "HiSax: S0Box ports %x-%x already in use\n", 233 cs->hw.teles3.cfg_reg, 234 cs->hw.teles3.cfg_reg + 7); 235 return 0; 236 } 237 printk(KERN_INFO "HiSax: S0Box config irq:%d isac:0x%x cfg:0x%x\n", 238 cs->irq, 239 cs->hw.teles3.isac, cs->hw.teles3.cfg_reg); 240 printk(KERN_INFO "HiSax: hscx A:0x%x hscx B:0x%x\n", 241 cs->hw.teles3.hscx[0], cs->hw.teles3.hscx[1]); 242 setup_isac(cs); 243 cs->readisac = &ReadISAC; 244 cs->writeisac = &WriteISAC; 245 cs->readisacfifo = &ReadISACfifo; 246 cs->writeisacfifo = &WriteISACfifo; 247 cs->BC_Read_Reg = &ReadHSCX; 248 cs->BC_Write_Reg = &WriteHSCX; 249 cs->BC_Send_Data = &hscx_fill_fifo; 250 cs->cardmsg = &S0Box_card_msg; 251 cs->irq_func = &s0box_interrupt; 252 ISACVersion(cs, "S0Box:"); 253 if (HscxVersion(cs, "S0Box:")) { 254 printk(KERN_WARNING 255 "S0Box: wrong HSCX versions check IO address\n"); 256 release_io_s0box(cs); 257 return (0); 258 } 259 return (1); 260} 261