1/* $Id: bkm_a4t.c,v 1.22.2.4 2004/01/14 16:04:48 keil Exp $ 2 * 3 * low level stuff for T-Berkom A4T 4 * 5 * Author Roland Klabunde 6 * Copyright by Roland Klabunde <R.Klabunde@Berkom.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 14#include <linux/init.h> 15#include "hisax.h" 16#include "isac.h" 17#include "hscx.h" 18#include "jade.h" 19#include "isdnl1.h" 20#include <linux/pci.h> 21#include "bkm_ax.h" 22 23static const char *bkm_a4t_revision = "$Revision: 1.22.2.4 $"; 24 25 26static inline u_char 27readreg(unsigned int ale, unsigned long adr, u_char off) 28{ 29 register u_int ret; 30 unsigned int *po = (unsigned int *) adr; /* Postoffice */ 31 32 *po = (GCS_2 | PO_WRITE | off); 33 __WAITI20__(po); 34 *po = (ale | PO_READ); 35 __WAITI20__(po); 36 ret = *po; 37 return ((unsigned char) ret); 38} 39 40 41static inline void 42readfifo(unsigned int ale, unsigned long adr, u_char off, u_char *data, int size) 43{ 44 int i; 45 for (i = 0; i < size; i++) 46 *data++ = readreg(ale, adr, off); 47} 48 49 50static inline void 51writereg(unsigned int ale, unsigned long adr, u_char off, u_char data) 52{ 53 unsigned int *po = (unsigned int *) adr; /* Postoffice */ 54 *po = (GCS_2 | PO_WRITE | off); 55 __WAITI20__(po); 56 *po = (ale | PO_WRITE | data); 57 __WAITI20__(po); 58} 59 60 61static inline void 62writefifo(unsigned int ale, unsigned long adr, u_char off, u_char *data, int size) 63{ 64 int i; 65 66 for (i = 0; i < size; i++) 67 writereg(ale, adr, off, *data++); 68} 69 70 71/* Interface functions */ 72 73static u_char 74ReadISAC(struct IsdnCardState *cs, u_char offset) 75{ 76 return (readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset)); 77} 78 79static void 80WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) 81{ 82 writereg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset, value); 83} 84 85static void 86ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) 87{ 88 readfifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size); 89} 90 91static void 92WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) 93{ 94 writefifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size); 95} 96 97static u_char 98ReadJADE(struct IsdnCardState *cs, int jade, u_char offset) 99{ 100 return (readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)))); 101} 102 103static void 104WriteJADE(struct IsdnCardState *cs, int jade, u_char offset, u_char value) 105{ 106 writereg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)), value); 107} 108 109/* 110 * fast interrupt JADE stuff goes here 111 */ 112 113#define READJADE(cs, nr, reg) readreg(cs->hw.ax.jade_ale, \ 114 cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80))) 115#define WRITEJADE(cs, nr, reg, data) writereg(cs->hw.ax.jade_ale, \ 116 cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), data) 117 118#define READJADEFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.jade_ale, \ 119 cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt) 120#define WRITEJADEFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.jade_ale, \ 121 cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt) 122 123#include "jade_irq.c" 124 125static irqreturn_t 126bkm_interrupt(int intno, void *dev_id) 127{ 128 struct IsdnCardState *cs = dev_id; 129 u_char val = 0; 130 u_long flags; 131 I20_REGISTER_FILE *pI20_Regs; 132 133 spin_lock_irqsave(&cs->lock, flags); 134 pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); 135 136 /* ISDN interrupt pending? */ 137 if (pI20_Regs->i20IntStatus & intISDN) { 138 /* Reset the ISDN interrupt */ 139 pI20_Regs->i20IntStatus = intISDN; 140 /* Disable ISDN interrupt */ 141 pI20_Regs->i20IntCtrl &= ~intISDN; 142 /* Channel A first */ 143 val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0x80); 144 if (val) { 145 jade_int_main(cs, val, 0); 146 } 147 /* Channel B */ 148 val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0xC0); 149 if (val) { 150 jade_int_main(cs, val, 1); 151 } 152 /* D-Channel */ 153 val = readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, ISAC_ISTA); 154 if (val) { 155 isac_interrupt(cs, val); 156 } 157 /* Reenable ISDN interrupt */ 158 pI20_Regs->i20IntCtrl |= intISDN; 159 spin_unlock_irqrestore(&cs->lock, flags); 160 return IRQ_HANDLED; 161 } else { 162 spin_unlock_irqrestore(&cs->lock, flags); 163 return IRQ_NONE; 164 } 165} 166 167static void 168release_io_bkm(struct IsdnCardState *cs) 169{ 170 if (cs->hw.ax.base) { 171 iounmap((void *) cs->hw.ax.base); 172 cs->hw.ax.base = 0; 173 } 174} 175 176static void 177enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable) 178{ 179 if (cs->typ == ISDN_CTYPE_BKM_A4T) { 180 I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); 181 if (bEnable) 182 pI20_Regs->i20IntCtrl |= (intISDN | intPCI); 183 else 184 /* CAUTION: This disables the video capture driver too */ 185 pI20_Regs->i20IntCtrl &= ~(intISDN | intPCI); 186 } 187} 188 189static void 190reset_bkm(struct IsdnCardState *cs) 191{ 192 if (cs->typ == ISDN_CTYPE_BKM_A4T) { 193 I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); 194 /* Issue the I20 soft reset */ 195 pI20_Regs->i20SysControl = 0xFF; /* all in */ 196 mdelay(10); 197 /* Remove the soft reset */ 198 pI20_Regs->i20SysControl = sysRESET | 0xFF; 199 mdelay(10); 200 /* Set our configuration */ 201 pI20_Regs->i20SysControl = sysRESET | sysCFG; 202 /* Issue ISDN reset */ 203 pI20_Regs->i20GuestControl = guestWAIT_CFG | 204 g_A4T_JADE_RES | 205 g_A4T_ISAR_RES | 206 g_A4T_ISAC_RES | 207 g_A4T_JADE_BOOTR | 208 g_A4T_ISAR_BOOTR; 209 mdelay(10); 210 211 /* Remove RESET state from ISDN */ 212 pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES | 213 g_A4T_JADE_RES | 214 g_A4T_ISAR_RES); 215 mdelay(10); 216 } 217} 218 219static int 220BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg) 221{ 222 u_long flags; 223 224 switch (mt) { 225 case CARD_RESET: 226 /* Disable ints */ 227 spin_lock_irqsave(&cs->lock, flags); 228 enable_bkm_int(cs, 0); 229 reset_bkm(cs); 230 spin_unlock_irqrestore(&cs->lock, flags); 231 return (0); 232 case CARD_RELEASE: 233 /* Sanity */ 234 spin_lock_irqsave(&cs->lock, flags); 235 enable_bkm_int(cs, 0); 236 reset_bkm(cs); 237 spin_unlock_irqrestore(&cs->lock, flags); 238 release_io_bkm(cs); 239 return (0); 240 case CARD_INIT: 241 spin_lock_irqsave(&cs->lock, flags); 242 clear_pending_isac_ints(cs); 243 clear_pending_jade_ints(cs); 244 initisac(cs); 245 initjade(cs); 246 /* Enable ints */ 247 enable_bkm_int(cs, 1); 248 spin_unlock_irqrestore(&cs->lock, flags); 249 return (0); 250 case CARD_TEST: 251 return (0); 252 } 253 return (0); 254} 255 256static int __devinit a4t_pci_probe(struct pci_dev *dev_a4t, 257 struct IsdnCardState *cs, 258 u_int *found, 259 u_int *pci_memaddr) 260{ 261 u16 sub_sys; 262 u16 sub_vendor; 263 264 sub_vendor = dev_a4t->subsystem_vendor; 265 sub_sys = dev_a4t->subsystem_device; 266 if ((sub_sys == PCI_DEVICE_ID_BERKOM_A4T) && (sub_vendor == PCI_VENDOR_ID_BERKOM)) { 267 if (pci_enable_device(dev_a4t)) 268 return (0); /* end loop & function */ 269 *found = 1; 270 *pci_memaddr = pci_resource_start(dev_a4t, 0); 271 cs->irq = dev_a4t->irq; 272 return (1); /* end loop */ 273 } 274 275 return (-1); /* continue looping */ 276} 277 278static int __devinit a4t_cs_init(struct IsdnCard *card, 279 struct IsdnCardState *cs, 280 u_int pci_memaddr) 281{ 282 I20_REGISTER_FILE *pI20_Regs; 283 284 if (!cs->irq) { /* IRQ range check ?? */ 285 printk(KERN_WARNING "HiSax: Telekom A4T: No IRQ\n"); 286 return (0); 287 } 288 cs->hw.ax.base = (long) ioremap(pci_memaddr, 4096); 289 /* Check suspecious address */ 290 pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); 291 if ((pI20_Regs->i20IntStatus & 0x8EFFFFFF) != 0) { 292 printk(KERN_WARNING "HiSax: Telekom A4T address " 293 "%lx-%lx suspicious\n", 294 cs->hw.ax.base, cs->hw.ax.base + 4096); 295 iounmap((void *) cs->hw.ax.base); 296 cs->hw.ax.base = 0; 297 return (0); 298 } 299 cs->hw.ax.isac_adr = cs->hw.ax.base + PO_OFFSET; 300 cs->hw.ax.jade_adr = cs->hw.ax.base + PO_OFFSET; 301 cs->hw.ax.isac_ale = GCS_1; 302 cs->hw.ax.jade_ale = GCS_3; 303 304 printk(KERN_INFO "HiSax: Telekom A4T: Card configured at " 305 "0x%lX IRQ %d\n", 306 cs->hw.ax.base, cs->irq); 307 308 setup_isac(cs); 309 cs->readisac = &ReadISAC; 310 cs->writeisac = &WriteISAC; 311 cs->readisacfifo = &ReadISACfifo; 312 cs->writeisacfifo = &WriteISACfifo; 313 cs->BC_Read_Reg = &ReadJADE; 314 cs->BC_Write_Reg = &WriteJADE; 315 cs->BC_Send_Data = &jade_fill_fifo; 316 cs->cardmsg = &BKM_card_msg; 317 cs->irq_func = &bkm_interrupt; 318 cs->irq_flags |= IRQF_SHARED; 319 ISACVersion(cs, "Telekom A4T:"); 320 /* Jade version */ 321 JadeVersion(cs, "Telekom A4T:"); 322 323 return (1); 324} 325 326static struct pci_dev *dev_a4t __devinitdata = NULL; 327 328int __devinit 329setup_bkm_a4t(struct IsdnCard *card) 330{ 331 struct IsdnCardState *cs = card->cs; 332 char tmp[64]; 333 u_int pci_memaddr = 0, found = 0; 334 int ret; 335 336 strcpy(tmp, bkm_a4t_revision); 337 printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp)); 338 if (cs->typ == ISDN_CTYPE_BKM_A4T) { 339 cs->subtyp = BKM_A4T; 340 } else 341 return (0); 342 343 while ((dev_a4t = hisax_find_pci_device(PCI_VENDOR_ID_ZORAN, 344 PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) { 345 ret = a4t_pci_probe(dev_a4t, cs, &found, &pci_memaddr); 346 if (!ret) 347 return (0); 348 if (ret > 0) 349 break; 350 } 351 if (!found) { 352 printk(KERN_WARNING "HiSax: Telekom A4T: Card not found\n"); 353 return (0); 354 } 355 if (!pci_memaddr) { 356 printk(KERN_WARNING "HiSax: Telekom A4T: " 357 "No Memory base address\n"); 358 return (0); 359 } 360 361 return a4t_cs_init(card, cs, pci_memaddr); 362} 363