linux/drivers/isdn/hisax/ix1_micro.c
<<
>>
Prefs
   1/* $Id: ix1_micro.c,v 2.12.2.4 2004/01/13 23:48:39 keil Exp $
   2 *
   3 * low level stuff for ITK ix1-micro Rev.2 isdn cards
   4 * derived from the original file teles3.c from Karsten Keil
   5 *
   6 * Author       Klaus-Peter Nischke
   7 * Copyright    by Klaus-Peter Nischke, ITK AG
   8 *                                   <klaus@nischke.do.eunet.de>
   9 *              by Karsten Keil      <keil@isdn4linux.de>
  10 * 
  11 * This software may be used and distributed according to the terms
  12 * of the GNU General Public License, incorporated herein by reference.
  13 *
  14 * Klaus-Peter Nischke
  15 * Deusener Str. 287
  16 * 44369 Dortmund
  17 * Germany
  18 */
  19
  20#include <linux/init.h>
  21#include <linux/isapnp.h>
  22#include "hisax.h"
  23#include "isac.h"
  24#include "hscx.h"
  25#include "isdnl1.h"
  26
  27extern const char *CardType[];
  28static const char *ix1_revision = "$Revision: 2.12.2.4 $";
  29
  30#define byteout(addr,val) outb(val,addr)
  31#define bytein(addr) inb(addr)
  32
  33#define SPECIAL_PORT_OFFSET 3
  34
  35#define ISAC_COMMAND_OFFSET 2
  36#define ISAC_DATA_OFFSET 0
  37#define HSCX_COMMAND_OFFSET 2
  38#define HSCX_DATA_OFFSET 1
  39
  40#define TIMEOUT 50
  41
  42static inline u_char
  43readreg(unsigned int ale, unsigned int adr, u_char off)
  44{
  45        register u_char ret;
  46
  47        byteout(ale, off);
  48        ret = bytein(adr);
  49        return (ret);
  50}
  51
  52static inline void
  53readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
  54{
  55        byteout(ale, off);
  56        insb(adr, data, size);
  57}
  58
  59
  60static inline void
  61writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
  62{
  63        byteout(ale, off);
  64        byteout(adr, data);
  65}
  66
  67static inline void
  68writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
  69{
  70        byteout(ale, off);
  71        outsb(adr, data, size);
  72}
  73
  74/* Interface functions */
  75
  76static u_char
  77ReadISAC(struct IsdnCardState *cs, u_char offset)
  78{
  79        return (readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset));
  80}
  81
  82static void
  83WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
  84{
  85        writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset, value);
  86}
  87
  88static void
  89ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
  90{
  91        readfifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size);
  92}
  93
  94static void
  95WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
  96{
  97        writefifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size);
  98}
  99
 100static u_char
 101ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 102{
 103        return (readreg(cs->hw.ix1.hscx_ale,
 104                        cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0)));
 105}
 106
 107static void
 108WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 109{
 110        writereg(cs->hw.ix1.hscx_ale,
 111                 cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0), value);
 112}
 113
 114#define READHSCX(cs, nr, reg) readreg(cs->hw.ix1.hscx_ale, \
 115                cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0))
 116#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ix1.hscx_ale, \
 117                cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0), data)
 118
 119#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ix1.hscx_ale, \
 120                cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt)
 121
 122#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ix1.hscx_ale, \
 123                cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt)
 124
 125#include "hscx_irq.c"
 126
 127static irqreturn_t
 128ix1micro_interrupt(int intno, void *dev_id)
 129{
 130        struct IsdnCardState *cs = dev_id;
 131        u_char val;
 132        u_long flags;
 133
 134        spin_lock_irqsave(&cs->lock, flags);
 135        val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
 136      Start_HSCX:
 137        if (val)
 138                hscx_int_main(cs, val);
 139        val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA);
 140      Start_ISAC:
 141        if (val)
 142                isac_interrupt(cs, val);
 143        val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
 144        if (val) {
 145                if (cs->debug & L1_DEB_HSCX)
 146                        debugl1(cs, "HSCX IntStat after IntRoutine");
 147                goto Start_HSCX;
 148        }
 149        val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA);
 150        if (val) {
 151                if (cs->debug & L1_DEB_ISAC)
 152                        debugl1(cs, "ISAC IntStat after IntRoutine");
 153                goto Start_ISAC;
 154        }
 155        writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0xFF);
 156        writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0xFF);
 157        writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0xFF);
 158        writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0);
 159        writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0);
 160        writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0);
 161        spin_unlock_irqrestore(&cs->lock, flags);
 162        return IRQ_HANDLED;
 163}
 164
 165static void
 166release_io_ix1micro(struct IsdnCardState *cs)
 167{
 168        if (cs->hw.ix1.cfg_reg)
 169                release_region(cs->hw.ix1.cfg_reg, 4);
 170}
 171
 172static void
 173ix1_reset(struct IsdnCardState *cs)
 174{
 175        int cnt;
 176
 177        /* reset isac */
 178        cnt = 3 * (HZ / 10) + 1;
 179        while (cnt--) {
 180                byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 1);
 181                HZDELAY(1);     /* wait >=10 ms */
 182        }
 183        byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 0);
 184}
 185
 186static int
 187ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 188{
 189        u_long flags;
 190
 191        switch (mt) {
 192                case CARD_RESET:
 193                        spin_lock_irqsave(&cs->lock, flags);
 194                        ix1_reset(cs);
 195                        spin_unlock_irqrestore(&cs->lock, flags);
 196                        return(0);
 197                case CARD_RELEASE:
 198                        release_io_ix1micro(cs);
 199                        return(0);
 200                case CARD_INIT:
 201                        spin_lock_irqsave(&cs->lock, flags);
 202                        ix1_reset(cs);
 203                        inithscxisac(cs, 3);
 204                        spin_unlock_irqrestore(&cs->lock, flags);
 205                        return(0);
 206                case CARD_TEST:
 207                        return(0);
 208        }
 209        return(0);
 210}
 211
 212#ifdef __ISAPNP__
 213static struct isapnp_device_id itk_ids[] __devinitdata = {
 214        { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
 215          ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25), 
 216          (unsigned long) "ITK micro 2" },
 217        { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29),
 218          ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29), 
 219          (unsigned long) "ITK micro 2." },
 220        { 0, }
 221};
 222
 223static struct isapnp_device_id *ipid __devinitdata = &itk_ids[0];
 224static struct pnp_card *pnp_c __devinitdata = NULL;
 225#endif
 226
 227
 228int __devinit
 229setup_ix1micro(struct IsdnCard *card)
 230{
 231        struct IsdnCardState *cs = card->cs;
 232        char tmp[64];
 233
 234        strcpy(tmp, ix1_revision);
 235        printk(KERN_INFO "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp));
 236        if (cs->typ != ISDN_CTYPE_IX1MICROR2)
 237                return (0);
 238
 239#ifdef __ISAPNP__
 240        if (!card->para[1] && isapnp_present()) {
 241                struct pnp_dev *pnp_d;
 242                while(ipid->card_vendor) {
 243                        if ((pnp_c = pnp_find_card(ipid->card_vendor,
 244                                ipid->card_device, pnp_c))) {
 245                                pnp_d = NULL;
 246                                if ((pnp_d = pnp_find_dev(pnp_c,
 247                                        ipid->vendor, ipid->function, pnp_d))) {
 248                                        int err;
 249
 250                                        printk(KERN_INFO "HiSax: %s detected\n",
 251                                                (char *)ipid->driver_data);
 252                                        pnp_disable_dev(pnp_d);
 253                                        err = pnp_activate_dev(pnp_d);
 254                                        if (err<0) {
 255                                                printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
 256                                                        __FUNCTION__, err);
 257                                                return(0);
 258                                        }
 259                                        card->para[1] = pnp_port_start(pnp_d, 0);
 260                                        card->para[0] = pnp_irq(pnp_d, 0);
 261                                        if (!card->para[0] || !card->para[1]) {
 262                                                printk(KERN_ERR "ITK PnP:some resources are missing %ld/%lx\n",
 263                                                        card->para[0], card->para[1]);
 264                                                pnp_disable_dev(pnp_d);
 265                                                return(0);
 266                                        }
 267                                        break;
 268                                } else {
 269                                        printk(KERN_ERR "ITK PnP: PnP error card found, no device\n");
 270                                }
 271                        }
 272                        ipid++;
 273                        pnp_c = NULL;
 274                } 
 275                if (!ipid->card_vendor) {
 276                        printk(KERN_INFO "ITK PnP: no ISAPnP card found\n");
 277                        return(0);
 278                }
 279        }
 280#endif
 281        /* IO-Ports */
 282        cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET;
 283        cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET;
 284        cs->hw.ix1.isac = card->para[1] + ISAC_DATA_OFFSET;
 285        cs->hw.ix1.hscx = card->para[1] + HSCX_DATA_OFFSET;
 286        cs->hw.ix1.cfg_reg = card->para[1];
 287        cs->irq = card->para[0];
 288        if (cs->hw.ix1.cfg_reg) {
 289                if (!request_region(cs->hw.ix1.cfg_reg, 4, "ix1micro cfg")) {
 290                        printk(KERN_WARNING
 291                          "HiSax: %s config port %x-%x already in use\n",
 292                               CardType[card->typ],
 293                               cs->hw.ix1.cfg_reg,
 294                               cs->hw.ix1.cfg_reg + 4);
 295                        return (0);
 296                }
 297        }
 298        printk(KERN_INFO "HiSax: %s config irq:%d io:0x%X\n",
 299                CardType[cs->typ], cs->irq, cs->hw.ix1.cfg_reg);
 300        setup_isac(cs);
 301        cs->readisac = &ReadISAC;
 302        cs->writeisac = &WriteISAC;
 303        cs->readisacfifo = &ReadISACfifo;
 304        cs->writeisacfifo = &WriteISACfifo;
 305        cs->BC_Read_Reg = &ReadHSCX;
 306        cs->BC_Write_Reg = &WriteHSCX;
 307        cs->BC_Send_Data = &hscx_fill_fifo;
 308        cs->cardmsg = &ix1_card_msg;
 309        cs->irq_func = &ix1micro_interrupt;
 310        ISACVersion(cs, "ix1-Micro:");
 311        if (HscxVersion(cs, "ix1-Micro:")) {
 312                printk(KERN_WARNING
 313                    "ix1-Micro: wrong HSCX versions check IO address\n");
 314                release_io_ix1micro(cs);
 315                return (0);
 316        }
 317        return (1);
 318}
 319