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