aboutsummaryrefslogtreecommitdiff
path: root/drivers/isdn
diff options
context:
space:
mode:
authorKarsten Keil <keil@b1-systems.de>2009-07-22 19:42:46 +0200
committerKarsten Keil <keil@b1-systems.de>2009-07-25 20:18:29 +0200
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 3024566dd09..a8542b81f95 100644
--- a/drivers/isdn/hardware/mISDN/Kconfig
+++ b/drivers/isdn/hardware/mISDN/Kconfig
@@ -39,3 +39,17 @@ config MISDN_HFCUSB
Enable support for USB ISDN TAs with Cologne Chip AG's
HFC-S USB ISDN Controller
+config MISDN_INFINEON
+ tristate "Support for cards with Infineon chipset"
+ depends on MISDN
+ depends on PCI
+ select MISDN_IPAC
+ help
+ Enable support for cards with ISAC + HSCX, IPAC or IPAC-SX
+ chip from Infineon (former manufacturer Siemens).
+
+
+config MISDN_IPAC
+ tristate
+ depends on MISDN
+
diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile
index b0403526bbb..2863455b493 100644
--- a/drivers/isdn/hardware/mISDN/Makefile
+++ b/drivers/isdn/hardware/mISDN/Makefile
@@ -6,3 +6,6 @@
obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o
obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o
obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o
+obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o
+# chip modules
+obj-$(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 00000000000..c16a217301e
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/iohelper.h
@@ -0,0 +1,109 @@
+/*
+ * iohelper.h
+ * helper for define functions to access ISDN hardware
+ * supported are memory mapped IO
+ * indirect port IO (one port for address, one for data)
+ *
+ * Author Karsten Keil <keil@isdn4linux.de>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _IOHELPER_H
+#define _IOHELPER_H
+
+typedef u8 (read_reg_t)(void *, u8);
+typedef void (write_reg_t)(void *, u8, u8);
+typedef void (fifo_func_t)(void *, u8, u8 *, int);
+
+struct _ioport {
+ u32 port;
+ u32 ale;
+};
+
+#define IOFUNC_IO(name, hws, ap) \
+ static u8 Read##name##_IO(void *p, u8 off) {\
+ struct hws *hw = p;\
+ return inb(hw->ap.port + off);\
+ } \
+ static void Write##name##_IO(void *p, u8 off, u8 val) {\
+ struct hws *hw = p;\
+ outb(val, hw->ap.port + off);\
+ } \
+ static void ReadFiFo##name##_IO(void *p, u8 off, u8 *dp, int size) {\
+ struct hws *hw = p;\
+ insb(hw->ap.port + off, dp, size);\
+ } \
+ static void WriteFiFo##name##_IO(void *p, u8 off, u8 *dp, int size) {\
+ struct hws *hw = p;\
+ outsb(hw->ap.port + off, dp, size);\
+ }
+
+#define IOFUNC_IND(name, hws, ap) \
+ static u8 Read##name##_IND(void *p, u8 off) {\
+ struct hws *hw = p;\
+ outb(off, hw->ap.ale);\
+ return inb(hw->ap.port);\
+ } \
+ static void Write##name##_IND(void *p, u8 off, u8 val) {\
+ struct hws *hw = p;\
+ outb(off, hw->ap.ale);\
+ outb(val, hw->ap.port);\
+ } \
+ static void ReadFiFo##name##_IND(void *p, u8 off, u8 *dp, int size) {\
+ struct hws *hw = p;\
+ outb(off, hw->ap.ale);\
+ insb(hw->ap.port, dp, size);\
+ } \
+ static void WriteFiFo##name##_IND(void *p, u8 off, u8 *dp, int size) {\
+ struct hws *hw = p;\
+ outb(off, hw->ap.ale);\
+ outsb(hw->ap.port, dp, size);\
+ }
+
+#define IOFUNC_MEMIO(name, hws, typ, adr) \
+ static u8 Read##name##_MIO(void *p, u8 off) {\
+ struct hws *hw = p;\
+ return readb(((typ *)hw->adr) + off);\
+ } \
+ static void Write##name##_MIO(void *p, u8 off, u8 val) {\
+ struct hws *hw = p;\
+ writeb(val, ((typ *)hw->adr) + off);\
+ } \
+ static void ReadFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) {\
+ struct hws *hw = p;\
+ while (size--)\
+ *dp++ = readb(((typ *)hw->adr) + off);\
+ } \
+ static void WriteFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) {\
+ struct inf_hw *hw = p;\
+ while (size--)\
+ writeb(*dp++, ((typ *)hw->adr) + off);\
+ }
+
+#define ASSIGN_FUNC(typ, name, dest) do {\
+ dest.read_reg = &Read##name##_##typ;\
+ dest.write_reg = &Write##name##_##typ;\
+ dest.read_fifo = &ReadFiFo##name##_##typ;\
+ dest.write_fifo = &WriteFiFo##name##_##typ;\
+ } while (0)
+#define ASSIGN_FUNC_IPAC(typ, target) do {\
+ ASSIGN_FUNC(typ, ISAC, target.isac);\
+ ASSIGN_FUNC(typ, IPAC, target);\
+ } while (0)
+
+#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 00000000000..f9601d55dbc
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/ipac.h
@@ -0,0 +1,405 @@
+/*
+ *
+ * ipac.h Defines for the Infineon (former Siemens) ISDN
+ * chip series
+ *
+ * Author Karsten Keil <keil@isdn4linux.de>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "iohelper.h"
+
+struct isac_hw {
+ struct dchannel dch;
+ u32 type;
+ u32 off; /* offset to isac regs */
+ char *name;
+ spinlock_t *hwlock; /* lock HW acccess */
+ read_reg_t *read_reg;
+ write_reg_t *write_reg;
+ fifo_func_t *read_fifo;
+ fifo_func_t *write_fifo;
+ int (*monitor)(void *, u32, u8 *, int);
+ void (*release)(struct isac_hw *);
+ int (*init)(struct isac_hw *);
+ int (*ctrl)(struct isac_hw *, u32, u_long);
+ int (*open)(struct isac_hw *, struct channel_req *);
+ u8 *mon_tx;
+ u8 *mon_rx;
+ int mon_txp;
+ int mon_txc;
+ int mon_rxp;
+ struct arcofi_msg *arcofi_list;
+ struct timer_list arcofitimer;
+ wait_queue_head_t arcofi_wait;
+ u8 arcofi_bc;
+ u8 arcofi_state;
+ u8 mocr;
+ u8 adf2;
+ u8 state;
+};
+
+struct ipac_hw;
+
+struct hscx_hw {
+ struct bchannel bch;
+ struct ipac_hw *ip;
+ u8 fifo_size;
+ u8 off; /* offset to ICA or ICB */
+ u8 slot;
+ char log[64];
+};
+
+struct ipac_hw {
+ struct isac_hw isac;
+ struct hscx_hw hscx[2];
+ char *name;
+ void *hw;
+ spinlock_t *hwlock; /* lock HW acccess */
+ struct module *owner;
+ u32 type;
+ read_reg_t *read_reg;
+ write_reg_t *write_reg;
+ fifo_func_t *read_fifo;
+ fifo_func_t *write_fifo;
+ void (*release)(struct ipac_hw *);
+ int (*init)(struct ipac_hw *);
+ int (*ctrl)(struct ipac_hw *, u32, u_long);
+ u8 conf;
+};
+
+#define IPAC_TYPE_ISAC 0x0010
+#define IPAC_TYPE_IPAC 0x0020
+#define IPAC_TYPE_ISACX 0x0040
+#define IPAC_TYPE_IPACX 0x0080
+#define IPAC_TYPE_HSCX 0x0100
+
+#define ISAC_USE_ARCOFI 0x1000
+
+/* Monitor functions */
+#define MONITOR_RX_0 0x1000
+#define MONITOR_RX_1 0x1001
+#define MONITOR_TX_0 0x2000
+#define MONITOR_TX_1 0x2001
+
+/* All registers original Siemens Spec */
+/* IPAC/ISAC registers */
+#define ISAC_MASK 0x20
+#define ISAC_ISTA 0x20
+#define ISAC_STAR 0x21
+#define ISAC_CMDR 0x21
+#define ISAC_EXIR 0x24
+#define ISAC_ADF2 0x39
+#define ISAC_SPCR 0x30
+#define ISAC_ADF1 0x38
+#define ISAC_CIR0 0x31
+#define ISAC_CIX0 0x31
+#define ISAC_CIR1 0x33
+#define ISAC_CIX1 0x33
+#define ISAC_STCR 0x37
+#define ISAC_MODE 0x22
+#define ISAC_RSTA 0x27
+#define ISAC_RBCL 0x25
+#define ISAC_RBCH 0x2A
+#define ISAC_TIMR 0x23
+#define ISAC_SQXR 0x3b
+#define ISAC_SQRR 0x3b
+#define ISAC_MOSR 0x3a
+#define ISAC_MOCR 0x3a
+#define ISAC_MOR0 0x32
+#define ISAC_MOX0 0x32
+#define ISAC_MOR1 0x34
+#define ISAC_MOX1 0x34
+
+#define ISAC_RBCH_XAC 0x80
+
+#define IPAC_D_TIN2 0x01
+
+/* IPAC/HSCX */
+#define IPAC_ISTAB 0x20 /* RD */
+#define IPAC_MASKB 0x20 /* WR */
+#define IPAC_STARB 0x21 /* RD */
+#define IPAC_CMDRB 0x21 /* WR */
+#define IPAC_MODEB 0x22 /* R/W */
+#define IPAC_EXIRB 0x24 /* RD */
+#define IPAC_RBCLB 0x25 /* RD */
+#define IPAC_RAH1 0x26 /* WR */
+#define IPAC_RAH2 0x27 /* WR */
+#define IPAC_RSTAB 0x27 /* RD */
+#define IPAC_RAL1 0x28 /* R/W */
+#define IPAC_RAL2 0x29 /* WR */
+#define IPAC_RHCRB 0x29 /* RD */
+#define IPAC_XBCL 0x2A /* WR */
+#define IPAC_CCR2 0x2C /* R/W */
+#define IPAC_RBCHB 0x2D /* RD */
+#define IPAC_XBCH 0x2D /* WR */
+#define HSCX_VSTR 0x2E /* RD */
+#define IPAC_RLCR 0x2E /* WR */
+#define IPAC_CCR1 0x2F /* R/W */
+#define IPAC_TSAX 0x30 /* WR */
+#define IPAC_TSAR 0x31 /* WR */
+#define IPAC_XCCR 0x32 /* WR */
+#define IPAC_RCCR 0x33 /* WR */
+
+/* IPAC_ISTAB/IPAC_MASKB bits */
+#define IPAC_B_XPR 0x10
+#define IPAC_B_RPF 0x40
+#define IPAC_B_RME 0x80
+#define IPAC_B_ON 0x2F
+
+/* IPAC_EXIRB bits */
+#define IPAC_B_RFS 0x04
+#define IPAC_B_RFO 0x10
+#define IPAC_B_XDU 0x40
+#define IPAC_B_XMR 0x80
+
+/* IPAC special registers */
+#define IPAC_CONF 0xC0 /* R/W */
+#define IPAC_ISTA 0xC1 /* RD */
+#define IPAC_MASK 0xC1 /* WR */
+#define IPAC_ID 0xC2 /* RD */
+#define IPAC_ACFG 0xC3 /* R/W */
+#define IPAC_AOE 0xC4 /* R/W */
+#define IPAC_ARX 0xC5 /* RD */
+#define IPAC_ATX 0xC5 /* WR */
+#define IPAC_PITA1 0xC6 /* R/W */
+#define IPAC_PITA2 0xC7 /* R/W */
+#define IPAC_POTA1 0xC8 /* R/W */
+#define IPAC_POTA2 0xC9 /* R/W */
+#define IPAC_PCFG 0xCA /* R/W */
+#define IPAC_SCFG 0xCB /* R/W */
+#define IPAC_TIMR2 0xCC /* R/W */
+
+/* IPAC_ISTA/_MASK bits */
+#define IPAC__EXB 0x01
+#define IPAC__ICB 0x02
+#define IPAC__EXA 0x04
+#define IPAC__ICA 0x08
+#define IPAC__EXD 0x10
+#define IPAC__ICD 0x20
+#define IPAC__INT0 0x40
+#define IPAC__INT1 0x80
+#define IPAC__ON 0xC0
+
+/* HSCX ISTA/MASK bits */
+#define HSCX__EXB 0x01
+#define HSCX__EXA 0x02
+#define HSCX__ICA 0x04
+
+/* ISAC/ISACX/IPAC/IPACX L1 commands */
+#define ISAC_CMD_TIM 0x0
+#define ISAC_CMD_RS 0x1
+#define ISAC_CMD_SCZ 0x4
+#define ISAC_CMD_SSZ 0x2
+#define ISAC_CMD_AR8 0x8
+#define ISAC_CMD_AR10 0x9
+#define ISAC_CMD_ARL 0xA
+#define ISAC_CMD_DUI 0xF
+
+/* ISAC/ISACX/IPAC/IPACX L1 indications */
+#define ISAC_IND_RS 0x1
+#define ISAC_IND_PU 0x7
+#define ISAC_IND_DR 0x0
+#define ISAC_IND_SD 0x2
+#define ISAC_IND_DIS 0x3
+#define ISAC_IND_EI 0x6
+#define ISAC_IND_RSY 0x4
+#define ISAC_IND_ARD 0x8
+#define ISAC_IND_TI 0xA
+#define ISAC_IND_ATI 0xB
+#define ISAC_IND_AI8 0xC
+#define ISAC_IND_AI10 0xD
+#define ISAC_IND_DID 0xF
+
+/* the new ISACX / IPACX */
+/* D-channel registers */
+#define ISACX_RFIFOD 0x00 /* RD */
+#define ISACX_XFIFOD 0x00 /* WR */
+#define ISACX_ISTAD 0x20 /* RD */
+#define ISACX_MASKD 0x20 /* WR */
+#define ISACX_STARD 0x21 /* RD */
+#define ISACX_CMDRD 0x21 /* WR */
+#define ISACX_MODED 0x22 /* R/W */
+#define ISACX_EXMD1 0x23 /* R/W */
+#define ISACX_TIMR1 0x24 /* R/W */
+#define ISACX_SAP1 0x25 /* WR */
+#define ISACX_SAP2 0x26 /* WR */
+#define ISACX_RBCLD 0x26 /* RD */
+#define ISACX_RBCHD 0x27 /* RD */
+#define ISACX_TEI1 0x27 /* WR */
+#define ISACX_TEI2 0x28 /* WR */
+#define ISACX_RSTAD 0x28 /* RD */
+#define ISACX_TMD 0x29 /* R/W */
+#define ISACX_CIR0 0x2E /* RD */
+#define ISACX_CIX0 0x2E /* WR */
+#define ISACX_CIR1 0x2F /* RD */
+#define ISACX_CIX1 0x2F /* WR */
+
+/* Transceiver registers */
+#define ISACX_TR_CONF0 0x30 /* R/W */
+#define ISACX_TR_CONF1 0x31 /* R/W */
+#define ISACX_TR_CONF2 0x32 /* R/W */
+#define ISACX_TR_STA 0x33 /* RD */
+#define ISACX_TR_CMD 0x34 /* R/W */
+#define ISACX_SQRR1 0x35 /* RD */
+#define ISACX_SQXR1 0x35 /* WR */
+#define ISACX_SQRR2 0x36 /* RD */
+#define ISACX_SQXR2 0x36 /* WR */
+#define ISACX_SQRR3 0x37 /* RD */
+#define ISACX_SQXR3 0x37 /* WR */
+#define ISACX_ISTATR 0x38 /* RD */
+#define ISACX_MASKTR 0x39 /* R/W */
+#define ISACX_TR_MODE 0x3A /* R/W */
+#define ISACX_ACFG1 0x3C /* R/W */
+#define ISACX_ACFG2 0x3D /* R/W */
+#define ISACX_AOE 0x3E /* R/W */
+#define ISACX_ARX 0x3F /* RD */
+#define ISACX_ATX 0x3F /* WR */
+
+/* IOM: Timeslot, DPS, CDA */
+#define ISACX_CDA10 0x40 /* R/W */
+#define ISACX_CDA11 0x41 /* R/W */
+#define ISACX_CDA20 0x42 /* R/W */
+#define ISACX_CDA21 0x43 /* R/W */
+#define ISACX_CDA_TSDP10 0x44 /* R/W */
+#define ISACX_CDA_TSDP11 0x45 /* R/W */
+#define ISACX_CDA_TSDP20 0x46 /* R/W */
+#define ISACX_CDA_TSDP21 0x47 /* R/W */
+#define ISACX_BCHA_TSDP_BC1 0x48 /* R/W */
+#define ISACX_BCHA_TSDP_BC2 0x49 /* R/W */
+#define ISACX_BCHB_TSDP_BC1 0x4A /* R/W */
+#define ISACX_BCHB_TSDP_BC2 0x4B /* R/W */
+#define ISACX_TR_TSDP_BC1 0x4C /* R/W */
+#define ISACX_TR_TSDP_BC2 0x4D /* R/W */
+#define ISACX_CDA1_CR 0x4E /* R/W */
+#define ISACX_CDA2_CR 0x4F /* R/W */
+
+/* IOM: Contol, Sync transfer, Monitor */
+#define ISACX_TR_CR 0x50 /* R/W */
+#define ISACX_TRC_CR 0x50 /* R/W */
+#define ISACX_BCHA_CR 0x51 /* R/W */
+#define ISACX_BCHB_CR 0x52 /* R/W */
+#define ISACX_DCI_CR 0x53 /* R/W */
+#define ISACX_DCIC_CR 0x53 /* R/W */
+#define ISACX_MON_CR 0x54 /* R/W */
+#define ISACX_SDS1_CR 0x55 /* R/W */
+#define ISACX_SDS2_CR 0x56 /* R/W */
+#define ISACX_IOM_CR 0x57 /* R/W */
+#define ISACX_STI 0x58 /* RD */
+#define ISACX_ASTI 0x58 /* WR */
+#define ISACX_MSTI 0x59 /* R/W */
+#define ISACX_SDS_CONF 0x5A /* R/W */
+#define ISACX_MCDA 0x5B /* RD */
+#define ISACX_MOR 0x5C /* RD */
+#define ISACX_MOX 0x5C /* WR */
+#define ISACX_MOSR 0x5D /* RD */
+#define ISACX_MOCR 0x5E /* R/W */
+#define ISACX_MSTA 0x5F /* RD */
+#define ISACX_MCONF 0x5F /* WR */
+
+/* Interrupt and general registers */
+#define ISACX_ISTA 0x60 /* RD */
+#define ISACX_MASK 0x60 /* WR */
+#define ISACX_AUXI 0x61 /* RD */
+#define ISACX_AUXM 0x61 /* WR */
+#define ISACX_MODE1 0x62 /* R/W */
+#define ISACX_MODE2 0x63 /* R/W */
+#define ISACX_ID 0x64 /* RD */
+#define ISACX_SRES 0x64 /* WR */
+#define ISACX_TIMR2 0x65 /* R/W */
+
+/* Register Bits */
+/* ISACX/IPACX _ISTAD (R) and _MASKD (W) */
+#define ISACX_D_XDU 0x04
+#define ISACX_D_XMR 0x08
+#define ISACX_D_XPR 0x10
+#define ISACX_D_RFO 0x20
+#define ISACX_D_RPF 0x40
+#define ISACX_D_RME 0x80
+
+/* ISACX/IPACX _ISTA (R) and _MASK (W) */
+#define ISACX__ICD 0x01
+#define ISACX__MOS 0x02
+#define ISACX__TRAN 0x04
+#define ISACX__AUX 0x08
+#define ISACX__CIC 0x10
+#define ISACX__ST 0x20
+#define IPACX__ICB 0x40
+#define IPACX__ICA 0x80
+#define IPACX__ON 0x2C
+
+/* ISACX/IPACX _CMDRD (W) */
+#define ISACX_CMDRD_XRES 0x01
+#define ISACX_CMDRD_XME 0x02
+#define ISACX_CMDRD_XTF 0x08
+#define ISACX_CMDRD_STI 0x10
+#define ISACX_CMDRD_RRES 0x40
+#define ISACX_CMDRD_RMC 0x80
+
+/* ISACX/IPACX _RSTAD (R) */
+#define ISACX_RSTAD_TA 0x01
+#define ISACX_RSTAD_CR 0x02
+#define ISACX_RSTAD_SA0 0x04
+#define ISACX_RSTAD_SA1 0x08
+#define ISACX_RSTAD_RAB 0x10
+#define ISACX_RSTAD_CRC 0x20
+#define ISACX_RSTAD_RDO 0x40
+#define ISACX_RSTAD_VFR 0x80
+
+/* ISACX/IPACX _CIR0 (R) */
+#define ISACX_CIR0_BAS 0x01
+#define ISACX_CIR0_SG 0x08
+#define ISACX_CIR0_CIC1 0x08
+#define ISACX_CIR0_CIC0 0x08
+
+/* B-channel registers */
+#define IPACX_OFF_ICA 0x70
+#define IPACX_OFF_ICB 0x80
+
+/* ICA: IPACX_OFF_ICA + Reg ICB: IPACX_OFF_ICB + Reg */
+
+#define IPACX_ISTAB 0x00 /* RD */
+#define IPACX_MASKB 0x00 /* WR */
+#define IPACX_STARB 0x01 /* RD */
+#define IPACX_CMDRB 0x01 /* WR */
+#define IPACX_MODEB 0x02 /* R/W */
+#define IPACX_EXMB 0x03 /* R/W */
+#define IPACX_RAH1 0x05 /* WR */
+#define IPACX_RAH2 0x06 /* WR */
+#define IPACX_RBCLB 0x06 /* RD */
+#define IPACX_RBCHB 0x07 /* RD */
+#define IPACX_RAL1 0x07 /* WR */
+#define IPACX_RAL2 0x08 /* WR */
+#define IPACX_RSTAB 0x08 /* RD */
+#define IPACX_TMB 0x09 /* R/W */
+#define IPACX_RFIFOB 0x0A /* RD */
+#define IPACX_XFIFOB 0x0A /* WR */
+
+/* IPACX_ISTAB / IPACX_MASKB bits */
+#define IPACX_B_XDU 0x04
+#define IPACX_B_XPR 0x10
+#define IPACX_B_RFO 0x20
+#define IPACX_B_RPF 0x40
+#define IPACX_B_RME 0x80
+
+#define IPACX_B_ON 0x0B
+
+extern int mISDNisac_init(struct isac_hw *, void *);
+extern irqreturn_t mISDNisac_irq(struct isac_hw *, u8);
+extern u32 mISDNipac_init(struct ipac_hw *, void *);
+extern 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 00000000000..62441ba53b9
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/mISDNinfineon.c
@@ -0,0 +1,1178 @@
+/*
+ * mISDNinfineon.c
+ * Support for cards based on following Infineon ISDN chipsets
+ * - ISAC + HSCX
+ * - IPAC and IPAC-X
+ * - ISAC-SX + HSCX
+ *
+ * Supported cards:
+ * - Dialogic Diva 2.0
+ * - Dialogic Diva 2.0U
+ * - Dialogic Diva 2.01
+ * - Dialogic Diva 2.02
+ * - Sedlbauer Speedwin
+ * - HST Saphir3
+ * - Develo (former ELSA) Microlink PCI (Quickstep 1000)
+ * - Develo (former ELSA) Quickstep 3000
+ * - Berkom Scitel BRIX Quadro
+ * - Dr.Neuhaus (Sagem) Niccy
+ *
+ *
+ *
+ * Author Karsten Keil <keil@isdn4linux.de>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/mISDNhw.h>
+#include "ipac.h"
+
+#define INFINEON_REV "1.0"
+
+static int inf_cnt;
+static u32 debug;
+static u32 irqloops = 4;
+
+enum inf_types {
+ INF_NONE,
+ INF_DIVA20,
+ INF_DIVA20U,
+ INF_DIVA201,
+ INF_DIVA202,
+ INF_SPEEDWIN,
+ INF_SAPHIR3,
+ INF_QS1000,
+ INF_QS3000,
+ INF_NICCY,
+ INF_SCT_1,
+ INF_SCT_2,
+ INF_SCT_3,
+ INF_SCT_4,
+ INF_GAZEL_R685,
+ INF_GAZEL_R753
+};
+
+enum addr_mode {
+ AM_NONE = 0,
+ AM_IO,
+ AM_MEMIO,
+ AM_IND_IO,
+};
+
+struct inf_cinfo {
+ enum inf_types typ;
+ const char *full;
+ const char *name;
+ enum addr_mode cfg_mode;
+ enum addr_mode addr_mode;
+ u8 cfg_bar;
+ u8 addr_bar;
+ void *irqfunc;
+};
+
+struct _ioaddr {
+ enum addr_mode mode;
+ union {
+ void __iomem *p;
+ struct _ioport io;
+ } a;
+};
+
+struct _iohandle {
+ enum addr_mode mode;
+ resource_size_t size;
+ resource_size_t start;
+ void __iomem *p;
+};
+
+struct inf_hw {
+ struct list_head list;
+ struct pci_dev *pdev;
+ const struct inf_cinfo *ci;
+ char name[MISDN_MAX_IDLEN];
+ u32 irq;
+ u32 irqcnt;
+ struct _iohandle cfg;
+ struct _iohandle addr;
+ struct _ioaddr isac;
+ struct _ioaddr hscx;
+ spinlock_t lock; /* HW access lock */
+ struct ipac_hw ipac;
+ struct inf_hw *sc[3]; /* slave cards */
+};
+
+
+#define PCI_SUBVENDOR_HST_SAPHIR3 0x52
+#define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53
+#define PCI_SUB_ID_SEDLBAUER 0x01
+
+static struct pci_device_id infineon_ids[] __devinitdata = {
+ { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA20},
+ { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20_U,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA20U},
+ { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA201,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA201},
+ { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA202,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA202},
+ { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
+ PCI_SUBVENDOR_SEDLBAUER_PCI, PCI_SUB_ID_SEDLBAUER, 0, 0,
+ INF_SPEEDWIN},
+ { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
+ PCI_SUBVENDOR_HST_SAPHIR3, PCI_SUB_ID_SEDLBAUER, 0, 0, INF_SAPHIR3},
+ { PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_MICROLINK,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_QS1000},
+ { PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_QS3000,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_QS3000},
+ { PCI_VENDOR_ID_SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_NICCY},
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO, 0, 0,
+ INF_SCT_1},
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R685,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R685},
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R753,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753},
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753},
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_OLITEC,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753},
+ { }
+};
+MODULE_DEVICE_TABLE(pci, infineon_ids);
+
+/* PCI interface specific defines */
+/* Diva 2.0/2.0U */
+#define DIVA_HSCX_PORT 0x00
+#define DIVA_HSCX_ALE 0x04
+#define DIVA_ISAC_PORT 0x08
+#define DIVA_ISAC_ALE 0x0C
+#define DIVA_PCI_CTRL 0x10
+
+/* DIVA_PCI_CTRL bits */
+#define DIVA_IRQ_BIT 0x01
+#define DIVA_RESET_BIT 0x08
+#define DIVA_EEPROM_CLK 0x40
+#define DIVA_LED_A 0x10
+#define DIVA_LED_B 0x20
+#define DIVA_IRQ_CLR 0x80
+
+/* Diva 2.01/2.02 */
+/* Siemens PITA */
+#define PITA_ICR_REG 0x00
+#define PITA_INT0_STATUS 0x02
+
+#define PITA_MISC_REG 0x1c
+#define PITA_PARA_SOFTRESET 0x01000000
+#define PITA_SER_SOFTRESET 0x02000000
+#define PITA_PARA_MPX_MODE 0x04000000
+#define PITA_INT0_ENABLE 0x00020000
+
+/* TIGER 100 Registers */
+#define TIGER_RESET_ADDR 0x00
+#define TIGER_EXTERN_RESET 0x01
+#define TIGER_AUX_CTRL 0x02
+#define TIGER_AUX_DATA 0x03
+#define TIGER_AUX_IRQMASK 0x05
+#define TIGER_AUX_STATUS 0x07
+
+/* Tiger AUX BITs */
+#define TIGER_IOMASK 0xdd /* 1 and 5 are inputs */
+#define TIGER_IRQ_BIT 0x02
+
+#define TIGER_IPAC_ALE 0xC0
+#define TIGER_IPAC_PORT 0xC8
+
+/* ELSA (now Develo) PCI cards */
+#define ELSA_IRQ_ADDR 0x4c
+#define ELSA_IRQ_MASK 0x04
+#define QS1000_IRQ_OFF 0x01
+#define QS3000_IRQ_OFF 0x03
+#define QS1000_IRQ_ON 0x41
+#define QS3000_IRQ_ON 0x43
+
+/* Dr Neuhaus/Sagem Niccy */
+#define NICCY_ISAC_PORT 0x00
+#define NICCY_HSCX_PORT 0x01
+#define NICCY_ISAC_ALE 0x02
+#define NICCY_HSCX_ALE 0x03
+
+#define NICCY_IRQ_CTRL_REG 0x38
+#define NICCY_IRQ_ENABLE 0x001f00
+#define NICCY_IRQ_DISABLE 0xff0000
+#define NICCY_IRQ_BIT 0x800000
+
+
+/* Scitel PLX */
+#define SCT_PLX_IRQ_ADDR 0x4c
+#define SCT_PLX_RESET_ADDR 0x50
+#define SCT_PLX_IRQ_ENABLE 0x41
+#define SCT_PLX_RESET_BIT 0x04
+
+/* Gazel */
+#define GAZEL_IPAC_DATA_PORT 0x04
+/* Gazel PLX */
+#define GAZEL_CNTRL 0x50
+#define GAZEL_RESET 0x04
+#define GAZEL_RESET_9050 0x40000000
+#define GAZEL_INCSR 0x4C
+#define GAZEL_ISAC_EN 0x08
+#define GAZEL_INT_ISAC 0x20
+#define GAZEL_HSCX_EN 0x01
+#define GAZEL_INT_HSCX 0x04
+#define GAZEL_PCI_EN 0x40
+#define GAZEL_IPAC_EN 0x03
+
+
+static LIST_HEAD(Cards);
+static DEFINE_RWLOCK(card_lock); /* protect Cards */
+
+static void
+_set_debug(struct inf_hw *card)
+{
+ card->ipac.isac.dch.debug = debug;
+ card->ipac.hscx[0].bch.debug = debug;
+ card->ipac.hscx[1].bch.debug = debug;
+}
+
+static int
+set_debug(const char *val, struct kernel_param *kp)
+{
+ int ret;
+ struct inf_hw *card;
+
+ ret = param_set_uint(val, kp);
+ if (!ret) {
+ read_lock(&card_lock);
+ list_for_each_entry(card, &Cards, list)
+ _set_debug(card);
+ read_unlock(&card_lock);
+ }
+ return ret;
+}
+
+MODULE_AUTHOR("Karsten Keil");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(INFINEON_REV);
+module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "infineon debug mask");
+module_param(irqloops, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(irqloops, "infineon maximal irqloops (default 4)");
+
+/* Interface functions */
+
+IOFUNC_IO(ISAC, inf_hw, isac.a.io)
+IOFUNC_IO(IPAC, inf_hw, hscx.a.io)
+IOFUNC_IND(ISAC, inf_hw, isac.a.io)
+IOFUNC_IND(IPAC, inf_hw, hscx.a.io)
+IOFUNC_MEMIO(ISAC, inf_hw, u32, isac.a.p)
+IOFUNC_MEMIO(IPAC, inf_hw, u32, hscx.a.p)
+
+static irqreturn_t
+diva_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ u8 val;
+
+ spin_lock(&hw->lock);
+ val = inb((u32)hw->cfg.start + DIVA_PCI_CTRL);
+ if (!(val & DIVA_IRQ_BIT)) { /* for us or shared ? */
+ spin_unlock(&hw->lock);
+ return IRQ_NONE; /* shared */
+ }
+ hw->irqcnt++;
+ mISDNipac_irq(&hw->ipac, irqloops);
+ spin_unlock(&hw->lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+diva20x_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ u8 val;
+
+ spin_lock(&hw->lock);
+ val = readb(hw->cfg.p);
+ if (!(val & PITA_INT0_STATUS)) { /* for us or shared ? */
+ spin_unlock(&hw->lock);
+ return IRQ_NONE; /* shared */
+ }
+ hw->irqcnt++;
+ mISDNipac_irq(&hw->ipac, irqloops);
+ writeb(PITA_INT0_STATUS, hw->cfg.p); /* ACK PITA INT0 */
+ spin_unlock(&hw->lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+tiger_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ u8 val;
+
+ spin_lock(&hw->lock);
+ val = inb((u32)hw->cfg.start + TIGER_AUX_STATUS);
+ if (val & TIGER_IRQ_BIT) { /* for us or shared ? */
+ spin_unlock(&hw->lock);
+ return IRQ_NONE; /* shared */
+ }
+ hw->irqcnt++;
+ mISDNipac_irq(&hw->ipac, irqloops);
+ spin_unlock(&hw->lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+elsa_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ u8 val;
+
+ spin_lock(&hw->lock);
+ val = inb((u32)hw->cfg.start + ELSA_IRQ_ADDR);
+ if (!(val & ELSA_IRQ_MASK)) {
+ spin_unlock(&hw->lock);
+ return IRQ_NONE; /* shared */
+ }
+ hw->irqcnt++;
+ mISDNipac_irq(&hw->ipac, irqloops);
+ spin_unlock(&hw->lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+niccy_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ u32 val;
+
+ spin_lock(&hw->lock);
+ val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
+ if (!(val & NICCY_IRQ_BIT)) { /* for us or shared ? */
+ spin_unlock(&hw->lock);
+ return IRQ_NONE; /* shared */
+ }
+ outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
+ hw->irqcnt++;
+ mISDNipac_irq(&hw->ipac, irqloops);
+ spin_unlock(&hw->lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+gazel_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ irqreturn_t ret;
+
+ spin_lock(&hw->lock);
+ ret = mISDNipac_irq(&hw->ipac, irqloops);
+ spin_unlock(&hw->lock);
+ return ret;
+}
+
+static irqreturn_t
+ipac_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ u8 val;
+
+ spin_lock(&hw->lock);
+ val = hw->ipac.read_reg(hw, IPAC_ISTA);
+ if (!(val & 0x3f)) {
+ spin_unlock(&hw->lock);
+ return IRQ_NONE; /* shared */
+ }
+ hw->irqcnt++;
+ mISDNipac_irq(&hw->ipac, irqloops);
+ spin_unlock(&hw->lock);
+ return IRQ_HANDLED;
+}
+
+static void
+enable_hwirq(struct inf_hw *hw)
+{
+ u16 w;
+ u32 val;
+
+ switch (hw->ci->typ) {
+ case INF_DIVA201:
+ case INF_DIVA202:
+ writel(PITA_INT0_ENABLE, hw->cfg.p);
+ break;
+ case INF_SPEEDWIN:
+ case INF_SAPHIR3:
+ outb(TIGER_IRQ_BIT, (u32)hw->cfg.start + TIGER_AUX_IRQMASK);
+ break;
+ case INF_QS1000:
+ outb(QS1000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
+ break;
+ case INF_QS3000:
+ outb(QS3000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
+ break;
+ case INF_NICCY:
+ val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
+ val |= NICCY_IRQ_ENABLE;;
+ outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
+ break;
+ case INF_SCT_1:
+ w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
+ w |= SCT_PLX_IRQ_ENABLE;
+ outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
+ break;
+ case INF_GAZEL_R685:
+ outb(GAZEL_ISAC_EN + GAZEL_HSCX_EN + GAZEL_PCI_EN,
+ (u32)hw->cfg.start + GAZEL_INCSR);
+ break;
+ case INF_GAZEL_R753:
+ outb(GAZEL_IPAC_EN + GAZEL_PCI_EN,
+ (u32)hw->cfg.start + GAZEL_INCSR);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+disable_hwirq(struct inf_hw *hw)
+{
+ u16 w;
+ u32 val;
+
+ switch (hw->ci->typ) {
+ case INF_DIVA201:
+ case INF_DIVA202:
+ writel(0, hw->cfg.p);
+ break;
+ case INF_SPEEDWIN:
+ case INF_SAPHIR3:
+ outb(0, (u32)hw->cfg.start + TIGER_AUX_IRQMASK);
+ break;
+ case INF_QS1000:
+ outb(QS1000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
+ break;
+ case INF_QS3000:
+ outb(QS3000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
+ break;
+ case INF_NICCY:
+ val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
+ val &= NICCY_IRQ_DISABLE;
+ outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
+ break;
+ case INF_SCT_1:
+ w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
+ w &= (~SCT_PLX_IRQ_ENABLE);
+ outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
+ break;
+ case INF_GAZEL_R685:
+ case INF_GAZEL_R753:
+ outb(0, (u32)hw->cfg.start + GAZEL_INCSR);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+ipac_chip_reset(struct inf_hw *hw)
+{
+ hw->ipac.write_reg(hw, IPAC_POTA2, 0x20);
+ mdelay(5);
+ hw->ipac.write_reg(hw, IPAC_POTA2, 0x00);
+ mdelay(5);
+ hw->ipac.write_reg(hw, IPAC_CONF, hw->ipac.conf);
+ hw->ipac.write_reg(hw, IPAC_MASK, 0xc0);
+}
+
+static void
+reset_inf(struct inf_hw *hw)
+{
+ u16 w;
+ u32 val;
+
+ if (debug & DEBUG_HW)
+ pr_notice("%s: resetting card\n", hw->name);
+ switch (hw->ci->typ) {
+ case INF_DIVA20:
+ case INF_DIVA20U:
+ outb(0, (u32)hw->cfg.start + DIVA_PCI_CTRL);
+ mdelay(10);
+ outb(DIVA_RESET_BIT, (u32)hw->cfg.start + DIVA_PCI_CTRL);
+ mdelay(10);
+ /* Workaround PCI9060 */
+ outb(9, (u32)hw->cfg.start + 0x69);
+ outb(DIVA_RESET_BIT | DIVA_LED_A,
+ (u32)hw->cfg.start + DIVA_PCI_CTRL);
+ break;
+ case INF_DIVA201:
+ writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE,
+ hw->cfg.p + PITA_MISC_REG);
+ mdelay(1);
+ writel(PITA_PARA_MPX_MODE, hw->cfg.p + PITA_MISC_REG);
+ mdelay(10);
+ break;
+ case INF_DIVA202:
+ writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE,
+ hw->cfg.p + PITA_MISC_REG);
+ mdelay(1);
+ writel(PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET,
+ hw->cfg.p + PITA_MISC_REG);
+ mdelay(10);
+ break;
+ case INF_SPEEDWIN:
+ case INF_SAPHIR3:
+ ipac_chip_reset(hw);
+ hw->ipac.write_reg(hw, IPAC_ACFG, 0xff);
+ hw->ipac.write_reg(hw, IPAC_AOE, 0x00);
+ hw->ipac.write_reg(hw, IPAC_PCFG, 0x12);
+ break;
+ case INF_QS1000:
+ case INF_QS3000:
+ ipac_chip_reset(hw);
+ hw->ipac.write_reg(hw, IPAC_ACFG, 0x00);
+ hw->ipac.write_reg(hw, IPAC_AOE, 0x3c);
+ hw->ipac.write_reg(hw, IPAC_ATX, 0xff);
+ break;
+ case INF_NICCY:
+ break;
+ case INF_SCT_1:
+ w = inw((u32)hw->c