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