1/* $Id: avm_a1.c,v 1.1.1.1 2007/08/03 18:52:35 Exp $ 2 * 3 * low level stuff for AVM A1 (Fritz) isdn cards 4 * 5 * Author Karsten Keil 6 * Copyright by Karsten Keil <keil@isdn4linux.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 19extern const char *CardType[]; 20static const char *avm_revision = "$Revision: 1.1.1.1 $"; 21 22#define AVM_A1_STAT_ISAC 0x01 23#define AVM_A1_STAT_HSCX 0x02 24#define AVM_A1_STAT_TIMER 0x04 25 26#define byteout(addr,val) outb(val,addr) 27#define bytein(addr) inb(addr) 28 29static inline u_char 30readreg(unsigned int adr, u_char off) 31{ 32 return (bytein(adr + off)); 33} 34 35static inline void 36writereg(unsigned int adr, u_char off, u_char data) 37{ 38 byteout(adr + off, data); 39} 40 41 42static inline void 43read_fifo(unsigned int adr, u_char * data, int size) 44{ 45 insb(adr, data, size); 46} 47 48static void 49write_fifo(unsigned int adr, u_char * data, int size) 50{ 51 outsb(adr, data, size); 52} 53 54/* Interface functions */ 55 56static u_char 57ReadISAC(struct IsdnCardState *cs, u_char offset) 58{ 59 return (readreg(cs->hw.avm.isac, offset)); 60} 61 62static void 63WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) 64{ 65 writereg(cs->hw.avm.isac, offset, value); 66} 67 68static void 69ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) 70{ 71 read_fifo(cs->hw.avm.isacfifo, data, size); 72} 73 74static void 75WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) 76{ 77 write_fifo(cs->hw.avm.isacfifo, data, size); 78} 79 80static u_char 81ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) 82{ 83 return (readreg(cs->hw.avm.hscx[hscx], offset)); 84} 85 86static void 87WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) 88{ 89 writereg(cs->hw.avm.hscx[hscx], offset, value); 90} 91 92/* 93 * fast interrupt HSCX stuff goes here 94 */ 95 96#define READHSCX(cs, nr, reg) readreg(cs->hw.avm.hscx[nr], reg) 97#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.avm.hscx[nr], reg, data) 98#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt) 99#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt) 100 101#include "hscx_irq.c" 102 103static irqreturn_t 104avm_a1_interrupt(int intno, void *dev_id) 105{ 106 struct IsdnCardState *cs = dev_id; 107 u_char val, sval; 108 u_long flags; 109 110 spin_lock_irqsave(&cs->lock, flags); 111 while (((sval = bytein(cs->hw.avm.cfg_reg)) & 0xf) != 0x7) { 112 if (!(sval & AVM_A1_STAT_TIMER)) { 113 byteout(cs->hw.avm.cfg_reg, 0x1E); 114 sval = bytein(cs->hw.avm.cfg_reg); 115 } else if (cs->debug & L1_DEB_INTSTAT) 116 debugl1(cs, "avm IntStatus %x", sval); 117 if (!(sval & AVM_A1_STAT_HSCX)) { 118 val = readreg(cs->hw.avm.hscx[1], HSCX_ISTA); 119 if (val) 120 hscx_int_main(cs, val); 121 } 122 if (!(sval & AVM_A1_STAT_ISAC)) { 123 val = readreg(cs->hw.avm.isac, ISAC_ISTA); 124 if (val) 125 isac_interrupt(cs, val); 126 } 127 } 128 writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0xFF); 129 writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0xFF); 130 writereg(cs->hw.avm.isac, ISAC_MASK, 0xFF); 131 writereg(cs->hw.avm.isac, ISAC_MASK, 0x0); 132 writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0x0); 133 writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0x0); 134 spin_unlock_irqrestore(&cs->lock, flags); 135 return IRQ_HANDLED; 136} 137 138static inline void 139release_ioregs(struct IsdnCardState *cs, int mask) 140{ 141 release_region(cs->hw.avm.cfg_reg, 8); 142 if (mask & 1) 143 release_region(cs->hw.avm.isac + 32, 32); 144 if (mask & 2) 145 release_region(cs->hw.avm.isacfifo, 1); 146 if (mask & 4) 147 release_region(cs->hw.avm.hscx[0] + 32, 32); 148 if (mask & 8) 149 release_region(cs->hw.avm.hscxfifo[0], 1); 150 if (mask & 0x10) 151 release_region(cs->hw.avm.hscx[1] + 32, 32); 152 if (mask & 0x20) 153 release_region(cs->hw.avm.hscxfifo[1], 1); 154} 155 156static int 157AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) 158{ 159 u_long flags; 160 161 switch (mt) { 162 case CARD_RESET: 163 return(0); 164 case CARD_RELEASE: 165 release_ioregs(cs, 0x3f); 166 return(0); 167 case CARD_INIT: 168 spin_lock_irqsave(&cs->lock, flags); 169 inithscxisac(cs, 1); 170 byteout(cs->hw.avm.cfg_reg, 0x16); 171 byteout(cs->hw.avm.cfg_reg, 0x1E); 172 inithscxisac(cs, 2); 173 spin_unlock_irqrestore(&cs->lock, flags); 174 return(0); 175 case CARD_TEST: 176 return(0); 177 } 178 return(0); 179} 180 181int __devinit 182setup_avm_a1(struct IsdnCard *card) 183{ 184 u_char val; 185 struct IsdnCardState *cs = card->cs; 186 char tmp[64]; 187 188 strcpy(tmp, avm_revision); 189 printk(KERN_INFO "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp)); 190 if (cs->typ != ISDN_CTYPE_A1) 191 return (0); 192 193 cs->hw.avm.cfg_reg = card->para[1] + 0x1800; 194 cs->hw.avm.isac = card->para[1] + 0x1400 - 0x20; 195 cs->hw.avm.hscx[0] = card->para[1] + 0x400 - 0x20; 196 cs->hw.avm.hscx[1] = card->para[1] + 0xc00 - 0x20; 197 cs->hw.avm.isacfifo = card->para[1] + 0x1000; 198 cs->hw.avm.hscxfifo[0] = card->para[1]; 199 cs->hw.avm.hscxfifo[1] = card->para[1] + 0x800; 200 cs->irq = card->para[0]; 201 if (!request_region(cs->hw.avm.cfg_reg, 8, "avm cfg")) { 202 printk(KERN_WARNING 203 "HiSax: %s config port %x-%x already in use\n", 204 CardType[card->typ], 205 cs->hw.avm.cfg_reg, 206 cs->hw.avm.cfg_reg + 8); 207 return (0); 208 } 209 if (!request_region(cs->hw.avm.isac + 32, 32, "HiSax isac")) { 210 printk(KERN_WARNING 211 "HiSax: %s isac ports %x-%x already in use\n", 212 CardType[cs->typ], 213 cs->hw.avm.isac + 32, 214 cs->hw.avm.isac + 64); 215 release_ioregs(cs, 0); 216 return (0); 217 } 218 if (!request_region(cs->hw.avm.isacfifo, 1, "HiSax isac fifo")) { 219 printk(KERN_WARNING 220 "HiSax: %s isac fifo port %x already in use\n", 221 CardType[cs->typ], 222 cs->hw.avm.isacfifo); 223 release_ioregs(cs, 1); 224 return (0); 225 } 226 if (!request_region(cs->hw.avm.hscx[0] + 32, 32, "HiSax hscx A")) { 227 printk(KERN_WARNING 228 "HiSax: %s hscx A ports %x-%x already in use\n", 229 CardType[cs->typ], 230 cs->hw.avm.hscx[0] + 32, 231 cs->hw.avm.hscx[0] + 64); 232 release_ioregs(cs, 3); 233 return (0); 234 } 235 if (!request_region(cs->hw.avm.hscxfifo[0], 1, "HiSax hscx A fifo")) { 236 printk(KERN_WARNING 237 "HiSax: %s hscx A fifo port %x already in use\n", 238 CardType[cs->typ], 239 cs->hw.avm.hscxfifo[0]); 240 release_ioregs(cs, 7); 241 return (0); 242 } 243 if (!request_region(cs->hw.avm.hscx[1] + 32, 32, "HiSax hscx B")) { 244 printk(KERN_WARNING 245 "HiSax: %s hscx B ports %x-%x already in use\n", 246 CardType[cs->typ], 247 cs->hw.avm.hscx[1] + 32, 248 cs->hw.avm.hscx[1] + 64); 249 release_ioregs(cs, 0xf); 250 return (0); 251 } 252 if (!request_region(cs->hw.avm.hscxfifo[1], 1, "HiSax hscx B fifo")) { 253 printk(KERN_WARNING 254 "HiSax: %s hscx B fifo port %x already in use\n", 255 CardType[cs->typ], 256 cs->hw.avm.hscxfifo[1]); 257 release_ioregs(cs, 0x1f); 258 return (0); 259 } 260 byteout(cs->hw.avm.cfg_reg, 0x0); 261 HZDELAY(HZ / 5 + 1); 262 byteout(cs->hw.avm.cfg_reg, 0x1); 263 HZDELAY(HZ / 5 + 1); 264 byteout(cs->hw.avm.cfg_reg, 0x0); 265 HZDELAY(HZ / 5 + 1); 266 val = cs->irq; 267 if (val == 9) 268 val = 2; 269 byteout(cs->hw.avm.cfg_reg + 1, val); 270 HZDELAY(HZ / 5 + 1); 271 byteout(cs->hw.avm.cfg_reg, 0x0); 272 HZDELAY(HZ / 5 + 1); 273 274 val = bytein(cs->hw.avm.cfg_reg); 275 printk(KERN_INFO "AVM A1: Byte at %x is %x\n", 276 cs->hw.avm.cfg_reg, val); 277 val = bytein(cs->hw.avm.cfg_reg + 3); 278 printk(KERN_INFO "AVM A1: Byte at %x is %x\n", 279 cs->hw.avm.cfg_reg + 3, val); 280 val = bytein(cs->hw.avm.cfg_reg + 2); 281 printk(KERN_INFO "AVM A1: Byte at %x is %x\n", 282 cs->hw.avm.cfg_reg + 2, val); 283 val = bytein(cs->hw.avm.cfg_reg); 284 printk(KERN_INFO "AVM A1: Byte at %x is %x\n", 285 cs->hw.avm.cfg_reg, val); 286 287 printk(KERN_INFO 288 "HiSax: %s config irq:%d cfg:0x%X\n", 289 CardType[cs->typ], cs->irq, 290 cs->hw.avm.cfg_reg); 291 printk(KERN_INFO 292 "HiSax: isac:0x%X/0x%X\n", 293 cs->hw.avm.isac + 32, cs->hw.avm.isacfifo); 294 printk(KERN_INFO 295 "HiSax: hscx A:0x%X/0x%X hscx B:0x%X/0x%X\n", 296 cs->hw.avm.hscx[0] + 32, cs->hw.avm.hscxfifo[0], 297 cs->hw.avm.hscx[1] + 32, cs->hw.avm.hscxfifo[1]); 298 299 cs->readisac = &ReadISAC; 300 cs->writeisac = &WriteISAC; 301 cs->readisacfifo = &ReadISACfifo; 302 cs->writeisacfifo = &WriteISACfifo; 303 cs->BC_Read_Reg = &ReadHSCX; 304 cs->BC_Write_Reg = &WriteHSCX; 305 cs->BC_Send_Data = &hscx_fill_fifo; 306 setup_isac(cs); 307 cs->cardmsg = &AVM_card_msg; 308 cs->irq_func = &avm_a1_interrupt; 309 ISACVersion(cs, "AVM A1:"); 310 if (HscxVersion(cs, "AVM A1:")) { 311 printk(KERN_WARNING 312 "AVM A1: wrong HSCX versions check IO address\n"); 313 release_ioregs(cs, 0x3f); 314 return (0); 315 } 316 return (1); 317} 318