linux/drivers/isdn/hisax/bkm_a4t.c
<<
>>
Prefs
   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