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 __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
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.