diff options
Diffstat (limited to 'drivers/isdn')
80 files changed, 9901 insertions, 5396 deletions
diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in index df610b5b5..52e3acbdb 100644 --- a/drivers/isdn/Config.in +++ b/drivers/isdn/Config.in @@ -19,34 +19,39 @@ dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then bool 'HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO if [ "$CONFIG_HISAX_EURO" != "n" ]; then - bool 'Support for german tarifinfo' CONFIG_DE_AOC - bool 'Support for australian Microlink service (not for std. EURO)' CONFIG_HISAX_ML + bool 'Support for german chargeinfo' CONFIG_DE_AOC + bool 'Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE + bool 'Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC fi bool 'HiSax Support for german 1TR6' CONFIG_HISAX_1TR6 bool 'HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0 bool 'HiSax Support for Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3 bool 'HiSax Support for Teles 16.3c' CONFIG_HISAX_TELES3C + bool 'HiSax Support for Teles PCI' CONFIG_HISAX_TELESPCI + bool 'HiSax Support for Teles S0Box' CONFIG_HISAX_S0BOX bool 'HiSax Support for AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1 + bool 'HiSax Support for AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI + bool 'HiSax Support for AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA bool 'HiSax Support for Elsa cards' CONFIG_HISAX_ELSA bool 'HiSax Support for ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2 bool 'HiSax Support for Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA bool 'HiSax Support for ASUSCOM cards' CONFIG_HISAX_ASUSCOM bool 'HiSax Support for TELEINT cards' CONFIG_HISAX_TELEINT - bool 'HiSax Support for Sedlbauer speed card/win/star' CONFIG_HISAX_SEDLBAUER + bool 'HiSax Support for Sedlbauer speed card/win/star/fax' CONFIG_HISAX_SEDLBAUER bool 'HiSax Support for USR Sportster internal TA' CONFIG_HISAX_SPORTSTER bool 'HiSax Support for MIC card' CONFIG_HISAX_MIC bool 'HiSax Support for NETjet card' CONFIG_HISAX_NETJET bool 'HiSax Support for Niccy PnP/PCI card' CONFIG_HISAX_NICCY if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then - bool 'HiSax Support for SPARC Am7930' CONFIG_HISAX_AMD7930 - bool 'HiSax Support for SPARC DBRI' CONFIG_HISAX_DBRI + bool 'HiSax Support for Am7930' CONFIG_HISAX_AMD7930 fi fi fi if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then dep_tristate 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN dep_tristate 'IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN + dep_tristate 'Eicon.Diehl active card support (EXPERIMENTAL)' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN fi dep_tristate 'AVM-B1 with CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile index 35d56d142..36a1f5bb7 100644 --- a/drivers/isdn/Makefile +++ b/drivers/isdn/Makefile @@ -1,6 +1,6 @@ SUB_DIRS := MOD_SUB_DIRS := -ALL_SUB_DIRS := icn pcbit hisax avmb1 act2000 +ALL_SUB_DIRS := icn pcbit hisax avmb1 act2000 eicon L_OBJS := LX_OBJS := @@ -33,6 +33,7 @@ else OX_OBJS += isdn_common.o ifdef CONFIG_ISDN_PPP O_OBJS += isdn_ppp.o + M_OBJS += isdn_bsdcomp.o endif ifdef CONFIG_ISDN_X25 O_OBJS += isdn_x25iface.o @@ -114,5 +115,15 @@ else endif endif +ifeq ($(CONFIG_ISDN_DRV_EICON),y) + L_OBJS += eicon/eicon.o + SUB_DIRS += eicon + MOD_SUB_DIRS += eicon +else + ifeq ($(CONFIG_ISDN_DRV_EICON),m) + MOD_SUB_DIRS += eicon + endif +endif + include $(TOPDIR)/Rules.make diff --git a/drivers/isdn/act2000/act2000.h b/drivers/isdn/act2000/act2000.h index 129888258..5d35a12ec 100644 --- a/drivers/isdn/act2000/act2000.h +++ b/drivers/isdn/act2000/act2000.h @@ -1,8 +1,8 @@ -/* $Id: act2000.h,v 1.5 1997/10/09 22:22:59 fritz Exp $ +/* $Id: act2000.h,v 1.7 1999/04/12 13:13:54 fritz Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000. * - * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de) * Thanks to Friedemann Baitinger and IBM Germany * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: act2000.h,v $ + * Revision 1.7 1999/04/12 13:13:54 fritz + * Made cards pointer static to avoid name-clash. + * + * Revision 1.6 1998/11/05 22:12:38 fritz + * Changed mail-address. + * * Revision 1.5 1997/10/09 22:22:59 fritz * New HL<->LL interface: * New BSENT callback with nr. of bytes included. @@ -213,8 +219,6 @@ typedef struct act2000_card { char regname[35]; /* Name used for request_region */ } act2000_card; -extern act2000_card *actcards; - extern __inline__ void act2000_schedule_tx(act2000_card *card) { queue_task(&card->snd_tq, &tq_immediate); diff --git a/drivers/isdn/act2000/act2000_isa.c b/drivers/isdn/act2000/act2000_isa.c index d19ff99e4..80f06b080 100644 --- a/drivers/isdn/act2000/act2000_isa.c +++ b/drivers/isdn/act2000/act2000_isa.c @@ -1,8 +1,8 @@ -/* $Id: act2000_isa.c,v 1.5 1998/02/12 23:06:47 keil Exp $ +/* $Id: act2000_isa.c,v 1.8 1999/01/05 18:29:25 he Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version). * - * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de) * Thanks to Friedemann Baitinger and IBM Germany * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,17 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: act2000_isa.c,v $ + * Revision 1.8 1999/01/05 18:29:25 he + * merged remaining schedule_timeout() changes from 2.1.127 + * + * Revision 1.7 1998/11/05 22:12:41 fritz + * Changed mail-address. + * + * Revision 1.6 1998/06/17 19:51:09 he + * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) + * brute force fix to avoid Ugh's in isdn_tty_write() + * cleaned up some dead code + * * Revision 1.5 1998/02/12 23:06:47 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * diff --git a/drivers/isdn/act2000/act2000_isa.h b/drivers/isdn/act2000/act2000_isa.h index b7c01ee2b..35a68e7d2 100644 --- a/drivers/isdn/act2000/act2000_isa.h +++ b/drivers/isdn/act2000/act2000_isa.h @@ -1,8 +1,8 @@ -/* $Id: act2000_isa.h,v 1.1 1997/09/23 18:00:07 fritz Exp $ +/* $Id: act2000_isa.h,v 1.2 1998/11/05 22:12:43 fritz Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version). * - * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de) * Thanks to Friedemann Baitinger and IBM Germany * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: act2000_isa.h,v $ + * Revision 1.2 1998/11/05 22:12:43 fritz + * Changed mail-address. + * * Revision 1.1 1997/09/23 18:00:07 fritz * New driver for IBM Active 2000. * diff --git a/drivers/isdn/act2000/capi.c b/drivers/isdn/act2000/capi.c index d0310bcc0..df2fd68d3 100644 --- a/drivers/isdn/act2000/capi.c +++ b/drivers/isdn/act2000/capi.c @@ -1,9 +1,9 @@ -/* $Id: capi.c,v 1.7 1998/02/23 23:35:41 fritz Exp $ +/* $Id: capi.c,v 1.8 1998/11/05 22:12:46 fritz Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000. * CAPI encoder/decoder * - * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de) * Thanks to Friedemann Baitinger and IBM Germany * * This program is free software; you can redistribute it and/or modify @@ -21,6 +21,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: capi.c,v $ + * Revision 1.8 1998/11/05 22:12:46 fritz + * Changed mail-address. + * * Revision 1.7 1998/02/23 23:35:41 fritz * Eliminated some compiler warnings. * diff --git a/drivers/isdn/act2000/capi.h b/drivers/isdn/act2000/capi.h index 901f15ed4..69a104100 100644 --- a/drivers/isdn/act2000/capi.h +++ b/drivers/isdn/act2000/capi.h @@ -1,8 +1,8 @@ -/* $Id: capi.h,v 1.4 1997/10/01 09:21:04 fritz Exp $ +/* $Id: capi.h,v 1.5 1998/11/05 22:12:48 fritz Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000. * - * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de) * Thanks to Friedemann Baitinger and IBM Germany * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: capi.h,v $ + * Revision 1.5 1998/11/05 22:12:48 fritz + * Changed mail-address. + * * Revision 1.4 1997/10/01 09:21:04 fritz * Removed old compatibility stuff for 2.0.X kernels. * From now on, this code is for 2.1.X ONLY! diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c index 34a3be1d7..2ec5e2fd4 100644 --- a/drivers/isdn/act2000/module.c +++ b/drivers/isdn/act2000/module.c @@ -1,8 +1,8 @@ -/* $Id: module.c,v 1.7 1998/02/12 23:06:52 keil Exp $ +/* $Id: module.c,v 1.9 1999/04/12 13:13:56 fritz Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000. * - * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de) * Thanks to Friedemann Baitinger and IBM Germany * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: module.c,v $ + * Revision 1.9 1999/04/12 13:13:56 fritz + * Made cards pointer static to avoid name-clash. + * + * Revision 1.8 1998/11/05 22:12:51 fritz + * Changed mail-address. + * * Revision 1.7 1998/02/12 23:06:52 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -57,7 +63,7 @@ static unsigned short isa_ports[] = }; #define ISA_NRPORTS (sizeof(isa_ports)/sizeof(unsigned short)) -act2000_card *actcards = (act2000_card *) NULL; +static act2000_card *cards = (act2000_card *) NULL; /* Parameters to be set by insmod */ static int act_bus = 0; @@ -589,7 +595,7 @@ act2000_logstat(struct act2000_card *card, char *str) static inline act2000_card * act2000_findcard(int driverid) { - act2000_card *p = actcards; + act2000_card *p = cards; while (p) { if (p->myid == driverid) @@ -714,8 +720,8 @@ act2000_alloccard(int bus, int port, int irq, char *id) card->bus = bus; card->port = port; card->irq = irq; - card->next = actcards; - actcards = card; + card->next = cards; + cards = card; } /* @@ -805,9 +811,9 @@ act2000_addcard(int bus, int port, int irq, char *id) bus); } } - if (!actcards) + if (!cards) return 1; - p = actcards; + p = cards; while (p) { initialized = 0; if (!p->interface.statcallb) { @@ -870,9 +876,9 @@ act2000_addcard(int bus, int port, int irq, char *id) kfree(p); p = q->next; } else { - actcards = p->next; + cards = p->next; kfree(p); - p = actcards; + p = cards; } failed++; } @@ -890,9 +896,9 @@ int act2000_init(void) { printk(KERN_INFO "%s\n", DRIVERNAME); - if (!actcards) + if (!cards) act2000_addcard(act_bus, act_port, act_irq, act_id); - if (!actcards) + if (!cards) printk(KERN_INFO "act2000: No cards defined yet\n"); /* No symbols to export, hide all symbols */ EXPORT_NO_SYMBOLS; @@ -903,14 +909,14 @@ act2000_init(void) void cleanup_module(void) { - act2000_card *card = actcards; + act2000_card *card = cards; act2000_card *last; while (card) { unregister_card(card); del_timer(&card->ptimer); card = card->next; } - card = actcards; + card = cards; while (card) { last = card; card = card->next; diff --git a/drivers/isdn/avmb1/b1capi.c b/drivers/isdn/avmb1/b1capi.c index dbf3606f4..ea4aeb369 100644 --- a/drivers/isdn/avmb1/b1capi.c +++ b/drivers/isdn/avmb1/b1capi.c @@ -1,11 +1,49 @@ /* - * $Id: b1capi.c,v 1.10 1998/02/13 07:09:10 calle Exp $ + * $Id: b1capi.c,v 1.14 1999/04/15 19:49:29 calle Exp $ * * CAPI 2.0 Module for AVM B1-card. * * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1capi.c,v $ + * Revision 1.14 1999/04/15 19:49:29 calle + * fix fuer die B1-PCI. Jetzt geht z.B. auch IRQ 17 ... + * + * Revision 1.13 1999/01/05 18:29:31 he + * merged remaining schedule_timeout() changes from 2.1.127 + * + * Revision 1.12 1998/10/25 14:38:58 fritz + * Backported from MIPS (Cobalt). + * + * Revision 1.11 1998/03/29 16:05:58 calle + * changes from 2.0 tree merged. + * + * Revision 1.4.2.18 1998/03/20 20:34:37 calle + * port valid check now only for T1, because of the PCI and PCMCIA cards. + * + * Revision 1.4.2.17 1998/03/20 14:38:17 calle + * capidrv: prepared state machines for suspend/resume/hold + * capidrv: fix bug in state machine if B1/T1 is out of nccis + * b1capi: changed some errno returns. + * b1capi: detect if you try to add same T1 to different io address. + * b1capi: change number of nccis depending on number of channels. + * b1lli: cosmetics + * + * Revision 1.4.2.16 1998/03/20 09:01:08 calle + * Changes capi_register handling to get full support for 30 bchannels. + * + * Revision 1.4.2.15 1998/03/18 17:43:26 calle + * T1 with fastlink, bugfix for multicontroller support in capidrv.c + * + * Revision 1.4.2.14 1998/03/04 17:33:47 calle + * Changes for T1. + * + * Revision 1.4.2.13 1998/02/27 15:40:41 calle + * T1 running with slow link. bugfix in capi_release. + * + * Revision 1.4.2.12 1998/02/24 17:58:25 calle + * changes for T1. + * * Revision 1.10 1998/02/13 07:09:10 calle * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -76,7 +114,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.10 $"; +static char *revision = "$Revision: 1.14 $"; /* ------------------------------------------------------------- */ @@ -84,7 +122,7 @@ int showcapimsgs = 0; /* used in lli.c */ int loaddebug = 0; MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>"); -MODULE_PARM(showcapimsgs, "0-3i"); +MODULE_PARM(showcapimsgs, "0-5i"); MODULE_PARM(loaddebug, "0-1i"); /* ------------------------------------------------------------- */ @@ -150,10 +188,11 @@ static char *cardtype2str(int cardtype) { switch (cardtype) { default: - case AVM_CARDTYPE_B1: return "B1"; - case AVM_CARDTYPE_M1: return "M1"; - case AVM_CARDTYPE_M2: return "M2"; - case AVM_CARDTYPE_T1: return "T1"; + case AVM_CARDTYPE_B1: return "B1-ISA"; + case AVM_CARDTYPE_B1PCI: return "B1-PCI"; + case AVM_CARDTYPE_M1: return "M1"; + case AVM_CARDTYPE_M2: return "M2"; + case AVM_CARDTYPE_T1: return "T1"; } } @@ -300,7 +339,7 @@ void avmb1_handle_free_ncci(avmb1_card * card, } } APPL(appl)->releasing--; - if (APPL(appl)->releasing == 0) { + if (APPL(appl)->releasing <= 0) { APPL(appl)->signal = 0; APPL_MARK_FREE(appl); printk(KERN_INFO "b1capi: appl %d down\n", appl); @@ -433,6 +472,7 @@ static void notify_handler(void *dummy) /* -------- card ready callback ------------------------------- */ + void avmb1_card_ready(avmb1_card * card) { struct capi_profile *profp = @@ -441,6 +481,7 @@ void avmb1_card_ready(avmb1_card * card) __u16 appl; char *cardname, cname[20]; __u32 flag; + int nbchan = profp->nbchannel; card->cversion.majorversion = 2; card->cversion.minorversion = 0; @@ -453,9 +494,14 @@ void avmb1_card_ready(avmb1_card * card) for (appl = 1; appl <= CAPI_MAXAPPL; appl++) { if (VALID_APPLID(appl) && !APPL(appl)->releasing) { + int nconn, want = APPL(appl)->rparam.level3cnt; + + if (want > 0) nconn = want; + else nconn = nbchan * -want; + if (nconn == 0) nconn = nbchan; + B1_send_register(card->port, appl, - 1024 * (APPL(appl)->rparam.level3cnt+1), - APPL(appl)->rparam.level3cnt, + 1024 * (nconn+1), nconn, APPL(appl)->rparam.datablkcnt, APPL(appl)->rparam.datablklen); } @@ -553,8 +599,8 @@ int avmb1_registercard(int port, int irq, int cardtype, int allocio) SA_SHIRQ, card->name, card)) != 0) { printk(KERN_ERR "b1capi: unable to get IRQ %d (irqval=%d).\n", irq, irqval); - release_region((unsigned short) port, AVMB1_PORTLEN); - return -EIO; + release_region(port, AVMB1_PORTLEN); + return -EBUSY; } card->cardstate = CARD_DETECTED; @@ -578,8 +624,14 @@ int avmb1_detectcard(int port, int irq, int cardtype) if (!B1_valid_irq(irq, cardtype)) { printk(KERN_WARNING "b1capi: irq %d not valid for %s-card.\n", irq, cardtype2str(cardtype)); - return -EIO; + return -EINVAL; + } + if (!B1_valid_port(port, cardtype)) { + printk(KERN_WARNING "b1capi: port 0x%x not valid for %s-card.\n", + port, cardtype2str(cardtype)); + return -EINVAL; } + B1_reset(port); if ((rc = B1_detect(port, cardtype)) != 0) { printk(KERN_NOTICE "b1capi: NO %s-card at 0x%x (%d)\n", cardtype2str(cardtype), port, rc); @@ -591,10 +643,10 @@ int avmb1_detectcard(int port, int irq, int cardtype) case AVM_CARDTYPE_M1: case AVM_CARDTYPE_M2: case AVM_CARDTYPE_B1: + case AVM_CARDTYPE_B1PCI: printk(KERN_NOTICE "b1capi: AVM-%s-Controller detected at 0x%x\n", cardtype2str(cardtype), port); break; case AVM_CARDTYPE_T1: - printk(KERN_NOTICE "b1capi: AVM-%s-Controller may be at 0x%x\n", cardtype2str(cardtype), port); break; } @@ -603,11 +655,11 @@ int avmb1_detectcard(int port, int irq, int cardtype) int avmb1_probecard(int port, int irq, int cardtype) { - if (check_region((unsigned short) port, AVMB1_PORTLEN)) { + if (check_region(port, AVMB1_PORTLEN)) { printk(KERN_WARNING "b1capi: ports 0x%03x-0x%03x in use.\n", port, port + AVMB1_PORTLEN); - return -EIO; + return -EBUSY; } return avmb1_detectcard(port, irq, cardtype); } @@ -618,11 +670,16 @@ int avmb1_unregistercard(int cnr, int freeio) if (!VALID_CARD(cnr)) return -ESRCH; card = CARD(cnr); + if (card->cardstate == CARD_FREE) return -ESRCH; if (card->cardstate == CARD_RUNNING) avmb1_card_down(card, freeio); + if (card->cardstate != CARD_FREE) + if (card->cardtype == AVM_CARDTYPE_T1) + T1_reset(card->port); + free_irq(card->irq, card); if (freeio) release_region(card->port, AVMB1_PORTLEN); @@ -667,6 +724,7 @@ static int capi_installed(void) static __u16 capi_register(capi_register_params * rparam, __u16 * applidp) { + int nconn, want = rparam->level3cnt; int i; int appl; @@ -686,13 +744,20 @@ static __u16 capi_register(capi_register_params * rparam, __u16 * applidp) memcpy(&APPL(appl)->rparam, rparam, sizeof(capi_register_params)); for (i = 0; i < CAPI_MAXCONTR; i++) { + struct capi_profile *profp = + (struct capi_profile *)cards[i].version[VER_PROFILE]; + if (cards[i].cardstate != CARD_RUNNING) continue; + + if (want > 0) nconn = want; + else nconn = profp->nbchannel * -want; + if (nconn == 0) nconn = profp->nbchannel; + B1_send_register(cards[i].port, appl, - 1024 * (APPL(appl)->rparam.level3cnt + 1), - APPL(appl)->rparam.level3cnt, - APPL(appl)->rparam.datablkcnt, - APPL(appl)->rparam.datablklen); + 1024 * (nconn+1), nconn, + APPL(appl)->rparam.datablkcnt, + APPL(appl)->rparam.datablklen); } *applidp = appl; printk(KERN_INFO "b1capi: appl %d up\n", appl); @@ -705,8 +770,6 @@ static __u16 capi_release(__u16 applid) struct sk_buff *skb; int i; - if (ncards == 0) - return CAPI_REGNOTINSTALLED; if (!VALID_APPLID(applid) || APPL(applid)->releasing) return CAPI_ILLAPPNR; while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0) @@ -718,7 +781,7 @@ static __u16 capi_release(__u16 applid) APPL(applid)->releasing++; B1_send_release(cards[i].port, applid); } - if (APPL(applid)->releasing == 0) { + if (APPL(applid)->releasing <= 0) { APPL(applid)->signal = 0; APPL_MARK_FREE(applid); printk(KERN_INFO "b1capi: appl %d down\n", applid); @@ -863,7 +926,43 @@ static int capi_manufacturer(unsigned int cmd, void *data) if ((rc = avmb1_probecard(cdef.port, cdef.irq, cdef.cardtype)) != 0) return rc; - return avmb1_addcard(cdef.port, cdef.irq, cdef.cardtype); + if (cdef.cardtype == AVM_CARDTYPE_T1) { + int i; + for (i=0; i < CAPI_MAXCONTR; i++) { + if ( cards[i].cardstate != CARD_FREE + && cards[i].cardtype == AVM_CARDTYPE_T1 + && cards[i].cardnr == cdef.cardnr) { + printk(KERN_ERR + "b1capi: T1-HEMA-card-%d already at 0x%x\n", + cdef.cardnr, cards[i].port); + return -EBUSY; + } + } + rc = T1_detectandinit(cdef.port,cdef.irq,cdef.cardnr); + if (rc) { + printk(KERN_NOTICE "b1capi: NO T1-HEMA-card-%d at 0x%x (%d)\n", + cdef.cardnr, cdef.port, rc); + return -EIO; + } + printk(KERN_NOTICE "b1capi: T1-HEMA-card-%d at 0x%x\n", + cdef.cardnr, cdef.port); + } + + rc = avmb1_addcard(cdef.port, cdef.irq, cdef.cardtype); + if (rc < 0) + return rc; + /* don't want to change interface t + addcard/probecard/registercard */ + if (cdef.cardtype == AVM_CARDTYPE_T1) { + int i; + for (i=0; i < CAPI_MAXCONTR; i++) { + if (cards[i].cnr == rc) { + cards[i].cardnr = cdef.cardnr; + break; + } + } + } + return rc; case AVMB1_LOAD: case AVMB1_LOAD_AND_CONFIG: @@ -883,8 +982,7 @@ static int capi_manufacturer(unsigned int cmd, void *data) return -ESRCH; if (ldef.t4file.len <= 0) { - if (loaddebug) - printk(KERN_DEBUG "b1capi: load: invalid parameter length of t4file is %d ?\n", ldef.t4file.len); + printk(KERN_DEBUG "b1capi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len); return -EINVAL; } @@ -906,12 +1004,19 @@ static int capi_manufacturer(unsigned int cmd, void *data) } B1_reset(card->port); + + if (loaddebug) { + printk(KERN_DEBUG "b1capi: loading contr %d\n", + ldef.contr); + } + if ((rc = B1_load_t4file(card->port, &ldef.t4file))) { B1_reset(card->port); printk(KERN_ERR "b1capi: failed to load t4file!!\n"); card->cardstate = CARD_DETECTED; return rc; } + B1_disable_irq(card->port); if (ldef.t4config.len > 0) { /* load config */ @@ -944,8 +1049,7 @@ static int capi_manufacturer(unsigned int cmd, void *data) card->cardstate = CARD_INITSTATE; save_flags(flags); cli(); - B1_assign_irq(card->port, card->irq, card->cardtype); - B1_enable_irq(card->port); + B1_setinterrupt(card->port, card->irq, card->cardtype); restore_flags(flags); if (loaddebug) { @@ -956,7 +1060,14 @@ static int capi_manufacturer(unsigned int cmd, void *data) /* * init card */ - B1_send_init(card->port, AVM_NAPPS, AVM_NNCCI, card->cnr - 1); + if (card->cardtype == AVM_CARDTYPE_T1) + B1_send_init(card->port, AVM_NAPPS, + AVM_NNCCI_PER_CHANNEL*30, + card->cnr - 1); + else + B1_send_init(card->port, AVM_NAPPS, + AVM_NNCCI_PER_CHANNEL*2, + card->cnr - 1); if (loaddebug) { printk(KERN_DEBUG "b1capi: load: waiting for init reply contr %d\n", @@ -998,6 +1109,19 @@ static int capi_manufacturer(unsigned int cmd, void *data) return rc; return 0; + case AVMB1_REMOVECARD: + if ((rc = copy_from_user((void *) &rdef, data, + sizeof(avmb1_resetdef)))) + return rc; + if (!VALID_CARD(rdef.contr)) + return -ESRCH; + + card = CARD(rdef.contr); + + if (card->cardstate != CARD_DETECTED) + return -EBUSY; + + return avmb1_unregistercard(rdef.contr, 1); } return -EINVAL; } @@ -1035,6 +1159,7 @@ struct capi_interface *attach_capi_interface(struct capi_interface_user *userp) userp->next = capi_users; capi_users = userp; MOD_INC_USE_COUNT; + printk(KERN_NOTICE "b1capi: %s attached\n", userp->name); return &avmb1_interface; } @@ -1048,6 +1173,7 @@ int detach_capi_interface(struct capi_interface_user *userp) *pp = userp->next; userp->next = 0; MOD_DEC_USE_COUNT; + printk(KERN_NOTICE "b1capi: %s detached\n", userp->name); return 0; } } diff --git a/drivers/isdn/avmb1/b1lli.c b/drivers/isdn/avmb1/b1lli.c index db6fe1453..4d9fd647c 100644 --- a/drivers/isdn/avmb1/b1lli.c +++ b/drivers/isdn/avmb1/b1lli.c @@ -1,11 +1,46 @@ /* - * $Id: b1lli.c,v 1.6 1998/02/13 07:09:11 calle Exp $ + * $Id: b1lli.c,v 1.10 1999/04/15 19:49:31 calle Exp $ * * ISDN lowlevel-module for AVM B1-card. * * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1lli.c,v $ + * Revision 1.10 1999/04/15 19:49:31 calle + * fix fuer die B1-PCI. Jetzt geht z.B. auch IRQ 17 ... + * + * Revision 1.9 1999/01/05 18:33:23 he + * merged remaining 2.2pre{1,2} changes (jiffies and Config) + * + * Revision 1.8 1998/10/25 14:39:00 fritz + * Backported from MIPS (Cobalt). + * + * Revision 1.7 1998/03/29 16:06:00 calle + * changes from 2.0 tree merged. + * + * Revision 1.1.2.10 1998/03/20 20:34:41 calle + * port valid check now only for T1, because of the PCI and PCMCIA cards. + * + * Revision 1.1.2.9 1998/03/20 14:38:20 calle + * capidrv: prepared state machines for suspend/resume/hold + * capidrv: fix bug in state machine if B1/T1 is out of nccis + * b1capi: changed some errno returns. + * b1capi: detect if you try to add same T1 to different io address. + * b1capi: change number of nccis depending on number of channels. + * b1lli: cosmetics + * + * Revision 1.1.2.8 1998/03/18 17:43:29 calle + * T1 with fastlink, bugfix for multicontroller support in capidrv.c + * + * Revision 1.1.2.7 1998/03/04 17:33:50 calle + * Changes for T1. + * + * Revision 1.1.2.6 1998/02/27 15:40:44 calle + * T1 running with slow link. bugfix in capi_release. + * + * Revision 1.1.2.5 1998/02/13 16:28:28 calle + * first step for T1 + * * Revision 1.6 1998/02/13 07:09:11 calle * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -41,6 +76,7 @@ * * */ +/* #define FASTLINK_DEBUG */ #include <linux/kernel.h> #include <linux/skbuff.h> @@ -55,6 +91,8 @@ #include "capicmd.h" #include "capiutil.h" +extern int showcapimsgs; + /* * LLI Messages to the ISDN-ControllerISDN Controller */ @@ -93,6 +131,8 @@ #define SEND_CONFIG 0x21 /* */ +#define SEND_POLLACK 0x73 /* T1 Watchdog */ + /* * LLI Messages from the ISDN-ControllerISDN Controller */ @@ -136,6 +176,10 @@ #define RECEIVE_RELEASE 0x26 /* * int32 AppllID int32 0xffffffff */ +#define RECEIVE_TASK_READY 0x31 /* + * int32 tasknr + * int32 Length Taskname ... + */ #define WRITE_REGISTER 0x00 #define READ_REGISTER 0x01 @@ -150,14 +194,48 @@ #define B1_OUTSTAT 0x03 #define B1_RESET 0x10 #define B1_ANALYSE 0x04 -#define B1_IDENT 0x17 /* Hema card T1 */ -#define B1_IRQ_MASTER 0x12 /* Hema card T1 */ + +/* Hema card T1 */ + +#define T1_FASTLINK 0x00 +#define T1_SLOWLINK 0x08 + +#define T1_READ B1_READ +#define T1_WRITE B1_WRITE +#define T1_INSTAT B1_INSTAT +#define T1_OUTSTAT B1_OUTSTAT +#define T1_IRQENABLE 0x05 +#define T1_FIFOSTAT 0x06 +#define T1_RESETLINK 0x10 +#define T1_ANALYSE 0x11 +#define T1_IRQMASTER 0x12 +#define T1_IDENT 0x17 +#define T1_RESETBOARD 0x1f + +#define T1F_IREADY 0x01 +#define T1F_IHALF 0x02 +#define T1F_IFULL 0x04 +#define T1F_IEMPTY 0x08 +#define T1F_IFLAGS 0xF0 + +#define T1F_OREADY 0x10 +#define T1F_OHALF 0x20 +#define T1F_OEMPTY 0x40 +#define T1F_OFULL 0x80 +#define T1F_OFLAGS 0xF0 + +/* there are HEMA cards with 1k and 4k FIFO out */ +#define FIFO_OUTBSIZE 256 +#define FIFO_INPBSIZE 512 + +#define HEMA_VERSION_ID 0 +#define HEMA_PAL_ID 0 #define B1_STAT0(cardtype) ((cardtype) == AVM_CARDTYPE_M1 ? 0x81200000l : 0x80A00000l) #define B1_STAT1(cardtype) (0x80E00000l) -static inline unsigned char b1outp(unsigned short base, +static inline unsigned char b1outp(unsigned int base, unsigned short offset, unsigned char value) { @@ -165,22 +243,44 @@ static inline unsigned char b1outp(unsigned short base, return inb(base + B1_ANALYSE); } -static inline int B1_rx_full(unsigned short base) +static inline void t1outp(unsigned int base, + unsigned short offset, + unsigned char value) +{ + outb(value, base + offset); +} + +static inline unsigned char t1inp(unsigned int base, + unsigned short offset) +{ + return inb(base + offset); +} + +static inline int B1_isfastlink(unsigned int base) +{ + return (inb(base + T1_IDENT) & ~0x82) == 1; +} +static inline unsigned char B1_fifostatus(unsigned int base) +{ + return inb(base + T1_FIFOSTAT); +} + +static inline int B1_rx_full(unsigned int base) { return inb(base + B1_INSTAT) & 0x1; } -static inline unsigned char B1_get_byte(unsigned short base) +static inline unsigned char B1_get_byte(unsigned int base) { - unsigned long i = jiffies + 5 * HZ; /* maximum wait time 5 sec */ + unsigned long i = jiffies + 1 * HZ; /* maximum wait time 1 sec */ while (!B1_rx_full(base) && time_before(jiffies, i)); if (B1_rx_full(base)) return inb(base + B1_READ); - printk(KERN_CRIT "b1lli: rx not full after 5 second\n"); + printk(KERN_CRIT "b1lli(0x%x): rx not full after 1 second\n", base); return 0; } -static inline unsigned int B1_get_word(unsigned short base) +static inline unsigned int B1_get_word(unsigned int base) { unsigned int val = 0; val |= B1_get_byte(base); @@ -190,18 +290,18 @@ static inline unsigned int B1_get_word(unsigned short base) return val; } -static inline int B1_tx_empty(unsigned short base) +static inline int B1_tx_empty(unsigned int base) { return inb(base + B1_OUTSTAT) & 0x1; } -static inline void B1_put_byte(unsigned short base, unsigned char val) +static inline void B1_put_byte(unsigned int base, unsigned char val) { while (!B1_tx_empty(base)); b1outp(base, B1_WRITE, val); } -static inline void B1_put_word(unsigned short base, unsigned int val) +static inline void B1_put_word(unsigned int base, unsigned int val) { B1_put_byte(base, val & 0xff); B1_put_byte(base, (val >> 8) & 0xff); @@ -209,26 +309,95 @@ static inline void B1_put_word(unsigned short base, unsigned int val) B1_put_byte(base, (val >> 24) & 0xff); } -static inline unsigned int B1_get_slice(unsigned short base, +static inline unsigned int B1_get_slice(unsigned int base, unsigned char *dp) { unsigned int len, i; +#ifdef FASTLINK_DEBUG + unsigned wcnt = 0, bcnt = 0; +#endif len = i = B1_get_word(base); - while (i-- > 0) - *dp++ = B1_get_byte(base); + if (B1_isfastlink(base)) { + int status; + while (i > 0) { + status = B1_fifostatus(base) & (T1F_IREADY|T1F_IHALF); + if (i >= FIFO_INPBSIZE) status |= T1F_IFULL; + + switch (status) { + case T1F_IREADY|T1F_IHALF|T1F_IFULL: + insb(base+B1_READ, dp, FIFO_INPBSIZE); + dp += FIFO_INPBSIZE; + i -= FIFO_INPBSIZE; +#ifdef FASTLINK_DEBUG + wcnt += FIFO_INPBSIZE; +#endif + break; + case T1F_IREADY|T1F_IHALF: + insb(base+B1_READ,dp, i); +#ifdef FASTLINK_DEBUG + wcnt += i; +#endif + dp += i; + i = 0; + if (i == 0) + break; + /* fall through */ + default: + *dp++ = B1_get_byte(base); + i--; +#ifdef FASTLINK_DEBUG + bcnt++; +#endif + break; + } + } +#ifdef FASTLINK_DEBUG + if (wcnt) + printk(KERN_DEBUG "b1lli(0x%x): get_slice l=%d w=%d b=%d\n", + base, len, wcnt, bcnt); +#endif + } else { + while (i-- > 0) + *dp++ = B1_get_byte(base); + } return len; } -static inline void B1_put_slice(unsigned short base, +static inline void B1_put_slice(unsigned int base, unsigned char *dp, unsigned int len) { - B1_put_word(base, len); - while (len-- > 0) - B1_put_byte(base, *dp++); + unsigned i = len; + B1_put_word(base, i); + if (B1_isfastlink(base)) { + int status; + while (i > 0) { + status = B1_fifostatus(base) & (T1F_OREADY|T1F_OHALF); + if (i >= FIFO_OUTBSIZE) status |= T1F_OEMPTY; + switch (status) { + case T1F_OREADY|T1F_OHALF|T1F_OEMPTY: + outsb(base+B1_WRITE, dp, FIFO_OUTBSIZE); + dp += FIFO_OUTBSIZE; + i -= FIFO_OUTBSIZE; + break; + case T1F_OREADY|T1F_OHALF: + outsb(base+B1_WRITE, dp, i); + dp += i; + i = 0; + break; + default: + B1_put_byte(base, *dp++); + i--; + break; + } + } + } else { + while (i-- > 0) + B1_put_byte(base, *dp++); + } } -static void b1_wr_reg(unsigned short base, +static void b1_wr_reg(unsigned int base, unsigned int reg, unsigned int value) { @@ -237,7 +406,7 @@ static void b1_wr_reg(unsigned short base, B1_put_word(base, value); } -static inline unsigned int b1_rd_reg(unsigned short base, +static inline unsigned int b1_rd_reg(unsigned int base, unsigned int reg) { B1_put_byte(base, READ_REGISTER); @@ -246,14 +415,14 @@ static inline unsigned int b1_rd_reg(unsigned short base, } -static inline void b1_set_test_bit(unsigned short base, +static inline void b1_set_test_bit(unsigned int base, int cardtype, int onoff) { b1_wr_reg(base, B1_STAT0(cardtype), onoff ? 0x21 : 0x20); } -static inline int b1_get_test_bit(unsigned short base, +static inline int b1_get_test_bit(unsigned int base, int cardtype) { return (b1_rd_reg(base, B1_STAT0(cardtype)) & 0x01) != 0; @@ -278,6 +447,26 @@ static int irq_table[16] = 112, /* irq 15 */ }; +static int hema_irq_table[16] = +{0, + 0, + 0, + 0x80, /* irq 3 */ + 0, + 0x90, /* irq 5 */ + 0, + 0xA0, /* irq 7 */ + 0, + 0xB0, /* irq 9 */ + 0xC0, /* irq 10 */ + 0xD0, /* irq 11 */ + 0xE0, /* irq 12 */ + 0, + 0, + 0xF0, /* irq 15 */ +}; + + int B1_valid_irq(unsigned irq, int cardtype) { switch (cardtype) { @@ -285,36 +474,76 @@ int B1_valid_irq(unsigned irq, int cardtype) case AVM_CARDTYPE_M1: case AVM_CARDTYPE_M2: case AVM_CARDTYPE_B1: - return irq_table[irq] != 0; + return irq_table[irq & 0xf] != 0; case AVM_CARDTYPE_T1: - return irq == 5; + return hema_irq_table[irq & 0xf] != 0; + case AVM_CARDTYPE_B1PCI: + return 1; } } -unsigned char B1_assign_irq(unsigned short base, unsigned irq, int cardtype) +int B1_valid_port(unsigned port, int cardtype) +{ + switch (cardtype) { + default: + case AVM_CARDTYPE_M1: + case AVM_CARDTYPE_M2: + case AVM_CARDTYPE_B1: +#if 0 /* problem with PCMCIA and PCI cards */ + switch (port) { + case 0x150: + case 0x250: + case 0x300: + case 0x340: + return 1; + } + return 0; +#else + return 1; +#endif + case AVM_CARDTYPE_B1PCI: + return 1; + case AVM_CARDTYPE_T1: + return ((port & 0x7) == 0) && ((port & 0x30) != 0x30); + } +} + +void B1_setinterrupt(unsigned int base, + unsigned irq, int cardtype) { switch (cardtype) { case AVM_CARDTYPE_T1: - return b1outp(base, B1_IRQ_MASTER, 0x08); + t1outp(base, B1_INSTAT, 0x00); + t1outp(base, B1_INSTAT, 0x02); + t1outp(base, T1_IRQMASTER, 0x08); + break; default: case AVM_CARDTYPE_M1: case AVM_CARDTYPE_M2: case AVM_CARDTYPE_B1: - return b1outp(base, B1_RESET, irq_table[irq]); + b1outp(base, B1_INSTAT, 0x00); + b1outp(base, B1_RESET, irq_table[irq]); + b1outp(base, B1_INSTAT, 0x02); + break; + case AVM_CARDTYPE_B1PCI: + b1outp(base, B1_INSTAT, 0x00); + b1outp(base, B1_RESET, 0xf0); + b1outp(base, B1_INSTAT, 0x02); + break; } } -unsigned char B1_enable_irq(unsigned short base) +unsigned char B1_disable_irq(unsigned int base) { - return b1outp(base, B1_INSTAT, 0x02); + return b1outp(base, B1_INSTAT, 0x00); } -unsigned char B1_disable_irq(unsigned short base) +void T1_disable_irq(unsigned int base) { - return b1outp(base, B1_INSTAT, 0x00); + t1outp(base, T1_IRQMASTER, 0x00); } -void B1_reset(unsigned short base) +void B1_reset(unsigned int base) { b1outp(base, B1_RESET, 0); udelay(55 * 2 * 1000); /* 2 TIC's */ @@ -326,7 +555,19 @@ void B1_reset(unsigned short base) udelay(55 * 2 * 1000); /* 2 TIC's */ } -int B1_detect(unsigned short base, int cardtype) +void T1_reset(unsigned int base) +{ + /* reset T1 Controller */ + B1_reset(base); + /* disable irq on HEMA */ + t1outp(base, B1_INSTAT, 0x00); + t1outp(base, B1_OUTSTAT, 0x00); + t1outp(base, T1_IRQMASTER, 0x00); + /* reset HEMA board configuration */ + t1outp(base, T1_RESETBOARD, 0xf); +} + +int B1_detect(unsigned int base, int cardtype) { int onoff, i; @@ -372,10 +613,79 @@ int B1_detect(unsigned short base, int cardtype) return 0; } +int T1_detectandinit(unsigned int base, unsigned irq, int cardnr) +{ + unsigned char cregs[8]; + unsigned char reverse_cardnr; + unsigned long flags; + unsigned char dummy; + int i; + + reverse_cardnr = ((cardnr & 0x01) << 3) | ((cardnr & 0x02) << 1) + | ((cardnr & 0x04) >> 1) | ((cardnr & 0x08) >> 3); + cregs[0] = (HEMA_VERSION_ID << 4) | (reverse_cardnr & 0xf); + cregs[1] = 0x00; /* fast & slow link connected to CON1 */ + cregs[2] = 0x05; /* fast link 20MBit, slow link 20 MBit */ + cregs[3] = 0; + cregs[4] = 0x11; /* zero wait state */ + cregs[5] = hema_irq_table[irq & 0xf]; + cregs[6] = 0; + cregs[7] = 0; + + save_flags(flags); + cli(); + /* board reset */ + t1outp(base, T1_RESETBOARD, 0xf); + udelay(100 * 1000); + dummy = t1inp(base, T1_FASTLINK+T1_OUTSTAT); /* first read */ + + /* write config */ + dummy = (base >> 4) & 0xff; + for (i=1;i<=0xf;i++) t1outp(base, i, dummy); + t1outp(base, HEMA_PAL_ID & 0xf, dummy); + t1outp(base, HEMA_PAL_ID >> 4, cregs[0]); + for(i=1;i<7;i++) t1outp(base, 0, cregs[i]); + t1outp(base, ((base >> 4)) & 0x3, cregs[7]); + restore_flags(flags); + + udelay(100 * 1000); + t1outp(base, T1_FASTLINK+T1_RESETLINK, 0); + t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0); + udelay(10 * 1000); + t1outp(base, T1_FASTLINK+T1_RESETLINK, 1); + t1outp(base, T1_SLOWLINK+T1_RESETLINK, 1); + udelay(100 * 1000); + t1outp(base, T1_FASTLINK+T1_RESETLINK, 0); + t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0); + udelay(10 * 1000); + t1outp(base, T1_FASTLINK+T1_ANALYSE, 0); + udelay(5 * 1000); + t1outp(base, T1_SLOWLINK+T1_ANALYSE, 0); + + if (t1inp(base, T1_FASTLINK+T1_OUTSTAT) != 0x1) /* tx empty */ + return 1; + if (t1inp(base, T1_FASTLINK+T1_INSTAT) != 0x0) /* rx empty */ + return 2; + if (t1inp(base, T1_FASTLINK+T1_IRQENABLE) != 0x0) + return 3; + if ((t1inp(base, T1_FASTLINK+T1_FIFOSTAT) & 0xf0) != 0x70) + return 4; + if ((t1inp(base, T1_FASTLINK+T1_IRQMASTER) & 0x0e) != 0) + return 5; + if ((t1inp(base, T1_FASTLINK+T1_IDENT) & 0x7d) != 1) + return 6; + if (t1inp(base, T1_SLOWLINK+T1_OUTSTAT) != 0x1) /* tx empty */ + return 7; + if ((t1inp(base, T1_SLOWLINK+T1_IRQMASTER) & 0x0e) != 0) + return 8; + if ((t1inp(base, T1_SLOWLINK+T1_IDENT) & 0x7d) != 0) + return 9; + return 0; +} extern int loaddebug; -int B1_load_t4file(unsigned short base, avmb1_t4file * t4file) +int B1_load_t4file(unsigned int base, avmb1_t4file * t4file) { /* * Data is in user space !!! @@ -414,7 +724,7 @@ int B1_load_t4file(unsigned short base, avmb1_t4file * t4file) return 0; } -int B1_load_config(unsigned short base, avmb1_t4file * config) +int B1_load_config(unsigned int base, avmb1_t4file * config) { /* * Data is in user space !!! @@ -470,7 +780,7 @@ int B1_load_config(unsigned short base, avmb1_t4file * config) return 0; } -int B1_loaded(unsigned short base) +int B1_loaded(unsigned int base) { int i; unsigned char ans; @@ -482,7 +792,7 @@ int B1_loaded(unsigned short base) break; } if (!B1_tx_empty(base)) { - printk(KERN_ERR "b1lli: B1_loaded: timeout tx\n"); + printk(KERN_ERR "b1lli(0x%x): B1_loaded: timeout tx\n", base); return 0; } B1_put_byte(base, SEND_POLL); @@ -494,11 +804,12 @@ int B1_loaded(unsigned short base) printk(KERN_DEBUG "b1capi: loaded: ok\n"); return 1; } - printk(KERN_ERR "b1lli: B1_loaded: got 0x%x ???\n", ans); + printk(KERN_ERR "b1lli(0x%x): B1_loaded: got 0x%x ???\n", + base, ans); return 0; } } - printk(KERN_ERR "b1lli: B1_loaded: timeout rx\n"); + printk(KERN_ERR "b1lli(0x%x): B1_loaded: timeout rx\n", base); return 0; } @@ -519,7 +830,7 @@ static inline void parse_version(avmb1_card * card) * ------------------------------------------------------------------- */ -void B1_send_init(unsigned short port, +void B1_send_init(unsigned int port, unsigned int napps, unsigned int nncci, unsigned int cardnr) { unsigned long flags; @@ -533,7 +844,7 @@ void B1_send_init(unsigned short port, restore_flags(flags); } -void B1_send_register(unsigned short port, +void B1_send_register(unsigned int port, __u16 appid, __u32 nmsg, __u32 nb3conn, __u32 nb3blocks, __u32 b3bsize) { @@ -550,7 +861,7 @@ void B1_send_register(unsigned short port, restore_flags(flags); } -void B1_send_release(unsigned short port, +void B1_send_release(unsigned int port, __u16 appid) { unsigned long flags; @@ -562,9 +873,7 @@ void B1_send_release(unsigned short port, restore_flags(flags); } -extern int showcapimsgs; - -void B1_send_message(unsigned short port, struct sk_buff *skb) +void B1_send_message(unsigned int port, struct sk_buff *skb) { unsigned long flags; __u16 len = CAPIMSG_LEN(skb->data); @@ -630,6 +939,7 @@ void B1_handle_interrupt(avmb1_card * card) unsigned NCCI; unsigned WindowSize; +t1retry: if (!B1_rx_full(card->port)) return; @@ -704,7 +1014,7 @@ void B1_handle_interrupt(avmb1_card * card) WindowSize = B1_get_word(card->port); if (showcapimsgs) - printk(KERN_DEBUG "b1lli: NEW_NCCI app %u ncci 0x%x\n", ApplId, NCCI); + printk(KERN_DEBUG "b1lli(0x%x): NEW_NCCI app %u ncci 0x%x\n", card->port, ApplId, NCCI); avmb1_handle_new_ncci(card, ApplId, NCCI, WindowSize); @@ -716,19 +1026,23 @@ void B1_handle_interrupt(avmb1_card * card) NCCI = B1_get_word(card->port); if (showcapimsgs) - printk(KERN_DEBUG "b1lli: FREE_NCCI app %u ncci 0x%x\n", ApplId, NCCI); + printk(KERN_DEBUG "b1lli(0x%x): FREE_NCCI app %u ncci 0x%x\n", card->port, ApplId, NCCI); avmb1_handle_free_ncci(card, ApplId, NCCI); break; case RECEIVE_START: + if (card->cardtype == AVM_CARDTYPE_T1) { + B1_put_byte(card->port, SEND_POLLACK); + /* printk(KERN_DEBUG "b1lli: T1 watchdog\n"); */ + } if (card->blocked) - printk(KERN_DEBUG "b1lli: RESTART\n"); + printk(KERN_DEBUG "b1lli(0x%x): RESTART\n", card->port); card->blocked = 0; break; case RECEIVE_STOP: - printk(KERN_DEBUG "b1lli: STOP\n"); + printk(KERN_DEBUG "b1lli(0x%x): STOP\n", card->port); card->blocked = 1; break; @@ -737,13 +1051,24 @@ void B1_handle_interrupt(avmb1_card * card) card->versionlen = B1_get_slice(card->port, card->versionbuf); card->cardstate = CARD_ACTIVE; parse_version(card); - printk(KERN_INFO "b1lli: %s-card (%s) now active\n", + printk(KERN_INFO "b1lli(0x%x): %s-card (%s) now active\n", + card->port, card->version[VER_CARDTYPE], card->version[VER_DRIVER]); avmb1_card_ready(card); break; + case RECEIVE_TASK_READY: + ApplId = (unsigned) B1_get_word(card->port); + MsgLen = B1_get_slice(card->port, card->msgbuf); + card->msgbuf[MsgLen] = 0; + printk(KERN_INFO "b1lli(0x%x): Task %d \"%s\" ready.\n", + card->port, ApplId, card->msgbuf); + break; default: - printk(KERN_ERR "b1lli: B1_handle_interrupt: 0x%x ???\n", b1cmd); + printk(KERN_ERR "b1lli(0x%x): B1_handle_interrupt: 0x%x ???\n", + card->port, b1cmd); break; } + if (card->cardtype == AVM_CARDTYPE_T1) + goto t1retry; } diff --git a/drivers/isdn/avmb1/b1pci.c b/drivers/isdn/avmb1/b1pci.c index b5c45acfd..112ddbb81 100644 --- a/drivers/isdn/avmb1/b1pci.c +++ b/drivers/isdn/avmb1/b1pci.c @@ -1,11 +1,29 @@ /* - * $Id: b1pci.c,v 1.5 1998/01/31 11:14:43 calle Exp $ + * $Id: b1pci.c,v 1.9 1999/04/15 19:49:32 calle Exp $ * * Module for AVM B1 PCI-card. * * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1pci.c,v $ + * Revision 1.9 1999/04/15 19:49:32 calle + * fix fuer die B1-PCI. Jetzt geht z.B. auch IRQ 17 ... + * + * Revision 1.8 1998/06/17 19:51:16 he + * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) + * brute force fix to avoid Ugh's in isdn_tty_write() + * cleaned up some dead code + * + * Revision 1.7 1998/03/29 16:06:02 calle + * changes from 2.0 tree merged. + * + * Revision 1.2.2.2 1998/01/23 16:49:30 calle + * added functions for pcmcia cards, + * avmb1_addcard returns now the controller number. + * + * Revision 1.6 1998/02/25 09:15:36 fritz + * apply Martin's pci driver patch to isdn drivers (vgerCVS) + * * Revision 1.5 1998/01/31 11:14:43 calle * merged changes to 2.0 tree, prepare 2.1.82 to work. * @@ -28,6 +46,7 @@ */ #include <linux/config.h> +#include <linux/string.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/pci.h> @@ -44,7 +63,7 @@ #define PCI_DEVICE_ID_AVM_B1 0x700 #endif -static char *revision = "$Revision: 1.5 $"; +static char *revision = "$Revision: 1.9 $"; /* ------------------------------------------------------------- */ @@ -93,13 +112,13 @@ int b1pci_init(void) printk(KERN_INFO "b1pci: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n", ioaddr, irq); - if ((rc = avmb1_probecard(ioaddr, irq, AVM_CARDTYPE_B1)) != 0) { + if ((rc = avmb1_probecard(ioaddr, irq, AVM_CARDTYPE_B1PCI)) != 0) { printk(KERN_ERR "b1pci: no AVM-B1 at i/o %#x, irq %d detected\n", ioaddr, irq); return rc; } - if ((rc = avmb1_addcard(ioaddr, irq, AVM_CARDTYPE_B1)) < 0) + if ((rc = avmb1_addcard(ioaddr, irq, AVM_CARDTYPE_B1PCI)) < 0) return rc; } return 0; diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c index f4f5c7039..69ed317f3 100644 --- a/drivers/isdn/avmb1/capi.c +++ b/drivers/isdn/avmb1/capi.c @@ -1,11 +1,23 @@ /* - * $Id: capi.c,v 1.10 1998/02/13 07:09:13 calle Exp $ + * $Id: capi.c,v 1.13 1998/08/28 04:32:25 calle Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capi.c,v $ + * Revision 1.13 1998/08/28 04:32:25 calle + * Added patch send by Michael.Mueller4@post.rwth-aachen.de, to get AVM B1 + * driver running with 2.1.118. + * + * Revision 1.12 1998/05/26 22:39:34 he + * sync'ed with 2.1.102 where appropriate (CAPABILITY changes) + * concap typo + * cleared dev.tbusy in isdn_net BCONN status callback + * + * Revision 1.11 1998/03/09 17:46:37 he + * merged in 2.1.89 changes + * * Revision 1.10 1998/02/13 07:09:13 calle * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -237,6 +249,9 @@ capi_poll(struct file *file, poll_table * wait) return POLLERR; cdev = &capidevs[minor]; +#if (LINUX_VERSION_CODE < 0x020159) /* 2.1.89 */ +#define poll_wait(f,wq,w) poll_wait((wq),(w)) +#endif poll_wait(file, &(cdev->recv_wait), wait); mask = POLLOUT | POLLWRNORM; if (!skb_queue_empty(&cdev->recv_queue)) @@ -464,7 +479,9 @@ static struct file_operations capi_fops = capi_ioctl, NULL, /* capi_mmap */ capi_open, - NULL, /* flush */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,118) + NULL, /* capi_flush */ +#endif capi_release, NULL, /* capi_fsync */ NULL, /* capi_fasync */ @@ -484,7 +501,16 @@ static struct capi_interface_user cuser = { int capi_init(void) { +#if LINUX_VERSION_CODE >= 131841 + int j; +#endif + memset(capidevs, 0, sizeof(capidevs)); +#if LINUX_VERSION_CODE >= 131841 + for ( j = 0; j < CAPI_MAXMINOR+1; j++ ) { + init_waitqueue_head(&capidevs[j].recv_wait); + } +#endif if (register_chrdev(capi_major, "capi20", &capi_fops)) { printk(KERN_ERR "capi20: unable to get major %d\n", capi_major); @@ -496,6 +522,7 @@ int capi_init(void) unregister_chrdev(capi_major, "capi20"); return -EIO; } + return 0; } diff --git a/drivers/isdn/avmb1/capidev.h b/drivers/isdn/avmb1/capidev.h index f2e0d6d2d..bd57255b6 100644 --- a/drivers/isdn/avmb1/capidev.h +++ b/drivers/isdn/avmb1/capidev.h @@ -22,7 +22,11 @@ struct capidev { int is_registered; __u16 applid; struct sk_buff_head recv_queue; +#if LINUX_VERSION_CODE < 131841 struct wait_queue *recv_wait; +#else + wait_queue_head_t recv_wait; +#endif __u16 errcode; }; diff --git a/drivers/isdn/avmb1/capidrv.c b/drivers/isdn/avmb1/capidrv.c index 1d4a7c2e8..7eb0c33cf 100644 --- a/drivers/isdn/avmb1/capidrv.c +++ b/drivers/isdn/avmb1/capidrv.c @@ -1,11 +1,36 @@ /* - * $Id: capidrv.c,v 1.11 1998/02/13 07:09:15 calle Exp $ + * $Id: capidrv.c,v 1.13 1998/06/26 15:12:55 fritz Exp $ * * ISDN4Linux Driver, using capi20 interface (kernelcapi) * * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capidrv.c,v $ + * Revision 1.13 1998/06/26 15:12:55 fritz + * Added handling of STAT_ICALL with incomplete CPN. + * Added AT&L for ttyI emulator. + * Added more locking stuff in tty_write. + * + * Revision 1.12 1998/03/29 16:06:03 calle + * changes from 2.0 tree merged. + * + * Revision 1.3.2.10 1998/03/20 14:38:24 calle + * capidrv: prepared state machines for suspend/resume/hold + * capidrv: fix bug in state machine if B1/T1 is out of nccis + * b1capi: changed some errno returns. + * b1capi: detect if you try to add same T1 to different io address. + * b1capi: change number of nccis depending on number of channels. + * b1lli: cosmetics + * + * Revision 1.3.2.9 1998/03/20 09:01:12 calle + * Changes capi_register handling to get full support for 30 bchannels. + * + * Revision 1.3.2.8 1998/03/18 17:51:28 calle + * added controller number to error messages + * + * Revision 1.3.2.7 1998/02/27 15:40:47 calle + * T1 running with slow link. bugfix in capi_release. + * * Revision 1.11 1998/02/13 07:09:15 calle * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -79,7 +104,7 @@ #include "capicmd.h" #include "capidrv.h" -static char *revision = "$Revision: 1.11 $"; +static char *revision = "$Revision: 1.13 $"; int debugmode = 0; MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>"); @@ -378,8 +403,8 @@ static void free_plci(capidrv_contr * card, capidrv_plci * plcip) return; } } - printk(KERN_ERR "capidrv: free_plci %p (0x%x) not found, Huh?\n", - plcip, plcip->plci); + printk(KERN_ERR "capidrv-%d: free_plci %p (0x%x) not found, Huh?\n", + card->contrnr, plcip, plcip->plci); } /* -------- ncci management ------------------------------------------ */ @@ -512,15 +537,15 @@ struct listenstatechange { static struct listenstatechange listentable[] = { - {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ}, - {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ}, - {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR}, - {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR}, - {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, - {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, - {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, - {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, - {}, + {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ}, + {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ}, + {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR}, + {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR}, + {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, + {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, + {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, + {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, + {}, }; static void listen_change_state(capidrv_contr * card, int event) @@ -529,15 +554,15 @@ static void listen_change_state(capidrv_contr * card, int event) while (p->event) { if (card->state == p->actstate && p->event == event) { if (debugmode) - printk(KERN_DEBUG "capidrv: listen_change_state %d -> %d\n", - card->state, p->nextstate); + printk(KERN_DEBUG "capidrv-%d: listen_change_state %d -> %d\n", + card->contrnr, card->state, p->nextstate); card->state = p->nextstate; return; } p++; } - printk(KERN_ERR "capidrv: listen_change_state state=%d event=%d ????\n", - card->state, event); + printk(KERN_ERR "capidrv-%d: listen_change_state state=%d event=%d ????\n", + card->contrnr, card->state, event); } @@ -567,46 +592,57 @@ struct plcistatechange { static struct plcistatechange plcitable[] = { /* P-0 */ - {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, 0}, - {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, 0}, - {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, 0}, + {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, 0}, + {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, 0}, + {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, 0}, + {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, 0}, /* P-0.1 */ - {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0}, - {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, 0}, - {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, - {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0}, + {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, 0}, + {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, /* P-1 */ - {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0}, - {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, -{ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, - {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0}, + {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, /* P-ACT */ - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, 0}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, 0}, /* P-2 */ - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0}, - {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, 0}, - {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, 0}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0}, + {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, 0}, + {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, 0}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, 0}, /* P-3 */ -{ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0}, -{ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, 0}, -{ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0}, + {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, 0}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, /* P-4 */ - {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0}, - {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, -{ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, - {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0}, + {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, /* P-5 */ -{ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, /* P-6 */ - {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0}, - {}, + {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0}, + /* P-0.Res */ + {ST_PLCI_RESUMEING, ST_PLCI_NONE, EV_PLCI_RESUME_CONF_ERROR, p0}, + {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, 0}, + /* P-RES */ + {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, 0}, + /* P-HELD */ + {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, 0}, + {}, }; static void plci_change_state(capidrv_contr * card, capidrv_plci * plci, int event) @@ -615,8 +651,8 @@ static void plci_change_state(capidrv_contr * card, capidrv_plci * plci, int eve while (p->event) { if (plci->state == p->actstate && p->event == event) { if (debugmode) - printk(KERN_DEBUG "capidrv: plci_change_state:0x%x %d -> %d\n", - plci->plci, plci->state, p->nextstate); + printk(KERN_DEBUG "capidrv-%d: plci_change_state:0x%x %d -> %d\n", + card->contrnr, plci->plci, plci->state, p->nextstate); plci->state = p->nextstate; if (p->changefunc) p->changefunc(card, plci); @@ -624,8 +660,8 @@ static void plci_change_state(capidrv_contr * card, capidrv_plci * plci, int eve } p++; } - printk(KERN_ERR "capidrv: plci_change_state:0x%x state=%d event=%d ????\n", - plci->plci, plci->state, event); + printk(KERN_ERR "capidrv-%d: plci_change_state:0x%x state=%d event=%d ????\n", + card->contrnr, plci->plci, plci->state, event); } /* ------------------------------------------------------------------ */ @@ -642,7 +678,7 @@ static void n0(capidrv_contr * card, capidrv_ncci * ncci) ncci->plcip->plci, 0, /* BChannelinformation */ 0, /* Keypadfacility */ - 0, /* Useruserdata */ + 0, /* Useruserdata */ /* $$$$ */ 0 /* Facilitydataarray */ ); send_message(card, &cmsg); @@ -667,34 +703,35 @@ struct nccistatechange { static struct nccistatechange nccitable[] = { /* N-0 */ - {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, 0}, - {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, 0}, + {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, 0}, + {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, 0}, /* N-0.1 */ - {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, 0}, - {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, 0}, + {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, 0}, + {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, n0}, /* N-1 */ - {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, 0}, - {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, 0}, + {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, 0}, + {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, 0}, {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, - {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, /* N-2 */ - {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, 0}, - {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, -{ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, 0}, + {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, + {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, /* N-ACT */ - {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, 0}, - {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, - {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0}, + {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, 0}, + {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, + {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, /* N-3 */ - {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0}, + {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0}, {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, - {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, /* N-4 */ - {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, - {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR, 0}, + {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, + {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR,0}, /* N-5 */ - {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0}, - {}, + {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0}, + {}, }; static void ncci_change_state(capidrv_contr * card, capidrv_ncci * ncci, int event) @@ -703,8 +740,8 @@ static void ncci_change_state(capidrv_contr * card, capidrv_ncci * ncci, int eve while (p->event) { if (ncci->state == p->actstate && p->event == event) { if (debugmode) - printk(KERN_DEBUG "capidrv: ncci_change_state:0x%x %d -> %d\n", - ncci->ncci, ncci->state, p->nextstate); + printk(KERN_DEBUG "capidrv-%d: ncci_change_state:0x%x %d -> %d\n", + card->contrnr, ncci->ncci, ncci->state, p->nextstate); if (p->nextstate == ST_NCCI_PREVIOUS) { ncci->state = ncci->oldstate; ncci->oldstate = p->actstate; @@ -718,8 +755,8 @@ static void ncci_change_state(capidrv_contr * card, capidrv_ncci * ncci, int eve } p++; } - printk(KERN_ERR "capidrv: ncci_change_state:0x%x state=%d event=%d ????\n", - ncci->ncci, ncci->state, event); + printk(KERN_ERR "capidrv-%d: ncci_change_state:0x%x state=%d event=%d ????\n", + card->contrnr, ncci->ncci, ncci->state, event); } /* ------------------------------------------------------------------- */ @@ -752,8 +789,8 @@ static void handle_controller(_cmsg * cmsg) case CAPI_LISTEN_CONF: /* Controller */ if (debugmode) - printk(KERN_DEBUG "capidrv: listenconf Info=0x%4x (%s) cipmask=0x%x\n", - cmsg->Info, capi_info2str(cmsg->Info), card->cipmask); + printk(KERN_DEBUG "capidrv-%d: listenconf Info=0x%4x (%s) cipmask=0x%x\n", + card->contrnr, cmsg->Info, capi_info2str(cmsg->Info), card->cipmask); if (cmsg->Info) { listen_change_state(card, EV_LISTEN_CONF_ERROR); } else if (card->cipmask == 0) { @@ -789,7 +826,8 @@ static void handle_controller(_cmsg * cmsg) handle_dtrace_data(card, direction, 0, data, len); break; } - printk(KERN_INFO "capidrv: %s from controller 0x%x layer 0x%x, ignored\n", + printk(KERN_INFO "capidrv-%d: %s from controller 0x%x layer 0x%x, ignored\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrController, layer); break; @@ -805,7 +843,8 @@ static void handle_controller(_cmsg * cmsg) default: s = "unkown error"; break; } if (s) - printk(KERN_INFO "capidrv: %s from controller 0x%x function %d: %s\n", + printk(KERN_INFO "capidrv-%d: %s from controller 0x%x function %d: %s\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrController, cmsg->Function, s); @@ -822,14 +861,16 @@ static void handle_controller(_cmsg * cmsg) goto ignored; default: - printk(KERN_ERR "capidrv: got %s from controller 0x%x ???", + printk(KERN_ERR "capidrv-%d: got %s from controller 0x%x ???", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrController); } return; ignored: - printk(KERN_INFO "capidrv: %s from controller 0x%x ignored\n", + printk(KERN_INFO "capidrv-%d: %s from controller 0x%x ignored\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrController); } @@ -842,12 +883,12 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg) int chan; if ((chan = new_bchan(card)) == -1) { - printk(KERN_ERR "capidrv: incoming call on not existing bchan ?\n"); + printk(KERN_ERR "capidrv-%d: incoming call on not existing bchan ?\n", card->contrnr); return; } bchan = &card->bchans[chan]; if ((plcip = new_plci(card, chan)) == 0) { - printk(KERN_ERR "capidrv: incoming call: no memory, sorry.\n"); + printk(KERN_ERR "capidrv-%d: incoming call: no memory, sorry.\n", card->contrnr); return; } bchan->incoming = 1; @@ -869,7 +910,8 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg) cmd.parm.setup.plan = cmsg->CallingPartyNumber[1]; cmd.parm.setup.screen = cmsg->CallingPartyNumber[2]; - printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s\n", + printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s\n", + card->contrnr, cmd.parm.setup.phone, cmd.parm.setup.si1, cmd.parm.setup.si2, @@ -877,6 +919,7 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg) switch (card->interface.statcallb(&cmd)) { case 0: + case 3: /* No device matching this call. * and isdn_common.c has send a HANGUP command * which is ignored in state ST_PLCI_INCOMING, @@ -886,7 +929,8 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg) cmsg->Reject = 1; /* ignore */ send_message(card, cmsg); plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT); - printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s ignored\n", + printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s ignored\n", + card->contrnr, cmd.parm.setup.phone, cmd.parm.setup.si1, cmd.parm.setup.si2, @@ -903,7 +947,8 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg) * and CONNECT_RESP already sent. */ if (plcip->state == ST_PLCI_INCOMING) { - printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s tty alerting\n", + printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s tty alerting\n", + card->contrnr, cmd.parm.setup.phone, cmd.parm.setup.si1, cmd.parm.setup.si2, @@ -920,7 +965,8 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg) plcip->msgid = cmsg->Messagenumber; send_message(card, cmsg); } else { - printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s on netdev\n", + printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s on netdev\n", + card->contrnr, cmd.parm.setup.phone, cmd.parm.setup.si1, cmd.parm.setup.si2, @@ -963,7 +1009,8 @@ static void handle_plci(_cmsg * cmsg) case CAPI_DISCONNECT_IND: /* plci */ if (cmsg->Reason) { - printk(KERN_INFO "capidrv: %s reason 0x%x (%s) for plci 0x%x\n", + printk(KERN_INFO "capidrv-%d: %s reason 0x%x (%s) for plci 0x%x\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI); } @@ -981,7 +1028,8 @@ static void handle_plci(_cmsg * cmsg) case CAPI_DISCONNECT_CONF: /* plci */ if (cmsg->Info) { - printk(KERN_INFO "capidrv: %s info 0x%x (%s) for plci 0x%x\n", + printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->Info, capi_info2str(cmsg->Info), cmsg->adr.adrPLCI); @@ -994,7 +1042,8 @@ static void handle_plci(_cmsg * cmsg) case CAPI_ALERT_CONF: /* plci */ if (cmsg->Info) { - printk(KERN_INFO "capidrv: %s info 0x%x (%s) for plci 0x%x\n", + printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->Info, capi_info2str(cmsg->Info), cmsg->adr.adrPLCI); @@ -1007,7 +1056,8 @@ static void handle_plci(_cmsg * cmsg) case CAPI_CONNECT_CONF: /* plci */ if (cmsg->Info) { - printk(KERN_INFO "capidrv: %s info 0x%x (%s) for plci 0x%x\n", + printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->Info, capi_info2str(cmsg->Info), cmsg->adr.adrPLCI); @@ -1040,7 +1090,7 @@ static void handle_plci(_cmsg * cmsg) nccip = new_ncci(card, plcip, cmsg->adr.adrPLCI); if (!nccip) { - printk(KERN_ERR "capidrv: no mem for ncci, sorry\n"); + printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr); break; /* $$$$ */ } capi_fill_CONNECT_B3_REQ(cmsg, @@ -1080,7 +1130,8 @@ static void handle_plci(_cmsg * cmsg) break; } } - printk(KERN_ERR "capidrv: %s\n", capi_cmsg2str(cmsg)); + printk(KERN_ERR "capidrv-%d: %s\n", + card->contrnr, capi_cmsg2str(cmsg)); break; case CAPI_CONNECT_ACTIVE_CONF: /* plci */ @@ -1096,18 +1147,21 @@ static void handle_plci(_cmsg * cmsg) goto ignored; default: - printk(KERN_ERR "capidrv: got %s for plci 0x%x ???", + printk(KERN_ERR "capidrv-%d: got %s for plci 0x%x ???", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrPLCI); } return; ignored: - printk(KERN_INFO "capidrv: %s for plci 0x%x ignored\n", + printk(KERN_INFO "capidrv-%d: %s for plci 0x%x ignored\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrPLCI); return; notfound: - printk(KERN_ERR "capidrv: %s: plci 0x%x not found\n", + printk(KERN_ERR "capidrv-%d: %s: plci 0x%x not found\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrPLCI); return; @@ -1142,8 +1196,8 @@ static void handle_ncci(_cmsg * cmsg) cmd.arg = nccip->chan; card->interface.statcallb(&cmd); - printk(KERN_INFO "capidrv: chan %d up with ncci 0x%x\n", - nccip->chan, nccip->ncci); + printk(KERN_INFO "capidrv-%d: chan %d up with ncci 0x%x\n", + card->contrnr, nccip->chan, nccip->ncci); break; case CAPI_CONNECT_B3_ACTIVE_CONF: /* ncci */ @@ -1167,9 +1221,10 @@ static void handle_ncci(_cmsg * cmsg) ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP); break; } - printk(KERN_ERR "capidrv: no mem for ncci, sorry\n"); + printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr); } else { - printk(KERN_ERR "capidrv: %s: plci for ncci 0x%x not found\n", + printk(KERN_ERR "capidrv-%d: %s: plci for ncci 0x%x not found\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrNCCI); } @@ -1192,7 +1247,8 @@ static void handle_ncci(_cmsg * cmsg) nccip->ncci = cmsg->adr.adrNCCI; if (cmsg->Info) { - printk(KERN_INFO "capidrv: %s info 0x%x (%s) for ncci 0x%x\n", + printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->Info, capi_info2str(cmsg->Info), cmsg->adr.adrNCCI); @@ -1242,7 +1298,8 @@ static void handle_ncci(_cmsg * cmsg) if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) goto notfound; if (cmsg->Info) { - printk(KERN_INFO "capidrv: %s info 0x%x (%s) for ncci 0x%x\n", + printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->Info, capi_info2str(cmsg->Info), cmsg->adr.adrNCCI); @@ -1251,6 +1308,9 @@ static void handle_ncci(_cmsg * cmsg) break; case CAPI_RESET_B3_IND: /* ncci */ + if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) + goto notfound; + ncci_change_state(card, nccip, EV_NCCI_RESET_B3_IND); capi_cmsg_answer(cmsg); send_message(card, cmsg); break; @@ -1264,18 +1324,21 @@ static void handle_ncci(_cmsg * cmsg) goto ignored; default: - printk(KERN_ERR "capidrv: got %s for ncci 0x%x ???", + printk(KERN_ERR "capidrv-%d: got %s for ncci 0x%x ???", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrNCCI); } return; ignored: - printk(KERN_INFO "capidrv: %s for ncci 0x%x ignored\n", + printk(KERN_INFO "capidrv-%d: %s for ncci 0x%x ignored\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrNCCI); return; notfound: - printk(KERN_ERR "capidrv: %s: ncci 0x%x not found\n", + printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrNCCI); } @@ -1293,7 +1356,8 @@ static void handle_data(_cmsg * cmsg, struct sk_buff *skb) return; } if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) { - printk(KERN_ERR "capidrv: %s: ncci 0x%x not found\n", + printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrNCCI); kfree_skb(skb); @@ -1314,7 +1378,8 @@ static void capidrv_signal(__u16 applid, __u32 dummy) while ((*capifuncs->capi_get_message) (global.appid, &skb) == CAPI_NOERROR) { capi_message2cmsg(&s_cmsg, skb->data); if (debugmode > 1) - printk(KERN_DEBUG "capidrv_signal: %s\n", capi_cmsg2str(&s_cmsg)); + printk(KERN_DEBUG "capidrv_signal: applid=%d %s\n", + applid, capi_cmsg2str(&s_cmsg)); if (s_cmsg.Command == CAPI_DATA_B3 && s_cmsg.Subcommand == CAPI_IND) { @@ -1348,7 +1413,8 @@ static void handle_dtrace_data(capidrv_contr *card, isdn_ctrl cmd; if (!len) { - printk(KERN_DEBUG "avmb1_q931_data: len == %d\n", len); + printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n", + card->contrnr, len); return; } @@ -1393,7 +1459,8 @@ static int capidrv_ioctl(isdn_ctrl * c, capidrv_contr * card) { switch (c->arg) { default: - printk(KERN_DEBUG "capidrv: capidrv_ioctl(%ld) called ??\n", c->arg); + printk(KERN_DEBUG "capidrv-%d: capidrv_ioctl(%ld) called ??\n", + card->contrnr, c->arg); return -EINVAL; } return -EINVAL; @@ -1414,7 +1481,8 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card) __u8 called[ISDN_MSNLEN + 2]; if (debugmode) - printk(KERN_DEBUG "capidrv: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n", + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n", + card->contrnr, c->arg, c->parm.setup.phone, c->parm.setup.si1, @@ -1424,7 +1492,8 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card) bchan = &card->bchans[c->arg % card->nbchan]; if (bchan->plcip) { - printk(KERN_ERR "capidrv: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n", + printk(KERN_ERR "capidrv-%d: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n", + card->contrnr, c->arg, c->parm.setup.phone, c->parm.setup.si1, @@ -1486,10 +1555,11 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card) case ISDN_CMD_ACCEPTD: - if (debugmode) - printk(KERN_DEBUG "capidrv: ISDN_CMD_ACCEPTD(ch=%ld)\n", - c->arg); bchan = &card->bchans[c->arg % card->nbchan]; + if (debugmode) + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTD(ch=%ld) l2=%d l3=%d\n", + card->contrnr, + c->arg, bchan->l2, bchan->l3); capi_fill_CONNECT_RESP(&cmdcmsg, global.appid, @@ -1517,19 +1587,22 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card) case ISDN_CMD_ACCEPTB: if (debugmode) - printk(KERN_DEBUG "capidrv: ISDN_CMD_ACCEPTB(ch=%ld)\n", + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTB(ch=%ld)\n", + card->contrnr, c->arg); return -ENOSYS; case ISDN_CMD_HANGUP: if (debugmode) - printk(KERN_DEBUG "capidrv: ISDN_CMD_HANGUP(ch=%ld)\n", + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_HANGUP(ch=%ld)\n", + card->contrnr, c->arg); bchan = &card->bchans[c->arg % card->nbchan]; if (bchan->disconnecting) { if (debugmode) - printk(KERN_DEBUG "capidrv: chan %ld already disconnecting ...\n", + printk(KERN_DEBUG "capidrv-%d: chan %ld already disconnecting ...\n", + card->contrnr, c->arg); return 0; } @@ -1568,23 +1641,26 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card) case ISDN_CMD_SETL2: if (debugmode) - printk(KERN_DEBUG "capidrv: set L2 on chan %ld to %ld\n", + printk(KERN_DEBUG "capidrv-%d: set L2 on chan %ld to %ld\n", + card->contrnr, (c->arg & 0xff), (c->arg >> 8)); - bchan = &card->bchans[c->arg % card->nbchan]; + bchan = &card->bchans[(c->arg & 0xff) % card->nbchan]; bchan->l2 = (c->arg >> 8); return 0; case ISDN_CMD_SETL3: if (debugmode) - printk(KERN_DEBUG "capidrv: set L3 on chan %ld to %ld\n", + printk(KERN_DEBUG "capidrv-%d: set L3 on chan %ld to %ld\n", + card->contrnr, (c->arg & 0xff), (c->arg >> 8)); - bchan = &card->bchans[c->arg % card->nbchan]; + bchan = &card->bchans[(c->arg & 0xff) % card->nbchan]; bchan->l3 = (c->arg >> 8); return 0; case ISDN_CMD_SETEAZ: if (debugmode) - printk(KERN_DEBUG "capidrv: set EAZ \"%s\" on chan %ld\n", + printk(KERN_DEBUG "capidrv-%d: set EAZ \"%s\" on chan %ld\n", + card->contrnr, c->parm.num, c->arg); bchan = &card->bchans[c->arg % card->nbchan]; strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN); @@ -1592,46 +1668,54 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card) case ISDN_CMD_CLREAZ: if (debugmode) - printk(KERN_DEBUG "capidrv: clearing EAZ on chan %ld\n", c->arg); + printk(KERN_DEBUG "capidrv-%d: clearing EAZ on chan %ld\n", + card->contrnr, c->arg); bchan = &card->bchans[c->arg % card->nbchan]; bchan->msn[0] = 0; return 0; case ISDN_CMD_LOCK: if (debugmode > 1) - printk(KERN_DEBUG "capidrv: ISDN_CMD_LOCK (%ld)\n", c->arg); + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_LOCK (%ld)\n", card->contrnr, c->arg); MOD_INC_USE_COUNT; break; case ISDN_CMD_UNLOCK: if (debugmode > 1) - printk(KERN_DEBUG "capidrv: ISDN_CMD_UNLOCK (%ld)\n", c->arg); + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_UNLOCK (%ld)\n", + card->contrnr, c->arg); MOD_DEC_USE_COUNT; break; /* never called */ case ISDN_CMD_GETL2: if (debugmode) - printk(KERN_DEBUG "capidrv: ISDN_CMD_GETL2\n"); + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETL2\n", + card->contrnr); return -ENODEV; case ISDN_CMD_GETL3: if (debugmode) - printk(KERN_DEBUG "capidrv: ISDN_CMD_GETL3\n"); + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETL3\n", + card->contrnr); return -ENODEV; case ISDN_CMD_GETEAZ: if (debugmode) - printk(KERN_DEBUG "capidrv: ISDN_CMD_GETEAZ\n"); + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETEAZ\n", + card->contrnr); return -ENODEV; case ISDN_CMD_SETSIL: if (debugmode) - printk(KERN_DEBUG "capidrv: ISDN_CMD_SETSIL\n"); + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_SETSIL\n", + card->contrnr); return -ENODEV; case ISDN_CMD_GETSIL: if (debugmode) - printk(KERN_DEBUG "capidrv: ISDN_CMD_GETSIL\n"); + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETSIL\n", + card->contrnr); return -ENODEV; default: - printk(KERN_ERR "capidrv: ISDN_CMD_%d, Huh?\n", c->command); + printk(KERN_ERR "capidrv-%d: ISDN_CMD_%d, Huh?\n", + card->contrnr, c->command); return -EINVAL; } return 0; @@ -1645,8 +1729,8 @@ static int if_command(isdn_ctrl * c) return capidrv_command(c, card); printk(KERN_ERR - "capidrv: if_command %d called with invalid driverId %d!\n", - c->command, c->driver); + "capidrv-%d: if_command %d called with invalid driverId %d!\n", + card->contrnr, c->command, c->driver); return -ENODEV; } @@ -1663,15 +1747,15 @@ static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb) __u16 datahandle; if (!card) { - printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n", - id); + printk(KERN_ERR "capidrv-%d: if_sendbuf called with invalid driverId %d!\n", + card->contrnr, id); return 0; } bchan = &card->bchans[channel % card->nbchan]; nccip = bchan->nccip; if (!nccip || nccip->state != ST_NCCI_ACTIVE) { - printk(KERN_ERR "capidrv: if_sendbuf: %s:%d: chan not up!\n", - card->name, channel); + printk(KERN_ERR "capidrv-%d: if_sendbuf: %s:%d: chan not up!\n", + card->contrnr, card->name, channel); return 0; } datahandle = nccip->datahandle; @@ -1691,13 +1775,14 @@ static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb) if (skb_headroom(skb) < msglen) { struct sk_buff *nskb = dev_alloc_skb(msglen + skb->len); if (!nskb) { - printk(KERN_ERR "capidrv: if_sendbuf: no memory\n"); + printk(KERN_ERR "capidrv-%d: if_sendbuf: no memory\n", + card->contrnr); (void)capidrv_del_ack(nccip, datahandle); return 0; } #if 0 - printk(KERN_DEBUG "capidrv: only %d bytes headroom\n", - skb_headroom(skb)); + printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom\n", + card->contrnr, skb_headroom(skb)); #endif memcpy(skb_put(nskb, msglen), sendcmsg.buf, msglen); memcpy(skb_put(nskb, skb->len), skb->data, skb->len); @@ -1729,8 +1814,8 @@ static int if_readstat(__u8 *buf, int len, int user, int id, int channel) __u8 *p; if (!card) { - printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n", - id); + printk(KERN_ERR "capidrv-%d: if_readstat called with invalid driverId %d!\n", + card->contrnr, id); return -ENODEV; } @@ -1776,7 +1861,7 @@ static void enable_dchannel_trace(capidrv_contr *card) avmversion[1] |= (version.minormanuversion >> 4) & 0x0f; avmversion[2] |= version.minormanuversion & 0x0f; - if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) { + if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 6)) { printk(KERN_INFO "%s: D2 trace enabled\n", card->name); capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid, card->msgid++, @@ -1878,7 +1963,8 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp) printk(KERN_INFO "%s: now up (%d B channels)\n", card->name, card->nbchan); - enable_dchannel_trace(card); + if (card->nbchan == 2) /* no T1 */ + enable_dchannel_trace(card); return 0; } @@ -1965,8 +2051,8 @@ int capidrv_init(void) } else strcpy(rev, " ??? "); - rparam.level3cnt = 2; - rparam.datablkcnt = 8; + rparam.level3cnt = -2; /* number of bchannels twice */ + rparam.datablkcnt = 16; rparam.datablklen = 2048; errcode = (*capifuncs->capi_register) (&rparam, &global.appid); if (errcode) { diff --git a/drivers/isdn/avmb1/capidrv.h b/drivers/isdn/avmb1/capidrv.h index f30c3f4dd..2e5abf04b 100644 --- a/drivers/isdn/avmb1/capidrv.h +++ b/drivers/isdn/avmb1/capidrv.h @@ -1,11 +1,22 @@ /* - * $Id: capidrv.h,v 1.1 1997/03/04 21:50:33 calle Exp $ + * $Id: capidrv.h,v 1.2 1998/03/29 16:06:06 calle Exp $ * * ISDN4Linux Driver, using capi20 interface (kernelcapi) * * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capidrv.h,v $ + * Revision 1.2 1998/03/29 16:06:06 calle + * changes from 2.0 tree merged. + * + * Revision 1.1.2.1 1998/03/20 14:38:28 calle + * capidrv: prepared state machines for suspend/resume/hold + * capidrv: fix bug in state machine if B1/T1 is out of nccis + * b1capi: changed some errno returns. + * b1capi: detect if you try to add same T1 to different io address. + * b1capi: change number of nccis depending on number of channels. + * b1lli: cosmetics + * * Revision 1.1 1997/03/04 21:50:33 calle * Frirst version in isdn4linux * @@ -49,34 +60,70 @@ #define ST_PLCI_ACCEPTING 6 /* P-4 */ #define ST_PLCI_DISCONNECTING 7 /* P-5 */ #define ST_PLCI_DISCONNECTED 8 /* P-6 */ +#define ST_PLCI_RESUMEING 9 /* P-0.Res */ +#define ST_PLCI_RESUME 10 /* P-Res */ +#define ST_PLCI_HELD 11 /* P-HELD */ -#define EV_PLCI_CONNECT_REQ 1 /* P-0 -> P-0.1 */ -#define EV_PLCI_CONNECT_CONF_ERROR 2 /* P-0.1 -> P-0 */ -#define EV_PLCI_CONNECT_CONF_OK 3 /* P-0.1 -> P-1 */ -#define EV_PLCI_FACILITY_IND_UP 4 /* P-0 -> P-1 */ -#define EV_PLCI_CONNECT_IND 5 /* P-0 -> P-2 */ -#define EV_PLCI_CONNECT_ACTIVE_IND 6 /* P-1 -> P-ACT */ +#define EV_PLCI_CONNECT_REQ 1 /* P-0 -> P-0.1 + */ +#define EV_PLCI_CONNECT_CONF_ERROR 2 /* P-0.1 -> P-0 + */ +#define EV_PLCI_CONNECT_CONF_OK 3 /* P-0.1 -> P-1 + */ +#define EV_PLCI_FACILITY_IND_UP 4 /* P-0 -> P-1 + */ +#define EV_PLCI_CONNECT_IND 5 /* P-0 -> P-2 + */ +#define EV_PLCI_CONNECT_ACTIVE_IND 6 /* P-1 -> P-ACT + */ #define EV_PLCI_CONNECT_REJECT 7 /* P-2 -> P-5 - P-3 -> P-5 */ + P-3 -> P-5 + */ #define EV_PLCI_DISCONNECT_REQ 8 /* P-1 -> P-5 P-2 -> P-5 P-3 -> P-5 P-4 -> P-5 - P-ACT -> P-5 */ + P-ACT -> P-5 + P-Res -> P-5 (*) + P-HELD -> P-5 (*) + */ #define EV_PLCI_DISCONNECT_IND 9 /* P-1 -> P-6 P-2 -> P-6 P-3 -> P-6 P-4 -> P-6 P-5 -> P-6 - P-ACT -> P-6 */ + P-ACT -> P-6 + P-Res -> P-6 (*) + P-HELD -> P-6 (*) + */ #define EV_PLCI_FACILITY_IND_DOWN 10 /* P-0.1 -> P-5 P-1 -> P-5 P-ACT -> P-5 P-2 -> P-5 P-3 -> P-5 - P-4 -> P-5 */ -#define EV_PLCI_DISCONNECT_RESP 11 /* P-6 -> P-0 */ -#define EV_PLCI_CONNECT_RESP 12 /* P-6 -> P-0 */ + P-4 -> P-5 + */ +#define EV_PLCI_DISCONNECT_RESP 11 /* P-6 -> P-0 + */ +#define EV_PLCI_CONNECT_RESP 12 /* P-6 -> P-0 + */ + +#define EV_PLCI_RESUME_REQ 13 /* P-0 -> P-0.Res + */ +#define EV_PLCI_RESUME_CONF_OK 14 /* P-0.Res -> P-Res + */ +#define EV_PLCI_RESUME_CONF_ERROR 15 /* P-0.Res -> P-0 + */ +#define EV_PLCI_RESUME_IND 16 /* P-Res -> P-ACT + */ +#define EV_PLCI_HOLD_IND 17 /* P-ACT -> P-HELD + */ +#define EV_PLCI_RETRIEVE_IND 18 /* P-HELD -> P-ACT + */ +#define EV_PLCI_SUSPEND_IND 19 /* P-ACT -> P-5 + */ +#define EV_PLCI_CD_IND 20 /* P-2 -> P-5 + */ /* * per ncci state machine diff --git a/drivers/isdn/avmb1/compat.h b/drivers/isdn/avmb1/compat.h index 41ad2b626..15f471559 100644 --- a/drivers/isdn/avmb1/compat.h +++ b/drivers/isdn/avmb1/compat.h @@ -1,11 +1,14 @@ /* - * $Id: compat.h,v 1.3 1997/11/04 06:12:15 calle Exp $ + * $Id: compat.h,v 1.4 1998/10/25 14:39:02 fritz Exp $ * * Headerfile for Compartibility between different kernel versions * * (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: compat.h,v $ + * Revision 1.4 1998/10/25 14:39:02 fritz + * Backported from MIPS (Cobalt). + * * Revision 1.3 1997/11/04 06:12:15 calle * capi.c: new read/write in file_ops since 2.1.60 * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware. @@ -32,6 +35,7 @@ #define __COMPAT_H__ #include <linux/version.h> +#include <asm/segment.h> #include <linux/isdnif.h> #ifndef LinuxVersionCode diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile index da07e7b8c..9e7cb7773 100644 --- a/drivers/isdn/hisax/Makefile +++ b/drivers/isdn/hisax/Makefile @@ -8,7 +8,7 @@ L_TARGET := O_TARGET := O_OBJS := isdnl1.o tei.o isdnl2.o isdnl3.o \ - lmgr.o q931.o callc.o fsm.o + lmgr.o q931.o callc.o fsm.o cert.o # EXTRA_CFLAGS += -S @@ -27,6 +27,7 @@ endif ISAC_OBJ := ARCOFI_OBJ := HSCX_OBJ := +ISAR_OBJ := HFC_OBJ := HFC_2BDS0 := RAWHDLC_OBJ := @@ -43,12 +44,36 @@ ifeq ($(CONFIG_HISAX_16_3),y) HSCX_OBJ := hscx.o endif +ifeq ($(CONFIG_HISAX_TELESPCI),y) + O_OBJS += telespci.o + ISAC_OBJ := isac.o + HSCX_OBJ := hscx.o +endif + +ifeq ($(CONFIG_HISAX_S0BOX),y) + O_OBJS += s0box.o + ISAC_OBJ := isac.o + HSCX_OBJ := hscx.o +endif + ifeq ($(CONFIG_HISAX_AVM_A1),y) O_OBJS += avm_a1.o ISAC_OBJ := isac.o HSCX_OBJ := hscx.o endif +ifeq ($(CONFIG_HISAX_AVM_A1_PCMCIA),y) + O_OBJS += avm_a1p.o + ISAC_OBJ := isac.o + HSCX_OBJ := hscx.o +endif + +ifeq ($(CONFIG_HISAX_FRITZPCI),y) + O_OBJS += avm_pci.o + ISAC_OBJ := isac.o +endif + + ifeq ($(CONFIG_HISAX_ELSA),y) O_OBJS += elsa.o ISAC_OBJ := isac.o @@ -84,6 +109,7 @@ ifeq ($(CONFIG_HISAX_SEDLBAUER),y) O_OBJS += sedlbauer.o ISAC_OBJ := isac.o HSCX_OBJ := hscx.o + ISAR_OBJ := isar.o endif ifeq ($(CONFIG_HISAX_SPORTSTER),y) @@ -101,6 +127,7 @@ endif ifeq ($(CONFIG_HISAX_NETJET),y) O_OBJS += netjet.o ISAC_OBJ := isac.o +# RAWHDLC_OBJ := rawhdlc.o endif ifeq ($(CONFIG_HISAX_TELES3C),y) @@ -108,10 +135,8 @@ ifeq ($(CONFIG_HISAX_TELES3C),y) HFC_2BDS0 := hfc_2bds0.o endif ifeq ($(CONFIG_HISAX_AMD7930),y) - RAWHDLC_OBJ := foreign.o rawhdlc.o -endif -ifeq ($(CONFIG_HISAX_DBRI),y) - RAWHDLC_OBJ := foreign.o rawhdlc.o + O_OBJS += amd7930.o + RAWHDLC_OBJ := rawhdlc.o endif ifeq ($(CONFIG_HISAX_NICCY),y) @@ -120,7 +145,8 @@ ifeq ($(CONFIG_HISAX_NICCY),y) HSCX_OBJ := hscx.o endif -O_OBJS += $(ISAC_OBJ) $(HSCX_OBJ) $(HFC_OBJ) $(ARCOFI_OBJ) $(HFC_2BDS0) $(RAWHDLC_OBJ) +O_OBJS += $(ISAC_OBJ) $(HSCX_OBJ) $(ISAR_OBJ) $(ARCOFI_OBJ) +O_OBJS += $(HFC_OBJ) $(HFC_2BDS0) $(RAWHDLC_OBJ) OX_OBJS += config.o O_TARGET := @@ -134,4 +160,14 @@ else endif endif + 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 + +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/arcofi.c b/drivers/isdn/hisax/arcofi.c index 1717b3a27..a7c091321 100644 --- a/drivers/isdn/hisax/arcofi.c +++ b/drivers/isdn/hisax/arcofi.c @@ -1,12 +1,28 @@ -/* $Id: arcofi.c,v 1.1 1997/10/29 18:51:20 keil Exp $ +/* $Id: arcofi.c,v 1.6 1998/09/30 22:21:56 keil Exp $ - * arcofi.h Ansteuerung ARCOFI 2165 + * arcofi.c Ansteuerung ARCOFI 2165 * * Author Karsten Keil (keil@temic-ech.spacenet.de) * * * * $Log: arcofi.c,v $ + * Revision 1.6 1998/09/30 22:21:56 keil + * cosmetics + * + * Revision 1.5 1998/09/27 12:52:57 keil + * cosmetics + * + * Revision 1.4 1998/08/20 13:50:24 keil + * More support for hybrid modem (not working yet) + * + * Revision 1.3 1998/05/25 12:57:38 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 1.2 1998/04/15 16:47:16 keil + * new interface + * * Revision 1.1 1997/10/29 18:51:20 keil * New files * @@ -18,18 +34,25 @@ #include "isac.h" int -send_arcofi(struct IsdnCardState *cs, const u_char *msg) { +send_arcofi(struct IsdnCardState *cs, const u_char *msg, int bc, int receive) { u_char val; - char tmp[32]; long flags; - int cnt=2; + int cnt=30; cs->mon_txp = 0; cs->mon_txc = msg[0]; memcpy(cs->mon_tx, &msg[1], cs->mon_txc); + switch(bc) { + case 0: break; + case 1: cs->mon_tx[1] |= 0x40; + break; + default: break; + } cs->mocr &= 0x0f; cs->mocr |= 0xa0; test_and_clear_bit(HW_MON1_TX_END, &cs->HW_Flags); + if (receive) + test_and_clear_bit(HW_MON1_RX_END, &cs->HW_Flags); cs->writeisac(cs, ISAC_MOCR, cs->mocr); val = cs->readisac(cs, ISAC_MOSR); cs->writeisac(cs, ISAC_MOX1, cs->mon_tx[cs->mon_txp++]); @@ -39,12 +62,18 @@ send_arcofi(struct IsdnCardState *cs, const u_char *msg) { sti(); while (cnt && !test_bit(HW_MON1_TX_END, &cs->HW_Flags)) { cnt--; - current->state = TASK_INTERRUPTIBLE; - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + udelay(500); + } + if (receive) { + while (cnt && !test_bit(HW_MON1_RX_END, &cs->HW_Flags)) { + cnt--; + udelay(500); + } } restore_flags(flags); - sprintf(tmp, "arcofi tout %d", cnt); - debugl1(cs, tmp); + if (cnt <= 0) { + printk(KERN_WARNING"HiSax arcofi monitor timed out\n"); + debugl1(cs, "HiSax arcofi monitor timed out"); + } return(cnt); } - diff --git a/drivers/isdn/hisax/arcofi.h b/drivers/isdn/hisax/arcofi.h index 5e1bb9e99..be1097d15 100644 --- a/drivers/isdn/hisax/arcofi.h +++ b/drivers/isdn/hisax/arcofi.h @@ -1,4 +1,4 @@ -/* $Id: arcofi.h,v 1.1 1997/10/29 18:51:20 keil Exp $ +/* $Id: arcofi.h,v 1.3 1998/05/25 12:57:39 keil Exp $ * arcofi.h Ansteuerung ARCOFI 2165 * @@ -7,6 +7,13 @@ * * * $Log: arcofi.h,v $ + * Revision 1.3 1998/05/25 12:57:39 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 1.2 1998/04/15 16:47:17 keil + * new interface + * * Revision 1.1 1997/10/29 18:51:20 keil * New files * @@ -14,4 +21,4 @@ #define ARCOFI_USE 1 -extern int send_arcofi(struct IsdnCardState *cs, const u_char *msg); +extern int send_arcofi(struct IsdnCardState *cs, const u_char *msg, int bc, int receive); diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c index 6980a2888..4990f9eb8 100644 --- a/drivers/isdn/hisax/asuscom.c +++ b/drivers/isdn/hisax/asuscom.c @@ -1,13 +1,22 @@ -/* $Id: asuscom.c,v 1.2 1998/02/02 13:27:06 keil Exp $ +/* $Id: asuscom.c,v 1.5 1998/11/15 23:54:19 keil Exp $ * asuscom.c low level stuff for ASUSCOM NETWORK INC. ISDNLink cards * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * Thanks to ASUSCOM NETWORK INC. Taiwan and Dynalink NL for informations * * * $Log: asuscom.c,v $ + * Revision 1.5 1998/11/15 23:54:19 keil + * changes from 2.0 + * + * Revision 1.4 1998/06/18 23:18:20 keil + * Support for new IPAC card + * + * Revision 1.3 1998/04/15 16:46:53 keil + * new init code + * * Revision 1.2 1998/02/02 13:27:06 keil * New * @@ -17,12 +26,13 @@ #define __NO_VERSION__ #include "hisax.h" #include "isac.h" +#include "ipac.h" #include "hscx.h" #include "isdnl1.h" extern const char *CardType[]; -const char *Asuscom_revision = "$Revision: 1.2 $"; +const char *Asuscom_revision = "$Revision: 1.5 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -33,6 +43,12 @@ const char *Asuscom_revision = "$Revision: 1.2 $"; #define ASUS_CTRL_U7 3 #define ASUS_CTRL_POTS 5 +#define ASUS_IPAC_ALE 0 +#define ASUS_IPAC_DATA 1 + +#define ASUS_ISACHSCX 1 +#define ASUS_IPAC 2 + /* CARD_ADR (Write) */ #define ASUS_RESET 0x80 /* Bit 7 Reset-Leitung */ @@ -107,6 +123,30 @@ WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) } static u_char +ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) +{ + return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset|0x80)); +} + +static void +WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) +{ + writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset|0x80, value); +} + +static void +ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) +{ + readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size); +} + +static void +WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) +{ + writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size); +} + +static u_char ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { return (readreg(cs->hw.asus.adr, @@ -183,6 +223,52 @@ asuscom_interrupt(int intno, void *dev_id, struct pt_regs *regs) } } +static void +asuscom_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char ista, val, icnt = 20; + + if (!cs) { + printk(KERN_WARNING "ISDNLink: Spurious interrupt!\n"); + return; + } + ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA); +Start_IPAC: + if (cs->debug & L1_DEB_IPAC) + debugl1(cs, "IPAC ISTA %02X", ista); + if (ista & 0x0f) { + val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40); + if (ista & 0x01) + val |= 0x01; + if (ista & 0x04) + val |= 0x02; + if (ista & 0x08) + val |= 0x04; + if (val) + hscx_int_main(cs, val); + } + if (ista & 0x20) { + val = 0xfe & readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA | 0x80); + if (val) { + isac_interrupt(cs, val); + } + } + if (ista & 0x10) { + val = 0x01; + isac_interrupt(cs, val); + } + ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA); + if ((ista & 0x3f) && icnt) { + icnt--; + goto Start_IPAC; + } + if (!icnt) + printk(KERN_WARNING "ASUS IRQ LOOP\n"); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xFF); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xC0); +} + void release_io_asuscom(struct IsdnCardState *cs) { @@ -197,14 +283,27 @@ reset_asuscom(struct IsdnCardState *cs) { long flags; - byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */ + if (cs->subtyp == ASUS_IPAC) + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x20); + else + byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */ save_flags(flags); sti(); current->state = TASK_INTERRUPTIBLE; schedule_timeout(1); - byteout(cs->hw.asus.adr, 0); /* Reset Off */ + if (cs->subtyp == ASUS_IPAC) + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x0); + else + byteout(cs->hw.asus.adr, 0); /* Reset Off */ current->state = TASK_INTERRUPTIBLE; schedule_timeout(1); + if (cs->subtyp == ASUS_IPAC) { + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_CONF, 0x0); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ACFG, 0xff); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_AOE, 0x0); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xc0); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_PCFG, 0x12); + } restore_flags(flags); } @@ -219,13 +318,15 @@ Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg) release_io_asuscom(cs); return(0); case CARD_SETIRQ: - return(request_irq(cs->irq, &asuscom_interrupt, + if (cs->subtyp == ASUS_IPAC) + return(request_irq(cs->irq, &asuscom_interrupt_ipac, + I4L_IRQ_FLAG, "HiSax", cs)); + else + return(request_irq(cs->irq, &asuscom_interrupt, I4L_IRQ_FLAG, "HiSax", cs)); case CARD_INIT: - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + cs->debug |= L1_DEB_IPAC; + inithscxisac(cs, 3); return(0); case CARD_TEST: return(0); @@ -238,6 +339,7 @@ setup_asuscom(struct IsdnCard *card)) { int bytecnt; struct IsdnCardState *cs = card->cs; + u_char val; char tmp[64]; strcpy(tmp, Asuscom_revision); @@ -248,12 +350,6 @@ setup_asuscom(struct IsdnCard *card)) bytecnt = 8; cs->hw.asus.cfg_reg = card->para[1]; cs->irq = card->para[0]; - cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_ADR; - cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_ISAC; - cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_HSCX; - cs->hw.asus.u7 = cs->hw.asus.cfg_reg + ASUS_CTRL_U7; - cs->hw.asus.pots = cs->hw.asus.cfg_reg + ASUS_CTRL_POTS; - if (check_region((cs->hw.asus.cfg_reg), bytecnt)) { printk(KERN_WARNING "HiSax: %s config port %x-%x already in use\n", @@ -264,27 +360,45 @@ setup_asuscom(struct IsdnCard *card)) } else { request_region(cs->hw.asus.cfg_reg, bytecnt, "asuscom isdn"); } - - printk(KERN_INFO - "ISDNLink: defined at 0x%x IRQ %d\n", - cs->hw.asus.cfg_reg, - cs->irq); - printk(KERN_INFO "ISDNLink: resetting card\n"); - reset_asuscom(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; + printk(KERN_INFO "ISDNLink: defined at 0x%x IRQ %d\n", + cs->hw.asus.cfg_reg, cs->irq); cs->BC_Read_Reg = &ReadHSCX; cs->BC_Write_Reg = &WriteHSCX; cs->BC_Send_Data = &hscx_fill_fifo; cs->cardmsg = &Asus_card_msg; - ISACVersion(cs, "ISDNLink:"); - if (HscxVersion(cs, "ISDNLink:")) { - printk(KERN_WARNING - "ISDNLink: wrong HSCX versions check IO address\n"); - release_io_asuscom(cs); - return (0); + val = readreg(cs->hw.asus.cfg_reg + ASUS_IPAC_ALE, + cs->hw.asus.cfg_reg + ASUS_IPAC_DATA, IPAC_ID); + if (val == 1) { + cs->subtyp = ASUS_IPAC; + cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_IPAC_ALE; + cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA; + cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + cs->readisac = &ReadISAC_IPAC; + cs->writeisac = &WriteISAC_IPAC; + cs->readisacfifo = &ReadISACfifo_IPAC; + cs->writeisacfifo = &WriteISACfifo_IPAC; + printk(KERN_INFO "Asus: IPAC version %x\n", val); + } else { + cs->subtyp = ASUS_ISACHSCX; + cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_ADR; + cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_ISAC; + cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_HSCX; + cs->hw.asus.u7 = cs->hw.asus.cfg_reg + ASUS_CTRL_U7; + cs->hw.asus.pots = cs->hw.asus.cfg_reg + ASUS_CTRL_POTS; + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + ISACVersion(cs, "ISDNLink:"); + if (HscxVersion(cs, "ISDNLink:")) { + printk(KERN_WARNING + "ISDNLink: wrong HSCX versions check IO address\n"); + release_io_asuscom(cs); + return (0); + } } + printk(KERN_INFO "ISDNLink: resetting card\n"); + reset_asuscom(cs); return (1); } diff --git a/drivers/isdn/hisax/avm_a1.c b/drivers/isdn/hisax/avm_a1.c index 464bc33fd..5c5f944d4 100644 --- a/drivers/isdn/hisax/avm_a1.c +++ b/drivers/isdn/hisax/avm_a1.c @@ -1,11 +1,20 @@ -/* $Id: avm_a1.c,v 2.7 1998/02/02 13:29:37 keil Exp $ +/* $Id: avm_a1.c,v 2.10 1998/11/15 23:54:21 keil Exp $ * avm_a1.c low level stuff for AVM A1 (Fritz) isdn cards * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * * $Log: avm_a1.c,v $ + * Revision 2.10 1998/11/15 23:54:21 keil + * changes from 2.0 + * + * Revision 2.9 1998/08/13 23:36:12 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 2.8 1998/04/15 16:44:27 keil + * new init code + * * Revision 2.7 1998/02/02 13:29:37 keil * fast io * @@ -57,7 +66,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *avm_revision = "$Revision: 2.7 $"; +static const char *avm_revision = "$Revision: 2.10 $"; #define AVM_A1_STAT_ISAC 0x01 #define AVM_A1_STAT_HSCX 0x02 @@ -145,7 +154,6 @@ avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; u_char val, sval, stat = 0; - char tmp[32]; if (!cs) { printk(KERN_WARNING "AVM A1: Spurious interrupt!\n"); @@ -155,10 +163,8 @@ avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs) if (!(sval & AVM_A1_STAT_TIMER)) { byteout(cs->hw.avm.cfg_reg, 0x1E); sval = bytein(cs->hw.avm.cfg_reg); - } else if (cs->debug & L1_DEB_INTSTAT) { - sprintf(tmp, "avm IntStatus %x", sval); - debugl1(cs, tmp); - } + } else if (cs->debug & L1_DEB_INTSTAT) + debugl1(cs, "avm IntStatus %x", sval); if (!(sval & AVM_A1_STAT_HSCX)) { val = readreg(cs->hw.avm.hscx[1], HSCX_ISTA); if (val) { @@ -217,10 +223,10 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(request_irq(cs->irq, &avm_a1_interrupt, I4L_IRQ_FLAG, "HiSax", cs)); case CARD_INIT: - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + inithscxisac(cs, 1); + byteout(cs->hw.avm.cfg_reg, 0x16); + byteout(cs->hw.avm.cfg_reg, 0x1E); + inithscxisac(cs, 2); return(0); case CARD_TEST: return(0); @@ -348,7 +354,6 @@ setup_avm_a1(struct IsdnCard *card)) val = bytein(cs->hw.avm.cfg_reg + 2); printk(KERN_INFO "AVM A1: Byte at %x is %x\n", cs->hw.avm.cfg_reg + 2, val); - byteout(cs->hw.avm.cfg_reg, 0x1E); val = bytein(cs->hw.avm.cfg_reg); printk(KERN_INFO "AVM A1: Byte at %x is %x\n", cs->hw.avm.cfg_reg, val); diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c index bcd305058..bf09acd20 100644 --- a/drivers/isdn/hisax/callc.c +++ b/drivers/isdn/hisax/callc.c @@ -1,12 +1,61 @@ -/* $Id: callc.c,v 2.13 1998/02/12 23:07:16 keil Exp $ +/* $Id: callc.c,v 2.25 1999/01/02 11:17:20 keil Exp $ - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/HiSax.cert + * * Thanks to Jan den Ouden * Fritz Elfert * * $Log: callc.c,v $ + * Revision 2.25 1999/01/02 11:17:20 keil + * Changes for 2.2 + * + * Revision 2.24 1998/11/15 23:54:24 keil + * changes from 2.0 + * + * Revision 2.23 1998/09/30 22:21:57 keil + * cosmetics + * + * Revision 2.22 1998/08/20 13:50:29 keil + * More support for hybrid modem (not working yet) + * + * Revision 2.21 1998/08/13 23:36:15 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 2.20 1998/06/26 15:13:05 fritz + * Added handling of STAT_ICALL with incomplete CPN. + * Added AT&L for ttyI emulator. + * Added more locking stuff in tty_write. + * + * Revision 2.19 1998/05/25 14:08:06 keil + * HiSax 3.0 + * fixed X.75 and leased line to work again + * Point2Point and fixed TEI are runtime options now: + * hisaxctrl <id> 7 1 set PTP + * hisaxctrl <id> 8 <TEIVALUE *2 > + * set fixed TEI to TEIVALUE (0-63) + * + * Revision 2.18 1998/05/25 12:57:40 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 2.17 1998/04/15 16:46:06 keil + * RESUME support + * + * Revision 2.16 1998/04/10 10:35:17 paul + * fixed (silly?) warnings from egcs on Alpha. + * + * Revision 2.15 1998/03/19 13:18:37 keil + * Start of a CAPI like interface for supplementary Service + * first service: SUSPEND + * + * Revision 2.14 1998/03/07 22:56:54 tsbogend + * made HiSax working on Linux/Alpha + * * Revision 2.13 1998/02/12 23:07:16 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -60,12 +109,13 @@ #define __NO_VERSION__ #include "hisax.h" +#include "../avmb1/capicmd.h" /* this should be moved in a common place */ #ifdef MODULE #define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module)) #endif /* MODULE */ -const char *lli_revision = "$Revision: 2.13 $"; +const char *lli_revision = "$Revision: 2.25 $"; extern struct IsdnCard cards[]; extern int nrcards; @@ -77,20 +127,18 @@ static void release_b_st(struct Channel *chanp); static struct Fsm callcfsm = {NULL, 0, 0, NULL, NULL}; -static struct Fsm lcfsm = -{NULL, 0, 0, NULL, NULL}; static int chancount = 0; -/* experimental REJECT after ALERTING for CALLBACK to beat the 4s delay */ -#define ALERT_REJECT 1 +/* experimental REJECT after ALERTING for CALLBACK to beat the 4s delay */ +#define ALERT_REJECT 0 /* Value to delay the sending of the first B-channel paket after CONNECT * here is no value given by ITU, but experience shows that 300 ms will * work on many networks, if you or your other side is behind local exchanges * a greater value may be recommented. If the delay is to short the first paket * will be lost and autodetect on many comercial routers goes wrong ! - * You can adjust this value on runtime with + * You can adjust this value on runtime with * hisaxctrl <id> 2 <value> * value is in milliseconds */ @@ -114,11 +162,12 @@ static int chancount = 0; #define FLG_DO_HANGUP 13 #define FLG_DO_CONNECT 14 #define FLG_DO_ESTAB 15 +#define FLG_RESUME 16 /* * Because of callback it's a good idea to delay the shutdown of the d-channel */ -#define DREL_TIMER_VALUE 10000 +#define DREL_TIMER_VALUE 40000 /* * Find card with given driverId @@ -136,15 +185,30 @@ hisax_findcard(int driverid) return (struct IsdnCardState *) 0; } +int +discard_queue(struct sk_buff_head *q) +{ + struct sk_buff *skb; + int ret=0; + + while ((skb = skb_dequeue(q))) { + dev_kfree_skb(skb); + ret++; + } + return(ret); +} + static void -link_debug(struct Channel *chanp, char *s, int direction) +link_debug(struct Channel *chanp, int direction, char *fmt, ...) { - char tmp[100], tm[32]; + va_list args; + char tmp[16]; - jiftime(tm, jiffies); - sprintf(tmp, "%s Channel %d %s %s\n", tm, chanp->chan, - direction ? "LL->HL" : "HL->LL", s); - HiSax_putstatus(chanp->cs, tmp); + va_start(args, fmt); + sprintf(tmp, "Ch%d %s ", chanp->chan, + direction ? "LL->HL" : "HL->LL"); + VHiSax_putstatus(chanp->cs, tmp, fmt, args); + va_end(args); } @@ -244,72 +308,21 @@ static char *strEvent[] = "EV_RELEASE_ERR", }; -enum { - ST_LC_NULL, - ST_LC_ACTIVATE_WAIT, - ST_LC_DELAY, - ST_LC_ESTABLISH_WAIT, - ST_LC_CONNECTED, - ST_LC_FLUSH_WAIT, - ST_LC_RELEASE_WAIT, -}; - -#define LC_STATE_COUNT (ST_LC_RELEASE_WAIT+1) - -static char *strLcState[] = -{ - "ST_LC_NULL", - "ST_LC_ACTIVATE_WAIT", - "ST_LC_DELAY", - "ST_LC_ESTABLISH_WAIT", - "ST_LC_CONNECTED", - "ST_LC_FLUSH_WAIT", - "ST_LC_RELEASE_WAIT", -}; - -enum { - EV_LC_ESTABLISH, - EV_LC_PH_ACTIVATE, - EV_LC_PH_DEACTIVATE, - EV_LC_DL_ESTABLISH, - EV_LC_TIMER, - EV_LC_DL_RELEASE, - EV_LC_RELEASE, -}; - -#define LC_EVENT_COUNT (EV_LC_RELEASE+1) - -static char *strLcEvent[] = -{ - "EV_LC_ESTABLISH", - "EV_LC_PH_ACTIVATE", - "EV_LC_PH_DEACTIVATE", - "EV_LC_DL_ESTABLISH", - "EV_LC_TIMER", - "EV_LC_DL_RELEASE", - "EV_LC_RELEASE", -}; - -#define LC_D 0 -#define LC_B 1 - static inline void -lli_deliver_cause(struct Channel *chanp) +lli_deliver_cause(struct Channel *chanp, isdn_ctrl *ic) { - isdn_ctrl ic; - if (chanp->proc->para.cause < 0) return; - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_CAUSE; - ic.arg = chanp->chan; + ic->driver = chanp->cs->myid; + ic->command = ISDN_STAT_CAUSE; + ic->arg = chanp->chan; if (chanp->cs->protocol == ISDN_PTYPE_EURO) - sprintf(ic.parm.num, "E%02X%02X", chanp->proc->para.loc & 0x7f, + sprintf(ic->parm.num, "E%02X%02X", chanp->proc->para.loc & 0x7f, chanp->proc->para.cause & 0x7f); else - sprintf(ic.parm.num, "%02X%02X", chanp->proc->para.loc & 0x7f, + sprintf(ic->parm.num, "%02X%02X", chanp->proc->para.loc & 0x7f, chanp->proc->para.cause & 0x7f); - chanp->cs->iif.statcallb(&ic); + chanp->cs->iif.statcallb(ic); } static void @@ -321,13 +334,12 @@ lli_d_established(struct FsmInst *fi, int event, void *arg) if (chanp->leased) { isdn_ctrl ic; int ret; - char txt[32]; - chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) chanp->chan); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); FsmChangeState(fi, ST_IN_WAIT_LL); test_and_set_bit(FLG_CALL_REC, &chanp->Flags); if (chanp->debug & 1) - link_debug(chanp, "STAT_ICALL_LEASED", 0); + link_debug(chanp, 0, "STAT_ICALL_LEASED"); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_ICALL; ic.arg = chanp->chan; @@ -335,15 +347,13 @@ lli_d_established(struct FsmInst *fi, int event, void *arg) ic.parm.setup.si2 = 0; ic.parm.setup.plan = 0; ic.parm.setup.screen = 0; - sprintf(ic.parm.setup.eazmsn,"%d", chanp->chan + 1); + sprintf(ic.parm.setup.eazmsn,"%d", chanp->chan + 1); sprintf(ic.parm.setup.phone,"LEASED%d", chanp->cs->myid); ret = chanp->cs->iif.statcallb(&ic); - if (chanp->debug & 1) { - sprintf(txt, "statcallb ret=%d", ret); - link_debug(chanp, txt, 1); - } + if (chanp->debug & 1) + link_debug(chanp, 1, "statcallb ret=%d", ret); if (!ret) { - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); FsmChangeState(fi, ST_NULL); } } else if (fi->state == ST_WAIT_DSHUTDOWN) @@ -371,28 +381,14 @@ lli_prep_dialout(struct FsmInst *fi, int event, void *arg) FsmDelTimer(&chanp->dial_timer, 73); chanp->l2_active_protocol = chanp->l2_protocol; chanp->incoming = 0; - chanp->lc_b->l2_start = !0; - switch (chanp->l2_active_protocol) { - case (ISDN_PROTO_L2_X75I): - chanp->lc_b->l2_establish = !0; - break; - case (ISDN_PROTO_L2_HDLC): - case (ISDN_PROTO_L2_TRANS): - chanp->lc_b->l2_establish = 0; - break; - default: - printk(KERN_WARNING "lli_prep_dialout unknown protocol\n"); - break; - } if (test_bit(FLG_ESTAB_D, &chanp->Flags)) { FsmEvent(fi, EV_DLEST, NULL); } else { chanp->Flags = 0; + if (EV_RESUME == event) + test_and_set_bit(FLG_RESUME, &chanp->Flags); test_and_set_bit(FLG_START_D, &chanp->Flags); - if (chanp->leased) { - chanp->lc_d->l2_establish = 0; - } - FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL); + chanp->d_st->lli.l4l3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL); } } @@ -400,14 +396,19 @@ static void lli_do_dialout(struct FsmInst *fi, int event, void *arg) { struct Channel *chanp = fi->userdata; + int ev; FsmChangeState(fi, ST_OUT_DIAL); - chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) chanp->chan); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); + if (test_and_clear_bit(FLG_RESUME, &chanp->Flags)) + ev = CC_RESUME | REQUEST; + else + ev = CC_SETUP | REQUEST; if (chanp->leased) { FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL); } else { test_and_set_bit(FLG_ESTAB_D, &chanp->Flags); - chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP_REQ, chanp); + chanp->d_st->lli.l4l3(chanp->d_st, ev, chanp); test_and_set_bit(FLG_CALL_SEND, &chanp->Flags); } } @@ -421,14 +422,14 @@ lli_init_bchan_out(struct FsmInst *fi, int event, void *arg) FsmChangeState(fi, ST_WAIT_BCONN); test_and_set_bit(FLG_LL_DCONN, &chanp->Flags); if (chanp->debug & 1) - link_debug(chanp, "STAT_DCONN", 0); + link_debug(chanp, 0, "STAT_DCONN"); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_DCONN; ic.arg = chanp->chan; chanp->cs->iif.statcallb(&ic); init_b_st(chanp, 0); test_and_set_bit(FLG_START_B, &chanp->Flags); - FsmEvent(&chanp->lc_b->lcfi, EV_LC_ESTABLISH, NULL); + chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL); } static void @@ -441,15 +442,19 @@ lli_go_active(struct FsmInst *fi, int event, void *arg) chanp->data_open = !0; test_and_set_bit(FLG_CONNECT_B, &chanp->Flags); if (chanp->debug & 1) - link_debug(chanp, "STAT_BCONN", 0); + link_debug(chanp, 0, "STAT_BCONN"); test_and_set_bit(FLG_LL_BCONN, &chanp->Flags); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_BCONN; ic.arg = chanp->chan; chanp->cs->iif.statcallb(&ic); - chanp->cs->cardmsg(chanp->cs, MDL_INFO_CONN, (void *) chanp->chan); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_CONN, (void *) (long)chanp->chan); } +/* + * RESUME + */ + /* incomming call */ static void @@ -463,14 +468,14 @@ lli_start_dchan(struct FsmInst *fi, int event, void *arg) test_and_set_bit(FLG_DO_CONNECT, &chanp->Flags); else if (event == EV_HANGUP) { test_and_set_bit(FLG_DO_HANGUP, &chanp->Flags); -#ifdef ALERT_REJECT +#ifdef ALERT_REJECT test_and_set_bit(FLG_DO_ALERT, &chanp->Flags); #endif - } + } if (test_bit(FLG_ESTAB_D, &chanp->Flags)) { FsmEvent(fi, EV_DLEST, NULL); } else if (!test_and_set_bit(FLG_START_D, &chanp->Flags)) - FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL); + chanp->d_st->lli.l4l3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL); } static void @@ -479,9 +484,8 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg) struct Channel *chanp = fi->userdata; isdn_ctrl ic; int ret; - char txt[32]; - chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) chanp->chan); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); /* * Report incoming calls only once to linklevel, use CallFlags * which is set to 3 with each broadcast message in isdnl1.c @@ -491,7 +495,7 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg) FsmChangeState(fi, ST_IN_WAIT_LL); test_and_set_bit(FLG_CALL_REC, &chanp->Flags); if (chanp->debug & 1) - link_debug(chanp, "STAT_ICALL", 0); + link_debug(chanp, 0, "STAT_ICALL"); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_ICALL; ic.arg = chanp->chan; @@ -501,22 +505,21 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg) */ ic.parm.setup = chanp->proc->para.setup; ret = chanp->cs->iif.statcallb(&ic); - if (chanp->debug & 1) { - sprintf(txt, "statcallb ret=%d", ret); - link_debug(chanp, txt, 1); - } + if (chanp->debug & 1) + link_debug(chanp, 1, "statcallb ret=%d", ret); switch (ret) { case 1: /* OK, anybody likes this call */ FsmDelTimer(&chanp->drel_timer, 61); if (test_bit(FLG_ESTAB_D, &chanp->Flags)) { FsmChangeState(fi, ST_IN_ALERT_SEND); test_and_set_bit(FLG_CALL_ALERT, &chanp->Flags); - chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING_REQ, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); } else { test_and_set_bit(FLG_DO_ALERT, &chanp->Flags); FsmChangeState(fi, ST_IN_WAIT_D); test_and_set_bit(FLG_START_D, &chanp->Flags); - FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL); + chanp->d_st->lli.l4l3(chanp->d_st, + DL_ESTABLISH | REQUEST, NULL); } break; case 2: /* Rejecting Call */ @@ -524,38 +527,36 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg) break; case 0: /* OK, nobody likes this call */ default: /* statcallb problems */ - chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE, chanp->proc); - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan); + chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); FsmChangeState(fi, ST_NULL); -#ifndef LAYER2_WATCHING - if (test_bit(FLG_ESTAB_D, &chanp->Flags)) + if (test_bit(FLG_ESTAB_D, &chanp->Flags) && + !test_bit(FLG_PTP, &chanp->d_st->l2.flag)) FsmRestartTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 61); -#endif break; } } else { - chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE, chanp->proc); - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan); + chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); FsmChangeState(fi, ST_NULL); -#ifndef LAYER2_WATCHING - if (test_bit(FLG_ESTAB_D, &chanp->Flags)) + if (test_bit(FLG_ESTAB_D, &chanp->Flags) && + !test_bit(FLG_PTP, &chanp->d_st->l2.flag)) FsmRestartTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 62); -#endif } } static void lli_establish_d(struct FsmInst *fi, int event, void *arg) { - /* This establish the D-channel for pending L3 messages - * without blocking th channel + /* This establish the D-channel for pending L3 messages + * without blocking the channel */ struct Channel *chanp = fi->userdata; test_and_set_bit(FLG_DO_ESTAB, &chanp->Flags); FsmChangeState(fi, ST_IN_WAIT_D); test_and_set_bit(FLG_START_D, &chanp->Flags); - FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL); + chanp->d_st->lli.l4l3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL); } static void @@ -573,27 +574,18 @@ lli_do_action(struct FsmInst *fi, int event, void *arg) !test_bit(FLG_DO_HANGUP, &chanp->Flags)) { FsmChangeState(fi, ST_IN_WAIT_CONN_ACK); test_and_clear_bit(FLG_DO_ALERT, &chanp->Flags); - chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP_RSP, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc); } else if (test_and_clear_bit(FLG_DO_ALERT, &chanp->Flags)) { if (test_bit(FLG_DO_HANGUP, &chanp->Flags)) FsmRestartTimer(&chanp->drel_timer, 40, EV_HANGUP, NULL, 63); FsmChangeState(fi, ST_IN_ALERT_SEND); test_and_set_bit(FLG_CALL_ALERT, &chanp->Flags); - chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING_REQ, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); } else if (test_and_clear_bit(FLG_DO_HANGUP, &chanp->Flags)) { FsmChangeState(fi, ST_WAIT_DRELEASE); chanp->proc->para.cause = 0x15; /* Call Rejected */ - chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT_REQ, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc); test_and_set_bit(FLG_DISC_SEND, &chanp->Flags); - } else if (test_and_clear_bit(FLG_DO_ESTAB, &chanp->Flags)) { - FsmChangeState(fi, ST_NULL); - chanp->Flags = 0; - test_and_set_bit(FLG_ESTAB_D, &chanp->Flags); - chanp->d_st->lli.l4l3(chanp->d_st, CC_ESTABLISH, chanp->proc); - chanp->proc = NULL; -#ifndef LAYER2_WATCHING - FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 60); -#endif } } @@ -603,7 +595,7 @@ lli_send_dconnect(struct FsmInst *fi, int event, void *arg) struct Channel *chanp = fi->userdata; FsmChangeState(fi, ST_IN_WAIT_CONN_ACK); - chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP_RSP, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc); } static void @@ -615,29 +607,26 @@ lli_init_bchan_in(struct FsmInst *fi, int event, void *arg) FsmChangeState(fi, ST_WAIT_BCONN); test_and_set_bit(FLG_LL_DCONN, &chanp->Flags); if (chanp->debug & 1) - link_debug(chanp, "STAT_DCONN", 0); + link_debug(chanp, 0, "STAT_DCONN"); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_DCONN; ic.arg = chanp->chan; chanp->cs->iif.statcallb(&ic); chanp->l2_active_protocol = chanp->l2_protocol; chanp->incoming = !0; - chanp->lc_b->l2_start = 0; - switch (chanp->l2_active_protocol) { - case (ISDN_PROTO_L2_X75I): - chanp->lc_b->l2_establish = !0; - break; - case (ISDN_PROTO_L2_HDLC): - case (ISDN_PROTO_L2_TRANS): - chanp->lc_b->l2_establish = 0; - break; - default: - printk(KERN_WARNING "bchannel unknown protocol\n"); - break; - } init_b_st(chanp, !0); test_and_set_bit(FLG_START_B, &chanp->Flags); - FsmEvent(&chanp->lc_b->lcfi, EV_LC_ESTABLISH, NULL); + chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL); +} + +/* Call suspend */ + +static void +lli_suspend(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + chanp->d_st->lli.l4l3(chanp->d_st, CC_SUSPEND | REQUEST, chanp->proc); } /* Call clearing */ @@ -651,7 +640,7 @@ lli_cancel_call(struct FsmInst *fi, int event, void *arg) FsmChangeState(fi, ST_WAIT_DRELEASE); if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) { if (chanp->debug & 1) - link_debug(chanp, "STAT_BHUP", 0); + link_debug(chanp, 0, "STAT_BHUP"); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_BHUP; ic.arg = chanp->chan; @@ -660,7 +649,7 @@ lli_cancel_call(struct FsmInst *fi, int event, void *arg) if (test_and_clear_bit(FLG_START_B, &chanp->Flags)) release_b_st(chanp); chanp->proc->para.cause = 0x10; /* Normal Call Clearing */ - chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT_REQ, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc); test_and_set_bit(FLG_DISC_SEND, &chanp->Flags); } @@ -670,22 +659,22 @@ lli_shutdown_d(struct FsmInst *fi, int event, void *arg) struct Channel *chanp = fi->userdata; FsmDelTimer(&chanp->drel_timer, 62); -#ifdef LAYER2_WATCHING - FsmChangeState(fi, ST_NULL); -#else - if (!test_bit(FLG_TWO_DCHAN, &chanp->cs->HW_Flags)) { - if (chanp->chan) { - if (chanp->cs->channel[0].fi.state != ST_NULL) - return; - } else { - if (chanp->cs->channel[1].fi.state != ST_NULL) - return; + if (test_bit(FLG_PTP, &chanp->d_st->l2.flag)) { + FsmChangeState(fi, ST_NULL); + } else { + if (!test_bit(FLG_TWO_DCHAN, &chanp->cs->HW_Flags)) { + if (chanp->chan) { + if (chanp->cs->channel[0].fi.state != ST_NULL) + return; + } else { + if (chanp->cs->channel[1].fi.state != ST_NULL) + return; + } } + FsmChangeState(fi, ST_WAIT_DSHUTDOWN); + test_and_clear_bit(FLG_ESTAB_D, &chanp->Flags); + chanp->d_st->lli.l4l3(chanp->d_st, DL_RELEASE | REQUEST, NULL); } - FsmChangeState(fi, ST_WAIT_DSHUTDOWN); - test_and_clear_bit(FLG_ESTAB_D, &chanp->Flags); - FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL); -#endif } static void @@ -694,22 +683,20 @@ lli_timeout_d(struct FsmInst *fi, int event, void *arg) struct Channel *chanp = fi->userdata; isdn_ctrl ic; - if (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); - lli_deliver_cause(chanp); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - } + test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags); + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_DHUP"); + lli_deliver_cause(chanp, &ic); + ic.driver = chanp->cs->myid; + ic.command = ISDN_STAT_DHUP; + ic.arg = chanp->chan; + chanp->cs->iif.statcallb(&ic); FsmChangeState(fi, ST_NULL); chanp->Flags = 0; test_and_set_bit(FLG_ESTAB_D, &chanp->Flags); -#ifndef LAYER2_WATCHING - FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 60); -#endif - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan); + if (!test_bit(FLG_PTP, &chanp->d_st->l2.flag)) + FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 60); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); } static void @@ -720,7 +707,7 @@ lli_go_null(struct FsmInst *fi, int event, void *arg) FsmChangeState(fi, ST_NULL); chanp->Flags = 0; FsmDelTimer(&chanp->drel_timer, 63); - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); } static void @@ -731,7 +718,7 @@ lli_disconn_bchan(struct FsmInst *fi, int event, void *arg) chanp->data_open = 0; FsmChangeState(fi, ST_WAIT_BRELEASE); test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags); - FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL); + chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); } static void @@ -746,7 +733,7 @@ lli_send_d_disc(struct FsmInst *fi, int event, void *arg) FsmChangeState(fi, ST_WAIT_DRELEASE); if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) { if (chanp->debug & 1) - link_debug(chanp, "STAT_BHUP", 0); + link_debug(chanp, 0, "STAT_BHUP"); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_BHUP; ic.arg = chanp->chan; @@ -760,20 +747,20 @@ lli_send_d_disc(struct FsmInst *fi, int event, void *arg) sprintf(ic.parm.num, "L0010"); chanp->cs->iif.statcallb(&ic); if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); + link_debug(chanp, 0, "STAT_DHUP"); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_DHUP; ic.arg = chanp->chan; chanp->cs->iif.statcallb(&ic); FsmChangeState(fi, ST_WAIT_DSHUTDOWN); test_and_clear_bit(FLG_ESTAB_D, &chanp->Flags); - FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL); + chanp->d_st->lli.l4l3(chanp->d_st, DL_RELEASE | REQUEST, NULL); } else { if (test_and_clear_bit(FLG_DO_HANGUP, &chanp->Flags)) chanp->proc->para.cause = 0x15; /* Call Reject */ else chanp->proc->para.cause = 0x10; /* Normal Call Clearing */ - chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT_REQ, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc); test_and_set_bit(FLG_DISC_SEND, &chanp->Flags); } } @@ -788,7 +775,7 @@ lli_released_bchan(struct FsmInst *fi, int event, void *arg) chanp->data_open = 0; if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) { if (chanp->debug & 1) - link_debug(chanp, "STAT_BHUP", 0); + link_debug(chanp, 0, "STAT_BHUP"); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_BHUP; ic.arg = chanp->chan; @@ -808,7 +795,7 @@ lli_release_bchan(struct FsmInst *fi, int event, void *arg) test_and_set_bit(FLG_DISC_REC, &chanp->Flags); FsmChangeState(fi, ST_WAIT_BREL_DISC); test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags); - FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL); + chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); } static void @@ -821,12 +808,11 @@ lli_received_d_rel(struct FsmInst *fi, int event, void *arg) FsmChangeState(fi, ST_NULL); test_and_set_bit(FLG_REL_REC, &chanp->Flags); if (test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags)) { - chanp->lc_b->l2_establish = 0; /* direct reset in lc_b->lcfi */ - FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL); + chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); } if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) { if (chanp->debug & 1) - link_debug(chanp, "STAT_BHUP", 0); + link_debug(chanp, 0, "STAT_BHUP"); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_BHUP; ic.arg = chanp->chan; @@ -834,17 +820,13 @@ lli_received_d_rel(struct FsmInst *fi, int event, void *arg) } if (test_and_clear_bit(FLG_START_B, &chanp->Flags)) release_b_st(chanp); - if (test_bit(FLG_LL_DCONN, &chanp->Flags) || - test_bit(FLG_CALL_SEND, &chanp->Flags) || - test_bit(FLG_CALL_ALERT, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); - lli_deliver_cause(chanp); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - } + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_DHUP"); + lli_deliver_cause(chanp, &ic); + ic.driver = chanp->cs->myid; + ic.command = ISDN_STAT_DHUP; + ic.arg = chanp->chan; + chanp->cs->iif.statcallb(&ic); test_and_clear_bit(FLG_DISC_SEND, &chanp->Flags); test_and_clear_bit(FLG_CALL_REC, &chanp->Flags); test_and_clear_bit(FLG_CALL_ALERT, &chanp->Flags); @@ -862,12 +844,11 @@ lli_received_d_relcnf(struct FsmInst *fi, int event, void *arg) chanp->data_open = 0; FsmChangeState(fi, ST_NULL); if (test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags)) { - chanp->lc_b->l2_establish = 0; /* direct reset in lc_b->lcfi */ - FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL); + chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); } if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) { if (chanp->debug & 1) - link_debug(chanp, "STAT_BHUP", 0); + link_debug(chanp, 0, "STAT_BHUP"); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_BHUP; ic.arg = chanp->chan; @@ -875,17 +856,13 @@ lli_received_d_relcnf(struct FsmInst *fi, int event, void *arg) } if (test_and_clear_bit(FLG_START_B, &chanp->Flags)) release_b_st(chanp); - if (test_bit(FLG_LL_DCONN, &chanp->Flags) || - test_bit(FLG_CALL_SEND, &chanp->Flags) || - test_bit(FLG_CALL_ALERT, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); - lli_deliver_cause(chanp); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - } + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_DHUP"); + lli_deliver_cause(chanp, &ic); + ic.driver = chanp->cs->myid; + ic.command = ISDN_STAT_DHUP; + ic.arg = chanp->chan; + chanp->cs->iif.statcallb(&ic); test_and_clear_bit(FLG_DISC_SEND, &chanp->Flags); test_and_clear_bit(FLG_CALL_REC, &chanp->Flags); test_and_clear_bit(FLG_CALL_ALERT, &chanp->Flags); @@ -905,7 +882,7 @@ lli_received_d_disc(struct FsmInst *fi, int event, void *arg) test_and_set_bit(FLG_DISC_REC, &chanp->Flags); if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) { if (chanp->debug & 1) - link_debug(chanp, "STAT_BHUP", 0); + link_debug(chanp, 0, "STAT_BHUP"); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_BHUP; ic.arg = chanp->chan; @@ -913,21 +890,17 @@ lli_received_d_disc(struct FsmInst *fi, int event, void *arg) } if (test_and_clear_bit(FLG_START_B, &chanp->Flags)) release_b_st(chanp); - if (test_bit(FLG_LL_DCONN, &chanp->Flags) || - test_bit(FLG_CALL_SEND, &chanp->Flags) || - test_bit(FLG_CALL_ALERT, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); - lli_deliver_cause(chanp); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - } + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_DHUP"); + lli_deliver_cause(chanp, &ic); + ic.driver = chanp->cs->myid; + ic.command = ISDN_STAT_DHUP; + ic.arg = chanp->chan; + chanp->cs->iif.statcallb(&ic); test_and_clear_bit(FLG_CALL_ALERT, &chanp->Flags); test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags); test_and_clear_bit(FLG_CALL_SEND, &chanp->Flags); - chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE_REQ, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE | REQUEST, chanp->proc); } /* processing charge info */ @@ -953,14 +926,14 @@ lli_no_dchan(struct FsmInst *fi, int event, void *arg) isdn_ctrl ic; if (chanp->debug & 1) - link_debug(chanp, "STAT_NODCH", 0); + link_debug(chanp, 0, "STAT_NODCH"); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_NODCH; ic.arg = chanp->chan; chanp->cs->iif.statcallb(&ic); chanp->Flags = 0; FsmChangeState(fi, ST_NULL); - FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL); + chanp->d_st->lli.l4l3(chanp->d_st, DL_RELEASE | REQUEST, NULL); } static void @@ -970,7 +943,7 @@ lli_no_dchan_ready(struct FsmInst *fi, int event, void *arg) isdn_ctrl ic; if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); + link_debug(chanp, 0, "STAT_DHUP"); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_DHUP; ic.arg = chanp->chan; @@ -984,15 +957,15 @@ lli_no_dchan_in(struct FsmInst *fi, int event, void *arg) isdn_ctrl ic; if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); + link_debug(chanp, 0, "STAT_DHUP"); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_DHUP; ic.arg = chanp->chan; chanp->cs->iif.statcallb(&ic); - chanp->d_st->lli.l4l3(chanp->d_st, CC_DLRL, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_DLRL | REQUEST, chanp->proc); chanp->Flags = 0; FsmChangeState(fi, ST_NULL); - FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL); + chanp->d_st->lli.l4l3(chanp->d_st, DL_RELEASE | REQUEST, NULL); } static void @@ -1004,7 +977,7 @@ lli_no_setup_rsp(struct FsmInst *fi, int event, void *arg) FsmChangeState(fi, ST_NULL); test_and_clear_bit(FLG_CALL_SEND, &chanp->Flags); if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); + link_debug(chanp, 0, "STAT_DHUP"); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_DHUP; ic.arg = chanp->chan; @@ -1019,15 +992,14 @@ lli_setup_err(struct FsmInst *fi, int event, void *arg) isdn_ctrl ic; FsmChangeState(fi, ST_WAIT_DRELEASE); - if (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); - lli_deliver_cause(chanp); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - } + test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags); + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_DHUP"); + lli_deliver_cause(chanp, &ic); + ic.driver = chanp->cs->myid; + ic.command = ISDN_STAT_DHUP; + ic.arg = chanp->chan; + chanp->cs->iif.statcallb(&ic); test_and_set_bit(FLG_DISC_SEND, &chanp->Flags); /* DISCONN was sent from L3 */ } @@ -1038,15 +1010,14 @@ lli_connect_err(struct FsmInst *fi, int event, void *arg) isdn_ctrl ic; FsmChangeState(fi, ST_WAIT_DRELEASE); - if (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); - lli_deliver_cause(chanp); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - } + test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags); + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_DHUP"); + lli_deliver_cause(chanp, &ic); + ic.driver = chanp->cs->myid; + ic.command = ISDN_STAT_DHUP; + ic.arg = chanp->chan; + chanp->cs->iif.statcallb(&ic); test_and_set_bit(FLG_DISC_SEND, &chanp->Flags); /* DISCONN was sent from L3 */ } @@ -1059,12 +1030,11 @@ lli_got_dlrl(struct FsmInst *fi, int event, void *arg) chanp->data_open = 0; FsmChangeState(fi, ST_NULL); if (test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags)) { - chanp->lc_b->l2_establish = 0; /* direct reset in lc_b->lcfi */ - FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL); + chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); } if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) { if (chanp->debug & 1) - link_debug(chanp, "STAT_BHUP", 0); + link_debug(chanp, 0, "STAT_BHUP"); ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_BHUP; ic.arg = chanp->chan; @@ -1084,33 +1054,33 @@ lli_got_dlrl(struct FsmInst *fi, int event, void *arg) chanp->cs->iif.statcallb(&ic); chanp->Flags = 0; } else { - if (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); - if (chanp->cs->protocol == ISDN_PTYPE_EURO) { - chanp->proc->para.cause = 0x2f; - chanp->proc->para.loc = 0; - } else { - chanp->proc->para.cause = 0x70; - chanp->proc->para.loc = 0; - } - lli_deliver_cause(chanp); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); + test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags); + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_DHUP"); + if (chanp->cs->protocol == ISDN_PTYPE_EURO) { + chanp->proc->para.cause = 0x2f; + chanp->proc->para.loc = 0; + } else { + chanp->proc->para.cause = 0x70; + chanp->proc->para.loc = 0; } - chanp->d_st->lli.l4l3(chanp->d_st, CC_DLRL, chanp->proc); + lli_deliver_cause(chanp, &ic); + ic.driver = chanp->cs->myid; + ic.command = ISDN_STAT_DHUP; + ic.arg = chanp->chan; + chanp->cs->iif.statcallb(&ic); + chanp->d_st->lli.l4l3(chanp->d_st, CC_DLRL | REQUEST, chanp->proc); chanp->Flags = 0; - FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL); + chanp->d_st->lli.l4l3(chanp->d_st, DL_RELEASE | REQUEST, NULL); } - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); } /* *INDENT-OFF* */ static struct FsmNode fnlist[] HISAX_INITDATA = { {ST_NULL, EV_DIAL, lli_prep_dialout}, + {ST_NULL, EV_RESUME, lli_prep_dialout}, {ST_NULL, EV_SETUP_IND, lli_deliver_call}, {ST_NULL, EV_SHUTDOWN_D, lli_shutdown_d}, {ST_NULL, EV_DLRL, lli_go_null}, @@ -1162,6 +1132,7 @@ static struct FsmNode fnlist[] HISAX_INITDATA = {ST_WAIT_BCONN, EV_CINF, lli_charge_info}, {ST_ACTIVE, EV_CINF, lli_charge_info}, {ST_ACTIVE, EV_BC_REL, lli_released_bchan}, + {ST_ACTIVE, EV_SUSPEND, lli_suspend}, {ST_ACTIVE, EV_HANGUP, lli_disconn_bchan}, {ST_ACTIVE, EV_DISCONNECT_IND, lli_release_bchan}, {ST_ACTIVE, EV_RELEASE_CNF, lli_received_d_relcnf}, @@ -1195,6 +1166,7 @@ static struct FsmNode fnlist[] HISAX_INITDATA = {ST_WAIT_DSHUTDOWN, EV_DLRL, lli_go_null}, {ST_WAIT_DSHUTDOWN, EV_DLEST, lli_d_established}, {ST_WAIT_DSHUTDOWN, EV_DIAL, lli_prep_dialout}, + {ST_WAIT_DSHUTDOWN, EV_RESUME, lli_prep_dialout}, {ST_WAIT_DSHUTDOWN, EV_SETUP_IND, lli_deliver_call}, }; /* *INDENT-ON* */ @@ -1202,153 +1174,6 @@ static struct FsmNode fnlist[] HISAX_INITDATA = #define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode)) -static void -lc_activate_l1(struct FsmInst *fi, int event, void *arg) -{ - struct LcFsm *lf = fi->userdata; - - FsmDelTimer(&lf->act_timer, 50); - FsmChangeState(fi, ST_LC_ACTIVATE_WAIT); - /* This timeout is to avoid a hang if no L1 activation is possible */ - FsmAddTimer(&lf->act_timer, 30000, EV_LC_TIMER, NULL, 50); - lf->st->ma.manl1(lf->st, PH_ACTIVATE_REQ, NULL); -} - -static void -lc_activated_from_l1(struct FsmInst *fi, int event, void *arg) -{ - struct LcFsm *lf = fi->userdata; - - if (lf->l2_establish) - FsmChangeState(fi, ST_LC_DELAY); - else { - FsmChangeState(fi, ST_LC_CONNECTED); - lf->lccall(lf, LC_ESTABLISH, NULL); - } -} - -static void -lc_l1_activated(struct FsmInst *fi, int event, void *arg) -{ - struct LcFsm *lf = fi->userdata; - - FsmDelTimer(&lf->act_timer, 50); - FsmChangeState(fi, ST_LC_DELAY); - /* This timer is needed for delay the first paket on a channel - to be shure that the other side is ready too */ - if (lf->delay) - FsmAddTimer(&lf->act_timer, lf->delay, EV_LC_TIMER, NULL, 51); - else - FsmEvent(fi, EV_LC_TIMER, NULL); -} - -static void -lc_start_l2(struct FsmInst *fi, int event, void *arg) -{ - struct LcFsm *lf = fi->userdata; - -/* if (!lf->st->l1.act_state) - lf->st->l1.act_state = 2; -*/ if (lf->l2_establish) { - FsmChangeState(fi, ST_LC_ESTABLISH_WAIT); - if (lf->l2_start) - lf->st->ma.manl2(lf->st, DL_ESTABLISH, NULL); - } else { - FsmChangeState(fi, ST_LC_CONNECTED); - lf->lccall(lf, LC_ESTABLISH, NULL); - } -} - -static void -lc_connected(struct FsmInst *fi, int event, void *arg) -{ - struct LcFsm *lf = fi->userdata; - - FsmDelTimer(&lf->act_timer, 50); - FsmChangeState(fi, ST_LC_CONNECTED); - lf->lccall(lf, LC_ESTABLISH, NULL); -} - -static void -lc_release_l2(struct FsmInst *fi, int event, void *arg) -{ - struct LcFsm *lf = fi->userdata; - - if (lf->l2_establish) { - FsmChangeState(fi, ST_LC_RELEASE_WAIT); - lf->st->ma.manl2(lf->st, DL_RELEASE, NULL); - } else { - FsmChangeState(fi, ST_LC_NULL); - lf->st->ma.manl1(lf->st, PH_DEACTIVATE_REQ, NULL); - lf->lccall(lf, LC_RELEASE, NULL); - } -} - -static void -lc_l2_released(struct FsmInst *fi, int event, void *arg) -{ - struct LcFsm *lf = fi->userdata; - - FsmChangeState(fi, ST_LC_RELEASE_WAIT); - FsmDelTimer(&lf->act_timer, 51); - /* This delay is needed for send out the UA frame before - * PH_DEACTIVATE the interface - */ - FsmAddTimer(&lf->act_timer, 20, EV_LC_TIMER, NULL, 54); -} - -static void -lc_release_l1(struct FsmInst *fi, int event, void *arg) -{ - struct LcFsm *lf = fi->userdata; - - FsmDelTimer(&lf->act_timer, 54); - FsmChangeState(fi, ST_LC_NULL); - lf->st->ma.manl1(lf->st, PH_DEACTIVATE_REQ, NULL); - lf->lccall(lf, LC_RELEASE, NULL); -} - -static void -lc_l1_deactivated(struct FsmInst *fi, int event, void *arg) -{ - struct LcFsm *lf = fi->userdata; - - FsmDelTimer(&lf->act_timer, 54); - FsmChangeState(fi, ST_LC_NULL); - lf->lccall(lf, LC_RELEASE, NULL); -} -/* *INDENT-OFF* */ -static struct FsmNode LcFnList[] HISAX_INITDATA = -{ - {ST_LC_NULL, EV_LC_ESTABLISH, lc_activate_l1}, - {ST_LC_NULL, EV_LC_PH_ACTIVATE, lc_activated_from_l1}, - {ST_LC_NULL, EV_LC_DL_ESTABLISH, lc_connected}, - {ST_LC_ACTIVATE_WAIT, EV_LC_PH_ACTIVATE, lc_l1_activated}, - {ST_LC_ACTIVATE_WAIT, EV_LC_TIMER, lc_release_l1}, - {ST_LC_ACTIVATE_WAIT, EV_LC_PH_DEACTIVATE, lc_l1_deactivated}, - {ST_LC_DELAY, EV_LC_ESTABLISH, lc_start_l2}, - {ST_LC_DELAY, EV_LC_TIMER, lc_start_l2}, - {ST_LC_DELAY, EV_LC_DL_ESTABLISH, lc_connected}, - {ST_LC_DELAY, EV_LC_PH_DEACTIVATE, lc_l1_deactivated}, - {ST_LC_ESTABLISH_WAIT, EV_LC_DL_ESTABLISH, lc_connected}, - {ST_LC_ESTABLISH_WAIT, EV_LC_RELEASE, lc_release_l1}, - {ST_LC_ESTABLISH_WAIT, EV_LC_DL_RELEASE, lc_release_l1}, - {ST_LC_ESTABLISH_WAIT, EV_LC_PH_DEACTIVATE, lc_l1_deactivated}, - {ST_LC_CONNECTED, EV_LC_ESTABLISH, lc_connected}, - {ST_LC_CONNECTED, EV_LC_RELEASE, lc_release_l2}, - {ST_LC_CONNECTED, EV_LC_DL_RELEASE, lc_l2_released}, - {ST_LC_CONNECTED, EV_LC_PH_DEACTIVATE, lc_l1_deactivated}, - {ST_LC_FLUSH_WAIT, EV_LC_TIMER, lc_release_l2}, - {ST_LC_FLUSH_WAIT, EV_LC_PH_DEACTIVATE, lc_l1_deactivated}, - {ST_LC_RELEASE_WAIT, EV_LC_DL_RELEASE, lc_release_l1}, - {ST_LC_RELEASE_WAIT, EV_LC_TIMER, lc_release_l1}, - {ST_LC_FLUSH_WAIT, EV_LC_PH_DEACTIVATE, lc_l1_deactivated}, -}; -/* *INDENT-ON* */ - - -#define LC_FN_COUNT (sizeof(LcFnList)/sizeof(struct FsmNode)) - HISAX_INITFUNC(void CallcNew(void)) { @@ -1357,18 +1182,11 @@ CallcNew(void)) callcfsm.strEvent = strEvent; callcfsm.strState = strState; FsmNew(&callcfsm, fnlist, FNCOUNT); - - lcfsm.state_count = LC_STATE_COUNT; - lcfsm.event_count = LC_EVENT_COUNT; - lcfsm.strEvent = strLcEvent; - lcfsm.strState = strLcState; - FsmNew(&lcfsm, LcFnList, LC_FN_COUNT); } void CallcFree(void) { - FsmFree(&lcfsm); FsmFree(&callcfsm); } @@ -1384,75 +1202,10 @@ release_b_st(struct Channel *chanp) break; case (ISDN_PROTO_L2_HDLC): case (ISDN_PROTO_L2_TRANS): +// case (ISDN_PROTO_L2_MODEM): releasestack_transl2(st); break; } - /* Reset B-Channel Statemachine */ - FsmDelTimer(&chanp->lc_b->act_timer, 79); - FsmChangeState(&chanp->lc_b->lcfi, ST_LC_NULL); -} - -static void -dc_l1man(struct PStack *st, int pr, void *arg) -{ - struct Channel *chanp; - - chanp = (struct Channel *) st->lli.userdata; - switch (pr) { - case (PH_ACTIVATE_CNF): - case (PH_ACTIVATE_IND): - FsmEvent(&chanp->lc_d->lcfi, EV_LC_PH_ACTIVATE, NULL); - break; - case (PH_DEACTIVATE_IND): - FsmEvent(&chanp->lc_d->lcfi, EV_LC_PH_DEACTIVATE, NULL); - break; - } -} - -static void -dc_l2man(struct PStack *st, int pr, void *arg) -{ - struct Channel *chanp = (struct Channel *) st->lli.userdata; - - switch (pr) { - case (DL_ESTABLISH): - FsmEvent(&chanp->lc_d->lcfi, EV_LC_DL_ESTABLISH, NULL); - break; - case (DL_RELEASE): - FsmEvent(&chanp->lc_d->lcfi, EV_LC_DL_RELEASE, NULL); - break; - } -} - -static void -bc_l1man(struct PStack *st, int pr, void *arg) -{ - struct Channel *chanp = (struct Channel *) st->lli.userdata; - - switch (pr) { - case (PH_ACTIVATE_IND): - case (PH_ACTIVATE_CNF): - FsmEvent(&chanp->lc_b->lcfi, EV_LC_PH_ACTIVATE, NULL); - break; - case (PH_DEACTIVATE_IND): - FsmEvent(&chanp->lc_b->lcfi, EV_LC_PH_DEACTIVATE, NULL); - break; - } -} - -static void -bc_l2man(struct PStack *st, int pr, void *arg) -{ - struct Channel *chanp = (struct Channel *) st->lli.userdata; - - switch (pr) { - case (DL_ESTABLISH): - FsmEvent(&chanp->lc_b->lcfi, EV_LC_DL_ESTABLISH, NULL); - break; - case (DL_RELEASE): - FsmEvent(&chanp->lc_b->lcfi, EV_LC_DL_RELEASE, NULL); - break; - } } struct Channel @@ -1471,7 +1224,7 @@ struct Channel return (chanp); chanp++; i++; - } + } return (NULL); } @@ -1491,62 +1244,85 @@ is_activ(struct PStack *st) return (1); chanp++; i++; - } + } return (0); } static void -ll_handler(struct l3_process *pc, int pr, void *arg) +dchan_l3l4(struct PStack *st, int pr, void *arg) { + struct l3_process *pc = arg; + struct IsdnCardState *cs = st->l1.hardware; struct Channel *chanp; - char tmp[64], tm[32]; + int event; + + switch (pr) { + case (DL_ESTABLISH | INDICATION): + event = EV_DLEST; + break; + case (DL_RELEASE | INDICATION): + event = EV_DLRL; + break; + default: + event = -1; + break; + } + if (event >= 0) { + int i; - if (pr == CC_SETUP_IND) { + chanp = st->lli.userdata; + if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags)) + i = 1; + else + i = 0; + while (i < 2) { + FsmEvent(&chanp->fi, event, NULL); + chanp++; + i++; + } + return; + } else if (pr == (CC_SETUP | INDICATION)) { if (!(chanp = selectfreechannel(pc->st))) { - pc->st->lli.l4l3(pc->st, CC_DLRL, pc); - return; + pc->st->lli.l4l3(pc->st, CC_DLRL | REQUEST, pc); } else { chanp->proc = pc; pc->chan = chanp; FsmEvent(&chanp->fi, EV_SETUP_IND, NULL); - return; } - } else if (pr == CC_ESTABLISH) { - if (is_activ(pc->st)) { - pc->st->lli.l4l3(pc->st, CC_ESTABLISH, pc); - return; - } else if (!(chanp = selectfreechannel(pc->st))) { - pc->st->lli.l4l3(pc->st, CC_DLRL, pc); - return; - } else { - chanp->proc = pc; - FsmEvent(&chanp->fi, EV_ESTABLISH, NULL); - return; - } - - + return; } - chanp = pc->chan; + if (!(chanp = pc->chan)) + return; + switch (pr) { - case (CC_DISCONNECT_IND): + case (CC_DISCONNECT | INDICATION): FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL); break; - case (CC_RELEASE_CNF): + case (CC_RELEASE | CONFIRM): + FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL); + break; + case (CC_SUSPEND | CONFIRM): FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL); break; - case (CC_RELEASE_IND): + case (CC_RESUME | CONFIRM): + FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL); + break; + case (CC_RESUME_ERR): + FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL); + break; + case (CC_RELEASE | INDICATION): FsmEvent(&chanp->fi, EV_RELEASE_IND, NULL); break; - case (CC_SETUP_COMPLETE_IND): + case (CC_SETUP_COMPL | INDICATION): FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL); break; - case (CC_SETUP_CNF): + case (CC_SETUP | CONFIRM): FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL); break; - case (CC_INFO_CHARGE): + case (CC_CHARGE | INDICATION): FsmEvent(&chanp->fi, EV_CINF, NULL); break; - case (CC_NOSETUP_RSP_ERR): + case (CC_NOSETUP_RSP): FsmEvent(&chanp->fi, EV_NOSETUP_RSP, NULL); break; case (CC_SETUP_ERR): @@ -1558,15 +1334,14 @@ ll_handler(struct l3_process *pc, int pr, void *arg) case (CC_RELEASE_ERR): FsmEvent(&chanp->fi, EV_RELEASE_ERR, NULL); break; - case (CC_PROCEEDING_IND): - case (CC_ALERTING_IND): + case (CC_PROCEEDING | INDICATION): + case (CC_ALERTING | INDICATION): break; default: if (chanp->debug & 0x800) { - jiftime(tm, jiffies); - sprintf(tmp, "%s Channel %d L3->L4 unknown primitiv %d\n", - tm, chanp->chan, pr); - HiSax_putstatus(chanp->cs, tmp); + HiSax_putstatus(chanp->cs, "Ch", + "%d L3->L4 unknown primitiv %x", + chanp->chan, pr); } } } @@ -1576,7 +1351,7 @@ init_d_st(struct Channel *chanp) { struct PStack *st = chanp->d_st; struct IsdnCardState *cs = chanp->cs; - char tmp[128]; + char tmp[16]; HiSax_addlist(cs, st); setstack_HiSax(st, cs); @@ -1590,95 +1365,50 @@ init_d_st(struct Channel *chanp) st->l2.window = 1; st->l2.T200 = 1000; /* 1000 milliseconds */ st->l2.N200 = 3; /* try 3 times */ - if (st->protocol == ISDN_PTYPE_1TR6) - st->l2.T203 = 10000; /* 10000 milliseconds */ + st->l2.T203 = 10000; /* 10000 milliseconds */ + if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags)) + sprintf(tmp, "DCh%d Q.921 ", chanp->chan); else - st->l2.T203 = 10000; /* 5000 milliseconds */ - - sprintf(tmp, "Channel %d q.921", chanp->chan); + sprintf(tmp, "DCh Q.921 "); setstack_isdnl2(st, tmp); - setstack_isdnl3(st, chanp); + setstack_l3dc(st, chanp); st->lli.userdata = chanp; st->lli.l2writewakeup = NULL; - st->l3.l3l4 = ll_handler; - st->l1.l1man = dc_l1man; - st->l2.l2man = dc_l2man; + st->l3.l3l4 = dchan_l3l4; } static void -callc_debug(struct FsmInst *fi, char *s) +callc_debug(struct FsmInst *fi, char *fmt, ...) { - char str[80], tm[32]; + va_list args; struct Channel *chanp = fi->userdata; + char tmp[16]; - jiftime(tm, jiffies); - sprintf(str, "%s Channel %d callc %s\n", tm, chanp->chan, s); - HiSax_putstatus(chanp->cs, str); -} - -static void -lc_debug(struct FsmInst *fi, char *s) -{ - char str[256], tm[32]; - struct LcFsm *lf = fi->userdata; - - jiftime(tm, jiffies); - sprintf(str, "%s Channel %d dc %s\n", tm, lf->ch->chan, s); - HiSax_putstatus(lf->ch->cs, str); -} - -static void -dlc_debug(struct FsmInst *fi, char *s) -{ - char str[256], tm[32]; - struct LcFsm *lf = fi->userdata; - - jiftime(tm, jiffies); - sprintf(str, "%s Channel %d bc %s\n", tm, lf->ch->chan, s); - HiSax_putstatus(lf->ch->cs, str); + va_start(args, fmt); + sprintf(tmp, "Ch%d callc ", chanp->chan); + VHiSax_putstatus(chanp->cs, tmp, fmt, args); + va_end(args); } static void -lccall_d(struct LcFsm *lf, int pr, void *arg) -{ - struct IsdnCardState *cs = lf->st->l1.hardware; - struct Channel *chanp; - int i; - - if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags)) { - chanp = lf->ch; - i = 1; - } else { - chanp = cs->channel; - i = 0; - } - while (i < 2) { - switch (pr) { - case (LC_ESTABLISH): - FsmEvent(&chanp->fi, EV_DLEST, NULL); - break; - case (LC_RELEASE): - FsmEvent(&chanp->fi, EV_DLRL, NULL); - break; - } - chanp++; - i++; - } +dummy_pstack(struct PStack *st, int pr, void *arg) { + printk(KERN_WARNING"call to dummy_pstack pr=%04x arg %lx\n", pr, (long)arg); } static void -lccall_b(struct LcFsm *lf, int pr, void *arg) -{ - struct Channel *chanp = lf->ch; - - switch (pr) { - case (LC_ESTABLISH): - FsmEvent(&chanp->fi, EV_BC_EST, NULL); - break; - case (LC_RELEASE): - FsmEvent(&chanp->fi, EV_BC_REL, NULL); - break; - } +init_PStack(struct PStack **stp) { + *stp = kmalloc(sizeof(struct PStack), GFP_ATOMIC); + (*stp)->next = NULL; + (*stp)->l1.l1l2 = dummy_pstack; + (*stp)->l1.l1hw = dummy_pstack; + (*stp)->l1.l1tei = dummy_pstack; + (*stp)->l2.l2tei = dummy_pstack; + (*stp)->l2.l2l1 = dummy_pstack; + (*stp)->l2.l2l3 = dummy_pstack; + (*stp)->l3.l3l2 = dummy_pstack; + (*stp)->l3.l3l4 = dummy_pstack; + (*stp)->lli.l4l3 = dummy_pstack; + (*stp)->ma.layer = dummy_pstack; } static void @@ -1693,9 +1423,8 @@ init_chan(int chan, struct IsdnCardState *csta) chanp->debug = 0; chanp->Flags = 0; chanp->leased = 0; - chanp->b_st = kmalloc(sizeof(struct PStack), GFP_ATOMIC); - chanp->b_st->next = NULL; - + init_PStack(&chanp->b_st); + chanp->b_st->l1.delay = DEFAULT_B_DELAY; chanp->fi.fsm = &callcfsm; chanp->fi.state = ST_NULL; chanp->fi.debug = 0; @@ -1704,41 +1433,14 @@ init_chan(int chan, struct IsdnCardState *csta) FsmInitTimer(&chanp->fi, &chanp->dial_timer); FsmInitTimer(&chanp->fi, &chanp->drel_timer); if (!chan || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) { - chanp->d_st = kmalloc(sizeof(struct PStack), GFP_ATOMIC); + init_PStack(&chanp->d_st); + if (chan) + csta->channel->d_st->next = chanp->d_st; chanp->d_st->next = NULL; init_d_st(chanp); - chanp->lc_d = kmalloc(sizeof(struct LcFsm), GFP_ATOMIC); - chanp->lc_d->lcfi.fsm = &lcfsm; - chanp->lc_d->lcfi.state = ST_LC_NULL; - chanp->lc_d->lcfi.debug = 0; - chanp->lc_d->lcfi.userdata = chanp->lc_d; - chanp->lc_d->lcfi.printdebug = lc_debug; - chanp->lc_d->type = LC_D; - chanp->lc_d->delay = 0; - chanp->lc_d->ch = chanp; - chanp->lc_d->st = chanp->d_st; - chanp->lc_d->l2_establish = !0; - chanp->lc_d->l2_start = !0; - chanp->lc_d->lccall = lccall_d; - FsmInitTimer(&chanp->lc_d->lcfi, &chanp->lc_d->act_timer); } else { chanp->d_st = csta->channel->d_st; - chanp->lc_d = csta->channel->lc_d; } - chanp->lc_b = kmalloc(sizeof(struct LcFsm), GFP_ATOMIC); - chanp->lc_b->lcfi.fsm = &lcfsm; - chanp->lc_b->lcfi.state = ST_LC_NULL; - chanp->lc_b->lcfi.debug = 0; - chanp->lc_b->lcfi.userdata = chanp->lc_b; - chanp->lc_b->lcfi.printdebug = dlc_debug; - chanp->lc_b->type = LC_B; - chanp->lc_b->delay = DEFAULT_B_DELAY; - chanp->lc_b->ch = chanp; - chanp->lc_b->st = chanp->b_st; - chanp->lc_b->l2_establish = !0; - chanp->lc_b->l2_start = !0; - chanp->lc_b->lccall = lccall_b; - FsmInitTimer(&chanp->lc_b->lcfi, &chanp->lc_b->act_timer); chanp->data_open = 0; } @@ -1749,11 +1451,12 @@ CallcNewChan(struct IsdnCardState *csta) init_chan(0, csta); init_chan(1, csta); printk(KERN_INFO "HiSax: 2 channels added\n"); -#ifdef LAYER2_WATCHING - printk(KERN_INFO "LAYER2 ESTABLISH\n"); - test_and_set_bit(FLG_START_D, &csta->channel->Flags); - FsmEvent(&csta->channel->lc_d->lcfi, EV_LC_ESTABLISH, NULL); -#endif + if (test_bit(FLG_PTP, &csta->channel->d_st->l2.flag)) { + printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n"); + test_and_set_bit(FLG_START_D, &csta->channel->Flags); + csta->channel->d_st->lli.l4l3(csta->channel->d_st, + DL_ESTABLISH | REQUEST, NULL); + } return (2); } @@ -1779,8 +1482,6 @@ CallcFreeChan(struct IsdnCardState *csta) for (i = 0; i < 2; i++) { FsmDelTimer(&csta->channel[i].drel_timer, 74); FsmDelTimer(&csta->channel[i].dial_timer, 75); - FsmDelTimer(&csta->channel[i].lc_d->act_timer, 77); - FsmDelTimer(&csta->channel[i].lc_b->act_timer, 76); if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) release_d_st(csta->channel + i); if (csta->channel[i].b_st) { @@ -1790,18 +1491,8 @@ CallcFreeChan(struct IsdnCardState *csta) csta->channel[i].b_st = NULL; } else printk(KERN_WARNING "CallcFreeChan b_st ch%d allready freed\n", i); - if (csta->channel[i].lc_b) { - kfree(csta->channel[i].lc_b); - csta->channel[i].b_st = NULL; - } if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) { release_d_st(csta->channel + i); - FsmDelTimer(&csta->channel[i].lc_d->act_timer, 77); - if (csta->channel[i].lc_d) { - kfree(csta->channel[i].lc_d); - csta->channel[i].d_st = NULL; - } else - printk(KERN_WARNING "CallcFreeChan lc_d ch%d allready freed\n", i); } else csta->channel[i].d_st = NULL; } @@ -1814,15 +1505,23 @@ lldata_handler(struct PStack *st, int pr, void *arg) struct sk_buff *skb = arg; switch (pr) { - case (DL_DATA): + case (DL_DATA | INDICATION): if (chanp->data_open) chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb); else { dev_kfree_skb(skb); } break; + case (DL_ESTABLISH | INDICATION): + case (DL_ESTABLISH | CONFIRM): + FsmEvent(&chanp->fi, EV_BC_EST, NULL); + break; + case (DL_RELEASE | INDICATION): + case (DL_RELEASE | CONFIRM): + FsmEvent(&chanp->fi, EV_BC_REL, NULL); + break; default: - printk(KERN_WARNING "lldata_handler unknown primitive %d\n", + printk(KERN_WARNING "lldata_handler unknown primitive %x\n", pr); break; } @@ -1835,22 +1534,24 @@ lltrans_handler(struct PStack *st, int pr, void *arg) struct sk_buff *skb = arg; switch (pr) { - case (PH_DATA_IND): + case (PH_DATA | INDICATION): if (chanp->data_open) chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb); else { - if (chanp->lc_b->lcfi.state == ST_LC_DELAY) - FsmEvent(&chanp->lc_b->lcfi, EV_LC_DL_ESTABLISH, NULL); - if (chanp->data_open) { - link_debug(chanp, "channel now open", 0); - chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, - chanp->chan, skb); - } else - dev_kfree_skb(skb); + link_debug(chanp, 0, "channel not open"); + dev_kfree_skb(skb); } break; + case (PH_ACTIVATE | INDICATION): + case (PH_ACTIVATE | CONFIRM): + FsmEvent(&chanp->fi, EV_BC_EST, NULL); + break; + case (PH_DEACTIVATE | INDICATION): + case (PH_DEACTIVATE | CONFIRM): + FsmEvent(&chanp->fi, EV_BC_REL, NULL); + break; default: - printk(KERN_WARNING "lltrans_handler unknown primitive %d\n", + printk(KERN_WARNING "lltrans_handler unknown primitive %x\n", pr); break; } @@ -1865,7 +1566,7 @@ ll_writewakeup(struct PStack *st, int len) ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_BSENT; ic.arg = chanp->chan; - ic.parm.length = len; +// ic.parm.length = len; chanp->cs->iif.statcallb(&ic); } @@ -1874,10 +1575,27 @@ init_b_st(struct Channel *chanp, int incoming) { struct PStack *st = chanp->b_st; struct IsdnCardState *cs = chanp->cs; - char tmp[128]; + char tmp[16]; st->l1.hardware = cs; - chanp->bcs->mode = 2; + if (chanp->leased) + st->l1.bc = chanp->chan & 1; + else + st->l1.bc = chanp->proc->para.bchannel - 1; + switch (chanp->l2_active_protocol) { + case (ISDN_PROTO_L2_X75I): + case (ISDN_PROTO_L2_HDLC): + st->l1.mode = L1_MODE_HDLC; + break; + case (ISDN_PROTO_L2_TRANS): + st->l1.mode = L1_MODE_TRANS; + break; +#if 0 + case (ISDN_PROTO_L2_MODEM): + st->l1.mode = L1_MODE_MODEM; + break; +#endif + } if (chanp->bcs->BC_SetStack(st, chanp->bcs)) return (-1); st->l2.flag = 0; @@ -1892,50 +1610,87 @@ init_b_st(struct Channel *chanp, int incoming) st->l3.debug = 0; switch (chanp->l2_active_protocol) { case (ISDN_PROTO_L2_X75I): - sprintf(tmp, "Channel %d x.75", chanp->chan); + sprintf(tmp, "Ch%d X.75", chanp->chan); setstack_isdnl2(st, tmp); + setstack_l3bc(st, chanp); st->l2.l2l3 = lldata_handler; - st->l1.l1man = bc_l1man; - st->l2.l2man = bc_l2man; st->lli.userdata = chanp; st->lli.l1writewakeup = NULL; st->lli.l2writewakeup = ll_writewakeup; st->l2.l2m.debug = chanp->debug & 16; st->l2.debug = chanp->debug & 64; - st->ma.manl2(st, MDL_NOTEIPROC, NULL); - st->l1.mode = L1_MODE_HDLC; - if (chanp->leased) - st->l1.bc = chanp->chan & 1; - else - st->l1.bc = chanp->proc->para.bchannel - 1; break; case (ISDN_PROTO_L2_HDLC): - st->l1.l1l2 = lltrans_handler; - st->l1.l1man = bc_l1man; - st->lli.userdata = chanp; - st->lli.l1writewakeup = ll_writewakeup; - st->l1.mode = L1_MODE_HDLC; - if (chanp->leased) - st->l1.bc = chanp->chan & 1; - else - st->l1.bc = chanp->proc->para.bchannel - 1; - break; case (ISDN_PROTO_L2_TRANS): +// case (ISDN_PROTO_L2_MODEM): st->l1.l1l2 = lltrans_handler; - st->l1.l1man = bc_l1man; st->lli.userdata = chanp; st->lli.l1writewakeup = ll_writewakeup; - st->l1.mode = L1_MODE_TRANS; - if (chanp->leased) - st->l1.bc = chanp->chan & 1; - else - st->l1.bc = chanp->proc->para.bchannel - 1; + setstack_transl2(st); + setstack_l3bc(st, chanp); break; } return (0); } static void +leased_l4l3(struct PStack *st, int pr, void *arg) +{ + struct Channel *chanp = (struct Channel *) st->lli.userdata; + struct sk_buff *skb = arg; + + switch (pr) { + case (DL_DATA | REQUEST): + link_debug(chanp, 0, "leased line d-channel DATA"); + dev_kfree_skb(skb); + break; + case (DL_ESTABLISH | REQUEST): + st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL); + break; + case (DL_RELEASE | REQUEST): + break; + default: + printk(KERN_WARNING "transd_l4l3 unknown primitive %x\n", + pr); + break; + } +} + +static void +leased_l1l2(struct PStack *st, int pr, void *arg) +{ + struct Channel *chanp = (struct Channel *) st->lli.userdata; + struct sk_buff *skb = arg; + int i,event = EV_DLRL; + + switch (pr) { + case (PH_DATA | INDICATION): + link_debug(chanp, 0, "leased line d-channel DATA"); + dev_kfree_skb(skb); + break; + case (PH_ACTIVATE | INDICATION): + case (PH_ACTIVATE | CONFIRM): + event = EV_DLEST; + case (PH_DEACTIVATE | INDICATION): + case (PH_DEACTIVATE | CONFIRM): + if (test_bit(FLG_TWO_DCHAN, &chanp->cs->HW_Flags)) + i = 1; + else + i = 0; + while (i < 2) { + FsmEvent(&chanp->fi, event, NULL); + chanp++; + i++; + } + break; + default: + printk(KERN_WARNING + "transd_l1l2 unknown primitive %x\n", pr); + break; + } +} + +static void channel_report(struct Channel *chanp) { } @@ -1953,13 +1708,70 @@ distr_debug(struct IsdnCardState *csta, int debugflags) chanp[i].b_st->l2.l2m.debug = debugflags & 0x10; chanp[i].d_st->l2.debug = debugflags & 0x20; chanp[i].b_st->l2.debug = debugflags & 0x40; - chanp[i].lc_d->lcfi.debug = debugflags & 0x80; - chanp[i].lc_b->lcfi.debug = debugflags & 0x100; + chanp[i].d_st->l3.l3m.debug = debugflags & 0x80; + chanp[i].b_st->l3.l3m.debug = debugflags & 0x100; chanp[i].b_st->ma.tei_m.debug = debugflags & 0x200; chanp[i].b_st->ma.debug = debugflags & 0x200; chanp[i].d_st->l1.l1m.debug = debugflags & 0x1000; + chanp[i].b_st->l1.l1m.debug = debugflags & 0x2000; + } + if (debugflags & 4) + csta->debug |= DEB_DLOG_HEX; + else + csta->debug &= ~DEB_DLOG_HEX; +} + +static char tmpbuf[256]; + +static void +capi_debug(struct Channel *chanp, capi_msg *cm) +{ + char *t = tmpbuf; + + t += sprintf(tmpbuf, "%d CAPIMSG", chanp->chan); + t += QuickHex(t, (u_char *)cm, (cm->Length>50)? 50: cm->Length); + t--; + *t= 0; + HiSax_putstatus(chanp->cs, "Ch", "%d CAPIMSG %s", chanp->chan, tmpbuf); +} + +void +lli_got_fac_req(struct Channel *chanp, capi_msg *cm) { + if ((cm->para[0] != 3) || (cm->para[1] != 0)) + return; + if (cm->para[2]<3) + return; + if (cm->para[4] != 0) + return; + switch(cm->para[3]) { + case 4: /* Suspend */ + if (cm->para[5]) { + strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1); + FsmEvent(&chanp->fi, EV_SUSPEND, cm); + } + break; + case 5: /* Resume */ + if (cm->para[5]) { + strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1); + if (chanp->fi.state == ST_NULL) { + FsmEvent(&chanp->fi, EV_RESUME, cm); + } else { + FsmDelTimer(&chanp->dial_timer, 72); + FsmAddTimer(&chanp->dial_timer, 80, EV_RESUME, cm, 73); + } + } + break; + } +} + +void +lli_got_manufacturer(struct Channel *chanp, struct IsdnCardState *cs, capi_msg *cm) { + if ((cs->typ == ISDN_CTYPE_ELSA) || (cs->typ == ISDN_CTYPE_ELSA_PNP) || + (cs->typ == ISDN_CTYPE_ELSA_PCI)) { + if (cs->hw.elsa.MFlag) { + cs->cardmsg(cs, CARD_AUX_IND, cm->para); + } } - csta->dlogflag = debugflags & 4; } int @@ -1967,9 +1779,9 @@ HiSax_command(isdn_ctrl * ic) { struct IsdnCardState *csta = hisax_findcard(ic->driver); struct Channel *chanp; - char tmp[128]; int i; - unsigned int num; + u_int num; + u_long adr; if (!csta) { printk(KERN_ERR @@ -1977,32 +1789,32 @@ HiSax_command(isdn_ctrl * ic) ic->command, ic->driver); return -ENODEV; } + switch (ic->command) { case (ISDN_CMD_SETEAZ): chanp = csta->channel + ic->arg; - if (chanp->debug & 1) { - sprintf(tmp, "SETEAZ card %d %s", csta->cardnr + 1, - ic->parm.num); - link_debug(chanp, tmp, 1); - } break; + case (ISDN_CMD_SETL2): chanp = csta->channel + (ic->arg & 0xff); - if (chanp->debug & 1) { - sprintf(tmp, "SETL2 card %d %ld", csta->cardnr + 1, - ic->arg >> 8); - link_debug(chanp, tmp, 1); - } + if (chanp->debug & 1) + link_debug(chanp, 1, "SETL2 card %d %ld", + csta->cardnr + 1, ic->arg >> 8); chanp->l2_protocol = ic->arg >> 8; break; + case (ISDN_CMD_SETL3): + chanp = csta->channel + (ic->arg & 0xff); + if (chanp->debug & 1) + link_debug(chanp, 1, "SETL3 card %d %ld", + csta->cardnr + 1, ic->arg >> 8); + chanp->l3_protocol = ic->arg >> 8; + break; case (ISDN_CMD_DIAL): chanp = csta->channel + (ic->arg & 0xff); - if (chanp->debug & 1) { - sprintf(tmp, "DIAL %s -> %s (%d,%d)", + if (chanp->debug & 1) + 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); - link_debug(chanp, tmp, 1); - } + ic->parm.setup.si1, ic->parm.setup.si2); chanp->setup = ic->parm.setup; if (!strcmp(chanp->setup.eazmsn, "0")) chanp->setup.eazmsn[0] = '\0'; @@ -2018,57 +1830,54 @@ HiSax_command(isdn_ctrl * ic) case (ISDN_CMD_ACCEPTB): chanp = csta->channel + ic->arg; if (chanp->debug & 1) - link_debug(chanp, "ACCEPTB", 1); + link_debug(chanp, 1, "ACCEPTB"); FsmEvent(&chanp->fi, EV_ACCEPTB, NULL); break; case (ISDN_CMD_ACCEPTD): chanp = csta->channel + ic->arg; if (chanp->debug & 1) - link_debug(chanp, "ACCEPTD", 1); + link_debug(chanp, 1, "ACCEPTD"); FsmEvent(&chanp->fi, EV_ACCEPTD, NULL); break; case (ISDN_CMD_HANGUP): chanp = csta->channel + ic->arg; if (chanp->debug & 1) - link_debug(chanp, "HANGUP", 1); + link_debug(chanp, 1, "HANGUP"); FsmEvent(&chanp->fi, EV_HANGUP, NULL); break; - case (ISDN_CMD_SUSPEND): - chanp = csta->channel + ic->arg; - if (chanp->debug & 1) { - sprintf(tmp, "SUSPEND %s", ic->parm.num); - link_debug(chanp, tmp, 1); - } - FsmEvent(&chanp->fi, EV_SUSPEND, ic); - break; - case (ISDN_CMD_RESUME): + case (CAPI_PUT_MESSAGE): chanp = csta->channel + ic->arg; - if (chanp->debug & 1) { - sprintf(tmp, "RESUME %s", ic->parm.num); - link_debug(chanp, tmp, 1); + if (chanp->debug & 1) + capi_debug(chanp, &ic->parm.cmsg); + if (ic->parm.cmsg.Length < 8) + break; + switch(ic->parm.cmsg.Command) { + case CAPI_FACILITY: + if (ic->parm.cmsg.Subcommand == CAPI_REQ) + lli_got_fac_req(chanp, &ic->parm.cmsg); + break; + case CAPI_MANUFACTURER: + if (ic->parm.cmsg.Subcommand == CAPI_REQ) + lli_got_manufacturer(chanp, csta, &ic->parm.cmsg); + break; + default: + break; } - FsmEvent(&chanp->fi, EV_RESUME, ic); break; case (ISDN_CMD_LOCK): HiSax_mod_inc_use_count(); #ifdef MODULE - if (csta->channel[0].debug & 0x400) { - jiftime(tmp, jiffies); - i = strlen(tmp); - sprintf(tmp + i, " LOCK modcnt %d\n", MOD_USE_COUNT); - HiSax_putstatus(csta, tmp); - } + if (csta->channel[0].debug & 0x400) + HiSax_putstatus(csta, " LOCK ", "modcnt %x", + MOD_USE_COUNT); #endif /* MODULE */ break; case (ISDN_CMD_UNLOCK): HiSax_mod_dec_use_count(); #ifdef MODULE - if (csta->channel[0].debug & 0x400) { - jiftime(tmp, jiffies); - i = strlen(tmp); - sprintf(tmp + i, " UNLOCK modcnt %d\n", MOD_USE_COUNT); - HiSax_putstatus(csta, tmp); - } + if (csta->channel[0].debug & 0x400) + HiSax_putstatus(csta, " UNLOCK ", "modcnt %x", + MOD_USE_COUNT); #endif /* MODULE */ break; case (ISDN_CMD_IOCTL): @@ -2081,19 +1890,19 @@ HiSax_command(isdn_ctrl * ic) case (1): num = *(unsigned int *) ic->parm.num; distr_debug(csta, num); - sprintf(tmp, "debugging flags card %d set to %x\n", + printk(KERN_DEBUG "HiSax: debugging flags card %d set to %x\n", csta->cardnr + 1, num); - HiSax_putstatus(csta, tmp); - printk(KERN_DEBUG "HiSax: %s", tmp); + HiSax_putstatus(csta, "debugging flags ", + "card %d set to %x", csta->cardnr + 1, num); break; case (2): - num = *(unsigned int *) ic->parm.num; - csta->channel[0].lc_b->delay = num; - csta->channel[1].lc_b->delay = num; - sprintf(tmp, "delay card %d set to %d ms\n", + num = *(unsigned int *) ic->parm.num; + csta->channel[0].b_st->l1.delay = num; + csta->channel[1].b_st->l1.delay = num; + HiSax_putstatus(csta, "delay ", "card %d set to %d ms", + csta->cardnr + 1, num); + printk(KERN_DEBUG "HiSax: delay card %d set to %d ms\n", csta->cardnr + 1, num); - HiSax_putstatus(csta, tmp); - printk(KERN_DEBUG "HiSax: %s", tmp); break; case (3): for (i = 0; i < *(unsigned int *) ic->parm.num; i++) @@ -2106,47 +1915,91 @@ HiSax_command(isdn_ctrl * ic) case (5): /* set card in leased mode */ num = *(unsigned int *) ic->parm.num; if ((num <1) || (num > 2)) { - sprintf(tmp, "Set LEASED wrong channel %d\n", + HiSax_putstatus(csta, "Set LEASED ", + "wrong channel %d", num); + printk(KERN_WARNING "HiSax: Set LEASED wrong channel %d\n", num); - HiSax_putstatus(csta, tmp); - printk(KERN_WARNING "HiSax: %s", tmp); } else { num--; - csta->channel[num].leased = 1; - csta->channel[num].lc_d->l2_establish = 0; - sprintf(tmp, "card %d channel %d set leased mode\n", + chanp = csta->channel +num; + chanp->leased = 1; + HiSax_putstatus(csta, "Card", + "%d channel %d set leased mode\n", csta->cardnr + 1, num + 1); - HiSax_putstatus(csta, tmp); - FsmEvent(&csta->channel[num].lc_d->lcfi, EV_LC_ESTABLISH, NULL); + chanp->d_st->l1.l1l2 = leased_l1l2; + chanp->d_st->lli.l4l3 = leased_l4l3; + chanp->d_st->lli.l4l3(chanp->d_st, + DL_ESTABLISH | REQUEST, NULL); } break; case (6): /* set B-channel test loop */ num = *(unsigned int *) ic->parm.num; if (csta->stlist) - csta->stlist->ma.manl1(csta->stlist, - PH_TESTLOOP_REQ, (void *) num); + csta->stlist->l2.l2l1(csta->stlist, + PH_TESTLOOP | REQUEST, (void *) (long)num); + break; + case (7): /* set card in PTP mode */ + num = *(unsigned int *) ic->parm.num; + if (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) { + printk(KERN_ERR "HiSax PTP mode only with one TEI possible\n"); + } else if (num) { + test_and_set_bit(FLG_PTP, &csta->channel[0].d_st->l2.flag); + test_and_set_bit(FLG_FIXED_TEI, &csta->channel[0].d_st->l2.flag); + csta->channel[0].d_st->l2.tei = 0; + HiSax_putstatus(csta, "set card ", "in PTP mode"); + printk(KERN_DEBUG "HiSax: set card in PTP mode\n"); + printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n"); + test_and_set_bit(FLG_START_D, &csta->channel[0].Flags); + test_and_set_bit(FLG_START_D, &csta->channel[1].Flags); + csta->channel[0].d_st->lli.l4l3(csta->channel[0].d_st, + DL_ESTABLISH | REQUEST, NULL); + } else { + test_and_clear_bit(FLG_PTP, &csta->channel[0].d_st->l2.flag); + test_and_clear_bit(FLG_FIXED_TEI, &csta->channel[0].d_st->l2.flag); + HiSax_putstatus(csta, "set card ", "in PTMP mode"); + printk(KERN_DEBUG "HiSax: set card in PTMP mode\n"); + } + break; + case (8): /* set card in FIXED TEI mode */ + num = *(unsigned int *) ic->parm.num; + chanp = csta->channel + (num & 1); + num = num >>1; + test_and_set_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag); + chanp->d_st->l2.tei = num; + HiSax_putstatus(csta, "set card ", "in FIXED TEI (%d) mode", num); + printk(KERN_DEBUG "HiSax: set card in FIXED TEI (%d) mode\n", + num); + break; + case (9): /* load firmware */ + memcpy(&adr, ic->parm.num, sizeof(ulong)); + csta->cardmsg(csta, CARD_LOAD_FIRM, + (void *) adr); break; #ifdef MODULE case (55): while ( MOD_USE_COUNT > 0) - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; HiSax_mod_inc_use_count(); break; #endif /* MODULE */ case (11): + num = csta->debug & DEB_DLOG_HEX; csta->debug = *(unsigned int *) ic->parm.num; - sprintf(tmp, "l1 debugging flags card %d set to %x\n", + csta->debug |= num; + HiSax_putstatus(cards[0].cs, "l1 debugging ", + "flags card %d set to %x", + csta->cardnr + 1, csta->debug); + printk(KERN_DEBUG "HiSax: l1 debugging flags card %d set to %x\n", csta->cardnr + 1, csta->debug); - HiSax_putstatus(cards[0].cs, tmp); - printk(KERN_DEBUG "HiSax: %s", tmp); break; case (13): csta->channel[0].d_st->l3.debug = *(unsigned int *) ic->parm.num; csta->channel[1].d_st->l3.debug = *(unsigned int *) ic->parm.num; - sprintf(tmp, "l3 debugging flags card %d set to %x\n", + HiSax_putstatus(cards[0].cs, "l3 debugging ", + "flags card %d set to %x\n", csta->cardnr + 1, + *(unsigned int *) ic->parm.num); + printk(KERN_DEBUG "HiSax: l3 debugging flags card %d set to %x\n", csta->cardnr + 1, *(unsigned int *) ic->parm.num); - HiSax_putstatus(cards[0].cs, tmp); - printk(KERN_DEBUG "HiSax: %s", tmp); break; default: printk(KERN_DEBUG "HiSax: invalid ioclt %d\n", @@ -2170,7 +2023,6 @@ HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb) int len = skb->len; unsigned long flags; struct sk_buff *nskb; - char tmp[64]; if (!csta) { printk(KERN_ERR @@ -2180,13 +2032,13 @@ HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb) chanp = csta->channel + chan; st = chanp->b_st; if (!chanp->data_open) { - link_debug(chanp, "writebuf: channel not open", 1); + link_debug(chanp, 1, "writebuf: channel not open"); return -EIO; } if (len > MAX_DATA_SIZE) { - sprintf(tmp, "writebuf: packet too large (%d bytes)", len); - printk(KERN_WARNING "HiSax_%s !\n", tmp); - link_debug(chanp, tmp, 1); + link_debug(chanp, 1, "writebuf: packet too large (%d bytes)", len); + printk(KERN_WARNING "HiSax_writebuf: packet too large (%d bytes) !\n", + len); return -EINVAL; } if (len) { @@ -2194,10 +2046,8 @@ HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb) /* Must return 0 here, since this is not an error * but a temporary lack of resources. */ - if (chanp->debug & 0x800) { - sprintf(tmp, "writebuf: no buffers for %d bytes", len); - link_debug(chanp, tmp, 1); - } + if (chanp->debug & 0x800) + link_debug(chanp, 1, "writebuf: no buffers for %d bytes", len); return 0; } save_flags(flags); @@ -2206,11 +2056,11 @@ HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb) if (nskb) { if (!ack) nskb->pkt_type = PACKET_NOACK; - if (chanp->lc_b->l2_establish) - st->l3.l3l2(st, DL_DATA, nskb); + if (chanp->l2_active_protocol == ISDN_PROTO_L2_X75I) + st->l3.l3l2(st, DL_DATA | REQUEST, nskb); else { chanp->bcs->tx_cnt += len; - st->l2.l2l1(st, PH_DATA_REQ, nskb); + st->l2.l2l1(st, PH_DATA | REQUEST, nskb); } dev_kfree_skb(skb); } else diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index 3b98a3a30..7ca2de9e4 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -1,10 +1,50 @@ -/* $Id: config.c,v 2.12 1998/02/11 17:28:02 keil Exp $ +/* $Id: config.c,v 2.23 1999/02/17 10:53:02 cpetig Exp $ - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * * * $Log: config.c,v $ + * Revision 2.23 1999/02/17 10:53:02 cpetig + * Added Hisax_closecard to exported symbols. + * As indicated by Oliver Schoett <os@sdm.de>. + * + * If anyone is annoyed by exporting symbols deep inside the code, please + * contact me. + * + * Revision 2.22 1999/02/04 21:41:53 keil + * Fix printk msg + * + * Revision 2.21 1999/02/04 10:48:52 keil + * Fix readstat bug + * + * Revision 2.20 1998/11/15 23:54:28 keil + * changes from 2.0 + * + * Revision 2.19 1998/08/13 23:36:18 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 2.18 1998/07/30 21:01:37 niemann + * Fixed Sedlbauer Speed Fax PCMCIA missing isdnl3new + * + * Revision 2.17 1998/07/15 15:01:26 calle + * Support for AVM passive PCMCIA cards: + * A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0 + * + * Revision 2.16 1998/05/25 14:10:03 keil + * HiSax 3.0 + * X.75 and leased are working again. + * + * Revision 2.15 1998/05/25 12:57:43 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 2.14 1998/04/15 16:38:25 keil + * Add S0Box and Teles PCI support + * + * Revision 2.13 1998/03/09 23:19:23 keil + * Changes for PCMCIA + * * Revision 2.12 1998/02/11 17:28:02 keil * Niccy PnP/PCI support * @@ -55,6 +95,12 @@ #include <linux/timer.h> #include <linux/config.h> #include "hisax.h" +#include <linux/module.h> +#include <linux/kernel_stat.h> +#include <linux/tqueue.h> +#include <linux/interrupt.h> +#define HISAX_STATUS_BUFSIZE 4096 +#define INCLUDE_INLINE_FUNCS /* * This structure array contains one entry per card. An entry looks @@ -78,42 +124,78 @@ * 13 Teleint p0=irq p1=iobase * 14 Teles 16.3c p0=irq p1=iobase * 15 Sedlbauer speed p0=irq p1=iobase + * 15 Sedlbauer PC/104 p0=irq p1=iobase + * 15 Sedlbauer speed pci no parameter * 16 USR Sportster internal p0=irq p1=iobase * 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 - * 21 reserved TELES PCI + * 21 TELES PCI no parameter * 22 Sedlbauer Speed Star p0=irq p1=iobase * 23 reserved * 24 Dr Neuhaus Niccy PnP/PCI card p0=irq p1=IO0 p2=IO1 (PnP only) - * + * 25 Teles S0Box p0=irq p1=iobase (from isapnp setup) + * 26 AVM A1 PCMCIA (Fritz) p0=irq p1=iobase + * 27 AVM PnP/PCI p0=irq p1=iobase (PCI no parameter) + * 28 Sedlbauer Speed Fax+ p0=irq p1=iobase (from isapnp setup) * * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1 * * */ +const char *CardType[] = +{"No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3", "Creatix/Teles PnP", + "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)", + "AMD 7930", "NICCY", "S0Box", "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI", + "Sedlbauer Speed Fax +" +}; + #ifdef CONFIG_HISAX_ELSA #define DEFAULT_CARD ISDN_CTYPE_ELSA #define DEFAULT_CFG {0,0,0,0} -#ifdef MODULE int elsa_init_pcmcia(void*, int, int*, int); EXPORT_SYMBOL(elsa_init_pcmcia); #endif -#endif #ifdef CONFIG_HISAX_AVM_A1 #undef DEFAULT_CARD #undef DEFAULT_CFG #define DEFAULT_CARD ISDN_CTYPE_A1 #define DEFAULT_CFG {10,0x340,0,0} #endif + +#ifdef CONFIG_HISAX_AVM_A1_PCMCIA +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_A1_PCMCIA +#define DEFAULT_CFG {11,0x170,0,0} +int avm_a1_init_pcmcia(void*, int, int*, int); +EXPORT_SYMBOL(avm_a1_init_pcmcia); +#endif + +#ifdef CONFIG_HISAX_FRITZPCI +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_FRITZPCI +#define DEFAULT_CFG {0,0,0,0} +#endif + #ifdef CONFIG_HISAX_16_3 #undef DEFAULT_CARD #undef DEFAULT_CFG #define DEFAULT_CARD ISDN_CTYPE_16_3 #define DEFAULT_CFG {15,0x180,0,0} #endif +#ifdef CONFIG_HISAX_S0BOX +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_S0BOX +#define DEFAULT_CFG {7,0x378,0,0} +#endif #ifdef CONFIG_HISAX_16_0 #undef DEFAULT_CARD #undef DEFAULT_CFG @@ -121,6 +203,13 @@ EXPORT_SYMBOL(elsa_init_pcmcia); #define DEFAULT_CFG {15,0xd0000,0xd80,0} #endif +#ifdef CONFIG_HISAX_TELESPCI +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_TELESPCI +#define DEFAULT_CFG {0,0,0,0} +#endif + #ifdef CONFIG_HISAX_IX1MICROR2 #undef DEFAULT_CARD #undef DEFAULT_CFG @@ -193,13 +282,6 @@ EXPORT_SYMBOL(sedl_init_pcmcia); #define DEFAULT_CFG {12,0x3e0,0,0} #endif -#ifdef CONFIG_HISAX_DBRI -#undef DEFAULT_CARD -#undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_DBRI -#define DEFAULT_CFG {0,0x0,0,0} -#endif - #ifdef CONFIG_HISAX_NICCY #undef DEFAULT_CARD #undef DEFAULT_CFG @@ -232,10 +314,10 @@ EXPORT_SYMBOL(sedl_init_pcmcia); #endif #define FIRST_CARD { \ - DEFAULT_CARD, \ - DEFAULT_PROTO, \ - DEFAULT_CFG, \ - NULL, \ + DEFAULT_CARD, \ + DEFAULT_PROTO, \ + DEFAULT_CFG, \ + NULL, \ } #define EMPTY_CARD {0, DEFAULT_PROTO, {0, 0, 0, 0}, NULL} @@ -250,29 +332,20 @@ struct IsdnCard cards[] = EMPTY_CARD, EMPTY_CARD, EMPTY_CARD, - EMPTY_CARD, - EMPTY_CARD, - EMPTY_CARD, - EMPTY_CARD, - EMPTY_CARD, - EMPTY_CARD, - EMPTY_CARD, - EMPTY_CARD, }; -static char HiSaxID[96] HISAX_INITDATA = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \ -"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \ +static char HiSaxID[64] HISAX_INITDATA = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \ -"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; +"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; char *HiSax_id HISAX_INITDATA = HiSaxID; #ifdef MODULE /* Variables for insmod */ static int type[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +{0, 0, 0, 0, 0, 0, 0, 0}; static int protocol[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +{0, 0, 0, 0, 0, 0, 0, 0}; static int io[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +{0, 0, 0, 0, 0, 0, 0, 0}; #undef IO0_IO1 #ifdef CONFIG_HISAX_16_3 #define IO0_IO1 @@ -283,29 +356,29 @@ static int io[] HISAX_INITDATA = #endif #ifdef IO0_IO1 static int io0[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +{0, 0, 0, 0, 0, 0, 0, 0}; static int io1[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +{0, 0, 0, 0, 0, 0, 0, 0}; #endif static int irq[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +{0, 0, 0, 0, 0, 0, 0, 0}; static int mem[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +{0, 0, 0, 0, 0, 0, 0, 0}; static char *id HISAX_INITDATA = HiSaxID; MODULE_AUTHOR("Karsten Keil"); -MODULE_PARM(type, "1-3i"); -MODULE_PARM(protocol, "1-2i"); +MODULE_PARM(type, "1-8i"); +MODULE_PARM(protocol, "1-8i"); MODULE_PARM(io, "1-8i"); -MODULE_PARM(irq, "1-2i"); -MODULE_PARM(mem, "1-12i"); +MODULE_PARM(irq, "1-8i"); +MODULE_PARM(mem, "1-8i"); MODULE_PARM(id, "s"); #ifdef CONFIG_HISAX_16_3 /* For Creatix/Teles PnP */ MODULE_PARM(io0, "1-8i"); MODULE_PARM(io1, "1-8i"); -#endif +#endif /* CONFIG_HISAX_16_3 */ -#endif +#endif /* MODULE */ int nrcards; @@ -333,23 +406,25 @@ HiSax_getrev(const char *revision)) HISAX_INITFUNC(void HiSaxVersion(void)) { - char tmp[64], rev[64]; - char *r = rev; + char tmp[64]; + printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n"); +#ifdef MODULE + printk(KERN_INFO "HiSax: Version 3.1a (module)\n"); +#else + printk(KERN_INFO "HiSax: Version 3.1a (kernel)\n"); +#endif strcpy(tmp, l1_revision); - r += sprintf(r, "%s/", HiSax_getrev(tmp)); + printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp)); strcpy(tmp, l2_revision); - r += sprintf(r, "%s/", HiSax_getrev(tmp)); + printk(KERN_INFO "HiSax: Layer2 Revision %s\n", HiSax_getrev(tmp)); + strcpy(tmp, tei_revision); + printk(KERN_INFO "HiSax: TeiMgr Revision %s\n", HiSax_getrev(tmp)); strcpy(tmp, l3_revision); - r += sprintf(r, "%s/", HiSax_getrev(tmp)); + printk(KERN_INFO "HiSax: Layer3 Revision %s\n", HiSax_getrev(tmp)); strcpy(tmp, lli_revision); - r += sprintf(r, "%s/", HiSax_getrev(tmp)); - strcpy(tmp, tei_revision); - r += sprintf(r, "%s", HiSax_getrev(tmp)); - - printk(KERN_INFO "HiSax: Driver for Siemens chip set ISDN cards\n"); - printk(KERN_INFO "HiSax: Version 2.8\n"); - printk(KERN_INFO "HiSax: Revisions %s\n", rev); + printk(KERN_INFO "HiSax: LinkLayer Revision %s\n", HiSax_getrev(tmp)); + certification_check(1); } void @@ -375,7 +450,7 @@ HiSax_setup(char *str, int *ints)) argc = ints[0]; i = 0; j = 1; - while (argc && (i < 16)) { + while (argc && (i < HISAX_MAX_CARDS)) { if (argc) { cards[i].typ = ints[j]; j++; @@ -413,11 +488,759 @@ HiSax_setup(char *str, int *ints)) } #endif +#if CARD_TELES0 +extern int setup_teles0(struct IsdnCard *card); +#endif + +#if CARD_TELES3 +extern int setup_teles3(struct IsdnCard *card); +#endif + +#if CARD_S0BOX +extern int setup_s0box(struct IsdnCard *card); +#endif + +#if CARD_TELESPCI +extern int setup_telespci(struct IsdnCard *card); +#endif + +#if CARD_AVM_A1 +extern int setup_avm_a1(struct IsdnCard *card); +#endif + +#if CARD_AVM_A1_PCMCIA +extern int setup_avm_a1_pcmcia(struct IsdnCard *card); +#endif + +#if CARD_FRITZPCI +extern int setup_avm_pcipnp(struct IsdnCard *card); +#endif + +#if CARD_ELSA +extern int setup_elsa(struct IsdnCard *card); +#endif + +#if CARD_IX1MICROR2 +extern int setup_ix1micro(struct IsdnCard *card); +#endif + +#if CARD_DIEHLDIVA +extern int setup_diva(struct IsdnCard *card); +#endif + +#if CARD_ASUSCOM +extern int setup_asuscom(struct IsdnCard *card); +#endif + +#if CARD_TELEINT +extern int setup_TeleInt(struct IsdnCard *card); +#endif + +#if CARD_SEDLBAUER +extern int setup_sedlbauer(struct IsdnCard *card); +#endif + +#if CARD_SPORTSTER +extern int setup_sportster(struct IsdnCard *card); +#endif + +#if CARD_MIC +extern int setup_mic(struct IsdnCard *card); +#endif + +#if CARD_NETJET +extern int setup_netjet(struct IsdnCard *card); +#endif + +#if CARD_TELES3C +extern int setup_t163c(struct IsdnCard *card); +#endif + +#if CARD_AMD7930 +extern int setup_amd7930(struct IsdnCard *card); +#endif + +#if CARD_NICCY +extern int setup_niccy(struct IsdnCard *card); +#endif + +/* + * Find card with given driverId + */ +static inline struct IsdnCardState +*hisax_findcard(int driverid) +{ + int i; + + for (i = 0; i < nrcards; i++) + if (cards[i].cs) + if (cards[i].cs->myid == driverid) + return (cards[i].cs); + return (NULL); +} + +int +HiSax_readstatus(u_char * buf, int len, int user, int id, int channel) +{ + int count,cnt; + u_char *p = buf; + struct IsdnCardState *cs = hisax_findcard(id); + + if (cs) { + if (len > HISAX_STATUS_BUFSIZE) { + printk(KERN_WARNING "HiSax: status overflow readstat %d/%d\n", + len, HISAX_STATUS_BUFSIZE); + } + count = cs->status_end - cs->status_read +1; + if (count >= len) + count = len; + if (user) + copy_to_user(p, cs->status_read, count); + else + memcpy(p, cs->status_read, count); + cs->status_read += count; + if (cs->status_read > cs->status_end) + cs->status_read = cs->status_buf; + p += count; + count = len - count; + while (count) { + if (count > HISAX_STATUS_BUFSIZE) + cnt = HISAX_STATUS_BUFSIZE; + else + cnt = count; + if (user) + copy_to_user(p, cs->status_read, cnt); + else + memcpy(p, cs->status_read, cnt); + p += cnt; + cs->status_read += cnt % HISAX_STATUS_BUFSIZE; + count -= cnt; + } + return len; + } else { + printk(KERN_ERR + "HiSax: if_readstatus called with invalid driverId!\n"); + return -ENODEV; + } +} + +inline int +jiftime(char *s, long mark) +{ + s += 8; + + *s-- = '\0'; + *s-- = mark % 10 + '0'; + mark /= 10; + *s-- = mark % 10 + '0'; + mark /= 10; + *s-- = '.'; + *s-- = mark % 10 + '0'; + mark /= 10; + *s-- = mark % 6 + '0'; + mark /= 6; + *s-- = ':'; + *s-- = mark % 10 + '0'; + mark /= 10; + *s-- = mark % 10 + '0'; + return(8); +} + +static u_char tmpbuf[HISAX_STATUS_BUFSIZE]; + +void +VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args) +{ +/* if head == NULL the fmt contains the full info */ + + long flags; + int count, i; + u_char *p; + isdn_ctrl ic; + int len; + + save_flags(flags); + cli(); + p = tmpbuf; + if (head) { + p += jiftime(p, jiffies); + p += sprintf(p, " %s", head); + p += vsprintf(p, fmt, args); + *p++ = '\n'; + *p = 0; + len = p - tmpbuf; + p = tmpbuf; + } else { + p = fmt; + len = strlen(fmt); + } + if (!cs) { + printk(KERN_WARNING "HiSax: No CardStatus for message %s", p); + restore_flags(flags); + return; + } + if (len > HISAX_STATUS_BUFSIZE) { + printk(KERN_WARNING "HiSax: status overflow %d/%d\n", + len, HISAX_STATUS_BUFSIZE); + restore_flags(flags); + return; + } + count = len; + i = cs->status_end - cs->status_write +1; + if (i >= len) + i = len; + len -= i; + memcpy(cs->status_write, p, i); + cs->status_write += i; + if (cs->status_write > cs->status_end) + cs->status_write = cs->status_buf; + p += i; + if (len) { + memcpy(cs->status_write, p, len); + cs->status_write += len; + } +#ifdef KERNELSTACK_DEBUG + i = (ulong)&len - current->kernel_stack_page; + sprintf(tmpbuf, "kstack %s %lx use %ld\n", current->comm, + current->kernel_stack_page, i); + len = strlen(tmpbuf); + for (p = tmpbuf, i = len; i > 0; i--, p++) { + *cs->status_write++ = *p; + if (cs->status_write > cs->status_end) + cs->status_write = cs->status_buf; + count++; + } +#endif + restore_flags(flags); + if (count) { + ic.command = ISDN_STAT_STAVAIL; + ic.driver = cs->myid; + ic.arg = count; + cs->iif.statcallb(&ic); + } +} + +void +HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + VHiSax_putstatus(cs, head, fmt, args); + va_end(args); +} + +int +ll_run(struct IsdnCardState *cs) +{ + long flags; + isdn_ctrl ic; + + save_flags(flags); + cli(); + ic.driver = cs->myid; + ic.command = ISDN_STAT_RUN; + cs->iif.statcallb(&ic); + restore_flags(flags); + return 0; +} + +void +ll_stop(struct IsdnCardState *cs) +{ + isdn_ctrl ic; + + ic.command = ISDN_STAT_STOP; + ic.driver = cs->myid; + cs->iif.statcallb(&ic); + CallcFreeChan(cs); +} + +static void +ll_unload(struct IsdnCardState *cs) +{ + isdn_ctrl ic; + + ic.command = ISDN_STAT_UNLOAD; + ic.driver = cs->myid; + cs->iif.statcallb(&ic); + if (cs->status_buf) + kfree(cs->status_buf); + cs->status_read = NULL; + cs->status_write = NULL; + cs->status_end = NULL; + kfree(cs->dlog); +} + +static void +closecard(int cardnr) +{ + struct IsdnCardState *csta = cards[cardnr].cs; + + if (csta->bcs->BC_Close != NULL) { + csta->bcs->BC_Close(csta->bcs + 1); + csta->bcs->BC_Close(csta->bcs); + } + + if (csta->rcvbuf) { + kfree(csta->rcvbuf); + csta->rcvbuf = NULL; + } + discard_queue(&csta->rq); + discard_queue(&csta->sq); + if (csta->tx_skb) { + dev_kfree_skb(csta->tx_skb); + csta->tx_skb = NULL; + } + if (csta->mon_rx) { + kfree(csta->mon_rx); + csta->mon_rx = NULL; + } + if (csta->mon_tx) { + kfree(csta->mon_tx); + csta->mon_tx = NULL; + } + csta->cardmsg(csta, CARD_RELEASE, NULL); + if (csta->dbusytimer.function != NULL) + del_timer(&csta->dbusytimer); + ll_unload(csta); +} + +HISAX_INITFUNC(static int init_card(struct IsdnCardState *cs)) +{ + int irq_cnt, cnt = 3; + long flags; + + save_flags(flags); + cli(); + irq_cnt = kstat_irqs(cs->irq); + printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], cs->irq, + irq_cnt); + if (cs->cardmsg(cs, CARD_SETIRQ, NULL)) { + printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n", + cs->irq); + restore_flags(flags); + return(1); + } + while (cnt) { + cs->cardmsg(cs, CARD_INIT, NULL); + sti(); + current->state = TASK_INTERRUPTIBLE; + /* Timeout 10ms */ + schedule_timeout((10 * HZ) / 1000); + restore_flags(flags); + printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], + cs->irq, kstat_irqs(cs->irq)); + if (kstat_irqs(cs->irq) == irq_cnt) { + printk(KERN_WARNING + "%s: IRQ(%d) getting no interrupts during init %d\n", + CardType[cs->typ], cs->irq, 4 - cnt); + if (cnt == 1) { + free_irq(cs->irq, cs); + return (2); + } else { + cs->cardmsg(cs, CARD_RESET, NULL); + cnt--; + } + } else { + cs->cardmsg(cs, CARD_TEST, NULL); + return(0); + } + } + restore_flags(flags); + return(3); +} + +HISAX_INITFUNC(static int +checkcard(int cardnr, char *id, int *busy_flag)) +{ + long flags; + int ret = 0; + struct IsdnCard *card = cards + cardnr; + struct IsdnCardState *cs; + + save_flags(flags); + cli(); + if (!(cs = (struct IsdnCardState *) + kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for IsdnCardState(card %d)\n", + cardnr + 1); + restore_flags(flags); + return (0); + } + memset(cs, 0, sizeof(struct IsdnCardState)); + card->cs = cs; + cs->cardnr = cardnr; + cs->debug = L1_DEB_WARN; + cs->HW_Flags = 0; + cs->busy_flag = busy_flag; +#if TEI_PER_CARD +#else + test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); +#endif + cs->protocol = card->protocol; + + if ((card->typ > 0) && (card->typ < 31)) { + if (!((1 << card->typ) & SUPORTED_CARDS)) { + printk(KERN_WARNING + "HiSax: Support for %s Card not selected\n", + CardType[card->typ]); + restore_flags(flags); + return (0); + } + } else { + printk(KERN_WARNING + "HiSax: Card Type %d out of range\n", + card->typ); + restore_flags(flags); + return (0); + } + if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for dlog(card %d)\n", + cardnr + 1); + restore_flags(flags); + return (0); + } + if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for status_buf(card %d)\n", + cardnr + 1); + kfree(cs->dlog); + restore_flags(flags); + return (0); + } + cs->stlist = NULL; + cs->mon_tx = NULL; + cs->mon_rx = NULL; + cs->status_read = cs->status_buf; + cs->status_write = cs->status_buf; + cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1; + cs->typ = card->typ; + strcpy(cs->iif.id, id); + cs->iif.channels = 2; + cs->iif.maxbufsize = MAX_DATA_SIZE; + cs->iif.hl_hdrlen = MAX_HEADER_LEN; + cs->iif.features = + ISDN_FEATURE_L2_X75I | + ISDN_FEATURE_L2_HDLC | + ISDN_FEATURE_L2_MODEM | + ISDN_FEATURE_L2_TRANS | + ISDN_FEATURE_L3_TRANS | +#ifdef CONFIG_HISAX_1TR6 + ISDN_FEATURE_P_1TR6 | +#endif +#ifdef CONFIG_HISAX_EURO + ISDN_FEATURE_P_EURO | +#endif +#ifdef CONFIG_HISAX_NI1 + ISDN_FEATURE_P_NI1 | +#endif + 0; + + cs->iif.command = HiSax_command; + cs->iif.writecmd = NULL; + cs->iif.writebuf_skb = HiSax_writebuf_skb; + cs->iif.readstat = HiSax_readstatus; + register_isdn(&cs->iif); + cs->myid = cs->iif.channels; + printk(KERN_INFO + "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1, + (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : + (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" : + (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" : + (card->protocol == ISDN_PTYPE_NI1) ? "NI1" : + "NONE", cs->iif.id, cs->myid); + switch (card->typ) { +#if CARD_TELES0 + case ISDN_CTYPE_16_0: + case ISDN_CTYPE_8_0: + ret = setup_teles0(card); + break; +#endif +#if CARD_TELES3 + case ISDN_CTYPE_16_3: + case ISDN_CTYPE_PNP: + case ISDN_CTYPE_TELESPCMCIA: + case ISDN_CTYPE_COMPAQ_ISA: + ret = setup_teles3(card); + break; +#endif +#if CARD_S0BOX + case ISDN_CTYPE_S0BOX: + ret = setup_s0box(card); + break; +#endif +#if CARD_TELESPCI + case ISDN_CTYPE_TELESPCI: + ret = setup_telespci(card); + break; +#endif +#if CARD_AVM_A1 + case ISDN_CTYPE_A1: + ret = setup_avm_a1(card); + break; +#endif +#if CARD_AVM_A1_PCMCIA + case ISDN_CTYPE_A1_PCMCIA: + ret = setup_avm_a1_pcmcia(card); + break; +#endif +#if CARD_FRITZPCI + case ISDN_CTYPE_FRITZPCI: + ret = setup_avm_pcipnp(card); + break; +#endif +#if CARD_ELSA + case ISDN_CTYPE_ELSA: + case ISDN_CTYPE_ELSA_PNP: + case ISDN_CTYPE_ELSA_PCMCIA: + case ISDN_CTYPE_ELSA_PCI: + ret = setup_elsa(card); + break; +#endif +#if CARD_IX1MICROR2 + case ISDN_CTYPE_IX1MICROR2: + ret = setup_ix1micro(card); + break; +#endif +#if CARD_DIEHLDIVA + case ISDN_CTYPE_DIEHLDIVA: + ret = setup_diva(card); + break; +#endif +#if CARD_ASUSCOM + case ISDN_CTYPE_ASUSCOM: + ret = setup_asuscom(card); + break; +#endif +#if CARD_TELEINT + case ISDN_CTYPE_TELEINT: + ret = setup_TeleInt(card); + break; +#endif +#if CARD_SEDLBAUER + case ISDN_CTYPE_SEDLBAUER: + case ISDN_CTYPE_SEDLBAUER_PCMCIA: + case ISDN_CTYPE_SEDLBAUER_FAX: + ret = setup_sedlbauer(card); + break; +#endif +#if CARD_SPORTSTER + case ISDN_CTYPE_SPORTSTER: + ret = setup_sportster(card); + break; +#endif +#if CARD_MIC + case ISDN_CTYPE_MIC: + ret = setup_mic(card); + break; +#endif +#if CARD_NETJET + case ISDN_CTYPE_NETJET: + ret = setup_netjet(card); + break; +#endif +#if CARD_TELES3C + case ISDN_CTYPE_TELES3C: + ret = setup_t163c(card); + break; +#endif +#if CARD_NICCY + case ISDN_CTYPE_NICCY: + ret = setup_niccy(card); + break; +#endif +#if CARD_AMD7930 + case ISDN_CTYPE_AMD7930: + ret = setup_amd7930(card); + break; +#endif + default: + printk(KERN_WARNING "HiSax: Unknown Card Typ %d\n", + card->typ); + ll_unload(cs); + restore_flags(flags); + return (0); + } + if (!ret) { + ll_unload(cs); + restore_flags(flags); + return (0); + } + if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for isac rcvbuf\n"); + return (1); + } + cs->rcvidx = 0; + cs->tx_skb = NULL; + cs->tx_cnt = 0; + cs->event = 0; + cs->tqueue.next = 0; + cs->tqueue.sync = 0; + cs->tqueue.data = cs; + + skb_queue_head_init(&cs->rq); + skb_queue_head_init(&cs->sq); + + init_bcstate(cs, 0); + init_bcstate(cs, 1); + ret = init_card(cs); + if (ret) { + closecard(cardnr); + restore_flags(flags); + return (0); + } + init_tei(cs, cs->protocol); + CallcNewChan(cs); + /* ISAR needs firmware download first */ + if (!test_bit(HW_ISAR, &cs->HW_Flags)) + ll_run(cs); + restore_flags(flags); + return (1); +} + +HISAX_INITFUNC(void +HiSax_shiftcards(int idx)) +{ + int i; + + for (i = idx; i < (HISAX_MAX_CARDS - 1); i++) + memcpy(&cards[i], &cards[i + 1], sizeof(cards[i])); +} + +HISAX_INITFUNC(int +HiSax_inithardware(int *busy_flag)) +{ + int foundcards = 0; + int i = 0; + int t = ','; + int flg = 0; + char *id; + char *next_id = HiSax_id; + char ids[20]; + + if (strchr(HiSax_id, ',')) + t = ','; + else if (strchr(HiSax_id, '%')) + t = '%'; + + while (i < nrcards) { + if (cards[i].typ < 1) + break; + id = next_id; + if ((next_id = strchr(id, t))) { + *next_id++ = 0; + strcpy(ids, id); + flg = i + 1; + } else { + next_id = id; + if (flg >= i) + strcpy(ids, id); + else + sprintf(ids, "%s%d", id, i); + } + if (checkcard(i, ids, busy_flag)) { + foundcards++; + i++; + } else { + printk(KERN_WARNING "HiSax: Card %s not installed !\n", + CardType[cards[i].typ]); + if (cards[i].cs) + kfree((void *) cards[i].cs); + cards[i].cs = NULL; + HiSax_shiftcards(i); + } + } + return foundcards; +} + +void +HiSax_closecard(int cardnr) +{ + int i,last=nrcards - 1; + + if (cardnr>last) + return; + if (cards[cardnr].cs) { + ll_stop(cards[cardnr].cs); + release_tei(cards[cardnr].cs); + closecard(cardnr); + free_irq(cards[cardnr].cs->irq, cards[cardnr].cs); + kfree((void *) cards[cardnr].cs); + cards[cardnr].cs = NULL; + } + i = cardnr; + while (i!=last) { + cards[i] = cards[i+1]; + i++; + } + nrcards--; +} + +EXPORT_SYMBOL(HiSax_closecard); + +void +HiSax_reportcard(int cardnr) +{ + struct IsdnCardState *cs = cards[cardnr].cs; + struct PStack *stptr; + struct l3_process *pc; + int j, i = 1; + + printk(KERN_DEBUG "HiSax: reportcard No %d\n", cardnr + 1); + printk(KERN_DEBUG "HiSax: Type %s\n", CardType[cs->typ]); + printk(KERN_DEBUG "HiSax: debuglevel %x\n", cs->debug); + printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n", + (ulong) & HiSax_reportcard); + printk(KERN_DEBUG "HiSax: cs 0x%lX\n", (ulong) cs); + printk(KERN_DEBUG "HiSax: HW_Flags %x bc0 flg %x bc0 flg %x\n", + cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag); + printk(KERN_DEBUG "HiSax: bcs 0 mode %d ch%d\n", + cs->bcs[0].mode, cs->bcs[0].channel); + printk(KERN_DEBUG "HiSax: bcs 1 mode %d ch%d\n", + cs->bcs[1].mode, cs->bcs[1].channel); + printk(KERN_DEBUG "HiSax: cs stl 0x%lX\n", (ulong) & (cs->stlist)); + stptr = cs->stlist; + while (stptr != NULL) { + printk(KERN_DEBUG "HiSax: dst%d 0x%lX\n", i, (ulong) stptr); + printk(KERN_DEBUG "HiSax: dst%d stp 0x%lX\n", i, (ulong) stptr->l1.stlistp); + printk(KERN_DEBUG "HiSax: tei %d sapi %d\n", + stptr->l2.tei, stptr->l2.sap); + printk(KERN_DEBUG "HiSax: man 0x%lX\n", (ulong) stptr->ma.layer); + pc = stptr->l3.proc; + while (pc) { + printk(KERN_DEBUG "HiSax: l3proc %x 0x%lX\n", pc->callref, + (ulong) pc); + printk(KERN_DEBUG "HiSax: state %d st 0x%lX chan 0x%lX\n", + pc->state, (ulong) pc->st, (ulong) pc->chan); + pc = pc->next; + } + stptr = stptr->next; + i++; + } + for (j = 0; j < 2; j++) { + printk(KERN_DEBUG "HiSax: ch%d 0x%lX\n", j, + (ulong) & cs->channel[j]); + stptr = cs->channel[j].b_st; + i = 1; + while (stptr != NULL) { + printk(KERN_DEBUG "HiSax: b_st%d 0x%lX\n", i, (ulong) stptr); + printk(KERN_DEBUG "HiSax: man 0x%lX\n", (ulong) stptr->ma.layer); + stptr = stptr->next; + i++; + } + } +} + + __initfunc(int HiSax_init(void)) { int i; - + #ifdef MODULE int nzproto = 0; #ifdef CONFIG_HISAX_ELSA @@ -432,13 +1255,19 @@ HiSax_init(void)) return 0; } #endif +#ifdef CONFIG_HISAX_AVM_A1_PCMCIA + if (type[0] == ISDN_CTYPE_A1_PCMCIA) { + /* we have to export and return in this case */ + return 0; + } +#endif #endif - HiSaxVersion(); nrcards = 0; + HiSaxVersion(); #ifdef MODULE if (id) /* If id= string used */ HiSax_id = id; - for (i = 0; i < 16; i++) { + for (i = 0; i < HISAX_MAX_CARDS; i++) { cards[i].typ = type[i]; if (protocol[i]) { cards[i].protocol = protocol[i]; @@ -476,6 +1305,7 @@ HiSax_init(void)) case ISDN_CTYPE_16_3: case ISDN_CTYPE_TELESPCMCIA: case ISDN_CTYPE_A1: + case ISDN_CTYPE_A1_PCMCIA: case ISDN_CTYPE_ELSA_PNP: case ISDN_CTYPE_ELSA_PCMCIA: case ISDN_CTYPE_IX1MICROR2: @@ -484,16 +1314,19 @@ HiSax_init(void)) case ISDN_CTYPE_TELEINT: case ISDN_CTYPE_SEDLBAUER: case ISDN_CTYPE_SEDLBAUER_PCMCIA: + case ISDN_CTYPE_SEDLBAUER_FAX: case ISDN_CTYPE_SPORTSTER: case ISDN_CTYPE_MIC: case ISDN_CTYPE_TELES3C: + case ISDN_CTYPE_S0BOX: + case ISDN_CTYPE_FRITZPCI: cards[i].para[0] = irq[i]; cards[i].para[1] = io[i]; break; case ISDN_CTYPE_ELSA_PCI: case ISDN_CTYPE_NETJET: case ISDN_CTYPE_AMD7930: - case ISDN_CTYPE_DBRI: + case ISDN_CTYPE_TELESPCI: break; } } @@ -507,13 +1340,14 @@ HiSax_init(void)) HiSax_id = HiSaxID; if (!HiSaxID[0]) strcpy(HiSaxID, "HiSax"); - for (i = 0; i < 16; i++) + for (i = 0; i < HISAX_MAX_CARDS; i++) if (cards[i].typ > 0) nrcards++; printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", nrcards, (nrcards > 1) ? "s" : ""); CallcNew(); + Isdnl3New(); Isdnl2New(); TeiNew(); Isdnl1New(); @@ -522,7 +1356,6 @@ HiSax_init(void)) /* No symbols to export, hide all symbols */ #ifdef MODULE - EXPORT_NO_SYMBOLS; printk(KERN_INFO "HiSax: module installed\n"); #endif return (0); @@ -530,6 +1363,7 @@ HiSax_init(void)) Isdnl1Free(); TeiFree(); Isdnl2Free(); + Isdnl3Free(); CallcFree(); return -EIO; } @@ -539,13 +1373,27 @@ HiSax_init(void)) void cleanup_module(void) { - HiSax_closehardware(); + int cardnr = nrcards -1; + long flags; + + save_flags(flags); + cli(); + while(cardnr>=0) + HiSax_closecard(cardnr--); + Isdnl1Free(); + TeiFree(); + Isdnl2Free(); + Isdnl3Free(); + CallcFree(); + restore_flags(flags); printk(KERN_INFO "HiSax module removed\n"); } +#endif #ifdef CONFIG_HISAX_ELSA int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) { +#ifdef MODULE int i; int nzproto = 0; @@ -553,10 +1401,10 @@ int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) HiSaxVersion(); if (id) /* If id= string used */ HiSax_id = id; - /* Initialize all 16 structs, even though we only accept + /* Initialize all 8 structs, even though we only accept two pcmcia cards */ - for (i = 0; i < 16; i++) { + for (i = 0; i < HISAX_MAX_CARDS; i++) { cards[i].para[0] = irq[i]; cards[i].para[1] = io[i]; cards[i].typ = type[i]; @@ -575,7 +1423,7 @@ int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) HiSax_id = HiSaxID; if (!HiSaxID[0]) strcpy(HiSaxID, "HiSax"); - for (i = 0; i < 16; i++) + for (i = 0; i < HISAX_MAX_CARDS; i++) if (cards[i].typ > 0) nrcards++; printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", @@ -583,16 +1431,71 @@ int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) Isdnl1New(); CallcNew(); + Isdnl3New(); Isdnl2New(); TeiNew(); HiSax_inithardware(busy_flag); printk(KERN_NOTICE "HiSax: module installed\n"); +#endif return (0); } #endif + #ifdef CONFIG_HISAX_SEDLBAUER int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) { +#ifdef MODULE + int i; + int nzproto = 0; + + nrcards = 0; + HiSaxVersion(); + if (id) /* If id= string used */ + HiSax_id = id; + /* Initialize all 8 structs, even though we only accept + two pcmcia cards + */ + for (i = 0; i < HISAX_MAX_CARDS; i++) { + cards[i].para[0] = irq[i]; + cards[i].para[1] = io[i]; + cards[i].typ = type[i]; + if (protocol[i]) { + cards[i].protocol = protocol[i]; + nzproto++; + } + } + cards[0].para[0] = pcm_irq; + cards[0].para[1] = (int)pcm_iob; + cards[0].protocol = prot; + cards[0].typ = ISDN_CTYPE_SEDLBAUER_PCMCIA; + nzproto = 1; + + if (!HiSax_id) + HiSax_id = HiSaxID; + if (!HiSaxID[0]) + strcpy(HiSaxID, "HiSax"); + for (i = 0; i < HISAX_MAX_CARDS; i++) + if (cards[i].typ > 0) + nrcards++; + printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", + nrcards, (nrcards > 1) ? "s" : ""); + + CallcNew(); + Isdnl3New(); + Isdnl2New(); + Isdnl1New(); + TeiNew(); + HiSax_inithardware(busy_flag); + printk(KERN_NOTICE "HiSax: module installed\n"); +#endif + return (0); +} +#endif + +#ifdef CONFIG_HISAX_AVM_A1_PCMCIA +int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) +{ +#ifdef MODULE int i; int nzproto = 0; @@ -615,14 +1518,14 @@ int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) cards[0].para[0] = pcm_irq; cards[0].para[1] = (int)pcm_iob; cards[0].protocol = prot; - cards[0].typ = ISDN_CTYPE_SEDLBAUER_PCMCIA; + cards[0].typ = ISDN_CTYPE_A1_PCMCIA; nzproto = 1; if (!HiSax_id) HiSax_id = HiSaxID; if (!HiSaxID[0]) strcpy(HiSaxID, "HiSax"); - for (i = 0; i < 16; i++) + for (i = 0; i < HISAX_MAX_CARDS; i++) if (cards[i].typ > 0) nrcards++; printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", @@ -630,11 +1533,12 @@ int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) Isdnl1New(); CallcNew(); + Isdnl3New(); Isdnl2New(); TeiNew(); HiSax_inithardware(busy_flag); printk(KERN_NOTICE "HiSax: module installed\n"); +#endif return (0); } #endif -#endif diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index a533272c8..4baf740b1 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -1,13 +1,30 @@ -/* $Id: diva.c,v 1.5 1998/02/02 13:29:38 keil Exp $ +/* $Id: diva.c,v 1.10 1998/11/15 23:54:31 keil Exp $ * diva.c low level stuff for Eicon.Diehl Diva Family ISDN cards * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * Thanks to Eicon Technology Diehl GmbH & Co. oHG for documents and informations * * * $Log: diva.c,v $ + * Revision 1.10 1998/11/15 23:54:31 keil + * changes from 2.0 + * + * Revision 1.9 1998/06/27 22:52:03 keil + * support for Diva 2.01 + * + * Revision 1.8 1998/05/25 12:57:46 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 1.7 1998/04/15 16:42:36 keil + * new init code + * new PCI init (2.1.94) + * + * Revision 1.6 1998/03/07 22:56:57 tsbogend + * made HiSax working on Linux/Alpha + * * Revision 1.5 1998/02/02 13:29:38 keil * fast io * @@ -31,13 +48,13 @@ #include "hisax.h" #include "isac.h" #include "hscx.h" +#include "ipac.h" #include "isdnl1.h" #include <linux/pci.h> -#include <linux/bios32.h> extern const char *CardType[]; -const char *Diva_revision = "$Revision: 1.5 $"; +const char *Diva_revision = "$Revision: 1.10 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -47,6 +64,8 @@ const char *Diva_revision = "$Revision: 1.5 $"; #define DIVA_ISA_ISAC_DATA 2 #define DIVA_ISA_ISAC_ADR 6 #define DIVA_ISA_CTRL 7 +#define DIVA_IPAC_ADR 0 +#define DIVA_IPAC_DATA 1 #define DIVA_PCI_ISAC_DATA 8 #define DIVA_PCI_ISAC_ADR 0xc @@ -55,6 +74,7 @@ const char *Diva_revision = "$Revision: 1.5 $"; /* SUB Types */ #define DIVA_ISA 1 #define DIVA_PCI 2 +#define DIVA_IPAC_ISA 3 /* PCI stuff */ #define PCI_VENDOR_EICON_DIEHL 0x1133 @@ -140,13 +160,37 @@ ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size); } -static void +static void WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) { writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size); } static u_char +ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) +{ + return (readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset+0x80)); +} + +static void +WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) +{ + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset|0x80, value); +} + +static void +ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) +{ + readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, data, size); +} + +static void +WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) +{ + writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, data, size); +} + +static u_char ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { return(readreg(cs->hw.diva.hscx_adr, @@ -168,13 +212,13 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) cs->hw.diva.hscx, reg + (nr ? 0x40 : 0)) #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.diva.hscx_adr, \ cs->hw.diva.hscx, reg + (nr ? 0x40 : 0), data) - + #define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.diva.hscx_adr, \ cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt) - + #define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.diva.hscx_adr, \ cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt) - + #include "hscx_irq.c" static void @@ -215,18 +259,69 @@ diva_interrupt(int intno, void *dev_id, struct pt_regs *regs) } } +static void +diva_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char ista,val; + int icnt=20; + + if (!cs) { + printk(KERN_WARNING "Diva: Spurious interrupt!\n"); + return; + } + ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA); +Start_IPAC: + if (cs->debug & L1_DEB_IPAC) + debugl1(cs, "IPAC ISTA %02X", ista); + if (ista & 0x0f) { + val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, HSCX_ISTA + 0x40); + if (ista & 0x01) + val |= 0x01; + if (ista & 0x04) + val |= 0x02; + if (ista & 0x08) + val |= 0x04; + if (val) + hscx_int_main(cs, val); + } + if (ista & 0x20) { + val = 0xfe & readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA + 0x80); + if (val) { + isac_interrupt(cs, val); + } + } + if (ista & 0x10) { + val = 0x01; + isac_interrupt(cs, val); + } + ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA); + if ((ista & 0x3f) && icnt) { + icnt--; + goto Start_IPAC; + } + if (!icnt) + printk(KERN_WARNING "DIVA IPAC IRQ LOOP\n"); + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xFF); + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xC0); +} + + void release_io_diva(struct IsdnCardState *cs) { int bytecnt; - - del_timer(&cs->hw.diva.tl); - if (cs->subtyp == DIVA_ISA) + + if (cs->subtyp != DIVA_IPAC_ISA) { + del_timer(&cs->hw.diva.tl); + if (cs->hw.diva.cfg_reg) + byteout(cs->hw.diva.ctrl, 0); /* LED off, Reset */ + } + if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA)) bytecnt = 8; else bytecnt = 32; if (cs->hw.diva.cfg_reg) { - byteout(cs->hw.diva.ctrl, 0); /* LED off, Reset */ release_region(cs->hw.diva.cfg_reg, bytecnt); } } @@ -238,19 +333,30 @@ reset_diva(struct IsdnCardState *cs) save_flags(flags); sti(); - cs->hw.diva.ctrl_reg = 0; /* Reset On */ - byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - cs->hw.diva.ctrl_reg |= DIVA_RESET; /* Reset Off */ - byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - if (cs->subtyp == DIVA_ISA) - cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A; - else - cs->hw.diva.ctrl_reg |= DIVA_PCI_LED_A; - byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); + if (cs->subtyp == DIVA_IPAC_ISA) { + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x20); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x00); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xc0); + } else { + cs->hw.diva.ctrl_reg = 0; /* Reset On */ + byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + cs->hw.diva.ctrl_reg |= DIVA_RESET; /* Reset Off */ + byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + if (cs->subtyp == DIVA_ISA) + cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A; + else + cs->hw.diva.ctrl_reg |= DIVA_PCI_LED_A; + byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); + } + restore_flags(flags); } #define DIVA_ASSIGN 1 @@ -260,6 +366,8 @@ diva_led_handler(struct IsdnCardState *cs) { int blink = 0; + if (cs->subtyp == DIVA_IPAC_ISA) + return; del_timer(&cs->hw.diva.tl); if (cs->hw.diva.status & DIVA_ASSIGN) cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ? @@ -272,14 +380,14 @@ diva_led_handler(struct IsdnCardState *cs) if (cs->hw.diva.status & 0xf000) cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ? DIVA_ISA_LED_B : DIVA_PCI_LED_B; - else if (cs->hw.diva.status & 0x0f00) { + else if (cs->hw.diva.status & 0x0f00) { cs->hw.diva.ctrl_reg ^= (DIVA_ISA == cs->subtyp) ? DIVA_ISA_LED_B : DIVA_PCI_LED_B; blink = 500; } else cs->hw.diva.ctrl_reg &= ~((DIVA_ISA == cs->subtyp) ? DIVA_ISA_LED_B : DIVA_PCI_LED_B); - + byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); if (blink) { init_timer(&cs->hw.diva.tl); @@ -291,6 +399,8 @@ diva_led_handler(struct IsdnCardState *cs) static int Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg) { + u_int irq_flag = I4L_IRQ_FLAG; + switch (mt) { case CARD_RESET: reset_diva(cs); @@ -299,36 +409,40 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg) release_io_diva(cs); return(0); case CARD_SETIRQ: - return(request_irq(cs->irq, &diva_interrupt, - I4L_IRQ_FLAG, "HiSax", cs)); + if (cs->subtyp == DIVA_PCI) + irq_flag |= SA_SHIRQ; + if (cs->subtyp == DIVA_IPAC_ISA) { + return(request_irq(cs->irq, &diva_interrupt_ipac, + irq_flag, "HiSax", cs)); + } else { + return(request_irq(cs->irq, &diva_interrupt, + irq_flag, "HiSax", cs)); + } case CARD_INIT: - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + inithscxisac(cs, 3); return(0); case CARD_TEST: return(0); - case MDL_REMOVE_REQ: + case (MDL_REMOVE | REQUEST): cs->hw.diva.status = 0; break; - case MDL_ASSIGN_REQ: + case (MDL_ASSIGN | REQUEST): cs->hw.diva.status |= DIVA_ASSIGN; break; case MDL_INFO_SETUP: - if ((int)arg) + if ((long)arg) cs->hw.diva.status |= 0x0200; else cs->hw.diva.status |= 0x0100; break; case MDL_INFO_CONN: - if ((int)arg) + if ((long)arg) cs->hw.diva.status |= 0x2000; else cs->hw.diva.status |= 0x1000; break; case MDL_INFO_REL: - if ((int)arg) { + if ((long)arg) { cs->hw.diva.status &= ~0x2000; cs->hw.diva.status &= ~0x0200; } else { @@ -337,18 +451,19 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg) } break; } - diva_led_handler(cs); + if (cs->subtyp != DIVA_IPAC_ISA) + diva_led_handler(cs); return(0); } - - -static int pci_index __initdata = 0; +static struct pci_dev *dev_diva __initdata = NULL; +static struct pci_dev *dev_diva_u __initdata = NULL; __initfunc(int setup_diva(struct IsdnCard *card)) { int bytecnt; + u_char val; struct IsdnCardState *cs = card->cs; char tmp[64]; @@ -358,64 +473,72 @@ setup_diva(struct IsdnCard *card)) return(0); cs->hw.diva.status = 0; if (card->para[1]) { - cs->subtyp = DIVA_ISA; cs->hw.diva.ctrl_reg = 0; cs->hw.diva.cfg_reg = card->para[1]; - cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL; - cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA; - cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR; - cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR; + val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR, + cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID); + printk(KERN_INFO "Diva: IPAC version %x\n", val); + if (val == 1) { + cs->subtyp = DIVA_IPAC_ISA; + cs->hw.diva.ctrl = 0; + cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR; + cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->subtyp = DIVA_ISA; + cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL; + cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA; + cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA; + cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR; + cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR; + } cs->irq = card->para[0]; bytecnt = 8; } else { #if CONFIG_PCI - u_char pci_bus, pci_device_fn, pci_irq; - u_int pci_ioaddr; + if (!pci_present()) { + printk(KERN_ERR "Diva: no PCI bus present\n"); + return(0); + } cs->subtyp = 0; - for (; pci_index < 0xff; pci_index++) { - if (pcibios_find_device(PCI_VENDOR_EICON_DIEHL, - PCI_DIVA20_ID, pci_index, &pci_bus, &pci_device_fn) - == PCIBIOS_SUCCESSFUL) + if ((dev_diva = pci_find_device(PCI_VENDOR_EICON_DIEHL, + PCI_DIVA20_ID, dev_diva))) { cs->subtyp = DIVA_PCI; - else if (pcibios_find_device(PCI_VENDOR_EICON_DIEHL, - PCI_DIVA20_ID, pci_index, &pci_bus, &pci_device_fn) - == PCIBIOS_SUCCESSFUL) + /* get IRQ */ + cs->irq = dev_diva->irq; + /* get IO address */ + cs->hw.diva.cfg_reg = dev_diva->base_address[2] + & PCI_BASE_ADDRESS_IO_MASK; + } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_EICON_DIEHL, + PCI_DIVA20_U_ID, dev_diva_u))) { cs->subtyp = DIVA_PCI; - else - break; /* get IRQ */ - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq); - + cs->irq = dev_diva_u->irq; /* get IO address */ - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_2, &pci_ioaddr); - if (cs->subtyp) - break; - } - if (!cs->subtyp) { + cs->hw.diva.cfg_reg = dev_diva_u->base_address[2] + & PCI_BASE_ADDRESS_IO_MASK; + } else { printk(KERN_WARNING "Diva: No PCI card found\n"); return(0); } - if (!pci_irq) { + + if (!cs->irq) { printk(KERN_WARNING "Diva: No IRQ for PCI card found\n"); return(0); } - if (!pci_ioaddr) { + if (!cs->hw.diva.cfg_reg) { printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n"); return(0); } - pci_ioaddr &= ~3; /* remove io/mem flag */ - cs->hw.diva.cfg_reg = pci_ioaddr; - cs->hw.diva.ctrl = pci_ioaddr + DIVA_PCI_CTRL; - cs->hw.diva.isac = pci_ioaddr + DIVA_PCI_ISAC_DATA; - cs->hw.diva.hscx = pci_ioaddr + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = pci_ioaddr + DIVA_PCI_ISAC_ADR; - cs->hw.diva.hscx_adr = pci_ioaddr + DIVA_HSCX_ADR; - cs->irq = pci_irq; + cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL; + cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA; + cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA; + cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR; + cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR; bytecnt = 32; #else printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n"); @@ -426,7 +549,8 @@ setup_diva(struct IsdnCard *card)) printk(KERN_INFO "Diva: %s card configured at 0x%x IRQ %d\n", - (cs->subtyp == DIVA_ISA) ? "ISA" : "PCI", + (cs->subtyp == DIVA_PCI) ? "PCI" : + (cs->subtyp == DIVA_ISA) ? "ISA" : "IPAC", cs->hw.diva.cfg_reg, cs->irq); if (check_region(cs->hw.diva.cfg_reg, bytecnt)) { printk(KERN_WARNING @@ -440,24 +564,32 @@ setup_diva(struct IsdnCard *card)) } reset_diva(cs); - cs->hw.diva.tl.function = (void *) diva_led_handler; - cs->hw.diva.tl.data = (long) cs; - init_timer(&cs->hw.diva.tl); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; cs->BC_Read_Reg = &ReadHSCX; cs->BC_Write_Reg = &WriteHSCX; cs->BC_Send_Data = &hscx_fill_fifo; cs->cardmsg = &Diva_card_msg; - - ISACVersion(cs, "Diva:"); - if (HscxVersion(cs, "Diva:")) { - printk(KERN_WARNING + if (cs->subtyp == DIVA_IPAC_ISA) { + cs->readisac = &ReadISAC_IPAC; + cs->writeisac = &WriteISAC_IPAC; + cs->readisacfifo = &ReadISACfifo_IPAC; + cs->writeisacfifo = &WriteISACfifo_IPAC; + val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ID); + printk(KERN_INFO "Diva: IPAC version %x\n", val); + } else { + cs->hw.diva.tl.function = (void *) diva_led_handler; + cs->hw.diva.tl.data = (long) cs; + init_timer(&cs->hw.diva.tl); + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + ISACVersion(cs, "Diva:"); + if (HscxVersion(cs, "Diva:")) { + printk(KERN_WARNING "Diva: wrong HSCX versions check IO address\n"); - release_io_diva(cs); - return (0); + release_io_diva(cs); + return (0); + } } return (1); } diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c index 008178065..50f9df9c0 100644 --- a/drivers/isdn/hisax/elsa.c +++ b/drivers/isdn/hisax/elsa.c @@ -1,13 +1,41 @@ -/* $Id: elsa.c,v 2.6 1998/02/02 13:29:40 keil Exp $ +/* $Id: elsa.c,v 2.12 1998/11/15 23:54:35 keil Exp $ * elsa.c low level stuff for Elsa isdn cards * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) + * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/HiSax.cert * * Thanks to Elsa GmbH for documents and informations * + * Klaus Lichtenwalder (Klaus.Lichtenwalder@WebForum.DE) + * for ELSA PCMCIA support + * * * $Log: elsa.c,v $ + * Revision 2.12 1998/11/15 23:54:35 keil + * changes from 2.0 + * + * Revision 2.11 1998/08/20 13:50:34 keil + * More support for hybrid modem (not working yet) + * + * Revision 2.10 1998/08/13 23:36:22 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 2.9 1998/05/25 12:57:48 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 2.8 1998/04/15 16:41:42 keil + * QS3000 PCI support + * new init code + * new PCI init (2.1.94) + * + * Revision 2.7 1998/03/07 22:56:58 tsbogend + * made HiSax working on Linux/Alpha + * * Revision 2.6 1998/02/02 13:29:40 keil * fast io * @@ -29,15 +57,6 @@ * Revision 2.0 1997/06/26 11:02:40 keil * New Layer and card interface * - * Revision 1.14 1997/04/13 19:53:25 keil - * Fixed QS1000 init, change in IRQ check delay for SMP - * - * Revision 1.13 1997/04/07 22:58:07 keil - * need include config.h - * - * Revision 1.12 1997/04/06 22:54:14 keil - * Using SKB's - * * old changes removed KKe * */ @@ -51,14 +70,16 @@ #include "hscx.h" #include "isdnl1.h" #include <linux/pci.h> -#include <linux/bios32.h> + +//#define KDEBUG_DEF +//#include "../kdebug.h" extern const char *CardType[]; -const char *Elsa_revision = "$Revision: 2.6 $"; +static const char *Elsa_revision = "$Revision: 2.12 $"; const char *Elsa_Types[] = {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", - "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI"}; + "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI", "QS 3000 PCI"}; const char *ITACVer[] = {"?0?", "?1?", "?2?", "?3?", "?4?", "V2.2", @@ -87,11 +108,13 @@ const char *ITACVer[] = #define ELSA_QS1000 7 #define ELSA_QS3000 8 #define ELSA_QS1000PCI 9 +#define ELSA_QS3000PCI 10 /* PCI stuff */ #define PCI_VENDOR_ELSA 0x1048 #define PCI_QS1000_ID 0x1000 - +#define PCI_QS3000_ID 0x3000 +#define ELSA_PCI_IRQ_MASK 0x04 /* ITAC Registeradressen (only Microlink PC) */ #define ITAC_SYS 0x34 @@ -128,6 +151,30 @@ const char *ITACVer[] = #define ELSA_BAD_PWR 2 #define ELSA_ASSIGN 4 +#define RS_ISR_PASS_LIMIT 256 +#define _INLINE_ inline +#define FLG_MODEM_ACTIVE 1 +/* IPAC AUX */ +#define ELSA_IPAC_LINE_LED 0x40 /* Bit 6 Gelbe LED */ +#define ELSA_IPAC_STAT_LED 0x80 /* Bit 7 Gruene LED */ + +const u_char ARCOFI_VERSION[] = {2,0xa0,0}; +const u_char ARCOFI_COP_5[] = {4,0xa1,0x25,0xbb,0x4a}; /* GTX */ +const u_char ARCOFI_COP_6[] = {6,0xa1,0x26,0,0,0x82,0x7c}; /* GRL GRH */ +const u_char ARCOFI_COP_7[] = {4,0xa1,0x27,0x80,0x80}; /* GZ */ +const u_char ARCOFI_COP_8[] = {10,0xa1,0x28,0x49,0x31,0x8,0x13,0x6e,0x88,0x2a,0x61}; /* TX */ +const u_char ARCOFI_COP_9[] = {10,0xa1,0x29,0x80,0xcb,0xe9,0x88,0x00,0xc8,0xd8,0x80}; /* RX */ +const u_char ARCOFI_XOP_0[] = {2,0xa1,0x30}; /* PWR Down */ +const u_char ARCOFI_XOP_1[] = {2,0xa1,0x31}; /* PWR UP */ +const u_char ARCOFI_XOP_F[] = {2,0xa1,0x3f}; /* Normal OP */ +const u_char ARCOFI_SOP_F[] = {10,0xa1,0x1f,0x00,0x50,0x10,0x00,0x00,0x80,0x02,0x12}; + +static void set_arcofi(struct IsdnCardState *cs, int bc); + +#if ARCOFI_USE +#include "elsa_ser.c" +#endif + static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off) { @@ -302,6 +349,21 @@ elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs) printk(KERN_WARNING "Elsa: Spurious interrupt!\n"); return; } + if ((cs->typ == ISDN_CTYPE_ELSA_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 "Elsa: card not available!\n"); + return; + } +#if ARCOFI_USE + if (cs->hw.elsa.MFlag) { + val = serial_inp(cs, UART_IIR); + if (!(val & UART_IIR_NO_INT)) { + debugl1(cs,"IIR %02x", val); + rs_interrupt_elsa(intno, cs); + } + } +#endif val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); Start_HSCX: if (val) { @@ -338,6 +400,14 @@ elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs) cs->hw.elsa.counter++; } } + if (cs->hw.elsa.MFlag) { + val = serial_inp(cs, UART_MCR); + val ^= 0x8; + serial_outp(cs, UART_MCR, val); + val = serial_inp(cs, UART_MCR); + val ^= 0x8; + serial_outp(cs, UART_MCR, val); + } if (cs->hw.elsa.trig) byteout(cs->hw.elsa.trig, 0x00); writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0x0); @@ -350,25 +420,28 @@ elsa_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; u_char ista,val; - char tmp[64]; int icnt=20; if (!cs) { printk(KERN_WARNING "Elsa: Spurious interrupt!\n"); return; } - if ((cs->typ == ISDN_CTYPE_ELSA_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 "Elsa: card not available!\n"); - return; + val = bytein(cs->hw.elsa.cfg + 0x4c); /* PCI IRQ */ + if (!(val & ELSA_PCI_IRQ_MASK)) + return; +#if ARCOFI_USE + if (cs->hw.elsa.MFlag) { + val = serial_inp(cs, UART_IIR); + if (!(val & UART_IIR_NO_INT)) { + debugl1(cs,"IIR %02x", val); + rs_interrupt_elsa(intno, cs); + } } +#endif ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA); Start_IPAC: - if (cs->debug & L1_DEB_IPAC) { - sprintf(tmp, "IPAC ISTA %02X", ista); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_IPAC) + debugl1(cs, "IPAC ISTA %02X", ista); if (ista & 0x0f) { val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); if (ista & 0x01) @@ -409,15 +482,24 @@ release_io_elsa(struct IsdnCardState *cs) del_timer(&cs->hw.elsa.tl); if (cs->hw.elsa.ctrl) byteout(cs->hw.elsa.ctrl, 0); /* LEDs Out */ - if ((cs->subtyp == ELSA_PCFPRO) || - (cs->subtyp == ELSA_QS3000) || - (cs->subtyp == ELSA_PCF)) - bytecnt = 16; if (cs->subtyp == ELSA_QS1000PCI) { byteout(cs->hw.elsa.cfg + 0x4c, 0x01); /* disable IRQ */ + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); bytecnt = 2; release_region(cs->hw.elsa.cfg, 0x80); } + if (cs->subtyp == ELSA_QS3000PCI) { + byteout(cs->hw.elsa.cfg + 0x4c, 0x03); /* disable ELSA PCI IRQ */ + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); + release_region(cs->hw.elsa.cfg, 0x80); + } + if ((cs->subtyp == ELSA_PCFPRO) || + (cs->subtyp == ELSA_QS3000) || + (cs->subtyp == ELSA_PCF) || + (cs->subtyp == ELSA_QS3000PCI)) { + bytecnt = 16; + release_modem(cs); + } if (cs->hw.elsa.base) release_region(cs->hw.elsa.base, bytecnt); } @@ -445,7 +527,7 @@ reset_elsa(struct IsdnCardState *cs) if (cs->hw.elsa.trig) byteout(cs->hw.elsa.trig, 0xff); } - if (cs->subtyp == ELSA_QS1000PCI) { + if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) { save_flags(flags); sti(); writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20); @@ -455,35 +537,55 @@ reset_elsa(struct IsdnCardState *cs) current->state = TASK_INTERRUPTIBLE; schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0); - schedule(); restore_flags(flags); - byteout(cs->hw.elsa.cfg + 0x4c, 0x41); /* enable ELSA PCI IRQ */ + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x0); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0x3c); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); + if (cs->subtyp == ELSA_QS1000PCI) + byteout(cs->hw.elsa.cfg + 0x4c, 0x41); /* enable ELSA PCI IRQ */ + else if (cs->subtyp == ELSA_QS3000PCI) + byteout(cs->hw.elsa.cfg + 0x4c, 0x43); /* enable ELSA PCI IRQ */ } } -const u_char ARCOFI_VERSION[] = {2,0xa0,0}; -const u_char ARCOFI_COP_5[] = {4,0xa1,0x25,0xbb,0x4a}; /* GTX */ -const u_char ARCOFI_COP_6[] = {6,0xa1,0x26,0,0,0x82,0x7c}; /* GRL GRH */ -const u_char ARCOFI_COP_7[] = {4,0xa1,0x27,0x80,0x80}; /* GZ */ -const u_char ARCOFI_COP_8[] = {10,0xa1,0x28,0x49,0x31,0x8,0x13,0x6e,0x88,0x2a,0x61}; /* TX */ -const u_char ARCOFI_COP_9[] = {10,0xa1,0x29,0x80,0xcb,0x9e,0x88,0x00,0xc8,0xd8,0x80}; /* RX */ -const u_char ARCOFI_XOP_0[] = {2,0xa1,0x30}; /* PWR Down */ -const u_char ARCOFI_XOP_1[] = {2,0xa1,0x31}; /* PWR Down */ -const u_char ARCOFI_XOP_F[] = {2,0xa1,0x3f}; /* PWR Down */ -const u_char ARCOFI_SOP_F[] = {10,0xa1,0x1f,0x00,0x50,0x10,0x00,0x00,0x80,0x02,0x12}; - static void init_arcofi(struct IsdnCardState *cs) { - send_arcofi(cs, ARCOFI_COP_5); - send_arcofi(cs, ARCOFI_COP_6); - send_arcofi(cs, ARCOFI_COP_7); - send_arcofi(cs, ARCOFI_COP_8); - send_arcofi(cs, ARCOFI_COP_9); - send_arcofi(cs, ARCOFI_SOP_F); - send_arcofi(cs, ARCOFI_XOP_F); + send_arcofi(cs, ARCOFI_XOP_0, 1, 0); +/* send_arcofi(cs, ARCOFI_XOP_F, 1); +*/ } +#define ARCDEL 500 + static void +set_arcofi(struct IsdnCardState *cs, int bc) { + long flags; + + debugl1(cs,"set_arcofi bc=%d", bc); + save_flags(flags); + sti(); + send_arcofi(cs, ARCOFI_XOP_0, bc, 0); + udelay(ARCDEL); + send_arcofi(cs, ARCOFI_COP_5, bc, 0); + udelay(ARCDEL); + send_arcofi(cs, ARCOFI_COP_6, bc, 0); + udelay(ARCDEL); + send_arcofi(cs, ARCOFI_COP_7, bc, 0); + udelay(ARCDEL); + send_arcofi(cs, ARCOFI_COP_8, bc, 0); + udelay(ARCDEL); + send_arcofi(cs, ARCOFI_COP_9, bc, 0); + udelay(ARCDEL); + send_arcofi(cs, ARCOFI_SOP_F, bc, 0); + udelay(ARCDEL); + send_arcofi(cs, ARCOFI_XOP_1, bc, 0); + udelay(ARCDEL); + send_arcofi(cs, ARCOFI_XOP_F, bc, 0); + restore_flags(flags); + debugl1(cs,"end set_arcofi bc=%d", bc); +} + +static int check_arcofi(struct IsdnCardState *cs) { #if ARCOFI_USE @@ -496,13 +598,12 @@ check_arcofi(struct IsdnCardState *cs) if (!(cs->mon_tx=kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "ISAC MON TX out of buffers!"); - return; + return(0); } - send_arcofi(cs, ARCOFI_VERSION); + send_arcofi(cs, ARCOFI_VERSION, 0, 1); if (test_and_clear_bit(HW_MON1_TX_END, &cs->HW_Flags)) { if (test_and_clear_bit(HW_MON1_RX_END, &cs->HW_Flags)) { - sprintf(tmp, "Arcofi response received %d bytes", cs->mon_rxp); - debugl1(cs, tmp); + debugl1(cs, "Arcofi response received %d bytes", cs->mon_rxp); p = cs->mon_rx; t = tmp; t += sprintf(tmp, "Arcofi data"); @@ -531,8 +632,7 @@ check_arcofi(struct IsdnCardState *cs) cs->mon_rxp = 0; } } else if (cs->mon_tx) { - sprintf(tmp, "Arcofi not detected"); - debugl1(cs, tmp); + debugl1(cs, "Arcofi not detected"); } if (arcofi_present) { if (cs->subtyp==ELSA_QS1000) { @@ -573,8 +673,10 @@ check_arcofi(struct IsdnCardState *cs) Elsa_Types[cs->subtyp], cs->hw.elsa.base+8); init_arcofi(cs); + return(1); } #endif + return(0); } static void @@ -582,8 +684,7 @@ elsa_led_handler(struct IsdnCardState *cs) { int blink = 0; - if ((cs->subtyp == ELSA_PCMCIA) && - (cs->subtyp == ELSA_QS1000PCI)) + if (cs->subtyp == ELSA_PCMCIA) return; del_timer(&cs->hw.elsa.tl); if (cs->hw.elsa.status & ELSA_ASSIGN) @@ -602,7 +703,16 @@ elsa_led_handler(struct IsdnCardState *cs) } else cs->hw.elsa.ctrl_reg &= ~ELSA_LINE_LED; - byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); + if ((cs->subtyp == ELSA_QS1000PCI) || + (cs->subtyp == ELSA_QS3000PCI)) { + u_char led = 0xff; + if (cs->hw.elsa.ctrl_reg & ELSA_LINE_LED) + led ^= ELSA_IPAC_LINE_LED; + if (cs->hw.elsa.ctrl_reg & ELSA_STAT_LED) + led ^= ELSA_IPAC_STAT_LED; + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, led); + } else + byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); if (blink) { init_timer(&cs->hw.elsa.tl); cs->hw.elsa.tl.expires = jiffies + ((blink * HZ) / 1000); @@ -613,8 +723,9 @@ elsa_led_handler(struct IsdnCardState *cs) static int Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - int pwr, ret = 0; - long flags; + int len, ret = 0; + u_char *msg; + long flags; switch (mt) { case CARD_RESET: @@ -624,28 +735,33 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg) release_io_elsa(cs); return(0); case CARD_SETIRQ: - if (cs->subtyp == ELSA_QS1000PCI) + if ((cs->subtyp == ELSA_QS1000PCI) || + (cs->subtyp == ELSA_QS3000PCI)) ret = request_irq(cs->irq, &elsa_interrupt_ipac, - I4L_IRQ_FLAG, "HiSax", cs); + I4L_IRQ_FLAG | SA_SHIRQ, "HiSax", cs); else ret = request_irq(cs->irq, &elsa_interrupt, I4L_IRQ_FLAG, "HiSax", cs); return(ret); case CARD_INIT: - if (cs->hw.elsa.trig) - byteout(cs->hw.elsa.trig, 0xff); - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); - if (cs->subtyp == ELSA_QS1000) { + cs->debug |= L1_DEB_IPAC; + inithscxisac(cs, 1); + if ((cs->subtyp == ELSA_QS1000) || + (cs->subtyp == ELSA_QS3000)) + { byteout(cs->hw.elsa.timer, 0); - byteout(cs->hw.elsa.trig, 0xff); } + if (cs->hw.elsa.trig) + byteout(cs->hw.elsa.trig, 0xff); + inithscxisac(cs, 2); return(0); case CARD_TEST: - if ((cs->subtyp != ELSA_PCMCIA) && - (cs->subtyp != ELSA_QS1000PCI)) { + if ((cs->subtyp == ELSA_PCMCIA) || + (cs->subtyp == ELSA_QS1000PCI)) { + return(0); + } else if (cs->subtyp == ELSA_QS3000PCI) { + ret = 0; + } else { save_flags(flags); cs->hw.elsa.counter = 0; sti(); @@ -653,48 +769,52 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg) cs->hw.elsa.status |= ELSA_TIMER_AKTIV; byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); byteout(cs->hw.elsa.timer, 0); - } else - return(0); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout((110*HZ)/1000); /* Timeout 110ms */ - restore_flags(flags); - cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT; - byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); - 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) { - printk(KERN_INFO "Elsa: timer and irq OK\n"); - ret = 0; - } else { - printk(KERN_WARNING - "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n", - cs->hw.elsa.counter, cs->irq); - ret = 1; + current->state = TASK_INTERRUPTIBLE; + /* Timeout 110ms */ + schedule_timeout((110*HZ)/1000); + restore_flags(flags); + cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT; + byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); + 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) { + printk(KERN_INFO "Elsa: timer and irq OK\n"); + ret = 0; + } else { + printk(KERN_WARNING + "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n", + cs->hw.elsa.counter, cs->irq); + ret = 1; + } } - check_arcofi(cs); +#if ARCOFI_USE + if (check_arcofi(cs)) { + init_modem(cs); + } +#endif elsa_led_handler(cs); return(ret); - case MDL_REMOVE_REQ: + case (MDL_REMOVE | REQUEST): cs->hw.elsa.status &= 0; break; - case MDL_ASSIGN_REQ: + case (MDL_ASSIGN | REQUEST): cs->hw.elsa.status |= ELSA_ASSIGN; break; case MDL_INFO_SETUP: - if ((int) arg) + if ((long) arg) cs->hw.elsa.status |= 0x0200; else cs->hw.elsa.status |= 0x0100; break; case MDL_INFO_CONN: - if ((int) arg) + if ((long) arg) cs->hw.elsa.status |= 0x2000; else cs->hw.elsa.status |= 0x1000; break; case MDL_INFO_REL: - if ((int) arg) { + if ((long) arg) { cs->hw.elsa.status &= ~0x2000; cs->hw.elsa.status &= ~0x0200; } else { @@ -703,13 +823,23 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg) } break; case CARD_AUX_IND: + if (cs->hw.elsa.MFlag) { + if (!arg) + return(0); + msg = arg; + len = *msg; + msg++; + modem_write_cmd(cs, msg, len); + } break; } - pwr = bytein(cs->hw.elsa.ale); - if (pwr & 0x08) - cs->hw.elsa.status |= ELSA_BAD_PWR; - else - cs->hw.elsa.status &= ~ELSA_BAD_PWR; + if (cs->typ == ISDN_CTYPE_ELSA) { + int pwr = bytein(cs->hw.elsa.ale); + if (pwr & 0x08) + cs->hw.elsa.status |= ELSA_BAD_PWR; + else + cs->hw.elsa.status &= ~ELSA_BAD_PWR; + } elsa_led_handler(cs); return(ret); } @@ -778,7 +908,8 @@ probe_elsa(struct IsdnCardState *cs) return (CARD_portlist[i]); } -static int pci_index __initdata = 0; +static struct pci_dev *dev_qs1000 __initdata = NULL; +static struct pci_dev *dev_qs3000 __initdata = NULL; int setup_elsa(struct IsdnCard *card) @@ -793,6 +924,7 @@ setup_elsa(struct IsdnCard *card) printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp)); cs->hw.elsa.ctrl_reg = 0; cs->hw.elsa.status = 0; + cs->hw.elsa.MFlag = 0; if (cs->typ == ISDN_CTYPE_ELSA) { cs->hw.elsa.base = card->para[0]; printk(KERN_INFO "Elsa: Microlink IO probing\n"); @@ -886,59 +1018,62 @@ setup_elsa(struct IsdnCard *card) cs->irq); } else if (cs->typ == ISDN_CTYPE_ELSA_PCI) { #if CONFIG_PCI - u_char pci_bus, pci_device_fn, pci_irq; - u_int pci_ioaddr; - + if (!pci_present()) { + printk(KERN_ERR "Elsa: no PCI bus present\n"); + return(0); + } cs->subtyp = 0; - for (; pci_index < 0xff; pci_index++) { - if (pcibios_find_device(PCI_VENDOR_ELSA, - PCI_QS1000_ID, pci_index, &pci_bus, &pci_device_fn) - == PCIBIOS_SUCCESSFUL) + if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ELSA, PCI_QS1000_ID, + dev_qs1000))) { cs->subtyp = ELSA_QS1000PCI; - else - break; - /* get IRQ */ - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq); - - /* get IO address */ - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_1, &pci_ioaddr); - pci_ioaddr &= ~3; /* remove io/mem flag */ - cs->hw.elsa.cfg = pci_ioaddr; - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_3, &pci_ioaddr); - if (cs->subtyp) - break; - } - if (!cs->subtyp) { + cs->irq = dev_qs1000->irq; + cs->hw.elsa.cfg = dev_qs1000->base_address[1] & + PCI_BASE_ADDRESS_IO_MASK; + cs->hw.elsa.base = dev_qs1000->base_address[3] & + PCI_BASE_ADDRESS_IO_MASK; + } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ELSA, + PCI_QS3000_ID, dev_qs3000))) { + cs->subtyp = ELSA_QS3000PCI; + cs->irq = dev_qs3000->irq; + cs->hw.elsa.cfg = dev_qs3000->base_address[1] & + PCI_BASE_ADDRESS_IO_MASK; + cs->hw.elsa.base = dev_qs3000->base_address[3] & + PCI_BASE_ADDRESS_IO_MASK; + } else { printk(KERN_WARNING "Elsa: No PCI card found\n"); return(0); } - if (!pci_irq) { + if (!cs->irq) { printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n"); return(0); } - if (!pci_ioaddr) { + if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) { printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n"); return(0); } - pci_ioaddr &= ~3; /* remove io/mem flag */ - cs->hw.elsa.base = pci_ioaddr; - cs->hw.elsa.ale = pci_ioaddr; - cs->hw.elsa.isac = pci_ioaddr +1; - cs->hw.elsa.hscx = pci_ioaddr +1; - cs->irq = pci_irq; + cs->hw.elsa.ale = cs->hw.elsa.base; + cs->hw.elsa.isac = cs->hw.elsa.base +1; + cs->hw.elsa.hscx = cs->hw.elsa.base +1; test_and_set_bit(HW_IPAC, &cs->HW_Flags); cs->hw.elsa.timer = 0; cs->hw.elsa.trig = 0; printk(KERN_INFO - "Elsa: %s defined at 0x%x/0x%x IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - cs->hw.elsa.cfg, - cs->irq); + "Elsa: %s defined at 0x%x/0x%x IRQ %d\n", + Elsa_Types[cs->subtyp], + cs->hw.elsa.base, + cs->hw.elsa.cfg, + cs->irq); + if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) { + printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n"); + printk(KERN_WARNING "Elsa: If your system hangs now, read\n"); + printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n"); + printk(KERN_WARNING "Elsa: Waiting 5 sec to sync discs\n"); + save_flags(flags); + sti(); + HZDELAY(500); /* wait 500*10 ms */ + restore_flags(flags); + } #else printk(KERN_WARNING "Elsa: Elsa PCI and NO_PCI_BIOS\n"); printk(KERN_WARNING "Elsa: unable to config Elsa PCI\n"); @@ -957,6 +1092,7 @@ setup_elsa(struct IsdnCard *card) break; case ELSA_PCFPRO: case ELSA_PCF: + case ELSA_QS3000PCI: bytecnt = 16; break; case ELSA_QS1000PCI: @@ -980,7 +1116,7 @@ setup_elsa(struct IsdnCard *card) } else { request_region(cs->hw.elsa.base, bytecnt, "elsa isdn"); } - if (cs->subtyp == ELSA_QS1000PCI) { + if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) { if (check_region(cs->hw.elsa.cfg, 0x80)) { printk(KERN_WARNING "HiSax: %s pci port %x-%x already in use\n", @@ -1020,12 +1156,12 @@ setup_elsa(struct IsdnCard *card) } printk(KERN_INFO "Elsa: timer OK; resetting card\n"); } - reset_elsa(cs); cs->BC_Read_Reg = &ReadHSCX; cs->BC_Write_Reg = &WriteHSCX; cs->BC_Send_Data = &hscx_fill_fifo; cs->cardmsg = &Elsa_card_msg; - if (cs->subtyp == ELSA_QS1000PCI) { + reset_elsa(cs); + if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) { cs->readisac = &ReadISAC_IPAC; cs->writeisac = &WriteISAC_IPAC; cs->readisacfifo = &ReadISACfifo_IPAC; @@ -1056,4 +1192,3 @@ setup_elsa(struct IsdnCard *card) } return (1); } - diff --git a/drivers/isdn/hisax/fsm.c b/drivers/isdn/hisax/fsm.c index ae0662f3f..aa0ff4adb 100644 --- a/drivers/isdn/hisax/fsm.c +++ b/drivers/isdn/hisax/fsm.c @@ -1,4 +1,4 @@ -/* $Id: fsm.c,v 1.7 1997/11/06 17:09:13 keil Exp $ +/* $Id: fsm.c,v 1.10 1998/11/15 23:54:39 keil Exp $ * Author Karsten Keil (keil@temic-ech.spacenet.de) * based on the teles driver from Jan den Ouden @@ -7,6 +7,18 @@ * Fritz Elfert * * $Log: fsm.c,v $ + * Revision 1.10 1998/11/15 23:54:39 keil + * changes from 2.0 + * + * Revision 1.9 1998/03/26 07:10:02 paul + * The jumpmatrix table in struct Fsm was an array of "int". This is not + * large enough for pointers to functions on Linux/Alpha (instant crash + * on "insmod hisax). Now there is a typedef for the pointer to function. + * This also prevents warnings about "incompatible pointer types". + * + * Revision 1.8 1998/03/07 22:56:59 tsbogend + * made HiSax working on Linux/Alpha + * * Revision 1.7 1997/11/06 17:09:13 keil * New 2.1 init code * @@ -41,18 +53,18 @@ FsmNew(struct Fsm *fsm, { int i; - fsm->jumpmatrix = (int *) - kmalloc(4L * fsm->state_count * fsm->event_count, GFP_KERNEL); - memset(fsm->jumpmatrix, 0, 4L * fsm->state_count * fsm->event_count); + fsm->jumpmatrix = (FSMFNPTR *) + kmalloc(sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count, GFP_KERNEL); + memset(fsm->jumpmatrix, 0, sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count); for (i = 0; i < fncount; i++) if ((fnlist[i].state>=fsm->state_count) || (fnlist[i].event>=fsm->event_count)) { - printk(KERN_ERR "FsmNew Error line %d st(%d/%d) ev(%d/%d)\n", - i,fnlist[i].state,fsm->state_count, - fnlist[i].event,fsm->event_count); + printk(KERN_ERR "FsmNew Error line %d st(%ld/%ld) ev(%ld/%ld)\n", + i,(long)fnlist[i].state,(long)fsm->state_count, + (long)fnlist[i].event,(long)fsm->event_count); } else fsm->jumpmatrix[fsm->state_count * fnlist[i].event + - fnlist[i].state] = (int) fnlist[i].routine; + fnlist[i].state] = (FSMFNPTR) fnlist[i].routine; } void @@ -64,31 +76,26 @@ FsmFree(struct Fsm *fsm) int FsmEvent(struct FsmInst *fi, int event, void *arg) { - void (*r) (struct FsmInst *, int, void *); - char str[80]; + FSMFNPTR r; if ((fi->state>=fi->fsm->state_count) || (event >= fi->fsm->event_count)) { - printk(KERN_ERR "FsmEvent Error st(%d/%d) ev(%d/%d)\n", - fi->state,fi->fsm->state_count,event,fi->fsm->event_count); + printk(KERN_ERR "FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n", + (long)fi->state,(long)fi->fsm->state_count,event,(long)fi->fsm->event_count); return(1); } - r = (void (*)) fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state]; + r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state]; if (r) { - if (fi->debug) { - sprintf(str, "State %s Event %s", + if (fi->debug) + fi->printdebug(fi, "State %s Event %s", fi->fsm->strState[fi->state], fi->fsm->strEvent[event]); - fi->printdebug(fi, str); - } r(fi, event, arg); return (0); } else { - if (fi->debug) { - sprintf(str, "State %s Event %s no routine", + if (fi->debug) + fi->printdebug(fi, "State %s Event %s no routine", fi->fsm->strState[fi->state], fi->fsm->strEvent[event]); - fi->printdebug(fi, str); - } return (!0); } } @@ -96,25 +103,18 @@ FsmEvent(struct FsmInst *fi, int event, void *arg) void FsmChangeState(struct FsmInst *fi, int newstate) { - char str[80]; - fi->state = newstate; - if (fi->debug) { - sprintf(str, "ChangeState %s", + if (fi->debug) + fi->printdebug(fi, "ChangeState %s", fi->fsm->strState[newstate]); - fi->printdebug(fi, str); - } } static void FsmExpireTimer(struct FsmTimer *ft) { #if FSM_TIMER_DEBUG - if (ft->fi->debug) { - char str[40]; - sprintf(str, "FsmExpireTimer %lx", (long) ft); - ft->fi->printdebug(ft->fi, str); - } + if (ft->fi->debug) + ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft); #endif FsmEvent(ft->fi, ft->event, ft->arg); } @@ -126,11 +126,8 @@ FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft) ft->tl.function = (void *) FsmExpireTimer; ft->tl.data = (long) ft; #if FSM_TIMER_DEBUG - if (ft->fi->debug) { - char str[40]; - sprintf(str, "FsmInitTimer %lx", (long) ft); - ft->fi->printdebug(ft->fi, str); - } + if (ft->fi->debug) + ft->fi->printdebug(ft->fi, "FsmInitTimer %lx", (long) ft); #endif init_timer(&ft->tl); } @@ -139,11 +136,8 @@ void FsmDelTimer(struct FsmTimer *ft, int where) { #if FSM_TIMER_DEBUG - if (ft->fi->debug) { - char str[40]; - sprintf(str, "FsmDelTimer %lx %d", (long) ft, where); - ft->fi->printdebug(ft->fi, str); - } + if (ft->fi->debug) + ft->fi->printdebug(ft->fi, "FsmDelTimer %lx %d", (long) ft, where); #endif del_timer(&ft->tl); } @@ -154,11 +148,9 @@ FsmAddTimer(struct FsmTimer *ft, { #if FSM_TIMER_DEBUG - if (ft->fi->debug) { - char str[40]; - sprintf(str, "FsmAddTimer %lx %d %d", (long) ft, millisec, where); - ft->fi->printdebug(ft->fi, str); - } + if (ft->fi->debug) + ft->fi->printdebug(ft->fi, "FsmAddTimer %lx %d %d", + (long) ft, millisec, where); #endif if (ft->tl.next || ft->tl.prev) { @@ -180,11 +172,9 @@ FsmRestartTimer(struct FsmTimer *ft, { #if FSM_TIMER_DEBUG - if (ft->fi->debug) { - char str[40]; - sprintf(str, "FsmRestartTimer %lx %d %d", (long) ft, millisec, where); - ft->fi->printdebug(ft->fi, str); - } + if (ft->fi->debug) + ft->fi->printdebug(ft->fi, "FsmRestartTimer %lx %d %d", + (long) ft, millisec, where); #endif if (ft->tl.next || ft->tl.prev) @@ -195,24 +185,3 @@ FsmRestartTimer(struct FsmTimer *ft, ft->tl.expires = jiffies + (millisec * HZ) / 1000; add_timer(&ft->tl); } - -void -jiftime(char *s, long mark) -{ - s += 8; - - *s-- = '\0'; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = '.'; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = mark % 6 + '0'; - mark /= 6; - *s-- = ':'; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = mark % 10 + '0'; -} diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c index c42a2bb56..b649c55f4 100644 --- a/drivers/isdn/hisax/hfc_2bds0.c +++ b/drivers/isdn/hisax/hfc_2bds0.c @@ -1,4 +1,4 @@ -/* $Id: hfc_2bds0.c,v 1.3 1998/02/12 23:07:22 keil Exp $ +/* $Id: hfc_2bds0.c,v 1.8 1998/11/15 23:54:40 keil Exp $ * * specific routines for CCD's HFC 2BDS0 * @@ -6,6 +6,22 @@ * * * $Log: hfc_2bds0.c,v $ + * Revision 1.8 1998/11/15 23:54:40 keil + * changes from 2.0 + * + * Revision 1.7 1998/09/30 22:24:45 keil + * Fix missing line in setstack* + * + * Revision 1.6 1998/08/13 23:36:26 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 1.5 1998/06/27 22:52:58 keil + * make 16.3c working with 3.0 + * + * Revision 1.4 1998/05/25 12:57:52 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * * Revision 1.3 1998/02/12 23:07:22 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -46,11 +62,8 @@ ReadReg(struct IsdnCardState *cs, int data, u_char reg) } ret = bytein(cs->hw.hfcD.addr); #if HFC_REG_DEBUG - if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) { - char tmp[32]; - sprintf(tmp, "t3c RD %02x %02x", reg, ret); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) + debugl1(cs, "t3c RD %02x %02x", reg, ret); #endif } else ret = bytein(cs->hw.hfcD.addr | 1); @@ -67,11 +80,8 @@ WriteReg(struct IsdnCardState *cs, int data, u_char reg, u_char value) if (data) byteout(cs->hw.hfcD.addr, value); #if HFC_REG_DEBUG - if (cs->debug & L1_DEB_HSCX_FIFO && (data != HFCD_DATA_NODEB)) { - char tmp[16]; - sprintf(tmp, "t3c W%c %02x %02x", data ? 'D' : 'C', reg, value); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_HSCX_FIFO && (data != HFCD_DATA_NODEB)) + debugl1(cs, "t3c W%c %02x %02x", data ? 'D' : 'C', reg, value); #endif } @@ -227,7 +237,6 @@ static struct sk_buff int chksum; long flags; u_char stat, cip; - char tmp[64]; if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) debugl1(cs, "hfc_empty_fifo"); @@ -283,11 +292,9 @@ static struct sk_buff WaitNoBusy(cs); stat = ReadReg(cs, HFCD_DATA, cip); sti(); - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc_empty_fifo %d chksum %x stat %x", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x", bcs->channel, chksum, stat); - debugl1(cs, tmp); - } if (stat) { debugl1(cs, "FIFO CRC error"); dev_kfree_skb(skb); @@ -315,14 +322,11 @@ hfc_fill_fifo(struct BCState *bcs) int idx, fcnt; int count; u_char cip; - char tmp[64]; - - if (!bcs->hw.hfc.tx_skb) + if (!bcs->tx_skb) return; - if (bcs->hw.hfc.tx_skb->len <= 0) + if (bcs->tx_skb->len <= 0) return; - save_flags(flags); cli(); SelFiFo(cs, HFCB_SEND | HFCB_CHANNEL(bcs->channel)); @@ -335,12 +339,10 @@ hfc_fill_fifo(struct BCState *bcs) bcs->hw.hfc.f2 = ReadReg(cs, HFCD_DATA, cip); bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_CHANNEL(bcs->channel)); sti(); - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)", bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2, bcs->hw.hfc.send[bcs->hw.hfc.f1]); - debugl1(cs, tmp); - } fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2; if (fcnt < 0) fcnt += 32; @@ -351,13 +353,11 @@ hfc_fill_fifo(struct BCState *bcs) return; } count = GetFreeFifoBytes_B(bcs); - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc_fill_fifo %d count(%d/%d),%lx", - bcs->channel, bcs->hw.hfc.tx_skb->len, + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc_fill_fifo %d count(%ld/%d),%lx", + bcs->channel, bcs->tx_skb->len, count, current->state); - debugl1(cs, tmp); - } - if (count < bcs->hw.hfc.tx_skb->len) { + if (count < bcs->tx_skb->len) { if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc_fill_fifo no fifo mem"); restore_flags(flags); @@ -368,26 +368,26 @@ hfc_fill_fifo(struct BCState *bcs) cli(); WaitForBusy(cs); WaitNoBusy(cs); - WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->hw.hfc.tx_skb->data[idx++]); - while (idx < bcs->hw.hfc.tx_skb->len) { + WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->tx_skb->data[idx++]); + while (idx < bcs->tx_skb->len) { cli(); if (!WaitNoBusy(cs)) break; - WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->hw.hfc.tx_skb->data[idx]); + WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->tx_skb->data[idx]); sti(); idx++; } - if (idx != bcs->hw.hfc.tx_skb->len) { + if (idx != bcs->tx_skb->len) { sti(); debugl1(cs, "FIFO Send BUSY error"); printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel); } else { - bcs->tx_cnt -= bcs->hw.hfc.tx_skb->len; + bcs->tx_cnt -= bcs->tx_skb->len; if (bcs->st->lli.l1writewakeup && - (PACKET_NOACK != bcs->hw.hfc.tx_skb->pkt_type)) - bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hfc.tx_skb->len); - dev_kfree_skb(bcs->hw.hfc.tx_skb); - bcs->hw.hfc.tx_skb = NULL; + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); + dev_kfree_skb(bcs->tx_skb); + bcs->tx_skb = NULL; } WaitForBusy(cs); cli(); @@ -404,15 +404,12 @@ static void hfc_send_data(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; - char tmp[32]; if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfc_fill_fifo(bcs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - sprintf(tmp,"send_data %d blocked", bcs->channel); - debugl1(cs, tmp); - } + } else + debugl1(cs,"send_data %d blocked", bcs->channel); } void @@ -424,15 +421,13 @@ main_rec_2bds0(struct BCState *bcs) u_char f1, f2, cip; int receive, count = 5; struct sk_buff *skb; - char tmp[64]; save_flags(flags); Begin: count--; cli(); if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - sprintf(tmp,"rec_data %d blocked", bcs->channel); - debugl1(cs, tmp); + debugl1(cs,"rec_data %d blocked", bcs->channel); restore_flags(flags); return; } @@ -445,11 +440,9 @@ main_rec_2bds0(struct BCState *bcs) f2 = ReadReg(cs, HFCD_DATA, cip); sti(); if (f1 != f2) { - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc rec %d f1(%d) f2(%d)", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc rec %d f1(%d) f2(%d)", bcs->channel, f1, f2); - debugl1(cs, tmp); - } cli(); z1 = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_CHANNEL(bcs->channel)); z2 = ReadZReg(cs, HFCB_FIFO | HFCB_Z2 | HFCB_REC | HFCB_CHANNEL(bcs->channel)); @@ -458,11 +451,9 @@ main_rec_2bds0(struct BCState *bcs) if (rcnt < 0) rcnt += cs->hw.hfcD.bfifosize; rcnt++; - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc rec %d z1(%x) z2(%x) cnt(%d)", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)", bcs->channel, z1, z2, rcnt); - debugl1(cs, tmp); - } if ((skb = hfc_empty_fifo(bcs, rcnt))) { cli(); skb_queue_tail(&bcs->rqueue, skb); @@ -490,12 +481,9 @@ mode_2bs0(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; - if (cs->debug & L1_DEB_HSCX) { - char tmp[40]; - sprintf(tmp, "HFCD bchannel mode %d bchan %d/%d", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HFCD bchannel mode %d bchan %d/%d", mode, bc, bcs->channel); - debugl1(cs, tmp); - } bcs->mode = mode; bcs->channel = bc; switch (mode) { @@ -543,122 +531,99 @@ hfc_l2l1(struct PStack *st, int pr, void *arg) long flags; switch (pr) { - case (PH_DATA_REQ): + case (PH_DATA | REQUEST): save_flags(flags); cli(); - if (st->l1.bcs->hw.hfc.tx_skb) { + if (st->l1.bcs->tx_skb) { skb_queue_tail(&st->l1.bcs->squeue, skb); restore_flags(flags); } else { - st->l1.bcs->hw.hfc.tx_skb = skb; + st->l1.bcs->tx_skb = skb; /* test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); */ st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); restore_flags(flags); } break; - case (PH_PULL_IND): - if (st->l1.bcs->hw.hfc.tx_skb) { + case (PH_PULL | INDICATION): + if (st->l1.bcs->tx_skb) { printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n"); break; } save_flags(flags); cli(); /* test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); -*/ st->l1.bcs->hw.hfc.tx_skb = skb; +*/ st->l1.bcs->tx_skb = skb; st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); restore_flags(flags); break; - case (PH_PULL_REQ): - if (!st->l1.bcs->hw.hfc.tx_skb) { + case (PH_PULL | REQUEST): + if (!st->l1.bcs->tx_skb) { test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL_CNF, NULL); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); } else test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; + case (PH_ACTIVATE | REQUEST): + test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + mode_2bs0(st->l1.bcs, st->l1.mode, st->l1.bc); + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | REQUEST): + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | CONFIRM): + test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + mode_2bs0(st->l1.bcs, 0, st->l1.bc); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); + break; } } void close_2bs0(struct BCState *bcs) { - struct sk_buff *skb; - - mode_2bs0(bcs, 0, 0); + mode_2bs0(bcs, 0, bcs->channel); if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - while ((skb = skb_dequeue(&bcs->rqueue))) { - dev_kfree_skb(skb); - } - while ((skb = skb_dequeue(&bcs->squeue))) { - dev_kfree_skb(skb); - } - if (bcs->hw.hfc.tx_skb) { - dev_kfree_skb(bcs->hw.hfc.tx_skb); - bcs->hw.hfc.tx_skb = NULL; + discard_queue(&bcs->rqueue); + discard_queue(&bcs->squeue); + if (bcs->tx_skb) { + dev_kfree_skb(bcs->tx_skb); + bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } } } static int -open_hfcstate(struct IsdnCardState *cs, - int bc) +open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs) { - struct BCState *bcs = cs->bcs + bc; - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { skb_queue_head_init(&bcs->rqueue); skb_queue_head_init(&bcs->squeue); } - bcs->hw.hfc.tx_skb = NULL; + bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); bcs->event = 0; bcs->tx_cnt = 0; return (0); } -static void -hfc_manl1(struct PStack *st, int pr, - void *arg) -{ - switch (pr) { - case (PH_ACTIVATE_REQ): - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - mode_2bs0(st->l1.bcs, st->l1.mode, st->l1.bc); - st->l1.l1man(st, PH_ACTIVATE_CNF, NULL); - break; - case (PH_DEACTIVATE_REQ): - if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) - mode_2bs0(st->l1.bcs, 0, 0); - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - break; - } -} - int setstack_2b(struct PStack *st, struct BCState *bcs) { - if (open_hfcstate(st->l1.hardware, bcs->channel)) + bcs->channel = st->l1.bc; + if (open_hfcstate(st->l1.hardware, bcs)) return (-1); st->l1.bcs = bcs; st->l2.l2l1 = hfc_l2l1; - st->ma.manl1 = hfc_manl1; setstack_manager(st); bcs->st = st; + setstack_l1_B(st); return (0); } static void -manl1_msg(struct IsdnCardState *cs, int msg, void *arg) { - struct PStack *st; - - st = cs->stlist; - while (st) { - st->ma.manl1(st, msg, arg); - st = st->next; - } -} - -static void hfcd_bh(struct IsdnCardState *cs) { /* struct PStack *stptr; @@ -671,7 +636,7 @@ hfcd_bh(struct IsdnCardState *cs) debugl1(cs, "D-Channel Busy cleared"); stptr = cs->stlist; while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE_CNF, NULL); + stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); stptr = stptr->next; } } @@ -679,19 +644,19 @@ hfcd_bh(struct IsdnCardState *cs) if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { switch (cs->ph_state) { case (0): - manl1_msg(cs, PH_RESET_IND, NULL); + l1_msg(cs, HW_RESET | INDICATION, NULL); break; case (3): - manl1_msg(cs, PH_DEACT_IND, NULL); + l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); break; case (8): - manl1_msg(cs, PH_RSYNC_IND, NULL); + l1_msg(cs, HW_RSYNC | INDICATION, NULL); break; case (6): - manl1_msg(cs, PH_INFO2_IND, NULL); + l1_msg(cs, HW_INFO2 | INDICATION, NULL); break; case (7): - manl1_msg(cs, PH_I4_P8_IND, NULL); + l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); break; default: break; @@ -722,7 +687,6 @@ int receive_dmsg(struct IsdnCardState *cs) int chksum; int count=5; u_char *ptr; - char tmp[64]; save_flags(flags); cli(); @@ -745,11 +709,9 @@ int receive_dmsg(struct IsdnCardState *cs) if (rcnt < 0) rcnt += cs->hw.hfcD.dfifosize; rcnt++; - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "hfcd recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)", + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "hfcd recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)", f1, f2, z1, z2, rcnt); - debugl1(cs, tmp); - } sti(); idx = 0; cip = HFCD_FIFO | HFCD_FIFO_OUT | HFCD_REC; @@ -796,11 +758,9 @@ int receive_dmsg(struct IsdnCardState *cs) WaitNoBusy(cs); stat = ReadReg(cs, HFCD_DATA, cip); sti(); - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "empty_dfifo chksum %x stat %x", + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "empty_dfifo chksum %x stat %x", chksum, stat); - debugl1(cs, tmp); - } if (stat) { debugl1(cs, "FIFO CRC error"); dev_kfree_skb(skb); @@ -837,7 +797,6 @@ hfc_fill_dfifo(struct IsdnCardState *cs) int idx, fcnt; int count; u_char cip; - char tmp[64]; if (!cs->tx_skb) return; @@ -855,12 +814,10 @@ hfc_fill_dfifo(struct IsdnCardState *cs) cs->hw.hfcD.f2 = ReadReg(cs, HFCD_DATA, cip) & 0xf; cs->hw.hfcD.send[cs->hw.hfcD.f1] = ReadZReg(cs, HFCD_FIFO | HFCD_Z1 | HFCD_SEND); sti(); - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "hfc_fill_Dfifo f1(%d) f2(%d) z1(%x)", + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "hfc_fill_Dfifo f1(%d) f2(%d) z1(%x)", cs->hw.hfcD.f1, cs->hw.hfcD.f2, cs->hw.hfcD.send[cs->hw.hfcD.f1]); - debugl1(cs, tmp); - } fcnt = cs->hw.hfcD.f1 - cs->hw.hfcD.f2; if (fcnt < 0) fcnt += 16; @@ -871,11 +828,9 @@ hfc_fill_dfifo(struct IsdnCardState *cs) return; } count = GetFreeFifoBytes_D(cs); - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "hfc_fill_Dfifo count(%d/%d)", + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "hfc_fill_Dfifo count(%ld/%d)", cs->tx_skb->len, count); - debugl1(cs, tmp); - } if (count < cs->tx_skb->len) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "hfc_fill_Dfifo no fifo mem"); @@ -929,24 +884,19 @@ hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val) { u_char exval; struct BCState *bcs; - char tmp[32]; int count=15; long flags; - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "HFCD irq %x %s", val, + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "HFCD irq %x %s", val, test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ? "locked" : "unlocked"); - debugl1(cs, tmp); - } val &= cs->hw.hfcD.int_m1; if (val & 0x40) { /* TE state machine irq */ exval = cs->readisac(cs, HFCD_STATES) & 0xf; - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "ph_state chg %d->%d", cs->ph_state, + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ph_state chg %d->%d", cs->ph_state, exval); - debugl1(cs, tmp); - } cs->ph_state = exval; sched_event_D(cs, D_L1STATECHANGE); val &= ~0x40; @@ -983,23 +933,19 @@ hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val) if (cs->debug) debugl1(cs, "hfcd spurious 0x01 IRQ"); } else { - if (bcs->hw.hfc.tx_skb) { + if (bcs->tx_skb) { if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfc_fill_fifo(bcs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - sprintf(tmp,"fill_data %d blocked", bcs->channel); - debugl1(cs, tmp); - } + } else + debugl1(cs,"fill_data %d blocked", bcs->channel); } else { - if ((bcs->hw.hfc.tx_skb = skb_dequeue(&bcs->squeue))) { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfc_fill_fifo(bcs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - sprintf(tmp,"fill_data %d blocked", bcs->channel); - debugl1(cs, tmp); - } + } else + debugl1(cs,"fill_data %d blocked", bcs->channel); } else { hfc_sched_event(bcs, B_XMTBUFREADY); } @@ -1011,23 +957,19 @@ hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val) if (cs->debug) debugl1(cs, "hfcd spurious 0x02 IRQ"); } else { - if (bcs->hw.hfc.tx_skb) { + if (bcs->tx_skb) { if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfc_fill_fifo(bcs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - sprintf(tmp,"fill_data %d blocked", bcs->channel); - debugl1(cs, tmp); - } + } else + debugl1(cs,"fill_data %d blocked", bcs->channel); } else { - if ((bcs->hw.hfc.tx_skb = skb_dequeue(&bcs->squeue))) { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfc_fill_fifo(bcs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - sprintf(tmp,"fill_data %d blocked", bcs->channel); - debugl1(cs, tmp); - } + } else + debugl1(cs,"fill_data %d blocked", bcs->channel); } else { hfc_sched_event(bcs, B_XMTBUFREADY); } @@ -1042,7 +984,7 @@ hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val) del_timer(&cs->dbusytimer); if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) sched_event_D(cs, D_CLEARBUSY); - if (cs->tx_skb) { + if (cs->tx_skb) if (cs->tx_skb->len) { if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfc_fill_dfifo(cs); @@ -1056,7 +998,6 @@ hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val) cs->tx_cnt = 0; cs->tx_skb = NULL; } - } if ((cs->tx_skb = skb_dequeue(&cs->sq))) { cs->tx_cnt = 0; if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { @@ -1072,10 +1013,8 @@ hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val) if (cs->hw.hfcD.int_s1 && count--) { val = cs->hw.hfcD.int_s1; cs->hw.hfcD.int_s1 = 0; - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "HFCD irq %x loop %d", val, 15-count); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "HFCD irq %x loop %d", val, 15-count); } else val = 0; restore_flags(flags); @@ -1083,13 +1022,17 @@ hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val) } static void -HFCD_l2l1(struct PStack *st, int pr, void *arg) +HFCD_l1hw(struct PStack *st, int pr, void *arg) { struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; struct sk_buff *skb = arg; - char str[64]; + switch (pr) { - case (PH_DATA_REQ): + 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 */ @@ -1097,12 +1040,6 @@ HFCD_l2l1(struct PStack *st, int pr, void *arg) Logl2Frame(cs, skb, "PH_DATA Queued", 0); #endif } else { - if ((cs->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */ - LogFrame(cs, skb->data, skb->len); - sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei); - dlogframe(cs, skb->data + 4, skb->len - 4, - str); - } cs->tx_skb = skb; cs->tx_cnt = 0; #ifdef L2FRAME_DEBUG /* psa */ @@ -1117,19 +1054,17 @@ HFCD_l2l1(struct PStack *st, int pr, void *arg) } break; - case (PH_PULL_IND): + 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->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */ + if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len); - sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei); - dlogframe(cs, skb->data + 4, skb->len - 4, - str); - } + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); cs->tx_skb = skb; cs->tx_cnt = 0; #ifdef L2FRAME_DEBUG /* psa */ @@ -1142,47 +1077,39 @@ HFCD_l2l1(struct PStack *st, int pr, void *arg) } else debugl1(cs, "hfc_fill_dfifo blocked"); break; - case (PH_PULL_REQ): + 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_CNF, NULL); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); } else test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; - } -} - -void -hfcd_l1cmd(struct IsdnCardState *cs, int msg, void *arg) -{ - char tmp[32]; - switch(msg) { - case PH_RESET_REQ: + case (HW_RESET | REQUEST): cs->writeisac(cs, HFCD_STATES, HFCD_LOAD_STATE | 3); /* HFC ST 3 */ udelay(6); cs->writeisac(cs, HFCD_STATES, 3); /* HFC ST 2 */ cs->hw.hfcD.mst_m |= HFCD_MASTER; cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION); - manl1_msg(cs, PH_POWERUP_CNF, NULL); + l1_msg(cs, HW_POWERUP | CONFIRM, NULL); break; - case PH_ENABLE_REQ: + case (HW_ENABLE | REQUEST): cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION); break; - case PH_DEACT_ACK: + case (HW_DEACTIVATE | REQUEST): cs->hw.hfcD.mst_m &= ~HFCD_MASTER; cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); break; - case PH_INFO3_REQ: + case (HW_INFO3 | REQUEST): cs->hw.hfcD.mst_m |= HFCD_MASTER; cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); break; #if 0 - case PH_TESTLOOP_REQ: + case (HW_TESTLOOP | REQUEST): u_char val = 0; if (1 & (int) arg) val |= 0x0c; @@ -1208,10 +1135,8 @@ hfcd_l1cmd(struct IsdnCardState *cs, int msg, void *arg) break; #endif default: - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "hfcd_l1cmd unknown %4x", msg); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "hfcd_l1hw unknown pr %4x", pr); break; } } @@ -1219,7 +1144,7 @@ hfcd_l1cmd(struct IsdnCardState *cs, int msg, void *arg) void setstack_hfcd(struct PStack *st, struct IsdnCardState *cs) { - st->l2.l2l1 = HFCD_l2l1; + st->l1.l1hw = HFCD_l1hw; } static void @@ -1234,7 +1159,7 @@ hfc_dbusy_timer(struct IsdnCardState *cs) stptr = cs->stlist; while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE_IND, NULL); + stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); stptr = stptr->next; } } @@ -1260,7 +1185,6 @@ __initfunc(void init2bds0(struct IsdnCardState *cs)) { cs->setstack_d = setstack_hfcd; - cs->l1cmd = hfcd_l1cmd; cs->dbusytimer.function = (void *) hfc_dbusy_timer; cs->dbusytimer.data = (long) cs; init_timer(&cs->dbusytimer); diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c index 2d9ce5bd5..26d47b936 100644 --- a/drivers/isdn/hisax/hfc_2bs0.c +++ b/drivers/isdn/hisax/hfc_2bs0.c @@ -1,11 +1,24 @@ -/* $Id: hfc_2bs0.c,v 1.4 1998/02/12 23:07:29 keil Exp $ +/* $Id: hfc_2bs0.c,v 1.8 1998/11/15 23:54:43 keil Exp $ * specific routines for CCD's HFC 2BS0 * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * * $Log: hfc_2bs0.c,v $ + * Revision 1.8 1998/11/15 23:54:43 keil + * changes from 2.0 + * + * Revision 1.7 1998/09/30 22:24:46 keil + * Fix missing line in setstack* + * + * Revision 1.6 1998/08/13 23:36:28 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 1.5 1998/05/25 12:57:54 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * * Revision 1.4 1998/02/12 23:07:29 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -109,7 +122,6 @@ hfc_clear_fifo(struct BCState *bcs) int idx, cnt; int rcnt, z1, z2; u_char cip, f1, f2; - char tmp[64]; if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) debugl1(cs, "hfc_clear_fifo"); @@ -129,21 +141,17 @@ hfc_clear_fifo(struct BCState *bcs) z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel)); cnt = 32; while (((f1 != f2) || (z1 != z2)) && cnt--) { - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc clear %d f1(%d) f2(%d)", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc clear %d f1(%d) f2(%d)", bcs->channel, f1, f2); - debugl1(cs, tmp); - } rcnt = z1 - z2; if (rcnt < 0) rcnt += cs->hw.hfc.fifosize; if (rcnt) rcnt++; - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc clear %d z1(%x) z2(%x) cnt(%d)", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc clear %d z1(%x) z2(%x) cnt(%d)", bcs->channel, z1, z2, rcnt); - debugl1(cs, tmp); - } cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); idx = 0; while ((idx < rcnt) && WaitNoBusy(cs)) { @@ -180,7 +188,6 @@ hfc_empty_fifo(struct BCState *bcs, int count) int idx; int chksum; u_char stat, cip; - char tmp[64]; if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) debugl1(cs, "hfc_empty_fifo"); @@ -235,11 +242,9 @@ hfc_empty_fifo(struct BCState *bcs, int count) chksum += cs->BC_Read_Reg(cs, HFC_DATA, cip); WaitNoBusy(cs); stat = cs->BC_Read_Reg(cs, HFC_DATA, cip); - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc_empty_fifo %d chksum %x stat %x", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x", bcs->channel, chksum, stat); - debugl1(cs, tmp); - } if (stat) { debugl1(cs, "FIFO CRC error"); dev_kfree_skb(skb); @@ -261,11 +266,10 @@ hfc_fill_fifo(struct BCState *bcs) int idx, fcnt; int count; u_char cip; - char tmp[64]; - if (!bcs->hw.hfc.tx_skb) + if (!bcs->tx_skb) return; - if (bcs->hw.hfc.tx_skb->len <= 0) + if (bcs->tx_skb->len <= 0) return; save_flags(flags); @@ -281,12 +285,10 @@ hfc_fill_fifo(struct BCState *bcs) WaitNoBusy(cs); bcs->hw.hfc.f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(bcs, HFC_Z1 | HFC_SEND | HFC_CHANNEL(bcs->channel)); - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)", bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2, bcs->hw.hfc.send[bcs->hw.hfc.f1]); - debugl1(cs, tmp); - } fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2; if (fcnt < 0) fcnt += 32; @@ -297,13 +299,11 @@ hfc_fill_fifo(struct BCState *bcs) return; } count = GetFreeFifoBytes(bcs); - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc_fill_fifo %d count(%d/%d)", - bcs->channel, bcs->hw.hfc.tx_skb->len, + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc_fill_fifo %d count(%ld/%d)", + bcs->channel, bcs->tx_skb->len, count); - debugl1(cs, tmp); - } - if (count < bcs->hw.hfc.tx_skb->len) { + if (count < bcs->tx_skb->len) { if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc_fill_fifo no fifo mem"); restore_flags(flags); @@ -311,18 +311,18 @@ hfc_fill_fifo(struct BCState *bcs) } cip = HFC_CIP | HFC_FIFO_IN | HFC_SEND | HFC_CHANNEL(bcs->channel); idx = 0; - while ((idx < bcs->hw.hfc.tx_skb->len) && WaitNoBusy(cs)) - cs->BC_Write_Reg(cs, HFC_DATA_NODEB, cip, bcs->hw.hfc.tx_skb->data[idx++]); - if (idx != bcs->hw.hfc.tx_skb->len) { + while ((idx < bcs->tx_skb->len) && WaitNoBusy(cs)) + cs->BC_Write_Reg(cs, HFC_DATA_NODEB, cip, bcs->tx_skb->data[idx++]); + if (idx != bcs->tx_skb->len) { debugl1(cs, "FIFO Send BUSY error"); printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel); } else { - count = bcs->hw.hfc.tx_skb->len; + count = bcs->tx_skb->len; bcs->tx_cnt -= count; - if (PACKET_NOACK == bcs->hw.hfc.tx_skb->pkt_type) + if (PACKET_NOACK == bcs->tx_skb->pkt_type) count = -1; - dev_kfree_skb(bcs->hw.hfc.tx_skb); - bcs->hw.hfc.tx_skb = NULL; + dev_kfree_skb(bcs->tx_skb); + bcs->tx_skb = NULL; WaitForBusy(cs); WaitNoBusy(cs); cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel)); @@ -343,7 +343,6 @@ main_irq_hfc(struct BCState *bcs) u_char f1, f2, cip; int receive, transmit, count = 5; struct sk_buff *skb; - char tmp[64]; save_flags(flags); Begin: @@ -360,11 +359,9 @@ main_irq_hfc(struct BCState *bcs) WaitNoBusy(cs); f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); if (f1 != f2) { - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc rec %d f1(%d) f2(%d)", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc rec %d f1(%d) f2(%d)", bcs->channel, f1, f2); - debugl1(cs, tmp); - } WaitForBusy(cs); z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel)); z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel)); @@ -372,11 +369,9 @@ main_irq_hfc(struct BCState *bcs) if (rcnt < 0) rcnt += cs->hw.hfc.fifosize; rcnt++; - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc rec %d z1(%x) z2(%x) cnt(%d)", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)", bcs->channel, z1, z2, rcnt); - debugl1(cs, tmp); - } /* sti(); */ if ((skb = hfc_empty_fifo(bcs, rcnt))) { skb_queue_tail(&bcs->rqueue, skb); @@ -388,14 +383,14 @@ main_irq_hfc(struct BCState *bcs) restore_flags(flags); udelay(1); cli(); - if (bcs->hw.hfc.tx_skb) { + if (bcs->tx_skb) { transmit = 1; test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); hfc_fill_fifo(bcs); if (test_bit(BC_FLG_BUSY, &bcs->Flag)) transmit = 0; } else { - if ((bcs->hw.hfc.tx_skb = skb_dequeue(&bcs->squeue))) { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { transmit = 1; test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); hfc_fill_fifo(bcs); @@ -417,13 +412,11 @@ mode_hfc(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; - if (cs->debug & L1_DEB_HSCX) { - char tmp[40]; - sprintf(tmp, "HFC 2BS0 mode %d bchan %d/%d", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HFC 2BS0 mode %d bchan %d/%d", mode, bc, bcs->channel); - debugl1(cs, tmp); - } bcs->mode = mode; + bcs->channel = bc; switch (mode) { case (L1_MODE_NULL): @@ -468,57 +461,66 @@ hfc_l2l1(struct PStack *st, int pr, void *arg) long flags; switch (pr) { - case (PH_DATA_REQ): + case (PH_DATA | REQUEST): save_flags(flags); cli(); - if (st->l1.bcs->hw.hfc.tx_skb) { + if (st->l1.bcs->tx_skb) { skb_queue_tail(&st->l1.bcs->squeue, skb); restore_flags(flags); } else { - st->l1.bcs->hw.hfc.tx_skb = skb; + st->l1.bcs->tx_skb = skb; test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); restore_flags(flags); } break; - case (PH_PULL_IND): - if (st->l1.bcs->hw.hfc.tx_skb) { + case (PH_PULL | INDICATION): + if (st->l1.bcs->tx_skb) { printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n"); break; } save_flags(flags); cli(); test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); - st->l1.bcs->hw.hfc.tx_skb = skb; + st->l1.bcs->tx_skb = skb; st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); restore_flags(flags); break; - case (PH_PULL_REQ): - if (!st->l1.bcs->hw.hfc.tx_skb) { + case (PH_PULL | REQUEST): + if (!st->l1.bcs->tx_skb) { test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL_CNF, NULL); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); } else test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; + case (PH_ACTIVATE | REQUEST): + test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + mode_hfc(st->l1.bcs, st->l1.mode, st->l1.bc); + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | REQUEST): + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | CONFIRM): + test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + mode_hfc(st->l1.bcs, 0, st->l1.bc); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); + break; } } + void close_hfcstate(struct BCState *bcs) { - struct sk_buff *skb; - - mode_hfc(bcs, 0, 0); + mode_hfc(bcs, 0, bcs->channel); if (test_bit(BC_FLG_INIT, &bcs->Flag)) { - while ((skb = skb_dequeue(&bcs->rqueue))) { - dev_kfree_skb(skb); - } - while ((skb = skb_dequeue(&bcs->squeue))) { - dev_kfree_skb(skb); - } - if (bcs->hw.hfc.tx_skb) { - dev_kfree_skb(bcs->hw.hfc.tx_skb); - bcs->hw.hfc.tx_skb = NULL; + discard_queue(&bcs->rqueue); + discard_queue(&bcs->squeue); + if (bcs->tx_skb) { + dev_kfree_skb(bcs->tx_skb); + bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } } @@ -526,50 +528,30 @@ close_hfcstate(struct BCState *bcs) } static int -open_hfcstate(struct IsdnCardState *cs, - int bc) +open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs) { - struct BCState *bcs = cs->bcs + bc; - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { skb_queue_head_init(&bcs->rqueue); skb_queue_head_init(&bcs->squeue); } - bcs->hw.hfc.tx_skb = NULL; + bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); bcs->event = 0; bcs->tx_cnt = 0; return (0); } -static void -hfc_manl1(struct PStack *st, int pr, - void *arg) -{ - switch (pr) { - case (PH_ACTIVATE_REQ): - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - mode_hfc(st->l1.bcs, st->l1.mode, st->l1.bc); - st->l1.l1man(st, PH_ACTIVATE_CNF, NULL); - break; - case (PH_DEACTIVATE_REQ): - if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) - mode_hfc(st->l1.bcs, 0, 0); - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - break; - } -} - int setstack_hfc(struct PStack *st, struct BCState *bcs) { - if (open_hfcstate(st->l1.hardware, bcs->channel)) + bcs->channel = st->l1.bc; + if (open_hfcstate(st->l1.hardware, bcs)) return (-1); st->l1.bcs = bcs; st->l2.l2l1 = hfc_l2l1; - st->ma.manl1 = hfc_manl1; setstack_manager(st); bcs->st = st; + setstack_l1_B(st); return (0); } diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index 4795ada08..36cd82ee1 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -1,8 +1,48 @@ -/* $Id: hisax.h,v 2.14 1998/02/11 17:28:04 keil Exp $ +/* $Id: hisax.h,v 2.26 1998/11/15 23:54:45 keil Exp $ * Basic declarations, defines and prototypes * * $Log: hisax.h,v $ + * Revision 2.26 1998/11/15 23:54:45 keil + * changes from 2.0 + * + * Revision 2.25 1998/09/30 22:28:42 keil + * More work for ISAR support + * + * Revision 2.24 1998/08/20 13:50:39 keil + * More support for hybrid modem (not working yet) + * + * Revision 2.23 1998/08/13 23:36:31 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 2.22 1998/07/15 15:01:28 calle + * Support for AVM passive PCMCIA cards: + * A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0 + * + * Revision 2.21 1998/05/25 14:10:05 keil + * HiSax 3.0 + * X.75 and leased are working again. + * + * Revision 2.20 1998/05/25 12:57:57 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 2.19 1998/04/15 16:39:15 keil + * Add S0Box and Teles PCI support + * + * Revision 2.18 1998/03/26 07:10:04 paul + * The jumpmatrix table in struct Fsm was an array of "int". This is not + * large enough for pointers to functions on Linux/Alpha (instant crash + * on "insmod hisax). Now there is a typedef for the pointer to function. + * This also prevents warnings about "incompatible pointer types". + * + * Revision 2.17 1998/03/19 13:18:43 keil + * Start of a CAPI like interface for supplementary Service + * first service: SUSPEND + * + * Revision 2.16 1998/03/09 23:19:25 keil + * Changes for PCMCIA + * * Revision 2.14 1998/02/11 17:28:04 keil * Niccy PnP/PCI support * @@ -72,120 +112,90 @@ #include <linux/isdnif.h> #include <linux/tty.h> #include <linux/init.h> +#include <linux/serialP.h> + +#define REQUEST 0 +#define CONFIRM 1 +#define INDICATION 2 +#define RESPONSE 3 + +#define HW_ENABLE 0x0000 +#define HW_RESET 0x0004 +#define HW_POWERUP 0x0008 +#define HW_ACTIVATE 0x0010 +#define HW_DEACTIVATE 0x0018 +#define HW_INFO2 0x0020 +#define HW_INFO3 0x0030 +#define HW_INFO4_P8 0x0040 +#define HW_INFO4_P10 0x0048 +#define HW_RSYNC 0x0060 +#define HW_TESTLOOP 0x0070 +#define CARD_RESET 0x00F0 +#define CARD_SETIRQ 0x00F1 +#define CARD_INIT 0x00F2 +#define CARD_RELEASE 0x00F3 +#define CARD_TEST 0x00F4 +#define CARD_AUX_IND 0x00F5 +#define CARD_LOAD_FIRM 0x00F6 + +#define PH_ACTIVATE 0x0100 +#define PH_DEACTIVATE 0x0110 +#define PH_DATA 0x0120 +#define PH_PULL 0x0130 +#define PH_TESTLOOP 0x0140 +#define PH_PAUSE 0x0150 +#define MPH_ACTIVATE 0x0180 +#define MPH_DEACTIVATE 0x0190 +#define MPH_INFORMATION 0x01A0 + +#define DL_ESTABLISH 0x0200 +#define DL_RELEASE 0x0210 +#define DL_DATA 0x0220 +#define DL_FLUSH 0x0224 +#define DL_UNIT_DATA 0x0230 +#define MDL_ASSIGN 0x0280 +#define MDL_REMOVE 0x0284 +#define MDL_ERROR 0x0288 +#define MDL_INFO_SETUP 0x02E0 +#define MDL_INFO_CONN 0x02E4 +#define MDL_INFO_REL 0x02E8 + +#define CC_SETUP 0x0300 +#define CC_RESUME 0x0304 +#define CC_MORE_INFO 0x0310 +#define CC_IGNORE 0x0320 +#define CC_REJECT 0x0324 +#define CC_SETUP_COMPL 0x0330 +#define CC_PROCEEDING 0x0340 +#define CC_ALERTING 0x0344 +#define CC_CONNECT 0x0350 +#define CC_CHARGE 0x0354 +#define CC_DISCONNECT 0x0360 +#define CC_RELEASE 0x0368 +#define CC_SUSPEND 0x0370 +#define CC_T303 0x0383 +#define CC_T304 0x0384 +#define CC_T305 0x0385 +#define CC_T308_1 0x0388 +#define CC_T308_2 0x0389 +#define CC_T310 0x0390 +#define CC_T313 0x0393 +#define CC_T318 0x0398 +#define CC_T319 0x0399 +#define CC_NOSETUP_RSP 0x03E0 +#define CC_SETUP_ERR 0x03E1 +#define CC_SUSPEND_ERR 0x03E2 +#define CC_RESUME_ERR 0x03E3 +#define CC_CONNECT_ERR 0x03E4 +#define CC_RELEASE_ERR 0x03E5 +#define CC_DLRL 0x03F0 +#define CC_RESTART 0x03F4 -#define PH_ACTIVATE_REQ 0x0010 -#define PH_ACTIVATE_CNF 0x0011 -#define PH_ACTIVATE_IND 0x0012 -#define PH_DEACTIVATE_REQ 0x0020 -#define PH_DEACTIVATE_CNF 0x0021 -#define PH_DEACTIVATE_IND 0x0022 -#define PH_DEACT_REQ 0x0024 -#define PH_DEACT_CNF 0x0025 -#define PH_DEACT_IND 0x0026 -#define PH_DEACT_ACK 0x0027 -#define PH_TESTLOOP_REQ 0x0030 -#define PH_PAUSE_CNF 0x0035 -#define PH_PAUSE_IND 0x0036 -#define PH_PULL_REQ 0x0038 -#define PH_PULL_CNF 0x0039 -#define PH_PULL_IND 0x003A -#define PH_DATA_REQ 0x0040 -#define PH_DATA_IND 0x0042 - -#define PH_INFO3_REQ 0x0008 -#define PH_INFO2_IND 0x000A -#define PH_ENABLE_REQ 0x0004 -#define PH_RSYNC_IND 0x0006 -#define PH_RESET_REQ 0x0000 -#define PH_RESET_IND 0x0002 -#define PH_POWERUP_CNF 0x0003 -#define PH_ACTIV_REQ 0x000C -#define PH_I4_P8_IND 0x000D -#define PH_I4_P10_IND 0x000F - -#define MDL_ASSIGN_REQ 0x0050 -#define MDL_ASSIGN_IND 0x0052 -#define MDL_REMOVE_REQ 0x0054 -#define MDL_ERROR_REQ 0x0058 -#define MDL_ERROR_IND 0x005A -#define CARD_AUX_IND 0x005E - -#define DL_UNIT_DATA 6 -#define CC_ESTABLISH 7 -#define DL_ESTABLISH 8 -#define DL_DATA 9 - -#define CC_CONNECT 15 -#define DL_RELEASE 20 -#define DL_FLUSH 21 - -#define CC_REJECT 23 - -#define CC_SETUP_REQ 24 -#define CC_SETUP_CNF 25 -#define CC_SETUP_IND 26 -#define CC_SETUP_RSP 27 -#define CC_SETUP_COMPLETE_IND 28 - -#define CC_DISCONNECT_REQ 29 -#define CC_DISCONNECT_IND 30 - -#define CC_RELEASE_CNF 31 -#define CC_RELEASE_IND 32 -#define CC_RELEASE_REQ 33 - -#define CC_REJECT_REQ 34 - -#define CC_PROCEEDING_IND 35 - -#define CC_DLRL 36 -#define CC_DLEST 37 - -#define CC_ALERTING_REQ 38 -#define CC_ALERTING_IND 39 - -#define DL_STOP 40 -#define DL_START 41 - -#define MDL_INFO_SETUP 42 -#define MDL_INFO_CONN 43 -#define MDL_INFO_REL 44 -#define MDL_NOTEIPROC 46 - -#define LC_ESTABLISH 47 -#define LC_RELEASE 48 - -#define CC_INFO_CHARGE 52 - -#define CC_MORE_INFO 53 -#define CC_IGNORE 54 -#define CC_RESTART 55 - - -#define CC_T303 60 -#define CC_T304 61 -#define CC_T305 62 -#define CC_T308_1 64 -#define CC_T308_2 65 -#define CC_T310 66 -#define CC_T313 67 -#define CC_T318 68 -#define CC_T319 69 - -#define CC_NOSETUP_RSP_ERR 70 -#define CC_SETUP_ERR 71 -#define CC_CONNECT_ERR 72 -#define CC_RELEASE_ERR 73 - -#define CARD_RESET 0x1001 -#define CARD_SETIRQ 0x1002 -#define CARD_INIT 0x1003 -#define CARD_RELEASE 0x1004 -#define CARD_TEST 0x1005 #ifdef __KERNEL__ #define MAX_DFRAME_LEN 260 +#define MAX_DFRAME_LEN_L1 300 #define HSCX_BUFMAX 4096 #define MAX_DATA_SIZE (HSCX_BUFMAX - 4) #define MAX_DATA_MEM (HSCX_BUFMAX + 64) @@ -193,6 +203,8 @@ #define MAX_HEADER_LEN 4 #define MAX_WINDOW 8 #define MAX_MON_FRAME 32 +#define MAX_DLOG_SPACE 2048 +#define MAX_BLOG_SPACE 256 /* #define I4L_IRQ_FLAG SA_INTERRUPT */ #define I4L_IRQ_FLAG 0 @@ -201,8 +213,12 @@ * Statemachine */ +struct FsmInst; + +typedef void (* FSMFNPTR)(struct FsmInst *, int, void *); + struct Fsm { - int *jumpmatrix; + FSMFNPTR *jumpmatrix; int state_count, event_count; char **strEvent, **strState; }; @@ -213,7 +229,7 @@ struct FsmInst { int debug; void *userdata; int userint; - void (*printdebug) (struct FsmInst *, char *); + void (*printdebug) (struct FsmInst *, char *, ...); }; struct FsmNode { @@ -249,9 +265,10 @@ struct Layer1 { struct FsmInst l1m; struct FsmTimer timer; void (*l1l2) (struct PStack *, int, void *); - void (*l1man) (struct PStack *, int, void *); + void (*l1hw) (struct PStack *, int, void *); void (*l1tei) (struct PStack *, int, void *); int mode, bc; + int delay; }; #define GROUP_TEI 127 @@ -266,17 +283,20 @@ struct Layer1 { #define FLG_ORIG 2 #define FLG_MOD128 3 #define FLG_PEND_REL 4 -#define FLG_L3_INIT 5 -#define FLG_T200_RUN 6 +#define FLG_L3_INIT 5 +#define FLG_T200_RUN 6 #define FLG_ACK_PEND 7 #define FLG_REJEXC 8 #define FLG_OWN_BUSY 9 #define FLG_PEER_BUSY 10 #define FLG_DCHAN_BUSY 11 +#define FLG_L1_ACTIV 12 +#define FLG_ESTAB_PEND 13 +#define FLG_PTP 14 +#define FLG_FIXED_TEI 15 struct Layer2 { int tei; - int tei_wanted; int sap; int maxlen; unsigned int flag; @@ -288,23 +308,25 @@ struct Layer2 { struct sk_buff_head i_queue; struct sk_buff_head ui_queue; void (*l2l1) (struct PStack *, int, void *); - void (*l2man) (struct PStack *, int, void *); void (*l2l3) (struct PStack *, int, void *); void (*l2tei) (struct PStack *, int, void *); struct FsmInst l2m; struct FsmTimer t200, t203; int T200, N200, T203; int debug; - char debug_id[32]; + char debug_id[16]; }; struct Layer3 { - void (*l3l4) (struct l3_process *, int, void *); + void (*l3l4) (struct PStack *, int, void *); void (*l3l2) (struct PStack *, int, void *); + struct FsmInst l3m; + struct sk_buff_head squeue; struct l3_process *proc; struct l3_process *global; int N303; int debug; + char debug_id[8]; }; struct LLInterface { @@ -321,8 +343,6 @@ struct Management { struct FsmTimer t202; int T202, N202, debug; void (*layer) (struct PStack *, int, void *); - void (*manl1) (struct PStack *, int, void *); - void (*manl2) (struct PStack *, int, void *); }; @@ -343,7 +363,7 @@ struct PStack { struct Layer1 l1; struct Layer2 l2; struct Layer3 l3; - struct LLInterface lli; + struct LLInterface lli; struct Management ma; int protocol; /* EDSS1 or 1TR6 */ }; @@ -361,21 +381,55 @@ struct l3_process { }; struct hscx_hw { + int hscx; + int rcvidx; + int count; /* Current skb sent count */ + u_char *rcvbuf; /* B-Channel receive Buffer */ +}; + +struct isar_reg { + unsigned int Flags; + volatile u_char bstat; + volatile u_char iis; + volatile u_char cmsb; + volatile u_char clsb; + volatile u_char par[8]; +}; + +struct isar_hw { + int dpath; + int rcvidx; + int txcnt; + int mml; + u_char *rcvbuf; /* B-Channel receive Buffer */ + struct isar_reg *reg; +}; + +struct hdlc_stat_reg { + u_char cmd __attribute__((packed)); + u_char xml __attribute__((packed)); + u_char mode __attribute__((packed)); + u_char fill __attribute__((packed)); +}; + +struct hdlc_hw { + union { + u_int ctrl; + struct hdlc_stat_reg sr; + } ctrl; + u_int stat; int rcvidx; int count; /* Current skb sent count */ u_char *rcvbuf; /* B-Channel receive Buffer */ - struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ }; struct hfcB_hw { unsigned int *send; int f1; int f2; - struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ }; struct tiger_hw { - struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ u_int *send; u_int *s_irq; u_int *s_end; @@ -397,8 +451,7 @@ struct tiger_hw { u_char s_state; }; -struct foreign_hw { - int doHDLCprocessing; +struct amd7930_hw { u_char *tx_buff; u_char *rv_buff; int rv_buff_in; @@ -407,9 +460,9 @@ struct foreign_hw { struct hdlc_state *hdlc_state; struct tq_struct tq_rcv; struct tq_struct tq_xmt; - struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ }; + #define BC_FLG_INIT 1 #define BC_FLG_ACTIV 2 #define BC_FLG_BUSY 3 @@ -420,6 +473,7 @@ struct foreign_hw { #define L1_MODE_NULL 0 #define L1_MODE_TRANS 1 #define L1_MODE_HDLC 2 +#define L1_MODE_MODEM 7 struct BCState { int channel; @@ -427,34 +481,26 @@ struct BCState { int Flag; struct IsdnCardState *cs; int tx_cnt; /* B-Channel transmit counter */ + struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ struct sk_buff_head rqueue; /* B-Channel receive Queue */ struct sk_buff_head squeue; /* B-Channel send Queue */ struct PStack *st; + u_char *blog; + struct timer_list transbusy; struct tq_struct tqueue; int event; int (*BC_SetStack) (struct PStack *, struct BCState *); void (*BC_Close) (struct BCState *); union { struct hscx_hw hscx; + struct hdlc_hw hdlc; + struct isar_hw isar; struct hfcB_hw hfc; struct tiger_hw tiger; - struct foreign_hw foreign; + struct amd7930_hw amd7930; } hw; }; -struct LcFsm { - int type; - int delay; - struct FsmInst lcfi; - struct Channel *ch; - void (*lccall) (struct LcFsm *, int, void *); - struct PStack *st; - int l2_establish; - int l2_start; - struct FsmTimer act_timer; - char debug_id[32]; -}; - struct Channel { struct PStack *b_st, *d_st; struct IsdnCardState *cs; @@ -462,11 +508,10 @@ struct Channel { int chan; int incoming; struct FsmInst fi; - struct LcFsm *lc_d; - struct LcFsm *lc_b; struct FsmTimer drel_timer, dial_timer; int debug; int l2_protocol, l2_active_protocol; + int l3_protocol; int data_open; struct l3_process *proc; setup_parm setup; /* from isdnif.h numbers and Serviceindicator */ @@ -487,21 +532,33 @@ struct elsa_hw { unsigned int counter; unsigned int status; struct timer_list tl; + unsigned int MFlag; + struct BCState *bcs; + u_char *transbuf; + u_char *rcvbuf; + unsigned int transp; + unsigned int rcvp; + unsigned int transcnt; + unsigned int rcvcnt; + u_char IER; + u_char FCR; + u_char LCR; + u_char MCR; u_char ctrl_reg; -}; +}; struct teles3_hw { unsigned int cfg_reg; - unsigned int isac; - unsigned int hscx[2]; - unsigned int isacfifo; - unsigned int hscxfifo[2]; -}; + signed int isac; + signed int hscx[2]; + signed int isacfifo; + signed int hscxfifo[2]; +}; struct teles0_hw { unsigned int cfg_reg; unsigned int membase; -}; +}; struct avm_hw { unsigned int cfg_reg; @@ -510,7 +567,7 @@ struct avm_hw { unsigned int isacfifo; unsigned int hscxfifo[2]; unsigned int counter; -}; +}; struct ix1_hw { unsigned int cfg_reg; @@ -530,7 +587,7 @@ struct diva_hw { unsigned int status; struct timer_list tl; u_char ctrl_reg; -}; +}; struct asus_hw { unsigned int cfg_reg; @@ -559,6 +616,9 @@ struct sedl_hw { unsigned int hscx; unsigned int reset_on; unsigned int reset_off; + struct isar_reg isar; + unsigned int chip; + unsigned int bus; }; struct spt_hw { @@ -566,7 +626,7 @@ struct spt_hw { unsigned int isac; unsigned int hscx[2]; unsigned char res_irq; -}; +}; struct mic_hw { unsigned int cfg_reg; @@ -610,6 +670,7 @@ struct hfcD_hw { #define HW_IOM1 0 #define HW_IPAC 1 +#define HW_ISAR 2 #define FLG_TWO_DCHAN 4 #define FLG_L1_DBUSY 5 #define FLG_DBUSY_TIMER 6 @@ -624,7 +685,7 @@ struct IsdnCardState { unsigned char subtyp; int protocol; unsigned int irq; - int HW_Flags; + int HW_Flags; int *busy_flag; union { struct elsa_hw elsa; @@ -641,7 +702,6 @@ struct IsdnCardState { struct njet_hw njet; struct hfcD_hw hfcD; struct ix1_hw niccy; - struct foreign_interface *foreign; } hw; int myid; isdn_if iif; @@ -657,7 +717,6 @@ struct IsdnCardState { void (*BC_Write_Reg) (struct IsdnCardState *, int, u_char, u_char); void (*BC_Send_Data) (struct BCState *); int (*cardmsg) (struct IsdnCardState *, int, void *); - void (*l1cmd) (struct IsdnCardState *, int, void *); struct Channel channel[2]; struct BCState bcs[2]; struct PStack *stlist; @@ -671,8 +730,7 @@ struct IsdnCardState { struct sk_buff_head rq, sq; /* D-channel queues */ int ph_state; int cardnr; - int dlogflag; - char *dlogspace; + char *dlog; int debug; u_char *mon_tx; u_char *mon_rx; @@ -688,6 +746,8 @@ struct IsdnCardState { #define MON0_TX 4 #define MON1_TX 8 +#define HISAX_MAX_CARDS 8 + #define ISDN_CTYPE_16_0 1 #define ISDN_CTYPE_8_0 2 #define ISDN_CTYPE_16_3 3 @@ -712,9 +772,12 @@ struct IsdnCardState { #define ISDN_CTYPE_SEDLBAUER_PCMCIA 22 #define ISDN_CTYPE_AMD7930 23 #define ISDN_CTYPE_NICCY 24 -#define ISDN_CTYPE_DBRI 25 +#define ISDN_CTYPE_S0BOX 25 +#define ISDN_CTYPE_A1_PCMCIA 26 +#define ISDN_CTYPE_FRITZPCI 27 +#define ISDN_CTYPE_SEDLBAUER_FAX 28 -#define ISDN_CTYPE_COUNT 25 +#define ISDN_CTYPE_COUNT 28 #ifdef ISDN_CHIP_ISAC #undef ISDN_CHIP_ISAC @@ -742,15 +805,42 @@ struct IsdnCardState { #define CARD_TELES3 0 #endif +#ifdef CONFIG_HISAX_TELESPCI +#define CARD_TELESPCI (1<< ISDN_CTYPE_TELESPCI) +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_TELESPCI 0 +#endif + #ifdef CONFIG_HISAX_AVM_A1 #define CARD_AVM_A1 (1<< ISDN_CTYPE_A1) -#ifndef ISDN_CHIP_ISAC +#ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif #else #define CARD_AVM_A1 0 #endif +#ifdef CONFIG_HISAX_AVM_A1_PCMCIA +#define CARD_AVM_A1_PCMCIA (1<< ISDN_CTYPE_A1_PCMCIA) +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_AVM_A1_PCMCIA 0 +#endif + +#ifdef CONFIG_HISAX_FRITZPCI +#define CARD_FRITZPCI (1<< ISDN_CTYPE_FRITZPCI) +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_FRITZPCI 0 +#endif + #ifdef CONFIG_HISAX_ELSA #define CARD_ELSA (1<< ISDN_CTYPE_ELSA) | (1<< ISDN_CTYPE_ELSA_PNP) | \ (1<< ISDN_CTYPE_ELSA_PCMCIA) | (1<< ISDN_CTYPE_ELSA_PCI) @@ -803,7 +893,7 @@ struct IsdnCardState { #endif #ifdef CONFIG_HISAX_SEDLBAUER -#define CARD_SEDLBAUER (1 << ISDN_CTYPE_SEDLBAUER) | (1 << ISDN_CTYPE_SEDLBAUER_PCMCIA) +#define CARD_SEDLBAUER (1 << ISDN_CTYPE_SEDLBAUER) | (1 << ISDN_CTYPE_SEDLBAUER_PCMCIA) | ( 1 << ISDN_CTYPE_SEDLBAUER_FAX) #ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif @@ -859,18 +949,21 @@ struct IsdnCardState { #define CARD_NICCY 0 #endif -#ifdef CONFIG_HISAX_DBRI -#define CARD_DBRI (1 << ISDN_CTYPE_DBRI) +#ifdef CONFIG_HISAX_S0BOX +#define CARD_S0BOX (1 << ISDN_CTYPE_S0BOX) +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif #else -#define CARD_DBRI 0 +#define CARD_S0BOX 0 #endif - #define SUPORTED_CARDS (CARD_TELES0 | CARD_TELES3 | CARD_AVM_A1 | CARD_ELSA \ | CARD_IX1MICROR2 | CARD_DIEHLDIVA | CARD_ASUSCOM \ | CARD_TELEINT | CARD_SEDLBAUER | CARD_SPORTSTER \ | CARD_MIC | CARD_NETJET | CARD_TELES3C | CARD_AMD7930 \ - | CARD_NICCY | CARD_DBRI) + | CARD_AVM_A1_PCMCIA | CARD_FRITZPCI\ + | CARD_NICCY | CARD_S0BOX | CARD_TELESPCI) #define TEI_PER_CARD 0 @@ -883,25 +976,38 @@ struct IsdnCardState { #undef TEI_PER_CARD #define TEI_PER_CARD 1 #define HISAX_EURO_SENDCOMPLETE 1 -#ifdef CONFIG_HISAX_ML +#define EXT_BEARER_CAPS 1 +#define HISAX_SEND_STD_LLC_IE 1 +#ifdef CONFIG_HISAX_NO_SENDCOMPLETE #undef HISAX_EURO_SENDCOMPLETE #endif +#ifdef CONFIG_HISAX_NO_LLC +#undef HISAX_SEND_STD_LLC_IE +#endif #undef HISAX_DE_AOC #ifdef CONFIG_DE_AOC #define HISAX_DE_AOC 1 #endif #endif -#if TEI_PER_CARD -#undef TEI_FIXED -#endif - -#undef PTP_DATA_LINK - -#ifdef PTP_DATA_LINK -#undef TEI_FIXED -#define TEI_FIXED 0 -#define LAYER2_WATCHING +/* L1 Debug */ +#define L1_DEB_WARN 0x01 +#define L1_DEB_INTSTAT 0x02 +#define L1_DEB_ISAC 0x04 +#define L1_DEB_ISAC_FIFO 0x08 +#define L1_DEB_HSCX 0x10 +#define L1_DEB_HSCX_FIFO 0x20 +#define L1_DEB_LAPD 0x40 +#define L1_DEB_IPAC 0x80 +#define L1_DEB_RECEIVE_FRAME 0x100 +#define L1_DEB_MONITOR 0x200 +#define DEB_DLOG_HEX 0x400 +#define DEB_DLOG_VERBOSE 0x800 + +#define L2FRAME_DEBUG + +#ifdef L2FRAME_DEBUG +extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir); #endif struct IsdnCard { @@ -911,17 +1017,26 @@ struct IsdnCard { struct IsdnCardState *cs; }; -void setstack_isdnl2(struct PStack *st, char *debug_id); -int HiSax_inithardware(int *); -void HiSax_closehardware(void); +void init_bcstate(struct IsdnCardState *cs, int bc); void setstack_HiSax(struct PStack *st, struct IsdnCardState *cs); unsigned int random_ri(void); -void setstack_isdnl3(struct PStack *st, struct Channel *chanp); void HiSax_addlist(struct IsdnCardState *sp, struct PStack *st); +void HiSax_rmlist(struct IsdnCardState *sp, struct PStack *st); + +void setstack_l1_B(struct PStack *st); + +void setstack_tei(struct PStack *st); +void setstack_manager(struct PStack *st); + +void setstack_isdnl2(struct PStack *st, char *debug_id); void releasestack_isdnl2(struct PStack *st); +void setstack_transl2(struct PStack *st); +void releasestack_transl2(struct PStack *st); + +void setstack_l3dc(struct PStack *st, struct Channel *chanp); +void setstack_l3bc(struct PStack *st, struct Channel *chanp); void releasestack_isdnl3(struct PStack *st); -void HiSax_rmlist(struct IsdnCardState *sp, struct PStack *st); u_char *findie(u_char * p, int size, u_char ie, int wanted_set); int getcallref(u_char * p); @@ -937,20 +1052,18 @@ int FsmAddTimer(struct FsmTimer *ft, int millisec, int event, void FsmRestartTimer(struct FsmTimer *ft, int millisec, int event, void *arg, int where); void FsmDelTimer(struct FsmTimer *ft, int where); -void jiftime(char *s, long mark); +int jiftime(char *s, long mark); int HiSax_command(isdn_ctrl * ic); int HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb); -void HiSax_putstatus(struct IsdnCardState *csta, char *buf); +void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...); +void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args); void HiSax_reportcard(int cardnr); int QuickHex(char *txt, u_char * p, int cnt); -void LogFrame(struct IsdnCardState *sp, u_char * p, int size); -void dlogframe(struct IsdnCardState *sp, u_char * p, int size, char *comment); +void LogFrame(struct IsdnCardState *cs, u_char * p, int size); +void dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir); void iecpy(u_char * dest, u_char * iestart, int ieoffset); -void setstack_transl2(struct PStack *st); -void releasestack_transl2(struct PStack *st); -void setstack_tei(struct PStack *st); -void setstack_manager(struct PStack *st); +int discard_queue(struct sk_buff_head *q); #ifdef ISDN_CHIP_ISAC void setstack_isac(struct PStack *st, struct IsdnCardState *cs); #endif /* ISDN_CHIP_ISAC */ @@ -958,18 +1071,21 @@ void setstack_isac(struct PStack *st, struct IsdnCardState *cs); #define HZDELAY(jiffs) {int tout = jiffs; while (tout--) udelay(1000000/HZ);} -int ll_run(struct IsdnCardState *csta); -void ll_stop(struct IsdnCardState *csta); +int ll_run(struct IsdnCardState *cs); +void ll_stop(struct IsdnCardState *cs); void CallcNew(void); void CallcFree(void); -int CallcNewChan(struct IsdnCardState *csta); -void CallcFreeChan(struct IsdnCardState *csta); +int CallcNewChan(struct IsdnCardState *cs); +void CallcFreeChan(struct IsdnCardState *cs); void Isdnl1New(void); void Isdnl1Free(void); void Isdnl2New(void); void Isdnl2Free(void); -void init_tei(struct IsdnCardState *sp, int protocol); -void release_tei(struct IsdnCardState *sp); +void Isdnl3New(void); +void Isdnl3Free(void); +void init_tei(struct IsdnCardState *cs, int protocol); +void release_tei(struct IsdnCardState *cs); char *HiSax_getrev(const char *revision); void TeiNew(void); void TeiFree(void); +int certification_check(int output); diff --git a/drivers/isdn/hisax/hscx.c b/drivers/isdn/hisax/hscx.c index c44cc54df..980dc76e8 100644 --- a/drivers/isdn/hisax/hscx.c +++ b/drivers/isdn/hisax/hscx.c @@ -1,11 +1,40 @@ -/* $Id: hscx.c,v 1.7 1998/02/12 23:07:36 keil Exp $ +/* $Id: hscx.c,v 1.16 1998/11/15 23:54:48 keil Exp $ * hscx.c HSCX specific routines * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * * $Log: hscx.c,v $ + * Revision 1.16 1998/11/15 23:54:48 keil + * changes from 2.0 + * + * Revision 1.15 1998/08/20 13:50:42 keil + * More support for hybrid modem (not working yet) + * + * Revision 1.14 1998/08/13 23:36:33 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 1.13 1998/06/26 22:03:28 keil + * send flags between hdlc frames + * + * Revision 1.12 1998/06/09 18:26:01 keil + * PH_DEACTIVATE B-channel every time signaled to higher layer + * + * Revision 1.11 1998/05/25 14:10:07 keil + * HiSax 3.0 + * X.75 and leased are working again. + * + * Revision 1.10 1998/05/25 12:57:59 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 1.9 1998/04/15 16:45:33 keil + * new init code + * + * Revision 1.8 1998/03/19 13:16:24 keil + * fix the correct release of the hscx + * * Revision 1.7 1998/02/12 23:07:36 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -30,6 +59,7 @@ #define __NO_VERSION__ #include "hisax.h" #include "hscx.h" +#include "isac.h" #include "isdnl1.h" #include <linux/interrupt.h> @@ -56,21 +86,20 @@ void modehscx(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; - int hscx = bcs->channel; + int hscx = bcs->hw.hscx.hscx; - if (cs->debug & L1_DEB_HSCX) { - char tmp[40]; - sprintf(tmp, "hscx %c mode %d ichan %d", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hscx %c mode %d ichan %d", 'A' + hscx, mode, bc); - debugl1(cs, tmp); - } bcs->mode = mode; - cs->BC_Write_Reg(cs, hscx, HSCX_CCR1, 0x85); + bcs->channel = bc; cs->BC_Write_Reg(cs, hscx, HSCX_XAD1, 0xFF); cs->BC_Write_Reg(cs, hscx, HSCX_XAD2, 0xFF); cs->BC_Write_Reg(cs, hscx, HSCX_RAH2, 0xFF); cs->BC_Write_Reg(cs, hscx, HSCX_XBCH, 0x0); cs->BC_Write_Reg(cs, hscx, HSCX_RLCR, 0x0); + cs->BC_Write_Reg(cs, hscx, HSCX_CCR1, + test_bit(HW_IPAC, &cs->HW_Flags) ? 0x82 : 0x85); cs->BC_Write_Reg(cs, hscx, HSCX_CCR2, 0x30); cs->BC_Write_Reg(cs, hscx, HSCX_XCCR, 7); cs->BC_Write_Reg(cs, hscx, HSCX_RCCR, 7); @@ -90,14 +119,16 @@ modehscx(struct BCState *bcs, int mode, int bc) } switch (mode) { case (L1_MODE_NULL): - cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, 0xff); - cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, 0xff); + cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, 0x1f); + cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, 0x1f); cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x84); break; case (L1_MODE_TRANS): cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0xe4); break; case (L1_MODE_HDLC): + cs->BC_Write_Reg(cs, hscx, HSCX_CCR1, + test_bit(HW_IPAC, &cs->HW_Flags) ? 0x8a : 0x8d); cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x8c); break; } @@ -114,89 +145,106 @@ hscx_sched_event(struct BCState *bcs, int event) mark_bh(IMMEDIATE_BH); } -static void +void hscx_l2l1(struct PStack *st, int pr, void *arg) { struct sk_buff *skb = arg; long flags; switch (pr) { - case (PH_DATA_REQ): + case (PH_DATA | REQUEST): save_flags(flags); cli(); - if (st->l1.bcs->hw.hscx.tx_skb) { + if (st->l1.bcs->tx_skb) { skb_queue_tail(&st->l1.bcs->squeue, skb); restore_flags(flags); } else { - st->l1.bcs->hw.hscx.tx_skb = skb; + st->l1.bcs->tx_skb = skb; test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); st->l1.bcs->hw.hscx.count = 0; restore_flags(flags); st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); } break; - case (PH_PULL_IND): - if (st->l1.bcs->hw.hscx.tx_skb) { + case (PH_PULL | INDICATION): + if (st->l1.bcs->tx_skb) { printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n"); break; } test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); - st->l1.bcs->hw.hscx.tx_skb = skb; + st->l1.bcs->tx_skb = skb; st->l1.bcs->hw.hscx.count = 0; st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); break; - case (PH_PULL_REQ): - if (!st->l1.bcs->hw.hscx.tx_skb) { + case (PH_PULL | REQUEST): + if (!st->l1.bcs->tx_skb) { test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL_CNF, NULL); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); } else test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; + case (PH_ACTIVATE | REQUEST): + test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + modehscx(st->l1.bcs, st->l1.mode, st->l1.bc); + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | REQUEST): + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | CONFIRM): + test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + modehscx(st->l1.bcs, 0, st->l1.bc); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); + break; } - } void close_hscxstate(struct BCState *bcs) { - struct sk_buff *skb; - - modehscx(bcs, 0, 0); + modehscx(bcs, 0, bcs->channel); if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { if (bcs->hw.hscx.rcvbuf) { kfree(bcs->hw.hscx.rcvbuf); bcs->hw.hscx.rcvbuf = NULL; } - while ((skb = skb_dequeue(&bcs->rqueue))) { - dev_kfree_skb(skb); - } - while ((skb = skb_dequeue(&bcs->squeue))) { - dev_kfree_skb(skb); + if (bcs->blog) { + kfree(bcs->blog); + bcs->blog = NULL; } - if (bcs->hw.hscx.tx_skb) { - dev_kfree_skb(bcs->hw.hscx.tx_skb); - bcs->hw.hscx.tx_skb = NULL; + discard_queue(&bcs->rqueue); + discard_queue(&bcs->squeue); + if (bcs->tx_skb) { + dev_kfree_skb(bcs->tx_skb); + bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } } } -static int -open_hscxstate(struct IsdnCardState *cs, - int bc) +int +open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs) { - struct BCState *bcs = cs->bcs + bc; - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { printk(KERN_WARNING - "HiSax: No memory for hscx.rcvbuf\n"); + "HiSax: No memory for hscx.rcvbuf\n"); + test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); return (1); } + if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for bcs->blog\n"); + test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); + kfree(bcs->hw.hscx.rcvbuf); + bcs->hw.hscx.rcvbuf = NULL; + return (2); + } skb_queue_head_init(&bcs->rqueue); skb_queue_head_init(&bcs->squeue); } - bcs->hw.hscx.tx_skb = NULL; + bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); bcs->event = 0; bcs->hw.hscx.rcvidx = 0; @@ -204,77 +252,74 @@ open_hscxstate(struct IsdnCardState *cs, return (0); } -static void -hscx_manl1(struct PStack *st, int pr, - void *arg) -{ - switch (pr) { - case (PH_ACTIVATE_REQ): - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - modehscx(st->l1.bcs, st->l1.mode, st->l1.bc); - st->l1.l1man(st, PH_ACTIVATE_CNF, NULL); - break; - case (PH_DEACTIVATE_REQ): - if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) - modehscx(st->l1.bcs, 0, 0); - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - break; - } -} - int setstack_hscx(struct PStack *st, struct BCState *bcs) { - if (open_hscxstate(st->l1.hardware, bcs->channel)) + bcs->channel = st->l1.bc; + if (open_hscxstate(st->l1.hardware, bcs)) return (-1); st->l1.bcs = bcs; st->l2.l2l1 = hscx_l2l1; - st->ma.manl1 = hscx_manl1; setstack_manager(st); bcs->st = st; + setstack_l1_B(st); return (0); } HISAX_INITFUNC(void clear_pending_hscx_ints(struct IsdnCardState *cs)) { - int val; - char tmp[64]; + int val, eval; val = cs->BC_Read_Reg(cs, 1, HSCX_ISTA); - sprintf(tmp, "HSCX B ISTA %x", val); - debugl1(cs, tmp); + debugl1(cs, "HSCX B ISTA %x", val); if (val & 0x01) { - val = cs->BC_Read_Reg(cs, 1, HSCX_EXIR); - sprintf(tmp, "HSCX B EXIR %x", val); - debugl1(cs, tmp); - } else if (val & 0x02) { - val = cs->BC_Read_Reg(cs, 0, HSCX_EXIR); - sprintf(tmp, "HSCX A EXIR %x", val); - debugl1(cs, tmp); + eval = cs->BC_Read_Reg(cs, 1, HSCX_EXIR); + debugl1(cs, "HSCX B EXIR %x", eval); + } + if (val & 0x02) { + eval = cs->BC_Read_Reg(cs, 0, HSCX_EXIR); + debugl1(cs, "HSCX A EXIR %x", eval); } val = cs->BC_Read_Reg(cs, 0, HSCX_ISTA); - sprintf(tmp, "HSCX A ISTA %x", val); - debugl1(cs, tmp); + debugl1(cs, "HSCX A ISTA %x", val); val = cs->BC_Read_Reg(cs, 1, HSCX_STAR); - sprintf(tmp, "HSCX B STAR %x", val); - debugl1(cs, tmp); + debugl1(cs, "HSCX B STAR %x", val); val = cs->BC_Read_Reg(cs, 0, HSCX_STAR); - sprintf(tmp, "HSCX A STAR %x", val); - debugl1(cs, tmp); + debugl1(cs, "HSCX A STAR %x", val); + /* disable all IRQ */ cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0xFF); cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0xFF); - cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0); - cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0); } -HISAX_INITFUNC(void +HISAX_INITFUNC(void inithscx(struct IsdnCardState *cs)) { cs->bcs[0].BC_SetStack = setstack_hscx; cs->bcs[1].BC_SetStack = setstack_hscx; cs->bcs[0].BC_Close = close_hscxstate; cs->bcs[1].BC_Close = close_hscxstate; + cs->bcs[0].hw.hscx.hscx = 0; + cs->bcs[1].hw.hscx.hscx = 1; modehscx(cs->bcs, 0, 0); modehscx(cs->bcs + 1, 0, 0); } + +HISAX_INITFUNC(void +inithscxisac(struct IsdnCardState *cs, int part)) +{ + if (part & 1) { + clear_pending_isac_ints(cs); + clear_pending_hscx_ints(cs); + initisac(cs); + inithscx(cs); + } + if (part & 2) { + /* Reenable all IRQ */ + cs->writeisac(cs, ISAC_MASK, 0); + cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0); + cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0); + /* RESET Receiver and Transmitter */ + cs->writeisac(cs, ISAC_CMDR, 0x41); + } +} diff --git a/drivers/isdn/hisax/hscx.h b/drivers/isdn/hisax/hscx.h index ac2d38086..08801bc73 100644 --- a/drivers/isdn/hisax/hscx.h +++ b/drivers/isdn/hisax/hscx.h @@ -1,4 +1,4 @@ -/* $Id: hscx.h,v 1.3 1997/07/27 21:38:35 keil Exp $ +/* $Id: hscx.h,v 1.4 1998/04/15 16:45:34 keil Exp $ * hscx.h HSCX specific defines * @@ -6,6 +6,9 @@ * * * $Log: hscx.h,v $ + * Revision 1.4 1998/04/15 16:45:34 keil + * new init code + * * Revision 1.3 1997/07/27 21:38:35 keil * new B-channel interface * @@ -44,3 +47,4 @@ extern void hscx_sched_event(struct BCState *bcs, int event); extern void modehscx(struct BCState *bcs, int mode, int bc); extern void clear_pending_hscx_ints(struct IsdnCardState *cs); extern void inithscx(struct IsdnCardState *cs); +extern void inithscxisac(struct IsdnCardState *cs, int part); diff --git a/drivers/isdn/hisax/hscx_irq.c b/drivers/isdn/hisax/hscx_irq.c index 992ec813b..217d241c3 100644 --- a/drivers/isdn/hisax/hscx_irq.c +++ b/drivers/isdn/hisax/hscx_irq.c @@ -1,12 +1,24 @@ -/* $Id: hscx_irq.c,v 1.7 1998/02/12 23:07:37 keil Exp $ +/* $Id: hscx_irq.c,v 1.11 1998/11/15 23:54:49 keil Exp $ * hscx_irq.c low level b-channel stuff for Siemens HSCX * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * This is an include file for fast inline IRQ stuff * * $Log: hscx_irq.c,v $ + * Revision 1.11 1998/11/15 23:54:49 keil + * changes from 2.0 + * + * Revision 1.10 1998/08/13 23:36:35 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 1.9 1998/06/24 14:44:51 keil + * Fix recovery of TX IRQ loss + * + * Revision 1.8 1998/04/10 10:35:22 paul + * fixed (silly?) warnings from egcs on Alpha. + * * Revision 1.7 1998/02/12 23:07:37 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -30,6 +42,8 @@ * */ +#include <linux/string.h> + static inline void waitforCEC(struct IsdnCardState *cs, int hscx) @@ -85,7 +99,7 @@ hscx_empty_fifo(struct BCState *bcs, int count) if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "hscx_empty_fifo: incoming packet too large"); - WriteHSCXCMDR(cs, bcs->channel, 0x80); + WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); bcs->hw.hscx.rcvidx = 0; return; } @@ -93,17 +107,16 @@ hscx_empty_fifo(struct BCState *bcs, int count) bcs->hw.hscx.rcvidx += count; save_flags(flags); cli(); - READHSCXFIFO(cs, bcs->channel, ptr, count); - WriteHSCXCMDR(cs, bcs->channel, 0x80); + READHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count); + WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); restore_flags(flags); if (cs->debug & L1_DEB_HSCX_FIFO) { - char tmp[256]; - char *t = tmp; + char *t = bcs->blog; t += sprintf(t, "hscx_empty_fifo %c cnt %d", - bcs->channel ? 'B' : 'A', count); + bcs->hw.hscx.hscx ? 'B' : 'A', count); QuickHex(t, ptr, count); - debugl1(cs, tmp); + debugl1(cs, bcs->blog); } } @@ -120,36 +133,35 @@ hscx_fill_fifo(struct BCState *bcs) if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) debugl1(cs, "hscx_fill_fifo"); - if (!bcs->hw.hscx.tx_skb) + if (!bcs->tx_skb) return; - if (bcs->hw.hscx.tx_skb->len <= 0) + if (bcs->tx_skb->len <= 0) return; more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; - if (bcs->hw.hscx.tx_skb->len > fifo_size) { + if (bcs->tx_skb->len > fifo_size) { more = !0; count = fifo_size; } else - count = bcs->hw.hscx.tx_skb->len; + count = bcs->tx_skb->len; - waitforXFW(cs, bcs->channel); + waitforXFW(cs, bcs->hw.hscx.hscx); save_flags(flags); cli(); - ptr = bcs->hw.hscx.tx_skb->data; - skb_pull(bcs->hw.hscx.tx_skb, count); + ptr = bcs->tx_skb->data; + skb_pull(bcs->tx_skb, count); bcs->tx_cnt -= count; bcs->hw.hscx.count += count; - WRITEHSCXFIFO(cs, bcs->channel, ptr, count); - WriteHSCXCMDR(cs, bcs->channel, more ? 0x8 : 0xa); + WRITEHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count); + WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa); restore_flags(flags); if (cs->debug & L1_DEB_HSCX_FIFO) { - char tmp[256]; - char *t = tmp; + char *t = bcs->blog; t += sprintf(t, "hscx_fill_fifo %c cnt %d", - bcs->channel ? 'B' : 'A', count); + bcs->hw.hscx.hscx ? 'B' : 'A', count); QuickHex(t, ptr, count); - debugl1(cs, tmp); + debugl1(cs, bcs->blog); } } @@ -161,7 +173,6 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) struct sk_buff *skb; int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32; int count; - char tmp[32]; if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return; @@ -173,11 +184,9 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) if (cs->debug & L1_DEB_WARN) debugl1(cs, "HSCX invalid frame"); if ((r & 0x40) && bcs->mode) - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "HSCX RDO mode=%d", + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "HSCX RDO mode=%d", bcs->mode); - debugl1(cs, tmp); - } if (!(r & 0x20)) if (cs->debug & L1_DEB_WARN) debugl1(cs, "HSCX CRC error"); @@ -189,10 +198,8 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) count = fifo_size; hscx_empty_fifo(bcs, count); if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { - if (cs->debug & L1_DEB_HSCX_FIFO) { - sprintf(tmp, "HX Frame %d", count); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_HSCX_FIFO) + debugl1(cs, "HX Frame %d", count); if (!(skb = dev_alloc_skb(count))) printk(KERN_WARNING "HSCX: receive out of memory\n"); else { @@ -219,20 +226,20 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) } } if (val & 0x10) { /* XPR */ - if (bcs->hw.hscx.tx_skb) { - if (bcs->hw.hscx.tx_skb->len) { + if (bcs->tx_skb) { + if (bcs->tx_skb->len) { hscx_fill_fifo(bcs); return; } else { if (bcs->st->lli.l1writewakeup && - (PACKET_NOACK != bcs->hw.hscx.tx_skb->pkt_type)) + (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); - dev_kfree_skb(bcs->hw.hscx.tx_skb); + dev_kfree_skb(bcs->tx_skb); bcs->hw.hscx.count = 0; - bcs->hw.hscx.tx_skb = NULL; + bcs->tx_skb = NULL; } } - if ((bcs->hw.hscx.tx_skb = skb_dequeue(&bcs->squeue))) { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { bcs->hw.hscx.count = 0; test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); hscx_fill_fifo(bcs); @@ -249,73 +256,60 @@ hscx_int_main(struct IsdnCardState *cs, u_char val) u_char exval; struct BCState *bcs; - char tmp[32]; if (val & 0x01) { bcs = cs->bcs + 1; exval = READHSCX(cs, 1, HSCX_EXIR); - if (exval == 0x40) { + if (exval & 0x40) { if (bcs->mode == 1) hscx_fill_fifo(bcs); else { /* Here we lost an TX interrupt, so * restart transmitting the whole frame. */ - if (bcs->hw.hscx.tx_skb) { - skb_push(bcs->hw.hscx.tx_skb, bcs->hw.hscx.count); + if (bcs->tx_skb) { + skb_push(bcs->tx_skb, bcs->hw.hscx.count); bcs->tx_cnt += bcs->hw.hscx.count; bcs->hw.hscx.count = 0; } - WriteHSCXCMDR(cs, bcs->channel, 0x01); - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "HSCX B EXIR %x Lost TX", exval); - debugl1(cs, tmp); - } + WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "HSCX B EXIR %x Lost TX", exval); } - } else if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "HSCX B EXIR %x", exval); - debugl1(cs, tmp); - } + } else if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX B EXIR %x", exval); } if (val & 0xf8) { - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "HSCX B interrupt %x", val); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX B interrupt %x", val); hscx_interrupt(cs, val, 1); } if (val & 0x02) { bcs = cs->bcs; exval = READHSCX(cs, 0, HSCX_EXIR); - if (exval == 0x40) { + if (exval & 0x40) { if (bcs->mode == L1_MODE_TRANS) hscx_fill_fifo(bcs); else { /* Here we lost an TX interrupt, so * restart transmitting the whole frame. */ - if (bcs->hw.hscx.tx_skb) { - skb_push(bcs->hw.hscx.tx_skb, bcs->hw.hscx.count); + if (bcs->tx_skb) { + skb_push(bcs->tx_skb, bcs->hw.hscx.count); bcs->tx_cnt += bcs->hw.hscx.count; bcs->hw.hscx.count = 0; } - WriteHSCXCMDR(cs, bcs->channel, 0x01); - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "HSCX A EXIR %x Lost TX", exval); - debugl1(cs, tmp); - } + WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "HSCX A EXIR %x Lost TX", exval); } - } else if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "HSCX A EXIR %x", exval); - debugl1(cs, tmp); - } + } else if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX A EXIR %x", exval); } if (val & 0x04) { exval = READHSCX(cs, 0, HSCX_ISTA); - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "HSCX A interrupt %x", exval); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX A interrupt %x", exval); hscx_interrupt(cs, exval, 0); } } diff --git a/drivers/isdn/hisax/ipac.h b/drivers/isdn/hisax/ipac.h index 6d856ec6c..82c5fa8f8 100644 --- a/drivers/isdn/hisax/ipac.h +++ b/drivers/isdn/hisax/ipac.h @@ -1,4 +1,4 @@ -/* $Id: ipac.h,v 1.2 1997/10/29 18:51:21 keil Exp $ +/* $Id: ipac.h,v 1.3 1998/04/15 16:48:09 keil Exp $ * ipac.h IPAC specific defines * @@ -6,6 +6,9 @@ * * * $Log: ipac.h,v $ + * Revision 1.3 1998/04/15 16:48:09 keil + * IPAC_ATX added + * * Revision 1.2 1997/10/29 18:51:21 keil * New files * @@ -26,6 +29,7 @@ #define IPAC_ACFG 0xC3 #define IPAC_AOE 0xC4 #define IPAC_ARX 0xC5 +#define IPAC_ATX 0xC5 #define IPAC_PITA1 0xC6 #define IPAC_PITA2 0xC7 #define IPAC_POTA1 0xC8 diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c index f8458364c..a239fdfad 100644 --- a/drivers/isdn/hisax/isac.c +++ b/drivers/isdn/hisax/isac.c @@ -1,11 +1,33 @@ -/* $Id: isac.c,v 1.12 1998/02/12 23:07:40 keil Exp $ +/* $Id: isac.c,v 1.18 1998/11/15 23:54:51 keil Exp $ * isac.c ISAC specific routines * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/HiSax.cert * * $Log: isac.c,v $ + * Revision 1.18 1998/11/15 23:54:51 keil + * changes from 2.0 + * + * Revision 1.17 1998/08/13 23:36:37 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 1.16 1998/05/25 12:58:01 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 1.15 1998/04/15 16:45:32 keil + * new init code + * + * Revision 1.14 1998/04/10 10:35:26 paul + * fixed (silly?) warnings from egcs on Alpha. + * + * Revision 1.13 1998/03/07 22:57:01 tsbogend + * made HiSax working on Linux/Alpha + * * Revision 1.12 1998/02/12 23:07:40 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -63,30 +85,17 @@ ISACVersion(struct IsdnCardState *cs, char *s) int val; val = cs->readisac(cs, ISAC_RBCH); - printk(KERN_INFO "%s ISAC version : %s\n", s, ISACVer[(val >> 5) & 3]); + printk(KERN_INFO "%s ISAC version (%x): %s\n", s, val, ISACVer[(val >> 5) & 3]); } static void ph_command(struct IsdnCardState *cs, unsigned int command) { - if (cs->debug & L1_DEB_ISAC) { - char tmp[32]; - sprintf(tmp, "ph_command %x", command); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ph_command %x", command); cs->writeisac(cs, ISAC_CIX0, (command << 2) | 3); } -static void -manl1_msg(struct IsdnCardState *cs, int msg, void *arg) { - struct PStack *st; - - st = cs->stlist; - while (st) { - st->ma.manl1(st, msg, arg); - st = st->next; - } -} static void isac_new_ph(struct IsdnCardState *cs) @@ -95,28 +104,28 @@ isac_new_ph(struct IsdnCardState *cs) case (ISAC_IND_RS): case (ISAC_IND_EI): ph_command(cs, ISAC_CMD_DUI); - manl1_msg(cs, PH_RESET_IND, NULL); + l1_msg(cs, HW_RESET | INDICATION, NULL); break; case (ISAC_IND_DID): - manl1_msg(cs, PH_DEACT_CNF, NULL); + l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); break; case (ISAC_IND_DR): - manl1_msg(cs, PH_DEACT_IND, NULL); + l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); break; case (ISAC_IND_PU): - manl1_msg(cs, PH_POWERUP_CNF, NULL); + l1_msg(cs, HW_POWERUP | CONFIRM, NULL); break; case (ISAC_IND_RSY): - manl1_msg(cs, PH_RSYNC_IND, NULL); + l1_msg(cs, HW_RSYNC | INDICATION, NULL); break; case (ISAC_IND_ARD): - manl1_msg(cs, PH_INFO2_IND, NULL); + l1_msg(cs, HW_INFO2 | INDICATION, NULL); break; case (ISAC_IND_AI8): - manl1_msg(cs, PH_I4_P8_IND, NULL); + l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); break; case (ISAC_IND_AI10): - manl1_msg(cs, PH_I4_P10_IND, NULL); + l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL); break; default: break; @@ -130,13 +139,12 @@ isac_bh(struct IsdnCardState *cs) 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_CNF, NULL); + stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); stptr = stptr->next; } } @@ -147,13 +155,13 @@ isac_bh(struct IsdnCardState *cs) if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) DChannel_proc_xmt(cs); if (test_and_clear_bit(D_RX_MON0, &cs->event)) - test_and_set_bit(HW_MON0_TX_END, &cs->HW_Flags); + test_and_set_bit(HW_MON0_RX_END, &cs->HW_Flags); if (test_and_clear_bit(D_RX_MON1, &cs->event)) - test_and_set_bit(HW_MON1_TX_END, &cs->HW_Flags); + test_and_set_bit(HW_MON1_RX_END, &cs->HW_Flags); if (test_and_clear_bit(D_TX_MON0, &cs->event)) - test_and_set_bit(HW_MON0_RX_END, &cs->HW_Flags); + test_and_set_bit(HW_MON0_TX_END, &cs->HW_Flags); if (test_and_clear_bit(D_TX_MON1, &cs->event)) - test_and_set_bit(HW_MON1_RX_END, &cs->HW_Flags); + test_and_set_bit(HW_MON1_TX_END, &cs->HW_Flags); } void @@ -165,13 +173,10 @@ isac_empty_fifo(struct IsdnCardState *cs, int count) if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) debugl1(cs, "isac_empty_fifo"); - if ((cs->rcvidx + count) >= MAX_DFRAME_LEN) { - if (cs->debug & L1_DEB_WARN) { - char tmp[40]; - sprintf(tmp, "isac_empty_fifo overrun %d", + if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isac_empty_fifo overrun %d", cs->rcvidx + count); - debugl1(cs, tmp); - } cs->writeisac(cs, ISAC_CMDR, 0x80); cs->rcvidx = 0; return; @@ -184,12 +189,11 @@ isac_empty_fifo(struct IsdnCardState *cs, int count) cs->writeisac(cs, ISAC_CMDR, 0x80); restore_flags(flags); if (cs->debug & L1_DEB_ISAC_FIFO) { - char tmp[128]; - char *t = tmp; + char *t = cs->dlog; t += sprintf(t, "isac_empty_fifo cnt %d", count); QuickHex(t, ptr, count); - debugl1(cs, tmp); + debugl1(cs, cs->dlog); } } @@ -231,12 +235,11 @@ isac_fill_fifo(struct IsdnCardState *cs) cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); add_timer(&cs->dbusytimer); if (cs->debug & L1_DEB_ISAC_FIFO) { - char tmp[128]; - char *t = tmp; + char *t = cs->dlog; t += sprintf(t, "isac_fill_fifo cnt %d", count); QuickHex(t, ptr, count); - debugl1(cs, tmp); + debugl1(cs, cs->dlog); } } @@ -255,12 +258,9 @@ isac_interrupt(struct IsdnCardState *cs, u_char val) struct sk_buff *skb; unsigned int count; long flags; - char tmp[32]; - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "ISAC interrupt %x", val); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC interrupt %x", val); if (val & 0x80) { /* RME */ exval = cs->readisac(cs, ISAC_RSTA); if ((exval & 0x70) != 0x20) { @@ -323,12 +323,20 @@ isac_interrupt(struct IsdnCardState *cs, u_char val) } afterXPR: if (val & 0x04) { /* CISQ */ - cs->ph_state = (cs->readisac(cs, ISAC_CIX0) >> 2) & 0xf; - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "ph_state change %x", cs->ph_state); - debugl1(cs, tmp); + exval = cs->readisac(cs, ISAC_CIR0); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC CIR0 %02X", exval ); + if (exval & 2) { + cs->ph_state = (exval >> 2) & 0xf; + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ph_state change %x", cs->ph_state); + isac_sched_event(cs, D_L1STATECHANGE); + } + if (exval & 1) { + exval = cs->readisac(cs, ISAC_CIR1); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC CIR1 %02X", exval ); } - isac_sched_event(cs, D_L1STATECHANGE); } if (val & 0x02) { /* SIN */ /* never */ @@ -337,16 +345,12 @@ isac_interrupt(struct IsdnCardState *cs, u_char val) } if (val & 0x01) { /* EXI */ exval = cs->readisac(cs, ISAC_EXIR); - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "ISAC EXIR %02x", exval); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ISAC EXIR %02x", exval); if (exval & 0x04) { v1 = cs->readisac(cs, ISAC_MOSR); - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "ISAC MOSR %02x", v1); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ISAC MOSR %02x", v1); #if ARCOFI_USE if (v1 & 0x08) { if (!cs->mon_rx) { @@ -370,10 +374,8 @@ isac_interrupt(struct IsdnCardState *cs, u_char val) goto afterMONR0; } cs->mon_rx[cs->mon_rxp++] = cs->readisac(cs, ISAC_MOR0); - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "ISAC MOR0 %02x", cs->mon_rx[cs->mon_rxp -1]); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ISAC MOR0 %02x", cs->mon_rx[cs->mon_rxp -1]); if (cs->mon_rxp == 1) { cs->mocr |= 0x04; cs->writeisac(cs, ISAC_MOCR, cs->mocr); @@ -402,66 +404,70 @@ isac_interrupt(struct IsdnCardState *cs, u_char val) goto afterMONR1; } cs->mon_rx[cs->mon_rxp++] = cs->readisac(cs, ISAC_MOR1); - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "ISAC MOR1 %02x", cs->mon_rx[cs->mon_rxp -1]); - debugl1(cs, tmp); - } - if (cs->mon_rxp == 1) { - cs->mocr |= 0x40; - cs->writeisac(cs, ISAC_MOCR, cs->mocr); - } + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ISAC MOR1 %02x", cs->mon_rx[cs->mon_rxp -1]); + cs->mocr |= 0x40; + cs->writeisac(cs, ISAC_MOCR, cs->mocr); } afterMONR1: if (v1 & 0x04) { cs->mocr &= 0xf0; + cs->writeisac(cs, ISAC_MOCR, cs->mocr); cs->mocr |= 0x0a; cs->writeisac(cs, ISAC_MOCR, cs->mocr); - isac_sched_event(cs, D_RX_MON0); + test_and_set_bit(HW_MON0_RX_END, &cs->HW_Flags); } if (v1 & 0x40) { cs->mocr &= 0x0f; + cs->writeisac(cs, ISAC_MOCR, cs->mocr); cs->mocr |= 0xa0; cs->writeisac(cs, ISAC_MOCR, cs->mocr); - isac_sched_event(cs, D_RX_MON1); + test_and_set_bit(HW_MON1_RX_END, &cs->HW_Flags); } if (v1 & 0x02) { - if (!cs->mon_tx) { + if ((!cs->mon_tx) || (cs->mon_txc && + (cs->mon_txp >= cs->mon_txc) && + !(v1 & 0x08))) { cs->mocr &= 0xf0; + cs->writeisac(cs, ISAC_MOCR, cs->mocr); cs->mocr |= 0x0a; cs->writeisac(cs, ISAC_MOCR, cs->mocr); + if (cs->mon_txc && + (cs->mon_txp >= cs->mon_txc)) + test_and_set_bit(HW_MON0_TX_END, &cs->HW_Flags); goto AfterMOX0; } - if (cs->mon_txp >= cs->mon_txc) { - if (cs->mon_txc) - isac_sched_event(cs, D_TX_MON0); + if (cs->mon_txc && (cs->mon_txp >= cs->mon_txc)) { + test_and_set_bit(HW_MON0_TX_END, &cs->HW_Flags); goto AfterMOX0; } cs->writeisac(cs, ISAC_MOX0, cs->mon_tx[cs->mon_txp++]); - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "ISAC %02x -> MOX0", cs->mon_tx[cs->mon_txp -1]); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ISAC %02x -> MOX0", cs->mon_tx[cs->mon_txp -1]); } AfterMOX0: if (v1 & 0x20) { - if (!cs->mon_tx) { + if ((!cs->mon_tx) || (cs->mon_txc && + (cs->mon_txp >= cs->mon_txc) && + !(v1 & 0x80))) { cs->mocr &= 0x0f; + cs->writeisac(cs, ISAC_MOCR, cs->mocr); cs->mocr |= 0xa0; cs->writeisac(cs, ISAC_MOCR, cs->mocr); + if (cs->mon_txc && + (cs->mon_txp >= cs->mon_txc)) + test_and_set_bit(HW_MON1_TX_END, &cs->HW_Flags); goto AfterMOX1; } - if (cs->mon_txp >= cs->mon_txc) { - if (cs->mon_txc) - isac_sched_event(cs, D_TX_MON1); + if (cs->mon_txc && (cs->mon_txp >= cs->mon_txc)) { + test_and_set_bit(HW_MON1_TX_END, &cs->HW_Flags); goto AfterMOX1; } cs->writeisac(cs, ISAC_MOX1, cs->mon_tx[cs->mon_txp++]); - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "ISAC %02x -> MOX1", cs->mon_tx[cs->mon_txp -1]); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ISAC %02x -> MOX1", cs->mon_tx[cs->mon_txp -1]); } AfterMOX1: #endif @@ -470,14 +476,18 @@ isac_interrupt(struct IsdnCardState *cs, u_char val) } static void -ISAC_l2l1(struct PStack *st, int pr, void *arg) +ISAC_l1hw(struct PStack *st, int pr, void *arg) { struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; struct sk_buff *skb = arg; - char str[64]; + int val; switch (pr) { - case (PH_DATA_REQ): + 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 */ @@ -485,12 +495,6 @@ ISAC_l2l1(struct PStack *st, int pr, void *arg) Logl2Frame(cs, skb, "PH_DATA Queued", 0); #endif } else { - if ((cs->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */ - LogFrame(cs, skb->data, skb->len); - sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei); - dlogframe(cs, skb->data + 4, skb->len - 4, - str); - } cs->tx_skb = skb; cs->tx_cnt = 0; #ifdef L2FRAME_DEBUG /* psa */ @@ -500,19 +504,17 @@ ISAC_l2l1(struct PStack *st, int pr, void *arg) isac_fill_fifo(cs); } break; - case (PH_PULL_IND): + 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->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */ + if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len); - sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei); - dlogframe(cs, skb->data + 4, skb->len - 4, - str); - } + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); cs->tx_skb = skb; cs->tx_cnt = 0; #ifdef L2FRAME_DEBUG /* psa */ @@ -521,28 +523,18 @@ ISAC_l2l1(struct PStack *st, int pr, void *arg) #endif isac_fill_fifo(cs); break; - case (PH_PULL_REQ): + 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_CNF, NULL); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); } else test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; - } -} - -void -isac_l1cmd(struct IsdnCardState *cs, int msg, void *arg) -{ - u_char val; - char tmp[32]; - - switch(msg) { - case PH_RESET_REQ: + case (HW_RESET | REQUEST): if ((cs->ph_state == ISAC_IND_EI) || (cs->ph_state == ISAC_IND_DR) || (cs->ph_state == ISAC_IND_RS)) @@ -550,17 +542,17 @@ isac_l1cmd(struct IsdnCardState *cs, int msg, void *arg) else ph_command(cs, ISAC_CMD_RS); break; - case PH_ENABLE_REQ: + case (HW_ENABLE | REQUEST): ph_command(cs, ISAC_CMD_TIM); break; - case PH_INFO3_REQ: + case (HW_INFO3 | REQUEST): ph_command(cs, ISAC_CMD_AR8); break; - case PH_TESTLOOP_REQ: + case (HW_TESTLOOP | REQUEST): val = 0; - if (1 & (int) arg) + if (1 & (long) arg) val |= 0x0c; - if (2 & (int) arg) + if (2 & (long) arg) val |= 0x3; if (test_bit(HW_IOM1, &cs->HW_Flags)) { /* IOM 1 Mode */ @@ -580,11 +572,21 @@ isac_l1cmd(struct IsdnCardState *cs, int msg, void *arg) cs->writeisac(cs, ISAC_ADF1, 0x0); } break; - default: - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "isac_l1cmd unknown %4x", msg); - debugl1(cs, tmp); + case (HW_DEACTIVATE | RESPONSE): + discard_queue(&cs->rq); + discard_queue(&cs->sq); + if (cs->tx_skb) { + dev_kfree_skb(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)) + isac_sched_event(cs, D_CLEARBUSY); + break; + default: + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isac_l1hw unknown %04x", pr); break; } } @@ -592,22 +594,29 @@ isac_l1cmd(struct IsdnCardState *cs, int msg, void *arg) void setstack_isac(struct PStack *st, struct IsdnCardState *cs) { - st->l2.l2l1 = ISAC_l2l1; + st->l1.l1hw = ISAC_l1hw; } static void dbusy_timer_handler(struct IsdnCardState *cs) { struct PStack *stptr; + int val; if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - if (cs->debug) + if (cs->debug) { debugl1(cs, "D-Channel Busy"); + val = cs->readisac(cs, ISAC_RBCH); + if (val & ISAC_RBCH_XAC) + debugl1(cs, "ISAC XAC"); + else + debugl1(cs, "ISAC No XAC"); + } test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); stptr = cs->stlist; while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE_IND, NULL); + stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); stptr = stptr->next; } } @@ -617,7 +626,6 @@ HISAX_INITFUNC(void initisac(struct IsdnCardState *cs)) { cs->tqueue.routine = (void *) (void *) isac_bh; - cs->l1cmd = isac_l1cmd; cs->setstack_d = setstack_isac; cs->dbusytimer.function = (void *) dbusy_timer_handler; cs->dbusytimer.data = (long) cs; @@ -648,35 +656,24 @@ initisac(struct IsdnCardState *cs)) HISAX_INITFUNC(void clear_pending_isac_ints(struct IsdnCardState *cs)) { - int val; - char tmp[64]; + int val, eval; val = cs->readisac(cs, ISAC_STAR); - sprintf(tmp, "ISAC STAR %x", val); - debugl1(cs, tmp); + debugl1(cs, "ISAC STAR %x", val); val = cs->readisac(cs, ISAC_MODE); - sprintf(tmp, "ISAC MODE %x", val); - debugl1(cs, tmp); + debugl1(cs, "ISAC MODE %x", val); val = cs->readisac(cs, ISAC_ADF2); - sprintf(tmp, "ISAC ADF2 %x", val); - debugl1(cs, tmp); + debugl1(cs, "ISAC ADF2 %x", val); val = cs->readisac(cs, ISAC_ISTA); - sprintf(tmp, "ISAC ISTA %x", val); - debugl1(cs, tmp); + debugl1(cs, "ISAC ISTA %x", val); if (val & 0x01) { - val = cs->readisac(cs, ISAC_EXIR); - sprintf(tmp, "ISAC EXIR %x", val); - debugl1(cs, tmp); - } else if (val & 0x04) { - val = cs->readisac(cs, ISAC_CIR0); - sprintf(tmp, "ISAC CIR0 %x", val); - debugl1(cs, tmp); - cs->ph_state = (val >> 2) & 0xf; - } else { - cs->ph_state = (cs->readisac(cs, ISAC_CIX0) >> 2) & 0xf; + eval = cs->readisac(cs, ISAC_EXIR); + debugl1(cs, "ISAC EXIR %x", eval); } + val = cs->readisac(cs, ISAC_CIR0); + debugl1(cs, "ISAC CIR0 %x", val); + cs->ph_state = (val >> 2) & 0xf; isac_sched_event(cs, D_L1STATECHANGE); + /* Disable all IRQ */ cs->writeisac(cs, ISAC_MASK, 0xFF); - cs->writeisac(cs, ISAC_MASK, 0); - cs->writeisac(cs, ISAC_CMDR, 0x41); } diff --git a/drivers/isdn/hisax/isac.h b/drivers/isdn/hisax/isac.h index ac4d55647..bed887d4f 100644 --- a/drivers/isdn/hisax/isac.h +++ b/drivers/isdn/hisax/isac.h @@ -1,4 +1,4 @@ -/* $Id: isac.h,v 1.4 1997/10/29 19:09:34 keil Exp $ +/* $Id: isac.h,v 1.5 1998/05/25 12:58:03 keil Exp $ * isac.h ISAC specific defines * @@ -6,6 +6,10 @@ * * * $Log: isac.h,v $ + * Revision 1.5 1998/05/25 12:58:03 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * * Revision 1.4 1997/10/29 19:09:34 keil * new L1 * @@ -26,16 +30,18 @@ #define ISAC_STAR 0x21 #define ISAC_CMDR 0x21 #define ISAC_EXIR 0x24 -#define ISAC_RBCH 0x2a #define ISAC_ADF2 0x39 #define ISAC_SPCR 0x30 #define ISAC_ADF1 0x38 #define ISAC_CIR0 0x31 #define ISAC_CIX0 0x31 +#define ISAC_CIR1 0x33 +#define ISAC_CIX1 0x33 #define ISAC_STCR 0x37 #define ISAC_MODE 0x22 #define ISAC_RSTA 0x27 #define ISAC_RBCL 0x25 +#define ISAC_RBCH 0x2A #define ISAC_TIMR 0x23 #define ISAC_SQXR 0x3b #define ISAC_MOSR 0x3a @@ -45,6 +51,8 @@ #define ISAC_MOR1 0x34 #define ISAC_MOX1 0x34 +#define ISAC_RBCH_XAC 0x80 + #define ISAC_CMD_TIM 0x0 #define ISAC_CMD_RS 0x1 #define ISAC_CMD_SCZ 0x4 diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c index b249b2c47..c8f88a162 100644 --- a/drivers/isdn/hisax/isdnl1.c +++ b/drivers/isdn/hisax/isdnl1.c @@ -1,9 +1,13 @@ -/* $Id: isdnl1.c,v 2.18 1998/02/12 23:07:42 keil Exp $ +/* $Id: isdnl1.c,v 2.31 1998/11/15 23:54:56 keil Exp $ * isdnl1.c common low level stuff for Siemens Chipsetbased isdn cards * based on the teles driver from Jan den Ouden * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) + * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/HiSax.cert * * Thanks to Jan den Ouden * Fritz Elfert @@ -11,6 +15,43 @@ * * * $Log: isdnl1.c,v $ + * Revision 2.31 1998/11/15 23:54:56 keil + * changes from 2.0 + * + * Revision 2.30 1998/09/30 22:27:00 keil + * Add init of l1.Flags + * + * Revision 2.29 1998/09/27 23:54:43 keil + * cosmetics + * + * Revision 2.28 1998/09/27 12:52:23 keil + * Fix against segfault, if the driver cannot allocate an IRQ channel + * + * Revision 2.27 1998/08/13 23:36:39 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 2.26 1998/07/15 15:01:31 calle + * Support for AVM passive PCMCIA cards: + * A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0 + * + * Revision 2.25 1998/05/25 14:10:09 keil + * HiSax 3.0 + * X.75 and leased are working again. + * + * Revision 2.24 1998/05/25 12:58:04 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 2.22 1998/04/15 16:40:13 keil + * Add S0Box and Teles PCI support + * Fix cardnr overwrite bug + * + * Revision 2.21 1998/04/10 10:35:28 paul + * fixed (silly?) warnings from egcs on Alpha. + * + * Revision 2.20 1998/03/09 23:19:27 keil + * Changes for PCMCIA + * * Revision 2.18 1998/02/12 23:07:42 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -79,102 +120,20 @@ * */ -const char *l1_revision = "$Revision: 2.18 $"; +const char *l1_revision = "$Revision: 2.31 $"; #define __NO_VERSION__ -#include <linux/config.h> #include "hisax.h" #include "isdnl1.h" -#include <linux/kernel_stat.h> -#if (LINUX_VERSION_CODE < 0x020150) /* 2.1.80 */ -#define kstat_irqs( PAR ) kstat.interrupts( (PAR) ) -#endif - - - -#if CARD_TELES0 -extern int setup_teles0(struct IsdnCard *card); -#endif - -#if CARD_TELES3 -extern int setup_teles3(struct IsdnCard *card); -#endif - -#if CARD_AVM_A1 -extern int setup_avm_a1(struct IsdnCard *card); -#endif - -#if CARD_ELSA -extern int setup_elsa(struct IsdnCard *card); -#endif - -#if CARD_IX1MICROR2 -extern int setup_ix1micro(struct IsdnCard *card); -#endif - -#if CARD_DIEHLDIVA -extern int setup_diva(struct IsdnCard *card); -#endif - -#if CARD_ASUSCOM -extern int setup_asuscom(struct IsdnCard *card); -#endif - -#if CARD_TELEINT -extern int setup_TeleInt(struct IsdnCard *card); -#endif - -#if CARD_SEDLBAUER -extern int setup_sedlbauer(struct IsdnCard *card); -#endif - -#if CARD_SPORTSTER -extern int setup_sportster(struct IsdnCard *card); -#endif - -#if CARD_MIC -extern int setup_mic(struct IsdnCard *card); -#endif - -#if CARD_NETJET -extern int setup_netjet(struct IsdnCard *card); -#endif - -#if CARD_TELES3C -extern int setup_t163c(struct IsdnCard *card); -#endif -#if CARD_AMD7930 || CARD_DBRI -extern int setup_foreign(struct IsdnCard *card); -#endif - -#if CARD_NICCY -extern int setup_niccy(struct IsdnCard *card); -#endif - -#define HISAX_STATUS_BUFSIZE 4096 -#define ISDN_CTRL_DEBUG 1 -#define INCLUDE_INLINE_FUNCS -#include <linux/tqueue.h> -#include <linux/interrupt.h> -const char *CardType[] = -{"No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3", "Creatix/Teles PnP", - "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)", - "AMD 7930", "NICCY", "DBRI" -}; +#define TIMER3_VALUE 7000 -extern struct IsdnCard cards[]; -extern int nrcards; -extern char *HiSax_id; -extern struct IsdnBuffers *tracebuf; - -#define TIMER3_VALUE 7 +static +struct Fsm l1fsm_b = +{NULL, 0, 0, NULL, NULL}; static -struct Fsm l1fsm = +struct Fsm l1fsm_d = {NULL, 0, 0, NULL, NULL}; enum { @@ -187,9 +146,9 @@ enum { ST_L1_F8, }; -#define L1_STATE_COUNT (ST_L1_F8+1) +#define L1D_STATE_COUNT (ST_L1_F8+1) -static char *strL1State[] = +static char *strL1DState[] = { "ST_L1_F2", "ST_L1_F3", @@ -201,7 +160,25 @@ static char *strL1State[] = }; enum { + ST_L1_NULL, + ST_L1_WAIT_ACT, + ST_L1_WAIT_DEACT, + ST_L1_ACTIV, +}; + +#define L1B_STATE_COUNT (ST_L1_ACTIV+1) + +static char *strL1BState[] = +{ + "ST_L1_NULL", + "ST_L1_WAIT_ACT", + "ST_L1_WAIT_DEACT", + "ST_L1_ACTIV", +}; + +enum { EV_PH_ACTIVATE, + EV_PH_DEACTIVATE, EV_RESET_IND, EV_DEACT_CNF, EV_DEACT_IND, @@ -219,6 +196,7 @@ enum { static char *strL1Event[] = { "EV_PH_ACTIVATE", + "EV_PH_DEACTIVATE", "EV_RESET_IND", "EV_DEACT_CNF", "EV_DEACT_IND", @@ -231,154 +209,30 @@ static char *strL1Event[] = "EV_TIMER3", }; -/* - * Find card with given driverId - */ -static inline struct IsdnCardState -*hisax_findcard(int driverid) -{ - int i; - - for (i = 0; i < nrcards; i++) - if (cards[i].cs) - if (cards[i].cs->myid == driverid) - return (cards[i].cs); - return (NULL); -} - -int -HiSax_readstatus(u_char * buf, int len, int user, int id, int channel) -{ - int count; - u_char *p; - struct IsdnCardState *csta = hisax_findcard(id); - - if (csta) { - for (p = buf, count = 0; count < len; p++, count++) { - if (user) - put_user(*csta->status_read++, p); - else - *p++ = *csta->status_read++; - if (csta->status_read > csta->status_end) - csta->status_read = csta->status_buf; - } - return count; - } else { - printk(KERN_ERR - "HiSax: if_readstatus called with invalid driverId!\n"); - return -ENODEV; - } -} - -#if ISDN_CTRL_DEBUG -void -HiSax_putstatus(struct IsdnCardState *csta, char *buf) -{ - long flags; - int len, count, i; - u_char *p; - isdn_ctrl ic; - - save_flags(flags); - cli(); - count = 0; - len = strlen(buf); - - if (!csta) { - printk(KERN_WARNING "HiSax: No CardStatus for message %s", buf); - restore_flags(flags); - return; - } - for (p = buf, i = len; i > 0; i--, p++) { - *csta->status_write++ = *p; - if (csta->status_write > csta->status_end) - csta->status_write = csta->status_buf; - count++; - } - restore_flags(flags); - if (count) { - ic.command = ISDN_STAT_STAVAIL; - ic.driver = csta->myid; - ic.arg = count; - csta->iif.statcallb(&ic); - } -} -#else -#define KDEBUG_DEF -#include "../kdebug.h" - -static int DbgLineNr=0,DbgSequenzNr=1; - void -HiSax_putstatus(struct IsdnCardState *csta, char *buf) +debugl1(struct IsdnCardState *cs, char *fmt, ...) { - char tmp[512]; + va_list args; + char tmp[8]; - if (DbgLineNr==23) - DbgLineNr=0; - sprintf(tmp, "%5d %s",DbgSequenzNr++,buf); - gput_str(tmp,0,DbgLineNr++); -} -#endif - -int -ll_run(struct IsdnCardState *csta) -{ - long flags; - isdn_ctrl ic; - - save_flags(flags); - cli(); - ic.driver = csta->myid; - ic.command = ISDN_STAT_RUN; - csta->iif.statcallb(&ic); - restore_flags(flags); - return 0; -} - -void -ll_stop(struct IsdnCardState *csta) -{ - isdn_ctrl ic; - - ic.command = ISDN_STAT_STOP; - ic.driver = csta->myid; - csta->iif.statcallb(&ic); - CallcFreeChan(csta); + va_start(args, fmt); + sprintf(tmp, "Card%d ", cs->cardnr + 1); + VHiSax_putstatus(cs, tmp, fmt, args); + va_end(args); } static void -ll_unload(struct IsdnCardState *csta) -{ - isdn_ctrl ic; - - ic.command = ISDN_STAT_UNLOAD; - ic.driver = csta->myid; - csta->iif.statcallb(&ic); - if (csta->status_buf) - kfree(csta->status_buf); - csta->status_read = NULL; - csta->status_write = NULL; - csta->status_end = NULL; - kfree(csta->dlogspace); -} - -void -debugl1(struct IsdnCardState *cs, char *msg) -{ - char tmp[1024], tm[32]; - - jiftime(tm, jiffies); - sprintf(tmp, "%s Card %d %s\n", tm, cs->cardnr + 1, msg); - HiSax_putstatus(cs, tmp); -} - -static void -l1m_debug(struct FsmInst *fi, char *s) +l1m_debug(struct FsmInst *fi, char *fmt, ...) { + va_list args; struct PStack *st = fi->userdata; + struct IsdnCardState *cs = st->l1.hardware; + char tmp[8]; - debugl1(st->l1.hardware, s); + va_start(args, fmt); + sprintf(tmp, "Card%d ", cs->cardnr + 1); + VHiSax_putstatus(cs, tmp, fmt, args); + va_end(args); } void @@ -389,9 +243,9 @@ L1activated(struct IsdnCardState *cs) st = cs->stlist; while (st) { if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) - st->l1.l1man(st, PH_ACTIVATE_CNF, NULL); + st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); else - st->l1.l1man(st, PH_ACTIVATE_IND, NULL); + st->l1.l1l2(st, PH_ACTIVATE | INDICATION, NULL); st = st->next; } } @@ -404,8 +258,8 @@ L1deactivated(struct IsdnCardState *cs) st = cs->stlist; while (st) { if (test_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - st->l1.l1l2(st, PH_PAUSE_CNF, NULL); - st->l1.l1man(st, PH_DEACTIVATE_IND, NULL); + st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL); + st->l1.l1l2(st, PH_DEACTIVATE | INDICATION, NULL); st = st->next; } test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags); @@ -422,7 +276,7 @@ DChannel_proc_xmt(struct IsdnCardState *cs) stptr = cs->stlist; while (stptr != NULL) if (test_and_clear_bit(FLG_L1_PULL_REQ, &stptr->l1.Flags)) { - stptr->l1.l1l2(stptr, PH_PULL_CNF, NULL); + stptr->l1.l1l2(stptr, PH_PULL | CONFIRM, NULL); break; } else stptr = stptr->next; @@ -434,7 +288,6 @@ DChannel_proc_rcv(struct IsdnCardState *cs) struct sk_buff *skb, *nskb; struct PStack *stptr = cs->stlist; int found, tei, sapi; - char tmp[64]; if (stptr) if (test_bit(FLG_L1_ACTTIMER, &stptr->l1.Flags)) @@ -448,16 +301,15 @@ DChannel_proc_rcv(struct IsdnCardState *cs) sapi = skb->data[0] >> 2; tei = skb->data[1] >> 1; + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 1); if (tei == GROUP_TEI) { - if (sapi == CTRL_SAPI) { /* sapi 0 */ - if (cs->dlogflag) { - LogFrame(cs, skb->data, skb->len); - dlogframe(cs, skb->data + 3, skb->len - 3, - "Q.931 frame network->user broadcast"); - } + if (sapi == CTRL_SAPI) { /* sapi 0 */ while (stptr != NULL) { if ((nskb = skb_clone(skb, GFP_ATOMIC))) - stptr->l1.l1l2(stptr, PH_DATA_IND, nskb); + stptr->l1.l1l2(stptr, PH_DATA | INDICATION, nskb); else printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n"); stptr = stptr->next; @@ -465,37 +317,24 @@ DChannel_proc_rcv(struct IsdnCardState *cs) } else if (sapi == TEI_SAPI) { while (stptr != NULL) { if ((nskb = skb_clone(skb, GFP_ATOMIC))) - stptr->l1.l1tei(stptr, PH_DATA_IND, nskb); + stptr->l1.l1tei(stptr, PH_DATA | INDICATION, nskb); else printk(KERN_WARNING "HiSax: tei broadcast buffer shortage\n"); stptr = stptr->next; } } dev_kfree_skb(skb); - } else if (sapi == CTRL_SAPI) { + } else if (sapi == CTRL_SAPI) { /* sapi 0 */ found = 0; while (stptr != NULL) if (tei == stptr->l2.tei) { - stptr->l1.l1l2(stptr, PH_DATA_IND, skb); + stptr->l1.l1l2(stptr, PH_DATA | INDICATION, skb); found = !0; break; } else stptr = stptr->next; - if (!found) { - /* BD 10.10.95 - * Print out D-Channel msg not processed - * by isdn4linux - */ - - if ((!(skb->data[0] >> 2)) && (!(skb->data[2] & 0x01))) { - sprintf(tmp, - "Q.931 frame network->user with tei %d (not for us)", - skb->data[1] >> 1); - LogFrame(cs, skb->data, skb->len); - dlogframe(cs, skb->data + 4, skb->len - 4, tmp); - } + if (!found) dev_kfree_skb(skb); - } } } } @@ -505,14 +344,18 @@ BChannel_proc_xmt(struct BCState *bcs) { struct PStack *st = bcs->st; - if (test_bit(BC_FLG_BUSY, &bcs->Flag)) + if (test_bit(BC_FLG_BUSY, &bcs->Flag)) { + debugl1(bcs->cs, "BC_BUSY Error"); return; + } if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) - st->l1.l1l2(st, PH_PULL_CNF, NULL); - if (!test_bit(BC_FLG_ACTIV, &bcs->Flag)) - if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && (!skb_queue_len(&bcs->squeue))) - st->ma.manl1(st, PH_DEACTIVATE_CNF, 0); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + if (!test_bit(BC_FLG_ACTIV, &bcs->Flag)) { + if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && (!skb_queue_len(&bcs->squeue))) { + st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL); + } + } } static void @@ -520,8 +363,12 @@ BChannel_proc_rcv(struct BCState *bcs) { struct sk_buff *skb; + if (bcs->st->l1.l1m.state == ST_L1_WAIT_ACT) { + FsmDelTimer(&bcs->st->l1.timer, 4); + FsmEvent(&bcs->st->l1.l1m, EV_TIMER_ACT, NULL); + } while ((skb = skb_dequeue(&bcs->rqueue))) { - bcs->st->l1.l1l2(bcs->st, PH_DATA_IND, skb); + bcs->st->l1.l1l2(bcs->st, PH_DATA | INDICATION, skb); } } @@ -581,443 +428,6 @@ init_bcstate(struct IsdnCardState *cs, bcs->Flag = 0; } -static void -closecard(int cardnr) -{ - struct IsdnCardState *csta = cards[cardnr].cs; - struct sk_buff *skb; - - if (csta->bcs->BC_Close != NULL) { - csta->bcs->BC_Close(csta->bcs + 1); - csta->bcs->BC_Close(csta->bcs); - } - - if (csta->rcvbuf) { - kfree(csta->rcvbuf); - csta->rcvbuf = NULL; - } - while ((skb = skb_dequeue(&csta->rq))) { - dev_kfree_skb(skb); - } - while ((skb = skb_dequeue(&csta->sq))) { - dev_kfree_skb(skb); - } - if (csta->tx_skb) { - dev_kfree_skb(csta->tx_skb); - csta->tx_skb = NULL; - } - if (csta->mon_rx) { - kfree(csta->mon_rx); - csta->mon_rx = NULL; - } - if (csta->mon_tx) { - kfree(csta->mon_tx); - csta->mon_tx = NULL; - } - csta->cardmsg(csta, CARD_RELEASE, NULL); - del_timer(&csta->dbusytimer); - ll_unload(csta); -} - -HISAX_INITFUNC(static int init_card(struct IsdnCardState *cs)) -{ - int irq_cnt, cnt = 3; - long flags; - - save_flags(flags); - cli(); - irq_cnt = kstat_irqs(cs->irq); - printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], cs->irq, - irq_cnt); - if (cs->cardmsg(cs, CARD_SETIRQ, NULL)) { - printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n", - cs->irq); - return(1); - } - while (cnt) { - cs->cardmsg(cs, CARD_INIT, NULL); - sti(); - current->state = TASK_INTERRUPTIBLE; - /* Timeout 10ms */ - schedule_timeout((10 * HZ) / 1000); - restore_flags(flags); - printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], - cs->irq, kstat_irqs(cs->irq)); - if (kstat_irqs(cs->irq) == irq_cnt) { - printk(KERN_WARNING - "%s: IRQ(%d) getting no interrupts during init %d\n", - CardType[cs->typ], cs->irq, 4 - cnt); - if (cnt == 1) { - free_irq(cs->irq, cs); - return (2); - } else { - cs->cardmsg(cs, CARD_RESET, NULL); - cnt--; - } - } else { - cs->cardmsg(cs, CARD_TEST, NULL); - return(0); - } - } - restore_flags(flags); - return(3); -} - -HISAX_INITFUNC(static int -checkcard(int cardnr, char *id, int *busy_flag)) -{ - long flags; - int ret = 0; - struct IsdnCard *card = cards + cardnr; - struct IsdnCardState *cs; - - save_flags(flags); - cli(); - if (!(cs = (struct IsdnCardState *) - kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for IsdnCardState(card %d)\n", - cardnr + 1); - restore_flags(flags); - return (0); - } - card->cs = cs; - cs->cardnr = cardnr; - cs->debug = L1_DEB_WARN; - cs->HW_Flags = 0; - cs->busy_flag = busy_flag; -#if TEI_PER_CARD -#else - test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); -#endif - cs->protocol = card->protocol; - - if ((card->typ > 0) && (card->typ < 31)) { - if (!((1 << card->typ) & SUPORTED_CARDS)) { - printk(KERN_WARNING - "HiSax: Support for %s Card not selected\n", - CardType[card->typ]); - restore_flags(flags); - return (0); - } - } else { - printk(KERN_WARNING - "HiSax: Card Type %d out of range\n", - card->typ); - restore_flags(flags); - return (0); - } - if (!(cs->dlogspace = kmalloc(4096, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for dlogspace(card %d)\n", - cardnr + 1); - restore_flags(flags); - return (0); - } - if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for status_buf(card %d)\n", - cardnr + 1); - kfree(cs->dlogspace); - restore_flags(flags); - return (0); - } - cs->stlist = NULL; - cs->dlogflag = 0; - cs->mon_tx = NULL; - cs->mon_rx = NULL; - cs->status_read = cs->status_buf; - cs->status_write = cs->status_buf; - cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1; - cs->typ = card->typ; - strcpy(cs->iif.id, id); - cs->iif.channels = 2; - cs->iif.maxbufsize = MAX_DATA_SIZE; - cs->iif.hl_hdrlen = MAX_HEADER_LEN; - cs->iif.features = - ISDN_FEATURE_L2_X75I | - ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_TRANS | - ISDN_FEATURE_L3_TRANS | -#ifdef CONFIG_HISAX_1TR6 - ISDN_FEATURE_P_1TR6 | -#endif -#ifdef CONFIG_HISAX_EURO - ISDN_FEATURE_P_EURO | -#endif -#ifdef CONFIG_HISAX_NI1 - ISDN_FEATURE_P_NI1 | -#endif - 0; - - cs->iif.command = HiSax_command; - cs->iif.writecmd = NULL; - cs->iif.writebuf_skb = HiSax_writebuf_skb; - cs->iif.readstat = HiSax_readstatus; - register_isdn(&cs->iif); - cs->myid = cs->iif.channels; - printk(KERN_INFO - "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1, - (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : - (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" : - (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" : - (card->protocol == ISDN_PTYPE_NI1) ? "NI1" : - "NONE", cs->iif.id, cs->myid); - switch (card->typ) { -#if CARD_TELES0 - case ISDN_CTYPE_16_0: - case ISDN_CTYPE_8_0: - ret = setup_teles0(card); - break; -#endif -#if CARD_TELES3 - case ISDN_CTYPE_16_3: - case ISDN_CTYPE_PNP: - case ISDN_CTYPE_TELESPCMCIA: - case ISDN_CTYPE_COMPAQ_ISA: - ret = setup_teles3(card); - break; -#endif -#if CARD_AVM_A1 - case ISDN_CTYPE_A1: - ret = setup_avm_a1(card); - break; -#endif -#if CARD_ELSA - case ISDN_CTYPE_ELSA: - case ISDN_CTYPE_ELSA_PNP: - case ISDN_CTYPE_ELSA_PCMCIA: - case ISDN_CTYPE_ELSA_PCI: - ret = setup_elsa(card); - break; -#endif -#if CARD_IX1MICROR2 - case ISDN_CTYPE_IX1MICROR2: - ret = setup_ix1micro(card); - break; -#endif -#if CARD_DIEHLDIVA - case ISDN_CTYPE_DIEHLDIVA: - ret = setup_diva(card); - break; -#endif -#if CARD_ASUSCOM - case ISDN_CTYPE_ASUSCOM: - ret = setup_asuscom(card); - break; -#endif -#if CARD_TELEINT - case ISDN_CTYPE_TELEINT: - ret = setup_TeleInt(card); - break; -#endif -#if CARD_SEDLBAUER - case ISDN_CTYPE_SEDLBAUER: - case ISDN_CTYPE_SEDLBAUER_PCMCIA: - ret = setup_sedlbauer(card); - break; -#endif -#if CARD_SPORTSTER - case ISDN_CTYPE_SPORTSTER: - ret = setup_sportster(card); - break; -#endif -#if CARD_MIC - case ISDN_CTYPE_MIC: - ret = setup_mic(card); - break; -#endif -#if CARD_NETJET - case ISDN_CTYPE_NETJET: - ret = setup_netjet(card); - break; -#endif -#if CARD_TELES3C - case ISDN_CTYPE_TELES3C: - ret = setup_t163c(card); - break; -#endif -#if CARD_NICCY - case ISDN_CTYPE_NICCY: - ret = setup_niccy(card); - break; -#endif -#if CARD_AMD7930 || CARD_DBRI - case ISDN_CTYPE_AMD7930: - case ISDN_CTYPE_DBRI: - ret = setup_foreign(card); - break; -#endif - default: - printk(KERN_WARNING "HiSax: Unknown Card Typ %d\n", - card->typ); - ll_unload(cs); - restore_flags(flags); - return (0); - } - if (!ret) { - ll_unload(cs); - restore_flags(flags); - return (0); - } - if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for isac rcvbuf\n"); - return (1); - } - cs->rcvidx = 0; - cs->tx_skb = NULL; - cs->tx_cnt = 0; - cs->event = 0; - cs->tqueue.next = 0; - cs->tqueue.sync = 0; - cs->tqueue.data = cs; - - skb_queue_head_init(&cs->rq); - skb_queue_head_init(&cs->sq); - - init_bcstate(cs, 0); - init_bcstate(cs, 1); - ret = init_card(cs); - if (ret) { - closecard(cardnr); - restore_flags(flags); - return (0); - } - init_tei(cs, cs->protocol); - CallcNewChan(cs); - ll_run(cs); - cs->l1cmd(cs, PH_RESET_REQ, NULL); - restore_flags(flags); - return (1); -} - -HISAX_INITFUNC(void -HiSax_shiftcards(int idx)) -{ - int i; - - for (i = idx; i < 15; i++) - memcpy(&cards[i], &cards[i + 1], sizeof(cards[i])); -} - -HISAX_INITFUNC(int -HiSax_inithardware(int *busy_flag)) -{ - int foundcards = 0; - int i = 0; - int t = ','; - int flg = 0; - char *id; - char *next_id = HiSax_id; - char ids[20]; - - if (strchr(HiSax_id, ',')) - t = ','; - else if (strchr(HiSax_id, '%')) - t = '%'; - - while (i < nrcards) { - if (cards[i].typ < 1) - break; - id = next_id; - if ((next_id = strchr(id, t))) { - *next_id++ = 0; - strcpy(ids, id); - flg = i + 1; - } else { - next_id = id; - if (flg >= i) - strcpy(ids, id); - else - sprintf(ids, "%s%d", id, i); - } - if (checkcard(i, ids, busy_flag)) { - foundcards++; - i++; - } else { - printk(KERN_WARNING "HiSax: Card %s not installed !\n", - CardType[cards[i].typ]); - if (cards[i].cs) - kfree((void *) cards[i].cs); - cards[i].cs = NULL; - HiSax_shiftcards(i); - } - } - return foundcards; -} - -void -HiSax_closehardware(void) -{ - int i; - long flags; - - save_flags(flags); - cli(); - for (i = 0; i < nrcards; i++) - if (cards[i].cs) { - ll_stop(cards[i].cs); - release_tei(cards[i].cs); - closecard(i); - free_irq(cards[i].cs->irq, cards[i].cs); - kfree((void *) cards[i].cs); - cards[i].cs = NULL; - } - Isdnl1Free(); - TeiFree(); - Isdnl2Free(); - CallcFree(); - restore_flags(flags); -} - -void -HiSax_reportcard(int cardnr) -{ - struct IsdnCardState *cs = cards[cardnr].cs; - struct PStack *stptr; - struct l3_process *pc; - int j, i = 1; - - printk(KERN_DEBUG "HiSax: reportcard No %d\n", cardnr + 1); - printk(KERN_DEBUG "HiSax: Type %s\n", CardType[cs->typ]); - printk(KERN_DEBUG "HiSax: debuglevel %x\n", cs->debug); - printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n", - (ulong) & HiSax_reportcard); - printk(KERN_DEBUG "HiSax: cs 0x%lX\n", (ulong) cs); - printk(KERN_DEBUG "HiSax: cs stl 0x%lX\n", (ulong) & (cs->stlist)); - stptr = cs->stlist; - while (stptr != NULL) { - printk(KERN_DEBUG "HiSax: dst%d 0x%lX\n", i, (ulong) stptr); - printk(KERN_DEBUG "HiSax: dst%d stp 0x%lX\n", i, (ulong) stptr->l1.stlistp); - printk(KERN_DEBUG "HiSax: tei %d sapi %d\n", - stptr->l2.tei, stptr->l2.sap); - printk(KERN_DEBUG "HiSax: man 0x%lX\n", (ulong) stptr->ma.layer); - pc = stptr->l3.proc; - while (pc) { - printk(KERN_DEBUG "HiSax: l3proc %x 0x%lX\n", pc->callref, - (ulong) pc); - printk(KERN_DEBUG "HiSax: state %d st 0x%lX chan 0x%lX\n", - pc->state, (ulong) pc->st, (ulong) pc->chan); - pc = pc->next; - } - stptr = stptr->next; - i++; - } - for (j = 0; j < 2; j++) { - printk(KERN_DEBUG "HiSax: ch%d 0x%lX\n", j, - (ulong) & cs->channel[j]); - stptr = cs->channel[j].b_st; - i = 1; - while (stptr != NULL) { - printk(KERN_DEBUG "HiSax: b_st%d 0x%lX\n", i, (ulong) stptr); - printk(KERN_DEBUG "HiSax: man 0x%lX\n", (ulong) stptr->ma.layer); - stptr = stptr->next; - i++; - } - } -} - #ifdef L2FRAME_DEBUG /* psa */ char * @@ -1052,7 +462,7 @@ l2cmd(u_char cmd) } } -static char tmp[20]; +static char tmpdeb[32]; char * l2frames(u_char * ptr) @@ -1061,7 +471,7 @@ l2frames(u_char * ptr) case 1: case 5: case 9: - sprintf(tmp, "%s[%d](nr %d)", l2cmd(ptr[2]), ptr[3] & 1, ptr[3] >> 1); + sprintf(tmpdeb, "%s[%d](nr %d)", l2cmd(ptr[2]), ptr[3] & 1, ptr[3] >> 1); break; case 0x6f: case 0x0f: @@ -1070,36 +480,33 @@ l2frames(u_char * ptr) case 0x63: case 0x87: case 0xaf: - sprintf(tmp, "%s[%d]", l2cmd(ptr[2]), (ptr[2] & 0x10) >> 4); + sprintf(tmpdeb, "%s[%d]", l2cmd(ptr[2]), (ptr[2] & 0x10) >> 4); break; default: if (!(ptr[2] & 1)) { - sprintf(tmp, "I[%d](ns %d, nr %d)", ptr[3] & 1, ptr[2] >> 1, ptr[3] >> 1); + sprintf(tmpdeb, "I[%d](ns %d, nr %d)", ptr[3] & 1, ptr[2] >> 1, ptr[3] >> 1); break; } else return "invalid command"; } - return tmp; + return tmpdeb; } void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir) { - char tmp[132]; u_char *ptr; ptr = skb->data; if (ptr[0] & 1 || !(ptr[1] & 1)) - debugl1(cs, "Addres not LAPD"); - else { - sprintf(tmp, "%s %s: %s%c (sapi %d, tei %d)", + debugl1(cs, "Address not LAPD"); + else + debugl1(cs, "%s %s: %s%c (sapi %d, tei %d)", (dir ? "<-" : "->"), buf, l2frames(ptr), ((ptr[0] & 2) >> 1) == dir ? 'C' : 'R', ptr[0] >> 2, ptr[1] >> 1); - debugl1(cs, tmp); - } } #endif @@ -1113,11 +520,10 @@ static void l1_deact_cnf(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct IsdnCardState *cs = st->l1.hardware; FsmChangeState(fi, ST_L1_F3); if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) - cs->l1cmd(cs, PH_ENABLE_REQ, NULL); + st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); } static void @@ -1126,24 +532,23 @@ l1_deact_req(struct FsmInst *fi, int event, void *arg) struct PStack *st = fi->userdata; FsmChangeState(fi, ST_L1_F3); - if (!test_bit(FLG_L1_T3RUN, &st->l1.Flags)) { +// if (!test_bit(FLG_L1_T3RUN, &st->l1.Flags)) { FsmDelTimer(&st->l1.timer, 1); FsmAddTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2); test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags); - } +// } } static void l1_power_up(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct IsdnCardState *cs = st->l1.hardware; if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) { FsmChangeState(fi, ST_L1_F4); - cs->l1cmd(cs, PH_INFO3_REQ, NULL); + st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); FsmDelTimer(&st->l1.timer, 1); - FsmAddTimer(&st->l1.timer, TIMER3_VALUE * HZ, EV_TIMER3, NULL, 2); + FsmAddTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags); } else FsmChangeState(fi, ST_L1_F3); @@ -1165,20 +570,18 @@ static void l1_info2_ind(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct IsdnCardState *cs = st->l1.hardware; FsmChangeState(fi, ST_L1_F6); - cs->l1cmd(cs, PH_INFO3_REQ, NULL); + st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); } static void l1_info4_ind(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct IsdnCardState *cs = st->l1.hardware; FsmChangeState(fi, ST_L1_F7); - cs->l1cmd(cs, PH_INFO3_REQ, NULL); + st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); if (test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags)) FsmDelTimer(&st->l1.timer, 4); if (!test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) { @@ -1193,50 +596,61 @@ static void l1_timer3(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct IsdnCardState *cs = st->l1.hardware; - + test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags); - if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) - L1deactivated(cs); - if (st->l1.l1m.state != ST_L1_F6) - FsmChangeState(fi, ST_L1_F3); + if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) + L1deactivated(st->l1.hardware); + if (st->l1.l1m.state != ST_L1_F6) { + FsmChangeState(fi, ST_L1_F3); + st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); + } } static void l1_timer_act(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct IsdnCardState *cs = st->l1.hardware; test_and_clear_bit(FLG_L1_ACTTIMER, &st->l1.Flags); test_and_set_bit(FLG_L1_ACTIVATED, &st->l1.Flags); - L1activated(cs); + L1activated(st->l1.hardware); } static void l1_timer_deact(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct IsdnCardState *cs = st->l1.hardware; test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags); test_and_clear_bit(FLG_L1_ACTIVATED, &st->l1.Flags); - L1deactivated(cs); - cs->l1cmd(cs, PH_DEACT_ACK, NULL); + L1deactivated(st->l1.hardware); + st->l1.l1hw(st, HW_DEACTIVATE | RESPONSE, NULL); } static void l1_activate(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct IsdnCardState *cs = st->l1.hardware; - cs->l1cmd(cs, PH_RESET_REQ, NULL); + st->l1.l1hw(st, HW_RESET | REQUEST, NULL); } -static struct FsmNode L1FnList[] HISAX_INITDATA = +static void +l1_activate_no(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + if ((!test_bit(FLG_L1_DEACTTIMER, &st->l1.Flags)) && (!test_bit(FLG_L1_T3RUN, &st->l1.Flags))) { + test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags); + L1deactivated(st->l1.hardware); + } +} + +static struct FsmNode L1DFnList[] HISAX_INITDATA = { {ST_L1_F3, EV_PH_ACTIVATE, l1_activate}, + {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}, {ST_L1_F4, EV_RESET_IND, l1_reset}, {ST_L1_F5, EV_RESET_IND, l1_reset}, @@ -1280,86 +694,159 @@ static struct FsmNode L1FnList[] HISAX_INITDATA = {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact}, }; -#define L1_FN_COUNT (sizeof(L1FnList)/sizeof(struct FsmNode)) +#define L1D_FN_COUNT (sizeof(L1DFnList)/sizeof(struct FsmNode)) + +static void +l1b_activate(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L1_WAIT_ACT); + FsmAddTimer(&st->l1.timer, st->l1.delay, EV_TIMER_ACT, NULL, 2); +} + +static void +l1b_deactivate(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L1_WAIT_DEACT); + FsmAddTimer(&st->l1.timer, 10, EV_TIMER_DEACT, NULL, 2); +} + +static void +l1b_timer_act(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L1_ACTIV); + st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); +} + +static void +l1b_timer_deact(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L1_NULL); + st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL); +} + +static struct FsmNode L1BFnList[] HISAX_INITDATA = +{ + {ST_L1_NULL, EV_PH_ACTIVATE, l1b_activate}, + {ST_L1_WAIT_ACT, EV_TIMER_ACT, l1b_timer_act}, + {ST_L1_ACTIV, EV_PH_DEACTIVATE, l1b_deactivate}, + {ST_L1_WAIT_DEACT, EV_TIMER_DEACT, l1b_timer_deact}, +}; + +#define L1B_FN_COUNT (sizeof(L1BFnList)/sizeof(struct FsmNode)) HISAX_INITFUNC(void Isdnl1New(void)) { - l1fsm.state_count = L1_STATE_COUNT; - l1fsm.event_count = L1_EVENT_COUNT; - l1fsm.strEvent = strL1Event; - l1fsm.strState = strL1State; - FsmNew(&l1fsm, L1FnList, L1_FN_COUNT); + 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); + l1fsm_b.state_count = L1B_STATE_COUNT; + l1fsm_b.event_count = L1_EVENT_COUNT; + l1fsm_b.strEvent = strL1Event; + l1fsm_b.strState = strL1BState; + FsmNew(&l1fsm_b, L1BFnList, L1B_FN_COUNT); } void Isdnl1Free(void) { - FsmFree(&l1fsm); + FsmFree(&l1fsm_d); + FsmFree(&l1fsm_b); } static void -dch_manl1(struct PStack *st, int pr, - void *arg) +dch_l2l1(struct PStack *st, int pr, void *arg) { struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - char tmp[32]; switch (pr) { - case PH_ACTIVATE_REQ: - if (cs->debug) { - sprintf(tmp, "PH_ACTIVATE_REQ %s", - strL1State[st->l1.l1m.state]); - debugl1(cs, tmp); - } + case (PH_DATA | REQUEST): + case (PH_PULL | REQUEST): + case (PH_PULL |INDICATION): + st->l1.l1hw(st, pr, arg); + break; + case (PH_ACTIVATE | REQUEST): + if (cs->debug) + debugl1(cs, "PH_ACTIVATE_REQ %s", + strL1DState[st->l1.l1m.state]); if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) - st->l1.l1man(st, PH_ACTIVATE_CNF, NULL); + st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); else { test_and_set_bit(FLG_L1_ACTIVATING, &st->l1.Flags); FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, arg); } break; - case PH_DEACTIVATE_REQ: - if (cs->debug) { - sprintf(tmp, "PH_DEACTIVATE_REQ %s", - strL1State[st->l1.l1m.state]); - debugl1(cs, tmp); - } - break; - case PH_TESTLOOP_REQ: - if (1 & (int) arg) + case (PH_TESTLOOP | REQUEST): + if (1 & (long) arg) debugl1(cs, "PH_TEST_LOOP B1"); - if (2 & (int) arg) + if (2 & (long) arg) debugl1(cs, "PH_TEST_LOOP B2"); - if (!(3 & (int) arg)) + if (!(3 & (long) arg)) debugl1(cs, "PH_TEST_LOOP DISABLED"); - cs->l1cmd(cs, PH_TESTLOOP_REQ, arg); - break; - case PH_RESET_IND: - FsmEvent(&st->l1.l1m, EV_RESET_IND, arg); - break; - case PH_DEACT_CNF: - FsmEvent(&st->l1.l1m, EV_DEACT_CNF, arg); - break; - case PH_DEACT_IND: - FsmEvent(&st->l1.l1m, EV_DEACT_IND, arg); + st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg); break; - case PH_POWERUP_CNF: - FsmEvent(&st->l1.l1m, EV_POWER_UP, arg); - break; - case PH_RSYNC_IND: - FsmEvent(&st->l1.l1m, EV_RSYNC_IND, arg); - break; - case PH_INFO2_IND: - FsmEvent(&st->l1.l1m, EV_INFO2_IND, arg); + default: + if (cs->debug) + debugl1(cs, "dch_l2l1 msg %04X unhandled", pr); break; - case PH_I4_P8_IND: - case PH_I4_P10_IND: - FsmEvent(&st->l1.l1m, EV_INFO4_IND, arg); + } +} + +void +l1_msg(struct IsdnCardState *cs, int pr, void *arg) { + struct PStack *st; + + st = cs->stlist; + + while (st) { + switch(pr) { + case (HW_RESET | INDICATION): + FsmEvent(&st->l1.l1m, EV_RESET_IND, arg); + break; + case (HW_DEACTIVATE | CONFIRM): + FsmEvent(&st->l1.l1m, EV_DEACT_CNF, arg); + break; + case (HW_DEACTIVATE | INDICATION): + FsmEvent(&st->l1.l1m, EV_DEACT_IND, arg); + break; + case (HW_POWERUP | CONFIRM): + FsmEvent(&st->l1.l1m, EV_POWER_UP, arg); + break; + case (HW_RSYNC | INDICATION): + FsmEvent(&st->l1.l1m, EV_RSYNC_IND, arg); + break; + case (HW_INFO2 | INDICATION): + FsmEvent(&st->l1.l1m, EV_INFO2_IND, arg); + break; + case (HW_INFO4_P8 | INDICATION): + case (HW_INFO4_P10 | INDICATION): + FsmEvent(&st->l1.l1m, EV_INFO4_IND, arg); + break; + default: + if (cs->debug) + debugl1(cs, "l1msg %04X unhandled", pr); + break; + } + st = st->next; + } +} + +void +l1_msg_b(struct PStack *st, int pr, void *arg) { + switch(pr) { + case (PH_ACTIVATE | REQUEST): + FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, NULL); break; - default: - if (cs->debug) { - sprintf(tmp, "dch_manl1 msg %04X unhandled", pr); - debugl1(cs, tmp); - } + case (PH_DEACTIVATE | REQUEST): + FsmEvent(&st->l1.l1m, EV_PH_DEACTIVATE, NULL); break; } } @@ -1369,7 +856,7 @@ setstack_HiSax(struct PStack *st, struct IsdnCardState *cs) { st->l1.hardware = cs; st->protocol = cs->protocol; - st->l1.l1m.fsm = &l1fsm; + st->l1.l1m.fsm = &l1fsm_d; st->l1.l1m.state = ST_L1_F3; st->l1.l1m.debug = cs->debug; st->l1.l1m.userdata = st; @@ -1379,7 +866,22 @@ setstack_HiSax(struct PStack *st, struct IsdnCardState *cs) setstack_tei(st); setstack_manager(st); st->l1.stlistp = &(cs->stlist); - st->ma.manl1 = dch_manl1; + st->l2.l2l1 = dch_l2l1; st->l1.Flags = 0; cs->setstack_d(st, cs); } + +void +setstack_l1_B(struct PStack *st) +{ + struct IsdnCardState *cs = st->l1.hardware; + + st->l1.l1m.fsm = &l1fsm_b; + st->l1.l1m.state = ST_L1_NULL; + st->l1.l1m.debug = cs->debug; + st->l1.l1m.userdata = st; + st->l1.l1m.userint = 0; + st->l1.l1m.printdebug = l1m_debug; + st->l1.Flags = 0; + FsmInitTimer(&st->l1.l1m, &st->l1.timer); +} diff --git a/drivers/isdn/hisax/isdnl1.h b/drivers/isdn/hisax/isdnl1.h index 71f081a07..01a96b7dd 100644 --- a/drivers/isdn/hisax/isdnl1.h +++ b/drivers/isdn/hisax/isdnl1.h @@ -1,6 +1,16 @@ -/* $Id: isdnl1.h,v 2.5 1998/02/02 13:36:58 keil Exp $ +/* $Id: isdnl1.h,v 2.8 1998/11/15 23:54:59 keil Exp $ * $Log: isdnl1.h,v $ + * Revision 2.8 1998/11/15 23:54:59 keil + * changes from 2.0 + * + * Revision 2.7 1998/09/30 22:21:55 keil + * cosmetics + * + * Revision 2.6 1998/05/25 12:58:06 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * * Revision 2.5 1998/02/02 13:36:58 keil * more debug * @@ -22,21 +32,6 @@ * */ - -#define L2FRAME_DEBUG - -/* DEBUG Level */ - -#define L1_DEB_WARN 0x01 -#define L1_DEB_INTSTAT 0x02 -#define L1_DEB_ISAC 0x04 -#define L1_DEB_ISAC_FIFO 0x08 -#define L1_DEB_HSCX 0x10 -#define L1_DEB_HSCX_FIFO 0x20 -#define L1_DEB_LAPD 0x40 -#define L1_DEB_IPAC 0x80 -#define L1_DEB_RECEIVE_FRAME 0x100 - #define D_RCVBUFREADY 0 #define D_XMTBUFREADY 1 #define D_L1STATECHANGE 2 @@ -49,11 +44,12 @@ #define B_RCVBUFREADY 0 #define B_XMTBUFREADY 1 -extern void debugl1(struct IsdnCardState *sp, char *msg); +extern void debugl1(struct IsdnCardState *cs, char *fmt, ...); extern void DChannel_proc_xmt(struct IsdnCardState *cs); extern void DChannel_proc_rcv(struct IsdnCardState *cs); - +extern void l1_msg(struct IsdnCardState *cs, int pr, void *arg); +extern void l1_msg_b(struct PStack *st, int pr, void *arg); #ifdef L2FRAME_DEBUG -extern void Logl2Frame(struct IsdnCardState *sp, struct sk_buff *skb, char *buf, int dir); +extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir); #endif diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c index 824ba16c3..ccef2682e 100644 --- a/drivers/isdn/hisax/isdnl2.c +++ b/drivers/isdn/hisax/isdnl2.c @@ -1,12 +1,42 @@ -/* $Id: isdnl2.c,v 2.7 1998/02/12 23:07:47 keil Exp $ +/* $Id: isdnl2.c,v 2.16 1998/11/15 23:55:01 keil Exp $ - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/HiSax.cert + * * Thanks to Jan den Ouden * Fritz Elfert * * $Log: isdnl2.c,v $ + * Revision 2.16 1998/11/15 23:55:01 keil + * changes from 2.0 + * + * Revision 2.15 1998/08/13 23:36:42 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 2.14 1998/06/19 15:19:18 keil + * fix LAPB tx_cnt for none I-frames + * + * Revision 2.13 1998/06/18 23:17:20 keil + * LAPB bugfix + * + * Revision 2.12 1998/05/25 14:10:12 keil + * HiSax 3.0 + * X.75 and leased are working again. + * + * Revision 2.11 1998/05/25 12:58:08 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 2.9 1998/04/10 10:35:30 paul + * fixed (silly?) warnings from egcs on Alpha. + * + * Revision 2.8 1998/03/07 22:57:04 tsbogend + * made HiSax working on Linux/Alpha + * * Revision 2.7 1998/02/12 23:07:47 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -25,7 +55,7 @@ * Old stuff is still in the separate branch. * * Revision 2.2 1997/07/31 11:49:05 keil - * Eroor handling for no TEI assign + * Error handling for no TEI assign * * Revision 2.1 1997/07/27 21:34:38 keil * cosmetics @@ -41,9 +71,9 @@ #include "hisax.h" #include "isdnl2.h" -const char *l2_revision = "$Revision: 2.7 $"; +const char *l2_revision = "$Revision: 2.16 $"; -static void l2m_debug(struct FsmInst *fi, char *s); +static void l2m_debug(struct FsmInst *fi, char *fmt, ...); static struct Fsm l2fsm = @@ -91,7 +121,6 @@ enum { EV_L2_MDL_ASSIGN, EV_L2_MDL_REMOVE, EV_L2_MDL_ERROR, - EV_L2_MDL_NOTEIPROC, EV_L1_DEACTIVATE, EV_L2_T200, EV_L2_T203, @@ -117,7 +146,6 @@ static char *strL2Event[] = "EV_L2_MDL_ASSIGN", "EV_L2_MDL_REMOVE", "EV_L2_MDL_ERROR", - "EV_L2_MDL_NOTEIPROC", "EV_L1_DEACTIVATE", "EV_L2_T200", "EV_L2_T203", @@ -161,26 +189,6 @@ cansend(struct PStack *st) return ((p1 < st->l2.window) && !test_bit(FLG_PEER_BUSY, &st->l2.flag)); } -static void -discard_i_queue(struct PStack *st) -{ - struct sk_buff *skb; - - while ((skb = skb_dequeue(&st->l2.i_queue))) { - dev_kfree_skb(skb); - } -} - -static void -discard_ui_queue(struct PStack *st) -{ - struct sk_buff *skb; - - while ((skb = skb_dequeue(&st->l2.ui_queue))) { - dev_kfree_skb(skb); - } -} - inline void clear_exception(struct Layer2 *l2) { @@ -224,20 +232,17 @@ sethdraddr(struct Layer2 *l2, u_char * header, int rsp) } } -static void -enqueue_ui(struct PStack *st, - struct sk_buff *skb) -{ - st->l2.l2l1(st, PH_DATA_REQ, skb); -} - -static void +inline static void enqueue_super(struct PStack *st, struct sk_buff *skb) { - st->l2.l2l1(st, PH_DATA_REQ, skb); + if (test_bit(FLG_LAPB, &st->l2.flag)) + st->l1.bcs->tx_cnt += skb->len; + st->l2.l2l1(st, PH_DATA | REQUEST, skb); } +#define enqueue_ui(a, b) enqueue_super(a, b) + inline int IsUI(u_char * data, int ext) { @@ -272,6 +277,16 @@ IsRR(u_char * data, int ext) } inline int +IsSFrame(u_char * data, int ext) +{ + register u_char d = *data; + + if (!ext) + d &= 0xf; + return(((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c)); +} + +inline int IsSABMX(u_char * data, int ext) { u_char d = data[0] & ~0x10; @@ -393,15 +408,15 @@ l2_mdl_error(struct FsmInst *fi, int event, void *arg) switch (event) { case EV_L2_UA: if (get_PollFlagFree(st, skb)) - st->ma.layer(st, MDL_ERROR_IND, (void *) 'C'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'C'); else - st->ma.layer(st, MDL_ERROR_IND, (void *) 'D'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'D'); break; case EV_L2_DM: if (get_PollFlagFree(st, skb)) - st->ma.layer(st, MDL_ERROR_IND, (void *) 'B'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B'); else { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'E'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E'); establishlink(fi); test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); } @@ -415,9 +430,16 @@ l2_dl_establish(struct FsmInst *fi, int event, void *arg) struct PStack *st = fi->userdata; int state = fi->state; - FsmChangeState(fi, ST_L2_3); - if (state == ST_L2_1) - st->l2.l2tei(st, MDL_ASSIGN_IND, NULL); + + if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) { + FsmChangeState(fi, ST_L2_4); + establishlink(fi); + test_and_set_bit(FLG_L3_INIT, &st->l2.flag); + } else { + FsmChangeState(fi, ST_L2_3); + if (state == ST_L2_1) + st->l2.l2tei(st, MDL_ASSIGN | INDICATION, NULL); + } } static void @@ -444,7 +466,7 @@ l2_put_ui(struct FsmInst *fi, int event, void *arg) skb_queue_tail(&st->l2.ui_queue, skb); if (fi->state == ST_L2_1) { FsmChangeState(fi, ST_L2_2); - st->l2.l2tei(st, MDL_ASSIGN_IND, NULL); + st->l2.l2tei(st, MDL_ASSIGN | INDICATION, NULL); } if (fi->state > ST_L2_3) l2_send_ui(st); @@ -458,10 +480,10 @@ l2_got_ui(struct FsmInst *fi, int event, void *arg) skb_pull(skb, l2headersize(&st->l2, 1)); if (skb->len > st->l2.maxlen) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'O'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'O'); FreeSkb(skb); } else - st->l2.l2l3(st, DL_UNIT_DATA, skb); + st->l2.l2l3(st, DL_UNIT_DATA | INDICATION, skb); } static void @@ -470,7 +492,7 @@ l2_establish(struct FsmInst *fi, int event, void *arg) struct PStack *st = fi->userdata; if (fi->state != ST_L2_4) - discard_i_queue(st); + discard_queue(&st->l2.i_queue); if (fi->state != ST_L2_5) establishlink(fi); test_and_set_bit(FLG_L3_INIT, &st->l2.flag); @@ -482,13 +504,13 @@ l2_dl_release(struct FsmInst *fi, int event, void *arg) struct PStack *st = fi->userdata; if (fi->state == ST_L2_4) { - st->l2.l2man(st, DL_RELEASE, NULL); + st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL); return; } else if (fi->state == ST_L2_5) { test_and_set_bit(FLG_PEND_REL, &st->l2.flag); return; } - discard_i_queue(st); + discard_queue(&st->l2.i_queue); FsmChangeState(fi, ST_L2_6); st->l2.rc = 0; send_uframe(st, DISC | 0x10, CMD); @@ -510,14 +532,14 @@ l2_got_SABMX(struct FsmInst *fi, int event, void *arg) if (test_bit(FLG_ORIG, &st->l2.flag)) rsp = !rsp; if (rsp) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'L'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'L'); FreeSkb(skb); if ((state == ST_L2_7) || (state == ST_L2_8)) establishlink(fi); return; } if (skb->len != (l2addrsize(&st->l2) + 1)) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N'); FreeSkb(skb); if ((state == ST_L2_7) || (state == ST_L2_8)) establishlink(fi); @@ -532,9 +554,9 @@ l2_got_SABMX(struct FsmInst *fi, int event, void *arg) if (ST_L2_5 == state) return; if (ST_L2_4 != state) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'F'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'F'); if (st->l2.vs != st->l2.va) { - discard_i_queue(st); + discard_queue(&st->l2.i_queue); est = 1; } else est = 0; @@ -547,14 +569,14 @@ l2_got_SABMX(struct FsmInst *fi, int event, void *arg) FsmChangeState(fi, ST_L2_7); if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) FsmDelTimer(&st->l2.t200, 2); - FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3); + FsmRestartTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3); if (est) - st->l2.l2man(st, DL_ESTABLISH, NULL); + st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL); if (ST_L2_8 == state) if (skb_queue_len(&st->l2.i_queue) && cansend(st)) - st->l2.l2l1(st, PH_PULL_REQ, NULL); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } static void @@ -571,14 +593,14 @@ l2_got_disconn(struct FsmInst *fi, int event, void *arg) rsp = !rsp; if (rsp) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'L'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'L'); FreeSkb(skb); if ((state == ST_L2_7) || (state == ST_L2_8)) establishlink(fi); return; } if (skb->len != (l2addrsize(&st->l2) + 1)) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N'); FreeSkb(skb); if ((state == ST_L2_7) || (state == ST_L2_8)) establishlink(fi); @@ -600,8 +622,11 @@ l2_got_disconn(struct FsmInst *fi, int event, void *arg) FsmDelTimer(&st->l2.t200, 2); } send_uframe(st, cmd | PollFlag, RSP); - if (rel) - st->l2.l2man(st, DL_RELEASE, NULL); + if (rel) { + if (test_bit(FLG_LAPB, &st->l2.flag)) + st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); + st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); + } } @@ -610,7 +635,8 @@ l2_got_ua(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; struct sk_buff *skb = arg; - u_char PollFlag, est = 1; + int pr=-1; + u_char PollFlag; int state,rsp; state = fi->state; @@ -619,14 +645,14 @@ l2_got_ua(struct FsmInst *fi, int event, void *arg) rsp = !rsp; if (!rsp) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'L'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'L'); FreeSkb(skb); if ((state == ST_L2_7) || (state == ST_L2_8)) establishlink(fi); return; } if (skb->len != (l2addrsize(&st->l2) + 1)) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N'); FreeSkb(skb); if ((fi->state == ST_L2_7) || (fi->state == ST_L2_8)) establishlink(fi); @@ -643,30 +669,31 @@ l2_got_ua(struct FsmInst *fi, int event, void *arg) FsmDelTimer(&st->l2.t200, 2); if (fi->state == ST_L2_5) { if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag)) { - discard_i_queue(st); + discard_queue(&st->l2.i_queue); st->l2.rc = 0; send_uframe(st, DISC | 0x10, CMD); FsmChangeState(fi, ST_L2_6); FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 4); test_and_set_bit(FLG_T200_RUN, &st->l2.flag); } else { - if (!test_and_clear_bit(FLG_L3_INIT, &st->l2.flag)) { - if (st->l2.vs != st->l2.va) - discard_i_queue(st); - else - est = 0; + if (test_and_clear_bit(FLG_L3_INIT, &st->l2.flag)) { + pr = DL_ESTABLISH | CONFIRM; + } else if (st->l2.vs != st->l2.va) { + discard_queue(&st->l2.i_queue); + pr = DL_ESTABLISH | INDICATION; } st->l2.vs = 0; st->l2.va = 0; st->l2.vr = 0; st->l2.sow = 0; FsmChangeState(fi, ST_L2_7); - FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 4); - if (est) - st->l2.l2man(st, DL_ESTABLISH, NULL); + if (pr > -1) + st->l2.l2l3(st, pr, NULL); } } else { /* ST_L2_6 */ - st->l2.l2man(st, DL_RELEASE, NULL); + if (test_bit(FLG_LAPB, &st->l2.flag)) + st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); + st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL); FsmChangeState(fi, ST_L2_4); } } @@ -685,14 +712,14 @@ l2_got_dm(struct FsmInst *fi, int event, void *arg) rsp = !rsp; if (!rsp) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'L'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'L'); FreeSkb(skb); if ((state == ST_L2_7) || (state == ST_L2_8)) establishlink(fi); return; } if (skb->len != (l2addrsize(&st->l2) + 1)) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N'); FreeSkb(skb); if ((fi->state == ST_L2_7) || (fi->state == ST_L2_8)) establishlink(fi); @@ -700,15 +727,41 @@ l2_got_dm(struct FsmInst *fi, int event, void *arg) } PollFlag = get_PollFlagFree(st, skb); if (!PollFlag) { - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); + if (fi->state == ST_L2_4) { + establishlink(fi); + test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); + FsmChangeState(fi, ST_L2_5); + } else if ((fi->state == ST_L2_7) || (fi->state == ST_L2_8)) { + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E'); + establishlink(fi); + } } else { - if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) - FsmDelTimer(&st->l2.t200, 2); - if (fi->state == ST_L2_5 && !test_bit(FLG_L3_INIT, &st->l2.flag)) - discard_i_queue(st); - st->l2.l2man(st, DL_RELEASE, NULL); - FsmChangeState(fi, ST_L2_4); + switch (fi->state) { + case ST_L2_8: + establishlink(fi); + case ST_L2_7: + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B'); + break; + case ST_L2_4: + break; + case ST_L2_5: + if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) + FsmDelTimer(&st->l2.t200, 2); + discard_queue(&st->l2.i_queue); + if (test_bit(FLG_LAPB, &st->l2.flag)) + st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); + st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); + FsmChangeState(fi, ST_L2_4); + break; + case ST_L2_6: + if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) + FsmDelTimer(&st->l2.t200, 2); + if (test_bit(FLG_LAPB, &st->l2.flag)) + st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); + st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL); + FsmChangeState(fi, ST_L2_4); + break; + } } } @@ -763,7 +816,7 @@ nrerrorrecovery(struct FsmInst *fi) { struct PStack *st = fi->userdata; - st->ma.layer(st, MDL_ERROR_IND, (void *) 'J'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'J'); establishlink(fi); } @@ -785,11 +838,13 @@ invoke_retransmission(struct PStack *st, int nr) if (p1 < 0) p1 += (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8); p1 = (p1 + l2->sow) % l2->window; + if (test_bit(FLG_LAPB, &l2->flag)) + st->l1.bcs->tx_cnt += l2->windowar[p1]->len + l2headersize(l2, 0); skb_queue_head(&l2->i_queue, l2->windowar[p1]); l2->windowar[p1] = NULL; } restore_flags(flags); - st->l2.l2l1(st, PH_PULL_REQ, NULL); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } } @@ -818,9 +873,11 @@ l2_got_st7_super(struct FsmInst *fi, int event, void *arg) PollFlag = (skb->data[1] & 0x1) == 0x1; nr = skb->data[1] >> 1; } else { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); + if (skb->len >2) { + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N'); + establishlink(fi); + } FreeSkb(skb); - establishlink(fi); return; } } else { @@ -828,7 +885,7 @@ l2_got_st7_super(struct FsmInst *fi, int event, void *arg) PollFlag = (skb->data[0] & 0x10); nr = (skb->data[0] >> 5) & 0x7; } else { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N'); FreeSkb(skb); establishlink(fi); return; @@ -839,7 +896,7 @@ l2_got_st7_super(struct FsmInst *fi, int event, void *arg) if ((!rsp) && PollFlag) enquiry_response(st); if (rsp && PollFlag) - st->ma.layer(st, MDL_ERROR_IND, (void *) 'A'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'A'); if (legalnr(st, nr)) { if (typ == REJ) { setva(st, nr); @@ -862,13 +919,13 @@ l2_got_st7_super(struct FsmInst *fi, int event, void *arg) test_and_set_bit(FLG_T200_RUN, &st->l2.flag); } if (skb_queue_len(&st->l2.i_queue) && (typ == RR)) - st->l2.l2l1(st, PH_PULL_REQ, NULL); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } else nrerrorrecovery(fi); if ((fi->userint & LC_FLUSH_WAIT) && rsp && !(skb_queue_len(&st->l2.i_queue))) { fi->userint &= ~LC_FLUSH_WAIT; - st->l2.l2man(st, DL_FLUSH, NULL); + st->l2.l2l3(st, DL_FLUSH | INDICATION, NULL); } } @@ -883,7 +940,7 @@ l2_feed_iqueue(struct FsmInst *fi, int event, void *arg) if (!((fi->state == ST_L2_5) && test_bit(FLG_L3_INIT, &st->l2.flag))) skb_queue_tail(&st->l2.i_queue, skb); if (fi->state == ST_L2_7) - st->l2.l2l1(st, PH_PULL_REQ, NULL); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } static void @@ -891,17 +948,15 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; struct sk_buff *skb = arg; - struct IsdnCardState *sp = st->l1.hardware; struct Layer2 *l2 = &(st->l2); - int PollFlag, ns, nr, i, hs, rsp; - char str[64]; + int PollFlag, ns, nr, i, rsp; rsp = *skb->data & 0x2; if (test_bit(FLG_ORIG, &l2->flag)) rsp = !rsp; if (rsp) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'L'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'L'); FreeSkb(skb); establishlink(fi); return; @@ -909,12 +964,10 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg) i = l2addrsize(l2); if (test_bit(FLG_MOD128, &l2->flag)) { if (skb->len <= (i + 1)) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); FreeSkb(skb); - establishlink(fi); return; } else if ((skb->len - i - 1) > l2->maxlen) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'O'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'O'); FreeSkb(skb); establishlink(fi); return; @@ -924,12 +977,12 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg) nr = (skb->data[i + 1] >> 1) & 0x7f; } else { if (skb->len <= i) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N'); FreeSkb(skb); establishlink(fi); return; } else if ((skb->len - i) > l2->maxlen) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'O'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'O'); FreeSkb(skb); establishlink(fi); return; @@ -944,20 +997,12 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg) } else if (l2->vr == ns) { l2->vr = (l2->vr + 1) % (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8); test_and_clear_bit(FLG_REJEXC, &l2->flag); - if (test_bit(FLG_LAPD, &l2->flag)) - if (sp->dlogflag) { - hs = l2headersize(l2, 0); - LogFrame(st->l1.hardware, skb->data, skb->len); - sprintf(str, "Q.931 frame network->user tei %d", st->l2.tei); - dlogframe(st->l1.hardware, skb->data + hs, - skb->len - hs, str); - } if (PollFlag) enquiry_response(st); else test_and_set_bit(FLG_ACK_PEND, &l2->flag); skb_pull(skb, l2headersize(l2, 0)); - st->l2.l2l3(st, DL_DATA, skb); + st->l2.l2l3(st, DL_DATA | INDICATION, skb); } else { /* n(s)!=v(r) */ FreeSkb(skb); @@ -990,7 +1035,7 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg) } if (skb_queue_len(&st->l2.i_queue) && (fi->state == ST_L2_7)) - st->l2.l2l1(st, PH_PULL_REQ, NULL); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); if (test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag)) enquiry_cr(st, RR, RSP, 0); } @@ -1000,7 +1045,7 @@ l2_got_tei(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - st->l2.tei = (int) arg; + st->l2.tei = (long) arg; if (fi->state == ST_L2_3) { establishlink(fi); @@ -1012,12 +1057,6 @@ l2_got_tei(struct FsmInst *fi, int event, void *arg) } static void -l2_no_tei(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L2_4); -} - -static void l2_st5_tout_200(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -1028,9 +1067,11 @@ l2_st5_tout_200(struct FsmInst *fi, int event, void *arg) } else if (st->l2.rc == st->l2.N200) { FsmChangeState(fi, ST_L2_4); test_and_clear_bit(FLG_T200_RUN, &st->l2.flag); - discard_i_queue(st); - st->ma.layer(st, MDL_ERROR_IND, (void *) 'G'); - st->l2.l2man(st, DL_RELEASE, NULL); + discard_queue(&st->l2.i_queue); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'G'); + if (test_bit(FLG_LAPB, &st->l2.flag)) + st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); + st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); } else { st->l2.rc++; FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9); @@ -1049,8 +1090,10 @@ l2_st6_tout_200(struct FsmInst *fi, int event, void *arg) FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9); } else if (st->l2.rc == st->l2.N200) { FsmChangeState(fi, ST_L2_4); - st->ma.layer(st, MDL_ERROR_IND, (void *) 'H'); - st->l2.l2man(st, DL_RELEASE, NULL); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'H'); + if (test_bit(FLG_LAPB, &st->l2.flag)) + st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); + st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); } else { st->l2.rc++; FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, @@ -1146,14 +1189,14 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) memcpy(skb_put(skb, oskb->len), oskb->data, oskb->len); FreeSkb(oskb); } - st->l2.l2l1(st, PH_PULL_IND, skb); + st->l2.l2l1(st, PH_PULL | INDICATION, skb); test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) { FsmDelTimer(&st->l2.t203, 13); FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 11); } if (skb_queue_len(&l2->i_queue) && cansend(st)) - st->l2.l2l1(st, PH_PULL_REQ, NULL); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } static void @@ -1179,7 +1222,7 @@ l2_got_st8_super(struct FsmInst *fi, int event, void *arg) PollFlag = (skb->data[1] & 0x1) == 0x1; nr = skb->data[1] >> 1; } else { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N'); FreeSkb(skb); establishlink(fi); return; @@ -1189,7 +1232,7 @@ l2_got_st8_super(struct FsmInst *fi, int event, void *arg) PollFlag = (skb->data[0] & 0x10); nr = (skb->data[0] >> 5) & 0x7; } else { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N'); FreeSkb(skb); establishlink(fi); return; @@ -1213,10 +1256,10 @@ l2_got_st8_super(struct FsmInst *fi, int event, void *arg) invoke_retransmission(st, nr); FsmChangeState(fi, ST_L2_7); if (skb_queue_len(&l2->i_queue) && cansend(st)) - st->l2.l2l1(st, PH_PULL_REQ, NULL); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); else if (fi->userint & LC_FLUSH_WAIT) { fi->userint &= ~LC_FLUSH_WAIT; - st->l2.l2man(st, DL_FLUSH, NULL); + st->l2.l2l3(st, DL_FLUSH | INDICATION, NULL); } } } else { @@ -1233,30 +1276,25 @@ l2_got_FRMR(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; struct sk_buff *skb = arg; - char tmp[64]; skb_pull(skb, l2addrsize(&st->l2) + 1); if (test_bit(FLG_MOD128, &st->l2.flag)) { if (skb->len < 5) - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); - else { - sprintf(tmp, "FRMR information %2x %2x %2x %2x %2x", + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N'); + else + l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x %2x %2x", skb->data[0], skb->data[1], skb->data[2], skb->data[3], skb->data[4]); - l2m_debug(&st->l2.l2m, tmp); - } } else { if (skb->len < 3) - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); - else { - sprintf(tmp, "FRMR information %2x %2x %2x", + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N'); + else + l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x", skb->data[0], skb->data[1], skb->data[2]); - l2m_debug(&st->l2.l2m, tmp); - } } if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) || /* I or S */ (IsUA(skb->data, 0) && (fi->state == ST_L2_7))) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'K'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'K'); establishlink(fi); test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); } @@ -1268,14 +1306,14 @@ l2_tei_remove(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - discard_i_queue(st); - discard_ui_queue(st); + discard_queue(&st->l2.i_queue); + discard_queue(&st->l2.ui_queue); st->l2.tei = -1; if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) FsmDelTimer(&st->l2.t200, 18); FsmDelTimer(&st->l2.t203, 19); if (fi->state != ST_L2_4) - st->l2.l2man(st, DL_RELEASE, NULL); + st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); FsmChangeState(fi, ST_L2_1); } @@ -1283,33 +1321,45 @@ static void l2_persistant_da(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; + int rel = DL_RELEASE | INDICATION; + - discard_i_queue(st); - discard_ui_queue(st); + discard_queue(&st->l2.i_queue); + discard_queue(&st->l2.ui_queue); if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) FsmDelTimer(&st->l2.t200, 18); FsmDelTimer(&st->l2.t203, 19); - test_and_clear_bit(FLG_PEND_REL, &st->l2.flag); clear_exception(&st->l2); switch (fi->state) { + case ST_L2_1: + if (!test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag)) + break; case ST_L2_3: - st->l2.l2man(st, DL_RELEASE, NULL); + st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); case ST_L2_2: FsmChangeState(fi, ST_L2_1); break; - case ST_L2_5: case ST_L2_6: + rel = DL_RELEASE | CONFIRM; + case ST_L2_5: + if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag)) + rel = DL_RELEASE | CONFIRM; case ST_L2_7: case ST_L2_8: - st->l2.l2man(st, DL_RELEASE, NULL); + st->l2.l2l3(st, rel, NULL); FsmChangeState(fi, ST_L2_4); break; + case ST_L2_4: + if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag)) + st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); + break; } + test_and_clear_bit(FLG_PEND_REL, &st->l2.flag); + test_and_clear_bit(FLG_L1_ACTIV, &st->l2.flag); } static struct FsmNode L2FnList[] HISAX_INITDATA = { - {ST_L2_1, EV_L2_MDL_NOTEIPROC, l2_no_tei}, {ST_L2_1, EV_L2_DL_ESTABLISH, l2_dl_establish}, {ST_L2_2, EV_L2_DL_ESTABLISH, l2_dl_establish}, {ST_L2_4, EV_L2_DL_ESTABLISH, l2_establish}, @@ -1359,8 +1409,8 @@ static struct FsmNode L2FnList[] HISAX_INITDATA = {ST_L2_4, EV_L2_DM, l2_got_dm}, {ST_L2_5, EV_L2_DM, l2_got_dm}, {ST_L2_6, EV_L2_DM, l2_got_dm}, - {ST_L2_7, EV_L2_DM, l2_mdl_error}, - {ST_L2_8, EV_L2_DM, l2_mdl_error}, + {ST_L2_7, EV_L2_DM, l2_got_dm}, + {ST_L2_8, EV_L2_DM, l2_got_dm}, {ST_L2_1, EV_L2_UI, l2_got_ui}, {ST_L2_2, EV_L2_UI, l2_got_ui}, {ST_L2_3, EV_L2_UI, l2_got_ui}, @@ -1381,6 +1431,7 @@ static struct FsmNode L2FnList[] HISAX_INITDATA = {ST_L2_8, EV_L2_T200, l2_st78_tout_200}, {ST_L2_7, EV_L2_T203, l2_st7_tout_203}, {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue}, + {ST_L2_1, EV_L1_DEACTIVATE, l2_persistant_da}, {ST_L2_2, EV_L1_DEACTIVATE, l2_persistant_da}, {ST_L2_3, EV_L1_DEACTIVATE, l2_persistant_da}, {ST_L2_4, EV_L1_DEACTIVATE, l2_persistant_da}, @@ -1400,19 +1451,19 @@ isdnl2_l1l2(struct PStack *st, int pr, void *arg) int ret = 1, len; switch (pr) { - case (PH_DATA_IND): + case (PH_DATA | INDICATION): datap = skb->data; len = l2addrsize(&st->l2); if (skb->len > len) datap += len; else { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N'); FreeSkb(skb); return; } if (!(*datap & 1)) /* I-Frame */ ret = FsmEvent(&st->l2.l2m, EV_L2_I, skb); - else if ((*datap & 3) == 1) /* S-Frame */ + else if (IsSFrame(datap, test_bit(FLG_MOD128, &st->l2.flag))) ret = FsmEvent(&st->l2.l2m, EV_L2_SUPER, skb); else if (IsUI(datap, test_bit(FLG_MOD128, &st->l2.flag))) ret = FsmEvent(&st->l2.l2m, EV_L2_UI, skb); @@ -1427,23 +1478,39 @@ isdnl2_l1l2(struct PStack *st, int pr, void *arg) else if (IsFRMR(datap, test_bit(FLG_MOD128, &st->l2.flag))) ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, skb); else { - ret = 0; - st->ma.layer(st, MDL_ERROR_IND, (void *) 'L'); - FreeSkb(skb); + ret = 1; + if ((st->l2.l2m.state == ST_L2_7) || + (st->l2.l2m.state == ST_L2_8)) + establishlink(&st->l2.l2m); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'L'); } if (ret) { FreeSkb(skb); } break; - case (PH_PULL_CNF): + case (PH_PULL | CONFIRM): FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg); break; - case (PH_PAUSE_IND): + case (PH_PAUSE | INDICATION): test_and_set_bit(FLG_DCHAN_BUSY, &st->l2.flag); break; - case (PH_PAUSE_CNF): + case (PH_PAUSE | CONFIRM): test_and_clear_bit(FLG_DCHAN_BUSY, &st->l2.flag); break; + case (PH_ACTIVATE | CONFIRM): + case (PH_ACTIVATE | INDICATION): + test_and_set_bit(FLG_L1_ACTIV, &st->l2.flag); + if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag)) + FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg); + break; + case (PH_DEACTIVATE | INDICATION): + case (PH_DEACTIVATE | CONFIRM): + test_and_clear_bit(FLG_L1_ACTIV, &st->l2.flag); + FsmEvent(&st->l2.l2m, EV_L1_DEACTIVATE, arg); + break; + default: + l2m_debug(&st->l2.l2m, "l2 unknown pr %04x", pr); + break; } } @@ -1451,45 +1518,46 @@ static void isdnl2_l3l2(struct PStack *st, int pr, void *arg) { switch (pr) { - case (DL_DATA): + case (DL_DATA | REQUEST): if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg)) { dev_kfree_skb((struct sk_buff *) arg); } break; - case (DL_UNIT_DATA): + case (DL_UNIT_DATA | REQUEST): if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg)) { dev_kfree_skb((struct sk_buff *) arg); } break; - } -} - -static void -isdnl2_manl2(struct PStack *st, int pr, void *arg) -{ - switch (pr) { - case (DL_ESTABLISH): - FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg); + case (DL_ESTABLISH | REQUEST): + if (test_bit(FLG_L1_ACTIV, &st->l2.flag)) { + if (test_bit(FLG_LAPD, &st->l2.flag) || + test_bit(FLG_ORIG, &st->l2.flag)) { + FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg); + } + } else { + if (test_bit(FLG_LAPD, &st->l2.flag) || + test_bit(FLG_ORIG, &st->l2.flag)) { + test_and_set_bit(FLG_ESTAB_PEND, &st->l2.flag); + } + st->l2.l2l1(st, PH_ACTIVATE, NULL); + } break; - case (DL_RELEASE): + case (DL_RELEASE | REQUEST): + if (test_bit(FLG_LAPB, &st->l2.flag)) { + st->l2.l2l1(st, PH_DEACTIVATE, NULL); + } FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE, arg); break; - case (MDL_NOTEIPROC): - FsmEvent(&st->l2.l2m, EV_L2_MDL_NOTEIPROC, NULL); - break; - case (DL_FLUSH): + case (DL_FLUSH | REQUEST): (&st->l2.l2m)->userint |= LC_FLUSH_WAIT; break; - case (PH_DEACTIVATE_IND): - FsmEvent(&st->l2.l2m, EV_L1_DEACTIVATE, arg); - break; - case (MDL_ASSIGN_REQ): + case (MDL_ASSIGN | REQUEST): FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg); break; - case (MDL_REMOVE_REQ): + case (MDL_REMOVE | REQUEST): FsmEvent(&st->l2.l2m, EV_L2_MDL_REMOVE, arg); break; - case (MDL_ERROR_REQ): + case (MDL_ERROR | RESPONSE): FsmEvent(&st->l2.l2m, EV_L2_MDL_ERROR, arg); break; } @@ -1500,20 +1568,20 @@ releasestack_isdnl2(struct PStack *st) { FsmDelTimer(&st->l2.t200, 15); FsmDelTimer(&st->l2.t203, 16); - discard_i_queue(st); - discard_ui_queue(st); + discard_queue(&st->l2.i_queue); + discard_queue(&st->l2.ui_queue); ReleaseWin(&st->l2); } static void -l2m_debug(struct FsmInst *fi, char *s) +l2m_debug(struct FsmInst *fi, char *fmt, ...) { + va_list args; struct PStack *st = fi->userdata; - char tm[32], str[256]; - jiftime(tm, jiffies); - sprintf(str, "%s %s %s\n", tm, st->l2.debug_id, s); - HiSax_putstatus(st->l1.hardware, str); + va_start(args, fmt); + VHiSax_putstatus(st->l1.hardware, st->l2.debug_id, fmt, args); + va_end(args); } void @@ -1521,7 +1589,6 @@ setstack_isdnl2(struct PStack *st, char *debug_id) { st->l1.l1l2 = isdnl2_l1l2; st->l3.l3l2 = isdnl2_l3l2; - st->ma.manl2 = isdnl2_manl2; skb_queue_head_init(&st->l2.i_queue); skb_queue_head_init(&st->l2.ui_queue); @@ -1529,6 +1596,9 @@ setstack_isdnl2(struct PStack *st, char *debug_id) st->l2.debug = 0; st->l2.l2m.fsm = &l2fsm; + if (test_bit(FLG_LAPB, &st->l2.flag)) + st->l2.l2m.state = ST_L2_4; + else st->l2.l2m.state = ST_L2_1; st->l2.l2m.debug = 0; st->l2.l2m.userdata = st; @@ -1540,9 +1610,27 @@ setstack_isdnl2(struct PStack *st, char *debug_id) FsmInitTimer(&st->l2.l2m, &st->l2.t203); } +static void +transl2_l3l2(struct PStack *st, int pr, void *arg) +{ + switch (pr) { + case (DL_DATA | REQUEST): + case (DL_UNIT_DATA | REQUEST): + st->l2.l2l1(st, PH_DATA | REQUEST, arg); + break; + case (DL_ESTABLISH | REQUEST): + st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL); + break; + case (DL_RELEASE | REQUEST): + st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); + break; + } +} + void setstack_transl2(struct PStack *st) { + st->l3.l3l2 = transl2_l3l2; } void diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c index 026d8eb76..4511251e7 100644 --- a/drivers/isdn/hisax/isdnl3.c +++ b/drivers/isdn/hisax/isdnl3.c @@ -1,12 +1,27 @@ -/* $Id: isdnl3.c,v 2.5 1998/02/12 23:07:52 keil Exp $ +/* $Id: isdnl3.c,v 2.8 1998/11/15 23:55:04 keil Exp $ - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/HiSax.cert + * * Thanks to Jan den Ouden * Fritz Elfert * * $Log: isdnl3.c,v $ + * Revision 2.8 1998/11/15 23:55:04 keil + * changes from 2.0 + * + * Revision 2.7 1998/05/25 14:10:15 keil + * HiSax 3.0 + * X.75 and leased are working again. + * + * Revision 2.6 1998/05/25 12:58:11 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * * Revision 2.5 1998/02/12 23:07:52 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -47,7 +62,60 @@ #include "isdnl3.h" #include <linux/config.h> -const char *l3_revision = "$Revision: 2.5 $"; +const char *l3_revision = "$Revision: 2.8 $"; + +static +struct Fsm l3fsm = +{NULL, 0, 0, NULL, NULL}; + +enum { + ST_L3_LC_REL, + ST_L3_LC_ESTAB_WAIT, + ST_L3_LC_REL_WAIT, + ST_L3_LC_ESTAB, +}; + +#define L3_STATE_COUNT (ST_L3_LC_ESTAB+1) + +static char *strL3State[] = +{ + "ST_L3_LC_REL", + "ST_L3_LC_ESTAB_WAIT", + "ST_L3_LC_REL_WAIT", + "ST_L3_LC_ESTAB", +}; + +enum { + EV_ESTABLISH_REQ, + EV_ESTABLISH_IND, + EV_ESTABLISH_CNF, + EV_RELEASE_REQ, + EV_RELEASE_CNF, + EV_RELEASE_IND, +}; + +#define L3_EVENT_COUNT (EV_RELEASE_IND+1) + +static char *strL3Event[] = +{ + "EV_ESTABLISH_REQ", + "EV_ESTABLISH_IND", + "EV_ESTABLISH_CNF", + "EV_RELEASE_REQ", + "EV_RELEASE_CNF", + "EV_RELEASE_IND", +}; + +static void +l3m_debug(struct FsmInst *fi, char *fmt, ...) +{ + va_list args; + struct PStack *st = fi->userdata; + + va_start(args, fmt); + VHiSax_putstatus(st->l1.hardware, st->l3.debug_id, fmt, args); + va_end(args); +} u_char * findie(u_char * p, int size, u_char ie, int wanted_set) @@ -115,25 +183,11 @@ newcallref(void) } void -l3_debug(struct PStack *st, char *s) -{ - char str[256], tm[32]; - - jiftime(tm, jiffies); - sprintf(str, "%s l3 %s\n", tm, s); - HiSax_putstatus(st->l1.hardware, str); -} - -void newl3state(struct l3_process *pc, int state) { - char tmp[80]; - - if (pc->debug & L3_DEB_STATE) { - sprintf(tmp, "newstate cr %d %d --> %d", pc->callref, + if (pc->debug & L3_DEB_STATE) + l3_debug(pc->st, "newstate cr %d %d --> %d", pc->callref, pc->state, state); - l3_debug(pc->st, tmp); - } pc->state = state; } @@ -197,7 +251,7 @@ no_l3_proto(struct PStack *st, int pr, void *arg) { struct sk_buff *skb = arg; - HiSax_putstatus(st->l1.hardware, "L3 no D protocol\n"); + HiSax_putstatus(st->l1.hardware, "L3", "no D protocol"); if (skb) { dev_kfree_skb(skb); } @@ -277,16 +331,25 @@ release_l3_process(struct l3_process *p) pp = np; np = np->next; } - printk(KERN_ERR "HiSax internal L3 error CR not in list\n"); + printk(KERN_ERR "HiSax internal L3 error CR(%d) not in list\n", p->callref); + l3_debug(p->st, "HiSax internal L3 error CR(%d) not in list", p->callref); }; void -setstack_isdnl3(struct PStack *st, struct Channel *chanp) +setstack_l3dc(struct PStack *st, struct Channel *chanp) { char tmp[64]; st->l3.proc = NULL; st->l3.global = NULL; + skb_queue_head_init(&st->l3.squeue); + st->l3.l3m.fsm = &l3fsm; + st->l3.l3m.state = ST_L3_LC_REL; + st->l3.l3m.debug = 1; + st->l3.l3m.userdata = st; + st->l3.l3m.userint = 0; + st->l3.l3m.printdebug = l3m_debug; + strcpy(st->l3.debug_id, "L3DC "); #ifdef CONFIG_HISAX_EURO if (st->protocol == ISDN_PTYPE_EURO) { @@ -321,6 +384,11 @@ setstack_isdnl3(struct PStack *st, struct Channel *chanp) } void +isdnl3_trans(struct PStack *st, int pr, void *arg) { + st->l3.l3l2(st, pr, arg); +} + +void releasestack_isdnl3(struct PStack *st) { while (st->l3.proc) @@ -330,4 +398,136 @@ releasestack_isdnl3(struct PStack *st) kfree(st->l3.global); st->l3.global = NULL; } + discard_queue(&st->l3.squeue); +} + +void +setstack_l3bc(struct PStack *st, struct Channel *chanp) +{ + + st->l3.proc = NULL; + st->l3.global = NULL; + skb_queue_head_init(&st->l3.squeue); + st->l3.l3m.fsm = &l3fsm; + st->l3.l3m.state = ST_L3_LC_REL; + st->l3.l3m.debug = 1; + st->l3.l3m.userdata = st; + st->l3.l3m.userint = 0; + st->l3.l3m.printdebug = l3m_debug; + strcpy(st->l3.debug_id, "L3BC "); + st->lli.l4l3 = isdnl3_trans; +} + +static void +lc_activate(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT); + st->l3.l3l2(st, DL_ESTABLISH | REQUEST, NULL); +} + +static void +lc_connect(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct sk_buff *skb = arg; + + FsmChangeState(fi, ST_L3_LC_ESTAB); + while ((skb = skb_dequeue(&st->l3.squeue))) { + st->l3.l3l2(st, DL_DATA | REQUEST, skb); + } + st->l3.l3l4(st, DL_ESTABLISH | INDICATION, NULL); +} + +static void +lc_release_req(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + if (fi->state == ST_L3_LC_ESTAB_WAIT) + FsmChangeState(fi, ST_L3_LC_REL); + else + FsmChangeState(fi, ST_L3_LC_REL_WAIT); + st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL); +} + +static void +lc_release_ind(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L3_LC_REL); + discard_queue(&st->l3.squeue); + st->l3.l3l4(st, DL_RELEASE | INDICATION, NULL); +} + +/* *INDENT-OFF* */ +static struct FsmNode L3FnList[] HISAX_INITDATA = +{ + {ST_L3_LC_REL, EV_ESTABLISH_REQ, lc_activate}, + {ST_L3_LC_REL, EV_ESTABLISH_IND, lc_connect}, + {ST_L3_LC_REL, EV_ESTABLISH_CNF, lc_connect}, + {ST_L3_LC_ESTAB_WAIT, EV_ESTABLISH_CNF, lc_connect}, + {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_REQ, lc_release_req}, + {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_IND, lc_release_ind}, + {ST_L3_LC_ESTAB, EV_RELEASE_IND, lc_release_ind}, + {ST_L3_LC_ESTAB, EV_RELEASE_REQ, lc_release_req}, + {ST_L3_LC_REL_WAIT, EV_RELEASE_CNF, lc_release_ind}, + {ST_L3_LC_REL_WAIT, EV_ESTABLISH_REQ, lc_activate}, +}; +/* *INDENT-ON* */ + +#define L3_FN_COUNT (sizeof(L3FnList)/sizeof(struct FsmNode)) + +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) { + st->l3.l3l2(st, pr, arg); + } else { + struct sk_buff *skb = arg; + + skb_queue_head(&st->l3.squeue, skb); + FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL); + } + break; + case (DL_ESTABLISH | REQUEST): + FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL); + break; + case (DL_ESTABLISH | CONFIRM): + FsmEvent(&st->l3.l3m, EV_ESTABLISH_CNF, NULL); + break; + case (DL_ESTABLISH | INDICATION): + FsmEvent(&st->l3.l3m, EV_ESTABLISH_IND, NULL); + break; + case (DL_RELEASE | INDICATION): + FsmEvent(&st->l3.l3m, EV_RELEASE_IND, NULL); + break; + case (DL_RELEASE | CONFIRM): + FsmEvent(&st->l3.l3m, EV_RELEASE_CNF, NULL); + break; + case (DL_RELEASE | REQUEST): + FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL); + break; + } +} + +HISAX_INITFUNC(void +Isdnl3New(void)) +{ + l3fsm.state_count = L3_STATE_COUNT; + l3fsm.event_count = L3_EVENT_COUNT; + l3fsm.strEvent = strL3Event; + l3fsm.strState = strL3State; + FsmNew(&l3fsm, L3FnList, L3_FN_COUNT); +} + +void +Isdnl3Free(void) +{ + FsmFree(&l3fsm); } diff --git a/drivers/isdn/hisax/isdnl3.h b/drivers/isdn/hisax/isdnl3.h index 2ff582b4a..a0e518f8c 100644 --- a/drivers/isdn/hisax/isdnl3.h +++ b/drivers/isdn/hisax/isdnl3.h @@ -1,6 +1,17 @@ -/* $Id: isdnl3.h,v 2.0 1997/07/27 21:15:42 keil Exp $ +/* $Id: isdnl3.h,v 2.3 1998/11/15 23:55:06 keil Exp $ * $Log: isdnl3.h,v $ + * Revision 2.3 1998/11/15 23:55:06 keil + * changes from 2.0 + * + * Revision 2.2 1998/05/25 14:10:17 keil + * HiSax 3.0 + * X.75 and leased are working again. + * + * Revision 2.1 1998/05/25 12:58:13 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * * Revision 2.0 1997/07/27 21:15:42 keil * New Callref based layer3 * @@ -31,11 +42,12 @@ struct stateentry { int state; - u_char primitive; + int primitive; void (*rout) (struct l3_process *, u_char, void *); }; -extern void l3_debug(struct PStack *st, char *s); +#define l3_debug(st, fmt, args...) HiSax_putstatus(st->l1.hardware, "l3 ", fmt, ## args) + extern void newl3state(struct l3_process *pc, int state); extern void L3InitTimer(struct l3_process *pc, struct L3Timer *t); extern void L3DelTimer(struct L3Timer *t); @@ -45,3 +57,4 @@ extern struct sk_buff *l3_alloc_skb(int len); extern struct l3_process *new_l3_process(struct PStack *st, int cr); extern void release_l3_process(struct l3_process *p); extern struct l3_process *getl3proc(struct PStack *st, int cr); +extern void l3_msg(struct PStack *st, int pr, void *arg); diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c index 0c075546b..009783b6d 100644 --- a/drivers/isdn/hisax/ix1_micro.c +++ b/drivers/isdn/hisax/ix1_micro.c @@ -1,4 +1,4 @@ -/* $Id: ix1_micro.c,v 2.6 1998/02/11 17:28:09 keil Exp $ +/* $Id: ix1_micro.c,v 2.7 1998/04/15 16:44:31 keil Exp $ * ix1_micro.c low level stuff for ITK ix1-micro Rev.2 isdn cards * derived from the original file teles3.c from Karsten Keil @@ -11,6 +11,9 @@ * Beat Doebeli * * $Log: ix1_micro.c,v $ + * Revision 2.7 1998/04/15 16:44:31 keil + * new init code + * * Revision 2.6 1998/02/11 17:28:09 keil * Niccy PnP/PCI support * @@ -81,7 +84,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *ix1_revision = "$Revision: 2.6 $"; +const char *ix1_revision = "$Revision: 2.7 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -277,10 +280,7 @@ ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(request_irq(cs->irq, &ix1micro_interrupt, I4L_IRQ_FLAG, "HiSax", cs)); case CARD_INIT: - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + inithscxisac(cs, 3); return(0); case CARD_TEST: return(0); diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c index d60a5da66..db6ceca76 100644 --- a/drivers/isdn/hisax/l3_1tr6.c +++ b/drivers/isdn/hisax/l3_1tr6.c @@ -1,11 +1,29 @@ -/* $Id: l3_1tr6.c,v 2.4 1998/02/12 23:07:57 keil Exp $ +/* $Id: l3_1tr6.c,v 2.8 1998/11/15 23:55:08 keil Exp $ * German 1TR6 D-channel protocol * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) + * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/HiSax.cert * * * $Log: l3_1tr6.c,v $ + * Revision 2.8 1998/11/15 23:55:08 keil + * changes from 2.0 + * + * Revision 2.7 1998/08/13 23:36:45 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 2.6 1998/05/25 14:10:18 keil + * HiSax 3.0 + * X.75 and leased are working again. + * + * Revision 2.5 1998/05/25 12:58:14 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * * Revision 2.4 1998/02/12 23:07:57 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -38,7 +56,7 @@ #include <linux/ctype.h> extern char *HiSax_getrev(const char *revision); -const char *l3_1tr6_revision = "$Revision: 2.4 $"; +const char *l3_1tr6_revision = "$Revision: 2.8 $"; #define MsgHead(ptr, cref, mty, dis) \ *ptr++ = dis; \ @@ -56,66 +74,34 @@ l3_1TR6_message(struct l3_process *pc, u_char mt, u_char pd) return; p = skb_put(skb, 4); MsgHead(p, pc->callref, mt, pd); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); } -static int -l31tr6_check_messagetype_validity(int mt, int pd) { -/* verify if a message type exists */ - - if (pd == PROTO_DIS_N0) - switch(mt) { - case MT_N0_REG_IND: - case MT_N0_CANC_IND: - case MT_N0_FAC_STA: - case MT_N0_STA_ACK: - case MT_N0_STA_REJ: - case MT_N0_FAC_INF: - case MT_N0_INF_ACK: - case MT_N0_INF_REJ: - case MT_N0_CLOSE: - case MT_N0_CLO_ACK: - return(1); - default: - return(0); - } - else if (pd == PROTO_DIS_N1) - switch(mt) { - case MT_N1_ESC: - case MT_N1_ALERT: - case MT_N1_CALL_SENT: - case MT_N1_CONN: - case MT_N1_CONN_ACK: - case MT_N1_SETUP: - case MT_N1_SETUP_ACK: - case MT_N1_RES: - case MT_N1_RES_ACK: - case MT_N1_RES_REJ: - case MT_N1_SUSP: - case MT_N1_SUSP_ACK: - case MT_N1_SUSP_REJ: - case MT_N1_USER_INFO: - case MT_N1_DET: - case MT_N1_DISC: - case MT_N1_REL: - case MT_N1_REL_ACK: - case MT_N1_CANC_ACK: - case MT_N1_CANC_REJ: - case MT_N1_CON_CON: - case MT_N1_FAC: - case MT_N1_FAC_ACK: - case MT_N1_FAC_CAN: - case MT_N1_FAC_REG: - case MT_N1_FAC_REJ: - case MT_N1_INFO: - case MT_N1_REG_ACK: - case MT_N1_REG_REJ: - case MT_N1_STAT: - return (1); - default: - return(0); - } - return(0); +static void +l3_1tr6_release_req(struct l3_process *pc, u_char pr, void *arg) +{ + StopAllL3Timer(pc); + newl3state(pc, 19); + l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1); + L3AddTimer(&pc->timer, T308, CC_T308_1); +} + +static void +l3_1tr6_invalid(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + + dev_kfree_skb(skb); + l3_1tr6_release_req(pc, 0, NULL); +} + +static void +l3_1tr6_error(struct l3_process *pc, u_char *msg, struct sk_buff *skb) +{ + dev_kfree_skb(skb); + if (pc->st->l3.debug & L3_DEB_WARN) + l3_debug(pc->st, msg); + l3_1tr6_release_req(pc, 0, NULL); } static void @@ -204,7 +190,7 @@ l3_1tr6_setup_req(struct l3_process *pc, u_char pr, void *arg) L3DelTimer(&pc->timer); L3AddTimer(&pc->timer, T303, CC_T303); newl3state(pc, 1); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); } static void @@ -220,17 +206,29 @@ l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg) /* Channel Identification */ p = skb->data; if ((p = findie(p, skb->len, WE0_chanID, 0))) { - pc->para.bchannel = p[2] & 0x3; - bcfound++; - } else if (pc->st->l3.debug & L3_DEB_WARN) - l3_debug(pc->st, "setup without bchannel"); + if (p[1] != 1) { + l3_1tr6_error(pc, "setup wrong chanID len", skb); + return; + } + if ((p[2] & 0xf4) != 0x80) { + l3_1tr6_error(pc, "setup wrong WE0_chanID", skb); + return; + } + if ((pc->para.bchannel = p[2] & 0x3)) + bcfound++; + } else { + l3_1tr6_error(pc, "missing setup chanID", skb); + return; + } p = skb->data; if ((p = findie(p, skb->len, WE6_serviceInd, 6))) { pc->para.setup.si1 = p[2]; pc->para.setup.si2 = p[3]; - } else if (pc->st->l3.debug & L3_DEB_WARN) - l3_debug(pc->st, "setup without service indicator"); + } else { + l3_1tr6_error(pc, "missing setup SI", skb); + return; + } p = skb->data; if ((p = findie(p, skb->len, WE0_destAddr, 0))) @@ -261,7 +259,7 @@ l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg) l3_debug(pc->st, tmp); } newl3state(pc, 6); - pc->st->l3.l3l4(pc, CC_SETUP_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); } else release_l3_process(pc); } @@ -276,12 +274,22 @@ l3_1tr6_setup_ack(struct l3_process *pc, u_char pr, void *arg) p = skb->data; newl3state(pc, 2); if ((p = findie(p, skb->len, WE0_chanID, 0))) { + if (p[1] != 1) { + l3_1tr6_error(pc, "setup_ack wrong chanID len", skb); + return; + } + if ((p[2] & 0xf4) != 0x80) { + l3_1tr6_error(pc, "setup_ack wrong WE0_chanID", skb); + return; + } pc->para.bchannel = p[2] & 0x3; - } else if (pc->st->l3.debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer without bchannel"); + } else { + l3_1tr6_error(pc, "missing setup_ack WE0_chanID", skb); + return; + } dev_kfree_skb(skb); L3AddTimer(&pc->timer, T304, CC_T304); - pc->st->l3.l3l4(pc, CC_MORE_INFO, NULL); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); } static void @@ -293,13 +301,27 @@ l3_1tr6_call_sent(struct l3_process *pc, u_char pr, void *arg) L3DelTimer(&pc->timer); p = skb->data; if ((p = findie(p, skb->len, WE0_chanID, 0))) { + if (p[1] != 1) { + l3_1tr6_error(pc, "call sent wrong chanID len", skb); + return; + } + if ((p[2] & 0xf4) != 0x80) { + l3_1tr6_error(pc, "call sent wrong WE0_chanID", skb); + return; + } + if ((pc->state == 2) && (pc->para.bchannel != (p[2] & 0x3))) { + l3_1tr6_error(pc, "call sent wrong chanID value", skb); + return; + } pc->para.bchannel = p[2] & 0x3; - } else if (pc->st->l3.debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer without bchannel"); + } else { + l3_1tr6_error(pc, "missing call sent WE0_chanID", skb); + return; + } dev_kfree_skb(skb); L3AddTimer(&pc->timer, T310, CC_T310); newl3state(pc, 3); - pc->st->l3.l3l4(pc, CC_PROCEEDING_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc); } static void @@ -310,7 +332,7 @@ l3_1tr6_alert(struct l3_process *pc, u_char pr, void *arg) dev_kfree_skb(skb); L3DelTimer(&pc->timer); /* T304 */ newl3state(pc, 4); - pc->st->l3.l3l4(pc, CC_ALERTING_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc); } static void @@ -330,7 +352,7 @@ l3_1tr6_info(struct l3_process *pc, u_char pr, void *arg) } if (tmpcharge > pc->para.chargeinfo) { pc->para.chargeinfo = tmpcharge; - pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL); + pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc); } if (pc->st->l3.debug & L3_DEB_CHARGE) { sprintf(tmp, "charging info %d", pc->para.chargeinfo); @@ -356,10 +378,14 @@ l3_1tr6_connect(struct l3_process *pc, u_char pr, void *arg) struct sk_buff *skb = arg; L3DelTimer(&pc->timer); /* T310 */ + if (!findie(skb->data, skb->len, WE6_date, 6)) { + l3_1tr6_error(pc, "missing connect date", skb); + return; + } newl3state(pc, 10); dev_kfree_skb(skb); pc->para.chargeinfo = 0; - pc->st->l3.l3l4(pc, CC_SETUP_CNF, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc); } static void @@ -380,13 +406,16 @@ l3_1tr6_rel(struct l3_process *pc, u_char pr, void *arg) pc->para.cause = 0; pc->para.loc = 0; } - } else + } else { pc->para.cause = -1; + l3_1tr6_error(pc, "missing REL cause", skb); + return; + } dev_kfree_skb(skb); StopAllL3Timer(pc); newl3state(pc, 0); l3_1TR6_message(pc, MT_N1_REL_ACK, PROTO_DIS_N1); - pc->st->l3.l3l4(pc, CC_RELEASE_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); release_l3_process(pc); } @@ -399,7 +428,7 @@ l3_1tr6_rel_ack(struct l3_process *pc, u_char pr, void *arg) StopAllL3Timer(pc); newl3state(pc, 0); pc->para.cause = -1; - pc->st->l3.l3l4(pc, CC_RELEASE_CNF, NULL); + pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); release_l3_process(pc); } @@ -421,7 +450,7 @@ l3_1tr6_disc(struct l3_process *pc, u_char pr, void *arg) } if (tmpcharge > pc->para.chargeinfo) { pc->para.chargeinfo = tmpcharge; - pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL); + pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc); } if (pc->st->l3.debug & L3_DEB_CHARGE) { sprintf(tmp, "charging info %d", pc->para.chargeinfo); @@ -448,9 +477,13 @@ l3_1tr6_disc(struct l3_process *pc, u_char pr, void *arg) l3_debug(pc->st, "cause not found"); pc->para.cause = -1; } + if (!findie(skb->data, skb->len, WE6_date, 6)) { + l3_1tr6_error(pc, "missing connack date", skb); + return; + } dev_kfree_skb(skb); newl3state(pc, 12); - pc->st->l3.l3l4(pc, CC_DISCONNECT_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc); } @@ -459,11 +492,15 @@ l3_1tr6_connect_ack(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; + if (!findie(skb->data, skb->len, WE6_date, 6)) { + l3_1tr6_error(pc, "missing connack date", skb); + return; + } dev_kfree_skb(skb); newl3state(pc, 10); pc->para.chargeinfo = 0; L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc, CC_SETUP_COMPLETE_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc); } static void @@ -502,7 +539,7 @@ l3_1tr6_setup_rsp(struct l3_process *pc, u_char pr, void *arg) if (!(skb = l3_alloc_skb(l))) return; memcpy(skb_put(skb, l), tmp, l); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); L3DelTimer(&pc->timer); L3AddTimer(&pc->timer, T313, CC_T313); } @@ -545,20 +582,11 @@ l3_1tr6_disconnect_req(struct l3_process *pc, u_char pr, void *arg) if (!(skb = l3_alloc_skb(l))) return; memcpy(skb_put(skb, l), tmp, l); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); L3AddTimer(&pc->timer, T305, CC_T305); } static void -l3_1tr6_release_req(struct l3_process *pc, u_char pr, void *arg) -{ - StopAllL3Timer(pc); - newl3state(pc, 19); - l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1); - L3AddTimer(&pc->timer, T308, CC_T308_1); -} - -static void l3_1tr6_t303(struct l3_process *pc, u_char pr, void *arg) { if (pc->N303 > 0) { @@ -567,8 +595,8 @@ l3_1tr6_t303(struct l3_process *pc, u_char pr, void *arg) l3_1tr6_setup_req(pc, pr, arg); } else { L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc, CC_NOSETUP_RSP_ERR, NULL); - release_l3_process(pc); + pc->para.cause = 0; + l3_1tr6_disconnect_req(pc, 0, NULL); } } @@ -578,7 +606,7 @@ l3_1tr6_t304(struct l3_process *pc, u_char pr, void *arg) L3DelTimer(&pc->timer); pc->para.cause = 0xE6; l3_1tr6_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } static void @@ -613,7 +641,7 @@ l3_1tr6_t305(struct l3_process *pc, u_char pr, void *arg) if (!(skb = l3_alloc_skb(l))) return; memcpy(skb_put(skb, l), tmp, l); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); L3AddTimer(&pc->timer, T308, CC_T308_1); } @@ -623,7 +651,7 @@ l3_1tr6_t310(struct l3_process *pc, u_char pr, void *arg) L3DelTimer(&pc->timer); pc->para.cause = 0xE6; l3_1tr6_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } static void @@ -632,7 +660,7 @@ l3_1tr6_t313(struct l3_process *pc, u_char pr, void *arg) L3DelTimer(&pc->timer); pc->para.cause = 0xE6; l3_1tr6_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc, CC_CONNECT_ERR, NULL); + pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); } static void @@ -648,29 +676,29 @@ static void l3_1tr6_t308_2(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc, CC_RELEASE_ERR, NULL); + pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); release_l3_process(pc); } /* *INDENT-OFF* */ static struct stateentry downstl[] = { {SBIT(0), - CC_SETUP_REQ, l3_1tr6_setup_req}, + CC_SETUP | REQUEST, l3_1tr6_setup_req}, {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(10), - CC_DISCONNECT_REQ, l3_1tr6_disconnect_req}, + CC_DISCONNECT | REQUEST, l3_1tr6_disconnect_req}, {SBIT(12), - CC_RELEASE_REQ, l3_1tr6_release_req}, + CC_RELEASE | REQUEST, l3_1tr6_release_req}, {ALL_STATES, - CC_DLRL, l3_1tr6_reset}, + CC_DLRL | REQUEST, l3_1tr6_reset}, {SBIT(6), - CC_IGNORE, l3_1tr6_reset}, + CC_IGNORE | REQUEST, l3_1tr6_reset}, {SBIT(6), - CC_REJECT_REQ, l3_1tr6_disconnect_req}, + CC_REJECT | REQUEST, l3_1tr6_disconnect_req}, {SBIT(6), - CC_ALERTING_REQ, l3_1tr6_alert_req}, + CC_ALERTING | REQUEST, l3_1tr6_alert_req}, {SBIT(6) | SBIT(7), - CC_SETUP_RSP, l3_1tr6_setup_rsp}, + CC_SETUP | RESPONSE, l3_1tr6_setup_rsp}, {SBIT(1), CC_T303, l3_1tr6_t303}, {SBIT(2), @@ -687,12 +715,14 @@ static struct stateentry downstl[] = CC_T308_2, l3_1tr6_t308_2}, }; -static int downstl_len = sizeof(downstl) / -sizeof(struct stateentry); +#define DOWNSTL_LEN \ + (sizeof(downstl) / sizeof(struct stateentry)) static struct stateentry datastln1[] = { {SBIT(0), + MT_N1_INVALID, l3_1tr6_invalid}, + {SBIT(0), MT_N1_SETUP, l3_1tr6_setup}, {SBIT(1), MT_N1_SETUP_ACK, l3_1tr6_setup_ack}, @@ -711,18 +741,20 @@ static struct stateentry datastln1[] = {SBIT(10), MT_N1_INFO, l3_1tr6_info}, {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(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17), MT_N1_REL, l3_1tr6_rel}, {SBIT(19), + MT_N1_REL, l3_1tr6_rel_ack}, + {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | + SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17), + MT_N1_REL_ACK, l3_1tr6_invalid}, + {SBIT(19), MT_N1_REL_ACK, l3_1tr6_rel_ack} }; /* *INDENT-ON* */ - - - -static int datastln1_len = sizeof(datastln1) / -sizeof(struct stateentry); +#define DATASTLN1_LEN \ + (sizeof(datastln1) / sizeof(struct stateentry)) static void up1tr6(struct PStack *st, int pr, void *arg) @@ -732,9 +764,21 @@ up1tr6(struct PStack *st, int pr, void *arg) struct sk_buff *skb = arg; char tmp[80]; + switch (pr) { + case (DL_DATA | INDICATION): + case (DL_UNIT_DATA | INDICATION): + break; + case (DL_ESTABLISH | CONFIRM): + case (DL_ESTABLISH | INDICATION): + case (DL_RELEASE | INDICATION): + case (DL_RELEASE | CONFIRM): + l3_msg(st, pr, arg); + return; + break; + } if (skb->len < 4) { if (st->l3.debug & L3_DEB_PROTERR) { - sprintf(tmp, "up1tr6 len only %d", skb->len); + sprintf(tmp, "up1tr6 len only %ld", skb->len); l3_debug(st, tmp); } dev_kfree_skb(skb); @@ -742,8 +786,8 @@ up1tr6(struct PStack *st, int pr, void *arg) } if ((skb->data[0] & 0xfe) != PROTO_DIS_N0) { if (st->l3.debug & L3_DEB_PROTERR) { - sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %d", - (pr == DL_DATA) ? " " : "(broadcast) ", + sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %ld", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", skb->data[0], skb->len); l3_debug(st, tmp); } @@ -764,12 +808,33 @@ up1tr6(struct PStack *st, int pr, void *arg) dev_kfree_skb(skb); if (st->l3.debug & L3_DEB_STATE) { sprintf(tmp, "up1tr6%s N0 mt %x unhandled", - (pr == DL_DATA) ? " " : "(broadcast) ", mt); + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", mt); l3_debug(st, tmp); } } else if (skb->data[0] == PROTO_DIS_N1) { if (!(proc = getl3proc(st, cr))) { - if ((mt == MT_N1_SETUP) && (cr < 128)) { + if (mt == MT_N1_SETUP) { + if (cr < 128) { + if (!(proc = new_l3_process(st, cr))) { + if (st->l3.debug & L3_DEB_PROTERR) { + sprintf(tmp, "up1tr6 no roc mem"); + l3_debug(st, tmp); + } + dev_kfree_skb(skb); + return; + } + } else { + dev_kfree_skb(skb); + return; + } + } else if ((mt == MT_N1_REL) || (mt == MT_N1_REL_ACK) || + (mt == MT_N1_CANC_ACK) || (mt == MT_N1_CANC_REJ) || + (mt == MT_N1_REG_ACK) || (mt == MT_N1_REG_REJ) || + (mt == MT_N1_SUSP_ACK) || (mt == MT_N1_RES_REJ) || + (mt == MT_N1_INFO)) { + dev_kfree_skb(skb); + return; + } else { if (!(proc = new_l3_process(st, cr))) { if (st->l3.debug & L3_DEB_PROTERR) { sprintf(tmp, "up1tr6 no roc mem"); @@ -778,20 +843,18 @@ up1tr6(struct PStack *st, int pr, void *arg) dev_kfree_skb(skb); return; } - } else { - dev_kfree_skb(skb); - return; + mt = MT_N1_INVALID; } } - for (i = 0; i < datastln1_len; i++) + for (i = 0; i < DATASTLN1_LEN; i++) if ((mt == datastln1[i].primitive) && ((1 << proc->state) & datastln1[i].state)) break; - if (i == datastln1_len) { + if (i == DATASTLN1_LEN) { dev_kfree_skb(skb); if (st->l3.debug & L3_DEB_STATE) { sprintf(tmp, "up1tr6%sstate %d mt %x unhandled", - (pr == DL_DATA) ? " " : "(broadcast) ", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", proc->state, mt); l3_debug(st, tmp); } @@ -799,7 +862,7 @@ up1tr6(struct PStack *st, int pr, void *arg) } else { if (st->l3.debug & L3_DEB_STATE) { sprintf(tmp, "up1tr6%sstate %d mt %x", - (pr == DL_DATA) ? " " : "(broadcast) ", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", proc->state, mt); l3_debug(st, tmp); } @@ -816,7 +879,10 @@ down1tr6(struct PStack *st, int pr, void *arg) struct Channel *chan; char tmp[80]; - if (CC_SETUP_REQ == pr) { + if (((DL_ESTABLISH | REQUEST)== pr) || ((DL_RELEASE | REQUEST)== pr)) { + l3_msg(st, pr, NULL); + return; + } else if ((CC_SETUP | REQUEST) == pr) { chan = arg; cr = newcallref(); cr |= 0x80; @@ -832,11 +898,11 @@ down1tr6(struct PStack *st, int pr, void *arg) proc = arg; } - for (i = 0; i < downstl_len; i++) + for (i = 0; i < DOWNSTL_LEN; i++) if ((pr == downstl[i].primitive) && ((1 << proc->state) & downstl[i].state)) break; - if (i == downstl_len) { + if (i == DOWNSTL_LEN) { if (st->l3.debug & L3_DEB_STATE) { sprintf(tmp, "down1tr6 state %d prim %d unhandled", proc->state, pr); diff --git a/drivers/isdn/hisax/l3_1tr6.h b/drivers/isdn/hisax/l3_1tr6.h index 90d08793e..7c0ba56b2 100644 --- a/drivers/isdn/hisax/l3_1tr6.h +++ b/drivers/isdn/hisax/l3_1tr6.h @@ -1,8 +1,11 @@ -/* $Id: l3_1tr6.h,v 2.0 1997/07/27 21:15:47 keil Exp $ +/* $Id: l3_1tr6.h,v 2.1 1998/08/13 23:36:48 keil Exp $ * * German 1TR6 D-channel protocol defines * * $Log: l3_1tr6.h,v $ + * Revision 2.1 1998/08/13 23:36:48 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * * Revision 2.0 1997/07/27 21:15:47 keil * New Callref based layer3 * @@ -64,6 +67,7 @@ #define MT_N1_REG_ACK 0x6C #define MT_N1_REG_REJ 0x6F #define MT_N1_STAT 0x63 +#define MT_N1_INVALID 0 /* * W Elemente diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c index f8b97fd73..0808d32a0 100644 --- a/drivers/isdn/hisax/l3dss1.c +++ b/drivers/isdn/hisax/l3dss1.c @@ -1,14 +1,36 @@ -/* $Id: l3dss1.c,v 2.7 1998/02/12 23:08:01 keil Exp $ +/* $Id: l3dss1.c,v 2.12 1998/11/15 23:55:10 keil Exp $ * EURO/DSS1 D-channel protocol * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/HiSax.cert + * * Thanks to Jan den Ouden * Fritz Elfert * * $Log: l3dss1.c,v $ + * Revision 2.12 1998/11/15 23:55:10 keil + * changes from 2.0 + * + * Revision 2.11 1998/08/13 23:36:51 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 2.10 1998/05/25 14:10:20 keil + * HiSax 3.0 + * X.75 and leased are working again. + * + * Revision 2.9 1998/05/25 12:58:17 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 2.8 1998/03/19 13:18:47 keil + * Start of a CAPI like interface for supplementary Service + * first service: SUSPEND + * * Revision 2.7 1998/02/12 23:08:01 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -50,9 +72,7 @@ #include <linux/ctype.h> extern char *HiSax_getrev(const char *revision); -const char *dss1_revision = "$Revision: 2.7 $"; - -#define EXT_BEARER_CAPS 1 +const char *dss1_revision = "$Revision: 2.12 $"; #define MsgHead(ptr, cref, mty) \ *ptr++ = 0x8; \ @@ -61,12 +81,11 @@ const char *dss1_revision = "$Revision: 2.7 $"; *ptr++ = mty -#ifdef HISAX_DE_AOC +#if HISAX_DE_AOC static void -l3dss1_parse_facility(struct l3_process *pc, u_char *p) +l3dss1_parse_facility(struct l3_process *pc, u_char * p) { int qd_len = 0; - char tmp[32]; p++; qd_len = *p++; @@ -74,91 +93,99 @@ l3dss1_parse_facility(struct l3_process *pc, u_char *p) l3_debug(pc->st, "qd_len == 0"); return; } - if((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */ + if ((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */ l3_debug(pc->st, "supplementary service != 0x11"); return; } - while(qd_len > 0 && !(*p & 0x80)) { /* extension ? */ - p++; qd_len--; - } - if(qd_len < 2) { + while (qd_len > 0 && !(*p & 0x80)) { /* extension ? */ + p++; + qd_len--; + } + if (qd_len < 2) { l3_debug(pc->st, "qd_len < 2"); return; } - p++; qd_len--; - if((*p & 0xE0) != 0xA0) { /* class and form */ + p++; + qd_len--; + if ((*p & 0xE0) != 0xA0) { /* class and form */ l3_debug(pc->st, "class and form != 0xA0"); return; } - switch(*p & 0x1F) { /* component tag */ - case 1: /* invoke */ - { - unsigned char nlen, ilen; - int ident; - - p++; qd_len--; - if(qd_len < 1) { - l3_debug(pc->st, "qd_len < 1"); - break; - } - if(*p & 0x80) { /* length format */ - l3_debug(pc->st, "*p & 0x80 length format"); - break; - } - nlen = *p++; qd_len--; - if(qd_len < nlen) { - l3_debug(pc->st, "qd_len < nlen"); - return; - } - qd_len -= nlen; - - if(nlen < 2) { - l3_debug(pc->st, "nlen < 2"); - return; - } - if(*p != 0x02) { /* invoke identifier tag */ - l3_debug(pc->st, "invoke identifier tag !=0x02"); - return; - } - p++; nlen--; - if(*p & 0x80) { /* length format */ - l3_debug(pc->st, "*p & 0x80 length format 2"); - break; - } - ilen = *p++; nlen--; - if(ilen > nlen || ilen == 0) { - l3_debug(pc->st, "ilen > nlen || ilen == 0"); - return; - } - nlen -= ilen; - ident = 0; - while(ilen > 0) { - ident = (ident << 8) | (*p++ & 0xFF); /* invoke identifier */ - ilen--; - } - - if(nlen < 2) { - l3_debug(pc->st, "nlen < 2 22"); - return; - } - if(*p != 0x02) { /* operation value */ - l3_debug(pc->st, "operation value !=0x02"); - return; - } - p++; nlen--; - ilen = *p++; nlen--; - if(ilen > nlen || ilen == 0) { - l3_debug(pc->st, "ilen > nlen || ilen == 0 22"); - return; - } - nlen -= ilen; - ident = 0; - while(ilen > 0) { - ident = (ident << 8) | (*p++ & 0xFF); - ilen--; - } - - #define FOO1(s,a,b) \ + switch (*p & 0x1F) { /* component tag */ + case 1: /* invoke */ + { + unsigned char nlen = 0, ilen; + int ident; + + p++; + qd_len--; + if (qd_len < 1) { + l3_debug(pc->st, "qd_len < 1"); + break; + } + if (*p & 0x80) { /* length format */ + l3_debug(pc->st, "*p & 0x80 length format"); + break; + } + nlen = *p++; + qd_len--; + if (qd_len < nlen) { + l3_debug(pc->st, "qd_len < nlen"); + return; + } + qd_len -= nlen; + + if (nlen < 2) { + l3_debug(pc->st, "nlen < 2"); + return; + } + if (*p != 0x02) { /* invoke identifier tag */ + l3_debug(pc->st, "invoke identifier tag !=0x02"); + return; + } + p++; + nlen--; + if (*p & 0x80) { /* length format */ + l3_debug(pc->st, "*p & 0x80 length format 2"); + break; + } + ilen = *p++; + nlen--; + if (ilen > nlen || ilen == 0) { + l3_debug(pc->st, "ilen > nlen || ilen == 0"); + return; + } + nlen -= ilen; + ident = 0; + while (ilen > 0) { + ident = (ident << 8) | (*p++ & 0xFF); /* invoke identifier */ + ilen--; + } + + if (nlen < 2) { + l3_debug(pc->st, "nlen < 2 22"); + return; + } + if (*p != 0x02) { /* operation value */ + l3_debug(pc->st, "operation value !=0x02"); + return; + } + p++; + nlen--; + ilen = *p++; + nlen--; + if (ilen > nlen || ilen == 0) { + l3_debug(pc->st, "ilen > nlen || ilen == 0 22"); + return; + } + nlen -= ilen; + ident = 0; + while (ilen > 0) { + ident = (ident << 8) | (*p++ & 0xFF); + ilen--; + } + +#define FOO1(s,a,b) \ while(nlen > 1) { \ int ilen = p[1]; \ if(nlen < ilen+2) { \ @@ -174,72 +201,74 @@ l3dss1_parse_facility(struct l3_process *pc, u_char *p) p += ilen+2; \ } \ } - - switch(ident) { - default: - break; - case 0x22: /* during */ - FOO1("1A",0x30,FOO1("1C",0xA1,FOO1("1D",0x30,FOO1("1E",0x02,({ - ident = 0; - while(ilen > 0) { - ident = (ident<<8) | *p++; - ilen--; - } - if (ident > pc->para.chargeinfo) { - pc->para.chargeinfo = ident; - pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL); - } - if (pc->st->l3.debug & L3_DEB_CHARGE) { - if (*(p+2) == 0) { - sprintf(tmp, "charging info during %d", pc->para.chargeinfo); - l3_debug(pc->st, tmp); - } - else { - sprintf(tmp, "charging info final %d", pc->para.chargeinfo); - l3_debug(pc->st, tmp); - } - } - }))))) - break; - case 0x24: /* final */ - FOO1("2A",0x30,FOO1("2B",0x30,FOO1("2C",0xA1,FOO1("2D",0x30,FOO1("2E",0x02,({ - ident = 0; - while(ilen > 0) { - ident = (ident<<8) | *p++; - ilen--; - } - if (ident > pc->para.chargeinfo) { - pc->para.chargeinfo = ident; - pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL); - } - if (pc->st->l3.debug & L3_DEB_CHARGE) { - sprintf(tmp, "charging info final %d", pc->para.chargeinfo); - l3_debug(pc->st, tmp); - } - })))))) - break; - } - #undef FOO1 - - } - break; - case 2: /* return result */ - l3_debug(pc->st, "return result break"); - break; - case 3: /* return error */ - l3_debug(pc->st, "return error break"); - break; - default: - l3_debug(pc->st, "default break"); - break; + + switch (ident) { + default: + break; + case 0x22: /* during */ + FOO1("1A", 0x30, FOO1("1C", 0xA1, FOO1("1D", 0x30, FOO1("1E", 0x02, ( { + ident = 0; + nlen = (nlen)?nlen:0; /* Make gcc happy */ + while (ilen > 0) { + ident = (ident << 8) | *p++; + ilen--; + } + if (ident > pc->para.chargeinfo) { + pc->para.chargeinfo = ident; + pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc); + } + if (pc->st->l3.debug & L3_DEB_CHARGE) { + if (*(p + 2) == 0) { + l3_debug(pc->st, "charging info during %d", pc->para.chargeinfo); + } + else { + l3_debug(pc->st, "charging info final %d", pc->para.chargeinfo); + } + } + } + ))))) + break; + case 0x24: /* final */ + FOO1("2A", 0x30, FOO1("2B", 0x30, FOO1("2C", 0xA1, FOO1("2D", 0x30, FOO1("2E", 0x02, ( { + ident = 0; + nlen = (nlen)?nlen:0; /* Make gcc happy */ + while (ilen > 0) { + ident = (ident << 8) | *p++; + ilen--; + } + if (ident > pc->para.chargeinfo) { + pc->para.chargeinfo = ident; + pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc); + } + if (pc->st->l3.debug & L3_DEB_CHARGE) { + l3_debug(pc->st, "charging info final %d", pc->para.chargeinfo); + } + } + )))))) + break; + } +#undef FOO1 + + } + break; + case 2: /* return result */ + l3_debug(pc->st, "return result break"); + break; + case 3: /* return error */ + l3_debug(pc->st, "return error break"); + break; + default: + l3_debug(pc->st, "default break"); + break; } } -#endif +#endif -static int -l3dss1_check_messagetype_validity(int mt) { +static int +l3dss1_check_messagetype_validity(int mt) +{ /* verify if a message type exists */ - switch(mt) { + switch (mt) { case MT_ALERTING: case MT_CALL_PROCEEDING: case MT_CONNECT: @@ -283,7 +312,7 @@ l3dss1_message(struct l3_process *pc, u_char mt) return; p = skb_put(skb, 4); MsgHead(p, pc->callref, mt); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); } static void @@ -314,165 +343,244 @@ l3dss1_release_cmpl(struct l3_process *pc, u_char pr, void *arg) StopAllL3Timer(pc); pc->para.cause = cause; newl3state(pc, 0); - pc->st->l3.l3l4(pc, CC_RELEASE_CNF, NULL); + pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); release_l3_process(pc); } -#ifdef EXT_BEARER_CAPS - -u_char *EncodeASyncParams(u_char *p, u_char si2) -{ // 7c 06 88 90 21 42 00 bb - - p[0] = p[1] = 0; 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; +#if EXT_BEARER_CAPS + +u_char * +EncodeASyncParams(u_char * p, u_char si2) +{ // 7c 06 88 90 21 42 00 bb + + p[0] = p[1] = 0; + 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; } -u_char EncodeSyncParams(u_char si2, u_char ai) +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; + 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 bleibt gleich - 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 +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) +static u_char +DecodeSyncParams(u_char si2, u_char info) { - info &= 0x7f; - switch (info) - { - case 40: // bit/s aushandeln --- hat nicht geklappt, ai wird 165 statt 175! - return si2 + 15; - case 15: // 56000 bit/s --- hat nicht geklappt, ai wird 0 statt 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; - } + 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 - return DecodeSyncParams(176, p[5]); // V.120 - break; - } - } - return 0; +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 + + return DecodeSyncParams(176, p[5]); // V.120 + + break; + } + } + return 0; } #endif @@ -498,7 +606,7 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr, /* * Set Bearer Capability, Map info from 1TR6-convention to EDSS1 */ -#ifdef HISAX_EURO_SENDCOMPLETE +#if HISAX_EURO_SENDCOMPLETE *p++ = 0xa1; /* complete indicator */ #endif switch (pc->para.setup.si1) { @@ -558,11 +666,11 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr, msn = pc->para.setup.eazmsn; sub = NULL; sp = msn; - while (*sp) { + while (*sp) { if ('.' == *sp) { sub = sp; *sp = 0; - } else + } else sp++; } if (*msn) { @@ -579,20 +687,20 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr, } if (sub) { *sub++ = '.'; - *p++ = 0x6d; /* Calling party subaddress */ - *p++ = strlen(sub) + 2; + *p++ = 0x6d; /* Calling party subaddress */ + *p++ = strlen(sub) + 2; *p++ = 0x80; /* NSAP coded */ *p++ = 0x50; /* local IDI format */ - while (*sub) + while (*sub) *p++ = *sub++ & 0x7f; } sub = NULL; sp = teln; - while (*sp) { + while (*sp) { if ('.' == *sp) { sub = sp; *sp = 0; - } else + } else sp++; } *p++ = 0x70; @@ -604,31 +712,47 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr, if (sub) { *sub++ = '.'; - *p++ = 0x71; /* Called party subaddress */ - *p++ = strlen(sub) + 2; + *p++ = 0x71; /* Called party subaddress */ + *p++ = strlen(sub) + 2; *p++ = 0x80; /* NSAP coded */ *p++ = 0x50; /* local IDI format */ - while (*sub) + while (*sub) *p++ = *sub++ & 0x7f; } - -#ifdef EXT_BEARER_CAPS - if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) - { // sync. Bitratenadaption, V.110/X.30 - *p++ = 0x7c; *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++ = 0x7c; *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++ = 0x7c; *p++ = 0x06; *p++ = 0x88; *p++ = 0x90; *p++ = 0x21; - p = EncodeASyncParams(p, pc->para.setup.si2 - 192); - } +#if EXT_BEARER_CAPS + if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30 + + *p++ = 0x7c; + *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++ = 0x7c; + *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++ = 0x7c; + *p++ = 0x06; + *p++ = 0x88; + *p++ = 0x90; + *p++ = 0x21; + p = EncodeASyncParams(p, pc->para.setup.si2 - 192); +#if HISAX_SEND_STD_LLC_IE + } else { + *p++ = 0x7c; + *p++ = 0x02; + *p++ = 0x88; + *p++ = 0x90; +#endif + } #endif l = p - tmp; if (!(skb = l3_alloc_skb(l))) @@ -637,7 +761,7 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr, L3DelTimer(&pc->timer); L3AddTimer(&pc->timer, T303, CC_T303); newl3state(pc, 1); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); } static void @@ -657,7 +781,7 @@ l3dss1_call_proc(struct l3_process *pc, u_char pr, void *arg) dev_kfree_skb(skb); newl3state(pc, 3); L3AddTimer(&pc->timer, T310, CC_T310); - pc->st->l3.l3l4(pc, CC_PROCEEDING_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc); } static void @@ -677,7 +801,7 @@ l3dss1_setup_ack(struct l3_process *pc, u_char pr, void *arg) dev_kfree_skb(skb); newl3state(pc, 2); L3AddTimer(&pc->timer, T304, CC_T304); - pc->st->l3.l3l4(pc, CC_MORE_INFO, NULL); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); } static void @@ -699,7 +823,7 @@ l3dss1_disconnect(struct l3_process *pc, u_char pr, void *arg) dev_kfree_skb(skb); newl3state(pc, 12); pc->para.cause = cause; - pc->st->l3.l3l4(pc, CC_DISCONNECT_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc); } static void @@ -711,7 +835,7 @@ l3dss1_connect(struct l3_process *pc, u_char pr, void *arg) L3DelTimer(&pc->timer); /* T310 */ newl3state(pc, 10); pc->para.chargeinfo = 0; - pc->st->l3.l3l4(pc, CC_SETUP_CNF, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc); } static void @@ -722,49 +846,48 @@ l3dss1_alerting(struct l3_process *pc, u_char pr, void *arg) dev_kfree_skb(skb); L3DelTimer(&pc->timer); /* T304 */ newl3state(pc, 4); - pc->st->l3.l3l4(pc, CC_ALERTING_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc); } static void l3dss1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg) { - /* This routine is called if here was no SETUP made (checks in dss1up and in - * l3dss1_setup) and a RELEASE_COMPLETE have to be sent with an error code - * It is called after it is veryfied that Layer2 is up. - * The cause value is allready in pc->para.cause - * MT_STATUS_ENQUIRE in the NULL state is handled too - */ + /* This routine is called if here was no SETUP made (checks in dss1up and in + * l3dss1_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; + u_char *p = tmp; int l; struct sk_buff *skb; switch (pc->para.cause) { - case 81: /* 0x51 invalid callreference */ - case 96: /* 0x60 mandory IE missing */ - case 101: /* 0x65 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 internal error l3dss1_msg_without_setup\n"); - return; - } + case 81: /* 0x51 invalid callreference */ + case 88: /* 0x58 incomp destination */ + case 96: /* 0x60 mandory IE missing */ + case 101: /* 0x65 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 internal error l3dss1_msg_without_setup\n"); + return; + } l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; memcpy(skb_put(skb, l), tmp, l); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); release_l3_process(pc); } static void l3dss1_setup(struct l3_process *pc, u_char pr, void *arg) { - u_char *p, *ptmp[8]; + u_char *p, *ptmp[8]; int i; int bcfound = 0; char tmp[80]; @@ -772,9 +895,9 @@ l3dss1_setup(struct l3_process *pc, u_char pr, void *arg) /* ETS 300-104 1.3.4 and 1.3.5 * we need to detect unknown inform. element from 0 to 7 - */ + */ p = skb->data; - for(i = 0; i < 8; i++) + for (i = 0; i < 8; i++) ptmp[i] = skb->data; if (findie(ptmp[1], skb->len, 0x01, 0) || findie(ptmp[2], skb->len, 0x02, 0) @@ -782,18 +905,14 @@ l3dss1_setup(struct l3_process *pc, u_char pr, void *arg) || findie(ptmp[5], skb->len, 0x05, 0) || findie(ptmp[6], skb->len, 0x06, 0) || findie(ptmp[7], skb->len, 0x07, 0)) { - /* if ie is < 8 and not 0 nor 4, send RELEASE_COMPLETE - * cause 0x60 - */ - pc->para.cause = 0x60; + /* if ie is < 8 and not 0 nor 4, send RELEASE_COMPLETE + * cause 0x60 + */ + pc->para.cause = 0x60; dev_kfree_skb(skb); - if (pc->state == 0) - pc->st->l3.l3l4(pc, CC_ESTABLISH, NULL); - else - l3dss1_msg_without_setup(pc, pr, NULL); + l3dss1_msg_without_setup(pc, pr, NULL); return; } - /* * Channel Identification */ @@ -804,9 +923,14 @@ l3dss1_setup(struct l3_process *pc, u_char pr, void *arg) bcfound++; else if (pc->debug & L3_DEB_WARN) l3_debug(pc->st, "setup without bchannel"); - } else if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup without bchannel"); - + } else { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup without bchannel"); + pc->para.cause = 0x60; + dev_kfree_skb(skb); + l3dss1_msg_without_setup(pc, pr, NULL); + return; + } /* * Bearer Capabilities */ @@ -824,10 +948,10 @@ l3dss1_setup(struct l3_process *pc, u_char pr, void *arg) /* Unrestricted digital information */ pc->para.setup.si1 = 7; /* JIM, 05.11.97 I wanna set service indicator 2 */ -#ifdef EXT_BEARER_CAPS - pc->para.setup.si2 = DecodeSI2(skb); - printk(KERN_DEBUG "HiSax: SI=%d, AI=%d\n", - pc->para.setup.si1, pc->para.setup.si2); +#if EXT_BEARER_CAPS + pc->para.setup.si2 = DecodeSI2(skb); + printk(KERN_DEBUG "HiSax: SI=%d, AI=%d\n", + pc->para.setup.si1, pc->para.setup.si2); #endif break; case 0x09: @@ -849,12 +973,9 @@ l3dss1_setup(struct l3_process *pc, u_char pr, void *arg) if (pc->debug & L3_DEB_WARN) l3_debug(pc->st, "setup without bearer capabilities"); /* ETS 300-104 1.3.3 */ - pc->para.cause = 0x60; + pc->para.cause = 0x60; dev_kfree_skb(skb); - if (pc->state == 0) - pc->st->l3.l3l4(pc, CC_ESTABLISH, NULL); - else - l3dss1_msg_without_setup(pc, pr, NULL); + l3dss1_msg_without_setup(pc, pr, NULL); return; } @@ -867,8 +988,8 @@ l3dss1_setup(struct l3_process *pc, u_char pr, void *arg) 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]='.'; + 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) @@ -892,24 +1013,28 @@ l3dss1_setup(struct l3_process *pc, u_char pr, void *arg) 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]='.'; + 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"); } - dev_kfree_skb(skb); if (bcfound) { if ((pc->para.setup.si1 != 7) && (pc->debug & L3_DEB_WARN)) { - sprintf(tmp, "non-digital call: %s -> %s", - pc->para.setup.phone, pc->para.setup.eazmsn); - l3_debug(pc->st, tmp); + l3_debug(pc->st, "non-digital call: %s -> %s", + pc->para.setup.phone, pc->para.setup.eazmsn); + } + if ((pc->para.setup.si1 != 7) && + test_bit(FLG_PTP, &pc->st->l2.flag)) { + pc->para.cause = 0x58; + l3dss1_msg_without_setup(pc, pr, NULL); + return; } newl3state(pc, 6); - pc->st->l3.l3l4(pc, CC_SETUP_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); } else release_l3_process(pc); } @@ -938,7 +1063,7 @@ l3dss1_connect_ack(struct l3_process *pc, u_char pr, void *arg) dev_kfree_skb(skb); newl3state(pc, 10); L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc, CC_SETUP_COMPLETE_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc); } static void @@ -967,7 +1092,7 @@ l3dss1_disconnect_req(struct l3_process *pc, u_char pr, void *arg) return; memcpy(skb_put(skb, l), tmp, l); newl3state(pc, 11); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); L3AddTimer(&pc->timer, T305, CC_T305); } @@ -994,8 +1119,8 @@ l3dss1_reject_req(struct l3_process *pc, u_char pr, void *arg) if (!(skb = l3_alloc_skb(l))) return; memcpy(skb_put(skb, l), tmp, l); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); - pc->st->l3.l3l4(pc, CC_RELEASE_IND, NULL); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); newl3state(pc, 0); release_l3_process(pc); } @@ -1016,8 +1141,8 @@ l3dss1_release(struct l3_process *pc, u_char pr, void *arg) } p = skb->data; if ((p = findie(p, skb->len, IE_FACILITY, 0))) { -#ifdef HISAX_DE_AOC - l3dss1_parse_facility(pc,p); +#if HISAX_DE_AOC + l3dss1_parse_facility(pc, p); #else p = NULL; #endif @@ -1026,7 +1151,7 @@ l3dss1_release(struct l3_process *pc, u_char pr, void *arg) StopAllL3Timer(pc); pc->para.cause = cause; l3dss1_message(pc, MT_RELEASE_COMPLETE); - pc->st->l3.l3l4(pc, CC_RELEASE_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); newl3state(pc, 0); release_l3_process(pc); } @@ -1064,15 +1189,15 @@ l3dss1_status_enq(struct l3_process *pc, u_char pr, void *arg) if (!(skb = l3_alloc_skb(l))) return; memcpy(skb_put(skb, l), tmp, l); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); } static void l3dss1_status_req(struct l3_process *pc, u_char pr, void *arg) { - /* ETS 300-104 7.4.1, 8.4.1, 10.3.1, 11.4.1, 12.4.1, 13.4.1, 14.4.1... - if setup has been made and a non expected message type is received, we must send MT_STATUS cause 0x62 */ - u_char tmp[16]; + /* ETS 300-104 7.4.1, 8.4.1, 10.3.1, 11.4.1, 12.4.1, 13.4.1, 14.4.1... + if setup has been made and a non expected message type is received, we must send MT_STATUS cause 0x62 */ + u_char tmp[16]; u_char *p = tmp; int l; struct sk_buff *skb = arg; @@ -1084,7 +1209,7 @@ l3dss1_status_req(struct l3_process *pc, u_char pr, void *arg) *p++ = IE_CAUSE; *p++ = 0x2; *p++ = 0x80; - *p++ = 0x62 | 0x80; /* status sending */ + *p++ = 0x62 | 0x80; /* status sending */ *p++ = 0x14; /* CallState */ *p++ = 0x1; @@ -1094,7 +1219,7 @@ l3dss1_status_req(struct l3_process *pc, u_char pr, void *arg) if (!(skb = l3_alloc_skb(l))) return; memcpy(skb_put(skb, l), tmp, l); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); } static void @@ -1107,18 +1232,18 @@ l3dss1_release_ind(struct l3_process *pc, u_char pr, void *arg) if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) { p++; - if (1== *p++) + if (1 == *p++) callState = *p; } - if(callState == 0) { + 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, CC_RELEASE_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); newl3state(pc, 0); release_l3_process(pc); } else { - pc->st->l3.l3l4(pc, CC_IGNORE, NULL); + pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc); } } @@ -1131,7 +1256,7 @@ l3dss1_t303(struct l3_process *pc, u_char pr, void *arg) l3dss1_setup_req(pc, pr, arg); } else { L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc, CC_NOSETUP_RSP_ERR, NULL); + pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc); release_l3_process(pc); } } @@ -1142,7 +1267,7 @@ l3dss1_t304(struct l3_process *pc, u_char pr, void *arg) L3DelTimer(&pc->timer); pc->para.cause = 0xE6; l3dss1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } @@ -1171,7 +1296,7 @@ l3dss1_t305(struct l3_process *pc, u_char pr, void *arg) return; memcpy(skb_put(skb, l), tmp, l); newl3state(pc, 19); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); L3AddTimer(&pc->timer, T308, CC_T308_1); } @@ -1181,7 +1306,7 @@ l3dss1_t310(struct l3_process *pc, u_char pr, void *arg) L3DelTimer(&pc->timer); pc->para.cause = 0xE6; l3dss1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } static void @@ -1190,7 +1315,7 @@ l3dss1_t313(struct l3_process *pc, u_char pr, void *arg) L3DelTimer(&pc->timer); pc->para.cause = 0xE6; l3dss1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc, CC_CONNECT_ERR, NULL); + pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); } static void @@ -1206,15 +1331,37 @@ static void l3dss1_t308_2(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc, CC_RELEASE_ERR, NULL); + pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); release_l3_process(pc); } static void +l3dss1_t318(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.cause = 0x66; /* Timer expiry */ + pc->para.loc = 0; /* local */ + pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); + newl3state(pc, 19); + l3dss1_message(pc, MT_RELEASE); + L3AddTimer(&pc->timer, T308, CC_T308_1); +} + +static void +l3dss1_t319(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.cause = 0x66; /* Timer expiry */ + pc->para.loc = 0; /* local */ + pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); + newl3state(pc, 10); +} + +static void l3dss1_restart(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc, CC_DLRL, NULL); + pc->st->l3.l3l4(pc->st, CC_DLRL | INDICATION, pc); release_l3_process(pc); } @@ -1233,31 +1380,30 @@ l3dss1_status(struct l3_process *pc, u_char pr, void *arg) if ((p = findie(p, skb->len, IE_CAUSE, 0))) { p++; l = *p++; - t += sprintf(t,"Status CR %x Cause:", pc->callref); + t += sprintf(t, "Status CR %x Cause:", pc->callref); while (l--) { - cause = *p; - t += sprintf(t," %2x",*p++); + cause = *p; + t += sprintf(t, " %2x", *p++); } } else - sprintf(t,"Status CR %x no Cause", pc->callref); + sprintf(t, "Status CR %x no Cause", pc->callref); l3_debug(pc->st, tmp); p = skb->data; t = tmp; - t += sprintf(t,"Status state %x ", pc->state); + t += sprintf(t, "Status state %x ", pc->state); if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) { p++; - if (1== *p++) { - callState = *p; - t += sprintf(t,"peer state %x" , *p); - } - else - t += sprintf(t,"peer state len error"); + if (1 == *p++) { + callState = *p; + t += sprintf(t, "peer state %x", *p); + } else + t += sprintf(t, "peer state len error"); } else - sprintf(t,"no peer state"); + sprintf(t, "no peer state"); l3_debug(pc->st, tmp); - if(((cause & 0x7f) == 0x6f) && (callState == 0)) { - /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... - * if received MT_STATUS with cause == 0x6f and call + if (((cause & 0x7f) == 0x6f) && (callState == 0)) { + /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... + * if received MT_STATUS with cause == 0x6f and call * state == 0, then we must set down layer 3 */ l3dss1_release_ind(pc, pr, arg); @@ -1268,56 +1414,189 @@ l3dss1_status(struct l3_process *pc, u_char pr, void *arg) static void l3dss1_facility(struct l3_process *pc, u_char pr, void *arg) { - u_char *p; + u_char *p; struct sk_buff *skb = arg; p = skb->data; if ((p = findie(p, skb->len, IE_FACILITY, 0))) { -#ifdef HISAX_DE_AOC - l3dss1_parse_facility(pc,p); +#if HISAX_DE_AOC + l3dss1_parse_facility(pc, p); #else p = NULL; #endif } } +static void +l3dss1_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); + + *p++ = IE_CALLID; + l = *msg++; + if (l && (l <= 10)) { /* Max length 10 octets */ + *p++ = l; + for (i = 0; i < l; i++) + *p++ = *msg++; + } else { + l3_debug(pc->st, "SUS wrong CALLID 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 +l3dss1_suspend_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + + L3DelTimer(&pc->timer); + newl3state(pc, 0); + dev_kfree_skb(skb); + pc->para.cause = -1; + pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc); + release_l3_process(pc); +} + +static void +l3dss1_suspend_rej(struct l3_process *pc, u_char pr, void *arg) +{ + u_char *p; + struct sk_buff *skb = arg; + int cause = -1; + + L3DelTimer(&pc->timer); + p = skb->data; + if ((p = findie(p, skb->len, IE_CAUSE, 0))) { + p++; + if (*p++ == 2) + pc->para.loc = *p++; + cause = *p & 0x7f; + } + dev_kfree_skb(skb); + pc->para.cause = cause; + pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); + newl3state(pc, 10); +} + +static void +l3dss1_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); + + *p++ = IE_CALLID; + l = *msg++; + if (l && (l <= 10)) { /* Max length 10 octets */ + *p++ = l; + for (i = 0; i < l; i++) + *p++ = *msg++; + } else { + l3_debug(pc->st, "RES wrong CALLID 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, T319, CC_T319); +} + +static void +l3dss1_resume_ack(struct l3_process *pc, u_char pr, void *arg) +{ + u_char *p; + struct sk_buff *skb = arg; + + L3DelTimer(&pc->timer); + p = skb->data; + if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { + pc->para.bchannel = p[2] & 0x3; + if ((!pc->para.bchannel) && (pc->debug & L3_DEB_WARN)) + l3_debug(pc->st, "resume ack without bchannel"); + } else if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "resume ack without bchannel"); + dev_kfree_skb(skb); + pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc); + newl3state(pc, 10); +} + +static void +l3dss1_resume_rej(struct l3_process *pc, u_char pr, void *arg) +{ + u_char *p; + struct sk_buff *skb = arg; + int cause = -1; + + L3DelTimer(&pc->timer); + p = skb->data; + if ((p = findie(p, skb->len, IE_CAUSE, 0))) { + p++; + if (*p++ == 2) + pc->para.loc = *p++; + cause = *p & 0x7f; + } + dev_kfree_skb(skb); + pc->para.cause = cause; + newl3state(pc, 0); + pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); + release_l3_process(pc); +} - static void l3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg) { u_char tmp[32]; u_char *p; - u_char ri, chan=0; + 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]; - sprintf(tmp, "Restart %x", ri); + ri = p[2]; + l3_debug(pc->st, "Restart %x", ri); } else { - sprintf(tmp, "Restart without restart IE"); + l3_debug(pc->st, "Restart without restart IE"); ri = 0x86; } - l3_debug(pc->st, tmp); p = skb->data; if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { chan = p[2] & 3; - sprintf(tmp, "Restart for channel %d", chan); - l3_debug(pc->st, tmp); + ch = p[2]; + if (pc->st->l3.debug) + l3_debug(pc->st, "Restart for channel %d", chan); } dev_kfree_skb(skb); newl3state(pc, 2); up = pc->st->l3.proc; while (up) { - if ((ri & 7)==7) - up->st->lli.l4l3(up->st, CC_RESTART, 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, up); + up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); up = up->next; } p = tmp; @@ -1325,9 +1604,9 @@ l3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg) if (chan) { *p++ = IE_CHANNEL_ID; *p++ = 1; - *p++ = chan | 0x80; + *p++ = ch | 0x80; } - *p++ = 0x79; /* RESTART Ind */ + *p++ = 0x79; /* RESTART Ind */ *p++ = 1; *p++ = ri; l = p - tmp; @@ -1335,32 +1614,33 @@ l3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg) return; memcpy(skb_put(skb, l), tmp, l); newl3state(pc, 0); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); } - /* *INDENT-OFF* */ static struct stateentry downstatelist[] = { {SBIT(0), - CC_ESTABLISH, l3dss1_msg_without_setup}, + CC_SETUP | REQUEST, l3dss1_setup_req}, {SBIT(0), - CC_SETUP_REQ, l3dss1_setup_req}, + CC_RESUME | REQUEST, l3dss1_resume_req}, {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(10), - CC_DISCONNECT_REQ, l3dss1_disconnect_req}, + CC_DISCONNECT | REQUEST, l3dss1_disconnect_req}, {SBIT(12), - CC_RELEASE_REQ, l3dss1_release_req}, + CC_RELEASE | REQUEST, l3dss1_release_req}, {ALL_STATES, - CC_DLRL, l3dss1_reset}, + CC_DLRL | REQUEST, l3dss1_reset}, {ALL_STATES, - CC_RESTART, l3dss1_restart}, + CC_RESTART | REQUEST, l3dss1_restart}, {SBIT(6), - CC_IGNORE, l3dss1_reset}, + CC_IGNORE | REQUEST, l3dss1_reset}, {SBIT(6), - CC_REJECT_REQ, l3dss1_reject_req}, + CC_REJECT | REQUEST, l3dss1_reject_req}, {SBIT(6), - CC_ALERTING_REQ, l3dss1_alert_req}, + CC_ALERTING | REQUEST, l3dss1_alert_req}, {SBIT(6) | SBIT(7), - CC_SETUP_RSP, l3dss1_setup_rsp}, + CC_SETUP | RESPONSE, l3dss1_setup_rsp}, + {SBIT(10), + CC_SUSPEND | REQUEST, l3dss1_suspend_req}, {SBIT(1), CC_T303, l3dss1_t303}, {SBIT(2), @@ -1371,14 +1651,18 @@ static struct stateentry downstatelist[] = CC_T313, l3dss1_t313}, {SBIT(11), CC_T305, l3dss1_t305}, + {SBIT(15), + CC_T319, l3dss1_t319}, + {SBIT(17), + CC_T318, l3dss1_t318}, {SBIT(19), CC_T308_1, l3dss1_t308_1}, {SBIT(19), CC_T308_2, l3dss1_t308_2}, }; -static int downsllen = sizeof(downstatelist) / -sizeof(struct stateentry); +#define DOWNSLLEN \ + (sizeof(downstatelist) / sizeof(struct stateentry)) static struct stateentry datastatelist[] = { @@ -1408,10 +1692,10 @@ static struct stateentry datastatelist[] = SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19), MT_RELEASE_COMPLETE, l3dss1_release_cmpl}, {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(11) | SBIT(12) | SBIT(15) /* | SBIT(17) | SBIT(19)*/, MT_RELEASE, l3dss1_release}, {SBIT(19), MT_RELEASE, l3dss1_release_ind}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10), + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) | SBIT(15), MT_DISCONNECT, l3dss1_disconnect}, {SBIT(11), MT_DISCONNECT, l3dss1_release_req}, @@ -1423,61 +1707,57 @@ static struct stateentry datastatelist[] = MT_CONNECT_ACKNOWLEDGE, l3dss1_status_req}, {SBIT(8), MT_CONNECT_ACKNOWLEDGE, l3dss1_connect_ack}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19), + {SBIT(15), + MT_SUSPEND_ACKNOWLEDGE, l3dss1_suspend_ack}, + {SBIT(15), + MT_SUSPEND_REJECT, l3dss1_suspend_rej}, + {SBIT(17), + MT_RESUME_ACKNOWLEDGE, l3dss1_resume_ack}, + {SBIT(17), + MT_RESUME_REJECT, l3dss1_resume_rej}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(19), MT_INVALID, l3dss1_status_req}, }; -static int datasllen = sizeof(datastatelist) / sizeof(struct stateentry); +#define DATASLLEN \ + (sizeof(datastatelist) / sizeof(struct stateentry)) static struct stateentry globalmes_list[] = { {ALL_STATES, - MT_STATUS, l3dss1_status}, + MT_STATUS, l3dss1_status}, {SBIT(0), MT_RESTART, l3dss1_global_restart}, /* {SBIT(1), - MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack}, + MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack}, */ }; -static int globalm_len = sizeof(globalmes_list) / sizeof(struct stateentry); - -#if 0 -static struct stateentry globalcmd_list[] = -{ - {ALL_STATES, - CC_STATUS, l3dss1_status_req}, - {SBIT(0), - CC_RESTART, l3dss1_restart_req}, -}; - -static int globalc_len = sizeof(globalcmd_list) / sizeof(struct stateentry); -#endif +#define GLOBALM_LEN \ + (sizeof(globalmes_list) / sizeof(struct stateentry)) /* *INDENT-ON* */ + static void global_handler(struct PStack *st, int mt, struct sk_buff *skb) { int i; - char tmp[64]; struct l3_process *proc = st->l3.global; - - for (i = 0; i < globalm_len; i++) + + 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 (i == GLOBALM_LEN) { dev_kfree_skb(skb); if (st->l3.debug & L3_DEB_STATE) { - sprintf(tmp, "dss1 global state %d mt %x unhandled", + l3_debug(st, "dss1 global state %d mt %x unhandled", proc->state, mt); - l3_debug(st, tmp); } return; } else { if (st->l3.debug & L3_DEB_STATE) { - sprintf(tmp, "dss1 global %d mt %x", + l3_debug(st, "dss1 global %d mt %x", proc->state, mt); - l3_debug(st, tmp); } globalmes_list[i].rout(proc, mt, skb); } @@ -1490,24 +1770,34 @@ dss1up(struct PStack *st, int pr, void *arg) char *ptr; struct sk_buff *skb = arg; struct l3_process *proc; - char tmp[80]; + switch (pr) { + case (DL_DATA | INDICATION): + case (DL_UNIT_DATA | INDICATION): + break; + case (DL_ESTABLISH | CONFIRM): + case (DL_ESTABLISH | INDICATION): + case (DL_RELEASE | INDICATION): + case (DL_RELEASE | CONFIRM): + l3_msg(st, pr, arg); + return; + break; + } if (skb->data[0] != PROTO_DIS_EURO) { if (st->l3.debug & L3_DEB_PROTERR) { - sprintf(tmp, "dss1up%sunexpected discriminator %x message len %d", - (pr == DL_DATA) ? " " : "(broadcast) ", - skb->data[0], skb->len); - l3_debug(st, tmp); + l3_debug(st, "dss1up%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); mt = skb->data[skb->data[1] + 2]; - if (!cr) { /* Global CallRef */ + if (!cr) { /* Global CallRef */ global_handler(st, mt, skb); return; - } else if (cr == -1) { /* Dummy Callref */ + } else if (cr == -1) { /* Dummy Callref */ dev_kfree_skb(skb); return; } else if (!(proc = getl3proc(st, cr))) { @@ -1515,7 +1805,7 @@ dss1up(struct PStack *st, int pr, void *arg) * this callreference is active */ if (mt == MT_SETUP) { - /* Setup creates a new transaction process */ + /* Setup creates a new transaction process */ if (!(proc = new_l3_process(st, cr))) { /* May be to answer with RELEASE_COMPLETE and * CAUSE 0x2f "Resource unavailable", but this @@ -1526,14 +1816,14 @@ dss1up(struct PStack *st, int pr, void *arg) } } 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; + 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) { + if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) { ptr++; if (*ptr++ == 2) ptr++; @@ -1549,29 +1839,29 @@ dss1up(struct PStack *st, int pr, void *arg) return; } else { /* ETS 300-104 part 2.4.2 - * if setup has not been made and a message type + * 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 */ dev_kfree_skb(skb); if ((proc = new_l3_process(st, cr))) { - proc->para.cause = 0x65; /* 101 */ - proc->st->l3.l3l4(proc, CC_ESTABLISH, NULL); + proc->para.cause = 0x65; /* 101 */ + l3dss1_msg_without_setup(proc, 0, NULL); } return; } - } else if (mt == MT_RELEASE_COMPLETE){ + } 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 + * 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 = new_l3_process(st, cr))) { - proc->para.cause = 0x51; /* 81 */ - proc->st->l3.l3l4(proc, CC_ESTABLISH, NULL); + proc->para.cause = 0x51; /* 81 */ + l3dss1_msg_without_setup(proc, 0, NULL); } return; } @@ -1581,28 +1871,25 @@ dss1up(struct PStack *st, int pr, void *arg) * if setup has been made and invalid message type is received, * we must send MT_STATUS cause 0x62 */ - mt = MT_INVALID; /* sorry, not clean, but do the right thing ;-) */ + mt = MT_INVALID; /* sorry, not clean, but do the right thing ;-) */ } - - for (i = 0; i < datasllen; i++) + for (i = 0; i < DATASLLEN; i++) if ((mt == datastatelist[i].primitive) && ((1 << proc->state) & datastatelist[i].state)) break; - if (i == datasllen) { + if (i == DATASLLEN) { dev_kfree_skb(skb); if (st->l3.debug & L3_DEB_STATE) { - sprintf(tmp, "dss1up%sstate %d mt %x unhandled", - (pr == DL_DATA) ? " " : "(broadcast) ", + l3_debug(st, "dss1up%sstate %d mt %x unhandled", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", proc->state, mt); - l3_debug(st, tmp); } return; } else { if (st->l3.debug & L3_DEB_STATE) { - sprintf(tmp, "dss1up%sstate %d mt %x", - (pr == DL_DATA) ? " " : "(broadcast) ", + l3_debug(st, "dss1up%sstate %d mt %x", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", proc->state, mt); - l3_debug(st, tmp); } datastatelist[i].rout(proc, pr, skb); } @@ -1614,9 +1901,11 @@ dss1down(struct PStack *st, int pr, void *arg) int i, cr; struct l3_process *proc; struct Channel *chan; - char tmp[80]; - if (CC_SETUP_REQ == pr) { + if (((DL_ESTABLISH | REQUEST) == pr) || ((DL_RELEASE | REQUEST) == pr)) { + l3_msg(st, pr, NULL); + return; + } else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) { chan = arg; cr = newcallref(); cr |= 0x80; @@ -1630,24 +1919,22 @@ dss1down(struct PStack *st, int pr, void *arg) proc = arg; } if (!proc) { - printk(KERN_ERR "HiSax internal error dss1down without proc\n"); + printk(KERN_ERR "HiSax dss1down without proc pr=%04x\n", pr); return; } - for (i = 0; i < downsllen; i++) + for (i = 0; i < DOWNSLLEN; i++) if ((pr == downstatelist[i].primitive) && ((1 << proc->state) & downstatelist[i].state)) break; - if (i == downsllen) { + if (i == DOWNSLLEN) { if (st->l3.debug & L3_DEB_STATE) { - sprintf(tmp, "dss1down state %d prim %d unhandled", + l3_debug(st, "dss1down state %d prim %d unhandled", proc->state, pr); - l3_debug(st, tmp); } } else { if (st->l3.debug & L3_DEB_STATE) { - sprintf(tmp, "dss1down state %d prim %d", + l3_debug(st, "dss1down state %d prim %d", proc->state, pr); - l3_debug(st, tmp); } downstatelist[i].rout(proc, pr, arg); } diff --git a/drivers/isdn/hisax/l3dss1.h b/drivers/isdn/hisax/l3dss1.h index 8508c3109..10e612482 100644 --- a/drivers/isdn/hisax/l3dss1.h +++ b/drivers/isdn/hisax/l3dss1.h @@ -1,8 +1,12 @@ -/* $Id: l3dss1.h,v 1.5 1998/02/02 13:34:30 keil Exp $ +/* $Id: l3dss1.h,v 1.6 1998/03/19 13:18:50 keil Exp $ * * DSS1 (Euro) D-channel protocol defines * * $Log: l3dss1.h,v $ + * Revision 1.6 1998/03/19 13:18:50 keil + * Start of a CAPI like interface for supplementary Service + * first service: SUSPEND + * * Revision 1.5 1998/02/02 13:34:30 keil * Support australian Microlink net and german AOCD * @@ -63,8 +67,9 @@ #define MT_INVALID 0xff -#define IE_CAUSE 0x08 #define IE_BEARER 0x04 +#define IE_CAUSE 0x08 +#define IE_CALLID 0x10 #define IE_FACILITY 0x1c #define IE_CALL_STATE 0x14 #define IE_CHANNEL_ID 0x18 diff --git a/drivers/isdn/hisax/lmgr.c b/drivers/isdn/hisax/lmgr.c index b3e9819b2..d6ef0b630 100644 --- a/drivers/isdn/hisax/lmgr.c +++ b/drivers/isdn/hisax/lmgr.c @@ -1,11 +1,21 @@ -/* $Id: lmgr.c,v 1.2 1997/10/29 19:09:34 keil Exp $ +/* $Id: lmgr.c,v 1.5 1998/11/15 23:55:12 keil Exp $ - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * * Layermanagement module * * $Log: lmgr.c,v $ + * Revision 1.5 1998/11/15 23:55:12 keil + * changes from 2.0 + * + * Revision 1.4 1998/05/25 12:58:19 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 1.3 1998/03/07 22:57:06 tsbogend + * made HiSax working on Linux/Alpha + * * Revision 1.2 1997/10/29 19:09:34 keil * new L1 * @@ -26,7 +36,7 @@ error_handling_dchan(struct PStack *st, int Error) case 'D': case 'G': case 'H': - st->l2.l2tei(st, MDL_ERROR_REQ, NULL); + st->l2.l2tei(st, MDL_ERROR | REQUEST, NULL); break; } } @@ -34,17 +44,15 @@ error_handling_dchan(struct PStack *st, int Error) static void hisax_manager(struct PStack *st, int pr, void *arg) { - char tm[32], str[256]; - int Code; + long Code; switch (pr) { - case MDL_ERROR_IND: - Code = (int) arg; - jiftime(tm, jiffies); - sprintf(str, "%s manager: MDL_ERROR %c %s\n", tm, - Code, test_bit(FLG_LAPD, &st->l2.flag) ? + case (MDL_ERROR | INDICATION): + Code = (long) arg; + HiSax_putstatus(st->l1.hardware, "manager: MDL_ERROR", + "%c %s\n", (char)Code, + test_bit(FLG_LAPD, &st->l2.flag) ? "D-channel" : "B-channel"); - HiSax_putstatus(st->l1.hardware, str); if (test_bit(FLG_LAPD, &st->l2.flag)) error_handling_dchan(st, Code); break; diff --git a/drivers/isdn/hisax/mic.c b/drivers/isdn/hisax/mic.c index 8bf4757c9..ccd103fed 100644 --- a/drivers/isdn/hisax/mic.c +++ b/drivers/isdn/hisax/mic.c @@ -1,4 +1,4 @@ -/* $Id: mic.c,v 1.6 1998/02/17 15:39:57 keil Exp $ +/* $Id: mic.c,v 1.7 1998/04/15 16:44:32 keil Exp $ * mic.c low level stuff for mic cards * @@ -8,6 +8,9 @@ * * * $Log: mic.c,v $ + * Revision 1.7 1998/04/15 16:44:32 keil + * new init code + * * Revision 1.6 1998/02/17 15:39:57 keil * fix reset problem * @@ -37,7 +40,7 @@ extern const char *CardType[]; -const char *mic_revision = "$Revision: 1.6 $"; +const char *mic_revision = "$Revision: 1.7 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -220,10 +223,7 @@ mic_card_msg(struct IsdnCardState *cs, int mt, void *arg) I4L_IRQ_FLAG, "HiSax", cs)); case CARD_INIT: inithscx(cs); /* /RTSA := ISAC RST */ - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + inithscxisac(cs, 3); return(0); case CARD_TEST: return(0); diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c index 54f9c14d8..746451ba0 100644 --- a/drivers/isdn/hisax/netjet.c +++ b/drivers/isdn/hisax/netjet.c @@ -1,13 +1,30 @@ -/* $Id: netjet.c,v 1.3 1998/02/12 23:08:05 keil Exp $ +/* $Id: netjet.c,v 1.8 1998/11/15 23:55:14 keil Exp $ * netjet.c low level stuff for Traverse Technologie NETJet ISDN cards * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * Thanks to Traverse Technologie Australia for documents and informations * * * $Log: netjet.c,v $ + * Revision 1.8 1998/11/15 23:55:14 keil + * changes from 2.0 + * + * Revision 1.7 1998/09/30 22:24:48 keil + * Fix missing line in setstack* + * + * Revision 1.6 1998/08/13 23:36:54 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 1.5 1998/05/25 12:58:21 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 1.4 1998/04/15 16:42:35 keil + * new init code + * new PCI init (2.1.94) + * * Revision 1.3 1998/02/12 23:08:05 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -25,15 +42,12 @@ #include "hscx.h" #include "isdnl1.h" #include <linux/pci.h> -#include <linux/bios32.h> #include <linux/interrupt.h> -#define fcstab ppp_crc16_table #include <linux/ppp_defs.h> -extern __u16 ppp_crc16_table[256]; /* from ppp code */ extern const char *CardType[]; -const char *NETjet_revision = "$Revision: 1.3 $"; +const char *NETjet_revision = "$Revision: 1.8 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -62,6 +76,12 @@ const char *NETjet_revision = "$Revision: 1.3 $"; #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_SIZE 512 @@ -115,6 +135,42 @@ ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) insb(cs->hw.njet.isac, data, size); } +__u16 fcstab[256] = +{ + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + static void WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) { @@ -146,25 +202,20 @@ void mode_tiger(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; - char tmp[64]; - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "Tiger mode %d bchan %d/%d", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "Tiger mode %d bchan %d/%d", mode, bc, bcs->channel); - debugl1(cs, tmp); - } bcs->mode = mode; bcs->channel = bc; switch (mode) { case (L1_MODE_NULL): fill_mem(bcs, bcs->hw.tiger.send, NETJET_DMA_SIZE, bc, 0xff); - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "Tiger stat rec %d/%d send %d", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "Tiger stat rec %d/%d send %d", bcs->hw.tiger.r_tot, bcs->hw.tiger.r_err, bcs->hw.tiger.s_tot); - debugl1(cs, tmp); - } if ((cs->bcs[0].mode == L1_MODE_NULL) && (cs->bcs[1].mode == L1_MODE_NULL)) { cs->hw.njet.dmactrl = 0; @@ -197,16 +248,14 @@ mode_tiger(struct BCState *bcs, int mode, int bc) test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag); break; } - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "tiger: set %x %x %x %x/%x pulse=%d", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "tiger: set %x %x %x %x/%x pulse=%d", bytein(cs->hw.njet.base + NETJET_DMACTRL), bytein(cs->hw.njet.base + NETJET_IRQMASK0), bytein(cs->hw.njet.base + NETJET_IRQSTAT0), 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)); - debugl1(cs, tmp); - } } static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) @@ -266,7 +315,7 @@ static void printframe(struct IsdnCardState *cs, u_char *buf, int count, char *s val >>= 1;\ } -static void make_raw_data(struct BCState *bcs) { +static int make_raw_data(struct BCState *bcs) { register u_int i,s_cnt=0; register u_char j; register u_char val; @@ -274,13 +323,15 @@ static void make_raw_data(struct BCState *bcs) { register u_char s_val = 0; register u_char bitcnt = 0; u_int fcs; - char tmp[64]; - + if (!bcs->tx_skb) { + debugl1(bcs->cs, "tiger make_raw: NULL skb"); + return(1); + } bcs->hw.tiger.sendbuf[s_cnt++] = HDLC_FLAG_VALUE; fcs = PPP_INITFCS; - for (i=0; i<bcs->hw.tiger.tx_skb->len; i++) { - val = bcs->hw.tiger.tx_skb->data[i]; + for (i=0; i<bcs->tx_skb->len; i++) { + val = bcs->tx_skb->data[i]; fcs = PPP_FCS (fcs, val); MAKE_RAW_BYTE; } @@ -303,11 +354,9 @@ static void make_raw_data(struct BCState *bcs) { } val >>= 1; } - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger make_raw: in %d out %d.%d", - bcs->hw.tiger.tx_skb->len, s_cnt, bitcnt); - debugl1(bcs->cs,tmp); - } + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger make_raw: in %ld out %d.%d", + bcs->tx_skb->len, s_cnt, bitcnt); if (bitcnt) { while (8>bitcnt++) { s_val >>= 1; @@ -316,8 +365,9 @@ static void make_raw_data(struct BCState *bcs) { bcs->hw.tiger.sendbuf[s_cnt++] = s_val; } bcs->hw.tiger.sendcnt = s_cnt; - bcs->tx_cnt -= bcs->hw.tiger.tx_skb->len; + bcs->tx_cnt -= bcs->tx_skb->len; bcs->hw.tiger.sp = bcs->hw.tiger.sendbuf; + return(0); } static void got_frame(struct BCState *bcs, int count) { @@ -349,7 +399,6 @@ static void read_raw(struct BCState *bcs, u_int *buf, int cnt){ register u_char r_val = bcs->hw.tiger.r_val; register u_int bitcnt = bcs->hw.tiger.r_bitcnt; u_int *p = buf; - char tmp[64]; for (i=0;i<cnt;i++) { val = bcs->channel ? ((*p>>8) & 0xff) : (*p & 0xff); @@ -370,11 +419,9 @@ static void read_raw(struct BCState *bcs, u_int *buf, int cnt){ } else { r_one=0; state= HDLC_FLAG_SEARCH; - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger read_raw: zBit(%d,%d,%d) %x", + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger read_raw: zBit(%d,%d,%d) %x", bcs->hw.tiger.r_tot,i,j,val); - debugl1(bcs->cs,tmp); - } } } else if (state == HDLC_FLAG_SEARCH) { if (val & 1) { @@ -387,11 +434,9 @@ static void read_raw(struct BCState *bcs, u_int *buf, int cnt){ bitcnt=0; r_val=0; state=HDLC_FLAG_FOUND; - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger read_raw: flag(%d,%d,%d) %x", + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger read_raw: flag(%d,%d,%d) %x", bcs->hw.tiger.r_tot,i,j,val); - debugl1(bcs->cs,tmp); - } } r_one=0; } @@ -425,12 +470,10 @@ static void read_raw(struct BCState *bcs, u_int *buf, int cnt){ bcs->hw.tiger.r_fcs = PPP_INITFCS; bcs->hw.tiger.rcvbuf[0] = r_val; bcs->hw.tiger.r_fcs = PPP_FCS (bcs->hw.tiger.r_fcs, r_val); - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger read_raw: byte1(%d,%d,%d) rval %x val %x i %x", + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger read_raw: byte1(%d,%d,%d) rval %x val %x i %x", bcs->hw.tiger.r_tot,i,j,r_val,val, bcs->cs->hw.njet.irqstat0); - debugl1(bcs->cs,tmp); - } } } else if (state == HDLC_FRAME_FOUND) { if (val & 1) { @@ -453,11 +496,9 @@ static void read_raw(struct BCState *bcs, u_int *buf, int cnt){ state=HDLC_FLAG_SEARCH; bcs->hw.tiger.r_err++; } else { - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger frame end(%d,%d): fcs(%x) i %x", + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger frame end(%d,%d): fcs(%x) i %x", i,j,bcs->hw.tiger.r_fcs, bcs->cs->hw.njet.irqstat0); - debugl1(bcs->cs, tmp); - } if (bcs->hw.tiger.r_fcs == PPP_GOODFCS) { got_frame(bcs, (bitcnt>>3)-3); } else @@ -509,7 +550,15 @@ static void read_tiger(struct IsdnCardState *cs) { u_int *p; int cnt = NETJET_DMA_SIZE/2; - if (cs->hw.njet.irqstat0 & 4) + if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_READ) { + debugl1(cs,"tiger warn read double dma %x/%x", + cs->hw.njet.irqstat0, cs->hw.njet.last_is0); + return; + } else { + cs->hw.njet.last_is0 &= ~NETJET_IRQM0_READ; + cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ); + } + if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ_1) p = cs->bcs[0].hw.tiger.rec + NETJET_DMA_SIZE - 1; else p = cs->bcs[0].hw.tiger.rec + cnt - 1; @@ -517,32 +566,28 @@ static void read_tiger(struct IsdnCardState *cs) { read_raw(cs->bcs, p, cnt); if (cs->bcs[1].mode == L1_MODE_HDLC) read_raw(cs->bcs + 1, p, cnt); - cs->hw.njet.irqstat0 &= 0xf3; + cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_READ; } static void write_raw(struct BCState *bcs, u_int *buf, int cnt); static void fill_dma(struct BCState *bcs) { - char tmp[64]; register u_int *p, *sp; register int cnt; - if (!bcs->hw.tiger.tx_skb) + if (!bcs->tx_skb) return; - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger fill_dma1: c%d %4x", bcs->channel, + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger fill_dma1: c%d %4x", bcs->channel, bcs->Flag); - debugl1(bcs->cs,tmp); - } if (test_and_set_bit(BC_FLG_BUSY, &bcs->Flag)) return; - make_raw_data(bcs); - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger fill_dma2: c%d %4x", bcs->channel, + if (make_raw_data(bcs)) + return; + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger fill_dma2: c%d %4x", bcs->channel, bcs->Flag); - debugl1(bcs->cs,tmp); - } if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) { write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free); } else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) { @@ -582,17 +627,14 @@ static void fill_dma(struct BCState *bcs) } write_raw(bcs, p, cnt); } - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger fill_dma3: c%d %4x", bcs->channel, + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger fill_dma3: c%d %4x", bcs->channel, bcs->Flag); - debugl1(bcs->cs,tmp); - } } static void write_raw(struct BCState *bcs, u_int *buf, int cnt) { u_int mask, val, *p=buf; u_int i, s_cnt; - char tmp[64]; if (cnt <= 0) return; @@ -617,26 +659,23 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) { p = bcs->hw.tiger.send; } bcs->hw.tiger.s_tot += s_cnt; - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger write_raw: c%d %x-%x %d/%d %d %x", bcs->channel, - (u_int)buf, (u_int)p, s_cnt, cnt, bcs->hw.tiger.sendcnt, - bcs->cs->hw.njet.irqstat0); - debugl1(bcs->cs,tmp); - } + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger write_raw: c%d %x-%x %d/%d %d %x", bcs->channel, + (u_int)buf, (u_int)p, s_cnt, cnt, + bcs->hw.tiger.sendcnt, bcs->cs->hw.njet.irqstat0); if (bcs->cs->debug & L1_DEB_HSCX_FIFO) printframe(bcs->cs, bcs->hw.tiger.sp, s_cnt, "snd"); bcs->hw.tiger.sp += s_cnt; bcs->hw.tiger.sendp = p; if (!bcs->hw.tiger.sendcnt) { - if (!bcs->hw.tiger.tx_skb) { - sprintf(tmp,"tiger write_raw: NULL skb s_cnt %d", s_cnt); - debugl1(bcs->cs, tmp); + if (!bcs->tx_skb) { + debugl1(bcs->cs,"tiger write_raw: NULL skb s_cnt %d", s_cnt); } else { if (bcs->st->lli.l1writewakeup && - (PACKET_NOACK != bcs->hw.tiger.tx_skb->pkt_type)) - bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.tiger.tx_skb->len); - dev_kfree_skb(bcs->hw.tiger.tx_skb); - bcs->hw.tiger.tx_skb = NULL; + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); + dev_kfree_skb(bcs->tx_skb); + bcs->tx_skb = NULL; } test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); bcs->hw.tiger.free = cnt - s_cnt; @@ -646,7 +685,7 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) { test_and_clear_bit(BC_FLG_HALF, &bcs->Flag); test_and_set_bit(BC_FLG_NOFRAME, &bcs->Flag); } - if ((bcs->hw.tiger.tx_skb = skb_dequeue(&bcs->squeue))) { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { fill_dma(bcs); } else { mask ^= 0xffffffff; @@ -656,11 +695,9 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) { if (p>bcs->hw.tiger.s_end) p = bcs->hw.tiger.send; } - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "tiger write_raw: fill rest %d", + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs, "tiger write_raw: fill rest %d", cnt - s_cnt); - debugl1(bcs->cs,tmp); - } } bcs->event |= 1 << B_XMTBUFREADY; queue_task(&bcs->tqueue, &tq_immediate); @@ -671,24 +708,28 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) { test_and_set_bit(BC_FLG_HALF, &bcs->Flag); fill_mem(bcs, buf, cnt, bcs->channel, 0xff); bcs->hw.tiger.free += cnt; - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger write_raw: fill half"); - debugl1(bcs->cs,tmp); - } + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger write_raw: fill half"); } else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) { test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag); fill_mem(bcs, buf, cnt, bcs->channel, 0xff); - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger write_raw: fill full"); - debugl1(bcs->cs,tmp); - } + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger write_raw: fill full"); } } static void write_tiger(struct IsdnCardState *cs) { u_int *p, cnt = NETJET_DMA_SIZE/2; - if (cs->hw.njet.irqstat0 & 1) + if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_WRITE) { + debugl1(cs,"tiger warn write double dma %x/%x", + cs->hw.njet.irqstat0, cs->hw.njet.last_is0); + return; + } else { + cs->hw.njet.last_is0 &= ~NETJET_IRQM0_WRITE; + cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE); + } + if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE_1) p = cs->bcs[0].hw.tiger.send + NETJET_DMA_SIZE - 1; else p = cs->bcs[0].hw.tiger.send + cnt - 1; @@ -696,7 +737,7 @@ static void write_tiger(struct IsdnCardState *cs) { write_raw(cs->bcs, p, cnt); if (cs->bcs[1].mode == L1_MODE_HDLC) write_raw(cs->bcs + 1, p, cnt); - cs->hw.njet.irqstat0 &= 0xfc; + cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_WRITE; } static void @@ -706,45 +747,58 @@ tiger_l2l1(struct PStack *st, int pr, void *arg) long flags; switch (pr) { - case (PH_DATA_REQ): + case (PH_DATA | REQUEST): save_flags(flags); cli(); - if (st->l1.bcs->hw.tiger.tx_skb) { + if (st->l1.bcs->tx_skb) { skb_queue_tail(&st->l1.bcs->squeue, skb); restore_flags(flags); } else { - st->l1.bcs->hw.tiger.tx_skb = skb; + st->l1.bcs->tx_skb = skb; st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); restore_flags(flags); } break; - case (PH_PULL_IND): - if (st->l1.bcs->hw.tiger.tx_skb) { + case (PH_PULL | INDICATION): + if (st->l1.bcs->tx_skb) { printk(KERN_WARNING "tiger_l2l1: this shouldn't happen\n"); break; } save_flags(flags); cli(); - st->l1.bcs->hw.tiger.tx_skb = skb; + st->l1.bcs->tx_skb = skb; st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); restore_flags(flags); break; - case (PH_PULL_REQ): - if (!st->l1.bcs->hw.tiger.tx_skb) { + case (PH_PULL | REQUEST): + if (!st->l1.bcs->tx_skb) { test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL_CNF, NULL); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); } else test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; + case (PH_ACTIVATE | REQUEST): + test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + mode_tiger(st->l1.bcs, st->l1.mode, st->l1.bc); + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | REQUEST): + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | CONFIRM): + test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + mode_tiger(st->l1.bcs, 0, st->l1.bc); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); + break; } } + void close_tigerstate(struct BCState *bcs) { - struct sk_buff *skb; - - mode_tiger(bcs, 0, 0); + mode_tiger(bcs, 0, bcs->channel); if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { if (bcs->hw.tiger.rcvbuf) { kfree(bcs->hw.tiger.rcvbuf); @@ -754,32 +808,26 @@ close_tigerstate(struct BCState *bcs) kfree(bcs->hw.tiger.sendbuf); bcs->hw.tiger.sendbuf = NULL; } - while ((skb = skb_dequeue(&bcs->rqueue))) { - dev_kfree_skb(skb); - } - while ((skb = skb_dequeue(&bcs->squeue))) { - dev_kfree_skb(skb); - } - if (bcs->hw.tiger.tx_skb) { - dev_kfree_skb(bcs->hw.tiger.tx_skb); - bcs->hw.tiger.tx_skb = NULL; + discard_queue(&bcs->rqueue); + discard_queue(&bcs->squeue); + if (bcs->tx_skb) { + dev_kfree_skb(bcs->tx_skb); + bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } } } static int -open_tigerstate(struct IsdnCardState *cs, int bc) +open_tigerstate(struct IsdnCardState *cs, struct BCState *bcs) { - struct BCState *bcs = cs->bcs + bc; - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - if (!(bcs->hw.tiger.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_KERNEL))) { + if (!(bcs->hw.tiger.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { printk(KERN_WARNING "HiSax: No memory for tiger.rcvbuf\n"); return (1); } - if (!(bcs->hw.tiger.sendbuf = kmalloc(RAW_BUFMAX, GFP_KERNEL))) { + if (!(bcs->hw.tiger.sendbuf = kmalloc(RAW_BUFMAX, GFP_ATOMIC))) { printk(KERN_WARNING "HiSax: No memory for tiger.sendbuf\n"); return (1); @@ -787,7 +835,7 @@ open_tigerstate(struct IsdnCardState *cs, int bc) skb_queue_head_init(&bcs->rqueue); skb_queue_head_init(&bcs->squeue); } - bcs->hw.tiger.tx_skb = NULL; + bcs->tx_skb = NULL; bcs->hw.tiger.sendcnt = 0; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); bcs->event = 0; @@ -795,34 +843,17 @@ open_tigerstate(struct IsdnCardState *cs, int bc) return (0); } -static void -tiger_manl1(struct PStack *st, int pr, - void *arg) -{ - switch (pr) { - case (PH_ACTIVATE_REQ): - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - mode_tiger(st->l1.bcs, st->l1.mode, st->l1.bc); - st->l1.l1man(st, PH_ACTIVATE_CNF, NULL); - break; - case (PH_DEACTIVATE_REQ): - if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) - mode_tiger(st->l1.bcs, 0, 0); - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - break; - } -} - int setstack_tiger(struct PStack *st, struct BCState *bcs) { - if (open_tigerstate(st->l1.hardware, bcs->channel)) + bcs->channel = st->l1.bc; + if (open_tigerstate(st->l1.hardware, bcs)) return (-1); st->l1.bcs = bcs; st->l2.l2l1 = tiger_l2l1; - st->ma.manl1 = tiger_manl1; setstack_manager(st); bcs->st = st; + setstack_l1_B(st); return (0); } @@ -830,8 +861,6 @@ setstack_tiger(struct PStack *st, struct BCState *bcs) __initfunc(void inittiger(struct IsdnCardState *cs)) { - char tmp[128]; - if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_SIZE * sizeof(unsigned int), GFP_KERNEL | GFP_DMA))) { printk(KERN_WARNING @@ -845,9 +874,8 @@ inittiger(struct IsdnCardState *cs)) cs->bcs[1].hw.tiger.s_end = cs->bcs[0].hw.tiger.s_end; memset(cs->bcs[0].hw.tiger.send, 0xff, NETJET_DMA_SIZE * sizeof(unsigned int)); - sprintf(tmp, "tiger: send buf %x - %x", (u_int)cs->bcs[0].hw.tiger.send, + debugl1(cs, "tiger: send buf %x - %x", (u_int)cs->bcs[0].hw.tiger.send, (u_int)(cs->bcs[0].hw.tiger.send + NETJET_DMA_SIZE - 1)); - debugl1(cs, tmp); outl(virt_to_bus(cs->bcs[0].hw.tiger.send), cs->hw.njet.base + NETJET_DMA_READ_START); outl(virt_to_bus(cs->bcs[0].hw.tiger.s_irq), @@ -860,9 +888,8 @@ inittiger(struct IsdnCardState *cs)) "HiSax: No memory for tiger.rec\n"); return; } - sprintf(tmp, "tiger: rec buf %x - %x", (u_int)cs->bcs[0].hw.tiger.rec, + debugl1(cs, "tiger: rec buf %x - %x", (u_int)cs->bcs[0].hw.tiger.rec, (u_int)(cs->bcs[0].hw.tiger.rec + NETJET_DMA_SIZE - 1)); - debugl1(cs, tmp); cs->bcs[1].hw.tiger.rec = cs->bcs[0].hw.tiger.rec; memset(cs->bcs[0].hw.tiger.rec, 0xff, NETJET_DMA_SIZE * sizeof(unsigned int)); outl(virt_to_bus(cs->bcs[0].hw.tiger.rec), @@ -871,11 +898,10 @@ inittiger(struct IsdnCardState *cs)) cs->hw.njet.base + NETJET_DMA_WRITE_IRQ); outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_SIZE - 1), cs->hw.njet.base + NETJET_DMA_WRITE_END); - sprintf(tmp, "tiger: dmacfg %x/%x pulse=%d", + debugl1(cs, "tiger: dmacfg %x/%x pulse=%d", inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); - debugl1(cs, tmp); cs->hw.njet.last_is0 = 0; cs->bcs[0].BC_SetStack = setstack_tiger; cs->bcs[1].BC_SetStack = setstack_tiger; @@ -906,8 +932,8 @@ static void netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u_char val, sval, stat = 1; - char tmp[128]; + u_char val, sval; + long flags; if (!cs) { printk(KERN_WARNING "NETjet: Spurious interrupt!\n"); @@ -916,49 +942,49 @@ netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs) if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) & NETJET_ISACIRQ)) { val = ReadISAC(cs, ISAC_ISTA); - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "tiger: i1 %x %x", sval, val); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "tiger: i1 %x %x", sval, val); if (val) { isac_interrupt(cs, val); - stat |= 2; + WriteISAC(cs, ISAC_MASK, 0xFF); + WriteISAC(cs, ISAC_MASK, 0x0); } } - if ((cs->hw.njet.irqstat0 = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) { -/* sprintf(tmp, "tiger: ist0 %x %x %x %x/%x pulse=%d", + 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)); - debugl1(cs, tmp); */ - if (cs->hw.njet.last_is0 & cs->hw.njet.irqstat0 & 0xf) { - sprintf(tmp, "tiger: ist0 %x->%x irq lost", - cs->hw.njet.last_is0, cs->hw.njet.irqstat0); - debugl1(cs, tmp); - } - cs->hw.njet.last_is0 = cs->hw.njet.irqstat0; /* 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 & 0x0c) +*/ if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) read_tiger(cs); - if (cs->hw.njet.irqstat0 & 0x03) + 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); } -*/ if (stat & 2) { - WriteISAC(cs, ISAC_MASK, 0xFF); - WriteISAC(cs, ISAC_MASK, 0x0); - } +*/ } static void @@ -1006,11 +1032,13 @@ NETjet_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); case CARD_SETIRQ: return(request_irq(cs->irq, &netjet_interrupt, - I4L_IRQ_FLAG, "HiSax", cs)); + I4L_IRQ_FLAG | SA_SHIRQ, "HiSax", cs)); 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); @@ -1020,7 +1048,7 @@ NETjet_card_msg(struct IsdnCardState *cs, int mt, void *arg) -static int pci_index __initdata = 0; +static struct pci_dev *dev_netjet __initdata = NULL; __initfunc(int setup_netjet(struct IsdnCard *card)) @@ -1028,52 +1056,37 @@ setup_netjet(struct IsdnCard *card)) int bytecnt; struct IsdnCardState *cs = card->cs; char tmp[64]; -#if CONFIG_PCI - u_char pci_bus, pci_device_fn, pci_irq; - u_int pci_ioaddr, found; -#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 - found = 0; - for (; pci_index < 0xff; pci_index++) { - if (pcibios_find_device(PCI_VENDOR_TRAVERSE_TECH, - PCI_NETJET_ID, pci_index, &pci_bus, &pci_device_fn) - == PCIBIOS_SUCCESSFUL) - found = 1; - else - break; - /* get IRQ */ - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq); - - /* get IO address */ - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &pci_ioaddr); - if (found) - break; - } - if (!found) { - printk(KERN_WARNING "NETjet: No PCI card found\n"); + if (!pci_present()) { + printk(KERN_ERR "Netjet: no PCI bus present\n"); return(0); } - if (!pci_irq) { + if ((dev_netjet = pci_find_device(PCI_VENDOR_TRAVERSE_TECH, + PCI_NETJET_ID, dev_netjet))) { + cs->irq = dev_netjet->irq; + if (!cs->irq) { printk(KERN_WARNING "NETjet: No IRQ for PCI card found\n"); return(0); } - if (!pci_ioaddr) { + cs->hw.njet.base = dev_netjet->base_address[0] & + PCI_BASE_ADDRESS_IO_MASK; + if (!cs->hw.njet.base) { printk(KERN_WARNING "NETjet: No IO-Adr for PCI card found\n"); return(0); } - pci_ioaddr &= ~3; /* remove io/mem flag */ - cs->hw.njet.base = pci_ioaddr; - cs->hw.njet.auxa = pci_ioaddr + NETJET_AUXDATA; - cs->hw.njet.isac = pci_ioaddr | NETJET_ISAC_OFF; - cs->irq = pci_irq; + 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 card found\n"); + return(0); + } #else printk(KERN_WARNING "NETjet: NO_PCI_BIOS\n"); printk(KERN_WARNING "NETjet: unable to config NETJET PCI\n"); diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c index 59a8a94e3..13717f856 100644 --- a/drivers/isdn/hisax/niccy.c +++ b/drivers/isdn/hisax/niccy.c @@ -1,4 +1,4 @@ -/* $Id: niccy.c,v 1.2 1998/02/11 17:31:04 keil Exp $ +/* $Id: niccy.c,v 1.4 1998/04/16 19:16:48 keil Exp $ * niccy.c low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and * compatible (SAGEM cybermodem) @@ -8,24 +8,28 @@ * Thanks to Dr. Neuhaus and SAGEM for informations * * $Log: niccy.c,v $ - * Revision 1.2 1998/02/11 17:31:04 keil - * new file + * Revision 1.4 1998/04/16 19:16:48 keil + * need config.h * + * Revision 1.3 1998/04/15 16:42:59 keil + * new init code * + * Revision 1.2 1998/02/11 17:31:04 keil + * new file * */ -#include <linux/config.h> + #define __NO_VERSION__ +#include <linux/config.h> #include "hisax.h" #include "isac.h" #include "hscx.h" #include "isdnl1.h" #include <linux/pci.h> -#include <linux/bios32.h> extern const char *CardType[]; -const char *niccy_revision = "$Revision: 1.2 $"; +const char *niccy_revision = "$Revision: 1.4 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -44,6 +48,10 @@ const char *niccy_revision = "$Revision: 1.2 $"; /* PCI stuff */ #define PCI_VENDOR_DR_NEUHAUS 0x1267 #define PCI_NICCY_ID 0x1016 +#define PCI_IRQ_CTRL_REG 0x38 +#define PCI_IRQ_ENABLE 0x1f00 +#define PCI_IRQ_DISABLE 0xff0000 +#define PCI_IRQ_ASSERT 0x800000 static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off) @@ -152,6 +160,13 @@ niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs) printk(KERN_WARNING "Niccy: Spurious interrupt!\n"); return; } + if (cs->subtyp == NICCY_PCI) { + int ival; + ival = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); + if (!(ival & PCI_IRQ_ASSERT)) /* IRQ not for us (shared) */ + return; + outl(ival, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); + } val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40); Start_HSCX: if (val) { @@ -191,9 +206,15 @@ niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs) void release_io_niccy(struct IsdnCardState *cs) { - if (cs->subtyp == NICCY_PCI) + if (cs->subtyp == NICCY_PCI) { + int val; + + val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); + val &= PCI_IRQ_DISABLE; + outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); + release_region(cs->hw.niccy.cfg_reg, 0x80); release_region(cs->hw.niccy.isac, 4); - else { + } else { release_region(cs->hw.niccy.isac, 2); release_region(cs->hw.niccy.isac_ale, 2); } @@ -202,12 +223,20 @@ release_io_niccy(struct IsdnCardState *cs) static void niccy_reset(struct IsdnCardState *cs) { - // No reset procedure known + int val, nval; + + val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); + nval = val | PCI_IRQ_ENABLE; + outl(nval, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); + + inithscxisac(cs, 3); } static int niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg) { + int imode; + switch (mt) { case CARD_RESET: niccy_reset(cs); @@ -216,13 +245,15 @@ niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg) release_io_niccy(cs); return(0); case CARD_SETIRQ: + if (cs->subtyp == NICCY_PCI) + imode = I4L_IRQ_FLAG | SA_SHIRQ; + else + imode = I4L_IRQ_FLAG; return(request_irq(cs->irq, &niccy_interrupt, - I4L_IRQ_FLAG, "HiSax", cs)); + imode, "HiSax", cs)); + break; case CARD_INIT: - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + niccy_reset(cs); return(0); case CARD_TEST: return(0); @@ -230,7 +261,7 @@ niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static int pci_index __initdata = 0; +static struct pci_dev *niccy_dev __initdata = NULL; __initfunc(int setup_niccy(struct IsdnCard *card)) @@ -272,49 +303,41 @@ setup_niccy(struct IsdnCard *card)) request_region(cs->hw.niccy.isac_ale, 2, "niccy addr"); } else { #if CONFIG_PCI - u_char pci_bus, pci_device_fn, pci_irq; u_int pci_ioaddr; + if (!pci_present()) { + printk(KERN_ERR "Niccy: no PCI bus present\n"); + return(0); + } + cs->subtyp = 0; - for (; pci_index < 0xff; pci_index++) { - if (pcibios_find_device(PCI_VENDOR_DR_NEUHAUS, - PCI_NICCY_ID, pci_index, &pci_bus, &pci_device_fn) - == PCIBIOS_SUCCESSFUL) - cs->subtyp = NICCY_PCI; - else - break; + if ((niccy_dev = pci_find_device(PCI_VENDOR_DR_NEUHAUS, + PCI_NICCY_ID, niccy_dev))) { /* get IRQ */ - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq); - - /* get IO address */ - /* if it won't work try the other PCI addresses - * PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_5 - */ - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_2, &pci_ioaddr); - if (cs->subtyp) - break; - } - if (!cs->subtyp) { - printk(KERN_WARNING "Niccy: No PCI card found\n"); + if (!niccy_dev->irq) { + printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n"); return(0); } - if (!pci_irq) { - printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n"); + cs->irq = niccy_dev->irq; + if (!niccy_dev->base_address[0]) { + printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n"); return(0); } - - if (!pci_ioaddr) { + cs->hw.niccy.cfg_reg = niccy_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + if (!niccy_dev->base_address[1]) { printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n"); return(0); } - pci_ioaddr &= ~3; /* remove io/mem flag */ + pci_ioaddr = niccy_dev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA; cs->hw.niccy.isac_ale = pci_ioaddr + ISAC_PCI_ADDR; cs->hw.niccy.hscx = pci_ioaddr + HSCX_PCI_DATA; cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR; - cs->irq = pci_irq; + cs->subtyp = NICCY_PCI; + } else { + printk(KERN_WARNING "Niccy: No PCI card found\n"); + return(0); + } if (check_region((cs->hw.niccy.isac), 4)) { printk(KERN_WARNING "HiSax: %s data port %x-%x already in use\n", @@ -324,6 +347,17 @@ setup_niccy(struct IsdnCard *card)) return (0); } else request_region(cs->hw.niccy.isac, 4, "niccy"); + if (check_region(cs->hw.niccy.cfg_reg, 0x80)) { + printk(KERN_WARNING + "HiSax: %s pci port %x-%x already in use\n", + CardType[card->typ], + cs->hw.niccy.cfg_reg, + cs->hw.niccy.cfg_reg + 0x80); + release_region(cs->hw.niccy.isac, 4); + return (0); + } else { + request_region(cs->hw.niccy.cfg_reg, 0x80, "niccy pci"); + } #else printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n"); printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n"); @@ -334,7 +368,6 @@ setup_niccy(struct IsdnCard *card)) "HiSax: %s %s config irq:%d data:0x%X ale:0x%X\n", CardType[cs->typ], (cs->subtyp==1) ? "PnP":"PCI", cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale); - niccy_reset(cs); cs->readisac = &ReadISAC; cs->writeisac = &WriteISAC; cs->readisacfifo = &ReadISACfifo; diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c index a0ba3645a..d3c269a04 100644 --- a/drivers/isdn/hisax/q931.c +++ b/drivers/isdn/hisax/q931.c @@ -1,4 +1,4 @@ -/* $Id: q931.c,v 1.6 1997/07/27 21:09:44 keil Exp $ +/* $Id: q931.c,v 1.7 1998/11/15 23:55:17 keil Exp $ * q931.c code to decode ITU Q.931 call control messages * @@ -14,6 +14,9 @@ * * * $Log: q931.c,v $ + * Revision 1.7 1998/11/15 23:55:17 keil + * changes from 2.0 + * * Revision 1.6 1997/07/27 21:09:44 keil * move functions to isdnl3.c * @@ -159,7 +162,7 @@ struct MessageType mt_n0[] = {MT_N0_CLO_ACK, "CLOse ACKnowledge"} }; -int mt_n0_len = (sizeof(mt_n0) / sizeof(struct MessageType)); +#define MT_N0_LEN (sizeof(mt_n0) / sizeof(struct MessageType)) static struct MessageType mt_n1[] = @@ -196,7 +199,7 @@ struct MessageType mt_n1[] = {MT_N1_STAT, "STATus"} }; -int mt_n1_len = (sizeof(mt_n1) / sizeof(struct MessageType)); +#define MT_N1_LEN (sizeof(mt_n1) / sizeof(struct MessageType)) static struct MessageType fac_1tr6[] = { @@ -220,9 +223,7 @@ static struct MessageType fac_1tr6[] = {FAC_Rueckwechsel, "Rueckwechsel"}, {FAC_Umleitung, "Umleitung"} }; -int fac_1tr6_len = (sizeof(fac_1tr6) / sizeof(struct MessageType)); - - +#define FAC_1TR6_LEN (sizeof(fac_1tr6) / sizeof(struct MessageType)) static int prbits(char *dest, u_char b, int start, int len) @@ -925,7 +926,7 @@ static struct InformationElement we_0[] = {WE0_userInfo, "User Info", general} }; -static int we_0_len = (sizeof(we_0) / sizeof(struct InformationElement)); +#define WE_0_LEN (sizeof(we_0) / sizeof(struct InformationElement)) static struct InformationElement we_6[] = { @@ -937,7 +938,7 @@ static struct InformationElement we_6[] = {WE6_statusCalled, "Status Called", general}, {WE6_addTransAttr, "Additional Transmission Attributes", general} }; -static int we_6_len = (sizeof(we_6) / sizeof(struct InformationElement)); +#define WE_6_LEN (sizeof(we_6) / sizeof(struct InformationElement)) int QuickHex(char *txt, u_char * p, int cnt) @@ -964,39 +965,92 @@ QuickHex(char *txt, u_char * p, int cnt) } void -LogFrame(struct IsdnCardState *sp, u_char * buf, int size) +LogFrame(struct IsdnCardState *cs, u_char * buf, int size) { char *dp; if (size < 1) return; - dp = sp->dlogspace; - if (size < 4096 / 3 - 10) { - dp += sprintf(dp, "HEX:"); + dp = cs->dlog; + if (size < MAX_DLOG_SPACE / 3 - 10) { + *dp++ = 'H'; + *dp++ = 'E'; + *dp++ = 'X'; + *dp++ = ':'; dp += QuickHex(dp, buf, size); dp--; *dp++ = '\n'; *dp = 0; + HiSax_putstatus(cs, NULL, cs->dlog); } else - sprintf(dp, "LogFrame: warning Frame too big (%d)\n", - size); - HiSax_putstatus(sp, sp->dlogspace); + HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size); } void -dlogframe(struct IsdnCardState *sp, u_char * buf, int size, char *comment) +dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir) { - u_char *bend = buf + size; + u_char *bend, *buf; char *dp; unsigned char pd, cr_l, cr, mt; - int i, cs = 0, cs_old = 0, cs_fest = 0; + unsigned char sapi, tei, ftyp; + int i, cset = 0, cs_old = 0, cs_fest = 0; + int size, finish = 0; - if (size < 1) + if (skb->len < 3) return; /* display header */ - dp = sp->dlogspace; - dp += sprintf(dp, "%s\n", comment); - + dp = cs->dlog; + dp += jiftime(dp, jiffies); + *dp++ = ' '; + sapi = skb->data[0] >> 2; + tei = skb->data[1] >> 1; + ftyp = skb->data[2]; + buf = skb->data; + dp += sprintf(dp, "frame %s ", dir ? "network->user" : "user->network"); + size = skb->len; + + if (tei == GROUP_TEI) { + if (sapi == CTRL_SAPI) { /* sapi 0 */ + if (ftyp == 3) { + dp += sprintf(dp, "broadcast\n"); + buf += 3; + size -= 3; + } else { + dp += sprintf(dp, "no UI broadcast\n"); + finish = 1; + } + } else if (sapi == TEI_SAPI) { + dp += sprintf(dp, "tei managment\n"); + finish = 1; + } else { + dp += sprintf(dp, "unknown sapi %d broadcast\n", sapi); + finish = 1; + } + } else { + if (sapi == CTRL_SAPI) { + if (!(ftyp & 1)) { /* IFrame */ + dp += sprintf(dp, "with tei %d\n", tei); + buf += 4; + size -= 4; + } else { + dp += sprintf(dp, "SFrame with tei %d\n", tei); + finish = 1; + } + } else { + dp += sprintf(dp, "unknown sapi %d tei %d\n", sapi, tei); + finish = 1; + } + } + bend = skb->data + skb->len; + if (buf >= bend) { + dp += sprintf(dp, "frame too short\n"); + finish = 1; + } + if (finish) { + *dp = 0; + HiSax_putstatus(cs, NULL, cs->dlog); + return; + } if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */ /* locate message type */ pd = *buf++; @@ -1007,11 +1061,11 @@ dlogframe(struct IsdnCardState *sp, u_char * buf, int size, char *comment) cr = 0; mt = *buf++; if (pd == PROTO_DIS_N0) { /* N0 */ - for (i = 0; i < mt_n0_len; i++) + for (i = 0; i < MT_N0_LEN; i++) if (mt_n0[i].nr == mt) break; /* display message type if it exists */ - if (i == mt_n0_len) + if (i == MT_N0_LEN) dp += sprintf(dp, "callref %d %s size %d unknown message type N0 %x!\n", cr & 0x7f, (cr & 0x80) ? "called" : "caller", size, mt); @@ -1020,11 +1074,11 @@ dlogframe(struct IsdnCardState *sp, u_char * buf, int size, char *comment) cr & 0x7f, (cr & 0x80) ? "called" : "caller", size, mt_n0[i].descr); } else { /* N1 */ - for (i = 0; i < mt_n1_len; i++) + for (i = 0; i < MT_N1_LEN; i++) if (mt_n1[i].nr == mt) break; /* display message type if it exists */ - if (i == mt_n1_len) + if (i == MT_N1_LEN) dp += sprintf(dp, "callref %d %s size %d unknown message type N1 %x!\n", cr & 0x7f, (cr & 0x80) ? "called" : "caller", size, mt); @@ -1041,8 +1095,8 @@ dlogframe(struct IsdnCardState *sp, u_char * buf, int size, char *comment) switch ((*buf >> 4) & 7) { case 1: dp += sprintf(dp, " Shift %x\n", *buf & 0xf); - cs_old = cs; - cs = *buf & 7; + cs_old = cset; + cset = *buf & 7; cs_fest = *buf & 8; break; case 3: @@ -1066,33 +1120,33 @@ dlogframe(struct IsdnCardState *sp, u_char * buf, int size, char *comment) continue; } /* No, locate it in the table */ - if (cs == 0) { - for (i = 0; i < we_0_len; i++) + if (cset == 0) { + for (i = 0; i < WE_0_LEN; i++) if (*buf == we_0[i].nr) break; /* When found, give appropriate msg */ - if (i != we_0_len) { + if (i != WE_0_LEN) { dp += sprintf(dp, " %s\n", we_0[i].descr); dp += we_0[i].f(dp, buf); } else - dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]); - } else if (cs == 6) { - for (i = 0; i < we_6_len; i++) + dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); + } else if (cset == 6) { + for (i = 0; i < WE_6_LEN; i++) if (*buf == we_6[i].nr) break; /* When found, give appropriate msg */ - if (i != we_6_len) { + if (i != WE_6_LEN) { dp += sprintf(dp, " %s\n", we_6[i].descr); dp += we_6[i].f(dp, buf); } else - dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]); + dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); } else - dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]); + dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); /* Skip to next element */ if (cs_fest == 8) { - cs = cs_old; + cset = cs_old; cs_old = 0; cs_fest = 0; } @@ -1170,6 +1224,6 @@ dlogframe(struct IsdnCardState *sp, u_char * buf, int size, char *comment) } else { dp += sprintf(dp, "Unknown protocol %x!", buf[0]); } - dp += sprintf(dp, "\n"); - HiSax_putstatus(sp, sp->dlogspace); + *dp = 0; + HiSax_putstatus(cs, NULL, cs->dlog); } diff --git a/drivers/isdn/hisax/rawhdlc.c b/drivers/isdn/hisax/rawhdlc.c index b878cb699..17ac5c602 100644 --- a/drivers/isdn/hisax/rawhdlc.c +++ b/drivers/isdn/hisax/rawhdlc.c @@ -1,4 +1,4 @@ -/* $Id: rawhdlc.c,v 1.2 1998/02/09 10:53:51 keil Exp $ +/* $Id: rawhdlc.c,v 1.3 1998/06/17 19:51:21 he Exp $ * rawhdlc.c support routines for cards that don't support HDLC * diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c index 46d3edaf0..85e64001a 100644 --- a/drivers/isdn/hisax/sedlbauer.c +++ b/drivers/isdn/hisax/sedlbauer.c @@ -1,11 +1,14 @@ -/* $Id: sedlbauer.c,v 1.6 1998/02/09 18:46:06 keil Exp $ +/* $Id: sedlbauer.c,v 1.9 1998/11/15 23:55:20 keil Exp $ * sedlbauer.c low level stuff for Sedlbauer cards - * includes Support for the Sedlbauer Speed Star - * derived from the original file dynalink.c from Karsten Keil + * includes support for the Sedlbauer speed star (speed star II), + * support for the Sedlbauer speed fax+, + * support for the Sedlbauer ISDN-Controller PC/104 and + * support for the Sedlbauer speed pci + * derived from the original file asuscom.c from Karsten Keil * * Copyright (C) 1997,1998 Marcus Niemann (for the modifications to - * the original file dynalink.c) + * the original file asuscom.c) * * Author Marcus Niemann (niemann@www-bib.fh-bielefeld.de) * @@ -14,6 +17,15 @@ * Edgar Toernig * * $Log: sedlbauer.c,v $ + * Revision 1.9 1998/11/15 23:55:20 keil + * changes from 2.0 + * + * Revision 1.8 1998/08/13 23:34:51 keil + * starting speedfax+ (ISAR) support + * + * Revision 1.7 1998/04/15 16:44:33 keil + * new init code + * * Revision 1.6 1998/02/09 18:46:06 keil * Support for Sedlbauer PCMCIA (Marcus Niemann) * @@ -35,36 +47,91 @@ * */ +/* Supported cards: + * Card: Chip: Configuration: Comment: + * --------------------------------------------------------------------- + * Speed Card ISAC_HSCX DIP-SWITCH + * Speed Win ISAC_HSCX ISAPNP + * Speed Fax+ ISAC_ISAR ISAPNP #HDLC works# + * Speed Star ISAC_HSCX CARDMGR + * Speed Win2 IPAC ISAPNP + * ISDN PC/104 IPAC DIP-SWITCH + * Speed Star2 IPAC CARDMGR + * Speed PCI IPAC PNP + * + * Important: + * For the sedlbauer speed fax+ to work properly you have to download + * the firmware onto the card. + * For example: hisaxctrl <DriverID> 9 ISAR.BIN +*/ + +#define SEDLBAUER_PCI 1 + #define __NO_VERSION__ +#include <linux/config.h> #include "hisax.h" #include "isac.h" +#include "ipac.h" #include "hscx.h" +#include "isar.h" #include "isdnl1.h" +#include <linux/pci.h> extern const char *CardType[]; -const char *Sedlbauer_revision = "$Revision: 1.6 $"; +const char *Sedlbauer_revision = "$Revision: 1.9 $"; const char *Sedlbauer_Types[] = -{"None", "Speed Card", "Speed Win", "Speed Star"}; + {"None", "speed card/win", "speed star", "speed fax+", + "speed win II / ISDN PC/104", "speed star II", "speed pci"}; + +#ifdef SEDLBAUER_PCI +#define PCI_VENDOR_SEDLBAUER 0xe159 +#define PCI_SPEEDPCI_ID 0x02 +#endif -#define SEDL_SPEED_CARD 1 -#define SEDL_SPEED_WIN 2 -#define SEDL_SPEED_STAR 3 +#define SEDL_SPEED_CARD_WIN 1 +#define SEDL_SPEED_STAR 2 +#define SEDL_SPEED_FAX 3 +#define SEDL_SPEED_WIN2_PC104 4 +#define SEDL_SPEED_STAR2 5 +#define SEDL_SPEED_PCI 6 + +#define SEDL_CHIP_TEST 0 +#define SEDL_CHIP_ISAC_HSCX 1 +#define SEDL_CHIP_ISAC_ISAR 2 +#define SEDL_CHIP_IPAC 3 + +#define SEDL_BUS_ISA 1 +#define SEDL_BUS_PCI 2 +#define SEDL_BUS_PCMCIA 3 #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) -#define SEDL_RESET_ON 0 -#define SEDL_RESET_OFF 1 -#define SEDL_ISAC 2 -#define SEDL_HSCX 3 -#define SEDL_ADR 4 +#define SEDL_HSCX_ISA_RESET_ON 0 +#define SEDL_HSCX_ISA_RESET_OFF 1 +#define SEDL_HSCX_ISA_ISAC 2 +#define SEDL_HSCX_ISA_HSCX 3 +#define SEDL_HSCX_ISA_ADR 4 + +#define SEDL_HSCX_PCMCIA_RESET 0 +#define SEDL_HSCX_PCMCIA_ISAC 1 +#define SEDL_HSCX_PCMCIA_HSCX 2 +#define SEDL_HSCX_PCMCIA_ADR 4 + +#define SEDL_ISAR_ISA_ISAC 4 +#define SEDL_ISAR_ISA_ISAR 6 +#define SEDL_ISAR_ISA_ADR 8 +#define SEDL_ISAR_ISA_ISAR_RESET_ON 10 +#define SEDL_ISAR_ISA_ISAR_RESET_OFF 12 -#define SEDL_PCMCIA_RESET 0 -#define SEDL_PCMCIA_ISAC 1 -#define SEDL_PCMCIA_HSCX 2 -#define SEDL_PCMCIA_ADR 4 +#define SEDL_IPAC_ANY_ADR 0 +#define SEDL_IPAC_ANY_IPAC 2 + +#define SEDL_IPAC_PCI_BASE 0 +#define SEDL_IPAC_PCI_ADR 0xc0 +#define SEDL_IPAC_PCI_IPAC 0xc8 #define SEDL_RESET 0x3 /* same as DOS driver */ @@ -139,6 +206,29 @@ WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) } static u_char +ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) +{ + return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80));} + +static void +WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) +{ + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80, value); +} + +static void +ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) +{ + readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size); +} + +static void +WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) +{ + writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size); +} + +static u_char ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { return (readreg(cs->hw.sedl.adr, @@ -152,6 +242,34 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0), value); } +/* ISAR access routines + * mode = 0 access with IRQ on + * mode = 1 access with IRQ off + * mode = 2 access with IRQ off and using last offset + */ + +static u_char +ReadISAR(struct IsdnCardState *cs, int mode, u_char offset) +{ + if (mode == 0) + return (readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset)); + else if (mode == 1) + byteout(cs->hw.sedl.adr, offset); + return(bytein(cs->hw.sedl.hscx)); +} + +static void +WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value) +{ + if (mode == 0) + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset, value); + else { + if (mode == 1) + byteout(cs->hw.sedl.adr, offset); + byteout(cs->hw.sedl.hscx, value); + } +} + /* * fast interrupt HSCX stuff goes here */ @@ -180,7 +298,7 @@ sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs) return; } - if ((cs->typ == ISDN_CTYPE_SEDLBAUER_PCMCIA) && (*cs->busy_flag == 1)) { + 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"); @@ -223,11 +341,101 @@ sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs) } } +static void +sedlbauer_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char ista, val, icnt = 20; + + if (!cs) { + printk(KERN_WARNING "Sedlbauer: Spurious interrupt!\n"); + return; + } + ista = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA); +Start_IPAC: + if (cs->debug & L1_DEB_IPAC) + debugl1(cs, "IPAC ISTA %02X", ista); + if (ista & 0x0f) { + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40); + if (ista & 0x01) + val |= 0x01; + if (ista & 0x04) + val |= 0x02; + if (ista & 0x08) + val |= 0x04; + if (val) + hscx_int_main(cs, val); + } + if (ista & 0x20) { + val = 0xfe & readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA | 0x80); + if (val) { + isac_interrupt(cs, val); + } + } + if (ista & 0x10) { + val = 0x01; + isac_interrupt(cs, val); + } + ista = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA); + if ((ista & 0x3f) && icnt) { + icnt--; + goto Start_IPAC; + } + if (!icnt) + printk(KERN_WARNING "Sedlbauer IRQ LOOP\n"); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xFF); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xC0); +} + +static void +sedlbauer_interrupt_isar(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val; + int cnt = 20; + + if (!cs) { + printk(KERN_WARNING "Sedlbauer: Spurious interrupt!\n"); + return; + } + + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT); + Start_ISAR: + if (val & ISAR_IRQSTA) + isar_int_main(cs); + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA); + Start_ISAC: + if (val) + isac_interrupt(cs, val); + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT); + if ((val & ISAR_IRQSTA) && --cnt) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "ISAR IntStat after IntRoutine"); + goto Start_ISAR; + } + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA); + if (val && --cnt) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC IntStat after IntRoutine"); + goto Start_ISAC; + } + if (!cnt) + printk(KERN_WARNING "Sedlbauer IRQ LOOP\n"); + + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, 0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, ISAR_IRQMSK); +} + void release_io_sedlbauer(struct IsdnCardState *cs) { - int bytecnt = 8; + int bytecnt = (cs->subtyp == SEDL_SPEED_FAX) ? 16 : 8; + if (cs->hw.sedl.bus == SEDL_BUS_PCI) { + bytecnt = 256; + } if (cs->hw.sedl.cfg_reg) release_region(cs->hw.sedl.cfg_reg, bytecnt); } @@ -237,16 +445,36 @@ reset_sedlbauer(struct IsdnCardState *cs) { long flags; - if (cs->typ != ISDN_CTYPE_SEDLBAUER_PCMCIA) { - byteout(cs->hw.sedl.reset_on, SEDL_RESET); /* Reset On */ - save_flags(flags); - sti(); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - byteout(cs->hw.sedl.reset_off, 0); /* Reset Off */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - restore_flags(flags); + printk(KERN_INFO "Sedlbauer: resetting card\n"); + + if (!((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) && + (cs->hw.sedl.chip == SEDL_CHIP_ISAC_HSCX))) { + if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) { + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x20); + save_flags(flags); + sti(); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x0); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_CONF, 0x0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ACFG, 0xff); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_AOE, 0x0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xc0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_PCFG, 0x12); + restore_flags(flags); + } else { + byteout(cs->hw.sedl.reset_on, SEDL_RESET); /* Reset On */ + save_flags(flags); + sti(); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + byteout(cs->hw.sedl.reset_off, 0); /* Reset Off */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + restore_flags(flags); + } } } @@ -261,94 +489,256 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg) release_io_sedlbauer(cs); return(0); case CARD_SETIRQ: - return(request_irq(cs->irq, &sedlbauer_interrupt, + if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { + return(request_irq(cs->irq, &sedlbauer_interrupt_isar, I4L_IRQ_FLAG, "HiSax", cs)); + } else if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) { + return(request_irq(cs->irq, &sedlbauer_interrupt_ipac, + I4L_IRQ_FLAG, "HiSax", cs)); + } else { + return(request_irq(cs->irq, &sedlbauer_interrupt, + I4L_IRQ_FLAG, "HiSax", cs)); + } case CARD_INIT: - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { + clear_pending_isac_ints(cs); + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, + ISAR_IRQBIT, 0); + initisac(cs); + initisar(cs); + /* Reenable all IRQ */ + cs->writeisac(cs, ISAC_MASK, 0); + /* RESET Receiver and Transmitter */ + cs->writeisac(cs, ISAC_CMDR, 0x41); + } else { + inithscxisac(cs, 3); + } return(0); case CARD_TEST: return(0); + case CARD_LOAD_FIRM: + if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { + if (isar_load_firmware(cs, arg)) + return(1); + else + ll_run(cs); + } + return(0); } return(0); } + +#ifdef SEDLBAUER_PCI +static int pci_index __initdata = 0; +#endif + __initfunc(int setup_sedlbauer(struct IsdnCard *card)) { - int bytecnt; + int bytecnt, ver, val; struct IsdnCardState *cs = card->cs; char tmp[64]; strcpy(tmp, Sedlbauer_revision); printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ == ISDN_CTYPE_SEDLBAUER) { - cs->subtyp = SEDL_SPEED_CARD; + cs->subtyp = SEDL_SPEED_CARD_WIN; + cs->hw.sedl.bus = SEDL_BUS_ISA; + cs->hw.sedl.chip = SEDL_CHIP_TEST; } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_PCMCIA) { cs->subtyp = SEDL_SPEED_STAR; + cs->hw.sedl.bus = SEDL_BUS_PCMCIA; + cs->hw.sedl.chip = SEDL_CHIP_TEST; + } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_FAX) { + cs->subtyp = SEDL_SPEED_FAX; + cs->hw.sedl.bus = SEDL_BUS_ISA; + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; } else return (0); bytecnt = 8; - cs->hw.sedl.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (cs->subtyp == SEDL_SPEED_STAR) { - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_ISAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_HSCX; - cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_RESET; - cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_RESET; + if (card->para[1]) { + cs->hw.sedl.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { + bytecnt = 16; + } } else { - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_ISAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX; - cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_RESET_ON; - cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_RESET_OFF; - } - - /* In case of the sedlbauer pcmcia card, this region is in use, +/* Probe for Sedlbauer speed pci */ +#if SEDLBAUER_PCI +#if CONFIG_PCI + for (; pci_index < 255; pci_index++) { + unsigned char pci_bus, pci_device_fn; + unsigned int ioaddr; + unsigned char irq; + + if (pcibios_find_device (PCI_VENDOR_SEDLBAUER, + PCI_SPEEDPCI_ID, pci_index, + &pci_bus, &pci_device_fn) != 0) { + continue; + } + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, &irq); + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, &ioaddr); + cs->irq = irq; + cs->hw.sedl.cfg_reg = ioaddr & PCI_BASE_ADDRESS_IO_MASK; + if (!cs->hw.sedl.cfg_reg) { + printk(KERN_WARNING "Sedlbauer: No IO-Adr for PCI card found\n"); + return(0); + } + cs->hw.sedl.bus = SEDL_BUS_PCI; + cs->hw.sedl.chip = SEDL_CHIP_IPAC; + cs->subtyp = SEDL_SPEED_PCI; + bytecnt = 256; + byteout(cs->hw.sedl.cfg_reg, 0xff); + byteout(cs->hw.sedl.cfg_reg, 0x00); + byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd); + byteout(cs->hw.sedl.cfg_reg+ 5, 0x02); + break; + } + if (pci_index == 255) { + printk(KERN_WARNING "Sedlbauer: No PCI card found\n"); + return(0); + } + pci_index++; +#else + 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, reserved for us by the card manager. So we do not check it here, it would fail. */ - if (cs->typ != ISDN_CTYPE_SEDLBAUER_PCMCIA && - check_region((cs->hw.sedl.cfg_reg), bytecnt)) { + if (cs->hw.sedl.bus != SEDL_BUS_PCMCIA && + check_region((cs->hw.sedl.cfg_reg), bytecnt)) { printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], - cs->hw.sedl.cfg_reg, - cs->hw.sedl.cfg_reg + bytecnt); - return (0); + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.sedl.cfg_reg, + cs->hw.sedl.cfg_reg + bytecnt); + return (0); } else { request_region(cs->hw.sedl.cfg_reg, bytecnt, "sedlbauer isdn"); } printk(KERN_INFO - "Sedlbauer: defined at 0x%x IRQ %d\n", + "Sedlbauer: defined at 0x%x-0x%x IRQ %d\n", cs->hw.sedl.cfg_reg, + cs->hw.sedl.cfg_reg + bytecnt, cs->irq); - printk(KERN_WARNING - "Sedlbauer %s uses ports 0x%x-0x%x\n", - Sedlbauer_Types[cs->subtyp], - cs->hw.sedl.cfg_reg, - cs->hw.sedl.cfg_reg + bytecnt); - printk(KERN_INFO "Sedlbauer: resetting card\n"); - reset_sedlbauer(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; cs->BC_Read_Reg = &ReadHSCX; cs->BC_Write_Reg = &WriteHSCX; cs->BC_Send_Data = &hscx_fill_fifo; cs->cardmsg = &Sedl_card_msg; - ISACVersion(cs, "Sedlbauer:"); - if (HscxVersion(cs, "Sedlbauer:")) { - printk(KERN_WARNING - "Sedlbauer: wrong HSCX versions check IO address\n"); - release_io_sedlbauer(cs); - return (0); + +/* + * testing ISA and PCMCIA Cards for IPAC, default is ISAC + * do not test for PCI card, because ports are different + * and PCI card uses only IPAC (for the moment) + */ + if (cs->hw.sedl.bus != SEDL_BUS_PCI) { + val = readreg(cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR, + cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC, IPAC_ID); + if (val == 1) { + /* IPAC */ + cs->subtyp = SEDL_SPEED_WIN2_PC104; + if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) { + cs->subtyp = SEDL_SPEED_STAR2; + } + cs->hw.sedl.chip = SEDL_CHIP_IPAC; + } else { + /* ISAC_HSCX oder ISAC_ISAR */ + if (cs->hw.sedl.chip == SEDL_CHIP_TEST) { + cs->hw.sedl.chip = SEDL_CHIP_ISAC_HSCX; + } + } + } + +/* + * hw.sedl.chip is now properly set + */ + printk(KERN_INFO "Sedlbauer: %s detected\n", + Sedlbauer_Types[cs->subtyp]); + + + 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; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC; + } else { + cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR; + cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC; + } + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + cs->readisac = &ReadISAC_IPAC; + cs->writeisac = &WriteISAC_IPAC; + cs->readisacfifo = &ReadISACfifo_IPAC; + cs->writeisacfifo = &WriteISACfifo_IPAC; + + val = readreg(cs->hw.sedl.adr,cs->hw.sedl.isac, IPAC_ID); + printk(KERN_INFO "Sedlbauer: IPAC version %x\n", val); + reset_sedlbauer(cs); + } else { + /* ISAC_HSCX oder ISAC_ISAR */ + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { + cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ADR; + cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAC; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR; + cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR_RESET_ON; + cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR_RESET_OFF; + cs->bcs[0].hw.isar.reg = &cs->hw.sedl.isar; + cs->bcs[1].hw.isar.reg = &cs->hw.sedl.isar; + test_and_set_bit(HW_ISAR, &cs->HW_Flags); + + ISACVersion(cs, "Sedlbauer:"); + + cs->BC_Read_Reg = &ReadISAR; + cs->BC_Write_Reg = &WriteISAR; + cs->BC_Send_Data = &isar_fill_fifo; + ver = ISARVersion(cs, "Sedlbauer:"); + if (ver < 0) { + printk(KERN_WARNING + "Sedlbauer: wrong ISAR version (ret = %d)\n", ver); + release_io_sedlbauer(cs); + return (0); + } + } else { + if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) { + cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ADR; + cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ISAC; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_HSCX; + cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET; + cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET; + } else { + cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ADR; + cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ISAC; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_HSCX; + cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_ON; + cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_OFF; + } + ISACVersion(cs, "Sedlbauer:"); + + if (HscxVersion(cs, "Sedlbauer:")) { + printk(KERN_WARNING + "Sedlbauer: wrong HSCX versions check IO address\n"); + release_io_sedlbauer(cs); + return (0); + } + reset_sedlbauer(cs); + } } return (1); } diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c index 43d0641da..655abfadc 100644 --- a/drivers/isdn/hisax/sportster.c +++ b/drivers/isdn/hisax/sportster.c @@ -1,4 +1,4 @@ -/* $Id: sportster.c,v 1.5 1998/02/02 13:29:46 keil Exp $ +/* $Id: sportster.c,v 1.7 1998/11/15 23:55:22 keil Exp $ * sportster.c low level stuff for USR Sportster internal TA * @@ -7,6 +7,12 @@ * Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation * * $Log: sportster.c,v $ + * Revision 1.7 1998/11/15 23:55:22 keil + * changes from 2.0 + * + * Revision 1.6 1998/04/15 16:44:35 keil + * new init code + * * Revision 1.5 1998/02/02 13:29:46 keil * fast io * @@ -30,7 +36,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *sportster_revision = "$Revision: 1.5 $"; +const char *sportster_revision = "$Revision: 1.7 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -187,12 +193,10 @@ Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(request_irq(cs->irq, &sportster_interrupt, I4L_IRQ_FLAG, "HiSax", cs)); case CARD_INIT: - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + inithscxisac(cs, 1); cs->hw.spt.res_irq |= SPORTSTER_INTE; /* IRQ On */ byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); + inithscxisac(cs, 2); return(0); case CARD_TEST: return(0); diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c index a52078746..c9d94fe4d 100644 --- a/drivers/isdn/hisax/tei.c +++ b/drivers/isdn/hisax/tei.c @@ -1,12 +1,34 @@ -/* $Id: tei.c,v 2.7 1998/02/12 23:08:11 keil Exp $ +/* $Id: tei.c,v 2.11 1998/11/15 23:55:24 keil Exp $ - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/HiSax.cert + * * Thanks to Jan den Ouden * Fritz Elfert * * $Log: tei.c,v $ + * Revision 2.11 1998/11/15 23:55:24 keil + * changes from 2.0 + * + * Revision 2.10 1998/05/25 14:08:10 keil + * HiSax 3.0 + * fixed X.75 and leased line to work again + * Point2Point and fixed TEI are runtime options now: + * hisaxctrl <id> 7 1 set PTP + * hisaxctrl <id> 8 <TEIVALUE *2 > + * set fixed TEI to TEIVALUE (0-63) + * + * Revision 2.9 1998/05/25 12:58:23 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 2.8 1998/03/07 22:57:07 tsbogend + * made HiSax working on Linux/Alpha + * * Revision 2.7 1998/02/12 23:08:11 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -50,7 +72,7 @@ #include "isdnl2.h" #include <linux/random.h> -const char *tei_revision = "$Revision: 2.7 $"; +const char *tei_revision = "$Revision: 2.11 $"; #define ID_REQUEST 1 #define ID_ASSIGNED 2 @@ -151,26 +173,24 @@ put_tei_msg(struct PStack *st, u_char m_id, unsigned int ri, u_char tei) bp[2] = ri & 0xff; bp[3] = m_id; bp[4] = (tei << 1) | 1; - st->l2.l2l1(st, PH_DATA_REQ, skb); + st->l2.l2l1(st, PH_DATA | REQUEST, skb); } static void tei_id_request(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - char tmp[64]; if (st->l2.tei != -1) { - sprintf(tmp, "assign request for allready asigned tei %d", + st->ma.tei_m.printdebug(&st->ma.tei_m, + "assign request for allready asigned tei %d", st->l2.tei); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); return; } st->ma.ri = random_ri(); - if (st->ma.debug) { - sprintf(tmp, "assign request ri %d", st->ma.ri); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - } + if (st->ma.debug) + st->ma.tei_m.printdebug(&st->ma.tei_m, + "assign request ri %d", st->ma.ri); put_tei_msg(st, ID_REQUEST, st->ma.ri, 127); FsmChangeState(&st->ma.tei_m, ST_TEI_IDREQ); FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 1); @@ -184,26 +204,24 @@ tei_id_assign(struct FsmInst *fi, int event, void *arg) struct sk_buff *skb = arg; struct IsdnCardState *cs; int ri, tei; - char tmp[64]; ri = ((unsigned int) skb->data[1] << 8) + skb->data[2]; tei = skb->data[4] >> 1; - if (st->ma.debug) { - sprintf(tmp, "identity assign ri %d tei %d", ri, tei); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - } + 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 (ri != ost->ma.ri) { - sprintf(tmp, "possible duplicate assignment tei %d", tei); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - ost->l2.l2tei(ost, MDL_ERROR_REQ, NULL); + st->ma.tei_m.printdebug(&st->ma.tei_m, + "possible duplicate assignment tei %d", tei); + ost->l2.l2tei(ost, MDL_ERROR | RESPONSE, NULL); } } else if (ri == st->ma.ri) { FsmDelTimer(&st->ma.t202, 1); FsmChangeState(&st->ma.tei_m, ST_TEI_NOP); - st->ma.manl2(st, MDL_ASSIGN_REQ, (void *) (int) tei); + st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) tei); cs = (struct IsdnCardState *) st->l1.hardware; - cs->cardmsg(cs, MDL_ASSIGN_REQ, NULL); + cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL); } } @@ -213,14 +231,12 @@ tei_id_denied(struct FsmInst *fi, int event, void *arg) struct PStack *st = fi->userdata; struct sk_buff *skb = arg; int ri, tei; - char tmp[64]; ri = ((unsigned int) skb->data[1] << 8) + skb->data[2]; tei = skb->data[4] >> 1; - if (st->ma.debug) { - sprintf(tmp, "identity denied ri %d tei %d", ri, tei); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - } + if (st->ma.debug) + st->ma.tei_m.printdebug(&st->ma.tei_m, + "identity denied ri %d tei %d", ri, tei); } static void @@ -229,13 +245,11 @@ tei_id_chk_req(struct FsmInst *fi, int event, void *arg) struct PStack *st = fi->userdata; struct sk_buff *skb = arg; int tei; - char tmp[64]; tei = skb->data[4] >> 1; - if (st->ma.debug) { - sprintf(tmp, "identity check req tei %d", tei); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - } + if (st->ma.debug) + st->ma.tei_m.printdebug(&st->ma.tei_m, + "identity check req tei %d", tei); if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) { FsmDelTimer(&st->ma.t202, 4); FsmChangeState(&st->ma.tei_m, ST_TEI_NOP); @@ -250,19 +264,17 @@ tei_id_remove(struct FsmInst *fi, int event, void *arg) struct sk_buff *skb = arg; struct IsdnCardState *cs; int tei; - char tmp[64]; tei = skb->data[4] >> 1; - if (st->ma.debug) { - sprintf(tmp, "identity remove tei %d", tei); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - } + if (st->ma.debug) + st->ma.tei_m.printdebug(&st->ma.tei_m, + "identity remove tei %d", tei); if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) { FsmDelTimer(&st->ma.t202, 5); FsmChangeState(&st->ma.tei_m, ST_TEI_NOP); - st->ma.manl2(st, MDL_REMOVE_REQ, 0); + st->l3.l3l2(st, MDL_REMOVE | REQUEST, 0); cs = (struct IsdnCardState *) st->l1.hardware; - cs->cardmsg(cs, MDL_REMOVE_REQ, NULL); + cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); } } @@ -270,12 +282,10 @@ static void tei_id_verify(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - char tmp[64]; - if (st->ma.debug) { - sprintf(tmp, "id verify request for tei %d", st->l2.tei); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - } + if (st->ma.debug) + st->ma.tei_m.printdebug(&st->ma.tei_m, + "id verify request for tei %d", st->l2.tei); put_tei_msg(st, ID_VERIFY, 0, st->l2.tei); FsmChangeState(&st->ma.tei_m, ST_TEI_IDVERIFY); FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 2); @@ -286,24 +296,21 @@ static void tei_id_req_tout(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - char tmp[64]; struct IsdnCardState *cs; if (--st->ma.N202) { st->ma.ri = random_ri(); - if (st->ma.debug) { - sprintf(tmp, "assign req(%d) ri %d", - 4 - st->ma.N202, st->ma.ri); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - } + if (st->ma.debug) + st->ma.tei_m.printdebug(&st->ma.tei_m, + "assign req(%d) ri %d", 4 - st->ma.N202, + st->ma.ri); put_tei_msg(st, ID_REQUEST, st->ma.ri, 127); FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 3); } else { - sprintf(tmp, "assign req failed"); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - st->ma.manl2(st, MDL_ERROR_IND, 0); + st->ma.tei_m.printdebug(&st->ma.tei_m, "assign req failed"); + st->l3.l3l2(st, MDL_ERROR | RESPONSE, 0); cs = (struct IsdnCardState *) st->l1.hardware; - cs->cardmsg(cs, MDL_REMOVE_REQ, NULL); + cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); FsmChangeState(fi, ST_TEI_NOP); } } @@ -312,23 +319,21 @@ static void tei_id_ver_tout(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - char tmp[64]; struct IsdnCardState *cs; if (--st->ma.N202) { - if (st->ma.debug) { - sprintf(tmp, "id verify req(%d) for tei %d", + if (st->ma.debug) + st->ma.tei_m.printdebug(&st->ma.tei_m, + "id verify req(%d) for tei %d", 3 - st->ma.N202, st->l2.tei); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - } put_tei_msg(st, ID_VERIFY, 0, st->l2.tei); FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 4); } else { - sprintf(tmp, "verify req for tei %d failed", st->l2.tei); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - st->ma.manl2(st, MDL_REMOVE_REQ, 0); + st->ma.tei_m.printdebug(&st->ma.tei_m, + "verify req for tei %d failed", st->l2.tei); + st->l3.l3l2(st, MDL_REMOVE | REQUEST, 0); cs = (struct IsdnCardState *) st->l1.hardware; - cs->cardmsg(cs, MDL_REMOVE_REQ, NULL); + cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); FsmChangeState(fi, ST_TEI_NOP); } } @@ -338,31 +343,34 @@ tei_l1l2(struct PStack *st, int pr, void *arg) { struct sk_buff *skb = arg; int mt; - char tmp[64]; - if (pr == PH_DATA_IND) { + if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) { + dev_kfree_skb(skb); + return; + } + + if (pr == (PH_DATA | INDICATION)) { if (skb->len < 3) { - sprintf(tmp, "short mgr frame %d/3", skb->len); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); + st->ma.tei_m.printdebug(&st->ma.tei_m, + "short mgr frame %ld/3", skb->len); } else if (((skb->data[0] >> 2) != TEI_SAPI) || ((skb->data[1] >> 1) != GROUP_TEI)) { - sprintf(tmp, "wrong mgr sapi/tei %x/%x", + st->ma.tei_m.printdebug(&st->ma.tei_m, + "wrong mgr sapi/tei %x/%x", skb->data[0], skb->data[1]); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); } else if ((skb->data[2] & 0xef) != UI) { - sprintf(tmp, "mgr frame is not ui %x", - skb->data[2]); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); + st->ma.tei_m.printdebug(&st->ma.tei_m, + "mgr frame is not ui %x", skb->data[2]); } else { skb_pull(skb, 3); if (skb->len < 5) { - sprintf(tmp, "short mgr frame %d/5", skb->len); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); + st->ma.tei_m.printdebug(&st->ma.tei_m, + "short mgr frame %ld/5", skb->len); } else if (skb->data[0] != TEI_ENTITY_ID) { /* wrong management entity identifier, ignore */ - sprintf(tmp, "tei handler wrong entity id %x\n", + st->ma.tei_m.printdebug(&st->ma.tei_m, + "tei handler wrong entity id %x", skb->data[0]); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); } else { mt = skb->data[3]; if (mt == ID_ASSIGNED) @@ -374,15 +382,14 @@ tei_l1l2(struct PStack *st, int pr, void *arg) else if (mt == ID_REMOVE) FsmEvent(&st->ma.tei_m, EV_REMOVE, skb); else { - sprintf(tmp, "tei handler wrong mt %x\n", - mt); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); + st->ma.tei_m.printdebug(&st->ma.tei_m, + "tei handler wrong mt %x\n", mt); } } } } else { - sprintf(tmp, "tei handler wrong pr %x\n", pr); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); + st->ma.tei_m.printdebug(&st->ma.tei_m, + "tei handler wrong pr %x\n", pr); } dev_kfree_skb(skb); } @@ -390,20 +397,24 @@ tei_l1l2(struct PStack *st, int pr, void *arg) static void tei_l2tei(struct PStack *st, int pr, void *arg) { + struct IsdnCardState *cs; + + if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) { + if (pr == (MDL_ASSIGN | INDICATION)) { + if (st->ma.debug) + st->ma.tei_m.printdebug(&st->ma.tei_m, + "fixed assign tei %d", st->l2.tei); + st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) st->l2.tei); + cs = (struct IsdnCardState *) st->l1.hardware; + cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL); + } + return; + } switch (pr) { - case (MDL_ASSIGN_IND): -#ifdef TEI_FIXED - if (st->ma.debug) { - char tmp[64]; - sprintf(tmp, "fixed assign tei %d", TEI_FIXED); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - } - st->ma.manl2(st, MDL_ASSIGN_REQ, (void *) (int) TEI_FIXED); -#else + case (MDL_ASSIGN | INDICATION): FsmEvent(&st->ma.tei_m, EV_IDREQ, arg); -#endif break; - case (MDL_ERROR_REQ): + case (MDL_ERROR | REQUEST): FsmEvent(&st->ma.tei_m, EV_VERIFY, arg); break; default: @@ -412,14 +423,14 @@ tei_l2tei(struct PStack *st, int pr, void *arg) } static void -tei_debug(struct FsmInst *fi, char *s) +tei_debug(struct FsmInst *fi, char *fmt, ...) { + va_list args; struct PStack *st = fi->userdata; - char tm[32], str[256]; - jiftime(tm, jiffies); - sprintf(str, "%s Tei %s\n", tm, s); - HiSax_putstatus(st->l1.hardware, str); + va_start(args, fmt); + VHiSax_putstatus(st->l1.hardware, "tei ", fmt, args); + va_end(args); } void @@ -439,9 +450,8 @@ setstack_tei(struct PStack *st) } void -init_tei(struct IsdnCardState *sp, int protocol) +init_tei(struct IsdnCardState *cs, int protocol) { - } void diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c index f7e38253b..180eee6a1 100644 --- a/drivers/isdn/hisax/teleint.c +++ b/drivers/isdn/hisax/teleint.c @@ -1,11 +1,17 @@ -/* $Id: teleint.c,v 1.5 1998/02/02 13:40:47 keil Exp $ +/* $Id: teleint.c,v 1.7 1998/11/15 23:55:26 keil Exp $ * teleint.c low level stuff for TeleInt isdn cards * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * * $Log: teleint.c,v $ + * Revision 1.7 1998/11/15 23:55:26 keil + * changes from 2.0 + * + * Revision 1.6 1998/04/15 16:45:31 keil + * new init code + * * Revision 1.5 1998/02/02 13:40:47 keil * fast io * @@ -32,7 +38,7 @@ extern const char *CardType[]; -const char *TeleInt_revision = "$Revision: 1.5 $"; +const char *TeleInt_revision = "$Revision: 1.7 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -64,17 +70,20 @@ static inline void readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { register u_char ret; - int max_delay = 2000; + register int max_delay = 20000; + register int i; + byteout(ale, off); - - ret = HFC_BUSY & bytein(ale); - while (ret && --max_delay) + for (i = 0; i<size; i++) { ret = HFC_BUSY & bytein(ale); - if (!max_delay) { - printk(KERN_WARNING "TeleInt Busy not inaktive\n"); - return; + while (ret && --max_delay) + ret = HFC_BUSY & bytein(ale); + if (!max_delay) { + printk(KERN_WARNING "TeleInt Busy not inaktive\n"); + return; + } + data[i] = bytein(adr); } - insb(adr, data, size); } @@ -104,18 +113,21 @@ static inline void writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { register u_char ret; - int max_delay = 2000; - + register int max_delay = 20000; + register int i; + /* fifo write without cli because it's allready done */ byteout(ale, off); - ret = HFC_BUSY & bytein(ale); - while (ret && --max_delay) + for (i = 0; i<size; i++) { ret = HFC_BUSY & bytein(ale); - if (!max_delay) { - printk(KERN_WARNING "TeleInt Busy not inaktive\n"); - return; + while (ret && --max_delay) + ret = HFC_BUSY & bytein(ale); + if (!max_delay) { + printk(KERN_WARNING "TeleInt Busy not inaktive\n"); + return; + } + byteout(adr, data[i]); } - outsb(adr, data, size); } /* Interface functions */ @@ -157,11 +169,8 @@ ReadHFC(struct IsdnCardState *cs, int data, u_char reg) cs->hw.hfc.cip = reg; byteout(cs->hw.hfc.addr | 1, reg); ret = bytein(cs->hw.hfc.addr); - if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) { - char tmp[32]; - sprintf(tmp, "hfc RD %02x %02x", reg, ret); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) + debugl1(cs, "hfc RD %02x %02x", reg, ret); } else ret = bytein(cs->hw.hfc.addr | 1); return (ret); @@ -174,11 +183,8 @@ WriteHFC(struct IsdnCardState *cs, int data, u_char reg, u_char value) cs->hw.hfc.cip = reg; if (data) byteout(cs->hw.hfc.addr, value); - if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) { - char tmp[32]; - sprintf(tmp, "hfc W%c %02x %02x", data ? 'D' : 'C', reg, value); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) + debugl1(cs, "hfc W%c %02x %02x", data ? 'D' : 'C', reg, value); } static void @@ -271,6 +277,9 @@ TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg) inithfc(cs); clear_pending_isac_ints(cs); initisac(cs); + /* Reenable all IRQ */ + cs->writeisac(cs, ISAC_MASK, 0); + cs->writeisac(cs, ISAC_CMDR, 0x41); cs->hw.hfc.timer.expires = jiffies + 1; add_timer(&cs->hw.hfc.timer); return(0); diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c index 7cd173154..3137a8b7e 100644 --- a/drivers/isdn/hisax/teles0.c +++ b/drivers/isdn/hisax/teles0.c @@ -1,4 +1,4 @@ -/* $Id: teles0.c,v 2.6 1998/02/03 23:27:47 keil Exp $ +/* $Id: teles0.c,v 2.8 1998/04/15 16:44:28 keil Exp $ * teles0.c low level stuff for Teles Memory IO isdn cards * based on the teles driver from Jan den Ouden @@ -10,6 +10,12 @@ * Beat Doebeli * * $Log: teles0.c,v $ + * Revision 2.8 1998/04/15 16:44:28 keil + * new init code + * + * Revision 2.7 1998/03/07 22:57:08 tsbogend + * made HiSax working on Linux/Alpha + * * Revision 2.6 1998/02/03 23:27:47 keil * IRQ 9 * @@ -48,7 +54,7 @@ extern const char *CardType[]; -const char *teles0_revision = "$Revision: 2.6 $"; +const char *teles0_revision = "$Revision: 2.8 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -62,7 +68,7 @@ readisac(unsigned int adr, u_char off) static inline void writeisac(unsigned int adr, u_char off, u_char data) { - writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off); + writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off); mb(); } @@ -77,14 +83,14 @@ static inline void writehscx(unsigned int adr, int hscx, u_char off, u_char data) { writeb(data, adr + (hscx ? 0x1c0 : 0x180) + - ((off & 1) ? 0x1ff : 0) + off); + ((off & 1) ? 0x1ff : 0) + off); mb(); } static inline void read_fifo_isac(unsigned int adr, u_char * data, int size) { register int i; - register u_char *ad = (u_char *) (adr + 0x100); + register u_char *ad = (u_char *) ((long)adr + 0x100); for (i = 0; i < size; i++) data[i] = readb(ad); } @@ -93,16 +99,17 @@ static inline void write_fifo_isac(unsigned int adr, u_char * data, int size) { register int i; - register u_char *ad = (u_char *) (adr + 0x100); - for (i = 0; i < size; i++) - writeb(data[i], ad); + register u_char *ad = (u_char *) ((long)adr + 0x100); + for (i = 0; i < size; i++) { + writeb(data[i], ad); mb(); + } } static inline void read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size) { register int i; - register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180)); + register u_char *ad = (u_char *) ((long)adr + (hscx ? 0x1c0 : 0x180)); for (i = 0; i < size; i++) data[i] = readb(ad); } @@ -111,9 +118,10 @@ static inline void write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size) { int i; - register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180)); - for (i = 0; i < size; i++) - writeb(data[i], ad); + register u_char *ad = (u_char *) ((long)adr + (hscx ? 0x1c0 : 0x180)); + for (i = 0; i < size; i++) { + writeb(data[i], ad); mb(); + } } /* Interface functions */ @@ -264,9 +272,9 @@ reset_teles0(struct IsdnCardState *cs) byteout(cs->hw.teles0.cfg_reg + 4, cfval | 1); HZDELAY(HZ / 10 + 1); } - writeb(0, cs->hw.teles0.membase + 0x80); + writeb(0, cs->hw.teles0.membase + 0x80); mb(); HZDELAY(HZ / 5 + 1); - writeb(1, cs->hw.teles0.membase + 0x80); + writeb(1, cs->hw.teles0.membase + 0x80); mb(); HZDELAY(HZ / 5 + 1); restore_flags(flags); return(0); @@ -286,10 +294,7 @@ Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(request_irq(cs->irq, &teles0_interrupt, I4L_IRQ_FLAG, "HiSax", cs)); case CARD_INIT: - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + inithscxisac(cs, 3); return(0); case CARD_TEST: return(0); diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c index 871b10e4a..297ccb740 100644 --- a/drivers/isdn/hisax/teles3.c +++ b/drivers/isdn/hisax/teles3.c @@ -1,4 +1,4 @@ -/* $Id: teles3.c,v 2.7 1998/02/02 13:29:48 keil Exp $ +/* $Id: teles3.c,v 2.10 1999/02/15 14:37:15 cpetig Exp $ * teles3.c low level stuff for Teles 16.3 & PNP isdn cards * @@ -11,6 +11,15 @@ * Beat Doebeli * * $Log: teles3.c,v $ + * Revision 2.10 1999/02/15 14:37:15 cpetig + * oops, missed something in last commit + * + * Revision 2.9 1999/02/15 14:11:02 cpetig + * fixed a bug with Teles PCMCIA, it doesn't have a config register + * + * Revision 2.8 1998/04/15 16:44:30 keil + * new init code + * * Revision 2.7 1998/02/02 13:29:48 keil * fast io * @@ -69,7 +78,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *teles3_revision = "$Revision: 2.7 $"; +const char *teles3_revision = "$Revision: 2.10 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -214,15 +223,14 @@ void release_io_teles3(struct IsdnCardState *cs) { if (cs->typ == ISDN_CTYPE_TELESPCMCIA) - release_region(cs->hw.teles3.cfg_reg, 97); + release_region(cs->hw.teles3.hscx[0], 97); else { - if (cs->hw.teles3.cfg_reg) { + if (cs->hw.teles3.cfg_reg) if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { release_region(cs->hw.teles3.cfg_reg, 1); } else { release_region(cs->hw.teles3.cfg_reg, 8); } - } release_ioregs(cs, 0x7); } } @@ -305,10 +313,7 @@ Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(request_irq(cs->irq, &teles3_interrupt, I4L_IRQ_FLAG, "HiSax", cs)); case CARD_INIT: - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + inithscxisac(cs, 3); return(0); case CARD_TEST: return(0); @@ -342,7 +347,7 @@ setup_teles3(struct IsdnCard *card)) cs->hw.teles3.hscx[0] = cs->hw.teles3.cfg_reg - 0xc20; cs->hw.teles3.hscx[1] = cs->hw.teles3.cfg_reg - 0x820; } else if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { - cs->hw.teles3.cfg_reg = card->para[1]; + cs->hw.teles3.cfg_reg = 0; cs->hw.teles3.hscx[0] = card->para[1] - 0x20; cs->hw.teles3.hscx[1] = card->para[1]; cs->hw.teles3.isac = card->para[1] + 0x20; @@ -362,12 +367,12 @@ setup_teles3(struct IsdnCard *card)) cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e; cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e; if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { - if (check_region((cs->hw.teles3.cfg_reg), 97)) { + if (check_region((cs->hw.teles3.hscx[0]), 97)) { printk(KERN_WARNING "HiSax: %s ports %x-%x already in use\n", CardType[cs->typ], - cs->hw.teles3.cfg_reg, - cs->hw.teles3.cfg_reg + 96); + cs->hw.teles3.hscx[0], + cs->hw.teles3.hscx[0] + 96); return (0); } else request_region(cs->hw.teles3.hscx[0], 97, "HiSax Teles PCMCIA"); @@ -400,13 +405,12 @@ setup_teles3(struct IsdnCard *card)) CardType[cs->typ], cs->hw.teles3.isac + 32, cs->hw.teles3.isac + 64); - if (cs->hw.teles3.cfg_reg) { + if (cs->hw.teles3.cfg_reg) if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { release_region(cs->hw.teles3.cfg_reg, 1); } else { release_region(cs->hw.teles3.cfg_reg, 8); } - } return (0); } else request_region(cs->hw.teles3.isac + 32, 32, "HiSax isac"); @@ -416,13 +420,12 @@ setup_teles3(struct IsdnCard *card)) CardType[cs->typ], cs->hw.teles3.hscx[0] + 32, cs->hw.teles3.hscx[0] + 64); - if (cs->hw.teles3.cfg_reg) { + if (cs->hw.teles3.cfg_reg) if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { release_region(cs->hw.teles3.cfg_reg, 1); } else { release_region(cs->hw.teles3.cfg_reg, 8); } - } release_ioregs(cs, 1); return (0); } else @@ -433,13 +436,12 @@ setup_teles3(struct IsdnCard *card)) CardType[cs->typ], cs->hw.teles3.hscx[1] + 32, cs->hw.teles3.hscx[1] + 64); - if (cs->hw.teles3.cfg_reg) { + if (cs->hw.teles3.cfg_reg) if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { release_region(cs->hw.teles3.cfg_reg, 1); } else { release_region(cs->hw.teles3.cfg_reg, 8); } - } release_ioregs(cs, 3); return (0); } else diff --git a/drivers/isdn/hisax/teles3c.c b/drivers/isdn/hisax/teles3c.c index 3042f7139..8ba6a311a 100644 --- a/drivers/isdn/hisax/teles3c.c +++ b/drivers/isdn/hisax/teles3c.c @@ -1,11 +1,14 @@ -/* $Id: teles3c.c,v 1.2 1998/02/02 13:27:07 keil Exp $ +/* $Id: teles3c.c,v 1.3 1998/11/15 23:55:27 keil Exp $ * teles3c.c low level stuff for teles 16.3c * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * * $Log: teles3c.c,v $ + * Revision 1.3 1998/11/15 23:55:27 keil + * changes from 2.0 + * * Revision 1.2 1998/02/02 13:27:07 keil * New * @@ -20,14 +23,13 @@ extern const char *CardType[]; -const char *teles163c_revision = "$Revision: 1.2 $"; +const char *teles163c_revision = "$Revision: 1.3 $"; static void t163c_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; u_char val, stat; - char tmp[32]; if (!cs) { printk(KERN_WARNING "teles3c: Spurious interrupt!\n"); @@ -36,16 +38,12 @@ t163c_interrupt(int intno, void *dev_id, struct pt_regs *regs) if ((HFCD_ANYINT | HFCD_BUSY_NBUSY) & (stat = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_STAT))) { val = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_INT_S1); - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "teles3c: stat(%02x) s1(%02x)", stat, val); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "teles3c: stat(%02x) s1(%02x)", stat, val); hfc2bds0_interrupt(cs, val); } else { - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "teles3c: irq_no_irq stat(%02x)", stat); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "teles3c: irq_no_irq stat(%02x)", stat); } } @@ -110,13 +108,9 @@ static int t163c_card_msg(struct IsdnCardState *cs, int mt, void *arg) { long flags; - char tmp[32]; - if (cs->debug & L1_DEB_ISAC) { - - sprintf(tmp, "teles3c: card_msg %x", mt); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "teles3c: card_msg %x", mt); switch (mt) { case CARD_RESET: reset_t163c(cs); diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c index fe5737344..d08730e17 100644 --- a/drivers/isdn/icn/icn.c +++ b/drivers/isdn/icn/icn.c @@ -1,4 +1,4 @@ -/* $Id: icn.c,v 1.49 1998/02/13 11:14:15 keil Exp $ +/* $Id: icn.c,v 1.56 1999/04/12 13:15:07 fritz Exp $ * ISDN low-level module for the ICN active ISDN-Card. * @@ -19,6 +19,30 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.c,v $ + * Revision 1.56 1999/04/12 13:15:07 fritz + * Fixed a cast. + * + * Revision 1.55 1999/04/12 12:34:02 fritz + * Changes from 2.0 tree. + * + * Revision 1.54 1999/01/05 18:29:39 he + * merged remaining schedule_timeout() changes from 2.1.127 + * + * Revision 1.53 1998/06/17 19:51:28 he + * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) + * brute force fix to avoid Ugh's in isdn_tty_write() + * cleaned up some dead code + * + * Revision 1.52 1998/05/20 19:29:58 tsbogend + * fixed bug introduced by changes for new BSENT callback + * + * Revision 1.51 1998/03/07 22:29:55 fritz + * Adapted Detlef's chenges for 2.1. + * + * Revision 1.50 1998/03/07 17:41:54 detabc + * add d-channel connect and disconnect support statcallback + * from icn low-level to link->level + * * Revision 1.49 1998/02/13 11:14:15 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -209,7 +233,7 @@ #undef MAP_DEBUG static char -*revision = "$Revision: 1.49 $"; +*revision = "$Revision: 1.56 $"; static int icn_addcard(int, char *, char *); @@ -232,10 +256,10 @@ icn_free_queue(icn_card * card, int channel) cli(); card->xlen[channel] = 0; card->sndcount[channel] = 0; - if (card->xskb[channel]) { + if ((skb = card->xskb[channel])) { card->xskb[channel] = NULL; restore_flags(flags); - dev_kfree_skb(card->xskb[channel]); + dev_kfree_skb(skb); } else restore_flags(flags); } @@ -529,6 +553,11 @@ icn_pollbchan_send(int channel, icn_card * card) cmd.parm.length = card->xlen[channel]; card->interface.statcallb(&cmd); } + } else { + save_flags(flags); + cli(); + card->xskb[channel] = skb; + restore_flags(flags); } card->xmit_lock[channel] = 0; if (!icn_trymaplock_channel(card, mch)) @@ -580,8 +609,11 @@ static icn_stat icn_stat_table[] = { {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */ {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */ - {"DCON_", ISDN_STAT_DCONN, 0}, /* D-Channel connected */ - {"DDIS_", ISDN_STAT_DHUP, 0}, /* D-Channel disconnected */ + /* + ** add d-channel connect and disconnect support to link-level + */ + {"DCON_", ISDN_STAT_DCONN, 10}, /* D-Channel connected */ + {"DDIS_", ISDN_STAT_DHUP, 11}, /* D-Channel disconnected */ {"DCAL_I", ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line */ {"DSCA_I", ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV */ {"FCALL", ISDN_STAT_ICALL, 4}, /* Leased line connection up */ @@ -630,7 +662,33 @@ icn_parse_status(u_char * status, int channel, icn_card * card) cmd.driver = card->myid; cmd.arg = channel; switch (action) { + case 11: + save_flags(flags); + cli(); + icn_free_queue(card,channel); + card->rcvidx[channel] = 0; + + if (card->flags & + ((channel)?ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE)) { + + isdn_ctrl ncmd; + + card->flags &= ~((channel)? + ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE); + + memset(&ncmd, 0, sizeof(ncmd)); + + ncmd.driver = card->myid; + ncmd.arg = channel; + ncmd.command = ISDN_STAT_BHUP; + restore_flags(flags); + card->interface.statcallb(&cmd); + } else + restore_flags(flags); + + break; case 1: + icn_free_queue(card,channel); card->flags |= (channel) ? ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE; break; @@ -1539,7 +1597,7 @@ icn_command(isdn_ctrl * c, icn_card * card) c->parm.num[0] ? "N" : "ALL", c->parm.num); } else sprintf(cbuf, "%02d;EAZ%s\n", (int) a, - c->parm.num[0] ? c->parm.num : "0123456789"); + c->parm.num[0] ? (char *)(c->parm.num) : "0123456789"); i = icn_writecmd(cbuf, strlen(cbuf), 0, card); } break; diff --git a/drivers/isdn/icn/icn.h b/drivers/isdn/icn/icn.h index 4aba68b38..3bd2819ce 100644 --- a/drivers/isdn/icn/icn.h +++ b/drivers/isdn/icn/icn.h @@ -318,9 +318,9 @@ static char *icn_id2 = "\0"; #ifdef MODULE MODULE_AUTHOR("Fritz Elfert"); MODULE_PARM(portbase, "i"); -MODULE_PARM_DESC(portbase, "Port address of first card"); +MODULE_PARM_DESC(portbase, "Port adress of first card"); MODULE_PARM(membase, "i"); -MODULE_PARM_DESC(membase, "Shared memory address of all cards"); +MODULE_PARM_DESC(membase, "Shared memory adress of all cards"); MODULE_PARM(icn_id, "s"); MODULE_PARM_DESC(icn_id, "ID-String of first card"); MODULE_PARM(icn_id2, "s"); diff --git a/drivers/isdn/isdn_audio.c b/drivers/isdn/isdn_audio.c index d097366ed..67307a0ec 100644 --- a/drivers/isdn/isdn_audio.c +++ b/drivers/isdn/isdn_audio.c @@ -1,9 +1,10 @@ -/* $Id: isdn_audio.c,v 1.10 1998/02/20 17:09:40 fritz Exp $ +/* $Id: isdn_audio.c,v 1.13 1999/04/12 12:33:09 fritz Exp $ * Linux ISDN subsystem, audio conversion and compression (linklevel). * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at) + * Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de) * * 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 @@ -20,6 +21,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_audio.c,v $ + * Revision 1.13 1999/04/12 12:33:09 fritz + * Changes from 2.0 tree. + * + * Revision 1.12 1998/07/26 18:48:43 armin + * Added silence detection in voice receive mode. + * + * Revision 1.11 1998/04/10 10:35:10 paul + * fixed (silly?) warnings from egcs on Alpha. + * * Revision 1.10 1998/02/20 17:09:40 fritz * Changes for recent kernels. * @@ -61,7 +71,7 @@ #include "isdn_audio.h" #include "isdn_common.h" -char *isdn_audio_revision = "$Revision: 1.10 $"; +char *isdn_audio_revision = "$Revision: 1.13 $"; /* * Misc. lookup-tables. @@ -276,7 +286,7 @@ static inline void isdn_audio_tlookup(const char *table, char *buff, unsigned long n) { while (n--) - *buff++ = table[*buff]; + *buff++ = table[*(unsigned char *)buff]; } #endif @@ -660,3 +670,92 @@ isdn_audio_calc_dtmf(modem_info * info, unsigned char *buf, int len, int fmt) len -= c; } } + +silence_state * +isdn_audio_silence_init(silence_state * s) +{ + if (!s) + s = (silence_state *) kmalloc(sizeof(silence_state), GFP_ATOMIC); + if (s) { + s->idx = 0; + s->state = 0; + } + return s; +} + +void +isdn_audio_calc_silence(modem_info * info, unsigned char *buf, int len, int fmt) +{ + silence_state *s = info->silence_state; + int i; + signed char c; + + if (!info->emu.vpar[1]) return; + + for (i = 0; i < len; i++) { + if (fmt) + c = isdn_audio_alaw_to_ulaw[*buf++]; + else + c = *buf++; + + if (c > 0) c -= 128; + c = abs(c); + + if (c > (info->emu.vpar[1] * 4)) { + s->idx = 0; + s->state = 1; + } else { + if (s->idx < 210000) s->idx++; + } + } +} + +void +isdn_audio_eval_silence(modem_info * info) +{ + silence_state *s = info->silence_state; + struct sk_buff *skb; + unsigned long flags; + int di; + int ch; + char what; + char *p; + + what = ' '; + + if (s->idx > (info->emu.vpar[2] * 800)) { + s->idx = 0; + if (!s->state) { /* silence from beginning of rec */ + what = 's'; + } else { + what = 'q'; + } + } + if ((what == 's') || (what == 'q')) { + printk(KERN_DEBUG "ttyI%d: %s\n", info->line, + (what=='s') ? "silence":"quiet"); + skb = dev_alloc_skb(2); + p = (char *) skb_put(skb, 2); + p[0] = 0x10; + p[1] = what; + if (skb_headroom(skb) < sizeof(isdn_audio_skb)) { + printk(KERN_WARNING + "isdn_audio: insufficient skb_headroom, dropping\n"); + kfree_skb(skb); + return; + } + ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; + ISDN_AUDIO_SKB_LOCK(skb) = 0; + save_flags(flags); + cli(); + di = info->isdn_driver; + ch = info->isdn_channel; + __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb); + dev->drv[di]->rcvcount[ch] += 2; + restore_flags(flags); + /* Schedule dequeuing */ + if ((dev->modempoll) && (info->rcvsched)) + isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); + wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]); + } +} diff --git a/drivers/isdn/isdn_audio.h b/drivers/isdn/isdn_audio.h index 0cf8267cf..ee33ce020 100644 --- a/drivers/isdn/isdn_audio.h +++ b/drivers/isdn/isdn_audio.h @@ -1,8 +1,8 @@ -/* $Id: isdn_audio.h,v 1.5 1997/02/03 22:45:21 fritz Exp $ +/* $Id: isdn_audio.h,v 1.7 1999/04/12 12:33:11 fritz Exp $ * Linux ISDN subsystem, audio conversion and compression (linklevel). * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * * 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 @@ -19,6 +19,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_audio.h,v $ + * Revision 1.7 1999/04/12 12:33:11 fritz + * Changes from 2.0 tree. + * + * Revision 1.6 1998/07/26 18:48:44 armin + * Added silence detection in voice receive mode. + * * Revision 1.5 1997/02/03 22:45:21 fritz * Reformatted according CodingStyle * @@ -51,6 +57,11 @@ typedef struct dtmf_state { int buf[DTMF_NPOINTS]; } dtmf_state; +typedef struct silence_state { + int state; + unsigned int idx; +} silence_state; + extern void isdn_audio_ulaw2alaw(unsigned char *, unsigned long); extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long); extern adpcm_state *isdn_audio_adpcm_init(adpcm_state *, int); @@ -60,3 +71,6 @@ extern int isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out); extern void isdn_audio_calc_dtmf(modem_info *, unsigned char *, int, int); extern void isdn_audio_eval_dtmf(modem_info *); dtmf_state *isdn_audio_dtmf_init(dtmf_state *); +extern void isdn_audio_calc_silence(modem_info *, unsigned char *, int, int); +extern void isdn_audio_eval_silence(modem_info *); +silence_state *isdn_audio_silence_init(silence_state *); diff --git a/drivers/isdn/isdn_cards.c b/drivers/isdn/isdn_cards.c index 30a4a7703..06fa3e7d7 100644 --- a/drivers/isdn/isdn_cards.c +++ b/drivers/isdn/isdn_cards.c @@ -1,8 +1,8 @@ -/* $Id: isdn_cards.c,v 1.7 1998/02/20 17:24:28 fritz Exp $ +/* $Id: isdn_cards.c,v 1.9 1999/04/12 12:33:11 fritz Exp $ * Linux ISDN subsystem, initialization for non-modularized drivers. * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de) * * 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 @@ -19,6 +19,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_cards.c,v $ + * Revision 1.9 1999/04/12 12:33:11 fritz + * Changes from 2.0 tree. + * + * Revision 1.8 1999/03/29 11:13:23 armin + * Added eicon driver init. + * * Revision 1.7 1998/02/20 17:24:28 fritz * Added ACT2000 init. * @@ -56,6 +62,10 @@ extern void HiSax_init(void); extern void pcbit_init(void); #endif +#ifdef CONFIG_ISDN_DRV_EICON +extern void eicon_init(void); +#endif + #ifdef CONFIG_ISDN_DRV_AVMB1 extern void avmb1_init(void); extern void capi_init(void); @@ -88,4 +98,7 @@ isdn_cards_init(void) #if CONFIG_ISDN_DRV_ACT2000 act2000_init(); #endif +#if CONFIG_ISDN_DRV_EICON + eicon_init(); +#endif } diff --git a/drivers/isdn/isdn_cards.h b/drivers/isdn/isdn_cards.h index e6e2aa127..78173e747 100644 --- a/drivers/isdn/isdn_cards.h +++ b/drivers/isdn/isdn_cards.h @@ -1,8 +1,8 @@ -/* $Id: isdn_cards.h,v 1.2 1997/02/03 23:31:55 fritz Exp $ +/* $Id: isdn_cards.h,v 1.3 1999/04/12 12:33:13 fritz Exp $ * Linux ISDN subsystem, initialization for non-modularized drivers. * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * * 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 @@ -19,6 +19,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_cards.h,v $ + * Revision 1.3 1999/04/12 12:33:13 fritz + * Changes from 2.0 tree. + * * Revision 1.2 1997/02/03 23:31:55 fritz * Reformatted according CodingStyle * diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c index 92e2ee544..779a327fa 100644 --- a/drivers/isdn/isdn_common.c +++ b/drivers/isdn/isdn_common.c @@ -1,8 +1,8 @@ -/* $Id: isdn_common.c,v 1.55 1998/02/23 23:35:32 fritz Exp $ +/* $Id: isdn_common.c,v 1.75 1999/04/18 14:06:47 fritz Exp $ * Linux ISDN subsystem, common used functions (linklevel). * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) * @@ -20,11 +20,85 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Note: This file differs from the corresponding revision as present in the - * isdn4linux CVS repository because some later bug fixes have been extracted - * from the repository and merged into this file. -- Henner Eisen - * * $Log: isdn_common.c,v $ + * Revision 1.75 1999/04/18 14:06:47 fritz + * Removed TIMRU stuff. + * + * Revision 1.74 1999/04/12 13:16:45 fritz + * Changes from 2.0 tree. + * + * Revision 1.73 1999/04/12 12:33:15 fritz + * Changes from 2.0 tree. + * + * Revision 1.72 1999/03/02 12:04:44 armin + * -added ISDN_STAT_ADDCH to increase supported channels after + * register_isdn(). + * -ttyI now goes on-hook on ATZ when B-Ch is connected. + * -added timer-function for register S7 (Wait for Carrier). + * -analog modem (ISDN_PROTO_L2_MODEM) implementations. + * -on L2_MODEM a string will be appended to the CONNECT-Message, + * which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN. + * -variable "dialing" used for ATA also, for interrupting call + * establishment and register S7. + * + * Revision 1.71 1999/01/28 09:10:43 armin + * Fixed bad while-loop in isdn_readbch(). + * + * Revision 1.70 1999/01/15 19:58:54 he + * removed compatibiltity macro + * + * Revision 1.69 1998/09/07 21:59:58 he + * flush method for 2.1.118 and above + * updated IIOCTLNETGPN + * + * Revision 1.68 1998/08/31 21:09:45 he + * new ioctl IIOCNETGPN for /dev/isdninfo (get network interface' + * peer phone number) + * + * Revision 1.67 1998/06/26 15:12:21 fritz + * Added handling of STAT_ICALL with incomplete CPN. + * Added AT&L for ttyI emulator. + * Added more locking stuff in tty_write. + * + * Revision 1.66 1998/06/17 19:50:41 he + * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) + * brute force fix to avoid Ugh's in isdn_tty_write() + * cleaned up some dead code + * + * Revision 1.65 1998/06/07 00:20:00 fritz + * abc cleanup. + * + * Revision 1.64 1998/06/02 12:10:03 detabc + * wegen einer einstweiliger verfuegung gegen DW ist zur zeit + * die abc-extension bis zur klaerung der rechtslage nicht verfuegbar + * + * Revision 1.63 1998/05/03 17:40:38 detabc + * Include abc-extension-support for >= 2.1.x Kernels in + * isdn_net.c and isdn_common.c. alpha-test OK and running ! + * + * Revision 1.62 1998/04/14 16:28:43 he + * Fixed user space access with interrupts off and remaining + * copy_{to,from}_user() -> -EFAULT return codes + * + * Revision 1.61 1998/03/22 18:50:46 hipp + * Added BSD Compression for syncPPP .. UNTESTED at the moment + * + * Revision 1.60 1998/03/19 13:18:18 keil + * Start of a CAPI like interface for supplementary Service + * first service: SUSPEND + * + * Revision 1.59 1998/03/09 17:46:23 he + * merged in 2.1.89 changes + * + * Revision 1.58 1998/03/07 22:35:24 fritz + * Starting generic module support (Nothing usable yet). + * + * Revision 1.57 1998/03/07 18:21:01 cal + * Dynamic Timeout-Rule-Handling vs. 971110 included + * + * Revision 1.56 1998/02/25 17:49:38 he + * Changed return codes caused be failing copy_{to,from}_user to -EFAULT + * * Revision 1.55 1998/02/23 23:35:32 fritz * Eliminated some compiler warnings. * @@ -269,7 +343,7 @@ isdn_dev *dev = (isdn_dev *) 0; -static char *isdn_revision = "$Revision: 1.55 $"; +static char *isdn_revision = "$Revision: 1.75 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -290,13 +364,36 @@ static int isdn_writebuf_stub(int, int, const u_char *, int, int); void isdn_MOD_INC_USE_COUNT(void) { + int i; + MOD_INC_USE_COUNT; + for (i = 0; i < dev->drivers; i++) { + isdn_ctrl cmd; + + cmd.driver = i; + cmd.arg = 0; + cmd.command = ISDN_CMD_LOCK; + isdn_command(&cmd); + dev->drv[i]->locks++; + } } void isdn_MOD_DEC_USE_COUNT(void) { + int i; + MOD_DEC_USE_COUNT; + for (i = 0; i < dev->drivers; i++) + if (dev->drv[i]->locks > 0) { + isdn_ctrl cmd; + + cmd.driver = i; + cmd.arg = 0; + cmd.command = ISDN_CMD_UNLOCK; + isdn_command(&cmd); + dev->drv[i]->locks--; + } } #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) @@ -312,6 +409,82 @@ isdn_dumppkt(char *s, u_char * p, int len, int dumplen) } #endif +/* + * I picked the pattern-matching-functions from an old GNU-tar version (1.10) + * It was originally written and put to PD by rs@mirror.TMC.COM (Rich Salz) + */ +static int +isdn_star(char *s, char *p) +{ + while (isdn_wildmat(s, p)) { + if (*++s == '\0') + return (2); + } + return (0); +} + +/* + * Shell-type Pattern-matching for incoming caller-Ids + * This function gets a string in s and checks, if it matches the pattern + * given in p. + * + * Return: + * 0 = match. + * 1 = no match. + * 2 = no match. Would eventually match, if s would be longer. + * + * Possible Patterns: + * + * '?' matches one character + * '*' matches zero or more characters + * [xyz] matches the set of characters in brackets. + * [^xyz] matches any single character not in the set of characters + */ + +int +isdn_wildmat(char *s, char *p) +{ + register int last; + register int matched; + register int reverse; + register int nostar = 1; + + for (; *p; s++, p++) + switch (*p) { + case '\\': + /* + * Literal match with following character, + * fall through. + */ + p++; + default: + if (*s != *p) + return (*s == '\0')?2:1; + continue; + case '?': + /* Match anything. */ + if (*s == '\0') + return (2); + continue; + case '*': + nostar = 0; + /* Trailing star matches everything. */ + return (*++p ? isdn_star(s, p) : 0); + case '[': + /* [^....] means inverse character class. */ + if ((reverse = (p[1] == '^'))) + p++; + for (last = 0, matched = 0; *++p && (*p != ']'); last = *p) + /* This next line requires a good C compiler. */ + if (*p == '-' ? *s <= *++p && *s >= last : *s == *p) + matched = 1; + if (matched == reverse) + return (1); + continue; + } + return (*s == '\0')?0:nostar; +} + static void isdn_free_queue(struct sk_buff_head *queue) { @@ -345,7 +518,6 @@ static void isdn_timer_funct(ulong dummy) { int tf = dev->tflags; - if (tf & ISDN_TIMER_FAST) { if (tf & ISDN_TIMER_MODEMREAD) isdn_tty_readmodem(); @@ -374,13 +546,16 @@ isdn_timer_funct(ulong dummy) if (tf & ISDN_TIMER_KEEPALIVE) isdn_net_slarp_out(); } + if (tf & ISDN_TIMER_CARRIER) + isdn_tty_carrier_timeout(); #if (defined CONFIG_ISDN_PPP) && (defined CONFIG_ISDN_MPP) if (tf & ISDN_TIMER_IPPP) isdn_ppp_timer_timeout(); #endif } } - if (tf) { + if (tf) + { int flags; save_flags(flags); @@ -506,6 +681,29 @@ isdn_all_eaz(int di, int ch) isdn_command(&cmd); } +/* + * Begin of a CAPI like LL<->HL interface, currently used only for + * supplementary service (CAPI 2.0 part III) + */ +#include "avmb1/capicmd.h" /* this should be moved in a common place */ + +int +isdn_capi_rec_hl_msg(capi_msg *cm) { + + int di; + int ch; + + di = (cm->adr.Controller & 0x7f) -1; + ch = isdn_dc2minor(di, (cm->adr.Controller>>8)& 0x7f); + switch(cm->Command) { + case CAPI_FACILITY: + /* in the moment only handled in tty */ + return(isdn_tty_capi_facility(cm)); + default: + return(-1); + } +} + static int isdn_status_callback(isdn_ctrl * c) { @@ -540,13 +738,13 @@ isdn_status_callback(isdn_ctrl * c) wake_up_interruptible(&dev->drv[di]->st_waitq); break; case ISDN_STAT_RUN: - dev->drv[di]->running = 1; + dev->drv[di]->flags |= DRV_FLAG_RUNNING; for (i = 0; i < ISDN_MAX_CHANNELS; i++) if (dev->drvmap[i] == di) isdn_all_eaz(di, dev->chanmap[i]); break; case ISDN_STAT_STOP: - dev->drv[di]->running = 0; + dev->drv[di]->flags &= ~DRV_FLAG_RUNNING; break; case ISDN_STAT_ICALL: if (i < 0) @@ -562,19 +760,17 @@ isdn_status_callback(isdn_ctrl * c) return 0; } /* Try to find a network-interface which will accept incoming call */ - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_LOCK; - isdn_command(&cmd); r = isdn_net_find_icall(di, c->arg, i, c->parm.setup); switch (r) { case 0: /* No network-device replies. - * Try ttyI's + * Try ttyI's. + * These return 0 on no match, 1 on match and + * 3 on eventually match, if CID is longer. */ - if (isdn_tty_find_icall(di, c->arg, c->parm.setup) >= 0) - retval = 1; - else if (dev->drv[di]->reject_bus) { + retval = isdn_tty_find_icall(di, c->arg, c->parm.setup); + if ((!retval) && (dev->drv[di]->flags & DRV_FLAG_REJBUS)) { + /* No tty responding */ cmd.driver = di; cmd.arg = c->arg; cmd.command = ISDN_CMD_HANGUP; @@ -606,13 +802,14 @@ isdn_status_callback(isdn_ctrl * c) /* ... then start callback. */ isdn_net_dial(); break; + case 5: + /* Number would eventually match, if longer */ + retval = 3; + break; } - if (retval != 1) { - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_UNLOCK; - isdn_command(&cmd); - } +#ifdef ISDN_DEBUG_STATCALLB + printk(KERN_DEBUG "ICALL: ret=%d\n", retval); +#endif return retval; break; case ISDN_STAT_CINF: @@ -664,7 +861,7 @@ isdn_status_callback(isdn_ctrl * c) #endif if (dev->global_flags & ISDN_GLOBAL_STOPPED) return 0; - dev->drv[di]->flags &= ~(1 << (c->arg)); + dev->drv[di]->online &= ~(1 << (c->arg)); isdn_info_update(); /* Signal hangup to network-devices */ if (isdn_net_stat_callback(i, c)) @@ -682,7 +879,7 @@ isdn_status_callback(isdn_ctrl * c) /* Signal B-channel-connect to network-devices */ if (dev->global_flags & ISDN_GLOBAL_STOPPED) return 0; - dev->drv[di]->flags |= (1 << (c->arg)); + dev->drv[di]->online |= (1 << (c->arg)); isdn_info_update(); if (isdn_net_stat_callback(i, c)) break; @@ -698,7 +895,7 @@ isdn_status_callback(isdn_ctrl * c) #endif if (dev->global_flags & ISDN_GLOBAL_STOPPED) return 0; - dev->drv[di]->flags &= ~(1 << (c->arg)); + dev->drv[di]->online &= ~(1 << (c->arg)); isdn_info_update(); #ifdef CONFIG_ISDN_X25 /* Signal hangup to network-devices */ @@ -723,6 +920,9 @@ isdn_status_callback(isdn_ctrl * c) break; break; case ISDN_STAT_ADDCH: + if (isdn_add_channels(dev->drv[di], di, c->arg, 1)) + return -1; + isdn_info_update(); break; case ISDN_STAT_UNLOAD: save_flags(flags); @@ -741,7 +941,9 @@ isdn_status_callback(isdn_ctrl * c) isdn_free_queue(&dev->drv[di]->rpqueue[i]); kfree(dev->drv[di]->rpqueue); kfree(dev->drv[di]->rcv_waitq); +#if LINUX_VERSION_CODE < 131841 kfree(dev->drv[di]->snd_waitq); +#endif kfree(dev->drv[di]); dev->drv[di] = NULL; dev->drvid[di][0] = '\0'; @@ -750,6 +952,8 @@ isdn_status_callback(isdn_ctrl * c) return 0; case ISDN_STAT_L1ERR: break; + case CAPI_PUT_MESSAGE: + return(isdn_capi_rec_hl_msg(&c->parm.cmsg)); default: return -1; } @@ -785,7 +989,11 @@ isdn_getnum(char **p) * of the mapping (di,ch)<->minor, happen during the sleep? --he */ int +#if LINUX_VERSION_CODE < 131841 isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, struct wait_queue **sleep) +#else +isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_queue_head_t *sleep) +#endif { int left; int count; @@ -819,7 +1027,8 @@ isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, struct w dflag = 0; count_pull = count_put = 0; - while ((count_pull < skb->len) && (left-- > 0)) { + while ((count_pull < skb->len) && (left > 0)) { + left--; if (dev->drv[di]->DLEflag & DLEmask) { *cp++ = DLE; dev->drv[di]->DLEflag &= ~DLEmask; @@ -894,8 +1103,6 @@ isdn_minor2chan(int minor) return (dev->chanmap[minor]); } -#define INF_DV 0x01 /* Data version for /dev/isdninfo */ - static char * isdn_statstr(void) { @@ -931,7 +1138,7 @@ isdn_statstr(void) p = istatbuf + strlen(istatbuf); for (i = 0; i < ISDN_MAX_DRIVERS; i++) { if (dev->drv[i]) { - sprintf(p, "%ld ", dev->drv[i]->flags); + sprintf(p, "%ld ", dev->drv[i]->online); p = istatbuf + strlen(istatbuf); } else { sprintf(p, "? "); @@ -997,7 +1204,7 @@ isdn_read(struct file *file, char *buf, size_t count, loff_t * off) drvidx = isdn_minor2drv(minor); if (drvidx < 0) return -ENODEV; - if (!dev->drv[drvidx]->running) + if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) return -ENODEV; chidx = isdn_minor2chan(minor); if( ! (p = kmalloc(count,GFP_KERNEL)) ) return -ENOMEM; @@ -1067,7 +1274,7 @@ isdn_write(struct file *file, const char *buf, size_t count, loff_t * off) drvidx = isdn_minor2drv(minor); if (drvidx < 0) return -ENODEV; - if (!dev->drv[drvidx]->running) + if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) return -ENODEV; chidx = isdn_minor2chan(minor); while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count) @@ -1081,7 +1288,7 @@ isdn_write(struct file *file, const char *buf, size_t count, loff_t * off) /* * We want to use the isdnctrl device to load the firmware * - if (!dev->drv[drvidx]->running) + if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) return -ENODEV; */ if (dev->drv[drvidx]->interface->writecmd) @@ -1132,143 +1339,6 @@ isdn_poll(struct file *file, poll_table * wait) return POLLERR; } -/* - * This accesses user space with interrupts off, but is not needed by - * any of the isdn4k-util programs anyway. Thus, in contrast to your - * first impression after looking at the code, fixing is trival!*/ -#if 0 -static int -isdn_set_allcfg(char *src) -{ - int ret; - int i; - ulong flags; - isdn_net_ioctl_cfg cfg; - isdn_net_ioctl_phone phone; - - if ((ret = isdn_net_rmall())) - return ret; - if (copy_from_user((char *) &i, src, sizeof(int))) return -EFAULT; - save_flags(flags); - cli(); - src += sizeof(int); - while (i) { - int phone_len; - int out_flag; - - if (copy_from_user((char *) &cfg, src, sizeof(cfg))) { - restore_flags(flags); - return -EFAULT; - } - src += sizeof(cfg); - if (!isdn_net_new(cfg.name, NULL)) { - restore_flags(flags); - return -EIO; - } - if ((ret = isdn_net_setcfg(&cfg))) { - restore_flags(flags); - return ret; - } - phone_len = out_flag = 0; - while (out_flag < 2) { - if ((ret = verify_area(VERIFY_READ, src, 1))) { - restore_flags(flags); - return ret; - } - get_user(phone.phone[phone_len], src++); - if ((phone.phone[phone_len] == ' ') || - (phone.phone[phone_len] == '\0')) { - if (phone_len) { - phone.phone[phone_len] = '\0'; - strcpy(phone.name, cfg.name); - phone.outgoing = out_flag; - if ((ret = isdn_net_addphone(&phone))) { - restore_flags(flags); - return ret; - } - } else - out_flag++; - phone_len = 0; - } - if (++phone_len >= sizeof(phone.phone)) - printk(KERN_WARNING - "%s: IIOCSETSET phone number too long, ignored\n", - cfg.name); - } - i--; - } - restore_flags(flags); - return 0; -} - -static int -isdn_get_allcfg(char *dest) -{ - isdn_net_ioctl_cfg cfg; - isdn_net_ioctl_phone phone; - isdn_net_dev *p; - ulong flags; - int ret; - - /* Walk through netdev-chain */ - save_flags(flags); - cli(); - p = dev->netdev; - while (p) { - isdn_net_local *lp = p->local; - - if ((ret = verify_area(VERIFY_WRITE, (void *) dest, sizeof(cfg) + 200))) { - restore_flags(flags); - return ret; - } - strcpy(cfg.eaz, lp->msn); - cfg.exclusive = lp->exclusive; - if (lp->pre_device >= 0) { - sprintf(cfg.drvid, "%s,%d", dev->drvid[lp->pre_device], - lp->pre_channel); - } else - cfg.drvid[0] = '\0'; - cfg.onhtime = lp->onhtime; - cfg.charge = lp->charge; - cfg.l2_proto = lp->l2_proto; - cfg.l3_proto = lp->l3_proto; - cfg.p_encap = lp->p_encap; - cfg.secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0; - cfg.callback = (lp->flags & ISDN_NET_CALLBACK) ? 1 : 0; - cfg.chargehup = (lp->hupflags & ISDN_CHARGEHUP) ? 1 : 0; - cfg.ihup = (lp->hupflags & ISDN_INHUP) ? 1 : 0; - cfg.chargeint = lp->chargeint; - if (copy_to_user(dest, lp->name, 10)) { - restore_flags(flags); - return -EFAULT; - } - dest += 10; - if (copy_to_user(dest, (char *) &cfg, sizeof(cfg))) { - restore_flags(flags); - return -EFAULT; - } - dest += sizeof(cfg); - strcpy(phone.name, lp->name); - phone.outgoing = 0; - if ((ret = isdn_net_getphones(&phone, dest)) < 0) { - restore_flags(flags); - return ret; - } else - dest += ret; - strcpy(phone.name, lp->name); - phone.outgoing = 1; - if ((ret = isdn_net_getphones(&phone, dest)) < 0) { - restore_flags(flags); - return ret; - } else - dest += ret; - put_user(0, dest); - p = p->next; - } - restore_flags(flags); - return 0; -} -#endif static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) @@ -1316,6 +1386,17 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) } else return -EINVAL; break; +#ifdef CONFIG_NETDEVICES + case IIOCNETGPN: + /* Get peer phone number of a connected + * isdn network interface */ + if (arg) { + if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) + return -EFAULT; + return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg); + } else + return -EINVAL; +#endif default: return -EINVAL; } @@ -1327,7 +1408,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) if (drvidx < 0) return -ENODEV; chidx = isdn_minor2chan(minor); - if (!dev->drv[drvidx]->running) + if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) return -ENODEV; return 0; } @@ -1513,26 +1594,11 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) } if (drvidx == -1) return -ENODEV; - dev->drv[drvidx]->reject_bus = iocts.arg; - return 0; -#if 0 - case IIOCGETSET: - /* Get complete setup (all network-interfaces and profile- - settings of all tty-devices */ - if (arg) - return (isdn_get_allcfg((char *) arg)); + if (iocts.arg) + dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS; else - return -EINVAL; - break; - case IIOCSETSET: - /* Set complete setup (all network-interfaces and profile- - settings of all tty-devices */ - if (arg) - return (isdn_set_allcfg((char *) arg)); - else - return -EINVAL; - break; -#endif + dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS; + return 0; case IIOCSIGPRF: dev->profd = current; return 0; @@ -1544,7 +1610,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) int i; if ((ret = verify_area(VERIFY_WRITE, (void *) arg, - (ISDN_MODEM_ANZREG + ISDN_MSNLEN) + (ISDN_MODEM_ANZREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS))) return ret; @@ -1556,8 +1622,11 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN)) return -EFAULT; p += ISDN_MSNLEN; + if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN)) + return -EFAULT; + p += ISDN_LMSNLEN; } - return (ISDN_MODEM_ANZREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS; + return (ISDN_MODEM_ANZREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS; } else return -EINVAL; break; @@ -1721,7 +1790,6 @@ isdn_open(struct inode *ino, struct file *filep) uint minor = MINOR(ino->i_rdev); int drvidx; int chidx; - isdn_ctrl c; if (minor == ISDN_MINOR_STATUS) { infostruct *p; @@ -1744,31 +1812,25 @@ isdn_open(struct inode *ino, struct file *filep) if (drvidx < 0) return -ENODEV; chidx = isdn_minor2chan(minor); - if (!dev->drv[drvidx]->running) + if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) return -ENODEV; - if (!(dev->drv[drvidx]->flags & (1 << chidx))) + if (!(dev->drv[drvidx]->online & (1 << chidx))) return -ENODEV; - c.command = ISDN_CMD_LOCK; - c.driver = drvidx; - isdn_command(&c); - MOD_INC_USE_COUNT; + isdn_MOD_INC_USE_COUNT(); return 0; } if (minor <= ISDN_MINOR_CTRLMAX) { drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); if (drvidx < 0) return -ENODEV; - c.command = ISDN_CMD_LOCK; - c.driver = drvidx; - MOD_INC_USE_COUNT; - isdn_command(&c); + isdn_MOD_INC_USE_COUNT(); return 0; } #ifdef CONFIG_ISDN_PPP if (minor <= ISDN_MINOR_PPPMAX) { int ret; if (!(ret = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep))) - MOD_INC_USE_COUNT; + isdn_MOD_INC_USE_COUNT(); return ret; } #endif @@ -1779,13 +1841,12 @@ static int isdn_close(struct inode *ino, struct file *filep) { uint minor = MINOR(ino->i_rdev); - int drvidx; - isdn_ctrl c; - MOD_DEC_USE_COUNT; if (minor == ISDN_MINOR_STATUS) { infostruct *p = dev->infochain; infostruct *q = NULL; + + MOD_DEC_USE_COUNT; while (p) { if (p->private == (char *) &(filep->private_data)) { if (q) @@ -1801,24 +1862,12 @@ isdn_close(struct inode *ino, struct file *filep) printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n"); return 0; } - if (minor < ISDN_MINOR_CTRL) { - drvidx = isdn_minor2drv(minor); - if (drvidx < 0) - return 0; - c.command = ISDN_CMD_UNLOCK; - c.driver = drvidx; - isdn_command(&c); + isdn_MOD_DEC_USE_COUNT(); + if (minor < ISDN_MINOR_CTRL) return 0; - } if (minor <= ISDN_MINOR_CTRLMAX) { - drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); - if (drvidx < 0) - return 0; if (dev->profd == current) dev->profd = NULL; - c.command = ISDN_CMD_UNLOCK; - c.driver = drvidx; - isdn_command(&c); return 0; } #ifdef CONFIG_ISDN_PPP @@ -1872,7 +1921,6 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev ulong flags; ulong features; ulong vfeatures; - isdn_ctrl cmd; save_flags(flags); cli(); @@ -1890,7 +1938,7 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) && ((pre_dev != d) || (pre_chan != dev->chanmap[i]))) continue; - if ((dev->drv[d]->running)) { + if (dev->drv[d]->flags & DRV_FLAG_RUNNING) { if (((dev->drv[d]->interface->features & features) == features) || (((dev->drv[d]->interface->features & vfeatures) == vfeatures) && (dev->drv[d]->interface->features & ISDN_FEATURE_L2_TRANS))) { @@ -1898,10 +1946,6 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev dev->usage[i] &= ISDN_USAGE_EXCLUSIVE; dev->usage[i] |= usage; isdn_info_update(); - cmd.driver = d; - cmd.arg = 0; - cmd.command = ISDN_CMD_LOCK; - isdn_command(&cmd); restore_flags(flags); return i; } else { @@ -1909,10 +1953,6 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev dev->usage[i] &= ISDN_USAGE_EXCLUSIVE; dev->usage[i] |= usage; isdn_info_update(); - cmd.driver = d; - cmd.arg = 0; - cmd.command = ISDN_CMD_LOCK; - isdn_command(&cmd); restore_flags(flags); return i; } @@ -1932,7 +1972,6 @@ isdn_free_channel(int di, int ch, int usage) { int i; ulong flags; - isdn_ctrl cmd; save_flags(flags); cli(); @@ -1946,12 +1985,6 @@ isdn_free_channel(int di, int ch, int usage) dev->obytes[i] = 0; isdn_info_update(); isdn_free_queue(&dev->drv[di]->rpqueue[ch]); - cmd.driver = di; - cmd.arg = ch; - cmd.command = ISDN_CMD_UNLOCK; - restore_flags(flags); - isdn_command(&cmd); - return; } restore_flags(flags); } @@ -1996,7 +2029,6 @@ isdn_writebuf_stub(int drvidx, int chan, const u_char * buf, int len, copy_from_user(skb_put(skb, len), buf, len); else memcpy(skb_put(skb, len), buf, len); - ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb); if (ret <= 0) dev_kfree_skb(skb); @@ -2052,100 +2084,213 @@ isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb) return ret; } -/* - * Low-level-driver registration - */ +int +register_isdn_module(isdn_module *m) { +#if 0 + isdn_module_list **pp = &dev->modules; + isdn_module *new = kmalloc(sizeof(isdn_module_list), GFP_KERNEL); -EXPORT_SYMBOL(register_isdn); + if (!new) { + printk(KERN_WARNING "isdn: Out of memory in register_isdn_module\n"); + return -1; + } + while (*pp && (*pp)->orig != m) + pp = &(*pp)->next; + if (*pp != NULL) { + printk(KERN_WARNING "isdn: Module %s already registered\n", m->name); + return -1; + } + while (*pp && ((*pp)->module.priority < m->priority)) + pp = &(*pp)->next; + new->next = *pp; + new->orig = m; + new->module = *m; + + *pp = new; +#endif + return 0; +} int -register_isdn(isdn_if * i) +unregister_isdn_module(isdn_module *m) { +#if 0 + isdn_module_list **pp = &dev->modules; + + while (*pp && *pp != m) + pp = &(*pp)->next; + if (*pp == NULL) { + printk(KERN_WARNING "isdn: Module %s not found\n", m->name); + return -1; + } +#endif + return 0; +} + +int +isdn_add_channels(driver *d, int drvidx, int n, int adding) { - driver *d; - int n, - j, - k; + int j, k, m; ulong flags; - int drvidx; - if (dev->drivers >= ISDN_MAX_DRIVERS) { - printk(KERN_WARNING "register_isdn: Max. %d drivers supported\n", - ISDN_MAX_DRIVERS); +#if LINUX_VERSION_CODE >= 131841 + init_waitqueue_head(&d->st_waitq); +#endif + if (d->flags & DRV_FLAG_RUNNING) + return -1; + if (n < 1) return 0; - } - n = i->channels; + + m = (adding) ? d->channels + n : n; + if (dev->channels + n > ISDN_MAX_CHANNELS) { printk(KERN_WARNING "register_isdn: Max. %d channels supported\n", ISDN_MAX_CHANNELS); - return 0; - } - if (!i->writebuf_skb) { - printk(KERN_WARNING "register_isdn: No write routine given.\n"); - return 0; - } - if (!(d = (driver *) kmalloc(sizeof(driver), GFP_KERNEL))) { - printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n"); - return 0; + return -1; } - memset((char *) d, 0, sizeof(driver)); - if (!(d->rcverr = (int *) kmalloc(sizeof(int) * n, GFP_KERNEL))) { + + if ((adding) && (d->rcverr)) + kfree(d->rcverr); + if (!(d->rcverr = (int *) kmalloc(sizeof(int) * m, GFP_KERNEL))) { printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n"); - kfree(d); - return 0; + return -1; } - memset((char *) d->rcverr, 0, sizeof(int) * n); - if (!(d->rcvcount = (int *) kmalloc(sizeof(int) * n, GFP_KERNEL))) { + memset((char *) d->rcverr, 0, sizeof(int) * m); + + if ((adding) && (d->rcvcount)) + kfree(d->rcvcount); + if (!(d->rcvcount = (int *) kmalloc(sizeof(int) * m, GFP_KERNEL))) { printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n"); - kfree(d->rcverr); - kfree(d); - return 0; + if (!adding) kfree(d->rcverr); + return -1; + } + memset((char *) d->rcvcount, 0, sizeof(int) * m); + + if ((adding) && (d->rpqueue)) { + for (j = 0; j < d->channels; j++) + isdn_free_queue(&d->rpqueue[j]); + kfree(d->rpqueue); } - memset((char *) d->rcvcount, 0, sizeof(int) * n); if (!(d->rpqueue = - (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * n, GFP_KERNEL))) { + (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * m, GFP_KERNEL))) { printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n"); - kfree(d->rcvcount); - kfree(d->rcverr); - kfree(d); - return 0; + if (!adding) { + kfree(d->rcvcount); + kfree(d->rcverr); + } + return -1; } - for (j = 0; j < n; j++) { + for (j = 0; j < m; j++) { skb_queue_head_init(&d->rpqueue[j]); } + + if ((adding) && (d->rcv_waitq)) + kfree(d->rcv_waitq); +#if LINUX_VERSION_CODE < 131841 if (!(d->rcv_waitq = (struct wait_queue **) - kmalloc(sizeof(struct wait_queue *) * n, GFP_KERNEL))) { + kmalloc(sizeof(struct wait_queue *) * m, GFP_KERNEL))) { +#else + d->rcv_waitq = (wait_queue_head_t *) + kmalloc(sizeof(wait_queue_head_t) * 2 * m, GFP_KERNEL); + if (!d->rcv_waitq) { +#endif printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n"); - kfree(d->rpqueue); - kfree(d->rcvcount); - kfree(d->rcverr); - kfree(d); - return 0; + if (!adding) { + kfree(d->rpqueue); + kfree(d->rcvcount); + kfree(d->rcverr); + } + return -1; } - memset((char *) d->rcv_waitq, 0, sizeof(struct wait_queue *) * n); +#if LINUX_VERSION_CODE < 131841 + memset((char *) d->rcv_waitq, 0, sizeof(struct wait_queue *) * m); + + if ((adding) && (d->snd_waitq)) + kfree(d->snd_waitq); if (!(d->snd_waitq = (struct wait_queue **) - kmalloc(sizeof(struct wait_queue *) * n, GFP_KERNEL))) { + kmalloc(sizeof(struct wait_queue *) * m, GFP_KERNEL))) { printk(KERN_WARNING "register_isdn: Could not alloc snd_waitq\n"); - kfree(d->rcv_waitq); - kfree(d->rpqueue); - kfree(d->rcvcount); - kfree(d->rcverr); - kfree(d); + if (!adding) { + kfree(d->rcv_waitq); + kfree(d->rpqueue); + kfree(d->rcvcount); + kfree(d->rcverr); + } + return -1; + } + memset((char *) d->snd_waitq, 0, sizeof(struct wait_queue *) * m); +#else + d->snd_waitq = d->rcv_waitq + m; + for (j = 0; j < m; j++) { + init_waitqueue_head(&d->rcv_waitq[m]); + init_waitqueue_head(&d->snd_waitq[m]); + } +#endif + + dev->channels += n; + save_flags(flags); + cli(); + for (j = d->channels; j < m; j++) + for (k = 0; k < ISDN_MAX_CHANNELS; k++) + if (dev->chanmap[k] < 0) { + dev->chanmap[k] = j; + dev->drvmap[k] = drvidx; + break; + } + restore_flags(flags); + d->channels = m; + return 0; +} + +/* + * Low-level-driver registration + */ + +EXPORT_SYMBOL(register_isdn); +EXPORT_SYMBOL(register_isdn_module); +EXPORT_SYMBOL(unregister_isdn_module); +#ifdef CONFIG_ISDN_PPP +EXPORT_SYMBOL(isdn_ppp_register_compressor); +EXPORT_SYMBOL(isdn_ppp_unregister_compressor); +#endif + +int +register_isdn(isdn_if * i) +{ + driver *d; + int j; + ulong flags; + int drvidx; + + if (dev->drivers >= ISDN_MAX_DRIVERS) { + printk(KERN_WARNING "register_isdn: Max. %d drivers supported\n", + ISDN_MAX_DRIVERS); + return 0; + } + if (!i->writebuf_skb) { + printk(KERN_WARNING "register_isdn: No write routine given.\n"); + return 0; + } + if (!(d = (driver *) kmalloc(sizeof(driver), GFP_KERNEL))) { + printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n"); return 0; } - memset((char *) d->snd_waitq, 0, sizeof(struct wait_queue *) * n); - d->channels = n; - d->loaded = 1; + memset((char *) d, 0, sizeof(driver)); + d->maxbufsize = i->maxbufsize; d->pktcount = 0; d->stavail = 0; - d->running = 0; - d->flags = 0; + d->flags = DRV_FLAG_LOADED; + d->online = 0; d->interface = i; + d->channels = 0; for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) if (!dev->drv[drvidx]) break; + if (isdn_add_channels(d, drvidx, i->channels, 0)) { + kfree(d); + return 0; + } i->channels = drvidx; - i->rcvcallb_skb = isdn_receive_skb_callback; i->statcallb = isdn_status_callback; if (!strlen(i->id)) @@ -2155,15 +2300,7 @@ register_isdn(isdn_if * i) for (j = 0; j < drvidx; j++) if (!strcmp(i->id, dev->drvid[j])) sprintf(i->id, "line%d", drvidx); - for (j = 0; j < n; j++) - for (k = 0; k < ISDN_MAX_CHANNELS; k++) - if (dev->chanmap[k] < 0) { - dev->chanmap[k] = j; - dev->drvmap[k] = drvidx; - break; - } dev->drv[drvidx] = d; - dev->channels += n; strcpy(dev->drvid[drvidx], i->id); isdn_info_update(); dev->drivers++; @@ -2215,12 +2352,21 @@ isdn_init(void) memset((char *) dev, 0, sizeof(isdn_dev)); init_timer(&dev->timer); dev->timer.function = isdn_timer_funct; +#if LINUX_VERSION_CODE < 131841 dev->sem = MUTEX; +#else + init_MUTEX(&dev->sem); + init_waitqueue_head(&dev->info_waitq); +#endif for (i = 0; i < ISDN_MAX_CHANNELS; i++) { dev->drvmap[i] = -1; dev->chanmap[i] = -1; dev->m_idx[i] = -1; strcpy(dev->num[i], "???"); +#if LINUX_VERSION_CODE >= 131841 + init_waitqueue_head(&dev->mdm.info[i].open_wait); + init_waitqueue_head(&dev->mdm.info[i].close_wait); +#endif } if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) { printk(KERN_WARNING "isdn: Could not register control devices\n"); diff --git a/drivers/isdn/isdn_common.h b/drivers/isdn/isdn_common.h index 6cb503b9f..3ba4855b7 100644 --- a/drivers/isdn/isdn_common.h +++ b/drivers/isdn/isdn_common.h @@ -1,8 +1,8 @@ -/* $Id: isdn_common.h,v 1.9 1998/02/20 17:19:01 fritz Exp $ +/* $Id: isdn_common.h,v 1.15 1999/04/18 14:06:50 fritz Exp $ * header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel). * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) * @@ -20,11 +20,36 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Note: This file differs from the corresponding revision as present in the - * isdn4linux CVS repository because some later bug fixes have been extracted - * from the repository and merged into this file. -- Henner Eisen - * * $Log: isdn_common.h,v $ + * Revision 1.15 1999/04/18 14:06:50 fritz + * Removed TIMRU stuff. + * + * Revision 1.14 1999/04/12 12:33:18 fritz + * Changes from 2.0 tree. + * + * Revision 1.13 1999/03/02 12:04:47 armin + * -added ISDN_STAT_ADDCH to increase supported channels after + * register_isdn(). + * -ttyI now goes on-hook on ATZ when B-Ch is connected. + * -added timer-function for register S7 (Wait for Carrier). + * -analog modem (ISDN_PROTO_L2_MODEM) implementations. + * -on L2_MODEM a string will be appended to the CONNECT-Message, + * which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN. + * -variable "dialing" used for ATA also, for interrupting call + * establishment and register S7. + * + * Revision 1.12 1998/06/26 15:12:27 fritz + * Added handling of STAT_ICALL with incomplete CPN. + * Added AT&L for ttyI emulator. + * Added more locking stuff in tty_write. + * + * Revision 1.11 1998/04/14 16:28:47 he + * Fixed user space access with interrupts off and remaining + * copy_{to,from}_user() -> -EFAULT return codes + * + * Revision 1.10 1998/03/07 18:21:03 cal + * Dynamic Timeout-Rule-Handling vs. 971110 included + * * Revision 1.9 1998/02/20 17:19:01 fritz * Added common stub for sending commands to lowlevel. * @@ -90,10 +115,16 @@ extern char *isdn_map_eaz2msn(char *msn, int di); extern void isdn_timer_ctrl(int tf, int onoff); extern void isdn_unexclusive_channel(int di, int ch); extern int isdn_getnum(char **); +#if LINUX_VERSION_CODE < 131841 extern int isdn_readbchan(int, int, u_char *, u_char *, int, struct wait_queue**); +#else +extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *); +#endif extern int isdn_get_free_channel(int, int, int, int, int); extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *); extern int register_isdn(isdn_if * i); +extern int isdn_wildmat(char *, char *); +extern int isdn_add_channels(driver *, int, int, int); #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) extern void isdn_dumppkt(char *, u_char *, int, int); #endif diff --git a/drivers/isdn/isdn_concap.c b/drivers/isdn/isdn_concap.c index 0d9abb226..1ca6c34e3 100644 --- a/drivers/isdn/isdn_concap.c +++ b/drivers/isdn/isdn_concap.c @@ -1,10 +1,21 @@ -/* $Id: isdn_concap.c,v 1.2 1998/01/31 22:49:21 keil Exp $ +/* $Id: isdn_concap.c,v 1.5 1998/10/30 18:44:48 he Exp $ * Stuff to support the concap_proto by isdn4linux. isdn4linux - specific * stuff goes here. Stuff that depends only on the concap protocol goes to * another -- protocol specific -- source file. * * $Log: isdn_concap.c,v $ + * Revision 1.5 1998/10/30 18:44:48 he + * pass return value from isdn_net_dial_req for dialmode change + * + * Revision 1.4 1998/10/30 17:55:24 he + * dialmode for x25iface and multulink ppp + * + * Revision 1.3 1998/05/26 22:39:22 he + * sync'ed with 2.1.102 where appropriate (CAPABILITY changes) + * concap typo + * cleared dev.tbusy in isdn_net BCONN status callback + * * Revision 1.2 1998/01/31 22:49:21 keil * correct comments * @@ -20,14 +31,9 @@ #include <linux/concap.h> #include "isdn_concap.h" -/* The declaration of this (or a plublic variant thereof) should really go - in linux/isdn.h. But we really need it here (and isdn_ppp, like us, also - refers to that private function currently owned by isdn_net.c) */ -extern int isdn_net_force_dial_lp(isdn_net_local *); - /* The following set of device service operations are for encapsulation - protocols that require for reliable datalink sematics. That means: + protocols that require for reliable datalink semantics. That means: - before any data is to be submitted the connection must explicitly be set up. @@ -66,9 +72,9 @@ int isdn_concap_dl_connect_req(struct concap_proto *concap) IX25DEBUG( "isdn_concap_dl_connect_req: %s \n", ndev -> name); /* dial ... */ - ret = isdn_net_force_dial_lp( lp ); + ret = isdn_net_dial_req( lp ); if ( ret ) IX25DEBUG("dialing failed\n"); - return 0; + return ret; } int isdn_concap_dl_disconn_req(struct concap_proto *concap) diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c index daafceb1a..9e4426af0 100644 --- a/drivers/isdn/isdn_net.c +++ b/drivers/isdn/isdn_net.c @@ -1,8 +1,8 @@ -/* $Id: isdn_net.c,v 1.55 1998/02/23 19:38:22 fritz Exp $ +/* $Id: isdn_net.c,v 1.84 1999/04/18 14:06:55 fritz Exp $ * Linux ISDN subsystem, network interfaces and related functions (linklevel). * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) * @@ -20,11 +20,119 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Note: This file differs from the corresponding revision as present in the - * isdn4linux CVS repository because some later bug fixes have been extracted - * from the repository and merged into this file. -- Henner Eisen - * * $Log: isdn_net.c,v $ + * Revision 1.84 1999/04/18 14:06:55 fritz + * Removed TIMRU stuff. + * + * Revision 1.83 1999/04/12 12:33:23 fritz + * Changes from 2.0 tree. + * + * Revision 1.82 1999/01/17 00:55:58 he + * added mark_bh in BCONN statcallb and cleaned up some dead code + * + * Revision 1.81 1999/01/15 16:36:52 he + * replaced icmp_send() by dst_link_failure() + * + * Revision 1.80 1998/12/01 13:06:22 paul + * Also huptimeout with dialmode == manual + * + * Revision 1.79 1998/10/30 17:55:27 he + * dialmode for x25iface and multulink ppp + * + * Revision 1.78 1998/10/26 18:20:46 he + * re-inserted p=p->next in isdn_net_find_icall() (fixes kernel lock up + * on incoming call not matching the first interface) + * + * Revision 1.77 1998/10/23 10:18:44 paul + * Implementation of "dialmode" (successor of "status") + * You also need current isdnctrl for this! + * + * Revision 1.76 1998/09/07 22:00:05 he + * flush method for 2.1.118 and above + * updated IIOCTLNETGPN + * + * Revision 1.75 1998/08/31 21:09:50 he + * new ioctl IIOCNETGPN for /dev/isdninfo (get network interface' + * peer phone number) + * + * Revision 1.74 1998/07/30 11:28:32 paul + * printk message only appeared when status is off and interface is rawIP, + * which is confusing for people who don't know about "isdnctrl status <if> on". + * + * Revision 1.73 1998/06/26 22:01:37 keil + * tx_queue_len = 5 was too small + * + * Revision 1.72 1998/06/26 15:12:31 fritz + * Added handling of STAT_ICALL with incomplete CPN. + * Added AT&L for ttyI emulator. + * Added more locking stuff in tty_write. + * + * Revision 1.71 1998/06/18 22:43:08 fritz + * Bugfix: Setting ndev->do_ioctl had beed accidetly removed at abc-cleanup. + * + * Revision 1.70 1998/06/17 19:50:49 he + * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) + * brute force fix to avoid Ugh's in isdn_tty_write() + * cleaned up some dead code + * + * Revision 1.69 1998/06/09 12:27:37 cal + * Changed default of local netdev flags: ISDN_NET_STOPPED is default now, + * so autodial is suppressed for that device until it is switched on using + * 'isdnctrl status dev-name on'. + * + * Revision 1.68 1998/06/07 00:20:05 fritz + * abc cleanup. + * + * Revision 1.67 1998/06/02 12:10:08 detabc + * wegen einer einstweiliger verfuegung gegen DW ist zur zeit + * die abc-extension bis zur klaerung der rechtslage nicht verfuegbar + * + * Revision 1.66 1998/05/26 22:39:24 he + * sync'ed with 2.1.102 where appropriate (CAPABILITY changes) + * concap typo + * cleared dev.tbusy in isdn_net BCONN status callback + * + * Revision 1.65 1998/05/22 10:01:11 detabc + * in case of a icmp-unreach condition the tcp-keepalive-entrys + * will be dropped from the internal double-link-list (only abc-extension). + * send icmp unreach only if the skb->protocol == ETH_P_IP + * speedup abc-no-dchan redial + * + * Revision 1.64 1998/05/07 19:58:39 detabc + * bugfix in abc_delayed_hangup + * optimize keepalive-tests for abc_rawip + * + * Revision 1.63 1998/05/05 23:23:36 detabc + * change ICMP_HOST_UNREACH to ICMP_NET_UNREACH (only abc-ext.) + * set dev->tbusy to zero in isdn_net_unreachable() (only abc-ext.) + * drop all new packets and send ICMP_NET_UNREACH for + * min. dialwait to max. dialwait * 6 time. (only abc-ext.) + * change random-deliver of packets (small first) from all emcapsulation + * to only rawip with ABC-Router-Flag enabled. + * + * Revision 1.62 1998/05/03 17:40:42 detabc + * Include abc-extension-support for >= 2.1.x Kernels in + * isdn_net.c and isdn_common.c. alpha-test OK and running ! + * + * Revision 1.61 1998/04/16 19:19:42 keil + * Fix from vger (tx max qlength) + * + * Revision 1.60 1998/04/14 16:28:49 he + * Fixed user space access with interrupts off and remaining + * copy_{to,from}_user() -> -EFAULT return codes + * + * Revision 1.59 1998/03/07 22:37:33 fritz + * Bugfix: restore_flags missing. + * + * Revision 1.58 1998/03/07 18:21:05 cal + * Dynamic Timeout-Rule-Handling vs. 971110 included + * + * Revision 1.57 1998/02/25 18:31:13 fritz + * Added debugging output in adjust_header. + * + * Revision 1.56 1998/02/25 17:49:42 he + * Changed return codes caused be failing copy_{to,from}_user to -EFAULT + * * Revision 1.55 1998/02/23 19:38:22 fritz * Corrected check for modified feature-flags. * @@ -248,9 +356,7 @@ #include <linux/isdn.h> #include <net/arp.h> #include <net/dst.h> -#ifndef DEV_NUMBUFFS #include <net/pkt_sched.h> -#endif #include <linux/inetdevice.h> #include "isdn_common.h" #include "isdn_net.h" @@ -265,14 +371,10 @@ /* Prototypes */ int isdn_net_force_dial_lp(isdn_net_local *); -static int isdn_net_wildmat(char *s, char *p); static int isdn_net_start_xmit(struct sk_buff *, struct device *); static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *); -#ifdef DEV_NUMBUFFS -static void dev_purge_queues(struct device *dev); /* move this to net/core/dev.c */ -#endif -char *isdn_net_revision = "$Revision: 1.55 $"; +char *isdn_net_revision = "$Revision: 1.84 $"; /* * Code for raw-networking over ISDN @@ -293,16 +395,21 @@ isdn_net_unreachable(struct device *dev, struct sk_buff *skb, char *reason) dst_link_failure(skb); } + else { /* dial not triggered by rawIP packet */ + printk(KERN_DEBUG "isdn_net: %s: %s\n", + dev->name, + (reason != NULL) ? reason : "reason unknown"); + } } static void isdn_net_reset(struct device *dev) { #ifdef CONFIG_ISDN_X25 - struct concap_device_ops * dops = + struct concap_device_ops * dops = ( (isdn_net_local *) dev->priv ) -> dops; - struct concap_proto * cprot = - ( (isdn_net_local *) dev->priv ) -> netdev -> cprot; + struct concap_proto * cprot = + ( (isdn_net_local *) dev->priv ) -> netdev -> cprot; #endif ulong flags; @@ -311,7 +418,7 @@ isdn_net_reset(struct device *dev) dev->interrupt = 0; dev->tbusy = 0; #ifdef CONFIG_ISDN_X25 - if( cprot && cprot -> pops && dops ) + if( cprot && cprot -> pops && dops ) cprot -> pops -> restart ( cprot, dev, dops ); #endif restore_flags(flags); @@ -338,7 +445,7 @@ isdn_net_open(struct device *dev) if (ifa != NULL) memcpy(dev->dev_addr+2, &ifa->ifa_local, 4); } - + /* If this interface has slaves, start them also */ if ((p = (((isdn_net_local *) dev->priv)->slave))) { @@ -362,6 +469,7 @@ isdn_net_bind_channel(isdn_net_local * lp, int idx) save_flags(flags); cli(); + lp->flags |= ISDN_NET_CONNECTED; lp->isdn_device = dev->drvmap[idx]; lp->isdn_channel = dev->chanmap[idx]; dev->rx_netdev[idx] = lp->netdev; @@ -387,10 +495,6 @@ isdn_net_unbind_channel(isdn_net_local * lp) dev_kfree_skb(lp->sav_skb); lp->sav_skb = NULL; } -#ifdef DEV_NUMBUFFS - if (!lp->master) /* purge only for master device */ - dev_purge_queues(&lp->netdev->dev); -#else if (!lp->master) { /* reset only master device */ /* Moral equivalent of dev_purge_queues(): BEWARE! This chunk of code cannot be called from hardware @@ -398,7 +502,6 @@ isdn_net_unbind_channel(isdn_net_local * lp) */ qdisc_reset(lp->netdev->dev.qdisc); } -#endif lp->dialstate = 0; dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL; dev->st_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL; @@ -444,7 +547,13 @@ isdn_net_autohup() if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) { anymore = 1; l->huptimer++; - if ((l->onhtime) && (l->huptimer > l->onhtime)) { + /* + * if there is some dialmode where timeout-hangup + * should _not_ be done, check for that here + */ + if ((l->onhtime) && + (l->huptimer > l->onhtime)) + { if (l->hupflags & ISDN_MANCHARGE && l->hupflags & ISDN_CHARGEHUP) { while (jiffies - l->chargetime > l->chargeint) @@ -469,6 +578,11 @@ isdn_net_autohup() } else if (l->hupflags & ISDN_INHUP) isdn_net_hangup(&p->dev); } + + if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) { + isdn_net_hangup(&p->dev); + break; + } } p = (isdn_net_dev *) p->next; } @@ -487,7 +601,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) { isdn_net_dev *p = dev->st_netdev[idx]; int cmd = c->command; - + if (p) { isdn_net_local *lp = p->local; #ifdef CONFIG_ISDN_X25 @@ -538,23 +652,12 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) failed. If there are generic encap protocol receiver routines signal the closure of the link*/ - - if( !(lp->flags & ISDN_NET_CONNECTED) + + if( !(lp->flags & ISDN_NET_CONNECTED) && pops && pops -> disconn_ind ) pops -> disconn_ind(cprot); #endif /* CONFIG_ISDN_X25 */ if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) { - lp->flags &= ~ISDN_NET_CONNECTED; - if (lp->first_skb) { - dev_kfree_skb(lp->first_skb); - lp->first_skb = NULL; - } - if (lp->sav_skb) { - dev_kfree_skb(lp->sav_skb); - lp->sav_skb = NULL; - } - isdn_free_channel(lp->isdn_device, lp->isdn_channel, - ISDN_USAGE_NET); #ifdef CONFIG_ISDN_PPP isdn_ppp_free(lp); #endif @@ -562,10 +665,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) printk(KERN_INFO "%s: remote hangup\n", lp->name); printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge); - lp->isdn_device = -1; - lp->isdn_channel = -1; - dev->st_netdev[idx] = NULL; - dev->rx_netdev[idx] = NULL; + isdn_net_unbind_channel(lp); return 1; } break; @@ -607,6 +707,11 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) lp->chargetime = jiffies; printk(KERN_DEBUG "isdn_net: chargetime of %s now %d\n", lp->name, lp->chargetime); + + /* reset dial-timeout */ + lp->dialstarted = 0; + lp->dialwait_timer = 0; + /* Immediately send first skb to speed up arp */ #ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) @@ -617,13 +722,13 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) if( pops ) if( pops->connect_ind) pops->connect_ind(cprot); - #endif /* CONFIG_ISDN_X25 */ if (lp->first_skb) { - + if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb))) lp->first_skb = NULL; - } else { + } + else { /* * dev.tbusy is usually cleared implicitly by isdn_net_xmit(,,lp->first_skb). * With an empty lp->first_skb, we need to do this ourselves @@ -721,6 +826,13 @@ isdn_net_dial(void) break; } anymore = 1; + + if(lp->dialtimeout > 0) + if(lp->dialstarted == 0 || jiffies > (lp->dialstarted + lp->dialtimeout + lp->dialwait)) { + lp->dialstarted = jiffies; + lp->dialwait_timer = 0; + } + lp->dialstate++; /* Fall through */ case 2: @@ -735,12 +847,22 @@ isdn_net_dial(void) lp->dialretry = 0; anymore = 1; lp->dialstate++; - /* Falls through */ + /* Fall through */ case 3: /* Setup interface, dial current phone-number, switch to next number. * If list of phone-numbers is exhausted, increment * retry-counter. */ + if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)) { + char *s; + if (dev->global_flags & ISDN_GLOBAL_STOPPED) + s = "dial suppressed: isdn system stopped"; + else + s = "dial suppressed: dialmode `off'"; + isdn_net_unreachable(&p->dev, lp->first_skb, s); + isdn_net_hangup(&p->dev); + break; + } cmd.driver = lp->isdn_device; cmd.command = ISDN_CMD_SETL2; cmd.arg = lp->isdn_channel + (lp->l2_proto << 8); @@ -765,6 +887,16 @@ isdn_net_dial(void) lp->dialstate = 4; printk(KERN_INFO "%s: Open leased line ...\n", lp->name); } else { + if(lp->dialtimeout > 0) + if(jiffies > (lp->dialstarted + lp->dialtimeout)) { + restore_flags(flags); + lp->dialwait_timer = jiffies + lp->dialwait; + lp->dialstarted = 0; + isdn_net_unreachable(&p->dev, lp->first_skb, "dial: timed out"); + isdn_net_hangup(&p->dev); + break; + } + sprintf(cmd.parm.setup.phone, "%s", lp->dial->num); /* * Switch to next number or back to start if at end of list. @@ -772,6 +904,17 @@ isdn_net_dial(void) if (!(lp->dial = (isdn_net_phone *) lp->dial->next)) { lp->dial = lp->phone[1]; lp->dialretry++; + + if (lp->dialretry > lp->dialmax) { + restore_flags(flags); + if (lp->dialtimeout == 0) { + lp->dialwait_timer = jiffies + lp->dialwait; + lp->dialstarted = 0; + isdn_net_unreachable(&p->dev, lp->first_skb, "dial: tried all numbers dialmax times"); + } + isdn_net_hangup(&p->dev); + break; + } } restore_flags(flags); cmd.driver = lp->isdn_device; @@ -786,7 +929,7 @@ isdn_net_dial(void) isdn_info_update(); } printk(KERN_INFO "%s: dialing %d %s...\n", lp->name, - lp->dialretry - 1, cmd.parm.setup.phone); + lp->dialretry, cmd.parm.setup.phone); lp->dtimer = 0; #ifdef ISDN_DEBUG_NET_DIAL printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device, @@ -810,15 +953,11 @@ isdn_net_dial(void) break; case 4: /* Wait for D-Channel-connect. - * If timeout and max retries not - * reached, switch back to state 3. + * If timeout, switch back to state 3. + * Dialmax-handling moved to state 3. */ - if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) { - if (lp->dialretry < lp->dialmax) { - lp->dialstate = 3; - } else - isdn_net_hangup(&p->dev); - } + if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) + lp->dialstate = 3; anymore = 1; break; case 5: @@ -895,7 +1034,8 @@ isdn_net_dial(void) /* Remote does callback. Hangup after cbdelay, then wait for incoming * call (in state 4). */ - if (lp->dtimer++ > lp->cbdelay) { + if (lp->dtimer++ > lp->cbdelay) + { printk(KERN_INFO "%s: hangup waiting for callback ...\n", lp->name); lp->dtimer = 0; lp->dialstate = 4; @@ -930,7 +1070,6 @@ isdn_net_hangup(struct device *d) #endif if (lp->flags & ISDN_NET_CONNECTED) { - lp->flags &= ~ISDN_NET_CONNECTED; printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name); #ifdef CONFIG_ISDN_PPP isdn_ppp_free(lp); @@ -938,7 +1077,7 @@ isdn_net_hangup(struct device *d) #ifdef CONFIG_ISDN_X25 /* try if there are generic encap protocol receiver routines and signal the closure of - the link */ + the link */ if( pops && pops -> disconn_ind ) pops -> disconn_ind(cprot); #endif /* CONFIG_ISDN_X25 */ @@ -968,7 +1107,7 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp) char addinfo[100]; addinfo[0] = '\0'; - /* This check stolen from 2.1.72 dev_queue_xmit_nit() */ + /* This check stolen from 2.1.72 dev_queue_xmit_nit() */ if (skb->nh.raw < skb->data || skb->nh.raw >= skb->tail) { /* fall back to old isdn_net_log_packet method() */ char * buf = skb->data; @@ -1062,20 +1201,17 @@ isdn_net_send_skb(struct device *ndev, isdn_net_local * lp, if (ret == len) { lp->transcount += len; clear_bit(0, (void *) &(ndev->tbusy)); - mark_bh(NET_BH); return 0; } if (ret < 0) { dev_kfree_skb(skb); lp->stats.tx_errors++; clear_bit(0, (void *) &(ndev->tbusy)); - mark_bh(NET_BH); return 0; } return 1; } - /* * Helper function for isdn_net_start_xmit. * When called, the connection is already established. @@ -1150,9 +1286,11 @@ isdn_net_adjust_hdr(struct sk_buff *skb, struct device *dev) if (!skb) return; if (lp->p_encap == ISDN_NET_ENCAP_ETHER) { - ulong pullsize = (ulong)skb->nh.raw - (ulong)skb->data - ETH_HLEN; - if (pullsize) + int pullsize = (ulong)skb->nh.raw - (ulong)skb->data - ETH_HLEN; + if (pullsize > 0) { + printk(KERN_DEBUG "isdn_net: Pull junk %d\n", pullsize); skb_pull(skb, pullsize); + } } } @@ -1166,7 +1304,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev) { isdn_net_local *lp = (isdn_net_local *) ndev->priv; #ifdef CONFIG_ISDN_X25 - struct concap_proto * cprot = lp -> netdev -> cprot; + struct concap_proto * cprot = lp -> netdev -> cprot; #endif if (ndev->tbusy) { @@ -1179,7 +1317,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev) ndev->tbusy = 1; /* left instead of obsolete test_and_set_bit() */ #ifdef CONFIG_ISDN_X25 /* At this point hard_start_xmit() passes control to the encapsulation - protocol (if present). + protocol (if present). For X.25 auto-dialing is completly bypassed because: - It does not conform with the semantics of a reliable datalink service as needed by X.25 PLP. @@ -1205,17 +1343,46 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev) #endif if (!(lp->flags & ISDN_NET_CONNECTED)) { int chi; + /* only do autodial if allowed by config */ + if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) { + isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'"); + dev_kfree_skb(skb); + ndev->tbusy = 0; + return 0; + } if (lp->phone[1]) { ulong flags; save_flags(flags); cli(); + + if(lp->dialwait_timer <= 0) + if(lp->dialstarted > 0 && lp->dialtimeout > 0 && jiffies < lp->dialstarted + lp->dialtimeout + lp->dialwait) + lp->dialwait_timer = lp->dialstarted + lp->dialtimeout + lp->dialwait; + + if(lp->dialwait_timer > 0) { + if(jiffies < lp->dialwait_timer) { + isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached"); + dev_kfree_skb(skb); + ndev->tbusy = 0; + restore_flags(flags); + return 0; + } else + lp->dialwait_timer = 0; + } + /* Grab a free ISDN-Channel */ - if ((chi = + if (((chi = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto, lp->l3_proto, lp->pre_device, - lp->pre_channel)) < 0) { + lp->pre_channel)) < 0) && + ((chi = + isdn_get_free_channel(ISDN_USAGE_NET, + lp->l2_proto, + lp->l3_proto, + lp->pre_device, + lp->pre_channel^1)) < 0)) { restore_flags(flags); isdn_net_unreachable(ndev, skb, "No channel"); @@ -1227,7 +1394,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev) if (dev->net_verbose) isdn_net_log_skb(skb, lp); lp->dialstate = 1; - lp->flags |= ISDN_NET_CONNECTED; /* Connect interface with channel */ isdn_net_bind_channel(lp, chi); #ifdef CONFIG_ISDN_PPP @@ -1290,8 +1456,8 @@ isdn_net_close(struct device *dev) { struct device *p; #ifdef CONFIG_ISDN_X25 - struct concap_proto * cprot = - ( (isdn_net_local *) dev->priv ) -> netdev -> cprot; + struct concap_proto * cprot = + ( (isdn_net_local *) dev->priv ) -> netdev -> cprot; /* printk(KERN_DEBUG "isdn_net_close %s\n" , dev-> name ); */ #endif @@ -1304,9 +1470,9 @@ isdn_net_close(struct device *dev) /* If this interface has slaves, stop them also */ while (p) { #ifdef CONFIG_ISDN_X25 - cprot = ( (isdn_net_local *) p->priv ) - -> netdev -> cprot; - if( cprot && cprot -> pops ) + cprot = ( (isdn_net_local *) p->priv ) + -> netdev -> cprot; + if( cprot && cprot -> pops ) cprot -> pops -> close( cprot ); #endif isdn_net_hangup(p); @@ -1392,7 +1558,7 @@ isdn_net_slarp_send(isdn_net_local *lp, int is_reply) int len; cisco_hdr *ch; cisco_slarp *s; - + if (!skb) { printk(KERN_WARNING "%s: Could not allocate SLARP reply\n", lp->name); @@ -1406,7 +1572,7 @@ isdn_net_slarp_send(isdn_net_local *lp, int is_reply) s = (cisco_slarp *)skb_put(skb, sizeof(cisco_slarp)); if (is_reply) { s->code = htonl(CISCO_SLARP_REPLY); - memset(&s->slarp.reply.ifaddr, 0, sizeof(__u32)); + memset(&s->slarp.reply.ifaddr, 0, sizeof(__u32)); memset(&s->slarp.reply.netmask, 0, sizeof(__u32)); } else { lp->cisco_myseq++; @@ -1589,7 +1755,7 @@ isdn_net_receive(struct device *ndev, struct sk_buff *skb) default: #ifdef CONFIG_ISDN_X25 /* try if there are generic sync_device receiver routines */ - if(cprot) if(cprot -> pops) + if(cprot) if(cprot -> pops) if( cprot -> pops -> data_ind){ cprot -> pops -> data_ind(cprot,skb); return; @@ -1600,6 +1766,7 @@ isdn_net_receive(struct device *ndev, struct sk_buff *skb) kfree_skb(skb); return; } + netif_rx(skb); return; } @@ -1788,16 +1955,12 @@ isdn_net_init(struct device *ndev) ndev->type = ARPHRD_ETHER; ndev->addr_len = ETH_ALEN; - ndev->tx_queue_len = 10; /* for clients without MPPP 5 is better. */ + /* for clients with MPPP maybe higher values better */ + ndev->tx_queue_len = 30; for (i = 0; i < ETH_ALEN; i++) ndev->broadcast[i] = 0xff; -#ifdef DEV_NUMBUFFS - for (i = 0; i < DEV_NUMBUFFS; i++) - skb_queue_head_init(&ndev->buffs[i]); -#endif - /* The ISDN-specific entries in the device structure. */ ndev->open = &isdn_net_open; ndev->hard_start_xmit = &isdn_net_start_xmit; @@ -1813,86 +1976,15 @@ isdn_net_init(struct device *ndev) max_hlhdr_len = dev->drv[drvidx]->interface->hl_hdrlen; ndev->hard_header_len = ETH_HLEN + max_hlhdr_len; - ndev->stop = &isdn_net_close; ndev->get_stats = &isdn_net_get_stats; ndev->rebuild_header = &isdn_net_rebuild_header; - #ifdef CONFIG_ISDN_PPP ndev->do_ioctl = isdn_ppp_dev_ioctl; #endif return 0; } -/* - * I picked the pattern-matching-functions from an old GNU-tar version (1.10) - * It was originally written and put to PD by rs@mirror.TMC.COM (Rich Salz) - */ - -static int -isdn_net_Star(char *s, char *p) -{ - while (isdn_net_wildmat(s, p) == 0) - if (*++s == '\0') - return (0); - return (1); -} - -/* - * Shell-type Pattern-matching for incoming caller-Ids - * This function gets a string in s and checks, if it matches the pattern - * given in p. It returns 1 on success, 0 otherwise. - * - * Possible Patterns: - * - * '?' matches one character - * '*' matches zero or more characters - * [xyz] matches the set of characters in brackets. - * [^xyz] matches any single character not in the set of characters - */ - -static int -isdn_net_wildmat(char *s, char *p) -{ - register int last; - register int matched; - register int reverse; - - for (; *p; s++, p++) - switch (*p) { - case '\\': - /* - * Literal match with following character, - * fall through. - */ - p++; - default: - if (*s != *p) - return (0); - continue; - case '?': - /* Match anything. */ - if (*s == '\0') - return (0); - continue; - case '*': - /* Trailing star matches everything. */ - return (*++p ? isdn_net_Star(s, p) : 1); - case '[': - /* [^....] means inverse character class. */ - if ((reverse = (p[1] == '^'))) - p++; - for (last = 0, matched = 0; *++p && (*p != ']'); last = *p) - /* This next line requires a good C compiler. */ - if (*p == '-' ? *s <= *++p && *s >= last : *s == *p) - matched = 1; - if (matched == reverse) - return (0); - continue; - } - return (*s == '\0'); -} - static void isdn_net_swapbind(int drvidx) { @@ -1945,6 +2037,8 @@ isdn_net_swap_usage(int i1, int i2) * 2 = Reject call, wait cbdelay, then call back * 3 = Reject call * 4 = Wait cbdelay, then call back + * 5 = No appropriate interface for this call, + * would eventually match if CID was longer. */ int isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) @@ -1953,6 +2047,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) int si1; int si2; int ematch; + int wret; int swapped; int sidx = 0; isdn_net_dev *p; @@ -1987,13 +2082,13 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) } n = (isdn_net_phone *) 0; p = dev->netdev; - ematch = 0; + ematch = wret = swapped = 0; #ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx, dev->usage[idx]); #endif - swapped = 0; while (p) { + int matchret; isdn_net_local *lp = p->local; /* If last check has triggered as binding-swap, revert it */ @@ -2006,18 +2101,22 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) break; } swapped = 0; - if (!strcmp(isdn_map_eaz2msn(lp->msn, di), eaz)) + if (!(matchret = isdn_wildmat(eaz, isdn_map_eaz2msn(lp->msn, di)))) ematch = 1; + /* Remember if more numbers eventually can match */ + if (matchret > wret) + wret = matchret; #ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n", lp->name, lp->msn, lp->flags, lp->dialstate); #endif - if ((!strcmp(isdn_map_eaz2msn(lp->msn, di), eaz)) && /* EAZ is matching */ - (((!(lp->flags & ISDN_NET_CONNECTED)) && /* but not connected */ - (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */ - ((((lp->dialstate == 4) || (lp->dialstate == 12)) && /* if dialing */ - (!(lp->flags & ISDN_NET_CALLBACK))) /* but no callback */ - ))) { + if ((!matchret) && /* EAZ is matching */ + (((!(lp->flags & ISDN_NET_CONNECTED)) && /* but not connected */ + (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */ + ((((lp->dialstate == 4) || (lp->dialstate == 12)) && /* if dialing */ + (!(lp->flags & ISDN_NET_CALLBACK))) /* but no callback */ + ))) + { #ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n", lp->pre_device, lp->pre_channel); @@ -2085,8 +2184,6 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) #ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: already on 2nd channel\n"); #endif - p = (isdn_net_dev *) p->next; - continue; } } } @@ -2096,7 +2193,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) n = lp->phone[0]; if (lp->flags & ISDN_NET_SECURE) { while (n) { - if (isdn_net_wildmat(nr, n->num)) + if (!isdn_wildmat(nr, n->num)) break; n = (isdn_net_phone *) n->next; } @@ -2105,7 +2202,21 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) #ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: match3\n"); #endif - /* Here we got an interface matched, now see if it is up. + /* matching interface found */ + + /* + * Is the state STOPPED? + * If so, no dialin is allowed, + * so reject actively. + * */ + if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) { + restore_flags(flags); + printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n", + lp->name); + return 3; + } + /* + * Is the interface up? * If not, reject the call actively. */ if (!p->dev.start) { @@ -2140,6 +2251,17 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) } if (lp->flags & ISDN_NET_CALLBACK) { int chi; + /* + * Is the state MANUAL? + * If so, no callback can be made, + * so reject actively. + * */ + if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) { + restore_flags(flags); + printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n", + lp->name); + return 3; + } printk(KERN_DEBUG "%s: call from %s -> %s, start callback\n", lp->name, nr, eaz); if (lp->phone[1]) { @@ -2155,7 +2277,6 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) /* Setup dialstate. */ lp->dtimer = 0; lp->dialstate = 11; - lp->flags |= ISDN_NET_CONNECTED; /* Connect interface with channel */ isdn_net_bind_channel(lp, chi); #ifdef CONFIG_ISDN_PPP @@ -2217,10 +2338,10 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) p = (isdn_net_dev *) p->next; } /* If none of configured EAZ/MSN matched and not verbose, be silent */ - if (ematch || dev->net_verbose) + if (!ematch || dev->net_verbose) printk(KERN_INFO "isdn_net: call from %s -> %d %s ignored\n", nr, di, eaz); restore_flags(flags); - return 0; + return (wret == 2)?5:0; } /* @@ -2253,6 +2374,7 @@ isdn_net_force_dial_lp(isdn_net_local * lp) ulong flags; save_flags(flags); cli(); + /* Grab a free ISDN-Channel */ if ((chi = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto, lp->l3_proto, @@ -2263,7 +2385,6 @@ isdn_net_force_dial_lp(isdn_net_local * lp) return -EAGAIN; } lp->dialstate = 1; - lp->flags |= ISDN_NET_CONNECTED; /* Connect interface with channel */ isdn_net_bind_channel(lp, chi); #ifdef CONFIG_ISDN_PPP @@ -2285,6 +2406,20 @@ isdn_net_force_dial_lp(isdn_net_local * lp) } /* + * This is called from certain upper protocol layers (multilink ppp + * and x25iface encapsulation module) that want to initiate dialing + * themselves. + */ +int +isdn_net_dial_req(isdn_net_local * lp) +{ + /* is there a better error code? */ + if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) return -EBUSY; + + return isdn_net_force_dial_lp(lp); +} + +/* * Force a net-interface to dial out. * This is always called from within userspace (ISDN_IOCTL_NET_DIAL). */ @@ -2383,8 +2518,13 @@ isdn_net_new(char *name, struct device *master) netdev->local->onhtime = 10; /* Default hangup-time for saving costs of those who forget configuring this */ netdev->local->dialmax = 1; - netdev->local->flags = ISDN_NET_CBHUP; /* Hangup before Callback */ + netdev->local->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL; /* Hangup before Callback, manual dial */ netdev->local->cbdelay = 25; /* Wait 5 secs before Callback */ + netdev->local->dialtimeout = -1; /* Infinite Dial-Timeout */ + netdev->local->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */ + netdev->local->dialstarted = 0; /* Jiffies of last dial-start */ + netdev->local->dialwait_timer = 0; /* Jiffies of earliest next dial-start */ + /* Put into to netdev-chain */ netdev->next = (void *) dev->netdev; dev->netdev = netdev; @@ -2465,7 +2605,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) save_flags(flags); cli(); /* avoid races with incoming events trying to call cprot->pops methods */ - if( cprot && cprot -> pops ) + if( cprot && cprot -> pops ) cprot -> pops -> proto_del ( cprot ); p -> cprot = NULL; lp -> dops = NULL; @@ -2479,7 +2619,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) p -> cprot = isdn_concap_new( cfg -> p_encap ); /* p -> cprot == NULL now if p_encap is not supported by means of the concap_proto mechanism */ - /* the protocol is not configured yet; this will + /* the protocol is not configured yet; this will happen later when isdn_net_reset() is called */ #endif } @@ -2508,7 +2648,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) if( cfg->p_encap >= 0 && cfg->p_encap <= ISDN_NET_ENCAP_MAX_ENCAP ) break; - printk(KERN_WARNING + printk(KERN_WARNING "%s: encapsulation protocol %d not supported\n", p->local->name, cfg->p_encap); return -EINVAL; @@ -2583,6 +2723,8 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) lp->triggercps = cfg->triggercps; lp->slavedelay = cfg->slavedelay * HZ; lp->pppbind = cfg->pppbind; + lp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1; + lp->dialwait = cfg->dialwait * HZ; if (cfg->secure) lp->flags |= ISDN_NET_SECURE; else @@ -2604,6 +2746,16 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) lp->flags &= ~ISDN_NET_CALLBACK; break; } + lp->flags &= ~ISDN_NET_DIALMODE_MASK; /* first all bits off */ + if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) { + /* old isdnctrl version, where only 0 or 1 is given */ + printk(KERN_WARNING + "Old isdnctrl version detected! Please update.\n"); + lp->flags |= ISDN_NET_DM_OFF; /* turn on `off' bit */ + } + else { + lp->flags |= cfg->dialmode; /* turn on selected bits */ + } if (cfg->chargehup) lp->hupflags |= ISDN_CHARGEHUP; else @@ -2671,6 +2823,7 @@ isdn_net_getcfg(isdn_net_ioctl_cfg * cfg) if (lp->flags & ISDN_NET_CBOUT) cfg->callback = 2; cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0; + cfg->dialmode = lp->flags & ISDN_NET_DIALMODE_MASK; cfg->chargehup = (lp->hupflags & 4) ? 1 : 0; cfg->ihup = (lp->hupflags & 8) ? 1 : 0; cfg->cbdelay = lp->cbdelay; @@ -2680,6 +2833,8 @@ isdn_net_getcfg(isdn_net_ioctl_cfg * cfg) cfg->chargeint = (lp->hupflags & ISDN_CHARGEHUP) ? (lp->chargeint / HZ) : 0; cfg->pppbind = lp->pppbind; + cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1; + cfg->dialwait = lp->dialwait / HZ; if (lp->slave) strcpy(cfg->slave, ((isdn_net_local *) lp->slave->priv)->name); else @@ -2749,9 +2904,37 @@ isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones) } /* - * Delete a phone-number from an interface. + * Copy a string containing the peer's phone number of a connected interface + * to user space. */ +int +isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone *peer) +{ + isdn_net_dev *p = isdn_net_findif(phone->name); + int ch, dv, idx; + if (!p) return -ENODEV; + /* + * Theoretical race: while this executes, the remote number might + * become invalid (hang up) or change (new connection), resulting + * in (partially) wrong number copied to user. This race + * currently ignored. + */ + ch = p->local->isdn_channel; + dv = p->local->isdn_device; + if(ch<0 && dv<0) return -ENOTCONN; + idx = isdn_dc2minor(dv, ch); + if (idx<0) return -ENODEV; + /* for pre-bound channels, we need this extra check */ + if ( strncmp(dev->num[idx],"???",3) == 0 ) return -ENOTCONN; + strncpy(phone->phone,dev->num[idx],ISDN_MSNLEN); + phone->outgoing=USG_OUTGOING(idx); + if ( copy_to_user(peer,phone,sizeof(*peer)) ) return -EFAULT; + return 0; +} +/* + * Delete a phone-number from an interface. + */ int isdn_net_delphone(isdn_net_ioctl_phone * phone) { @@ -2957,21 +3140,3 @@ isdn_net_rmall(void) restore_flags(flags); return 0; } - -#ifdef DEV_NUMBUFFS -/* - * helper function to flush device queues - * the better place would be net/core/dev.c - */ -static void -dev_purge_queues(struct device *dev) -{ - int i; - for (i = 0; i < DEV_NUMBUFFS; i++) { - struct sk_buff *skb; - while ((skb = skb_dequeue(&dev->buffs[i]))) - dev_kfree_skb(skb); - } - -} -#endif diff --git a/drivers/isdn/isdn_net.h b/drivers/isdn/isdn_net.h index 19a084dd2..79d4ff615 100644 --- a/drivers/isdn/isdn_net.h +++ b/drivers/isdn/isdn_net.h @@ -1,8 +1,8 @@ -/* $Id: isdn_net.h,v 1.6 1997/10/09 21:28:54 fritz Exp $ +/* $Id: isdn_net.h,v 1.9 1999/04/12 12:33:27 fritz Exp $ * header for Linux ISDN subsystem, network related functions (linklevel). * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) * @@ -21,6 +21,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.h,v $ + * Revision 1.9 1999/04/12 12:33:27 fritz + * Changes from 2.0 tree. + * + * Revision 1.8 1998/10/30 17:55:33 he + * dialmode for x25iface and multulink ppp + * + * Revision 1.7 1998/08/31 21:09:55 he + * new ioctl IIOCNETGPN for /dev/isdninfo (get network interface' + * peer phone number) + * * Revision 1.6 1997/10/09 21:28:54 fritz * New HL<->LL interface: * New BSENT callback with nr. of bytes included. @@ -99,6 +109,7 @@ extern int isdn_net_setcfg(isdn_net_ioctl_cfg *); extern int isdn_net_getcfg(isdn_net_ioctl_cfg *); extern int isdn_net_addphone(isdn_net_ioctl_phone *); extern int isdn_net_getphones(isdn_net_ioctl_phone *, char *); +extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone *); extern int isdn_net_delphone(isdn_net_ioctl_phone *); extern int isdn_net_find_icall(int, int, int, setup_parm); extern void isdn_net_hangup(struct device *); @@ -111,3 +122,4 @@ extern int isdn_net_send_skb(struct device *, isdn_net_local *, struct sk_buff *); extern int isdn_net_rcv_skb(int, struct sk_buff *); extern void isdn_net_slarp_out(void); +extern int isdn_net_dial_req(isdn_net_local *); diff --git a/drivers/isdn/isdn_ppp.c b/drivers/isdn/isdn_ppp.c index 5da3a49f0..7bce66d44 100644 --- a/drivers/isdn/isdn_ppp.c +++ b/drivers/isdn/isdn_ppp.c @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.c,v 1.33 1998/02/20 17:11:54 fritz Exp $ +/* $Id: isdn_ppp.c,v 1.47 1999/04/18 14:06:59 fritz Exp $ * * Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -18,11 +18,50 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Note: This file differs from the corresponding revision as present in the - * isdn4linux CVS repository because some later bug fixes have been extracted - * from the repository and merged into this file. -- Henner Eisen - * * $Log: isdn_ppp.c,v $ + * Revision 1.47 1999/04/18 14:06:59 fritz + * Removed TIMRU stuff. + * + * Revision 1.46 1999/04/12 12:33:35 fritz + * Changes from 2.0 tree. + * + * Revision 1.45 1998/12/30 17:48:24 paul + * fixed syncPPP callback out + * + * Revision 1.44 1998/10/30 17:55:34 he + * dialmode for x25iface and multulink ppp + * + * Revision 1.43 1998/10/29 17:23:54 hipp + * Minor MPPP fixes, verboser logging. + * + * Revision 1.42 1998/07/20 11:30:07 hipp + * Readded compression check + * + * Revision 1.41 1998/07/08 16:50:57 hipp + * Compression changes + * + * Revision 1.40 1998/04/06 19:07:27 hipp + * added check, whether compression is enabled. + * + * Revision 1.39 1998/03/25 22:46:53 hipp + * Some additional CCP changes. + * + * Revision 1.38 1998/03/24 16:33:06 hipp + * More CCP changes. BSD compression now "works" on a local loopback link. + * Moved some isdn_ppp stuff from isdn.h to isdn_ppp.h + * + * Revision 1.37 1998/03/22 18:50:49 hipp + * Added BSD Compression for syncPPP .. UNTESTED at the moment + * + * Revision 1.36 1998/03/09 17:46:30 he + * merged in 2.1.89 changes + * + * Revision 1.35 1998/03/07 18:21:11 cal + * Dynamic Timeout-Rule-Handling vs. 971110 included + * + * Revision 1.34 1998/02/25 17:49:48 he + * Changed return codes caused be failing copy_{to,from}_user to -EFAULT + * * Revision 1.33 1998/02/20 17:11:54 fritz * Changes for recent kernels. * @@ -157,13 +196,16 @@ * experimental for dynamic addressing: readdress IP frames */ #undef ISDN_SYNCPPP_READDRESS +#define CONFIG_ISDN_CCP 1 #include <linux/config.h> #define __NO_VERSION__ #include <linux/module.h> #include <linux/version.h> -#include <linux/isdn.h> #include <linux/poll.h> +#include <linux/isdn.h> +#include <linux/ppp-comp.h> + #include "isdn_common.h" #include "isdn_ppp.h" #include "isdn_net.h" @@ -180,13 +222,33 @@ static int isdn_ppp_closewait(int slot); static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto); static int isdn_ppp_if_get_unit(char *namebuf); -static int isdn_ppp_set_compressor(struct ippp_struct *is,int num); +static int isdn_ppp_set_compressor(struct ippp_struct *is,struct isdn_ppp_comp_data *); static struct sk_buff *isdn_ppp_decompress(struct sk_buff *, - struct ippp_struct *,struct ippp_struct *); + struct ippp_struct *,struct ippp_struct *,int proto); static void isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp, - struct sk_buff *skb); + struct sk_buff *skb,int proto); static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto, struct ippp_struct *is,struct ippp_struct *master,int type); +static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, + struct sk_buff *skb); + +/* New CCP stuff */ +static void isdn_ppp_ccp_kickup(struct ippp_struct *is); +static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto, + unsigned char code, unsigned char id, + unsigned char *data, int len); +static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is); +static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is, + unsigned char id); +static void isdn_ppp_ccp_timer_callback(unsigned long closure); +static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is, + unsigned char id); +static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is, + struct isdn_ppp_resetparams *rp); +static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is, + unsigned char id); + + #ifdef CONFIG_ISDN_MPP static int isdn_ppp_bundle(struct ippp_struct *, int unit); @@ -199,18 +261,16 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb, static void isdn_ppp_free_mpqueue(isdn_net_dev *); #endif -char *isdn_ppp_revision = "$Revision: 1.33 $"; +char *isdn_ppp_revision = "$Revision: 1.47 $"; static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; static struct isdn_ppp_compressor *ipc_head = NULL; -extern int isdn_net_force_dial_lp(isdn_net_local *); - /* * frame log (debug) */ static void -isdn_ppp_frame_log(char *info, char *data, int len, int maxlen) +isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot) { int cnt, j, @@ -223,13 +283,14 @@ isdn_ppp_frame_log(char *info, char *data, int len, int maxlen) for (i = 0, cnt = 0; cnt < maxlen; i++) { for (j = 0; j < 16 && cnt < maxlen; j++, cnt++) sprintf(buf + j * 3, "%02x ", (unsigned char) data[cnt]); - printk(KERN_DEBUG "%s[%d]: %s\n", info, i, buf); + printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n",unit,slot, info, i, buf); } } /* * unbind isdn_net_local <=> ippp-device * note: it can happen, that we hangup/free the master before the slaves + * in this case we bind another lp to the master device */ int isdn_ppp_free(isdn_net_local * lp) @@ -267,8 +328,7 @@ isdn_ppp_free(isdn_net_local * lp) if ((is->state & IPPP_CONNECT)) isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */ else if (is->state & IPPP_ASSIGNED) - is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGEND' staet */ - + is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */ if (is->debug & 0x1) printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp); @@ -320,14 +380,16 @@ isdn_ppp_bind(isdn_net_local * lp) } } } else { - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if (ippp_table[i]->minor == lp->pppbind && ippp_table[i]->state == IPPP_OPEN) + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + if (ippp_table[i]->minor == lp->pppbind && + (ippp_table[i]->state & IPPP_OPEN) == IPPP_OPEN) break; + } } if (i >= ISDN_MAX_CHANNELS) { restore_flags(flags); - printk(KERN_WARNING "isdn_ppp_bind: Can't find usable ippp device.\n"); + printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n"); return -1; } unit = isdn_ppp_if_get_unit(lp->name); /* get unit number from interface name .. ugly! */ @@ -336,6 +398,15 @@ isdn_ppp_bind(isdn_net_local * lp) return -1; } lp->ppp_slot = i; + + /* reset some values */ + lp->netdev->ib.bundled = 0; + lp->netdev->ib.next_num = 0; + lp->netdev->ib.modify = 0; + lp->netdev->ib.last = NULL; + lp->netdev->ib.min = 0; + lp->netdev->ib.sq = NULL; + is = ippp_table[i]; is->lp = lp; is->unit = unit; @@ -359,7 +430,9 @@ isdn_ppp_wakeup_daemon(isdn_net_local * lp) ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; +#if LINUX_VERSION_CODE < 131841 if (ippp_table[lp->ppp_slot]->wq) +#endif wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq); } @@ -377,7 +450,11 @@ isdn_ppp_closewait(int slot) return 0; is = ippp_table[slot]; +#if LINUX_VERSION_CODE < 131841 if (is->state && is->wq) +#else + if (is->state) +#endif wake_up_interruptible(&is->wq); is->state = IPPP_CLOSEWAIT; @@ -418,14 +495,19 @@ isdn_ppp_open(int min, struct file *file) } is = file->private_data = ippp_table[slot]; +#if 0 if (is->debug & 0x1) +#endif printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, min, is->state); /* compression stuff */ - is->compressor = NULL; - is->decomp_stat = is->comp_stat = NULL; - is->link_compressor = NULL; - is->link_decomp_stat = is->link_comp_stat = NULL; + is->link_compressor = is->compressor = NULL; + is->link_decompressor = is->decompressor = NULL; + is->link_comp_stat = is->comp_stat = NULL; + is->link_decomp_stat = is->decomp_stat = NULL; + is->compflags = 0; + + is->reset = isdn_ppp_ccp_reset_alloc(is); is->lp = NULL; is->mp_seqno = 0; /* MP sequence number */ @@ -437,8 +519,11 @@ isdn_ppp_open(int min, struct file *file) is->mru = 1524; /* MRU, default 1524 */ is->maxcid = 16; /* VJ: maxcid */ is->tk = current; +#if LINUX_VERSION_CODE < 131841 is->wq = NULL; /* read() wait queue */ - is->wq1 = NULL; /* select() wait queue */ +#else + init_waitqueue_head(&is->wq); +#endif is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */ is->last = is->rq; is->minor = min; @@ -491,10 +576,30 @@ isdn_ppp_release(int min, struct file *file) is->last = is->rq; #ifdef CONFIG_ISDN_PPP_VJ +/* TODO: if this was the previous master: link the slcomp to the new master */ slhc_free(is->slcomp); is->slcomp = NULL; #endif +/* TODO: if this was the previous master: link the the stuff to the new master */ + if(is->comp_stat) + is->compressor->free(is->comp_stat); + if(is->link_comp_stat) + is->link_compressor->free(is->link_comp_stat); + if(is->link_decomp_stat) + is->link_decompressor->free(is->link_decomp_stat); + if(is->decomp_stat) + is->decompressor->free(is->decomp_stat); + is->compressor = is->link_compressor = NULL; + is->decompressor = is->link_decompressor = NULL; + is->comp_stat = is->link_comp_stat = NULL; + is->decomp_stat = is->link_decomp_stat = NULL; + + if(is->reset) + kfree(is->reset); + is->reset = NULL; + + /* this slot is ready for new connections */ is->state = 0; } @@ -505,7 +610,7 @@ static int get_arg(void *b, void *val, int len) { if (len <= 0) - len = sizeof(unsigned long); + len = sizeof(void *); if (copy_from_user((void *) val, b, len)) return -EFAULT; return 0; @@ -515,15 +620,12 @@ get_arg(void *b, void *val, int len) * set arg .. ioctl helper */ static int -set_arg(void *b, unsigned long val, void *str) +set_arg(void *b, void *val,int len) { - if (!str) { - if (copy_to_user(b, (void *) &val, 4)) - return -EFAULT; - } else { - if (copy_to_user(b, str, val)) - return -EFAULT; - } + if(len <= 0) + len = sizeof(void *); + if (copy_to_user(b, (void *) val, len)) + return -EFAULT; return 0; } @@ -534,9 +636,10 @@ int isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) { unsigned long val; - int num,r; + int r,i,j; struct ippp_struct *is; isdn_net_local *lp; + struct isdn_ppp_comp_data data; is = (struct ippp_struct *) file->private_data; lp = is->lp; @@ -552,7 +655,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) #ifdef CONFIG_ISDN_MPP if (!(is->state & IPPP_CONNECT)) return -EINVAL; - if ((r = get_arg((void *) arg, &val, 0))) + if ((r = get_arg((void *) arg, &val, sizeof(val) ))) return r; printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n", (int) min, (int) is->unit, (int) val); @@ -562,24 +665,30 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) #endif break; case PPPIOCGUNIT: /* get ppp/isdn unit number */ - if ((r = set_arg((void *) arg, is->unit, NULL))) + if ((r = set_arg((void *) arg, &is->unit, sizeof(is->unit) ))) + return r; + break; + case PPPIOCGIFNAME: + if(!lp) + return -EINVAL; + if ((r = set_arg((void *) arg, lp->name,strlen(lp->name)))) return r; break; case PPPIOCGMPFLAGS: /* get configuration flags */ - if ((r = set_arg((void *) arg, is->mpppcfg, NULL))) + if ((r = set_arg((void *) arg, &is->mpppcfg, sizeof(is->mpppcfg) ))) return r; break; case PPPIOCSMPFLAGS: /* set configuration flags */ - if ((r = get_arg((void *) arg, &val, 0))) + if ((r = get_arg((void *) arg, &val, sizeof(val) ))) return r; is->mpppcfg = val; break; case PPPIOCGFLAGS: /* get configuration flags */ - if ((r = set_arg((void *) arg, is->pppcfg, NULL))) + if ((r = set_arg((void *) arg, &is->pppcfg,sizeof(is->pppcfg) ))) return r; break; case PPPIOCSFLAGS: /* set configuration flags */ - if ((r = get_arg((void *) arg, &val, 0))) { + if ((r = get_arg((void *) arg, &val, sizeof(val) ))) { return r; } if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) { @@ -598,12 +707,12 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) if (lp) { struct ppp_idle pidle; pidle.xmit_idle = pidle.recv_idle = lp->huptimer; - if ((r = set_arg((void *) arg, sizeof(struct ppp_idle), &pidle))) + if ((r = set_arg((void *) arg, &pidle,sizeof(struct ppp_idle)))) return r; } break; case PPPIOCSMRU: /* set receive unit size for PPP */ - if ((r = get_arg((void *) arg, &val, 0))) + if ((r = get_arg((void *) arg, &val, sizeof(val) ))) return r; is->mru = val; break; @@ -612,7 +721,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) case PPPIOCSMPMTU: break; case PPPIOCSMAXCID: /* set the maximum compression slot id */ - if ((r = get_arg((void *) arg, &val, 0))) + if ((r = get_arg((void *) arg, &val, sizeof(val) ))) return r; val++; if (is->maxcid != val) { @@ -635,31 +744,33 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) } break; case PPPIOCGDEBUG: - if ((r = set_arg((void *) arg, is->debug, 0))) + if ((r = set_arg((void *) arg, &is->debug, sizeof(is->debug) ))) return r; break; case PPPIOCSDEBUG: - if ((r = get_arg((void *) arg, &val, 0))) + if ((r = get_arg((void *) arg, &val, sizeof(val) ))) return r; is->debug = val; break; case PPPIOCGCOMPRESSORS: { - unsigned long protos = 0; + unsigned long protos[8] = {0,}; struct isdn_ppp_compressor *ipc = ipc_head; while(ipc) { - protos |= (0x1<<ipc->num); + j = ipc->num / (sizeof(long)*8); + i = ipc->num % (sizeof(long)*8); + if(j < 8) + protos[j] |= (0x1<<i); ipc = ipc->next; } - if ((r = set_arg((void *) arg, protos, 0))) + if ((r = set_arg((void *) arg,protos,8*sizeof(long) ))) return r; } break; case PPPIOCSCOMPRESSOR: - if ((r = get_arg((void *) arg, &num, sizeof(int)))) + if ((r = get_arg((void *) arg, &data, sizeof(struct isdn_ppp_comp_data)))) return r; - return isdn_ppp_set_compressor(is, num); - break; + return isdn_ppp_set_compressor(is, &data); case PPPIOCGCALLINFO: { struct pppcallinfo pci; @@ -678,7 +789,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) if(lp->flags & ISDN_NET_CALLBACK) pci.calltype |= CALLTYPE_CALLBACK; } - return set_arg((void *)arg,sizeof(struct pppcallinfo),&pci); + return set_arg((void *)arg,&pci,sizeof(struct pppcallinfo)); } default: break; @@ -701,9 +812,12 @@ isdn_ppp_poll(struct file *file, poll_table * wait) printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n", MINOR(file->f_dentry->d_inode->i_rdev)); + /* just registers wait_queue hook. This doesn't really wait. */ poll_wait(file, &is->wq, wait); if (!(is->state & IPPP_OPEN)) { + if(is->state == IPPP_CLOSEWAIT) + return POLLHUP; printk(KERN_DEBUG "isdn_ppp: device not open\n"); return POLLERR; } @@ -777,7 +891,9 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot) is->last = bl->next; restore_flags(flags); +#if LINUX_VERSION_CODE < 131841 if (is->wq) +#endif wake_up_interruptible(&is->wq); return len; @@ -864,7 +980,8 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count) if (lp->isdn_device < 0 || lp->isdn_channel < 0) return 0; - if (dev->drv[lp->isdn_device]->running && lp->dialstate == 0 && + if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) && + lp->dialstate == 0 && (lp->flags & ISDN_NET_CONNECTED)) { int cnt; struct sk_buff *skb; @@ -877,8 +994,11 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count) return -EFAULT; if (is->debug & 0x40) { printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len); - isdn_ppp_frame_log("xmit", skb->data, skb->len, 32); + isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,is->unit,lp->ppp_slot); } + + isdn_ppp_send_ccp(lp->netdev,lp,skb); /* keeps CCP/compression states in sync */ + if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb)) != count) { if (lp->sav_skb) { dev_kfree_skb(lp->sav_skb); @@ -962,8 +1082,9 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf is = ippp_table[lp->ppp_slot]; if (is->debug & 0x4) { - printk(KERN_DEBUG "ippp_receive: len: %d\n", (int) skb->len); - isdn_ppp_frame_log("receive", skb->data, skb->len, 32); + printk(KERN_DEBUG "ippp_receive: is:%08lx lp:%08lx slot:%d unit:%d len:%d\n", + (long)is,(long)lp,lp->ppp_slot,is->unit,(int) skb->len); + isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,lp->ppp_slot); } if (net_dev->local->master) { printk(KERN_WARNING "isdn_ppp_receice: net_dev != master\n"); @@ -981,13 +1102,18 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf #ifdef CONFIG_ISDN_MPP if (!(is->mpppcfg & SC_REJ_MP_PROT)) { int sqno_end; - - if(proto == PPP_LINK_COMP) { - printk(KERN_DEBUG "received single link compressed frame\n"); - skb = isdn_ppp_decompress(skb,is,NULL); - if(!skb) - return; - proto = isdn_ppp_strip_proto(skb); + + if(is->compflags & SC_LINK_DECOMP_ON) { + if(proto == PPP_LINK_COMP) { + if(is->debug & 0x10) + printk(KERN_DEBUG "received single link compressed frame\n"); + skb = isdn_ppp_decompress(skb,is,NULL,proto); + if(!skb) + return; + proto = isdn_ppp_strip_proto(skb); + } + else + isdn_ppp_decompress(skb,is,NULL,proto); } if (proto == PPP_MP) { @@ -1054,7 +1180,8 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf } min_sqno &= mask; for (lpq = net_dev->queue;;) { - ippp_table[lpq->ppp_slot]->last_link_seqno &= mask; + if(ippp_table[lpq->ppp_slot]->last_link_seqno >= 0) + ippp_table[lpq->ppp_slot]->last_link_seqno &= mask; lpq = lpq->next; if (lpq == net_dev->queue) break; @@ -1149,17 +1276,31 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff if (is->debug & 0x10) { printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto); - isdn_ppp_frame_log("rpush", skb->data, skb->len, 32); + isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit,lp->ppp_slot); } if(proto == PPP_COMP) { if(!lp->master) - skb = isdn_ppp_decompress(skb,is,is); + skb = isdn_ppp_decompress(skb,is,is,proto); else - skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot]); - if(!skb) + skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot],proto); + + if(!skb) { + printk(KERN_DEBUG "ippp: compressed frame discarded!\n"); return; + } + proto = isdn_ppp_strip_proto(skb); + if (is->debug & 0x10) { + printk(KERN_DEBUG "RPostDecomp, skb %d %04x\n", (int) skb->len, proto); + isdn_ppp_frame_log("R-Decomp", skb->data, skb->len, 32,is->unit,lp->ppp_slot); + } + } + else if(is->compflags & SC_DECOMP_ON) { /* If decomp is ON */ + if(!lp->master) + isdn_ppp_decompress(skb,is,is,proto); + else + isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot],proto); } switch (proto) { @@ -1226,7 +1367,13 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff #endif break; case PPP_CCP: - isdn_ppp_receive_ccp(net_dev,lp,skb); + case PPP_LINK_CCP: + isdn_ppp_receive_ccp(net_dev,lp,skb,proto); + /* Dont pop up ResetReq/Ack stuff to the daemon any + longer - the job is done already */ + if(skb->data[0] == CCP_RESETREQ || + skb->data[0] == CCP_RESETACK) + break; /* fall through */ default: isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */ @@ -1234,10 +1381,10 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff return; } + /* Reset hangup-timer */ + lp->huptimer = 0; netif_rx(skb); /* net_dev->local->stats.rx_packets++; *//* done in isdn_net.c */ - /* Reset hangup-timer */ - lp->huptimer = 0; return; } @@ -1338,7 +1485,6 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) lp = nlp; } ipt = ippp_table[lp->ppp_slot]; - lp->huptimer = 0; /* @@ -1354,6 +1500,8 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) if (ipt->debug & 0x4) printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len); + if (ipts->debug & 0x40) + isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32,ipts->unit,lp->ppp_slot); #ifdef CONFIG_ISDN_PPP_VJ if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */ @@ -1393,10 +1541,11 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) } #endif - /* - * normal or bundle compression - */ - skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0); + /* + * normal (single link) or bundle compression + */ + if(ipts->compflags & SC_COMP_ON) + skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0); if (ipt->debug & 0x24) printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto); @@ -1430,9 +1579,10 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) #endif /* - * 'link' compression + * 'link in bundle' compression ... */ - skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1); + if(ipt->compflags & SC_LINK_COMP_ON) + skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1); if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) { unsigned char *data = isdn_ppp_skb_push(&skb,1); @@ -1459,7 +1609,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) if (ipts->debug & 0x40) { printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len); - isdn_ppp_frame_log("xmit", skb->data, skb->len, 32); + isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,ipt->unit,lp->ppp_slot); } if (isdn_net_send_skb(dev, lp, skb)) { if (lp->sav_skb) { /* whole sav_skb processing with disabled IRQs ?? */ @@ -1473,6 +1623,12 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) #ifdef CONFIG_ISDN_MPP +/* + * free SQ queue + * ------------- + * Note: We need two queues for MPPP. The SQ queue holds fully (re)assembled frames, + * that can't be delivered, because there is an outstanding earlier frame + */ static void isdn_ppp_free_sqqueue(isdn_net_dev * p) { @@ -1489,6 +1645,12 @@ isdn_ppp_free_sqqueue(isdn_net_dev * p) } +/* + * free MP queue + * ------------- + * Note: The MP queue holds all frame fragments of frames, that can't be + * reassembled, because there is at least one missing fragment. + */ static void isdn_ppp_free_mpqueue(isdn_net_dev * p) { @@ -1550,7 +1712,9 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit) return 0; } - +/* + * Mask sequence numbers in MP queue + */ static void isdn_ppp_mask_queue(isdn_net_dev * dev, long mask) { @@ -1561,6 +1725,11 @@ isdn_ppp_mask_queue(isdn_net_dev * dev, long mask) } } +/* + * put a fragment at the right place into the MP queue + * Also checks, whether this fragment completes a frame. In this case + * the fragments are copied together into one SKB + */ static int isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff **skb, int BEbyte, long *sqnop, int min_sqno) { @@ -1761,13 +1930,11 @@ isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min_sqno) slhc_toss(ippp_table[dev->local->ppp_slot]->slcomp); #endif } +#endif /* * a buffered packet timed-out? */ - -#endif - void isdn_ppp_timer_timeout(void) { @@ -1939,7 +2106,7 @@ isdn_ppp_dial_slave(char *name) if (!sdev) return 2; - isdn_net_force_dial_lp((isdn_net_local *) sdev->priv); + isdn_net_dial_req((isdn_net_local *) sdev->priv); return 0; #else return -1; @@ -1980,47 +2147,440 @@ isdn_ppp_hangup_slave(char *name) /* * PPP compression stuff */ -static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master) + + +/* Push an empty CCP Data Frame up to the daemon to wake it up and let it + generate a CCP Reset-Request or tear down CCP altogether */ + +static void isdn_ppp_ccp_kickup(struct ippp_struct *is) +{ + isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->lp->ppp_slot); +} + +/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary, + but absolutely nontrivial. The most abstruse problem we are facing is + that the generation, reception and all the handling of timeouts and + resends including proper request id management should be entirely left + to the (de)compressor, but indeed is not covered by the current API to + the (de)compressor. The API is a prototype version from PPP where only + some (de)compressors have yet been implemented and all of them are + rather simple in their reset handling. Especially, their is only one + outstanding ResetAck at a time with all of them and ResetReq/-Acks do + not have parameters. For this very special case it was sufficient to + just return an error code from the decompressor and have a single + reset() entry to communicate all the necessary information between + the framework and the (de)compressor. Bad enough, LZS is different + (and any other compressor may be different, too). It has multiple + histories (eventually) and needs to Reset each of them independently + and thus uses multiple outstanding Acks and history numbers as an + additional parameter to Reqs/Acks. + All that makes it harder to port the reset state engine into the + kernel because it is not just the same simple one as in (i)pppd but + it must be able to pass additional parameters and have multiple out- + standing Acks. We are trying to achieve the impossible by handling + reset transactions independent by their id. The id MUST change when + the data portion changes, thus any (de)compressor who uses more than + one resettable state must provide and recognize individual ids for + each individual reset transaction. The framework itself does _only_ + differentiate them by id, because it has no other semantics like the + (de)compressor might. + This looks like a major redesign of the interface would be nice, + but I don't have an idea how to do it better. */ + +/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. This is + getting that lengthy because there is no simple "send-this-frame-out" + function above but every wrapper does a bit different. Hope I guess + correct in this hack... */ + +static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto, + unsigned char code, unsigned char id, + unsigned char *data, int len) +{ + struct sk_buff *skb; + unsigned char *p; + int count; + int cnt = 0; + isdn_net_local *lp = is->lp; + + /* Alloc large enough skb */ + skb = dev_alloc_skb(len + 16); + if(!skb) { + printk(KERN_WARNING + "ippp: CCP cannot send reset - out of memory\n"); + return; + } + + /* We may need to stuff an address and control field first */ + if(!(is->pppcfg & SC_COMP_AC)) { + p = skb_put(skb, 2); + *p++ = 0xff; + *p++ = 0x03; + } + + /* Stuff proto, code, id and length */ + p = skb_put(skb, 6); + *p++ = (proto >> 8); + *p++ = (proto & 0xff); + *p++ = code; + *p++ = id; + cnt = 4 + len; + *p++ = (cnt >> 8); + *p++ = (cnt & 0xff); + + /* Now stuff remaining bytes */ + if(len) { + p = skb_put(skb, len); + memcpy(p, data, len); + } + + /* skb is now ready for xmit */ + printk(KERN_DEBUG "Sending CCP Frame:\n"); + isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot); + + /* Just ripped from isdn_ppp_write. Dunno whether it makes sense, + especially dunno what the sav_skb stuff is good for. */ + + count = skb->len; + if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, + 1, skb)) != count) { + if (lp->sav_skb) { + dev_kfree_skb(lp->sav_skb); + printk(KERN_INFO + "isdn_ppp_write: freeing sav_skb (%d,%d)!\n", + cnt, count); + } else + printk(KERN_INFO + "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n", + cnt, count); + lp->sav_skb = skb; + } +} + +/* Allocate the reset state vector */ +static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is) +{ + struct ippp_ccp_reset *r; + printk(KERN_DEBUG "ippp_ccp: allocating reset data structure\n"); + r = kmalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL); + if(!r) + return NULL; + memset(r, 0, sizeof(struct ippp_ccp_reset)); + is->reset = r; + return r; +} + +/* Free a given state and clear everything up for later reallocation */ +static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is, + unsigned char id) +{ + struct ippp_ccp_reset_state *rs; + + if(is->reset->rs[id]) { + printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id); + rs = is->reset->rs[id]; + /* Make sure the kernel will not call back later */ + if(rs->ta) + del_timer(&rs->timer); + is->reset->rs[id] = NULL; + kfree(rs); + } else { + printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id); + } +} + +/* The timer callback function which is called when a ResetReq has timed out, + aka has never been answered by a ResetAck */ +static void isdn_ppp_ccp_timer_callback(unsigned long closure) { -#if 1 - printk(KERN_ERR "compression not included!\n"); - dev_kfree_skb(skb); - return NULL; + struct ippp_ccp_reset_state *rs = + (struct ippp_ccp_reset_state *)closure; + + if(!rs) { + printk(KERN_ERR "ippp_ccp: timer cb with zero closure.\n"); + return; + } + if(rs->ta && rs->state == CCPResetSentReq) { + /* We are correct here */ + printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n", + rs->id); + if(!rs->expra) { + /* Hmm, there is no Ack really expected. We can clean + up the state now, it will be reallocated if the + decompressor insists on another reset */ + rs->ta = 0; + isdn_ppp_ccp_reset_free_state(rs->is, rs->id); + return; + } + /* Push it again */ + isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id, + rs->data, rs->dlen); + /* Restart timer */ + rs->timer.expires = jiffies + HZ*5; + add_timer(&rs->timer); + } else { + printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n", + rs->state); + } +} + +/* Allocate a new reset transaction state */ +static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is, + unsigned char id) +{ + struct ippp_ccp_reset_state *rs; + if(is->reset->rs[id]) { + printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n", + id); + return NULL; + } else { + rs = kmalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL); + if(!rs) + return NULL; + memset(rs, 0, sizeof(struct ippp_ccp_reset_state)); + rs->state = CCPResetIdle; + rs->is = is; + rs->id = id; + rs->timer.data = (unsigned long)rs; + rs->timer.function = isdn_ppp_ccp_timer_callback; + is->reset->rs[id] = rs; + } + return rs; +} + + +/* A decompressor wants a reset with a set of parameters - do what is + necessary to fulfill it */ +static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is, + struct isdn_ppp_resetparams *rp) +{ + struct ippp_ccp_reset_state *rs; + + if(rp->valid) { + /* The decompressor defines parameters by itself */ + if(rp->rsend) { + /* And he wants us to send a request */ + if(!(rp->idval)) { + printk(KERN_ERR "ippp_ccp: decompressor must" + " specify reset id\n"); + return; + } + if(is->reset->rs[rp->id]) { + /* There is already a transaction in existence + for this id. May be still waiting for a + Ack or may be wrong. */ + rs = is->reset->rs[rp->id]; + if(rs->state == CCPResetSentReq && rs->ta) { + printk(KERN_DEBUG "ippp_ccp: reset" + " trans still in progress" + " for id %d\n", rp->id); + } else { + printk(KERN_WARNING "ippp_ccp: reset" + " trans in wrong state %d for" + " id %d\n", rs->state, rp->id); + } + } else { + /* Ok, this is a new transaction */ + printk(KERN_DEBUG "ippp_ccp: new trans for id" + " %d to be started\n", rp->id); + rs = isdn_ppp_ccp_reset_alloc_state(is, rp->id); + if(!rs) { + printk(KERN_ERR "ippp_ccp: out of mem" + " allocing ccp trans\n"); + return; + } + rs->state = CCPResetSentReq; + rs->expra = rp->expra; + if(rp->dtval) { + rs->dlen = rp->dlen; + memcpy(rs->data, rp->data, rp->dlen); + } + /* HACK TODO - add link comp here */ + isdn_ppp_ccp_xmit_reset(is, PPP_CCP, + CCP_RESETREQ, rs->id, + rs->data, rs->dlen); + /* Start the timer */ + rs->timer.expires = jiffies + 5*HZ; + add_timer(&rs->timer); + rs->ta = 1; + } + } else { + printk(KERN_DEBUG "ippp_ccp: no reset sent\n"); + } + } else { + /* The reset params are invalid. The decompressor does not + care about them, so we just send the minimal requests + and increase ids only when an Ack is received for a + given id */ + if(is->reset->rs[is->reset->lastid]) { + /* There is already a transaction in existence + for this id. May be still waiting for a + Ack or may be wrong. */ + rs = is->reset->rs[is->reset->lastid]; + if(rs->state == CCPResetSentReq && rs->ta) { + printk(KERN_DEBUG "ippp_ccp: reset" + " trans still in progress" + " for id %d\n", rp->id); + } else { + printk(KERN_WARNING "ippp_ccp: reset" + " trans in wrong state %d for" + " id %d\n", rs->state, rp->id); + } + } else { + printk(KERN_DEBUG "ippp_ccp: new trans for id" + " %d to be started\n", is->reset->lastid); + rs = isdn_ppp_ccp_reset_alloc_state(is, + is->reset->lastid); + if(!rs) { + printk(KERN_ERR "ippp_ccp: out of mem" + " allocing ccp trans\n"); + return; + } + rs->state = CCPResetSentReq; + /* We always expect an Ack if the decompressor doesnt + know better */ + rs->expra = 1; + rs->dlen = 0; + /* HACK TODO - add link comp here */ + isdn_ppp_ccp_xmit_reset(is, PPP_CCP, CCP_RESETREQ, + rs->id, NULL, 0); + /* Start the timer */ + rs->timer.expires = jiffies + 5*HZ; + add_timer(&rs->timer); + rs->ta = 1; + } + } +} + +/* An Ack was received for this id. This means we stop the timer and clean + up the state prior to calling the decompressors reset routine. */ +static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is, + unsigned char id) +{ + struct ippp_ccp_reset_state *rs = is->reset->rs[id]; + + if(rs) { + if(rs->ta && rs->state == CCPResetSentReq) { + /* Great, we are correct */ + if(!rs->expra) + printk(KERN_DEBUG "ippp_ccp: ResetAck received" + " for id %d but not expected\n", id); + } else { + printk(KERN_INFO "ippp_ccp: ResetAck received out of" + "sync for id %d\n", id); + } + if(rs->ta) { + rs->ta = 0; + del_timer(&rs->timer); + } + isdn_ppp_ccp_reset_free_state(is, id); + } else { + printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id" + " %d\n", id); + } + /* Make sure the simple reset stuff uses a new id next time */ + is->reset->lastid++; +} + +static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master, + int proto) +{ +#ifndef CONFIG_ISDN_CCP + if(proto == PPP_COMP || proto == PPP_LINK_COMP) { + printk(KERN_ERR "isdn_ppp: Ouch! Compression not included!\n"); + dev_kfree_skb(skb); + return NULL; + } + return skb; #else + void *stat = NULL; + struct isdn_ppp_compressor *ipc = NULL; + struct sk_buff *skb_out; + int len; + struct ippp_struct *ri; + struct isdn_ppp_resetparams rsparm; + unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; + if(!master) { /* - * single link compression + * single link decompression */ - if(!is->link_compressor) { - printk(KERN_ERR "ippp: no (link) compressor defined!\n"); + if(!is->link_decompressor) { + printk(KERN_ERR "ippp: no link decompressor defined!\n"); dev_kfree_skb(skb); return NULL; } if(!is->link_decomp_stat) { - printk(KERN_DEBUG "ippp: initialize link compressor\n"); + printk(KERN_DEBUG "ippp: no link decompressor data allocated\n"); + dev_kfree_skb(skb); + return NULL; } -/* - -> decompress link -*/ - } + stat = is->link_decomp_stat; + ipc = is->link_decompressor; + ri = is; + } else { /* * 'normal' or bundle-compression */ - if(!master->compressor) { - printk(KERN_ERR "ippp: no (link) compressor defined!\n"); + if(!master->decompressor) { + printk(KERN_ERR "ippp: no decompressor defined!\n"); dev_kfree_skb(skb); return NULL; } if(!master->decomp_stat) { -#if 0 - master->decomp_stat = (master->compressor->decomp_alloc)( .. ); -#endif - printk(KERN_DEBUG "ippp: initialize compressor\n"); + printk(KERN_DEBUG "ippp: no decompressor data allocated\n"); + dev_kfree_skb(skb); + return NULL; } + stat = master->decomp_stat; + ipc = master->decompressor; + ri = master; + } + + /* + printk(KERN_DEBUG "ippp: Decompress valid!\n"); + */ + + if((master && proto == PPP_COMP) || (!master && proto == PPP_LINK_COMP) ) { + /* Set up reset params for the decompressor */ + memset(&rsparm, 0, sizeof(rsparm)); + rsparm.data = rsdata; + rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; + +/* !!!HACK,HACK,HACK!!! 2048 is only assumed */ + skb_out = dev_alloc_skb(2048); + len = ipc->decompress(stat,skb,skb_out, &rsparm); + dev_kfree_skb(skb); + if(len <= 0) { + /* Ok, some error */ + switch(len) { + case DECOMP_ERROR: + ri->pppcfg |= SC_DC_ERROR; + printk(KERN_INFO "ippp: decomp wants reset %s params\n", + rsparm.valid ? "with" : "without"); + + isdn_ppp_ccp_reset_trans(ri, &rsparm); + + break; + case DECOMP_FATALERROR: + ri->pppcfg |= SC_DC_FERROR; + /* Kick ipppd to recognize the error */ + isdn_ppp_ccp_kickup(ri); + break; + } + /* Did I see a leak here ? */ + dev_kfree_skb(skb_out); + return NULL; + } + return skb_out; + } + else { + /* + printk(KERN_DEBUG "isdn_ppp: [%d] Calling incomp with this frame!\n",is->unit); + */ + ipc->incomp(stat,skb,proto); + return skb; } - - return skb; #endif } @@ -2034,19 +2594,29 @@ static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struc static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto, struct ippp_struct *is,struct ippp_struct *master,int type) { -#if 1 - return skb_in; -#else int ret; int new_proto; struct isdn_ppp_compressor *compressor; void *stat; struct sk_buff *skb_out; +#ifdef CONFIG_ISDN_CCP + /* we do not compress control protocols */ + if(*proto < 0 || *proto > 0x3fff) { +#else + { +#endif + return skb_in; + } + if(type) { /* type=1 => Link compression */ +#if 0 compressor = is->link_compressor; stat = is->link_comp_stat; new_proto = PPP_LINK_COMP; +#else + return skb_in; +#endif } else { if(!master) { @@ -2061,15 +2631,16 @@ static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto, } if(!compressor) { - printk(KERN_ERR "No compressor set!\n"); + printk(KERN_ERR "isdn_ppp: No compressor set!\n"); return skb_in; } if(!stat) { - /* init here ? */ + printk(KERN_ERR "isdn_ppp: Compressor not initialized?\n"); return skb_in; } - skb_out = dev_alloc_skb(skb_in->len); + /* Allow for at least 150 % expansion (for now) */ + skb_out = dev_alloc_skb(skb_in->len + skb_in->len/2 + 32); if(!skb_out) return skb_in; @@ -2082,24 +2653,225 @@ static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto, dev_kfree_skb(skb_in); *proto = new_proto; return skb_out; -#endif - } /* * we received a CCP frame .. - * not a clean solution, but we SHOULD handle a few cased in the kernel + * not a clean solution, but we MUST handle a few cases in the kernel */ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *skb) + struct sk_buff *skb,int proto) { -#if 0 - printk(KERN_DEBUG "isdn_ppp_receive_cpp: %02x %02x %02x %02x %02x %02x %02x %02x\n", - skb->data[0],skb->data[1],skb->data[2],skb->data[3], - skb->data[4],skb->data[5],skb->data[6],skb->data[7] ); -#endif + struct ippp_struct *is = ippp_table[lp->ppp_slot]; + struct ippp_struct *mis; + int len; + struct isdn_ppp_resetparams rsparm; + unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; + + printk(KERN_DEBUG "Received CCP frame from peer\n"); + isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,lp->ppp_slot); + + if(lp->master) + mis = ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot]; + else + mis = is; + + switch(skb->data[0]) { + case CCP_CONFREQ: + case CCP_TERMREQ: + case CCP_TERMACK: + if(is->debug & 0x10) + printk(KERN_DEBUG "Disable (de)compression here!\n"); + if(proto == PPP_CCP) + mis->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); + else + is->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON); + break; + case CCP_CONFACK: + /* if we RECEIVE an ackowledge we enable the decompressor */ + if(is->debug & 0x10) + printk(KERN_DEBUG "Enable decompression here!\n"); + if(proto == PPP_CCP) + mis->compflags |= SC_DECOMP_ON; + else + is->compflags |= SC_LINK_DECOMP_ON; + break; + + case CCP_RESETACK: + printk(KERN_DEBUG "Received ResetAck from peer\n"); + len = (skb->data[2] << 8) | skb->data[3]; + len -= 4; + + if(proto == PPP_CCP) { + /* If a reset Ack was outstanding for this id, then + clean up the state engine */ + isdn_ppp_ccp_reset_ack_rcvd(mis, skb->data[1]); + if(mis->decompressor && mis->decomp_stat) + mis->decompressor-> + reset(mis->decomp_stat, + skb->data[0], + skb->data[1], + len ? &skb->data[4] : NULL, + len, NULL); + /* TODO: This is not easy to decide here */ + mis->compflags &= ~SC_DECOMP_DISCARD; + mis->pppcfg &= ~SC_DC_ERROR; + } + else { + isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]); + if(is->link_decompressor && is->link_decomp_stat) + is->link_decompressor-> + reset(is->link_decomp_stat, + skb->data[0], + skb->data[1], + len ? &skb->data[4] : NULL, + len, NULL); + /* TODO: neither here */ + is->compflags &= ~SC_LINK_DECOMP_DISCARD; + is->pppcfg &= ~SC_DC_ERROR; + } + break; + + case CCP_RESETREQ: + printk(KERN_DEBUG "Received ResetReq from peer\n"); + /* Receiving a ResetReq means we must reset our compressor */ + /* Set up reset params for the reset entry */ + memset(&rsparm, 0, sizeof(rsparm)); + rsparm.data = rsdata; + rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; + /* Isolate data length */ + len = (skb->data[2] << 8) | skb->data[3]; + len -= 4; + if(proto == PPP_CCP) { + if(mis->compressor && mis->comp_stat) + mis->compressor-> + reset(mis->comp_stat, + skb->data[0], + skb->data[1], + len ? &skb->data[4] : NULL, + len, &rsparm); + } + else { + if(is->link_compressor && is->link_comp_stat) + is->link_compressor-> + reset(is->link_comp_stat, + skb->data[0], + skb->data[1], + len ? &skb->data[4] : NULL, + len, &rsparm); + } + /* Ack the Req as specified by rsparm */ + if(rsparm.valid) { + /* Compressor reset handler decided how to answer */ + if(rsparm.rsend) { + /* We should send a Frame */ + isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK, + rsparm.idval ? rsparm.id + : skb->data[1], + rsparm.dtval ? + rsparm.data : NULL, + rsparm.dtval ? + rsparm.dlen : 0); + } else { + printk(KERN_DEBUG "ResetAck suppressed\n"); + } + } else { + /* We answer with a straight reflected Ack */ + isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK, + skb->data[1], + len ? &skb->data[4] : NULL, + len); + } + break; + } } + +/* + * Daemon sends a CCP frame ... + */ + +/* TODO: Clean this up with new Reset semantics */ + +static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb) +{ + struct ippp_struct *mis,*is = ippp_table[lp->ppp_slot]; + int proto; + unsigned char *data; + + if(!skb || skb->len < 3) + return; + + /* Daemon may send with or without address and control field comp */ + data = skb->data; + if(!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) { + data += 2; + if(skb->len < 5) + return; + } + + proto = ((int)data[0]<<8)+data[1]; + if(proto != PPP_CCP && proto != PPP_LINK_CCP) + return; + + printk(KERN_DEBUG "Received CCP frame from daemon:\n"); + isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot); + + if(lp->master) + mis = ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot]; + else + mis = is; + + if(mis != is) + printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n"); + + switch(data[2]) { + case CCP_CONFREQ: + case CCP_TERMREQ: + case CCP_TERMACK: + if(is->debug & 0x10) + printk(KERN_DEBUG "Disable (de)compression here!\n"); + if(proto == PPP_CCP) + is->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); + else + is->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON); + break; + case CCP_CONFACK: + /* if we SEND an ackowledge we can/must enable the compressor */ + if(is->debug & 0x10) + printk(KERN_DEBUG "Enable compression here!\n"); + if(proto == PPP_CCP) + is->compflags |= SC_COMP_ON; + else + is->compflags |= SC_LINK_COMP_ON; + break; + case CCP_RESETACK: + /* If we send a ACK we should reset our compressor */ + if(is->debug & 0x10) + printk(KERN_DEBUG "Reset decompression state here!\n"); + printk(KERN_DEBUG "ResetAck from daemon passed by\n"); + if(proto == PPP_CCP) { + /* link to master? */ + if(is->compressor && is->comp_stat) + is->compressor->reset(is->comp_stat, 0, 0, + NULL, 0, NULL); + is->compflags &= ~SC_COMP_DISCARD; + } + else { + if(is->link_compressor && is->link_comp_stat) + is->link_compressor->reset(is->link_comp_stat, + 0, 0, NULL, 0, NULL); + is->compflags &= ~SC_LINK_COMP_DISCARD; + } + break; + case CCP_RESETREQ: + /* Just let it pass by */ + printk(KERN_DEBUG "ResetReq from daemon passed by\n"); + break; + } +} + + int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc) { ipc->next = ipc_head; @@ -2123,15 +2895,63 @@ int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc) return 0; } -static int isdn_ppp_set_compressor(struct ippp_struct *is,int num) +static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *data) { struct isdn_ppp_compressor *ipc = ipc_head; + int ret; + void *stat; + int num = data->num; + + if(is->debug & 0x10) + printk(KERN_DEBUG "[%d] Set %s type %d\n",is->unit, + (data->flags&IPPP_COMP_FLAG_XMIT)?"compressor":"decompressor",num); while(ipc) { if(ipc->num == num) { - return 0; - is->compressor = ipc; - is->link_compressor = ipc; + stat = ipc->alloc(data); + if(stat) { + ret = ipc->init(stat,data,is->unit,0); + if(!ret) { + printk(KERN_ERR "Can't init (de)compression!\n"); + ipc->free(stat); + stat = NULL; + break; + } + } + else { + printk(KERN_ERR "Can't alloc (de)compression!\n"); + break; + } + + if(data->flags & IPPP_COMP_FLAG_XMIT) { + if(data->flags & IPPP_COMP_FLAG_LINK) { + if(is->link_comp_stat) + is->link_compressor->free(is->link_comp_stat); + is->link_comp_stat = stat; + is->link_compressor = ipc; + } + else { + if(is->comp_stat) + is->compressor->free(is->comp_stat); + is->comp_stat = stat; + is->compressor = ipc; + } + } + else { + if(data->flags & IPPP_COMP_FLAG_LINK) { + if(is->link_decomp_stat) + is->link_decompressor->free(is->link_decomp_stat); + is->link_decomp_stat = stat; + is->link_decompressor = ipc; + } + else { + if(is->decomp_stat) + is->decompressor->free(is->decomp_stat); + is->decomp_stat = stat; + is->decompressor = ipc; + } + } + return 0; } ipc = ipc->next; } @@ -2139,16 +2959,3 @@ static int isdn_ppp_set_compressor(struct ippp_struct *is,int num) } -#if 0 -static struct symbol_table isdn_ppp_syms = -{ -#include <linux/symtab_begin.h> - X(isdn_ppp_register_compressor), - X(isdn_ppp_unregister_compressor), -#include <linux/symtab_end.h> -}; -#endif - - - - diff --git a/drivers/isdn/isdn_ppp.h b/drivers/isdn/isdn_ppp.h index 0e05af08b..2c60240a5 100644 --- a/drivers/isdn/isdn_ppp.h +++ b/drivers/isdn/isdn_ppp.h @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.h,v 1.12 1998/01/31 22:07:48 keil Exp $ +/* $Id: isdn_ppp.h,v 1.13 1998/03/22 18:50:50 hipp Exp $ * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -19,6 +19,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ppp.h,v $ + * Revision 1.13 1998/03/22 18:50:50 hipp + * Added BSD Compression for syncPPP .. UNTESTED at the moment + * * Revision 1.12 1998/01/31 22:07:48 keil * changes for newer kernels * @@ -84,6 +87,9 @@ extern void isdn_ppp_release(int, struct file *); extern int isdn_ppp_dial_slave(char *); extern void isdn_ppp_wakeup_daemon(isdn_net_local *); +extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc); +extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc); + #define IPPP_OPEN 0x01 #define IPPP_CONNECT 0x02 #define IPPP_CLOSEWAIT 0x04 diff --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c index a37178676..bfa895424 100644 --- a/drivers/isdn/isdn_tty.c +++ b/drivers/isdn/isdn_tty.c @@ -1,8 +1,8 @@ -/* $Id: isdn_tty.c,v 1.47 1998/02/22 19:44:14 fritz Exp $ +/* $Id: isdn_tty.c,v 1.63 1999/04/12 12:33:39 fritz Exp $ * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,73 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.c,v $ + * Revision 1.63 1999/04/12 12:33:39 fritz + * Changes from 2.0 tree. + * + * Revision 1.62 1999/03/02 12:04:48 armin + * -added ISDN_STAT_ADDCH to increase supported channels after + * register_isdn(). + * -ttyI now goes on-hook on ATZ when B-Ch is connected. + * -added timer-function for register S7 (Wait for Carrier). + * -analog modem (ISDN_PROTO_L2_MODEM) implementations. + * -on L2_MODEM a string will be appended to the CONNECT-Message, + * which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN. + * -variable "dialing" used for ATA also, for interrupting call + * establishment and register S7. + * + * Revision 1.61 1999/01/27 22:53:11 he + * minor updates (spellings, jiffies wrap around in isdn_tty) + * + * Revision 1.60 1998/11/15 23:57:32 keil + * changes for 2.1.127 + * + * Revision 1.59 1998/08/20 13:50:15 keil + * More support for hybrid modem (not working yet) + * + * Revision 1.58 1998/07/26 18:48:45 armin + * Added silence detection in voice receive mode. + * + * Revision 1.57 1998/06/26 15:12:36 fritz + * Added handling of STAT_ICALL with incomplete CPN. + * Added AT&L for ttyI emulator. + * Added more locking stuff in tty_write. + * + * Revision 1.56 1998/06/18 23:31:51 fritz + * Replaced cli()/restore_flags() in isdn_tty_write() by locking. + * Removed direct-senddown feature in isdn_tty_write because it will + * never succeed with locking and is useless anyway. + * + * Revision 1.55 1998/06/17 19:50:55 he + * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) + * brute force fix to avoid Ugh's in isdn_tty_write() + * cleaned up some dead code + * + * Revision 1.54 1998/06/07 00:20:13 fritz + * abc cleanup. + * + * Revision 1.53 1998/06/02 12:10:16 detabc + * wegen einer einstweiliger verfuegung gegen DW ist zur zeit + * die abc-extension bis zur klaerung der rechtslage nicht verfuegbar + * + * Revision 1.52 1998/03/19 13:18:21 keil + * Start of a CAPI like interface for supplementary Service + * first service: SUSPEND + * + * Revision 1.51 1998/03/08 14:26:11 detabc + * change kfree_skb to dev_kfree_skb + * remove SET_SKB_FREE + * + * Revision 1.50 1998/03/08 13:14:28 detabc + * abc-extension support for kernels > 2.1.x + * first try (sorry experimental) + * + * Revision 1.49 1998/03/08 00:01:59 fritz + * Bugfix: Lowlevel module usage and channel usage were not + * reset on NO DCHANNEL. + * + * Revision 1.48 1998/03/07 12:28:15 tsbogend + * fixed kernel unaligned traps on Linux/Alpha + * * Revision 1.47 1998/02/22 19:44:14 fritz * Bugfixes and improvements regarding V.110, V.110 now running. * @@ -254,7 +321,7 @@ static int bit2si[8] = static int si2bit[8] = {4, 1, 4, 4, 4, 4, 4, 4}; -char *isdn_tty_revision = "$Revision: 1.47 $"; +char *isdn_tty_revision = "$Revision: 1.63 $"; #define DLE 0x10 #define ETX 0x03 @@ -270,6 +337,8 @@ char *isdn_tty_revision = "$Revision: 1.47 $"; #define REG_LF 4 #define REG_BS 5 +#define REG_WAITC 7 + #define REG_RESP 12 #define BIT_RESP 1 #define REG_RESPNUM 12 @@ -287,8 +356,6 @@ char *isdn_tty_revision = "$Revision: 1.47 $"; #define REG_CPPP 12 #define BIT_CPPP 128 -#define REG_DELXMT 13 -#define BIT_DELXMT 1 #define REG_T70 13 #define BIT_T70 2 #define BIT_T70_EXT 32 @@ -300,6 +367,8 @@ char *isdn_tty_revision = "$Revision: 1.47 $"; #define BIT_CIDONCE 16 #define REG_RUNG 13 #define BIT_RUNG 64 +#define REG_RESRXT 13 +#define BIT_RESRXT 128 #define REG_L2PROT 14 #define REG_L3PROT 15 @@ -389,6 +458,8 @@ isdn_tty_readmodem(void) r = 0; #ifdef CONFIG_ISDN_AUDIO isdn_audio_eval_dtmf(info); + if ((info->vonline & 1) && (info->emu.vpar[1])) + isdn_audio_eval_silence(info); #endif if ((tty = info->tty)) { if (info->mcr & UART_MCR_RTS) { @@ -445,6 +516,8 @@ isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb) if (info->vonline) isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt); + if ((info->vonline & 1) && (info->emu.vpar[1])) + isdn_audio_calc_silence(info, skb->data, skb->len, ifmt); #endif if ((info->online < 2) #ifdef CONFIG_ISDN_AUDIO @@ -566,8 +639,8 @@ isdn_tty_tint(modem_info * info) info->isdn_channel, 1, skb)) == len) { struct tty_struct *tty = info->tty; info->send_outstanding++; - info->msr |= UART_MSR_CTS; - info->lsr |= UART_LSR_TEMT; + info->msr &= ~UART_MSR_CTS; + info->lsr &= ~UART_LSR_TEMT; if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup) (tty); @@ -579,8 +652,6 @@ isdn_tty_tint(modem_info * info) dev_kfree_skb(skb); return; } - if (slen) - skb_pull(skb, slen); skb_queue_head(&info->xmit_queue, skb); } @@ -702,7 +773,6 @@ isdn_tty_senddown(modem_info * info) int audio_len; #endif struct sk_buff *skb; - unsigned long flags; #ifdef CONFIG_ISDN_AUDIO if (info->vonline & 4) { @@ -717,18 +787,20 @@ isdn_tty_senddown(modem_info * info) } } #endif - save_flags(flags); - cli(); - if (!(buflen = info->xmit_count)) { - restore_flags(flags); + if (!(buflen = info->xmit_count)) return; - } - if ((info->emu.mdmreg[REG_CTS] & BIT_CTS) != 0) + if ((info->emu.mdmreg[REG_CTS] & BIT_CTS) != 0) info->msr &= ~UART_MSR_CTS; - info->lsr &= ~UART_LSR_TEMT; + info->lsr &= ~UART_LSR_TEMT; + /* info->xmit_count is modified here and in isdn_tty_write(). + * So we return here if isdn_tty_write() is in the + * critical section. + */ + atomic_inc(&info->xmit_lock); + if (!(atomic_dec_and_test(&info->xmit_lock))) + return; if (info->isdn_driver < 0) { info->xmit_count = 0; - restore_flags(flags); return; } skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4; @@ -742,7 +814,6 @@ isdn_tty_senddown(modem_info * info) skb = dev_alloc_skb(skb_res + buflen); #endif if (!skb) { - restore_flags(flags); printk(KERN_WARNING "isdn_tty: Out of memory in ttyI%d senddown\n", info->line); @@ -751,7 +822,6 @@ isdn_tty_senddown(modem_info * info) skb_reserve(skb, skb_res); memcpy(skb_put(skb, buflen), info->xmit_buf, buflen); info->xmit_count = 0; - restore_flags(flags); #ifdef CONFIG_ISDN_AUDIO if (info->vonline & 2) { /* For now, ifmt is fixed to 1 (alaw), since this @@ -859,7 +929,7 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m) break; } #ifdef CONFIG_ISDN_AUDIO - if (si == 1) { + if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) { l2 = ISDN_PROTO_L2_TRANS; usg = ISDN_USAGE_VOICE; } @@ -907,9 +977,11 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m) cmd.parm.setup.si2 = m->mdmreg[REG_SI2]; cmd.command = ISDN_CMD_DIAL; info->dialing = 1; + info->emu.carrierwait = 0; strcpy(dev->num[i], n); isdn_info_update(); isdn_command(&cmd); + isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1); } } @@ -942,6 +1014,10 @@ isdn_tty_modem_hup(modem_info * info, int local) kfree(info->dtmf_state); info->dtmf_state = NULL; } + if (info->silence_state) { + kfree(info->silence_state); + info->silence_state = NULL; + } if (info->adpcms) { kfree(info->adpcms); info->adpcms = NULL; @@ -965,8 +1041,9 @@ isdn_tty_modem_hup(modem_info * info, int local) } isdn_all_eaz(info->isdn_driver, info->isdn_channel); info->emu.mdmreg[REG_RINGCNT] = 0; - usage = (info->emu.mdmreg[REG_SI1I] == 1) ? - ISDN_USAGE_VOICE : ISDN_USAGE_MODEM; + usage = ((info->emu.mdmreg[REG_SI1I] != 1) || + (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM)) ? + ISDN_USAGE_MODEM : ISDN_USAGE_VOICE; isdn_free_channel(info->isdn_driver, info->isdn_channel, usage); } @@ -978,6 +1055,226 @@ isdn_tty_modem_hup(modem_info * info, int local) } } +/* + * Begin of a CAPI like interface, currently used only for + * supplementary service (CAPI 2.0 part III) + */ +#include "avmb1/capicmd.h" /* this should be moved in a common place */ + +int +isdn_tty_capi_facility(capi_msg *cm) { + return(-1); /* dummy */ +} + +/* isdn_tty_suspend() tries to suspend the current tty connection + */ +static void +isdn_tty_suspend(char *id, modem_info * info, atemu * m) +{ + isdn_ctrl cmd; + + int l; + + if (!info) + return; + +#ifdef ISDN_DEBUG_MODEM_SERVICES + printk(KERN_DEBUG "Msusp ttyI%d\n", info->line); +#endif + l = strlen(id); + if ((info->isdn_driver >= 0) && l) { + cmd.parm.cmsg.Length = l+17; + cmd.parm.cmsg.Command = CAPI_FACILITY; + cmd.parm.cmsg.Subcommand = CAPI_REQ; + cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1; + cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */ + cmd.parm.cmsg.para[1] = 0; + cmd.parm.cmsg.para[2] = l + 3; + cmd.parm.cmsg.para[3] = 4; /* 16 bit 0x0004 Suspend */ + cmd.parm.cmsg.para[4] = 0; + cmd.parm.cmsg.para[5] = l; + strncpy(&cmd.parm.cmsg.para[6], id, l); + cmd.command = CAPI_PUT_MESSAGE; + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + isdn_command(&cmd); + } +} + +/* isdn_tty_resume() tries to resume a suspended call + * setup of the lower levels before that. unfortunatly here is no + * checking for compatibility of used protocols implemented by Q931 + * It does the same things like isdn_tty_dial, the last command + * is different, may be we can merge it. + */ + +static void +isdn_tty_resume(char *id, modem_info * info, atemu * m) +{ + int usg = ISDN_USAGE_MODEM; + int si = 7; + int l2 = m->mdmreg[REG_L2PROT]; + isdn_ctrl cmd; + ulong flags; + int i; + int j; + int l; + + l = strlen(id); + if (!l) { + isdn_tty_modem_result(4, info); + return; + } + for (j = 7; j >= 0; j--) + if (m->mdmreg[REG_SI1] & (1 << j)) { + si = bit2si[j]; + break; + } +#ifdef CONFIG_ISDN_AUDIO + if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) { + l2 = ISDN_PROTO_L2_TRANS; + usg = ISDN_USAGE_VOICE; + } +#endif + m->mdmreg[REG_SI1I] = si2bit[si]; + save_flags(flags); + cli(); + i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1); + if (i < 0) { + restore_flags(flags); + isdn_tty_modem_result(6, info); + } else { + info->isdn_driver = dev->drvmap[i]; + info->isdn_channel = dev->chanmap[i]; + info->drv_index = i; + dev->m_idx[i] = info->line; + dev->usage[i] |= ISDN_USAGE_OUTGOING; + info->last_dir = 1; +// strcpy(info->last_num, n); + isdn_info_update(); + restore_flags(flags); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.command = ISDN_CMD_CLREAZ; + isdn_command(&cmd); + strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver)); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETEAZ; + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL2; + info->last_l2 = l2; + cmd.arg = info->isdn_channel + (l2 << 8); + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL3; + cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8); + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.parm.cmsg.Length = l+17; + cmd.parm.cmsg.Command = CAPI_FACILITY; + cmd.parm.cmsg.Subcommand = CAPI_REQ; + cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1; + cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */ + cmd.parm.cmsg.para[1] = 0; + cmd.parm.cmsg.para[2] = l+3; + cmd.parm.cmsg.para[3] = 5; /* 16 bit 0x0005 Resume */ + cmd.parm.cmsg.para[4] = 0; + cmd.parm.cmsg.para[5] = l; + strncpy(&cmd.parm.cmsg.para[6], id, l); + cmd.command =CAPI_PUT_MESSAGE; +/* info->dialing = 1; + strcpy(dev->num[i], n); + isdn_info_update(); +*/ + isdn_command(&cmd); + } +} + +/* isdn_tty_send_msg() sends a message to a HL driver + * This is used for hybrid modem cards to send AT commands to it + */ + +static void +isdn_tty_send_msg(modem_info * info, atemu * m, char *msg) +{ + int usg = ISDN_USAGE_MODEM; + int si = 7; + int l2 = m->mdmreg[REG_L2PROT]; + isdn_ctrl cmd; + ulong flags; + int i; + int j; + int l; + + l = strlen(msg); + if (!l) { + isdn_tty_modem_result(4, info); + return; + } + for (j = 7; j >= 0; j--) + if (m->mdmreg[REG_SI1] & (1 << j)) { + si = bit2si[j]; + break; + } +#ifdef CONFIG_ISDN_AUDIO + if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) { + l2 = ISDN_PROTO_L2_TRANS; + usg = ISDN_USAGE_VOICE; + } +#endif + m->mdmreg[REG_SI1I] = si2bit[si]; + save_flags(flags); + cli(); + i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1); + if (i < 0) { + restore_flags(flags); + isdn_tty_modem_result(6, info); + } else { + info->isdn_driver = dev->drvmap[i]; + info->isdn_channel = dev->chanmap[i]; + info->drv_index = i; + dev->m_idx[i] = info->line; + dev->usage[i] |= ISDN_USAGE_OUTGOING; + info->last_dir = 1; + isdn_info_update(); + restore_flags(flags); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.command = ISDN_CMD_CLREAZ; + isdn_command(&cmd); + strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver)); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETEAZ; + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL2; + info->last_l2 = l2; + cmd.arg = info->isdn_channel + (l2 << 8); + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL3; + cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8); + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.parm.cmsg.Length = l+14; + cmd.parm.cmsg.Command = CAPI_MANUFACTURER; + cmd.parm.cmsg.Subcommand = CAPI_REQ; + cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1; + cmd.parm.cmsg.para[0] = l+1; + strncpy(&cmd.parm.cmsg.para[1], msg, l); + cmd.parm.cmsg.para[l+1] = 0xd; + cmd.command =CAPI_PUT_MESSAGE; +/* info->dialing = 1; + strcpy(dev->num[i], n); + isdn_info_update(); +*/ + isdn_command(&cmd); + } +} + static inline int isdn_tty_paranoia_check(modem_info * info, kdev_t device, const char *routine) { @@ -1138,15 +1435,16 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co { int c; int total = 0; - ulong flags; modem_info *info = (modem_info *) tty->driver_data; if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_write")) return 0; if (!tty) return 0; - save_flags(flags); - cli(); + if (from_user) + down(&info->write_sem); + /* See isdn_tty_senddown() */ + atomic_inc(&info->xmit_lock); while (1) { c = MIN(count, info->xmit_size - info->xmit_count); if (info->isdn_driver >= 0) @@ -1205,10 +1503,6 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co } else #endif info->xmit_count += c; - if (m->mdmreg[REG_DELXMT] & BIT_DELXMT) { - isdn_tty_senddown(info); - isdn_tty_tint(info); - } } else { info->msr |= UART_MSR_CTS; info->lsr |= UART_LSR_TEMT; @@ -1228,7 +1522,9 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co } if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1); - restore_flags(flags); + atomic_dec(&info->xmit_lock); + if (from_user) + up(&info->write_sem); return total; } @@ -1359,7 +1655,7 @@ isdn_tty_get_lsr_info(modem_info * info, uint * value) status = info->lsr; restore_flags(flags); result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); - put_user(result, (ulong *) value); + put_user(result, (uint *) value); return 0; } @@ -1383,7 +1679,7 @@ isdn_tty_get_modem_info(modem_info * info, uint * value) | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); - put_user(result, (ulong *) value); + put_user(result, (uint *) value); return 0; } @@ -1567,8 +1863,12 @@ isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios) static int isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info) { +#if LINUX_VERSION_CODE < 131841 struct wait_queue wait = {current, NULL}; +#else + DECLARE_WAITQUEUE(wait, NULL); +#endif int do_clocal = 0; unsigned long flags; int retval; @@ -1892,6 +2192,7 @@ isdn_tty_reset_profile(atemu * m) m->profile[19] = 0; m->profile[20] = 0; m->pmsn[0] = '\0'; + m->plmsn[0] = '\0'; } #ifdef CONFIG_ISDN_AUDIO @@ -1912,6 +2213,7 @@ isdn_tty_modem_reset_regs(modem_info * info, int force) if ((m->mdmreg[REG_DTRR] & BIT_DTRR) || force) { memcpy(m->mdmreg, m->profile, ISDN_MODEM_ANZREG); memcpy(m->msn, m->pmsn, ISDN_MSNLEN); + memcpy(m->lmsn, m->plmsn, ISDN_LMSNLEN); info->xmit_size = m->mdmreg[REG_PSIZE] * 16; } #ifdef CONFIG_ISDN_AUDIO @@ -1925,6 +2227,7 @@ modem_write_profile(atemu * m) { memcpy(m->profile, m->mdmreg, ISDN_MODEM_ANZREG); memcpy(m->pmsn, m->msn, ISDN_MSNLEN); + memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN); if (dev->profd) send_sig(SIGIO, dev->profd, 1); } @@ -1988,6 +2291,11 @@ isdn_tty_modem_init(void) } for (i = 0; i < ISDN_MAX_CHANNELS; i++) { info = &m->info[i]; +#if LINUX_VERSION_CODE < 131841 + info->write_sem = MUTEX; +#else + init_MUTEX(&info->write_sem); +#endif sprintf(info->last_cause, "0000"); sprintf(info->last_num, "none"); info->last_dir = 0; @@ -2004,8 +2312,13 @@ isdn_tty_modem_init(void) info->blocked_open = 0; info->callout_termios = m->cua_modem.init_termios; info->normal_termios = m->tty_modem.init_termios; +#if LINUX_VERSION_CODE < 131841 info->open_wait = 0; info->close_wait = 0; +#else + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); +#endif info->isdn_driver = -1; info->isdn_channel = -1; info->drv_index = -1; @@ -2024,25 +2337,67 @@ isdn_tty_modem_init(void) return 0; } +static int +isdn_tty_match_icall(char *cid, atemu *emu, int di) +{ +#ifdef ISDN_DEBUG_MODEM_ICALL + printk(KERN_DEBUG "m_fi: msn=%s lmsn=%s mmsn=%s mreg[SI1]=%d mreg[SI2]=%d\n", + emu->msn, emu->lmsn, isdn_map_eaz2msn(emu->msn, di), + emu->mdmreg[REG_SI1], emu->mdmreg[REG_SI2]); +#endif + if (strlen(emu->lmsn)) { + char *p = emu->lmsn; + char *q; + int tmp; + int ret = 0; + + while (1) { + if ((q = strchr(p, ';'))) + *q = '\0'; + if ((tmp = isdn_wildmat(cid, isdn_map_eaz2msn(p, di))) > ret) + ret = tmp; +#ifdef ISDN_DEBUG_MODEM_ICALL + printk(KERN_DEBUG "m_fi: lmsnX=%s mmsn=%s -> tmp=%d\n", + p, isdn_map_eaz2msn(emu->msn, di), tmp); +#endif + if (q) { + *q = ';'; + p = q; + p++; + } + if (!tmp) + return 0; + if (!q) + break; + } + return ret; + } else + return isdn_wildmat(cid, isdn_map_eaz2msn(emu->msn, di)); +} + /* * An incoming call-request has arrived. * Search the tty-devices for an appropriate device and bind * it to the ISDN-Channel. - * Return Index to dev->mdm or -1 if none found. + * Return: + * + * 0 = No matching device found. + * 1 = A matching device found. + * 3 = No match found, but eventually would match, if + * CID is longer. */ int isdn_tty_find_icall(int di, int ch, setup_parm setup) { char *eaz; int i; + int wret; int idx; int si1; int si2; char nr[32]; ulong flags; - save_flags(flags); - cli(); if (!setup.phone[0]) { nr[0] = '0'; nr[1] = '\0'; @@ -2059,17 +2414,14 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup) #ifdef ISDN_DEBUG_MODEM_ICALL printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2); #endif + wret = 0; + save_flags(flags); + cli(); for (i = 0; i < ISDN_MAX_CHANNELS; i++) { modem_info *info = &dev->mdm.info[i]; -#ifdef ISDN_DEBUG_MODEM_ICALL - printk(KERN_DEBUG "m_fi: i=%d msn=%s mmsn=%s mreg18=%d mreg19=%d\n", i, - info->emu.msn, isdn_map_eaz2msn(info->emu.msn, di), - info->emu.mdmreg[REG_SI1], info->emu.mdmreg[REG_SI2]); -#endif - if ((!strcmp(isdn_map_eaz2msn(info->emu.msn, di), - eaz)) && /* EAZ is matching */ - (info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */ - (info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */ + + if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */ + (info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */ idx = isdn_dc2minor(di, ch); #ifdef ISDN_DEBUG_MODEM_ICALL printk(KERN_DEBUG "m_fi: match1\n"); @@ -2081,34 +2433,42 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup) #ifndef FIX_FILE_TRANSFER (info->flags & ISDN_ASYNC_NORMAL_ACTIVE) && #endif - (info->isdn_driver == -1) && - (info->isdn_channel == -1) && - (USG_NONE(dev->usage[idx]))) { - info->isdn_driver = di; - info->isdn_channel = ch; - info->drv_index = idx; - dev->m_idx[idx] = info->line; - dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE; - dev->usage[idx] |= (si1 == 1) ? ISDN_USAGE_VOICE : ISDN_USAGE_MODEM; - strcpy(dev->num[idx], nr); - info->emu.mdmreg[REG_SI1I] = si2bit[si1]; - info->emu.mdmreg[REG_PLAN] = setup.plan; - info->emu.mdmreg[REG_SCREEN] = setup.screen; - isdn_info_update(); - restore_flags(flags); - printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr, - info->line); - info->msr |= UART_MSR_RI; - isdn_tty_modem_result(2, info); - isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1); - return info->line; + (info->isdn_driver == -1) && + (info->isdn_channel == -1) && + (USG_NONE(dev->usage[idx]))) { + int matchret; + + if ((matchret = isdn_tty_match_icall(eaz, &info->emu, di)) > wret) + wret = matchret; + if (!matchret) { /* EAZ is matching */ + info->isdn_driver = di; + info->isdn_channel = ch; + info->drv_index = idx; + dev->m_idx[idx] = info->line; + dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE; + dev->usage[idx] |= ((si1 != 1) || (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM)) ? + ISDN_USAGE_MODEM : ISDN_USAGE_VOICE; + strcpy(dev->num[idx], nr); + strcpy(info->emu.cpn, eaz); + info->emu.mdmreg[REG_SI1I] = si2bit[si1]; + info->emu.mdmreg[REG_PLAN] = setup.plan; + info->emu.mdmreg[REG_SCREEN] = setup.screen; + isdn_info_update(); + restore_flags(flags); + printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr, + info->line); + info->msr |= UART_MSR_RI; + isdn_tty_modem_result(2, info); + isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1); + return 1; + } } } } - printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz, - dev->drv[di]->reject_bus ? "rejected" : "ignored"); restore_flags(flags); - return -1; + printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz, + ((dev->drv[di]->flags & DRV_FLAG_REJBUS) && (wret != 2))? "rejected" : "ignored"); + return (wret == 2)?3:0; } #define TTY_IS_ACTIVE(info) \ @@ -2129,7 +2489,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c) case ISDN_STAT_CINF: printk(KERN_DEBUG "CHARGEINFO on ttyI%d: %ld %s\n", info->line, c->arg, c->parm.num); info->emu.charge = (unsigned) simple_strtoul(c->parm.num, &e, 10); - if (e == c->parm.num) + if (e == (char *)c->parm.num) info->emu.charge = 0; break; @@ -2170,10 +2530,11 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c) printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line); #endif if (TTY_IS_ACTIVE(info)) { - if (info->dialing == 1) { - info->dialing = 0; + if (info->dialing == 1) isdn_tty_modem_result(7, info); - } + if (info->dialing > 1) + isdn_tty_modem_result(3, info); + info->dialing = 0; #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n"); #endif @@ -2192,14 +2553,20 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c) if (TTY_IS_ACTIVE(info)) { info->msr |= UART_MSR_DCD; info->emu.charge = 0; - if (info->dialing) { - info->dialing = 0; + if (info->dialing & 0xf) info->last_dir = 1; - } else + else info->last_dir = 0; + info->dialing = 0; info->rcvsched = 1; - if (USG_MODEM(dev->usage[i])) - isdn_tty_modem_result(5, info); + if (USG_MODEM(dev->usage[i])) { + if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) { + strcpy(info->emu.connmsg, c->parm.num); + isdn_tty_modem_result(1, info); + } + else + isdn_tty_modem_result(5, info); + } if (USG_VOICE(dev->usage[i])) isdn_tty_modem_result(11, info); return 1; @@ -2229,11 +2596,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c) sprintf(info->last_cause, "0000"); isdn_tty_modem_result(6, info); } - info->msr &= ~UART_MSR_DCD; - if (info->online) { - isdn_tty_modem_result(3, info); - info->online = 0; - } + isdn_tty_modem_hup(info, 0); return 1; } break; @@ -2394,7 +2757,7 @@ isdn_tty_modem_result(int code, modem_info * info) "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER", "RINGING", "NO MSN/EAZ", "VCON", "RUNG"}; ulong flags; - char s[10]; + char s[ISDN_MSNLEN+10]; switch (code) { case 2: @@ -2474,7 +2837,20 @@ isdn_tty_modem_result(int code, modem_info * info) } isdn_tty_at_cout(msg[code], info); switch (code) { + case 1: + switch (m->mdmreg[REG_L2PROT]) { + case ISDN_PROTO_L2_MODEM: + isdn_tty_at_cout(" ", info); + isdn_tty_at_cout(m->connmsg, info); + break; + } + break; case 2: + /* Append CPN, if enabled */ + if ((m->mdmreg[REG_RESRXT] & BIT_RESRXT)) { + sprintf(s, "/%s", m->cpn); + isdn_tty_at_cout(s, info); + } /* Print CID only once, _after_ 1.st RING */ if ((m->mdmreg[REG_CIDONCE] & BIT_CIDONCE) && (m->mdmreg[REG_RINGCNT] == 1)) { @@ -2561,7 +2937,9 @@ isdn_tty_show_profile(int ridx, modem_info * info) static void isdn_tty_get_msnstr(char *n, char **p) { - while ((*p[0] >= '0' && *p[0] <= '9') || (*p[0] == ',')) + while ((*p[0] >= '0' && *p[0] <= '9') || + /* Why a comma ??? */ + (*p[0] == ',')) *n++ = *p[0]++; *n = '\0'; } @@ -2627,6 +3005,9 @@ isdn_tty_report(modem_info * info) case ISDN_PROTO_L2_TRANS: isdn_tty_at_cout("transparent", info); break; + case ISDN_PROTO_L2_MODEM: + isdn_tty_at_cout("modem", info); + break; default: isdn_tty_at_cout("unknown", info); break; @@ -2669,6 +3050,8 @@ isdn_tty_cmd_ATand(char **p, modem_info * info) int i; char rb[100]; +#define MAXRB (sizeof(rb) - 1) + switch (*p[0]) { case 'B': /* &B - Set Buffersize */ @@ -2720,6 +3103,15 @@ isdn_tty_cmd_ATand(char **p, modem_info * info) isdn_tty_reset_profile(m); isdn_tty_modem_reset_regs(info, 1); break; + case 'L': + /* &L -Set Numbers to listen on */ + p[0]++; + i = 0; + while ((strchr("0123456789,*[]?;", *p[0])) && + (i < ISDN_LMSNLEN)) + m->lmsn[i++] = *p[0]++; + m->lmsn[i] = '\0'; + break; case 'R': /* &R - Set V.110 bitrate adaption */ p[0]++; @@ -2775,6 +3167,11 @@ isdn_tty_cmd_ATand(char **p, modem_info * info) sprintf(rb, "\r\nEAZ/MSN: %.50s\r\n", strlen(m->msn) ? m->msn : "None"); isdn_tty_at_cout(rb, info); + if (strlen(m->lmsn)) { + isdn_tty_at_cout("\r\nListen: ", info); + isdn_tty_at_cout(m->lmsn, info); + isdn_tty_at_cout("\r\n", info); + } break; case 'W': /* &W - Write Profile */ @@ -2940,9 +3337,10 @@ isdn_tty_cmd_ATA(modem_info * info) #ifdef CONFIG_ISDN_AUDIO /* If more than one bit set in reg18, autoselect Layer2 */ if ((m->mdmreg[REG_SI1] & m->mdmreg[REG_SI1I]) != m->mdmreg[REG_SI1]) { - if (m->mdmreg[REG_SI1I] == 1) - l2 = ISDN_PROTO_L2_TRANS; - else + if (m->mdmreg[REG_SI1I] == 1) { + if (l2 != ISDN_PROTO_L2_MODEM) + l2 = ISDN_PROTO_L2_TRANS; + } else l2 = ISDN_PROTO_L2_X75I; } #endif @@ -2958,7 +3356,10 @@ isdn_tty_cmd_ATA(modem_info * info) cmd.driver = info->isdn_driver; cmd.arg = info->isdn_channel; cmd.command = ISDN_CMD_ACCEPTD; + info->dialing = 16; + info->emu.carrierwait = 0; isdn_command(&cmd); + isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1); } else isdn_tty_modem_result(8, info); } @@ -3222,6 +3623,11 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info) printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n"); PARSE_ERROR1; } + info->silence_state = isdn_audio_silence_init(info->silence_state); + if (!info->silence_state) { + printk(KERN_WARNING "isdn_tty: Couldn't malloc silence state\n"); + PARSE_ERROR1; + } if (m->vpar[3] < 5) { info->adpcmr = isdn_audio_adpcm_init(info->adpcmr, m->vpar[3]); if (!info->adpcmr) { @@ -3248,31 +3654,27 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info) break; case '=': p[0]++; - switch (*p[0]) { - case '0': - case '1': - case '2': - case '3': - par1 = isdn_getnum(p); - if ((par1 < 0) || (par1 > 31)) - PARSE_ERROR1; - if (*p[0] != ',') - PARSE_ERROR1; - p[0]++; - par2 = isdn_getnum(p); - if ((par2 < 0) || (par2 > 255)) - PARSE_ERROR1; - m->vpar[1] = par1; - m->vpar[2] = par2; - break; - case '?': - p[0]++; - isdn_tty_at_cout("\r\n<0-31>,<0-255>", - info); - break; - default: + if ((*p[0]>='0') && (*p[0]<='9')) { + par1 = isdn_getnum(p); + if ((par1 < 0) || (par1 > 31)) PARSE_ERROR1; - } + if (*p[0] != ',') + PARSE_ERROR1; + p[0]++; + par2 = isdn_getnum(p); + if ((par2 < 0) || (par2 > 255)) + PARSE_ERROR1; + m->vpar[1] = par1; + m->vpar[2] = par2; + break; + } else + if (*p[0] == '?') { + p[0]++; + isdn_tty_at_cout("\r\n<0-31>,<0-255>", + info); + break; + } else + PARSE_ERROR1; break; default: PARSE_ERROR1; @@ -3446,7 +3848,7 @@ isdn_tty_parse_at(modem_info * info) p++; if (info->msr & UART_MSR_DCD) /* if B-Channel is up */ - isdn_tty_modem_result(5, info); + isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? 1:5, info); else isdn_tty_modem_result(3, info); return; @@ -3487,29 +3889,46 @@ isdn_tty_parse_at(modem_info * info) case 'Z': /* Z - Load Registers from Profile */ p++; + if (info->msr & UART_MSR_DCD) { + info->online = 0; + isdn_tty_on_hook(info); + } isdn_tty_modem_reset_regs(info, 1); break; -#ifdef CONFIG_ISDN_AUDIO case '+': p++; switch (*p) { +#ifdef CONFIG_ISDN_AUDIO case 'F': p++; if (isdn_tty_cmd_PLUSF(&p, info)) return; break; case 'V': - if (!(m->mdmreg[REG_SI1] & 1)) + if ((!(m->mdmreg[REG_SI1] & 1)) || + (m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM)) PARSE_ERROR; p++; if (isdn_tty_cmd_PLUSV(&p, info)) return; break; +#endif /* CONFIG_ISDN_AUDIO */ + case 'S': /* SUSPEND */ + p++; + isdn_tty_get_msnstr(ds, &p); + isdn_tty_suspend(ds, info, m); + break; + case 'R': /* RESUME */ + isdn_tty_get_msnstr(ds, &p); + isdn_tty_resume(ds, info, m); + case 'M': /* MESSAGE */ + p++; + isdn_tty_send_msg(info, m, p); + break; default: PARSE_ERROR; } break; -#endif /* CONFIG_ISDN_AUDIO */ case '&': p++; if (isdn_tty_cmd_ATand(&p, info)) @@ -3674,3 +4093,28 @@ isdn_tty_modem_xmit(void) } isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton); } + +/* + * Check all channels if we have a 'no carrier' timeout. + * Timeout value is set by Register S7. + */ +void +isdn_tty_carrier_timeout(void) +{ + int ton = 0; + int i; + + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + modem_info *info = &dev->mdm.info[i]; + if (info->dialing) { + if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) { + info->dialing = 0; + isdn_tty_modem_result(3, info); + isdn_tty_modem_hup(info, 1); + } + else + ton = 1; + } + } + isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton); +} diff --git a/drivers/isdn/isdn_tty.h b/drivers/isdn/isdn_tty.h index 986cb54f7..663648e58 100644 --- a/drivers/isdn/isdn_tty.h +++ b/drivers/isdn/isdn_tty.h @@ -1,8 +1,8 @@ -/* $Id: isdn_tty.h,v 1.10 1997/03/02 14:29:26 fritz Exp $ +/* $Id: isdn_tty.h,v 1.13 1999/04/12 12:33:46 fritz Exp $ * header for Linux ISDN subsystem, tty related functions (linklevel). * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,24 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.h,v $ + * Revision 1.13 1999/04/12 12:33:46 fritz + * Changes from 2.0 tree. + * + * Revision 1.12 1999/03/02 12:04:51 armin + * -added ISDN_STAT_ADDCH to increase supported channels after + * register_isdn(). + * -ttyI now goes on-hook on ATZ when B-Ch is connected. + * -added timer-function for register S7 (Wait for Carrier). + * -analog modem (ISDN_PROTO_L2_MODEM) implementations. + * -on L2_MODEM a string will be appended to the CONNECT-Message, + * which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN. + * -variable "dialing" used for ATA also, for interrupting call + * establishment and register S7. + * + * Revision 1.11 1998/03/19 13:18:27 keil + * Start of a CAPI like interface for supplementary Service + * first service: SUSPEND + * * Revision 1.10 1997/03/02 14:29:26 fritz * More ttyI related cleanup. * @@ -56,6 +74,7 @@ extern void isdn_tty_modem_escape(void); extern void isdn_tty_modem_ring(void); +extern void isdn_tty_carrier_timeout(void); extern void isdn_tty_modem_xmit(void); extern int isdn_tty_modem_init(void); extern void isdn_tty_readmodem(void); @@ -63,3 +82,4 @@ extern int isdn_tty_find_icall(int, int, setup_parm); extern void isdn_tty_cleanup_xmit(modem_info *); extern int isdn_tty_stat_callback(int, isdn_ctrl *); extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *); +extern int isdn_tty_capi_facility(capi_msg *cm); diff --git a/drivers/isdn/isdn_x25iface.c b/drivers/isdn/isdn_x25iface.c index 2ae21fcf3..d0594fe34 100644 --- a/drivers/isdn/isdn_x25iface.c +++ b/drivers/isdn/isdn_x25iface.c @@ -1,4 +1,4 @@ -/* $Id: isdn_x25iface.c,v 1.3 1998/02/20 17:25:20 fritz Exp $ +/* $Id: isdn_x25iface.c,v 1.6 1999/01/27 22:53:19 he Exp $ * stuff needed to support the Linux X.25 PLP code on top of devices that * can provide a lab_b service using the concap_proto mechanism. * This module supports a network interface wich provides lapb_sematics @@ -10,6 +10,17 @@ * goes to another -- device related -- concap_proto support source file. * * $Log: isdn_x25iface.c,v $ + * Revision 1.6 1999/01/27 22:53:19 he + * minor updates (spellings, jiffies wrap around in isdn_tty) + * + * Revision 1.5 1998/10/30 17:55:39 he + * dialmode for x25iface and multulink ppp + * + * Revision 1.4 1998/06/17 19:51:00 he + * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) + * brute force fix to avoid Ugh's in isdn_tty_write() + * cleaned up some dead code + * * Revision 1.3 1998/02/20 17:25:20 fritz * Changes for recent kernels. * @@ -302,7 +313,12 @@ int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb) case 0x01: /* dl_connect request */ if( *state == WAN_DISCONNECTED ){ *state = WAN_CONNECTING; - cprot -> dops -> connect_req(cprot); + ret = cprot -> dops -> connect_req(cprot); + if(ret){ + /* reset state and notify upper layer about + * immidiatly failed attempts */ + isdn_x25iface_disconn_ind(cprot); + } } else { illegal_state_warn( *state, firstbyte ); } diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c index 46d4f6518..2e580e1c7 100644 --- a/drivers/isdn/isdnloop/isdnloop.c +++ b/drivers/isdn/isdnloop/isdnloop.c @@ -1,4 +1,4 @@ -/* $Id: isdnloop.c,v 1.4 1998/02/24 21:39:05 he Exp $ +/* $Id: isdnloop.c,v 1.8 1998/11/18 18:59:43 armin Exp $ * ISDN low-level module implementing a dummy loop driver. * @@ -19,6 +19,20 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdnloop.c,v $ + * Revision 1.8 1998/11/18 18:59:43 armin + * changes for 2.1.127 + * + * Revision 1.7 1998/10/30 18:58:03 he + * typecast to suppress a compiler warning + * + * Revision 1.6 1998/06/17 19:51:37 he + * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) + * brute force fix to avoid Ugh's in isdn_tty_write() + * cleaned up some dead code + * + * Revision 1.5 1998/04/14 20:59:32 he + * merged 2.1.94 changes + * * Revision 1.4 1998/02/24 21:39:05 he * L2_PROT_X25DTE / DCE * additional state 17 and new internal signal messages "BCON_I" @@ -42,7 +56,7 @@ #include "isdnloop.h" static char -*revision = "$Revision: 1.4 $"; +*revision = "$Revision: 1.8 $"; static int isdnloop_addcard(char *); @@ -1312,7 +1326,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card) c->parm.num[0] ? "N" : "ALL", c->parm.num); } else sprintf(cbuf, "%02d;EAZ%s\n", (int) a, - c->parm.num[0] ? c->parm.num : "0123456789"); + c->parm.num[0] ? c->parm.num : (u_char *) "0123456789"); i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); } break; diff --git a/drivers/isdn/isdnloop/isdnloop.h b/drivers/isdn/isdnloop/isdnloop.h index cacd686d7..42906c143 100644 --- a/drivers/isdn/isdnloop/isdnloop.h +++ b/drivers/isdn/isdnloop/isdnloop.h @@ -1,4 +1,4 @@ -/* $Id: isdnloop.h,v 1.2 1997/10/01 09:22:07 fritz Exp $ +/* $Id: isdnloop.h,v 1.3 1998/04/14 20:59:35 he Exp $ * Loopback lowlevel module for testing of linklevel. * @@ -19,6 +19,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdnloop.h,v $ + * Revision 1.3 1998/04/14 20:59:35 he + * merged 2.1.94 changes + * * Revision 1.2 1997/10/01 09:22:07 fritz * Removed old compatibility stuff for 2.0.X kernels. * From now on, this code is for 2.1.X ONLY! diff --git a/drivers/isdn/pcbit/callbacks.c b/drivers/isdn/pcbit/callbacks.c index 14c0bdcb8..afa22b740 100644 --- a/drivers/isdn/pcbit/callbacks.c +++ b/drivers/isdn/pcbit/callbacks.c @@ -11,6 +11,13 @@ * callbacks for the FSM */ +/* + * Fix: 19981230 - Carlos Morgado <chbm@techie.com> + * Port of Nelson Escravana's <nelson.escravana@usa.net> fix to CalledPN + * NULL pointer dereference in cb_in_1 (originally fixed in 2.0) + */ + + #define __NO_VERSION__ #include <linux/module.h> @@ -164,12 +171,24 @@ void cb_in_1(struct pcbit_dev * dev, struct pcbit_chan* chan, * ictl.num >= strlen() + strlen() + 5 */ + if (cbdata->data.setup.CallingPN == NULL) { + printk(KERN_DEBUG "NULL CallingPN to phone; using 0\n"); + strcpy(ictl.parm.setup.phone, "0"); + } + else { strcpy(ictl.parm.setup.phone, cbdata->data.setup.CallingPN); + } + if (cbdata->data.setup.CalledPN == NULL) { + printk(KERN_DEBUG "NULL CalledPN to eazmsn; using 0\n"); + strcpy(ictl.parm.setup.eazmsn, "0"); + } + else { strcpy(ictl.parm.setup.eazmsn, cbdata->data.setup.CalledPN); - ictl.parm.setup.si1 = 7; - ictl.parm.setup.si2 = 0; - ictl.parm.setup.plan = 0; - ictl.parm.setup.screen = 0; + } + ictl.parm.setup.si1 = 7; + ictl.parm.setup.si2 = 0; + ictl.parm.setup.plan = 0; + ictl.parm.setup.screen = 0; #ifdef DEBUG printk(KERN_DEBUG "statstr: %s\n", ictl.num); diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c index 43c36fa9e..a3186ac11 100644 --- a/drivers/isdn/pcbit/drv.c +++ b/drivers/isdn/pcbit/drv.c @@ -86,6 +86,9 @@ int pcbit_init_dev(int board, int mem_base, int irq) dev_pcbit[board] = dev; memset(dev, 0, sizeof(struct pcbit_dev)); +#if LINUX_VERSION_CODE >= 131841 + init_waitqueue_head(&dev->set_running_wq); +#endif if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF ) dev->sh_mem = (unsigned char*) mem_base; diff --git a/drivers/isdn/pcbit/pcbit.h b/drivers/isdn/pcbit/pcbit.h index 20051bf3e..0dbdb5fd1 100644 --- a/drivers/isdn/pcbit/pcbit.h +++ b/drivers/isdn/pcbit/pcbit.h @@ -68,7 +68,11 @@ struct pcbit_dev { struct frame_buf *write_queue; /* Protocol start */ +#if LINUX_VERSION_CODE < 131841 struct wait_queue *set_running_wq; +#else + wait_queue_head_t set_running_wq; +#endif struct timer_list set_running_timer; struct timer_list error_recover_timer; diff --git a/drivers/isdn/sc/message.c b/drivers/isdn/sc/message.c index 628cdc803..4d4765f79 100644 --- a/drivers/isdn/sc/message.c +++ b/drivers/isdn/sc/message.c @@ -1,5 +1,5 @@ /* - * $Id: message.c,v 1.3 1998/01/31 22:10:55 keil Exp $ + * $Id: message.c,v 1.4 1999/01/05 18:29:47 he Exp $ * Copyright (C) 1996 SpellCaster Telecommunications Inc. * * message.c - functions for sending and receiving control messages |