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