1/* $Id: teleint.c,v 1.1.1.1 2007/08/03 18:52:36 Exp $ 2 * 3 * low level stuff for TeleInt 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 "hfc_2bs0.h" 17#include "isdnl1.h" 18 19extern const char *CardType[]; 20 21static const char *TeleInt_revision = "$Revision: 1.1.1.1 $"; 22 23#define byteout(addr,val) outb(val,addr) 24#define bytein(addr) inb(addr) 25 26static inline u_char 27readreg(unsigned int ale, unsigned int adr, u_char off) 28{ 29 register u_char ret; 30 int max_delay = 2000; 31 32 byteout(ale, off); 33 ret = HFC_BUSY & bytein(ale); 34 while (ret && --max_delay) 35 ret = HFC_BUSY & bytein(ale); 36 if (!max_delay) { 37 printk(KERN_WARNING "TeleInt Busy not inactive\n"); 38 return (0); 39 } 40 ret = bytein(adr); 41 return (ret); 42} 43 44static inline void 45readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) 46{ 47 register u_char ret; 48 register int max_delay = 20000; 49 register int i; 50 51 byteout(ale, off); 52 for (i = 0; i<size; i++) { 53 ret = HFC_BUSY & bytein(ale); 54 while (ret && --max_delay) 55 ret = HFC_BUSY & bytein(ale); 56 if (!max_delay) { 57 printk(KERN_WARNING "TeleInt Busy not inactive\n"); 58 return; 59 } 60 data[i] = bytein(adr); 61 } 62} 63 64 65static inline void 66writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) 67{ 68 register u_char ret; 69 int max_delay = 2000; 70 71 byteout(ale, off); 72 ret = HFC_BUSY & bytein(ale); 73 while (ret && --max_delay) 74 ret = HFC_BUSY & bytein(ale); 75 if (!max_delay) { 76 printk(KERN_WARNING "TeleInt Busy not inactive\n"); 77 return; 78 } 79 byteout(adr, data); 80} 81 82static inline void 83writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) 84{ 85 register u_char ret; 86 register int max_delay = 20000; 87 register int i; 88 89 byteout(ale, off); 90 for (i = 0; i<size; i++) { 91 ret = HFC_BUSY & bytein(ale); 92 while (ret && --max_delay) 93 ret = HFC_BUSY & bytein(ale); 94 if (!max_delay) { 95 printk(KERN_WARNING "TeleInt Busy not inactive\n"); 96 return; 97 } 98 byteout(adr, data[i]); 99 } 100} 101 102/* Interface functions */ 103 104static u_char 105ReadISAC(struct IsdnCardState *cs, u_char offset) 106{ 107 cs->hw.hfc.cip = offset; 108 return (readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset)); 109} 110 111static void 112WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) 113{ 114 cs->hw.hfc.cip = offset; 115 writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset, value); 116} 117 118static void 119ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) 120{ 121 cs->hw.hfc.cip = 0; 122 readfifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size); 123} 124 125static void 126WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) 127{ 128 cs->hw.hfc.cip = 0; 129 writefifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size); 130} 131 132static u_char 133ReadHFC(struct IsdnCardState *cs, int data, u_char reg) 134{ 135 register u_char ret; 136 137 if (data) { 138 cs->hw.hfc.cip = reg; 139 byteout(cs->hw.hfc.addr | 1, reg); 140 ret = bytein(cs->hw.hfc.addr); 141 if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) 142 debugl1(cs, "hfc RD %02x %02x", reg, ret); 143 } else 144 ret = bytein(cs->hw.hfc.addr | 1); 145 return (ret); 146} 147 148static void 149WriteHFC(struct IsdnCardState *cs, int data, u_char reg, u_char value) 150{ 151 byteout(cs->hw.hfc.addr | 1, reg); 152 cs->hw.hfc.cip = reg; 153 if (data) 154 byteout(cs->hw.hfc.addr, value); 155 if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) 156 debugl1(cs, "hfc W%c %02x %02x", data ? 'D' : 'C', reg, value); 157} 158 159static irqreturn_t 160TeleInt_interrupt(int intno, void *dev_id) 161{ 162 struct IsdnCardState *cs = dev_id; 163 u_char val; 164 u_long flags; 165 166 spin_lock_irqsave(&cs->lock, flags); 167 val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA); 168 Start_ISAC: 169 if (val) 170 isac_interrupt(cs, val); 171 val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA); 172 if (val) { 173 if (cs->debug & L1_DEB_ISAC) 174 debugl1(cs, "ISAC IntStat after IntRoutine"); 175 goto Start_ISAC; 176 } 177 writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0xFF); 178 writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0x0); 179 spin_unlock_irqrestore(&cs->lock, flags); 180 return IRQ_HANDLED; 181} 182 183static void 184TeleInt_Timer(struct IsdnCardState *cs) 185{ 186 int stat = 0; 187 u_long flags; 188 189 spin_lock_irqsave(&cs->lock, flags); 190 if (cs->bcs[0].mode) { 191 stat |= 1; 192 main_irq_hfc(&cs->bcs[0]); 193 } 194 if (cs->bcs[1].mode) { 195 stat |= 2; 196 main_irq_hfc(&cs->bcs[1]); 197 } 198 spin_unlock_irqrestore(&cs->lock, flags); 199 stat = HZ/100; 200 if (!stat) 201 stat = 1; 202 cs->hw.hfc.timer.expires = jiffies + stat; 203 add_timer(&cs->hw.hfc.timer); 204} 205 206static void 207release_io_TeleInt(struct IsdnCardState *cs) 208{ 209 del_timer(&cs->hw.hfc.timer); 210 releasehfc(cs); 211 if (cs->hw.hfc.addr) 212 release_region(cs->hw.hfc.addr, 2); 213} 214 215static void 216reset_TeleInt(struct IsdnCardState *cs) 217{ 218 printk(KERN_INFO "TeleInt: resetting card\n"); 219 cs->hw.hfc.cirm |= HFC_RESET; 220 byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset On */ 221 mdelay(10); 222 cs->hw.hfc.cirm &= ~HFC_RESET; 223 byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset Off */ 224 mdelay(10); 225} 226 227static int 228TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg) 229{ 230 u_long flags; 231 int delay; 232 233 switch (mt) { 234 case CARD_RESET: 235 spin_lock_irqsave(&cs->lock, flags); 236 reset_TeleInt(cs); 237 spin_unlock_irqrestore(&cs->lock, flags); 238 return(0); 239 case CARD_RELEASE: 240 release_io_TeleInt(cs); 241 return(0); 242 case CARD_INIT: 243 spin_lock_irqsave(&cs->lock, flags); 244 reset_TeleInt(cs); 245 inithfc(cs); 246 clear_pending_isac_ints(cs); 247 initisac(cs); 248 /* Reenable all IRQ */ 249 cs->writeisac(cs, ISAC_MASK, 0); 250 cs->writeisac(cs, ISAC_CMDR, 0x41); 251 spin_unlock_irqrestore(&cs->lock, flags); 252 delay = HZ/100; 253 if (!delay) 254 delay = 1; 255 cs->hw.hfc.timer.expires = jiffies + delay; 256 add_timer(&cs->hw.hfc.timer); 257 return(0); 258 case CARD_TEST: 259 return(0); 260 } 261 return(0); 262} 263 264int __devinit 265setup_TeleInt(struct IsdnCard *card) 266{ 267 struct IsdnCardState *cs = card->cs; 268 char tmp[64]; 269 270 strcpy(tmp, TeleInt_revision); 271 printk(KERN_INFO "HiSax: TeleInt driver Rev. %s\n", HiSax_getrev(tmp)); 272 if (cs->typ != ISDN_CTYPE_TELEINT) 273 return (0); 274 275 cs->hw.hfc.addr = card->para[1] & 0x3fe; 276 cs->irq = card->para[0]; 277 cs->hw.hfc.cirm = HFC_CIRM; 278 cs->hw.hfc.isac_spcr = 0x00; 279 cs->hw.hfc.cip = 0; 280 cs->hw.hfc.ctmt = HFC_CTMT | HFC_CLTIMER; 281 cs->bcs[0].hw.hfc.send = NULL; 282 cs->bcs[1].hw.hfc.send = NULL; 283 cs->hw.hfc.fifosize = 7 * 1024 + 512; 284 cs->hw.hfc.timer.function = (void *) TeleInt_Timer; 285 cs->hw.hfc.timer.data = (long) cs; 286 init_timer(&cs->hw.hfc.timer); 287 if (!request_region(cs->hw.hfc.addr, 2, "TeleInt isdn")) { 288 printk(KERN_WARNING 289 "HiSax: %s config port %x-%x already in use\n", 290 CardType[card->typ], 291 cs->hw.hfc.addr, 292 cs->hw.hfc.addr + 2); 293 return (0); 294 } 295 /* HW IO = IO */ 296 byteout(cs->hw.hfc.addr, cs->hw.hfc.addr & 0xff); 297 byteout(cs->hw.hfc.addr | 1, ((cs->hw.hfc.addr & 0x300) >> 8) | 0x54); 298 switch (cs->irq) { 299 case 3: 300 cs->hw.hfc.cirm |= HFC_INTA; 301 break; 302 case 4: 303 cs->hw.hfc.cirm |= HFC_INTB; 304 break; 305 case 5: 306 cs->hw.hfc.cirm |= HFC_INTC; 307 break; 308 case 7: 309 cs->hw.hfc.cirm |= HFC_INTD; 310 break; 311 case 10: 312 cs->hw.hfc.cirm |= HFC_INTE; 313 break; 314 case 11: 315 cs->hw.hfc.cirm |= HFC_INTF; 316 break; 317 default: 318 printk(KERN_WARNING "TeleInt: wrong IRQ\n"); 319 release_io_TeleInt(cs); 320 return (0); 321 } 322 byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); 323 byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.ctmt); 324 325 printk(KERN_INFO "TeleInt: defined at 0x%x IRQ %d\n", 326 cs->hw.hfc.addr, cs->irq); 327 328 setup_isac(cs); 329 cs->readisac = &ReadISAC; 330 cs->writeisac = &WriteISAC; 331 cs->readisacfifo = &ReadISACfifo; 332 cs->writeisacfifo = &WriteISACfifo; 333 cs->BC_Read_Reg = &ReadHFC; 334 cs->BC_Write_Reg = &WriteHFC; 335 cs->cardmsg = &TeleInt_card_msg; 336 cs->irq_func = &TeleInt_interrupt; 337 ISACVersion(cs, "TeleInt:"); 338 return (1); 339} 340