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