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 setup_avm_a1(struct IsdnCard *card)
 181{
 182        u_char val;
 183        struct IsdnCardState *cs = card->cs;
 184        char tmp[64];
 185
 186        strcpy(tmp, avm_revision);
 187        printk(KERN_INFO "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp));
 188        if (cs->typ != ISDN_CTYPE_A1)
 189                return (0);
 190
 191        cs->hw.avm.cfg_reg = card->para[1] + 0x1800;
 192        cs->hw.avm.isac = card->para[1] + 0x1400 - 0x20;
 193        cs->hw.avm.hscx[0] = card->para[1] + 0x400 - 0x20;
 194        cs->hw.avm.hscx[1] = card->para[1] + 0xc00 - 0x20;
 195        cs->hw.avm.isacfifo = card->para[1] + 0x1000;
 196        cs->hw.avm.hscxfifo[0] = card->para[1];
 197        cs->hw.avm.hscxfifo[1] = card->para[1] + 0x800;
 198        cs->irq = card->para[0];
 199        if (!request_region(cs->hw.avm.cfg_reg, 8, "avm cfg")) {
 200                printk(KERN_WARNING
 201                       "HiSax: AVM A1 config port %x-%x already in use\n",
 202                       cs->hw.avm.cfg_reg,
 203                       cs->hw.avm.cfg_reg + 8);
 204                return (0);
 205        }
 206        if (!request_region(cs->hw.avm.isac + 32, 32, "HiSax isac")) {
 207                printk(KERN_WARNING
 208                       "HiSax: AVM A1 isac ports %x-%x already in use\n",
 209                       cs->hw.avm.isac + 32,
 210                       cs->hw.avm.isac + 64);
 211                release_ioregs(cs, 0);
 212                return (0);
 213        }
 214        if (!request_region(cs->hw.avm.isacfifo, 1, "HiSax isac fifo")) {
 215                printk(KERN_WARNING
 216                       "HiSax: AVM A1 isac fifo port %x already in use\n",
 217                       cs->hw.avm.isacfifo);
 218                release_ioregs(cs, 1);
 219                return (0);
 220        }
 221        if (!request_region(cs->hw.avm.hscx[0] + 32, 32, "HiSax hscx A")) {
 222                printk(KERN_WARNING
 223                       "HiSax: AVM A1 hscx A ports %x-%x already in use\n",
 224                       cs->hw.avm.hscx[0] + 32,
 225                       cs->hw.avm.hscx[0] + 64);
 226                release_ioregs(cs, 3);
 227                return (0);
 228        }
 229        if (!request_region(cs->hw.avm.hscxfifo[0], 1, "HiSax hscx A fifo")) {
 230                printk(KERN_WARNING
 231                       "HiSax: AVM A1 hscx A fifo port %x already in use\n",
 232                       cs->hw.avm.hscxfifo[0]);
 233                release_ioregs(cs, 7);
 234                return (0);
 235        }
 236        if (!request_region(cs->hw.avm.hscx[1] + 32, 32, "HiSax hscx B")) {
 237                printk(KERN_WARNING
 238                       "HiSax: AVM A1 hscx B ports %x-%x already in use\n",
 239                       cs->hw.avm.hscx[1] + 32,
 240                       cs->hw.avm.hscx[1] + 64);
 241                release_ioregs(cs, 0xf);
 242                return (0);
 243        }
 244        if (!request_region(cs->hw.avm.hscxfifo[1], 1, "HiSax hscx B fifo")) {
 245                printk(KERN_WARNING
 246                       "HiSax: AVM A1 hscx B fifo port %x already in use\n",
 247                       cs->hw.avm.hscxfifo[1]);
 248                release_ioregs(cs, 0x1f);
 249                return (0);
 250        }
 251        byteout(cs->hw.avm.cfg_reg, 0x0);
 252        HZDELAY(HZ / 5 + 1);
 253        byteout(cs->hw.avm.cfg_reg, 0x1);
 254        HZDELAY(HZ / 5 + 1);
 255        byteout(cs->hw.avm.cfg_reg, 0x0);
 256        HZDELAY(HZ / 5 + 1);
 257        val = cs->irq;
 258        if (val == 9)
 259                val = 2;
 260        byteout(cs->hw.avm.cfg_reg + 1, val);
 261        HZDELAY(HZ / 5 + 1);
 262        byteout(cs->hw.avm.cfg_reg, 0x0);
 263        HZDELAY(HZ / 5 + 1);
 264
 265        val = bytein(cs->hw.avm.cfg_reg);
 266        printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
 267               cs->hw.avm.cfg_reg, val);
 268        val = bytein(cs->hw.avm.cfg_reg + 3);
 269        printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
 270               cs->hw.avm.cfg_reg + 3, val);
 271        val = bytein(cs->hw.avm.cfg_reg + 2);
 272        printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
 273               cs->hw.avm.cfg_reg + 2, val);
 274        val = bytein(cs->hw.avm.cfg_reg);
 275        printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
 276               cs->hw.avm.cfg_reg, val);
 277
 278        printk(KERN_INFO "HiSax: AVM A1 config irq:%d cfg:0x%X\n",
 279               cs->irq,
 280               cs->hw.avm.cfg_reg);
 281        printk(KERN_INFO
 282               "HiSax: isac:0x%X/0x%X\n",
 283               cs->hw.avm.isac + 32, cs->hw.avm.isacfifo);
 284        printk(KERN_INFO
 285               "HiSax: hscx A:0x%X/0x%X  hscx B:0x%X/0x%X\n",
 286               cs->hw.avm.hscx[0] + 32, cs->hw.avm.hscxfifo[0],
 287               cs->hw.avm.hscx[1] + 32, cs->hw.avm.hscxfifo[1]);
 288
 289        cs->readisac = &ReadISAC;
 290        cs->writeisac = &WriteISAC;
 291        cs->readisacfifo = &ReadISACfifo;
 292        cs->writeisacfifo = &WriteISACfifo;
 293        cs->BC_Read_Reg = &ReadHSCX;
 294        cs->BC_Write_Reg = &WriteHSCX;
 295        cs->BC_Send_Data = &hscx_fill_fifo;
 296        setup_isac(cs);
 297        cs->cardmsg = &AVM_card_msg;
 298        cs->irq_func = &avm_a1_interrupt;
 299        ISACVersion(cs, "AVM A1:");
 300        if (HscxVersion(cs, "AVM A1:")) {
 301                printk(KERN_WARNING
 302                       "AVM A1: wrong HSCX versions check IO address\n");
 303                release_ioregs(cs, 0x3f);
 304                return (0);
 305        }
 306        return (1);
 307}
 308