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