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);
 113      Start_HSCX:
 114        if (val)
 115                hscx_int_main(cs, val);
 116        val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
 117      Start_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[] __devinitdata = {
 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 __devinitdata = &teles_ids[0];
 270static struct pnp_card *pnp_c __devinitdata = NULL;
 271#endif
 272
 273int __devinit
 274setup_teles3(struct IsdnCard *card)
 275{
 276        u_char val;
 277        struct IsdnCardState *cs = card->cs;
 278        char tmp[64];
 279
 280        strcpy(tmp, teles3_revision);
 281        printk(KERN_INFO "HiSax: Teles IO driver Rev. %s\n", HiSax_getrev(tmp));
 282        if ((cs->typ != ISDN_CTYPE_16_3) && (cs->typ != ISDN_CTYPE_PNP)
 283            && (cs->typ != ISDN_CTYPE_TELESPCMCIA) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA))
 284                return (0);
 285
 286#ifdef __ISAPNP__
 287        if (!card->para[1] && isapnp_present()) {
 288                struct pnp_dev *pnp_d;
 289                while(ipid->card_vendor) {
 290                        if ((pnp_c = pnp_find_card(ipid->card_vendor,
 291                                ipid->card_device, pnp_c))) {
 292                                pnp_d = NULL;
 293                                if ((pnp_d = pnp_find_dev(pnp_c,
 294                                        ipid->vendor, ipid->function, pnp_d))) {
 295                                        int err;
 296
 297                                        printk(KERN_INFO "HiSax: %s detected\n",
 298                                                (char *)ipid->driver_data);
 299                                        pnp_disable_dev(pnp_d);
 300                                        err = pnp_activate_dev(pnp_d);
 301                                        if (err<0) {
 302                                                printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
 303                                                        __func__, err);
 304                                                return(0);
 305                                        }
 306                                        card->para[3] = pnp_port_start(pnp_d, 2);
 307                                        card->para[2] = pnp_port_start(pnp_d, 1);
 308                                        card->para[1] = pnp_port_start(pnp_d, 0);
 309                                        card->para[0] = pnp_irq(pnp_d, 0);
 310                                        if (!card->para[0] || !card->para[1] || !card->para[2]) {
 311                                                printk(KERN_ERR "Teles PnP:some resources are missing %ld/%lx/%lx\n",
 312                                                        card->para[0], card->para[1], card->para[2]);
 313                                                pnp_disable_dev(pnp_d);
 314                                                return(0);
 315                                        }
 316                                        break;
 317                                } else {
 318                                        printk(KERN_ERR "Teles PnP: PnP error card found, no device\n");
 319                                }
 320                        }
 321                        ipid++;
 322                        pnp_c = NULL;
 323                } 
 324                if (!ipid->card_vendor) {
 325                        printk(KERN_INFO "Teles PnP: no ISAPnP card found\n");
 326                        return(0);
 327                }
 328        }
 329#endif
 330        if (cs->typ == ISDN_CTYPE_16_3) {
 331                cs->hw.teles3.cfg_reg = card->para[1];
 332                switch (cs->hw.teles3.cfg_reg) {
 333                        case 0x180:
 334                        case 0x280:
 335                        case 0x380:
 336                                cs->hw.teles3.cfg_reg |= 0xc00;
 337                                break;
 338                }
 339                cs->hw.teles3.isac = cs->hw.teles3.cfg_reg - 0x420;
 340                cs->hw.teles3.hscx[0] = cs->hw.teles3.cfg_reg - 0xc20;
 341                cs->hw.teles3.hscx[1] = cs->hw.teles3.cfg_reg - 0x820;
 342        } else if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
 343                cs->hw.teles3.cfg_reg = 0;
 344                cs->hw.teles3.hscx[0] = card->para[1] - 0x20;
 345                cs->hw.teles3.hscx[1] = card->para[1];
 346                cs->hw.teles3.isac = card->para[1] + 0x20;
 347        } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
 348                cs->hw.teles3.cfg_reg = card->para[3];
 349                cs->hw.teles3.isac = card->para[2] - 32;
 350                cs->hw.teles3.hscx[0] = card->para[1] - 32;
 351                cs->hw.teles3.hscx[1] = card->para[1];
 352        } else {        /* PNP */
 353                cs->hw.teles3.cfg_reg = 0;
 354                cs->hw.teles3.isac = card->para[1] - 32;
 355                cs->hw.teles3.hscx[0] = card->para[2] - 32;
 356                cs->hw.teles3.hscx[1] = card->para[2];
 357        }
 358        cs->irq = card->para[0];
 359        cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e;
 360        cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e;
 361        cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e;
 362        if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
 363                if (!request_region(cs->hw.teles3.hscx[1], 96, "HiSax Teles PCMCIA")) {
 364                        printk(KERN_WARNING
 365                               "HiSax: %s ports %x-%x already in use\n",
 366                               CardType[cs->typ],
 367                               cs->hw.teles3.hscx[1],
 368                               cs->hw.teles3.hscx[1] + 96);
 369                        return (0);
 370                }
 371                cs->irq_flags |= IRQF_SHARED; /* cardbus can share */
 372        } else {
 373                if (cs->hw.teles3.cfg_reg) {
 374                        if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
 375                                if (!request_region(cs->hw.teles3.cfg_reg, 1, "teles3 cfg")) {
 376                                        printk(KERN_WARNING
 377                                                "HiSax: %s config port %x already in use\n",
 378                                                CardType[card->typ],
 379                                                cs->hw.teles3.cfg_reg);
 380                                        return (0);
 381                                }
 382                        } else {
 383                                if (!request_region(cs->hw.teles3.cfg_reg, 8, "teles3 cfg")) {
 384                                        printk(KERN_WARNING
 385                                               "HiSax: %s config port %x-%x already in use\n",
 386                                               CardType[card->typ],
 387                                               cs->hw.teles3.cfg_reg,
 388                                                cs->hw.teles3.cfg_reg + 8);
 389                                        return (0);
 390                                }
 391                        }
 392                }
 393                if (!request_region(cs->hw.teles3.isac + 32, 32, "HiSax isac")) {
 394                        printk(KERN_WARNING
 395                           "HiSax: %s isac ports %x-%x already in use\n",
 396                               CardType[cs->typ],
 397                               cs->hw.teles3.isac + 32,
 398                               cs->hw.teles3.isac + 64);
 399                        if (cs->hw.teles3.cfg_reg) {
 400                                if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
 401                                        release_region(cs->hw.teles3.cfg_reg, 1);
 402                                } else {
 403                                        release_region(cs->hw.teles3.cfg_reg, 8);
 404                                }
 405                        }
 406                        return (0);
 407                }
 408                if (!request_region(cs->hw.teles3.hscx[0] + 32, 32, "HiSax hscx A")) {
 409                        printk(KERN_WARNING
 410                         "HiSax: %s hscx A ports %x-%x already in use\n",
 411                               CardType[cs->typ],
 412                               cs->hw.teles3.hscx[0] + 32,
 413                               cs->hw.teles3.hscx[0] + 64);
 414                        if (cs->hw.teles3.cfg_reg) {
 415                                if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
 416                                        release_region(cs->hw.teles3.cfg_reg, 1);
 417                                } else {
 418                                        release_region(cs->hw.teles3.cfg_reg, 8);
 419                                }
 420                        }
 421                        release_ioregs(cs, 1);
 422                        return (0);
 423                }
 424                if (!request_region(cs->hw.teles3.hscx[1] + 32, 32, "HiSax hscx B")) {
 425                        printk(KERN_WARNING
 426                         "HiSax: %s hscx B ports %x-%x already in use\n",
 427                               CardType[cs->typ],
 428                               cs->hw.teles3.hscx[1] + 32,
 429                               cs->hw.teles3.hscx[1] + 64);
 430                        if (cs->hw.teles3.cfg_reg) {
 431                                if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
 432                                        release_region(cs->hw.teles3.cfg_reg, 1);
 433                                } else {
 434                                        release_region(cs->hw.teles3.cfg_reg, 8);
 435                                }
 436                        }
 437                        release_ioregs(cs, 3);
 438                        return (0);
 439                }
 440        }
 441        if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) {
 442                if ((val = bytein(cs->hw.teles3.cfg_reg + 0)) != 0x51) {
 443                        printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
 444                               cs->hw.teles3.cfg_reg + 0, val);
 445                        release_io_teles3(cs);
 446                        return (0);
 447                }
 448                if ((val = bytein(cs->hw.teles3.cfg_reg + 1)) != 0x93) {
 449                        printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
 450                               cs->hw.teles3.cfg_reg + 1, val);
 451                        release_io_teles3(cs);
 452                        return (0);
 453                }
 454                val = bytein(cs->hw.teles3.cfg_reg + 2);/* 0x1e=without AB
 455                                                         * 0x1f=with AB
 456                                                         * 0x1c 16.3 ???
 457                                                         * 0x39 16.3 1.1
 458                                                         * 0x38 16.3 1.3
 459                                                         * 0x46 16.3 with AB + Video (Teles-Vision)
 460                                                         */
 461                if (val != 0x46 && val != 0x39 && val != 0x38 && val != 0x1c && val != 0x1e && val != 0x1f) {
 462                        printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
 463                               cs->hw.teles3.cfg_reg + 2, val);
 464                        release_io_teles3(cs);
 465                        return (0);
 466                }
 467        }
 468        printk(KERN_INFO
 469               "HiSax: %s config irq:%d isac:0x%X  cfg:0x%X\n",
 470               CardType[cs->typ], cs->irq,
 471               cs->hw.teles3.isac + 32, cs->hw.teles3.cfg_reg);
 472        printk(KERN_INFO
 473               "HiSax: hscx A:0x%X  hscx B:0x%X\n",
 474               cs->hw.teles3.hscx[0] + 32, cs->hw.teles3.hscx[1] + 32);
 475
 476        setup_isac(cs);
 477        if (reset_teles3(cs)) {
 478                printk(KERN_WARNING "Teles3: wrong IRQ\n");
 479                release_io_teles3(cs);
 480                return (0);
 481        }
 482        cs->readisac = &ReadISAC;
 483        cs->writeisac = &WriteISAC;
 484        cs->readisacfifo = &ReadISACfifo;
 485        cs->writeisacfifo = &WriteISACfifo;
 486        cs->BC_Read_Reg = &ReadHSCX;
 487        cs->BC_Write_Reg = &WriteHSCX;
 488        cs->BC_Send_Data = &hscx_fill_fifo;
 489        cs->cardmsg = &Teles_card_msg;
 490        cs->irq_func = &teles3_interrupt;
 491        ISACVersion(cs, "Teles3:");
 492        if (HscxVersion(cs, "Teles3:")) {
 493                printk(KERN_WARNING
 494                       "Teles3: wrong HSCX versions check IO address\n");
 495                release_io_teles3(cs);
 496                return (0);
 497        }
 498        return (1);
 499}
 500