summaryrefslogtreecommitdiffstats
path: root/drivers/isdn/eicon
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/isdn/eicon')
-rw-r--r--drivers/isdn/eicon/eicon.h164
-rw-r--r--drivers/isdn/eicon/eicon_dsp.h119
-rw-r--r--drivers/isdn/eicon/eicon_idi.c648
-rw-r--r--drivers/isdn/eicon/eicon_idi.h31
-rw-r--r--drivers/isdn/eicon/eicon_io.c258
-rw-r--r--drivers/isdn/eicon/eicon_isa.c19
-rw-r--r--drivers/isdn/eicon/eicon_mod.c474
-rw-r--r--drivers/isdn/eicon/eicon_pci.c37
8 files changed, 1530 insertions, 220 deletions
diff --git a/drivers/isdn/eicon/eicon.h b/drivers/isdn/eicon/eicon.h
index 9552d2b54..beee023dc 100644
--- a/drivers/isdn/eicon/eicon.h
+++ b/drivers/isdn/eicon/eicon.h
@@ -1,4 +1,4 @@
-/* $Id: eicon.h,v 1.5 1999/03/29 11:19:41 armin Exp $
+/* $Id: eicon.h,v 1.11 1999/08/29 17:23:44 armin Exp $
*
* ISDN low-level module for Eicon.Diehl active ISDN-Cards.
*
@@ -21,6 +21,33 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon.h,v $
+ * Revision 1.11 1999/08/29 17:23:44 armin
+ * New setup compat.
+ * Bugfix if compile as not module.
+ *
+ * Revision 1.10 1999/08/22 20:26:41 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.9 1999/08/18 20:16:57 armin
+ * Added XLOG function for all cards.
+ * Bugfix of alloc_skb NULL pointer.
+ *
+ * Revision 1.8 1999/07/25 15:12:01 armin
+ * fix of some debug logs.
+ * enabled ISA-cards option.
+ *
+ * Revision 1.7 1999/07/11 17:16:23 armin
+ * Bugfixes in queue handling.
+ * Added DSP-DTMF decoder functions.
+ * Reorganized ack_handler.
+ *
+ * Revision 1.6 1999/06/09 19:31:24 armin
+ * Wrong PLX size for request_region() corrected.
+ * Added first MCA code from Erik Weber.
+ *
* Revision 1.5 1999/03/29 11:19:41 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
@@ -60,6 +87,7 @@
#define EICON_IOCTL_LOADPCI 7
#define EICON_IOCTL_LOADISA 8
#define EICON_IOCTL_GETVER 9
+#define EICON_IOCTL_GETXLOG 10
#define EICON_IOCTL_MANIF 90
@@ -89,6 +117,7 @@
#define MAX_HEADER_LEN 10
+
/* Struct for adding new cards */
typedef struct eicon_cdef {
int membase;
@@ -100,6 +129,7 @@ typedef struct eicon_cdef {
#define EICON_ISA_BOOT_NORMAL 2
/* Struct for downloading protocol via ioctl for ISA cards */
+/* same struct for downloading protocol via ioctl for MCA cards */
typedef struct {
/* start-up parameters */
unsigned char tei;
@@ -156,6 +186,7 @@ typedef struct {
/* Data for downloading protocol via ioctl */
typedef union {
eicon_isa_codebuf isa;
+ eicon_isa_codebuf mca;
eicon_pci_codebuf pci;
} eicon_codebuf;
@@ -171,6 +202,7 @@ typedef struct {
#ifdef __KERNEL__
/* Kernel includes */
+#include <linux/config.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/tqueue.h>
@@ -194,6 +226,8 @@ typedef struct {
#include <linux/isdnif.h>
+#include <linux/isdn_compat.h>
+
typedef struct {
__u16 length __attribute__ ((packed)); /* length of data/parameter field */
__u8 P[1]; /* data/parameter field */
@@ -209,6 +243,92 @@ typedef struct {
#endif /* KERNEL */
+#define DIVAS_SHARED_OFFSET (0x1000)
+
+#define MIPS_BUFFER_SZ 128
+#define MIPS_MAINT_OFFS 0xff00
+
+#define XLOG_ERR_CARD_NUM (13)
+#define XLOG_ERR_DONE (14)
+#define XLOG_ERR_CMD (15)
+#define XLOG_ERR_TIMEOUT (16)
+#define XLOG_ERR_CARD_STATE (17)
+#define XLOG_ERR_UNKNOWN (18)
+#define XLOG_OK (0)
+
+typedef struct {
+ __u8 Id __attribute__ ((packed));
+ __u8 uX __attribute__ ((packed));
+ __u8 listen __attribute__ ((packed));
+ __u8 active __attribute__ ((packed));
+ __u8 sin[3] __attribute__ ((packed));
+ __u8 bc[6] __attribute__ ((packed));
+ __u8 llc[6] __attribute__ ((packed));
+ __u8 hlc[6] __attribute__ ((packed));
+ __u8 oad[20] __attribute__ ((packed));
+}DSigStruc;
+
+typedef struct {
+ __u32 cx_b1 __attribute__ ((packed));
+ __u32 cx_b2 __attribute__ ((packed));
+ __u32 cr_b1 __attribute__ ((packed));
+ __u32 cr_b2 __attribute__ ((packed));
+ __u32 px_b1 __attribute__ ((packed));
+ __u32 px_b2 __attribute__ ((packed));
+ __u32 pr_b1 __attribute__ ((packed));
+ __u32 pr_b2 __attribute__ ((packed));
+ __u16 er_b1 __attribute__ ((packed));
+ __u16 er_b2 __attribute__ ((packed));
+}BL1Struc;
+
+typedef struct {
+ __u32 XTotal __attribute__ ((packed));
+ __u32 RTotal __attribute__ ((packed));
+ __u16 XError __attribute__ ((packed));
+ __u16 RError __attribute__ ((packed));
+}L2Struc;
+
+typedef struct {
+ __u16 free_n;
+}OSStruc;
+
+typedef union
+{
+ DSigStruc DSigStats;
+ BL1Struc BL1Stats;
+ L2Struc L2Stats;
+ OSStruc OSStats;
+ __u8 b[MIPS_BUFFER_SZ];
+ __u16 w[MIPS_BUFFER_SZ>>1];
+ __u16 l[MIPS_BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */
+ __u32 d[MIPS_BUFFER_SZ>>2];
+} MIPS_BUFFER;
+
+typedef struct
+{
+ __u8 req __attribute__ ((packed));
+ __u8 rc __attribute__ ((packed));
+ __u8 reserved[2] __attribute__ ((packed)); /* R3000 alignment ... */
+ __u8 *mem __attribute__ ((packed));
+ __u16 length __attribute__ ((packed)); /* used to be short */
+ __u16 port __attribute__ ((packed));
+ __u8 fill[4] __attribute__ ((packed)); /* data at offset 16 */
+ MIPS_BUFFER data __attribute__ ((packed));
+} mi_pc_maint_t;
+
+typedef struct
+{
+ __u16 command;
+ mi_pc_maint_t pcm;
+}xlogreq_t;
+
+typedef struct{
+ __u16 code __attribute__ ((packed)); /* used to be short */
+ __u16 timeh __attribute__ ((packed));
+ __u16 timel __attribute__ ((packed));
+ char buffer[MIPS_BUFFER_SZ - 6];
+}xlog_entry_t;
+
#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48
#define DSP_COMBIFILE_FORMAT_VERSION_BCD 0x0100
@@ -333,19 +453,39 @@ typedef struct {
__u16 ref; /* saved reference */
} entity;
+#define FAX_MAX_SCANLINE 256
+
+typedef struct {
+ __u8 PrevObject;
+ __u8 NextObject;
+ __u8 abLine[FAX_MAX_SCANLINE];
+ __u8 abFrame[FAX_MAX_SCANLINE];
+ unsigned int LineLen;
+ unsigned int LineDataLen;
+ __u32 LineData;
+ unsigned int NullBytesPos;
+ __u8 NullByteExist;
+ int PageCount;
+ __u8 Dle;
+ __u8 Eop;
+} eicon_ch_fax_buf;
typedef struct {
int No; /* Channel Number */
unsigned short callref; /* Call Reference */
unsigned short fsm_state; /* Current D-Channel state */
unsigned short eazmask; /* EAZ-Mask for this Channel */
- unsigned int queued; /* User-Data Bytes in TX queue */
- unsigned int waitq; /* User-Data Bytes in wait queue */
- unsigned int waitpq; /* User-Data Bytes in packet queue */
+ int queued; /* User-Data Bytes in TX queue */
+ int waitq; /* User-Data Bytes in wait queue */
+ int waitpq; /* User-Data Bytes in packet queue */
unsigned short plci;
unsigned short ncci;
unsigned char l2prot; /* Layer 2 protocol */
unsigned char l3prot; /* Layer 3 protocol */
+#ifdef CONFIG_ISDN_TTY_FAX
+ T30_s *fax; /* pointer to fax data in LL */
+ eicon_ch_fax_buf fax2; /* fax related struct */
+#endif
entity e; /* Entity */
char cpn[32]; /* remember cpn */
char oad[32]; /* remember oad */
@@ -392,14 +532,10 @@ typedef struct {
#define EICON_LOCK_TX 0
#define EICON_LOCK_RX 1
-typedef struct {
- int dummy;
-} eicon_mca_card;
-
typedef union {
eicon_isa_card isa;
eicon_pci_card pci;
- eicon_mca_card mca;
+ eicon_isa_card mca;
} eicon_hwif;
typedef struct {
@@ -465,6 +601,9 @@ typedef struct eicon_card {
char *status_buf_end;
isdn_if interface; /* Interface to upper layer */
char regname[35]; /* Name used for request_region */
+#ifdef CONFIG_MCA
+ int mca_slot; /* # of cards MCA slot */
+#endif
} eicon_card;
/* -----------------------------------------------------------**
@@ -521,6 +660,13 @@ extern void eicon_io_transmit(eicon_card *card);
extern void eicon_irq(int irq, void *dev_id, struct pt_regs *regs);
extern void eicon_io_rcv_dispatch(eicon_card *ccard);
extern void eicon_io_ack_dispatch(eicon_card *ccard);
+extern int eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq);
+#ifdef CONFIG_MCA
+extern int eicon_mca_find_card(int, int, int, char *);
+extern int eicon_mca_probe(int, int, int, int, char *);
+extern int eicon_info(char *, int , void *);
+#endif /* CONFIG_MCA */
+
extern ulong DebugVar;
#endif /* __KERNEL__ */
diff --git a/drivers/isdn/eicon/eicon_dsp.h b/drivers/isdn/eicon/eicon_dsp.h
index 94a4595c8..9ffbd9bdb 100644
--- a/drivers/isdn/eicon/eicon_dsp.h
+++ b/drivers/isdn/eicon/eicon_dsp.h
@@ -1,4 +1,4 @@
-/* $Id: eicon_dsp.h,v 1.2 1999/03/29 11:19:42 armin Exp $
+/* $Id: eicon_dsp.h,v 1.4 1999/07/25 15:12:02 armin Exp $
*
* ISDN lowlevel-module for Eicon.Diehl active cards.
* DSP definitions
@@ -21,6 +21,15 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_dsp.h,v $
+ * Revision 1.4 1999/07/25 15:12:02 armin
+ * fix of some debug logs.
+ * enabled ISA-cards option.
+ *
+ * Revision 1.3 1999/07/11 17:16:24 armin
+ * Bugfixes in queue handling.
+ * Added DSP-DTMF decoder functions.
+ * Reorganized ack_handler.
+ *
* Revision 1.2 1999/03/29 11:19:42 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
@@ -31,7 +40,7 @@
*
*/
-#ifndef DSP_H
+#ifndef DSP_H
#define DSP_H
#define DSP_UDATA_REQUEST_RECONFIGURE 0
@@ -264,6 +273,10 @@ parameters:
<word> tone duration (ms)
<word> gap duration (ms)
*/
+typedef struct enable_dtmf_s {
+ __u16 tone;
+ __u16 gap;
+} enable_dtmf_s;
#define DSP_UDATA_REQUEST_DISABLE_DTMF_RECEIVER 18
/*
@@ -300,5 +313,107 @@ returns:
- none -
*/
+/* ============= FAX ================ */
+
+#define EICON_FAXID_LEN 20
+
+typedef struct eicon_t30_s {
+ __u8 code;
+ __u8 rate;
+ __u8 resolution;
+ __u8 format;
+ __u8 pages_low;
+ __u8 pages_high;
+ __u8 atf;
+ __u8 control_bits_low;
+ __u8 control_bits_high;
+ __u8 feature_bits_low;
+ __u8 feature_bits_high;
+ __u8 universal_5;
+ __u8 universal_6;
+ __u8 universal_7;
+ __u8 station_id_len;
+ __u8 head_line_len;
+ __u8 station_id[EICON_FAXID_LEN];
+/* __u8 head_line[]; */
+} eicon_t30_s;
+
+ /* EDATA transmit messages */
+#define EDATA_T30_DIS 0x01
+#define EDATA_T30_FTT 0x02
+#define EDATA_T30_MCF 0x03
+
+ /* EDATA receive messages */
+#define EDATA_T30_DCS 0x81
+#define EDATA_T30_TRAIN_OK 0x82
+#define EDATA_T30_EOP 0x83
+#define EDATA_T30_MPS 0x84
+#define EDATA_T30_EOM 0x85
+#define EDATA_T30_DTC 0x86
+
+#define T30_FORMAT_SFF 0
+#define T30_FORMAT_ASCII 1
+#define T30_FORMAT_COUNT 2
+
+#define T30_CONTROL_BIT_DISABLE_FINE 0x0001
+#define T30_CONTROL_BIT_ENABLE_ECM 0x0002
+#define T30_CONTROL_BIT_ECM_64_BYTES 0x0004
+#define T30_CONTROL_BIT_ENABLE_2D_CODING 0x0008
+#define T30_CONTROL_BIT_ENABLE_T6_CODING 0x0010
+#define T30_CONTROL_BIT_ENABLE_UNCOMPR 0x0020
+#define T30_CONTROL_BIT_ACCEPT_POLLING 0x0040
+#define T30_CONTROL_BIT_REQUEST_POLLING 0x0080
+#define T30_CONTROL_BIT_MORE_DOCUMENTS 0x0100
+
+#define T30_CONTROL_BIT_ALL_FEATURES\
+ (T30_CONTROL_BIT_ENABLE_ECM | T30_CONTROL_BIT_ENABLE_2D_CODING |\
+ T30_CONTROL_BIT_ENABLE_T6_CODING | T30_CONTROL_BIT_ENABLE_UNCOMPR)
+
+#define T30_FEATURE_BIT_FINE 0x0001
+#define T30_FEATURE_BIT_ECM 0x0002
+#define T30_FEATURE_BIT_ECM_64_BYTES 0x0004
+#define T30_FEATURE_BIT_2D_CODING 0x0008
+#define T30_FEATURE_BIT_T6_CODING 0x0010
+#define T30_FEATURE_BIT_UNCOMPR_ENABLED 0x0020
+#define T30_FEATURE_BIT_POLLING 0x0040
+
+#define FAX_OBJECT_DOCU 1
+#define FAX_OBJECT_PAGE 2
+#define FAX_OBJECT_LINE 3
+
+#define T4_EOL 0x800
+#define T4_EOL_BITSIZE 12
+#define T4_EOL_DWORD (T4_EOL << (32 - T4_EOL_BITSIZE))
+#define T4_EOL_MASK_DWORD ((__u32) -1 << (32 - T4_EOL_BITSIZE))
+
+#define SFF_LEN_FLD_SIZE 3
+
+#define _DLE_ 0x10
+#define _ETX_ 0x03
+
+typedef struct eicon_sff_dochead {
+ __u32 id __attribute__ ((packed));
+ __u8 version __attribute__ ((packed));
+ __u8 reserved1 __attribute__ ((packed));
+ __u16 userinfo __attribute__ ((packed));
+ __u16 pagecount __attribute__ ((packed));
+ __u16 off1pagehead __attribute__ ((packed));
+ __u32 offnpagehead __attribute__ ((packed));
+ __u32 offdocend __attribute__ ((packed));
+} eicon_sff_dochead;
+
+typedef struct eicon_sff_pagehead {
+ __u8 pageheadid __attribute__ ((packed));
+ __u8 pageheadlen __attribute__ ((packed));
+ __u8 resvert __attribute__ ((packed));
+ __u8 reshoriz __attribute__ ((packed));
+ __u8 coding __attribute__ ((packed));
+ __u8 reserved2 __attribute__ ((packed));
+ __u16 linelength __attribute__ ((packed));
+ __u16 pagelength __attribute__ ((packed));
+ __u32 offprevpage __attribute__ ((packed));
+ __u32 offnextpage __attribute__ ((packed));
+} eicon_sff_pagehead;
+
#endif /* DSP_H */
diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c
index a28f316c1..af9c30483 100644
--- a/drivers/isdn/eicon/eicon_idi.c
+++ b/drivers/isdn/eicon/eicon_idi.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.c,v 1.9 1999/03/29 11:19:42 armin Exp $
+/* $Id: eicon_idi.c,v 1.15 1999/08/28 21:32:50 armin Exp $
*
* ISDN lowlevel-module for Eicon.Diehl active cards.
* IDI interface
@@ -21,6 +21,33 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_idi.c,v $
+ * Revision 1.15 1999/08/28 21:32:50 armin
+ * Prepared for fax related functions.
+ * Now compilable without errors/warnings.
+ *
+ * Revision 1.14 1999/08/28 20:24:40 armin
+ * Corrected octet 3/3a in CPN/OAD information element.
+ * Thanks to John Simpson <xfl23@dial.pipex.com>
+ *
+ * Revision 1.13 1999/08/22 20:26:44 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.12 1999/08/18 20:16:59 armin
+ * Added XLOG function for all cards.
+ * Bugfix of alloc_skb NULL pointer.
+ *
+ * Revision 1.11 1999/07/25 15:12:03 armin
+ * fix of some debug logs.
+ * enabled ISA-cards option.
+ *
+ * Revision 1.10 1999/07/11 17:16:24 armin
+ * Bugfixes in queue handling.
+ * Added DSP-DTMF decoder functions.
+ * Reorganized ack_handler.
+ *
* Revision 1.9 1999/03/29 11:19:42 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
@@ -61,6 +88,7 @@
*
*/
+#include <linux/config.h>
#define __NO_VERSION__
#include "eicon.h"
#include "eicon_idi.h"
@@ -68,7 +96,7 @@
#undef EICON_FULL_SERVICE_OKTETT
-char *eicon_idi_revision = "$Revision: 1.9 $";
+char *eicon_idi_revision = "$Revision: 1.15 $";
eicon_manifbuf *manbuf;
@@ -86,11 +114,15 @@ static char HLC_faxg3[2] = { 0x91, 0x84 };
int eicon_idi_manage_assign(eicon_card *card);
int eicon_idi_manage_remove(eicon_card *card);
+int idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer);
int
idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan)
{
int l = 0;
+ int tmp;
+
+ tmp = 0;
if (!signet) {
/* Signal Layer */
reqbuf->XBuffer.P[l++] = CAI;
@@ -133,10 +165,25 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan)
case ISDN_PROTO_L2_MODEM:
reqbuf->XBuffer.P[l++] = 2;
break;
+ case ISDN_PROTO_L2_FAX:
+ if (chan->fsm_state == EICON_STATE_IWAIT)
+ reqbuf->XBuffer.P[l++] = 3; /* autoconnect on incoming */
+ else
+ reqbuf->XBuffer.P[l++] = 2;
+ break;
default:
reqbuf->XBuffer.P[l++] = 1;
}
switch(chan->l3prot) {
+ case ISDN_PROTO_L3_FAX:
+#ifdef CONFIG_ISDN_TTY_FAX
+ reqbuf->XBuffer.P[l++] = 6;
+ reqbuf->XBuffer.P[l++] = NLC;
+ tmp = idi_fill_in_T30(chan, &reqbuf->XBuffer.P[l+1]);
+ reqbuf->XBuffer.P[l++] = tmp;
+ l += tmp;
+ break;
+#endif
case ISDN_PROTO_L3_TRANS:
default:
reqbuf->XBuffer.P[l++] = 4;
@@ -210,6 +257,20 @@ idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan)
reqbuf->XBuffer.P[6] = 128;
reqbuf->XBuffer.P[7] = 0;
break;
+ case ISDN_PROTO_L2_FAX:
+ reqbuf->XBuffer.P[2] = 0x10;
+ reqbuf->XBuffer.P[3] = 0;
+ reqbuf->XBuffer.P[4] = 0;
+ reqbuf->XBuffer.P[5] = 0;
+ reqbuf->XBuffer.P[6] = 128;
+ reqbuf->XBuffer.P[7] = 0;
+ break;
+ case ISDN_PROTO_L2_TRANS:
+ switch(chan->l3prot) {
+ case ISDN_PROTO_L3_TRANSDSP:
+ reqbuf->XBuffer.P[2] = 22; /* DTMF, audio events on */
+ }
+ break;
}
reqbuf->XBuffer.P[8] = 0;
reqbuf->XBuffer.length = l;
@@ -232,7 +293,11 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer)
if ((!skb) || (!skb2)) {
if (DebugVar & 1)
- printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed\n", chan->No);
+ printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in do_req()\n", chan->No);
+ if (skb)
+ dev_kfree_skb(skb);
+ if (skb2)
+ dev_kfree_skb(skb2);
return -ENOMEM;
}
@@ -241,7 +306,7 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer)
reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ));
if (DebugVar & 8)
- printk(KERN_DEBUG "idi_req: Ch%d: 0x%02x (%s)\n", chan->No, cmd, (layer)?"Net":"Sig");
+ printk(KERN_DEBUG "idi_req: Ch%d: req %x (%s)\n", chan->No, cmd, (layer)?"Net":"Sig");
if (layer) cmd |= 0x700;
switch(cmd) {
case ASSIGN:
@@ -282,6 +347,8 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer)
default:
if (DebugVar & 1)
printk(KERN_ERR "idi_req: Ch%d: Unknown request\n", chan->No);
+ dev_kfree_skb(skb);
+ dev_kfree_skb(skb2);
return(-1);
}
@@ -358,6 +425,9 @@ idi_hangup(eicon_card *card, eicon_chan *chan)
chan->fsm_state = EICON_STATE_NULL;
if (DebugVar & 8)
printk(KERN_DEBUG"idi_req: Ch%d: Hangup\n", chan->No);
+#ifdef CONFIG_ISDN_TTY_FAX
+ chan->fax = 0;
+#endif
return(0);
}
@@ -389,7 +459,11 @@ idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
if ((!skb) || (!skb2)) {
if (DebugVar & 1)
- printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed\n", chan->No);
+ printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in connect_req()\n", chan->No);
+ if (skb)
+ dev_kfree_skb(skb);
+ if (skb2)
+ dev_kfree_skb(skb2);
return -ENOMEM;
}
@@ -403,14 +477,14 @@ idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
reqbuf->XBuffer.P[l++] = CPN;
reqbuf->XBuffer.P[l++] = strlen(phone) + 1;
- reqbuf->XBuffer.P[l++] = 0xc1;
+ reqbuf->XBuffer.P[l++] = 0x81;
for(i=0; i<strlen(phone);i++)
reqbuf->XBuffer.P[l++] = phone[i];
reqbuf->XBuffer.P[l++] = OAD;
reqbuf->XBuffer.P[l++] = strlen(eazmsn) + 2;
reqbuf->XBuffer.P[l++] = 0x01;
- reqbuf->XBuffer.P[l++] = 0x81;
+ reqbuf->XBuffer.P[l++] = 0x80;
for(i=0; i<strlen(eazmsn);i++)
reqbuf->XBuffer.P[l++] = eazmsn[i];
@@ -472,6 +546,20 @@ idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
reqbuf->XBuffer.P[l-2] = 128;
reqbuf->XBuffer.P[l-1] = 0;
break;
+ case ISDN_PROTO_L2_FAX:
+ reqbuf->XBuffer.P[l-6] = 0x10;
+ reqbuf->XBuffer.P[l-5] = 0;
+ reqbuf->XBuffer.P[l-4] = 0;
+ reqbuf->XBuffer.P[l-3] = 0;
+ reqbuf->XBuffer.P[l-2] = 128;
+ reqbuf->XBuffer.P[l-1] = 0;
+ break;
+ case ISDN_PROTO_L2_TRANS:
+ switch(chan->l3prot) {
+ case ISDN_PROTO_L3_TRANSDSP:
+ reqbuf->XBuffer.P[l-6] = 22; /* DTMF, audio events on */
+ }
+ break;
}
reqbuf->XBuffer.P[l++] = 0; /* end */
@@ -813,6 +901,195 @@ idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *si1, unsigned ch
}
}
+/********************* FAX stuff ***************************/
+
+#ifdef CONFIG_ISDN_TTY_FAX
+
+int
+idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer)
+{
+
+ /* TODO , code follows */
+
+ return(0);
+}
+
+/* send fax struct */
+int
+idi_send_edata(eicon_card *card, eicon_chan *chan)
+{
+
+ /* TODO , code follows */
+
+ return (0);
+}
+
+void
+idi_parse_edata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int len)
+{
+
+ /* TODO , code follows */
+
+}
+
+void
+idi_fax_send_header(eicon_card *card, eicon_chan *chan, int header)
+{
+
+ /* TODO , code follows */
+
+}
+
+void
+idi_fax_cmd(eicon_card *card, eicon_chan *chan)
+{
+
+ /* TODO , code follows */
+
+}
+
+void
+idi_edata_rcveop(eicon_card *card, eicon_chan *chan)
+{
+
+ /* TODO , code follows */
+
+}
+
+void
+idi_reset_fax_stat(eicon_chan *chan)
+{
+
+ /* TODO , code follows */
+
+}
+
+void
+idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len)
+{
+
+ /* TODO , code follows */
+
+}
+
+void
+fax_put_rcv(eicon_card *ccard, eicon_chan *chan, u_char *Data, int len)
+{
+
+ /* TODO , code follows */
+
+}
+
+void
+idi_faxdata_rcv(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb)
+{
+
+ /* TODO , code follows */
+
+}
+
+int
+idi_fax_send_outbuf(eicon_card *ccard, eicon_chan *chan, eicon_OBJBUFFER *OutBuf)
+{
+
+ /* TODO , code follows */
+
+ return(0);
+}
+
+int
+idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb)
+{
+
+ /* TODO , code follows */
+
+ return(0);
+}
+
+void
+idi_fax_hangup(eicon_card *ccard, eicon_chan *chan)
+{
+
+ /* TODO , code follows */
+
+}
+
+#endif /******** FAX ********/
+
+int
+idi_send_udata(eicon_card *card, eicon_chan *chan, int UReq, u_char *buffer, int len)
+{
+ struct sk_buff *skb;
+ struct sk_buff *skb2;
+ eicon_REQ *reqbuf;
+ eicon_chan_ptr *chan2;
+
+ if ((chan->fsm_state == EICON_STATE_NULL) || (chan->fsm_state == EICON_STATE_LISTEN)) {
+ if (DebugVar & 1)
+ printk(KERN_DEBUG"idi_snd: Ch%d: send udata on state %d !\n", chan->No, chan->fsm_state);
+ return -ENODEV;
+ }
+ if (DebugVar & 8)
+ printk(KERN_DEBUG"idi_snd: Ch%d: udata 0x%x: %d %d %d %d\n", chan->No,
+ UReq, buffer[0], buffer[1], buffer[2], buffer[3]);
+
+ skb = alloc_skb(sizeof(eicon_REQ) + len + 1, GFP_ATOMIC);
+ skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
+
+ if ((!skb) || (!skb2)) {
+ if (DebugVar & 1)
+ printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in send_udata()\n", chan->No);
+ if (skb)
+ dev_kfree_skb(skb);
+ if (skb2)
+ dev_kfree_skb(skb2);
+ return -ENOMEM;
+ }
+
+ chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
+ chan2->ptr = chan;
+
+ reqbuf = (eicon_REQ *)skb_put(skb, 1 + len + sizeof(eicon_REQ));
+
+ reqbuf->Req = IDI_N_UDATA;
+ reqbuf->ReqCh = 0;
+ reqbuf->ReqId = 1;
+
+ reqbuf->XBuffer.length = len + 1;
+ reqbuf->XBuffer.P[0] = UReq;
+ memcpy(&reqbuf->XBuffer.P[1], buffer, len);
+ reqbuf->Reference = 1; /* Net Entity */
+
+ skb_queue_tail(&chan->e.X, skb);
+ skb_queue_tail(&card->sndq, skb2);
+ eicon_schedule_tx(card);
+ return (0);
+}
+
+void
+idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value)
+{
+ u_char buf[6];
+ struct enable_dtmf_s *dtmf_buf = (struct enable_dtmf_s *)buf;
+
+ memset(buf, 0, 6);
+ switch(cmd) {
+ case ISDN_AUDIO_SETDD:
+ if (value[0]) {
+ dtmf_buf->tone = (__u16) (value[1] * 5);
+ dtmf_buf->gap = (__u16) (value[1] * 5);
+ idi_send_udata(ccard, chan,
+ DSP_UDATA_REQUEST_ENABLE_DTMF_RECEIVER,
+ buf, 4);
+ } else {
+ idi_send_udata(ccard, chan,
+ DSP_UDATA_REQUEST_DISABLE_DTMF_RECEIVER,
+ buf, 0);
+ }
+ break;
+ }
+}
+
void
idi_parse_udata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int len)
{
@@ -822,6 +1099,9 @@ idi_parse_udata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int
{"", "V.21", "V.23", "V.22", "V.22bis", "V.32bis", "V.34",
"V.8", "Bell 212A", "Bell 103", "V.29 Leased", "V.33 Leased", "V.90",
"V.21 CH2", "V.27ter", "V.29", "V.33", "V.17"};
+ static u_char dtmf_code[] = {
+ '1','4','7','*','2','5','8','0','3','6','9','#','A','B','C','D'
+ };
switch (buffer[0]) {
case DSP_UDATA_INDICATION_SYNC:
@@ -863,6 +1143,17 @@ idi_parse_udata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int
if (DebugVar & 8)
printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DISCONNECT cause %d\n", chan->No, buffer[1]);
break;
+ case DSP_UDATA_INDICATION_DTMF_DIGITS_RECEIVED:
+ if (DebugVar & 8)
+ printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DTMF_REC '%c'\n", chan->No,
+ dtmf_code[buffer[1]]);
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_AUDIO;
+ cmd.parm.num[0] = ISDN_AUDIO_DTMF;
+ cmd.parm.num[1] = dtmf_code[buffer[1]];
+ cmd.arg = chan->No;
+ ccard->interface.statcallb(&cmd);
+ break;
default:
if (DebugVar & 8)
printk(KERN_WARNING "idi_ind: Ch%d: UNHANDLED UDATA Indication 0x%02x\n", chan->No, buffer[0]);
@@ -887,7 +1178,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
if ((DebugVar & 128) ||
((DebugVar & 16) && (ind->Ind != 8))) {
- printk(KERN_DEBUG "idi_hdl: Ch%d: Ind=%d Id=%d Ch=%d MInd=%d MLen=%d Len=%d\n", chan->No,
+ printk(KERN_DEBUG "idi_hdl: Ch%d: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", chan->No,
ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
}
@@ -921,6 +1212,10 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
cmd.command = ISDN_STAT_DHUP;
ccard->interface.statcallb(&cmd);
eicon_idi_listen_req(ccard, chan);
+#ifdef CONFIG_ISDN_TTY_FAX
+ if (!chan->e.B2Id)
+ chan->fax = 0;
+#endif
break;
case INDICATE_IND:
if (DebugVar & 8)
@@ -994,9 +1289,17 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
cmd.command = ISDN_STAT_DCONN;
cmd.arg = chan->No;
ccard->interface.statcallb(&cmd);
- idi_do_req(ccard, chan, IDI_N_CONNECT, 1);
+ if (chan->l2prot != ISDN_PROTO_L2_FAX) {
+ idi_do_req(ccard, chan, IDI_N_CONNECT, 1);
+ }
+#ifdef CONFIG_ISDN_TTY_FAX
+ else {
+ if (chan->fax)
+ chan->fax->phase = ISDN_FAX_PHASE_A;
+ }
+#endif
} else
- idi_hangup(ccard, chan);
+ idi_hangup(ccard, chan);
break;
case CALL_CON:
if (DebugVar & 8)
@@ -1009,6 +1312,12 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
ccard->interface.statcallb(&cmd);
idi_do_req(ccard, chan, ASSIGN, 1);
idi_do_req(ccard, chan, IDI_N_CONNECT, 1);
+#ifdef CONFIG_ISDN_TTY_FAX
+ if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+ if (chan->fax)
+ chan->fax->phase = ISDN_FAX_PHASE_A;
+ }
+#endif
} else
idi_hangup(ccard, chan);
break;
@@ -1038,6 +1347,27 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
chan->fsm_state = EICON_STATE_WMCONN;
break;
}
+ if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+#ifdef CONFIG_ISDN_TTY_FAX
+ chan->fsm_state = EICON_STATE_ACTIVE;
+ idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
+ if (chan->fax) {
+ if (chan->fax->phase == ISDN_FAX_PHASE_B) {
+ idi_fax_send_header(ccard, chan, 2);
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_FAXIND;
+ cmd.arg = chan->No;
+ chan->fax->r_code = ISDN_TTY_FAX_DCS;
+ ccard->interface.statcallb(&cmd);
+ }
+ }
+ else {
+ if (DebugVar & 1)
+ printk(KERN_DEBUG "idi_ind: N_CONNECT_ACK with NULL fax struct, ERROR\n");
+ }
+#endif
+ break;
+ }
chan->fsm_state = EICON_STATE_ACTIVE;
cmd.driver = ccard->myid;
cmd.command = ISDN_STAT_BCONN;
@@ -1048,6 +1378,9 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
if (DebugVar & 16)
printk(KERN_DEBUG"idi_ind: Ch%d: N_Connect\n", chan->No);
if (chan->e.B2Id) idi_do_req(ccard, chan, IDI_N_CONNECT_ACK, 1);
+ if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+ break;
+ }
if (chan->l2prot == ISDN_PROTO_L2_MODEM) {
chan->fsm_state = EICON_STATE_WMCONN;
break;
@@ -1065,19 +1398,35 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
idi_do_req(ccard, chan, IDI_N_DISC_ACK, 1);
idi_do_req(ccard, chan, REMOVE, 1);
}
+#ifdef CONFIG_ISDN_TTY_FAX
+ if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+ idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
+ idi_fax_hangup(ccard, chan);
+ }
+#endif
chan->queued = 0;
chan->waitq = 0;
chan->waitpq = 0;
+ idi_do_req(ccard, chan, HANGUP, 0);
if (chan->fsm_state == EICON_STATE_ACTIVE) {
cmd.driver = ccard->myid;
cmd.command = ISDN_STAT_BHUP;
cmd.arg = chan->No;
ccard->interface.statcallb(&cmd);
}
+#ifdef CONFIG_ISDN_TTY_FAX
+ chan->fax = 0;
+#endif
break;
case IDI_N_DISC_ACK:
if (DebugVar & 16)
printk(KERN_DEBUG"idi_ind: Ch%d: N_DISC_ACK\n", chan->No);
+#ifdef CONFIG_ISDN_TTY_FAX
+ if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+ idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
+ idi_fax_hangup(ccard, chan);
+ }
+#endif
break;
case IDI_N_DATA_ACK:
if (DebugVar & 16)
@@ -1087,12 +1436,23 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
skb_pull(skb, sizeof(eicon_IND) - 1);
if (DebugVar & 128)
printk(KERN_DEBUG"idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len);
- ccard->interface.rcvcallb_skb(ccard->myid, chan->No, skb);
- free_buff = 0;
+ if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+#ifdef CONFIG_ISDN_TTY_FAX
+ idi_faxdata_rcv(ccard, chan, skb);
+#endif
+ } else {
+ ccard->interface.rcvcallb_skb(ccard->myid, chan->No, skb);
+ free_buff = 0;
+ }
break;
case IDI_N_UDATA:
idi_parse_udata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
break;
+#ifdef CONFIG_ISDN_TTY_FAX
+ case IDI_N_EDATA:
+ idi_edata_action(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
+ break;
+#endif
default:
if (DebugVar & 8)
printk(KERN_WARNING "idi_ind: Ch%d: UNHANDLED NetIndication 0x%02x\n", chan->No, ind->Ind);
@@ -1105,90 +1465,138 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
if (free_buff) dev_kfree_skb(skb);
}
-void
-idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
+int
+idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack)
{
- int j;
- eicon_RC *ack = (eicon_RC *)skb->data;
- eicon_chan *chan;
isdn_ctrl cmd;
- if ((ack->Rc != ASSIGN_OK) && (ack->Rc != OK)) {
- if ((chan = ccard->IdTable[ack->RcId]) != NULL) {
- chan->e.busy = 0;
- if (DebugVar & 24)
- printk(KERN_ERR "eicon_ack: Ch%d: Not OK: Rc=%d Id=%d Ch=%d\n", chan->No,
- ack->Rc, ack->RcId, ack->RcCh);
- if (chan->No == ccard->nchannels) { /* Management */
- chan->fsm_state = 2;
- } else { /* any other channel */
- /* card reports error: we hangup */
- idi_hangup(ccard, chan);
- cmd.driver = ccard->myid;
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = chan->No;
- ccard->interface.statcallb(&cmd);
- }
+ if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) {
+ /* I dont know why this happens, just ignoring this RC */
+ if (DebugVar & 16)
+ printk(KERN_DEBUG "idi_ack: Ch%d: RcId %d not equal to last %d\n", chan->No,
+ ack->RcId, (chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id);
+ return 1;
+ }
+
+ /* Management Interface */
+ if (chan->No == ccard->nchannels) {
+ /* Managementinterface: changing state */
+ if (chan->e.Req == 0x04)
+ chan->fsm_state = 1;
+ }
+
+ /* Remove an Id */
+ if (chan->e.Req == REMOVE) {
+ if (ack->Reference != chan->e.ref) {
+ if (DebugVar & 16)
+ printk(KERN_DEBUG "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No,
+ ack->Reference, chan->e.ref);
+ return 0;
}
- }
- else {
- if ((chan = ccard->IdTable[ack->RcId]) != NULL) {
- if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) {
- if (DebugVar & 16)
- printk(KERN_DEBUG "idi_ack: Ch%d: RcId %d not equal to last %d\n", chan->No,
- ack->RcId, (chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id);
- } else {
- if (chan->No == ccard->nchannels) { /* Management */
- if (chan->e.Req == 0x04) chan->fsm_state = 1;
- }
- if (chan->e.ReqCh) {
- switch(chan->e.Req & 0x0f) {
- case IDI_N_MDATA:
- case IDI_N_DATA:
- chan->queued -= chan->waitq;
- if (chan->queued < 0) chan->queued = 0;
- if ((chan->e.Req & 0x0f) == IDI_N_DATA) {
+ ccard->IdTable[ack->RcId] = NULL;
+ if (DebugVar & 16)
+ printk(KERN_DEBUG "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No,
+ ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig");
+ if (!chan->e.ReqCh)
+ chan->e.D3Id = 0;
+ else
+ chan->e.B2Id = 0;
+ return 1;
+ }
+
+ /* Signal layer */
+ if (!chan->e.ReqCh) {
+ if (DebugVar & 16)
+ printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
+ ack->RcId, ack->RcCh, ack->Reference);
+ } else {
+ /* Network layer */
+ switch(chan->e.Req & 0x0f) {
+ case IDI_N_MDATA:
+ case IDI_N_DATA:
+ if ((chan->e.Req & 0x0f) == IDI_N_DATA) {
+ if (chan->queued) {
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_BSENT;
+ cmd.arg = chan->No;
+ cmd.parm.length = chan->waitpq;
+ ccard->interface.statcallb(&cmd);
+ }
+ chan->waitpq = 0;
+#ifdef CONFIG_ISDN_TTY_FAX
+ if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+ if (((chan->queued - chan->waitq) < 1) &&
+ (chan->fax2.Eop)) {
+ chan->fax2.Eop = 0;
+ if (chan->fax) {
cmd.driver = ccard->myid;
- cmd.command = ISDN_STAT_BSENT;
+ cmd.command = ISDN_STAT_FAXIND;
cmd.arg = chan->No;
- cmd.parm.length = chan->waitpq;
- chan->waitpq = 0;
+ chan->fax->r_code = ISDN_TTY_FAX_SENT;
ccard->interface.statcallb(&cmd);
}
- break;
- default:
- if (DebugVar & 16)
- printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%d Ch=%d (ref:%d)\n", chan->No,
- ack->RcId, ack->RcCh, ack->Reference);
+ else {
+ if (DebugVar & 1)
+ printk(KERN_DEBUG "idi_ack: Sent with NULL fax struct, ERROR\n");
+ }
+ }
}
- }
- else {
- if (DebugVar & 16)
- printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%d Ch=%d (ref:%d)\n", chan->No,
- ack->RcId, ack->RcCh, ack->Reference);
+#endif
}
+ chan->queued -= chan->waitq;
+ if (chan->queued < 0) chan->queued = 0;
+ break;
+ default:
+ if (DebugVar & 16)
+ printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
+ ack->RcId, ack->RcCh, ack->Reference);
+ }
+ }
+ return 1;
+}
- if (chan->e.Req == REMOVE) {
- if (ack->Reference == chan->e.ref) {
- ccard->IdTable[ack->RcId] = NULL;
- if (DebugVar & 16)
- printk(KERN_DEBUG "idi_ack: Ch%d: Removed : Id=%d Ch=%d (%s)\n", chan->No,
- ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig");
- if (!chan->e.ReqCh)
- chan->e.D3Id = 0;
- else
- chan->e.B2Id = 0;
- }
- else {
- if (DebugVar & 16)
- printk(KERN_DEBUG "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No,
- ack->Reference, chan->e.ref);
- }
- }
- chan->e.busy = 0;
+void
+idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
+{
+ int j;
+ eicon_RC *ack = (eicon_RC *)skb->data;
+ eicon_chan *chan;
+ isdn_ctrl cmd;
+ int dCh = -1;
+
+ if ((chan = ccard->IdTable[ack->RcId]) != NULL)
+ dCh = chan->No;
+
+
+ switch (ack->Rc) {
+ case OK_FC:
+ case N_FLOW_CONTROL:
+ case ASSIGN_RC:
+ if (DebugVar & 1)
+ printk(KERN_ERR "idi_ack: Ch%d: unhandled RC 0x%x\n",
+ dCh, ack->Rc);
+ break;
+ case READY_INT:
+ case TIMER_INT:
+ /* we do nothing here */
+ break;
+
+ case OK:
+ if (!chan) {
+ if (DebugVar & 1)
+ printk(KERN_ERR "idi_ack: Ch%d: OK on chan without Id\n", dCh);
+ break;
+ }
+ if (!idi_handle_ack_ok(ccard, chan, ack))
+ chan = NULL;
+ break;
+
+ case ASSIGN_OK:
+ if (chan) {
+ if (DebugVar & 1)
+ printk(KERN_ERR "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%x,%x)\n",
+ chan->No, chan->e.D3Id, chan->e.B2Id);
}
- }
- else {
for(j = 0; j < ccard->nchannels + 1; j++) {
if (ccard->bch[j].e.ref == ack->Reference) {
if (!ccard->bch[j].e.ReqCh)
@@ -1199,7 +1607,7 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
ccard->bch[j].e.busy = 0;
ccard->bch[j].e.ref = 0;
if (DebugVar & 16)
- printk(KERN_DEBUG"idi_ack: Ch%d: Id %d assigned (%s)\n", j,
+ printk(KERN_DEBUG"idi_ack: Ch%d: Id %x assigned (%s)\n", j,
ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig");
break;
}
@@ -1209,14 +1617,39 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
printk(KERN_DEBUG"idi_ack: Ch??: ref %d not found for Id %d\n",
ack->Reference, ack->RcId);
}
- }
+ break;
+
+ case OUT_OF_RESOURCES:
+ case UNKNOWN_COMMAND:
+ case WRONG_COMMAND:
+ case WRONG_ID:
+ case WRONG_CH:
+ case UNKNOWN_IE:
+ case WRONG_IE:
+ default:
+ if (DebugVar & 1)
+ printk(KERN_ERR "eicon_ack: Ch%d: Not OK !!: Rc=%d Id=%x Ch=%d\n", dCh,
+ ack->Rc, ack->RcId, ack->RcCh);
+ if (dCh == ccard->nchannels) { /* Management */
+ chan->fsm_state = 2;
+ } else if (dCh >= 0) {
+ /* any other channel */
+ /* card reports error: we hangup */
+ idi_hangup(ccard, chan);
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_DHUP;
+ cmd.arg = chan->No;
+ ccard->interface.statcallb(&cmd);
+ }
}
- dev_kfree_skb(skb);
- eicon_schedule_tx(ccard);
+ if (chan)
+ chan->e.busy = 0;
+ dev_kfree_skb(skb);
+ eicon_schedule_tx(ccard);
}
int
-idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb)
+idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que)
{
struct sk_buff *xmit_skb;
struct sk_buff *skb2;
@@ -1240,6 +1673,7 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb)
return 0;
if (DebugVar & 128)
printk(KERN_DEBUG"idi_snd: Ch%d: %d bytes\n", chan->No, len);
+
save_flags(flags);
cli();
while(offset < len) {
@@ -1249,10 +1683,14 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb)
xmit_skb = alloc_skb(plen + sizeof(eicon_REQ), GFP_ATOMIC);
skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
- if ((!skb) || (!skb2)) {
+ if ((!xmit_skb) || (!skb2)) {
restore_flags(flags);
if (DebugVar & 1)
- printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed\n", chan->No);
+ printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No);
+ if (xmit_skb)
+ dev_kfree_skb(skb);
+ if (skb2)
+ dev_kfree_skb(skb2);
return -ENOMEM;
}
@@ -1278,7 +1716,8 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb)
offset += plen;
}
- chan->queued += len;
+ if (que)
+ chan->queued += len;
restore_flags(flags);
eicon_schedule_tx(card);
dev_kfree_skb(skb);
@@ -1286,7 +1725,6 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb)
}
-
int
eicon_idi_manage_assign(eicon_card *card)
{
@@ -1303,7 +1741,11 @@ eicon_idi_manage_assign(eicon_card *card)
if ((!skb) || (!skb2)) {
if (DebugVar & 1)
- printk(KERN_WARNING "idi_err: alloc_skb failed\n");
+ printk(KERN_WARNING "idi_err: alloc_skb failed in manage_assign()\n");
+ if (skb)
+ dev_kfree_skb(skb);
+ if (skb2)
+ dev_kfree_skb(skb2);
return -ENOMEM;
}
@@ -1342,7 +1784,11 @@ eicon_idi_manage_remove(eicon_card *card)
if ((!skb) || (!skb2)) {
if (DebugVar & 1)
- printk(KERN_WARNING "idi_err: alloc_skb failed\n");
+ printk(KERN_WARNING "idi_err: alloc_skb failed in manage_remove()\n");
+ if (skb)
+ dev_kfree_skb(skb);
+ if (skb2)
+ dev_kfree_skb(skb2);
return -ENOMEM;
}
@@ -1379,7 +1825,8 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
chan = &(card->bch[card->nchannels]);
- if (chan->e.D3Id) return -EBUSY;
+ if (chan->e.D3Id)
+ return -EBUSY;
chan->e.D3Id = 1;
while((skb2 = skb_dequeue(&chan->e.X)))
dev_kfree_skb(skb2);
@@ -1409,6 +1856,7 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
return -ENOMEM;
}
if (copy_from_user(manbuf, mb, sizeof(eicon_manifbuf))) {
+ kfree(manbuf);
chan->e.D3Id = 0;
return -EFAULT;
}
@@ -1418,7 +1866,11 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
if ((!skb) || (!skb2)) {
if (DebugVar & 1)
- printk(KERN_WARNING "idi_err_manif: alloc_skb failed\n");
+ printk(KERN_WARNING "idi_err_manif: alloc_skb failed in manage()\n");
+ if (skb)
+ dev_kfree_skb(skb);
+ if (skb2)
+ dev_kfree_skb(skb2);
kfree(manbuf);
chan->e.D3Id = 0;
return -ENOMEM;
@@ -1464,11 +1916,13 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
}
if ((ret = eicon_idi_manage_remove(card))) {
+ kfree(manbuf);
chan->e.D3Id = 0;
return(ret);
}
if (copy_to_user(mb, manbuf, sizeof(eicon_manifbuf))) {
+ kfree(manbuf);
chan->e.D3Id = 0;
return -EFAULT;
}
diff --git a/drivers/isdn/eicon/eicon_idi.h b/drivers/isdn/eicon/eicon_idi.h
index a0605cdef..e09c1954d 100644
--- a/drivers/isdn/eicon/eicon_idi.h
+++ b/drivers/isdn/eicon/eicon_idi.h
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.h,v 1.4 1999/03/29 11:19:44 armin Exp $
+/* $Id: eicon_idi.h,v 1.7 1999/08/22 20:26:46 calle Exp $
*
* ISDN lowlevel-module for the Eicon.Diehl active cards.
* IDI-Interface
@@ -21,6 +21,21 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_idi.h,v $
+ * Revision 1.7 1999/08/22 20:26:46 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.6 1999/07/25 15:12:04 armin
+ * fix of some debug logs.
+ * enabled ISA-cards option.
+ *
+ * Revision 1.5 1999/07/11 17:16:26 armin
+ * Bugfixes in queue handling.
+ * Added DSP-DTMF decoder functions.
+ * Reorganized ack_handler.
+ *
* Revision 1.4 1999/03/29 11:19:44 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
@@ -45,6 +60,7 @@
#ifndef IDI_H
#define IDI_H
+#include <linux/config.h>
#define ASSIGN 0x01
#define REMOVE 0xff
@@ -232,6 +248,12 @@ typedef struct {
__u8 B[1]; /* buffer space for Req,Ind and Rc */
} eicon_pr_ram;
+typedef struct {
+ __u8 *Data;
+ unsigned int Size;
+ unsigned int Len;
+ __u8 *Next;
+} eicon_OBJBUFFER;
extern int idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer);
extern int idi_hangup(eicon_card *card, eicon_chan *chan);
@@ -243,6 +265,11 @@ extern int idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
extern void idi_handle_ack(eicon_card *card, struct sk_buff *skb);
extern void idi_handle_ind(eicon_card *card, struct sk_buff *skb);
extern int eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb);
-extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb);
+extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que);
+extern void idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value);
+#ifdef CONFIG_ISDN_TTY_FAX
+extern void idi_fax_cmd(eicon_card *card, eicon_chan *chan);
+extern int idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb);
+#endif
#endif
diff --git a/drivers/isdn/eicon/eicon_io.c b/drivers/isdn/eicon/eicon_io.c
index 1c69d37cd..60b5b4818 100644
--- a/drivers/isdn/eicon/eicon_io.c
+++ b/drivers/isdn/eicon/eicon_io.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_io.c,v 1.1 1999/03/29 11:19:45 armin Exp $
+/* $Id: eicon_io.c,v 1.4 1999/08/22 20:26:47 calle Exp $
*
* ISDN low-level module for Eicon.Diehl active ISDN-Cards.
* Code for communicating with hardware.
@@ -24,6 +24,20 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_io.c,v $
+ * Revision 1.4 1999/08/22 20:26:47 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.3 1999/08/18 20:17:01 armin
+ * Added XLOG function for all cards.
+ * Bugfix of alloc_skb NULL pointer.
+ *
+ * Revision 1.2 1999/07/25 15:12:05 armin
+ * fix of some debug logs.
+ * enabled ISA-cards option.
+ *
* Revision 1.1 1999/03/29 11:19:45 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
@@ -32,6 +46,7 @@
*/
+#include <linux/config.h>
#include "eicon.h"
void
@@ -56,8 +71,8 @@ eicon_io_rcv_dispatch(eicon_card *ccard) {
/* doesn't matter if this happens */
break;
default:
- printk(KERN_ERR "idi: Indication for unknown channel Ind=%d Id=%d\n", ind->Ind, ind->IndId);
- printk(KERN_DEBUG "idi_hdl: Ch??: Ind=%d Id=%d Ch=%d MInd=%d MLen=%d Len=%d\n",
+ printk(KERN_ERR "idi: Indication for unknown channel Ind=%d Id=%x\n", ind->Ind, ind->IndId);
+ printk(KERN_DEBUG "idi_hdl: Ch??: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
}
}
@@ -84,12 +99,18 @@ eicon_io_rcv_dispatch(eicon_card *ccard) {
if (DebugVar & 1)
printk(KERN_ERR "eicon: buffer incomplete, but 0 in queue\n");
dev_kfree_skb(skb);
- dev_kfree_skb(skb2);
continue;
}
ind2 = (eicon_IND *)skb2->data;
skb_new = alloc_skb(((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length),
GFP_ATOMIC);
+ if (!skb_new) {
+ if (DebugVar & 1)
+ printk(KERN_ERR "eicon_io: skb_alloc failed in rcv_dispatch()\n");
+ dev_kfree_skb(skb);
+ dev_kfree_skb(skb2);
+ continue;
+ }
ind_new = (eicon_IND *)skb_put(skb_new,
((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length));
ind_new->Ind = ind2->Ind;
@@ -272,6 +293,92 @@ void ram_copytocard(eicon_card *card, void *adrto, void *adr, int len) {
}
/*
+ * XLOG
+ */
+int
+eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq)
+{
+ int timeout, i;
+ int divas_shared_offset = 0;
+ int len = 0;
+ int stype = 0;
+ __u32 time = 0;
+ mi_pc_maint_t *pcm = &xlogreq->pcm;
+ eicon_pci_card *pci_card = &card->hwif.pci;
+ eicon_isa_card *isa_card = &card->hwif.isa;
+ eicon_pr_ram *prram = 0;
+ char *ram;
+
+ switch(card->type) {
+ case EICON_CTYPE_MAESTRAP:
+ ram = (char *)pci_card->PCIram;
+ prram = (eicon_pr_ram *)ram;
+ divas_shared_offset = DIVAS_SHARED_OFFSET;
+ len = sizeof(mi_pc_maint_t);
+ break;
+ case EICON_CTYPE_MAESTRA:
+ prram = 0;
+ divas_shared_offset = 0;
+ len = sizeof(mi_pc_maint_t);
+ break;
+ case EICON_CTYPE_S:
+ case EICON_CTYPE_SX:
+ case EICON_CTYPE_SCOM:
+ case EICON_CTYPE_QUADRO:
+ case EICON_CTYPE_S2M:
+ prram = (eicon_pr_ram *)isa_card->shmem;
+ divas_shared_offset = 0xfb80;
+ len = sizeof(mi_pc_maint_t) - 78;
+ stype = 1;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ memset(&(xlogreq->pcm), 0, sizeof(mi_pc_maint_t));
+
+ xlogreq->pcm.rc = 0;
+ xlogreq->pcm.req = 1; /* DO_LOG */
+
+ ram = ((char *)prram) + MIPS_MAINT_OFFS - divas_shared_offset;
+
+ ram_outb(card, ram+1, pcm->rc);
+ ram_outb(card, ram+0, pcm->req);
+
+ timeout = jiffies + 50;
+ while (timeout > jiffies) {
+ pcm->rc = ram_inb(card, ram+1);
+ pcm->req = ram_inb(card, ram+0);
+ if (!pcm->req) break;
+ SLEEP(10);
+ }
+
+ if (pcm->req) {
+ return XLOG_ERR_TIMEOUT;
+ }
+
+ if (pcm->rc != OK) {
+ return XLOG_ERR_DONE;
+ }
+
+ ram_copyfromcard(card, pcm, ram, len);
+
+ if (stype) {
+ for (i=0; i<8; i++)
+ ((__u8 *)pcm)[11-i] = ((__u8 *)pcm)[9-i];
+ time = (__u32)pcm->data.w[2] * 3600 * 1000 +
+ (__u32)pcm->data.w[1] * 1000 +
+ (__u32)pcm->data.b[1] * 20 +
+ (__u32)pcm->data.b[0] ;
+ pcm->data.w[1] = (__u16) (time >> 16);
+ pcm->data.w[2] = (__u16) (time & 0x0000ffff);
+ pcm->data.w[0] = 2;
+ }
+
+ return XLOG_OK;
+}
+
+/*
* Transmit-Function
*/
void
@@ -303,6 +410,7 @@ eicon_io_transmit(eicon_card *ccard) {
}
switch(ccard->type) {
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
@@ -314,6 +422,7 @@ eicon_io_transmit(eicon_card *ccard) {
scom = 0;
prram = (eicon_pr_ram *)isa_card->shmem;
break;
+#endif
case EICON_CTYPE_MAESTRAP:
scom = 0;
ram = (char *)pci_card->PCIram;
@@ -366,9 +475,13 @@ eicon_io_transmit(eicon_card *ccard) {
chan = chan2->ptr;
if (!chan->e.busy) {
if((skb = skb_dequeue(&chan->e.X))) {
- save_flags(flags);
- cli();
- reqbuf = (eicon_REQ *)skb->data;
+ save_flags(flags);
+ cli();
+ reqbuf = (eicon_REQ *)skb->data;
+ if ((reqbuf->Reference) && (chan->e.B2Id == 0) && (reqbuf->ReqId & 0x1f)) {
+ if (DebugVar & 16)
+ printk(KERN_WARNING "eicon: transmit: error Id=0 on %d (Net)\n", chan->No);
+ } else {
if (scom) {
ram_outw(ccard, &com->XBuffer.length, reqbuf->XBuffer.length);
ram_copytocard(ccard, &com->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length);
@@ -383,7 +496,7 @@ eicon_io_transmit(eicon_card *ccard) {
ram_outb(ccard, &ReqOut->Req, reqbuf->Req);
}
- if (reqbuf->ReqId &0x1f) { /* if this is no ASSIGN */
+ if (reqbuf->ReqId & 0x1f) { /* if this is no ASSIGN */
if (!reqbuf->Reference) { /* Signal Layer */
if (scom)
@@ -432,14 +545,15 @@ eicon_io_transmit(eicon_card *ccard) {
ram_outw(ccard, &prram->NextReq, ram_inw(ccard, &ReqOut->next));
chan->e.busy = 1;
- restore_flags(flags);
if (DebugVar & 32)
- printk(KERN_DEBUG "eicon: Req=%x Id=%x Ch=%x Len=%x Ref=%d\n",
+ printk(KERN_DEBUG "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n",
reqbuf->Req,
ram_inb(ccard, &ReqOut->ReqId),
reqbuf->ReqCh, reqbuf->XBuffer.length,
chan->e.ref);
- dev_kfree_skb(skb);
+ }
+ restore_flags(flags);
+ dev_kfree_skb(skb);
}
dev_kfree_skb(skb2);
}
@@ -510,6 +624,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
isa_card = &ccard->hwif.isa;
switch(ccard->type) {
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
@@ -523,6 +638,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
prram = (eicon_pr_ram *)isa_card->shmem;
irqprobe = &isa_card->irqprobe;
break;
+#endif
case EICON_CTYPE_MAESTRAP:
scom = 0;
ram = (char *)pci_card->PCIram;
@@ -546,6 +662,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
if (*irqprobe) {
switch(ccard->type) {
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
@@ -563,6 +680,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
}
(*irqprobe)++;
break;
+#endif
case EICON_CTYPE_MAESTRAP:
if (readb(&ram[0x3fe])) {
writeb(0, &prram->RcOutput);
@@ -581,6 +699,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
}
switch(ccard->type) {
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
@@ -592,6 +711,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
return;
}
break;
+#endif
case EICON_CTYPE_MAESTRAP:
if (!(readb(&ram[0x3fe]))) { /* card did not interrupt */
if (DebugVar & 1)
@@ -623,16 +743,21 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
}
} else {
skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC);
- ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
- ack->Rc = tmp;
- ack->RcId = ram_inb(ccard, &com->RcId);
- ack->RcCh = ram_inb(ccard, &com->RcCh);
- ack->Reference = ccard->ref_in++;
- if (DebugVar & 64)
- printk(KERN_INFO "eicon: IRQ Rc=%d Id=%d Ch=%d Ref=%d\n",
- tmp,ack->RcId,ack->RcCh,ack->Reference);
- skb_queue_tail(&ccard->rackq, skb);
- eicon_schedule_ack(ccard);
+ if (!skb) {
+ if (DebugVar & 1)
+ printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n");
+ } else {
+ ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
+ ack->Rc = tmp;
+ ack->RcId = ram_inb(ccard, &com->RcId);
+ ack->RcCh = ram_inb(ccard, &com->RcCh);
+ ack->Reference = ccard->ref_in++;
+ if (DebugVar & 64)
+ printk(KERN_INFO "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n",
+ tmp,ack->RcId,ack->RcCh,ack->Reference);
+ skb_queue_tail(&ccard->rackq, skb);
+ eicon_schedule_ack(ccard);
+ }
ram_outb(ccard, &com->Req, 0);
ram_outb(ccard, &com->Rc, 0);
}
@@ -644,19 +769,24 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
eicon_IND *ind;
int len = ram_inw(ccard, &com->RBuffer.length);
skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC);
- ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
- ind->Ind = tmp;
- ind->IndId = ram_inb(ccard, &com->IndId);
- ind->IndCh = ram_inb(ccard, &com->IndCh);
- ind->MInd = ram_inb(ccard, &com->MInd);
- ind->MLength = ram_inw(ccard, &com->MLength);
- ind->RBuffer.length = len;
- if (DebugVar & 64)
- printk(KERN_INFO "eicon: IRQ Ind=%d Id=%d Ch=%d MInd=%d MLen=%d Len=%d\n",
- tmp,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len);
- ram_copyfromcard(ccard, &ind->RBuffer.P, &com->RBuffer.P, len);
- skb_queue_tail(&ccard->rcvq, skb);
- eicon_schedule_rx(ccard);
+ if (!skb) {
+ if (DebugVar & 1)
+ printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n");
+ } else {
+ ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
+ ind->Ind = tmp;
+ ind->IndId = ram_inb(ccard, &com->IndId);
+ ind->IndCh = ram_inb(ccard, &com->IndCh);
+ ind->MInd = ram_inb(ccard, &com->MInd);
+ ind->MLength = ram_inw(ccard, &com->MLength);
+ ind->RBuffer.length = len;
+ if (DebugVar & 64)
+ printk(KERN_INFO "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
+ tmp,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len);
+ ram_copyfromcard(ccard, &ind->RBuffer.P, &com->RBuffer.P, len);
+ skb_queue_tail(&ccard->rcvq, skb);
+ eicon_schedule_rx(ccard);
+ }
ram_outb(ccard, &com->Ind, 0);
}
}
@@ -673,17 +803,22 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
if((Rc=ram_inb(ccard, &RcIn->Rc))) {
skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC);
- ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
- ack->Rc = Rc;
- ack->RcId = ram_inb(ccard, &RcIn->RcId);
- ack->RcCh = ram_inb(ccard, &RcIn->RcCh);
- ack->Reference = ram_inw(ccard, &RcIn->Reference);
- if (DebugVar & 64)
- printk(KERN_INFO "eicon: IRQ Rc=%d Id=%d Ch=%d Ref=%d\n",
- Rc,ack->RcId,ack->RcCh,ack->Reference);
- ram_outb(ccard, &RcIn->Rc, 0);
- skb_queue_tail(&ccard->rackq, skb);
- eicon_schedule_ack(ccard);
+ if (!skb) {
+ if (DebugVar & 1)
+ printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n");
+ } else {
+ ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
+ ack->Rc = Rc;
+ ack->RcId = ram_inb(ccard, &RcIn->RcId);
+ ack->RcCh = ram_inb(ccard, &RcIn->RcCh);
+ ack->Reference = ram_inw(ccard, &RcIn->Reference);
+ if (DebugVar & 64)
+ printk(KERN_INFO "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n",
+ Rc,ack->RcId,ack->RcCh,ack->Reference);
+ skb_queue_tail(&ccard->rackq, skb);
+ eicon_schedule_ack(ccard);
+ }
+ ram_outb(ccard, &RcIn->Rc, 0);
}
/* get buffer address of next return code */
RcIn = (eicon_RC *)&prram->B[ram_inw(ccard, &RcIn->next)];
@@ -703,19 +838,24 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
if(Ind) {
int len = ram_inw(ccard, &IndIn->RBuffer.length);
skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC);
- ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
- ind->Ind = Ind;
- ind->IndId = ram_inb(ccard, &IndIn->IndId);
- ind->IndCh = ram_inb(ccard, &IndIn->IndCh);
- ind->MInd = ram_inb(ccard, &IndIn->MInd);
- ind->MLength = ram_inw(ccard, &IndIn->MLength);
- ind->RBuffer.length = len;
- if (DebugVar & 64)
- printk(KERN_INFO "eicon: IRQ Ind=%d Id=%d Ch=%d MInd=%d MLen=%d Len=%d\n",
- Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len);
- ram_copyfromcard(ccard, &ind->RBuffer.P, &IndIn->RBuffer.P, len);
- skb_queue_tail(&ccard->rcvq, skb);
- eicon_schedule_rx(ccard);
+ if (!skb) {
+ if (DebugVar & 1)
+ printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n");
+ } else {
+ ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
+ ind->Ind = Ind;
+ ind->IndId = ram_inb(ccard, &IndIn->IndId);
+ ind->IndCh = ram_inb(ccard, &IndIn->IndCh);
+ ind->MInd = ram_inb(ccard, &IndIn->MInd);
+ ind->MLength = ram_inw(ccard, &IndIn->MLength);
+ ind->RBuffer.length = len;
+ if (DebugVar & 64)
+ printk(KERN_INFO "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
+ Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len);
+ ram_copyfromcard(ccard, &ind->RBuffer.P, &IndIn->RBuffer.P, len);
+ skb_queue_tail(&ccard->rcvq, skb);
+ eicon_schedule_rx(ccard);
+ }
ram_outb(ccard, &IndIn->Ind, 0);
}
/* get buffer address of next indication */
@@ -728,6 +868,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
/* clear interrupt */
switch(ccard->type) {
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_QUADRO:
writeb(0, isa_card->intack);
writeb(0, &com[0x401]);
@@ -738,6 +879,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
case EICON_CTYPE_S2M:
writeb(0, isa_card->intack);
break;
+#endif
case EICON_CTYPE_MAESTRAP:
writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]);
writew(0, &cfg[MP_IRQ_RESET + 2]);
diff --git a/drivers/isdn/eicon/eicon_isa.c b/drivers/isdn/eicon/eicon_isa.c
index 184f1c394..75122559c 100644
--- a/drivers/isdn/eicon/eicon_isa.c
+++ b/drivers/isdn/eicon/eicon_isa.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_isa.c,v 1.5 1999/04/01 12:48:33 armin Exp $
+/* $Id: eicon_isa.c,v 1.7 1999/08/22 20:26:48 calle Exp $
*
* ISDN low-level module for Eicon.Diehl active ISDN-Cards.
* Hardware-specific code for old ISA cards.
@@ -22,6 +22,16 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_isa.c,v $
+ * Revision 1.7 1999/08/22 20:26:48 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.6 1999/07/25 15:12:06 armin
+ * fix of some debug logs.
+ * enabled ISA-cards option.
+ *
* Revision 1.5 1999/04/01 12:48:33 armin
* Changed some log outputs.
*
@@ -46,6 +56,7 @@
*
*/
+#include <linux/config.h>
#include "eicon.h"
#include "eicon_isa.h"
@@ -53,7 +64,9 @@
#define release_shmem release_region
#define request_shmem request_region
-char *eicon_isa_revision = "$Revision: 1.5 $";
+char *eicon_isa_revision = "$Revision: 1.7 $";
+
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
/* Mask for detecting invalid IRQ parameter */
static int eicon_isa_valid_irq[] = {
@@ -430,3 +443,5 @@ eicon_isa_load(eicon_isa_card *card, eicon_isa_codebuf *cb) {
card->irqprobe = 0;
return 0;
}
+
+#endif /* CONFIG_ISDN_DRV_EICON_ISA */
diff --git a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c
index c14d91d7e..1ac22aa80 100644
--- a/drivers/isdn/eicon/eicon_mod.c
+++ b/drivers/isdn/eicon/eicon_mod.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_mod.c,v 1.5 1999/04/01 12:48:35 armin Exp $
+/* $Id: eicon_mod.c,v 1.11 1999/08/29 17:23:45 armin Exp $
*
* ISDN lowlevel-module for Eicon.Diehl active cards.
*
@@ -26,6 +26,31 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_mod.c,v $
+ * Revision 1.11 1999/08/29 17:23:45 armin
+ * New setup compat.
+ * Bugfix if compile as not module.
+ *
+ * Revision 1.10 1999/08/28 21:32:53 armin
+ * Prepared for fax related functions.
+ * Now compilable without errors/warnings.
+ *
+ * Revision 1.9 1999/08/18 20:17:02 armin
+ * Added XLOG function for all cards.
+ * Bugfix of alloc_skb NULL pointer.
+ *
+ * Revision 1.8 1999/07/25 15:12:08 armin
+ * fix of some debug logs.
+ * enabled ISA-cards option.
+ *
+ * Revision 1.7 1999/07/11 17:16:27 armin
+ * Bugfixes in queue handling.
+ * Added DSP-DTMF decoder functions.
+ * Reorganized ack_handler.
+ *
+ * Revision 1.6 1999/06/09 19:31:26 armin
+ * Wrong PLX size for request_region() corrected.
+ * Added first MCA code from Erik Weber.
+ *
* Revision 1.5 1999/04/01 12:48:35 armin
* Changed some log outputs.
*
@@ -50,17 +75,23 @@
*
*/
+#define DRIVERPATCH ""
+
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
+#ifdef CONFIG_MCA
+#include <linux/mca.h>
+#endif
#include "eicon.h"
#define INCLUDE_INLINE_FUNCS
-static eicon_card *cards = (eicon_card *) NULL;
+static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains
+ start of card-list */
-static char *eicon_revision = "$Revision: 1.5 $";
+static char *eicon_revision = "$Revision: 1.11 $";
extern char *eicon_pci_revision;
extern char *eicon_isa_revision;
@@ -70,24 +101,28 @@ extern char *eicon_idi_revision;
#define MOD_USE_COUNT (GET_USE_COUNT (&__this_module))
#endif
-#define EICON_CTRL_VERSION 1
+#define EICON_CTRL_VERSION 2
ulong DebugVar;
/* Parameters to be set by insmod */
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
static int membase = -1;
static int irq = -1;
+#endif
static char *id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
MODULE_DESCRIPTION( "Driver for Eicon.Diehl active ISDN cards");
MODULE_AUTHOR( "Armin Schindler");
MODULE_SUPPORTED_DEVICE( "ISDN subsystem");
+MODULE_PARM_DESC(id, "ID-String of first card");
+MODULE_PARM(id, "s");
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
MODULE_PARM_DESC(membase, "Base address of first ISA card");
MODULE_PARM_DESC(irq, "IRQ of first card");
-MODULE_PARM_DESC(id, "ID-String of first card");
MODULE_PARM(membase, "i");
MODULE_PARM(irq, "i");
-MODULE_PARM(id, "s");
+#endif
char *eicon_ctype_name[] = {
"ISDN-S",
@@ -291,10 +326,10 @@ eicon_rcv_dispatch(struct eicon_card *card)
{
switch (card->bus) {
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
case EICON_BUS_PCI:
eicon_io_rcv_dispatch(card);
break;
- case EICON_BUS_MCA:
default:
if (DebugVar & 1)
printk(KERN_WARNING
@@ -307,10 +342,10 @@ eicon_ack_dispatch(struct eicon_card *card)
{
switch (card->bus) {
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
case EICON_BUS_PCI:
eicon_io_ack_dispatch(card);
break;
- case EICON_BUS_MCA:
default:
if (DebugVar & 1)
printk(KERN_WARNING
@@ -323,10 +358,10 @@ eicon_transmit(struct eicon_card *card)
{
switch (card->bus) {
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
case EICON_BUS_PCI:
eicon_io_transmit(card);
break;
- case EICON_BUS_MCA:
default:
if (DebugVar & 1)
printk(KERN_WARNING
@@ -334,6 +369,32 @@ eicon_transmit(struct eicon_card *card)
}
}
+static int eicon_xlog(eicon_card *card, xlogreq_t *xlogreq)
+{
+ xlogreq_t *xlr;
+ int ret_val;
+
+ if (!(xlr = kmalloc(sizeof(xlogreq_t), GFP_KERNEL))) {
+ if (DebugVar & 1)
+ printk(KERN_WARNING "idi_err: alloc_xlogreq_t failed\n");
+ return -ENOMEM;
+ }
+ if (copy_from_user(xlr, xlogreq, sizeof(xlogreq_t))) {
+ kfree(xlr);
+ return -EFAULT;
+ }
+
+ ret_val = eicon_get_xlog(card, xlr);
+
+ if (copy_to_user(xlogreq, xlr, sizeof(xlogreq_t))) {
+ kfree(xlr);
+ return -EFAULT;
+ }
+ kfree(xlr);
+
+ return ret_val;
+}
+
static int
eicon_command(eicon_card * card, isdn_ctrl * c)
{
@@ -345,6 +406,10 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
int ret = 0;
unsigned long flags;
+ if (DebugVar & 16)
+ printk(KERN_WARNING "eicon_cmd 0x%x with arg 0x%lx (0x%lx)\n",
+ c->command, c->arg, (ulong) *c->parm.num);
+
switch (c->command) {
case ISDN_CMD_IOCTL:
memcpy(&a, c->parm.num, sizeof(ulong));
@@ -356,6 +421,7 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
case EICON_IOCTL_GETMMIO:
switch (card->bus) {
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
return (int)card->hwif.isa.shmem;
#if CONFIG_PCI
case EICON_BUS_PCI:
@@ -368,11 +434,13 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
card->bus);
ret = -ENODEV;
}
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_IOCTL_SETMMIO:
if (card->flags & EICON_FLAGS_LOADED)
return -EBUSY;
switch (card->bus) {
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
if (eicon_isa_find_card(a,
card->hwif.isa.irq,
card->regname) < 0)
@@ -386,9 +454,11 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
card->bus);
ret = -ENODEV;
}
+#endif
case EICON_IOCTL_GETIRQ:
switch (card->bus) {
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
return card->hwif.isa.irq;
#if CONFIG_PCI
case EICON_BUS_PCI:
@@ -408,6 +478,7 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
return -EFAULT;
switch (card->bus) {
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
card->hwif.isa.irq = a;
return 0;
default:
@@ -417,11 +488,13 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
card->bus);
ret = -ENODEV;
}
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_IOCTL_LOADBOOT:
if (card->flags & EICON_FLAGS_RUNNING)
return -EBUSY;
switch (card->bus) {
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
ret = eicon_isa_bootload(
&(card->hwif.isa),
&(((eicon_codebuf *)a)->isa));
@@ -434,11 +507,14 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
ret = -ENODEV;
}
return ret;
+#endif
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_IOCTL_LOADISA:
if (card->flags & EICON_FLAGS_RUNNING)
return -EBUSY;
switch (card->bus) {
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
ret = eicon_isa_load(
&(card->hwif.isa),
&(((eicon_codebuf *)a)->isa));
@@ -465,7 +541,7 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
ret = -ENODEV;
}
return ret;
-
+#endif
case EICON_IOCTL_MANIF:
if (!card->flags & EICON_FLAGS_RUNNING)
return -ENODEV;
@@ -475,6 +551,12 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
card,
(eicon_manifbuf *)a);
return ret;
+
+ case EICON_IOCTL_GETXLOG:
+ if (!card->flags & EICON_FLAGS_RUNNING)
+ return XLOG_ERR_CARD_STATE;
+ ret = eicon_xlog(card, (xlogreq_t *)a);
+ return ret;
#if CONFIG_PCI
case EICON_IOCTL_LOADPCI:
if (card->flags & EICON_FLAGS_RUNNING)
@@ -639,14 +721,13 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
case ISDN_CMD_SETL3:
if (!card->flags & EICON_FLAGS_RUNNING)
return -ENODEV;
- if ((c->arg >> 8) != ISDN_PROTO_L3_TRANS) {
- if (DebugVar & 1)
- printk(KERN_WARNING "L3 protocol unknown\n");
- return -1;
- }
if (!(chan = find_channel(card, c->arg & 0x1f)))
break;
chan->l3prot = (c->arg >> 8);
+#ifdef CONFIG_ISDN_TTY_FAX
+ if (chan->l3prot == ISDN_PROTO_L3_FAX)
+ chan->fax = c->parm.fax;
+#endif
return 0;
case ISDN_CMD_GETL3:
if (!card->flags & EICON_FLAGS_RUNNING)
@@ -678,6 +759,24 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
case ISDN_CMD_UNLOCK:
MOD_DEC_USE_COUNT;
return 0;
+#ifdef CONFIG_ISDN_TTY_FAX
+ case ISDN_CMD_FAXCMD:
+ if (!card->flags & EICON_FLAGS_RUNNING)
+ return -ENODEV;
+ if (!(chan = find_channel(card, c->arg & 0x1f)))
+ break;
+ if (!chan->fax)
+ break;
+ idi_fax_cmd(card, chan);
+ return 0;
+#endif
+ case ISDN_CMD_AUDIO:
+ if (!card->flags & EICON_FLAGS_RUNNING)
+ return -ENODEV;
+ if (!(chan = find_channel(card, c->arg & 0x1f)))
+ break;
+ idi_audio_cmd(card, chan, c->arg >> 8, c->parm.num);
+ return 0;
}
return -EINVAL;
@@ -718,16 +817,19 @@ if_command(isdn_ctrl * c)
static int
if_writecmd(const u_char * buf, int len, int user, int id, int channel)
{
+#if 0
+ /* Not yet used */
eicon_card *card = eicon_findcard(id);
if (card) {
if (!card->flags & EICON_FLAGS_RUNNING)
- return -ENODEV;
+ return (len);
return (len);
}
printk(KERN_ERR
"eicon: if_writecmd called with invalid driverId!\n");
- return -ENODEV;
+#endif
+ return (len);
}
static int
@@ -745,7 +847,7 @@ if_readstatus(u_char * buf, int len, int user, int id, int channel)
printk(KERN_ERR
"eicon: if_readstatus called with invalid driverId!\n");
#endif
- return -ENODEV;
+ return 0;
}
static int
@@ -753,6 +855,10 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
{
eicon_card *card = eicon_findcard(id);
eicon_chan *chan;
+ int ret = 0;
+ int len;
+
+ len = skb->len;
if (card) {
if (!card->flags & EICON_FLAGS_RUNNING) {
@@ -763,9 +869,17 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
dev_kfree_skb(skb);
return -ENODEV;
}
- if (chan->fsm_state == EICON_STATE_ACTIVE)
- return (idi_send_data(card, chan, ack, skb));
- else {
+ if (chan->fsm_state == EICON_STATE_ACTIVE) {
+#ifdef CONFIG_ISDN_TTY_FAX
+ if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+ if ((ret = idi_faxdata_send(card, chan, skb)) > 0)
+ ret = len;
+ }
+ else
+#endif
+ ret = idi_send_data(card, chan, ack, skb, 1);
+ return (ret);
+ } else {
dev_kfree_skb(skb);
return -ENODEV;
}
@@ -787,7 +901,9 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
int i;
int j;
int qloop;
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
char qid[5];
+#endif
eicon_card *card;
#if CONFIG_PCI
eicon_pci_card *pcic;
@@ -828,12 +944,32 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
card->myid = -1;
card->type = Type;
switch (Type) {
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
+#if CONFIG_MCA /* only needed for MCA */
+ case EICON_CTYPE_S:
+ case EICON_CTYPE_SX:
+ case EICON_CTYPE_SCOM:
+ if (membase == -1)
+ membase = EICON_ISA_MEMBASE;
+ if (irq == -1)
+ irq = EICON_ISA_IRQ;
+ card->bus = EICON_BUS_MCA;
+ card->hwif.isa.card = (void *)card;
+ card->hwif.isa.shmem = (eicon_isa_shmem *)membase;
+ card->hwif.isa.master = 1;
+
+ card->hwif.isa.irq = irq;
+ card->hwif.isa.type = Type;
+ card->nchannels = 2;
+ card->interface.channels = 1;
+ break;
+#endif /* CONFIG_MCA */
case EICON_CTYPE_QUADRO:
if (membase == -1)
membase = EICON_ISA_MEMBASE;
if (irq == -1)
irq = EICON_ISA_IRQ;
- card->bus = EICON_BUS_ISA;
+ card->bus = EICON_BUS_ISA;
card->hwif.isa.card = (void *)card;
card->hwif.isa.shmem = (eicon_isa_shmem *)(membase + (i+1) * EICON_ISA_QOFFSET);
card->hwif.isa.master = 0;
@@ -868,6 +1004,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
card->nchannels = 2;
card->interface.channels = 1;
break;
+#endif
#if CONFIG_PCI
case EICON_CTYPE_MAESTRA:
(eicon_pci_card *)pcic = (eicon_pci_card *)membase;
@@ -876,7 +1013,10 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
ISDN_FEATURE_L2_V11096 |
ISDN_FEATURE_L2_V11019 |
ISDN_FEATURE_L2_V11038 |
- ISDN_FEATURE_L2_MODEM;
+ ISDN_FEATURE_L2_MODEM |
+ /* ISDN_FEATURE_L2_FAX | */
+ ISDN_FEATURE_L3_TRANSDSP |
+ ISDN_FEATURE_L3_FAX;
card->hwif.pci.card = (void *)card;
card->hwif.pci.PCIreg = pcic->PCIreg;
card->hwif.pci.PCIcfg = pcic->PCIcfg;
@@ -897,7 +1037,10 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
ISDN_FEATURE_L2_V11096 |
ISDN_FEATURE_L2_V11019 |
ISDN_FEATURE_L2_V11038 |
- ISDN_FEATURE_L2_MODEM;
+ ISDN_FEATURE_L2_MODEM |
+ /* ISDN_FEATURE_L2_FAX | */
+ ISDN_FEATURE_L3_TRANSDSP |
+ ISDN_FEATURE_L3_FAX;
card->hwif.pci.card = (void *)card;
card->hwif.pci.shmem = (eicon_pci_shmem *)pcic->shmem;
card->hwif.pci.PCIreg = pcic->PCIreg;
@@ -913,6 +1056,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
card->interface.channels = 1;
break;
#endif
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_ISABRI:
if (membase == -1)
membase = EICON_ISA_MEMBASE;
@@ -932,7 +1076,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
membase = EICON_ISA_MEMBASE;
if (irq == -1)
irq = EICON_ISA_IRQ;
- card->bus = EICON_BUS_ISA;
+ card->bus = EICON_BUS_ISA;
card->hwif.isa.card = (void *)card;
card->hwif.isa.shmem = (eicon_isa_shmem *)membase;
card->hwif.isa.master = 1;
@@ -941,6 +1085,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
card->nchannels = 30;
card->interface.channels = 1;
break;
+#endif
default:
printk(KERN_WARNING "eicon_alloccard: Invalid type %d\n", Type);
kfree(card);
@@ -978,15 +1123,21 @@ static int
eicon_registercard(eicon_card * card)
{
switch (card->bus) {
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_BUS_ISA:
/* TODO something to print */
break;
+#ifdef CONFIG_MCA
+ case EICON_BUS_MCA:
+ eicon_isa_printpar(&card->hwif.isa);
+ break;
+#endif
+#endif
case EICON_BUS_PCI:
#if CONFIG_PCI
eicon_pci_printpar(&card->hwif.pci);
break;
#endif
- case EICON_BUS_MCA:
default:
if (DebugVar & 1)
printk(KERN_WARNING
@@ -1015,15 +1166,19 @@ unregister_card(eicon_card * card)
cmd.driver = card->myid;
card->interface.statcallb(&cmd);
switch (card->bus) {
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_BUS_ISA:
+#ifdef CONFIG_MCA
+ case EICON_BUS_MCA:
+#endif
eicon_isa_release(&card->hwif.isa);
break;
+#endif
case EICON_BUS_PCI:
#if CONFIG_PCI
eicon_pci_release(&card->hwif.pci);
break;
#endif
- case EICON_BUS_MCA:
default:
if (DebugVar & 1)
printk(KERN_WARNING
@@ -1050,9 +1205,11 @@ eicon_addcard(int Type, int membase, int irq, char *id)
int added = 0;
int failed = 0;
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
if (!Type) /* ISA */
if ((Type = eicon_isa_find_card(membase, irq, id)) < 0)
return 0;
+#endif
eicon_alloccard(Type, membase, irq, id);
p = cards;
while (p) {
@@ -1063,11 +1220,14 @@ eicon_addcard(int Type, int membase, int irq, char *id)
*/
added++;
switch (p->bus) {
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_BUS_ISA:
+ case EICON_BUS_MCA:
if (eicon_registercard(p))
break;
registered = 1;
break;
+#endif
case EICON_BUS_PCI:
#if CONFIG_PCI
if (eicon_registercard(p))
@@ -1075,7 +1235,6 @@ eicon_addcard(int Type, int membase, int irq, char *id)
registered = 1;
break;
#endif
- case EICON_BUS_MCA:
default:
if (DebugVar & 1)
printk(KERN_WARNING
@@ -1116,10 +1275,10 @@ eicon_addcard(int Type, int membase, int irq, char *id)
#define eicon_init init_module
#endif
-__initfunc(int
-eicon_init(void))
+int __init
+eicon_init(void)
{
- int tmp = 0;
+ int card_count = 0;
int release = 0;
char tmprev[50];
@@ -1130,30 +1289,66 @@ eicon_init(void))
printk("%s/", eicon_getrev(tmprev));
release += getrel(tmprev);
strcpy(tmprev, eicon_pci_revision);
+#if CONFIG_PCI
printk("%s/", eicon_getrev(tmprev));
+#else
+ printk("---/");
+#endif
release += getrel(tmprev);
strcpy(tmprev, eicon_isa_revision);
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
printk("%s/", eicon_getrev(tmprev));
+#else
+ printk("---/");
+#endif
release += getrel(tmprev);
strcpy(tmprev, eicon_idi_revision);
printk("%s\n", eicon_getrev(tmprev));
release += getrel(tmprev);
sprintf(tmprev,"%d", release);
- printk(KERN_INFO "%s Release: %s.%s\n", DRIVERNAME,
- DRIVERRELEASE, tmprev);
+ printk(KERN_INFO "%s Release: %s.%s%s\n", DRIVERNAME,
+ DRIVERRELEASE, tmprev, DRIVERPATCH);
- tmp = eicon_addcard(0, membase, irq, id);
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
+#ifdef CONFIG_MCA
+ /* Check if we have MCA-bus */
+ if (!MCA_bus)
+ {
+ printk(KERN_INFO
+ "eicon: No MCA bus, ISDN-interfaces not probed.\n");
+ } else {
+ if (DebugVar & 8)
+ printk(KERN_DEBUG
+ "eicon_mca_find_card, irq=%d.\n",
+ irq);
+ if (!eicon_mca_find_card(0, membase, irq, id))
+ card_count++;
+ };
+#else
+ card_count = eicon_addcard(0, membase, irq, id);
+#endif /* CONFIG_MCA */
+#endif /* CONFIG_ISDN_DRV_EICON_ISA */
+
#if CONFIG_PCI
- tmp += eicon_pci_find_card(id);
+ card_count += eicon_pci_find_card(id);
#endif
if (!cards) {
#ifdef MODULE
+#ifndef CONFIG_PCI
+#ifndef CONFIG_ISDN_DRV_EICON_ISA
+ printk(KERN_INFO "Eicon: Driver is neither ISA nor PCI compiled !\n");
+#else
printk(KERN_INFO "Eicon: No cards defined, driver not loaded !\n");
#endif
+#else
+ printk(KERN_INFO "Eicon: No PCI-cards found, driver not loaded !\n");
+#endif
+#endif /* MODULE */
return -ENODEV;
} else
- printk(KERN_INFO "Eicon: %d card%s added\n", tmp, (tmp>1)?"s":"");
+ printk(KERN_INFO "Eicon: %d card%s added\n", card_count,
+ (card_count>1)?"s":"");
/* No symbols to export, hide all symbols */
EXPORT_NO_SYMBOLS;
return 0;
@@ -1166,6 +1361,13 @@ cleanup_module(void)
eicon_card *card = cards;
eicon_card *last;
while (card) {
+#ifdef CONFIG_MCA
+ if (MCA_bus)
+ {
+ mca_mark_as_unused (card->mca_slot);
+ mca_set_adapter_procfn(card->mca_slot, NULL, NULL);
+ };
+#endif
unregister_card(card);
card = card->next;
}
@@ -1178,14 +1380,27 @@ cleanup_module(void)
printk(KERN_INFO "%s unloaded\n", DRIVERNAME);
}
+#else /* no module */
+
+#ifdef COMPAT_HAS_NEW_SETUP
+static int __init
+eicon_setup(char *line)
+{
+ int i, argc;
+ int ints[5];
+ char *str;
+
+ str = get_options(line, 4, ints);
#else
-__initfunc(void
-eicon_setup(char *str, int *ints))
+void __init
+eicon_setup(char *str, int *ints)
{
int i, argc;
+#endif
argc = ints[0];
i = 1;
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
if (argc) {
membase = irq = -1;
if (argc) {
@@ -1203,8 +1418,187 @@ eicon_setup(char *str, int *ints))
} else {
strcpy(id, "eicon");
}
- /* eicon_addcard(0, membase, irq, id); */
- printk(KERN_INFO "eicon: membase=0x%x irq=%d id=%s\n", membase, irq, id);
+ printk(KERN_INFO "Eicon ISDN active driver setup (id=%s membase=0x%x irq=%d)\n",
+ id, membase, irq);
}
+#else
+ printk(KERN_INFO "Eicon ISDN active driver setup\n");
+#endif
+#ifdef COMPAT_HAS_NEW_SETUP
+ return(1);
+}
+__setup("eicon=", eicon_setup);
+#else
}
#endif
+
+#endif /* MODULE */
+
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
+#ifdef CONFIG_MCA
+
+struct eicon_mca_adapters_struct {
+ char * name;
+ int adf_id;
+};
+/* possible MCA-brands of eicon cards */
+struct eicon_mca_adapters_struct eicon_mca_adapters[] = {
+ { "ISDN-P/2 Adapter", 0x6abb },
+ { "ISDN-[S|SX|SCOM]/2 Adapter", 0x6a93 },
+ { "DIVA /MCA", 0x6336 },
+ { NULL, 0 },
+};
+
+int eicon_mca_find_card(int type, /* type-idx of eicon-card */
+ int membase,
+ int irq,
+ char * id) /* name of eicon-isdn-dev */
+{
+ int j, curr_slot = 0;
+
+ if (DebugVar & 8)
+ printk(KERN_DEBUG
+ "eicon_mca_find_card type: %d, membase: %#x, irq %d \n",
+ type, membase, irq);
+ /* find a no-driver-assigned eicon card */
+ for (j=0; eicon_mca_adapters[j].adf_id != 0; j++)
+ {
+ for ( curr_slot=0; curr_slot<=MCA_MAX_SLOT_NR; curr_slot++)
+ {
+ curr_slot = mca_find_unused_adapter(
+ eicon_mca_adapters[j].adf_id, curr_slot);
+ if (curr_slot != MCA_NOTFOUND)
+ {
+ /* check if pre-set parameters match
+ these of the card, check cards memory */
+ if (!(int) eicon_mca_probe(curr_slot,
+ j,
+ membase,
+ irq,
+ id))
+ {
+ return 0;
+ /* means: adapter parms did match */
+ };
+ };
+ break;
+ /* MCA_NOTFOUND-branch: no matching adapter of
+ THIS flavor found, next flavor */
+
+ };
+ };
+ /* all adapter flavors checked without match, finito with: */
+ return ENODEV;
+};
+
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ * stolen from 3c523.c/elmc_getinfo, ewe, 10.5.1999
+ */
+int eicon_info(char * buf, int slot, void *d)
+{
+ int len = 0;
+ struct eicon_card *dev;
+
+ dev = (struct eicon_card *) d;
+
+ if (dev == NULL)
+ return len;
+ len += sprintf(buf+len, "eicon ISDN adapter, type %d.\n",dev->type);
+ len += sprintf(buf+len, "IRQ: %d\n", dev->hwif.isa.irq);
+ len += sprintf(buf+len, "MEMBASE: %#lx\n", (unsigned long)dev->hwif.isa.shmem);
+
+ return len;
+};
+
+int eicon_mca_probe(int slot, /* slot-nr where the card was detected */
+ int a_idx, /* idx-nr of probed card in eicon_mca_adapters */
+ int membase,
+ int irq,
+ char * id) /* name of eicon-isdn-dev */
+{
+ unsigned char adf_pos0;
+ int cards_irq, cards_membase, cards_io;
+ int type = EICON_CTYPE_S;
+ int irq_array[]={0,3,4,2};
+ int irq_array1[]={3,4,0,0,2,10,11,12};
+
+ adf_pos0 = mca_read_stored_pos(slot,2);
+ if (DebugVar & 8)
+ printk(KERN_DEBUG
+ "eicon_mca_probe irq=%d, membase=%d\n",
+ irq,
+ membase);
+ switch (a_idx) {
+ case 0: /* P/2-Adapter (== PRI/S2M ? ) */
+ cards_membase= 0xC0000+((adf_pos0>>4)*0x4000);
+ if (membase == -1) {
+ membase = cards_membase;
+ } else {
+ if (membase != cards_membase)
+ return ENODEV;
+ };
+ cards_irq=irq_array[((adf_pos0 & 0xC)>>2)];
+ if (irq == -1) {
+ irq = cards_irq;
+ } else {
+ if (irq != irq)
+ return ENODEV;
+ };
+ cards_io= 0xC00 + ((adf_pos0>>4)*0x10);
+ type = EICON_CTYPE_ISAPRI;
+ break;
+
+ case 1: /* [S|SX|SCOM]/2 */
+ cards_membase= 0xC0000+((adf_pos0>>4)*0x2000);
+ if (membase == -1) {
+ membase = cards_membase;
+ } else {
+ if (membase != cards_membase)
+ return ENODEV;
+ };
+ cards_irq=irq_array[((adf_pos0 & 0xC)>>2)];
+ if (irq == -1) {
+ irq = cards_irq;
+ } else {
+ if (irq != cards_irq)
+ return ENODEV;
+ };
+
+ cards_io= 0xC00 + ((adf_pos0>>4)*0x10);
+ type = EICON_CTYPE_SCOM;
+ break;
+
+ case 2: /* DIVA/MCA */
+ cards_io = 0x200+ ((adf_pos0>>4)* 0x20);
+ cards_irq = irq_array1[(adf_pos0 & 0x7)];
+ if (irq == -1) {
+ irq = cards_irq;
+ } else {
+ if (irq != irq)
+ return ENODEV;
+ };
+ type = 0;
+ break;
+ default:
+ return ENODEV;
+ };
+ /* Uebereinstimmung vorgegebener membase & irq */
+ if ( 1 == eicon_addcard(type, membase, irq, id)) {
+ mca_set_adapter_name(slot, eicon_mca_adapters[a_idx].name);
+ mca_set_adapter_procfn(slot, (MCA_ProcFn) eicon_info, cards);
+
+ mca_mark_as_used(slot);
+ cards->mca_slot = slot;
+ /* card->io noch setzen oder ?? */
+ if (DebugVar & 8)
+ printk("eicon_addcard: erfolgreich fuer slot: %d.\n",
+ cards->mca_slot+1);
+ return 0 ; /* eicon_addcard hat eine Karte zugefuegt */
+ } else {
+ return ENODEV;
+ };
+};
+#endif /* CONFIG_MCA */
+#endif /* CONFIG_ISDN_DRV_EICON_ISA */
+
diff --git a/drivers/isdn/eicon/eicon_pci.c b/drivers/isdn/eicon/eicon_pci.c
index 3d07167ce..c1919e9f8 100644
--- a/drivers/isdn/eicon/eicon_pci.c
+++ b/drivers/isdn/eicon/eicon_pci.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_pci.c,v 1.6 1999/04/01 12:48:37 armin Exp $
+/* $Id: eicon_pci.c,v 1.10 1999/08/22 20:26:49 calle Exp $
*
* ISDN low-level module for Eicon.Diehl active ISDN-Cards.
* Hardware-specific code for PCI cards.
@@ -26,6 +26,22 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_pci.c,v $
+ * Revision 1.10 1999/08/22 20:26:49 calle
+ * backported changes from kernel 2.3.14:
+ * - several #include "config.h" gone, others come.
+ * - "struct device" changed to "struct net_device" in 2.3.14, added a
+ * define in isdn_compat.h for older kernel versions.
+ *
+ * Revision 1.9 1999/08/11 21:01:11 keil
+ * new PCI codefix
+ *
+ * Revision 1.8 1999/08/10 16:02:20 calle
+ * struct pci_dev changed in 2.3.13. Made the necessary changes.
+ *
+ * Revision 1.7 1999/06/09 19:31:29 armin
+ * Wrong PLX size for request_region() corrected.
+ * Added first MCA code from Erik Weber.
+ *
* Revision 1.6 1999/04/01 12:48:37 armin
* Changed some log outputs.
*
@@ -61,7 +77,7 @@
#include "eicon_pci.h"
-char *eicon_pci_revision = "$Revision: 1.6 $";
+char *eicon_pci_revision = "$Revision: 1.10 $";
#if CONFIG_PCI /* intire stuff is only for PCI */
@@ -136,8 +152,8 @@ int eicon_pci_find_card(char *ID)
aparms->type = EICON_CTYPE_MAESTRA;
aparms->irq = pdev->irq;
- preg = pdev->base_address[2] & 0xfffffffc;
- pcfg = pdev->base_address[1] & 0xffffff80;
+ preg = get_pcibase(pdev, 2) & 0xfffffffc;
+ pcfg = get_pcibase(pdev, 1) & 0xffffff80;
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq);
@@ -158,9 +174,9 @@ int eicon_pci_find_card(char *ID)
printk(KERN_INFO "Eicon: DIVA Server PRI/PCI detected !\n");
aparms->type = EICON_CTYPE_MAESTRAP; /*includes 9M,30M*/
aparms->irq = pdev->irq;
- pram = pdev->base_address[0] & 0xfffff000;
- preg = pdev->base_address[2] & 0xfffff000;
- pcfg = pdev->base_address[4] & 0xfffff000;
+ pram = get_pcibase(pdev, 0) & 0xfffff000;
+ preg = get_pcibase(pdev, 2) & 0xfffff000;
+ pcfg = get_pcibase(pdev, 4) & 0xfffff000;
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq);
@@ -194,12 +210,13 @@ int eicon_pci_find_card(char *ID)
} else {
request_region(aparms->PCIreg, 0x20, "eicon reg");
}
- if (check_region((aparms->PCIcfg), 0x100)) {
+ if (check_region((aparms->PCIcfg), 0x80)) {
printk(KERN_WARNING "eicon_pci: cfg port already in use !\n");
aparms->PCIcfg = 0;
+ release_region(aparms->PCIreg, 0x20);
break;
} else {
- request_region(aparms->PCIcfg, 0x100, "eicon cfg");
+ request_region(aparms->PCIcfg, 0x80, "eicon cfg");
}
break;
case PCI_MAESTRAQ:
@@ -327,7 +344,7 @@ eicon_pci_release_shmem(eicon_pci_card *card) {
outw(0, card->PCIreg + M_DATA);
release_region(card->PCIreg, 0x20);
- release_region(card->PCIcfg, 0x100);
+ release_region(card->PCIcfg, 0x80);
break;
case EICON_CTYPE_MAESTRAQ:
case EICON_CTYPE_MAESTRAQ_U: