Path: blob/master/drivers/isdn/hardware/mISDN/mISDNinfineon.c
15112 views
/*1* mISDNinfineon.c2* Support for cards based on following Infineon ISDN chipsets3* - ISAC + HSCX4* - IPAC and IPAC-X5* - ISAC-SX + HSCX6*7* Supported cards:8* - Dialogic Diva 2.09* - Dialogic Diva 2.0U10* - Dialogic Diva 2.0111* - Dialogic Diva 2.0212* - Sedlbauer Speedwin13* - HST Saphir314* - Develo (former ELSA) Microlink PCI (Quickstep 1000)15* - Develo (former ELSA) Quickstep 300016* - Berkom Scitel BRIX Quadro17* - Dr.Neuhaus (Sagem) Niccy18*19*20*21* Author Karsten Keil <[email protected]>22*23* Copyright 2009 by Karsten Keil <[email protected]>24*25* This program is free software; you can redistribute it and/or modify26* it under the terms of the GNU General Public License version 2 as27* published by the Free Software Foundation.28*29* This program is distributed in the hope that it will be useful,30* but WITHOUT ANY WARRANTY; without even the implied warranty of31* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the32* GNU General Public License for more details.33*34* You should have received a copy of the GNU General Public License35* along with this program; if not, write to the Free Software36* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.37*38*/3940#include <linux/module.h>41#include <linux/pci.h>42#include <linux/delay.h>43#include <linux/mISDNhw.h>44#include <linux/slab.h>45#include "ipac.h"4647#define INFINEON_REV "1.0"4849static int inf_cnt;50static u32 debug;51static u32 irqloops = 4;5253enum inf_types {54INF_NONE,55INF_DIVA20,56INF_DIVA20U,57INF_DIVA201,58INF_DIVA202,59INF_SPEEDWIN,60INF_SAPHIR3,61INF_QS1000,62INF_QS3000,63INF_NICCY,64INF_SCT_1,65INF_SCT_2,66INF_SCT_3,67INF_SCT_4,68INF_GAZEL_R685,69INF_GAZEL_R75370};7172enum addr_mode {73AM_NONE = 0,74AM_IO,75AM_MEMIO,76AM_IND_IO,77};7879struct inf_cinfo {80enum inf_types typ;81const char *full;82const char *name;83enum addr_mode cfg_mode;84enum addr_mode addr_mode;85u8 cfg_bar;86u8 addr_bar;87void *irqfunc;88};8990struct _ioaddr {91enum addr_mode mode;92union {93void __iomem *p;94struct _ioport io;95} a;96};9798struct _iohandle {99enum addr_mode mode;100resource_size_t size;101resource_size_t start;102void __iomem *p;103};104105struct inf_hw {106struct list_head list;107struct pci_dev *pdev;108const struct inf_cinfo *ci;109char name[MISDN_MAX_IDLEN];110u32 irq;111u32 irqcnt;112struct _iohandle cfg;113struct _iohandle addr;114struct _ioaddr isac;115struct _ioaddr hscx;116spinlock_t lock; /* HW access lock */117struct ipac_hw ipac;118struct inf_hw *sc[3]; /* slave cards */119};120121122#define PCI_SUBVENDOR_HST_SAPHIR3 0x52123#define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53124#define PCI_SUB_ID_SEDLBAUER 0x01125126static struct pci_device_id infineon_ids[] __devinitdata = {127{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20), INF_DIVA20 },128{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20_U), INF_DIVA20U },129{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA201), INF_DIVA201 },130{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA202), INF_DIVA202 },131{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,132PCI_SUBVENDOR_SEDLBAUER_PCI, PCI_SUB_ID_SEDLBAUER, 0, 0,133INF_SPEEDWIN },134{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,135PCI_SUBVENDOR_HST_SAPHIR3, PCI_SUB_ID_SEDLBAUER, 0, 0, INF_SAPHIR3 },136{ PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_MICROLINK), INF_QS1000 },137{ PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_QS3000), INF_QS3000 },138{ PCI_VDEVICE(SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY), INF_NICCY },139{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,140PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO, 0, 0,141INF_SCT_1 },142{ PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R685), INF_GAZEL_R685 },143{ PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R753), INF_GAZEL_R753 },144{ PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO), INF_GAZEL_R753 },145{ PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_OLITEC), INF_GAZEL_R753 },146{ }147};148MODULE_DEVICE_TABLE(pci, infineon_ids);149150/* PCI interface specific defines */151/* Diva 2.0/2.0U */152#define DIVA_HSCX_PORT 0x00153#define DIVA_HSCX_ALE 0x04154#define DIVA_ISAC_PORT 0x08155#define DIVA_ISAC_ALE 0x0C156#define DIVA_PCI_CTRL 0x10157158/* DIVA_PCI_CTRL bits */159#define DIVA_IRQ_BIT 0x01160#define DIVA_RESET_BIT 0x08161#define DIVA_EEPROM_CLK 0x40162#define DIVA_LED_A 0x10163#define DIVA_LED_B 0x20164#define DIVA_IRQ_CLR 0x80165166/* Diva 2.01/2.02 */167/* Siemens PITA */168#define PITA_ICR_REG 0x00169#define PITA_INT0_STATUS 0x02170171#define PITA_MISC_REG 0x1c172#define PITA_PARA_SOFTRESET 0x01000000173#define PITA_SER_SOFTRESET 0x02000000174#define PITA_PARA_MPX_MODE 0x04000000175#define PITA_INT0_ENABLE 0x00020000176177/* TIGER 100 Registers */178#define TIGER_RESET_ADDR 0x00179#define TIGER_EXTERN_RESET 0x01180#define TIGER_AUX_CTRL 0x02181#define TIGER_AUX_DATA 0x03182#define TIGER_AUX_IRQMASK 0x05183#define TIGER_AUX_STATUS 0x07184185/* Tiger AUX BITs */186#define TIGER_IOMASK 0xdd /* 1 and 5 are inputs */187#define TIGER_IRQ_BIT 0x02188189#define TIGER_IPAC_ALE 0xC0190#define TIGER_IPAC_PORT 0xC8191192/* ELSA (now Develo) PCI cards */193#define ELSA_IRQ_ADDR 0x4c194#define ELSA_IRQ_MASK 0x04195#define QS1000_IRQ_OFF 0x01196#define QS3000_IRQ_OFF 0x03197#define QS1000_IRQ_ON 0x41198#define QS3000_IRQ_ON 0x43199200/* Dr Neuhaus/Sagem Niccy */201#define NICCY_ISAC_PORT 0x00202#define NICCY_HSCX_PORT 0x01203#define NICCY_ISAC_ALE 0x02204#define NICCY_HSCX_ALE 0x03205206#define NICCY_IRQ_CTRL_REG 0x38207#define NICCY_IRQ_ENABLE 0x001f00208#define NICCY_IRQ_DISABLE 0xff0000209#define NICCY_IRQ_BIT 0x800000210211212/* Scitel PLX */213#define SCT_PLX_IRQ_ADDR 0x4c214#define SCT_PLX_RESET_ADDR 0x50215#define SCT_PLX_IRQ_ENABLE 0x41216#define SCT_PLX_RESET_BIT 0x04217218/* Gazel */219#define GAZEL_IPAC_DATA_PORT 0x04220/* Gazel PLX */221#define GAZEL_CNTRL 0x50222#define GAZEL_RESET 0x04223#define GAZEL_RESET_9050 0x40000000224#define GAZEL_INCSR 0x4C225#define GAZEL_ISAC_EN 0x08226#define GAZEL_INT_ISAC 0x20227#define GAZEL_HSCX_EN 0x01228#define GAZEL_INT_HSCX 0x04229#define GAZEL_PCI_EN 0x40230#define GAZEL_IPAC_EN 0x03231232233static LIST_HEAD(Cards);234static DEFINE_RWLOCK(card_lock); /* protect Cards */235236static void237_set_debug(struct inf_hw *card)238{239card->ipac.isac.dch.debug = debug;240card->ipac.hscx[0].bch.debug = debug;241card->ipac.hscx[1].bch.debug = debug;242}243244static int245set_debug(const char *val, struct kernel_param *kp)246{247int ret;248struct inf_hw *card;249250ret = param_set_uint(val, kp);251if (!ret) {252read_lock(&card_lock);253list_for_each_entry(card, &Cards, list)254_set_debug(card);255read_unlock(&card_lock);256}257return ret;258}259260MODULE_AUTHOR("Karsten Keil");261MODULE_LICENSE("GPL v2");262MODULE_VERSION(INFINEON_REV);263module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);264MODULE_PARM_DESC(debug, "infineon debug mask");265module_param(irqloops, uint, S_IRUGO | S_IWUSR);266MODULE_PARM_DESC(irqloops, "infineon maximal irqloops (default 4)");267268/* Interface functions */269270IOFUNC_IO(ISAC, inf_hw, isac.a.io)271IOFUNC_IO(IPAC, inf_hw, hscx.a.io)272IOFUNC_IND(ISAC, inf_hw, isac.a.io)273IOFUNC_IND(IPAC, inf_hw, hscx.a.io)274IOFUNC_MEMIO(ISAC, inf_hw, u32, isac.a.p)275IOFUNC_MEMIO(IPAC, inf_hw, u32, hscx.a.p)276277static irqreturn_t278diva_irq(int intno, void *dev_id)279{280struct inf_hw *hw = dev_id;281u8 val;282283spin_lock(&hw->lock);284val = inb((u32)hw->cfg.start + DIVA_PCI_CTRL);285if (!(val & DIVA_IRQ_BIT)) { /* for us or shared ? */286spin_unlock(&hw->lock);287return IRQ_NONE; /* shared */288}289hw->irqcnt++;290mISDNipac_irq(&hw->ipac, irqloops);291spin_unlock(&hw->lock);292return IRQ_HANDLED;293}294295static irqreturn_t296diva20x_irq(int intno, void *dev_id)297{298struct inf_hw *hw = dev_id;299u8 val;300301spin_lock(&hw->lock);302val = readb(hw->cfg.p);303if (!(val & PITA_INT0_STATUS)) { /* for us or shared ? */304spin_unlock(&hw->lock);305return IRQ_NONE; /* shared */306}307hw->irqcnt++;308mISDNipac_irq(&hw->ipac, irqloops);309writeb(PITA_INT0_STATUS, hw->cfg.p); /* ACK PITA INT0 */310spin_unlock(&hw->lock);311return IRQ_HANDLED;312}313314static irqreturn_t315tiger_irq(int intno, void *dev_id)316{317struct inf_hw *hw = dev_id;318u8 val;319320spin_lock(&hw->lock);321val = inb((u32)hw->cfg.start + TIGER_AUX_STATUS);322if (val & TIGER_IRQ_BIT) { /* for us or shared ? */323spin_unlock(&hw->lock);324return IRQ_NONE; /* shared */325}326hw->irqcnt++;327mISDNipac_irq(&hw->ipac, irqloops);328spin_unlock(&hw->lock);329return IRQ_HANDLED;330}331332static irqreturn_t333elsa_irq(int intno, void *dev_id)334{335struct inf_hw *hw = dev_id;336u8 val;337338spin_lock(&hw->lock);339val = inb((u32)hw->cfg.start + ELSA_IRQ_ADDR);340if (!(val & ELSA_IRQ_MASK)) {341spin_unlock(&hw->lock);342return IRQ_NONE; /* shared */343}344hw->irqcnt++;345mISDNipac_irq(&hw->ipac, irqloops);346spin_unlock(&hw->lock);347return IRQ_HANDLED;348}349350static irqreturn_t351niccy_irq(int intno, void *dev_id)352{353struct inf_hw *hw = dev_id;354u32 val;355356spin_lock(&hw->lock);357val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);358if (!(val & NICCY_IRQ_BIT)) { /* for us or shared ? */359spin_unlock(&hw->lock);360return IRQ_NONE; /* shared */361}362outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);363hw->irqcnt++;364mISDNipac_irq(&hw->ipac, irqloops);365spin_unlock(&hw->lock);366return IRQ_HANDLED;367}368369static irqreturn_t370gazel_irq(int intno, void *dev_id)371{372struct inf_hw *hw = dev_id;373irqreturn_t ret;374375spin_lock(&hw->lock);376ret = mISDNipac_irq(&hw->ipac, irqloops);377spin_unlock(&hw->lock);378return ret;379}380381static irqreturn_t382ipac_irq(int intno, void *dev_id)383{384struct inf_hw *hw = dev_id;385u8 val;386387spin_lock(&hw->lock);388val = hw->ipac.read_reg(hw, IPAC_ISTA);389if (!(val & 0x3f)) {390spin_unlock(&hw->lock);391return IRQ_NONE; /* shared */392}393hw->irqcnt++;394mISDNipac_irq(&hw->ipac, irqloops);395spin_unlock(&hw->lock);396return IRQ_HANDLED;397}398399static void400enable_hwirq(struct inf_hw *hw)401{402u16 w;403u32 val;404405switch (hw->ci->typ) {406case INF_DIVA201:407case INF_DIVA202:408writel(PITA_INT0_ENABLE, hw->cfg.p);409break;410case INF_SPEEDWIN:411case INF_SAPHIR3:412outb(TIGER_IRQ_BIT, (u32)hw->cfg.start + TIGER_AUX_IRQMASK);413break;414case INF_QS1000:415outb(QS1000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR);416break;417case INF_QS3000:418outb(QS3000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR);419break;420case INF_NICCY:421val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);422val |= NICCY_IRQ_ENABLE;423outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);424break;425case INF_SCT_1:426w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);427w |= SCT_PLX_IRQ_ENABLE;428outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);429break;430case INF_GAZEL_R685:431outb(GAZEL_ISAC_EN + GAZEL_HSCX_EN + GAZEL_PCI_EN,432(u32)hw->cfg.start + GAZEL_INCSR);433break;434case INF_GAZEL_R753:435outb(GAZEL_IPAC_EN + GAZEL_PCI_EN,436(u32)hw->cfg.start + GAZEL_INCSR);437break;438default:439break;440}441}442443static void444disable_hwirq(struct inf_hw *hw)445{446u16 w;447u32 val;448449switch (hw->ci->typ) {450case INF_DIVA201:451case INF_DIVA202:452writel(0, hw->cfg.p);453break;454case INF_SPEEDWIN:455case INF_SAPHIR3:456outb(0, (u32)hw->cfg.start + TIGER_AUX_IRQMASK);457break;458case INF_QS1000:459outb(QS1000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR);460break;461case INF_QS3000:462outb(QS3000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR);463break;464case INF_NICCY:465val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);466val &= NICCY_IRQ_DISABLE;467outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);468break;469case INF_SCT_1:470w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);471w &= (~SCT_PLX_IRQ_ENABLE);472outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);473break;474case INF_GAZEL_R685:475case INF_GAZEL_R753:476outb(0, (u32)hw->cfg.start + GAZEL_INCSR);477break;478default:479break;480}481}482483static void484ipac_chip_reset(struct inf_hw *hw)485{486hw->ipac.write_reg(hw, IPAC_POTA2, 0x20);487mdelay(5);488hw->ipac.write_reg(hw, IPAC_POTA2, 0x00);489mdelay(5);490hw->ipac.write_reg(hw, IPAC_CONF, hw->ipac.conf);491hw->ipac.write_reg(hw, IPAC_MASK, 0xc0);492}493494static void495reset_inf(struct inf_hw *hw)496{497u16 w;498u32 val;499500if (debug & DEBUG_HW)501pr_notice("%s: resetting card\n", hw->name);502switch (hw->ci->typ) {503case INF_DIVA20:504case INF_DIVA20U:505outb(0, (u32)hw->cfg.start + DIVA_PCI_CTRL);506mdelay(10);507outb(DIVA_RESET_BIT, (u32)hw->cfg.start + DIVA_PCI_CTRL);508mdelay(10);509/* Workaround PCI9060 */510outb(9, (u32)hw->cfg.start + 0x69);511outb(DIVA_RESET_BIT | DIVA_LED_A,512(u32)hw->cfg.start + DIVA_PCI_CTRL);513break;514case INF_DIVA201:515writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE,516hw->cfg.p + PITA_MISC_REG);517mdelay(1);518writel(PITA_PARA_MPX_MODE, hw->cfg.p + PITA_MISC_REG);519mdelay(10);520break;521case INF_DIVA202:522writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE,523hw->cfg.p + PITA_MISC_REG);524mdelay(1);525writel(PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET,526hw->cfg.p + PITA_MISC_REG);527mdelay(10);528break;529case INF_SPEEDWIN:530case INF_SAPHIR3:531ipac_chip_reset(hw);532hw->ipac.write_reg(hw, IPAC_ACFG, 0xff);533hw->ipac.write_reg(hw, IPAC_AOE, 0x00);534hw->ipac.write_reg(hw, IPAC_PCFG, 0x12);535break;536case INF_QS1000:537case INF_QS3000:538ipac_chip_reset(hw);539hw->ipac.write_reg(hw, IPAC_ACFG, 0x00);540hw->ipac.write_reg(hw, IPAC_AOE, 0x3c);541hw->ipac.write_reg(hw, IPAC_ATX, 0xff);542break;543case INF_NICCY:544break;545case INF_SCT_1:546w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR);547w &= (~SCT_PLX_RESET_BIT);548outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR);549mdelay(10);550w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR);551w |= SCT_PLX_RESET_BIT;552outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR);553mdelay(10);554break;555case INF_GAZEL_R685:556val = inl((u32)hw->cfg.start + GAZEL_CNTRL);557val |= (GAZEL_RESET_9050 + GAZEL_RESET);558outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);559val &= ~(GAZEL_RESET_9050 + GAZEL_RESET);560mdelay(4);561outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);562mdelay(10);563hw->ipac.isac.adf2 = 0x87;564hw->ipac.hscx[0].slot = 0x1f;565hw->ipac.hscx[1].slot = 0x23;566break;567case INF_GAZEL_R753:568val = inl((u32)hw->cfg.start + GAZEL_CNTRL);569val |= (GAZEL_RESET_9050 + GAZEL_RESET);570outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);571val &= ~(GAZEL_RESET_9050 + GAZEL_RESET);572mdelay(4);573outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);574mdelay(10);575ipac_chip_reset(hw);576hw->ipac.write_reg(hw, IPAC_ACFG, 0xff);577hw->ipac.write_reg(hw, IPAC_AOE, 0x00);578hw->ipac.conf = 0x01; /* IOM off */579break;580default:581return;582}583enable_hwirq(hw);584}585586static int587inf_ctrl(struct inf_hw *hw, u32 cmd, u_long arg)588{589int ret = 0;590591switch (cmd) {592case HW_RESET_REQ:593reset_inf(hw);594break;595default:596pr_info("%s: %s unknown command %x %lx\n",597hw->name, __func__, cmd, arg);598ret = -EINVAL;599break;600}601return ret;602}603604static int __devinit605init_irq(struct inf_hw *hw)606{607int ret, cnt = 3;608u_long flags;609610if (!hw->ci->irqfunc)611return -EINVAL;612ret = request_irq(hw->irq, hw->ci->irqfunc, IRQF_SHARED, hw->name, hw);613if (ret) {614pr_info("%s: couldn't get interrupt %d\n", hw->name, hw->irq);615return ret;616}617while (cnt--) {618spin_lock_irqsave(&hw->lock, flags);619reset_inf(hw);620ret = hw->ipac.init(&hw->ipac);621if (ret) {622spin_unlock_irqrestore(&hw->lock, flags);623pr_info("%s: ISAC init failed with %d\n",624hw->name, ret);625break;626}627spin_unlock_irqrestore(&hw->lock, flags);628msleep_interruptible(10);629if (debug & DEBUG_HW)630pr_notice("%s: IRQ %d count %d\n", hw->name,631hw->irq, hw->irqcnt);632if (!hw->irqcnt) {633pr_info("%s: IRQ(%d) got no requests during init %d\n",634hw->name, hw->irq, 3 - cnt);635} else636return 0;637}638free_irq(hw->irq, hw);639return -EIO;640}641642static void643release_io(struct inf_hw *hw)644{645if (hw->cfg.mode) {646if (hw->cfg.p) {647release_mem_region(hw->cfg.start, hw->cfg.size);648iounmap(hw->cfg.p);649} else650release_region(hw->cfg.start, hw->cfg.size);651hw->cfg.mode = AM_NONE;652}653if (hw->addr.mode) {654if (hw->addr.p) {655release_mem_region(hw->addr.start, hw->addr.size);656iounmap(hw->addr.p);657} else658release_region(hw->addr.start, hw->addr.size);659hw->addr.mode = AM_NONE;660}661}662663static int __devinit664setup_io(struct inf_hw *hw)665{666int err = 0;667668if (hw->ci->cfg_mode) {669hw->cfg.start = pci_resource_start(hw->pdev, hw->ci->cfg_bar);670hw->cfg.size = pci_resource_len(hw->pdev, hw->ci->cfg_bar);671if (hw->ci->cfg_mode == AM_MEMIO) {672if (!request_mem_region(hw->cfg.start, hw->cfg.size,673hw->name))674err = -EBUSY;675} else {676if (!request_region(hw->cfg.start, hw->cfg.size,677hw->name))678err = -EBUSY;679}680if (err) {681pr_info("mISDN: %s config port %lx (%lu bytes)"682"already in use\n", hw->name,683(ulong)hw->cfg.start, (ulong)hw->cfg.size);684return err;685}686if (hw->ci->cfg_mode == AM_MEMIO)687hw->cfg.p = ioremap(hw->cfg.start, hw->cfg.size);688hw->cfg.mode = hw->ci->cfg_mode;689if (debug & DEBUG_HW)690pr_notice("%s: IO cfg %lx (%lu bytes) mode%d\n",691hw->name, (ulong)hw->cfg.start,692(ulong)hw->cfg.size, hw->ci->cfg_mode);693694}695if (hw->ci->addr_mode) {696hw->addr.start = pci_resource_start(hw->pdev, hw->ci->addr_bar);697hw->addr.size = pci_resource_len(hw->pdev, hw->ci->addr_bar);698if (hw->ci->addr_mode == AM_MEMIO) {699if (!request_mem_region(hw->addr.start, hw->addr.size,700hw->name))701err = -EBUSY;702} else {703if (!request_region(hw->addr.start, hw->addr.size,704hw->name))705err = -EBUSY;706}707if (err) {708pr_info("mISDN: %s address port %lx (%lu bytes)"709"already in use\n", hw->name,710(ulong)hw->addr.start, (ulong)hw->addr.size);711return err;712}713if (hw->ci->addr_mode == AM_MEMIO)714hw->addr.p = ioremap(hw->addr.start, hw->addr.size);715hw->addr.mode = hw->ci->addr_mode;716if (debug & DEBUG_HW)717pr_notice("%s: IO addr %lx (%lu bytes) mode%d\n",718hw->name, (ulong)hw->addr.start,719(ulong)hw->addr.size, hw->ci->addr_mode);720721}722723switch (hw->ci->typ) {724case INF_DIVA20:725case INF_DIVA20U:726hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;727hw->isac.mode = hw->cfg.mode;728hw->isac.a.io.ale = (u32)hw->cfg.start + DIVA_ISAC_ALE;729hw->isac.a.io.port = (u32)hw->cfg.start + DIVA_ISAC_PORT;730hw->hscx.mode = hw->cfg.mode;731hw->hscx.a.io.ale = (u32)hw->cfg.start + DIVA_HSCX_ALE;732hw->hscx.a.io.port = (u32)hw->cfg.start + DIVA_HSCX_PORT;733break;734case INF_DIVA201:735hw->ipac.type = IPAC_TYPE_IPAC;736hw->ipac.isac.off = 0x80;737hw->isac.mode = hw->addr.mode;738hw->isac.a.p = hw->addr.p;739hw->hscx.mode = hw->addr.mode;740hw->hscx.a.p = hw->addr.p;741break;742case INF_DIVA202:743hw->ipac.type = IPAC_TYPE_IPACX;744hw->isac.mode = hw->addr.mode;745hw->isac.a.p = hw->addr.p;746hw->hscx.mode = hw->addr.mode;747hw->hscx.a.p = hw->addr.p;748break;749case INF_SPEEDWIN:750case INF_SAPHIR3:751hw->ipac.type = IPAC_TYPE_IPAC;752hw->ipac.isac.off = 0x80;753hw->isac.mode = hw->cfg.mode;754hw->isac.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE;755hw->isac.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT;756hw->hscx.mode = hw->cfg.mode;757hw->hscx.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE;758hw->hscx.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT;759outb(0xff, (ulong)hw->cfg.start);760mdelay(1);761outb(0x00, (ulong)hw->cfg.start);762mdelay(1);763outb(TIGER_IOMASK, (ulong)hw->cfg.start + TIGER_AUX_CTRL);764break;765case INF_QS1000:766case INF_QS3000:767hw->ipac.type = IPAC_TYPE_IPAC;768hw->ipac.isac.off = 0x80;769hw->isac.a.io.ale = (u32)hw->addr.start;770hw->isac.a.io.port = (u32)hw->addr.start + 1;771hw->isac.mode = hw->addr.mode;772hw->hscx.a.io.ale = (u32)hw->addr.start;773hw->hscx.a.io.port = (u32)hw->addr.start + 1;774hw->hscx.mode = hw->addr.mode;775break;776case INF_NICCY:777hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;778hw->isac.mode = hw->addr.mode;779hw->isac.a.io.ale = (u32)hw->addr.start + NICCY_ISAC_ALE;780hw->isac.a.io.port = (u32)hw->addr.start + NICCY_ISAC_PORT;781hw->hscx.mode = hw->addr.mode;782hw->hscx.a.io.ale = (u32)hw->addr.start + NICCY_HSCX_ALE;783hw->hscx.a.io.port = (u32)hw->addr.start + NICCY_HSCX_PORT;784break;785case INF_SCT_1:786hw->ipac.type = IPAC_TYPE_IPAC;787hw->ipac.isac.off = 0x80;788hw->isac.a.io.ale = (u32)hw->addr.start;789hw->isac.a.io.port = hw->isac.a.io.ale + 4;790hw->isac.mode = hw->addr.mode;791hw->hscx.a.io.ale = hw->isac.a.io.ale;792hw->hscx.a.io.port = hw->isac.a.io.port;793hw->hscx.mode = hw->addr.mode;794break;795case INF_SCT_2:796hw->ipac.type = IPAC_TYPE_IPAC;797hw->ipac.isac.off = 0x80;798hw->isac.a.io.ale = (u32)hw->addr.start + 0x08;799hw->isac.a.io.port = hw->isac.a.io.ale + 4;800hw->isac.mode = hw->addr.mode;801hw->hscx.a.io.ale = hw->isac.a.io.ale;802hw->hscx.a.io.port = hw->isac.a.io.port;803hw->hscx.mode = hw->addr.mode;804break;805case INF_SCT_3:806hw->ipac.type = IPAC_TYPE_IPAC;807hw->ipac.isac.off = 0x80;808hw->isac.a.io.ale = (u32)hw->addr.start + 0x10;809hw->isac.a.io.port = hw->isac.a.io.ale + 4;810hw->isac.mode = hw->addr.mode;811hw->hscx.a.io.ale = hw->isac.a.io.ale;812hw->hscx.a.io.port = hw->isac.a.io.port;813hw->hscx.mode = hw->addr.mode;814break;815case INF_SCT_4:816hw->ipac.type = IPAC_TYPE_IPAC;817hw->ipac.isac.off = 0x80;818hw->isac.a.io.ale = (u32)hw->addr.start + 0x20;819hw->isac.a.io.port = hw->isac.a.io.ale + 4;820hw->isac.mode = hw->addr.mode;821hw->hscx.a.io.ale = hw->isac.a.io.ale;822hw->hscx.a.io.port = hw->isac.a.io.port;823hw->hscx.mode = hw->addr.mode;824break;825case INF_GAZEL_R685:826hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;827hw->ipac.isac.off = 0x80;828hw->isac.mode = hw->addr.mode;829hw->isac.a.io.port = (u32)hw->addr.start;830hw->hscx.mode = hw->addr.mode;831hw->hscx.a.io.port = hw->isac.a.io.port;832break;833case INF_GAZEL_R753:834hw->ipac.type = IPAC_TYPE_IPAC;835hw->ipac.isac.off = 0x80;836hw->isac.mode = hw->addr.mode;837hw->isac.a.io.ale = (u32)hw->addr.start;838hw->isac.a.io.port = (u32)hw->addr.start + GAZEL_IPAC_DATA_PORT;839hw->hscx.mode = hw->addr.mode;840hw->hscx.a.io.ale = hw->isac.a.io.ale;841hw->hscx.a.io.port = hw->isac.a.io.port;842break;843default:844return -EINVAL;845}846switch (hw->isac.mode) {847case AM_MEMIO:848ASSIGN_FUNC_IPAC(MIO, hw->ipac);849break;850case AM_IND_IO:851ASSIGN_FUNC_IPAC(IND, hw->ipac);852break;853case AM_IO:854ASSIGN_FUNC_IPAC(IO, hw->ipac);855break;856default:857return -EINVAL;858}859return 0;860}861862static void863release_card(struct inf_hw *card) {864ulong flags;865int i;866867spin_lock_irqsave(&card->lock, flags);868disable_hwirq(card);869spin_unlock_irqrestore(&card->lock, flags);870card->ipac.isac.release(&card->ipac.isac);871free_irq(card->irq, card);872mISDN_unregister_device(&card->ipac.isac.dch.dev);873release_io(card);874write_lock_irqsave(&card_lock, flags);875list_del(&card->list);876write_unlock_irqrestore(&card_lock, flags);877switch (card->ci->typ) {878case INF_SCT_2:879case INF_SCT_3:880case INF_SCT_4:881break;882case INF_SCT_1:883for (i = 0; i < 3; i++) {884if (card->sc[i])885release_card(card->sc[i]);886card->sc[i] = NULL;887}888default:889pci_disable_device(card->pdev);890pci_set_drvdata(card->pdev, NULL);891break;892}893kfree(card);894inf_cnt--;895}896897static int __devinit898setup_instance(struct inf_hw *card)899{900int err;901ulong flags;902903snprintf(card->name, MISDN_MAX_IDLEN - 1, "%s.%d", card->ci->name,904inf_cnt + 1);905write_lock_irqsave(&card_lock, flags);906list_add_tail(&card->list, &Cards);907write_unlock_irqrestore(&card_lock, flags);908909_set_debug(card);910card->ipac.isac.name = card->name;911card->ipac.name = card->name;912card->ipac.owner = THIS_MODULE;913spin_lock_init(&card->lock);914card->ipac.isac.hwlock = &card->lock;915card->ipac.hwlock = &card->lock;916card->ipac.ctrl = (void *)&inf_ctrl;917918err = setup_io(card);919if (err)920goto error_setup;921922card->ipac.isac.dch.dev.Bprotocols =923mISDNipac_init(&card->ipac, card);924925if (card->ipac.isac.dch.dev.Bprotocols == 0)926goto error_setup;927928err = mISDN_register_device(&card->ipac.isac.dch.dev,929&card->pdev->dev, card->name);930if (err)931goto error;932933err = init_irq(card);934if (!err) {935inf_cnt++;936pr_notice("Infineon %d cards installed\n", inf_cnt);937return 0;938}939mISDN_unregister_device(&card->ipac.isac.dch.dev);940error:941card->ipac.release(&card->ipac);942error_setup:943release_io(card);944write_lock_irqsave(&card_lock, flags);945list_del(&card->list);946write_unlock_irqrestore(&card_lock, flags);947return err;948}949950static const struct inf_cinfo inf_card_info[] = {951{952INF_DIVA20,953"Dialogic Diva 2.0",954"diva20",955AM_IND_IO, AM_NONE, 2, 0,956&diva_irq957},958{959INF_DIVA20U,960"Dialogic Diva 2.0U",961"diva20U",962AM_IND_IO, AM_NONE, 2, 0,963&diva_irq964},965{966INF_DIVA201,967"Dialogic Diva 2.01",968"diva201",969AM_MEMIO, AM_MEMIO, 0, 1,970&diva20x_irq971},972{973INF_DIVA202,974"Dialogic Diva 2.02",975"diva202",976AM_MEMIO, AM_MEMIO, 0, 1,977&diva20x_irq978},979{980INF_SPEEDWIN,981"Sedlbauer SpeedWin PCI",982"speedwin",983AM_IND_IO, AM_NONE, 0, 0,984&tiger_irq985},986{987INF_SAPHIR3,988"HST Saphir 3",989"saphir",990AM_IND_IO, AM_NONE, 0, 0,991&tiger_irq992},993{994INF_QS1000,995"Develo Microlink PCI",996"qs1000",997AM_IO, AM_IND_IO, 1, 3,998&elsa_irq999},1000{1001INF_QS3000,1002"Develo QuickStep 3000",1003"qs3000",1004AM_IO, AM_IND_IO, 1, 3,1005&elsa_irq1006},1007{1008INF_NICCY,1009"Sagem NICCY",1010"niccy",1011AM_IO, AM_IND_IO, 0, 1,1012&niccy_irq1013},1014{1015INF_SCT_1,1016"SciTel Quadro",1017"p1_scitel",1018AM_IO, AM_IND_IO, 1, 5,1019&ipac_irq1020},1021{1022INF_SCT_2,1023"SciTel Quadro",1024"p2_scitel",1025AM_NONE, AM_IND_IO, 0, 4,1026&ipac_irq1027},1028{1029INF_SCT_3,1030"SciTel Quadro",1031"p3_scitel",1032AM_NONE, AM_IND_IO, 0, 3,1033&ipac_irq1034},1035{1036INF_SCT_4,1037"SciTel Quadro",1038"p4_scitel",1039AM_NONE, AM_IND_IO, 0, 2,1040&ipac_irq1041},1042{1043INF_GAZEL_R685,1044"Gazel R685",1045"gazel685",1046AM_IO, AM_IO, 1, 2,1047&gazel_irq1048},1049{1050INF_GAZEL_R753,1051"Gazel R753",1052"gazel753",1053AM_IO, AM_IND_IO, 1, 2,1054&ipac_irq1055},1056{1057INF_NONE,1058}1059};10601061static const struct inf_cinfo * __devinit1062get_card_info(enum inf_types typ)1063{1064const struct inf_cinfo *ci = inf_card_info;10651066while (ci->typ != INF_NONE) {1067if (ci->typ == typ)1068return ci;1069ci++;1070}1071return NULL;1072}10731074static int __devinit1075inf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)1076{1077int err = -ENOMEM;1078struct inf_hw *card;10791080card = kzalloc(sizeof(struct inf_hw), GFP_KERNEL);1081if (!card) {1082pr_info("No memory for Infineon ISDN card\n");1083return err;1084}1085card->pdev = pdev;1086err = pci_enable_device(pdev);1087if (err) {1088kfree(card);1089return err;1090}1091card->ci = get_card_info(ent->driver_data);1092if (!card->ci) {1093pr_info("mISDN: do not have informations about adapter at %s\n",1094pci_name(pdev));1095kfree(card);1096pci_disable_device(pdev);1097return -EINVAL;1098} else1099pr_notice("mISDN: found adapter %s at %s\n",1100card->ci->full, pci_name(pdev));11011102card->irq = pdev->irq;1103pci_set_drvdata(pdev, card);1104err = setup_instance(card);1105if (err) {1106pci_disable_device(pdev);1107kfree(card);1108pci_set_drvdata(pdev, NULL);1109} else if (ent->driver_data == INF_SCT_1) {1110int i;1111struct inf_hw *sc;11121113for (i = 1; i < 4; i++) {1114sc = kzalloc(sizeof(struct inf_hw), GFP_KERNEL);1115if (!sc) {1116release_card(card);1117pci_disable_device(pdev);1118return -ENOMEM;1119}1120sc->irq = card->irq;1121sc->pdev = card->pdev;1122sc->ci = card->ci + i;1123err = setup_instance(sc);1124if (err) {1125pci_disable_device(pdev);1126kfree(sc);1127release_card(card);1128break;1129} else1130card->sc[i - 1] = sc;1131}1132}1133return err;1134}11351136static void __devexit1137inf_remove(struct pci_dev *pdev)1138{1139struct inf_hw *card = pci_get_drvdata(pdev);11401141if (card)1142release_card(card);1143else1144pr_debug("%s: drvdata already removed\n", __func__);1145}11461147static struct pci_driver infineon_driver = {1148.name = "ISDN Infineon pci",1149.probe = inf_probe,1150.remove = __devexit_p(inf_remove),1151.id_table = infineon_ids,1152};11531154static int __init1155infineon_init(void)1156{1157int err;11581159pr_notice("Infineon ISDN Driver Rev. %s\n", INFINEON_REV);1160err = pci_register_driver(&infineon_driver);1161return err;1162}11631164static void __exit1165infineon_cleanup(void)1166{1167pci_unregister_driver(&infineon_driver);1168}11691170module_init(infineon_init);1171module_exit(infineon_cleanup);117211731174