1169 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * mISDNinfineon.c4 * Support for cards based on following Infineon ISDN chipsets5 * - ISAC + HSCX6 * - IPAC and IPAC-X7 * - ISAC-SX + HSCX8 *9 * Supported cards:10 * - Dialogic Diva 2.011 * - Dialogic Diva 2.0U12 * - Dialogic Diva 2.0113 * - Dialogic Diva 2.0214 * - Sedlbauer Speedwin15 * - HST Saphir316 * - Develo (former ELSA) Microlink PCI (Quickstep 1000)17 * - Develo (former ELSA) Quickstep 300018 * - Berkom Scitel BRIX Quadro19 * - Dr.Neuhaus (Sagem) Niccy20 *21 * Author Karsten Keil <keil@isdn4linux.de>22 *23 * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>24 */25 26#include <linux/interrupt.h>27#include <linux/module.h>28#include <linux/pci.h>29#include <linux/delay.h>30#include <linux/mISDNhw.h>31#include <linux/slab.h>32#include "ipac.h"33 34#define INFINEON_REV "1.0"35 36static int inf_cnt;37static u32 debug;38static u32 irqloops = 4;39 40enum inf_types {41 INF_NONE,42 INF_DIVA20,43 INF_DIVA20U,44 INF_DIVA201,45 INF_DIVA202,46 INF_SPEEDWIN,47 INF_SAPHIR3,48 INF_QS1000,49 INF_QS3000,50 INF_NICCY,51 INF_SCT_1,52 INF_SCT_2,53 INF_SCT_3,54 INF_SCT_4,55 INF_GAZEL_R685,56 INF_GAZEL_R75357};58 59enum addr_mode {60 AM_NONE = 0,61 AM_IO,62 AM_MEMIO,63 AM_IND_IO,64};65 66struct inf_cinfo {67 enum inf_types typ;68 const char *full;69 const char *name;70 enum addr_mode cfg_mode;71 enum addr_mode addr_mode;72 u8 cfg_bar;73 u8 addr_bar;74 void *irqfunc;75};76 77struct _ioaddr {78 enum addr_mode mode;79 union {80 void __iomem *p;81 struct _ioport io;82 } a;83};84 85struct _iohandle {86 enum addr_mode mode;87 resource_size_t size;88 resource_size_t start;89 void __iomem *p;90};91 92struct inf_hw {93 struct list_head list;94 struct pci_dev *pdev;95 const struct inf_cinfo *ci;96 char name[MISDN_MAX_IDLEN];97 u32 irq;98 u32 irqcnt;99 struct _iohandle cfg;100 struct _iohandle addr;101 struct _ioaddr isac;102 struct _ioaddr hscx;103 spinlock_t lock; /* HW access lock */104 struct ipac_hw ipac;105 struct inf_hw *sc[3]; /* slave cards */106};107 108 109#define PCI_SUBVENDOR_HST_SAPHIR3 0x52110#define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53111#define PCI_SUB_ID_SEDLBAUER 0x01112 113static struct pci_device_id infineon_ids[] = {114 { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20), INF_DIVA20 },115 { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20_U), INF_DIVA20U },116 { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA201), INF_DIVA201 },117 { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA202), INF_DIVA202 },118 { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,119 PCI_SUBVENDOR_SEDLBAUER_PCI, PCI_SUB_ID_SEDLBAUER, 0, 0,120 INF_SPEEDWIN },121 { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,122 PCI_SUBVENDOR_HST_SAPHIR3, PCI_SUB_ID_SEDLBAUER, 0, 0, INF_SAPHIR3 },123 { PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_MICROLINK), INF_QS1000 },124 { PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_QS3000), INF_QS3000 },125 { PCI_VDEVICE(SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY), INF_NICCY },126 { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,127 PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO, 0, 0,128 INF_SCT_1 },129 { PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R685), INF_GAZEL_R685 },130 { PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R753), INF_GAZEL_R753 },131 { PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO), INF_GAZEL_R753 },132 { PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_OLITEC), INF_GAZEL_R753 },133 { }134};135MODULE_DEVICE_TABLE(pci, infineon_ids);136 137/* PCI interface specific defines */138/* Diva 2.0/2.0U */139#define DIVA_HSCX_PORT 0x00140#define DIVA_HSCX_ALE 0x04141#define DIVA_ISAC_PORT 0x08142#define DIVA_ISAC_ALE 0x0C143#define DIVA_PCI_CTRL 0x10144 145/* DIVA_PCI_CTRL bits */146#define DIVA_IRQ_BIT 0x01147#define DIVA_RESET_BIT 0x08148#define DIVA_EEPROM_CLK 0x40149#define DIVA_LED_A 0x10150#define DIVA_LED_B 0x20151#define DIVA_IRQ_CLR 0x80152 153/* Diva 2.01/2.02 */154/* Siemens PITA */155#define PITA_ICR_REG 0x00156#define PITA_INT0_STATUS 0x02157 158#define PITA_MISC_REG 0x1c159#define PITA_PARA_SOFTRESET 0x01000000160#define PITA_SER_SOFTRESET 0x02000000161#define PITA_PARA_MPX_MODE 0x04000000162#define PITA_INT0_ENABLE 0x00020000163 164/* TIGER 100 Registers */165#define TIGER_RESET_ADDR 0x00166#define TIGER_EXTERN_RESET 0x01167#define TIGER_AUX_CTRL 0x02168#define TIGER_AUX_DATA 0x03169#define TIGER_AUX_IRQMASK 0x05170#define TIGER_AUX_STATUS 0x07171 172/* Tiger AUX BITs */173#define TIGER_IOMASK 0xdd /* 1 and 5 are inputs */174#define TIGER_IRQ_BIT 0x02175 176#define TIGER_IPAC_ALE 0xC0177#define TIGER_IPAC_PORT 0xC8178 179/* ELSA (now Develo) PCI cards */180#define ELSA_IRQ_ADDR 0x4c181#define ELSA_IRQ_MASK 0x04182#define QS1000_IRQ_OFF 0x01183#define QS3000_IRQ_OFF 0x03184#define QS1000_IRQ_ON 0x41185#define QS3000_IRQ_ON 0x43186 187/* Dr Neuhaus/Sagem Niccy */188#define NICCY_ISAC_PORT 0x00189#define NICCY_HSCX_PORT 0x01190#define NICCY_ISAC_ALE 0x02191#define NICCY_HSCX_ALE 0x03192 193#define NICCY_IRQ_CTRL_REG 0x38194#define NICCY_IRQ_ENABLE 0x001f00195#define NICCY_IRQ_DISABLE 0xff0000196#define NICCY_IRQ_BIT 0x800000197 198 199/* Scitel PLX */200#define SCT_PLX_IRQ_ADDR 0x4c201#define SCT_PLX_RESET_ADDR 0x50202#define SCT_PLX_IRQ_ENABLE 0x41203#define SCT_PLX_RESET_BIT 0x04204 205/* Gazel */206#define GAZEL_IPAC_DATA_PORT 0x04207/* Gazel PLX */208#define GAZEL_CNTRL 0x50209#define GAZEL_RESET 0x04210#define GAZEL_RESET_9050 0x40000000211#define GAZEL_INCSR 0x4C212#define GAZEL_ISAC_EN 0x08213#define GAZEL_INT_ISAC 0x20214#define GAZEL_HSCX_EN 0x01215#define GAZEL_INT_HSCX 0x04216#define GAZEL_PCI_EN 0x40217#define GAZEL_IPAC_EN 0x03218 219 220static LIST_HEAD(Cards);221static DEFINE_RWLOCK(card_lock); /* protect Cards */222 223static void224_set_debug(struct inf_hw *card)225{226 card->ipac.isac.dch.debug = debug;227 card->ipac.hscx[0].bch.debug = debug;228 card->ipac.hscx[1].bch.debug = debug;229}230 231static int232set_debug(const char *val, const struct kernel_param *kp)233{234 int ret;235 struct inf_hw *card;236 237 ret = param_set_uint(val, kp);238 if (!ret) {239 read_lock(&card_lock);240 list_for_each_entry(card, &Cards, list)241 _set_debug(card);242 read_unlock(&card_lock);243 }244 return ret;245}246 247MODULE_AUTHOR("Karsten Keil");248MODULE_DESCRIPTION("mISDN driver for cards based on Infineon ISDN chipsets");249MODULE_LICENSE("GPL v2");250MODULE_VERSION(INFINEON_REV);251module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);252MODULE_PARM_DESC(debug, "infineon debug mask");253module_param(irqloops, uint, S_IRUGO | S_IWUSR);254MODULE_PARM_DESC(irqloops, "infineon maximal irqloops (default 4)");255 256/* Interface functions */257 258IOFUNC_IO(ISAC, inf_hw, isac.a.io)259IOFUNC_IO(IPAC, inf_hw, hscx.a.io)260IOFUNC_IND(ISAC, inf_hw, isac.a.io)261IOFUNC_IND(IPAC, inf_hw, hscx.a.io)262IOFUNC_MEMIO(ISAC, inf_hw, u32, isac.a.p)263IOFUNC_MEMIO(IPAC, inf_hw, u32, hscx.a.p)264 265static irqreturn_t266diva_irq(int intno, void *dev_id)267{268 struct inf_hw *hw = dev_id;269 u8 val;270 271 spin_lock(&hw->lock);272 val = inb((u32)hw->cfg.start + DIVA_PCI_CTRL);273 if (!(val & DIVA_IRQ_BIT)) { /* for us or shared ? */274 spin_unlock(&hw->lock);275 return IRQ_NONE; /* shared */276 }277 hw->irqcnt++;278 mISDNipac_irq(&hw->ipac, irqloops);279 spin_unlock(&hw->lock);280 return IRQ_HANDLED;281}282 283static irqreturn_t284diva20x_irq(int intno, void *dev_id)285{286 struct inf_hw *hw = dev_id;287 u8 val;288 289 spin_lock(&hw->lock);290 val = readb(hw->cfg.p);291 if (!(val & PITA_INT0_STATUS)) { /* for us or shared ? */292 spin_unlock(&hw->lock);293 return IRQ_NONE; /* shared */294 }295 hw->irqcnt++;296 mISDNipac_irq(&hw->ipac, irqloops);297 writeb(PITA_INT0_STATUS, hw->cfg.p); /* ACK PITA INT0 */298 spin_unlock(&hw->lock);299 return IRQ_HANDLED;300}301 302static irqreturn_t303tiger_irq(int intno, void *dev_id)304{305 struct inf_hw *hw = dev_id;306 u8 val;307 308 spin_lock(&hw->lock);309 val = inb((u32)hw->cfg.start + TIGER_AUX_STATUS);310 if (val & TIGER_IRQ_BIT) { /* for us or shared ? */311 spin_unlock(&hw->lock);312 return IRQ_NONE; /* shared */313 }314 hw->irqcnt++;315 mISDNipac_irq(&hw->ipac, irqloops);316 spin_unlock(&hw->lock);317 return IRQ_HANDLED;318}319 320static irqreturn_t321elsa_irq(int intno, void *dev_id)322{323 struct inf_hw *hw = dev_id;324 u8 val;325 326 spin_lock(&hw->lock);327 val = inb((u32)hw->cfg.start + ELSA_IRQ_ADDR);328 if (!(val & ELSA_IRQ_MASK)) {329 spin_unlock(&hw->lock);330 return IRQ_NONE; /* shared */331 }332 hw->irqcnt++;333 mISDNipac_irq(&hw->ipac, irqloops);334 spin_unlock(&hw->lock);335 return IRQ_HANDLED;336}337 338static irqreturn_t339niccy_irq(int intno, void *dev_id)340{341 struct inf_hw *hw = dev_id;342 u32 val;343 344 spin_lock(&hw->lock);345 val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);346 if (!(val & NICCY_IRQ_BIT)) { /* for us or shared ? */347 spin_unlock(&hw->lock);348 return IRQ_NONE; /* shared */349 }350 outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);351 hw->irqcnt++;352 mISDNipac_irq(&hw->ipac, irqloops);353 spin_unlock(&hw->lock);354 return IRQ_HANDLED;355}356 357static irqreturn_t358gazel_irq(int intno, void *dev_id)359{360 struct inf_hw *hw = dev_id;361 irqreturn_t ret;362 363 spin_lock(&hw->lock);364 ret = mISDNipac_irq(&hw->ipac, irqloops);365 spin_unlock(&hw->lock);366 return ret;367}368 369static irqreturn_t370ipac_irq(int intno, void *dev_id)371{372 struct inf_hw *hw = dev_id;373 u8 val;374 375 spin_lock(&hw->lock);376 val = hw->ipac.read_reg(hw, IPAC_ISTA);377 if (!(val & 0x3f)) {378 spin_unlock(&hw->lock);379 return IRQ_NONE; /* shared */380 }381 hw->irqcnt++;382 mISDNipac_irq(&hw->ipac, irqloops);383 spin_unlock(&hw->lock);384 return IRQ_HANDLED;385}386 387static void388enable_hwirq(struct inf_hw *hw)389{390 u16 w;391 u32 val;392 393 switch (hw->ci->typ) {394 case INF_DIVA201:395 case INF_DIVA202:396 writel(PITA_INT0_ENABLE, hw->cfg.p);397 break;398 case INF_SPEEDWIN:399 case INF_SAPHIR3:400 outb(TIGER_IRQ_BIT, (u32)hw->cfg.start + TIGER_AUX_IRQMASK);401 break;402 case INF_QS1000:403 outb(QS1000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR);404 break;405 case INF_QS3000:406 outb(QS3000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR);407 break;408 case INF_NICCY:409 val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);410 val |= NICCY_IRQ_ENABLE;411 outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);412 break;413 case INF_SCT_1:414 w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);415 w |= SCT_PLX_IRQ_ENABLE;416 outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);417 break;418 case INF_GAZEL_R685:419 outb(GAZEL_ISAC_EN + GAZEL_HSCX_EN + GAZEL_PCI_EN,420 (u32)hw->cfg.start + GAZEL_INCSR);421 break;422 case INF_GAZEL_R753:423 outb(GAZEL_IPAC_EN + GAZEL_PCI_EN,424 (u32)hw->cfg.start + GAZEL_INCSR);425 break;426 default:427 break;428 }429}430 431static void432disable_hwirq(struct inf_hw *hw)433{434 u16 w;435 u32 val;436 437 switch (hw->ci->typ) {438 case INF_DIVA201:439 case INF_DIVA202:440 writel(0, hw->cfg.p);441 break;442 case INF_SPEEDWIN:443 case INF_SAPHIR3:444 outb(0, (u32)hw->cfg.start + TIGER_AUX_IRQMASK);445 break;446 case INF_QS1000:447 outb(QS1000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR);448 break;449 case INF_QS3000:450 outb(QS3000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR);451 break;452 case INF_NICCY:453 val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);454 val &= NICCY_IRQ_DISABLE;455 outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);456 break;457 case INF_SCT_1:458 w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);459 w &= (~SCT_PLX_IRQ_ENABLE);460 outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);461 break;462 case INF_GAZEL_R685:463 case INF_GAZEL_R753:464 outb(0, (u32)hw->cfg.start + GAZEL_INCSR);465 break;466 default:467 break;468 }469}470 471static void472ipac_chip_reset(struct inf_hw *hw)473{474 hw->ipac.write_reg(hw, IPAC_POTA2, 0x20);475 mdelay(5);476 hw->ipac.write_reg(hw, IPAC_POTA2, 0x00);477 mdelay(5);478 hw->ipac.write_reg(hw, IPAC_CONF, hw->ipac.conf);479 hw->ipac.write_reg(hw, IPAC_MASK, 0xc0);480}481 482static void483reset_inf(struct inf_hw *hw)484{485 u16 w;486 u32 val;487 488 if (debug & DEBUG_HW)489 pr_notice("%s: resetting card\n", hw->name);490 switch (hw->ci->typ) {491 case INF_DIVA20:492 case INF_DIVA20U:493 outb(0, (u32)hw->cfg.start + DIVA_PCI_CTRL);494 mdelay(10);495 outb(DIVA_RESET_BIT, (u32)hw->cfg.start + DIVA_PCI_CTRL);496 mdelay(10);497 /* Workaround PCI9060 */498 outb(9, (u32)hw->cfg.start + 0x69);499 outb(DIVA_RESET_BIT | DIVA_LED_A,500 (u32)hw->cfg.start + DIVA_PCI_CTRL);501 break;502 case INF_DIVA201:503 writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE,504 hw->cfg.p + PITA_MISC_REG);505 mdelay(1);506 writel(PITA_PARA_MPX_MODE, hw->cfg.p + PITA_MISC_REG);507 mdelay(10);508 break;509 case INF_DIVA202:510 writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE,511 hw->cfg.p + PITA_MISC_REG);512 mdelay(1);513 writel(PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET,514 hw->cfg.p + PITA_MISC_REG);515 mdelay(10);516 break;517 case INF_SPEEDWIN:518 case INF_SAPHIR3:519 ipac_chip_reset(hw);520 hw->ipac.write_reg(hw, IPAC_ACFG, 0xff);521 hw->ipac.write_reg(hw, IPAC_AOE, 0x00);522 hw->ipac.write_reg(hw, IPAC_PCFG, 0x12);523 break;524 case INF_QS1000:525 case INF_QS3000:526 ipac_chip_reset(hw);527 hw->ipac.write_reg(hw, IPAC_ACFG, 0x00);528 hw->ipac.write_reg(hw, IPAC_AOE, 0x3c);529 hw->ipac.write_reg(hw, IPAC_ATX, 0xff);530 break;531 case INF_NICCY:532 break;533 case INF_SCT_1:534 w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR);535 w &= (~SCT_PLX_RESET_BIT);536 outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR);537 mdelay(10);538 w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR);539 w |= SCT_PLX_RESET_BIT;540 outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR);541 mdelay(10);542 break;543 case INF_GAZEL_R685:544 val = inl((u32)hw->cfg.start + GAZEL_CNTRL);545 val |= (GAZEL_RESET_9050 + GAZEL_RESET);546 outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);547 val &= ~(GAZEL_RESET_9050 + GAZEL_RESET);548 mdelay(4);549 outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);550 mdelay(10);551 hw->ipac.isac.adf2 = 0x87;552 hw->ipac.hscx[0].slot = 0x1f;553 hw->ipac.hscx[1].slot = 0x23;554 break;555 case INF_GAZEL_R753:556 val = inl((u32)hw->cfg.start + GAZEL_CNTRL);557 val |= (GAZEL_RESET_9050 + GAZEL_RESET);558 outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);559 val &= ~(GAZEL_RESET_9050 + GAZEL_RESET);560 mdelay(4);561 outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);562 mdelay(10);563 ipac_chip_reset(hw);564 hw->ipac.write_reg(hw, IPAC_ACFG, 0xff);565 hw->ipac.write_reg(hw, IPAC_AOE, 0x00);566 hw->ipac.conf = 0x01; /* IOM off */567 break;568 default:569 return;570 }571 enable_hwirq(hw);572}573 574static int575inf_ctrl(struct inf_hw *hw, u32 cmd, u_long arg)576{577 int ret = 0;578 579 switch (cmd) {580 case HW_RESET_REQ:581 reset_inf(hw);582 break;583 default:584 pr_info("%s: %s unknown command %x %lx\n",585 hw->name, __func__, cmd, arg);586 ret = -EINVAL;587 break;588 }589 return ret;590}591 592static int593init_irq(struct inf_hw *hw)594{595 int ret, cnt = 3;596 u_long flags;597 598 if (!hw->ci->irqfunc)599 return -EINVAL;600 ret = request_irq(hw->irq, hw->ci->irqfunc, IRQF_SHARED, hw->name, hw);601 if (ret) {602 pr_info("%s: couldn't get interrupt %d\n", hw->name, hw->irq);603 return ret;604 }605 while (cnt--) {606 spin_lock_irqsave(&hw->lock, flags);607 reset_inf(hw);608 ret = hw->ipac.init(&hw->ipac);609 if (ret) {610 spin_unlock_irqrestore(&hw->lock, flags);611 pr_info("%s: ISAC init failed with %d\n",612 hw->name, ret);613 break;614 }615 spin_unlock_irqrestore(&hw->lock, flags);616 msleep_interruptible(10);617 if (debug & DEBUG_HW)618 pr_notice("%s: IRQ %d count %d\n", hw->name,619 hw->irq, hw->irqcnt);620 if (!hw->irqcnt) {621 pr_info("%s: IRQ(%d) got no requests during init %d\n",622 hw->name, hw->irq, 3 - cnt);623 } else624 return 0;625 }626 free_irq(hw->irq, hw);627 return -EIO;628}629 630static void631release_io(struct inf_hw *hw)632{633 if (hw->cfg.mode) {634 if (hw->cfg.mode == AM_MEMIO) {635 release_mem_region(hw->cfg.start, hw->cfg.size);636 if (hw->cfg.p)637 iounmap(hw->cfg.p);638 } else639 release_region(hw->cfg.start, hw->cfg.size);640 hw->cfg.mode = AM_NONE;641 }642 if (hw->addr.mode) {643 if (hw->addr.mode == AM_MEMIO) {644 release_mem_region(hw->addr.start, hw->addr.size);645 if (hw->addr.p)646 iounmap(hw->addr.p);647 } else648 release_region(hw->addr.start, hw->addr.size);649 hw->addr.mode = AM_NONE;650 }651}652 653static int654setup_io(struct inf_hw *hw)655{656 int err = 0;657 658 if (hw->ci->cfg_mode) {659 hw->cfg.start = pci_resource_start(hw->pdev, hw->ci->cfg_bar);660 hw->cfg.size = pci_resource_len(hw->pdev, hw->ci->cfg_bar);661 if (hw->ci->cfg_mode == AM_MEMIO) {662 if (!request_mem_region(hw->cfg.start, hw->cfg.size,663 hw->name))664 err = -EBUSY;665 } else {666 if (!request_region(hw->cfg.start, hw->cfg.size,667 hw->name))668 err = -EBUSY;669 }670 if (err) {671 pr_info("mISDN: %s config port %lx (%lu bytes)"672 "already in use\n", hw->name,673 (ulong)hw->cfg.start, (ulong)hw->cfg.size);674 return err;675 }676 hw->cfg.mode = hw->ci->cfg_mode;677 if (hw->ci->cfg_mode == AM_MEMIO) {678 hw->cfg.p = ioremap(hw->cfg.start, hw->cfg.size);679 if (!hw->cfg.p)680 return -ENOMEM;681 }682 if (debug & DEBUG_HW)683 pr_notice("%s: IO cfg %lx (%lu bytes) mode%d\n",684 hw->name, (ulong)hw->cfg.start,685 (ulong)hw->cfg.size, hw->ci->cfg_mode);686 687 }688 if (hw->ci->addr_mode) {689 hw->addr.start = pci_resource_start(hw->pdev, hw->ci->addr_bar);690 hw->addr.size = pci_resource_len(hw->pdev, hw->ci->addr_bar);691 if (hw->ci->addr_mode == AM_MEMIO) {692 if (!request_mem_region(hw->addr.start, hw->addr.size,693 hw->name))694 err = -EBUSY;695 } else {696 if (!request_region(hw->addr.start, hw->addr.size,697 hw->name))698 err = -EBUSY;699 }700 if (err) {701 pr_info("mISDN: %s address port %lx (%lu bytes)"702 "already in use\n", hw->name,703 (ulong)hw->addr.start, (ulong)hw->addr.size);704 return err;705 }706 hw->addr.mode = hw->ci->addr_mode;707 if (hw->ci->addr_mode == AM_MEMIO) {708 hw->addr.p = ioremap(hw->addr.start, hw->addr.size);709 if (!hw->addr.p)710 return -ENOMEM;711 }712 if (debug & DEBUG_HW)713 pr_notice("%s: IO addr %lx (%lu bytes) mode%d\n",714 hw->name, (ulong)hw->addr.start,715 (ulong)hw->addr.size, hw->ci->addr_mode);716 717 }718 719 switch (hw->ci->typ) {720 case INF_DIVA20:721 case INF_DIVA20U:722 hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;723 hw->isac.mode = hw->cfg.mode;724 hw->isac.a.io.ale = (u32)hw->cfg.start + DIVA_ISAC_ALE;725 hw->isac.a.io.port = (u32)hw->cfg.start + DIVA_ISAC_PORT;726 hw->hscx.mode = hw->cfg.mode;727 hw->hscx.a.io.ale = (u32)hw->cfg.start + DIVA_HSCX_ALE;728 hw->hscx.a.io.port = (u32)hw->cfg.start + DIVA_HSCX_PORT;729 break;730 case INF_DIVA201:731 hw->ipac.type = IPAC_TYPE_IPAC;732 hw->ipac.isac.off = 0x80;733 hw->isac.mode = hw->addr.mode;734 hw->isac.a.p = hw->addr.p;735 hw->hscx.mode = hw->addr.mode;736 hw->hscx.a.p = hw->addr.p;737 break;738 case INF_DIVA202:739 hw->ipac.type = IPAC_TYPE_IPACX;740 hw->isac.mode = hw->addr.mode;741 hw->isac.a.p = hw->addr.p;742 hw->hscx.mode = hw->addr.mode;743 hw->hscx.a.p = hw->addr.p;744 break;745 case INF_SPEEDWIN:746 case INF_SAPHIR3:747 hw->ipac.type = IPAC_TYPE_IPAC;748 hw->ipac.isac.off = 0x80;749 hw->isac.mode = hw->cfg.mode;750 hw->isac.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE;751 hw->isac.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT;752 hw->hscx.mode = hw->cfg.mode;753 hw->hscx.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE;754 hw->hscx.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT;755 outb(0xff, (ulong)hw->cfg.start);756 mdelay(1);757 outb(0x00, (ulong)hw->cfg.start);758 mdelay(1);759 outb(TIGER_IOMASK, (ulong)hw->cfg.start + TIGER_AUX_CTRL);760 break;761 case INF_QS1000:762 case INF_QS3000:763 hw->ipac.type = IPAC_TYPE_IPAC;764 hw->ipac.isac.off = 0x80;765 hw->isac.a.io.ale = (u32)hw->addr.start;766 hw->isac.a.io.port = (u32)hw->addr.start + 1;767 hw->isac.mode = hw->addr.mode;768 hw->hscx.a.io.ale = (u32)hw->addr.start;769 hw->hscx.a.io.port = (u32)hw->addr.start + 1;770 hw->hscx.mode = hw->addr.mode;771 break;772 case INF_NICCY:773 hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;774 hw->isac.mode = hw->addr.mode;775 hw->isac.a.io.ale = (u32)hw->addr.start + NICCY_ISAC_ALE;776 hw->isac.a.io.port = (u32)hw->addr.start + NICCY_ISAC_PORT;777 hw->hscx.mode = hw->addr.mode;778 hw->hscx.a.io.ale = (u32)hw->addr.start + NICCY_HSCX_ALE;779 hw->hscx.a.io.port = (u32)hw->addr.start + NICCY_HSCX_PORT;780 break;781 case INF_SCT_1:782 hw->ipac.type = IPAC_TYPE_IPAC;783 hw->ipac.isac.off = 0x80;784 hw->isac.a.io.ale = (u32)hw->addr.start;785 hw->isac.a.io.port = hw->isac.a.io.ale + 4;786 hw->isac.mode = hw->addr.mode;787 hw->hscx.a.io.ale = hw->isac.a.io.ale;788 hw->hscx.a.io.port = hw->isac.a.io.port;789 hw->hscx.mode = hw->addr.mode;790 break;791 case INF_SCT_2:792 hw->ipac.type = IPAC_TYPE_IPAC;793 hw->ipac.isac.off = 0x80;794 hw->isac.a.io.ale = (u32)hw->addr.start + 0x08;795 hw->isac.a.io.port = hw->isac.a.io.ale + 4;796 hw->isac.mode = hw->addr.mode;797 hw->hscx.a.io.ale = hw->isac.a.io.ale;798 hw->hscx.a.io.port = hw->isac.a.io.port;799 hw->hscx.mode = hw->addr.mode;800 break;801 case INF_SCT_3:802 hw->ipac.type = IPAC_TYPE_IPAC;803 hw->ipac.isac.off = 0x80;804 hw->isac.a.io.ale = (u32)hw->addr.start + 0x10;805 hw->isac.a.io.port = hw->isac.a.io.ale + 4;806 hw->isac.mode = hw->addr.mode;807 hw->hscx.a.io.ale = hw->isac.a.io.ale;808 hw->hscx.a.io.port = hw->isac.a.io.port;809 hw->hscx.mode = hw->addr.mode;810 break;811 case INF_SCT_4:812 hw->ipac.type = IPAC_TYPE_IPAC;813 hw->ipac.isac.off = 0x80;814 hw->isac.a.io.ale = (u32)hw->addr.start + 0x20;815 hw->isac.a.io.port = hw->isac.a.io.ale + 4;816 hw->isac.mode = hw->addr.mode;817 hw->hscx.a.io.ale = hw->isac.a.io.ale;818 hw->hscx.a.io.port = hw->isac.a.io.port;819 hw->hscx.mode = hw->addr.mode;820 break;821 case INF_GAZEL_R685:822 hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;823 hw->ipac.isac.off = 0x80;824 hw->isac.mode = hw->addr.mode;825 hw->isac.a.io.port = (u32)hw->addr.start;826 hw->hscx.mode = hw->addr.mode;827 hw->hscx.a.io.port = hw->isac.a.io.port;828 break;829 case INF_GAZEL_R753:830 hw->ipac.type = IPAC_TYPE_IPAC;831 hw->ipac.isac.off = 0x80;832 hw->isac.mode = hw->addr.mode;833 hw->isac.a.io.ale = (u32)hw->addr.start;834 hw->isac.a.io.port = (u32)hw->addr.start + GAZEL_IPAC_DATA_PORT;835 hw->hscx.mode = hw->addr.mode;836 hw->hscx.a.io.ale = hw->isac.a.io.ale;837 hw->hscx.a.io.port = hw->isac.a.io.port;838 break;839 default:840 return -EINVAL;841 }842 switch (hw->isac.mode) {843 case AM_MEMIO:844 ASSIGN_FUNC_IPAC(MIO, hw->ipac);845 break;846 case AM_IND_IO:847 ASSIGN_FUNC_IPAC(IND, hw->ipac);848 break;849 case AM_IO:850 ASSIGN_FUNC_IPAC(IO, hw->ipac);851 break;852 default:853 return -EINVAL;854 }855 return 0;856}857 858static void859release_card(struct inf_hw *card) {860 ulong flags;861 int i;862 863 spin_lock_irqsave(&card->lock, flags);864 disable_hwirq(card);865 spin_unlock_irqrestore(&card->lock, flags);866 card->ipac.isac.release(&card->ipac.isac);867 free_irq(card->irq, card);868 mISDN_unregister_device(&card->ipac.isac.dch.dev);869 release_io(card);870 write_lock_irqsave(&card_lock, flags);871 list_del(&card->list);872 write_unlock_irqrestore(&card_lock, flags);873 switch (card->ci->typ) {874 case INF_SCT_2:875 case INF_SCT_3:876 case INF_SCT_4:877 break;878 case INF_SCT_1:879 for (i = 0; i < 3; i++) {880 if (card->sc[i])881 release_card(card->sc[i]);882 card->sc[i] = NULL;883 }884 fallthrough;885 default:886 pci_disable_device(card->pdev);887 pci_set_drvdata(card->pdev, NULL);888 break;889 }890 kfree(card);891 inf_cnt--;892}893 894static int895setup_instance(struct inf_hw *card)896{897 int err;898 ulong flags;899 900 snprintf(card->name, MISDN_MAX_IDLEN - 1, "%s.%d", card->ci->name,901 inf_cnt + 1);902 write_lock_irqsave(&card_lock, flags);903 list_add_tail(&card->list, &Cards);904 write_unlock_irqrestore(&card_lock, flags);905 906 _set_debug(card);907 card->ipac.isac.name = card->name;908 card->ipac.name = card->name;909 card->ipac.owner = THIS_MODULE;910 spin_lock_init(&card->lock);911 card->ipac.isac.hwlock = &card->lock;912 card->ipac.hwlock = &card->lock;913 card->ipac.ctrl = (void *)&inf_ctrl;914 915 err = setup_io(card);916 if (err)917 goto error_setup;918 919 card->ipac.isac.dch.dev.Bprotocols =920 mISDNipac_init(&card->ipac, card);921 922 if (card->ipac.isac.dch.dev.Bprotocols == 0)923 goto error_setup;924 925 err = mISDN_register_device(&card->ipac.isac.dch.dev,926 &card->pdev->dev, card->name);927 if (err)928 goto error;929 930 err = init_irq(card);931 if (!err) {932 inf_cnt++;933 pr_notice("Infineon %d cards installed\n", inf_cnt);934 return 0;935 }936 mISDN_unregister_device(&card->ipac.isac.dch.dev);937error:938 card->ipac.release(&card->ipac);939error_setup:940 release_io(card);941 write_lock_irqsave(&card_lock, flags);942 list_del(&card->list);943 write_unlock_irqrestore(&card_lock, flags);944 return err;945}946 947static const struct inf_cinfo inf_card_info[] = {948 {949 INF_DIVA20,950 "Dialogic Diva 2.0",951 "diva20",952 AM_IND_IO, AM_NONE, 2, 0,953 &diva_irq954 },955 {956 INF_DIVA20U,957 "Dialogic Diva 2.0U",958 "diva20U",959 AM_IND_IO, AM_NONE, 2, 0,960 &diva_irq961 },962 {963 INF_DIVA201,964 "Dialogic Diva 2.01",965 "diva201",966 AM_MEMIO, AM_MEMIO, 0, 1,967 &diva20x_irq968 },969 {970 INF_DIVA202,971 "Dialogic Diva 2.02",972 "diva202",973 AM_MEMIO, AM_MEMIO, 0, 1,974 &diva20x_irq975 },976 {977 INF_SPEEDWIN,978 "Sedlbauer SpeedWin PCI",979 "speedwin",980 AM_IND_IO, AM_NONE, 0, 0,981 &tiger_irq982 },983 {984 INF_SAPHIR3,985 "HST Saphir 3",986 "saphir",987 AM_IND_IO, AM_NONE, 0, 0,988 &tiger_irq989 },990 {991 INF_QS1000,992 "Develo Microlink PCI",993 "qs1000",994 AM_IO, AM_IND_IO, 1, 3,995 &elsa_irq996 },997 {998 INF_QS3000,999 "Develo QuickStep 3000",1000 "qs3000",1001 AM_IO, AM_IND_IO, 1, 3,1002 &elsa_irq1003 },1004 {1005 INF_NICCY,1006 "Sagem NICCY",1007 "niccy",1008 AM_IO, AM_IND_IO, 0, 1,1009 &niccy_irq1010 },1011 {1012 INF_SCT_1,1013 "SciTel Quadro",1014 "p1_scitel",1015 AM_IO, AM_IND_IO, 1, 5,1016 &ipac_irq1017 },1018 {1019 INF_SCT_2,1020 "SciTel Quadro",1021 "p2_scitel",1022 AM_NONE, AM_IND_IO, 0, 4,1023 &ipac_irq1024 },1025 {1026 INF_SCT_3,1027 "SciTel Quadro",1028 "p3_scitel",1029 AM_NONE, AM_IND_IO, 0, 3,1030 &ipac_irq1031 },1032 {1033 INF_SCT_4,1034 "SciTel Quadro",1035 "p4_scitel",1036 AM_NONE, AM_IND_IO, 0, 2,1037 &ipac_irq1038 },1039 {1040 INF_GAZEL_R685,1041 "Gazel R685",1042 "gazel685",1043 AM_IO, AM_IO, 1, 2,1044 &gazel_irq1045 },1046 {1047 INF_GAZEL_R753,1048 "Gazel R753",1049 "gazel753",1050 AM_IO, AM_IND_IO, 1, 2,1051 &ipac_irq1052 },1053 {1054 INF_NONE,1055 }1056};1057 1058static const struct inf_cinfo *1059get_card_info(enum inf_types typ)1060{1061 const struct inf_cinfo *ci = inf_card_info;1062 1063 while (ci->typ != INF_NONE) {1064 if (ci->typ == typ)1065 return ci;1066 ci++;1067 }1068 return NULL;1069}1070 1071static int1072inf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)1073{1074 int err = -ENOMEM;1075 struct inf_hw *card;1076 1077 card = kzalloc(sizeof(struct inf_hw), GFP_KERNEL);1078 if (!card) {1079 pr_info("No memory for Infineon ISDN card\n");1080 return err;1081 }1082 card->pdev = pdev;1083 err = pci_enable_device(pdev);1084 if (err) {1085 kfree(card);1086 return err;1087 }1088 card->ci = get_card_info(ent->driver_data);1089 if (!card->ci) {1090 pr_info("mISDN: do not have information about adapter at %s\n",1091 pci_name(pdev));1092 kfree(card);1093 pci_disable_device(pdev);1094 return -EINVAL;1095 } else1096 pr_notice("mISDN: found adapter %s at %s\n",1097 card->ci->full, pci_name(pdev));1098 1099 card->irq = pdev->irq;1100 pci_set_drvdata(pdev, card);1101 err = setup_instance(card);1102 if (err) {1103 pci_disable_device(pdev);1104 kfree(card);1105 pci_set_drvdata(pdev, NULL);1106 } else if (ent->driver_data == INF_SCT_1) {1107 int i;1108 struct inf_hw *sc;1109 1110 for (i = 1; i < 4; i++) {1111 sc = kzalloc(sizeof(struct inf_hw), GFP_KERNEL);1112 if (!sc) {1113 release_card(card);1114 pci_disable_device(pdev);1115 return -ENOMEM;1116 }1117 sc->irq = card->irq;1118 sc->pdev = card->pdev;1119 sc->ci = card->ci + i;1120 err = setup_instance(sc);1121 if (err) {1122 pci_disable_device(pdev);1123 kfree(sc);1124 release_card(card);1125 break;1126 } else1127 card->sc[i - 1] = sc;1128 }1129 }1130 return err;1131}1132 1133static void1134inf_remove(struct pci_dev *pdev)1135{1136 struct inf_hw *card = pci_get_drvdata(pdev);1137 1138 if (card)1139 release_card(card);1140 else1141 pr_debug("%s: drvdata already removed\n", __func__);1142}1143 1144static struct pci_driver infineon_driver = {1145 .name = "ISDN Infineon pci",1146 .probe = inf_probe,1147 .remove = inf_remove,1148 .id_table = infineon_ids,1149};1150 1151static int __init1152infineon_init(void)1153{1154 int err;1155 1156 pr_notice("Infineon ISDN Driver Rev. %s\n", INFINEON_REV);1157 err = pci_register_driver(&infineon_driver);1158 return err;1159}1160 1161static void __exit1162infineon_cleanup(void)1163{1164 pci_unregister_driver(&infineon_driver);1165}1166 1167module_init(infineon_init);1168module_exit(infineon_cleanup);1169