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 a4t_pci_probe(struct pci_dev *dev_a4t, struct IsdnCardState *cs, 257 u_int *found, u_int *pci_memaddr) 258{ 259 u16 sub_sys; 260 u16 sub_vendor; 261 262 sub_vendor = dev_a4t->subsystem_vendor; 263 sub_sys = dev_a4t->subsystem_device; 264 if ((sub_sys == PCI_DEVICE_ID_BERKOM_A4T) && (sub_vendor == PCI_VENDOR_ID_BERKOM)) { 265 if (pci_enable_device(dev_a4t)) 266 return (0); /* end loop & function */ 267 *found = 1; 268 *pci_memaddr = pci_resource_start(dev_a4t, 0); 269 cs->irq = dev_a4t->irq; 270 return (1); /* end loop */ 271 } 272 273 return (-1); /* continue looping */ 274} 275 276static int a4t_cs_init(struct IsdnCard *card, struct IsdnCardState *cs, 277 u_int pci_memaddr) 278{ 279 I20_REGISTER_FILE *pI20_Regs; 280 281 if (!cs->irq) { /* IRQ range check ?? */ 282 printk(KERN_WARNING "HiSax: Telekom A4T: No IRQ\n"); 283 return (0); 284 } 285 cs->hw.ax.base = (long) ioremap(pci_memaddr, 4096); 286 /* Check suspecious address */ 287 pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); 288 if ((pI20_Regs->i20IntStatus & 0x8EFFFFFF) != 0) { 289 printk(KERN_WARNING "HiSax: Telekom A4T address " 290 "%lx-%lx suspicious\n", 291 cs->hw.ax.base, cs->hw.ax.base + 4096); 292 iounmap((void *) cs->hw.ax.base); 293 cs->hw.ax.base = 0; 294 return (0); 295 } 296 cs->hw.ax.isac_adr = cs->hw.ax.base + PO_OFFSET; 297 cs->hw.ax.jade_adr = cs->hw.ax.base + PO_OFFSET; 298 cs->hw.ax.isac_ale = GCS_1; 299 cs->hw.ax.jade_ale = GCS_3; 300 301 printk(KERN_INFO "HiSax: Telekom A4T: Card configured at " 302 "0x%lX IRQ %d\n", 303 cs->hw.ax.base, cs->irq); 304 305 setup_isac(cs); 306 cs->readisac = &ReadISAC; 307 cs->writeisac = &WriteISAC; 308 cs->readisacfifo = &ReadISACfifo; 309 cs->writeisacfifo = &WriteISACfifo; 310 cs->BC_Read_Reg = &ReadJADE; 311 cs->BC_Write_Reg = &WriteJADE; 312 cs->BC_Send_Data = &jade_fill_fifo; 313 cs->cardmsg = &BKM_card_msg; 314 cs->irq_func = &bkm_interrupt; 315 cs->irq_flags |= IRQF_SHARED; 316 ISACVersion(cs, "Telekom A4T:"); 317 /* Jade version */ 318 JadeVersion(cs, "Telekom A4T:"); 319 320 return (1); 321} 322 323static struct pci_dev *dev_a4t = NULL; 324 325int setup_bkm_a4t(struct IsdnCard *card) 326{ 327 struct IsdnCardState *cs = card->cs; 328 char tmp[64]; 329 u_int pci_memaddr = 0, found = 0; 330 int ret; 331 332 strcpy(tmp, bkm_a4t_revision); 333 printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp)); 334 if (cs->typ == ISDN_CTYPE_BKM_A4T) { 335 cs->subtyp = BKM_A4T; 336 } else 337 return (0); 338 339 while ((dev_a4t = hisax_find_pci_device(PCI_VENDOR_ID_ZORAN, 340 PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) { 341 ret = a4t_pci_probe(dev_a4t, cs, &found, &pci_memaddr); 342 if (!ret) 343 return (0); 344 if (ret > 0) 345 break; 346 } 347 if (!found) { 348 printk(KERN_WARNING "HiSax: Telekom A4T: Card not found\n"); 349 return (0); 350 } 351 if (!pci_memaddr) { 352 printk(KERN_WARNING "HiSax: Telekom A4T: " 353 "No Memory base address\n"); 354 return (0); 355 } 356 357 return a4t_cs_init(card, cs, pci_memaddr); 358} 359