linux/drivers/isdn/hisax/teles3.c
<<
>>
Prefs
   1/* $Id: teles3.c,v 2.19.2.4 2004/01/13 23:48:39 keil Exp $
   2 *
   3 * low level stuff for Teles 16.3 & PNP isdn 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 * Thanks to    Jan den Ouden
  12 *              Fritz Elfert
  13 *              Beat Doebeli
  14 *
  15 */
  16#include <linux/init.h>
  17#include <linux/isapnp.h>
  18#include "hisax.h"
  19#include "isac.h"
  20#include "hscx.h"
  21#include "isdnl1.h"
  22
  23static const char *teles3_revision = "$Revision: 2.19.2.4 $";
  24
  25#define byteout(addr, val) outb(val, addr)
  26#define bytein(addr) inb(addr)
  27
  28static inline u_char
  29readreg(unsigned int adr, u_char off)
  30{
  31        return (bytein(adr + off));
  32}
  33
  34static inline void
  35writereg(unsigned int adr, u_char off, u_char data)
  36{
  37        byteout(adr + off, data);
  38}
  39
  40
  41static inline void
  42read_fifo(unsigned int adr, u_char *data, int size)
  43{
  44        insb(adr, data, size);
  45}
  46
  47static void
  48write_fifo(unsigned int adr, u_char *data, int size)
  49{
  50        outsb(adr, data, size);
  51}
  52
  53/* Interface functions */
  54
  55static u_char
  56ReadISAC(struct IsdnCardState *cs, u_char offset)
  57{
  58        return (readreg(cs->hw.teles3.isac, offset));
  59}
  60
  61static void
  62WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
  63{
  64        writereg(cs->hw.teles3.isac, offset, value);
  65}
  66
  67static void
  68ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
  69{
  70        read_fifo(cs->hw.teles3.isacfifo, data, size);
  71}
  72
  73static void
  74WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
  75{
  76        write_fifo(cs->hw.teles3.isacfifo, data, size);
  77}
  78
  79static u_char
  80ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
  81{
  82        return (readreg(cs->hw.teles3.hscx[hscx], offset));
  83}
  84
  85static void
  86WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
  87{
  88        writereg(cs->hw.teles3.hscx[hscx], offset, value);
  89}
  90
  91/*
  92 * fast interrupt HSCX stuff goes here
  93 */
  94
  95#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.hscx[nr], reg)
  96#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.hscx[nr], reg, data)
  97#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
  98#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
  99
 100#include "hscx_irq.c"
 101
 102static irqreturn_t
 103teles3_interrupt(int intno, void *dev_id)
 104{
 105#define MAXCOUNT 5
 106        struct IsdnCardState *cs = dev_id;
 107        u_char val;
 108        u_long flags;
 109        int count = 0;
 110
 111        spin_lock_irqsave(&cs->lock, flags);
 112        val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
 113Start_HSCX:
 114        if (val)
 115                hscx_int_main(cs, val);
 116        val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
 117Start_ISAC:
 118        if (val)
 119                isac_interrupt(cs, val);
 120        count++;
 121        val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
 122        if (val && count < MAXCOUNT) {
 123                if (cs->debug & L1_DEB_HSCX)
 124                        debugl1(cs, "HSCX IntStat after IntRoutine");
 125                goto Start_HSCX;
 126        }
 127        val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
 128        if (val && count < MAXCOUNT) {
 129                if (cs->debug & L1_DEB_ISAC)
 130                        debugl1(cs, "ISAC IntStat after IntRoutine");
 131                goto Start_ISAC;
 132        }
 133        if (count >= MAXCOUNT)
 134                printk(KERN_WARNING "Teles3: more than %d loops in teles3_interrupt\n", count);
 135        writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF);
 136        writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF);
 137        writereg(cs->hw.teles3.isac, ISAC_MASK, 0xFF);
 138        writereg(cs->hw.teles3.isac, ISAC_MASK, 0x0);
 139        writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0x0);
 140        writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0x0);
 141        spin_unlock_irqrestore(&cs->lock, flags);
 142        return IRQ_HANDLED;
 143}
 144
 145static inline void
 146release_ioregs(struct IsdnCardState *cs, int mask)
 147{
 148        if (mask & 1)
 149                release_region(cs->hw.teles3.isac + 32, 32);
 150        if (mask & 2)
 151                release_region(cs->hw.teles3.hscx[0] + 32, 32);
 152        if (mask & 4)
 153                release_region(cs->hw.teles3.hscx[1] + 32, 32);
 154}
 155
 156static void
 157release_io_teles3(struct IsdnCardState *cs)
 158{
 159        if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
 160                release_region(cs->hw.teles3.hscx[1], 96);
 161        } else {
 162                if (cs->hw.teles3.cfg_reg) {
 163                        if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
 164                                release_region(cs->hw.teles3.cfg_reg, 1);
 165                        } else {
 166                                release_region(cs->hw.teles3.cfg_reg, 8);
 167                        }
 168                }
 169                release_ioregs(cs, 0x7);
 170        }
 171}
 172
 173static int
 174reset_teles3(struct IsdnCardState *cs)
 175{
 176        u_char irqcfg;
 177
 178        if (cs->typ != ISDN_CTYPE_TELESPCMCIA) {
 179                if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) {
 180                        switch (cs->irq) {
 181                        case 2:
 182                        case 9:
 183                                irqcfg = 0x00;
 184                                break;
 185                        case 3:
 186                                irqcfg = 0x02;
 187                                break;
 188                        case 4:
 189                                irqcfg = 0x04;
 190                                break;
 191                        case 5:
 192                                irqcfg = 0x06;
 193                                break;
 194                        case 10:
 195                                irqcfg = 0x08;
 196                                break;
 197                        case 11:
 198                                irqcfg = 0x0A;
 199                                break;
 200                        case 12:
 201                                irqcfg = 0x0C;
 202                                break;
 203                        case 15:
 204                                irqcfg = 0x0E;
 205                                break;
 206                        default:
 207                                return (1);
 208                        }
 209                        byteout(cs->hw.teles3.cfg_reg + 4, irqcfg);
 210                        HZDELAY(HZ / 10 + 1);
 211                        byteout(cs->hw.teles3.cfg_reg + 4, irqcfg | 1);
 212                        HZDELAY(HZ / 10 + 1);
 213                } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
 214                        byteout(cs->hw.teles3.cfg_reg, 0xff);
 215                        HZDELAY(2);
 216                        byteout(cs->hw.teles3.cfg_reg, 0x00);
 217                        HZDELAY(2);
 218                } else {
 219                        /* Reset off for 16.3 PnP , thanks to Georg Acher */
 220                        byteout(cs->hw.teles3.isac + 0x3c, 0);
 221                        HZDELAY(2);
 222                        byteout(cs->hw.teles3.isac + 0x3c, 1);
 223                        HZDELAY(2);
 224                }
 225        }
 226        return (0);
 227}
 228
 229static int
 230Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 231{
 232        u_long flags;
 233
 234        switch (mt) {
 235        case CARD_RESET:
 236                spin_lock_irqsave(&cs->lock, flags);
 237                reset_teles3(cs);
 238                spin_unlock_irqrestore(&cs->lock, flags);
 239                return (0);
 240        case CARD_RELEASE:
 241                release_io_teles3(cs);
 242                return (0);
 243        case CARD_INIT:
 244                spin_lock_irqsave(&cs->lock, flags);
 245                inithscxisac(cs, 3);
 246                spin_unlock_irqrestore(&cs->lock, flags);
 247                return (0);
 248        case CARD_TEST:
 249                return (0);
 250        }
 251        return (0);
 252}
 253
 254#ifdef __ISAPNP__
 255
 256static struct isapnp_device_id teles_ids[] = {
 257        { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
 258          ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
 259          (unsigned long) "Teles 16.3 PnP" },
 260        { ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0),
 261          ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0),
 262          (unsigned long) "Creatix 16.3 PnP" },
 263        { ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002),
 264          ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002),
 265          (unsigned long) "Compaq ISDN S0" },
 266        { 0, }
 267};
 268
 269static struct isapnp_device_id *ipid = &teles_ids[0];
 270static struct pnp_card *pnp_c = NULL;
 271#endif
 272
 273int setup_teles3(struct IsdnCard *card)
 274{
 275        u_char val;
 276        struct IsdnCardState *cs = card->cs;
 277        char tmp[64];
 278
 279        strcpy(tmp, teles3_revision);
 280        printk(KERN_INFO "HiSax: Teles IO driver Rev. %s\n", HiSax_getrev(tmp));
 281        if ((cs->typ != ISDN_CTYPE_16_3) && (cs->typ != ISDN_CTYPE_PNP)
 282            && (cs->typ != ISDN_CTYPE_TELESPCMCIA) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA))
 283                return (0);
 284
 285#ifdef __ISAPNP__
 286        if (!card->para[1] && isapnp_present()) {
 287                struct pnp_dev *pnp_d;
 288                while (ipid->card_vendor) {
 289                        if ((pnp_c = pnp_find_card(ipid->card_vendor,
 290                                                   ipid->card_device, pnp_c))) {
 291                                pnp_d = NULL;
 292                                if ((pnp_d = pnp_find_dev(pnp_c,
 293                                                          ipid->vendor, ipid->function, pnp_d))) {
 294                                        int err;
 295
 296                                        printk(KERN_INFO "HiSax: %s detected\n",
 297                                               (char *)ipid->driver_data);
 298                                        pnp_disable_dev(pnp_d);
 299                                        err = pnp_activate_dev(pnp_d);
 300                                        if (err < 0) {
 301                                                printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
 302                                                       __func__, err);
 303                                                return (0);
 304                                        }
 305                                        card->para[3] = pnp_port_start(pnp_d, 2);
 306                                        card->para[2] = pnp_port_start(pnp_d, 1);
 307                                        card->para[1] = pnp_port_start(pnp_d, 0);
 308                                        card->para[0] = pnp_irq(pnp_d, 0);
 309                                        if (!card->para[0] || !card->para[1] || !card->para[2]) {
 310                                                printk(KERN_ERR "Teles PnP:some resources are missing %ld/%lx/%lx\n",
 311                                                       card->para[0], card->para[1], card->para[2]);
 312                                                pnp_disable_dev(pnp_d);
 313                                                return (0);
 314                                        }
 315                                        break;
 316                                } else {
 317                                        printk(KERN_ERR "Teles PnP: PnP error card found, no device\n");
 318                                }
 319                        }
 320                        ipid++;
 321                        pnp_c = NULL;
 322                }
 323                if (!ipid->card_vendor) {
 324                        printk(KERN_INFO "Teles PnP: no ISAPnP card found\n");
 325                        return (0);
 326                }
 327        }
 328#endif
 329        if (cs->typ == ISDN_CTYPE_16_3) {
 330                cs->hw.teles3.cfg_reg = card->para[1];
 331                switch (cs->hw.teles3.cfg_reg) {
 332                case 0x180:
 333                case 0x280:
 334                case 0x380:
 335                        cs->hw.teles3.cfg_reg |= 0xc00;
 336                        break;
 337                }
 338                cs->hw.teles3.isac = cs->hw.teles3.cfg_reg - 0x420;
 339                cs->hw.teles3.hscx[0] = cs->hw.teles3.cfg_reg - 0xc20;
 340                cs->hw.teles3.hscx[1] = cs->hw.teles3.cfg_reg - 0x820;
 341        } else if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
 342                cs->hw.teles3.cfg_reg = 0;
 343                cs->hw.teles3.hscx[0] = card->para[1] - 0x20;
 344                cs->hw.teles3.hscx[1] = card->para[1];
 345                cs->hw.teles3.isac = card->para[1] + 0x20;
 346        } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
 347                cs->hw.teles3.cfg_reg = card->para[3];
 348                cs->hw.teles3.isac = card->para[2] - 32;
 349                cs->hw.teles3.hscx[0] = card->para[1] - 32;
 350                cs->hw.teles3.hscx[1] = card->para[1];
 351        } else {        /* PNP */
 352                cs->hw.teles3.cfg_reg = 0;
 353                cs->hw.teles3.isac = card->para[1] - 32;
 354                cs->hw.teles3.hscx[0] = card->para[2] - 32;
 355                cs->hw.teles3.hscx[1] = card->para[2];
 356        }
 357        cs->irq = card->para[0];
 358        cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e;
 359        cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e;
 360        cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e;
 361        if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
 362                if (!request_region(cs->hw.teles3.hscx[1], 96, "HiSax Teles PCMCIA")) {
 363                        printk(KERN_WARNING
 364                               "HiSax: %s ports %x-%x already in use\n",
 365                               CardType[cs->typ],
 366                               cs->hw.teles3.hscx[1],
 367                               cs->hw.teles3.hscx[1] + 96);
 368                        return (0);
 369                }
 370                cs->irq_flags |= IRQF_SHARED; /* cardbus can share */
 371        } else {
 372                if (cs->hw.teles3.cfg_reg) {
 373                        if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
 374                                if (!request_region(cs->hw.teles3.cfg_reg, 1, "teles3 cfg")) {
 375                                        printk(KERN_WARNING
 376                                               "HiSax: %s config port %x already in use\n",
 377                                               CardType[card->typ],
 378                                               cs->hw.teles3.cfg_reg);
 379                                        return (0);
 380                                }
 381                        } else {
 382                                if (!request_region(cs->hw.teles3.cfg_reg, 8, "teles3 cfg")) {
 383                                        printk(KERN_WARNING
 384                                               "HiSax: %s config port %x-%x already in use\n",
 385                                               CardType[card->typ],
 386                                               cs->hw.teles3.cfg_reg,
 387                                               cs->hw.teles3.cfg_reg + 8);
 388                                        return (0);
 389                                }
 390                        }
 391                }
 392                if (!request_region(cs->hw.teles3.isac + 32, 32, "HiSax isac")) {
 393                        printk(KERN_WARNING
 394                               "HiSax: %s isac ports %x-%x already in use\n",
 395                               CardType[cs->typ],
 396                               cs->hw.teles3.isac + 32,
 397                               cs->hw.teles3.isac + 64);
 398                        if (cs->hw.teles3.cfg_reg) {
 399                                if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
 400                                        release_region(cs->hw.teles3.cfg_reg, 1);
 401                                } else {
 402                                        release_region(cs->hw.teles3.cfg_reg, 8);
 403                                }
 404                        }
 405                        return (0);
 406                }
 407                if (!request_region(cs->hw.teles3.hscx[0] + 32, 32, "HiSax hscx A")) {
 408                        printk(KERN_WARNING
 409                               "HiSax: %s hscx A ports %x-%x already in use\n",
 410                               CardType[cs->typ],
 411                               cs->hw.teles3.hscx[0] + 32,
 412                               cs->hw.teles3.hscx[0] + 64);
 413                        if (cs->hw.teles3.cfg_reg) {
 414                                if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
 415                                        release_region(cs->hw.teles3.cfg_reg, 1);
 416                                } else {
 417                                        release_region(cs->hw.teles3.cfg_reg, 8);
 418                                }
 419                        }
 420                        release_ioregs(cs, 1);
 421                        return (0);
 422                }
 423                if (!request_region(cs->hw.teles3.hscx[1] + 32, 32, "HiSax hscx B")) {
 424                        printk(KERN_WARNING
 425                               "HiSax: %s hscx B ports %x-%x already in use\n",
 426                               CardType[cs->typ],
 427                               cs->hw.teles3.hscx[1] + 32,
 428                               cs->hw.teles3.hscx[1] + 64);
 429                        if (cs->hw.teles3.cfg_reg) {
 430                                if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
 431                                        release_region(cs->hw.teles3.cfg_reg, 1);
 432                                } else {
 433                                        release_region(cs->hw.teles3.cfg_reg, 8);
 434                                }
 435                        }
 436                        release_ioregs(cs, 3);
 437                        return (0);
 438                }
 439        }
 440        if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) {
 441                if ((val = bytein(cs->hw.teles3.cfg_reg + 0)) != 0x51) {
 442                        printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
 443                               cs->hw.teles3.cfg_reg + 0, val);
 444                        release_io_teles3(cs);
 445                        return (0);
 446                }
 447                if ((val = bytein(cs->hw.teles3.cfg_reg + 1)) != 0x93) {
 448                        printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
 449                               cs->hw.teles3.cfg_reg + 1, val);
 450                        release_io_teles3(cs);
 451                        return (0);
 452                }
 453                val = bytein(cs->hw.teles3.cfg_reg + 2);/* 0x1e=without AB
 454                                                         * 0x1f=with AB
 455                                                         * 0x1c 16.3 ???
 456                                                         * 0x39 16.3 1.1
 457                                                         * 0x38 16.3 1.3
 458                                                         * 0x46 16.3 with AB + Video (Teles-Vision)
 459                                                         */
 460                if (val != 0x46 && val != 0x39 && val != 0x38 && val != 0x1c && val != 0x1e && val != 0x1f) {
 461                        printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
 462                               cs->hw.teles3.cfg_reg + 2, val);
 463                        release_io_teles3(cs);
 464                        return (0);
 465                }
 466        }
 467        printk(KERN_INFO
 468               "HiSax: %s config irq:%d isac:0x%X  cfg:0x%X\n",
 469               CardType[cs->typ], cs->irq,
 470               cs->hw.teles3.isac + 32, cs->hw.teles3.cfg_reg);
 471        printk(KERN_INFO
 472               "HiSax: hscx A:0x%X  hscx B:0x%X\n",
 473               cs->hw.teles3.hscx[0] + 32, cs->hw.teles3.hscx[1] + 32);
 474
 475        setup_isac(cs);
 476        if (reset_teles3(cs)) {
 477                printk(KERN_WARNING "Teles3: wrong IRQ\n");
 478                release_io_teles3(cs);
 479                return (0);
 480        }
 481        cs->readisac = &ReadISAC;
 482        cs->writeisac = &WriteISAC;
 483        cs->readisacfifo = &ReadISACfifo;
 484        cs->writeisacfifo = &WriteISACfifo;
 485        cs->BC_Read_Reg = &ReadHSCX;
 486        cs->BC_Write_Reg = &WriteHSCX;
 487        cs->BC_Send_Data = &hscx_fill_fifo;
 488        cs->cardmsg = &Teles_card_msg;
 489        cs->irq_func = &teles3_interrupt;
 490        ISACVersion(cs, "Teles3:");
 491        if (HscxVersion(cs, "Teles3:")) {
 492                printk(KERN_WARNING
 493                       "Teles3: wrong HSCX versions check IO address\n");
 494                release_io_teles3(cs);
 495                return (0);
 496        }
 497        return (1);
 498}
 499