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