linux/drivers/isdn/hisax/isurf.c
<<
>>
Prefs
   1/* $Id: isurf.c,v 1.12.2.4 2004/01/13 21:46:03 keil Exp $
   2 *
   3 * low level stuff for Siemens I-Surf/I-Talk 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 "isar.h"
  17#include "isdnl1.h"
  18#include <linux/isapnp.h>
  19
  20static const char *ISurf_revision = "$Revision: 1.12.2.4 $";
  21
  22#define byteout(addr,val) outb(val,addr)
  23#define bytein(addr) inb(addr)
  24
  25#define ISURF_ISAR_RESET        1
  26#define ISURF_ISAC_RESET        2
  27#define ISURF_ISAR_EA           4
  28#define ISURF_ARCOFI_RESET      8
  29#define ISURF_RESET (ISURF_ISAR_RESET | ISURF_ISAC_RESET | ISURF_ARCOFI_RESET)
  30
  31#define ISURF_ISAR_OFFSET       0
  32#define ISURF_ISAC_OFFSET       0x100
  33#define ISURF_IOMEM_SIZE        0x400
  34/* Interface functions */
  35
  36static u_char
  37ReadISAC(struct IsdnCardState *cs, u_char offset)
  38{
  39        return (readb(cs->hw.isurf.isac + offset));
  40}
  41
  42static void
  43WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
  44{
  45        writeb(value, cs->hw.isurf.isac + offset); mb();
  46}
  47
  48static void
  49ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
  50{
  51        register int i;
  52        for (i = 0; i < size; i++)
  53                data[i] = readb(cs->hw.isurf.isac);
  54}
  55
  56static void
  57WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
  58{
  59        register int i;
  60        for (i = 0; i < size; i++){
  61                writeb(data[i], cs->hw.isurf.isac);mb();
  62        }
  63}
  64
  65/* ISAR access routines
  66 * mode = 0 access with IRQ on
  67 * mode = 1 access with IRQ off
  68 * mode = 2 access with IRQ off and using last offset
  69 */
  70  
  71static u_char
  72ReadISAR(struct IsdnCardState *cs, int mode, u_char offset)
  73{       
  74        return(readb(cs->hw.isurf.isar + offset));
  75}
  76
  77static void
  78WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value)
  79{
  80        writeb(value, cs->hw.isurf.isar + offset);mb();
  81}
  82
  83static irqreturn_t
  84isurf_interrupt(int intno, void *dev_id)
  85{
  86        struct IsdnCardState *cs = dev_id;
  87        u_char val;
  88        int cnt = 5;
  89        u_long flags;
  90
  91        spin_lock_irqsave(&cs->lock, flags);
  92        val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
  93      Start_ISAR:
  94        if (val & ISAR_IRQSTA)
  95                isar_int_main(cs);
  96        val = readb(cs->hw.isurf.isac + ISAC_ISTA);
  97      Start_ISAC:
  98        if (val)
  99                isac_interrupt(cs, val);
 100        val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
 101        if ((val & ISAR_IRQSTA) && --cnt) {
 102                if (cs->debug & L1_DEB_HSCX)
 103                        debugl1(cs, "ISAR IntStat after IntRoutine");
 104                goto Start_ISAR;
 105        }
 106        val = readb(cs->hw.isurf.isac + ISAC_ISTA);
 107        if (val && --cnt) {
 108                if (cs->debug & L1_DEB_ISAC)
 109                        debugl1(cs, "ISAC IntStat after IntRoutine");
 110                goto Start_ISAC;
 111        }
 112        if (!cnt)
 113                printk(KERN_WARNING "ISurf IRQ LOOP\n");
 114
 115        writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
 116        writeb(0xFF, cs->hw.isurf.isac + ISAC_MASK);mb();
 117        writeb(0, cs->hw.isurf.isac + ISAC_MASK);mb();
 118        writeb(ISAR_IRQMSK, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
 119        spin_unlock_irqrestore(&cs->lock, flags);
 120        return IRQ_HANDLED;
 121}
 122
 123static void
 124release_io_isurf(struct IsdnCardState *cs)
 125{
 126        release_region(cs->hw.isurf.reset, 1);
 127        iounmap(cs->hw.isurf.isar);
 128        release_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
 129}
 130
 131static void
 132reset_isurf(struct IsdnCardState *cs, u_char chips)
 133{
 134        printk(KERN_INFO "ISurf: resetting card\n");
 135
 136        byteout(cs->hw.isurf.reset, chips); /* Reset On */
 137        mdelay(10);
 138        byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */
 139        mdelay(10);
 140}
 141
 142static int
 143ISurf_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 144{
 145        u_long flags;
 146
 147        switch (mt) {
 148                case CARD_RESET:
 149                        spin_lock_irqsave(&cs->lock, flags);
 150                        reset_isurf(cs, ISURF_RESET);
 151                        spin_unlock_irqrestore(&cs->lock, flags);
 152                        return(0);
 153                case CARD_RELEASE:
 154                        release_io_isurf(cs);
 155                        return(0);
 156                case CARD_INIT:
 157                        spin_lock_irqsave(&cs->lock, flags);
 158                        reset_isurf(cs, ISURF_RESET);
 159                        clear_pending_isac_ints(cs);
 160                        writeb(0, cs->hw.isurf.isar+ISAR_IRQBIT);mb();
 161                        initisac(cs);
 162                        initisar(cs);
 163                        /* Reenable ISAC IRQ */
 164                        cs->writeisac(cs, ISAC_MASK, 0);
 165                        /* RESET Receiver and Transmitter */
 166                        cs->writeisac(cs, ISAC_CMDR, 0x41);
 167                        spin_unlock_irqrestore(&cs->lock, flags);
 168                        return(0);
 169                case CARD_TEST:
 170                        return(0);
 171        }
 172        return(0);
 173}
 174
 175static int
 176isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
 177        int ret;
 178        u_long flags;
 179
 180        if ((ic->command == ISDN_CMD_IOCTL) && (ic->arg == 9)) {
 181                ret = isar_auxcmd(cs, ic);
 182                spin_lock_irqsave(&cs->lock, flags);
 183                if (!ret) {
 184                        reset_isurf(cs, ISURF_ISAR_EA | ISURF_ISAC_RESET |
 185                                ISURF_ARCOFI_RESET);
 186                        initisac(cs);
 187                        cs->writeisac(cs, ISAC_MASK, 0);
 188                        cs->writeisac(cs, ISAC_CMDR, 0x41);
 189                }
 190                spin_unlock_irqrestore(&cs->lock, flags);
 191                return(ret);
 192        }
 193        return(isar_auxcmd(cs, ic));
 194}
 195
 196#ifdef __ISAPNP__
 197static struct pnp_card *pnp_c __devinitdata = NULL;
 198#endif
 199
 200int __devinit
 201setup_isurf(struct IsdnCard *card)
 202{
 203        int ver;
 204        struct IsdnCardState *cs = card->cs;
 205        char tmp[64];
 206
 207        strcpy(tmp, ISurf_revision);
 208        printk(KERN_INFO "HiSax: ISurf driver Rev. %s\n", HiSax_getrev(tmp));
 209        
 210        if (cs->typ != ISDN_CTYPE_ISURF)
 211                return(0);
 212        if (card->para[1] && card->para[2]) {
 213                cs->hw.isurf.reset = card->para[1];
 214                cs->hw.isurf.phymem = card->para[2];
 215                cs->irq = card->para[0];
 216        } else {
 217#ifdef __ISAPNP__
 218                if (isapnp_present()) {
 219                        struct pnp_dev *pnp_d = NULL;
 220                        int err;
 221
 222                        cs->subtyp = 0;
 223                        if ((pnp_c = pnp_find_card(
 224                                ISAPNP_VENDOR('S', 'I', 'E'),
 225                                ISAPNP_FUNCTION(0x0010), pnp_c))) {
 226                                if (!(pnp_d = pnp_find_dev(pnp_c,
 227                                        ISAPNP_VENDOR('S', 'I', 'E'),
 228                                        ISAPNP_FUNCTION(0x0010), pnp_d))) {
 229                                        printk(KERN_ERR "ISurfPnP: PnP error card found, no device\n");
 230                                        return (0);
 231                                }
 232                                pnp_disable_dev(pnp_d);
 233                                err = pnp_activate_dev(pnp_d);
 234                                cs->hw.isurf.reset = pnp_port_start(pnp_d, 0);
 235                                cs->hw.isurf.phymem = pnp_mem_start(pnp_d, 1);
 236                                cs->irq = pnp_irq(pnp_d, 0);
 237                                if (!cs->irq || !cs->hw.isurf.reset || !cs->hw.isurf.phymem) {
 238                                        printk(KERN_ERR "ISurfPnP:some resources are missing %d/%x/%lx\n",
 239                                                cs->irq, cs->hw.isurf.reset, cs->hw.isurf.phymem);
 240                                        pnp_disable_dev(pnp_d);
 241                                        return(0);
 242                                }
 243                        } else {
 244                                printk(KERN_INFO "ISurfPnP: no ISAPnP card found\n");
 245                                return(0);
 246                        }
 247                } else {
 248                        printk(KERN_INFO "ISurfPnP: no ISAPnP bus found\n");
 249                        return(0);
 250                }
 251#else
 252                printk(KERN_WARNING "HiSax: Siemens I-Surf port/mem not set\n");
 253                return (0);
 254#endif
 255        }
 256        if (!request_region(cs->hw.isurf.reset, 1, "isurf isdn")) {
 257                printk(KERN_WARNING
 258                        "HiSax: Siemens I-Surf config port %x already in use\n",
 259                        cs->hw.isurf.reset);
 260                        return (0);
 261        }
 262        if (!request_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE, "isurf iomem")) {
 263                printk(KERN_WARNING "HiSax: Siemens I-Surf memory region "
 264                        "%lx-%lx already in use\n",
 265                        cs->hw.isurf.phymem,
 266                        cs->hw.isurf.phymem + ISURF_IOMEM_SIZE);
 267                release_region(cs->hw.isurf.reset, 1);
 268                return (0);
 269        }
 270        cs->hw.isurf.isar = ioremap(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
 271        cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET;
 272        printk(KERN_INFO
 273               "ISurf: defined at 0x%x 0x%lx IRQ %d\n",
 274               cs->hw.isurf.reset,
 275               cs->hw.isurf.phymem,
 276               cs->irq);
 277
 278        setup_isac(cs);
 279        cs->cardmsg = &ISurf_card_msg;
 280        cs->irq_func = &isurf_interrupt;
 281        cs->auxcmd = &isurf_auxcmd;
 282        cs->readisac = &ReadISAC;
 283        cs->writeisac = &WriteISAC;
 284        cs->readisacfifo = &ReadISACfifo;
 285        cs->writeisacfifo = &WriteISACfifo;
 286        cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r;
 287        cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r;
 288        test_and_set_bit(HW_ISAR, &cs->HW_Flags);
 289        ISACVersion(cs, "ISurf:");
 290        cs->BC_Read_Reg = &ReadISAR;
 291        cs->BC_Write_Reg = &WriteISAR;
 292        cs->BC_Send_Data = &isar_fill_fifo;
 293        ver = ISARVersion(cs, "ISurf:");
 294        if (ver < 0) {
 295                printk(KERN_WARNING
 296                        "ISurf: wrong ISAR version (ret = %d)\n", ver);
 297                release_io_isurf(cs);
 298                return (0);
 299        }
 300        return (1);
 301}
 302