linux/drivers/isdn/hisax/avm_a1.c
<<
>>
Prefs
   1/* $Id: avm_a1.c,v 2.15.2.4 2004/01/13 21:46:03 keil Exp $
   2 *
   3 * low level stuff for AVM A1 (Fritz) isdn cards
   4 *
   5 * Author       Karsten Keil
   6 * Copyright    by Karsten Keil      <keil@isdn4linux.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#include <linux/init.h>
  14#include "hisax.h"
  15#include "isac.h"
  16#include "hscx.h"
  17#include "isdnl1.h"
  18
  19static const char *avm_revision = "$Revision: 2.15.2.4 $";
  20
  21#define  AVM_A1_STAT_ISAC       0x01
  22#define  AVM_A1_STAT_HSCX       0x02
  23#define  AVM_A1_STAT_TIMER      0x04
  24
  25#define byteout(addr, val) outb(val, addr)
  26#define bytein(addr) inb(addr)
  27
  28static inline u_char
  29readreg(unsigned int adr, u_char off)
  30{
  31        return (bytein(adr + off));
  32}
  33
  34static inline void
  35writereg(unsigned int adr, u_char off, u_char data)
  36{
  37        byteout(adr + off, data);
  38}
  39
  40
  41static inline void
  42read_fifo(unsigned int adr, u_char *data, int size)
  43{
  44        insb(adr, data, size);
  45}
  46
  47static void
  48write_fifo(unsigned int adr, u_char *data, int size)
  49{
  50        outsb(adr, data, size);
  51}
  52
  53/* Interface functions */
  54
  55static u_char
  56ReadISAC(struct IsdnCardState *cs, u_char offset)
  57{
  58        return (readreg(cs->hw.avm.isac, offset));
  59}
  60
  61static void
  62WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
  63{
  64        writereg(cs->hw.avm.isac, offset, value);
  65}
  66
  67static void
  68ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
  69{
  70        read_fifo(cs->hw.avm.isacfifo, data, size);
  71}
  72
  73static void
  74WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
  75{
  76        write_fifo(cs->hw.avm.isacfifo, data, size);
  77}
  78
  79static u_char
  80ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
  81{
  82        return (readreg(cs->hw.avm.hscx[hscx], offset));
  83}
  84
  85static void
  86WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
  87{
  88        writereg(cs->hw.avm.hscx[hscx], offset, value);
  89}
  90
  91/*
  92 * fast interrupt HSCX stuff goes here
  93 */
  94
  95#define READHSCX(cs, nr, reg) readreg(cs->hw.avm.hscx[nr], reg)
  96#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.avm.hscx[nr], reg, data)
  97#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt)
  98#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt)
  99
 100#include "hscx_irq.c"
 101
 102static irqreturn_t
 103avm_a1_interrupt(int intno, void *dev_id)
 104{
 105        struct IsdnCardState *cs = dev_id;
 106        u_char val, sval;
 107        u_long flags;
 108
 109        spin_lock_irqsave(&cs->lock, flags);
 110        while (((sval = bytein(cs->hw.avm.cfg_reg)) & 0xf) != 0x7) {
 111                if (!(sval & AVM_A1_STAT_TIMER)) {
 112                        byteout(cs->hw.avm.cfg_reg, 0x1E);
 113                        sval = bytein(cs->hw.avm.cfg_reg);
 114                } else if (cs->debug & L1_DEB_INTSTAT)
 115                        debugl1(cs, "avm IntStatus %x", sval);
 116                if (!(sval & AVM_A1_STAT_HSCX)) {
 117                        val = readreg(cs->hw.avm.hscx[1], HSCX_ISTA);
 118                        if (val)
 119                                hscx_int_main(cs, val);
 120                }
 121                if (!(sval & AVM_A1_STAT_ISAC)) {
 122                        val = readreg(cs->hw.avm.isac, ISAC_ISTA);
 123                        if (val)
 124                                isac_interrupt(cs, val);
 125                }
 126        }
 127        writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0xFF);
 128        writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0xFF);
 129        writereg(cs->hw.avm.isac, ISAC_MASK, 0xFF);
 130        writereg(cs->hw.avm.isac, ISAC_MASK, 0x0);
 131        writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0x0);
 132        writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0x0);
 133        spin_unlock_irqrestore(&cs->lock, flags);
 134        return IRQ_HANDLED;
 135}
 136
 137static inline void
 138release_ioregs(struct IsdnCardState *cs, int mask)
 139{
 140        release_region(cs->hw.avm.cfg_reg, 8);
 141        if (mask & 1)
 142                release_region(cs->hw.avm.isac + 32, 32);
 143        if (mask & 2)
 144                release_region(cs->hw.avm.isacfifo, 1);
 145        if (mask & 4)
 146                release_region(cs->hw.avm.hscx[0] + 32, 32);
 147        if (mask & 8)
 148                release_region(cs->hw.avm.hscxfifo[0], 1);
 149        if (mask & 0x10)
 150                release_region(cs->hw.avm.hscx[1] + 32, 32);
 151        if (mask & 0x20)
 152                release_region(cs->hw.avm.hscxfifo[1], 1);
 153}
 154
 155static int
 156AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 157{
 158        u_long flags;
 159
 160        switch (mt) {
 161        case CARD_RESET:
 162                return (0);
 163        case CARD_RELEASE:
 164                release_ioregs(cs, 0x3f);
 165                return (0);
 166        case CARD_INIT:
 167                spin_lock_irqsave(&cs->lock, flags);
 168                inithscxisac(cs, 1);
 169                byteout(cs->hw.avm.cfg_reg, 0x16);
 170                byteout(cs->hw.avm.cfg_reg, 0x1E);
 171                inithscxisac(cs, 2);
 172                spin_unlock_irqrestore(&cs->lock, flags);
 173                return (0);
 174        case CARD_TEST:
 175                return (0);
 176        }
 177        return (0);
 178}
 179
 180int __devinit
 181setup_avm_a1(struct IsdnCard *card)
 182{
 183        u_char val;
 184        struct IsdnCardState *cs = card->cs;
 185        char tmp[64];
 186
 187        strcpy(tmp, avm_revision);
 188        printk(KERN_INFO "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp));
 189        if (cs->typ != ISDN_CTYPE_A1)
 190                return (0);
 191
 192        cs->hw.avm.cfg_reg = card->para[1] + 0x1800;
 193        cs->hw.avm.isac = card->para[1] + 0x1400 - 0x20;
 194        cs->hw.avm.hscx[0] = card->para[1] + 0x400 - 0x20;
 195        cs->hw.avm.hscx[1] = card->para[1] + 0xc00 - 0x20;
 196        cs->hw.avm.isacfifo = card->para[1] + 0x1000;
 197        cs->hw.avm.hscxfifo[0] = card->para[1];
 198        cs->hw.avm.hscxfifo[1] = card->para[1] + 0x800;
 199        cs->irq = card->para[0];
 200        if (!request_region(cs->hw.avm.cfg_reg, 8, "avm cfg")) {
 201                printk(KERN_WARNING
 202                       "HiSax: AVM A1 config port %x-%x already in use\n",
 203                       cs->hw.avm.cfg_reg,
 204                       cs->hw.avm.cfg_reg + 8);
 205                return (0);
 206        }
 207        if (!request_region(cs->hw.avm.isac + 32, 32, "HiSax isac")) {
 208                printk(KERN_WARNING
 209                       "HiSax: AVM A1 isac ports %x-%x already in use\n",
 210                       cs->hw.avm.isac + 32,
 211                       cs->hw.avm.isac + 64);
 212                release_ioregs(cs, 0);
 213                return (0);
 214        }
 215        if (!request_region(cs->hw.avm.isacfifo, 1, "HiSax isac fifo")) {
 216                printk(KERN_WARNING
 217                       "HiSax: AVM A1 isac fifo port %x already in use\n",
 218                       cs->hw.avm.isacfifo);
 219                release_ioregs(cs, 1);
 220                return (0);
 221        }
 222        if (!request_region(cs->hw.avm.hscx[0] + 32, 32, "HiSax hscx A")) {
 223                printk(KERN_WARNING
 224                       "HiSax: AVM A1 hscx A ports %x-%x already in use\n",
 225                       cs->hw.avm.hscx[0] + 32,
 226                       cs->hw.avm.hscx[0] + 64);
 227                release_ioregs(cs, 3);
 228                return (0);
 229        }
 230        if (!request_region(cs->hw.avm.hscxfifo[0], 1, "HiSax hscx A fifo")) {
 231                printk(KERN_WARNING
 232                       "HiSax: AVM A1 hscx A fifo port %x already in use\n",
 233                       cs->hw.avm.hscxfifo[0]);
 234                release_ioregs(cs, 7);
 235                return (0);
 236        }
 237        if (!request_region(cs->hw.avm.hscx[1] + 32, 32, "HiSax hscx B")) {
 238                printk(KERN_WARNING
 239                       "HiSax: AVM A1 hscx B ports %x-%x already in use\n",
 240                       cs->hw.avm.hscx[1] + 32,
 241                       cs->hw.avm.hscx[1] + 64);
 242                release_ioregs(cs, 0xf);
 243                return (0);
 244        }
 245        if (!request_region(cs->hw.avm.hscxfifo[1], 1, "HiSax hscx B fifo")) {
 246                printk(KERN_WARNING
 247                       "HiSax: AVM A1 hscx B fifo port %x already in use\n",
 248                       cs->hw.avm.hscxfifo[1]);
 249                release_ioregs(cs, 0x1f);
 250                return (0);
 251        }
 252        byteout(cs->hw.avm.cfg_reg, 0x0);
 253        HZDELAY(HZ / 5 + 1);
 254        byteout(cs->hw.avm.cfg_reg, 0x1);
 255        HZDELAY(HZ / 5 + 1);
 256        byteout(cs->hw.avm.cfg_reg, 0x0);
 257        HZDELAY(HZ / 5 + 1);
 258        val = cs->irq;
 259        if (val == 9)
 260                val = 2;
 261        byteout(cs->hw.avm.cfg_reg + 1, val);
 262        HZDELAY(HZ / 5 + 1);
 263        byteout(cs->hw.avm.cfg_reg, 0x0);
 264        HZDELAY(HZ / 5 + 1);
 265
 266        val = bytein(cs->hw.avm.cfg_reg);
 267        printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
 268               cs->hw.avm.cfg_reg, val);
 269        val = bytein(cs->hw.avm.cfg_reg + 3);
 270        printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
 271               cs->hw.avm.cfg_reg + 3, val);
 272        val = bytein(cs->hw.avm.cfg_reg + 2);
 273        printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
 274               cs->hw.avm.cfg_reg + 2, val);
 275        val = bytein(cs->hw.avm.cfg_reg);
 276        printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
 277               cs->hw.avm.cfg_reg, val);
 278
 279        printk(KERN_INFO "HiSax: AVM A1 config irq:%d cfg:0x%X\n",
 280               cs->irq,
 281               cs->hw.avm.cfg_reg);
 282        printk(KERN_INFO
 283               "HiSax: isac:0x%X/0x%X\n",
 284               cs->hw.avm.isac + 32, cs->hw.avm.isacfifo);
 285        printk(KERN_INFO
 286               "HiSax: hscx A:0x%X/0x%X  hscx B:0x%X/0x%X\n",
 287               cs->hw.avm.hscx[0] + 32, cs->hw.avm.hscxfifo[0],
 288               cs->hw.avm.hscx[1] + 32, cs->hw.avm.hscxfifo[1]);
 289
 290        cs->readisac = &ReadISAC;
 291        cs->writeisac = &WriteISAC;
 292        cs->readisacfifo = &ReadISACfifo;
 293        cs->writeisacfifo = &WriteISACfifo;
 294        cs->BC_Read_Reg = &ReadHSCX;
 295        cs->BC_Write_Reg = &WriteHSCX;
 296        cs->BC_Send_Data = &hscx_fill_fifo;
 297        setup_isac(cs);
 298        cs->cardmsg = &AVM_card_msg;
 299        cs->irq_func = &avm_a1_interrupt;
 300        ISACVersion(cs, "AVM A1:");
 301        if (HscxVersion(cs, "AVM A1:")) {
 302                printk(KERN_WARNING
 303                       "AVM A1: wrong HSCX versions check IO address\n");
 304                release_ioregs(cs, 0x3f);
 305                return (0);
 306        }
 307        return (1);
 308}
 309