enternow_pci.c revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2
1/* enternow_pci.c,v 0.99 2001/10/02 2 * 3 * enternow_pci.c Card-specific routines for 4 * Formula-n enter:now ISDN PCI ab 5 * Gerdes AG Power ISDN PCI 6 * Woerltronic SA 16 PCI 7 * (based on HiSax driver by Karsten Keil) 8 * 9 * Author Christoph Ersfeld <info@formula-n.de> 10 * Formula-n Europe AG (www.formula-n.com) 11 * previously Gerdes AG 12 * 13 * 14 * This file is (c) under GNU PUBLIC LICENSE 15 * 16 * Notes: 17 * This driver interfaces to netjet.c which performs B-channel 18 * processing. 19 * 20 * Version 0.99 is the first release of this driver and there are 21 * certainly a few bugs. 22 * It isn't testet on linux 2.4 yet, so consider this code to be 23 * beta. 24 * 25 * Please don't report me any malfunction without sending 26 * (compressed) debug-logs. 27 * It would be nearly impossible to retrace it. 28 * 29 * Log D-channel-processing as follows: 30 * 31 * 1. Load hisax with card-specific parameters, this example ist for 32 * Formula-n enter:now ISDN PCI and compatible 33 * (f.e. Gerdes Power ISDN PCI) 34 * 35 * modprobe hisax type=41 protocol=2 id=gerdes 36 * 37 * if you chose an other value for id, you need to modify the 38 * code below, too. 39 * 40 * 2. set debug-level 41 * 42 * hisaxctrl gerdes 1 0x3ff 43 * hisaxctrl gerdes 11 0x4f 44 * cat /dev/isdnctrl >> ~/log & 45 * 46 * Please take also a look into /var/log/messages if there is 47 * anything importand concerning HISAX. 48 * 49 * 50 * Credits: 51 * Programming the driver for Formula-n enter:now ISDN PCI and 52 * necessary the driver for the used Amd 7930 D-channel-controller 53 * was spnsored by Formula-n Europe AG. 54 * Thanks to Karsten Keil and Petr Novak, who gave me support in 55 * Hisax-specific questions. 56 * I want so say special thanks to Carl-Friedrich Braun, who had to 57 * answer a lot of questions about generally ISDN and about handling 58 * of the Amd-Chip. 59 * 60 */ 61 62 63#include <linux/config.h> 64#include "hisax.h" 65#include "isac.h" 66#include "isdnl1.h" 67#include "amd7930_fn.h" 68#include "enternow.h" 69#include <linux/interrupt.h> 70#include <linux/ppp_defs.h> 71#include <linux/pci.h> 72#include <linux/init.h> 73#include "netjet.h" 74 75 76 77const char *enternow_pci_rev = "$Revision: 1.1.4.5 $"; 78 79 80/* *************************** I/O-Interface functions ************************************* */ 81 82 83/* cs->readisac, macro rByteAMD */ 84BYTE 85ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset) 86{ 87 /* direktes Register */ 88 if(offset < 8) 89 return (InByte(cs->hw.njet.isac + 4*offset)); 90 91 /* indirektes Register */ 92 else { 93 OutByte(cs->hw.njet.isac + 4*AMD_CR, offset); 94 return(InByte(cs->hw.njet.isac + 4*AMD_DR)); 95 } 96} 97 98/* cs->writeisac, macro wByteAMD */ 99void 100WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value) 101{ 102 /* direktes Register */ 103 if(offset < 8) 104 OutByte(cs->hw.njet.isac + 4*offset, value); 105 106 /* indirektes Register */ 107 else { 108 OutByte(cs->hw.njet.isac + 4*AMD_CR, offset); 109 OutByte(cs->hw.njet.isac + 4*AMD_DR, value); 110 } 111} 112 113 114void 115enpci_setIrqMask(struct IsdnCardState *cs, BYTE val) { 116 if (!val) 117 OutByte(cs->hw.njet.base+NETJET_IRQMASK1, 0x00); 118 else 119 OutByte(cs->hw.njet.base+NETJET_IRQMASK1, TJ_AMD_IRQ); 120} 121 122 123static BYTE dummyrr(struct IsdnCardState *cs, int chan, BYTE off) 124{ 125 return(5); 126} 127 128static void dummywr(struct IsdnCardState *cs, int chan, BYTE off, BYTE value) 129{ 130 131} 132 133 134/* ******************************************************************************** */ 135 136 137static void 138reset_enpci(struct IsdnCardState *cs) 139{ 140 if (cs->debug & L1_DEB_ISAC) 141 debugl1(cs, "enter:now PCI: reset"); 142 143 /* Reset on, (also for AMD) */ 144 cs->hw.njet.ctrl_reg = 0x07; 145 OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); 146 mdelay(20); 147 /* Reset off */ 148 cs->hw.njet.ctrl_reg = 0x30; 149 OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); 150 /* 20ms delay */ 151 mdelay(20); 152 cs->hw.njet.auxd = 0; // LED-status 153 cs->hw.njet.dmactrl = 0; 154 OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ); 155 OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ); 156 OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd); // LED off 157} 158 159 160static int 161enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg) 162{ 163 u_long flags; 164 BYTE *chan; 165 166 if (cs->debug & L1_DEB_ISAC) 167 debugl1(cs, "enter:now PCI: card_msg: 0x%04X", mt); 168 169 switch (mt) { 170 case CARD_RESET: 171 spin_lock_irqsave(&cs->lock, flags); 172 reset_enpci(cs); 173 Amd7930_init(cs); 174 spin_unlock_irqrestore(&cs->lock, flags); 175 break; 176 case CARD_RELEASE: 177 release_io_netjet(cs); 178 break; 179 case CARD_INIT: 180 reset_enpci(cs); 181 inittiger(cs); 182 /* irq must be on here */ 183 Amd7930_init(cs); 184 break; 185 case CARD_TEST: 186 break; 187 case MDL_ASSIGN: 188 /* TEI assigned, LED1 on */ 189 cs->hw.njet.auxd = TJ_AMD_IRQ << 1; 190 OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd); 191 break; 192 case MDL_REMOVE: 193 /* TEI removed, LEDs off */ 194 cs->hw.njet.auxd = 0; 195 OutByte(cs->hw.njet.base + NETJET_AUXDATA, 0x00); 196 break; 197 case MDL_BC_ASSIGN: 198 /* activate B-channel */ 199 chan = (BYTE *)arg; 200 201 if (cs->debug & L1_DEB_ISAC) 202 debugl1(cs, "enter:now PCI: assign phys. BC %d in AMD LMR1", *chan); 203 204 cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 | (*chan + 1)), "MDL_BC_ASSIGN"); 205 /* at least one b-channel in use, LED 2 on */ 206 cs->hw.njet.auxd |= TJ_AMD_IRQ << 2; 207 OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd); 208 break; 209 case MDL_BC_RELEASE: 210 /* deactivate B-channel */ 211 chan = (BYTE *)arg; 212 213 if (cs->debug & L1_DEB_ISAC) 214 debugl1(cs, "enter:now PCI: release phys. BC %d in Amd LMR1", *chan); 215 216 cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 & ~(*chan + 1)), "MDL_BC_RELEASE"); 217 /* no b-channel active -> LED2 off */ 218 if (!(cs->dc.amd7930.lmr1 & 3)) { 219 cs->hw.njet.auxd &= ~(TJ_AMD_IRQ << 2); 220 OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd); 221 } 222 break; 223 default: 224 break; 225 226 } 227 return(0); 228} 229 230static irqreturn_t 231enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs) 232{ 233 struct IsdnCardState *cs = dev_id; 234 BYTE s0val, s1val, ir; 235 u_long flags; 236 237 spin_lock_irqsave(&cs->lock, flags); 238 s1val = InByte(cs->hw.njet.base + NETJET_IRQSTAT1); 239 240 /* AMD threw an interrupt */ 241 if (!(s1val & TJ_AMD_IRQ)) { 242 /* read and clear interrupt-register */ 243 ir = ReadByteAmd7930(cs, 0x00); 244 Amd7930_interrupt(cs, ir); 245 s1val = 1; 246 } else 247 s1val = 0; 248 s0val = InByte(cs->hw.njet.base + NETJET_IRQSTAT0); 249 if ((s0val | s1val)==0) { // shared IRQ 250 spin_unlock_irqrestore(&cs->lock, flags); 251 return IRQ_NONE; 252 } 253 if (s0val) 254 OutByte(cs->hw.njet.base + NETJET_IRQSTAT0, s0val); 255 256 /* DMA-Interrupt: B-channel-stuff */ 257 /* set bits in sval to indicate which page is free */ 258 if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) < 259 inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ)) 260 /* the 2nd write page is free */ 261 s0val = 0x08; 262 else /* the 1st write page is free */ 263 s0val = 0x04; 264 if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) < 265 inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ)) 266 /* the 2nd read page is free */ 267 s0val = s0val | 0x02; 268 else /* the 1st read page is free */ 269 s0val = s0val | 0x01; 270 if (s0val != cs->hw.njet.last_is0) /* we have a DMA interrupt */ 271 { 272 if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { 273 spin_unlock_irqrestore(&cs->lock, flags); 274 return IRQ_HANDLED; 275 } 276 cs->hw.njet.irqstat0 = s0val; 277 if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) != 278 (cs->hw.njet.last_is0 & NETJET_IRQM0_READ)) 279 /* we have a read dma int */ 280 read_tiger(cs); 281 if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) != 282 (cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE)) 283 /* we have a write dma int */ 284 write_tiger(cs); 285 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); 286 } 287 spin_unlock_irqrestore(&cs->lock, flags); 288 return IRQ_HANDLED; 289} 290 291 292static struct pci_dev *dev_netjet __initdata = NULL; 293 294/* called by config.c */ 295int __init 296setup_enternow_pci(struct IsdnCard *card) 297{ 298 int bytecnt; 299 struct IsdnCardState *cs = card->cs; 300 char tmp[64]; 301 302#ifdef CONFIG_PCI 303#ifdef __BIG_ENDIAN 304#error "not running on big endian machines now" 305#endif 306 strcpy(tmp, enternow_pci_rev); 307 printk(KERN_INFO "HiSax: Formula-n Europe AG enter:now ISDN PCI driver Rev. %s\n", HiSax_getrev(tmp)); 308 if (cs->typ != ISDN_CTYPE_ENTERNOW) 309 return(0); 310 test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); 311 312 for ( ;; ) 313 { 314 if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET, 315 PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) { 316 if (pci_enable_device(dev_netjet)) 317 return(0); 318 cs->irq = dev_netjet->irq; 319 if (!cs->irq) { 320 printk(KERN_WARNING "enter:now PCI: No IRQ for PCI card found\n"); 321 return(0); 322 } 323 cs->hw.njet.base = pci_resource_start(dev_netjet, 0); 324 if (!cs->hw.njet.base) { 325 printk(KERN_WARNING "enter:now PCI: No IO-Adr for PCI card found\n"); 326 return(0); 327 } 328 /* checks Sub-Vendor ID because system crashes with Traverse-Card */ 329 if ((dev_netjet->subsystem_vendor != 0x55) || 330 (dev_netjet->subsystem_device != 0x02)) { 331 printk(KERN_WARNING "enter:now: You tried to load this driver with an incompatible TigerJet-card\n"); 332 printk(KERN_WARNING "Use type=20 for Traverse NetJet PCI Card.\n"); 333 return(0); 334 } 335 } else { 336 printk(KERN_WARNING "enter:now PCI: No PCI card found\n"); 337 return(0); 338 } 339 340 cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; 341 cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD 342 343 /* Reset an */ 344 cs->hw.njet.ctrl_reg = 0x07; // ge�ndert von 0xff 345 OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); 346 /* 20 ms Pause */ 347 mdelay(20); 348 349 cs->hw.njet.ctrl_reg = 0x30; /* Reset Off and status read clear */ 350 OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); 351 mdelay(10); 352 353 cs->hw.njet.auxd = 0x00; // war 0xc0 354 cs->hw.njet.dmactrl = 0; 355 356 OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ); 357 OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ); 358 OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd); 359 360 break; 361 } 362#else 363 364 printk(KERN_WARNING "enter:now PCI: NO_PCI_BIOS\n"); 365 printk(KERN_WARNING "enter:now PCI: unable to config Formula-n enter:now ISDN PCI ab\n"); 366 return (0); 367 368#endif /* CONFIG_PCI */ 369 370 bytecnt = 256; 371 372 printk(KERN_INFO 373 "enter:now PCI: PCI card configured at 0x%lx IRQ %d\n", 374 cs->hw.njet.base, cs->irq); 375 if (!request_region(cs->hw.njet.base, bytecnt, "Fn_ISDN")) { 376 printk(KERN_WARNING 377 "HiSax: %s config port %lx-%lx already in use\n", 378 CardType[card->typ], 379 cs->hw.njet.base, 380 cs->hw.njet.base + bytecnt); 381 return (0); 382 } 383 setup_Amd7930(cs); 384 cs->hw.njet.last_is0 = 0; 385 /* macro rByteAMD */ 386 cs->readisac = &ReadByteAmd7930; 387 /* macro wByteAMD */ 388 cs->writeisac = &WriteByteAmd7930; 389 cs->dc.amd7930.setIrqMask = &enpci_setIrqMask; 390 391 cs->BC_Read_Reg = &dummyrr; 392 cs->BC_Write_Reg = &dummywr; 393 cs->BC_Send_Data = &netjet_fill_dma; 394 cs->cardmsg = &enpci_card_msg; 395 cs->irq_func = &enpci_interrupt; 396 cs->irq_flags |= SA_SHIRQ; 397 398 return (1); 399} 400