linux/drivers/isdn/hisax/sportster.c
<<
>>
Prefs
   1/* $Id: sportster.c,v 1.16.2.4 2004/01/13 23:48:39 keil Exp $
   2 *
   3 * low level stuff for USR Sportster internal TA
   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 * Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation
  12 *
  13 *
  14 */
  15#include <linux/init.h>
  16#include "hisax.h"
  17#include "isac.h"
  18#include "hscx.h"
  19#include "isdnl1.h"
  20
  21static const char *sportster_revision = "$Revision: 1.16.2.4 $";
  22
  23#define byteout(addr, val) outb(val, addr)
  24#define bytein(addr) inb(addr)
  25
  26#define  SPORTSTER_ISAC         0xC000
  27#define  SPORTSTER_HSCXA        0x0000
  28#define  SPORTSTER_HSCXB        0x4000
  29#define  SPORTSTER_RES_IRQ      0x8000
  30#define  SPORTSTER_RESET        0x80
  31#define  SPORTSTER_INTE         0x40
  32
  33static inline int
  34calc_off(unsigned int base, unsigned int off)
  35{
  36        return (base + ((off & 0xfc) << 8) + ((off & 3) << 1));
  37}
  38
  39static inline void
  40read_fifo(unsigned int adr, u_char *data, int size)
  41{
  42        insb(adr, data, size);
  43}
  44
  45static void
  46write_fifo(unsigned int adr, u_char *data, int size)
  47{
  48        outsb(adr, data, size);
  49}
  50
  51/* Interface functions */
  52
  53static u_char
  54ReadISAC(struct IsdnCardState *cs, u_char offset)
  55{
  56        return (bytein(calc_off(cs->hw.spt.isac, offset)));
  57}
  58
  59static void
  60WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
  61{
  62        byteout(calc_off(cs->hw.spt.isac, offset), value);
  63}
  64
  65static void
  66ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
  67{
  68        read_fifo(cs->hw.spt.isac, data, size);
  69}
  70
  71static void
  72WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
  73{
  74        write_fifo(cs->hw.spt.isac, data, size);
  75}
  76
  77static u_char
  78ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
  79{
  80        return (bytein(calc_off(cs->hw.spt.hscx[hscx], offset)));
  81}
  82
  83static void
  84WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
  85{
  86        byteout(calc_off(cs->hw.spt.hscx[hscx], offset), value);
  87}
  88
  89/*
  90 * fast interrupt HSCX stuff goes here
  91 */
  92
  93#define READHSCX(cs, nr, reg) bytein(calc_off(cs->hw.spt.hscx[nr], reg))
  94#define WRITEHSCX(cs, nr, reg, data) byteout(calc_off(cs->hw.spt.hscx[nr], reg), data)
  95#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.spt.hscx[nr], ptr, cnt)
  96#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.spt.hscx[nr], ptr, cnt)
  97
  98#include "hscx_irq.c"
  99
 100static irqreturn_t
 101sportster_interrupt(int intno, void *dev_id)
 102{
 103        struct IsdnCardState *cs = dev_id;
 104        u_char val;
 105        u_long flags;
 106
 107        spin_lock_irqsave(&cs->lock, flags);
 108        val = READHSCX(cs, 1, HSCX_ISTA);
 109Start_HSCX:
 110        if (val)
 111                hscx_int_main(cs, val);
 112        val = ReadISAC(cs, ISAC_ISTA);
 113Start_ISAC:
 114        if (val)
 115                isac_interrupt(cs, val);
 116        val = READHSCX(cs, 1, HSCX_ISTA);
 117        if (val) {
 118                if (cs->debug & L1_DEB_HSCX)
 119                        debugl1(cs, "HSCX IntStat after IntRoutine");
 120                goto Start_HSCX;
 121        }
 122        val = ReadISAC(cs, ISAC_ISTA);
 123        if (val) {
 124                if (cs->debug & L1_DEB_ISAC)
 125                        debugl1(cs, "ISAC IntStat after IntRoutine");
 126                goto Start_ISAC;
 127        }
 128        /* get a new irq impulse if there any pending */
 129        bytein(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ + 1);
 130        spin_unlock_irqrestore(&cs->lock, flags);
 131        return IRQ_HANDLED;
 132}
 133
 134static void
 135release_io_sportster(struct IsdnCardState *cs)
 136{
 137        int i, adr;
 138
 139        byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, 0);
 140        for (i = 0; i < 64; i++) {
 141                adr = cs->hw.spt.cfg_reg + i * 1024;
 142                release_region(adr, 8);
 143        }
 144}
 145
 146static void
 147reset_sportster(struct IsdnCardState *cs)
 148{
 149        cs->hw.spt.res_irq |= SPORTSTER_RESET; /* Reset On */
 150        byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
 151        mdelay(10);
 152        cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */
 153        byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
 154        mdelay(10);
 155}
 156
 157static int
 158Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 159{
 160        u_long flags;
 161
 162        switch (mt) {
 163        case CARD_RESET:
 164                spin_lock_irqsave(&cs->lock, flags);
 165                reset_sportster(cs);
 166                spin_unlock_irqrestore(&cs->lock, flags);
 167                return (0);
 168        case CARD_RELEASE:
 169                release_io_sportster(cs);
 170                return (0);
 171        case CARD_INIT:
 172                spin_lock_irqsave(&cs->lock, flags);
 173                reset_sportster(cs);
 174                inithscxisac(cs, 1);
 175                cs->hw.spt.res_irq |= SPORTSTER_INTE; /* IRQ On */
 176                byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
 177                inithscxisac(cs, 2);
 178                spin_unlock_irqrestore(&cs->lock, flags);
 179                return (0);
 180        case CARD_TEST:
 181                return (0);
 182        }
 183        return (0);
 184}
 185
 186static int get_io_range(struct IsdnCardState *cs)
 187{
 188        int i, j, adr;
 189
 190        for (i = 0; i < 64; i++) {
 191                adr = cs->hw.spt.cfg_reg + i * 1024;
 192                if (!request_region(adr, 8, "sportster")) {
 193                        printk(KERN_WARNING "HiSax: USR Sportster config port "
 194                               "%x-%x already in use\n",
 195                               adr, adr + 8);
 196                        break;
 197                }
 198        }
 199        if (i == 64)
 200                return (1);
 201        else {
 202                for (j = 0; j < i; j++) {
 203                        adr = cs->hw.spt.cfg_reg + j * 1024;
 204                        release_region(adr, 8);
 205                }
 206                return (0);
 207        }
 208}
 209
 210int setup_sportster(struct IsdnCard *card)
 211{
 212        struct IsdnCardState *cs = card->cs;
 213        char tmp[64];
 214
 215        strcpy(tmp, sportster_revision);
 216        printk(KERN_INFO "HiSax: USR Sportster driver Rev. %s\n", HiSax_getrev(tmp));
 217        if (cs->typ != ISDN_CTYPE_SPORTSTER)
 218                return (0);
 219
 220        cs->hw.spt.cfg_reg = card->para[1];
 221        cs->irq = card->para[0];
 222        if (!get_io_range(cs))
 223                return (0);
 224        cs->hw.spt.isac = cs->hw.spt.cfg_reg + SPORTSTER_ISAC;
 225        cs->hw.spt.hscx[0] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXA;
 226        cs->hw.spt.hscx[1] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXB;
 227
 228        switch (cs->irq) {
 229        case 5: cs->hw.spt.res_irq = 1;
 230                break;
 231        case 7: cs->hw.spt.res_irq = 2;
 232                break;
 233        case 10:cs->hw.spt.res_irq = 3;
 234                break;
 235        case 11:cs->hw.spt.res_irq = 4;
 236                break;
 237        case 12:cs->hw.spt.res_irq = 5;
 238                break;
 239        case 14:cs->hw.spt.res_irq = 6;
 240                break;
 241        case 15:cs->hw.spt.res_irq = 7;
 242                break;
 243        default:release_io_sportster(cs);
 244                printk(KERN_WARNING "Sportster: wrong IRQ\n");
 245                return (0);
 246        }
 247        printk(KERN_INFO "HiSax: USR Sportster config irq:%d cfg:0x%X\n",
 248               cs->irq, cs->hw.spt.cfg_reg);
 249        setup_isac(cs);
 250        cs->readisac = &ReadISAC;
 251        cs->writeisac = &WriteISAC;
 252        cs->readisacfifo = &ReadISACfifo;
 253        cs->writeisacfifo = &WriteISACfifo;
 254        cs->BC_Read_Reg = &ReadHSCX;
 255        cs->BC_Write_Reg = &WriteHSCX;
 256        cs->BC_Send_Data = &hscx_fill_fifo;
 257        cs->cardmsg = &Sportster_card_msg;
 258        cs->irq_func = &sportster_interrupt;
 259        ISACVersion(cs, "Sportster:");
 260        if (HscxVersion(cs, "Sportster:")) {
 261                printk(KERN_WARNING
 262                       "Sportster: wrong HSCX versions check IO address\n");
 263                release_io_sportster(cs);
 264                return (0);
 265        }
 266        return (1);
 267}
 268