xref: /openbmc/linux/drivers/isdn/hardware/mISDN/mISDNinfineon.c (revision cae86d4a4e56eeda1afdea38f230d222edda7dd5)
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