diff options
Diffstat (limited to 'drivers/isdn')
106 files changed, 16978 insertions, 3829 deletions
diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in index e4ba2cf1f..2062f753c 100644 --- a/drivers/isdn/Config.in +++ b/drivers/isdn/Config.in @@ -37,6 +37,7 @@ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then bool ' Disable keypad protocol option' CONFIG_HISAX_NO_KEYPAD fi bool ' HiSax Support for german 1TR6' CONFIG_HISAX_1TR6 + bool ' HiSax Support for US NI1' CONFIG_HISAX_NI1 comment ' HiSax supported cards' bool ' Teles 16.0/8.0' CONFIG_HISAX_16_0 bool ' Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3 @@ -55,6 +56,7 @@ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then bool ' USR Sportster internal TA' CONFIG_HISAX_SPORTSTER bool ' MIC card' CONFIG_HISAX_MIC bool ' NETjet card' CONFIG_HISAX_NETJET + bool ' NETspider U card' CONFIG_HISAX_NETJET_U bool ' Niccy PnP/PCI card' CONFIG_HISAX_NICCY bool ' Siemens I-Surf card' CONFIG_HISAX_ISURF bool ' HST Saphir card' CONFIG_HISAX_HSTSAPHIR @@ -83,7 +85,15 @@ if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then fi dep_tristate 'Eicon active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then - bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA + if [ "$CONFIG_ISDN_DRV_EICON_STANDALONE" != "y" ]; then + if [ "$CONFIG_PCI" = "y" ]; then + bool ' Eicon PCI DIVA Server BRI/PRI/4BRI support' CONFIG_ISDN_DRV_EICON_PCI + fi + bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA + fi + if [ "$CONFIG_PCI" = "y" ]; then + bool ' build eicon driver type standalone' CONFIG_ISDN_DRV_EICON_STANDALONE + fi fi dep_tristate 'CAPI2.0 support' CONFIG_ISDN_CAPI $CONFIG_ISDN if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then @@ -109,8 +119,13 @@ if [ "$CONFIG_ISDN_CAPI" != "n" ]; then bool ' Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON fi if [ "$CONFIG_PROC_FS" != "n" ]; then -if [ "$CONFIG_MODULES" != "n" ]; then - bool 'Hypercope HYSDN cards (Champ, Ergo, Metro) support (module)' CONFIG_HYSDN + if [ "$CONFIG_MODULES" != "n" ]; then + bool 'Hypercope HYSDN cards (Champ, Ergo, Metro) support (module)' CONFIG_HYSDN + fi fi +if [ "$CONFIG_HYSDN" != "n" ]; then + if [ "$CONFIG_ISDN_CAPI" != "n" ]; then + bool ' HYSDN CAPI 2.0 support' CONFIG_HYSDN_CAPI + fi fi endmenu diff --git a/drivers/isdn/avmb1/b1.c b/drivers/isdn/avmb1/b1.c index ff13e1636..747b5ea7f 100644 --- a/drivers/isdn/avmb1/b1.c +++ b/drivers/isdn/avmb1/b1.c @@ -1,11 +1,17 @@ /* - * $Id: b1.c,v 1.14 2000/06/19 16:51:53 keil Exp $ + * $Id: b1.c,v 1.16 2000/08/04 15:36:31 calle Exp $ * * Common module for AVM B1 cards. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1.c,v $ + * Revision 1.16 2000/08/04 15:36:31 calle + * copied wrong from file to file :-( + * + * Revision 1.15 2000/08/04 12:20:08 calle + * - Fix unsigned/signed warning in the right way ... + * * Revision 1.14 2000/06/19 16:51:53 keil * don't free skb in irq context * @@ -95,7 +101,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.14 $"; +static char *revision = "$Revision: 1.16 $"; /* ------------------------------------------------------------- */ @@ -597,25 +603,29 @@ void b1_handle_interrupt(avmcard * card) ctrl->ready(ctrl); break; - case RECEIVE_TASK_READY: + case RECEIVE_TASK_READY: ApplId = (unsigned) b1_get_word(card->port); MsgLen = b1_get_slice(card->port, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: task %d \"%s\" ready.\n", card->name, ApplId, card->msgbuf); break; - case RECEIVE_DEBUGMSG: + case RECEIVE_DEBUGMSG: MsgLen = b1_get_slice(card->port, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); break; diff --git a/drivers/isdn/avmb1/b1dma.c b/drivers/isdn/avmb1/b1dma.c index 42a77acf5..3bd6a01c0 100644 --- a/drivers/isdn/avmb1/b1dma.c +++ b/drivers/isdn/avmb1/b1dma.c @@ -1,11 +1,14 @@ /* - * $Id: b1dma.c,v 1.6 2000/06/29 13:59:06 calle Exp $ + * $Id: b1dma.c,v 1.7 2000/08/04 12:20:08 calle Exp $ * * Common module for AVM B1 cards that support dma with AMCC * * (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1dma.c,v $ + * Revision 1.7 2000/08/04 12:20:08 calle + * - Fix unsigned/signed warning in the right way ... + * * Revision 1.6 2000/06/29 13:59:06 calle * Bugfix: reinit txdma without interrupt will confuse some AMCC chips. * @@ -44,7 +47,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.6 $"; +static char *revision = "$Revision: 1.7 $"; /* ------------------------------------------------------------- */ @@ -561,22 +564,26 @@ static void b1dma_handle_rx(avmcard *card) case RECEIVE_TASK_READY: ApplId = (unsigned) _get_word(&p); MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: task %d \"%s\" ready.\n", card->name, ApplId, card->msgbuf); break; case RECEIVE_DEBUGMSG: MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); break; diff --git a/drivers/isdn/avmb1/b1pci.c b/drivers/isdn/avmb1/b1pci.c index fb7b5f755..69bab9557 100644 --- a/drivers/isdn/avmb1/b1pci.c +++ b/drivers/isdn/avmb1/b1pci.c @@ -1,11 +1,14 @@ /* - * $Id: b1pci.c,v 1.26 2000/07/20 10:21:21 calle Exp $ + * $Id: b1pci.c,v 1.27 2000/08/08 09:24:19 calle Exp $ * * Module for AVM B1 PCI-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1pci.c,v $ + * Revision 1.27 2000/08/08 09:24:19 calle + * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI + * * Revision 1.26 2000/07/20 10:21:21 calle * Bugfix: driver will not be unregistered, if not cards were detected. * this result in an oops in kcapi.c @@ -91,13 +94,12 @@ #include <linux/pci.h> #include <linux/capi.h> #include <asm/io.h> -#include <linux/isdn.h> #include "capicmd.h" #include "capiutil.h" #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.26 $"; +static char *revision = "$Revision: 1.27 $"; /* ------------------------------------------------------------- */ diff --git a/drivers/isdn/avmb1/c4.c b/drivers/isdn/avmb1/c4.c index 64de830c2..d814eec1a 100644 --- a/drivers/isdn/avmb1/c4.c +++ b/drivers/isdn/avmb1/c4.c @@ -1,11 +1,20 @@ /* - * $Id: c4.c,v 1.13 2000/07/20 10:21:21 calle Exp $ + * $Id: c4.c,v 1.16 2000/08/20 07:30:13 keil Exp $ * * Module for AVM C4 card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: c4.c,v $ + * Revision 1.16 2000/08/20 07:30:13 keil + * changes for 2.4 + * + * Revision 1.15 2000/08/08 09:24:19 calle + * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI + * + * Revision 1.14 2000/08/04 12:20:08 calle + * - Fix unsigned/signed warning in the right way ... + * * Revision 1.13 2000/07/20 10:21:21 calle * Bugfix: driver will not be unregistered, if not cards were detected. * this result in an oops in kcapi.c @@ -63,15 +72,15 @@ #include <linux/ioport.h> #include <linux/pci.h> #include <linux/capi.h> -#include <linux/isdn.h> #include <asm/io.h> #include <asm/uaccess.h> +#include <linux/netdevice.h> #include "capicmd.h" #include "capiutil.h" #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.13 $"; +static char *revision = "$Revision: 1.16 $"; #undef CONFIG_C4_DEBUG #undef CONFIG_C4_POLLDEBUG @@ -682,22 +691,26 @@ static void c4_handle_rx(avmcard *card) case RECEIVE_TASK_READY: ApplId = (unsigned) _get_word(&p); MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: task %d \"%s\" ready.\n", card->name, ApplId, card->msgbuf); break; case RECEIVE_DEBUGMSG: MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); break; diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c index a4223e878..0b7cc80d2 100644 --- a/drivers/isdn/avmb1/capi.c +++ b/drivers/isdn/avmb1/capi.c @@ -1,11 +1,14 @@ /* - * $Id: capi.c,v 1.38 2000/07/24 08:49:09 calle Exp $ + * $Id: capi.c,v 1.39 2000/07/24 13:42:50 calle Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capi.c,v $ + * Revision 1.39 2000/07/24 13:42:50 calle + * - lock_kernel/unlock_kernel for _release functions. (from 2.4) + * * Revision 1.38 2000/07/24 08:49:09 calle * - Bugfix: capiminor_del_all_ack completely wrong :-( * @@ -216,7 +219,7 @@ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ #include <linux/slab.h> -static char *revision = "$Revision: 1.38 $"; +static char *revision = "$Revision: 1.39 $"; MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)"); @@ -325,11 +328,11 @@ static struct capidev *capidev_openlist = 0; static struct capiminor *minors = 0; #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ -static kmem_cache_t *capidev_cachep = 0; -static kmem_cache_t *capincci_cachep = 0; +static kmem_cache_t *capidev_cachep = 0; +static kmem_cache_t *capincci_cachep = 0; #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE -static kmem_cache_t *capiminor_cachep = 0; -static kmem_cache_t *capidh_cachep = 0; +static kmem_cache_t *capiminor_cachep = 0; +static kmem_cache_t *capidh_cachep = 0; #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE @@ -1239,7 +1242,7 @@ capi_release(struct inode *inode, struct file *file) capincci_free(cdev, 0xffffffff); capidev_free(cdev); file->private_data = NULL; - + MOD_DEC_USE_COUNT; #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capi_release %d\n", GET_USE_COUNT(THIS_MODULE)); @@ -1251,13 +1254,13 @@ capi_release(struct inode *inode, struct file *file) static struct file_operations capi_fops = { owner: THIS_MODULE, - llseek: capi_llseek, - read: capi_read, - write: capi_write, - poll: capi_poll, - ioctl: capi_ioctl, - open: capi_open, - release: capi_release, + llseek: capi_llseek, + read: capi_read, + write: capi_write, + poll: capi_poll, + ioctl: capi_ioctl, + open: capi_open, + release: capi_release, }; #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE @@ -1980,9 +1983,9 @@ static void alloc_exit(void) static int alloc_init(void) { - capidev_cachep = kmem_cache_create("capi20_dev", + capidev_cachep = kmem_cache_create("capi20_dev", sizeof(struct capidev), - 0, + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!capidev_cachep) { @@ -1990,9 +1993,9 @@ static int alloc_init(void) return -ENOMEM; } - capincci_cachep = kmem_cache_create("capi20_ncci", + capincci_cachep = kmem_cache_create("capi20_ncci", sizeof(struct capincci), - 0, + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!capincci_cachep) { @@ -2000,18 +2003,18 @@ static int alloc_init(void) return -ENOMEM; } #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - capidh_cachep = kmem_cache_create("capi20_dh", + capidh_cachep = kmem_cache_create("capi20_dh", sizeof(struct datahandle_queue), - 0, + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!capidh_cachep) { alloc_exit(); return -ENOMEM; } - capiminor_cachep = kmem_cache_create("capi20_minor", + capiminor_cachep = kmem_cache_create("capi20_minor", sizeof(struct capiminor), - 0, + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!capiminor_cachep) { diff --git a/drivers/isdn/avmb1/capidrv.c b/drivers/isdn/avmb1/capidrv.c index 0b04920f8..58b2eb9c6 100644 --- a/drivers/isdn/avmb1/capidrv.c +++ b/drivers/isdn/avmb1/capidrv.c @@ -2183,50 +2183,6 @@ static void enable_dchannel_trace(capidrv_contr *card) send_message(card, &cmdcmsg); } -static void disable_dchannel_trace(capidrv_contr *card) -{ - __u8 manufacturer[CAPI_MANUFACTURER_LEN]; - capi_version version; - __u16 contr = card->contrnr; - __u16 errcode; - __u16 avmversion[3]; - - errcode = (*capifuncs->capi_get_manufacturer)(contr, manufacturer); - if (errcode != CAPI_NOERROR) { - printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n", - card->name, errcode); - return; - } - if (strstr(manufacturer, "AVM") == 0) { - printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n", - card->name, manufacturer); - return; - } - errcode = (*capifuncs->capi_get_version)(contr, &version); - if (errcode != CAPI_NOERROR) { - printk(KERN_ERR "%s: can't get version (0x%x)\n", - card->name, errcode); - return; - } - avmversion[0] = (version.majormanuversion >> 4) & 0x0f; - avmversion[1] = (version.majormanuversion << 4) & 0xf0; - avmversion[1] |= (version.minormanuversion >> 4) & 0x0f; - avmversion[2] |= version.minormanuversion & 0x0f; - - if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) { - printk(KERN_INFO "%s: D2 trace disabled\n", card->name); - } else { - printk(KERN_INFO "%s: D3 trace disabled\n", card->name); - } - capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid, - card->msgid++, - contr, - 0x214D5641, /* ManuID */ - 0, /* Class */ - 1, /* Function */ - (_cstruct)"\004\000\000\000\000"); - send_message(card, &cmdcmsg); -} static void send_listen(capidrv_contr *card) { @@ -2288,15 +2244,15 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp) card->interface.writecmd = 0; card->interface.readstat = if_readstat; card->interface.features = ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_TRANS | - ISDN_FEATURE_L3_TRANS | + ISDN_FEATURE_L2_TRANS | + ISDN_FEATURE_L3_TRANS | ISDN_FEATURE_P_UNKNOWN | ISDN_FEATURE_L2_X75I | ISDN_FEATURE_L2_X75UI | ISDN_FEATURE_L2_X75BUI; if (profp->support1 & (1<<2)) card->interface.features |= ISDN_FEATURE_L2_V11096 | - ISDN_FEATURE_L2_V11019 | + ISDN_FEATURE_L2_V11019 | ISDN_FEATURE_L2_V11038; if (profp->support1 & (1<<8)) card->interface.features |= ISDN_FEATURE_L2_MODEM; diff --git a/drivers/isdn/avmb1/capifs.c b/drivers/isdn/avmb1/capifs.c index ec4f9c559..64ef8436c 100644 --- a/drivers/isdn/avmb1/capifs.c +++ b/drivers/isdn/avmb1/capifs.c @@ -1,11 +1,20 @@ /* - * $Id: capifs.c,v 1.6 2000/04/03 13:29:25 calle Exp $ + * $Id: capifs.c,v 1.9 2000/08/20 07:30:13 keil Exp $ * * (c) Copyright 2000 by Carsten Paeth (calle@calle.de) * * Heavily based on devpts filesystem from H. Peter Anvin * * $Log: capifs.c,v $ + * Revision 1.9 2000/08/20 07:30:13 keil + * changes for 2.4 + * + * Revision 1.8 2000/07/20 10:23:13 calle + * Include isdn_compat.h for people that don't use -p option of std2kern. + * + * Revision 1.7 2000/06/18 16:09:54 keil + * more changes for 2.4 + * * Revision 1.6 2000/04/03 13:29:25 calle * make Tim Waugh happy (module unload races in 2.3.99-pre3). * no real problem there, but now it is much cleaner ... @@ -60,7 +69,7 @@ MODULE_AUTHOR("Carsten Paeth <calle@calle.de>"); -static char *revision = "$Revision: 1.6 $"; +static char *revision = "$Revision: 1.9 $"; struct capifs_ncci { struct inode *inode; @@ -130,12 +139,12 @@ static int capifs_root_readdir(struct file *filp, void *dirent, filldir_t filldi switch(nr) { case 0: - if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0) + if (filldir(dirent, ".", 1, nr, inode->i_ino, DT_DIR) < 0) return 0; filp->f_pos = ++nr; /* fall through */ case 1: - if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0) + if (filldir(dirent, "..", 2, nr, inode->i_ino, DT_DIR) < 0) return 0; filp->f_pos = ++nr; /* fall through */ @@ -147,7 +156,7 @@ static int capifs_root_readdir(struct file *filp, void *dirent, filldir_t filldi char *p = numbuf; if (np->type) *p++ = np->type; sprintf(p, "%u", np->num); - if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr) < 0 ) + if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr, DT_UNKNOWN) < 0 ) return 0; } filp->f_pos = ++nr; @@ -228,9 +237,9 @@ static void capifs_put_super(struct super_block *sb) for ( i = 0 ; i < sbi->max_ncci ; i++ ) { if ( (inode = sbi->nccis[i].inode) ) { - if ( atomic_read(&inode->i_count) != 1 ) + if (atomic_read(&inode->i_count) != 1 ) printk("capifs_put_super: badness: entry %d count %d\n", - i, atomic_read(&inode->i_count)); + i, (unsigned)atomic_read(&inode->i_count)); inode->i_nlink--; iput(inode); } diff --git a/drivers/isdn/avmb1/t1isa.c b/drivers/isdn/avmb1/t1isa.c index b87f7293e..b6ec1aa52 100644 --- a/drivers/isdn/avmb1/t1isa.c +++ b/drivers/isdn/avmb1/t1isa.c @@ -1,11 +1,17 @@ /* - * $Id: t1isa.c,v 1.11 2000/04/03 13:29:25 calle Exp $ + * $Id: t1isa.c,v 1.13 2000/08/04 15:36:31 calle Exp $ * * Module for AVM T1 HEMA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: t1isa.c,v $ + * Revision 1.13 2000/08/04 15:36:31 calle + * copied wrong from file to file :-( + * + * Revision 1.12 2000/08/04 12:20:08 calle + * - Fix unsigned/signed warning in the right way ... + * * Revision 1.11 2000/04/03 13:29:25 calle * make Tim Waugh happy (module unload races in 2.3.99-pre3). * no real problem there, but now it is much cleaner ... @@ -85,7 +91,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.11 $"; +static char *revision = "$Revision: 1.13 $"; /* ------------------------------------------------------------- */ @@ -282,25 +288,30 @@ static void t1_handle_interrupt(avmcard * card) case RECEIVE_TASK_READY: ApplId = (unsigned) b1_get_word(card->port); MsgLen = t1_get_slice(card->port, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: task %d \"%s\" ready.\n", card->name, ApplId, card->msgbuf); break; case RECEIVE_DEBUGMSG: MsgLen = t1_get_slice(card->port, card->msgbuf); - card->msgbuf[MsgLen--] = 0; - while ( MsgLen >= 0 - && ( card->msgbuf[MsgLen] == '\n' - || card->msgbuf[MsgLen] == '\r')) - card->msgbuf[MsgLen--] = 0; + card->msgbuf[MsgLen] = 0; + while ( MsgLen > 0 + && ( card->msgbuf[MsgLen-1] == '\n' + || card->msgbuf[MsgLen-1] == '\r')) { + card->msgbuf[MsgLen-1] = 0; + MsgLen--; + } printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); break; + case 0xff: printk(KERN_ERR "%s: card reseted ?\n", card->name); return; diff --git a/drivers/isdn/avmb1/t1pci.c b/drivers/isdn/avmb1/t1pci.c index 6248419be..d2303feab 100644 --- a/drivers/isdn/avmb1/t1pci.c +++ b/drivers/isdn/avmb1/t1pci.c @@ -1,11 +1,14 @@ /* - * $Id: t1pci.c,v 1.10 2000/07/20 10:21:21 calle Exp $ + * $Id: t1pci.c,v 1.11 2000/08/08 09:24:19 calle Exp $ * * Module for AVM T1 PCI-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: t1pci.c,v $ + * Revision 1.11 2000/08/08 09:24:19 calle + * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI + * * Revision 1.10 2000/07/20 10:21:21 calle * Bugfix: driver will not be unregistered, if not cards were detected. * this result in an oops in kcapi.c @@ -60,13 +63,12 @@ #include <linux/pci.h> #include <linux/capi.h> #include <asm/io.h> -#include <linux/isdn.h> #include "capicmd.h" #include "capiutil.h" #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.10 $"; +static char *revision = "$Revision: 1.11 $"; #undef CONFIG_T1PCI_DEBUG #undef CONFIG_T1PCI_POLLDEBUG diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c index bd065a48d..5b08e8025 100644 --- a/drivers/isdn/divert/divert_procfs.c +++ b/drivers/isdn/divert/divert_procfs.c @@ -1,5 +1,5 @@ /* - * $Id: divert_procfs.c,v 1.8 2000/03/03 16:37:11 kai Exp $ + * $Id: divert_procfs.c,v 1.9 2000/08/20 07:40:14 keil Exp $ * * Filesystem handling for the diversion supplementary services. * @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: divert_procfs.c,v $ + * Revision 1.9 2000/08/20 07:40:14 keil + * changes from 2.4 + * * Revision 1.8 2000/03/03 16:37:11 kai * incorporated some cosmetic changes from the official kernel tree back * into CVS diff --git a/drivers/isdn/eicon/Divas_mod.c b/drivers/isdn/eicon/Divas_mod.c new file mode 100644 index 000000000..8cb2a0409 --- /dev/null +++ b/drivers/isdn/eicon/Divas_mod.c @@ -0,0 +1,172 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.15 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include <linux/config.h> +#include <linux/fs.h> +#undef N_DATA + +#include <linux/kernel.h> + +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/ioport.h> +#include <linux/malloc.h> +#include <errno.h> + +#include "adapter.h" +#include "uxio.h" + +#ifdef MODULE +#include "idi.h" +void EtdM_DIDD_Write(DESCRIPTOR *, int); +EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Read); +EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Write); +EXPORT_SYMBOL_NOVERS(DivasPrintf); +#define Divas_init init_module +#endif + +extern char *file_check(void); + +int DivasCardsDiscover(void); + +int +Divas_init(void) +{ + printk(KERN_DEBUG "DIVA Server Driver - initialising\n"); + + printk(KERN_DEBUG "DIVA Server Driver - Version 2.0.12 (%s)\n",file_check()); + + +#if !defined(CONFIG_PCI) + printk(KERN_WARNING "CONFIG_PCI is not defined!\n"); + return -ENODEV; +#endif + + if (pci_present()) + { + if (DivasCardsDiscover() < 0) + { + printk(KERN_WARNING "Divas: Not loaded\n"); + return -ENODEV; + } + } + else + { + printk(KERN_WARNING "Divas: No PCI bus present\n"); + return -ENODEV; + } + + return 0; +} + +#ifdef MODULE +void +cleanup_module(void) +{ + card_t *pCard; + word wCardIndex; + extern int Divas_major; + + printk(KERN_DEBUG "DIVA Server Driver - unloading\n"); + + pCard = DivasCards; + for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++) + { + if ((pCard->hw) && (pCard->hw->in_use)) + { + + (*pCard->card_reset)(pCard); + + UxIsrRemove(pCard->hw, pCard); + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + + if(pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + release_region(pCard->hw->io_base,0x20); + release_region(pCard->hw->reset_base,0x80); + } + + // If this is a 4BRI ... + if (pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + // Skip over the next 3 virtual adapters + wCardIndex += 3; + + // But free their handles + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + } + } + pCard++; + } + + unregister_chrdev(Divas_major, "Divas"); +} + +void mod_inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + +void mod_dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + +#else +Divas_setup(char *str, int *ints) +{ +} +#endif + diff --git a/drivers/isdn/eicon/Makefile b/drivers/isdn/eicon/Makefile index 306aac0e8..63c557492 100644 --- a/drivers/isdn/eicon/Makefile +++ b/drivers/isdn/eicon/Makefile @@ -1,8 +1,37 @@ L_OBJS := M_OBJS := -O_OBJS := eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o eicon_io.o +LX_OBJS := +MX_OBJS := +O_OBJS := +OX_OBJS := +L_TARGET := +O_TARGET := + +ifeq ($(CONFIG_ISDN_DRV_EICON_STANDALONE),y) + + ifeq ($(CONFIG_PCI),y) + O_OBJS += common.o idi.o bri.o pri.o log.o xlog.o kprintf.o fpga.o fourbri.o + O_OBJS += lincfg.o linchr.o linsys.o linio.o + O_OBJS += fcheck.o + OX_OBJS += Divas_mod.o + endif + +else + + OX_OBJS += eicon_mod.o + O_OBJS := eicon_isa.o eicon_pci.o eicon_idi.o eicon_io.o + O_OBJS += fcheck.o + ifeq ($(CONFIG_PCI),y) + ifeq ($(CONFIG_ISDN_DRV_EICON_PCI),y) + O_OBJS += common.o idi.o bri.o pri.o log.o xlog.o kprintf.o fpga.o fourbri.o + O_OBJS += lincfg.o linchr.o linsys.o linio.o + endif + endif + +endif O_TARGET := + ifeq ($(CONFIG_ISDN_DRV_EICON),y) O_TARGET += eicon.o else @@ -10,4 +39,14 @@ else M_OBJS = eicon.o endif + include $(TOPDIR)/Rules.make + +MD5FILES += common.c idi.c bri.c pri.c log.c xlog.c kprintf.c fpga.c \ + fourbri.c fcheck.c + +FCHECK = $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?) + +fcheck.o: $(MD5FILES) + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -D FILECHECK=$(FCHECK) -c -o fcheck.o fcheck.c + diff --git a/drivers/isdn/eicon/adapter.h b/drivers/isdn/eicon/adapter.h new file mode 100644 index 000000000..cabba68be --- /dev/null +++ b/drivers/isdn/eicon/adapter.h @@ -0,0 +1,265 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.7 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* Main internal include file for Diva Server driver */ + +#if !defined(ADAPTER_H) +#define ADAPTER_H + +#include "sys.h" +#include "idi.h" +#include "divas.h" +#undef ID_MASK +#include "pc.h" + +#define XMOREC 0x1f +#define XMOREF 0x20 +#define XBUSY 0x40 +#define RMORE 0x80 + + /* structure for all information we have to keep on a per */ + /* adapater basis */ + +typedef struct adapter_s ADAPTER; + +struct adapter_s { + void * io; + + byte IdTable[256]; + byte ReadyInt; + + byte (* ram_in)(ADAPTER * a, void * adr); + word (* ram_inw)(ADAPTER * a, void * adr); + void (* ram_in_buffer)(ADAPTER * a, void * adr, void * P, word length); + void (* ram_look_ahead)(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e); + + void (* ram_out)(ADAPTER * a, void * adr, byte data); + void (* ram_outw)(ADAPTER * a, void * adr, word data); + void (* ram_out_buffer)(ADAPTER * a, void * adr, void * P, word length); + + void (* ram_inc)(ADAPTER * a, void * adr); +}; + +typedef struct card card_t; + +typedef int card_load_fn_t(card_t *card, dia_load_t *load); +typedef int card_config_fn_t(card_t *card, dia_config_t *config); +typedef int card_start_fn_t(card_t *card, byte *channels); +typedef int card_reset_fn_t(card_t *card); +typedef int card_mem_get_fn_t(card_t *card, mem_block_t *mem_block); + +#define MAX_PENTITIES 256 /* Number of entities primary adapter */ +#define MAX_ENTITIES 16 /* Number of entities standard adapter */ + +typedef struct e_info_s E_INFO; + +struct e_info_s +{ + ENTITY *e; /* entity pointer */ + byte next; /* chaining index */ + word assign_ref; /* assign reference */ +}; + +/* DIVA card info (details hidden from user) */ + +typedef struct ux_diva_card_s ux_diva_card_t; + +/* card info */ + +struct card +{ + ADAPTER a; /* per-adapter information */ + dia_card_t cfg; /* card configuration */ + int state; /* State of the adapter */ + dword serial_no; /* serial number */ + int test_int_pend; /* set for interrupt testing */ + ux_diva_card_t *hw; /* O/S-specific handle */ + card_reset_fn_t *card_reset; /* call this to reset card */ + card_load_fn_t *card_load; /* call this to load card */ + card_config_fn_t *card_config; /* call this to config card */ + card_start_fn_t *card_start; /* call this to start card */ + card_mem_get_fn_t *card_mem_get; /* call this to get card memory */ + E_INFO *e_tbl; /* table of ENTITY pointers */ + byte e_head; /* list of active ENTITIES */ + byte e_tail; /* list of active ENTITIES */ + int e_count; /* # of active ENTITIES */ + int e_max; /* total # of ENTITIES */ + byte assign; /* assign queue entry */ + PBUFFER RBuffer; /* Copy of receive lookahead buffer */ + int log_types; /* bit-mask of active logs */ + word xlog_offset; /* offset to XLOG buffer on card */ + void (*out)(ADAPTER *a); + byte (*dpc)(ADAPTER * a); + byte (*test_int)(ADAPTER * a); + void (*clear_int)(ADAPTER * a); + void (*reset_int)(card_t *c); + int is_live; + + int (*card_isr)(card_t *card); + + int int_pend; /* interrupt pending */ + long interrupt_reentered; + long dpc_reentered; + int set_xlog_request; + +} ; + +/* card information */ + +#define MAX_CARDS 20 /* max number of cards on a system */ + +extern +card_t DivasCards[]; + +extern +int DivasCardNext; + +extern +dia_config_t DivasCardConfigs[]; + +extern +byte DivasFlavourConfig[]; + +/*------------------------------------------------------------------*/ +/* public functions of IDI common code */ +/*------------------------------------------------------------------*/ + +void DivasOut(ADAPTER * a); +byte DivasDpc(ADAPTER * a); +byte DivasTestInt(ADAPTER * a); +void DivasClearInt(ADAPTER * a); + +/*------------------------------------------------------------------*/ +/* public functions of configuration platform-specific code */ +/*------------------------------------------------------------------*/ + +int DivasConfigGet(dia_card_t *card); + +/*------------------------------------------------------------------*/ +/* public functions of LOG related code */ +/*------------------------------------------------------------------*/ + +void DivasXlogReq(int card_num); +int DivasXlogRetrieve(card_t *card); +void DivasLog(dia_log_t *log); +void DivasLogIdi(card_t *card, ENTITY *e, int request); + +/*------------------------------------------------------------------*/ +/* public functions to initialise cards for each type supported */ +/*------------------------------------------------------------------*/ + +int DivasPriInit(card_t *card, dia_card_t *cfg); + +int DivasBriInit(card_t *card, dia_card_t *cfg); +int Divas4BriInit(card_t *card, dia_card_t *cfg); +void DivasBriPatch(card_t *card); + +/*------------------------------------------------------------------*/ +/* public functions of log common code */ +/*------------------------------------------------------------------*/ + +extern char *DivasLogFifoRead(void); +extern void DivasLogFifoWrite(char *entry, int length); +extern int DivasLogFifoEmpty(void); +extern int DivasLogFifoFull(void); +extern void DivasLogAdd(void *buffer, int length); + +/*------------------------------------------------------------------*/ +/* public functions of misc. platform-specific code */ +/*------------------------------------------------------------------*/ + +int DivasDpcSchedule(void); +void DivasDoDpc(void *); +void DivasDoRequestDpc(void *pData); +int DivasScheduleRequestDpc(void); + +/* table of IDI request functions */ + +extern +IDI_CALL DivasIdiRequest[]; + +/* + * intialisation entry point + */ + +int DivasInit(void); + +/* + * Get information on the number and type of cards present + */ + +extern +int DivasCardsDiscover(void); + +/* + * initialise a new card + */ + +int DivasCardNew(dia_card_t *card); + +/* + * configure specified card + */ + +int DivasCardConfig(dia_config_t *config); + +/* + * load specified binary code onto card + */ + +int DivasCardLoad(dia_load_t *load); + +/* + * start specified card running + */ + +int DivasCardStart(int card_id); + +/* + * ISR for card + * Returns 0 if specified card was interrupting + */ + +int DivasIsr(void *arg); + +/* + * Get number of active cards + */ + +int DivasGetNum(void); + +/* + * Get list of active cards + */ + +int DivasGetList(dia_card_list_t *card_list); + +/* definitions common to several card types */ + +#define DIVAS_SHARED_OFFSET (0x1000) + +#endif /* ADAPTER_H */ diff --git a/drivers/isdn/eicon/bri.c b/drivers/isdn/eicon/bri.c new file mode 100644 index 000000000..5a8afc11d --- /dev/null +++ b/drivers/isdn/eicon/bri.c @@ -0,0 +1,717 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.8 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <sys/types.h> + +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" +#include "dsp_defs.h" + +#include "adapter.h" +#include "uxio.h" + +#define PCI_COMMAND 0x04 +#define PCI_STATUS 0x06 +#define PCI_LATENCY 0x0D +#define PCI_BADDR0 0x10 +#define PCI_BADDR1 0x14 +#define PCI_BADDR2 0x18 + +#define DIVAS_SIGNATURE 0x4447 + +/* offset to start of MAINT area (used by xlog) */ + +#define DIVAS_MAINT_OFFSET 0xff00 /* value for BRI card */ + +#define PROTCAP_TELINDUS 0x1 +#define PROTCAP_V90D 0x8 + +word GetProtFeatureValue(char *sw_id); +byte io_in(ADAPTER *a, void *adr); +word io_inw(ADAPTER *a, void *adr); +void io_in_buffer(ADAPTER *a, void *adr, void *P, word length); +void io_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e); +void io_out(ADAPTER *a, void *adr, byte data); +void io_outw(ADAPTER *a, void *adr, word data); +void io_out_buffer(ADAPTER *a, void *adr, void *P, word length); +void io_inc(ADAPTER *a, void *adr); + +static int diva_server_bri_test_int(card_t *card); + +#define PLX_IOBASE 0 +#define DIVAS_IOBASE 1 + +#define REG_DATA 0x00 +#define REG_ADDRLO 0x04 +#define REG_ADDRHI 0x0C +#define REG_IOCTRL 0x10 + +#define M_PCI_RESET 0x10 + +byte UxCardPortIoIn(ux_diva_card_t *card, byte *base, int offset); +word UxCardPortIoInW(ux_diva_card_t *card, byte *base, int offset); +void UxCardPortIoOut(ux_diva_card_t *card, byte *base, int offset, byte); +void UxCardPortIoOutW(ux_diva_card_t *card, byte *base, int offset, word); + +int DivasBRIInitPCI(card_t *card, dia_card_t *cfg); +int bri_ISR (card_t* card); + +static +int diva_server_bri_reset(card_t *card) +{ + byte *DivasIOBase; + word i; + dword dwWait; + + UxCardLog(0); + + DPRINTF(("divas: resetting BRI adapter")); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0); + + for (i=0; i < 50000; i++) + ; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_DATA , 0); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x0000); + + for (i=0; i<0x8000; i++) + { + UxCardPortIoOutW(card->hw, DivasIOBase, REG_DATA , 0); + } + + for (dwWait=0; dwWait < 0x00FFFFFF; dwWait++) + ; + + UxCardMemDetach(card->hw, DivasIOBase); + + return 0; +} + +static +void diva_server_bri_reset_int(card_t *card) +{ + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x08); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +static +int diva_server_bri_start(card_t *card, byte *channels) +{ + byte *DivasIOBase, *PLXIOBase; + word wSig = 0; + word i; + dword dwSerialNum; + byte bPLX9060 = FALSE; + + DPRINTF(("divas: starting Diva Server BRI card")); + + card->is_live = FALSE; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x1E); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA , 0); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA , 0); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x08); + + /* wait for signature to indicate card has started */ + for (i = 0; i < 300; i++) + { + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x1E); + wSig = UxCardPortIoInW(card->hw, DivasIOBase, REG_DATA); + + if (wSig == DIVAS_SIGNATURE) + { + DPRINTF(("divas: card started after %d ms", i * 10)); + break; + } + UxPause(10); + } + + if (wSig != DIVAS_SIGNATURE) + { + DPRINTF(("divas: card failed to start (Sig=0x%x)", wSig)); + UxCardMemDetach(card->hw, DivasIOBase); + return -1; + } + + card->is_live = TRUE; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x3F6); + *channels = UxCardPortIoInW(card->hw, DivasIOBase, REG_DATA); + + UxCardMemDetach(card->hw, DivasIOBase); + + PLXIOBase = UxCardMemAttach(card->hw, PLX_IOBASE); + + bPLX9060 = UxCardPortIoInW(card->hw, PLXIOBase, 0x6C) | UxCardPortIoInW(card->hw, PLXIOBase, 0x6E); + + if (bPLX9060) + { + dwSerialNum = (UxCardPortIoInW(card->hw, PLXIOBase, 0x1E) << 16) | + (UxCardPortIoInW(card->hw, PLXIOBase, 0x22)); + DPRINTF(("divas: PLX9060 in use. Serial number 0x%04X", dwSerialNum)); + } + else + { + dwSerialNum = (UxCardPortIoInW(card->hw, PLXIOBase, 0x22) << 16) | + (UxCardPortIoInW(card->hw, PLXIOBase, 0x26)); + DPRINTF(("divas: PLX9050 in use. Serial number 0x%04X", dwSerialNum)); + } + + UxCardMemDetach(card->hw, PLXIOBase); + + card->serial_no = dwSerialNum; + + diva_server_bri_test_int(card); + + return 0; +} + +static +int diva_server_bri_load(card_t *card, dia_load_t *load) +{ + byte *DivasIOBase; + dword r3000_base; + dword dwAddr, dwLength, i; + word wTest, aWord; + + DPRINTF(("divas: loading Diva Server BRI card")); + + switch (load->code_type) + { + case DIA_CPU_CODE: + DPRINTF(("divas: loading RISC %s", &load->code[0x80])); + + card->hw->features = GetProtFeatureValue((char *)&load->code[0x80]); + DPRINTF(("divas: features 0x%x", card->hw->features)); + if (card->hw->features == 0xFFFF) + { + DPRINTF(("divas: invalid feature string failed load\n")); + return -1; + } + + r3000_base = 0; + break; + + case DIA_DSP_CODE: + DPRINTF(("divas: DSP code \"%s\"", load->code)); + + if ((card->hw->features) && (!(card->hw->features & PROTCAP_TELINDUS))) + { + DPRINTF(("divas: only Telindus style binaries supported")); + return -1; + } + + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + DPRINTF(("divas: V.90 DSP binary")); + r3000_base = (0xBF790000 + (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC)); + } + else + { + DPRINTF(("divas: non-V.90 DSP binary")); + r3000_base = (0xBF7A0000 + (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC)); + } + DPRINTF(("divas: loading at 0x%x", r3000_base)); + break; + + case DIA_TABLE_CODE: + DPRINTF(("divas: TABLE code")); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + r3000_base = 0xBF790000 + sizeof(dword); + } + else + { + r3000_base = 0xBF7A0000 + sizeof(dword); + } + + break; + + case DIA_DLOAD_CNT: + DPRINTF(("divas: COUNT code")); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + r3000_base = 0xBF790000; + } + else + { + r3000_base = 0xBF7A0000; + } + break; + + default: + DPRINTF(("divas: unknown code type %d", load->code_type)); + return -1; + break; + } + + DPRINTF(("divas: Writing %d bytes to adapter, address 0x%x", load->length, r3000_base)); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + DPRINTF(("divas: Attached to 0x%04X", DivasIOBase)); + + dwLength = load->length; + + for (i=0; i < dwLength; i++) + { + dwAddr = r3000_base + i; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, dwAddr >> 16); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, dwAddr); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, load->code[i]); + } + + DPRINTF(("divas: Verifying")); + + for (i=0; i<dwLength; i++) + { + dwAddr = r3000_base + i; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, dwAddr >> 16); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, dwAddr); + + wTest = UxCardPortIoIn(card->hw, DivasIOBase, REG_DATA); + + aWord = load->code[i]; + + if (wTest != aWord) + { + DPRINTF(("divas: load verify failed on byte %d", i)); + DPRINTF(("divas: RAM 0x%x File 0x%x",wTest,aWord)); + + UxCardMemDetach(card->hw, DivasIOBase); + + return -1; + } + } + + DPRINTF(("divas: Loaded and verified. Detaching from adapter")); + + UxCardMemDetach(card->hw, DivasIOBase); + + UxCardLog(0); + + return 0; +} + +static +int diva_server_bri_config(card_t *card, dia_config_t *config) +{ + byte *DivasIOBase, i; + + DPRINTF(("divas: configuring Diva Server BRI card")); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 8); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->tei); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 9); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->nt2); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 10); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 11); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->watchdog); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 12); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->permanent); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 13); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 14); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->stable_l2); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 15); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->no_order_check); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 16); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 17); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 18); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->low_channel); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 19); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->prot_version); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 20); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->crc4); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 21); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + DPRINTF(("divas: Signifying V.90")); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 22); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 4); + } + else + { + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 22); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + } + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 23); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, card->serial_no & 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 24); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, (card->serial_no >> 8) & 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 25); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, (card->serial_no >> 16) & 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 26); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 21); + + for (i=0; i<32; i++) + { + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 32+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].oad[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 64+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].osa[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 96+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].spid[i]); + + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 128+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].oad[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 160+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].osa[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 192+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].spid[i]); + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return 0; +} + +void DivasBriPatch(card_t *card) +{ + dword PLXIOBase = 0; + dword DivasIOBase = 0; + + PLXIOBase = card->cfg.reset_base; + DivasIOBase = card->cfg.io_base; + + if(card->hw == NULL) + { + DPRINTF(("Divas: BRI PATCH (PLX chip) card->hw is null")); + return; + } + + if (PLXIOBase == 0) + { + DPRINTF(("Divas: BRI (PLX chip) cannot be patched. The BRI adapter may")); + DPRINTF(("Divas: not function properly. If you do encounter problems,")); + DPRINTF(("Divas: ensure that your machine is using the latest BIOS.")); + return; + } + + DPRINTF(("Divas: PLX I/O Base 0x%x", PLXIOBase)); + DPRINTF(("Divas: Divas I/O Base 0x%x", DivasIOBase)); + + if (PLXIOBase & 0x80) + { + dword dwSize, dwSerialNum, dwCmd; + boolean_t bPLX9060; + word wSerHi, wSerLo; + + DPRINTF(("Divas: Patch required")); + dwCmd = 0; + UxPciConfigWrite(card->hw, 4, PCI_COMMAND, &dwCmd); + + PLXIOBase &= ~0x80; + UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &PLXIOBase); + + dwSize = 0xFFFFFFFF; + UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &dwSize); + UxPciConfigRead(card->hw, 4, PCI_BADDR1, &dwSize); + + dwSize = (~ (dwSize & ~7)) + 1; + + DivasIOBase = PLXIOBase + dwSize; + + card->cfg.reset_base = PLXIOBase; + card->cfg.io_base = DivasIOBase; + UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &card->cfg.reset_base); + UxPciConfigWrite(card->hw, 4, PCI_BADDR2, &card->cfg.io_base); + + dwCmd = 5; + UxPciConfigWrite(card->hw, 4, PCI_COMMAND, &dwCmd); + + bPLX9060 = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6C) | + UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6E); + + if (bPLX9060) + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x1E); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + dwSerialNum = (wSerHi << 16) | wSerLo; + UxCardLog(0); + } + else + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x26); + dwSerialNum = (wSerHi << 16) | wSerLo; + UxCardLog(0); + } + } + else + { + word wSerHi, wSerLo; + boolean_t bPLX9060; + dword dwSerialNum; + + DPRINTF(("divas: No patch required")); + + bPLX9060 = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6C) | + UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6E); + + if (bPLX9060) + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x1E); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + dwSerialNum = (wSerHi << 16) | wSerLo; + } + else + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x26); + dwSerialNum = (wSerHi << 16) | wSerLo; + } + } + DPRINTF(("Divas: After patching:")); + DPRINTF(("Divas: PLX I/O Base 0x%x", PLXIOBase)); + DPRINTF(("Divas: Divas I/O Base 0x%x", DivasIOBase)); + +} + +#define TEST_INT_DIVAS_BRI 0x12 +static +int diva_server_bri_test_int(card_t *card) +{ + boolean_t bPLX9060 = FALSE; + byte *PLXIOBase = NULL, *DivasIOBase = NULL; + + DPRINTF(("divas: test interrupt for Diva Server BRI card")); + + PLXIOBase = UxCardMemAttach(card->hw, PLX_IOBASE); + + bPLX9060 = UxCardPortIoInW(card->hw, PLXIOBase, 0x6C) || UxCardPortIoInW(card->hw, PLXIOBase, 0x6E); + + if (bPLX9060) + { /* PLX9060 */ + UxCardPortIoOut(card->hw, PLXIOBase, 0x69, 0x09); + } + else + { /* PLX9050 */ + UxCardPortIoOut(card->hw, PLXIOBase, 0x4C, 0x41); + } + + card->test_int_pend = TEST_INT_DIVAS_BRI; + + UxCardMemDetach(card->hw, PLXIOBase); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x89); + + UxCardMemDetach(card->hw, DivasIOBase); + + return 0; +} + +static +int diva_server_bri_mem_get(card_t *card, mem_block_t *mem_block) +{ + dword user_addr = mem_block->addr; + word length = 0; + dword addr; + word i; + byte *DivasIOBase; + + DPRINTF(("divas: Retrieving memory from 0x%x", user_addr)); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + addr = user_addr; + + for (i=0; i < (16 * 8); i++) + { + addr = user_addr + i; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, addr >> 16); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, (word) addr); + + mem_block->data[i] = UxCardPortIoIn(card->hw, DivasIOBase, REG_DATA); + length++; + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return length; +} + +int DivasBriInit(card_t *card, dia_card_t *cfg) +{ + DPRINTF(("divas: initialise Diva Server BRI card")); + + if (DivasBRIInitPCI(card, cfg) == -1) + { + return -1; + } + + card->card_reset = diva_server_bri_reset; + card->card_start = diva_server_bri_start; + card->card_load = diva_server_bri_load; + card->card_config = diva_server_bri_config; + card->reset_int = diva_server_bri_reset_int; + card->card_mem_get = diva_server_bri_mem_get; + + card->xlog_offset = DIVAS_MAINT_OFFSET; + + card->out = DivasOut; + card->test_int = DivasTestInt; + card->dpc = DivasDpc; + card->clear_int = DivasClearInt; + card->card_isr = bri_ISR; + + card->a.ram_out = io_out; + card->a.ram_outw = io_outw; + card->a.ram_out_buffer = io_out_buffer; + card->a.ram_inc = io_inc; + + card->a.ram_in = io_in; + card->a.ram_inw = io_inw; + card->a.ram_in_buffer = io_in_buffer; + card->a.ram_look_ahead = io_look_ahead; + + return 0; +} + +word GetProtFeatureValue(char *sw_id) +{ + word features = 0; + + while ((*sw_id) && (sw_id[0] != '[')) + sw_id++; + + if (sw_id == NULL) + { + DPRINTF(("divas: no feature string present")); + features = -1; + } + else + { + byte i, shifter; + + sw_id += 3; + + for (i=0, shifter=12; i<4; i++, shifter-=4) + { + if ((sw_id[i] >= '0') && (sw_id[i] <= '9')) + { + features |= (sw_id[i] - '0') << shifter; + } + else if ((sw_id[i] >= 'a') && (sw_id[i] <= 'f')) + { + features |= (sw_id[i] - 'a' + 10) << shifter; + } + else if ((sw_id[i] >= 'A') && (sw_id[i] <= 'F')) + { + features |= (sw_id[i] - 'A' + 10) << shifter; + } + else + { + DPRINTF(("divas: invalid feature string")); + return -1; + } + } + } + + return features; +} + + +int bri_ISR (card_t* card) +{ + int served = 0; + byte *DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + if (UxCardPortIoIn (card->hw, DivasIOBase, M_PCI_RESET) & 0x01) + { + served = 1; + card->int_pend += 1; + DivasDpcSchedule(); /* ISR DPC */ + UxCardPortIoOut (card->hw, DivasIOBase, M_PCI_RESET, 0x08); + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return (served != 0); +} + + diff --git a/drivers/isdn/eicon/common.c b/drivers/isdn/eicon/common.c new file mode 100644 index 000000000..4a4f77d9f --- /dev/null +++ b/drivers/isdn/eicon/common.c @@ -0,0 +1,896 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.15 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include "sys.h" +#include "idi.h" +#include "constant.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" + +#include "uxio.h" +#include <sys/types.h> + +#define MAX_ADDR_LEN + +#define DIVAS_LOAD_CMD 0x02 +#define DIVAS_START_CMD 0x03 +#define DIVAS_IRQ_RESET 0xC18 +#define DIVAS_IRQ_RESET_VAL 0xFE + +#define PCI_COMMAND 0x04 +#define PCI_STATUS 0x06 +#define PCI_LATENCY 0x0D +#define PCI_INTERRUPT 0x3C + +#define TEST_INT_DIVAS 0x11 +#define TEST_INT_DIVAS_BRI 0x12 +#define TEST_INT_DIVAS_Q 0x13 + +#define DIVAS_RESET 0x81 +#define DIVAS_LED1 0x04 +#define DIVAS_LED2 0x08 +#define DIVAS_LED3 0x20 +#define DIVAS_LED4 0x40 + +#define DIVAS_SIGNATURE 0x4447 + +#define MP_PROTOCOL_ADDR 0xA0011000 + +#define PLX_IOBASE 0 +#define DIVAS_IOBASE 1 + +typedef struct { + dword cmd; + dword addr; + dword len; + dword err; + dword live; + dword reserved[(0x1020>>2)-6]; + dword signature; + byte data[1]; +} diva_server_boot_t; + +int DivasCardNext; +card_t DivasCards[MAX_CARDS]; + +dia_config_t *DivasConfig(card_t *, dia_config_t *); + +static +DESCRIPTOR DIDD_Table[16]; +static +int DIDD_Length = 0; + +void EtdM_DIDD_Read( DESCRIPTOR *table, int *tablelength ) +{ + int table_size = sizeof(DIDD_Table); + + bcopy((caddr_t)DIDD_Table, (caddr_t)table, table_size); + + *tablelength = DIDD_Length; + + return; +} + +static +void EtdM_DIDD_Write(DESCRIPTOR *table, int tablelength) +{ + int table_size = sizeof(DIDD_Table); + + bcopy((caddr_t)table, (caddr_t)DIDD_Table, table_size); + + DIDD_Length = tablelength; + + return; +} + +static +void init_idi_tab(void) +{ + int length = 0; + + DESCRIPTOR d[16]; + + EtdM_DIDD_Read(d, &length); + + d[length].type = IDI_DIMAINT; /* identify the DIMAINT entry */ + d[length].channels = 0; /* zero channels associated with dimaint*/ + d[length].features = 0; /* no features associated with dimaint */ + d[length].request = (IDI_CALL) DivasPrintf; + length++; + + EtdM_DIDD_Write(d, length); + + return; +} + +/* + * I/O routines for memory mapped cards + */ + +byte mem_in(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + unsigned char *b, *m; + byte value; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + value = UxCardMemIn(card->hw, m); + + UxCardMemDetach(card->hw, b); + + return value; +} + +word mem_inw(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + unsigned char *b, *m; + word value; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + value = UxCardMemInW(card->hw, m); + + UxCardMemDetach(card->hw, b); + + return value; +} + +void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemInBuffer(card->hw, m, P, length); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (dword) &RBuffer->length; + card->RBuffer.length = UxCardMemInW(card->hw, m); + + m = b; + m += (dword) &RBuffer->P; + UxCardMemInBuffer(card->hw, m, card->RBuffer.P, card->RBuffer.length); + + e->RBuffer = (DBUFFER *) &card->RBuffer; + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_out(ADAPTER *a, void *adr, byte data) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemOut(card->hw, m, data); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_outw(ADAPTER *a, void *adr, word data) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemOutW(card->hw, m, data); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemOutBuffer(card->hw, m, P, length); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_inc(ADAPTER *a, void *adr) +{ + word value; + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + value = UxCardMemInW(card->hw, m); + value++; + UxCardMemOutW(card->hw, m, value); + + UxCardMemDetach(card->hw, b); + + return; +} + +/* + * I/O routines for I/O mapped cards + */ + +byte io_in(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + byte value; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + value = UxCardIoIn(card->hw, DivasIOBase, adr); + + UxCardMemDetach(card->hw, DivasIOBase); + + return value; +} + +word io_inw(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + word value; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + value = UxCardIoInW(card->hw, DivasIOBase, adr); + + UxCardMemDetach(card->hw, DivasIOBase); + + return value; +} + +void io_in_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoInBuffer(card->hw, DivasIOBase, adr, P,length); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + card->RBuffer.length = UxCardIoInW(card->hw, DivasIOBase, (byte *) RBuffer); + + UxCardIoInBuffer(card->hw, DivasIOBase, &RBuffer->P, card->RBuffer.P, card->RBuffer.length); + + UxCardMemDetach(card->hw, DivasIOBase); + + e->RBuffer = (DBUFFER *) &card->RBuffer; + + return; +} + +void io_out(ADAPTER *a, void *adr, byte data) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoOut(card->hw, DivasIOBase, adr, data); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_outw(ADAPTER *a, void *adr, word data) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoOutW(card->hw, DivasIOBase, adr, data); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_out_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoOutBuffer(card->hw, DivasIOBase, adr, P, length); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_inc(ADAPTER *a, void *adr) +{ + word value; + card_t *card = a->io; + byte *DivasIOBase; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + value = UxCardIoInW(card->hw, DivasIOBase, adr); + + value++; + + UxCardIoOutW(card->hw, DivasIOBase, adr, value); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +static +void test_int(card_t *card) + +{ + byte *shared, *DivasIOBase; + + switch (card->test_int_pend) + { + case TEST_INT_DIVAS: + DPRINTF(("divas: test interrupt pending")); + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + if (UxCardMemIn(card->hw, &shared[0x3FE])) + { + UxCardMemOut(card->hw, + &(((struct pr_ram *)shared)->RcOutput), 0); + UxCardMemDetach(card->hw, shared); + (*card->reset_int)(card); + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + UxCardMemOut(card->hw, &shared[0x3FE], 0); + DPRINTF(("divas: test interrupt cleared")); + } + + UxCardMemDetach(card->hw, shared); + + card->test_int_pend = 0; + break; + + case TEST_INT_DIVAS_BRI: + DPRINTF(("divas: BRI test interrupt pending")); + (*card->reset_int)(card); + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + UxCardIoOutW(card->hw, DivasIOBase, (void *) 0x3FE, 0); + UxCardMemDetach(card->hw, DivasIOBase); + DPRINTF(("divas: test interrupt cleared")); + card->test_int_pend = 0; + break; + + case TEST_INT_DIVAS_Q: + DPRINTF(("divas: 4BRI test interrupt pending")); + (*card->reset_int)(card); + card->test_int_pend = 0; + break; + + default: + DPRINTF(("divas: unknown test interrupt pending")); + return; + } + return; +} + +void card_isr (void *dev_id) +{ + card_t *card = (card_t *) dev_id; + ADAPTER *a = &card->a; + int ipl; + + if (card->test_int_pend) + { + ipl = UxCardLock(card->hw); + card->int_pend=0; + test_int(card); + UxCardUnlock(card->hw,ipl); + return; + } + + if(card->card_isr) + { + (*(card->card_isr))(card); + } + else + { + ipl = UxCardLock(card->hw); + + if ((card->test_int)(a)) + { + (card->reset_int)(card); + } + + UxCardUnlock(card->hw,ipl); + + } + +} + +int DivasCardNew(dia_card_t *card_info) +{ + card_t *card; + byte b; + static boolean_t first_call = TRUE; + boolean_t NeedISRandReset = FALSE; + + DPRINTF(("divas: new card ")); + + if (first_call) + { + first_call = FALSE; + init_idi_tab(); + } + + DivasConfigGet(card_info); + + if (DivasCardNext == DIM(DivasCards)) + { + KDPRINTF((KERN_WARNING "Divas: no space available for new card")); + return -1; + } + + card = &DivasCards[DivasCardNext]; + + card->state = DIA_UNKNOWN; + + card->cfg = *card_info; + + card->a.io = card; + + if (UxCardHandleGet(&card->hw, card_info)) + { + KDPRINTF((KERN_WARNING "Divas: cannot get OS specific handle for card")); + return -1; + } + + if (card_info->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + DivasBriPatch(card); + card_info->io_base = card->cfg.io_base; + } + + switch (card_info->card_type) + { + case DIA_CARD_TYPE_DIVA_SERVER: + if (DivasPriInit(card, card_info)) + { + return -1; + } + NeedISRandReset = TRUE; + break; + + case DIA_CARD_TYPE_DIVA_SERVER_B: + if (DivasBriInit(card, card_info)) + { + return -1; + } + NeedISRandReset = TRUE; + break; + + case DIA_CARD_TYPE_DIVA_SERVER_Q: + if (Divas4BriInit(card, card_info)) + { + return -1; + } + + if (card_info->name[6] == '0') + { + NeedISRandReset = TRUE; + } + else // Need to set paramater for ISR anyway + { + card->hw->user_isr_arg = card; + card->hw->user_isr = card_isr; + } + break; + + default: + KDPRINTF((KERN_WARNING "Divas: unsupported card type (%d)", card_info->card_type)); + return -1; + } + + if (NeedISRandReset) + { + if (UxIsrInstall(card->hw, card_isr, card)) + { + KDPRINTF((KERN_WARNING "Divas: Install ISR failed (IRQ %d)", card->cfg.irq)); + UxCardHandleFree(card->hw); + return -1; + } + + b = card->cfg.irq; + + UxPciConfigWrite(card->hw, sizeof(b), PCI_INTERRUPT, &b); + + if (card_info->card_type != DIA_CARD_TYPE_DIVA_SERVER_Q) + { + if ((*card->card_reset)(card)) + { + KDPRINTF((KERN_WARNING "Divas: Adapter reset failed")); + return -1; + } + card->state = DIA_RESET; + } + + NeedISRandReset = FALSE; + } + + DivasCardNext++; + + return 0; +} + +void *get_card(int card_id) +{ + int i; + + for (i=0; i < DivasCardNext; i++) + { + if (DivasCards[i].cfg.card_id == card_id) + { + return(&DivasCards[i]); + } + } + + DPRINTF(("divas: get_card() : no such card id (%d)", card_id)); + + return NULL; +} + +int DivasCardConfig(dia_config_t *config) +{ + card_t *card; + int status; + + DPRINTF(("divas: configuring card")); + + card = get_card(config->card_id); + if (!card) + { + return -1; + } + + config = DivasConfig(card, config); + + status = (*card->card_config)(card, config); + + if (!status) + { + card->state = DIA_CONFIGURED; + } + return status; +} + +int DivasCardLoad(dia_load_t *load) +{ + card_t *card; + int status; + + card = get_card(load->card_id); + if (!card) + { + return -1; + } + + if (card->state == DIA_RUNNING) + { + (*card->card_reset)(card); + } + + status = (*card->card_load)(card, load); + if (!status) + { + card->state = DIA_LOADED; + } + return status; +} + +static int idi_register(card_t *card, byte channels) +{ + DESCRIPTOR d[16]; + int length, num_entities; + + DPRINTF(("divas: registering card with IDI")); + + num_entities = (channels > 2) ? MAX_PENTITIES : MAX_ENTITIES; + card->e_tbl = UxAlloc(sizeof(E_INFO) * num_entities); + + if (!card->e_tbl) + { + KDPRINTF((KERN_WARNING "Divas: IDI register failed - no memory available")); + return -1; + } + + bzero(card->e_tbl, sizeof(E_INFO) * num_entities); + card->e_max = num_entities; + + EtdM_DIDD_Read(d, &length); + + if (length == DIM(d)) + { + KDPRINTF((KERN_WARNING "Divas: IDI register failed - table full")); + return -1; + } + + switch (card->cfg.card_type) + { + case DIA_CARD_TYPE_DIVA_SERVER: + d[length].type = IDI_ADAPTER_PR; + d[length].serial = card->serial_no; + break; + + case DIA_CARD_TYPE_DIVA_SERVER_B: + d[length].type = IDI_ADAPTER_MAESTRA; + d[length].serial = card->serial_no; + break; + + // 4BRI is treated as 4 BRI adapters + case DIA_CARD_TYPE_DIVA_SERVER_Q: + d[length].type = IDI_ADAPTER_MAESTRA; + d[length].serial = card->cfg.serial; + } + + d[length].features = 0; + d[length].features |= DI_FAX3|DI_MODEM|DI_POST|DI_V110|DI_V120; + + if ( card->hw->features & PROTCAP_MANIF ) + { + d[length].features |= DI_MANAGE ; + } + if ( card->hw->features & PROTCAP_V_42 ) + { + d[length].features |= DI_V_42 ; + } + if ( card->hw->features & PROTCAP_EXTD_FAX ) + { + d[length].features |= DI_EXTD_FAX ; + } + + d[length].channels = channels; + d[length].request = DivasIdiRequest[card - DivasCards]; + + length++; + + EtdM_DIDD_Write(d, length); + + return 0; +} + +int DivasCardStart(int card_id) +{ + card_t *card; + byte channels; + int status; + + DPRINTF(("divas: starting card")); + + card = get_card(card_id); + if (!card) + { + return -1; + } + + status = (*card->card_start)(card, &channels); + if (status) + { + return status; + } + + /* 4BRI == 4 x BRI so call idi_register 4 times each with 2 channels */ + if (card->cfg.card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + int i; + card_t *FourBRISlave; + + for (i=3; i >= 0; i--) + { + FourBRISlave = get_card(card_id - i); /* 0, 1, 2, 3 */ + if (FourBRISlave) + { + idi_register(FourBRISlave, 2); + FourBRISlave->state = DIA_RUNNING; + } + } + card->serial_no = card->cfg.serial; + + DPRINTF(("divas: card id %d (4BRI), serial no. 0x%x ready with %d channels", + card_id - 3, card->serial_no, (int) channels)); + } + else + { + status = idi_register(card, channels); + if (!status) + { + card->state = DIA_RUNNING; + DPRINTF(("divas: card id %d, serial no. 0x%x ready with %d channels", + card_id, card->serial_no, (int) channels)); + } + } + + return status; +} + +int DivasGetMem(mem_block_t *mem_block) +{ + card_t *card; + word card_id = mem_block->card_id; + + card = get_card(card_id); + if (!card) + { + return 0; + } + + return (*card->card_mem_get)(card, mem_block); +} + + +/* + * Deleyed Procedure Call for handling interrupts from card + */ + +void DivaDoCardDpc(card_t *card) +{ + ADAPTER *a; + + a = &card->a; + + if(UxInterlockedIncrement(card->hw, &card->dpc_reentered) > 1) + { + return; + } + + do{ + if((*(card->test_int))(a)) + { + (*(card->dpc))(a); + (*(card->clear_int))(a); + } + (*(card->out))(a); + }while(UxInterlockedDecrement(card->hw, &card->dpc_reentered)); + +} + +void DivasDoDpc(void *pData) +{ + card_t *card = DivasCards; + int i = DivasCardNext; + + while(i--) + { + DivaDoCardDpc(card++); + } +} + +void DivasDoRequestDpc(void *pData) +{ + DivasDoDpc(pData); +} + +/* + * DivasGetNum + * Returns the number of active adapters + */ + +int DivasGetNum(void) +{ + return(DivasCardNext); +} + +/* + * DivasGetList + * Returns a list of active adapters + */ +int DivasGetList(dia_card_list_t *card_list) +{ + int i; + + bzero(card_list, sizeof(dia_card_list_t)); + + for(i = 0; i < DivasCardNext; i++) + { + card_list->card_type = DivasCards[i].cfg.card_type; + card_list->card_slot = DivasCards[i].cfg.slot; + card_list->state = DivasCards[i].state; + card_list++; + } + + return 0; + +} + +/* + * control logging for specified card + */ + +void DivasLog(dia_log_t *log) +{ + card_t *card; + + card = get_card(log->card_id); + if (!card) + { + return; + } + + card->log_types = log->log_types; + + return; +} + diff --git a/drivers/isdn/eicon/constant.h b/drivers/isdn/eicon/constant.h new file mode 100644 index 000000000..ea92f05ad --- /dev/null +++ b/drivers/isdn/eicon/constant.h @@ -0,0 +1,179 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + + +/*------------------------------------------------------------------*/ +/* Q.931 information elements maximum length */ +/* excluding the identifier, including the length field */ +/*------------------------------------------------------------------*/ + +#define MAX_LEN_BC 13 +#define MAX_LEN_LLC 19 /* ctr3 */ +#define MAX_LEN_HLC 6 /* ctr3 */ +#define MAX_LEN_UUI 200 /* Hicom USBS req */ +#define MAX_LEN_NUM 24 +#define MAX_LEN_DSP 83 /* ctr3 */ +#define MAX_LEN_NI 4 +#define MAX_LEN_PI 5 +#define MAX_LEN_SIN 3 +#define MAX_LEN_CST 4 +#define MAX_LEN_SIG 2 +#define MAX_LEN_SPID 32 +#define MAX_LEN_EID 3 +#define MAX_LEN_CHI 35 /* ctr3 */ +#define MAX_LEN_CAU 33 +#define MAX_LEN_FTY 130 +#define MAX_LEN_KEY 83 /* ctr3 */ +#define MAX_LEN_RSI 4 +#define MAX_LEN_CAI 11 +#define MAX_NUM_SPID 4 +#define MAX_LEN_USERID 9 +#define MAX_LEN_APPLID 5 +#define MAX_LEN_NTTCIF 15 + +/*------------------------------------------------------------------*/ +/* decision return values */ +/*------------------------------------------------------------------*/ + +#define YES 1 +#define NO 0 + + +/*-------------------------------------------------------------------*/ +/* w element coding */ +/*-------------------------------------------------------------------*/ + +#define NTTCIF 0x01 +#define BC 0x04 +#define CAU 0x08 +#define CAD 0x0c +#define CAI 0x10 +#define CST 0x14 +#define CHI 0x18 +#define LLI 0x19 +#define CHA 0x1a +#define FTY 0x1c +#define PI 0x1e +#define NFAC 0x20 +#define TC 0x24 +#define ATT_EID 0x26 +#define NI 0x27 +#define DSP 0x28 +#define DT 0x29 +#define KEY 0x2c +#define KP 0x2c +#define UID 0x2d +#define SIG 0x34 +#define FI 0x39 +#define SPID 0x3a +#define EID 0x3b +#define DSPF 0x3c +#define ECAD 0x4c +#define OAD 0x6c +#define OSA 0x6d +#define DAD 0x70 +#define CPN 0x70 +#define DSA 0x71 +#define RDX 0x73 +#define RAD 0x74 +#define RDN 0x74 +#define RSI 0x79 +#define SCR 0x7A /* internal unscreened CPN */ +#define MIE 0x7a /* internal management info element */ +#define LLC 0x7c +#define HLC 0x7d +#define UUI 0x7e +#define ESC 0x7f + +#define SHIFT 0x90 +#define MORE 0xa0 +#define CL 0xb0 + +/* information elements used on the spid interface */ +#define SPID_CMD 0xc0 +#define SPID_LINK 0x10 +#define SPID_DN 0x70 +#define SPID_BC 0x04 +#define SPID_SWITCH 0x11 + +/*------------------------------------------------------------------*/ +/* global configuration parameters, defined in exec.c */ +/* these parameters are configured with program loading */ +/*------------------------------------------------------------------*/ + +#define PROT_1TR6 0 +#define PROT_ETSI 1 +#define PROT_FRANC 2 +#define PROT_BELG 3 +#define PROT_SWED 4 +#define PROT_NI 5 +#define PROT_5ESS 6 +#define PROT_JAPAN 7 +#define PROT_ATEL 8 +#define PROT_US 9 +#define PROT_ITALY 10 +#define PROT_TWAN 11 +#define PROT_AUSTRAL 12 + +#define INIT_PROT_1TR6 0x80|PROT_1TR6 +#define INIT_PROT_ETSI 0x80|PROT_ETSI +#define INIT_PROT_FRANC 0x80|PROT_FRANC +#define INIT_PROT_BELG 0x80|PROT_BELG +#define INIT_PROT_SWED 0x80|PROT_SWED +#define INIT_PROT_NI 0x80|PROT_NI +#define INIT_PROT_5ESS 0x80|PROT_5ESS +#define INIT_PROT_JAPAN 0x80|PROT_JAPAN +#define INIT_PROT_ATEL 0x80|PROT_ATEL +#define INIT_PROT_ITALY 0x80|PROT_ITALY +#define INIT_PROT_TWAN 0x80|PROT_TWAN +#define INIT_PROT_AUSTRAL 0x80|PROT_AUSTRAL + + +/* -----------------------------------------------------------** +** The PROTOCOL_FEATURE_STRING in feature.h (included ** +** in prstart.sx and astart.sx) defines capabilities and ** +** features of the actual protocol code. It's used as a bit ** +** mask. ** +** The following Bits are defined: ** +** -----------------------------------------------------------*/ + +#define PROTCAP_TELINDUS 0x0001 /* Telindus Variant of protocol code */ +#define PROTCAP_MANIF 0x0002 /* Management interface implemented */ +#define PROTCAP_V_42 0x0004 /* V42 implemented */ +#define PROTCAP_V90D 0x0008 /* V.90D (implies up to 384k DSP code) */ +#define PROTCAP_EXTD_FAX 0x0010 /* Extended FAX (ECM, 2D, T6, Polling) */ +#define PROTCAP_FREE4 0x0020 /* not used */ +#define PROTCAP_FREE5 0x0040 /* not used */ +#define PROTCAP_FREE6 0x0080 /* not used */ +#define PROTCAP_FREE7 0x0100 /* not used */ +#define PROTCAP_FREE8 0x0200 /* not used */ +#define PROTCAP_FREE9 0x0400 /* not used */ +#define PROTCAP_FREE10 0x0800 /* not used */ +#define PROTCAP_FREE11 0x1000 /* not used */ +#define PROTCAP_FREE12 0x2000 /* not used */ +#define PROTCAP_FREE13 0x4000 /* not used */ +#define PROTCAP_EXTENSION 0x8000 /* used for future extentions */ diff --git a/drivers/isdn/eicon/divalog.h b/drivers/isdn/eicon/divalog.h new file mode 100644 index 000000000..93bd56ae9 --- /dev/null +++ b/drivers/isdn/eicon/divalog.h @@ -0,0 +1,57 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* + * Include file for defining the kernel loggger messages + * These definitions are shared between the klog driver and the + * klogd daemon process + */ + +#if !defined(_KLOGMSG_H) +#define _KLOGMSG_H + +/* define a type for a log entry */ + +#define KLOG_TEXT_MSG (0) +#define KLOG_XLOG_MSG (1) +#define KLOG_XTXT_MSG (2) +#define KLOG_IDI_REQ (4) +#define KLOG_IDI_CALLBACK (5) +#define KLOG_CAPI_MSG (6) + +typedef struct +{ + unsigned long time_stamp; /* in ms since last system boot */ + int card; /* card number (-1 for all) */ + unsigned int type; /* type of log message (0 is text) */ + unsigned int length; /* message length (non-text messages only) */ + unsigned short code; /* message code (non-text messages only) */ + char buffer[110];/* text/data to log */ +} klog_t; + +void DivasLogAdd(void *buffer, int length); +#endif /* of _KLOGMSG_H */ diff --git a/drivers/isdn/eicon/divas.h b/drivers/isdn/eicon/divas.h new file mode 100644 index 000000000..2fcd8349b --- /dev/null +++ b/drivers/isdn/eicon/divas.h @@ -0,0 +1,232 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.5 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* External Diva Server driver include file */ + +#if !defined(DIVAS_H) +#define DIVAS_H + +#include "sys.h" + + +/* IOCTL commands */ + +#define DIA_IOCTL_INIT (0) +#define DIA_IOCTL_LOAD (1) +#define DIA_IOCTL_CONFIG (2) +#define DIA_IOCTL_START (3) +#define DIA_IOCTL_GET_NUM (4) +#define DIA_IOCTL_GET_LIST (5) +#define DIA_IOCTL_LOG (6) +#define DIA_IOCTL_DETECT (7) +#define DIA_IOCTL_SPACE (8) +#define DIA_IOCTL_GET_MEM (9) +#define DIA_IOCTL_FLAVOUR (10) +#define DIA_IOCTL_XLOG_REQ (11) + +/* Error codes */ + +#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) + +/* Adapter states */ + +#define DIA_UNKNOWN (0) +#define DIA_RESET (1) +#define DIA_LOADED (2) +#define DIA_CONFIGURED (3) +#define DIA_RUNNING (4) + +/* Stucture for getting card specific information from active cad driver */ + +typedef struct +{ + int card_type; + int card_slot; + int state; +} dia_card_list_t; + +/* use following to select which logging to have active */ + +#define DIVAS_LOG_DEBUG (1 << 0) +#define DIVAS_LOG_XLOG (1 << 1) +#define DIVAS_LOG_IDI (1 << 2) +#define DIVAS_LOG_CAPI (1 << 3) + +/* stucture for DIA_IOCTL_LOG to get information from adapter */ + +typedef struct +{ + int card_id; + int log_types; /* bit mask of log types: use DIVAS_LOG_XXX */ +} dia_log_t; + +/* list of cards supported by this driver */ + +#define DIA_CARD_TYPE_DIVA_SERVER (0) /* Diva Server PRI */ +#define DIA_CARD_TYPE_DIVA_SERVER_B (1) /* Diva Server BRI */ +#define DIA_CARD_TYPE_DIVA_SERVER_Q (2) /* Diva Server 4-BRI */ + +/* bus types */ + +#define DIA_BUS_TYPE_ISA (0) +#define DIA_BUS_TYPE_ISA_PNP (1) +#define DIA_BUS_TYPE_PCI (2) +#define DIA_BUS_TYPE_MCA (3) + +/* types of memory used (index for memory array below) */ + +#define DIVAS_RAM_MEMORY 0 +#define DIVAS_REG_MEMORY 1 +#define DIVAS_CFG_MEMORY 2 +#define DIVAS_SHARED_MEMORY 3 +#define DIVAS_CTL_MEMORY 4 +/* + * card config information + * passed as parameter to DIA_IOCTL_INIT ioctl to initialise new card + */ + +typedef struct +{ + int card_id; /* unique id assigned to this card */ + int card_type; /* use DIA_CARD_TYPE_xxx above */ + int bus_type; /* use DIA_BUS_TYPE_xxx above */ + int bus_num; /* bus number (instance number of bus type) */ + int func_num; /* adapter function number (PCI register) */ + int slot; /* slot number in bus */ + unsigned char irq; /* IRQ number */ + int reset_base; /* Reset register for I/O mapped cards */ + int io_base; /* I/O base for I/O mapped cards */ + void *memory[5]; /* memory base addresses for memory mapped cards */ + char name[9]; /* name of adapter */ + int serial; /* serial number */ + unsigned char int_priority; /* Interrupt priority */ +} dia_card_t; + +/* + * protocol configuration information + * passed as parameter to DIA_IOCTL_CONFIG ioctl to configure card + */ + +typedef struct +{ + int card_id; /* to identify particular card */ + unsigned char tei; + unsigned char nt2; + unsigned char watchdog; + unsigned char permanent; + unsigned char x_interface; + unsigned char stable_l2; + unsigned char no_order_check; + unsigned char handset_type; + unsigned char sig_flags; + unsigned char low_channel; + unsigned char prot_version; + unsigned char crc4; + struct + { + unsigned char oad[32]; + unsigned char osa[32]; + unsigned char spid[32]; + }terminal[2]; +} dia_config_t; + +/* + * code configuration + * passed as parameter to DIA_IOCTL_LOAD ioctl + * one of these ioctl per code file to load + */ + +typedef struct +{ + int card_id; /* card to load */ + enum + { + DIA_CPU_CODE, /* CPU code */ + DIA_DSP_CODE, /* DSP code */ + DIA_CONT_CODE, /* continuation of code */ + DIA_TABLE_CODE, /* code table */ + DIA_DLOAD_CNT, /* number of downloads*/ + DIA_FPGA_CODE + } code_type; /* code for CPU or DSP ? */ + int length; /* length of code */ + unsigned char *code; /* pointer (in user-space) to code */ +} dia_load_t; + +/* + * start configuration + * passed as parameter to DIA_IOCTL_START ioctl + */ + +typedef struct +{ + int card_id; /* card to start */ +} dia_start_t; + +/* used for retrieving memory from the card */ + +typedef struct { + word card_id; + dword addr; + byte data[16 * 8]; +} mem_block_t; + +/* DIVA Server specific addresses */ + +#define DIVAS_CPU_START_ADDR (0x0) +#define ORG_MAX_PROTOCOL_CODE_SIZE 0x000A0000 +#define ORG_MAX_DSP_CODE_SIZE (0x000F0000 - ORG_MAX_PROTOCOL_CODE_SIZE) +#define ORG_DSP_CODE_BASE (0xBF7F0000 - ORG_MAX_DSP_CODE_SIZE) +#define DIVAS_DSP_START_ADDR (0xBF7A0000) +#define DIVAS_SHARED_OFFSET (0x1000) +#define MP_DSP_CODE_BASE 0xa03a0000 +#define MQ_PROTCODE_OFFSET 0x100000 +#define MQ_SM_OFFSET 0X0f0000 + +#define V90D_MAX_PROTOCOL_CODE_SIZE 0x00090000 +#define V90D_MAX_DSP_CODE_SIZE (0x000F0000 - V90D_MAX_PROTOCOL_CODE_SIZE) +#define V90D_DSP_CODE_BASE (0xBF7F0000 - V90D_MAX_DSP_CODE_SIZE) + +#define MQ_ORG_MAX_PROTOCOL_CODE_SIZE 0x000a0000 /* max 640K Protocol-Code */ +#define MQ_ORG_MAX_DSP_CODE_SIZE 0x00050000 /* max 320K DSP-Code */ +#define MQ_ORG_DSP_CODE_BASE (MQ_MAX_DSP_DOWNLOAD_ADDR \ + - MQ_ORG_MAX_DSP_CODE_SIZE) +#define MQ_V90D_MAX_PROTOCOL_CODE_SIZE 0x00090000 /* max 576K Protocol-Code */ +#define MQ_V90D_MAX_DSP_CODE_SIZE 0x00060000 /* max 384K DSP-Code if V.90D included */ +#define MQ_MAX_DSP_DOWNLOAD_ADDR 0xa03f0000 +#define MQ_V90D_DSP_CODE_BASE (MQ_MAX_DSP_DOWNLOAD_ADDR \ + - MQ_V90D_MAX_DSP_CODE_SIZE) + + +#define ALIGNMENT_MASK_MAESTRA 0xfffffffc + +#endif /* DIVAS_H */ diff --git a/drivers/isdn/eicon/dsp_defs.h b/drivers/isdn/eicon/dsp_defs.h new file mode 100644 index 000000000..ee7c1429e --- /dev/null +++ b/drivers/isdn/eicon/dsp_defs.h @@ -0,0 +1,303 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef DSP_DEFS_H_ +#define DSP_DEFS_H_ + +#ifndef DSPDIDS_H_ +#include "dspdids.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif +/*---------------------------------------------------------------------------*/ + +#ifndef NULL +#define NULL 0 +#endif +#ifndef TRUE +#define TRUE (0 == 0) +#endif +#ifndef FALSE +#define FALSE (0 != 0) +#endif + + +/*---------------------------------------------------------------------------*/ + +#define DSP_MEMORY_TYPE_EXTERNAL_DM 0 +#define DSP_MEMORY_TYPE_EXTERNAL_PM 1 +#define DSP_MEMORY_TYPE_INTERNAL_DM 2 +#define DSP_MEMORY_TYPE_INTERNAL_PM 3 + +#define DSP_DOWNLOAD_FLAG_BOOTABLE 0x0001 +#define DSP_DOWNLOAD_FLAG_2181 0x0002 +#define DSP_DOWNLOAD_FLAG_TIMECRITICAL 0x0004 +#define DSP_DOWNLOAD_FLAG_COMPAND 0x0008 + +#define DSP_MEMORY_BLOCK_COUNT 16 + +#define DSP_SEGMENT_PM_FLAG 0x0001 +#define DSP_SEGMENT_SHARED_FLAG 0x0002 + +#define DSP_SEGMENT_EXTERNAL_DM DSP_MEMORY_TYPE_EXTERNAL_DM +#define DSP_SEGMENT_EXTERNAL_PM DSP_MEMORY_TYPE_EXTERNAL_PM +#define DSP_SEGMENT_INTERNAL_DM DSP_MEMORY_TYPE_INTERNAL_DM +#define DSP_SEGMENT_INTERNAL_PM DSP_MEMORY_TYPE_INTERNAL_PM +#define DSP_SEGMENT_FIRST_RELOCATABLE 4 + +#define DSP_DATA_BLOCK_PM_FLAG 0x0001 +#define DSP_DATA_BLOCK_DWORD_FLAG 0x0002 +#define DSP_DATA_BLOCK_RESOLVE_FLAG 0x0004 + +#define DSP_RELOC_NONE 0x00 +#define DSP_RELOC_SEGMENT_MASK 0x3f +#define DSP_RELOC_TYPE_MASK 0xc0 +#define DSP_RELOC_TYPE_0 0x00 /* relocation of address in DM word / high part of PM word */ +#define DSP_RELOC_TYPE_1 0x40 /* relocation of address in low part of PM data word */ +#define DSP_RELOC_TYPE_2 0x80 /* relocation of address in standard command */ +#define DSP_RELOC_TYPE_3 0xc0 /* relocation of address in call/jump on flag in */ + +#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48 +#define DSP_COMBIFILE_FORMAT_VERSION_BCD 0x0100 + +#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48 +#define DSP_FILE_FORMAT_VERSION_BCD 0x0100 + + +typedef struct tag_dsp_combifile_header +{ + char format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE]; + word format_version_bcd; + word header_size; + word combifile_description_size; + word directory_entries; + word directory_size; + word download_count; + word usage_mask_size; +} t_dsp_combifile_header; + +typedef struct tag_dsp_combifile_directory_entry +{ + word card_type_number; + word file_set_number; +} t_dsp_combifile_directory_entry; + +typedef struct tag_dsp_file_header +{ + char format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE]; + word format_version_bcd; + word download_id; + word download_flags; + word required_processing_power; + word interface_channel_count; + word header_size; + word download_description_size; + word memory_block_table_size; + word memory_block_count; + word segment_table_size; + word segment_count; + word symbol_table_size; + word symbol_count; + word total_data_size_dm; + word data_block_count_dm; + word total_data_size_pm; + word data_block_count_pm; +} t_dsp_file_header; + +typedef struct tag_dsp_memory_block_desc +{ + word alias_memory_block; + word memory_type; + word address; + word size; /* DSP words */ +} t_dsp_memory_block_desc; + +typedef struct tag_dsp_segment_desc +{ + word memory_block; + word attributes; + word base; + word size; + word alignment; /* ==0 -> no other legal start address than base */ +} t_dsp_segment_desc; + +typedef struct tag_dsp_symbol_desc +{ + word symbol_id; + word segment; + word offset; + word size; /* DSP words */ +} t_dsp_symbol_desc; + +typedef struct tag_dsp_data_block_header +{ + word attributes; + word segment; + word offset; + word size; /* DSP words */ +} t_dsp_data_block_header; + +typedef struct tag_dsp_download_desc /* be sure to keep native alignment for MAESTRA's */ +{ + word download_id; + word download_flags; + word required_processing_power; + word interface_channel_count; + word excess_header_size; + word memory_block_count; + word segment_count; + word symbol_count; + word data_block_count_dm; + word data_block_count_pm; + byte *p_excess_header_data; + char *p_download_description; + t_dsp_memory_block_desc *p_memory_block_table; + t_dsp_segment_desc *p_segment_table; + t_dsp_symbol_desc *p_symbol_table; + word *p_data_blocks_dm; + word *p_data_blocks_pm; +} t_dsp_download_desc; + +#define DSP_DOWNLOAD_INDEX_KERNEL 0 +#define DSP30TX_DOWNLOAD_INDEX_KERNEL 1 +#define DSP30RX_DOWNLOAD_INDEX_KERNEL 2 +#define DSP_MAX_DOWNLOAD_COUNT 35 + + +#define DSP_DOWNLOAD_MAX_SEGMENTS 16 + +#define DSP_UDATA_REQUEST_RECONFIGURE 0 +/* +parameters: + <word> reconfigure delay (in 8kHz samples) + <word> reconfigure code + <byte> reconfigure hdlc preamble flags +*/ + +#define DSP_RECONFIGURE_TX_FLAG 0x8000 +#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG 0x4000 +#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG 0x2000 +#define DSP_RECONFIGURE_HDLC_FLAG 0x1000 +#define DSP_RECONFIGURE_SYNC_FLAG 0x0800 +#define DSP_RECONFIGURE_PROTOCOL_MASK 0x00ff +#define DSP_RECONFIGURE_IDLE 0 +#define DSP_RECONFIGURE_V25 1 +#define DSP_RECONFIGURE_V21_CH2 2 +#define DSP_RECONFIGURE_V27_2400 3 +#define DSP_RECONFIGURE_V27_4800 4 +#define DSP_RECONFIGURE_V29_7200 5 +#define DSP_RECONFIGURE_V29_9600 6 +#define DSP_RECONFIGURE_V33_12000 7 +#define DSP_RECONFIGURE_V33_14400 8 +#define DSP_RECONFIGURE_V17_7200 9 +#define DSP_RECONFIGURE_V17_9600 10 +#define DSP_RECONFIGURE_V17_12000 11 +#define DSP_RECONFIGURE_V17_14400 12 + +/* +data indications if transparent framer + <byte> data 0 + <byte> data 1 + ... + +data indications if HDLC framer + <byte> data 0 + <byte> data 1 + ... + <byte> CRC 0 + <byte> CRC 1 + <byte> preamble flags +*/ + +#define DSP_UDATA_INDICATION_SYNC 0 +/* +returns: + <word> time of sync (sampled from counter at 8kHz) +*/ + +#define DSP_UDATA_INDICATION_DCD_OFF 1 +/* +returns: + <word> time of DCD off (sampled from counter at 8kHz) +*/ + +#define DSP_UDATA_INDICATION_DCD_ON 2 +/* +returns: + <word> time of DCD on (sampled from counter at 8kHz) + <byte> connected norm + <word> connected options + <dword> connected speed (bit/s) +*/ + +#define DSP_UDATA_INDICATION_CTS_OFF 3 +/* +returns: + <word> time of CTS off (sampled from counter at 8kHz) +*/ + +#define DSP_UDATA_INDICATION_CTS_ON 4 +/* +returns: + <word> time of CTS on (sampled from counter at 8kHz) + <byte> connected norm + <word> connected options + <dword> connected speed (bit/s) +*/ + +#define DSP_CONNECTED_NORM_UNSPECIFIED 0 +#define DSP_CONNECTED_NORM_V21 1 +#define DSP_CONNECTED_NORM_V23 2 +#define DSP_CONNECTED_NORM_V22 3 +#define DSP_CONNECTED_NORM_V22_BIS 4 +#define DSP_CONNECTED_NORM_V32_BIS 5 +#define DSP_CONNECTED_NORM_V34 6 +#define DSP_CONNECTED_NORM_V8 7 +#define DSP_CONNECTED_NORM_BELL_212A 8 +#define DSP_CONNECTED_NORM_BELL_103 9 +#define DSP_CONNECTED_NORM_V29_LEASED_LINE 10 +#define DSP_CONNECTED_NORM_V33_LEASED_LINE 11 +#define DSP_CONNECTED_NORM_TFAST 12 +#define DSP_CONNECTED_NORM_V21_CH2 13 +#define DSP_CONNECTED_NORM_V27_TER 14 +#define DSP_CONNECTED_NORM_V29 15 +#define DSP_CONNECTED_NORM_V33 16 +#define DSP_CONNECTED_NORM_V17 17 + +#define DSP_CONNECTED_OPTION_TRELLIS 0x0001 + + +/*---------------------------------------------------------------------------*/ +#ifdef __cplusplus +} +#endif + +#endif + +/*---------------------------------------------------------------------------*/ diff --git a/drivers/isdn/eicon/dspdids.h b/drivers/isdn/eicon/dspdids.h new file mode 100644 index 000000000..1ac6a9bc6 --- /dev/null +++ b/drivers/isdn/eicon/dspdids.h @@ -0,0 +1,84 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef DSPDIDS_H_ +#define DSPDIDS_H_ + + +/*---------------------------------------------------------------------------*/ + +#define DSP_DID_INVALID 0 +#define DSP_DID_DIVA 1 +#define DSP_DID_DIVA_PRO 2 +#define DSP_DID_DIVA_PRO_20 3 +#define DSP_DID_DIVA_PRO_PCCARD 4 +#define DSP_DID_DIVA_SERVER_BRI_1M 5 +#define DSP_DID_DIVA_SERVER_BRI_2M 6 +#define DSP_DID_DIVA_SERVER_PRI_2M_TX 7 +#define DSP_DID_DIVA_SERVER_PRI_2M_RX 8 +#define DSP_DID_DIVA_SERVER_PRI_30M 9 +#define DSP_DID_TASK_HSCX 100 +#define DSP_DID_TASK_HSCX_PRI_2M_TX 101 +#define DSP_DID_TASK_HSCX_PRI_2M_RX 102 +#define DSP_DID_TASK_V110KRNL 200 +#define DSP_DID_OVERLAY_V1100 201 +#define DSP_DID_OVERLAY_V1101 202 +#define DSP_DID_OVERLAY_V1102 203 +#define DSP_DID_OVERLAY_V1103 204 +#define DSP_DID_OVERLAY_V1104 205 +#define DSP_DID_OVERLAY_V1105 206 +#define DSP_DID_OVERLAY_V1106 207 +#define DSP_DID_OVERLAY_V1107 208 +#define DSP_DID_OVERLAY_V1108 209 +#define DSP_DID_OVERLAY_V1109 210 +#define DSP_DID_TASK_V110_PRI_2M_TX 220 +#define DSP_DID_TASK_V110_PRI_2M_RX 221 +#define DSP_DID_TASK_MODEM 300 +#define DSP_DID_TASK_FAX05 400 +#define DSP_DID_TASK_VOICE 500 +#define DSP_DID_TASK_TIKRNL81 600 +#define DSP_DID_OVERLAY_DIAL 601 +#define DSP_DID_OVERLAY_V22 602 +#define DSP_DID_OVERLAY_V32 603 +#define DSP_DID_OVERLAY_FSK 604 +#define DSP_DID_OVERLAY_FAX 605 +#define DSP_DID_OVERLAY_VXX 606 +#define DSP_DID_OVERLAY_V8 607 +#define DSP_DID_OVERLAY_INFO 608 +#define DSP_DID_OVERLAY_V34 609 +#define DSP_DID_OVERLAY_DFX 610 +#define DSP_DID_PARTIAL_OVERLAY_DIAL 611 +#define DSP_DID_PARTIAL_OVERLAY_FSK 612 +#define DSP_DID_PARTIAL_OVERLAY_FAX 613 +#define DSP_DID_TASK_TIKRNL05 700 + + +/*---------------------------------------------------------------------------*/ + +#endif + +/*---------------------------------------------------------------------------*/ diff --git a/drivers/isdn/eicon/eicon.h b/drivers/isdn/eicon/eicon.h index 5ad164518..42e9b3b95 100644 --- a/drivers/isdn/eicon/eicon.h +++ b/drivers/isdn/eicon/eicon.h @@ -1,4 +1,4 @@ -/* $Id: eicon.h,v 1.19 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon.h,v 1.23 2000/06/21 11:28:42 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * @@ -20,86 +20,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon.h,v $ - * Revision 1.19 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.18 1999/11/25 11:43:27 armin - * Fixed statectrl and connect message. - * X.75 fix and HDLC/transparent with autoconnect. - * Minor cleanup. - * - * Revision 1.17 1999/10/26 21:15:33 armin - * using define for checking phone number len to avoid buffer overflow. - * - * Revision 1.16 1999/10/08 22:09:33 armin - * Some fixes of cards interface handling. - * Bugfix of NULL pointer occurence. - * Changed a few log outputs. - * - * Revision 1.15 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.14 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber. - * - * Revision 1.13 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.12 1999/09/04 06:20:05 keil - * Changes from kernel set_current_state() - * - * 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. - * - * Revision 1.4 1999/03/02 12:37:42 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.3 1999/01/24 20:14:07 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.2 1999/01/10 18:46:04 armin - * Bug with wrong values in HLC fixed. - * Bytes to send are counted and limited now. - * - * Revision 1.1 1999/01/01 18:09:41 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ @@ -124,6 +44,8 @@ #define EICON_IOCTL_TEST 98 #define EICON_IOCTL_DEBUGVAR 99 +#define EICON_IOCTL_DIA_OFFSET 100 + /* Bus types */ #define EICON_BUS_ISA 1 #define EICON_BUS_MCA 2 @@ -185,39 +107,10 @@ typedef struct { unsigned char code[1]; /* Rest (bootstrap- and firmware code) will be allocated */ } eicon_isa_codebuf; -/* Struct for downloading protocol via ioctl for PCI cards */ -typedef struct { - /* start-up parameters */ - unsigned char tei; - unsigned char nt2; - unsigned char WatchDog; - unsigned char Permanent; - unsigned char XInterface; - unsigned char StableL2; - unsigned char NoOrderCheck; - unsigned char HandsetType; - unsigned char LowChannel; - unsigned char ProtVersion; - unsigned char Crc4; - unsigned char NoHscx30Mode; /* switch PRI into No HSCX30 test mode */ - unsigned char Loopback; /* switch card into Loopback mode */ - struct q931_link_s - { - unsigned char oad[32]; - unsigned char osa[32]; - unsigned char spid[32]; - } l[2]; - unsigned long protocol_len; - unsigned int dsp_code_num; - unsigned long dsp_code_len[9]; - unsigned char code[1]; /* Rest (protocol- and dsp code) will be allocated */ -} eicon_pci_codebuf; - /* Data for downloading protocol via ioctl */ typedef union { eicon_isa_codebuf isa; eicon_isa_codebuf mca; - eicon_pci_codebuf pci; } eicon_codebuf; /* Data for Management interface */ @@ -228,6 +121,7 @@ typedef struct { unsigned char data[700]; } eicon_manifbuf; +#define TRACE_OK (1) #ifdef __KERNEL__ @@ -265,206 +159,34 @@ typedef struct { #include "eicon_isa.h" +#include "idi.h" + +typedef struct { + __u16 NextReq __attribute__ ((packed)); /* pointer to next Req Buffer */ + __u16 NextRc __attribute__ ((packed)); /* pointer to next Rc Buffer */ + __u16 NextInd __attribute__ ((packed)); /* pointer to next Ind Buffer */ + __u8 ReqInput __attribute__ ((packed)); /* number of Req Buffers sent */ + __u8 ReqOutput __attribute__ ((packed)); /* number of Req Buffers returned */ + __u8 ReqReserved __attribute__ ((packed));/*number of Req Buffers reserved */ + __u8 Int __attribute__ ((packed)); /* ISDN-P interrupt */ + __u8 XLock __attribute__ ((packed)); /* Lock field for arbitration */ + __u8 RcOutput __attribute__ ((packed)); /* number of Rc buffers received */ + __u8 IndOutput __attribute__ ((packed)); /* number of Ind buffers received */ + __u8 IMask __attribute__ ((packed)); /* Interrupt Mask Flag */ + __u8 Reserved1[2] __attribute__ ((packed)); /* reserved field, do not use */ + __u8 ReadyInt __attribute__ ((packed)); /* request field for ready int */ + __u8 Reserved2[12] __attribute__ ((packed)); /* reserved field, do not use */ + __u8 InterfaceType __attribute__ ((packed)); /* interface type 1=16K */ + __u16 Signature __attribute__ ((packed)); /* ISDN-P initialized ind */ + __u8 B[1]; /* buffer space for Req,Ind and Rc */ +} eicon_pr_ram; + /* Macro for delay via schedule() */ #define SLEEP(j) { \ set_current_state(TASK_UNINTERRUPTIBLE); \ schedule_timeout(j); \ } -#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) - -#define TRACE_OK (1) - -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 - -#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48 -#define DSP_FILE_FORMAT_VERSION_BCD 0x0100 - -typedef struct tag_dsp_combifile_header -{ - char format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed)); - __u16 format_version_bcd __attribute__ ((packed)); - __u16 header_size __attribute__ ((packed)); - __u16 combifile_description_size __attribute__ ((packed)); - __u16 directory_entries __attribute__ ((packed)); - __u16 directory_size __attribute__ ((packed)); - __u16 download_count __attribute__ ((packed)); - __u16 usage_mask_size __attribute__ ((packed)); -} t_dsp_combifile_header; - -typedef struct tag_dsp_combifile_directory_entry -{ - __u16 card_type_number __attribute__ ((packed)); - __u16 file_set_number __attribute__ ((packed)); -} t_dsp_combifile_directory_entry; - -typedef struct tag_dsp_file_header -{ - char format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed)); - __u16 format_version_bcd __attribute__ ((packed)); - __u16 download_id __attribute__ ((packed)); - __u16 download_flags __attribute__ ((packed)); - __u16 required_processing_power __attribute__ ((packed)); - __u16 interface_channel_count __attribute__ ((packed)); - __u16 header_size __attribute__ ((packed)); - __u16 download_description_size __attribute__ ((packed)); - __u16 memory_block_table_size __attribute__ ((packed)); - __u16 memory_block_count __attribute__ ((packed)); - __u16 segment_table_size __attribute__ ((packed)); - __u16 segment_count __attribute__ ((packed)); - __u16 symbol_table_size __attribute__ ((packed)); - __u16 symbol_count __attribute__ ((packed)); - __u16 total_data_size_dm __attribute__ ((packed)); - __u16 data_block_count_dm __attribute__ ((packed)); - __u16 total_data_size_pm __attribute__ ((packed)); - __u16 data_block_count_pm __attribute__ ((packed)); -} t_dsp_file_header; - -typedef struct tag_dsp_memory_block_desc -{ - __u16 alias_memory_block; - __u16 memory_type; - __u16 address; - __u16 size; /* DSP words */ -} t_dsp_memory_block_desc; - -typedef struct tag_dsp_segment_desc -{ - __u16 memory_block; - __u16 attributes; - __u16 base; - __u16 size; - __u16 alignment; /* ==0 -> no other legal start address than base */ -} t_dsp_segment_desc; - -typedef struct tag_dsp_symbol_desc -{ - __u16 symbol_id; - __u16 segment; - __u16 offset; - __u16 size; /* DSP words */ -} t_dsp_symbol_desc; - -typedef struct tag_dsp_data_block_header -{ - __u16 attributes; - __u16 segment; - __u16 offset; - __u16 size; /* DSP words */ -} t_dsp_data_block_header; - -typedef struct tag_dsp_download_desc /* be sure to keep native alignment for MAESTRA's */ -{ - __u16 download_id; - __u16 download_flags; - __u16 required_processing_power; - __u16 interface_channel_count; - __u16 excess_header_size; - __u16 memory_block_count; - __u16 segment_count; - __u16 symbol_count; - __u16 data_block_count_dm; - __u16 data_block_count_pm; - __u8 * p_excess_header_data __attribute__ ((packed)); - char * p_download_description __attribute__ ((packed)); - t_dsp_memory_block_desc *p_memory_block_table __attribute__ ((packed)); - t_dsp_segment_desc *p_segment_table __attribute__ ((packed)); - t_dsp_symbol_desc *p_symbol_table __attribute__ ((packed)); - __u16 * p_data_blocks_dm __attribute__ ((packed)); - __u16 * p_data_blocks_pm __attribute__ ((packed)); -} t_dsp_download_desc; - - -#ifdef __KERNEL__ - typedef struct { __u8 Req; /* pending request */ __u8 Rc; /* return code received */ @@ -508,6 +230,7 @@ typedef struct { unsigned short statectrl; /* State controling bits */ unsigned short eazmask; /* EAZ-Mask for this Channel */ int queued; /* User-Data Bytes in TX queue */ + int pqueued; /* User-Data Packets in TX queue */ int waitq; /* User-Data Bytes in wait queue */ int waitpq; /* User-Data Bytes in packet queue */ struct sk_buff *tskb1; /* temp skb 1 */ @@ -518,7 +241,9 @@ typedef struct { T30_s *fax; /* pointer to fax data in LL */ eicon_ch_fax_buf fax2; /* fax related struct */ #endif - entity e; /* Entity */ + entity e; /* Native Entity */ + ENTITY de; /* Divas D Entity */ + ENTITY be; /* Divas B Entity */ char cpn[32]; /* remember cpn */ char oad[32]; /* remember oad */ char dsa[32]; /* remember dsa */ @@ -542,8 +267,6 @@ typedef struct { #define EICON_FLAGS_MVALID 8 /* Cards membase is valid */ #define EICON_FLAGS_LOADED 8 /* Firmware loaded */ -#define EICON_BCH 2 /* # of channels per card */ - /* D-Channel states */ #define EICON_STATE_NULL 0 #define EICON_STATE_ICALL 1 @@ -565,9 +288,6 @@ typedef struct { #define EICON_MAX_QUEUE 2138 -#define EICON_LOCK_TX 0 -#define EICON_LOCK_RX 1 - typedef union { eicon_isa_card isa; eicon_pci_card pci; @@ -593,17 +313,12 @@ typedef struct { __u8 more; } eicon_indhdr; -typedef struct msn_entry { - char eaz; - char msn[16]; - struct msn_entry * next; -} msn_entry; - /* * Per card driver data */ typedef struct eicon_card { eicon_hwif hwif; /* Hardware dependant interface */ + DESCRIPTOR *d; /* IDI Descriptor */ u_char ptype; /* Protocol type (1TR6 or Euro) */ u_char bus; /* Bustype (ISA, MCA, PCI) */ u_char type; /* Cardtype (EICON_CTYPE_...) */ @@ -621,49 +336,23 @@ typedef struct eicon_card { struct tq_struct snd_tq; /* Task struct for xmit bh */ struct tq_struct rcv_tq; /* Task struct for rcv bh */ struct tq_struct ack_tq; /* Task struct for ack bh */ - msn_entry *msn_list; eicon_chan* IdTable[256]; /* Table to find entity */ __u16 ref_in; __u16 ref_out; int nchannels; /* Number of B-Channels */ int ReadyInt; /* Ready Interrupt */ eicon_chan *bch; /* B-Channel status/control */ - char status_buf[256]; /* Buffer for status messages */ - char *status_buf_read; - char *status_buf_write; - char *status_buf_end; + DBUFFER *dbuf; /* Dbuffer for Diva Server */ + BUFFERS *sbuf; /* Buffer for Diva Server */ + char *sbufp; /* Data Buffer for Diva Server */ isdn_if interface; /* Interface to upper layer */ - char regname[35]; /* Name used for request_region */ + char regname[35]; /* Drivers card name */ #ifdef CONFIG_MCA int mca_slot; /* # of cards MCA slot */ int mca_io; /* MCA cards IO port */ #endif /* CONFIG_MCA */ } eicon_card; -/* -----------------------------------------------------------** -** The PROTOCOL_FEATURE_STRING ** -** defines capabilities and ** -** features of the actual protocol code. It's used as a bit ** -** mask. ** -** The following Bits are defined: ** -** -----------------------------------------------------------*/ -#define PROTCAP_TELINDUS 0x0001 /* Telindus Variant of protocol code */ -#define PROTCAP_MANIF 0x0002 /* Management interface implemented */ -#define PROTCAP_V_42 0x0004 /* V42 implemented */ -#define PROTCAP_V90D 0x0008 /* V.90D (implies up to 384k DSP code) */ -#define PROTCAP_EXTD_FAX 0x0010 /* Extended FAX (ECM, 2D, T6, Polling) */ -#define PROTCAP_FREE4 0x0020 /* not used */ -#define PROTCAP_FREE5 0x0040 /* not used */ -#define PROTCAP_FREE6 0x0080 /* not used */ -#define PROTCAP_FREE7 0x0100 /* not used */ -#define PROTCAP_FREE8 0x0200 /* not used */ -#define PROTCAP_FREE9 0x0400 /* not used */ -#define PROTCAP_FREE10 0x0800 /* not used */ -#define PROTCAP_FREE11 0x1000 /* not used */ -#define PROTCAP_FREE12 0x2000 /* not used */ -#define PROTCAP_FREE13 0x4000 /* not used */ -#define PROTCAP_EXTENSION 0x8000 /* used for future extentions */ - #include "eicon_idi.h" extern eicon_card *cards; @@ -688,13 +377,11 @@ extern __inline__ void eicon_schedule_ack(eicon_card *card) mark_bh(IMMEDIATE_BH); } -extern char *eicon_find_eaz(eicon_card *, char); -extern int eicon_addcard(int, int, int, char *); +extern int eicon_addcard(int, int, int, char *, int); 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 *); @@ -705,6 +392,8 @@ extern ulong DebugVar; extern void eicon_log(eicon_card * card, int level, const char *fmt, ...); extern void eicon_putstatus(eicon_card * card, char * buf); +extern spinlock_t eicon_lock; + #endif /* __KERNEL__ */ #endif /* eicon_h */ diff --git a/drivers/isdn/eicon/eicon_dsp.h b/drivers/isdn/eicon/eicon_dsp.h index 420d73f6e..1470fa7e6 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.5 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_dsp.h,v 1.7 2000/05/07 08:51:04 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * DSP definitions @@ -20,75 +20,14 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_dsp.h,v $ - * Revision 1.5 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * 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. - * - * Revision 1.1 1999/03/02 12:18:54 armin - * First checkin of DSP defines for audio features. - * * */ #ifndef DSP_H #define DSP_H -#define DSP_UDATA_REQUEST_RECONFIGURE 0 -/* -parameters: - <word> reconfigure delay (in 8kHz samples) - <word> reconfigure code - <byte> reconfigure hdlc preamble flags -*/ +#include "dsp_defs.h" -#define DSP_RECONFIGURE_TX_FLAG 0x8000 -#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG 0x4000 -#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG 0x2000 -#define DSP_RECONFIGURE_HDLC_FLAG 0x1000 -#define DSP_RECONFIGURE_SYNC_FLAG 0x0800 -#define DSP_RECONFIGURE_PROTOCOL_MASK 0x00ff -#define DSP_RECONFIGURE_IDLE 0 -#define DSP_RECONFIGURE_V25 1 -#define DSP_RECONFIGURE_V21_CH2 2 -#define DSP_RECONFIGURE_V27_2400 3 -#define DSP_RECONFIGURE_V27_4800 4 -#define DSP_RECONFIGURE_V29_7200 5 -#define DSP_RECONFIGURE_V29_9600 6 -#define DSP_RECONFIGURE_V33_12000 7 -#define DSP_RECONFIGURE_V33_14400 8 -#define DSP_RECONFIGURE_V17_7200 9 -#define DSP_RECONFIGURE_V17_9600 10 -#define DSP_RECONFIGURE_V17_12000 11 -#define DSP_RECONFIGURE_V17_14400 12 - -/* -data indications if transparent framer - <byte> data 0 - <byte> data 1 - ... - -data indications if HDLC framer - <byte> data 0 - <byte> data 1 - ... - <byte> CRC 0 - <byte> CRC 1 - <byte> preamble flags -*/ #define DSP_UDATA_REQUEST_SWITCH_FRAMER 1 /* @@ -122,49 +61,6 @@ parameters: - none - */ - -#define DSP_UDATA_INDICATION_SYNC 0 -/* -returns: - <word> time of sync (sampled from counter at 8kHz) -*/ - -#define DSP_UDATA_INDICATION_DCD_OFF 1 -/* -returns: - <word> time of DCD off (sampled from counter at 8kHz) -*/ - -#define DSP_UDATA_INDICATION_DCD_ON 2 -/* -returns: - <word> time of DCD on (sampled from counter at 8kHz) - <byte> connected norm - <word> connected options - <dword> connected speed (bit/s, max of tx and rx speed) - <word> roundtrip delay (ms) - <dword> connected speed tx (bit/s) - <dword> connected speed rx (bit/s) -*/ - -#define DSP_UDATA_INDICATION_CTS_OFF 3 -/* -returns: - <word> time of CTS off (sampled from counter at 8kHz) -*/ - -#define DSP_UDATA_INDICATION_CTS_ON 4 -/* -returns: - <word> time of CTS on (sampled from counter at 8kHz) - <byte> connected norm - <word> connected options - <dword> connected speed (bit/s, max of tx and rx speed) - <word> roundtrip delay (ms) - <dword> connected speed tx (bit/s) - <dword> connected speed rx (bit/s) -*/ - typedef struct eicon_dsp_ind { __u16 time __attribute__ ((packed)); __u8 norm __attribute__ ((packed)); @@ -175,32 +71,11 @@ typedef struct eicon_dsp_ind { __u32 rxspeed __attribute__ ((packed)); } eicon_dsp_ind; -#define DSP_CONNECTED_NORM_UNSPECIFIED 0 -#define DSP_CONNECTED_NORM_V21 1 -#define DSP_CONNECTED_NORM_V23 2 -#define DSP_CONNECTED_NORM_V22 3 -#define DSP_CONNECTED_NORM_V22_BIS 4 -#define DSP_CONNECTED_NORM_V32_BIS 5 -#define DSP_CONNECTED_NORM_V34 6 -#define DSP_CONNECTED_NORM_V8 7 -#define DSP_CONNECTED_NORM_BELL_212A 8 -#define DSP_CONNECTED_NORM_BELL_103 9 -#define DSP_CONNECTED_NORM_V29_LEASED_LINE 10 -#define DSP_CONNECTED_NORM_V33_LEASED_LINE 11 -#define DSP_CONNECTED_NORM_V90 12 -#define DSP_CONNECTED_NORM_V21_CH2 13 -#define DSP_CONNECTED_NORM_V27_TER 14 -#define DSP_CONNECTED_NORM_V29 15 -#define DSP_CONNECTED_NORM_V33 16 -#define DSP_CONNECTED_NORM_V17 17 - -#define DSP_CONNECTED_OPTION_TRELLIS 0x0001 #define DSP_CONNECTED_OPTION_V42_TRANS 0x0002 #define DSP_CONNECTED_OPTION_V42_LAPM 0x0004 #define DSP_CONNECTED_OPTION_SHORT_TRAIN 0x0008 #define DSP_CONNECTED_OPTION_TALKER_ECHO_PROTECT 0x0010 - #define DSP_UDATA_INDICATION_DISCONNECT 5 /* returns: @@ -214,7 +89,6 @@ returns: #define DSP_DISCONNECT_CAUSE_CLEARDOWN 0x04 #define DSP_DISCONNECT_CAUSE_TRAINING_TIMEOUT 0x05 - #define DSP_UDATA_INDICATION_TX_CONFIRMATION 6 /* returns: diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c index 9cef520bc..5b63311da 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.33 2000/03/06 15:45:17 armin Exp $ +/* $Id: eicon_idi.c,v 1.41 2000/08/12 18:00:47 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * IDI interface @@ -25,135 +25,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_idi.c,v $ - * Revision 1.33 2000/03/06 15:45:17 armin - * Fixed incomplete number handling with BRI PtP connection. - * - * Revision 1.32 2000/03/04 17:04:21 armin - * Fix of statemachine, B-connect before D-connect, - * thanks to Helmut Adams <adams@ipcon.de> - * Minor change in send-data packet handling. - * - * Revision 1.31 2000/02/22 16:26:40 armin - * Fixed membase error message. - * Fixed missing log buffer struct. - * - * Revision 1.30 2000/02/16 16:08:46 armin - * Fixed virtual channel handling of IDI. - * - * Revision 1.29 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.28 2000/01/20 19:55:34 keil - * Add FAX Class 1 support - * - * Revision 1.27 1999/11/29 13:12:03 armin - * Autoconnect on L2_TRANS doesn't work with link_level correctly, - * changed back to former mode. - * - * Revision 1.26 1999/11/25 11:43:27 armin - * Fixed statectrl and connect message. - * X.75 fix and HDLC/transparent with autoconnect. - * Minor cleanup. - * - * Revision 1.25 1999/11/18 20:30:55 armin - * removed old workaround for ISA cards. - * - * Revision 1.24 1999/10/26 21:15:33 armin - * using define for checking phone number len to avoid buffer overflow. - * - * Revision 1.23 1999/10/11 18:13:25 armin - * Added fax capabilities for Eicon Diva Server cards. - * - * Revision 1.22 1999/10/08 22:09:33 armin - * Some fixes of cards interface handling. - * Bugfix of NULL pointer occurence. - * Changed a few log outputs. - * - * Revision 1.21 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.20 1999/09/21 20:35:43 armin - * added more error checking. - * - * Revision 1.19 1999/09/21 20:06:40 armin - * Added pointer checks. - * - * Revision 1.18 1999/09/07 12:48:05 armin - * Prepared for sub-address usage. - * - * Revision 1.17 1999/09/07 12:35:39 armin - * Better checking and channel Id handling. - * - * Revision 1.16 1999/09/04 13:44:19 armin - * Fix of V.42 analog Modem negotiation handling. - * - * 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. - * - * Revision 1.8 1999/03/02 12:37:43 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.7 1999/02/03 18:34:35 armin - * Channel selection for outgoing calls w/o CHI. - * Added channel # in debug messages. - * L2 Transparent should work with 800 byte/packet now. - * - * Revision 1.6 1999/01/26 07:18:59 armin - * Bug with wrong added CPN fixed. - * - * Revision 1.5 1999/01/24 20:14:11 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.4 1999/01/10 18:46:05 armin - * Bug with wrong values in HLC fixed. - * Bytes to send are counted and limited now. - * - * Revision 1.3 1999/01/05 14:49:34 armin - * Added experimental usage of full BC and HLC for - * speech, 3.1kHz audio, fax gr.2/3 - * - * Revision 1.2 1999/01/04 13:19:29 armin - * Channel status with listen-request wrong - fixed. - * - * Revision 1.1 1999/01/01 18:09:41 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #include <linux/config.h> @@ -161,25 +32,14 @@ #include "eicon.h" #include "eicon_idi.h" #include "eicon_dsp.h" +#include "uxio.h" #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.33 $"; +char *eicon_idi_revision = "$Revision: 1.41 $"; eicon_manifbuf *manbuf; -static char BC_Speech[3] = { 0x80, 0x90, 0xa3 }; -static char BC_31khz[3] = { 0x90, 0x90, 0xa3 }; -static char BC_64k[2] = { 0x88, 0x90 }; -static char BC_video[3] = { 0x91, 0x90, 0xa5 }; - -#ifdef EICON_FULL_SERVICE_OKTETT -/* -static char HLC_telephony[2] = { 0x91, 0x81 }; -*/ -static char HLC_faxg3[2] = { 0x91, 0x84 }; -#endif - 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); @@ -209,7 +69,7 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan) reqbuf->XBuffer.P[l++] = 0; /* end */ reqbuf->Req = ASSIGN; reqbuf->ReqCh = 0; - reqbuf->ReqId = 0; + reqbuf->ReqId = DSIG_ID; reqbuf->XBuffer.length = l; reqbuf->Reference = 0; /* Sig Entity */ } @@ -221,6 +81,9 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan) reqbuf->XBuffer.P[l++] = LLC; reqbuf->XBuffer.P[l++] = 2; switch(chan->l2prot) { + case ISDN_PROTO_L2_V11096: + case ISDN_PROTO_L2_V11019: + case ISDN_PROTO_L2_V11038: case ISDN_PROTO_L2_TRANS: reqbuf->XBuffer.P[l++] = 2; /* transparent */ break; @@ -262,7 +125,7 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan) reqbuf->XBuffer.P[l++] = 0; /* end */ reqbuf->Req = ASSIGN; reqbuf->ReqCh = 0; - reqbuf->ReqId = 0x20; + reqbuf->ReqId = NL_ID; reqbuf->XBuffer.length = l; reqbuf->Reference = 1; /* Net Entity */ } @@ -282,6 +145,21 @@ idi_put_req(eicon_REQ *reqbuf, int rq, int signet, int Ch) } int +idi_put_suspend_req(eicon_REQ *reqbuf, eicon_chan *chan) +{ + reqbuf->Req = SUSPEND; + reqbuf->ReqCh = 0; + reqbuf->ReqId = 1; + reqbuf->XBuffer.P[0] = CAI; + reqbuf->XBuffer.P[1] = 1; + reqbuf->XBuffer.P[2] = chan->No; + reqbuf->XBuffer.P[3] = 0; + reqbuf->XBuffer.length = 4; + reqbuf->Reference = 0; /* Sig Entity */ + return(0); +} + +int idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan) { int l = 9; @@ -295,7 +173,7 @@ idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan) reqbuf->XBuffer.P[4] = 0; reqbuf->XBuffer.P[5] = 0; reqbuf->XBuffer.P[6] = 32; - reqbuf->XBuffer.P[7] = 3; + reqbuf->XBuffer.P[7] = 0; switch(chan->l2prot) { case ISDN_PROTO_L2_X75I: case ISDN_PROTO_L2_X75UI: @@ -391,6 +269,12 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer) case HANGUP: idi_put_req(reqbuf, HANGUP, 0, 0); break; + case SUSPEND: + idi_put_suspend_req(reqbuf, chan); + break; + case RESUME: + idi_put_req(reqbuf, RESUME, 0 ,0); + break; case REJECT: idi_put_req(reqbuf, REJECT, 0 ,0); break; @@ -400,17 +284,20 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer) case CALL_RES: idi_call_res_req(reqbuf, chan); break; - case IDI_N_CONNECT|0x700: - idi_put_req(reqbuf, IDI_N_CONNECT, 1, 0); + case CALL_HOLD: + idi_put_req(reqbuf, CALL_HOLD, 0, 0); + break; + case N_CONNECT|0x700: + idi_put_req(reqbuf, N_CONNECT, 1, 0); break; - case IDI_N_CONNECT_ACK|0x700: - idi_put_req(reqbuf, IDI_N_CONNECT_ACK, 1, 0); + case N_CONNECT_ACK|0x700: + idi_put_req(reqbuf, N_CONNECT_ACK, 1, 0); break; - case IDI_N_DISC|0x700: - idi_put_req(reqbuf, IDI_N_DISC, 1, chan->e.IndCh); + case N_DISC|0x700: + idi_put_req(reqbuf, N_DISC, 1, chan->e.IndCh); break; - case IDI_N_DISC_ACK|0x700: - idi_put_req(reqbuf, IDI_N_DISC_ACK, 1, chan->e.IndCh); + case N_DISC_ACK|0x700: + idi_put_req(reqbuf, N_DISC_ACK, 1, chan->e.IndCh); break; default: eicon_log(card, 1, "idi_req: Ch%d: Unknown request\n", chan->No); @@ -492,7 +379,7 @@ idi_hangup(eicon_card *card, eicon_chan *chan) if ((chan->fsm_state == EICON_STATE_ACTIVE) || (chan->fsm_state == EICON_STATE_WMCONN)) { - if (chan->e.B2Id) idi_do_req(card, chan, IDI_N_DISC, 1); + if (chan->e.B2Id) idi_do_req(card, chan, N_DISC, 1); } if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1); if (chan->fsm_state != EICON_STATE_NULL) { @@ -508,6 +395,32 @@ idi_hangup(eicon_card *card, eicon_chan *chan) } int +capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm) +{ + if ((cm->para[0] != 3) || (cm->para[1] != 0)) + return -1; + if (cm->para[2] < 3) + return -1; + if (cm->para[4] != 0) + return -1; + switch(cm->para[3]) { + case 4: /* Suspend */ + eicon_log(card, 8, "idi_req: Ch%d: Call Suspend\n", chan->No); + if (cm->para[5]) { + idi_do_req(card, chan, SUSPEND, 0); + } else { + idi_do_req(card, chan, CALL_HOLD, 0); + } + break; + case 5: /* Resume */ + eicon_log(card, 8, "idi_req: Ch%d: Call Resume\n", chan->No); + idi_do_req(card, chan, RESUME, 0); + break; + } + return 0; +} + +int idi_connect_res(eicon_card *card, eicon_chan *chan) { if ((!card) || (!chan)) @@ -612,7 +525,14 @@ idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone, reqbuf->XBuffer.P[l++] = *sub++ & 0x7f; } - if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) { + if (si2 > 2) { + reqbuf->XBuffer.P[l++] = SHIFT|6; + reqbuf->XBuffer.P[l++] = SIN; + reqbuf->XBuffer.P[l++] = 2; + reqbuf->XBuffer.P[l++] = si1; + reqbuf->XBuffer.P[l++] = si2; + } + else if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) { reqbuf->XBuffer.P[l++] = BC; reqbuf->XBuffer.P[l++] = tmp; for(i=0; i<tmp;i++) @@ -632,7 +552,7 @@ idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone, reqbuf->XBuffer.P[l++] = 0; reqbuf->XBuffer.P[l++] = 0; reqbuf->XBuffer.P[l++] = 32; - reqbuf->XBuffer.P[l++] = 3; + reqbuf->XBuffer.P[l++] = 0; switch(chan->l2prot) { case ISDN_PROTO_L2_X75I: case ISDN_PROTO_L2_X75UI: @@ -859,7 +779,7 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi } for(i=0; i < wlen; i++) message->llc[i] = buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d\n", chan->No, message->llc[0], + eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d ...\n", chan->No, message->llc[0], message->llc[1],message->llc[2],message->llc[3]); break; case HLC: @@ -869,7 +789,7 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi } for(i=0; i < wlen; i++) message->hlc[i] = buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x\n", chan->No, + eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x ...\n", chan->No, message->hlc[0], message->hlc[1], message->hlc[2], message->hlc[3], message->hlc[4]); break; @@ -1061,31 +981,55 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi } void -idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *si1, unsigned char *si2) +idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *sin, unsigned char *si1, unsigned char *si2) { - si1[0] = 0; - si2[0] = 0; - if (memcmp(bc, BC_Speech, 3) == 0) { /* Speech */ - si1[0] = 1; + si1[0] = 0; + si2[0] = 0; + + switch (bc[0] & 0x7f) { + case 0x00: /* Speech */ + si1[0] = 1; #ifdef EICON_FULL_SERVICE_OKTETT - si2[0] = 1; + si1[0] = sin[0]; + si2[0] = sin[1]; #endif - } - if (memcmp(bc, BC_31khz, 3) == 0) { /* 3.1kHz audio */ - si1[0] = 1; + break; + case 0x10: /* 3.1 Khz audio */ + si1[0] = 1; #ifdef EICON_FULL_SERVICE_OKTETT - si2[0] = 2; - if (memcmp(hlc, HLC_faxg3, 2) == 0) { /* Fax Gr.2/3 */ - si1[0] = 2; - } + si1[0] = sin[0]; + si2[0] = sin[1]; #endif - } - if (memcmp(bc, BC_64k, 2) == 0) { /* unrestricted 64 kbits */ - si1[0] = 7; - } - if (memcmp(bc, BC_video, 3) == 0) { /* video */ - si1[0] = 4; - } + break; + case 0x08: /* Unrestricted digital information */ + si1[0] = 7; + si2[0] = sin[1]; + break; + case 0x09: /* Restricted digital information */ + si1[0] = 2; + break; + case 0x11: + /* Unrestr. digital information with + * tones/announcements ( or 7 kHz audio + */ + si1[0] = 3; + break; + case 0x18: /* Video */ + si1[0] = 4; + break; + } + switch (bc[1] & 0x7f) { + case 0x40: /* packed mode */ + si1[0] = 8; + break; + case 0x10: /* 64 kbit */ + case 0x11: /* 2*64 kbit */ + case 0x13: /* 384 kbit */ + case 0x15: /* 1536 kbit */ + case 0x17: /* 1920 kbit */ + /* moderate = bc[1] & 0x7f; */ + break; + } } /********************* FAX stuff ***************************/ @@ -1225,7 +1169,7 @@ idi_send_edata(eicon_card *card, eicon_chan *chan) reqbuf = (eicon_REQ *)skb_put(skb, sizeof(eicon_t30_s) + sizeof(eicon_REQ)); - reqbuf->Req = IDI_N_EDATA; + reqbuf->Req = N_EDATA; reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; @@ -1359,7 +1303,7 @@ idi_fax_send_header(eicon_card *card, eicon_chan *chan, int header) eicon_log(card, 128, "sSFF-Head: pagelength = %d\n", page->pagelength); break; } - idi_send_data(card, chan, 0, skb, 0); + idi_send_data(card, chan, 0, skb, 0, 0); } void @@ -1913,7 +1857,7 @@ idi_fax_send_outbuf(eicon_card *ccard, eicon_chan *chan, eicon_OBJBUFFER *OutBuf OutBuf->Len = 0; OutBuf->Next = OutBuf->Data; - return(idi_send_data(ccard, chan, 0, skb, 1)); + return(idi_send_data(ccard, chan, 0, skb, 1, 0)); } int @@ -1958,6 +1902,8 @@ idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb) if (chan->queued + skb->len > 1200) return 0; + if (chan->pqueued > 1) + return 0; InBuf.Data = skb->data; InBuf.Size = skb->len; @@ -2183,6 +2129,7 @@ idi_fax_hangup(eicon_card *ccard, eicon_chan *chan) } if ((chan->fax->code > 1) && (chan->fax->code < 120)) chan->fax->code += 120; + eicon_log(ccard, 8, "idi_fax: Ch%d: Hangup (code=%d)\n", chan->No, chan->fax->code); chan->fax->r_code = ISDN_TTY_FAX_HNG; cmd.driver = ccard->myid; cmd.command = ISDN_STAT_FAXIND; @@ -2224,7 +2171,7 @@ idi_send_udata(eicon_card *card, eicon_chan *chan, int UReq, u_char *buffer, int reqbuf = (eicon_REQ *)skb_put(skb, 1 + len + sizeof(eicon_REQ)); - reqbuf->Req = IDI_N_UDATA; + reqbuf->Req = N_UDATA; reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; @@ -2418,12 +2365,12 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) while((skb2 = skb_dequeue(&chan->e.X))) { dev_kfree_skb(skb2); } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); chan->queued = 0; + chan->pqueued = 0; chan->waitq = 0; chan->waitpq = 0; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); if (message.e_cau[0] & 0x7f) { cmd.driver = ccard->myid; cmd.arg = chan->No; @@ -2433,10 +2380,6 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) ccard->interface.statcallb(&cmd); } chan->cause[0] = 0; -#ifdef CONFIG_ISDN_TTY_FAX - if (!chan->e.B2Id) - chan->fax = 0; -#endif if (((chan->fsm_state == EICON_STATE_ACTIVE) || (chan->fsm_state == EICON_STATE_WMCONN)) || ((chan->l2prot == ISDN_PROTO_L2_FAX) && @@ -2446,6 +2389,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) if (chan->e.B2Id) idi_do_req(ccard, chan, REMOVE, 1); chan->statectrl &= ~WAITING_FOR_HANGUP; + chan->statectrl &= ~IN_HOLD; if (chan->statectrl & HAVE_CONN_REQ) { eicon_log(ccard, 32, "idi_req: Ch%d: queueing delayed conn_req\n", chan->No); chan->statectrl &= ~HAVE_CONN_REQ; @@ -2463,6 +2407,9 @@ 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 + chan->fax = 0; +#endif } } break; @@ -2475,7 +2422,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) break; } chan->fsm_state = EICON_STATE_ICALL; - idi_bc2si(message.bc, message.hlc, &chan->si1, &chan->si2); + idi_bc2si(message.bc, message.hlc, message.sin, &chan->si1, &chan->si2); strcpy(chan->cpn, message.cpn + 1); strcpy(chan->oad, message.oad); strcpy(chan->dsa, message.dsa); @@ -2553,12 +2500,15 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) case ISDN_PROTO_L2_MODEM: /* do nothing, wait for connect */ break; + case ISDN_PROTO_L2_V11096: + case ISDN_PROTO_L2_V11019: + case ISDN_PROTO_L2_V11038: case ISDN_PROTO_L2_TRANS: - idi_do_req(ccard, chan, IDI_N_CONNECT, 1); + idi_do_req(ccard, chan, N_CONNECT, 1); break; default: /* On most incoming calls we use automatic connect */ - /* idi_do_req(ccard, chan, IDI_N_CONNECT, 1); */ + /* idi_do_req(ccard, chan, N_CONNECT, 1); */ } } else { if (chan->fsm_state != EICON_STATE_ACTIVE) @@ -2568,33 +2518,50 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) case CALL_CON: eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Con\n", chan->No); if (chan->fsm_state == EICON_STATE_OCALL) { - chan->fsm_state = EICON_STATE_OBWAIT; - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_DCONN; - cmd.arg = chan->No; - ccard->interface.statcallb(&cmd); - /* check if old NetID has been removed */ if (chan->e.B2Id) { eicon_log(ccard, 1, "eicon: Ch%d: old net_id %x still exist, removing.\n", chan->No, chan->e.B2Id); idi_do_req(ccard, chan, REMOVE, 1); } - - 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) + if (chan->fax) { chan->fax->phase = ISDN_FAX_PHASE_A; + } else { + eicon_log(ccard, 1, "idi_ind: Call_Con with NULL fax struct, ERROR\n"); + idi_hangup(ccard, chan); + break; + } } #endif + chan->fsm_state = EICON_STATE_OBWAIT; + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_DCONN; + cmd.arg = chan->No; + ccard->interface.statcallb(&cmd); + + idi_do_req(ccard, chan, ASSIGN, 1); + idi_do_req(ccard, chan, N_CONNECT, 1); } else - idi_hangup(ccard, chan); + idi_hangup(ccard, chan); break; case AOC_IND: eicon_log(ccard, 8, "idi_ind: Ch%d: Advice of Charge\n", chan->No); break; + case CALL_HOLD_ACK: + chan->statectrl |= IN_HOLD; + eicon_log(ccard, 8, "idi_ind: Ch%d: Call Hold Ack\n", chan->No); + break; + case SUSPEND_REJ: + eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Rejected\n", chan->No); + break; + case SUSPEND: + eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Ack\n", chan->No); + break; + case RESUME: + eicon_log(ccard, 8, "idi_ind: Ch%d: Resume Ack\n", chan->No); + break; default: eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED SigIndication 0x%02x\n", chan->No, ind->Ind); } @@ -2613,7 +2580,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) } else switch(ind->Ind) { - case IDI_N_CONNECT_ACK: + case N_CONNECT_ACK: eicon_log(ccard, 16, "idi_ind: Ch%d: N_Connect_Ack\n", chan->No); if (chan->l2prot == ISDN_PROTO_L2_MODEM) { chan->fsm_state = EICON_STATE_WMCONN; @@ -2634,7 +2601,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) } } else { - eicon_log(ccard, 1, "idi_ind: N_CONNECT_ACK with NULL fax struct, ERROR\n"); + eicon_log(ccard, 1, "idi_ind: N_Connect_Ack with NULL fax struct, ERROR\n"); } #endif break; @@ -2646,10 +2613,10 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) strcpy(cmd.parm.num, "64000"); ccard->interface.statcallb(&cmd); break; - case IDI_N_CONNECT: + case N_CONNECT: eicon_log(ccard, 16,"idi_ind: Ch%d: N_Connect\n", chan->No); chan->e.IndCh = ind->IndCh; - if (chan->e.B2Id) idi_do_req(ccard, chan, IDI_N_CONNECT_ACK, 1); + if (chan->e.B2Id) idi_do_req(ccard, chan, N_CONNECT_ACK, 1); if (chan->l2prot == ISDN_PROTO_L2_FAX) { break; } @@ -2664,43 +2631,47 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) strcpy(cmd.parm.num, "64000"); ccard->interface.statcallb(&cmd); break; - case IDI_N_DISC: - eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC\n", chan->No); + case N_DISC: + eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc\n", chan->No); if (chan->e.B2Id) { while((skb2 = skb_dequeue(&chan->e.X))) { dev_kfree_skb(skb2); } - idi_do_req(ccard, chan, IDI_N_DISC_ACK, 1); + idi_do_req(ccard, chan, N_DISC_ACK, 1); idi_do_req(ccard, chan, REMOVE, 1); } #ifdef CONFIG_ISDN_TTY_FAX - if (chan->l2prot == ISDN_PROTO_L2_FAX) { + if ((chan->l2prot == ISDN_PROTO_L2_FAX) && (chan->fax)){ idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); idi_fax_hangup(ccard, chan); } #endif chan->e.IndCh = 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); chan->queued = 0; + chan->pqueued = 0; chan->waitq = 0; chan->waitpq = 0; - restore_flags(flags); - idi_do_req(ccard, chan, HANGUP, 0); + spin_unlock_irqrestore(&eicon_lock, flags); + if (!(chan->statectrl & IN_HOLD)) { + 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); chan->fsm_state = EICON_STATE_NULL; - chan->statectrl |= WAITING_FOR_HANGUP; + if (!(chan->statectrl & IN_HOLD)) { + chan->statectrl |= WAITING_FOR_HANGUP; + } } #ifdef CONFIG_ISDN_TTY_FAX chan->fax = 0; #endif break; - case IDI_N_DISC_ACK: - eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC_ACK\n", chan->No); + case N_DISC_ACK: + eicon_log(ccard, 16, "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); @@ -2708,10 +2679,10 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) } #endif break; - case IDI_N_DATA_ACK: - eicon_log(ccard, 128, "idi_ind: Ch%d: N_DATA_ACK\n", chan->No); + case N_DATA_ACK: + eicon_log(ccard, 128, "idi_ind: Ch%d: N_Data_Ack\n", chan->No); break; - case IDI_N_DATA: + case N_DATA: skb_pull(skb, sizeof(eicon_IND) - 1); eicon_log(ccard, 128, "idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len); if (chan->l2prot == ISDN_PROTO_L2_FAX) { @@ -2723,11 +2694,11 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) free_buff = 0; } break; - case IDI_N_UDATA: + case N_UDATA: idi_parse_udata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); break; #ifdef CONFIG_ISDN_TTY_FAX - case IDI_N_EDATA: + case N_EDATA: idi_edata_action(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); break; #endif @@ -2747,6 +2718,8 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) { ulong flags; isdn_ctrl cmd; + int tqueued = 0; + int twaitpq = 0; if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) { /* I dont know why this happens, should not ! */ @@ -2770,16 +2743,15 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) eicon_log(ccard, 16, "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No, ack->Reference, chan->e.ref); } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); ccard->IdTable[ack->RcId] = NULL; - eicon_log(ccard, 16, "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; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); + eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No, + ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig"); return 1; } @@ -2790,25 +2762,21 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) } else { /* Network layer */ switch(chan->e.Req & 0x0f) { - case IDI_N_CONNECT: + case N_CONNECT: chan->e.IndCh = ack->RcCh; eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, ack->RcId, ack->RcCh, ack->Reference); break; - 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); - } - save_flags(flags); - cli(); + case N_MDATA: + case N_DATA: + tqueued = chan->queued; + twaitpq = chan->waitpq; + if ((chan->e.Req & 0x0f) == N_DATA) { + spin_lock_irqsave(&eicon_lock, flags); chan->waitpq = 0; - restore_flags(flags); + if(chan->pqueued) + chan->pqueued--; + spin_unlock_irqrestore(&eicon_lock, flags); #ifdef CONFIG_ISDN_TTY_FAX if (chan->l2prot == ISDN_PROTO_L2_FAX) { if (((chan->queued - chan->waitq) < 1) && @@ -2828,11 +2796,17 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) } #endif } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); chan->queued -= chan->waitq; if (chan->queued < 0) chan->queued = 0; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); + if (((chan->e.Req & 0x0f) == N_DATA) && (tqueued)) { + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_BSENT; + cmd.arg = chan->No; + cmd.parm.length = twaitpq; + ccard->interface.statcallb(&cmd); + } break; default: eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, @@ -2858,11 +2832,10 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) return; } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if ((chan = ccard->IdTable[ack->RcId]) != NULL) dCh = chan->No; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); switch (ack->Rc) { case OK_FC: @@ -2890,8 +2863,7 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) eicon_log(ccard, 1, "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%x,%x)\n", chan->No, chan->e.D3Id, chan->e.B2Id); } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); for(j = 0; j < ccard->nchannels + 1; j++) { if ((ccard->bch[j].e.ref == ack->Reference) && (ccard->bch[j].e.Req == ASSIGN)) { @@ -2901,12 +2873,12 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) ccard->bch[j].e.B2Id = ack->RcId; ccard->IdTable[ack->RcId] = &ccard->bch[j]; chan = &ccard->bch[j]; - eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j, - ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig"); break; } - } - restore_flags(flags); + } + spin_unlock_irqrestore(&eicon_lock, flags); + eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j, + ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig"); if (j > ccard->nchannels) { eicon_log(ccard, 24, "idi_ack: Ch??: ref %d not found for Id %d\n", ack->Reference, ack->RcId); @@ -2917,6 +2889,7 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) case UNKNOWN_COMMAND: case WRONG_COMMAND: case WRONG_ID: + case ADAPTER_DEAD: case WRONG_CH: case UNKNOWN_IE: case WRONG_IE: @@ -2949,19 +2922,18 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) ccard->interface.statcallb(&cmd); } } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if (chan) { chan->e.ref = 0; chan->e.busy = 0; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); dev_kfree_skb(skb); eicon_schedule_tx(ccard); } int -idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que) +idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk) { struct sk_buff *xmit_skb; struct sk_buff *skb2; @@ -2985,13 +2957,14 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, return -1; if (!len) return 0; - if (chan->queued + len > EICON_MAX_QUEUE) + + if ((chk) && (chan->pqueued > 1)) return 0; - eicon_log(card, 128, "idi_snd: Ch%d: %d bytes\n", chan->No, len); + eicon_log(card, 128, "idi_snd: Ch%d: %d bytes (Pqueue=%d)\n", + chan->No, len, chan->pqueued); - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); while(offset < len) { plen = ((len - offset) > 270) ? 270 : len - offset; @@ -3000,7 +2973,7 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); if ((!xmit_skb) || (!skb2)) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No); if (xmit_skb) dev_kfree_skb(skb); @@ -3013,13 +2986,10 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, chan2->ptr = chan; reqbuf = (eicon_REQ *)skb_put(xmit_skb, plen + sizeof(eicon_REQ)); - if (((len - offset) > 270) && - (chan->l2prot != ISDN_PROTO_L2_MODEM) && - (chan->l2prot != ISDN_PROTO_L2_FAX) && - (chan->l2prot != ISDN_PROTO_L2_TRANS)) { - reqbuf->Req = IDI_N_MDATA; + if ((len - offset) > 270) { + reqbuf->Req = N_MDATA; } else { - reqbuf->Req = IDI_N_DATA; + reqbuf->Req = N_DATA; /* if (ack) reqbuf->Req |= N_D_BIT; */ } reqbuf->ReqCh = chan->e.IndCh; @@ -3033,9 +3003,11 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, offset += plen; } - if (que) + if (que) { chan->queued += len; - restore_flags(flags); + chan->pqueued++; + } + spin_unlock_irqrestore(&eicon_lock, flags); eicon_schedule_tx(card); dev_kfree_skb(skb); return len; @@ -3073,7 +3045,7 @@ eicon_idi_manage_assign(eicon_card *card) reqbuf->XBuffer.P[0] = 0; reqbuf->Req = ASSIGN; reqbuf->ReqCh = 0; - reqbuf->ReqId = 0xe0; + reqbuf->ReqId = MAN_ID; reqbuf->XBuffer.length = 1; reqbuf->Reference = 2; /* Man Entity */ @@ -3199,7 +3171,7 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb) reqbuf->XBuffer.P[1] = manbuf->length[0] + 1; reqbuf->XBuffer.P[l++] = 0; - reqbuf->Req = (manbuf->count) ? manbuf->count : 0x02; /* Request */ + reqbuf->Req = (manbuf->count) ? manbuf->count : MAN_READ; reqbuf->ReqCh = 0; reqbuf->ReqId = 1; reqbuf->XBuffer.length = l; diff --git a/drivers/isdn/eicon/eicon_idi.h b/drivers/isdn/eicon/eicon_idi.h index 2fe6167a4..a11039219 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.9 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_idi.h,v 1.11 2000/05/07 08:51:04 armin Exp $ * * ISDN lowlevel-module for the Eicon active cards. * IDI-Interface @@ -20,168 +20,30 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_idi.h,v $ - * Revision 1.9 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.8 1999/11/25 11:43:27 armin - * Fixed statectrl and connect message. - * X.75 fix and HDLC/transparent with autoconnect. - * Minor cleanup. - * - * 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. - * - * Revision 1.3 1999/03/02 12:37:45 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.2 1999/01/24 20:14:18 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.1 1999/01/01 18:09:42 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * * */ -#ifndef IDI_H -#define IDI_H +#ifndef E_IDI_H +#define E_IDI_H #include <linux/config.h> -#define ASSIGN 0x01 -#define REMOVE 0xff - -#define CALL_REQ 1 /* call request */ -#define CALL_CON 1 /* call confirmation */ -#define CALL_IND 2 /* incoming call connected */ -#define LISTEN_REQ 2 /* listen request */ -#define HANGUP 3 /* hangup request/indication */ -#define SUSPEND 4 /* call suspend request/confirm */ -#define RESUME 5 /* call resume request/confirm */ -#define SUSPEND_REJ 6 /* suspend rejected indication */ -#define USER_DATA 8 /* user data for user to user signaling */ -#define CONGESTION 9 /* network congestion indication */ -#define INDICATE_REQ 10 /* request to indicate an incoming call */ -#define INDICATE_IND 10 /* indicates that there is an incoming call */ -#define CALL_RES 11 /* accept an incoming call */ -#define CALL_ALERT 12 /* send ALERT for incoming call */ -#define INFO_REQ 13 /* INFO request */ -#define INFO_IND 13 /* INFO indication */ -#define REJECT 14 /* reject an incoming call */ -#define RESOURCES 15 /* reserve B-Channel hardware resources */ -#define TEL_CTRL 16 /* Telephone control request/indication */ -#define STATUS_REQ 17 /* Request D-State (returned in INFO_IND) */ -#define FAC_REG_REQ 18 /* connection idependent fac registration */ -#define FAC_REG_ACK 19 /* fac registration acknowledge */ -#define FAC_REG_REJ 20 /* fac registration reject */ -#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call */ -#define AOC_IND 26/* Advice of Charge */ - -#define IDI_N_MDATA (0x01) -#define IDI_N_CONNECT (0x02) -#define IDI_N_CONNECT_ACK (0x03) -#define IDI_N_DISC (0x04) -#define IDI_N_DISC_ACK (0x05) -#define IDI_N_RESET (0x06) -#define IDI_N_RESET_ACK (0x07) -#define IDI_N_DATA (0x08) -#define IDI_N_EDATA (0x09) -#define IDI_N_UDATA (0x0a) -#define IDI_N_BDATA (0x0b) -#define IDI_N_DATA_ACK (0x0c) -#define IDI_N_EDATA_ACK (0x0d) +#undef N_DATA +#undef ID_MASK -#define N_Q_BIT 0x10 /* Q-bit for req/ind */ -#define N_M_BIT 0x20 /* M-bit for req/ind */ -#define N_D_BIT 0x40 /* D-bit for req/ind */ +#include "pc.h" +#define AOC_IND 26 /* Advice of Charge */ +#define PI 0x1e /* Progress Indicator */ +#define NI 0x27 /* Notification Indicator */ -#define SHIFT 0x90 /* codeset shift */ -#define MORE 0xa0 /* more data */ -#define CL 0xb0 /* congestion level */ - - /* codeset 0 */ - -#define BC 0x04 /* Bearer Capability */ -#define CAU 0x08 /* cause */ -#define CAD 0x0c /* Connected address */ -#define CAI 0x10 /* call identity */ -#define CHI 0x18 /* channel identification */ -#define LLI 0x19 /* logical link id */ -#define CHA 0x1a /* charge advice */ -#define FTY 0x1c -#define PI 0x1e /* Progress Indicator */ -#define NI 0x27 /* Notification Indicator */ -#define DT 0x29 /* ETSI date/time */ -#define KEY 0x2c /* keypad information element */ -#define DSP 0x28 /* display */ -#define OAD 0x6c /* origination address */ -#define OSA 0x6d /* origination sub-address */ -#define CPN 0x70 /* called party number */ -#define DSA 0x71 /* destination sub-address */ -#define RDN 0x74 /* redirecting number */ -#define LLC 0x7c /* low layer compatibility */ -#define HLC 0x7d /* high layer compatibility */ -#define UUI 0x7e /* user user information */ -#define ESC 0x7f /* escape extension */ - -#define DLC 0x20 /* data link layer configuration */ -#define NLC 0x21 /* network layer configuration */ - - /* codeset 6 */ - -#define SIN 0x01 /* service indicator */ -#define CIF 0x02 /* charging information */ -#define DATE 0x03 /* date */ -#define CPS 0x07 /* called party status */ - -/*------------------------------------------------------------------*/ -/* return code coding */ -/*------------------------------------------------------------------*/ - -#define UNKNOWN_COMMAND 0x01 /* unknown command */ -#define WRONG_COMMAND 0x02 /* wrong command */ -#define WRONG_ID 0x03 /* unknown task/entity id */ -#define WRONG_CH 0x04 /* wrong task/entity id */ -#define UNKNOWN_IE 0x05 /* unknown information el. */ -#define WRONG_IE 0x06 /* wrong information el. */ -#define OUT_OF_RESOURCES 0x07 /* card out of res. */ -#define N_FLOW_CONTROL 0x10 /* Flow-Control, retry */ -#define ASSIGN_RC 0xe0 /* ASSIGN acknowledgement */ -#define ASSIGN_OK 0xef /* ASSIGN OK */ -#define OK_FC 0xfc /* Flow-Control RC */ -#define READY_INT 0xfd /* Ready interrupt */ -#define TIMER_INT 0xfe /* timer interrupt */ -#define OK 0xff /* command accepted */ - -/*------------------------------------------------------------------*/ +#define CALL_HOLD 0x22 +#define CALL_HOLD_ACK 0x24 /* defines for statectrl */ #define WAITING_FOR_HANGUP 0x01 #define HAVE_CONN_REQ 0x02 +#define IN_HOLD 0x04 typedef struct { char cpn[32]; @@ -242,26 +104,6 @@ typedef struct { } eicon_IND; typedef struct { - __u16 NextReq __attribute__ ((packed)); /* pointer to next Req Buffer */ - __u16 NextRc __attribute__ ((packed)); /* pointer to next Rc Buffer */ - __u16 NextInd __attribute__ ((packed)); /* pointer to next Ind Buffer */ - __u8 ReqInput __attribute__ ((packed)); /* number of Req Buffers sent */ - __u8 ReqOutput __attribute__ ((packed)); /* number of Req Buffers returned */ - __u8 ReqReserved __attribute__ ((packed));/*number of Req Buffers reserved */ - __u8 Int __attribute__ ((packed)); /* ISDN-P interrupt */ - __u8 XLock __attribute__ ((packed)); /* Lock field for arbitration */ - __u8 RcOutput __attribute__ ((packed)); /* number of Rc buffers received */ - __u8 IndOutput __attribute__ ((packed)); /* number of Ind buffers received */ - __u8 IMask __attribute__ ((packed)); /* Interrupt Mask Flag */ - __u8 Reserved1[2] __attribute__ ((packed)); /* reserved field, do not use */ - __u8 ReadyInt __attribute__ ((packed)); /* request field for ready int */ - __u8 Reserved2[12] __attribute__ ((packed)); /* reserved field, do not use */ - __u8 InterfaceType __attribute__ ((packed)); /* interface type 1=16K */ - __u16 Signature __attribute__ ((packed)); /* ISDN-P initialized ind */ - __u8 B[1]; /* buffer space for Req,Ind and Rc */ -} eicon_pr_ram; - -typedef struct { __u8 *Data; unsigned int Size; unsigned int Len; @@ -278,8 +120,9 @@ 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, int que); +extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk); extern void idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value); +extern int capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm); #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); diff --git a/drivers/isdn/eicon/eicon_io.c b/drivers/isdn/eicon/eicon_io.c index 4f4180ed6..6f294e8b7 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.10 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_io.c,v 1.13 2000/05/07 08:51:04 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Code for communicating with hardware. @@ -23,52 +23,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_io.c,v $ - * Revision 1.10 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.9 1999/11/18 20:55:25 armin - * Ready_Int fix of ISA cards. - * - * Revision 1.8 1999/10/08 22:09:34 armin - * Some fixes of cards interface handling. - * Bugfix of NULL pointer occurence. - * Changed a few log outputs. - * - * Revision 1.7 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.6 1999/09/21 20:35:43 armin - * added more error checking. - * - * Revision 1.5 1999/08/31 11:20:11 paul - * various spelling corrections (new checksums may be needed, Karsten!) - * - * 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. - * - * */ #include <linux/config.h> #include "eicon.h" +#include "uxio.h" void eicon_io_rcv_dispatch(eicon_card *ccard) { @@ -85,12 +45,12 @@ eicon_io_rcv_dispatch(eicon_card *ccard) { while((skb = skb_dequeue(&ccard->rcvq))) { ind = (eicon_IND *)skb->data; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if ((chan = ccard->IdTable[ind->IndId]) == NULL) { + spin_unlock_irqrestore(&eicon_lock, flags); if (DebugVar & 1) { switch(ind->Ind) { - case IDI_N_DISC_ACK: + case N_DISC_ACK: /* doesn't matter if this happens */ break; default: @@ -99,11 +59,10 @@ eicon_io_rcv_dispatch(eicon_card *ccard) { ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length); } } - restore_flags(flags); dev_kfree_skb(skb); continue; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); if (chan->e.complete) { /* check for rec-buffer chaining */ if (ind->MLength == ind->RBuffer.length) { @@ -119,12 +78,9 @@ eicon_io_rcv_dispatch(eicon_card *ccard) { } } else { - save_flags(flags); - cli(); if (!(skb2 = skb_dequeue(&chan->e.R))) { chan->e.complete = 1; eicon_log(ccard, 1, "eicon: buffer incomplete, but 0 in queue\n"); - restore_flags(flags); dev_kfree_skb(skb); continue; } @@ -133,7 +89,6 @@ eicon_io_rcv_dispatch(eicon_card *ccard) { GFP_ATOMIC); if (!skb_new) { eicon_log(ccard, 1, "eicon_io: skb_alloc failed in rcv_dispatch()\n"); - restore_flags(flags); dev_kfree_skb(skb); dev_kfree_skb(skb2); continue; @@ -152,14 +107,12 @@ eicon_io_rcv_dispatch(eicon_card *ccard) { dev_kfree_skb(skb2); if (ind->MLength == ind->RBuffer.length) { chan->e.complete = 2; - restore_flags(flags); idi_handle_ind(ccard, skb_new); continue; } else { chan->e.complete = 0; skb_queue_tail(&chan->e.R, skb_new); - restore_flags(flags); continue; } } @@ -181,242 +134,120 @@ eicon_io_ack_dispatch(eicon_card *ccard) { /* - * IO-Functions for different card-types + * IO-Functions for ISA cards */ u8 ram_inb(eicon_card *card, void *adr) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - return(inb((u16)pcard->PCIreg + M_DATA)); - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - return(readb(addr)); - } - return(0); + return(readb(addr)); } u16 ram_inw(eicon_card *card, void *adr) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - return(inw((u16)pcard->PCIreg + M_DATA)); - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - return(readw(addr)); - } - return(0); + + return(readw(addr)); } void ram_outb(eicon_card *card, void *adr, u8 data) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - outb((u8)data, (u16)pcard->PCIreg + M_DATA); - break; - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - writeb(data, addr); - break; - } + writeb(data, addr); } void ram_outw(eicon_card *card, void *adr , u16 data) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - outw((u16)data, (u16)pcard->PCIreg + M_DATA); - break; - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - writew(data, addr); - break; - } + writew(data, addr); } void ram_copyfromcard(eicon_card *card, void *adrto, void *adr, int len) { - int i; - switch(card->type) { - case EICON_CTYPE_MAESTRA: - for(i = 0; i < len; i++) { - writeb(ram_inb(card, adr + i), adrto + i); - } - break; - case EICON_CTYPE_MAESTRAP: - memcpy(adrto, adr, len); - break; - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - memcpy_fromio(adrto, adr, len); - break; - } + memcpy_fromio(adrto, adr, len); } void ram_copytocard(eicon_card *card, void *adrto, void *adr, int len) { - int i; - switch(card->type) { - case EICON_CTYPE_MAESTRA: - for(i = 0; i < len; i++) { - ram_outb(card, adrto + i, readb(adr + i)); - } - break; - case EICON_CTYPE_MAESTRAP: - memcpy(adrto, adr, len); - break; - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - memcpy_toio(adrto, adr, len); - break; - } + memcpy_toio(adrto, adr, len); } + +#ifdef CONFIG_ISDN_DRV_EICON_PCI /* - * XLOG + * IDI-Callback function */ -int -eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq) +void +eicon_idi_callback(ENTITY *de) { - int timeout, i; - int divas_shared_offset = 0; + eicon_card *ccard = (eicon_card *)de->R; + struct sk_buff *skb; + eicon_RC *ack; + eicon_IND *ind; 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; + if (de->complete == 255) { + /* Return Code */ + skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC); + if (!skb) { + eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _idi_callback()\n"); + } else { + ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC)); + ack->Rc = de->Rc; + if (de->Rc == ASSIGN_OK) { + ack->RcId = de->Id; + de->user[1] = de->Id; + } else { + ack->RcId = de->user[1]; + } + ack->RcCh = de->RcCh; + ack->Reference = de->user[0]; + skb_queue_tail(&ccard->rackq, skb); + eicon_schedule_ack(ccard); + eicon_log(ccard, 128, "idi_cbk: Ch%d: Rc=%x Id=%x RLen=%x compl=%x\n", + de->user[0], de->Rc, ack->RcId, de->RLength, de->complete); + } + } else { + /* Indication */ + if (de->complete) { + len = de->RLength; + } else { + len = 270; + if (de->RLength <= 270) + eicon_log(ccard, 1, "eicon_cbk: ind not complete but <= 270\n"); + } + skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC); + if (!skb) { + eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _idi_callback()\n"); + } else { + ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1)); + ind->Ind = de->Ind; + ind->IndId = de->user[1]; + ind->IndCh = de->IndCh; + ind->MInd = de->Ind; + ind->RBuffer.length = len; + ind->MLength = de->RLength; + memcpy(&ind->RBuffer.P, &de->RBuffer->P, len); + skb_queue_tail(&ccard->rcvq, skb); + eicon_schedule_rx(ccard); + eicon_log(ccard, 128, "idi_cbk: Ch%d: Ind=%x Id=%x RLen=%x compl=%x\n", + de->user[0], de->Ind, ind->IndId, de->RLength, de->complete); + } } - return XLOG_OK; + de->RNum = 0; + de->RNR = 0; + de->Rc = 0; + de->Ind = 0; } +#endif /* CONFIG_ISDN_DRV_EICON_PCI */ /* * Transmit-Function */ void eicon_io_transmit(eicon_card *ccard) { - eicon_pci_card *pci_card; eicon_isa_card *isa_card; struct sk_buff *skb; struct sk_buff *skb2; unsigned long flags; - char *ram, *reg, *cfg; eicon_pr_ram *prram = 0; eicon_isa_com *com = 0; eicon_REQ *ReqOut = 0; @@ -426,10 +257,11 @@ eicon_io_transmit(eicon_card *ccard) { int ReqCount; int scom = 0; int tmp = 0; + int tmpid = 0; int quloop = 1; int dlev = 0; + ENTITY *ep = 0; - pci_card = &ccard->hwif.pci; isa_card = &ccard->hwif.isa; if (!ccard) { @@ -451,20 +283,17 @@ eicon_io_transmit(eicon_card *ccard) { prram = (eicon_pr_ram *)isa_card->shmem; break; #endif +#ifdef CONFIG_ISDN_DRV_EICON_PCI case EICON_CTYPE_MAESTRAP: - scom = 0; - ram = (char *)pci_card->PCIram; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - prram = (eicon_pr_ram *)ram; + scom = 2; + break; + case EICON_CTYPE_MAESTRAQ: + scom = 2; break; case EICON_CTYPE_MAESTRA: - scom = 0; - ram = (char *)pci_card->PCIram; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - prram = 0; + scom = 2; break; +#endif default: eicon_log(ccard, 1, "eicon_transmit: unsupported card-type!\n"); return; @@ -474,69 +303,91 @@ eicon_io_transmit(eicon_card *ccard) { if (!(skb2 = skb_dequeue(&ccard->sndq))) quloop = 0; while(quloop) { - save_flags(flags); - cli(); - if (scom) { + spin_lock_irqsave(&eicon_lock, flags); + switch (scom) { + case 1: if ((ram_inb(ccard, &com->Req)) || (ccard->ReadyInt)) { if (!ccard->ReadyInt) { tmp = ram_inb(ccard, &com->ReadyInt) + 1; ram_outb(ccard, &com->ReadyInt, tmp); ccard->ReadyInt++; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); skb_queue_head(&ccard->sndq, skb2); eicon_log(ccard, 32, "eicon: transmit: Card not ready\n"); return; } - } else { + break; + case 0: if (!(ram_inb(ccard, &prram->ReqOutput) - ram_inb(ccard, &prram->ReqInput))) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); skb_queue_head(&ccard->sndq, skb2); eicon_log(ccard, 32, "eicon: transmit: Card not ready\n"); return; } + break; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); + chan2 = (eicon_chan_ptr *)skb2->data; chan = chan2->ptr; if (!chan->e.busy) { if((skb = skb_dequeue(&chan->e.X))) { - save_flags(flags); - cli(); + reqbuf = (eicon_REQ *)skb->data; if ((reqbuf->Reference) && (chan->e.B2Id == 0) && (reqbuf->ReqId & 0x1f)) { eicon_log(ccard, 16, "eicon: transmit: error Id=0 on %d (Net)\n", chan->No); } else { - if (scom) { + spin_lock_irqsave(&eicon_lock, flags); + + switch (scom) { + case 1: ram_outw(ccard, &com->XBuffer.length, reqbuf->XBuffer.length); ram_copytocard(ccard, &com->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); ram_outb(ccard, &com->ReqCh, reqbuf->ReqCh); - - } else { + break; + case 0: /* get address of next available request buffer */ ReqOut = (eicon_REQ *)&prram->B[ram_inw(ccard, &prram->NextReq)]; ram_outw(ccard, &ReqOut->XBuffer.length, reqbuf->XBuffer.length); ram_copytocard(ccard, &ReqOut->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); ram_outb(ccard, &ReqOut->ReqCh, reqbuf->ReqCh); ram_outb(ccard, &ReqOut->Req, reqbuf->Req); + break; } + dlev = 160; + if (reqbuf->ReqId & 0x1f) { /* if this is no ASSIGN */ if (!reqbuf->Reference) { /* Signal Layer */ - if (scom) + switch (scom) { + case 1: ram_outb(ccard, &com->ReqId, chan->e.D3Id); - else + break; + case 0: ram_outb(ccard, &ReqOut->ReqId, chan->e.D3Id); - + break; + case 2: + ep = &chan->de; + break; + } + tmpid = chan->e.D3Id; chan->e.ReqCh = 0; } else { /* Net Layer */ - if (scom) + switch(scom) { + case 1: ram_outb(ccard, &com->ReqId, chan->e.B2Id); - else + break; + case 0: ram_outb(ccard, &ReqOut->ReqId, chan->e.B2Id); - + break; + case 2: + ep = &chan->be; + break; + } + tmpid = chan->e.B2Id; chan->e.ReqCh = 1; if (((reqbuf->Req & 0x0f) == 0x08) || ((reqbuf->Req & 0x0f) == 0x01)) { /* Send Data */ @@ -548,51 +399,106 @@ eicon_io_transmit(eicon_card *ccard) { } else { /* It is an ASSIGN */ - if (scom) + switch(scom) { + case 1: ram_outb(ccard, &com->ReqId, reqbuf->ReqId); - else + break; + case 0: ram_outb(ccard, &ReqOut->ReqId, reqbuf->ReqId); + break; + case 2: + if (!reqbuf->Reference) + ep = &chan->de; + else + ep = &chan->be; + ep->Id = reqbuf->ReqId; + break; + } + tmpid = reqbuf->ReqId; if (!reqbuf->Reference) chan->e.ReqCh = 0; else chan->e.ReqCh = 1; } - if (scom) + + switch(scom) { + case 1: chan->e.ref = ccard->ref_out++; - else + break; + case 0: chan->e.ref = ram_inw(ccard, &ReqOut->Reference); + break; + case 2: + chan->e.ref = chan->No; + break; + } chan->e.Req = reqbuf->Req; ReqCount++; - if (scom) + + switch (scom) { + case 1: ram_outb(ccard, &com->Req, reqbuf->Req); - else + break; + case 0: ram_outw(ccard, &prram->NextReq, ram_inw(ccard, &ReqOut->next)); + break; + case 2: +#ifdef CONFIG_ISDN_DRV_EICON_PCI + if (!ep) break; + ep->callback = eicon_idi_callback; + ep->R = (BUFFERS *)ccard; + ep->user[0] = (word)chan->No; + ep->user[1] = (word)tmpid; + ep->XNum = 1; + ep->RNum = 0; + ep->RNR = 0; + ep->Rc = 0; + ep->Ind = 0; + ep->X->PLength = reqbuf->XBuffer.length; + memcpy(ep->X->P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); + ep->ReqCh = reqbuf->ReqCh; + ep->Req = reqbuf->Req; +#endif + break; + } chan->e.busy = 1; + spin_unlock_irqrestore(&eicon_lock, flags); eicon_log(ccard, dlev, "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n", - reqbuf->Req, - (scom) ? ram_inb(ccard, &com->ReqId) : - ram_inb(ccard, &ReqOut->ReqId), + reqbuf->Req, tmpid, reqbuf->ReqCh, reqbuf->XBuffer.length, chan->e.ref); +#ifdef CONFIG_ISDN_DRV_EICON_PCI + if (scom == 2) { + if (ep) { + ccard->d->request(ep); + if (ep->Rc) + eicon_idi_callback(ep); + } + } +#endif } - restore_flags(flags); dev_kfree_skb(skb); } dev_kfree_skb(skb2); } else { - skb_queue_tail(&ccard->sackq, skb2); - eicon_log(ccard, 128, "eicon: transmit: busy chan %d\n", chan->No); + skb_queue_tail(&ccard->sackq, skb2); + eicon_log(ccard, 128, "eicon: transmit: busy chan %d\n", chan->No); } - if (scom) - quloop = 0; - else - if (!(skb2 = skb_dequeue(&ccard->sndq))) + switch(scom) { + case 1: quloop = 0; + break; + case 0: + case 2: + if (!(skb2 = skb_dequeue(&ccard->sndq))) + quloop = 0; + break; + } } if (!scom) @@ -603,18 +509,14 @@ eicon_io_transmit(eicon_card *ccard) { } } - +#ifdef CONFIG_ISDN_DRV_EICON_ISA /* * IRQ handler */ void eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { eicon_card *ccard = (eicon_card *)dev_id; - eicon_pci_card *pci_card; eicon_isa_card *isa_card; - char *ram = 0; - char *reg = 0; - char *cfg = 0; eicon_pr_ram *prram = 0; eicon_isa_com *com = 0; eicon_RC *RcIn; @@ -646,11 +548,9 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { } } - pci_card = &ccard->hwif.pci; 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: @@ -664,23 +564,6 @@ 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; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - irqprobe = &pci_card->irqprobe; - prram = (eicon_pr_ram *)ram; - break; - case EICON_CTYPE_MAESTRA: - scom = 0; - ram = (char *)pci_card->PCIram; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - irqprobe = &pci_card->irqprobe; - prram = 0; - break; default: eicon_log(ccard, 1, "eicon_irq: unsupported card-type!\n"); return; @@ -688,7 +571,6 @@ 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: @@ -706,26 +588,11 @@ 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); - writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]); - writew(0, &cfg[MP_IRQ_RESET + 2]); - writeb(0, &ram[0x3fe]); - } - *irqprobe = 0; - break; - case EICON_CTYPE_MAESTRA: - outb(0x08, pci_card->PCIreg + M_RESET); - *irqprobe = 0; - break; } return; } switch(ccard->type) { -#ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_S: case EICON_CTYPE_SX: case EICON_CTYPE_SCOM: @@ -736,20 +603,6 @@ 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 */ - eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n"); - return; - } - break; - case EICON_CTYPE_MAESTRA: - outw(0x3fe, pci_card->PCIreg + M_ADDR); - if (!(inb(pci_card->PCIreg + M_DATA))) { /* card did not interrupt */ - eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n"); - return; - } - break; } if (scom) { @@ -891,7 +744,6 @@ 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]); @@ -902,19 +754,8 @@ 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]); - writeb(0, &ram[0x3fe]); - break; - case EICON_CTYPE_MAESTRA: - outb(0x08, pci_card->PCIreg + M_RESET); - outw(0x3fe, pci_card->PCIreg + M_ADDR); - outb(0, pci_card->PCIreg + M_DATA); - break; } return; } - +#endif diff --git a/drivers/isdn/eicon/eicon_isa.c b/drivers/isdn/eicon/eicon_isa.c index 265e07e08..1d2ece7cd 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.14 2000/02/22 16:26:40 armin Exp $ +/* $Id: eicon_isa.c,v 1.16 2000/06/12 12:44:02 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for old ISA cards. @@ -21,62 +21,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_isa.c,v $ - * Revision 1.14 2000/02/22 16:26:40 armin - * Fixed membase error message. - * Fixed missing log buffer struct. - * - * Revision 1.13 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.12 1999/11/27 12:56:19 armin - * Forgot some iomem changes for last ioremap compat. - * - * Revision 1.11 1999/11/25 11:33:09 armin - * Microchannel fix from Erik Weber (exrz73@ibm.net). - * - * Revision 1.10 1999/11/18 21:14:30 armin - * New ISA memory mapped IO - * - * Revision 1.9 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber (exrz73@ibm.net). - * - * Revision 1.8 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * 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. - * - * Revision 1.4 1999/03/29 11:19:46 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.3 1999/03/02 12:37:45 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.2 1999/01/24 20:14:19 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.1 1999/01/01 18:09:43 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #include <linux/config.h> @@ -87,7 +31,7 @@ #define release_shmem release_region #define request_shmem request_region -char *eicon_isa_revision = "$Revision: 1.14 $"; +char *eicon_isa_revision = "$Revision: 1.16 $"; #undef EICON_MCA_DEBUG @@ -357,7 +301,7 @@ eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) { printk(KERN_INFO "%s: startup-code loaded\n", eicon_ctype_name[card->type]); if ((card->type == EICON_CTYPE_QUADRO) && (card->master)) { tmp = eicon_addcard(card->type, card->physmem, card->irq, - ((eicon_card *)card->card)->regname); + ((eicon_card *)card->card)->regname, 0); printk(KERN_INFO "Eicon: %d adapters added\n", tmp); } return 0; diff --git a/drivers/isdn/eicon/eicon_isa.h b/drivers/isdn/eicon/eicon_isa.h index b53adfcbf..1c8034f77 100644 --- a/drivers/isdn/eicon/eicon_isa.h +++ b/drivers/isdn/eicon/eicon_isa.h @@ -1,4 +1,4 @@ -/* $Id: eicon_isa.h,v 1.8 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_isa.h,v 1.10 2000/05/07 08:51:04 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * @@ -20,38 +20,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_isa.h,v $ - * Revision 1.8 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.7 1999/11/18 21:14:30 armin - * New ISA memory mapped IO - * - * Revision 1.6 1999/11/15 19:37:04 keil - * need config.h - * - * Revision 1.5 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber. - * - * Revision 1.4 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.3 1999/03/29 11:19:47 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.2 1999/03/02 12:37:46 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.1 1999/01/01 18:09:44 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #ifndef eicon_isa_h @@ -138,7 +106,6 @@ typedef struct { unsigned char mvalid; /* Flag: Memory is valid */ unsigned char ivalid; /* Flag: IRQ is valid */ unsigned char master; /* Flag: Card ist Quadro 1/4 */ - void* generic; /* Ptr to generic card struct */ } eicon_isa_card; /* Offsets for special locations on standard cards */ diff --git a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c index 9bc91d6f4..f3af22b27 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.25 2000/02/22 16:26:40 armin Exp $ +/* $Id: eicon_mod.c,v 1.35 2000/08/12 18:00:47 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * @@ -9,8 +9,6 @@ * Thanks to Eicon Technology GmbH & Co. oHG for * documents, informations and hardware. * - * Deutsche Telekom AG for S2M support. - * * Deutsche Mailbox Saar-Lor-Lux GmbH * for sponsoring and testing fax * capabilities with Diva Server cards. @@ -30,105 +28,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_mod.c,v $ - * Revision 1.25 2000/02/22 16:26:40 armin - * Fixed membase error message. - * Fixed missing log buffer struct. - * - * Revision 1.24 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.23 2000/01/20 19:55:34 keil - * Add FAX Class 1 support - * - * Revision 1.22 1999/11/27 12:56:19 armin - * Forgot some iomem changes for last ioremap compat. - * - * Revision 1.21 1999/11/25 11:35:10 armin - * Microchannel fix from Erik Weber (exrz73@ibm.net). - * Minor cleanup. - * - * Revision 1.20 1999/11/18 21:14:30 armin - * New ISA memory mapped IO - * - * Revision 1.19 1999/11/12 13:21:44 armin - * Bugfix of undefined reference with CONFIG_MCA - * - * Revision 1.18 1999/10/11 18:13:25 armin - * Added fax capabilities for Eicon Diva Server cards. - * - * Revision 1.17 1999/10/08 22:09:34 armin - * Some fixes of cards interface handling. - * Bugfix of NULL pointer occurence. - * Changed a few log outputs. - * - * Revision 1.16 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.15 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber (exrz73@ibm.net). - * - * Revision 1.14 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.13 1999/09/04 17:37:59 armin - * Removed not used define, did not work and caused error - * in 2.3.16 - * - * Revision 1.12 1999/08/31 11:20:14 paul - * various spelling corrections (new checksums may be needed, Karsten!) - * - * 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. - * - * Revision 1.4 1999/03/29 11:19:47 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.3 1999/03/02 12:37:47 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.2 1999/01/24 20:14:21 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.1 1999/01/01 18:09:44 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ -#define DRIVERPATCH "" +#define DRIVERNAME "Eicon active ISDN driver" +#define DRIVERRELEASE "2.0" +#define DRIVERPATCH ".14" + #include <linux/config.h> #include <linux/module.h> @@ -139,17 +44,30 @@ #include "eicon.h" +#include "../avmb1/capicmd.h" /* this should be moved in a common place */ + +#undef N_DATA +#include "adapter.h" +#include "uxio.h" + #define INCLUDE_INLINE_FUNCS static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains start of card-list */ -static char *eicon_revision = "$Revision: 1.25 $"; +static char *eicon_revision = "$Revision: 1.35 $"; extern char *eicon_pci_revision; extern char *eicon_isa_revision; extern char *eicon_idi_revision; +extern int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, + unsigned int command, unsigned long arg); +extern void eicon_pci_init_conf(eicon_card *card); +void mod_inc_use_count(void); +void mod_dec_use_count(void); +extern char *file_check(void); + #ifdef MODULE #define MOD_USE_COUNT (GET_USE_COUNT (&__this_module)) #endif @@ -158,6 +76,11 @@ extern char *eicon_idi_revision; ulong DebugVar; +spinlock_t eicon_lock; + +DESCRIPTOR idi_d[16]; +int idi_dlength; + /* Parameters to be set by insmod */ #ifdef CONFIG_ISDN_DRV_EICON_ISA static int membase = -1; @@ -189,23 +112,6 @@ char *eicon_ctype_name[] = { "DIVA Server PRI/PCI" }; -static int -getrel(char *p) -{ - int v = 0; - char *tmp = 0; - - if ((tmp = strchr(p, '.'))) - p = tmp + 1; - while (p[0] >= '0' && p[0] <= '9') { - v = ((v < 0) ? 0 : (v * 10)) + (int) (p[0] - '0'); - p++; - } - return v; - - -} - static char * eicon_getrev(const char *revision) { @@ -229,68 +135,26 @@ find_channel(eicon_card *card, int channel) return NULL; } +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI /* - * Free MSN list + * Find pcicard with given card number */ -static void -eicon_clear_msn(eicon_card *card) +static inline eicon_card * +eicon_findnpcicard(int driverid) { - struct msn_entry *p = card->msn_list; - struct msn_entry *q; - unsigned long flags; + eicon_card *p = cards; - save_flags(flags); - cli(); - card->msn_list = NULL; - restore_flags(flags); while (p) { - q = p->next; - kfree(p); - p = q; + if ((p->regname[strlen(p->regname)-1] == (driverid + '0')) && + (p->bus == EICON_BUS_PCI)) + return p; + p = p->next; } + return (eicon_card *) 0; } - -/* - * Find an MSN entry in the list. - * If ia5 != 0, return IA5-encoded EAZ, else - * return a bitmask with corresponding bit set. - */ -static __u16 -eicon_find_msn(eicon_card *card, char *msn, int ia5) -{ - struct msn_entry *p = card->msn_list; - __u8 eaz = '0'; - - while (p) { - if (!strcmp(p->msn, msn)) { - eaz = p->eaz; - break; - } - p = p->next; - } - if (!ia5) - return (1 << (eaz - '0')); - else - return eaz; -} - -/* - * Find an EAZ entry in the list. - * return a string with corresponding msn. - */ -char * -eicon_find_eaz(eicon_card *card, char eaz) -{ - struct msn_entry *p = card->msn_list; - - while (p) { - if (p->eaz == eaz) - return(p->msn); - p = p->next; - } - return("\0"); -} - +#endif +#endif /* CONFIG_PCI */ static void eicon_rcv_dispatch(struct eicon_card *card) @@ -337,39 +201,18 @@ 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))) { - eicon_log(card, 1, "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) { ulong a; eicon_chan *chan; eicon_cdef cdef; +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + dia_start_t dstart; +#endif +#endif isdn_ctrl cmd; - char tmp[17]; int ret = 0; unsigned long flags; @@ -383,16 +226,15 @@ eicon_command(eicon_card * card, isdn_ctrl * c) case EICON_IOCTL_GETVER: return(EICON_CTRL_VERSION); case EICON_IOCTL_GETTYPE: + if (card->bus == EICON_BUS_PCI) { + copy_to_user((char *)a, &card->hwif.pci.master, sizeof(int)); + } return(card->type); 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: - return card->hwif.pci.PCIram; -#endif default: eicon_log(card, 1, "eicon: Illegal BUS type %d\n", @@ -433,10 +275,6 @@ eicon_command(eicon_card * card, isdn_ctrl * c) case EICON_BUS_ISA: case EICON_BUS_MCA: return card->hwif.isa.irq; -#if CONFIG_PCI - case EICON_BUS_PCI: - return card->hwif.pci.irq; -#endif default: eicon_log(card, 1, "eicon: Illegal BUS type %d\n", @@ -514,7 +352,9 @@ eicon_command(eicon_card * card, isdn_ctrl * c) case EICON_IOCTL_MANIF: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; - if (!card->Feature & PROTCAP_MANIF) + if (!card->d) + return -ENODEV; + if (!card->d->features & DI_MANAGE) return -ENODEV; ret = eicon_idi_manage( card, @@ -522,49 +362,12 @@ eicon_command(eicon_card * card, isdn_ctrl * c) 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) - return -EBUSY; - if (card->bus == EICON_BUS_PCI) { - switch(card->type) { - case EICON_CTYPE_MAESTRA: - ret = eicon_pci_load_bri( - &(card->hwif.pci), - &(((eicon_codebuf *)a)->pci)); - break; - - case EICON_CTYPE_MAESTRAP: - ret = eicon_pci_load_pri( - &(card->hwif.pci), - &(((eicon_codebuf *)a)->pci)); - break; - } - if (!ret) { - card->flags |= EICON_FLAGS_LOADED; - card->flags |= EICON_FLAGS_RUNNING; - if (card->hwif.pci.channels > 1) { - cmd.command = ISDN_STAT_ADDCH; - cmd.driver = card->myid; - cmd.arg = card->hwif.pci.channels - 1; - card->interface.statcallb(&cmd); - } - cmd.command = ISDN_STAT_RUN; - cmd.driver = card->myid; - cmd.arg = 0; - card->interface.statcallb(&cmd); - } - return ret; - } else return -ENODEV; -#endif + return -ENODEV; + case EICON_IOCTL_ADDCARD: if ((ret = copy_from_user(&cdef, (char *)a, sizeof(cdef)))) return -EFAULT; - if (!(eicon_addcard(0, cdef.membase, cdef.irq, cdef.id))) + if (!(eicon_addcard(0, cdef.membase, cdef.irq, cdef.id, 0))) return -EIO; return 0; case EICON_IOCTL_DEBUGVAR: @@ -574,11 +377,77 @@ eicon_command(eicon_card * card, isdn_ctrl * c) #ifdef MODULE case EICON_IOCTL_FREEIT: while (MOD_USE_COUNT > 0) MOD_DEC_USE_COUNT; - MOD_INC_USE_COUNT; + mod_inc_use_count(); return 0; #endif - default: + case EICON_IOCTL_LOADPCI: + eicon_log(card, 1, "Eicon: Wrong version of load-utility,\n"); + eicon_log(card, 1, "Eicon: re-compile eiconctrl !\n"); + eicon_log(card, 1, "Eicon: Maybe update of utility is necessary !\n"); return -EINVAL; + default: +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + if (c->arg < EICON_IOCTL_DIA_OFFSET) + return -EINVAL; + if (copy_from_user(&dstart, (char *)a, sizeof(dstart))) + return -1; + if (!(card = eicon_findnpcicard(dstart.card_id))) + return -EINVAL; + ret = do_ioctl(NULL, NULL, + c->arg - EICON_IOCTL_DIA_OFFSET, + (unsigned long) a); + if (((c->arg - EICON_IOCTL_DIA_OFFSET)==DIA_IOCTL_START) && (!ret)) { + if (card->type != EICON_CTYPE_MAESTRAQ) { + EtdM_DIDD_Read(idi_d, &idi_dlength); + card->d = &idi_d[idi_dlength - 1]; + card->flags |= EICON_FLAGS_LOADED; + card->flags |= EICON_FLAGS_RUNNING; + eicon_pci_init_conf(card); + if (card->d->channels > 1) { + cmd.command = ISDN_STAT_ADDCH; + cmd.driver = card->myid; + cmd.arg = card->d->channels - 1; + card->interface.statcallb(&cmd); + } + cmd.command = ISDN_STAT_RUN; + cmd.driver = card->myid; + cmd.arg = 0; + card->interface.statcallb(&cmd); + eicon_log(card, 1, "Eicon: %s started, %d channels (feat. 0x%x, SerNo. %d)\n", + (card->type == EICON_CTYPE_MAESTRA) ? "BRI" : "PRI", + card->d->channels, card->d->features, card->d->serial); + } else { + int i; + EtdM_DIDD_Read(idi_d, &idi_dlength); + for(i = 3; i >= 0; i--) { + if (!(card = eicon_findnpcicard(dstart.card_id - i))) + return -EINVAL; + + card->flags |= EICON_FLAGS_LOADED; + card->flags |= EICON_FLAGS_RUNNING; + card->d = &idi_d[idi_dlength - (i+1)]; + eicon_pci_init_conf(card); + if (card->d->channels > 1) { + cmd.command = ISDN_STAT_ADDCH; + cmd.driver = card->myid; + cmd.arg = card->d->channels - 1; + card->interface.statcallb(&cmd); + } + cmd.command = ISDN_STAT_RUN; + cmd.driver = card->myid; + cmd.arg = 0; + card->interface.statcallb(&cmd); + eicon_log(card, 1, "Eicon: %d/4BRI started, %d channels (feat. 0x%x, SerNo. %d)\n", + 4-i, card->d->channels, card->d->features, card->d->serial); + } + } + } + return ret; +#else + return -EINVAL; +#endif +#endif /* CONFIG_PCI */ } break; case ISDN_CMD_DIAL: @@ -586,20 +455,15 @@ eicon_command(eicon_card * card, isdn_ctrl * c) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if ((chan->fsm_state != EICON_STATE_NULL) && (chan->fsm_state != EICON_STATE_LISTEN)) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); eicon_log(card, 1, "Dial on channel %d with state %d\n", chan->No, chan->fsm_state); return -EBUSY; } - if (card->ptype == ISDN_PTYPE_EURO) - tmp[0] = eicon_find_msn(card, c->parm.setup.eazmsn, 1); - else - tmp[0] = c->parm.setup.eazmsn[0]; chan->fsm_state = EICON_STATE_OCALL; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); ret = idi_connect_req(card, chan, c->parm.setup.phone, c->parm.setup.eazmsn, @@ -637,19 +501,7 @@ eicon_command(eicon_card * card, isdn_ctrl * c) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; - if (strlen(c->parm.num)) { - if (card->ptype == ISDN_PTYPE_EURO) { - chan->eazmask = eicon_find_msn(card, c->parm.num, 0); - } - if (card->ptype == ISDN_PTYPE_1TR6) { - int i; - chan->eazmask = 0; - for (i = 0; i < strlen(c->parm.num); i++) - if (isdigit(c->parm.num[i])) - chan->eazmask |= (1 << (c->parm.num[i] - '0')); - } - } else - chan->eazmask = 0x3ff; + chan->eazmask = 0x3ff; eicon_idi_listen_req(card, chan); return 0; case ISDN_CMD_CLREAZ: @@ -680,8 +532,10 @@ eicon_command(eicon_card * card, isdn_ctrl * c) break; chan->l3prot = (c->arg >> 8); #ifdef CONFIG_ISDN_TTY_FAX - if (chan->l3prot == ISDN_PROTO_L3_FCLASS2) + if (chan->l3prot == ISDN_PROTO_L3_FCLASS2) { chan->fax = c->parm.fax; + eicon_log(card, 128, "idi_cmd: Ch%d: SETL3 struct fax=0x%x\n",chan->No, chan->fax); + } #endif return 0; case ISDN_CMD_GETL3: @@ -706,10 +560,14 @@ eicon_command(eicon_card * card, isdn_ctrl * c) eicon_log(card, 1, "eicon CMD_GETSIL not implemented\n"); return 0; case ISDN_CMD_LOCK: - MOD_INC_USE_COUNT; +#ifdef MODULE + mod_inc_use_count(); +#endif return 0; case ISDN_CMD_UNLOCK: - MOD_DEC_USE_COUNT; +#ifdef MODULE + mod_dec_use_count(); +#endif return 0; #ifdef CONFIG_ISDN_TTY_FAX case ISDN_CMD_FAXCMD: @@ -729,6 +587,23 @@ eicon_command(eicon_card * card, isdn_ctrl * c) break; idi_audio_cmd(card, chan, c->arg >> 8, c->parm.num); return 0; + case CAPI_PUT_MESSAGE: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (!(chan = find_channel(card, c->arg & 0x1f))) + break; + if (c->parm.cmsg.Length < 8) + break; + switch(c->parm.cmsg.Command) { + case CAPI_FACILITY: + if (c->parm.cmsg.Subcommand == CAPI_REQ) + return(capipmsg(card, chan, &c->parm.cmsg)); + break; + case CAPI_MANUFACTURER: + default: + break; + } + return 0; } return -EINVAL; @@ -787,8 +662,7 @@ if_readstatus(u_char * buf, int len, int user, int id, int channel) if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); while((skb = skb_dequeue(&card->statq))) { if ((skb->len + count) > len) @@ -811,12 +685,12 @@ if_readstatus(u_char * buf, int len, int user, int id, int channel) } else { skb_pull(skb, cnt); skb_queue_head(&card->statq, skb); - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); return count; } } card->statq_entries = 0; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); return count; } printk(KERN_ERR @@ -848,7 +722,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb) } else #endif - ret = idi_send_data(card, chan, ack, skb, 1); + ret = idi_send_data(card, chan, ack, skb, 1, 1); return (ret); } else { return -ENODEV; @@ -895,12 +769,11 @@ eicon_putstatus(eicon_card * card, char * buf) return; } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); count = strlen(buf); skb = alloc_skb(count, GFP_ATOMIC); if (!skb) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); printk(KERN_ERR "eicon: could not alloc skb in putstatus\n"); return; } @@ -918,7 +791,7 @@ eicon_putstatus(eicon_card * card, char * buf) } else card->statq_entries++; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); if (count) { cmd.command = ISDN_STAT_STAVAIL; cmd.driver = card->myid; @@ -967,7 +840,7 @@ eicon_log(eicon_card * card, int level, const char *fmt, ...) * link it into cards-list. */ static void -eicon_alloccard(int Type, int membase, int irq, char *id) +eicon_alloccard(int Type, int membase, int irq, char *id, int card_id) { int i; int j; @@ -976,9 +849,6 @@ eicon_alloccard(int Type, int membase, int irq, char *id) char qid[5]; #endif eicon_card *card; -#if CONFIG_PCI - eicon_pci_card *pcic; -#endif qloop = (Type == EICON_CTYPE_QUADRO)?2:0; for (i = 0; i <= qloop; i++) { @@ -1088,9 +958,9 @@ eicon_alloccard(int Type, int membase, int irq, char *id) card->interface.channels = 1; break; #endif -#if CONFIG_PCI +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI case EICON_CTYPE_MAESTRA: - (eicon_pci_card *)pcic = (eicon_pci_card *)membase; card->bus = EICON_BUS_PCI; card->interface.features |= ISDN_FEATURE_L2_V11096 | @@ -1101,11 +971,26 @@ eicon_alloccard(int Type, int membase, int irq, char *id) ISDN_FEATURE_L3_TRANSDSP | ISDN_FEATURE_L3_FCLASS2; card->hwif.pci.card = (void *)card; - card->hwif.pci.PCIreg = pcic->PCIreg; - card->hwif.pci.PCIcfg = pcic->PCIcfg; - card->hwif.pci.master = 1; - card->hwif.pci.mvalid = pcic->mvalid; - card->hwif.pci.ivalid = 0; + card->hwif.pci.master = card_id; + card->hwif.pci.irq = irq; + card->hwif.pci.type = Type; + card->flags = 0; + card->nchannels = 2; + card->interface.channels = 1; + break; + + case EICON_CTYPE_MAESTRAQ: + card->bus = EICON_BUS_PCI; + card->interface.features |= + ISDN_FEATURE_L2_V11096 | + ISDN_FEATURE_L2_V11019 | + ISDN_FEATURE_L2_V11038 | + ISDN_FEATURE_L2_MODEM | + ISDN_FEATURE_L2_FAX | + ISDN_FEATURE_L3_TRANSDSP | + ISDN_FEATURE_L3_FCLASS2; + card->hwif.pci.card = (void *)card; + card->hwif.pci.master = card_id; card->hwif.pci.irq = irq; card->hwif.pci.type = Type; card->flags = 0; @@ -1114,7 +999,6 @@ eicon_alloccard(int Type, int membase, int irq, char *id) break; case EICON_CTYPE_MAESTRAP: - (eicon_pci_card *)pcic = (eicon_pci_card *)membase; card->bus = EICON_BUS_PCI; card->interface.features |= ISDN_FEATURE_L2_V11096 | @@ -1125,13 +1009,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id) ISDN_FEATURE_L3_TRANSDSP | ISDN_FEATURE_L3_FCLASS2; card->hwif.pci.card = (void *)card; - card->hwif.pci.shmem = (eicon_pci_shmem *)pcic->shmem; - card->hwif.pci.PCIreg = pcic->PCIreg; - card->hwif.pci.PCIram = pcic->PCIram; - card->hwif.pci.PCIcfg = pcic->PCIcfg; - card->hwif.pci.master = 1; - card->hwif.pci.mvalid = pcic->mvalid; - card->hwif.pci.ivalid = 0; + card->hwif.pci.master = card_id; card->hwif.pci.irq = irq; card->hwif.pci.type = Type; card->flags = 0; @@ -1139,6 +1017,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id) card->interface.channels = 1; break; #endif +#endif #ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_ISABRI: if (membase == -1) @@ -1197,6 +1076,53 @@ eicon_alloccard(int Type, int membase, int irq, char *id) skb_queue_head_init(&card->bch[j].e.X); skb_queue_head_init(&card->bch[j].e.R); } + +#ifdef CONFIG_ISDN_DRV_EICON_PCI + /* *** Diva Server *** */ + if (!(card->dbuf = (DBUFFER *) kmalloc((sizeof(DBUFFER) * (card->nchannels + 1))*2 + , GFP_KERNEL))) { + eicon_log(card, 1, + "eicon: (%s) Could not allocate DBUFFER-struct.\n", id); + kfree(card); + kfree(card->bch); + return; + } + if (!(card->sbuf = (BUFFERS *) kmalloc((sizeof(BUFFERS) * (card->nchannels + 1)) * 2, GFP_KERNEL))) { + eicon_log(card, 1, + "eicon: (%s) Could not allocate BUFFERS-struct.\n", id); + kfree(card); + kfree(card->bch); + kfree(card->dbuf); + return; + } + if (!(card->sbufp = (char *) kmalloc((270 * (card->nchannels + 1)) * 2, GFP_KERNEL))) { + eicon_log(card, 1, + "eicon: (%s) Could not allocate BUFFERSP-struct.\n", id); + kfree(card); + kfree(card->bch); + kfree(card->dbuf); + kfree(card->sbuf); + return; + } + for (j=0; j< (card->nchannels + 1); j++) { + memset((char *)&card->dbuf[j], 0, sizeof(DBUFFER)); + card->bch[j].de.RBuffer = (DBUFFER *)&card->dbuf[j]; + memset((char *)&card->dbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS)); + card->bch[j].be.RBuffer = (DBUFFER *)&card->dbuf[j+(card->nchannels+1)]; + + memset((char *)&card->sbuf[j], 0, sizeof(BUFFERS)); + card->bch[j].de.X = (BUFFERS *)&card->sbuf[j]; + memset((char *)&card->sbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS)); + card->bch[j].be.X = (BUFFERS *)&card->sbuf[j+(card->nchannels+1)]; + + memset((char *)&card->sbufp[j], 0, 270); + card->bch[j].de.X->P = (char *)&card->sbufp[j * 270]; + memset((char *)&card->sbufp[j+(card->nchannels+1)], 0, 270); + card->bch[j].be.X->P = (char *)&card->sbufp[(j+(card->nchannels+1)) * 270]; + } + /* *** */ +#endif /* CONFIG_ISDN_DRV_EICON_PCI */ + card->next = cards; cards = card; } @@ -1220,10 +1146,7 @@ eicon_registercard(eicon_card * card) #endif /* CONFIG_MCA */ #endif case EICON_BUS_PCI: -#if CONFIG_PCI - eicon_pci_printpar(&card->hwif.pci); break; -#endif default: eicon_log(card, 1, "eicon_registercard: Illegal BUS type %d\n", @@ -1260,10 +1183,7 @@ unregister_card(eicon_card * card) break; #endif case EICON_BUS_PCI: -#if CONFIG_PCI - eicon_pci_release(&card->hwif.pci); break; -#endif default: eicon_log(card, 1, "eicon: Invalid BUS type %d\n", @@ -1295,13 +1215,17 @@ eicon_freecard(eicon_card *card) { while((skb = skb_dequeue(&card->statq))) dev_kfree_skb(skb); - eicon_clear_msn(card); +#ifdef CONFIG_ISDN_DRV_EICON_PCI + kfree(card->sbufp); + kfree(card->sbuf); + kfree(card->dbuf); +#endif kfree(card->bch); kfree(card); } int -eicon_addcard(int Type, int membase, int irq, char *id) +eicon_addcard(int Type, int membase, int irq, char *id, int card_id) { eicon_card *p; eicon_card *q = NULL; @@ -1314,7 +1238,7 @@ eicon_addcard(int Type, int membase, int irq, char *id) if ((Type = eicon_isa_find_card(membase, irq, id)) < 0) return 0; #endif - eicon_alloccard(Type, membase, irq, id); + eicon_alloccard(Type, membase, irq, id, card_id); p = cards; while (p) { registered = 0; @@ -1333,12 +1257,14 @@ eicon_addcard(int Type, int membase, int irq, char *id) break; #endif case EICON_BUS_PCI: -#if CONFIG_PCI +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI if (eicon_registercard(p)) break; registered = 1; break; #endif +#endif default: printk(KERN_ERR "eicon: addcard: Invalid BUS type %d\n", @@ -1371,8 +1297,6 @@ eicon_addcard(int Type, int membase, int irq, char *id) return (added - failed); } -#define DRIVERNAME "Eicon active ISDN driver" -#define DRIVERRELEASE "1" #ifdef MODULE #define eicon_init init_module @@ -1382,35 +1306,30 @@ int eicon_init(void) { int card_count = 0; - int release = 0; char tmprev[50]; DebugVar = 1; + eicon_lock = (spinlock_t) SPIN_LOCK_UNLOCKED; printk(KERN_INFO "%s Rev: ", DRIVERNAME); strcpy(tmprev, eicon_revision); printk("%s/", eicon_getrev(tmprev)); - release += getrel(tmprev); strcpy(tmprev, eicon_pci_revision); -#if CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_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%s\n", DRIVERNAME, - DRIVERRELEASE, tmprev, DRIVERPATCH); + printk(KERN_INFO "%s Release: %s%s (%s)\n", DRIVERNAME, + DRIVERRELEASE, DRIVERPATCH, file_check()); #ifdef CONFIG_ISDN_DRV_EICON_ISA #ifdef CONFIG_MCA @@ -1427,18 +1346,23 @@ eicon_init(void) card_count++; }; #else - card_count = eicon_addcard(0, membase, irq, id); + card_count = eicon_addcard(0, membase, irq, id, 0); #endif /* CONFIG_MCA */ #endif /* CONFIG_ISDN_DRV_EICON_ISA */ -#if CONFIG_PCI +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + DivasCardsDiscover(); card_count += eicon_pci_find_card(id); #endif +#endif + if (!cards) { #ifdef MODULE -#ifndef CONFIG_PCI +#ifndef CONFIG_ISDN_DRV_EICON_PCI #ifndef CONFIG_ISDN_DRV_EICON_ISA printk(KERN_INFO "Eicon: Driver is neither ISA nor PCI compiled !\n"); + printk(KERN_INFO "Eicon: Driver not loaded !\n"); #else printk(KERN_INFO "Eicon: No cards defined, driver not loaded !\n"); #endif @@ -1451,17 +1375,47 @@ eicon_init(void) } else 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; } + #ifdef MODULE + +void mod_inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + +void mod_dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + +#ifdef CONFIG_ISDN_DRV_EICON_PCI +void EtdM_DIDD_Write(DESCRIPTOR *, int); +EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Read); +EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Write); +EXPORT_SYMBOL_NOVERS(DivasPrintf); +#else +int DivasCardNext; +card_t DivasCards[1]; +#endif + void cleanup_module(void) { +#if CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + card_t *pCard; + word wCardIndex; + extern int Divas_major; + int iTmp = 0; +#endif +#endif + eicon_card *card = cards; eicon_card *last; + while (card) { #ifdef CONFIG_ISDN_DRV_EICON_ISA #ifdef CONFIG_MCA @@ -1481,6 +1435,54 @@ cleanup_module(void) card = card->next; eicon_freecard(last); } + +#if CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + pCard = DivasCards; + for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++) + { + if ((pCard->hw) && (pCard->hw->in_use)) + { + (*pCard->card_reset)(pCard); + + UxIsrRemove(pCard->hw, pCard); + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + if(pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + release_region(pCard->hw->io_base,0x20); + release_region(pCard->hw->reset_base,0x80); + } + + // If this is a 4BRI ... + if (pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + // Skip over the next 3 virtual adapters + wCardIndex += 3; + + // But free their handles + for (iTmp = 0; iTmp < 3; iTmp++) + { + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + } + } + } + pCard++; + } + unregister_chrdev(Divas_major, "Divas"); +#endif +#endif /* CONFIG_PCI */ printk(KERN_INFO "%s unloaded\n", DRIVERNAME); } @@ -1675,7 +1677,7 @@ int eicon_mca_probe(int slot, /* slot-nr where the card was detected */ return ENODEV; }; /* matching membase & irq */ - if ( 1 == eicon_addcard(type, membase, irq, id)) { + if ( 1 == eicon_addcard(type, membase, irq, id, 0)) { mca_set_adapter_name(slot, eicon_mca_adapters[a_idx].name); mca_set_adapter_procfn(slot, (MCA_ProcFn) eicon_info, cards); diff --git a/drivers/isdn/eicon/eicon_pci.c b/drivers/isdn/eicon/eicon_pci.c index e696b5584..6cb3bca6d 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.11 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_pci.c,v 1.15 2000/06/12 12:44:02 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for PCI cards. @@ -9,8 +9,6 @@ * Thanks to Eicon Technology GmbH & Co. oHG for * documents, informations and hardware. * - * Deutsche Telekom AG for S2M support. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) @@ -25,53 +23,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_pci.c,v $ - * Revision 1.11 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * 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. - * - * Revision 1.5 1999/03/29 11:19:49 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.4 1999/03/02 12:37:48 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.3 1999/01/24 20:14:24 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.2 1999/01/10 18:46:06 armin - * Bug with wrong values in HLC fixed. - * Bytes to send are counted and limited now. - * - * Revision 1.1 1999/01/01 18:09:45 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #include <linux/config.h> @@ -80,896 +31,90 @@ #include "eicon.h" #include "eicon_pci.h" +#undef N_DATA +#include "adapter.h" +#include "uxio.h" -char *eicon_pci_revision = "$Revision: 1.11 $"; +char *eicon_pci_revision = "$Revision: 1.15 $"; #if CONFIG_PCI /* intire stuff is only for PCI */ - -#undef EICON_PCI_DEBUG +#ifdef CONFIG_ISDN_DRV_EICON_PCI int eicon_pci_find_card(char *ID) { - if (pci_present()) { - struct pci_dev *pdev = NULL; - int pci_nextindex=0, pci_cards=0, pci_akt=0; - int pci_type = PCI_MAESTRA; - int NoMorePCICards = FALSE; - char *ram, *reg, *cfg; - unsigned int pram=0, preg=0, pcfg=0; - char did[12]; - eicon_pci_card *aparms; - - if (!(aparms = (eicon_pci_card *) kmalloc(sizeof(eicon_pci_card), GFP_KERNEL))) { - printk(KERN_WARNING - "eicon_pci: Could not allocate card-struct.\n"); - return 0; - } - - for (pci_cards = 0; pci_cards < 0x0f; pci_cards++) - { - do { - if ((pdev = pci_find_device(PCI_VENDOR_EICON, - pci_type, - pdev))) + int pci_cards = 0; + int card_id = 0; + int had_q = 0; + int ctype = 0; + char did[20]; + card_t *pCard; + word wCardIndex; + + pCard = DivasCards; + for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++) { - pci_nextindex++; - break; - } - else { - pci_nextindex = 0; - switch (pci_type) /* switch to next card type */ - { - case PCI_MAESTRA: - pci_type = PCI_MAESTRAQ; break; - case PCI_MAESTRAQ: - pci_type = PCI_MAESTRAQ_U; break; - case PCI_MAESTRAQ_U: - pci_type = PCI_MAESTRAP; break; - default: - case PCI_MAESTRAP: - NoMorePCICards = TRUE; - } - } - } - while (!NoMorePCICards); - if (NoMorePCICards) - { - if (pci_cards < 1) { - printk(KERN_INFO "Eicon: No supported PCI cards found.\n"); - kfree(aparms); - return 0; - } - else - { - printk(KERN_INFO "Eicon: %d PCI card%s registered.\n", - pci_cards, (pci_cards > 1) ? "s":""); - kfree(aparms); - return (pci_cards); - } - } - - pci_enable_device(pdev); /* XXX handle error return */ - - pci_akt = 0; - switch(pci_type) - { - case PCI_MAESTRA: - printk(KERN_INFO "Eicon: DIVA Server BRI/PCI detected !\n"); - aparms->type = EICON_CTYPE_MAESTRA; - - aparms->irq = pdev->irq; - preg = pci_resource_start(pdev, 2); - pcfg = pci_resource_start(pdev, 1); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq); - printk(KERN_DEBUG "eicon_pci: reg=0x%x\n", preg); - printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n", pcfg); -#endif - pci_akt = 1; - break; - - case PCI_MAESTRAQ: - case PCI_MAESTRAQ_U: - printk(KERN_ERR "Eicon: DIVA Server 4BRI/PCI detected but not supported !\n"); - pci_cards--; - pci_akt = 0; - break; - - case PCI_MAESTRAP: - printk(KERN_INFO "Eicon: DIVA Server PRI/PCI detected !\n"); - aparms->type = EICON_CTYPE_MAESTRAP; /*includes 9M,30M*/ - aparms->irq = pdev->irq; - pram = pci_resource_start(pdev, 0); - preg = pci_resource_start(pdev, 2); - pcfg = pci_resource_start(pdev, 4); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq); - printk(KERN_DEBUG "eicon_pci: ram=0x%x\n", - (pram)); - printk(KERN_DEBUG "eicon_pci: reg=0x%x\n", - (preg)); - printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n", - (pcfg)); -#endif - pci_akt = 1; - break; - default: - printk(KERN_ERR "eicon_pci: Unknown PCI card detected !\n"); - pci_cards--; - pci_akt = 0; - break; - } - - if (pci_akt) { - /* remapping memory */ - switch(pci_type) + if ((pCard->hw) && (pCard->hw->in_use)) { - case PCI_MAESTRA: - aparms->PCIreg = (unsigned int) preg; - aparms->PCIcfg = (unsigned int) pcfg; - if (check_region((aparms->PCIreg), 0x20)) { - printk(KERN_WARNING "eicon_pci: reg port already in use !\n"); - aparms->PCIreg = 0; - break; - } else { - request_region(aparms->PCIreg, 0x20, "eicon reg"); + switch(pCard->hw->card_type) { + case DIA_CARD_TYPE_DIVA_SERVER: + ctype = EICON_CTYPE_MAESTRAP; + card_id++; + had_q = 0; + break; + case DIA_CARD_TYPE_DIVA_SERVER_B: + ctype = EICON_CTYPE_MAESTRA; + card_id++; + had_q = 0; + break; + case DIA_CARD_TYPE_DIVA_SERVER_Q: + ctype = EICON_CTYPE_MAESTRAQ; + if (!had_q) + card_id++; + if (++had_q >=4) + had_q = 0; + break; + default: + printk(KERN_ERR "eicon_pci: unknown card type %d !\n", + pCard->hw->card_type); + goto err; } - 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, 0x80, "eicon cfg"); - } - break; - case PCI_MAESTRAQ: - case PCI_MAESTRAQ_U: - case PCI_MAESTRAP: - aparms->shmem = (eicon_pci_shmem *) ioremap(pram, 0x10000); - ram = (u8 *) ((u32)aparms->shmem + MP_SHARED_RAM_OFFSET); - reg = ioremap(preg, 0x4000); - cfg = ioremap(pcfg, 0x1000); - aparms->PCIram = (unsigned int) ram; - aparms->PCIreg = (unsigned int) reg; - aparms->PCIcfg = (unsigned int) cfg; - break; - } - if ((!aparms->PCIreg) || (!aparms->PCIcfg)) { - printk(KERN_ERR "eicon_pci: Card could not be added !\n"); - pci_cards--; - } else { - aparms->mvalid = 1; - sprintf(did, "%s%d", (strlen(ID) < 1) ? "eicon":ID, pci_cards); - - printk(KERN_INFO "%s: DriverID: '%s'\n",eicon_ctype_name[aparms->type] , did); - - if (!(eicon_addcard(aparms->type, (int) aparms, aparms->irq, did))) { + if ((!ctype) || (!(eicon_addcard(ctype, 0, pCard->hw->irq, did, card_id)))) { printk(KERN_ERR "eicon_pci: Card could not be added !\n"); - pci_cards--; + } else { + pci_cards++; + printk(KERN_INFO "%s: DriverID='%s' CardID=%d\n", + eicon_ctype_name[ctype], did, card_id); } +err: } + pCard++; } - - } - } else - printk(KERN_ERR "eicon_pci: Kernel compiled with PCI but no PCI-bios found !\n"); - return 0; -} - -/* - * Checks protocol file id for "F#xxxx" string fragment to - * extract the features, supported by this protocol version. - * binary representation of the feature string value is returned - * in *value. The function returns 0 if feature string was not - * found or has a wrong format, else 1. - */ -static int GetProtFeatureValue(char *sw_id, int *value) -{ - __u8 i, offset; - - while (*sw_id) - { - if ((sw_id[0] == 'F') && (sw_id[1] == '#')) - { - sw_id = &sw_id[2]; - for (i=0, *value=0; i<4; i++, sw_id++) - { - if ((*sw_id >= '0') && (*sw_id <= '9')) - { - offset = '0'; - } - else if ((*sw_id >= 'A') && (*sw_id <= 'F')) - { - offset = 'A' + 10; - } - else if ((*sw_id >= 'a') && (*sw_id <= 'f')) - { - offset = 'a' + 10; - } - else - { - return 0; - } - *value |= (*sw_id - offset) << (4*(3-i)); - } - return 1; - } - else - { - sw_id++; - } - } - return 0; + return pci_cards; } - void -eicon_pci_printpar(eicon_pci_card *card) { - switch (card->type) { - case EICON_CTYPE_MAESTRA: - printk(KERN_INFO "%s at 0x%x / 0x%x, irq %d\n", - eicon_ctype_name[card->type], - (unsigned int)card->PCIreg, - (unsigned int)card->PCIcfg, - card->irq); - break; - case EICON_CTYPE_MAESTRAQ: - case EICON_CTYPE_MAESTRAQ_U: - case EICON_CTYPE_MAESTRAP: - printk(KERN_INFO "%s at 0x%x, irq %d\n", - eicon_ctype_name[card->type], - (unsigned int)card->shmem, - card->irq); -#ifdef EICON_PCI_DEBUG - printk(KERN_INFO "eicon_pci: remapped ram= 0x%x\n",(unsigned int)card->PCIram); - printk(KERN_INFO "eicon_pci: remapped reg= 0x%x\n",(unsigned int)card->PCIreg); - printk(KERN_INFO "eicon_pci: remapped cfg= 0x%x\n",(unsigned int)card->PCIcfg); -#endif - break; - } -} - - -static void -eicon_pci_release_shmem(eicon_pci_card *card) { - if (!card->master) - return; - if (card->mvalid) { - switch (card->type) { - case EICON_CTYPE_MAESTRA: - /* reset board */ - outb(0, card->PCIcfg + 0x4c); /* disable interrupts from PLX */ - outb(0, card->PCIreg + M_RESET); - SLEEP(20); - outb(0, card->PCIreg + M_ADDRH); - outw(0, card->PCIreg + M_ADDR); - outw(0, card->PCIreg + M_DATA); - - release_region(card->PCIreg, 0x20); - release_region(card->PCIcfg, 0x80); - break; - case EICON_CTYPE_MAESTRAQ: - case EICON_CTYPE_MAESTRAQ_U: - case EICON_CTYPE_MAESTRAP: - /* reset board */ - writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET); - SLEEP(20); - writeb(0, card->PCIreg + MP_RESET); - SLEEP(20); - - iounmap((void *)card->shmem); - iounmap((void *)card->PCIreg); - iounmap((void *)card->PCIcfg); - break; - } - } - card->mvalid = 0; -} - -static void -eicon_pci_release_irq(eicon_pci_card *card) { - if (!card->master) - return; - if (card->ivalid) - free_irq(card->irq, card); - card->ivalid = 0; -} - -void -eicon_pci_release(eicon_pci_card *card) { - eicon_pci_release_irq(card); - eicon_pci_release_shmem(card); -} - -/* - * Upload buffer content to adapters shared memory - * on verify error, 1 is returned and a message is printed on screen - * else 0 is returned - * Can serve IO-Type and Memory type adapters - */ -int eicon_upload(t_dsp_download_space *p_para, - __u16 length, /* byte count */ - __u8 *buffer, - int verify) +eicon_pci_init_conf(eicon_card *card) { - __u32 i, dwdata = 0, val = 0, timeout; - __u16 data; - eicon_pci_boot *boot = 0; - - switch (p_para->type) /* actions depend on type of union */ - { - case DL_PARA_IO_TYPE: - for (i=0; i<length; i+=2) - { - outb ((u8) ((p_para->dat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH); - outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR); - /* outw (((u16 *)code)[i >> 1], p_para->dat.io.ioDATA); */ - outw (*(u16 *)&buffer[i], p_para->dat.io.ioDATA); - } - if (verify) /* check written block */ - { - for (i=0; i<length; i+=2) - { - outb ((u8) ((p_para->dat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH); - outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR); - data = inw(p_para->dat.io.ioDATA); - if (data != *(u16 *)&buffer[i]) - { - p_para->dat.io.r3addr += i; - p_para->dat.io.BadData = data; - p_para->dat.io.GoodData = *(u16 *)&buffer[i]; - return 1; - } - } - } - break; - - case DL_PARA_MEM_TYPE: - boot = p_para->dat.mem.boot; - writel(p_para->dat.mem.r3addr, &boot->addr); - for (i=0; i<length; i+=4) - { - writel(((u32 *)buffer)[i >> 2], &boot->data[i]); - } - if (verify) /* check written block */ - { - for (i=0; i<length; i+=4) - { - dwdata = readl(&boot->data[i]); - if (((u32 *)buffer)[i >> 2] != dwdata) - { - p_para->dat.mem.r3addr += i; - p_para->dat.mem.BadData = dwdata; - p_para->dat.mem.GoodData = ((u32 *)buffer)[i >> 2]; - return 1; - } - } - } - writel(((length + 3) / 4), &boot->len); /* len in dwords */ - writel(2, &boot->cmd); - - timeout = jiffies + 20; - while (timeout > jiffies) { - val = readl(&boot->cmd); - if (!val) break; - SLEEP(2); - } - if (val) - { - p_para->dat.mem.timeout = 1; - return 1; - } - break; - } - return 0; -} - - -/* show header information of code file */ -static -int eicon_pci_print_hdr(unsigned char *code, int offset) -{ - unsigned char hdr[80]; - int i, fvalue = 0; - - i = 0; - while ((i < (sizeof(hdr) -1)) - && (code[offset + i] != '\0') - && (code[offset + i] != '\r') - && (code[offset + i] != '\n')) - { - hdr[i] = code[offset + i]; - i++; - } - hdr[i] = '\0'; - printk(KERN_DEBUG "Eicon: loading %s\n", hdr); - if (GetProtFeatureValue(hdr, &fvalue)) return(fvalue); - else return(0); -} - - -/* - * Configure a card, download code into BRI card, - * check if we get interrupts and return 0 on succes. - * Return -ERRNO on failure. - */ -int -eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb) { - int i,j; - int timeout; - unsigned int offset, offp=0, size, length; - int signature = 0; - int FeatureValue = 0; - eicon_pci_codebuf cbuf; - t_dsp_download_space dl_para; - t_dsp_download_desc dsp_download_table; - unsigned char *code; - unsigned int reg; - unsigned int cfg; - - if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf))) - return -EFAULT; - - reg = card->PCIreg; - cfg = card->PCIcfg; - - /* reset board */ - outb(0, reg + M_RESET); - SLEEP(10); - outb(0, reg + M_ADDRH); - outw(0, reg + M_ADDR); - outw(0, reg + M_DATA); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: reset card\n"); -#endif - - /* clear shared memory */ - outb(0xff, reg + M_ADDRH); - outw(0, reg + M_ADDR); - for(i = 0; i < 0xffff; i++) outw(0, reg + M_DATA); - SLEEP(10); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: clear shared memory\n"); -#endif - - /* download protocol and dsp file */ - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: downloading firmware...\n"); -#endif - - /* Allocate code-buffer */ - if (!(code = kmalloc(400, GFP_KERNEL))) { - printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n"); - return -ENOMEM; - } - - /* prepare protocol upload */ - dl_para.type = DL_PARA_IO_TYPE; - dl_para.dat.io.ioADDR = reg + M_ADDR; - dl_para.dat.io.ioADDRH = reg + M_ADDRH; - dl_para.dat.io.ioDATA = reg + M_DATA; - - for (j = 0; j <= cbuf.dsp_code_num; j++) - { - if (j == 0) size = cbuf.protocol_len; - else size = cbuf.dsp_code_len[j]; - - offset = 0; - - if (j == 0) dl_para.dat.io.r3addr = 0; - if (j == 1) dl_para.dat.io.r3addr = M_DSP_CODE_BASE + - ((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc); - if (j == 2) dl_para.dat.io.r3addr = M_DSP_CODE_BASE; - if (j == 3) dl_para.dat.io.r3addr = M_DSP_CODE_BASE + sizeof(__u32); - - do /* download block of up to 400 bytes */ - { - length = ((size - offset) >= 400) ? 400 : (size - offset); - - if (copy_from_user(code, (&cb->code) + offp + offset, length)) { - kfree(code); - return -EFAULT; - } - - if ((offset == 0) && (j < 2)) { - FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80); -#ifdef EICON_PCI_DEBUG - if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%04x.\n", FeatureValue); -#endif - if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) { - printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n"); - kfree(code); - return -EFAULT; - } - ((eicon_card *)card->card)->Feature = FeatureValue; - } - - if (eicon_upload(&dl_para, length, code, 1)) - { - printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr); - kfree(code); - return -EIO; - } - /* move onto next block */ - offset += length; - dl_para.dat.io.r3addr += length; - } while (offset < size); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "Eicon: %d bytes loaded.\n", offset); -#endif - offp += size; - } - kfree(code); - - /* clear signature */ - outb(0xff, reg + M_ADDRH); - outw(0x1e, reg + M_ADDR); - outw(0, reg + M_DATA); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n"); -#endif - /* copy configuration data into shared memory */ - outw(8, reg + M_ADDR); outb(cbuf.tei, reg + M_DATA); - outw(9, reg + M_ADDR); outb(cbuf.nt2, reg + M_DATA); - outw(10,reg + M_ADDR); outb(0, reg + M_DATA); - outw(11,reg + M_ADDR); outb(cbuf.WatchDog, reg + M_DATA); - outw(12,reg + M_ADDR); outb(cbuf.Permanent, reg + M_DATA); - outw(13,reg + M_ADDR); outb(0, reg + M_DATA); /* XInterface */ - outw(14,reg + M_ADDR); outb(cbuf.StableL2, reg + M_DATA); - outw(15,reg + M_ADDR); outb(cbuf.NoOrderCheck, reg + M_DATA); - outw(16,reg + M_ADDR); outb(0, reg + M_DATA); /* HandsetType */ - outw(17,reg + M_ADDR); outb(0, reg + M_DATA); /* SigFlags */ - outw(18,reg + M_ADDR); outb(cbuf.LowChannel, reg + M_DATA); - outw(19,reg + M_ADDR); outb(cbuf.ProtVersion, reg + M_DATA); - outw(20,reg + M_ADDR); outb(cbuf.Crc4, reg + M_DATA); - outw(21,reg + M_ADDR); outb((cbuf.Loopback) ? 2:0, reg + M_DATA); - - for (i=0;i<32;i++) - { - outw( 32+i, reg + M_ADDR); outb(cbuf.l[0].oad[i], reg + M_DATA); - outw( 64+i, reg + M_ADDR); outb(cbuf.l[0].osa[i], reg + M_DATA); - outw( 96+i, reg + M_ADDR); outb(cbuf.l[0].spid[i], reg + M_DATA); - outw(128+i, reg + M_ADDR); outb(cbuf.l[1].oad[i], reg + M_DATA); - outw(160+i, reg + M_ADDR); outb(cbuf.l[1].osa[i], reg + M_DATA); - outw(192+i, reg + M_ADDR); outb(cbuf.l[1].spid[i], reg + M_DATA); + int j; + + /* initializing some variables */ + card->ReadyInt = 0; + + for(j = 0; j < 256; j++) + card->IdTable[j] = NULL; + + for(j = 0; j < (card->d->channels + 1); j++) { + card->bch[j].e.busy = 0; + card->bch[j].e.D3Id = 0; + card->bch[j].e.B2Id = 0; + card->bch[j].e.ref = 0; + card->bch[j].e.Req = 0; + card->bch[j].e.complete = 1; + card->bch[j].fsm_state = EICON_STATE_NULL; } - -#ifdef EICON_PCI_DEBUG - printk(KERN_ERR "eicon_pci: starting CPU...\n"); -#endif - /* let the CPU run */ - outw(0x08, reg + M_RESET); - - timeout = jiffies + (5*HZ); - while (timeout > jiffies) { - outw(0x1e, reg + M_ADDR); - signature = inw(reg + M_DATA); - if (signature == DIVAS_SIGNATURE) break; - SLEEP(2); - } - if (signature != DIVAS_SIGNATURE) - { -#ifdef EICON_PCI_DEBUG - printk(KERN_ERR "eicon_pci: signature 0x%x expected 0x%x\n",signature,DIVAS_SIGNATURE); -#endif - printk(KERN_ERR "eicon_pci: Timeout, protocol code not running !\n"); - return -EIO; - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n"); -#endif - - /* get serial number and number of channels supported by card */ - outb(0xff, reg + M_ADDRH); - outw(0x3f6, reg + M_ADDR); - card->channels = inw(reg + M_DATA); - card->serial = (u32)inw(cfg + 0x22) << 16 | (u32)inw(cfg + 0x26); - printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels); - printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial); - - /* test interrupt */ - card->irqprobe = 1; - - if (!card->ivalid) { - if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card)) - { - printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq); - return -EIO; - } - } - card->ivalid = 1; - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: testing interrupt\n"); -#endif - /* Trigger an interrupt and check if it is delivered */ - outb(0x41, cfg + 0x4c); /* enable PLX for interrupts */ - outb(0x89, reg + M_RESET); /* place int request */ - - timeout = jiffies + 20; - while (timeout > jiffies) { - if (card->irqprobe != 1) break; - SLEEP(5); - } - if (card->irqprobe == 1) { - free_irq(card->irq, card); - card->ivalid = 0; - printk(KERN_ERR "eicon_pci: Getting no interrupts !\n"); - return -EIO; - } - - /* initializing some variables */ - ((eicon_card *)card->card)->ReadyInt = 0; - for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL; - for(j=0; j< (card->channels + 1); j++) { - ((eicon_card *)card->card)->bch[j].e.busy = 0; - ((eicon_card *)card->card)->bch[j].e.D3Id = 0; - ((eicon_card *)card->card)->bch[j].e.B2Id = 0; - ((eicon_card *)card->card)->bch[j].e.ref = 0; - ((eicon_card *)card->card)->bch[j].e.Req = 0; - ((eicon_card *)card->card)->bch[j].e.complete = 1; - ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL; - } - - printk(KERN_INFO "Eicon: Card successfully started\n"); - - return 0; } - -/* - * Configure a card, download code into PRI card, - * check if we get interrupts and return 0 on succes. - * Return -ERRNO on failure. - */ -int -eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb) { - eicon_pci_boot *boot; - eicon_pr_ram *prram; - int i,j; - int timeout; - int FeatureValue = 0; - unsigned int offset, offp=0, size, length; - unsigned long int signature = 0; - t_dsp_download_space dl_para; - t_dsp_download_desc dsp_download_table; - eicon_pci_codebuf cbuf; - unsigned char *code; - unsigned char req_int; - char *ram, *reg, *cfg; - - if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf))) - return -EFAULT; - - boot = &card->shmem->boot; - ram = (char *)card->PCIram; - reg = (char *)card->PCIreg; - cfg = (char *)card->PCIcfg; - prram = (eicon_pr_ram *)ram; - - /* reset board */ - writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET); - SLEEP(20); - writeb(0, card->PCIreg + MP_RESET); - SLEEP(20); - - /* set command count to 0 */ - writel(0, &boot->reserved); - - /* check if CPU increments the life word */ - i = readw(&boot->live); - SLEEP(20); - if (i == readw(&boot->live)) { - printk(KERN_ERR "eicon_pci: card is reset, but CPU not running !\n"); - return -EIO; - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: reset card OK (CPU running)\n"); #endif - - /* download firmware : DSP and Protocol */ -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: downloading firmware...\n"); -#endif - - /* Allocate code-buffer */ - if (!(code = kmalloc(400, GFP_KERNEL))) { - printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n"); - return -ENOMEM; - } - - /* prepare protocol upload */ - dl_para.type = DL_PARA_MEM_TYPE; - dl_para.dat.mem.boot = boot; - - for (j = 0; j <= cbuf.dsp_code_num; j++) - { - if (j==0) size = cbuf.protocol_len; - else size = cbuf.dsp_code_len[j]; - - if (j==1) writel(MP_DSP_ADDR, &boot->addr); /* DSP code entry point */ - - if (j == 0) dl_para.dat.io.r3addr = MP_PROTOCOL_ADDR; - if (j == 1) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE + - ((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc); - if (j == 2) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE; - if (j == 3) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE + sizeof(__u32); - - offset = 0; - do /* download block of up to 400 bytes */ - { - length = ((size - offset) >= 400) ? 400 : (size - offset); - - if (copy_from_user(code, (&cb->code) + offp + offset, length)) { - kfree(code); - return -EFAULT; - } - - if ((offset == 0) && (j < 2)) { - FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80); -#ifdef EICON_PCI_DEBUG - if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%x.\n", FeatureValue); -#endif - if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) { - printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n"); - kfree(code); - return -EFAULT; - } - ((eicon_card *)card->card)->Feature = FeatureValue; - } - - if (eicon_upload(&dl_para, length, code, 1)) - { - if (dl_para.dat.mem.timeout == 0) - printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr); - else - printk(KERN_ERR "eicon_pci: timeout, no ACK to load !\n"); - kfree(code); - return -EIO; - } - - /* move onto next block */ - offset += length; - dl_para.dat.mem.r3addr += length; - } while (offset < size); -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: %d bytes loaded.\n", offset); -#endif - offp += size; - } - kfree(code); - - /* initialize the adapter data structure */ -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n"); -#endif - /* clear out config space */ - for (i = 0; i < 256; i++) writeb(0, &ram[i]); - - /* copy configuration down to the card */ - writeb(cbuf.tei, &ram[8]); - writeb(cbuf.nt2, &ram[9]); - writeb(0, &ram[10]); - writeb(cbuf.WatchDog, &ram[11]); - writeb(cbuf.Permanent, &ram[12]); - writeb(cbuf.XInterface, &ram[13]); - writeb(cbuf.StableL2, &ram[14]); - writeb(cbuf.NoOrderCheck, &ram[15]); - writeb(cbuf.HandsetType, &ram[16]); - writeb(0, &ram[17]); - writeb(cbuf.LowChannel, &ram[18]); - writeb(cbuf.ProtVersion, &ram[19]); - writeb(cbuf.Crc4, &ram[20]); - for (i = 0; i < 32; i++) - { - writeb(cbuf.l[0].oad[i], &ram[32 + i]); - writeb(cbuf.l[0].osa[i], &ram[64 + i]); - writeb(cbuf.l[0].spid[i], &ram[96 + i]); - writeb(cbuf.l[1].oad[i], &ram[128 + i]); - writeb(cbuf.l[1].osa[i], &ram[160 + i]); - writeb(cbuf.l[1].spid[i], &ram[192 + i]); - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: configured card OK\n"); -#endif - - /* start adapter */ -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: tell card to start...\n"); -#endif - writel(MP_PROTOCOL_ADDR, &boot->addr); /* RISC code entry point */ - writel(3, &boot->cmd); /* DIVAS_START_CMD */ - - /* wait till card ACKs */ - timeout = jiffies + (5*HZ); - while (timeout > jiffies) { - signature = readl(&boot->signature); - if ((signature >> 16) == DIVAS_SIGNATURE) break; - SLEEP(2); - } - if ((signature >> 16) != DIVAS_SIGNATURE) - { -#ifdef EICON_PCI_DEBUG - printk(KERN_ERR "eicon_pci: signature 0x%lx expected 0x%x\n",(signature >> 16),DIVAS_SIGNATURE); -#endif - printk(KERN_ERR "eicon_pci: timeout, protocol code not running !\n"); - return -EIO; - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n"); -#endif - - /* get serial number and number of channels supported by card */ - card->channels = readb(&ram[0x3f6]); - card->serial = readl(&ram[0x3f0]); - printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels); - printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial); - - /* test interrupt */ - readb(&ram[0x3fe]); - writeb(0, &ram[0x3fe]); /* reset any pending interrupt */ - readb(&ram[0x3fe]); - - writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]); - writew(0, &cfg[MP_IRQ_RESET + 2]); - - card->irqprobe = 1; - - if (!card->ivalid) { - if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card)) - { - printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq); - return -EIO; - } - } - card->ivalid = 1; - - req_int = readb(&prram->ReadyInt); -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: testing interrupt\n"); -#endif - req_int++; - /* Trigger an interrupt and check if it is delivered */ - writeb(req_int, &prram->ReadyInt); - - timeout = jiffies + 20; - while (timeout > jiffies) { - if (card->irqprobe != 1) break; - SLEEP(2); - } - if (card->irqprobe == 1) { - free_irq(card->irq, card); - card->ivalid = 0; - printk(KERN_ERR "eicon_pci: Getting no interrupts !\n"); - return -EIO; - } - - /* initializing some variables */ - ((eicon_card *)card->card)->ReadyInt = 0; - for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL; - for(j=0; j< (card->channels + 1); j++) { - ((eicon_card *)card->card)->bch[j].e.busy = 0; - ((eicon_card *)card->card)->bch[j].e.D3Id = 0; - ((eicon_card *)card->card)->bch[j].e.B2Id = 0; - ((eicon_card *)card->card)->bch[j].e.ref = 0; - ((eicon_card *)card->card)->bch[j].e.Req = 0; - ((eicon_card *)card->card)->bch[j].e.complete = 1; - ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL; - } - - printk(KERN_INFO "Eicon: Card successfully started\n"); - - return 0; -} - #endif /* CONFIG_PCI */ diff --git a/drivers/isdn/eicon/eicon_pci.h b/drivers/isdn/eicon/eicon_pci.h index 384cc422c..17fd4183a 100644 --- a/drivers/isdn/eicon/eicon_pci.h +++ b/drivers/isdn/eicon/eicon_pci.h @@ -1,4 +1,4 @@ -/* $Id: eicon_pci.h,v 1.4 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_pci.h,v 1.6 2000/05/07 08:51:04 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards (PCI part). * @@ -19,26 +19,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_pci.h,v $ - * Revision 1.4 2000/01/23 21:21:23 armin - * Added new trace capability and some updates. - * DIVA Server BRI now supports data for ISDNLOG. - * - * Revision 1.3 1999/03/29 11:19:51 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.2 1999/03/02 12:37:50 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.1 1999/01/01 18:09:46 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #ifndef eicon_pci_h @@ -46,147 +26,20 @@ #ifdef __KERNEL__ - -#define PCI_VENDOR_EICON 0x1133 -#define PCI_DIVA_PRO20 0xe001 /* Not supported */ -#define PCI_DIVA20 0xe002 /* Not supported */ -#define PCI_DIVA_PRO20_U 0xe003 /* Not supported */ -#define PCI_DIVA20_U 0xe004 /* Not supported */ -#define PCI_MAESTRA 0xe010 -#define PCI_MAESTRAQ 0xe012 -#define PCI_MAESTRAQ_U 0xe013 -#define PCI_MAESTRAP 0xe014 - -#define DIVA_PRO20 1 -#define DIVA20 2 -#define DIVA_PRO20_U 3 -#define DIVA20_U 4 -#define MAESTRA 5 -#define MAESTRAQ 6 -#define MAESTRAQ_U 7 -#define MAESTRAP 8 - -#define TRUE 1 -#define FALSE 0 - -#define DIVAS_SIGNATURE 0x4447 - - -/* MAESTRA BRI PCI */ - -#define M_RESET 0x10 /* offset of reset register */ -#define M_DATA 0x00 /* offset of data register */ -#define M_ADDR 0x04 /* offset of address register */ -#define M_ADDRH 0x0c /* offset of high address register */ - -#define M_DSP_CODE_LEN 0xbf7d0000 -#define M_DSP_CODE 0xbf7d0004 /* max 128K DSP-Code */ -#define M_DSP_CODE_BASE 0xbf7a0000 -#define M_MAX_DSP_CODE_SIZE 0x00050000 /* max 320K DSP-Code (Telindus) */ - - - -/* MAESTRA PRI PCI */ - -#define MP_SHARED_RAM_OFFSET 0x1000 /* offset of shared RAM base in the DRAM memory bar */ - -#define MP_IRQ_RESET 0xc18 /* offset of interrupt status register in the CONFIG memory bar */ -#define MP_IRQ_RESET_VAL 0xfe /* value to clear an interrupt */ - -#define MP_PROTOCOL_ADDR 0xa0011000 /* load address of protocol code */ -#define MP_DSP_ADDR 0xa03c0000 /* load address of DSP code */ -#define MP_MAX_PROTOCOL_CODE_SIZE 0x000a0000 /* max 640K Protocol-Code */ -#define MP_DSP_CODE_BASE 0xa03a0000 -#define MP_MAX_DSP_CODE_SIZE 0x00060000 /* max 384K DSP-Code */ - -#define MP_RESET 0x20 /* offset of RESET register in the DEVICES memory bar */ - -/* RESET register bits */ -#define _MP_S2M_RESET 0x10 /* active lo */ -#define _MP_LED2 0x08 /* 1 = on */ -#define _MP_LED1 0x04 /* 1 = on */ -#define _MP_DSP_RESET 0x02 /* active lo */ -#define _MP_RISC_RESET 0x81 /* active hi, bit 7 for compatibility with old boards */ - -/* boot interface structure */ -typedef struct { - __u32 cmd __attribute__ ((packed)); - __u32 addr __attribute__ ((packed)); - __u32 len __attribute__ ((packed)); - __u32 err __attribute__ ((packed)); - __u32 live __attribute__ ((packed)); - __u32 reserved[(0x1020>>2)-6] __attribute__ ((packed)); - __u32 signature __attribute__ ((packed)); - __u8 data[1]; /* real interface description */ -} eicon_pci_boot; - - -#define DL_PARA_IO_TYPE 0 -#define DL_PARA_MEM_TYPE 1 - -typedef struct tag_dsp_download_space -{ - __u16 type; /* see definitions above to differ union elements */ - union - { - struct - { - __u32 r3addr; - __u16 ioADDR; - __u16 ioADDRH; - __u16 ioDATA; - __u16 BadData; /* in case of verify error */ - __u16 GoodData; - } io; /* for io based adapters */ - struct - { - __u32 r3addr; - eicon_pci_boot *boot; - __u32 BadData; /* in case of verify error */ - __u32 GoodData; - __u16 timeout; - } mem; /* for memory based adapters */ - } dat; -} t_dsp_download_space; - - -/* Shared memory */ -typedef union { - eicon_pci_boot boot; -} eicon_pci_shmem; - /* * card's description */ typedef struct { - int ramsize; int irq; /* IRQ */ - unsigned int PCIram; - unsigned int PCIreg; - unsigned int PCIcfg; - long int serial; /* Serial No. */ int channels; /* No. of supported channels */ void* card; - eicon_pci_shmem* shmem; /* Shared-memory area */ - unsigned char* intack; /* Int-Acknowledge */ - unsigned char* stopcpu; /* Writing here stops CPU */ - unsigned char* startcpu; /* Writing here starts CPU */ unsigned char type; /* card type */ - unsigned char irqprobe; /* Flag: IRQ-probing */ - unsigned char mvalid; /* Flag: Memory is valid */ - unsigned char ivalid; /* Flag: IRQ is valid */ unsigned char master; /* Flag: Card is Quadro 1/4 */ - void* generic; /* Ptr to generic card struct */ } eicon_pci_card; - - -extern int eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb); -extern int eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb); -extern void eicon_pci_release(eicon_pci_card *card); -extern void eicon_pci_printpar(eicon_pci_card *card); extern int eicon_pci_find_card(char *ID); #endif /* __KERNEL__ */ #endif /* eicon_pci_h */ + diff --git a/drivers/isdn/eicon/fcheck.c b/drivers/isdn/eicon/fcheck.c new file mode 100644 index 000000000..c86f7d3df --- /dev/null +++ b/drivers/isdn/eicon/fcheck.c @@ -0,0 +1,31 @@ +/* $Id: fcheck.c,v 1.3 2000/06/12 12:44:02 armin Exp $ + * + * (c) 2000 Cytronics & Melware + * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/README.eicon + * + * + */ + +#include <linux/kernel.h> + +char * +file_check(void) { + +#ifdef FILECHECK +#if FILECHECK == 0 + return("verified"); +#endif +#if FILECHECK == 1 + return("modified"); +#endif +#if FILECHECK == 127 + return("verification failed"); +#endif +#else + return("not verified"); +#endif +} + diff --git a/drivers/isdn/eicon/fourbri.c b/drivers/isdn/eicon/fourbri.c new file mode 100644 index 000000000..5fe9817e0 --- /dev/null +++ b/drivers/isdn/eicon/fourbri.c @@ -0,0 +1,583 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.7 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* Diva Server 4BRI specific part of initialisation */ +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" +#include "dsp_defs.h" +#include "constant.h" +#include "adapter.h" +#include "uxio.h" + +#define TEST_INT_DIVAS_Q 0x13 + +#define DIVAS_MAINT_OFFSET 0xff00 /* value for 4BRI card */ +#define MQ_BOARD_DSP_OFFSET 0x00a00000 +#define MQ_DSP1_ADDR_OFFSET 0x00000008 +#define MQ_DSP_JUNK_OFFSET 0x00000400 +#define MQ_DSP1_DATA_OFFSET 0x00000000 +#define MQ_BOARD_ISAC_DSP_RESET 0x00800028 +#define MQ_BREG_RISC 0x1200 /* RISC Reset */ +#define MQ_ISAC_DSP_RESET 0x0028 /* ISAC and DSP reset address offset */ +#define MQ_RISC_COLD_RESET_MASK 0x0001 /* RISC Cold reset */ +#define MQ_RISC_WARM_RESET_MASK 0x0002 /* RISC Warm reset */ +#define MQ_IRQ_REQ_ON 0x1 +#define MQ_IRQ_REQ_OFF 0x0 +#define MQ_BREG_IRQ_TEST 0x0608 +#define PLX9054_INTCSR 0x69 +#define PLX9054_INT_ENA 0x09 + +#define DIVAS_IOBASE 0x01 +#define M_PCI_RESET 0x10 + +byte mem_in(ADAPTER *a, void *adr); +word mem_inw(ADAPTER *a, void *adr); +void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e); +void mem_out(ADAPTER *a, void *adr, byte data); +void mem_outw(ADAPTER *a, void *adr, word data); +void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_inc(ADAPTER *a, void *adr); + +int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg); +int fourbri_ISR (card_t* card); + +int FPGA_Download(word, dword, byte *, byte *, int); +extern byte FPGA_Bytes[]; +extern void *get_card(int); + +byte UxCardPortIoIn(ux_diva_card_t *card, byte *base, int offset); +void UxCardPortIoOut(ux_diva_card_t *card, byte *base, int offset, byte); +word GetProtFeatureValue(char *sw_id); + +void memcp(byte *dst, byte *src, dword dwLen); +int memcm(byte *dst, byte *src, dword dwLen); + +static int diva_server_4bri_reset(card_t *card) +{ + byte *ctl; + + DPRINTF(("divas: reset Diva Server 4BRI")); + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + /* stop RISC, DSP's and ISAC */ + UxCardMemOut(card->hw, &ctl[MQ_BREG_RISC], 0); + UxCardMemOut(card->hw, &ctl[MQ_ISAC_DSP_RESET], 0); + + UxCardMemDetach(card->hw, ctl); + + return 0; +} + +static int diva_server_4bri_config(card_t *card, dia_config_t *config) +{ + byte *shared; + int i, j; + + DPRINTF(("divas: configure Diva Server 4BRI")); + + shared = (byte *) UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + for (i=0; i<256; i++) + { + UxCardMemOut(card->hw, &shared[i], 0); + } + + UxCardMemOut(card->hw, &shared[ 8], config->tei); + UxCardMemOut(card->hw, &shared[ 9], config->nt2); + UxCardMemOut(card->hw, &shared[10], 0); + UxCardMemOut(card->hw, &shared[11], config->watchdog); + UxCardMemOut(card->hw, &shared[12], config->permanent); + UxCardMemOut(card->hw, &shared[13], config->x_interface); + UxCardMemOut(card->hw, &shared[14], config->stable_l2); + UxCardMemOut(card->hw, &shared[15], config->no_order_check); + UxCardMemOut(card->hw, &shared[16], config->handset_type); + UxCardMemOut(card->hw, &shared[17], 0); + UxCardMemOut(card->hw, &shared[18], config->low_channel); + UxCardMemOut(card->hw, &shared[19], config->prot_version); + UxCardMemOut(card->hw, &shared[20], config->crc4); + + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + DPRINTF(("divas: Signifying V.90")); + UxCardMemOut(card->hw, &shared[22], 4); + } + else + { + UxCardMemOut(card->hw, &shared[22], 0); + } + + for (i=0; i<2; i++) + { + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[32+(i*96)+j],config->terminal[i].oad[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[64+(i*96)+j],config->terminal[i].osa[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[96+(i*96)+j],config->terminal[i].spid[j]); + } + } + + UxCardMemDetach(card->hw, shared); + + return 0; +} + +static +void diva_server_4bri_reset_int(card_t *card) +{ + byte *ctl; + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF); + + UxCardMemDetach(card->hw, ctl); + + return; +} + + +static int diva_server_4bri_test_int(card_t *card) +{ + byte *ctl, i; + byte *reg; + + DPRINTF(("divas: test interrupt for Diva Server 4BRI")); + + /* We get the last (dummy) adapter in so we need to go back to the first */ + + card = get_card(card->cfg.card_id - 3); + + /* Enable interrupts on PLX chip */ + + reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY); + + UxCardPortIoOut(card->hw, reg, PLX9054_INTCSR, PLX9054_INT_ENA); + + UxCardMemDetach(card->hw, reg); + + /* Set the test interrupt flag */ + card->test_int_pend = TEST_INT_DIVAS_Q; + + /* Now to trigger the interrupt */ + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_ON); + + UxCardMemDetach(card->hw, ctl); + + for (i = 0; i < 50; i++) + { + if (!card->test_int_pend) + { + break; + } + UxPause(10); + } + + if (card->test_int_pend) + { + DPRINTF(("active: timeout waiting for card to interrupt")); + return (-1); + } + + return 0; +} + + +static void print_hdr(unsigned char *code, int offset) +{ + unsigned char hdr[80]; + int i; + + i = 0; + + while ((i < (DIM(hdr) -1)) && + (code[offset + i] != '\0') && + (code[offset + i] != '\r') && + (code[offset + i] != '\n')) + { + hdr[i] = code[offset + i]; + i++; + } + + hdr[i] = '\0'; + + DPRINTF(("divas: loading %s", hdr)); +} + +static int diva_server_4bri_load(card_t *card, dia_load_t *load) +{ + byte *pRAM=NULL; + int download_offset=0; + card_t *FirstCard; + byte sw_id[80]; + + DPRINTF(("divas: loading Diva Server 4BRI[%d]", load->card_id)); + + switch(load->code_type) + { + case DIA_CPU_CODE: + DPRINTF(("divas: RISC code")); + print_hdr(load->code, 0x80); + card->hw->features = GetProtFeatureValue((char *)&load->code[0x80]); + download_offset = 0; // Protocol code written to offset 0 + pRAM = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + break; + + case DIA_DSP_CODE: + DPRINTF(("divas: DSP code")); + print_hdr(load->code, 0x0); + FirstCard = get_card(load->card_id - 3); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + download_offset = MQ_V90D_DSP_CODE_BASE; + } + else + { + download_offset = MQ_ORG_DSP_CODE_BASE; + } + pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY); + download_offset += (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC); + + break; + + case DIA_TABLE_CODE: + DPRINTF(("divas: TABLE code")); + FirstCard = get_card(load->card_id - 3); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + download_offset = MQ_V90D_DSP_CODE_BASE + sizeof(dword); + } + else + { + download_offset = MQ_ORG_DSP_CODE_BASE + sizeof(dword); + } + pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY); + break; + + case DIA_CONT_CODE: + DPRINTF(("divas: continuation code")); + break; + + case DIA_DLOAD_CNT: + DPRINTF(("divas: COUNT code")); + FirstCard = get_card(load->card_id - 3); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + download_offset = MQ_V90D_DSP_CODE_BASE; + } + else + { + download_offset = MQ_ORG_DSP_CODE_BASE; + } + pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY); + break; + + case DIA_FPGA_CODE: + DPRINTF(("divas: 4BRI FPGA download - %d bytes", load->length)); + if (FPGA_Download(IDI_ADAPTER_MAESTRAQ, + card->hw->io_base, + sw_id, + load->code, + load->length + ) == -1) + { + DPRINTF(("divas: FPGA download failed")); + return -1; + } + + /* NOW reset the 4BRI */ + diva_server_4bri_reset(card); + return 0; // No need for anything further loading + + default: + DPRINTF(("divas: unknown code type")); + return -1; + } + + memcp(pRAM + (download_offset & 0x3FFFFF), load->code, load->length); + + { + int mism_off; + if ((mism_off = memcm(pRAM + (download_offset & 0x3FFFFF), load->code, load->length))) + { + DPRINTF(("divas: memory mismatch at offset %d", mism_off)); + UxCardMemDetach(card->hw, pRAM); + return -1; + } + } + + UxCardMemDetach(card->hw, pRAM); + + return 0; +} + +static int diva_server_4bri_start(card_t *card, byte *channels) +{ + byte *ctl; + byte *shared, i; + int adapter_num; + + DPRINTF(("divas: start Diva Server 4BRI")); + *channels = 0; + card->is_live = FALSE; + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + UxCardMemOutW(card->hw, &ctl[MQ_BREG_RISC], MQ_RISC_COLD_RESET_MASK); + + UxPause(2); + + UxCardMemOutW(card->hw, &ctl[MQ_BREG_RISC], MQ_RISC_WARM_RESET_MASK | MQ_RISC_COLD_RESET_MASK); + + UxPause(10); + + UxCardMemDetach(card->hw, ctl); + + shared = (byte *) UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + for ( i = 0 ; i < 300 ; ++i ) + { + UxPause (10) ; + + if ( UxCardMemInW(card->hw, &shared[0x1E]) == 0x4447 ) + { + DPRINTF(("divas: Protocol startup time %d.%02d seconds", + (i / 100), (i % 100) )); + + break; + } + } + + if (i==300) + { + DPRINTF(("divas: Timeout starting card")); + DPRINTF(("divas: Signature == 0x%04X", UxCardMemInW(card->hw, &shared[0x1E]))); + + UxCardMemDetach(card->hw, shared); + return -1; + } + + UxCardMemDetach(card->hw, shared); + + for (adapter_num=3; adapter_num >= 0; adapter_num--) + { + card_t *qbri_card; + + qbri_card = get_card(card->cfg.card_id - adapter_num); + + if (qbri_card) + { + qbri_card->is_live = TRUE; + shared = UxCardMemAttach(qbri_card->hw, DIVAS_SHARED_MEMORY); + *channels += UxCardMemIn(qbri_card->hw, &shared[0x3F6]); + UxCardMemDetach(qbri_card->hw, shared); + } + else + { + DPRINTF(("divas: Couldn't get card info %d", card->cfg.card_id)); + } + } + + diva_server_4bri_test_int(card); + + return 0; +} + +static +int diva_server_4bri_mem_get(card_t *card, mem_block_t *mem_block) + +{ + byte *a; + byte *card_addr; + word length = 0; + int i; + + a = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + card_addr = a; + card_addr += mem_block->addr; + + for (i=0; i < sizeof(mem_block->data); i++) + { + mem_block->data[i] = UxCardMemIn(card->hw, card_addr); + card_addr++; + length++; + } + + UxCardMemDetach(card->hw, a); + + return length; +} + +/* + * Initialise 4BRI specific entry points + */ + +int Divas4BriInit(card_t *card, dia_card_t *cfg) +{ +// byte sw_id[80]; +// extern int FPGA_Done; + + DPRINTF(("divas: initialise Diva Server 4BRI")); + + if (Divas4BRIInitPCI(card, cfg) == -1) + { + return -1; + } + + /* Need to download the FPGA */ +/* if (!FPGA_Done) + { + int retVal; + + retVal=FPGA_Download(IDI_ADAPTER_MAESTRAQ, + cfg->io_base, + sw_id, + FPGA_Bytes + ); + if(retVal==-1) + { + + DPRINTF(("divas: FPGA Download Failed")); + return -1; + + } + FPGA_Done = 1; + } */ + + card->card_reset = diva_server_4bri_reset; + card->card_load = diva_server_4bri_load; + card->card_config = diva_server_4bri_config; + card->card_start = diva_server_4bri_start; + card->reset_int = diva_server_4bri_reset_int; + card->card_mem_get = diva_server_4bri_mem_get; + + card->xlog_offset = DIVAS_MAINT_OFFSET; + + card->out = DivasOut; + card->test_int = DivasTestInt; + card->dpc = DivasDpc; + card->clear_int = DivasClearInt; + card->card_isr = fourbri_ISR; + + card->a.ram_out = mem_out; + card->a.ram_outw = mem_outw; + card->a.ram_out_buffer = mem_out_buffer; + card->a.ram_inc = mem_inc; + + card->a.ram_in = mem_in; + card->a.ram_inw = mem_inw; + card->a.ram_in_buffer = mem_in_buffer; + card->a.ram_look_ahead = mem_look_ahead; + + return 0; +} + +void memcp(byte *dst, byte *src, dword dwLen) +{ + while (dwLen) + { + *dst = *src; + dst++; src++; + dwLen--; + } +} + +int memcm(byte *dst, byte *src, dword dwLen) +{ + int offset = 0; + + while (offset < dwLen) + { + if(*dst != *src) + return (offset+1); + + offset++; + src++; + dst++; + } + + return 0; +} + + + +/*int fourbri_ISR (card_t* card) +{ + int served = 0; + byte *DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + + if (UxCardPortIoIn (card->hw, DivasIOBase, M_PCI_RESET) & 0x01) + { + served = 1; + card->int_pend += 1; + DivasDpcSchedule(); + UxCardPortIoOut (card->hw, DivasIOBase, M_PCI_RESET, 0x08); + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return (served != 0); +}*/ + + +int fourbri_ISR (card_t* card) +{ + int served = 0; + byte *ctl; + byte *reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY); + + if (UxCardPortIoIn(card->hw, reg, PLX9054_INTCSR) & 0x80) + { + served = 1; + card->int_pend += 1; + DivasDpcSchedule(); /* ISR DPC */ + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF); + UxCardMemDetach(card->hw, ctl); + } + + UxCardMemDetach(card->hw, reg); + return (served != 0); +} diff --git a/drivers/isdn/eicon/fpga.c b/drivers/isdn/eicon/fpga.c new file mode 100644 index 000000000..b5f21678e --- /dev/null +++ b/drivers/isdn/eicon/fpga.c @@ -0,0 +1,158 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include "sys.h" +#include "idi.h" +#include "uxio.h" + +#define FPGA_PORT 0x6E +#define FPGA_DLOAD_BUFLEN 256 +#define NAME_OFFSET 0x10 +#define NAME_MAXLEN 12 +#define DATE_OFFSET 0x2c +#define DATE_MAXLEN 10 + +word UxCardPortIoInW(ux_diva_card_t *card, byte *base, int offset); +void UxCardPortIoOutW(ux_diva_card_t *card, byte *base, int offset, word); +void UxPause(long int); + +/*-------------------------------------------------------------------------*/ +/* Loads the FPGA configuration file onto the hardware. */ +/* Function returns 0 on success, else an error number. */ +/* On success, an identifier string is returned in the buffer */ +/* */ +/* A buffer of FPGA_BUFSIZE, a handle to the already opened bitstream */ +/* file and a file read function has to be provided by the operating */ +/* system part. */ +/* ----------------------------------------------------------------------- */ +int FPGA_Download( word cardtype, + dword RegBase, + byte *strbuf, + byte FPGA_SRC[], + int FPGA_LEN + ) +{ + word i, j, k; + word baseval, Mask_PROGRAM, Mask_DONE, Mask_CCLK, Mask_DIN; + dword addr; + byte *pFPGA; + + //--- check for legal cardtype + switch (cardtype) + { + case IDI_ADAPTER_MAESTRAQ: + addr = RegBase ; // address where to access FPGA + Mask_PROGRAM = 0x0001; // FPGA pins at address + Mask_DONE = 0x0002; + Mask_CCLK = 0x0100; + Mask_DIN = 0x0400; + baseval = 0x000d; // PROGRAM hi, CCLK lo, DIN lo by default + break; + + default: + + DPRINTF(("divas: FPGA Download ,Illegal Card")); + return -1; // illegal card + } + + //--- generate id string from file content + for (j=NAME_OFFSET, k=0; j<(NAME_OFFSET+NAME_MAXLEN); j++, k++) //name + { + if (!FPGA_SRC[j]) break; + strbuf[k] = FPGA_SRC[j]; + } + strbuf[k++] = ' '; + for (j=DATE_OFFSET; j<(DATE_OFFSET+DATE_MAXLEN); j++, k++) // date + { + if (!FPGA_SRC[j]) break; + strbuf[k] = FPGA_SRC[j]; + } + strbuf[k] = 0; + + DPRINTF(("divas: FPGA Download - %s", strbuf)); + + //--- prepare download, Pulse PROGRAM pin down. + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval &~Mask_PROGRAM); // PROGRAM low pulse + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); // release + UxPause(50); // wait until FPGA finised internal memory clear + + //--- check done pin, must be low + if (UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT) &Mask_DONE) + { + DPRINTF(("divas: FPGA_ERR_DONE_WRONG_LEVEL")); + return -1; + } + + pFPGA = FPGA_SRC; + + i = 0; + /* Move past the header */ + while ((FPGA_SRC[i] != 0xFF) && (i < FPGA_LEN)) + { + i++; + } + + // We've hit the 0xFF so move on to the next byte + // i++; + DPRINTF(("divas: FPGA Code starts at offset %d", i)); + + //--- put data onto the FPGA + for (;i<FPGA_LEN; i++) + { + //--- put byte onto FPGA + for (j=0; j<8; j++) + { + if (FPGA_SRC[i] &(0x80>>j)) baseval |= Mask_DIN; // write a hi + else baseval &=~Mask_DIN; // write a lo + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval | Mask_CCLK); // set CCLK hi + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); // set CCLK lo + } + } + + //--- add some additional startup clock cycles and check done pin + for (i=0; i<5; i++) + { + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval | Mask_CCLK); // set CCLK hi + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); // set CCLK lo + } + + UxPause(100); + + if (UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT) &Mask_DONE) + { + DPRINTF(("divas: FPGA download successful")); + } + else + { + DPRINTF(("divas: FPGA download failed - 0x%x", UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT))); + return -1; + } + +return 0; +} + diff --git a/drivers/isdn/eicon/idi.c b/drivers/isdn/eicon/idi.c new file mode 100644 index 000000000..f9b8a0ee3 --- /dev/null +++ b/drivers/isdn/eicon/idi.c @@ -0,0 +1,870 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.8 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* + * Core driver for Diva Server cards + * Implements the IDI interface + */ + +#include "idi.h" +#include "adapter.h" +#include "pc.h" +#include "pr_pc.h" +#include "sys.h" +#include "uxio.h" + +/* IDI request functions */ + +static void request(card_t *card, ENTITY *e); + +static void req_0(ENTITY *e) { request(&DivasCards[ 0], e); } +static void req_1(ENTITY *e) { request(&DivasCards[ 1], e); } +static void req_2(ENTITY *e) { request(&DivasCards[ 2], e); } +static void req_3(ENTITY *e) { request(&DivasCards[ 3], e); } +static void req_4(ENTITY *e) { request(&DivasCards[ 4], e); } +static void req_5(ENTITY *e) { request(&DivasCards[ 5], e); } +static void req_6(ENTITY *e) { request(&DivasCards[ 6], e); } +static void req_7(ENTITY *e) { request(&DivasCards[ 7], e); } +static void req_8(ENTITY *e) { request(&DivasCards[ 8], e); } +static void req_9(ENTITY *e) { request(&DivasCards[ 9], e); } +static void req_10(ENTITY *e) { request(&DivasCards[10], e); } +static void req_11(ENTITY *e) { request(&DivasCards[11], e); } +static void req_12(ENTITY *e) { request(&DivasCards[12], e); } +static void req_13(ENTITY *e) { request(&DivasCards[13], e); } +static void req_14(ENTITY *e) { request(&DivasCards[14], e); } +static void req_15(ENTITY *e) { request(&DivasCards[15], e); } + +IDI_CALL DivasIdiRequest[16] = +{ + &req_0, &req_1, &req_2, &req_3, + &req_4, &req_5, &req_6, &req_7, + &req_8, &req_9, &req_10, &req_11, + &req_12, &req_13, &req_14, &req_15 +}; + +#define PR_RAM ((struct pr_ram *)0) +#define RAM ((struct dual *)0) + +/*------------------------------------------------------------------*/ +/* local function prototypes */ +/*------------------------------------------------------------------*/ + +static byte isdn_rc(ADAPTER *, byte, byte, byte, word); +static byte isdn_ind(ADAPTER *, byte, byte, byte, PBUFFER *, byte, word); + +/* + * IDI related functions + */ + +static +ENTITY *entity_ptr(ADAPTER *a, byte e_no) +{ + card_t *card; + + card = a->io; + + return card->e_tbl[e_no].e; +} + +static +void CALLBACK(ADAPTER *a, ENTITY *e) +{ + card_t *card = a->io; + + if (card->log_types & DIVAS_LOG_IDI) + { + DivasLogIdi(card, e, FALSE); + } + + (*e->callback)(e); +} + +static +void *PTR_P(ADAPTER *a, ENTITY *e, void *P) +{ + return(P); +} + +static +void *PTR_R(ADAPTER *a, ENTITY *e) +{ + return((void*)e->R); +} + +static +void *PTR_X(ADAPTER *a, ENTITY *e) +{ + return((void*)e->X); +} + +static +void free_entity(ADAPTER *a, byte e_no) +{ + card_t *card; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_tbl[e_no].e = NULL; + card->e_count--; + + UxCardUnlock(card->hw, ipl); + + return; +} + +static +void assign_queue(ADAPTER * a, byte e_no, word ref) +{ + card_t *card; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_tbl[e_no].assign_ref = ref; + card->e_tbl[e_no].next = card->assign; + card->assign = e_no; + + UxCardUnlock(card->hw, ipl); + + return; +} + +static +byte get_assign(ADAPTER *a, word ref) +{ + card_t *card; + byte e_no; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + e_no = (byte)card->assign; + while (e_no) + { + if (card->e_tbl[e_no].assign_ref == ref) + { + break; + } + e_no = card->e_tbl[e_no].next; + } + + UxCardUnlock(card->hw, ipl); + + return e_no; +} + +static +void req_queue(ADAPTER * a, byte e_no) +{ + card_t *card; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_tbl[e_no].next = 0; + + if (card->e_head) + { + card->e_tbl[card->e_tail].next = e_no; + card->e_tail = e_no; + } + else + { + card->e_head = e_no; + card->e_tail = e_no; + } + + UxCardUnlock(card->hw, ipl); + + return; +} + +static +byte look_req(ADAPTER * a) +{ + card_t *card; + + card = a->io; + + return(card->e_head); +} + +static +void next_req(ADAPTER * a) +{ + card_t *card; + int ipl; + + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_head = card->e_tbl[card->e_head].next; + if (!card->e_head) + { + card->e_tail = 0; + } + + UxCardUnlock(card->hw, ipl); + + return; +} + + +/* + * IDI request function for active cards + */ + +static +void request(card_t *card, ENTITY *e) +{ + word *special_req; + int i; + int ipl; + + if (card->log_types & DIVAS_LOG_IDI) + { + DivasLogIdi(card, e, TRUE); + } + + if (!e->Req) + { + special_req = (word *) e; + + switch (*special_req) + { + case REQ_REMOVE: + return; + + case REQ_NAME: + for (i=0; i < DIM(card->cfg.name); i++) + { + ((struct get_name_s *) e)->name[i] = card->cfg.name[i]; + } + return; + + case REQ_SERIAL: + case REQ_XLOG: + DPRINTF(("IDI: attempted REQ_SERIAL or REQ_XLOG")); + return; + + default: + return; + } + } + + ipl = UxCardLock(card->hw); + + if (!(e->Id & 0x1f)) + { + DPRINTF(("IDI: ASSIGN req")); + + for (i = 1; i < card->e_max; i++) + { + if (!card->e_tbl[i].e) + { + break; + } + } + + if (i == card->e_max) + { + DPRINTF(("IDI: request all ids in use (IDI req ignored)")); + UxCardUnlock(card->hw, ipl); + e->Rc = OUT_OF_RESOURCES; + return; + } + + card->e_tbl[i].e = e; + card->e_count++; + + e->No = (byte) i; + e->More = 0; + e->RCurrent = 0xff; + } + else + { + i = e->No; + } + + if (e->More & XBUSY) + { + DPRINTF(("IDI: request - entity is busy")); + UxCardUnlock(card->hw, ipl); + return; + } + + e->More |= XBUSY; + e->More &= ~ XMOREF; + e->XCurrent = 0; + e->XOffset = 0; + + card->e_tbl[i].next = 0; + + if(card->e_head) + { + card->e_tbl[card->e_tail].next = i; + card->e_tail = i; + } + else + { + card->e_head = i; + card->e_tail = i; + } + + UxCardUnlock(card->hw, ipl); + + DivasScheduleRequestDpc(); + + return; +} + +static byte pr_ready(ADAPTER * a) +{ + byte ReadyCount; + + ReadyCount = (byte)(a->ram_in(a, &PR_RAM->ReqOutput) - + a->ram_in(a, &PR_RAM->ReqInput)); + + if(!ReadyCount) { + if(!a->ReadyInt) { + a->ram_inc(a, &PR_RAM->ReadyInt); + a->ReadyInt++; + } + } + return ReadyCount; +} + +/*------------------------------------------------------------------*/ +/* output function */ +/*------------------------------------------------------------------*/ + +void DivasOut(ADAPTER * a) +{ + byte e_no; + ENTITY * this = NULL; + BUFFERS *X; + word length; + word i; + word clength; + REQ * ReqOut; + byte more; + byte ReadyCount; + byte ReqCount; + byte Id; + + /* while a request is pending ... */ + e_no = look_req(a); + if(!e_no) + { + return; + } + + ReadyCount = pr_ready(a); + if(!ReadyCount) + { + DPRINTF(("IDI: card not ready for next request")); + return; + } + + ReqCount = 0; + while(e_no && ReadyCount) { + + next_req(a); + + this = entity_ptr(a, e_no); + +#ifdef USE_EXTENDED_DEBUGS + if ( !this ) + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DBG_FTL(("!A%d ==> NULL entity ptr - try to ignore", (int)io->ANum)) + e_no = look_req(a) ; + ReadyCount-- ; + continue ; + } + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DPRINTF(("IDI: >A%d Id=0x%x Req=0x%x", io->ANum, this->Id, this->Req)) + } +#else + DPRINTF(("IDI: >REQ=%x,Id=%x,Ch=%x",this->Req,this->Id,this->ReqCh)); +#endif + + /* get address of next available request buffer */ + ReqOut = (REQ *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextReq)]; + + /* now copy the data from the current data buffer into the */ + /* adapters request buffer */ + length = 0; + i = this->XCurrent; + X = PTR_X(a,this); + while(i<this->XNum && length<270) { + clength = MIN((word)(270-length),X[i].PLength-this->XOffset); + a->ram_out_buffer(a, + &ReqOut->XBuffer.P[length], + PTR_P(a,this,&X[i].P[this->XOffset]), + clength); + + length +=clength; + this->XOffset +=clength; + if(this->XOffset==X[i].PLength) { + this->XCurrent = (byte)++i; + this->XOffset = 0; + } + } + + a->ram_outw(a, &ReqOut->XBuffer.length, length); + a->ram_out(a, &ReqOut->ReqId, this->Id); + a->ram_out(a, &ReqOut->ReqCh, this->ReqCh); + + /* if its a specific request (no ASSIGN) ... */ + + if(this->Id &0x1f) { + + /* if buffers are left in the list of data buffers do */ + /* do chaining (LL_MDATA, N_MDATA) */ + + this->More++; + if(i<this->XNum && this->MInd) { + a->ram_out(a, &ReqOut->Req, this->MInd); + more = TRUE; + } + else { + this->More |=XMOREF; + a->ram_out(a, &ReqOut->Req, this->Req); + more = FALSE; + } + + /* if we did chaining, this entity is put back into the */ + /* request queue */ + + if(more) { + req_queue(a,this->No); + } + } + + /* else it's a ASSIGN */ + + else { + + /* save the request code used for buffer chaining */ + + this->MInd = 0; + if (this->Id==BLLC_ID) this->MInd = LL_MDATA; + if (this->Id==NL_ID || + this->Id==TASK_ID || + this->Id==MAN_ID + ) this->MInd = N_MDATA; + + /* send the ASSIGN */ + + this->More |=XMOREF; + a->ram_out(a, &ReqOut->Req, this->Req); + + /* save the reference of the ASSIGN */ + + assign_queue(a, this->No, a->ram_inw(a, &ReqOut->Reference)); + } + a->ram_outw(a, &PR_RAM->NextReq, a->ram_inw(a, &ReqOut->next)); + ReadyCount--; + ReqCount++; + + e_no = look_req(a); + } + + /* send the filled request buffers to the ISDN adapter */ + + a->ram_out(a, &PR_RAM->ReqInput, + (byte)(a->ram_in(a, &PR_RAM->ReqInput) + ReqCount)); + + /* if it is a 'unreturncoded' UREMOVE request, remove the */ + /* Id from our table after sending the request */ + if(this->Req==UREMOVE && this->Id) { + Id = this->Id; + e_no = a->IdTable[Id]; + free_entity(a, e_no); + a->IdTable[Id] = 0; + this->Id = 0; + } + +} + +/*------------------------------------------------------------------*/ +/* isdn interrupt handler */ +/*------------------------------------------------------------------*/ + +byte DivasDpc(ADAPTER * a) +{ + byte Count; + RC * RcIn; + IND * IndIn; + byte c; + byte RNRId; + byte Rc; + byte Ind; + + /* if return codes are available ... */ + if((Count = a->ram_in(a, &PR_RAM->RcOutput))) { + + DPRINTF(("IDI: #Rc=%x",Count)); + + /* get the buffer address of the first return code */ + RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextRc)]; + + /* for all return codes do ... */ + while(Count--) { + + if((Rc=a->ram_in(a, &RcIn->Rc))) { + + /* call return code handler, if it is not our return code */ + /* the handler returns 2 */ + /* for all return codes we process, we clear the Rc field */ + isdn_rc(a, + Rc, + a->ram_in(a, &RcIn->RcId), + a->ram_in(a, &RcIn->RcCh), + a->ram_inw(a, &RcIn->Reference)); + + a->ram_out(a, &RcIn->Rc, 0); + } + + /* get buffer address of next return code */ + RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &RcIn->next)]; + } + + /* clear all return codes (no chaining!) */ + a->ram_out(a, &PR_RAM->RcOutput ,0); + + /* call output function */ + DivasOut(a); + } + + /* clear RNR flag */ + RNRId = 0; + + /* if indications are available ... */ + if((Count = a->ram_in(a, &PR_RAM->IndOutput))) { + + DPRINTF(("IDI: #Ind=%x",Count)); + + /* get the buffer address of the first indication */ + IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextInd)]; + + /* for all indications do ... */ + while(Count--) { + + /* if the application marks an indication as RNR, all */ + /* indications from the same Id delivered in this interrupt */ + /* are marked RNR */ + if(RNRId && RNRId==a->ram_in(a, &IndIn->IndId)) { + a->ram_out(a, &IndIn->Ind, 0); + a->ram_out(a, &IndIn->RNR, TRUE); + } + else { + Ind = a->ram_in(a, &IndIn->Ind); + if(Ind) { + RNRId = 0; + + /* call indication handler, a return value of 2 means chain */ + /* a return value of 1 means RNR */ + /* for all indications we process, we clear the Ind field */ + c = isdn_ind(a, + Ind, + a->ram_in(a, &IndIn->IndId), + a->ram_in(a, &IndIn->IndCh), + &IndIn->RBuffer, + a->ram_in(a, &IndIn->MInd), + a->ram_inw(a, &IndIn->MLength)); + + if(c==1) { + DPRINTF(("IDI: RNR")); + a->ram_out(a, &IndIn->Ind, 0); + RNRId = a->ram_in(a, &IndIn->IndId); + a->ram_out(a, &IndIn->RNR, TRUE); + } + } + } + + /* get buffer address of next indication */ + IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &IndIn->next)]; + } + + a->ram_out(a, &PR_RAM->IndOutput, 0); + } + return FALSE; +} + +byte DivasTestInt(ADAPTER * a) +{ + return a->ram_in(a,(void *)0x3fe); +} + +void DivasClearInt(ADAPTER * a) +{ + a->ram_out(a,(void *)0x3fe,0); +} + +/*------------------------------------------------------------------*/ +/* return code handler */ +/*------------------------------------------------------------------*/ + +static +byte isdn_rc(ADAPTER * a, + byte Rc, + byte Id, + byte Ch, + word Ref) +{ + ENTITY * this; + byte e_no; + +#ifdef USE_EXTENDED_DEBUGS + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DPRINTF(("IDI: <A%d Id=0x%x Rc=0x%x", io->ANum, Id, Rc)) + } +#else + DPRINTF(("IDI: <RC(Rc=%x,Id=%x,Ch=%x)",Rc,Id,Ch)); +#endif + + /* check for ready interrupt */ + if(Rc==READY_INT) { + if(a->ReadyInt) { + a->ReadyInt--; + return 0; + } + return 2; + } + + /* if we know this Id ... */ + e_no = a->IdTable[Id]; + if(e_no) { + + this = entity_ptr(a,e_no); + + this->RcCh = Ch; + + /* if it is a return code to a REMOVE request, remove the */ + /* Id from our table */ + if(this->Req==REMOVE && Rc==OK) { + free_entity(a, e_no); + a->IdTable[Id] = 0; + this->Id = 0; +/**************************************************************/ + if ((this->More & XMOREC) > 1) { + this->More &= ~XMOREC; + this->More |= 1; + DPRINTF(("isdn_rc, Id=%x, correct More on REMOVE", Id)); + } + } + + if (Rc==OK_FC) { + this->Rc = Rc; + this->More = (this->More & (~XBUSY | XMOREC)) | 1; + this->complete = 0xFF; + CALLBACK(a, this); + return 0; + } + if(this->More &XMOREC) + this->More--; + + /* call the application callback function */ + if(this->More &XMOREF && !(this->More &XMOREC)) { + this->Rc = Rc; + this->More &=~XBUSY; + this->complete=0xff; + CALLBACK(a, this); + } + return 0; + } + + /* if it's an ASSIGN return code check if it's a return */ + /* code to an ASSIGN request from us */ + if((Rc &0xf0)==ASSIGN_RC) { + + e_no = get_assign(a, Ref); + + if(e_no) { + + this = entity_ptr(a,e_no); + + this->Id = Id; + + /* call the application callback function */ + this->Rc = Rc; + this->More &=~XBUSY; + this->complete=0xff; + CALLBACK(a, this); + + if(Rc==ASSIGN_OK) { + a->IdTable[Id] = e_no; + } + else + { + free_entity(a, e_no); + a->IdTable[Id] = 0; + this->Id = 0; + } + return 1; + } + } + return 2; +} + +/*------------------------------------------------------------------*/ +/* indication handler */ +/*------------------------------------------------------------------*/ + +static +byte isdn_ind(ADAPTER * a, + byte Ind, + byte Id, + byte Ch, + PBUFFER * RBuffer, + byte MInd, + word MLength) +{ + ENTITY * this; + word clength; + word offset; + BUFFERS *R; + +#ifdef USE_EXTENDED_DEBUGS + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DPRINTF(("IDI: <A%d Id=0x%x Ind=0x%x", io->ANum, Id, Ind)) + } +#else + DPRINTF(("IDI: <IND(Ind=%x,Id=%x,Ch=%x)",Ind,Id,Ch)); +#endif + + if(a->IdTable[Id]) { + + this = entity_ptr(a,a->IdTable[Id]); + + this->IndCh = Ch; + + /* if the Receive More flag is not yet set, this is the */ + /* first buffer of the packet */ + if(this->RCurrent==0xff) { + + /* check for receive buffer chaining */ + if(Ind==this->MInd) { + this->complete = 0; + this->Ind = MInd; + } + else { + this->complete = 1; + this->Ind = Ind; + } + + /* call the application callback function for the receive */ + /* look ahead */ + this->RLength = MLength; + + a->ram_look_ahead(a, RBuffer, this); + + this->RNum = 0; + CALLBACK(a, this); + + /* map entity ptr, selector could be re-mapped by call to */ + /* IDI from within callback */ + this = entity_ptr(a,a->IdTable[Id]); + + /* check for RNR */ + if(this->RNR==1) { + this->RNR = 0; + return 1; + } + + /* if no buffers are provided by the application, the */ + /* application want to copy the data itself including */ + /* N_MDATA/LL_MDATA chaining */ + if(!this->RNR && !this->RNum) { + return 0; + } + + /* if there is no RNR, set the More flag */ + this->RCurrent = 0; + this->ROffset = 0; + } + + if(this->RNR==2) { + if(Ind!=this->MInd) { + this->RCurrent = 0xff; + this->RNR = 0; + } + return 0; + } + /* if we have received buffers from the application, copy */ + /* the data into these buffers */ + offset = 0; + R = PTR_R(a,this); + do { + if(this->ROffset==R[this->RCurrent].PLength) { + this->ROffset = 0; + this->RCurrent++; + } + clength = MIN(a->ram_inw(a, &RBuffer->length)-offset, + R[this->RCurrent].PLength-this->ROffset); + if(R[this->RCurrent].P) { + a->ram_in_buffer(a, + &RBuffer->P[offset], + PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]), + clength); + } + offset +=clength; + this->ROffset +=clength; + } while(offset<(a->ram_inw(a, &RBuffer->length))); + + /* if it's the last buffer of the packet, call the */ + /* application callback function for the receive complete */ + /* call */ + if(Ind!=this->MInd) { + R[this->RCurrent].PLength = this->ROffset; + if(this->ROffset) this->RCurrent++; + this->RNum = this->RCurrent; + this->RCurrent = 0xff; + this->Ind = Ind; + this->complete = 2; + CALLBACK(a, this); + } + return 0; + } + return 2; +} diff --git a/drivers/isdn/eicon/idi.h b/drivers/isdn/eicon/idi.h new file mode 100644 index 000000000..0819665fe --- /dev/null +++ b/drivers/isdn/eicon/idi.h @@ -0,0 +1,146 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* External IDI interface */ + +#if !defined(IDI_H) +#define IDI_H + +#include "sys.h" + +/* typedefs for our data structures */ + +typedef struct get_name_s GET_NAME; +typedef struct entity_s ENTITY; +typedef struct buffers_s BUFFERS; + +/* IDI request/callback function pointer */ + +typedef void (* IDI_CALL)(ENTITY *); + +typedef struct { + word length; /* length of data/parameter field */ + byte P[270]; /* data/parameter field */ +} DBUFFER; + +#define REQ_NAME 0x0100 +#define BOARD_NAME_LENGTH 9 +struct get_name_s { + word command; /* command = 0x0100 */ + byte name[BOARD_NAME_LENGTH]; +}; + +#define REQ_REMOVE 0x0000 /* pointer to word which is 0 */ +#define REQ_SERIAL 0x0200 +struct get_serial_s { + word command; /* command = 0x0200 */ + dword serial; /* serial number */ +}; + +#define REQ_POSTCALL 0x0300 +struct postcall_s { + word command; /* command = 0x0300 */ + word dummy; /* not used */ + IDI_CALL callback; /* routine adress to call back */ + ENTITY *contxt; /* ptr to entity to use */ +}; + +#define REQ_XLOG 0x0400 /* structure is card dependent/defined locally */ + +struct buffers_s { + word PLength; + byte *P; +}; + +struct entity_s { + byte Req; /* pending request */ + byte Rc; /* return code received */ + byte Ind; /* indication received */ + byte ReqCh; /* channel of current Req */ + byte RcCh; /* channel of current Rc */ + byte IndCh; /* channel of current Ind */ + byte Id; /* ID used by this entity */ + byte GlobalId; /* reserved field */ + byte XNum; /* number of X-buffers */ + byte RNum; /* number of R-buffers */ + BUFFERS *X; /* pointer to X-buffer list */ + BUFFERS *R; /* pointer to R-buffer list */ + word RLength; /* length of current R-data */ + DBUFFER *RBuffer; /* buffer of current R-data */ + byte RNR; /* receive not ready flag */ + byte complete; /* receive complete status */ + IDI_CALL callback; + + word user[2]; + + /* fields used by the driver internally */ + byte No; /* entity number */ + byte reserved2; /* reserved field */ + byte More; /* R/X More flags */ + byte MInd; /* MDATA coding for this ID */ + byte XCurrent; /* current transmit buffer */ + byte RCurrent; /* current receive buffer */ + word XOffset; /* offset in x-buffer */ + word ROffset; /* offset in r-buffer */ +}; + +typedef struct { + byte type; + byte channels; + word features; + dword serial; + IDI_CALL request; +} DESCRIPTOR; + +extern void EtdM_DIDD_Read(DESCRIPTOR *, int *); + + /* descriptor type field coding */ +#define IDI_ADAPTER_S 1 +#define IDI_ADAPTER_PR 2 +#define IDI_ADAPTER_DIVA 3 +#define IDI_ADAPTER_MAESTRA 4 +#define IDI_ADAPTER_MAESTRAQ 5 +#define IDI_ADAPTER_MAESTRAP 6 +#define IDI_VADAPTER 0x40 +#define IDI_DRIVER 0x80 +#define IDI_DIMAINT 0xff + +/* feature bit mask values */ + +#define DI_VOICE 0x0 /* obsolete define */ +#define DI_FAX3 0x1 +#define DI_MODEM 0x2 +#define DI_POST 0x4 +#define DI_V110 0x8 +#define DI_V120 0x10 +#define DI_POTS 0x20 +#define DI_CODEC 0x40 +#define DI_MANAGE 0x80 +#define DI_V_42 0x0100 +#define DI_EXTD_FAX 0x0200 /* Extended FAX (ECM, 2D, T.6, Polling) */ + +#endif /* IDI_H */ diff --git a/drivers/isdn/eicon/kprintf.c b/drivers/isdn/eicon/kprintf.c new file mode 100644 index 000000000..3282b7fc5 --- /dev/null +++ b/drivers/isdn/eicon/kprintf.c @@ -0,0 +1,538 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.3 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* + * Source file for kernel interface to kernel log facility + */ + + +#include "sys.h" +#include <stdarg.h> +#undef MAX +#undef MIN + +#include <sys/types.h> +#include <sys/param.h> + +#include "divas.h" +#include "divalog.h" +#include "uxio.h" + +/* + * Implementation of printf and sprintf for kernel + */ + +#define MAX_BUFF (80) /* limit size of temporary buffers */ + +#define WRITE_CHAR(BUFFER, SIZE, C) \ + if (--(SIZE) < 0) { (BUFFER)--; *(BUFFER) = '\0'; return; } *(BUFFER)++ = (C) + + +/* + * convert a number to decimal ASCII + */ + +static +void do_decimal( char *temp, + int temp_len, + unsigned int value, + char *s) + +{ + int i; + + temp[0] = '\0'; + + for (i = 1; i < temp_len; i++) + { + temp[i] = (char) ((value % 10) + (int) '0'); + value /= 10; + } + + for (i = (temp_len - 1); temp[i] == '0'; i--) + { + ; + } + + if (i == 0) + { + i++; + } + + while (i >= 0) + { + *s++ = temp[i--]; + } + + return; +} + +/* + * convert a number to octal ASCII + */ + +static +void do_octal( char *temp, + unsigned int value, + char *s) + +{ + int i; + + temp[0] = '\0'; + + for (i = 1; i <= 11; i++) + { + temp[i] = (char) ((value & 07) + (int) '0'); + value >>= 3; + } + temp[11] &= '3'; + + for (i = 11; temp[i] == '0'; i--) + { + ; + } + + if (i == 0) + { + i++; + } + + while (i >= 0) + { + *s++ = temp[i--]; + } + + return; +} + +/* + * convert a number to hex ASCII + */ + +static +void do_hex( char *temp, + unsigned int value, + char *s) + +{ + int i; + static + char *dec_to_hex = "0123456789abcdef"; + + temp[0] = '\0'; + + for (i = 1; i <= 8; i++) + { + temp[i] = dec_to_hex[value & 0x0f]; + value >>= 4; + } + + for (i = 8; temp[i] == '0'; i--) + { + ; + } + + if (i == 0) + { + i++; + } + + while (i >= 0) + { + *s++ = temp[i--]; + } + + return; +} + +/* + * convert a buffer to ASCII HEX + */ + +static +void do_buffer( char *buffer, + int length, + char *s) + +{ + static + char hex_char [] = "0123456789abcdef"; + char *b = buffer; + int hex_byte; + int nybble; + + length = (length >= ((MAX_BUFF / 3) + 1)) ? (MAX_BUFF / 3) : length; + + while (length) + { + hex_byte = (int) *b++; + nybble = (hex_byte >> 4) & 0xf; + *s++ = hex_char[nybble]; + nybble = hex_byte & 0xf; + *s++ = hex_char[nybble]; + *s++ = ' '; + length--; + } + *s = '\0'; + + return; +} + +/* + * Body of sprintf function: behaves just like standard sprintf, except we + * have an extra argument (buffer size) which we use to ensure we don't + * overflow + */ + +void Divas_vsprintf( char *buffer, + int size, + char *fmt, + va_list argptr) + +{ + char c; /* single character buffer */ + int i; /* handy scratch counter */ + int f; /* format character (after %) */ + char *str; /* pointer into string */ + char temp[20]; /* temp buffer used in printing numbers */ + char string[MAX_BUFF]; /* output from number conversion */ + int length; /* length of string "str" */ + char fill; /* fill character ' ' or '0' */ + boolean_t leftjust; /* TRUE if left justified, else right justified */ + int fmax, fmin; /* field specifiers % MIN . MAX s */ + int leading; /* number of leading/trailing fill characters */ + char sign; /* set to '-' for negative decimals */ + int number; /* numeric argument */ + + char *buff_ptr; /* pointer to user's buffer of hex data */ + int buff_len; /* length of hex data */ + + /* make sure we have somthing to write into */ + + if ((!buffer) || (size <= 0)) + { + return; + } + + while (TRUE) + { + /* echo characters until end or '%' encountered */ + + while ((c = *fmt++) != '%') + { + if (!c) + { + *buffer = '\0'; + return; + } + WRITE_CHAR(buffer, size, c); + } + + /* echo %% as % */ + + if (*fmt == '%') + { + WRITE_CHAR(buffer, size, *fmt); + continue; + } + + /* %- turns on left-justify */ + + if ((leftjust = (boolean_t) ((*fmt == '-') ? TRUE : FALSE))) + { + fmt++; + } + + /* %0 turns on zero filling */ + + if (*fmt == '0') + { + fill = '0'; + } + else + { + fill = ' '; + } + + /* minium field width specifier for %d, u, x, c, s */ + + fmin = 0; + + if (*fmt == '*') + { + fmin = va_arg(argptr, int); + fmt++; + } + else + { + while ('0' <= *fmt && *fmt <= '9') + { + fmin = (fmin * 10) + (*fmt++ - '0'); + } + } + + /* maximum string width specifier for %s */ + + fmax = 0; + + if (*fmt == '.') + { + if (*(++fmt) == '*') + { + fmax = va_arg(argptr, int); + fmt++; + } + else + { + while ('0' <= *fmt && *fmt <= '9') + { + fmax = (fmax * 10) + (*fmt++ - '0'); + } + } + } + + /* skip over 'l' option (ints are assumed same size as longs) */ + + if (*fmt == 'l') + { + fmt++; + } + + /* get the format chacater */ + + if (!(f = *fmt++)) + { + WRITE_CHAR(buffer, size, '%'); + *buffer = '\0'; + return; + } + + sign = '\0'; /* sign == '-' for negative decimal */ + + str = string; + + switch (f) + { + case 'c' : + string[0] = (char) va_arg(argptr, int); + string[1] = '\0'; + fmax = 0; + fill = ' '; + break; + + case 's' : + str = va_arg(argptr, char *); + fill = ' '; + break; + + case 'D' : + case 'd' : + number = va_arg(argptr, int); + if (number < 0) + { + sign = '-'; + number = -number; + } + do_decimal(temp, DIM(temp), (unsigned int) number, str); + fmax = 0; + break; + + case 'U' : + case 'u' : + number = va_arg(argptr, int); + do_decimal(temp, DIM(temp), (unsigned int) number, str); + fmax = 0; + break; + + case 'O' : + case 'o' : + number = va_arg(argptr, int); + do_octal(temp, (unsigned int) number, str); + fmax = 0; + break; + + case 'X' : + case 'x' : + number = va_arg(argptr, int); + do_hex(temp, (unsigned int) number, str); + fmax = 0; + break; + + case 'H' : + case 'h' : + buff_ptr = va_arg(argptr, char *); + buff_len = va_arg(argptr, int); + do_buffer(buff_ptr, buff_len, str); + fmax = 0; + break; + + default : + WRITE_CHAR(buffer, size, ((char) f)); + break; + } + + /* get the length of the string */ + + length = 0; + while (str[length]) + { + length++; + } + + /* make sure we have fmax and fmin values that are O.K. */ + + if (fmin > DIM(string) || fmin < 0) + { + fmin = 0; + } + + if (fmax > DIM(string) || fmax < 0) + { + fmax = 0; + } + + /* figure out how many leading characters thare are */ + + leading = 0; + + if (fmax || fmin) + { + if (fmax) + { + if (length > fmax) + { + length = fmax; + } + } + + if (fmin) + { + leading = fmin - length; + } + + if (sign == '-') + { + leading--; + } + } + + /* output sign now, if fill is numeric */ + + if (sign == '-' && fill == '0') + { + WRITE_CHAR(buffer, size, '-'); + } + + /* if right justified, output fill characters */ + + if (!leftjust) + { + for (i = 0; i < leading; i++) + { + WRITE_CHAR(buffer, size, fill); + } + } + + /* output sign now, if fill is spaces */ + + if (sign == '-' && fill == ' ') + { + WRITE_CHAR(buffer, size, '-'); + } + + /* now the actual value */ + + for (i = 0; i < length; i++) + { + WRITE_CHAR(buffer, size, str[i]); + } + + /* if left justified, fill out with the fill character */ + + if (leftjust) + { + for (i = 0; i < leading; i++) + { + WRITE_CHAR(buffer, size, fill); + } + } + } +} + +/* + * sprintf for kernel + * + * call our vsprintf assuming user has a big buffer.... + */ + +void DivasSprintf(char *buffer, char *fmt, ...) + +{ + va_list argptr; /* pointer to additional args */ + + va_start(argptr, fmt); + + Divas_vsprintf(buffer, 1024, fmt, argptr); + + va_end(argptr); + + return; +} + +void DivasPrintf(char *fmt, ...) + +{ + klog_t log; /* log entry buffer */ + + va_list argptr; /* pointer to additional args */ + + va_start(argptr, fmt); + + /* clear log entry */ + + bzero((caddr_t) &log, sizeof(klog_t)); + + log.card = -1; + log.type = KLOG_TEXT_MSG; + + /* time stamp the entry */ + + log.time_stamp = UxTimeGet(); + + /* call vsprintf to format the user's information */ + + Divas_vsprintf(log.buffer, DIM(log.buffer), fmt, argptr); + + va_end(argptr); + + /* send to the log streams driver and return */ + + DivasLogAdd(&log, sizeof(klog_t)); + + return; +} diff --git a/drivers/isdn/eicon/lincfg.c b/drivers/isdn/eicon/lincfg.c new file mode 100644 index 000000000..3d2a8bfb1 --- /dev/null +++ b/drivers/isdn/eicon/lincfg.c @@ -0,0 +1,410 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.9 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include <linux/fs.h> +#undef N_DATA /* Because we have our own definition */ + +#include <asm/segment.h> +#include <asm/io.h> + +#include "sys.h" +#include "idi.h" +#include "constant.h" +#include "divas.h" +#undef ID_MASK +#include "pc.h" +#include "pr_pc.h" + +#include "adapter.h" +#include "uxio.h" + +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/ioport.h> + +#define HW_ID_EICON_PCI 0x1133 +#define HW_ID_DIVA_SERVER_P 0xE014 +#define HW_ID_DIVA_SERVER_B_ST 0xE010 +#define HW_ID_DIVA_SERVER_B_U 0xE013 +#define HW_ID_DIVA_SERVER_Q 0xE012 + +struct file_operations Divas_fops; +int Divas_major; + +extern int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, + unsigned int command, unsigned long arg); +extern unsigned int do_poll(struct file *pFile, struct poll_table_struct *pPollTable); +extern ssize_t do_read(struct file *pFile, char *pUserBuffer, size_t BufferSize, loff_t *pOffset); +extern int do_open(struct inode *, struct file *); +extern int do_release(struct inode *, struct file *); + +int FPGA_Done=0; + +int DivasCardsDiscover(void) +{ + word wNumCards = 0, wDeviceIndex = 0; + byte byBus, byFunc; + word wPCIConsultation, PCItmp; + dword j, i; + unsigned int PCIserial; + dia_card_t Card; + byte *b; + + while (wDeviceIndex < 10) + { + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_Q, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + + dword dwRAM, dwDivasIOBase, dwCFG, dwCTL; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server 4BRI Found\n"); + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2,(unsigned int *) &dwRAM); + dwRAM &= 0xFFC00000; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1,(unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFF00; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_0,(unsigned int *) &dwCFG); + dwCFG &= 0xFFFFFF00; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_3,(unsigned int *) &dwCTL); + dwCTL &= 0xFFFFE000; + + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + /* Retrieve the serial number */ + + pcibios_write_config_word(byBus,byFunc,0x4E,0x00FC); + + for (j=0, PCItmp=0; j<10000 && !PCItmp; j++) + { + pcibios_read_config_word(byBus,byFunc,0x4E, &PCItmp); + PCItmp &= 0x8000; // extract done flag + } + + pcibios_read_config_dword(byBus,byFunc,0x50, &PCIserial); + + + Card.memory[DIVAS_RAM_MEMORY] = ioremap(dwRAM, 0x400000); + Card.memory[DIVAS_CTL_MEMORY] = ioremap(dwCTL, 0x2000); + Card.memory[DIVAS_CFG_MEMORY] = ioremap(dwCFG, 0x100); + Card.io_base=dwDivasIOBase; + + Card.irq = byIRQ; + + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_Q; + Card.bus_type = DIA_BUS_TYPE_PCI; + + FPGA_Done = 0; + + /* Create four virtual card structures as we want to treat + the 4Bri card as 4 Bri cards*/ + for(i=0;i<4;i++) + { + + b=Card.memory[DIVAS_RAM_MEMORY]; + b+=(MQ_PROTCODE_OFFSET) * (i==0?0:1); + DPRINTF(("divas: offset = 0x%x", i* MQ_PROTCODE_OFFSET)); + Card.memory[DIVAS_RAM_MEMORY]=b; + + b = Card.memory[DIVAS_RAM_MEMORY]; + b += MQ_SM_OFFSET; + Card.memory[DIVAS_SHARED_MEMORY] = b; + + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + + + /* Fill in Name */ + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'Q'; + Card.name[6] = '0' + i; + Card.name[7] = '\0'; + + Card.serial = PCIserial; + + Card.card_id = wNumCards; + + if (DivasCardNew(&Card) != 0) + { + // Force for loop to terminate + i = 4; + continue; + } + wNumCards++; + + }//for + } + wDeviceIndex++; + } + + wDeviceIndex = 0; + + while (wDeviceIndex < 10) + { + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_B_ST, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + dword dwPLXIOBase, dwDivasIOBase; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server BRI (S/T) Found\n"); + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase); + dwPLXIOBase &= 0xFFFFFF80; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFFFC; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + + Card.card_id = wNumCards; + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_B; + Card.bus_type = DIA_BUS_TYPE_PCI; + Card.irq = byIRQ; + Card.reset_base = dwPLXIOBase; + Card.io_base = dwDivasIOBase; + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'B'; + Card.name[6] = '\0'; + + if (check_region(Card.io_base, 0x20)) + { + printk(KERN_WARNING "Divas: DIVA I/O Base already in use 0x%x-0x%x\n", Card.io_base, Card.io_base + 0x1F); + wDeviceIndex++; + continue; + } + + if (check_region(Card.reset_base, 0x80)) + { + printk(KERN_WARNING "Divas: PLX I/O Base already in use 0x%x-0x%x\n", Card.reset_base, Card.reset_base + 0x7F); + wDeviceIndex++; + continue; + } + + if (DivasCardNew(&Card) != 0) + { + wDeviceIndex++; + continue; + } + wNumCards++; + } + + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_B_U, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + dword dwPLXIOBase, dwDivasIOBase; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server BRI (U) Found\n"); + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase); + dwPLXIOBase &= 0xFFFFFF80; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFFFC; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + + Card.card_id = wNumCards; + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_B; + Card.bus_type = DIA_BUS_TYPE_PCI; + Card.irq = byIRQ; + Card.reset_base = dwPLXIOBase; + Card.io_base = dwDivasIOBase; + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'B'; + Card.name[6] = '\0'; + + if (check_region(Card.io_base, 0x20)) + { + printk(KERN_WARNING "Divas: DIVA I/O Base already in use 0x%x-0x%x\n", Card.io_base, Card.io_base + 0x1F); + wDeviceIndex++; + continue; + } + + if (check_region(Card.reset_base, 0x80)) + { + printk(KERN_WARNING "Divas: PLX I/O Base already in use 0x%x-0x%x\n", Card.reset_base, Card.reset_base + 0x7F); + wDeviceIndex++; + continue; + } + + if (DivasCardNew(&Card) != 0) + { + wDeviceIndex++; + continue; + } + wNumCards++; + } + + wDeviceIndex++; + } + + wDeviceIndex = 0; + + while (wDeviceIndex < 10) + { + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_P, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + dword dwRAM, dwREG, dwCFG; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server PRI Found\n"); + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_0, (unsigned int *) &dwRAM); + dwRAM &= 0xFFFFF000; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwREG); + dwREG &= 0xFFFFF000; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_4, (unsigned int *) &dwCFG); + dwCFG &= 0xFFFFF000; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + + Card.memory[DIVAS_RAM_MEMORY] = ioremap(dwRAM, 0x10000); + Card.memory[DIVAS_REG_MEMORY] = ioremap(dwREG, 0x4000); + Card.memory[DIVAS_CFG_MEMORY] = ioremap(dwCFG, 0x1000); + Card.memory[DIVAS_SHARED_MEMORY] = Card.memory[DIVAS_RAM_MEMORY] + DIVAS_SHARED_OFFSET; + +/* pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase); + dwPLXIOBase &= 0xFFFFFFFc; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFF80; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); +*/ + Card.card_id = wNumCards; + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER; + Card.bus_type = DIA_BUS_TYPE_PCI; + Card.irq = byIRQ; +/* Card.reset_base = dwPLXIOBase; + Card.io_base = dwDivasIOBase;*/ + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'P'; + Card.name[6] = '\0'; + + if (DivasCardNew(&Card) != 0) + { + wDeviceIndex++; + continue; + } + wNumCards++; + } + + wDeviceIndex++; + } + + + printk(KERN_INFO "Divas: %d cards detected\n", wNumCards); + + if(wNumCards == 0) + { + return -1; + } + + Divas_fops.ioctl = do_ioctl; + Divas_fops.poll = do_poll; + Divas_fops.read = do_read; + Divas_fops.open = do_open; + Divas_fops.release = do_release; + + Divas_major = register_chrdev(0, "Divas", &Divas_fops); + + if (Divas_major < 0) + { + printk(KERN_WARNING "Divas: Unable to register character driver\n"); + return -1; + } + + return 0; +} + +/* Error return -1 */ +int DivasConfigGet(dia_card_t *card) +{ + /* Retrieve Config from O/S? Not in Linux */ + return 0; +} + +dia_config_t *DivasConfig(card_t *card, dia_config_t *config) +{ + /* If config retrieved from OS then copy the data into a dia_config_t structure here + and return the pointer here. If the config 'came from above' then just + + return config; + */ + + return config; +} + diff --git a/drivers/isdn/eicon/linchr.c b/drivers/isdn/eicon/linchr.c new file mode 100644 index 000000000..782429523 --- /dev/null +++ b/drivers/isdn/eicon/linchr.c @@ -0,0 +1,274 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.12 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include <linux/kernel.h> +#include <linux/poll.h> +#include <linux/fs.h> +#include <linux/malloc.h> + +#undef N_DATA + +#include "adapter.h" +#include "divas.h" +#include "divalog.h" + +extern int DivasCardNext; +void UxPause(long ms); +void bcopy(void *pSource, void *pDest, dword dwLength); +int DivasGetMem(mem_block_t *); + +#define DIA_IOCTL_UNLOCK 12 +void UnlockDivas(void); + +int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, + unsigned int command, unsigned long arg) +{ + dia_load_t *pDivaLoad; + dia_start_t *pDivaStart; + dia_config_t *pDivaConfig; + dia_log_t *pDivaLog; + byte *pUserCards, card_i; + word wCardNum; + mem_block_t *mem_block; + + switch (command) + { + case DIA_IOCTL_CONFIG: + pDivaConfig = (dia_config_t *) arg; + + if (!verify_area(VERIFY_READ, pDivaConfig, sizeof(dia_config_t))) + { + DivasCardConfig(pDivaConfig); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete CONFIG ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_DETECT: + pUserCards = (byte *) arg; + + if (!verify_area(VERIFY_WRITE, pUserCards, 20)) + { + put_user(DivasCardNext, pUserCards++); + + for (card_i=1; card_i < 20; card_i++) + { + put_user((byte) DivasCards[card_i - 1].cfg.card_type, pUserCards++); + } + } + else + { + printk(KERN_WARNING "Divas: Unable to complete DETECT ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_START: + pDivaStart = (dia_start_t *) arg; + + if (!verify_area(VERIFY_READ, pDivaStart, sizeof(dia_start_t))) + { + return DivasCardStart(pDivaStart->card_id); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete START ioctl (verify area failed)\n"); + return -1; + } + + + case DIA_IOCTL_FLAVOUR: + return 0; + + case DIA_IOCTL_LOAD: + pDivaLoad = (dia_load_t *) arg; + if (!verify_area(VERIFY_READ, pDivaLoad->code,pDivaLoad->length)) + { + if (DivasCardLoad(pDivaLoad)) + { + printk(KERN_WARNING "Divas: Error loading DIVA Server adapter\n"); + return -EINVAL; + } + } + else + { + printk(KERN_WARNING "Divas: Error in LOAD parameters (verify failed)\n"); + return -EINVAL; + } + return 0; + + case DIA_IOCTL_LOG: + pDivaLog = (dia_log_t *) arg; + + if (!verify_area(VERIFY_READ, pDivaLog, sizeof(dia_log_t))) + { + DivasLog(pDivaLog); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete LOG ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_XLOG_REQ: + + if (!verify_area(VERIFY_READ, (void *)arg, sizeof(word))) + { + wCardNum = * (word *) arg; + DivasXlogReq(wCardNum); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete XLOG_REQ ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_GET_NUM: + + if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(int))) + { + * (int *) arg = DivasCardNext; + } + else + { + printk(KERN_WARNING "Divas: Unable to complete GET_NUM ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_GET_LIST: + DPRINTF(("divas: DIA_IOCTL_GET_LIST")); + + if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(dia_card_list_t))) + { + DivasGetList((dia_card_list_t *)arg); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete GET_LIST ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_GET_MEM: + mem_block = (mem_block_t *) arg; + + if (!verify_area(VERIFY_WRITE, mem_block, sizeof(mem_block_t))) + { + DivasGetMem(mem_block); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete GET_MEM ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_UNLOCK: + UnlockDivas(); + return 0; + + default: + printk(KERN_WARNING "Divas: Unknown IOCTL Received by DIVA Server Driver(%d)\n", command); + return -EINVAL; + } + + return -EINVAL; +} + +unsigned int do_poll(struct file *pFile, struct poll_table_struct *pPollTable) +{ + word wMask = 0; + + if (!DivasLogFifoEmpty()) + { + wMask |= POLLIN | POLLRDNORM; + } + + return wMask; +} + +ssize_t do_read(struct file *pFile, char *pUserBuffer, size_t BufferSize, loff_t *pOffset) +{ + klog_t *pClientLogBuffer = (klog_t *) pUserBuffer; + klog_t *pHeadItem; + + if (BufferSize < sizeof(klog_t)) + { + printk(KERN_WARNING "Divas: Divalog buffer specifed a size that is too small (%d - %d required)\n", + BufferSize, sizeof(klog_t)); + return 0; + } + + pHeadItem = (klog_t *) DivasLogFifoRead(); + + if (pHeadItem) + { + bcopy(pHeadItem, pClientLogBuffer, sizeof(klog_t)); + kfree(pHeadItem); + return sizeof(klog_t); + } + + return 0; +} +int private_usage_count; +extern void mod_inc_use_count(void); +extern void mod_dec_use_count(void); + +int do_open(struct inode *pInode, struct file *pFile) +{ +#if defined(MODULE) + mod_inc_use_count(); + private_usage_count++; +#endif + return 0; +} + +int do_release(struct inode *pInode, struct file *pFile) +{ +#if defined(MODULE) + mod_dec_use_count(); + private_usage_count--; +#endif + return 0; +} + +void UnlockDivas(void) +{ + while (private_usage_count > 0) + { + private_usage_count--; +#if defined(MODULE) + mod_dec_use_count(); +#endif + } +} diff --git a/drivers/isdn/eicon/linio.c b/drivers/isdn/eicon/linio.c new file mode 100644 index 000000000..74c599069 --- /dev/null +++ b/drivers/isdn/eicon/linio.c @@ -0,0 +1,750 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.16 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#define N_DATA + +#include <asm/io.h> +#include <asm/system.h> +#include <linux/malloc.h> +#include <linux/pci.h> +#include <linux/delay.h> +#undef N_DATA + +#include "uxio.h" + +static +int log_on=0; + +int Divasdevflag = 0; + +//spinlock_t diva_lock = SPIN_LOCK_UNLOCKED; + +static +ux_diva_card_t card_pool[MAX_CARDS]; + +void UxPause(long int ms) +{ + int timeout = jiffies + ((ms * HZ) / 1000); + + while (time_before(jiffies, timeout)); +} + +int UxCardHandleGet(ux_diva_card_t **card, dia_card_t *cfg) +{ + int i; + ux_diva_card_t *c; + + if (cfg->bus_type != DIA_BUS_TYPE_PCI) + { + DPRINTF(("divas hw: type not PCI (%d)", cfg->bus_type)); + return -1; + } + + for (i = 0; (i < DIM(card_pool)) && (card_pool[i].in_use); i++) + { + ; + } + + if (i == DIM(card_pool)) + { + DPRINTF(("divas hw: card_pool exhausted")); + return -1; + } + + c = *card = &card_pool[i]; + + switch (cfg->bus_type) + { + case DIA_BUS_TYPE_PCI: + c->bus_num = cfg->bus_num; + c->func_num = cfg->func_num; + c->io_base = cfg->io_base; + c->reset_base = cfg->reset_base; + c->card_type = cfg->card_type; + c->mapped = NULL; + c->slot = cfg->slot; + c->irq = (int) cfg->irq; + c->pDRAM = cfg->memory[DIVAS_RAM_MEMORY]; + c->pDEVICES = cfg->memory[DIVAS_REG_MEMORY]; + c->pCONFIG = cfg->memory[DIVAS_CFG_MEMORY]; + c->pSHARED = cfg->memory[DIVAS_SHARED_MEMORY]; + c->pCONTROL = cfg->memory[DIVAS_CTL_MEMORY]; + + /* c->bus_type = DIA_BUS_TYPE_PCI; + c->bus_num = cfg->bus_num & 0x3f; + c->slot = cfg->slot; + c->irq = (int) cfg->irq; + c->int_priority = (int) cfg->int_priority; + c->card_type = cfg->card_type; + c->io_base = cfg->io_base; + c->reset_base = cfg->reset_base; + c->pDRAM = cfg->memory[DIVAS_RAM_MEMORY]; + c->pDEVICES = cfg->memory[DIVAS_REG_MEMORY]; + c->pCONFIG = cfg->memory[DIVAS_CFG_MEMORY]; + c->pSHARED = cfg->memory[DIVAS_SHARED_MEMORY]; + DPRINTF(("divas hw: pDRAM is 0x%x", c->pDRAM)); + DPRINTF(("divas hw: pSHARED is 0x%x", c->pSHARED)); + DPRINTF(("divas hw: pCONFIG is 0x%x", c->pCONFIG)); + c->cm_key = cm_getbrdkey("Divas", cfg->card_id);*/ + break; + default: + break; + } + + c->in_use = TRUE; + + return 0; +} + +void UxCardHandleFree(ux_diva_card_t *card) +{ + card->in_use = FALSE; +} + + +#define PLX_IOBASE 0 +#define DIVAS_IOBASE 1 +void *UxCardMemAttach(ux_diva_card_t *card, int id) +{ + if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER) + { + switch (id) + { + case DIVAS_SHARED_MEMORY: + card->mapped = card->pSHARED; + return card->pSHARED; + break; + case DIVAS_RAM_MEMORY: + card->mapped = card->pDRAM; + return card->pDRAM; + break; + case DIVAS_REG_MEMORY: + card->mapped = card->pDEVICES; + return card->pDEVICES; + break; + case DIVAS_CFG_MEMORY: + card->mapped = card->pCONFIG; + return card->pCONFIG; + break; + default: + ASSERT(FALSE); + card->mapped = NULL; + return (void *) 0; + } + } + else if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + switch (id) + { + case PLX_IOBASE: + return (void *) card->reset_base; + break; + case DIVAS_IOBASE: + return (void *) card->io_base; + break; + default: + ASSERT(FALSE); + return 0; + } + } + + else if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + switch (id) + { + case DIVAS_SHARED_MEMORY: + card->mapped = card->pSHARED; + return card->pSHARED; + break; + case DIVAS_RAM_MEMORY: + card->mapped = card->pDRAM; + return card->pDRAM; + break; + case DIVAS_REG_MEMORY: + card->mapped = (void *) card->io_base; + return (void *) card->io_base; + break; + case DIVAS_CTL_MEMORY: + card->mapped = card->pCONTROL; + return card->pCONTROL; + break; + default: + // ASSERT(FALSE); + DPRINTF(("divas: Trying to attach to mem %d", id)); + card->mapped = NULL; + return (void *) 0; + } + } else + DPRINTF(("divas: Tried to attach to unknown card")); + + /* Unknown card type */ + return NULL; +} + +void UxCardMemDetach(ux_diva_card_t *card, void *address) +{ + return; // Just a place holder. No un-mapping done. +} + +void UxCardLog(int turn_on) +{ + log_on = turn_on; +} + +/* + * Control Register I/O Routines to be performed on Attached I/O ports + */ + +void UxCardPortIoOut(ux_diva_card_t *card, void *AttachedBase, int offset, byte the_byte) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + outb(the_byte, base); +} + +void UxCardPortIoOutW(ux_diva_card_t *card, void *AttachedBase, int offset, word the_word) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + outw(the_word, base); +} + +void UxCardPortIoOutD(ux_diva_card_t *card, void *AttachedBase, int offset, dword the_dword) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + outl(the_dword, base); +} + +byte UxCardPortIoIn(ux_diva_card_t *card, void *AttachedBase, int offset) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + return inb(base); +} + +word UxCardPortIoInW(ux_diva_card_t *card, void *AttachedBase, int offset) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + return inw(base); +} + +/* + * Memory mapped card I/O functions + */ + +byte UxCardMemIn(ux_diva_card_t *card, void *address) +{ + byte b; + volatile byte* t = (byte*)address; + + b = *t; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: read 0x%02x from 0x%x (memory mapped)", b & 0xff, a)); + } + + return(b); +} + +word UxCardMemInW(ux_diva_card_t *card, void *address) +{ + word w; + volatile word* t = (word*)address; + + w = *t; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: read 0x%04x from 0x%x (memory mapped)", w & 0xffff, a)); + } + + return (w); +} + +dword UxCardMemInD(ux_diva_card_t *card, void *address) +{ + dword dw; + volatile dword* t = (dword*)address; + + dw = *t; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: read 0x%08x from 0x%x (memory mapped)", dw, a)); + } + + return (dw); +} + +void UxCardMemInBuffer(ux_diva_card_t *card, void *address, void *buffer, int length) +{ + volatile byte *pSource = address; + byte *pDest = buffer; + + while (length--) + { + *pDest++ = *pSource++; + } + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + pDest = buffer; + DPRINTF(("divas hw: read %02x %02x %02x %02x %02x %02x %02x %02x from 0x%x (memory mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + a)); + } + + return; +} + +void UxCardMemOut(ux_diva_card_t *card, void *address, byte data) +{ + volatile byte* t = (byte*)address; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: wrote 0x%02x to 0x%x (memory mapped)", data & 0xff, a)); + } + + *t = data; + + return; +} + +void UxCardMemOutW(ux_diva_card_t *card, void *address, word data) +{ + volatile word* t = (word*)address; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: wrote 0x%04x to 0x%x (memory mapped)", data & 0xffff, a)); + } + + *t = data; + return; +} + +void UxCardMemOutD(ux_diva_card_t *card, void *address, dword data) +{ + volatile dword* t = (dword*)address; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: wrote 0x%08x to 0x%x (memory mapped)", data, a)); + } + + *t = data; + return; +} + +void UxCardMemOutBuffer(ux_diva_card_t *card, void *address, void *buffer, int length) +{ + byte *pSource = buffer; + byte *pDest = address; + + while (length--) + { + *pDest++ = *pSource++; + } + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + pDest = buffer; + DPRINTF(("divas hw: wrote %02x %02x %02x %02x %02x %02x %02x %02x to 0x%x (memory mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + a)); + } + + return; +} + +/* + * Memory mapped card I/O functions + */ + +byte UxCardIoIn(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address) + +{ + byte the_byte; + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + + the_byte = inb(card->io_base); + + if (log_on) + { + DPRINTF(("divas hw: read 0x%02x from 0x%x (I/O mapped)", + the_byte & 0xff, address)); + } + + return the_byte; +} + +word UxCardIoInW(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address) + +{ + word the_word; + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + the_word = inw(card->io_base); + + if (log_on) + { + DPRINTF(("divas hw: read 0x%04x from 0x%x (I/O mapped)", + the_word & 0xffff, address)); + } + + return the_word; +} + +dword UxCardIoInD(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address) + +{ + dword the_dword; + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + the_dword = inl(card->io_base); + + if (log_on) + { + DPRINTF(("divas hw: read 0x%08x from 0x%x (I/O mapped)", + the_dword, address)); + } + + return the_dword; +} + +void UxCardIoInBuffer(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, void *buffer, int length) + +{ + byte *pSource = address; + byte *pDest = buffer; + + if ((word) (dword) address & 0x1) + { + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pSource, card->io_base + 4); + *pDest = (byte) inb(card->io_base); + pDest++; + pSource++; + length--; + if (!length) + { + return; + } + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pSource, card->io_base + 4); + insw(card->io_base, (word *)pDest,length%2 ? (length+1)>>1 : length>>1); + + if (log_on) + { + pDest = buffer; + DPRINTF(("divas hw: read %02x %02x %02x %02x %02x %02x %02x %02x from 0x%x (I/O mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + address)); + } + + return; +} + +/* Output */ + +void UxCardIoOut(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, byte data) +{ + if (log_on) + { + DPRINTF(("divas hw: wrote 0x%02x to 0x%x (I/O mapped)", + data & 0xff, address)); + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + outb((byte) data & 0xFF, card->io_base); + + return; +} + +void UxCardIoOutW(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, word data) +{ + if (log_on) + { + DPRINTF(("divas hw: wrote 0x%04x to 0x%x (I/O mapped)", + data & 0xffff, address)); + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + outw((word) data & 0xFFFF, card->io_base); + + return; +} + +void UxCardIoOutD(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, dword data) +{ + if (log_on) + { + DPRINTF(("divas hw: wrote 0x%08x to 0x%x (I/O mapped)", data, address)); + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + outl((dword) data & 0xFFFFFFFF, card->io_base); + + return; +} + +void UxCardIoOutBuffer(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, void *buffer, int length) + +{ + byte *pSource = buffer; + byte *pDest = address; + + if ((word) (dword) address & 1) + { + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pDest, card->io_base + 4); + outb(*pSource, card->io_base); + pSource++; + pDest++; + length--; + if (!length) + { + return; + } + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pDest, card->io_base + 4); + outsw(card->io_base, (word *)pSource, length%2 ? (length+1)>>1 : length>>1); + + if (log_on) + { + pDest = buffer; + DPRINTF(("divas hw: wrote %02x %02x %02x %02x %02x %02x %02x %02x to 0x%x (I/O mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + address)); + } + + return; +} + +void Divasintr(int arg, void *unused, struct pt_regs *unused_regs) +{ + int i; + card_t *card = NULL; + ux_diva_card_t *ux_ref = NULL; + + for (i = 0; i < DivasCardNext; i++) + { + + if (arg == DivasCards[i].cfg.irq) + { + card = &DivasCards[i]; + ux_ref = card->hw; + + if ((ux_ref) && (card->is_live)) + { + (*ux_ref->user_isr)(ux_ref->user_isr_arg); + } + else + { + DPRINTF(("divas: ISR couldn't locate card")); + } + } + } + + return; +} + + +int UxIsrInstall(ux_diva_card_t *card, isr_fn_t *isr_fn, void *isr_arg) +{ + int result; + + card->user_isr = isr_fn; + card->user_isr_arg = isr_arg; + + result = request_irq(card->irq, Divasintr, SA_INTERRUPT | SA_SHIRQ, "Divas", (void *) isr_arg); + + return result; +} + +void UxIsrRemove(ux_diva_card_t *card, void *dev_id) +{ + free_irq(card->irq, card->user_isr_arg); +} + +void UxPciConfigWrite(ux_diva_card_t *card, int size, int offset, void *value) +{ + switch (size) + { + case sizeof(byte): + pcibios_write_config_byte(card->bus_num, card->func_num, offset, * (byte *) value); + break; + case sizeof(word): + pcibios_write_config_word(card->bus_num, card->func_num, offset, * (word *) value); + break; + case sizeof(dword): + pcibios_write_config_dword(card->bus_num, card->func_num, offset, * (dword *) value); + break; + default: + printk(KERN_WARNING "Divas: Invalid size in UxPciConfigWrite\n"); + } +} + +void UxPciConfigRead(ux_diva_card_t *card, int size, int offset, void *value) +{ + switch (size) + { + case sizeof(byte): + pcibios_read_config_byte(card->bus_num, card->func_num, offset, (byte *) value); + break; + case sizeof(word): + pcibios_read_config_word(card->bus_num, card->func_num, offset, (word *) value); + break; + case sizeof(dword): + pcibios_read_config_dword(card->bus_num, card->func_num, offset, (unsigned int *) value); + break; + default: + printk(KERN_WARNING "Divas: Invalid size in UxPciConfigRead\n"); + } +} + +void *UxAlloc(unsigned int size) +{ + void *m; + + m = kmalloc(size, GFP_ATOMIC); + + return m; +} + +void UxFree(void *ptr) +{ + kfree(ptr); +} + +int UxCardLock(ux_diva_card_t *card) +{ + unsigned long flags; + + //spin_lock_irqsave(&diva_lock, flags); + + save_flags(flags); + cli(); + return flags; + +} + +void UxCardUnlock(ux_diva_card_t *card, int ipl) +{ + //spin_unlock_irqrestore(&diva_lock, ipl); + + restore_flags(ipl); + +} + +dword UxTimeGet(void) +{ + return jiffies; +} + +long UxInterlockedIncrement(ux_diva_card_t *card, long *dst) +{ + register volatile long *p; + register long ret; + int ipl; + + p =dst; + + ipl = UxCardLock(card); + + *p += 1; + ret = *p; + + UxCardUnlock(card,ipl); + + return(ret); + +} + +long UxInterlockedDecrement(ux_diva_card_t *card, long *dst) +{ + register volatile long *p; + register long ret; + int ipl; + + p =dst; + + ipl = UxCardLock(card); + + *p -= 1; + ret = *p; + + UxCardUnlock(card,ipl); + + return(ret); + +} diff --git a/drivers/isdn/eicon/linsys.c b/drivers/isdn/eicon/linsys.c new file mode 100644 index 000000000..3f167ed7b --- /dev/null +++ b/drivers/isdn/eicon/linsys.c @@ -0,0 +1,170 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.10 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include <linux/sched.h> +#undef N_DATA +#include <linux/tqueue.h> + +#include <linux/smp.h> +struct pt_regs; +#include <linux/interrupt.h> +#include <linux/ioport.h> + +#include "sys.h" +#include "divas.h" +#include "adapter.h" +#include "divalog.h" + +#include "uxio.h" + +#ifdef MODULE +void bcopy(void *pSource, void *pDest, dword dwLength) +{ + memcpy(pDest, pSource, dwLength); +} +#endif + +void bzero(void *pDataArea, dword dwLength) +{ + memset(pDataArea, 0, dwLength); +} + +int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg) +{ + /* Use UxPciConfigWrite routines to initialise PCI config space */ + +/* wPCIcommand = 0x03; + cm_write_devconfig16(CMKey, PCI_COMMAND, &wPCIcommand); + + wPCIcommand = 0x280; + cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand); + + bPCIcommand = 0x30; + cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand); +*/ + return 0; +} + +int DivasPRIInitPCI(card_t *card, dia_card_t *cfg) +{ + /* Use UxPciConfigWrite routines to initialise PCI config space */ + +/* wPCIcommand = 0x03; + cm_write_devconfig16(CMKey, PCI_COMMAND, &wPCIcommand); + + wPCIcommand = 0x280; + cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand); + + bPCIcommand = 0x30; + cm_write_devconfig8(CMKey, PCI_LATENCY, &bPCIcommand);*/ + + return 0; +} + +int DivasBRIInitPCI(card_t *card, dia_card_t *cfg) +{ + /* Need to set these platform dependent values after patching */ + + card->hw->reset_base = card->cfg.reset_base; + card->hw->io_base = card->cfg.io_base; + + request_region(card->hw->reset_base,0x80,"Divas"); + request_region(card->hw->io_base,0x20,"Divas"); + + + /* Same as for PRI */ + return DivasPRIInitPCI(card, cfg); +} + +/* ######################### Stubs of routines that are not done yet ################## */ +/*void DivasLogIdi(card_t *card, ENTITY *e, int request) +{ +} +*/ + +int DivasDpcSchedule(void) +{ + static struct tq_struct DivasTask; + + DivasTask.routine = DivasDoDpc; + DivasTask.data = (void *) 0; + + queue_task(&DivasTask, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + return 0; +} + +int DivasScheduleRequestDpc(void) +{ + static struct tq_struct DivasTask; + + DivasTask.routine = DivasDoRequestDpc; + DivasTask.data = (void *) 0; + + queue_task(&DivasTask, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + return 0; +} + +void DivasLogAdd(void *buffer, int length) +{ + static + boolean_t overflow = FALSE; + static + boolean_t busy = FALSE; + + /* make sure we're not interrupting ourselves */ + + if (busy) + { + printk(KERN_DEBUG "Divas: Logging interrupting self !\n"); + return; + } + busy = TRUE; + + /* ignore call if daemon isn't running and we've reached limit */ + + if (DivasLogFifoFull()) + { + if (!overflow) + { + printk(KERN_DEBUG "Divas: Trace buffer full\n"); + overflow = TRUE; + } + busy = FALSE; + return; + } + + DivasLogFifoWrite(buffer, length); + + busy = FALSE; + return; +} + +/* #################################################################################### */ diff --git a/drivers/isdn/eicon/log.c b/drivers/isdn/eicon/log.c new file mode 100644 index 000000000..1d847f0a8 --- /dev/null +++ b/drivers/isdn/eicon/log.c @@ -0,0 +1,179 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.5 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* + * Source file for diva log facility + */ + +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "adapter.h" +#include "divalog.h" + +#include "uxio.h" + +/*Counter to monitor number of messages */ +static int m_count; + +#define MAX_BUFFERED_MSGS (1000) + +/* Our Linked List Structure to hold message */ +typedef struct klog_link{ + klog_t klog; + struct klog_link *next; +}KNODE; + +/* First & Last structures in list*/ +KNODE *head; +KNODE *tail; + +/* + * retrieve message from FIFO buffer + * returns NULL if buffer empty + * otherwise returns pointer to entry + */ + +char *DivasLogFifoRead(void) + +{ + KNODE *old_head; + + if(head==NULL) + { + /* Buffer Empty - No Messages */ + return NULL; + } + + m_count--; + /* Keep track of message to be read & increment to next message*/ + old_head = head; + head = head->next; + /*Return ptr to Msg */ + return((char *)old_head); +} + +/* + * write message into FIFO buffer + */ + +void DivasLogFifoWrite(char *entry, int length) + +{ + KNODE *new_klog; + + if(head == NULL) + { + /* No Entries in Log */ + tail=NULL; + m_count=0; + new_klog=UxAlloc(sizeof(KNODE)); + + if(new_klog==NULL) + { + return; + } + + m_count++; + bzero(new_klog,sizeof(KNODE)); + + /* Set head & tail to point to the new Msg Struct */ + head=tail=new_klog; + tail->next=NULL; + } + else + { + new_klog=UxAlloc(sizeof(KNODE)); + + if(new_klog==NULL) + { + return; + } + + m_count++; + bzero(new_klog,sizeof(KNODE)); + + /* Let last Msg Struct point to new Msg Struct & inc tail */ + tail->next=new_klog; + tail=new_klog; + tail->next=NULL; + } + + if (length > sizeof(klog_t)) + { + length = sizeof(klog_t); + } + + bcopy(entry,&tail->klog,length); + + return; +} + +/* + * DivaslogFifoEmpty:return TRUE if FIFO buffer is empty,otherwise FALSE + */ +int DivasLogFifoEmpty(void) +{ + return (m_count == 0); +} + +/* + *DivasLogFifoFull:return TRUE if FIFO buffer is full,otherwise FALSE + */ +int DivasLogFifoFull(void) +{ + return (m_count == MAX_BUFFERED_MSGS); +} + +/* + * generate an IDI log entry + */ + +void DivasLogIdi(card_t *card, ENTITY *e, int request) + +{ + klog_t klog; + + bzero(&klog, sizeof(klog)); + + klog.time_stamp = UxTimeGet(); + + klog.length = sizeof(ENTITY) > sizeof(klog.buffer) ? + sizeof(klog.buffer) : sizeof(ENTITY); + + klog.card = (int) (card - DivasCards); + + klog.type = request ? KLOG_IDI_REQ : KLOG_IDI_CALLBACK; + klog.code = 0; + bcopy(e, klog.buffer, klog.length); + + /* send to the log driver and return */ + + DivasLogAdd(&klog, sizeof(klog)); + + return; +} diff --git a/drivers/isdn/eicon/md5sums.asc b/drivers/isdn/eicon/md5sums.asc new file mode 100644 index 000000000..aa1cd9065 --- /dev/null +++ b/drivers/isdn/eicon/md5sums.asc @@ -0,0 +1,16 @@ +# These are valid md5sums to detect modifications +# in eicon driver files provided by Eicon Technology. +# For changes and modifications in these files please +# read ../../../Documentation/isdn/README.eicon +# +9b0e381d4558af3a6eba66843e1ee5d9 common.c +dbb92cba52db31ff8325a252b3f595c3 idi.c +15687687ef82f099966ed42772001cd3 bri.c +c3e3b720c3351b66635bd548195e29e8 pri.c +b0a6d2ab49bcfcfd1825860f178a84b4 log.c +673746176316b72271a09c0a27287a01 xlog.c +07e1bbabdb4d69880db196ef31bfb241 kprintf.c +b60b40ad630f26b7923369df95b4d1b9 fpga.c +5013ecca0a38a8fcc4a61642754f2076 fourbri.c +1501ae468a0c5eaab1e60720fa723a67 fcheck.c +# end of md5sums diff --git a/drivers/isdn/eicon/pc.h b/drivers/isdn/eicon/pc.h new file mode 100644 index 000000000..412a61faa --- /dev/null +++ b/drivers/isdn/eicon/pc.h @@ -0,0 +1,320 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef PC_H_INCLUDED +#define PC_H_INCLUDED + + +#define byte unsigned char +#define word unsigned short +#define dword unsigned long +#if !defined(MIN) +#define MIN(a,b) ((a)>(b) ? (b) : (a)) +#endif +#if !defined(MAX) +#define MAX(a,b) ((a)>(b) ? (a) : (b)) +#endif + +/*------------------------------------------------------------------*/ +/* buffer definition */ +/*------------------------------------------------------------------*/ + +typedef struct { + word length; /* length of data/parameter field */ + byte P[270]; /* data/parameter field */ +} PBUFFER; + +/*------------------------------------------------------------------*/ +/* dual port ram structure */ +/*------------------------------------------------------------------*/ + +struct dual +{ + byte Req; /* request register */ + byte ReqId; /* request task/entity identification */ + byte Rc; /* return code register */ + byte RcId; /* return code task/entity identification */ + byte Ind; /* Indication register */ + byte IndId; /* Indication task/entity identification */ + byte IMask; /* Interrupt Mask Flag */ + byte RNR; /* Receiver Not Ready (set by PC) */ + byte XLock; /* XBuffer locked Flag */ + byte Int; /* ISDN-S interrupt */ + byte ReqCh; /* Channel field for layer-3 Requests */ + byte RcCh; /* Channel field for layer-3 Returncodes */ + byte IndCh; /* Channel field for layer-3 Indications */ + byte MInd; /* more data indication field */ + word MLength; /* more data total packet length */ + byte ReadyInt; /* request field for ready interrupt */ + byte SWReg; /* Software register for special purposes */ + byte Reserved[11]; /* reserved space */ + byte InterfaceType; /* interface type 1=16K interface */ + word Signature; /* ISDN-S adapter Signature (GD) */ + PBUFFER XBuffer; /* Transmit Buffer */ + PBUFFER RBuffer; /* Receive Buffer */ +}; + +/*------------------------------------------------------------------*/ +/* SWReg Values (0 means no command) */ +/*------------------------------------------------------------------*/ +#define SWREG_DIE_WITH_LEDON 0x01 +#define SWREG_HALT_CPU 0x02 /* Push CPU into a while(1) loop */ + +/*------------------------------------------------------------------*/ +/* Id Fields Coding */ +/*------------------------------------------------------------------*/ + +#define ID_MASK 0xe0 /* Mask for the ID field */ +#define GL_ERR_ID 0x1f /* ID for error reporting on global requests*/ + +#define DSIG_ID 0x00 /* ID for D-channel signaling */ +#define NL_ID 0x20 /* ID for network-layer access (B or D) */ +#define BLLC_ID 0x60 /* ID for B-channel link level access */ +#define TASK_ID 0x80 /* ID for dynamic user tasks */ +#define TIMER_ID 0xa0 /* ID for timer task */ +#define TEL_ID 0xc0 /* ID for telephone support */ +#define MAN_ID 0xe0 /* ID for management */ + +/*------------------------------------------------------------------*/ +/* ASSIGN and REMOVE requests are the same for all entities */ +/*------------------------------------------------------------------*/ + +#define ASSIGN 0x01 +#define UREMOVE 0xfe /* without returncode */ +#define REMOVE 0xff + +/*------------------------------------------------------------------*/ +/* Timer Interrupt Task Interface */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_TIM 0x01 +#define REMOVE_TIM 0xff + +/*------------------------------------------------------------------*/ +/* dynamic user task interface */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_TSK 0x01 +#define REMOVE_TSK 0xff + +#define LOAD 0xf0 +#define RELOCATE 0xf1 +#define START 0xf2 +#define LOAD2 0xf3 +#define RELOCATE2 0xf4 + +/*------------------------------------------------------------------*/ +/* dynamic user task messages */ +/*------------------------------------------------------------------*/ + +#define TSK_B2 0x0000 +#define TSK_WAKEUP 0x2000 +#define TSK_TIMER 0x4000 +#define TSK_TSK 0x6000 +#define TSK_PC 0xe000 + +/*------------------------------------------------------------------*/ +/* LL management primitives */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_LL 1 /* assign logical link */ +#define REMOVE_LL 0xff /* remove logical link */ + +/*------------------------------------------------------------------*/ +/* LL service primitives */ +/*------------------------------------------------------------------*/ + +#define LL_UDATA 1 /* link unit data request/indication */ +#define LL_ESTABLISH 2 /* link establish request/indication */ +#define LL_RELEASE 3 /* link release request/indication */ +#define LL_DATA 4 /* data request/indication */ +#define LL_LOCAL 5 /* switch to local operation (COM only) */ +#define LL_DATA_PEND 5 /* data pending indication (SDLC SHM only) */ +#define LL_REMOTE 6 /* switch to remote operation (COM only) */ +#define LL_TEST 8 /* link test request */ +#define LL_MDATA 9 /* more data request/indication */ +#define LL_BUDATA 10 /* broadcast unit data request/indication */ +#define LL_XID 12 /* XID command request/indication */ +#define LL_XID_R 13 /* XID response request/indication */ + +/*------------------------------------------------------------------*/ +/* NL service primitives */ +/*------------------------------------------------------------------*/ + +#define N_MDATA 1 /* more data to come REQ/IND */ +#define N_CONNECT 2 /* OSI N-CONNECT REQ/IND */ +#define N_CONNECT_ACK 3 /* OSI N-CONNECT CON/RES */ +#define N_DISC 4 /* OSI N-DISC REQ/IND */ +#define N_DISC_ACK 5 /* OSI N-DISC CON/RES */ +#define N_RESET 6 /* OSI N-RESET REQ/IND */ +#define N_RESET_ACK 7 /* OSI N-RESET CON/RES */ +#define N_DATA 8 /* OSI N-DATA REQ/IND */ +#define N_EDATA 9 /* OSI N-EXPEDITED DATA REQ/IND */ +#define N_UDATA 10 /* OSI D-UNIT-DATA REQ/IND */ +#define N_BDATA 11 /* BROADCAST-DATA REQ/IND */ +#define N_DATA_ACK 12 /* data ack ind for D-bit procedure */ +#define N_EDATA_ACK 13 /* data ack ind for INTERRUPT */ + +#define N_Q_BIT 0x10 /* Q-bit for req/ind */ +#define N_M_BIT 0x20 /* M-bit for req/ind */ +#define N_D_BIT 0x40 /* D-bit for req/ind */ + +/*------------------------------------------------------------------*/ +/* Signaling management primitives */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_SIG 1 /* assign signaling task */ +#define UREMOVE_SIG 0xfe /* remove signaling task without returncode */ +#define REMOVE_SIG 0xff /* remove signaling task */ + +/*------------------------------------------------------------------*/ +/* Signaling service primitives */ +/*------------------------------------------------------------------*/ + +#define CALL_REQ 1 /* call request */ +#define CALL_CON 1 /* call confirmation */ +#define CALL_IND 2 /* incoming call connected */ +#define LISTEN_REQ 2 /* listen request */ +#define HANGUP 3 /* hangup request/indication */ +#define SUSPEND 4 /* call suspend request/confirm */ +#define RESUME 5 /* call resume request/confirm */ +#define SUSPEND_REJ 6 /* suspend rejected indication */ +#define USER_DATA 8 /* user data for user to user signaling */ +#define CONGESTION 9 /* network congestion indication */ +#define INDICATE_REQ 10 /* request to indicate an incoming call */ +#define INDICATE_IND 10 /* indicates that there is an incoming call */ +#define CALL_RES 11 /* accept an incoming call */ +#define CALL_ALERT 12 /* send ALERT for incoming call */ +#define INFO_REQ 13 /* INFO request */ +#define INFO_IND 13 /* INFO indication */ +#define REJECT 14 /* reject an incoming call */ +#define RESOURCES 15 /* reserve B-Channel hardware resources */ +#define TEL_CTRL 16 /* Telephone control request/indication */ +#define STATUS_REQ 17 /* Request D-State (returned in INFO_IND) */ +#define FAC_REG_REQ 18 /* connection idependent fac registration */ +#define FAC_REG_ACK 19 /* fac registration acknowledge */ +#define FAC_REG_REJ 20 /* fac registration reject */ +#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call */ +#define FACILITY_REQ 22 /* send a Facility Message type */ +#define FACILITY_IND 22 /* Facility Message type indication */ +#define SIG_CTRL 29 /* Control for signalling hardware */ +#define DSP_CTRL 30 /* Control for DSPs */ +#define LAW_REQ 31 /* Law config request for (returns info_i) */ + + +/*------------------------------------------------------------------*/ +/* management service primitives */ +/*------------------------------------------------------------------*/ + +#define MAN_READ 2 +#define MAN_WRITE 3 +#define MAN_EXECUTE 4 +#define MAN_EVENT_ON 5 +#define MAN_EVENT_OFF 6 +#define MAN_LOCK 7 +#define MAN_UNLOCK 8 + +#define MAN_INFO_IND 2 +#define MAN_EVENT_IND 3 +#define MAN_TRACE_IND 4 + +#define MAN_ESC 0x80 + +/*------------------------------------------------------------------*/ +/* return code coding */ +/*------------------------------------------------------------------*/ + +#define UNKNOWN_COMMAND 0x01 /* unknown command */ +#define WRONG_COMMAND 0x02 /* wrong command */ +#define WRONG_ID 0x03 /* unknown task/entity id */ +#define WRONG_CH 0x04 /* wrong task/entity id */ +#define UNKNOWN_IE 0x05 /* unknown information el. */ +#define WRONG_IE 0x06 /* wrong information el. */ +#define OUT_OF_RESOURCES 0x07 /* ISDN-S card out of res. */ +#define ADAPTER_DEAD 0x08 /* ISDN card CPU halted */ +#define N_FLOW_CONTROL 0x10 /* Flow-Control, retry */ +#define ASSIGN_RC 0xe0 /* ASSIGN acknowledgement */ +#define ASSIGN_OK 0xef /* ASSIGN OK */ +#define OK_FC 0xfc /* Flow-Control RC */ +#define READY_INT 0xfd /* Ready interrupt */ +#define TIMER_INT 0xfe /* timer interrupt */ +#define OK 0xff /* command accepted */ + +/*------------------------------------------------------------------*/ +/* information elements */ +/*------------------------------------------------------------------*/ + +#define SHIFT 0x90 /* codeset shift */ +#define MORE 0xa0 /* more data */ +#define CL 0xb0 /* congestion level */ + + /* codeset 0 */ + +#define BC 0x04 /* Bearer Capability */ +#define CAU 0x08 /* cause */ +#define CAD 0x0c /* Connected address */ +#define CAI 0x10 /* call identity */ +#define CHI 0x18 /* channel identification */ +#define LLI 0x19 /* logical link id */ +#define CHA 0x1a /* charge advice */ +#define DT 0x29 /* ETSI date/time */ +#define KEY 0x2c /* keypad information element */ +#define FTY 0x1c /* facility information element */ +#define DSP 0x28 /* display */ +#define OAD 0x6c /* origination address */ +#define OSA 0x6d /* origination sub-address */ +#define CPN 0x70 /* called party number */ +#define DSA 0x71 /* destination sub-address */ +#define RDX 0x73 /* redirected number extended */ +#define RDN 0x74 /* redirected number */ +#define LLC 0x7c /* low layer compatibility */ +#define HLC 0x7d /* high layer compatibility */ +#define UUI 0x7e /* user user information */ +#define ESC 0x7f /* escape extension */ + +#define DLC 0x20 /* data link layer configuration */ +#define NLC 0x21 /* network layer configuration */ + + /* codeset 6 */ + +#define SIN 0x01 /* service indicator */ +#define CIF 0x02 /* charging information */ +#define DATE 0x03 /* date */ +#define CPS 0x07 /* called party status */ + +/*------------------------------------------------------------------*/ +/* TEL_CTRL contents */ +/*------------------------------------------------------------------*/ + +#define RING_ON 0x01 +#define RING_OFF 0x02 +#define HANDS_FREE_ON 0x03 +#define HANDS_FREE_OFF 0x04 +#define ON_HOOK 0x80 +#define OFF_HOOK 0x90 + +#endif diff --git a/drivers/isdn/eicon/pc_maint.h b/drivers/isdn/eicon/pc_maint.h new file mode 100644 index 000000000..e6e902f00 --- /dev/null +++ b/drivers/isdn/eicon/pc_maint.h @@ -0,0 +1,165 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef PC_MAINT_H +#define PC_MAINT_H + +#if !defined(MIPS_SCOM) +#define BUFFER_SZ 48 +#define MAINT_OFFS 0x380 +#else +#define BUFFER_SZ 128 +#define MAINT_OFFS 0xff00 +#endif + +#define MIPS_BUFFER_SZ 128 +#define MIPS_MAINT_OFFS 0xff00 + +#define DO_LOG 1 +#define MEMR 2 +#define MEMW 3 +#define IOR 4 +#define IOW 5 +#define B1TEST 6 +#define B2TEST 7 +#define BTESTOFF 8 +#define DSIG_STATS 9 +#define B_CH_STATS 10 +#define D_CH_STATS 11 +#define BL1_STATS 12 +#define BL1_STATS_C 13 +#define GET_VERSION 14 +#define OS_STATS 15 +#define XLOG_SET_MASK 16 +#define XLOG_GET_MASK 17 +#define DSP_READ 20 +#define DSP_WRITE 21 + +#define OK 0xff +#define MORE_EVENTS 0xfe +#define NO_EVENT 1 + +struct DSigStruc +{ + byte Id; + byte uX; + byte listen; + byte active; + byte sin[3]; + byte bc[6]; + byte llc[6]; + byte hlc[6]; + byte oad[20]; +}; + +struct BL1Struc { + dword cx_b1; + dword cx_b2; + dword cr_b1; + dword cr_b2; + dword px_b1; + dword px_b2; + dword pr_b1; + dword pr_b2; + word er_b1; + word er_b2; +}; + +struct L2Struc { + dword XTotal; + dword RTotal; + word XError; + word RError; +}; + +struct OSStruc { + word free_n; +}; + +typedef union +{ + struct DSigStruc DSigStats; + struct BL1Struc BL1Stats; + struct L2Struc L2Stats; + struct OSStruc OSStats; + byte b[BUFFER_SZ]; + word w[BUFFER_SZ>>1]; + word l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */ + dword d[BUFFER_SZ>>2]; +} BUFFER; + +typedef union +{ + struct DSigStruc DSigStats; + struct BL1Struc BL1Stats; + struct L2Struc L2Stats; + struct OSStruc OSStats; + byte b[MIPS_BUFFER_SZ]; + word w[MIPS_BUFFER_SZ>>1]; + word l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */ + dword d[MIPS_BUFFER_SZ>>2]; +} MIPS_BUFFER; + + +#if !defined(MIPS_SCOM) +struct pc_maint +{ + byte req; + byte rc; + byte *mem; /*far*/ + short length; + word port; + byte fill[6]; + BUFFER data; +}; +#else +struct pc_maint +{ + byte req; + byte rc; + byte reserved[2]; /* R3000 alignment ... */ + byte far *mem; + short length; + word port; + byte fill[4]; /* data at offset 16 */ + BUFFER data; +}; +#endif + +struct mi_pc_maint +{ + byte req; + byte rc; + byte reserved[2]; /* R3000 alignment ... */ + byte *mem; /*far*/ + short length; + word port; + byte fill[4]; /* data at offset 16 */ + MIPS_BUFFER data; +}; + +#endif /* PC_MAINT_H */ diff --git a/drivers/isdn/eicon/pr_pc.h b/drivers/isdn/eicon/pr_pc.h new file mode 100644 index 000000000..f01ad4499 --- /dev/null +++ b/drivers/isdn/eicon/pr_pc.h @@ -0,0 +1,86 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#if !defined(PR_PC_H) +#define PR_PC_H + +struct pr_ram { + word NextReq; /* pointer to next Req Buffer */ + word NextRc; /* pointer to next Rc Buffer */ + word NextInd; /* pointer to next Ind Buffer */ + byte ReqInput; /* number of Req Buffers sent */ + byte ReqOutput; /* number of Req Buffers returned */ + byte ReqReserved; /* number of Req Buffers reserved */ + byte Int; /* ISDN-P interrupt */ + byte XLock; /* Lock field for arbitration */ + byte RcOutput; /* number of Rc buffers received */ + byte IndOutput; /* number of Ind buffers received */ + byte IMask; /* Interrupt Mask Flag */ + byte Reserved1[2]; /* reserved field, do not use */ + byte ReadyInt; /* request field for ready interrupt */ + byte Reserved2[12]; /* reserved field, do not use */ + byte InterfaceType; /* interface type 1=16K interface */ + word Signature; /* ISDN-P initialized indication */ + byte B[1]; /* buffer space for Req,Ind and Rc */ +}; + +typedef struct { + word next; + byte Req; + byte ReqId; + byte ReqCh; + byte Reserved1; + word Reference; + byte Reserved[8]; + PBUFFER XBuffer; +} REQ; + +typedef struct { + word next; + byte Rc; + byte RcId; + byte RcCh; + byte Reserved1; + word Reference; + byte Reserved2[8]; +} RC; + +typedef struct { + word next; + byte Ind; + byte IndId; + byte IndCh; + byte MInd; + word MLength; + word Reference; + byte RNR; + byte Reserved; + dword Ack; + PBUFFER RBuffer; +} IND; + +#endif diff --git a/drivers/isdn/eicon/pri.c b/drivers/isdn/eicon/pri.c new file mode 100644 index 000000000..a6a63945e --- /dev/null +++ b/drivers/isdn/eicon/pri.c @@ -0,0 +1,533 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.5 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* Diva Server PRI specific part of initialisation */ +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" +#include "dsp_defs.h" + +#include "adapter.h" +#include "uxio.h" + +#define DIVAS_LOAD_CMD 0x02 +#define DIVAS_START_CMD 0x03 +#define DIVAS_IRQ_RESET 0xC18 +#define DIVAS_IRQ_RESET_VAL 0xFE + +#define TEST_INT_DIVAS 0x11 +#define TEST_INT_DIVAS_BRI 0x12 + +#define DIVAS_RESET 0x81 +#define DIVAS_LED1 0x04 +#define DIVAS_LED2 0x08 +#define DIVAS_LED3 0x20 +#define DIVAS_LED4 0x40 + +#define DIVAS_RESET_REG 0x20 + +#define DIVAS_SIGNATURE 0x4447 + +/* offset to start of MAINT area (used by xlog) */ + +#define DIVAS_MAINT_OFFSET 0xef00 /* value for PRI card */ + +#define MP_PROTOCOL_ADDR 0xA0011000 +#define MP_DSP_CODE_BASE 0xa03a0000 + +typedef struct { + dword cmd; + dword addr; + dword len; + dword err; + dword live; + dword reserved[(0x1020>>2)-6]; + dword signature; + byte data[1]; +} diva_server_boot_t; + +byte mem_in(ADAPTER *a, void *adr); +word mem_inw(ADAPTER *a, void *adr); +void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e); +void mem_out(ADAPTER *a, void *adr, byte data); +void mem_outw(ADAPTER *a, void *adr, word data); +void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_inc(ADAPTER *a, void *adr); + +int DivasPRIInitPCI(card_t *card, dia_card_t *cfg); +int pri_ISR (card_t* card); + +static int diva_server_reset(card_t *card) +{ + byte *reg; + diva_server_boot_t *boot = NULL; + dword live = 0; + int i = 0; + dword dwWait; + + DPRINTF(("divas: reset Diva Server PRI")); + + reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY); + + UxCardMemOut(card->hw, ®[DIVAS_RESET_REG], DIVAS_RESET | + DIVAS_LED1 | DIVAS_LED2 | DIVAS_LED3 | DIVAS_LED4); + + for (dwWait = 0x000fffff; dwWait; dwWait--) + ; + + UxCardMemOut(card->hw, ®[DIVAS_RESET_REG], 0x00); + + for (dwWait = 0x000fffff; dwWait; dwWait--) + ; + + UxCardMemDetach(card->hw, reg); + + boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + UxCardMemOutD(card->hw, boot->reserved, 0); + + live = UxCardMemInD(card->hw, &boot->live); + + for (i=0; i<5; i++) + { + if (live != UxCardMemInD(card->hw, &boot->live)) + { + break; + } + UxPause(10); + } + + if (i == 5) + { + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: card is reset but CPU not running")); + return -1; + } + + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: card reset after %d ms", i * 10)); + + return 0; +} + +static int diva_server_config(card_t *card, dia_config_t *config) +{ + byte *shared; + int i, j; + + DPRINTF(("divas: configure Diva Server PRI")); + + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + UxCardLog(0); + for (i=0; i<256; i++) + { + UxCardMemOut(card->hw, &shared[i], 0); + } + + UxCardMemOut(card->hw, &shared[ 8], config->tei); + UxCardMemOut(card->hw, &shared[ 9], config->nt2); + UxCardMemOut(card->hw, &shared[10], 0); + UxCardMemOut(card->hw, &shared[11], config->watchdog); + UxCardMemOut(card->hw, &shared[12], config->permanent); + UxCardMemOut(card->hw, &shared[13], config->x_interface); + UxCardMemOut(card->hw, &shared[14], config->stable_l2); + UxCardMemOut(card->hw, &shared[15], config->no_order_check); + UxCardMemOut(card->hw, &shared[16], config->handset_type); + UxCardMemOut(card->hw, &shared[17], 0); + UxCardMemOut(card->hw, &shared[18], config->low_channel); + UxCardMemOut(card->hw, &shared[19], config->prot_version); + UxCardMemOut(card->hw, &shared[20], config->crc4); + + for (i=0; i<2; i++) + { + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[32+(i*96)+j],config->terminal[i].oad[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[64+(i*96)+j],config->terminal[i].osa[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[96+(i*96)+j],config->terminal[i].spid[j]); + } + } + + UxCardMemDetach(card->hw, shared); + + return 0; +} + +static +void diva_server_reset_int(card_t *card) +{ + byte *cfg; + + cfg = UxCardMemAttach(card->hw, DIVAS_CFG_MEMORY); + + UxCardMemOutW(card->hw, &cfg[DIVAS_IRQ_RESET], DIVAS_IRQ_RESET_VAL); + UxCardMemOutW(card->hw, &cfg[DIVAS_IRQ_RESET + 2], 0); + UxCardMemDetach(card->hw, cfg); + + return; +} + + +static int diva_server_test_int(card_t *card) +{ + int i; + byte *shared; + byte req_int; + + DPRINTF(("divas: test interrupt for Diva Server PRI")); + + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + UxCardMemIn(card->hw, &shared[0x3FE]); + UxCardMemOut(card->hw, &shared[0x3FE], 0); + UxCardMemIn(card->hw, &shared[0x3FE]); + + UxCardMemDetach(card->hw, shared); + + diva_server_reset_int(card); + + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + card->test_int_pend = TEST_INT_DIVAS; + + req_int = UxCardMemIn(card->hw, &(((struct pr_ram *)shared)->ReadyInt)); + + req_int++; + + UxCardMemOut(card->hw, &(((struct pr_ram *)shared)->ReadyInt), req_int); + + UxCardMemDetach(card->hw, shared); + + UxCardLog(0); + for (i = 0; i < 50; i++) + { + if (!card->test_int_pend) + { + break; + } + UxPause(10); + } + + + if (card->test_int_pend) + { + + DPRINTF(("active: timeout waiting for card to interrupt")); + return (-1); + + } + + return 0; +} + + +static void print_hdr(unsigned char *code, int offset) +{ + unsigned char hdr[80]; + int i; + + i = 0; + + while ((i < (DIM(hdr) -1)) && + (code[offset + i] != '\0') && + (code[offset + i] != '\r') && + (code[offset + i] != '\n')) + { + hdr[i] = code[offset + i]; + i++; + } + + hdr[i] = '\0'; + + DPRINTF(("divas: loading %s", hdr)); +} + +static int diva_server_load(card_t *card, dia_load_t *load) +{ + diva_server_boot_t *boot; + int i, offset, length; + dword cmd = 0; + + DPRINTF(("divas: loading Diva Server PRI")); + + boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + switch(load->code_type) + { + case DIA_CPU_CODE: + DPRINTF(("divas: RISC code")); + print_hdr(load->code, 0x80); + + UxCardMemOutD(card->hw, &boot->addr, MP_PROTOCOL_ADDR); + break; + + case DIA_DSP_CODE: + DPRINTF(("divas: DSP code")); + print_hdr(load->code, 0x0); + + UxCardMemOutD(card->hw, &boot->addr, + (MP_DSP_CODE_BASE + (((sizeof(dword) + + (sizeof(t_dsp_download_desc) * DSP_MAX_DOWNLOAD_COUNT)) + + ~ALIGNMENT_MASK_MAESTRA) & ALIGNMENT_MASK_MAESTRA))); + break; + + case DIA_TABLE_CODE: + DPRINTF(("divas: TABLE code")); + UxCardMemOutD(card->hw, &boot->addr, + (MP_DSP_CODE_BASE + sizeof(dword))); + break; + + case DIA_CONT_CODE: + DPRINTF(("divas: continuation code")); + break; + + case DIA_DLOAD_CNT: + DPRINTF(("divas: COUNT code")); + UxCardMemOutD(card->hw, &boot->addr, MP_DSP_CODE_BASE); + break; + + default: + DPRINTF(("divas: unknown code type")); + UxCardMemDetach(card->hw, boot); + return -1; + } + + UxCardLog(0); + offset = 0; + + do + { + length = (load->length - offset >= 400) ? 400 : load->length - offset; + + for (i=0; i<length; i++) + { + UxCardMemOut(card->hw, &boot->data[i], load->code[offset+i]); + } + + for (i=0; i<length; i++) + { + if (load->code[offset + i] != UxCardMemIn(card->hw, &boot->data[i])) + { + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: card code block verify failed")); + return -1; + } + } + + UxCardMemOutD(card->hw, &boot->len, (length + 3) / 4); + UxCardMemOutD(card->hw, &boot->cmd, DIVAS_LOAD_CMD); + + for (i=0; i<50000; i++) + { + cmd = UxCardMemInD(card->hw, &boot->cmd); + if (!cmd) + { + break; + } + /*UxPause(1);*/ + } + + if (cmd) + { + DPRINTF(("divas: timeout waiting for card to ACK load (offset = %d)", offset)); + UxCardMemDetach(card->hw, boot); + return -1; + } + + offset += length; + + } while (offset < load->length); + + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: DIVA Server card loaded")); + + return 0; +} + +static int diva_server_start(card_t *card, byte *channels) +{ + diva_server_boot_t *boot; + byte *ram; + int i; + dword signature = 0; + + DPRINTF(("divas: start Diva Server PRI")); + + card->is_live = FALSE; + + boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + UxCardMemOutD(card->hw, &boot->addr, MP_PROTOCOL_ADDR); + UxCardMemOutD(card->hw, &boot->cmd, DIVAS_START_CMD); + + UxCardLog(0); + + for (i = 0; i < 300; i++) + { + signature = UxCardMemInD(card->hw, &boot->signature); + if ((signature >> 16) == DIVAS_SIGNATURE) + { + DPRINTF(("divas: started card after %d ms", i * 10)); + break; + } + UxPause(10); + } + + if ((signature >> 16) != DIVAS_SIGNATURE) + { + UxCardMemDetach(card->hw, boot); + DPRINTF(("divas: timeout waiting for card to run protocol code (sig = 0x%x)", signature)); + return -1; + } + + card->is_live = TRUE; + + ram = (byte *) boot; + ram += DIVAS_SHARED_OFFSET; + + *channels = UxCardMemIn(card->hw, &ram[0x3F6]); + card->serial_no = UxCardMemInD(card->hw, &ram[0x3F0]); + + UxCardMemDetach(card->hw, boot); + + if (diva_server_test_int(card)) + { + DPRINTF(("divas: interrupt test failed")); + return -1; + } + + DPRINTF(("divas: DIVA Server card started")); + + return 0; +} + +static +int diva_server_mem_get(card_t *card, mem_block_t *mem_block) + +{ + byte *a; + byte *card_addr; + word length = 0; + int i; + + a = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + card_addr = a; + card_addr += mem_block->addr; + + for (i=0; i < sizeof(mem_block->data); i++) + { + mem_block->data[i] = UxCardMemIn(card->hw, card_addr); + card_addr++; + length++; + } + + UxCardMemDetach(card->hw, a); + + return length; +} + +/* + * Initialise PRI specific entry points + */ + +int DivasPriInit(card_t *card, dia_card_t *cfg) +{ + DPRINTF(("divas: initialise Diva Server PRI")); + + if (DivasPRIInitPCI(card, cfg) == -1) + { + return -1; + } + + card->card_reset = diva_server_reset; + card->card_load = diva_server_load; + card->card_config = diva_server_config; + card->card_start = diva_server_start; + card->reset_int = diva_server_reset_int; + card->card_mem_get = diva_server_mem_get; + + card->xlog_offset = DIVAS_MAINT_OFFSET; + + card->out = DivasOut; + card->test_int = DivasTestInt; + card->dpc = DivasDpc; + card->clear_int = DivasClearInt; + card->card_isr = pri_ISR; + + card->a.ram_out = mem_out; + card->a.ram_outw = mem_outw; + card->a.ram_out_buffer = mem_out_buffer; + card->a.ram_inc = mem_inc; + + card->a.ram_in = mem_in; + card->a.ram_inw = mem_inw; + card->a.ram_in_buffer = mem_in_buffer; + card->a.ram_look_ahead = mem_look_ahead; + + return 0; +} + + +int pri_ISR (card_t* card) +{ + int served = 0; + byte* cfg = UxCardMemAttach(card->hw, DIVAS_CFG_MEMORY); + volatile unsigned long* isr = (unsigned long*)&cfg[DIVAS_IRQ_RESET]; + register unsigned long val = *isr; + + if (val & 0x80000000) /* our card had caused interrupt ??? */ + { + served = 1; + card->int_pend += 1; + DivasDpcSchedule(); /* ISR DPC */ + + *isr = (unsigned long)~0x03E00000; /* Clear interrupt line */ + } + + UxCardMemDetach(card->hw, cfg); + + return (served != 0); +} + + diff --git a/drivers/isdn/eicon/sys.h b/drivers/isdn/eicon/sys.h new file mode 100644 index 000000000..0e636c547 --- /dev/null +++ b/drivers/isdn/eicon/sys.h @@ -0,0 +1,119 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* Environment provided by system and miscellaneous definitions */ + +#if !defined(SYS_H) +#define SYS_H + +/* abreviations for unsigned types */ +typedef int boolean_t; + +typedef unsigned char byte; + +typedef unsigned long dword; +typedef unsigned short word; + +/* abreviations for volatile types */ + +typedef volatile byte vbyte; +typedef volatile word vword; +typedef volatile dword vdword; + +/* Booleans */ + +#if !defined(TRUE) +#define TRUE (1) +#define FALSE (0) +#endif + +/* NULL pointer */ + +#if !defined(NULL) +#define NULL ((void *) 0) +#endif + +/* MIN and MAX */ + +#if !defined(MIN) +#define MIN(a,b) ((a)>(b) ? (b) : (a)) +#endif +#if !defined(MAX) +#define MAX(a,b) ((a)>(b) ? (a) : (b)) +#endif + +/* Return the dimension of an array */ + +#if !defined(DIM) +#define DIM(array) (sizeof (array)/sizeof ((array)[0])) +#endif + +/* + * Return the number of milliseconds since last boot + */ + +extern dword UxTimeGet(void); + +extern void DivasSprintf(char *buffer, char *format, ...); +extern void DivasPrintf(char *format, ...); + +/* fatal errors, asserts and tracing */ + +void HwFatalErrorFrom(char *file, int line); +void HwFatalError(void); +/* void HwAssert(char *file, int line, char *condition); */ + +#include <linux/kernel.h> +#define _PRINTK printk + +#define _PRINTF DivasPrintf +void _PRINTF(char *format, ...); +#define PRINTF(arg_list) _PRINTF arg_list +#if defined DTRACE +# define DPRINTF(arg_list) _PRINTF arg_list +# define KDPRINTF(arg_list) _PRINTF arg_list ; _PRINTK arg_list ; _PRINTK("\n"); +#else +# define DPRINTF(arg_list) (void)0 +# define KDPRINTF(arg_list) _PRINTK arg_list ; _PRINTK("\n"); +#endif + +#if !defined(ASSERT) +#if defined DEBUG || defined DBG +# define HwFatalError() HwFatalErrorFrom(__FILE__, __LINE__) +# define ASSERT(cond) \ + if (!(cond)) \ + { \ +/* HwAssert(__FILE__, __LINE__, #cond);*/ \ + } +#else +# define ASSERT(cond) ((void)0) +#endif +#endif /* !defined(ASSERT) */ + +#define TRACE (_PRINTF(__FILE__"@%d\n", __LINE__)) + +#endif /* SYS_H */ diff --git a/drivers/isdn/eicon/uxio.h b/drivers/isdn/eicon/uxio.h new file mode 100644 index 000000000..c15d93f96 --- /dev/null +++ b/drivers/isdn/eicon/uxio.h @@ -0,0 +1,220 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.6 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* + * Interface to Unix specific code for performing card I/O + */ + +#if !defined(UXIO_H) +#define UXIO_H + +#include "sys.h" +#include "adapter.h" + + +struct pt_regs; + +/* user callback, returns zero if interrupt was from this card */ +typedef void isr_fn_t(void *); +struct ux_diva_card_s +{ + word in_use; + int io_base; + int reset_base; + int card_type; + byte *mapped; + int bus_num; + int func_num; + int slot; + int irq; + byte *pDRAM; + byte *pDEVICES; + byte *pCONFIG; + byte *pSHARED; + byte *pCONTROL; + word features; + void *user_isr_arg; + isr_fn_t *user_isr; +}; + +void bcopy(void *pSource, void *pDest, dword dwLength); +void bzero(void *pDataArea, dword dwLength); + + +/* + * Get a card handle to enable card to be accessed + */ + +int UxCardHandleGet( ux_diva_card_t **card, + dia_card_t *cfg); + +/* + * Free a card handle as no longer needed + */ + +void UxCardHandleFree(ux_diva_card_t *card); + +/* + * Lock and unlock access to a card + */ + +int UxCardLock(ux_diva_card_t *card); +void UxCardUnlock(ux_diva_card_t *card, int ipl); + +/* + * Set the mapping address for PCI cards + */ + +int UxCardAddrMappingSet(ux_diva_card_t *card, + int id, + void *address, + int size); + +/* + * Attach card to memory to enable it to be accessed + * Returns the mapped address + */ + +void *UxCardMemAttach(ux_diva_card_t *card, int id); + +/* + * map card out of memory after completion of access + */ + +void UxCardMemDetach(ux_diva_card_t *card, void *address); + +/* + * input functions for memory-mapped cards + */ + +byte UxCardMemIn(ux_diva_card_t *card, void *address); + +word UxCardMemInW(ux_diva_card_t *card, void *address); + +dword UxCardMemInD(ux_diva_card_t *card, void *address); + +void UxCardMemInBuffer( ux_diva_card_t *card, + void *address, + void *buffer, + int length); + +/* + * output functions for memory-mapped cards + */ + +void UxCardMemOut(ux_diva_card_t *card, void *address, byte data); + +void UxCardMemOutW(ux_diva_card_t *card, void *address, word data); + +void UxCardMemOutD(ux_diva_card_t *card, void *address, dword data); + +void UxCardMemOutBuffer( ux_diva_card_t *card, + void *address, + void *buffer, + int length); + +/* + * input functions for I/O-mapped cards + */ + +byte UxCardIoIn(ux_diva_card_t *card, void *, void *address); + +word UxCardIoInW(ux_diva_card_t *card, void *, void *address); + +dword UxCardIoInD(ux_diva_card_t *card, void *, void *address); + +void UxCardIoInBuffer( ux_diva_card_t *card, + void *, void *address, + void *buffer, + int length); + +/* + * output functions for I/O-mapped cards + */ + +void UxCardIoOut(ux_diva_card_t *card, void *, void *address, byte data); + +void UxCardIoOutW(ux_diva_card_t *card, void *, void *address, word data); + +void UxCardIoOutD(ux_diva_card_t *card, void *, void *address, dword data); + +void UxCardIoOutBuffer( ux_diva_card_t *card, + void *, void *address, + void *buffer, + int length); + +/* + * Get specified PCI config + */ + +void UxPciConfigRead(ux_diva_card_t *card, + int size, + int offset, + void *value); + +/* + * Set specified PCI config + */ + +void UxPciConfigWrite(ux_diva_card_t *card, + int size, + int offset, + void *value); + +/* allocate memory, returning NULL if none available */ + +void *UxAlloc(unsigned int size); + +void UxFree(void *); + +/* + * Pause for specified number of milli-seconds + */ + +void UxPause(long ms); + +/* + * Install an ISR for the specified card + */ + +int UxIsrInstall(ux_diva_card_t *card, isr_fn_t *isr_fn, void *isr_arg); + +/* + * Remove an ISR for the specified card + */ +void UxIsrRemove(ux_diva_card_t *card, void *); + +/* + * DEBUG function to turn logging ON or OFF + */ + +void UxCardLog(int turn_on); + +long UxInterlockedIncrement(ux_diva_card_t *card, long *dst); +long UxInterlockedDecrement(ux_diva_card_t *card, long *dst); + +#endif /* of UXIO_H */ diff --git a/drivers/isdn/eicon/xlog.c b/drivers/isdn/eicon/xlog.c new file mode 100644 index 000000000..282662cfc --- /dev/null +++ b/drivers/isdn/eicon/xlog.c @@ -0,0 +1,183 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * This source file is supplied for the exclusive use with Eicon + * Technology Corporation's range of DIVA Server Adapters. + * + * Eicon File Revision : 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* + * Unix Eicon active card driver + * XLOG related functions + */ + +#include "sys.h" +#include "idi.h" +#include "pc.h" +#include "pc_maint.h" +#include "divalog.h" + +#include "adapter.h" +#include "uxio.h" + +/* + * convert/copy XLOG info into a KLOG entry + */ + +static +void xlog_to_klog(byte *b, int size, int card_num) + +{ + typedef struct + { + word code; + word time_hi; + word time_lo; + word xcode; + byte data[2]; + } card_xlog_t; + + card_xlog_t *x; + + klog_t klog; + + x = (card_xlog_t *) b; + + bzero(&klog, sizeof(klog)); + + klog.time_stamp = (dword) x->time_hi; + klog.time_stamp = (klog.time_stamp << 16) | (dword) x->time_lo; + + klog.length = size > sizeof(klog.buffer) ? sizeof(klog.buffer) : size; + + klog.card = card_num; + if (x->code == 1) + { + klog.type = KLOG_XTXT_MSG; + klog.code = 0; + bcopy(&x->xcode, klog.buffer, klog.length); + } + else if (x->code == 2) + { + klog.type = KLOG_XLOG_MSG; + klog.code = x->xcode; + bcopy(&x->data, klog.buffer, klog.length); + } + else + { + char *c; int i; + klog.type = KLOG_TEXT_MSG; + klog.code = 0; + c = "divas: invalid xlog message code from card"; + i = 0; + while (*c) + { + klog.buffer[i] = *c; + c++; + i++; + } + klog.buffer[i] = *c; + } + + /* send to the log driver and return */ + + DivasLogAdd(&klog, sizeof(klog)); + + return; +} + +/* + * send an XLOG request down to specified card + * if response available from previous request then read it + * if not then just send down new request, ready for next time + */ + +void DivasXlogReq(int card_num) + +{ + card_t *card; + ADAPTER *a; + + if ((card_num < 0) || (card_num > DivasCardNext)) + { + DPRINTF(("xlog: invalid card number")); + return; + } + + card = &DivasCards[card_num]; + + if (DivasXlogRetrieve(card)) + { + return; + } + + /* send down request for next time */ + + a = &card->a; + + a->ram_out(a, (word *) (card->xlog_offset + 1), 0); + a->ram_out(a, (word *) (dword) (card->xlog_offset), DO_LOG); + + return; +} + +/* + * retrieve XLOG request from specified card + * returns non-zero if new request sent to card + */ + +int DivasXlogRetrieve(card_t *card) + +{ + ADAPTER *a; + struct mi_pc_maint pcm; + + a = &card->a; + + /* get status of last request */ + + pcm.rc = a->ram_in(a, (word *)(card->xlog_offset + 1)); + + /* if nothing there from previous request, send down a new one */ + + if (pcm.rc == OK) + { + /* read in response */ + + a->ram_in_buffer(a, (word *) (dword) card->xlog_offset, &pcm, sizeof(pcm)); + + xlog_to_klog((byte *) &pcm.data, sizeof(pcm.data), + (int) (card - DivasCards)); + } + + /* if any response received from card, re-send request */ + + if (pcm.rc) + { + a->ram_out(a, (word *) (card->xlog_offset + 1), 0); + a->ram_out(a, (word *) (dword) (card->xlog_offset), DO_LOG); + + return 1; + } + + return 0; +} diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile index 7bc340de9..071e3b1ca 100644 --- a/drivers/isdn/hisax/Makefile +++ b/drivers/isdn/hisax/Makefile @@ -31,6 +31,8 @@ HFC_OBJ := HFC_2BDS0 := JADE_OBJ := W6692_OBJ := +NETJ_OBJ := +ICC_OBJ := ifeq ($(CONFIG_HISAX_16_0),y) O_OBJS += teles0.o @@ -124,10 +126,17 @@ ifeq ($(CONFIG_HISAX_MIC),y) endif ifeq ($(CONFIG_HISAX_NETJET),y) - O_OBJS += netjet.o + O_OBJS += nj_s.o + NETJ_OBJ := netjet.o ISAC_OBJ := isac.o endif +ifeq ($(CONFIG_HISAX_NETJET_U),y) + O_OBJS += nj_u.o + NETJ_OBJ := netjet.o + ICC_OBJ := icc.o +endif + ifeq ($(CONFIG_HISAX_HFCS),y) O_OBJS += hfcscard.o HFC_2BDS0 := hfc_2bds0.o @@ -189,7 +198,7 @@ ifeq ($(ISAC_OBJ), isac.o) endif O_OBJS += $(ISAC_OBJ) $(HSCX_OBJ) $(ISAR_OBJ) $(JADE_OBJ) -O_OBJS += $(HFC_OBJ) $(HFC_2BDS0) $(W6692_OBJ) +O_OBJS += $(HFC_OBJ) $(HFC_2BDS0) $(W6692_OBJ) $(NETJ_OBJ) $(ICC_OBJ) OX_OBJS += config.o O_TARGET := @@ -208,10 +217,9 @@ include $(TOPDIR)/Rules.make MD5FILES += isac.c isdnl1.c isdnl2.c isdnl3.c \ tei.c callc.c cert.c l3dss1.c l3_1tr6.c \ - elsa.c diva.c + elsa.c diva.c sedlbauer.c CERT = $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?) cert.o: $(MD5FILES) md5sums.asc $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -D CERTIFICATION=$(CERT) -c -o cert.o cert.c - diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index dabb179b5..4302585dc 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -1,4 +1,4 @@ -/* $Id: avm_pci.c,v 1.17 2000/06/26 08:59:12 keil Exp $ +/* $Id: avm_pci.c,v 1.18 2000/08/20 07:34:04 keil Exp $ * * avm_pci.c low level stuff for AVM Fritz!PCI and ISA PnP isdn cards * Thanks to AVM, Berlin for informations @@ -17,13 +17,17 @@ #include <linux/interrupt.h> extern const char *CardType[]; -static const char *avm_pci_rev = "$Revision: 1.15 $"; +static const char *avm_pci_rev = "$Revision: 1.18 $"; #define AVM_FRITZ_PCI 1 #define AVM_FRITZ_PNP 2 -#define PCI_VENDOR_AVM 0x1244 -#define PCI_FRITZPCI_ID 0xa00 +#ifndef PCI_VENDOR_ID_AVM +#define PCI_VENDOR_ID_AVM 0x1244 +#endif +#ifndef PCI_DEVICE_ID_AVM_FRITZ +#define PCI_DEVICE_ID_AVM_FRITZ 0xa00 +#endif #define HDLC_FIFO 0x0 #define HDLC_STATUS 0x4 @@ -293,7 +297,15 @@ hdlc_empty_fifo(struct BCState *bcs, int count) if (cs->subtyp == AVM_FRITZ_PCI) { outl(idx, cs->hw.avm.cfg_reg + 4); while (cnt < count) { +#ifdef __powerpc__ +#ifdef CONFIG_APUS + *ptr++ = in_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE)); +#else + *ptr++ = in_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE)); +#endif /* CONFIG_APUS */ +#else *ptr++ = inl(cs->hw.avm.isac); +#endif /* __powerpc__ */ cnt += 4; } } else { @@ -349,7 +361,15 @@ hdlc_fill_fifo(struct BCState *bcs) write_ctrl(bcs, 3); /* sets the correct index too */ if (cs->subtyp == AVM_FRITZ_PCI) { while (cnt<count) { +#ifdef __powerpc__ +#ifdef CONFIG_APUS + out_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++); +#else + out_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++); +#endif /* CONFIG_APUS */ +#else outl(*ptr++, cs->hw.avm.isac); +#endif /* __powerpc__ */ cnt += 4; } } else { @@ -767,8 +787,8 @@ setup_avm_pcipnp(struct IsdnCard *card)) printk(KERN_ERR "FritzPCI: no PCI bus present\n"); return(0); } - if ((dev_avm = pci_find_device(PCI_VENDOR_AVM, - PCI_FRITZPCI_ID, dev_avm))) { + if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM, + PCI_DEVICE_ID_AVM_FRITZ, dev_avm))) { cs->irq = dev_avm->irq; if (!cs->irq) { printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); @@ -776,9 +796,9 @@ setup_avm_pcipnp(struct IsdnCard *card)) } if (pci_enable_device(dev_avm)) return(0); - cs->hw.avm.cfg_reg = pci_resource_start (dev_avm, 1); + cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1); if (!cs->hw.avm.cfg_reg) { - printk(KERN_WARNING "FritzPCI: No IO-Adr for PCI card found\n"); + printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); return(0); } cs->subtyp = AVM_FRITZ_PCI; diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c index 17e3a19a7..75729c282 100644 --- a/drivers/isdn/hisax/bkm_a4t.c +++ b/drivers/isdn/hisax/bkm_a4t.c @@ -18,12 +18,12 @@ #include "hscx.h" #include "jade.h" #include "isdnl1.h" -#include "bkm_ax.h" #include <linux/pci.h> +#include "bkm_ax.h" extern const char *CardType[]; -const char *bkm_a4t_revision = "$Revision: 1.9 $"; +const char *bkm_a4t_revision = "$Revision: 1.11 $"; static inline u_char @@ -287,17 +287,20 @@ __initfunc(int printk(KERN_ERR "bkm_a4t: no PCI bus present\n"); return (0); } - if ((dev_a4t = pci_find_device(I20_VENDOR_ID, I20_DEVICE_ID, dev_a4t))) { - u_int sub_sys_id = 0; - - if (pci_enable_device(dev_a4t)) - return (0); - pci_read_config_dword(dev_a4t, PCI_SUBSYSTEM_VENDOR_ID, - &sub_sys_id); - if (sub_sys_id == ((A4T_SUBSYS_ID << 16) | A4T_SUBVEN_ID)) { + while ((dev_a4t = pci_find_device(PCI_VENDOR_ID_ZORAN, + PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) { + u16 sub_sys; + u16 sub_vendor; + + sub_vendor = dev_a4t->subsystem_vendor; + sub_sys = dev_a4t->subsystem_device; + if ((sub_sys == A4T_SUBSYS_ID) && (sub_vendor == A4T_SUBVEN_ID)) { + if (pci_enable_device(dev_a4t)) + return(0); found = 1; - pci_memaddr = pci_resource_start (dev_a4t, 0); + pci_memaddr = pci_resource_start(dev_a4t, 0); cs->irq = dev_a4t->irq; + break; } } if (!found) { diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c index 61e0bde3c..6f00073c6 100644 --- a/drivers/isdn/hisax/bkm_a8.c +++ b/drivers/isdn/hisax/bkm_a8.c @@ -17,29 +17,16 @@ #include "ipac.h" #include "hscx.h" #include "isdnl1.h" -#include "bkm_ax.h" #include <linux/pci.h> +#include "bkm_ax.h" + +#if CONFIG_PCI #define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */ extern const char *CardType[]; -const char sct_quadro_revision[] = "$Revision: 1.9 $"; - -/* To survive the startup phase */ -typedef struct { - u_int active; /* true/false */ - u_int base; /* ipac base address */ -} IPAC_STATE; - -static IPAC_STATE ipac_state[4 + 1] __initdata = -{ - {0, 0}, /* dummy */ - {0, 0}, /* SCT_1 */ - {0, 0}, /* SCT_2 */ - {0, 0}, /* SCT_3 */ - {0, 0} /* SCT_4 */ -}; +const char sct_quadro_revision[] = "$Revision: 1.12 $"; static const char *sct_quadro_subtypes[] = { @@ -138,19 +125,13 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value); } -/* Check whether the specified ipac is already active or not */ -static int -is_ipac_active(u_int ipac_nr) -{ - return (ipac_state[ipac_nr].active); -} - /* Set the specific ipac to active */ static void -set_ipac_active(u_int ipac_nr, u_int active) +set_ipac_active(struct IsdnCardState *cs, u_int active) { - /* set activation state */ - ipac_state[ipac_nr].active = active; + /* set irq mask */ + writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, + active ? 0xc0 : 0xff); } /* @@ -173,13 +154,14 @@ bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; u_char ista, val, icnt = 5; - int i; + if (!cs) { printk(KERN_WARNING "HiSax: Scitel Quadro: Spurious interrupt!\n"); return; } ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA); - + if (!(ista & 0x3f)) /* not this IPAC */ + return; Start_IPAC: if (cs->debug & L1_DEB_IPAC) debugl1(cs, "IPAC ISTA %02X", ista); @@ -216,30 +198,15 @@ bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) sct_quadro_subtypes[cs->subtyp]); writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF); writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0); - - /* Read out all interrupt sources from currently not active ipacs */ - /* "Handle" all interrupts from currently not active ipac by reading the regs */ - for (i = SCT_1; i <= SCT_4; i++) - if (!is_ipac_active(i)) { - u_int base = ipac_state[i].base; - if (readreg(base, base + 4, 0xC1)) { - readreg(base, base + 4, 0xA0); - readreg(base, base + 4, 0xA4); - readreg(base, base + 4, 0x20); - readreg(base, base + 4, 0x24); - readreg(base, base + 4, 0x60); - readreg(base, base + 4, 0x64); - readreg(base, base + 4, 0xC1); - readreg(base, base + 4, ISAC_CIR0 + 0x80); - } - } } void release_io_sct_quadro(struct IsdnCardState *cs) { - /* ?? */ + release_region(cs->hw.ax.base & 0xffffffc0, 256); + if (cs->subtyp == SCT_1) + release_region(cs->hw.ax.plx_adr, 256); } static void @@ -249,11 +216,6 @@ enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable) if (bEnable) wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41)); else - /* Issue general di only if no ipac is active */ - if (!is_ipac_active(SCT_1) && - !is_ipac_active(SCT_2) && - !is_ipac_active(SCT_3) && - !is_ipac_active(SCT_4)) wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41)); } } @@ -263,26 +225,17 @@ reset_bkm(struct IsdnCardState *cs) { long flags; - if (cs->typ == ISDN_CTYPE_SCT_QUADRO) { - if (!is_ipac_active(SCT_1) && - !is_ipac_active(SCT_2) && - !is_ipac_active(SCT_3) && - !is_ipac_active(SCT_4)) { - /* Issue total reset only if no ipac is active */ - wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4)); - - save_flags(flags); - sti(); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10 * HZ) / 1000); - - /* Remove the soft reset */ - wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4)); - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10 * HZ) / 1000); - restore_flags(flags); - } + if (cs->subtyp == SCT_1) { + wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4)); + save_flags(flags); + sti(); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10 * HZ) / 1000); + /* Remove the soft reset */ + wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4)); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10 * HZ) / 1000); + restore_flags(flags); } } @@ -292,20 +245,19 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg) switch (mt) { case CARD_RESET: /* Disable ints */ - set_ipac_active(cs->subtyp, 0); + set_ipac_active(cs, 0); enable_bkm_int(cs, 0); reset_bkm(cs); return (0); case CARD_RELEASE: /* Sanity */ - set_ipac_active(cs->subtyp, 0); + set_ipac_active(cs, 0); enable_bkm_int(cs, 0); - reset_bkm(cs); release_io_sct_quadro(cs); return (0); case CARD_INIT: cs->debug |= L1_DEB_IPAC; - set_ipac_active(cs->subtyp, 1); + set_ipac_active(cs, 1); inithscxisac(cs, 3); /* Enable ints */ enable_bkm_int(cs, 1); @@ -316,18 +268,38 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg) return (0); } +__initfunc(int +sct_alloc_io(u_int adr, u_int len)) +{ + if (check_region(adr, len)) { + printk(KERN_WARNING + "HiSax: Scitel port %#x-%#x already in use\n", + adr, adr + len); + return (1); + } else { + request_region(adr, len, "scitel"); + } + return(0); +} + static struct pci_dev *dev_a8 __initdata = NULL; +static u16 sub_vendor_id __initdata = 0; +static u16 sub_sys_id __initdata = 0; +static u_char pci_bus __initdata = 0; +static u_char pci_device_fn __initdata = 0; +static u_char pci_irq __initdata = 0; + +#endif /* CONFIG_PCI */ __initfunc(int - setup_sct_quadro(struct IsdnCard *card)) +setup_sct_quadro(struct IsdnCard *card)) { +#if CONFIG_PCI struct IsdnCardState *cs = card->cs; char tmp[64]; -#if CONFIG_PCI - u_char pci_bus = 0, pci_device_fn = 0, pci_irq = 0, pci_rev_id; + u_char pci_rev_id; u_int found = 0; u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5; -#endif strcpy(tmp, sct_quadro_revision); printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp)); @@ -339,32 +311,61 @@ __initfunc(int /* Identify subtype by para[0] */ if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4) cs->subtyp = card->para[0]; - else + else { printk(KERN_WARNING "HiSax: %s: Invalid subcontroller in configuration, default to 1\n", - CardType[card->typ]); -#if CONFIG_PCI - if (!pci_present()) { - printk(KERN_ERR "bkm_a4t: no PCI bus present\n"); + CardType[card->typ]); return (0); } - if ((dev_a8 = pci_find_device(PLX_VENDOR_ID, PLX_DEVICE_ID, dev_a8))) { - u_int sub_sys_id = 0; - - pci_read_config_dword(dev_a8, PCI_SUBSYSTEM_VENDOR_ID, - &sub_sys_id); - if (sub_sys_id == ((SCT_SUBSYS_ID << 16) | SCT_SUBVEN_ID)) { - found = 1; - pci_ioaddr1 = dev_a8->resource[ 1].start; - pci_irq = dev_a8->irq; - pci_bus = dev_a8->bus->number; - pci_device_fn = dev_a8->devfn; - } - } - if (!found) { - printk(KERN_WARNING "HiSax: %s (%s): Card not found\n", - CardType[card->typ], - sct_quadro_subtypes[cs->subtyp]); + if ((cs->subtyp != SCT_1) && ((sub_sys_id != SCT_SUBSYS_ID) || + (sub_vendor_id != SCT_SUBVEN_ID))) return (0); + if (cs->subtyp == SCT_1) { + if (!pci_present()) { + printk(KERN_ERR "bkm_a4t: no PCI bus present\n"); + return (0); + } + while ((dev_a8 = pci_find_device(PCI_VENDOR_ID_PLX, + PCI_DEVICE_ID_PLX_9050, dev_a8))) { + + sub_vendor_id = dev_a8->subsystem_vendor; + sub_sys_id = dev_a8->subsystem_device; + if ((sub_sys_id == SCT_SUBSYS_ID) && + (sub_vendor_id == SCT_SUBVEN_ID)) { + if (pci_enable_device(dev_a8)) + return(0); + pci_ioaddr1 = pci_resource_start(dev_a8, 1); + pci_irq = dev_a8->irq; + pci_bus = dev_a8->bus->number; + pci_device_fn = dev_a8->devfn; + found = 1; + break; + } + } + if (!found) { + printk(KERN_WARNING "HiSax: %s (%s): Card not found\n", + CardType[card->typ], + sct_quadro_subtypes[cs->subtyp]); + return (0); + } +#ifdef ATTEMPT_PCI_REMAPPING +/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */ + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_REVISION_ID, &pci_rev_id); + if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) { + printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!\n", + CardType[card->typ], + sct_quadro_subtypes[cs->subtyp]); + /* Restart PCI negotiation */ + pcibios_write_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_1, (u_int) - 1); + /* Move up by 0x80 byte */ + pci_ioaddr1 += 0x80; + pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK; + pcibios_write_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_1, pci_ioaddr1); + dev_a8->resource[ 1].start = pci_ioaddr1; + } +#endif /* End HACK */ } if (!pci_irq) { /* IRQ range check ?? */ printk(KERN_WARNING "HiSax: %s (%s): No IRQ\n", @@ -372,25 +373,6 @@ __initfunc(int sct_quadro_subtypes[cs->subtyp]); return (0); } -#ifdef ATTEMPT_PCI_REMAPPING -/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */ - pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_REVISION_ID, &pci_rev_id); - if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) { - printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!\n", - CardType[card->typ], - sct_quadro_subtypes[cs->subtyp]); - /* Restart PCI negotiation */ - pcibios_write_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_1, (u_int) - 1); - /* Move up by 0x80 byte */ - pci_ioaddr1 += 0x80; - pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK; - pcibios_write_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_1, pci_ioaddr1); - dev_a8->resource[ 1].start = pci_ioaddr1; - } -/* End HACK */ -#endif pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &pci_ioaddr1); pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &pci_ioaddr2); pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_3, &pci_ioaddr3); @@ -417,23 +399,42 @@ __initfunc(int /* pci_ioaddr5 is for the first subdevice only */ cs->hw.ax.plx_adr = pci_ioaddr1; /* Enter all ipac_base addresses */ - ipac_state[SCT_1].base = pci_ioaddr5 + 0x00; - ipac_state[SCT_2].base = pci_ioaddr4 + 0x08; - ipac_state[SCT_3].base = pci_ioaddr3 + 0x10; - ipac_state[SCT_4].base = pci_ioaddr2 + 0x20; - /* For isac and hscx control path */ - cs->hw.ax.base = ipac_state[cs->subtyp].base; + switch(cs->subtyp) { + case 1: + cs->hw.ax.base = pci_ioaddr5 + 0x00; + if (sct_alloc_io(pci_ioaddr1, 256)) + return(0); + if (sct_alloc_io(pci_ioaddr5, 256)) + return(0); + /* disable all IPAC */ + writereg(pci_ioaddr5, pci_ioaddr5 + 4, + IPAC_MASK, 0xFF); + writereg(pci_ioaddr4 + 0x08, pci_ioaddr4 + 0x0c, + IPAC_MASK, 0xFF); + writereg(pci_ioaddr3 + 0x10, pci_ioaddr3 + 0x14, + IPAC_MASK, 0xFF); + writereg(pci_ioaddr2 + 0x20, pci_ioaddr2 + 0x24, + IPAC_MASK, 0xFF); + break; + case 2: + cs->hw.ax.base = pci_ioaddr4 + 0x08; + if (sct_alloc_io(pci_ioaddr4, 256)) + return(0); + break; + case 3: + cs->hw.ax.base = pci_ioaddr3 + 0x10; + if (sct_alloc_io(pci_ioaddr3, 256)) + return(0); + break; + case 4: + cs->hw.ax.base = pci_ioaddr2 + 0x20; + if (sct_alloc_io(pci_ioaddr2, 256)) + return(0); + break; + } /* For isac and hscx data path */ cs->hw.ax.data_adr = cs->hw.ax.base + 4; -#else - printk(KERN_WARNING "HiSax: %s (%s): NO_PCI_BIOS\n", - CardType[card->typ], - sct_quadro_subtypes[cs->subtyp]); - printk(KERN_WARNING "HiSax: %s (%s): Unable to configure\n", - CardType[card->typ], - sct_quadro_subtypes[cs->subtyp]); - return (0); -#endif /* CONFIG_PCI */ + printk(KERN_INFO "HiSax: %s (%s) configured at 0x%.4X, 0x%.4X, 0x%.4X and IRQ %d\n", CardType[card->typ], sct_quadro_subtypes[cs->subtyp], @@ -444,19 +445,6 @@ __initfunc(int test_and_set_bit(HW_IPAC, &cs->HW_Flags); - /* Disable all currently not active ipacs */ - if (!is_ipac_active(SCT_1)) - set_ipac_active(SCT_1, 0); - if (!is_ipac_active(SCT_2)) - set_ipac_active(SCT_2, 0); - if (!is_ipac_active(SCT_3)) - set_ipac_active(SCT_3, 0); - if (!is_ipac_active(SCT_4)) - set_ipac_active(SCT_4, 0); - - /* Perfom general reset (if possible) */ - reset_bkm(cs); - cs->readisac = &ReadISAC; cs->writeisac = &WriteISAC; cs->readisacfifo = &ReadISACfifo; @@ -473,4 +461,7 @@ __initfunc(int sct_quadro_subtypes[cs->subtyp], readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID)); return (1); +#else + printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n"); +#endif /* CONFIG_PCI */ } diff --git a/drivers/isdn/hisax/bkm_ax.h b/drivers/isdn/hisax/bkm_ax.h index 418c4bd47..e513c81a6 100644 --- a/drivers/isdn/hisax/bkm_ax.h +++ b/drivers/isdn/hisax/bkm_ax.h @@ -19,13 +19,21 @@ /* A4T */ -#define I20_DEVICE_ID 0x6120 /* I20 PCI device ID */ -#define I20_VENDOR_ID 0x11DE /* I20 PCI vendor ID */ +#ifndef PCI_VENDOR_ID_ZORAN +#define PCI_VENDOR_ID_ZORAN 0x11DE +#endif +#ifndef PCI_DEVICE_ID_ZORAN_36120 +#define PCI_DEVICE_ID_ZORAN_36120 0x6120 +#endif #define A4T_SUBVEN_ID 0x0871 #define A4T_SUBSYS_ID 0xFFA4 /* Scitel Quadro */ -#define PLX_DEVICE_ID 0x9050 /* Scitel Quadro PLX */ -#define PLX_VENDOR_ID 0x10B5 +#ifndef PCI_VENDOR_ID_PLX +#define PCI_VENDOR_ID_PLX 0x10B5 +#endif +#ifndef PCI_DEVICE_ID_PLX_9050 +#define PCI_DEVICE_ID_PLX_9050 0x9050 +#endif #define SCT_SUBVEN_ID 0x0871 #define SCT_SUBSYS_ID 0xFFA8 diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c index 9ed33d0f3..4d3290392 100644 --- a/drivers/isdn/hisax/callc.c +++ b/drivers/isdn/hisax/callc.c @@ -366,7 +366,7 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg) * No need to return "unknown" for calls without OAD, * cause that's handled in linklevel now (replaced by '0') */ - memcpy (&ic.parm.setup, &chanp->proc->para.setup, sizeof(ic.parm.setup)); + memcpy(&ic.parm.setup, &chanp->proc->para.setup, sizeof(setup_parm)); ret = chanp->cs->iif.statcallb(&ic); if (chanp->debug & 1) link_debug(chanp, 1, "statcallb ret=%d", ret); @@ -383,12 +383,16 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg) FsmChangeState(fi, ST_IN_PROCEED_SEND); chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc); if (ret == 5) { - memcpy (&chanp->setup, &ic.parm.setup, sizeof(chanp->setup)); + memcpy(&chanp->setup, &ic.parm.setup, sizeof(setup_parm)); chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); } break; case 2: /* Rejecting Call */ break; + case 3: /* incomplete number */ + FsmDelTimer(&chanp->drel_timer, 61); + chanp->d_st->lli.l4l3(chanp->d_st, CC_MORE_INFO | REQUEST, chanp->proc); + break; case 0: /* OK, nobody likes this call */ default: /* statcallb problems */ chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc); @@ -795,6 +799,8 @@ static struct FsmNode fnlist[] HISAX_INITDATA = {ST_IN_WAIT_LL, EV_HANGUP, lli_reject_req}, {ST_IN_WAIT_LL, EV_DISCONNECT_IND, lli_release_req}, {ST_IN_WAIT_LL, EV_RELEASE, lli_dhup_close}, + {ST_IN_WAIT_LL, EV_SETUP_IND, lli_deliver_call}, + {ST_IN_WAIT_LL, EV_SETUP_ERR, lli_error}, {ST_IN_ALERT_SENT, EV_SETUP_CMPL_IND, lli_init_bchan_in}, {ST_IN_ALERT_SENT, EV_ACCEPTD, lli_send_dconnect}, {ST_IN_ALERT_SENT, EV_HANGUP, lli_disconnect_reject}, @@ -956,6 +962,9 @@ dchan_l3l4(struct PStack *st, int pr, void *arg) return; switch (pr) { + case (CC_MORE_INFO | INDICATION): + FsmEvent(&chanp->fi, EV_SETUP_IND, NULL); + break; case (CC_DISCONNECT | INDICATION): FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL); break; @@ -1103,7 +1112,7 @@ init_chan(int chan, struct IsdnCardState *csta) chanp->fi.printdebug = callc_debug; FsmInitTimer(&chanp->fi, &chanp->dial_timer); FsmInitTimer(&chanp->fi, &chanp->drel_timer); - if (!chan || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) { + if (!chan || (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags) && chan < 2)) { init_d_st(chanp); } else { chanp->d_st = csta->channel->d_st; @@ -1176,9 +1185,12 @@ lldata_handler(struct PStack *st, int pr, void *arg) switch (pr) { case (DL_DATA | INDICATION): - if (chanp->data_open) + if (chanp->data_open) { + if (chanp->debug & 0x800) + link_debug(chanp, 0, "lldata: %d", skb->len); chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb); - else { + } else { + link_debug(chanp, 0, "lldata: channel not open"); dev_kfree_skb(skb); } break; @@ -1205,10 +1217,12 @@ lltrans_handler(struct PStack *st, int pr, void *arg) switch (pr) { case (PH_DATA | INDICATION): - if (chanp->data_open) + if (chanp->data_open) { + if (chanp->debug & 0x800) + link_debug(chanp, 0, "lltrans: %d", skb->len); chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb); - else { - link_debug(chanp, 0, "channel not open"); + } else { + link_debug(chanp, 0, "lltrans: channel not open"); dev_kfree_skb(skb); } break; @@ -1233,6 +1247,8 @@ ll_writewakeup(struct PStack *st, int len) struct Channel *chanp = st->lli.userdata; isdn_ctrl ic; + if (chanp->debug & 0x800) + link_debug(chanp, 0, "llwakeup: %d", len); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_BSENT; ic.arg = chanp->chan; @@ -1506,7 +1522,7 @@ HiSax_command(isdn_ctrl * ic) link_debug(chanp, 1, "DIAL %s -> %s (%d,%d)", ic->parm.setup.eazmsn, ic->parm.setup.phone, ic->parm.setup.si1, ic->parm.setup.si2); - memcpy (&chanp->setup, &ic->parm.setup, sizeof (chanp->setup)); + memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm)); if (!strcmp(chanp->setup.eazmsn, "0")) chanp->setup.eazmsn[0] = '\0'; /* this solution is dirty and may be change, if @@ -1526,6 +1542,7 @@ HiSax_command(isdn_ctrl * ic) break; case (ISDN_CMD_ACCEPTD): chanp = csta->channel + ic->arg; + memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm)); if (chanp->debug & 1) link_debug(chanp, 1, "ACCEPTD"); FsmEvent(&chanp->fi, EV_ACCEPTD, NULL); @@ -1722,7 +1739,7 @@ HiSax_command(isdn_ctrl * ic) chanp = csta->channel + ic->arg; if (chanp->debug & 1) link_debug(chanp, 1, "REDIR"); - memcpy (&chanp->setup, &ic->parm.setup, sizeof(chanp->setup)); + memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm)); FsmEvent(&chanp->fi, EV_REDIR, NULL); break; diff --git a/drivers/isdn/hisax/cert.c b/drivers/isdn/hisax/cert.c index bf0c6465d..64f3bccc8 100644 --- a/drivers/isdn/hisax/cert.c +++ b/drivers/isdn/hisax/cert.c @@ -17,11 +17,9 @@ certification_check(int output) { #if CERTIFICATION == 0 if (output) { printk(KERN_INFO "HiSax: Approval certification valid\n"); - printk(KERN_INFO "HiSax: Approved with ELSA Quickstep series cards\n"); - printk(KERN_INFO "HiSax: Approval registration numbers:\n"); - printk(KERN_INFO "HiSax: German D133361J CETECOM ICT Services GmbH\n"); - printk(KERN_INFO "HiSax: EU (D133362J) CETECOM ICT Services GmbH\n"); + printk(KERN_INFO "HiSax: Approved with ELSA Microlink PCI cards\n"); printk(KERN_INFO "HiSax: Approved with Eicon Technology Diva 2.01 PCI cards\n"); + printk(KERN_INFO "HiSax: Approved with Sedlbauer Speedfax + cards\n"); } return(0); #endif diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index cda0fe872..4ed7e4129 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -47,7 +47,7 @@ * 17 MIC card p0=irq p1=iobase * 18 ELSA Quickstep 1000PCI no parameter * 19 Compaq ISDN S0 ISA card p0=irq p1=IO0 (HSCX) p2=IO1 (ISAC) p3=IO2 - * 20 Travers Technologies NETjet PCI card + * 20 Travers Technologies NETjet-S PCI card * 21 TELES PCI no parameter * 22 Sedlbauer Speed Star p0=irq p1=iobase * 23 reserved @@ -65,6 +65,7 @@ * 35 HFC 2BDS0 PCI none * 36 Winbond 6692 PCI none * 37 HFC 2BDS0 S+/SP p0=irq p1=iobase + * 38 Travers Technologies NETspider-U PCI card * * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1 * @@ -76,11 +77,11 @@ const char *CardType[] = "AVM A1", "Elsa ML", "Elsa Quickstep", "Teles PCMCIA", "ITK ix1-micro Rev.2", "Elsa PCMCIA", "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c", "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux", "Elsa PCI", - "Compaq ISA", "NETjet", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)", + "Compaq ISA", "NETjet-S", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)", "AMD 7930", "NICCY", "S0Box", "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI", "Sedlbauer Speed Fax +", "Siemens I-Surf", "Acer P10", "HST Saphir", "Telekom A4T", "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692", - "HFC 2BDS0 SX", + "HFC 2BDS0 SX", "NETspider-U", }; void HiSax_closecard(int cardnr); @@ -106,7 +107,6 @@ EXPORT_SYMBOL(elsa_init_pcmcia); #define DEFAULT_CFG {11,0x170,0,0} int avm_a1_init_pcmcia(void*, int, int*, int); EXPORT_SYMBOL(avm_a1_init_pcmcia); -EXPORT_SYMBOL(HiSax_closecard); #endif /* CONFIG_HISAX_AVM_A1_PCMCIA */ #ifdef CONFIG_HISAX_FRITZPCI @@ -198,7 +198,7 @@ EXPORT_SYMBOL(sedl_init_pcmcia); #ifdef CONFIG_HISAX_NETJET #undef DEFAULT_CARD #undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_NETJET +#define DEFAULT_CARD ISDN_CTYPE_NETJET_S #define DEFAULT_CFG {0,0,0,0} #endif @@ -280,22 +280,29 @@ EXPORT_SYMBOL(sedl_init_pcmcia); #define DEFAULT_CFG {0,0,0,0} #endif +#ifdef CONFIG_HISAX_NETJET_U +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_NETJET_U +#define DEFAULT_CFG {0,0,0,0} +#endif + #ifdef CONFIG_HISAX_1TR6 #define DEFAULT_PROTO ISDN_PTYPE_1TR6 #define DEFAULT_PROTO_NAME "1TR6" #endif -#ifdef CONFIG_HISAX_EURO -#undef DEFAULT_PROTO -#define DEFAULT_PROTO ISDN_PTYPE_EURO -#undef DEFAULT_PROTO_NAME -#define DEFAULT_PROTO_NAME "EURO" -#endif #ifdef CONFIG_HISAX_NI1 #undef DEFAULT_PROTO #define DEFAULT_PROTO ISDN_PTYPE_NI1 #undef DEFAULT_PROTO_NAME #define DEFAULT_PROTO_NAME "NI1" #endif +#ifdef CONFIG_HISAX_EURO +#undef DEFAULT_PROTO +#define DEFAULT_PROTO ISDN_PTYPE_EURO +#undef DEFAULT_PROTO_NAME +#define DEFAULT_PROTO_NAME "EURO" +#endif #ifndef DEFAULT_PROTO #define DEFAULT_PROTO ISDN_PTYPE_UNKNOWN #define DEFAULT_PROTO_NAME "UNKNOWN" @@ -304,6 +311,10 @@ EXPORT_SYMBOL(sedl_init_pcmcia); #error "HiSax: No cards configured" #endif +int hisax_init_pcmcia(void *, int *, struct IsdnCard *); +EXPORT_SYMBOL(hisax_init_pcmcia); +EXPORT_SYMBOL(HiSax_closecard); + #define FIRST_CARD { \ DEFAULT_CARD, \ DEFAULT_PROTO, \ @@ -400,9 +411,9 @@ HiSaxVersion(void)) printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n"); #ifdef MODULE - printk(KERN_INFO "HiSax: Version 3.3e (module)\n"); + printk(KERN_INFO "HiSax: Version 3.5 (module)\n"); #else - printk(KERN_INFO "HiSax: Version 3.3e (kernel)\n"); + printk(KERN_INFO "HiSax: Version 3.5 (kernel)\n"); #endif strcpy(tmp, l1_revision); printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp)); @@ -546,8 +557,8 @@ extern int setup_sportster(struct IsdnCard *card); extern int setup_mic(struct IsdnCard *card); #endif -#if CARD_NETJET -extern int setup_netjet(struct IsdnCard *card); +#if CARD_NETJET_S +extern int setup_netjet_s(struct IsdnCard *card); #endif #if CARD_HFCS @@ -598,6 +609,10 @@ extern int setup_gazel(struct IsdnCard *card); extern int setup_w6692(struct IsdnCard *card); #endif +#if CARD_NETJET_U +extern int setup_netjet_u(struct IsdnCard *card); +#endif + /* * Find card with given driverId */ @@ -800,7 +815,7 @@ ll_stop(struct IsdnCardState *cs) ic.command = ISDN_STAT_STOP; ic.driver = cs->myid; cs->iif.statcallb(&ic); - CallcFreeChan(cs); +// CallcFreeChan(cs); } static void @@ -923,6 +938,8 @@ checkcard(int cardnr, char *id, int *busy_flag)) cs->busy_flag = busy_flag; cs->irq_flags = I4L_IRQ_FLAG; #if TEI_PER_CARD + if (card->protocol == ISDN_PTYPE_NI1) + test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); #else test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); #endif @@ -1067,9 +1084,9 @@ checkcard(int cardnr, char *id, int *busy_flag)) ret = setup_mic(card); break; #endif -#if CARD_NETJET - case ISDN_CTYPE_NETJET: - ret = setup_netjet(card); +#if CARD_NETJET_S + case ISDN_CTYPE_NETJET_S: + ret = setup_netjet_s(card); break; #endif #if CARD_HFCS @@ -1133,6 +1150,11 @@ checkcard(int cardnr, char *id, int *busy_flag)) ret = setup_w6692(card); break; #endif +#if CARD_NETJET_U + case ISDN_CTYPE_NETJET_U: + ret = setup_netjet_u(card); + break; +#endif default: printk(KERN_WARNING "HiSax: Support for %s Card not selected\n", @@ -1252,6 +1274,9 @@ HiSax_closecard(int cardnr) if (cards[cardnr].cs) { ll_stop(cards[cardnr].cs); release_tei(cards[cardnr].cs); + + CallcFreeChan(cards[cardnr].cs); + closecard(cardnr); if (cards[cardnr].cs->irq) free_irq(cards[cardnr].cs->irq, cards[cardnr].cs); @@ -1310,10 +1335,19 @@ HiSax_reportcard(int cardnr, int sel) __initfunc(int HiSax_init(void)) { - int i; + int i,j; #ifdef MODULE int nzproto = 0; + if (!type[0]) { + /* We 'll register drivers later, but init basic functions*/ + CallcNew(); + Isdnl3New(); + Isdnl2New(); + TeiNew(); + Isdnl1New(); + return 0; + } #ifdef CONFIG_HISAX_ELSA if (type[0] == ISDN_CTYPE_ELSA_PCMCIA) { /* we have exported and return in this case */ @@ -1338,41 +1372,41 @@ HiSax_init(void)) #ifdef MODULE if (id) /* If id= string used */ HiSax_id = id; - for (i = 0; i < HISAX_MAX_CARDS; i++) { - cards[i].typ = type[i]; + for (i = j = 0; j < HISAX_MAX_CARDS; i++) { + cards[j].typ = type[i]; if (protocol[i]) { - cards[i].protocol = protocol[i]; + cards[j].protocol = protocol[i]; nzproto++; } switch (type[i]) { case ISDN_CTYPE_16_0: - cards[i].para[0] = irq[i]; - cards[i].para[1] = mem[i]; - cards[i].para[2] = io[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = mem[i]; + cards[j].para[2] = io[i]; break; case ISDN_CTYPE_8_0: - cards[i].para[0] = irq[i]; - cards[i].para[1] = mem[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = mem[i]; break; #ifdef IO0_IO1 case ISDN_CTYPE_PNP: case ISDN_CTYPE_NICCY: - cards[i].para[0] = irq[i]; - cards[i].para[1] = io0[i]; - cards[i].para[2] = io1[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = io0[i]; + cards[j].para[2] = io1[i]; break; case ISDN_CTYPE_COMPAQ_ISA: - cards[i].para[0] = irq[i]; - cards[i].para[1] = io0[i]; - cards[i].para[2] = io1[i]; - cards[i].para[3] = io[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = io0[i]; + cards[j].para[2] = io1[i]; + cards[j].para[3] = io[i]; break; #endif case ISDN_CTYPE_ELSA: case ISDN_CTYPE_HFC_PCI: - cards[i].para[0] = io[i]; + cards[j].para[0] = io[i]; break; case ISDN_CTYPE_16_3: case ISDN_CTYPE_TELESPCMCIA: @@ -1396,26 +1430,42 @@ HiSax_init(void)) case ISDN_CTYPE_HSTSAPHIR: case ISDN_CTYPE_GAZEL: case ISDN_CTYPE_HFC_SX: - cards[i].para[0] = irq[i]; - cards[i].para[1] = io[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = io[i]; break; case ISDN_CTYPE_ISURF: - cards[i].para[0] = irq[i]; - cards[i].para[1] = io[i]; - cards[i].para[2] = mem[i]; + cards[j].para[0] = irq[i]; + cards[j].para[1] = io[i]; + cards[j].para[2] = mem[i]; break; case ISDN_CTYPE_ELSA_PCI: - case ISDN_CTYPE_NETJET: + case ISDN_CTYPE_NETJET_S: case ISDN_CTYPE_AMD7930: case ISDN_CTYPE_TELESPCI: case ISDN_CTYPE_W6692: + case ISDN_CTYPE_NETJET_U: break; case ISDN_CTYPE_BKM_A4T: - break; + break; case ISDN_CTYPE_SCT_QUADRO: - cards[i].para[0] = irq[i]; + if (irq[i]) { + cards[j].para[0] = irq[i]; + } else { + /* QUADRO is a 4 BRI card */ + cards[j++].para[0] = 1; + cards[j].typ = ISDN_CTYPE_SCT_QUADRO; + cards[j].protocol = protocol[i]; + cards[j++].para[0] = 2; + cards[j].typ = ISDN_CTYPE_SCT_QUADRO; + cards[j].protocol = protocol[i]; + cards[j++].para[0] = 3; + cards[j].typ = ISDN_CTYPE_SCT_QUADRO; + cards[j].protocol = protocol[i]; + cards[j].para[0] = 4; + } break; } + j++; } if (!nzproto) { printk(KERN_WARNING "HiSax: Warning - no protocol specified\n"); @@ -1620,3 +1670,21 @@ int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) return (0); } #endif + +int hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card) +{ + u_char ids[16]; + int ret = -1; + + cards[nrcards] = *card; + if (nrcards) + sprintf(ids, "HiSax%d", nrcards); + else + sprintf(ids, "HiSax"); + if (!checkcard(nrcards, ids, busy_flag)) { + return(-1); + } + ret = nrcards; + nrcards++; + return (ret); +} diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index 002ee0d60..f39dd7558 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -47,12 +47,18 @@ const char *Diva_revision = "$Revision: 1.21 $"; #define DIVA_IPAC_PCI 4 /* PCI stuff */ -#define PCI_VENDOR_EICON_DIEHL 0x1133 -#define PCI_DIVA20PRO_ID 0xe001 -#define PCI_DIVA20_ID 0xe002 -#define PCI_DIVA20PRO_U_ID 0xe003 -#define PCI_DIVA20_U_ID 0xe004 -#define PCI_DIVA_201 0xe005 +#ifndef PCI_VENDOR_ID_EICON +#define PCI_VENDOR_ID_EICON 0x1133 +#endif +#ifndef PCI_DEVICE_ID_EICON_DIVA20 +#define PCI_DEVICE_ID_EICON_DIVA20 0xe002 +#endif +#ifndef PCI_DEVICE_ID_EICON_DIVA20_U +#define PCI_DEVICE_ID_EICON_DIVA20_U 0xe004 +#endif +#ifndef PCI_DEVICE_ID_EICON_DIVA201 +#define PCI_DEVICE_ID_EICON_DIVA201 0xe005 +#endif /* CTRL (Read) */ #define DIVA_IRQ_STAT 0x01 @@ -70,10 +76,16 @@ const char *Diva_revision = "$Revision: 1.21 $"; /* Siemens PITA */ #define PITA_MISC_REG 0x1c +#ifdef __BIG_ENDIAN +#define PITA_PARA_SOFTRESET 0x00000001 +#define PITA_PARA_MPX_MODE 0x00000004 +#define PITA_INT0_ENABLE 0x00000200 +#else #define PITA_PARA_SOFTRESET 0x01000000 #define PITA_PARA_MPX_MODE 0x04000000 #define PITA_INT0_ENABLE 0x00020000 -#define PITA_INT0_STATUS 0x00000002 +#endif +#define PITA_INT0_STATUS 0x02 static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off) @@ -122,7 +134,7 @@ writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size static inline u_char memreadreg(unsigned long adr, u_char off) { - return(0xff & *((unsigned int *) + return(*((unsigned char *) (((unsigned int *)adr) + off))); } @@ -870,24 +882,24 @@ setup_diva(struct IsdnCard *card)) } cs->subtyp = 0; - if ((dev_diva = pci_find_device(PCI_VENDOR_EICON_DIEHL, - PCI_DIVA20_ID, dev_diva))) { + if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) { if (pci_enable_device(dev_diva)) - return (0); + return(0); cs->subtyp = DIVA_PCI; cs->irq = dev_diva->irq; cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2); - } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_EICON_DIEHL, - PCI_DIVA20_U_ID, dev_diva_u))) { + } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) { if (pci_enable_device(dev_diva_u)) - return (0); + return(0); cs->subtyp = DIVA_PCI; cs->irq = dev_diva_u->irq; cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2); - } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_EICON_DIEHL, - PCI_DIVA_201, dev_diva201))) { + } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON, + PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) { if (pci_enable_device(dev_diva201)) - return (0); + return(0); cs->subtyp = DIVA_IPAC_PCI; cs->irq = dev_diva201->irq; cs->hw.diva.pci_cfg = diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c index 70cff176b..f2357cc4b 100644 --- a/drivers/isdn/hisax/elsa.c +++ b/drivers/isdn/hisax/elsa.c @@ -29,10 +29,10 @@ extern const char *CardType[]; -const char *Elsa_revision = "$Revision: 2.20 $"; +const char *Elsa_revision = "$Revision: 2.23 $"; const char *Elsa_Types[] = {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", - "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI", "QS 3000 PCI", + "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI", "PCMCIA-IPAC" }; const char *ITACVer[] = @@ -66,9 +66,15 @@ const char *ITACVer[] = #define ELSA_PCMCIA_IPAC 11 /* PCI stuff */ -#define PCI_VENDOR_ELSA 0x1048 -#define PCI_QS1000_ID 0x1000 -#define PCI_QS3000_ID 0x3000 +#ifndef PCI_VENDOR_ID_ELSA +#define PCI_VENDOR_ID_ELSA 0x1048 +#endif +#ifndef PCI_DEVICE_ID_ELSA_MIRCOLINK +#define PCI_DEVICE_ID_ELSA_MIRCOLINK 0x1000 +#endif +#ifndef PCI_DEVICE_ID_ELSA_QS3000 +#define PCI_DEVICE_ID_ELSA_QS3000 0x3000 +#endif #define ELSA_PCI_IRQ_MASK 0x04 /* ITAC Registeradressen (only Microlink PC) */ @@ -723,7 +729,8 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg) cs->hw.elsa.status &= ~ELSA_TIMER_AKTIV; printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n", cs->hw.elsa.counter); - if (abs(cs->hw.elsa.counter - 13) < 3) { + if ((cs->hw.elsa.counter > 10) && + (cs->hw.elsa.counter < 16)) { printk(KERN_INFO "Elsa: timer and irq OK\n"); ret = 0; } else { @@ -982,18 +989,18 @@ setup_elsa(struct IsdnCard *card) return(0); } cs->subtyp = 0; - if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ELSA, PCI_QS1000_ID, - dev_qs1000))) { + if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA, + PCI_DEVICE_ID_ELSA_MIRCOLINK, dev_qs1000))) { if (pci_enable_device(dev_qs1000)) - return (0); + return(0); cs->subtyp = ELSA_QS1000PCI; cs->irq = dev_qs1000->irq; cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1); cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3); - } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ELSA, - PCI_QS3000_ID, dev_qs3000))) { - if (pci_enable_device(dev_qs1000)) - return (0); + } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA, + PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) { + if (pci_enable_device(dev_qs3000)) + return(0); cs->subtyp = ELSA_QS3000PCI; cs->irq = dev_qs3000->irq; cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1); diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c index 4693318dc..eb777b184 100644 --- a/drivers/isdn/hisax/gazel.c +++ b/drivers/isdn/hisax/gazel.c @@ -26,10 +26,18 @@ const char *gazel_revision = "$Revision: 2.8 $"; #define R742 4 /* Gazel R685 stuff */ -#define GAZEL_MANUFACTURER 0x10b5 -#define GAZEL_R685 0x1030 -#define GAZEL_R753 0x1152 -#define GAZEL_DJINN_ITOO 0x1151 +#ifndef PCI_VENDOR_ID_PLX +#define PCI_VENDOR_ID_PLX 0x10b5 +#endif +#ifndef PCI_DEVICE_ID_PLX_R685 +#define PCI_DEVICE_ID_PLX_R685 0x1030 +#endif +#ifndef PCI_DEVICE_ID_PLX_R753 +#define PCI_DEVICE_ID_PLX_R753 0x1152 +#endif +#ifndef PCI_DEVICE_ID_PLX_DJINN_ITOO +#define PCI_DEVICE_ID_PLX_DJINN_ITOO 0x1151 +#endif #define PLX_CNTRL 0x50 /* registre de controle PLX */ #define RESET_GAZEL 0x4 @@ -565,25 +573,25 @@ setup_gazelpci(struct IsdnCardState *cs) printk(KERN_WARNING "Gazel: No PCI bus present\n"); return 1; } - seekcard = GAZEL_R685; + seekcard = PCI_DEVICE_ID_PLX_R685; for (nbseek = 0; nbseek < 3; nbseek++) { - if ((dev_tel = pci_find_device(GAZEL_MANUFACTURER, seekcard, dev_tel))) { + if ((dev_tel = pci_find_device(PCI_VENDOR_ID_PLX, seekcard, dev_tel))) { if (pci_enable_device(dev_tel)) return 1; pci_irq = dev_tel->irq; - pci_ioaddr0 = dev_tel->resource[ 1].start; - pci_ioaddr1 = dev_tel->resource[ 2].start; + pci_ioaddr0 = pci_resource_start(dev_tel, 1); + pci_ioaddr1 = pci_resource_start(dev_tel, 2); found = 1; } if (found) break; else { switch (seekcard) { - case GAZEL_R685: - seekcard = GAZEL_R753; + case PCI_DEVICE_ID_PLX_R685: + seekcard = PCI_DEVICE_ID_PLX_R753; break; - case GAZEL_R753: - seekcard = GAZEL_DJINN_ITOO; + case PCI_DEVICE_ID_PLX_R753: + seekcard = PCI_DEVICE_ID_PLX_DJINN_ITOO; break; } } @@ -612,7 +620,7 @@ setup_gazelpci(struct IsdnCardState *cs) cs->irq_flags |= SA_SHIRQ; switch (seekcard) { - case GAZEL_R685: + case PCI_DEVICE_ID_PLX_R685: printk(KERN_INFO "Gazel: Card PCI R685 found\n"); cs->subtyp = R685; cs->dc.isac.adf2 = 0x87; @@ -623,8 +631,8 @@ setup_gazelpci(struct IsdnCardState *cs) "Gazel: hscx A:0x%X hscx B:0x%X\n", cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]); break; - case GAZEL_R753: - case GAZEL_DJINN_ITOO: + case PCI_DEVICE_ID_PLX_R753: + case PCI_DEVICE_ID_PLX_DJINN_ITOO: printk(KERN_INFO "Gazel: Card PCI R753 found\n"); cs->subtyp = R753; test_and_set_bit(HW_IPAC, &cs->HW_Flags); diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c index f28585a84..bd1442046 100644 --- a/drivers/isdn/hisax/hfc_2bs0.c +++ b/drivers/isdn/hisax/hfc_2bs0.c @@ -1,4 +1,4 @@ -/* $Id: hfc_2bs0.c,v 1.14 2000/06/26 08:59:13 keil Exp $ +/* $Id: hfc_2bs0.c,v 1.15 2000/07/26 20:46:47 keil Exp $ * * specific routines for CCD's HFC 2BS0 * @@ -203,7 +203,7 @@ hfc_empty_fifo(struct BCState *bcs, int count) ptr = skb_put(skb, count); idx = 0; cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); - while ((idx < count - 3) && WaitNoBusy(cs)) { + while ((idx < count) && WaitNoBusy(cs)) { *ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); idx++; } diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index ac673c227..c0ff9b642 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -1,4 +1,4 @@ -/* $Id: hfc_pci.c,v 1.30 2000/06/26 08:59:13 keil Exp $ +/* $Id: hfc_pci.c,v 1.31 2000/08/20 07:32:55 keil Exp $ * hfc_pci.c low level driver for CCD´s hfc-pci based cards * @@ -34,7 +34,7 @@ extern const char *CardType[]; -static const char *hfcpci_revision = "$Revision: 1.30 $"; +static const char *hfcpci_revision = "$Revision: 1.31 $"; /* table entry in the PCI devices list */ typedef struct { @@ -44,7 +44,9 @@ typedef struct { char *card_name; } PCI_ENTRY; -#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */ +#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */ +#define CLKDEL_TE 0x0e /* CLKDEL in TE mode */ +#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */ static const PCI_ENTRY id_list[] = { @@ -63,7 +65,10 @@ static const PCI_ENTRY id_list[] = {0x1051, 0x0100, "Motorola MC145575", "MC145575"}, {0x1397, 0xB100, "Seyeon", "B100"}, {0x15B0, 0x2BD0, "Zoltrix", "2BD0"}, - {0x114f, 0x71, "Digi intl.","Digicom"}, + {0x114F, 0x70,"Digi International", "Digi DataFire Micro V IOM2 (Europe)"}, + {0x114F, 0x71,"Digi International", "Digi DataFire Micro V (Europe)"}, + {0x114F, 0x72,"Digi International", "Digi DataFire Micro V IOM2 (North America)"}, + {0x114F, 0x73,"Digi International", "Digi DataFire Micro V (North America)"}, {0, 0, NULL, NULL}, }; @@ -130,7 +135,7 @@ reset_hfcpci(struct IsdnCardState *cs) cs->hw.hfcpci.trm = 0 + HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */ Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm); - Write_hfc(cs, HFCPCI_CLKDEL, 0x0e); /* ST-Bit delay for TE-Mode */ + Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_TE); /* ST-Bit delay for TE-Mode */ cs->hw.hfcpci.sctrl_e = HFCPCI_AUTO_AWAKE; Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e); /* S/T Auto awake */ cs->hw.hfcpci.bswapped = 0; /* no exchange */ @@ -254,6 +259,9 @@ hfcpci_empty_fifo(struct BCState *bcs, bzfifo_type * bz, u_char * bdata, int cou (*(bdata + (zp->z1 - B_SUB_VAL)))) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "hfcpci_empty_fifo: incoming packet invalid length %d or crc", count); +#ifdef ERROR_STATISTIC + bcs->err_inv++; +#endif bz->za[new_f2].z2 = new_z2; bz->f2 = new_f2; /* next buffer */ skb = NULL; @@ -320,6 +328,9 @@ receive_dmsg(struct IsdnCardState *cs) (df->data[zp->z1])) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "empty_fifo hfcpci paket inv. len %d or crc %d", rcnt, df->data[zp->z1]); +#ifdef ERROR_STATISTIC + cs->err_rx++; +#endif df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */ df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + rcnt) & (D_FIFO_SIZE - 1); } else if ((skb = dev_alloc_skb(rcnt - 3))) { @@ -506,6 +517,9 @@ hfcpci_fill_dfifo(struct IsdnCardState *cs) if (fcnt > (MAX_D_FRAMES - 1)) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "hfcpci_fill_Dfifo more as 14 frames"); +#ifdef ERROR_STATISTIC + cs->err_tx++; +#endif return; } /* now determine free bytes in FIFO buffer */ @@ -740,6 +754,7 @@ hfcpci_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic) (!(cs->hw.hfcpci.int_m1 & (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC + HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC)))) { save_flags(flags); cli(); + Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_NT); /* ST-Bit delay for NT-Mode */ Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0); /* HFC ST G0 */ udelay(10); cs->hw.hfcpci.sctrl |= SCTRL_MODE_NT; @@ -1625,6 +1640,9 @@ __initfunc(int int i; struct pci_dev *tmp_hfcpci = NULL; +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif strcpy(tmp, hfcpci_revision); printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp)); #if CONFIG_PCI @@ -1645,7 +1663,7 @@ __initfunc(int if (tmp_hfcpci) { if (pci_enable_device(tmp_hfcpci)) continue; - if ((card->para[0]) && (card->para[0] != pci_resource_start(tmp_hfcpci, 0))) + if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[ 0].start & PCI_BASE_ADDRESS_IO_MASK))) continue; else break; diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index 11d38baf2..abc215f87 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -39,8 +39,11 @@ #define HW_POWERUP 0x0008 #define HW_ACTIVATE 0x0010 #define HW_DEACTIVATE 0x0018 + +#define HW_INFO1 0x0010 #define HW_INFO2 0x0020 #define HW_INFO3 0x0030 +#define HW_INFO4 0x0040 #define HW_INFO4_P8 0x0040 #define HW_INFO4_P10 0x0048 #define HW_RSYNC 0x0060 @@ -90,6 +93,7 @@ #define CC_SUSPEND 0x0370 #define CC_PROCEED_SEND 0x0374 #define CC_REDIR 0x0378 +#define CC_T302 0x0382 #define CC_T303 0x0383 #define CC_T304 0x0384 #define CC_T305 0x0385 @@ -100,6 +104,7 @@ #define CC_T313 0x0393 #define CC_T318 0x0398 #define CC_T319 0x0399 +#define CC_TSPID 0x03A0 #define CC_NOSETUP_RSP 0x03E0 #define CC_SETUP_ERR 0x03E1 #define CC_SUSPEND_ERR 0x03E2 @@ -108,6 +113,7 @@ #define CC_RELEASE_ERR 0x03E5 #define CC_RESTART 0x03F4 #define CC_TDSS1_IO 0x13F4 /* DSS1 IO user timer */ +#define CC_TNI1_IO 0x13F5 /* NI1 IO user timer */ /* define maximum number of possible waiting incoming calls */ #define MAX_WAITING_CALLS 2 @@ -115,13 +121,19 @@ #ifdef __KERNEL__ -/* include only l3dss1 specific process structures, but no other defines */ +/* include l3dss1 & ni1 specific process structures, but no other defines */ #ifdef CONFIG_HISAX_EURO #define l3dss1_process #include "l3dss1.h" #undef l3dss1_process #endif CONFIG_HISAX_EURO +#ifdef CONFIG_HISAX_NI1 + #define l3ni1_process + #include "l3ni1.h" + #undef l3ni1_process +#endif CONFIG_HISAX_NI1 + #define MAX_DFRAME_LEN 260 #define MAX_DFRAME_LEN_L1 300 #define HSCX_BUFMAX 4096 @@ -184,6 +196,7 @@ struct L3Timer { #define FLG_L1_ACTTIMER 4 #define FLG_L1_T3RUN 5 #define FLG_L1_PULL_REQ 6 +#define FLG_L1_UINT 7 struct Layer1 { void *hardware; @@ -298,7 +311,7 @@ struct PStack { struct Layer3 l3; struct LLInterface lli; struct Management ma; - int protocol; /* EDSS1 or 1TR6 */ + int protocol; /* EDSS1, 1TR6 or NI1 */ /* protocol specific data fields */ union @@ -306,6 +319,9 @@ struct PStack { #ifdef CONFIG_HISAX_EURO dss1_stk_priv dss1; /* private dss1 data */ #endif CONFIG_HISAX_EURO +#ifdef CONFIG_HISAX_NI1 + ni1_stk_priv ni1; /* private ni1 data */ +#endif CONFIG_HISAX_NI1 } prot; }; @@ -327,6 +343,9 @@ struct l3_process { #ifdef CONFIG_HISAX_EURO dss1_proc_priv dss1; /* private dss1 data */ #endif CONFIG_HISAX_EURO +#ifdef CONFIG_HISAX_NI1 + ni1_proc_priv ni1; /* private ni1 data */ +#endif CONFIG_HISAX_NI1 } prot; }; @@ -373,10 +392,17 @@ struct isar_hw { }; struct hdlc_stat_reg { +#ifdef __BIG_ENDIAN + u_char fill __attribute__((packed)); + u_char mode __attribute__((packed)); + u_char xml __attribute__((packed)); + u_char cmd __attribute__((packed)); +#else u_char cmd __attribute__((packed)); u_char xml __attribute__((packed)); u_char mode __attribute__((packed)); u_char fill __attribute__((packed)); +#endif }; struct hdlc_hw { @@ -805,6 +831,22 @@ struct w6692_chip { int ph_state; }; +struct icc_chip { + int ph_state; + u_char *mon_tx; + u_char *mon_rx; + int mon_txp; + int mon_txc; + int mon_rxp; + struct arcofi_msg *arcofi_list; + struct timer_list arcofitimer; + wait_queue_head_t arcofi_wait; + u_char arcofi_bc; + u_char arcofi_state; + u_char mocr; + u_char adf2; +}; + #define HW_IOM1 0 #define HW_IPAC 1 #define HW_ISAR 2 @@ -815,6 +857,7 @@ struct w6692_chip { #define FLG_LOCK_ATOMIC 7 #define FLG_ARCOFI_TIMER 8 #define FLG_ARCOFI_ERROR 9 +#define FLG_HW_L1_UINT 10 struct IsdnCardState { unsigned char typ; @@ -883,6 +926,7 @@ struct IsdnCardState { struct hfcpci_chip hfcpci; struct hfcsx_chip hfcsx; struct w6692_chip w6692; + struct icc_chip icc; } dc; u_char *rcvbuf; int rcvidx; @@ -924,7 +968,7 @@ struct IsdnCardState { #define ISDN_CTYPE_MIC 17 #define ISDN_CTYPE_ELSA_PCI 18 #define ISDN_CTYPE_COMPAQ_ISA 19 -#define ISDN_CTYPE_NETJET 20 +#define ISDN_CTYPE_NETJET_S 20 #define ISDN_CTYPE_TELESPCI 21 #define ISDN_CTYPE_SEDLBAUER_PCMCIA 22 #define ISDN_CTYPE_AMD7930 23 @@ -942,7 +986,8 @@ struct IsdnCardState { #define ISDN_CTYPE_HFC_PCI 35 #define ISDN_CTYPE_W6692 36 #define ISDN_CTYPE_HFC_SX 37 -#define ISDN_CTYPE_COUNT 37 +#define ISDN_CTYPE_NETJET_U 38 +#define ISDN_CTYPE_COUNT 38 #ifdef ISDN_CHIP_ISAC @@ -1091,12 +1136,12 @@ struct IsdnCardState { #endif #ifdef CONFIG_HISAX_NETJET -#define CARD_NETJET 1 +#define CARD_NETJET_S 1 #ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif #else -#define CARD_NETJET 0 +#define CARD_NETJET_S 0 #endif #ifdef CONFIG_HISAX_HFCS @@ -1204,17 +1249,19 @@ struct IsdnCardState { #define CARD_W6692 0 #endif -#define TEI_PER_CARD 0 - -#ifdef CONFIG_HISAX_1TR6 -#undef TEI_PER_CARD -#define TEI_PER_CARD 1 +#ifdef CONFIG_HISAX_NETJET_U +#define CARD_NETJET_U 1 +#ifndef ISDN_CHIP_ICC +#define ISDN_CHIP_ICC 1 +#endif +#ifndef HISAX_UINTERFACE +#define HISAX_UINTERFACE 1 +#endif +#else +#define CARD_NETJET_U 0 #endif -#ifdef CONFIG_HISAX_EURO -#undef TEI_PER_CARD #define TEI_PER_CARD 1 -#endif /* L1 Debug */ #define L1_DEB_WARN 0x01 @@ -1238,7 +1285,7 @@ extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, struct IsdnCard { int typ; - int protocol; /* EDSS1 or 1TR6 */ + int protocol; /* EDSS1, 1TR6 or NI1 */ unsigned int para[4]; struct IsdnCardState *cs; }; diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c new file mode 100644 index 000000000..5f2740e9e --- /dev/null +++ b/drivers/isdn/hisax/icc.c @@ -0,0 +1,685 @@ +// $Id: icc.c,v 1.3 2000/08/20 07:34:04 keil Exp $ +//----------------------------------------------------------------------------- +// +// ICC specific routines +// +// Author Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd +// www.traverse.com.au +// +// 1999.6.25 Initial implementation of routines for Siemens ISDN +// Communication Controler PEB 2070 based on the ISAC routines +// written by Karsten Keil. +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- + +#define __NO_VERSION__ +#include "hisax.h" +#include "icc.h" +// #include "arcofi.h" +#include "isdnl1.h" +#include <linux/interrupt.h> + +#define DBUSY_TIMER_VALUE 80 +#define ARCOFI_USE 0 + +static char *ICCVer[] HISAX_INITDATA = +{"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"}; + +void +ICCVersion(struct IsdnCardState *cs, char *s) +{ + int val; + + val = cs->readisac(cs, ICC_RBCH); + printk(KERN_INFO "%s ICC version (%x): %s\n", s, val, ICCVer[(val >> 5) & 3]); +} + +static void +ph_command(struct IsdnCardState *cs, unsigned int command) +{ + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ph_command %x", command); + cs->writeisac(cs, ICC_CIX0, (command << 2) | 3); +} + + +static void +icc_new_ph(struct IsdnCardState *cs) +{ + switch (cs->dc.icc.ph_state) { + case (ICC_IND_EI1): + ph_command(cs, ICC_CMD_DI); + l1_msg(cs, HW_RESET | INDICATION, NULL); + break; + case (ICC_IND_DC): + l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); + break; + case (ICC_IND_DR): + l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); + break; + case (ICC_IND_PU): + l1_msg(cs, HW_POWERUP | CONFIRM, NULL); + break; + case (ICC_IND_FJ): + l1_msg(cs, HW_RSYNC | INDICATION, NULL); + break; + case (ICC_IND_AR): + l1_msg(cs, HW_INFO2 | INDICATION, NULL); + break; + case (ICC_IND_AI): + l1_msg(cs, HW_INFO4 | INDICATION, NULL); + break; + default: + break; + } +} + +static void +icc_bh(struct IsdnCardState *cs) +{ + struct PStack *stptr; + + if (!cs) + return; + if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { + if (cs->debug) + debugl1(cs, "D-Channel Busy cleared"); + stptr = cs->stlist; + while (stptr != NULL) { + stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); + stptr = stptr->next; + } + } + if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) + icc_new_ph(cs); + if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) + DChannel_proc_rcv(cs); + if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) + DChannel_proc_xmt(cs); +#if ARCOFI_USE + if (!test_bit(HW_ARCOFI, &cs->HW_Flags)) + return; + if (test_and_clear_bit(D_RX_MON1, &cs->event)) + arcofi_fsm(cs, ARCOFI_RX_END, NULL); + if (test_and_clear_bit(D_TX_MON1, &cs->event)) + arcofi_fsm(cs, ARCOFI_TX_END, NULL); +#endif +} + +void +icc_empty_fifo(struct IsdnCardState *cs, int count) +{ + u_char *ptr; + long flags; + + if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) + debugl1(cs, "icc_empty_fifo"); + + if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "icc_empty_fifo overrun %d", + cs->rcvidx + count); + cs->writeisac(cs, ICC_CMDR, 0x80); + cs->rcvidx = 0; + return; + } + ptr = cs->rcvbuf + cs->rcvidx; + cs->rcvidx += count; + save_flags(flags); + cli(); + cs->readisacfifo(cs, ptr, count); + cs->writeisac(cs, ICC_CMDR, 0x80); + restore_flags(flags); + if (cs->debug & L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "icc_empty_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } +} + +static void +icc_fill_fifo(struct IsdnCardState *cs) +{ + int count, more; + u_char *ptr; + long flags; + + if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) + debugl1(cs, "icc_fill_fifo"); + + if (!cs->tx_skb) + return; + + count = cs->tx_skb->len; + if (count <= 0) + return; + + more = 0; + if (count > 32) { + more = !0; + count = 32; + } + save_flags(flags); + cli(); + ptr = cs->tx_skb->data; + skb_pull(cs->tx_skb, count); + cs->tx_cnt += count; + cs->writeisacfifo(cs, ptr, count); + cs->writeisac(cs, ICC_CMDR, more ? 0x8 : 0xa); + if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { + debugl1(cs, "icc_fill_fifo dbusytimer running"); + del_timer(&cs->dbusytimer); + } + init_timer(&cs->dbusytimer); + cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); + add_timer(&cs->dbusytimer); + restore_flags(flags); + if (cs->debug & L1_DEB_ISAC_FIFO) { + char *t = cs->dlog; + + t += sprintf(t, "icc_fill_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(cs, cs->dlog); + } +} + +void +icc_sched_event(struct IsdnCardState *cs, int event) +{ + test_and_set_bit(event, &cs->event); + queue_task(&cs->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +void +icc_interrupt(struct IsdnCardState *cs, u_char val) +{ + u_char exval, v1; + struct sk_buff *skb; + unsigned int count; + long flags; + + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ICC interrupt %x", val); + if (val & 0x80) { /* RME */ + exval = cs->readisac(cs, ICC_RSTA); + if ((exval & 0x70) != 0x20) { + if (exval & 0x40) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC RDO"); +#ifdef ERROR_STATISTIC + cs->err_rx++; +#endif + } + if (!(exval & 0x20)) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC CRC error"); +#ifdef ERROR_STATISTIC + cs->err_crc++; +#endif + } + cs->writeisac(cs, ICC_CMDR, 0x80); + } else { + count = cs->readisac(cs, ICC_RBCL) & 0x1f; + if (count == 0) + count = 32; + icc_empty_fifo(cs, count); + save_flags(flags); + cli(); + if ((count = cs->rcvidx) > 0) { + cs->rcvidx = 0; + if (!(skb = alloc_skb(count, GFP_ATOMIC))) + printk(KERN_WARNING "HiSax: D receive out of memory\n"); + else { + memcpy(skb_put(skb, count), cs->rcvbuf, count); + skb_queue_tail(&cs->rq, skb); + } + } + restore_flags(flags); + } + cs->rcvidx = 0; + icc_sched_event(cs, D_RCVBUFREADY); + } + if (val & 0x40) { /* RPF */ + icc_empty_fifo(cs, 32); + } + if (val & 0x20) { /* RSC */ + /* never */ + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC RSC interrupt"); + } + if (val & 0x10) { /* XPR */ + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + icc_sched_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { + if (cs->tx_skb->len) { + icc_fill_fifo(cs); + goto afterXPR; + } else { + dev_kfree_skb_irq(cs->tx_skb); + cs->tx_cnt = 0; + cs->tx_skb = NULL; + } + } + if ((cs->tx_skb = skb_dequeue(&cs->sq))) { + cs->tx_cnt = 0; + icc_fill_fifo(cs); + } else + icc_sched_event(cs, D_XMTBUFREADY); + } + afterXPR: + if (val & 0x04) { /* CISQ */ + exval = cs->readisac(cs, ICC_CIR0); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ICC CIR0 %02X", exval ); + if (exval & 2) { + cs->dc.icc.ph_state = (exval >> 2) & 0xf; + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ph_state change %x", cs->dc.icc.ph_state); + icc_sched_event(cs, D_L1STATECHANGE); + } + if (exval & 1) { + exval = cs->readisac(cs, ICC_CIR1); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ICC CIR1 %02X", exval ); + } + } + if (val & 0x02) { /* SIN */ + /* never */ + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC SIN interrupt"); + } + if (val & 0x01) { /* EXI */ + exval = cs->readisac(cs, ICC_EXIR); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC EXIR %02x", exval); + if (exval & 0x80) { /* XMR */ + debugl1(cs, "ICC XMR"); + printk(KERN_WARNING "HiSax: ICC XMR\n"); + } + if (exval & 0x40) { /* XDU */ + debugl1(cs, "ICC XDU"); + printk(KERN_WARNING "HiSax: ICC XDU\n"); +#ifdef ERROR_STATISTIC + cs->err_tx++; +#endif + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + icc_sched_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { /* Restart frame */ + skb_push(cs->tx_skb, cs->tx_cnt); + cs->tx_cnt = 0; + icc_fill_fifo(cs); + } else { + printk(KERN_WARNING "HiSax: ICC XDU no skb\n"); + debugl1(cs, "ICC XDU no skb"); + } + } + if (exval & 0x04) { /* MOS */ + v1 = cs->readisac(cs, ICC_MOSR); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC MOSR %02x", v1); +#if ARCOFI_USE + if (v1 & 0x08) { + if (!cs->dc.icc.mon_rx) { + if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC MON RX out of memory!"); + cs->dc.icc.mocr &= 0xf0; + cs->dc.icc.mocr |= 0x0a; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + goto afterMONR0; + } else + cs->dc.icc.mon_rxp = 0; + } + if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) { + cs->dc.icc.mocr &= 0xf0; + cs->dc.icc.mocr |= 0x0a; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mon_rxp = 0; + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC MON RX overflow!"); + goto afterMONR0; + } + cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR0); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC MOR0 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]); + if (cs->dc.icc.mon_rxp == 1) { + cs->dc.icc.mocr |= 0x04; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + } + } + afterMONR0: + if (v1 & 0x80) { + if (!cs->dc.icc.mon_rx) { + if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC MON RX out of memory!"); + cs->dc.icc.mocr &= 0x0f; + cs->dc.icc.mocr |= 0xa0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + goto afterMONR1; + } else + cs->dc.icc.mon_rxp = 0; + } + if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) { + cs->dc.icc.mocr &= 0x0f; + cs->dc.icc.mocr |= 0xa0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mon_rxp = 0; + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ICC MON RX overflow!"); + goto afterMONR1; + } + cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR1); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC MOR1 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]); + cs->dc.icc.mocr |= 0x40; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + } + afterMONR1: + if (v1 & 0x04) { + cs->dc.icc.mocr &= 0xf0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mocr |= 0x0a; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + icc_sched_event(cs, D_RX_MON0); + } + if (v1 & 0x40) { + cs->dc.icc.mocr &= 0x0f; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mocr |= 0xa0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + icc_sched_event(cs, D_RX_MON1); + } + if (v1 & 0x02) { + if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && + (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && + !(v1 & 0x08))) { + cs->dc.icc.mocr &= 0xf0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mocr |= 0x0a; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + if (cs->dc.icc.mon_txc && + (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) + icc_sched_event(cs, D_TX_MON0); + goto AfterMOX0; + } + if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) { + icc_sched_event(cs, D_TX_MON0); + goto AfterMOX0; + } + cs->writeisac(cs, ICC_MOX0, + cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC %02x -> MOX0", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]); + } + AfterMOX0: + if (v1 & 0x20) { + if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && + (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && + !(v1 & 0x80))) { + cs->dc.icc.mocr &= 0x0f; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + cs->dc.icc.mocr |= 0xa0; + cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); + if (cs->dc.icc.mon_txc && + (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) + icc_sched_event(cs, D_TX_MON1); + goto AfterMOX1; + } + if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) { + icc_sched_event(cs, D_TX_MON1); + goto AfterMOX1; + } + cs->writeisac(cs, ICC_MOX1, + cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ICC %02x -> MOX1", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]); + } + AfterMOX1: +#endif + } + } +} + +static void +ICC_l1hw(struct PStack *st, int pr, void *arg) +{ + struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; + struct sk_buff *skb = arg; + int val; + + switch (pr) { + case (PH_DATA |REQUEST): + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + if (cs->tx_skb) { + skb_queue_tail(&cs->sq, skb); +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA Queued", 0); +#endif + } else { + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA", 0); +#endif + icc_fill_fifo(cs); + } + break; + case (PH_PULL |INDICATION): + if (cs->tx_skb) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); + skb_queue_tail(&cs->sq, skb); + break; + } + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); +#endif + icc_fill_fifo(cs); + break; + case (PH_PULL | REQUEST): +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + debugl1(cs, "-> PH_REQUEST_PULL"); +#endif + if (!cs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + break; + case (HW_RESET | REQUEST): + if ((cs->dc.icc.ph_state == ICC_IND_EI1) || + (cs->dc.icc.ph_state == ICC_IND_DR)) + ph_command(cs, ICC_CMD_DI); + else + ph_command(cs, ICC_CMD_RES); + break; + case (HW_ENABLE | REQUEST): + ph_command(cs, ICC_CMD_DI); + break; + case (HW_INFO1 | REQUEST): + ph_command(cs, ICC_CMD_AR); + break; + case (HW_INFO3 | REQUEST): + ph_command(cs, ICC_CMD_AI); + break; + case (HW_TESTLOOP | REQUEST): + val = 0; + if (1 & (long) arg) + val |= 0x0c; + if (2 & (long) arg) + val |= 0x3; + if (test_bit(HW_IOM1, &cs->HW_Flags)) { + /* IOM 1 Mode */ + if (!val) { + cs->writeisac(cs, ICC_SPCR, 0xa); + cs->writeisac(cs, ICC_ADF1, 0x2); + } else { + cs->writeisac(cs, ICC_SPCR, val); + cs->writeisac(cs, ICC_ADF1, 0xa); + } + } else { + /* IOM 2 Mode */ + cs->writeisac(cs, ICC_SPCR, val); + if (val) + cs->writeisac(cs, ICC_ADF1, 0x8); + else + cs->writeisac(cs, ICC_ADF1, 0x0); + } + break; + case (HW_DEACTIVATE | RESPONSE): + discard_queue(&cs->rq); + discard_queue(&cs->sq); + if (cs->tx_skb) { + dev_kfree_skb_any(cs->tx_skb); + cs->tx_skb = NULL; + } + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + icc_sched_event(cs, D_CLEARBUSY); + break; + default: + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "icc_l1hw unknown %04x", pr); + break; + } +} + +void +setstack_icc(struct PStack *st, struct IsdnCardState *cs) +{ + st->l1.l1hw = ICC_l1hw; +} + +void +DC_Close_icc(struct IsdnCardState *cs) { + if (cs->dc.icc.mon_rx) { + kfree(cs->dc.icc.mon_rx); + cs->dc.icc.mon_rx = NULL; + } + if (cs->dc.icc.mon_tx) { + kfree(cs->dc.icc.mon_tx); + cs->dc.icc.mon_tx = NULL; + } +} + +static void +dbusy_timer_handler(struct IsdnCardState *cs) +{ + struct PStack *stptr; + int rbch, star; + + if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { + rbch = cs->readisac(cs, ICC_RBCH); + star = cs->readisac(cs, ICC_STAR); + if (cs->debug) + debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x", + rbch, star); + if (rbch & ICC_RBCH_XAC) { /* D-Channel Busy */ + test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); + stptr = cs->stlist; + while (stptr != NULL) { + stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); + stptr = stptr->next; + } + } else { + /* discard frame; reset transceiver */ + test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); + if (cs->tx_skb) { + dev_kfree_skb_any(cs->tx_skb); + cs->tx_cnt = 0; + cs->tx_skb = NULL; + } else { + printk(KERN_WARNING "HiSax: ICC D-Channel Busy no skb\n"); + debugl1(cs, "D-Channel Busy no skb"); + } + cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */ + cs->irq_func(cs->irq, cs, NULL); + } + } +} + +HISAX_INITFUNC(void +initicc(struct IsdnCardState *cs)) +{ + cs->tqueue.routine = (void *) (void *) icc_bh; + cs->setstack_d = setstack_icc; + cs->DC_Close = DC_Close_icc; + cs->dc.icc.mon_tx = NULL; + cs->dc.icc.mon_rx = NULL; + cs->dbusytimer.function = (void *) dbusy_timer_handler; + cs->dbusytimer.data = (long) cs; + init_timer(&cs->dbusytimer); + cs->writeisac(cs, ICC_MASK, 0xff); + cs->dc.icc.mocr = 0xaa; + if (test_bit(HW_IOM1, &cs->HW_Flags)) { + /* IOM 1 Mode */ + cs->writeisac(cs, ICC_ADF2, 0x0); + cs->writeisac(cs, ICC_SPCR, 0xa); + cs->writeisac(cs, ICC_ADF1, 0x2); + cs->writeisac(cs, ICC_STCR, 0x70); + cs->writeisac(cs, ICC_MODE, 0xc9); + } else { + /* IOM 2 Mode */ + if (!cs->dc.icc.adf2) + cs->dc.icc.adf2 = 0x80; + cs->writeisac(cs, ICC_ADF2, cs->dc.icc.adf2); + cs->writeisac(cs, ICC_SQXR, 0xa0); + cs->writeisac(cs, ICC_SPCR, 0x20); + cs->writeisac(cs, ICC_STCR, 0x70); + cs->writeisac(cs, ICC_MODE, 0xca); + cs->writeisac(cs, ICC_TIMR, 0x00); + cs->writeisac(cs, ICC_ADF1, 0x20); + } + ph_command(cs, ICC_CMD_RES); + cs->writeisac(cs, ICC_MASK, 0x0); + ph_command(cs, ICC_CMD_DI); +} + +HISAX_INITFUNC(void +clear_pending_icc_ints(struct IsdnCardState *cs)) +{ + int val, eval; + + val = cs->readisac(cs, ICC_STAR); + debugl1(cs, "ICC STAR %x", val); + val = cs->readisac(cs, ICC_MODE); + debugl1(cs, "ICC MODE %x", val); + val = cs->readisac(cs, ICC_ADF2); + debugl1(cs, "ICC ADF2 %x", val); + val = cs->readisac(cs, ICC_ISTA); + debugl1(cs, "ICC ISTA %x", val); + if (val & 0x01) { + eval = cs->readisac(cs, ICC_EXIR); + debugl1(cs, "ICC EXIR %x", eval); + } + val = cs->readisac(cs, ICC_CIR0); + debugl1(cs, "ICC CIR0 %x", val); + cs->dc.icc.ph_state = (val >> 2) & 0xf; + icc_sched_event(cs, D_L1STATECHANGE); + /* Disable all IRQ */ + cs->writeisac(cs, ICC_MASK, 0xFF); +} diff --git a/drivers/isdn/hisax/icc.h b/drivers/isdn/hisax/icc.h new file mode 100644 index 000000000..b3ecbdcf8 --- /dev/null +++ b/drivers/isdn/hisax/icc.h @@ -0,0 +1,73 @@ +// $Id: icc.h,v 1.2 2000/06/26 08:59:13 keil Exp $ +//----------------------------------------------------------------------------- +// +// ICC specific routines +// +// Author Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd +// www.traverse.com.au +// +// 1999.7.14 Initial implementation of routines for Siemens ISDN +// Communication Controler PEB 2070 based on the ISAC routines +// written by Karsten Keil. +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- + + +/* All Registers original Siemens Spec */ + +#define ICC_MASK 0x20 +#define ICC_ISTA 0x20 +#define ICC_STAR 0x21 +#define ICC_CMDR 0x21 +#define ICC_EXIR 0x24 +#define ICC_ADF2 0x39 +#define ICC_SPCR 0x30 +#define ICC_ADF1 0x38 +#define ICC_CIR0 0x31 +#define ICC_CIX0 0x31 +#define ICC_CIR1 0x33 +#define ICC_CIX1 0x33 +#define ICC_STCR 0x37 +#define ICC_MODE 0x22 +#define ICC_RSTA 0x27 +#define ICC_RBCL 0x25 +#define ICC_RBCH 0x2A +#define ICC_TIMR 0x23 +#define ICC_SQXR 0x3b +#define ICC_MOSR 0x3a +#define ICC_MOCR 0x3a +#define ICC_MOR0 0x32 +#define ICC_MOX0 0x32 +#define ICC_MOR1 0x34 +#define ICC_MOX1 0x34 + +#define ICC_RBCH_XAC 0x80 + +#define ICC_CMD_TIM 0x0 +#define ICC_CMD_RES 0x1 +#define ICC_CMD_DU 0x3 +#define ICC_CMD_EI1 0x4 +#define ICC_CMD_SSP 0x5 +#define ICC_CMD_DT 0x6 +#define ICC_CMD_AR 0x8 +#define ICC_CMD_ARL 0xA +#define ICC_CMD_AI 0xC +#define ICC_CMD_DI 0xF + +#define ICC_IND_DR 0x0 +#define ICC_IND_FJ 0x2 +#define ICC_IND_EI1 0x4 +#define ICC_IND_INT 0x6 +#define ICC_IND_PU 0x7 +#define ICC_IND_AR 0x8 +#define ICC_IND_ARL 0xA +#define ICC_IND_AI 0xC +#define ICC_IND_AIL 0xE +#define ICC_IND_DC 0xF + +extern void ICCVersion(struct IsdnCardState *cs, char *s); +extern void initicc(struct IsdnCardState *cs); +extern void icc_interrupt(struct IsdnCardState *cs, u_char val); +extern void clear_pending_icc_ints(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c index 6f19d6cb6..d91f86f02 100644 --- a/drivers/isdn/hisax/isar.c +++ b/drivers/isdn/hisax/isar.c @@ -243,6 +243,14 @@ isar_load_firmware(struct IsdnCardState *cs, u_char *buf) printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret); goto reterror; } +#ifdef __BIG_ENDIAN + sadr = (blk_head.sadr & 0xff)*256 + blk_head.sadr/256; + blk_head.sadr = sadr; + sadr = (blk_head.len & 0xff)*256 + blk_head.len/256; + blk_head.len = sadr; + sadr = (blk_head.d_key & 0xff)*256 + blk_head.d_key/256; + blk_head.d_key = sadr; +#endif /* __BIG_ENDIAN */ cnt += BLK_HEAD_SIZE; p += BLK_HEAD_SIZE; printk(KERN_DEBUG"isar firmware block (%#x,%5d,%#x)\n", @@ -284,8 +292,13 @@ isar_load_firmware(struct IsdnCardState *cs, u_char *buf) #endif sadr += noc; while(noc) { +#ifdef __BIG_ENDIAN + *mp++ = *sp % 256; + *mp++ = *sp / 256; +#else *mp++ = *sp / 256; *mp++ = *sp % 256; +#endif /* __BIG_ENDIAN */ sp++; noc--; } @@ -528,8 +541,9 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs) rcv_mbox(cs, ireg, ptr); if (ireg->cmsb & HDLC_FED) { if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */ - printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n", - bcs->hw.isar.rcvidx); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar frame to short %d", + bcs->hw.isar.rcvidx); } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx-2))) { printk(KERN_WARNING "ISAR: receive out of memory\n"); } else { @@ -538,6 +552,7 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs) skb_queue_tail(&bcs->rqueue, skb); isar_sched_event(bcs, B_RCVBUFREADY); } + bcs->hw.isar.rcvidx = 0; } } break; @@ -606,13 +621,16 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs) bcs->hw.isar.rcvidx += ireg->clsb; rcv_mbox(cs, ireg, ptr); if (ireg->cmsb & HDLC_FED) { + int len = bcs->hw.isar.rcvidx + + dle_count(bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx); if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */ - printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n", - bcs->hw.isar.rcvidx); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar frame to short %d", + bcs->hw.isar.rcvidx); } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) { printk(KERN_WARNING "ISAR: receive out of memory\n"); } else { - memcpy(skb_put(skb, bcs->hw.isar.rcvidx), + insert_dle((u_char *)skb_put(skb, len), bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx); skb_queue_tail(&bcs->rqueue, skb); @@ -620,8 +638,20 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs) send_DLE_ETX(bcs); isar_sched_event(bcs, B_LL_OK); } + bcs->hw.isar.rcvidx = 0; } } + if (ireg->cmsb & SART_NMD) { /* ABORT */ + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar_rcv_frame: no more data"); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + bcs->hw.isar.rcvidx = 0; + send_DLE_ETX(bcs); + sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | + ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); + bcs->hw.isar.state = STFAX_ESCAPE; + isar_sched_event(bcs, B_LL_NOCARRIER); + } break; default: printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode); @@ -1044,6 +1074,9 @@ isar_pump_statev_fax(struct BCState *bcs, u_char devt) { debugl1(cs, "pump stev RSP_DISC"); if (bcs->hw.isar.state == STFAX_ESCAPE) { switch(bcs->hw.isar.newcmd) { + case 0: + bcs->hw.isar.state = STFAX_READY; + break; case PCTRL_CMD_FTH: case PCTRL_CMD_FTM: p1 = 10; diff --git a/drivers/isdn/hisax/isar.h b/drivers/isdn/hisax/isar.h index 7726622ca..d34621834 100644 --- a/drivers/isdn/hisax/isar.h +++ b/drivers/isdn/hisax/isar.h @@ -186,7 +186,7 @@ #define HDLC_ERROR 0x1c #define HDLC_ERR_FAD 0x10 #define HDLC_ERR_RER 0x08 -#define HDLC_ERR_CER 0x01 +#define HDLC_ERR_CER 0x04 #define SART_NMD 0x01 #define BSTAT_RDM0 0x1 diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c index d0e734357..f523f378d 100644 --- a/drivers/isdn/hisax/isdnl1.c +++ b/drivers/isdn/hisax/isdnl1.c @@ -28,7 +28,7 @@ struct Fsm l1fsm_b = {NULL, 0, 0, NULL, NULL}; static -struct Fsm l1fsm_d = +struct Fsm l1fsm_s = {NULL, 0, 0, NULL, NULL}; enum { @@ -41,9 +41,9 @@ enum { ST_L1_F8, }; -#define L1D_STATE_COUNT (ST_L1_F8+1) +#define L1S_STATE_COUNT (ST_L1_F8+1) -static char *strL1DState[] = +static char *strL1SState[] = { "ST_L1_F2", "ST_L1_F3", @@ -54,6 +54,29 @@ static char *strL1DState[] = "ST_L1_F8", }; +#ifdef HISAX_UINTERFACE +static +struct Fsm l1fsm_u = +{NULL, 0, 0, NULL, NULL}; + +enum { + ST_L1_RESET, + ST_L1_DEACT, + ST_L1_SYNC2, + ST_L1_TRANS, +}; + +#define L1U_STATE_COUNT (ST_L1_TRANS+1) + +static char *strL1UState[] = +{ + "ST_L1_RESET", + "ST_L1_DEACT", + "ST_L1_SYNC2", + "ST_L1_TRANS", +}; +#endif + enum { ST_L1_NULL, ST_L1_WAIT_ACT, @@ -432,7 +455,7 @@ l1_deact_cnf(struct FsmInst *fi, int event, void *arg) } static void -l1_deact_req(struct FsmInst *fi, int event, void *arg) +l1_deact_req_s(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -442,7 +465,7 @@ l1_deact_req(struct FsmInst *fi, int event, void *arg) } static void -l1_power_up(struct FsmInst *fi, int event, void *arg) +l1_power_up_s(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -472,7 +495,12 @@ l1_info2_ind(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - FsmChangeState(fi, ST_L1_F6); +#ifdef HISAX_UINTERFACE + if (test_bit(FLG_L1_UINT, &st->l1.Flags)) + FsmChangeState(fi, ST_L1_SYNC2); + else +#endif + FsmChangeState(fi, ST_L1_F6); st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); } @@ -481,7 +509,12 @@ l1_info4_ind(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - FsmChangeState(fi, ST_L1_F7); +#ifdef HISAX_UINTERFACE + if (test_bit(FLG_L1_UINT, &st->l1.Flags)) + FsmChangeState(fi, ST_L1_TRANS); + else +#endif + FsmChangeState(fi, ST_L1_F7); st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); if (test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags)) FsmDelTimer(&st->l1.timer, 4); @@ -501,6 +534,10 @@ l1_timer3(struct FsmInst *fi, int event, void *arg) test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags); if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) L1deactivated(st->l1.hardware); + +#ifdef HISAX_UINTERFACE + if (!test_bit(FLG_L1_UINT, &st->l1.Flags)) +#endif if (st->l1.l1m.state != ST_L1_F6) { FsmChangeState(fi, ST_L1_F3); st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); @@ -529,7 +566,7 @@ l1_timer_deact(struct FsmInst *fi, int event, void *arg) } static void -l1_activate(struct FsmInst *fi, int event, void *arg) +l1_activate_s(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -547,9 +584,9 @@ l1_activate_no(struct FsmInst *fi, int event, void *arg) } } -static struct FsmNode L1DFnList[] HISAX_INITDATA = +static struct FsmNode L1SFnList[] HISAX_INITDATA = { - {ST_L1_F3, EV_PH_ACTIVATE, l1_activate}, + {ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s}, {ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no}, {ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no}, {ST_L1_F3, EV_RESET_IND, l1_reset}, @@ -564,10 +601,10 @@ static struct FsmNode L1DFnList[] HISAX_INITDATA = {ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf}, {ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf}, {ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F6, EV_DEACT_IND, l1_deact_req}, - {ST_L1_F7, EV_DEACT_IND, l1_deact_req}, - {ST_L1_F8, EV_DEACT_IND, l1_deact_req}, - {ST_L1_F3, EV_POWER_UP, l1_power_up}, + {ST_L1_F6, EV_DEACT_IND, l1_deact_req_s}, + {ST_L1_F7, EV_DEACT_IND, l1_deact_req_s}, + {ST_L1_F8, EV_DEACT_IND, l1_deact_req_s}, + {ST_L1_F3, EV_POWER_UP, l1_power_up_s}, {ST_L1_F4, EV_RSYNC_IND, l1_go_F5}, {ST_L1_F6, EV_RSYNC_IND, l1_go_F8}, {ST_L1_F7, EV_RSYNC_IND, l1_go_F8}, @@ -595,7 +632,68 @@ static struct FsmNode L1DFnList[] HISAX_INITDATA = {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact}, }; -#define L1D_FN_COUNT (sizeof(L1DFnList)/sizeof(struct FsmNode)) +#define L1S_FN_COUNT (sizeof(L1SFnList)/sizeof(struct FsmNode)) + +#ifdef HISAX_UINTERFACE +static void +l1_deact_req_u(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L1_RESET); + FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2); + test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags); + st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); +} + +static void +l1_power_up_u(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); + test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags); +} + +static void +l1_info0_ind(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_L1_DEACT); +} + +static void +l1_activate_u(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + st->l1.l1hw(st, HW_INFO1 | REQUEST, NULL); +} + +static struct FsmNode L1UFnList[] HISAX_INITDATA = +{ + {ST_L1_RESET, EV_DEACT_IND, l1_deact_req_u}, + {ST_L1_DEACT, EV_DEACT_IND, l1_deact_req_u}, + {ST_L1_SYNC2, EV_DEACT_IND, l1_deact_req_u}, + {ST_L1_TRANS, EV_DEACT_IND, l1_deact_req_u}, + {ST_L1_DEACT, EV_PH_ACTIVATE, l1_activate_u}, + {ST_L1_DEACT, EV_POWER_UP, l1_power_up_u}, + {ST_L1_DEACT, EV_INFO2_IND, l1_info2_ind}, + {ST_L1_TRANS, EV_INFO2_IND, l1_info2_ind}, + {ST_L1_RESET, EV_DEACT_CNF, l1_info0_ind}, + {ST_L1_DEACT, EV_INFO4_IND, l1_info4_ind}, + {ST_L1_SYNC2, EV_INFO4_IND, l1_info4_ind}, + {ST_L1_RESET, EV_INFO4_IND, l1_info4_ind}, + {ST_L1_DEACT, EV_TIMER3, l1_timer3}, + {ST_L1_SYNC2, EV_TIMER3, l1_timer3}, + {ST_L1_TRANS, EV_TIMER_ACT, l1_timer_act}, + {ST_L1_DEACT, EV_TIMER_DEACT, l1_timer_deact}, + {ST_L1_SYNC2, EV_TIMER_DEACT, l1_timer_deact}, + {ST_L1_RESET, EV_TIMER_DEACT, l1_timer_deact}, +}; + +#define L1U_FN_COUNT (sizeof(L1UFnList)/sizeof(struct FsmNode)) + +#endif static void l1b_activate(struct FsmInst *fi, int event, void *arg) @@ -645,11 +743,18 @@ static struct FsmNode L1BFnList[] HISAX_INITDATA = HISAX_INITFUNC(void Isdnl1New(void)) { - l1fsm_d.state_count = L1D_STATE_COUNT; - l1fsm_d.event_count = L1_EVENT_COUNT; - l1fsm_d.strEvent = strL1Event; - l1fsm_d.strState = strL1DState; - FsmNew(&l1fsm_d, L1DFnList, L1D_FN_COUNT); +#ifdef HISAX_UINTERFACE + l1fsm_u.state_count = L1U_STATE_COUNT; + l1fsm_u.event_count = L1_EVENT_COUNT; + l1fsm_u.strEvent = strL1Event; + l1fsm_u.strState = strL1UState; + FsmNew(&l1fsm_u, L1UFnList, L1U_FN_COUNT); +#endif + l1fsm_s.state_count = L1S_STATE_COUNT; + l1fsm_s.event_count = L1_EVENT_COUNT; + l1fsm_s.strEvent = strL1Event; + l1fsm_s.strState = strL1SState; + FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT); l1fsm_b.state_count = L1B_STATE_COUNT; l1fsm_b.event_count = L1_EVENT_COUNT; l1fsm_b.strEvent = strL1Event; @@ -659,7 +764,10 @@ HISAX_INITFUNC(void Isdnl1New(void)) void Isdnl1Free(void) { - FsmFree(&l1fsm_d); +#ifdef HISAX_UINTERFACE + FsmFree(&l1fsm_u); +#endif + FsmFree(&l1fsm_s); FsmFree(&l1fsm_b); } @@ -677,7 +785,7 @@ dch_l2l1(struct PStack *st, int pr, void *arg) case (PH_ACTIVATE | REQUEST): if (cs->debug) debugl1(cs, "PH_ACTIVATE_REQ %s", - strL1DState[st->l1.l1m.state]); + st->l1.l1m.fsm->strState[st->l1.l1m.state]); if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); else { @@ -757,8 +865,16 @@ setstack_HiSax(struct PStack *st, struct IsdnCardState *cs) { st->l1.hardware = cs; st->protocol = cs->protocol; - st->l1.l1m.fsm = &l1fsm_d; + st->l1.l1m.fsm = &l1fsm_s; st->l1.l1m.state = ST_L1_F3; + st->l1.Flags = 0; +#ifdef HISAX_UINTERFACE + if (test_bit(FLG_HW_L1_UINT, &cs->HW_Flags)) { + st->l1.l1m.fsm = &l1fsm_u; + st->l1.l1m.state = ST_L1_RESET; + st->l1.Flags = FLG_L1_UINT; + } +#endif st->l1.l1m.debug = cs->debug; st->l1.l1m.userdata = st; st->l1.l1m.userint = 0; @@ -768,7 +884,6 @@ setstack_HiSax(struct PStack *st, struct IsdnCardState *cs) setstack_manager(st); st->l1.stlistp = &(cs->stlist); st->l2.l2l1 = dch_l2l1; - st->l1.Flags = 0; cs->setstack_d(st, cs); } diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c index c20706553..b4e473670 100644 --- a/drivers/isdn/hisax/isdnl3.c +++ b/drivers/isdn/hisax/isdnl3.c @@ -234,7 +234,7 @@ no_l3_proto_spec(struct PStack *st, isdn_ctrl *ic) extern void setstack_dss1(struct PStack *st); #endif -#ifdef CONFIG_HISAX_NI1 +#ifdef CONFIG_HISAX_NI1 extern void setstack_ni1(struct PStack *st); #endif @@ -356,7 +356,7 @@ setstack_l3dc(struct PStack *st, struct Channel *chanp) setstack_dss1(st); } else #endif -#ifdef CONFIG_HISAX_NI1 +#ifdef CONFIG_HISAX_NI1 if (st->protocol == ISDN_PTYPE_NI1) { setstack_ni1(st); } else @@ -544,7 +544,6 @@ static struct FsmNode L3FnList[] HISAX_INITDATA = void l3_msg(struct PStack *st, int pr, void *arg) { - switch (pr) { case (DL_DATA | REQUEST): if (st->l3.l3m.state == ST_L3_LC_ESTAB) { diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c index ee56447c8..831d788b5 100644 --- a/drivers/isdn/hisax/l3_1tr6.c +++ b/drivers/isdn/hisax/l3_1tr6.c @@ -1,4 +1,4 @@ -/* $Id: l3_1tr6.c,v 2.11 2000/06/26 08:59:14 keil Exp $ +/* $Id: l3_1tr6.c,v 2.12 2000/08/20 07:31:30 keil Exp $ * * German 1TR6 D-channel protocol * @@ -17,7 +17,7 @@ #include <linux/ctype.h> extern char *HiSax_getrev(const char *revision); -const char *l3_1tr6_revision = "$Revision: 2.11 $"; +const char *l3_1tr6_revision = "$Revision: 2.12 $"; #define MsgHead(ptr, cref, mty, dis) \ *ptr++ = dis; \ @@ -883,7 +883,7 @@ down1tr6(struct PStack *st, int pr, void *arg) } else { proc->chan = chan; chan->proc = proc; - memcpy (&proc->para.setup, &chan->setup, sizeof (chan->setup)); + memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); proc->callref = cr; } } else { diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c index 32ae7576f..8778bf3a0 100644 --- a/drivers/isdn/hisax/l3dss1.c +++ b/drivers/isdn/hisax/l3dss1.c @@ -721,6 +721,9 @@ check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist) u_char *p, ie; int l, newpos, oldpos; int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0; + u_char codeset = 0; + u_char old_codeset = 0; + u_char codelock = 1; p = skb->data; /* skip cr */ @@ -729,20 +732,34 @@ check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist) p += l; mt = *p++; oldpos = 0; -/* shift codeset procedure not implemented in the moment */ while ((p - skb->data) < skb->len) { - if ((newpos = ie_in_set(pc, *p, cl))) { - if (newpos > 0) { - if (newpos < oldpos) - err_seq++; + if ((*p & 0xf0) == 0x90) { /* shift codeset */ + old_codeset = codeset; + codeset = *p & 7; + if (*p & 0x08) + codelock = 0; + else + codelock = 1; + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE shift%scodeset %d->%d", + codelock ? " locking ": " ", old_codeset, codeset); + p++; + continue; + } + if (!codeset) { /* only codeset 0 */ + if ((newpos = ie_in_set(pc, *p, cl))) { + if (newpos > 0) { + if (newpos < oldpos) + err_seq++; + else + oldpos = newpos; + } + } else { + if (ie_in_set(pc, *p, comp_required)) + err_compr++; else - oldpos = newpos; + err_ureg++; } - } else { - if (ie_in_set(pc, *p, comp_required)) - err_compr++; - else - err_ureg++; } ie = *p++; if (ie & 0x80) { @@ -752,12 +769,19 @@ check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist) p += l; l += 2; } - if (l > getmax_ie_len(ie)) + if (!codeset && (l > getmax_ie_len(ie))) err_len++; + if (!codelock) { + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE shift back codeset %d->%d", + codeset, old_codeset); + codeset = old_codeset; + codelock = 1; + } } if (err_compr | err_ureg | err_len | err_seq) { if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check_infoelements mt %x %d/%d/%d/%d", + l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d", mt, err_compr, err_ureg, err_len, err_seq); if (err_compr) return(ERR_IE_COMPREHENSION); @@ -959,7 +983,7 @@ l3dss1_release_cmpl(struct l3_process *pc, u_char pr, void *arg) #if EXT_BEARER_CAPS -u_char * +static u_char * EncodeASyncParams(u_char * p, u_char si2) { // 7c 06 88 90 21 42 00 bb @@ -1024,7 +1048,7 @@ EncodeASyncParams(u_char * p, u_char si2) return p + 3; } -u_char +static u_char EncodeSyncParams(u_char si2, u_char ai) { @@ -1889,6 +1913,16 @@ l3dss1_proceed_req(struct l3_process *pc, u_char pr, pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); } +static void +l3dss1_setup_ack_req(struct l3_process *pc, u_char pr, + void *arg) +{ + newl3state(pc, 25); + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T302, CC_T302); + l3dss1_message(pc, MT_SETUP_ACKNOWLEDGE); +} + /********************************************/ /* deliver a incoming display message to HL */ /********************************************/ @@ -1926,7 +1960,7 @@ l3dss1_progress(struct l3_process *pc, u_char pr, void *arg) if (p[1] != 2) { err = 1; pc->para.cause = 100; - } else if (p[2] & 0x60) { + } else if (!(p[2] & 0x70)) { switch (p[2]) { case 0x80: case 0x81: @@ -2030,9 +2064,22 @@ l3dss1_information(struct l3_process *pc, u_char pr, void *arg) { int ret; struct sk_buff *skb = arg; + u_char *p; + char tmp[32]; ret = check_infoelements(pc, skb, ie_INFORMATION); - l3dss1_std_ie_err(pc, ret); + if (ret) + l3dss1_std_ie_err(pc, ret); + if (pc->state == 25) { /* overlap receiving */ + L3DelTimer(&pc->timer); + p = skb->data; + if ((p = findie(p, skb->len, 0x70, 0))) { + iecpy(tmp, p, 1); + strcat(pc->para.setup.eazmsn, tmp); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); + } + L3AddTimer(&pc->timer, T302, CC_T302); + } } /******************************/ @@ -2258,6 +2305,16 @@ l3dss1_dummy(struct l3_process *pc, u_char pr, void *arg) } static void +l3dss1_t302(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 28; /* invalid number */ + l3dss1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); +} + +static void l3dss1_t303(struct l3_process *pc, u_char pr, void *arg) { if (pc->N303 > 0) { @@ -2276,6 +2333,7 @@ static void l3dss1_t304(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); + pc->para.loc = 0; pc->para.cause = 102; l3dss1_disconnect_req(pc, pr, NULL); pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); @@ -2315,6 +2373,7 @@ static void l3dss1_t310(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); + pc->para.loc = 0; pc->para.cause = 102; l3dss1_disconnect_req(pc, pr, NULL); pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); @@ -2324,6 +2383,7 @@ static void l3dss1_t313(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); + pc->para.loc = 0; pc->para.cause = 102; l3dss1_disconnect_req(pc, pr, NULL); pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); @@ -2713,32 +2773,36 @@ static struct stateentry downstatelist[] = CC_SETUP | REQUEST, l3dss1_setup_req}, {SBIT(0), CC_RESUME | REQUEST, l3dss1_resume_req}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10), + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25), CC_DISCONNECT | REQUEST, l3dss1_disconnect_req}, {SBIT(12), CC_RELEASE | REQUEST, l3dss1_release_req}, {ALL_STATES, CC_RESTART | REQUEST, l3dss1_restart}, - {SBIT(6), + {SBIT(6) | SBIT(25), CC_IGNORE | REQUEST, l3dss1_reset}, - {SBIT(6), + {SBIT(6) | SBIT(25), CC_REJECT | REQUEST, l3dss1_reject_req}, - {SBIT(6), + {SBIT(6) | SBIT(25), CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req}, - {SBIT(6) | SBIT(9), + {SBIT(6), + CC_MORE_INFO | REQUEST, l3dss1_setup_ack_req}, + {SBIT(25), + CC_MORE_INFO | REQUEST, l3dss1_dummy}, + {SBIT(6) | SBIT(9) | SBIT(25), CC_ALERTING | REQUEST, l3dss1_alert_req}, - {SBIT(6) | SBIT(7) | SBIT(9), + {SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25), CC_SETUP | RESPONSE, l3dss1_setup_rsp}, {SBIT(10), CC_SUSPEND | REQUEST, l3dss1_suspend_req}, - {SBIT(6), - CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req}, - {SBIT(7) | SBIT(9), + {SBIT(7) | SBIT(9) | SBIT(25), CC_REDIR | REQUEST, l3dss1_redir_req}, {SBIT(6), CC_REDIR | REQUEST, l3dss1_redir_req_early}, {SBIT(9) | SBIT(25), CC_DISCONNECT | REQUEST, l3dss1_disconnect_req}, + {SBIT(25), + CC_T302, l3dss1_t302}, {SBIT(1), CC_T303, l3dss1_t303}, {SBIT(2), @@ -3081,7 +3145,7 @@ dss1down(struct PStack *st, int pr, void *arg) if ((proc = dss1_new_l3_process(st, cr))) { proc->chan = chan; chan->proc = proc; - memcpy (&proc->para.setup, &chan->setup, sizeof (chan->setup)); + memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); proc->callref = cr; } } else { diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c new file mode 100644 index 000000000..ec28539a7 --- /dev/null +++ b/drivers/isdn/hisax/l3ni1.c @@ -0,0 +1,3171 @@ +// $Id: l3ni1.c,v 2.3 2000/06/26 08:59:14 keil Exp $ +//----------------------------------------------------------------------------- +// +// NI1 D-channel protocol +// +// Author Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd +// www.traverse.com.au +// +// 2000.6.6 Initial implementation of routines for US NI1 +// Layer 3 protocol based on the EURO/DSS1 D-channel protocol +// driver written by Karsten Keil et al. Thanks also for the +// code provided by Ragnar Paulson and Will Scales. +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- + +#define __NO_VERSION__ +#include "hisax.h" +#include "isdnl3.h" +#include "l3ni1.h" +#include <linux/ctype.h> + +extern char *HiSax_getrev(const char *revision); +const char *ni1_revision = "$Revision: 2.3 $"; + +#define EXT_BEARER_CAPS 1 + +#define MsgHead(ptr, cref, mty) \ + *ptr++ = 0x8; \ + if (cref == -1) { \ + *ptr++ = 0x0; \ + } else { \ + *ptr++ = 0x1; \ + *ptr++ = cref^0x80; \ + } \ + *ptr++ = mty + + +/**********************************************/ +/* get a new invoke id for remote operations. */ +/* Only a return value != 0 is valid */ +/**********************************************/ +static unsigned char new_invoke_id(struct PStack *p) +{ + unsigned char retval; + int flags,i; + + i = 32; /* maximum search depth */ + + save_flags(flags); + cli(); + + retval = p->prot.ni1.last_invoke_id + 1; /* try new id */ + while ((i) && (p->prot.ni1.invoke_used[retval >> 3] == 0xFF)) { + p->prot.ni1.last_invoke_id = (retval & 0xF8) + 8; + i--; + } + if (i) { + while (p->prot.ni1.invoke_used[retval >> 3] & (1 << (retval & 7))) + retval++; + } else + retval = 0; + p->prot.ni1.last_invoke_id = retval; + p->prot.ni1.invoke_used[retval >> 3] |= (1 << (retval & 7)); + restore_flags(flags); + + return(retval); +} /* new_invoke_id */ + +/*************************/ +/* free a used invoke id */ +/*************************/ +static void free_invoke_id(struct PStack *p, unsigned char id) +{ int flags; + + if (!id) return; /* 0 = invalid value */ + + save_flags(flags); + cli(); + p->prot.ni1.invoke_used[id >> 3] &= ~(1 << (id & 7)); + restore_flags(flags); +} /* free_invoke_id */ + + +/**********************************************************/ +/* create a new l3 process and fill in ni1 specific data */ +/**********************************************************/ +static struct l3_process +*ni1_new_l3_process(struct PStack *st, int cr) +{ struct l3_process *proc; + + if (!(proc = new_l3_process(st, cr))) + return(NULL); + + proc->prot.ni1.invoke_id = 0; + proc->prot.ni1.remote_operation = 0; + proc->prot.ni1.uus1_data[0] = '\0'; + + return(proc); +} /* ni1_new_l3_process */ + +/************************************************/ +/* free a l3 process and all ni1 specific data */ +/************************************************/ +static void +ni1_release_l3_process(struct l3_process *p) +{ + free_invoke_id(p->st,p->prot.ni1.invoke_id); + release_l3_process(p); +} /* ni1_release_l3_process */ + +/********************************************************/ +/* search a process with invoke id id and dummy callref */ +/********************************************************/ +static struct l3_process * +l3ni1_search_dummy_proc(struct PStack *st, int id) +{ struct l3_process *pc = st->l3.proc; /* start of processes */ + + if (!id) return(NULL); + + while (pc) + { if ((pc->callref == -1) && (pc->prot.ni1.invoke_id == id)) + return(pc); + pc = pc->next; + } + return(NULL); +} /* l3ni1_search_dummy_proc */ + +/*******************************************************************/ +/* called when a facility message with a dummy callref is received */ +/* and a return result is delivered. id specifies the invoke id. */ +/*******************************************************************/ +static void +l3ni1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen) +{ isdn_ctrl ic; + struct IsdnCardState *cs; + struct l3_process *pc = NULL; + + if ((pc = l3ni1_search_dummy_proc(st, id))) + { L3DelTimer(&pc->timer); /* remove timer */ + + cs = pc->st->l1.hardware; + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = NI1_STAT_INVOKE_RES; + ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; + ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; + ic.parm.ni1_io.proc = pc->prot.ni1.proc; + ic.parm.ni1_io.timeout= 0; + ic.parm.ni1_io.datalen = nlen; + ic.parm.ni1_io.data = p; + free_invoke_id(pc->st, pc->prot.ni1.invoke_id); + pc->prot.ni1.invoke_id = 0; /* reset id */ + + cs->iif.statcallb(&ic); + ni1_release_l3_process(pc); + } + else + l3_debug(st, "dummy return result id=0x%x result len=%d",id,nlen); +} /* l3ni1_dummy_return_result */ + +/*******************************************************************/ +/* called when a facility message with a dummy callref is received */ +/* and a return error is delivered. id specifies the invoke id. */ +/*******************************************************************/ +static void +l3ni1_dummy_error_return(struct PStack *st, int id, ulong error) +{ isdn_ctrl ic; + struct IsdnCardState *cs; + struct l3_process *pc = NULL; + + if ((pc = l3ni1_search_dummy_proc(st, id))) + { L3DelTimer(&pc->timer); /* remove timer */ + + cs = pc->st->l1.hardware; + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = NI1_STAT_INVOKE_ERR; + ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; + ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; + ic.parm.ni1_io.proc = pc->prot.ni1.proc; + ic.parm.ni1_io.timeout= error; + ic.parm.ni1_io.datalen = 0; + ic.parm.ni1_io.data = NULL; + free_invoke_id(pc->st, pc->prot.ni1.invoke_id); + pc->prot.ni1.invoke_id = 0; /* reset id */ + + cs->iif.statcallb(&ic); + ni1_release_l3_process(pc); + } + else + l3_debug(st, "dummy return error id=0x%x error=0x%lx",id,error); +} /* l3ni1_error_return */ + +/*******************************************************************/ +/* called when a facility message with a dummy callref is received */ +/* and a invoke is delivered. id specifies the invoke id. */ +/*******************************************************************/ +static void +l3ni1_dummy_invoke(struct PStack *st, int cr, int id, + int ident, u_char *p, u_char nlen) +{ isdn_ctrl ic; + struct IsdnCardState *cs; + + l3_debug(st, "dummy invoke %s id=0x%x ident=0x%x datalen=%d", + (cr == -1) ? "local" : "broadcast",id,ident,nlen); + if (cr >= -1) return; /* ignore local data */ + + cs = st->l1.hardware; + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = NI1_STAT_INVOKE_BRD; + ic.parm.ni1_io.hl_id = id; + ic.parm.ni1_io.ll_id = 0; + ic.parm.ni1_io.proc = ident; + ic.parm.ni1_io.timeout= 0; + ic.parm.ni1_io.datalen = nlen; + ic.parm.ni1_io.data = p; + + cs->iif.statcallb(&ic); +} /* l3ni1_dummy_invoke */ + +static void +l3ni1_parse_facility(struct PStack *st, struct l3_process *pc, + int cr, u_char * p) +{ + int qd_len = 0; + unsigned char nlen = 0, ilen, cp_tag; + int ident, id; + ulong err_ret; + + if (pc) + st = pc->st; /* valid Stack */ + else + if ((!st) || (cr >= 0)) return; /* neither pc nor st specified */ + + p++; + qd_len = *p++; + if (qd_len == 0) { + l3_debug(st, "qd_len == 0"); + return; + } + if ((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */ + l3_debug(st, "supplementary service != 0x11"); + return; + } + while (qd_len > 0 && !(*p & 0x80)) { /* extension ? */ + p++; + qd_len--; + } + if (qd_len < 2) { + l3_debug(st, "qd_len < 2"); + return; + } + p++; + qd_len--; + if ((*p & 0xE0) != 0xA0) { /* class and form */ + l3_debug(st, "class and form != 0xA0"); + return; + } + + cp_tag = *p & 0x1F; /* remember tag value */ + + p++; + qd_len--; + if (qd_len < 1) + { l3_debug(st, "qd_len < 1"); + return; + } + if (*p & 0x80) + { /* length format indefinite or limited */ + nlen = *p++ & 0x7F; /* number of len bytes or indefinite */ + if ((qd_len-- < ((!nlen) ? 3 : (1 + nlen))) || + (nlen > 1)) + { l3_debug(st, "length format error or not implemented"); + return; + } + if (nlen == 1) + { nlen = *p++; /* complete length */ + qd_len--; + } + else + { qd_len -= 2; /* trailing null bytes */ + if ((*(p+qd_len)) || (*(p+qd_len+1))) + { l3_debug(st,"length format indefinite error"); + return; + } + nlen = qd_len; + } + } + else + { nlen = *p++; + qd_len--; + } + if (qd_len < nlen) + { l3_debug(st, "qd_len < nlen"); + return; + } + qd_len -= nlen; + + if (nlen < 2) + { l3_debug(st, "nlen < 2"); + return; + } + if (*p != 0x02) + { /* invoke identifier tag */ + l3_debug(st, "invoke identifier tag !=0x02"); + return; + } + p++; + nlen--; + if (*p & 0x80) + { /* length format */ + l3_debug(st, "invoke id length format 2"); + return; + } + ilen = *p++; + nlen--; + if (ilen > nlen || ilen == 0) + { l3_debug(st, "ilen > nlen || ilen == 0"); + return; + } + nlen -= ilen; + id = 0; + while (ilen > 0) + { id = (id << 8) | (*p++ & 0xFF); /* invoke identifier */ + ilen--; + } + + switch (cp_tag) { /* component tag */ + case 1: /* invoke */ + if (nlen < 2) { + l3_debug(st, "nlen < 2 22"); + return; + } + if (*p != 0x02) { /* operation value */ + l3_debug(st, "operation value !=0x02"); + return; + } + p++; + nlen--; + ilen = *p++; + nlen--; + if (ilen > nlen || ilen == 0) { + l3_debug(st, "ilen > nlen || ilen == 0 22"); + return; + } + nlen -= ilen; + ident = 0; + while (ilen > 0) { + ident = (ident << 8) | (*p++ & 0xFF); + ilen--; + } + + if (!pc) + { + l3ni1_dummy_invoke(st, cr, id, ident, p, nlen); + return; + } + l3_debug(st, "invoke break"); + break; + case 2: /* return result */ + /* if no process available handle separately */ + if (!pc) + { if (cr == -1) + l3ni1_dummy_return_result(st, id, p, nlen); + return; + } + if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id)) + { /* Diversion successfull */ + free_invoke_id(st,pc->prot.ni1.invoke_id); + pc->prot.ni1.remote_result = 0; /* success */ + pc->prot.ni1.invoke_id = 0; + pc->redir_result = pc->prot.ni1.remote_result; + st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successfull */ + else + l3_debug(st,"return error unknown identifier"); + break; + case 3: /* return error */ + err_ret = 0; + if (nlen < 2) + { l3_debug(st, "return error nlen < 2"); + return; + } + if (*p != 0x02) + { /* result tag */ + l3_debug(st, "invoke error tag !=0x02"); + return; + } + p++; + nlen--; + if (*p > 4) + { /* length format */ + l3_debug(st, "invoke return errlen > 4 "); + return; + } + ilen = *p++; + nlen--; + if (ilen > nlen || ilen == 0) + { l3_debug(st, "error return ilen > nlen || ilen == 0"); + return; + } + nlen -= ilen; + while (ilen > 0) + { err_ret = (err_ret << 8) | (*p++ & 0xFF); /* error value */ + ilen--; + } + /* if no process available handle separately */ + if (!pc) + { if (cr == -1) + l3ni1_dummy_error_return(st, id, err_ret); + return; + } + if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id)) + { /* Deflection error */ + free_invoke_id(st,pc->prot.ni1.invoke_id); + pc->prot.ni1.remote_result = err_ret; /* result */ + pc->prot.ni1.invoke_id = 0; + pc->redir_result = pc->prot.ni1.remote_result; + st->l3.l3l4(st, CC_REDIR | INDICATION, pc); + } /* Deflection error */ + else + l3_debug(st,"return result unknown identifier"); + break; + default: + l3_debug(st, "facility default break tag=0x%02x",cp_tag); + break; + } +} + +static void +l3ni1_message(struct l3_process *pc, u_char mt) +{ + struct sk_buff *skb; + u_char *p; + + if (!(skb = l3_alloc_skb(4))) + return; + p = skb_put(skb, 4); + MsgHead(p, pc->callref, mt); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_message_cause(struct l3_process *pc, u_char mt, u_char cause) +{ + struct sk_buff *skb; + u_char tmp[16]; + u_char *p = tmp; + int l; + + MsgHead(p, pc->callref, mt); + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause | 0x80; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_status_send(struct l3_process *pc, u_char pr, void *arg) +{ + u_char tmp[16]; + u_char *p = tmp; + int l; + struct sk_buff *skb; + + MsgHead(p, pc->callref, MT_STATUS); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = pc->para.cause | 0x80; + + *p++ = IE_CALL_STATE; + *p++ = 0x1; + *p++ = pc->state & 0x3f; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg) +{ + /* This routine is called if here was no SETUP made (checks in ni1up and in + * l3ni1_setup) and a RELEASE_COMPLETE have to be sent with an error code + * MT_STATUS_ENQUIRE in the NULL state is handled too + */ + u_char tmp[16]; + u_char *p = tmp; + int l; + struct sk_buff *skb; + + switch (pc->para.cause) { + case 81: /* invalid callreference */ + case 88: /* incomp destination */ + case 96: /* mandory IE missing */ + case 100: /* invalid IE contents */ + case 101: /* incompatible Callstate */ + MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = pc->para.cause | 0x80; + break; + default: + printk(KERN_ERR "HiSax l3ni1_msg_without_setup wrong cause %d\n", + pc->para.cause); + return; + } + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + ni1_release_l3_process(pc); +} + +static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, + IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC, + IE_USER_USER, -1}; +static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, + IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1}; +static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, + IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL, + IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1}; +static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1}; +static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY, + IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; +static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, + IE_CALLED_PN, -1}; +static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1}; +static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS | + IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1}; +static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY, + IE_SIGNAL, IE_USER_USER, -1}; +/* a RELEASE_COMPLETE with errors don't require special actions +static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; +*/ +static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, + IE_DISPLAY, -1}; +static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; +static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY, + IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, IE_PROGRESS, + IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN, + IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR, + IE_LLC, IE_HLC, IE_USER_USER, -1}; +static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, + IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1}; +static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE | + IE_MANDATORY, IE_DISPLAY, -1}; +static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1}; +static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_DISPLAY, IE_FACILITY, -1}; +static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; +/* not used + * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY, + * IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; + * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1}; + * static int ie_RESTART[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_RESTART_IND | + * IE_MANDATORY, -1}; + */ +static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1}; +static int comp_required[] = {1,2,3,5,6,7,9,10,11,14,15,-1}; +static int l3_valid_states[] = {0,1,2,3,4,6,7,8,9,10,11,12,15,17,19,25,-1}; + +struct ie_len { + int ie; + int len; +}; + +static +struct ie_len max_ie_len[] = { + {IE_SEGMENT, 4}, + {IE_BEARER, 12}, + {IE_CAUSE, 32}, + {IE_CALL_ID, 10}, + {IE_CALL_STATE, 3}, + {IE_CHANNEL_ID, 34}, + {IE_FACILITY, 255}, + {IE_PROGRESS, 4}, + {IE_NET_FAC, 255}, + {IE_NOTIFY, 3}, + {IE_DISPLAY, 82}, + {IE_DATE, 8}, + {IE_KEYPAD, 34}, + {IE_SIGNAL, 3}, + {IE_INFORATE, 6}, + {IE_E2E_TDELAY, 11}, + {IE_TDELAY_SEL, 5}, + {IE_PACK_BINPARA, 3}, + {IE_PACK_WINSIZE, 4}, + {IE_PACK_SIZE, 4}, + {IE_CUG, 7}, + {IE_REV_CHARGE, 3}, + {IE_CALLING_PN, 24}, + {IE_CALLING_SUB, 23}, + {IE_CALLED_PN, 24}, + {IE_CALLED_SUB, 23}, + {IE_REDIR_NR, 255}, + {IE_TRANS_SEL, 255}, + {IE_RESTART_IND, 3}, + {IE_LLC, 18}, + {IE_HLC, 5}, + {IE_USER_USER, 131}, + {-1,0}, +}; + +static int +getmax_ie_len(u_char ie) { + int i = 0; + while (max_ie_len[i].ie != -1) { + if (max_ie_len[i].ie == ie) + return(max_ie_len[i].len); + i++; + } + return(255); +} + +static int +ie_in_set(struct l3_process *pc, u_char ie, int *checklist) { + int ret = 1; + + while (*checklist != -1) { + if ((*checklist & 0xff) == ie) { + if (ie & 0x80) + return(-ret); + else + return(ret); + } + ret++; + checklist++; + } + return(0); +} + +static int +check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist) +{ + int *cl = checklist; + u_char mt; + u_char *p, ie; + int l, newpos, oldpos; + int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0; + u_char codeset = 0; + u_char old_codeset = 0; + u_char codelock = 1; + + p = skb->data; + /* skip cr */ + p++; + l = (*p++) & 0xf; + p += l; + mt = *p++; + oldpos = 0; + while ((p - skb->data) < skb->len) { + if ((*p & 0xf0) == 0x90) { /* shift codeset */ + old_codeset = codeset; + codeset = *p & 7; + if (*p & 0x08) + codelock = 0; + else + codelock = 1; + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE shift%scodeset %d->%d", + codelock ? " locking ": " ", old_codeset, codeset); + p++; + continue; + } + if (!codeset) { /* only codeset 0 */ + if ((newpos = ie_in_set(pc, *p, cl))) { + if (newpos > 0) { + if (newpos < oldpos) + err_seq++; + else + oldpos = newpos; + } + } else { + if (ie_in_set(pc, *p, comp_required)) + err_compr++; + else + err_ureg++; + } + } + ie = *p++; + if (ie & 0x80) { + l = 1; + } else { + l = *p++; + p += l; + l += 2; + } + if (!codeset && (l > getmax_ie_len(ie))) + err_len++; + if (!codelock) { + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE shift back codeset %d->%d", + codeset, old_codeset); + codeset = old_codeset; + codelock = 1; + } + } + if (err_compr | err_ureg | err_len | err_seq) { + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d", + mt, err_compr, err_ureg, err_len, err_seq); + if (err_compr) + return(ERR_IE_COMPREHENSION); + if (err_ureg) + return(ERR_IE_UNRECOGNIZED); + if (err_len) + return(ERR_IE_LENGTH); + if (err_seq) + return(ERR_IE_SEQUENCE); + } + return(0); +} + +/* verify if a message type exists and contain no IE error */ +static int +l3ni1_check_messagetype_validity(struct l3_process *pc, int mt, void *arg) +{ + switch (mt) { + case MT_ALERTING: + case MT_CALL_PROCEEDING: + case MT_CONNECT: + case MT_CONNECT_ACKNOWLEDGE: + case MT_DISCONNECT: + case MT_INFORMATION: + case MT_FACILITY: + case MT_NOTIFY: + case MT_PROGRESS: + case MT_RELEASE: + case MT_RELEASE_COMPLETE: + case MT_SETUP: + case MT_SETUP_ACKNOWLEDGE: + case MT_RESUME_ACKNOWLEDGE: + case MT_RESUME_REJECT: + case MT_SUSPEND_ACKNOWLEDGE: + case MT_SUSPEND_REJECT: + case MT_USER_INFORMATION: + case MT_RESTART: + case MT_RESTART_ACKNOWLEDGE: + case MT_CONGESTION_CONTROL: + case MT_STATUS: + case MT_STATUS_ENQUIRY: + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) OK", mt); + break; + case MT_RESUME: /* RESUME only in user->net */ + case MT_SUSPEND: /* SUSPEND only in user->net */ + default: + if (pc->debug & (L3_DEB_CHECK | L3_DEB_WARN)) + l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) fail", mt); + pc->para.cause = 97; + l3ni1_status_send(pc, 0, NULL); + return(1); + } + return(0); +} + +static void +l3ni1_std_ie_err(struct l3_process *pc, int ret) { + + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check_infoelements ret %d", ret); + switch(ret) { + case 0: + break; + case ERR_IE_COMPREHENSION: + pc->para.cause = 96; + l3ni1_status_send(pc, 0, NULL); + break; + case ERR_IE_UNRECOGNIZED: + pc->para.cause = 99; + l3ni1_status_send(pc, 0, NULL); + break; + case ERR_IE_LENGTH: + pc->para.cause = 100; + l3ni1_status_send(pc, 0, NULL); + break; + case ERR_IE_SEQUENCE: + default: + break; + } +} + +static int +l3ni1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) { + u_char *p; + + p = skb->data; + if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { + p++; + if (*p != 1) { /* len for BRI = 1 */ + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "wrong chid len %d", *p); + return (-2); + } + p++; + if (*p & 0x60) { /* only base rate interface */ + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "wrong chid %x", *p); + return (-3); + } + return(*p & 0x3); + } else + return(-1); +} + +static int +l3ni1_get_cause(struct l3_process *pc, struct sk_buff *skb) { + u_char l, i=0; + u_char *p; + + p = skb->data; + pc->para.cause = 31; + pc->para.loc = 0; + if ((p = findie(p, skb->len, IE_CAUSE, 0))) { + p++; + l = *p++; + if (l>30) + return(1); + if (l) { + pc->para.loc = *p++; + l--; + } else { + return(2); + } + if (l && !(pc->para.loc & 0x80)) { + l--; + p++; /* skip recommendation */ + } + if (l) { + pc->para.cause = *p++; + l--; + if (!(pc->para.cause & 0x80)) + return(3); + } else + return(4); + while (l && (i<6)) { + pc->para.diag[i++] = *p++; + l--; + } + } else + return(-1); + return(0); +} + +static void +l3ni1_msg_with_uus(struct l3_process *pc, u_char cmd) +{ + struct sk_buff *skb; + u_char tmp[16+40]; + u_char *p = tmp; + int l; + + MsgHead(p, pc->callref, cmd); + + if (pc->prot.ni1.uus1_data[0]) + { *p++ = IE_USER_USER; /* UUS info element */ + *p++ = strlen(pc->prot.ni1.uus1_data) + 1; + *p++ = 0x04; /* IA5 chars */ + strcpy(p,pc->prot.ni1.uus1_data); + p += strlen(pc->prot.ni1.uus1_data); + pc->prot.ni1.uus1_data[0] = '\0'; + } + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} /* l3ni1_msg_with_uus */ + +static void +l3ni1_release_req(struct l3_process *pc, u_char pr, void *arg) +{ + StopAllL3Timer(pc); + newl3state(pc, 19); + if (!pc->prot.ni1.uus1_data[0]) + l3ni1_message(pc, MT_RELEASE); + else + l3ni1_msg_with_uus(pc, MT_RELEASE); + L3AddTimer(&pc->timer, T308, CC_T308_1); +} + +static void +l3ni1_release_cmpl(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + if ((ret = l3ni1_get_cause(pc, skb))>0) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "RELCMPL get_cause ret(%d)",ret); + } else if (ret < 0) + pc->para.cause = NO_CAUSE; + StopAllL3Timer(pc); + newl3state(pc, 0); + pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); + ni1_release_l3_process(pc); +} + +#if EXT_BEARER_CAPS + +static u_char * +EncodeASyncParams(u_char * p, u_char si2) +{ // 7c 06 88 90 21 42 00 bb + + p[0] = 0; + p[1] = 0x40; // Intermediate rate: 16 kbit/s jj 2000.02.19 + p[2] = 0x80; + if (si2 & 32) // 7 data bits + + p[2] += 16; + else // 8 data bits + + p[2] += 24; + + if (si2 & 16) // 2 stop bits + + p[2] += 96; + else // 1 stop bit + + p[2] += 32; + + if (si2 & 8) // even parity + + p[2] += 2; + else // no parity + + p[2] += 3; + + switch (si2 & 0x07) { + case 0: + p[0] = 66; // 1200 bit/s + + break; + case 1: + p[0] = 88; // 1200/75 bit/s + + break; + case 2: + p[0] = 87; // 75/1200 bit/s + + break; + case 3: + p[0] = 67; // 2400 bit/s + + break; + case 4: + p[0] = 69; // 4800 bit/s + + break; + case 5: + p[0] = 72; // 9600 bit/s + + break; + case 6: + p[0] = 73; // 14400 bit/s + + break; + case 7: + p[0] = 75; // 19200 bit/s + + break; + } + return p + 3; +} + +static u_char +EncodeSyncParams(u_char si2, u_char ai) +{ + + switch (si2) { + case 0: + return ai + 2; // 1200 bit/s + + case 1: + return ai + 24; // 1200/75 bit/s + + case 2: + return ai + 23; // 75/1200 bit/s + + case 3: + return ai + 3; // 2400 bit/s + + case 4: + return ai + 5; // 4800 bit/s + + case 5: + return ai + 8; // 9600 bit/s + + case 6: + return ai + 9; // 14400 bit/s + + case 7: + return ai + 11; // 19200 bit/s + + case 8: + return ai + 14; // 48000 bit/s + + case 9: + return ai + 15; // 56000 bit/s + + case 15: + return ai + 40; // negotiate bit/s + + default: + break; + } + return ai; +} + + +static u_char +DecodeASyncParams(u_char si2, u_char * p) +{ + u_char info; + + switch (p[5]) { + case 66: // 1200 bit/s + + break; // si2 don't change + + case 88: // 1200/75 bit/s + + si2 += 1; + break; + case 87: // 75/1200 bit/s + + si2 += 2; + break; + case 67: // 2400 bit/s + + si2 += 3; + break; + case 69: // 4800 bit/s + + si2 += 4; + break; + case 72: // 9600 bit/s + + si2 += 5; + break; + case 73: // 14400 bit/s + + si2 += 6; + break; + case 75: // 19200 bit/s + + si2 += 7; + break; + } + + info = p[7] & 0x7f; + if ((info & 16) && (!(info & 8))) // 7 data bits + + si2 += 32; // else 8 data bits + + if ((info & 96) == 96) // 2 stop bits + + si2 += 16; // else 1 stop bit + + if ((info & 2) && (!(info & 1))) // even parity + + si2 += 8; // else no parity + + return si2; +} + + +static u_char +DecodeSyncParams(u_char si2, u_char info) +{ + info &= 0x7f; + switch (info) { + case 40: // bit/s negotiation failed ai := 165 not 175! + + return si2 + 15; + case 15: // 56000 bit/s failed, ai := 0 not 169 ! + + return si2 + 9; + case 14: // 48000 bit/s + + return si2 + 8; + case 11: // 19200 bit/s + + return si2 + 7; + case 9: // 14400 bit/s + + return si2 + 6; + case 8: // 9600 bit/s + + return si2 + 5; + case 5: // 4800 bit/s + + return si2 + 4; + case 3: // 2400 bit/s + + return si2 + 3; + case 23: // 75/1200 bit/s + + return si2 + 2; + case 24: // 1200/75 bit/s + + return si2 + 1; + default: // 1200 bit/s + + return si2; + } +} + +static u_char +DecodeSI2(struct sk_buff *skb) +{ + u_char *p; //, *pend=skb->data + skb->len; + + if ((p = findie(skb->data, skb->len, 0x7c, 0))) { + switch (p[4] & 0x0f) { + case 0x01: + if (p[1] == 0x04) // sync. Bitratenadaption + + return DecodeSyncParams(160, p[5]); // V.110/X.30 + + else if (p[1] == 0x06) // async. Bitratenadaption + + return DecodeASyncParams(192, p); // V.110/X.30 + + break; + case 0x08: // if (p[5] == 0x02) // sync. Bitratenadaption + if (p[1] > 3) + return DecodeSyncParams(176, p[5]); // V.120 + break; + } + } + return 0; +} + +#endif + + +static void +l3ni1_setup_req(struct l3_process *pc, u_char pr, + void *arg) +{ + struct sk_buff *skb; + u_char tmp[128]; + u_char *p = tmp; + + u_char *teln; + u_char *sub; + u_char *sp; + int l; + + MsgHead(p, pc->callref, MT_SETUP); + + teln = pc->para.setup.phone; + + *p++ = 0xa1; /* complete indicator */ + /* + * Set Bearer Capability, Map info from 1TR6-convention to NI1 + */ + switch (pc->para.setup.si1) { + case 1: /* Telephony */ + *p++ = IE_BEARER; + *p++ = 0x3; /* Length */ + *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + *p++ = 0xa3; /* A-Law Audio */ + break; + case 5: /* Datatransmission 64k, BTX */ + case 7: /* Datatransmission 64k */ + default: + *p++ = IE_BEARER; + *p++ = 0x2; /* Length */ + *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + break; + } + + sub = NULL; + sp = teln; + while (*sp) { + if ('.' == *sp) { + sub = sp; + *sp = 0; + } else + sp++; + } + + *p++ = IE_KEYPAD; + *p++ = strlen(teln); + while (*teln) + *p++ = (*teln++) & 0x7F; + + if (sub) + *sub++ = '.'; + +#if EXT_BEARER_CAPS + if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30 + + *p++ = IE_LLC; + *p++ = 0x04; + *p++ = 0x88; + *p++ = 0x90; + *p++ = 0x21; + *p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80); + } else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) { // sync. Bitratenadaption, V.120 + + *p++ = IE_LLC; + *p++ = 0x05; + *p++ = 0x88; + *p++ = 0x90; + *p++ = 0x28; + *p++ = EncodeSyncParams(pc->para.setup.si2 - 176, 0); + *p++ = 0x82; + } else if (pc->para.setup.si2 >= 192) { // async. Bitratenadaption, V.110/X.30 + + *p++ = IE_LLC; + *p++ = 0x06; + *p++ = 0x88; + *p++ = 0x90; + *p++ = 0x21; + p = EncodeASyncParams(p, pc->para.setup.si2 - 192); + } else { + switch (pc->para.setup.si1) { + case 1: /* Telephony */ + *p++ = IE_LLC; + *p++ = 0x3; /* Length */ + *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + *p++ = 0xa3; /* A-Law Audio */ + break; + case 5: /* Datatransmission 64k, BTX */ + case 7: /* Datatransmission 64k */ + default: + *p++ = IE_LLC; + *p++ = 0x2; /* Length */ + *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + break; + } + } +#endif + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) +{ + return; +} + memcpy(skb_put(skb, l), tmp, l); + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T303, CC_T303); + newl3state(pc, 1); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_call_proc(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int id, ret; + + if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { + if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer with wrong chid %x", id); + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + pc->para.bchannel = id; + } else if (1 == pc->state) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer wrong chid (ret %d)", id); + if (id == -1) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + ret = check_infoelements(pc, skb, ie_CALL_PROCEEDING); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + newl3state(pc, 3); + L3AddTimer(&pc->timer, T310, CC_T310); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc); +} + +static void +l3ni1_setup_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int id, ret; + + if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { + if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer with wrong chid %x", id); + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + pc->para.bchannel = id; + } else { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer wrong chid (ret %d)", id); + if (id == -1) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + ret = check_infoelements(pc, skb, ie_SETUP_ACKNOWLEDGE); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + newl3state(pc, 2); + L3AddTimer(&pc->timer, T304, CC_T304); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); +} + +static void +l3ni1_disconnect(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + u_char *p; + int ret; + u_char cause = 0; + + StopAllL3Timer(pc); + if ((ret = l3ni1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "DISC get_cause ret(%d)", ret); + if (ret < 0) + cause = 96; + else if (ret > 0) + cause = 100; + } + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) + l3ni1_parse_facility(pc->st, pc, pc->callref, p); + ret = check_infoelements(pc, skb, ie_DISCONNECT); + if (ERR_IE_COMPREHENSION == ret) + cause = 96; + else if ((!cause) && (ERR_IE_UNRECOGNIZED == ret)) + cause = 99; + ret = pc->state; + newl3state(pc, 12); + if (cause) + newl3state(pc, 19); + if (11 != ret) + pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc); + else if (!cause) + l3ni1_release_req(pc, pr, NULL); + if (cause) { + l3ni1_message_cause(pc, MT_RELEASE, cause); + L3AddTimer(&pc->timer, T308, CC_T308_1); + } +} + +static void +l3ni1_connect(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_CONNECT); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); /* T310 */ + newl3state(pc, 10); + pc->para.chargeinfo = 0; + /* here should inserted COLP handling KKe */ + if (ret) + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc); +} + +static void +l3ni1_alerting(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_ALERTING); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); /* T304 */ + newl3state(pc, 4); + if (ret) + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc); +} + +static void +l3ni1_setup(struct l3_process *pc, u_char pr, void *arg) +{ + u_char *p; + int bcfound = 0; + char tmp[80]; + struct sk_buff *skb = arg; + int id; + int err = 0; + + /* + * Bearer Capabilities + */ + p = skb->data; + /* only the first occurence 'll be detected ! */ + if ((p = findie(p, skb->len, 0x04, 0))) { + if ((p[1] < 2) || (p[1] > 11)) + err = 1; + else { + pc->para.setup.si2 = 0; + switch (p[2] & 0x7f) { + case 0x00: /* Speech */ + case 0x10: /* 3.1 Khz audio */ + pc->para.setup.si1 = 1; + break; + case 0x08: /* Unrestricted digital information */ + pc->para.setup.si1 = 7; +/* JIM, 05.11.97 I wanna set service indicator 2 */ +#if EXT_BEARER_CAPS + pc->para.setup.si2 = DecodeSI2(skb); +#endif + break; + case 0x09: /* Restricted digital information */ + pc->para.setup.si1 = 2; + break; + case 0x11: + /* Unrestr. digital information with + * tones/announcements ( or 7 kHz audio + */ + pc->para.setup.si1 = 3; + break; + case 0x18: /* Video */ + pc->para.setup.si1 = 4; + break; + default: + err = 2; + break; + } + switch (p[3] & 0x7f) { + case 0x40: /* packed mode */ + pc->para.setup.si1 = 8; + break; + case 0x10: /* 64 kbit */ + case 0x11: /* 2*64 kbit */ + case 0x13: /* 384 kbit */ + case 0x15: /* 1536 kbit */ + case 0x17: /* 1920 kbit */ + pc->para.moderate = p[3] & 0x7f; + break; + default: + err = 3; + break; + } + } + if (pc->debug & L3_DEB_SI) + l3_debug(pc->st, "SI=%d, AI=%d", + pc->para.setup.si1, pc->para.setup.si2); + if (err) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup with wrong bearer(l=%d:%x,%x)", + p[1], p[2], p[3]); + pc->para.cause = 100; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + } else { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup without bearer capabilities"); + /* ETS 300-104 1.3.3 */ + pc->para.cause = 96; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + /* + * Channel Identification + */ + if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { + if ((pc->para.bchannel = id)) { + if ((3 == id) && (0x10 == pc->para.moderate)) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup with wrong chid %x", + id); + pc->para.cause = 100; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + bcfound++; + } else + { if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup without bchannel, call waiting"); + bcfound++; + } + } else { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup with wrong chid ret %d", id); + if (id == -1) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + err = check_infoelements(pc, skb, ie_SETUP); + if (ERR_IE_COMPREHENSION == err) { + pc->para.cause = 96; + l3ni1_msg_without_setup(pc, pr, NULL); + return; + } + p = skb->data; + if ((p = findie(p, skb->len, 0x70, 0))) + iecpy(pc->para.setup.eazmsn, p, 1); + else + pc->para.setup.eazmsn[0] = 0; + + p = skb->data; + if ((p = findie(p, skb->len, 0x71, 0))) { + /* Called party subaddress */ + if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { + tmp[0] = '.'; + iecpy(&tmp[1], p, 2); + strcat(pc->para.setup.eazmsn, tmp); + } else if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "wrong called subaddress"); + } + p = skb->data; + if ((p = findie(p, skb->len, 0x6c, 0))) { + pc->para.setup.plan = p[2]; + if (p[2] & 0x80) { + iecpy(pc->para.setup.phone, p, 1); + pc->para.setup.screen = 0; + } else { + iecpy(pc->para.setup.phone, p, 2); + pc->para.setup.screen = p[3]; + } + } else { + pc->para.setup.phone[0] = 0; + pc->para.setup.plan = 0; + pc->para.setup.screen = 0; + } + p = skb->data; + if ((p = findie(p, skb->len, 0x6d, 0))) { + /* Calling party subaddress */ + if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { + tmp[0] = '.'; + iecpy(&tmp[1], p, 2); + strcat(pc->para.setup.phone, tmp); + } else if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "wrong calling subaddress"); + } + newl3state(pc, 6); + if (err) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, err); + pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); +} + +static void +l3ni1_reset(struct l3_process *pc, u_char pr, void *arg) +{ + ni1_release_l3_process(pc); +} + +static void +l3ni1_disconnect_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[16+40]; + u_char *p = tmp; + int l; + u_char cause = 16; + + if (pc->para.cause != NO_CAUSE) + cause = pc->para.cause; + + StopAllL3Timer(pc); + + MsgHead(p, pc->callref, MT_DISCONNECT); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause | 0x80; + + if (pc->prot.ni1.uus1_data[0]) + { *p++ = IE_USER_USER; /* UUS info element */ + *p++ = strlen(pc->prot.ni1.uus1_data) + 1; + *p++ = 0x04; /* IA5 chars */ + strcpy(p,pc->prot.ni1.uus1_data); + p += strlen(pc->prot.ni1.uus1_data); + pc->prot.ni1.uus1_data[0] = '\0'; + } + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + newl3state(pc, 11); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + L3AddTimer(&pc->timer, T305, CC_T305); +} + +static void +l3ni1_setup_rsp(struct l3_process *pc, u_char pr, + void *arg) +{ + if (!pc->para.bchannel) + { if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "D-chan connect for waiting call"); + l3ni1_disconnect_req(pc, pr, arg); + return; + } + newl3state(pc, 8); + l3ni1_message(pc, MT_CONNECT); + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T313, CC_T313); +} + +static void +l3ni1_connect_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_CONNECT_ACKNOWLEDGE); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + newl3state(pc, 10); + L3DelTimer(&pc->timer); + if (ret) + l3ni1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc); +} + +static void +l3ni1_reject_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[16]; + u_char *p = tmp; + int l; + u_char cause = 21; + + if (pc->para.cause != NO_CAUSE) + cause = pc->para.cause; + + MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause | 0x80; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + newl3state(pc, 0); + ni1_release_l3_process(pc); +} + +static void +l3ni1_release(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + u_char *p; + int ret, cause=0; + + StopAllL3Timer(pc); + if ((ret = l3ni1_get_cause(pc, skb))>0) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "REL get_cause ret(%d)", ret); + } else if (ret<0) + pc->para.cause = NO_CAUSE; + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { + l3ni1_parse_facility(pc->st, pc, pc->callref, p); + } + if ((ret<0) && (pc->state != 11)) + cause = 96; + else if (ret>0) + cause = 100; + ret = check_infoelements(pc, skb, ie_RELEASE); + if (ERR_IE_COMPREHENSION == ret) + cause = 96; + else if ((ERR_IE_UNRECOGNIZED == ret) && (!cause)) + cause = 99; + if (cause) + l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, cause); + else + l3ni1_message(pc, MT_RELEASE_COMPLETE); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + newl3state(pc, 0); + ni1_release_l3_process(pc); +} + +static void +l3ni1_alert_req(struct l3_process *pc, u_char pr, + void *arg) +{ + newl3state(pc, 7); + if (!pc->prot.ni1.uus1_data[0]) + l3ni1_message(pc, MT_ALERTING); + else + l3ni1_msg_with_uus(pc, MT_ALERTING); +} + +static void +l3ni1_proceed_req(struct l3_process *pc, u_char pr, + void *arg) +{ + newl3state(pc, 9); + l3ni1_message(pc, MT_CALL_PROCEEDING); + pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); +} + +static void +l3ni1_setup_ack_req(struct l3_process *pc, u_char pr, + void *arg) +{ + newl3state(pc, 25); + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T302, CC_T302); + l3ni1_message(pc, MT_SETUP_ACKNOWLEDGE); +} + +/********************************************/ +/* deliver a incoming display message to HL */ +/********************************************/ +static void +l3ni1_deliver_display(struct l3_process *pc, int pr, u_char *infp) +{ u_char len; + isdn_ctrl ic; + struct IsdnCardState *cs; + char *p; + + if (*infp++ != IE_DISPLAY) return; + if ((len = *infp++) > 80) return; /* total length <= 82 */ + if (!pc->chan) return; + + p = ic.parm.display; + while (len--) + *p++ = *infp++; + *p = '\0'; + ic.command = ISDN_STAT_DISPLAY; + cs = pc->st->l1.hardware; + ic.driver = cs->myid; + ic.arg = pc->chan->chan; + cs->iif.statcallb(&ic); +} /* l3ni1_deliver_display */ + + +static void +l3ni1_progress(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int err = 0; + u_char *p; + + if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) { + if (p[1] != 2) { + err = 1; + pc->para.cause = 100; + } else if (!(p[2] & 0x70)) { + switch (p[2]) { + case 0x80: + case 0x81: + case 0x82: + case 0x84: + case 0x85: + case 0x87: + case 0x8a: + switch (p[3]) { + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x88: + break; + default: + err = 2; + pc->para.cause = 100; + break; + } + break; + default: + err = 3; + pc->para.cause = 100; + break; + } + } + } else { + pc->para.cause = 96; + err = 4; + } + if (err) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "progress error %d", err); + l3ni1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + err = check_infoelements(pc, skb, ie_PROGRESS); + if (err) + l3ni1_std_ie_err(pc, err); + if (ERR_IE_COMPREHENSION != err) + pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc); +} + +static void +l3ni1_notify(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int err = 0; + u_char *p; + + if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) { + if (p[1] != 1) { + err = 1; + pc->para.cause = 100; + } else { + switch (p[2]) { + case 0x80: + case 0x81: + case 0x82: + break; + default: + pc->para.cause = 100; + err = 2; + break; + } + } + } else { + pc->para.cause = 96; + err = 3; + } + if (err) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "notify error %d", err); + l3ni1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + err = check_infoelements(pc, skb, ie_NOTIFY); + if (err) + l3ni1_std_ie_err(pc, err); + if (ERR_IE_COMPREHENSION != err) + pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc); +} + +static void +l3ni1_status_enq(struct l3_process *pc, u_char pr, void *arg) +{ + int ret; + struct sk_buff *skb = arg; + + ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY); + l3ni1_std_ie_err(pc, ret); + pc->para.cause = 30; /* response to STATUS_ENQUIRY */ + l3ni1_status_send(pc, pr, NULL); +} + +static void +l3ni1_information(struct l3_process *pc, u_char pr, void *arg) +{ + int ret; + struct sk_buff *skb = arg; + u_char *p; + char tmp[32]; + + ret = check_infoelements(pc, skb, ie_INFORMATION); + if (ret) + l3ni1_std_ie_err(pc, ret); + if (pc->state == 25) { /* overlap receiving */ + L3DelTimer(&pc->timer); + p = skb->data; + if ((p = findie(p, skb->len, 0x70, 0))) { + iecpy(tmp, p, 1); + strcat(pc->para.setup.eazmsn, tmp); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); + } + L3AddTimer(&pc->timer, T302, CC_T302); + } +} + +/******************************/ +/* handle deflection requests */ +/******************************/ +static void l3ni1_redir_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[128]; + u_char *p = tmp; + u_char *subp; + u_char len_phone = 0; + u_char len_sub = 0; + int l; + + + strcpy(pc->prot.ni1.uus1_data,pc->chan->setup.eazmsn); /* copy uus element if available */ + if (!pc->chan->setup.phone[0]) + { pc->para.cause = -1; + l3ni1_disconnect_req(pc,pr,arg); /* disconnect immediately */ + return; + } /* only uus */ + + if (pc->prot.ni1.invoke_id) + free_invoke_id(pc->st,pc->prot.ni1.invoke_id); + + if (!(pc->prot.ni1.invoke_id = new_invoke_id(pc->st))) + return; + + MsgHead(p, pc->callref, MT_FACILITY); + + for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */ + if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subadress element */ + + *p++ = 0x1c; /* Facility info element */ + *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */ + *p++ = 0x91; /* remote operations protocol */ + *p++ = 0xa1; /* invoke component */ + + *p++ = len_phone + len_sub + 2 + 2 + 8 + 3; /* length of data */ + *p++ = 0x02; /* invoke id tag, integer */ + *p++ = 0x01; /* length */ + *p++ = pc->prot.ni1.invoke_id; /* invoke id */ + *p++ = 0x02; /* operation value tag, integer */ + *p++ = 0x01; /* length */ + *p++ = 0x0D; /* Call Deflect */ + + *p++ = 0x30; /* sequence phone number */ + *p++ = len_phone + 2 + 2 + 3 + len_sub; /* length */ + + *p++ = 0x30; /* Deflected to UserNumber */ + *p++ = len_phone+2+len_sub; /* length */ + *p++ = 0x80; /* NumberDigits */ + *p++ = len_phone; /* length */ + for (l = 0; l < len_phone; l++) + *p++ = pc->chan->setup.phone[l]; + + if (len_sub) + { *p++ = 0x04; /* called party subadress */ + *p++ = len_sub - 2; + while (*subp) *p++ = *subp++; + } + + *p++ = 0x01; /* screening identifier */ + *p++ = 0x01; + *p++ = pc->chan->setup.screen; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) return; + memcpy(skb_put(skb, l), tmp, l); + + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} /* l3ni1_redir_req */ + +/********************************************/ +/* handle deflection request in early state */ +/********************************************/ +static void l3ni1_redir_req_early(struct l3_process *pc, u_char pr, void *arg) +{ + l3ni1_proceed_req(pc,pr,arg); + l3ni1_redir_req(pc,pr,arg); +} /* l3ni1_redir_req_early */ + +/***********************************************/ +/* handle special commands for this protocol. */ +/* Examples are call independant services like */ +/* remote operations with dummy callref. */ +/***********************************************/ +static int l3ni1_cmd_global(struct PStack *st, isdn_ctrl *ic) +{ u_char id; + u_char temp[265]; + u_char *p = temp; + int i, l, proc_len; + struct sk_buff *skb; + struct l3_process *pc = NULL; + + switch (ic->arg) + { case NI1_CMD_INVOKE: + if (ic->parm.ni1_io.datalen < 0) return(-2); /* invalid parameter */ + + for (proc_len = 1, i = ic->parm.ni1_io.proc >> 8; i; i++) + i = i >> 8; /* add one byte */ + l = ic->parm.ni1_io.datalen + proc_len + 8; /* length excluding ie header */ + if (l > 255) + return(-2); /* too long */ + + if (!(id = new_invoke_id(st))) + return(0); /* first get a invoke id -> return if no available */ + + i = -1; + MsgHead(p, i, MT_FACILITY); /* build message head */ + *p++ = 0x1C; /* Facility IE */ + *p++ = l; /* length of ie */ + *p++ = 0x91; /* remote operations */ + *p++ = 0xA1; /* invoke */ + *p++ = l - 3; /* length of invoke */ + *p++ = 0x02; /* invoke id tag */ + *p++ = 0x01; /* length is 1 */ + *p++ = id; /* invoke id */ + *p++ = 0x02; /* operation */ + *p++ = proc_len; /* length of operation */ + + for (i = proc_len; i; i--) + *p++ = (ic->parm.ni1_io.proc >> (i-1)) & 0xFF; + memcpy(p, ic->parm.ni1_io.data, ic->parm.ni1_io.datalen); /* copy data */ + l = (p - temp) + ic->parm.ni1_io.datalen; /* total length */ + + if (ic->parm.ni1_io.timeout > 0) + if (!(pc = ni1_new_l3_process(st, -1))) + { free_invoke_id(st, id); + return(-2); + } + pc->prot.ni1.ll_id = ic->parm.ni1_io.ll_id; /* remember id */ + pc->prot.ni1.proc = ic->parm.ni1_io.proc; /* and procedure */ + + if (!(skb = l3_alloc_skb(l))) + { free_invoke_id(st, id); + if (pc) ni1_release_l3_process(pc); + return(-2); + } + memcpy(skb_put(skb, l), temp, l); + + if (pc) + { pc->prot.ni1.invoke_id = id; /* remember id */ + L3AddTimer(&pc->timer, ic->parm.ni1_io.timeout, CC_TNI1_IO | REQUEST); + } + + l3_msg(st, DL_DATA | REQUEST, skb); + ic->parm.ni1_io.hl_id = id; /* return id */ + return(0); + + case NI1_CMD_INVOKE_ABORT: + if ((pc = l3ni1_search_dummy_proc(st, ic->parm.ni1_io.hl_id))) + { L3DelTimer(&pc->timer); /* remove timer */ + ni1_release_l3_process(pc); + return(0); + } + else + { l3_debug(st, "l3ni1_cmd_global abort unknown id"); + return(-2); + } + break; + + default: + l3_debug(st, "l3ni1_cmd_global unknown cmd 0x%lx", ic->arg); + return(-1); + } /* switch ic-> arg */ + return(-1); +} /* l3ni1_cmd_global */ + +static void +l3ni1_io_timer(struct l3_process *pc) +{ isdn_ctrl ic; + struct IsdnCardState *cs = pc->st->l1.hardware; + + L3DelTimer(&pc->timer); /* remove timer */ + + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = NI1_STAT_INVOKE_ERR; + ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; + ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; + ic.parm.ni1_io.proc = pc->prot.ni1.proc; + ic.parm.ni1_io.timeout= -1; + ic.parm.ni1_io.datalen = 0; + ic.parm.ni1_io.data = NULL; + free_invoke_id(pc->st, pc->prot.ni1.invoke_id); + pc->prot.ni1.invoke_id = 0; /* reset id */ + + cs->iif.statcallb(&ic); + + ni1_release_l3_process(pc); +} /* l3ni1_io_timer */ + +static void +l3ni1_release_ind(struct l3_process *pc, u_char pr, void *arg) +{ + u_char *p; + struct sk_buff *skb = arg; + int callState = 0; + p = skb->data; + + if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) { + p++; + if (1 == *p++) + callState = *p; + } + if (callState == 0) { + /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1 + * set down layer 3 without sending any message + */ + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + newl3state(pc, 0); + ni1_release_l3_process(pc); + } else { + pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc); + } +} + +static void +l3ni1_dummy(struct l3_process *pc, u_char pr, void *arg) +{ +} + +static void +l3ni1_t302(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 28; /* invalid number */ + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); +} + +static void +l3ni1_t303(struct l3_process *pc, u_char pr, void *arg) +{ + if (pc->N303 > 0) { + pc->N303--; + L3DelTimer(&pc->timer); + l3ni1_setup_req(pc, pr, arg); + } else { + L3DelTimer(&pc->timer); + l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, 102); + pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc); + ni1_release_l3_process(pc); + } +} + +static void +l3ni1_t304(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 102; + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); + +} + +static void +l3ni1_t305(struct l3_process *pc, u_char pr, void *arg) +{ + u_char tmp[16]; + u_char *p = tmp; + int l; + struct sk_buff *skb; + u_char cause = 16; + + L3DelTimer(&pc->timer); + if (pc->para.cause != NO_CAUSE) + cause = pc->para.cause; + + MsgHead(p, pc->callref, MT_RELEASE); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause | 0x80; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + newl3state(pc, 19); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + L3AddTimer(&pc->timer, T308, CC_T308_1); +} + +static void +l3ni1_t310(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 102; + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); +} + +static void +l3ni1_t313(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.loc = 0; + pc->para.cause = 102; + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); +} + +static void +l3ni1_t308_1(struct l3_process *pc, u_char pr, void *arg) +{ + newl3state(pc, 19); + L3DelTimer(&pc->timer); + l3ni1_message(pc, MT_RELEASE); + L3AddTimer(&pc->timer, T308, CC_T308_2); +} + +static void +l3ni1_t308_2(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); + ni1_release_l3_process(pc); +} + +static void +l3ni1_t318(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.cause = 102; /* Timer expiry */ + pc->para.loc = 0; /* local */ + pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); + newl3state(pc, 19); + l3ni1_message(pc, MT_RELEASE); + L3AddTimer(&pc->timer, T308, CC_T308_1); +} + +static void +l3ni1_t319(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.cause = 102; /* Timer expiry */ + pc->para.loc = 0; /* local */ + pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); + newl3state(pc, 10); +} + +static void +l3ni1_restart(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + ni1_release_l3_process(pc); +} + +static void +l3ni1_status(struct l3_process *pc, u_char pr, void *arg) +{ + u_char *p; + struct sk_buff *skb = arg; + int ret; + u_char cause = 0, callState = 0; + + if ((ret = l3ni1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "STATUS get_cause ret(%d)",ret); + if (ret < 0) + cause = 96; + else if (ret > 0) + cause = 100; + } + if ((p = findie(skb->data, skb->len, IE_CALL_STATE, 0))) { + p++; + if (1 == *p++) { + callState = *p; + if (!ie_in_set(pc, *p, l3_valid_states)) + cause = 100; + } else + cause = 100; + } else + cause = 96; + if (!cause) { /* no error before */ + ret = check_infoelements(pc, skb, ie_STATUS); + if (ERR_IE_COMPREHENSION == ret) + cause = 96; + else if (ERR_IE_UNRECOGNIZED == ret) + cause = 99; + } + if (cause) { + u_char tmp; + + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "STATUS error(%d/%d)",ret,cause); + tmp = pc->para.cause; + pc->para.cause = cause; + l3ni1_status_send(pc, 0, NULL); + if (cause == 99) + pc->para.cause = tmp; + else + return; + } + cause = pc->para.cause; + if (((cause & 0x7f) == 111) && (callState == 0)) { + /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... + * if received MT_STATUS with cause == 111 and call + * state == 0, then we must set down layer 3 + */ + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + newl3state(pc, 0); + ni1_release_l3_process(pc); + } +} + +static void +l3ni1_facility(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_FACILITY); + l3ni1_std_ie_err(pc, ret); + { + u_char *p; + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) + l3ni1_parse_facility(pc->st, pc, pc->callref, p); + } +} + +static void +l3ni1_suspend_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[32]; + u_char *p = tmp; + u_char i, l; + u_char *msg = pc->chan->setup.phone; + + MsgHead(p, pc->callref, MT_SUSPEND); + l = *msg++; + if (l && (l <= 10)) { /* Max length 10 octets */ + *p++ = IE_CALL_ID; + *p++ = l; + for (i = 0; i < l; i++) + *p++ = *msg++; + } else if (l) { + l3_debug(pc->st, "SUS wrong CALL_ID len %d", l); + return; + } + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + newl3state(pc, 15); + L3AddTimer(&pc->timer, T319, CC_T319); +} + +static void +l3ni1_suspend_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + L3DelTimer(&pc->timer); + newl3state(pc, 0); + pc->para.cause = NO_CAUSE; + pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc); + /* We don't handle suspend_ack for IE errors now */ + if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE))) + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "SUSPACK check ie(%d)",ret); + ni1_release_l3_process(pc); +} + +static void +l3ni1_suspend_rej(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + if ((ret = l3ni1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "SUSP_REJ get_cause ret(%d)",ret); + if (ret < 0) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + ret = check_infoelements(pc, skb, ie_SUSPEND_REJECT); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); + newl3state(pc, 10); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); +} + +static void +l3ni1_resume_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[32]; + u_char *p = tmp; + u_char i, l; + u_char *msg = pc->para.setup.phone; + + MsgHead(p, pc->callref, MT_RESUME); + + l = *msg++; + if (l && (l <= 10)) { /* Max length 10 octets */ + *p++ = IE_CALL_ID; + *p++ = l; + for (i = 0; i < l; i++) + *p++ = *msg++; + } else if (l) { + l3_debug(pc->st, "RES wrong CALL_ID len %d", l); + return; + } + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + newl3state(pc, 17); + L3AddTimer(&pc->timer, T318, CC_T318); +} + +static void +l3ni1_resume_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int id, ret; + + if ((id = l3ni1_get_channel_id(pc, skb)) > 0) { + if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "resume ack with wrong chid %x", id); + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + pc->para.bchannel = id; + } else if (1 == pc->state) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "resume ack without chid (ret %d)", id); + pc->para.cause = 96; + l3ni1_status_send(pc, pr, NULL); + return; + } + ret = check_infoelements(pc, skb, ie_RESUME_ACKNOWLEDGE); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc); + newl3state(pc, 10); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); +} + +static void +l3ni1_resume_rej(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + if ((ret = l3ni1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "RES_REJ get_cause ret(%d)",ret); + if (ret < 0) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3ni1_status_send(pc, pr, NULL); + return; + } + ret = check_infoelements(pc, skb, ie_RESUME_REJECT); + if (ERR_IE_COMPREHENSION == ret) { + l3ni1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); + newl3state(pc, 0); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3ni1_std_ie_err(pc, ret); + ni1_release_l3_process(pc); +} + +static void +l3ni1_global_restart(struct l3_process *pc, u_char pr, void *arg) +{ + u_char tmp[32]; + u_char *p; + u_char ri, ch = 0, chan = 0; + int l; + struct sk_buff *skb = arg; + struct l3_process *up; + + newl3state(pc, 2); + L3DelTimer(&pc->timer); + p = skb->data; + if ((p = findie(p, skb->len, IE_RESTART_IND, 0))) { + ri = p[2]; + l3_debug(pc->st, "Restart %x", ri); + } else { + l3_debug(pc->st, "Restart without restart IE"); + ri = 0x86; + } + p = skb->data; + if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { + chan = p[2] & 3; + ch = p[2]; + if (pc->st->l3.debug) + l3_debug(pc->st, "Restart for channel %d", chan); + } + newl3state(pc, 2); + up = pc->st->l3.proc; + while (up) { + if ((ri & 7) == 7) + up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); + else if (up->para.bchannel == chan) + up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); + up = up->next; + } + p = tmp; + MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE); + if (chan) { + *p++ = IE_CHANNEL_ID; + *p++ = 1; + *p++ = ch | 0x80; + } + *p++ = 0x79; /* RESTART Ind */ + *p++ = 1; + *p++ = ri; + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + newl3state(pc, 0); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3ni1_dl_reset(struct l3_process *pc, u_char pr, void *arg) +{ + pc->para.cause = 0x29; /* Temporary failure */ + pc->para.loc = 0; + l3ni1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); +} + +static void +l3ni1_dl_release(struct l3_process *pc, u_char pr, void *arg) +{ + newl3state(pc, 0); + pc->para.cause = 0x1b; /* Destination out of order */ + pc->para.loc = 0; + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + release_l3_process(pc); +} + +static void +l3ni1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T309, CC_T309); + l3_msg(pc->st, DL_ESTABLISH | REQUEST, NULL); +} + +static void +l3ni1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + + pc->para.cause = 0x1F; /* normal, unspecified */ + l3ni1_status_send(pc, 0, NULL); +} + +static void l3ni1_SendSpid( struct l3_process *pc, u_char pr, struct sk_buff *skb, int iNewState ) +{ + u_char * p; + char * pSPID; + struct Channel * pChan = pc->st->lli.userdata; + int l; + + if ( skb ) + dev_kfree_skb( skb); + + if ( !( pSPID = strchr( pChan->setup.eazmsn, ':' ) ) ) + { + printk( KERN_ERR "SPID not supplied in EAZMSN %s\n", pChan->setup.eazmsn ); + newl3state( pc, 0 ); + pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL ); + return; + } + + l = strlen( ++pSPID ); + if ( !( skb = l3_alloc_skb( 5+l ) ) ) + { + printk( KERN_ERR "HiSax can't get memory to send SPID\n" ); + return; + } + + p = skb_put( skb, 5 ); + *p++ = PROTO_DIS_EURO; + *p++ = 0; + *p++ = MT_INFORMATION; + *p++ = IE_SPID; + *p++ = l; + + memcpy( skb_put( skb, l ), pSPID, l ); + + newl3state( pc, iNewState ); + + L3DelTimer( &pc->timer ); + L3AddTimer( &pc->timer, TSPID, CC_TSPID ); + + pc->st->l3.l3l2( pc->st, DL_DATA | REQUEST, skb ); +} + +static void l3ni1_spid_send( struct l3_process *pc, u_char pr, void *arg ) +{ + l3ni1_SendSpid( pc, pr, arg, 20 ); +} + +void l3ni1_spid_epid( struct l3_process *pc, u_char pr, void *arg ) +{ + struct sk_buff *skb = arg; + + if ( skb->data[ 1 ] == 0 ) + if ( skb->data[ 3 ] == IE_ENDPOINT_ID ) + { + L3DelTimer( &pc->timer ); + newl3state( pc, 0 ); + l3_msg( pc->st, DL_ESTABLISH | CONFIRM, NULL ); + } + dev_kfree_skb( skb); +} + +static void l3ni1_spid_tout( struct l3_process *pc, u_char pr, void *arg ) +{ + if ( pc->state < 22 ) + l3ni1_SendSpid( pc, pr, arg, pc->state+1 ); + else + { + L3DelTimer( &pc->timer ); + dev_kfree_skb( arg); + + printk( KERN_ERR "SPID not accepted\n" ); + newl3state( pc, 0 ); + pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL ); + } +} + +/* *INDENT-OFF* */ +static struct stateentry downstatelist[] = +{ + {SBIT(0), + CC_SETUP | REQUEST, l3ni1_setup_req}, + {SBIT(0), + CC_RESUME | REQUEST, l3ni1_resume_req}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25), + CC_DISCONNECT | REQUEST, l3ni1_disconnect_req}, + {SBIT(12), + CC_RELEASE | REQUEST, l3ni1_release_req}, + {ALL_STATES, + CC_RESTART | REQUEST, l3ni1_restart}, + {SBIT(6) | SBIT(25), + CC_IGNORE | REQUEST, l3ni1_reset}, + {SBIT(6) | SBIT(25), + CC_REJECT | REQUEST, l3ni1_reject_req}, + {SBIT(6) | SBIT(25), + CC_PROCEED_SEND | REQUEST, l3ni1_proceed_req}, + {SBIT(6), + CC_MORE_INFO | REQUEST, l3ni1_setup_ack_req}, + {SBIT(25), + CC_MORE_INFO | REQUEST, l3ni1_dummy}, + {SBIT(6) | SBIT(9) | SBIT(25), + CC_ALERTING | REQUEST, l3ni1_alert_req}, + {SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25), + CC_SETUP | RESPONSE, l3ni1_setup_rsp}, + {SBIT(10), + CC_SUSPEND | REQUEST, l3ni1_suspend_req}, + {SBIT(7) | SBIT(9) | SBIT(25), + CC_REDIR | REQUEST, l3ni1_redir_req}, + {SBIT(6), + CC_REDIR | REQUEST, l3ni1_redir_req_early}, + {SBIT(9) | SBIT(25), + CC_DISCONNECT | REQUEST, l3ni1_disconnect_req}, + {SBIT(25), + CC_T302, l3ni1_t302}, + {SBIT(1), + CC_T303, l3ni1_t303}, + {SBIT(2), + CC_T304, l3ni1_t304}, + {SBIT(3), + CC_T310, l3ni1_t310}, + {SBIT(8), + CC_T313, l3ni1_t313}, + {SBIT(11), + CC_T305, l3ni1_t305}, + {SBIT(15), + CC_T319, l3ni1_t319}, + {SBIT(17), + CC_T318, l3ni1_t318}, + {SBIT(19), + CC_T308_1, l3ni1_t308_1}, + {SBIT(19), + CC_T308_2, l3ni1_t308_2}, + {SBIT(10), + CC_T309, l3ni1_dl_release}, + { SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ), + CC_TSPID, l3ni1_spid_tout }, +}; + +#define DOWNSLLEN \ + (sizeof(downstatelist) / sizeof(struct stateentry)) + +static struct stateentry datastatelist[] = +{ + {ALL_STATES, + MT_STATUS_ENQUIRY, l3ni1_status_enq}, + {ALL_STATES, + MT_FACILITY, l3ni1_facility}, + {SBIT(19), + MT_STATUS, l3ni1_release_ind}, + {ALL_STATES, + MT_STATUS, l3ni1_status}, + {SBIT(0), + MT_SETUP, l3ni1_setup}, + {SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | + SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), + MT_SETUP, l3ni1_dummy}, + {SBIT(1) | SBIT(2), + MT_CALL_PROCEEDING, l3ni1_call_proc}, + {SBIT(1), + MT_SETUP_ACKNOWLEDGE, l3ni1_setup_ack}, + {SBIT(2) | SBIT(3), + MT_ALERTING, l3ni1_alerting}, + {SBIT(2) | SBIT(3), + MT_PROGRESS, l3ni1_progress}, + {SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | + SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), + MT_INFORMATION, l3ni1_information}, + {SBIT(10) | SBIT(11) | SBIT(15), + MT_NOTIFY, l3ni1_notify}, + {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) | + SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), + MT_RELEASE_COMPLETE, l3ni1_release_cmpl}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(25), + MT_RELEASE, l3ni1_release}, + {SBIT(19), MT_RELEASE, l3ni1_release_ind}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25), + MT_DISCONNECT, l3ni1_disconnect}, + {SBIT(19), + MT_DISCONNECT, l3ni1_dummy}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4), + MT_CONNECT, l3ni1_connect}, + {SBIT(8), + MT_CONNECT_ACKNOWLEDGE, l3ni1_connect_ack}, + {SBIT(15), + MT_SUSPEND_ACKNOWLEDGE, l3ni1_suspend_ack}, + {SBIT(15), + MT_SUSPEND_REJECT, l3ni1_suspend_rej}, + {SBIT(17), + MT_RESUME_ACKNOWLEDGE, l3ni1_resume_ack}, + {SBIT(17), + MT_RESUME_REJECT, l3ni1_resume_rej}, +}; + +#define DATASLLEN \ + (sizeof(datastatelist) / sizeof(struct stateentry)) + +static struct stateentry globalmes_list[] = +{ + {ALL_STATES, + MT_STATUS, l3ni1_status}, + {SBIT(0), + MT_RESTART, l3ni1_global_restart}, +/* {SBIT(1), + MT_RESTART_ACKNOWLEDGE, l3ni1_restart_ack}, +*/ + { SBIT( 0 ), MT_DL_ESTABLISHED, l3ni1_spid_send }, + { SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ), MT_INFORMATION, l3ni1_spid_epid }, +}; +#define GLOBALM_LEN \ + (sizeof(globalmes_list) / sizeof(struct stateentry)) + +static struct stateentry manstatelist[] = +{ + {SBIT(2), + DL_ESTABLISH | INDICATION, l3ni1_dl_reset}, + {SBIT(10), + DL_ESTABLISH | CONFIRM, l3ni1_dl_reest_status}, + {SBIT(10), + DL_RELEASE | INDICATION, l3ni1_dl_reestablish}, + {ALL_STATES, + DL_RELEASE | INDICATION, l3ni1_dl_release}, +}; + +#define MANSLLEN \ + (sizeof(manstatelist) / sizeof(struct stateentry)) +/* *INDENT-ON* */ + + +static void +global_handler(struct PStack *st, int mt, struct sk_buff *skb) +{ + u_char tmp[16]; + u_char *p = tmp; + int l; + int i; + struct l3_process *proc = st->l3.global; + + if ( skb ) + proc->callref = skb->data[2]; /* cr flag */ + else + proc->callref = 0; + for (i = 0; i < GLOBALM_LEN; i++) + if ((mt == globalmes_list[i].primitive) && + ((1 << proc->state) & globalmes_list[i].state)) + break; + if (i == GLOBALM_LEN) { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1 global state %d mt %x unhandled", + proc->state, mt); + } + MsgHead(p, proc->callref, MT_STATUS); + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = 81 |0x80; /* invalid cr */ + *p++ = 0x14; /* CallState */ + *p++ = 0x1; + *p++ = proc->state & 0x3f; + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(proc->st, DL_DATA | REQUEST, skb); + } else { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1 global %d mt %x", + proc->state, mt); + } + globalmes_list[i].rout(proc, mt, skb); + } +} + +static void +ni1up(struct PStack *st, int pr, void *arg) +{ + int i, mt, cr, cause, callState; + char *ptr; + u_char *p; + struct sk_buff *skb = arg; + struct l3_process *proc; + + switch (pr) { + case (DL_DATA | INDICATION): + case (DL_UNIT_DATA | INDICATION): + break; + case (DL_ESTABLISH | INDICATION): + case (DL_RELEASE | INDICATION): + case (DL_RELEASE | CONFIRM): + l3_msg(st, pr, arg); + return; + break; + + case (DL_ESTABLISH | CONFIRM): + global_handler( st, MT_DL_ESTABLISHED, NULL ); + return; + + default: + printk(KERN_ERR "HiSax ni1up unknown pr=%04x\n", pr); + return; + } + if (skb->len < 3) { + l3_debug(st, "ni1up frame too short(%d)", skb->len); + dev_kfree_skb(skb); + return; + } + + if (skb->data[0] != PROTO_DIS_EURO) { + if (st->l3.debug & L3_DEB_PROTERR) { + l3_debug(st, "ni1up%sunexpected discriminator %x message len %d", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", + skb->data[0], skb->len); + } + dev_kfree_skb(skb); + return; + } + cr = getcallref(skb->data); + if (skb->len < ((skb->data[1] & 0x0f) + 3)) { + l3_debug(st, "ni1up frame too short(%d)", skb->len); + dev_kfree_skb(skb); + return; + } + mt = skb->data[skb->data[1] + 2]; + if (st->l3.debug & L3_DEB_STATE) + l3_debug(st, "ni1up cr %d", cr); + if (cr == -2) { /* wrong Callref */ + if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "ni1up wrong Callref"); + dev_kfree_skb(skb); + return; + } else if (cr == -1) { /* Dummy Callref */ + if (mt == MT_FACILITY) + { + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { + l3ni1_parse_facility(st, NULL, + (pr == (DL_DATA | INDICATION)) ? -1 : -2, p); + dev_kfree_skb(skb); + return; + } + } + else + { + global_handler(st, mt, skb); + return; + } + + if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "ni1up dummy Callref (no facility msg or ie)"); + dev_kfree_skb(skb); + return; + } else if ((((skb->data[1] & 0x0f) == 1) && (0==(cr & 0x7f))) || + (((skb->data[1] & 0x0f) == 2) && (0==(cr & 0x7fff)))) { /* Global CallRef */ + if (st->l3.debug & L3_DEB_STATE) + l3_debug(st, "ni1up Global CallRef"); + global_handler(st, mt, skb); + dev_kfree_skb(skb); + return; + } else if (!(proc = getl3proc(st, cr))) { + /* No transaction process exist, that means no call with + * this callreference is active + */ + if (mt == MT_SETUP) { + /* Setup creates a new transaction process */ + if (skb->data[2] & 0x80) { + /* Setup with wrong CREF flag */ + if (st->l3.debug & L3_DEB_STATE) + l3_debug(st, "ni1up wrong CRef flag"); + dev_kfree_skb(skb); + return; + } + if (!(proc = ni1_new_l3_process(st, cr))) { + /* May be to answer with RELEASE_COMPLETE and + * CAUSE 0x2f "Resource unavailable", but this + * need a new_l3_process too ... arghh + */ + dev_kfree_skb(skb); + return; + } + } else if (mt == MT_STATUS) { + cause = 0; + if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) { + ptr++; + if (*ptr++ == 2) + ptr++; + cause = *ptr & 0x7f; + } + callState = 0; + if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) { + ptr++; + if (*ptr++ == 2) + ptr++; + callState = *ptr; + } + /* ETS 300-104 part 2.4.1 + * if setup has not been made and a message type + * MT_STATUS is received with call state == 0, + * we must send nothing + */ + if (callState != 0) { + /* ETS 300-104 part 2.4.2 + * if setup has not been made and a message type + * MT_STATUS is received with call state != 0, + * we must send MT_RELEASE_COMPLETE cause 101 + */ + if ((proc = ni1_new_l3_process(st, cr))) { + proc->para.cause = 101; + l3ni1_msg_without_setup(proc, 0, NULL); + } + } + dev_kfree_skb(skb); + return; + } else if (mt == MT_RELEASE_COMPLETE) { + dev_kfree_skb(skb); + return; + } else { + /* ETS 300-104 part 2 + * if setup has not been made and a message type + * (except MT_SETUP and RELEASE_COMPLETE) is received, + * we must send MT_RELEASE_COMPLETE cause 81 */ + dev_kfree_skb(skb); + if ((proc = ni1_new_l3_process(st, cr))) { + proc->para.cause = 81; + l3ni1_msg_without_setup(proc, 0, NULL); + } + return; + } + } + if (l3ni1_check_messagetype_validity(proc, mt, skb)) { + dev_kfree_skb(skb); + return; + } + if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL) + l3ni1_deliver_display(proc, pr, p); /* Display IE included */ + for (i = 0; i < DATASLLEN; i++) + if ((mt == datastatelist[i].primitive) && + ((1 << proc->state) & datastatelist[i].state)) + break; + if (i == DATASLLEN) { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1up%sstate %d mt %#x unhandled", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", + proc->state, mt); + } + if ((MT_RELEASE_COMPLETE != mt) && (MT_RELEASE != mt)) { + proc->para.cause = 101; + l3ni1_status_send(proc, pr, skb); + } + } else { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1up%sstate %d mt %x", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", + proc->state, mt); + } + datastatelist[i].rout(proc, pr, skb); + } + dev_kfree_skb(skb); + return; +} + +static void +ni1down(struct PStack *st, int pr, void *arg) +{ + int i, cr; + struct l3_process *proc; + struct Channel *chan; + + if ((DL_ESTABLISH | REQUEST) == pr) { + l3_msg(st, pr, NULL); + return; + } else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) { + chan = arg; + cr = newcallref(); + cr |= 0x80; + if ((proc = ni1_new_l3_process(st, cr))) { + proc->chan = chan; + chan->proc = proc; + memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); + proc->callref = cr; + } + } else { + proc = arg; + } + if (!proc) { + printk(KERN_ERR "HiSax ni1down without proc pr=%04x\n", pr); + return; + } + + if ( pr == (CC_TNI1_IO | REQUEST)) { + l3ni1_io_timer(proc); /* timer expires */ + return; + } + + for (i = 0; i < DOWNSLLEN; i++) + if ((pr == downstatelist[i].primitive) && + ((1 << proc->state) & downstatelist[i].state)) + break; + if (i == DOWNSLLEN) { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1down state %d prim %#x unhandled", + proc->state, pr); + } + } else { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "ni1down state %d prim %#x", + proc->state, pr); + } + downstatelist[i].rout(proc, pr, arg); + } +} + +static void +ni1man(struct PStack *st, int pr, void *arg) +{ + int i; + struct l3_process *proc = arg; + + if (!proc) { + printk(KERN_ERR "HiSax ni1man without proc pr=%04x\n", pr); + return; + } + for (i = 0; i < MANSLLEN; i++) + if ((pr == manstatelist[i].primitive) && + ((1 << proc->state) & manstatelist[i].state)) + break; + if (i == MANSLLEN) { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "cr %d ni1man state %d prim %#x unhandled", + proc->callref & 0x7f, proc->state, pr); + } + } else { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "cr %d ni1man state %d prim %#x", + proc->callref & 0x7f, proc->state, pr); + } + manstatelist[i].rout(proc, pr, arg); + } +} + +void +setstack_ni1(struct PStack *st) +{ + char tmp[64]; + int i; + + st->lli.l4l3 = ni1down; + st->lli.l4l3_proto = l3ni1_cmd_global; + st->l2.l2l3 = ni1up; + st->l3.l3ml3 = ni1man; + st->l3.N303 = 1; + st->prot.ni1.last_invoke_id = 0; + st->prot.ni1.invoke_used[0] = 1; /* Bit 0 must always be set to 1 */ + i = 1; + while (i < 32) + st->prot.ni1.invoke_used[i++] = 0; + + if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) { + printk(KERN_ERR "HiSax can't get memory for ni1 global CR\n"); + } else { + st->l3.global->state = 0; + st->l3.global->callref = 0; + st->l3.global->next = NULL; + st->l3.global->debug = L3_DEB_WARN; + st->l3.global->st = st; + st->l3.global->N303 = 1; + st->l3.global->prot.ni1.invoke_id = 0; + + L3InitTimer(st->l3.global, &st->l3.global->timer); + } + strcpy(tmp, ni1_revision); + printk(KERN_INFO "HiSax: National ISDN-1 Rev. %s\n", HiSax_getrev(tmp)); +} diff --git a/drivers/isdn/hisax/l3ni1.h b/drivers/isdn/hisax/l3ni1.h new file mode 100644 index 000000000..24c919a17 --- /dev/null +++ b/drivers/isdn/hisax/l3ni1.h @@ -0,0 +1,136 @@ +// $Id: l3ni1.h,v 2.2 2000/06/26 08:59:14 keil Exp $ +//----------------------------------------------------------------------------- +// +// NI1 D-channel protocol +// +// Author Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd +// www.traverse.com.au +// +// 2000.6.6 Initial implementation of routines for US NI1 +// Layer 3 protocol based on the EURO/DSS1 D-channel protocol +// driver written by Karsten Keil et al. Thanks also for the +// code provided by Ragnar Paulson. +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- + +#ifndef l3ni1_process + +#define T302 15000 +#define T303 4000 +#define T304 30000 +#define T305 30000 +#define T308 4000 +/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */ +/* This makes some tests easier and quicker */ +#define T309 40000 +#define T310 30000 +#define T313 4000 +#define T318 4000 +#define T319 4000 +#define TSPID 2000 + +/* + * Message-Types + */ + +#define MT_ALERTING 0x01 +#define MT_CALL_PROCEEDING 0x02 +#define MT_CONNECT 0x07 +#define MT_CONNECT_ACKNOWLEDGE 0x0f +#define MT_PROGRESS 0x03 +#define MT_SETUP 0x05 +#define MT_SETUP_ACKNOWLEDGE 0x0d +#define MT_RESUME 0x26 +#define MT_RESUME_ACKNOWLEDGE 0x2e +#define MT_RESUME_REJECT 0x22 +#define MT_SUSPEND 0x25 +#define MT_SUSPEND_ACKNOWLEDGE 0x2d +#define MT_SUSPEND_REJECT 0x21 +#define MT_USER_INFORMATION 0x20 +#define MT_DISCONNECT 0x45 +#define MT_RELEASE 0x4d +#define MT_RELEASE_COMPLETE 0x5a +#define MT_RESTART 0x46 +#define MT_RESTART_ACKNOWLEDGE 0x4e +#define MT_SEGMENT 0x60 +#define MT_CONGESTION_CONTROL 0x79 +#define MT_INFORMATION 0x7b +#define MT_FACILITY 0x62 +#define MT_NOTIFY 0x6e +#define MT_STATUS 0x7d +#define MT_STATUS_ENQUIRY 0x75 +#define MT_DL_ESTABLISHED 0xfe + +#define IE_SEGMENT 0x00 +#define IE_BEARER 0x04 +#define IE_CAUSE 0x08 +#define IE_CALL_ID 0x10 +#define IE_CALL_STATE 0x14 +#define IE_CHANNEL_ID 0x18 +#define IE_FACILITY 0x1c +#define IE_PROGRESS 0x1e +#define IE_NET_FAC 0x20 +#define IE_NOTIFY 0x27 +#define IE_DISPLAY 0x28 +#define IE_DATE 0x29 +#define IE_KEYPAD 0x2c +#define IE_SIGNAL 0x34 +#define IE_SPID 0x3a +#define IE_ENDPOINT_ID 0x3b +#define IE_INFORATE 0x40 +#define IE_E2E_TDELAY 0x42 +#define IE_TDELAY_SEL 0x43 +#define IE_PACK_BINPARA 0x44 +#define IE_PACK_WINSIZE 0x45 +#define IE_PACK_SIZE 0x46 +#define IE_CUG 0x47 +#define IE_REV_CHARGE 0x4a +#define IE_CONNECT_PN 0x4c +#define IE_CONNECT_SUB 0x4d +#define IE_CALLING_PN 0x6c +#define IE_CALLING_SUB 0x6d +#define IE_CALLED_PN 0x70 +#define IE_CALLED_SUB 0x71 +#define IE_REDIR_NR 0x74 +#define IE_TRANS_SEL 0x78 +#define IE_RESTART_IND 0x79 +#define IE_LLC 0x7c +#define IE_HLC 0x7d +#define IE_USER_USER 0x7e +#define IE_ESCAPE 0x7f +#define IE_SHIFT 0x90 +#define IE_MORE_DATA 0xa0 +#define IE_COMPLETE 0xa1 +#define IE_CONGESTION 0xb0 +#define IE_REPEAT 0xd0 + +#define IE_MANDATORY 0x0100 +/* mandatory not in every case */ +#define IE_MANDATORY_1 0x0200 + +#define ERR_IE_COMPREHENSION 1 +#define ERR_IE_UNRECOGNIZED -1 +#define ERR_IE_LENGTH -2 +#define ERR_IE_SEQUENCE -3 + +#else /* only l3ni1_process */ + +/* l3ni1 specific data in l3 process */ +typedef struct + { unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */ + ulong ll_id; /* remebered ll id */ + u_char remote_operation; /* handled remote operation, 0 = not active */ + int proc; /* rememered procedure */ + ulong remote_result; /* result of remote operation for statcallb */ + char uus1_data[35]; /* data send during alerting or disconnect */ + } ni1_proc_priv; + +/* l3dni1 specific data in protocol stack */ +typedef struct + { unsigned char last_invoke_id; /* last used value for invoking */ + unsigned char invoke_used[32]; /* 256 bits for 256 values */ + } ni1_stk_priv; + +#endif /* only l3dni1_process */ diff --git a/drivers/isdn/hisax/md5sums.asc b/drivers/isdn/hisax/md5sums.asc index 3ccbfc33a..a8e65d8b2 100644 --- a/drivers/isdn/hisax/md5sums.asc +++ b/drivers/isdn/hisax/md5sums.asc @@ -2,30 +2,32 @@ # This are valid md5sums for certificated HiSax driver. # The certification is valid only if the md5sums of all files match. -# The certification is valid only for ELSA QuickStep cards and -# Eicon Technology Diva 2.01 PCI cards in the moment. +# The certification is valid only for ELSA Microlink PCI, +# Eicon Technology Diva 2.01 PCI and Sedlbauer SpeedFax + +# cards in the moment. # Read ../../../Documentation/isdn/HiSax.cert for more informations. # -3fb9c99465857a4c136ae2881f4e30ba isac.c -dd3955847bbf680b41233478fe521d88 isdnl1.c -d362523462c424a8bce8b596ed5bdf2e isdnl2.c -92ea268891c222963a6ca70935bf1556 isdnl3.c -a23fbf8879c1432b04640b8b04bdf419 tei.c -838791b14269ec94c74ba4ae89c022e6 callc.c -bf9605b36429898f7be6630034e83230 cert.c -a30e6253837739f6f54d9dadcd42d9f2 l3dss1.c -a3a570781f828b6d59e6b231653133de l3_1tr6.c -4aeba32c4c3480d2a6b9af34600b974f elsa.c -a296edc459b508bf0346c3132815a4db diva.c +f4573d10ffe38b49f6c94e4c966b7bab isac.c +a29f5270c0c89626d8d6fa5dd09e7005 isdnl1.c +fbe41751c8130a8c3c607bfe1b41cb4e isdnl2.c +7915b7e802b98f6f4f05b931c4736ad4 isdnl3.c +7c31c12b3c2cfde33596bd2c406f775c tei.c +f1fbd532016f005e01decf36e5197d8f callc.c +a1834e9b2ec068440cff2e899eff4710 cert.c +a1f908f8b4f225c5c2f2a13842549b72 l3dss1.c +5bcab52f9937beb352aa02093182e039 l3_1tr6.c +030d4600ee59a2b246410d6a73977412 elsa.c +9e800b8e05c24542d731721eb192f305 diva.c +f32fae58dd9b2b3a73b2e5028f68dc4c sedlbauer.c # end of md5sums -----BEGIN PGP SIGNATURE----- Version: 2.6.3i Charset: noconv -iQCVAwUBOPT2aTpxHvX/mS9tAQFJyAQAj+eY8MhPxQ2TS3rtfjK7bv8jrOGeJYu6 -P0YPnkkc09pCA6UdmYP6VSFkhtDS43HEZiGMb1MV/Y4LQ4wVDNrFDk9AyUNhP2/0 -gY+nYON6hT9ilXYqsbqoqGmh5qLaxj64p9mKu+MIgZ69CS4g7aj/OAXWB06zh7li -MiC65PNo6k0= -=d7xA +iQCVAwUBOaARmDpxHvX/mS9tAQFT7wP/TEEhtP96uKKgzr2o3GpJ5rRik0Q1HbKY +dzeA3U79QCEYqyptU09Uz96Av3dt1lNxpQyaahX419NjHH53HCaZgFCxgRxFWBYS +M9s4aSXLPTCSNM/kWiZkzWQ2lZ7ISNk2/+fF73w4l3G+4zF5y+VotjZCPx7OJj6i +R/L1m4vZXys= +=6DzE -----END PGP SIGNATURE----- diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c index fd51217bf..6be8a493d 100644 --- a/drivers/isdn/hisax/netjet.c +++ b/drivers/isdn/hisax/netjet.c @@ -11,7 +11,6 @@ */ #define __NO_VERSION__ -#include <linux/config.h> #include "hisax.h" #include "isac.h" #include "hscx.h" @@ -19,6 +18,7 @@ #include <linux/pci.h> #include <linux/interrupt.h> #include <linux/ppp_defs.h> +#include "netjet.h" #ifndef bus_to_virt #define bus_to_virt (u_int *) @@ -28,61 +28,12 @@ #define virt_to_bus (u_int) #endif -extern const char *CardType[]; - -const char *NETjet_revision = "$Revision: 1.18 $"; - -#define byteout(addr,val) outb(val,addr) -#define bytein(addr) inb(addr) - -/* PCI stuff */ -#define PCI_VENDOR_TRAVERSE_TECH 0xe159 -#define PCI_NETJET_ID 0x0001 - -#define NETJET_CTRL 0x00 -#define NETJET_DMACTRL 0x01 -#define NETJET_AUXCTRL 0x02 -#define NETJET_AUXDATA 0x03 -#define NETJET_IRQMASK0 0x04 -#define NETJET_IRQMASK1 0x05 -#define NETJET_IRQSTAT0 0x06 -#define NETJET_IRQSTAT1 0x07 -#define NETJET_DMA_READ_START 0x08 -#define NETJET_DMA_READ_IRQ 0x0c -#define NETJET_DMA_READ_END 0x10 -#define NETJET_DMA_READ_ADR 0x14 -#define NETJET_DMA_WRITE_START 0x18 -#define NETJET_DMA_WRITE_IRQ 0x1c -#define NETJET_DMA_WRITE_END 0x20 -#define NETJET_DMA_WRITE_ADR 0x24 -#define NETJET_PULSE_CNT 0x28 - -#define NETJET_ISAC_OFF 0xc0 -#define NETJET_ISACIRQ 0x10 -#define NETJET_IRQM0_READ 0x0c -#define NETJET_IRQM0_READ_1 0x04 -#define NETJET_IRQM0_READ_2 0x08 -#define NETJET_IRQM0_WRITE 0x03 -#define NETJET_IRQM0_WRITE_1 0x01 -#define NETJET_IRQM0_WRITE_2 0x02 - -#define NETJET_DMA_TXSIZE 512 -#define NETJET_DMA_RXSIZE 128 - -#define HDLC_ZERO_SEARCH 0 -#define HDLC_FLAG_SEARCH 1 -#define HDLC_FLAG_FOUND 2 -#define HDLC_FRAME_FOUND 3 -#define HDLC_NULL 4 -#define HDLC_PART 5 -#define HDLC_FULL 6 - -#define HDLC_FLAG_VALUE 0x7e +const char *NETjet_revision = "$Revision: 1.20 $"; /* Interface functions */ -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) +u_char +NETjet_ReadIC(struct IsdnCardState *cs, u_char offset) { long flags; u_char ret; @@ -97,8 +48,8 @@ ReadISAC(struct IsdnCardState *cs, u_char offset) return(ret); } -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) +void +NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value) { long flags; @@ -111,8 +62,8 @@ WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) restore_flags(flags); } -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) +void +NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size) { cs->hw.njet.auxd &= 0xfc; byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); @@ -155,8 +106,8 @@ __u16 fcstab[256] = 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) +void +NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size) { cs->hw.njet.auxd &= 0xfc; byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); @@ -242,15 +193,6 @@ mode_tiger(struct BCState *bcs, int mode, int bc) bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); } -static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) -{ - return(5); -} - -static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value) -{ -} - static void printframe(struct IsdnCardState *cs, u_char *buf, int count, char *s) { char tmp[128]; char *t = tmp; @@ -541,7 +483,7 @@ static void read_raw(struct BCState *bcs, u_int *buf, int cnt){ bcs->hw.tiger.r_bitcnt = bitcnt; } -static void read_tiger(struct IsdnCardState *cs) { +void read_tiger(struct IsdnCardState *cs) { u_int *p; int cnt = NETJET_DMA_RXSIZE/2; @@ -572,7 +514,7 @@ static void read_tiger(struct IsdnCardState *cs) { static void write_raw(struct BCState *bcs, u_int *buf, int cnt); -static void fill_dma(struct BCState *bcs) +void netjet_fill_dma(struct BCState *bcs) { register u_int *p, *sp; register int cnt; @@ -687,7 +629,7 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) { test_and_set_bit(BC_FLG_NOFRAME, &bcs->Flag); } if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - fill_dma(bcs); + netjet_fill_dma(bcs); } else { mask ^= 0xffffffff; if (s_cnt < cnt) { @@ -719,7 +661,7 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) { } } -static void write_tiger(struct IsdnCardState *cs) { +void write_tiger(struct IsdnCardState *cs) { u_int *p, cnt = NETJET_DMA_TXSIZE/2; if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_WRITE) { @@ -935,88 +877,6 @@ releasetiger(struct IsdnCardState *cs) } } -static void -netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs) -{ - struct IsdnCardState *cs = dev_id; - u_char val, sval; - long flags; - - if (!cs) { - printk(KERN_WARNING "NETjet: Spurious interrupt!\n"); - return; - } - if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) & - NETJET_ISACIRQ)) { - val = ReadISAC(cs, ISAC_ISTA); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "tiger: i1 %x %x", sval, val); - if (val) { - isac_interrupt(cs, val); - WriteISAC(cs, ISAC_MASK, 0xFF); - WriteISAC(cs, ISAC_MASK, 0x0); - } - } - save_flags(flags); - cli(); - if ((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) { - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - restore_flags(flags); - return; - } - cs->hw.njet.irqstat0 = sval; - restore_flags(flags); -/* debugl1(cs, "tiger: ist0 %x %x %x %x/%x pulse=%d", - sval, - bytein(cs->hw.njet.base + NETJET_DMACTRL), - bytein(cs->hw.njet.base + NETJET_IRQMASK0), - inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), - inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), - bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); -*/ -/* cs->hw.njet.irqmask0 = ((0x0f & cs->hw.njet.irqstat0) ^ 0x0f) | 0x30; -*/ byteout(cs->hw.njet.base + NETJET_IRQSTAT0, cs->hw.njet.irqstat0); -/* byteout(cs->hw.njet.base + NETJET_IRQMASK0, cs->hw.njet.irqmask0); -*/ if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) - read_tiger(cs); - if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) - write_tiger(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - restore_flags(flags); - -/* if (!testcnt--) { - cs->hw.njet.dmactrl = 0; - byteout(cs->hw.njet.base + NETJET_DMACTRL, - cs->hw.njet.dmactrl); - byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); - } -*/ -} - -static void -reset_netjet(struct IsdnCardState *cs) -{ - long flags; - - save_flags(flags); - sti(); - cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - restore_flags(flags); - cs->hw.njet.auxd = 0; - cs->hw.njet.dmactrl = 0; - byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); - byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); -} - void release_io_netjet(struct IsdnCardState *cs) { @@ -1026,100 +886,3 @@ release_io_netjet(struct IsdnCardState *cs) release_region(cs->hw.njet.base, 256); } - -static int -NETjet_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - switch (mt) { - case CARD_RESET: - reset_netjet(cs); - return(0); - case CARD_RELEASE: - release_io_netjet(cs); - return(0); - case CARD_INIT: - inittiger(cs); - clear_pending_isac_ints(cs); - initisac(cs); - /* Reenable all IRQ */ - cs->writeisac(cs, ISAC_MASK, 0); - return(0); - case CARD_TEST: - return(0); - } - return(0); -} - -static struct pci_dev *dev_netjet __initdata = NULL; - -__initfunc(int -setup_netjet(struct IsdnCard *card)) -{ - int bytecnt; - struct IsdnCardState *cs = card->cs; - char tmp[64]; -#if CONFIG_PCI -#endif - strcpy(tmp, NETjet_revision); - printk(KERN_INFO "HiSax: Traverse Tech. NETjet driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_NETJET) - return(0); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); -#if CONFIG_PCI - if (!pci_present()) { - printk(KERN_ERR "Netjet: no PCI bus present\n"); - return(0); - } - if ((dev_netjet = pci_find_device(PCI_VENDOR_TRAVERSE_TECH, - PCI_NETJET_ID, dev_netjet))) { - if (pci_enable_device(dev_netjet)) - return (0); - cs->irq = dev_netjet->irq; - if (!cs->irq) { - printk(KERN_WARNING "NETjet: No IRQ for PCI card found\n"); - return(0); - } - cs->hw.njet.base = pci_resource_start(dev_netjet, 0); - if (!cs->hw.njet.base) { - printk(KERN_WARNING "NETjet: No IO-Adr for PCI card found\n"); - return(0); - } - } else { - printk(KERN_WARNING "NETjet: No PCI card found\n"); - return(0); - } - cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; - cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; - bytecnt = 256; -#else - printk(KERN_WARNING "NETjet: NO_PCI_BIOS\n"); - printk(KERN_WARNING "NETjet: unable to config NETJET PCI\n"); - return (0); -#endif /* CONFIG_PCI */ - printk(KERN_INFO - "NETjet: PCI card configured at 0x%x IRQ %d\n", - cs->hw.njet.base, cs->irq); - if (check_region(cs->hw.njet.base, bytecnt)) { - printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], - cs->hw.njet.base, - cs->hw.njet.base + bytecnt); - return (0); - } else { - request_region(cs->hw.njet.base, bytecnt, "netjet isdn"); - } - reset_netjet(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &dummyrr; - cs->BC_Write_Reg = &dummywr; - cs->BC_Send_Data = &fill_dma; - cs->cardmsg = &NETjet_card_msg; - cs->irq_func = &netjet_interrupt; - cs->irq_flags |= SA_SHIRQ; - ISACVersion(cs, "NETjet:"); - return (1); -} diff --git a/drivers/isdn/hisax/netjet.h b/drivers/isdn/hisax/netjet.h new file mode 100644 index 000000000..d7dede4ff --- /dev/null +++ b/drivers/isdn/hisax/netjet.h @@ -0,0 +1,77 @@ +// $Id: netjet.h,v 2.3 2000/06/26 08:59:14 keil Exp $ +//----------------------------------------------------------------------------- +// +// NETjet common header file +// +// Author Kerstern Keil repackaged by +// Matt Henderson - Traverse Technologies P/L www.traverse.com.au +// +// This file is (c) under GNU PUBLIC LICENSE +// +//----------------------------------------------------------------------------- + +extern const char *CardType[]; + +#define byteout(addr,val) outb(val,addr) +#define bytein(addr) inb(addr) + +/* PCI stuff */ +#ifndef PCI_VENDOR_ID_TIGERJET +#define PCI_VENDOR_ID_TIGERJET 0xe159 +#endif +#ifndef PCI_DEVICE_ID_TIGERJET_300 +#define PCI_DEVICE_ID_TIGERJET_300 0x0001 +#endif +#define NETJET_CTRL 0x00 +#define NETJET_DMACTRL 0x01 +#define NETJET_AUXCTRL 0x02 +#define NETJET_AUXDATA 0x03 +#define NETJET_IRQMASK0 0x04 +#define NETJET_IRQMASK1 0x05 +#define NETJET_IRQSTAT0 0x06 +#define NETJET_IRQSTAT1 0x07 +#define NETJET_DMA_READ_START 0x08 +#define NETJET_DMA_READ_IRQ 0x0c +#define NETJET_DMA_READ_END 0x10 +#define NETJET_DMA_READ_ADR 0x14 +#define NETJET_DMA_WRITE_START 0x18 +#define NETJET_DMA_WRITE_IRQ 0x1c +#define NETJET_DMA_WRITE_END 0x20 +#define NETJET_DMA_WRITE_ADR 0x24 +#define NETJET_PULSE_CNT 0x28 + +#define NETJET_ISAC_OFF 0xc0 +#define NETJET_ISACIRQ 0x10 +#define NETJET_IRQM0_READ 0x0c +#define NETJET_IRQM0_READ_1 0x04 +#define NETJET_IRQM0_READ_2 0x08 +#define NETJET_IRQM0_WRITE 0x03 +#define NETJET_IRQM0_WRITE_1 0x01 +#define NETJET_IRQM0_WRITE_2 0x02 + +#define NETJET_DMA_TXSIZE 512 +#define NETJET_DMA_RXSIZE 128 + +#define HDLC_ZERO_SEARCH 0 +#define HDLC_FLAG_SEARCH 1 +#define HDLC_FLAG_FOUND 2 +#define HDLC_FRAME_FOUND 3 +#define HDLC_NULL 4 +#define HDLC_PART 5 +#define HDLC_FULL 6 + +#define HDLC_FLAG_VALUE 0x7e + +u_char NETjet_ReadIC(struct IsdnCardState *cs, u_char offset); +void NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value); +void NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size); +void NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size); + +void read_tiger(struct IsdnCardState *cs); +void write_tiger(struct IsdnCardState *cs); + +void netjet_fill_dma(struct BCState *bcs); +void netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs); +__initfunc(void inittiger(struct IsdnCardState *cs)); +void release_io_netjet(struct IsdnCardState *cs); + diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c index 31f01355e..4428483b3 100644 --- a/drivers/isdn/hisax/niccy.c +++ b/drivers/isdn/hisax/niccy.c @@ -38,8 +38,12 @@ const char *niccy_revision = "$Revision: 1.12 $"; #define NICCY_PCI 2 /* PCI stuff */ -#define PCI_VENDOR_DR_NEUHAUS 0x1267 -#define PCI_NICCY_ID 0x1016 +#ifndef PCI_VENDOR_ID_SATSAGEM +#define PCI_VENDOR_ID_SATSAGEM 0x1267 +#endif +#ifndef PCI_DEVICE_ID_SATSAGEM_NICCY +#define PCI_DEVICE_ID_SATSAGEM_NICCY 0x1016 +#endif #define PCI_IRQ_CTRL_REG 0x38 #define PCI_IRQ_ENABLE 0x1f00 #define PCI_IRQ_DISABLE 0xff0000 @@ -284,26 +288,26 @@ setup_niccy(struct IsdnCard *card)) return(0); } cs->subtyp = 0; - if ((niccy_dev = pci_find_device(PCI_VENDOR_DR_NEUHAUS, - PCI_NICCY_ID, niccy_dev))) { + if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM, + PCI_DEVICE_ID_SATSAGEM_NICCY, niccy_dev))) { if (pci_enable_device(niccy_dev)) - return (0); + return(0); /* get IRQ */ if (!niccy_dev->irq) { printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n"); return(0); } cs->irq = niccy_dev->irq; - if (!niccy_dev->resource[ 0].start) { + cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0); + if (!cs->hw.niccy.cfg_reg) { printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n"); return(0); } - cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0); - if (!niccy_dev->resource[ 1].start) { + pci_ioaddr = pci_resource_start(niccy_dev, 1); + if (!pci_ioaddr) { printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n"); return(0); } - pci_ioaddr = pci_resource_start(niccy_dev, 1); cs->subtyp = NICCY_PCI; } else { printk(KERN_WARNING "Niccy: No PCI card found\n"); diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c new file mode 100644 index 000000000..2acb1a6de --- /dev/null +++ b/drivers/isdn/hisax/nj_s.c @@ -0,0 +1,257 @@ +// $Id: nj_s.c,v 2.3 2000/06/26 08:59:14 keil Exp $ +// +// This file is (c) under GNU PUBLIC LICENSE +// +#define __NO_VERSION__ +#include <linux/config.h> +#include "hisax.h" +#include "isac.h" +#include "isdnl1.h" +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/ppp_defs.h> +#include "netjet.h" + +const char *NETjet_S_revision = "$Revision: 2.3 $"; + +static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) +{ + return(5); +} + +static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value) +{ +} + +static void +netjet_s_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val, sval; + long flags; + + if (!cs) { + printk(KERN_WARNING "NETjet-S: Spurious interrupt!\n"); + return; + } + if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) & + NETJET_ISACIRQ)) { + val = NETjet_ReadIC(cs, ISAC_ISTA); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "tiger: i1 %x %x", sval, val); + if (val) { + isac_interrupt(cs, val); + NETjet_WriteIC(cs, ISAC_MASK, 0xFF); + NETjet_WriteIC(cs, ISAC_MASK, 0x0); + } + } + save_flags(flags); + cli(); + if ((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) { + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + restore_flags(flags); + return; + } + cs->hw.njet.irqstat0 = sval; + restore_flags(flags); +/* debugl1(cs, "tiger: ist0 %x %x %x %x/%x pulse=%d", + sval, + bytein(cs->hw.njet.base + NETJET_DMACTRL), + bytein(cs->hw.njet.base + NETJET_IRQMASK0), + inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), + inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), + bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); +*/ +/* cs->hw.njet.irqmask0 = ((0x0f & cs->hw.njet.irqstat0) ^ 0x0f) | 0x30; +*/ byteout(cs->hw.njet.base + NETJET_IRQSTAT0, cs->hw.njet.irqstat0); +/* byteout(cs->hw.njet.base + NETJET_IRQMASK0, cs->hw.njet.irqmask0); +*/ if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) + read_tiger(cs); + if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) + write_tiger(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + restore_flags(flags); + +/* if (!testcnt--) { + cs->hw.njet.dmactrl = 0; + byteout(cs->hw.njet.base + NETJET_DMACTRL, + cs->hw.njet.dmactrl); + byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); + } +*/ +} + +static void +reset_netjet_s(struct IsdnCardState *cs) +{ + long flags; + + save_flags(flags); + sti(); + cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + restore_flags(flags); + cs->hw.njet.auxd = 0; + cs->hw.njet.dmactrl = 0; + byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); + byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); + byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); +} + +static int +NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + switch (mt) { + case CARD_RESET: + reset_netjet_s(cs); + return(0); + case CARD_RELEASE: + release_io_netjet(cs); + return(0); + case CARD_INIT: + inittiger(cs); + clear_pending_isac_ints(cs); + initisac(cs); + /* Reenable all IRQ */ + cs->writeisac(cs, ISAC_MASK, 0); + return(0); + case CARD_TEST: + return(0); + } + return(0); +} + +static struct pci_dev *dev_netjet __initdata = NULL; + +__initfunc(int +setup_netjet_s(struct IsdnCard *card)) +{ + int bytecnt; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + long flags; +#if CONFIG_PCI +#endif +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif + strcpy(tmp, NETjet_S_revision); + printk(KERN_INFO "HiSax: Traverse Tech. NETjet-S driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_NETJET_S) + return(0); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + + for ( ;; ) + { + +#if CONFIG_PCI + + if (!pci_present()) { + printk(KERN_ERR "Netjet: no PCI bus present\n"); + return(0); + } + if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) { + if (pci_enable_device(dev_netjet)) + return(0); + cs->irq = dev_netjet->irq; + if (!cs->irq) { + printk(KERN_WARNING "NETjet-S: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.njet.base = pci_resource_start(dev_netjet, 0); + if (!cs->hw.njet.base) { + printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n"); + return(0); + } + } else { + printk(KERN_WARNING "NETjet-S: No PCI card found\n"); + return(0); + } + + cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; + cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; + + save_flags(flags); + sti(); + + cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + + cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + + restore_flags(flags); + + cs->hw.njet.auxd = 0xC0; + cs->hw.njet.dmactrl = 0; + + byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); + byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); + byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); + + switch ( ( ( NETjet_ReadIC( cs, ISAC_RBCH ) >> 5 ) & 3 ) ) + { + case 0 : + break; + + case 3 : + printk( KERN_WARNING "NETjet-S: NETspider-U PCI card found\n" ); + continue; + + default : + printk( KERN_WARNING "NETjet-S: No PCI card found\n" ); + return 0; + } + break; + } +#else + + printk(KERN_WARNING "NETjet-S: NO_PCI_BIOS\n"); + printk(KERN_WARNING "NETjet-S: unable to config NETJET-S PCI\n"); + return (0); + +#endif /* CONFIG_PCI */ + + bytecnt = 256; + + printk(KERN_INFO + "NETjet-S: PCI card configured at 0x%x IRQ %d\n", + cs->hw.njet.base, cs->irq); + if (check_region(cs->hw.njet.base, bytecnt)) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.njet.base, + cs->hw.njet.base + bytecnt); + return (0); + } else { + request_region(cs->hw.njet.base, bytecnt, "netjet-s isdn"); + } + reset_netjet_s(cs); + cs->readisac = &NETjet_ReadIC; + cs->writeisac = &NETjet_WriteIC; + cs->readisacfifo = &NETjet_ReadICfifo; + cs->writeisacfifo = &NETjet_WriteICfifo; + cs->BC_Read_Reg = &dummyrr; + cs->BC_Write_Reg = &dummywr; + cs->BC_Send_Data = &netjet_fill_dma; + cs->cardmsg = &NETjet_S_card_msg; + cs->irq_func = &netjet_s_interrupt; + cs->irq_flags |= SA_SHIRQ; + ISACVersion(cs, "NETjet-S:"); + return (1); +} diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c new file mode 100644 index 000000000..5ad977128 --- /dev/null +++ b/drivers/isdn/hisax/nj_u.c @@ -0,0 +1,260 @@ +/* $Id: nj_u.c,v 2.4 2000/06/26 11:42:16 keil Exp $ + * + * This file is (c) under GNU PUBLIC LICENSE + * + */ +#define __NO_VERSION__ +#include <linux/config.h> +#include "hisax.h" +#include "icc.h" +#include "isdnl1.h" +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/ppp_defs.h> +#include "netjet.h" + +const char *NETjet_U_revision = "$Revision: 2.4 $"; + +static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) +{ + return(5); +} + +static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value) +{ +} + +static void +netjet_u_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val, sval; + long flags; + + if (!cs) { + printk(KERN_WARNING "NETspider-U: Spurious interrupt!\n"); + return; + } + if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) & + NETJET_ISACIRQ)) { + val = NETjet_ReadIC(cs, ICC_ISTA); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "tiger: i1 %x %x", sval, val); + if (val) { + icc_interrupt(cs, val); + NETjet_WriteIC(cs, ICC_MASK, 0xFF); + NETjet_WriteIC(cs, ICC_MASK, 0x0); + } + } + save_flags(flags); + cli(); + if ((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) { + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + restore_flags(flags); + return; + } + cs->hw.njet.irqstat0 = sval; + restore_flags(flags); +/* debugl1(cs, "tiger: ist0 %x %x %x %x/%x pulse=%d", + sval, + bytein(cs->hw.njet.base + NETJET_DMACTRL), + bytein(cs->hw.njet.base + NETJET_IRQMASK0), + inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), + inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), + bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); +*/ +/* cs->hw.njet.irqmask0 = ((0x0f & cs->hw.njet.irqstat0) ^ 0x0f) | 0x30; +*/ byteout(cs->hw.njet.base + NETJET_IRQSTAT0, cs->hw.njet.irqstat0); +/* byteout(cs->hw.njet.base + NETJET_IRQMASK0, cs->hw.njet.irqmask0); +*/ if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) + read_tiger(cs); + if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) + write_tiger(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + restore_flags(flags); + +/* if (!testcnt--) { + cs->hw.njet.dmactrl = 0; + byteout(cs->hw.njet.base + NETJET_DMACTRL, + cs->hw.njet.dmactrl); + byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); + } +*/ +} + +static void +reset_netjet_u(struct IsdnCardState *cs) +{ + long flags; + + save_flags(flags); + sti(); + cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + restore_flags(flags); + cs->hw.njet.auxd = 0xC0; + cs->hw.njet.dmactrl = 0; + byteout(cs->hw.njet.auxa, 0); + byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); + byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); + byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); +} + +static int +NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + switch (mt) { + case CARD_RESET: + reset_netjet_u(cs); + return(0); + case CARD_RELEASE: + release_io_netjet(cs); + return(0); + case CARD_INIT: + inittiger(cs); + clear_pending_icc_ints(cs); + initicc(cs); + /* Reenable all IRQ */ + cs->writeisac(cs, ICC_MASK, 0); + return(0); + case CARD_TEST: + return(0); + } + return(0); +} + +static struct pci_dev *dev_netjet __initdata = NULL; + +__initfunc(int +setup_netjet_u(struct IsdnCard *card)) +{ + int bytecnt; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + long flags; +#if CONFIG_PCI +#endif +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif + strcpy(tmp, NETjet_U_revision); + printk(KERN_INFO "HiSax: Traverse Tech. NETspider-U driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_NETJET_U) + return(0); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + + for ( ;; ) + { + +#if CONFIG_PCI + + if (!pci_present()) { + printk(KERN_ERR "NETspider-U: no PCI bus present\n"); + return(0); + } + if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) { + if (pci_enable_device(dev_netjet)) + return(0); + cs->irq = dev_netjet->irq; + if (!cs->irq) { + printk(KERN_WARNING "NETspider-U: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.njet.base = pci_resource_start(dev_netjet, 0); + if (!cs->hw.njet.base) { + printk(KERN_WARNING "NETspider-U: No IO-Adr for PCI card found\n"); + return(0); + } + } else { + printk(KERN_WARNING "NETspider-U: No PCI card found\n"); + return(0); + } + + cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; + cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; + + save_flags(flags); + sti(); + + cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + + cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ + byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + + restore_flags(flags); + + cs->hw.njet.auxd = 0xC0; + cs->hw.njet.dmactrl = 0; + + byteout(cs->hw.njet.auxa, 0); + byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); + byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); + byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); + + switch ( ( ( NETjet_ReadIC( cs, ICC_RBCH ) >> 5 ) & 3 ) ) + { + case 3 : + break; + + case 0 : + printk( KERN_WARNING "NETspider-U: NETjet-S PCI card found\n" ); + continue; + + default : + printk( KERN_WARNING "NETspider-U: No PCI card found\n" ); + return 0; + } + break; + } +#else + + printk(KERN_WARNING "NETspider-U: NO_PCI_BIOS\n"); + printk(KERN_WARNING "NETspider-U: unable to config NETspider-U PCI\n"); + return (0); + +#endif /* CONFIG_PCI */ + + bytecnt = 256; + + printk(KERN_INFO + "NETspider-U: PCI card configured at 0x%x IRQ %d\n", + cs->hw.njet.base, cs->irq); + if (check_region(cs->hw.njet.base, bytecnt)) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.njet.base, + cs->hw.njet.base + bytecnt); + return (0); + } else { + request_region(cs->hw.njet.base, bytecnt, "netjet-u isdn"); + } + reset_netjet_u(cs); + cs->readisac = &NETjet_ReadIC; + cs->writeisac = &NETjet_WriteIC; + cs->readisacfifo = &NETjet_ReadICfifo; + cs->writeisacfifo = &NETjet_WriteICfifo; + cs->BC_Read_Reg = &dummyrr; + cs->BC_Write_Reg = &dummywr; + cs->BC_Send_Data = &netjet_fill_dma; + cs->cardmsg = &NETjet_U_card_msg; + cs->irq_func = &netjet_u_interrupt; + cs->irq_flags |= SA_SHIRQ; + ICCVersion(cs, "NETspider-U:"); + return (1); +} diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c index 342e4e8fc..3f461883d 100644 --- a/drivers/isdn/hisax/q931.c +++ b/drivers/isdn/hisax/q931.c @@ -65,6 +65,24 @@ struct MessageType { 0xd, "SETUP ACKNOWLEDGE" }, { + 0x24, "HOLD" + }, + { + 0x28, "HOLD ACKNOWLEDGE" + }, + { + 0x30, "HOLD REJECT" + }, + { + 0x31, "RETRIEVE" + }, + { + 0x33, "RETRIEVE ACKNOWLEDGE" + }, + { + 0x37, "RETRIEVE REJECT" + }, + { 0x26, "RESUME" }, { @@ -638,6 +656,65 @@ prbearer(char *dest, u_char * p) return (dp - dest); } + +static +int +prbearer_ni1(char *dest, u_char * p) +{ + char *dp = dest; + u_char len; + + p++; + len = *p++; + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p, 8, 8); + switch (*p++) { + case 0x80: + dp += sprintf(dp, " Speech"); + break; + case 0x88: + dp += sprintf(dp, " Unrestricted digital information"); + break; + case 0x90: + dp += sprintf(dp, " 3.1 kHz audio"); + break; + default: + dp += sprintf(dp, " Unknown information-transfer capability"); + } + *dp++ = '\n'; + dp += sprintf(dp, " octet 4 "); + dp += prbits(dp, *p, 8, 8); + switch (*p++) { + case 0x90: + dp += sprintf(dp, " 64 kbps, circuit mode"); + break; + case 0xc0: + dp += sprintf(dp, " Packet mode"); + break; + default: + dp += sprintf(dp, " Unknown transfer mode"); + } + *dp++ = '\n'; + if (len > 2) { + dp += sprintf(dp, " octet 5 "); + dp += prbits(dp, *p, 8, 8); + switch (*p++) { + case 0x21: + dp += sprintf(dp, " Rate adaption\n"); + dp += sprintf(dp, " octet 5a "); + dp += prbits(dp, *p, 8, 8); + break; + case 0xa2: + dp += sprintf(dp, " u-law"); + break; + default: + dp += sprintf(dp, " Unknown UI layer 1 protocol"); + } + *dp++ = '\n'; + } + return (dp - dest); +} + static int general(char *dest, u_char * p) { @@ -666,6 +743,33 @@ general(char *dest, u_char * p) } static int +general_ni1(char *dest, u_char * p) +{ + char *dp = dest; + char ch = ' '; + int l, octet = 3; + + p++; + l = *p++; + /* Iterate over all octets in the information element */ + while (l--) { + dp += sprintf(dp, " octet %d%c ", octet, ch); + dp += prbits(dp, *p, 8, 8); + *dp++ = '\n'; + + /* last octet in group? */ + if (*p++ & 0x80) { + octet++; + ch = ' '; + } else if (ch == ' ') + ch = 'a'; + else + ch++; + } + return (dp - dest); +} + +static int prcharge(char *dest, u_char * p) { char *dp = dest; @@ -697,6 +801,112 @@ prtext(char *dest, u_char * p) *dp++ = '\n'; return (dp - dest); } + +static int +prfeatureind(char *dest, u_char * p) +{ + char *dp = dest; + + p += 2; /* skip id, len */ + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p, 8, 8); + *dp++ = '\n'; + if (!(*p++ & 80)) { + dp += sprintf(dp, " octet 4 "); + dp += prbits(dp, *p++, 8, 8); + *dp++ = '\n'; + } + dp += sprintf(dp, " Status: "); + switch (*p) { + case 0: + dp += sprintf(dp, "Idle"); + break; + case 1: + dp += sprintf(dp, "Active"); + break; + case 2: + dp += sprintf(dp, "Prompt"); + break; + case 3: + dp += sprintf(dp, "Pending"); + break; + default: + dp += sprintf(dp, "(Reserved)"); + break; + } + *dp++ = '\n'; + return (dp - dest); +} + +static +struct DTag { /* Display tags */ + u_char nr; + char *descr; +} dtaglist[] = { + { 0x82, "Continuation" }, + { 0x83, "Called address" }, + { 0x84, "Cause" }, + { 0x85, "Progress indicator" }, + { 0x86, "Notification indicator" }, + { 0x87, "Prompt" }, + { 0x88, "Accumlated digits" }, + { 0x89, "Status" }, + { 0x8a, "Inband" }, + { 0x8b, "Calling address" }, + { 0x8c, "Reason" }, + { 0x8d, "Calling party name" }, + { 0x8e, "Called party name" }, + { 0x8f, "Orignal called name" }, + { 0x90, "Redirecting name" }, + { 0x91, "Connected name" }, + { 0x92, "Originating restrictions" }, + { 0x93, "Date & time of day" }, + { 0x94, "Call Appearance ID" }, + { 0x95, "Feature address" }, + { 0x96, "Redirection name" }, + { 0x9e, "Text" }, +}; +#define DTAGSIZE sizeof(dtaglist)/sizeof(struct DTag) + +static int +disptext_ni1(char *dest, u_char * p) +{ + char *dp = dest; + int l, tag, len, i; + + p++; + l = *p++ - 1; + if (*p++ != 0x80) { + dp += sprintf(dp, " Unknown display type\n"); + return (dp - dest); + } + /* Iterate over all tag,length,text fields */ + while (l > 0) { + tag = *p++; + len = *p++; + l -= len + 2; + /* Don't space or skip */ + if ((tag == 0x80) || (tag == 0x81)) p++; + else { + for (i = 0; i < DTAGSIZE; i++) + if (tag == dtaglist[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != DTAGSIZE) { + dp += sprintf(dp, " %s: ", dtaglist[i].descr); + while (len--) + *dp++ = *p++; + } else { + dp += sprintf(dp, " (unknown display tag %2x): ", tag); + while (len--) + *dp++ = *p++; + } + dp += sprintf(dp, "\n"); + } + } + return (dp - dest); +} static int display(char *dest, u_char * p) { @@ -867,6 +1077,49 @@ struct InformationElement { #define IESIZE sizeof(ielist)/sizeof(struct InformationElement) +static +struct InformationElement ielist_ni1[] = { + { 0x04, "Bearer Capability", prbearer_ni1 }, + { 0x08, "Cause", prcause }, + { 0x14, "Call State", general_ni1 }, + { 0x18, "Channel Identification", prchident }, + { 0x1e, "Progress Indicator", general_ni1 }, + { 0x27, "Notification Indicator", general_ni1 }, + { 0x2c, "Keypad Facility", prtext }, + { 0x32, "Information Request", general_ni1 }, + { 0x34, "Signal", general_ni1 }, + { 0x38, "Feature Activation", general_ni1 }, + { 0x39, "Feature Indication", prfeatureind }, + { 0x3a, "Service Profile Identification (SPID)", prtext }, + { 0x3b, "Endpoint Identifier", general_ni1 }, + { 0x6c, "Calling Party Number", prcalling }, + { 0x6d, "Calling Party Subaddress", general_ni1 }, + { 0x70, "Called Party Number", prcalled }, + { 0x71, "Called Party Subaddress", general_ni1 }, + { 0x74, "Redirecting Number", general_ni1 }, + { 0x78, "Transit Network Selection", general_ni1 }, + { 0x7c, "Low Layer Compatibility", general_ni1 }, + { 0x7d, "High Layer Compatibility", general_ni1 }, +}; + + +#define IESIZE_NI1 sizeof(ielist_ni1)/sizeof(struct InformationElement) + +static +struct InformationElement ielist_ni1_cs5[] = { + { 0x1d, "Operator system access", general_ni1 }, + { 0x2a, "Display text", disptext_ni1 }, +}; + +#define IESIZE_NI1_CS5 sizeof(ielist_ni1_cs5)/sizeof(struct InformationElement) + +static +struct InformationElement ielist_ni1_cs6[] = { + { 0x7b, "Call appearance", general_ni1 }, +}; + +#define IESIZE_NI1_CS6 sizeof(ielist_ni1_cs6)/sizeof(struct InformationElement) + static struct InformationElement we_0[] = { {WE0_cause, "Cause", prcause_1tr6}, @@ -1107,7 +1360,93 @@ dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir) } buf += buf[1] + 2; } - } else if (buf[0] == 8) { /* EURO */ + } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_NI1)) { /* NI-1 */ + /* locate message type */ + buf++; + cr_l = *buf++; + if (cr_l) + cr = *buf++; + else + cr = 0; + mt = *buf++; + for (i = 0; i < MTSIZE; i++) + if (mtlist[i].nr == mt) + break; + + /* display message type if it exists */ + if (i == MTSIZE) + dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mt); + else + dp += sprintf(dp, "callref %d %s size %d message type %s\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mtlist[i].descr); + + /* display each information element */ + while (buf < bend) { + /* Is it a single octet information element? */ + if (*buf & 0x80) { + switch ((*buf >> 4) & 7) { + case 1: + dp += sprintf(dp, " Shift %x\n", *buf & 0xf); + cs_old = cset; + cset = *buf & 7; + cs_fest = *buf & 8; + break; + default: + dp += sprintf(dp, " Unknown single-octet IE %x\n", *buf); + break; + } + buf++; + continue; + } + /* No, locate it in the table */ + if (cset == 0) { + for (i = 0; i < IESIZE; i++) + if (*buf == ielist_ni1[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != IESIZE) { + dp += sprintf(dp, " %s\n", ielist_ni1[i].descr); + dp += ielist_ni1[i].f(dp, buf); + } else + dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); + } else if (cset == 5) { + for (i = 0; i < IESIZE_NI1_CS5; i++) + if (*buf == ielist_ni1_cs5[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != IESIZE_NI1_CS5) { + dp += sprintf(dp, " %s\n", ielist_ni1_cs5[i].descr); + dp += ielist_ni1_cs5[i].f(dp, buf); + } else + dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); + } else if (cset == 6) { + for (i = 0; i < IESIZE_NI1_CS6; i++) + if (*buf == ielist_ni1_cs6[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != IESIZE_NI1_CS6) { + dp += sprintf(dp, " %s\n", ielist_ni1_cs6[i].descr); + dp += ielist_ni1_cs6[i].f(dp, buf); + } else + dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); + } else + dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); + + /* Skip to next element */ + if (cs_fest == 8) { + cset = cs_old; + cs_old = 0; + cs_fest = 0; + } + buf += buf[1] + 2; + } + } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_EURO)) { /* EURO */ /* locate message type */ buf++; cr_l = *buf++; diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c index b463b154a..192c496b0 100644 --- a/drivers/isdn/hisax/sedlbauer.c +++ b/drivers/isdn/hisax/sedlbauer.c @@ -39,8 +39,6 @@ * For example: hisaxctrl <DriverID> 9 ISAR.BIN */ -#define SEDLBAUER_PCI 1 - #define __NO_VERSION__ #include <linux/config.h> #include "hisax.h" @@ -53,19 +51,23 @@ extern const char *CardType[]; -const char *Sedlbauer_revision = "$Revision: 1.20 $"; +const char *Sedlbauer_revision = "$Revision: 1.23 $"; const char *Sedlbauer_Types[] = {"None", "speed card/win", "speed star", "speed fax+", "speed win II / ISDN PC/104", "speed star II", "speed pci", - "speed fax+ pci"}; + "speed fax+ pyramid", "speed fax+ pci"}; -#ifdef SEDLBAUER_PCI -#define PCI_VENDOR_SEDLBAUER 0xe159 -#define PCI_SPEEDPCI_ID 0x02 -#define PCI_SUBVENDOR_SEDLBAUER 0x51 -#define PCI_SUB_ID_SPEEDFAXP 0x01 +#ifndef PCI_VENDOR_ID_TIGERJET +#define PCI_VENDOR_ID_TIGERJET 0xe159 +#endif +#ifndef PCI_DEVICE_ID_TIGERJET_100 +#define PCI_DEVICE_ID_TIGERJET_100 0x0002 #endif +#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51 +#define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53 +#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54 +#define PCI_SUB_ID_SEDLBAUER 0x01 #define SEDL_SPEED_CARD_WIN 1 #define SEDL_SPEED_STAR 2 @@ -73,7 +75,8 @@ const char *Sedlbauer_Types[] = #define SEDL_SPEED_WIN2_PC104 4 #define SEDL_SPEED_STAR2 5 #define SEDL_SPEED_PCI 6 -#define SEDL_SPEEDFAX_PCI 7 +#define SEDL_SPEEDFAX_PYRAMID 7 +#define SEDL_SPEEDFAX_PCI 8 #define SEDL_CHIP_TEST 0 #define SEDL_CHIP_ISAC_HSCX 1 @@ -285,10 +288,10 @@ sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs) } if ((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) && (*cs->busy_flag == 1)) { - /* The card tends to generate interrupts while being removed - causing us to just crash the kernel. bad. */ - printk(KERN_WARNING "Sedlbauer: card not available!\n"); - return; + /* The card tends to generate interrupts while being removed + causing us to just crash the kernel. bad. */ + printk(KERN_WARNING "Sedlbauer: card not available!\n"); + return; } val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40); @@ -360,7 +363,8 @@ Start_IPAC: goto Start_IPAC; } if (!icnt) - printk(KERN_WARNING "Sedlbauer IRQ LOOP\n"); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "Sedlbauer IRQ LOOP"); writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xFF); writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xC0); } @@ -398,7 +402,8 @@ sedlbauer_interrupt_isar(int intno, void *dev_id, struct pt_regs *regs) goto Start_ISAC; } if (!cnt) - printk(KERN_WARNING "Sedlbauer IRQ LOOP\n"); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "Sedlbauer IRQ LOOP"); writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, 0); writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF); @@ -508,7 +513,7 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg) case CARD_TEST: return(0); case MDL_INFO_CONN: - if (cs->subtyp != SEDL_SPEEDFAX_PCI) + if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID) return(0); if ((long) arg) cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED2; @@ -517,7 +522,7 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg) byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); break; case MDL_INFO_REL: - if (cs->subtyp != SEDL_SPEEDFAX_PCI) + if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID) return(0); if ((long) arg) cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED2; @@ -529,9 +534,7 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -#ifdef SEDLBAUER_PCI static struct pci_dev *dev_sedl __initdata = NULL; -#endif __initfunc(int setup_sedlbauer(struct IsdnCard *card)) @@ -569,16 +572,15 @@ setup_sedlbauer(struct IsdnCard *card)) } } else { /* Probe for Sedlbauer speed pci */ -#if SEDLBAUER_PCI #if CONFIG_PCI if (!pci_present()) { printk(KERN_ERR "Sedlbauer: no PCI bus present\n"); return(0); } - if ((dev_sedl = pci_find_device(PCI_VENDOR_SEDLBAUER, - PCI_SPEEDPCI_ID, dev_sedl))) { + if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET, + PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) { if (pci_enable_device(dev_sedl)) - return (0); + return(0); cs->irq = dev_sedl->irq; if (!cs->irq) { printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n"); @@ -597,13 +599,23 @@ setup_sedlbauer(struct IsdnCard *card)) sub_vendor_id, sub_id); printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n", cs->hw.sedl.cfg_reg); - if ((sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER) && - (sub_id == PCI_SUB_ID_SPEEDFAXP)) { + if (sub_id != PCI_SUB_ID_SEDLBAUER) { + printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id); + return(0); + } + if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) { + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; + cs->subtyp = SEDL_SPEEDFAX_PYRAMID; + } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) { cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; cs->subtyp = SEDL_SPEEDFAX_PCI; - } else { + } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) { cs->hw.sedl.chip = SEDL_CHIP_IPAC; cs->subtyp = SEDL_SPEED_PCI; + } else { + printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n", + sub_vendor_id); + return(0); } bytecnt = 256; cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON; @@ -623,7 +635,6 @@ setup_sedlbauer(struct IsdnCard *card)) printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n"); return (0); #endif /* CONFIG_PCI */ -#endif /* SEDLBAUER_PCI */ } /* In case of the sedlbauer pcmcia card, this region is in use, @@ -683,7 +694,6 @@ setup_sedlbauer(struct IsdnCard *card)) if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) { - /* IPAC */ if (cs->hw.sedl.bus == SEDL_BUS_PCI) { cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_ADR; cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC; diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c index 359e9932e..2a84aa2d2 100644 --- a/drivers/isdn/hisax/tei.c +++ b/drivers/isdn/hisax/tei.c @@ -154,7 +154,7 @@ tei_id_assign(struct FsmInst *fi, int event, void *arg) if (st->ma.debug) st->ma.tei_m.printdebug(&st->ma.tei_m, "identity assign ri %d tei %d", ri, tei); - if ((ost = findtei(st, tei))) { /* same tei is in use */ + if ((ost = findtei(st, tei))) { /* same tei is in use */ if (ri != ost->ma.ri) { st->ma.tei_m.printdebug(&st->ma.tei_m, "possible duplicate assignment tei %d", tei); @@ -181,10 +181,12 @@ tei_id_test_dup(struct FsmInst *fi, int event, void *arg) if (st->ma.debug) st->ma.tei_m.printdebug(&st->ma.tei_m, "foreign identity assign ri %d tei %d", ri, tei); - if ((ost = findtei(st, tei))) { /* same tei is in use */ - st->ma.tei_m.printdebug(&st->ma.tei_m, - "possible duplicate assignment tei %d", tei); - FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL); + if ((ost = findtei(st, tei))) { /* same tei is in use */ + if (ri != ost->ma.ri) { /* and it wasn't our request */ + st->ma.tei_m.printdebug(&st->ma.tei_m, + "possible duplicate assignment tei %d", tei); + FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL); + } } } diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c index 856b73fd9..eb17ce331 100644 --- a/drivers/isdn/hisax/telespci.c +++ b/drivers/isdn/hisax/telespci.c @@ -27,6 +27,12 @@ const char *telespci_revision = "$Revision: 2.13 $"; #define ZORAN_PO_GREG1 0x00010000 #define ZORAN_PO_DMASK 0xFF +#ifndef PCI_VENDOR_ID_ZORAN +#define PCI_VENDOR_ID_ZORAN 0x11DE +#endif +#ifndef PCI_DEVICE_ID_ZORAN_36120 +#define PCI_DEVICE_ID_ZORAN_36120 0x6120 +#endif #define WRITE_ADDR_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG0) #define READ_DATA_ISAC (ZORAN_PO_GID0 | ZORAN_PO_GREG1) #define WRITE_DATA_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG1) @@ -282,6 +288,9 @@ setup_telespci(struct IsdnCard *card)) struct IsdnCardState *cs = card->cs; char tmp[64]; +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif strcpy(tmp, telespci_revision); printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_TELESPCI) @@ -291,18 +300,18 @@ setup_telespci(struct IsdnCard *card)) printk(KERN_ERR "TelesPCI: no PCI bus present\n"); return(0); } - if ((dev_tel = pci_find_device (0x11DE, 0x6120, dev_tel))) { + if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) { if (pci_enable_device(dev_tel)) - return (0); + return(0); cs->irq = dev_tel->irq; if (!cs->irq) { printk(KERN_WARNING "Teles: No IRQ for PCI card found\n"); return(0); } - cs->hw.teles0.membase = (u_long) ioremap(dev_tel->resource[ 0].start, + cs->hw.teles0.membase = (u_long) ioremap(pci_resource_start(dev_tel, 0), PAGE_SIZE); printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n", - dev_tel->resource[ 0].start, dev_tel->irq); + pci_resource_start(dev_tel, 0), dev_tel->irq); } else { printk(KERN_WARNING "TelesPCI: No PCI card found\n"); return(0); diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index cea2f61df..eca66942e 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -17,13 +17,18 @@ #include <linux/interrupt.h> #include <linux/pci.h> -#define PCI_VEND_ASUSCOM 0x675 -#define PCI_DEV_ASUSCOMPCI1 0x1702 +#ifndef PCI_VENDOR_ID_ASUSCOM +#define PCI_VENDOR_ID_ASUSCOM 0x675 +#endif +#ifndef PCI_DEVICE_ID_ASUSCOM_TA1 +#define PCI_DEVICE_ID_ASUSCOM_TA1 0x1702 +#endif #ifndef PCI_VENDOR_ID_WINBOND2 #define PCI_VENDOR_ID_WINBOND2 0x1050 #endif -#define PCI_DEVICE_W6692 0x6692 - +#ifndef PCI_DEVICE_ID_WINBOND_6692 +#define PCI_DEVICE_ID_WINBOND_6692 0x6692 +#endif /* table entry in the PCI devices list */ typedef struct { int vendor_id; @@ -34,14 +39,14 @@ typedef struct { static const PCI_ENTRY id_list[] = { - {PCI_VEND_ASUSCOM, PCI_DEV_ASUSCOMPCI1, "AsusCom", "TA XXX"}, - {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_W6692, "Winbond", "W6692"}, + {PCI_VENDOR_ID_ASUSCOM, PCI_DEVICE_ID_ASUSCOM_TA1, "AsusCom", "TA XXX"}, + {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND_6692, "Winbond", "W6692"}, {0, 0, NULL, NULL} }; extern const char *CardType[]; -const char *w6692_revision = "$Revision: 1.4 $"; +const char *w6692_revision = "$Revision: 1.7 $"; #define DBUSY_TIMER_VALUE 80 @@ -239,7 +244,7 @@ W6692B_empty_fifo(struct BCState *bcs, int count) if (bcs->hw.w6692.rcvidx + count > HSCX_BUFMAX) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692B_empty_fifo: incoming packet too large"); - cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); bcs->hw.w6692.rcvidx = 0; return; } @@ -247,14 +252,14 @@ W6692B_empty_fifo(struct BCState *bcs, int count) bcs->hw.w6692.rcvidx += count; save_flags(flags); cli(); - READW6692BFIFO(cs, bcs->hw.w6692.bchan, ptr, count); - cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + READW6692BFIFO(cs, bcs->channel, ptr, count); + cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); restore_flags(flags); if (cs->debug & L1_DEB_HSCX_FIFO) { char *t = bcs->blog; t += sprintf(t, "W6692B_empty_fifo %c cnt %d", - bcs->hw.w6692.bchan ? 'B' : 'A', count); + bcs->channel + '1', count); QuickHex(t, ptr, count); debugl1(cs, bcs->blog); } @@ -290,14 +295,14 @@ W6692B_fill_fifo(struct BCState *bcs) skb_pull(bcs->tx_skb, count); bcs->tx_cnt -= count; bcs->hw.w6692.count += count; - WRITEW6692BFIFO(cs, bcs->hw.w6692.bchan, ptr, count); - cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME)); + WRITEW6692BFIFO(cs, bcs->channel, ptr, count); + cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME)); restore_flags(flags); if (cs->debug & L1_DEB_HSCX_FIFO) { char *t = bcs->blog; t += sprintf(t, "W6692B_fill_fifo %c cnt %d", - bcs->hw.w6692.bchan ? 'B' : 'A', count); + bcs->channel + '1', count); QuickHex(t, ptr, count); debugl1(cs, bcs->blog); } @@ -308,13 +313,11 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan) { u_char val; u_char r; - struct BCState *bcs = cs->bcs; + struct BCState *bcs; struct sk_buff *skb; int count; - if (bcs->channel != bchan) - bcs++; /* hardware bchan must match ! */ - + bcs = (cs->bcs->channel == bchan) ? cs->bcs : (cs->bcs+1); val = cs->BC_Read_Reg(cs, bchan, W_B_EXIR); debugl1(cs, "W6692B chan %d B_EXIR 0x%02X", bchan, val); @@ -401,7 +404,7 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan) bcs->tx_cnt += bcs->hw.w6692.count; bcs->hw.w6692.count = 0; } - cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); + cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692 B EXIR %x Lost TX", val); } @@ -715,18 +718,16 @@ dbusy_timer_handler(struct IsdnCardState *cs) } static void -W6692Bmode(struct BCState *bcs, int mode, int bc) +W6692Bmode(struct BCState *bcs, int mode, int bchan) { struct IsdnCardState *cs = bcs->cs; - int bchan = bc; - - bcs->hw.w6692.bchan = bc; if (cs->debug & L1_DEB_HSCX) debugl1(cs, "w6692 %c mode %d ichan %d", - '1' + bchan, mode, bc); + '1' + bchan, mode, bchan); bcs->mode = mode; - bcs->channel = bc; + bcs->channel = bchan; + bcs->hw.w6692.bchan = bchan; switch (mode) { case (L1_MODE_NULL): @@ -895,8 +896,6 @@ HISAX_INITFUNC(void initW6692(struct IsdnCardState *cs, int part)) cs->bcs[1].BC_SetStack = setstack_w6692; cs->bcs[0].BC_Close = close_w6692state; cs->bcs[1].BC_Close = close_w6692state; - cs->bcs[0].hw.w6692.bchan = 0; - cs->bcs[1].hw.w6692.bchan = 1; W6692Bmode(cs->bcs, 0, 0); W6692Bmode(cs->bcs + 1, 0, 0); } @@ -979,6 +978,9 @@ __initfunc(int setup_w6692(struct IsdnCard *card)) u_char pci_irq = 0; u_int pci_ioaddr = 0; +#ifdef __BIG_ENDIAN +#error "not running on big endian machines now" +#endif strcpy(tmp, w6692_revision); printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_W6692) diff --git a/drivers/isdn/hysdn/Makefile b/drivers/isdn/hysdn/Makefile index 626a6deaa..5613784b7 100644 --- a/drivers/isdn/hysdn/Makefile +++ b/drivers/isdn/hysdn/Makefile @@ -16,6 +16,9 @@ ifeq ($(CONFIG_PROC_FS),y) M_OBJS += hysdn.o O_TARGET += hysdn.o O_OBJS += hysdn_procconf.o hysdn_proclog.o boardergo.o hysdn_boot.o hysdn_sched.o hysdn_net.o + ifeq ($(CONFIG_HYSDN_CAPI),y) + O_OBJS += hycapi.o + endif OX_OBJS += hysdn_init.o endif endif diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c index 578e4a14d..54849eab1 100644 --- a/drivers/isdn/hysdn/boardergo.c +++ b/drivers/isdn/hysdn/boardergo.c @@ -1,4 +1,4 @@ -/* $Id: boardergo.c,v 1.1 2000/02/10 19:45:18 werner Exp $ +/* $Id: boardergo.c,v 1.3 2000/05/17 11:41:30 ualbrecht Exp $ * Linux driver for HYSDN cards, specific routines for ergo type boards. * @@ -25,6 +25,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: boardergo.c,v $ + * Revision 1.3 2000/05/17 11:41:30 ualbrecht + * CAPI 2.0 support added + * + * Revision 1.2 2000/04/23 14:18:36 kai + * merge changes from main tree + * * Revision 1.1 2000/02/10 19:45:18 werner * * Initial release @@ -33,6 +39,7 @@ */ #define __NO_VERSION__ +#include <linux/config.h> #include <linux/module.h> #include <linux/version.h> #include <asm/io.h> @@ -153,6 +160,9 @@ ergo_stopcard(hysdn_card * card) uchar val; hysdn_net_release(card); /* first release the net device if existing */ +#ifdef CONFIG_HYSDN_CAPI + hycapi_capi_stop(card); +#endif /* CONFIG_HYSDN_CAPI */ save_flags(flags); cli(); val = bytein(card->iobase + PCI9050_INTR_REG); /* get actual value */ @@ -238,7 +248,7 @@ ergo_writebootimg(struct HYSDN_CARD *card, uchar * buf, ulong offs) uchar *dst; tErgDpram *dpram; int cnt = (BOOT_IMG_SIZE >> 2); /* number of words to move and swap (byte order!) */ - + if (card->debug_flags & LOG_POF_CARD) hysdn_addlog(card, "ERGO: write bootldr offs=0x%lx ", offs); @@ -334,7 +344,6 @@ ergo_writebootseq(struct HYSDN_CARD *card, uchar * buf, int len) } /* while (nr_write) */ } /* while (len) */ - return (0); } /* ergo_writebootseq */ @@ -354,7 +363,6 @@ ergo_waitpofready(struct HYSDN_CARD *card) if (card->debug_flags & LOG_POF_CARD) hysdn_addlog(card, "ERGO: waiting for pof ready"); - while (timecnt--) { /* wait until timeout */ @@ -375,7 +383,6 @@ ergo_waitpofready(struct HYSDN_CARD *card) if (card->debug_flags & LOG_POF_RECORD) hysdn_addlog(card, "ERGO: pof boot success"); - save_flags(flags); cli(); @@ -396,6 +403,11 @@ ergo_waitpofready(struct HYSDN_CARD *card) card->state = CARD_STATE_BOOTERR; return (i); } +#ifdef CONFIG_HYSDN_CAPI + if((i = hycapi_capi_create(card))) { + printk(KERN_WARNING "HYSDN: failed to create capi-interface.\n"); + } +#endif /* CONFIG_HYSDN_CAPI */ return (0); /* success */ } /* data has arrived */ sti(); diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c new file mode 100644 index 000000000..aabb28b8d --- /dev/null +++ b/drivers/isdn/hysdn/hycapi.c @@ -0,0 +1,859 @@ +/* $Id: hycapi.c,v 1.6 2000/07/25 08:07:42 ualbrecht Exp $ + * + * Linux driver for HYSDN cards, CAPI2.0-Interface. + * written by Ulrich Albrecht (u.albrecht@hypercope.de) for Hypercope GmbH + * + * Copyright 2000 by Hypercope GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Log: hycapi.c,v $ + * Revision 1.6 2000/07/25 08:07:42 ualbrecht + * Fixed stupid re-registering bug resulting in system-freeze + * + * Revision 1.5 2000/06/18 16:08:18 keil + * 2.4 PCI changes and some cosmetics + * + * Revision 1.4 2000/06/13 09:13:06 ualbrecht + * Changed internal application handling: Registration is now deferred + * until a CAPI-message is actually sent to the controller (no good + * wasting memory on the card if it's never used anyways). + * Module will now unload more gracefully. + * + * Revision 1.2 2000/05/22 10:31:22 ualbrecht + * Parameter-checking for app-registration fixed + * + * Revision 1.1 2000/05/17 11:34:30 ualbrecht + * Initial release + * + * + */ + +#define __NO_VERSION__ +#include <linux/module.h> +#include <linux/version.h> +#include <linux/signal.h> +#include <linux/kernel.h> +#include <linux/skbuff.h> + + +#define VER_DRIVER 0 +#define VER_CARDTYPE 1 +#define VER_HWID 2 +#define VER_SERIAL 3 +#define VER_OPTION 4 +#define VER_PROTO 5 +#define VER_PROFILE 6 +#define VER_CAPI 7 + +#include "hysdn_defs.h" +#include <linux/kernelcapi.h> + +static char hycapi_revision[]="$Revision: 1.6 $"; + +typedef struct _hycapi_appl { + unsigned int ctrl_mask; + capi_register_params rp; + struct sk_buff *listen_req[CAPI_MAXCONTR]; +} hycapi_appl; + +static hycapi_appl hycapi_applications[CAPI_MAXAPPL]; + +static inline int _hycapi_appCheck(int app_id, int ctrl_no) +{ + if((ctrl_no <= 0) || (ctrl_no > CAPI_MAXCONTR) || (app_id <= 0) || + (app_id > CAPI_MAXAPPL)) + { + printk(KERN_ERR "HYCAPI: Invalid request app_id %d for controller %d", app_id, ctrl_no); + return -1; + } + return ((hycapi_applications[app_id-1].ctrl_mask & (1 << (ctrl_no-1))) != 0); +} + +struct capi_driver_interface *hy_di = NULL; + +/****************************** +Kernel-Capi callback reset_ctr +******************************/ + +void +hycapi_reset_ctr(struct capi_ctr *ctrl) +{ +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "HYCAPI hycapi_reset_ctr\n"); +#endif + ctrl->reseted(ctrl); +} + +/****************************** +Kernel-Capi callback remove_ctr +******************************/ + +void +hycapi_remove_ctr(struct capi_ctr *ctrl) +{ + int i; + hycapictrl_info *cinfo = NULL; + hysdn_card *card = NULL; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "HYCAPI hycapi_remove_ctr\n"); +#endif + if(!hy_di) { + printk(KERN_ERR "No capi_driver_interface set!"); + return; + } + cinfo = (hycapictrl_info *)(ctrl->driverdata); + if(!cinfo) { + printk(KERN_ERR "No hycapictrl_info set!"); + return; + } + card = cinfo->card; + ctrl->suspend_output(ctrl); + for(i=0; i<CAPI_MAXAPPL;i++) { + if(hycapi_applications[i].listen_req[ctrl->cnr-1]) { + kfree_skb(hycapi_applications[i].listen_req[ctrl->cnr-1]); + hycapi_applications[i].listen_req[ctrl->cnr-1] = NULL; + } + } + hy_di->detach_ctr(ctrl); + ctrl->driverdata = 0; + kfree(card->hyctrlinfo); + + + card->hyctrlinfo = NULL; +} + +/*********************************************************** + +Queue a CAPI-message to the controller. + +***********************************************************/ + +static void +hycapi_sendmsg_internal(struct capi_ctr *ctrl, struct sk_buff *skb) +{ + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + + spin_lock_irq(&cinfo->lock); +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_send_message\n"); +#endif + cinfo->skbs[cinfo->in_idx++] = skb; /* add to buffer list */ + if (cinfo->in_idx >= HYSDN_MAX_CAPI_SKB) + cinfo->in_idx = 0; /* wrap around */ + cinfo->sk_count++; /* adjust counter */ + if (cinfo->sk_count >= HYSDN_MAX_CAPI_SKB) { + /* inform upper layers we're full */ + printk(KERN_ERR "HYSDN Card%d: CAPI-buffer overrun!\n", + card->myid); + ctrl->suspend_output(ctrl); + } + cinfo->tx_skb = skb; + spin_unlock_irq(&cinfo->lock); + queue_task(&card->irq_queue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +/*********************************************************** +hycapi_register_internal + +Send down the CAPI_REGISTER-Command to the controller. +This functions will also be used if the adapter has been rebooted to +re-register any applications in the private list. + +************************************************************/ + +static void +hycapi_register_internal(struct capi_ctr *ctrl, __u16 appl, + capi_register_params *rp) +{ + char ExtFeatureDefaults[] = "49 /0/0/0/0,*/1,*/2,*/3,*/4,*/5,*/6,*/7,*/8,*/9,*"; + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + struct sk_buff *skb; + __u16 len; + __u8 _command = 0xa0, _subcommand = 0x80; + __u16 MessageNumber = 0x0000; + __u16 MessageBufferSize = 0; + int slen = strlen(ExtFeatureDefaults); +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_register_appl\n"); +#endif + MessageBufferSize = rp->level3cnt * rp->datablkcnt * rp->datablklen; + + len = CAPI_MSG_BASELEN + 8 + slen + 1; + if (!(skb = alloc_skb(len, GFP_ATOMIC))) { + printk(KERN_ERR "HYSDN card%d: memory squeeze in hycapi_register_appl\n", + card->myid); + return; + } + memcpy(skb_put(skb,sizeof(__u16)), &len, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &appl, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u8)), &_command, sizeof(_command)); + memcpy(skb_put(skb,sizeof(__u8)), &_subcommand, sizeof(_subcommand)); + memcpy(skb_put(skb,sizeof(__u16)), &MessageNumber, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &MessageBufferSize, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &(rp->level3cnt), sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &(rp->datablkcnt), sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &(rp->datablklen), sizeof(__u16)); + memcpy(skb_put(skb,slen), ExtFeatureDefaults, slen); + hycapi_applications[appl-1].ctrl_mask |= (1 << (ctrl->cnr-1)); + hycapi_send_message(ctrl, skb); +} + +/************************************************************ +hycapi_restart_internal + +After an adapter has been rebootet, re-register all applications and +send a LISTEN_REQ (if there has been such a thing ) + +*************************************************************/ + +static void hycapi_restart_internal(struct capi_ctr *ctrl) +{ + int i; + struct sk_buff *skb; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_WARNING "HYSDN: hycapi_restart_internal"); +#endif + for(i=0; i<CAPI_MAXAPPL; i++) { + if(_hycapi_appCheck(i+1, ctrl->cnr) == 1) { + hycapi_register_internal(ctrl, i+1, + &hycapi_applications[i].rp); + if(hycapi_applications[i].listen_req[ctrl->cnr-1]) { + skb = skb_copy(hycapi_applications[i].listen_req[ctrl->cnr-1], GFP_ATOMIC); + hycapi_sendmsg_internal(ctrl, skb); + } + } + } +} + +/************************************************************* +Register an application. +Error-checking is done for CAPI-compliance. + +The application is recorded in the internal list. +*************************************************************/ + +void +hycapi_register_appl(struct capi_ctr *ctrl, __u16 appl, + capi_register_params *rp) +{ + int MaxLogicalConnections = 0, MaxBDataBlocks = 0, MaxBDataLen = 0; + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + int chk = _hycapi_appCheck(appl, ctrl->cnr); + if(chk < 0) { + return; + } + if(chk == 1) { + printk(KERN_INFO "HYSDN: apl %d allready registered\n", appl); + return; + } + MaxBDataBlocks = rp->datablkcnt > CAPI_MAXDATAWINDOW ? CAPI_MAXDATAWINDOW : rp->datablkcnt; + rp->datablkcnt = MaxBDataBlocks; + MaxBDataLen = rp->datablklen < 1024 ? 1024 : rp->datablklen ; + rp->datablklen = MaxBDataLen; + + MaxLogicalConnections = rp->level3cnt; + if (MaxLogicalConnections < 0) { + MaxLogicalConnections = card->bchans * -MaxLogicalConnections; + } + if (MaxLogicalConnections == 0) { + MaxLogicalConnections = card->bchans; + } + + rp->level3cnt = MaxLogicalConnections; + memcpy(&hycapi_applications[appl-1].rp, + rp, sizeof(capi_register_params)); + +/* MOD_INC_USE_COUNT; */ + ctrl->appl_registered(ctrl, appl); +} + +/********************************************************************* + +hycapi_release_internal + +Send down a CAPI_RELEASE to the controller. +*********************************************************************/ + +static void hycapi_release_internal(struct capi_ctr *ctrl, __u16 appl) +{ + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + struct sk_buff *skb; + __u16 len; + __u8 _command = 0xa1, _subcommand = 0x80; + __u16 MessageNumber = 0x0000; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_release_appl\n"); +#endif + len = CAPI_MSG_BASELEN; + if (!(skb = alloc_skb(len, GFP_ATOMIC))) { + printk(KERN_ERR "HYSDN card%d: memory squeeze in hycapi_register_appl\n", + card->myid); + return; + } + memcpy(skb_put(skb,sizeof(__u16)), &len, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u16)), &appl, sizeof(__u16)); + memcpy(skb_put(skb,sizeof(__u8)), &_command, sizeof(_command)); + memcpy(skb_put(skb,sizeof(__u8)), &_subcommand, sizeof(_subcommand)); + memcpy(skb_put(skb,sizeof(__u16)), &MessageNumber, sizeof(__u16)); + hycapi_send_message(ctrl, skb); + hycapi_applications[appl-1].ctrl_mask &= ~(1 << (ctrl->cnr-1)); +} + +/****************************************************************** +hycapi_release_appl + +Release the application from the internal list an remove it's +registration at controller-level +******************************************************************/ + +void +hycapi_release_appl(struct capi_ctr *ctrl, __u16 appl) +{ + int chk; + + chk = _hycapi_appCheck(appl, ctrl->cnr); + if(chk<0) { + printk(KERN_ERR "HYCAPI: Releasing invalid appl %d on controller %d\n", appl, ctrl->cnr); + return; + } + if(hycapi_applications[appl-1].listen_req[ctrl->cnr-1]) { + kfree_skb(hycapi_applications[appl-1].listen_req[ctrl->cnr-1]); + hycapi_applications[appl-1].listen_req[ctrl->cnr-1] = NULL; + } + if(chk == 1) + { + hycapi_release_internal(ctrl, appl); + } + ctrl->appl_released(ctrl, appl); +/* MOD_DEC_USE_COUNT; */ +} + + +/************************************************************** +Kill a single controller. +**************************************************************/ + +int hycapi_capi_release(hysdn_card *card) +{ + hycapictrl_info *cinfo = card->hyctrlinfo; + struct capi_ctr *ctrl; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_capi_release\n"); +#endif + if(cinfo) { + ctrl = cinfo->capi_ctrl; + hycapi_remove_ctr(ctrl); + } + return 0; +} + +/************************************************************** +hycapi_capi_stop + +Stop CAPI-Output on a card. (e.g. during reboot) +***************************************************************/ + +int hycapi_capi_stop(hysdn_card *card) +{ + hycapictrl_info *cinfo = card->hyctrlinfo; + struct capi_ctr *ctrl; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_capi_stop\n"); +#endif + if(cinfo) { + if(cinfo->capi_ctrl) { + ctrl = cinfo->capi_ctrl; +/* ctrl->suspend_output(ctrl); */ + ctrl->reseted(ctrl); + + } else { + printk(KERN_NOTICE "hycapi_capi_stop: cinfo but no capi_ctrl\n"); + } + } + return 0; +} + +/*************************************************************** +hycapi_send_message + +Send a message to the controller. + +Messages are parsed for their Command/Subcommand-type, and appropriate +action's are performed. + +Note that we have to muck around with a 64Bit-DATA_REQ as there are +firmware-releases that do not check the MsgLen-Indication! + +***************************************************************/ + +void hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) +{ + __u16 appl_id; + int _len, _len2; + __u8 msghead[64]; + + appl_id = CAPIMSG_APPID(skb->data); + switch(_hycapi_appCheck(appl_id, ctrl->cnr)) + { + case 0: +/* printk(KERN_INFO "Need to register\n"); */ + hycapi_register_internal(ctrl, + appl_id, + &(hycapi_applications[appl_id-1].rp)); + break; + case 1: + break; + default: + printk(KERN_ERR "HYCAPI: Controller mixup!\n"); + return; + } + switch(CAPIMSG_CMD(skb->data)) { + case CAPI_DISCONNECT_B3_RESP: + ctrl->free_ncci(ctrl, appl_id, + CAPIMSG_NCCI(skb->data)); + break; + case CAPI_DATA_B3_REQ: + _len = CAPIMSG_LEN(skb->data); + if (_len > 22) { + _len2 = _len - 22; + memcpy(msghead, skb->data, 22); + memcpy(skb->data + _len2, msghead, 22); + skb_pull(skb, _len2); + CAPIMSG_SETLEN(skb->data, 22); + } + break; + case CAPI_LISTEN_REQ: + if(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1]) + { + kfree_skb(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1]); + hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1] = NULL; + } + if (!(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1] = skb_copy(skb, GFP_ATOMIC))) + { + printk(KERN_ERR "HYSDN: memory squeeze in private_listen\n"); + } + break; + default: + break; + } + hycapi_sendmsg_internal(ctrl, skb); +} + +/********************************************************************* +hycapi_read_proc + +Informations provided in the /proc/capi-entries. + +*********************************************************************/ + +int hycapi_read_proc(char *page, char **start, off_t off, + int count, int *eof, struct capi_ctr *ctrl) +{ + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); + hysdn_card *card = cinfo->card; + int len = 0; + char *s; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_read_proc\n"); +#endif + len += sprintf(page+len, "%-16s %s\n", "name", cinfo->cardname); + len += sprintf(page+len, "%-16s 0x%x\n", "io", card->iobase); + len += sprintf(page+len, "%-16s %d\n", "irq", card->irq); + + switch (card->brdtype) { + case BD_PCCARD: s = "HYSDN Hycard"; break; + case BD_ERGO: s = "HYSDN Ergo2"; break; + case BD_METRO: s = "HYSDN Metro4"; break; + case BD_CHAMP2: s = "HYSDN Champ2"; break; + case BD_PLEXUS: s = "HYSDN Plexus30"; break; + default: s = "???"; break; + } + len += sprintf(page+len, "%-16s %s\n", "type", s); + if ((s = cinfo->version[VER_DRIVER]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); + if ((s = cinfo->version[VER_CARDTYPE]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); + if ((s = cinfo->version[VER_SERIAL]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); + + len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname); + + if (off+count >= len) + *eof = 1; + if (len < off) + return 0; + *start = page + off; + return ((count < len-off) ? count : len-off); +} + +/************************************************************** +hycapi_load_firmware + +This does NOT load any firmware, but the callback somehow is needed +on capi-interface registration. + +**************************************************************/ + +int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) +{ +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_load_firmware\n"); +#endif + return 0; +} + + +char *hycapi_procinfo(struct capi_ctr *ctrl) +{ + hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_proc_info\n"); +#endif + if (!cinfo) + return ""; + sprintf(cinfo->infobuf, "%s %s 0x%x %d %s", + cinfo->cardname[0] ? cinfo->cardname : "-", + cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", + cinfo->card ? cinfo->card->iobase : 0x0, + cinfo->card ? cinfo->card->irq : 0, + hycapi_revision + ); + return cinfo->infobuf; +} + +/****************************************************************** +hycapi_rx_capipkt + +Recieve a capi-message. + +All B3_DATA_IND are converted to 64K-extension compatible format. +New nccis are created if neccessary. +*******************************************************************/ + +void +hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len) +{ + struct sk_buff *skb; + hycapictrl_info *cinfo = card->hyctrlinfo; + struct capi_ctr *ctrl; + __u16 ApplId; + __u16 MsgLen, info; + __u16 len2, CapiCmd; + __u32 CP64[2] = {0,0}; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_rx_capipkt\n"); +#endif + if(!cinfo) { + printk(KERN_ERR "HYSDN Card%d: no HYCAPI-controller!\n", + card->myid); + return; + } + ctrl = cinfo->capi_ctrl; + if(!ctrl) + { + printk(KERN_ERR "HYSDN Card%d: no CAPI-controller (1)!\n", + card->myid); + return; + } + if(len < CAPI_MSG_BASELEN) { + printk(KERN_ERR "HYSDN Card%d: invalid CAPI-message, lenght %d!\n", + card->myid, len); + return; + } + MsgLen = CAPIMSG_LEN(buf); + ApplId = CAPIMSG_APPID(buf); + CapiCmd = CAPIMSG_CMD(buf); + + if((CapiCmd == CAPI_DATA_B3_IND) && (MsgLen < 30)) { + len2 = len + (30 - MsgLen); + if (!(skb = alloc_skb(len2, GFP_ATOMIC))) { + printk(KERN_ERR "HYSDN Card%d: incoming packet dropped\n", + card->myid); + return; + } + memcpy(skb_put(skb, MsgLen), buf, MsgLen); + memcpy(skb_put(skb, 2*sizeof(__u32)), CP64, 2* sizeof(__u32)); + memcpy(skb_put(skb, len - MsgLen), buf + MsgLen, + len - MsgLen); + CAPIMSG_SETLEN(skb->data, 30); + } else { + if (!(skb = alloc_skb(len, GFP_ATOMIC))) { + printk(KERN_ERR "HYSDN Card%d: incoming packet dropped\n", + card->myid); + return; + } + memcpy(skb_put(skb, len), buf, len); + } + switch(CAPIMSG_CMD(skb->data)) + { + case CAPI_CONNECT_B3_CONF: +/* Check info-field for error-indication: */ + info = CAPIMSG_U16(skb->data, 12); + switch(info) + { + case 0: + ctrl->new_ncci(ctrl, ApplId, CAPIMSG_NCCI(skb->data), + hycapi_applications[ApplId-1].rp.datablkcnt); + + break; + case 0x0001: + printk(KERN_ERR "HYSDN Card%d: NCPI not supported by current " + "protocol. NCPI ignored.\n", card->myid); + break; + case 0x2001: + printk(KERN_ERR "HYSDN Card%d: Message not supported in" + " current state\n", card->myid); + break; + case 0x2002: + printk(KERN_ERR "HYSDN Card%d: illegal PLCI\n", card->myid); + break; + case 0x2004: + printk(KERN_ERR "HYSDN Card%d: out of NCCI\n", card->myid); + break; + case 0x3008: + printk(KERN_ERR "HYSDN Card%d: NCPI not supported\n", + card->myid); + break; + default: + printk(KERN_ERR "HYSDN Card%d: Info in CONNECT_B3_CONF: %d\n", + card->myid, info); + break; + } + break; + case CAPI_CONNECT_B3_IND: + ctrl->new_ncci(ctrl, ApplId, + CAPIMSG_NCCI(skb->data), + hycapi_applications[ApplId-1].rp.datablkcnt); + break; + default: + break; + } + ctrl->handle_capimsg(ctrl, ApplId, skb); +} + +/****************************************************************** +hycapi_tx_capiack + +Internally acknowledge a msg sent. This will remove the msg from the +internal queue. + +*******************************************************************/ + +void hycapi_tx_capiack(hysdn_card * card) +{ + hycapictrl_info *cinfo = card->hyctrlinfo; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_tx_capiack\n"); +#endif + if(!cinfo) { + printk(KERN_ERR "HYSDN Card%d: no CAPI-controller (2)!\n", + card->myid); + return; + } + spin_lock_irq(&cinfo->lock); + kfree_skb(cinfo->skbs[cinfo->out_idx]); /* free skb */ + cinfo->skbs[cinfo->out_idx++] = NULL; + if (cinfo->out_idx >= HYSDN_MAX_CAPI_SKB) + cinfo->out_idx = 0; /* wrap around */ + + if (cinfo->sk_count-- == HYSDN_MAX_CAPI_SKB) /* dec usage count */ + cinfo->capi_ctrl->resume_output(cinfo->capi_ctrl); + spin_unlock_irq(&cinfo->lock); +} + +/*************************************************************** +hycapi_tx_capiget(hysdn_card *card) + +This is called when polling for messages to SEND. + +****************************************************************/ + +struct sk_buff * +hycapi_tx_capiget(hysdn_card *card) +{ + hycapictrl_info *cinfo = card->hyctrlinfo; + if(!cinfo) { + printk(KERN_ERR "HYSDN Card%d: no CAPI-controller! (3)\n", + card->myid); + return (struct sk_buff *)NULL; + } + if (!cinfo->sk_count) + return (struct sk_buff *)NULL; /* nothing available */ + + return (cinfo->skbs[cinfo->out_idx]); /* next packet to send */ +} + + +static struct capi_driver hycapi_driver = { + "hysdn", + "0.0", + hycapi_load_firmware, + hycapi_reset_ctr, + hycapi_remove_ctr, + hycapi_register_appl, + hycapi_release_appl, + hycapi_send_message, + hycapi_procinfo, + hycapi_read_proc, + 0, /* use standard driver_read_proc */ + 0, /* no add_card function */ +}; + + +/********************************************************** +int hycapi_init() + +attach the capi-driver to the kernel-capi. + +***********************************************************/ + +int hycapi_init() +{ + struct capi_driver *driver; + int i; + if(hy_di) { + printk(KERN_NOTICE "HyDI allready set\n"); + return 0; + } + driver = &hycapi_driver; + printk(KERN_NOTICE "HYSDN: Attaching capi-driver\n"); + hy_di = attach_capi_driver(driver); + if (!hy_di) { + printk(KERN_ERR "HYCAPI: failed to attach capi_driver\n"); + return(-1); + } + for(i=0;i<CAPI_MAXAPPL;i++) { + memset(&(hycapi_applications[i]), 0, sizeof(hycapi_appl)); + } + return(0); +} + +/************************************************************** +hycapi_cleanup(void) + +detach the capi-driver to the kernel-capi. Actually this should +free some more ressources. Do that later. +**************************************************************/ + +void +hycapi_cleanup(void) +{ + struct capi_driver *driver; + driver = &hycapi_driver; + if (!hy_di) { + printk(KERN_ERR "HYSDN: no capi-driver to detach (???)\n"); + return; + } + printk(KERN_NOTICE "HYSDN: Detaching capi-driver\n"); + detach_capi_driver(driver); + hy_di = 0; + return; +} + +/******************************************************************** +hycapi_capi_create(hysdn_card *card) + +Attach the card with it's capi-ctrl. +*********************************************************************/ + +static void hycapi_fill_profile(hysdn_card *card) +{ + hycapictrl_info *cinfo = NULL; + struct capi_ctr *ctrl = NULL; + cinfo = card->hyctrlinfo; + if(!cinfo) return; + ctrl = cinfo->capi_ctrl; + if(!ctrl) return; + strcpy(ctrl->manu, "Hypercope"); + ctrl->version.majorversion = 2; + ctrl->version.minorversion = 0; + ctrl->version.majormanuversion = 3; + ctrl->version.minormanuversion = 2; + ctrl->profile.ncontroller = card->myid; + ctrl->profile.nbchannel = card->bchans; + ctrl->profile.goptions = GLOBAL_OPTION_INTERNAL_CONTROLLER | + GLOBAL_OPTION_B_CHANNEL_OPERATION; + ctrl->profile.support1 = B1_PROT_64KBIT_HDLC | + (card->faxchans ? B1_PROT_T30 : 0) | + B1_PROT_64KBIT_TRANSPARENT; + ctrl->profile.support2 = B2_PROT_ISO7776 | + (card->faxchans ? B2_PROT_T30 : 0) | + B2_PROT_TRANSPARENT; + ctrl->profile.support3 = B3_PROT_TRANSPARENT | + B3_PROT_T90NL | + (card->faxchans ? B3_PROT_T30 : 0) | + (card->faxchans ? B3_PROT_T30EXT : 0) | + B3_PROT_ISO8208; +} + +int +hycapi_capi_create(hysdn_card *card) +{ + hycapictrl_info *cinfo = NULL; + struct capi_ctr *ctrl = NULL; +#ifdef HYCAPI_PRINTFNAMES + printk(KERN_NOTICE "hycapi_capi_create\n"); +#endif + if (!card->hyctrlinfo) { + cinfo = (hycapictrl_info *) kmalloc(sizeof(hycapictrl_info), GFP_ATOMIC); + if (!cinfo) { + printk(KERN_WARNING "HYSDN: no memory for capi-ctrl.\n"); + return -ENOMEM; + } + memset(cinfo, 0, sizeof(hycapictrl_info)); + card->hyctrlinfo = cinfo; + cinfo->card = card; + spin_lock_init(&cinfo->lock); + + switch (card->brdtype) { + case BD_PCCARD: strcpy(cinfo->cardname,"HYSDN Hycard"); break; + case BD_ERGO: strcpy(cinfo->cardname,"HYSDN Ergo2"); break; + case BD_METRO: strcpy(cinfo->cardname,"HYSDN Metro4"); break; + case BD_CHAMP2: strcpy(cinfo->cardname,"HYSDN Champ2"); break; + case BD_PLEXUS: strcpy(cinfo->cardname,"HYSDN Plexus30"); break; + default: strcpy(cinfo->cardname,"HYSDN ???"); break; + } + + cinfo->capi_ctrl = hy_di->attach_ctr(&hycapi_driver, + cinfo->cardname, cinfo); + ctrl = cinfo->capi_ctrl; + if (!ctrl) { + printk(KERN_ERR "%s: attach controller failed.\n", + hycapi_driver.name); + return -EBUSY; + } + /* fill in the blanks: */ + hycapi_fill_profile(card); + ctrl->ready(ctrl); + } else { + /* resume output on stopped ctrl */ + ctrl = card->hyctrlinfo->capi_ctrl; + if(ctrl) { + hycapi_fill_profile(card); + ctrl->ready(ctrl); + hycapi_restart_internal(ctrl); +/* ctrl->resume_output(ctrl); */ + } else { + printk(KERN_WARNING "HYSDN: No ctrl???? How come?\n"); + } + } + return 0; +} diff --git a/drivers/isdn/hysdn/hysdn_boot.c b/drivers/isdn/hysdn/hysdn_boot.c index 030c40de6..31eaa14cb 100644 --- a/drivers/isdn/hysdn/hysdn_boot.c +++ b/drivers/isdn/hysdn/hysdn_boot.c @@ -1,4 +1,4 @@ -/* $Id: hysdn_boot.c,v 1.1 2000/02/10 19:45:18 werner Exp $ +/* $Id: hysdn_boot.c,v 1.3 2000/05/17 11:41:30 ualbrecht Exp $ * Linux driver for HYSDN cards, specific routines for booting and pof handling. * @@ -21,6 +21,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_boot.c,v $ + * Revision 1.3 2000/05/17 11:41:30 ualbrecht + * CAPI 2.0 support added + * + * Revision 1.2 2000/04/23 14:18:36 kai + * merge changes from main tree + * * Revision 1.1 2000/02/10 19:45:18 werner * * Initial release @@ -260,7 +266,6 @@ pof_write_buffer(hysdn_card * card, int datlen) } if ((boot->last_error = pof_handle_data(card, datlen)) < 0) return (boot->last_error); /* an error occured */ - boot->pof_recoffset += datlen; if (boot->pof_recoffset >= boot->pof_reclen) { boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h index cac76cb26..e5ad863d4 100644 --- a/drivers/isdn/hysdn/hysdn_defs.h +++ b/drivers/isdn/hysdn/hysdn_defs.h @@ -1,4 +1,4 @@ -/* $Id: hysdn_defs.h,v 1.1 2000/02/10 19:44:30 werner Exp $ +/* $Id: hysdn_defs.h,v 1.3 2000/06/13 09:14:26 ualbrecht Exp $ * Linux driver for HYSDN cards, global definitions and exported vars and functions. * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH @@ -20,6 +20,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_defs.h,v $ + * Revision 1.3 2000/06/13 09:14:26 ualbrecht + * Removed obsolete struct for CAPI-application tracking. + * + * Revision 1.2 2000/05/17 11:41:30 ualbrecht + * CAPI 2.0 support added + * * Revision 1.1 2000/02/10 19:44:30 werner * * Initial release @@ -27,6 +33,10 @@ * */ +#ifndef HYSDN_DEFS_H +#define HYSDN_DEFS_H + +#include <linux/config.h> #include <linux/hysdn_if.h> #include <linux/interrupt.h> #include <linux/tqueue.h> @@ -42,6 +52,54 @@ #include "ince1pc.h" +#ifdef CONFIG_HYSDN_CAPI +#include <linux/capi.h> +#include "../avmb1/capicmd.h" +#include "../avmb1/capiutil.h" +#include "../avmb1/capilli.h" + +/***************************/ +/* CAPI-Profile values. */ +/***************************/ + +#define GLOBAL_OPTION_INTERNAL_CONTROLLER 0x0001 +#define GLOBAL_OPTION_EXTERNAL_CONTROLLER 0x0002 +#define GLOBAL_OPTION_HANDSET 0x0004 +#define GLOBAL_OPTION_DTMF 0x0008 +#define GLOBAL_OPTION_SUPPL_SERVICES 0x0010 +#define GLOBAL_OPTION_CHANNEL_ALLOCATION 0x0020 +#define GLOBAL_OPTION_B_CHANNEL_OPERATION 0x0040 + +#define B1_PROT_64KBIT_HDLC 0x0001 +#define B1_PROT_64KBIT_TRANSPARENT 0x0002 +#define B1_PROT_V110_ASYNCH 0x0004 +#define B1_PROT_V110_SYNCH 0x0008 +#define B1_PROT_T30 0x0010 +#define B1_PROT_64KBIT_INV_HDLC 0x0020 +#define B1_PROT_56KBIT_TRANSPARENT 0x0040 + +#define B2_PROT_ISO7776 0x0001 +#define B2_PROT_TRANSPARENT 0x0002 +#define B2_PROT_SDLC 0x0004 +#define B2_PROT_LAPD 0x0008 +#define B2_PROT_T30 0x0010 +#define B2_PROT_PPP 0x0020 +#define B2_PROT_TRANSPARENT_IGNORE_B1_FRAMING_ERRORS 0x0040 + +#define B3_PROT_TRANSPARENT 0x0001 +#define B3_PROT_T90NL 0x0002 +#define B3_PROT_ISO8208 0x0004 +#define B3_PROT_X25_DCE 0x0008 +#define B3_PROT_T30 0x0010 +#define B3_PROT_T30EXT 0x0020 + +#define HYSDN_MAXVERSION 8 + +/* Number of sendbuffers in CAPI-queue */ +#define HYSDN_MAX_CAPI_SKB 20 + +#endif /* CONFIG_HYSDN_CAPI*/ + /************************************************/ /* constants and bits for debugging/log outputs */ /************************************************/ @@ -176,8 +234,30 @@ typedef struct HYSDN_CARD { /* init and deinit stopcard for booting, too */ void (*stopcard) (struct HYSDN_CARD *); void (*releasehardware) (struct HYSDN_CARD *); +#ifdef CONFIG_HYSDN_CAPI + struct hycapictrl_info { + char cardname[32]; + spinlock_t lock; + int versionlen; + char versionbuf[1024]; + char *version[HYSDN_MAXVERSION]; + + char infobuf[128]; /* for function procinfo */ + + struct HYSDN_CARD *card; + struct capi_ctr *capi_ctrl; + struct sk_buff *skbs[HYSDN_MAX_CAPI_SKB]; + int in_idx, out_idx; /* indexes to buffer ring */ + int sk_count; /* number of buffers currently in ring */ + struct sk_buff *tx_skb; /* buffer for tx operation */ + } *hyctrlinfo; +#endif /* CONFIG_HYSDN_CAPI */ } hysdn_card; +#ifdef CONFIG_HYSDN_CAPI +typedef struct hycapictrl_info hycapictrl_info; +#endif /* CONFIG_HYSDN_CAPI */ + /*****************/ /* exported vars */ @@ -227,3 +307,27 @@ extern char *hysdn_net_getname(hysdn_card *); /* get name of net interface */ extern void hysdn_tx_netack(hysdn_card *); /* acknowledge a packet tx */ extern struct sk_buff *hysdn_tx_netget(hysdn_card *); /* get next network packet */ extern void hysdn_rx_netpkt(hysdn_card *, uchar *, word); /* rxed packet from network */ + +#ifdef CONFIG_HYSDN_CAPI +extern struct capi_driver_interface *hy_di; +extern int hycapi_capi_create(hysdn_card *); /* create a new capi device */ +extern int hycapi_capi_release(hysdn_card *); /* delete the device */ +extern int hycapi_capi_stop(hysdn_card *card); /* suspend */ +extern int hycapi_load_firmware(struct capi_ctr *, capiloaddata *); +extern void hycapi_reset_ctr(struct capi_ctr *); +extern void hycapi_remove_ctr(struct capi_ctr *); +extern void hycapi_register_appl(struct capi_ctr *, __u16 appl, + capi_register_params *); +extern void hycapi_release_appl(struct capi_ctr *, __u16 appl); +extern void hycapi_send_message(struct capi_ctr *, struct sk_buff *skb); +extern char *hycapi_procinfo(struct capi_ctr *); +extern int hycapi_read_proc(char *page, char **start, off_t off, + int count, int *eof, struct capi_ctr *card); +extern void hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len); +extern void hycapi_tx_capiack(hysdn_card * card); +extern struct sk_buff *hycapi_tx_capiget(hysdn_card *card); +extern int hycapi_init(void); +extern void hycapi_cleanup(void); +#endif /* CONFIG_HYSDN_CAPI */ + +#endif /* HYSDN_DEFS_H */ diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c index 23b79ddd9..6ae0c3a7f 100644 --- a/drivers/isdn/hysdn/hysdn_init.c +++ b/drivers/isdn/hysdn/hysdn_init.c @@ -1,4 +1,4 @@ -/* $Id: hysdn_init.c,v 1.1 2000/02/10 19:45:18 werner Exp $ +/* $Id: hysdn_init.c,v 1.5 2000/08/20 16:46:09 keil Exp $ * Linux driver for HYSDN cards, init functions. * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH @@ -20,6 +20,18 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_init.c,v $ + * Revision 1.5 2000/08/20 16:46:09 keil + * Changes for 2.4 + * + * Revision 1.4 2000/06/18 16:08:18 keil + * 2.4 PCI changes and some cosmetics + * + * Revision 1.3 2000/06/13 09:15:07 ualbrecht + * Module will now unload more gracefully. + * + * Revision 1.2 2000/05/17 11:41:30 ualbrecht + * CAPI 2.0 support added + * * Revision 1.1 2000/02/10 19:45:18 werner * * Initial release @@ -37,7 +49,7 @@ #include "hysdn_defs.h" -static char *hysdn_init_revision = "$Revision: 1.1 $"; +static char *hysdn_init_revision = "$Revision: 1.5 $"; int cardmax; /* number of found cards */ hysdn_card *card_root = NULL; /* pointer to first card */ @@ -77,7 +89,6 @@ search_cards(void) { struct pci_dev *akt_pcidev = NULL; hysdn_card *card, *card_last; - uchar irq; int i; card_root = NULL; @@ -218,6 +229,14 @@ init_module(void) free_resources(); /* proc file_sys not created */ return (-1); } +#ifdef CONFIG_HYSDN_CAPI + if(cardmax > 0) { + if(hycapi_init()) { + printk(KERN_ERR "HYCAPI: init failed\n"); + return(-1); + } + } +#endif /* CONFIG_HYSDN_CAPI */ return (0); /* no error */ } /* init_module */ @@ -233,8 +252,18 @@ init_module(void) void cleanup_module(void) { - +#ifdef CONFIG_HYSDN_CAPI + hysdn_card *card; +#endif /* CONFIG_HYSDN_CAPI */ stop_cards(); +#ifdef CONFIG_HYSDN_CAPI + card = card_root; /* first in chain */ + while (card) { + hycapi_capi_release(card); + card = card->next; /* remove card from chain */ + } /* while card */ + hycapi_cleanup(); +#endif /* CONFIG_HYSDN_CAPI */ hysdn_procconf_release(); free_resources(); printk(KERN_NOTICE "HYSDN: module unloaded\n"); diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c index 538dfe6d4..61441da10 100644 --- a/drivers/isdn/hysdn/hysdn_net.c +++ b/drivers/isdn/hysdn/hysdn_net.c @@ -1,4 +1,4 @@ -/* $Id: hysdn_net.c,v 1.3 2000/02/14 19:24:12 werner Exp $ +/* $Id: hysdn_net.c,v 1.7 2000/05/23 06:48:54 ualbrecht Exp $ * Linux driver for HYSDN cards, net (ethernet type) handling routines. * @@ -24,6 +24,19 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_net.c,v $ + * Revision 1.7 2000/05/23 06:48:54 ualbrecht + * Reverted last change in dev->name assignment (broken netdevice.h in 2.3.99pre6?) + * + * Revision 1.6 2000/05/17 11:43:03 ualbrecht + * Fixed a NULL-pointer kernel-oops assigning the device-name + * + * Revision 1.5 2000/05/06 00:52:38 kai + * merged changes from kernel tree + * fixed timer and net_device->name breakage + * + * Revision 1.4 2000/04/23 14:18:36 kai + * merge changes from main tree + * * Revision 1.3 2000/02/14 19:24:12 werner * * Removed superflous file @@ -52,7 +65,7 @@ #include "hysdn_defs.h" /* store the actual version for log reporting */ -char *hysdn_net_revision = "$Revision: 1.3 $"; +char *hysdn_net_revision = "$Revision: 1.7 $"; #define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */ @@ -308,7 +321,10 @@ hysdn_net_create(hysdn_card * card) { struct net_device *dev; int i; - + if(!card) { + printk(KERN_WARNING "No card-pt in hysdn_net_create!\n"); + return (-ENOMEM); + } hysdn_net_release(card); /* release an existing net device */ if ((dev = kmalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) { printk(KERN_WARNING "HYSDN: unable to allocate mem\n"); @@ -323,6 +339,9 @@ hysdn_net_create(hysdn_card * card) dev->base_addr = card->iobase; /* IO address */ dev->irq = card->irq; /* irq */ dev->init = net_init; /* the init function of the device */ + if(dev->name) { + strcpy(dev->name, ((struct net_local *) dev)->dev_name); + } if ((i = register_netdev(dev))) { printk(KERN_WARNING "HYSDN: unable to create network device\n"); kfree(dev); diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c index c28aedc1f..aa17c1014 100644 --- a/drivers/isdn/hysdn/hysdn_procconf.c +++ b/drivers/isdn/hysdn/hysdn_procconf.c @@ -1,4 +1,4 @@ -/* $Id: hysdn_procconf.c,v 1.4 2000/03/03 16:37:12 kai Exp $ +/* $Id: hysdn_procconf.c,v 1.7 2000/08/20 16:46:09 keil Exp $ * Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions. * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH @@ -20,6 +20,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_procconf.c,v $ + * Revision 1.7 2000/08/20 16:46:09 keil + * Changes for 2.4 + * + * Revision 1.6 2000/05/17 11:41:30 ualbrecht + * CAPI 2.0 support added + * + * Revision 1.5 2000/04/23 14:18:36 kai + * merge changes from main tree + * * Revision 1.4 2000/03/03 16:37:12 kai * incorporated some cosmetic changes from the official kernel tree back * into CVS @@ -49,7 +58,7 @@ #include "hysdn_defs.h" -static char *hysdn_procconf_revision = "$Revision: 1.4 $"; +static char *hysdn_procconf_revision = "$Revision: 1.7 $"; #define INFO_OUT_LEN 80 /* length of info line including lf */ @@ -335,7 +344,7 @@ hysdn_conf_open(struct inode *ino, struct file *filep) *cp++ = '\n'; /* and now the data */ - sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08x %7d %9d %3d %s", + sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08lx %7d %9d %3d %s", card->myid, card->bus, PCI_SLOT(card->devfn), diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index ba454b9dc..a0ac125fe 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -1,4 +1,4 @@ -/* $Id: hysdn_proclog.c,v 1.4 2000/03/03 16:37:12 kai Exp $ +/* $Id: hysdn_proclog.c,v 1.7 2000/08/20 16:46:09 keil Exp $ * Linux driver for HYSDN cards, /proc/net filesystem log functions. * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH @@ -20,6 +20,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_proclog.c,v $ + * Revision 1.7 2000/08/20 16:46:09 keil + * Changes for 2.4 + * + * Revision 1.6 2000/06/18 16:08:18 keil + * 2.4 PCI changes and some cosmetics + * + * Revision 1.5 2000/04/23 14:18:36 kai + * merge changes from main tree + * * Revision 1.4 2000/03/03 16:37:12 kai * incorporated some cosmetic changes from the official kernel tree back * into CVS @@ -49,8 +58,6 @@ #include "hysdn_defs.h" -static char *hysdn_proclog_revision = "$Revision: 1.4 $"; - /* the proc subdir for the interface is defined in the procconf module */ extern struct proc_dir_entry *hysdn_proc_entry; @@ -456,7 +463,7 @@ hysdn_proclog_init(hysdn_card * card) sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) { pd->log->proc_fops = &log_fops; - pd->log->owner = THIS_MODULE; + pd->log->owner = THIS_MODULE; } init_waitqueue_head(&(pd->rd_queue)); diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/isdn/hysdn/hysdn_sched.c index 0e5f9e7ba..64b8782f0 100644 --- a/drivers/isdn/hysdn/hysdn_sched.c +++ b/drivers/isdn/hysdn/hysdn_sched.c @@ -1,4 +1,4 @@ -/* $Id: hysdn_sched.c,v 1.1 2000/02/10 19:45:18 werner Exp $ +/* $Id: hysdn_sched.c,v 1.3 2000/05/17 11:41:30 ualbrecht Exp $ * Linux driver for HYSDN cards, scheduler routines for handling exchange card <-> pc. * @@ -21,6 +21,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_sched.c,v $ + * Revision 1.3 2000/05/17 11:41:30 ualbrecht + * CAPI 2.0 support added + * + * Revision 1.2 2000/04/23 14:18:36 kai + * merge changes from main tree + * * Revision 1.1 2000/02/10 19:45:18 werner * * Initial release @@ -29,6 +35,7 @@ */ #define __NO_VERSION__ +#include <linux/config.h> #include <linux/module.h> #include <linux/version.h> #include <asm/io.h> @@ -60,7 +67,12 @@ hysdn_sched_rx(hysdn_card * card, uchar * buf, word len, word chan) if (card->err_log_state == ERRLOG_STATE_ON) card->err_log_state = ERRLOG_STATE_START; /* start new fetch */ break; - +#ifdef CONFIG_HYSDN_CAPI + case CHAN_CAPI: +/* give packet to CAPI handler */ + hycapi_rx_capipkt(card, buf, len); + break; +#endif /* CONFIG_HYSDN_CAPI */ default: printk(KERN_INFO "irq message channel %d len %d unhandled \n", chan, len); break; @@ -125,6 +137,17 @@ hysdn_sched_tx(hysdn_card * card, uchar * buf, word volatile *len, word volatile } else hysdn_tx_netack(card); /* aknowledge packet -> throw away */ } /* send a network packet if available */ +#ifdef CONFIG_HYSDN_CAPI + if((skb = hycapi_tx_capiget(card)) != NULL) { + if (skb->len <= maxlen) { + memcpy(buf, skb->data, skb->len); + *len = skb->len; + *chan = CHAN_CAPI; + hycapi_tx_capiack(card); + return (1); /* go and send the data */ + } + } +#endif /* CONFIG_HYSDN_CAPI */ return (0); /* nothing to send */ } /* hysdn_sched_tx */ diff --git a/drivers/isdn/hysdn/ince1pc.h b/drivers/isdn/hysdn/ince1pc.h index c22974d85..9f9d3104d 100644 --- a/drivers/isdn/hysdn/ince1pc.h +++ b/drivers/isdn/hysdn/ince1pc.h @@ -1,132 +1,132 @@ -#ifndef __INCE1PC_H__
-#define __INCE1PC_H__
-
-/****************************************************************************
-
- FILE: ince1pc.h
-
- AUTHOR: M.Steinkopf
-
- PURPOSE: common definitions for both sides of the bus:
- - conventions both spoolers must know
- - channel numbers agreed upon
-
-*****************************************************************************/
-
-/* basic scalar definitions have same meanning,
- * but their declaration location depends on environment
- */
-
-/*--------------------------------------channel numbers---------------------*/
-#define CHAN_SYSTEM 0x0001 /* system channel (spooler to spooler) */
-#define CHAN_ERRLOG 0x0005 /* error logger */
-#define CHAN_CAPI 0x0064 /* CAPI interface */
-#define CHAN_NDIS_DATA 0x1001 /* NDIS data transfer */
-
-/*--------------------------------------POF ready msg-----------------------*/
- /* NOTE: after booting POF sends system ready message to PC: */
-#define RDY_MAGIC 0x52535953UL /* 'SYSR' reversed */
-#define RDY_MAGIC_SIZE 4 /* size in bytes */
-
-#define MAX_N_TOK_BYTES 255
-
-#define MIN_RDY_MSG_SIZE RDY_MAGIC_SIZE
-#define MAX_RDY_MSG_SIZE (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
-
-#define SYSR_TOK_END 0
-#define SYSR_TOK_B_CHAN 1 /* nr. of B-Channels; DataLen=1; def: 2 */
-#define SYSR_TOK_FAX_CHAN 2 /* nr. of FAX Channels; DataLen=1; def: 0 */
-#define SYSR_TOK_MAC_ADDR 3 /* MAC-Address; DataLen=6; def: auto */
-#define SYSR_TOK_ESC 255 /* undefined data size yet */
- /* default values, if not corrected by token: */
-#define SYSR_TOK_B_CHAN_DEF 2 /* assume 2 B-Channels */
-#define SYSR_TOK_FAX_CHAN_DEF 1 /* assume 1 FAX Channel */
-
-/* syntax of new SYSR token stream:
- * channel: CHAN_SYSTEM
- * msgsize: MIN_RDY_MSG_SIZE <= x <= MAX_RDY_MSG_SIZE
- * RDY_MAGIC_SIZE <= x <= (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
- * msg : 0 1 2 3 {4 5 6 ..}
- * S Y S R MAX_N_TOK_BYTES bytes of TokenStream
- *
- * TokenStream := empty
- * | {NonEndTokenChunk} EndToken RotlCRC
- * NonEndTokenChunk:= NonEndTokenId DataLen [Data]
- * NonEndTokenId := 0x01 .. 0xFE 1 BYTE
- * DataLen := 0x00 .. 0xFF 1 BYTE
- * Data := DataLen bytes
- * EndToken := 0x00
- * RotlCRC := special 1 byte CRC over all NonEndTokenChunk bytes
- * s. RotlCRC algorithm
- *
- * RotlCRC algorithm:
- * ucSum= 0 1 uchar
- * for all NonEndTokenChunk bytes:
- * ROTL(ucSum,1) rotate left by 1
- * ucSum += Char; add current byte with swap around
- * RotlCRC= ~ucSum; invert all bits for result
- *
- * note:
- * - for 16-bit FIFO add padding 0 byte to achieve even token data bytes!
- */
-
-/*--------------------------------------error logger------------------------*/
- /* note: pof needs final 0 ! */
-#define ERRLOG_CMD_REQ "ERRLOG ON"
-#define ERRLOG_CMD_REQ_SIZE 10 /* with final 0 byte ! */
-#define ERRLOG_CMD_STOP "ERRLOG OFF"
-#define ERRLOG_CMD_STOP_SIZE 11 /* with final 0 byte ! */
-
-#define ERRLOG_ENTRY_SIZE 64 /* sizeof(tErrLogEntry) */
- /* remaining text size = 55 */
-#define ERRLOG_TEXT_SIZE (ERRLOG_ENTRY_SIZE-2*4-1)
-
+#ifndef __INCE1PC_H__ +#define __INCE1PC_H__ + +/**************************************************************************** + + FILE: ince1pc.h + + AUTHOR: M.Steinkopf + + PURPOSE: common definitions for both sides of the bus: + - conventions both spoolers must know + - channel numbers agreed upon + +*****************************************************************************/ + +/* basic scalar definitions have same meanning, + * but their declaration location depends on environment + */ + +/*--------------------------------------channel numbers---------------------*/ +#define CHAN_SYSTEM 0x0001 /* system channel (spooler to spooler) */ +#define CHAN_ERRLOG 0x0005 /* error logger */ +#define CHAN_CAPI 0x0064 /* CAPI interface */ +#define CHAN_NDIS_DATA 0x1001 /* NDIS data transfer */ + +/*--------------------------------------POF ready msg-----------------------*/ + /* NOTE: after booting POF sends system ready message to PC: */ +#define RDY_MAGIC 0x52535953UL /* 'SYSR' reversed */ +#define RDY_MAGIC_SIZE 4 /* size in bytes */ + +#define MAX_N_TOK_BYTES 255 + +#define MIN_RDY_MSG_SIZE RDY_MAGIC_SIZE +#define MAX_RDY_MSG_SIZE (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES) + +#define SYSR_TOK_END 0 +#define SYSR_TOK_B_CHAN 1 /* nr. of B-Channels; DataLen=1; def: 2 */ +#define SYSR_TOK_FAX_CHAN 2 /* nr. of FAX Channels; DataLen=1; def: 0 */ +#define SYSR_TOK_MAC_ADDR 3 /* MAC-Address; DataLen=6; def: auto */ +#define SYSR_TOK_ESC 255 /* undefined data size yet */ + /* default values, if not corrected by token: */ +#define SYSR_TOK_B_CHAN_DEF 2 /* assume 2 B-Channels */ +#define SYSR_TOK_FAX_CHAN_DEF 1 /* assume 1 FAX Channel */ + +/* syntax of new SYSR token stream: + * channel: CHAN_SYSTEM + * msgsize: MIN_RDY_MSG_SIZE <= x <= MAX_RDY_MSG_SIZE + * RDY_MAGIC_SIZE <= x <= (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES) + * msg : 0 1 2 3 {4 5 6 ..} + * S Y S R MAX_N_TOK_BYTES bytes of TokenStream + * + * TokenStream := empty + * | {NonEndTokenChunk} EndToken RotlCRC + * NonEndTokenChunk:= NonEndTokenId DataLen [Data] + * NonEndTokenId := 0x01 .. 0xFE 1 BYTE + * DataLen := 0x00 .. 0xFF 1 BYTE + * Data := DataLen bytes + * EndToken := 0x00 + * RotlCRC := special 1 byte CRC over all NonEndTokenChunk bytes + * s. RotlCRC algorithm + * + * RotlCRC algorithm: + * ucSum= 0 1 uchar + * for all NonEndTokenChunk bytes: + * ROTL(ucSum,1) rotate left by 1 + * ucSum += Char; add current byte with swap around + * RotlCRC= ~ucSum; invert all bits for result + * + * note: + * - for 16-bit FIFO add padding 0 byte to achieve even token data bytes! + */ + +/*--------------------------------------error logger------------------------*/ + /* note: pof needs final 0 ! */ +#define ERRLOG_CMD_REQ "ERRLOG ON" +#define ERRLOG_CMD_REQ_SIZE 10 /* with final 0 byte ! */ +#define ERRLOG_CMD_STOP "ERRLOG OFF" +#define ERRLOG_CMD_STOP_SIZE 11 /* with final 0 byte ! */ + +#define ERRLOG_ENTRY_SIZE 64 /* sizeof(tErrLogEntry) */ + /* remaining text size = 55 */ +#define ERRLOG_TEXT_SIZE (ERRLOG_ENTRY_SIZE-2*4-1) + typedef struct ErrLogEntry_tag { -
+ /*00 */ ulong ulErrType; -
+ /*04 */ ulong ulErrSubtype; -
+ /*08 */ uchar ucTextSize; -
+ /*09 */ uchar ucText[ERRLOG_TEXT_SIZE]; /* ASCIIZ of len ucTextSize-1 */ -
-/*40 */
+ +/*40 */ } tErrLogEntry; -
-#if defined(__TURBOC__)
-#if sizeof(tErrLogEntry) != ERRLOG_ENTRY_SIZE
-#error size of tErrLogEntry != ERRLOG_ENTRY_SIZE
-#endif /*
*/ -#endif /*
*/ -
-/*--------------------------------------DPRAM boot spooler------------------*/
- /* this is the struture used between pc and
- * hyperstone to exchange boot data
- */
-#define DPRAM_SPOOLER_DATA_SIZE 0x20
+ +#if defined(__TURBOC__) +#if sizeof(tErrLogEntry) != ERRLOG_ENTRY_SIZE +#error size of tErrLogEntry != ERRLOG_ENTRY_SIZE +#endif /* */ +#endif /* */ + +/*--------------------------------------DPRAM boot spooler------------------*/ + /* this is the struture used between pc and + * hyperstone to exchange boot data + */ +#define DPRAM_SPOOLER_DATA_SIZE 0x20 typedef struct DpramBootSpooler_tag { -
+ /*00 */ uchar Len; -
+ /*01 */ volatile uchar RdPtr; -
+ /*02 */ uchar WrPtr; -
+ /*03 */ uchar Data[DPRAM_SPOOLER_DATA_SIZE]; -
-/*23 */
+ +/*23 */ } tDpramBootSpooler; -
-#define DPRAM_SPOOLER_MIN_SIZE 5 /* Len+RdPtr+Wrptr+2*data */
-#define DPRAM_SPOOLER_DEF_SIZE 0x23 /* current default size */
-
-/*--------------------------------------HYCARD/ERGO DPRAM SoftUart----------*/
- /* at DPRAM offset 0x1C00: */
-#define SIZE_RSV_SOFT_UART 0x1B0 /* 432 bytes reserved for SoftUart */
-
-
-#endif /* __INCE1PC_H__ */
+ +#define DPRAM_SPOOLER_MIN_SIZE 5 /* Len+RdPtr+Wrptr+2*data */ +#define DPRAM_SPOOLER_DEF_SIZE 0x23 /* current default size */ + +/*--------------------------------------HYCARD/ERGO DPRAM SoftUart----------*/ + /* at DPRAM offset 0x1C00: */ +#define SIZE_RSV_SOFT_UART 0x1B0 /* 432 bytes reserved for SoftUart */ + + +#endif /* __INCE1PC_H__ */ diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c index 727165387..74905bba0 100644 --- a/drivers/isdn/icn/icn.c +++ b/drivers/isdn/icn/icn.c @@ -1,4 +1,4 @@ -/* $Id: icn.c,v 1.62 1999/09/06 07:29:35 fritz Exp $ +/* $Id: icn.c,v 1.63 2000/05/06 00:52:39 kai Exp $ * ISDN low-level module for the ICN active ISDN-Card. * @@ -19,6 +19,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.c,v $ + * Revision 1.63 2000/05/06 00:52:39 kai + * merged changes from kernel tree + * fixed timer and net_device->name breakage + * * Revision 1.62 1999/09/06 07:29:35 fritz * Changed my mail-address. * @@ -247,7 +251,7 @@ #undef MAP_DEBUG static char -*revision = "$Revision: 1.62 $"; +*revision = "$Revision: 1.63 $"; static int icn_addcard(int, char *, char *); diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c index caf46b112..5dffb2770 100644 --- a/drivers/isdn/isdn_common.c +++ b/drivers/isdn/isdn_common.c @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.108 2000/06/24 15:52:47 keil Exp $ +/* $Id: isdn_common.c,v 1.111 2000/08/20 07:40:14 keil Exp $ * Linux ISDN subsystem, common used functions (linklevel). * @@ -48,7 +48,7 @@ isdn_dev *dev = (isdn_dev *) 0; -static char *isdn_revision = "$Revision: 1.108 $"; +static char *isdn_revision = "$Revision: 1.111 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -1660,6 +1660,8 @@ isdn_open(struct inode *ino, struct file *filep) uint minor = MINOR(ino->i_rdev); int drvidx; int chidx; + int retval = -ENODEV; + if (minor == ISDN_MINOR_STATUS) { infostruct *p; @@ -1670,41 +1672,47 @@ isdn_open(struct inode *ino, struct file *filep) dev->infochain = p; /* At opening we allow a single update */ filep->private_data = (char *) 1; - return 0; - } else - return -ENOMEM; + retval = 0; + goto out; + } else { + retval = -ENOMEM; + goto out; + } } if (!dev->channels) - return -ENODEV; + goto out; if (minor < ISDN_MINOR_CTRL) { printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor); drvidx = isdn_minor2drv(minor); if (drvidx < 0) - return -ENODEV; + goto out; chidx = isdn_minor2chan(minor); if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) - return -ENODEV; + goto out; if (!(dev->drv[drvidx]->online & (1 << chidx))) - return -ENODEV; + goto out; isdn_lock_drivers(); - return 0; + retval = 0; + goto out; } if (minor <= ISDN_MINOR_CTRLMAX) { drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); if (drvidx < 0) - return -ENODEV; + goto out; isdn_lock_drivers(); - return 0; + retval = 0; + goto out; } #ifdef CONFIG_ISDN_PPP if (minor <= ISDN_MINOR_PPPMAX) { - int ret; - if (!(ret = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep))) + retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep); + if (retval == 0) isdn_lock_drivers(); - return ret; + goto out; } #endif - return -ENODEV; + out: + return retval; } static int @@ -1724,31 +1732,28 @@ isdn_close(struct inode *ino, struct file *filep) else dev->infochain = (infostruct *) (p->next); kfree(p); - unlock_kernel(); - return 0; + goto out; } q = p; p = (infostruct *) (p->next); } printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n"); - unlock_kernel(); - return 0; + goto out; } isdn_unlock_drivers(); - if (minor < ISDN_MINOR_CTRL) { - unlock_kernel(); - return 0; - } + if (minor < ISDN_MINOR_CTRL) + goto out; if (minor <= ISDN_MINOR_CTRLMAX) { if (dev->profd == current) dev->profd = NULL; - unlock_kernel(); - return 0; + goto out; } #ifdef CONFIG_ISDN_PPP if (minor <= ISDN_MINOR_PPPMAX) isdn_ppp_release(minor - ISDN_MINOR_PPP, filep); #endif + + out: unlock_kernel(); return 0; } diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c index 4951bb29e..d33fb5135 100644 --- a/drivers/isdn/isdn_net.c +++ b/drivers/isdn/isdn_net.c @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.134 2000/06/21 09:54:29 keil Exp $ +/* $Id: isdn_net.c,v 1.135 2000/08/10 22:52:46 kai Exp $ * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -181,7 +181,7 @@ static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp) int isdn_net_force_dial_lp(isdn_net_local *); static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); -char *isdn_net_revision = "$Revision: 1.134 $"; +char *isdn_net_revision = "$Revision: 1.135 $"; /* * Code for raw-networking over ISDN diff --git a/drivers/isdn/isdn_ppp.h b/drivers/isdn/isdn_ppp.h index 20ab41046..6587cf84a 100644 --- a/drivers/isdn/isdn_ppp.h +++ b/drivers/isdn/isdn_ppp.h @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.h,v 1.16 2000/05/18 23:14:18 keil Exp $ +/* $Id: isdn_ppp.h,v 1.17 2000/08/10 22:52:46 kai Exp $ * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel). * diff --git a/drivers/isdn/pcbit/capi.c b/drivers/isdn/pcbit/capi.c index ed681f375..1a32c0825 100644 --- a/drivers/isdn/pcbit/capi.c +++ b/drivers/isdn/pcbit/capi.c @@ -304,7 +304,14 @@ int capi_tdata_req(struct pcbit_chan* chan, struct sk_buff *skb) data_len = skb->len; - skb_push(skb, 10); + if(skb_headroom(skb) < 10) + { + printk(KERN_CRIT "No headspace (%u) on headroom %p for capi header\n", skb_headroom(skb), skb); + } + else + { + skb_push(skb, 10); + } *((u16 *) (skb->data)) = chan->callref; skb->data[2] = chan->layer2link; diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c index 3c21adb9f..cd58e0d3b 100644 --- a/drivers/isdn/pcbit/drv.c +++ b/drivers/isdn/pcbit/drv.c @@ -162,7 +162,7 @@ int pcbit_init_dev(int board, int mem_base, int irq) dev->send_seq = 0; dev->unack_seq = 0; - dev->hl_hdrlen = 10; + dev->hl_hdrlen = 16; dev_if = kmalloc(sizeof(isdn_if), GFP_KERNEL); @@ -186,7 +186,7 @@ int pcbit_init_dev(int board, int mem_base, int irq) ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS ); dev_if->writebuf_skb = pcbit_xmit; - dev_if->hl_hdrlen = 10; + dev_if->hl_hdrlen = 16; dev_if->maxbufsize = MAXBUFSIZE; dev_if->command = pcbit_command; @@ -518,9 +518,6 @@ void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg, struct callb_data cbdata; int complete, err; isdn_ctrl ictl; -#ifdef DEBUG - struct msg_fmt * fmsg; -#endif switch(msg) { @@ -734,9 +731,6 @@ void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg, default: printk(KERN_DEBUG "pcbit_l3_receive: unknown message %08lx\n", msg); - fmsg = (struct msg_fmt *) &msg; - printk(KERN_DEBUG "cmd=%02x sub=%02x\n", - fmsg->cmd, fmsg->scmd); break; #endif } diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c index 36bd6f8aa..98daf7558 100644 --- a/drivers/isdn/pcbit/layer2.c +++ b/drivers/isdn/pcbit/layer2.c @@ -8,6 +8,11 @@ */ /* + * 19991203 - Fernando Carvalho - takion@superbofh.org + * Hacked to compile with egcs and run with current version of isdn modules +*/ + +/* * PCBIT-D low-layer interface */ @@ -205,7 +210,7 @@ pcbit_transmit(struct pcbit_dev *dev) /* Type 0 frame */ - struct msg_fmt *msg; + ulong msg; if (frame->skb) totlen = FRAME_HDR_LEN + PREHDR_LEN + frame->skb->len; @@ -214,7 +219,7 @@ pcbit_transmit(struct pcbit_dev *dev) flen = MIN(totlen, free); - msg = (struct msg_fmt *) &(frame->msg); + msg = frame->msg; /* * Board level 2 header @@ -222,9 +227,9 @@ pcbit_transmit(struct pcbit_dev *dev) pcbit_writew(dev, flen - FRAME_HDR_LEN); - pcbit_writeb(dev, msg->cpu); + pcbit_writeb(dev, GET_MSG_CPU(msg)); - pcbit_writeb(dev, msg->proc); + pcbit_writeb(dev, GET_MSG_PROC(msg)); /* TH */ pcbit_writew(dev, frame->hdr_len + PREHDR_LEN); @@ -244,8 +249,8 @@ pcbit_transmit(struct pcbit_dev *dev) pcbit_writew(dev, 0); /* C + S */ - pcbit_writeb(dev, msg->cmd); - pcbit_writeb(dev, msg->scmd); + pcbit_writeb(dev, GET_MSG_CMD(msg)); + pcbit_writeb(dev, GET_MSG_SCMD(msg)); /* NUM */ pcbit_writew(dev, frame->refnum); @@ -312,8 +317,7 @@ void pcbit_deliver(void *data) { struct frame_buf *frame; - unsigned long flags; - struct msg_fmt msg; + unsigned long flags, msg; struct pcbit_dev *dev = (struct pcbit_dev *) data; save_flags(flags); @@ -323,10 +327,10 @@ pcbit_deliver(void *data) dev->read_queue = frame->next; restore_flags(flags); - msg.cpu = 0; - msg.proc = 0; - msg.cmd = frame->skb->data[2]; - msg.scmd = frame->skb->data[3]; + SET_MSG_CPU(msg, 0); + SET_MSG_PROC(msg, 0); + SET_MSG_CMD(msg, frame->skb->data[2]); + SET_MSG_SCMD(msg, frame->skb->data[3]); frame->refnum = *((ushort *) frame->skb->data + 4); frame->msg = *((ulong *) & msg); diff --git a/drivers/isdn/pcbit/layer2.h b/drivers/isdn/pcbit/layer2.h index 2f56a5844..f8984f990 100644 --- a/drivers/isdn/pcbit/layer2.h +++ b/drivers/isdn/pcbit/layer2.h @@ -7,6 +7,11 @@ * the GNU Public License, incorporated herein by reference. */ +/* + * 19991203 - Fernando Carvalho - takion@superbofh.org + * Hacked to compile with egcs and run with current version of isdn modules +*/ + /* * PCBIT-D low-layer interface definitions */ @@ -84,21 +89,20 @@ Intel 1 2 3 4 */ -struct msg_fmt { -#ifdef __LITTLE_ENDIAN /* Little Endian */ - u_char scmd; - u_char cmd; - u_char proc; - u_char cpu; +#ifdef __LITTLE_ENDIAN +#define SET_MSG_SCMD(msg, ch) (msg = (msg & 0xffffff00) | (((ch) & 0xff))) +#define SET_MSG_CMD(msg, ch) (msg = (msg & 0xffff00ff) | (((ch) & 0xff) << 8)) +#define SET_MSG_PROC(msg, ch) (msg = (msg & 0xff00ffff) | (((ch) & 0xff) << 16)) +#define SET_MSG_CPU(msg, ch) (msg = (msg & 0x00ffffff) | (((ch) & 0xff) << 24)) + +#define GET_MSG_SCMD(msg) ((msg) & 0xFF) +#define GET_MSG_CMD(msg) ((msg) >> 8 & 0xFF) +#define GET_MSG_PROC(msg) ((msg) >> 16 & 0xFF) +#define GET_MSG_CPU(msg) ((msg) >> 24) + #else #error "Non-Intel CPU" - u_char cpu; - u_char proc; - u_char cmd; - u_char scmd; #endif -}; - #define MAX_QUEUED 7 @@ -107,14 +111,13 @@ struct msg_fmt { #define SET_RUN_TIMEOUT 2*HZ /* 2 seconds */ - struct frame_buf { ulong msg; - unsigned short refnum; - unsigned short dt_len; - unsigned short hdr_len; + unsigned int refnum; + unsigned int dt_len; + unsigned int hdr_len; struct sk_buff *skb; - unsigned short copied; + unsigned int copied; struct frame_buf * next; }; diff --git a/drivers/isdn/pcbit/module.c b/drivers/isdn/pcbit/module.c index 9d3aa8007..c85f68688 100644 --- a/drivers/isdn/pcbit/module.c +++ b/drivers/isdn/pcbit/module.c @@ -46,8 +46,8 @@ int pcbit_init(void) num_boards = 0; - printk(KERN_INFO - "PCBIT-D device driver v 0.5 - " + printk(KERN_NOTICE + "PCBIT-D device driver v 0.5-fjpc0 19991204 - " "Copyright (C) 1996 Universidade de Lisboa\n"); if (mem[0] || irq[0]) @@ -97,7 +97,7 @@ void cleanup_module(void) for (board = 0; board < num_boards; board++) pcbit_terminate(board); - printk(KERN_INFO + printk(KERN_NOTICE "PCBIT-D module unloaded\n"); } diff --git a/drivers/isdn/sc/timer.c b/drivers/isdn/sc/timer.c index 7cff7a727..1c355dc28 100644 --- a/drivers/isdn/sc/timer.c +++ b/drivers/isdn/sc/timer.c @@ -1,5 +1,5 @@ /* - * $Id: timer.c,v 1.2 1996/11/20 17:49:57 fritz Exp $ + * $Id: timer.c,v 1.3 2000/05/06 00:52:39 kai Exp $ * Copyright (C) 1996 SpellCaster Telecommunications Inc. * * This program is free software; you can redistribute it and/or modify |