1/* $Id: teles0.c,v 1.1.1.1 2007/08/03 18:52:36 Exp $ 2 * 3 * low level stuff for Teles Memory IO isdn cards 4 * 5 * Author Karsten Keil 6 * based on the teles driver from Jan den Ouden 7 * Copyright by Karsten Keil <keil@isdn4linux.de> 8 * 9 * This software may be used and distributed according to the terms 10 * of the GNU General Public License, incorporated herein by reference. 11 * 12 * Thanks to Jan den Ouden 13 * Fritz Elfert 14 * Beat Doebeli 15 * 16 */ 17 18#include <linux/init.h> 19#include "hisax.h" 20#include "isdnl1.h" 21#include "isac.h" 22#include "hscx.h" 23 24extern const char *CardType[]; 25 26static const char *teles0_revision = "$Revision: 1.1.1.1 $"; 27 28#define TELES_IOMEM_SIZE 0x400 29#define byteout(addr,val) outb(val,addr) 30#define bytein(addr) inb(addr) 31 32static inline u_char 33readisac(void __iomem *adr, u_char off) 34{ 35 return readb(adr + ((off & 1) ? 0x2ff : 0x100) + off); 36} 37 38static inline void 39writeisac(void __iomem *adr, u_char off, u_char data) 40{ 41 writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off); mb(); 42} 43 44 45static inline u_char 46readhscx(void __iomem *adr, int hscx, u_char off) 47{ 48 return readb(adr + (hscx ? 0x1c0 : 0x180) + 49 ((off & 1) ? 0x1ff : 0) + off); 50} 51 52static inline void 53writehscx(void __iomem *adr, int hscx, u_char off, u_char data) 54{ 55 writeb(data, adr + (hscx ? 0x1c0 : 0x180) + 56 ((off & 1) ? 0x1ff : 0) + off); mb(); 57} 58 59static inline void 60read_fifo_isac(void __iomem *adr, u_char * data, int size) 61{ 62 register int i; 63 register u_char __iomem *ad = adr + 0x100; 64 for (i = 0; i < size; i++) 65 data[i] = readb(ad); 66} 67 68static inline void 69write_fifo_isac(void __iomem *adr, u_char * data, int size) 70{ 71 register int i; 72 register u_char __iomem *ad = adr + 0x100; 73 for (i = 0; i < size; i++) { 74 writeb(data[i], ad); mb(); 75 } 76} 77 78static inline void 79read_fifo_hscx(void __iomem *adr, int hscx, u_char * data, int size) 80{ 81 register int i; 82 register u_char __iomem *ad = adr + (hscx ? 0x1c0 : 0x180); 83 for (i = 0; i < size; i++) 84 data[i] = readb(ad); 85} 86 87static inline void 88write_fifo_hscx(void __iomem *adr, int hscx, u_char * data, int size) 89{ 90 int i; 91 register u_char __iomem *ad = adr + (hscx ? 0x1c0 : 0x180); 92 for (i = 0; i < size; i++) { 93 writeb(data[i], ad); mb(); 94 } 95} 96 97/* Interface functions */ 98 99static u_char 100ReadISAC(struct IsdnCardState *cs, u_char offset) 101{ 102 return (readisac(cs->hw.teles0.membase, offset)); 103} 104 105static void 106WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) 107{ 108 writeisac(cs->hw.teles0.membase, offset, value); 109} 110 111static void 112ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) 113{ 114 read_fifo_isac(cs->hw.teles0.membase, data, size); 115} 116 117static void 118WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) 119{ 120 write_fifo_isac(cs->hw.teles0.membase, data, size); 121} 122 123static u_char 124ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) 125{ 126 return (readhscx(cs->hw.teles0.membase, hscx, offset)); 127} 128 129static void 130WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) 131{ 132 writehscx(cs->hw.teles0.membase, hscx, offset, value); 133} 134 135/* 136 * fast interrupt HSCX stuff goes here 137 */ 138 139#define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg) 140#define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data) 141#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt) 142#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt) 143 144#include "hscx_irq.c" 145 146static irqreturn_t 147teles0_interrupt(int intno, void *dev_id) 148{ 149 struct IsdnCardState *cs = dev_id; 150 u_char val; 151 u_long flags; 152 int count = 0; 153 154 spin_lock_irqsave(&cs->lock, flags); 155 val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA); 156 Start_HSCX: 157 if (val) 158 hscx_int_main(cs, val); 159 val = readisac(cs->hw.teles0.membase, ISAC_ISTA); 160 Start_ISAC: 161 if (val) 162 isac_interrupt(cs, val); 163 count++; 164 val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA); 165 if (val && count < 5) { 166 if (cs->debug & L1_DEB_HSCX) 167 debugl1(cs, "HSCX IntStat after IntRoutine"); 168 goto Start_HSCX; 169 } 170 val = readisac(cs->hw.teles0.membase, ISAC_ISTA); 171 if (val && count < 5) { 172 if (cs->debug & L1_DEB_ISAC) 173 debugl1(cs, "ISAC IntStat after IntRoutine"); 174 goto Start_ISAC; 175 } 176 writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF); 177 writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF); 178 writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF); 179 writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0); 180 writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0); 181 writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0); 182 spin_unlock_irqrestore(&cs->lock, flags); 183 return IRQ_HANDLED; 184} 185 186static void 187release_io_teles0(struct IsdnCardState *cs) 188{ 189 if (cs->hw.teles0.cfg_reg) 190 release_region(cs->hw.teles0.cfg_reg, 8); 191 iounmap(cs->hw.teles0.membase); 192 release_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE); 193} 194 195static int 196reset_teles0(struct IsdnCardState *cs) 197{ 198 u_char cfval; 199 200 if (cs->hw.teles0.cfg_reg) { 201 switch (cs->irq) { 202 case 2: 203 case 9: 204 cfval = 0x00; 205 break; 206 case 3: 207 cfval = 0x02; 208 break; 209 case 4: 210 cfval = 0x04; 211 break; 212 case 5: 213 cfval = 0x06; 214 break; 215 case 10: 216 cfval = 0x08; 217 break; 218 case 11: 219 cfval = 0x0A; 220 break; 221 case 12: 222 cfval = 0x0C; 223 break; 224 case 15: 225 cfval = 0x0E; 226 break; 227 default: 228 return(1); 229 } 230 cfval |= ((cs->hw.teles0.phymem >> 9) & 0xF0); 231 byteout(cs->hw.teles0.cfg_reg + 4, cfval); 232 HZDELAY(HZ / 10 + 1); 233 byteout(cs->hw.teles0.cfg_reg + 4, cfval | 1); 234 HZDELAY(HZ / 10 + 1); 235 } 236 writeb(0, cs->hw.teles0.membase + 0x80); mb(); 237 HZDELAY(HZ / 5 + 1); 238 writeb(1, cs->hw.teles0.membase + 0x80); mb(); 239 HZDELAY(HZ / 5 + 1); 240 return(0); 241} 242 243static int 244Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg) 245{ 246 u_long flags; 247 248 switch (mt) { 249 case CARD_RESET: 250 spin_lock_irqsave(&cs->lock, flags); 251 reset_teles0(cs); 252 spin_unlock_irqrestore(&cs->lock, flags); 253 return(0); 254 case CARD_RELEASE: 255 release_io_teles0(cs); 256 return(0); 257 case CARD_INIT: 258 spin_lock_irqsave(&cs->lock, flags); 259 inithscxisac(cs, 3); 260 spin_unlock_irqrestore(&cs->lock, flags); 261 return(0); 262 case CARD_TEST: 263 return(0); 264 } 265 return(0); 266} 267 268int __devinit 269setup_teles0(struct IsdnCard *card) 270{ 271 u_char val; 272 struct IsdnCardState *cs = card->cs; 273 char tmp[64]; 274 275 strcpy(tmp, teles0_revision); 276 printk(KERN_INFO "HiSax: Teles 8.0/16.0 driver Rev. %s\n", HiSax_getrev(tmp)); 277 if ((cs->typ != ISDN_CTYPE_16_0) && (cs->typ != ISDN_CTYPE_8_0)) 278 return (0); 279 280 if (cs->typ == ISDN_CTYPE_16_0) 281 cs->hw.teles0.cfg_reg = card->para[2]; 282 else /* 8.0 */ 283 cs->hw.teles0.cfg_reg = 0; 284 285 if (card->para[1] < 0x10000) { 286 card->para[1] <<= 4; 287 printk(KERN_INFO 288 "Teles0: membase configured DOSish, assuming 0x%lx\n", 289 (unsigned long) card->para[1]); 290 } 291 cs->irq = card->para[0]; 292 if (cs->hw.teles0.cfg_reg) { 293 if (!request_region(cs->hw.teles0.cfg_reg, 8, "teles cfg")) { 294 printk(KERN_WARNING 295 "HiSax: %s config port %x-%x already in use\n", 296 CardType[card->typ], 297 cs->hw.teles0.cfg_reg, 298 cs->hw.teles0.cfg_reg + 8); 299 return (0); 300 } 301 } 302 if (cs->hw.teles0.cfg_reg) { 303 if ((val = bytein(cs->hw.teles0.cfg_reg + 0)) != 0x51) { 304 printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n", 305 cs->hw.teles0.cfg_reg + 0, val); 306 release_region(cs->hw.teles0.cfg_reg, 8); 307 return (0); 308 } 309 if ((val = bytein(cs->hw.teles0.cfg_reg + 1)) != 0x93) { 310 printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n", 311 cs->hw.teles0.cfg_reg + 1, val); 312 release_region(cs->hw.teles0.cfg_reg, 8); 313 return (0); 314 } 315 val = bytein(cs->hw.teles0.cfg_reg + 2); /* 0x1e=without AB 316 * 0x1f=with AB 317 * 0x1c 16.3 ??? 318 */ 319 if (val != 0x1e && val != 0x1f) { 320 printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n", 321 cs->hw.teles0.cfg_reg + 2, val); 322 release_region(cs->hw.teles0.cfg_reg, 8); 323 return (0); 324 } 325 } 326 /* 16.0 and 8.0 designed for IOM1 */ 327 test_and_set_bit(HW_IOM1, &cs->HW_Flags); 328 cs->hw.teles0.phymem = card->para[1]; 329 if (!request_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE, "teles iomem")) { 330 printk(KERN_WARNING 331 "HiSax: %s memory region %lx-%lx already in use\n", 332 CardType[card->typ], 333 cs->hw.teles0.phymem, 334 cs->hw.teles0.phymem + TELES_IOMEM_SIZE); 335 if (cs->hw.teles0.cfg_reg) 336 release_region(cs->hw.teles0.cfg_reg, 8); 337 return (0); 338 } 339 cs->hw.teles0.membase = ioremap(cs->hw.teles0.phymem, TELES_IOMEM_SIZE); 340 printk(KERN_INFO 341 "HiSax: %s config irq:%d mem:%p cfg:0x%X\n", 342 CardType[cs->typ], cs->irq, 343 cs->hw.teles0.membase, cs->hw.teles0.cfg_reg); 344 if (reset_teles0(cs)) { 345 printk(KERN_WARNING "Teles0: wrong IRQ\n"); 346 release_io_teles0(cs); 347 return (0); 348 } 349 setup_isac(cs); 350 cs->readisac = &ReadISAC; 351 cs->writeisac = &WriteISAC; 352 cs->readisacfifo = &ReadISACfifo; 353 cs->writeisacfifo = &WriteISACfifo; 354 cs->BC_Read_Reg = &ReadHSCX; 355 cs->BC_Write_Reg = &WriteHSCX; 356 cs->BC_Send_Data = &hscx_fill_fifo; 357 cs->cardmsg = &Teles_card_msg; 358 cs->irq_func = &teles0_interrupt; 359 ISACVersion(cs, "Teles0:"); 360 if (HscxVersion(cs, "Teles0:")) { 361 printk(KERN_WARNING 362 "Teles0: wrong HSCX versions check IO/MEM addresses\n"); 363 release_io_teles0(cs); 364 return (0); 365 } 366 return (1); 367} 368