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