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