linux/drivers/isdn/hisax/teles0.c
<<
>>
Prefs
   1/* $Id: teles0.c,v 2.15.2.4 2004/01/13 23:48:39 keil Exp $
   2 *
   3 * low level stuff for Teles Memory IO isdn cards
   4 *
   5 * Author       Karsten Keil
   6 *              based on the teles driver from Jan den Ouden
   7 * Copyright    by Karsten Keil      <keil@isdn4linux.de>
   8 *
   9 * This software may be used and distributed according to the terms
  10 * of the GNU General Public License, incorporated herein by reference.
  11 *
  12 * Thanks to    Jan den Ouden
  13 *              Fritz Elfert
  14 *              Beat Doebeli
  15 *
  16 */
  17
  18#include <linux/init.h>
  19#include "hisax.h"
  20#include "isdnl1.h"
  21#include "isac.h"
  22#include "hscx.h"
  23
  24static const char *teles0_revision = "$Revision: 2.15.2.4 $";
  25
  26#define TELES_IOMEM_SIZE        0x400
  27#define byteout(addr, val) outb(val, addr)
  28#define bytein(addr) inb(addr)
  29
  30static inline u_char
  31readisac(void __iomem *adr, u_char off)
  32{
  33        return readb(adr + ((off & 1) ? 0x2ff : 0x100) + off);
  34}
  35
  36static inline void
  37writeisac(void __iomem *adr, u_char off, u_char data)
  38{
  39        writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off); mb();
  40}
  41
  42
  43static inline u_char
  44readhscx(void __iomem *adr, int hscx, u_char off)
  45{
  46        return readb(adr + (hscx ? 0x1c0 : 0x180) +
  47                     ((off & 1) ? 0x1ff : 0) + off);
  48}
  49
  50static inline void
  51writehscx(void __iomem *adr, int hscx, u_char off, u_char data)
  52{
  53        writeb(data, adr + (hscx ? 0x1c0 : 0x180) +
  54               ((off & 1) ? 0x1ff : 0) + off); mb();
  55}
  56
  57static inline void
  58read_fifo_isac(void __iomem *adr, u_char *data, int size)
  59{
  60        register int i;
  61        register u_char __iomem *ad = adr + 0x100;
  62        for (i = 0; i < size; i++)
  63                data[i] = readb(ad);
  64}
  65
  66static inline void
  67write_fifo_isac(void __iomem *adr, u_char *data, int size)
  68{
  69        register int i;
  70        register u_char __iomem *ad = adr + 0x100;
  71        for (i = 0; i < size; i++) {
  72                writeb(data[i], ad); mb();
  73        }
  74}
  75
  76static inline void
  77read_fifo_hscx(void __iomem *adr, int hscx, u_char *data, int size)
  78{
  79        register int i;
  80        register u_char __iomem *ad = adr + (hscx ? 0x1c0 : 0x180);
  81        for (i = 0; i < size; i++)
  82                data[i] = readb(ad);
  83}
  84
  85static inline void
  86write_fifo_hscx(void __iomem *adr, int hscx, u_char *data, int size)
  87{
  88        int i;
  89        register u_char __iomem *ad = adr + (hscx ? 0x1c0 : 0x180);
  90        for (i = 0; i < size; i++) {
  91                writeb(data[i], ad); mb();
  92        }
  93}
  94
  95/* Interface functions */
  96
  97static u_char
  98ReadISAC(struct IsdnCardState *cs, u_char offset)
  99{
 100        return (readisac(cs->hw.teles0.membase, offset));
 101}
 102
 103static void
 104WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 105{
 106        writeisac(cs->hw.teles0.membase, offset, value);
 107}
 108
 109static void
 110ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
 111{
 112        read_fifo_isac(cs->hw.teles0.membase, data, size);
 113}
 114
 115static void
 116WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
 117{
 118        write_fifo_isac(cs->hw.teles0.membase, data, size);
 119}
 120
 121static u_char
 122ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 123{
 124        return (readhscx(cs->hw.teles0.membase, hscx, offset));
 125}
 126
 127static void
 128WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 129{
 130        writehscx(cs->hw.teles0.membase, hscx, offset, value);
 131}
 132
 133/*
 134 * fast interrupt HSCX stuff goes here
 135 */
 136
 137#define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg)
 138#define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data)
 139#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
 140#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
 141
 142#include "hscx_irq.c"
 143
 144static irqreturn_t
 145teles0_interrupt(int intno, void *dev_id)
 146{
 147        struct IsdnCardState *cs = dev_id;
 148        u_char val;
 149        u_long flags;
 150        int count = 0;
 151
 152        spin_lock_irqsave(&cs->lock, flags);
 153        val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
 154Start_HSCX:
 155        if (val)
 156                hscx_int_main(cs, val);
 157        val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
 158Start_ISAC:
 159        if (val)
 160                isac_interrupt(cs, val);
 161        count++;
 162        val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
 163        if (val && count < 5) {
 164                if (cs->debug & L1_DEB_HSCX)
 165                        debugl1(cs, "HSCX IntStat after IntRoutine");
 166                goto Start_HSCX;
 167        }
 168        val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
 169        if (val && count < 5) {
 170                if (cs->debug & L1_DEB_ISAC)
 171                        debugl1(cs, "ISAC IntStat after IntRoutine");
 172                goto Start_ISAC;
 173        }
 174        writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF);
 175        writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF);
 176        writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF);
 177        writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0);
 178        writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0);
 179        writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0);
 180        spin_unlock_irqrestore(&cs->lock, flags);
 181        return IRQ_HANDLED;
 182}
 183
 184static void
 185release_io_teles0(struct IsdnCardState *cs)
 186{
 187        if (cs->hw.teles0.cfg_reg)
 188                release_region(cs->hw.teles0.cfg_reg, 8);
 189        iounmap(cs->hw.teles0.membase);
 190        release_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE);
 191}
 192
 193static int
 194reset_teles0(struct IsdnCardState *cs)
 195{
 196        u_char cfval;
 197
 198        if (cs->hw.teles0.cfg_reg) {
 199                switch (cs->irq) {
 200                case 2:
 201                case 9:
 202                        cfval = 0x00;
 203                        break;
 204                case 3:
 205                        cfval = 0x02;
 206                        break;
 207                case 4:
 208                        cfval = 0x04;
 209                        break;
 210                case 5:
 211                        cfval = 0x06;
 212                        break;
 213                case 10:
 214                        cfval = 0x08;
 215                        break;
 216                case 11:
 217                        cfval = 0x0A;
 218                        break;
 219                case 12:
 220                        cfval = 0x0C;
 221                        break;
 222                case 15:
 223                        cfval = 0x0E;
 224                        break;
 225                default:
 226                        return (1);
 227                }
 228                cfval |= ((cs->hw.teles0.phymem >> 9) & 0xF0);
 229                byteout(cs->hw.teles0.cfg_reg + 4, cfval);
 230                HZDELAY(HZ / 10 + 1);
 231                byteout(cs->hw.teles0.cfg_reg + 4, cfval | 1);
 232                HZDELAY(HZ / 10 + 1);
 233        }
 234        writeb(0, cs->hw.teles0.membase + 0x80); mb();
 235        HZDELAY(HZ / 5 + 1);
 236        writeb(1, cs->hw.teles0.membase + 0x80); mb();
 237        HZDELAY(HZ / 5 + 1);
 238        return (0);
 239}
 240
 241static int
 242Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 243{
 244        u_long flags;
 245
 246        switch (mt) {
 247        case CARD_RESET:
 248                spin_lock_irqsave(&cs->lock, flags);
 249                reset_teles0(cs);
 250                spin_unlock_irqrestore(&cs->lock, flags);
 251                return (0);
 252        case CARD_RELEASE:
 253                release_io_teles0(cs);
 254                return (0);
 255        case CARD_INIT:
 256                spin_lock_irqsave(&cs->lock, flags);
 257                inithscxisac(cs, 3);
 258                spin_unlock_irqrestore(&cs->lock, flags);
 259                return (0);
 260        case CARD_TEST:
 261                return (0);
 262        }
 263        return (0);
 264}
 265
 266int setup_teles0(struct IsdnCard *card)
 267{
 268        u_char val;
 269        struct IsdnCardState *cs = card->cs;
 270        char tmp[64];
 271
 272        strcpy(tmp, teles0_revision);
 273        printk(KERN_INFO "HiSax: Teles 8.0/16.0 driver Rev. %s\n", HiSax_getrev(tmp));
 274        if ((cs->typ != ISDN_CTYPE_16_0) && (cs->typ != ISDN_CTYPE_8_0))
 275                return (0);
 276
 277        if (cs->typ == ISDN_CTYPE_16_0)
 278                cs->hw.teles0.cfg_reg = card->para[2];
 279        else                    /* 8.0 */
 280                cs->hw.teles0.cfg_reg = 0;
 281
 282        if (card->para[1] < 0x10000) {
 283                card->para[1] <<= 4;
 284                printk(KERN_INFO
 285                       "Teles0: membase configured DOSish, assuming 0x%lx\n",
 286                       (unsigned long) card->para[1]);
 287        }
 288        cs->irq = card->para[0];
 289        if (cs->hw.teles0.cfg_reg) {
 290                if (!request_region(cs->hw.teles0.cfg_reg, 8, "teles cfg")) {
 291                        printk(KERN_WARNING
 292                               "HiSax: %s config port %x-%x already in use\n",
 293                               CardType[card->typ],
 294                               cs->hw.teles0.cfg_reg,
 295                               cs->hw.teles0.cfg_reg + 8);
 296                        return (0);
 297                }
 298        }
 299        if (cs->hw.teles0.cfg_reg) {
 300                if ((val = bytein(cs->hw.teles0.cfg_reg + 0)) != 0x51) {
 301                        printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
 302                               cs->hw.teles0.cfg_reg + 0, val);
 303                        release_region(cs->hw.teles0.cfg_reg, 8);
 304                        return (0);
 305                }
 306                if ((val = bytein(cs->hw.teles0.cfg_reg + 1)) != 0x93) {
 307                        printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
 308                               cs->hw.teles0.cfg_reg + 1, val);
 309                        release_region(cs->hw.teles0.cfg_reg, 8);
 310                        return (0);
 311                }
 312                val = bytein(cs->hw.teles0.cfg_reg + 2);        /* 0x1e=without AB
 313                                                                 * 0x1f=with AB
 314                                                                 * 0x1c 16.3 ???
 315                                                                 */
 316                if (val != 0x1e && val != 0x1f) {
 317                        printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
 318                               cs->hw.teles0.cfg_reg + 2, val);
 319                        release_region(cs->hw.teles0.cfg_reg, 8);
 320                        return (0);
 321                }
 322        }
 323        /* 16.0 and 8.0 designed for IOM1 */
 324        test_and_set_bit(HW_IOM1, &cs->HW_Flags);
 325        cs->hw.teles0.phymem = card->para[1];
 326        if (!request_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE, "teles iomem")) {
 327                printk(KERN_WARNING
 328                       "HiSax: %s memory region %lx-%lx already in use\n",
 329                       CardType[card->typ],
 330                       cs->hw.teles0.phymem,
 331                       cs->hw.teles0.phymem + TELES_IOMEM_SIZE);
 332                if (cs->hw.teles0.cfg_reg)
 333                        release_region(cs->hw.teles0.cfg_reg, 8);
 334                return (0);
 335        }
 336        cs->hw.teles0.membase = ioremap(cs->hw.teles0.phymem, TELES_IOMEM_SIZE);
 337        printk(KERN_INFO
 338               "HiSax: %s config irq:%d mem:%p cfg:0x%X\n",
 339               CardType[cs->typ], cs->irq,
 340               cs->hw.teles0.membase, cs->hw.teles0.cfg_reg);
 341        if (reset_teles0(cs)) {
 342                printk(KERN_WARNING "Teles0: wrong IRQ\n");
 343                release_io_teles0(cs);
 344                return (0);
 345        }
 346        setup_isac(cs);
 347        cs->readisac = &ReadISAC;
 348        cs->writeisac = &WriteISAC;
 349        cs->readisacfifo = &ReadISACfifo;
 350        cs->writeisacfifo = &WriteISACfifo;
 351        cs->BC_Read_Reg = &ReadHSCX;
 352        cs->BC_Write_Reg = &WriteHSCX;
 353        cs->BC_Send_Data = &hscx_fill_fifo;
 354        cs->cardmsg = &Teles_card_msg;
 355        cs->irq_func = &teles0_interrupt;
 356        ISACVersion(cs, "Teles0:");
 357        if (HscxVersion(cs, "Teles0:")) {
 358                printk(KERN_WARNING
 359                       "Teles0: wrong HSCX versions check IO/MEM addresses\n");
 360                release_io_teles0(cs);
 361                return (0);
 362        }
 363        return (1);
 364}
 365