1/* $Id: mic.c,v 1.1.1.1 2007/08/03 18:52:35 Exp $ 2 * 3 * low level stuff for mic cards 4 * 5 * Author Stephan von Krawczynski 6 * Copyright by Stephan von Krawczynski <skraw@ithnet.com> 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 19extern const char *CardType[]; 20 21static const char *mic_revision = "$Revision: 1.1.1.1 $"; 22 23#define byteout(addr,val) outb(val,addr) 24#define bytein(addr) inb(addr) 25 26#define MIC_ISAC 2 27#define MIC_HSCX 1 28#define MIC_ADR 7 29 30/* CARD_ADR (Write) */ 31#define MIC_RESET 0x3 /* same as DOS driver */ 32 33static inline u_char 34readreg(unsigned int ale, unsigned int adr, u_char off) 35{ 36 register u_char ret; 37 38 byteout(ale, off); 39 ret = bytein(adr); 40 return (ret); 41} 42 43static inline void 44readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) 45{ 46 byteout(ale, off); 47 insb(adr, data, size); 48} 49 50 51static inline void 52writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) 53{ 54 byteout(ale, off); 55 byteout(adr, data); 56} 57 58static inline void 59writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) 60{ 61 byteout(ale, off); 62 outsb(adr, data, size); 63} 64 65/* Interface functions */ 66 67static u_char 68ReadISAC(struct IsdnCardState *cs, u_char offset) 69{ 70 return (readreg(cs->hw.mic.adr, cs->hw.mic.isac, offset)); 71} 72 73static void 74WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) 75{ 76 writereg(cs->hw.mic.adr, cs->hw.mic.isac, offset, value); 77} 78 79static void 80ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) 81{ 82 readfifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size); 83} 84 85static void 86WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) 87{ 88 writefifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size); 89} 90 91static u_char 92ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) 93{ 94 return (readreg(cs->hw.mic.adr, 95 cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0))); 96} 97 98static void 99WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) 100{ 101 writereg(cs->hw.mic.adr, 102 cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0), value); 103} 104 105/* 106 * fast interrupt HSCX stuff goes here 107 */ 108 109#define READHSCX(cs, nr, reg) readreg(cs->hw.mic.adr, \ 110 cs->hw.mic.hscx, reg + (nr ? 0x40 : 0)) 111#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.mic.adr, \ 112 cs->hw.mic.hscx, reg + (nr ? 0x40 : 0), data) 113 114#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.mic.adr, \ 115 cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt) 116 117#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.mic.adr, \ 118 cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt) 119 120#include "hscx_irq.c" 121 122static irqreturn_t 123mic_interrupt(int intno, void *dev_id) 124{ 125 struct IsdnCardState *cs = dev_id; 126 u_char val; 127 u_long flags; 128 129 spin_lock_irqsave(&cs->lock, flags); 130 val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40); 131 Start_HSCX: 132 if (val) 133 hscx_int_main(cs, val); 134 val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA); 135 Start_ISAC: 136 if (val) 137 isac_interrupt(cs, val); 138 val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40); 139 if (val) { 140 if (cs->debug & L1_DEB_HSCX) 141 debugl1(cs, "HSCX IntStat after IntRoutine"); 142 goto Start_HSCX; 143 } 144 val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA); 145 if (val) { 146 if (cs->debug & L1_DEB_ISAC) 147 debugl1(cs, "ISAC IntStat after IntRoutine"); 148 goto Start_ISAC; 149 } 150 writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0xFF); 151 writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0xFF); 152 writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0xFF); 153 writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0x0); 154 writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0x0); 155 writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0x0); 156 spin_unlock_irqrestore(&cs->lock, flags); 157 return IRQ_HANDLED; 158} 159 160static void 161release_io_mic(struct IsdnCardState *cs) 162{ 163 int bytecnt = 8; 164 165 if (cs->hw.mic.cfg_reg) 166 release_region(cs->hw.mic.cfg_reg, bytecnt); 167} 168 169static int 170mic_card_msg(struct IsdnCardState *cs, int mt, void *arg) 171{ 172 u_long flags; 173 174 switch (mt) { 175 case CARD_RESET: 176 return(0); 177 case CARD_RELEASE: 178 release_io_mic(cs); 179 return(0); 180 case CARD_INIT: 181 spin_lock_irqsave(&cs->lock, flags); 182 inithscx(cs); /* /RTSA := ISAC RST */ 183 inithscxisac(cs, 3); 184 spin_unlock_irqrestore(&cs->lock, flags); 185 return(0); 186 case CARD_TEST: 187 return(0); 188 } 189 return(0); 190} 191 192int __devinit 193setup_mic(struct IsdnCard *card) 194{ 195 int bytecnt; 196 struct IsdnCardState *cs = card->cs; 197 char tmp[64]; 198 199 strcpy(tmp, mic_revision); 200 printk(KERN_INFO "HiSax: mic driver Rev. %s\n", HiSax_getrev(tmp)); 201 if (cs->typ != ISDN_CTYPE_MIC) 202 return (0); 203 204 bytecnt = 8; 205 cs->hw.mic.cfg_reg = card->para[1]; 206 cs->irq = card->para[0]; 207 cs->hw.mic.adr = cs->hw.mic.cfg_reg + MIC_ADR; 208 cs->hw.mic.isac = cs->hw.mic.cfg_reg + MIC_ISAC; 209 cs->hw.mic.hscx = cs->hw.mic.cfg_reg + MIC_HSCX; 210 211 if (!request_region(cs->hw.mic.cfg_reg, bytecnt, "mic isdn")) { 212 printk(KERN_WARNING 213 "HiSax: %s config port %x-%x already in use\n", 214 CardType[card->typ], 215 cs->hw.mic.cfg_reg, 216 cs->hw.mic.cfg_reg + bytecnt); 217 return (0); 218 } 219 printk(KERN_INFO "mic: defined at 0x%x IRQ %d\n", 220 cs->hw.mic.cfg_reg, cs->irq); 221 setup_isac(cs); 222 cs->readisac = &ReadISAC; 223 cs->writeisac = &WriteISAC; 224 cs->readisacfifo = &ReadISACfifo; 225 cs->writeisacfifo = &WriteISACfifo; 226 cs->BC_Read_Reg = &ReadHSCX; 227 cs->BC_Write_Reg = &WriteHSCX; 228 cs->BC_Send_Data = &hscx_fill_fifo; 229 cs->cardmsg = &mic_card_msg; 230 cs->irq_func = &mic_interrupt; 231 ISACVersion(cs, "mic:"); 232 if (HscxVersion(cs, "mic:")) { 233 printk(KERN_WARNING 234 "mic: wrong HSCX versions check IO address\n"); 235 release_io_mic(cs); 236 return (0); 237 } 238 return (1); 239} 240