From d6434e1042f3b0a6dfe1b1f615af369486f9b1fa Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sat, 9 Oct 1999 00:00:47 +0000 Subject: Merge with 2.3.19. --- drivers/isdn/eicon/eicon.h | 164 ++++++++++- drivers/isdn/eicon/eicon_dsp.h | 119 +++++++- drivers/isdn/eicon/eicon_idi.c | 648 +++++++++++++++++++++++++++++++++++------ drivers/isdn/eicon/eicon_idi.h | 31 +- drivers/isdn/eicon/eicon_io.c | 258 ++++++++++++---- drivers/isdn/eicon/eicon_isa.c | 19 +- drivers/isdn/eicon/eicon_mod.c | 474 +++++++++++++++++++++++++++--- drivers/isdn/eicon/eicon_pci.c | 37 ++- 8 files changed, 1530 insertions(+), 220 deletions(-) (limited to 'drivers/isdn/eicon') 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 #include #include #include @@ -194,6 +226,8 @@ typedef struct { #include +#include + 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: tone duration (ms) 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 + * + * 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 #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; iXBuffer.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; iXBuffer.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 #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 #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; @@ -271,6 +292,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 */ @@ -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 #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 #include #include +#ifdef CONFIG_MCA +#include +#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: -- cgit v1.2.3