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);
 109      Start_HSCX:
 110        if (val)
 111                hscx_int_main(cs, val);
 112        val = ReadISAC(cs, ISAC_ISTA);
 113      Start_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 __devinit
 187get_io_range(struct IsdnCardState *cs)
 188{
 189        int i, j, adr;
 190        
 191        for (i=0;i<64;i++) {
 192                adr = cs->hw.spt.cfg_reg + i *1024;
 193                if (!request_region(adr, 8, "sportster")) {
 194                        printk(KERN_WARNING "HiSax: USR Sportster config port "
 195                                "%x-%x already in use\n",
 196                                adr, adr + 8);
 197                        break;
 198                } 
 199        }
 200        if (i==64)
 201                return(1);
 202        else {
 203                for (j=0; j<i; j++) {
 204                        adr = cs->hw.spt.cfg_reg + j *1024;
 205                        release_region(adr, 8);
 206                }
 207                return(0);
 208        }
 209}
 210
 211int __devinit
 212setup_sportster(struct IsdnCard *card)
 213{
 214        struct IsdnCardState *cs = card->cs;
 215        char tmp[64];
 216
 217        strcpy(tmp, sportster_revision);
 218        printk(KERN_INFO "HiSax: USR Sportster driver Rev. %s\n", HiSax_getrev(tmp));
 219        if (cs->typ != ISDN_CTYPE_SPORTSTER)
 220                return (0);
 221
 222        cs->hw.spt.cfg_reg = card->para[1];
 223        cs->irq = card->para[0];
 224        if (!get_io_range(cs))
 225                return (0);
 226        cs->hw.spt.isac = cs->hw.spt.cfg_reg + SPORTSTER_ISAC;
 227        cs->hw.spt.hscx[0] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXA;
 228        cs->hw.spt.hscx[1] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXB;
 229        
 230        switch(cs->irq) {
 231                case 5: cs->hw.spt.res_irq = 1;
 232                        break;
 233                case 7: cs->hw.spt.res_irq = 2;
 234                        break;
 235                case 10:cs->hw.spt.res_irq = 3;
 236                        break;
 237                case 11:cs->hw.spt.res_irq = 4;
 238                        break;
 239                case 12:cs->hw.spt.res_irq = 5;
 240                        break;
 241                case 14:cs->hw.spt.res_irq = 6;
 242                        break;
 243                case 15:cs->hw.spt.res_irq = 7;
 244                        break;
 245                default:release_io_sportster(cs);
 246                        printk(KERN_WARNING "Sportster: wrong IRQ\n");
 247                        return(0);
 248        }
 249        printk(KERN_INFO "HiSax: USR Sportster config irq:%d cfg:0x%X\n",
 250                cs->irq, cs->hw.spt.cfg_reg);
 251        setup_isac(cs);
 252        cs->readisac = &ReadISAC;
 253        cs->writeisac = &WriteISAC;
 254        cs->readisacfifo = &ReadISACfifo;
 255        cs->writeisacfifo = &WriteISACfifo;
 256        cs->BC_Read_Reg = &ReadHSCX;
 257        cs->BC_Write_Reg = &WriteHSCX;
 258        cs->BC_Send_Data = &hscx_fill_fifo;
 259        cs->cardmsg = &Sportster_card_msg;
 260        cs->irq_func = &sportster_interrupt;
 261        ISACVersion(cs, "Sportster:");
 262        if (HscxVersion(cs, "Sportster:")) {
 263                printk(KERN_WARNING
 264                       "Sportster: wrong HSCX versions check IO address\n");
 265                release_io_sportster(cs);
 266                return (0);
 267        }
 268        return (1);
 269}
 270