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