1/* $Id: mic.c,v 1.12.2.4 2004/01/13 23:48:39 keil 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); 129Start_HSCX: 130 if (val) 131 hscx_int_main(cs, val); 132 val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA); 133Start_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 setup_mic(struct IsdnCard *card) 191{ 192 int bytecnt; 193 struct IsdnCardState *cs = card->cs; 194 char tmp[64]; 195 196 strcpy(tmp, mic_revision); 197 printk(KERN_INFO "HiSax: mic driver Rev. %s\n", HiSax_getrev(tmp)); 198 if (cs->typ != ISDN_CTYPE_MIC) 199 return (0); 200 201 bytecnt = 8; 202 cs->hw.mic.cfg_reg = card->para[1]; 203 cs->irq = card->para[0]; 204 cs->hw.mic.adr = cs->hw.mic.cfg_reg + MIC_ADR; 205 cs->hw.mic.isac = cs->hw.mic.cfg_reg + MIC_ISAC; 206 cs->hw.mic.hscx = cs->hw.mic.cfg_reg + MIC_HSCX; 207 208 if (!request_region(cs->hw.mic.cfg_reg, bytecnt, "mic isdn")) { 209 printk(KERN_WARNING 210 "HiSax: ith mic config port %x-%x already in use\n", 211 cs->hw.mic.cfg_reg, 212 cs->hw.mic.cfg_reg + bytecnt); 213 return (0); 214 } 215 printk(KERN_INFO "mic: defined at 0x%x IRQ %d\n", 216 cs->hw.mic.cfg_reg, cs->irq); 217 setup_isac(cs); 218 cs->readisac = &ReadISAC; 219 cs->writeisac = &WriteISAC; 220 cs->readisacfifo = &ReadISACfifo; 221 cs->writeisacfifo = &WriteISACfifo; 222 cs->BC_Read_Reg = &ReadHSCX; 223 cs->BC_Write_Reg = &WriteHSCX; 224 cs->BC_Send_Data = &hscx_fill_fifo; 225 cs->cardmsg = &mic_card_msg; 226 cs->irq_func = &mic_interrupt; 227 ISACVersion(cs, "mic:"); 228 if (HscxVersion(cs, "mic:")) { 229 printk(KERN_WARNING 230 "mic: wrong HSCX versions check IO address\n"); 231 release_io_mic(cs); 232 return (0); 233 } 234 return (1); 235} 236