aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn
diff options
context:
space:
mode:
authorKarsten Keil <keil@b1-systems.de>2009-07-22 13:42:46 -0400
committerKarsten Keil <keil@b1-systems.de>2009-07-25 14:18:29 -0400
commitcae86d4a4e56eeda1afdea38f230d222edda7dd5 (patch)
tree78726e574c914abb2df7185d77aab0fa28fd7846 /drivers/isdn
parentfb286f0471a04ef646c8e5c79750ae6718183745 (diff)
mISDN: Add driver for Infineon ISDN chipset family
This driver supports cards with Infineon ISAC/HSCX, ISACX, IPAC and IPACX chips from various manufacturers. Signed-off-by: Karsten Keil <keil@b1-systems.de>
Diffstat (limited to 'drivers/isdn')
-rw-r--r--drivers/isdn/hardware/mISDN/Kconfig14
-rw-r--r--drivers/isdn/hardware/mISDN/Makefile3
-rw-r--r--drivers/isdn/hardware/mISDN/iohelper.h109
-rw-r--r--drivers/isdn/hardware/mISDN/ipac.h405
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNinfineon.c1178
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNipac.c1655
6 files changed, 3364 insertions, 0 deletions
diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig
index 3024566dd099..a8542b81f95c 100644
--- a/drivers/isdn/hardware/mISDN/Kconfig
+++ b/drivers/isdn/hardware/mISDN/Kconfig
@@ -39,3 +39,17 @@ config MISDN_HFCUSB
39 Enable support for USB ISDN TAs with Cologne Chip AG's 39 Enable support for USB ISDN TAs with Cologne Chip AG's
40 HFC-S USB ISDN Controller 40 HFC-S USB ISDN Controller
41 41
42config MISDN_INFINEON
43 tristate "Support for cards with Infineon chipset"
44 depends on MISDN
45 depends on PCI
46 select MISDN_IPAC
47 help
48 Enable support for cards with ISAC + HSCX, IPAC or IPAC-SX
49 chip from Infineon (former manufacturer Siemens).
50
51
52config MISDN_IPAC
53 tristate
54 depends on MISDN
55
diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile
index b0403526bbba..2863455b4939 100644
--- a/drivers/isdn/hardware/mISDN/Makefile
+++ b/drivers/isdn/hardware/mISDN/Makefile
@@ -6,3 +6,6 @@
6obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o 6obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o
7obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o 7obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o
8obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o 8obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o
9obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o
10# chip modules
11obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o
diff --git a/drivers/isdn/hardware/mISDN/iohelper.h b/drivers/isdn/hardware/mISDN/iohelper.h
new file mode 100644
index 000000000000..c16a217301e8
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/iohelper.h
@@ -0,0 +1,109 @@
1/*
2 * iohelper.h
3 * helper for define functions to access ISDN hardware
4 * supported are memory mapped IO
5 * indirect port IO (one port for address, one for data)
6 *
7 * Author Karsten Keil <keil@isdn4linux.de>
8 *
9 * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25
26#ifndef _IOHELPER_H
27#define _IOHELPER_H
28
29typedef u8 (read_reg_t)(void *, u8);
30typedef void (write_reg_t)(void *, u8, u8);
31typedef void (fifo_func_t)(void *, u8, u8 *, int);
32
33struct _ioport {
34 u32 port;
35 u32 ale;
36};
37
38#define IOFUNC_IO(name, hws, ap) \
39 static u8 Read##name##_IO(void *p, u8 off) {\
40 struct hws *hw = p;\
41 return inb(hw->ap.port + off);\
42 } \
43 static void Write##name##_IO(void *p, u8 off, u8 val) {\
44 struct hws *hw = p;\
45 outb(val, hw->ap.port + off);\
46 } \
47 static void ReadFiFo##name##_IO(void *p, u8 off, u8 *dp, int size) {\
48 struct hws *hw = p;\
49 insb(hw->ap.port + off, dp, size);\
50 } \
51 static void WriteFiFo##name##_IO(void *p, u8 off, u8 *dp, int size) {\
52 struct hws *hw = p;\
53 outsb(hw->ap.port + off, dp, size);\
54 }
55
56#define IOFUNC_IND(name, hws, ap) \
57 static u8 Read##name##_IND(void *p, u8 off) {\
58 struct hws *hw = p;\
59 outb(off, hw->ap.ale);\
60 return inb(hw->ap.port);\
61 } \
62 static void Write##name##_IND(void *p, u8 off, u8 val) {\
63 struct hws *hw = p;\
64 outb(off, hw->ap.ale);\
65 outb(val, hw->ap.port);\
66 } \
67 static void ReadFiFo##name##_IND(void *p, u8 off, u8 *dp, int size) {\
68 struct hws *hw = p;\
69 outb(off, hw->ap.ale);\
70 insb(hw->ap.port, dp, size);\
71 } \
72 static void WriteFiFo##name##_IND(void *p, u8 off, u8 *dp, int size) {\
73 struct hws *hw = p;\
74 outb(off, hw->ap.ale);\
75 outsb(hw->ap.port, dp, size);\
76 }
77
78#define IOFUNC_MEMIO(name, hws, typ, adr) \
79 static u8 Read##name##_MIO(void *p, u8 off) {\
80 struct hws *hw = p;\
81 return readb(((typ *)hw->adr) + off);\
82 } \
83 static void Write##name##_MIO(void *p, u8 off, u8 val) {\
84 struct hws *hw = p;\
85 writeb(val, ((typ *)hw->adr) + off);\
86 } \
87 static void ReadFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) {\
88 struct hws *hw = p;\
89 while (size--)\
90 *dp++ = readb(((typ *)hw->adr) + off);\
91 } \
92 static void WriteFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) {\
93 struct inf_hw *hw = p;\
94 while (size--)\
95 writeb(*dp++, ((typ *)hw->adr) + off);\
96 }
97
98#define ASSIGN_FUNC(typ, name, dest) do {\
99 dest.read_reg = &Read##name##_##typ;\
100 dest.write_reg = &Write##name##_##typ;\
101 dest.read_fifo = &ReadFiFo##name##_##typ;\
102 dest.write_fifo = &WriteFiFo##name##_##typ;\
103 } while (0)
104#define ASSIGN_FUNC_IPAC(typ, target) do {\
105 ASSIGN_FUNC(typ, ISAC, target.isac);\
106 ASSIGN_FUNC(typ, IPAC, target);\
107 } while (0)
108
109#endif \ No newline at end of file
diff --git a/drivers/isdn/hardware/mISDN/ipac.h b/drivers/isdn/hardware/mISDN/ipac.h
new file mode 100644
index 000000000000..f9601d55dbca
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/ipac.h
@@ -0,0 +1,405 @@
1/*
2 *
3 * ipac.h Defines for the Infineon (former Siemens) ISDN
4 * chip series
5 *
6 * Author Karsten Keil <keil@isdn4linux.de>
7 *
8 * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24
25#include "iohelper.h"
26
27struct isac_hw {
28 struct dchannel dch;
29 u32 type;
30 u32 off; /* offset to isac regs */
31 char *name;
32 spinlock_t *hwlock; /* lock HW acccess */
33 read_reg_t *read_reg;
34 write_reg_t *write_reg;
35 fifo_func_t *read_fifo;
36 fifo_func_t *write_fifo;
37 int (*monitor)(void *, u32, u8 *, int);
38 void (*release)(struct isac_hw *);
39 int (*init)(struct isac_hw *);
40 int (*ctrl)(struct isac_hw *, u32, u_long);
41 int (*open)(struct isac_hw *, struct channel_req *);
42 u8 *mon_tx;
43 u8 *mon_rx;
44 int mon_txp;
45 int mon_txc;
46 int mon_rxp;
47 struct arcofi_msg *arcofi_list;
48 struct timer_list arcofitimer;
49 wait_queue_head_t arcofi_wait;
50 u8 arcofi_bc;
51 u8 arcofi_state;
52 u8 mocr;
53 u8 adf2;
54 u8 state;
55};
56
57struct ipac_hw;
58
59struct hscx_hw {
60 struct bchannel bch;
61 struct ipac_hw *ip;
62 u8 fifo_size;
63 u8 off; /* offset to ICA or ICB */
64 u8 slot;
65 char log[64];
66};
67
68struct ipac_hw {
69 struct isac_hw isac;
70 struct hscx_hw hscx[2];
71 char *name;
72 void *hw;
73 spinlock_t *hwlock; /* lock HW acccess */
74 struct module *owner;
75 u32 type;
76 read_reg_t *read_reg;
77 write_reg_t *write_reg;
78 fifo_func_t *read_fifo;
79 fifo_func_t *write_fifo;
80 void (*release)(struct ipac_hw *);
81 int (*init)(struct ipac_hw *);
82 int (*ctrl)(struct ipac_hw *, u32, u_long);
83 u8 conf;
84};
85
86#define IPAC_TYPE_ISAC 0x0010
87#define IPAC_TYPE_IPAC 0x0020
88#define IPAC_TYPE_ISACX 0x0040
89#define IPAC_TYPE_IPACX 0x0080
90#define IPAC_TYPE_HSCX 0x0100
91
92#define ISAC_USE_ARCOFI 0x1000
93
94/* Monitor functions */
95#define MONITOR_RX_0 0x1000
96#define MONITOR_RX_1 0x1001
97#define MONITOR_TX_0 0x2000
98#define MONITOR_TX_1 0x2001
99
100/* All registers original Siemens Spec */
101/* IPAC/ISAC registers */
102#define ISAC_MASK 0x20
103#define ISAC_ISTA 0x20
104#define ISAC_STAR 0x21
105#define ISAC_CMDR 0x21
106#define ISAC_EXIR 0x24
107#define ISAC_ADF2 0x39
108#define ISAC_SPCR 0x30
109#define ISAC_ADF1 0x38
110#define ISAC_CIR0 0x31
111#define ISAC_CIX0 0x31
112#define ISAC_CIR1 0x33
113#define ISAC_CIX1 0x33
114#define ISAC_STCR 0x37
115#define ISAC_MODE 0x22
116#define ISAC_RSTA 0x27
117#define ISAC_RBCL 0x25
118#define ISAC_RBCH 0x2A
119#define ISAC_TIMR 0x23
120#define ISAC_SQXR 0x3b
121#define ISAC_SQRR 0x3b
122#define ISAC_MOSR 0x3a
123#define ISAC_MOCR 0x3a
124#define ISAC_MOR0 0x32
125#define ISAC_MOX0 0x32
126#define ISAC_MOR1 0x34
127#define ISAC_MOX1 0x34
128
129#define ISAC_RBCH_XAC 0x80
130
131#define IPAC_D_TIN2 0x01
132
133/* IPAC/HSCX */
134#define IPAC_ISTAB 0x20 /* RD */
135#define IPAC_MASKB 0x20 /* WR */
136#define IPAC_STARB 0x21 /* RD */
137#define IPAC_CMDRB 0x21 /* WR */
138#define IPAC_MODEB 0x22 /* R/W */
139#define IPAC_EXIRB 0x24 /* RD */
140#define IPAC_RBCLB 0x25 /* RD */
141#define IPAC_RAH1 0x26 /* WR */
142#define IPAC_RAH2 0x27 /* WR */
143#define IPAC_RSTAB 0x27 /* RD */
144#define IPAC_RAL1 0x28 /* R/W */
145#define IPAC_RAL2 0x29 /* WR */
146#define IPAC_RHCRB 0x29 /* RD */
147#define IPAC_XBCL 0x2A /* WR */
148#define IPAC_CCR2 0x2C /* R/W */
149#define IPAC_RBCHB 0x2D /* RD */
150#define IPAC_XBCH 0x2D /* WR */
151#define HSCX_VSTR 0x2E /* RD */
152#define IPAC_RLCR 0x2E /* WR */
153#define IPAC_CCR1 0x2F /* R/W */
154#define IPAC_TSAX 0x30 /* WR */
155#define IPAC_TSAR 0x31 /* WR */
156#define IPAC_XCCR 0x32 /* WR */
157#define IPAC_RCCR 0x33 /* WR */
158
159/* IPAC_ISTAB/IPAC_MASKB bits */
160#define IPAC_B_XPR 0x10
161#define IPAC_B_RPF 0x40
162#define IPAC_B_RME 0x80
163#define IPAC_B_ON 0x2F
164
165/* IPAC_EXIRB bits */
166#define IPAC_B_RFS 0x04
167#define IPAC_B_RFO 0x10
168#define IPAC_B_XDU 0x40
169#define IPAC_B_XMR 0x80
170
171/* IPAC special registers */
172#define IPAC_CONF 0xC0 /* R/W */
173#define IPAC_ISTA 0xC1 /* RD */
174#define IPAC_MASK 0xC1 /* WR */
175#define IPAC_ID 0xC2 /* RD */
176#define IPAC_ACFG 0xC3 /* R/W */
177#define IPAC_AOE 0xC4 /* R/W */
178#define IPAC_ARX 0xC5 /* RD */
179#define IPAC_ATX 0xC5 /* WR */
180#define IPAC_PITA1 0xC6 /* R/W */
181#define IPAC_PITA2 0xC7 /* R/W */
182#define IPAC_POTA1 0xC8 /* R/W */
183#define IPAC_POTA2 0xC9 /* R/W */
184#define IPAC_PCFG 0xCA /* R/W */
185#define IPAC_SCFG 0xCB /* R/W */
186#define IPAC_TIMR2 0xCC /* R/W */
187
188/* IPAC_ISTA/_MASK bits */
189#define IPAC__EXB 0x01
190#define IPAC__ICB 0x02
191#define IPAC__EXA 0x04
192#define IPAC__ICA 0x08
193#define IPAC__EXD 0x10
194#define IPAC__ICD 0x20
195#define IPAC__INT0 0x40
196#define IPAC__INT1 0x80
197#define IPAC__ON 0xC0
198
199/* HSCX ISTA/MASK bits */
200#define HSCX__EXB 0x01
201#define HSCX__EXA 0x02
202#define HSCX__ICA 0x04
203
204/* ISAC/ISACX/IPAC/IPACX L1 commands */
205#define ISAC_CMD_TIM 0x0
206#define ISAC_CMD_RS 0x1
207#define ISAC_CMD_SCZ 0x4
208#define ISAC_CMD_SSZ 0x2
209#define ISAC_CMD_AR8 0x8
210#define ISAC_CMD_AR10 0x9
211#define ISAC_CMD_ARL 0xA
212#define ISAC_CMD_DUI 0xF
213
214/* ISAC/ISACX/IPAC/IPACX L1 indications */
215#define ISAC_IND_RS 0x1
216#define ISAC_IND_PU 0x7
217#define ISAC_IND_DR 0x0
218#define ISAC_IND_SD 0x2
219#define ISAC_IND_DIS 0x3
220#define ISAC_IND_EI 0x6
221#define ISAC_IND_RSY 0x4
222#define ISAC_IND_ARD 0x8
223#define ISAC_IND_TI 0xA
224#define ISAC_IND_ATI 0xB
225#define ISAC_IND_AI8 0xC
226#define ISAC_IND_AI10 0xD
227#define ISAC_IND_DID 0xF
228
229/* the new ISACX / IPACX */
230/* D-channel registers */
231#define ISACX_RFIFOD 0x00 /* RD */
232#define ISACX_XFIFOD 0x00 /* WR */
233#define ISACX_ISTAD 0x20 /* RD */
234#define ISACX_MASKD 0x20 /* WR */
235#define ISACX_STARD 0x21 /* RD */
236#define ISACX_CMDRD 0x21 /* WR */
237#define ISACX_MODED 0x22 /* R/W */
238#define ISACX_EXMD1 0x23 /* R/W */
239#define ISACX_TIMR1 0x24 /* R/W */
240#define ISACX_SAP1 0x25 /* WR */
241#define ISACX_SAP2 0x26 /* WR */
242#define ISACX_RBCLD 0x26 /* RD */
243#define ISACX_RBCHD 0x27 /* RD */
244#define ISACX_TEI1 0x27 /* WR */
245#define ISACX_TEI2 0x28 /* WR */
246#define ISACX_RSTAD 0x28 /* RD */
247#define ISACX_TMD 0x29 /* R/W */
248#define ISACX_CIR0 0x2E /* RD */
249#define ISACX_CIX0 0x2E /* WR */
250#define ISACX_CIR1 0x2F /* RD */
251#define ISACX_CIX1 0x2F /* WR */
252
253/* Transceiver registers */
254#define ISACX_TR_CONF0 0x30 /* R/W */
255#define ISACX_TR_CONF1 0x31 /* R/W */
256#define ISACX_TR_CONF2 0x32 /* R/W */
257#define ISACX_TR_STA 0x33 /* RD */
258#define ISACX_TR_CMD 0x34 /* R/W */
259#define ISACX_SQRR1 0x35 /* RD */
260#define ISACX_SQXR1 0x35 /* WR */
261#define ISACX_SQRR2 0x36 /* RD */
262#define ISACX_SQXR2 0x36 /* WR */
263#define ISACX_SQRR3 0x37 /* RD */
264#define ISACX_SQXR3 0x37 /* WR */
265#define ISACX_ISTATR 0x38 /* RD */
266#define ISACX_MASKTR 0x39 /* R/W */
267#define ISACX_TR_MODE 0x3A /* R/W */
268#define ISACX_ACFG1 0x3C /* R/W */
269#define ISACX_ACFG2 0x3D /* R/W */
270#define ISACX_AOE 0x3E /* R/W */
271#define ISACX_ARX 0x3F /* RD */
272#define ISACX_ATX 0x3F /* WR */
273
274/* IOM: Timeslot, DPS, CDA */
275#define ISACX_CDA10 0x40 /* R/W */
276#define ISACX_CDA11 0x41 /* R/W */
277#define ISACX_CDA20 0x42 /* R/W */
278#define ISACX_CDA21 0x43 /* R/W */
279#define ISACX_CDA_TSDP10 0x44 /* R/W */
280#define ISACX_CDA_TSDP11 0x45 /* R/W */
281#define ISACX_CDA_TSDP20 0x46 /* R/W */
282#define ISACX_CDA_TSDP21 0x47 /* R/W */
283#define ISACX_BCHA_TSDP_BC1 0x48 /* R/W */
284#define ISACX_BCHA_TSDP_BC2 0x49 /* R/W */
285#define ISACX_BCHB_TSDP_BC1 0x4A /* R/W */
286#define ISACX_BCHB_TSDP_BC2 0x4B /* R/W */
287#define ISACX_TR_TSDP_BC1 0x4C /* R/W */
288#define ISACX_TR_TSDP_BC2 0x4D /* R/W */
289#define ISACX_CDA1_CR 0x4E /* R/W */
290#define ISACX_CDA2_CR 0x4F /* R/W */
291
292/* IOM: Contol, Sync transfer, Monitor */
293#define ISACX_TR_CR 0x50 /* R/W */
294#define ISACX_TRC_CR 0x50 /* R/W */
295#define ISACX_BCHA_CR 0x51 /* R/W */
296#define ISACX_BCHB_CR 0x52 /* R/W */
297#define ISACX_DCI_CR 0x53 /* R/W */
298#define ISACX_DCIC_CR 0x53 /* R/W */
299#define ISACX_MON_CR 0x54 /* R/W */
300#define ISACX_SDS1_CR 0x55 /* R/W */
301#define ISACX_SDS2_CR 0x56 /* R/W */
302#define ISACX_IOM_CR 0x57 /* R/W */
303#define ISACX_STI 0x58 /* RD */
304#define ISACX_ASTI 0x58 /* WR */
305#define ISACX_MSTI 0x59 /* R/W */
306#define ISACX_SDS_CONF 0x5A /* R/W */
307#define ISACX_MCDA 0x5B /* RD */
308#define ISACX_MOR 0x5C /* RD */
309#define ISACX_MOX 0x5C /* WR */
310#define ISACX_MOSR 0x5D /* RD */
311#define ISACX_MOCR 0x5E /* R/W */
312#define ISACX_MSTA 0x5F /* RD */
313#define ISACX_MCONF 0x5F /* WR */
314
315/* Interrupt and general registers */
316#define ISACX_ISTA 0x60 /* RD */
317#define ISACX_MASK 0x60 /* WR */
318#define ISACX_AUXI 0x61 /* RD */
319#define ISACX_AUXM 0x61 /* WR */
320#define ISACX_MODE1 0x62 /* R/W */
321#define ISACX_MODE2 0x63 /* R/W */
322#define ISACX_ID 0x64 /* RD */
323#define ISACX_SRES 0x64 /* WR */
324#define ISACX_TIMR2 0x65 /* R/W */
325
326/* Register Bits */
327/* ISACX/IPACX _ISTAD (R) and _MASKD (W) */
328#define ISACX_D_XDU 0x04
329#define ISACX_D_XMR 0x08
330#define ISACX_D_XPR 0x10
331#define ISACX_D_RFO 0x20
332#define ISACX_D_RPF 0x40
333#define ISACX_D_RME 0x80
334
335/* ISACX/IPACX _ISTA (R) and _MASK (W) */
336#define ISACX__ICD 0x01
337#define ISACX__MOS 0x02
338#define ISACX__TRAN 0x04
339#define ISACX__AUX 0x08
340#define ISACX__CIC 0x10
341#define ISACX__ST 0x20
342#define IPACX__ICB 0x40
343#define IPACX__ICA 0x80
344#define IPACX__ON 0x2C
345
346/* ISACX/IPACX _CMDRD (W) */
347#define ISACX_CMDRD_XRES 0x01
348#define ISACX_CMDRD_XME 0x02
349#define ISACX_CMDRD_XTF 0x08
350#define ISACX_CMDRD_STI 0x10
351#define ISACX_CMDRD_RRES 0x40
352#define ISACX_CMDRD_RMC 0x80
353
354/* ISACX/IPACX _RSTAD (R) */
355#define ISACX_RSTAD_TA 0x01
356#define ISACX_RSTAD_CR 0x02
357#define ISACX_RSTAD_SA0 0x04
358#define ISACX_RSTAD_SA1 0x08
359#define ISACX_RSTAD_RAB 0x10
360#define ISACX_RSTAD_CRC 0x20
361#define ISACX_RSTAD_RDO 0x40
362#define ISACX_RSTAD_VFR 0x80
363
364/* ISACX/IPACX _CIR0 (R) */
365#define ISACX_CIR0_BAS 0x01
366#define ISACX_CIR0_SG 0x08
367#define ISACX_CIR0_CIC1 0x08
368#define ISACX_CIR0_CIC0 0x08
369
370/* B-channel registers */
371#define IPACX_OFF_ICA 0x70
372#define IPACX_OFF_ICB 0x80
373
374/* ICA: IPACX_OFF_ICA + Reg ICB: IPACX_OFF_ICB + Reg */
375
376#define IPACX_ISTAB 0x00 /* RD */
377#define IPACX_MASKB 0x00 /* WR */
378#define IPACX_STARB 0x01 /* RD */
379#define IPACX_CMDRB 0x01 /* WR */
380#define IPACX_MODEB 0x02 /* R/W */
381#define IPACX_EXMB 0x03 /* R/W */
382#define IPACX_RAH1 0x05 /* WR */
383#define IPACX_RAH2 0x06 /* WR */
384#define IPACX_RBCLB 0x06 /* RD */
385#define IPACX_RBCHB 0x07 /* RD */
386#define IPACX_RAL1 0x07 /* WR */
387#define IPACX_RAL2 0x08 /* WR */
388#define IPACX_RSTAB 0x08 /* RD */
389#define IPACX_TMB 0x09 /* R/W */
390#define IPACX_RFIFOB 0x0A /* RD */
391#define IPACX_XFIFOB 0x0A /* WR */
392
393/* IPACX_ISTAB / IPACX_MASKB bits */
394#define IPACX_B_XDU 0x04
395#define IPACX_B_XPR 0x10
396#define IPACX_B_RFO 0x20
397#define IPACX_B_RPF 0x40
398#define IPACX_B_RME 0x80
399
400#define IPACX_B_ON 0x0B
401
402extern int mISDNisac_init(struct isac_hw *, void *);
403extern irqreturn_t mISDNisac_irq(struct isac_hw *, u8);
404extern u32 mISDNipac_init(struct ipac_hw *, void *);
405extern irqreturn_t mISDNipac_irq(struct ipac_hw *, int);
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
49static int inf_cnt;
50static u32 debug;
51static u32 irqloops = 4;
52
53enum 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
72enum addr_mode {
73 AM_NONE = 0,
74 AM_IO,
75 AM_MEMIO,
76 AM_IND_IO,
77};
78
79struct 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
90struct _ioaddr {
91 enum addr_mode mode;
92 union {
93 void __iomem *p;
94 struct _ioport io;
95 } a;
96};
97
98struct _iohandle {
99 enum addr_mode mode;
100 resource_size_t size;
101 resource_size_t start;
102 void __iomem *p;
103};
104
105struct 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
126static 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};
159MODULE_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
244static LIST_HEAD(Cards);
245static DEFINE_RWLOCK(card_lock); /* protect Cards */
246
247static 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
255static int
256set_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
271MODULE_AUTHOR("Karsten Keil");
272MODULE_LICENSE("GPL v2");
273MODULE_VERSION(INFINEON_REV);
274module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
275MODULE_PARM_DESC(debug, "infineon debug mask");
276module_param(irqloops, uint, S_IRUGO | S_IWUSR);
277MODULE_PARM_DESC(irqloops, "infineon maximal irqloops (default 4)");
278
279/* Interface functions */
280
281IOFUNC_IO(ISAC, inf_hw, isac.a.io)
282IOFUNC_IO(IPAC, inf_hw, hscx.a.io)
283IOFUNC_IND(ISAC, inf_hw, isac.a.io)
284IOFUNC_IND(IPAC, inf_hw, hscx.a.io)
285IOFUNC_MEMIO(ISAC, inf_hw, u32, isac.a.p)
286IOFUNC_MEMIO(IPAC, inf_hw, u32, hscx.a.p)
287
288static irqreturn_t
289diva_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
306static irqreturn_t
307diva20x_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
325static irqreturn_t
326tiger_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
343static irqreturn_t
344elsa_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
361static irqreturn_t
362niccy_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
380static irqreturn_t
381gazel_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
392static irqreturn_t
393ipac_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
410static void
411enable_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
454static void
455disable_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
494static void
495ipac_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
505static void
506reset_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
597static int
598inf_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
615static int __devinit
616init_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
653static void
654release_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
674static int __devinit
675setup_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
873static void
874release_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
908static int __devinit
909setup_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);
951error:
952 card->ipac.release(&card->ipac);
953error_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
961static 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
1072static const struct inf_cinfo * __devinit
1073get_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
1085static int __devinit
1086inf_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
1143static void __devexit
1144inf_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
1154static 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
1161static int __init
1162infineon_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
1171static void __exit
1172infineon_cleanup(void)
1173{
1174 pci_unregister_driver(&infineon_driver);
1175}
1176
1177module_init(infineon_init);
1178module_exit(infineon_cleanup);
diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c
new file mode 100644
index 000000000000..613ba0435372
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/mISDNipac.c
@@ -0,0 +1,1655 @@
1/*
2 * isac.c ISAC specific routines
3 *
4 * Author Karsten Keil <keil@isdn4linux.de>
5 *
6 * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 */
22
23#include <linux/module.h>
24#include <linux/mISDNhw.h>
25#include "ipac.h"
26
27
28#define DBUSY_TIMER_VALUE 80
29#define ARCOFI_USE 1
30
31#define ISAC_REV "2.0"
32
33MODULE_AUTHOR("Karsten Keil");
34MODULE_VERSION(ISAC_REV);
35MODULE_LICENSE("GPL v2");
36
37#define ReadISAC(is, o) (is->read_reg(is->dch.hw, o + is->off))
38#define WriteISAC(is, o, v) (is->write_reg(is->dch.hw, o + is->off, v))
39#define ReadHSCX(h, o) (h->ip->read_reg(h->ip->hw, h->off + o))
40#define WriteHSCX(h, o, v) (h->ip->write_reg(h->ip->hw, h->off + o, v))
41#define ReadIPAC(ip, o) (ip->read_reg(ip->hw, o))
42#define WriteIPAC(ip, o, v) (ip->write_reg(ip->hw, o, v))
43
44static inline void
45ph_command(struct isac_hw *isac, u8 command)
46{
47 pr_debug("%s: ph_command %x\n", isac->name, command);
48 if (isac->type & IPAC_TYPE_ISACX)
49 WriteISAC(isac, ISACX_CIX0, (command << 4) | 0xE);
50 else
51 WriteISAC(isac, ISAC_CIX0, (command << 2) | 3);
52}
53
54static void
55isac_ph_state_change(struct isac_hw *isac)
56{
57 switch (isac->state) {
58 case (ISAC_IND_RS):
59 case (ISAC_IND_EI):
60 ph_command(isac, ISAC_CMD_DUI);
61 }
62 schedule_event(&isac->dch, FLG_PHCHANGE);
63}
64
65static void
66isac_ph_state_bh(struct dchannel *dch)
67{
68 struct isac_hw *isac = container_of(dch, struct isac_hw, dch);
69
70 switch (isac->state) {
71 case ISAC_IND_RS:
72 case ISAC_IND_EI:
73 dch->state = 0;
74 l1_event(dch->l1, HW_RESET_IND);
75 break;
76 case ISAC_IND_DID:
77 dch->state = 3;
78 l1_event(dch->l1, HW_DEACT_CNF);
79 break;
80 case ISAC_IND_DR:
81 dch->state = 3;
82 l1_event(dch->l1, HW_DEACT_IND);
83 break;
84 case ISAC_IND_PU:
85 dch->state = 4;
86 l1_event(dch->l1, HW_POWERUP_IND);
87 break;
88 case ISAC_IND_RSY:
89 if (dch->state <= 5) {
90 dch->state = 5;
91 l1_event(dch->l1, ANYSIGNAL);
92 } else {
93 dch->state = 8;
94 l1_event(dch->l1, LOSTFRAMING);
95 }
96 break;
97 case ISAC_IND_ARD:
98 dch->state = 6;
99 l1_event(dch->l1, INFO2);
100 break;
101 case ISAC_IND_AI8:
102 dch->state = 7;
103 l1_event(dch->l1, INFO4_P8);
104 break;
105 case ISAC_IND_AI10:
106 dch->state = 7;
107 l1_event(dch->l1, INFO4_P10);
108 break;
109 }
110 pr_debug("%s: TE newstate %x\n", isac->name, dch->state);
111}
112
113void
114isac_empty_fifo(struct isac_hw *isac, int count)
115{
116 u8 *ptr;
117
118 pr_debug("%s: %s %d\n", isac->name, __func__, count);
119
120 if (!isac->dch.rx_skb) {
121 isac->dch.rx_skb = mI_alloc_skb(isac->dch.maxlen, GFP_ATOMIC);
122 if (!isac->dch.rx_skb) {
123 pr_info("%s: D receive out of memory\n", isac->name);
124 WriteISAC(isac, ISAC_CMDR, 0x80);
125 return;
126 }
127 }
128 if ((isac->dch.rx_skb->len + count) >= isac->dch.maxlen) {
129 pr_debug("%s: %s overrun %d\n", isac->name, __func__,
130 isac->dch.rx_skb->len + count);
131 WriteISAC(isac, ISAC_CMDR, 0x80);
132 return;
133 }
134 ptr = skb_put(isac->dch.rx_skb, count);
135 isac->read_fifo(isac->dch.hw, isac->off, ptr, count);
136 WriteISAC(isac, ISAC_CMDR, 0x80);
137 if (isac->dch.debug & DEBUG_HW_DFIFO) {
138 char pfx[MISDN_MAX_IDLEN + 16];
139
140 snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-recv %s %d ",
141 isac->name, count);
142 print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count);
143 }
144}
145
146static void
147isac_fill_fifo(struct isac_hw *isac)
148{
149 int count, more;
150 u8 *ptr;
151
152 if (!isac->dch.tx_skb)
153 return;
154 count = isac->dch.tx_skb->len - isac->dch.tx_idx;
155 if (count <= 0)
156 return;
157
158 more = 0;
159 if (count > 32) {
160 more = !0;
161 count = 32;
162 }
163 pr_debug("%s: %s %d\n", isac->name, __func__, count);
164 ptr = isac->dch.tx_skb->data + isac->dch.tx_idx;
165 isac->dch.tx_idx += count;
166 isac->write_fifo(isac->dch.hw, isac->off, ptr, count);
167 WriteISAC(isac, ISAC_CMDR, more ? 0x8 : 0xa);
168 if (test_and_set_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) {
169 pr_debug("%s: %s dbusytimer running\n", isac->name, __func__);
170 del_timer(&isac->dch.timer);
171 }
172 init_timer(&isac->dch.timer);
173 isac->dch.timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
174 add_timer(&isac->dch.timer);
175 if (isac->dch.debug & DEBUG_HW_DFIFO) {
176 char pfx[MISDN_MAX_IDLEN + 16];
177
178 snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-send %s %d ",
179 isac->name, count);
180 print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count);
181 }
182}
183
184static void
185isac_rme_irq(struct isac_hw *isac)
186{
187 u8 val, count;
188
189 val = ReadISAC(isac, ISAC_RSTA);
190 if ((val & 0x70) != 0x20) {
191 if (val & 0x40) {
192 pr_debug("%s: ISAC RDO\n", isac->name);
193#ifdef ERROR_STATISTIC
194 isac->dch.err_rx++;
195#endif
196 }
197 if (!(val & 0x20)) {
198 pr_debug("%s: ISAC CRC error\n", isac->name);
199#ifdef ERROR_STATISTIC
200 isac->dch.err_crc++;
201#endif
202 }
203 WriteISAC(isac, ISAC_CMDR, 0x80);
204 if (isac->dch.rx_skb)
205 dev_kfree_skb(isac->dch.rx_skb);
206 isac->dch.rx_skb = NULL;
207 } else {
208 count = ReadISAC(isac, ISAC_RBCL) & 0x1f;
209 if (count == 0)
210 count = 32;
211 isac_empty_fifo(isac, count);
212 recv_Dchannel(&isac->dch);
213 }
214}
215
216static void
217isac_xpr_irq(struct isac_hw *isac)
218{
219 if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags))
220 del_timer(&isac->dch.timer);
221 if (isac->dch.tx_skb && isac->dch.tx_idx < isac->dch.tx_skb->len) {
222 isac_fill_fifo(isac);
223 } else {
224 if (isac->dch.tx_skb)
225 dev_kfree_skb(isac->dch.tx_skb);
226 if (get_next_dframe(&isac->dch))
227 isac_fill_fifo(isac);
228 }
229}
230
231static void
232isac_retransmit(struct isac_hw *isac)
233{
234 if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags))
235 del_timer(&isac->dch.timer);
236 if (test_bit(FLG_TX_BUSY, &isac->dch.Flags)) {
237 /* Restart frame */
238 isac->dch.tx_idx = 0;
239 isac_fill_fifo(isac);
240 } else if (isac->dch.tx_skb) { /* should not happen */
241 pr_info("%s: tx_skb exist but not busy\n", isac->name);
242 test_and_set_bit(FLG_TX_BUSY, &isac->dch.Flags);
243 isac->dch.tx_idx = 0;
244 isac_fill_fifo(isac);
245 } else {
246 pr_info("%s: ISAC XDU no TX_BUSY\n", isac->name);
247 if (get_next_dframe(&isac->dch))
248 isac_fill_fifo(isac);
249 }
250}
251
252static void
253isac_mos_irq(struct isac_hw *isac)
254{
255 u8 val;
256 int ret;
257
258 val = ReadISAC(isac, ISAC_MOSR);
259 pr_debug("%s: ISAC MOSR %02x\n", isac->name, val);
260#if ARCOFI_USE
261 if (val & 0x08) {
262 if (!isac->mon_rx) {
263 isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC);
264 if (!isac->mon_rx) {
265 pr_info("%s: ISAC MON RX out of memory!\n",
266 isac->name);
267 isac->mocr &= 0xf0;
268 isac->mocr |= 0x0a;
269 WriteISAC(isac, ISAC_MOCR, isac->mocr);
270 goto afterMONR0;
271 } else
272 isac->mon_rxp = 0;
273 }
274 if (isac->mon_rxp >= MAX_MON_FRAME) {
275 isac->mocr &= 0xf0;
276 isac->mocr |= 0x0a;
277 WriteISAC(isac, ISAC_MOCR, isac->mocr);
278 isac->mon_rxp = 0;
279 pr_debug("%s: ISAC MON RX overflow!\n", isac->name);
280 goto afterMONR0;
281 }
282 isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR0);
283 pr_debug("%s: ISAC MOR0 %02x\n", isac->name,
284 isac->mon_rx[isac->mon_rxp - 1]);
285 if (isac->mon_rxp == 1) {
286 isac->mocr |= 0x04;
287 WriteISAC(isac, ISAC_MOCR, isac->mocr);
288 }
289 }
290afterMONR0:
291 if (val & 0x80) {
292 if (!isac->mon_rx) {
293 isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC);
294 if (!isac->mon_rx) {
295 pr_info("%s: ISAC MON RX out of memory!\n",
296 isac->name);
297 isac->mocr &= 0x0f;
298 isac->mocr |= 0xa0;
299 WriteISAC(isac, ISAC_MOCR, isac->mocr);
300 goto afterMONR1;
301 } else
302 isac->mon_rxp = 0;
303 }
304 if (isac->mon_rxp >= MAX_MON_FRAME) {
305 isac->mocr &= 0x0f;
306 isac->mocr |= 0xa0;
307 WriteISAC(isac, ISAC_MOCR, isac->mocr);
308 isac->mon_rxp = 0;
309 pr_debug("%s: ISAC MON RX overflow!\n", isac->name);
310 goto afterMONR1;
311 }
312 isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR1);
313 pr_debug("%s: ISAC MOR1 %02x\n", isac->name,
314 isac->mon_rx[isac->mon_rxp - 1]);
315 isac->mocr |= 0x40;
316 WriteISAC(isac, ISAC_MOCR, isac->mocr);
317 }
318afterMONR1:
319 if (val & 0x04) {
320 isac->mocr &= 0xf0;
321 WriteISAC(isac, ISAC_MOCR, isac->mocr);
322 isac->mocr |= 0x0a;
323 WriteISAC(isac, ISAC_MOCR, isac->mocr);
324 if (isac->monitor) {
325 ret = isac->monitor(isac->dch.hw, MONITOR_RX_0,
326 isac->mon_rx, isac->mon_rxp);
327 if (ret)
328 kfree(isac->mon_rx);
329 } else {
330 pr_info("%s: MONITOR 0 received %d but no user\n",
331 isac->name, isac->mon_rxp);
332 kfree(isac->mon_rx);
333 }
334 isac->mon_rx = NULL;
335 isac->mon_rxp = 0;
336 }
337 if (val & 0x40) {
338 isac->mocr &= 0x0f;
339 WriteISAC(isac, ISAC_MOCR, isac->mocr);
340 isac->mocr |= 0xa0;
341 WriteISAC(isac, ISAC_MOCR, isac->mocr);
342 if (isac->monitor) {
343 ret = isac->monitor(isac->dch.hw, MONITOR_RX_1,
344 isac->mon_rx, isac->mon_rxp);
345 if (ret)
346 kfree(isac->mon_rx);
347 } else {
348 pr_info("%s: MONITOR 1 received %d but no user\n",
349 isac->name, isac->mon_rxp);
350 kfree(isac->mon_rx);
351 }
352 isac->mon_rx = NULL;
353 isac->mon_rxp = 0;
354 }
355 if (val & 0x02) {
356 if ((!isac->mon_tx) || (isac->mon_txc &&
357 (isac->mon_txp >= isac->mon_txc) && !(val & 0x08))) {
358 isac->mocr &= 0xf0;
359 WriteISAC(isac, ISAC_MOCR, isac->mocr);
360 isac->mocr |= 0x0a;
361 WriteISAC(isac, ISAC_MOCR, isac->mocr);
362 if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
363 if (isac->monitor)
364 ret = isac->monitor(isac->dch.hw,
365 MONITOR_TX_0, NULL, 0);
366 }
367 kfree(isac->mon_tx);
368 isac->mon_tx = NULL;
369 isac->mon_txc = 0;
370 isac->mon_txp = 0;
371 goto AfterMOX0;
372 }
373 if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
374 if (isac->monitor)
375 ret = isac->monitor(isac->dch.hw,
376 MONITOR_TX_0, NULL, 0);
377 kfree(isac->mon_tx);
378 isac->mon_tx = NULL;
379 isac->mon_txc = 0;
380 isac->mon_txp = 0;
381 goto AfterMOX0;
382 }
383 WriteISAC(isac, ISAC_MOX0, isac->mon_tx[isac->mon_txp++]);
384 pr_debug("%s: ISAC %02x -> MOX0\n", isac->name,
385 isac->mon_tx[isac->mon_txp - 1]);
386 }
387AfterMOX0:
388 if (val & 0x20) {
389 if ((!isac->mon_tx) || (isac->mon_txc &&
390 (isac->mon_txp >= isac->mon_txc) && !(val & 0x80))) {
391 isac->mocr &= 0x0f;
392 WriteISAC(isac, ISAC_MOCR, isac->mocr);
393 isac->mocr |= 0xa0;
394 WriteISAC(isac, ISAC_MOCR, isac->mocr);
395 if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
396 if (isac->monitor)
397 ret = isac->monitor(isac->dch.hw,
398 MONITOR_TX_1, NULL, 0);
399 }
400 kfree(isac->mon_tx);
401 isac->mon_tx = NULL;
402 isac->mon_txc = 0;
403 isac->mon_txp = 0;
404 goto AfterMOX1;
405 }
406 if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
407 if (isac->monitor)
408 ret = isac->monitor(isac->dch.hw,
409 MONITOR_TX_1, NULL, 0);
410 kfree(isac->mon_tx);
411 isac->mon_tx = NULL;
412 isac->mon_txc = 0;
413 isac->mon_txp = 0;
414 goto AfterMOX1;
415 }
416 WriteISAC(isac, ISAC_MOX1, isac->mon_tx[isac->mon_txp++]);
417 pr_debug("%s: ISAC %02x -> MOX1\n", isac->name,
418 isac->mon_tx[isac->mon_txp - 1]);
419 }
420AfterMOX1:
421 val = 0; /* dummy to avoid warning */
422#endif
423}
424
425static void
426isac_cisq_irq(struct isac_hw *isac) {
427 u8 val;
428
429 val = ReadISAC(isac, ISAC_CIR0);
430 pr_debug("%s: ISAC CIR0 %02X\n", isac->name, val);
431 if (val & 2) {
432 pr_debug("%s: ph_state change %x->%x\n", isac->name,
433 isac->state, (val >> 2) & 0xf);
434 isac->state = (val >> 2) & 0xf;
435 isac_ph_state_change(isac);
436 }
437 if (val & 1) {
438 val = ReadISAC(isac, ISAC_CIR1);
439 pr_debug("%s: ISAC CIR1 %02X\n", isac->name, val);
440 }
441}
442
443static void
444isacsx_cic_irq(struct isac_hw *isac)
445{
446 u8 val;
447
448 val = ReadISAC(isac, ISACX_CIR0);
449 pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val);
450 if (val & ISACX_CIR0_CIC0) {
451 pr_debug("%s: ph_state change %x->%x\n", isac->name,
452 isac->state, val >> 4);
453 isac->state = val >> 4;
454 isac_ph_state_change(isac);
455 }
456}
457
458static void
459isacsx_rme_irq(struct isac_hw *isac)
460{
461 int count;
462 u8 val;
463
464 val = ReadISAC(isac, ISACX_RSTAD);
465 if ((val & (ISACX_RSTAD_VFR |
466 ISACX_RSTAD_RDO |
467 ISACX_RSTAD_CRC |
468 ISACX_RSTAD_RAB))
469 != (ISACX_RSTAD_VFR | ISACX_RSTAD_CRC)) {
470 pr_debug("%s: RSTAD %#x, dropped\n", isac->name, val);
471#ifdef ERROR_STATISTIC
472 if (val & ISACX_RSTAD_CRC)
473 isac->dch.err_rx++;
474 else
475 isac->dch.err_crc++;
476#endif
477 WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC);
478 if (isac->dch.rx_skb)
479 dev_kfree_skb(isac->dch.rx_skb);
480 isac->dch.rx_skb = NULL;
481 } else {
482 count = ReadISAC(isac, ISACX_RBCLD) & 0x1f;
483 if (count == 0)
484 count = 32;
485 isac_empty_fifo(isac, count);
486 if (isac->dch.rx_skb) {
487 skb_trim(isac->dch.rx_skb, isac->dch.rx_skb->len - 1);
488 pr_debug("%s: dchannel received %d\n", isac->name,
489 isac->dch.rx_skb->len);
490 recv_Dchannel(&isac->dch);
491 }
492 }
493}
494
495irqreturn_t
496mISDNisac_irq(struct isac_hw *isac, u8 val)
497{
498 if (unlikely(!val))
499 return IRQ_NONE;
500 pr_debug("%s: ISAC interrupt %02x\n", isac->name, val);
501 if (isac->type & IPAC_TYPE_ISACX) {
502 if (val & ISACX__CIC)
503 isacsx_cic_irq(isac);
504 if (val & ISACX__ICD) {
505 val = ReadISAC(isac, ISACX_ISTAD);
506 pr_debug("%s: ISTAD %02x\n", isac->name, val);
507 if (val & ISACX_D_XDU) {
508 pr_debug("%s: ISAC XDU\n", isac->name);
509#ifdef ERROR_STATISTIC
510 isac->dch.err_tx++;
511#endif
512 isac_retransmit(isac);
513 }
514 if (val & ISACX_D_XMR) {
515 pr_debug("%s: ISAC XMR\n", isac->name);
516#ifdef ERROR_STATISTIC
517 isac->dch.err_tx++;
518#endif
519 isac_retransmit(isac);
520 }
521 if (val & ISACX_D_XPR)
522 isac_xpr_irq(isac);
523 if (val & ISACX_D_RFO) {
524 pr_debug("%s: ISAC RFO\n", isac->name);
525 WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC);
526 }
527 if (val & ISACX_D_RME)
528 isacsx_rme_irq(isac);
529 if (val & ISACX_D_RPF)
530 isac_empty_fifo(isac, 0x20);
531 }
532 } else {
533 if (val & 0x80) /* RME */
534 isac_rme_irq(isac);
535 if (val & 0x40) /* RPF */
536 isac_empty_fifo(isac, 32);
537 if (val & 0x10) /* XPR */
538 isac_xpr_irq(isac);
539 if (val & 0x04) /* CISQ */
540 isac_cisq_irq(isac);
541 if (val & 0x20) /* RSC - never */
542 pr_debug("%s: ISAC RSC interrupt\n", isac->name);
543 if (val & 0x02) /* SIN - never */
544 pr_debug("%s: ISAC SIN interrupt\n", isac->name);
545 if (val & 0x01) { /* EXI */
546 val = ReadISAC(isac, ISAC_EXIR);
547 pr_debug("%s: ISAC EXIR %02x\n", isac->name, val);
548 if (val & 0x80) /* XMR */
549 pr_debug("%s: ISAC XMR\n", isac->name);
550 if (val & 0x40) { /* XDU */
551 pr_debug("%s: ISAC XDU\n", isac->name);
552#ifdef ERROR_STATISTIC
553 isac->dch.err_tx++;
554#endif
555 isac_retransmit(isac);
556 }
557 if (val & 0x04) /* MOS */
558 isac_mos_irq(isac);
559 }
560 }
561 return IRQ_HANDLED;
562}
563EXPORT_SYMBOL(mISDNisac_irq);
564
565static int
566isac_l1hw(struct mISDNchannel *ch, struct sk_buff *skb)
567{
568 struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
569 struct dchannel *dch = container_of(dev, struct dchannel, dev);
570 struct isac_hw *isac = container_of(dch, struct isac_hw, dch);
571 int ret = -EINVAL;
572 struct mISDNhead *hh = mISDN_HEAD_P(skb);
573 u32 id;
574 u_long flags;
575
576 switch (hh->prim) {
577 case PH_DATA_REQ:
578 spin_lock_irqsave(isac->hwlock, flags);
579 ret = dchannel_senddata(dch, skb);
580 if (ret > 0) { /* direct TX */
581 id = hh->id; /* skb can be freed */
582 isac_fill_fifo(isac);
583 ret = 0;
584 spin_unlock_irqrestore(isac->hwlock, flags);
585 queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
586 } else
587 spin_unlock_irqrestore(isac->hwlock, flags);
588 return ret;
589 case PH_ACTIVATE_REQ:
590 ret = l1_event(dch->l1, hh->prim);
591 break;
592 case PH_DEACTIVATE_REQ:
593 test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
594 ret = l1_event(dch->l1, hh->prim);
595 break;
596 }
597
598 if (!ret)
599 dev_kfree_skb(skb);
600 return ret;
601}
602
603static int
604isac_ctrl(struct isac_hw *isac, u32 cmd, u_long para)
605{
606 u8 tl = 0;
607 u_long flags;
608
609 switch (cmd) {
610 case HW_TESTLOOP:
611 spin_lock_irqsave(isac->hwlock, flags);
612 if (!(isac->type & IPAC_TYPE_ISACX)) {
613 /* TODO: implement for IPAC_TYPE_ISACX */
614 if (para & 1) /* B1 */
615 tl |= 0x0c;
616 else if (para & 2) /* B2 */
617 tl |= 0x3;
618 /* we only support IOM2 mode */
619 WriteISAC(isac, ISAC_SPCR, tl);
620 if (tl)
621 WriteISAC(isac, ISAC_ADF1, 0x8);
622 else
623 WriteISAC(isac, ISAC_ADF1, 0x0);
624 }
625 spin_unlock_irqrestore(isac->hwlock, flags);
626 break;
627 default:
628 pr_debug("%s: %s unknown command %x %lx\n", isac->name,
629 __func__, cmd, para);
630 return -1;
631 }
632 return 0;
633}
634
635static int
636isac_l1cmd(struct dchannel *dch, u32 cmd)
637{
638 struct isac_hw *isac = container_of(dch, struct isac_hw, dch);
639 u_long flags;
640
641 pr_debug("%s: cmd(%x) state(%02x)\n", isac->name, cmd, isac->state);
642 switch (cmd) {
643 case INFO3_P8:
644 spin_lock_irqsave(isac->hwlock, flags);
645 ph_command(isac, ISAC_CMD_AR8);
646 spin_unlock_irqrestore(isac->hwlock, flags);
647 break;
648 case INFO3_P10:
649 spin_lock_irqsave(isac->hwlock, flags);
650 ph_command(isac, ISAC_CMD_AR10);
651 spin_unlock_irqrestore(isac->hwlock, flags);
652 break;
653 case HW_RESET_REQ:
654 spin_lock_irqsave(isac->hwlock, flags);
655 if ((isac->state == ISAC_IND_EI) ||
656 (isac->state == ISAC_IND_DR) ||
657 (isac->state == ISAC_IND_RS))
658 ph_command(isac, ISAC_CMD_TIM);
659 else
660 ph_command(isac, ISAC_CMD_RS);
661 spin_unlock_irqrestore(isac->hwlock, flags);
662 break;
663 case HW_DEACT_REQ:
664 skb_queue_purge(&dch->squeue);
665 if (dch->tx_skb) {
666 dev_kfree_skb(dch->tx_skb);
667 dch->tx_skb = NULL;
668 }
669 dch->tx_idx = 0;
670 if (dch->rx_skb) {
671 dev_kfree_skb(dch->rx_skb);
672 dch->rx_skb = NULL;
673 }
674 test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
675 if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
676 del_timer(&dch->timer);
677 break;
678 case HW_POWERUP_REQ:
679 spin_lock_irqsave(isac->hwlock, flags);
680 ph_command(isac, ISAC_CMD_TIM);
681 spin_unlock_irqrestore(isac->hwlock, flags);
682 break;
683 case PH_ACTIVATE_IND:
684 test_and_set_bit(FLG_ACTIVE, &dch->Flags);
685 _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
686 GFP_ATOMIC);
687 break;
688 case PH_DEACTIVATE_IND:
689 test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
690 _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
691 GFP_ATOMIC);
692 break;
693 default:
694 pr_debug("%s: %s unknown command %x\n", isac->name,
695 __func__, cmd);
696 return -1;
697 }
698 return 0;
699}
700
701static void
702isac_release(struct isac_hw *isac)
703{
704 if (isac->type & IPAC_TYPE_ISACX)
705 WriteISAC(isac, ISACX_MASK, 0xff);
706 else
707 WriteISAC(isac, ISAC_MASK, 0xff);
708 if (isac->dch.timer.function != NULL) {
709 del_timer(&isac->dch.timer);
710 isac->dch.timer.function = NULL;
711 }
712 kfree(isac->mon_rx);
713 isac->mon_rx = NULL;
714 kfree(isac->mon_tx);
715 isac->mon_tx = NULL;
716 if (isac->dch.l1)
717 l1_event(isac->dch.l1, CLOSE_CHANNEL);
718 mISDN_freedchannel(&isac->dch);
719}
720
721static void
722dbusy_timer_handler(struct isac_hw *isac)
723{
724 int rbch, star;
725 u_long flags;
726
727 if (test_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) {
728 spin_lock_irqsave(isac->hwlock, flags);
729 rbch = ReadISAC(isac, ISAC_RBCH);
730 star = ReadISAC(isac, ISAC_STAR);
731 pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n",
732 isac->name, rbch, star);
733 if (rbch & ISAC_RBCH_XAC) /* D-Channel Busy */
734 test_and_set_bit(FLG_L1_BUSY, &isac->dch.Flags);
735 else {
736 /* discard frame; reset transceiver */
737 test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags);
738 if (isac->dch.tx_idx)
739 isac->dch.tx_idx = 0;
740 else
741 pr_info("%s: ISAC D-Channel Busy no tx_idx\n",
742 isac->name);
743 /* Transmitter reset */
744 WriteISAC(isac, ISAC_CMDR, 0x01);
745 }
746 spin_unlock_irqrestore(isac->hwlock, flags);
747 }
748}
749
750static int
751open_dchannel(struct isac_hw *isac, struct channel_req *rq)
752{
753 pr_debug("%s: %s dev(%d) open from %p\n", isac->name, __func__,
754 isac->dch.dev.id, __builtin_return_address(1));
755 if (rq->protocol != ISDN_P_TE_S0)
756 return -EINVAL;
757 if (rq->adr.channel == 1)
758 /* E-Channel not supported */
759 return -EINVAL;
760 rq->ch = &isac->dch.dev.D;
761 rq->ch->protocol = rq->protocol;
762 if (isac->dch.state == 7)
763 _queue_data(rq->ch, PH_ACTIVATE_IND, MISDN_ID_ANY,
764 0, NULL, GFP_KERNEL);
765 return 0;
766}
767
768static const char *ISACVer[] =
769{"2086/2186 V1.1", "2085 B1", "2085 B2",
770 "2085 V2.3"};
771
772static int
773isac_init(struct isac_hw *isac)
774{
775 u8 val;
776 int err = 0;
777
778 if (!isac->dch.l1) {
779 err = create_l1(&isac->dch, isac_l1cmd);
780 if (err)
781 return err;
782 }
783 isac->mon_tx = NULL;
784 isac->mon_rx = NULL;
785 isac->dch.timer.function = (void *) dbusy_timer_handler;
786 isac->dch.timer.data = (long)isac;
787 init_timer(&isac->dch.timer);
788 isac->mocr = 0xaa;
789 if (isac->type & IPAC_TYPE_ISACX) {
790 /* Disable all IRQ */
791 WriteISAC(isac, ISACX_MASK, 0xff);
792 val = ReadISAC(isac, ISACX_STARD);
793 pr_debug("%s: ISACX STARD %x\n", isac->name, val);
794 val = ReadISAC(isac, ISACX_ISTAD);
795 pr_debug("%s: ISACX ISTAD %x\n", isac->name, val);
796 val = ReadISAC(isac, ISACX_ISTA);
797 pr_debug("%s: ISACX ISTA %x\n", isac->name, val);
798 /* clear LDD */
799 WriteISAC(isac, ISACX_TR_CONF0, 0x00);
800 /* enable transmitter */
801 WriteISAC(isac, ISACX_TR_CONF2, 0x00);
802 /* transparent mode 0, RAC, stop/go */
803 WriteISAC(isac, ISACX_MODED, 0xc9);
804 /* all HDLC IRQ unmasked */
805 val = ReadISAC(isac, ISACX_ID);
806 if (isac->dch.debug & DEBUG_HW)
807 pr_notice("%s: ISACX Design ID %x\n",
808 isac->name, val & 0x3f);
809 val = ReadISAC(isac, ISACX_CIR0);
810 pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val);
811 isac->state = val >> 4;
812 isac_ph_state_change(isac);
813 ph_command(isac, ISAC_CMD_RS);
814 WriteISAC(isac, ISACX_MASK, IPACX__ON);
815 WriteISAC(isac, ISACX_MASKD, 0x00);
816 } else { /* old isac */
817 WriteISAC(isac, ISAC_MASK, 0xff);
818 val = ReadISAC(isac, ISAC_STAR);
819 pr_debug("%s: ISAC STAR %x\n", isac->name, val);
820 val = ReadISAC(isac, ISAC_MODE);
821 pr_debug("%s: ISAC MODE %x\n", isac->name, val);
822 val = ReadISAC(isac, ISAC_ADF2);
823 pr_debug("%s: ISAC ADF2 %x\n", isac->name, val);
824 val = ReadISAC(isac, ISAC_ISTA);
825 pr_debug("%s: ISAC ISTA %x\n", isac->name, val);
826 if (val & 0x01) {
827 val = ReadISAC(isac, ISAC_EXIR);
828 pr_debug("%s: ISAC EXIR %x\n", isac->name, val);
829 }
830 val = ReadISAC(isac, ISAC_RBCH);
831 if (isac->dch.debug & DEBUG_HW)
832 pr_notice("%s: ISAC version (%x): %s\n", isac->name,
833 val, ISACVer[(val >> 5) & 3]);
834 isac->type |= ((val >> 5) & 3);
835 if (!isac->adf2)
836 isac->adf2 = 0x80;
837 if (!(isac->adf2 & 0x80)) { /* only IOM 2 Mode */
838 pr_info("%s: only support IOM2 mode but adf2=%02x\n",
839 isac->name, isac->adf2);
840 isac_release(isac);
841 return -EINVAL;
842 }
843 WriteISAC(isac, ISAC_ADF2, isac->adf2);
844 WriteISAC(isac, ISAC_SQXR, 0x2f);
845 WriteISAC(isac, ISAC_SPCR, 0x00);
846 WriteISAC(isac, ISAC_STCR, 0x70);
847 WriteISAC(isac, ISAC_MODE, 0xc9);
848 WriteISAC(isac, ISAC_TIMR, 0x00);
849 WriteISAC(isac, ISAC_ADF1, 0x00);
850 val = ReadISAC(isac, ISAC_CIR0);
851 pr_debug("%s: ISAC CIR0 %x\n", isac->name, val);
852 isac->state = (val >> 2) & 0xf;
853 isac_ph_state_change(isac);
854 ph_command(isac, ISAC_CMD_RS);
855 WriteISAC(isac, ISAC_MASK, 0);
856 }
857 return err;
858}
859
860int
861mISDNisac_init(struct isac_hw *isac, void *hw)
862{
863 mISDN_initdchannel(&isac->dch, MAX_DFRAME_LEN_L1, isac_ph_state_bh);
864 isac->dch.hw = hw;
865 isac->dch.dev.D.send = isac_l1hw;
866 isac->init = isac_init;
867 isac->release = isac_release;
868 isac->ctrl = isac_ctrl;
869 isac->open = open_dchannel;
870 isac->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0);
871 isac->dch.dev.nrbchan = 2;
872 return 0;
873}
874EXPORT_SYMBOL(mISDNisac_init);
875
876static void
877waitforCEC(struct hscx_hw *hx)
878{
879 u8 starb, to = 50;
880
881 while (to) {
882 starb = ReadHSCX(hx, IPAC_STARB);
883 if (!(starb & 0x04))
884 break;
885 udelay(1);
886 to--;
887 }
888 if (to < 50)
889 pr_debug("%s: B%1d CEC %d us\n", hx->ip->name, hx->bch.nr,
890 50 - to);
891 if (!to)
892 pr_info("%s: B%1d CEC timeout\n", hx->ip->name, hx->bch.nr);
893}
894
895
896static void
897waitforXFW(struct hscx_hw *hx)
898{
899 u8 starb, to = 50;
900
901 while (to) {
902 starb = ReadHSCX(hx, IPAC_STARB);
903 if ((starb & 0x44) == 0x40)
904 break;
905 udelay(1);
906 to--;
907 }
908 if (to < 50)
909 pr_debug("%s: B%1d XFW %d us\n", hx->ip->name, hx->bch.nr,
910 50 - to);
911 if (!to)
912 pr_info("%s: B%1d XFW timeout\n", hx->ip->name, hx->bch.nr);
913}
914
915static void
916hscx_cmdr(struct hscx_hw *hx, u8 cmd)
917{
918 if (hx->ip->type & IPAC_TYPE_IPACX)
919 WriteHSCX(hx, IPACX_CMDRB, cmd);
920 else {
921 waitforCEC(hx);
922 WriteHSCX(hx, IPAC_CMDRB, cmd);
923 }
924}
925
926static void
927hscx_empty_fifo(struct hscx_hw *hscx, u8 count)
928{
929 u8 *p;
930
931 pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count);
932 if (!hscx->bch.rx_skb) {
933 hscx->bch.rx_skb = mI_alloc_skb(hscx->bch.maxlen, GFP_ATOMIC);
934 if (!hscx->bch.rx_skb) {
935 pr_info("%s: B receive out of memory\n",
936 hscx->ip->name);
937 hscx_cmdr(hscx, 0x80); /* RMC */
938 return;
939 }
940 }
941 if ((hscx->bch.rx_skb->len + count) > hscx->bch.maxlen) {
942 pr_debug("%s: overrun %d\n", hscx->ip->name,
943 hscx->bch.rx_skb->len + count);
944 skb_trim(hscx->bch.rx_skb, 0);
945 hscx_cmdr(hscx, 0x80); /* RMC */
946 return;
947 }
948 p = skb_put(hscx->bch.rx_skb, count);
949
950 if (hscx->ip->type & IPAC_TYPE_IPACX)
951 hscx->ip->read_fifo(hscx->ip->hw,
952 hscx->off + IPACX_RFIFOB, p, count);
953 else
954 hscx->ip->read_fifo(hscx->ip->hw,
955 hscx->off, p, count);
956
957 hscx_cmdr(hscx, 0x80); /* RMC */
958
959 if (hscx->bch.debug & DEBUG_HW_BFIFO) {
960 snprintf(hscx->log, 64, "B%1d-recv %s %d ",
961 hscx->bch.nr, hscx->ip->name, count);
962 print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count);
963 }
964}
965
966static void
967hscx_fill_fifo(struct hscx_hw *hscx)
968{
969 int count, more;
970 u8 *p;
971
972 if (!hscx->bch.tx_skb)
973 return;
974 count = hscx->bch.tx_skb->len - hscx->bch.tx_idx;
975 if (count <= 0)
976 return;
977 p = hscx->bch.tx_skb->data + hscx->bch.tx_idx;
978
979 more = test_bit(FLG_TRANSPARENT, &hscx->bch.Flags) ? 1 : 0;
980 if (count > hscx->fifo_size) {
981 count = hscx->fifo_size;
982 more = 1;
983 }
984 pr_debug("%s: B%1d %d/%d/%d\n", hscx->ip->name, hscx->bch.nr, count,
985 hscx->bch.tx_idx, hscx->bch.tx_skb->len);
986 hscx->bch.tx_idx += count;
987
988 if (hscx->ip->type & IPAC_TYPE_IPACX)
989 hscx->ip->write_fifo(hscx->ip->hw,
990 hscx->off + IPACX_XFIFOB, p, count);
991 else {
992 waitforXFW(hscx);
993 hscx->ip->write_fifo(hscx->ip->hw,
994 hscx->off, p, count);
995 }
996 hscx_cmdr(hscx, more ? 0x08 : 0x0a);
997
998 if (hscx->bch.debug & DEBUG_HW_BFIFO) {
999 snprintf(hscx->log, 64, "B%1d-send %s %d ",
1000 hscx->bch.nr, hscx->ip->name, count);
1001 print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count);
1002 }
1003}
1004
1005static void
1006hscx_xpr(struct hscx_hw *hx)
1007{
1008 if (hx->bch.tx_skb && hx->bch.tx_idx < hx->bch.tx_skb->len)
1009 hscx_fill_fifo(hx);
1010 else {
1011 if (hx->bch.tx_skb) {
1012 /* send confirm, on trans, free on hdlc. */
1013 if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags))
1014 confirm_Bsend(&hx->bch);
1015 dev_kfree_skb(hx->bch.tx_skb);
1016 }
1017 if (get_next_bframe(&hx->bch))
1018 hscx_fill_fifo(hx);
1019 }
1020}
1021
1022static void
1023ipac_rme(struct hscx_hw *hx)
1024{
1025 int count;
1026 u8 rstab;
1027
1028 if (hx->ip->type & IPAC_TYPE_IPACX)
1029 rstab = ReadHSCX(hx, IPACX_RSTAB);
1030 else
1031 rstab = ReadHSCX(hx, IPAC_RSTAB);
1032 pr_debug("%s: B%1d RSTAB %02x\n", hx->ip->name, hx->bch.nr, rstab);
1033 if ((rstab & 0xf0) != 0xa0) {
1034 /* !(VFR && !RDO && CRC && !RAB) */
1035 if (!(rstab & 0x80)) {
1036 if (hx->bch.debug & DEBUG_HW_BCHANNEL)
1037 pr_notice("%s: B%1d invalid frame\n",
1038 hx->ip->name, hx->bch.nr);
1039 }
1040 if (rstab & 0x40) {
1041 if (hx->bch.debug & DEBUG_HW_BCHANNEL)
1042 pr_notice("%s: B%1d RDO proto=%x\n",
1043 hx->ip->name, hx->bch.nr,
1044 hx->bch.state);
1045 }
1046 if (!(rstab & 0x20)) {
1047 if (hx->bch.debug & DEBUG_HW_BCHANNEL)
1048 pr_notice("%s: B%1d CRC error\n",
1049 hx->ip->name, hx->bch.nr);
1050 }
1051 hscx_cmdr(hx, 0x80); /* Do RMC */
1052 return;
1053 }
1054 if (hx->ip->type & IPAC_TYPE_IPACX)
1055 count = ReadHSCX(hx, IPACX_RBCLB);
1056 else
1057 count = ReadHSCX(hx, IPAC_RBCLB);
1058 count &= (hx->fifo_size - 1);
1059 if (count == 0)
1060 count = hx->fifo_size;
1061 hscx_empty_fifo(hx, count);
1062 if (!hx->bch.rx_skb)
1063 return;
1064 if (hx->bch.rx_skb->len < 2) {
1065 pr_debug("%s: B%1d frame to short %d\n",
1066 hx->ip->name, hx->bch.nr, hx->bch.rx_skb->len);
1067 skb_trim(hx->bch.rx_skb, 0);
1068 } else {
1069 skb_trim(hx->bch.rx_skb, hx->bch.rx_skb->len - 1);
1070 recv_Bchannel(&hx->bch, 0);
1071 }
1072}
1073
1074static void
1075ipac_irq(struct hscx_hw *hx, u8 ista)
1076{
1077 u8 istab, m, exirb = 0;
1078
1079 if (hx->ip->type & IPAC_TYPE_IPACX)
1080 istab = ReadHSCX(hx, IPACX_ISTAB);
1081 else if (hx->ip->type & IPAC_TYPE_IPAC) {
1082 istab = ReadHSCX(hx, IPAC_ISTAB);
1083 m = (hx->bch.nr & 1) ? IPAC__EXA : IPAC__EXB;
1084 if (m & ista) {
1085 exirb = ReadHSCX(hx, IPAC_EXIRB);
1086 pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name,
1087 hx->bch.nr, exirb);
1088 }
1089 } else if (hx->bch.nr & 2) { /* HSCX B */
1090 if (ista & (HSCX__EXA | HSCX__ICA))
1091 ipac_irq(&hx->ip->hscx[0], ista);
1092 if (ista & HSCX__EXB) {
1093 exirb = ReadHSCX(hx, IPAC_EXIRB);
1094 pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name,
1095 hx->bch.nr, exirb);
1096 }
1097 istab = ista & 0xF8;
1098 } else { /* HSCX A */
1099 istab = ReadHSCX(hx, IPAC_ISTAB);
1100 if (ista & HSCX__EXA) {
1101 exirb = ReadHSCX(hx, IPAC_EXIRB);
1102 pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name,
1103 hx->bch.nr, exirb);
1104 }
1105 istab = istab & 0xF8;
1106 }
1107 if (exirb & IPAC_B_XDU)
1108 istab |= IPACX_B_XDU;
1109 if (exirb & IPAC_B_RFO)
1110 istab |= IPACX_B_RFO;
1111 pr_debug("%s: B%1d ISTAB %02x\n", hx->ip->name, hx->bch.nr, istab);
1112
1113 if (!test_bit(FLG_ACTIVE, &hx->bch.Flags))
1114 return;
1115
1116 if (istab & IPACX_B_RME)
1117 ipac_rme(hx);
1118
1119 if (istab & IPACX_B_RPF) {
1120 hscx_empty_fifo(hx, hx->fifo_size);
1121 if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) {
1122 /* receive transparent audio data */
1123 if (hx->bch.rx_skb)
1124 recv_Bchannel(&hx->bch, 0);
1125 }
1126 }
1127
1128 if (istab & IPACX_B_RFO) {
1129 pr_debug("%s: B%1d RFO error\n", hx->ip->name, hx->bch.nr);
1130 hscx_cmdr(hx, 0x40); /* RRES */
1131 }
1132
1133 if (istab & IPACX_B_XPR)
1134 hscx_xpr(hx);
1135
1136 if (istab & IPACX_B_XDU) {
1137 if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) {
1138 hscx_fill_fifo(hx);
1139 return;
1140 }
1141 pr_debug("%s: B%1d XDU error at len %d\n", hx->ip->name,
1142 hx->bch.nr, hx->bch.tx_idx);
1143 hx->bch.tx_idx = 0;
1144 hscx_cmdr(hx, 0x01); /* XRES */
1145 }
1146}
1147
1148irqreturn_t
1149mISDNipac_irq(struct ipac_hw *ipac, int maxloop)
1150{
1151 int cnt = maxloop + 1;
1152 u8 ista, istad;
1153 struct isac_hw *isac = &ipac->isac;
1154
1155 if (ipac->type & IPAC_TYPE_IPACX) {
1156 ista = ReadIPAC(ipac, ISACX_ISTA);
1157 while (ista && cnt--) {
1158 pr_debug("%s: ISTA %02x\n", ipac->name, ista);
1159 if (ista & IPACX__ICA)
1160 ipac_irq(&ipac->hscx[0], ista);
1161 if (ista & IPACX__ICB)
1162 ipac_irq(&ipac->hscx[1], ista);
1163 if (ista & (ISACX__ICD | ISACX__CIC))
1164 mISDNisac_irq(&ipac->isac, ista);
1165 ista = ReadIPAC(ipac, ISACX_ISTA);
1166 }
1167 } else if (ipac->type & IPAC_TYPE_IPAC) {
1168 ista = ReadIPAC(ipac, IPAC_ISTA);
1169 while (ista && cnt--) {
1170 pr_debug("%s: ISTA %02x\n", ipac->name, ista);
1171 if (ista & (IPAC__ICD | IPAC__EXD)) {
1172 istad = ReadISAC(isac, ISAC_ISTA);
1173 pr_debug("%s: ISTAD %02x\n", ipac->name, istad);
1174 if (istad & IPAC_D_TIN2)
1175 pr_debug("%s TIN2 irq\n", ipac->name);
1176 if (ista & IPAC__EXD)
1177 istad |= 1; /* ISAC EXI */
1178 mISDNisac_irq(isac, istad);
1179 }
1180 if (ista & (IPAC__ICA | IPAC__EXA))
1181 ipac_irq(&ipac->hscx[0], ista);
1182 if (ista & (IPAC__ICB | IPAC__EXB))
1183 ipac_irq(&ipac->hscx[1], ista);
1184 ista = ReadIPAC(ipac, IPAC_ISTA);
1185 }
1186 } else if (ipac->type & IPAC_TYPE_HSCX) {
1187 while (cnt) {
1188 ista = ReadIPAC(ipac, IPAC_ISTAB + ipac->hscx[1].off);
1189 pr_debug("%s: B2 ISTA %02x\n", ipac->name, ista);
1190 if (ista)
1191 ipac_irq(&ipac->hscx[1], ista);
1192 istad = ReadISAC(isac, ISAC_ISTA);
1193 pr_debug("%s: ISTAD %02x\n", ipac->name, istad);
1194 if (istad)
1195 mISDNisac_irq(isac, istad);
1196 if (0 == (ista | istad))
1197 break;
1198 cnt--;
1199 }
1200 }
1201 if (cnt > maxloop) /* only for ISAC/HSCX without PCI IRQ test */
1202 return IRQ_NONE;
1203 if (cnt < maxloop)
1204 pr_debug("%s: %d irqloops cpu%d\n", ipac->name,
1205 maxloop - cnt, smp_processor_id());
1206 if (maxloop && !cnt)
1207 pr_notice("%s: %d IRQ LOOP cpu%d\n", ipac->name,
1208 maxloop, smp_processor_id());
1209 return IRQ_HANDLED;
1210}
1211EXPORT_SYMBOL(mISDNipac_irq);
1212
1213static int
1214hscx_mode(struct hscx_hw *hscx, u32 bprotocol)
1215{
1216 pr_debug("%s: HSCX %c protocol %x-->%x ch %d\n", hscx->ip->name,
1217 '@' + hscx->bch.nr, hscx->bch.state, bprotocol, hscx->bch.nr);
1218 if (hscx->ip->type & IPAC_TYPE_IPACX) {
1219 if (hscx->bch.nr & 1) { /* B1 and ICA */
1220 WriteIPAC(hscx->ip, ISACX_BCHA_TSDP_BC1, 0x80);
1221 WriteIPAC(hscx->ip, ISACX_BCHA_CR, 0x88);
1222 } else { /* B2 and ICB */
1223 WriteIPAC(hscx->ip, ISACX_BCHB_TSDP_BC1, 0x81);
1224 WriteIPAC(hscx->ip, ISACX_BCHB_CR, 0x88);
1225 }
1226 switch (bprotocol) {
1227 case ISDN_P_NONE: /* init */
1228 WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* rec off */
1229 WriteHSCX(hscx, IPACX_EXMB, 0x30); /* std adj. */
1230 WriteHSCX(hscx, IPACX_MASKB, 0xFF); /* ints off */
1231 hscx_cmdr(hscx, 0x41);
1232 test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags);
1233 test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
1234 break;
1235 case ISDN_P_B_RAW:
1236 WriteHSCX(hscx, IPACX_MODEB, 0x88); /* ex trans */
1237 WriteHSCX(hscx, IPACX_EXMB, 0x00); /* trans */
1238 hscx_cmdr(hscx, 0x41);
1239 WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON);
1240 test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
1241 break;
1242 case ISDN_P_B_HDLC:
1243 WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* trans */
1244 WriteHSCX(hscx, IPACX_EXMB, 0x00); /* hdlc,crc */
1245 hscx_cmdr(hscx, 0x41);
1246 WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON);
1247 test_and_set_bit(FLG_HDLC, &hscx->bch.Flags);
1248 break;
1249 default:
1250 pr_info("%s: protocol not known %x\n", hscx->ip->name,
1251 bprotocol);
1252 return -ENOPROTOOPT;
1253 }
1254 } else if (hscx->ip->type & IPAC_TYPE_IPAC) { /* IPAC */
1255 WriteHSCX(hscx, IPAC_CCR1, 0x82);
1256 WriteHSCX(hscx, IPAC_CCR2, 0x30);
1257 WriteHSCX(hscx, IPAC_XCCR, 0x07);
1258 WriteHSCX(hscx, IPAC_RCCR, 0x07);
1259 WriteHSCX(hscx, IPAC_TSAX, hscx->slot);
1260 WriteHSCX(hscx, IPAC_TSAR, hscx->slot);
1261 switch (bprotocol) {
1262 case ISDN_P_NONE:
1263 WriteHSCX(hscx, IPAC_TSAX, 0x1F);
1264 WriteHSCX(hscx, IPAC_TSAR, 0x1F);
1265 WriteHSCX(hscx, IPAC_MODEB, 0x84);
1266 WriteHSCX(hscx, IPAC_CCR1, 0x82);
1267 WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */
1268 test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags);
1269 test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
1270 break;
1271 case ISDN_P_B_RAW:
1272 WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */
1273 WriteHSCX(hscx, IPAC_CCR1, 0x82);
1274 hscx_cmdr(hscx, 0x41);
1275 WriteHSCX(hscx, IPAC_MASKB, 0);
1276 test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
1277 break;
1278 case ISDN_P_B_HDLC:
1279 WriteHSCX(hscx, IPAC_MODEB, 0x8c);
1280 WriteHSCX(hscx, IPAC_CCR1, 0x8a);
1281 hscx_cmdr(hscx, 0x41);
1282 WriteHSCX(hscx, IPAC_MASKB, 0);
1283 test_and_set_bit(FLG_HDLC, &hscx->bch.Flags);
1284 break;
1285 default:
1286 pr_info("%s: protocol not known %x\n", hscx->ip->name,
1287 bprotocol);
1288 return -ENOPROTOOPT;
1289 }
1290 } else if (hscx->ip->type & IPAC_TYPE_HSCX) { /* HSCX */
1291 WriteHSCX(hscx, IPAC_CCR1, 0x85);
1292 WriteHSCX(hscx, IPAC_CCR2, 0x30);
1293 WriteHSCX(hscx, IPAC_XCCR, 0x07);
1294 WriteHSCX(hscx, IPAC_RCCR, 0x07);
1295 WriteHSCX(hscx, IPAC_TSAX, hscx->slot);
1296 WriteHSCX(hscx, IPAC_TSAR, hscx->slot);
1297 switch (bprotocol) {
1298 case ISDN_P_NONE:
1299 WriteHSCX(hscx, IPAC_TSAX, 0x1F);
1300 WriteHSCX(hscx, IPAC_TSAR, 0x1F);
1301 WriteHSCX(hscx, IPAC_MODEB, 0x84);
1302 WriteHSCX(hscx, IPAC_CCR1, 0x85);
1303 WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */
1304 test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags);
1305 test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
1306 break;
1307 case ISDN_P_B_RAW:
1308 WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */
1309 WriteHSCX(hscx, IPAC_CCR1, 0x85);
1310 hscx_cmdr(hscx, 0x41);
1311 WriteHSCX(hscx, IPAC_MASKB, 0);
1312 test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
1313 break;
1314 case ISDN_P_B_HDLC:
1315 WriteHSCX(hscx, IPAC_MODEB, 0x8c);
1316 WriteHSCX(hscx, IPAC_CCR1, 0x8d);
1317 hscx_cmdr(hscx, 0x41);
1318 WriteHSCX(hscx, IPAC_MASKB, 0);
1319 test_and_set_bit(FLG_HDLC, &hscx->bch.Flags);
1320 break;
1321 default:
1322 pr_info("%s: protocol not known %x\n", hscx->ip->name,
1323 bprotocol);
1324 return -ENOPROTOOPT;
1325 }
1326 } else
1327 return -EINVAL;
1328 hscx->bch.state = bprotocol;
1329 return 0;
1330}
1331
1332static int
1333hscx_l2l1(struct mISDNchannel *ch, struct sk_buff *skb)
1334{
1335 struct bchannel *bch = container_of(ch, struct bchannel, ch);
1336 struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch);
1337 int ret = -EINVAL;
1338 struct mISDNhead *hh = mISDN_HEAD_P(skb);
1339 u32 id;
1340 u_long flags;
1341
1342 switch (hh->prim) {
1343 case PH_DATA_REQ:
1344 spin_lock_irqsave(hx->ip->hwlock, flags);
1345 ret = bchannel_senddata(bch, skb);
1346 if (ret > 0) { /* direct TX */
1347 id = hh->id; /* skb can be freed */
1348 ret = 0;
1349 hscx_fill_fifo(hx);
1350 spin_unlock_irqrestore(hx->ip->hwlock, flags);
1351 if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
1352 queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
1353 } else
1354 spin_unlock_irqrestore(hx->ip->hwlock, flags);
1355 return ret;
1356 case PH_ACTIVATE_REQ:
1357 spin_lock_irqsave(hx->ip->hwlock, flags);
1358 if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
1359 ret = hscx_mode(hx, ch->protocol);
1360 else
1361 ret = 0;
1362 spin_unlock_irqrestore(hx->ip->hwlock, flags);
1363 if (!ret)
1364 _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
1365 NULL, GFP_KERNEL);
1366 break;
1367 case PH_DEACTIVATE_REQ:
1368 spin_lock_irqsave(hx->ip->hwlock, flags);
1369 mISDN_clear_bchannel(bch);
1370 hscx_mode(hx, ISDN_P_NONE);
1371 spin_unlock_irqrestore(hx->ip->hwlock, flags);
1372 _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
1373 NULL, GFP_KERNEL);
1374 ret = 0;
1375 break;
1376 default:
1377 pr_info("%s: %s unknown prim(%x,%x)\n",
1378 hx->ip->name, __func__, hh->prim, hh->id);
1379 ret = -EINVAL;
1380 }
1381 if (!ret)
1382 dev_kfree_skb(skb);
1383 return ret;
1384}
1385
1386static int
1387channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
1388{
1389 int ret = 0;
1390
1391 switch (cq->op) {
1392 case MISDN_CTRL_GETOP:
1393 cq->op = 0;
1394 break;
1395 /* Nothing implemented yet */
1396 case MISDN_CTRL_FILL_EMPTY:
1397 default:
1398 pr_info("%s: unknown Op %x\n", __func__, cq->op);
1399 ret = -EINVAL;
1400 break;
1401 }
1402 return ret;
1403}
1404
1405static int
1406hscx_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
1407{
1408 struct bchannel *bch = container_of(ch, struct bchannel, ch);
1409 struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch);
1410 int ret = -EINVAL;
1411 u_long flags;
1412
1413 pr_debug("%s: %s cmd:%x %p\n", hx->ip->name, __func__, cmd, arg);
1414 switch (cmd) {
1415 case CLOSE_CHANNEL:
1416 test_and_clear_bit(FLG_OPEN, &bch->Flags);
1417 if (test_bit(FLG_ACTIVE, &bch->Flags)) {
1418 spin_lock_irqsave(hx->ip->hwlock, flags);
1419 mISDN_freebchannel(bch);
1420 hscx_mode(hx, ISDN_P_NONE);
1421 spin_unlock_irqrestore(hx->ip->hwlock, flags);
1422 } else {
1423 skb_queue_purge(&bch->rqueue);
1424 bch->rcount = 0;
1425 }
1426 ch->protocol = ISDN_P_NONE;
1427 ch->peer = NULL;
1428 module_put(hx->ip->owner);
1429 ret = 0;
1430 break;
1431 case CONTROL_CHANNEL:
1432 ret = channel_bctrl(bch, arg);
1433 break;
1434 default:
1435 pr_info("%s: %s unknown prim(%x)\n",
1436 hx->ip->name, __func__, cmd);
1437 }
1438 return ret;
1439}
1440
1441static void
1442free_ipac(struct ipac_hw *ipac)
1443{
1444 isac_release(&ipac->isac);
1445}
1446
1447static const char *HSCXVer[] =
1448{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",
1449 "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};
1450
1451
1452
1453static void
1454hscx_init(struct hscx_hw *hx)
1455{
1456 u8 val;
1457
1458 WriteHSCX(hx, IPAC_RAH2, 0xFF);
1459 WriteHSCX(hx, IPAC_XBCH, 0x00);
1460 WriteHSCX(hx, IPAC_RLCR, 0x00);
1461
1462 if (hx->ip->type & IPAC_TYPE_HSCX) {
1463 WriteHSCX(hx, IPAC_CCR1, 0x85);
1464 val = ReadHSCX(hx, HSCX_VSTR);
1465 pr_debug("%s: HSCX VSTR %02x\n", hx->ip->name, val);
1466 if (hx->bch.debug & DEBUG_HW)
1467 pr_notice("%s: HSCX version %s\n", hx->ip->name,
1468 HSCXVer[val & 0x0f]);
1469 } else
1470 WriteHSCX(hx, IPAC_CCR1, 0x82);
1471 WriteHSCX(hx, IPAC_CCR2, 0x30);
1472 WriteHSCX(hx, IPAC_XCCR, 0x07);
1473 WriteHSCX(hx, IPAC_RCCR, 0x07);
1474}
1475
1476static int
1477ipac_init(struct ipac_hw *ipac)
1478{
1479 u8 val;
1480
1481 if (ipac->type & IPAC_TYPE_HSCX) {
1482 hscx_init(&ipac->hscx[0]);
1483 hscx_init(&ipac->hscx[1]);
1484 val = ReadIPAC(ipac, IPAC_ID);
1485 } else if (ipac->type & IPAC_TYPE_IPAC) {
1486 hscx_init(&ipac->hscx[0]);
1487 hscx_init(&ipac->hscx[1]);
1488 WriteIPAC(ipac, IPAC_MASK, IPAC__ON);
1489 val = ReadIPAC(ipac, IPAC_CONF);
1490 /* conf is default 0, but can be overwritten by card setup */
1491 pr_debug("%s: IPAC CONF %02x/%02x\n", ipac->name,
1492 val, ipac->conf);
1493 WriteIPAC(ipac, IPAC_CONF, ipac->conf);
1494 val = ReadIPAC(ipac, IPAC_ID);
1495 if (ipac->hscx[0].bch.debug & DEBUG_HW)
1496 pr_notice("%s: IPAC Design ID %02x\n", ipac->name, val);
1497 }
1498 /* nothing special for IPACX to do here */
1499 return isac_init(&ipac->isac);
1500}
1501
1502static int
1503open_bchannel(struct ipac_hw *ipac, struct channel_req *rq)
1504{
1505 struct bchannel *bch;
1506
1507 if (rq->adr.channel > 2)
1508 return -EINVAL;
1509 if (rq->protocol == ISDN_P_NONE)
1510 return -EINVAL;
1511 bch = &ipac->hscx[rq->adr.channel - 1].bch;
1512 if (test_and_set_bit(FLG_OPEN, &bch->Flags))
1513 return -EBUSY; /* b-channel can be only open once */
1514 test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
1515 bch->ch.protocol = rq->protocol;
1516 rq->ch = &bch->ch;
1517 return 0;
1518}
1519
1520static int
1521channel_ctrl(struct ipac_hw *ipac, struct mISDN_ctrl_req *cq)
1522{
1523 int ret = 0;
1524
1525 switch (cq->op) {
1526 case MISDN_CTRL_GETOP:
1527 cq->op = MISDN_CTRL_LOOP;
1528 break;
1529 case MISDN_CTRL_LOOP:
1530 /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */
1531 if (cq->channel < 0 || cq->channel > 3) {
1532 ret = -EINVAL;
1533 break;
1534 }
1535 ret = ipac->ctrl(ipac, HW_TESTLOOP, cq->channel);
1536 break;
1537 default:
1538 pr_info("%s: unknown CTRL OP %x\n", ipac->name, cq->op);
1539 ret = -EINVAL;
1540 break;
1541 }
1542 return ret;
1543}
1544
1545static int
1546ipac_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
1547{
1548 struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
1549 struct dchannel *dch = container_of(dev, struct dchannel, dev);
1550 struct isac_hw *isac = container_of(dch, struct isac_hw, dch);
1551 struct ipac_hw *ipac = container_of(isac, struct ipac_hw, isac);
1552 struct channel_req *rq;
1553 int err = 0;
1554
1555 pr_debug("%s: DCTRL: %x %p\n", ipac->name, cmd, arg);
1556 switch (cmd) {
1557 case OPEN_CHANNEL:
1558 rq = arg;
1559 if (rq->protocol == ISDN_P_TE_S0)
1560 err = open_dchannel(isac, rq);
1561 else
1562 err = open_bchannel(ipac, rq);
1563 if (err)
1564 break;
1565 if (!try_module_get(ipac->owner))
1566 pr_info("%s: cannot get module\n", ipac->name);
1567 break;
1568 case CLOSE_CHANNEL:
1569 pr_debug("%s: dev(%d) close from %p\n", ipac->name,
1570 dch->dev.id, __builtin_return_address(0));
1571 module_put(ipac->owner);
1572 break;
1573 case CONTROL_CHANNEL:
1574 err = channel_ctrl(ipac, arg);
1575 break;
1576 default:
1577 pr_debug("%s: unknown DCTRL command %x\n", ipac->name, cmd);
1578 return -EINVAL;
1579 }
1580 return err;
1581}
1582
1583u32
1584mISDNipac_init(struct ipac_hw *ipac, void *hw)
1585{
1586 u32 ret;
1587 u8 i;
1588
1589 ipac->hw = hw;
1590 if (ipac->isac.dch.debug & DEBUG_HW)
1591 pr_notice("%s: ipac type %x\n", ipac->name, ipac->type);
1592 if (ipac->type & IPAC_TYPE_HSCX) {
1593 ipac->isac.type = IPAC_TYPE_ISAC;
1594 ipac->hscx[0].off = 0;
1595 ipac->hscx[1].off = 0x40;
1596 ipac->hscx[0].fifo_size = 32;
1597 ipac->hscx[1].fifo_size = 32;
1598 } else if (ipac->type & IPAC_TYPE_IPAC) {
1599 ipac->isac.type = IPAC_TYPE_IPAC | IPAC_TYPE_ISAC;
1600 ipac->hscx[0].off = 0;
1601 ipac->hscx[1].off = 0x40;
1602 ipac->hscx[0].fifo_size = 64;
1603 ipac->hscx[1].fifo_size = 64;
1604 } else if (ipac->type & IPAC_TYPE_IPACX) {
1605 ipac->isac.type = IPAC_TYPE_IPACX | IPAC_TYPE_ISACX;
1606 ipac->hscx[0].off = IPACX_OFF_ICA;
1607 ipac->hscx[1].off = IPACX_OFF_ICB;
1608 ipac->hscx[0].fifo_size = 64;
1609 ipac->hscx[1].fifo_size = 64;
1610 } else
1611 return 0;
1612
1613 mISDNisac_init(&ipac->isac, hw);
1614
1615 ipac->isac.dch.dev.D.ctrl = ipac_dctrl;
1616
1617 for (i = 0; i < 2; i++) {
1618 ipac->hscx[i].bch.nr = i + 1;
1619 set_channelmap(i + 1, ipac->isac.dch.dev.channelmap);
1620 list_add(&ipac->hscx[i].bch.ch.list,
1621 &ipac->isac.dch.dev.bchannels);
1622 mISDN_initbchannel(&ipac->hscx[i].bch, MAX_DATA_MEM);
1623 ipac->hscx[i].bch.ch.nr = i + 1;
1624 ipac->hscx[i].bch.ch.send = &hscx_l2l1;
1625 ipac->hscx[i].bch.ch.ctrl = hscx_bctrl;
1626 ipac->hscx[i].bch.hw = hw;
1627 ipac->hscx[i].ip = ipac;
1628 /* default values for IOM time slots
1629 * can be overwriten by card */
1630 ipac->hscx[i].slot = (i == 0) ? 0x2f : 0x03;
1631 }
1632
1633 ipac->init = ipac_init;
1634 ipac->release = free_ipac;
1635
1636 ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
1637 (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
1638 return ret;
1639}
1640EXPORT_SYMBOL(mISDNipac_init);
1641
1642static int __init
1643isac_mod_init(void)
1644{
1645 pr_notice("mISDNipac module version %s\n", ISAC_REV);
1646 return 0;
1647}
1648
1649static void __exit
1650isac_mod_cleanup(void)
1651{
1652 pr_notice("mISDNipac module unloaded\n");
1653}
1654module_init(isac_mod_init);
1655module_exit(isac_mod_cleanup);