diff -u --recursive --new-file v2.1.26/linux/Documentation/Changes linux/Documentation/Changes --- v2.1.26/linux/Documentation/Changes Mon Feb 3 03:06:10 1997 +++ linux/Documentation/Changes Fri Feb 21 14:58:32 1997 @@ -26,7 +26,7 @@ http://www.datanet.hu/generations/linux/Changes2.html is an English-language HTML version. -Last updated: January 29, 1997. +Last updated: February 11, 1997. Current Author: Chris Ricker (gt1355b@prism.gatech.edu). Current Minimal Requirements @@ -47,6 +47,7 @@ - Net-tools 1.32-alpha - Kbd 0.91 - Loadlin 1.6a +- Sh-utils 1.16 Upgrade notes ************* @@ -136,6 +137,13 @@ Linux 2.1.22 and later releases use a new method of memory size detection, requiring loadlin users to upgrade to loadlin-1.6a. +Sh-utils +======== + + As of Linux-2.1.26, the Configure script ("make config") has been +updated to be POSIX-compliant. As a result, your expr needs to be +updated. Use sh-utils 1.16 or later. + How to know the version of the installed programs ************************************************* @@ -155,6 +163,7 @@ SysVinit: strings `egrep -li INIT_VERSION=sysvinit- /proc/*/environ | head -1` | egrep -i INIT_VERSION=sysvinit- RPM: rpm --version +Sh-utils: expr --v Where to get the files ********************** @@ -253,6 +262,13 @@ The 1.6a release: ftp://ftp.suse.com/pub/loadlin/update-1.6a/loadlin.exe.gz ftp://elserv.ffm.fgan.de/pub/linux/loadlin-1.6/update-1.6a/loadlin.exe.gz + +Sh-utils +======== + +The 1.16 release +ftp://sunsite.unc.edu/pub/gnu/sh-utils-1.16.tar.gz +ftp://prep.ai.mit.edu/pub/gnu/sh-utils-1.16.tar.gz Other Info ========== diff -u --recursive --new-file v2.1.26/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.26/linux/Documentation/Configure.help Tue Feb 4 06:44:24 1997 +++ linux/Documentation/Configure.help Tue Feb 25 17:12:49 1997 @@ -1217,8 +1217,8 @@ IP-over-DDP support CONFIG_IPDDP This allows IP networking for users who only have Appletalk - networking available. It doesn't work yet in 2.1.xx, so you - should say N. + networking available. This feature is experimental. Please see + http://www.maths.unm.edu/~bradford/ltpc.html LocalTalk PC card support CONFIG_LTPC @@ -1229,7 +1229,8 @@ This driver is experimental, which means that it may not work. In particular the module support is not yet working for the 2.1.xx kernels, so choose Y or N, but not M for now. - See README.ltpc in the drivers/net directory. + See README.ltpc in the drivers/net directory, and the web site + http://www.math.unm.edu/~bradford/ltpc.html Amateur Radio AX.25 Level 2 CONFIG_AX25 @@ -2214,26 +2215,12 @@ compatible to popular modems using TCM3105 or AM7911. The demodulator requires about 12% of the CPU power of a Pentium 75 CPU per channel. -Soundmodem 1200 baud AFSK using floating point -CONFIG_SOUNDMODEM_AFSK1200_FP - This option enables floating point calculations to be used for the - AFSK1200 baud modem. The Intel Pentium is a perverted chip because - integer multiplications are, although easier to implement in silicon, - an order of magnitude slower than floating point calculations. - Enabling this option uses a highly optimized assembler routine for - correlations, modeled after the one published by Phil Karn, KA9Q. - This reduces the computing power needed on Intel Pentium chips to - about 50%. On the other hand, Pentium clones with faster integer - multiply and slower floating point multiply will probably take - longer with this option turned on. As a rule of thumb, enable it for - Intel Pentium and Pentium Pro processors, and disable it for - anything else. - I (sailer@ife.ee.ethz.ch) am very interested in figures. If you are - willing to give me a feedback, please compile the driver once with - this option enabled and once with it disabled, and send me the cycle - counter numbers obtained with both compilations, and your exact - chip. The cycle counter numbers can be obtained with a recent - sethdlc utility. +Soundcard modem support for 4800 baud HAPN-1 modulation +CONFIG_SOUNDMODEM_HAPN4800 + This option enables the soundmodem driver 4800 baud HAPN-1 compatible + modem. This modulation seems to be widely used 'down under' and in + the netherlands. Here, nobody uses it, so I could not test if it works. + It is compatible to itself, however :-) Soundcard modem support for 9600 baud FSK G3RUH modulation CONFIG_SOUNDMODEM_FSK9600 @@ -2244,6 +2231,25 @@ can only use one protocol at a time, depending on what the other end can understand). +Soundcard modem support using floating point arithmetic +CONFIG_SOUNDMODEM_FLOAT + This option enables floating point calculations to be used for the + AFSK1200 baud modem. The Intel Pentium is a perverted chip because + integer multiplications are, altough easier to implement in silicon, + an order of a magnitude slower than floating point calculations. + Enabling this option uses a highly optimized assembler routine for + correlations, modelled after the one published by Phil Karn, KA9Q. + This reduces the computing power needed on Intel Pentium chips to about + 50%. On the other hand, Pentium clones with faster integer multiply and + slower floating point multiply will probably take longer with this + option turned on. As a rule of thumb, enable it for Intel Pentium and + Pentium Pro processors, and disable it for anything else. + I (sailer@ife.ee.ethz.ch) am very interested in figures. If you are + willing to give me a feedback, please compile the driver once with this + option enabled and once with it disabled, and send me the cycle counter + numbers obtained with both compilations, and your exact chip. The cycle + counter numbers can be optained by a recent sethdlc utility. + Serial port KISS driver for AX.25 CONFIG_MKISS KISS is the protocol used to send IP traffic over AX.25 radio @@ -4473,8 +4479,8 @@ (mgetty+sendfax by gert@greenie.muc.de with an extension, available with the ISDN utility package for example), you will be able to use your Linux box as an ISDN-answering machine. Of course, this must be - supported by the lowlevel driver also. Currently, the Teles driver - is the only voice-supporting one. See + supported by the lowlevel driver also. Currently, the Teles and HiSax + drivers are the only voice-supporting drivers. See Documentation/isdn/README.audio for more information. ICN 2B and 4B support @@ -4493,14 +4499,77 @@ Teles, NICCY1016PC, Creatix support CONFIG_ISDN_DRV_TELES This enables support for the Teles ISDN-cards S0-16.0, S0-16.3, S0-8 - and many compatibles. By default, the driver is configured to - support a 16.0-type using EDSS1-protocol. See - Documentation/isdn/README on how to configure it using 16.3, a - different D-channel protocol, or non-standard irq/port/shmem - settings. If you want to compile this as a module ( = code which can - be inserted in and removed from the running kernel whenever you - want), say M here and read Documentation/modules.txt. The module - will be called teles.o. + and many compatibles. + There is a new, heavily improved driver called HiSax which can be + enabled in the next section. This driver will be removed soon. Please + use this driver only if you cannot get the HiSax driver working. + By default, the driver is configured to support a 16.0-type using + EDSS1-protocol. See Documentation/isdn/README on how to configure + it using 16.3, a different D-channel protocol, or non-standard + irq/port/shmem settings. + +HiSax SiemensChipSet driver support +CONFIG_ISDN_DRV_HISAX + This is an alternative driver supporting the Siemens chipset on + various ISDN-cards (like AVM A1, Elsa ISDN cards, Teles S0-16.0, + Teles S0-16.3, Teles S0-8, Teles/Creatix PnP, ITK micro ix1 and + many compatibles). It's a complete rewrite of the original Teles + driver. So you either say M or Y here and N in the above Teles + section. + See Documentation/isdn/README.HiSax for further informations on + using this driver. + +HiSax Support for Teles 16.0/8.0 +CONFIG_HISAX_16_0 + This enables HiSax support for the Teles ISDN-cards S0-16.0, + S0-8 and many compatibles. + See Documentation/isdn/README.HiSax on how to configure it + using the different cards, a different D-channel protocol, or + non-standard irq/port/shmem settings. + +HiSax Support for Teles 16.3 or PNP or PCMCIA +CONFIG_HISAX_16_3 + This enables HiSax support for the Teles ISDN-cards S0-16.3 + the Teles/Creatix PnP and the Teles PCMCIA. + See Documentation/isdn/README.HiSax on how to configure it + using the different cards, a different D-channel protocol, or + non-standard irq/port/shmem settings. + +HiSax Support for AVM A1 (Fritz) +CONFIG_HISAX_AVM_A1 + This enables HiSax support for the AVM A1 (aka "Fritz"). + See Documentation/isdn/README.HiSax on how to configure it + using the different cards, a different D-channel protocol, or + non-standard irq/port/shmem settings. + +HiSax Support for Elsa cards +CONFIG_HISAX_ELSA_PCC + This enables HiSax support for the Elsa Mircolink cards and + for the Elsa Quickstep series cards. + See Documentation/isdn/README.HiSax on how to configure it + using the different cards, a different D-channel protocol, or + non-standard irq/port/shmem settings. + +HiSax Support for ITK ix1-micro Revision 2 +CONFIG_HISAX_IX1MICROR2 + This enables HiSax support for the ITK ix1-micro Revision 2 card. + See Documentation/isdn/README.HiSax on how to configure it + using the different cards, a different D-channel protocol, or + non-standard irq/port/shmem settings. + +HiSax Support for EURO/DSS1 +CONFIG_HISAX_EURO + You should choose your D-channel protocol your local + telephone service provider uses here by saying Y or N. + NOTE: This is mutually exclusive with HiSax Support for + german 1TR6 if you have only one ISDN card installed. + +HiSax Support for german 1TR6 +CONFIG_HISAX_1TR6 + You should choose your D-channel protocol your local + telephone service provider uses here by saying Y or N. + NOTE: This is mutually exclusive with HiSax Support for + EURO/DSS1 if you have only one ISDN card installed. PCBIT-D support CONFIG_ISDN_DRV_PCBIT @@ -4513,6 +4582,13 @@ which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be called pcbit.o. + +Spellcaster support (EXPERIMENTAL) +CONFIG_ISDN_DRV_SC + This enables support for the Spellcaster BRI boards. This driver + currently builds in a modularized version only. + See Documentation/isdn/README.sc and http://www.spellcast.com + for more information. Support for AP1000 multicomputer CONFIG_AP1000 diff -u --recursive --new-file v2.1.26/linux/Documentation/isdn/CREDITS linux/Documentation/isdn/CREDITS --- v2.1.26/linux/Documentation/isdn/CREDITS Sun Apr 21 01:56:13 1996 +++ linux/Documentation/isdn/CREDITS Tue Feb 25 17:12:49 1997 @@ -12,11 +12,18 @@ For contribution of man-pages, the imontty-tool and a perfect maintaining of the mailing-list at hub-wue. +Bernhard Hailer (Bernhard.Hailer@lrz.uni-muenchen.de) + For maintaining the FAQ. + +Michael 'Ghandi' Herold (michael@abadonna.franken.de) + For contribution of the vbox answering machine. + Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) For his Sync-PPP-code. Karsten Keil (isdn4@temic-ech.spacenet.de) For adding 1TR6-support to the Teles-driver. + For the HiSax-driver. Michael Knigge (knick@cove.han.de) For contributing the imon-tool @@ -39,7 +46,7 @@ Gerhard 'Fido' Schneider (fido@wuff.franken.de) For heavy-duty-beta-testing with his BBS ;) -Thomas Uhl (uhl@hn-net.de) +Thomas Uhl (uhl@think.de) For distributing the cards. For pushing me to work ;-) diff -u --recursive --new-file v2.1.26/linux/Documentation/isdn/INTERFACE linux/Documentation/isdn/INTERFACE --- v2.1.26/linux/Documentation/isdn/INTERFACE Sat Jun 29 10:36:22 1996 +++ linux/Documentation/isdn/INTERFACE Tue Feb 25 17:12:49 1997 @@ -1,4 +1,4 @@ -$Id: INTERFACE,v 1.3 1996/06/25 17:52:41 fritz Exp $ +$Id: INTERFACE,v 1.6 1997/02/10 22:40:57 fritz Exp $ Description of the Interface between Linklevel and Hardwarelevel of isdn4linux: @@ -140,7 +140,7 @@ int (*writebuf)(int, int, u_char*, int, int); - ***CHANGEc1.14: Declared obsolete. Do NOT use this field/function + ***CHANGED1.14: Declared obsolete. Do NOT use this field/function anymore, since it will be removed when all current LL drivers have been changed accordingly. Set this field to NULL and use writebuf_skb instead. @@ -199,7 +199,7 @@ int driver-Id. int channel-number locally to the HL-driver. (starts with 0) -***CHANGEc1.14: The driver-Id and channel-number are new since this revision. +***CHANGED1.14: The driver-Id and channel-number are new since this revision. Returnvalue: Length of data accepted on success, else error-code (-EINVAL etc.) @@ -223,7 +223,7 @@ int driver-Id. int channel-number locally to the HL-driver. (starts with 0) -***CHANGEc1.14: The driver-Id and channel-number are new since this revision. +***CHANGED1.14: The driver-Id and channel-number are new since this revision. Returnvalue: Length of data on success, else error-code (-EINVAL etc.) @@ -249,6 +249,9 @@ Until now, the following commands are defined: +***CHANGED1.34: The parameter "num" has been replaced by a union "para" containing + the old "num" and a new setup_type struct used for ISDN_CMD_DIAL + and ISDN_STAT_ICALL callback. ISDN_CMD_IOCTL: @@ -262,10 +265,10 @@ called with the field command set to 1. Parameter: - driver = driver-Id. - command = ISDN_CMD_IOCTL - arg = Original ioctl-cmd - IIOCDRVCTL - num = first bytes filled with (unsigned long)arg + driver = driver-Id. + command = ISDN_CMD_IOCTL + arg = Original ioctl-cmd - IIOCDRVCTL + para.num = first bytes filled with (unsigned long)arg Returnvalue: Depending on driver. @@ -280,12 +283,14 @@ driver = driver-Id. command = ISDN_CMD_DIAL arg = channel-number locally to the driver. (starting with 0) - num = An ASCII-String containing the number to dial, the own - EAZ or MSN, the Service-Indicator and the Additional - Info. Format: - "%s,%s,%d,%d" RemotePhoneNumber,EazOrMsn,SI,AI + + para.setup.phone = An ASCII-String containing the number to dial. + para.setup.eazmsn = An ASCII-Sting containing the own EAZ or MSN. + para.setup.si1 = The Service-Indicator. + para.setup.si2 = Additional Service-Indicator. + If the Line has been designed as SPV (a special german - feature, meaning semi-leased-line) the number has to + feature, meaning semi-leased-line) the phone has to start with an "S". ***CHANGE0.6: In previous versions the EAZ has been given in the highbyte of arg. @@ -300,7 +305,7 @@ driver = driver-Id. command = ISDN_CMD_ACCEPTD arg = channel-number locally to the driver. (starting with 0) - num = unused. + para = unused. ISDN_CMD_ACCEPTB: @@ -311,7 +316,7 @@ driver = driver-Id. command = ISDN_CMD_ACCEPTB arg = channel-number locally to the driver. (starting with 0) - num = unused. + para = unused. ISDN_CMD_HANGUP: @@ -323,7 +328,7 @@ driver = driver-Id. command = ISDN_CMD_HANGUP arg = channel-number locally to the driver. (starting with 0) - num = unused. + para = unused. ISDN_CMD_CLREAZ: @@ -334,7 +339,7 @@ driver = driver-Id. command = ISDN_CMD_CLREAZ arg = channel-number locally to the driver. (starting with 0) - num = unused. + para = unused. ISDN_CMD_SETEAZ: @@ -345,7 +350,7 @@ driver = driver-Id. command = ISDN_CMD_SETEAZ arg = channel-number locally to the driver. (starting with 0) - num = ASCII-String, containing the desired EAZ's/MSN's + para.num = ASCII-String, containing the desired EAZ's/MSN's (comma-separated). If an empty String is given, the HL-driver should respond to ALL incoming calls, regardless of the destination-address. @@ -360,7 +365,7 @@ driver = driver-Id. command = ISDN_CMD_GETEAZ arg = channel-number locally to the driver. (starting with 0) - num = ASCII-String, containing the current EAZ's/MSN's + para.num = ASCII-String, containing the current EAZ's/MSN's ISDN_CMD_SETSIL: (currently unused) @@ -371,7 +376,7 @@ driver = driver-Id. command = ISDN_CMD_SETSIL arg = channel-number locally to the driver. (starting with 0) - num = ASCII-String, containing the desired Service-Indicators. + para.num = ASCII-String, containing the desired Service-Indicators. ISDN_CMD_GETSIL: (currently unused) @@ -382,7 +387,7 @@ driver = driver-Id. command = ISDN_CMD_SETSIL arg = channel-number locally to the driver. (starting with 0) - num = ASCII-String, containing the current Service-Indicators. + para.num = ASCII-String, containing the current Service-Indicators. ISDN_CMD_SETL2: @@ -397,7 +402,7 @@ arg = channel-number locally to the driver. (starting with 0) logical or'ed with (protocol-Id << 8) protocol-Id is one of the constants ISDN_PROTO_L2... - num = unused. + para = unused. ISDN_CMD_GETL2: (currently unused) @@ -408,7 +413,7 @@ driver = driver-Id. command = ISDN_CMD_GETL2 arg = channel-number locally to the driver. (starting with 0) - num = unused. + para = unused. Returnvalue: current protocol-Id (one of the constants ISDN_L2_PROTO) @@ -425,7 +430,7 @@ arg = channel-number locally to the driver. (starting with 0) logical or'ed with (protocol-Id << 8) protocol-Id is one of the constants ISDN_PROTO_L3... - num = unused. + para = unused. ISDN_CMD_GETL2: (currently unused) @@ -436,7 +441,7 @@ driver = driver-Id. command = ISDN_CMD_GETL3 arg = channel-number locally to the driver. (starting with 0) - num = unused. + para = unused. Returnvalue: current protocol-Id (one of the constants ISDN_L3_PROTO) @@ -450,7 +455,7 @@ driver = driver-Id. command = ISDN_CMD_LOCK arg = unused. - num = unused. + para = unused. ISDN_CMD_UNLOCK: @@ -462,7 +467,7 @@ driver = driver-Id. command = ISDN_CMD_UNLOCK arg = unused. - num = unused. + para = unused. 3. Description of the events to be signaled by the HL-driver to th LL. @@ -484,19 +489,29 @@ driver = driver-Id command = ISDN_STAT_STAVAIL arg = length of available data. - num = unused. + para = unused. ISDN_STAT_ICALL: With this call, the HL-driver signals an incoming call to the LL. Parameter: - driver = driver-Id - command = ISDN_STAT_ICALL - arg = channel-number, locally to the driver. (starting with 0) - num = ASCII-String in the following format: - "%s,%d,%d,%s",CallerNumber,ServiceIndicator,AddInfo, - CalledNumber. + driver = driver-Id + command = ISDN_STAT_ICALL + arg = channel-number, locally to the driver. (starting with 0) + para.setup.phone = Callernumber. + para.setup.eazmsn = CalledNumber. + para.setup.si1 = Service Indicator. + para.setup.si2 = Additional Service Indicator. + para.setup.plan = octet 3 from Calling party number Information Element. + para.setup.screen = octet 3a from Calling party number Information Element. + + Return: + 0 = No device matching this call. + 1 = At least one device matching this call (RING on ttyI). + HL-driver may send ALERTING on the D-channel in this case. + 2 = Call will be rejected. + -1 = An error happened. (Invalid parameters for example.) ISDN_STAT_RUN: @@ -507,7 +522,7 @@ driver = driver-Id command = ISDN_STAT_RUN arg = unused. - num = unused. + para = unused. ISDN_STAT_STOP: @@ -518,7 +533,7 @@ driver = driver-Id command = ISDN_STAT_STOP arg = unused. - num = unused. + para = unused. ISDN_STAT_DCONN: @@ -529,7 +544,7 @@ driver = driver-Id command = ISDN_STAT_DCONN arg = channel-number, locally to the driver. (starting with 0) - num = unused. + para = unused. ISDN_STAT_BCONN: @@ -541,7 +556,7 @@ driver = driver-Id command = ISDN_STAT_BCONN arg = channel-number, locally to the driver. (starting with 0) - num = unused. + para = unused. ISDN_STAT_DHUP: @@ -554,7 +569,7 @@ driver = driver-Id command = ISDN_STAT_DHUP arg = channel-number, locally to the driver. (starting with 0) - num = unused. + para = unused. ISDN_STAT_BHUP: @@ -566,7 +581,7 @@ driver = driver-Id command = ISDN_STAT_BHUP arg = channel-number, locally to the driver. (starting with 0) - num = unused. + para = unused. ISDN_STAT_CINF: @@ -577,7 +592,7 @@ driver = driver-Id command = ISDN_STAT_CINF arg = channel-number, locally to the driver. (starting with 0) - num = ASCII string containing charge-units (digits only). + para.num = ASCII string containing charge-units (digits only). ISDN_STAT_LOAD: (currently unused) @@ -590,7 +605,7 @@ driver = driver-Id command = ISDN_STAT_UNLOAD arg = unused. - num = unused. + para = unused. ISDN_STAT_BSENT: @@ -602,7 +617,7 @@ driver = driver-Id command = ISDN_STAT_BSENT arg = channel-number, locally to the driver. (starting with 0) - num = unused. + para = unused. ISDN_STAT_NODCH: @@ -613,7 +628,7 @@ driver = driver-Id command = ISDN_STAT_NODCH arg = channel-number, locally to the driver. (starting with 0) - num = unused. + para = unused. ISDN_STAT_ADDCH: (currently unused) @@ -627,7 +642,7 @@ driver = driver-Id command = ISDN_STAT_ADDCH arg = to be defined. - num = to be defined. + para = to be defined. ISDN_STAT_CAUSE: @@ -640,5 +655,5 @@ driver = driver-Id command = ISDN_STAT_NODCH arg = channel-number, locally to the driver. (starting with 0) - num = ASCII string containing CAUSE-message. + para.num = ASCII string containing CAUSE-message. diff -u --recursive --new-file v2.1.26/linux/Documentation/isdn/README linux/Documentation/isdn/README --- v2.1.26/linux/Documentation/isdn/README Fri Jun 7 06:02:39 1996 +++ linux/Documentation/isdn/README Tue Feb 25 17:12:49 1997 @@ -27,7 +27,14 @@ subscribe isdn4linux To write to the mailing-list, write to isdn4linux@hub-wue.franken.de + + This mailinglist is bidirectionally gated to the newsgroup + + de.alt.comm.isdn4linux + There is also a well maintained FAQ (both english and german) available + at ftp.franken.de in /pub/isdn4linux/FAQ/ + This FAQ is also available at http://www.lrz-muenchen.de/~ui161ab/www/isdn/ 1.1 Technical details @@ -89,6 +96,7 @@ ATI Return "ISDN for Linux...". ATI0 " ATI1 " + ATI2 Report of last connection. ATO On line (data mode). ATQ0 Enable result codes (default). ATQ1 Disable result codes (default). @@ -173,6 +181,10 @@ 1 = T.70 protocol (Only for BTX!) on Bit 2: 0 = Don't hangup on DTR low. 1 = Hangup on DTR low. + Bit 3: 0 = Standard response messages + 1 = Extended response messages + Bit 4: 0 = CALLER NUMBER before every RING. + 1 = CALLER NUMBER after first RING. 14 0 Layer-2 protocol: 0 = X75/LAPB with I-frames 1 = X75/LAPB with UI-frames @@ -201,6 +213,14 @@ 20 0 Bit coded register (readonly) Service-Octet-1 of last call. Bit mapping is the same like register 18 + 21 0 Bit coded register (readonly) + Set on incoming call (during RING) to + octet 3 of calling party number IE (Numbering plan) + See section 4.5.10 of ITU Q.931 + 22 0 Bit coded register (readonly) + Set on incoming call (during RING) to + octet 3a of calling party number IE (Screening info) + See section 4.5.10 of ITU Q.931 Last but not least a (at the moment fairly primitive) device to request the line-status (/dev/isdninfo) is made available. @@ -243,16 +263,11 @@ 2 System prerequisites: - ATTENTION! The program "insmod" from the Package "modules-1.2.8" (It's - on nearly all newer distributions) has a bug, which makes - it impossible to set both driver-Id's when loading the - icn-module for the Double-ICN-Card. A patch is supplied - in the utility-package called "insmod-1.2.8.patch". Change into - the source-directory of insmod, and type - "patch < insmod-1.2.8.patch". Then recompile it. This will fix - the bug. - This bug does NOT occur when using insmod with the Teles-driver - or a single ICN-card. + ATTENTION! + + Always use the latest module utilities. The current version is + named in Documentation/Changes. Some old versions of insmod + are not capable of setting the driver-Ids correctly. 3. Lowlevel-driver configuration. diff -u --recursive --new-file v2.1.26/linux/Documentation/isdn/README.HiSax linux/Documentation/isdn/README.HiSax --- v2.1.26/linux/Documentation/isdn/README.HiSax Wed Dec 31 16:00:00 1969 +++ linux/Documentation/isdn/README.HiSax Tue Feb 25 17:12:49 1997 @@ -0,0 +1,343 @@ +HiSax is a Linux hardware level driver for passive ISDN cards with Siemens +chipset (ISAC_S 2085/2086/2186 HSCX SAB 82525). It is based on the Teles +driver from Jan den Ouden. +It is meant to be used with isdn4linux, an ISDN Link-level module for Linux +written by Fritz Elfert. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + +Supported Cards +--------------- + +Teles 8.0/16.0/16.3 and compatible +Teles S0/PCMCIA +Creatix PnP S0 +AVM A1 (Fritz) +ELSA Microlink PCC-16 PCF PCF-Pro PCC-8 +ELSA Quickstep 1000 +ITK ix1-micro Rev.2 + +Note: PCF PCF-Pro only the ISDN part is supported yet + PCC-8 not tested yet + Teles PCMCIA is EXPERIMENTAL + +If you know other passive cards with the Siemens chipset, please let me know. +To use the PNP cards you need the isapnptools. + + +Configuring the Driver +---------------------- + +The driver can be build direct into the kernel or as module. +The HiSax driver can be configured using the command line feature +while loading the kernel with LILO or LOADLIN or, if built as a module, +using insmod/modprobe with parameters. +Please note: All PnP cards need config with isapnp and will work only as +module. + +As Module +--------- + +insmod/modprobe hisax.o \ + io=iobase irq=IRQ mem=membase type=card_type \ + protocol=D_channel_protocol id=idstring + +or, if several cards are installed: + +insmod/modprobe hisax.o \ + io=iobase1,iobase2,... mem=membase1,membase2,... \ + type=card_type1,card_type2,... \ + protocol=D_channel_protocol1,D_channel_protocol2,... \ + id=idstring1%idstring2 ... + +where iobaseN = io base address of the Nth card, membaseN = memory +base address of the Nth card, etc. +The reason for the delimiter "%" in the idstrings is that "," won't +work with the current modules package. + +The parameters can be specified in any order. For example, the io +parameter can precede the irq parameter, or vice versa. If several +cards are installed the ordering within the comma separated parameter +lists must be consistent, of course. + +Only parameters applicable to the card type need be specified. For +example, the Teles 16.3 card is not memory mapped, so the mem +parameter may be omitted for a Teles 16.3. Sometimes it is necessary +to specify a dummy parameter, however. This is the case when there is +a card of a different type later in the list that needs a parameter +which the preceding card does not. For instance, if a Teles 16.0 card +is listed after a Teles 16.3 card, a dummy mem=0 parameter must be +specified for the 16.3. Instead of a dummy value, the parameter can +also be skipped by simply omitting the value. For example: +mem=,0xd0000. See example 6 below. +The protocol parameter for the D-channel may be omittedprotocol may be +omitted, if you select the correct one during kernel config. +Valid values are 1 for german 1TR6, 2 for DSS1 (EURO) and 3 for leased lines +(no D-channel). + +The Creatix/Teles PnP cards uses io1= and io2= instead of io= for specifying +the I/O addresses of the ISAC and HSCX chips, respectively. + +Card types: + + Type Required parameters (in addition to type and protocol) + + 1 Teles 16.0 irq, mem, io + 2 Teles 8.0 irq, mem + 3 Teles 16.3 (non PnP) irq, io + 4 Creatix/Teles PnP irq, io0 (ISAC), io1 (HSCX) + 5 AVM A1 (Fritz) irq, io + 6 ELSA PCC/PCF cards io or nothing for autodetect (the iobase is + only required, if you have more than one ELSA + card in your PC) + 7 ELSA Quickstep 1000 irq, io (from isapnp setup) + 8 Teles 16.3 PCMCIA irq, io + 9 ITK ix1-micro Rev.2 irq, io + +At the moment IRQ sharing is not possible. Please make sure that your IRQ +is free and enabled for ISA use. + +Examples for module loading + +1. Teles 16.3, Euro ISDN, I/O base 280 hex, IRQ 10 + modprobe hisax type=3 protocol=2 io=0x280 irq=10 + +2. Teles 16.0, 1TR6 ISDN, I/O base d80 hex, IRQ 5, Memory d0000 hex + modprobe hisax protocol=1 type=1 io=0xd80 mem=0xd0000 irq=5 + +3. Fritzcard, Euro ISDN, I/O base 340 hex, IRQ 10 and ELSA PCF, Euro ISDN + modprobe hisax type=5,6 protocol=2,2 io=0x340 irq=10 id=Fritz%Elsa + +4. Any ELSA PCC/PCF card Euro ISDN + modprobe hisax type=6 protocol=2 + +5. Teles 16.3 PnP, Euro ISDN, with isapnp configured + isapnp config: (INT 0 (IRQ 10 (MODE +E))) + (IO 0 (BASE 0x0580)) + (IO 1 (BASE 0x0180)) + modprobe hisax type=4 protocol=2 io0=0x580 io1=0x180 + +6. Teles 16.3, Euro ISDN, I/O base 280 hex, IRQ 12 and + Teles 16.0, 1TR6, IRQ 5, Memory d0000 hex + modprobe hisax type=3,1 protocol=2,1 io=0x280 mem=0,0xd0000 + + Please note the dummy 0 memory address for the Teles 16.3 in the last + example as placeholder. + +7. Teles PCMCIA EURO 180 hex IRQ 15 (default values) + modprobe hisax type=8 protocol=2 io=0x180 irq=15 + + +LILO/LOADLIN with driver compiled direct into the kernel: + +hisax=typ1,dp1,pa_1,pb_1,pc_1[,typ2,dp2,pa_2 ... \ + typn,dpn,pa_n,pb_n,pc_n][,idstring1[,idstring2,...,idstringn]] + +where + typ1 = Cardtype of 1st card. (default: depends on kernel settings) + dp1 = D-channel protocol of 1st card. 1=1TR6, 2=EDSS1, 3=leased + pa_1 = 1. parameter (depend on the cardtype) + pb_1 = 2. parameter (depend on the cardtype) + pc_1 = 3. parameter (depend on the cardtype) + + typ2,dp2,pa_2,pb_2,pc_2 = Parameters of second card (defaults: none) + typn,dpn,pa_n,pb_n,pc_n = Parameters of n'th card (up to 16 cards are supported) + + idstring = Driver-Id for accessing with utilities and identification + when using a Line-monitor. (default: HiSax) + idstring must start with a character! + +Card types: + + typ + 1 Teles 16.0 pa=irq pb=membase pc=iobase + 2 Teles 8.0 pa=irq pb=membase + 3 Teles 16.3 pa=irq pb=iobase + 4 Creatix/Teles PNP ONLY WORK AS MODULE ! + 5 AVM A1 (Fritz) pa=irq pb=iobase + 6 ELSA PCC/PCF cards pa=iobase or nothing for autodetect + 7 ELSA Quickstep 1000 ONLY WORK AS MODULE ! + 8 Teles S0 PCMCIA pa=irq pb=iobase + 9 ITK ix1-micro Rev.2 pa=irq pb=iobase + + +Running +------- + +When you insmod isdn.o and hisax.o (or with the kernel-version, during +boottime) a few lines should appear in your syslog. Look for something like: + +Oct 13 20:46:39 kke01 kernel: ISDN subsystem Rev: 1.23/1.21/1.18/1.13/none loaded +Oct 13 20:46:41 kke01 kernel: HiSax: Driver for Siemens Chipset ISDN cards +Oct 13 20:46:41 kke01 kernel: HiSax: Revision (1.3) +Oct 13 20:46:41 kke01 kernel: HiSax: Total 1 card defined +Oct 13 20:46:41 kke01 kernel: HiSax: Card 1 Protocol EDSS1 +... +Oct 13 20:46:41 kke01 kernel: Elsa: PCC16 found at 0x360 Rev.:B IRQ 9 +... +Oct 13 20:46:41 kke01 kernel: HiSax: 2 channels available +Oct 13 20:46:41 kke01 kernel: HiSax: module installed + +This means that the card is ready for use. +Cabling problems or line downs are not detected, ELSA can detect the +S0 power. + +Remember, that according to the new strategy for accessing Low-level-drivers +from within isdn4linux you should also define a driver-id while doing +insmod: Simply append hisax_id= to the insmod-commandline. This +string MUST NOT start with a digit or a small 'x'! + +At this point you can run a 'cat /dev/isdnctrl0' and view debugging +messages. +In the moment debugging messages are enabled with the telesctrl tool : + + telesctrl DebugCmd + + default is HiSax, if you didn't specified one. + +DebugCmd is 1 for generic Debug + 11 for Layer 1 development Debug + 13 for Layer 3 development Debug + +where is the integer sum of the following debugging +options you wish enabled: + +With DebugCmd 1 is + + 1 Link-level <--> Hardware-level communication + 2 Top state machine + 4 D channel Q.931 (call control messages) + 8 D channel Q.921 + 16 B channel X.75 + 32 D channel l2 + 64 B channel l2 + 128 D-Channel link state debug + 256 B-Channel link state debug + 512 Tei debug + 1024 LOCK debug in callc.c + +With DebugCmd 11 is + + 1 Warnings (default on) + 2 Irq Status + 4 Isac + 8 Isac fifo + 16 Hscx + 32 Hscx fifo (attention full B-channel output) + 64 D-channel LAPD frame types + +With DebugCmd 13 is + + 1 Warnings (default on) + 2 l3 protocol discriptor errors + 4 l3 stat machine + 8 charge info debug (1TR6) + +For example 'telesctrl HiSax 1 0x3ff' enables full generic debugging. + + + +Warning +------- +HiSax is a work in progress and may crash your machine. It has not been +certified and therefore operation on your PTT's ISDN network is probably +illegal. + +Limitations +----------- +HiSax only works on Euro ISDN lines and german 1TR6-lines.(in this time) + +Bugs +---- +If you find any please let me know. + +Thanks +------ +Special thanks to: + + Emil Stephan for the name HiSax which is a mix of HSCX and ISAC. + + Fritz Elfert, Jan den Ouden, Michael Hipp, Michael Wein, + Andreas Kool, Pekka Sarnila, Sim Yskes, Johan Myrre'en, + Klaus-Peter Nischke (ITK AG), Christof Petig, Werner Fehn (Elsa GmbH), + Volker Schmidt + and more people, who are hunting bugs (If I forgot somebody, please + send me a mail). + + Firma ELSA GmbH + + My girl friend and partner in life Ute for her patience with me + + +Enjoy, + +Karsten Keil +keil@temic-ech.spacenet.de + +Appendix: PCMCIA driver +----------------------- + +Up to now, the Teles PCMCIA driver is a complete hack. I had no +documentation about the card - it might destroy your hardware (though mine +at last works fine). + +Second I'm working on a module for linux pcmcia services, this version +clearly assumes some (unrealistic) facts about your hardware: + - you MUST have an i82365 + - Teles PCMCIA MUST be in slot 0 (the upper one) and the ONLY card + (since you can't use cardmgr, there's no use for a second one) + - ports 0x180-0x1e0 must be free, it uses IRQ 15 + +The following program will initialize the PCMCIA chip to the values I probed +inside Windows95 (native Teles driver). + +------------------telesinit.c----------------------------------------- +/* telesinit.c, compile with + * gcc -O -o telesinit telesinit.c + */ +#include +#define inportb(x) inb(x) +#define outportb(x,v) outb(v,x) +#define BASE 0x180 +#define NUM 97 +#define CARD 0x3e0 +#define i365(x) ( outportb(CARD,x), inportb(CARD+1) ) +#define i365w(x,y) ( outportb(CARD,x), outportb(CARD+1,y) ) + +void main(int argc,char **argv) +{ int i; + static unsigned char i365_cont[]= + { 0x83,0x7f,0xf5,0x6f, 0x00,0x08,0x60,0x00, + 0x80,0x01,0xe0,0x01, 0xff,0xff,0xff,0xff, + 0xd0,0x00,0xd0,0x00, 0x30,0x7f,0x00,0x0f, + 0xff,0x07,0xff,0x07, 0x00,0x00,0x00,0xff + }; + + ioperm(BASE,NUM,1); ioperm(CARD,2,1); + for (i=0;i<32;i++) + { if (i365_cont[i]==i365(i)) continue; + outportb(CARD+1,i365_cont[i]); + } + + outportb(BASE+0x18,0x41); + /* enable the teles card and its IRQ */ + /* this was found by brute force */ +} +------------------------------------------------------------------------ + +If you want to wait for the PCMCIA services driver ... I finish my diploma +about end of February 1997 ... please be patient with me + Christof Petig (ea0141@uni-wuppertal.de) diff -u --recursive --new-file v2.1.26/linux/Documentation/isdn/README.audio linux/Documentation/isdn/README.audio --- v2.1.26/linux/Documentation/isdn/README.audio Fri Jun 7 06:02:39 1996 +++ linux/Documentation/isdn/README.audio Tue Feb 25 17:12:49 1997 @@ -1,4 +1,4 @@ -$Id: README.audio,v 1.3 1996/06/05 02:19:36 fritz Exp $ +$Id: README.audio,v 1.4 1997/02/03 23:43:47 fritz Exp $ ISDN subsystem for Linux. Description of audio mode. @@ -86,8 +86,11 @@ starts sending audio data to the application. There are several escape sequences defined, all using DLE (0x10) as Escape char: - End of audio data. Emulator stops + End of audio data. (i.e. caused by a + hangup of the remote side) Emulator stops recording, responding with VCON. + Abort recording, (send by appl.) Emulator + stops recording, sends DLE,ETX. Escape sequence for DLE in data stream. 0 Touchtone "0" received. ... @@ -107,13 +110,16 @@ s silence. Silence detected from the start of recording. - Any character sent by the application, except XON (0x11) or XOFF (0x13) - immediately stops recording. - Audio playback. When sending audio data, upon AT+VTX command, emulator responds with CONNECT, and starts transferring data from application to the phone line. The same DLE sequences apply to this mode. + Full-Duplex-Audio: + + When _both_ commands for recording and playback are given in _one_ + AT-command-line (i.e.: "AT+VTX+VRX"), full-duplex-mode is selected. + In this mode, the only way to stop recording is sending + and the only way to stop playback is to send . diff -u --recursive --new-file v2.1.26/linux/Documentation/isdn/README.sc linux/Documentation/isdn/README.sc --- v2.1.26/linux/Documentation/isdn/README.sc Wed Dec 31 16:00:00 1969 +++ linux/Documentation/isdn/README.sc Tue Feb 25 17:12:49 1997 @@ -0,0 +1,274 @@ +Welcome to Beta Release 2 of the combination ISDN driver for SpellCaster's +ISA ISDN adapters. Please note this release 2 includes support for the +DataCommute/BRI and TeleCommute/BRI adapters only and any other use is +guaranteed to fail. If you have a DataCommute/PRI installed in the test +computer, we recommend removing it as it will be detected but will not +be usable. To see what we have done to Beta Release 2, see section 3. + +Speaking of guarantees, THIS IS BETA SOFTWARE and as such contains +bugs and defects either known or unknown. Use this software at your own +risk. There is NO SUPPORT for this software. Some help may be available +through the web site or the mailing list but such support is totally at +our own option and without warrantee. If you choose to assume all and +total risk by using this driver, we encourage you to join the beta +mailing list. + +To join the Linux beta mailing list, send a message to: +majordomo@spellcast.com with the words "subscribe linux-beta" as the only +contents of the message. Do not include a signature. If you choose to +remove yourself from this list at a later date, send another message to +the same address with the words "unsubscribe linux-beta" as it's only +contents. + +TABLE OF CONTENTS +----------------- + 1. Introduction + 1.1 What is ISDN4Linux? + 1.2 What is different between this driver and previous drivers? + 1.3 How do I setup my system with the correct software to use + this driver release? + + 2. Basic Operations + 2.1 Unpacking and installing the driver + 2.2 Read the man pages!!! + 2.3 Installing the driver + 2.4 Removing the driver + 2.5 What to do if it doesn't load + 2.6 How to setup ISDN4Linux with the driver + + 3. Beta Change Summaries and Miscellaneous Notes + +1. Introduction +--------------- + +The revision 2 Linux driver for SpellCaster ISA ISDN adapters is built +upon ISDN4Linux available seperately or as included in Linux 2.0 and later. +The driver will support a maximum of 4 adapters in any one system of any +type including DataCommute/BRI, DataCommute/PRI and TeleCommute/BRI for a +maximum of 92 channels for host. The driver is supplied as a module in +source form and needs to be complied before it can be used. It has been +tested on Linux 2.0.20. + +1.1 What Is ISDN4Linux + +ISDN4Linux is a driver and set of tools used to access and use ISDN devices +on a Linux platform in a common and standard way. It supports HDLC and PPP +protocols and offers channel bundling and MLPPP support. To use ISDN4Linux +you need to configure your kernel for ISDN support and get the ISDN4Linux +tool kit from our web site. + +ISDN4Linux creates a channel pool from all of the available ISDN channels +and therefore can function across adapters. When an ISDN4Linux compliant +driver (such as ours) is loaded, all of the channels go into a pool and +are used on a first-come first-served basis. In addition, individual +channels can be specifically bound to particular interfaces. + +1.2 What is different between this driver and previous drivers? + +The revision 2 driver besides adopting the ISDN4Linux architecture has many +subtle and not so subtle functional differences from previous releases. These +include: + - More efficient shared memory management combined with a simpler + configuration. All adapters now use only 16Kbytes of shared RAM + versus between 16K and 64K. New methods for using the shared RAM + allow us to utilize all of the available RAM on the adapter through + only one 16K page. + - Better detection of available upper memory. The probing routines + have been improved to better detect avaialble shared RAM pages and + used pages are now locked. + - Decreased loading time and a wider range of I/O ports probed. + We have significantly reduced the amount of time it takes to load + the driver and at the same time doubled the number of I/O ports + probed increasing the likelyhood of finding an adapter. + - We now support all ISA adapter models with a single driver instead + of seperate drivers for each model. The revision 2 driver supports + the DataCommute/BRI, DataCommute/PRI and TeleCommute/BRI in any + combination up to a maximum of four adapters per system. + - On board PPP protocol support has been removed in favour of the + sync-PPP support used in ISDN4Linux. This means more control of + the protocol parameters, faster negotiation time and a more + familiar interface. + +1.3 How do I setup my system with the correct software to use + this driver release? + +Before you can compile, install and use the SpellCaster ISA ISDN driver, you +must ensure that the following software is installed, configuraed and running: + + - Linux kernel 2.0.20 or later with the required init and ps + versions. Please see your distribution vendor for the correct + utility packages. The latest kernel is available from + ftp://sunsite.unc.edu/pub/Linux/kernel/v2.0/ + + - The latest modules package (modules-2.0.0.tar.gz) from + ftp://sunsite.unc.edu/pub/Linux/kernel/modules-2.0.0.tar.gz + + - The ISDN4Linux tools available from + ftp://ftp.franken.de/pub/isdn4linux/v2.0/isdn4k-utils-2.0.tar.gz + This package may fail to compile for you so you can alternatively + get a pre-compiled version from + ftp://ftp.spellcast.com/pub/drivers/isdn4linux/isdn4k-bin-2.0.tar.gz + + +2. Basic Operations +------------------- + +2.1 Unpacking and installing the driver + + 1. As root, create a directory in a convienient place. We suggest + /usr/src/spellcaster. + + 2. Unpack the archive with : + tar xzf sc-n.nn.tar.gz -C /usr/src/spellcaster + + 3. Change directory to /usr/src/spellcaster + + 4. Read the README and RELNOTES files. + + 5. Run 'make' and if all goes well, run 'make install'. + +2.2 Read the man pages!!! + +Make sure you read the scctrl(8) and sc(4) manual pages before continuing +any further. Type 'man 8 scctrl' and 'man 4 sc'. + +2.3 Installing the driver + +To install the driver, type '/sbin/insmod sc' as root. sc(4) details options +you can specify but you shouldn't need to use any unless this doesn't work. + +Make sure the driver loaded and detected all of the adapters by typing +'dmesg'. + +The driver can be configured so that it is loaded upon startup. To do this, +edit the file "/etc/modules/'uname -f'/'uname -v'" and insert the driver name +"sc" into this file. + +2.4 Removing the driver + +To remove the driver, delete any interfaces that may exist (see isdnctrl(8) +for more on this) and then type '/sbin/rmmod sc'. + +2.5 What to do if it doesn't load + +If, when you try to install the driver, you get a message mentioning +'register_isdn' then you do not have the ISDN4Linux system installed. Please +make sure that ISDN support is configured in the kernel. + +If you get a message that says 'initialization of sc failed', then the +driver failed to detect an adapter or failed to find resources needed such +as a free IRQ line or shared memory segment. If you are sure there are free +resources available, use the insmod options detailed in sc(4) to override +the probing function. + +Upon testing, the following problem was noted, the driver would load without +problems, but the board would not respond beyond that point. When a check was +done with 'cat /proc/interrupts' the interrupt count for sc was 0. In the event +of this problem, change the BIOS settings so that the interrupts in question are +reserved for ISA use only. + + +2.6 How to setup ISDN4Linux with the driver + +There are two main configurations which you can use with the driver: + +A) Basic HDLC connection +B) PPP connection +C) MLPPP connection + +It should be mentioned here that you may also use a tty connection if you desire. +The Documentation directory of the isdn4linux subsystem offers a good documentation +on this feature. + +A) 10 steps to the establishment of a basic HDLC connection +----------------------------------------------------------- + +- please open the isdn-hdlc file in the examples directory and follow along... + + This file is a script used to configure a BRI ISDN TA to establish a basic HDLC + connection between its two channels. There two network interfaces which are + created and two routes added between the channels. + + i) using the isdnctrl utitity, add an interface with "addif" and name it "isdn0" + ii) add the outgoing and inbound telephone numbers + iii) set the Layer 2 protocol to hdlc + iv) set the eaz of the interface to be the phone number of that specific channel + v) to turn the callback features off, set the callback to "off" and + the callback delay (cbdelay) to 0. + vi) the hangup timeout can be set to a specified number of seconds + vii) the hangup upon incomming call can be set on or off + viii) use the ifconfig command to bring-up the network interface with a specific + IP address and point to point address + viv) add a route to the IP address through the isdn0 interface + x) a ping should result in the establishment of the connection + + +B) Establishment of a PPP connection +------------------------------------ + +- please open the isdn-ppp file in the examples directory and follow along... + + This file is a script used to configure a BRI ISDN TA to establish a PPP connection + between the two channels. The file is almost identical to the HDLC connection + example except that the packet ecapsulation type has to be set. + + use the same procedure as in the HDLC connection from steps i) to iii) then, + after the Layer 2 protocol is set, set the encapsulation "encap" to syncppp. + With this done, the rest of the steps, iv) to x) can be followed from above. + + Then, the ipppd (ippp daemon) must be setup: + + xi) use the ipppd function found in /sbin/ipppd to set the following: + xii) take out (minus) VJ compression and bsd compression + xiii) set the mru size to 2000 + xiv) link the two /dev interfaces to the daemon + +NOTE: A "*" in the inbound telephone number specifies that a call can be accepted + on any number. + +C) Establishment of a MLPPP connection +-------------------------------------- + +- please open the isdn-mppp file in the examples directory and follow along... + + This file is a script used to configure a BRI ISDN TA to accept a Multi Link PPP + connection. + + i) using the isdnctrl utitity, add an interface with "addif" and name it "ippp0" + ii) add the inbound telephone number + iii) set the Layer 2 protocol to hdlc and the Layer 3 protocol to trans (transparent) + iv) set the packet encapsulation to syncppp + v) set the eaz of the interface to be the phone number of that specific channel + vi) to turn the callback features off, set the callback to "off" and + the callback delay (cbdelay) to 0. + vi) the hangup timeout can be set to a specified number of seconds + vii) the hangup upon incomming call can be set on or off + viii) add a slave interface and name it "ippp32" for example + viv) set the similar parameters for the ippp32 interface + x) use the ifconfig command to bring-up the ippp0 interface with a specific + IP address and point to point address + xi) add a route to the IP address through the ippp0 interface + xii) use the ipppd function found in /sbin/ipppd to set the following: + xiii) take out (minus) bsd compression + xiv) set the mru size to 2000 + xv) add (+) the multi-link function "+mp" + xv) link the two /dev interfaces to the daemon + +NOTE: To use the MLPPP connection to dial OUT to a MLPPP connection, change the + inbound telephone numbers to the outgoing telephone numbers of the MLPPP + host. + + +3. Beta Change Summaries and Miscellaneous Notes +------------------------------------------------ +When using the "scctrl" utility to upload firmware revisions on the board, please +note that the byte count displayed at the end of the operation may be different +than the total number of bytes in the "dcbfwn.nn.sr" file. Please disregard the +displayed byte count. + +It was noted that in Beta Release 1, the module would fail to load and result in a +segmentation fault when insmod"ed". This problem was created when one of the +isdn4linux parameters, (isdn_ctrl, data field) was filled in. In some cases, this +data field was NULL, and was left unchecked, so when it was referenced.. segv. +The bug has been fixed around line 63-68 of event.c. + diff -u --recursive --new-file v2.1.26/linux/Documentation/networking/ax25.txt linux/Documentation/networking/ax25.txt --- v2.1.26/linux/Documentation/networking/ax25.txt Sun Feb 2 05:18:29 1997 +++ linux/Documentation/networking/ax25.txt Fri Feb 21 14:58:32 1997 @@ -1,53 +1,14 @@ -With the version of the AX.25, NET/ROM and Rose protocol stacks provided in -the Linux kernel from 2.1.9 onwards, a change has occurred in the -configuration of the protocols. With previous versions such changes were -made via ioctl calls, but now use is being made of the sysctl interface. - -Each AX.25 device will be represented in the directory /proc/sys/net/ax25, -in the form "dev.parms" where dev is the device name, eg ax0. In it are a -string of numbers that represent different values for the different -parameters, they are: - -No. Name Meaning Default -1 IP Default Mode 0=DG 1=VC 0 -2 AX.25 Default Mode 0=Normal 1=Extended 0 -3 Allow Vanilla Connects 0=No 1=Yes 1 -4 Backoff 0=None 1=Linear 2=Exponential 1 -5 Connected Mode 0=No 1=Yes 1 -6 Standard Window 1 <= N <= 7 2 -7 Extended Window 1 <= N <= 63 32 -8 T1 Timeout 1s <= N <= 30s 10s -9 T2 Timeout 1s <= N <= 20s 3s -10 T3 Timeout 0s <= N <= 3600s 300s -11 Idle Timeout 0m <= N 20m -12 N2 1 <= N <= 31 10 -13 AX.25 MTU 1 <= N <= 512 256 -14 Max Queue 1 <= N <= 20 2 -15 Digipeater Mode 0=None 1=Inband 2=XBand 3=Both 3 - -In the above list T1, T2 and T3 are given in seconds, and the Idle Timeout -is given in minutes. But please note that the values used in the sysctl -interface are given in internal units where the time in seconds is -multiplied by 10, this allows resolution down to 1/10 of a second. With -timers that are allowed to be zero, eg T3 and Idle, a zero value indicates -that the timer is disabled. - -With NET/ROM and Rose protocol stacks, the entries in /proc/sys/net/netrom -and /proc/sys/net/rose are more obvious. Each file in these directories has -a name more in keeping with its function, and will not be explained in any -greater depth here. As with the AX.25 sysctl entries, timers operate with a -resolution of 100ms and so values should be written accordingly. - -It is possible that the AX.25 sysctl interface will change in the future and -become more user friendly. - -For more information about the AX.25 and NET/ROM protocol stacks, see the -AX25-HOWTO written by Terry Dawson who is -also the AX.25 Utilities maintainer. +To use the amateur radio protocols within Linux you will need to get a +suitable copy of the AX.25 Utilities. More detailed information about these +and associated programs can be found on http://www.cs.nott.ac.uk/~jsn/. + +For more information about the AX.25, NET/ROM and ROSE protocol stacks, see +the AX25-HOWTO written by Terry Dawson +who is also the AX.25 Utilities maintainer. There is an active mailing list for discussing Linux amateur radio matters called linux-hams. To subscribe to it, send a message to -majordomo@vger.rutgers.edu with the words "subscribe linux-hams" in the body +Majordomo@vger.rutgers.edu with the words "subscribe linux-hams" in the body of the message, the subject field is ignored. Jonathan G4KLX diff -u --recursive --new-file v2.1.26/linux/MAINTAINERS linux/MAINTAINERS --- v2.1.26/linux/MAINTAINERS Fri Feb 7 05:54:53 1997 +++ linux/MAINTAINERS Fri Feb 21 14:58:32 1997 @@ -81,6 +81,7 @@ M gpg109@rsphy1.anu.edu.au L: linux-net@vger.rutgers.edu S: Maintained +W: http://rsphy1.anu.edu.au/~gpg109/ne2000.html ETHEREXPRESS-16 NETWORK DRIVER P: Philip Blundell diff -u --recursive --new-file v2.1.26/linux/Makefile linux/Makefile --- v2.1.26/linux/Makefile Fri Feb 7 06:30:55 1997 +++ linux/Makefile Fri Feb 21 15:33:17 1997 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 26 +SUBLEVEL = 27 ARCH = i386 @@ -11,7 +11,7 @@ # # NOTE! SMP is experimental. See the file Documentation/SMP.txt # -# SMP = 1 +SMP = 1 # # SMP profiling options # SMP_PROF = 1 @@ -330,6 +330,9 @@ rm -f drivers/sound/local.h drivers/sound/.defines rm -f drivers/scsi/aic7xxx_asm drivers/scsi/aic7xxx_seq.h rm -f drivers/char/uni_hash.tbl drivers/char/conmakehash + rm -f drivers/net/soundmodem/sm_tbl_{afsk1200,afsk2666,fsk9600}.h + rm -f drivers/net/soundmodem/sm_tbl_{hapn4800,psk4800}.h + rm -f drivers/net/soundmodem/gentbl rm -f .version .config* config.in config.old rm -f scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog diff -u --recursive --new-file v2.1.26/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.1.26/linux/arch/alpha/kernel/entry.S Thu Feb 6 04:42:35 1997 +++ linux/arch/alpha/kernel/entry.S Wed Feb 26 13:34:09 1997 @@ -123,7 +123,7 @@ SAVE_ALL /* start atomic operation with respect to software interrupts */ lda $0,intr_count - ldq $1,0($0) + ldl $1,0($0) addq $1,1,$1 stq $1,0($0) /* set up the arguments to the C interrupt handler */ @@ -131,7 +131,7 @@ jsr $26,do_entInt /* ok, return */ lda $0,intr_count - ldq $1,0($0) + ldl $1,0($0) subq $1,1,$1 stq $1,0($0) br $31,ret_from_sys_call @@ -527,7 +527,7 @@ cmovne $26,0,$19 /* $19 = 0 => non-restartable */ /* check bottom half interrupts */ lda $0,intr_count - ldq $1,0($0) + ldl $1,0($0) bne $1,ret_from_handle_bh lda $2,bh_active ldq $3,0($2) @@ -622,7 +622,7 @@ * We're called with $0 containing the address of * 'intr_count' and $1 containing 'intr_count+1' */ - stq $1,0($0) /* intr_count = 1 */ + stl $1,0($0) /* intr_count = 1 */ subq $30,16,$30 stq $19,0($30) /* save syscall nr */ stq $20,8($30) /* and error indication (a3) */ @@ -631,7 +631,7 @@ ldq $19,0($30) ldq $20,8($30) addq $30,16,$30 - stq $31,0($0) /* intr_count = 0 */ + stl $31,0($0) /* intr_count = 0 */ br $31,ret_from_handle_bh .align 3 diff -u --recursive --new-file v2.1.26/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.1.26/linux/arch/i386/defconfig Fri Feb 7 06:49:49 1997 +++ linux/arch/i386/defconfig Fri Feb 21 15:32:54 1997 @@ -26,8 +26,8 @@ CONFIG_BINFMT_ELF=y # CONFIG_M386 is not set # CONFIG_M486 is not set -CONFIG_M586=y -# CONFIG_M686 is not set +# CONFIG_M586 is not set +CONFIG_M686=y # CONFIG_VIDEO_SELECT is not set # @@ -48,7 +48,7 @@ CONFIG_BLK_DEV_CMD640=y # CONFIG_BLK_DEV_CMD640_ENHANCED is not set CONFIG_BLK_DEV_RZ1000=y -# CONFIG_BLK_DEV_TRITON is not set +CONFIG_BLK_DEV_TRITON=y # CONFIG_IDE_CHIPSETS is not set # @@ -92,7 +92,51 @@ # # SCSI support # -# CONFIG_SCSI is not set +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +CONFIG_SCSI_BUSLOGIC=y +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set # # Network device support @@ -102,15 +146,16 @@ CONFIG_DUMMY=m # CONFIG_EQUALIZER is not set CONFIG_NET_ETHERNET=y -CONFIG_NET_VENDOR_3COM=y -# CONFIG_EL1 is not set -# CONFIG_EL2 is not set -CONFIG_EL3=y -# CONFIG_VORTEX is not set +# CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_ISA is not set -# CONFIG_NET_EISA is not set +CONFIG_NET_EISA=y +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_DE4X5=y +# CONFIG_DEC_ELCP is not set +# CONFIG_DGRS is not set # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set # CONFIG_DLCI is not set @@ -139,7 +184,7 @@ CONFIG_EXT2_FS=y CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y -# CONFIG_VFAT_FS is not set +CONFIG_VFAT_FS=y # CONFIG_UMSDOS_FS is not set CONFIG_PROC_FS=y CONFIG_NFS_FS=y @@ -162,7 +207,12 @@ # CONFIG_RISCOM8 is not set # CONFIG_ESPSERIAL is not set # CONFIG_PRINTER is not set -# CONFIG_MOUSE is not set +CONFIG_MOUSE=y +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_BUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set +CONFIG_PSMOUSE=y +CONFIG_82C710_MOUSE=y # CONFIG_UMISC is not set # CONFIG_QIC02_TAPE is not set # CONFIG_FTAPE is not set diff -u --recursive --new-file v2.1.26/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.1.26/linux/arch/i386/kernel/entry.S Sun Jan 26 02:07:04 1997 +++ linux/arch/i386/kernel/entry.S Wed Feb 26 13:22:32 1997 @@ -163,7 +163,7 @@ ALIGN handle_bottom_half: - pushl $9f + pushl $2f jmp SYMBOL_NAME(do_bottom_half) ALIGN @@ -183,14 +183,20 @@ movl %eax,EAX(%esp) # save the return value ALIGN .globl ret_from_sys_call + .globl ret_from_intr +ret_from_intr: ret_from_sys_call: GET_CURRENT(%ebx) cmpl $0,SYMBOL_NAME(intr_count) +#ifdef __SMP__ + jne 2f +#else jne 1f +#endif 9: movl SYMBOL_NAME(bh_mask),%eax andl SYMBOL_NAME(bh_active),%eax jne handle_bottom_half - movl EFLAGS(%esp),%eax # mix EFLAGS and CS +2: movl EFLAGS(%esp),%eax # mix EFLAGS and CS movb CS(%esp),%al testl $(VM_MASK | 3),%eax # return to VM86 mode or non-supervisor? je 1f @@ -201,7 +207,8 @@ notl %eax andl signal(%ebx),%eax jne signal_return -1: RESTORE_ALL +1: + RESTORE_ALL ALIGN signal_return: testl $(VM_MASK),EFLAGS(%esp) diff -u --recursive --new-file v2.1.26/linux/arch/i386/kernel/sys_i386.c linux/arch/i386/kernel/sys_i386.c --- v2.1.26/linux/arch/i386/kernel/sys_i386.c Fri Feb 7 05:54:53 1997 +++ linux/arch/i386/kernel/sys_i386.c Tue Feb 25 13:36:08 1997 @@ -88,14 +88,11 @@ asmlinkage int old_select(struct sel_arg_struct *arg) { struct sel_arg_struct a; - int ret; if (copy_from_user(&a, arg, sizeof(a))) return -EFAULT; - lock_kernel(); - ret = sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); - unlock_kernel(); - return ret; + /* sys_select() does the appropriate kernel locking */ + return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); } /* diff -u --recursive --new-file v2.1.26/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c --- v2.1.26/linux/arch/i386/kernel/time.c Fri Feb 7 05:54:54 1997 +++ linux/arch/i386/kernel/time.c Fri Feb 21 14:58:32 1997 @@ -33,6 +33,10 @@ #include extern int setup_x86_irq(int, struct irqaction *); +extern volatile unsigned long lost_ticks; + +/* change this if you have some constant time drift */ +#define USECS_PER_JIFFY (1000020/HZ) #ifndef CONFIG_APM /* cycle counter may be unreliable */ /* Cycle counter value at the previous timer interrupt.. */ @@ -40,11 +44,6 @@ unsigned long low; unsigned long high; } init_timer_cc, last_timer_cc; - -extern volatile unsigned long lost_ticks; - -/* change this if you have some constant time drift */ -#define USECS_PER_JIFFY (1000020/HZ) static unsigned long do_fast_gettimeoffset(void) { diff -u --recursive --new-file v2.1.26/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c --- v2.1.26/linux/arch/i386/kernel/vm86.c Sun Feb 2 05:18:30 1997 +++ linux/arch/i386/kernel/vm86.c Tue Feb 25 12:19:18 1997 @@ -434,10 +434,10 @@ if ( (trapno==3) || (trapno==1) ) return_to_32bit(regs, VM86_TRAP + (trapno << 8)); do_int(regs, trapno, (unsigned char *) (regs->ss << 4), SP(regs)); - return 1; + return 0; } if (trapno !=1) - return 0; /* we let this handle by the calling routine */ + return 1; /* we let this handle by the calling routine */ if (current->flags & PF_PTRACED) current->blocked &= ~(1 << (SIGTRAP-1)); send_sig(SIGTRAP, current, 1); diff -u --recursive --new-file v2.1.26/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.1.26/linux/drivers/block/ll_rw_blk.c Mon Dec 23 00:13:53 1996 +++ linux/drivers/block/ll_rw_blk.c Wed Feb 26 11:10:36 1997 @@ -585,7 +585,7 @@ for (; j < 8 && i < nb; j++, i++, buf += buffersize) { rdev = dev; - rsector = (b[i] * buffersize) >> 9; + rsector = b[i] * (buffersize >> 9); #ifdef CONFIG_BLK_DEV_MD if (major==MD_MAJOR && md_map (MINOR(dev), &rdev, diff -u --recursive --new-file v2.1.26/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.1.26/linux/drivers/char/lp.c Sun Jan 26 02:07:16 1997 +++ linux/drivers/char/lp.c Fri Feb 21 14:58:33 1997 @@ -8,6 +8,7 @@ * LPCAREFUL, LPABORT, LPGETSTATUS added by Chris Metcalf, metcalf@lcs.mit.edu * Statistics and support for slow printers by Rob Janssen, rob@knoware.nl * "lp=" command line parameters added by Grant Guenther, grant@torque.net + * lp_read (Status readback) support added by Carsten Gross, carsten@sol.wohnheim.uni-ulm.de */ #include @@ -316,6 +317,116 @@ return -ESPIPE; } +/* Test if nibble mode for status readback is okay. + * returns false if not, otherwise true + */ +static int lp_nibble_mode_ok(int minor) +{ + int reply=1; + + outb_p(0, LP_B(minor)); /* Request "nibble mode" */ + udelay(LP_DELAY); + outb((inb(LP_C(minor)) & ~8), LP_C(minor)); /* SelectIN low */ + outb((inb(LP_C(minor)) | 2), LP_C(minor)); /* AutoFeed high */ + udelay(LP_DELAY); + outb((inb(LP_C(minor)) | 1), LP_C(minor)); /* Strobe high */ + if (( LP_S(minor) & ~0x80) != 0x38) reply=0; /* expected answer? */ + outb((inb(LP_C(minor)) & ~1 ), LP_C(minor)); /* Strobe low */ + outb((inb(LP_C(minor)) & ~2 ), LP_C(minor)); /* Autofeed low */ + udelay(LP_DELAY); + return(reply); +} + + +static int lp_read_nibble(int minor) +{ + unsigned char i; + i=LP_S(minor)>>3; + i&=~8; + if ( ( i & 0x10) == 0) i|=8; + return(i & 0x0f); +} + +static void lp_select_in_high(int minor) { + outb((inb(LP_C(minor)) | 8), LP_C(minor)); +} + +/* Status readback confirming to ieee1284 */ +static long lp_read(struct inode * inode, struct file * file, + char * buf, unsigned long count) +{ + unsigned char z=0, Byte=0, status; + char *temp; + int retval; + unsigned int counter=0; + unsigned int i; + unsigned int minor=MINOR(inode->i_rdev); + + temp=buf; +#ifdef LP_READ_DEBUG + printk(KERN_INFO "lp%d: read mode\n", minor); +#endif + + retval = verify_area(VERIFY_WRITE, buf, count); + if (retval) + return retval; + if (lp_nibble_mode_ok(minor)==0) { + lp_select_in_high(minor); + return temp-buf; /* End of file */ + } + for (i=0; i<=(count*2); i++) { + outb((inb(LP_C(minor)) | 2), LP_C(minor)); /* AutoFeed high */ + do { + status=(LP_S(minor) & 0x40); + udelay(50); + counter++; + if (need_resched) + schedule(); + } while ( (status == 0x40) && (counter < 20) ); + if ( counter == 20 ) { /* Timeout */ +#ifdef LP_READ_DEBUG + printk(KERN_DEBUG "lp_read: (Autofeed high) timeout\n"); +#endif + outb((inb(LP_C(minor)) & ~2), LP_C(minor)); + lp_select_in_high(minor); + return temp-buf; /* end the read at timeout */ + } + counter=0; + z=lp_read_nibble(minor); + outb((inb(LP_C(minor)) & ~2), LP_C(minor)); /* AutoFeed low */ + do { + status=(LP_S(minor) & 0x40); + udelay(20); + counter++; + if (need_resched) + schedule(); + } while ( (status == 0) && (counter < 20) ); + if (counter == 20) { /* Timeout */ +#ifdef LP_READ_DEBUG + printk(KERN_DEBUG "lp_read: (Autofeed low) timeout\n"); +#endif + if (current->signal & ~current->blocked) { + lp_select_in_high(minor); + if (temp !=buf) + return temp-buf; + else + return -EINTR; + } + current->state=TASK_INTERRUPTIBLE; + current->timeout=jiffies + LP_TIME(minor); + schedule(); + } + counter=0; + if (( i & 1) != 0) { + Byte= (Byte | z<<4); + put_user(Byte, temp); + temp++; + } else Byte=z; + } + lp_select_in_high(minor); + return temp-buf; +} + static int lp_open(struct inode * inode, struct file * file) { unsigned int minor = MINOR(inode->i_rdev); @@ -524,7 +635,7 @@ static struct file_operations lp_fops = { lp_lseek, - NULL, /* lp_read */ + lp_read, lp_write, NULL, /* lp_readdir */ NULL, /* lp_poll */ diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/Config.in linux/drivers/isdn/Config.in --- v2.1.26/linux/drivers/isdn/Config.in Sun May 19 05:29:29 1996 +++ linux/drivers/isdn/Config.in Tue Feb 25 17:12:49 1997 @@ -12,3 +12,16 @@ dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN dep_tristate 'Teles/NICCY1016PC/Creatix support' CONFIG_ISDN_DRV_TELES $CONFIG_ISDN +dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN +if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then + 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 AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1 + bool 'HiSax Support for Elsa cards' CONFIG_HISAX_ELSA_PCC + bool 'HiSax Support for ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2 + bool 'HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO + bool 'HiSax Support for german 1TR6' CONFIG_HISAX_1TR6 +fi +if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then + dep_tristate 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN +fi diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/Makefile linux/drivers/isdn/Makefile --- v2.1.26/linux/drivers/isdn/Makefile Sun May 19 05:29:29 1996 +++ linux/drivers/isdn/Makefile Tue Feb 25 17:12:49 1997 @@ -1,6 +1,6 @@ SUB_DIRS := MOD_SUB_DIRS := -ALL_SUB_DIRS := icn teles pcbit +ALL_SUB_DIRS := icn teles pcbit hisax L_OBJS := LX_OBJS := @@ -13,8 +13,8 @@ ifeq ($(CONFIG_ISDN),y) L_TARGET := isdn.a - L_OBJS += isdn_net.o isdn_tty.o isdn_cards.o - LX_OBJS += isdn_common.o + L_OBJS += isdn_common.o isdn_net.o isdn_tty.o isdn_cards.o + LX_OBJS += isdn_syms.o ifdef CONFIG_ISDN_PPP L_OBJS += isdn_ppp.o endif @@ -25,8 +25,8 @@ ifeq ($(CONFIG_ISDN),m) M_OBJS += isdn.o O_TARGET += isdn.o - O_OBJS += isdn_net.o isdn_tty.o - OX_OBJS += isdn_common.o + O_OBJS += isdn_common.o isdn_net.o isdn_tty.o + OX_OBJS += isdn_syms.o ifdef CONFIG_ISDN_PPP O_OBJS += isdn_ppp.o endif @@ -46,6 +46,16 @@ endif endif +ifeq ($(CONFIG_ISDN_DRV_HISAX),y) + L_OBJS += hisax/hisax.o + SUB_DIRS += hisax + MOD_SUB_DIRS += hisax +else + ifeq ($(CONFIG_ISDN_DRV_HISAX),m) + MOD_SUB_DIRS += hisax + endif +endif + ifeq ($(CONFIG_ISDN_DRV_ICN),y) L_OBJS += icn/icn.o SUB_DIRS += icn @@ -63,6 +73,16 @@ else ifeq ($(CONFIG_ISDN_DRV_PCBIT),m) MOD_SUB_DIRS += pcbit + endif +endif + +ifeq ($(CONFIG_ISDN_DRV_SC),y) + L_OBJS += sc/sc.o + SUB_DIRS += sc + MOD_SUB_DIRS += sc +else + ifeq ($(CONFIG_ISDN_DRV_SC),m) + MOD_SUB_DIRS += sc endif endif diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/Makefile linux/drivers/isdn/hisax/Makefile --- v2.1.26/linux/drivers/isdn/hisax/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/Makefile Tue Feb 25 17:12:49 1997 @@ -0,0 +1,46 @@ +L_OBJS := +M_OBJS := +O_OBJS := isdnl1.o config.o buffers.o tei.o isdnl2.o isdnl3.o \ + q931.o callc.o fsm.o + +# EXTRA_CFLAGS += -S + +ifeq ($(CONFIG_HISAX_EURO),y) + O_OBJS += l3dss1.o +endif + +ifeq ($(CONFIG_HISAX_1TR6),y) + O_OBJS += l3_1tr6.o +endif + +ifeq ($(CONFIG_HISAX_16_0),y) + O_OBJS += teles0.o +endif + +ifeq ($(CONFIG_HISAX_16_3),y) + O_OBJS += teles3.o +endif + +ifeq ($(CONFIG_HISAX_AVM_A1),y) + O_OBJS += avm_a1.o +endif + +ifeq ($(CONFIG_HISAX_ELSA_PCC),y) + O_OBJS += elsa.o +endif + +ifeq ($(CONFIG_HISAX_IX1MICROR2),y) + O_OBJS += ix1_micro.o +endif + +O_TARGET := +ifeq ($(CONFIG_ISDN_DRV_HISAX),y) + O_TARGET += hisax.o +else + ifeq ($(CONFIG_ISDN_DRV_HISAX),m) + O_TARGET += hisax.o + M_OBJS += hisax.o + endif +endif + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/avm_a1.c linux/drivers/isdn/hisax/avm_a1.c --- v2.1.26/linux/drivers/isdn/hisax/avm_a1.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/avm_a1.c Tue Feb 25 17:12:49 1997 @@ -0,0 +1,982 @@ +/* $Id: avm_a1.c,v 1.4 1997/01/27 15:50:21 keil Exp $ + + * avm_a1.c low level stuff for AVM A1 (Fritz) isdn cards + * + * Author Karsten Keil (keil@temic-ech.spacenet.de) + * + * + * $Log: avm_a1.c,v $ + * Revision 1.4 1997/01/27 15:50:21 keil + * SMP proof,cosmetics + * + * Revision 1.3 1997/01/21 22:14:20 keil + * cleanups + * + * Revision 1.2 1996/10/27 22:07:31 keil + * cosmetic changes + * + * Revision 1.1 1996/10/13 20:04:49 keil + * Initial revision + * + * + */ +#define __NO_VERSION__ +#include "siemens.h" +#include "hisax.h" +#include "avm_a1.h" +#include "isdnl1.h" +#include + +extern const char *CardType[]; +const char *avm_revision = "$Revision: 1.4 $"; + +#define byteout(addr,val) outb_p(val,addr) +#define bytein(addr) inb_p(addr) + +static inline byte +readreg(unsigned int adr, byte off) +{ + return (bytein(adr + off)); +} + +static inline void +writereg(unsigned int adr, byte off, byte data) +{ + byteout(adr + off, data); +} + + +static inline void +read_fifo(unsigned int adr, byte * data, int size) +{ + insb(adr - 0x400, data, size); +} + +static void +write_fifo(unsigned int adr, byte * data, int size) +{ + outsb(adr - 0x400, data, size); +} + +static inline void +waitforCEC(int adr) +{ + int to = 50; + + while ((readreg(adr, HSCX_STAR) & 0x04) && to) { + udelay(1); + to--; + } + if (!to) + printk(KERN_WARNING "AVM A1: waitforCEC timeout\n"); +} + + +static inline void +waitforXFW(int adr) +{ + int to = 50; + + while ((!(readreg(adr, HSCX_STAR) & 0x44) == 0x40) && to) { + udelay(1); + to--; + } + if (!to) + printk(KERN_WARNING "AVM A1: waitforXFW timeout\n"); +} +static inline void +writehscxCMDR(int adr, byte data) +{ + long flags; + + save_flags(flags); + cli(); + waitforCEC(adr); + writereg(adr, HSCX_CMDR, data); + restore_flags(flags); +} + +/* + * fast interrupt here + */ + +static void +hscxreport(struct IsdnCardState *sp, int hscx) +{ + printk(KERN_DEBUG "HSCX %d\n", hscx); + printk(KERN_DEBUG "ISTA %x\n", readreg(sp->hscx[hscx], HSCX_ISTA)); + printk(KERN_DEBUG "STAR %x\n", readreg(sp->hscx[hscx], HSCX_STAR)); + printk(KERN_DEBUG "EXIR %x\n", readreg(sp->hscx[hscx], HSCX_EXIR)); +} + +void +avm_a1_report(struct IsdnCardState *sp) +{ + printk(KERN_DEBUG "ISAC\n"); + printk(KERN_DEBUG "ISTA %x\n", readreg(sp->isac, ISAC_ISTA)); + printk(KERN_DEBUG "STAR %x\n", readreg(sp->isac, ISAC_STAR)); + printk(KERN_DEBUG "EXIR %x\n", readreg(sp->isac, ISAC_EXIR)); + hscxreport(sp, 0); + hscxreport(sp, 1); +} + +/* + * HSCX stuff goes here + */ + +static void +hscx_empty_fifo(struct HscxState *hsp, int count) +{ + byte *ptr; + struct IsdnCardState *sp = hsp->sp; + struct BufHeader *ibh = hsp->rcvibh; + long flags; + + if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO)) + debugl1(sp, "hscx_empty_fifo"); + + if (hsp->rcvptr + count > BUFFER_SIZE(HSCX_RBUF_ORDER, + HSCX_RBUF_BPPS)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "hscx_empty_fifo: incoming packet too large"); + writehscxCMDR(sp->hscx[hsp->hscx], 0x80); + return; + } + ptr = DATAPTR(ibh); + ptr += hsp->rcvptr; + + hsp->rcvptr += count; + save_flags(flags); + cli(); + read_fifo(sp->hscx[hsp->hscx], ptr, count); + writehscxCMDR(sp->hscx[hsp->hscx], 0x80); + restore_flags(flags); + if (sp->debug & L1_DEB_HSCX_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "hscx_empty_fifo %c cnt %d", + hsp->hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static void +hscx_fill_fifo(struct HscxState *hsp) +{ + struct IsdnCardState *sp = hsp->sp; + struct BufHeader *ibh; + int more, count; + byte *ptr; + long flags; + + if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO)) + debugl1(sp, "hscx_fill_fifo"); + + ibh = hsp->xmtibh; + if (!ibh) + return; + + count = ibh->datasize - hsp->sendptr; + if (count <= 0) + return; + + more = (hsp->mode == 1) ? 1 : 0; + if (count > 32) { + more = !0; + count = 32; + } + ptr = DATAPTR(ibh); + ptr += hsp->sendptr; + hsp->sendptr += count; + + waitforXFW(sp->hscx[hsp->hscx]); + save_flags(flags); + cli(); + write_fifo(sp->hscx[hsp->hscx], ptr, count); + writehscxCMDR(sp->hscx[hsp->hscx], more ? 0x8 : 0xa); + restore_flags(flags); + if (sp->debug & L1_DEB_HSCX_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "hscx_fill_fifo %c cnt %d", + hsp->hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static inline void +hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx) +{ + byte r; + struct HscxState *hsp = sp->hs + hscx; + int count, err; + char tmp[32]; + + if (!hsp->init) + return; + + if (val & 0x80) { /* RME */ + + r = readreg(sp->hscx[hsp->hscx], HSCX_RSTA); + if ((r & 0xf0) != 0xa0) { + if (!r & 0x80) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX invalid frame"); + if ((r & 0x40) && hsp->mode) + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "HSCX RDO mode=%d", + hsp->mode); + debugl1(sp, tmp); + } + if (!r & 0x20) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX CRC error"); + if (hsp->rcvibh) + BufPoolRelease(hsp->rcvibh); + hsp->rcvibh = NULL; + writehscxCMDR(sp->hscx[hsp->hscx], 0x80); + goto afterRME; + } + if (!hsp->rcvibh) + if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool, + GFP_ATOMIC, (void *) 1, 1)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX RME out of buffers"); + writehscxCMDR(sp->hscx[hsp->hscx], 0x80); + goto afterRME; + } else + hsp->rcvptr = 0; + + count = readreg(sp->hscx[hsp->hscx], HSCX_RBCL) & 0x1f; + if (count == 0) + count = 32; + hscx_empty_fifo(hsp, count); + hsp->rcvibh->datasize = hsp->rcvptr - 1; + BufQueueLink(&hsp->rq, hsp->rcvibh); + hsp->rcvibh = NULL; + hscx_sched_event(hsp, HSCX_RCVBUFREADY); + } + afterRME: + if (val & 0x40) { /* RPF */ + if (!hsp->rcvibh) { + if (hsp->mode == 1) + err = BufPoolGet(&hsp->rcvibh, &hsp->smallpool, + GFP_ATOMIC, (void *) 1, 2); + else + err = BufPoolGet(&hsp->rcvibh, &hsp->rbufpool, + GFP_ATOMIC, (void *) 1, 2); + + if (err) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX RPF out of buffers"); + writehscxCMDR(sp->hscx[hsp->hscx], 0x80); + goto afterRPF; + } else + hsp->rcvptr = 0; + } + hscx_empty_fifo(hsp, 32); + if (hsp->mode == 1) { + /* receive audio data */ + hsp->rcvibh->datasize = hsp->rcvptr; + BufQueueLink(&hsp->rq, hsp->rcvibh); + hsp->rcvibh = NULL; + hscx_sched_event(hsp, HSCX_RCVBUFREADY); + } + } + afterRPF: + if (val & 0x10) { /* XPR */ + if (hsp->xmtibh) + if (hsp->xmtibh->datasize > hsp->sendptr) { + hscx_fill_fifo(hsp); + goto afterXPR; + } else { + if (hsp->releasebuf) + BufPoolRelease(hsp->xmtibh); + hsp->sendptr = 0; + if (hsp->st->l4.l1writewakeup) + hsp->st->l4.l1writewakeup(hsp->st); + hsp->xmtibh = NULL; + } + if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) { + hsp->releasebuf = !0; + hscx_fill_fifo(hsp); + } else + hscx_sched_event(hsp, HSCX_XMTBUFREADY); + } + afterXPR: +} + +/* + * ISAC stuff goes here + */ + +static void +isac_empty_fifo(struct IsdnCardState *sp, int count) +{ + byte *ptr; + struct BufHeader *ibh = sp->rcvibh; + long flags; + + if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO)) + if (sp->debug & L1_DEB_ISAC) + debugl1(sp, "isac_empty_fifo"); + + if (sp->rcvptr >= 3072) { + if (sp->debug & L1_DEB_WARN) { + char tmp[40]; + sprintf(tmp, "isac_empty_fifo rcvptr %d", sp->rcvptr); + debugl1(sp, tmp); + } + return; + } + ptr = DATAPTR(ibh); + ptr += sp->rcvptr; + sp->rcvptr += count; + + save_flags(flags); + cli(); + read_fifo(sp->isac, ptr, count); + writereg(sp->isac, ISAC_CMDR, 0x80); + restore_flags(flags); + if (sp->debug & L1_DEB_ISAC_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "isac_empty_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static void +isac_fill_fifo(struct IsdnCardState *sp) +{ + struct BufHeader *ibh; + int count, more; + byte *ptr; + long flags; + + if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO)) + debugl1(sp, "isac_fill_fifo"); + + ibh = sp->xmtibh; + if (!ibh) + return; + + count = ibh->datasize - sp->sendptr; + if (count <= 0) + return; + if (count >= 3072) + return; + + more = 0; + if (count > 32) { + more = !0; + count = 32; + } + ptr = DATAPTR(ibh); + ptr += sp->sendptr; + sp->sendptr += count; + + save_flags(flags); + cli(); + write_fifo(sp->isac, ptr, count); + writereg(sp->isac, ISAC_CMDR, more ? 0x8 : 0xa); + restore_flags(flags); + if (sp->debug & L1_DEB_ISAC_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "isac_fill_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static void +ph_command(struct IsdnCardState *sp, unsigned int command) +{ + if (sp->debug & L1_DEB_ISAC) { + char tmp[32]; + sprintf(tmp, "ph_command %d", command); + debugl1(sp, tmp); + } + writereg(sp->isac, ISAC_CIX0, (command << 2) | 3); +} + + +static inline void +isac_interrupt(struct IsdnCardState *sp, byte val) +{ + byte exval; + unsigned int count; + char tmp[32]; + + if (sp->debug & L1_DEB_ISAC) { + sprintf(tmp, "ISAC interrupt %x", val); + debugl1(sp, tmp); + } + if (val & 0x80) { /* RME */ + exval = readreg(sp->isac, ISAC_RSTA); + if ((exval & 0x70) != 0x20) { + if (exval & 0x40) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RDO"); + if (!exval & 0x20) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC CRC error"); + if (sp->rcvibh) + BufPoolRelease(sp->rcvibh); + sp->rcvibh = NULL; + writereg(sp->isac, ISAC_CMDR, 0x80); + goto afterRME; + } + if (!sp->rcvibh) + if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool), + GFP_ATOMIC, (void *) 1, 3)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RME out of buffers!"); + writereg(sp->isac, ISAC_CMDR, 0x80); + goto afterRME; + } else + sp->rcvptr = 0; + count = readreg(sp->isac, ISAC_RBCL) & 0x1f; + if (count == 0) + count = 32; + isac_empty_fifo(sp, count); + sp->rcvibh->datasize = sp->rcvptr; + BufQueueLink(&(sp->rq), sp->rcvibh); + sp->rcvibh = NULL; + isac_sched_event(sp, ISAC_RCVBUFREADY); + } + afterRME: + if (val & 0x40) { /* RPF */ + if (!sp->rcvibh) + if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool), + GFP_ATOMIC, (void *) 1, 4)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RME out of buffers!"); + writereg(sp->isac, ISAC_CMDR, 0x80); + goto afterRPF; + } else + sp->rcvptr = 0; + isac_empty_fifo(sp, 32); + } + afterRPF: + if (val & 0x20) { /* RSC */ + /* never */ + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RSC interrupt"); + } + if (val & 0x10) { /* XPR */ + if (sp->xmtibh) + if (sp->xmtibh->datasize > sp->sendptr) { + isac_fill_fifo(sp); + goto afterXPR; + } else { + if (sp->releasebuf) + BufPoolRelease(sp->xmtibh); + sp->xmtibh = NULL; + sp->sendptr = 0; + } + if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) { + sp->releasebuf = !0; + isac_fill_fifo(sp); + } else + isac_sched_event(sp, ISAC_XMTBUFREADY); + } + afterXPR: + if (val & 0x04) { /* CISQ */ + sp->ph_state = (readreg(sp->isac, ISAC_CIX0) >> 2) + & 0xf; + if (sp->debug & L1_DEB_ISAC) { + sprintf(tmp, "l1state %d", sp->ph_state); + debugl1(sp, tmp); + } + isac_new_ph(sp); + } + if (val & 0x02) { /* SIN */ + /* never */ + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC SIN interrupt"); + } + if (val & 0x01) { /* EXI */ + exval = readreg(sp->isac, ISAC_EXIR); + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "ISAC EXIR %02x", exval); + debugl1(sp, tmp); + } + } +} + +static inline void +hscx_int_main(struct IsdnCardState *sp, byte val) +{ + + byte exval; + struct HscxState *hsp; + char tmp[32]; + + + if (val & 0x01) { + hsp = sp->hs + 1; + exval = readreg(sp->hscx[1], HSCX_EXIR); + if (exval == 0x40) { + if (hsp->mode == 1) + hscx_fill_fifo(hsp); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + hsp->sendptr = 0; + writehscxCMDR(sp->hscx[hsp->hscx], 0x01); + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "HSCX B EXIR %x Lost TX", exval); + debugl1(sp, tmp); + } + } + } else if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX B EXIR %x", exval); + debugl1(sp, tmp); + } + } + if (val & 0xf8) { + if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX B interrupt %x", val); + debugl1(sp, tmp); + } + hscx_interrupt(sp, val, 1); + } + if (val & 0x02) { + hsp = sp->hs; + exval = readreg(sp->hscx[0], HSCX_EXIR); + if (exval == 0x40) { + if (hsp->mode == 1) + hscx_fill_fifo(hsp); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + hsp->sendptr = 0; + writehscxCMDR(sp->hscx[hsp->hscx], 0x01); + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "HSCX A EXIR %x Lost TX", exval); + debugl1(sp, tmp); + } + } + } else if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX A EXIR %x", exval); + debugl1(sp, tmp); + } + } + if (val & 0x04) { + exval = readreg(sp->hscx[0], HSCX_ISTA); + if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX A interrupt %x", exval); + debugl1(sp, tmp); + } + hscx_interrupt(sp, exval, 0); + } +} + +static void +avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *sp; + byte val, sval, stat = 0; + char tmp[32]; + + sp = (struct IsdnCardState *) irq2dev_map[intno]; + + if (!sp) { + printk(KERN_WARNING "AVM A1: Spurious interrupt!\n"); + return; + } + while (((sval = bytein(sp->cfg_reg)) & 0xf) != 0x7) { + if (!(sval & AVM_A1_STAT_TIMER)) { + byteout(sp->cfg_reg, 0x14); + byteout(sp->cfg_reg, 0x18); + sval = bytein(sp->cfg_reg); + } else if (sp->debug & L1_DEB_INTSTAT) { + sprintf(tmp, "avm IntStatus %x", sval); + debugl1(sp, tmp); + } + if (!(sval & AVM_A1_STAT_HSCX)) { + val = readreg(sp->hscx[1], HSCX_ISTA); + if (val) { + hscx_int_main(sp, val); + stat |= 1; + } + } + if (!(sval & AVM_A1_STAT_ISAC)) { + val = readreg(sp->isac, ISAC_ISTA); + if (val) { + isac_interrupt(sp, val); + stat |= 2; + } + } + } + if (stat & 1) { + writereg(sp->hscx[0], HSCX_MASK, 0xFF); + writereg(sp->hscx[1], HSCX_MASK, 0xFF); + writereg(sp->hscx[0], HSCX_MASK, 0x0); + writereg(sp->hscx[1], HSCX_MASK, 0x0); + } + if (stat & 2) { + writereg(sp->isac, ISAC_MASK, 0xFF); + writereg(sp->isac, ISAC_MASK, 0x0); + } +} + + +static void +initisac(struct IsdnCardState *sp) +{ + unsigned int adr = sp->isac; + + /* 16.3 IOM 2 Mode */ + writereg(adr, ISAC_MASK, 0xff); + writereg(adr, ISAC_ADF2, 0x80); + writereg(adr, ISAC_SQXR, 0x2f); + writereg(adr, ISAC_SPCR, 0x0); + writereg(adr, ISAC_ADF1, 0x2); + writereg(adr, ISAC_STCR, 0x70); + writereg(adr, ISAC_MODE, 0xc9); + writereg(adr, ISAC_TIMR, 0x0); + writereg(adr, ISAC_ADF1, 0x0); + writereg(adr, ISAC_CMDR, 0x41); + writereg(adr, ISAC_CIX0, (1 << 2) | 3); + writereg(adr, ISAC_MASK, 0xff); + writereg(adr, ISAC_MASK, 0x0); +} + +static void +modehscx(struct HscxState *hs, int mode, int ichan) +{ + struct IsdnCardState *sp = hs->sp; + int hscx = hs->hscx; + + if (sp->debug & L1_DEB_HSCX) { + char tmp[40]; + sprintf(tmp, "hscx %c mode %d ichan %d", + 'A' + hscx, mode, ichan); + debugl1(sp, tmp); + } + hs->mode = mode; + writereg(sp->hscx[hscx], HSCX_CCR1, 0x85); + writereg(sp->hscx[hscx], HSCX_XAD1, 0xFF); + writereg(sp->hscx[hscx], HSCX_XAD2, 0xFF); + writereg(sp->hscx[hscx], HSCX_RAH2, 0xFF); + writereg(sp->hscx[hscx], HSCX_XBCH, 0x0); + writereg(sp->hscx[hscx], HSCX_RLCR, 0x0); + + switch (mode) { + case (0): + writereg(sp->hscx[hscx], HSCX_CCR2, 0x30); + writereg(sp->hscx[hscx], HSCX_TSAX, 0xff); + writereg(sp->hscx[hscx], HSCX_TSAR, 0xff); + writereg(sp->hscx[hscx], HSCX_XCCR, 7); + writereg(sp->hscx[hscx], HSCX_RCCR, 7); + writereg(sp->hscx[hscx], HSCX_MODE, 0x84); + break; + case (1): + if (ichan == 0) { + writereg(sp->hscx[hscx], HSCX_CCR2, 0x30); + writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f); + writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f); + writereg(sp->hscx[hscx], HSCX_XCCR, 7); + writereg(sp->hscx[hscx], HSCX_RCCR, 7); + } else { + writereg(sp->hscx[hscx], HSCX_CCR2, 0x30); + writereg(sp->hscx[hscx], HSCX_TSAX, 0x3); + writereg(sp->hscx[hscx], HSCX_TSAR, 0x3); + writereg(sp->hscx[hscx], HSCX_XCCR, 7); + writereg(sp->hscx[hscx], HSCX_RCCR, 7); + } + writereg(sp->hscx[hscx], HSCX_MODE, 0xe4); + writereg(sp->hscx[hscx], HSCX_CMDR, 0x41); + break; + case (2): + if (ichan == 0) { + writereg(sp->hscx[hscx], HSCX_CCR2, 0x30); + writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f); + writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f); + writereg(sp->hscx[hscx], HSCX_XCCR, 7); + writereg(sp->hscx[hscx], HSCX_RCCR, 7); + } else { + writereg(sp->hscx[hscx], HSCX_CCR2, 0x30); + writereg(sp->hscx[hscx], HSCX_TSAX, 0x3); + writereg(sp->hscx[hscx], HSCX_TSAR, 0x3); + writereg(sp->hscx[hscx], HSCX_XCCR, 7); + writereg(sp->hscx[hscx], HSCX_RCCR, 7); + } + writereg(sp->hscx[hscx], HSCX_MODE, 0x8c); + writereg(sp->hscx[hscx], HSCX_CMDR, 0x41); + break; + } + writereg(sp->hscx[hscx], HSCX_ISTA, 0x00); +} + +inline static void +release_ioregs(struct IsdnCard *card, int mask) +{ + release_region(card->sp->cfg_reg, 8); + if (mask & 1) + release_region(card->sp->isac, 32); + if (mask & 2) + release_region(card->sp->isac - 0x400, 1); + if (mask & 4) + release_region(card->sp->hscx[0], 32); + if (mask & 8) + release_region(card->sp->hscx[0] - 0x400, 1); + if (mask & 0x10) + release_region(card->sp->hscx[1], 32); + if (mask & 0x20) + release_region(card->sp->hscx[1] - 0x400, 1); +} + +void +release_io_avm_a1(struct IsdnCard *card) +{ + release_ioregs(card, 0x3f); +} + +static void +clear_pending_ints(struct IsdnCardState *sp) +{ + int val; + char tmp[64]; + + val = readreg(sp->hscx[1], HSCX_ISTA); + sprintf(tmp, "HSCX B ISTA %x", val); + debugl1(sp, tmp); + if (val & 0x01) { + val = readreg(sp->hscx[1], HSCX_EXIR); + sprintf(tmp, "HSCX B EXIR %x", val); + debugl1(sp, tmp); + } else if (val & 0x02) { + val = readreg(sp->hscx[0], HSCX_EXIR); + sprintf(tmp, "HSCX A EXIR %x", val); + debugl1(sp, tmp); + } + val = readreg(sp->hscx[0], HSCX_ISTA); + sprintf(tmp, "HSCX A ISTA %x", val); + debugl1(sp, tmp); + val = readreg(sp->hscx[1], HSCX_STAR); + sprintf(tmp, "HSCX B STAR %x", val); + debugl1(sp, tmp); + val = readreg(sp->hscx[0], HSCX_STAR); + sprintf(tmp, "HSCX A STAR %x", val); + debugl1(sp, tmp); + val = readreg(sp->isac, ISAC_STAR); + sprintf(tmp, "ISAC STAR %x", val); + debugl1(sp, tmp); + val = readreg(sp->isac, ISAC_MODE); + sprintf(tmp, "ISAC MODE %x", val); + debugl1(sp, tmp); + val = readreg(sp->isac, ISAC_ADF2); + sprintf(tmp, "ISAC ADF2 %x", val); + debugl1(sp, tmp); + val = readreg(sp->isac, ISAC_ISTA); + sprintf(tmp, "ISAC ISTA %x", val); + debugl1(sp, tmp); + if (val & 0x01) { + val = readreg(sp->isac, ISAC_EXIR); + sprintf(tmp, "ISAC EXIR %x", val); + debugl1(sp, tmp); + } else if (val & 0x04) { + val = readreg(sp->isac, ISAC_CIR0); + sprintf(tmp, "ISAC CIR0 %x", val); + debugl1(sp, tmp); + } + writereg(sp->isac, ISAC_MASK, 0); + writereg(sp->isac, ISAC_CMDR, 0x41); +} + +int +initavm_a1(struct IsdnCardState *sp) +{ + int ret; + char tmp[40]; + + sp->counter = kstat.interrupts[sp->irq]; + sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter); + debugl1(sp, tmp); + clear_pending_ints(sp); + ret = get_irq(sp->cardnr, &avm_a1_interrupt); + if (ret) { + initisac(sp); + sp->modehscx(sp->hs, 0, 0); + sp->modehscx(sp->hs + 1, 0, 0); + sprintf(tmp, "IRQ %d count %d", sp->irq, + kstat.interrupts[sp->irq]); + debugl1(sp, tmp); + if (kstat.interrupts[sp->irq] == sp->counter) { + printk(KERN_WARNING + "AVM A1: IRQ(%d) getting no interrupts during init\n", + sp->irq); + irq2dev_map[sp->irq] = NULL; + free_irq(sp->irq, NULL); + return (0); + } + } + return (ret); +} + +int +setup_avm_a1(struct IsdnCard *card) +{ + byte val, verA, verB; + struct IsdnCardState *sp = card->sp; + long flags; + char tmp[64]; + + strcpy(tmp, avm_revision); + printk(KERN_NOTICE "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp)); + if (sp->typ != ISDN_CTYPE_A1) + return (0); + + sp->cfg_reg = card->para[1] + 0x1800; + sp->isac = card->para[1] + 0x1400; + sp->hscx[0] = card->para[1] + 0x400; + sp->hscx[1] = card->para[1] + 0xc00; + sp->irq = card->para[0]; + if (check_region((sp->cfg_reg), 8)) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + sp->cfg_reg, + sp->cfg_reg + 8); + return (0); + } else { + request_region(sp->cfg_reg, 8, "avm cfg"); + } + if (check_region((sp->isac), 32)) { + printk(KERN_WARNING + "HiSax: %s isac ports %x-%x already in use\n", + CardType[sp->typ], + sp->isac, + sp->isac + 32); + release_ioregs(card, 0); + return (0); + } else { + request_region(sp->isac, 32, "HiSax isac"); + } + if (check_region((sp->isac - 0x400), 1)) { + printk(KERN_WARNING + "HiSax: %s isac fifo port %x already in use\n", + CardType[sp->typ], + sp->isac - 0x400); + release_ioregs(card, 1); + return (0); + } else { + request_region(sp->isac - 0x400, 1, "HiSax isac fifo"); + } + if (check_region((sp->hscx[0]), 32)) { + printk(KERN_WARNING + "HiSax: %s hscx A ports %x-%x already in use\n", + CardType[sp->typ], + sp->hscx[0], + sp->hscx[0] + 32); + release_ioregs(card, 3); + return (0); + } else { + request_region(sp->hscx[0], 32, "HiSax hscx A"); + } + if (check_region((sp->hscx[0] - 0x400), 1)) { + printk(KERN_WARNING + "HiSax: %s hscx A fifo port %x already in use\n", + CardType[sp->typ], + sp->hscx[0] - 0x400); + release_ioregs(card, 7); + return (0); + } else { + request_region(sp->hscx[0] - 0x400, 1, "HiSax hscx A fifo"); + } + if (check_region((sp->hscx[1]), 32)) { + printk(KERN_WARNING + "HiSax: %s hscx B ports %x-%x already in use\n", + CardType[sp->typ], + sp->hscx[1], + sp->hscx[1] + 32); + release_ioregs(card, 0xf); + return (0); + } else { + request_region(sp->hscx[1], 32, "HiSax hscx B"); + } + if (check_region((sp->hscx[1] - 0x400), 1)) { + printk(KERN_WARNING + "HiSax: %s hscx B fifo port %x already in use\n", + CardType[sp->typ], + sp->hscx[1] - 0x400); + release_ioregs(card, 0x1f); + return (0); + } else { + request_region(sp->hscx[1] - 0x400, 1, "HiSax hscx B fifo"); + } + save_flags(flags); + byteout(sp->cfg_reg, 0x0); + sti(); + HZDELAY(HZ / 5 + 1); + byteout(sp->cfg_reg, 0x1); + HZDELAY(HZ / 5 + 1); + byteout(sp->cfg_reg, 0x0); + HZDELAY(HZ / 5 + 1); + val = sp->irq; + if (val == 9) + val = 2; + byteout(sp->cfg_reg + 1, val); + HZDELAY(HZ / 5 + 1); + byteout(sp->cfg_reg, 0x0); + HZDELAY(HZ / 5 + 1); + restore_flags(flags); + + val = bytein(sp->cfg_reg); + printk(KERN_INFO "AVM A1: Byte at %x is %x\n", + sp->cfg_reg, val); + val = bytein(sp->cfg_reg + 3); + printk(KERN_INFO "AVM A1: Byte at %x is %x\n", + sp->cfg_reg + 3, val); + val = bytein(sp->cfg_reg + 2); + printk(KERN_INFO "AVM A1: Byte at %x is %x\n", + sp->cfg_reg + 2, val); + byteout(sp->cfg_reg, 0x14); + byteout(sp->cfg_reg, 0x18); + val = bytein(sp->cfg_reg); + printk(KERN_INFO "AVM A1: Byte at %x is %x\n", + sp->cfg_reg, val); + + printk(KERN_NOTICE + "HiSax: %s config irq:%d cfg:%x\n", + CardType[sp->typ], sp->irq, + sp->cfg_reg); + printk(KERN_NOTICE + "HiSax: isac:%x/%x\n", + sp->isac, sp->isac - 0x400); + printk(KERN_NOTICE + "HiSax: hscx A:%x/%x hscx B:%x/%x\n", + sp->hscx[0], sp->hscx[0] - 0x400, + sp->hscx[1], sp->hscx[1] - 0x400); + verA = readreg(sp->hscx[0], HSCX_VSTR) & 0xf; + verB = readreg(sp->hscx[1], HSCX_VSTR) & 0xf; + printk(KERN_INFO "AVM A1: HSCX version A: %s B: %s\n", + HscxVersion(verA), HscxVersion(verB)); + val = readreg(sp->isac, ISAC_RBCH); + printk(KERN_INFO "AVM A1: ISAC %s\n", + ISACVersion(val)); + if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) { + printk(KERN_WARNING + "AVM A1: wrong HSCX versions check IO address\n"); + release_io_avm_a1(card); + return (0); + } + sp->modehscx = &modehscx; + sp->ph_command = &ph_command; + sp->hscx_fill_fifo = &hscx_fill_fifo; + sp->isac_fill_fifo = &isac_fill_fifo; + return (1); +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/avm_a1.h linux/drivers/isdn/hisax/avm_a1.h --- v2.1.26/linux/drivers/isdn/hisax/avm_a1.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/avm_a1.h Tue Feb 25 17:12:49 1997 @@ -0,0 +1,25 @@ +/* $Id: avm_a1.h,v 1.2 1997/01/21 22:14:36 keil Exp $ + * + * avm_a1.h Header for AVM A1 (Fritz) ISDN card + * + * Author Karsten Keil (keil@temic-ech.spacenet.de) + * + * + * $Log: avm_a1.h,v $ + * Revision 1.2 1997/01/21 22:14:36 keil + * cleanups + * + * Revision 1.1 1996/10/12 21:42:40 keil + * Initial revision + * + * +*/ + +#define AVM_A1_STAT_ISAC 0x01 +#define AVM_A1_STAT_HSCX 0x02 +#define AVM_A1_STAT_TIMER 0x04 + +extern void avm_a1_report(struct IsdnCardState *sp); +extern void release_io_avm_a1(struct IsdnCard *card); +extern int setup_avm_a1(struct IsdnCard *card); +extern int initavm_a1(struct IsdnCardState *sp); diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/buffers.c linux/drivers/isdn/hisax/buffers.c --- v2.1.26/linux/drivers/isdn/hisax/buffers.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/buffers.c Tue Feb 25 17:12:49 1997 @@ -0,0 +1,326 @@ +/* $Id: buffers.c,v 1.1 1996/10/13 20:04:49 keil Exp $ + * + * Author Karsten Keil (keil@temic-ech.spacenet.de) + * based on the teles driver from Jan den Ouden + * + * Thanks to Jan den Ouden + * Fritz Elfert + * + * $Log: buffers.c,v $ + * Revision 1.1 1996/10/13 20:04:49 keil + * Initial revision + * + * + */ +#define __NO_VERSION__ +#include "hisax.h" +#include +#include + +#undef SMALLOC_DEBUG + +void +BufPoolInit(struct BufPool *bp, int order, int bpps, + int maxpages) +{ +#ifdef DEBUG_MAGIC + generateerror + bp->magic = 010167; +#endif + +#if 0 + printk(KERN_DEBUG "BufPoolInit bp %x\n", bp); +#endif + + bp->freelist = NULL; + bp->pageslist = NULL; + bp->pageorder = order; + bp->pagescount = 0; + bp->bpps = bpps; + bp->bufsize = BUFFER_SIZE(order, bpps); + bp->maxpages = maxpages; +} + +int +BufPoolAdd(struct BufPool *bp, int priority) +{ + struct Pages *ptr; + byte *bptr; + int i; + struct BufHeader *bh = NULL, *prev, *first; + +#if 0 + printk(KERN_DEBUG "BufPoolAdd bp %x\n", bp); +#endif + + ptr = (struct Pages *) __get_free_pages(priority, bp->pageorder, 0); + if (!ptr) { + printk(KERN_WARNING "BufPoolAdd couldn't get pages!\n"); + return (-1); + } +#if 0 + printk(KERN_DEBUG "Order %d pages allocated at %x\n", bp->pageorder, ptr); +#endif + + ptr->next = bp->pageslist; + bp->pageslist = ptr; + bp->pagescount++; + + bptr = (byte *) ptr + sizeof(struct Pages *); + + i = bp->bpps; + first = (struct BufHeader *) bptr; + prev = NULL; + while (i--) { + bh = (struct BufHeader *) bptr; +#ifdef DEBUG_MAGIC + bh->magic = 020167; +#endif + bh->next = prev; + prev = bh; + bh->bp = bp; + bptr += PART_SIZE(bp->pageorder, bp->bpps); + } + + first->next = bp->freelist; + bp->freelist = bh; + return (0); +} + +void +BufPoolFree(struct BufPool *bp) +{ + struct Pages *p; + +#if 0 + printk(KERN_DEBUG "BufPoolFree bp %x\n", bp); +#endif + + while (bp->pagescount--) { + p = bp->pageslist->next; + free_pages((unsigned long) bp->pageslist, bp->pageorder); +#if 0 + printk(KERN_DEBUG "Free pages %x order %d\n", bp->pageslist, bp->pageorder); +#endif + bp->pageslist = p; + } +} + +int +BufPoolGet(struct BufHeader **bh, + struct BufPool *bp, int priority, void *heldby, int where) +{ + long flags; + int i; + +#ifdef DEBUG_MAGIC + if (bp->magic != 010167) { + printk(KERN_DEBUG "BufPoolGet: not a BufHeader\n"); + return (-1); + } +#endif + + save_flags(flags); + cli(); + i = 0; + while (!0) { + if (bp->freelist) { + *bh = bp->freelist; + bp->freelist = bp->freelist->next; + (*bh)->heldby = heldby; + (*bh)->where = where; + restore_flags(flags); + return (0); + } + if ((i == 0) && (bp->pagescount < bp->maxpages)) { + if (BufPoolAdd(bp, priority)) { + restore_flags(flags); + return -1; + } + i++; + } else { + *bh = NULL; + restore_flags(flags); + return (-1); + } + } + +} + +void +BufPoolRelease(struct BufHeader *bh) +{ + struct BufPool *bp; + long flags; + +#ifdef DEBUG_MAGIC + if (bh->magic != 020167) { + printk(KERN_DEBUG "BufPoolRelease: not a BufHeader\n"); + printk(KERN_DEBUG "called from %x\n", __builtin_return_address(0)); + return; + } +#endif + + bp = bh->bp; + +#ifdef DEBUG_MAGIC + if (bp->magic != 010167) { + printk(KERN_DEBUG "BufPoolRelease: not a BufPool\n"); + return; + } +#endif + + save_flags(flags); + cli(); + bh->next = bp->freelist; + bp->freelist = bh; + restore_flags(flags); +} + +void +BufQueueLink(struct BufQueue *bq, + struct BufHeader *bh) +{ + unsigned long flags; + + save_flags(flags); + cli(); + if (!bq->head) + bq->head = bh; + if (bq->tail) + bq->tail->next = bh; + bq->tail = bh; + bh->next = NULL; + restore_flags(flags); +} + +void +BufQueueLinkFront(struct BufQueue *bq, + struct BufHeader *bh) +{ + unsigned long flags; + + save_flags(flags); + cli(); + bh->next = bq->head; + bq->head = bh; + if (!bq->tail) + bq->tail = bh; + restore_flags(flags); +} + +int +BufQueueUnlink(struct BufHeader **bh, struct BufQueue *bq) +{ + long flags; + + save_flags(flags); + cli(); + + if (bq->head) { + if (bq->tail == bq->head) + bq->tail = NULL; + *bh = bq->head; + bq->head = (*bh)->next; + restore_flags(flags); + return (0); + } else { + restore_flags(flags); + return (-1); + } +} + +void +BufQueueInit(struct BufQueue *bq) +{ +#ifdef DEBUG_MAGIC + bq->magic = 030167; +#endif + bq->head = NULL; + bq->tail = NULL; +} + +void +BufQueueRelease(struct BufQueue *bq) +{ + struct BufHeader *bh; + + while (bq->head) { + BufQueueUnlink(&bh, bq); + BufPoolRelease(bh); + } +} + +int +BufQueueLength(struct BufQueue *bq) +{ + int i = 0; + struct BufHeader *bh; + + bh = bq->head; + while (bh) { + i++; + bh = bh->next; + } + return (i); +} + +void +BufQueueDiscard(struct BufQueue *q, int pr, void *heldby, + int releasetoo) +{ + long flags; + struct BufHeader *sp; + + save_flags(flags); + cli(); + + while (!0) { + sp = q->head; + if (!sp) + break; + if ((sp->primitive == pr) && (sp->heldby == heldby)) { + q->head = sp->next; + if (q->tail == sp) + q->tail = NULL; + if (releasetoo) + BufPoolRelease(sp); + } else + break; + } + + sp = q->head; + if (sp) + while (sp->next) { + if ((sp->next->primitive == pr) && (sp->next->heldby == heldby)) { + if (q->tail == sp->next) + q->tail = sp; + if (releasetoo) + BufPoolRelease(sp->next); + sp->next = sp->next->next; + } else + sp = sp->next; + } + restore_flags(flags); +} + +void +Sfree(byte * ptr) +{ +#ifdef SMALLOC_DEBUG + printk(KERN_DEBUG "Sfree %x\n", (unsigned int)ptr); +#endif + kfree(ptr); +} + +byte * +Smalloc(int size, int pr, char *why) +{ + byte *p; + + p = (byte *) kmalloc(size, pr); +#ifdef SMALLOC_DEBUG + printk(KERN_DEBUG "Smalloc %s size %d res %x\n", why, size, (unsigned int)p); +#endif + return (p); +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/callc.c linux/drivers/isdn/hisax/callc.c --- v2.1.26/linux/drivers/isdn/hisax/callc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/callc.c Tue Feb 25 17:12:49 1997 @@ -0,0 +1,1946 @@ +/* $Id: callc.c,v 1.20 1997/02/17 00:32:47 keil Exp $ + + * Author Karsten Keil (keil@temic-ech.spacenet.de) + * based on the teles driver from Jan den Ouden + * + * Thanks to Jan den Ouden + * Fritz Elfert + * + * $Log: callc.c,v $ + * Revision 1.20 1997/02/17 00:32:47 keil + * Bugfix: No Busy reported to LL + * + * Revision 1.19 1997/02/14 12:23:10 fritz + * Added support for new insmod parameter handling. + * + * Revision 1.18 1997/02/11 01:36:58 keil + * Changed setup-interface (incoming and outgoing), cause reporting + * + * Revision 1.17 1997/02/09 00:23:10 keil + * new interface handling, one interface per card + * some changes in debug and leased line mode + * + * Revision 1.16 1997/01/27 23:17:03 keil + * delete timers while unloading + * + * Revision 1.15 1997/01/27 16:00:38 keil + * D-channel shutdown delay; improved callback + * + * Revision 1.14 1997/01/21 22:16:39 keil + * new statemachine; leased line support; cleanup for 2.0 + * + * Revision 1.13 1996/12/08 19:51:17 keil + * bugfixes from Pekka Sarnila + * + * Revision 1.12 1996/11/26 20:20:03 keil + * fixed warning while compile + * + * Revision 1.11 1996/11/26 18:43:17 keil + * change ioctl 555 --> 55 (555 didn't work) + * + * Revision 1.10 1996/11/26 18:06:07 keil + * fixed missing break statement,ioctl 555 reset modcount + * + * Revision 1.9 1996/11/18 20:23:19 keil + * log writebuf channel not open changed + * + * Revision 1.8 1996/11/06 17:43:17 keil + * more changes for 2.1.X;block fixed ST_PRO_W + * + * Revision 1.7 1996/11/06 15:13:51 keil + * typo 0x64 --->64 in debug code + * + * Revision 1.6 1996/11/05 19:40:33 keil + * X.75 windowsize + * + * Revision 1.5 1996/10/30 10:11:06 keil + * debugging LOCK changed;ST_REL_W EV_HANGUP added + * + * Revision 1.4 1996/10/27 22:20:16 keil + * alerting bugfixes + * no static b-channel<->channel mapping + * + * Revision 1.2 1996/10/16 21:29:45 keil + * compile bug as "not module" + * Callback with euro + * + * Revision 1.1 1996/10/13 20:04:50 keil + * Initial revision + * + */ + +#define __NO_VERSION__ +#include "hisax.h" + +#ifdef MODULE +#if (LINUX_VERSION_CODE < 0x020111) +extern long mod_use_count_; +#define MOD_USE_COUNT mod_use_count_ +#else +#define MOD_USE_COUNT ((&__this_module)->usecount) +#endif +#endif /* MODULE */ + +const char *l4_revision = "$Revision: 1.20 $"; + +extern struct IsdnCard cards[]; +extern int nrcards; +extern void HiSax_mod_dec_use_count(void); +extern void HiSax_mod_inc_use_count(void); + +static int init_ds(struct Channel *chanp, int incoming); +static void release_ds(struct Channel *chanp); + +static struct Fsm callcfsm = +{NULL, 0, 0}; +static struct Fsm lcfsm = +{NULL, 0, 0}; + +static int chancount = 0; + +/* Flags for remembering action done in l4 */ + +#define FLG_START_D 0x0001 +#define FLG_ESTAB_D 0x0002 +#define FLG_CALL_SEND 0x0004 +#define FLG_CALL_REC 0x0008 +#define FLG_CALL_ALERT 0x0010 +#define FLG_START_B 0x0020 +#define FLG_CONNECT_B 0x0040 +#define FLG_LL_DCONN 0x0080 +#define FLG_LL_BCONN 0x0100 +#define FLG_DISC_SEND 0x0200 +#define FLG_DISC_REC 0x0400 +#define FLG_REL_REC 0x0800 + +#define SETBIT(flg, item) flg |= item +#define RESBIT(flg, item) flg &= (~item) + +/* + * Because of callback it's a good idea to delay the shutdown of the d-channel + */ +#define DREL_TIMER_VALUE 30000 + +/* + * Find card with given driverId + */ +static inline struct IsdnCardState +* +hisax_findcard(int driverid) +{ + int i; + + for (i = 0; i < nrcards; i++) + if (cards[i].sp) + if (cards[i].sp->myid == driverid) + return (cards[i].sp); + return (struct IsdnCardState *) 0; +} + +static void +link_debug(struct Channel *chanp, char *s, int direction) +{ + char tmp[100], tm[32]; + + jiftime(tm, jiffies); + sprintf(tmp, "%s Channel %d %s %s\n", tm, chanp->chan, + direction ? "LL->HL" : "HL->LL", s); + HiSax_putstatus(chanp->sp, tmp); +} + + +enum { + ST_NULL, /* 0 inactive */ + ST_OUT_WAIT_D, /* 1 outgoing, awaiting d-channel establishment */ + ST_IN_WAIT_D, /* 2 incoming, awaiting d-channel establishment */ + ST_OUT_DIAL, /* 3 outgoing, SETUP send; awaiting confirm */ + ST_IN_WAIT_LL, /* 4 incoming call received; wait for LL confirm */ + ST_IN_ALERT_SEND, /* 5 incoming call received; ALERT send */ + ST_IN_WAIT_CONN_ACK, /* 6 incoming CONNECT send; awaiting CONN_ACK */ + ST_WAIT_BCONN, /* 7 CONNECT/CONN_ACK received, awaiting b-channel prot. estbl. */ + ST_ACTIVE, /* 8 active, b channel prot. established */ + ST_WAIT_BRELEASE, /* 9 call clear. (initiator), awaiting b channel prot. rel. */ + ST_WAIT_BREL_DISC, /* 10 call clear. (receiver), DISCONNECT req. received */ + ST_WAIT_DCOMMAND, /* 11 call clear. (receiver), awaiting DCHANNEL message */ + ST_WAIT_DRELEASE, /* 12 DISCONNECT sent, awaiting RELEASE */ + ST_WAIT_D_REL_CNF, /* 13 RELEASE sent, awaiting RELEASE confirm */ + ST_WAIT_DSHUTDOWN, /* 14 awaiting d-channel shutdown */ +}; + +#define STATE_COUNT (ST_WAIT_DSHUTDOWN +1) + +static char *strState[] = +{ + "ST_NULL", + "ST_OUT_WAIT_D", + "ST_IN_WAIT_D", + "ST_OUT_DIAL", + "ST_IN_WAIT_LL", + "ST_IN_ALERT_SEND", + "ST_IN_WAIT_CONN_ACK", + "ST_WAIT_BCONN", + "ST_ACTIVE", + "ST_WAIT_BRELEASE", + "ST_WAIT_BREL_DISC", + "ST_WAIT_DCOMMAND", + "ST_WAIT_DRELEASE", + "ST_WAIT_D_REL_CNF", + "ST_WAIT_DSHUTDOWN", +}; + +enum { + EV_DIAL, /* 0 */ + EV_SETUP_CNF, /* 1 */ + EV_ACCEPTB, /* 2 */ + EV_DISCONNECT_IND, /* 3 */ + EV_RELEASE_CNF, /* 4 */ + EV_DLEST, /* 5 */ + EV_DLRL, /* 6 */ + EV_SETUP_IND, /* 7 */ + EV_RELEASE_IND, /* 8 */ + EV_ACCEPTD, /* 9 */ + EV_SETUP_CMPL_IND, /* 10 */ + EV_BC_EST, /* 11 */ + EV_WRITEBUF, /* 12 */ + EV_DATAIN, /* 13 */ + EV_HANGUP, /* 14 */ + EV_BC_REL, /* 15 */ + EV_CINF, /* 16 */ + EV_SUSPEND, /* 17 */ + EV_RESUME, /* 18 */ + EV_SHUTDOWN_D, /* 19 */ + EV_NOSETUP_RSP, /* 20 */ + EV_SETUP_ERR, /* 21 */ + EV_CONNECT_ERR, /* 22 */ + EV_RELEASE_ERR, /* 23 */ +}; + +#define EVENT_COUNT (EV_RELEASE_ERR +1) + +static char *strEvent[] = +{ + "EV_DIAL", + "EV_SETUP_CNF", + "EV_ACCEPTB", + "EV_DISCONNECT_IND", + "EV_RELEASE_CNF", + "EV_DLEST", + "EV_DLRL", + "EV_SETUP_IND", + "EV_RELEASE_IND", + "EV_ACCEPTD", + "EV_SETUP_CMPL_IND", + "EV_BC_EST", + "EV_WRITEBUF", + "EV_DATAIN", + "EV_HANGUP", + "EV_BC_REL", + "EV_CINF", + "EV_SUSPEND", + "EV_RESUME", + "EV_SHUTDOWN_D", + "EV_NOSETUP_RSP", + "EV_SETUP_ERR", + "EV_CONNECT_ERR", + "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_FLUSH_DELAY, + 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_FLUSH_DELAY", + "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_FLUSH, + EV_LC_DL_RELEASE, + EV_LC_FLUSH, + 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_FLUSH", + "EV_LC_DL_RELEASE", + "EV_LC_FLUSH", + "EV_LC_RELEASE", +}; + +#define LC_D 0 +#define LC_B 1 + +static inline void +l4_deliver_cause(struct Channel *chanp) +{ + isdn_ctrl ic; + + if (chanp->para.cause<0) + return; + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_CAUSE; + ic.arg = chanp->chan; + if (chanp->sp->protocol == ISDN_PTYPE_EURO) + sprintf(ic.parm.num, "E%02X%02X", chanp->para.loc, + chanp->para.cause); + else + sprintf(ic.parm.num, "%02X%02X", chanp->para.loc, + chanp->para.cause); + chanp->sp->iif.statcallb(&ic); +} + +/* + * Dial out + */ +static void +l4_prep_dialout(struct FsmInst *fi, int event, void *arg) +{ + isdn_ctrl *ic = arg; + struct Channel *chanp = fi->userdata; + + FsmChangeState(fi, ST_OUT_WAIT_D); + FsmDelTimer(&chanp->drel_timer, 60); + FsmDelTimer(&chanp->dial_timer, 73); + chanp->para.setup = ic->parm.setup; + if (!strcmp(chanp->para.setup.eazmsn, "0")) + chanp->para.setup.eazmsn[0] = '\0'; + + 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 "l4_prep_dialout unknown protocol\n"); + break; + } + if (chanp->Flags & FLG_ESTAB_D) { + FsmEvent(fi, EV_DLEST, NULL); + } else { + chanp->Flags = FLG_START_D; + if (chanp->leased) { + chanp->lc_d.l2_establish = 0; + } + FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL); + } +} + +static void +l4_do_dialout(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + FsmChangeState(fi, ST_OUT_DIAL); + if (chanp->leased) { + chanp->para.bchannel = (chanp->chan & 1) + 1; + FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL); + } else { + SETBIT(chanp->Flags, FLG_ESTAB_D); + chanp->para.callref = chanp->outcallref; + chanp->outcallref++; + if (chanp->outcallref == 128) + chanp->outcallref = 64; + chanp->is.l4.l4l3(&chanp->is, CC_SETUP_REQ, NULL); + SETBIT(chanp->Flags, FLG_CALL_SEND); + } +} + +static void +l4_init_bchan_out(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + + FsmChangeState(fi, ST_WAIT_BCONN); + SETBIT(chanp->Flags, FLG_LL_DCONN); + if (chanp->debug & 1) + link_debug(chanp, "STAT_DCONN", 0); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_DCONN; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); + init_ds(chanp, 0); + SETBIT(chanp->Flags, FLG_START_B); + FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL); +} + +static void +l4_go_active(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + + FsmChangeState(fi, ST_ACTIVE); + chanp->data_open = !0; + SETBIT(chanp->Flags, FLG_CONNECT_B); + if (chanp->debug & 1) + link_debug(chanp, "STAT_BCONN", 0); + SETBIT(chanp->Flags, FLG_LL_BCONN); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_BCONN; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); +} + +/* incomming call */ + +static void +l4_start_dchan(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + FsmChangeState(fi, ST_IN_WAIT_D); + FsmDelTimer(&chanp->drel_timer, 61); + if (chanp->Flags & FLG_ESTAB_D) { + FsmEvent(fi, EV_DLEST, NULL); + } else { + chanp->Flags = FLG_START_D; + FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL); + } +} + +static void +l4_deliver_call(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + int ret; + char txt[32]; + + /* + * Report incoming calls only once to linklevel, use CallFlags + * which is set to 3 with each broadcast message in isdnl1.c + * and resetted if a interface answered the STAT_ICALL. + */ + if ((chanp->sp) && (chanp->sp->CallFlags == 3)) { + FsmChangeState(fi, ST_IN_WAIT_LL); + SETBIT(chanp->Flags, FLG_ESTAB_D); + SETBIT(chanp->Flags, FLG_CALL_REC); + if (chanp->debug & 1) + link_debug(chanp, "STAT_ICALL", 0); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_ICALL; + ic.arg = chanp->chan; + /* + * No need to return "unknown" for calls without OAD, + * cause that's handled in linklevel now (replaced by '0') + */ + ic.parm.setup = chanp->para.setup; + ret = chanp->sp->iif.statcallb(&ic); + if (chanp->debug & 1) { + sprintf(txt, "statcallb ret=%d", ret); + link_debug(chanp, txt, 1); + } + if (ret) /* if a interface knows this call, reset the CallFlag + * to avoid a second Call report to the linklevel + */ + chanp->sp->CallFlags &= ~(chanp->chan + 1); + switch (ret) { + case 1: /* OK, anybody likes this call */ + FsmChangeState(fi, ST_IN_ALERT_SEND); + SETBIT(chanp->Flags, FLG_CALL_ALERT); + chanp->is.l4.l4l3(&chanp->is, CC_ALERTING_REQ, NULL); + break; + case 2: /* Rejecting Call */ + RESBIT(chanp->Flags, FLG_CALL_REC); + break; + case 0: /* OK, nobody likes this call */ + default: /* statcallb problems */ + chanp->is.l4.l4l3(&chanp->is, CC_IGNORE, NULL); + FsmChangeState(fi, ST_NULL); + chanp->Flags = FLG_ESTAB_D; + FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 61); + break; + } + } else { + chanp->is.l4.l4l3(&chanp->is, CC_IGNORE, NULL); + FsmChangeState(fi, ST_NULL); + chanp->Flags = FLG_ESTAB_D; + FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 62); + } +} + +static void +l4_send_dconnect(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + FsmChangeState(fi, ST_IN_WAIT_CONN_ACK); + chanp->is.l4.l4l3(&chanp->is, CC_SETUP_RSP, NULL); +} + +static void +l4_init_bchan_in(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + + FsmChangeState(fi, ST_WAIT_BCONN); + SETBIT(chanp->Flags, FLG_LL_DCONN); + if (chanp->debug & 1) + link_debug(chanp, "STAT_DCONN", 0); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_DCONN; + ic.arg = chanp->chan; + chanp->sp->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 "r9 unknown protocol\n"); + break; + } + init_ds(chanp, !0); + SETBIT(chanp->Flags, FLG_START_B); + FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL); +} + +/* Call clearing */ + +static void +l4_reject_call(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + FsmChangeState(fi, ST_WAIT_DRELEASE); + chanp->para.cause = 0x15; /* Call Rejected */ + chanp->is.l4.l4l3(&chanp->is, CC_REJECT_REQ, NULL); + SETBIT(chanp->Flags, FLG_DISC_SEND); +} + +static void +l4_cancel_call(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + + FsmChangeState(fi, ST_WAIT_DRELEASE); + if (chanp->Flags & FLG_LL_BCONN) { + if (chanp->debug & 1) + link_debug(chanp, "STAT_BHUP", 0); + RESBIT(chanp->Flags, FLG_LL_BCONN); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_BHUP; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); + } + if (chanp->Flags & FLG_START_B) { + release_ds(chanp); + RESBIT(chanp->Flags, FLG_START_B); + } + chanp->para.cause = 0x10; /* Normal Call Clearing */ + chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL); + SETBIT(chanp->Flags, FLG_DISC_SEND); +} + +static void +l4_shutdown_d(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + FsmChangeState(fi, ST_WAIT_DSHUTDOWN); + FsmDelTimer(&chanp->drel_timer, 62); + RESBIT(chanp->Flags, FLG_ESTAB_D); + FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL); +} + +static void +l4_timeout_d(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + + if (chanp->Flags & FLG_LL_DCONN) { + if (chanp->debug & 1) + link_debug(chanp, "STAT_DHUP", 0); + RESBIT(chanp->Flags, FLG_LL_DCONN); + l4_deliver_cause(chanp); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_DHUP; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); + } + FsmChangeState(fi, ST_NULL); + chanp->Flags = FLG_ESTAB_D; + FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 60); +} + +static void +l4_go_null(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + chanp->Flags = 0; + FsmChangeState(fi, ST_NULL); +} + +static void +l4_disconn_bchan(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + chanp->data_open = 0; + FsmChangeState(fi, ST_WAIT_BRELEASE); + RESBIT(chanp->Flags, FLG_CONNECT_B); + FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL); +} + +static void +l4_send_d_disc(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + + + if (chanp->Flags & (FLG_DISC_REC | FLG_REL_REC)) + return; + FsmChangeState(fi, ST_WAIT_DRELEASE); + if (chanp->Flags & FLG_LL_BCONN) { + if (chanp->debug & 1) + link_debug(chanp, "STAT_BHUP", 0); + RESBIT(chanp->Flags, FLG_LL_BCONN); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_BHUP; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); + } + if (chanp->Flags & FLG_START_B) { + release_ds(chanp); + RESBIT(chanp->Flags, FLG_START_B); + } + chanp->para.cause = 0x10; /* Normal Call Clearing */ + chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL); + SETBIT(chanp->Flags, FLG_DISC_SEND); +} + +static void +l4_released_bchan(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + + FsmChangeState(fi, ST_WAIT_DCOMMAND); + chanp->data_open = 0; + if (chanp->Flags & FLG_LL_BCONN) { + if (chanp->debug & 1) + link_debug(chanp, "STAT_BHUP", 0); + RESBIT(chanp->Flags, FLG_LL_BCONN); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_BHUP; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); + } + release_ds(chanp); + RESBIT(chanp->Flags, FLG_START_B); +} + + +static void +l4_release_bchan(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + chanp->data_open = 0; + SETBIT(chanp->Flags, FLG_DISC_REC); + FsmChangeState(fi, ST_WAIT_BREL_DISC); + RESBIT(chanp->Flags, FLG_CONNECT_B); + FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL); +} + +static void +l4_received_d_rel(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + + chanp->data_open = 0; + FsmChangeState(fi, ST_WAIT_DSHUTDOWN); + SETBIT(chanp->Flags, FLG_REL_REC); + if (chanp->Flags & FLG_CONNECT_B) { + chanp->lc_b.l2_establish = 0; /* direct reset in lc_b.lcfi */ + FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL); + RESBIT(chanp->Flags, FLG_CONNECT_B); + } + if (chanp->Flags & FLG_LL_BCONN) { + if (chanp->debug & 1) + link_debug(chanp, "STAT_BHUP", 0); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_BHUP; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); + RESBIT(chanp->Flags, FLG_LL_BCONN); + } + if (chanp->Flags & FLG_START_B) { + release_ds(chanp); + RESBIT(chanp->Flags, FLG_START_B); + } + if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND)) { + if (chanp->debug & 1) + link_debug(chanp, "STAT_DHUP", 0); + RESBIT(chanp->Flags, FLG_LL_DCONN); + RESBIT(chanp->Flags, FLG_CALL_SEND); + l4_deliver_cause(chanp); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_DHUP; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); + } + FsmEvent(&chanp->lc_d.lcfi, EV_LC_FLUSH, NULL); + RESBIT(chanp->Flags, FLG_ESTAB_D); + RESBIT(chanp->Flags, FLG_DISC_SEND); + RESBIT(chanp->Flags, FLG_CALL_REC); + RESBIT(chanp->Flags, FLG_CALL_ALERT); +} + +static void +l4_received_d_relcnf(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + + chanp->data_open = 0; + FsmChangeState(fi, ST_WAIT_DSHUTDOWN); + if (chanp->Flags & FLG_CONNECT_B) { + chanp->lc_b.l2_establish = 0; /* direct reset in lc_b.lcfi */ + FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL); + RESBIT(chanp->Flags, FLG_CONNECT_B); + } + if (chanp->Flags & FLG_LL_BCONN) { + if (chanp->debug & 1) + link_debug(chanp, "STAT_BHUP", 0); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_BHUP; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); + RESBIT(chanp->Flags, FLG_LL_BCONN); + } + if (chanp->Flags & FLG_START_B) { + release_ds(chanp); + RESBIT(chanp->Flags, FLG_START_B); + } + if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND)) { + if (chanp->debug & 1) + link_debug(chanp, "STAT_DHUP", 0); + RESBIT(chanp->Flags, FLG_LL_DCONN); + RESBIT(chanp->Flags, FLG_CALL_SEND); + l4_deliver_cause(chanp); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_DHUP; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); + } + FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL); + RESBIT(chanp->Flags, FLG_ESTAB_D); + RESBIT(chanp->Flags, FLG_DISC_SEND); + RESBIT(chanp->Flags, FLG_CALL_REC); + RESBIT(chanp->Flags, FLG_CALL_ALERT); +} + +static void +l4_received_d_disc(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + + chanp->data_open = 0; + FsmChangeState(fi, ST_WAIT_D_REL_CNF); + SETBIT(chanp->Flags, FLG_DISC_REC); + if (chanp->Flags & FLG_LL_BCONN) { + if (chanp->debug & 1) + link_debug(chanp, "STAT_BHUP", 0); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_BHUP; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); + RESBIT(chanp->Flags, FLG_LL_BCONN); + } + if (chanp->Flags & FLG_START_B) { + release_ds(chanp); + RESBIT(chanp->Flags, FLG_START_B); + } + if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND)) { + if (chanp->debug & 1) + link_debug(chanp, "STAT_DHUP", 0); + RESBIT(chanp->Flags, FLG_LL_DCONN); + RESBIT(chanp->Flags, FLG_CALL_SEND); + RESBIT(chanp->Flags, FLG_CALL_ALERT); + l4_deliver_cause(chanp); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_DHUP; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); + } + RESBIT(chanp->Flags, FLG_CALL_ALERT); + chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL); +} + +/* processing charge info */ +static void +l4_charge_info(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_CINF; + ic.arg = chanp->chan; + sprintf(ic.parm.num, "%d", chanp->para.chargeinfo); + chanp->sp->iif.statcallb(&ic); +} + +/* error procedures */ + +static void +l4_no_dchan(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + + if (chanp->debug & 1) + link_debug(chanp, "STAT_NODCH", 0); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_NODCH; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); + chanp->Flags = 0; + FsmChangeState(fi, ST_NULL); + FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL); +} + +static void +l4_no_dchan_ready(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + + if (chanp->debug & 1) + link_debug(chanp, "STAT_DHUP", 0); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_DHUP; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); +} + +static void +l4_no_dchan_in(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + chanp->is.l4.l4l3(&chanp->is, CC_DLRL, NULL); + chanp->Flags = 0; + FsmChangeState(fi, ST_NULL); + FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL); +} + +static void +l4_no_setup_rsp(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + + chanp->Flags = 0; + FsmChangeState(fi, ST_NULL); + FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL); + if (chanp->debug & 1) + link_debug(chanp, "STAT_DHUP", 0); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_DHUP; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); +} + +static void +l4_setup_err(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + + FsmChangeState(fi, ST_WAIT_DRELEASE); + if (chanp->Flags & FLG_LL_DCONN) { + if (chanp->debug & 1) + link_debug(chanp, "STAT_DHUP", 0); + RESBIT(chanp->Flags, FLG_LL_DCONN); + l4_deliver_cause(chanp); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_DHUP; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); + } + SETBIT(chanp->Flags, FLG_DISC_SEND); /* DISCONN was sent from L3 */ +} + +static void +l4_connect_err(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + + FsmChangeState(fi, ST_WAIT_DRELEASE); + if (chanp->Flags & FLG_LL_DCONN) { + if (chanp->debug & 1) + link_debug(chanp, "STAT_DHUP", 0); + RESBIT(chanp->Flags, FLG_LL_DCONN); + l4_deliver_cause(chanp); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_DHUP; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); + } + SETBIT(chanp->Flags, FLG_DISC_SEND); /* DISCONN was sent from L3 */ +} + +static void +l4_active_dlrl(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + + chanp->data_open = 0; + FsmChangeState(fi, ST_NULL); + if (chanp->Flags & FLG_CONNECT_B) { + chanp->lc_b.l2_establish = 0; /* direct reset in lc_b.lcfi */ + FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL); + RESBIT(chanp->Flags, FLG_CONNECT_B); + } + if (chanp->Flags & FLG_LL_BCONN) { + if (chanp->debug & 1) + link_debug(chanp, "STAT_BHUP", 0); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_BHUP; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); + RESBIT(chanp->Flags, FLG_LL_BCONN); + } + if (chanp->Flags & FLG_START_B) { + release_ds(chanp); + RESBIT(chanp->Flags, FLG_START_B); + } + if (chanp->Flags & FLG_LL_DCONN) { + if (chanp->debug & 1) + link_debug(chanp, "STAT_DHUP", 0); + RESBIT(chanp->Flags, FLG_LL_DCONN); + if (chanp->sp->protocol == ISDN_PTYPE_EURO) { + chanp->para.cause = 0x2f; + chanp->para.loc = 0; + } else { + chanp->para.cause = 0x70; + chanp->para.loc = 0; + } + l4_deliver_cause(chanp); + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_DHUP; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); + } + chanp->Flags = 0; + chanp->is.l4.l4l3(&chanp->is, CC_DLRL, NULL); + FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL); +} +/* *INDENT-OFF* */ +static struct FsmNode fnlist[] = +{ + {ST_NULL, EV_DIAL, l4_prep_dialout}, + {ST_NULL, EV_SETUP_IND, l4_start_dchan}, + {ST_NULL, EV_SHUTDOWN_D, l4_shutdown_d}, + {ST_OUT_WAIT_D, EV_DLEST, l4_do_dialout}, + {ST_OUT_WAIT_D, EV_DLRL, l4_no_dchan}, + {ST_OUT_WAIT_D, EV_HANGUP, l4_no_dchan}, + {ST_IN_WAIT_D, EV_DLEST, l4_deliver_call}, + {ST_IN_WAIT_D, EV_DLRL, l4_no_dchan_in}, + {ST_IN_WAIT_D, EV_HANGUP, l4_no_dchan_in}, + {ST_OUT_DIAL, EV_SETUP_CNF, l4_init_bchan_out}, + {ST_OUT_DIAL, EV_HANGUP, l4_cancel_call}, + {ST_OUT_DIAL, EV_DISCONNECT_IND, l4_received_d_disc}, + {ST_OUT_DIAL, EV_RELEASE_IND, l4_received_d_rel}, + {ST_OUT_DIAL, EV_RELEASE_CNF, l4_received_d_relcnf}, + {ST_OUT_DIAL, EV_NOSETUP_RSP, l4_no_setup_rsp}, + {ST_OUT_DIAL, EV_SETUP_ERR, l4_setup_err}, + {ST_IN_WAIT_LL, EV_SETUP_CMPL_IND, l4_init_bchan_in}, + {ST_IN_WAIT_LL, EV_ACCEPTD, l4_send_dconnect}, + {ST_IN_WAIT_LL, EV_HANGUP, l4_reject_call}, + {ST_IN_WAIT_LL, EV_DISCONNECT_IND, l4_received_d_disc}, + {ST_IN_WAIT_LL, EV_RELEASE_IND, l4_received_d_rel}, + {ST_IN_WAIT_LL, EV_RELEASE_CNF, l4_received_d_relcnf}, + {ST_IN_ALERT_SEND, EV_SETUP_CMPL_IND, l4_init_bchan_in}, + {ST_IN_ALERT_SEND, EV_ACCEPTD, l4_send_dconnect}, + {ST_IN_ALERT_SEND, EV_HANGUP, l4_send_d_disc}, + {ST_IN_ALERT_SEND, EV_DISCONNECT_IND, l4_received_d_disc}, + {ST_IN_ALERT_SEND, EV_RELEASE_IND, l4_received_d_rel}, + {ST_IN_ALERT_SEND, EV_RELEASE_CNF, l4_received_d_relcnf}, + {ST_IN_WAIT_CONN_ACK, EV_SETUP_CMPL_IND, l4_init_bchan_in}, + {ST_IN_WAIT_CONN_ACK, EV_HANGUP, l4_send_d_disc}, + {ST_IN_WAIT_CONN_ACK, EV_DISCONNECT_IND, l4_received_d_disc}, + {ST_IN_WAIT_CONN_ACK, EV_RELEASE_IND, l4_received_d_rel}, + {ST_IN_WAIT_CONN_ACK, EV_RELEASE_CNF, l4_received_d_relcnf}, + {ST_IN_WAIT_CONN_ACK, EV_CONNECT_ERR, l4_connect_err}, + {ST_WAIT_BCONN, EV_BC_EST, l4_go_active}, + {ST_WAIT_BCONN, EV_BC_REL, l4_send_d_disc}, + {ST_WAIT_BCONN, EV_HANGUP, l4_send_d_disc}, + {ST_WAIT_BCONN, EV_DISCONNECT_IND, l4_received_d_disc}, + {ST_WAIT_BCONN, EV_RELEASE_IND, l4_received_d_rel}, + {ST_WAIT_BCONN, EV_RELEASE_CNF, l4_received_d_relcnf}, + {ST_ACTIVE, EV_CINF, l4_charge_info}, + {ST_ACTIVE, EV_BC_REL, l4_released_bchan}, + {ST_ACTIVE, EV_HANGUP, l4_disconn_bchan}, + {ST_ACTIVE, EV_DISCONNECT_IND, l4_release_bchan}, + {ST_ACTIVE, EV_RELEASE_CNF, l4_received_d_relcnf}, + {ST_ACTIVE, EV_RELEASE_IND, l4_received_d_rel}, + {ST_ACTIVE, EV_DLRL, l4_active_dlrl}, + {ST_WAIT_BRELEASE, EV_BC_REL, l4_send_d_disc}, + {ST_WAIT_BRELEASE, EV_DISCONNECT_IND, l4_received_d_disc}, + {ST_WAIT_BRELEASE, EV_RELEASE_CNF, l4_received_d_relcnf}, + {ST_WAIT_BRELEASE, EV_RELEASE_IND, l4_received_d_rel}, + {ST_WAIT_BREL_DISC, EV_BC_REL, l4_received_d_disc}, + {ST_WAIT_BREL_DISC, EV_RELEASE_CNF, l4_received_d_relcnf}, + {ST_WAIT_BREL_DISC, EV_RELEASE_IND, l4_received_d_rel}, + {ST_WAIT_DCOMMAND, EV_HANGUP, l4_send_d_disc}, + {ST_WAIT_DCOMMAND, EV_DISCONNECT_IND, l4_received_d_disc}, + {ST_WAIT_DCOMMAND, EV_RELEASE_CNF, l4_received_d_relcnf}, + {ST_WAIT_DCOMMAND, EV_RELEASE_IND, l4_received_d_rel}, + {ST_WAIT_DRELEASE, EV_RELEASE_IND, l4_timeout_d}, + {ST_WAIT_DRELEASE, EV_RELEASE_CNF, l4_timeout_d}, + {ST_WAIT_DRELEASE, EV_RELEASE_ERR, l4_timeout_d}, + {ST_WAIT_DRELEASE, EV_DIAL, l4_no_dchan_ready}, + {ST_WAIT_D_REL_CNF, EV_RELEASE_CNF, l4_timeout_d}, + {ST_WAIT_D_REL_CNF, EV_RELEASE_ERR, l4_timeout_d}, + {ST_WAIT_D_REL_CNF, EV_DIAL, l4_no_dchan_ready}, + {ST_WAIT_DSHUTDOWN, EV_DLRL, l4_go_null}, + {ST_WAIT_DSHUTDOWN, EV_DIAL, l4_prep_dialout}, + {ST_WAIT_DSHUTDOWN, EV_SETUP_IND, l4_start_dchan}, +}; +/* *INDENT-ON* */ + + + + + + + + +#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode)) + +static void +lc_r1(struct FsmInst *fi, int event, void *arg) +{ + struct LcFsm *lf = fi->userdata; + + FsmChangeState(fi, ST_LC_ACTIVATE_WAIT); + FsmAddTimer(&lf->act_timer, 1000, EV_LC_TIMER, NULL, 50); + lf->st->ma.manl1(lf->st, PH_ACTIVATE, NULL); + +} + +static void +lc_r6(struct FsmInst *fi, int event, void *arg) +{ + struct LcFsm *lf = fi->userdata; + + FsmDelTimer(&lf->act_timer, 50); + FsmChangeState(fi, ST_LC_DELAY); + FsmAddTimer(&lf->act_timer, 40, EV_LC_TIMER, NULL, 51); +} + +static void +lc_r2(struct FsmInst *fi, int event, void *arg) +{ + struct LcFsm *lf = fi->userdata; + + 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_r3(struct FsmInst *fi, int event, void *arg) +{ + struct LcFsm *lf = fi->userdata; + + FsmChangeState(fi, ST_LC_CONNECTED); + lf->lccall(lf, LC_ESTABLISH, NULL); +} + +static void +lc_r7(struct FsmInst *fi, int event, void *arg) +{ + struct LcFsm *lf = fi->userdata; + + FsmChangeState(fi, ST_LC_FLUSH_WAIT); + lf->st->ma.manl2(lf->st, DL_FLUSH, NULL); +} + +static void +lc_r4(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); + /* This timer is for releasing the channel even + * there is a hang in layer 2 ; 5 sec are a try + */ + FsmAddTimer(&lf->act_timer, 5000, EV_LC_TIMER, NULL, 53); + } else { + FsmChangeState(fi, ST_LC_NULL); + lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL); + lf->lccall(lf, LC_RELEASE, NULL); + } +} + +static void +lc_r4_1(struct FsmInst *fi, int event, void *arg) +{ + struct LcFsm *lf = fi->userdata; + + FsmChangeState(fi, ST_LC_FLUSH_DELAY); + FsmAddTimer(&lf->act_timer, 50, EV_LC_TIMER, NULL, 52); +} + +static void +lc_r5_1(struct FsmInst *fi, int event, void *arg) +{ + struct LcFsm *lf = fi->userdata; + + FsmChangeState(fi, ST_LC_RELEASE_WAIT); + /* This delay is needed for send out the UA frame before + * PH_DEACTIVATE the interface + */ + FsmAddTimer(&lf->act_timer, 10, EV_LC_TIMER, NULL, 54); +} + +static void +lc_r5(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, NULL); + lf->lccall(lf, LC_RELEASE, NULL); +} +/* *INDENT-OFF* */ +static struct FsmNode LcFnList[] = +{ + {ST_LC_NULL, EV_LC_ESTABLISH, lc_r1}, + {ST_LC_ACTIVATE_WAIT, EV_LC_PH_ACTIVATE, lc_r6}, + {ST_LC_DELAY, EV_LC_TIMER, lc_r2}, + {ST_LC_DELAY, EV_LC_DL_ESTABLISH, lc_r3}, + {ST_LC_ESTABLISH_WAIT, EV_LC_DL_ESTABLISH, lc_r3}, + {ST_LC_ESTABLISH_WAIT, EV_LC_RELEASE, lc_r5}, + {ST_LC_CONNECTED, EV_LC_FLUSH, lc_r7}, + {ST_LC_CONNECTED, EV_LC_RELEASE, lc_r4}, + {ST_LC_CONNECTED, EV_LC_DL_RELEASE, lc_r5_1}, + {ST_LC_FLUSH_WAIT, EV_LC_DL_FLUSH, lc_r4_1}, + {ST_LC_FLUSH_DELAY, EV_LC_TIMER, lc_r4}, + {ST_LC_RELEASE_WAIT, EV_LC_DL_RELEASE, lc_r5}, + {ST_LC_RELEASE_WAIT, EV_LC_TIMER, lc_r5}, + {ST_LC_ACTIVATE_WAIT, EV_LC_TIMER, lc_r5}, + {ST_LC_ESTABLISH_WAIT, EV_LC_DL_RELEASE, lc_r5}, +}; +/* *INDENT-ON* */ + + + + + + + +#define LC_FN_COUNT (sizeof(LcFnList)/sizeof(struct FsmNode)) + +void +CallcNew(void) +{ + callcfsm.state_count = STATE_COUNT; + callcfsm.event_count = EVENT_COUNT; + 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); +} + +static void +release_ds(struct Channel *chanp) +{ + struct PStack *st = &chanp->ds; + struct IsdnCardState *sp; + struct HscxState *hsp; + + sp = st->l1.hardware; + hsp = sp->hs + chanp->hscx; + + close_hscxstate(hsp); + + switch (chanp->l2_active_protocol) { + case (ISDN_PROTO_L2_X75I): + releasestack_isdnl2(st); + break; + case (ISDN_PROTO_L2_HDLC): + case (ISDN_PROTO_L2_TRANS): + releasestack_transl2(st); + break; + } +} + +static void +cc_l1man(struct PStack *st, int pr, void *arg) +{ + struct Channel *chanp = (struct Channel *) st->l4.userdata; + + switch (pr) { + case (PH_ACTIVATE): + FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_ACTIVATE, NULL); + break; + case (PH_DEACTIVATE): + FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_DEACTIVATE, NULL); + break; + } +} + +static void +cc_l2man(struct PStack *st, int pr, void *arg) +{ + struct Channel *chanp = (struct Channel *) st->l4.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; + case (DL_FLUSH): + FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_FLUSH, NULL); + break; + } +} + +static void +dcc_l1man(struct PStack *st, int pr, void *arg) +{ + struct Channel *chanp = (struct Channel *) st->l4.userdata; + + switch (pr) { + case (PH_ACTIVATE): + FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_ACTIVATE, NULL); + break; + case (PH_DEACTIVATE): + FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_DEACTIVATE, NULL); + break; + } +} + +static void +dcc_l2man(struct PStack *st, int pr, void *arg) +{ + struct Channel *chanp = (struct Channel *) st->l4.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; + } +} + +static void +ll_handler(struct PStack *st, int pr, + struct BufHeader *ibh) +{ + struct Channel *chanp = (struct Channel *) st->l4.userdata; + char tmp[64], tm[32]; + + switch (pr) { + case (CC_DISCONNECT_IND): + FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL); + break; + case (CC_RELEASE_CNF): + FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL); + break; + case (CC_SETUP_IND): + FsmEvent(&chanp->fi, EV_SETUP_IND, NULL); + break; + case (CC_RELEASE_IND): + FsmEvent(&chanp->fi, EV_RELEASE_IND, NULL); + break; + case (CC_SETUP_COMPLETE_IND): + FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL); + break; + case (CC_SETUP_CNF): + FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL); + break; + case (CC_INFO_CHARGE): + FsmEvent(&chanp->fi, EV_CINF, NULL); + break; + case (CC_NOSETUP_RSP_ERR): + FsmEvent(&chanp->fi, EV_NOSETUP_RSP, NULL); + break; + case (CC_SETUP_ERR): + FsmEvent(&chanp->fi, EV_SETUP_ERR, NULL); + break; + case (CC_CONNECT_ERR): + FsmEvent(&chanp->fi, EV_CONNECT_ERR, NULL); + break; + case (CC_RELEASE_ERR): + FsmEvent(&chanp->fi, EV_RELEASE_ERR, NULL); + break; + default: + jiftime(tm, jiffies); + sprintf(tmp, "%s Channel %d L3->L4 unknown primitiv %d\n", tm, chanp->chan, pr); + HiSax_putstatus(chanp->sp, tmp); + } +} + +static void +init_is(struct Channel *chanp, unsigned int ces) +{ + struct PStack *st = &chanp->is; + struct IsdnCardState *sp = chanp->sp; + char tmp[128]; + + setstack_HiSax(st, sp); + st->l2.sap = 0; + st->l2.tei = 255; + st->l2.ces = ces; + st->l2.extended = !0; + st->l2.laptype = LAPD; + st->l2.window = 1; + st->l2.orig = !0; + st->l2.t200 = 1000; /* 1000 milliseconds */ + if (st->protocol == ISDN_PTYPE_1TR6) { + st->l2.n200 = 3; /* try 3 times */ + st->l2.t203 = 10000; /* 10000 milliseconds */ + } else { + st->l2.n200 = 4; /* try 4 times */ + st->l2.t203 = 5000; /* 5000 milliseconds */ + } + sprintf(tmp, "Channel %d q.921", chanp->chan); + setstack_isdnl2(st, tmp); + setstack_isdnl3(st, chanp); + st->l4.userdata = chanp; + st->l4.l2writewakeup = NULL; + st->l3.l3l4 = ll_handler; + st->l1.l1man = cc_l1man; + st->l2.l2man = cc_l2man; + st->pa = &chanp->para; + HiSax_addlist(sp, st); +} + +static void +callc_debug(struct FsmInst *fi, char *s) +{ + char str[80], tm[32]; + struct Channel *chanp = fi->userdata; + + jiftime(tm, jiffies); + sprintf(str, "%s Channel %d callc %s\n", tm, chanp->chan, s); + HiSax_putstatus(chanp->sp, 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 lc %s\n", tm, lf->ch->chan, s); + HiSax_putstatus(lf->ch->sp, 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 dlc %s\n", tm, lf->ch->chan, s); + HiSax_putstatus(lf->ch->sp, str); +} + +static void +lccall_d(struct LcFsm *lf, int pr, void *arg) +{ + struct Channel *chanp = lf->ch; + + switch (pr) { + case (LC_ESTABLISH): + FsmEvent(&chanp->fi, EV_DLEST, NULL); + break; + case (LC_RELEASE): + FsmEvent(&chanp->fi, EV_DLRL, NULL); + break; + } +} + +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; + } +} + +static void +init_chan(int chan, struct IsdnCardState *csta, int hscx, + unsigned int ces) +{ + struct Channel *chanp = csta->channel + chan; + + chanp->sp = csta; + chanp->hscx = hscx; + chanp->chan = chan; + chanp->incoming = 0; + chanp->debug = 0; + chanp->Flags = 0; + chanp->leased = 0; + init_is(chanp, ces); + + chanp->fi.fsm = &callcfsm; + chanp->fi.state = ST_NULL; + chanp->fi.debug = 0; + chanp->fi.userdata = chanp; + chanp->fi.printdebug = callc_debug; + FsmInitTimer(&chanp->fi, &chanp->dial_timer); + FsmInitTimer(&chanp->fi, &chanp->drel_timer); + + 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.ch = chanp; + chanp->lc_d.st = &chanp->is; + 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); + + 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.ch = chanp; + chanp->lc_b.st = &chanp->ds; + 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->outcallref = 64; + chanp->data_open = 0; +} + +int +CallcNewChan(struct IsdnCardState *csta) +{ + int ces; + + chancount += 2; + ces = randomces(); + init_chan(0, csta, 1, ces++); + ces %= 0xffff; + init_chan(1, csta, 0, ces++); + printk(KERN_INFO "HiSax: 2 channels added\n"); + return (2); +} + +static void +release_is(struct Channel *chanp) +{ + struct PStack *st = &chanp->is; + + releasestack_isdnl2(st); + releasestack_isdnl3(st); + HiSax_rmlist(st->l1.hardware, st); + BufQueueRelease(&st->l2.i_queue); +} + +void +CallcFreeChan(struct IsdnCardState *csta) +{ + int i; + + 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_b.act_timer, 76); + FsmDelTimer(&csta->channel[i].lc_d.act_timer, 77); + if (csta->channel[i].Flags & FLG_START_B) { + release_ds(csta->channel + i); + } + release_is(csta->channel + i); + } +} + +static void +lldata_handler(struct PStack *st, int pr, + void *arg) +{ + struct Channel *chanp = (struct Channel *) st->l4.userdata; + byte *ptr; + int size; + struct BufHeader *ibh = arg; + + switch (pr) { + case (DL_DATA): + if (chanp->data_open) { + ptr = DATAPTR(ibh); + ptr += chanp->ds.l2.ihsize; + size = ibh->datasize - chanp->ds.l2.ihsize; + chanp->sp->iif.rcvcallb(chanp->sp->myid, chanp->chan, ptr, size); + } + BufPoolRelease(ibh); + break; + default: + printk(KERN_WARNING "lldata_handler unknown primitive %d\n", + pr); + break; + } +} + +static void +lltrans_handler(struct PStack *st, int pr, + struct BufHeader *ibh) +{ + struct Channel *chanp = (struct Channel *) st->l4.userdata; + byte *ptr; + + switch (pr) { + case (PH_DATA): + if (chanp->data_open) { + ptr = DATAPTR(ibh); + chanp->sp->iif.rcvcallb(chanp->sp->myid, chanp->chan, ptr, ibh->datasize); + } + BufPoolRelease(ibh); + break; + default: + printk(KERN_WARNING "lltrans_handler unknown primitive %d\n", + pr); + break; + } +} + +static void +ll_writewakeup(struct PStack *st) +{ + struct Channel *chanp = st->l4.userdata; + isdn_ctrl ic; + + ic.driver = chanp->sp->myid; + ic.command = ISDN_STAT_BSENT; + ic.arg = chanp->chan; + chanp->sp->iif.statcallb(&ic); +} + +static int +init_ds(struct Channel *chanp, int incoming) +{ + struct PStack *st = &chanp->ds; + struct IsdnCardState *sp = chanp->sp; + struct HscxState *hsp = sp->hs + chanp->hscx; + char tmp[128]; + + st->l1.hardware = sp; + + hsp->mode = 2; + hsp->transbufsize = 4000; + + if (setstack_hscx(st, hsp)) + return (-1); + + st->l2.extended = 0; + st->l2.laptype = LAPB; + st->l2.orig = !incoming; + st->l2.t200 = 1000; /* 1000 milliseconds */ + st->l2.window = 7; + st->l2.n200 = 4; /* try 4 times */ + st->l2.t203 = 5000; /* 5000 milliseconds */ + + st->l3.debug = 0; + switch (chanp->l2_active_protocol) { + case (ISDN_PROTO_L2_X75I): + sprintf(tmp, "Channel %d x.75", chanp->chan); + setstack_isdnl2(st, tmp); + st->l2.l2l3 = lldata_handler; + st->l1.l1man = dcc_l1man; + st->l2.l2man = dcc_l2man; + st->l4.userdata = chanp; + st->l4.l1writewakeup = NULL; + st->l4.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.hscxmode = 2; /* Packet-Mode ? */ + st->l1.hscxchannel = chanp->para.bchannel - 1; + break; + case (ISDN_PROTO_L2_HDLC): + st->l1.l1l2 = lltrans_handler; + st->l1.l1man = dcc_l1man; + st->l4.userdata = chanp; + st->l4.l1writewakeup = ll_writewakeup; + st->l1.hscxmode = 2; + st->l1.hscxchannel = chanp->para.bchannel - 1; + break; + case (ISDN_PROTO_L2_TRANS): + st->l1.l1l2 = lltrans_handler; + st->l1.l1man = dcc_l1man; + st->l4.userdata = chanp; + st->l4.l1writewakeup = ll_writewakeup; + st->l1.hscxmode = 1; + st->l1.hscxchannel = chanp->para.bchannel - 1; + break; + } + return (0); +} + +static void +channel_report(struct Channel *chanp) +{ +} + +static void +distr_debug(struct IsdnCardState *csta, int debugflags) +{ + int i; + struct Channel *chanp = csta->channel; + + for (i = 0; i < 2; i++) { + chanp[i].debug = debugflags; + chanp[i].fi.debug = debugflags & 2; + chanp[i].is.l2.l2m.debug = debugflags & 8; + chanp[i].ds.l2.l2m.debug = debugflags & 16; + chanp[i].is.l2.debug = debugflags & 32; + chanp[i].ds.l2.debug = debugflags & 64; + chanp[i].lc_d.lcfi.debug = debugflags & 128; + chanp[i].lc_b.lcfi.debug = debugflags & 256; + } + csta->dlogflag = debugflags & 4; + csta->teistack->l2.l2m.debug = debugflags & 512; +} + +int +HiSax_command(isdn_ctrl * ic) +{ + struct IsdnCardState *csta = hisax_findcard(ic->driver); + struct Channel *chanp; + char tmp[128]; + int i; + unsigned int num; + + if (!csta) { + printk(KERN_ERR + "HiSax: if_command %d called with invalid driverId %d!\n", + ic->command, ic->driver); + return -ENODEV; + } + switch (ic->command) { + case (ISDN_CMD_SETEAZ): + chanp = csta->channel + ic->arg; + if (chanp->debug & 1) + link_debug(chanp, "SETEAZ", 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); + } + chanp->l2_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)", + ic->parm.setup.eazmsn, ic->parm.setup.phone, + ic->parm.setup.si1, ic->parm.setup.si2); + link_debug(chanp, tmp, 1); + } + /* this solution is dirty and may be change, if + * we make a callreference based callmanager */ + if (chanp->fi.state == ST_NULL) { + FsmEvent(&chanp->fi, EV_DIAL, ic); + } else { + FsmDelTimer(&chanp->dial_timer, 70); + FsmAddTimer(&chanp->dial_timer, 50, EV_DIAL, ic, 71); + } + break; + case (ISDN_CMD_ACCEPTB): + chanp = csta->channel + ic->arg; + if (chanp->debug & 1) + link_debug(chanp, "ACCEPTB", 1); + 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); + 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); + 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): + chanp = csta->channel + ic->arg; + if (chanp->debug & 1) { + sprintf(tmp, "RESUME %s", ic->parm.num); + link_debug(chanp, tmp, 1); + } + FsmEvent(&chanp->fi, EV_RESUME, ic); + break; + case (ISDN_CMD_LOCK): + HiSax_mod_inc_use_count(); +#ifdef MODULE + if (csta->channel[0].debug & 1024) { + jiftime(tmp, jiffies); + i = strlen(tmp); + sprintf(tmp + i, " LOCK modcnt %lx\n", MOD_USE_COUNT); + HiSax_putstatus(csta, tmp); + } +#endif /* MODULE */ + break; + case (ISDN_CMD_UNLOCK): + HiSax_mod_dec_use_count(); +#ifdef MODULE + if (csta->channel[0].debug & 1024) { + jiftime(tmp, jiffies); + i = strlen(tmp); + sprintf(tmp + i, " UNLOCK modcnt %lx\n", MOD_USE_COUNT); + HiSax_putstatus(csta, tmp); + } +#endif /* MODULE */ + break; + case (ISDN_CMD_IOCTL): + switch (ic->arg) { + case (0): + HiSax_reportcard(csta->cardnr); + for (i = 0; i < 2; i++) + channel_report(&csta->channel[i]); + break; + case (1): + num = *(unsigned int *) ic->parm.num; + distr_debug(csta, num); + sprintf(tmp, "debugging flags card %d set to %x\n", + csta->cardnr + 1, num); + HiSax_putstatus(csta, tmp); + printk(KERN_DEBUG "HiSax: %s", tmp); + break; + case (2): + num = *(unsigned int *) ic->parm.num; + i = num >> 8; + if (i >= 2) + break; + chanp = csta->channel + i; + chanp->impair = num & 0xff; + if (chanp->debug & 1) { + sprintf(tmp, "IMPAIR %x", chanp->impair); + link_debug(chanp, tmp, 1); + } + break; + case (3): + for (i = 0; i < *(unsigned int *) ic->parm.num; i++) + HiSax_mod_dec_use_count(); + break; + case (4): + for (i = 0; i < *(unsigned int *) ic->parm.num; i++) + HiSax_mod_inc_use_count(); + break; + case (5): /* set card in leased mode */ + csta->channel[0].leased = 1; + csta->channel[1].leased = 1; + sprintf(tmp, "card %d set into leased mode\n", + csta->cardnr + 1); + HiSax_putstatus(csta, tmp); + break; +#ifdef MODULE + case (55): +#if (LINUX_VERSION_CODE < 0x020111) + MOD_USE_COUNT = MOD_VISITED; +#else + MOD_USE_COUNT = 0; +#endif + HiSax_mod_inc_use_count(); + break; +#endif /* MODULE */ + case (11): + csta->debug = *(unsigned int *) ic->parm.num; + sprintf(tmp, "l1 debugging flags card %d set to %x\n", + csta->cardnr + 1, csta->debug); + HiSax_putstatus(cards[0].sp, tmp); + printk(KERN_DEBUG "HiSax: %s", tmp); + break; + case (13): + csta->channel[0].is.l3.debug = *(unsigned int *) ic->parm.num; + csta->channel[1].is.l3.debug = *(unsigned int *) ic->parm.num; + sprintf(tmp, "l3 debugging flags card %d set to %x\n", + csta->cardnr + 1, *(unsigned int *) ic->parm.num); + HiSax_putstatus(cards[0].sp, tmp); + printk(KERN_DEBUG "HiSax: %s", tmp); + break; + default: + printk(KERN_DEBUG "HiSax: invalid ioclt %d\n", + (int) ic->arg); + return (-EINVAL); + } + break; + default: + break; + } + + return (0); +} + +int +HiSax_writebuf(int id, int chan, const u_char * buf, int count, int user) +{ + struct IsdnCardState *csta = hisax_findcard(id); + struct Channel *chanp; + struct PStack *st; + struct BufHeader *ibh; + int err, i; + byte *ptr; + char tmp[64]; + + if (!csta) { + printk(KERN_ERR + "HiSax: if_sendbuf called with invalid driverId!\n"); + return -ENODEV; + } + chanp = csta->channel + chan; + st = &chanp->ds; + if (!chanp->data_open) { + link_debug(chanp, "writebuf: channel not open", 1); + return -EIO; + } + err = BufPoolGet(&ibh, st->l1.sbufpool, GFP_ATOMIC, st, 21); + if (err) { + /* Must return 0 here, since this is not an error + * but a temporary lack of resources. + */ + if (chanp->debug & 1) { + sprintf(tmp, "writebuf: no buffers for %d bytes", count); + link_debug(chanp, tmp, 1); + } + return 0; + } +#if 0 + if (chanp->debug & 1) { + sprintf(tmp, "writebuf: %d bytes", count); + link_debug(chanp, tmp, 1); + } +#endif + ptr = DATAPTR(ibh); + if (chanp->lc_b.l2_establish) + i = st->l2.ihsize; + else + i = 0; + + if ((count + i) > BUFFER_SIZE(HSCX_SBUF_ORDER, HSCX_SBUF_BPPS)) { + sprintf(tmp, "writebuf: packet too large (%d bytes)", count + i); + printk(KERN_WARNING "HiSax_%s !\n", tmp); + link_debug(chanp, tmp, 1); + return (-EINVAL); + } + ptr += i; + + if (user) + copy_from_user(ptr, buf, count); + else + memcpy(ptr, buf, count); + ibh->datasize = count + i; + + if (chanp->data_open) { + if (chanp->lc_b.l2_establish) + chanp->ds.l3.l3l2(&chanp->ds, DL_DATA, ibh); + else + chanp->ds.l2.l2l1(&chanp->ds, PH_DATA, ibh); + return (count); + } else { + BufPoolRelease(ibh); + return (0); + } +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c --- v2.1.26/linux/drivers/isdn/hisax/config.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/config.c Tue Feb 25 17:12:49 1997 @@ -0,0 +1,401 @@ +/* $Id: config.c,v 1.11 1997/02/14 12:23:12 fritz Exp $ + + * Author Karsten Keil (keil@temic-ech.spacenet.de) + * based on the teles driver from Jan den Ouden + * + * + * $Log: config.c,v $ + * Revision 1.11 1997/02/14 12:23:12 fritz + * Added support for new insmod parameter handling. + * + * Revision 1.10 1997/02/14 09:22:09 keil + * Final 2.0 version + * + * Revision 1.9 1997/02/10 11:45:09 fritz + * More changes for Kernel 2.1.X compatibility. + * + * Revision 1.8 1997/02/09 00:28:05 keil + * new interface handling, one interface per card + * default protocol now works again + * + * Revision 1.7 1997/01/27 15:56:57 keil + * Teles PCMCIA ITK ix1 micro added + * + * Revision 1.6 1997/01/21 22:17:56 keil + * new module load syntax + * + * Revision 1.5 1997/01/09 18:28:20 keil + * cosmetic cleanups + * + * Revision 1.4 1996/11/05 19:35:17 keil + * using config.h; some spelling fixes + * + * Revision 1.3 1996/10/23 17:23:28 keil + * default config changes + * + * Revision 1.2 1996/10/23 11:58:48 fritz + * Changed default setup to reflect user's selection of supported + * cards/protocols. + * + * Revision 1.1 1996/10/13 20:04:51 keil + * Initial revision + * + * + * + */ +#include +#include +#include +#include +#include "hisax.h" + +/* + * This structure array contains one entry per card. An entry looks + * like this: + * + * { type, protocol, p0, p1, p2, NULL } + * + * type + * 1 Teles 16.0 p0=irq p1=membase p2=iobase + * 2 Teles 8.0 p0=irq p1=membase + * 3 Teles 16.3 p0=irq p1=iobase + * 4 Creatix PNP p0=irq p1=IO0 (ISAC) p2=IO1 (HSCX) + * 5 AVM A1 (Fritz) p0=irq p1=iobase + * 6 ELSA PC [p0=iobase] or nothing (autodetect) + * 7 ELSA Quickstep p0=irq p1=iobase + * 8 Teles PCMCIA p0=irq p1=iobase + * 9 ITK ix1-micro p0=irq p1=iobase + * + * + * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 + * + * + */ + +#ifdef CONFIG_HISAX_ELSA_PCC +#define DEFAULT_CARD ISDN_CTYPE_ELSA +#define DEFAULT_CFG {0,0,0} +#endif +#ifdef CONFIG_HISAX_AVM_A1 +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_A1 +#define DEFAULT_CFG {10,0x340,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} +#endif +#ifdef CONFIG_HISAX_16_0 +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_16_0 +#define DEFAULT_CFG {15,0xd0000,0xd80} +#endif + +#ifdef CONFIG_HISAX_IX1MICROR2 +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_IX1MICROR2 +#define DEFAULT_CFG {5,0x390,0} +#endif + +#ifdef CONFIG_HISAX_1TR6 +#define DEFAULT_PROTO ISDN_PTYPE_1TR6 +#define DEFAULT_PROTO_NAME "1TR6" +#endif +#ifdef CONFIG_HISAX_EURO +#undef DEFAULT_PROTO +#define DEFAULT_PROTO ISDN_PTYPE_EURO +#undef DEFAULT_PROTO_NAME +#define DEFAULT_PROTO_NAME "EURO" +#endif +#ifndef DEFAULT_PROTO +#define DEFAULT_PROTO ISDN_PTYPE_UNKNOWN +#define DEFAULT_PROTO_NAME "UNKNOWN" +#endif +#ifndef DEFAULT_CARD +#error "HiSax: No cards configured" +#endif + +#define FIRST_CARD { \ + DEFAULT_CARD, \ + DEFAULT_PROTO, \ + DEFAULT_CFG, \ + NULL, \ +} + +#define EMPTY_CARD {0, DEFAULT_PROTO, {0, 0, 0}, NULL} + +struct IsdnCard cards[] = +{ + FIRST_CARD, + EMPTY_CARD, + EMPTY_CARD, + EMPTY_CARD, + EMPTY_CARD, + 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] = "\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\0\0\0\0\0\0\0\0"; +char *HiSax_id = HiSaxID; +#ifdef MODULE +/* Variables for insmod */ +int type[] = +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +int protocol[] = +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +int io[] = +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +#ifdef CONFIG_HISAX_16_3 /* For Creatix/Teles PnP */ +int io0[] = +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +int io1[] = +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +#endif +int irq[] = +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +int mem[] = +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +char *id = HiSaxID; + +#if (LINUX_VERSION_CODE > 0x020111) +MODULE_AUTHOR("Karsten Keil"); +MODULE_PARM(type, "1-16i"); +MODULE_PARM(protocol, "1-16i"); +MODULE_PARM(io, "1-16i"); +MODULE_PARM(irq, "1-16i"); +MODULE_PARM(mem, "1-16i"); +MODULE_PARM(id, "s"); +#ifdef CONFIG_HISAX_16_3 /* For Creatix/Teles PnP */ +MODULE_PARM(io0, "1-16i"); +MODULE_PARM(io1, "1-16i"); +#endif +#endif + +#endif + +extern char *l1_revision; +extern char *l2_revision; +extern char *l3_revision; +extern char *l4_revision; +extern char *tei_revision; + +char * +HiSax_getrev(const char *revision) +{ + char *rev; + char *p; + + if ((p = strchr(revision, ':'))) { + rev = p + 2; + p = strchr(rev, '$'); + *--p = 0; + } else + rev = "???"; + return rev; +} + +int nrcards; + +void +HiSax_mod_dec_use_count(void) +{ + MOD_DEC_USE_COUNT; +} + +void +HiSax_mod_inc_use_count(void) +{ + MOD_INC_USE_COUNT; +} + +#ifdef MODULE +#define HiSax_init init_module +#else +void +HiSax_setup(char *str, int *ints) +{ + int i, j, argc; + + argc = ints[0]; + i = 0; + j = 1; + while (argc && (i < 16)) { + if (argc) { + cards[i].typ = ints[j]; + j++; + argc--; + } + if (argc) { + cards[i].protocol = ints[j]; + j++; + argc--; + } + if (argc) { + cards[i].para[0] = ints[j]; + j++; + argc--; + } + if (argc) { + cards[i].para[1] = ints[j]; + j++; + argc--; + } + if (argc) { + cards[i].para[2] = ints[j]; + j++; + argc--; + } + i++; + } + if (strlen(str)) { + strcpy(HiSaxID, str); + HiSax_id = HiSaxID; + } else { + strcpy(HiSaxID, "HiSax"); + HiSax_id = HiSaxID; + } +} +#endif + +int +HiSax_init(void) +{ + int i; + char tmp[64], rev[64]; + char *r = rev; + int nzproto = 0; + + nrcards = 0; + strcpy(tmp, l1_revision); + r += sprintf(r, "%s/", HiSax_getrev(tmp)); + strcpy(tmp, l2_revision); + r += sprintf(r, "%s/", HiSax_getrev(tmp)); + strcpy(tmp, l3_revision); + r += sprintf(r, "%s/", HiSax_getrev(tmp)); + strcpy(tmp, l4_revision); + r += sprintf(r, "%s/", HiSax_getrev(tmp)); + strcpy(tmp, tei_revision); + r += sprintf(r, "%s", HiSax_getrev(tmp)); + + printk(KERN_NOTICE "HiSax: Driver for Siemens chip set ISDN cards\n"); + printk(KERN_NOTICE "HiSax: Version 2.0\n"); + printk(KERN_NOTICE "HiSax: Revisions %s\n", rev); + +#ifdef MODULE + if (id) /* If id= string used */ + HiSax_id = id; + for (i = 0; i < 16; i++) { + cards[i].typ = type[i]; + if (protocol[i]) { + cards[i].protocol = protocol[i]; + nzproto++; + } + switch (type[i]) { + case ISDN_CTYPE_16_0: + cards[i].para[0] = irq[i]; + cards[i].para[1] = mem[i]; + cards[i].para[2] = io[i]; + break; + + case ISDN_CTYPE_8_0: + cards[i].para[0] = irq[i]; + cards[i].para[1] = mem[i]; + break; + + case ISDN_CTYPE_16_3: + case ISDN_CTYPE_TELESPCMCIA: + cards[i].para[0] = irq[i]; + cards[i].para[1] = io[i]; + break; + +#ifdef CONFIG_HISAX_16_3 /* For Creatix/Teles PnP */ + case ISDN_CTYPE_PNP: + cards[i].para[0] = irq[i]; + cards[i].para[1] = io0[i]; + cards[i].para[2] = io1[i]; + break; +#endif + case ISDN_CTYPE_A1: + cards[i].para[0] = irq[i]; + cards[i].para[1] = io[i]; + break; + + case ISDN_CTYPE_ELSA: + cards[i].para[0] = io[i]; + break; + case ISDN_CTYPE_ELSA_QS1000: + cards[i].para[0] = irq[i]; + cards[i].para[1] = io[i]; + break; + + case ISDN_CTYPE_IX1MICROR2: + cards[i].para[0] = irq[i]; + cards[i].para[1] = io[i]; + break; + + } + } + if (!nzproto) { + printk(KERN_WARNING "HiSax: Warning - no protocol specified\n"); + printk(KERN_WARNING "HiSax: Note! module load syntax has changed.\n"); + printk(KERN_WARNING "HiSax: using protocol %s\n", DEFAULT_PROTO_NAME); + } +#endif + if (!HiSax_id) + HiSax_id = HiSaxID; + if (!HiSaxID[0]) + strcpy(HiSaxID, "HiSax"); + for (i = 0; i < 16; i++) + if (cards[i].typ > 0) + nrcards++; + printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", + nrcards, (nrcards > 1) ? "s" : ""); + + CallcNew(); + Isdnl2New(); + if (HiSax_inithardware()) { + /* Install only, if at least one card found */ + /* No symbols to export, hide all symbols */ + +#ifdef MODULE +#if (LINUX_VERSION_CODE < 0x020111) + register_symtab(NULL); +#else + EXPORT_NO_SYMBOLS; +#endif + printk(KERN_NOTICE "HiSax: module installed\n"); +#endif + return (0); + } else { + Isdnl2Free(); + CallcFree(); + return -EIO; + } +} + +#ifdef MODULE +void +cleanup_module(void) +{ + HiSax_closehardware(); + printk(KERN_NOTICE "HiSax module removed\n"); +} + +#endif diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/elsa.c linux/drivers/isdn/hisax/elsa.c --- v2.1.26/linux/drivers/isdn/hisax/elsa.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/elsa.c Tue Feb 25 17:12:49 1997 @@ -0,0 +1,1327 @@ +/* $Id: elsa.c,v 1.8 1997/01/27 15:51:48 keil Exp $ + + * elsa.c low level stuff for Elsa isdn cards + * + * Author Karsten Keil (keil@temic-ech.spacenet.de) + * + * Thanks to Elsa GmbH for documents and informations + * + * + * $Log: elsa.c,v $ + * Revision 1.8 1997/01/27 15:51:48 keil + * SMP proof,cosmetics + * + * Revision 1.7 1997/01/21 22:20:48 keil + * Elsa Quickstep support + * + * Revision 1.6 1997/01/09 18:22:46 keil + * one more PCC-8 fix + * + * Revision 1.5 1996/12/08 19:46:14 keil + * PCC-8 correct IRQs; starting ARCOFI support + * + * Revision 1.4 1996/11/18 20:50:54 keil + * with PCF Pro release 16 Byte IO + * + * Revision 1.3 1996/11/18 15:33:04 keil + * PCC and PCFPro support + * + * Revision 1.2 1996/10/27 22:08:03 keil + * cosmetic changes + * + * Revision 1.1 1996/10/13 20:04:52 keil + * Initial revision + * + * + */ + +#define ARCOFI_USE 0 + +#define __NO_VERSION__ +#include "siemens.h" +#include "hisax.h" +#include "elsa.h" +#include "isdnl1.h" +#include + +extern const char *CardType[]; + +const char *Elsa_revision = "$Revision: 1.8 $"; +const char *Elsa_Types[] = +{"None", "PCC-8", "PCF-Pro", "PCC-16", "PCF", + "QS 1000"}; + +#define byteout(addr,val) outb_p(val,addr) +#define bytein(addr) inb_p(addr) + +static inline byte +readhscx(unsigned int adr, int hscx, byte off) +{ + register byte ret; + long flags; + + save_flags(flags); + cli(); + byteout(adr + CARD_ALE, off + (hscx ? 0x60 : 0x20)); + ret = bytein(adr + CARD_HSCX); + restore_flags(flags); + return (ret); +} + +static inline void +read_fifo_hscx(unsigned int adr, int hscx, byte * data, int size) +{ + /* fifo read without cli because it's allready done */ + + byteout(adr + CARD_ALE, (hscx ? 0x40 : 0)); + insb(adr + CARD_HSCX, data, size); +} + + +static inline void +writehscx(unsigned int adr, int hscx, byte off, byte data) +{ + long flags; + + save_flags(flags); + cli(); + byteout(adr + CARD_ALE, off + (hscx ? 0x60 : 0x20)); + byteout(adr + CARD_HSCX, data); + restore_flags(flags); +} + +static inline void +write_fifo_hscx(unsigned int adr, int hscx, byte * data, int size) +{ + /* fifo write without cli because it's allready done */ + byteout(adr + CARD_ALE, (hscx ? 0x40 : 0)); + outsb(adr + CARD_HSCX, data, size); +} + +static inline byte +readisac(unsigned int adr, byte off) +{ + register byte ret; + long flags; + + save_flags(flags); + cli(); + byteout(adr + CARD_ALE, off + 0x20); + ret = bytein(adr); + restore_flags(flags); + return (ret); +} + +static inline void +read_fifo_isac(unsigned int adr, byte * data, int size) +{ + /* fifo read without cli because it's allready done */ + + byteout(adr + CARD_ALE, 0); + insb(adr, data, size); +} + + +static inline void +writeisac(unsigned int adr, byte off, byte data) +{ + long flags; + + save_flags(flags); + cli(); + byteout(adr + CARD_ALE, off + 0x20); + byteout(adr, data); + restore_flags(flags); +} + +static inline void +write_fifo_isac(unsigned int adr, byte * data, int size) +{ + /* fifo write without cli because it's allready done */ + + byteout(adr + CARD_ALE, 0); + outsb(adr, data, size); +} + +static inline int +TimerRun(struct IsdnCardState *sp) +{ + register byte val; + + val = bytein(sp->cfg_reg + CARD_CONFIG); + if (sp->subtyp == ELSA_QS1000) + return (0 == (val & TIMER_RUN)); + return ((val & TIMER_RUN)); +} + +static inline void +elsa_led_handler(struct IsdnCardState *sp) +{ + + byte outval = 0xf0; + int stat = 0, cval; + + + if ((sp->ph_state == 0) || (sp->ph_state == 15)) { + stat = 1; + } else { + if (sp->hs[0].mode != 0) + stat |= 2; + if (sp->hs[1].mode != 0) + stat |= 4; + } + cval = (sp->counter >> 6) & 3; + switch (cval) { + case 0: + if (!stat) + outval |= STAT_LED; + else if (stat == 1) + outval |= LINE_LED | STAT_LED; + else { + if (stat & 2) + outval |= STAT_LED; + if (stat & 4) + outval |= LINE_LED; + } + break; + case 1: + if (!stat) + outval |= LINE_LED; + else if (stat == 1) + outval |= LINE_LED | STAT_LED; + else { + if (stat & 2) + outval |= STAT_LED; + if (stat & 4) + outval |= LINE_LED; + } + break; + case 2: + if (!stat) + outval |= STAT_LED; + else if (stat == 1) + outval |= 0; + else { + if (stat & 2) + outval |= STAT_LED; + if (stat & 4) + outval |= LINE_LED; + } + break; + case 3: + if (!stat) + outval |= LINE_LED; + break; + } + byteout(sp->cfg_reg + CARD_CONTROL, outval); +} + +static inline void +waitforCEC(int adr, int hscx) +{ + int to = 50; + + while ((readhscx(adr, hscx, HSCX_STAR) & 0x04) && to) { + udelay(1); + to--; + } + if (!to) + printk(KERN_WARNING "Elsa: waitforCEC timeout\n"); +} + + +static inline void +waitforXFW(int adr, int hscx) +{ + int to = 50; + + while ((!(readhscx(adr, hscx, HSCX_STAR) & 0x44) == 0x40) && to) { + udelay(1); + to--; + } + if (!to) + printk(KERN_WARNING "Elsa: waitforXFW timeout\n"); +} + +static inline void +writehscxCMDR(int adr, int hscx, byte data) +{ + long flags; + + save_flags(flags); + cli(); + waitforCEC(adr, hscx); + writehscx(adr, hscx, HSCX_CMDR, data); + restore_flags(flags); +} + +/* + * fast interrupt here + */ + + +static void +hscxreport(struct IsdnCardState *sp, int hscx) +{ + printk(KERN_DEBUG "HSCX %d\n", hscx); + printk(KERN_DEBUG "ISTA %x\n", readhscx(sp->cfg_reg, hscx, HSCX_ISTA)); + printk(KERN_DEBUG "STAR %x\n", readhscx(sp->cfg_reg, hscx, HSCX_STAR)); + printk(KERN_DEBUG "EXIR %x\n", readhscx(sp->cfg_reg, hscx, HSCX_EXIR)); +} + +void +elsa_report(struct IsdnCardState *sp) +{ + printk(KERN_DEBUG "ISAC\n"); + printk(KERN_DEBUG "ISTA %x\n", readisac(sp->cfg_reg, ISAC_ISTA)); + printk(KERN_DEBUG "STAR %x\n", readisac(sp->cfg_reg, ISAC_STAR)); + printk(KERN_DEBUG "EXIR %x\n", readisac(sp->cfg_reg, ISAC_EXIR)); + hscxreport(sp, 0); + hscxreport(sp, 1); +} + +/* + * HSCX stuff goes here + */ + +static void +hscx_empty_fifo(struct HscxState *hsp, int count) +{ + byte *ptr; + struct IsdnCardState *sp = hsp->sp; + struct BufHeader *ibh = hsp->rcvibh; + long flags; + + if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO)) + debugl1(sp, "hscx_empty_fifo"); + + if (hsp->rcvptr + count > BUFFER_SIZE(HSCX_RBUF_ORDER, + HSCX_RBUF_BPPS)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "hscx_empty_fifo: incoming packet too large"); + writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80); + return; + } + ptr = DATAPTR(ibh); + ptr += hsp->rcvptr; + + hsp->rcvptr += count; + save_flags(flags); + cli(); + read_fifo_hscx(sp->cfg_reg, hsp->hscx, ptr, count); + writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80); + restore_flags(flags); + if (sp->debug & L1_DEB_HSCX_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "hscx_empty_fifo %c cnt %d", + hsp->hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static void +hscx_fill_fifo(struct HscxState *hsp) +{ + struct IsdnCardState *sp = hsp->sp; + struct BufHeader *ibh; + int more, count; + byte *ptr; + long flags; + + if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO)) + debugl1(sp, "hscx_fill_fifo"); + + ibh = hsp->xmtibh; + if (!ibh) + return; + + count = ibh->datasize - hsp->sendptr; + if (count <= 0) + return; + + more = (hsp->mode == 1) ? 1 : 0; + if (count > 32) { + more = !0; + count = 32; + } + ptr = DATAPTR(ibh); + ptr += hsp->sendptr; + hsp->sendptr += count; + + waitforXFW(sp->cfg_reg, hsp->hscx); + save_flags(flags); + cli(); + write_fifo_hscx(sp->cfg_reg, hsp->hscx, ptr, count); + writehscxCMDR(sp->cfg_reg, hsp->hscx, more ? 0x8 : 0xa); + restore_flags(flags); + if (sp->debug & L1_DEB_HSCX_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "hscx_fill_fifo %c cnt %d", + hsp->hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static inline void +hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx) +{ + byte r; + struct HscxState *hsp = sp->hs + hscx; + int count, err; + char tmp[32]; + + if (!hsp->init) + return; + + if (val & 0x80) { /* RME */ + + r = readhscx(sp->cfg_reg, hsp->hscx, HSCX_RSTA); + if ((r & 0xf0) != 0xa0) { + if (!r & 0x80) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX invalid frame"); + if ((r & 0x40) && hsp->mode) + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "HSCX RDO mode=%d", + hsp->mode); + debugl1(sp, tmp); + } + if (!r & 0x20) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX CRC error"); + if (hsp->rcvibh) + BufPoolRelease(hsp->rcvibh); + hsp->rcvibh = NULL; + writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80); + goto afterRME; + } + if (!hsp->rcvibh) + if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool, + GFP_ATOMIC, (void *) 1, 1)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX RME out of buffers"); + writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80); + goto afterRME; + } else + hsp->rcvptr = 0; + + count = readhscx(sp->cfg_reg, hsp->hscx, HSCX_RBCL) & 0x1f; + if (count == 0) + count = 32; + hscx_empty_fifo(hsp, count); + hsp->rcvibh->datasize = hsp->rcvptr - 1; + BufQueueLink(&hsp->rq, hsp->rcvibh); + hsp->rcvibh = NULL; + hscx_sched_event(hsp, HSCX_RCVBUFREADY); + } + afterRME: + if (val & 0x40) { /* RPF */ + if (!hsp->rcvibh) { + if (hsp->mode == 1) + err = BufPoolGet(&hsp->rcvibh, &hsp->smallpool, + GFP_ATOMIC, (void *) 1, 2); + else + err = BufPoolGet(&hsp->rcvibh, &hsp->rbufpool, + GFP_ATOMIC, (void *) 1, 2); + + if (err) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX RPF out of buffers"); + writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80); + goto afterRPF; + } else + hsp->rcvptr = 0; + } + hscx_empty_fifo(hsp, 32); + if (hsp->mode == 1) { + /* receive audio data */ + hsp->rcvibh->datasize = hsp->rcvptr; + BufQueueLink(&hsp->rq, hsp->rcvibh); + hsp->rcvibh = NULL; + hscx_sched_event(hsp, HSCX_RCVBUFREADY); + } + } + afterRPF: + if (val & 0x10) { /* XPR */ + if (hsp->xmtibh) + if (hsp->xmtibh->datasize > hsp->sendptr) { + hscx_fill_fifo(hsp); + goto afterXPR; + } else { + if (hsp->releasebuf) + BufPoolRelease(hsp->xmtibh); + hsp->sendptr = 0; + if (hsp->st->l4.l1writewakeup) + hsp->st->l4.l1writewakeup(hsp->st); + hsp->xmtibh = NULL; + } + if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) { + hsp->releasebuf = !0; + hscx_fill_fifo(hsp); + } else + hscx_sched_event(hsp, HSCX_XMTBUFREADY); + } + afterXPR: +} + +/* + * ISAC stuff goes here + */ + +static void +isac_empty_fifo(struct IsdnCardState *sp, int count) +{ + byte *ptr; + struct BufHeader *ibh = sp->rcvibh; + long flags; + + if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO)) + debugl1(sp, "isac_empty_fifo"); + + if (sp->rcvptr >= 3072) { + if (sp->debug & L1_DEB_WARN) { + char tmp[40]; + sprintf(tmp, "isac_empty_fifo rcvptr %d", sp->rcvptr); + debugl1(sp, tmp); + } + return; + } + ptr = DATAPTR(ibh); + ptr += sp->rcvptr; + sp->rcvptr += count; + + save_flags(flags); + cli(); + read_fifo_isac(sp->cfg_reg, ptr, count); + writeisac(sp->cfg_reg, ISAC_CMDR, 0x80); + restore_flags(flags); + if (sp->debug & L1_DEB_ISAC_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "isac_empty_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static void +isac_fill_fifo(struct IsdnCardState *sp) +{ + struct BufHeader *ibh; + int count, more; + byte *ptr; + long flags; + + if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO)) + debugl1(sp, "isac_fill_fifo"); + + ibh = sp->xmtibh; + if (!ibh) + return; + + count = ibh->datasize - sp->sendptr; + if (count <= 0) + return; + if (count >= 3072) + return; + + more = 0; + if (count > 32) { + more = !0; + count = 32; + } + ptr = DATAPTR(ibh); + ptr += sp->sendptr; + sp->sendptr += count; + + save_flags(flags); + cli(); + write_fifo_isac(sp->cfg_reg, ptr, count); + writeisac(sp->cfg_reg, ISAC_CMDR, more ? 0x8 : 0xa); + restore_flags(flags); + if (sp->debug & L1_DEB_ISAC_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "isac_fill_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static void +ph_command(struct IsdnCardState *sp, unsigned int command) +{ + if (sp->debug & L1_DEB_ISAC) { + char tmp[32]; + sprintf(tmp, "ph_command %d", command); + debugl1(sp, tmp); + } + writeisac(sp->cfg_reg, ISAC_CIX0, (command << 2) | 3); +} + +static inline void +isac_interrupt(struct IsdnCardState *sp, byte val) +{ + byte exval, v1; + unsigned int count; + char tmp[32]; +#if ARCOFI_USE + struct BufHeader *ibh; + byte *ptr; +#endif + + if (sp->debug & L1_DEB_ISAC) { + sprintf(tmp, "ISAC interrupt %x", val); + debugl1(sp, tmp); + } + if (val & 0x80) { /* RME */ + exval = readisac(sp->cfg_reg, ISAC_RSTA); + if ((exval & 0x70) != 0x20) { + if (exval & 0x40) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RDO"); + if (!exval & 0x20) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC CRC error"); + if (sp->rcvibh) + BufPoolRelease(sp->rcvibh); + sp->rcvibh = NULL; + writeisac(sp->cfg_reg, ISAC_CMDR, 0x80); + goto afterRME; + } + if (!sp->rcvibh) + if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool), + GFP_ATOMIC, (void *) 1, 3)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RME out of buffers!"); + writeisac(sp->cfg_reg, ISAC_CMDR, 0x80); + goto afterRME; + } else + sp->rcvptr = 0; + count = readisac(sp->cfg_reg, ISAC_RBCL) & 0x1f; + if (count == 0) + count = 32; + isac_empty_fifo(sp, count); + sp->rcvibh->datasize = sp->rcvptr; + BufQueueLink(&(sp->rq), sp->rcvibh); + sp->rcvibh = NULL; + isac_sched_event(sp, ISAC_RCVBUFREADY); + } + afterRME: + if (val & 0x40) { /* RPF */ + if (!sp->rcvibh) + if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool), + GFP_ATOMIC, (void *) 1, 4)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RME out of buffers!"); + writeisac(sp->cfg_reg, ISAC_CMDR, 0x80); + goto afterRPF; + } else + sp->rcvptr = 0; + isac_empty_fifo(sp, 32); + } + afterRPF: + if (val & 0x20) { /* RSC */ + /* never */ + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RSC interrupt"); + } + if (val & 0x10) { /* XPR */ + if (sp->xmtibh) + if (sp->xmtibh->datasize > sp->sendptr) { + isac_fill_fifo(sp); + goto afterXPR; + } else { + if (sp->releasebuf) + BufPoolRelease(sp->xmtibh); + sp->xmtibh = NULL; + sp->sendptr = 0; + } + if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) { + sp->releasebuf = !0; + isac_fill_fifo(sp); + } else + isac_sched_event(sp, ISAC_XMTBUFREADY); + } + afterXPR: + if (val & 0x04) { /* CISQ */ + sp->ph_state = (readisac(sp->cfg_reg, ISAC_CIX0) >> 2) + & 0xf; + if (sp->debug & L1_DEB_ISAC) { + sprintf(tmp, "l1state %d", sp->ph_state); + debugl1(sp, tmp); + } + isac_new_ph(sp); + } + if (val & 0x02) { /* SIN */ + /* never */ + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC SIN interrupt"); + } + if (val & 0x01) { /* EXI */ + exval = readisac(sp->cfg_reg, ISAC_EXIR); + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "ISAC EXIR %02x", exval); + debugl1(sp, tmp); + } + if (exval & 0x08) { + v1 = readisac(sp->cfg_reg, ISAC_MOSR); + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "ISAC MOSR %02x", v1); + debugl1(sp, tmp); + } +#if ARCOFI_USE + if (v1 & 0x08) { + if (!sp->mon_rx) + if (BufPoolGet(&(sp->mon_rx), &(sp->rbufpool), + GFP_ATOMIC, (void *) 1, 3)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC MON RX out of buffers!"); + writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a); + goto afterMONR0; + } else + sp->mon_rxp = 0; + ibh = sp->mon_rx; + ptr = DATAPTR(ibh); + ptr += sp->mon_rxp; + sp->mon_rxp++; + if (sp->mon_rxp >= 3072) { + writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a); + sp->mon_rxp = 0; + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC MON RX overflow!"); + goto afterMONR0; + } + *ptr = readisac(sp->cfg_reg, ISAC_MOR0); + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "ISAC MOR0 %02x", *ptr); + debugl1(sp, tmp); + } + } + afterMONR0: + if (v1 & 0x80) { + if (!sp->mon_rx) + if (BufPoolGet(&(sp->mon_rx), &(sp->rbufpool), + GFP_ATOMIC, (void *) 1, 3)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC MON RX out of buffers!"); + writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0); + goto afterMONR1; + } else + sp->mon_rxp = 0; + ibh = sp->mon_rx; + ptr = DATAPTR(ibh); + ptr += sp->mon_rxp; + sp->mon_rxp++; + if (sp->mon_rxp >= 3072) { + writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0); + sp->mon_rxp = 0; + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC MON RX overflow!"); + goto afterMONR1; + } + *ptr = readisac(sp->cfg_reg, ISAC_MOR1); + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "ISAC MOR1 %02x", *ptr); + debugl1(sp, tmp); + } + } + afterMONR1: + if (v1 & 0x04) { + writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a); + sp->mon_rx->datasize = sp->mon_rxp; + sp->mon_flg |= MON0_RX; + } + if (v1 & 0x40) { + writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0); + sp->mon_rx->datasize = sp->mon_rxp; + sp->mon_flg |= MON1_RX; + } + if (v1 == 0x02) { + ibh = sp->mon_tx; + if (!ibh) { + writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a); + goto AfterMOX0; + } + count = ibh->datasize - sp->mon_txp; + if (count <= 0) { + writeisac(sp->cfg_reg, ISAC_MOCR, 0x0f); + BufPoolRelease(sp->mon_tx); + sp->mon_tx = NULL; + sp->mon_txp = 0; + sp->mon_flg |= MON0_TX; + goto AfterMOX0; + } + ptr = DATAPTR(ibh); + ptr += sp->mon_txp; + sp->mon_txp++; + writeisac(sp->cfg_reg, ISAC_MOX0, *ptr); + } + AfterMOX0: + if (v1 == 0x20) { + ibh = sp->mon_tx; + if (!ibh) { + writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0); + goto AfterMOX1; + } + count = ibh->datasize - sp->mon_txp; + if (count <= 0) { + writeisac(sp->cfg_reg, ISAC_MOCR, 0xf0); + BufPoolRelease(sp->mon_tx); + sp->mon_tx = NULL; + sp->mon_txp = 0; + sp->mon_flg |= MON1_TX; + goto AfterMOX1; + } + ptr = DATAPTR(ibh); + ptr += sp->mon_txp; + sp->mon_txp++; + writeisac(sp->cfg_reg, ISAC_MOX1, *ptr); + } + AfterMOX1: +#endif + } + } +} + +static inline void +hscx_int_main(struct IsdnCardState *sp, byte val) +{ + + byte exval; + struct HscxState *hsp; + char tmp[32]; + + + if (val & 0x01) { + hsp = sp->hs + 1; + exval = readhscx(sp->cfg_reg, 1, HSCX_EXIR); + if (exval == 0x40) { + if (hsp->mode == 1) + hscx_fill_fifo(hsp); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + hsp->sendptr = 0; + writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x01); + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "HSCX B EXIR %x Lost TX", exval); + debugl1(sp, tmp); + } + } + } else if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX B EXIR %x", exval); + debugl1(sp, tmp); + } + } + if (val & 0xf8) { + if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX B interrupt %x", val); + debugl1(sp, tmp); + } + hscx_interrupt(sp, val, 1); + } + if (val & 0x02) { + hsp = sp->hs; + exval = readhscx(sp->cfg_reg, 0, HSCX_EXIR); + if (exval == 0x40) { + if (hsp->mode == 1) + hscx_fill_fifo(hsp); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + hsp->sendptr = 0; + writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x01); + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "HSCX A EXIR %x Lost TX", exval); + debugl1(sp, tmp); + } + } + } else if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX A EXIR %x", exval); + debugl1(sp, tmp); + } + } + if (val & 0x04) { + exval = readhscx(sp->cfg_reg, 0, HSCX_ISTA); + if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX A interrupt %x", exval); + debugl1(sp, tmp); + } + hscx_interrupt(sp, exval, 0); + } +} + +static void +elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *sp; + byte val, sval, stat = 0; + + sp = (struct IsdnCardState *) irq2dev_map[intno]; + + if (!sp) { + printk(KERN_WARNING "Elsa: Spurious interrupt!\n"); + return; + } + sval = bytein(sp->cfg_reg + CARD_CONFIG); + INT_RESTART: + if (!TimerRun(sp)) { + /* Timer Restart */ + bytein(sp->cfg_reg + CARD_START_TIMER); + if (!(sp->counter++ & 0x3f)) { + /* Call LEDs all 64 tics */ + elsa_led_handler(sp); + } + } + val = readhscx(sp->cfg_reg, 1, HSCX_ISTA); + Start_HSCX: + if (val) { + hscx_int_main(sp, val); + stat |= 1; + } + val = readisac(sp->cfg_reg, ISAC_ISTA); + Start_ISAC: + if (val) { + isac_interrupt(sp, val); + stat |= 2; + } + sval = bytein(sp->cfg_reg + CARD_CONFIG); + if (!TimerRun(sp)) + goto INT_RESTART; + + val = readhscx(sp->cfg_reg, 1, HSCX_ISTA); + if (val) { + if (sp->debug & L1_DEB_HSCX) + debugl1(sp, "HSCX IntStat after IntRoutine"); + goto Start_HSCX; + } + val = readisac(sp->cfg_reg, ISAC_ISTA); + if (val) { + if (sp->debug & L1_DEB_ISAC) + debugl1(sp, "ISAC IntStat after IntRoutine"); + goto Start_ISAC; + } + if (stat & 1) { + writehscx(sp->cfg_reg, 0, HSCX_MASK, 0xFF); + writehscx(sp->cfg_reg, 1, HSCX_MASK, 0xFF); + writehscx(sp->cfg_reg, 0, HSCX_MASK, 0x0); + writehscx(sp->cfg_reg, 1, HSCX_MASK, 0x0); + } + if (stat & 2) { + writeisac(sp->cfg_reg, ISAC_MASK, 0xFF); + writeisac(sp->cfg_reg, ISAC_MASK, 0x0); + } + byteout(sp->cfg_reg + 7, 0xff); +} + + +static void +initisac(struct IsdnCardState *sp) +{ + unsigned int adr = sp->cfg_reg; + + /* Elsa IOM 2 Mode */ + writeisac(adr, ISAC_MASK, 0xff); + writeisac(adr, ISAC_ADF2, 0x80); + writeisac(adr, ISAC_SQXR, 0x2f); + writeisac(adr, ISAC_SPCR, 0x00); + writeisac(adr, ISAC_STCR, 0x70); + writeisac(adr, ISAC_MODE, 0xc9); + writeisac(adr, ISAC_TIMR, 0x00); + writeisac(adr, ISAC_ADF1, 0x00); + writeisac(adr, ISAC_CIX0, (1 << 2) | 3); + writeisac(adr, ISAC_MASK, 0xff); + writeisac(adr, ISAC_MASK, 0x0); +} + +static void +modehscx(struct HscxState *hs, int mode, int ichan) +{ + struct IsdnCardState *sp = hs->sp; + int hscx = hs->hscx; + + if (sp->debug & L1_DEB_HSCX) { + char tmp[40]; + sprintf(tmp, "hscx %c mode %d ichan %d", + 'A' + hscx, mode, ichan); + debugl1(sp, tmp); + } + hs->mode = mode; + writehscx(sp->cfg_reg, hscx, HSCX_CCR1, 0x85); + writehscx(sp->cfg_reg, hscx, HSCX_XAD1, 0xFF); + writehscx(sp->cfg_reg, hscx, HSCX_XAD2, 0xFF); + writehscx(sp->cfg_reg, hscx, HSCX_RAH2, 0xFF); + writehscx(sp->cfg_reg, hscx, HSCX_XBCH, 0x0); + writehscx(sp->cfg_reg, hscx, HSCX_RLCR, 0x0); + writehscx(sp->cfg_reg, hscx, HSCX_CCR2, 0x30); + + switch (mode) { + case (0): + writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0xff); + writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0xff); + writehscx(sp->cfg_reg, hscx, HSCX_XCCR, 7); + writehscx(sp->cfg_reg, hscx, HSCX_RCCR, 7); + writehscx(sp->cfg_reg, hscx, HSCX_MODE, 0x84); + break; + case (1): + if (ichan == 0) { + writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x2f); + writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x2f); + } else { + writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x3); + writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x3); + } + writehscx(sp->cfg_reg, hscx, HSCX_XCCR, 7); + writehscx(sp->cfg_reg, hscx, HSCX_RCCR, 7); + writehscx(sp->cfg_reg, hscx, HSCX_MODE, 0xe4); + writehscx(sp->cfg_reg, hscx, HSCX_CMDR, 0x41); + break; + case (2): + if (ichan == 0) { + writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x2f); + writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x2f); + } else { + writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x3); + writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x3); + } + writehscx(sp->cfg_reg, hscx, HSCX_XCCR, 7); + writehscx(sp->cfg_reg, hscx, HSCX_RCCR, 7); + writehscx(sp->cfg_reg, hscx, HSCX_MODE, 0x8c); + writehscx(sp->cfg_reg, hscx, HSCX_CMDR, 0x41); + break; + } + writehscx(sp->cfg_reg, hscx, HSCX_ISTA, 0x00); +} + +void +release_io_elsa(struct IsdnCard *card) +{ + int bytecnt = 8; + + if (card->sp->subtyp == ELSA_PCFPRO) + bytecnt = 16; + if (card->sp->cfg_reg) + release_region(card->sp->cfg_reg, bytecnt); +} + +static void +clear_pending_ints(struct IsdnCardState *sp) +{ + writeisac(sp->cfg_reg, ISAC_MASK, 0); + writeisac(sp->cfg_reg, ISAC_CMDR, 0x41); +} + +static void +check_arcofi(struct IsdnCardState *sp) +{ +#if 0 + byte val; + char tmp[40]; + char *t; + long flags; + byte *p; + + if (BufPoolGet(&(sp->mon_tx), &(sp->sbufpool), + GFP_ATOMIC, (void *) 1, 3)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC MON TX out of buffers!"); + return; + } else + sp->mon_txp = 0; + p = DATAPTR(sp->mon_tx); + *p++ = 0xa0; + *p++ = 0x0; + sp->mon_tx->datasize = 2; + sp->mon_txp = 1; + sp->mon_flg = 0; + writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0); + val = readisac(sp->cfg_reg, ISAC_MOSR); + writeisac(sp->cfg_reg, ISAC_MOX1, 0xa0); + writeisac(sp->cfg_reg, ISAC_MOCR, 0xb0); + save_flags(flags); + sti(); + HZDELAY(3); + restore_flags(flags); + if (sp->mon_flg & MON1_TX) { + if (sp->mon_flg & MON1_RX) { + sprintf(tmp, "Arcofi response received %d bytes", sp->mon_rx->datasize); + debugl1(sp, tmp); + p = DATAPTR(sp->mon_rx); + t = tmp; + t += sprintf(tmp, "Arcofi data"); + QuickHex(t, p, sp->mon_rx->datasize); + debugl1(sp, tmp); + BufPoolRelease(sp->mon_rx); + sp->mon_rx = NULL; + sp->mon_rxp = 0; + sp->mon_flg = 0; + } + } else if (sp->mon_tx) { + BufPoolRelease(sp->mon_tx); + sp->mon_tx = NULL; + sp->mon_txp = 0; + sprintf(tmp, "Arcofi not detected"); + debugl1(sp, tmp); + } + sp->mon_flg = 0; +#endif +} + +int +initelsa(struct IsdnCardState *sp) +{ + int ret, irq_cnt; + long flags; + + sp->counter = 0; + irq_cnt = kstat.interrupts[sp->irq]; + printk(KERN_INFO "Elsa: IRQ %d count %d\n", sp->irq, irq_cnt); + clear_pending_ints(sp); + ret = get_irq(sp->cardnr, &elsa_interrupt); + if (ret) { + initisac(sp); + sp->modehscx(sp->hs, 0, 0); + sp->modehscx(sp->hs + 1, 0, 0); + save_flags(flags); + sp->counter = 0; + sti(); + byteout(sp->cfg_reg + CARD_CONTROL, ISDN_RESET | ENABLE_TIM_INT); + bytein(sp->cfg_reg + CARD_START_TIMER); + HZDELAY(11); /* Warte 110 ms */ + restore_flags(flags); + printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n", + sp->counter); + if (abs(sp->counter - 12) < 3) { + printk(KERN_INFO "Elsa: timer and irq OK\n"); + } else { + printk(KERN_WARNING + "Elsa: timer problem maybe an IRQ(%d) conflict\n", + sp->irq); + } + printk(KERN_INFO "Elsa: IRQ %d count %d\n", sp->irq, + kstat.interrupts[sp->irq]); + if (kstat.interrupts[sp->irq] == irq_cnt) { + printk(KERN_WARNING + "Elsa: IRQ(%d) getting no interrupts during init\n", + sp->irq); + irq2dev_map[sp->irq] = NULL; + free_irq(sp->irq, NULL); + return (0); + } + check_arcofi(sp); + } + sp->counter = 0; + return (ret); +} + +static unsigned char +probe_elsa_adr(unsigned int adr) +{ + int i, in1, in2, p16_1 = 0, p16_2 = 0, pcc_1 = 0, pcc_2 = 0, + pfp_1 = 0, pfp_2 = 0; + long flags; + + if (check_region(adr, 8)) { + printk(KERN_WARNING + "Elsa: Probing Port 0x%x: already in use\n", + adr); + return (0); + } + save_flags(flags); + cli(); + for (i = 0; i < 16; i++) { + in1 = inb(adr + CARD_CONFIG); /* 'toggelt' bei */ + in2 = inb(adr + CARD_CONFIG); /* jedem Zugriff */ + p16_1 += 0x04 & in1; + p16_2 += 0x04 & in2; + pcc_1 += 0x01 & in1; + pcc_2 += 0x01 & in2; + pfp_1 += 0x40 & in1; + pfp_2 += 0x40 & in2; + } + restore_flags(flags); + printk(KERN_INFO "Elsa: Probing IO 0x%x", adr); + if (65 == ++p16_1 * ++p16_2) { + printk(" PCC-16/PCF found\n"); + return (3); + } else if (1025 == ++pfp_1 * ++pfp_2) { + printk(" PCF-Pro found\n"); + return (2); + } else if (17 == ++pcc_1 * ++pcc_2) { + printk(" PCC8 found\n"); + return (1); + } else { + printk(" failed\n"); + return (0); + } +} + +static unsigned int +probe_elsa(struct IsdnCardState *sp) +{ + int i; + unsigned int CARD_portlist[] = + {0x160, 0x170, 0x260, 0x360, 0}; + + for (i = 0; CARD_portlist[i]; i++) { + if ((sp->subtyp = probe_elsa_adr(CARD_portlist[i]))) + break; + } + return (CARD_portlist[i]); +} + +int +setup_elsa(struct IsdnCard *card) +{ + long flags; + int bytecnt; + byte val, verA, verB; + struct IsdnCardState *sp = card->sp; + char tmp[64]; + + strcpy(tmp, Elsa_revision); + printk(KERN_NOTICE "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp)); + if (sp->typ == ISDN_CTYPE_ELSA) { + sp->cfg_reg = card->para[0]; + printk(KERN_INFO "Elsa: Mircolink IO probing\n"); + if (sp->cfg_reg) { + if (!(sp->subtyp = probe_elsa_adr(sp->cfg_reg))) { + printk(KERN_WARNING + "Elsa: no Elsa Mircolink at 0x%x\n", + sp->cfg_reg); + return (0); + } + } else + sp->cfg_reg = probe_elsa(sp); + if (sp->cfg_reg) { + val = bytein(sp->cfg_reg + CARD_CONFIG); + if (sp->subtyp == ELSA_PCC) { + const byte CARD_IrqTab[8] = + {7, 3, 5, 9, 0, 0, 0, 0}; + sp->irq = CARD_IrqTab[(val & 0x0c) >> 2]; + } else { + const byte CARD_IrqTab[8] = + {15, 10, 15, 3, 11, 5, 11, 9}; + sp->irq = CARD_IrqTab[(val & 0x38) >> 3]; + } + val = bytein(sp->cfg_reg + CARD_ALE) & 0x7; + if (val < 3) + val |= 8; + val += 'A' - 3; + if (val == 'B' || val == 'C') + val ^= 1; + if ((sp->subtyp == ELSA_PCFPRO) && (val = 'G')) + val = 'C'; + printk(KERN_INFO + "Elsa: %s found at 0x%x Rev.:%c IRQ %d\n", + Elsa_Types[sp->subtyp], + sp->cfg_reg, + val, sp->irq); + val = bytein(sp->cfg_reg + CARD_ALE) & 0x08; + if (val) + printk(KERN_WARNING + "Elsa: Mircolink S0 bus power bad\n"); + } else { + printk(KERN_WARNING + "No Elsa Mircolink found\n"); + return (0); + } + } else if (sp->typ == ISDN_CTYPE_ELSA_QS1000) { + sp->cfg_reg = card->para[1]; + sp->irq = card->para[0]; + sp->subtyp = ELSA_QS1000; + } else + return (0); + + switch (sp->subtyp) { + case ELSA_PCC: + bytecnt = 8; + break; + case ELSA_PCFPRO: + bytecnt = 16; + break; + case ELSA_PCC16: + bytecnt = 8; + break; + case ELSA_PCF: + bytecnt = 16; + break; + case ELSA_QS1000: + bytecnt = 8; + break; + default: + printk(KERN_WARNING + "Unknown ELSA subtype %d\n", sp->subtyp); + return (0); + } + + if (check_region((sp->cfg_reg), bytecnt)) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + sp->cfg_reg, + sp->cfg_reg + bytecnt); + return (0); + } else { + request_region(sp->cfg_reg, bytecnt, "elsa isdn"); + } + + /* Teste Timer */ + bytein(sp->cfg_reg + CARD_START_TIMER); + if (!TimerRun(sp)) { + bytein(sp->cfg_reg + CARD_START_TIMER); /* 2. Versuch */ + if (!TimerRun(sp)) { + printk(KERN_WARNING + "Elsa: timer do not start\n"); + release_io_elsa(card); + return (0); + } + } + save_flags(flags); + sti(); + HZDELAY(1); /* wait >=10 ms */ + restore_flags(flags); + if (TimerRun(sp)) { + printk(KERN_WARNING "Elsa: timer do not run down\n"); + release_io_elsa(card); + return (0); + } + printk(KERN_INFO "Elsa: timer OK; resetting card\n"); + /* Wait 1 Timer */ + bytein(sp->cfg_reg + CARD_START_TIMER); + while (TimerRun(sp)); + byteout(sp->cfg_reg + CARD_CONTROL, 0x00); /* Reset On */ + /* Wait 1 Timer */ + bytein(sp->cfg_reg + CARD_START_TIMER); + while (TimerRun(sp)); + byteout(sp->cfg_reg + CARD_CONTROL, ISDN_RESET); /* Reset Off */ + /* Wait 1 Timer */ + bytein(sp->cfg_reg + CARD_START_TIMER); + while (TimerRun(sp)); + + verA = readhscx(sp->cfg_reg, 0, HSCX_VSTR) & 0xf; + verB = readhscx(sp->cfg_reg, 1, HSCX_VSTR) & 0xf; + printk(KERN_INFO "Elsa: HSCX version A: %s B: %s\n", + HscxVersion(verA), HscxVersion(verB)); + val = readisac(sp->cfg_reg, ISAC_RBCH); + printk(KERN_INFO "Elsa: ISAC %s\n", + ISACVersion(val)); + + sp->modehscx = &modehscx; + sp->ph_command = &ph_command; + sp->hscx_fill_fifo = &hscx_fill_fifo; + sp->isac_fill_fifo = &isac_fill_fifo; + + return (1); +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/elsa.h linux/drivers/isdn/hisax/elsa.h --- v2.1.26/linux/drivers/isdn/hisax/elsa.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/elsa.h Tue Feb 25 17:12:49 1997 @@ -0,0 +1,63 @@ +/* $Id: elsa.h,v 1.4 1997/01/21 22:21:05 keil Exp $ + * + * elsa.h Header for Elsa ISDN cards + * + * Author Karsten Keil (keil@temic-ech.spacenet.de) + * + * Thanks to Elsa GmbH for documents and informations + * + * + * $Log: elsa.h,v $ + * Revision 1.4 1997/01/21 22:21:05 keil + * Elsa Quickstep support + * + * Revision 1.3 1996/12/08 19:47:38 keil + * ARCOFI support + * + * Revision 1.2 1996/11/18 15:33:35 keil + * PCC and PCFPro support + * + * Revision 1.1 1996/10/13 20:03:45 keil + * Initial revision + * + * +*/ + +#define CARD_ISAC 0 +#define CARD_HSCX 2 +#define CARD_ALE 3 +#define CARD_CONTROL 4 +#define CARD_CONFIG 5 +#define CARD_START_TIMER 6 +#define CARD_TRIG_IRQ 7 + +#define ELSA_PCC 1 +#define ELSA_PCFPRO 2 +#define ELSA_PCC16 3 +#define ELSA_PCF 4 +#define ELSA_QS1000 5 + +/*** *** + *** Makros als Befehle fuer die Kartenregister *** + *** (mehrere Befehle werden durch Bit-Oderung kombiniert) *** + *** ***/ + +/* Config-Register (Read) */ +#define TIMER_RUN 0x02 /* Bit 1 des Config-Reg */ +#define TIMER_RUN_PCC 0x01 /* Bit 0 des Config-Reg bei PCC */ +#define IRQ_INDEX 0x38 /* Bit 3,4,5 des Config-Reg */ + +/* Control-Register (Write) */ +#define LINE_LED 0x02 /* Bit 1 Gelbe LED */ +#define STAT_LED 0x08 /* Bit 3 Gruene LED */ +#define ISDN_RESET 0x20 /* Bit 5 Reset-Leitung */ +#define ENABLE_TIM_INT 0x80 /* Bit 7 Freigabe Timer Interrupt */ + +/* ALE-Register (Read) */ +#define HW_RELEASE 0x07 /* Bit 0-2 Hardwarerkennung */ +#define S0_POWER_BAD 0x08 /* Bit 3 S0-Bus Spannung fehlt */ + +extern void elsa_report(struct IsdnCardState *sp); +extern void release_io_elsa(struct IsdnCard *card); +extern int setup_elsa(struct IsdnCard *card); +extern int initelsa(struct IsdnCardState *sp); diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/fsm.c linux/drivers/isdn/hisax/fsm.c --- v2.1.26/linux/drivers/isdn/hisax/fsm.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/fsm.c Tue Feb 25 17:12:49 1997 @@ -0,0 +1,180 @@ +/* $Id: fsm.c,v 1.3 1997/02/16 01:04:08 fritz Exp $ + * + * Author Karsten Keil (keil@temic-ech.spacenet.de) + * based on the teles driver from Jan den Ouden + * + * Thanks to Jan den Ouden + * Fritz Elfert + * + * $Log: fsm.c,v $ + * Revision 1.3 1997/02/16 01:04:08 fritz + * Bugfix: Changed timer handling caused hang with 2.1.X + * + * Revision 1.2 1997/01/09 20:57:27 keil + * cleanup & FSM_TIMER_DEBUG + * + * Revision 1.1 1996/10/13 20:04:52 keil + * Initial revision + * + * + */ +#define __NO_VERSION__ +#include "hisax.h" + +#define FSM_TIMER_DEBUG 0 + +void +FsmNew(struct Fsm *fsm, + struct FsmNode *fnlist, int fncount) +{ + int i; + + fsm->jumpmatrix = (int *) Smalloc(4L * fsm->state_count * fsm->event_count, + GFP_KERNEL, "Fsm jumpmatrix"); + memset(fsm->jumpmatrix, 0, 4L * fsm->state_count * fsm->event_count); + + for (i = 0; i < fncount; i++) + fsm->jumpmatrix[fsm->state_count * fnlist[i].event + + fnlist[i].state] = (int) fnlist[i].routine; +} + +void +FsmFree(struct Fsm *fsm) +{ + Sfree((void *) fsm->jumpmatrix); +} + +int +FsmEvent(struct FsmInst *fi, int event, void *arg) +{ + void (*r) (struct FsmInst *, int, void *); + char str[80]; + + r = (void (*)) fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state]; + if (r) { + if (fi->debug) { + sprintf(str, "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", + fi->fsm->strState[fi->state], + fi->fsm->strEvent[event]); + fi->printdebug(fi, str); + } + return (!0); + } +} + +void +FsmChangeState(struct FsmInst *fi, int newstate) +{ + char str[80]; + + fi->state = newstate; + if (fi->debug) { + sprintf(str, "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); + } +#endif + FsmEvent(ft->fi, ft->event, ft->arg); +} + +void +FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft) +{ + ft->fi = fi; + 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); + } +#endif + init_timer(&ft->tl); +} + +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); + } +#endif + del_timer(&ft->tl); +} + +int +FsmAddTimer(struct FsmTimer *ft, + int millisec, int event, void *arg, int where) +{ + +#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); + } +#endif + + if (ft->tl.next || ft->tl.prev) { + printk(KERN_WARNING "FsmAddTimer: timer already active!\n"); + ft->fi->printdebug(ft->fi, "FsmAddTimer already active!"); + return -1; + } + init_timer(&ft->tl); + ft->event = event; + ft->arg = arg; + ft->tl.expires = jiffies + (millisec * HZ) / 1000; + add_timer(&ft->tl); + return 0; +} + +int +FsmTimerRunning(struct FsmTimer *ft) +{ + return (ft->tl.next != NULL); +} + +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 -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h --- v2.1.26/linux/drivers/isdn/hisax/hisax.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/hisax.h Tue Feb 25 17:12:49 1997 @@ -0,0 +1,612 @@ +/* $Id: hisax.h,v 1.11 1997/02/11 01:36:02 keil Exp $ + + * Basic declarations, defines and prototypes + * + * $Log: hisax.h,v $ + * Revision 1.11 1997/02/11 01:36:02 keil + * New Param structure + * + * Revision 1.10 1997/02/09 00:23:52 keil + * new interface handling, one interface per card + * + * Revision 1.9 1997/01/27 23:18:44 keil + * prototype for releasestack_isdnl3 + * + * Revision 1.8 1997/01/27 16:02:37 keil + * new cards, callc timers, HZDELAY macro, HiSax_getrev prototype + * + * Revision 1.7 1997/01/21 22:22:14 keil + * changes for 2.0; Elsa Quickstep support + * + * Revision 1.6 1997/01/04 13:48:28 keil + * primitiv for MDL_REMOVE added + * + * Revision 1.5 1996/12/08 19:49:19 keil + * Monitor channel support + * + * Revision 1.4 1996/11/18 15:35:39 keil + * some changes for ELSA cards + * + * Revision 1.3 1996/11/05 19:37:23 keil + * using config.h + * + * Revision 1.2 1996/10/27 22:21:52 keil + * CallFlags for broadcast messages + * + * Revision 1.1 1996/10/13 20:03:46 keil + * Initial revision + * + * + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PH_ACTIVATE 1 +#define PH_DATA 2 +#define PH_DEACTIVATE 3 + +#define MDL_ASSIGN 4 +#define DL_UNIT_DATA 5 +#define SC_STARTUP 6 +#define CC_ESTABLISH 7 +#define DL_ESTABLISH 8 +#define DL_DATA 9 +#define CC_S_STATUS_ENQ 10 + +#define CC_CONNECT 15 +#define CC_CONNECT_ACKNOWLEDGE 16 +#define CO_EOF 17 +#define SC_DISCONNECT 18 +#define CO_DTMF 19 +#define DL_RELEASE 20 +#define DL_FLUSH 21 + +#define CO_ALARM 22 +#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_NOTEIPROC 46 + +#define LC_ESTABLISH 47 +#define LC_RELEASE 48 + +#define PH_REQUEST_PULL 49 +#define PH_PULL_ACK 50 +#define PH_DATA_PULLED 51 +#define CC_INFO_CHARGE 52 + +#define CC_MORE_INFO 53 +#define CC_IGNORE 54 + +#define MDL_REMOVE 56 +#define MDL_VERIFY 57 + +#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 + +/* + * Message-Types + */ + +#define MT_ALERTING 0x01 +#define MT_CALL_PROCEEDING 0x02 +#define MT_CONNECT 0x07 +#define MT_CONNECT_ACKNOWLEDGE 0x0f +#define MT_PROGRESS 0x03 +#define MT_SETUP 0x05 +#define MT_SETUP_ACKNOWLEDGE 0x0d +#define MT_RESUME 0x26 +#define MT_RESUME_ACKNOWLEDGE 0x2e +#define MT_RESUME_REJECT 0x22 +#define MT_SUSPEND 0x25 +#define MT_SUSPEND_ACKNOWLEDGE 0x2d +#define MT_SUSPEND_REJECT 0x21 +#define MT_USER_INFORMATION 0x20 +#define MT_DISCONNECT 0x45 +#define MT_RELEASE 0x4d +#define MT_RELEASE_COMPLETE 0x5a +#define MT_RESTART 0x46 +#define MT_RESTART_ACKNOWLEDGE 0x4e +#define MT_SEGMENT 0x60 +#define MT_CONGESTION_CONTROL 0x79 +#define MT_INFORMATION 0x7b +#define MT_FACILITY 0x62 +#define MT_NOTIFY 0x6e +#define MT_STATUS 0x7d +#define MT_STATUS_ENQUIRY 0x75 + +#define IE_CAUSE 0x08 + +struct HscxIoctlArg { + int channel; + int mode; + int transbufsize; +}; + +#ifdef __KERNEL__ + +#undef DEBUG_MAGIC + +#define HSCX_SBUF_ORDER 1 +#define HSCX_SBUF_BPPS 2 +#define HSCX_SBUF_MAXPAGES 3 + +#define HSCX_RBUF_ORDER 1 +#define HSCX_RBUF_BPPS 2 +#define HSCX_RBUF_MAXPAGES 3 + +#define HSCX_SMALLBUF_ORDER 0 +#define HSCX_SMALLBUF_BPPS 40 +#define HSCX_SMALLBUF_MAXPAGES 1 + +#define ISAC_SBUF_ORDER 0 +#define ISAC_SBUF_BPPS 16 +#define ISAC_SBUF_MAXPAGES 1 + +#define ISAC_RBUF_ORDER 0 +#define ISAC_RBUF_BPPS 16 +#define ISAC_RBUF_MAXPAGES 1 + +#define ISAC_SMALLBUF_ORDER 0 +#define ISAC_SMALLBUF_BPPS 40 +#define ISAC_SMALLBUF_MAXPAGES 1 + +#define byte unsigned char + +#define MAX_WINDOW 8 + +byte *Smalloc(int size, int pr, char *why); +void Sfree(byte * ptr); + +/* + * Statemachine + */ +struct Fsm { + int *jumpmatrix; + int state_count, event_count; + char **strEvent, **strState; +}; + +struct FsmInst { + struct Fsm *fsm; + int state; + int debug; + void *userdata; + int userint; + void (*printdebug) (struct FsmInst *, char *); +}; + +struct FsmNode { + int state, event; + void (*routine) (struct FsmInst *, int, void *); +}; + +struct FsmTimer { + struct FsmInst *fi; + struct timer_list tl; + int event; + void *arg; +}; + +struct L3Timer { + struct PStack *st; + struct timer_list tl; + int event; +}; + +struct BufHeader { +#ifdef DEBUG_MAGIC + int magic; +#endif + struct BufHeader *next; + struct BufPool *bp; + int datasize; + byte primitive, where; + void *heldby; +}; + +struct Pages { + struct Pages *next; +}; + +struct BufPool { +#ifdef DEBUG_MAGIC + int magic; +#endif + struct BufHeader *freelist; + struct Pages *pageslist; + int pageorder; + int pagescount; + int bpps; + int bufsize; + int maxpages; +}; + +struct BufQueue { +#ifdef DEBUG_MAGIC + int magic; +#endif + struct BufHeader *head, *tail; +}; + +struct Layer1 { + void *hardware; + int hscx; + struct BufPool *sbufpool, *rbufpool, *smallpool; + struct PStack **stlistp; + int act_state; + void (*l1l2) (struct PStack *, int, struct BufHeader *); + void (*l1man) (struct PStack *, int, void *); + int hscxmode, hscxchannel, requestpull; +}; + +struct Layer2 { + int sap, tei, ces; + int extended, laptype; + int uihsize, ihsize; + int vs, va, vr; + struct BufQueue i_queue; + int window, orig; + int rejexp; + int debug; + struct BufHeader *windowar[MAX_WINDOW]; + int sow; + struct FsmInst l2m; + void (*l2l1) (struct PStack *, int, struct BufHeader *); + void (*l2l1discardq) (struct PStack *, int, void *, int); + void (*l2man) (struct PStack *, int, void *); + void (*l2l3) (struct PStack *, int, void *); + void (*l2tei) (struct PStack *, int, void *); + struct FsmTimer t200_timer, t203_timer; + int t200, n200, t203; + int rc, t200_running; + char debug_id[32]; +}; + +struct Layer3 { + void (*l3l4) (struct PStack *, int, struct BufHeader *); + void (*l3l2) (struct PStack *, int, void *); + int state, callref; + struct L3Timer timer; + int t303, t304, t305, t308, t310, t313, t318, t319; + int n_t303; + int debug; + int channr; +}; + +struct Layer4 { + void (*l4l3) (struct PStack *, int, void *); + void *userdata; + void (*l1writewakeup) (struct PStack *); + void (*l2writewakeup) (struct PStack *); +}; + +struct Management { + void (*manl1) (struct PStack *, int, void *); + void (*manl2) (struct PStack *, int, void *); + void (*teil2) (struct PStack *, int, void *); +}; + +struct Param { + int cause; + int loc; + int bchannel; + int callref; /* Callreferenz Number */ + setup_parm setup; /* from isdnif.h numbers and Serviceindicator */ + int chargeinfo; /* Charge Info - only for 1tr6 in + * the moment + */ + int spv; /* SPV Flag */ +}; + +struct PStack { + struct PStack *next; + struct Layer1 l1; + struct Layer2 l2; + struct Layer3 l3; + struct Layer4 l4; + struct Management ma; + struct Param *pa; + int protocol; /* EDSS1 or 1TR6 */ +}; + +struct HscxState { + int inuse, init, active; + struct BufPool sbufpool, rbufpool, smallpool; + struct IsdnCardState *sp; + int hscx, mode; + int transbufsize, receive; + struct BufHeader *rcvibh, *xmtibh; + int rcvptr, sendptr; + struct PStack *st; + struct tq_struct tqueue; + int event; + struct BufQueue rq, sq; + int releasebuf; +#ifdef DEBUG_MAGIC + int magic; /* 301270 */ +#endif +}; + +struct LcFsm { + struct FsmInst lcfi; + int type; + 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 ds, is; + struct IsdnCardState *sp; + int hscx; + int chan; + int incoming; + struct FsmInst fi; + struct LcFsm lc_d, lc_b; + struct Param para; + struct FsmTimer drel_timer, dial_timer; + int debug; +#ifdef DEBUG_MAGIC + int magic; /* 301272 */ +#endif + int l2_protocol, l2_active_protocol; + int l2_primitive, l2_headersize; + int data_open; + int outcallref; + int impair; + int Flags; /* for remembering action done in l4 */ + int leased; +}; + +struct IsdnCardState { +#ifdef DEBUG_MAGIC + int magic; +#endif + unsigned char typ; + unsigned char subtyp; + int protocol; + unsigned int irq; + unsigned int cfg_reg; + unsigned int membase; + unsigned int isac; + unsigned int hscx[2]; + unsigned int counter; + int myid; + isdn_if iif; + byte *status_buf; + byte *status_read; + byte *status_write; + byte *status_end; + struct BufHeader *mon_rx, *mon_tx; + int mon_rxp, mon_txp, mon_flg; + void (*ph_command) (struct IsdnCardState *, unsigned int); + void (*modehscx) (struct HscxState *, int, int); + void (*hscx_fill_fifo) (struct HscxState *); + void (*isac_fill_fifo) (struct IsdnCardState *); + struct BufPool sbufpool, rbufpool, smallpool; + struct Channel channel[2]; + struct PStack *stlist; + struct BufHeader *xmtibh, *rcvibh; + int rcvptr, sendptr; + int event; + struct tq_struct tqueue; + int ph_active; + struct BufQueue rq, sq; + int cardnr; + int ph_state; + struct PStack *teistack; + struct HscxState hs[2]; + int dlogflag; + char *dlogspace; + int debug; + int releasebuf; + unsigned int CallFlags; +}; + +#define MON0_RX 1 +#define MON1_RX 2 +#define MON0_TX 4 +#define MON1_TX 8 + +#define ISDN_CTYPE_16_0 1 +#define ISDN_CTYPE_8_0 2 +#define ISDN_CTYPE_16_3 3 +#define ISDN_CTYPE_PNP 4 +#define ISDN_CTYPE_A1 5 +#define ISDN_CTYPE_ELSA 6 +#define ISDN_CTYPE_ELSA_QS1000 7 +#define ISDN_CTYPE_TELESPCMCIA 8 +#define ISDN_CTYPE_IX1MICROR2 9 + +#define ISDN_CTYPE_COUNT 9 + +#ifdef CONFIG_HISAX_16_0 +#define CARD_TELES0 (1<< ISDN_CTYPE_16_0) | (1<< ISDN_CTYPE_8_0) +#else +#define CARD_TELES0 0 +#endif + +#ifdef CONFIG_HISAX_16_3 +#define CARD_TELES3 (1<< ISDN_CTYPE_16_3) | (1<< ISDN_CTYPE_PNP) | \ + (1<< ISDN_CTYPE_TELESPCMCIA) +#else +#define CARD_TELES3 0 +#endif + +#ifdef CONFIG_HISAX_AVM_A1 +#define CARD_AVM_A1 (1<< ISDN_CTYPE_A1) +#else +#define CARD_AVM_A1 0 +#endif + +#ifdef CONFIG_HISAX_ELSA_PCC +#define CARD_ELSA (1<< ISDN_CTYPE_ELSA) | (1<< ISDN_CTYPE_ELSA_QS1000) +#else +#define CARD_ELSA 0 +#endif + +#ifdef CONFIG_HISAX_IX1MICROR2 +#define CARD_IX1MICROR2 (1 << ISDN_CTYPE_IX1MICROR2) +#else +#define CARD_IX1MICROR2 0 +#endif + +#define SUPORTED_CARDS (CARD_TELES0 | CARD_TELES3 | CARD_AVM_A1 | CARD_ELSA \ + | CARD_IX1MICROR2) + +struct IsdnCard { + int typ; + int protocol; /* EDSS1 or 1TR6 */ + unsigned int para[3]; + struct IsdnCardState *sp; +}; + +#define DATAPTR(x) ((byte *)x+sizeof(struct BufHeader)) + +#define LAPD 0 +#define LAPB 1 + +void BufPoolInit(struct BufPool *bp, int order, int bpps, + int maxpages); +int BufPoolAdd(struct BufPool *bp, int priority); +void BufPoolFree(struct BufPool *bp); +int BufPoolGet(struct BufHeader **bh, struct BufPool *bp, + int priority, void *heldby, int where); +void BufPoolRelease(struct BufHeader *bh); +void BufQueueLink(struct BufQueue *bq, struct BufHeader *bh); +int BufQueueUnlink(struct BufHeader **bh, struct BufQueue *bq); +void BufQueueInit(struct BufQueue *bq); +void BufQueueRelease(struct BufQueue *bq); +void BufQueueDiscard(struct BufQueue *q, int pr, void *heldby, + int releasetoo); +int BufQueueLength(struct BufQueue *bq); +void BufQueueLinkFront(struct BufQueue *bq, struct BufHeader *bh); + +void l2down(struct PStack *st, byte pr, struct BufHeader *ibh); +void l2up(struct PStack *st, byte pr, struct BufHeader *ibh); +void acceptph(struct PStack *st, struct BufHeader *ibh); +void setstack_isdnl2(struct PStack *st, char *debug_id); +int HiSax_inithardware(void); +void HiSax_closehardware(void); + +void setstack_HiSax(struct PStack *st, struct IsdnCardState *sp); +unsigned int randomces(void); +void setstack_isdnl3(struct PStack *st, struct Channel *chanp ); +void HiSax_addlist(struct IsdnCardState *sp, struct PStack *st); +void releasestack_isdnl2(struct PStack *st); +void releasestack_isdnl3(struct PStack *st); +void HiSax_rmlist(struct IsdnCardState *sp, struct PStack *st); +void newcallref(struct PStack *st); + +int setstack_hscx(struct PStack *st, struct HscxState *hs); +byte *findie(byte * p, int size, byte ie, int wanted_set); +int getcallref(byte * p); + +void FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount); +void FsmFree(struct Fsm *fsm); +int FsmEvent(struct FsmInst *fi, int event, void *arg); +void FsmChangeState(struct FsmInst *fi, int newstate); +void FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft); +int FsmAddTimer(struct FsmTimer *ft, int millisec, + int event, void *arg, int where); +void FsmDelTimer(struct FsmTimer *ft, int where); +int FsmTimerRunning(struct FsmTimer *ft); +void jiftime(char *s, long mark); + +int HiSax_command(isdn_ctrl * ic); +int HiSax_writebuf(int id, int chan, const u_char * buf, int count, int user); +void HiSax_putstatus(struct IsdnCardState *csta, char *buf); +void HiSax_reportcard(int cardnr); +int ListLength(struct BufHeader *ibh); +int QuickHex(char *txt, byte * p, int cnt); +void LogFrame(struct IsdnCardState *sp, byte * p, int size); +void dlogframe(struct IsdnCardState *sp, byte * p, int size, char *comment); +void iecpy(byte * dest, byte * iestart, int ieoffset); +void setstack_transl2(struct PStack *st); +void releasestack_transl2(struct PStack *st); +void close_hscxstate(struct HscxState *); +void setstack_tei(struct PStack *st); + + + + +#define PART_SIZE(order,bpps) (( (PAGE_SIZE< +#include + +const char *CardType[] = +{"No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3", + "Creatix PnP", "AVM A1", "Elsa ML", "Elsa Quickstep", + "Teles PCMCIA", "ITK ix1-micro Rev.2"}; + +static char *HSCXVer[] = +{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7", + "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"}; + +static char *ISACVer[] = +{"2086/2186 V1.1", "2085 B1", "2085 B2", + "2085 V2.3"}; + +extern void tei_handler(struct PStack *st, byte pr, + struct BufHeader *ibh); +extern struct IsdnCard cards[]; +extern int nrcards; +extern char *HiSax_id; + +/* + * Find card with given driverId + */ +static inline struct IsdnCardState +* +hisax_findcard(int driverid) +{ + int i; + + for (i = 0; i < nrcards; i++) + if (cards[i].sp) + if (cards[i].sp->myid == driverid) + return (cards[i].sp); + return (struct IsdnCardState *) 0; +} + +int +HiSax_readstatus(byte * buf, int len, int user, int id, int channel) +{ + int count; + byte *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; + } +} + +void +HiSax_putstatus(struct IsdnCardState *csta, char *buf) +{ + long flags; + int len, count, i; + byte *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); + } +} + +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); +} + +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) + Sfree(csta->status_buf); + csta->status_read = NULL; + csta->status_write = NULL; + csta->status_end = NULL; + Sfree(csta->dlogspace); +} + +void +debugl1(struct IsdnCardState *sp, char *msg) +{ + char tmp[256], tm[32]; + + jiftime(tm, jiffies); + sprintf(tmp, "%s Card %d %s\n", tm, sp->cardnr + 1, msg); + HiSax_putstatus(sp, tmp); +} + +/* + * HSCX stuff goes here + */ + + +char * +HscxVersion(byte v) +{ + return (HSCXVer[v & 0xf]); +} + +void +hscx_sched_event(struct HscxState *hsp, int event) +{ + hsp->event |= 1 << event; + queue_task_irq_off(&hsp->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +/* + * ISAC stuff goes here + */ + +char * +ISACVersion(byte v) +{ + return (ISACVer[(v >> 5) & 3]); +} + +void +isac_sched_event(struct IsdnCardState *sp, int event) +{ + sp->event |= 1 << event; + queue_task_irq_off(&sp->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +int +act_wanted(struct IsdnCardState *sp) +{ + struct PStack *st; + + st = sp->stlist; + while (st) + if (st->l1.act_state) + return (!0); + else + st = st->next; + return (0); +} + +void +isac_new_ph(struct IsdnCardState *sp) +{ + int enq; + + enq = act_wanted(sp); + + switch (sp->ph_state) { + case (6): + sp->ph_active = 0; + sp->ph_command(sp, 15); + break; + case (15): + sp->ph_active = 0; + if (enq) + sp->ph_command(sp, 0); + break; + case (0): + sp->ph_active = 0; + if (enq) + sp->ph_command(sp, 0); +#if 0 + else + sp->ph_command(sp, 15); +#endif + break; + case (7): + sp->ph_active = 0; + if (enq) + sp->ph_command(sp, 9); + break; + case (12): + sp->ph_command(sp, 8); + sp->ph_active = 5; + isac_sched_event(sp, ISAC_PHCHANGE); + if (!sp->xmtibh) + if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) + sp->sendptr = 0; + if (sp->xmtibh) + sp->isac_fill_fifo(sp); + break; + case (13): + sp->ph_command(sp, 9); + sp->ph_active = 5; + isac_sched_event(sp, ISAC_PHCHANGE); + if (!sp->xmtibh) + if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) + sp->sendptr = 0; + if (sp->xmtibh) + sp->isac_fill_fifo(sp); + break; + case (4): + case (8): + sp->ph_active = 0; + break; + default: + sp->ph_active = 0; + break; + } +} + +static void +restart_ph(struct IsdnCardState *sp) +{ + if (!sp->ph_active) { + if ((sp->ph_state == 6) || (sp->ph_state == 0)) { + sp->ph_command(sp, 0); + sp->ph_active = 2; + } else { + sp->ph_command(sp, 1); + sp->ph_active = 1; + } + } else if (sp->ph_active == 2) { + sp->ph_command(sp, 1); + sp->ph_active = 1; + } +} + + +static void +act_ivated(struct IsdnCardState *sp) +{ + struct PStack *st; + + st = sp->stlist; + while (st) { + if (st->l1.act_state == 1) { + st->l1.act_state = 2; + st->l1.l1man(st, PH_ACTIVATE, NULL); + } + st = st->next; + } +} + +static void +process_new_ph(struct IsdnCardState *sp) +{ + if (sp->ph_active == 5) + act_ivated(sp); +} + +static void +process_xmt(struct IsdnCardState *sp) +{ + struct PStack *stptr; + + if (sp->xmtibh) + return; + + stptr = sp->stlist; + while (stptr != NULL) + if (stptr->l1.requestpull) { + stptr->l1.requestpull = 0; + stptr->l1.l1l2(stptr, PH_PULL_ACK, NULL); + break; + } else + stptr = stptr->next; +} + +static void +process_rcv(struct IsdnCardState *sp) +{ + struct BufHeader *ibh, *cibh; + struct PStack *stptr; + byte *ptr; + int found, broadc; + char tmp[64]; + + while (!BufQueueUnlink(&ibh, &sp->rq)) { +#ifdef L2FRAME_DEBUG /* psa */ + if (sp->debug & L1_DEB_LAPD) + Logl2Frame(sp, ibh, "PH_DATA", 1); +#endif + stptr = sp->stlist; + ptr = DATAPTR(ibh); + broadc = (ptr[1] >> 1) == 127; + + if (broadc) { + if (!(ptr[0] >> 2)) { /* sapi 0 */ + sp->CallFlags = 3; + if (sp->dlogflag) { + LogFrame(sp, ptr, ibh->datasize); + dlogframe(sp, ptr + 3, ibh->datasize - 3, + "Q.931 frame network->user broadcast"); + } + } + while (stptr != NULL) { + if ((ptr[0] >> 2) == stptr->l2.sap) + if (!BufPoolGet(&cibh, &sp->rbufpool, GFP_ATOMIC, + (void *) 1, 5)) { + memcpy(DATAPTR(cibh), DATAPTR(ibh), ibh->datasize); + cibh->datasize = ibh->datasize; + stptr->l1.l1l2(stptr, PH_DATA, cibh); + } else + printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n"); + stptr = stptr->next; + } + BufPoolRelease(ibh); + } else { + found = 0; + while (stptr != NULL) + if (((ptr[0] >> 2) == stptr->l2.sap) && + ((ptr[1] >> 1) == stptr->l2.tei)) { + stptr->l1.l1l2(stptr, PH_DATA, ibh); + found = !0; + break; + } else + stptr = stptr->next; + if (!found) { + /* BD 10.10.95 + * Print out D-Channel msg not processed + * by isdn4linux + */ + + if ((!(ptr[0] >> 2)) && (!(ptr[2] & 0x01))) { + sprintf(tmp, + "Q.931 frame network->user with tei %d (not for us)", + ptr[1] >> 1); + LogFrame(sp, ptr, ibh->datasize); + dlogframe(sp, ptr + 4, ibh->datasize - 4, tmp); + } + BufPoolRelease(ibh); + } + } + + } + +} + +static void +isac_bh(struct IsdnCardState *sp) +{ + if (!sp) + return; + + if (clear_bit(ISAC_PHCHANGE, &sp->event)) + process_new_ph(sp); + if (clear_bit(ISAC_RCVBUFREADY, &sp->event)) + process_rcv(sp); + if (clear_bit(ISAC_XMTBUFREADY, &sp->event)) + process_xmt(sp); +} + +static void +l2l1(struct PStack *st, int pr, + struct BufHeader *ibh) +{ + struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware; + byte *ptr = DATAPTR(ibh); + char str[64]; + + switch (pr) { + case (PH_DATA): + if (sp->xmtibh) { + BufQueueLink(&sp->sq, ibh); +#ifdef L2FRAME_DEBUG /* psa */ + if (sp->debug & L1_DEB_LAPD) + Logl2Frame(sp, ibh, "PH_DATA Queued", 0); +#endif + } else { + if ((sp->dlogflag) && (!(ptr[2] & 1))) { /* I-FRAME */ + LogFrame(sp, ptr, ibh->datasize); + sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei); + dlogframe(sp, ptr + st->l2.ihsize, ibh->datasize - st->l2.ihsize, + str); + } + sp->xmtibh = ibh; + sp->sendptr = 0; + sp->releasebuf = !0; + sp->isac_fill_fifo(sp); +#ifdef L2FRAME_DEBUG /* psa */ + if (sp->debug & L1_DEB_LAPD) + Logl2Frame(sp, ibh, "PH_DATA", 0); +#endif + } + break; + case (PH_DATA_PULLED): + if (sp->xmtibh) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, " l2l1 xmtibh exist this shouldn't happen"); + break; + } + if ((sp->dlogflag) && (!(ptr[2] & 1))) { /* I-FRAME */ + LogFrame(sp, ptr, ibh->datasize); + sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei); + dlogframe(sp, ptr + st->l2.ihsize, ibh->datasize - st->l2.ihsize, + str); + } + sp->xmtibh = ibh; + sp->sendptr = 0; + sp->releasebuf = 0; + sp->isac_fill_fifo(sp); +#ifdef L2FRAME_DEBUG /* psa */ + if (sp->debug & L1_DEB_LAPD) + Logl2Frame(sp, ibh, "PH_DATA_PULLED", 0); +#endif + break; + case (PH_REQUEST_PULL): +#ifdef L2FRAME_DEBUG /* psa */ + if (sp->debug & L1_DEB_LAPD) + debugl1(sp, "-> PH_REQUEST_PULL"); +#endif + if (!sp->xmtibh) { + st->l1.requestpull = 0; + st->l1.l1l2(st, PH_PULL_ACK, NULL); + } else + st->l1.requestpull = !0; + break; + } +} + + +static void +hscx_process_xmt(struct HscxState *hsp) +{ + struct PStack *st = hsp->st; + + if (hsp->xmtibh) + return; + + if (st->l1.requestpull) { + st->l1.requestpull = 0; + st->l1.l1l2(st, PH_PULL_ACK, NULL); + } + if (!hsp->active) + if ((!hsp->xmtibh) && (!hsp->sq.head)) + hsp->sp->modehscx(hsp, 0, 0); +} + +static void +hscx_process_rcv(struct HscxState *hsp) +{ + struct BufHeader *ibh; + +#ifdef DEBUG_MAGIC + if (hsp->magic != 301270) { + printk(KERN_DEBUG "hscx_process_rcv magic not 301270\n"); + return; + } +#endif + while (!BufQueueUnlink(&ibh, &hsp->rq)) { + hsp->st->l1.l1l2(hsp->st, PH_DATA, ibh); + } +} + +static void +hscx_bh(struct HscxState *hsp) +{ + + if (!hsp) + return; + + if (clear_bit(HSCX_RCVBUFREADY, &hsp->event)) + hscx_process_rcv(hsp); + if (clear_bit(HSCX_XMTBUFREADY, &hsp->event)) + hscx_process_xmt(hsp); + +} + +/* + * interrupt stuff ends here + */ + +void +HiSax_addlist(struct IsdnCardState *sp, + struct PStack *st) +{ + st->next = sp->stlist; + sp->stlist = st; +} + +void +HiSax_rmlist(struct IsdnCardState *sp, + struct PStack *st) +{ + struct PStack *p; + + if (sp->stlist == st) + sp->stlist = st->next; + else { + p = sp->stlist; + while (p) + if (p->next == st) { + p->next = st->next; + return; + } else + p = p->next; + } +} + +static void +check_ph_act(struct IsdnCardState *sp) +{ + struct PStack *st = sp->stlist; + + while (st) { + if (st->l1.act_state) + return; + st = st->next; + } + if (sp->ph_active == 5) + sp->ph_active = 4; +} + +static void +HiSax_manl1(struct PStack *st, int pr, + void *arg) +{ + struct IsdnCardState *sp = (struct IsdnCardState *) + st->l1.hardware; + long flags; + char tmp[32]; + + switch (pr) { + case (PH_ACTIVATE): + if (sp->debug) { + sprintf(tmp, "PH_ACT ph_active %d", sp->ph_active); + debugl1(sp, tmp); + } + save_flags(flags); + cli(); + if (sp->ph_active & 4) { + sp->ph_active = 5; + st->l1.act_state = 2; + restore_flags(flags); + st->l1.l1man(st, PH_ACTIVATE, NULL); + } else { + st->l1.act_state = 1; + if (sp->ph_active == 0) + restart_ph(sp); + restore_flags(flags); + } + break; + case (PH_DEACTIVATE): + st->l1.act_state = 0; + if (sp->debug) { + sprintf(tmp, "PH_DEACT ph_active %d", sp->ph_active); + debugl1(sp, tmp); + } + check_ph_act(sp); + break; + } +} + +static void +HiSax_l2l1discardq(struct PStack *st, int pr, + void *heldby, int releasetoo) +{ + struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware; + +#ifdef DEBUG_MAGIC + if (sp->magic != 301271) { + printk(KERN_DEBUG "isac_discardq magic not 301271\n"); + return; + } +#endif + + BufQueueDiscard(&sp->sq, pr, heldby, releasetoo); +} + +void +setstack_HiSax(struct PStack *st, struct IsdnCardState *sp) +{ + st->l1.hardware = sp; + st->l1.sbufpool = &(sp->sbufpool); + st->l1.rbufpool = &(sp->rbufpool); + st->l1.smallpool = &(sp->smallpool); + st->protocol = sp->protocol; + + setstack_tei(st); + + st->l1.stlistp = &(sp->stlist); + st->l1.act_state = 0; + st->l2.l2l1 = l2l1; + st->l2.l2l1discardq = HiSax_l2l1discardq; + st->ma.manl1 = HiSax_manl1; + st->l1.requestpull = 0; +} + +void +init_hscxstate(struct IsdnCardState *sp, + int hscx) +{ + struct HscxState *hsp = sp->hs + hscx; + + hsp->sp = sp; + hsp->hscx = hscx; + + hsp->tqueue.next = 0; + hsp->tqueue.sync = 0; + hsp->tqueue.routine = (void *) (void *) hscx_bh; + hsp->tqueue.data = hsp; + + hsp->inuse = 0; + hsp->init = 0; + hsp->active = 0; + +#ifdef DEBUG_MAGIC + hsp->magic = 301270; +#endif +} + +int +get_irq(int cardnr, void *routine) +{ + struct IsdnCard *card = cards + cardnr; + long flags; + + save_flags(flags); + cli(); + if (request_irq(card->sp->irq, routine, + SA_INTERRUPT, "HiSax", NULL)) { + printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n", + card->sp->irq); + restore_flags(flags); + return (0); + } + irq2dev_map[card->sp->irq] = (void *) card->sp; + restore_flags(flags); + return (1); +} + +static void +release_irq(int cardnr) +{ + struct IsdnCard *card = cards + cardnr; + + irq2dev_map[card->sp->irq] = NULL; + free_irq(card->sp->irq, NULL); +} + +void +close_hscxstate(struct HscxState *hs) +{ + hs->sp->modehscx(hs, 0, 0); + hs->inuse = 0; + + if (hs->init) { + BufPoolFree(&hs->smallpool); + BufPoolFree(&hs->rbufpool); + BufPoolFree(&hs->sbufpool); + } + hs->init = 0; +} + +static void +closecard(int cardnr) +{ + struct IsdnCardState *csta = cards[cardnr].sp; + + BufPoolFree(&csta->smallpool); + BufPoolFree(&csta->rbufpool); + BufPoolFree(&csta->sbufpool); + + close_hscxstate(csta->hs + 1); + close_hscxstate(csta->hs); + + switch (csta->typ) { +#if CARD_TELES0 + case ISDN_CTYPE_16_0: + case ISDN_CTYPE_8_0: + release_io_teles0(cards + cardnr); + break; +#endif +#if CARD_TELES3 + case ISDN_CTYPE_PNP: + case ISDN_CTYPE_16_3: + case ISDN_CTYPE_TELESPCMCIA: + release_io_teles3(cards + cardnr); + break; +#endif +#if CARD_AVM_A1 + case ISDN_CTYPE_A1: + release_io_avm_a1(cards + cardnr); + break; +#endif +#if CARD_ELSA + case ISDN_CTYPE_ELSA: + case ISDN_CTYPE_ELSA_QS1000: + release_io_elsa(cards + cardnr); + break; +#endif +#if CARD_IX1MICROR2 + case ISDN_CTYPE_IX1MICROR2: + release_io_ix1micro(cards + cardnr); + break; +#endif + default: + break; + } + ll_unload(csta); +} + +static int +checkcard(int cardnr, char *id) +{ + long flags; + int ret = 0; + struct IsdnCard *card = cards + cardnr; + struct IsdnCardState *sp; + + save_flags(flags); + cli(); + if (!(sp = (struct IsdnCardState *) + Smalloc(sizeof(struct IsdnCardState), GFP_KERNEL, + "struct IsdnCardState"))) { + printk(KERN_WARNING + "HiSax: No memory for IsdnCardState(card %d)\n", + cardnr + 1); + restore_flags(flags); + return (0); + } + card->sp = sp; + sp->cardnr = cardnr; + sp->cfg_reg = 0; + sp->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 (!(sp->dlogspace = Smalloc(4096, GFP_KERNEL, "dlogspace"))) { + printk(KERN_WARNING + "HiSax: No memory for dlogspace(card %d)\n", + cardnr + 1); + restore_flags(flags); + return (0); + } + if (!(sp->status_buf = Smalloc(HISAX_STATUS_BUFSIZE, GFP_KERNEL, "status_buf"))) { + printk(KERN_WARNING + "HiSax: No memory for status_buf(card %d)\n", + cardnr + 1); + Sfree(sp->dlogspace); + restore_flags(flags); + return (0); + } + sp->status_read = sp->status_buf; + sp->status_write = sp->status_buf; + sp->status_end = sp->status_buf + HISAX_STATUS_BUFSIZE - 1; + sp->typ = card->typ; + sp->CallFlags = 0; + strcpy(sp->iif.id, id); + sp->iif.channels = 2; + sp->iif.maxbufsize = BUFFER_SIZE(HSCX_SBUF_ORDER, HSCX_SBUF_BPPS); + sp->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 + 0; + + sp->iif.command = HiSax_command; + sp->iif.writebuf = HiSax_writebuf; + sp->iif.writecmd = NULL; + sp->iif.writebuf_skb = NULL; + sp->iif.readstat = HiSax_readstatus; + register_isdn(&sp->iif); + sp->myid = sp->iif.channels; + restore_flags(flags); + printk(KERN_NOTICE + "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" : + "NONE", sp->iif.id, sp->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: + 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_QS1000: + ret = setup_elsa(card); + break; +#endif +#if CARD_IX1MICROR2 + case ISDN_CTYPE_IX1MICROR2: + ret = setup_ix1micro(card); + break; +#endif + default: + printk(KERN_WARNING "HiSax: Unknown Card Typ %d\n", + card->typ); + ll_unload(sp); + return (0); + } + if (!ret) { + ll_unload(sp); + return (0); + } + BufPoolInit(&sp->sbufpool, ISAC_SBUF_ORDER, ISAC_SBUF_BPPS, + ISAC_SBUF_MAXPAGES); + BufPoolInit(&sp->rbufpool, ISAC_RBUF_ORDER, ISAC_RBUF_BPPS, + ISAC_RBUF_MAXPAGES); + BufPoolInit(&sp->smallpool, ISAC_SMALLBUF_ORDER, ISAC_SMALLBUF_BPPS, + ISAC_SMALLBUF_MAXPAGES); + sp->rcvibh = NULL; + sp->rcvptr = 0; + sp->xmtibh = NULL; + sp->sendptr = 0; + sp->mon_rx = NULL; + sp->mon_rxp = 0; + sp->mon_tx = NULL; + sp->mon_txp = 0; + sp->mon_flg = 0; + sp->event = 0; + sp->tqueue.next = 0; + sp->tqueue.sync = 0; + sp->tqueue.routine = (void *) (void *) isac_bh; + sp->tqueue.data = sp; + + BufQueueInit(&sp->rq); + BufQueueInit(&sp->sq); + + sp->stlist = NULL; + sp->ph_active = 0; + sp->dlogflag = 0; + sp->debug = L1_DEB_WARN; + sp->releasebuf = 0; +#ifdef DEBUG_MAGIC + sp->magic = 301271; +#endif + + init_hscxstate(sp, 0); + init_hscxstate(sp, 1); + + switch (card->typ) { +#if CARD_TELES0 + case ISDN_CTYPE_16_0: + case ISDN_CTYPE_8_0: + ret = initteles0(sp); + break; +#endif +#if CARD_TELES3 + case ISDN_CTYPE_16_3: + case ISDN_CTYPE_PNP: + case ISDN_CTYPE_TELESPCMCIA: + ret = initteles3(sp); + break; +#endif +#if CARD_AVM_A1 + case ISDN_CTYPE_A1: + ret = initavm_a1(sp); + break; +#endif +#if CARD_ELSA + case ISDN_CTYPE_ELSA: + case ISDN_CTYPE_ELSA_QS1000: + ret = initelsa(sp); + break; +#endif +#if CARD_IX1MICROR2 + case ISDN_CTYPE_IX1MICROR2: + ret = initix1micro(sp); + break; +#endif + default: + ret = 0; + break; + } + if (!ret) { + closecard(cardnr); + return (0); + } + init_tei(sp, sp->protocol); + CallcNewChan(sp); + ll_run(sp); + return (1); +} + +void +HiSax_shiftcards(int idx) +{ + int i; + + for (i = idx; i < 15; i++) + memcpy(&cards[i], &cards[i + 1], sizeof(cards[i])); +} + +int +HiSax_inithardware(void) +{ + 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)) { + foundcards++; + i++; + } else { + printk(KERN_WARNING "HiSax: Card %s not installed !\n", + CardType[cards[i].typ]); + if (cards[i].sp) + Sfree((void *) cards[i].sp); + cards[i].sp = 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].sp) { + ll_stop(cards[i].sp); + CallcFreeChan(cards[i].sp); + release_tei(cards[i].sp); + release_irq(i); + closecard(i); + Sfree((void *) cards[i].sp); + cards[i].sp = NULL; + } + Isdnl2Free(); + CallcFree(); + restore_flags(flags); +} + +static void +hscx_l2l1(struct PStack *st, int pr, + struct BufHeader *ibh) +{ + struct IsdnCardState *sp = (struct IsdnCardState *) + st->l1.hardware; + struct HscxState *hsp = sp->hs + st->l1.hscx; + long flags; + + switch (pr) { + case (PH_DATA): + save_flags(flags); + cli(); + if (hsp->xmtibh) { + BufQueueLink(&hsp->sq, ibh); + restore_flags(flags); + } else { + restore_flags(flags); + hsp->xmtibh = ibh; + hsp->sendptr = 0; + hsp->releasebuf = !0; + sp->hscx_fill_fifo(hsp); + } + break; + case (PH_DATA_PULLED): + if (hsp->xmtibh) { + printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n"); + break; + } + hsp->xmtibh = ibh; + hsp->sendptr = 0; + hsp->releasebuf = 0; + sp->hscx_fill_fifo(hsp); + break; + case (PH_REQUEST_PULL): + if (!hsp->xmtibh) { + st->l1.requestpull = 0; + st->l1.l1l2(st, PH_PULL_ACK, NULL); + } else + st->l1.requestpull = !0; + break; + } + +} +extern struct IsdnBuffers *tracebuf; + +static void +hscx_l2l1discardq(struct PStack *st, int pr, void *heldby, + int releasetoo) +{ + struct IsdnCardState *sp = (struct IsdnCardState *) + st->l1.hardware; + struct HscxState *hsp = sp->hs + st->l1.hscx; + +#ifdef DEBUG_MAGIC + if (hsp->magic != 301270) { + printk(KERN_DEBUG "hscx_discardq magic not 301270\n"); + return; + } +#endif + + BufQueueDiscard(&hsp->sq, pr, heldby, releasetoo); +} + +static int +open_hscxstate(struct IsdnCardState *sp, + int hscx) +{ + struct HscxState *hsp = sp->hs + hscx; + + if (!hsp->init) { + BufPoolInit(&hsp->sbufpool, HSCX_SBUF_ORDER, HSCX_SBUF_BPPS, + HSCX_SBUF_MAXPAGES); + BufPoolInit(&hsp->rbufpool, HSCX_RBUF_ORDER, HSCX_RBUF_BPPS, + HSCX_RBUF_MAXPAGES); + BufPoolInit(&hsp->smallpool, HSCX_SMALLBUF_ORDER, HSCX_SMALLBUF_BPPS, + HSCX_SMALLBUF_MAXPAGES); + } + hsp->init = !0; + + BufQueueInit(&hsp->rq); + BufQueueInit(&hsp->sq); + + hsp->releasebuf = 0; + hsp->rcvibh = NULL; + hsp->xmtibh = NULL; + hsp->rcvptr = 0; + hsp->sendptr = 0; + hsp->event = 0; + return (0); +} + +static void +hscx_manl1(struct PStack *st, int pr, + void *arg) +{ + struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware; + struct HscxState *hsp = sp->hs + st->l1.hscx; + + switch (pr) { + case (PH_ACTIVATE): + hsp->active = !0; + sp->modehscx(hsp, st->l1.hscxmode, st->l1.hscxchannel); + st->l1.l1man(st, PH_ACTIVATE, NULL); + break; + case (PH_DEACTIVATE): + if (!hsp->xmtibh) + sp->modehscx(hsp, 0, 0); + + hsp->active = 0; + break; + } +} + +int +setstack_hscx(struct PStack *st, struct HscxState *hs) +{ + if (open_hscxstate(st->l1.hardware, hs->hscx)) + return (-1); + + st->l1.hscx = hs->hscx; + st->l2.l2l1 = hscx_l2l1; + st->ma.manl1 = hscx_manl1; + st->l2.l2l1discardq = hscx_l2l1discardq; + + st->l1.sbufpool = &hs->sbufpool; + st->l1.rbufpool = &hs->rbufpool; + st->l1.smallpool = &hs->smallpool; + st->l1.act_state = 0; + st->l1.requestpull = 0; + + hs->st = st; + return (0); +} + +void +HiSax_reportcard(int cardnr) +{ + struct IsdnCardState *sp = cards[cardnr].sp; + + printk(KERN_DEBUG "HiSax: reportcard No %d\n", cardnr + 1); + printk(KERN_DEBUG "HiSax: Type %s\n", CardType[sp->typ]); + printk(KERN_DEBUG "HiSax: debuglevel %x\n", sp->debug); + printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n", + (ulong) & HiSax_reportcard); +} + +#ifdef L2FRAME_DEBUG /* psa */ + +char * +l2cmd(byte cmd) +{ + switch (cmd & ~0x10) { + case 1: + return "RR"; + case 5: + return "RNR"; + case 9: + return "REJ"; + case 0x6f: + return "SABME"; + case 0x0f: + return "DM"; + case 3: + return "UI"; + case 0x43: + return "DISC"; + case 0x63: + return "UA"; + case 0x87: + return "FRMR"; + case 0xaf: + return "XID"; + default: + if (!(cmd & 1)) + return "I"; + else + return "invalid command"; + } +} + +static char tmp[20]; + +char * +l2frames(byte * ptr) +{ + switch (ptr[2] & ~0x10) { + case 1: + case 5: + case 9: + sprintf(tmp, "%s[%d](nr %d)", l2cmd(ptr[2]), ptr[3] & 1, ptr[3] >> 1); + break; + case 0x6f: + case 0x0f: + case 3: + case 0x43: + case 0x63: + case 0x87: + case 0xaf: + sprintf(tmp, "%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); + break; + } else + return "invalid command"; + } + + + return tmp; +} + +void +Logl2Frame(struct IsdnCardState *sp, struct BufHeader *ibh, char *buf, int dir) +{ + char tmp[132]; + byte *ptr; + + ptr = DATAPTR(ibh); + + if (ptr[0] & 1 || !(ptr[1] & 1)) + debugl1(sp, "Addres not LAPD"); + else { + sprintf(tmp, "%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(sp, tmp); + } +} + +#endif diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/isdnl1.h linux/drivers/isdn/hisax/isdnl1.h --- v2.1.26/linux/drivers/isdn/hisax/isdnl1.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/isdnl1.h Tue Feb 25 17:12:49 1997 @@ -0,0 +1,45 @@ +/* $Id: isdnl1.h,v 1.3 1996/12/08 19:41:55 keil Exp $ + * + * $Log: isdnl1.h,v $ + * Revision 1.3 1996/12/08 19:41:55 keil + * L2FRAME_DEBUG + * + * Revision 1.2 1996/10/27 22:26:27 keil + * ISAC/HSCX version functions + * + * Revision 1.1 1996/10/13 20:03:47 keil + * Initial revision + * + * + * + */ + + +#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 ISAC_RCVBUFREADY 0 +#define ISAC_XMTBUFREADY 1 +#define ISAC_PHCHANGE 2 + +#define HSCX_RCVBUFREADY 0 +#define HSCX_XMTBUFREADY 1 + +extern void debugl1(struct IsdnCardState *sp, char *msg); +extern char *HscxVersion(byte v); +extern char *ISACVersion(byte v); +extern void hscx_sched_event(struct HscxState *hsp, int event); +extern void isac_sched_event(struct IsdnCardState *sp, int event); +extern void isac_new_ph(struct IsdnCardState *sp); +extern get_irq(int cardnr, void *routine); +extern void Logl2Frame(struct IsdnCardState *sp, struct BufHeader *ibh, char *buf, int dir); diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/isdnl2.c linux/drivers/isdn/hisax/isdnl2.c --- v2.1.26/linux/drivers/isdn/hisax/isdnl2.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/isdnl2.c Tue Feb 25 17:12:49 1997 @@ -0,0 +1,1465 @@ +/* $Id: isdnl2.c,v 1.7 1997/02/09 00:25:44 keil Exp $ + + * Author Karsten Keil (keil@temic-ech.spacenet.de) + * based on the teles driver from Jan den Ouden + * + * Thanks to Jan den Ouden + * Fritz Elfert + * + * $Log: isdnl2.c,v $ + * Revision 1.7 1997/02/09 00:25:44 keil + * new interface handling, one interface per card + * + * Revision 1.6 1997/01/21 22:23:42 keil + * D-channel log changed + * + * Revision 1.5 1997/01/04 13:47:06 keil + * handling of MDL_REMOVE added (Thanks to Sim Yskes) + * + * Revision 1.4 1996/12/08 19:51:51 keil + * many fixes from Pekka Sarnila + * + * Revision 1.3 1996/11/05 19:39:12 keil + * X.75 bugfixes Thank to Martin Maurer + * + * Revision 1.2 1996/10/30 10:20:58 keil + * X.75 answer of SABMX fixed to response address (AVM X.75 problem) + * + * Revision 1.1 1996/10/13 20:04:54 keil + * Initial revision + * + * + * + */ +#define __NO_VERSION__ +#include "hisax.h" +#include "isdnl2.h" + +#define TIMER_1 2000 + +const char *l2_revision = "$Revision: 1.7 $"; + +static void l2m_debug(struct FsmInst *fi, char *s); + +struct Fsm l2fsm = +{NULL, 0, 0}; + +enum { + ST_L2_1, + ST_L2_3, + ST_L2_4, + ST_L2_5, + ST_L2_6, + ST_L2_7, + ST_L2_8, +}; + +#define L2_STATE_COUNT (ST_L2_8+1) + +static char *strL2State[] = +{ + "ST_L2_1", + "ST_L2_3", + "ST_L2_4", + "ST_L2_5", + "ST_L2_6", + "ST_L2_7", + "ST_L2_8", +}; + +enum { + EV_L2_UI, + EV_L2_SABMX, + EV_L2_UA, + EV_L2_DISC, + EV_L2_I, + EV_L2_RR, + EV_L2_REJ, + EV_L2_FRMR, + EV_L2_DL_DATA, + EV_L2_DL_ESTABLISH, + EV_L2_MDL_ASSIGN, + EV_L2_MDL_REMOVE, + EV_L2_DL_UNIT_DATA, + EV_L2_DL_RELEASE, + EV_L2_MDL_NOTEIPROC, + EV_L2_T200, + EV_L2_ACK_PULL, + EV_L2_T203, + EV_L2_RNR, +}; + +#define L2_EVENT_COUNT (EV_L2_RNR+1) + +static char *strL2Event[] = +{ + "EV_L2_UI", + "EV_L2_SABMX", + "EV_L2_UA", + "EV_L2_DISC", + "EV_L2_I", + "EV_L2_RR", + "EV_L2_REJ", + "EV_L2_FRMR", + "EV_L2_DL_DATA", + "EV_L2_DL_ESTABLISH", + "EV_L2_MDL_ASSIGN", + "EV_L2_MDL_REMOVE", + "EV_L2_DL_UNIT_DATA", + "EV_L2_DL_RELEASE", + "EV_L2_MDL_NOTEIPROC", + "EV_L2_T200", + "EV_L2_ACK_PULL", + "EV_L2_T203", + "EV_L2_RNR", +}; + +int errcount = 0; + +static int l2addrsize(struct Layer2 *tsp); + +static int +cansend(struct PStack *st) +{ + int p1; + + p1 = (st->l2.va + st->l2.window) % (st->l2.extended ? 128 : 8); + return (st->l2.vs != p1); +} + +static void +discard_i_queue(struct PStack *st) +{ + struct BufHeader *ibh; + + while (!BufQueueUnlink(&ibh, &st->l2.i_queue)) + BufPoolRelease(ibh); +} + +int +l2headersize(struct Layer2 *tsp, int ui) +{ + return ((tsp->extended && (!ui) ? 2 : 1) + (tsp->laptype == LAPD ? 2 : 1)); +} + +int +l2addrsize(struct Layer2 *tsp) +{ + return (tsp->laptype == LAPD ? 2 : 1); +} + +static int +sethdraddr(struct Layer2 *tsp, + struct BufHeader *ibh, int rsp) +{ + byte *ptr = DATAPTR(ibh); + int crbit; + + if (tsp->laptype == LAPD) { + crbit = rsp; + if (!tsp->orig) + crbit = !crbit; + *ptr++ = (tsp->sap << 2) | (crbit ? 2 : 0); + *ptr++ = (tsp->tei << 1) | 1; + return (2); + } else { + crbit = rsp; + if (tsp->orig) + crbit = !crbit; + if (crbit) + *ptr++ = 1; + else + *ptr++ = 3; + return (1); + } +} + +static void +enqueue_ui(struct PStack *st, + struct BufHeader *ibh) +{ + st->l2.l2l1(st, PH_DATA, ibh); +} + +static void +enqueue_super(struct PStack *st, + struct BufHeader *ibh) +{ + st->l2.l2l1(st, PH_DATA, ibh); +} + +static int +legalnr(struct PStack *st, int nr) +{ + struct Layer2 *l2 = &st->l2; + int lnr, lvs; + + lvs = (l2->vs >= l2->va) ? l2->vs : (l2->vs + l2->extended ? 128 : 8); + lnr = (nr >= l2->va) ? nr : (nr + l2->extended ? 128 : 8); + return (lnr <= lvs); +} + +static void +setva(struct PStack *st, int nr) +{ + struct Layer2 *l2 = &st->l2; + + if (l2->va != nr) { + while (l2->va != nr) { + l2->va = (l2->va + 1) % (l2->extended ? 128 : 8); + BufPoolRelease(l2->windowar[l2->sow]); + l2->sow = (l2->sow + 1) % l2->window; + } + if (st->l4.l2writewakeup) + st->l4.l2writewakeup(st); + } +} + +static void +l2s1(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + st->l2.l2tei(st, MDL_ASSIGN, (void *) st->l2.ces); + FsmChangeState(fi, ST_L2_3); +} + +static void +l2s2(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct BufHeader *ibh = arg; + + byte *ptr; + int i; + + i = sethdraddr(&(st->l2), ibh, CMD); + ptr = DATAPTR(ibh); + ptr += i; + *ptr = UI; + + enqueue_ui(st, ibh); +} + +static void +l2s3(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct BufHeader *ibh = arg; + + st->l2.l2l3(st, DL_UNIT_DATA, ibh); +} + +static void +establishlink(struct FsmInst *fi) +{ + struct PStack *st = fi->userdata; + struct BufHeader *ibh; + int i; + byte *ptr; + + FsmChangeState(fi, ST_L2_5); + st->l2.rc = 0; + + if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 1)) + if (st->l2.l2m.debug) + l2m_debug(&st->l2.l2m, "FAT 1"); + + + if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15)) + return; + i = sethdraddr(&st->l2, ibh, CMD); + ptr = DATAPTR(ibh); + ptr += i; + if (st->l2.extended) + *ptr = SABME | 0x10; + else + *ptr = 0x3f; + ibh->datasize = i + 1; + + enqueue_super(st, ibh); +} + +static void +l2s11(struct FsmInst *fi, int event, void *arg) +{ + establishlink(fi); +} + +static void +l2s13(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct Channel *chanp = st->l4.userdata; + byte *ptr; + struct BufHeader *ibh; + int i; + + FsmChangeState(fi, ST_L2_6); + + FsmDelTimer(&st->l2.t203_timer, 1); + if (st->l2.t200_running) { + FsmDelTimer(&st->l2.t200_timer, 2); + st->l2.t200_running = 0; + } + st->l2.rc = 0; + if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 2)) + if (st->l2.l2m.debug) + l2m_debug(&st->l2.l2m, "FAT 2"); + + + if ((chanp->impair == 2) && (st->l2.laptype == LAPB)) + goto nodisc; + + if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 9)) + return; + i = sethdraddr(&(st->l2), ibh, CMD); + ptr = DATAPTR(ibh); + ptr += i; + *ptr = DISC | 0x10; + ibh->datasize = i + 1; + enqueue_super(st, ibh); + + nodisc: + discard_i_queue(st); +} + +static void +l2s12(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct BufHeader *ibh = arg; + byte *ptr; + int i, p; + + ptr = DATAPTR(ibh); + ptr += l2addrsize(&(st->l2)); + p = (*ptr) & 0x10; + BufPoolRelease(ibh); + + st->l2.vs = 0; + st->l2.va = 0; + st->l2.vr = 0; + st->l2.sow = 0; + FsmChangeState(fi, ST_L2_7); + if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 3)) + if (st->l2.l2m.debug) + l2m_debug(&st->l2.l2m, "FAT 3"); + + st->l2.l2man(st, DL_ESTABLISH, NULL); + + if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 10)) + return; + i = sethdraddr(&(st->l2), ibh, RSP); + ptr = DATAPTR(ibh); + ptr += i; + *ptr = UA | p; + ibh->datasize = i + 1; + enqueue_super(st, ibh); + +} + +static void +l2s14(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct BufHeader *ibh = arg; + struct Channel *chanp = st->l4.userdata; + byte *ptr; + int i, p; + + ptr = DATAPTR(ibh); + ptr += l2addrsize(&(st->l2)); + p = (*ptr) & 0x10; + BufPoolRelease(ibh); + + FsmChangeState(fi, ST_L2_4); + + FsmDelTimer(&st->l2.t203_timer, 3); + if (st->l2.t200_running) { + FsmDelTimer(&st->l2.t200_timer, 4); + st->l2.t200_running = 0; + } + if ((chanp->impair == 1) && (st->l2.laptype == LAPB)) + goto noresponse; + + if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 11)) + return; + i = sethdraddr(&(st->l2), ibh, RSP); + ptr = DATAPTR(ibh); + ptr += i; + *ptr = UA | p; + ibh->datasize = i + 1; + enqueue_super(st, ibh); + + noresponse: + st->l2.l2man(st, DL_RELEASE, NULL); + +} + +static void +l2s14_1(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct BufHeader *ibh = arg; + struct Channel *chanp = st->l4.userdata; + byte *ptr; + int i, p; + + ptr = DATAPTR(ibh); + ptr += l2addrsize(&(st->l2)); + p = (*ptr) & 0x10; + BufPoolRelease(ibh); + + if ((chanp->impair == 1) && (st->l2.laptype == LAPB)) + goto noresponse; + + if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 11)) + return; + i = sethdraddr(&(st->l2), ibh, RSP); + ptr = DATAPTR(ibh); + ptr += i; + *ptr = DM | (p ? 0x10 : 0x0); + + ibh->datasize = i + 1; + enqueue_super(st, ibh); + + noresponse: + +} + +static void +l2s5(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct BufHeader *ibh = arg; + int f; + byte *data; + + data = DATAPTR(ibh); + data += l2addrsize(&(st->l2)); + + f = *data & 0x10; + BufPoolRelease(ibh); + + if (f) { + st->l2.vs = 0; + st->l2.va = 0; + st->l2.vr = 0; + st->l2.sow = 0; + FsmChangeState(fi, ST_L2_7); + + FsmDelTimer(&st->l2.t200_timer, 5); + if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 4)) + if (st->l2.l2m.debug) + l2m_debug(&st->l2.l2m, "FAT 4"); + + + st->l2.l2man(st, DL_ESTABLISH, NULL); + } +} + +static void +l2s15(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct BufHeader *ibh = arg; + int f; + byte *data; + + data = DATAPTR(ibh); + data += l2addrsize(&st->l2); + + f = *data & 0x10; + BufPoolRelease(ibh); + + if (f) { + FsmDelTimer(&st->l2.t200_timer, 6); + FsmChangeState(fi, ST_L2_4); + st->l2.l2man(st, DL_RELEASE, NULL); + } +} + +static void +enquiry_response(struct PStack *st) +{ + struct BufHeader *ibh2; + int i; + byte *ptr; + struct Layer2 *l2; + + l2 = &st->l2; + if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 16)) { + i = sethdraddr(l2, ibh2, RSP); + ptr = DATAPTR(ibh2); + ptr += i; + + if (l2->extended) { + *ptr++ = RR; + *ptr++ = (l2->vr << 1) | 0x1; + i += 2; + } else { + *ptr++ = (l2->vr << 5) | 0x1 | 0x10; + i += 1; + } + ibh2->datasize = i; + enqueue_super(st, ibh2); + } +} + +static void +nrerrorrecovery(struct FsmInst *fi) +{ + /* should log error here */ + establishlink(fi); +} + +static void +l2s6(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct Channel *chanp = st->l4.userdata; + struct BufHeader *ibh = arg; + int p, seq, rsp; + byte *ptr; + struct Layer2 *l2; + + l2 = &st->l2; + ptr = DATAPTR(ibh); + + if (l2->laptype == LAPD) { + rsp = ptr[0] & 0x2; + if (l2->orig) + rsp = !rsp; + } else { + rsp = ptr[0] == 0x3; + if (l2->orig) + rsp = !rsp; + } + + ptr += l2addrsize(l2); + + if (l2->extended) { + p = (ptr[1] & 0x1) == 0x1; + seq = ptr[1] >> 1; + } else { + p = (ptr[0] & 0x10); + seq = (ptr[0] >> 5) & 0x7; + } + BufPoolRelease(ibh); + + if ((chanp->impair == 4) && (st->l2.laptype == LAPB)) + goto noresp; + + if ((!rsp) && p) + enquiry_response(st); + + noresp: + if (legalnr(st, seq)) { + if (seq == st->l2.vs) { + setva(st, seq); + FsmDelTimer(&st->l2.t200_timer, 7); + st->l2.t200_running = 0; + FsmDelTimer(&st->l2.t203_timer, 8); + if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 5)) + if (st->l2.l2m.debug) + l2m_debug(&st->l2.l2m, "FAT 5"); + + if (st->l2.i_queue.head) + st->l2.l2l1(st, PH_REQUEST_PULL, NULL); + } else if (st->l2.va != seq) { + setva(st, seq); + FsmDelTimer(&st->l2.t200_timer, 9); + if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 6)) + if (st->l2.l2m.debug) + l2m_debug(&st->l2.l2m, "FAT 6"); + + if (st->l2.i_queue.head) + st->l2.l2l1(st, PH_REQUEST_PULL, NULL); + } + } else + nrerrorrecovery(fi); + + if ((fi->userint & LC_FLUSH_WAIT) && rsp && !l2->i_queue.head) { + fi->userint &= ~LC_FLUSH_WAIT; + st->l2.l2man(st, DL_FLUSH, NULL); + } +} + +static void +l2s7(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct BufHeader *ibh = arg; + int i; + byte *ptr; + + i = sethdraddr(&st->l2, ibh, CMD); + ptr = DATAPTR(ibh); + BufQueueLink(&st->l2.i_queue, ibh); + st->l2.l2l1(st, PH_REQUEST_PULL, NULL); +} + +static int +icommandreceived(struct FsmInst *fi, int event, void *arg, int *nr) +{ + struct PStack *st = fi->userdata; + struct Channel *chanp = st->l4.userdata; + struct BufHeader *ibh = arg; + byte *ptr; + struct BufHeader *ibh2; + struct IsdnCardState *sp = st->l1.hardware; + struct Layer2 *l2 = &(st->l2); + int i, p, seq, wasok; + char str[64]; + + ptr = DATAPTR(ibh); + ptr += l2addrsize(l2); + if (l2->extended) { + p = (ptr[1] & 0x1) == 0x1; + seq = ptr[0] >> 1; + *nr = (ptr[1] >> 1) & 0x7f; + } else { + p = (ptr[0] & 0x10); + seq = (ptr[0] >> 1) & 0x7; + *nr = (ptr[0] >> 5) & 0x7; + } + + if (l2->vr == seq) { + wasok = !0; + + l2->vr = (l2->vr + 1) % (l2->extended ? 128 : 8); + l2->rejexp = 0; + + ptr = DATAPTR(ibh); + if (st->l2.laptype == LAPD) + if (sp->dlogflag) { + LogFrame(st->l1.hardware, ptr, ibh->datasize); + sprintf(str, "Q.931 frame network->user tei %d", st->l2.tei); + dlogframe(st->l1.hardware, ptr + l2->ihsize, + ibh->datasize - l2->ihsize, str); + } + label8_1: + if ((chanp->impair == 3) && (st->l2.laptype == LAPB)) + goto noRR; + + if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 13)) { + i = sethdraddr(&(st->l2), ibh2, RSP); + ptr = DATAPTR(ibh2); + ptr += i; + + if (l2->extended) { + *ptr++ = RR; + *ptr++ = (l2->vr << 1) | (p ? 1 : 0); + i += 2; + } else { + *ptr++ = (l2->vr << 5) | 0x1 | (p ? 0x10 : 0x0); + i += 1; + } + ibh2->datasize = i; + enqueue_super(st, ibh2); + noRR: + } + } else { + /* n(s)!=v(r) */ + wasok = 0; + BufPoolRelease(ibh); + if (st->l2.rejexp) { + if (p) + goto label8_1; + } else { + st->l2.rejexp = !0; + if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 14)) { + i = sethdraddr(&(st->l2), ibh2, RSP); + ptr = DATAPTR(ibh2); + ptr += i; + + if (l2->extended) { + *ptr++ = REJ; + *ptr++ = (l2->vr << 1) | (p ? 1 : 0); + i += 2; + } else { + *ptr++ = (l2->vr << 5) | 0x9 | (p ? 0x10 : 0x0); + i += 1; + } + ibh2->datasize = i; + enqueue_super(st, ibh2); + } + } + } + + return wasok; + +} + +static void +l2s8(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct BufHeader *ibh = arg; + int nr, wasok; + + wasok = icommandreceived(fi, event, arg, &nr); + + if (legalnr(st, nr)) { + if (nr == st->l2.vs) { + setva(st, nr); + FsmDelTimer(&st->l2.t200_timer, 10); + st->l2.t200_running = 0; + FsmDelTimer(&st->l2.t203_timer, 11); + if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 7)) + if (st->l2.l2m.debug) + l2m_debug(&st->l2.l2m, "FAT 5"); + + if (st->l2.i_queue.head) + st->l2.l2l1(st, PH_REQUEST_PULL, NULL); + } else if (nr != st->l2.va) { + setva(st, nr); + FsmDelTimer(&st->l2.t200_timer, 12); + if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 8)) + if (st->l2.l2m.debug) + l2m_debug(&st->l2.l2m, "FAT 6"); + + if (st->l2.i_queue.head) + st->l2.l2l1(st, PH_REQUEST_PULL, NULL); + } + } else + nrerrorrecovery(fi); + + if (wasok) + st->l2.l2l3(st, DL_DATA, ibh); +} + +static void +l2s8_1(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct BufHeader *ibh = arg; + int nr, wasok; + + wasok = icommandreceived(fi, event, arg, &nr); + + if (legalnr(st, nr)) { + setva(st, nr); + if (st->l2.i_queue.head) + st->l2.l2l1(st, PH_REQUEST_PULL, NULL); + } else + nrerrorrecovery(fi); + + if (wasok) + st->l2.l2l3(st, DL_DATA, ibh); +} + +static void +l2s17(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + st->l2.tei = (int) arg; + establishlink(fi); +} + +static void +invoke_retransmission(struct PStack *st, int nr) +{ + struct Layer2 *l2 = &st->l2; + int p1; + + if (l2->vs != nr) { + while (l2->vs != nr) { + + l2->vs = l2->vs - 1; + if (l2->vs < 0) + l2->vs += l2->extended ? 128 : 8; + + p1 = l2->vs - l2->va; + if (p1 < 0) + p1 += l2->extended ? 128 : 8; + p1 = (p1 + l2->sow) % l2->window; + + BufQueueLinkFront(&l2->i_queue, l2->windowar[p1]); + } + st->l2.l2l1(st, PH_REQUEST_PULL, NULL); + } +} + +static void +l2s16(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct BufHeader *ibh = arg; + int p, seq, rsp; + byte *ptr; + struct Layer2 *l2; + + l2 = &(st->l2); + ptr = DATAPTR(ibh); + + if (l2->laptype == LAPD) { + rsp = ptr[0] & 0x2; + if (l2->orig) + rsp = !rsp; + } else { + rsp = ptr[0] == 0x3; + if (l2->orig) + rsp = !rsp; + } + + + ptr += l2addrsize(l2); + + if (l2->extended) { + p = (ptr[1] & 0x1) == 0x1; + seq = ptr[1] >> 1; + } else { + p = (ptr[0] & 0x10); + seq = (ptr[0] >> 5) & 0x7; + } + BufPoolRelease(ibh); + + if ((!rsp) && p) + enquiry_response(st); + + if (!legalnr(st, seq)) + return; + + setva(st, seq); + invoke_retransmission(st, seq); + +} + +static void +l2s19(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_L2_4); +} + +static void +l2s20(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + int i; + struct BufHeader *ibh; + byte *ptr; + + if (st->l2.rc == st->l2.n200) { + FsmChangeState(fi, ST_L2_4); + st->l2.l2tei(st, MDL_VERIFY, (void *) st->l2.tei); + st->l2.l2man(st, DL_RELEASE, NULL); + } else { + st->l2.rc++; + + if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 9)) + if (st->l2.l2m.debug) + l2m_debug(&st->l2.l2m, "FAT 7"); + + if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15)) + return; + + i = sethdraddr(&st->l2, ibh, CMD); + ptr = DATAPTR(ibh); + ptr += i; + if (st->l2.extended) + *ptr = SABME | 0x10; + else + *ptr = 0x3f; + ibh->datasize = i + 1; + enqueue_super(st, ibh); + } +} + +static void +l2s21(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct Channel *chanp = st->l4.userdata; + int i; + struct BufHeader *ibh; + byte *ptr; + + if (st->l2.rc == st->l2.n200) { + FsmChangeState(fi, ST_L2_4); + st->l2.l2man(st, DL_RELEASE, NULL); + } else { + st->l2.rc++; + + if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 10)) + if (st->l2.l2m.debug) + l2m_debug(&st->l2.l2m, "FAT 8"); + + + if ((chanp->impair == 2) && (st->l2.laptype == LAPB)) + goto nodisc; + + if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15)) + return; + + i = sethdraddr(&st->l2, ibh, CMD); + ptr = DATAPTR(ibh); + ptr += i; + *ptr = DISC | 0x10; + ibh->datasize = i + 1; + enqueue_super(st, ibh); + nodisc: + + } +} + +static void +l2s22(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct BufHeader *ibh; + struct Layer2 *l2 = &st->l2; + byte *ptr; + int p1; + + if (!cansend(st)) + return; + + if (BufQueueUnlink(&ibh, &l2->i_queue)) + return; + + + p1 = l2->vs - l2->va; + if (p1 < 0) + p1 += l2->extended ? 128 : 8; + p1 = (p1 + l2->sow) % l2->window; + l2->windowar[p1] = ibh; + + ptr = DATAPTR(ibh); + ptr += l2addrsize(l2); + + if (l2->extended) { + *ptr++ = l2->vs << 1; + *ptr++ = l2->vr << 1; + l2->vs = (l2->vs + 1) % 128; + } else { + *ptr++ = (l2->vr << 5) | (l2->vs << 1); + l2->vs = (l2->vs + 1) % 8; + } + + st->l2.l2l1(st, PH_DATA_PULLED, ibh); + + if (!st->l2.t200_running) { + FsmDelTimer(&st->l2.t203_timer, 13); + if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 11)) + if (st->l2.l2m.debug) + l2m_debug(&st->l2.l2m, "FAT 9"); + + st->l2.t200_running = !0; + } + if (l2->i_queue.head && cansend(st)) + st->l2.l2l1(st, PH_REQUEST_PULL, NULL); +} + +static void +transmit_enquiry(struct PStack *st) +{ + struct BufHeader *ibh; + byte *ptr; + + if (!BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 12)) { + ptr = DATAPTR(ibh); + ptr += sethdraddr(&st->l2, ibh, CMD); + + if (st->l2.extended) { + *ptr++ = RR; + *ptr++ = (st->l2.vr << 1) | 1; + } else { + *ptr++ = (st->l2.vr << 5) | 0x11; + } + ibh->datasize = ptr - DATAPTR(ibh); + enqueue_super(st, ibh); + if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 12)) + if (st->l2.l2m.debug) + l2m_debug(&st->l2.l2m, "FAT 10"); + + st->l2.t200_running = !0; + } +} + +static void +l2s23(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + st->l2.t200_running = 0; + + st->l2.rc = 1; + FsmChangeState(fi, ST_L2_8); + transmit_enquiry(st); +} + +static void +l2s24(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct BufHeader *ibh = arg; + int p, seq, rsp; + byte *ptr; + struct Layer2 *l2; + + l2 = &st->l2; + ptr = DATAPTR(ibh); + + if (l2->laptype == LAPD) { + rsp = ptr[0] & 0x2; + if (l2->orig) + rsp = !rsp; + } else { + rsp = ptr[0] == 0x3; + if (l2->orig) + rsp = !rsp; + } + + + ptr += l2addrsize(l2); + + if (l2->extended) { + p = (ptr[1] & 0x1) == 0x1; + seq = ptr[1] >> 1; + } else { + p = (ptr[0] & 0x10); + seq = (ptr[0] >> 5) & 0x7; + } + BufPoolRelease(ibh); + + if (rsp && p) { + if (legalnr(st, seq)) { + FsmChangeState(fi, ST_L2_7); + setva(st, seq); + if (st->l2.t200_running) { + FsmDelTimer(&st->l2.t200_timer, 14); + st->l2.t200_running = 0; + } + if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 13)) + if (st->l2.l2m.debug) + l2m_debug(&st->l2.l2m, "FAT 11"); + + invoke_retransmission(st, seq); + + if (l2->i_queue.head && cansend(st)) + st->l2.l2l1(st, PH_REQUEST_PULL, NULL); + else if (fi->userint & LC_FLUSH_WAIT) { + fi->userint &= ~LC_FLUSH_WAIT; + st->l2.l2man(st, DL_FLUSH, NULL); + } + } + } else { + if (!rsp && p) + enquiry_response(st); + if (legalnr(st, seq)) { + setva(st, seq); + } + } +} + +static void +l2s25(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + st->l2.rc = 0; + FsmChangeState(fi, ST_L2_8); + transmit_enquiry(st); +} + +static void +l2s26(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + if (st->l2.rc == st->l2.n200) { + establishlink(fi); + } else { + st->l2.rc++; + transmit_enquiry(st); + } +} + +static void +l2s27(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct BufHeader *ibh = arg; + byte *ptr; + int i, p, est; + + ptr = DATAPTR(ibh); + ptr += l2addrsize(&st->l2); + + p = ptr[0] & 0x10; + + BufPoolRelease(ibh); + + if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 10)) + return; + i = sethdraddr(&st->l2, ibh, RSP); + ptr = DATAPTR(ibh); + ptr += i; + *ptr = UA | p; + ibh->datasize = i + 1; + enqueue_super(st, ibh); + + if (st->l2.vs != st->l2.va) { + discard_i_queue(st); + est = !0; + } else + est = 0; + + FsmDelTimer(&st->l2.t200_timer, 15); + st->l2.t200_running = 0; + + if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 3)) + if (st->l2.l2m.debug) + l2m_debug(&st->l2.l2m, "FAT 12"); + + st->l2.vs = 0; + st->l2.va = 0; + st->l2.vr = 0; + st->l2.sow = 0; + + + if (est) + st->l2.l2man(st, DL_ESTABLISH, NULL); + +} + +static void +l2s27_1(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L2_7); + l2s27(fi, event, arg); + + if (st->l2.i_queue.head && cansend(st)) + st->l2.l2l1(st, PH_REQUEST_PULL, NULL); +} + +static void +l2s28(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct BufHeader *ibh = arg; + byte *ptr; + char tmp[64]; + + ptr = DATAPTR(ibh); + ptr += l2addrsize(&st->l2); + ptr++; + + if (st->l2.l2m.debug) { + if (st->l2.extended) + sprintf(tmp, "FRMR information %2x %2x %2x %2x %2x", + ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]); + else + sprintf(tmp, "FRMR information %2x %2x %2x", + ptr[0], ptr[1], ptr[2]); + + l2m_debug(&st->l2.l2m, tmp); + } + BufPoolRelease(ibh); +} + +static void +l2s30(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + +/*TODO + if( DL_RELEASE.req outstanding ) { + ... issue DL_RELEASE.confirm + } else { + if( fi->state != ST_L2_4 ) { + ... issue DL_RELEASE.indication + } + } + TODO */ + discard_i_queue(st); /* There is no UI queue in layer 2 */ + st->l2.tei = 255; + if (st->l2.t200_running) { + FsmDelTimer(&st->l2.t200_timer, 18); + st->l2.t200_running = 0; + } + FsmDelTimer(&st->l2.t203_timer, 19); + st->l2.l2man(st, DL_RELEASE, NULL); /* TEMP */ + FsmChangeState(fi, ST_L2_1); +} + +static int +IsUI(byte * data, int ext) +{ + return ((data[0] & 0xef) == UI); +} + +static int +IsUA(byte * data, int ext) +{ + return ((data[0] & 0xef) == UA); +} + +static int +IsDISC(byte * data, int ext) +{ + return ((data[0] & 0xef) == DISC); +} + +static int +IsRR(byte * data, int ext) +{ + if (ext) + return (data[0] == RR); + else + return ((data[0] & 0xf) == 1); +} + +static int +IsI(byte * data, int ext) +{ + return ((data[0] & 0x1) == 0x0); +} + +static int +IsSABMX(byte * data, int ext) +{ + return (ext ? (data[0] & ~0x10) == SABME : data[0] == 0x3f); +} + +static int +IsREJ(byte * data, int ext) +{ + return (ext ? data[0] == REJ : (data[0] & 0xf) == 0x9); +} + +static int +IsFRMR(byte * data, int ext) +{ + return ((data[0] & 0xef) == FRMR); +} + +static int +IsRNR(byte * data, int ext) +{ + if (ext) + return (data[0] == RNR); + else + return ((data[0] & 0xf) == 5); +} + +static struct FsmNode L2FnList[] = +{ + {ST_L2_1, EV_L2_DL_ESTABLISH, l2s1}, + {ST_L2_1, EV_L2_MDL_NOTEIPROC, l2s19}, + {ST_L2_3, EV_L2_MDL_ASSIGN, l2s17}, + {ST_L2_4, EV_L2_DL_UNIT_DATA, l2s2}, + {ST_L2_4, EV_L2_DL_ESTABLISH, l2s11}, + {ST_L2_7, EV_L2_DL_UNIT_DATA, l2s2}, + {ST_L2_7, EV_L2_DL_DATA, l2s7}, + {ST_L2_7, EV_L2_DL_RELEASE, l2s13}, + {ST_L2_7, EV_L2_ACK_PULL, l2s22}, + {ST_L2_8, EV_L2_DL_DATA, l2s7}, + {ST_L2_8, EV_L2_DL_RELEASE, l2s13}, + + {ST_L2_1, EV_L2_UI, l2s3}, + {ST_L2_4, EV_L2_UI, l2s3}, + {ST_L2_4, EV_L2_SABMX, l2s12}, + {ST_L2_4, EV_L2_DISC, l2s14_1}, + {ST_L2_5, EV_L2_UA, l2s5}, + {ST_L2_6, EV_L2_UA, l2s15}, + {ST_L2_7, EV_L2_UI, l2s3}, + {ST_L2_7, EV_L2_DISC, l2s14}, + {ST_L2_7, EV_L2_I, l2s8}, + {ST_L2_7, EV_L2_RR, l2s6}, + {ST_L2_7, EV_L2_REJ, l2s16}, + {ST_L2_7, EV_L2_SABMX, l2s27}, + {ST_L2_7, EV_L2_FRMR, l2s28}, + {ST_L2_8, EV_L2_RR, l2s24}, + {ST_L2_8, EV_L2_REJ, l2s24}, + {ST_L2_8, EV_L2_SABMX, l2s27_1}, + {ST_L2_8, EV_L2_DISC, l2s14}, + {ST_L2_8, EV_L2_FRMR, l2s28}, + {ST_L2_8, EV_L2_I, l2s8_1}, + + {ST_L2_5, EV_L2_T200, l2s20}, + {ST_L2_6, EV_L2_T200, l2s21}, + {ST_L2_7, EV_L2_T200, l2s23}, + {ST_L2_7, EV_L2_T203, l2s25}, + {ST_L2_8, EV_L2_T200, l2s26}, + + {ST_L2_1, EV_L2_MDL_REMOVE, l2s30}, +/* {ST_L2_2, EV_L2_MDL_REMOVE, l2s30 }, */ + {ST_L2_3, EV_L2_MDL_REMOVE, l2s30}, + {ST_L2_4, EV_L2_MDL_REMOVE, l2s30}, + {ST_L2_5, EV_L2_MDL_REMOVE, l2s30}, + {ST_L2_6, EV_L2_MDL_REMOVE, l2s30}, + {ST_L2_7, EV_L2_MDL_REMOVE, l2s30}, + {ST_L2_8, EV_L2_MDL_REMOVE, l2s30}, +}; + +#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode)) + +static void +isdnl2_l1l2(struct PStack *st, int pr, struct BufHeader *arg) +{ + struct BufHeader *ibh; + byte *datap; + int ret = !0; + + switch (pr) { + case (PH_DATA): + + ibh = arg; + datap = DATAPTR(ibh); + datap += l2addrsize(&st->l2); + + if (IsI(datap, st->l2.extended)) + ret = FsmEvent(&st->l2.l2m, EV_L2_I, ibh); + else if (IsRR(datap, st->l2.extended)) + ret = FsmEvent(&st->l2.l2m, EV_L2_RR, ibh); + else if (IsUI(datap, st->l2.extended)) + ret = FsmEvent(&st->l2.l2m, EV_L2_UI, ibh); + else if (IsSABMX(datap, st->l2.extended)) + ret = FsmEvent(&st->l2.l2m, EV_L2_SABMX, ibh); + else if (IsUA(datap, st->l2.extended)) + ret = FsmEvent(&st->l2.l2m, EV_L2_UA, ibh); + else if (IsDISC(datap, st->l2.extended)) + ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, ibh); + else if (IsREJ(datap, st->l2.extended)) + ret = FsmEvent(&st->l2.l2m, EV_L2_REJ, ibh); + else if (IsFRMR(datap, st->l2.extended)) + ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, ibh); + else if (IsRNR(datap, st->l2.extended)) + ret = FsmEvent(&st->l2.l2m, EV_L2_RNR, ibh); + + if (ret) + BufPoolRelease(ibh); + + break; + case (PH_PULL_ACK): + FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg); + break; + } +} + +static void +isdnl2_l3l2(struct PStack *st, int pr, + void *arg) +{ + switch (pr) { + case (DL_DATA): + if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg)) + BufPoolRelease((struct BufHeader *) arg); + break; + case (DL_UNIT_DATA): + if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg)) + BufPoolRelease((struct BufHeader *) 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); + break; + case (DL_RELEASE): + 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): + (&st->l2.l2m)->userint |= LC_FLUSH_WAIT; + break; + } +} + +static void +isdnl2_teil2(struct PStack *st, int pr, + void *arg) +{ + switch (pr) { + case (MDL_ASSIGN): + FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg); + break; + case (MDL_REMOVE): + FsmEvent(&st->l2.l2m, EV_L2_MDL_REMOVE, arg); + break; + } +} + +void +releasestack_isdnl2(struct PStack *st) +{ + FsmDelTimer(&st->l2.t200_timer, 15); + FsmDelTimer(&st->l2.t203_timer, 16); +} + +static void +l2m_debug(struct FsmInst *fi, char *s) +{ + 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); +} + +void +setstack_isdnl2(struct PStack *st, char *debug_id) +{ + st->l1.l1l2 = isdnl2_l1l2; + st->l3.l3l2 = isdnl2_l3l2; + st->ma.manl2 = isdnl2_manl2; + st->ma.teil2 = isdnl2_teil2; + + st->l2.uihsize = l2headersize(&st->l2, !0); + st->l2.ihsize = l2headersize(&st->l2, 0); + BufQueueInit(&(st->l2.i_queue)); + st->l2.rejexp = 0; + st->l2.debug = 0; + + st->l2.l2m.fsm = &l2fsm; + st->l2.l2m.state = ST_L2_1; + st->l2.l2m.debug = 0; + st->l2.l2m.userdata = st; + st->l2.l2m.userint = 0; + st->l2.l2m.printdebug = l2m_debug; + strcpy(st->l2.debug_id, debug_id); + + FsmInitTimer(&st->l2.l2m, &st->l2.t200_timer); + FsmInitTimer(&st->l2.l2m, &st->l2.t203_timer); + st->l2.t200_running = 0; +} + +void +setstack_transl2(struct PStack *st) +{ +} + +void +releasestack_transl2(struct PStack *st) +{ +} + +void +Isdnl2New(void) +{ + l2fsm.state_count = L2_STATE_COUNT; + l2fsm.event_count = L2_EVENT_COUNT; + l2fsm.strEvent = strL2Event; + l2fsm.strState = strL2State; + FsmNew(&l2fsm, L2FnList, L2_FN_COUNT); +} + +void +Isdnl2Free(void) +{ + FsmFree(&l2fsm); +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/isdnl2.h linux/drivers/isdn/hisax/isdnl2.h --- v2.1.26/linux/drivers/isdn/hisax/isdnl2.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/isdnl2.h Tue Feb 25 17:12:49 1997 @@ -0,0 +1,17 @@ +/* isdnl2.h */ + +#define RR 0x01 +#define RNR 0x05 +#define REJ 0x09 +#define SABME 0x6f +#define DM 0x0f +#define UI 0x03 +#define DISC 0x43 +#define UA 0x63 +#define FRMR 0x87 +#define XID 0xaf + +#define CMD 0 +#define RSP 1 + +#define LC_FLUSH_WAIT 1 diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/isdnl3.c linux/drivers/isdn/hisax/isdnl3.c --- v2.1.26/linux/drivers/isdn/hisax/isdnl3.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/isdnl3.c Tue Feb 25 17:12:49 1997 @@ -0,0 +1,162 @@ +/* $Id: isdnl3.c,v 1.6 1997/02/16 01:04:08 fritz Exp $ + + * Author Karsten Keil (keil@temic-ech.spacenet.de) + * based on the teles driver from Jan den Ouden + * + * Thanks to Jan den Ouden + * Fritz Elfert + * + * $Log: isdnl3.c,v $ + * Revision 1.6 1997/02/16 01:04:08 fritz + * Bugfix: Changed timer handling caused hang with 2.1.X + * + * Revision 1.5 1997/02/09 00:26:27 keil + * new interface handling, one interface per card + * leased line changes + * + * Revision 1.4 1997/01/27 23:17:44 keil + * delete timers while unloading + * + * Revision 1.3 1997/01/21 22:31:12 keil + * new statemachine; L3 timers + * + * Revision 1.2 1996/11/05 19:42:04 keil + * using config.h + * + * Revision 1.1 1996/10/13 20:04:54 keil + * Initial revision + * + * + * + */ +#define __NO_VERSION__ +#include "hisax.h" +#include "isdnl3.h" +#include + +const char *l3_revision = "$Revision: 1.6 $"; + +void +l3_debug(struct PStack *st, char *s) +{ + char str[256], tm[32]; + + jiftime(tm, jiffies); + sprintf(str, "%s Channel %d l3 %s\n", tm, st->l3.channr, s); + HiSax_putstatus(st->l1.hardware, str); +} + + + +void +newl3state(struct PStack *st, int state) +{ + char tmp[80]; + + if (st->l3.debug & L3_DEB_STATE) { + sprintf(tmp, "newstate %d --> %d", st->l3.state, state); + l3_debug(st, tmp); + } + st->l3.state = state; +} + +static void +L3ExpireTimer(struct L3Timer *t) +{ + t->st->l4.l4l3(t->st, t->event, NULL); +} + +void +L3InitTimer(struct PStack *st, struct L3Timer *t) +{ + t->st = st; + t->tl.function = (void *) L3ExpireTimer; + t->tl.data = (long) t; + init_timer(&t->tl); +} + +void +L3DelTimer(struct L3Timer *t) +{ + del_timer(&t->tl); +} + +int +L3AddTimer(struct L3Timer *t, + int millisec, int event) +{ + if (t->tl.next || t->tl.prev) { + printk(KERN_WARNING "L3AddTimer: timer already active!\n"); + return -1; + } + init_timer(&t->tl); + t->event = event; + t->tl.expires = jiffies + (millisec * HZ) / 1000; + add_timer(&t->tl); + return 0; +} + +void +StopAllL3Timer(struct PStack *st) +{ + L3DelTimer(&st->l3.timer); +} + +static void +no_l3_proto(struct PStack *st, int pr, void *arg) +{ + struct BufHeader *ibh = arg; + + l3_debug(st, "no protocol"); + if (ibh) + BufPoolRelease(ibh); +} + +#ifdef CONFIG_HISAX_EURO +extern void setstack_dss1(struct PStack *st); +#endif + +#ifdef CONFIG_HISAX_1TR6 +extern void setstack_1tr6(struct PStack *st); +#endif + +void +setstack_isdnl3(struct PStack *st, struct Channel *chanp) +{ + char tmp[64]; + + st->l3.debug = L3_DEB_WARN; + st->l3.channr = chanp->chan; + L3InitTimer(st, &st->l3.timer); + +#ifdef CONFIG_HISAX_EURO + if (st->protocol == ISDN_PTYPE_EURO) { + setstack_dss1(st); + } else +#endif +#ifdef CONFIG_HISAX_1TR6 + if (st->protocol == ISDN_PTYPE_1TR6) { + setstack_1tr6(st); + } else +#endif + if (st->protocol == ISDN_PTYPE_LEASED) { + st->l4.l4l3 = no_l3_proto; + st->l2.l2l3 = no_l3_proto; + printk(KERN_NOTICE "HiSax: Leased line mode\n"); + } else { + sprintf(tmp, "protocol %s not supported", + (st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" : + (st->protocol == ISDN_PTYPE_EURO) ? "euro" : + "unknown"); + l3_debug(st, tmp); + st->protocol = -1; + } + st->l3.state = 0; + st->l3.callref = 0; +} + +void +releasestack_isdnl3(struct PStack *st) +{ + StopAllL3Timer(st); +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/isdnl3.h linux/drivers/isdn/hisax/isdnl3.h --- v2.1.26/linux/drivers/isdn/hisax/isdnl3.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/isdnl3.h Tue Feb 25 17:12:49 1997 @@ -0,0 +1,34 @@ +/* $Id: isdnl3.h,v 1.2 1997/01/21 22:31:28 keil Exp $ + * + * $Log: isdnl3.h,v $ + * Revision 1.2 1997/01/21 22:31:28 keil + * new statemachine; L3 timers + * + * Revision 1.1 1996/10/13 20:03:47 keil + * Initial revision + * + * + */ + +#define SBIT(state) (1< + +extern const char *CardType[]; +const char *ix1_revision = "$Revision: 1.1 $"; + +#define byteout(addr,val) outb_p(val,addr) +#define bytein(addr) inb_p(addr) + +#define SPECIAL_PORT_OFFSET 3 + +#define ISAC_COMMAND_OFFSET 2 +#define ISAC_DATA_OFFSET 0 +#define HSCX_COMMAND_OFFSET 2 +#define HSCX_DATA_OFFSET 1 + +#define ISAC_FIFOSIZE 16 +#define HSCX_FIFOSIZE 16 + +#define TIMEOUT 50 + +static inline byte +IsacReadReg(unsigned int adr, byte off) +{ + byteout(adr + ISAC_COMMAND_OFFSET, off + 0x20); + return bytein(adr + ISAC_DATA_OFFSET); +} + +static inline void +IsacWriteReg(unsigned int adr, byte off, byte data) +{ + byteout(adr + ISAC_COMMAND_OFFSET, off + 0x20); + byteout(adr + ISAC_DATA_OFFSET, data); +} + +#define HSCX_OFFSET(WhichHscx,offset) \ +( (WhichHscx) ? (offset+0x60) : (offset+0x20) ) + +static inline byte +HscxReadReg(unsigned int adr, int WhichHscx, byte off) +{ + byteout(adr + HSCX_COMMAND_OFFSET, HSCX_OFFSET(WhichHscx, off)); + return bytein(adr + HSCX_DATA_OFFSET); +} + +static inline void +HscxWriteReg(unsigned int adr, int WhichHscx, byte off, byte data) +{ + byteout(adr + HSCX_COMMAND_OFFSET, HSCX_OFFSET(WhichHscx, off)); + byteout(adr + HSCX_DATA_OFFSET, data); +} + + +static inline void +IsacReadFifo(unsigned int adr, byte * data, int size) +{ + byteout(adr + ISAC_COMMAND_OFFSET, 0); + while (size--) + *data++ = bytein(adr + ISAC_DATA_OFFSET); +} + +static void +IsacWriteFifo(unsigned int adr, byte * data, int size) +{ + byteout(adr + ISAC_COMMAND_OFFSET, 0); + while (size--) { + byteout(adr + ISAC_DATA_OFFSET, *data); + data++; + } +} + +static inline void +HscxReadFifo(unsigned int adr, int WhichHscx, byte * data, int size) +{ + byteout(adr + HSCX_COMMAND_OFFSET, (WhichHscx) ? 0x40 : 0x00); + while (size--) + *data++ = bytein(adr + HSCX_DATA_OFFSET); +} + +static void +HscxWriteFifo(unsigned int adr, int WhichHscx, byte * data, int size) +{ + byteout(adr + HSCX_COMMAND_OFFSET, (WhichHscx) ? 0x40 : 0x00); + while (size--) { + byteout(adr + HSCX_DATA_OFFSET, *data); + data++; + } +} + +static inline void +waitforCEC(int adr, int WhichHscx) +{ + int to = TIMEOUT; + + while ((HscxReadReg(adr, WhichHscx, HSCX_STAR) & 0x04) && to) { + udelay(1); + to--; + } + if (!to) + printk(KERN_WARNING "ix1-Micro: waitforCEC timeout\n"); +} + + +static inline void +waitforXFW(int adr, int WhichHscx) +{ + int to = TIMEOUT; + + while ((!(HscxReadReg(adr, WhichHscx, HSCX_STAR) & 0x44) == 0x40) && to) { + udelay(1); + to--; + } + if (!to) + printk(KERN_WARNING "ix1-Micro: waitforXFW timeout\n"); +} + +static inline void +writehscxCMDR(int adr, int WhichHscx, byte data) +{ + long flags; + + save_flags(flags); + cli(); + waitforCEC(adr, WhichHscx); + HscxWriteReg(adr, WhichHscx, HSCX_CMDR, data); + restore_flags(flags); +} + +/* + * fast interrupt here + */ + +static void +hscxreport(struct IsdnCardState *sp, int hscx) +{ + printk(KERN_DEBUG "HSCX %d\n", hscx); + printk(KERN_DEBUG "ISTA %x\n", HscxReadReg(sp->hscx[hscx], hscx, HSCX_ISTA)); + printk(KERN_DEBUG "STAR %x\n", HscxReadReg(sp->hscx[hscx], hscx, HSCX_STAR)); + printk(KERN_DEBUG "EXIR %x\n", HscxReadReg(sp->hscx[hscx], hscx, HSCX_EXIR)); +} + +void +ix1micro_report(struct IsdnCardState *sp) +{ + printk(KERN_DEBUG "ISAC\n"); + printk(KERN_DEBUG "ISTA %x\n", IsacReadReg(sp->isac, ISAC_ISTA)); + printk(KERN_DEBUG "STAR %x\n", IsacReadReg(sp->isac, ISAC_STAR)); + printk(KERN_DEBUG "EXIR %x\n", IsacReadReg(sp->isac, ISAC_EXIR)); + hscxreport(sp, 0); + hscxreport(sp, 1); +} + +/* + * HSCX stuff goes here + */ + +static void +hscx_empty_fifo(struct HscxState *hsp, int count) +{ + byte *ptr; + struct IsdnCardState *sp = hsp->sp; + struct BufHeader *ibh = hsp->rcvibh; + long flags; + + if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO)) + debugl1(sp, "hscx_empty_fifo"); + + if (hsp->rcvptr + count > BUFFER_SIZE(HSCX_RBUF_ORDER, + HSCX_RBUF_BPPS)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "hscx_empty_fifo: incoming packet too large"); + writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x80); + return; + } + ptr = DATAPTR(ibh); + ptr += hsp->rcvptr; + + hsp->rcvptr += count; + save_flags(flags); + cli(); + HscxReadFifo(sp->hscx[hsp->hscx], hsp->hscx, ptr, count); + writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x80); + restore_flags(flags); + if (sp->debug & L1_DEB_HSCX_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "hscx_empty_fifo %c cnt %d", + hsp->hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static void +hscx_fill_fifo(struct HscxState *hsp) +{ + struct IsdnCardState *sp = hsp->sp; + struct BufHeader *ibh; + int more, count; + byte *ptr; + long flags; + + if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO)) + debugl1(sp, "hscx_fill_fifo"); + + ibh = hsp->xmtibh; + if (!ibh) + return; + + count = ibh->datasize - hsp->sendptr; + if (count <= 0) + return; + + more = (hsp->mode == 1) ? 1 : 0; + if (count > 32) { + more = !0; + count = 32; + } + ptr = DATAPTR(ibh); + ptr += hsp->sendptr; + hsp->sendptr += count; + + waitforXFW(sp->hscx[hsp->hscx], hsp->hscx); + save_flags(flags); + cli(); + HscxWriteFifo(sp->hscx[hsp->hscx], hsp->hscx, ptr, count); + writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, more ? 0x8 : 0xa); + restore_flags(flags); + if (sp->debug & L1_DEB_HSCX_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "hscx_fill_fifo %c cnt %d", + hsp->hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static inline void +hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx) +{ + byte r; + struct HscxState *hsp = sp->hs + hscx; + int count, err; + char tmp[32]; + + if (!hsp->init) + return; + + if (val & 0x80) { /* RME */ + + r = HscxReadReg(sp->hscx[hsp->hscx], hscx, HSCX_RSTA); + if ((r & 0xf0) != 0xa0) { + if (!r & 0x80) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX invalid frame"); + if ((r & 0x40) && hsp->mode) + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "HSCX RDO mode=%d", + hsp->mode); + debugl1(sp, tmp); + } + if (!r & 0x20) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX CRC error"); + if (hsp->rcvibh) + BufPoolRelease(hsp->rcvibh); + hsp->rcvibh = NULL; + writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x80); + goto afterRME; + } + if (!hsp->rcvibh) + if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool, + GFP_ATOMIC, (void *) 1, 1)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX RME out of buffers"); + writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x80); + goto afterRME; + } else + hsp->rcvptr = 0; + + count = HscxReadReg(sp->hscx[hsp->hscx], hscx, HSCX_RBCL) & 0x1f; + if (count == 0) + count = 32; + hscx_empty_fifo(hsp, count); + hsp->rcvibh->datasize = hsp->rcvptr - 1; + BufQueueLink(&hsp->rq, hsp->rcvibh); + hsp->rcvibh = NULL; + hscx_sched_event(hsp, HSCX_RCVBUFREADY); + } + afterRME: + if (val & 0x40) { /* RPF */ + if (!hsp->rcvibh) { + if (hsp->mode == 1) + err = BufPoolGet(&hsp->rcvibh, &hsp->smallpool, + GFP_ATOMIC, (void *) 1, 2); + else + err = BufPoolGet(&hsp->rcvibh, &hsp->rbufpool, + GFP_ATOMIC, (void *) 1, 2); + + if (err) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX RPF out of buffers"); + writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x80); + goto afterRPF; + } else + hsp->rcvptr = 0; + } + hscx_empty_fifo(hsp, 32); + if (hsp->mode == 1) { + /* receive audio data */ + hsp->rcvibh->datasize = hsp->rcvptr; + BufQueueLink(&hsp->rq, hsp->rcvibh); + hsp->rcvibh = NULL; + hscx_sched_event(hsp, HSCX_RCVBUFREADY); + } + } + afterRPF: + if (val & 0x10) { /* XPR */ + if (hsp->xmtibh) + if (hsp->xmtibh->datasize > hsp->sendptr) { + hscx_fill_fifo(hsp); + goto afterXPR; + } else { + if (hsp->releasebuf) + BufPoolRelease(hsp->xmtibh); + hsp->sendptr = 0; + if (hsp->st->l4.l1writewakeup) + hsp->st->l4.l1writewakeup(hsp->st); + hsp->xmtibh = NULL; + } + if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) { + hsp->releasebuf = !0; + hscx_fill_fifo(hsp); + } else + hscx_sched_event(hsp, HSCX_XMTBUFREADY); + } + afterXPR: +} + +/* + * ISAC stuff goes here + */ + +static void +isac_empty_fifo(struct IsdnCardState *sp, int count) +{ + byte *ptr; + struct BufHeader *ibh = sp->rcvibh; + long flags; + + if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO)) + if (sp->debug & L1_DEB_ISAC) + debugl1(sp, "isac_empty_fifo"); + + if (sp->rcvptr >= 3072) { + if (sp->debug & L1_DEB_WARN) { + char tmp[40]; + sprintf(tmp, "isac_empty_fifo rcvptr %d", sp->rcvptr); + debugl1(sp, tmp); + } + return; + } + ptr = DATAPTR(ibh); + ptr += sp->rcvptr; + sp->rcvptr += count; + + save_flags(flags); + cli(); + IsacReadFifo(sp->isac, ptr, count); + IsacWriteReg(sp->isac, ISAC_CMDR, 0x80); + restore_flags(flags); + if (sp->debug & L1_DEB_ISAC_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "isac_empty_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static void +isac_fill_fifo(struct IsdnCardState *sp) +{ + struct BufHeader *ibh; + int count, more; + byte *ptr; + long flags; + + if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO)) + debugl1(sp, "isac_fill_fifo"); + + ibh = sp->xmtibh; + if (!ibh) + return; + + count = ibh->datasize - sp->sendptr; + if (count <= 0) + return; + if (count >= 3072) + return; + + more = 0; + if (count > 32) { + more = !0; + count = 32; + } + ptr = DATAPTR(ibh); + ptr += sp->sendptr; + sp->sendptr += count; + + save_flags(flags); + cli(); + IsacWriteFifo(sp->isac, ptr, count); + IsacWriteReg(sp->isac, ISAC_CMDR, more ? 0x8 : 0xa); + restore_flags(flags); + if (sp->debug & L1_DEB_ISAC_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "isac_fill_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static void +ph_command(struct IsdnCardState *sp, unsigned int command) +{ + if (sp->debug & L1_DEB_ISAC) { + char tmp[32]; + sprintf(tmp, "ph_command %d", command); + debugl1(sp, tmp); + } + IsacWriteReg(sp->isac, ISAC_CIX0, (command << 2) | 3); +} + + +static inline void +isac_interrupt(struct IsdnCardState *sp, byte val) +{ + byte exval; + unsigned int count; + char tmp[32]; + + if (sp->debug & L1_DEB_ISAC) { + sprintf(tmp, "ISAC interrupt %x", val); + debugl1(sp, tmp); + } + if (val & 0x80) { /* RME */ + exval = IsacReadReg(sp->isac, ISAC_RSTA); + if ((exval & 0x70) != 0x20) { + if (exval & 0x40) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RDO"); + if (!exval & 0x20) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC CRC error"); + if (sp->rcvibh) + BufPoolRelease(sp->rcvibh); + sp->rcvibh = NULL; + IsacWriteReg(sp->isac, ISAC_CMDR, 0x80); + goto afterRME; + } + if (!sp->rcvibh) + if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool), + GFP_ATOMIC, (void *) 1, 3)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RME out of buffers!"); + IsacWriteReg(sp->isac, ISAC_CMDR, 0x80); + goto afterRME; + } else + sp->rcvptr = 0; + count = IsacReadReg(sp->isac, ISAC_RBCL) & 0x1f; + if (count == 0) + count = 32; + isac_empty_fifo(sp, count); + sp->rcvibh->datasize = sp->rcvptr; + BufQueueLink(&(sp->rq), sp->rcvibh); + sp->rcvibh = NULL; + isac_sched_event(sp, ISAC_RCVBUFREADY); + } + afterRME: + if (val & 0x40) { /* RPF */ + if (!sp->rcvibh) + if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool), + GFP_ATOMIC, (void *) 1, 4)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RME out of buffers!"); + IsacWriteReg(sp->isac, ISAC_CMDR, 0x80); + goto afterRPF; + } else + sp->rcvptr = 0; + isac_empty_fifo(sp, 32); + } + afterRPF: + if (val & 0x20) { /* RSC */ + /* never */ + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RSC interrupt"); + } + if (val & 0x10) { /* XPR */ + if (sp->xmtibh) + if (sp->xmtibh->datasize > sp->sendptr) { + isac_fill_fifo(sp); + goto afterXPR; + } else { + if (sp->releasebuf) + BufPoolRelease(sp->xmtibh); + sp->xmtibh = NULL; + sp->sendptr = 0; + } + if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) { + sp->releasebuf = !0; + isac_fill_fifo(sp); + } else + isac_sched_event(sp, ISAC_XMTBUFREADY); + } + afterXPR: + if (val & 0x04) { /* CISQ */ + sp->ph_state = (IsacReadReg(sp->isac, ISAC_CIX0) >> 2) + & 0xf; + if (sp->debug & L1_DEB_ISAC) { + sprintf(tmp, "l1state %d", sp->ph_state); + debugl1(sp, tmp); + } + isac_new_ph(sp); + } + if (val & 0x02) { /* SIN */ + /* never */ + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC SIN interrupt"); + } + if (val & 0x01) { /* EXI */ + exval = IsacReadReg(sp->isac, ISAC_EXIR); + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "ISAC EXIR %02x", exval); + debugl1(sp, tmp); + } + } +} + +static inline void +hscx_int_main(struct IsdnCardState *sp, byte val) +{ + + byte exval; + struct HscxState *hsp; + char tmp[32]; + + + if (val & 0x01) { + hsp = sp->hs + 1; + exval = HscxReadReg(sp->hscx[1], 1, HSCX_EXIR); + if (exval == 0x40) { + if (hsp->mode == 1) + hscx_fill_fifo(hsp); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + hsp->sendptr = 0; + writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x01); + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "HSCX B EXIR %x Lost TX", exval); + debugl1(sp, tmp); + } + } + } else if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX B EXIR %x", exval); + debugl1(sp, tmp); + } + } + if (val & 0xf8) { + if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX B interrupt %x", val); + debugl1(sp, tmp); + } + hscx_interrupt(sp, val, 1); + } + if (val & 0x02) { + hsp = sp->hs; + exval = HscxReadReg(sp->hscx[0], 0, HSCX_EXIR); + if (exval == 0x40) { + if (hsp->mode == 1) + hscx_fill_fifo(hsp); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + hsp->sendptr = 0; + writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x01); + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "HSCX A EXIR %x Lost TX", exval); + debugl1(sp, tmp); + } + } + } else if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX A EXIR %x", exval); + debugl1(sp, tmp); + } + } + if (val & 0x04) { + exval = HscxReadReg(sp->hscx[0], 0, HSCX_ISTA); + if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX A interrupt %x", exval); + debugl1(sp, tmp); + } + hscx_interrupt(sp, exval, 0); + } +} + +static void +ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *sp; + byte val, stat = 0; + + sp = (struct IsdnCardState *) irq2dev_map[intno]; + + if (!sp) { + printk(KERN_WARNING "Teles: Spurious interrupt!\n"); + return; + } + val = HscxReadReg(sp->hscx[1], 1, HSCX_ISTA); + Start_HSCX: + if (val) { + hscx_int_main(sp, val); + stat |= 1; + } + val = IsacReadReg(sp->isac, ISAC_ISTA); + Start_ISAC: + if (val) { + isac_interrupt(sp, val); + stat |= 2; + } + val = HscxReadReg(sp->hscx[1], 1, HSCX_ISTA); + if (val) { + if (sp->debug & L1_DEB_HSCX) + debugl1(sp, "HSCX IntStat after IntRoutine"); + goto Start_HSCX; + } + val = IsacReadReg(sp->isac, ISAC_ISTA); + if (val) { + if (sp->debug & L1_DEB_ISAC) + debugl1(sp, "ISAC IntStat after IntRoutine"); + goto Start_ISAC; + } + if (stat & 1) { + HscxWriteReg(sp->hscx[0], 0, HSCX_MASK, 0xFF); + HscxWriteReg(sp->hscx[1], 1, HSCX_MASK, 0xFF); + HscxWriteReg(sp->hscx[0], 0, HSCX_MASK, 0x0); + HscxWriteReg(sp->hscx[1], 1, HSCX_MASK, 0x0); + } + if (stat & 2) { + IsacWriteReg(sp->isac, ISAC_MASK, 0xFF); + IsacWriteReg(sp->isac, ISAC_MASK, 0x0); + } +} + + +static void +initisac(struct IsdnCardState *sp) +{ + unsigned int adr = sp->isac; + + /* 16.3 IOM 2 Mode */ + IsacWriteReg(adr, ISAC_MASK, 0xff); + IsacWriteReg(adr, ISAC_ADF2, 0x80); + IsacWriteReg(adr, ISAC_SQXR, 0x2f); + IsacWriteReg(adr, ISAC_SPCR, 0x0); + IsacWriteReg(adr, ISAC_ADF1, 0x2); + IsacWriteReg(adr, ISAC_STCR, 0x70); + IsacWriteReg(adr, ISAC_MODE, 0xc9); + IsacWriteReg(adr, ISAC_TIMR, 0x0); + IsacWriteReg(adr, ISAC_ADF1, 0x0); + IsacWriteReg(adr, ISAC_CMDR, 0x41); + IsacWriteReg(adr, ISAC_CIX0, (1 << 2) | 3); + IsacWriteReg(adr, ISAC_MASK, 0xff); + IsacWriteReg(adr, ISAC_MASK, 0x0); +} + +static void +modehscx(struct HscxState *hs, int mode, int ichan) +{ + struct IsdnCardState *sp = hs->sp; + int hscx = hs->hscx; + + if (sp->debug & L1_DEB_HSCX) { + char tmp[40]; + sprintf(tmp, "hscx %c mode %d ichan %d", + 'A' + hscx, mode, ichan); + debugl1(sp, tmp); + } + hs->mode = mode; + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR1, 0x85); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XAD1, 0xFF); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XAD2, 0xFF); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RAH2, 0xFF); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XBCH, 0x0); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RLCR, 0x0); + + switch (mode) { + case 0: + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0xff); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0xff); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_MODE, 0x84); + break; + case 1: + if (ichan == 0) { + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0x2f); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0x2f); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7); + } else { + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0x3); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0x3); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7); + } + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_MODE, 0xe4); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CMDR, 0x41); + break; + case 2: + if (ichan == 0) { + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0x2f); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0x2f); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7); + } else { + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0x3); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0x3); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7); + } + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_MODE, 0x8c); + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CMDR, 0x41); + break; + } + HscxWriteReg(sp->hscx[hscx], hscx, HSCX_ISTA, 0x00); +} + +void +release_io_ix1micro(struct IsdnCard *card) +{ + if (card->sp->cfg_reg) + release_region(card->sp->cfg_reg, 4); +} + +static void +clear_pending_ints(struct IsdnCardState *sp) +{ + int val; + char tmp[64]; + + val = HscxReadReg(sp->hscx[1], 1, HSCX_ISTA); + sprintf(tmp, "HSCX B ISTA %x", val); + debugl1(sp, tmp); + if (val & 0x01) { + val = HscxReadReg(sp->hscx[1], 1, HSCX_EXIR); + sprintf(tmp, "HSCX B EXIR %x", val); + debugl1(sp, tmp); + } else if (val & 0x02) { + val = HscxReadReg(sp->hscx[0], 0, HSCX_EXIR); + sprintf(tmp, "HSCX A EXIR %x", val); + debugl1(sp, tmp); + } + val = HscxReadReg(sp->hscx[0], 0, HSCX_ISTA); + sprintf(tmp, "HSCX A ISTA %x", val); + debugl1(sp, tmp); + val = HscxReadReg(sp->hscx[1], 1, HSCX_STAR); + sprintf(tmp, "HSCX B STAR %x", val); + debugl1(sp, tmp); + val = HscxReadReg(sp->hscx[0], 0, HSCX_STAR); + sprintf(tmp, "HSCX A STAR %x", val); + debugl1(sp, tmp); + val = IsacReadReg(sp->isac, ISAC_STAR); + sprintf(tmp, "ISAC STAR %x", val); + debugl1(sp, tmp); + val = IsacReadReg(sp->isac, ISAC_MODE); + sprintf(tmp, "ISAC MODE %x", val); + debugl1(sp, tmp); + val = IsacReadReg(sp->isac, ISAC_ADF2); + sprintf(tmp, "ISAC ADF2 %x", val); + debugl1(sp, tmp); + val = IsacReadReg(sp->isac, ISAC_ISTA); + sprintf(tmp, "ISAC ISTA %x", val); + debugl1(sp, tmp); + if (val & 0x01) { + val = IsacReadReg(sp->isac, ISAC_EXIR); + sprintf(tmp, "ISAC EXIR %x", val); + debugl1(sp, tmp); + } else if (val & 0x04) { + val = IsacReadReg(sp->isac, ISAC_CIR0); + sprintf(tmp, "ISAC CIR0 %x", val); + debugl1(sp, tmp); + } + IsacWriteReg(sp->isac, ISAC_MASK, 0); + IsacWriteReg(sp->isac, ISAC_CMDR, 0x41); +} + +int +initix1micro(struct IsdnCardState *sp) +{ + int ret; + char tmp[40]; + + sp->counter = kstat.interrupts[sp->irq]; + sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter); + debugl1(sp, tmp); + clear_pending_ints(sp); + ret = get_irq(sp->cardnr, &ix1micro_interrupt); + if (ret) { + initisac(sp); + sp->modehscx(sp->hs, 0, 0); + sp->modehscx(sp->hs + 1, 0, 0); + sprintf(tmp, "IRQ %d count %d", sp->irq, + kstat.interrupts[sp->irq]); + debugl1(sp, tmp); + if (kstat.interrupts[sp->irq] == sp->counter) { + printk(KERN_WARNING + "ix1-Micro: IRQ(%d) getting no interrupts during init\n", + sp->irq); + irq2dev_map[sp->irq] = NULL; + free_irq(sp->irq, NULL); + return (0); + } + } + return (ret); +} + +int +setup_ix1micro(struct IsdnCard *card) +{ + byte val, verA, verB; + struct IsdnCardState *sp = card->sp; + long flags; + char tmp[64]; + + strcpy(tmp, ix1_revision); + printk(KERN_NOTICE "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp)); + if (sp->typ != ISDN_CTYPE_IX1MICROR2) + return (0); + + /* IO-Ports */ + sp->isac = sp->hscx[0] = sp->hscx[1] = sp->cfg_reg = card->para[1]; + sp->irq = card->para[0]; + if (sp->cfg_reg) { + if (check_region((sp->cfg_reg), 4)) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + sp->cfg_reg, + sp->cfg_reg + 4); + return (0); + } else + request_region(sp->cfg_reg, 4, "ix1micro cfg"); + } + /* reset isac */ + save_flags(flags); + val = 3 * (HZ / 10) + 1; + sti(); + while (val--) { + byteout(sp->cfg_reg + SPECIAL_PORT_OFFSET, 1); + HZDELAY(1); /* wait >=10 ms */ + } + byteout(sp->cfg_reg + SPECIAL_PORT_OFFSET, 0); + restore_flags(flags); + + printk(KERN_NOTICE + "HiSax: %s config irq:%d io:0x%x\n", + CardType[sp->typ], sp->irq, + sp->cfg_reg); + verA = HscxReadReg(sp->hscx[0], 0, HSCX_VSTR) & 0xf; + verB = HscxReadReg(sp->hscx[1], 1, HSCX_VSTR) & 0xf; + printk(KERN_INFO "ix1-Micro: HSCX version A: %s B: %s\n", + HscxVersion(verA), HscxVersion(verB)); + val = IsacReadReg(sp->isac, ISAC_RBCH); + printk(KERN_INFO "ix1-Micro: ISAC %s\n", + ISACVersion(val)); + if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) { + printk(KERN_WARNING + "ix1-Micro: wrong HSCX versions check IO address\n"); + release_io_ix1micro(card); + return (0); + } + sp->modehscx = &modehscx; + sp->ph_command = &ph_command; + sp->hscx_fill_fifo = &hscx_fill_fifo; + sp->isac_fill_fifo = &isac_fill_fifo; + return (1); +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/ix1_micro.h linux/drivers/isdn/hisax/ix1_micro.h --- v2.1.26/linux/drivers/isdn/hisax/ix1_micro.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/ix1_micro.h Tue Feb 25 17:12:49 1997 @@ -0,0 +1,50 @@ +/* $Id: ix1_micro.h,v 1.1 1997/01/27 15:42:48 keil Exp $ + + * ix1_micro.h low level stuff for ITK ix1-micro Rev.2 isdn cards + * + * derived from teles3.h from Karsten Keil + * + * Copyright (C) 1997 Klaus-Peter Nischke (ITK AG) (for the modifications + to the original file teles.c) + * + * $Log: ix1_micro.h,v $ + * Revision 1.1 1997/01/27 15:42:48 keil + * first version + * + * + */ + +/* + For the modification done by the author the following terms and conditions + apply (GNU PUBLIC LICENSE) + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + + You may contact Klaus-Peter Nischke by email: klaus@nischke.do.eunet.de + or by conventional mail: + + Klaus-Peter Nischke + Deusener Str. 287 + 44369 Dortmund + Germany + */ + + +extern void ix1micro_report(struct IsdnCardState *sp); +extern void release_io_ix1micro(struct IsdnCard *card); +extern int setup_ix1micro(struct IsdnCard *card); +extern int initix1micro(struct IsdnCardState *sp); diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/l3_1tr6.c linux/drivers/isdn/hisax/l3_1tr6.c --- v2.1.26/linux/drivers/isdn/hisax/l3_1tr6.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/l3_1tr6.c Tue Feb 25 17:12:49 1997 @@ -0,0 +1,784 @@ +/* $Id: l3_1tr6.c,v 1.9 1997/02/11 01:37:40 keil Exp $ + + * German 1TR6 D-channel protocol + * + * Author Karsten Keil (keil@temic-ech.spacenet.de) + * + * + * $Log: l3_1tr6.c,v $ + * Revision 1.9 1997/02/11 01:37:40 keil + * Changed setup-interface (incoming and outgoing) + * + * Revision 1.8 1997/01/27 23:20:21 keil + * report revision only ones + * + * Revision 1.7 1997/01/21 22:30:07 keil + * new statemachine; L3 timers + * + * Revision 1.6 1996/12/14 21:07:20 keil + * additional states for CC_REJECT + * + * Revision 1.5 1996/12/08 19:55:17 keil + * change CC_REJECT_REQ routine + * + * Revision 1.4 1996/10/30 10:18:01 keil + * bugfixes in debugging output + * + * Revision 1.3 1996/10/27 22:15:37 keil + * bugfix reject handling + * + * Revision 1.2 1996/10/13 23:08:56 keil + * added missing state for callback reject + * + * Revision 1.1 1996/10/13 20:04:55 keil + * Initial revision + * + * + */ + +#define __NO_VERSION__ +#include "hisax.h" +#include "l3_1tr6.h" +#include "isdnl3.h" + +extern char *HiSax_getrev(const char *revision); +const char *l3_1tr6_revision = "$Revision: 1.9 $"; + +#define MsgHead(ptr, cref, mty, dis) \ + *ptr++ = dis; \ + *ptr++ = 0x1; \ + *ptr++ = cref; \ + *ptr++ = mty + +static void +l3_1TR6_message(struct PStack *st, byte mt, byte pd) +{ + struct BufHeader *dibh; + byte *p; + + BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18); + p = DATAPTR(dibh); + p += st->l2.ihsize; + + MsgHead(p, st->l3.callref, mt, pd); + + dibh->datasize = p - DATAPTR(dibh); + st->l3.l3l2(st, DL_DATA, dibh); +} + +static void +l3_1tr6_setup_req(struct PStack *st, byte pr, void *arg) +{ + struct BufHeader *dibh; + byte *p; + char *teln; + + st->l3.callref = st->pa->callref; + BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19); + p = DATAPTR(dibh); + p += st->l2.ihsize; + + MsgHead(p, st->l3.callref, MT_N1_SETUP, PROTO_DIS_N1); + + if ('S' == (st->pa->setup.phone[0] & 0x5f)) { /* SPV ? */ + /* NSF SPV */ + *p++ = WE0_netSpecFac; + *p++ = 4; /* Laenge */ + *p++ = 0; + *p++ = FAC_SPV; /* SPV */ + *p++ = st->pa->setup.si1; /* 0 for all Services */ + *p++ = st->pa->setup.si2; /* 0 for all Services */ + *p++ = WE0_netSpecFac; + *p++ = 4; /* Laenge */ + *p++ = 0; + *p++ = FAC_Activate; /* aktiviere SPV (default) */ + *p++ = st->pa->setup.si1; /* 0 for all Services */ + *p++ = st->pa->setup.si2; /* 0 for all Services */ + } + if (st->pa->setup.eazmsn[0] != '\0') { + *p++ = WE0_origAddr; + *p++ = strlen(st->pa->setup.eazmsn) + 1; + /* Classify as AnyPref. */ + *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ + teln = st->pa->setup.eazmsn; + while (*teln) + *p++ = *teln++ & 0x7f; + } + *p++ = WE0_destAddr; + teln = st->pa->setup.phone; + if ('S' != (st->pa->setup.phone[0] & 0x5f)) { /* Keine SPV */ + *p++ = strlen(st->pa->setup.phone) + 1; + st->pa->spv = 0; + } else { /* SPV */ + *p++ = strlen(st->pa->setup.phone); + teln++; /* skip S */ + st->pa->spv = 1; + } + /* Classify as AnyPref. */ + *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ + while (*teln) + *p++ = *teln++ & 0x7f; + + *p++ = WE_Shift_F6; + /* Codesatz 6 fuer Service */ + *p++ = WE6_serviceInd; + *p++ = 2; /* len=2 info,info2 */ + *p++ = st->pa->setup.si1; + *p++ = st->pa->setup.si2; + + dibh->datasize = p - DATAPTR(dibh); + + L3DelTimer(&st->l3.timer); + L3AddTimer(&st->l3.timer, st->l3.t303, CC_T303); + newl3state(st, 1); + st->l3.l3l2(st, DL_DATA, dibh); + +} + +static void +l3_1tr6_setup(struct PStack *st, byte pr, void *arg) +{ + byte *p; + int bcfound = 0; + char tmp[80]; + struct BufHeader *ibh = arg; + + p = DATAPTR(ibh); + p += st->l2.uihsize; + st->pa->callref = getcallref(p); + st->l3.callref = 0x80 + st->pa->callref; + + /* Channel Identification */ + p = DATAPTR(ibh); + if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, + WE0_chanID, 0))) { + st->pa->bchannel = p[2] & 0x3; + bcfound++; + } else if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "setup without bchannel"); + + p = DATAPTR(ibh); + + if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, WE6_serviceInd, 6))) { + st->pa->setup.si1 = p[2]; + st->pa->setup.si2 = p[3]; + } else if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "setup without service indicator"); + + p = DATAPTR(ibh); + if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, + WE0_destAddr, 0))) + iecpy(st->pa->setup.eazmsn, p, 1); + else + st->pa->setup.eazmsn[0] = 0; + + p = DATAPTR(ibh); + if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, + WE0_origAddr, 0))) { + iecpy(st->pa->setup.phone, p, 1); + } else + st->pa->setup.phone[0] = 0; + + p = DATAPTR(ibh); + st->pa->spv = 0; + if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, + WE0_netSpecFac, 0))) { + if ((FAC_SPV == p[3]) || (FAC_Activate == p[3])) + st->pa->spv = 1; + } + BufPoolRelease(ibh); + + /* Signal all services, linklevel takes care of Service-Indicator */ + if (bcfound) { + if ((st->pa->setup.si1 != 7) && (st->l3.debug & L3_DEB_WARN)) { + sprintf(tmp, "non-digital call: %s -> %s", + st->pa->setup.phone, + st->pa->setup.eazmsn); + l3_debug(st, tmp); + } + newl3state(st, 6); + st->l3.l3l4(st, CC_SETUP_IND, NULL); + } +} + +static void +l3_1tr6_setup_ack(struct PStack *st, byte pr, void *arg) +{ + byte *p; + struct BufHeader *ibh = arg; + + L3DelTimer(&st->l3.timer); + newl3state(st, 2); + p = DATAPTR(ibh); + if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, + WE0_chanID, 0))) { + st->pa->bchannel = p[2] & 0x3; + } else if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "setup answer without bchannel"); + + BufPoolRelease(ibh); + L3AddTimer(&st->l3.timer, st->l3.t304, CC_T304); + st->l3.l3l4(st, CC_MORE_INFO, NULL); +} + +static void +l3_1tr6_call_sent(struct PStack *st, byte pr, void *arg) +{ + byte *p; + struct BufHeader *ibh = arg; + + L3DelTimer(&st->l3.timer); + p = DATAPTR(ibh); + if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, + WE0_chanID, 0))) { + st->pa->bchannel = p[2] & 0x3; + } else if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "setup answer without bchannel"); + + BufPoolRelease(ibh); + L3AddTimer(&st->l3.timer, st->l3.t310, CC_T310); + newl3state(st, 3); + st->l3.l3l4(st, CC_PROCEEDING_IND, NULL); +} + +static void +l3_1tr6_alert(struct PStack *st, byte pr, void *arg) +{ + struct BufHeader *ibh = arg; + + BufPoolRelease(ibh); + L3DelTimer(&st->l3.timer); /* T304 */ + newl3state(st, 4); + st->l3.l3l4(st, CC_ALERTING_IND, NULL); +} + +static void +l3_1tr6_info(struct PStack *st, byte pr, void *arg) +{ + byte *p; + int i, tmpcharge = 0; + char a_charge[8], tmp[32]; + struct BufHeader *ibh = arg; + + p = DATAPTR(ibh); + if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, + WE6_chargingInfo, 6))) { + iecpy(a_charge, p, 1); + for (i = 0; i < strlen(a_charge); i++) { + tmpcharge *= 10; + tmpcharge += a_charge[i] & 0xf; + } + if (tmpcharge > st->pa->chargeinfo) { + st->pa->chargeinfo = tmpcharge; + st->l3.l3l4(st, CC_INFO_CHARGE, NULL); + } + if (st->l3.debug & L3_DEB_CHARGE) { + sprintf(tmp, "charging info %d", st->pa->chargeinfo); + l3_debug(st, tmp); + } + } else if (st->l3.debug & L3_DEB_CHARGE) + l3_debug(st, "charging info not found"); + + BufPoolRelease(ibh); +} + +static void +l3_1tr6_info_s2(struct PStack *st, byte pr, void *arg) +{ + struct BufHeader *ibh = arg; + + BufPoolRelease(ibh); +} + +static void +l3_1tr6_connect(struct PStack *st, byte pr, void *arg) +{ + struct BufHeader *ibh = arg; + + L3DelTimer(&st->l3.timer); /* T310 */ + newl3state(st, 10); + st->pa->chargeinfo = 0; + BufPoolRelease(ibh); + st->l3.l3l4(st, CC_SETUP_CNF, NULL); +} + +static void +l3_1tr6_rel(struct PStack *st, byte pr, void *arg) +{ + struct BufHeader *ibh = arg; + byte *p; + + p = DATAPTR(ibh); + if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, + WE0_cause, 0))) { + if (p[1] > 0) { + st->pa->cause = p[2]; + if (p[1] > 1) + st->pa->loc = p[3]; + else + st->pa->loc = 0; + } else { + st->pa->cause = 0; + st->pa->loc = 0; + } + } else + st->pa->cause = -1; + BufPoolRelease(ibh); + StopAllL3Timer(st); + newl3state(st, 0); + l3_1TR6_message(st, MT_N1_REL_ACK, PROTO_DIS_N1); + st->l3.l3l4(st, CC_RELEASE_IND, NULL); +} + +static void +l3_1tr6_rel_ack(struct PStack *st, byte pr, void *arg) +{ + struct BufHeader *ibh = arg; + + BufPoolRelease(ibh); + StopAllL3Timer(st); + newl3state(st, 0); + st->pa->cause = -1; + st->l3.l3l4(st, CC_RELEASE_CNF, NULL); +} + +static void +l3_1tr6_disc(struct PStack *st, byte pr, void *arg) +{ + struct BufHeader *ibh = arg; + byte *p; + int i, tmpcharge = 0; + char a_charge[8], tmp[32]; + + StopAllL3Timer(st); + p = DATAPTR(ibh); + if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, + WE6_chargingInfo, 6))) { + iecpy(a_charge, p, 1); + for (i = 0; i < strlen(a_charge); i++) { + tmpcharge *= 10; + tmpcharge += a_charge[i] & 0xf; + } + if (tmpcharge > st->pa->chargeinfo) { + st->pa->chargeinfo = tmpcharge; + st->l3.l3l4(st, CC_INFO_CHARGE, NULL); + } + if (st->l3.debug & L3_DEB_CHARGE) { + sprintf(tmp, "charging info %d", st->pa->chargeinfo); + l3_debug(st, tmp); + } + } else if (st->l3.debug & L3_DEB_CHARGE) + l3_debug(st, "charging info not found"); + + + p = DATAPTR(ibh); + if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, + WE0_cause, 0))) { + if (p[1] > 0) { + st->pa->cause = p[2]; + if (p[1] > 1) + st->pa->loc = p[3]; + else + st->pa->loc = 0; + } else { + st->pa->cause = 0; + st->pa->loc = 0; + } + } else { + if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "cause not found"); + st->pa->cause = -1; + } + BufPoolRelease(ibh); + newl3state(st, 12); + st->l3.l3l4(st, CC_DISCONNECT_IND, NULL); +} + + +static void +l3_1tr6_connect_ack(struct PStack *st, byte pr, void *arg) +{ + struct BufHeader *ibh = arg; + + BufPoolRelease(ibh); + newl3state(st, 10); + st->pa->chargeinfo = 0; + L3DelTimer(&st->l3.timer); + st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL); +} + +static void +l3_1tr6_alert_req(struct PStack *st, byte pr, + void *arg) +{ + newl3state(st, 7); + l3_1TR6_message(st, MT_N1_ALERT, PROTO_DIS_N1); +} + +static void +l3_1tr6_setup_rsp(struct PStack *st, byte pr, + void *arg) +{ + struct BufHeader *dibh; + byte *p; + + BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20); + p = DATAPTR(dibh); + p += st->l2.ihsize; + MsgHead(p, st->l3.callref, MT_N1_CONN, PROTO_DIS_N1); + if (st->pa->spv) { /* SPV ? */ + /* NSF SPV */ + *p++ = WE0_netSpecFac; + *p++ = 4; /* Laenge */ + *p++ = 0; + *p++ = FAC_SPV; /* SPV */ + *p++ = st->pa->setup.si1; + *p++ = st->pa->setup.si2; + *p++ = WE0_netSpecFac; + *p++ = 4; /* Laenge */ + *p++ = 0; + *p++ = FAC_Activate; /* aktiviere SPV */ + *p++ = st->pa->setup.si1; + *p++ = st->pa->setup.si2; + } + newl3state(st, 8); + dibh->datasize = p - DATAPTR(dibh); + st->l3.l3l2(st, DL_DATA, dibh); + L3DelTimer(&st->l3.timer); + L3AddTimer(&st->l3.timer, st->l3.t313, CC_T313); +} + +static void +l3_1tr6_reset(struct PStack *st, byte pr, void *arg) +{ + newl3state(st, 0); +} + +static void +l3_1tr6_disconnect_req(struct PStack *st, byte pr, void *arg) +{ + struct BufHeader *dibh; + byte *p; + byte cause = 0x10; + byte clen = 1; + + if (st->pa->cause > 0) + cause = st->pa->cause; + /* Map DSS1 causes */ + switch (cause & 0x7f) { + case 0x10: + clen = 0; + break; + case 0x15: + cause = CAUSE_CallRejected; + break; + } + StopAllL3Timer(st); + BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 21); + p = DATAPTR(dibh); + p += st->l2.ihsize; + MsgHead(p, st->l3.callref, MT_N1_DISC, PROTO_DIS_N1); + *p++ = WE0_cause; + *p++ = clen; /* Laenge */ + if (clen) + *p++ = cause | 0x80; + dibh->datasize = p - DATAPTR(dibh); + newl3state(st, 11); + st->l3.l3l2(st, DL_DATA, dibh); + L3AddTimer(&st->l3.timer, st->l3.t305, CC_T305); +} + +static void +l3_1tr6_release_req(struct PStack *st, byte pr, void *arg) +{ + StopAllL3Timer(st); + newl3state(st, 19); + l3_1TR6_message(st, MT_N1_REL, PROTO_DIS_N1); + L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_1); +} + +static void +l3_1tr6_t303(struct PStack *st, byte pr, void *arg) +{ + if (st->l3.n_t303 > 0) { + st->l3.n_t303--; + L3DelTimer(&st->l3.timer); + l3_1tr6_setup_req(st, pr, arg); + } else { + L3DelTimer(&st->l3.timer); + st->l3.l3l4(st, CC_NOSETUP_RSP_ERR, NULL); + st->l3.n_t303 = 1; + newl3state(st, 0); + } +} + +static void +l3_1tr6_t304(struct PStack *st, byte pr, void *arg) +{ + L3DelTimer(&st->l3.timer); + st->pa->cause = 0xE6; + l3_1tr6_disconnect_req(st, pr, NULL); + st->l3.l3l4(st, CC_SETUP_ERR, NULL); + +} + +static void +l3_1tr6_t305(struct PStack *st, byte pr, void *arg) +{ + struct BufHeader *dibh; + byte *p; + byte cause = 0x90; + byte clen = 1; + + L3DelTimer(&st->l3.timer); + if (st->pa->cause > 0) + cause = st->pa->cause; + /* Map DSS1 causes */ + switch (cause & 0x7f) { + case 0x10: + clen = 0; + break; + case 0x15: + cause = CAUSE_CallRejected; + break; + } + BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20); + p = DATAPTR(dibh); + p += st->l2.ihsize; + MsgHead(p, st->l3.callref, MT_N1_REL, PROTO_DIS_N1); + *p++ = WE0_cause; + *p++ = clen; /* Laenge */ + if (clen) + *p++ = cause; + dibh->datasize = p - DATAPTR(dibh); + newl3state(st, 19); + st->l3.l3l2(st, DL_DATA, dibh); + L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_1); +} + +static void +l3_1tr6_t310(struct PStack *st, byte pr, void *arg) +{ + L3DelTimer(&st->l3.timer); + st->pa->cause = 0xE6; + l3_1tr6_disconnect_req(st, pr, NULL); + st->l3.l3l4(st, CC_SETUP_ERR, NULL); +} + +static void +l3_1tr6_t313(struct PStack *st, byte pr, void *arg) +{ + L3DelTimer(&st->l3.timer); + st->pa->cause = 0xE6; + l3_1tr6_disconnect_req(st, pr, NULL); + st->l3.l3l4(st, CC_CONNECT_ERR, NULL); +} + +static void +l3_1tr6_t308_1(struct PStack *st, byte pr, void *arg) +{ + L3DelTimer(&st->l3.timer); + l3_1TR6_message(st, MT_N1_REL, PROTO_DIS_N1); + L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_2); + newl3state(st, 19); +} + +static void +l3_1tr6_t308_2(struct PStack *st, byte pr, void *arg) +{ + L3DelTimer(&st->l3.timer); + st->l3.l3l4(st, CC_RELEASE_ERR, NULL); + newl3state(st, 0); +} + +static struct stateentry downstl[] = +{ + {SBIT(0), + CC_SETUP_REQ, 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}, + {SBIT(12), + CC_RELEASE_REQ, l3_1tr6_release_req}, + {ALL_STATES, + CC_DLRL, l3_1tr6_reset}, + {SBIT(6), + CC_IGNORE, l3_1tr6_reset}, + {SBIT(6), + CC_REJECT_REQ, l3_1tr6_disconnect_req}, + {SBIT(6), + CC_ALERTING_REQ, l3_1tr6_alert_req}, + {SBIT(6) | SBIT(7), + CC_SETUP_RSP, l3_1tr6_setup_rsp}, + {SBIT(1), + CC_T303, l3_1tr6_t303}, + {SBIT(2), + CC_T304, l3_1tr6_t304}, + {SBIT(3), + CC_T310, l3_1tr6_t310}, + {SBIT(8), + CC_T313, l3_1tr6_t313}, + {SBIT(11), + CC_T305, l3_1tr6_t305}, + {SBIT(19), + CC_T308_1, l3_1tr6_t308_1}, + {SBIT(19), + CC_T308_2, l3_1tr6_t308_2}, +}; + +static int downstl_len = sizeof(downstl) / +sizeof(struct stateentry); + +static struct stateentry datastln1[] = +{ + {SBIT(0), + MT_N1_SETUP, l3_1tr6_setup}, + {SBIT(1), + MT_N1_SETUP_ACK, l3_1tr6_setup_ack}, + {SBIT(1) | SBIT(2), + MT_N1_CALL_SENT, l3_1tr6_call_sent}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10), + MT_N1_DISC, l3_1tr6_disc}, + {SBIT(2) | SBIT(3) | SBIT(4), + MT_N1_ALERT, l3_1tr6_alert}, + {SBIT(2) | SBIT(3) | SBIT(4), + MT_N1_CONN, l3_1tr6_connect}, + {SBIT(2), + MT_N1_INFO, l3_1tr6_info_s2}, + {SBIT(8), + MT_N1_CONN_ACK, l3_1tr6_connect_ack}, + {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), + MT_N1_REL, l3_1tr6_rel}, + {SBIT(19), + MT_N1_REL_ACK, l3_1tr6_rel_ack} +}; + + +static int datastln1_len = sizeof(datastln1) / +sizeof(struct stateentry); + +static void +up1tr6(struct PStack *st, + int pr, void *arg) +{ + int i, mt, size; + byte *ptr; + struct BufHeader *ibh = arg; + char tmp[80]; + + if (pr == DL_DATA) { + ptr = DATAPTR(ibh); + ptr += st->l2.ihsize; + size = ibh->datasize - st->l2.ihsize; + } else if (pr == DL_UNIT_DATA) { + ptr = DATAPTR(ibh); + ptr += st->l2.uihsize; + size = ibh->datasize - st->l2.uihsize; + } else { + if (st->l3.debug & L3_DEB_WARN) { + sprintf(tmp, "up1tr6 unknown data typ %d state %d", + pr, st->l3.state); + l3_debug(st, tmp); + } + BufPoolRelease(ibh); + return; + } + if ((ptr[0] & 0xfe) != PROTO_DIS_N0) { + if (st->l3.debug & L3_DEB_PROTERR) { + sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %d state %d", + (pr == DL_DATA) ? " " : "(broadcast) ", + ptr[0], size, st->l3.state); + l3_debug(st, tmp); + } + BufPoolRelease(ibh); + return; + } + mt = ptr[3]; + + if (ptr[0] == PROTO_DIS_N0) { + BufPoolRelease(ibh); + if (st->l3.debug & L3_DEB_STATE) { + sprintf(tmp, "up1tr6%s N0 state %d mt %x unhandled", + (pr == DL_DATA) ? " " : "(broadcast) ", + st->l3.state, mt); + l3_debug(st, tmp); + } + } else if (ptr[0] == PROTO_DIS_N1) { + for (i = 0; i < datastln1_len; i++) + if ((mt == datastln1[i].primitive) && + ((1 << st->l3.state) & datastln1[i].state)) + break; + if (i == datastln1_len) { + BufPoolRelease(ibh); + if (st->l3.debug & L3_DEB_STATE) { + sprintf(tmp, "up1tr6%sstate %d mt %x unhandled", + (pr == DL_DATA) ? " " : "(broadcast) ", + st->l3.state, mt); + l3_debug(st, tmp); + } + return; + } else { + if (st->l3.debug & L3_DEB_STATE) { + sprintf(tmp, "up1tr6%sstate %d mt %x", + (pr == DL_DATA) ? " " : "(broadcast) ", + st->l3.state, mt); + l3_debug(st, tmp); + } + datastln1[i].rout(st, pr, ibh); + } + } +} + +static void +down1tr6(struct PStack *st, + int pr, void *arg) +{ + int i; + struct BufHeader *ibh = arg; + char tmp[80]; + + for (i = 0; i < downstl_len; i++) + if ((pr == downstl[i].primitive) && + ((1 << st->l3.state) & downstl[i].state)) + break; + if (i == downstl_len) { + if (st->l3.debug & L3_DEB_STATE) { + sprintf(tmp, "down1tr6 state %d prim %d unhandled", + st->l3.state, pr); + l3_debug(st, tmp); + } + } else { + if (st->l3.debug & L3_DEB_STATE) { + sprintf(tmp, "down1tr6 state %d prim %d", + st->l3.state, pr); + l3_debug(st, tmp); + } + downstl[i].rout(st, pr, ibh); + } +} + +void +setstack_1tr6(struct PStack *st) +{ + char tmp[64]; + + st->l4.l4l3 = down1tr6; + st->l2.l2l3 = up1tr6; + st->l3.t303 = 4000; + st->l3.t304 = 20000; + st->l3.t305 = 4000; + st->l3.t308 = 4000; + st->l3.t310 = 120000; + st->l3.t313 = 4000; + st->l3.t318 = 4000; + st->l3.t319 = 4000; + st->l3.n_t303 = 0; + + if (st->l3.channr & 1) { + strcpy(tmp, l3_1tr6_revision); + printk(KERN_NOTICE "HiSax: 1TR6 Rev. %s\n", HiSax_getrev(tmp)); + } +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/l3_1tr6.h linux/drivers/isdn/hisax/l3_1tr6.h --- v2.1.26/linux/drivers/isdn/hisax/l3_1tr6.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/l3_1tr6.h Tue Feb 25 17:12:49 1997 @@ -0,0 +1,160 @@ +/* $Id: l3_1tr6.h,v 1.1 1996/10/13 20:03:48 keil Exp $ + * + * German 1TR6 D-channel protocol defines + * + * $Log: l3_1tr6.h,v $ + * Revision 1.1 1996/10/13 20:03:48 keil + * Initial revision + * + * + * + */ +#ifndef l3_1tr6 +#define l3_1tr6 + +#define PROTO_DIS_N0 0x40 +#define PROTO_DIS_N1 0x41 + +/* + * MsgType N0 + */ +#define MT_N0_REG_IND 0x61 +#define MT_N0_CANC_IND 0x62 +#define MT_N0_FAC_STA 0x63 +#define MT_N0_STA_ACK 0x64 +#define MT_N0_STA_REJ 0x65 +#define MT_N0_FAC_INF 0x66 +#define MT_N0_INF_ACK 0x67 +#define MT_N0_INF_REJ 0x68 +#define MT_N0_CLOSE 0x75 +#define MT_N0_CLO_ACK 0x77 + + +/* + * MsgType N1 + */ + +#define MT_N1_ESC 0x00 +#define MT_N1_ALERT 0x01 +#define MT_N1_CALL_SENT 0x02 +#define MT_N1_CONN 0x07 +#define MT_N1_CONN_ACK 0x0F +#define MT_N1_SETUP 0x05 +#define MT_N1_SETUP_ACK 0x0D +#define MT_N1_RES 0x26 +#define MT_N1_RES_ACK 0x2E +#define MT_N1_RES_REJ 0x22 +#define MT_N1_SUSP 0x25 +#define MT_N1_SUSP_ACK 0x2D +#define MT_N1_SUSP_REJ 0x21 +#define MT_N1_USER_INFO 0x20 +#define MT_N1_DET 0x40 +#define MT_N1_DISC 0x45 +#define MT_N1_REL 0x4D +#define MT_N1_REL_ACK 0x5A +#define MT_N1_CANC_ACK 0x6E +#define MT_N1_CANC_REJ 0x67 +#define MT_N1_CON_CON 0x69 +#define MT_N1_FAC 0x60 +#define MT_N1_FAC_ACK 0x68 +#define MT_N1_FAC_CAN 0x66 +#define MT_N1_FAC_REG 0x64 +#define MT_N1_FAC_REJ 0x65 +#define MT_N1_INFO 0x6D +#define MT_N1_REG_ACK 0x6C +#define MT_N1_REG_REJ 0x6F +#define MT_N1_STAT 0x63 + + + +/* + * W Elemente + */ + +#define WE_Shift_F0 0x90 +#define WE_Shift_F6 0x96 +#define WE_Shift_OF0 0x98 +#define WE_Shift_OF6 0x9E + +#define WE0_cause 0x08 +#define WE0_connAddr 0x0C +#define WE0_callID 0x10 +#define WE0_chanID 0x18 +#define WE0_netSpecFac 0x20 +#define WE0_display 0x28 +#define WE0_keypad 0x2C +#define WE0_origAddr 0x6C +#define WE0_destAddr 0x70 +#define WE0_userInfo 0x7E + +#define WE0_moreData 0xA0 +#define WE0_congestLevel 0xB0 + +#define WE6_serviceInd 0x01 +#define WE6_chargingInfo 0x02 +#define WE6_date 0x03 +#define WE6_facSelect 0x05 +#define WE6_facStatus 0x06 +#define WE6_statusCalled 0x07 +#define WE6_addTransAttr 0x08 + +/* + * FacCodes + */ +#define FAC_Sperre 0x01 +#define FAC_Sperre_All 0x02 +#define FAC_Sperre_Fern 0x03 +#define FAC_Sperre_Intl 0x04 +#define FAC_Sperre_Interk 0x05 + +#define FAC_Forward1 0x02 +#define FAC_Forward2 0x03 +#define FAC_Konferenz 0x06 +#define FAC_GrabBchan 0x0F +#define FAC_Reactivate 0x10 +#define FAC_Konferenz3 0x11 +#define FAC_Dienstwechsel1 0x12 +#define FAC_Dienstwechsel2 0x13 +#define FAC_NummernIdent 0x14 +#define FAC_GBG 0x15 +#define FAC_DisplayUebergeben 0x17 +#define FAC_DisplayUmgeleitet 0x1A +#define FAC_Unterdruecke 0x1B +#define FAC_Deactivate 0x1E +#define FAC_Activate 0x1D +#define FAC_SPV 0x1F +#define FAC_Rueckwechsel 0x23 +#define FAC_Umleitung 0x24 + +/* + * Cause codes + */ +#define CAUSE_InvCRef 0x01 +#define CAUSE_BearerNotImpl 0x03 +#define CAUSE_CIDunknown 0x07 +#define CAUSE_CIDinUse 0x08 +#define CAUSE_NoChans 0x0A +#define CAUSE_FacNotImpl 0x10 +#define CAUSE_FacNotSubscr 0x11 +#define CAUSE_OutgoingBarred 0x20 +#define CAUSE_UserAccessBusy 0x21 +#define CAUSE_NegativeGBG 0x22 +#define CAUSE_UnknownGBG 0x23 +#define CAUSE_NoSPVknown 0x25 +#define CAUSE_DestNotObtain 0x35 +#define CAUSE_NumberChanged 0x38 +#define CAUSE_OutOfOrder 0x39 +#define CAUSE_NoUserResponse 0x3A +#define CAUSE_UserBusy 0x3B +#define CAUSE_IncomingBarred 0x3D +#define CAUSE_CallRejected 0x3E +#define CAUSE_NetworkCongestion 0x59 +#define CAUSE_RemoteUser 0x5A +#define CAUSE_LocalProcErr 0x70 +#define CAUSE_RemoteProcErr 0x71 +#define CAUSE_RemoteUserSuspend 0x72 +#define CAUSE_RemoteUserResumed 0x73 +#define CAUSE_UserInfoDiscarded 0x7F + + +#endif diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/l3dss1.c linux/drivers/isdn/hisax/l3dss1.c --- v2.1.26/linux/drivers/isdn/hisax/l3dss1.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/l3dss1.c Tue Feb 25 17:12:49 1997 @@ -0,0 +1,771 @@ +/* $Id: l3dss1.c,v 1.12 1997/02/17 00:34:26 keil Exp $ + + * EURO/DSS1 D-channel protocol + * + * Author Karsten Keil (keil@temic-ech.spacenet.de) + * based on the teles driver from Jan den Ouden + * + * Thanks to Jan den Ouden + * Fritz Elfert + * + * $Log: l3dss1.c,v $ + * Revision 1.12 1997/02/17 00:34:26 keil + * Bugfix: Wrong cause delivered + * + * Revision 1.11 1997/02/16 12:12:47 fritz + * Bugfix: SI2 was nont initialized on incoming calls. + * + * Revision 1.10 1997/02/11 01:37:24 keil + * Changed setup-interface (incoming and outgoing) + * + * Revision 1.9 1997/01/27 23:20:52 keil + * report revision only ones + * + * Revision 1.8 1997/01/21 22:29:41 keil + * new statemachine; L3 timers + * + * Revision 1.7 1996/12/14 21:06:59 keil + * additional states for CC_REJECT + * + * Revision 1.6 1996/12/08 22:59:16 keil + * fixed calling party number without octet 3a + * + * Revision 1.5 1996/12/08 19:53:31 keil + * fixes from Pekka Sarnila + * + * Revision 1.4 1996/11/05 19:44:36 keil + * some fixes from Henner Eisen + * + * Revision 1.3 1996/10/30 10:18:01 keil + * bugfixes in debugging output + * + * Revision 1.2 1996/10/27 22:15:16 keil + * bugfix reject handling + * + * Revision 1.1 1996/10/13 20:04:55 keil + * Initial revision + * + * + * + */ + +#define __NO_VERSION__ +#include "hisax.h" +#include "isdnl3.h" + +extern char *HiSax_getrev(const char *revision); +const char *dss1_revision = "$Revision: 1.12 $"; + +#define MsgHead(ptr, cref, mty) \ + *ptr++ = 0x8; \ + *ptr++ = 0x1; \ + *ptr++ = cref; \ + *ptr++ = mty + +static void +l3dss1_message(struct PStack *st, byte mt) +{ + struct BufHeader *dibh; + byte *p; + + BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18); + p = DATAPTR(dibh); + p += st->l2.ihsize; + + MsgHead(p, st->l3.callref, mt); + + dibh->datasize = p - DATAPTR(dibh); + st->l3.l3l2(st, DL_DATA, dibh); +} + +static void +l3dss1_release_req(struct PStack *st, byte pr, void *arg) +{ + StopAllL3Timer(st); + newl3state(st, 19); + l3dss1_message(st, MT_RELEASE); + L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_1); +} + +static void +l3dss1_release_cmpl(struct PStack *st, byte pr, void *arg) +{ + byte *p; + struct BufHeader *ibh = arg; + int cause = -1; + + p = DATAPTR(ibh); + if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, + IE_CAUSE, 0))) { + p++; + if (*p++ == 2) + st->pa->loc = *p++; + cause = *p & 0x7f; + } + BufPoolRelease(ibh); + StopAllL3Timer(st); + st->pa->cause = cause; + newl3state(st, 0); + st->l3.l3l4(st, CC_RELEASE_CNF, NULL); +} + +static void +l3dss1_setup_req(struct PStack *st, byte pr, + void *arg) +{ + struct BufHeader *dibh; + byte *p; + char *teln; + + st->l3.callref = st->pa->callref; + BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19); + p = DATAPTR(dibh); + p += st->l2.ihsize; + + MsgHead(p, st->l3.callref, MT_SETUP); + + /* + * Set Bearer Capability, Map info from 1TR6-convention to EDSS1 + */ + *p++ = 0xa1; + switch (st->pa->setup.si1) { + case 1: /* Telephony */ + *p++ = 0x4; /* BC-IE-code */ + *p++ = 0x3; /* Length */ + *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + *p++ = 0xa3; /* A-Law Audio */ + break; + case 5: /* Datatransmission 64k, BTX */ + case 7: /* Datatransmission 64k */ + default: + *p++ = 0x4; /* BC-IE-code */ + *p++ = 0x2; /* Length */ + *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + break; + } + /* + * What about info2? Mapping to High-Layer-Compatibility? + */ + if (st->pa->setup.eazmsn[0]) { + *p++ = 0x6c; + *p++ = strlen(st->pa->setup.eazmsn) + 1; + /* Classify as AnyPref. */ + *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ + teln = st->pa->setup.eazmsn; + while (*teln) + *p++ = *teln++ & 0x7f; + } + *p++ = 0x70; + *p++ = strlen(st->pa->setup.phone) + 1; + /* Classify as AnyPref. */ + *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ + + teln = st->pa->setup.phone; + while (*teln) + *p++ = *teln++ & 0x7f; + + + dibh->datasize = p - DATAPTR(dibh); + L3DelTimer(&st->l3.timer); + L3AddTimer(&st->l3.timer, st->l3.t303, CC_T303); + newl3state(st, 1); + st->l3.l3l2(st, DL_DATA, dibh); + +} + +static void +l3dss1_call_proc(struct PStack *st, byte pr, void *arg) +{ + byte *p; + struct BufHeader *ibh = arg; + + L3DelTimer(&st->l3.timer); + p = DATAPTR(ibh); + if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, + 0x18, 0))) { + st->pa->bchannel = p[2] & 0x3; + if ((!st->pa->bchannel) && (st->l3.debug & L3_DEB_WARN)) + l3_debug(st, "setup answer without bchannel"); + } else if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "setup answer without bchannel"); + BufPoolRelease(ibh); + newl3state(st, 3); + L3AddTimer(&st->l3.timer, st->l3.t310, CC_T310); + st->l3.l3l4(st, CC_PROCEEDING_IND, NULL); +} + +static void +l3dss1_setup_ack(struct PStack *st, byte pr, void *arg) +{ + byte *p; + struct BufHeader *ibh = arg; + + L3DelTimer(&st->l3.timer); + p = DATAPTR(ibh); + if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, + 0x18, 0))) { + st->pa->bchannel = p[2] & 0x3; + if ((!st->pa->bchannel) && (st->l3.debug & L3_DEB_WARN)) + l3_debug(st, "setup answer without bchannel"); + } else if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "setup answer without bchannel"); + + BufPoolRelease(ibh); + newl3state(st, 2); + L3AddTimer(&st->l3.timer, st->l3.t304, CC_T304); + st->l3.l3l4(st, CC_MORE_INFO, NULL); +} + +static void +l3dss1_disconnect(struct PStack *st, byte pr, void *arg) +{ + byte *p; + struct BufHeader *ibh = arg; + int cause = -1; + + StopAllL3Timer(st); + p = DATAPTR(ibh); + if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, + IE_CAUSE, 0))) { + p++; + if (*p++ == 2) + st->pa->loc = *p++; + cause = *p & 0x7f; + } + BufPoolRelease(ibh); + newl3state(st, 12); + st->pa->cause = cause; + st->l3.l3l4(st, CC_DISCONNECT_IND, NULL); +} + + +static void +l3dss1_connect(struct PStack *st, byte pr, void *arg) +{ + struct BufHeader *ibh = arg; + + + BufPoolRelease(ibh); + L3DelTimer(&st->l3.timer); /* T310 */ + newl3state(st, 10); + st->l3.l3l4(st, CC_SETUP_CNF, NULL); +} + +static void +l3dss1_alerting(struct PStack *st, byte pr, void *arg) +{ + struct BufHeader *ibh = arg; + + BufPoolRelease(ibh); + L3DelTimer(&st->l3.timer); /* T304 */ + newl3state(st, 4); + st->l3.l3l4(st, CC_ALERTING_IND, NULL); +} + +static void +l3dss1_setup(struct PStack *st, byte pr, void *arg) +{ + byte *p; + int bcfound = 0; + char tmp[80]; + struct BufHeader *ibh = arg; + + p = DATAPTR(ibh); + p += st->l2.uihsize; + st->pa->callref = getcallref(p); + st->l3.callref = 0x80 + st->pa->callref; + + /* + * Channel Identification + */ + p = DATAPTR(ibh); + if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, + 0x18, 0))) { + st->pa->bchannel = p[2] & 0x3; + if (st->pa->bchannel) + bcfound++; + else if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "setup without bchannel"); + } else if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "setup without bchannel"); + + p = DATAPTR(ibh); + /* + * Bearer Capabilities + */ + if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x04, 0))) { + st->pa->setup.si2 = 0; + switch (p[2] & 0x1f) { + case 0x00: + /* Speech */ + case 0x10: + /* 3.1 Khz audio */ + st->pa->setup.si1 = 1; + break; + case 0x08: + /* Unrestricted digital information */ + st->pa->setup.si1 = 7; + break; + case 0x09: + /* Restricted digital information */ + st->pa->setup.si1 = 2; + break; + case 0x11: + /* Unrestr. digital information with tones/announcements */ + st->pa->setup.si1 = 3; + break; + case 0x18: + /* Video */ + st->pa->setup.si1 = 4; + break; + default: + st->pa->setup.si1 = 0; + } + } else if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "setup without bearer capabilities"); + + p = DATAPTR(ibh); + if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, + 0x70, 0))) + iecpy(st->pa->setup.eazmsn, p, 1); + else + st->pa->setup.eazmsn[0] = 0; + + p = DATAPTR(ibh); + if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, + 0x6c, 0))) { + st->pa->setup.plan = p[2]; + if (p[2] & 0x80) { + iecpy(st->pa->setup.phone, p, 1); + st->pa->setup.screen = 0; + } else { + iecpy(st->pa->setup.phone, p, 2); + st->pa->setup.screen = p[3]; + } + } else { + st->pa->setup.phone[0] = 0; + st->pa->setup.plan = 0; + st->pa->setup.screen = 0; + } + BufPoolRelease(ibh); + + if (bcfound) { + if ((st->pa->setup.si1 != 7) && (st->l3.debug & L3_DEB_WARN)) { + sprintf(tmp, "non-digital call: %s -> %s", + st->pa->setup.phone, + st->pa->setup.eazmsn); + l3_debug(st, tmp); + } + newl3state(st, 6); + st->l3.l3l4(st, CC_SETUP_IND, NULL); + } +} + +static void +l3dss1_reset(struct PStack *st, byte pr, void *arg) +{ + StopAllL3Timer(st); + newl3state(st, 0); +} + +static void +l3dss1_setup_rsp(struct PStack *st, byte pr, + void *arg) +{ + newl3state(st, 8); + l3dss1_message(st, MT_CONNECT); + L3DelTimer(&st->l3.timer); + L3AddTimer(&st->l3.timer, st->l3.t313, CC_T313); +} + +static void +l3dss1_connect_ack(struct PStack *st, byte pr, void *arg) +{ + struct BufHeader *ibh = arg; + + BufPoolRelease(ibh); + newl3state(st, 10); + L3DelTimer(&st->l3.timer); + st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL); +} + +static void +l3dss1_disconnect_req(struct PStack *st, byte pr, void *arg) +{ + struct BufHeader *dibh; + byte *p; + byte cause = 0x10; + + if (st->pa->cause > 0) + cause = st->pa->cause; + + StopAllL3Timer(st); + BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20); + p = DATAPTR(dibh); + p += st->l2.ihsize; + + MsgHead(p, st->l3.callref, MT_DISCONNECT); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause | 0x80; + + dibh->datasize = p - DATAPTR(dibh); + newl3state(st, 11); + st->l3.l3l2(st, DL_DATA, dibh); + L3AddTimer(&st->l3.timer, st->l3.t305, CC_T305); +} + +static void +l3dss1_reject_req(struct PStack *st, byte pr, void *arg) +{ + struct BufHeader *dibh; + byte *p; + byte cause = 0x95; + + if (st->pa->cause > 0) + cause = st->pa->cause; + + BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20); + p = DATAPTR(dibh); + p += st->l2.ihsize; + + MsgHead(p, st->l3.callref, MT_RELEASE_COMPLETE); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause; + + dibh->datasize = p - DATAPTR(dibh); + newl3state(st, 0); + st->l3.l3l2(st, DL_DATA, dibh); + st->l3.l3l4(st, CC_RELEASE_IND, NULL); +} + +static void +l3dss1_release(struct PStack *st, byte pr, void *arg) +{ + byte *p; + struct BufHeader *ibh = arg; + int cause = -1; + + p = DATAPTR(ibh); + if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, + IE_CAUSE, 0))) { + p++; + if (*p++ == 2) + st->pa->loc = *p++; + cause = *p & 0x7f; + } + BufPoolRelease(ibh); + StopAllL3Timer(st); + st->pa->cause = cause; + newl3state(st, 0); + l3dss1_message(st, MT_RELEASE_COMPLETE); + st->l3.l3l4(st, CC_RELEASE_IND, NULL); +} + +static void +l3dss1_alert_req(struct PStack *st, byte pr, + void *arg) +{ + newl3state(st, 7); + l3dss1_message(st, MT_ALERTING); +} + +static void +l3dss1_status_enq(struct PStack *st, byte pr, void *arg) +{ + struct BufHeader *dibh = arg; + byte *p; + + BufPoolRelease(dibh); + + BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 22); + p = DATAPTR(dibh); + p += st->l2.ihsize; + + MsgHead(p, st->l3.callref, MT_STATUS); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = 0x9E; /* answer status enquire */ + + *p++ = 0x14; /* CallState */ + *p++ = 0x1; + *p++ = st->l3.state & 0x3f; + + dibh->datasize = p - DATAPTR(dibh); + st->l3.l3l2(st, DL_DATA, dibh); +} + +static void +l3dss1_t303(struct PStack *st, byte pr, void *arg) +{ + if (st->l3.n_t303 > 0) { + st->l3.n_t303--; + L3DelTimer(&st->l3.timer); + l3dss1_setup_req(st, pr, arg); + } else { + newl3state(st, 0); + L3DelTimer(&st->l3.timer); + st->l3.l3l4(st, CC_NOSETUP_RSP_ERR, NULL); + st->l3.n_t303 = 1; + } +} + +static void +l3dss1_t304(struct PStack *st, byte pr, void *arg) +{ + L3DelTimer(&st->l3.timer); + st->pa->cause = 0xE6; + l3dss1_disconnect_req(st, pr, NULL); + st->l3.l3l4(st, CC_SETUP_ERR, NULL); + +} + +static void +l3dss1_t305(struct PStack *st, byte pr, void *arg) +{ + struct BufHeader *dibh; + byte *p; + byte cause = 0x90; + + L3DelTimer(&st->l3.timer); + if (st->pa->cause > 0) + cause = st->pa->cause; + + BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20); + p = DATAPTR(dibh); + p += st->l2.ihsize; + + MsgHead(p, st->l3.callref, MT_RELEASE); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause; + + dibh->datasize = p - DATAPTR(dibh); + newl3state(st, 19); + st->l3.l3l2(st, DL_DATA, dibh); + L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_1); +} + +static void +l3dss1_t310(struct PStack *st, byte pr, void *arg) +{ + L3DelTimer(&st->l3.timer); + st->pa->cause = 0xE6; + l3dss1_disconnect_req(st, pr, NULL); + st->l3.l3l4(st, CC_SETUP_ERR, NULL); +} + +static void +l3dss1_t313(struct PStack *st, byte pr, void *arg) +{ + L3DelTimer(&st->l3.timer); + st->pa->cause = 0xE6; + l3dss1_disconnect_req(st, pr, NULL); + st->l3.l3l4(st, CC_CONNECT_ERR, NULL); +} + +static void +l3dss1_t308_1(struct PStack *st, byte pr, void *arg) +{ + newl3state(st, 19); + L3DelTimer(&st->l3.timer); + l3dss1_message(st, MT_RELEASE); + L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_2); +} + +static void +l3dss1_t308_2(struct PStack *st, byte pr, void *arg) +{ + newl3state(st, 0); + L3DelTimer(&st->l3.timer); + st->l3.l3l4(st, CC_RELEASE_ERR, NULL); +} + +static struct stateentry downstatelist[] = +{ + {SBIT(0), + CC_SETUP_REQ, l3dss1_setup_req}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(10), + CC_DISCONNECT_REQ, l3dss1_disconnect_req}, + {SBIT(12), + CC_RELEASE_REQ, l3dss1_release_req}, + {ALL_STATES, + CC_DLRL, l3dss1_reset}, + {SBIT(6), + CC_IGNORE, l3dss1_reset}, + {SBIT(6), + CC_REJECT_REQ, l3dss1_reject_req}, + {SBIT(6), + CC_ALERTING_REQ, l3dss1_alert_req}, + {SBIT(6) | SBIT(7), + CC_SETUP_RSP, l3dss1_setup_rsp}, + {SBIT(1), + CC_T303, l3dss1_t303}, + {SBIT(2), + CC_T304, l3dss1_t304}, + {SBIT(3), + CC_T310, l3dss1_t310}, + {SBIT(8), + CC_T313, l3dss1_t313}, + {SBIT(11), + CC_T305, l3dss1_t305}, + {SBIT(19), + CC_T308_1, l3dss1_t308_1}, + {SBIT(19), + CC_T308_2, l3dss1_t308_2}, +}; + +static int downsllen = sizeof(downstatelist) / +sizeof(struct stateentry); + +static struct stateentry datastatelist[] = +{ + {ALL_STATES, + MT_STATUS_ENQUIRY, l3dss1_status_enq}, + {SBIT(0) | SBIT(6), + MT_SETUP, l3dss1_setup}, + {SBIT(1) | SBIT(2), + MT_CALL_PROCEEDING, l3dss1_call_proc}, + {SBIT(1), + MT_SETUP_ACKNOWLEDGE, l3dss1_setup_ack}, + {SBIT(1) | SBIT(2) | SBIT(3), + MT_ALERTING, l3dss1_alerting}, + {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), + MT_RELEASE_COMPLETE, l3dss1_release_cmpl}, + {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), + MT_RELEASE, l3dss1_release}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10), + MT_DISCONNECT, l3dss1_disconnect}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4), + MT_CONNECT, l3dss1_connect}, + {SBIT(8), + MT_CONNECT_ACKNOWLEDGE, l3dss1_connect_ack}, +}; + +static int datasllen = sizeof(datastatelist) / +sizeof(struct stateentry); + +static void +dss1up(struct PStack *st, + int pr, void *arg) +{ + int i, mt, size; + byte *ptr; + struct BufHeader *ibh = arg; + char tmp[80]; + + if (pr == DL_DATA) { + ptr = DATAPTR(ibh); + ptr += st->l2.ihsize; + size = ibh->datasize - st->l2.ihsize; + } else if (pr == DL_UNIT_DATA) { + ptr = DATAPTR(ibh); + ptr += st->l2.uihsize; + size = ibh->datasize - st->l2.uihsize; + } else { + if (st->l3.debug & L3_DEB_WARN) { + sprintf(tmp, "dss1up unknown data typ %d state %d", + pr, st->l3.state); + l3_debug(st, tmp); + } + BufPoolRelease(ibh); + return; + } + if (ptr[0] != PROTO_DIS_EURO) { + if (st->l3.debug & L3_DEB_PROTERR) { + sprintf(tmp, "dss1up%sunexpected discriminator %x message len %d state %d", + (pr == DL_DATA) ? " " : "(broadcast) ", + ptr[0], size, st->l3.state); + l3_debug(st, tmp); + } + BufPoolRelease(ibh); + return; + } + mt = ptr[3]; + for (i = 0; i < datasllen; i++) + if ((mt == datastatelist[i].primitive) && + ((1 << st->l3.state) & datastatelist[i].state)) + break; + if (i == datasllen) { + BufPoolRelease(ibh); + if (st->l3.debug & L3_DEB_STATE) { + sprintf(tmp, "dss1up%sstate %d mt %x unhandled", + (pr == DL_DATA) ? " " : "(broadcast) ", + st->l3.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) ", + st->l3.state, mt); + l3_debug(st, tmp); + } + datastatelist[i].rout(st, pr, ibh); + } +} + +static void +dss1down(struct PStack *st, + int pr, void *arg) +{ + int i; + struct BufHeader *ibh = arg; + char tmp[80]; + + for (i = 0; i < downsllen; i++) + if ((pr == downstatelist[i].primitive) && + ((1 << st->l3.state) & downstatelist[i].state)) + break; + if (i == downsllen) { + if (st->l3.debug & L3_DEB_STATE) { + sprintf(tmp, "dss1down state %d prim %d unhandled", + st->l3.state, pr); + l3_debug(st, tmp); + } + } else { + if (st->l3.debug & L3_DEB_STATE) { + sprintf(tmp, "dss1down state %d prim %d", + st->l3.state, pr); + l3_debug(st, tmp); + } + downstatelist[i].rout(st, pr, ibh); + } +} + +void +setstack_dss1(struct PStack *st) +{ + char tmp[64]; + + st->l4.l4l3 = dss1down; + st->l2.l2l3 = dss1up; + st->l3.t303 = 4000; + st->l3.t304 = 30000; + st->l3.t305 = 30000; + st->l3.t308 = 4000; + st->l3.t310 = 30000; + st->l3.t313 = 4000; + st->l3.t318 = 4000; + st->l3.t319 = 4000; + st->l3.n_t303 = 1; + + if (st->l3.channr & 1) { + strcpy(tmp, dss1_revision); + printk(KERN_NOTICE "HiSax: DSS1 Rev. %s\n", HiSax_getrev(tmp)); + } +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/q931.c linux/drivers/isdn/hisax/q931.c --- v2.1.26/linux/drivers/isdn/hisax/q931.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/q931.c Tue Feb 25 17:12:49 1997 @@ -0,0 +1,1215 @@ +/* $Id: q931.c,v 1.4 1997/02/09 00:29:11 keil Exp $ + + * q931.c code to decode ITU Q.931 call control messages + * + * Author Jan den Ouden + * + * Changelog + * + * Pauline Middelink general improvements + * + * Beat Doebeli cause texts, display information element + * + * Karsten Keil cause texts, display information element for 1TR6 + * + * + * $Log: q931.c,v $ + * Revision 1.4 1997/02/09 00:29:11 keil + * new interface handling, one interface per card + * + * Revision 1.3 1997/01/21 22:24:59 keil + * cleanups + * + * Revision 1.2 1996/10/27 22:12:45 keil + * reporting unknown level 3 protocol ids + * + * Revision 1.1 1996/10/13 20:04:56 keil + * Initial revision + * + * + */ + + +#define __NO_VERSION__ +#include "hisax.h" +#include "l3_1tr6.h" + +byte * +findie(byte * p, int size, byte ie, int wanted_set) +{ + int l, codeset, maincodeset; + byte *pend = p + size; + + /* skip protocol discriminator, callref and message type */ + p++; + l = (*p++) & 0xf; + p += l; + p++; + codeset = 0; + maincodeset = 0; + /* while there are bytes left... */ + while (p < pend) { + if ((*p & 0xf0) == 0x90) { + codeset = *p & 0x07; + if (!(*p & 0x08)) + maincodeset = codeset; + } + if (*p & 0x80) + p++; + else { + if (codeset == wanted_set) { + if (*p == ie) + return (p); + if (*p > ie) + return (NULL); + } + p++; + l = *p++; + p += l; + codeset = maincodeset; + } + } + return (NULL); +} + +void +iecpy(byte * dest, byte * iestart, int ieoffset) +{ + byte *p; + int l; + + p = iestart + ieoffset + 2; + l = iestart[1] - ieoffset; + while (l--) + *dest++ = *p++; + *dest++ = '\0'; +} + +int +getcallref(byte * p) +{ + p++; /* prot discr */ + p++; /* callref length */ + return (*p); /* assuming one-byte callref */ +} + +/* + * According to Table 4-2/Q.931 + */ +static +struct MessageType { + byte nr; + char *descr; +} mtlist[] = { + + { + 0x1, "ALERTING" + }, + { + 0x2, "CALL PROCEEDING" + }, + { + 0x7, "CONNECT" + }, + { + 0xf, "CONNECT ACKNOWLEDGE" + }, + { + 0x3, "PROGRESS" + }, + { + 0x5, "SETUP" + }, + { + 0xd, "SETUP ACKNOWLEDGE" + }, + { + 0x26, "RESUME" + }, + { + 0x2e, "RESUME ACKNOWLEDGE" + }, + { + 0x22, "RESUME REJECT" + }, + { + 0x25, "SUSPEND" + }, + { + 0x2d, "SUSPEND ACKNOWLEDGE" + }, + { + 0x21, "SUSPEND REJECT" + }, + { + 0x20, "USER INFORMATION" + }, + { + 0x45, "DISCONNECT" + }, + { + 0x4d, "RELEASE" + }, + { + 0x5a, "RELEASE COMPLETE" + }, + { + 0x46, "RESTART" + }, + { + 0x4e, "RESTART ACKNOWLEDGE" + }, + { + 0x60, "SEGMENT" + }, + { + 0x79, "CONGESTION CONTROL" + }, + { + 0x7b, "INFORMATION" + }, + { + 0x62, "FACILITY" + }, + { + 0x6e, "NOTIFY" + }, + { + 0x7d, "STATUS" + }, + { + 0x75, "STATUS ENQUIRY" + } +}; + +#define MTSIZE sizeof(mtlist)/sizeof(struct MessageType) + +static +struct MessageType mt_n0[] = +{ + {MT_N0_REG_IND, "REGister INDication"}, + {MT_N0_CANC_IND, "CANCel INDication"}, + {MT_N0_FAC_STA, "FACility STAtus"}, + {MT_N0_STA_ACK, "STAtus ACKnowledge"}, + {MT_N0_STA_REJ, "STAtus REJect"}, + {MT_N0_FAC_INF, "FACility INFormation"}, + {MT_N0_INF_ACK, "INFormation ACKnowledge"}, + {MT_N0_INF_REJ, "INFormation REJect"}, + {MT_N0_CLOSE, "CLOSE"}, + {MT_N0_CLO_ACK, "CLOse ACKnowledge"} +}; + +int mt_n0_len = (sizeof(mt_n0) / sizeof(struct MessageType)); + +static +struct MessageType mt_n1[] = +{ + {MT_N1_ESC, "ESCape"}, + {MT_N1_ALERT, "ALERT"}, + {MT_N1_CALL_SENT, "CALL SENT"}, + {MT_N1_CONN, "CONNect"}, + {MT_N1_CONN_ACK, "CONNect ACKnowledge"}, + {MT_N1_SETUP, "SETUP"}, + {MT_N1_SETUP_ACK, "SETUP ACKnowledge"}, + {MT_N1_RES, "RESume"}, + {MT_N1_RES_ACK, "RESume ACKnowledge"}, + {MT_N1_RES_REJ, "RESume REJect"}, + {MT_N1_SUSP, "SUSPend"}, + {MT_N1_SUSP_ACK, "SUSPend ACKnowledge"}, + {MT_N1_SUSP_REJ, "SUSPend REJect"}, + {MT_N1_USER_INFO, "USER INFO"}, + {MT_N1_DET, "DETach"}, + {MT_N1_DISC, "DISConnect"}, + {MT_N1_REL, "RELease"}, + {MT_N1_REL_ACK, "RELease ACKnowledge"}, + {MT_N1_CANC_ACK, "CANCel ACKnowledge"}, + {MT_N1_CANC_REJ, "CANCel REJect"}, + {MT_N1_CON_CON, "CONgestion CONtrol"}, + {MT_N1_FAC, "FACility"}, + {MT_N1_FAC_ACK, "FACility ACKnowledge"}, + {MT_N1_FAC_CAN, "FACility CANcel"}, + {MT_N1_FAC_REG, "FACility REGister"}, + {MT_N1_FAC_REJ, "FACility REJect"}, + {MT_N1_INFO, "INFOrmation"}, + {MT_N1_REG_ACK, "REGister ACKnowledge"}, + {MT_N1_REG_REJ, "REGister REJect"}, + {MT_N1_STAT, "STATus"} +}; + +int mt_n1_len = (sizeof(mt_n1) / sizeof(struct MessageType)); + +static struct MessageType fac_1tr6[] = +{ + {FAC_Sperre, "Sperre"}, + {FAC_Forward1, "Forward 1"}, + {FAC_Forward2, "Forward 2"}, + {FAC_Konferenz, "Konferenz"}, + {FAC_GrabBchan, "Grab Bchannel"}, + {FAC_Reactivate, "Reactivate"}, + {FAC_Konferenz3, "Dreier Konferenz"}, + {FAC_Dienstwechsel1, "Einseitiger Dienstwechsel"}, + {FAC_Dienstwechsel2, "Zweiseitiger Dienstwechsel"}, + {FAC_NummernIdent, "Rufnummer-Identifizierung"}, + {FAC_GBG, "GBG"}, + {FAC_DisplayUebergeben, "Display Uebergeben"}, + {FAC_DisplayUmgeleitet, "Display Umgeleitet"}, + {FAC_Unterdruecke, "Unterdruecke Rufnummer"}, + {FAC_Deactivate, "Deactivate"}, + {FAC_Activate, "Activate"}, + {FAC_SPV, "SPV"}, + {FAC_Rueckwechsel, "Rueckwechsel"}, + {FAC_Umleitung, "Umleitung"} +}; +int fac_1tr6_len = (sizeof(fac_1tr6) / sizeof(struct MessageType)); + + + +static int +prbits(char *dest, byte b, int start, int len) +{ + char *dp = dest; + + b = b << (8 - start); + while (len--) { + if (b & 0x80) + *dp++ = '1'; + else + *dp++ = '0'; + b = b << 1; + } + return (dp - dest); +} + +static +byte * +skipext(byte * p) +{ + while (!(*p++ & 0x80)); + return (p); +} + +/* + * Cause Values According to Q.850 + * edescr: English description + * ddescr: German description used by Swissnet II (Swiss Telecom + * not yet written... + */ + +static +struct CauseValue { + byte nr; + char *edescr; + char *ddescr; +} cvlist[] = { + + { + 0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt" + }, + { + 0x02, "No route to specified transit network", "" + }, + { + 0x03, "No route to destination", "" + }, + { + 0x04, "Send special information tone", "" + }, + { + 0x05, "Misdialled trunk prefix", "" + }, + { + 0x06, "Channel unacceptable", "Kanal nicht akzeptierbar" + }, + { + 0x07, "Channel awarded and being delivered in an established channel", "" + }, + { + 0x08, "Preemption", "" + }, + { + 0x09, "Preemption - circuit reserved for reuse", "" + }, + { + 0x10, "Normal call clearing", "Normale Ausloesung" + }, + { + 0x11, "User busy", "TNB besetzt" + }, + { + 0x12, "No user responding", "" + }, + { + 0x13, "No answer from user (user alerted)", "" + }, + { + 0x14, "Subscriber absent", "" + }, + { + 0x15, "Call rejected", "" + }, + { + 0x16, "Number changed", "" + }, + { + 0x1a, "non-selected user clearing", "" + }, + { + 0x1b, "Destination out of order", "" + }, + { + 0x1c, "Invalid number format (address incomplete)", "" + }, + { + 0x1d, "Facility rejected", "" + }, + { + 0x1e, "Response to Status enquiry", "" + }, + { + 0x1f, "Normal, unspecified", "" + }, + { + 0x22, "No circuit/channel available", "" + }, + { + 0x26, "Network out of order", "" + }, + { + 0x27, "Permanent frame mode connection out-of-service", "" + }, + { + 0x28, "Permanent frame mode connection operational", "" + }, + { + 0x29, "Temporary failure", "" + }, + { + 0x2a, "Switching equipment congestion", "" + }, + { + 0x2b, "Access information discarded", "" + }, + { + 0x2c, "Requested circuit/channel not available", "" + }, + { + 0x2e, "Precedence call blocked", "" + }, + { + 0x2f, "Resource unavailable, unspecified", "" + }, + { + 0x31, "Quality of service unavailable", "" + }, + { + 0x32, "Requested facility not subscribed", "" + }, + { + 0x35, "Outgoing calls barred within CUG", "" + }, + { + 0x37, "Incoming calls barred within CUG", "" + }, + { + 0x39, "Bearer capability not authorized", "" + }, + { + 0x3a, "Bearer capability not presently available", "" + }, + { + 0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " " + }, + { + 0x3f, "Service or option not available, unspecified", "" + }, + { + 0x41, "Bearer capability not implemented", "" + }, + { + 0x42, "Channel type not implemented", "" + }, + { + 0x43, "Requested facility not implemented", "" + }, + { + 0x44, "Only restricted digital information bearer capability is available", "" + }, + { + 0x4f, "Service or option not implemented", "" + }, + { + 0x51, "Invalid call reference value", "" + }, + { + 0x52, "Identified channel does not exist", "" + }, + { + 0x53, "A suspended call exists, but this call identity does not", "" + }, + { + 0x54, "Call identity in use", "" + }, + { + 0x55, "No call suspended", "" + }, + { + 0x56, "Call having the requested call identity has been cleared", "" + }, + { + 0x57, "User not member of CUG", "" + }, + { + 0x58, "Incompatible destination", "" + }, + { + 0x5a, "Non-existent CUG", "" + }, + { + 0x5b, "Invalid transit network selection", "" + }, + { + 0x5f, "Invalid message, unspecified", "" + }, + { + 0x60, "Mandatory information element is missing", "" + }, + { + 0x61, "Message type non-existent or not implemented", "" + }, + { + 0x62, "Message not compatible with call state or message type non-existent or not implemented ", " " + }, + { + 0x63, "Information element/parameter non-existent or not implemented", "" + }, + { + 0x64, "Invalid information element contents", "" + }, + { + 0x65, "Message not compatible with call state", "" + }, + { + 0x66, "Recovery on timer expiry", "" + }, + { + 0x67, "Parameter non-existent or not implemented - passed on", "" + }, + { + 0x6e, "Message with unrecognized parameter discarded", "" + }, + { + 0x6f, "Protocol error, unspecified", "" + }, + { + 0x7f, "Interworking, unspecified", "" + }, +}; + +#define CVSIZE sizeof(cvlist)/sizeof(struct CauseValue) + +static +int +prcause(char *dest, byte * p) +{ + byte *end; + char *dp = dest; + int i, cause; + + end = p + p[1] + 1; + p += 2; + dp += sprintf(dp, " coding "); + dp += prbits(dp, *p, 7, 2); + dp += sprintf(dp, " location "); + dp += prbits(dp, *p, 4, 4); + *dp++ = '\n'; + p = skipext(p); + + cause = 0x7f & *p++; + + /* locate cause value */ + for (i = 0; i < CVSIZE; i++) + if (cvlist[i].nr == cause) + break; + + /* display cause value if it exists */ + if (i == CVSIZE) + dp += sprintf(dp, "Unknown cause type %x!\n", cause); + else + dp += sprintf(dp, " cause value %x : %s \n", cause, cvlist[i].edescr); + + while (!0) { + if (p > end) + break; + dp += sprintf(dp, " diag attribute %d ", *p++ & 0x7f); + dp += sprintf(dp, " rej %d ", *p & 0x7f); + if (*p & 0x80) { + *dp++ = '\n'; + break; + } else + dp += sprintf(dp, " av %d\n", (*++p) & 0x7f); + } + return (dp - dest); + +} + +static +struct MessageType cause_1tr6[] = +{ + {CAUSE_InvCRef, "Invalid Call Reference"}, + {CAUSE_BearerNotImpl, "Bearer Service Not Implemented"}, + {CAUSE_CIDunknown, "Caller Identity unknown"}, + {CAUSE_CIDinUse, "Caller Identity in Use"}, + {CAUSE_NoChans, "No Channels available"}, + {CAUSE_FacNotImpl, "Facility Not Implemented"}, + {CAUSE_FacNotSubscr, "Facility Not Subscribed"}, + {CAUSE_OutgoingBarred, "Outgoing calls barred"}, + {CAUSE_UserAccessBusy, "User Access Busy"}, + {CAUSE_NegativeGBG, "Negative GBG"}, + {CAUSE_UnknownGBG, "Unknown GBG"}, + {CAUSE_NoSPVknown, "No SPV known"}, + {CAUSE_DestNotObtain, "Destination not obtainable"}, + {CAUSE_NumberChanged, "Number changed"}, + {CAUSE_OutOfOrder, "Out Of Order"}, + {CAUSE_NoUserResponse, "No User Response"}, + {CAUSE_UserBusy, "User Busy"}, + {CAUSE_IncomingBarred, "Incoming Barred"}, + {CAUSE_CallRejected, "Call Rejected"}, + {CAUSE_NetworkCongestion, "Network Congestion"}, + {CAUSE_RemoteUser, "Remote User initiated"}, + {CAUSE_LocalProcErr, "Local Procedure Error"}, + {CAUSE_RemoteProcErr, "Remote Procedure Error"}, + {CAUSE_RemoteUserSuspend, "Remote User Suspend"}, + {CAUSE_RemoteUserResumed, "Remote User Resumed"}, + {CAUSE_UserInfoDiscarded, "User Info Discarded"} +}; + +int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType)); + +static int +prcause_1tr6(char *dest, byte * p) +{ + char *dp = dest; + int i, cause; + + p++; + if (0 == *p) { + dp += sprintf(dp, " OK (cause length=0)\n"); + return (dp - dest); + } else if (*p > 1) { + dp += sprintf(dp, " coding "); + dp += prbits(dp, p[2], 7, 2); + dp += sprintf(dp, " location "); + dp += prbits(dp, p[2], 4, 4); + *dp++ = '\n'; + } + p++; + cause = 0x7f & *p; + + /* locate cause value */ + for (i = 0; i < cause_1tr6_len; i++) + if (cause_1tr6[i].nr == cause) + break; + + /* display cause value if it exists */ + if (i == cause_1tr6_len) + dp += sprintf(dp, "Unknown cause type %x!\n", cause); + else + dp += sprintf(dp, " cause value %x : %s \n", cause, cause_1tr6[i].descr); + + return (dp - dest); + +} + +static int +prchident(char *dest, byte * p) +{ + char *dp = dest; + + p += 2; + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p, 8, 8); + *dp++ = '\n'; + return (dp - dest); +} + +static int +prcalled(char *dest, byte * p) +{ + int l; + char *dp = dest; + + p++; + l = *p++ - 1; + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p++, 8, 8); + *dp++ = '\n'; + dp += sprintf(dp, " number digits "); + while (l--) + *dp++ = *p++; + *dp++ = '\n'; + return (dp - dest); +} +static int +prcalling(char *dest, byte * p) +{ + int l; + char *dp = dest; + + p++; + l = *p++ - 1; + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p, 8, 8); + *dp++ = '\n'; + if (!(*p & 0x80)) { + dp += sprintf(dp, " octet 3a "); + dp += prbits(dp, *++p, 8, 8); + *dp++ = '\n'; + l--; + }; + p++; + + dp += sprintf(dp, " number digits "); + while (l--) + *dp++ = *p++; + *dp++ = '\n'; + return (dp - dest); +} + +static +int +prbearer(char *dest, byte * p) +{ + char *dp = dest, ch; + + p += 2; + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p++, 8, 8); + *dp++ = '\n'; + dp += sprintf(dp, " octet 4 "); + dp += prbits(dp, *p, 8, 8); + *dp++ = '\n'; + if ((*p++ & 0x1f) == 0x18) { + dp += sprintf(dp, " octet 4.1 "); + dp += prbits(dp, *p++, 8, 8); + *dp++ = '\n'; + } + /* check for user information layer 1 */ + if ((*p & 0x60) == 0x20) { + ch = ' '; + do { + dp += sprintf(dp, " octet 5%c ", ch); + dp += prbits(dp, *p, 8, 8); + *dp++ = '\n'; + if (ch == ' ') + ch = 'a'; + else + ch++; + } + while (!(*p++ & 0x80)); + } + /* check for user information layer 2 */ + if ((*p & 0x60) == 0x40) { + dp += sprintf(dp, " octet 6 "); + dp += prbits(dp, *p++, 8, 8); + *dp++ = '\n'; + } + /* check for user information layer 3 */ + if ((*p & 0x60) == 0x60) { + dp += sprintf(dp, " octet 7 "); + dp += prbits(dp, *p++, 8, 8); + *dp++ = '\n'; + } + return (dp - dest); +} + +static int +general(char *dest, byte * p) +{ + char *dp = dest; + char ch = ' '; + int l, octet = 3; + + p++; + l = *p++; + /* Iterate over all octets in the information element */ + while (l--) { + dp += sprintf(dp, " octet %d%c ", octet, ch); + dp += prbits(dp, *p++, 8, 8); + *dp++ = '\n'; + + /* last octet in group? */ + if (*p & 0x80) { + octet++; + ch = ' '; + } else if (ch == ' ') + ch = 'a'; + else + ch++; + } + return (dp - dest); +} + +static int +prcharge(char *dest, byte * p) +{ + char *dp = dest; + int l; + + p++; + l = *p++ - 1; + dp += sprintf(dp, " GEA "); + dp += prbits(dp, *p++, 8, 8); + dp += sprintf(dp, " Anzahl: "); + /* Iterate over all octets in the * information element */ + while (l--) + *dp++ = *p++; + *dp++ = '\n'; + return (dp - dest); +} +static int +prtext(char *dest, byte * p) +{ + char *dp = dest; + int l; + + p++; + l = *p++; + dp += sprintf(dp, " "); + /* Iterate over all octets in the * information element */ + while (l--) + *dp++ = *p++; + *dp++ = '\n'; + return (dp - dest); +} +static int +display(char *dest, byte * p) +{ + char *dp = dest; + char ch = ' '; + int l, octet = 3; + + p++; + l = *p++; + /* Iterate over all octets in the * display-information element */ + dp += sprintf(dp, " \""); + while (l--) { + dp += sprintf(dp, "%c", *p++); + + /* last octet in group? */ + if (*p & 0x80) { + octet++; + ch = ' '; + } else if (ch == ' ') + ch = 'a'; + + else + ch++; + } + *dp++ = '\"'; + *dp++ = '\n'; + return (dp - dest); +} + +int +prfacility(char *dest, byte * p) +{ + char *dp = dest; + int l, l2; + + p++; + l = *p++; + dp += sprintf(dp, " octet 3 "); + dp += prbits(dp, *p++, 8, 8); + dp += sprintf(dp, "\n"); + l -= 1; + + while (l > 0) { + dp += sprintf(dp, " octet 4 "); + dp += prbits(dp, *p++, 8, 8); + dp += sprintf(dp, "\n"); + dp += sprintf(dp, " octet 5 %d\n", l2 = *p++ & 0x7f); + l -= 2; + dp += sprintf(dp, " contents "); + while (l2--) { + dp += sprintf(dp, "%2x ", *p++); + l--; + } + dp += sprintf(dp, "\n"); + } + + return (dp - dest); +} + +static +struct InformationElement { + byte nr; + char *descr; + int (*f) (char *, byte *); +} ielist[] = { + + { + 0x00, "Segmented message", general + }, + { + 0x04, "Bearer capability", prbearer + }, + { + 0x08, "Cause", prcause + }, + { + 0x10, "Call identity", general + }, + { + 0x14, "Call state", general + }, + { + 0x18, "Channel identification", prchident + }, + { + 0x1c, "Facility", prfacility + }, + { + 0x1e, "Progress indicator", general + }, + { + 0x20, "Network-specific facilities", general + }, + { + 0x27, "Notification indicator", general + }, + { + 0x28, "Display", display + }, + { + 0x29, "Date/Time", general + }, + { + 0x2c, "Keypad facility", general + }, + { + 0x34, "Signal", general + }, + { + 0x40, "Information rate", general + }, + { + 0x42, "End-to-end delay", general + }, + { + 0x43, "Transit delay selection and indication", general + }, + { + 0x44, "Packet layer binary parameters", general + }, + { + 0x45, "Packet layer window size", general + }, + { + 0x46, "Packet size", general + }, + { + 0x47, "Closed user group", general + }, + { + 0x4a, "Reverse charge indication", general + }, + { + 0x6c, "Calling party number", prcalling + }, + { + 0x6d, "Calling party subaddress", general + }, + { + 0x70, "Called party number", prcalled + }, + { + 0x71, "Called party subaddress", general + }, + { + 0x74, "Redirecting number", general + }, + { + 0x78, "Transit network selection", general + }, + { + 0x79, "Restart indicator", general + }, + { + 0x7c, "Low layer compatibility", general + }, + { + 0x7d, "High layer compatibility", general + }, + { + 0x7e, "User-user", general + }, + { + 0x7f, "Escape for extension", general + }, +}; + + +#define IESIZE sizeof(ielist)/sizeof(struct InformationElement) + +static struct InformationElement we_0[] = +{ + {WE0_cause, "Cause", prcause_1tr6}, + {WE0_connAddr, "Connecting Address", prcalled}, + {WE0_callID, "Call IDentity", general}, + {WE0_chanID, "Channel IDentity", general}, + {WE0_netSpecFac, "Network Specific Facility", general}, + {WE0_display, "Display", general}, + {WE0_keypad, "Keypad", general}, + {WE0_origAddr, "Origination Address", prcalled}, + {WE0_destAddr, "Destination Address", prcalled}, + {WE0_userInfo, "User Info", general} +}; + +static int we_0_len = (sizeof(we_0) / sizeof(struct InformationElement)); + +static struct InformationElement we_6[] = +{ + {WE6_serviceInd, "Service Indicator", general}, + {WE6_chargingInfo, "Charging Information", prcharge}, + {WE6_date, "Date", prtext}, + {WE6_facSelect, "Facility Select", general}, + {WE6_facStatus, "Facility Status", general}, + {WE6_statusCalled, "Status Called", general}, + {WE6_addTransAttr, "Additional Transmission Attributes", general} +}; +static int we_6_len = (sizeof(we_6) / sizeof(struct InformationElement)); + +int +QuickHex(char *txt, byte * p, int cnt) +{ + register int i; + register char *t = txt; + register byte w; + + for (i = 0; i < cnt; i++) { + *t++ = ' '; + w = (p[i] >> 4) & 0x0f; + if (w < 10) + *t++ = '0' + w; + else + *t++ = 'A' - 10 + w; + w = p[i] & 0x0f; + if (w < 10) + *t++ = '0' + w; + else + *t++ = 'A' - 10 + w; + } + *t++ = 0; + return (t - txt); +} + +void +LogFrame(struct IsdnCardState *sp, byte * buf, int size) +{ + char *dp; + + if (size < 1) + return; + dp = sp->dlogspace; + if (size < 4096 / 3 - 10) { + dp += sprintf(dp, "HEX:"); + dp += QuickHex(dp, buf, size); + dp--; + *dp++ = '\n'; + *dp = 0; + } else + sprintf(dp, "LogFrame: warning Frame too big (%d)\n", + size); + HiSax_putstatus(sp, sp->dlogspace); +} + +void +dlogframe(struct IsdnCardState *sp, byte * buf, int size, char *comment) +{ + byte *bend = buf + size; + char *dp; + unsigned char pd, cr_l, cr, mt; + int i, cs = 0, cs_old = 0, cs_fest = 0; + + if (size < 1) + return; + /* display header */ + dp = sp->dlogspace; + dp += sprintf(dp, "%s\n", comment); + + if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */ + /* locate message type */ + pd = *buf++; + cr_l = *buf++; + if (cr_l) + cr = *buf++; + else + cr = 0; + mt = *buf++; + if (pd == PROTO_DIS_N0) { /* N0 */ + 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) + dp += sprintf(dp, "callref %d %s size %d unknown message type N0 %x!\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mt); + else + dp += sprintf(dp, "callref %d %s size %d message type %s\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mt_n0[i].descr); + } else { /* N1 */ + 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) + dp += sprintf(dp, "callref %d %s size %d unknown message type N1 %x!\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mt); + else + dp += sprintf(dp, "callref %d %s size %d message type %s\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mt_n1[i].descr); + } + + /* display each information element */ + while (buf < bend) { + /* Is it a single octet information element? */ + if (*buf & 0x80) { + switch ((*buf >> 4) & 7) { + case 1: + dp += sprintf(dp, " Shift %x\n", *buf & 0xf); + cs_old = cs; + cs = *buf & 7; + cs_fest = *buf & 8; + break; + case 3: + dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf); + break; + case 2: + if (*buf == 0xa0) { + dp += sprintf(dp, " More data\n"); + break; + } + if (*buf == 0xa1) { + dp += sprintf(dp, " Sending complete\n"); + } + break; + /* fall through */ + default: + dp += sprintf(dp, " Reserved %x\n", *buf); + break; + } + buf++; + continue; + } + /* No, locate it in the table */ + if (cs == 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) { + 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++) + if (*buf == we_6[i].nr) + break; + + /* When found, give appropriate msg */ + 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]); + } else + dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]); + /* Skip to next element */ + if (cs_fest == 8) { + cs = cs_old; + cs_old = 0; + cs_fest = 0; + } + buf += buf[1] + 2; + } + } else if (buf[0] == 8) { /* EURO */ + /* locate message type */ + buf++; + cr_l = *buf++; + if (cr_l) + cr = *buf++; + else + cr = 0; + mt = *buf++; + for (i = 0; i < MTSIZE; i++) + if (mtlist[i].nr == mt) + break; + + /* display message type if it exists */ + if (i == MTSIZE) + dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mt); + else + dp += sprintf(dp, "callref %d %s size %d message type %s\n", + cr & 0x7f, (cr & 0x80) ? "called" : "caller", + size, mtlist[i].descr); + + /* display each information element */ + while (buf < bend) { + /* Is it a single octet information element? */ + if (*buf & 0x80) { + switch ((*buf >> 4) & 7) { + case 1: + dp += sprintf(dp, " Shift %x\n", *buf & 0xf); + break; + case 3: + dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf); + break; + case 5: + dp += sprintf(dp, " Repeat indicator %x\n", *buf & 0xf); + break; + case 2: + if (*buf == 0xa0) { + dp += sprintf(dp, " More data\n"); + break; + } + if (*buf == 0xa1) { + dp += sprintf(dp, " Sending complete\n"); + } + break; + /* fall through */ + default: + dp += sprintf(dp, " Reserved %x\n", *buf); + break; + } + buf++; + continue; + } + /* No, locate it in the table */ + for (i = 0; i < IESIZE; i++) + if (*buf == ielist[i].nr) + break; + + /* When not found, give appropriate msg */ + if (i != IESIZE) { + dp += sprintf(dp, " %s\n", ielist[i].descr); + dp += ielist[i].f(dp, buf); + } else + dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); + + /* Skip to next element */ + buf += buf[1] + 2; + } + } else { + dp += sprintf(dp, "Unknown protocol %x!", buf[0]); + } + dp += sprintf(dp, "\n"); + HiSax_putstatus(sp, sp->dlogspace); +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/siemens.h linux/drivers/isdn/hisax/siemens.h --- v2.1.26/linux/drivers/isdn/hisax/siemens.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/siemens.h Tue Feb 25 17:12:49 1997 @@ -0,0 +1,71 @@ +/* $Id: siemens.h,v 1.4 1997/01/21 22:24:33 keil Exp $ + * + * siemens.h ISAC and HSCX spezific Macros + * + * Author Karsten Keil (keil@temic-ech.spacenet.de) + * + * + * $Log: siemens.h,v $ + * Revision 1.4 1997/01/21 22:24:33 keil + * cleanups + * + * Revision 1.3 1996/12/08 19:48:34 keil + * adding Monitor channel registers + * + * Revision 1.2 1996/10/27 22:24:00 keil + * HSCX version code removed + * + * Revision 1.1 1996/10/12 21:39:39 keil + * Initial revision + * + * +*/ + + +/* All Registers without FIFOs (original Siemens Spec - 20 hex) */ + +#define ISAC_MASK 0x0 +#define ISAC_ISTA 0x0 +#define ISAC_STAR 0x1 +#define ISAC_CMDR 0x1 +#define ISAC_EXIR 0x4 +#define ISAC_RBCH 0xa +#define ISAC_ADF2 0x19 +#define ISAC_SPCR 0x10 +#define ISAC_ADF1 0x18 +#define ISAC_CIR0 0x11 +#define ISAC_CIX0 0x11 +#define ISAC_STCR 0x17 +#define ISAC_MODE 0x2 +#define ISAC_RSTA 0x7 +#define ISAC_RBCL 0x5 +#define ISAC_TIMR 0x3 +#define ISAC_SQXR 0x1b +#define ISAC_MOSR 0x1a +#define ISAC_MOCR 0x1a +#define ISAC_MOR0 0x12 +#define ISAC_MOX0 0x12 +#define ISAC_MOR1 0x14 +#define ISAC_MOX1 0x14 + +#define HSCX_ISTA 0x0 +#define HSCX_CCR1 0xf +#define HSCX_CCR2 0xc +#define HSCX_TSAR 0x11 +#define HSCX_TSAX 0x10 +#define HSCX_XCCR 0x12 +#define HSCX_RCCR 0x13 +#define HSCX_MODE 0x2 +#define HSCX_CMDR 0x1 +#define HSCX_EXIR 0x4 +#define HSCX_XAD1 0x4 +#define HSCX_XAD2 0x5 +#define HSCX_RAH2 0x7 +#define HSCX_RSTA 0x7 +#define HSCX_TIMR 0x3 +#define HSCX_STAR 0x1 +#define HSCX_RBCL 0x5 +#define HSCX_XBCH 0xd +#define HSCX_VSTR 0xe +#define HSCX_RLCR 0xe +#define HSCX_MASK 0x0 diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/tei.c linux/drivers/isdn/hisax/tei.c --- v2.1.26/linux/drivers/isdn/hisax/tei.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/tei.c Tue Feb 25 17:12:49 1997 @@ -0,0 +1,314 @@ +/* $Id: tei.c,v 1.6 1997/02/09 00:25:12 keil Exp $ + + * Author Karsten Keil (keil@temic-ech.spacenet.de) + * based on the teles driver from Jan den Ouden + * + * Thanks to Jan den Ouden + * Fritz Elfert + * + * $Log: tei.c,v $ + * Revision 1.6 1997/02/09 00:25:12 keil + * new interface handling, one interface per card + * + * Revision 1.5 1997/01/27 15:57:51 keil + * cosmetics + * + * Revision 1.4 1997/01/21 22:32:44 keil + * Tei verify request + * + * Revision 1.3 1997/01/04 13:45:02 keil + * cleanup,adding remove tei request (thanks to Sim Yskes) + * + * Revision 1.2 1996/12/08 19:52:39 keil + * minor debug fix + * + * Revision 1.1 1996/10/13 20:04:57 keil + * Initial revision + * + * + * + */ +#define __NO_VERSION__ +#include "hisax.h" + +extern struct IsdnCard cards[]; +extern int nrcards; + +const char *tei_revision = "$Revision: 1.6 $"; + +static struct PStack * +findces(struct PStack *st, int ces) +{ + struct PStack *ptr = *(st->l1.stlistp); + + while (ptr) + if (ptr->l2.ces == ces) + return (ptr); + else + ptr = ptr->next; + return (NULL); +} + +static struct PStack * +findtei(struct PStack *st, int tei) +{ + struct PStack *ptr = *(st->l1.stlistp); + + if (tei == 127) + return (NULL); + + while (ptr) + if (ptr->l2.tei == tei) + return (ptr); + else + ptr = ptr->next; + return (NULL); +} + +static void +mdl_unit_data_res(struct PStack *st, unsigned int ri, byte mt, byte ai) +{ + struct BufHeader *ibh; + byte *bp; + + if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 7)) + return; + bp = DATAPTR(ibh); + bp += 3; + bp[0] = 0xf; + bp[1] = ri >> 8; + bp[2] = ri & 0xff; + bp[3] = mt; + bp[4] = (ai << 1) | 1; + ibh->datasize = 8; + st->l3.l3l2(st, DL_UNIT_DATA, ibh); +} + +static void +mdl_unit_data_ind(struct PStack *st, unsigned int ri, byte mt, byte ai) +{ + unsigned int tces; + struct PStack *otsp, *ptr; + char tmp[64]; + + switch (mt) { + case (2): + tces = ri; + if (st->l3.debug) { + sprintf(tmp, "identity assign ces %d ai %d", tces, ai); + st->l2.l2m.printdebug(&st->l2.l2m, tmp); + } + if ((otsp = findces(st, tces))) { + if (st->l3.debug) { + sprintf(tmp, "ces %d --> tei %d", tces, ai); + st->l2.l2m.printdebug(&st->l2.l2m, tmp); + } + otsp->ma.teil2(otsp, MDL_ASSIGN, (void *) (int) ai); + } + break; + case (3): + tces = ri; + if (st->l3.debug) { + sprintf(tmp, "identity denied for ces %d ai %d", tces, ai); + st->l2.l2m.printdebug(&st->l2.l2m, tmp); + } + if ((otsp = findces(st, tces))) { + if (st->l3.debug) { + sprintf(tmp, "ces %d denied tei %d", tces, ai); + st->l2.l2m.printdebug(&st->l2.l2m, tmp); + } + otsp->l2.tei = 255; + otsp->l2.ces = randomces(); + otsp->ma.teil2(otsp, MDL_REMOVE, 0); + } + break; + case (4): + if (st->l3.debug) { + sprintf(tmp, "checking identity for %d", ai); + st->l2.l2m.printdebug(&st->l2.l2m, tmp); + } + if (ai == 0x7f) { + ptr = *(st->l1.stlistp); + while (ptr) { + if ((ptr->l2.tei & 0x7f) != 0x7f) { + if (st->l3.debug) { + sprintf(tmp, "check response for ces %d with tei %d", + ptr->l2.ces, ptr->l2.tei); + st->l2.l2m.printdebug(&st->l2.l2m, tmp); + } + /* send identity check response (user->network) */ + mdl_unit_data_res(st, ptr->l2.ces, 5, ptr->l2.tei); + } + ptr = ptr->next; + } + } else { + otsp = findtei(st, ai); + if (!otsp) + break; + if (st->l3.debug) { + sprintf(tmp, "check response for ces %d with tei %d", + otsp->l2.ces, otsp->l2.tei); + st->l2.l2m.printdebug(&st->l2.l2m, tmp); + } + /* send identity check response (user->network) */ + mdl_unit_data_res(st, otsp->l2.ces, 5, otsp->l2.tei); + } + break; + case (6): + if (st->l3.debug) { + sprintf(tmp, "removal for %d", ai); + st->l2.l2m.printdebug(&st->l2.l2m, tmp); + } + if (ai == 0x7f) { + ptr = *(st->l1.stlistp); + while (ptr) { + if ((ptr->l2.tei & 0x7f) != 0x7f) { + if (st->l3.debug) { + sprintf(tmp, "rem ces %d with tei %d", + ptr->l2.ces, ptr->l2.tei); + st->l2.l2m.printdebug(&st->l2.l2m, tmp); + } + ptr->ma.teil2(ptr, MDL_REMOVE, 0); + } + ptr = ptr->next; + } + } else { + otsp = findtei(st, ai); + if (!otsp) + break; + if (st->l3.debug) { + sprintf(tmp, "rem ces %d with tei %d", + otsp->l2.ces, otsp->l2.tei); + st->l2.l2m.printdebug(&st->l2.l2m, tmp); + } + otsp->ma.teil2(otsp, MDL_REMOVE, 0); + } + break; + default: + if (st->l3.debug) { + sprintf(tmp, "message unknown %d ai %d", mt, ai); + st->l2.l2m.printdebug(&st->l2.l2m, tmp); + } + } +} + +void +tei_handler(struct PStack *st, + byte pr, struct BufHeader *ibh) +{ + byte *bp; + unsigned int data; + char tmp[32]; + + switch (pr) { + case (MDL_ASSIGN): + data = (unsigned int) ibh; + if (st->l3.debug) { + sprintf(tmp, "ces %d assign request", data); + st->l2.l2m.printdebug(&st->l2.l2m, tmp); + } + mdl_unit_data_res(st, data, 1, 127); + break; + case (MDL_VERIFY): + data = (unsigned int) ibh; + if (st->l3.debug) { + sprintf(tmp, "%d id verify request", data); + st->l2.l2m.printdebug(&st->l2.l2m, tmp); + } + mdl_unit_data_res(st, 0, 7, data); + break; + case (DL_UNIT_DATA): + bp = DATAPTR(ibh); + bp += 3; + if (bp[0] != 0xf) { + /* wrong management entity identifier, ignore */ + /* shouldn't ibh be released??? */ + printk(KERN_WARNING "tei handler wrong entity id %x\n", bp[0]); + BufPoolRelease(ibh); + break; + } + mdl_unit_data_ind(st, (bp[1] << 8) | bp[2], bp[3], bp[4] >> 1); + BufPoolRelease(ibh); + break; + default: + break; + } +} + +unsigned int +randomces(void) +{ + int x = jiffies & 0xffff; + + return (x); +} + +static void +tei_man(struct PStack *sp, int i, void *v) +{ + + printk(KERN_DEBUG "tei_man\n"); +} + +static void +tei_l2tei(struct PStack *st, int pr, void *arg) +{ + struct IsdnCardState *sp = st->l1.hardware; + + tei_handler(sp->teistack, pr, arg); +} + +void +setstack_tei(struct PStack *st) +{ + st->l2.l2tei = tei_l2tei; +} + +void +init_tei(struct IsdnCardState *sp, int protocol) +{ + struct PStack *st; + char tmp[128]; + + st = (struct PStack *) Smalloc(sizeof(struct PStack), GFP_KERNEL, + "struct PStack"); + setstack_HiSax(st, sp); + st->l2.extended = !0; + st->l2.laptype = LAPD; + st->l2.window = 1; + st->l2.orig = !0; + st->protocol = protocol; +/* + * the following is not necessary for tei mng. (broadcast only) + */ + + st->l2.t200 = 500; /* 500 milliseconds */ + st->l2.n200 = 4; /* try 4 times */ + + st->l2.sap = 63; + st->l2.tei = 127; + + sprintf(tmp, "Card %d tei", sp->cardnr + 1); + setstack_isdnl2(st, tmp); + st->l2.debug = 0; + st->l3.debug = 0; + + st->ma.manl2(st, MDL_NOTEIPROC, NULL); + + st->l2.l2l3 = (void *) tei_handler; + st->l1.l1man = tei_man; + st->l2.l2man = tei_man; + st->l4.l2writewakeup = NULL; + + HiSax_addlist(sp, st); + sp->teistack = st; +} + +void +release_tei(struct IsdnCardState *sp) +{ + struct PStack *st = sp->teistack; + + HiSax_rmlist(sp, st); + Sfree((void *) st); +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/teles0.c linux/drivers/isdn/hisax/teles0.c --- v2.1.26/linux/drivers/isdn/hisax/teles0.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/teles0.c Tue Feb 25 17:12:49 1997 @@ -0,0 +1,991 @@ +/* $Id: teles0.c,v 1.6 1997/01/27 15:52:18 keil Exp $ + + * teles0.c low level stuff for Teles Memory IO isdn cards + * based on the teles driver from Jan den Ouden + * + * Author Karsten Keil (keil@temic-ech.spacenet.de) + * + * Thanks to Jan den Ouden + * Fritz Elfert + * Beat Doebeli + * + * $Log: teles0.c,v $ + * Revision 1.6 1997/01/27 15:52:18 keil + * SMP proof,cosmetics + * + * Revision 1.5 1997/01/21 22:25:59 keil + * cleanups + * + * Revision 1.4 1996/11/05 19:41:27 keil + * more changes for 2.1 + * + * Revision 1.3 1996/10/30 10:22:58 keil + * Changes for 2.1 kernels + * + * Revision 1.2 1996/10/27 22:08:34 keil + * cosmetic changes + * + * Revision 1.1 1996/10/13 20:04:58 keil + * Initial revision + * + * + * + */ +#define __NO_VERSION__ +#include "siemens.h" +#include "hisax.h" +#include "teles0.h" +#include "isdnl1.h" +#include + +extern const char *CardType[]; + +const char *teles0_revision = "$Revision: 1.6 $"; + +#define byteout(addr,val) outb_p(val,addr) +#define bytein(addr) inb_p(addr) + +static inline byte +readisac(unsigned int adr, byte off) +{ + return readb(adr + 0x120 + ((off & 1) ? 0x1ff : 0) + off); +} + +static inline void +writeisac(unsigned int adr, byte off, byte data) +{ + writeb(data, adr + 0x120 + ((off & 1) ? 0x1ff : 0) + off); +} + + +static inline byte +readhscx(unsigned int adr, int hscx, byte off) +{ + return readb(adr + (hscx ? 0x1e0 : 0x1a0) + + ((off & 1) ? 0x1ff : 0) + off); +} + +static inline void +writehscx(unsigned int adr, int hscx, byte off, byte data) +{ + writeb(data, adr + (hscx ? 0x1e0 : 0x1a0) + + ((off & 1) ? 0x1ff : 0) + off); +} + +static inline void +read_fifo_isac(unsigned int adr, byte * data, int size) +{ + register int i; + register byte *ad = (byte *) (adr + 0x100); + for (i = 0; i < size; i++) + data[i] = readb(ad); +} + +static void +write_fifo_isac(unsigned int adr, byte * data, int size) +{ + register int i; + register byte *ad = (byte *) (adr + 0x100); + for (i = 0; i < size; i++) + writeb(data[i], ad); +} + +static inline void +read_fifo_hscx(unsigned int adr, int hscx, byte * data, int size) +{ + register int i; + register byte *ad = (byte *) (adr + (hscx ? 0x1c0 : 0x180)); + for (i = 0; i < size; i++) + data[i] = readb(ad); +} + +static inline void +write_fifo_hscx(unsigned int adr, int hscx, byte * data, int size) +{ + int i; + register byte *ad = (byte *) (adr + (hscx ? 0x1c0 : 0x180)); + for (i = 0; i < size; i++) + writeb(data[i], ad); +} +static inline void +waitforCEC(int adr, int hscx) +{ + int to = 50; + + while ((readhscx(adr, hscx, HSCX_STAR) & 0x04) && to) { + udelay(1); + to--; + } + if (!to) + printk(KERN_WARNING "Teles0: waitforCEC timeout\n"); +} + + +static inline void +waitforXFW(int adr, int hscx) +{ + int to = 50; + + while ((!(readhscx(adr, hscx, HSCX_STAR) & 0x44) == 0x40) && to) { + udelay(1); + to--; + } + if (!to) + printk(KERN_WARNING "Teles0: waitforXFW timeout\n"); +} + +static inline void +writehscxCMDR(int adr, int hscx, byte data) +{ + long flags; + + save_flags(flags); + cli(); + waitforCEC(adr, hscx); + writehscx(adr, hscx, HSCX_CMDR, data); + restore_flags(flags); +} + +/* + * fast interrupt here + */ + + +static void +hscxreport(struct IsdnCardState *sp, int hscx) +{ + printk(KERN_DEBUG "HSCX %d\n", hscx); + printk(KERN_DEBUG "ISTA %x\n", readhscx(sp->membase, hscx, HSCX_ISTA)); + printk(KERN_DEBUG "STAR %x\n", readhscx(sp->membase, hscx, HSCX_STAR)); + printk(KERN_DEBUG "EXIR %x\n", readhscx(sp->membase, hscx, HSCX_EXIR)); +} + +void +teles0_report(struct IsdnCardState *sp) +{ + printk(KERN_DEBUG "ISAC\n"); + printk(KERN_DEBUG "ISTA %x\n", readisac(sp->membase, ISAC_ISTA)); + printk(KERN_DEBUG "STAR %x\n", readisac(sp->membase, ISAC_STAR)); + printk(KERN_DEBUG "EXIR %x\n", readisac(sp->membase, ISAC_EXIR)); + hscxreport(sp, 0); + hscxreport(sp, 1); +} + +/* + * HSCX stuff goes here + */ + +static void +hscx_empty_fifo(struct HscxState *hsp, int count) +{ + byte *ptr; + struct IsdnCardState *sp = hsp->sp; + struct BufHeader *ibh = hsp->rcvibh; + long flags; + + if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO)) + debugl1(sp, "hscx_empty_fifo"); + + if (hsp->rcvptr + count > BUFFER_SIZE(HSCX_RBUF_ORDER, + HSCX_RBUF_BPPS)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "hscx_empty_fifo: incoming packet too large"); + writehscxCMDR(sp->membase, hsp->hscx, 0x80); + return; + } + ptr = DATAPTR(ibh); + ptr += hsp->rcvptr; + + hsp->rcvptr += count; + save_flags(flags); + cli(); + read_fifo_hscx(sp->membase, hsp->hscx, ptr, count); + writehscxCMDR(sp->membase, hsp->hscx, 0x80); + restore_flags(flags); + if (sp->debug & L1_DEB_HSCX_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "hscx_empty_fifo %c cnt %d", + hsp->hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static void +hscx_fill_fifo(struct HscxState *hsp) +{ + struct IsdnCardState *sp = hsp->sp; + struct BufHeader *ibh; + int more, count; + byte *ptr; + long flags; + + if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO)) + debugl1(sp, "hscx_fill_fifo"); + + ibh = hsp->xmtibh; + if (!ibh) + return; + + count = ibh->datasize - hsp->sendptr; + if (count <= 0) + return; + + more = (hsp->mode == 1) ? 1 : 0; + if (count > 32) { + more = !0; + count = 32; + } + ptr = DATAPTR(ibh); + ptr += hsp->sendptr; + hsp->sendptr += count; + + waitforXFW(sp->membase, hsp->hscx); + save_flags(flags); + cli(); + write_fifo_hscx(sp->membase, hsp->hscx, ptr, count); + writehscxCMDR(sp->membase, hsp->hscx, more ? 0x8 : 0xa); + restore_flags(flags); + if (sp->debug & L1_DEB_HSCX_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "hscx_fill_fifo %c cnt %d", + hsp->hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static inline void +hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx) +{ + byte r; + struct HscxState *hsp = sp->hs + hscx; + int count, err; + char tmp[32]; + + if (!hsp->init) + return; + + if (val & 0x80) { /* RME */ + + r = readhscx(sp->membase, hsp->hscx, HSCX_RSTA); + if ((r & 0xf0) != 0xa0) { + if (!r & 0x80) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX invalid frame"); + if ((r & 0x40) && hsp->mode) + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "HSCX RDO mode=%d", + hsp->mode); + debugl1(sp, tmp); + } + if (!r & 0x20) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX CRC error"); + if (hsp->rcvibh) + BufPoolRelease(hsp->rcvibh); + hsp->rcvibh = NULL; + writehscxCMDR(sp->membase, hsp->hscx, 0x80); + goto afterRME; + } + if (!hsp->rcvibh) + if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool, + GFP_ATOMIC, (void *) 1, 1)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX RME out of buffers"); + writehscxCMDR(sp->membase, hsp->hscx, 0x80); + goto afterRME; + } else + hsp->rcvptr = 0; + + count = readhscx(sp->membase, hsp->hscx, HSCX_RBCL) & 0x1f; + if (count == 0) + count = 32; + hscx_empty_fifo(hsp, count); + hsp->rcvibh->datasize = hsp->rcvptr - 1; + BufQueueLink(&hsp->rq, hsp->rcvibh); + hsp->rcvibh = NULL; + hscx_sched_event(hsp, HSCX_RCVBUFREADY); + } + afterRME: + if (val & 0x40) { /* RPF */ + if (!hsp->rcvibh) { + if (hsp->mode == 1) + err = BufPoolGet(&hsp->rcvibh, &hsp->smallpool, + GFP_ATOMIC, (void *) 1, 2); + else + err = BufPoolGet(&hsp->rcvibh, &hsp->rbufpool, + GFP_ATOMIC, (void *) 1, 2); + + if (err) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX RPF out of buffers"); + writehscxCMDR(sp->membase, hsp->hscx, 0x80); + goto afterRPF; + } else + hsp->rcvptr = 0; + } + hscx_empty_fifo(hsp, 32); + if (hsp->mode == 1) { + /* receive audio data */ + hsp->rcvibh->datasize = hsp->rcvptr; + BufQueueLink(&hsp->rq, hsp->rcvibh); + hsp->rcvibh = NULL; + hscx_sched_event(hsp, HSCX_RCVBUFREADY); + } + } + afterRPF: + if (val & 0x10) { /* XPR */ + if (hsp->xmtibh) + if (hsp->xmtibh->datasize > hsp->sendptr) { + hscx_fill_fifo(hsp); + goto afterXPR; + } else { + if (hsp->releasebuf) + BufPoolRelease(hsp->xmtibh); + hsp->sendptr = 0; + if (hsp->st->l4.l1writewakeup) + hsp->st->l4.l1writewakeup(hsp->st); + hsp->xmtibh = NULL; + } + if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) { + hsp->releasebuf = !0; + hscx_fill_fifo(hsp); + } else + hscx_sched_event(hsp, HSCX_XMTBUFREADY); + } + afterXPR: +} + +/* + * ISAC stuff goes here + */ + +static void +isac_empty_fifo(struct IsdnCardState *sp, int count) +{ + byte *ptr; + struct BufHeader *ibh = sp->rcvibh; + long flags; + + if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO)) + debugl1(sp, "isac_empty_fifo"); + + if (sp->rcvptr >= 3072) { + if (sp->debug & L1_DEB_WARN) { + char tmp[40]; + sprintf(tmp, "isac_empty_fifo rcvptr %d", sp->rcvptr); + debugl1(sp, tmp); + } + return; + } + ptr = DATAPTR(ibh); + ptr += sp->rcvptr; + sp->rcvptr += count; + + save_flags(flags); + cli(); + read_fifo_isac(sp->membase, ptr, count); + writeisac(sp->membase, ISAC_CMDR, 0x80); + restore_flags(flags); + if (sp->debug & L1_DEB_ISAC_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "isac_empty_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static void +isac_fill_fifo(struct IsdnCardState *sp) +{ + struct BufHeader *ibh; + int count, more; + byte *ptr; + long flags; + + if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO)) + debugl1(sp, "isac_fill_fifo"); + + ibh = sp->xmtibh; + if (!ibh) + return; + + count = ibh->datasize - sp->sendptr; + if (count <= 0) + return; + if (count >= 3072) + return; + + more = 0; + if (count > 32) { + more = !0; + count = 32; + } + ptr = DATAPTR(ibh); + ptr += sp->sendptr; + sp->sendptr += count; + + save_flags(flags); + cli(); + write_fifo_isac(sp->membase, ptr, count); + writeisac(sp->membase, ISAC_CMDR, more ? 0x8 : 0xa); + restore_flags(flags); + if (sp->debug & L1_DEB_ISAC_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "isac_fill_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static void +ph_command(struct IsdnCardState *sp, unsigned int command) +{ + if (sp->debug & L1_DEB_ISAC) { + char tmp[32]; + sprintf(tmp, "ph_command %d", command); + debugl1(sp, tmp); + } + writeisac(sp->membase, ISAC_CIX0, (command << 2) | 3); +} + +static inline void +isac_interrupt(struct IsdnCardState *sp, byte val) +{ + byte exval; + unsigned int count; + char tmp[32]; + + if (sp->debug & L1_DEB_ISAC) { + sprintf(tmp, "ISAC interrupt %x", val); + debugl1(sp, tmp); + } + if (val & 0x80) { /* RME */ + exval = readisac(sp->membase, ISAC_RSTA); + if ((exval & 0x70) != 0x20) { + if (exval & 0x40) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RDO"); + if (!exval & 0x20) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC CRC error"); + if (sp->rcvibh) + BufPoolRelease(sp->rcvibh); + sp->rcvibh = NULL; + writeisac(sp->membase, ISAC_CMDR, 0x80); + goto afterRME; + } + if (!sp->rcvibh) + if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool), + GFP_ATOMIC, (void *) 1, 3)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RME out of buffers!"); + writeisac(sp->membase, ISAC_CMDR, 0x80); + goto afterRME; + } else + sp->rcvptr = 0; + count = readisac(sp->membase, ISAC_RBCL) & 0x1f; + if (count == 0) + count = 32; + isac_empty_fifo(sp, count); + sp->rcvibh->datasize = sp->rcvptr; + BufQueueLink(&(sp->rq), sp->rcvibh); + sp->rcvibh = NULL; + isac_sched_event(sp, ISAC_RCVBUFREADY); + } + afterRME: + if (val & 0x40) { /* RPF */ + if (!sp->rcvibh) + if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool), + GFP_ATOMIC, (void *) 1, 4)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RME out of buffers!"); + writeisac(sp->membase, ISAC_CMDR, 0x80); + goto afterRPF; + } else + sp->rcvptr = 0; + isac_empty_fifo(sp, 32); + } + afterRPF: + if (val & 0x20) { /* RSC */ + /* never */ + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RSC interrupt"); + } + if (val & 0x10) { /* XPR */ + if (sp->xmtibh) + if (sp->xmtibh->datasize > sp->sendptr) { + isac_fill_fifo(sp); + goto afterXPR; + } else { + if (sp->releasebuf) + BufPoolRelease(sp->xmtibh); + sp->xmtibh = NULL; + sp->sendptr = 0; + } + if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) { + sp->releasebuf = !0; + isac_fill_fifo(sp); + } else + isac_sched_event(sp, ISAC_XMTBUFREADY); + } + afterXPR: + if (val & 0x04) { /* CISQ */ + sp->ph_state = (readisac(sp->membase, ISAC_CIX0) >> 2) + & 0xf; + if (sp->debug & L1_DEB_ISAC) { + sprintf(tmp, "l1state %d", sp->ph_state); + debugl1(sp, tmp); + } + isac_new_ph(sp); + } + if (val & 0x02) { /* SIN */ + /* never */ + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC SIN interrupt"); + } + if (val & 0x01) { /* EXI */ + exval = readisac(sp->membase, ISAC_EXIR); + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "ISAC EXIR %02x", exval); + debugl1(sp, tmp); + } + } +} + +static inline void +hscx_int_main(struct IsdnCardState *sp, byte val) +{ + + byte exval; + struct HscxState *hsp; + char tmp[32]; + + + if (val & 0x01) { + hsp = sp->hs + 1; + exval = readhscx(sp->membase, 1, HSCX_EXIR); + if (exval == 0x40) { + if (hsp->mode == 1) + hscx_fill_fifo(hsp); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + hsp->sendptr = 0; + writehscxCMDR(sp->membase, hsp->hscx, 0x01); + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "HSCX B EXIR %x Lost TX", exval); + debugl1(sp, tmp); + } + } + } else if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX B EXIR %x", exval); + debugl1(sp, tmp); + } + } + if (val & 0xf8) { + if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX B interrupt %x", val); + debugl1(sp, tmp); + } + hscx_interrupt(sp, val, 1); + } + if (val & 0x02) { + hsp = sp->hs; + exval = readhscx(sp->membase, 0, HSCX_EXIR); + if (exval == 0x40) { + if (hsp->mode == 1) + hscx_fill_fifo(hsp); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + hsp->sendptr = 0; + writehscxCMDR(sp->membase, hsp->hscx, 0x01); + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "HSCX A EXIR %x Lost TX", exval); + debugl1(sp, tmp); + } + } + } else if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX A EXIR %x", exval); + debugl1(sp, tmp); + } + } + if (val & 0x04) { + exval = readhscx(sp->membase, 0, HSCX_ISTA); + if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX A interrupt %x", exval); + debugl1(sp, tmp); + } + hscx_interrupt(sp, exval, 0); + } +} + +static void +telesS0_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *sp; + byte val, stat = 0; + + sp = (struct IsdnCardState *) irq2dev_map[intno]; + + if (!sp) { + printk(KERN_WARNING "Teles0: Spurious interrupt!\n"); + return; + } + val = readhscx(sp->membase, 1, HSCX_ISTA); + Start_HSCX: + if (val) { + hscx_int_main(sp, val); + stat |= 1; + } + val = readisac(sp->membase, ISAC_ISTA); + Start_ISAC: + if (val) { + isac_interrupt(sp, val); + stat |= 2; + } + val = readhscx(sp->membase, 1, HSCX_ISTA); + if (val) { + if (sp->debug & L1_DEB_HSCX) + debugl1(sp, "HSCX IntStat after IntRoutine"); + goto Start_HSCX; + } + val = readisac(sp->membase, ISAC_ISTA); + if (val) { + if (sp->debug & L1_DEB_ISAC) + debugl1(sp, "ISAC IntStat after IntRoutine"); + goto Start_ISAC; + } + if (stat & 1) { + writehscx(sp->membase, 0, HSCX_MASK, 0xFF); + writehscx(sp->membase, 1, HSCX_MASK, 0xFF); + writehscx(sp->membase, 0, HSCX_MASK, 0x0); + writehscx(sp->membase, 1, HSCX_MASK, 0x0); + } + if (stat & 2) { + writeisac(sp->membase, ISAC_MASK, 0xFF); + writeisac(sp->membase, ISAC_MASK, 0x0); + } +} + + +static void +initisac(struct IsdnCardState *sp) +{ + unsigned int adr = sp->membase; + + /* 16.0 IOM 1 Mode */ + writeisac(adr, ISAC_MASK, 0xff); + writeisac(adr, ISAC_ADF2, 0x0); + writeisac(adr, ISAC_SPCR, 0xa); + writeisac(adr, ISAC_ADF1, 0x2); + writeisac(adr, ISAC_STCR, 0x70); + writeisac(adr, ISAC_MODE, 0xc9); + writeisac(adr, ISAC_CMDR, 0x41); + writeisac(adr, ISAC_CIX0, (1 << 2) | 3); + writeisac(adr, ISAC_MASK, 0xff); + writeisac(adr, ISAC_MASK, 0x0); +} + +static void +modehscx(struct HscxState *hs, int mode, int ichan) +{ + struct IsdnCardState *sp = hs->sp; + int hscx = hs->hscx; + + if (sp->debug & L1_DEB_HSCX) { + char tmp[40]; + sprintf(tmp, "hscx %c mode %d ichan %d", + 'A' + hscx, mode, ichan); + debugl1(sp, tmp); + } + hs->mode = mode; + writehscx(sp->membase, hscx, HSCX_CCR1, 0x85); + writehscx(sp->membase, hscx, HSCX_XAD1, 0xFF); + writehscx(sp->membase, hscx, HSCX_XAD2, 0xFF); + writehscx(sp->membase, hscx, HSCX_RAH2, 0xFF); + writehscx(sp->membase, hscx, HSCX_XBCH, 0x0); + + /* Switch IOM 1 SSI */ + if (hscx == 0) + ichan = 1 - ichan; + + switch (mode) { + case (0): + writehscx(sp->membase, hscx, HSCX_CCR2, 0x30); + writehscx(sp->membase, hscx, HSCX_TSAX, 0xff); + writehscx(sp->membase, hscx, HSCX_TSAR, 0xff); + writehscx(sp->membase, hscx, HSCX_XCCR, 7); + writehscx(sp->membase, hscx, HSCX_RCCR, 7); + writehscx(sp->membase, hscx, HSCX_MODE, 0x84); + break; + case (1): + if (ichan == 0) { + writehscx(sp->membase, hscx, HSCX_CCR2, 0x30); + writehscx(sp->membase, hscx, HSCX_TSAX, 0x7); + writehscx(sp->membase, hscx, HSCX_TSAR, 0x7); + writehscx(sp->membase, hscx, HSCX_XCCR, 7); + writehscx(sp->membase, hscx, HSCX_RCCR, 7); + } else { + writehscx(sp->membase, hscx, HSCX_CCR2, 0x30); + writehscx(sp->membase, hscx, HSCX_TSAX, 0x3); + writehscx(sp->membase, hscx, HSCX_TSAR, 0x3); + writehscx(sp->membase, hscx, HSCX_XCCR, 7); + writehscx(sp->membase, hscx, HSCX_RCCR, 7); + } + writehscx(sp->membase, hscx, HSCX_MODE, 0xe4); + writehscx(sp->membase, hscx, HSCX_CMDR, 0x41); + break; + case (2): + if (ichan == 0) { + writehscx(sp->membase, hscx, HSCX_CCR2, 0x30); + writehscx(sp->membase, hscx, HSCX_TSAX, 0x7); + writehscx(sp->membase, hscx, HSCX_TSAR, 0x7); + writehscx(sp->membase, hscx, HSCX_XCCR, 7); + writehscx(sp->membase, hscx, HSCX_RCCR, 7); + } else { + writehscx(sp->membase, hscx, HSCX_CCR2, 0x30); + writehscx(sp->membase, hscx, HSCX_TSAX, 0x3); + writehscx(sp->membase, hscx, HSCX_TSAR, 0x3); + writehscx(sp->membase, hscx, HSCX_XCCR, 7); + writehscx(sp->membase, hscx, HSCX_RCCR, 7); + } + writehscx(sp->membase, hscx, HSCX_MODE, 0x8c); + writehscx(sp->membase, hscx, HSCX_CMDR, 0x41); + break; + } + writehscx(sp->membase, hscx, HSCX_ISTA, 0x00); +} + +void +release_io_teles0(struct IsdnCard *card) +{ + if (card->sp->cfg_reg) + release_region(card->sp->cfg_reg, 8); +} + +static void +clear_pending_ints(struct IsdnCardState *sp) +{ + int val; + char tmp[64]; + + val = readhscx(sp->membase, 1, HSCX_ISTA); + sprintf(tmp, "HSCX B ISTA %x", val); + debugl1(sp, tmp); + if (val & 0x01) { + val = readhscx(sp->membase, 1, HSCX_EXIR); + sprintf(tmp, "HSCX B EXIR %x", val); + debugl1(sp, tmp); + } else if (val & 0x02) { + val = readhscx(sp->membase, 0, HSCX_EXIR); + sprintf(tmp, "HSCX A EXIR %x", val); + debugl1(sp, tmp); + } + val = readhscx(sp->membase, 0, HSCX_ISTA); + sprintf(tmp, "HSCX A ISTA %x", val); + debugl1(sp, tmp); + val = readhscx(sp->membase, 1, HSCX_STAR); + sprintf(tmp, "HSCX B STAR %x", val); + debugl1(sp, tmp); + val = readhscx(sp->membase, 0, HSCX_STAR); + sprintf(tmp, "HSCX A STAR %x", val); + debugl1(sp, tmp); + val = readisac(sp->membase, ISAC_STAR); + sprintf(tmp, "ISAC STAR %x", val); + debugl1(sp, tmp); + val = readisac(sp->membase, ISAC_MODE); + sprintf(tmp, "ISAC MODE %x", val); + debugl1(sp, tmp); + val = readisac(sp->membase, ISAC_ADF2); + sprintf(tmp, "ISAC ADF2 %x", val); + debugl1(sp, tmp); + val = readisac(sp->membase, ISAC_ISTA); + sprintf(tmp, "ISAC ISTA %x", val); + debugl1(sp, tmp); + if (val & 0x01) { + val = readisac(sp->membase, ISAC_EXIR); + sprintf(tmp, "ISAC EXIR %x", val); + debugl1(sp, tmp); + } else if (val & 0x04) { + val = readisac(sp->membase, ISAC_CIR0); + sprintf(tmp, "ISAC CIR0 %x", val); + debugl1(sp, tmp); + } + writeisac(sp->membase, ISAC_MASK, 0); + writeisac(sp->membase, ISAC_CMDR, 0x41); +} + +int +initteles0(struct IsdnCardState *sp) +{ + int ret; + char tmp[40]; + + sp->counter = kstat.interrupts[sp->irq]; + sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter); + debugl1(sp, tmp); + clear_pending_ints(sp); + ret = get_irq(sp->cardnr, &telesS0_interrupt); + if (ret) { + initisac(sp); + sp->modehscx(sp->hs, 0, 0); + sp->modehscx(sp->hs + 1, 0, 0); + sprintf(tmp, "IRQ %d count %d", sp->irq, + kstat.interrupts[sp->irq]); + debugl1(sp, tmp); + if (kstat.interrupts[sp->irq] == sp->counter) { + printk(KERN_WARNING + "Teles0: IRQ(%d) getting no interrupts during init\n", + sp->irq); + irq2dev_map[sp->irq] = NULL; + free_irq(sp->irq, NULL); + return (0); + } + } + return (ret); +} + +int +setup_teles0(struct IsdnCard *card) +{ + byte cfval, val, verA, verB; + struct IsdnCardState *sp = card->sp; + long flags; + char tmp[64]; + + strcpy(tmp, teles0_revision); + printk(KERN_NOTICE "HiSax: Teles 8.0/16.0 driver Rev. %s\n", HiSax_getrev(tmp)); + if ((sp->typ != ISDN_CTYPE_16_0) && (sp->typ != ISDN_CTYPE_8_0)) + return (0); + + if (sp->typ == ISDN_CTYPE_16_0) + sp->cfg_reg = card->para[2]; + else /* 8.0 */ + sp->cfg_reg = 0; + + if (card->para[1] < 0x10000) { + card->para[1] <<= 4; + printk(KERN_INFO + "Teles0: membase configured DOSish, assuming 0x%lx\n", + (unsigned long) card->para[1]); + } + sp->membase = card->para[1]; + sp->irq = card->para[0]; + if (sp->cfg_reg) { + if (check_region((sp->cfg_reg), 8)) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + sp->cfg_reg, + sp->cfg_reg + 8); + return (0); + } else { + request_region(sp->cfg_reg, 8, "teles cfg"); + } + } + switch (sp->irq) { + case 2: + cfval = 0x00; + break; + case 3: + cfval = 0x02; + break; + case 4: + cfval = 0x04; + break; + case 5: + cfval = 0x06; + break; + case 10: + cfval = 0x08; + break; + case 11: + cfval = 0x0A; + break; + case 12: + cfval = 0x0C; + break; + case 15: + cfval = 0x0E; + break; + default: + cfval = 0x00; + break; + } + cfval |= ((card->para[1] >> 9) & 0xF0); + if (sp->cfg_reg) { + if ((val = bytein(sp->cfg_reg + 0)) != 0x51) { + printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n", + sp->cfg_reg + 0, val); + release_region(sp->cfg_reg, 8); + return (0); + } + if ((val = bytein(sp->cfg_reg + 1)) != 0x93) { + printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n", + sp->cfg_reg + 1, val); + release_region(sp->cfg_reg, 8); + return (0); + } + val = bytein(sp->cfg_reg + 2); /* 0x1e=without AB + * 0x1f=with AB + * 0x1c 16.3 ??? + */ + if (val != 0x1e && val != 0x1f) { + printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n", + sp->cfg_reg + 2, val); + release_region(sp->cfg_reg, 8); + return (0); + } + save_flags(flags); + byteout(sp->cfg_reg + 4, cfval); + sti(); + HZDELAY(HZ / 10 + 1); + byteout(sp->cfg_reg + 4, cfval | 1); + HZDELAY(HZ / 10 + 1); + restore_flags(flags); + } + printk(KERN_NOTICE + "HiSax: %s config irq:%d mem:%x cfg:%x\n", + CardType[sp->typ], sp->irq, + sp->membase, sp->cfg_reg); + verA = readhscx(sp->membase, 0, HSCX_VSTR) & 0xf; + verB = readhscx(sp->membase, 1, HSCX_VSTR) & 0xf; + printk(KERN_INFO "Teles0: HSCX version A: %s B: %s\n", + HscxVersion(verA), HscxVersion(verB)); + val = readisac(sp->membase, ISAC_RBCH); + printk(KERN_INFO "Teles0: ISAC %s\n", + ISACVersion(val)); + + if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) { + printk(KERN_WARNING + "Teles0: wrong HSCX versions check IO/MEM addresses\n"); + release_io_teles0(card); + return (0); + } + save_flags(flags); + writeb(0, sp->membase + 0x80); + sti(); + HZDELAY(HZ / 5 + 1); + writeb(1, sp->membase + 0x80); + HZDELAY(HZ / 5 + 1); + restore_flags(flags); + + sp->modehscx = &modehscx; + sp->ph_command = &ph_command; + sp->hscx_fill_fifo = &hscx_fill_fifo; + sp->isac_fill_fifo = &isac_fill_fifo; + return (1); +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/teles0.h linux/drivers/isdn/hisax/teles0.h --- v2.1.26/linux/drivers/isdn/hisax/teles0.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/teles0.h Tue Feb 25 17:12:49 1997 @@ -0,0 +1,21 @@ +/* $Id: teles0.h,v 1.2 1997/01/21 22:26:52 keil Exp $ + * + * teles0.h Header for Teles 16.0 8.0 & compatible + * + * Author Karsten Keil (keil@temic-ech.spacenet.de) + * + * + * $Log: teles0.h,v $ + * Revision 1.2 1997/01/21 22:26:52 keil + * cleanups + * + * Revision 1.1 1996/10/13 20:03:48 keil + * Initial revision + * + * +*/ + +extern void teles0_report(struct IsdnCardState *sp); +extern void release_io_teles0(struct IsdnCard *card); +extern int setup_teles0(struct IsdnCard *card); +extern int initteles0(struct IsdnCardState *sp); diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/teles3.c linux/drivers/isdn/hisax/teles3.c --- v2.1.26/linux/drivers/isdn/hisax/teles3.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/teles3.c Tue Feb 25 17:12:49 1997 @@ -0,0 +1,1037 @@ +/* $Id: teles3.c,v 1.7 1997/01/28 22:48:33 keil Exp $ + + * teles3.c low level stuff for Teles 16.3 & PNP isdn cards + * + * based on the teles driver from Jan den Ouden + * + * Author Karsten Keil (keil@temic-ech.spacenet.de) + * + * Thanks to Jan den Ouden + * Fritz Elfert + * Beat Doebeli + * + * $Log: teles3.c,v $ + * Revision 1.7 1997/01/28 22:48:33 keil + * fixes for Teles PCMCIA (Christof Petig) + * + * Revision 1.6 1997/01/27 15:52:55 keil + * SMP proof,cosmetics, PCMCIA added + * + * Revision 1.5 1997/01/21 22:28:32 keil + * cleanups + * + * Revision 1.4 1996/12/14 21:05:41 keil + * Reset for 16.3 PnP + * + * Revision 1.3 1996/11/05 19:56:54 keil + * debug output fixed + * + * Revision 1.2 1996/10/27 22:09:15 keil + * cosmetic changes + * + * Revision 1.1 1996/10/13 20:04:59 keil + * Initial revision + * + * + * + */ +#define __NO_VERSION__ +#include "siemens.h" +#include "hisax.h" +#include "teles3.h" +#include "isdnl1.h" +#include + +extern const char *CardType[]; +const char *teles3_revision = "$Revision: 1.7 $"; + +#define byteout(addr,val) outb_p(val,addr) +#define bytein(addr) inb_p(addr) + +static inline byte +readreg(unsigned int adr, byte off) +{ + return (bytein(adr + off)); +} + +static inline void +writereg(unsigned int adr, byte off, byte data) +{ + byteout(adr + off, data); +} + + +static inline void +read_fifo(unsigned int adr, byte * data, int size) +{ + insb(adr + 0x1e, data, size); +} + +static void +write_fifo(unsigned int adr, byte * data, int size) +{ + outsb(adr + 0x1e, data, size); +} + +static inline void +waitforCEC(int adr) +{ + int to = 50; + + while ((readreg(adr, HSCX_STAR) & 0x04) && to) { + udelay(1); + to--; + } + if (!to) + printk(KERN_WARNING "Teles3: waitforCEC timeout\n"); +} + + +static inline void +waitforXFW(int adr) +{ + int to = 50; + + while ((!(readreg(adr, HSCX_STAR) & 0x44) == 0x40) && to) { + udelay(1); + to--; + } + if (!to) + printk(KERN_WARNING "Teles3: waitforXFW timeout\n"); +} +static inline void +writehscxCMDR(int adr, byte data) +{ + long flags; + + save_flags(flags); + cli(); + waitforCEC(adr); + writereg(adr, HSCX_CMDR, data); + restore_flags(flags); +} + +/* + * fast interrupt here + */ + +static void +hscxreport(struct IsdnCardState *sp, int hscx) +{ + printk(KERN_DEBUG "HSCX %d\n", hscx); + printk(KERN_DEBUG "ISTA %x\n", readreg(sp->hscx[hscx], HSCX_ISTA)); + printk(KERN_DEBUG "STAR %x\n", readreg(sp->hscx[hscx], HSCX_STAR)); + printk(KERN_DEBUG "EXIR %x\n", readreg(sp->hscx[hscx], HSCX_EXIR)); +} + +void +teles3_report(struct IsdnCardState *sp) +{ + printk(KERN_DEBUG "ISAC\n"); + printk(KERN_DEBUG "ISTA %x\n", readreg(sp->isac, ISAC_ISTA)); + printk(KERN_DEBUG "STAR %x\n", readreg(sp->isac, ISAC_STAR)); + printk(KERN_DEBUG "EXIR %x\n", readreg(sp->isac, ISAC_EXIR)); + hscxreport(sp, 0); + hscxreport(sp, 1); +} + +/* + * HSCX stuff goes here + */ + +static void +hscx_empty_fifo(struct HscxState *hsp, int count) +{ + byte *ptr; + struct IsdnCardState *sp = hsp->sp; + struct BufHeader *ibh = hsp->rcvibh; + long flags; + + if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO)) + debugl1(sp, "hscx_empty_fifo"); + + if (hsp->rcvptr + count > BUFFER_SIZE(HSCX_RBUF_ORDER, + HSCX_RBUF_BPPS)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "hscx_empty_fifo: incoming packet too large"); + writehscxCMDR(sp->hscx[hsp->hscx], 0x80); + return; + } + ptr = DATAPTR(ibh); + ptr += hsp->rcvptr; + + hsp->rcvptr += count; + save_flags(flags); + cli(); + read_fifo(sp->hscx[hsp->hscx], ptr, count); + writehscxCMDR(sp->hscx[hsp->hscx], 0x80); + restore_flags(flags); + if (sp->debug & L1_DEB_HSCX_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "hscx_empty_fifo %c cnt %d", + hsp->hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static void +hscx_fill_fifo(struct HscxState *hsp) +{ + struct IsdnCardState *sp = hsp->sp; + struct BufHeader *ibh; + int more, count; + byte *ptr; + long flags; + + if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO)) + debugl1(sp, "hscx_fill_fifo"); + + ibh = hsp->xmtibh; + if (!ibh) + return; + + count = ibh->datasize - hsp->sendptr; + if (count <= 0) + return; + + more = (hsp->mode == 1) ? 1 : 0; + if (count > 32) { + more = !0; + count = 32; + } + ptr = DATAPTR(ibh); + ptr += hsp->sendptr; + hsp->sendptr += count; + + waitforXFW(sp->hscx[hsp->hscx]); + save_flags(flags); + cli(); + write_fifo(sp->hscx[hsp->hscx], ptr, count); + writehscxCMDR(sp->hscx[hsp->hscx], more ? 0x8 : 0xa); + restore_flags(flags); + if (sp->debug & L1_DEB_HSCX_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "hscx_fill_fifo %c cnt %d", + hsp->hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static inline void +hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx) +{ + byte r; + struct HscxState *hsp = sp->hs + hscx; + int count, err; + char tmp[32]; + + if (!hsp->init) + return; + + if (val & 0x80) { /* RME */ + + r = readreg(sp->hscx[hsp->hscx], HSCX_RSTA); + if ((r & 0xf0) != 0xa0) { + if (!r & 0x80) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX invalid frame"); + if ((r & 0x40) && hsp->mode) + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "HSCX RDO mode=%d", + hsp->mode); + debugl1(sp, tmp); + } + if (!r & 0x20) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX CRC error"); + if (hsp->rcvibh) + BufPoolRelease(hsp->rcvibh); + hsp->rcvibh = NULL; + writehscxCMDR(sp->hscx[hsp->hscx], 0x80); + goto afterRME; + } + if (!hsp->rcvibh) + if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool, + GFP_ATOMIC, (void *) 1, 1)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX RME out of buffers"); + writehscxCMDR(sp->hscx[hsp->hscx], 0x80); + goto afterRME; + } else + hsp->rcvptr = 0; + + count = readreg(sp->hscx[hsp->hscx], HSCX_RBCL) & 0x1f; + if (count == 0) + count = 32; + hscx_empty_fifo(hsp, count); + hsp->rcvibh->datasize = hsp->rcvptr - 1; + BufQueueLink(&hsp->rq, hsp->rcvibh); + hsp->rcvibh = NULL; + hscx_sched_event(hsp, HSCX_RCVBUFREADY); + } + afterRME: + if (val & 0x40) { /* RPF */ + if (!hsp->rcvibh) { + if (hsp->mode == 1) + err = BufPoolGet(&hsp->rcvibh, &hsp->smallpool, + GFP_ATOMIC, (void *) 1, 2); + else + err = BufPoolGet(&hsp->rcvibh, &hsp->rbufpool, + GFP_ATOMIC, (void *) 1, 2); + + if (err) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "HSCX RPF out of buffers"); + writehscxCMDR(sp->hscx[hsp->hscx], 0x80); + goto afterRPF; + } else + hsp->rcvptr = 0; + } + hscx_empty_fifo(hsp, 32); + if (hsp->mode == 1) { + /* receive audio data */ + hsp->rcvibh->datasize = hsp->rcvptr; + BufQueueLink(&hsp->rq, hsp->rcvibh); + hsp->rcvibh = NULL; + hscx_sched_event(hsp, HSCX_RCVBUFREADY); + } + } + afterRPF: + if (val & 0x10) { /* XPR */ + if (hsp->xmtibh) + if (hsp->xmtibh->datasize > hsp->sendptr) { + hscx_fill_fifo(hsp); + goto afterXPR; + } else { + if (hsp->releasebuf) + BufPoolRelease(hsp->xmtibh); + hsp->sendptr = 0; + if (hsp->st->l4.l1writewakeup) + hsp->st->l4.l1writewakeup(hsp->st); + hsp->xmtibh = NULL; + } + if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) { + hsp->releasebuf = !0; + hscx_fill_fifo(hsp); + } else + hscx_sched_event(hsp, HSCX_XMTBUFREADY); + } + afterXPR: +} + +/* + * ISAC stuff goes here + */ + +static void +isac_empty_fifo(struct IsdnCardState *sp, int count) +{ + byte *ptr; + struct BufHeader *ibh = sp->rcvibh; + long flags; + + if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO)) + if (sp->debug & L1_DEB_ISAC) + debugl1(sp, "isac_empty_fifo"); + + if (sp->rcvptr >= 3072) { + if (sp->debug & L1_DEB_WARN) { + char tmp[40]; + sprintf(tmp, "isac_empty_fifo rcvptr %d", sp->rcvptr); + debugl1(sp, tmp); + } + return; + } + ptr = DATAPTR(ibh); + ptr += sp->rcvptr; + sp->rcvptr += count; + + save_flags(flags); + cli(); + read_fifo(sp->isac, ptr, count); + writereg(sp->isac, ISAC_CMDR, 0x80); + restore_flags(flags); + if (sp->debug & L1_DEB_ISAC_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "isac_empty_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static void +isac_fill_fifo(struct IsdnCardState *sp) +{ + struct BufHeader *ibh; + int count, more; + byte *ptr; + long flags; + + if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO)) + debugl1(sp, "isac_fill_fifo"); + + ibh = sp->xmtibh; + if (!ibh) + return; + + count = ibh->datasize - sp->sendptr; + if (count <= 0) + return; + if (count >= 3072) + return; + + more = 0; + if (count > 32) { + more = !0; + count = 32; + } + ptr = DATAPTR(ibh); + ptr += sp->sendptr; + sp->sendptr += count; + + save_flags(flags); + cli(); + write_fifo(sp->isac, ptr, count); + writereg(sp->isac, ISAC_CMDR, more ? 0x8 : 0xa); + restore_flags(flags); + if (sp->debug & L1_DEB_ISAC_FIFO) { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "isac_fill_fifo cnt %d", count); + QuickHex(t, ptr, count); + debugl1(sp, tmp); + } +} + +static void +ph_command(struct IsdnCardState *sp, unsigned int command) +{ + if (sp->debug & L1_DEB_ISAC) { + char tmp[32]; + sprintf(tmp, "ph_command %d", command); + debugl1(sp, tmp); + } + writereg(sp->isac, ISAC_CIX0, (command << 2) | 3); +} + + +static inline void +isac_interrupt(struct IsdnCardState *sp, byte val) +{ + byte exval; + unsigned int count; + char tmp[32]; + + if (sp->debug & L1_DEB_ISAC) { + sprintf(tmp, "ISAC interrupt %x", val); + debugl1(sp, tmp); + } + if (val & 0x80) { /* RME */ + exval = readreg(sp->isac, ISAC_RSTA); + if ((exval & 0x70) != 0x20) { + if (exval & 0x40) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RDO"); + if (!exval & 0x20) + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC CRC error"); + if (sp->rcvibh) + BufPoolRelease(sp->rcvibh); + sp->rcvibh = NULL; + writereg(sp->isac, ISAC_CMDR, 0x80); + goto afterRME; + } + if (!sp->rcvibh) + if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool), + GFP_ATOMIC, (void *) 1, 3)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RME out of buffers!"); + writereg(sp->isac, ISAC_CMDR, 0x80); + goto afterRME; + } else + sp->rcvptr = 0; + count = readreg(sp->isac, ISAC_RBCL) & 0x1f; + if (count == 0) + count = 32; + isac_empty_fifo(sp, count); + sp->rcvibh->datasize = sp->rcvptr; + BufQueueLink(&(sp->rq), sp->rcvibh); + sp->rcvibh = NULL; + isac_sched_event(sp, ISAC_RCVBUFREADY); + } + afterRME: + if (val & 0x40) { /* RPF */ + if (!sp->rcvibh) + if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool), + GFP_ATOMIC, (void *) 1, 4)) { + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RME out of buffers!"); + writereg(sp->isac, ISAC_CMDR, 0x80); + goto afterRPF; + } else + sp->rcvptr = 0; + isac_empty_fifo(sp, 32); + } + afterRPF: + if (val & 0x20) { /* RSC */ + /* never */ + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC RSC interrupt"); + } + if (val & 0x10) { /* XPR */ + if (sp->xmtibh) + if (sp->xmtibh->datasize > sp->sendptr) { + isac_fill_fifo(sp); + goto afterXPR; + } else { + if (sp->releasebuf) + BufPoolRelease(sp->xmtibh); + sp->xmtibh = NULL; + sp->sendptr = 0; + } + if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) { + sp->releasebuf = !0; + isac_fill_fifo(sp); + } else + isac_sched_event(sp, ISAC_XMTBUFREADY); + } + afterXPR: + if (val & 0x04) { /* CISQ */ + sp->ph_state = (readreg(sp->isac, ISAC_CIX0) >> 2) + & 0xf; + if (sp->debug & L1_DEB_ISAC) { + sprintf(tmp, "l1state %d", sp->ph_state); + debugl1(sp, tmp); + } + isac_new_ph(sp); + } + if (val & 0x02) { /* SIN */ + /* never */ + if (sp->debug & L1_DEB_WARN) + debugl1(sp, "ISAC SIN interrupt"); + } + if (val & 0x01) { /* EXI */ + exval = readreg(sp->isac, ISAC_EXIR); + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "ISAC EXIR %02x", exval); + debugl1(sp, tmp); + } + } +} + +static inline void +hscx_int_main(struct IsdnCardState *sp, byte val) +{ + + byte exval; + struct HscxState *hsp; + char tmp[32]; + + + if (val & 0x01) { + hsp = sp->hs + 1; + exval = readreg(sp->hscx[1], HSCX_EXIR); + if (exval == 0x40) { + if (hsp->mode == 1) + hscx_fill_fifo(hsp); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + hsp->sendptr = 0; + writehscxCMDR(sp->hscx[hsp->hscx], 0x01); + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "HSCX B EXIR %x Lost TX", exval); + debugl1(sp, tmp); + } + } + } else if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX B EXIR %x", exval); + debugl1(sp, tmp); + } + } + if (val & 0xf8) { + if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX B interrupt %x", val); + debugl1(sp, tmp); + } + hscx_interrupt(sp, val, 1); + } + if (val & 0x02) { + hsp = sp->hs; + exval = readreg(sp->hscx[0], HSCX_EXIR); + if (exval == 0x40) { + if (hsp->mode == 1) + hscx_fill_fifo(hsp); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + hsp->sendptr = 0; + writehscxCMDR(sp->hscx[hsp->hscx], 0x01); + if (sp->debug & L1_DEB_WARN) { + sprintf(tmp, "HSCX A EXIR %x Lost TX", exval); + debugl1(sp, tmp); + } + } + } else if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX A EXIR %x", exval); + debugl1(sp, tmp); + } + } + if (val & 0x04) { + exval = readreg(sp->hscx[0], HSCX_ISTA); + if (sp->debug & L1_DEB_HSCX) { + sprintf(tmp, "HSCX A interrupt %x", exval); + debugl1(sp, tmp); + } + hscx_interrupt(sp, exval, 0); + } +} + +static void +teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *sp; + byte val, stat = 0; + + sp = (struct IsdnCardState *) irq2dev_map[intno]; + + if (!sp) { + printk(KERN_WARNING "Teles: Spurious interrupt!\n"); + return; + } + val = readreg(sp->hscx[1], HSCX_ISTA); + Start_HSCX: + if (val) { + hscx_int_main(sp, val); + stat |= 1; + } + val = readreg(sp->isac, ISAC_ISTA); + Start_ISAC: + if (val) { + isac_interrupt(sp, val); + stat |= 2; + } + val = readreg(sp->hscx[1], HSCX_ISTA); + if (val) { + if (sp->debug & L1_DEB_HSCX) + debugl1(sp, "HSCX IntStat after IntRoutine"); + goto Start_HSCX; + } + val = readreg(sp->isac, ISAC_ISTA); + if (val) { + if (sp->debug & L1_DEB_ISAC) + debugl1(sp, "ISAC IntStat after IntRoutine"); + goto Start_ISAC; + } + if (stat & 1) { + writereg(sp->hscx[0], HSCX_MASK, 0xFF); + writereg(sp->hscx[1], HSCX_MASK, 0xFF); + writereg(sp->hscx[0], HSCX_MASK, 0x0); + writereg(sp->hscx[1], HSCX_MASK, 0x0); + } + if (stat & 2) { + writereg(sp->isac, ISAC_MASK, 0xFF); + writereg(sp->isac, ISAC_MASK, 0x0); + } +} + + +static void +initisac(struct IsdnCardState *sp) +{ + unsigned int adr = sp->isac; + + /* 16.3 IOM 2 Mode */ + writereg(adr, ISAC_MASK, 0xff); + writereg(adr, ISAC_ADF2, 0x80); + writereg(adr, ISAC_SQXR, 0x2f); + writereg(adr, ISAC_SPCR, 0x0); + writereg(adr, ISAC_ADF1, 0x2); + writereg(adr, ISAC_STCR, 0x70); + writereg(adr, ISAC_MODE, 0xc9); + writereg(adr, ISAC_TIMR, 0x0); + writereg(adr, ISAC_ADF1, 0x0); + writereg(adr, ISAC_CMDR, 0x41); + writereg(adr, ISAC_CIX0, (1 << 2) | 3); + writereg(adr, ISAC_MASK, 0xff); + writereg(adr, ISAC_MASK, 0x0); +} + +static void +modehscx(struct HscxState *hs, int mode, int ichan) +{ + struct IsdnCardState *sp = hs->sp; + int hscx = hs->hscx; + + if (sp->debug & L1_DEB_HSCX) { + char tmp[40]; + sprintf(tmp, "hscx %c mode %d ichan %d", + 'A' + hscx, mode, ichan); + debugl1(sp, tmp); + } + hs->mode = mode; + writereg(sp->hscx[hscx], HSCX_CCR1, 0x85); + writereg(sp->hscx[hscx], HSCX_XAD1, 0xFF); + writereg(sp->hscx[hscx], HSCX_XAD2, 0xFF); + writereg(sp->hscx[hscx], HSCX_RAH2, 0xFF); + writereg(sp->hscx[hscx], HSCX_XBCH, 0x0); + writereg(sp->hscx[hscx], HSCX_RLCR, 0x0); + + switch (mode) { + case (0): + writereg(sp->hscx[hscx], HSCX_CCR2, 0x30); + writereg(sp->hscx[hscx], HSCX_TSAX, 0xff); + writereg(sp->hscx[hscx], HSCX_TSAR, 0xff); + writereg(sp->hscx[hscx], HSCX_XCCR, 7); + writereg(sp->hscx[hscx], HSCX_RCCR, 7); + writereg(sp->hscx[hscx], HSCX_MODE, 0x84); + break; + case (1): + if (ichan == 0) { + writereg(sp->hscx[hscx], HSCX_CCR2, 0x30); + writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f); + writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f); + writereg(sp->hscx[hscx], HSCX_XCCR, 7); + writereg(sp->hscx[hscx], HSCX_RCCR, 7); + } else { + writereg(sp->hscx[hscx], HSCX_CCR2, 0x30); + writereg(sp->hscx[hscx], HSCX_TSAX, 0x3); + writereg(sp->hscx[hscx], HSCX_TSAR, 0x3); + writereg(sp->hscx[hscx], HSCX_XCCR, 7); + writereg(sp->hscx[hscx], HSCX_RCCR, 7); + } + writereg(sp->hscx[hscx], HSCX_MODE, 0xe4); + writereg(sp->hscx[hscx], HSCX_CMDR, 0x41); + break; + case (2): + if (ichan == 0) { + writereg(sp->hscx[hscx], HSCX_CCR2, 0x30); + writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f); + writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f); + writereg(sp->hscx[hscx], HSCX_XCCR, 7); + writereg(sp->hscx[hscx], HSCX_RCCR, 7); + } else { + writereg(sp->hscx[hscx], HSCX_CCR2, 0x30); + writereg(sp->hscx[hscx], HSCX_TSAX, 0x3); + writereg(sp->hscx[hscx], HSCX_TSAR, 0x3); + writereg(sp->hscx[hscx], HSCX_XCCR, 7); + writereg(sp->hscx[hscx], HSCX_RCCR, 7); + } + writereg(sp->hscx[hscx], HSCX_MODE, 0x8c); + writereg(sp->hscx[hscx], HSCX_CMDR, 0x41); + break; + } + writereg(sp->hscx[hscx], HSCX_ISTA, 0x00); +} + +inline static void +release_ioregs(struct IsdnCard *card, int mask) +{ + if (mask & 1) + release_region(card->sp->isac, 32); + if (mask & 2) + release_region(card->sp->hscx[0], 32); + if (mask & 4) + release_region(card->sp->hscx[1], 32); +} + +void +release_io_teles3(struct IsdnCard *card) +{ + if (card->sp->typ == ISDN_CTYPE_TELESPCMCIA) + release_region(card->sp->hscx[0], 97); + else { + if (card->sp->cfg_reg) + release_region(card->sp->cfg_reg, 8); + release_ioregs(card, 0x7); + } +} + +static void +clear_pending_ints(struct IsdnCardState *sp) +{ + int val; + char tmp[64]; + + val = readreg(sp->hscx[1], HSCX_ISTA); + sprintf(tmp, "HSCX B ISTA %x", val); + debugl1(sp, tmp); + if (val & 0x01) { + val = readreg(sp->hscx[1], HSCX_EXIR); + sprintf(tmp, "HSCX B EXIR %x", val); + debugl1(sp, tmp); + } else if (val & 0x02) { + val = readreg(sp->hscx[0], HSCX_EXIR); + sprintf(tmp, "HSCX A EXIR %x", val); + debugl1(sp, tmp); + } + val = readreg(sp->hscx[0], HSCX_ISTA); + sprintf(tmp, "HSCX A ISTA %x", val); + debugl1(sp, tmp); + val = readreg(sp->hscx[1], HSCX_STAR); + sprintf(tmp, "HSCX B STAR %x", val); + debugl1(sp, tmp); + val = readreg(sp->hscx[0], HSCX_STAR); + sprintf(tmp, "HSCX A STAR %x", val); + debugl1(sp, tmp); + val = readreg(sp->isac, ISAC_STAR); + sprintf(tmp, "ISAC STAR %x", val); + debugl1(sp, tmp); + val = readreg(sp->isac, ISAC_MODE); + sprintf(tmp, "ISAC MODE %x", val); + debugl1(sp, tmp); + val = readreg(sp->isac, ISAC_ADF2); + sprintf(tmp, "ISAC ADF2 %x", val); + debugl1(sp, tmp); + val = readreg(sp->isac, ISAC_ISTA); + sprintf(tmp, "ISAC ISTA %x", val); + debugl1(sp, tmp); + if (val & 0x01) { + val = readreg(sp->isac, ISAC_EXIR); + sprintf(tmp, "ISAC EXIR %x", val); + debugl1(sp, tmp); + } else if (val & 0x04) { + val = readreg(sp->isac, ISAC_CIR0); + sprintf(tmp, "ISAC CIR0 %x", val); + debugl1(sp, tmp); + } + writereg(sp->isac, ISAC_MASK, 0); + writereg(sp->isac, ISAC_CMDR, 0x41); +} + +int +initteles3(struct IsdnCardState *sp) +{ + int ret; + char tmp[40]; + + sp->counter = kstat.interrupts[sp->irq]; + sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter); + debugl1(sp, tmp); + clear_pending_ints(sp); + ret = get_irq(sp->cardnr, &teles3_interrupt); + if (ret) { + initisac(sp); + sp->modehscx(sp->hs, 0, 0); + sp->modehscx(sp->hs + 1, 0, 0); + sprintf(tmp, "IRQ %d count %d", sp->irq, + kstat.interrupts[sp->irq]); + debugl1(sp, tmp); + if (kstat.interrupts[sp->irq] == sp->counter) { + printk(KERN_WARNING + "Teles3: IRQ(%d) getting no interrupts during init\n", + sp->irq); + irq2dev_map[sp->irq] = NULL; + free_irq(sp->irq, NULL); + return (0); + } + } + return (ret); +} + +int +setup_teles3(struct IsdnCard *card) +{ + byte cfval = 0, val, verA, verB; + struct IsdnCardState *sp = card->sp; + long flags; + char tmp[64]; + + strcpy(tmp, teles3_revision); + printk(KERN_NOTICE "HiSax: Teles IO driver Rev. %s\n", HiSax_getrev(tmp)); + if ((sp->typ != ISDN_CTYPE_16_3) && (sp->typ != ISDN_CTYPE_PNP) + && (sp->typ != ISDN_CTYPE_TELESPCMCIA)) + return (0); + + if (sp->typ == ISDN_CTYPE_16_3) { + sp->cfg_reg = card->para[1]; + switch (sp->cfg_reg) { + case 0x180: + case 0x280: + case 0x380: + sp->cfg_reg |= 0xc00; + break; + } + sp->isac = sp->cfg_reg - 0x400; + sp->hscx[0] = sp->cfg_reg - 0xc00; + sp->hscx[1] = sp->cfg_reg - 0x800; + } else if (sp->typ == ISDN_CTYPE_TELESPCMCIA) { + sp->cfg_reg = 0; + sp->hscx[0] = card->para[1]; + sp->hscx[1] = card->para[1] + 0x20; + sp->isac = card->para[1] + 0x40; + } else { /* PNP */ + sp->cfg_reg = 0; + sp->isac = card->para[1]; + sp->hscx[0] = card->para[2]; + sp->hscx[1] = card->para[2] + 0x20; + } + sp->irq = card->para[0]; + if (sp->typ == ISDN_CTYPE_TELESPCMCIA) { + if (check_region((sp->hscx[0]), 97)) { + printk(KERN_WARNING + "HiSax: %s ports %x-%x already in use\n", + CardType[sp->typ], + sp->hscx[0], + sp->hscx[0] + 96); + return (0); + } else + request_region(sp->hscx[0], 97, "HiSax Teles PCMCIA"); + } else { + if (sp->cfg_reg) { + if (check_region((sp->cfg_reg), 8)) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + sp->cfg_reg, + sp->cfg_reg + 8); + return (0); + } else { + request_region(sp->cfg_reg, 8, "teles3 cfg"); + } + } + if (check_region((sp->isac), 32)) { + printk(KERN_WARNING + "HiSax: %s isac ports %x-%x already in use\n", + CardType[sp->typ], + sp->isac, + sp->isac + 32); + if (sp->cfg_reg) { + release_region(sp->cfg_reg, 8); + } + return (0); + } else { + request_region(sp->isac, 32, "HiSax isac"); + } + if (check_region((sp->hscx[0]), 32)) { + printk(KERN_WARNING + "HiSax: %s hscx A ports %x-%x already in use\n", + CardType[sp->typ], + sp->hscx[0], + sp->hscx[0] + 32); + if (sp->cfg_reg) { + release_region(sp->cfg_reg, 8); + } + release_ioregs(card, 1); + return (0); + } else { + request_region(sp->hscx[0], 32, "HiSax hscx A"); + } + if (check_region((sp->hscx[1]), 32)) { + printk(KERN_WARNING + "HiSax: %s hscx B ports %x-%x already in use\n", + CardType[sp->typ], + sp->hscx[1], + sp->hscx[1] + 32); + if (sp->cfg_reg) { + release_region(sp->cfg_reg, 8); + } + release_ioregs(card, 3); + return (0); + } else { + request_region(sp->hscx[1], 32, "HiSax hscx B"); + } + switch (sp->irq) { + case 2: + cfval = 0x00; + break; + case 3: + cfval = 0x02; + break; + case 4: + cfval = 0x04; + break; + case 5: + cfval = 0x06; + break; + case 10: + cfval = 0x08; + break; + case 11: + cfval = 0x0A; + break; + case 12: + cfval = 0x0C; + break; + case 15: + cfval = 0x0E; + break; + default: + cfval = 0x00; + break; + } + } + if (sp->cfg_reg) { + if ((val = bytein(sp->cfg_reg + 0)) != 0x51) { + printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n", + sp->cfg_reg + 0, val); + release_io_teles3(card); + return (0); + } + if ((val = bytein(sp->cfg_reg + 1)) != 0x93) { + printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n", + sp->cfg_reg + 1, val); + release_io_teles3(card); + return (0); + } + val = bytein(sp->cfg_reg + 2); /* 0x1e=without AB + * 0x1f=with AB + * 0x1c 16.3 ??? + */ + if (val != 0x1c && val != 0x1e && val != 0x1f) { + printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n", + sp->cfg_reg + 2, val); + release_io_teles3(card); + return (0); + } + save_flags(flags); + byteout(sp->cfg_reg + 4, cfval); + sti(); + HZDELAY(HZ / 10 + 1); + byteout(sp->cfg_reg + 4, cfval | 1); + HZDELAY(HZ / 10 + 1); + restore_flags(flags); + } else { + /* Reset off for 16.3 PnP , thanks to Georg Acher */ + save_flags(flags); + byteout(sp->isac + 0x1c, 1); + HZDELAY(2); + restore_flags(flags); + } + printk(KERN_NOTICE + "HiSax: %s config irq:%d isac:%x cfg:%x\n", + CardType[sp->typ], sp->irq, + sp->isac, sp->cfg_reg); + printk(KERN_NOTICE + "HiSax: hscx A:%x hscx B:%x\n", + sp->hscx[0], sp->hscx[1]); + verA = readreg(sp->hscx[0], HSCX_VSTR) & 0xf; + verB = readreg(sp->hscx[1], HSCX_VSTR) & 0xf; + printk(KERN_INFO "Teles3: HSCX version A: %s B: %s\n", + HscxVersion(verA), HscxVersion(verB)); + val = readreg(sp->isac, ISAC_RBCH); + printk(KERN_INFO "Teles3: ISAC %s\n", + ISACVersion(val)); + if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) { + printk(KERN_WARNING + "Teles3: wrong HSCX versions check IO address\n"); + release_io_teles3(card); + return (0); + } + sp->modehscx = &modehscx; + sp->ph_command = &ph_command; + sp->hscx_fill_fifo = &hscx_fill_fifo; + sp->isac_fill_fifo = &isac_fill_fifo; + return (1); +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/hisax/teles3.h linux/drivers/isdn/hisax/teles3.h --- v2.1.26/linux/drivers/isdn/hisax/teles3.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/teles3.h Tue Feb 25 17:12:49 1997 @@ -0,0 +1,21 @@ +/* $Id: teles3.h,v 1.2 1997/01/21 22:27:14 keil Exp $ + * + * teles3.h Header for Teles 16.3 PNP & compatible + * + * Author Karsten Keil (keil@temic-ech.spacenet.de) + * + * + * $Log: teles3.h,v $ + * Revision 1.2 1997/01/21 22:27:14 keil + * cleanups + * + * Revision 1.1 1996/10/13 20:03:49 keil + * Initial revision + * + * +*/ + +extern void teles3_report(struct IsdnCardState *sp); +extern void release_io_teles3(struct IsdnCard *card); +extern int setup_teles3(struct IsdnCard *card); +extern int initteles3(struct IsdnCardState *sp); diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c --- v2.1.26/linux/drivers/isdn/icn/icn.c Fri Dec 27 02:03:22 1996 +++ linux/drivers/isdn/icn/icn.c Tue Feb 25 17:12:49 1997 @@ -1,5 +1,5 @@ -/* $Id: icn.c,v 1.29 1996/08/29 20:34:54 fritz Exp $ - * +/* $Id: icn.c,v 1.38 1997/02/11 18:29:31 fritz Exp $ + * ISDN low-level module for the ICN active ISDN-Card. * * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) @@ -19,6 +19,36 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.c,v $ + * Revision 1.38 1997/02/11 18:29:31 fritz + * Bugfix in D64S initialization. + * + * Revision 1.37 1997/02/10 22:43:20 fritz + * Added plan and screen elements on ISDN_STAT_ICALL + * + * Revision 1.36 1997/02/10 21:31:20 fritz + * Changed setup-interface (incoming and outgoing). + * + * Revision 1.35 1997/02/10 10:10:28 fritz + * Changes for Kernel 2.1.X compatibility. + * Enhanced initialization, can recover from + * misconfiguration by other autoprobing drivers. + * + * Revision 1.34 1997/01/29 22:34:44 fritz + * Cleanup, Corrected D64S setup of 2nd channel. + * + * Revision 1.33 1996/12/05 20:31:48 tsbogend + * added handling of L2: DATA LINK LOST messages + * + * Revision 1.32 1996/11/14 23:49:18 fritz + * Bugfix: copy_to_user/copy_from_user mismatch in debugging-ioctl. + * + * Revision 1.31 1996/11/13 02:36:25 fritz + * Fixed a race condition in writecmd. + * Some optimizations and cleanup. + * + * Revision 1.30 1996/10/22 23:14:09 fritz + * Changes for compatibility to 2.0.X and 2.1.X kernels. + * * Revision 1.29 1996/08/29 20:34:54 fritz * Bugfix in send queue management: * sndcount was not updated correctly. @@ -141,7 +171,7 @@ #undef MAP_DEBUG static char -*revision = "$Revision: 1.29 $"; +*revision = "$Revision: 1.38 $"; static int icn_addcard(int, char *, char *); @@ -150,16 +180,13 @@ * Parameter: * queue = pointer to queue-head */ -static void icn_free_queue(struct sk_buff_head *queue) +static void +icn_free_queue(struct sk_buff_head *queue) { - struct sk_buff *skb; - unsigned long flags; + struct sk_buff *skb; - save_flags(flags); - cli(); - while ((skb = skb_dequeue(queue))) - dev_kfree_skb(skb, FREE_WRITE); - restore_flags(flags); + while ((skb = skb_dequeue(queue))) + dev_kfree_skb(skb, FREE_WRITE); } /* Put a value into a shift-register, highest bit first. @@ -169,53 +196,57 @@ * firstbit = Bit-Number of highest bit * bitcount = Number of bits to output */ -static inline void icn_shiftout(unsigned short port, - unsigned long val, - int firstbit, - int bitcount) +static inline void +icn_shiftout(unsigned short port, + unsigned long val, + int firstbit, + int bitcount) { - register u_char s; - register u_char c; + register u_char s; + register u_char c; - for (s = firstbit, c = bitcount; c > 0; s--, c--) - OUTB_P((u_char) ((val >> s) & 1) ? 0xff : 0, port); + for (s = firstbit, c = bitcount; c > 0; s--, c--) + OUTB_P((u_char) ((val >> s) & 1) ? 0xff : 0, port); } /* * disable a cards shared memory */ -static inline void icn_disable_ram(icn_card *card) +static inline void +icn_disable_ram(icn_card * card) { - OUTB_P(0, ICN_MAPRAM); + OUTB_P(0, ICN_MAPRAM); } /* * enable a cards shared memory */ -static inline void icn_enable_ram(icn_card *card) +static inline void +icn_enable_ram(icn_card * card) { - OUTB_P(0xff, ICN_MAPRAM); + OUTB_P(0xff, ICN_MAPRAM); } /* * Map a cards channel0 (Bank0/Bank8) or channel1 (Bank4/Bank12) */ -static inline void icn_map_channel(icn_card *card, int channel) +static inline void +icn_map_channel(icn_card * card, int channel) { #ifdef MAP_DEBUG - printk(KERN_DEBUG "icn_map_channel %d %d\n", dev->channel, channel); + printk(KERN_DEBUG "icn_map_channel %d %d\n", dev->channel, channel); #endif - if ((channel == dev.channel) && (card == dev.mcard)) - return; - if (dev.mcard) - icn_disable_ram(dev.mcard); - icn_shiftout(ICN_BANK, chan2bank[channel], 3, 4); /* Select Bank */ - icn_enable_ram(card); - dev.mcard = card; - dev.channel = channel; + if ((channel == dev.channel) && (card == dev.mcard)) + return; + if (dev.mcard) + icn_disable_ram(dev.mcard); + icn_shiftout(ICN_BANK, chan2bank[channel], 3, 4); /* Select Bank */ + icn_enable_ram(card); + dev.mcard = card; + dev.channel = channel; #ifdef MAP_DEBUG - printk(KERN_DEBUG "icn_map_channel done\n"); + printk(KERN_DEBUG "icn_map_channel done\n"); #endif } @@ -224,98 +255,102 @@ * Return 0 if requested card/channel is unmapped (failure). * Return 1 on success. */ -static inline int icn_lock_channel(icn_card *card, int channel) +static inline int +icn_lock_channel(icn_card * card, int channel) { - register int retval; - ulong flags; + register int retval; + ulong flags; #ifdef MAP_DEBUG - printk(KERN_DEBUG "icn_lock_channel %d\n", channel); + printk(KERN_DEBUG "icn_lock_channel %d\n", channel); #endif - save_flags(flags); - cli(); - if ((dev.channel == channel) && (card == dev.mcard)) { - dev.chanlock++; - retval = 1; + save_flags(flags); + cli(); + if ((dev.channel == channel) && (card == dev.mcard)) { + dev.chanlock++; + retval = 1; #ifdef MAP_DEBUG - printk(KERN_DEBUG "icn_lock_channel %d OK\n", channel); + printk(KERN_DEBUG "icn_lock_channel %d OK\n", channel); #endif - } else { - retval = 0; + } else { + retval = 0; #ifdef MAP_DEBUG - printk(KERN_DEBUG "icn_lock_channel %d FAILED, dc=%d\n", channel, device->channel); + printk(KERN_DEBUG "icn_lock_channel %d FAILED, dc=%d\n", channel, device->channel); #endif - } - restore_flags(flags); - return retval; + } + restore_flags(flags); + return retval; } /* * Release current card/channel lock */ -static inline void icn_release_channel(void) +static inline void +icn_release_channel(void) { - ulong flags; + ulong flags; #ifdef MAP_DEBUG - printk(KERN_DEBUG "icn_release_channel l=%d\n", device->chanlock); + printk(KERN_DEBUG "icn_release_channel l=%d\n", device->chanlock); #endif - save_flags(flags); - cli(); - if (dev.chanlock) - dev.chanlock--; - restore_flags(flags); + save_flags(flags); + cli(); + if (dev.chanlock > 0) + dev.chanlock--; + restore_flags(flags); } /* * Try to map and lock a cards channel. * Return 1 on success, 0 on failure. */ -static inline int icn_trymaplock_channel(icn_card *card, int channel) +static inline int +icn_trymaplock_channel(icn_card * card, int channel) { - ulong flags; + ulong flags; - save_flags(flags); - cli(); #ifdef MAP_DEBUG - printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev.channel, - dev.chanlock); + printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev.channel, + dev.chanlock); #endif - if ((!dev.chanlock) || - ((dev.channel == channel) && (dev.mcard == card))) { - dev.chanlock++; - icn_map_channel(card,channel); - restore_flags(flags); + save_flags(flags); + cli(); + if ((!dev.chanlock) || + ((dev.channel == channel) && (dev.mcard == card))) { + dev.chanlock++; + icn_map_channel(card, channel); + restore_flags(flags); #ifdef MAP_DEBUG - printk(KERN_DEBUG "trymaplock %d OK\n", channel); + printk(KERN_DEBUG "trymaplock %d OK\n", channel); #endif - return 1; - } - restore_flags(flags); + return 1; + } + restore_flags(flags); #ifdef MAP_DEBUG - printk(KERN_DEBUG "trymaplock %d FAILED\n", channel); + printk(KERN_DEBUG "trymaplock %d FAILED\n", channel); #endif - return 0; + return 0; } /* * Release current card/channel lock, * then map same or other channel without locking. */ -static inline void icn_maprelease_channel(icn_card *card, int channel) +static inline void +icn_maprelease_channel(icn_card * card, int channel) { - ulong flags; + ulong flags; - save_flags(flags); - cli(); #ifdef MAP_DEBUG - printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev.chanlock); + printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev.chanlock); #endif - if (dev.chanlock) - dev.chanlock--; - if (!dev.chanlock) - icn_map_channel(card,channel); - restore_flags(flags); + save_flags(flags); + cli(); + if (dev.chanlock > 0) + dev.chanlock--; + if (!dev.chanlock) + icn_map_channel(card, channel); + restore_flags(flags); } /* Get Data from the B-Channel, assemble fragmented packets and put them @@ -323,47 +358,48 @@ * This routine is called via timer-callback from icn_pollbchan(). */ -static void icn_pollbchan_receive(int channel, icn_card *card) +static void +icn_pollbchan_receive(int channel, icn_card * card) { - int mch = channel + ((card->secondhalf) ? 2 : 0); - int eflag; - int cnt; + int mch = channel + ((card->secondhalf) ? 2 : 0); + int eflag; + int cnt; struct sk_buff *skb; - if (icn_trymaplock_channel(card,mch)) { - while (rbavl) { - cnt = readb(&rbuf_l); - if ((card->rcvidx[channel] + cnt) > 4000) { - printk(KERN_WARNING - "icn: (%s) bogus packet on ch%d, dropping.\n", - CID, - channel + 1); - card->rcvidx[channel] = 0; - eflag = 0; - } else { - memcpy_fromio(&card->rcvbuf[channel][card->rcvidx[channel]], - &rbuf_d, cnt); - card->rcvidx[channel] += cnt; - eflag = readb(&rbuf_f); - } - rbnext; - icn_maprelease_channel(card, mch & 2); - if (!eflag) { - if ((cnt = card->rcvidx[channel])) { - if (!(skb = dev_alloc_skb(cnt))) { - printk(KERN_WARNING "ïcn: receive out of memory\n"); - break; - } - memcpy(skb_put(skb, cnt), card->rcvbuf[channel], cnt); - card->rcvidx[channel] = 0; - card->interface.rcvcallb_skb(card->myid, channel, skb); - } - } - if (!icn_trymaplock_channel(card, mch)) - break; - } - icn_maprelease_channel(card, mch & 2); - } + if (icn_trymaplock_channel(card, mch)) { + while (rbavl) { + cnt = readb(&rbuf_l); + if ((card->rcvidx[channel] + cnt) > 4000) { + printk(KERN_WARNING + "icn: (%s) bogus packet on ch%d, dropping.\n", + CID, + channel + 1); + card->rcvidx[channel] = 0; + eflag = 0; + } else { + memcpy_fromio(&card->rcvbuf[channel][card->rcvidx[channel]], + &rbuf_d, cnt); + card->rcvidx[channel] += cnt; + eflag = readb(&rbuf_f); + } + rbnext; + icn_maprelease_channel(card, mch & 2); + if (!eflag) { + if ((cnt = card->rcvidx[channel])) { + if (!(skb = dev_alloc_skb(cnt))) { + printk(KERN_WARNING "ïcn: receive out of memory\n"); + break; + } + memcpy(skb_put(skb, cnt), card->rcvbuf[channel], cnt); + card->rcvidx[channel] = 0; + card->interface.rcvcallb_skb(card->myid, channel, skb); + } + } + if (!icn_trymaplock_channel(card, mch)) + break; + } + icn_maprelease_channel(card, mch & 2); + } } /* Send data-packet to B-Channel, split it up into fragments of @@ -373,56 +409,59 @@ * directly from icn_sendbuf(). */ -static void icn_pollbchan_send(int channel, icn_card *card) +static void +icn_pollbchan_send(int channel, icn_card * card) { - int mch = channel + ((card->secondhalf) ? 2 : 0); - int cnt; + int mch = channel + ((card->secondhalf) ? 2 : 0); + int cnt; unsigned long flags; - struct sk_buff *skb; - isdn_ctrl cmd; + struct sk_buff *skb; + isdn_ctrl cmd; - if (!card->sndcount[channel]) - return; - if (icn_trymaplock_channel(card,mch)) { - while (sbfree && card->sndcount[channel]) { - save_flags(flags); - cli(); - if (card->xmit_lock[channel]) { - restore_flags(flags); - break; - } - card->xmit_lock[channel]++; - restore_flags(flags); - skb = skb_dequeue(&card->spqueue[channel]); - if (!skb) - break; - if (skb->len > ICN_FRAGSIZE) { - writeb (0xff, &sbuf_f); - cnt = ICN_FRAGSIZE; + if (!(card->sndcount[channel] || + skb_queue_len(&card->spqueue[channel]))) + return; + if (icn_trymaplock_channel(card, mch)) { + while (sbfree && (card->sndcount[channel] || + skb_queue_len(&card->spqueue[channel]))) { + save_flags(flags); + cli(); + if (card->xmit_lock[channel]) { + restore_flags(flags); + break; + } + card->xmit_lock[channel]++; + restore_flags(flags); + skb = skb_dequeue(&card->spqueue[channel]); + if (!skb) + break; + if (skb->len > ICN_FRAGSIZE) { + writeb(0xff, &sbuf_f); + cnt = ICN_FRAGSIZE; } else { - writeb (0x0, &sbuf_f); - cnt = skb->len; + writeb(0x0, &sbuf_f); + cnt = skb->len; } - writeb (cnt, &sbuf_l); - memcpy_toio(&sbuf_d, skb->data, cnt); - skb_pull(skb, cnt); - card->sndcount[channel] -= cnt; - sbnext; /* switch to next buffer */ - icn_maprelease_channel(card, mch & 2); - if (!skb->len) { - dev_kfree_skb(skb, FREE_WRITE); - cmd.command = ISDN_STAT_BSENT; - cmd.driver = card->myid; - cmd.arg = channel; - card->interface.statcallb(&cmd); - } else - skb_queue_head(&card->spqueue[channel], skb); - card->xmit_lock[channel] = 0; - if (!icn_trymaplock_channel(card, mch)) - break; - } - icn_maprelease_channel(card, mch & 2); - } + writeb(cnt, &sbuf_l); + memcpy_toio(&sbuf_d, skb->data, cnt); + skb_pull(skb, cnt); + card->sndcount[channel] -= cnt; + sbnext; /* switch to next buffer */ + icn_maprelease_channel(card, mch & 2); + if (!skb->len) { + dev_kfree_skb(skb, FREE_WRITE); + cmd.command = ISDN_STAT_BSENT; + cmd.driver = card->myid; + cmd.arg = channel; + card->interface.statcallb(&cmd); + } else + skb_queue_head(&card->spqueue[channel], skb); + card->xmit_lock[channel] = 0; + if (!icn_trymaplock_channel(card, mch)) + break; + } + icn_maprelease_channel(card, mch & 2); + } } /* Send/Receive Data to/from the B-Channel. @@ -430,54 +469,59 @@ * It schedules itself while any B-Channel is open. */ -static void icn_pollbchan(unsigned long data) +static void +icn_pollbchan(unsigned long data) { - icn_card *card = (icn_card *)data; - unsigned long flags; + icn_card *card = (icn_card *) data; + unsigned long flags; - if (card->flags & ICN_FLAGS_B1ACTIVE) { - icn_pollbchan_receive(0, card); - icn_pollbchan_send(0, card); - } - if (card->flags & ICN_FLAGS_B2ACTIVE) { - icn_pollbchan_receive(1, card); - icn_pollbchan_send(1, card); - } - if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) { - /* schedule b-channel polling again */ - save_flags(flags); - cli(); - del_timer(&card->rb_timer); - card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD; - add_timer(&card->rb_timer); - card->flags |= ICN_FLAGS_RBTIMER; - restore_flags(flags); - } else - card->flags &= ~ICN_FLAGS_RBTIMER; + if (card->flags & ICN_FLAGS_B1ACTIVE) { + icn_pollbchan_receive(0, card); + icn_pollbchan_send(0, card); + } + if (card->flags & ICN_FLAGS_B2ACTIVE) { + icn_pollbchan_receive(1, card); + icn_pollbchan_send(1, card); + } + if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) { + /* schedule b-channel polling again */ + save_flags(flags); + cli(); + del_timer(&card->rb_timer); + card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD; + add_timer(&card->rb_timer); + card->flags |= ICN_FLAGS_RBTIMER; + restore_flags(flags); + } else + card->flags &= ~ICN_FLAGS_RBTIMER; } typedef struct icn_stat { - char *statstr; - int command; - int action; + char *statstr; + int command; + int action; } icn_stat; -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 */ - {"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 */ - {"CIF", ISDN_STAT_CINF, 5}, /* Charge-info, 1TR6-type */ - {"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */ - {"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */ - {"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */ - {"NO D-CHAN", ISDN_STAT_NODCH, 0}, /* No D-channel available */ - {"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */ - {NULL, 0 , -1} +/* *INDENT-OFF* */ +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 */ + {"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 */ + {"CIF", ISDN_STAT_CINF, 5}, /* Charge-info, 1TR6-type */ + {"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */ + {"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */ + {"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */ + {"NO D-CHAN", ISDN_STAT_NODCH, 0}, /* No D-channel available */ + {"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */ + {"E_L2: DATA LIN", ISDN_STAT_BHUP, 8}, /* Layer-2 data link lost */ + {NULL, 0, -1} }; +/* *INDENT-ON* */ /* * Check Statusqueue-Pointer from isdn-cards. @@ -489,192 +533,223 @@ * This routine is called periodically via timer. */ -static int icn_parse_status(u_char *status, int channel, icn_card *card) +static int +icn_parse_status(u_char * status, int channel, icn_card * card) { - icn_stat *s = icn_stat_table; - int action = -1; - int dflag = 0; - unsigned long flags; - isdn_ctrl cmd; - - while (s->statstr) { - if (!strncmp(status,s->statstr,strlen(s->statstr))) { - cmd.command = s->command; - action = s->action; - break; - } - s++; - } - if (action==-1) - return 0; - cmd.driver = card->myid; - cmd.arg = channel; - switch (action) { - case 1: - card->flags |= (channel)? - ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE; - break; - case 2: - card->flags &= ~((channel)? - ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE); - icn_free_queue(&card->spqueue[channel]); - save_flags(flags); - cli(); - card->rcvidx[channel] = 0; - restore_flags(flags); - dflag |= (channel+1); - break; - case 3: - strncpy(cmd.num, status + 6, sizeof(cmd.num) - 1); - break; - case 4: - sprintf(cmd.num,"LEASED%d,07,00,%d", - card->myid,channel+1); - break; - case 5: - strncpy(cmd.num, status + 3, sizeof(cmd.num) - 1); - break; - case 6: - sprintf(cmd.num,"%d", - (int)simple_strtoul(status + 7,NULL,16)); - break; - case 7: - status += 3; - if (strlen(status)==4) - sprintf(cmd.num,"%s%c%c", - status+2,*status,*(status+1)); - else - strncpy(cmd.num, status+1, sizeof(cmd.num) - 1); - break; - case 8: - cmd.arg = 0; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - cmd.command = ISDN_STAT_DHUP; - cmd.arg = 0; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - cmd.command = ISDN_STAT_BHUP; - cmd.arg = 1; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - cmd.command = ISDN_STAT_DHUP; - cmd.arg = 1; - cmd.driver = card->myid; - break; - } - card->interface.statcallb(&cmd); - return dflag; -} - -static void icn_polldchan(unsigned long data) -{ - icn_card *card = (icn_card *)data; - int mch = card->secondhalf ? 2 : 0; - int avail = 0; - int dflag = 0; - int left; - u_char c; - int ch; - int flags; - int i; - u_char *p; - isdn_ctrl cmd; - - if (icn_trymaplock_channel(card,mch)) { - avail = msg_avail; - for (left = avail, i = readb(&msg_o); left > 0; i++, left--) { - c = readb(&dev.shmem->comm_buffers.iopc_buf[i & 0xff]); - save_flags(flags); - cli(); - *card->msg_buf_write++ = (c == 0xff) ? '\n' : c; - if (card->msg_buf_write == card->msg_buf_read) { - if (++card->msg_buf_read > card->msg_buf_end) - card->msg_buf_read = card->msg_buf; - } - if (card->msg_buf_write > card->msg_buf_end) - card->msg_buf_write = card->msg_buf; - restore_flags(flags); - if (c == 0xff) { - card->imsg[card->iptr] = 0; - card->iptr = 0; - if (card->imsg[0] == '0' && card->imsg[1] >= '0' && - card->imsg[1] <= '2' && card->imsg[2] == ';') { - ch = (card->imsg[1] - '0') - 1; - p = &card->imsg[3]; - dflag |= icn_parse_status(p, ch, card); - } else { - p = card->imsg; - if (!strncmp(p, "DRV1.", 5)) { - u_char vstr[10]; - u_char *q = vstr; - - printk(KERN_INFO "icn: (%s) %s\n",CID,p); - if (!strncmp(p + 7, "TC", 2)) { - card->ptype = ISDN_PTYPE_1TR6; - card->interface.features |= ISDN_FEATURE_P_1TR6; - printk(KERN_INFO - "icn: (%s) 1TR6-Protocol loaded and running\n",CID); - } - if (!strncmp(p + 7, "EC", 2)) { - card->ptype = ISDN_PTYPE_EURO; - card->interface.features |= ISDN_FEATURE_P_EURO; - printk(KERN_INFO - "icn: (%s) Euro-Protocol loaded and running\n",CID); - } - p = strstr(card->imsg,"BRV") + 3; - while (*p) { - if (*p>='0' && *p<='9') - *q++ = *p; - p++; - } - *q = '\0'; - strcat(vstr,"000"); - vstr[3] = '\0'; - card->fw_rev = (int)simple_strtoul(vstr,NULL,10); - continue; - - } - } - } else { - card->imsg[card->iptr] = c; - if (card->iptr < 59) - card->iptr++; - } - } - writeb((readb(&msg_o) + avail) & 0xff, &msg_o); - icn_release_channel(); - } - if (avail) { - cmd.command = ISDN_STAT_STAVAIL; - cmd.driver = card->myid; - cmd.arg = avail; - card->interface.statcallb(&cmd); - } - if (dflag & 1) - card->interface.rcvcallb(card->myid, 0, card->rcvbuf[0], 0); - if (dflag & 2) - card->interface.rcvcallb(card->myid, 1, card->rcvbuf[1], 0); - if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) - if (!(card->flags & ICN_FLAGS_RBTIMER)) { - /* schedule b-channel polling */ - card->flags |= ICN_FLAGS_RBTIMER; - save_flags(flags); - cli(); - del_timer(&card->rb_timer); - card->rb_timer.function = icn_pollbchan; - card->rb_timer.data = (unsigned long)card; - card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD; - add_timer(&card->rb_timer); - restore_flags(flags); - } - /* schedule again */ - save_flags(flags); - cli(); - del_timer(&card->st_timer); - card->st_timer.expires = jiffies + ICN_TIMER_DCREAD; - add_timer(&card->st_timer); - restore_flags(flags); + icn_stat *s = icn_stat_table; + int action = -1; + int dflag = 0; + unsigned long flags; + isdn_ctrl cmd; + + while (s->statstr) { + if (!strncmp(status, s->statstr, strlen(s->statstr))) { + cmd.command = s->command; + action = s->action; + break; + } + s++; + } + if (action == -1) + return 0; + cmd.driver = card->myid; + cmd.arg = channel; + switch (action) { + case 1: + card->flags |= (channel) ? + ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE; + break; + case 2: + card->flags &= ~((channel) ? + ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE); + icn_free_queue(&card->spqueue[channel]); + save_flags(flags); + cli(); + card->rcvidx[channel] = 0; + restore_flags(flags); + dflag |= (channel + 1); + break; + case 3: + { + char *s = strtok(status + 6, ","); + strncpy(cmd.parm.setup.phone, s, sizeof(cmd.parm.setup.phone)); + s = strtok(NULL, ","); + if (!strlen(s)) + cmd.parm.setup.si1 = 0; + else + cmd.parm.setup.si1 = simple_strtoul(s, NULL, 10); + s = strtok(NULL, ","); + if (!strlen(s)) + cmd.parm.setup.si2 = 0; + else + cmd.parm.setup.si2 = simple_strtoul(s, NULL, 10); + s = strtok(NULL, ","); + strncpy(cmd.parm.setup.eazmsn, s, sizeof(cmd.parm.setup.eazmsn)); + } + cmd.parm.setup.plan = 0; + cmd.parm.setup.screen = 0; + break; + case 4: + sprintf(cmd.parm.setup.phone, "LEASED%d", card->myid); + sprintf(cmd.parm.setup.eazmsn, "%d", channel + 1); + cmd.parm.setup.si1 = 7; + cmd.parm.setup.si2 = 0; + cmd.parm.setup.plan = 0; + cmd.parm.setup.screen = 0; + break; + case 5: + strncpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num) - 1); + break; + case 6: + sprintf(cmd.parm.num, "%d", + (int) simple_strtoul(status + 7, NULL, 16)); + break; + case 7: + status += 3; + if (strlen(status) == 4) + sprintf(cmd.parm.num, "%s%c%c", + status + 2, *status, *(status + 1)); + else + strncpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num) - 1); + break; + case 8: + cmd.arg = 0; + cmd.driver = card->myid; + card->interface.statcallb(&cmd); + cmd.command = ISDN_STAT_DHUP; + cmd.arg = 0; + cmd.driver = card->myid; + card->interface.statcallb(&cmd); + cmd.command = ISDN_STAT_BHUP; + cmd.arg = 1; + cmd.driver = card->myid; + card->interface.statcallb(&cmd); + cmd.command = ISDN_STAT_DHUP; + cmd.arg = 1; + cmd.driver = card->myid; + break; + } + card->interface.statcallb(&cmd); + return dflag; +} + +static void +icn_putmsg(icn_card * card, unsigned char c) +{ + ulong flags; + + save_flags(flags); + cli(); + *card->msg_buf_write++ = (c == 0xff) ? '\n' : c; + if (card->msg_buf_write == card->msg_buf_read) { + if (++card->msg_buf_read > card->msg_buf_end) + card->msg_buf_read = card->msg_buf; + } + if (card->msg_buf_write > card->msg_buf_end) + card->msg_buf_write = card->msg_buf; + restore_flags(flags); +} + +static void +icn_polldchan(unsigned long data) +{ + icn_card *card = (icn_card *) data; + int mch = card->secondhalf ? 2 : 0; + int avail = 0; + int dflag = 0; + int left; + u_char c; + int ch; + int flags; + int i; + u_char *p; + isdn_ctrl cmd; + + if (icn_trymaplock_channel(card, mch)) { + avail = msg_avail; + for (left = avail, i = readb(&msg_o); left > 0; i++, left--) { + c = readb(&dev.shmem->comm_buffers.iopc_buf[i & 0xff]); + icn_putmsg(card, c); + if (c == 0xff) { + card->imsg[card->iptr] = 0; + card->iptr = 0; + if (card->imsg[0] == '0' && card->imsg[1] >= '0' && + card->imsg[1] <= '2' && card->imsg[2] == ';') { + ch = (card->imsg[1] - '0') - 1; + p = &card->imsg[3]; + dflag |= icn_parse_status(p, ch, card); + } else { + p = card->imsg; + if (!strncmp(p, "DRV1.", 5)) { + u_char vstr[10]; + u_char *q = vstr; + + printk(KERN_INFO "icn: (%s) %s\n", CID, p); + if (!strncmp(p + 7, "TC", 2)) { + card->ptype = ISDN_PTYPE_1TR6; + card->interface.features |= ISDN_FEATURE_P_1TR6; + printk(KERN_INFO + "icn: (%s) 1TR6-Protocol loaded and running\n", CID); + } + if (!strncmp(p + 7, "EC", 2)) { + card->ptype = ISDN_PTYPE_EURO; + card->interface.features |= ISDN_FEATURE_P_EURO; + printk(KERN_INFO + "icn: (%s) Euro-Protocol loaded and running\n", CID); + } + p = strstr(card->imsg, "BRV") + 3; + while (*p) { + if (*p >= '0' && *p <= '9') + *q++ = *p; + p++; + } + *q = '\0'; + strcat(vstr, "000"); + vstr[3] = '\0'; + card->fw_rev = (int) simple_strtoul(vstr, NULL, 10); + continue; + + } + } + } else { + card->imsg[card->iptr] = c; + if (card->iptr < 59) + card->iptr++; + } + } + writeb((readb(&msg_o) + avail) & 0xff, &msg_o); + icn_release_channel(); + } + if (avail) { + cmd.command = ISDN_STAT_STAVAIL; + cmd.driver = card->myid; + cmd.arg = avail; + card->interface.statcallb(&cmd); + } + if (dflag & 1) + card->interface.rcvcallb(card->myid, 0, card->rcvbuf[0], 0); + if (dflag & 2) + card->interface.rcvcallb(card->myid, 1, card->rcvbuf[1], 0); + if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) + if (!(card->flags & ICN_FLAGS_RBTIMER)) { + /* schedule b-channel polling */ + card->flags |= ICN_FLAGS_RBTIMER; + save_flags(flags); + cli(); + del_timer(&card->rb_timer); + card->rb_timer.function = icn_pollbchan; + card->rb_timer.data = (unsigned long) card; + card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD; + add_timer(&card->rb_timer); + restore_flags(flags); + } + /* schedule again */ + save_flags(flags); + cli(); + del_timer(&card->st_timer); + card->st_timer.expires = jiffies + ICN_TIMER_DCREAD; + add_timer(&card->st_timer); + restore_flags(flags); } /* Append a packet to the transmit buffer-queue. @@ -686,34 +761,35 @@ * Number of bytes transferred, -E??? on error */ -static int icn_sendbuf(int channel, struct sk_buff *skb, icn_card * card) +static int +icn_sendbuf(int channel, struct sk_buff *skb, icn_card * card) { - int len = skb->len; - unsigned long flags; - struct sk_buff *nskb; - - if (len > 4000) { - printk(KERN_WARNING - "icn: Send packet too large\n"); - return -EINVAL; - } - if (len) { - if (!(card->flags & (channel)?ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE)) - return 0; - if (card->sndcount[channel] > ICN_MAX_SQUEUE) - return 0; - save_flags(flags); - cli(); - nskb = skb_clone(skb, GFP_ATOMIC); - if (nskb) { - skb_queue_tail(&card->spqueue[channel], nskb); - dev_kfree_skb(skb, FREE_WRITE); - } else - len = 0; - card->sndcount[channel] += len; - restore_flags(flags); - } - return len; + int len = skb->len; + unsigned long flags; + struct sk_buff *nskb; + + if (len > 4000) { + printk(KERN_WARNING + "icn: Send packet too large\n"); + return -EINVAL; + } + if (len) { + if (!(card->flags & (channel) ? ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE)) + return 0; + if (card->sndcount[channel] > ICN_MAX_SQUEUE) + return 0; + save_flags(flags); + cli(); + nskb = skb_clone(skb, GFP_ATOMIC); + if (nskb) { + skb_queue_tail(&card->spqueue[channel], nskb); + dev_kfree_skb(skb, FREE_WRITE); + } else + len = 0; + card->sndcount[channel] += len; + restore_flags(flags); + } + return len; } /* @@ -723,37 +799,38 @@ * 0 on success (Boot loader ready) * -EIO on failure (timeout) */ -static int icn_check_loader(int cardnumber) +static int +icn_check_loader(int cardnumber) { - int timer = 0; + int timer = 0; - while (1) { + while (1) { #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Loader %d ?\n", cardnumber); + printk(KERN_DEBUG "Loader %d ?\n", cardnumber); #endif - if (readb(&dev.shmem->data_control.scns) || - readb(&dev.shmem->data_control.scnr)) { - if (timer++ > 5) { - printk(KERN_WARNING - "icn: Boot-Loader %d timed out.\n", - cardnumber); - icn_release_channel(); - return -EIO; - } + if (readb(&dev.shmem->data_control.scns) || + readb(&dev.shmem->data_control.scnr)) { + if (timer++ > 5) { + printk(KERN_WARNING + "icn: Boot-Loader %d timed out.\n", + cardnumber); + icn_release_channel(); + return -EIO; + } #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Loader %d TO?\n", cardnumber); + printk(KERN_DEBUG "Loader %d TO?\n", cardnumber); #endif - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + ICN_BOOT_TIMEOUT1; - schedule(); - } else { + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + ICN_BOOT_TIMEOUT1; + schedule(); + } else { #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Loader %d OK\n", cardnumber); + printk(KERN_DEBUG "Loader %d OK\n", cardnumber); #endif - icn_release_channel(); - return 0; - } - } + icn_release_channel(); + return 0; + } + } } /* Load the boot-code into the interface-card's memory and start it. @@ -780,894 +857,935 @@ #define SLEEP(sec) #endif -static int icn_loadboot(u_char * buffer, icn_card * card) +static int +icn_loadboot(u_char * buffer, icn_card * card) { - int ret; - ulong flags; + int ret; + ulong flags; u_char *codebuf; #ifdef BOOT_DEBUG - printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer); + printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer); #endif - if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE1))) - return ret; - if (!(codebuf = kmalloc(ICN_CODE_STAGE1,GFP_KERNEL))) { - printk(KERN_WARNING "icn: Could not allocate code buffer\n"); - return -ENOMEM; - } - save_flags(flags); - cli(); - if (!card->rvalid) { - if (check_region(card->port, ICN_PORTLEN)) { - printk(KERN_WARNING - "icn: (%s) ports 0x%03x-0x%03x in use.\n", - CID, - card->port, - card->port + ICN_PORTLEN); - restore_flags(flags); - kfree(codebuf); - return -EBUSY; - } - request_region(card->port, ICN_PORTLEN, card->regname); - card->rvalid = 1; - if (card->doubleS0) - card->other->rvalid = 1; - } - if (!dev.mvalid) { - if (check_shmem((ulong) dev.shmem, 0x4000)) { - printk(KERN_WARNING - "icn: memory at 0x%08lx in use.\n", - (ulong) dev.shmem); - restore_flags(flags); - return -EBUSY; - } - request_shmem((ulong) dev.shmem, 0x4000, "icn"); - dev.mvalid = 1; - } - restore_flags(flags); - OUTB_P(0, ICN_RUN); /* Reset Controller */ - OUTB_P(0, ICN_MAPRAM); /* Disable RAM */ - icn_shiftout(ICN_CFG, 0x0f, 3, 4); /* Windowsize= 16k */ - icn_shiftout(ICN_CFG, (unsigned long) dev.shmem, 23, 10); /* Set RAM-Addr. */ + if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE1))) + return ret; + if (!(codebuf = kmalloc(ICN_CODE_STAGE1, GFP_KERNEL))) { + printk(KERN_WARNING "icn: Could not allocate code buffer\n"); + return -ENOMEM; + } + save_flags(flags); + cli(); + if (!card->rvalid) { + if (check_region(card->port, ICN_PORTLEN)) { + printk(KERN_WARNING + "icn: (%s) ports 0x%03x-0x%03x in use.\n", + CID, + card->port, + card->port + ICN_PORTLEN); + restore_flags(flags); + kfree(codebuf); + return -EBUSY; + } + request_region(card->port, ICN_PORTLEN, card->regname); + card->rvalid = 1; + if (card->doubleS0) + card->other->rvalid = 1; + } + if (!dev.mvalid) { + if (check_shmem((ulong) dev.shmem, 0x4000)) { + printk(KERN_WARNING + "icn: memory at 0x%08lx in use.\n", + (ulong) dev.shmem); + restore_flags(flags); + return -EBUSY; + } + request_shmem((ulong) dev.shmem, 0x4000, "icn"); + dev.mvalid = 1; + } + restore_flags(flags); + OUTB_P(0, ICN_RUN); /* Reset Controller */ + OUTB_P(0, ICN_MAPRAM); /* Disable RAM */ + icn_shiftout(ICN_CFG, 0x0f, 3, 4); /* Windowsize= 16k */ + icn_shiftout(ICN_CFG, (unsigned long) dev.shmem, 23, 10); /* Set RAM-Addr. */ #ifdef BOOT_DEBUG - printk(KERN_DEBUG "shmem=%08lx\n", (ulong) dev.shmem); + printk(KERN_DEBUG "shmem=%08lx\n", (ulong) dev.shmem); #endif - SLEEP(1); - save_flags(flags); - cli(); + SLEEP(1); #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Map Bank 0\n"); + printk(KERN_DEBUG "Map Bank 0\n"); #endif - icn_map_channel(card,0); /* Select Bank 0 */ - icn_lock_channel(card,0); /* Lock Bank 0 */ - restore_flags(flags); - SLEEP(1); - if (copy_from_user(codebuf, buffer, ICN_CODE_STAGE1)) - return -EFAULT; - memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */ + save_flags(flags); + cli(); + icn_map_channel(card, 0); /* Select Bank 0 */ + icn_lock_channel(card, 0); /* Lock Bank 0 */ + restore_flags(flags); + SLEEP(1); + copy_from_user(codebuf, buffer, ICN_CODE_STAGE1); + memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */ #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Bootloader transfered\n"); + printk(KERN_DEBUG "Bootloader transfered\n"); #endif - if (card->doubleS0) { - SLEEP(1); - save_flags(flags); - cli(); - icn_release_channel(); + if (card->doubleS0) { + SLEEP(1); #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Map Bank 8\n"); + printk(KERN_DEBUG "Map Bank 8\n"); #endif - icn_map_channel(card,2); /* Select Bank 8 */ - icn_lock_channel(card,2); /* Lock Bank 8 */ - restore_flags(flags); - SLEEP(1); - memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */ + save_flags(flags); + cli(); + icn_release_channel(); + icn_map_channel(card, 2); /* Select Bank 8 */ + icn_lock_channel(card, 2); /* Lock Bank 8 */ + restore_flags(flags); + SLEEP(1); + memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */ #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Bootloader transfered\n"); + printk(KERN_DEBUG "Bootloader transfered\n"); #endif - } - kfree(codebuf); - SLEEP(1); - OUTB_P(0xff, ICN_RUN); /* Start Boot-Code */ - if ((ret = icn_check_loader(card->doubleS0 ? 2 : 1))) - return ret; - if (!card->doubleS0) - return 0; - /* reached only, if we have a Double-S0-Card */ - save_flags(flags); - cli(); + } + kfree(codebuf); + SLEEP(1); + OUTB_P(0xff, ICN_RUN); /* Start Boot-Code */ + if ((ret = icn_check_loader(card->doubleS0 ? 2 : 1))) + return ret; + if (!card->doubleS0) + return 0; + /* reached only, if we have a Double-S0-Card */ #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Map Bank 0\n"); + printk(KERN_DEBUG "Map Bank 0\n"); #endif - icn_map_channel(card,0); /* Select Bank 0 */ - icn_lock_channel(card,0); /* Lock Bank 0 */ - restore_flags(flags); - SLEEP(1); - return (icn_check_loader(1)); -} - -static int icn_loadproto(u_char * buffer, icn_card * card) -{ - register u_char *p = buffer; - u_char codebuf[256]; - uint left = ICN_CODE_STAGE2; - uint cnt; - int timer; - int ret; - unsigned long flags; + save_flags(flags); + cli(); + icn_map_channel(card, 0); /* Select Bank 0 */ + icn_lock_channel(card, 0); /* Lock Bank 0 */ + restore_flags(flags); + SLEEP(1); + return (icn_check_loader(1)); +} + +static int +icn_loadproto(u_char * buffer, icn_card * card) +{ + register u_char *p = buffer; + u_char codebuf[256]; + uint left = ICN_CODE_STAGE2; + uint cnt; + int timer; + int ret; + unsigned long flags; #ifdef BOOT_DEBUG - printk(KERN_DEBUG "icn_loadproto called\n"); + printk(KERN_DEBUG "icn_loadproto called\n"); #endif - if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE2))) - return ret; - timer = 0; - save_flags(flags); - cli(); - if (card->secondhalf) { - icn_map_channel(card, 2); - icn_lock_channel(card, 2); - } else { - icn_map_channel(card, 0); - icn_lock_channel(card, 0); - } - restore_flags(flags); - while (left) { - if (sbfree) { /* If there is a free buffer... */ - cnt = MIN(256, left); - if (copy_from_user(codebuf, p, cnt)) - /* FIXME -WRONG */return -EFAULT; - memcpy_toio(&sbuf_l, codebuf, cnt); /* copy data */ - sbnext; /* switch to next buffer */ - p += cnt; - left -= cnt; - timer = 0; - } else { + if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE2))) + return ret; + timer = 0; + save_flags(flags); + cli(); + if (card->secondhalf) { + icn_map_channel(card, 2); + icn_lock_channel(card, 2); + } else { + icn_map_channel(card, 0); + icn_lock_channel(card, 0); + } + restore_flags(flags); + while (left) { + if (sbfree) { /* If there is a free buffer... */ + cnt = MIN(256, left); + copy_from_user(codebuf, p, cnt); + memcpy_toio(&sbuf_l, codebuf, cnt); /* copy data */ + sbnext; /* switch to next buffer */ + p += cnt; + left -= cnt; + timer = 0; + } else { #ifdef BOOT_DEBUG - printk(KERN_DEBUG "boot 2 !sbfree\n"); + printk(KERN_DEBUG "boot 2 !sbfree\n"); #endif - if (timer++ > 5) { - icn_maprelease_channel(card, 0); - return -EIO; - } - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 10; - schedule(); - } - } - writeb (0x20, &sbuf_n); - timer = 0; - while (1) { - if (readb(&cmd_o) || readb(&cmd_i)) { + if (timer++ > 5) { + icn_maprelease_channel(card, 0); + return -EIO; + } + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + 10; + schedule(); + } + } + writeb(0x20, &sbuf_n); + timer = 0; + while (1) { + if (readb(&cmd_o) || readb(&cmd_i)) { #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Proto?\n"); + printk(KERN_DEBUG "Proto?\n"); #endif - if (timer++ > 5) { - printk(KERN_WARNING - "icn: (%s) Protocol timed out.\n", - CID); + if (timer++ > 5) { + printk(KERN_WARNING + "icn: (%s) Protocol timed out.\n", + CID); #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Proto TO!\n"); + printk(KERN_DEBUG "Proto TO!\n"); #endif - icn_maprelease_channel(card, 0); - return -EIO; - } + icn_maprelease_channel(card, 0); + return -EIO; + } #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Proto TO?\n"); + printk(KERN_DEBUG "Proto TO?\n"); #endif - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + ICN_BOOT_TIMEOUT1; - schedule(); - } else { - if ((card->secondhalf) || (!card->doubleS0)) { - save_flags(flags); - cli(); + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + ICN_BOOT_TIMEOUT1; + schedule(); + } else { + if ((card->secondhalf) || (!card->doubleS0)) { #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n", - card->secondhalf); + printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n", + card->secondhalf); #endif - init_timer(&card->st_timer); - card->st_timer.expires = jiffies + ICN_TIMER_DCREAD; - card->st_timer.function = icn_polldchan; - card->st_timer.data = (unsigned long)card; - add_timer(&card->st_timer); - card->flags |= ICN_FLAGS_RUNNING; - if (card->doubleS0) { - init_timer(&card->other->st_timer); - card->other->st_timer.expires = jiffies + ICN_TIMER_DCREAD; - card->other->st_timer.function = icn_polldchan; - card->other->st_timer.data = (unsigned long)card->other; - add_timer(&card->other->st_timer); - card->other->flags |= ICN_FLAGS_RUNNING; - } - restore_flags(flags); - } - icn_maprelease_channel(card, 0); - return 0; - } - } + save_flags(flags); + cli(); + init_timer(&card->st_timer); + card->st_timer.expires = jiffies + ICN_TIMER_DCREAD; + card->st_timer.function = icn_polldchan; + card->st_timer.data = (unsigned long) card; + add_timer(&card->st_timer); + card->flags |= ICN_FLAGS_RUNNING; + if (card->doubleS0) { + init_timer(&card->other->st_timer); + card->other->st_timer.expires = jiffies + ICN_TIMER_DCREAD; + card->other->st_timer.function = icn_polldchan; + card->other->st_timer.data = (unsigned long) card->other; + add_timer(&card->other->st_timer); + card->other->flags |= ICN_FLAGS_RUNNING; + } + restore_flags(flags); + } + icn_maprelease_channel(card, 0); + return 0; + } + } } /* Read the Status-replies from the Interface */ -static int icn_readstatus(u_char * buf, int len, int user, icn_card * card) +static int +icn_readstatus(u_char * buf, int len, int user, icn_card * card) { - int count; - u_char *p; + int count; + u_char *p; - for (p = buf, count = 0; count < len; p++, count++) { - if (card->msg_buf_read == card->msg_buf_write) - return count; - if (user) - put_user(*card->msg_buf_read++, p); - else - *p = *card->msg_buf_read++; - if (card->msg_buf_read > card->msg_buf_end) - card->msg_buf_read = card->msg_buf; - } - return count; + for (p = buf, count = 0; count < len; p++, count++) { + if (card->msg_buf_read == card->msg_buf_write) + return count; + if (user) + put_user(*card->msg_buf_read++, p); + else + *p = *card->msg_buf_read++; + if (card->msg_buf_read > card->msg_buf_end) + card->msg_buf_read = card->msg_buf; + } + return count; } /* Put command-strings into the command-queue of the Interface */ -static int icn_writecmd(const u_char * buf, int len, int user, icn_card * card, int waitflg) +static int +icn_writecmd(const u_char * buf, int len, int user, icn_card * card) { - int mch = card->secondhalf ? 2 : 0; - int avail; - int pp; - int i; - int count; - int ocount; - unsigned long flags; - u_char *p; - isdn_ctrl cmd; - u_char msg[0x100]; - - while (1) { - if (icn_trymaplock_channel(card, mch)) { - avail = cmd_free; - count = MIN(avail, len); - if (user) - { - if (copy_from_user(msg, buf, count) != 0) - { - icn_release_channel(); - return -EFAULT; - } - } - else - memcpy(msg, buf, count); - save_flags(flags); - cli(); - ocount = 1; - *card->msg_buf_write++ = '>'; - if (card->msg_buf_write > card->msg_buf_end) - card->msg_buf_write = card->msg_buf; - for (p = msg, pp = readb(&cmd_i), i = count; i > 0; i--, p++, pp++) { - writeb((*p == '\n') ? 0xff : *p, - &dev.shmem->comm_buffers.pcio_buf[pp & 0xff]); - *card->msg_buf_write++ = *p; - if ((*p == '\n') && (i > 1)) { - *card->msg_buf_write++ = '>'; - if (card->msg_buf_write > card->msg_buf_end) - card->msg_buf_write = card->msg_buf; - ocount++; - } - /* No checks for buffer overflow of raw-status-device */ - if (card->msg_buf_write > card->msg_buf_end) - card->msg_buf_write = card->msg_buf; - ocount++; - } - restore_flags(flags); - cmd.command = ISDN_STAT_STAVAIL; - cmd.driver = card->myid; - cmd.arg = ocount; - card->interface.statcallb(&cmd); - writeb((readb(&cmd_i) + count) & 0xff, &cmd_i); - icn_release_channel(); - waitflg = 0; - } else - count = 0; - if (!waitflg) - break; - current->timeout = jiffies + 10; - schedule(); - } - return count; + int mch = card->secondhalf ? 2 : 0; + int avail; + int pp; + int i; + int count; + int xcount; + int ocount; + int loop; + unsigned long flags; + int lastmap_channel; + struct icn_card *lastmap_card; + u_char *p; + isdn_ctrl cmd; + u_char msg[0x100]; + + ocount = 1; + xcount = loop = 0; + while (len) { + save_flags(flags); + cli(); + lastmap_card = dev.mcard; + lastmap_channel = dev.channel; + icn_map_channel(card, mch); + + avail = cmd_free; + count = MIN(avail, len); + if (user) + copy_from_user(msg, buf, count); + else + memcpy(msg, buf, count); + icn_putmsg(card, '>'); + for (p = msg, pp = readb(&cmd_i), i = count; i > 0; i--, p++, pp + ++) { + writeb((*p == '\n') ? 0xff : *p, + &dev.shmem->comm_buffers.pcio_buf[pp & 0xff]); + len--; + xcount++; + icn_putmsg(card, *p); + if ((*p == '\n') && (i > 1)) { + icn_putmsg(card, '>'); + ocount++; + } + ocount++; + } + writeb((readb(&cmd_i) + count) & 0xff, &cmd_i); + if (lastmap_card) + icn_map_channel(lastmap_card, lastmap_channel); + restore_flags(flags); + if (len) { + udelay(1000); + if (loop++ > 20) + break; + } else + break; + } + if (len && (!user)) + printk(KERN_WARNING "icn: writemsg incomplete!\n"); + cmd.command = ISDN_STAT_STAVAIL; + cmd.driver = card->myid; + cmd.arg = ocount; + card->interface.statcallb(&cmd); + return xcount; } /* * Delete card's pending timers, send STOP to linklevel */ -static void icn_stopcard(icn_card * card) +static void +icn_stopcard(icn_card * card) { - unsigned long flags; - isdn_ctrl cmd; + unsigned long flags; + isdn_ctrl cmd; - save_flags(flags); - cli(); - if (card->flags & ICN_FLAGS_RUNNING) { - card->flags &= ~ICN_FLAGS_RUNNING; - del_timer(&card->st_timer); - del_timer(&card->rb_timer); - cmd.command = ISDN_STAT_STOP; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - if (card->doubleS0) - icn_stopcard(card->other); - } - restore_flags(flags); -} - -static void icn_stopallcards(void) -{ - icn_card *p = cards; - - while (p) { - icn_stopcard(p); - p = p->next; - } -} - -static int icn_command(isdn_ctrl * c, icn_card * card) -{ - ulong a; - ulong flags; - int i; - char cbuf[60]; - isdn_ctrl cmd; - icn_cdef cdef; - - switch (c->command) { - case ISDN_CMD_IOCTL: - memcpy(&a, c->num, sizeof(ulong)); - switch (c->arg) { - case ICN_IOCTL_SETMMIO: - if ((unsigned long) dev.shmem != (a & 0x0ffc000)) { - if (check_shmem((ulong) (a & 0x0ffc000), 0x4000)) { - printk(KERN_WARNING - "icn: memory at 0x%08lx in use.\n", - (ulong) (a & 0x0ffc000)); - return -EINVAL; - } - icn_stopallcards(); - save_flags(flags); - cli(); - if (dev.mvalid) - release_shmem((ulong) dev.shmem, 0x4000); - dev.mvalid = 0; - dev.shmem = (icn_shmem *) (a & 0x0ffc000); - restore_flags(flags); - printk(KERN_INFO - "icn: (%s) mmio set to 0x%08lx\n", - CID, - (unsigned long) dev.shmem); - } - break; - case ICN_IOCTL_GETMMIO: - return (long) dev.shmem; - case ICN_IOCTL_SETPORT: - if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330 - || a == 0x340 || a == 0x350 || a == 0x360 || - a == 0x308 || a == 0x318 || a == 0x328 || a == 0x338 - || a == 0x348 || a == 0x358 || a == 0x368) { - if (card->port != (unsigned short) a) { - if (check_region((unsigned short) a, ICN_PORTLEN)) { - printk(KERN_WARNING - "icn: (%s) ports 0x%03x-0x%03x in use.\n", - CID, (int) a, (int) a + ICN_PORTLEN); - return -EINVAL; - } - icn_stopcard(card); - save_flags(flags); - cli(); - if (card->rvalid) - release_region(card->port, ICN_PORTLEN); - card->port = (unsigned short) a; - card->rvalid = 0; - if (card->doubleS0) { - card->other->port = (unsigned short) a; - card->other->rvalid = 0; - } - restore_flags(flags); - printk(KERN_INFO - "icn: (%s) port set to 0x%03x\n", - CID, card->port); - } - } else - return -EINVAL; - break; - case ICN_IOCTL_GETPORT: - return (int) card->port; - case ICN_IOCTL_GETDOUBLE: - return (int) card->doubleS0; - case ICN_IOCTL_DEBUGVAR: - if ((i = verify_area(VERIFY_WRITE, - (void *) a, - sizeof(ulong) * 2))) - return i; - if (copy_to_user((char *)a, - (char *)&card, sizeof(ulong))) - return -EFAULT; - a += sizeof(ulong); - { - ulong l = (ulong)&dev; - if (copy_to_user((char *)a, - (char *)&l, sizeof(ulong))) - return -EFAULT; - } - return 0; - case ICN_IOCTL_LOADBOOT: - icn_stopcard(card); - return (icn_loadboot((u_char *) a, card)); - case ICN_IOCTL_LOADPROTO: - icn_stopcard(card); - if ((i = (icn_loadproto((u_char *) a, card)))) - return i; - if (card->doubleS0) - i = icn_loadproto((u_char *) (a + ICN_CODE_STAGE2), card->other); - return i; - break; - case ICN_IOCTL_ADDCARD: - if ((i = verify_area(VERIFY_READ, (void *) a, sizeof(icn_cdef)))) - return i; - if (copy_from_user((char *)&cdef, (char *)a, sizeof(cdef))) - return -EFAULT; - return (icn_addcard(cdef.port, cdef.id1, cdef.id2)); - break; - case ICN_IOCTL_LEASEDCFG: - if (a) { - if (!card->leased) { - card->leased = 1; - while (card->ptype == ISDN_PTYPE_UNKNOWN) { - current->timeout = jiffies + ICN_BOOT_TIMEOUT1; - schedule(); - } - current->timeout = jiffies + ICN_BOOT_TIMEOUT1; - schedule(); - sprintf(cbuf, "00;FV2ON\n01;EAZ1\n"); - i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); - printk(KERN_INFO - "icn: (%s) Leased-line mode enabled\n", - CID); - cmd.command = ISDN_STAT_RUN; - cmd.driver = card->myid; - cmd.arg = 0; - card->interface.statcallb(&cmd); - } - } else { - if (card->leased) { - card->leased = 0; - sprintf(cbuf, "00;FV2OFF\n"); - i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); - printk(KERN_INFO - "icn: (%s) Leased-line mode disabled\n", - CID); - cmd.command = ISDN_STAT_RUN; - cmd.driver = card->myid; - cmd.arg = 0; - card->interface.statcallb(&cmd); - } - } - return 0; - default: - return -EINVAL; - } - break; - case ISDN_CMD_DIAL: - if (!card->flags & ICN_FLAGS_RUNNING) - return -ENODEV; - if (card->leased) - break; - if ((c->arg & 255) < ICN_BCH) { - char *p; - char *p2; - char dial[50]; - char sis[50]; - char dcode[4]; - int si1, si2; - - a = c->arg; - strcpy(sis, c->num); - p = strrchr(sis, ','); - *p++ = '\0'; - si2 = simple_strtoul(p,NULL,10); - p = strrchr(sis, ',') + 1; - si1 = simple_strtoul(p,NULL,10); - p = c->num; - if (*p == 's' || *p == 'S') { - /* Dial for SPV */ - p++; - strcpy(dcode, "SCA"); - } else - /* Normal Dial */ - strcpy(dcode, "CAL"); - strcpy(dial, p); - p = strchr(dial, ','); - *p++ = '\0'; - p2 = strchr(p, ','); - *p2 = '\0'; - sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1), dcode, dial, si1, - si2, p); - i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); - } - break; - case ISDN_CMD_ACCEPTD: - if (!card->flags & ICN_FLAGS_RUNNING) - return -ENODEV; - if (c->arg < ICN_BCH) { - a = c->arg + 1; - if (card->fw_rev >= 300) { - switch (card->l2_proto[a-1]) { - case ISDN_PROTO_L2_X75I: - sprintf(cbuf, "%02d;BX75\n", (int) a); - break; - case ISDN_PROTO_L2_HDLC: - sprintf(cbuf, "%02d;BTRA\n", (int) a); - break; - } - i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); - } - sprintf(cbuf, "%02d;DCON_R\n", (int) a); - i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); - } - break; - case ISDN_CMD_ACCEPTB: - if (!card->flags & ICN_FLAGS_RUNNING) - return -ENODEV; - if (c->arg < ICN_BCH) { - a = c->arg + 1; - if (card->fw_rev >= 300) - switch (card->l2_proto[a-1]) { - case ISDN_PROTO_L2_X75I: - sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a); - break; - case ISDN_PROTO_L2_HDLC: - sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a); - break; - } - else - sprintf(cbuf, "%02d;BCON_R\n", (int) a); - i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); - } - break; - case ISDN_CMD_HANGUP: - if (!card->flags & ICN_FLAGS_RUNNING) - return -ENODEV; - if (c->arg < ICN_BCH) { - a = c->arg + 1; - sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a); - i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); - } - break; - case ISDN_CMD_SETEAZ: - if (!card->flags & ICN_FLAGS_RUNNING) - return -ENODEV; - if (card->leased) - break; - if (c->arg < ICN_BCH) { - a = c->arg + 1; - if (card->ptype == ISDN_PTYPE_EURO) { - sprintf(cbuf, "%02d;MS%s%s\n", (int) a, - c->num[0] ? "N" : "ALL", c->num); - } else - sprintf(cbuf, "%02d;EAZ%s\n", (int) a, - c->num[0] ? c->num : "0123456789"); - i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); - } - break; - case ISDN_CMD_CLREAZ: - if (!card->flags & ICN_FLAGS_RUNNING) - return -ENODEV; - if (card->leased) - break; - if (c->arg < ICN_BCH) { - a = c->arg + 1; - if (card->ptype == ISDN_PTYPE_EURO) - sprintf(cbuf, "%02d;MSNC\n", (int) a); - else - sprintf(cbuf, "%02d;EAZC\n", (int) a); - i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); - } - break; - case ISDN_CMD_SETL2: - if (!card->flags & ICN_FLAGS_RUNNING) - return -ENODEV; - if ((c->arg & 255) < ICN_BCH) { - a = c->arg; - switch (a >> 8) { - case ISDN_PROTO_L2_X75I: - sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1); - break; - case ISDN_PROTO_L2_HDLC: - sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1); - break; - default: - return -EINVAL; - } - i = icn_writecmd(cbuf, strlen(cbuf), 0, card, 1); - card->l2_proto[a & 255] = (a >> 8); - } - break; - case ISDN_CMD_GETL2: - if (!card->flags & ICN_FLAGS_RUNNING) - return -ENODEV; - if ((c->arg & 255) < ICN_BCH) - return card->l2_proto[c->arg & 255]; - else - return -ENODEV; - case ISDN_CMD_SETL3: - if (!card->flags & ICN_FLAGS_RUNNING) - return -ENODEV; - return 0; - case ISDN_CMD_GETL3: - if (!card->flags & ICN_FLAGS_RUNNING) - return -ENODEV; - if ((c->arg & 255) < ICN_BCH) - return ISDN_PROTO_L3_TRANS; - else - return -ENODEV; - case ISDN_CMD_GETEAZ: - if (!card->flags & ICN_FLAGS_RUNNING) - return -ENODEV; - break; - case ISDN_CMD_SETSIL: - if (!card->flags & ICN_FLAGS_RUNNING) - return -ENODEV; - break; - case ISDN_CMD_GETSIL: - if (!card->flags & ICN_FLAGS_RUNNING) - return -ENODEV; - break; - case ISDN_CMD_LOCK: - MOD_INC_USE_COUNT; - break; - case ISDN_CMD_UNLOCK: - MOD_DEC_USE_COUNT; - break; - default: - return -EINVAL; - } - return 0; + save_flags(flags); + cli(); + if (card->flags & ICN_FLAGS_RUNNING) { + card->flags &= ~ICN_FLAGS_RUNNING; + del_timer(&card->st_timer); + del_timer(&card->rb_timer); + cmd.command = ISDN_STAT_STOP; + cmd.driver = card->myid; + card->interface.statcallb(&cmd); + if (card->doubleS0) + icn_stopcard(card->other); + } + restore_flags(flags); +} + +static void +icn_stopallcards(void) +{ + icn_card *p = cards; + + while (p) { + icn_stopcard(p); + p = p->next; + } } /* - * Find card with given driverId + * Unmap all cards, because some of them may be mapped accidetly during + * autoprobing of some network drivers (SMC-driver?) */ -static inline icn_card * - icn_findcard(int driverid) +static void +icn_disable_cards(void) { - icn_card *p = cards; + icn_card *card = cards; + unsigned long flags; - while (p) { - if (p->myid == driverid) - return p; - p = p->next; - } - return (icn_card *)0; + save_flags(flags); + cli(); + while (card) { + if (check_region(card->port, ICN_PORTLEN)) { + printk(KERN_WARNING + "icn: (%s) ports 0x%03x-0x%03x in use.\n", + CID, + card->port, + card->port + ICN_PORTLEN); + cli(); + } else { + OUTB_P(0, ICN_RUN); /* Reset Controller */ + OUTB_P(0, ICN_MAPRAM); /* Disable RAM */ + } + card = card->next; + } + restore_flags(flags); +} + +static int +icn_command(isdn_ctrl * c, icn_card * card) +{ + ulong a; + ulong flags; + int i; + char cbuf[60]; + isdn_ctrl cmd; + icn_cdef cdef; + + switch (c->command) { + case ISDN_CMD_IOCTL: + memcpy(&a, c->parm.num, sizeof(ulong)); + switch (c->arg) { + case ICN_IOCTL_SETMMIO: + if ((unsigned long) dev.shmem != (a & 0x0ffc000)) { + if (check_shmem((ulong) (a & 0x0ffc000), 0x4000)) { + printk(KERN_WARNING + "icn: memory at 0x%08lx in use.\n", + (ulong) (a & 0x0ffc000)); + return -EINVAL; + } + icn_stopallcards(); + save_flags(flags); + cli(); + if (dev.mvalid) + release_shmem((ulong) dev.shmem, 0x4000); + dev.mvalid = 0; + dev.shmem = (icn_shmem *) (a & 0x0ffc000); + restore_flags(flags); + printk(KERN_INFO + "icn: (%s) mmio set to 0x%08lx\n", + CID, + (unsigned long) dev.shmem); + } + break; + case ICN_IOCTL_GETMMIO: + return (long) dev.shmem; + case ICN_IOCTL_SETPORT: + if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330 + || a == 0x340 || a == 0x350 || a == 0x360 || + a == 0x308 || a == 0x318 || a == 0x328 || a == 0x338 + || a == 0x348 || a == 0x358 || a == 0x368) { + if (card->port != (unsigned short) a) { + if (check_region((unsigned short) a, ICN_PORTLEN)) { + printk(KERN_WARNING + "icn: (%s) ports 0x%03x-0x%03x in use.\n", + CID, (int) a, (int) a + ICN_PORTLEN); + return -EINVAL; + } + icn_stopcard(card); + save_flags(flags); + cli(); + if (card->rvalid) + release_region(card->port, ICN_PORTLEN); + card->port = (unsigned short) a; + card->rvalid = 0; + if (card->doubleS0) { + card->other->port = (unsigned short) a; + card->other->rvalid = 0; + } + restore_flags(flags); + printk(KERN_INFO + "icn: (%s) port set to 0x%03x\n", + CID, card->port); + } + } else + return -EINVAL; + break; + case ICN_IOCTL_GETPORT: + return (int) card->port; + case ICN_IOCTL_GETDOUBLE: + return (int) card->doubleS0; + case ICN_IOCTL_DEBUGVAR: + if ((i = verify_area(VERIFY_WRITE, + (void *) a, + sizeof(ulong) * 2))) + return i; + copy_to_user((char *) a, + (char *) &card, sizeof(ulong)); + a += sizeof(ulong); + { + ulong l = (ulong) & dev; + copy_to_user((char *) a, + (char *) &l, sizeof(ulong)); + } + return 0; + case ICN_IOCTL_LOADBOOT: + if (dev.firstload) { + icn_disable_cards(); + dev.firstload = 0; + } + icn_stopcard(card); + return (icn_loadboot((u_char *) a, card)); + case ICN_IOCTL_LOADPROTO: + icn_stopcard(card); + if ((i = (icn_loadproto((u_char *) a, card)))) + return i; + if (card->doubleS0) + i = icn_loadproto((u_char *) (a + ICN_CODE_STAGE2), card->other); + return i; + break; + case ICN_IOCTL_ADDCARD: + if (!dev.firstload) + return -EBUSY; + if ((i = verify_area(VERIFY_READ, (void *) a, sizeof(icn_cdef)))) + return i; + copy_from_user((char *) &cdef, (char *) a, sizeof(cdef)); + return (icn_addcard(cdef.port, cdef.id1, cdef.id2)); + break; + case ICN_IOCTL_LEASEDCFG: + if (a) { + if (!card->leased) { + card->leased = 1; + while (card->ptype == ISDN_PTYPE_UNKNOWN) { + current->timeout = jiffies + ICN_BOOT_TIMEOUT1; + schedule(); + } + current->timeout = jiffies + ICN_BOOT_TIMEOUT1; + schedule(); + sprintf(cbuf, "00;FV2ON\n01;EAZ1\n02;EAZ2\n"); + i = icn_writecmd(cbuf, strlen(cbuf), 0, card); + printk(KERN_INFO + "icn: (%s) Leased-line mode enabled\n", + CID); + cmd.command = ISDN_STAT_RUN; + cmd.driver = card->myid; + cmd.arg = 0; + card->interface.statcallb(&cmd); + } + } else { + if (card->leased) { + card->leased = 0; + sprintf(cbuf, "00;FV2OFF\n"); + i = icn_writecmd(cbuf, strlen(cbuf), 0, card); + printk(KERN_INFO + "icn: (%s) Leased-line mode disabled\n", + CID); + cmd.command = ISDN_STAT_RUN; + cmd.driver = card->myid; + cmd.arg = 0; + card->interface.statcallb(&cmd); + } + } + return 0; + default: + return -EINVAL; + } + break; + case ISDN_CMD_DIAL: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + if (card->leased) + break; + if ((c->arg & 255) < ICN_BCH) { + char *p; + char dial[50]; + char dcode[4]; + + a = c->arg; + p = c->parm.setup.phone; + if (*p == 's' || *p == 'S') { + /* Dial for SPV */ + p++; + strcpy(dcode, "SCA"); + } else + /* Normal Dial */ + strcpy(dcode, "CAL"); + strcpy(dial, p); + sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1), + dcode, dial, c->parm.setup.si1, + c->parm.setup.si2, c->parm.setup.eazmsn); + i = icn_writecmd(cbuf, strlen(cbuf), 0, card); + } + break; + case ISDN_CMD_ACCEPTD: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + if (c->arg < ICN_BCH) { + a = c->arg + 1; + if (card->fw_rev >= 300) { + switch (card->l2_proto[a - 1]) { + case ISDN_PROTO_L2_X75I: + sprintf(cbuf, "%02d;BX75\n", (int) a); + break; + case ISDN_PROTO_L2_HDLC: + sprintf(cbuf, "%02d;BTRA\n", (int) a); + break; + } + i = icn_writecmd(cbuf, strlen(cbuf), 0, card); + } + sprintf(cbuf, "%02d;DCON_R\n", (int) a); + i = icn_writecmd(cbuf, strlen(cbuf), 0, card); + } + break; + case ISDN_CMD_ACCEPTB: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + if (c->arg < ICN_BCH) { + a = c->arg + 1; + if (card->fw_rev >= 300) + switch (card->l2_proto[a - 1]) { + case ISDN_PROTO_L2_X75I: + sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a); + break; + case ISDN_PROTO_L2_HDLC: + sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a); + break; + } else + sprintf(cbuf, "%02d;BCON_R\n", (int) a); + i = icn_writecmd(cbuf, strlen(cbuf), 0, card); + } + break; + case ISDN_CMD_HANGUP: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + if (c->arg < ICN_BCH) { + a = c->arg + 1; + sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a); + i = icn_writecmd(cbuf, strlen(cbuf), 0, card); + } + break; + case ISDN_CMD_SETEAZ: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + if (card->leased) + break; + if (c->arg < ICN_BCH) { + a = c->arg + 1; + if (card->ptype == ISDN_PTYPE_EURO) { + sprintf(cbuf, "%02d;MS%s%s\n", (int) a, + 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"); + i = icn_writecmd(cbuf, strlen(cbuf), 0, card); + } + break; + case ISDN_CMD_CLREAZ: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + if (card->leased) + break; + if (c->arg < ICN_BCH) { + a = c->arg + 1; + if (card->ptype == ISDN_PTYPE_EURO) + sprintf(cbuf, "%02d;MSNC\n", (int) a); + else + sprintf(cbuf, "%02d;EAZC\n", (int) a); + i = icn_writecmd(cbuf, strlen(cbuf), 0, card); + } + break; + case ISDN_CMD_SETL2: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + if ((c->arg & 255) < ICN_BCH) { + a = c->arg; + switch (a >> 8) { + case ISDN_PROTO_L2_X75I: + sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1); + break; + case ISDN_PROTO_L2_HDLC: + sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1); + break; + default: + return -EINVAL; + } + i = icn_writecmd(cbuf, strlen(cbuf), 0, card); + card->l2_proto[a & 255] = (a >> 8); + } + break; + case ISDN_CMD_GETL2: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + if ((c->arg & 255) < ICN_BCH) + return card->l2_proto[c->arg & 255]; + else + return -ENODEV; + case ISDN_CMD_SETL3: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + return 0; + case ISDN_CMD_GETL3: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + if ((c->arg & 255) < ICN_BCH) + return ISDN_PROTO_L3_TRANS; + else + return -ENODEV; + case ISDN_CMD_GETEAZ: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + break; + case ISDN_CMD_SETSIL: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + break; + case ISDN_CMD_GETSIL: + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + break; + case ISDN_CMD_LOCK: + MOD_INC_USE_COUNT; + break; + case ISDN_CMD_UNLOCK: + MOD_DEC_USE_COUNT; + break; + default: + return -EINVAL; + } + return 0; } /* - * Wrapper functions for interface to linklevel + * Find card with given driverId */ -static int if_command(isdn_ctrl * c) -{ - icn_card *card = icn_findcard(c->driver); - - if (card) - return (icn_command(c, card)); - printk(KERN_ERR - "icn: if_command %d called with invalid driverId %d!\n", - c->command, c->driver); - return -ENODEV; -} - -static int if_writecmd(const u_char * buf, int len, int user, int id, int channel) -{ - icn_card *card = icn_findcard(id); - - if (card) { - if (!card->flags & ICN_FLAGS_RUNNING) - return -ENODEV; - return (icn_writecmd(buf, len, user, card, 0)); - } - printk(KERN_ERR - "icn: if_writecmd called with invalid driverId!\n"); - return -ENODEV; -} - -static int if_readstatus(u_char * buf, int len, int user, int id, int channel) +static inline icn_card * +icn_findcard(int driverid) { - icn_card *card = icn_findcard(id); + icn_card *p = cards; - if (card) { - if (!card->flags & ICN_FLAGS_RUNNING) - return -ENODEV; - return (icn_readstatus(buf, len, user, card)); - } - printk(KERN_ERR - "icn: if_readstatus called with invalid driverId!\n"); - return -ENODEV; + while (p) { + if (p->myid == driverid) + return p; + p = p->next; + } + return (icn_card *) 0; } -static int if_sendbuf(int id, int channel, struct sk_buff *skb) +/* + * Wrapper functions for interface to linklevel + */ +static int +if_command(isdn_ctrl * c) { - icn_card *card = icn_findcard(id); + icn_card *card = icn_findcard(c->driver); - if (card) { - if (!card->flags & ICN_FLAGS_RUNNING) - return -ENODEV; - return (icn_sendbuf(channel, skb, card)); - } - printk(KERN_ERR - "icn: if_sendbuf called with invalid driverId!\n"); - return -ENODEV; + if (card) + return (icn_command(c, card)); + printk(KERN_ERR + "icn: if_command %d called with invalid driverId %d!\n", + c->command, c->driver); + return -ENODEV; +} + +static int +if_writecmd(const u_char * buf, int len, int user, int id, int channel) +{ + icn_card *card = icn_findcard(id); + + if (card) { + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + return (icn_writecmd(buf, len, user, card)); + } + printk(KERN_ERR + "icn: if_writecmd called with invalid driverId!\n"); + return -ENODEV; +} + +static int +if_readstatus(u_char * buf, int len, int user, int id, int channel) +{ + icn_card *card = icn_findcard(id); + + if (card) { + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + return (icn_readstatus(buf, len, user, card)); + } + printk(KERN_ERR + "icn: if_readstatus called with invalid driverId!\n"); + return -ENODEV; +} + +static int +if_sendbuf(int id, int channel, struct sk_buff *skb) +{ + icn_card *card = icn_findcard(id); + + if (card) { + if (!card->flags & ICN_FLAGS_RUNNING) + return -ENODEV; + return (icn_sendbuf(channel, skb, card)); + } + printk(KERN_ERR + "icn: if_sendbuf called with invalid driverId!\n"); + return -ENODEV; } /* * Allocate a new card-struct, initialize it * link it into cards-list and register it at linklevel. */ -static icn_card *icn_initcard(int port, char *id) { - icn_card *card; - int i; - - if (!(card = (icn_card *) kmalloc(sizeof(icn_card), GFP_KERNEL))) { - printk(KERN_WARNING - "icn: (%s) Could not allocate card-struct.\n", id); - return (icn_card *)0; - } - memset((char *) card, 0, sizeof(icn_card)); - card->port = port; - card->interface.channels = ICN_BCH; - card->interface.maxbufsize = 4000; - card->interface.command = if_command; +static icn_card * +icn_initcard(int port, char *id) +{ + icn_card *card; + int i; + + if (!(card = (icn_card *) kmalloc(sizeof(icn_card), GFP_KERNEL))) { + printk(KERN_WARNING + "icn: (%s) Could not allocate card-struct.\n", id); + return (icn_card *) 0; + } + memset((char *) card, 0, sizeof(icn_card)); + card->port = port; + card->interface.channels = ICN_BCH; + card->interface.maxbufsize = 4000; + card->interface.command = if_command; card->interface.writebuf_skb = if_sendbuf; - card->interface.writecmd = if_writecmd; - card->interface.readstat = if_readstatus; - card->interface.features = ISDN_FEATURE_L2_X75I | - ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L3_TRANS | - ISDN_FEATURE_P_UNKNOWN; - card->ptype = ISDN_PTYPE_UNKNOWN; - strncpy(card->interface.id, id, sizeof(card->interface.id) - 1); - card->msg_buf_write = card->msg_buf; - card->msg_buf_read = card->msg_buf; - card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1]; - for (i=0;il2_proto[i] = ISDN_PROTO_L2_X75I; - skb_queue_head_init(&card->spqueue[i]); - } - card->next = cards; - cards = card; - if (!register_isdn(&card->interface)) { - cards = cards->next; - printk(KERN_WARNING - "icn: Unable to register %s\n", id); - kfree(card); - return (icn_card*)0; - } - card->myid = card->interface.channels; - sprintf(card->regname, "icn-isdn (%s)", card->interface.id); - return card; -} - -static int icn_addcard(int port, char *id1, char *id2) -{ - ulong flags; - icn_card *card; - icn_card *card2; - - save_flags(flags); - cli(); - if (!(card = icn_initcard(port,id1))) { - restore_flags(flags); - return -EIO; - } - if (!strlen(id2)) { - restore_flags(flags); - printk(KERN_INFO - "icn: (%s) ICN-2B, port 0x%x added\n", - card->interface.id, port); - return 0; - } - if (!(card2 = icn_initcard(port,id2))) { - restore_flags(flags); - printk(KERN_INFO - "icn: (%s) half ICN-4B, port 0x%x added\n", - card2->interface.id, port); - return 0; - } - card->doubleS0 = 1; - card->secondhalf = 0; - card->other = card2; - card2->doubleS0 = 1; - card2->secondhalf = 1; - card2->other = card; - restore_flags(flags); - printk(KERN_INFO - "icn: (%s and %s) ICN-4B, port 0x%x added\n", - card->interface.id, card2->interface.id, port); - return 0; + card->interface.writecmd = if_writecmd; + card->interface.readstat = if_readstatus; + card->interface.features = ISDN_FEATURE_L2_X75I | + ISDN_FEATURE_L2_HDLC | + ISDN_FEATURE_L3_TRANS | + ISDN_FEATURE_P_UNKNOWN; + card->ptype = ISDN_PTYPE_UNKNOWN; + strncpy(card->interface.id, id, sizeof(card->interface.id) - 1); + card->msg_buf_write = card->msg_buf; + card->msg_buf_read = card->msg_buf; + card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1]; + for (i = 0; i < ICN_BCH; i++) { + card->l2_proto[i] = ISDN_PROTO_L2_X75I; + skb_queue_head_init(&card->spqueue[i]); + } + card->next = cards; + cards = card; + if (!register_isdn(&card->interface)) { + cards = cards->next; + printk(KERN_WARNING + "icn: Unable to register %s\n", id); + kfree(card); + return (icn_card *) 0; + } + card->myid = card->interface.channels; + sprintf(card->regname, "icn-isdn (%s)", card->interface.id); + return card; +} + +static int +icn_addcard(int port, char *id1, char *id2) +{ + ulong flags; + icn_card *card; + icn_card *card2; + + save_flags(flags); + cli(); + if (!(card = icn_initcard(port, id1))) { + restore_flags(flags); + return -EIO; + } + if (!strlen(id2)) { + restore_flags(flags); + printk(KERN_INFO + "icn: (%s) ICN-2B, port 0x%x added\n", + card->interface.id, port); + return 0; + } + if (!(card2 = icn_initcard(port, id2))) { + restore_flags(flags); + printk(KERN_INFO + "icn: (%s) half ICN-4B, port 0x%x added\n", + card2->interface.id, port); + return 0; + } + card->doubleS0 = 1; + card->secondhalf = 0; + card->other = card2; + card2->doubleS0 = 1; + card2->secondhalf = 1; + card2->other = card; + restore_flags(flags); + printk(KERN_INFO + "icn: (%s and %s) ICN-4B, port 0x%x added\n", + card->interface.id, card2->interface.id, port); + return 0; } #ifdef MODULE -EXPORT_NO_SYMBOLS; #define icn_init init_module #else -void icn_setup(char *str, int *ints) +void +icn_setup(char *str, int *ints) { - char *p; - static char sid[20]; - static char sid2[20]; - - if (ints[0]) - portbase = ints[1]; - if (ints[0]>1) - membase = ints[2]; - if (strlen(str)) { - strcpy(sid,str); - icn_id = sid; - if ((p = strchr(sid,','))) { - *p++ = 0; - strcpy(sid2,p); - icn_id2 = sid2; - } - } + char *p; + static char sid[20]; + static char sid2[20]; + + if (ints[0]) + portbase = ints[1]; + if (ints[0] > 1) + membase = ints[2]; + if (strlen(str)) { + strcpy(sid, str); + icn_id = sid; + if ((p = strchr(sid, ','))) { + *p++ = 0; + strcpy(sid2, p); + icn_id2 = sid2; + } + } } #endif -int icn_init(void) -{ - char *p; - char rev[10]; - - memset(&dev, 0, sizeof(icn_dev)); - dev.shmem = (icn_shmem *) ((unsigned long)membase & 0x0ffc000); - dev.channel = -1; - dev.mcard = NULL; - - if ((p = strchr(revision, ':'))) { - strcpy(rev, p + 1); - p = strchr(rev, '$'); - *p = 0; - } else - strcpy(rev, " ??? "); - printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev, - (ulong) dev.shmem); - return (icn_addcard(portbase,icn_id,icn_id2)); +int +icn_init(void) +{ + char *p; + char rev[10]; + + memset(&dev, 0, sizeof(icn_dev)); + dev.shmem = (icn_shmem *) ((unsigned long) membase & 0x0ffc000); + dev.channel = -1; + dev.mcard = NULL; + dev.firstload = 1; + + /* No symbols to export, hide all symbols */ +#if (LINUX_VERSION_CODE < 0x020111) + register_symtab(NULL); +#else + EXPORT_NO_SYMBOLS; +#endif + + if ((p = strchr(revision, ':'))) { + strcpy(rev, p + 1); + p = strchr(rev, '$'); + *p = 0; + } else + strcpy(rev, " ??? "); + printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev, + (ulong) dev.shmem); + return (icn_addcard(portbase, icn_id, icn_id2)); } #ifdef MODULE -void cleanup_module(void) +void +cleanup_module(void) { - isdn_ctrl cmd; - icn_card *card = cards; - icn_card *last; - int i; - - icn_stopallcards(); - while (card) { - cmd.command = ISDN_STAT_UNLOAD; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - if (card->rvalid) { - OUTB_P(0, ICN_RUN); /* Reset Controller */ - OUTB_P(0, ICN_MAPRAM); /* Disable RAM */ - if (card->secondhalf || (!card->doubleS0)) { - release_region(card->port, ICN_PORTLEN); - card->rvalid = 0; - } - for (i = 0; i < ICN_BCH; i++) - icn_free_queue(&card->spqueue[i]); - } - card = card->next; - } - card = cards; - while (card) { - last = card; - card = card->next; - kfree(last); - } - if (dev.mvalid) - release_shmem((ulong) dev.shmem, 0x4000); - printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n"); + isdn_ctrl cmd; + icn_card *card = cards; + icn_card *last; + int i; + + icn_stopallcards(); + while (card) { + cmd.command = ISDN_STAT_UNLOAD; + cmd.driver = card->myid; + card->interface.statcallb(&cmd); + if (card->rvalid) { + OUTB_P(0, ICN_RUN); /* Reset Controller */ + OUTB_P(0, ICN_MAPRAM); /* Disable RAM */ + if (card->secondhalf || (!card->doubleS0)) { + release_region(card->port, ICN_PORTLEN); + card->rvalid = 0; + } + for (i = 0; i < ICN_BCH; i++) + icn_free_queue(&card->spqueue[i]); + } + card = card->next; + } + card = cards; + while (card) { + last = card; + card = card->next; + kfree(last); + } + if (dev.mvalid) + release_shmem((ulong) dev.shmem, 0x4000); + printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n"); } #endif diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/icn/icn.h linux/drivers/isdn/icn/icn.h --- v2.1.26/linux/drivers/isdn/icn/icn.h Mon Nov 18 01:31:31 1996 +++ linux/drivers/isdn/icn/icn.h Tue Feb 25 17:12:49 1997 @@ -1,5 +1,5 @@ -/* $Id: icn.h,v 1.21 1996/08/29 20:35:57 fritz Exp $ - * +/* $Id: icn.h,v 1.26 1997/02/14 12:23:16 fritz Exp $ + * ISDN lowlevel-module for the ICN active ISDN-Card. * * Copyright 1994 by Fritz Elfert (fritz@wuemaus.franken.de) @@ -16,9 +16,26 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.h,v $ + * Revision 1.26 1997/02/14 12:23:16 fritz + * Added support for new insmod parameter handling. + * + * Revision 1.25 1997/02/10 10:10:31 fritz + * Changes for Kernel 2.1.X compatibility. + * Enhanced initialization, can recover from + * misconfiguration by other autoprobing drivers. + * + * Revision 1.24 1997/01/29 22:34:46 fritz + * Cleanup, Corrected D64S setup of 2nd channel. + * + * Revision 1.23 1996/12/17 18:47:55 tsbogend + * changed timeouts from absolute numbers to HZ based values + * + * Revision 1.22 1996/11/13 02:37:33 fritz + * Added delay include. + * * Revision 1.21 1996/08/29 20:35:57 fritz * Speed up B-Channel polling interval. * @@ -110,15 +127,14 @@ /* Struct for adding new cards */ typedef struct icn_cdef { - int port; - char id1[10]; - char id2[10]; + int port; + char id1[10]; + char id2[10]; } icn_cdef; #if defined(__KERNEL__) || defined(__DEBUGVAR__) #ifdef __KERNEL__ - /* Kernel includes */ #include @@ -128,7 +144,6 @@ #include #include #include -#include #include #include #include @@ -137,10 +152,10 @@ #include #include #include +#include #include - -#endif /* __KERNEL__ */ +#endif /* __KERNEL__ */ /* some useful macros for debugging */ #ifdef ICN_DEBUG_PORT @@ -154,138 +169,154 @@ #define ICN_PORTLEN (0x04) #define ICN_MEMADDR 0x0d0000 -#define ICN_FLAGS_B1ACTIVE 1 /* B-Channel-1 is open */ -#define ICN_FLAGS_B2ACTIVE 2 /* B-Channel-2 is open */ -#define ICN_FLAGS_RUNNING 4 /* Cards driver activated */ -#define ICN_FLAGS_RBTIMER 8 /* cyclic scheduling of B-Channel-poll */ - -#define ICN_BOOT_TIMEOUT1 100 /* Delay for Boot-download (jiffies) */ -#define ICN_CHANLOCK_DELAY 10 /* Delay for Channel-mapping (jiffies) */ - -#define ICN_TIMER_BCREAD 1 /* B-Channel poll-cycle */ -#define ICN_TIMER_DCREAD 50 /* D-Channel poll-cycle */ - -#define ICN_CODE_STAGE1 4096 /* Size of bootcode */ -#define ICN_CODE_STAGE2 65536 /* Size of protocol-code */ - -#define ICN_MAX_SQUEUE 8000 /* Max. outstanding send-data (2* hw-buf.) */ -#define ICN_FRAGSIZE (250) /* Max. size of send-fragments */ -#define ICN_BCH 2 /* Number of supported channels per card */ +#define ICN_FLAGS_B1ACTIVE 1 /* B-Channel-1 is open */ +#define ICN_FLAGS_B2ACTIVE 2 /* B-Channel-2 is open */ +#define ICN_FLAGS_RUNNING 4 /* Cards driver activated */ +#define ICN_FLAGS_RBTIMER 8 /* cyclic scheduling of B-Channel-poll */ + +#define ICN_BOOT_TIMEOUT1 (HZ) /* Delay for Boot-download (jiffies) */ +#define ICN_CHANLOCK_DELAY (HZ/10) /* Delay for Channel-mapping (jiffies) */ + +#define ICN_TIMER_BCREAD (HZ/100) /* B-Channel poll-cycle */ +#define ICN_TIMER_DCREAD (HZ/2) /* D-Channel poll-cycle */ + +#define ICN_CODE_STAGE1 4096 /* Size of bootcode */ +#define ICN_CODE_STAGE2 65536 /* Size of protocol-code */ + +#define ICN_MAX_SQUEUE 8000 /* Max. outstanding send-data (2* hw-buf.) */ +#define ICN_FRAGSIZE (250) /* Max. size of send-fragments */ +#define ICN_BCH 2 /* Number of supported channels per card */ /* type-definitions for accessing the mmap-io-areas */ -#define SHM_DCTL_OFFSET (0) /* Offset to data-controlstructures in shm */ -#define SHM_CCTL_OFFSET (0x1d2) /* Offset to comm-controlstructures in shm */ -#define SHM_CBUF_OFFSET (0x200) /* Offset to comm-buffers in shm */ -#define SHM_DBUF_OFFSET (0x2000) /* Offset to data-buffers in shm */ +#define SHM_DCTL_OFFSET (0) /* Offset to data-controlstructures in shm */ +#define SHM_CCTL_OFFSET (0x1d2) /* Offset to comm-controlstructures in shm */ +#define SHM_CBUF_OFFSET (0x200) /* Offset to comm-buffers in shm */ +#define SHM_DBUF_OFFSET (0x2000) /* Offset to data-buffers in shm */ /* * Layout of card's data buffers */ typedef struct { - unsigned char length; /* Bytecount of fragment (max 250) */ - unsigned char endflag; /* 0=last frag., 0xff=frag. continued */ - unsigned char data[ICN_FRAGSIZE]; /* The data */ - /* Fill to 256 bytes */ - char unused[0x100 - ICN_FRAGSIZE - 2]; + unsigned char length; /* Bytecount of fragment (max 250) */ + unsigned char endflag; /* 0=last frag., 0xff=frag. continued */ + unsigned char data[ICN_FRAGSIZE]; /* The data */ + /* Fill to 256 bytes */ + char unused[0x100 - ICN_FRAGSIZE - 2]; } frag_buf; /* * Layout of card's shared memory */ typedef union { - struct { - unsigned char scns; /* Index to free SendFrag. */ - unsigned char scnr; /* Index to active SendFrag READONLY */ - unsigned char ecns; /* Index to free RcvFrag. READONLY */ - unsigned char ecnr; /* Index to valid RcvFrag */ - char unused[6]; - unsigned short fuell1; /* Internal Buf Bytecount */ - } data_control; - struct { - char unused[SHM_CCTL_OFFSET]; - unsigned char iopc_i; /* Read-Ptr Status-Queue READONLY */ - unsigned char iopc_o; /* Write-Ptr Status-Queue */ - unsigned char pcio_i; /* Write-Ptr Command-Queue */ - unsigned char pcio_o; /* Read-Ptr Command Queue READONLY */ - } comm_control; - struct { - char unused[SHM_CBUF_OFFSET]; - unsigned char pcio_buf[0x100]; /* Ring-Buffer Command-Queue */ - unsigned char iopc_buf[0x100]; /* Ring-Buffer Status-Queue */ - } comm_buffers; - struct { - char unused[SHM_DBUF_OFFSET]; - frag_buf receive_buf[0x10]; - frag_buf send_buf[0x10]; - } data_buffers; + struct { + unsigned char scns; /* Index to free SendFrag. */ + unsigned char scnr; /* Index to active SendFrag READONLY */ + unsigned char ecns; /* Index to free RcvFrag. READONLY */ + unsigned char ecnr; /* Index to valid RcvFrag */ + char unused[6]; + unsigned short fuell1; /* Internal Buf Bytecount */ + } data_control; + struct { + char unused[SHM_CCTL_OFFSET]; + unsigned char iopc_i; /* Read-Ptr Status-Queue READONLY */ + unsigned char iopc_o; /* Write-Ptr Status-Queue */ + unsigned char pcio_i; /* Write-Ptr Command-Queue */ + unsigned char pcio_o; /* Read-Ptr Command Queue READONLY */ + } comm_control; + struct { + char unused[SHM_CBUF_OFFSET]; + unsigned char pcio_buf[0x100]; /* Ring-Buffer Command-Queue */ + unsigned char iopc_buf[0x100]; /* Ring-Buffer Status-Queue */ + } comm_buffers; + struct { + char unused[SHM_DBUF_OFFSET]; + frag_buf receive_buf[0x10]; + frag_buf send_buf[0x10]; + } data_buffers; } icn_shmem; /* * Per card driver data */ typedef struct icn_card { - struct icn_card *next; /* Pointer to next device struct */ - struct icn_card *other; /* Pointer to other card for ICN4B */ - unsigned short port; /* Base-port-address */ - int myid; /* Driver-Nr. assigned by linklevel */ - int rvalid; /* IO-portregion has been requested */ - int leased; /* Flag: This Adapter is connected */ - /* to a leased line */ - unsigned short flags; /* Statusflags */ - int doubleS0; /* Flag: ICN4B */ - int secondhalf; /* Flag: Second half of a doubleS0 */ - int fw_rev; /* Firmware revision loaded */ - int ptype; /* Protocol type (1TR6 or Euro) */ - struct timer_list st_timer; /* Timer for Status-Polls */ - struct timer_list rb_timer; /* Timer for B-Channel-Polls */ - u_char rcvbuf[ICN_BCH][4096]; /* B-Channel-Receive-Buffers */ - int rcvidx[ICN_BCH]; /* Index for above buffers */ - int l2_proto[ICN_BCH]; /* Current layer-2-protocol */ - isdn_if interface; /* Interface to upper layer */ - int iptr; /* Index to imsg-buffer */ - char imsg[60]; /* Internal buf for status-parsing */ - char msg_buf[2048]; /* Buffer for status-messages */ - char *msg_buf_write; /* Writepointer for statusbuffer */ - char *msg_buf_read; /* Readpointer for statusbuffer */ - char *msg_buf_end; /* Pointer to end of statusbuffer */ - int sndcount[ICN_BCH]; /* Byte-counters for B-Ch.-send */ - struct sk_buff_head - spqueue[ICN_BCH]; /* Sendqueue */ - char regname[35]; /* Name used for request_region */ - u_char xmit_lock[ICN_BCH]; /* Semaphore for pollbchan_send() */ + struct icn_card *next; /* Pointer to next device struct */ + struct icn_card *other; /* Pointer to other card for ICN4B */ + unsigned short port; /* Base-port-address */ + int myid; /* Driver-Nr. assigned by linklevel */ + int rvalid; /* IO-portregion has been requested */ + int leased; /* Flag: This Adapter is connected */ + /* to a leased line */ + unsigned short flags; /* Statusflags */ + int doubleS0; /* Flag: ICN4B */ + int secondhalf; /* Flag: Second half of a doubleS0 */ + int fw_rev; /* Firmware revision loaded */ + int ptype; /* Protocol type (1TR6 or Euro) */ + struct timer_list st_timer; /* Timer for Status-Polls */ + struct timer_list rb_timer; /* Timer for B-Channel-Polls */ + u_char rcvbuf[ICN_BCH][4096]; /* B-Channel-Receive-Buffers */ + int rcvidx[ICN_BCH]; /* Index for above buffers */ + int l2_proto[ICN_BCH]; /* Current layer-2-protocol */ + isdn_if interface; /* Interface to upper layer */ + int iptr; /* Index to imsg-buffer */ + char imsg[60]; /* Internal buf for status-parsing */ + char msg_buf[2048]; /* Buffer for status-messages */ + char *msg_buf_write; /* Writepointer for statusbuffer */ + char *msg_buf_read; /* Readpointer for statusbuffer */ + char *msg_buf_end; /* Pointer to end of statusbuffer */ + int sndcount[ICN_BCH]; /* Byte-counters for B-Ch.-send */ + struct sk_buff_head + spqueue[ICN_BCH]; /* Sendqueue */ + char regname[35]; /* Name used for request_region */ + u_char xmit_lock[ICN_BCH]; /* Semaphore for pollbchan_send() */ } icn_card; /* * Main driver data */ typedef struct icn_dev { - icn_shmem *shmem; /* Pointer to memory-mapped-buffers */ - int mvalid; /* IO-shmem has been requested */ - int channel; /* Currently mapped channel */ - struct icn_card *mcard; /* Currently mapped card */ - int chanlock; /* Semaphore for channel-mapping */ + icn_shmem *shmem; /* Pointer to memory-mapped-buffers */ + int mvalid; /* IO-shmem has been requested */ + int channel; /* Currently mapped channel */ + struct icn_card *mcard; /* Currently mapped card */ + int chanlock; /* Semaphore for channel-mapping */ + int firstload; /* Flag: firmware never loaded */ } icn_dev; typedef icn_dev *icn_devptr; #ifdef __KERNEL__ -static icn_card *cards = (icn_card *) 0; -static u_char chan2bank[] = { 0, 4, 8, 12 }; /* for icn_map_channel() */ +static icn_card *cards = (icn_card *) 0; +static u_char chan2bank[] = +{0, 4, 8, 12}; /* for icn_map_channel() */ -static icn_dev dev; +static icn_dev dev; /* With modutils >= 1.1.67 Integers can be changed while loading a * module. For this reason define the Port-Base an Shmem-Base as * integers. */ -int portbase = ICN_BASEADDR; -int membase = ICN_MEMADDR; -char *icn_id = "\0"; -char *icn_id2 = "\0"; +static int portbase = ICN_BASEADDR; +static int membase = ICN_MEMADDR; +static char *icn_id = "\0"; +static char *icn_id2 = "\0"; + +#ifdef MODULE +#if (LINUX_VERSION_CODE > 0x020111) +MODULE_AUTHOR("Fritz Elfert"); +MODULE_PARM(portbase, "i"); +MODULE_PARM_DESC(portbase, "Port adress of first card"); +MODULE_PARM(membase, "i"); +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"); +MODULE_PARM_DESC(icn_id2, "ID-String of first card, second S0 (4B only)"); +#endif +#endif -#endif /* __KERNEL__ */ +#endif /* __KERNEL__ */ /* Utility-Macros */ @@ -297,11 +328,11 @@ /* Return true, if there is a free transmit-buffer */ #define sbfree (((readb(&dev.shmem->data_control.scns)+1) & 0xf) != \ - readb(&dev.shmem->data_control.scnr)) + readb(&dev.shmem->data_control.scnr)) /* Switch to next transmit-buffer */ #define sbnext (writeb((readb(&dev.shmem->data_control.scns)+1) & 0xf, \ - &dev.shmem->data_control.scns)) + &dev.shmem->data_control.scns)) /* Shortcuts for transmit-buffer-access */ #define sbuf_n dev.shmem->data_control.scns @@ -311,11 +342,11 @@ /* Return true, if there is receive-data is available */ #define rbavl (readb(&dev.shmem->data_control.ecnr) != \ - readb(&dev.shmem->data_control.ecns)) + readb(&dev.shmem->data_control.ecns)) /* Switch to next receive-buffer */ #define rbnext (writeb((readb(&dev.shmem->data_control.ecnr)+1) & 0xf, \ - &dev.shmem->data_control.ecnr)) + &dev.shmem->data_control.ecnr)) /* Shortcuts for receive-buffer-access */ #define rbuf_n dev.shmem->data_control.ecnr @@ -329,8 +360,8 @@ /* Return free space in command-buffer */ #define cmd_free ((readb(&cmd_i)>=readb(&cmd_o))? \ - 0x100-readb(&cmd_i)+readb(&cmd_o): \ - readb(&cmd_o)-readb(&cmd_i)) + 0x100-readb(&cmd_i)+readb(&cmd_o): \ + readb(&cmd_o)-readb(&cmd_i)) /* Shortcuts for message-buffer-access */ #define msg_o (dev.shmem->comm_control.iopc_o) @@ -338,8 +369,8 @@ /* Return length of Message, if avail. */ #define msg_avail ((readb(&msg_o)>readb(&msg_i))? \ - 0x100-readb(&msg_o)+readb(&msg_i): \ - readb(&msg_i)-readb(&msg_o)) + 0x100-readb(&msg_o)+readb(&msg_i): \ + readb(&msg_i)-readb(&msg_o)) #define CID (card->interface.id) @@ -354,5 +385,5 @@ #define release_shmem release_region #define request_shmem request_region -#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */ -#endif /* icn_h */ +#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */ +#endif /* icn_h */ diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/isdn_audio.c linux/drivers/isdn/isdn_audio.c --- v2.1.26/linux/drivers/isdn/isdn_audio.c Fri Jun 7 06:02:40 1996 +++ linux/drivers/isdn/isdn_audio.c Tue Feb 25 17:12:50 1997 @@ -1,10 +1,10 @@ -/* $Id: isdn_audio.c,v 1.6 1996/06/06 14:43:31 fritz Exp $ - * +/* $Id: isdn_audio.c,v 1.7 1997/02/03 22:44:11 fritz Exp $ + * Linux ISDN subsystem, audio conversion and compression (linklevel). * * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) * DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at) - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) @@ -17,9 +17,12 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_audio.c,v $ + * Revision 1.7 1997/02/03 22:44:11 fritz + * Reformatted according CodingStyle + * * Revision 1.6 1996/06/06 14:43:31 fritz * Changed to support DTMF decoding on audio playback also. * @@ -47,154 +50,158 @@ #include "isdn_audio.h" #include "isdn_common.h" -char *isdn_audio_revision = "$Revision: 1.6 $"; +char *isdn_audio_revision = "$Revision: 1.7 $"; /* * Misc. lookup-tables. */ /* ulaw -> signed 16-bit */ -static short isdn_audio_ulaw_to_s16[] = { - 0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84, - 0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84, - 0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84, - 0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84, - 0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804, - 0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004, - 0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444, - 0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844, - 0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64, - 0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64, - 0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74, - 0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74, - 0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc, - 0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c, - 0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0, - 0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000, - 0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c, - 0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c, - 0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c, - 0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c, - 0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc, - 0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc, - 0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc, - 0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc, - 0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c, - 0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c, - 0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c, - 0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c, - 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, - 0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084, - 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, - 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000 +static short isdn_audio_ulaw_to_s16[] = +{ + 0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84, + 0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84, + 0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84, + 0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84, + 0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804, + 0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004, + 0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444, + 0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844, + 0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64, + 0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64, + 0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74, + 0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74, + 0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc, + 0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c, + 0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0, + 0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000, + 0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c, + 0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c, + 0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c, + 0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c, + 0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc, + 0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc, + 0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc, + 0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc, + 0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c, + 0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c, + 0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c, + 0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c, + 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, + 0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084, + 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, + 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000 }; /* alaw -> signed 16-bit */ -static short isdn_audio_alaw_to_s16[] = { - 0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4, - 0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74, - 0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4, - 0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64, - 0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4, - 0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4, - 0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4, - 0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4, - 0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64, - 0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34, - 0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844, - 0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24, - 0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64, - 0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4, - 0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964, - 0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4, - 0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24, - 0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94, - 0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924, - 0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94, - 0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24, - 0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14, - 0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24, - 0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14, - 0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4, - 0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54, - 0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4, - 0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64, - 0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4, - 0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4, - 0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4, - 0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4 +static short isdn_audio_alaw_to_s16[] = +{ + 0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4, + 0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74, + 0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4, + 0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64, + 0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4, + 0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4, + 0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4, + 0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4, + 0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64, + 0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34, + 0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844, + 0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24, + 0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64, + 0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4, + 0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964, + 0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4, + 0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24, + 0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94, + 0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924, + 0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94, + 0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24, + 0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14, + 0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24, + 0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14, + 0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4, + 0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54, + 0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4, + 0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64, + 0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4, + 0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4, + 0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4, + 0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4 }; /* alaw -> ulaw */ -static char isdn_audio_alaw_to_ulaw[] = { - 0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49, - 0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57, - 0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41, - 0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f, - 0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d, - 0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b, - 0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45, - 0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53, - 0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47, - 0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55, - 0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f, - 0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e, - 0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b, - 0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59, - 0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43, - 0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51, - 0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a, - 0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58, - 0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42, - 0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50, - 0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e, - 0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c, - 0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46, - 0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54, - 0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48, - 0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56, - 0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40, - 0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f, - 0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c, - 0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a, - 0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44, - 0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52 +static char isdn_audio_alaw_to_ulaw[] = +{ + 0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49, + 0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57, + 0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41, + 0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f, + 0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d, + 0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b, + 0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45, + 0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53, + 0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47, + 0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55, + 0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f, + 0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e, + 0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b, + 0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59, + 0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43, + 0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51, + 0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a, + 0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58, + 0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42, + 0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50, + 0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e, + 0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c, + 0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46, + 0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54, + 0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48, + 0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56, + 0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40, + 0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f, + 0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c, + 0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a, + 0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44, + 0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52 }; /* ulaw -> alaw */ -static char isdn_audio_ulaw_to_alaw[] = { - 0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35, - 0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25, - 0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d, - 0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d, - 0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31, - 0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21, - 0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9, - 0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9, - 0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47, - 0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf, - 0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f, - 0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33, - 0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23, - 0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b, - 0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b, - 0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b, - 0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34, - 0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24, - 0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c, - 0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c, - 0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30, - 0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20, - 0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8, - 0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8, - 0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46, - 0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde, - 0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e, - 0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32, - 0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22, - 0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a, - 0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a, - 0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a +static char isdn_audio_ulaw_to_alaw[] = +{ + 0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35, + 0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25, + 0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d, + 0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d, + 0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31, + 0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21, + 0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9, + 0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9, + 0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47, + 0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf, + 0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f, + 0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33, + 0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23, + 0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b, + 0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b, + 0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b, + 0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34, + 0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24, + 0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c, + 0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c, + 0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30, + 0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20, + 0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8, + 0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8, + 0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46, + 0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde, + 0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e, + 0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32, + 0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22, + 0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a, + 0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a, + 0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a }; #define NCOEFF 16 /* number of frequencies to be analyzed */ @@ -206,68 +213,72 @@ #define HIGRP 1 typedef struct { - int grp; /* low/high group */ - int k; /* k */ - int k2; /* k fuer 2. harmonic */ + int grp; /* low/high group */ + int k; /* k */ + int k2; /* k fuer 2. harmonic */ } dtmf_t; /* For DTMF recognition: * 2 * cos(2 * PI * k / N) precalculated for all k */ -static int cos2pik[NCOEFF] = { - 55812, 29528, 53603, 24032, 51193, 14443, 48590, 6517, - 38113, -21204, 33057, -32186, 25889, -45081, 18332, -55279 +static int cos2pik[NCOEFF] = +{ + 55812, 29528, 53603, 24032, 51193, 14443, 48590, 6517, + 38113, -21204, 33057, -32186, 25889, -45081, 18332, -55279 }; -static dtmf_t dtmf_tones[8] = { - { LOGRP, 0, 1 }, /* 697 Hz */ - { LOGRP, 2, 3 }, /* 770 Hz */ - { LOGRP, 4, 5 }, /* 852 Hz */ - { LOGRP, 6, 7 }, /* 941 Hz */ - { HIGRP, 8, 9 }, /* 1209 Hz */ - { HIGRP, 10, 11 }, /* 1336 Hz */ - { HIGRP, 12, 13 }, /* 1477 Hz */ - { HIGRP, 14, 15 } /* 1633 Hz */ +static dtmf_t dtmf_tones[8] = +{ + {LOGRP, 0, 1}, /* 697 Hz */ + {LOGRP, 2, 3}, /* 770 Hz */ + {LOGRP, 4, 5}, /* 852 Hz */ + {LOGRP, 6, 7}, /* 941 Hz */ + {HIGRP, 8, 9}, /* 1209 Hz */ + {HIGRP, 10, 11}, /* 1336 Hz */ + {HIGRP, 12, 13}, /* 1477 Hz */ + {HIGRP, 14, 15} /* 1633 Hz */ }; -static char dtmf_matrix[4][4] = { - {'1', '2', '3', 'A'}, - {'4', '5', '6', 'B'}, - {'7', '8', '9', 'C'}, - {'*', '0', '#', 'D'} +static char dtmf_matrix[4][4] = +{ + {'1', '2', '3', 'A'}, + {'4', '5', '6', 'B'}, + {'7', '8', '9', 'C'}, + {'*', '0', '#', 'D'} }; #if ((CPU == 386) || (CPU == 486) || (CPU == 586)) static inline void isdn_audio_tlookup(const void *table, void *buff, unsigned long n) { - __asm__("cld\n" - "1:\tlodsb\n\t" - "xlatb\n\t" - "stosb\n\t" - "loop 1b\n\t" - ::"b" ((long)table), "c" (n), "D" ((long)buff), "S" ((long)buff) - :"bx","cx","di","si","ax"); + __asm__("cld\n" + "1:\tlodsb\n\t" + "xlatb\n\t" + "stosb\n\t" + "loop 1b\n\t" + : : "b"((long) table), "c"(n), "D"((long) buff), "S"((long) buff) + : "bx", "cx", "di", "si", "ax"); } + #else static inline void isdn_audio_tlookup(const char *table, char *buff, unsigned long n) { - while (n--) - *buff++ = table[*buff]; + while (n--) + *buff++ = table[*buff]; } #endif void isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len) { - isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len); + isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len); } void isdn_audio_alaw2ulaw(unsigned char *buff, unsigned long len) { - isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len); + isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len); } /* @@ -278,207 +289,218 @@ */ -#define ZEROTRAP /* turn on the trap as per the MIL-STD */ +#define ZEROTRAP /* turn on the trap as per the MIL-STD */ #undef ZEROTRAP -#define BIAS 0x84 /* define the add-in bias for 16 bit samples */ +#define BIAS 0x84 /* define the add-in bias for 16 bit samples */ #define CLIP 32635 static unsigned char -isdn_audio_linear2ulaw(int sample) { - static int exp_lut[256] = { - 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 - }; - int sign, exponent, mantissa; - unsigned char ulawbyte; - - /* Get the sample into sign-magnitude. */ - sign = (sample >> 8) & 0x80; /* set aside the sign */ - if(sign != 0) sample = -sample; /* get magnitude */ - if(sample > CLIP) sample = CLIP; /* clip the magnitude */ - - /* Convert from 16 bit linear to ulaw. */ - sample = sample + BIAS; - exponent = exp_lut[( sample >> 7 ) & 0xFF]; - mantissa = (sample >> (exponent + 3)) & 0x0F; - ulawbyte = ~(sign | (exponent << 4) | mantissa); +isdn_audio_linear2ulaw(int sample) +{ + static int exp_lut[256] = + { + 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + }; + int sign, + exponent, + mantissa; + unsigned char ulawbyte; + + /* Get the sample into sign-magnitude. */ + sign = (sample >> 8) & 0x80; /* set aside the sign */ + if (sign != 0) + sample = -sample; /* get magnitude */ + if (sample > CLIP) + sample = CLIP; /* clip the magnitude */ + + /* Convert from 16 bit linear to ulaw. */ + sample = sample + BIAS; + exponent = exp_lut[(sample >> 7) & 0xFF]; + mantissa = (sample >> (exponent + 3)) & 0x0F; + ulawbyte = ~(sign | (exponent << 4) | mantissa); #ifdef ZEROTRAP - /* optional CCITT trap */ - if (ulawbyte == 0) ulawbyte = 0x02; + /* optional CCITT trap */ + if (ulawbyte == 0) + ulawbyte = 0x02; #endif - return(ulawbyte); + return (ulawbyte); } -static int Mx[3][8] = { - { 0x3800, 0x5600, 0,0,0,0,0,0 }, - { 0x399a, 0x3a9f, 0x4d14, 0x6607, 0,0,0,0 }, - { 0x3556, 0x3556, 0x399A, 0x3A9F, 0x4200, 0x4D14, 0x6607, 0x6607 }, +static int Mx[3][8] = +{ + {0x3800, 0x5600, 0, 0, 0, 0, 0, 0}, + {0x399a, 0x3a9f, 0x4d14, 0x6607, 0, 0, 0, 0}, + {0x3556, 0x3556, 0x399A, 0x3A9F, 0x4200, 0x4D14, 0x6607, 0x6607}, }; -static int bitmask[9] = { - 0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff -}; +static int bitmask[9] = +{ + 0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff +}; static int -isdn_audio_get_bits (adpcm_state *s, unsigned char **in, int *len) +isdn_audio_get_bits(adpcm_state * s, unsigned char **in, int *len) { - while( s->nleft < s->nbits) { - int d = *((*in)++); - (*len)--; - s->word = (s->word << 8) | d; - s->nleft += 8; - } - s->nleft -= s->nbits; - return (s->word >> s->nleft) & bitmask[s->nbits]; + while (s->nleft < s->nbits) { + int d = *((*in)++); + (*len)--; + s->word = (s->word << 8) | d; + s->nleft += 8; + } + s->nleft -= s->nbits; + return (s->word >> s->nleft) & bitmask[s->nbits]; } static void -isdn_audio_put_bits (int data, int nbits, adpcm_state *s, - unsigned char **out, int *len) +isdn_audio_put_bits(int data, int nbits, adpcm_state * s, + unsigned char **out, int *len) { - s->word = (s->word << nbits) | (data & bitmask[nbits]); - s->nleft += nbits; - while(s->nleft >= 8) { - int d = (s->word >> (s->nleft-8)); - *(out[0]++) = d & 255; - (*len)++; - s->nleft -= 8; - } + s->word = (s->word << nbits) | (data & bitmask[nbits]); + s->nleft += nbits; + while (s->nleft >= 8) { + int d = (s->word >> (s->nleft - 8)); + *(out[0]++) = d & 255; + (*len)++; + s->nleft -= 8; + } } adpcm_state * -isdn_audio_adpcm_init(adpcm_state *s, int nbits) +isdn_audio_adpcm_init(adpcm_state * s, int nbits) { - if (!s) - s = (adpcm_state *) kmalloc(sizeof(adpcm_state), GFP_ATOMIC); - if (s) { - s->a = 0; - s->d = 5; - s->word = 0; - s->nleft = 0; - s->nbits = nbits; - } - return s; + if (!s) + s = (adpcm_state *) kmalloc(sizeof(adpcm_state), GFP_ATOMIC); + if (s) { + s->a = 0; + s->d = 5; + s->word = 0; + s->nleft = 0; + s->nbits = nbits; + } + return s; } dtmf_state * -isdn_audio_dtmf_init(dtmf_state *s) +isdn_audio_dtmf_init(dtmf_state * s) { - if (!s) - s = (dtmf_state *) kmalloc(sizeof(dtmf_state), GFP_ATOMIC); - if (s) { - s->idx = 0; - s->last = ' '; - } - return s; + if (!s) + s = (dtmf_state *) kmalloc(sizeof(dtmf_state), GFP_ATOMIC); + if (s) { + s->idx = 0; + s->last = ' '; + } + return s; } /* * Decompression of adpcm data to a/u-law * */ - + int -isdn_audio_adpcm2xlaw (adpcm_state *s, int fmt, unsigned char *in, - unsigned char *out, int len) +isdn_audio_adpcm2xlaw(adpcm_state * s, int fmt, unsigned char *in, + unsigned char *out, int len) { - int a = s->a; - int d = s->d; - int nbits = s->nbits; - int olen = 0; - - while (len) { - int e = isdn_audio_get_bits(s, &in, &len); - int sign; - - if (nbits == 4 && e == 0) - d = 4; - sign = (e >> (nbits-1))?-1:1; - e &= bitmask[nbits-1]; - a += sign * ((e << 1) + 1) * d >> 1; - if (d & 1) - a++; - if (fmt) - *out++ = isdn_audio_ulaw_to_alaw[ - isdn_audio_linear2ulaw(a << 2)]; - else - *out++ = isdn_audio_linear2ulaw(a << 2); - olen++; - d = (d * Mx[nbits-2][ e ] + 0x2000) >> 14; - if ( d < 5 ) - d = 5; - } - s->a = a; - s->d = d; - return olen; + int a = s->a; + int d = s->d; + int nbits = s->nbits; + int olen = 0; + + while (len) { + int e = isdn_audio_get_bits(s, &in, &len); + int sign; + + if (nbits == 4 && e == 0) + d = 4; + sign = (e >> (nbits - 1)) ? -1 : 1; + e &= bitmask[nbits - 1]; + a += sign * ((e << 1) + 1) * d >> 1; + if (d & 1) + a++; + if (fmt) + *out++ = isdn_audio_ulaw_to_alaw[ + isdn_audio_linear2ulaw(a << 2)]; + else + *out++ = isdn_audio_linear2ulaw(a << 2); + olen++; + d = (d * Mx[nbits - 2][e] + 0x2000) >> 14; + if (d < 5) + d = 5; + } + s->a = a; + s->d = d; + return olen; } int -isdn_audio_2adpcm_flush (adpcm_state *s, unsigned char *out) +isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out) { int olen = 0; - if (s->nleft) - isdn_audio_put_bits(0, 8-s->nleft, s, &out, &olen); - return olen; + if (s->nleft) + isdn_audio_put_bits(0, 8 - s->nleft, s, &out, &olen); + return olen; } int -isdn_audio_xlaw2adpcm (adpcm_state *s, int fmt, unsigned char *in, - unsigned char *out, int len) +isdn_audio_xlaw2adpcm(adpcm_state * s, int fmt, unsigned char *in, + unsigned char *out, int len) { - int a = s->a; - int d = s->d; - int nbits = s->nbits; - int olen = 0; - - while (len--) { - int e = 0, nmax = 1 << (nbits - 1); - int sign, delta; - - if (fmt) - delta = (isdn_audio_alaw_to_s16[*in++] >> 2) - a; - else - delta = (isdn_audio_ulaw_to_s16[*in++] >> 2) - a; - if (delta < 0) { - e = nmax; - delta = -delta; - } - while( --nmax && delta > d ) { - delta -= d; - e++; - } - if (nbits == 4 && ((e & 0x0f) == 0)) - e = 8; - isdn_audio_put_bits(e, nbits, s, &out, &olen); - sign = (e >> (nbits-1))?-1:1 ; - e &= bitmask[nbits-1]; - - a += sign * ((e << 1) + 1) * d >> 1; - if (d & 1) - a++; - d = (d * Mx[nbits-2][ e ] + 0x2000) >> 14; - if (d < 5) - d=5; - } + int a = s->a; + int d = s->d; + int nbits = s->nbits; + int olen = 0; + + while (len--) { + int e = 0, + nmax = 1 << (nbits - 1); + int sign, + delta; + + if (fmt) + delta = (isdn_audio_alaw_to_s16[*in++] >> 2) - a; + else + delta = (isdn_audio_ulaw_to_s16[*in++] >> 2) - a; + if (delta < 0) { + e = nmax; + delta = -delta; + } + while (--nmax && delta > d) { + delta -= d; + e++; + } + if (nbits == 4 && ((e & 0x0f) == 0)) + e = 8; + isdn_audio_put_bits(e, nbits, s, &out, &olen); + sign = (e >> (nbits - 1)) ? -1 : 1; + e &= bitmask[nbits - 1]; + + a += sign * ((e << 1) + 1) * d >> 1; + if (d & 1) + a++; + d = (d * Mx[nbits - 2][e] + 0x2000) >> 14; + if (d < 5) + d = 5; + } s->a = a; s->d = d; - return olen; + return olen; } /* @@ -488,99 +510,108 @@ * Result is stored into an sk_buff and queued up for later * evaluation. */ -void -isdn_audio_goertzel(int *sample, modem_info *info) { - int sk, sk1, sk2; - int k, n; - struct sk_buff *skb; - int *result; - - skb = dev_alloc_skb(sizeof(int) * NCOEFF); - if (!skb) { - printk(KERN_WARNING - "isdn_audio: Could not alloc DTMF result for ttyI%d\n", - info->line); - return; - } - result = (int *)skb_put(skb, sizeof(int) * NCOEFF); - skb->free = 1; - skb->users = 0; - for (k = 0; k < NCOEFF; k++) { - sk = sk1 = sk2 = 0; - for (n = 0; n < DTMF_NPOINTS; n++) { - sk = sample[n] + ((cos2pik[k] * sk1) >> 15) - sk2; - sk2 = sk1; - sk1 = sk; - } - result[k] = - ((sk * sk) >> AMP_BITS) - - ((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) + - ((sk2 * sk2) >> AMP_BITS); - } - skb_queue_tail(&info->dtmf_queue, skb); - isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); +static void +isdn_audio_goertzel(int *sample, modem_info * info) +{ + int sk, + sk1, + sk2; + int k, + n; + struct sk_buff *skb; + int *result; + + skb = dev_alloc_skb(sizeof(int) * NCOEFF); + if (!skb) { + printk(KERN_WARNING + "isdn_audio: Could not alloc DTMF result for ttyI%d\n", + info->line); + return; + } + SET_SKB_FREE(skb); + if (skb_headroom(skb) < sizeof(isdn_audio_skb)) { + printk(KERN_WARNING + "isdn_audio: insufficient DTMF skb_headroom, dropping\n"); + dev_kfree_skb(skb, FREE_READ); + return; + } + result = (int *) skb_put(skb, sizeof(int) * NCOEFF); + ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; + for (k = 0; k < NCOEFF; k++) { + sk = sk1 = sk2 = 0; + for (n = 0; n < DTMF_NPOINTS; n++) { + sk = sample[n] + ((cos2pik[k] * sk1) >> 15) - sk2; + sk2 = sk1; + sk1 = sk; + } + result[k] = + ((sk * sk) >> AMP_BITS) - + ((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) + + ((sk2 * sk2) >> AMP_BITS); + } + skb_queue_tail(&info->dtmf_queue, skb); + isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); } void -isdn_audio_eval_dtmf(modem_info *info) +isdn_audio_eval_dtmf(modem_info * info) { - struct sk_buff *skb; - int *result; - dtmf_state *s; - int silence; - int i; - int di; - int ch; - unsigned long flags; - int grp[2]; - char what; - char *p; - - while ((skb = skb_dequeue(&info->dtmf_queue))) { - result = (int *)skb->data; - s = info->dtmf_state; - grp[LOGRP] = grp[HIGRP] = -2; - silence = 0; - for(i = 0; i < 8; i++) { - if ((result[dtmf_tones[i].k] > DTMF_TRESH) && - (result[dtmf_tones[i].k2] < H2_TRESH) ) - grp[dtmf_tones[i].grp] = (grp[dtmf_tones[i].grp] == -2)?i:-1; - else - if ((result[dtmf_tones[i].k] < SILENCE_TRESH) && - (result[dtmf_tones[i].k2] < SILENCE_TRESH) ) - silence++; - } - if(silence == 8) - what = ' '; - else { - if((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) { - what = dtmf_matrix[grp[LOGRP]][grp[HIGRP] - 4]; - if(s->last != ' ' && s->last != '.') - s->last = what; /* min. 1 non-DTMF between DTMF */ - } else - what = '.'; - } - if ((what != s->last) && (what != ' ') && (what != '.')) { - printk(KERN_DEBUG "dtmf: tt='%c'\n", what); - p = skb->data; - *p++ = 0x10; - *p = what; - skb_trim(skb, 2); - 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]); - } else - kfree_skb(skb, FREE_READ); - s->last = what; - } + struct sk_buff *skb; + int *result; + dtmf_state *s; + int silence; + int i; + int di; + int ch; + unsigned long flags; + int grp[2]; + char what; + char *p; + + while ((skb = skb_dequeue(&info->dtmf_queue))) { + result = (int *) skb->data; + s = info->dtmf_state; + grp[LOGRP] = grp[HIGRP] = -2; + silence = 0; + for (i = 0; i < 8; i++) { + if ((result[dtmf_tones[i].k] > DTMF_TRESH) && + (result[dtmf_tones[i].k2] < H2_TRESH)) + grp[dtmf_tones[i].grp] = (grp[dtmf_tones[i].grp] == -2) ? i : -1; + else if ((result[dtmf_tones[i].k] < SILENCE_TRESH) && + (result[dtmf_tones[i].k2] < SILENCE_TRESH)) + silence++; + } + if (silence == 8) + what = ' '; + else { + if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) { + what = dtmf_matrix[grp[LOGRP]][grp[HIGRP] - 4]; + if (s->last != ' ' && s->last != '.') + s->last = what; /* min. 1 non-DTMF between DTMF */ + } else + what = '.'; + } + if ((what != s->last) && (what != ' ') && (what != '.')) { + printk(KERN_DEBUG "dtmf: tt='%c'\n", what); + p = skb->data; + *p++ = 0x10; + *p = what; + skb_trim(skb, 2); + 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]); + } else + kfree_skb(skb, FREE_READ); + s->last = what; + } } /* @@ -593,30 +624,28 @@ * fmt = audio data format (0 = ulaw, 1 = alaw) */ void -isdn_audio_calc_dtmf(modem_info *info, unsigned char *buf, int len, int fmt) +isdn_audio_calc_dtmf(modem_info * info, unsigned char *buf, int len, int fmt) { - dtmf_state *s = info->dtmf_state; - int i; - int c; - - while (len) { - c = MIN(len, (DTMF_NPOINTS - s->idx)); - if (c <= 0) - break; - for (i = 0; i < c; i++) { - if (fmt) - s->buf[s->idx++] = - isdn_audio_alaw_to_s16[*buf++] >> (15 - AMP_BITS); - else - s->buf[s->idx++] = - isdn_audio_ulaw_to_s16[*buf++] >> (15 - AMP_BITS); - } - if (s->idx == DTMF_NPOINTS) { - isdn_audio_goertzel(s->buf, info); - s->idx = 0; - } - len -= c; - } + dtmf_state *s = info->dtmf_state; + int i; + int c; + + while (len) { + c = MIN(len, (DTMF_NPOINTS - s->idx)); + if (c <= 0) + break; + for (i = 0; i < c; i++) { + if (fmt) + s->buf[s->idx++] = + isdn_audio_alaw_to_s16[*buf++] >> (15 - AMP_BITS); + else + s->buf[s->idx++] = + isdn_audio_ulaw_to_s16[*buf++] >> (15 - AMP_BITS); + } + if (s->idx == DTMF_NPOINTS) { + isdn_audio_goertzel(s->buf, info); + s->idx = 0; + } + len -= c; + } } - - diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/isdn_audio.h linux/drivers/isdn/isdn_audio.h --- v2.1.26/linux/drivers/isdn/isdn_audio.h Fri Jun 7 06:02:40 1996 +++ linux/drivers/isdn/isdn_audio.h Tue Feb 25 17:12:50 1997 @@ -1,9 +1,9 @@ -/* $Id: isdn_audio.h,v 1.4 1996/06/06 14:43:32 fritz Exp $ - * +/* $Id: isdn_audio.h,v 1.5 1997/02/03 22:45:21 fritz Exp $ + * Linux ISDN subsystem, audio conversion and compression (linklevel). * * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.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 * the Free Software Foundation; either version 2, or (at your option) @@ -16,9 +16,12 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_audio.h,v $ + * Revision 1.5 1997/02/03 22:45:21 fritz + * Reformatted according CodingStyle + * * Revision 1.4 1996/06/06 14:43:32 fritz * Changed to support DTMF decoding on audio playback also. * @@ -33,27 +36,27 @@ * */ -#define DTMF_NPOINTS 205 /* Number of samples for DTMF recognition */ +#define DTMF_NPOINTS 205 /* Number of samples for DTMF recognition */ typedef struct adpcm_state { - int a; - int d; - int word; - int nleft; - int nbits; + int a; + int d; + int word; + int nleft; + int nbits; } adpcm_state; typedef struct dtmf_state { - char last; - int idx; - int buf[DTMF_NPOINTS]; + char last; + int idx; + int buf[DTMF_NPOINTS]; } dtmf_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); -extern int isdn_audio_adpcm2xlaw(adpcm_state *, int, unsigned char *, unsigned char *, int); -extern int isdn_audio_xlaw2adpcm(adpcm_state *, int, unsigned char *, unsigned char *, int); -extern int isdn_audio_2adpcm_flush(adpcm_state *s, unsigned char *out); +extern int isdn_audio_adpcm2xlaw(adpcm_state *, int, unsigned char *, unsigned char *, int); +extern int isdn_audio_xlaw2adpcm(adpcm_state *, int, unsigned char *, unsigned char *, int); +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 *); diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/isdn_cards.c linux/drivers/isdn/isdn_cards.c --- v2.1.26/linux/drivers/isdn/isdn_cards.c Sun Apr 21 01:56:14 1996 +++ linux/drivers/isdn/isdn_cards.c Tue Feb 25 17:12:50 1997 @@ -1,9 +1,9 @@ -/* $Id: isdn_cards.c,v 1.1 1996/04/20 16:04:36 fritz Exp $ - * +/* $Id: isdn_cards.c,v 1.3 1997/02/03 23:31:14 fritz Exp $ + * Linux ISDN subsystem, initialization for non-modularized drivers. * * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.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 * the Free Software Foundation; either version 2, or (at your option) @@ -16,9 +16,15 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_cards.c,v $ + * Revision 1.3 1997/02/03 23:31:14 fritz + * Reformatted according CodingStyle + * + * Revision 1.2 1996/10/13 19:52:17 keil + * HiSax support + * * Revision 1.1 1996/04/20 16:04:36 fritz * Initial revision * @@ -34,20 +40,27 @@ extern void teles_init(void); #endif +#ifdef CONFIG_ISDN_DRV_HISAX +extern void HiSax_init(void); +#endif + #ifdef CONFIG_ISDN_DRV_PCBIT extern void pcbit_init(void); #endif -void isdn_cards_init(void) +void +isdn_cards_init(void) { #if CONFIG_ISDN_DRV_ICN - icn_init(); + icn_init(); #endif #if CONFIG_ISDN_DRV_TELES - teles_init(); + teles_init(); +#endif +#ifdef CONFIG_ISDN_DRV_HISAX + HiSax_init(); #endif #if CONFIG_ISDN_DRV_PCBIT - pcbit_init(); + pcbit_init(); #endif } - diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/isdn_cards.h linux/drivers/isdn/isdn_cards.h --- v2.1.26/linux/drivers/isdn/isdn_cards.h Sun Apr 21 01:56:14 1996 +++ linux/drivers/isdn/isdn_cards.h Tue Feb 25 17:12:50 1997 @@ -1,9 +1,9 @@ -/* $Id: isdn_cards.h,v 1.1 1996/04/20 16:04:03 fritz Exp $ - * +/* $Id: isdn_cards.h,v 1.2 1997/02/03 23:31:55 fritz Exp $ + * Linux ISDN subsystem, initialization for non-modularized drivers. * * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.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 * the Free Software Foundation; either version 2, or (at your option) @@ -16,13 +16,15 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_cards.h,v $ + * Revision 1.2 1997/02/03 23:31:55 fritz + * Reformatted according CodingStyle + * * Revision 1.1 1996/04/20 16:04:03 fritz * Initial revision * */ extern void isdn_cards_init(void); - diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- v2.1.26/linux/drivers/isdn/isdn_common.c Fri Dec 27 02:03:22 1996 +++ linux/drivers/isdn/isdn_common.c Tue Feb 25 17:12:50 1997 @@ -1,5 +1,5 @@ -/* $Id: isdn_common.c,v 1.23 1996/06/25 18:35:38 fritz Exp $ - * +/* $Id: isdn_common.c,v 1.34 1997/02/10 20:12:43 fritz Exp $ + * Linux ISDN subsystem, common used functions (linklevel). * * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) @@ -21,6 +21,48 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_common.c,v $ + * Revision 1.34 1997/02/10 20:12:43 fritz + * Changed interface for reporting incoming calls. + * + * Revision 1.33 1997/02/10 10:05:42 fritz + * More changes for Kernel 2.1.X + * Symbol information moved to isdn_syms.c + * + * Revision 1.32 1997/02/03 22:55:26 fritz + * Reformatted according CodingStyle. + * Changed isdn_writebuf_stub static. + * Slow down tty-RING counter. + * skb->free stuff replaced by macro. + * Bugfix in audio-skb locking. + * Bugfix in HL-driver locking. + * + * Revision 1.31 1997/01/17 01:19:18 fritz + * Applied chargeint patch. + * + * Revision 1.30 1997/01/14 01:27:47 fritz + * Changed audio receive not to rely on skb->users and skb->lock. + * Added ATI2 and related variables. + * Started adding full-duplex audio capability. + * + * Revision 1.29 1997/01/12 23:33:03 fritz + * Made isdn_all_eaz foolproof. + * + * Revision 1.28 1996/11/13 02:33:19 fritz + * Fixed a race condition. + * + * Revision 1.27 1996/10/27 22:02:41 keil + * return codes for ISDN_STAT_ICALL + * + * Revision 1.26 1996/10/23 11:59:40 fritz + * More compatibility changes. + * + * Revision 1.25 1996/10/22 23:13:54 fritz + * Changes for compatibility to 2.0.X and 2.1.X kernels. + * + * Revision 1.24 1996/10/11 14:02:03 fritz + * Bugfix: call to isdn_ppp_timer_timeout() never compiled, because of + * typo in #ifdef. + * * Revision 1.23 1996/06/25 18:35:38 fritz * Fixed bogus memory access in isdn_set_allcfg(). * @@ -117,13 +159,14 @@ * */ -#include #include +#define __NO_VERSION__ #include #include -#ifndef __GENKSYMS__ /* Don't want genksyms report unneeded structs */ -#include +#if (LINUX_VERSION_CODE >= 0x020117) +#include #endif +#include #include "isdn_common.h" #include "isdn_tty.h" #include "isdn_net.h" @@ -139,8 +182,7 @@ isdn_dev *dev = (isdn_dev *) 0; -static int has_exported = 0; -static char *isdn_revision = "$Revision: 1.23 $"; +static char *isdn_revision = "$Revision: 1.34 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -155,18 +197,23 @@ static char *isdn_audio_revision = ": none $"; #endif -void isdn_MOD_INC_USE_COUNT(void) +static int isdn_writebuf_stub(int, int, const u_char *, int, int); + +void +isdn_MOD_INC_USE_COUNT(void) { MOD_INC_USE_COUNT; } -void isdn_MOD_DEC_USE_COUNT(void) +void +isdn_MOD_DEC_USE_COUNT(void) { MOD_DEC_USE_COUNT; } #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) -void isdn_dumppkt(char *s, u_char * p, int len, int dumplen) +void +isdn_dumppkt(char *s, u_char * p, int len, int dumplen) { int dumpc; @@ -177,26 +224,29 @@ } #endif -static __inline void isdn_trash_skb(struct sk_buff *skb, int rw) +static __inline void +isdn_trash_skb(struct sk_buff *skb, int rw) { - skb->free = 1; - kfree_skb(skb, rw); + SET_SKB_FREE(skb); + kfree_skb(skb, rw); } -static void isdn_free_queue(struct sk_buff_head *queue) +static void +isdn_free_queue(struct sk_buff_head *queue) { - struct sk_buff *skb; - unsigned long flags; + struct sk_buff *skb; + unsigned long flags; - save_flags(flags); - cli(); - if (skb_queue_len(queue)) - while ((skb = skb_dequeue(queue))) - isdn_trash_skb(skb, FREE_READ); - restore_flags(flags); + save_flags(flags); + cli(); + if (skb_queue_len(queue)) + while ((skb = skb_dequeue(queue))) + isdn_trash_skb(skb, FREE_READ); + restore_flags(flags); } -int isdn_dc2minor(int di, int ch) +int +isdn_dc2minor(int di, int ch) { int i; for (i = 0; i < ISDN_MAX_CHANNELS; i++) @@ -207,8 +257,10 @@ static int isdn_timer_cnt1 = 0; static int isdn_timer_cnt2 = 0; +static int isdn_timer_cnt3 = 0; -static void isdn_timer_funct(ulong dummy) +static void +isdn_timer_funct(ulong dummy) { int tf = dev->tflags; @@ -226,26 +278,29 @@ if (tf & ISDN_TIMER_NETDIAL) isdn_net_dial(); } - if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) { - isdn_timer_cnt2 = 0; - if (tf & ISDN_TIMER_NETHANGUP) - isdn_net_autohup(); - if (tf & ISDN_TIMER_MODEMRING) - isdn_tty_modem_ring(); -#if (defined CONFIG_ISDN_PPP ) && (defined ISDN_CONFIG_MPP) - if (tf & ISDN_TIMER_IPPP) - isdn_ppp_timer_timeout(); + if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) { + isdn_timer_cnt2 = 0; + if (tf & ISDN_TIMER_NETHANGUP) + isdn_net_autohup(); + if (++isdn_timer_cnt3 > ISDN_TIMER_RINGING) { + isdn_timer_cnt3 = 0; + if (tf & ISDN_TIMER_MODEMRING) + isdn_tty_modem_ring(); + } +#if (defined CONFIG_ISDN_PPP) && (defined CONFIG_ISDN_MPP) + if (tf & ISDN_TIMER_IPPP) + isdn_ppp_timer_timeout(); #endif - } + } } if (tf) { - int flags; + int flags; save_flags(flags); cli(); - del_timer(&dev->timer); + del_timer(&dev->timer); #ifndef NEW_ISDN_TIMER_CTRL - dev->timer.function = isdn_timer_funct; + dev->timer.function = isdn_timer_funct; #endif dev->timer.expires = jiffies + ISDN_TIMER_RES; add_timer(&dev->timer); @@ -253,7 +308,8 @@ } } -void isdn_timer_ctrl(int tf, int onoff) +void +isdn_timer_ctrl(int tf, int onoff) { int flags; @@ -270,14 +326,14 @@ dev->tflags &= ~tf; #ifdef NEW_ISDN_TIMER_CTRL if (dev->tflags) { - if (!del_timer(&dev->timer)) /* del_timer is 1, when active */ - dev->timer.expires = jiffies + ISDN_TIMER_RES; + if (!del_timer(&dev->timer)) /* del_timer is 1, when active */ + dev->timer.expires = jiffies + ISDN_TIMER_RES; add_timer(&dev->timer); } #else if (dev->tflags) { - del_timer(&dev->timer); - dev->timer.function = isdn_timer_funct; + del_timer(&dev->timer); + dev->timer.function = isdn_timer_funct; dev->timer.expires = jiffies + ISDN_TIMER_RES; add_timer(&dev->timer); } @@ -288,258 +344,277 @@ /* * Receive a packet from B-Channel. (Called from low-level-module) */ -static void isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb) +static void +isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb) { ulong flags; int i; - int midx; + int midx; #ifdef CONFIG_ISDN_AUDIO - int ifmt; + int ifmt; #endif modem_info *info; - if ((i = isdn_dc2minor(di,channel))==-1) { - isdn_trash_skb(skb, FREE_READ); - return; - } + if ((i = isdn_dc2minor(di, channel)) == -1) { + isdn_trash_skb(skb, FREE_READ); + return; + } /* Update statistics */ - dev->ibytes[i] += skb->len; + dev->ibytes[i] += skb->len; /* First, try to deliver data to network-device */ if (isdn_net_rcv_skb(i, skb)) return; /* No network-device found, deliver to tty or raw-channel */ - skb->free = 1; + SET_SKB_FREE(skb); if (skb->len) { - if ((midx = dev->m_idx[i])<0) { - /* if midx is invalid, drop packet */ - isdn_trash_skb(skb, FREE_READ); - return; - } - info = &dev->mdm.info[midx]; + if ((midx = dev->m_idx[i]) < 0) { + /* if midx is invalid, drop packet */ + isdn_trash_skb(skb, FREE_READ); + return; + } + info = &dev->mdm.info[midx]; #ifdef CONFIG_ISDN_AUDIO - ifmt = 1; + ifmt = 1; - if (info->vonline) - isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt); + if (info->vonline) + isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt); #endif - if ((info->online < 2) && - (!(info->vonline & 1))) { - /* If Modem not listening, drop data */ - isdn_trash_skb(skb, FREE_READ); - return; - } - if (info->emu.mdmreg[13] & 2) - /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */ - if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1))) - skb_pull(skb,4); - /* The users field of an sk_buff is used in a special way - * with tty's incoming data: - * users is set to the number of DLE codes when in audio mode. - */ - skb->users = 0; + if ((info->online < 2) && + (!(info->vonline & 1))) { + /* If Modem not listening, drop data */ + isdn_trash_skb(skb, FREE_READ); + return; + } + if (info->emu.mdmreg[13] & 2) + /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */ + if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1))) + skb_pull(skb, 4); + if (skb_headroom(skb) < sizeof(isdn_audio_skb)) { + printk(KERN_WARNING + "isdn_audio: insufficient skb_headroom, dropping\n"); + isdn_trash_skb(skb, FREE_READ); + return; + } + ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; + ISDN_AUDIO_SKB_LOCK(skb) = 0; #ifdef CONFIG_ISDN_AUDIO - if (info->vonline & 1) { - /* voice conversion/compression */ - switch (info->emu.vpar[3]) { - case 2: - case 3: - case 4: - /* adpcm - * Since compressed data takes less - * space, we can overwrite the buffer. - */ - skb_trim(skb,isdn_audio_xlaw2adpcm(info->adpcmr, - ifmt, - skb->data, - skb->data, - skb->len)); - break; - case 5: - /* a-law */ - if (!ifmt) - isdn_audio_ulaw2alaw(skb->data,skb->len); - break; - case 6: - /* u-law */ - if (ifmt) - isdn_audio_alaw2ulaw(skb->data,skb->len); - break; - } - skb->users = isdn_tty_countDLE(skb->data,skb->len); - } -#endif - /* Try to deliver directly via tty-flip-buf if queue is empty */ - save_flags(flags); - cli(); - if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) - if (isdn_tty_try_read(info, skb)) { - restore_flags(flags); - return; - } - /* Direct deliver failed or queue wasn't empty. - * Queue up for later dequeueing via timer-irq. - */ - __skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb); - dev->drv[di]->rcvcount[channel] += (skb->len + skb->users); - 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[channel]); + if (info->vonline & 1) { + /* voice conversion/compression */ + switch (info->emu.vpar[3]) { + case 2: + case 3: + case 4: + /* adpcm + * Since compressed data takes less + * space, we can overwrite the buffer. + */ + skb_trim(skb, isdn_audio_xlaw2adpcm(info->adpcmr, + ifmt, + skb->data, + skb->data, + skb->len)); + break; + case 5: + /* a-law */ + if (!ifmt) + isdn_audio_ulaw2alaw(skb->data, skb->len); + break; + case 6: + /* u-law */ + if (ifmt) + isdn_audio_alaw2ulaw(skb->data, skb->len); + break; + } + ISDN_AUDIO_SKB_DLECOUNT(skb) = + isdn_tty_countDLE(skb->data, skb->len); + } +#endif + /* Try to deliver directly via tty-flip-buf if queue is empty */ + save_flags(flags); + cli(); + if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) + if (isdn_tty_try_read(info, skb)) { + restore_flags(flags); + return; + } + /* Direct deliver failed or queue wasn't empty. + * Queue up for later dequeueing via timer-irq. + */ + __skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb); + dev->drv[di]->rcvcount[channel] += + (skb->len + ISDN_AUDIO_SKB_DLECOUNT(skb)); + 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[channel]); } else - isdn_trash_skb(skb, FREE_READ); + isdn_trash_skb(skb, FREE_READ); } -void isdn_all_eaz(int di, int ch) +void +isdn_all_eaz(int di, int ch) { isdn_ctrl cmd; + if (di < 0) + return; cmd.driver = di; cmd.arg = ch; cmd.command = ISDN_CMD_SETEAZ; - cmd.num[0] = '\0'; + cmd.parm.num[0] = '\0'; (void) dev->drv[di]->interface->command(&cmd); } -static int isdn_status_callback(isdn_ctrl * c) +static int +isdn_status_callback(isdn_ctrl * c) { int di; int mi; ulong flags; int i; int r; - modem_info *info; + int retval = 0; + modem_info *info; isdn_ctrl cmd; di = c->driver; - i = isdn_dc2minor(di, c->arg); + i = isdn_dc2minor(di, c->arg); switch (c->command) { - case ISDN_STAT_BSENT: - if (i<0) + case ISDN_STAT_BSENT: + if (i < 0) return -1; - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - if (isdn_net_stat_callback(i, c->command)) - return 0; - isdn_tty_bsent(di, c->arg); - wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]); - break; - case ISDN_STAT_STAVAIL: - save_flags(flags); - cli(); - dev->drv[di]->stavail += c->arg; - restore_flags(flags); - wake_up_interruptible(&dev->drv[di]->st_waitq); - break; - case ISDN_STAT_RUN: - dev->drv[di]->running = 1; - 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; - break; - case ISDN_STAT_ICALL: - if (i<0) + if (dev->global_flags & ISDN_GLOBAL_STOPPED) + return 0; + if (isdn_net_stat_callback(i, c->command)) + return 0; + isdn_tty_bsent(di, c->arg); + wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]); + break; + case ISDN_STAT_STAVAIL: + save_flags(flags); + cli(); + dev->drv[di]->stavail += c->arg; + restore_flags(flags); + wake_up_interruptible(&dev->drv[di]->st_waitq); + break; + case ISDN_STAT_RUN: + dev->drv[di]->running = 1; + 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; + break; + case ISDN_STAT_ICALL: + if (i < 0) return -1; #ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->num); + printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->num); #endif - if (dev->global_flags & ISDN_GLOBAL_STOPPED) { - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_HANGUP; - dev->drv[di]->interface->command(&cmd); - return 0; - } - + if (dev->global_flags & ISDN_GLOBAL_STOPPED) { + cmd.driver = di; + cmd.arg = c->arg; + cmd.command = ISDN_CMD_HANGUP; + dev->drv[di]->interface->command(&cmd); + 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; - dev->drv[di]->interface->command(&cmd); - r = isdn_net_find_icall(di, c->arg, i, c->num); + cmd.driver = di; + cmd.arg = c->arg; + cmd.command = ISDN_CMD_LOCK; + dev->drv[di]->interface->command(&cmd); + r = isdn_net_find_icall(di, c->arg, i, c->parm.setup); switch (r) { - case 0: - /* No network-device replies. Schedule RING-message to - * tty and set RI-bit of modem-status. - */ - if ((mi = isdn_tty_find_icall(di, c->arg, c->num)) >= 0) { - info = &dev->mdm.info[mi]; - info->msr |= UART_MSR_RI; - isdn_tty_modem_result(2, info); - isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1); - return 0; - } else if (dev->drv[di]->reject_bus) { - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_HANGUP; - dev->drv[di]->interface->command(&cmd); - } - break; - case 1: - /* Schedule connection-setup */ - isdn_net_dial(); - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_ACCEPTD; - dev->drv[di]->interface->command(&cmd); - return 0; - break; - case 2: /* For calling back, first reject incoming call ... */ - case 3: /* Interface found, but down, reject call actively */ - printk(KERN_INFO "isdn: Rejecting Call\n"); - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_HANGUP; - dev->drv[di]->interface->command(&cmd); - if (r == 3) - break; - /* Fall through */ - case 4: - /* ... then start callback. */ - isdn_net_dial(); - return 0; + case 0: + /* No network-device replies. Schedule RING-message to + * tty and set RI-bit of modem-status. + */ + if ((mi = isdn_tty_find_icall(di, c->arg, c->parm.setup)) >= 0) { + info = &dev->mdm.info[mi]; + info->msr |= UART_MSR_RI; + isdn_tty_modem_result(2, info); + isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1); + retval = 1; + } else if (dev->drv[di]->reject_bus) { + cmd.driver = di; + cmd.arg = c->arg; + cmd.command = ISDN_CMD_HANGUP; + dev->drv[di]->interface->command(&cmd); + retval = 2; + } + break; + case 1: + /* Schedule connection-setup */ + isdn_net_dial(); + cmd.driver = di; + cmd.arg = c->arg; + cmd.command = ISDN_CMD_ACCEPTD; + dev->drv[di]->interface->command(&cmd); + retval = 1; + break; + case 2: /* For calling back, first reject incoming call ... */ + case 3: /* Interface found, but down, reject call actively */ + retval = 2; + printk(KERN_INFO "isdn: Rejecting Call\n"); + cmd.driver = di; + cmd.arg = c->arg; + cmd.command = ISDN_CMD_HANGUP; + dev->drv[di]->interface->command(&cmd); + if (r == 3) + break; + /* Fall through */ + case 4: + /* ... then start callback. */ + isdn_net_dial(); + break; + } + if (retval != 1) { + cmd.driver = di; + cmd.arg = c->arg; + cmd.command = ISDN_CMD_UNLOCK; + dev->drv[di]->interface->command(&cmd); } - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_UNLOCK; - dev->drv[di]->interface->command(&cmd); - return 0; - break; - case ISDN_STAT_CINF: - if (i<0) + return retval; + break; + case ISDN_STAT_CINF: + if (i < 0) return -1; #ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->num); + printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->num); #endif - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - if (strcmp(c->num, "0")) - isdn_net_stat_callback(i, c->command); - break; - case ISDN_STAT_CAUSE: + if (dev->global_flags & ISDN_GLOBAL_STOPPED) + return 0; + if (strcmp(c->parm.num, "0")) + isdn_net_stat_callback(i, c->command); + break; + case ISDN_STAT_CAUSE: #ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->num); + printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->num); #endif - printk(KERN_INFO "isdn: cause: %s\n", c->num); - break; - case ISDN_STAT_DCONN: - if (i<0) + printk(KERN_INFO "isdn: cause: %s\n", c->parm.num); + if ((mi = dev->m_idx[i]) >= 0) { + /* Signal cause to tty-device */ + info = &dev->mdm.info[mi]; + strncpy(info->last_cause, c->parm.num, 5); + } + break; + case ISDN_STAT_DCONN: + if (i < 0) return -1; #ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "DCONN: %ld\n", c->arg); + printk(KERN_DEBUG "DCONN: %ld\n", c->arg); #endif - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - /* Find any network-device, waiting for D-channel setup */ - if (isdn_net_stat_callback(i, c->command)) - break; + if (dev->global_flags & ISDN_GLOBAL_STOPPED) + return 0; + /* Find any network-device, waiting for D-channel setup */ + if (isdn_net_stat_callback(i, c->command)) + break; if ((mi = dev->m_idx[i]) >= 0) { /* If any tty has just dialed-out, setup B-Channel */ - info = &dev->mdm.info[mi]; + info = &dev->mdm.info[mi]; if (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) { if (info->dialing == 1) { @@ -551,24 +626,24 @@ return 0; } } - } - break; - case ISDN_STAT_DHUP: - if (i<0) + } + break; + case ISDN_STAT_DHUP: + if (i < 0) return -1; #ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "DHUP: %ld\n", c->arg); + printk(KERN_DEBUG "DHUP: %ld\n", c->arg); #endif - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - dev->drv[di]->flags &= ~(1 << (c->arg)); - isdn_info_update(); - /* Signal hangup to network-devices */ - if (isdn_net_stat_callback(i, c->command)) - break; + if (dev->global_flags & ISDN_GLOBAL_STOPPED) + return 0; + dev->drv[di]->flags &= ~(1 << (c->arg)); + isdn_info_update(); + /* Signal hangup to network-devices */ + if (isdn_net_stat_callback(i, c->command)) + break; if ((mi = dev->m_idx[i]) >= 0) { /* Signal hangup to tty-device */ - info = &dev->mdm.info[mi]; + info = &dev->mdm.info[mi]; if (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) { if (info->dialing == 1) { @@ -580,55 +655,58 @@ #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n"); #endif - isdn_tty_modem_hup(info); + isdn_tty_modem_hup(info, 0); return 0; } } - break; - case ISDN_STAT_BCONN: - if (i<0) + break; + case ISDN_STAT_BCONN: + if (i < 0) return -1; #ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "BCONN: %ld\n", c->arg); + printk(KERN_DEBUG "BCONN: %ld\n", c->arg); #endif - /* Signal B-channel-connect to network-devices */ - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - dev->drv[di]->flags |= (1 << (c->arg)); - isdn_info_update(); - if (isdn_net_stat_callback(i, c->command)) - break; + /* Signal B-channel-connect to network-devices */ + if (dev->global_flags & ISDN_GLOBAL_STOPPED) + return 0; + dev->drv[di]->flags |= (1 << (c->arg)); + isdn_info_update(); + if (isdn_net_stat_callback(i, c->command)) + break; if ((mi = dev->m_idx[i]) >= 0) { /* Schedule CONNECT-Message to any tty, waiting for it and * set DCD-bit of its modem-status. */ - info = &dev->mdm.info[mi]; + info = &dev->mdm.info[mi]; if (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) { info->msr |= UART_MSR_DCD; - if (info->dialing) + if (info->dialing) { info->dialing = 0; + info->last_dir = 1; + } else + info->last_dir = 0; info->rcvsched = 1; - if (USG_MODEM(dev->usage[i])) - isdn_tty_modem_result(5, info); - if (USG_VOICE(dev->usage[i])) - isdn_tty_modem_result(11, info); + if (USG_MODEM(dev->usage[i])) + isdn_tty_modem_result(5, info); + if (USG_VOICE(dev->usage[i])) + isdn_tty_modem_result(11, info); } } - break; - case ISDN_STAT_BHUP: - if (i<0) + break; + case ISDN_STAT_BHUP: + if (i < 0) return -1; #ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "BHUP: %ld\n", c->arg); + printk(KERN_DEBUG "BHUP: %ld\n", c->arg); #endif - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - dev->drv[di]->flags &= ~(1 << (c->arg)); - isdn_info_update(); + if (dev->global_flags & ISDN_GLOBAL_STOPPED) + return 0; + dev->drv[di]->flags &= ~(1 << (c->arg)); + isdn_info_update(); if ((mi = dev->m_idx[i]) >= 0) { /* Signal hangup to tty-device, schedule NO CARRIER-message */ - info = &dev->mdm.info[mi]; + info = &dev->mdm.info[mi]; if (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) { if (info->msr & UART_MSR_DCD) @@ -637,26 +715,29 @@ #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n"); #endif - isdn_tty_modem_hup(info); + isdn_tty_modem_hup(info, 0); } } - break; - case ISDN_STAT_NODCH: - if (i<0) + break; + case ISDN_STAT_NODCH: + if (i < 0) return -1; #ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "NODCH: %ld\n", c->arg); + printk(KERN_DEBUG "NODCH: %ld\n", c->arg); #endif - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - if (isdn_net_stat_callback(i, c->command)) - break; + if (dev->global_flags & ISDN_GLOBAL_STOPPED) + return 0; + if (isdn_net_stat_callback(i, c->command)) + break; if ((mi = dev->m_idx[i]) >= 0) { - info = &dev->mdm.info[mi]; + info = &dev->mdm.info[mi]; if (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) { if (info->dialing) { info->dialing = 0; + info->last_l2 = -1; + info->last_si = 0; + sprintf(info->last_cause, "0000"); isdn_tty_modem_result(6, info); } info->msr &= ~UART_MSR_DCD; @@ -666,46 +747,46 @@ } } } - break; - case ISDN_STAT_ADDCH: - break; - case ISDN_STAT_UNLOAD: - save_flags(flags); - cli(); - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if (dev->drvmap[i] == di) { - dev->drvmap[i] = -1; - dev->chanmap[i] = -1; - } - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - modem_info *info = &dev->mdm.info[i]; - - if (info->isdn_driver == di) { - info->isdn_driver = -1; - info->isdn_channel = -1; - if (info->online) { - isdn_tty_modem_result(3, info); - isdn_tty_modem_hup(info); - } - } - } - dev->drivers--; - dev->channels -= dev->drv[di]->channels; - kfree(dev->drv[di]->rcverr); - kfree(dev->drv[di]->rcvcount); - for (i = 0; i < dev->drv[di]->channels; i++) - isdn_free_queue(&dev->drv[di]->rpqueue[i]); - kfree(dev->drv[di]->rpqueue); - kfree(dev->drv[di]->rcv_waitq); - kfree(dev->drv[di]->snd_waitq); - kfree(dev->drv[di]); - dev->drv[di] = NULL; - dev->drvid[di][0] = '\0'; - isdn_info_update(); - restore_flags(flags); - return 0; - default: - return -1; + break; + case ISDN_STAT_ADDCH: + break; + case ISDN_STAT_UNLOAD: + save_flags(flags); + cli(); + for (i = 0; i < ISDN_MAX_CHANNELS; i++) + if (dev->drvmap[i] == di) { + dev->drvmap[i] = -1; + dev->chanmap[i] = -1; + } + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + modem_info *info = &dev->mdm.info[i]; + + if (info->isdn_driver == di) { + info->isdn_driver = -1; + info->isdn_channel = -1; + if (info->online) { + isdn_tty_modem_result(3, info); + isdn_tty_modem_hup(info, 1); + } + } + } + dev->drivers--; + dev->channels -= dev->drv[di]->channels; + kfree(dev->drv[di]->rcverr); + kfree(dev->drv[di]->rcvcount); + for (i = 0; i < dev->drv[di]->channels; i++) + isdn_free_queue(&dev->drv[di]->rpqueue[i]); + kfree(dev->drv[di]->rpqueue); + kfree(dev->drv[di]->rcv_waitq); + kfree(dev->drv[di]->snd_waitq); + kfree(dev->drv[di]); + dev->drv[di] = NULL; + dev->drvid[di][0] = '\0'; + isdn_info_update(); + restore_flags(flags); + return 0; + default: + return -1; } return 0; } @@ -713,7 +794,8 @@ /* * Get integer from char-pointer, set pointer to end of number */ -int isdn_getnum(char **p) +int +isdn_getnum(char **p) { int v = -1; @@ -727,19 +809,17 @@ /* * isdn_readbchan() tries to get data from the read-queue. * It MUST be called with interrupts off. - * - * I hope I got the EFAULT error path right -AK. */ -int isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, int user) +int +isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, int user) { int left; int count; int count_pull; - int count_put; + int count_put; int dflag; - struct sk_buff *skb; + struct sk_buff *skb; u_char *cp; - int ret = 0; if (!dev->drv[di]) return 0; @@ -753,106 +833,98 @@ cp = buf; count = 0; while (left) { - ret = 0; - if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel]))) - break; - if (skb->lock) - break; - skb->lock = 1; - if (skb->users) { - /* users is the count of DLE's in - * this buff when in voice mode. - */ - char *p = skb->data; - unsigned long DLEmask = (1 << channel); - - dflag = 0; - count_pull = count_put = 0; - while ((count_pull < skb->len) && (left-- > 0)) { - if (dev->drv[di]->DLEflag & DLEmask) { - if (user) { - ret = put_user(DLE,cp); - cp++; - if (ret) break; - } else - *cp++ = DLE; - dev->drv[di]->DLEflag &= ~DLEmask; - } else { - if (user) { - ret = put_user(*p,cp); - if (ret) break; - cp++; - } else - *cp++ = *p; - if (*p == DLE) { - dev->drv[di]->DLEflag |= DLEmask; - skb->users--; - } - p++; - count_pull++; - } - count_put++; - } - if (count_pull >= skb->len) - dflag = 1; - } else { - /* No DLE's in buff, so simply copy it */ - dflag = 1; - if ((count_pull = skb->len) > left) { - count_pull = left; - dflag = 0; - } - count_put = count_pull; - ret = 0; - if (user) - ret = copy_to_user(cp, skb->data, count_put); - else - memcpy(cp, skb->data, count_put); - count_put -= ret; - cp += count_put; - left -= count_put; - } - count += count_put; - if (fp) { - memset(fp, 0, count_put); - fp += count_put; - } - if (dflag) { - /* We got all the data in this buff. - * Now we can dequeue it. - */ + if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel]))) + break; + if (ISDN_AUDIO_SKB_LOCK(skb)) + break; + ISDN_AUDIO_SKB_LOCK(skb) = 1; + if (ISDN_AUDIO_SKB_DLECOUNT(skb)) { + char *p = skb->data; + unsigned long DLEmask = (1 << channel); + + dflag = 0; + count_pull = count_put = 0; + while ((count_pull < skb->len) && (left-- > 0)) { + if (dev->drv[di]->DLEflag & DLEmask) { + if (user) + put_user(DLE, cp++); + else + *cp++ = DLE; + dev->drv[di]->DLEflag &= ~DLEmask; + } else { + if (user) + put_user(*p, cp++); + else + *cp++ = *p; + if (*p == DLE) { + dev->drv[di]->DLEflag |= DLEmask; + (ISDN_AUDIO_SKB_DLECOUNT(skb))--; + } + p++; + count_pull++; + } + count_put++; + } + if (count_pull >= skb->len) + dflag = 1; + } else { + /* No DLE's in buff, so simply copy it */ + dflag = 1; + if ((count_pull = skb->len) > left) { + count_pull = left; + dflag = 0; + } + count_put = count_pull; + if (user) + copy_to_user(cp, skb->data, count_put); + else + memcpy(cp, skb->data, count_put); + cp += count_put; + left -= count_put; + } + count += count_put; + if (fp) { + memset(fp, 0, count_put); + fp += count_put; + } + if (dflag) { + /* We got all the data in this buff. + * Now we can dequeue it. + */ if (fp) *(fp - 1) = 0xff; - skb->lock = 0; - skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]); - isdn_trash_skb(skb, FREE_READ); + ISDN_AUDIO_SKB_LOCK(skb) = 0; + skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]); + isdn_trash_skb(skb, FREE_READ); } else { - /* Not yet emptied this buff, so it - * must stay in the queue, for further calls - * but we pull off the data we got until now. - */ - skb_pull(skb,count_pull); - skb->lock = 0; - } + /* Not yet emptied this buff, so it + * must stay in the queue, for further calls + * but we pull off the data we got until now. + */ + skb_pull(skb, count_pull); + ISDN_AUDIO_SKB_LOCK(skb) = 0; + } dev->drv[di]->rcvcount[channel] -= count_put; } - return ret ? -EFAULT : count; + return count; } -static __inline int isdn_minor2drv(int minor) +static __inline int +isdn_minor2drv(int minor) { return (dev->drvmap[minor]); } -static __inline int isdn_minor2chan(int minor) +static __inline int +isdn_minor2chan(int minor) { return (dev->chanmap[minor]); } -#define INF_DV 0x01 /* Data version for /dev/isdninfo */ +#define INF_DV 0x01 /* Data version for /dev/isdninfo */ static char * - isdn_statstr(void) +isdn_statstr(void) { static char istatbuf[2048]; char *p; @@ -905,7 +977,8 @@ /* Module interface-code */ -void isdn_info_update(void) +void +isdn_info_update(void) { infostruct *p = dev->infochain; @@ -916,7 +989,8 @@ wake_up_interruptible(&(dev->info_waitq)); } -static long isdn_read(struct inode *inode, struct file *file, char *buf, unsigned long count) +static RWTYPE +isdn_read(struct inode *inode, struct file *file, char *buf, RWARG count) { uint minor = MINOR(inode->i_rdev); int len = 0; @@ -927,15 +1001,14 @@ if (minor == ISDN_MINOR_STATUS) { char *p; if (!file->private_data) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; interruptible_sleep_on(&(dev->info_waitq)); - } + } p = isdn_statstr(); file->private_data = 0; if ((len = strlen(p)) <= count) { - if (copy_to_user(buf, p, len)) - return -EFAULT; + copy_to_user(buf, p, len); file->f_pos += len; return len; } @@ -950,11 +1023,11 @@ if (!dev->drv[drvidx]->running) return -ENODEV; chidx = isdn_minor2chan(minor); - save_flags(flags); - cli(); + save_flags(flags); + cli(); len = isdn_readbchan(drvidx, chidx, buf, 0, count, 1); file->f_pos += len; - restore_flags(flags); + restore_flags(flags); return len; } if (minor <= ISDN_MINOR_CTRLMAX) { @@ -962,10 +1035,10 @@ if (drvidx < 0) return -ENODEV; if (!dev->drv[drvidx]->stavail) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq)); - } + } if (dev->drv[drvidx]->interface->readstat) len = dev->drv[drvidx]->interface-> readstat(buf, MIN(count, dev->drv[drvidx]->stavail), @@ -974,10 +1047,10 @@ len = 0; save_flags(flags); cli(); - if (len) - dev->drv[drvidx]->stavail -= len; - else - dev->drv[drvidx]->stavail = 0; + if (len) + dev->drv[drvidx]->stavail -= len; + else + dev->drv[drvidx]->stavail = 0; restore_flags(flags); file->f_pos += len; return len; @@ -989,13 +1062,14 @@ return -ENODEV; } -static long long isdn_lseek(struct inode *inode, struct file *file, long long offset, int orig) +static LSTYPE +isdn_lseek(struct inode *inode, struct file *file, LSARG offset, int orig) { return -ESPIPE; } -static long isdn_write(struct inode *inode, struct file *file, - const char *buf, unsigned long count) +static RWTYPE +isdn_write(struct inode *inode, struct file *file, const char *buf, RWARG count) { uint minor = MINOR(inode->i_rdev); int drvidx; @@ -1039,10 +1113,12 @@ return -ENODEV; } -static int isdn_select(struct inode *inode, struct file *file, int type, select_table * st) +#if (LINUX_VERSION_CODE < 0x020117) +static int +isdn_select(struct inode *inode, struct file *file, int type, select_table * st) { uint minor = MINOR(inode->i_rdev); - int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); + int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); if (minor == ISDN_MINOR_STATUS) { if (file->private_data) @@ -1057,22 +1133,59 @@ if (drvidx < 0) return -ENODEV; if (dev->drv[drvidx]->stavail) - return 1; - else { - if (st) - select_wait(&(dev->drv[drvidx]->st_waitq), st); - return 0; - } + return 1; + else { + if (st) + select_wait(&(dev->drv[drvidx]->st_waitq), st); + return 0; + } return 1; - } + } #ifdef CONFIG_ISDN_PPP if (minor <= ISDN_MINOR_PPPMAX) return (isdn_ppp_select(minor - ISDN_MINOR_PPP, file, type, st)); #endif return -ENODEV; } +#else +static unsigned int +isdn_poll(struct file *file, poll_table * wait) +{ + unsigned int mask = 0; + unsigned int minor = MINOR(file->f_inode->i_rdev); + int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); + + if (minor == ISDN_MINOR_STATUS) { + poll_wait(&(dev->info_waitq), wait); + /* mask = POLLOUT | POLLWRNORM; */ + if (file->private_data) { + mask |= POLLIN | POLLRDNORM; + } + return mask; + } + if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) { + poll_wait(&(dev->drv[drvidx]->st_waitq), wait); + if (drvidx < 0) { + printk(KERN_ERR "isdn_common: isdn_poll 1 -> what the hell\n"); + return POLLERR; + } + mask = POLLOUT | POLLWRNORM; + if (dev->drv[drvidx]->stavail) { + mask |= POLLIN | POLLRDNORM; + } + return mask; + } +#ifdef CONFIG_ISDN_PPP + if (minor <= ISDN_MINOR_PPPMAX) + return (isdn_ppp_poll(file, wait)); +#endif + printk(KERN_ERR "isdn_common: isdn_poll 2 -> what the hell\n"); + return POLLERR; +} +#endif -static int isdn_set_allcfg(char *src) +static int +isdn_set_allcfg(char *src) { int ret; int i; @@ -1085,25 +1198,35 @@ return ret; save_flags(flags); cli(); - ret = get_user(i, src); - if (ret) - goto out; - src += sizeof(int); + if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(int)))) { + restore_flags(flags); + return ret; + } + copy_from_user((char *) &i, src, sizeof(int)); + src += sizeof(int); while (i) { char *c; char *c2; - if(copy_from_user((char *) &cfg, src, sizeof(cfg))) - goto fault; + if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(cfg)))) { + restore_flags(flags); + return ret; + } + copy_from_user((char *) &cfg, src, sizeof(cfg)); src += sizeof(cfg); if (!isdn_net_new(cfg.name, NULL)) { restore_flags(flags); return -EIO; } - if ((ret = isdn_net_setcfg(&cfg))) - goto out; - if(copy_from_user(buf, src, sizeof(buf))) - goto fault; + if ((ret = isdn_net_setcfg(&cfg))) { + restore_flags(flags); + return ret; + } + if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(buf)))) { + restore_flags(flags); + return ret; + } + copy_from_user(buf, src, sizeof(buf)); src += sizeof(buf); c = buf; while (*c) { @@ -1112,15 +1235,20 @@ strcpy(phone.phone, c); strcpy(phone.name, cfg.name); phone.outgoing = 0; - if ((ret = isdn_net_addphone(&phone))) - goto fault; + if ((ret = isdn_net_addphone(&phone))) { + restore_flags(flags); + return ret; + } if (c2) c = c2; else c += strlen(c); } - if(copy_from_user(buf, src, sizeof(buf))) - goto fault; + if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(buf)))) { + restore_flags(flags); + return ret; + } + copy_from_user(buf, src, sizeof(buf)); src += sizeof(buf); c = buf; while (*c) { @@ -1129,8 +1257,10 @@ strcpy(phone.phone, c); strcpy(phone.name, cfg.name); phone.outgoing = 1; - if ((ret = isdn_net_addphone(&phone))) - goto out; + if ((ret = isdn_net_addphone(&phone))) { + restore_flags(flags); + return ret; + } if (c2) c = c2; else @@ -1138,27 +1268,28 @@ } i--; } -out: restore_flags(flags); - return ret; -fault: - restore_flags(flags); - return -EFAULT; + return 0; } -static int isdn_get_allcfg(char *dest) +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 = 0; + int ret; /* Walk through netdev-chain */ save_flags(flags); cli(); p = dev->netdev; while (p) { + if ((ret = verify_area(VERIFY_WRITE, (void *) dest, sizeof(cfg) + 200))) { + restore_flags(flags); + return ret; + } strcpy(cfg.eaz, p->local.msn); cfg.exclusive = p->local.exclusive; if (p->local.pre_device >= 0) { @@ -1173,40 +1304,42 @@ cfg.p_encap = p->local.p_encap; cfg.secure = (p->local.flags & ISDN_NET_SECURE) ? 1 : 0; cfg.callback = (p->local.flags & ISDN_NET_CALLBACK) ? 1 : 0; - cfg.chargehup = (p->local.hupflags & 4) ? 1 : 0; - cfg.ihup = (p->local.hupflags & 8) ? 1 : 0; - ret = 0; - ret += copy_to_user(dest, p->local.name, 10); + cfg.chargehup = (p->local.hupflags & ISDN_CHARGEHUP) ? 1 : 0; + cfg.ihup = (p->local.hupflags & ISDN_INHUP) ? 1 : 0; + cfg.chargeint = p->local.chargeint; + copy_to_user(dest, p->local.name, 10); dest += 10; - ret += copy_to_user(dest, (char *) &cfg, sizeof(cfg)); + copy_to_user(dest, (char *) &cfg, sizeof(cfg)); dest += sizeof(cfg); strcpy(phone.name, p->local.name); phone.outgoing = 0; - if (ret) - break; - if ((ret = isdn_net_getphones(&phone, dest)) < 0) - break; - else + if ((ret = isdn_net_getphones(&phone, dest)) < 0) { + restore_flags(flags); + return ret; + } else dest += ret; strcpy(phone.name, p->local.name); phone.outgoing = 1; - if ((ret = isdn_net_getphones(&phone, dest)) < 0) - break; - else + 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 ret; + return 0; } -static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) +static int +isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) { uint minor = MINOR(inode->i_rdev); isdn_ctrl c; int drvidx; int chidx; - int ret = 0; + int ret; char *s; char name[10]; char bname[21]; @@ -1215,31 +1348,30 @@ isdn_net_ioctl_cfg cfg; if (minor == ISDN_MINOR_STATUS) { - switch (cmd) { - case IIOCGETDVR: - return(TTY_DV + - (NET_DV << 8) + - (INF_DV << 16)); - case IIOCGETCPS: - if (arg) { - ulong *p = (ulong *)arg; - int i; - for (i = 0;iibytes[i],p); - if (ret) break; - p++; - ret = put_user(dev->obytes[i],p); - p++; - if (ret) break; - } - return ret; - } else - return -EINVAL; - break; - default: - return -EINVAL; - } - } + switch (cmd) { + case IIOCGETDVR: + return (TTY_DV + + (NET_DV << 8) + + (INF_DV << 16)); + case IIOCGETCPS: + if (arg) { + ulong *p = (ulong *) arg; + int i; + if ((ret = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(ulong) * ISDN_MAX_CHANNELS * 2))) + return ret; + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + put_user(dev->ibytes[i], p++); + put_user(dev->obytes[i], p++); + } + return 0; + } else + return -EINVAL; + break; + default: + return -EINVAL; + } + } if (!dev->drivers) return -ENODEV; if (minor < ISDN_MINOR_CTRL) { @@ -1254,286 +1386,336 @@ if (minor <= ISDN_MINOR_CTRLMAX) { switch (cmd) { #ifdef CONFIG_NETDEVICES - case IIOCNETAIF: - /* Add a network-interface */ - if (arg) { - if(copy_from_user(name, (char *) arg, sizeof(name))) - return -EFAULT; - s = name; - } else - s = NULL; - if ((s = isdn_net_new(s, NULL))) { - return copy_to_user((char *) arg, s, strlen(s) + 1) ? -EFAULT : ret; - } else - return -ENODEV; - case IIOCNETASL: - /* Add a slave to a network-interface */ - if (arg) { - if(copy_from_user(bname, (char *) arg, sizeof(bname))) - return -EFAULT; - } else - return -EINVAL; - if ((s = isdn_net_newslave(bname))) { - return copy_to_user((char *) arg, s, strlen(s) + 1) ? -EFAULT : 0; - } else - return -ENODEV; - case IIOCNETDIF: - /* Delete a network-interface */ - if (arg) { - ret = copy_from_user(name, (char *) arg, sizeof(name)); - return ret ? -EFAULT : isdn_net_rm(name); - } else - return -EINVAL; - case IIOCNETSCF: - /* Set configurable parameters of a network-interface */ - if (arg) { - ret = copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)); - return ret ? -EFAULT : isdn_net_setcfg(&cfg); - } else - return -EINVAL; - case IIOCNETGCF: - /* Get configurable parameters of a network-interface */ - if (arg) { - if(copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))) - return -EFAULT; - if (!(ret = isdn_net_getcfg(&cfg))) { - if(copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg))) - return -EFAULT; - } - return ret; - } else - return -EINVAL; - case IIOCNETANM: - /* Add a phone-number to a network-interface */ - if (arg) { - ret = copy_from_user((char *) &phone, (char *) arg, sizeof(phone)); - return ret ? -EFAULT : isdn_net_addphone(&phone); - } else - return -EINVAL; - case IIOCNETGNM: - /* Get list of phone-numbers of a network-interface */ - if (arg) { - ret = copy_from_user((char *) &phone, (char *) arg, sizeof(phone)); - return ret ? -EFAULT : isdn_net_getphones(&phone, (char *) arg); - } else - return -EINVAL; - case IIOCNETDNM: - /* Delete a phone-number of a network-interface */ - if (arg) { - ret = copy_from_user((char *) &phone, (char *) arg, sizeof(phone)); - return ret ? -EFAULT : isdn_net_delphone(&phone); - } else - return -EINVAL; - case IIOCNETDIL: - /* Force dialing of a network-interface */ - if (arg) { - ret = copy_from_user(name, (char *) arg, sizeof(name)); - return ret ? -EFAULT : isdn_net_force_dial(name); - } else - return -EINVAL; + case IIOCNETAIF: + /* Add a network-interface */ + if (arg) { + if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name)))) + return ret; + copy_from_user(name, (char *) arg, sizeof(name)); + s = name; + } else + s = NULL; + if ((s = isdn_net_new(s, NULL))) { + if ((ret = verify_area(VERIFY_WRITE, (void *) arg, strlen(s) + 1))) + return ret; + copy_to_user((char *) arg, s, strlen(s) + 1); + return 0; + } else + return -ENODEV; + case IIOCNETASL: + /* Add a slave to a network-interface */ + if (arg) { + if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(bname)))) + return ret; + copy_from_user(bname, (char *) arg, sizeof(bname)); + } else + return -EINVAL; + if ((s = isdn_net_newslave(bname))) { + if ((ret = verify_area(VERIFY_WRITE, (void *) arg, strlen(s) + 1))) + return ret; + copy_to_user((char *) arg, s, strlen(s) + 1); + return 0; + } else + return -ENODEV; + case IIOCNETDIF: + /* Delete a network-interface */ + if (arg) { + if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name)))) + return ret; + copy_from_user(name, (char *) arg, sizeof(name)); + return isdn_net_rm(name); + } else + return -EINVAL; + case IIOCNETSCF: + /* Set configurable parameters of a network-interface */ + if (arg) { + if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(cfg)))) + return ret; + copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)); + return isdn_net_setcfg(&cfg); + } else + return -EINVAL; + case IIOCNETGCF: + /* Get configurable parameters of a network-interface */ + if (arg) { + if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(cfg)))) + return ret; + copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)); + if (!(ret = isdn_net_getcfg(&cfg))) { + if ((ret = verify_area(VERIFY_WRITE, (void *) arg, sizeof(cfg)))) + return ret; + copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg)); + } + return ret; + } else + return -EINVAL; + case IIOCNETANM: + /* Add a phone-number to a network-interface */ + if (arg) { + if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone)))) + return ret; + copy_from_user((char *) &phone, (char *) arg, sizeof(phone)); + return isdn_net_addphone(&phone); + } else + return -EINVAL; + case IIOCNETGNM: + /* Get list of phone-numbers of a network-interface */ + if (arg) { + if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone)))) + return ret; + copy_from_user((char *) &phone, (char *) arg, sizeof(phone)); + return isdn_net_getphones(&phone, (char *) arg); + } else + return -EINVAL; + case IIOCNETDNM: + /* Delete a phone-number of a network-interface */ + if (arg) { + if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone)))) + return ret; + copy_from_user((char *) &phone, (char *) arg, sizeof(phone)); + return isdn_net_delphone(&phone); + } else + return -EINVAL; + case IIOCNETDIL: + /* Force dialing of a network-interface */ + if (arg) { + if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name)))) + return ret; + copy_from_user(name, (char *) arg, sizeof(name)); + return isdn_net_force_dial(name); + } else + return -EINVAL; #ifdef CONFIG_ISDN_PPP - case IIOCNETALN: - if (arg) - ret = copy_from_user(name,(char*)arg,sizeof(name)); - else - return -EINVAL; - return ret ? -EFAULT : isdn_ppp_dial_slave(name); - case IIOCNETDLN: - - if(arg) { - ret = copy_from_user(name,(char*)arg,sizeof(name)); - } else - return -EINVAL; - return ret ? -EFAULT : isdn_ppp_hangup_slave(name); -#endif - case IIOCNETHUP: - /* Force hangup of a network-interface */ - if (arg) { - ret = copy_from_user(name, (char *) arg, sizeof(name)); - return ret ? -EFAULT : isdn_net_force_hangup(name); - } else - return -EINVAL; - break; -#endif /* CONFIG_NETDEVICES */ - case IIOCSETVER: - dev->net_verbose = arg; - printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose); - return 0; - case IIOCSETGST: - if (arg) - dev->global_flags |= ISDN_GLOBAL_STOPPED; - else - dev->global_flags &= ~ISDN_GLOBAL_STOPPED; - printk(KERN_INFO "isdn: Global Mode %s\n", - (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running"); - return 0; - case IIOCSETBRJ: - drvidx = -1; - if (arg) { - int i; - char *p; - if(copy_from_user((char *) &iocts, (char *) arg, - sizeof(isdn_ioctl_struct))) - return -EFAULT; - if (strlen(iocts.drvid)) { - if ((p = strchr(iocts.drvid, ','))) - *p = 0; - drvidx = -1; - for (i = 0; i < ISDN_MAX_DRIVERS; i++) - if (!(strcmp(dev->drvid[i], iocts.drvid))) { - drvidx = i; - break; - } - } - } - if (drvidx == -1) - return -ENODEV; - dev->drv[drvidx]->reject_bus = iocts.arg; - return 0; - case IIOCGETSET: - /* Get complete setup (all network-interfaces and profile- - settings of all tty-devices */ - if (arg) - return (isdn_get_allcfg((char *) arg)); - 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; - case IIOCSIGPRF: - dev->profd = current; - return 0; - break; - case IIOCGETPRF: - /* Get all Modem-Profiles */ - if (arg) { - char *p = (char *) arg; - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if(copy_to_user(p, dev->mdm.info[i].emu.profile, - ISDN_MODEM_ANZREG)) - return -EFAULT; - p += ISDN_MODEM_ANZREG; - if(copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN)) - return -EFAULT; - p += ISDN_MSNLEN; - } - return (ISDN_MODEM_ANZREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS; - } else - return -EINVAL; - break; - case IIOCSETPRF: - /* Set all Modem-Profiles */ - if (arg) { - char *p = (char *) arg; - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if(copy_from_user(dev->mdm.info[i].emu.profile, p, - ISDN_MODEM_ANZREG)) - return -EFAULT; - p += ISDN_MODEM_ANZREG; - if(copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)) - return -EFAULT; - p += ISDN_MSNLEN; - } - return 0; - } else - return -EINVAL; - break; - case IIOCSETMAP: - case IIOCGETMAP: - /* Set/Get MSN->EAZ-Mapping for a driver */ - if (arg) { - int i; - char *p; - char nstring[255]; - - ret = copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct)); - - if (ret) return -EFAULT; - if (strlen(iocts.drvid)) { - drvidx = -1; - for (i = 0; i < ISDN_MAX_DRIVERS; i++) - if (!(strcmp(dev->drvid[i], iocts.drvid))) { - drvidx = i; - break; - } - } else - drvidx = 0; - if (drvidx == -1) - return -ENODEV; - if (cmd == IIOCSETMAP) { - ret = copy_from_user(nstring, (char *) iocts.arg, 255); - if (ret) return -EFAULT; - memset(dev->drv[drvidx]->msn2eaz, 0, - sizeof(dev->drv[drvidx]->msn2eaz)); - p = strtok(nstring, ","); - i = 0; - while ((p) && (i < 10)) { - strcpy(dev->drv[drvidx]->msn2eaz[i++], p); - p = strtok(NULL, ","); - } - } else { - p = nstring; - for (i = 0; i < 10; i++) - p += sprintf(p, "%s%s", - strlen(dev->drv[drvidx]->msn2eaz[i]) ? - dev->drv[drvidx]->msn2eaz[i] : "-", - (i < 9) ? "," : "\0"); - if(copy_to_user((char *) iocts.arg, nstring, strlen(nstring) + 1)) - return -EFAULT; - } - return 0; - } else - return -EINVAL; - case IIOCDBGVAR: - if (arg) { - return copy_to_user((char *) arg, (char *) &dev, sizeof(ulong)) ? -EFAULT : 0; - } else - return -EINVAL; - break; - default: - if ((cmd&IIOCDRVCTL)==IIOCDRVCTL) - cmd = ((cmd>>_IOC_NRSHIFT)&_IOC_NRMASK)& ISDN_DRVIOCTL_MASK; + case IIOCNETALN: + if (arg) { + if ((ret = verify_area(VERIFY_READ, + (void *) arg, + sizeof(name)))) + return ret; + } else + return -EINVAL; + copy_from_user(name, (char *) arg, sizeof(name)); + return isdn_ppp_dial_slave(name); + case IIOCNETDLN: + if (arg) { + if ((ret = verify_area(VERIFY_READ, + (void *) arg, + sizeof(name)))) + return ret; + } else + return -EINVAL; + copy_from_user(name, (char *) arg, sizeof(name)); + return isdn_ppp_hangup_slave(name); +#endif + case IIOCNETHUP: + /* Force hangup of a network-interface */ + if (arg) { + if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name)))) + return ret; + copy_from_user(name, (char *) arg, sizeof(name)); + return isdn_net_force_hangup(name); + } else + return -EINVAL; + break; +#endif /* CONFIG_NETDEVICES */ + case IIOCSETVER: + dev->net_verbose = arg; + printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose); + return 0; + case IIOCSETGST: + if (arg) + dev->global_flags |= ISDN_GLOBAL_STOPPED; + else + dev->global_flags &= ~ISDN_GLOBAL_STOPPED; + printk(KERN_INFO "isdn: Global Mode %s\n", + (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running"); + return 0; + case IIOCSETBRJ: + drvidx = -1; + if (arg) { + int i; + char *p; + if ((ret = verify_area(VERIFY_READ, (void *) arg, + sizeof(isdn_ioctl_struct)))) + return ret; + copy_from_user((char *) &iocts, (char *) arg, + sizeof(isdn_ioctl_struct)); + if (strlen(iocts.drvid)) { + if ((p = strchr(iocts.drvid, ','))) + *p = 0; + drvidx = -1; + for (i = 0; i < ISDN_MAX_DRIVERS; i++) + if (!(strcmp(dev->drvid[i], iocts.drvid))) { + drvidx = i; + break; + } + } + } + if (drvidx == -1) + return -ENODEV; + dev->drv[drvidx]->reject_bus = iocts.arg; + return 0; + case IIOCGETSET: + /* Get complete setup (all network-interfaces and profile- + settings of all tty-devices */ + if (arg) + return (isdn_get_allcfg((char *) arg)); else return -EINVAL; - if (arg) { - int i; - char *p; - - ret = copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct)); - if (ret) - return -EFAULT; - if (strlen(iocts.drvid)) { - if ((p = strchr(iocts.drvid, ','))) - *p = 0; - drvidx = -1; - for (i = 0; i < ISDN_MAX_DRIVERS; i++) - if (!(strcmp(dev->drvid[i], iocts.drvid))) { - drvidx = i; - break; - } - } else - drvidx = 0; - if (drvidx == -1) - return -ENODEV; - c.driver = drvidx; - c.command = ISDN_CMD_IOCTL; - c.arg = cmd; - memcpy(c.num, (char *) &iocts.arg, sizeof(ulong)); - ret = dev->drv[drvidx]->interface->command(&c); - memcpy((char *) &iocts.arg, c.num, sizeof(ulong)); - return copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct)) ? -EFAULT : 0; - } 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; + case IIOCSIGPRF: + dev->profd = current; + return 0; + break; + case IIOCGETPRF: + /* Get all Modem-Profiles */ + if (arg) { + char *p = (char *) arg; + int i; + + if ((ret = verify_area(VERIFY_WRITE, (void *) arg, + (ISDN_MODEM_ANZREG + ISDN_MSNLEN) + * ISDN_MAX_CHANNELS))) + return ret; + + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + copy_to_user(p, dev->mdm.info[i].emu.profile, + ISDN_MODEM_ANZREG); + p += ISDN_MODEM_ANZREG; + copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN); + p += ISDN_MSNLEN; + } + return (ISDN_MODEM_ANZREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS; + } else + return -EINVAL; + break; + case IIOCSETPRF: + /* Set all Modem-Profiles */ + if (arg) { + char *p = (char *) arg; + int i; + + if ((ret = verify_area(VERIFY_READ, (void *) arg, + (ISDN_MODEM_ANZREG + ISDN_MSNLEN) + * ISDN_MAX_CHANNELS))) + return ret; + + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + copy_from_user(dev->mdm.info[i].emu.profile, p, + ISDN_MODEM_ANZREG); + p += ISDN_MODEM_ANZREG; + copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN); + p += ISDN_MSNLEN; + } + return 0; + } else + return -EINVAL; + break; + case IIOCSETMAP: + case IIOCGETMAP: + /* Set/Get MSN->EAZ-Mapping for a driver */ + if (arg) { + int i; + char *p; + char nstring[255]; + + if ((ret = verify_area(VERIFY_READ, (void *) arg, + sizeof(isdn_ioctl_struct)))) + return ret; + copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct)); + if (strlen(iocts.drvid)) { + drvidx = -1; + for (i = 0; i < ISDN_MAX_DRIVERS; i++) + if (!(strcmp(dev->drvid[i], iocts.drvid))) { + drvidx = i; + break; + } + } else + drvidx = 0; + if (drvidx == -1) + return -ENODEV; + if (cmd == IIOCSETMAP) { + if ((ret = verify_area(VERIFY_READ, (void *) iocts.arg, 255))) + return ret; + copy_from_user(nstring, (char *) iocts.arg, 255); + memset(dev->drv[drvidx]->msn2eaz, 0, + sizeof(dev->drv[drvidx]->msn2eaz)); + p = strtok(nstring, ","); + i = 0; + while ((p) && (i < 10)) { + strcpy(dev->drv[drvidx]->msn2eaz[i++], p); + p = strtok(NULL, ","); + } + } else { + p = nstring; + for (i = 0; i < 10; i++) + p += sprintf(p, "%s%s", + strlen(dev->drv[drvidx]->msn2eaz[i]) ? + dev->drv[drvidx]->msn2eaz[i] : "-", + (i < 9) ? "," : "\0"); + if ((ret = verify_area(VERIFY_WRITE, (void *) iocts.arg, + strlen(nstring) + 1))) + return ret; + copy_to_user((char *) iocts.arg, nstring, strlen(nstring) + 1); + } + return 0; + } else + return -EINVAL; + case IIOCDBGVAR: + if (arg) { + if ((ret = verify_area(VERIFY_WRITE, (void *) arg, sizeof(ulong)))) + return ret; + copy_to_user((char *) arg, (char *) &dev, sizeof(ulong)); + return 0; + } else + return -EINVAL; + break; + default: + if ((cmd & IIOCDRVCTL) == IIOCDRVCTL) + cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK; + else + return -EINVAL; + if (arg) { + int i; + char *p; + if ((ret = verify_area(VERIFY_READ, (void *) arg, + sizeof(isdn_ioctl_struct)))) + return ret; + copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct)); + if (strlen(iocts.drvid)) { + if ((p = strchr(iocts.drvid, ','))) + *p = 0; + drvidx = -1; + for (i = 0; i < ISDN_MAX_DRIVERS; i++) + if (!(strcmp(dev->drvid[i], iocts.drvid))) { + drvidx = i; + break; + } + } else + drvidx = 0; + if (drvidx == -1) + return -ENODEV; + if ((ret = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(isdn_ioctl_struct)))) + return ret; + c.driver = drvidx; + c.command = ISDN_CMD_IOCTL; + c.arg = cmd; + memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong)); + ret = dev->drv[drvidx]->interface->command(&c); + memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong)); + copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct)); + return ret; + } else + return -EINVAL; } } #ifdef CONFIG_ISDN_PPP @@ -1548,7 +1730,8 @@ * MOD_INC_USE_COUNT make sure that the driver memory is not freed * while the device is in use. */ -static int isdn_open(struct inode *ino, struct file *filep) +static int +isdn_open(struct inode *ino, struct file *filep) { uint minor = MINOR(ino->i_rdev); int drvidx; @@ -1600,20 +1783,21 @@ if (minor <= ISDN_MINOR_PPPMAX) { int ret; if (!(ret = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep))) - MOD_INC_USE_COUNT; + MOD_INC_USE_COUNT; return ret; } #endif return -ENODEV; } -static void isdn_close(struct inode *ino, struct file *filep) +static void +isdn_close(struct inode *ino, struct file *filep) { uint minor = MINOR(ino->i_rdev); int drvidx; isdn_ctrl c; - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; if (minor == ISDN_MINOR_STATUS) { infostruct *p = dev->infochain; infostruct *q = NULL; @@ -1629,7 +1813,7 @@ p = (infostruct *) (p->next); } printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n"); - return; + return; } if (minor < ISDN_MINOR_CTRL) { drvidx = isdn_minor2drv(minor); @@ -1662,17 +1846,21 @@ isdn_lseek, isdn_read, isdn_write, - NULL, /* isdn_readdir */ - isdn_select, /* isdn_select */ - isdn_ioctl, /* isdn_ioctl */ - NULL, /* isdn_mmap */ + NULL, /* isdn_readdir */ +#if (LINUX_VERSION_CODE < 0x020117) + isdn_select, /* isdn_select */ +#else + isdn_poll, /* isdn_poll */ +#endif + isdn_ioctl, /* isdn_ioctl */ + NULL, /* isdn_mmap */ isdn_open, isdn_close, - NULL /* fsync */ + NULL /* fsync */ }; char * - isdn_map_eaz2msn(char *msn, int di) +isdn_map_eaz2msn(char *msn, int di) { driver *this = dev->drv[di]; int i; @@ -1690,13 +1878,14 @@ * Find an unused ISDN-channel, whose feature-flags match the * given L2- and L3-protocols. */ -int isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev - ,int pre_chan) +int +isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev + ,int pre_chan) { int i; ulong flags; ulong features; - isdn_ctrl cmd; + isdn_ctrl cmd; save_flags(flags); cli(); @@ -1714,10 +1903,10 @@ dev->usage[i] &= ISDN_USAGE_EXCLUSIVE; dev->usage[i] |= usage; isdn_info_update(); - cmd.driver = d; - cmd.arg = 0; - cmd.command = ISDN_CMD_LOCK; - (void) dev->drv[d]->interface->command(&cmd); + cmd.driver = d; + cmd.arg = 0; + cmd.command = ISDN_CMD_LOCK; + (void) dev->drv[d]->interface->command(&cmd); restore_flags(flags); return i; } else { @@ -1725,10 +1914,10 @@ dev->usage[i] &= ISDN_USAGE_EXCLUSIVE; dev->usage[i] |= usage; isdn_info_update(); - cmd.driver = d; - cmd.arg = 0; - cmd.command = ISDN_CMD_LOCK; - (void) dev->drv[d]->interface->command(&cmd); + cmd.driver = d; + cmd.arg = 0; + cmd.command = ISDN_CMD_LOCK; + (void) dev->drv[d]->interface->command(&cmd); restore_flags(flags); return i; } @@ -1743,7 +1932,8 @@ /* * Set state of ISDN-channel to 'unused' */ -void isdn_free_channel(int di, int ch, int usage) +void +isdn_free_channel(int di, int ch, int usage) { int i; ulong flags; @@ -1757,15 +1947,15 @@ (dev->chanmap[i] == ch)) { dev->usage[i] &= (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE); strcpy(dev->num[i], "???"); - dev->ibytes[i] = 0; - dev->obytes[i] = 0; + dev->ibytes[i] = 0; + 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; - (void) dev->drv[di]->interface->command(&cmd); - restore_flags(flags); + isdn_free_queue(&dev->drv[di]->rpqueue[ch]); + cmd.driver = di; + cmd.arg = ch; + cmd.command = ISDN_CMD_UNLOCK; + restore_flags(flags); + (void) dev->drv[di]->interface->command(&cmd); return; } restore_flags(flags); @@ -1774,7 +1964,8 @@ /* * Cancel Exclusive-Flag for ISDN-channel */ -void isdn_unexclusive_channel(int di, int ch) +void +isdn_unexclusive_channel(int di, int ch) { int i; ulong flags; @@ -1802,58 +1993,57 @@ * len = Length of packet-data * */ -void isdn_receive_callback(int drvidx, int chan, u_char *buf, int len) +static void +isdn_receive_callback(int drvidx, int chan, u_char * buf, int len) { - struct sk_buff *skb; + struct sk_buff *skb; if (dev->global_flags & ISDN_GLOBAL_STOPPED) return; - skb = dev_alloc_skb(len); - if (skb) { - memcpy(skb_put(skb, len), buf, len); - isdn_receive_skb_callback(drvidx, chan, skb); - } else - printk(KERN_WARNING "isdn: rcv alloc_skb failed, packet dropped.\n"); + skb = dev_alloc_skb(len); + if (skb) { + memcpy(skb_put(skb, len), buf, len); + isdn_receive_skb_callback(drvidx, chan, skb); + } else + printk(KERN_WARNING "isdn: rcv alloc_skb failed, packet dropped.\n"); } /* * writebuf replacement for SKB_ABLE drivers */ -int isdn_writebuf_stub(int drvidx, int chan, const u_char *buf, int len, - int user) +static int +isdn_writebuf_stub(int drvidx, int chan, const u_char * buf, int len, + int user) { int ret; - if (dev->drv[drvidx]->interface->writebuf) - ret = dev->drv[drvidx]->interface->writebuf(drvidx, chan, buf, - len, user); - else { - struct sk_buff * skb; - - skb = alloc_skb(dev->drv[drvidx]->interface->hl_hdrlen + len, - GFP_ATOMIC); - if (skb == NULL) - return 0; - - skb_reserve(skb, dev->drv[drvidx]->interface->hl_hdrlen); - skb->free = 1; - - if (user) { - if(copy_from_user(skb_put(skb, len), buf, len)) { - kfree_skb(skb,FREE_WRITE); - return -EFAULT; - } - } else - memcpy(skb_put(skb, len), buf, len); + if (dev->drv[drvidx]->interface->writebuf) + ret = dev->drv[drvidx]->interface->writebuf(drvidx, chan, buf, + len, user); + else { + struct sk_buff *skb; + + skb = alloc_skb(dev->drv[drvidx]->interface->hl_hdrlen + len, + GFP_ATOMIC); + if (skb == NULL) + return 0; + + skb_reserve(skb, dev->drv[drvidx]->interface->hl_hdrlen); + SET_SKB_FREE(skb); + + if (user) + 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, skb); - if (ret <= 0) - kfree_skb(skb, FREE_WRITE); - } - if (ret > 0) - dev->obytes[isdn_dc2minor(drvidx,chan)] += ret; - return ret; + ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, + chan, skb); + if (ret <= 0) + kfree_skb(skb, FREE_WRITE); + } + if (ret > 0) + dev->obytes[isdn_dc2minor(drvidx, chan)] += ret; + return ret; } /* @@ -1864,32 +2054,36 @@ * Return: length of data on success, -ERRcode on failure. */ -int isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff * skb) +int +isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff *skb) { - int ret; - int len = skb->len; /* skb pointer no longer valid after free */ + int ret; + int len = skb->len; /* skb pointer no longer valid after free */ - if (dev->drv[drvidx]->interface->writebuf_skb) + if (dev->drv[drvidx]->interface->writebuf_skb) ret = dev->drv[drvidx]->interface-> - writebuf_skb(drvidx, chan, skb); + writebuf_skb(drvidx, chan, skb); else { if ((ret = dev->drv[drvidx]->interface-> - writebuf(drvidx,chan,skb->data,skb->len,0)) == len) - dev_kfree_skb(skb, FREE_WRITE); - } - if (ret > 0) - dev->obytes[isdn_dc2minor(drvidx,chan)] += len; - return ret; + writebuf(drvidx, chan, skb->data, skb->len, 0)) == len) + dev_kfree_skb(skb, FREE_WRITE); + } + if (ret > 0) + dev->obytes[isdn_dc2minor(drvidx, chan)] += len; + return ret; } /* * Low-level-driver registration */ -int register_isdn(isdn_if * i) +int +register_isdn(isdn_if * i) { driver *d; - int n, j, k; + int n, + j, + k; ulong flags; int drvidx; @@ -1905,9 +2099,9 @@ return 0; } if ((!i->writebuf_skb) && (!i->writebuf)) { - printk(KERN_WARNING "register_isdn: No write routine given.\n"); - return 0; - } + 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; @@ -1926,17 +2120,17 @@ return 0; } memset((char *) d->rcvcount, 0, sizeof(int) * n); - if (!(d->rpqueue = - (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * n, GFP_KERNEL))) { - printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n"); - kfree(d->rcvcount); - kfree(d->rcverr); - kfree(d); - return 0; - } - for (j = 0; j < n; j++) { - skb_queue_head_init(&d->rpqueue[j]); - } + if (!(d->rpqueue = + (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * n, GFP_KERNEL))) { + printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n"); + kfree(d->rcvcount); + kfree(d->rcverr); + kfree(d); + return 0; + } + for (j = 0; j < n; j++) { + skb_queue_head_init(&d->rpqueue[j]); + } if (!(d->rcv_waitq = (struct wait_queue **) kmalloc(sizeof(struct wait_queue *) * n, GFP_KERNEL))) { printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n"); @@ -1972,15 +2166,15 @@ i->channels = drvidx; i->rcvcallb_skb = isdn_receive_skb_callback; - i->rcvcallb = isdn_receive_callback; - i->statcallb = isdn_status_callback; + i->rcvcallb = isdn_receive_callback; + i->statcallb = isdn_status_callback; if (!strlen(i->id)) sprintf(i->id, "line%d", drvidx); save_flags(flags); cli(); - for (j = 0; j < drvidx; j++) - if (!strcmp(i->id,dev->drvid[j])) - sprintf(i->id, "line%d", drvidx); + 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) { @@ -2009,7 +2203,8 @@ #define isdn_init init_module #endif -static char *isdn_getrev(const char *revision) +static char * +isdn_getrev(const char *revision) { char *rev; char *p; @@ -2023,24 +2218,18 @@ return rev; } -EXPORT_SYMBOL(register_isdn); - -static void isdn_export_syms(void) -{ - has_exported = 1; -} - /* * Allocate and initialize all data, register modem-devices */ -int isdn_init(void) +int +isdn_init(void) { int i; - char irev[50]; - char trev[50]; - char nrev[50]; - char prev[50]; - char arev[50]; + char irev[50]; + char trev[50]; + char nrev[50]; + char prev[50]; + char arev[50]; sti(); if (!(dev = (isdn_dev *) kmalloc(sizeof(isdn_dev), GFP_KERNEL))) { @@ -2049,8 +2238,8 @@ } memset((char *) dev, 0, sizeof(isdn_dev)); #ifdef NEW_ISDN_TIMER_CTRL - init_timer(&dev->timer); - dev->timer.function = isdn_timer_funct; + init_timer(&dev->timer); + dev->timer.function = isdn_timer_funct; #endif for (i = 0; i < ISDN_MAX_CHANNELS; i++) { dev->drvmap[i] = -1; @@ -2084,21 +2273,20 @@ kfree(dev); return -EIO; } -#endif /* CONFIG_ISDN_PPP */ +#endif /* CONFIG_ISDN_PPP */ - if (!has_exported) - isdn_export_syms(); + isdn_export_syms(); - strcpy(irev,isdn_revision); - strcpy(trev,isdn_tty_revision); - strcpy(nrev,isdn_net_revision); - strcpy(prev,isdn_ppp_revision); - strcpy(arev,isdn_audio_revision); + strcpy(irev, isdn_revision); + strcpy(trev, isdn_tty_revision); + strcpy(nrev, isdn_net_revision); + strcpy(prev, isdn_ppp_revision); + strcpy(arev, isdn_audio_revision); printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(irev)); - printk("%s/", isdn_getrev(trev)); - printk("%s/", isdn_getrev(nrev)); - printk("%s/", isdn_getrev(prev)); - printk("%s", isdn_getrev(arev)); + printk("%s/", isdn_getrev(trev)); + printk("%s/", isdn_getrev(nrev)); + printk("%s/", isdn_getrev(prev)); + printk("%s", isdn_getrev(arev)); #ifdef MODULE printk(" loaded\n"); @@ -2114,7 +2302,8 @@ /* * Unload module */ -void cleanup_module(void) +void +cleanup_module(void) { int flags; int i; @@ -2140,9 +2329,9 @@ return; } for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - isdn_tty_cleanup_xmit(&dev->mdm.info[i]); - kfree(dev->mdm.info[i].xmit_buf - 4); - } + isdn_tty_cleanup_xmit(&dev->mdm.info[i]); + kfree(dev->mdm.info[i].xmit_buf - 4); + } if (unregister_chrdev(ISDN_MAJOR, "isdn") != 0) { printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n"); } else { diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/isdn_common.h linux/drivers/isdn/isdn_common.h --- v2.1.26/linux/drivers/isdn/isdn_common.h Sat Jun 1 01:56:51 1996 +++ linux/drivers/isdn/isdn_common.h Tue Feb 25 17:12:50 1997 @@ -1,11 +1,11 @@ -/* $Id: isdn_common.h,v 1.3 1996/05/19 00:13:05 fritz Exp $ - * +/* $Id: isdn_common.h,v 1.5 1997/02/10 10:05:45 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 1995,96 by Thinking Objects Software GmbH Wuerzburg * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.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 * the Free Software Foundation; either version 2, or (at your option) @@ -18,9 +18,16 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_common.h,v $ + * Revision 1.5 1997/02/10 10:05:45 fritz + * More changes for Kernel 2.1.X + * Symbol information moved to isdn_syms.c + * + * Revision 1.4 1997/02/03 22:56:50 fritz + * Removed isdn_writebuf_stub prototype. + * * Revision 1.3 1996/05/19 00:13:05 fritz * Removed debug flag. * @@ -44,20 +51,25 @@ #undef ISDN_DEBUG_NET_ICALL /* Prototypes */ -extern void isdn_MOD_INC_USE_COUNT(void); -extern void isdn_MOD_DEC_USE_COUNT(void); -extern void isdn_free_channel(int di, int ch, int usage); -extern void isdn_all_eaz(int di, int ch); -extern int isdn_dc2minor(int di, int ch); -extern void isdn_info_update(void); -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 **); -extern int isdn_readbchan (int, int, u_char *, u_char *, int, int); -extern int isdn_get_free_channel(int, int, int, int, int); -extern int isdn_writebuf_stub(int, int, const u_char *, int, int); -extern int isdn_writebuf_skb_stub(int, int, struct sk_buff *); +extern void isdn_MOD_INC_USE_COUNT(void); +extern void isdn_MOD_DEC_USE_COUNT(void); +extern void isdn_free_channel(int di, int ch, int usage); +extern void isdn_all_eaz(int di, int ch); +extern int isdn_dc2minor(int di, int ch); +extern void isdn_info_update(void); +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 **); +extern int isdn_readbchan(int, int, u_char *, u_char *, int, int); +extern int isdn_get_free_channel(int, int, int, int, int); +extern int isdn_writebuf_skb_stub(int, int, struct sk_buff *); +extern int register_isdn(isdn_if * i); +#if (LINUX_VERSION_CODE < 0x020111) +extern void isdn_export_syms(void); +#else +#define isdn_export_syms() +#endif #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) -extern void isdn_dumppkt(char *, u_char *, int, int); +extern void isdn_dumppkt(char *, u_char *, int, int); #endif diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c --- v2.1.26/linux/drivers/isdn/isdn_net.c Wed Oct 30 04:26:48 1996 +++ linux/drivers/isdn/isdn_net.c Tue Feb 25 17:12:50 1997 @@ -1,11 +1,11 @@ -/* $Id: isdn_net.c,v 1.20 1996/08/29 20:06:03 fritz Exp $ - * +/* $Id: isdn_net.c,v 1.37 1997/02/11 18:32:51 fritz Exp $ + * Linux ISDN subsystem, network interfaces and related functions (linklevel). * * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.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 * the Free Software Foundation; either version 2, or (at your option) @@ -18,9 +18,67 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.c,v $ + * Revision 1.37 1997/02/11 18:32:51 fritz + * Bugfix in isdn_ppp_free_mpqueue(). + * + * Revision 1.36 1997/02/10 21:31:11 fritz + * Changed setup-interface (incoming and outgoing). + * + * Revision 1.35 1997/02/10 20:12:45 fritz + * Changed interface for reporting incoming calls. + * + * Revision 1.34 1997/02/03 23:15:07 fritz + * Reformatted according CodingStyle. + * replaced arp_find prototype by proper include. + * made dev_purge_queues static. + * Bugfix in bogocps calculation. + * removed isdn_net_receive_callback - was never used ;-) + * Misc. fixes for Kernel 2.1.X comaptibility. + * + * Revision 1.33 1997/01/17 01:19:25 fritz + * Applied chargeint patch. + * + * Revision 1.32 1997/01/14 01:29:31 fritz + * Bugfix: isdn_net_hangup() did not reset ISDN_NET_CONNECTED. + * + * Revision 1.31 1997/01/11 23:30:42 fritz + * Speed up dial statemachine. + * + * Revision 1.30 1996/11/25 17:20:50 hipp + * fixed pppbind bug in isdn_net_find_icall() + * + * Revision 1.29 1996/11/13 02:31:38 fritz + * Minor cleanup. + * + * Revision 1.28 1996/10/27 20:49:06 keil + * bugfix to compile without MPP + * + * Revision 1.27 1996/10/25 18:46:01 fritz + * Another bugfix in isdn_net_autohup() + * + * Revision 1.26 1996/10/23 23:05:36 fritz + * Bugfix: Divide by zero in isdn_net_autohup() + * + * Revision 1.25 1996/10/22 23:13:58 fritz + * Changes for compatibility to 2.0.X and 2.1.X kernels. + * + * Revision 1.24 1996/10/11 13:57:40 fritz + * Bugfix: Error in BogoCPS calculation. + * + * Revision 1.23 1996/09/23 01:58:08 fritz + * Fix: With syncPPP encapsulation, discard LCP packets + * when calculating hangup timeout. + * + * Revision 1.22 1996/09/23 00:03:37 fritz + * Fix: did not compile without CONFIG_ISDN_PPP + * + * Revision 1.21 1996/09/07 12:44:50 hipp + * (hopefully) fixed callback problem with syncPPP + * syncPPP network devices now show PPP link encap + * * Revision 1.20 1996/08/29 20:06:03 fritz * Bugfix: Transmission timeout had been much to low. * @@ -106,32 +164,27 @@ * */ -#include #include #define __NO_VERSION__ #include #include #include +#include #include "isdn_common.h" #include "isdn_net.h" #ifdef CONFIG_ISDN_PPP #include "isdn_ppp.h" #endif -/* In ksyms.c, but why not in some .h ??? */ -extern int arp_find(unsigned char *, u32, struct device *, u32, - struct sk_buff *); - /* 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 *); - -extern void dev_purge_queues(struct device *dev); /* move this to net/core/dev.c */ +static void dev_purge_queues(struct device *dev); /* move this to net/core/dev.c */ -char *isdn_net_revision = "$Revision: 1.20 $"; +char *isdn_net_revision = "$Revision: 1.37 $"; /* * Code for raw-networking over ISDN @@ -143,7 +196,7 @@ ulong flags; save_flags(flags); - cli(); /* Avoid glitch on writes to CMD regs */ + cli(); /* Avoid glitch on writes to CMD regs */ dev->interrupt = 0; dev->tbusy = 0; restore_flags(flags); @@ -163,7 +216,7 @@ dev->dev_addr[i] = 0xfc; memcpy(&(dev->dev_addr[i]), &dev->pa_addr, sizeof(u32)); - /* If this interface has slaves, start them also */ + /* If this interface has slaves, start them also */ if ((p = (((isdn_net_local *) dev->priv)->slave))) { while (p) { @@ -171,27 +224,26 @@ p->start = 1; p = (((isdn_net_local *) p->priv)->slave); } - } - - isdn_MOD_INC_USE_COUNT(); - return 0; -} + } + isdn_MOD_INC_USE_COUNT(); + return 0; +} -/* - Assign an ISDN-channel to a net-interface +/* + * Assign an ISDN-channel to a net-interface */ static void isdn_net_bind_channel(isdn_net_local * lp, int idx) { - ulong flags; + ulong flags; - save_flags(flags); - cli(); + save_flags(flags); + cli(); lp->isdn_device = dev->drvmap[idx]; lp->isdn_channel = dev->chanmap[idx]; - dev->rx_netdev[idx] = lp->netdev; - dev->st_netdev[idx] = lp->netdev; - restore_flags(flags); + dev->rx_netdev[idx] = lp->netdev; + dev->st_netdev[idx] = lp->netdev; + restore_flags(flags); } /* @@ -204,25 +256,25 @@ save_flags(flags); cli(); - if (lp->first_skb) { - dev_kfree_skb(lp->first_skb,FREE_WRITE); - lp->first_skb = NULL; - } - if(lp->sav_skb) { - dev_kfree_skb(lp->sav_skb,FREE_WRITE); + if (lp->first_skb) { + dev_kfree_skb(lp->first_skb, FREE_WRITE); + lp->first_skb = NULL; + } + if (lp->sav_skb) { + dev_kfree_skb(lp->sav_skb, FREE_WRITE); lp->sav_skb = NULL; } - if(!lp->master) /* purge only for master device */ + if (!lp->master) /* purge only for master device */ dev_purge_queues(&lp->netdev->dev); 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; + dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL; + dev->st_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL; isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET); lp->flags &= ~ISDN_NET_CONNECTED; lp->isdn_device = -1; lp->isdn_channel = -1; - restore_flags(flags); + restore_flags(flags); } /* @@ -238,41 +290,56 @@ * Since this function is called every second, simply reset the * byte-counter of the interface after copying it to the cps-variable. */ +unsigned long last_jiffies = -HZ; + void isdn_net_autohup() { isdn_net_dev *p = dev->netdev; - int anymore; - ulong flags; + int anymore; - save_flags(flags); - cli(); - anymore = 0; + anymore = 0; while (p) { isdn_net_local *l = (isdn_net_local *) & (p->local); - l->cps = l->transcount; + if ((jiffies - last_jiffies) == 0) + l->cps = l->transcount; + else + l->cps = (l->transcount * HZ) / (jiffies - last_jiffies); l->transcount = 0; if (dev->net_verbose > 3) printk(KERN_DEBUG "%s: %d bogocps\n", l->name, l->cps); if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) { - anymore = 1; + anymore = 1; l->huptimer++; if ((l->onhtime) && (l->huptimer > l->onhtime)) - if (l->outgoing) { - if (l->hupflags & 4) { - if (l->hupflags & 1) + if (l->hupflags & ISDN_MANCHARGE && + l->hupflags & ISDN_CHARGEHUP) { + while (jiffies - l->chargetime > l->chargeint) + l->chargetime += l->chargeint; + if (jiffies - l->chargetime >= l->chargeint - 2 * HZ) + if (l->outgoing || l->hupflags & ISDN_INHUP) isdn_net_hangup(&p->dev); - else if (jiffies - l->chargetime > l->chargeint) + } else if (l->outgoing) { + if (l->hupflags & ISDN_CHARGEHUP) { + if (l->hupflags & ISDN_WAITCHARGE) { + printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n", + l->name, l->hupflags); isdn_net_hangup(&p->dev); + } else if (jiffies - l->chargetime > l->chargeint) { + printk(KERN_DEBUG + "isdn_net: %s: chtime = %d, chint = %d\n", + l->name, l->chargetime, l->chargeint); + isdn_net_hangup(&p->dev); + } } else isdn_net_hangup(&p->dev); - } else if (l->hupflags & 8) + } else if (l->hupflags & ISDN_INHUP) isdn_net_hangup(&p->dev); } p = (isdn_net_dev *) p->next; } - isdn_timer_ctrl(ISDN_TIMER_NETHANGUP,anymore); - restore_flags(flags); + last_jiffies = jiffies; + isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore); } /* @@ -288,57 +355,56 @@ if (p) { isdn_net_local *lp = &(p->local); - switch (cmd) { + switch (cmd) { case ISDN_STAT_BSENT: /* A packet has successfully been sent out */ if ((lp->flags & ISDN_NET_CONNECTED) && (!lp->dialstate)) { lp->stats.tx_packets++; - if(lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && lp->sav_skb) { + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && lp->sav_skb) { struct device *mdev; - if(lp->master) + if (lp->master) mdev = lp->master; else mdev = &lp->netdev->dev; - if(!isdn_net_send_skb(mdev,lp,lp->sav_skb)) { + if (!isdn_net_send_skb(mdev, lp, lp->sav_skb)) { lp->sav_skb = NULL; mark_bh(NET_BH); - } - else { + } else { return 1; } } - if (clear_bit(0,(void*)&(p->dev.tbusy))) - mark_bh(NET_BH); + if (clear_bit(0, (void *) &(p->dev.tbusy))) + mark_bh(NET_BH); } return 1; case ISDN_STAT_DCONN: /* D-Channel is up */ - switch (lp->dialstate) { - case 4: - case 7: - case 8: - lp->dialstate++; - return 1; - case 12: - lp->dialstate = 5; - return 1; - } + switch (lp->dialstate) { + case 4: + case 7: + case 8: + lp->dialstate++; + return 1; + case 12: + lp->dialstate = 5; + return 1; + } break; case ISDN_STAT_DHUP: /* Either D-Channel-hangup or error during dialout */ if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) { lp->flags &= ~ISDN_NET_CONNECTED; - if(lp->first_skb) { - dev_kfree_skb(lp->first_skb,FREE_WRITE); + if (lp->first_skb) { + dev_kfree_skb(lp->first_skb, FREE_WRITE); lp->first_skb = NULL; } - if(lp->sav_skb) { - dev_kfree_skb(lp->sav_skb,FREE_WRITE); + if (lp->sav_skb) { + dev_kfree_skb(lp->sav_skb, FREE_WRITE); lp->sav_skb = NULL; } isdn_free_channel(lp->isdn_device, lp->isdn_channel, - ISDN_USAGE_NET); + ISDN_USAGE_NET); #ifdef CONFIG_ISDN_PPP isdn_ppp_free(lp); #endif @@ -350,49 +416,51 @@ lp->isdn_channel = -1; dev->st_netdev[idx] = NULL; dev->rx_netdev[idx] = NULL; - return 1; + return 1; } - break; + break; case ISDN_STAT_BCONN: /* B-Channel is up */ - switch (lp->dialstate) { - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - case 12: - if (lp->dialstate <= 6) { - dev->usage[idx] |= ISDN_USAGE_OUTGOING; - isdn_info_update(); - } else - dev->rx_netdev[idx] = p; - lp->dialstate = 0; - isdn_timer_ctrl(ISDN_TIMER_NETHANGUP,1); - printk(KERN_INFO "isdn_net: %s connected\n", lp->name); - /* If first Chargeinfo comes before B-Channel connect, - * we correct the timestamp here. - */ - lp->chargetime = jiffies; - /* Immediately send first skb to speed up arp */ + switch (lp->dialstate) { + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 12: + if (lp->dialstate <= 6) { + dev->usage[idx] |= ISDN_USAGE_OUTGOING; + isdn_info_update(); + } else + dev->rx_netdev[idx] = p; + lp->dialstate = 0; + isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1); + printk(KERN_INFO "isdn_net: %s connected\n", lp->name); + /* If first Chargeinfo comes before B-Channel connect, + * we correct the timestamp here. + */ + lp->chargetime = jiffies; + printk(KERN_DEBUG "isdn_net: chargetime of %s now %d\n", + lp->name, lp->chargetime); + /* Immediately send first skb to speed up arp */ #ifdef CONFIG_ISDN_PPP - if(lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) isdn_ppp_wakeup_daemon(lp); #endif - if (lp->first_skb) { - if (!(isdn_net_xmit(&p->dev,lp,lp->first_skb))) - lp->first_skb = NULL; - } - return 1; + if (lp->first_skb) { + if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb))) + lp->first_skb = NULL; + } + return 1; } break; case ISDN_STAT_NODCH: /* No D-Channel avail. */ if (lp->dialstate == 4) { lp->dialstate--; - return 1; - } + return 1; + } break; case ISDN_STAT_CINF: /* Charge-info from TelCo. Calculate interval between @@ -400,17 +468,19 @@ * usage by isdn_net_autohup() */ lp->charge++; - if (lp->hupflags & 2) { - lp->hupflags &= ~1; + if (lp->hupflags & ISDN_HAVECHARGE) { + lp->hupflags &= ~ISDN_WAITCHARGE; lp->chargeint = jiffies - lp->chargetime - (2 * HZ); } - if (lp->hupflags & 1) - lp->hupflags |= 2; + if (lp->hupflags & ISDN_WAITCHARGE) + lp->hupflags |= ISDN_HAVECHARGE; lp->chargetime = jiffies; + printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %d\n", + lp->name, lp->chargetime); return 1; - } + } } - return 0; + return 0; } /* @@ -447,187 +517,195 @@ while (p) { #ifdef ISDN_DEBUG_NET_DIAL - if (p->local.dialstate) - printk(KERN_DEBUG "%s: dialstate=%d\n", p->local.name,p->local.dialstate); + if (p->local.dialstate) + printk(KERN_DEBUG "%s: dialstate=%d\n", p->local.name, p->local.dialstate); #endif switch (p->local.dialstate) { - case 0: - /* Nothing to do for this interface */ - break; - case 1: - /* Initiate dialout. Set phone-number-pointer to first number - * of interface. - */ - p->local.dial = p->local.phone[1]; - anymore = 1; - p->local.dialstate++; - break; - /* Prepare dialing. Clear EAZ, then set EAZ. */ - case 2: - cmd.driver = p->local.isdn_device; - cmd.arg = p->local.isdn_channel; - cmd.command = ISDN_CMD_CLREAZ; - dev->drv[p->local.isdn_device]->interface->command(&cmd); - sprintf(cmd.num, "%s", isdn_map_eaz2msn(p->local.msn, cmd.driver)); - cmd.command = ISDN_CMD_SETEAZ; - dev->drv[p->local.isdn_device]->interface->command(&cmd); - p->local.dialretry = 0; - anymore = 1; - p->local.dialstate++; - break; - case 3: - /* Setup interface, dial current phone-number, switch to next number. - * If list of phone-numbers is exhausted, increment - * retry-counter. - */ - cmd.driver = p->local.isdn_device; - cmd.command = ISDN_CMD_SETL2; - cmd.arg = p->local.isdn_channel + (p->local.l2_proto << 8); - dev->drv[p->local.isdn_device]->interface->command(&cmd); - cmd.driver = p->local.isdn_device; - cmd.command = ISDN_CMD_SETL3; - cmd.arg = p->local.isdn_channel + (p->local.l3_proto << 8); - dev->drv[p->local.isdn_device]->interface->command(&cmd); - cmd.driver = p->local.isdn_device; - cmd.arg = p->local.isdn_channel; - p->local.huptimer = 0; - p->local.outgoing = 1; - p->local.hupflags |= 1; - p->local.hupflags &= ~2; - if (!strcmp(p->local.dial->num, "LEASED")) { - p->local.dialstate = 4; - printk(KERN_INFO "%s: Open leased line ...\n", p->local.name); - } else { - cmd.command = ISDN_CMD_DIAL; - sprintf(cmd.num, "%s,%s,7,0", p->local.dial->num, - isdn_map_eaz2msn(p->local.msn, cmd.driver)); - i = isdn_dc2minor(p->local.isdn_device, p->local.isdn_channel); - if (i >= 0) { - strcpy(dev->num[i], p->local.dial->num); - isdn_info_update(); - } - printk(KERN_INFO "%s: dialing %d %s...\n", p->local.name, - p->local.dialretry, p->local.dial->num); - /* - * Switch to next number or back to start if at end of list. + case 0: + /* Nothing to do for this interface */ + break; + case 1: + /* Initiate dialout. Set phone-number-pointer to first number + * of interface. + */ + p->local.dial = p->local.phone[1]; + anymore = 1; + p->local.dialstate++; + /* Fall through */ + case 2: + /* Prepare dialing. Clear EAZ, then set EAZ. */ + cmd.driver = p->local.isdn_device; + cmd.arg = p->local.isdn_channel; + cmd.command = ISDN_CMD_CLREAZ; + dev->drv[p->local.isdn_device]->interface->command(&cmd); + sprintf(cmd.parm.num, "%s", isdn_map_eaz2msn(p->local.msn, cmd.driver)); + cmd.command = ISDN_CMD_SETEAZ; + dev->drv[p->local.isdn_device]->interface->command(&cmd); + p->local.dialretry = 0; + anymore = 1; + p->local.dialstate++; + /* Falls through */ + case 3: + /* Setup interface, dial current phone-number, switch to next number. + * If list of phone-numbers is exhausted, increment + * retry-counter. */ - if (!(p->local.dial = (isdn_net_phone *) p->local.dial->next)) { - p->local.dial = p->local.phone[1]; - p->local.dialretry++; + cmd.driver = p->local.isdn_device; + cmd.command = ISDN_CMD_SETL2; + cmd.arg = p->local.isdn_channel + (p->local.l2_proto << 8); + dev->drv[p->local.isdn_device]->interface->command(&cmd); + cmd.driver = p->local.isdn_device; + cmd.command = ISDN_CMD_SETL3; + cmd.arg = p->local.isdn_channel + (p->local.l3_proto << 8); + dev->drv[p->local.isdn_device]->interface->command(&cmd); + cmd.driver = p->local.isdn_device; + cmd.arg = p->local.isdn_channel; + p->local.huptimer = 0; + p->local.outgoing = 1; + if (p->local.chargeint) { + p->local.hupflags |= ISDN_HAVECHARGE; + p->local.hupflags &= ~ISDN_WAITCHARGE; + } else { + p->local.hupflags |= ISDN_WAITCHARGE; + p->local.hupflags &= ~ISDN_HAVECHARGE; } - p->local.dtimer = 0; + if (!strcmp(p->local.dial->num, "LEASED")) { + p->local.dialstate = 4; + printk(KERN_INFO "%s: Open leased line ...\n", p->local.name); + } else { + cmd.command = ISDN_CMD_DIAL; + cmd.parm.setup.si1 = 7; + cmd.parm.setup.si2 = 0; + sprintf(cmd.parm.setup.phone, "%s", p->local.dial->num); + sprintf(cmd.parm.setup.eazmsn, "%s", + isdn_map_eaz2msn(p->local.msn, cmd.driver)); + i = isdn_dc2minor(p->local.isdn_device, p->local.isdn_channel); + if (i >= 0) { + strcpy(dev->num[i], p->local.dial->num); + isdn_info_update(); + } + printk(KERN_INFO "%s: dialing %d %s...\n", p->local.name, + p->local.dialretry, p->local.dial->num); + /* + * Switch to next number or back to start if at end of list. + */ + if (!(p->local.dial = (isdn_net_phone *) p->local.dial->next)) { + p->local.dial = p->local.phone[1]; + p->local.dialretry++; + } + p->local.dtimer = 0; #ifdef ISDN_DEBUG_NET_DIAL - printk(KERN_DEBUG "dial: d=%d c=%d\n", p->local.isdn_device, - p->local.isdn_channel); + printk(KERN_DEBUG "dial: d=%d c=%d\n", p->local.isdn_device, + p->local.isdn_channel); #endif + dev->drv[p->local.isdn_device]->interface->command(&cmd); + } + anymore = 1; + p->local.dialstate = + (p->local.cbdelay && + (p->local.flags & ISDN_NET_CBOUT)) ? 12 : 4; + break; + case 4: + /* Wait for D-Channel-connect. + * If timeout and max retries not + * reached, switch back to state 3. + */ + if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10) + if (p->local.dialretry < p->local.dialmax) { + p->local.dialstate = 3; + } else + isdn_net_hangup(&p->dev); + anymore = 1; + break; + case 5: + /* Got D-Channel-Connect, send B-Channel-request */ + cmd.driver = p->local.isdn_device; + cmd.arg = p->local.isdn_channel; + cmd.command = ISDN_CMD_ACCEPTB; + anymore = 1; + p->local.dtimer = 0; + p->local.dialstate++; dev->drv[p->local.isdn_device]->interface->command(&cmd); - } - anymore = 1; - p->local.dialstate = - (p->local.cbdelay && - (p->local.flags & ISDN_NET_CBOUT))?12:4; - break; - case 4: - /* Wait for D-Channel-connect. - * If timeout and max retries not - * reached, switch back to state 3. - */ - if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10) - if (p->local.dialretry < p->local.dialmax) { - p->local.dialstate = 3; - } else - isdn_net_hangup(&p->dev); - anymore = 1; - break; - case 5: - /* Got D-Channel-Connect, send B-Channel-request */ - cmd.driver = p->local.isdn_device; - cmd.arg = p->local.isdn_channel; - cmd.command = ISDN_CMD_ACCEPTB; - anymore = 1; - p->local.dtimer = 0; - p->local.dialstate++; - dev->drv[p->local.isdn_device]->interface->command(&cmd); - break; - case 6: - /* Wait for B- or D-Channel-connect. If timeout, - * switch back to state 3. - */ + break; + case 6: + /* Wait for B- or D-Channel-connect. If timeout, + * switch back to state 3. + */ #ifdef ISDN_DEBUG_NET_DIAL - printk(KERN_DEBUG "dialtimer2: %d\n", p->local.dtimer); + printk(KERN_DEBUG "dialtimer2: %d\n", p->local.dtimer); #endif - if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10) - p->local.dialstate = 3; - anymore = 1; - break; - case 7: - /* Got incoming Call, setup L2 and L3 protocols, - * then wait for D-Channel-connect - */ + if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10) + p->local.dialstate = 3; + anymore = 1; + break; + case 7: + /* Got incoming Call, setup L2 and L3 protocols, + * then wait for D-Channel-connect + */ #ifdef ISDN_DEBUG_NET_DIAL - printk(KERN_DEBUG "dialtimer4: %d\n", p->local.dtimer); + printk(KERN_DEBUG "dialtimer4: %d\n", p->local.dtimer); #endif - cmd.driver = p->local.isdn_device; - cmd.command = ISDN_CMD_SETL2; - cmd.arg = p->local.isdn_channel + (p->local.l2_proto << 8); - dev->drv[p->local.isdn_device]->interface->command(&cmd); - cmd.driver = p->local.isdn_device; - cmd.command = ISDN_CMD_SETL3; - cmd.arg = p->local.isdn_channel + (p->local.l3_proto << 8); - dev->drv[p->local.isdn_device]->interface->command(&cmd); - if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT15) - isdn_net_hangup(&p->dev); - else { + cmd.driver = p->local.isdn_device; + cmd.command = ISDN_CMD_SETL2; + cmd.arg = p->local.isdn_channel + (p->local.l2_proto << 8); + dev->drv[p->local.isdn_device]->interface->command(&cmd); + cmd.driver = p->local.isdn_device; + cmd.command = ISDN_CMD_SETL3; + cmd.arg = p->local.isdn_channel + (p->local.l3_proto << 8); + dev->drv[p->local.isdn_device]->interface->command(&cmd); + if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT15) + isdn_net_hangup(&p->dev); + else { + anymore = 1; + p->local.dialstate++; + } + break; + case 9: + /* Got incoming D-Channel-Connect, send B-Channel-request */ + cmd.driver = p->local.isdn_device; + cmd.arg = p->local.isdn_channel; + cmd.command = ISDN_CMD_ACCEPTB; + dev->drv[p->local.isdn_device]->interface->command(&cmd); anymore = 1; - p->local.dialstate++; - } - break; - case 9: - /* Got incoming D-Channel-Connect, send B-Channel-request */ - cmd.driver = p->local.isdn_device; - cmd.arg = p->local.isdn_channel; - cmd.command = ISDN_CMD_ACCEPTB; - dev->drv[p->local.isdn_device]->interface->command(&cmd); - anymore = 1; - p->local.dtimer = 0; - p->local.dialstate++; - break; - case 8: - case 10: - /* Wait for B- or D-channel-connect */ + p->local.dtimer = 0; + p->local.dialstate++; + break; + case 8: + case 10: + /* Wait for B- or D-channel-connect */ #ifdef ISDN_DEBUG_NET_DIAL - printk(KERN_DEBUG "dialtimer4: %d\n", p->local.dtimer); + printk(KERN_DEBUG "dialtimer4: %d\n", p->local.dtimer); #endif - if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10) - isdn_net_hangup(&p->dev); - else + if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10) + isdn_net_hangup(&p->dev); + else + anymore = 1; + break; + case 11: + /* Callback Delay */ + if (p->local.dtimer++ > p->local.cbdelay) + p->local.dialstate = 1; anymore = 1; - break; - case 11: - /* Callback Delay */ - if (p->local.dtimer++ > p->local.cbdelay) - p->local.dialstate = 1; - anymore = 1; - break; - case 12: - /* Remote does callback. Hangup after cbdelay, then wait for incoming - * call (in state 4). - */ - if (p->local.dtimer++ > p->local.cbdelay) { - printk(KERN_INFO "%s: hangup waiting for callback ...\n", p->local.name); - p->local.dtimer = 0; - p->local.dialstate = 4; - cmd.driver = p->local.isdn_device; - cmd.command = ISDN_CMD_HANGUP; - cmd.arg = p->local.isdn_channel; - (void) dev->drv[cmd.driver]->interface->command(&cmd); - isdn_all_eaz(p->local.isdn_device, p->local.isdn_channel); - } - anymore = 1; - break; - default: - printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n", - p->local.dialstate, p->local.name); + break; + case 12: + /* Remote does callback. Hangup after cbdelay, then wait for incoming + * call (in state 4). + */ + if (p->local.dtimer++ > p->local.cbdelay) { + printk(KERN_INFO "%s: hangup waiting for callback ...\n", p->local.name); + p->local.dtimer = 0; + p->local.dialstate = 4; + cmd.driver = p->local.isdn_device; + cmd.command = ISDN_CMD_HANGUP; + cmd.arg = p->local.isdn_channel; + (void) dev->drv[cmd.driver]->interface->command(&cmd); + isdn_all_eaz(p->local.isdn_device, p->local.isdn_channel); + } + anymore = 1; + break; + default: + printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n", + p->local.dialstate, p->local.name); } p = (isdn_net_dev *) p->next; } @@ -644,6 +722,7 @@ isdn_ctrl cmd; 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); @@ -655,7 +734,7 @@ printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge); isdn_all_eaz(lp->isdn_device, lp->isdn_channel); } - isdn_net_unbind_channel(lp); + isdn_net_unbind_channel(lp); } typedef struct { @@ -666,59 +745,59 @@ static void isdn_net_log_packet(u_char * buf, isdn_net_local * lp) { - u_char *p = buf; + u_char *p = buf; unsigned short proto = ETH_P_IP; - int data_ofs; + int data_ofs; ip_ports *ipp; char addinfo[100]; - addinfo[0] = '\0'; - switch (lp->p_encap) { - case ISDN_NET_ENCAP_IPTYP: - proto = ntohs(*(unsigned short *)&buf[0]); - p = &buf[2]; - break; - case ISDN_NET_ENCAP_ETHER: - proto = ntohs(*(unsigned short *)&buf[12]); - p = &buf[14]; - break; - case ISDN_NET_ENCAP_CISCOHDLC: - proto = ntohs(*(unsigned short *)&buf[2]); - p = &buf[4]; - break; - } + addinfo[0] = '\0'; + switch (lp->p_encap) { + case ISDN_NET_ENCAP_IPTYP: + proto = ntohs(*(unsigned short *) &buf[0]); + p = &buf[2]; + break; + case ISDN_NET_ENCAP_ETHER: + proto = ntohs(*(unsigned short *) &buf[12]); + p = &buf[14]; + break; + case ISDN_NET_ENCAP_CISCOHDLC: + proto = ntohs(*(unsigned short *) &buf[2]); + p = &buf[4]; + break; + } data_ofs = ((p[0] & 15) * 4); - switch (proto) { + switch (proto) { case ETH_P_IP: switch (p[9]) { - case 1: - strcpy(addinfo, " ICMP"); - break; - case 2: - strcpy(addinfo, " IGMP"); - break; - case 4: - strcpy(addinfo, " IPIP"); - break; - case 6: - ipp = (ip_ports *) (&p[data_ofs]); - sprintf(addinfo, " TCP, port: %d -> %d", ntohs(ipp->source), - ntohs(ipp->dest)); - break; - case 8: - strcpy(addinfo, " EGP"); - break; - case 12: - strcpy(addinfo, " PUP"); - break; - case 17: - ipp = (ip_ports *) (&p[data_ofs]); - sprintf(addinfo, " UDP, port: %d -> %d", ntohs(ipp->source), - ntohs(ipp->dest)); - break; - case 22: - strcpy(addinfo, " IDP"); - break; + case 1: + strcpy(addinfo, " ICMP"); + break; + case 2: + strcpy(addinfo, " IGMP"); + break; + case 4: + strcpy(addinfo, " IPIP"); + break; + case 6: + ipp = (ip_ports *) (&p[data_ofs]); + sprintf(addinfo, " TCP, port: %d -> %d", ntohs(ipp->source), + ntohs(ipp->dest)); + break; + case 8: + strcpy(addinfo, " EGP"); + break; + case 12: + strcpy(addinfo, " PUP"); + break; + case 17: + ipp = (ip_ports *) (&p[data_ofs]); + sprintf(addinfo, " UDP, port: %d -> %d", ntohs(ipp->source), + ntohs(ipp->dest)); + break; + case 22: + strcpy(addinfo, " IDP"); + break; } printk(KERN_INFO "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n", p[12], p[13], p[14], p[15], @@ -730,7 +809,7 @@ p[14], p[15], p[16], p[17], p[24], p[25], p[26], p[27]); break; - } + } } /* @@ -742,28 +821,28 @@ * Side-effects: ndev->tbusy is cleared on success. */ int -isdn_net_send_skb(struct device *ndev, isdn_net_local *lp, - struct sk_buff *skb) +isdn_net_send_skb(struct device *ndev, isdn_net_local * lp, + struct sk_buff *skb) { int ret; - int len = skb->len; /* save len */ - - ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb); + int len = skb->len; /* save len */ + + ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb); if (ret == len) { lp->transcount += len; - clear_bit(0, (void *)&(ndev->tbusy)); + clear_bit(0, (void *) &(ndev->tbusy)); + return 0; + } + if (ret < 0) { + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_WRITE); + lp->stats.tx_errors++; + clear_bit(0, (void *) &(ndev->tbusy)); return 0; } - if (ret < 0) { - skb->free = 1; - dev_kfree_skb(skb, FREE_WRITE); - lp->stats.tx_errors++; - clear_bit(0, (void *)&(ndev->tbusy)); - return 0; - } return 1; -} - +} + /* * Helper function for isdn_net_start_xmit. @@ -777,23 +856,23 @@ */ static int -isdn_net_xmit(struct device *ndev, isdn_net_local *lp, struct sk_buff *skb) +isdn_net_xmit(struct device *ndev, isdn_net_local * lp, struct sk_buff *skb) { - int ret; + int ret; /* For the other encaps the header has already been built */ #ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { return isdn_ppp_xmit(skb, ndev); } -#endif +#endif /* Reset hangup-timeout */ lp->huptimer = 0; if (lp->cps > 7000) { /* Device overloaded */ - /* - * Packet-delivery via round-robin over master + /* + * Packet-delivery via round-robin over master * and all connected slaves. */ if (lp->master) @@ -817,18 +896,16 @@ /* First time overload: set timestamp only */ lp->sqfull = 1; lp->sqfull_stamp = jiffies; - } - else { + } else { /* subsequent overload: if slavedelay exceeded, start dialing */ if ((jiffies - lp->sqfull_stamp) > lp->slavedelay) isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv); } } - } - else { + } else { /* Not overloaded, deliver locally */ ret = isdn_net_send_skb(ndev, lp, skb); - if (lp->sqfull && ((jiffies - lp->sqfull_stamp) > (lp->slavedelay + (10*HZ) ))) + if (lp->sqfull && ((jiffies - lp->sqfull_stamp) > (lp->slavedelay + (10 * HZ)))) lp->sqfull = 0; } return ret; @@ -847,8 +924,8 @@ if (ndev->tbusy) { if (jiffies - ndev->trans_start < (2 * HZ)) return 1; - if (!lp->dialstate) - lp->stats.tx_errors++; + if (!lp->dialstate) + lp->stats.tx_errors++; ndev->tbusy = 0; ndev->trans_start = jiffies; } @@ -859,8 +936,8 @@ /* Avoid timer-based retransmission conflicts. */ if (set_bit(0, (void *) &ndev->tbusy) != 0) printk(KERN_WARNING - "%s: Transmitter access conflict.\n", - ndev->name); + "%s: Transmitter access conflict.\n", + ndev->name); else { u_char *buf = skb->data; #ifdef ISDN_DEBUG_NET_DUMP @@ -873,23 +950,23 @@ save_flags(flags); cli(); /* Grab a free ISDN-Channel */ - if ((chi = - isdn_get_free_channel(ISDN_USAGE_NET, - lp->l2_proto, - lp->l3_proto, - lp->pre_device, - lp->pre_channel)) < 0) { - printk(KERN_WARNING - "isdn_net_start_xmit: No channel for %s\n", - ndev->name); + if ((chi = + isdn_get_free_channel(ISDN_USAGE_NET, + lp->l2_proto, + lp->l3_proto, + lp->pre_device, + lp->pre_channel)) < 0) { + printk(KERN_WARNING + "isdn_net_start_xmit: No channel for %s\n", + ndev->name); restore_flags(flags); - /* we probably should drop the skb here and return 0 to omit - 'socket destroy delayed' messages */ + /* we probably should drop the skb here and return 0 to omit + 'socket destroy delayed' messages */ return 1; } - /* Log packet, which triggered dialing */ + /* Log packet, which triggered dialing */ if (dev->net_verbose) - isdn_net_log_packet(buf, lp); + isdn_net_log_packet(buf, lp); lp->dialstate = 1; lp->flags |= ISDN_NET_CONNECTED; /* Connect interface with channel */ @@ -898,59 +975,59 @@ if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { /* no 'first_skb' handling for syncPPP */ if (isdn_ppp_bind(lp) < 0) { - dev_kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb, FREE_WRITE); isdn_net_unbind_channel(lp); - restore_flags(flags); + restore_flags(flags); return 0; /* STN (skb to nirvana) ;) */ } - isdn_net_dial(); /* Initiate dialing */ restore_flags(flags); + isdn_net_dial(); /* Initiate dialing */ return 1; /* let upper layer requeue skb packet */ } #endif - /* remember first skb to speed up arp - * when using encap ETHER - */ - if (lp->first_skb) { - printk(KERN_WARNING "isdn_net_start_xmit: First skb already set!\n"); - dev_kfree_skb(lp->first_skb,FREE_WRITE); - lp->first_skb = NULL; - } - lp->first_skb = skb; + /* remember first skb to speed up arp + * when using encap ETHER + */ + if (lp->first_skb) { + printk(KERN_WARNING "isdn_net_start_xmit: First skb already set!\n"); + dev_kfree_skb(lp->first_skb, FREE_WRITE); + lp->first_skb = NULL; + } + lp->first_skb = skb; /* Initiate dialing */ - isdn_net_dial(); - ndev->tbusy = 0; + ndev->tbusy = 0; restore_flags(flags); - return 0; + isdn_net_dial(); + return 0; } else { - /* - * Having no phone-number is a permanent - * failure or misconfiguration. - * Instead of just dropping, we should also - * have the upper layers to respond - * with an ICMP No route to host in the - * future, however at the moment, i don't - * know a simple way to do that. - * The same applies, when the telecom replies - * "no destination" to our dialing-attempt. - */ - printk(KERN_WARNING - "isdn_net: No phone number for %s, packet dropped\n", - ndev->name); + /* + * Having no phone-number is a permanent + * failure or misconfiguration. + * Instead of just dropping, we should also + * have the upper layers to respond + * with an ICMP No route to host in the + * future, however at the moment, i don't + * know a simple way to do that. + * The same applies, when the telecom replies + * "no destination" to our dialing-attempt. + */ + printk(KERN_WARNING + "isdn_net: No phone number for %s, packet dropped\n", + ndev->name); dev_kfree_skb(skb, FREE_WRITE); ndev->tbusy = 0; - return 0; + return 0; } } else { - /* Connection is established, try sending */ + /* Connection is established, try sending */ ndev->trans_start = jiffies; if (!lp->dialstate) { - if (lp->first_skb) { - if (isdn_net_xmit(ndev,lp,lp->first_skb)) - return 1; - lp->first_skb = NULL; - } - return(isdn_net_xmit(ndev, lp, skb)); + if (lp->first_skb) { + if (isdn_net_xmit(ndev, lp, lp->first_skb)) + return 1; + lp->first_skb = NULL; + } + return (isdn_net_xmit(ndev, lp, skb)); } else ndev->tbusy = 1; } @@ -986,7 +1063,7 @@ * Get statistics */ static struct enet_statistics * - isdn_net_get_stats(struct device *dev) +isdn_net_get_stats(struct device *dev) { isdn_net_local *lp = (isdn_net_local *) dev->priv; return &lp->stats; @@ -1001,51 +1078,50 @@ * This is normal practice and works for any 'now in use' protocol. */ -unsigned short isdn_net_type_trans(struct sk_buff *skb, struct device *dev) +static unsigned short +isdn_net_type_trans(struct sk_buff *skb, struct device *dev) { - struct ethhdr *eth; - unsigned char *rawp; - - skb_pull(skb,ETH_HLEN); - eth= skb->mac.ethernet; - - if(*eth->h_dest&1) { - if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0) - skb->pkt_type=PACKET_BROADCAST; - else - skb->pkt_type=PACKET_MULTICAST; - } - - /* - * This ALLMULTI check should be redundant by 1.4 - * so don't forget to remove it. - */ - - else if (dev->flags&(IFF_PROMISC|IFF_ALLMULTI)) { - if (memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN)) - skb->pkt_type=PACKET_OTHERHOST; - } - - if (ntohs(eth->h_proto) >= 1536) - return eth->h_proto; - - rawp = skb->data; - - /* - * This is a magic hack to spot IPX packets. Older Novell breaks - * the protocol design and runs IPX over 802.3 without an 802.2 LLC - * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This - * won't work for fault tolerant netware but does for the rest. - */ - if (*(unsigned short *)rawp == 0xFFFF) - return htons(ETH_P_802_3); - /* - * Real 802.2 LLC - */ - return htons(ETH_P_802_2); + struct ethhdr *eth; + unsigned char *rawp; + + skb_pull(skb, ETH_HLEN); + eth = skb->mac.ethernet; + + if (*eth->h_dest & 1) { + if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0) + skb->pkt_type = PACKET_BROADCAST; + else + skb->pkt_type = PACKET_MULTICAST; + } + /* + * This ALLMULTI check should be redundant by 1.4 + * so don't forget to remove it. + */ + + else if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) { + if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN)) + skb->pkt_type = PACKET_OTHERHOST; + } + if (ntohs(eth->h_proto) >= 1536) + return eth->h_proto; + + rawp = skb->data; + + /* + * This is a magic hack to spot IPX packets. Older Novell breaks + * the protocol design and runs IPX over 802.3 without an 802.2 LLC + * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This + * won't work for fault tolerant netware but does for the rest. + */ + if (*(unsigned short *) rawp == 0xFFFF) + return htons(ETH_P_802_3); + /* + * Real 802.2 LLC + */ + return htons(ETH_P_802_2); } -/* +/* * Got a packet from ISDN-Channel. */ static void @@ -1053,12 +1129,21 @@ { isdn_net_local *lp = (isdn_net_local *) ndev->priv; #ifdef CONFIG_ISDN_PPP - isdn_net_local *olp = lp; /* original 'lp' */ + isdn_net_local *olp = lp; /* original 'lp' */ + int proto = PPP_PROTOCOL(skb->data); #endif lp->transcount += skb->len; lp->stats.rx_packets++; - lp->huptimer = 0; +#ifdef CONFIG_ISDN_PPP + /* + * If encapsulation is syncppp, don't reset + * huptimer on LCP packets. + */ + if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP || + (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && proto != PPP_LCP)) +#endif + lp->huptimer = 0; if (lp->master) { /* Bundling: If device is a slave-device, deliver to master, also @@ -1067,49 +1152,56 @@ ndev = lp->master; lp = (isdn_net_local *) ndev->priv; lp->stats.rx_packets++; - lp->huptimer = 0; +#ifdef CONFIG_ISDN_PPP + /* + * If encapsulation is syncppp, don't reset + * huptimer on LCP packets. + */ + if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP || + (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && proto != PPP_LCP)) +#endif + lp->huptimer = 0; } - skb->dev = ndev; skb->pkt_type = PACKET_HOST; - skb->mac.raw = skb->data; + skb->mac.raw = skb->data; #ifdef ISDN_DEBUG_NET_DUMP - isdn_dumppkt("R:", skb->data, skb->len, 40); + isdn_dumppkt("R:", skb->data, skb->len, 40); #endif switch (lp->p_encap) { - case ISDN_NET_ENCAP_ETHER: - /* Ethernet over ISDN */ - skb->protocol = isdn_net_type_trans(skb,ndev); - break; - case ISDN_NET_ENCAP_UIHDLC: - /* HDLC with UI-frame (for ispa with -h1 option) */ - skb_pull(skb,2); - /* Fall through */ - case ISDN_NET_ENCAP_RAWIP: - /* RAW-IP without MAC-Header */ - skb->protocol = htons(ETH_P_IP); - break; - case ISDN_NET_ENCAP_CISCOHDLC: - /* CISCO-HDLC IP with type field and fake I-frame-header */ - skb_pull(skb, 2); - /* Fall through */ - case ISDN_NET_ENCAP_IPTYP: - /* IP with type field */ - skb->protocol = *(unsigned short *)&(skb->data[0]); - skb_pull(skb, 2); - if (*(unsigned short *)skb->data == 0xFFFF) - skb->protocol = htons(ETH_P_802_3); - break; + case ISDN_NET_ENCAP_ETHER: + /* Ethernet over ISDN */ + skb->protocol = isdn_net_type_trans(skb, ndev); + break; + case ISDN_NET_ENCAP_UIHDLC: + /* HDLC with UI-frame (for ispa with -h1 option) */ + skb_pull(skb, 2); + /* Fall through */ + case ISDN_NET_ENCAP_RAWIP: + /* RAW-IP without MAC-Header */ + skb->protocol = htons(ETH_P_IP); + break; + case ISDN_NET_ENCAP_CISCOHDLC: + /* CISCO-HDLC IP with type field and fake I-frame-header */ + skb_pull(skb, 2); + /* Fall through */ + case ISDN_NET_ENCAP_IPTYP: + /* IP with type field */ + skb->protocol = *(unsigned short *) &(skb->data[0]); + skb_pull(skb, 2); + if (*(unsigned short *) skb->data == 0xFFFF) + skb->protocol = htons(ETH_P_802_3); + break; #ifdef CONFIG_ISDN_PPP - case ISDN_NET_ENCAP_SYNCPPP: - isdn_ppp_receive(lp->netdev, olp, skb); - return; -#endif - default: - printk(KERN_WARNING "%s: unknown encapsulation, dropping\n", - lp->name); - kfree_skb(skb,FREE_READ); - return; + case ISDN_NET_ENCAP_SYNCPPP: + isdn_ppp_receive(lp->netdev, olp, skb); + return; +#endif + default: + printk(KERN_WARNING "%s: unknown encapsulation, dropping\n", + lp->name); + kfree_skb(skb, FREE_READ); + return; } netif_rx(skb); return; @@ -1121,34 +1213,7 @@ * else return 0. */ int -isdn_net_receive_callback(int idx, u_char * buf, int len) -{ - isdn_net_dev *p = dev->rx_netdev[idx]; - struct sk_buff *skb; - - if (p) { - isdn_net_local *lp = &p->local; - if ((lp->flags & ISDN_NET_CONNECTED) && - (!lp->dialstate)) { - skb = dev_alloc_skb(len); - if (skb == NULL) { - printk(KERN_WARNING "out of memory\n"); - return 0; - } - memcpy(skb_put(skb, len), buf, len); - isdn_net_receive(&p->dev, skb); - return 1; - } - } - return 0; -} - -/* - * receive callback for lowlevel drivers, which support skb's - */ - -int -isdn_net_rcv_skb(int idx, struct sk_buff *skb) +isdn_net_rcv_skb(int idx, struct sk_buff *skb) { isdn_net_dev *p = dev->rx_netdev[idx]; @@ -1165,43 +1230,41 @@ static int my_eth_header(struct sk_buff *skb, struct device *dev, unsigned short type, - void *daddr, void *saddr, unsigned len) + void *daddr, void *saddr, unsigned len) { - struct ethhdr *eth = (struct ethhdr *)skb_push(skb,ETH_HLEN); + struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN); - /* + /* * Set the protocol type. For a packet of type ETH_P_802_3 we - * put the length here instead. It is up to the 802.2 layer to - * carry protocol information. + * put the length here instead. It is up to the 802.2 layer to + * carry protocol information. */ - - if(type!=ETH_P_802_3) + + if (type != ETH_P_802_3) eth->h_proto = htons(type); else eth->h_proto = htons(len); /* - * Set the source hardware address. + * Set the source hardware address. */ - if(saddr) - memcpy(eth->h_source,saddr,dev->addr_len); + if (saddr) + memcpy(eth->h_source, saddr, dev->addr_len); else - memcpy(eth->h_source,dev->dev_addr,dev->addr_len); + memcpy(eth->h_source, dev->dev_addr, dev->addr_len); /* - * Anyway, the loopback-device should never use this function... + * Anyway, the loopback-device should never use this function... */ if (dev->flags & IFF_LOOPBACK) { memset(eth->h_dest, 0, dev->addr_len); - return(dev->hard_header_len); + return (dev->hard_header_len); } - - if(daddr) { - memcpy(eth->h_dest,daddr,dev->addr_len); + if (daddr) { + memcpy(eth->h_dest, daddr, dev->addr_len); return dev->hard_header_len; } - return -dev->hard_header_len; } @@ -1209,76 +1272,107 @@ * build an header * depends on encaps that is being used. */ - + static int isdn_net_header(struct sk_buff *skb, struct device *dev, unsigned short type, - void *daddr, void *saddr, unsigned plen) + void *daddr, void *saddr, unsigned plen) { isdn_net_local *lp = dev->priv; ushort len = 0; - + switch (lp->p_encap) { - case ISDN_NET_ENCAP_ETHER: - len = my_eth_header(skb, dev, type, daddr, saddr, plen); - break; - case ISDN_NET_ENCAP_RAWIP: - printk(KERN_WARNING "isdn_net_header called with RAW_IP!\n"); + case ISDN_NET_ENCAP_ETHER: + len = my_eth_header(skb, dev, type, daddr, saddr, plen); + break; + case ISDN_NET_ENCAP_RAWIP: + printk(KERN_WARNING "isdn_net_header called with RAW_IP!\n"); len = 0; - break; - case ISDN_NET_ENCAP_IPTYP: - /* ethernet type field */ - *((ushort*) skb_push(skb, 2)) = htons(type); - len = 2; - break; - case ISDN_NET_ENCAP_UIHDLC: - /* HDLC with UI-Frames (for ispa with -h1 option) */ - *((ushort*) skb_push(skb, 2)) = htons(0x0103); - len = 2; - break; - case ISDN_NET_ENCAP_CISCOHDLC: + break; + case ISDN_NET_ENCAP_IPTYP: + /* ethernet type field */ + *((ushort *) skb_push(skb, 2)) = htons(type); + len = 2; + break; + case ISDN_NET_ENCAP_UIHDLC: + /* HDLC with UI-Frames (for ispa with -h1 option) */ + *((ushort *) skb_push(skb, 2)) = htons(0x0103); + len = 2; + break; + case ISDN_NET_ENCAP_CISCOHDLC: skb_push(skb, 4); - skb->data[0] = 0x0f; - skb->data[1] = 0x00; - *((ushort*)&skb->data[2]) = htons(type); - len = 4; - break; + skb->data[0] = 0x0f; + skb->data[1] = 0x00; + *((ushort *) & skb->data[2]) = htons(type); + len = 4; + break; } return len; } /* We don't need to send arp, because we have point-to-point connections. */ - +#if (LINUX_VERSION_CODE < 0x02010F) static int isdn_net_rebuild_header(void *buff, struct device *dev, unsigned long dst, - struct sk_buff *skb) + struct sk_buff *skb) { isdn_net_local *lp = dev->priv; - int ret = 0; + int ret = 0; + + if (lp->p_encap == ISDN_NET_ENCAP_ETHER) { + struct ethhdr *eth = (struct ethhdr *) buff; + + /* + * Only ARP/IP is currently supported + */ - if (lp->p_encap == ISDN_NET_ENCAP_ETHER) { - struct ethhdr *eth = (struct ethhdr *)buff; - - /* - * Only ARP/IP is currently supported - */ - - if(eth->h_proto != htons(ETH_P_IP)) { - printk(KERN_WARNING - "isdn_net: %s don't know how to resolve type %d addresses?\n", - dev->name, (int)eth->h_proto); - memcpy(eth->h_source, dev->dev_addr, dev->addr_len); - return 0; - } - /* - * Try to get ARP to resolve the header. - */ -#ifdef CONFIG_INET - ret = arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb)? 1 : 0; -#endif - } + if (eth->h_proto != htons(ETH_P_IP)) { + printk(KERN_WARNING + "isdn_net: %s don't know how to resolve type %d addresses?\n", + dev->name, (int) eth->h_proto); + memcpy(eth->h_source, dev->dev_addr, dev->addr_len); + return 0; + } + /* + * Try to get ARP to resolve the header. + */ +#ifdef CONFIG_INET + ret = arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb) ? 1 : 0; +#endif + } return ret; } +#else +static int +isdn_net_rebuild_header(struct sk_buff *skb) +{ + struct device *dev = skb->dev; + isdn_net_local *lp = dev->priv; + int ret = 0; + + if (lp->p_encap == ISDN_NET_ENCAP_ETHER) { + struct ethhdr *eth = (struct ethhdr *) skb->data; + /* + * Only ARP/IP is currently supported + */ + + if (eth->h_proto != htons(ETH_P_IP)) { + printk(KERN_WARNING + "isdn_net: %s don't know how to resolve type %d addresses?\n", + dev->name, (int) eth->h_proto); + memcpy(eth->h_source, dev->dev_addr, dev->addr_len); + return 0; + } + /* + * Try to get ARP to resolve the header. + */ +#ifdef CONFIG_INET + ret = arp_find(eth->h_dest, skb) ? 1 : 0; +#endif + } + return ret; +} +#endif /* * Interface-setup. (called just after registering a new interface) */ @@ -1286,8 +1380,9 @@ isdn_net_init(struct device *ndev) { ushort max_hlhdr_len = 0; - isdn_net_local *lp = (isdn_net_local *)ndev->priv; - int drvidx, i; + isdn_net_local *lp = (isdn_net_local *) ndev->priv; + int drvidx, + i; if (ndev == NULL) { printk(KERN_WARNING "isdn_net_init: dev = NULL!\n"); @@ -1297,54 +1392,61 @@ printk(KERN_WARNING "isdn_net_init: dev->priv = NULL!\n"); return -ENODEV; } - - ether_setup(ndev); - lp->org_hcb = ndev->header_cache_bind; - lp->org_hcu = ndev->header_cache_update; + ether_setup(ndev); +#if (LINUX_VERSION_CODE < 0x02010F) + lp->org_hcb = ndev->header_cache_bind; +#else + lp->org_hhc = ndev->hard_header_cache; +#endif + lp->org_hcu = ndev->header_cache_update; /* Setup the generic properties */ - ndev->hard_header = NULL; - ndev->header_cache_bind = NULL; - ndev->header_cache_update = NULL; - ndev->mtu = 1500; - ndev->flags = IFF_NOARP; - ndev->family = AF_INET; - ndev->type = ARPHRD_ETHER; - ndev->addr_len = ETH_ALEN; - ndev->pa_addr = 0; - ndev->pa_brdaddr = 0; - ndev->pa_mask = 0; - ndev->pa_alen = 4; + ndev->hard_header = NULL; +#if (LINUX_VERSION_CODE < 0x02010F) + ndev->header_cache_bind = NULL; +#else + ndev->hard_header_cache = NULL; +#endif + ndev->header_cache_update = NULL; + ndev->mtu = 1500; + ndev->flags = IFF_NOARP; + ndev->family = AF_INET; + ndev->type = ARPHRD_ETHER; + ndev->addr_len = ETH_ALEN; + ndev->pa_addr = 0; + ndev->pa_brdaddr = 0; + ndev->pa_mask = 0; + ndev->pa_alen = 4; - for (i = 0; i < ETH_ALEN; i++) - ndev->broadcast[i]=0xff; + for (i = 0; i < ETH_ALEN; i++) + ndev->broadcast[i] = 0xff; for (i = 0; i < DEV_NUMBUFFS; i++) - skb_queue_head_init(&ndev->buffs[i]); - + skb_queue_head_init(&ndev->buffs[i]); + /* The ISDN-specific entries in the device structure. */ - ndev->open = &isdn_net_open; - ndev->hard_start_xmit = &isdn_net_start_xmit; + ndev->open = &isdn_net_open; + ndev->hard_start_xmit = &isdn_net_start_xmit; - /* + /* * up till binding we ask the protocol layer to reserve as much * as we might need for HL layer - */ - + */ + for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) if (dev->drv[drvidx]) if (max_hlhdr_len < dev->drv[drvidx]->interface->hl_hdrlen) max_hlhdr_len = dev->drv[drvidx]->interface->hl_hdrlen; - ndev->hard_header_len = ETH_HLEN + max_hlhdr_len; + 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; + 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; + ndev->do_ioctl = isdn_ppp_dev_ioctl; #endif return 0; } @@ -1385,35 +1487,35 @@ 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; + 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'); } @@ -1430,12 +1532,12 @@ while (p) { if (p->local.pre_device == drvidx) switch (p->local.pre_channel) { - case 0: - p->local.pre_channel = 1; - break; - case 1: - p->local.pre_channel = 0; - break; + case 0: + p->local.pre_channel = 1; + break; + case 1: + p->local.pre_channel = 0; + break; } p = (isdn_net_dev *) p->next; } @@ -1472,7 +1574,7 @@ * 4 = Wait cbdelay, then call back */ int -isdn_net_find_icall(int di, int ch, int idx, char *num) +isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) { char *eaz; int si1; @@ -1483,40 +1585,24 @@ isdn_net_dev *p; isdn_net_phone *n; ulong flags; - char nr[31]; - char *s; + char nr[32]; /* Search name in netdev-chain */ save_flags(flags); cli(); - if (num[0] == ',') { + if (!setup.phone[0]) { nr[0] = '0'; - strncpy(&nr[1], num, 30); + nr[1] = '\0'; printk(KERN_INFO "isdn_net: Incoming call without OAD, assuming '0'\n"); } else - strncpy(nr, num, 30); - s = strtok(nr, ","); - s = strtok(NULL, ","); - if (!s) { - printk(KERN_WARNING "isdn_net: Incoming callinfo garbled, ignored: %s\n", - num); - restore_flags(flags); - return 0; - } - si1 = (int)simple_strtoul(s,NULL,10); - s = strtok(NULL, ","); - if (!s) { - printk(KERN_WARNING "isdn_net: Incoming callinfo garbled, ignored: %s\n", - num); - restore_flags(flags); - return 0; - } - si2 = (int)simple_strtoul(s,NULL,10); - eaz = strtok(NULL, ","); - if (!eaz) { + strcpy(nr, setup.phone); + si1 = (int) setup.si1; + si2 = (int) setup.si2; + if (!setup.eazmsn[0]) { printk(KERN_WARNING "isdn_net: Incoming call without CPN, assuming '0'\n"); eaz = "0"; - } + } else + eaz = setup.eazmsn; if (dev->net_verbose > 1) printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz); /* Accept only calls with Si1 = 7 (Data-Transmission) */ @@ -1536,12 +1622,12 @@ while (p) { /* If last check has triggered as binding-swap, revert it */ switch (swapped) { - case 2: - isdn_net_swap_usage(idx, sidx); - /* fall through */ - case 1: - isdn_net_swapbind(di); - break; + case 2: + isdn_net_swap_usage(idx, sidx); + /* fall through */ + case 1: + isdn_net_swapbind(di); + break; } swapped = 0; if (!strcmp(isdn_map_eaz2msn(p->local.msn, di), eaz)) @@ -1550,11 +1636,11 @@ printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n", p->local.name, p->local.msn, p->local.flags, p->local.dialstate); #endif - if ((!strcmp(isdn_map_eaz2msn(p->local.msn, di), eaz)) && /* EAZ is matching */ - (((!(p->local.flags & ISDN_NET_CONNECTED)) && /* but not connected */ - (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */ - ((((p->local.dialstate == 4) || (p->local.dialstate == 12)) && /* if dialing */ - (!(p->local.flags & ISDN_NET_CALLBACK))) /* but no callback */ + if ((!strcmp(isdn_map_eaz2msn(p->local.msn, di), eaz)) && /* EAZ is matching */ + (((!(p->local.flags & ISDN_NET_CONNECTED)) && /* but not connected */ + (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */ + ((((p->local.dialstate == 4) || (p->local.dialstate == 12)) && /* if dialing */ + (!(p->local.flags & ISDN_NET_CALLBACK))) /* but no callback */ ))) { #ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n", @@ -1564,13 +1650,13 @@ if ((p->local.pre_channel != ch) || (p->local.pre_device != di)) { /* Here we got a problem: - If using an ICN-Card, an incoming call is always signaled on - on the first channel of the card, if both channels are - down. However this channel may be bound exclusive. If the - second channel is free, this call should be accepted. - The solution is horribly but it runs, so what: - We exchange the exclusive bindings of the two channels, the - corresponding variables in the interface-structs. + * If using an ICN-Card, an incoming call is always signaled on + * on the first channel of the card, if both channels are + * down. However this channel may be bound exclusive. If the + * second channel is free, this call should be accepted. + * The solution is horribly but it runs, so what: + * We exchange the exclusive bindings of the two channels, the + * corresponding variables in the interface-structs. */ if (ch == 0) { sidx = isdn_dc2minor(di, 1); @@ -1579,13 +1665,13 @@ #endif if (USG_NONE(dev->usage[sidx])) { /* Second Channel is free, now see if it is bound - exclusive too. */ + * exclusive too. */ if (dev->usage[sidx] & ISDN_USAGE_EXCLUSIVE) { #ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: 2nd channel is down and bound\n"); #endif /* Yes, swap bindings only, if the original - binding is bound to channel 1 of this driver */ + * binding is bound to channel 1 of this driver */ if ((p->local.pre_device == di) && (p->local.pre_channel == 1)) { isdn_net_swapbind(di); @@ -1627,7 +1713,7 @@ continue; } } - } /* if (dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) */ + } #ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: match2\n"); #endif @@ -1692,7 +1778,7 @@ return 0; } /* Setup dialstate. */ - lp->dtimer = 0; + lp->dtimer = 0; lp->dialstate = 11; lp->flags |= ISDN_NET_CONNECTED; /* Connect interface with channel */ @@ -1707,7 +1793,7 @@ #endif /* Initiate dialing by returning 2 or 4 */ restore_flags(flags); - return (lp->flags & ISDN_NET_CBHUP)?2:4; + return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4; } else printk(KERN_WARNING "isdn_net: %s: No phone number\n", lp->name); restore_flags(flags); @@ -1717,25 +1803,29 @@ eaz); /* if this interface is dialing, it does it probably on a different device, so free this device */ - if ((p->local.dialstate == 4) || (p->local.dialstate == 12)) + if ((p->local.dialstate == 4) || (p->local.dialstate == 12)) { +#ifdef CONFIG_ISDN_PPP + if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) + isdn_ppp_free(lp); +#endif isdn_free_channel(p->local.isdn_device, p->local.isdn_channel, ISDN_USAGE_NET); + } dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE; dev->usage[idx] |= ISDN_USAGE_NET; strcpy(dev->num[idx], nr); isdn_info_update(); - dev->st_netdev[idx] = lp->netdev; + dev->st_netdev[idx] = lp->netdev; p->local.isdn_device = di; p->local.isdn_channel = ch; p->local.ppp_slot = -1; - p->local.pppbind = -1; p->local.flags |= ISDN_NET_CONNECTED; p->local.dialstate = 7; p->local.dtimer = 0; p->local.outgoing = 0; p->local.huptimer = 0; - p->local.hupflags |= 1; - p->local.hupflags &= ~2; + p->local.hupflags |= ISDN_WAITCHARGE; + p->local.hupflags &= ~ISDN_HAVECHARGE; #ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) if (isdn_ppp_bind(lp) < 0) { @@ -1762,7 +1852,7 @@ * Search list of net-interfaces for an interface with given name. */ isdn_net_dev * - isdn_net_findif(char *name) +isdn_net_findif(char *name) { isdn_net_dev *p = dev->netdev; @@ -1779,7 +1869,8 @@ * This is called from the userlevel-routine below or * from isdn_net_start_xmit(). */ -int isdn_net_force_dial_lp(isdn_net_local * lp) +int +isdn_net_force_dial_lp(isdn_net_local * lp) { if ((!(lp->flags & ISDN_NET_CONNECTED)) && !lp->dialstate) { int chi; @@ -1789,8 +1880,8 @@ cli(); /* Grab a free ISDN-Channel */ if ((chi = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto, - lp->l3_proto, - lp->pre_device, + lp->l3_proto, + lp->pre_device, lp->pre_channel)) < 0) { printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name); restore_flags(flags); @@ -1809,8 +1900,8 @@ } #endif /* Initiate dialing */ - isdn_net_dial(); restore_flags(flags); + isdn_net_dial(); return 0; } else return -EINVAL; @@ -1822,7 +1913,7 @@ * Force a net-interface to dial out. * This is always called from within userspace (ISDN_IOCTL_NET_DIAL). */ -int +int isdn_net_force_dial(char *name) { isdn_net_dev *p = isdn_net_findif(name); @@ -1854,9 +1945,9 @@ strcpy(netdev->local.name, " "); else strcpy(netdev->local.name, name); - netdev->dev.name = netdev->local.name; - netdev->dev.priv = &netdev->local; - netdev->dev.init = isdn_net_init; + netdev->dev.name = netdev->local.name; + netdev->dev.priv = &netdev->local; + netdev->dev.init = isdn_net_init; netdev->local.p_encap = ISDN_NET_ENCAP_RAWIP; if (master) { /* Device shall be a slave */ @@ -1884,7 +1975,7 @@ netdev->local.magic = ISDN_NET_MAGIC; #ifdef CONFIG_ISDN_PPP - netdev->mp_last = NULL; /* mpqueue is empty */ + netdev->mp_last = NULL; /* mpqueue is empty */ netdev->ib.next_num = 0; netdev->ib.last = NULL; #endif @@ -1900,16 +1991,18 @@ netdev->local.exclusive = -1; netdev->local.ppp_slot = -1; netdev->local.pppbind = -1; + netdev->local.sav_skb = NULL; + netdev->local.first_skb = NULL; netdev->local.l2_proto = ISDN_PROTO_L2_X75I; netdev->local.l3_proto = ISDN_PROTO_L3_TRANS; netdev->local.slavedelay = 10 * HZ; netdev->local.srobin = &netdev->dev; - netdev->local.hupflags = 8; /* Do hangup even on incoming calls */ + netdev->local.hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */ netdev->local.onhtime = 10; /* Default hangup-time for saving costs - of those who forget configuring this */ + of those who forget configuring this */ netdev->local.dialmax = 1; - netdev->local.flags = ISDN_NET_CBHUP; /* Hangup before Callback */ - netdev->local.cbdelay = 25; /* Wait 5 secs before Callback */ + netdev->local.flags = ISDN_NET_CBHUP; /* Hangup before Callback */ + netdev->local.cbdelay = 25; /* Wait 5 secs before Callback */ /* Put into to netdev-chain */ netdev->next = (void *) dev->netdev; dev->netdev = netdev; @@ -1935,6 +2028,9 @@ /* Master must be a real interface, not a slave */ if (n->local.master) return NULL; + /* Master must not be started yet */ + if (n->dev.start) + return NULL; return (isdn_net_new(newname, &(n->dev))); } return NULL; @@ -1946,7 +2042,8 @@ * for not overwriting existing setups. It has to get the current * setup first, if only selected parameters are to be changed. */ -int isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) +int +isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) { isdn_net_dev *p = isdn_net_findif(cfg->name); ulong features; @@ -1966,30 +2063,34 @@ printk(KERN_WARNING "isdn_net: No driver with selected features\n"); return -ENODEV; } - if (p->local.p_encap != cfg->p_encap) - if (p->dev.start) { - printk(KERN_WARNING - "%s: cannot change encap when if is up\n", - p->local.name); - return -EBUSY; - } + if (p->local.p_encap != cfg->p_encap) + if (p->dev.start) { + printk(KERN_WARNING + "%s: cannot change encap when if is up\n", + p->local.name); + return -EBUSY; + } + if (cfg->p_encap == ISDN_NET_ENCAP_SYNCPPP) { #ifndef CONFIG_ISDN_PPP - if (cfg->p_encap == ISDN_NET_ENCAP_SYNCPPP) { - printk(KERN_WARNING "%s: SyncPPP not configured\n", - p->local.name); - return -EINVAL; - } + printk(KERN_WARNING "%s: SyncPPP support not configured\n", + p->local.name); + return -EINVAL; +#else + p->dev.type = ARPHRD_PPP; /* change ARP type */ + p->dev.addr_len = 0; #endif + } if (strlen(cfg->drvid)) { /* A bind has been requested ... */ - char *c,*e; + char *c, + *e; drvidx = -1; chidx = -1; strcpy(drvid, cfg->drvid); if ((c = strchr(drvid, ','))) { /* The channel-number is appended to the driver-Id with a comma */ - chidx = (int)simple_strtoul(c + 1,&e,10); + chidx = (int) simple_strtoul(c + 1, &e, 10); if (e == c) chidx = -1; *c = '\0'; @@ -2014,9 +2115,9 @@ /* If binding is exclusive, try to grab the channel */ save_flags(flags); if ((i = isdn_get_free_channel(ISDN_USAGE_NET, p->local.l2_proto, - p->local.l3_proto, - drvidx, - chidx)) < 0) { + p->local.l3_proto, + drvidx, + chidx)) < 0) { /* Grab failed, because desired channel is in use */ p->local.exclusive = -1; restore_flags(flags); @@ -2032,22 +2133,22 @@ p->local.exclusive = -1; if ((p->local.pre_device != -1) && (cfg->exclusive == -1)) { isdn_unexclusive_channel(p->local.pre_device, p->local.pre_channel); - isdn_free_channel(p->local.pre_device, p->local.pre_channel,ISDN_USAGE_NET); + isdn_free_channel(p->local.pre_device, p->local.pre_channel, ISDN_USAGE_NET); drvidx = -1; chidx = -1; } } strcpy(p->local.msn, cfg->eaz); - p->local.pre_device = drvidx; + p->local.pre_device = drvidx; p->local.pre_channel = chidx; - p->local.onhtime = cfg->onhtime; - p->local.charge = cfg->charge; - p->local.l2_proto = cfg->l2_proto; - p->local.l3_proto = cfg->l3_proto; - p->local.cbdelay = cfg->cbdelay; - p->local.dialmax = cfg->dialmax; - p->local.slavedelay = cfg->slavedelay * HZ; - p->local.pppbind = cfg->pppbind; + p->local.onhtime = cfg->onhtime; + p->local.charge = cfg->charge; + p->local.l2_proto = cfg->l2_proto; + p->local.l3_proto = cfg->l3_proto; + p->local.cbdelay = cfg->cbdelay; + p->local.dialmax = cfg->dialmax; + p->local.slavedelay = cfg->slavedelay * HZ; + p->local.pppbind = cfg->pppbind; if (cfg->secure) p->local.flags |= ISDN_NET_SECURE; else @@ -2057,47 +2158,63 @@ else p->local.flags &= ~ISDN_NET_CBHUP; switch (cfg->callback) { - case 0: - p->local.flags &= ~(ISDN_NET_CALLBACK|ISDN_NET_CBOUT); - break; - case 1: - p->local.flags |= ISDN_NET_CALLBACK; - p->local.flags &= ~ISDN_NET_CBOUT; - break; - case 2: - p->local.flags |= ISDN_NET_CBOUT; - p->local.flags &= ~ISDN_NET_CALLBACK; - break; - } + case 0: + p->local.flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT); + break; + case 1: + p->local.flags |= ISDN_NET_CALLBACK; + p->local.flags &= ~ISDN_NET_CBOUT; + break; + case 2: + p->local.flags |= ISDN_NET_CBOUT; + p->local.flags &= ~ISDN_NET_CALLBACK; + break; + } if (cfg->chargehup) - p->local.hupflags |= 4; + p->local.hupflags |= ISDN_CHARGEHUP; else - p->local.hupflags &= ~4; + p->local.hupflags &= ~ISDN_CHARGEHUP; if (cfg->ihup) - p->local.hupflags |= 8; + p->local.hupflags |= ISDN_INHUP; else - p->local.hupflags &= ~8; + p->local.hupflags &= ~ISDN_INHUP; + if (cfg->chargeint > 10) { + p->local.hupflags |= ISDN_CHARGEHUP | ISDN_HAVECHARGE | ISDN_MANCHARGE; + p->local.chargeint = cfg->chargeint * HZ; + } if (cfg->p_encap != p->local.p_encap) { - if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) { - p->dev.hard_header = NULL; - p->dev.header_cache_bind = NULL; - p->dev.header_cache_update = NULL; - p->dev.flags = IFF_NOARP; - } else { - p->dev.hard_header = isdn_net_header; - if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) { - p->dev.header_cache_bind = p->local.org_hcb; - p->dev.header_cache_update = p->local.org_hcu; - p->dev.flags = IFF_BROADCAST | IFF_MULTICAST; - } else { - p->dev.header_cache_bind = NULL; - p->dev.header_cache_update = NULL; - p->dev.flags = IFF_NOARP; - } - } - } - p->local.p_encap = cfg->p_encap; - return 0; + if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) { + p->dev.hard_header = NULL; +#if (LINUX_VERSION_CODE < 0x02010F) + p->dev.header_cache_bind = NULL; +#else + p->dev.hard_header_cache = NULL; +#endif + p->dev.header_cache_update = NULL; + p->dev.flags = IFF_NOARP; + } else { + p->dev.hard_header = isdn_net_header; + if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) { +#if (LINUX_VERSION_CODE < 0x02010F) + p->dev.header_cache_bind = p->local.org_hcb; +#else + p->dev.hard_header_cache = p->local.org_hhc; +#endif + p->dev.header_cache_update = p->local.org_hcu; + p->dev.flags = IFF_BROADCAST | IFF_MULTICAST; + } else { +#if (LINUX_VERSION_CODE < 0x02010F) + p->dev.header_cache_bind = NULL; +#else + p->dev.hard_header_cache = NULL; +#endif + p->dev.header_cache_update = NULL; + p->dev.flags = IFF_NOARP; + } + } + } + p->local.p_encap = cfg->p_encap; + return 0; } return -ENODEV; } @@ -2105,7 +2222,8 @@ /* * Perform get-interface-parameters.ioctl */ -int isdn_net_getcfg(isdn_net_ioctl_cfg * cfg) +int +isdn_net_getcfg(isdn_net_ioctl_cfg * cfg) { isdn_net_dev *p = isdn_net_findif(cfg->name); @@ -2124,16 +2242,18 @@ cfg->p_encap = p->local.p_encap; cfg->secure = (p->local.flags & ISDN_NET_SECURE) ? 1 : 0; cfg->callback = 0; - if (p->local.flags & ISDN_NET_CALLBACK) - cfg->callback = 1; - if (p->local.flags & ISDN_NET_CBOUT) - cfg->callback = 2; + if (p->local.flags & ISDN_NET_CALLBACK) + cfg->callback = 1; + if (p->local.flags & ISDN_NET_CBOUT) + cfg->callback = 2; cfg->cbhup = (p->local.flags & ISDN_NET_CBHUP) ? 1 : 0; cfg->chargehup = (p->local.hupflags & 4) ? 1 : 0; cfg->ihup = (p->local.hupflags & 8) ? 1 : 0; - cfg->cbdelay = p->local.cbdelay; - cfg->dialmax = p->local.dialmax; + cfg->cbdelay = p->local.cbdelay; + cfg->dialmax = p->local.dialmax; cfg->slavedelay = p->local.slavedelay / HZ; + cfg->chargeint = (p->local.hupflags & ISDN_CHARGEHUP) ? + (p->local.chargeint / HZ) : 0; cfg->pppbind = p->local.pppbind; if (p->local.slave) strcpy(cfg->slave, ((isdn_net_local *) p->local.slave->priv)->name); @@ -2151,7 +2271,8 @@ /* * Add a phone-number to an interface. */ -int isdn_net_addphone(isdn_net_ioctl_phone * phone) +int +isdn_net_addphone(isdn_net_ioctl_phone * phone) { isdn_net_dev *p = isdn_net_findif(phone->name); isdn_net_phone *n; @@ -2172,7 +2293,8 @@ /* * Return a string of all phone-numbers of an interface. */ -int isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones) +int +isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones) { isdn_net_dev *p = isdn_net_findif(phone->name); int inout = phone->outgoing & 1; @@ -2180,38 +2302,39 @@ int count = 0; isdn_net_phone *n; int flags; - int ret = 0; + int ret; if (!p) return -ENODEV; save_flags(flags); cli(); inout &= 1; - for (n = p->local.phone[inout]; n; n = n->next) { + for (n = p->local.phone[inout]; n; n = n->next) { if (more) { - ret = put_user(((char)' '), phones); - phones++; + put_user(' ', phones++); count++; } - if (ret || copy_to_user(phones, n->num, strlen(n->num) + 1)) { + if ((ret = verify_area(VERIFY_WRITE, (void *) phones, strlen(n->num) + 1))) { restore_flags(flags); - return -EFAULT; + return ret; } + copy_to_user(phones, n->num, strlen(n->num) + 1); phones += strlen(n->num); count += strlen(n->num); more = 1; } - ret = put_user(((char)0),phones); - count++; + put_user(0, phones); + count++; restore_flags(flags); - return ret ? -EFAULT : count; + return count; } /* * Delete a phone-number from an interface. */ -int isdn_net_delphone(isdn_net_ioctl_phone * phone) +int +isdn_net_delphone(isdn_net_ioctl_phone * phone) { isdn_net_dev *p = isdn_net_findif(phone->name); int inout = phone->outgoing & 1; @@ -2241,7 +2364,8 @@ /* * Delete all phone-numbers of an interface. */ -static int isdn_net_rmallphone(isdn_net_dev * p) +static int +isdn_net_rmallphone(isdn_net_dev * p) { isdn_net_phone *n; isdn_net_phone *m; @@ -2266,19 +2390,15 @@ /* * Force a hangup of a network-interface. */ -int isdn_net_force_hangup(char *name) +int +isdn_net_force_hangup(char *name) { isdn_net_dev *p = isdn_net_findif(name); - int flags; struct device *q; if (p) { - save_flags(flags); - cli(); - if (p->local.isdn_device < 0) { - restore_flags(flags); + if (p->local.isdn_device < 0) return 1; - } isdn_net_hangup(&p->dev); q = p->local.slave; /* If this interface has slaves, do a hangup for them also. */ @@ -2286,7 +2406,6 @@ isdn_net_hangup(q); q = (((isdn_net_local *) q->priv)->slave); } - restore_flags(flags); return 0; } return -ENODEV; @@ -2295,7 +2414,8 @@ /* * Helper-function for isdn_net_rm: Do the real work. */ -static int isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q) +static int +isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q) { int flags; @@ -2348,9 +2468,6 @@ isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0); restore_flags(flags); -#ifdef CONFIG_ISDN_PPP - isdn_ppp_free_mpqueue(p); /* still necessary? */ -#endif kfree(p); return 0; @@ -2359,7 +2476,8 @@ /* * Remove a single network-interface. */ -int isdn_net_rm(char *name) +int +isdn_net_rm(char *name) { isdn_net_dev *p; isdn_net_dev *q; @@ -2382,7 +2500,8 @@ /* * Remove all network-interfaces */ -int isdn_net_rmall(void) +int +isdn_net_rmall(void) { int flags; int ret; @@ -2395,7 +2514,7 @@ /* Remove master-devices only, slaves get removed with their master */ if ((ret = isdn_net_realrm(dev->netdev, NULL))) { restore_flags(flags); - return ret; + return ret; } } } @@ -2404,28 +2523,18 @@ return 0; } -/* +/* * helper function to flush device queues * the better place would be net/core/dev.c */ -void dev_purge_queues(struct device *dev) +static void +dev_purge_queues(struct device *dev) { int i; - for(i=0;ibuffs[i]))) - dev_kfree_skb(skb,FREE_WRITE); - } - -} - - - - - - - - - - + while ((skb = skb_dequeue(&dev->buffs[i]))) + dev_kfree_skb(skb, FREE_WRITE); + } +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/isdn_net.h linux/drivers/isdn/isdn_net.h --- v2.1.26/linux/drivers/isdn/isdn_net.h Sun Apr 21 01:56:14 1996 +++ linux/drivers/isdn/isdn_net.h Tue Feb 25 17:12:50 1997 @@ -1,11 +1,11 @@ -/* $Id: isdn_net.h,v 1.2 1996/04/20 16:29:43 fritz Exp $ - * +/* $Id: isdn_net.h,v 1.5 1997/02/10 20:12:47 fritz Exp $ + * header for Linux ISDN subsystem, network related functions (linklevel). * * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.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 * the Free Software Foundation; either version 2, or (at your option) @@ -18,9 +18,18 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.h,v $ + * Revision 1.5 1997/02/10 20:12:47 fritz + * Changed interface for reporting incoming calls. + * + * Revision 1.4 1997/02/03 23:16:48 fritz + * Removed isdn_net_receive_callback prototype. + * + * Revision 1.3 1997/01/17 01:19:30 fritz + * Applied chargeint patch. + * * Revision 1.2 1996/04/20 16:29:43 fritz * Misc. typos * @@ -29,24 +38,30 @@ * */ -extern char* isdn_net_new(char *, struct device *); -extern char* isdn_net_newslave(char *); -extern int isdn_net_rm(char *); -extern int isdn_net_rmall(void); -extern int isdn_net_stat_callback(int, int); -extern int isdn_net_receive_callback(int, u_char *, int); -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_delphone(isdn_net_ioctl_phone *); -extern int isdn_net_find_icall(int, int, int, char *); -extern void isdn_net_hangup(struct device *); -extern void isdn_net_dial(void); -extern void isdn_net_autohup(void); -extern int isdn_net_force_hangup(char *); -extern int isdn_net_force_dial(char *); -extern isdn_net_dev* isdn_net_findif(char *); -extern int isdn_net_send_skb(struct device *, isdn_net_local *, - struct sk_buff *); -extern int isdn_net_rcv_skb(int, struct sk_buff *); + /* Definitions for hupflags: */ +#define ISDN_WAITCHARGE 1 /* did not get a charge info yet */ +#define ISDN_HAVECHARGE 2 /* We know a charge info */ +#define ISDN_CHARGEHUP 4 /* We want to use the charge mechanism */ +#define ISDN_INHUP 8 /* Even if incoming, close after huptimeout */ +#define ISDN_MANCHARGE 16 /* Charge Interval manually set */ + +extern char *isdn_net_new(char *, struct device *); +extern char *isdn_net_newslave(char *); +extern int isdn_net_rm(char *); +extern int isdn_net_rmall(void); +extern int isdn_net_stat_callback(int, int); +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_delphone(isdn_net_ioctl_phone *); +extern int isdn_net_find_icall(int, int, int, setup_parm); +extern void isdn_net_hangup(struct device *); +extern void isdn_net_dial(void); +extern void isdn_net_autohup(void); +extern int isdn_net_force_hangup(char *); +extern int isdn_net_force_dial(char *); +extern isdn_net_dev *isdn_net_findif(char *); +extern int isdn_net_send_skb(struct device *, isdn_net_local *, + struct sk_buff *); +extern int isdn_net_rcv_skb(int, struct sk_buff *); diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c --- v2.1.26/linux/drivers/isdn/isdn_ppp.c Wed Oct 30 04:26:48 1996 +++ linux/drivers/isdn/isdn_ppp.c Tue Feb 25 17:12:50 1997 @@ -1,9 +1,9 @@ -/* $Id: isdn_ppp.c,v 1.14 1996/08/12 16:26:47 hipp Exp $ +/* $Id: isdn_ppp.c,v 1.25 1997/02/12 20:37:35 hipp Exp $ * * Linux ISDN subsystem, functions for synchronous PPP (linklevel). * * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.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 * the Free Software Foundation; either version 2, or (at your option) @@ -16,9 +16,45 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ppp.c,v $ + * Revision 1.25 1997/02/12 20:37:35 hipp + * New ioctl() PPPIOCGCALLINFO, minor cleanup + * + * Revision 1.24 1997/02/11 18:32:56 fritz + * Bugfix in isdn_ppp_free_mpqueue(). + * + * Revision 1.23 1997/02/10 11:12:19 fritz + * More changes for Kernel 2.1.X compatibility. + * + * Revision 1.22 1997/02/06 15:03:51 hipp + * changed GFP_KERNEL kmalloc to GFP_ATOMIC in isdn_ppp_fill_mpqueue() + * + * Revision 1.21 1997/02/03 23:29:38 fritz + * Reformatted according CodingStyle + * Bugfix: removed isdn_ppp_skb_destructor, used by upper layers. + * Misc changes for Kernel 2.1.X compatibility. + * + * Revision 1.20 1996/10/30 12:21:58 fritz + * Cosmetic fix: Compiler warning when compiling without MPP. + * + * Revision 1.19 1996/10/25 19:03:21 hipp + * changed/added some defines to (re)allow compilation without MP/VJ + * + * Revision 1.18 1996/10/22 23:14:00 fritz + * Changes for compatibility to 2.0.X and 2.1.X kernels. + * + * Revision 1.17 1996/10/22 09:39:49 hipp + * a few MP changes and bugfixes + * + * Revision 1.16 1996/09/23 01:58:10 fritz + * Fix: With syncPPP encapsulation, discard LCP packets + * when calculating hangup timeout. + * + * Revision 1.15 1996/09/07 12:50:12 hipp + * bugfixes (unknown device after failed dial attempt, minor bugs) + * * Revision 1.14 1996/08/12 16:26:47 hipp * code cleanup * changed connection management from minors to slots @@ -73,46 +109,84 @@ /* TODO: right tbusy handling when using MP */ -#include +/* + * experimental for dynamic addressing: readdress IP frames + */ +#undef ISDN_SYNCPPP_READDRESS + #include #define __NO_VERSION__ #include +#include #include +#if (LINUX_VERSION_CODE >= 0x020117) +#include +#endif #include "isdn_common.h" #include "isdn_ppp.h" #include "isdn_net.h" #ifndef PPP_IPX -#define PPP_IPX 0x002b +#define PPP_IPX 0x002b #endif - + +/* set this if you use dynamic addressing */ + /* Prototypes */ -static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int slot); +static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot); 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); + struct sk_buff *skb, int proto); static int isdn_ppp_if_get_unit(char *namebuf); #ifdef CONFIG_ISDN_MPP static int isdn_ppp_bundle(struct ippp_struct *, int unit); static void isdn_ppp_mask_queue(isdn_net_dev * dev, long mask); -static void isdn_ppp_cleanup_queue(isdn_net_dev * dev, long min); +static void isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min); +static void isdn_ppp_cleanup_sqqueue(isdn_net_dev * dev, isdn_net_local *, long min); +static void isdn_ppp_free_sqqueue(isdn_net_dev *); static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb, - int BEbyte, int *sqno, int min_sqno); + int BEbyte, long *sqno, int min_sqno); +static void isdn_ppp_free_mpqueue(isdn_net_dev *); #endif -char *isdn_ppp_revision = "$Revision: 1.14 $"; -struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; +char *isdn_ppp_revision = "$Revision: 1.25 $"; + +static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; extern int isdn_net_force_dial_lp(isdn_net_local *); /* - * unbind isdn_net_local <=> ippp-device + * frame log (debug) + */ +static void +isdn_ppp_frame_log(char *info, char *data, int len, int maxlen) +{ + int cnt, + j, + i; + char buf[80]; + + if (len < maxlen) + maxlen = len; + + 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); + } +} + +/* + * unbind isdn_net_local <=> ippp-device * note: it can happen, that we hangup/free the master before the slaves */ -int isdn_ppp_free(isdn_net_local *lp) +int +isdn_ppp_free(isdn_net_local * lp) { - isdn_net_local *master_lp=lp; +#ifdef CONFIG_ISDN_MPP + isdn_net_local *master_lp = lp; +#endif unsigned long flags; struct ippp_struct *is; @@ -124,15 +198,15 @@ save_flags(flags); cli(); #ifdef CONFIG_ISDN_MPP - if(lp->master) + if (lp->master) master_lp = (isdn_net_local *) lp->master->priv; lp->last->next = lp->next; lp->next->last = lp->last; - if(master_lp->netdev->queue == lp) { + if (master_lp->netdev->queue == lp) { master_lp->netdev->queue = lp->next; - if(lp->next == lp) { /* last link in queue? */ - master_lp->netdev->ib.bundled = 0; + if (lp->next == lp) { /* last link in queue? */ + master_lp->netdev->ib.bundled = 0; isdn_ppp_free_mpqueue(master_lp->netdev); isdn_ppp_free_sqqueue(master_lp->netdev); } @@ -140,13 +214,21 @@ lp->next = lp->last = lp; /* (re)set own pointers */ #endif - isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */ + 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 */ + - if(is->debug & 0x1) - printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp,(long) is->lp); + if (is->debug & 0x1) + printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp); - is->lp = NULL; /* link is down .. set lp to NULL */ - lp->ppp_slot = -1; /* is this OK ?? */ + is->lp = NULL; /* link is down .. set lp to NULL */ +#ifdef ISDN_SYNCPPP_READDRESS + is->old_pa_addr = 0x0; + is->old_pa_dstaddr = 0x0; +#endif + lp->ppp_slot = -1; /* is this OK ?? */ restore_flags(flags); return 0; @@ -155,7 +237,8 @@ /* * bind isdn_net_local <=> ippp-device */ -int isdn_ppp_bind(isdn_net_local * lp) +int +isdn_ppp_bind(isdn_net_local * lp) { int i; int unit = 0; @@ -168,14 +251,13 @@ save_flags(flags); cli(); - if(lp->pppbind < 0) /* device bounded to ippp device ? */ - { - isdn_net_dev *net_dev = dev->netdev; + if (lp->pppbind < 0) { /* device bounded to ippp device ? */ + isdn_net_dev *net_dev = dev->netdev; char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */ - memset(exclusive,0,ISDN_MAX_CHANNELS); + memset(exclusive, 0, ISDN_MAX_CHANNELS); while (net_dev) { /* step through net devices to find exclusive minors */ isdn_net_local *lp = &net_dev->local; - if(lp->pppbind >= 0) + if (lp->pppbind >= 0) exclusive[lp->pppbind] = 1; net_dev = net_dev->next; } @@ -183,14 +265,13 @@ * search a free device / slot */ for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) { /* OPEN, but not connected! */ + if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) { /* OPEN, but not connected! */ break; } } - } - else { - for(i=0;iminor == lp->pppbind && ippp_table[i]->state == IPPP_OPEN) + } else { + for (i = 0; i < ISDN_MAX_CHANNELS; i++) + if (ippp_table[i]->minor == lp->pppbind && ippp_table[i]->state == IPPP_OPEN) break; } @@ -199,18 +280,16 @@ printk(KERN_WARNING "isdn_ppp_bind: Can't find usable ippp device.\n"); return -1; } - - unit = isdn_ppp_if_get_unit(lp->name); /* get unit number from interface name .. ugly! */ - if(unit < 0) { - printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n",lp->name); + unit = isdn_ppp_if_get_unit(lp->name); /* get unit number from interface name .. ugly! */ + if (unit < 0) { + printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", lp->name); return -1; } - lp->ppp_slot = i; is = ippp_table[i]; is->lp = lp; is->unit = unit; - is->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; + is->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */ restore_flags(flags); @@ -222,18 +301,25 @@ * (wakes up daemon after B-channel connect) */ -void isdn_ppp_wakeup_daemon(isdn_net_local *lp) +void +isdn_ppp_wakeup_daemon(isdn_net_local * lp) { + if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) + return; + + ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; + if (ippp_table[lp->ppp_slot]->wq) wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq); } /* * there was a hangup on the netdevice - * force wakeup of the ippp device + * force wakeup of the ippp device * go into 'device waits for release' state */ -static int isdn_ppp_closewait(int slot) +static int +isdn_ppp_closewait(int slot) { struct ippp_struct *is; @@ -252,53 +338,58 @@ * isdn_ppp_find_slot / isdn_ppp_free_slot */ -static int isdn_ppp_get_slot(void) +static int +isdn_ppp_get_slot(void) { int i; - for(i=0;istate) + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + if (!ippp_table[i]->state) return i; } return -1; } /* - * isdn_ppp_open + * isdn_ppp_open */ -int isdn_ppp_open(int min, struct file *file) +int +isdn_ppp_open(int min, struct file *file) { int slot; struct ippp_struct *is; + if (min < 0 || min > ISDN_MAX_CHANNELS) + return -ENODEV; + slot = isdn_ppp_get_slot(); - if(slot < 0) { + if (slot < 0) { return -EBUSY; } is = file->private_data = ippp_table[slot]; - if(is->debug & 0x1) - printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n",slot, min,is->state); + if (is->debug & 0x1) + printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, min, is->state); - is->lp = 0; - is->mp_seqno = 0; /* MP sequence number */ - is->pppcfg = 0; /* ppp configuration */ - is->mpppcfg = 0; /* mppp configuration */ - is->range = 0x1000000; /* MP: 24 bit range */ + is->lp = NULL; + is->mp_seqno = 0; /* MP sequence number */ + is->pppcfg = 0; /* ppp configuration */ + is->mpppcfg = 0; /* mppp configuration */ + is->range = 0x1000000; /* MP: 24 bit range */ is->last_link_seqno = -1; /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */ - is->unit = -1; /* set, when we have our interface */ - is->mru = 1524; /* MRU, default 1524 */ - is->maxcid = 16; /* VJ: maxcid */ + is->unit = -1; /* set, when we have our interface */ + is->mru = 1524; /* MRU, default 1524 */ + is->maxcid = 16; /* VJ: maxcid */ is->tk = current; - is->wq = NULL; /* read() wait queue */ - is->wq1 = NULL; /* select() wait queue */ - is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */ + is->wq = NULL; /* read() wait queue */ + is->wq1 = NULL; /* select() wait queue */ + is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */ is->last = is->rq; is->minor = min; #ifdef CONFIG_ISDN_PPP_VJ - /* - * VJ header compression init - */ + /* + * VJ header compression init + */ is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */ #endif @@ -310,7 +401,8 @@ /* * release ippp device */ -void isdn_ppp_release(int min, struct file *file) +void +isdn_ppp_release(int min, struct file *file) { int i; struct ippp_struct *is; @@ -319,15 +411,19 @@ return; is = file->private_data; - if(is->debug & 0x1) + if (is->debug & 0x1) printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp); - if (is->lp) { /* a lp address says: this link is still up */ - isdn_net_dev *p = dev->netdev; - p = is->lp->netdev; - is->lp->ppp_slot = -1; - isdn_net_hangup(&p->dev); /* lp->ppp_slot==-1 => no calling of isdn_ppp_closewait() */ - is->lp = NULL; + if (is->lp) { /* a lp address says: this link is still up */ + isdn_net_dev *p = is->lp->netdev; + + is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */ + /* + * isdn_net_hangup() calls isdn_ppp_free() + * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1 + * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon() + */ + isdn_net_hangup(&p->dev); } for (i = 0; i < NUM_RCV_BUFFS; i++) { if (is->rq[i].buf) { @@ -335,8 +431,8 @@ is->rq[i].buf = NULL; } } - is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */ - is->last = is->rq; + is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */ + is->last = is->rq; #ifdef CONFIG_ISDN_PPP_VJ slhc_free(is->slcomp); @@ -346,190 +442,286 @@ is->state = 0; } -#if 0 /* get_user() / put_user() in 2.1 replace them 1:1 */ /* * get_arg .. ioctl helper */ -static int get_arg(void *b, unsigned long *val) +static int +get_arg(void *b, void *val, int len) { int r; - if (copy_from_user((void *) val, b, sizeof(unsigned long))) - return -EFAULT; + if (len <= 0) + len = sizeof(unsigned long); + if ((r = verify_area(VERIFY_READ, (void *) b, len))) + return r; + copy_from_user((void *) val, b, len); return 0; } /* * set arg .. ioctl helper */ -static int set_arg(void *b, unsigned long val) +static int +set_arg(void *b, unsigned long val, void *str) { int r; - if ((r = verify_area(VERIFY_WRITE, b, sizeof(unsigned long)))) - return r; - copy_to_user(b, (void *) &val, sizeof(unsigned long)); + if (!str) { + if ((r = verify_area(VERIFY_WRITE, b, 4))) + return r; + copy_to_user(b, (void *) &val, 4); + } else { + if ((r = verify_area(VERIFY_WRITE, b, val))) + return r; + copy_to_user(b, str, val); + } return 0; } -#endif /* - * ippp device ioctl + * ippp device ioctl */ -int isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) +int +isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) { unsigned long val; int r; struct ippp_struct *is; - unsigned long *argp = (unsigned long*)arg; + isdn_net_local *lp; - is = file->private_data; + is = (struct ippp_struct *) file->private_data; + lp = is->lp; - if(is->debug & 0x1) - printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n",min,cmd,is->state); + if (is->debug & 0x1) + printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state); if (!(is->state & IPPP_OPEN)) return -EINVAL; switch (cmd) { - case PPPIOCBUNDLE: + case PPPIOCBUNDLE: #ifdef CONFIG_ISDN_MPP - if ((r = get_user(val, argp))) - return r; - printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n", - (int) min, (int) is->unit, (int) val); - return isdn_ppp_bundle(is, val); + if (!(is->state & IPPP_CONNECT)) + return -EINVAL; + if ((r = get_arg((void *) arg, &val, 0))) + return r; + printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n", + (int) min, (int) is->unit, (int) val); + return isdn_ppp_bundle(is, val); #else - return -1; + return -1; #endif - break; - case PPPIOCGUNIT: /* get ppp/isdn unit number */ - if ((r = put_user(is->unit, argp))) - return r; - break; - case PPPIOCGMPFLAGS: /* get configuration flags */ - if ((r = put_user(is->mpppcfg, argp))) - return r; - break; - case PPPIOCSMPFLAGS: /* set configuration flags */ - if ((r = get_user(val, argp))) - return r; - is->mpppcfg = val; - break; - case PPPIOCGFLAGS: /* get configuration flags */ - if ((r = put_user(is->pppcfg ,argp))) - return r; - break; - case PPPIOCSFLAGS: /* set configuration flags */ - if ((r = get_user(val, argp))) { - return r; - } - if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP)) { - isdn_net_local *lp = is->lp; - lp->netdev->dev.tbusy = 0; - mark_bh(NET_BH); /* OK .. we are ready to send buffers */ - } - is->pppcfg = val; - break; + break; + case PPPIOCGUNIT: /* get ppp/isdn unit number */ + if ((r = set_arg((void *) arg, is->unit, NULL))) + return r; + break; + case PPPIOCGMPFLAGS: /* get configuration flags */ + if ((r = set_arg((void *) arg, is->mpppcfg, NULL))) + return r; + break; + case PPPIOCSMPFLAGS: /* set configuration flags */ + if ((r = get_arg((void *) arg, &val, 0))) + return r; + is->mpppcfg = val; + break; + case PPPIOCGFLAGS: /* get configuration flags */ + if ((r = set_arg((void *) arg, is->pppcfg, NULL))) + return r; + break; + case PPPIOCSFLAGS: /* set configuration flags */ + if ((r = get_arg((void *) arg, &val, 0))) { + return r; + } + if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) { + if (lp) { + lp->netdev->dev.tbusy = 0; + mark_bh(NET_BH); /* OK .. we are ready to send buffers */ + } + } + is->pppcfg = val; + break; #if 0 - case PPPIOCGSTAT: /* read PPP statistic information */ - break; - case PPPIOCGTIME: /* read time delta information */ - break; + case PPPIOCGSTAT: /* read PPP statistic information */ + break; #endif - case PPPIOCSMRU: /* set receive unit size for PPP */ - if ((r = get_user(val, argp))) - return r; - is->mru = val; - break; - case PPPIOCSMPMRU: - break; - case PPPIOCSMPMTU: - break; - case PPPIOCSMAXCID: /* set the maximum compression slot id */ - if ((r = get_user(val, argp))) - return r; - val++; - if(is->maxcid != val) { + case PPPIOCGIDLE: /* get idle time information */ + 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))) + return r; + } + break; + case PPPIOCSMRU: /* set receive unit size for PPP */ + if ((r = get_arg((void *) arg, &val, 0))) + return r; + is->mru = val; + break; + case PPPIOCSMPMRU: + break; + case PPPIOCSMPMTU: + break; + case PPPIOCSMAXCID: /* set the maximum compression slot id */ + if ((r = get_arg((void *) arg, &val, 0))) + return r; + val++; + if (is->maxcid != val) { #ifdef CONFIG_ISDN_PPP_VJ - struct slcompress *sltmp; + struct slcompress *sltmp; #endif - if(is->debug & 0x1) - printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n",val); - is->maxcid = val; + if (is->debug & 0x1) + printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val); + is->maxcid = val; #ifdef CONFIG_ISDN_PPP_VJ - sltmp = slhc_init(16,val); - if(!sltmp) { - printk(KERN_ERR "ippp, can't realloc slhc struct\n"); - return -ENOMEM; - } - if(is->slcomp) - slhc_free(is->slcomp); - is->slcomp = sltmp; + sltmp = slhc_init(16, val); + if (!sltmp) { + printk(KERN_ERR "ippp, can't realloc slhc struct\n"); + return -ENOMEM; + } + if (is->slcomp) + slhc_free(is->slcomp); + is->slcomp = sltmp; #endif - } - break; - case PPPIOCGDEBUG: - if ((r = put_user(is->debug, argp))) - return r; - break; - case PPPIOCSDEBUG: - if ((r = get_user(val, argp))) - return r; - is->debug = val; - break; - default: - break; + } + break; + case PPPIOCGDEBUG: + if ((r = set_arg((void *) arg, is->debug, 0))) + return r; + break; + case PPPIOCSDEBUG: + if ((r = get_arg((void *) arg, &val, 0))) + return r; + is->debug = val; + break; + case PPPIOCSCOMPRESS: +#if 0 + { + struct ppp_option_data pod; + r = get_arg((void *) arg, &pod, sizeof(struct ppp_option_data)); + if (r) + return r; + ippp_set_compression(is, &pod); + } +#endif + break; + case PPPIOCGCALLINFO: + { + struct pppcallinfo pci; + memset((char *) &pci,0,sizeof(struct pppcallinfo)); + if(lp) + { + strncpy(pci.local_num,lp->msn,63); + if(lp->dial) { + strncpy(pci.remote_num,lp->dial->num,63); + } + pci.charge_units = lp->charge; + if(lp->outgoing) + pci.calltype = CALLTYPE_OUTGOING; + else + pci.calltype = CALLTYPE_INCOMING; + if(lp->flags & ISDN_NET_CALLBACK) + pci.calltype |= CALLTYPE_CALLBACK; + } + return set_arg((void *)arg,sizeof(struct pppcallinfo),&pci); + } + default: + break; } return 0; } -int isdn_ppp_select(int min, struct file *file, int type, select_table * st) +#if (LINUX_VERSION_CODE < 0x020117) +int +isdn_ppp_select(int min, struct file *file, int type, select_table * st) { - struct ippp_buf_queue *bf, *bl; + struct ippp_buf_queue *bf, + *bl; unsigned long flags; struct ippp_struct *is; is = file->private_data; - if(is->debug & 0x2) - printk(KERN_DEBUG "isdn_ppp_select: minor: %d, type: %d \n",min,type); + if (is->debug & 0x2) + printk(KERN_DEBUG "isdn_ppp_select: minor: %d, type: %d \n", min, type); if (!(is->state & IPPP_OPEN)) return -EINVAL; switch (type) { - case SEL_IN: - save_flags(flags); - cli(); - bl = is->last; - bf = is->first; - /* - * if IPPP_NOBLOCK is set we return even if we have nothing to read - */ - if (bf->next == bl && !(is->state & IPPP_NOBLOCK)) { - select_wait(&is->wq, st); + case SEL_IN: + save_flags(flags); + cli(); + bl = is->last; + bf = is->first; + /* + * if IPPP_NOBLOCK is set we return even if we have nothing to read + */ + if (bf->next == bl && !(is->state & IPPP_NOBLOCK)) { + select_wait(&is->wq, st); + restore_flags(flags); + return 0; + } + is->state &= ~IPPP_NOBLOCK; restore_flags(flags); + return 1; + case SEL_OUT: + /* we're always ready to send .. */ + return 1; + case SEL_EX: + select_wait(&is->wq1, st); return 0; - } - is->state &= ~IPPP_NOBLOCK; - restore_flags(flags); - return 1; - case SEL_OUT: - /* we're always ready to send .. */ - return 1; - case SEL_EX: - select_wait(&is->wq1, st); - return 0; } return 1; } +#else +unsigned int +isdn_ppp_poll(struct file *file, poll_table * wait) +{ + unsigned int mask; + struct ippp_buf_queue *bf; + struct ippp_buf_queue *bl; + unsigned long flags; + struct ippp_struct *is; + + is = file->private_data; + + if (is->debug & 0x2) + printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n", MINOR(file->f_inode->i_rdev)); + + poll_wait(&is->wq, wait); + + if (!(is->state & IPPP_OPEN)) { + printk(KERN_DEBUG "isdn_ppp: device not open\n"); + return POLLERR; + } + /* we're always ready to send .. */ + mask = POLLOUT | POLLWRNORM; + + save_flags(flags); + cli(); + bl = is->last; + bf = is->first; + /* + * if IPPP_NOBLOCK is set we return even if we have nothing to read + */ + if (bf->next != bl || (is->state & IPPP_NOBLOCK)) { + is->state &= ~IPPP_NOBLOCK; + mask |= POLLIN | POLLRDNORM; + } + restore_flags(flags); + return mask; +} +#endif + /* * fill up isdn_ppp_read() queue .. */ -static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int slot) +static int +isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot) { - struct ippp_buf_queue *bf, *bl; + struct ippp_buf_queue *bf, + *bl; unsigned long flags; unsigned char *nbuf; struct ippp_struct *is; @@ -544,9 +736,8 @@ printk(KERN_DEBUG "ippp: device not activated.\n"); return 0; } - - nbuf = (unsigned char *) kmalloc(len+4, GFP_ATOMIC); - if(!nbuf) { + nbuf = (unsigned char *) kmalloc(len + 4, GFP_ATOMIC); + if (!nbuf) { printk(KERN_WARNING "ippp: Can't alloc buf\n"); return 0; } @@ -554,7 +745,7 @@ nbuf[1] = PPP_UI; nbuf[2] = proto >> 8; nbuf[3] = proto & 0xff; - memcpy(nbuf+4, buf, len); + memcpy(nbuf + 4, buf, len); save_flags(flags); cli(); @@ -569,7 +760,7 @@ is->first = bf; } bl->buf = (char *) nbuf; - bl->len = len+4; + bl->len = len + 4; is->last = bl->next; restore_flags(flags); @@ -585,10 +776,12 @@ * reports, that there is data */ -int isdn_ppp_read(int min, struct file *file, char *buf, int count) +int +isdn_ppp_read(int min, struct file *file, char *buf, int count) { struct ippp_struct *is; struct ippp_buf_queue *b; + int r; unsigned long flags; is = file->private_data; @@ -596,6 +789,9 @@ if (!(is->state & IPPP_OPEN)) return 0; + if ((r = verify_area(VERIFY_WRITE, (void *) buf, count))) + return r; + save_flags(flags); cli(); @@ -606,8 +802,7 @@ } if (b->len < count) count = b->len; - if (copy_to_user(buf, b->buf, count)) - count = -EFAULT; /* ugly */ + copy_to_user(buf, b->buf, count); kfree(b->buf); b->buf = NULL; is->first = b; @@ -619,11 +814,14 @@ /* * ipppd wanna write a packet to the card .. non-blocking */ - -int isdn_ppp_write(int min, struct file *file, const char *buf, int count) + +int +isdn_ppp_write(int min, struct file *file, const char *buf, int count) { isdn_net_local *lp; struct ippp_struct *is; + int proto; + unsigned char protobuf[4]; is = file->private_data; @@ -637,49 +835,64 @@ if (!lp) printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n"); else { - lp->huptimer = 0; + /* + * Don't reset huptimer for + * LCP packets. (Echo requests). + */ + copy_from_user(protobuf, buf, 4); + proto = PPP_PROTOCOL(protobuf); + if (proto != PPP_LCP) + lp->huptimer = 0; + if (lp->isdn_device < 0 || lp->isdn_channel < 0) return 0; if (dev->drv[lp->isdn_device]->running && lp->dialstate == 0 && (lp->flags & ISDN_NET_CONNECTED)) { + int cnt; struct sk_buff *skb; skb = dev_alloc_skb(count); - if(!skb) { + if (!skb) { printk(KERN_WARNING "isdn_ppp_write: out of memory!\n"); return count; } - skb->free = 1; + SET_SKB_FREE(skb); copy_from_user(skb_put(skb, count), buf, count); - if(isdn_writebuf_skb_stub(lp->isdn_device,lp->isdn_channel,skb) != count) { - if(lp->sav_skb) { - dev_kfree_skb(lp->sav_skb,FREE_WRITE); - printk(KERN_INFO "isdn_ppp_write: freeing sav_skb!\n"); - } + 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); + } + if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb)) != count) { + if (lp->sav_skb) { + dev_kfree_skb(lp->sav_skb, FREE_WRITE); + 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; } } } - return count; } /* - * init memory, structures etc. + * init memory, structures etc. */ -int isdn_ppp_init(void) +int +isdn_ppp_init(void) { - int i, j; + int i, + j; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (!(ippp_table[i] = (struct ippp_struct *) - kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) { - printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n"); + if (!(ippp_table[i] = (struct ippp_struct *) + kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) { + printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n"); for (j = 0; j < i; j++) kfree(ippp_table[i]); - return -1; - } + return -1; + } memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct)); ippp_table[i]->state = 0; ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1; @@ -695,70 +908,72 @@ return 0; } -void isdn_ppp_cleanup(void) +void +isdn_ppp_cleanup(void) { - int i; + int i; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - kfree(ippp_table[i]); + for (i = 0; i < ISDN_MAX_CHANNELS; i++) + kfree(ippp_table[i]); } /* * handler for incoming packets on a syncPPP interface */ - -void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb) +void +isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb) { struct ippp_struct *is; is = ippp_table[lp->ppp_slot]; - if(is->debug & 0x4) - printk(KERN_DEBUG "recv skb, len: %ld\n",skb->len); - - if(net_dev->local.master) { + 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); + } + if (net_dev->local.master) { printk(KERN_WARNING "isdn_ppp_receice: net_dev != master\n"); - net_dev = ((isdn_net_local*) net_dev->local.master->priv)->netdev; + net_dev = ((isdn_net_local *) net_dev->local.master->priv)->netdev; } - - if(skb->data[0] == 0xff && skb->data[1] == 0x03) - skb_pull(skb,2); + if (skb->data[0] == 0xff && skb->data[1] == 0x03) + skb_pull(skb, 2); else if (is->pppcfg & SC_REJ_COMP_AC) { - skb->free = 1; - dev_kfree_skb(skb,0 /* FREE_READ */ ); - return; /* discard it silently */ + SET_SKB_FREE(skb); + dev_kfree_skb(skb, 0 /* FREE_READ */ ); + return; /* discard it silently */ } - #ifdef CONFIG_ISDN_MPP if (!(is->mpppcfg & SC_REJ_MP_PROT)) { int proto; int sqno_end; if (skb->data[0] & 0x1) { proto = skb->data[0]; - skb_pull(skb,1); /* protocol ID is only 8 bit */ + skb_pull(skb, 1); /* protocol ID is only 8 bit */ } else { proto = ((int) skb->data[0] << 8) + skb->data[1]; - skb_pull(skb,2); + skb_pull(skb, 2); } if (proto == PPP_MP) { isdn_net_local *lpq; - int sqno, min_sqno, tseq; + long sqno, + min_sqno, + tseq; u_char BEbyte = skb->data[0]; - if(is->debug & 0x8) - printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_slot, proto , - (int) skb->len, (int) skb->data[0], (int) skb->data[1], (int) skb->data[2], - (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]); + if (is->debug & 0x8) + printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_slot, proto, + (int) skb->len, (int) skb->data[0], (int) skb->data[1], (int) skb->data[2], + (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]); if (!(is->mpppcfg & SC_IN_SHORT_SEQ)) { sqno = ((int) skb->data[1] << 16) + ((int) skb->data[2] << 8) + (int) skb->data[3]; - skb_pull(skb,4); + skb_pull(skb, 4); } else { sqno = (((int) skb->data[0] & 0xf) << 8) + (int) skb->data[1]; - skb_pull(skb,2); + skb_pull(skb, 2); } if ((tseq = is->last_link_seqno) >= sqno) { int range = is->range; - if (tseq + 1024 < range + sqno) /* redundancy check .. not MP conform */ - printk(KERN_WARNING "isdn_ppp_receive, MP, detected overflow with sqno: %d, last: %d !!!\n", sqno, tseq); + if (tseq + 1024 < range + sqno) /* redundancy check .. not MP conform */ + printk(KERN_WARNING "isdn_ppp_receive, MP, detected overflow with sqno: %ld, last: %ld !!!\n", sqno, tseq); else { sqno += range; is->last_link_seqno = sqno; @@ -766,16 +981,19 @@ } else is->last_link_seqno = sqno; - for (min_sqno = 0, lpq = net_dev->queue;;) { - if (ippp_table[lpq->ppp_slot]->last_link_seqno > min_sqno) - min_sqno = ippp_table[lpq->ppp_slot]->last_link_seqno; + for (min_sqno = LONG_MAX, lpq = net_dev->queue;;) { + long lls = ippp_table[lpq->ppp_slot]->last_link_seqno; + if (lls >= 0 && lls < min_sqno) + min_sqno = lls; lpq = lpq->next; if (lpq == net_dev->queue) break; } if (min_sqno >= ippp_table[lpq->ppp_slot]->range) { /* OK, every link overflowed */ int mask = ippp_table[lpq->ppp_slot]->range - 1; /* range is a power of 2 */ +#if 0 isdn_ppp_cleanup_queue(net_dev, min_sqno); +#endif isdn_ppp_mask_queue(net_dev, mask); net_dev->ib.next_num &= mask; { @@ -794,12 +1012,23 @@ } } if ((BEbyte & (MP_BEGIN_FRAG | MP_END_FRAG)) != (MP_BEGIN_FRAG | MP_END_FRAG)) { - printk(KERN_DEBUG "ippp: trying ;) to fill mp_queue %d .. UNTESTED!!\n", lp->ppp_slot); - if ((sqno_end = isdn_ppp_fill_mpqueue(net_dev, &skb , BEbyte, &sqno, min_sqno)) < 0) - return; /* no packet complete */ + static int dmes = 0; + if( !dmes ) { + printk(KERN_DEBUG "ippp: trying ;) to fill mp_queue %d .. UNTESTED!!\n", lp->ppp_slot); + dmes = 1; + } + if ((sqno_end = isdn_ppp_fill_mpqueue(net_dev, &skb, BEbyte, &sqno, min_sqno)) < 0) { + net_dev->ib.modify = 1; /* block timeout-timer */ + isdn_ppp_cleanup_sqqueue(net_dev, lp, min_sqno); + net_dev->ib.modify = 0; + return; /* no packet complete */ + } } else sqno_end = sqno; + if (is->debug & 0x40) + printk(KERN_DEBUG "min_sqno: %ld sqno_end %d next: %ld\n", min_sqno, sqno_end, net_dev->ib.next_num); + /* * MP buffer management .. reorders incoming packets .. * lotsa mem-copies and not heavily tested. @@ -807,7 +1036,7 @@ * first check whether there is more than one link in the bundle * then check whether the number is in order */ - net_dev->ib.modify = 1; /* block timeout-timer */ + net_dev->ib.modify = 1; /* block timeout-timer */ if (net_dev->ib.bundled && net_dev->ib.next_num != sqno) { /* * packet is not 'in order' @@ -818,9 +1047,9 @@ if (!q) { net_dev->ib.modify = 0; printk(KERN_WARNING "ippp/MPPP: Bad! Can't alloc sq node!\n"); - skb->free = 1; + SET_SKB_FREE(skb); dev_kfree_skb(skb, 0 /* FREE_READ */ ); - return; /* discard */ + return; /* discard */ } q->skb = skb; q->sqno_end = sqno_end; @@ -842,136 +1071,123 @@ ql->next = q; } } - net_dev->ib.modify = 0; - return; } else { - /* - * packet was 'in order' .. push it higher + /* + * packet was 'in order' .. push it higher */ - struct sqqueue *q; - net_dev->ib.next_num = sqno_end + 1; isdn_ppp_push_higher(net_dev, lp, skb, -1); - - /* - * check queue, whether we have still buffered the next packet(s) - */ - while ((q = net_dev->ib.sq) && q->sqno_start == net_dev->ib.next_num) { - isdn_ppp_push_higher(net_dev, lp, q->skb, -1); - net_dev->ib.sq = q->next; - net_dev->ib.next_num = q->sqno_end + 1; - kfree(q); - } } + isdn_ppp_cleanup_sqqueue(net_dev, lp, min_sqno); net_dev->ib.modify = 0; } else - isdn_ppp_push_higher(net_dev, lp, skb , proto); + isdn_ppp_push_higher(net_dev, lp, skb, proto); } else #endif - isdn_ppp_push_higher(net_dev, lp, skb , -1); + isdn_ppp_push_higher(net_dev, lp, skb, -1); } - /* * push frame to higher layers * note: net_dev has to be master net_dev */ -static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb,int proto) +static void +isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto) { struct device *dev = &net_dev->dev; struct ippp_struct *is = ippp_table[lp->ppp_slot]; - if (proto < 0) { /* MP, oder normales Paket bei REJ_MP, MP Pakete gehen bei REJ zum pppd */ + if (proto < 0) { /* MP, oder normales Paket bei REJ_MP, MP Pakete gehen bei REJ zum pppd */ if (skb->data[0] & 0x01) { /* is it odd? */ proto = (unsigned char) skb->data[0]; - skb_pull(skb,1); /* protocol ID is only 8 bit */ + skb_pull(skb, 1); /* protocol ID is only 8 bit */ } else { proto = ((int) (unsigned char) skb->data[0] << 8) + (unsigned char) skb->data[1]; - skb_pull(skb,2); + skb_pull(skb, 2); } } - - if(is->debug & 0x10) - printk(KERN_DEBUG "push, skb %ld %04x\n",skb->len,proto); - + 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); + } switch (proto) { - case PPP_IPX: /* untested */ - if(is->debug & 0x20) - printk(KERN_DEBUG "isdn_ppp: _IPX\n"); - skb->dev = dev; - skb->mac.raw = skb->data; - skb->protocol = htons(ETH_P_IPX); - break; -#ifdef CONFIG_ISDN_PPP_VJ - case PPP_VJC_UNCOMP: - if(is->debug & 0x20) - printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n"); - if(slhc_remember(ippp_table[net_dev->local.ppp_slot]->slcomp, skb->data, skb->len) <= 0) { - printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n"); - net_dev->local.stats.rx_dropped++; - skb->free = 1; - dev_kfree_skb(skb,0 /* FREE_READ */ ); - return; - } -#endif - case PPP_IP: - if(is->debug & 0x20) - printk(KERN_DEBUG "isdn_ppp: IP\n"); - skb->dev = dev; - skb->mac.raw = skb->data; - skb->protocol = htons(ETH_P_IP); - break; - case PPP_VJC_COMP: - if(is->debug & 0x20) - printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n"); + case PPP_IPX: /* untested */ + if (is->debug & 0x20) + printk(KERN_DEBUG "isdn_ppp: IPX\n"); + skb->dev = dev; + skb->mac.raw = skb->data; + skb->protocol = htons(ETH_P_IPX); + break; #ifdef CONFIG_ISDN_PPP_VJ - { - struct sk_buff *skb_old = skb; - int pkt_len; - skb = dev_alloc_skb(skb_old->len + 40); - - skb_old->free = 1; - - if (!skb) { - printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); + case PPP_VJC_UNCOMP: + if (is->debug & 0x20) + printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n"); + if (slhc_remember(ippp_table[net_dev->local.ppp_slot]->slcomp, skb->data, skb->len) <= 0) { + printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n"); net_dev->local.stats.rx_dropped++; - dev_kfree_skb(skb_old,0 /* FREE_READ */ ); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, 0 /* FREE_READ */ ); return; } +#endif + case PPP_IP: + if (is->debug & 0x20) + printk(KERN_DEBUG "isdn_ppp: IP\n"); skb->dev = dev; - skb_put(skb,skb_old->len + 40); - memcpy(skb->data, skb_old->data, skb_old->len); skb->mac.raw = skb->data; - pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_slot]->slcomp, - skb->data, skb_old->len); - dev_kfree_skb(skb_old,0 /* FREE_READ */ ); - if(pkt_len < 0) { - skb->free = 1; - dev_kfree_skb(skb, 0 /* FREE_READ */ ); - lp->stats.rx_dropped++; - return; - } - skb_trim(skb, pkt_len); skb->protocol = htons(ETH_P_IP); - } + break; + case PPP_VJC_COMP: + if (is->debug & 0x20) + printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n"); +#ifdef CONFIG_ISDN_PPP_VJ + { + struct sk_buff *skb_old = skb; + int pkt_len; + skb = dev_alloc_skb(skb_old->len + 40); + + SET_SKB_FREE(skb_old); + + if (!skb) { + printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); + net_dev->local.stats.rx_dropped++; + dev_kfree_skb(skb_old, 0 /* FREE_READ */ ); + return; + } + skb->dev = dev; + skb_put(skb, skb_old->len + 40); + memcpy(skb->data, skb_old->data, skb_old->len); + skb->mac.raw = skb->data; + pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_slot]->slcomp, + skb->data, skb_old->len); + dev_kfree_skb(skb_old, 0 /* FREE_READ */ ); + if (pkt_len < 0) { + SET_SKB_FREE(skb); + dev_kfree_skb(skb, 0 /* FREE_READ */ ); + lp->stats.rx_dropped++; + return; + } + skb_trim(skb, pkt_len); + skb->protocol = htons(ETH_P_IP); + } #else - printk(KERN_INFO "isdn: Ooopsa .. VJ-Compression support not compiled into isdn driver.\n"); - lp->stats.rx_dropped++; - skb->free = 1; - dev_kfree_skb(skb,0 /* FREE_READ */ ); - return; + printk(KERN_INFO "isdn: Ooopsa .. VJ-Compression support not compiled into isdn driver.\n"); + lp->stats.rx_dropped++; + SET_SKB_FREE(skb); + dev_kfree_skb(skb, 0 /* FREE_READ */ ); + return; #endif - break; - default: - isdn_ppp_fill_rq(skb->data, skb->len,proto, lp->ppp_slot); /* push data to pppd device */ - skb->free = 1; - dev_kfree_skb(skb,0 /* FREE_READ */ ); - return; + break; + default: + isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */ + SET_SKB_FREE(skb); + dev_kfree_skb(skb, 0 /* FREE_READ */ ); + return; } netif_rx(skb); - net_dev->local.stats.rx_packets++; + /* net_dev->local.stats.rx_packets++; *//* done in isdn_net.c */ /* Reset hangup-timer */ lp->huptimer = 0; @@ -979,56 +1195,77 @@ } /* - * send ppp frame .. we expect a PIDCOMPressable proto -- + * send ppp frame .. we expect a PIDCOMPressable proto -- * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP) * * VJ compression may change skb pointer!!! .. requeue with old - * skb isn't allowed!! + * skb isn't allowed!! */ -static void isdn_ppp_skb_destructor(struct sk_buff *skb) +int +isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) { - char outstr[80],*outpnt=outstr; - int i; - - *outpnt = 0; - for(i=0;i<24 && ilen;i++) { - sprintf(outpnt,"%02x ",skb->data[i]); - outpnt += 3; - } - printk(KERN_DEBUG "ippp_dstrct: %s\n",outstr); -} - -int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) -{ - struct device *mdev = ((isdn_net_local *) (dev->priv) )->master; /* get master (for redundancy) */ - isdn_net_local *lp,*mlp; + struct device *mdev = ((isdn_net_local *) (dev->priv))->master; /* get master (for redundancy) */ + isdn_net_local *lp, + *mlp; isdn_net_dev *nd; - int proto = PPP_IP; /* 0x21 */ - struct ippp_struct *ipt,*ipts; + int proto = PPP_IP; /* 0x21 */ + struct ippp_struct *ipt, + *ipts; - if(mdev) - mlp = (isdn_net_local *) (mdev->priv); - else + if (mdev) + mlp = (isdn_net_local *) (mdev->priv); + else { + mdev = dev; mlp = (isdn_net_local *) (dev->priv); - nd = mlp->netdev; /* get master lp */ + } + nd = mlp->netdev; /* get master lp */ ipts = ippp_table[mlp->ppp_slot]; - if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ - if(ipts->debug & 0x1) { - printk(KERN_INFO "%s: IP frame delayed.\n",dev->name); - skb->destructor = isdn_ppp_skb_destructor; - } - return 1; - } + if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ +#ifdef ISDN_SYNCPPP_READDRESS + if (!ipts->old_pa_addr) + ipts->old_pa_addr = mdev->pa_addr; + if (!ipts->old_pa_dstaddr) + ipts->old_pa_dstaddr = mdev->pa_dstaddr; +#endif + if (ipts->debug & 0x1) + printk(KERN_INFO "%s: IP frame delayed.\n", dev->name); + return 1; + } + switch (ntohs(skb->protocol)) { + case ETH_P_IP: + proto = PPP_IP; +#ifdef ISDN_SYNCPPP_READDRESS + if (ipts->old_pa_addr != mdev->pa_addr) { + struct iphdr *ipfr; + ipfr = (struct iphdr *) skb->data; + printk(KERN_DEBUG "IF-address changed from %lx to %lx\n", ipts->old_pa_addr, mdev->pa_addr); + if (ipfr->version == 4) { + if (ipfr->saddr == ipts->old_pa_addr) { + printk(KERN_DEBUG "readdressing %lx to %lx\n", ipfr->saddr, mdev->pa_addr); + ipfr->saddr = mdev->pa_addr; + } + } + } + /* dstaddr change not so improtant */ +#endif + break; + case ETH_P_IPX: + proto = PPP_IPX; /* untested */ + break; + default: + dev_kfree_skb(skb, FREE_WRITE); + printk(KERN_ERR "isdn_ppp: skipped frame with unsupported protocoll: %#x.\n", skb->protocol); + return 0; + } - skb->destructor = NULL; + lp = nd->queue; /* get lp on top of queue */ - lp = nd->queue; /* get lp on top of queue */ - if(lp->sav_skb) { /* find a non-busy device */ + if (lp->sav_skb) { /* find a non-busy device */ isdn_net_local *nlp = lp->next; - while(lp->sav_skb) { - if(lp == nlp) + while (lp->sav_skb) { + if (lp == nlp) return 1; nlp = nd->queue = nd->queue->next; } @@ -1036,43 +1273,42 @@ } ipt = ippp_table[lp->ppp_slot]; - lp->huptimer = 0; + lp->huptimer = 0; /* - * after this line .. requeueing in the device queue is no longer allowed!!! + * after this line .. requeueing in the device queue is no longer allowed!!! */ - if(ipt->debug & 0x4) - printk(KERN_DEBUG "xmit skb, len %ld\n",skb->len); + if (ipt->debug & 0x4) + printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len); #ifdef CONFIG_ISDN_PPP_VJ - if (ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes .. but this check again */ + if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes .. but this check again */ struct sk_buff *new_skb; new_skb = dev_alloc_skb(skb->len); - if(new_skb) { + if (new_skb) { u_char *buf; int pktlen; new_skb->dev = skb->dev; - new_skb->free = 1; - skb_put(new_skb,skb->len); + SET_SKB_FREE(new_skb); + skb_put(new_skb, skb->len); buf = skb->data; pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data, - &buf, !(ipts->pppcfg & SC_NO_TCP_CCID)); + &buf, !(ipts->pppcfg & SC_NO_TCP_CCID)); - if(buf != skb->data) { /* copied to new buffer ??? (btw: WHY must slhc copy it?? *sigh*) */ - if(new_skb->data != buf) + if (buf != skb->data) { /* copied to new buffer ??? (btw: WHY must slhc copy it?? *sigh*) */ + if (new_skb->data != buf) printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n"); - dev_kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb, FREE_WRITE); skb = new_skb; - } - else { - dev_kfree_skb(new_skb,0 /* FREE_WRITE */ ); + } else { + dev_kfree_skb(new_skb, 0 /* FREE_WRITE */ ); } - skb_trim(skb,pktlen); + skb_trim(skb, pktlen); if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) { /* cslip? style -> PPP */ proto = PPP_VJC_COMP; skb->data[0] ^= SL_TYPE_COMPRESSED_TCP; @@ -1085,8 +1321,8 @@ } #endif - if(ipt->debug & 0x24) - printk(KERN_DEBUG "xmit2 skb, len %ld, proto %04x\n",skb->len,proto); + if (ipt->debug & 0x24) + printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto); #ifdef CONFIG_ISDN_MPP if (ipt->mpppcfg & SC_MP_PROT) { @@ -1111,34 +1347,41 @@ proto = PPP_MP; /* MP Protocol, 0x003d */ } #endif - skb_push(skb,4); - skb->data[0] = 0xff; /* All Stations */ - skb->data[1] = 0x03; /* Unnumbered information */ + skb_push(skb, 4); + skb->data[0] = 0xff; /* All Stations */ + skb->data[1] = 0x03; /* Unnumbered information */ skb->data[2] = proto >> 8; skb->data[3] = proto & 0xff; - /* tx-stats are now updated via BSENT-callback */ - if(isdn_net_send_skb(dev , lp , skb)) { - if(lp->sav_skb) { /* whole sav_skb processing with disabled IRQs ?? */ - printk(KERN_ERR "%s: whoops .. there is another stored skb!\n",dev->name); - dev_kfree_skb(skb,FREE_WRITE); - } - else + /* tx-stats are now updated via BSENT-callback */ + + 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); + } + if (isdn_net_send_skb(dev, lp, skb)) { + if (lp->sav_skb) { /* whole sav_skb processing with disabled IRQs ?? */ + printk(KERN_ERR "%s: whoops .. there is another stored skb!\n", dev->name); + dev_kfree_skb(skb, FREE_WRITE); + } else lp->sav_skb = skb; } return 0; } -void isdn_ppp_free_sqqueue(isdn_net_dev * p) +#ifdef CONFIG_ISDN_MPP + +static void +isdn_ppp_free_sqqueue(isdn_net_dev * p) { struct sqqueue *q = p->ib.sq; p->ib.sq = NULL; - while(q) { + while (q) { struct sqqueue *qn = q->next; - if(q->skb) { - q->skb->free = 1; - dev_kfree_skb(q->skb,0 /* FREE_READ */ ); + if (q->skb) { + SET_SKB_FREE(q->skb); + dev_kfree_skb(q->skb, 0 /* FREE_READ */ ); } kfree(q); q = qn; @@ -1146,26 +1389,29 @@ } -void isdn_ppp_free_mpqueue(isdn_net_dev * p) +static void +isdn_ppp_free_mpqueue(isdn_net_dev * p) { - struct mpqueue *ql, *q = p->mp_last; + struct mpqueue *q = p->mp_last; + p->mp_last = NULL; + while (q) { - ql = q->next; - q->skb->free = 1; - dev_kfree_skb(q->skb,0 /* FREE_READ */ ); + struct mpqueue *ql = q->next; + SET_SKB_FREE(q->skb); + dev_kfree_skb(q->skb, 0 /* FREE_READ */ ); kfree(q); q = ql; } } -#ifdef CONFIG_ISDN_MPP - -static int isdn_ppp_bundle(struct ippp_struct *is, int unit) +static int +isdn_ppp_bundle(struct ippp_struct *is, int unit) { char ifn[IFNAMSIZ + 1]; long flags; isdn_net_dev *p; - isdn_net_local *lp,*nlp; + isdn_net_local *lp, + *nlp; sprintf(ifn, "ippp%d", unit); p = isdn_net_findif(ifn); @@ -1206,7 +1452,8 @@ } -static void isdn_ppp_mask_queue(isdn_net_dev * dev, long mask) +static void +isdn_ppp_mask_queue(isdn_net_dev * dev, long mask) { struct mpqueue *q = dev->mp_last; while (q) { @@ -1215,20 +1462,24 @@ } } - -static int isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff ** skb, int BEbyte, int *sqnop, int min_sqno) +static int +isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff **skb, int BEbyte, long *sqnop, int min_sqno) { - struct mpqueue *qe, *q1, *q; - long cnt, flags; - int pktlen, sqno_end; + struct mpqueue *qe, + *q1, + *q; + long cnt, + flags; + int pktlen, + sqno_end; int sqno = *sqnop; - q1 = (struct mpqueue *) kmalloc(sizeof(struct mpqueue), GFP_KERNEL); + q1 = (struct mpqueue *) kmalloc(sizeof(struct mpqueue), GFP_ATOMIC); if (!q1) { printk(KERN_WARNING "isdn_ppp_fill_mpqueue: Can't alloc struct memory.\n"); save_flags(flags); cli(); - isdn_ppp_cleanup_queue(dev, min_sqno); + isdn_ppp_cleanup_mpqueue(dev, min_sqno); restore_flags(flags); return -1; } @@ -1244,11 +1495,11 @@ dev->mp_last = q1; q1->next = NULL; q1->last = NULL; - isdn_ppp_cleanup_queue(dev, min_sqno); /* not necessary */ + isdn_ppp_cleanup_mpqueue(dev, min_sqno); /* not necessary */ restore_flags(flags); - return -1; + return -1; /* -1 is not an error. Just says, that this fragment hasn't complete a full frame */ } - for (;;) { /* the faster way would be to step from the queue-end to the start */ + for (;;) { /* the faster way would be to step from the queue-end to the start */ if (sqno > q->sqno) { if (q->next) { q = q->next; @@ -1278,7 +1529,7 @@ while (!(q->BEbyte & MP_END_FRAG)) { cnt++; if (!(q->next) || q->next->sqno != cnt) { - isdn_ppp_cleanup_queue(dev, min_sqno); + isdn_ppp_cleanup_mpqueue(dev, min_sqno); restore_flags(flags); return -1; } @@ -1293,7 +1544,7 @@ while (!(q->BEbyte & MP_BEGIN_FRAG)) { cnt--; if (!(q->last) || q->last->sqno != cnt) { - isdn_ppp_cleanup_queue(dev, min_sqno); + isdn_ppp_cleanup_mpqueue(dev, min_sqno); restore_flags(flags); return -1; } @@ -1313,29 +1564,29 @@ sqno_end = qe->sqno; *sqnop = q->sqno; - isdn_ppp_cleanup_queue(dev, min_sqno); + isdn_ppp_cleanup_mpqueue(dev, min_sqno); restore_flags(flags); - *skb = dev_alloc_skb(pktlen + 40); /* not needed: +40 for VJ compression .. */ + *skb = dev_alloc_skb(pktlen + 40); /* not needed: +40 for VJ compression .. */ if (!(*skb)) { while (q) { struct mpqueue *ql = q->next; - q->skb->free = 1; - dev_kfree_skb(q->skb,0 /* FREE_READ */ ); + SET_SKB_FREE(q->skb); + dev_kfree_skb(q->skb, 0 /* FREE_READ */ ); kfree(q); q = ql; } return -2; } cnt = 0; - skb_put(*skb,pktlen); + skb_put(*skb, pktlen); while (q) { struct mpqueue *ql = q->next; memcpy((*skb)->data + cnt, q->skb->data, q->skb->len); cnt += q->skb->len; - q->skb->free = 1; - dev_kfree_skb(q->skb,0 /* FREE_READ */ ); + SET_SKB_FREE(q->skb); + dev_kfree_skb(q->skb, 0 /* FREE_READ */ ); kfree(q); q = ql; } @@ -1344,10 +1595,34 @@ } /* + * check sq-queue, whether we have still buffered the next packet(s) + * or packets with a sqno less or equal to min_sqno + * net_dev: master netdevice , lp: 'real' local connection + */ +static void +isdn_ppp_cleanup_sqqueue(isdn_net_dev * net_dev, isdn_net_local * lp, long min_sqno) +{ + struct sqqueue *q; + + while ((q = net_dev->ib.sq) && (q->sqno_start == net_dev->ib.next_num || q->sqno_end <= min_sqno)) { + if (q->sqno_start != net_dev->ib.next_num) { + printk(KERN_DEBUG "ippp: MP, stepping over missing frame: %ld\n", net_dev->ib.next_num); +#ifdef CONFIG_ISDN_PPP_VJ + slhc_toss(ippp_table[net_dev->local.ppp_slot]->slcomp); +#endif + } + isdn_ppp_push_higher(net_dev, lp, q->skb, -1); + net_dev->ib.sq = q->next; + net_dev->ib.next_num = q->sqno_end + 1; + kfree(q); + } +} + +/* * remove stale packets from list */ - -static void isdn_ppp_cleanup_queue(isdn_net_dev * dev, long min_sqno) +static void +isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min_sqno) { #ifdef CONFIG_ISDN_PPP_VJ int toss = 0; @@ -1355,11 +1630,12 @@ /* z.z einfaches aussortieren gammeliger pakete. Fuer die Zukunft: eventuell, solange vorne kein B-paket ist und sqno<=min_sqno: auch rauswerfen wenn sqnomp_last; + struct mpqueue *ql, + *q = dev->mp_last; while (q) { if (q->sqno < min_sqno) { if (q->BEbyte & MP_END_FRAG) { @@ -1368,8 +1644,8 @@ q->next->last = NULL; while (q) { ql = q->last; - q->skb->free = 1; - dev_kfree_skb(q->skb,0 /* FREE_READ */ ); + SET_SKB_FREE(q->skb); + dev_kfree_skb(q->skb, 0 /* FREE_READ */ ); kfree(q); #ifdef CONFIG_ISDN_PPP_VJ toss = 1; @@ -1384,7 +1660,7 @@ } #ifdef CONFIG_ISDN_PPP_VJ /* did we free a stale frame ? */ - if(toss) + if (toss) slhc_toss(ippp_table[dev->local.ppp_slot]->slcomp); #endif } @@ -1395,26 +1671,28 @@ #endif -void isdn_ppp_timer_timeout(void) +void +isdn_ppp_timer_timeout(void) { #ifdef CONFIG_ISDN_MPP isdn_net_dev *net_dev = dev->netdev; - struct sqqueue *q, *ql = NULL, *qn; + struct sqqueue *q, + *ql = NULL, + *qn; while (net_dev) { isdn_net_local *lp = &net_dev->local; - if (net_dev->ib.modify || lp->master) { /* interface locked or slave?*/ - net_dev = net_dev->next; + if (net_dev->ib.modify || lp->master) { /* interface locked or slave? */ + net_dev = net_dev->next; continue; - } - + } q = net_dev->ib.sq; while (q) { if (q->sqno_start == net_dev->ib.next_num || q->timer < jiffies) { #ifdef CONFIG_ISDN_PPP_VJ /* did we step over a missing frame ? */ - if(q->sqno_start != net_dev->ib.next_num) + if (q->sqno_start != net_dev->ib.next_num) slhc_toss(ippp_table[lp->ppp_slot]->slcomp); #endif @@ -1441,47 +1719,57 @@ * network device ioctl handlers */ -static int isdn_ppp_dev_ioctl_stats(int slot,struct ifreq *ifr,struct device *dev) +static int +isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct device *dev) { - struct ppp_stats *res, t; + struct ppp_stats *res, + t; isdn_net_local *lp = (isdn_net_local *) dev->priv; + int err; res = (struct ppp_stats *) ifr->ifr_ifru.ifru_data; + err = verify_area(VERIFY_WRITE, res, sizeof(struct ppp_stats)); + + if (err) + return err; /* build a temporary stat struct and copy it to user space */ - memset (&t, 0, sizeof(struct ppp_stats)); - if(dev->flags & IFF_UP) { + memset(&t, 0, sizeof(struct ppp_stats)); + if (dev->flags & IFF_UP) { t.p.ppp_ipackets = lp->stats.rx_packets; t.p.ppp_ierrors = lp->stats.rx_errors; t.p.ppp_opackets = lp->stats.tx_packets; t.p.ppp_oerrors = lp->stats.tx_errors; #ifdef CONFIG_ISDN_PPP_VJ - if(slot >= 0 && ippp_table[slot]->slcomp) { + if (slot >= 0 && ippp_table[slot]->slcomp) { struct slcompress *slcomp = ippp_table[slot]->slcomp; - t.vj.vjs_packets = slcomp->sls_o_compressed+slcomp->sls_o_uncompressed; + t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed; t.vj.vjs_compressed = slcomp->sls_o_compressed; t.vj.vjs_searches = slcomp->sls_o_searches; - t.vj.vjs_misses = slcomp->sls_o_misses; - t.vj.vjs_errorin = slcomp->sls_i_error; - t.vj.vjs_tossed = slcomp->sls_i_tossed; + t.vj.vjs_misses = slcomp->sls_o_misses; + t.vj.vjs_errorin = slcomp->sls_i_error; + t.vj.vjs_tossed = slcomp->sls_i_tossed; t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed; t.vj.vjs_compressedin = slcomp->sls_i_compressed; } #endif } - return copy_to_user (res, &t, sizeof (struct ppp_stats)) ? -EFAULT : 0; + copy_to_user(res, &t, sizeof(struct ppp_stats)); + return 0; + } -int isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd) +int +isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd) { - int error = 0; + int error; char *r; int len; isdn_net_local *lp = (isdn_net_local *) dev->priv; #if 0 - printk(KERN_DEBUG "ippp, dev_ioctl: cmd %#08x , %d \n",cmd,lp->ppp_slot); + printk(KERN_DEBUG "ippp, dev_ioctl: cmd %#08x , %d \n", cmd, lp->ppp_slot); #endif if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) @@ -1491,11 +1779,12 @@ case SIOCGPPPVER: r = (char *) ifr->ifr_ifru.ifru_data; len = strlen(PPP_VERSION) + 1; - if (copy_to_user(r, PPP_VERSION, len)) - error = -EFAULT; + error = verify_area(VERIFY_WRITE, r, len); + if (!error) + copy_to_user(r, PPP_VERSION, len); break; case SIOCGPPPSTATS: - error = isdn_ppp_dev_ioctl_stats (lp->ppp_slot, ifr, dev); + error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev); break; default: error = -EINVAL; @@ -1504,51 +1793,55 @@ return error; } -static int isdn_ppp_if_get_unit(char *name) +static int +isdn_ppp_if_get_unit(char *name) { - int len, i, unit = 0, deci; + int len, + i, + unit = 0, + deci; len = strlen(name); - if(strncmp("ippp",name,4) || len > 8) + if (strncmp("ippp", name, 4) || len > 8) return -1; for (i = 0, deci = 1; i < len; i++, deci *= 10) { - char a = name[len-i-1]; + char a = name[len - i - 1]; if (a >= '0' && a <= '9') unit += (a - '0') * deci; else break; } - if (!i || len-i != 4) + if (!i || len - i != 4) unit = -1; return unit; } -int isdn_ppp_dial_slave(char *name) +int +isdn_ppp_dial_slave(char *name) { #ifdef CONFIG_ISDN_MPP isdn_net_dev *ndev; isdn_net_local *lp; struct device *sdev; - if(!(ndev = isdn_net_findif(name))) + if (!(ndev = isdn_net_findif(name))) return 1; lp = &ndev->local; - if(!(lp->flags & ISDN_NET_CONNECTED)) + if (!(lp->flags & ISDN_NET_CONNECTED)) return 5; sdev = lp->slave; - while(sdev) - { + while (sdev) { isdn_net_local *mlp = (isdn_net_local *) sdev->priv; - if(!(mlp->flags & ISDN_NET_CONNECTED)) + if (!(mlp->flags & ISDN_NET_CONNECTED)) break; sdev = mlp->slave; } - if(!sdev) + if (!sdev) return 2; isdn_net_force_dial_lp((isdn_net_local *) sdev->priv); @@ -1558,28 +1851,28 @@ #endif } -int isdn_ppp_hangup_slave(char *name) +int +isdn_ppp_hangup_slave(char *name) { #ifdef CONFIG_ISDN_MPP - isdn_net_dev *ndev; - isdn_net_local *lp; - struct device *sdev; + isdn_net_dev *ndev; + isdn_net_local *lp; + struct device *sdev; - if(!(ndev = isdn_net_findif(name))) + if (!(ndev = isdn_net_findif(name))) return 1; lp = &ndev->local; - if(!(lp->flags & ISDN_NET_CONNECTED)) + if (!(lp->flags & ISDN_NET_CONNECTED)) return 5; sdev = lp->slave; - while(sdev) - { + while (sdev) { isdn_net_local *mlp = (isdn_net_local *) sdev->priv; - if((mlp->flags & ISDN_NET_CONNECTED)) + if ((mlp->flags & ISDN_NET_CONNECTED)) break; sdev = mlp->slave; } - if(!sdev) + if (!sdev) return 2; isdn_net_hangup(sdev); @@ -1589,3 +1882,12 @@ #endif } +#if 0 +static struct symbol_table isdn_ppp_syms = +{ +#include + X(isdn_ppp_register_compressor), + X(isdn_ppp_unregister_compressor), +#include +}; +#endif diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/isdn_ppp.h linux/drivers/isdn/isdn_ppp.h --- v2.1.26/linux/drivers/isdn/isdn_ppp.h Sat Aug 31 09:13:03 1996 +++ linux/drivers/isdn/isdn_ppp.h Tue Feb 25 17:12:50 1997 @@ -1,9 +1,9 @@ -/* $Id: isdn_ppp.h,v 1.4 1996/05/06 11:34:56 hipp Exp $ - * +/* $Id: isdn_ppp.h,v 1.9 1997/02/11 18:32:59 fritz Exp $ + * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel). * * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.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 * the Free Software Foundation; either version 2, or (at your option) @@ -16,9 +16,26 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ppp.h,v $ + * Revision 1.9 1997/02/11 18:32:59 fritz + * Bugfix in isdn_ppp_free_mpqueue(). + * + * Revision 1.8 1997/02/10 10:11:33 fritz + * More changes for Kernel 2.1.X compatibility. + * + * Revision 1.7 1997/02/03 23:18:57 fritz + * Removed isdn_ppp_free_sqqueue prototype + * and ippp_table (both static in isdn_ppp.c). + * + * Revision 1.6 1996/09/23 01:58:11 fritz + * Fix: With syncPPP encapsulation, discard LCP packets + * when calculating hangup timeout. + * + * Revision 1.5 1996/09/07 12:51:34 hipp + * *** empty log message *** + * * Revision 1.4 1996/05/06 11:34:56 hipp * fixed a few bugs * @@ -34,23 +51,30 @@ * */ +#include /* for PPP_PROTOCOL */ extern void isdn_ppp_timer_timeout(void); -extern int isdn_ppp_read(int , struct file *, char *, int); -extern int isdn_ppp_write(int , struct file *, const char *, int); -extern int isdn_ppp_open(int , struct file *); -extern int isdn_ppp_init(void); +extern int isdn_ppp_read(int, struct file *, char *, int); +extern int isdn_ppp_write(int, struct file *, const char *, int); +extern int isdn_ppp_open(int, struct file *); +extern int isdn_ppp_init(void); extern void isdn_ppp_cleanup(void); -extern int isdn_ppp_free(isdn_net_local *); -extern int isdn_ppp_bind(isdn_net_local *); -extern int isdn_ppp_xmit(struct sk_buff *, struct device *); +extern int isdn_ppp_free(isdn_net_local *); +extern int isdn_ppp_bind(isdn_net_local *); +extern int isdn_ppp_xmit(struct sk_buff *, struct device *); extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *); -extern int isdn_ppp_dev_ioctl(struct device *, struct ifreq *, int); -extern void isdn_ppp_free_mpqueue(isdn_net_dev *); -extern void isdn_ppp_free_sqqueue(isdn_net_dev *); -extern int isdn_ppp_select(int, struct file *, int, select_table *); -extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long); +extern int isdn_ppp_dev_ioctl(struct device *, struct ifreq *, int); +#if (LINUX_VERSION_CODE < 0x020117) +extern int isdn_ppp_select(int, struct file *, int, select_table *); +#else +extern unsigned int isdn_ppp_poll(struct file *, poll_table *); +#endif +extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long); extern void isdn_ppp_release(int, struct file *); -extern int isdn_ppp_dial_slave(char *); +extern int isdn_ppp_dial_slave(char *); extern void isdn_ppp_wakeup_daemon(isdn_net_local *); -extern struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; +#define IPPP_OPEN 0x01 +#define IPPP_CONNECT 0x02 +#define IPPP_CLOSEWAIT 0x04 +#define IPPP_NOBLOCK 0x08 +#define IPPP_ASSIGNED 0x10 diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/isdn_syms.c linux/drivers/isdn/isdn_syms.c --- v2.1.26/linux/drivers/isdn/isdn_syms.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/isdn_syms.c Tue Feb 25 17:12:50 1997 @@ -0,0 +1,55 @@ +/* $Id: isdn_syms.c,v 1.3 1997/02/16 01:02:47 fritz Exp $ + + * Linux ISDN subsystem, exported symbols (linklevel). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Log: isdn_syms.c,v $ + * Revision 1.3 1997/02/16 01:02:47 fritz + * Added GPL-Header, Id and Log + * + */ +#include +#include +#include + +#ifndef __GENKSYMS__ /* Don't want genksyms report unneeded structs */ +#include +#endif +#include "isdn_common.h" + +#if (LINUX_VERSION_CODE < 0x020111) +static int has_exported; + +static struct symbol_table isdn_syms = { +#include + X(register_isdn), +#include +}; + +void +isdn_export_syms(void) +{ + if (has_exported) + return; + register_symtab(&isdn_syms); + has_exported = 1; +} + +#else + +EXPORT_SYMBOL(register_isdn); + +#endif diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c --- v2.1.26/linux/drivers/isdn/isdn_tty.c Sat Nov 30 00:48:34 1996 +++ linux/drivers/isdn/isdn_tty.c Tue Feb 25 17:12:50 1997 @@ -1,10 +1,10 @@ -/* $Id: isdn_tty.c,v 1.21 1996/06/24 17:40:28 fritz Exp $ - * +/* $Id: isdn_tty.c,v 1.29 1997/02/16 12:11:51 fritz Exp $ + * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) @@ -17,9 +17,37 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.c,v $ + * Revision 1.29 1997/02/16 12:11:51 fritz + * Added S13,Bit4 option. + * + * Revision 1.28 1997/02/10 22:07:08 fritz + * Added 2 modem registers for numbering plan and screening info. + * + * Revision 1.27 1997/02/10 21:31:14 fritz + * Changed setup-interface (incoming and outgoing). + * + * Revision 1.26 1997/02/10 20:12:48 fritz + * Changed interface for reporting incoming calls. + * + * Revision 1.25 1997/02/03 23:04:30 fritz + * Reformatted according CodingStyle. + * skb->free stuff replaced by macro. + * Finished full-duplex audio. + * + * Revision 1.24 1997/01/14 01:32:42 fritz + * Changed audio receive not to rely on skb->users and skb->lock. + * Added ATI2 and related variables. + * Started adding full-duplex audio capability. + * + * Revision 1.23 1996/10/22 23:14:02 fritz + * Changes for compatibility to 2.0.X and 2.1.X kernels. + * + * Revision 1.22 1996/10/19 18:56:43 fritz + * ATZ did not change the xmitbuf size. + * * Revision 1.21 1996/06/24 17:40:28 fritz * Bugfix: Did not compile without CONFIG_ISDN_AUDIO * @@ -109,7 +137,6 @@ * */ -#include #define __NO_VERSION__ #include #include @@ -124,9 +151,9 @@ /* Prototypes */ -static int isdn_tty_edit_at(const char *, int, modem_info *, int); +static int isdn_tty_edit_at(const char *, int, modem_info *, int); static void isdn_tty_check_esc(const u_char *, u_char, int, int *, int *, int); -static void isdn_tty_modem_reset_regs(atemu *, int); +static void isdn_tty_modem_reset_regs(modem_info *, int); static void isdn_tty_cmd_ATA(modem_info *); static void isdn_tty_at_cout(char *, modem_info *); static void isdn_tty_flush_buffer(struct tty_struct *); @@ -136,11 +163,13 @@ #define MODEM_DO_RESTART static char *isdn_ttyname_ttyI = "ttyI"; -static char *isdn_ttyname_cui = "cui"; -static int bit2si[8] = {1,5,7,7,7,7,7,7}; -static int si2bit[8] = {4,1,4,4,4,4,4,4}; - -char *isdn_tty_revision = "$Revision: 1.21 $"; +static char *isdn_ttyname_cui = "cui"; +static int bit2si[8] = +{1, 5, 7, 7, 7, 7, 7, 7}; +static int si2bit[8] = +{4, 1, 4, 4, 4, 4, 4, 4}; + +char *isdn_tty_revision = "$Revision: 1.29 $"; #define DLE 0x10 #define ETX 0x03 @@ -155,37 +184,37 @@ * 0 = Failure, data has to be buffered and later processed by * isdn_tty_readmodem(). */ -int isdn_tty_try_read(modem_info *info, struct sk_buff *skb) +int +isdn_tty_try_read(modem_info * info, struct sk_buff *skb) { - int c; - int len; - struct tty_struct *tty; + int c; + int len; + struct tty_struct *tty; if (info->online) { if ((tty = info->tty)) { if (info->mcr & UART_MCR_RTS) { c = TTY_FLIPBUF_SIZE - tty->flip.count; - len = skb->len + skb->users; + len = skb->len + ISDN_AUDIO_SKB_DLECOUNT(skb); if (c >= len) { - if (skb->users) - while (skb->len--) { - if (*skb->data == DLE) - tty_insert_flip_char(tty, DLE, 0); - tty_insert_flip_char(tty, *skb->data++, 0); - } - else { - memcpy(tty->flip.char_buf_ptr, - skb->data, len); - tty->flip.count += len; - tty->flip.char_buf_ptr += len; - memset(tty->flip.flag_buf_ptr, 0, len); - tty->flip.flag_buf_ptr += len; - } - if (info->emu.mdmreg[12] & 128) - tty->flip.flag_buf_ptr[len - 1] = 0xff; + if (ISDN_AUDIO_SKB_DLECOUNT(skb)) + while (skb->len--) { + if (*skb->data == DLE) + tty_insert_flip_char(tty, DLE, 0); + tty_insert_flip_char(tty, *skb->data++, 0); + } else { + memcpy(tty->flip.char_buf_ptr, + skb->data, len); + tty->flip.count += len; + tty->flip.char_buf_ptr += len; + memset(tty->flip.flag_buf_ptr, 0, len); + tty->flip.flag_buf_ptr += len; + } + if (info->emu.mdmreg[12] & 128) + tty->flip.flag_buf_ptr[len - 1] = 0xff; queue_task_irq_off(&tty->flip.tqueue, &tq_timer); - skb->free = 1; - kfree_skb(skb, FREE_READ); + SET_SKB_FREE(skb); + kfree_skb(skb, FREE_READ); return 1; } } @@ -198,7 +227,8 @@ * It tries getting received data from the receive queue an stuff it into * the tty's flip-buffer. */ -void isdn_tty_readmodem(void) +void +isdn_tty_readmodem(void) { int resched = 0; int midx; @@ -211,7 +241,7 @@ for (i = 0; i < ISDN_MAX_CHANNELS; i++) { if ((midx = dev->m_idx[i]) >= 0) { - info = &dev->mdm.info[midx]; + info = &dev->mdm.info[midx]; if (info->online) { r = 0; #ifdef CONFIG_ISDN_AUDIO @@ -221,12 +251,12 @@ if (info->mcr & UART_MCR_RTS) { c = TTY_FLIPBUF_SIZE - tty->flip.count; if (c > 0) { - save_flags(flags); - cli(); + save_flags(flags); + cli(); r = isdn_readbchan(info->isdn_driver, info->isdn_channel, - tty->flip.char_buf_ptr, - tty->flip.flag_buf_ptr, c, 0); - /* CISCO AsyncPPP Hack */ + tty->flip.char_buf_ptr, + tty->flip.flag_buf_ptr, c, 0); + /* CISCO AsyncPPP Hack */ if (!(info->emu.mdmreg[12] & 128)) memset(tty->flip.flag_buf_ptr, 0, r); tty->flip.count += r; @@ -234,7 +264,7 @@ tty->flip.char_buf_ptr += r; if (r) queue_task_irq_off(&tty->flip.tqueue, &tq_timer); - restore_flags(flags); + restore_flags(flags); } } else r = 1; @@ -246,257 +276,265 @@ } else info->rcvsched = 1; } - } + } } if (!resched) isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0); } -void isdn_tty_cleanup_xmit(modem_info *info) +void +isdn_tty_cleanup_xmit(modem_info * info) { - struct sk_buff *skb; - unsigned long flags; + struct sk_buff *skb; + unsigned long flags; - save_flags(flags); - cli(); - if (skb_queue_len(&info->xmit_queue)) - while ((skb = skb_dequeue(&info->xmit_queue))) { - skb->free = 1; - kfree_skb(skb, FREE_WRITE); - } - if (skb_queue_len(&info->dtmf_queue)) - while ((skb = skb_dequeue(&info->dtmf_queue))) { - skb->free = 1; - kfree_skb(skb, FREE_WRITE); - } - restore_flags(flags); -} - -static void isdn_tty_tint(modem_info *info) -{ - struct sk_buff *skb = skb_dequeue(&info->xmit_queue); - int len, slen; - - if (!skb) - return; - len = skb->len; - if ((slen = isdn_writebuf_skb_stub(info->isdn_driver, - info->isdn_channel, skb)) == len) { - struct tty_struct *tty = info->tty; - info->send_outstanding++; - 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); - wake_up_interruptible(&tty->write_wait); - return; - } - if (slen > 0) - skb_pull(skb,slen); - skb_queue_head(&info->xmit_queue, skb); + save_flags(flags); + cli(); + if (skb_queue_len(&info->xmit_queue)) + while ((skb = skb_dequeue(&info->xmit_queue))) { + SET_SKB_FREE(skb); + kfree_skb(skb, FREE_WRITE); + } + if (skb_queue_len(&info->dtmf_queue)) + while ((skb = skb_dequeue(&info->dtmf_queue))) { + SET_SKB_FREE(skb); + kfree_skb(skb, FREE_WRITE); + } + restore_flags(flags); +} + +static void +isdn_tty_tint(modem_info * info) +{ + struct sk_buff *skb = skb_dequeue(&info->xmit_queue); + int len, + slen; + + if (!skb) + return; + len = skb->len; + if ((slen = isdn_writebuf_skb_stub(info->isdn_driver, + info->isdn_channel, skb)) == len) { + struct tty_struct *tty = info->tty; + info->send_outstanding++; + 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); + wake_up_interruptible(&tty->write_wait); + return; + } + if (slen > 0) + skb_pull(skb, slen); + skb_queue_head(&info->xmit_queue, skb); } #ifdef CONFIG_ISDN_AUDIO -int isdn_tty_countDLE(unsigned char *buf, int len) +int +isdn_tty_countDLE(unsigned char *buf, int len) { - int count = 0; + int count = 0; - while (len--) - if (*buf++ == DLE) - count++; - return count; + while (len--) + if (*buf++ == DLE) + count++; + return count; } /* This routine is called from within isdn_tty_write() to perform * DLE-decoding when sending audio-data. */ -static int isdn_tty_handleDLEdown(modem_info *info, atemu *m, int len) +static int +isdn_tty_handleDLEdown(modem_info * info, atemu * m, int len) { - unsigned char *p = &info->xmit_buf[info->xmit_count]; - int count = 0; + unsigned char *p = &info->xmit_buf[info->xmit_count]; + int count = 0; - while (len>0) { - if (m->lastDLE) { - m->lastDLE = 0; - switch (*p) { - case DLE: - /* Escape code */ - if (len>1) - memmove(p,p+1,len-1); - p--; - count++; - break; - case ETX: - /* End of data */ - info->vonline |= 4; - return count; - case DC4: - /* Abort RX */ - info->vonline &= ~1; - isdn_tty_at_cout("\020\003", info); - if (!info->vonline) - isdn_tty_at_cout("\r\nVCON\r\n", info); - /* Fall through */ - case 'q': - case 's': - /* Silence */ - if (len>1) - memmove(p,p+1,len-1); - p--; - break; - } - } else { - if (*p == DLE) - m->lastDLE = 1; - else - count++; - } - p++; - len--; - } - if (len<0) { - printk(KERN_WARNING "isdn_tty: len<0 in DLEdown\n"); - return 0; - } - return count; + while (len > 0) { + if (m->lastDLE) { + m->lastDLE = 0; + switch (*p) { + case DLE: + /* Escape code */ + if (len > 1) + memmove(p, p + 1, len - 1); + p--; + count++; + break; + case ETX: + /* End of data */ + info->vonline |= 4; + return count; + case DC4: + /* Abort RX */ + info->vonline &= ~1; + isdn_tty_at_cout("\020\003", info); + if (!info->vonline) + isdn_tty_at_cout("\r\nVCON\r\n", info); + /* Fall through */ + case 'q': + case 's': + /* Silence */ + if (len > 1) + memmove(p, p + 1, len - 1); + p--; + break; + } + } else { + if (*p == DLE) + m->lastDLE = 1; + else + count++; + } + p++; + len--; + } + if (len < 0) { + printk(KERN_WARNING "isdn_tty: len<0 in DLEdown\n"); + return 0; + } + return count; } /* This routine is called from within isdn_tty_write() when receiving * audio-data. It interrupts receiving, if an character other than * ^S or ^Q is sent. */ -static int isdn_tty_end_vrx(const char *buf, int c, int from_user) +static int +isdn_tty_end_vrx(const char *buf, int c, int from_user) { char tmpbuf[VBUF]; - char *p; + char *p; - if (c > VBUF) { - printk(KERN_ERR "isdn_tty: (end_vrx) BUFFER OVERFLOW!!!\n"); - return 1; - } + if (c > VBUF) { + printk(KERN_ERR "isdn_tty: (end_vrx) BUFFER OVERFLOW!!!\n"); + return 1; + } if (from_user) { copy_from_user(tmpbuf, buf, c); - p = tmpbuf; - } else - p = (char *)buf; - while (c--) { - if ((*p != 0x11) && (*p != 0x13)) - return 1; - p++; - } - return 0; + p = tmpbuf; + } else + p = (char *) buf; + while (c--) { + if ((*p != 0x11) && (*p != 0x13)) + return 1; + p++; + } + return 0; } -static int voice_cf[7] = { 1, 1, 4, 3, 2, 1, 1 }; +static int voice_cf[7] = +{1, 1, 4, 3, 2, 1, 1}; -#endif /* CONFIG_ISDN_AUDIO */ +#endif /* CONFIG_ISDN_AUDIO */ /* isdn_tty_senddown() is called either directly from within isdn_tty_write() * or via timer-interrupt from within isdn_tty_modem_xmit(). It pulls * outgoing data from the tty's xmit-buffer, handles voice-decompression or * T.70 if necessary, and finally queues it up for sending via isdn_tty_tint. */ -static void isdn_tty_senddown(modem_info * info) +static void +isdn_tty_senddown(modem_info * info) { - unsigned char *buf = info->xmit_buf; - int buflen; - int skb_res; - struct sk_buff *skb; - unsigned long flags; - - save_flags(flags); - cli(); - if (!(buflen = info->xmit_count)) { - restore_flags(flags); - 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; + unsigned char *buf = info->xmit_buf; + int buflen; + int skb_res; + struct sk_buff *skb; + unsigned long flags; + + save_flags(flags); + cli(); + if (!(buflen = info->xmit_count)) { + restore_flags(flags); + 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; #ifdef CONFIG_ISDN_AUDIO - if (info->vonline & 2) { - /* For now, ifmt is fixed to 1 (alaw), since this - * is used with ISDN everywhere in the world, except - * US, Canada and Japan. - * Later, when US-ISDN protocols are implemented, - * this setting will depend on the D-channel protocol. - */ - int ifmt = 1; - int skb_len; - unsigned char hbuf[VBUF]; - - memcpy(hbuf,info->xmit_buf,buflen); - info->xmit_count = 0; - restore_flags(flags); - /* voice conversion/decompression */ - skb_len = buflen * voice_cf[info->emu.vpar[3]]; - skb = dev_alloc_skb(skb_len + skb_res); - if (!skb) { - printk(KERN_WARNING - "isdn_tty: Out of memory in ttyI%d senddown\n", info->line); - return; - } - skb_reserve(skb, skb_res); - switch (info->emu.vpar[3]) { - case 2: - case 3: - case 4: - /* adpcm, compatible to ZyXel 1496 modem - * with ROM revision 6.01 - */ - buflen = isdn_audio_adpcm2xlaw(info->adpcms, - ifmt, - hbuf, - skb_put(skb,skb_len), - buflen); - skb_trim(skb, buflen); - break; - case 5: - /* a-law */ - if (!ifmt) - isdn_audio_alaw2ulaw(hbuf,buflen); - memcpy(skb_put(skb,buflen),hbuf,buflen); - break; - case 6: - /* u-law */ - if (ifmt) - isdn_audio_ulaw2alaw(hbuf,buflen); - memcpy(skb_put(skb,buflen),hbuf,buflen); - break; - } - if (info->vonline & 4) { - info->vonline &= ~6; - if (!info->vonline) - isdn_tty_at_cout("\r\nVCON\r\n",info); - } - } else { -#endif /* CONFIG_ISDN_AUDIO */ - skb = dev_alloc_skb(buflen + skb_res); - if (!skb) { - printk(KERN_WARNING - "isdn_tty: Out of memory in ttyI%d senddown\n", info->line); - restore_flags(flags); - return; - } - skb_reserve(skb, skb_res); - memcpy(skb_put(skb,buflen),buf,buflen); - info->xmit_count = 0; - restore_flags(flags); + if (info->vonline & 2) { + /* For now, ifmt is fixed to 1 (alaw), since this + * is used with ISDN everywhere in the world, except + * US, Canada and Japan. + * Later, when US-ISDN protocols are implemented, + * this setting will depend on the D-channel protocol. + */ + int ifmt = 1; + int skb_len; + unsigned char hbuf[VBUF]; + + memcpy(hbuf, info->xmit_buf, buflen); + info->xmit_count = 0; + restore_flags(flags); + /* voice conversion/decompression */ + skb_len = buflen * voice_cf[info->emu.vpar[3]]; + skb = dev_alloc_skb(skb_len + skb_res); + if (!skb) { + printk(KERN_WARNING + "isdn_tty: Out of memory in ttyI%d senddown\n", info->line); + return; + } + skb_reserve(skb, skb_res); + switch (info->emu.vpar[3]) { + case 2: + case 3: + case 4: + /* adpcm, compatible to ZyXel 1496 modem + * with ROM revision 6.01 + */ + buflen = isdn_audio_adpcm2xlaw(info->adpcms, + ifmt, + hbuf, + skb_put(skb, skb_len), + buflen); + skb_trim(skb, buflen); + break; + case 5: + /* a-law */ + if (!ifmt) + isdn_audio_alaw2ulaw(hbuf, buflen); + memcpy(skb_put(skb, buflen), hbuf, buflen); + break; + case 6: + /* u-law */ + if (ifmt) + isdn_audio_ulaw2alaw(hbuf, buflen); + memcpy(skb_put(skb, buflen), hbuf, buflen); + break; + } + if (info->vonline & 4) { + info->vonline &= ~6; + if (!info->vonline) + isdn_tty_at_cout("\r\nVCON\r\n", info); + } + } else { +#endif /* CONFIG_ISDN_AUDIO */ + skb = dev_alloc_skb(buflen + skb_res); + if (!skb) { + printk(KERN_WARNING + "isdn_tty: Out of memory in ttyI%d senddown\n", info->line); + restore_flags(flags); + return; + } + skb_reserve(skb, skb_res); + memcpy(skb_put(skb, buflen), buf, buflen); + info->xmit_count = 0; + restore_flags(flags); #ifdef CONFIG_ISDN_AUDIO - } + } #endif - skb->free = 1; - if (info->emu.mdmreg[13] & 2) - /* Add T.70 simplified header */ - memcpy(skb_push(skb, 4), "\1\0\1\0", 4); - skb_queue_tail(&info->xmit_queue, skb); - if ((info->emu.mdmreg[12] & 0x10) != 0) - info->msr &= UART_MSR_CTS; - info->lsr &= UART_LSR_TEMT; + SET_SKB_FREE(skb); + if (info->emu.mdmreg[13] & 2) + /* Add T.70 simplified header */ + memcpy(skb_push(skb, 4), "\1\0\1\0", 4); + skb_queue_tail(&info->xmit_queue, skb); + if ((info->emu.mdmreg[12] & 0x10) != 0) + info->msr &= UART_MSR_CTS; + info->lsr &= UART_LSR_TEMT; } /************************************************************ @@ -512,53 +550,56 @@ * isdn_tty_modem_result() to stuff a "NO CARRIER" Message * into the tty's flip-buffer. */ -static void isdn_tty_modem_do_ncarrier(unsigned long data) +static void +isdn_tty_modem_do_ncarrier(unsigned long data) { - modem_info * info = (modem_info *)data; - isdn_tty_modem_result(3, info); + modem_info *info = (modem_info *) data; + isdn_tty_modem_result(3, info); } /* Next routine is called, whenever the DTR-signal is raised. * It checks the ncarrier-flag, and triggers the above routine * when necessary. The ncarrier-flag is set, whenever DTR goes * low. - */ -static void isdn_tty_modem_ncarrier(modem_info * info) + */ +static void +isdn_tty_modem_ncarrier(modem_info * info) { - if (info->ncarrier) { - info->ncarrier = 0; - info->nc_timer.expires = jiffies + HZ; - info->nc_timer.function = isdn_tty_modem_do_ncarrier; - info->nc_timer.data = (unsigned long)info; - add_timer(&info->nc_timer); - } + if (info->ncarrier) { + info->ncarrier = 0; + info->nc_timer.expires = jiffies + HZ; + info->nc_timer.function = isdn_tty_modem_do_ncarrier; + info->nc_timer.data = (unsigned long) info; + add_timer(&info->nc_timer); + } } /* isdn_tty_dial() performs dialing of a tty an the necessary * setup of the lower levels before that. */ -static void isdn_tty_dial(char *n, modem_info * info, atemu * m) +static void +isdn_tty_dial(char *n, modem_info * info, atemu * m) { - int usg = ISDN_USAGE_MODEM; - int si = 7; - int l2 = m->mdmreg[14]; + int usg = ISDN_USAGE_MODEM; + int si = 7; + int l2 = m->mdmreg[14]; isdn_ctrl cmd; ulong flags; int i; - int j; + int j; - for (j=7;j>=0;j--) - if (m->mdmreg[18] & (1<= 0; j--) + if (m->mdmreg[18] & (1 << j)) { + si = bit2si[j]; + break; + } #ifdef CONFIG_ISDN_AUDIO - if (si == 1) { - l2 = 4; - usg = ISDN_USAGE_VOICE; - } + if (si == 1) { + l2 = 4; + usg = ISDN_USAGE_VOICE; + } #endif - m->mdmreg[20] = si2bit[si]; + m->mdmreg[20] = si2bit[si]; save_flags(flags); cli(); i = isdn_get_free_channel(usg, l2, m->mdmreg[15], -1, -1); @@ -566,38 +607,44 @@ 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; - isdn_info_update(); - restore_flags(flags); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.command = ISDN_CMD_CLREAZ; - dev->drv[info->isdn_driver]->interface->command(&cmd); - strcpy(cmd.num, isdn_map_eaz2msn(m->msn, info->isdn_driver)); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETEAZ; - dev->drv[info->isdn_driver]->interface->command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL2; - cmd.arg = info->isdn_channel + (l2 << 8); - dev->drv[info->isdn_driver]->interface->command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL3; - cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8); - dev->drv[info->isdn_driver]->interface->command(&cmd); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - sprintf(cmd.num, "%s,%s,%d,%d", n, isdn_map_eaz2msn(m->msn, info->isdn_driver), - si, m->mdmreg[19]); - cmd.command = ISDN_CMD_DIAL; - info->dialing = 1; - strcpy(dev->num[i], n); - isdn_info_update(); - dev->drv[info->isdn_driver]->interface->command(&cmd); + 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; + dev->drv[info->isdn_driver]->interface->command(&cmd); + strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver)); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETEAZ; + dev->drv[info->isdn_driver]->interface->command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL2; + info->last_l2 = l2; + cmd.arg = info->isdn_channel + (l2 << 8); + dev->drv[info->isdn_driver]->interface->command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL3; + cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8); + dev->drv[info->isdn_driver]->interface->command(&cmd); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + sprintf(cmd.parm.setup.phone, "%s", n); + sprintf(cmd.parm.setup.eazmsn, "%s", + isdn_map_eaz2msn(m->msn, info->isdn_driver)); + cmd.parm.setup.si1 = si; + cmd.parm.setup.si2 = m->mdmreg[19]; + cmd.command = ISDN_CMD_DIAL; + info->dialing = 1; + strcpy(dev->num[i], n); + isdn_info_update(); + dev->drv[info->isdn_driver]->interface->command(&cmd); } } @@ -605,64 +652,69 @@ * ISDN-line (hangup). The usage-status is cleared * and some cleanup is done also. */ -void isdn_tty_modem_hup(modem_info * info) +void +isdn_tty_modem_hup(modem_info * info, int local) { isdn_ctrl cmd; - int usage; + int usage; - if (!info) - return; + if (!info) + return; #ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup ttyI%d\n", info->line); + printk(KERN_DEBUG "Mhup ttyI%d\n", info->line); #endif - info->rcvsched = 0; - info->online = 0; - isdn_tty_flush_buffer(info->tty); - if (info->vonline & 1) { - /* voice-recording, add DLE-ETX */ - isdn_tty_at_cout("\020\003", info); - } - if (info->vonline & 2) { - /* voice-playing, add DLE-DC4 */ - isdn_tty_at_cout("\020\024", info); - } - info->vonline = 0; + info->rcvsched = 0; + info->online = 0; + if (info->online || info->vonline) + info->last_lhup = local; + isdn_tty_flush_buffer(info->tty); + if (info->vonline & 1) { + /* voice-recording, add DLE-ETX */ + isdn_tty_at_cout("\020\003", info); + } + if (info->vonline & 2) { + /* voice-playing, add DLE-DC4 */ + isdn_tty_at_cout("\020\024", info); + } + info->vonline = 0; #ifdef CONFIG_ISDN_AUDIO - if (info->dtmf_state) { - kfree(info->dtmf_state); - info->dtmf_state = NULL; - } - if (info->adpcms) { - kfree(info->adpcms); - info->adpcms = NULL; - } - if (info->adpcmr) { - kfree(info->adpcmr); - info->adpcmr = NULL; - } + if (info->dtmf_state) { + kfree(info->dtmf_state); + info->dtmf_state = NULL; + } + if (info->adpcms) { + kfree(info->adpcms); + info->adpcms = NULL; + } + if (info->adpcmr) { + kfree(info->adpcmr); + info->adpcmr = NULL; + } #endif - info->msr &= ~(UART_MSR_DCD | UART_MSR_RI); - info->lsr |= UART_LSR_TEMT; + info->msr &= ~(UART_MSR_DCD | UART_MSR_RI); + info->lsr |= UART_LSR_TEMT; if (info->isdn_driver >= 0) { cmd.driver = info->isdn_driver; cmd.command = ISDN_CMD_HANGUP; cmd.arg = info->isdn_channel; dev->drv[info->isdn_driver]->interface->command(&cmd); isdn_all_eaz(info->isdn_driver, info->isdn_channel); - usage = (info->emu.mdmreg[20] == 1)? - ISDN_USAGE_VOICE:ISDN_USAGE_MODEM; + info->emu.mdmreg[1] = 0; + usage = (info->emu.mdmreg[20] == 1) ? + ISDN_USAGE_VOICE : ISDN_USAGE_MODEM; isdn_free_channel(info->isdn_driver, info->isdn_channel, - usage); + usage); } info->isdn_driver = -1; info->isdn_channel = -1; - if (info->drv_index >= 0) { - dev->m_idx[info->drv_index] = -1; - info->drv_index = -1; - } + if (info->drv_index >= 0) { + dev->m_idx[info->drv_index] = -1; + info->drv_index = -1; + } } -static inline int isdn_tty_paranoia_check(modem_info * info, kdev_t device, const char *routine) +static inline int +isdn_tty_paranoia_check(modem_info * info, kdev_t device, const char *routine) { #ifdef MODEM_PARANOIA_CHECK if (!info) { @@ -683,9 +735,13 @@ * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ -static void isdn_tty_change_speed(modem_info * info) +static void +isdn_tty_change_speed(modem_info * info) { - uint cflag, cval, fcr, quot; + uint cflag, + cval, + fcr, + quot; int i; if (!info->tty || !info->tty->termios) @@ -702,19 +758,19 @@ } if (quot) { info->mcr |= UART_MCR_DTR; - isdn_tty_modem_ncarrier(info); + isdn_tty_modem_ncarrier(info); } else { info->mcr &= ~UART_MCR_DTR; - if (info->emu.mdmreg[13] & 4) { + if (info->emu.mdmreg[13] & 4) { #ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in changespeed\n"); + printk(KERN_DEBUG "Mhup in changespeed\n"); #endif - if (info->online) - info->ncarrier = 1; - isdn_tty_modem_reset_regs(&info->emu, 0); - isdn_tty_modem_hup(info); - } - return; + if (info->online) + info->ncarrier = 1; + isdn_tty_modem_reset_regs(info, 0); + isdn_tty_modem_hup(info, 1); + } + return; } /* byte size and parity */ cval = cflag & (CSIZE | CSTOPB); @@ -737,7 +793,8 @@ } } -static int isdn_tty_startup(modem_info * info) +static int +isdn_tty_startup(modem_info * info) { ulong flags; @@ -745,12 +802,12 @@ return 0; save_flags(flags); cli(); - isdn_MOD_INC_USE_COUNT(); + isdn_MOD_INC_USE_COUNT(); #ifdef ISDN_DEBUG_MODEM_OPEN printk(KERN_DEBUG "starting up ttyi%d ...\n", info->line); #endif /* - * Now, initialize the UART + * Now, initialize the UART */ info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; if (info->tty) @@ -771,7 +828,8 @@ * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */ -static void isdn_tty_shutdown(modem_info * info) +static void +isdn_tty_shutdown(modem_info * info) { ulong flags; @@ -781,17 +839,18 @@ printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line); #endif save_flags(flags); - cli(); /* Disable interrupts */ - isdn_MOD_DEC_USE_COUNT(); + cli(); /* Disable interrupts */ + isdn_MOD_DEC_USE_COUNT(); + info->msr &= ~UART_MSR_RI; if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS); - if (info->emu.mdmreg[13] & 4) { - isdn_tty_modem_reset_regs(&info->emu, 0); + if (info->emu.mdmreg[13] & 4) { + isdn_tty_modem_reset_regs(info, 0); #ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n"); + printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n"); #endif - isdn_tty_modem_hup(info); - } + isdn_tty_modem_hup(info, 1); + } } if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); @@ -809,9 +868,11 @@ * - If receiving audio-data, call isdn_tty_end_vrx() to abort if needed. * - If dialing, abort dial. */ -static int isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int count) +static int +isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int count) { - int c, total = 0; + int c, + total = 0; ulong flags; modem_info *info = (modem_info *) tty->driver_data; @@ -819,70 +880,73 @@ return 0; if (!tty) return 0; - save_flags(flags); - cli(); + save_flags(flags); + cli(); while (1) { c = MIN(count, info->xmit_size - info->xmit_count); if (info->isdn_driver >= 0) c = MIN(c, dev->drv[info->isdn_driver]->maxbufsize); if (c <= 0) break; - if ((info->online > 1) || - (info->vonline & 2)) { - atemu *m = &info->emu; - - if (!(info->vonline & 2)) - isdn_tty_check_esc(buf, m->mdmreg[2], c, - &(m->pluscount), - &(m->lastplus), - from_user); - if (from_user) - copy_from_user(&(info->xmit_buf[info->xmit_count]), buf, c); - else - memcpy(&(info->xmit_buf[info->xmit_count]), buf, c); + if ((info->online > 1) || + (info->vonline & 2)) { + atemu *m = &info->emu; + + if (!(info->vonline & 2)) + isdn_tty_check_esc(buf, m->mdmreg[2], c, + &(m->pluscount), + &(m->lastplus), + from_user); + if (from_user) + copy_from_user(&(info->xmit_buf[info->xmit_count]), buf, c); + else + memcpy(&(info->xmit_buf[info->xmit_count]), buf, c); #ifdef CONFIG_ISDN_AUDIO - if (info->vonline & 2) { - int cc; + if (info->vonline & 2) { + int cc; - if (!(cc = isdn_tty_handleDLEdown(info,m,c))) { - /* If DLE decoding results in zero-transmit, but - * c originally was non-zero, do a wakeup. - */ - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); - wake_up_interruptible(&tty->write_wait); - info->msr |= UART_MSR_CTS; - info->lsr |= UART_LSR_TEMT; - } - info->xmit_count += cc; - } else + if (!(cc = isdn_tty_handleDLEdown(info, m, c))) { + /* If DLE decoding results in zero-transmit, but + * c originally was non-zero, do a wakeup. + */ + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup) (tty); + wake_up_interruptible(&tty->write_wait); + info->msr |= UART_MSR_CTS; + info->lsr |= UART_LSR_TEMT; + } + info->xmit_count += cc; + } else #endif - info->xmit_count += c; + info->xmit_count += c; if (m->mdmreg[13] & 1) { - isdn_tty_senddown(info); - isdn_tty_tint(info); - } + isdn_tty_senddown(info); + isdn_tty_tint(info); + } } else { - info->msr |= UART_MSR_CTS; - info->lsr |= UART_LSR_TEMT; + info->msr |= UART_MSR_CTS; + info->lsr |= UART_LSR_TEMT; #ifdef CONFIG_ISDN_AUDIO - if (info->vonline & 1) { - if (isdn_tty_end_vrx(buf, c, from_user)) { - info->vonline &= ~1; - isdn_tty_at_cout("\020\003\r\nVCON\r\n", info); - } - } else + if ((info->vonline & 3) == 1) { + /* Do NOT handle Ctrl-Q or Ctrl-S + * when in full-duplex audio mode. + */ + if (isdn_tty_end_vrx(buf, c, from_user)) { + info->vonline &= ~1; + isdn_tty_at_cout("\020\003\r\nVCON\r\n", info); + } + } else #endif - if (info->dialing) { - info->dialing = 0; + if (info->dialing) { + info->dialing = 0; #ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in isdn_tty_write\n"); + printk(KERN_DEBUG "Mhup in isdn_tty_write\n"); #endif - isdn_tty_modem_result(3, info); - isdn_tty_modem_hup(info); - } else - c = isdn_tty_edit_at(buf, c, info, from_user); + isdn_tty_modem_result(3, info); + isdn_tty_modem_hup(info, 1); + } else + c = isdn_tty_edit_at(buf, c, info, from_user); } buf += c; count -= c; @@ -890,11 +954,12 @@ } if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1); - restore_flags(flags); + restore_flags(flags); return total; } -static int isdn_tty_write_room(struct tty_struct *tty) +static int +isdn_tty_write_room(struct tty_struct *tty) { modem_info *info = (modem_info *) tty->driver_data; int ret; @@ -907,7 +972,8 @@ return (ret < 0) ? 0 : ret; } -static int isdn_tty_chars_in_buffer(struct tty_struct *tty) +static int +isdn_tty_chars_in_buffer(struct tty_struct *tty) { modem_info *info = (modem_info *) tty->driver_data; @@ -918,32 +984,34 @@ return (info->xmit_count); } -static void isdn_tty_flush_buffer(struct tty_struct *tty) +static void +isdn_tty_flush_buffer(struct tty_struct *tty) { modem_info *info; - unsigned long flags; + unsigned long flags; - save_flags(flags); - cli(); - if (!tty) { - restore_flags(flags); - return; - } - info = (modem_info *) tty->driver_data; + save_flags(flags); + cli(); + if (!tty) { + restore_flags(flags); + return; + } + info = (modem_info *) tty->driver_data; if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_buffer")) { - restore_flags(flags); + restore_flags(flags); return; - } - isdn_tty_cleanup_xmit(info); - info->xmit_count = 0; - restore_flags(flags); + } + isdn_tty_cleanup_xmit(info); + info->xmit_count = 0; + restore_flags(flags); wake_up_interruptible(&tty->write_wait); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup) (tty); } -static void isdn_tty_flush_chars(struct tty_struct *tty) +static void +isdn_tty_flush_chars(struct tty_struct *tty) { modem_info *info = (modem_info *) tty->driver_data; @@ -956,12 +1024,13 @@ /* * ------------------------------------------------------------ * isdn_tty_throttle() - * + * * This routine is called by the upper-layer tty layer to signal that * incoming characters should be throttled. * ------------------------------------------------------------ */ -static void isdn_tty_throttle(struct tty_struct *tty) +static void +isdn_tty_throttle(struct tty_struct *tty) { modem_info *info = (modem_info *) tty->driver_data; @@ -972,7 +1041,8 @@ info->mcr &= ~UART_MCR_RTS; } -static void isdn_tty_unthrottle(struct tty_struct *tty) +static void +isdn_tty_unthrottle(struct tty_struct *tty) { modem_info *info = (modem_info *) tty->driver_data; @@ -1001,9 +1071,10 @@ * release the bus after transmitting. This must be done when * the transmit shift register is empty, not be done when the * transmit holding register is empty. This functionality - * allows RS485 driver to be written in user space. + * allows RS485 driver to be written in user space. */ -static int isdn_tty_get_lsr_info(modem_info * info, uint * value) +static int +isdn_tty_get_lsr_info(modem_info * info, uint * value) { u_char status; uint result; @@ -1014,13 +1085,16 @@ status = info->lsr; restore_flags(flags); result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); - return put_user(result, value); + put_user(result, (ulong *) value); + return 0; } -static int isdn_tty_get_modem_info(modem_info * info, uint * value) +static int +isdn_tty_get_modem_info(modem_info * info, uint * value) { - u_char control, status; + u_char control, + status; uint result; ulong flags; @@ -1035,83 +1109,82 @@ | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); - return put_user(result, value); + put_user(result, (ulong *) value); + return 0; } -static int isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value) +static int +isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value) { uint arg; - int pre_dtr; - int error; - - error = get_user(arg, ((uint *) value)); - if (error) - return error; + int pre_dtr; + GET_USER(arg, (uint *) value); switch (cmd) { - case TIOCMBIS: + case TIOCMBIS: #ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIS\n", info->line); + printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIS\n", info->line); #endif - if (arg & TIOCM_RTS) { - info->mcr |= UART_MCR_RTS; - } - if (arg & TIOCM_DTR) { - info->mcr |= UART_MCR_DTR; - isdn_tty_modem_ncarrier(info); - } - break; - case TIOCMBIC: + if (arg & TIOCM_RTS) { + info->mcr |= UART_MCR_RTS; + } + if (arg & TIOCM_DTR) { + info->mcr |= UART_MCR_DTR; + isdn_tty_modem_ncarrier(info); + } + break; + case TIOCMBIC: #ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIC\n", info->line); + printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIC\n", info->line); #endif - if (arg & TIOCM_RTS) { - info->mcr &= ~UART_MCR_RTS; - } - if (arg & TIOCM_DTR) { - info->mcr &= ~UART_MCR_DTR; - if (info->emu.mdmreg[13] & 4) { - isdn_tty_modem_reset_regs(&info->emu, 0); + if (arg & TIOCM_RTS) { + info->mcr &= ~UART_MCR_RTS; + } + if (arg & TIOCM_DTR) { + info->mcr &= ~UART_MCR_DTR; + if (info->emu.mdmreg[13] & 4) { + isdn_tty_modem_reset_regs(info, 0); #ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in TIOCMBIC\n"); + printk(KERN_DEBUG "Mhup in TIOCMBIC\n"); #endif - if (info->online) - info->ncarrier = 1; - isdn_tty_modem_hup(info); - } - } - break; - case TIOCMSET: + if (info->online) + info->ncarrier = 1; + isdn_tty_modem_hup(info, 1); + } + } + break; + case TIOCMSET: #ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TIOCMSET\n", info->line); + printk(KERN_DEBUG "ttyI%d ioctl TIOCMSET\n", info->line); #endif - pre_dtr = (info->mcr & UART_MCR_DTR); - info->mcr = ((info->mcr & ~(UART_MCR_RTS | UART_MCR_DTR)) - | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) - | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); - if (pre_dtr |= (info->mcr & UART_MCR_DTR)) { - if (!(info->mcr & UART_MCR_DTR)) { - if (info->emu.mdmreg[13] & 4) { - isdn_tty_modem_reset_regs(&info->emu, 0); + pre_dtr = (info->mcr & UART_MCR_DTR); + info->mcr = ((info->mcr & ~(UART_MCR_RTS | UART_MCR_DTR)) + | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) + | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); + if (pre_dtr |= (info->mcr & UART_MCR_DTR)) { + if (!(info->mcr & UART_MCR_DTR)) { + if (info->emu.mdmreg[13] & 4) { + isdn_tty_modem_reset_regs(info, 0); #ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in TIOCMSET\n"); + printk(KERN_DEBUG "Mhup in TIOCMSET\n"); #endif - if (info->online) - info->ncarrier = 1; - isdn_tty_modem_hup(info); - } - } else - isdn_tty_modem_ncarrier(info); - } - break; - default: - return -EINVAL; + if (info->online) + info->ncarrier = 1; + isdn_tty_modem_hup(info, 1); + } + } else + isdn_tty_modem_ncarrier(info); + } + break; + default: + return -EINVAL; } return 0; } -static int isdn_tty_ioctl(struct tty_struct *tty, struct file *file, - uint cmd, ulong arg) +static int +isdn_tty_ioctl(struct tty_struct *tty, struct file *file, + uint cmd, ulong arg) { modem_info *info = (modem_info *) tty->driver_data; int error; @@ -1119,82 +1192,98 @@ if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_ioctl")) return -ENODEV; - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; switch (cmd) { - case TCSBRK: /* SVID version: non-zero arg --> no break */ + case TCSBRK: /* SVID version: non-zero arg --> no break */ #ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TCSBRK\n", info->line); + printk(KERN_DEBUG "ttyI%d ioctl TCSBRK\n", info->line); #endif - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ #ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TCSBRKP\n", info->line); + printk(KERN_DEBUG "ttyI%d ioctl TCSBRKP\n", info->line); #endif - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - return 0; - case TIOCGSOFTCAR: + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + return 0; + case TIOCGSOFTCAR: #ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line); + printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line); #endif - return put_user(C_CLOCAL(tty) ? 1 : 0, (uint *) arg); - case TIOCSSOFTCAR: + error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long)); + if (error) + return error; + put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg); + return 0; + case TIOCSSOFTCAR: #ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line); + printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line); #endif - error = get_user(arg ,((uint *) arg)); + error = verify_area(VERIFY_READ, (void *) arg, sizeof(long)); if (error) return error; - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - return 0; - case TIOCMGET: + GET_USER(arg, (ulong *) arg); + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + return 0; + case TIOCMGET: #ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line); + printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line); #endif - return isdn_tty_get_modem_info(info, (uint *) arg); - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - return isdn_tty_set_modem_info(info, cmd, (uint *) arg); - case TIOCSERGETLSR: /* Get line status register */ + error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint)); + if (error) + return error; + return isdn_tty_get_modem_info(info, (uint *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + error = verify_area(VERIFY_READ, (void *) arg, sizeof(uint)); + if (error) + return error; + return isdn_tty_set_modem_info(info, cmd, (uint *) arg); + case TIOCSERGETLSR: /* Get line status register */ #ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line); + printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line); #endif - return isdn_tty_get_lsr_info(info, (uint *) arg); - - default: + error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint)); + if (error) + return error; + else + return isdn_tty_get_lsr_info(info, (uint *) arg); + + default: #ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line); + printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line); #endif - return -ENOIOCTLCMD; + return -ENOIOCTLCMD; } return 0; } -static void isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios) +static void +isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios) { modem_info *info = (modem_info *) tty->driver_data; - if (!old_termios) - isdn_tty_change_speed(info); - else { - if (tty->termios->c_cflag == old_termios->c_cflag) - return; - isdn_tty_change_speed(info); - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->hw_stopped = 0; - } - } + if (!old_termios) + isdn_tty_change_speed(info); + else { + if (tty->termios->c_cflag == old_termios->c_cflag) + return; + isdn_tty_change_speed(info); + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + } + } } /* @@ -1202,9 +1291,11 @@ * isdn_tty_open() and friends * ------------------------------------------------------------ */ -static int isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info) +static int +isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info) { - struct wait_queue wait = {current, NULL}; + struct wait_queue wait = + {current, NULL}; int do_clocal = 0; unsigned long flags; int retval; @@ -1215,8 +1306,8 @@ */ if (tty_hung_up_p(filp) || (info->flags & ISDN_ASYNC_CLOSING)) { - if (info->flags & ISDN_ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); + if (info->flags & ISDN_ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); #ifdef MODEM_DO_RESTART if (info->flags & ISDN_ASYNC_HUP_NOTIFY) return -EAGAIN; @@ -1249,7 +1340,7 @@ * and then exit. */ if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { + (tty->flags & (1 << TTY_IO_ERROR))) { if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) return -EBUSY; info->flags |= ISDN_ASYNC_NORMAL_ACTIVE; @@ -1275,11 +1366,11 @@ printk(KERN_DEBUG "isdn_tty_block_til_ready before block: ttyi%d, count = %d\n", info->line, info->count); #endif - save_flags(flags); - cli(); - if (!(tty_hung_up_p(filp))) - info->count--; - restore_flags(flags); + save_flags(flags); + cli(); + if (!(tty_hung_up_p(filp))) + info->count--; + restore_flags(flags); info->blocked_open++; while (1) { current->state = TASK_INTERRUPTIBLE; @@ -1331,10 +1422,12 @@ * the IRQ chain. It also performs the serial-specific * initialization for the tty structure. */ -static int isdn_tty_open(struct tty_struct *tty, struct file *filp) +static int +isdn_tty_open(struct tty_struct *tty, struct file *filp) { modem_info *info; - int retval, line; + int retval, + line; line = MINOR(tty->device) - tty->driver.minor_start; if (line < 0 || line > ISDN_MAX_CHANNELS) @@ -1385,7 +1478,8 @@ return 0; } -static void isdn_tty_close(struct tty_struct *tty, struct file *filp) +static void +isdn_tty_close(struct tty_struct *tty, struct file *filp) { modem_info *info = (modem_info *) tty->driver_data; ulong flags; @@ -1436,7 +1530,7 @@ if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) info->callout_termios = *tty->termios; - tty->closing = 1; + tty->closing = 1; /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and tell the @@ -1444,7 +1538,7 @@ * line status register. */ if (info->flags & ISDN_ASYNC_INITIALIZED) { - tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ + tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially @@ -1466,12 +1560,12 @@ if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); info->tty = 0; - info->ncarrier = 0; + info->ncarrier = 0; tty->closing = 0; if (info->blocked_open) { - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 50; - schedule(); + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + 50; + schedule(); wake_up_interruptible(&info->open_wait); } info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE | @@ -1486,7 +1580,8 @@ /* * isdn_tty_hangup() --- called by tty_hangup() when a hangup is signaled. */ -static void isdn_tty_hangup(struct tty_struct *tty) +static void +isdn_tty_hangup(struct tty_struct *tty) { modem_info *info = (modem_info *) tty->driver_data; @@ -1501,7 +1596,8 @@ /* This routine initializes all emulator-data. */ -static void isdn_tty_reset_profile(atemu * m) +static void +isdn_tty_reset_profile(atemu * m) { m->profile[0] = 0; m->profile[1] = 0; @@ -1527,25 +1623,30 @@ m->pmsn[0] = '\0'; } -static void isdn_tty_modem_reset_vpar(atemu *m) +static void +isdn_tty_modem_reset_vpar(atemu * m) { - m->vpar[0] = 2; /* Voice-device (2 = phone line) */ - m->vpar[1] = 0; /* Silence detection level (0 = none ) */ - m->vpar[2] = 70; /* Silence interval (7 sec. ) */ - m->vpar[3] = 2; /* Compression type (1 = ADPCM-2 ) */ + m->vpar[0] = 2; /* Voice-device (2 = phone line) */ + m->vpar[1] = 0; /* Silence detection level (0 = none ) */ + m->vpar[2] = 70; /* Silence interval (7 sec. ) */ + m->vpar[3] = 2; /* Compression type (1 = ADPCM-2 ) */ } -static void isdn_tty_modem_reset_regs(atemu * m, int force) +static void +isdn_tty_modem_reset_regs(modem_info * info, int force) { + atemu *m = &info->emu; if ((m->mdmreg[12] & 32) || force) { memcpy(m->mdmreg, m->profile, ISDN_MODEM_ANZREG); memcpy(m->msn, m->pmsn, ISDN_MSNLEN); + info->xmit_size = m->mdmreg[16] * 16; } - isdn_tty_modem_reset_vpar(m); + isdn_tty_modem_reset_vpar(m); m->mdmcmdl = 0; } -static void modem_write_profile(atemu * m) +static void +modem_write_profile(atemu * m) { memcpy(m->profile, m->mdmreg, ISDN_MODEM_ANZREG); memcpy(m->pmsn, m->msn, ISDN_MSNLEN); @@ -1553,7 +1654,8 @@ send_sig(SIGIO, dev->profd, 1); } -int isdn_tty_modem_init(void) +int +isdn_tty_modem_init(void) { modem *m; int i; @@ -1610,8 +1712,14 @@ } for (i = 0; i < ISDN_MAX_CHANNELS; i++) { info = &m->info[i]; + sprintf(info->last_cause, "0000"); + sprintf(info->last_num, "none"); + info->last_dir = 0; + info->last_lhup = 1; + info->last_l2 = 0; + info->last_si = 0; isdn_tty_reset_profile(&info->emu); - isdn_tty_modem_reset_regs(&info->emu, 1); + isdn_tty_modem_reset_regs(info, 1); info->magic = ISDN_ASYNC_MAGIC; info->line = i; info->tty = 0; @@ -1626,14 +1734,14 @@ info->isdn_channel = -1; info->drv_index = -1; info->xmit_size = ISDN_SERIAL_XMIT_SIZE; - skb_queue_head_init(&info->xmit_queue); - skb_queue_head_init(&info->dtmf_queue); - if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_SIZE + 5, GFP_KERNEL))) { - printk(KERN_ERR "Could not allocate modem xmit-buffer\n"); - return -3; - } - /* Make room for T.70 header */ - info->xmit_buf += 4; + skb_queue_head_init(&info->xmit_queue); + skb_queue_head_init(&info->dtmf_queue); + if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_SIZE + 5, GFP_KERNEL))) { + printk(KERN_ERR "Could not allocate modem xmit-buffer\n"); + return -3; + } + /* Make room for T.70 header */ + info->xmit_buf += 4; } return 0; } @@ -1644,61 +1752,46 @@ * it to the ISDN-Channel. * Return Index to dev->mdm or -1 if none found. */ -int isdn_tty_find_icall(int di, int ch, char *num) +int +isdn_tty_find_icall(int di, int ch, setup_parm setup) { char *eaz; int i; int idx; int si1; int si2; - char *s; - char nr[31]; + char nr[32]; ulong flags; save_flags(flags); cli(); - if (num[0] == ',') { + if (!setup.phone[0]) { nr[0] = '0'; - strncpy(&nr[1], num, 29); + nr[1] = '\0'; printk(KERN_INFO "isdn_tty: Incoming call without OAD, assuming '0'\n"); } else - strncpy(nr, num, 30); - s = strtok(nr, ","); - s = strtok(NULL, ","); - if (!s) { - printk(KERN_WARNING "isdn_tty: Incoming callinfo garbled, ignored: %s\n", - num); - restore_flags(flags); - return -1; - } - si1 = (int)simple_strtoul(s,NULL,10); - s = strtok(NULL, ","); - if (!s) { - printk(KERN_WARNING "isdn_tty: Incoming callinfo garbled, ignored: %s\n", - num); - restore_flags(flags); - return -1; - } - si2 = (int)simple_strtoul(s,NULL,10); - eaz = strtok(NULL, ","); - if (!eaz) { + strcpy(nr, setup.phone); + si1 = (int) setup.si1; + si2 = (int) setup.si2; + if (!setup.eazmsn[0]) { printk(KERN_WARNING "isdn_tty: Incoming call without CPN, assuming '0'\n"); eaz = "0"; - } + } else + eaz = setup.eazmsn; #ifdef ISDN_DEBUG_MODEM_ICALL printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2); #endif for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - modem_info *info = &dev->mdm.info[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[18], info->emu.mdmreg[19]); #endif if ((!strcmp(isdn_map_eaz2msn(info->emu.msn, di), - eaz)) && /* EAZ is matching */ - (info->emu.mdmreg[18] & si2bit[si1]) && /* SI1 is matching */ - ((info->emu.mdmreg[19] == si2) || !si2)) { /* SI2 is matching or 0 */ + eaz)) && /* EAZ is matching */ + (info->emu.mdmreg[18] & si2bit[si1]) && /* SI1 is matching */ + ((info->emu.mdmreg[19] == si2) || !si2)) { /* SI2 is matching or 0 */ idx = isdn_dc2minor(di, ch); #ifdef ISDN_DEBUG_MODEM_ICALL printk(KERN_DEBUG "m_fi: match1\n"); @@ -1715,9 +1808,11 @@ 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; + dev->usage[idx] |= (si1 == 1) ? ISDN_USAGE_VOICE : ISDN_USAGE_MODEM; strcpy(dev->num[idx], nr); - info->emu.mdmreg[20] = si2bit[si1]; + info->emu.mdmreg[20] = si2bit[si1]; + info->emu.mdmreg[21] = setup.plan; + info->emu.mdmreg[22] = setup.screen; isdn_info_update(); restore_flags(flags); printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr, @@ -1742,7 +1837,8 @@ * Put a message from the AT-emulator into receive-buffer of tty, * convert CR, LF, and BS to values in modem-registers 3, 4 and 5. */ -static void isdn_tty_at_cout(char *msg, modem_info * info) +static void +isdn_tty_at_cout(char *msg, modem_info * info) { struct tty_struct *tty; atemu *m = &info->emu; @@ -1759,17 +1855,17 @@ tty = info->tty; for (p = msg; *p; p++) { switch (*p) { - case '\r': - c = m->mdmreg[3]; - break; - case '\n': - c = m->mdmreg[4]; - break; - case '\b': - c = m->mdmreg[5]; - break; - default: - c = *p; + case '\r': + c = m->mdmreg[3]; + break; + case '\n': + c = m->mdmreg[4]; + break; + case '\b': + c = m->mdmreg[5]; + break; + default: + c = *p; } if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) { restore_flags(flags); @@ -1786,24 +1882,26 @@ /* * Perform ATH Hangup */ -static void isdn_tty_on_hook(modem_info * info) +static void +isdn_tty_on_hook(modem_info * info) { if (info->isdn_channel >= 0) { #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n"); #endif isdn_tty_modem_result(3, info); - isdn_tty_modem_hup(info); + isdn_tty_modem_hup(info, 1); } } -static void isdn_tty_off_hook(void) +static void +isdn_tty_off_hook(void) { printk(KERN_DEBUG "isdn_tty_off_hook\n"); } -#define PLUSWAIT1 (HZ/2) /* 0.5 sec. */ -#define PLUSWAIT2 (HZ*3/2) /* 1.5 sec */ +#define PLUSWAIT1 (HZ/2) /* 0.5 sec. */ +#define PLUSWAIT2 (HZ*3/2) /* 1.5 sec */ /* * Check Buffer for Modem-escape-sequence, activate timer-callback to @@ -1816,8 +1914,9 @@ * pluscount count of valid escape-characters so far * lastplus timestamp of last character */ -static void isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pluscount, - int *lastplus, int from_user) +static void +isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pluscount, + int *lastplus, int from_user) { char cbuf[3]; @@ -1860,7 +1959,8 @@ * For CONNECT-messages also switch to online-mode. * For RING-message handle auto-ATA if register 0 != 0 */ -void isdn_tty_modem_result(int code, modem_info * info) +void +isdn_tty_modem_result(int code, modem_info * info) { atemu *m = &info->emu; static char *msg[] = @@ -1868,47 +1968,50 @@ "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER", "RINGING", "NO MSN/EAZ", "VCON"}; ulong flags; - char s[4]; + char s[10]; switch (code) { - case 2: - m->mdmreg[1]++; /* RING */ - if (m->mdmreg[1] == m->mdmreg[0]) - /* Automatically accept incoming call */ - isdn_tty_cmd_ATA(info); - break; - case 3: - /* NO CARRIER */ - save_flags(flags); - cli(); + case 2: + m->mdmreg[1]++; /* RING */ + if (m->mdmreg[1] == m->mdmreg[0]) + /* Automatically accept incoming call */ + isdn_tty_cmd_ATA(info); + break; + case 3: + /* NO CARRIER */ + save_flags(flags); + cli(); + m->mdmreg[1] = 0; #ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n", - (info->flags & ISDN_ASYNC_CLOSING), - (!info->tty)); -#endif - if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) { - restore_flags(flags); - return; - } - restore_flags(flags); - if (info->vonline & 1) { - /* voice-recording, add DLE-ETX */ - isdn_tty_at_cout("\020\003", info); - } - if (info->vonline & 2) { - /* voice-playing, add DLE-DC4 */ - isdn_tty_at_cout("\020\024", info); - } - break; - case 1: - case 5: - if (!info->online) - info->online = 2; - break; - case 11: - if (!info->online) - info->online = 1; - break; + printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n", + (info->flags & ISDN_ASYNC_CLOSING), + (!info->tty)); +#endif + if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) { + restore_flags(flags); + return; + } + restore_flags(flags); + if (info->vonline & 1) { + /* voice-recording, add DLE-ETX */ + isdn_tty_at_cout("\020\003", info); + } + if (info->vonline & 2) { + /* voice-playing, add DLE-DC4 */ + isdn_tty_at_cout("\020\024", info); + } + break; + case 1: + case 5: + sprintf(info->last_cause, "0000"); + if (!info->online) + info->online = 2; + break; + case 11: + sprintf(info->last_cause, "0000"); + if (!info->online) + info->online = 1; + break; } if (m->mdmreg[12] & 1) { /* Show results */ @@ -1918,17 +2021,38 @@ sprintf(s, "%d", code); isdn_tty_at_cout(s, info); } else { - if (code == 2) { + if ((code == 2) && (!(m->mdmreg[13] & 16))) { isdn_tty_at_cout("CALLER NUMBER: ", info); isdn_tty_at_cout(dev->num[info->drv_index], info); isdn_tty_at_cout("\r\n", info); } isdn_tty_at_cout(msg[code], info); - if (code == 5) { - /* Append Protocol to CONNECT message */ - isdn_tty_at_cout((m->mdmreg[14] != 3) ? "/X.75" : "/HDLC", info); - if (m->mdmreg[13] & 2) - isdn_tty_at_cout("/T.70", info); + switch (code) { + case 2: + /* Print CID only once, _after_ 1.st RING */ + if ((m->mdmreg[13] & 16) && (m->mdmreg[1] == 1)) { + isdn_tty_at_cout("\r\n", info); + isdn_tty_at_cout("CALLER NUMBER: ", info); + isdn_tty_at_cout(dev->num[info->drv_index], info); + } + break; + case 3: + case 6: + case 7: + case 8: + m->mdmreg[1] = 0; + /* Append Cause-Message if enabled */ + if (m->mdmreg[13] & 8) { + sprintf(s, "/%s", info->last_cause); + isdn_tty_at_cout(s, info); + } + break; + case 5: + /* Append Protocol to CONNECT message */ + isdn_tty_at_cout((m->mdmreg[14] != 3) ? "/X.75" : "/HDLC", info); + if (m->mdmreg[13] & 2) + isdn_tty_at_cout("/T.70", info); + break; } } isdn_tty_at_cout("\r\n", info); @@ -1940,13 +2064,13 @@ restore_flags(flags); return; } - if (info->tty->ldisc.flush_buffer) - info->tty->ldisc.flush_buffer(info->tty); + if (info->tty->ldisc.flush_buffer) + info->tty->ldisc.flush_buffer(info->tty); if ((info->flags & ISDN_ASYNC_CHECK_CD) && (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) && (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) { tty_hangup(info->tty); - } + } restore_flags(flags); } } @@ -1954,7 +2078,8 @@ /* * Display a modem-register-value. */ -static void isdn_tty_show_profile(int ridx, modem_info * info) +static void +isdn_tty_show_profile(int ridx, modem_info * info) { char v[6]; @@ -1965,7 +2090,8 @@ /* * Get MSN-string from char-pointer, set pointer to end of number */ -static void isdn_tty_get_msnstr(char *n, char **p) +static void +isdn_tty_get_msnstr(char *n, char **p) { while ((*p[0] >= '0' && *p[0] <= '9') || (*p[0] == ',')) *n++ = *p[0]++; @@ -1975,7 +2101,8 @@ /* * Get phone-number from modem-commandbuffer */ -static void isdn_tty_getdial(char *p, char *q) +static void +isdn_tty_getdial(char *p, char *q) { int first = 1; @@ -1991,648 +2118,724 @@ #define PARSE_ERROR { isdn_tty_modem_result(4, info); return; } #define PARSE_ERROR1 { isdn_tty_modem_result(4, info); return 1; } +static void +isdn_tty_report(modem_info * info) +{ + atemu *m = &info->emu; + char s[80]; + + isdn_tty_at_cout("\r\nStatistics of last connection:\r\n\r\n", info); + sprintf(s, " Remote Number: %s\r\n", info->last_num); + isdn_tty_at_cout(s, info); + sprintf(s, " Direction: %s\r\n", info->last_dir ? "outgoing" : "incoming"); + isdn_tty_at_cout(s, info); + isdn_tty_at_cout(" Layer-2 Protocol: ", info); + switch (info->last_l2) { + case ISDN_PROTO_L2_X75I: + isdn_tty_at_cout("x75i", info); + break; + case ISDN_PROTO_L2_X75UI: + isdn_tty_at_cout("x75ui", info); + break; + case ISDN_PROTO_L2_X75BUI: + isdn_tty_at_cout("x75bui", info); + break; + case ISDN_PROTO_L2_HDLC: + isdn_tty_at_cout("hdlc", info); + break; + case ISDN_PROTO_L2_TRANS: + isdn_tty_at_cout("transparent", info); + break; + default: + isdn_tty_at_cout("unknown", info); + break; + } + isdn_tty_at_cout((m->mdmreg[13] & 2) ? "/t.70\r\n" : "\r\n", info); + isdn_tty_at_cout(" Service: ", info); + switch (info->last_si) { + case 1: + isdn_tty_at_cout("audio\r\n", info); + break; + case 5: + isdn_tty_at_cout("btx\r\n", info); + break; + case 7: + isdn_tty_at_cout("data\r\n", info); + break; + default: + sprintf(s, "%d\r\n", info->last_si); + isdn_tty_at_cout(s, info); + break; + } + sprintf(s, " Hangup location: %s\r\n", info->last_lhup ? "local" : "remote"); + isdn_tty_at_cout(s, info); + sprintf(s, " Last cause: %s\r\n", info->last_cause); + isdn_tty_at_cout(s, info); +} + /* * Parse AT&.. commands. */ -static int isdn_tty_cmd_ATand(char **p, modem_info * info) +static int +isdn_tty_cmd_ATand(char **p, modem_info * info) { - atemu *m = &info->emu; - int i; - char rb[100]; - - switch (*p[0]) { - case 'B': - /* &B - Set Buffersize */ - p[0]++; - i = isdn_getnum(p); - if ((i < 0) || (i > ISDN_SERIAL_XMIT_SIZE)) - PARSE_ERROR1; + atemu *m = &info->emu; + int i; + char rb[100]; + + switch (*p[0]) { + case 'B': + /* &B - Set Buffersize */ + p[0]++; + i = isdn_getnum(p); + if ((i < 0) || (i > ISDN_SERIAL_XMIT_SIZE)) + PARSE_ERROR1; #ifdef CONFIG_ISDN_AUDIO - if ((m->mdmreg[18] & 1) && (i > VBUF)) - PARSE_ERROR1; + if ((m->mdmreg[18] & 1) && (i > VBUF)) + PARSE_ERROR1; #endif - m->mdmreg[16] = i / 16; - info->xmit_size = m->mdmreg[16] * 16; - break; - case 'D': - /* &D - Set DCD-Low-behavior */ - p[0]++; - switch (isdn_getnum(p)) { - case 0: - m->mdmreg[13] &= ~4; - m->mdmreg[12] &= ~32; - break; - case 2: - m->mdmreg[13] |= 4; - m->mdmreg[12] &= ~32; - break; - case 3: - m->mdmreg[13] |= 4; - m->mdmreg[12] |= 32; - break; - default: - PARSE_ERROR1 - } - break; - case 'E': - /* &E -Set EAZ/MSN */ - p[0]++; - isdn_tty_get_msnstr(m->msn, p); - break; - case 'F': - /* &F -Set Factory-Defaults */ - p[0]++; - isdn_tty_reset_profile(m); - isdn_tty_modem_reset_regs(m, 1); - break; - case 'S': - /* &S - Set Windowsize */ - p[0]++; - i = isdn_getnum(p); - if ((i > 0) && (i < 9)) - m->mdmreg[17] = i; - else - PARSE_ERROR1; - break; - case 'V': - /* &V - Show registers */ - p[0]++; - for (i = 0; i < ISDN_MODEM_ANZREG; i++) { - sprintf(rb, "S%d=%d%s", i, - m->mdmreg[i], (i == 6) ? "\r\n" : " "); - isdn_tty_at_cout(rb, info); - } - sprintf(rb, "\r\nEAZ/MSN: %s\r\n", - strlen(m->msn) ? m->msn : "None"); - isdn_tty_at_cout(rb, info); - break; - case 'W': - /* &W - Write Profile */ - p[0]++; - switch (*p[0]) { - case '0': - p[0]++; - modem_write_profile(m); - break; - default: - PARSE_ERROR1; - } - break; - case 'X': - /* &X - Switch to BTX-Mode */ - p[0]++; - switch (isdn_getnum(p)) { - case 0: - m->mdmreg[13] &= ~2; - info->xmit_size = m->mdmreg[16] * 16; - break; - case 1: - m->mdmreg[13] |= 2; - m->mdmreg[14] = 0; - info->xmit_size = 112; - m->mdmreg[18] = 4; - m->mdmreg[19] = 0; - break; - default: - PARSE_ERROR1; - } - break; - default: - PARSE_ERROR1; - } - return 0; + m->mdmreg[16] = i / 16; + info->xmit_size = m->mdmreg[16] * 16; + break; + case 'D': + /* &D - Set DCD-Low-behavior */ + p[0]++; + switch (isdn_getnum(p)) { + case 0: + m->mdmreg[13] &= ~4; + m->mdmreg[12] &= ~32; + break; + case 2: + m->mdmreg[13] |= 4; + m->mdmreg[12] &= ~32; + break; + case 3: + m->mdmreg[13] |= 4; + m->mdmreg[12] |= 32; + break; + default: + PARSE_ERROR1 + } + break; + case 'E': + /* &E -Set EAZ/MSN */ + p[0]++; + isdn_tty_get_msnstr(m->msn, p); + break; + case 'F': + /* &F -Set Factory-Defaults */ + p[0]++; + isdn_tty_reset_profile(m); + isdn_tty_modem_reset_regs(info, 1); + break; + case 'S': + /* &S - Set Windowsize */ + p[0]++; + i = isdn_getnum(p); + if ((i > 0) && (i < 9)) + m->mdmreg[17] = i; + else + PARSE_ERROR1; + break; + case 'V': + /* &V - Show registers */ + p[0]++; + for (i = 0; i < ISDN_MODEM_ANZREG; i++) { + sprintf(rb, "S%d=%d%s", i, + m->mdmreg[i], (i == 6) ? "\r\n" : " "); + isdn_tty_at_cout(rb, info); + } + sprintf(rb, "\r\nEAZ/MSN: %s\r\n", + strlen(m->msn) ? m->msn : "None"); + isdn_tty_at_cout(rb, info); + break; + case 'W': + /* &W - Write Profile */ + p[0]++; + switch (*p[0]) { + case '0': + p[0]++; + modem_write_profile(m); + break; + default: + PARSE_ERROR1; + } + break; + case 'X': + /* &X - Switch to BTX-Mode */ + p[0]++; + switch (isdn_getnum(p)) { + case 0: + m->mdmreg[13] &= ~2; + info->xmit_size = m->mdmreg[16] * 16; + break; + case 1: + m->mdmreg[13] |= 2; + m->mdmreg[14] = 0; + info->xmit_size = 112; + m->mdmreg[18] = 4; + m->mdmreg[19] = 0; + break; + default: + PARSE_ERROR1; + } + break; + default: + PARSE_ERROR1; + } + return 0; } /* * Perform ATS command */ -static int isdn_tty_cmd_ATS(char **p, modem_info * info) +static int +isdn_tty_cmd_ATS(char **p, modem_info * info) { - atemu *m = &info->emu; - int mreg; - int mval; - - mreg = isdn_getnum(p); - if (mreg < 0 || mreg > ISDN_MODEM_ANZREG) - PARSE_ERROR1; - switch (*p[0]) { - case '=': - p[0]++; - mval = isdn_getnum(p); - if (mval < 0 || mval > 255) - PARSE_ERROR1; - switch (mreg) { - /* Some plausibility checks */ - case 14: - if (mval > ISDN_PROTO_L2_TRANS) - PARSE_ERROR1; - break; - case 16: - if ((mval * 16) > ISDN_SERIAL_XMIT_SIZE) - PARSE_ERROR1; + atemu *m = &info->emu; + int mreg; + int mval; + + mreg = isdn_getnum(p); + if (mreg < 0 || mreg > ISDN_MODEM_ANZREG) + PARSE_ERROR1; + switch (*p[0]) { + case '=': + p[0]++; + mval = isdn_getnum(p); + if (mval < 0 || mval > 255) + PARSE_ERROR1; + switch (mreg) { + /* Some plausibility checks */ + case 14: + if (mval > ISDN_PROTO_L2_TRANS) + PARSE_ERROR1; + break; + case 16: + if ((mval * 16) > ISDN_SERIAL_XMIT_SIZE) + PARSE_ERROR1; #ifdef CONFIG_ISDN_AUDIO - if ((m->mdmreg[18] & 1) && (mval > VBUFX)) - PARSE_ERROR1; + if ((m->mdmreg[18] & 1) && (mval > VBUFX)) + PARSE_ERROR1; #endif - info->xmit_size = mval * 16; - break; - case 20: - PARSE_ERROR1; - } - m->mdmreg[mreg] = mval; - break; - case '?': - p[0]++; - isdn_tty_show_profile(mreg, info); - break; - default: - PARSE_ERROR1; - break; - } - return 0; + info->xmit_size = mval * 16; + break; + case 20: + PARSE_ERROR1; + } + m->mdmreg[mreg] = mval; + break; + case '?': + p[0]++; + isdn_tty_show_profile(mreg, info); + break; + default: + PARSE_ERROR1; + break; + } + return 0; } /* * Perform ATA command */ -static void isdn_tty_cmd_ATA(modem_info * info) +static void +isdn_tty_cmd_ATA(modem_info * info) { - atemu *m = &info->emu; - isdn_ctrl cmd; - int l2; - - if (info->msr & UART_MSR_RI) { - /* Accept incoming call */ - m->mdmreg[1] = 0; - info->msr &= ~UART_MSR_RI; - l2 = m->mdmreg[14]; + atemu *m = &info->emu; + isdn_ctrl cmd; + int l2; + + if (info->msr & UART_MSR_RI) { + /* Accept incoming call */ + info->last_dir = 0; + strcpy(info->last_num, dev->num[info->drv_index]); + m->mdmreg[1] = 0; + info->msr &= ~UART_MSR_RI; + l2 = m->mdmreg[14]; #ifdef CONFIG_ISDN_AUDIO - /* If more than one bit set in reg18, autoselect Layer2 */ - if ((m->mdmreg[18] & m->mdmreg[20]) != m->mdmreg[18]) - if (m->mdmreg[20] == 1) l2 = 4; -#endif - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL2; - cmd.arg = info->isdn_channel + (l2 << 8); - dev->drv[info->isdn_driver]->interface->command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL3; - cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8); - dev->drv[info->isdn_driver]->interface->command(&cmd); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.command = ISDN_CMD_ACCEPTD; - dev->drv[info->isdn_driver]->interface->command(&cmd); - } else - isdn_tty_modem_result(8, info); + /* If more than one bit set in reg18, autoselect Layer2 */ + if ((m->mdmreg[18] & m->mdmreg[20]) != m->mdmreg[18]) + if (m->mdmreg[20] == 1) + l2 = 4; +#endif + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL2; + cmd.arg = info->isdn_channel + (l2 << 8); + info->last_l2 = l2; + dev->drv[info->isdn_driver]->interface->command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL3; + cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8); + dev->drv[info->isdn_driver]->interface->command(&cmd); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.command = ISDN_CMD_ACCEPTD; + dev->drv[info->isdn_driver]->interface->command(&cmd); + } else + isdn_tty_modem_result(8, info); } #ifdef CONFIG_ISDN_AUDIO /* * Parse AT+F.. commands */ -static int isdn_tty_cmd_PLUSF(char **p, modem_info * info) +static int +isdn_tty_cmd_PLUSF(char **p, modem_info * info) { - atemu *m = &info->emu; - int par; + atemu *m = &info->emu; + int par; char rs[20]; - if (!strncmp(p[0],"CLASS",5)) { - p[0] += 5; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs,"\r\n%d", - (m->mdmreg[18]&1)?8:0); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - switch (*p[0]) { - case '0': - p[0]++; - m->mdmreg[18] = 4; - info->xmit_size = - m->mdmreg[16] * 16; - break; - case '8': - p[0]++; - m->mdmreg[18] = 5; - info->xmit_size = VBUF; - break; - case '?': - p[0]++; - isdn_tty_at_cout("\r\n0,8", - info); - break; - default: - PARSE_ERROR1; - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - if (!strncmp(p[0],"AA",2)) { - p[0] += 2; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs,"\r\n%d", - m->mdmreg[0]); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - par = isdn_getnum(p); - if ((par < 0) || (par > 255)) - PARSE_ERROR1; - m->mdmreg[0]=par; - break; - default: - PARSE_ERROR1; - } - return 0; - } - PARSE_ERROR1; + if (!strncmp(p[0], "CLASS", 5)) { + p[0] += 5; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n%d", + (m->mdmreg[18] & 1) ? 8 : 0); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + switch (*p[0]) { + case '0': + p[0]++; + m->mdmreg[18] = 4; + info->xmit_size = + m->mdmreg[16] * 16; + break; + case '8': + p[0]++; + m->mdmreg[18] = 5; + info->xmit_size = VBUF; + break; + case '?': + p[0]++; + isdn_tty_at_cout("\r\n0,8", + info); + break; + default: + PARSE_ERROR1; + } + break; + default: + PARSE_ERROR1; + } + return 0; + } + if (!strncmp(p[0], "AA", 2)) { + p[0] += 2; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n%d", + m->mdmreg[0]); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + par = isdn_getnum(p); + if ((par < 0) || (par > 255)) + PARSE_ERROR1; + m->mdmreg[0] = par; + break; + default: + PARSE_ERROR1; + } + return 0; + } + PARSE_ERROR1; } /* * Parse AT+V.. commands */ -static int isdn_tty_cmd_PLUSV(char **p, modem_info * info) +static int +isdn_tty_cmd_PLUSV(char **p, modem_info * info) { - atemu *m = &info->emu; - static char *vcmd[] = {"NH","IP","LS","RX","SD","SM","TX",NULL}; - int i; + atemu *m = &info->emu; + static char *vcmd[] = + {"NH", "IP", "LS", "RX", "SD", "SM", "TX", NULL}; + int i; int par1; int par2; char rs[20]; - i = 0; - while (vcmd[i]) { - if (!strncmp(vcmd[i],p[0],2)) { - p[0] += 2; - break; - } - i++; - } - switch (i) { - case 0: - /* AT+VNH - Auto hangup feature */ - switch (*p[0]) { - case '?': - p[0]++; - isdn_tty_at_cout("\r\n1", info); - break; - case '=': - p[0]++; - switch (*p[0]) { - case '1': - p[0]++; - break; - case '?': - p[0]++; - isdn_tty_at_cout("\r\n1", info); - break; - default: - PARSE_ERROR1; - } - break; - default: - PARSE_ERROR1; - } - break; - case 1: - /* AT+VIP - Reset all voice parameters */ - isdn_tty_modem_reset_vpar(m); - break; - case 2: - /* AT+VLS - Select device, accept incoming call */ - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs,"\r\n%d",m->vpar[0]); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - switch (*p[0]) { - case '0': - p[0]++; - m->vpar[0] = 0; - break; - case '2': - p[0]++; - m->vpar[0] = 2; - break; - case '?': - p[0]++; - isdn_tty_at_cout("\r\n0,2", info); - break; - default: - PARSE_ERROR1; - } - break; - default: - PARSE_ERROR1; - } - break; - case 3: - /* AT+VRX - Start recording */ - if (!m->vpar[0]) - PARSE_ERROR1; - if (info->online != 1) { - isdn_tty_modem_result(8, info); - return 1; - } - info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state); - if (!info->dtmf_state) { - printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n"); - PARSE_ERROR1; - } - if (m->vpar[3] < 5) { - info->adpcmr = isdn_audio_adpcm_init(info->adpcmr, m->vpar[3]); - if (!info->adpcmr) { - printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n"); - PARSE_ERROR1; - } - } - info->vonline = 1; - isdn_tty_modem_result(1, info); - return 1; - break; - case 4: - /* AT+VSD - Silence detection */ - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs,"\r\n<%d>,<%d>", - m->vpar[1], - m->vpar[2]); - isdn_tty_at_cout(rs, 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: - PARSE_ERROR1; - } - break; - default: - PARSE_ERROR1; - } - break; - case 5: - /* AT+VSM - Select compression */ - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs,"\r\n<%d>,<%d><8000>", - m->vpar[3], - m->vpar[1]); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - switch (*p[0]) { - case '2': - case '3': - case '4': - case '5': - case '6': - par1 = isdn_getnum(p); - if ((par1 < 2) || (par1 > 6)) - PARSE_ERROR1; - m->vpar[3] = par1; - break; - case '?': - p[0]++; - isdn_tty_at_cout("\r\n2;ADPCM;2;0;(8000)\r\n", - info); - isdn_tty_at_cout("3;ADPCM;3;0;(8000)\r\n", - info); - isdn_tty_at_cout("4;ADPCM;4;0;(8000)\r\n", - info); - isdn_tty_at_cout("5;ALAW;8;0;(8000)", - info); - isdn_tty_at_cout("6;ULAW;8;0;(8000)", - info); - break; - default: - PARSE_ERROR1; - } - break; - default: - PARSE_ERROR1; - } - break; - case 6: - /* AT+VTX - Start sending */ - if (!m->vpar[0]) - PARSE_ERROR1; - if (info->online != 1) { - isdn_tty_modem_result(8, info); - return 1; - } - info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state); - if (!info->dtmf_state) { - printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n"); - PARSE_ERROR1; - } - if (m->vpar[3] < 5) { - info->adpcms = isdn_audio_adpcm_init(info->adpcms, m->vpar[3]); - if (!info->adpcms) { - printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n"); - PARSE_ERROR1; - } - } - m->lastDLE = 0; - info->vonline = 2; - isdn_tty_modem_result(1, info); - return 1; - break; - default: - PARSE_ERROR1; - } - return 0; + i = 0; + while (vcmd[i]) { + if (!strncmp(vcmd[i], p[0], 2)) { + p[0] += 2; + break; + } + i++; + } + switch (i) { + case 0: + /* AT+VNH - Auto hangup feature */ + switch (*p[0]) { + case '?': + p[0]++; + isdn_tty_at_cout("\r\n1", info); + break; + case '=': + p[0]++; + switch (*p[0]) { + case '1': + p[0]++; + break; + case '?': + p[0]++; + isdn_tty_at_cout("\r\n1", info); + break; + default: + PARSE_ERROR1; + } + break; + default: + PARSE_ERROR1; + } + break; + case 1: + /* AT+VIP - Reset all voice parameters */ + isdn_tty_modem_reset_vpar(m); + break; + case 2: + /* AT+VLS - Select device, accept incoming call */ + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n%d", m->vpar[0]); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + switch (*p[0]) { + case '0': + p[0]++; + m->vpar[0] = 0; + break; + case '2': + p[0]++; + m->vpar[0] = 2; + break; + case '?': + p[0]++; + isdn_tty_at_cout("\r\n0,2", info); + break; + default: + PARSE_ERROR1; + } + break; + default: + PARSE_ERROR1; + } + break; + case 3: + /* AT+VRX - Start recording */ + if (!m->vpar[0]) + PARSE_ERROR1; + if (info->online != 1) { + isdn_tty_modem_result(8, info); + return 1; + } + info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state); + if (!info->dtmf_state) { + printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n"); + PARSE_ERROR1; + } + if (m->vpar[3] < 5) { + info->adpcmr = isdn_audio_adpcm_init(info->adpcmr, m->vpar[3]); + if (!info->adpcmr) { + printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n"); + PARSE_ERROR1; + } + } +#ifdef ISDN_DEBUG_AT + printk(KERN_DEBUG "AT: +VRX\n"); +#endif + info->vonline |= 1; + isdn_tty_modem_result(1, info); + return 0; + break; + case 4: + /* AT+VSD - Silence detection */ + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n<%d>,<%d>", + m->vpar[1], + m->vpar[2]); + isdn_tty_at_cout(rs, 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: + PARSE_ERROR1; + } + break; + default: + PARSE_ERROR1; + } + break; + case 5: + /* AT+VSM - Select compression */ + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n<%d>,<%d><8000>", + m->vpar[3], + m->vpar[1]); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + switch (*p[0]) { + case '2': + case '3': + case '4': + case '5': + case '6': + par1 = isdn_getnum(p); + if ((par1 < 2) || (par1 > 6)) + PARSE_ERROR1; + m->vpar[3] = par1; + break; + case '?': + p[0]++; + isdn_tty_at_cout("\r\n2;ADPCM;2;0;(8000)\r\n", + info); + isdn_tty_at_cout("3;ADPCM;3;0;(8000)\r\n", + info); + isdn_tty_at_cout("4;ADPCM;4;0;(8000)\r\n", + info); + isdn_tty_at_cout("5;ALAW;8;0;(8000)", + info); + isdn_tty_at_cout("6;ULAW;8;0;(8000)", + info); + break; + default: + PARSE_ERROR1; + } + break; + default: + PARSE_ERROR1; + } + break; + case 6: + /* AT+VTX - Start sending */ + if (!m->vpar[0]) + PARSE_ERROR1; + if (info->online != 1) { + isdn_tty_modem_result(8, info); + return 1; + } + info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state); + if (!info->dtmf_state) { + printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n"); + PARSE_ERROR1; + } + if (m->vpar[3] < 5) { + info->adpcms = isdn_audio_adpcm_init(info->adpcms, m->vpar[3]); + if (!info->adpcms) { + printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n"); + PARSE_ERROR1; + } + } +#ifdef ISDN_DEBUG_AT + printk(KERN_DEBUG "AT: +VTX\n"); +#endif + m->lastDLE = 0; + info->vonline |= 2; + isdn_tty_modem_result(1, info); + return 0; + break; + default: + PARSE_ERROR1; + } + return 0; } -#endif /* CONFIG_ISDN_AUDIO */ +#endif /* CONFIG_ISDN_AUDIO */ /* * Parse and perform an AT-command-line. */ -static void isdn_tty_parse_at(modem_info * info) +static void +isdn_tty_parse_at(modem_info * info) { - atemu *m = &info->emu; - char *p; - char ds[40]; + atemu *m = &info->emu; + char *p; + char ds[40]; #ifdef ISDN_DEBUG_AT - printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd); + printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd); #endif - for (p = &m->mdmcmd[2]; *p;) { - switch (*p) { - case 'A': - /* A - Accept incoming call */ - p++; - isdn_tty_cmd_ATA(info); - return; - break; - case 'D': - /* D - Dial */ - isdn_tty_getdial(++p, ds); - p += strlen(p); - if (!strlen(m->msn)) - isdn_tty_modem_result(10, info); - else if (strlen(ds)) - isdn_tty_dial(ds, info, m); - else - isdn_tty_modem_result(4, info); - return; - case 'E': - /* E - Turn Echo on/off */ - p++; - switch (isdn_getnum(&p)) { - case 0: - m->mdmreg[12] &= ~4; - break; - case 1: - m->mdmreg[12] |= 4; - break; - default: - PARSE_ERROR; - } - break; - case 'H': - /* H - On/Off-hook */ - p++; - switch (*p) { - case '0': - p++; - isdn_tty_on_hook(info); - break; - case '1': - p++; - isdn_tty_off_hook(); - break; - default: - isdn_tty_on_hook(info); - break; - } - break; - case 'I': - /* I - Information */ - p++; - isdn_tty_at_cout("\r\nLinux ISDN", info); - switch (*p) { - case '0': - case '1': - p++; - break; - default: - } - break; - case 'O': - /* O - Go online */ - p++; - if (info->msr & UART_MSR_DCD) - /* if B-Channel is up */ - isdn_tty_modem_result(5, info); - else - isdn_tty_modem_result(3, info); - return; - case 'Q': - /* Q - Turn Emulator messages on/off */ - p++; - switch (isdn_getnum(&p)) { - case 0: - m->mdmreg[12] |= 1; - break; - case 1: - m->mdmreg[12] &= ~1; - break; - default: - PARSE_ERROR; - } - break; - case 'S': - /* S - Set/Get Register */ - p++; - if (isdn_tty_cmd_ATS(&p, info)) - return; - break; - case 'V': - /* V - Numeric or ASCII Emulator-messages */ - p++; - switch (isdn_getnum(&p)) { - case 0: - m->mdmreg[12] |= 2; - break; - case 1: - m->mdmreg[12] &= ~2; - break; - default: - PARSE_ERROR; - } - break; - case 'Z': - /* Z - Load Registers from Profile */ - p++; - isdn_tty_modem_reset_regs(m, 1); - break; + for (p = &m->mdmcmd[2]; *p;) { + switch (*p) { + case 'A': + /* A - Accept incoming call */ + p++; + isdn_tty_cmd_ATA(info); + return; + break; + case 'D': + /* D - Dial */ + isdn_tty_getdial(++p, ds); + p += strlen(p); + if (!strlen(m->msn)) + isdn_tty_modem_result(10, info); + else if (strlen(ds)) + isdn_tty_dial(ds, info, m); + else + isdn_tty_modem_result(4, info); + return; + case 'E': + /* E - Turn Echo on/off */ + p++; + switch (isdn_getnum(&p)) { + case 0: + m->mdmreg[12] &= ~4; + break; + case 1: + m->mdmreg[12] |= 4; + break; + default: + PARSE_ERROR; + } + break; + case 'H': + /* H - On/Off-hook */ + p++; + switch (*p) { + case '0': + p++; + isdn_tty_on_hook(info); + break; + case '1': + p++; + isdn_tty_off_hook(); + break; + default: + isdn_tty_on_hook(info); + break; + } + break; + case 'I': + /* I - Information */ + p++; + isdn_tty_at_cout("\r\nLinux ISDN", info); + switch (*p) { + case '0': + case '1': + p++; + break; + case '2': + p++; + isdn_tty_report(info); + break; + default: + } + break; + case 'O': + /* O - Go online */ + p++; + if (info->msr & UART_MSR_DCD) + /* if B-Channel is up */ + isdn_tty_modem_result(5, info); + else + isdn_tty_modem_result(3, info); + return; + case 'Q': + /* Q - Turn Emulator messages on/off */ + p++; + switch (isdn_getnum(&p)) { + case 0: + m->mdmreg[12] |= 1; + break; + case 1: + m->mdmreg[12] &= ~1; + break; + default: + PARSE_ERROR; + } + break; + case 'S': + /* S - Set/Get Register */ + p++; + if (isdn_tty_cmd_ATS(&p, info)) + return; + break; + case 'V': + /* V - Numeric or ASCII Emulator-messages */ + p++; + switch (isdn_getnum(&p)) { + case 0: + m->mdmreg[12] |= 2; + break; + case 1: + m->mdmreg[12] &= ~2; + break; + default: + PARSE_ERROR; + } + break; + case 'Z': + /* Z - Load Registers from Profile */ + p++; + isdn_tty_modem_reset_regs(info, 1); + break; #ifdef CONFIG_ISDN_AUDIO - case '+': - p++; - switch (*p) { - case 'F': - p++; - if (isdn_tty_cmd_PLUSF(&p, info)) - return; - break; - case 'V': - if (!(m->mdmreg[18] & 1)) - PARSE_ERROR; - p++; - if (isdn_tty_cmd_PLUSV(&p, info)) - return; - break; - } - break; -#endif /* CONFIG_ISDN_AUDIO */ - case '&': - p++; - if (isdn_tty_cmd_ATand(&p, info)) - return; - break; - default: - isdn_tty_modem_result(4, info); - return; - } - } - isdn_tty_modem_result(0, info); + case '+': + p++; + switch (*p) { + case 'F': + p++; + if (isdn_tty_cmd_PLUSF(&p, info)) + return; + break; + case 'V': + if (!(m->mdmreg[18] & 1)) + PARSE_ERROR; + p++; + if (isdn_tty_cmd_PLUSV(&p, info)) + return; + break; + } + break; +#endif /* CONFIG_ISDN_AUDIO */ + case '&': + p++; + if (isdn_tty_cmd_ATand(&p, info)) + return; + break; + default: + isdn_tty_modem_result(4, info); + return; + } + } + isdn_tty_modem_result(0, info); } /* Need own toupper() because standard-toupper is not available @@ -2649,7 +2852,8 @@ * channel index to line (minor-device) * user flag: buffer is in userspace */ -static int isdn_tty_edit_at(const char *p, int count, modem_info * info, int user) +static int +isdn_tty_edit_at(const char *p, int count, modem_info * info, int user) { atemu *m = &info->emu; int total = 0; @@ -2659,7 +2863,7 @@ for (cnt = count; cnt > 0; p++, cnt--) { if (user) - get_user(c, p); + GET_USER(c, p); else c = *p; total++; @@ -2695,16 +2899,16 @@ if (m->mdmcmdl < 255) { c = my_toupper(c); switch (m->mdmcmdl) { - case 0: - if (c == 'A') - m->mdmcmd[m->mdmcmdl++] = c; - break; - case 1: - if (c == 'T') - m->mdmcmd[m->mdmcmdl++] = c; - break; - default: - m->mdmcmd[m->mdmcmdl++] = c; + case 0: + if (c == 'A') + m->mdmcmd[m->mdmcmdl++] = c; + break; + case 1: + if (c == 'T') + m->mdmcmd[m->mdmcmdl++] = c; + break; + default: + m->mdmcmd[m->mdmcmdl++] = c; } } } @@ -2715,10 +2919,11 @@ /* * Switch all modem-channels who are online and got a valid * escape-sequence 1.5 seconds ago, to command-mode. - * This function is called every second via timer-interrupt from within + * This function is called every second via timer-interrupt from within * timer-dispatcher isdn_timer_function() */ -void isdn_tty_modem_escape(void) +void +isdn_tty_modem_escape(void) { int ton = 0; int i; @@ -2727,7 +2932,7 @@ for (i = 0; i < ISDN_MAX_CHANNELS; i++) if (USG_MODEM(dev->usage[i])) if ((midx = dev->m_idx[i]) >= 0) { - modem_info *info = &dev->mdm.info[midx]; + modem_info *info = &dev->mdm.info[midx]; if (info->online) { ton = 1; if ((info->emu.pluscount == 3) && @@ -2737,27 +2942,28 @@ isdn_tty_modem_result(0, info); } } - } + } isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton); } /* * Put a RING-message to all modem-channels who have the RI-bit set. - * This function is called every second via timer-interrupt from within + * This function is called every second via timer-interrupt from within * timer-dispatcher isdn_timer_function() */ -void isdn_tty_modem_ring(void) +void +isdn_tty_modem_ring(void) { int ton = 0; int i; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - modem_info *info = &dev->mdm.info[i]; - if (info->msr & UART_MSR_RI) { - ton = 1; - isdn_tty_modem_result(2, info); - } - } + modem_info *info = &dev->mdm.info[i]; + if (info->msr & UART_MSR_RI) { + ton = 1; + isdn_tty_modem_result(2, info); + } + } isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton); } @@ -2765,19 +2971,20 @@ * For all online tty's, try sending data to * the lower levels. */ -void isdn_tty_modem_xmit(void) +void +isdn_tty_modem_xmit(void) { int ton = 1; int i; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - modem_info *info = &dev->mdm.info[i]; - if (info->online) { - ton = 1; - isdn_tty_senddown(info); - isdn_tty_tint(info); - } - } + modem_info *info = &dev->mdm.info[i]; + if (info->online) { + ton = 1; + isdn_tty_senddown(info); + isdn_tty_tint(info); + } + } isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton); } @@ -2786,20 +2993,21 @@ * Search the tty-devices for an appropriate device, decrement its * counter for outstanding packets, and set CTS. */ -void isdn_tty_bsent(int drv, int chan) +void +isdn_tty_bsent(int drv, int chan) { int i; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - modem_info *info = &dev->mdm.info[i]; - if ((info->isdn_driver == drv) && - (info->isdn_channel == chan) ) { - info->msr |= UART_MSR_CTS; - if (info->send_outstanding) - if (!(--info->send_outstanding)) - info->lsr |= UART_LSR_TEMT; - isdn_tty_tint(info); - } - } + modem_info *info = &dev->mdm.info[i]; + if ((info->isdn_driver == drv) && + (info->isdn_channel == chan)) { + info->msr |= UART_MSR_CTS; + if (info->send_outstanding) + if (!(--info->send_outstanding)) + info->lsr |= UART_LSR_TEMT; + isdn_tty_tint(info); + } + } return; } diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/isdn_tty.h linux/drivers/isdn/isdn_tty.h --- v2.1.26/linux/drivers/isdn/isdn_tty.h Sun May 19 05:29:29 1996 +++ linux/drivers/isdn/isdn_tty.h Tue Feb 25 17:12:50 1997 @@ -1,10 +1,10 @@ -/* $Id: isdn_tty.h,v 1.5 1996/05/17 03:52:31 fritz Exp $ - * +/* $Id: isdn_tty.h,v 1.8 1997/02/10 20:12:50 fritz Exp $ + * header for Linux ISDN subsystem, tty related functions (linklevel). * * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) @@ -17,9 +17,18 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.h,v $ + * Revision 1.8 1997/02/10 20:12:50 fritz + * Changed interface for reporting incoming calls. + * + * Revision 1.7 1997/02/03 23:06:10 fritz + * Reformatted according CodingStyle + * + * Revision 1.6 1997/01/14 01:35:19 fritz + * Changed prototype of isdn_tty_modem_hup. + * * Revision 1.5 1996/05/17 03:52:31 fritz * Changed DLE handling for audio receive. * @@ -37,15 +46,15 @@ * */ -extern void isdn_tty_modem_result(int, modem_info *); -extern void isdn_tty_modem_escape(void); -extern void isdn_tty_modem_ring(void); -extern void isdn_tty_modem_xmit(void); -extern void isdn_tty_modem_hup(modem_info *); -extern int isdn_tty_modem_init(void); -extern void isdn_tty_readmodem(void); -extern int isdn_tty_try_read(modem_info *, struct sk_buff *); -extern int isdn_tty_find_icall(int, int, char *); -extern int isdn_tty_countDLE(unsigned char *, int); -extern void isdn_tty_bsent(int, int); -extern void isdn_tty_cleanup_xmit(modem_info *); +extern void isdn_tty_modem_result(int, modem_info *); +extern void isdn_tty_modem_escape(void); +extern void isdn_tty_modem_ring(void); +extern void isdn_tty_modem_xmit(void); +extern void isdn_tty_modem_hup(modem_info *, int); +extern int isdn_tty_modem_init(void); +extern void isdn_tty_readmodem(void); +extern int isdn_tty_try_read(modem_info *, struct sk_buff *); +extern int isdn_tty_find_icall(int, int, setup_parm); +extern int isdn_tty_countDLE(unsigned char *, int); +extern void isdn_tty_bsent(int, int); +extern void isdn_tty_cleanup_xmit(modem_info *); diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/pcbit/callbacks.c linux/drivers/isdn/pcbit/callbacks.c --- v2.1.26/linux/drivers/isdn/pcbit/callbacks.c Sat Jun 29 10:36:22 1996 +++ linux/drivers/isdn/pcbit/callbacks.c Tue Feb 25 17:12:50 1997 @@ -164,18 +164,12 @@ * ictl.num >= strlen() + strlen() + 5 */ - if (cbdata->data.setup.CalledPN) - sprintf(ictl.num, "%s,%d,%d,%s", - cbdata->data.setup.CallingPN, - 7, 0, - cbdata->data.setup.CalledPN); - - else - sprintf(ictl.num, "%s,%d,%d,%s", - cbdata->data.setup.CallingPN, - 7, 0, - "0"); - + strcpy(ictl.parm.setup.phone, cbdata->data.setup.CallingPN); + 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; #ifdef DEBUG printk(KERN_DEBUG "statstr: %s\n", ictl.num); diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/pcbit/capi.c linux/drivers/isdn/pcbit/capi.c --- v2.1.26/linux/drivers/isdn/pcbit/capi.c Sat Jun 29 10:36:22 1996 +++ linux/drivers/isdn/pcbit/capi.c Tue Feb 25 17:12:50 1997 @@ -147,7 +147,7 @@ return -1; } - (*skb)->free = 1; + SET_SKB_FREE((*skb)); *((ushort*) skb_put(*skb, 2) ) = chan->callref; @@ -170,7 +170,7 @@ return -1; } - (*skb)->free = 1; + SET_SKB_FREE((*skb)); *((ushort*) skb_put(*skb, 2) ) = chan->callref; @@ -200,7 +200,7 @@ return -1; } - (*skb)->free = 1; + SET_SKB_FREE((*skb)); *((ushort*) skb_put(*skb, 2) ) = chan->callref; @@ -222,7 +222,7 @@ return -1; } - (*skb)->free = 1; + SET_SKB_FREE((*skb)); *((ushort*) skb_put(*skb, 2) ) = chan->callref; @@ -285,7 +285,7 @@ return -1; } - (*skb)->free = 1; + SET_SKB_FREE((*skb)); *((ushort*) skb_put(*skb, 2) ) = chan->callref; @@ -338,7 +338,7 @@ return -1; } - (*skb)->free = 1; + SET_SKB_FREE((*skb)); *((ushort*) skb_put(*skb, 2) ) = chan->callref; @@ -357,7 +357,7 @@ return -1; } - (*skb)->free = 1; + SET_SKB_FREE((*skb)); *((ushort*) skb_put(*skb, 2) ) = callref; @@ -382,7 +382,7 @@ return -1; } - (*skb)->free = 1; + SET_SKB_FREE((*skb)); *((ushort*) skb_put(*skb, 2)) = chan->callref; diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/pcbit/drv.c linux/drivers/isdn/pcbit/drv.c --- v2.1.26/linux/drivers/isdn/pcbit/drv.c Mon Nov 18 01:31:31 1996 +++ linux/drivers/isdn/pcbit/drv.c Tue Feb 25 17:12:50 1997 @@ -37,7 +37,6 @@ #include #include #include -#include #include "pcbit.h" #include "edss1.h" @@ -227,7 +226,6 @@ struct pcbit_dev *dev; struct pcbit_chan *chan; struct callb_data info; - char *cp; dev = finddev(ctl->driver); @@ -246,14 +244,7 @@ break; case ISDN_CMD_DIAL: info.type = EV_USR_SETUP_REQ; - info.data.setup.CalledPN = (char *) &ctl->num; - cp = strchr(info.data.setup.CalledPN, ','); - if (cp) - *cp = 0; - else { - printk(KERN_DEBUG "DIAL: error in CalledPN\n"); - return -1; - } + info.data.setup.CalledPN = (char *) &ctl->parm.setup.phone; pcbit_fsm_event(dev, chan, EV_USR_SETUP_REQ, &info); break; case ISDN_CMD_ACCEPTD: @@ -281,7 +272,7 @@ pcbit_clear_msn(dev); break; case ISDN_CMD_SETEAZ: - pcbit_set_msn(dev, ctl->num); + pcbit_set_msn(dev, ctl->parm.num); break; case ISDN_CMD_SETL3: if ((ctl->arg >> 8) != ISDN_PROTO_L3_TRANS) @@ -429,8 +420,7 @@ { u_char cbuf[1024]; - if (copy_from_user(cbuf, buf, len)) - return -EFAULT; + copy_from_user(cbuf, buf, len); for (i=0; ish_mem + i); } @@ -448,11 +438,7 @@ /* get it into kernel space */ if ((ptr = kmalloc(len, GFP_KERNEL))==NULL) return -ENOMEM; - if (copy_from_user(ptr, buf, len)) - { - kfree(ptr); - return -EFAULT; - } + copy_from_user(ptr, buf, len); loadbuf = ptr; } else @@ -751,7 +737,7 @@ #endif } - skb->free = 1; + SET_SKB_FREE(skb); kfree_skb(skb, FREE_READ); @@ -767,12 +753,12 @@ static int stat_end = 0; -extern inline int memcpy_to_COND(int flag, void *d, void *s, int len) -{ +static __inline void +memcpy_to_COND(int flag, char *d, const char *s, int len) { if (flag) - return copy_to_user(d, s, len); - memcpy(d, s, len); - return 0; + copy_to_user(d, s, len); + else + memcpy(d, s, len); } @@ -790,27 +776,24 @@ if (stat_st < stat_end) { - if (memcpy_to_COND(user, buf, statbuf + stat_st, len)) - return -EFAULT; + memcpy_to_COND(user, buf, statbuf + stat_st, len); stat_st += len; } else { if (len > STATBUF_LEN - stat_st) { - if (memcpy_to_COND(user, buf, statbuf + stat_st, - STATBUF_LEN - stat_st)) - return -EFAULT; - if (memcpy_to_COND(user, buf, statbuf, - len - (STATBUF_LEN - stat_st))) - return -EFAULT; + memcpy_to_COND(user, buf, statbuf + stat_st, + STATBUF_LEN - stat_st); + memcpy_to_COND(user, buf, statbuf, + len - (STATBUF_LEN - stat_st)); + stat_st = len - (STATBUF_LEN - stat_st); } else { - if (memcpy_to_COND(user, buf, statbuf + stat_st, - len)) - return -EFAULT; + memcpy_to_COND(user, buf, statbuf + stat_st, + len); stat_st += len; @@ -953,7 +936,7 @@ return -ENODEV; } - cmd = (struct pcbit_ioctl *) ctl->num; + cmd = (struct pcbit_ioctl *) ctl->parm.num; switch(ctl->arg) { case PCBIT_IOCTL_GETSTAT: diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/pcbit/layer2.c linux/drivers/isdn/pcbit/layer2.c --- v2.1.26/linux/drivers/isdn/pcbit/layer2.c Sat Jun 29 10:36:22 1996 +++ linux/drivers/isdn/pcbit/layer2.c Tue Feb 25 17:12:50 1997 @@ -1,13 +1,13 @@ /* * Copyright (C) 1996 Universidade de Lisboa - * + * * Written by Pedro Roque Marques (roque@di.fc.ul.pt) * - * This software may be used and distributed according to the terms of + * This software may be used and distributed according to the terms of * the GNU Public License, incorporated herein by reference. */ -/* +/* * PCBIT-D low-layer interface */ @@ -19,7 +19,7 @@ /* * TODO: better handling of errors * re-write/remove debug printks - */ + */ #define __NO_VERSION__ @@ -57,7 +57,7 @@ /* * task queue struct - */ + */ @@ -66,16 +66,16 @@ * drv.c */ -extern void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg, - struct sk_buff * skb, +extern void pcbit_l3_receive(struct pcbit_dev *dev, ulong msg, + struct sk_buff *skb, ushort hdr_len, ushort refnum); /* * Prototypes */ -void pcbit_deliver(void * data); -static void pcbit_transmit(struct pcbit_dev * dev); +void pcbit_deliver(void *data); +static void pcbit_transmit(struct pcbit_dev *dev); static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack); @@ -83,9 +83,10 @@ static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info); static void pcbit_l2_err_recover(unsigned long data); -static void pcbit_firmware_bug(struct pcbit_dev * dev); +static void pcbit_firmware_bug(struct pcbit_dev *dev); -static __inline__ void pcbit_sched_delivery(struct pcbit_dev *dev) +static __inline__ void +pcbit_sched_delivery(struct pcbit_dev *dev) { queue_task(&dev->qdelivery, &tq_immediate); mark_bh(IMMEDIATE_BH); @@ -96,71 +97,67 @@ * Called from layer3 */ -int pcbit_l2_write(struct pcbit_dev * dev, ulong msg, ushort refnum, - struct sk_buff *skb, unsigned short hdr_len) - -{ - struct frame_buf * frame, * ptr; - unsigned long flags; - - if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) { - dev_kfree_skb(skb, FREE_WRITE); - return -1; - } - - if ( (frame = (struct frame_buf *) kmalloc(sizeof(struct frame_buf), - GFP_ATOMIC)) == NULL ) { - printk(KERN_WARNING "pcbit_2_write: kmalloc failed\n"); +int +pcbit_l2_write(struct pcbit_dev *dev, ulong msg, ushort refnum, + struct sk_buff *skb, unsigned short hdr_len) +{ + struct frame_buf *frame, + *ptr; + unsigned long flags; + + if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) { + dev_kfree_skb(skb, FREE_WRITE); + return -1; + } + if ((frame = (struct frame_buf *) kmalloc(sizeof(struct frame_buf), + GFP_ATOMIC)) == NULL) { + printk(KERN_WARNING "pcbit_2_write: kmalloc failed\n"); dev_kfree_skb(skb, FREE_WRITE); - return -1; - } + return -1; + } + frame->msg = msg; + frame->refnum = refnum; + frame->copied = 0; + frame->hdr_len = hdr_len; + + if (skb) + frame->dt_len = skb->len - hdr_len; + else + frame->dt_len = 0; - frame->msg = msg; - frame->refnum = refnum; - frame->copied = 0; - frame->hdr_len = hdr_len; - - if (skb) { - frame->dt_len = skb->len - hdr_len; - if (frame->dt_len == 0) - skb->lock++; - } - else - frame->dt_len = 0; - - frame->skb = skb; + frame->skb = skb; - frame->next = NULL; + frame->next = NULL; - save_flags(flags); - cli(); + save_flags(flags); + cli(); + + if (dev->write_queue == NULL) { + dev->write_queue = frame; + restore_flags(flags); + pcbit_transmit(dev); + } else { + for (ptr = dev->write_queue; ptr->next; ptr = ptr->next); + ptr->next = frame; - if (dev->write_queue == NULL) { - dev->write_queue = frame; restore_flags(flags); - pcbit_transmit(dev); - } - else { - for(ptr=dev->write_queue; ptr->next; ptr=ptr->next); - ptr->next = frame; - - restore_flags(flags); - } - return 0; + } + return 0; } -static __inline__ void pcbit_tx_update(struct pcbit_dev *dev, ushort len) +static __inline__ void +pcbit_tx_update(struct pcbit_dev *dev, ushort len) { - u_char info; + u_char info; - dev->send_seq = (dev->send_seq + 1) % 8; + dev->send_seq = (dev->send_seq + 1) % 8; - dev->fsize[dev->send_seq] = len; - info = 0; - info |= dev->rcv_seq << 3; - info |= dev->send_seq; + dev->fsize[dev->send_seq] = len; + info = 0; + info |= dev->rcv_seq << 3; + info |= dev->send_seq; - writeb(info, dev->sh_mem + BANK4); + writeb(info, dev->sh_mem + BANK4); } @@ -168,46 +165,47 @@ * called by interrupt service routine or by write_2 */ -static void pcbit_transmit(struct pcbit_dev * dev) +static void +pcbit_transmit(struct pcbit_dev *dev) { - struct frame_buf * frame = NULL; - unsigned char unacked; - int flen; /* fragment frame length including all headers */ - int totlen; /* non-fragmented frame length */ - int free; - int count, cp_len; - unsigned long flags; + struct frame_buf *frame = NULL; + unsigned char unacked; + int flen; /* fragment frame length including all headers */ + int totlen; /* non-fragmented frame length */ + int free; + int count, + cp_len; + unsigned long flags; unsigned short tt; - if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) - return; + if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) + return; - unacked = (dev->send_seq + (8 - dev->unack_seq) ) & 0x07; + unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07; save_flags(flags); cli(); - if (dev->free > 16 && dev->write_queue && unacked < 7) { + if (dev->free > 16 && dev->write_queue && unacked < 7) { - if (!dev->w_busy) - dev->w_busy = 1; - else - { - restore_flags(flags); - return; - } + if (!dev->w_busy) + dev->w_busy = 1; + else { + restore_flags(flags); + return; + } - frame = dev->write_queue; - free = dev->free; + frame = dev->write_queue; + free = dev->free; - restore_flags(flags); + restore_flags(flags); if (frame->copied == 0) { - /* Type 0 frame */ + /* Type 0 frame */ - struct msg_fmt * msg; + struct msg_fmt *msg; if (frame->skb) totlen = FRAME_HDR_LEN + PREHDR_LEN + frame->skb->len; @@ -216,67 +214,65 @@ flen = MIN(totlen, free); - msg = (struct msg_fmt *) &(frame->msg); + msg = (struct msg_fmt *) &(frame->msg); + + /* + * Board level 2 header + */ - /* - * Board level 2 header - */ + pcbit_writew(dev, flen - FRAME_HDR_LEN); - pcbit_writew(dev, flen - FRAME_HDR_LEN); + pcbit_writeb(dev, msg->cpu); - pcbit_writeb(dev, msg->cpu); + pcbit_writeb(dev, msg->proc); - pcbit_writeb(dev, msg->proc); + /* TH */ + pcbit_writew(dev, frame->hdr_len + PREHDR_LEN); - /* TH */ - pcbit_writew(dev, frame->hdr_len + PREHDR_LEN); + /* TD */ + pcbit_writew(dev, frame->dt_len); - /* TD */ - pcbit_writew(dev, frame->dt_len); + /* + * Board level 3 fixed-header + */ - /* - * Board level 3 fixed-header - */ - - /* LEN = TH */ - pcbit_writew(dev, frame->hdr_len + PREHDR_LEN); - - /* XX */ - pcbit_writew(dev, 0); + /* LEN = TH */ + pcbit_writew(dev, frame->hdr_len + PREHDR_LEN); - /* C + S */ - pcbit_writeb(dev, msg->cmd); - pcbit_writeb(dev, msg->scmd); + /* XX */ + pcbit_writew(dev, 0); + + /* C + S */ + pcbit_writeb(dev, msg->cmd); + pcbit_writeb(dev, msg->scmd); + + /* NUM */ + pcbit_writew(dev, frame->refnum); - /* NUM */ - pcbit_writew(dev, frame->refnum); - count = FRAME_HDR_LEN + PREHDR_LEN; - } - else { + } else { /* Type 1 frame */ - totlen = 2 + (frame->skb->len - frame->copied); - + totlen = 2 + (frame->skb->len - frame->copied); + flen = MIN(totlen, free); - /* TT */ - tt = ((ushort) (flen - 2)) | 0x8000U; /* Type 1 */ - pcbit_writew(dev, tt); + /* TT */ + tt = ((ushort) (flen - 2)) | 0x8000U; /* Type 1 */ + pcbit_writew(dev, tt); count = 2; } if (frame->skb) { - cp_len = MIN(frame->skb->len - frame->copied, - flen - count); - - memcpy_topcbit(dev, frame->skb->data + frame->copied, - cp_len); + cp_len = MIN(frame->skb->len - frame->copied, + flen - count); + + memcpy_topcbit(dev, frame->skb->data + frame->copied, + cp_len); frame->copied += cp_len; } - /* bookkeeping */ dev->free -= flen; pcbit_tx_update(dev, flen); @@ -285,28 +281,24 @@ cli(); - if (frame->skb == NULL || frame->copied == frame->skb->len) { - - dev->write_queue = frame->next; + if (frame->skb == NULL || frame->copied == frame->skb->len) { - if (frame->skb != NULL) { - /* free frame */ - dev_kfree_skb(frame->skb, FREE_WRITE); - } - - kfree(frame); - } + dev->write_queue = frame->next; + if (frame->skb != NULL) { + /* free frame */ + dev_kfree_skb(frame->skb, FREE_WRITE); + } + kfree(frame); + } dev->w_busy = 0; - restore_flags(flags); - } - else - { restore_flags(flags); -#ifdef DEBUG - printk(KERN_DEBUG "unacked %d free %d write_queue %s\n", - unacked, dev->free, dev->write_queue ? "not empty" : - "empty"); + } else { + restore_flags(flags); +#ifdef DEBUG + printk(KERN_DEBUG "unacked %d free %d write_queue %s\n", + unacked, dev->free, dev->write_queue ? "not empty" : + "empty"); #endif } } @@ -316,18 +308,18 @@ * deliver a queued frame to the upper layer */ -void pcbit_deliver(void * data) -{ - struct frame_buf *frame; - unsigned long flags; +void +pcbit_deliver(void *data) +{ + struct frame_buf *frame; + unsigned long flags; struct msg_fmt msg; - struct pcbit_dev *dev = (struct pcbit_dev *) data; + struct pcbit_dev *dev = (struct pcbit_dev *) data; save_flags(flags); - cli(); + cli(); - while((frame=dev->read_queue)) - { + while ((frame = dev->read_queue)) { dev->read_queue = frame->next; restore_flags(flags); @@ -336,12 +328,12 @@ msg.cmd = frame->skb->data[2]; msg.scmd = frame->skb->data[3]; - frame->refnum = *((ushort*) frame->skb->data + 4); - frame->msg = *((ulong*) &msg); - + frame->refnum = *((ushort *) frame->skb->data + 4); + frame->msg = *((ulong *) & msg); + skb_pull(frame->skb, 6); - pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len, + pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len, frame->refnum); kfree(frame); @@ -354,110 +346,104 @@ } /* - * Reads BANK 2 & Reassembles + * Reads BANK 2 & Reassembles */ -static void pcbit_receive(struct pcbit_dev * dev) +static void +pcbit_receive(struct pcbit_dev *dev) { - unsigned short tt; - u_char cpu, proc; - struct frame_buf * frame = NULL; - unsigned long flags; - u_char type1; + unsigned short tt; + u_char cpu, + proc; + struct frame_buf *frame = NULL; + unsigned long flags; + u_char type1; - if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) - return; + if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) + return; - tt = pcbit_readw(dev); + tt = pcbit_readw(dev); - if ((tt & 0x7fffU) > 511) { - printk(KERN_INFO "pcbit: invalid frame length -> TT=%04x\n", + if ((tt & 0x7fffU) > 511) { + printk(KERN_INFO "pcbit: invalid frame length -> TT=%04x\n", tt); - pcbit_l2_error(dev); - return; - } - - if (!(tt & 0x8000U)) - { /* Type 0 */ - type1 = 0; + pcbit_l2_error(dev); + return; + } + if (!(tt & 0x8000U)) { /* Type 0 */ + type1 = 0; - if (dev->read_frame) { - printk(KERN_DEBUG "pcbit_receive: Type 0 frame and read_frame != NULL\n"); + if (dev->read_frame) { + printk(KERN_DEBUG "pcbit_receive: Type 0 frame and read_frame != NULL\n"); #if 0 - pcbit_l2_error(dev); - return; + pcbit_l2_error(dev); + return; #else /* discard previous queued frame */ if (dev->read_frame->skb) { - dev->read_frame->skb->free = 1; + SET_SKB_FREE(dev->read_frame->skb); kfree_skb(dev->read_frame->skb, FREE_READ); } kfree(dev->read_frame); dev->read_frame = NULL; #endif - } + } + frame = kmalloc(sizeof(struct frame_buf), GFP_ATOMIC); + + if (frame == NULL) { + printk(KERN_WARNING "kmalloc failed\n"); + return; + } + memset(frame, 0, sizeof(struct frame_buf)); + + cpu = pcbit_readb(dev); + proc = pcbit_readb(dev); - frame = kmalloc(sizeof(struct frame_buf), GFP_ATOMIC); - - if (frame == NULL) { - printk(KERN_WARNING "kmalloc failed\n"); - return; - } - memset(frame, 0, sizeof(struct frame_buf)); - - cpu = pcbit_readb(dev); - proc = pcbit_readb(dev); - - - if (cpu != 0x06 && cpu != 0x02) - { - printk (KERN_DEBUG "pcbit: invalid cpu value\n"); + + if (cpu != 0x06 && cpu != 0x02) { + printk(KERN_DEBUG "pcbit: invalid cpu value\n"); kfree(frame); pcbit_l2_error(dev); - return; - } - - /* - * we discard cpu & proc on receiving - * but we read it to update the pointer - */ - - frame->hdr_len = pcbit_readw(dev); - frame->dt_len = pcbit_readw(dev); - - /* - * 0 sized packet - * I don't know if they are an error or not... - * But they are very frequent - * Not documented - */ + return; + } + /* + * we discard cpu & proc on receiving + * but we read it to update the pointer + */ + + frame->hdr_len = pcbit_readw(dev); + frame->dt_len = pcbit_readw(dev); + + /* + * 0 sized packet + * I don't know if they are an error or not... + * But they are very frequent + * Not documented + */ if (frame->hdr_len == 0) { - kfree(frame); + kfree(frame); #ifdef DEBUG - printk(KERN_DEBUG "0 sized frame\n"); + printk(KERN_DEBUG "0 sized frame\n"); #endif pcbit_firmware_bug(dev); - return; + return; } - - /* sanity check the length values */ - if (frame->hdr_len > 1024 || frame->dt_len > 2048) - { + /* sanity check the length values */ + if (frame->hdr_len > 1024 || frame->dt_len > 2048) { #ifdef DEBUG - printk(KERN_DEBUG "length problem: "); - printk(KERN_DEBUG "TH=%04x TD=%04x\n", - frame->hdr_len, - frame->dt_len); + printk(KERN_DEBUG "length problem: "); + printk(KERN_DEBUG "TH=%04x TD=%04x\n", + frame->hdr_len, + frame->dt_len); #endif pcbit_l2_error(dev); kfree(frame); - return; - } - - /* minimum frame read */ + return; + } + /* minimum frame read */ - frame->skb = dev_alloc_skb(frame->hdr_len + frame->dt_len + + frame->skb = dev_alloc_skb(frame->hdr_len + frame->dt_len + ((frame->hdr_len + 15) & ~15)); if (!frame->skb) { @@ -465,62 +451,57 @@ kfree(frame); return; } - - /* 16 byte alignment for IP */ + /* 16 byte alignment for IP */ if (frame->dt_len) - skb_reserve(frame->skb, (frame->hdr_len + 15) & ~15); + skb_reserve(frame->skb, (frame->hdr_len + 15) & ~15); - } - else { + } else { /* Type 1 */ - type1 = 1; - tt &= 0x7fffU; + type1 = 1; + tt &= 0x7fffU; - if (!(frame = dev->read_frame)) { - printk("Type 1 frame and no frame queued\n"); + if (!(frame = dev->read_frame)) { + printk("Type 1 frame and no frame queued\n"); #if 1 /* usually after an error: toss frame */ dev->readptr += tt; if (dev->readptr > dev->sh_mem + BANK2 + BANKLEN) dev->readptr -= BANKLEN; #else - pcbit_l2_error(dev); + pcbit_l2_error(dev); #endif - return; + return; - } - } + } + } memcpy_frompcbit(dev, skb_put(frame->skb, tt), tt); frame->copied += tt; - if (frame->copied == frame->hdr_len + frame->dt_len) { - - save_flags(flags); - cli(); - - if (type1) { - dev->read_frame = NULL; - } - - if (dev->read_queue) { - struct frame_buf *ptr; - for(ptr=dev->read_queue;ptr->next;ptr=ptr->next); - ptr->next = frame; - } - else - dev->read_queue = frame; - - restore_flags(flags); - - } - else { - save_flags(flags); - cli(); - dev->read_frame = frame; - restore_flags(flags); - } + if (frame->copied == frame->hdr_len + frame->dt_len) { + + save_flags(flags); + cli(); + + if (type1) { + dev->read_frame = NULL; + } + if (dev->read_queue) { + struct frame_buf *ptr; + for (ptr = dev->read_queue; ptr->next; ptr = ptr->next); + ptr->next = frame; + } else + dev->read_queue = frame; + + restore_flags(flags); + + } else { + save_flags(flags); + cli(); + dev->read_frame = frame; + restore_flags(flags); + } } /* @@ -529,194 +510,173 @@ * gotta send a fake acknowledgment to the upper layer somehow */ -static __inline__ void pcbit_fake_conf(struct pcbit_dev *dev, struct pcbit_chan * chan) +static __inline__ void +pcbit_fake_conf(struct pcbit_dev *dev, struct pcbit_chan *chan) { - isdn_ctrl ictl; + isdn_ctrl ictl; - if (chan->queued) { - chan->queued--; - - ictl.driver = dev->id; - ictl.command = ISDN_STAT_BSENT; - ictl.arg = chan->id; - dev->dev_if->statcallb(&ictl); - } + if (chan->queued) { + chan->queued--; + + ictl.driver = dev->id; + ictl.command = ISDN_STAT_BSENT; + ictl.arg = chan->id; + dev->dev_if->statcallb(&ictl); + } } -static void pcbit_firmware_bug(struct pcbit_dev * dev) +static void +pcbit_firmware_bug(struct pcbit_dev *dev) { - struct pcbit_chan *chan; - - chan = dev->b1; + struct pcbit_chan *chan; - if (chan->fsm_state == ST_ACTIVE) { - pcbit_fake_conf(dev, chan); - } + chan = dev->b1; - chan = dev->b2; + if (chan->fsm_state == ST_ACTIVE) { + pcbit_fake_conf(dev, chan); + } + chan = dev->b2; - if (chan->fsm_state == ST_ACTIVE) { - pcbit_fake_conf(dev, chan); - } - + if (chan->fsm_state == ST_ACTIVE) { + pcbit_fake_conf(dev, chan); + } } -void pcbit_irq_handler(int interrupt, void * devptr, struct pt_regs *regs) +void +pcbit_irq_handler(int interrupt, void *devptr, struct pt_regs *regs) { - struct pcbit_dev * dev; - u_char info, ack_seq, read_seq; + struct pcbit_dev *dev; + u_char info, + ack_seq, + read_seq; dev = (struct pcbit_dev *) devptr; - if (!dev) - { - printk(KERN_WARNING "pcbit_irq_handler: wrong device\n"); - return; - } - + if (!dev) { + printk(KERN_WARNING "pcbit_irq_handler: wrong device\n"); + return; + } if (dev->interrupt) { - printk(KERN_DEBUG "pcbit: reentering interrupt hander\n"); + printk(KERN_DEBUG "pcbit: reentering interrupt hander\n"); return; } - dev->interrupt = 1; - info = readb(dev->sh_mem + BANK3); + info = readb(dev->sh_mem + BANK3); - if (dev->l2_state == L2_STARTING || dev->l2_state == L2_ERROR) - { - pcbit_l2_active_conf(dev, info); + if (dev->l2_state == L2_STARTING || dev->l2_state == L2_ERROR) { + pcbit_l2_active_conf(dev, info); dev->interrupt = 0; - return; - } - - if (info & 0x40U) /* E bit set */ - { + return; + } + if (info & 0x40U) { /* E bit set */ #ifdef DEBUG printk(KERN_DEBUG "pcbit_irq_handler: E bit on\n"); #endif - pcbit_l2_error(dev); + pcbit_l2_error(dev); dev->interrupt = 0; - return; - } - - if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) - { - dev->interrupt = 0; - return; + return; } + if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) { + dev->interrupt = 0; + return; + } + ack_seq = (info >> 3) & 0x07U; + read_seq = (info & 0x07U); - ack_seq = (info >> 3) & 0x07U; - read_seq = (info & 0x07U); - dev->interrupt = 0; - if (read_seq != dev->rcv_seq) - { - while (read_seq != dev->rcv_seq) - { + if (read_seq != dev->rcv_seq) { + while (read_seq != dev->rcv_seq) { pcbit_receive(dev); dev->rcv_seq = (dev->rcv_seq + 1) % 8; } pcbit_sched_delivery(dev); - } - - if (ack_seq != dev->unack_seq) - { - pcbit_recv_ack(dev, ack_seq); - } - - + } + if (ack_seq != dev->unack_seq) { + pcbit_recv_ack(dev, ack_seq); + } info = dev->rcv_seq << 3; info |= dev->send_seq; - - writeb(info, dev->sh_mem + BANK4); + + writeb(info, dev->sh_mem + BANK4); } -static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info) +static void +pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info) { - u_char state; + u_char state; - state = dev->l2_state; + state = dev->l2_state; #ifdef DEBUG - printk(KERN_DEBUG "layer2_active_confirm\n"); + printk(KERN_DEBUG "layer2_active_confirm\n"); #endif - - if (info & 0x80U ) { - dev->rcv_seq = info & 0x07U; - dev->l2_state = L2_RUNNING; - } - else - dev->l2_state = L2_DOWN; - - if (state == L2_STARTING) - wake_up_interruptible(&dev->set_running_wq); - if (state == L2_ERROR && dev->l2_state == L2_RUNNING) { - pcbit_transmit(dev); - } + if (info & 0x80U) { + dev->rcv_seq = info & 0x07U; + dev->l2_state = L2_RUNNING; + } else + dev->l2_state = L2_DOWN; + + if (state == L2_STARTING) + wake_up_interruptible(&dev->set_running_wq); + if (state == L2_ERROR && dev->l2_state == L2_RUNNING) { + pcbit_transmit(dev); + } } -static void pcbit_l2_err_recover(unsigned long data) +static void +pcbit_l2_err_recover(unsigned long data) { - struct pcbit_dev * dev; - struct frame_buf *frame; + struct pcbit_dev *dev; + struct frame_buf *frame; - dev = (struct pcbit_dev *) data; + dev = (struct pcbit_dev *) data; - del_timer(&dev->error_recover_timer); - if (dev->w_busy || dev->r_busy) - { + del_timer(&dev->error_recover_timer); + if (dev->w_busy || dev->r_busy) { init_timer(&dev->error_recover_timer); dev->error_recover_timer.expires = jiffies + ERRTIME; add_timer(&dev->error_recover_timer); return; } - dev->w_busy = dev->r_busy = 1; - if (dev->read_frame) - { - if (dev->read_frame->skb) - { - dev->read_frame->skb->free = 1; - kfree_skb(dev->read_frame->skb, FREE_READ); - } - kfree(dev->read_frame); - dev->read_frame = NULL; - } - - - if (dev->write_queue) - { - frame = dev->write_queue; + if (dev->read_frame) { + if (dev->read_frame->skb) { + SET_SKB_FREE(dev->read_frame->skb); + kfree_skb(dev->read_frame->skb, FREE_READ); + } + kfree(dev->read_frame); + dev->read_frame = NULL; + } + if (dev->write_queue) { + frame = dev->write_queue; #ifdef FREE_ON_ERROR - dev->write_queue = dev->write_queue->next; + dev->write_queue = dev->write_queue->next; if (frame->skb) { - dev_kfree_skb(frame->skb, FREE_WRITE); + dev_kfree_skb(frame->skb, FREE_WRITE); } - - kfree(frame); -#else - frame->copied = 0; + kfree(frame); +#else + frame->copied = 0; #endif - } - - dev->rcv_seq = dev->send_seq = dev->unack_seq = 0; - dev->free = 511; - dev->l2_state = L2_ERROR; + } + dev->rcv_seq = dev->send_seq = dev->unack_seq = 0; + dev->free = 511; + dev->l2_state = L2_ERROR; /* this is an hack... */ pcbit_firmware_bug(dev); - dev->writeptr = dev->sh_mem; - dev->readptr = dev->sh_mem + BANK2; + dev->writeptr = dev->sh_mem; + dev->readptr = dev->sh_mem + BANK2; writeb((0x80U | ((dev->rcv_seq & 0x07) << 3) | (dev->send_seq & 0x07)), dev->sh_mem + BANK4); @@ -724,24 +684,25 @@ } -static void pcbit_l2_error(struct pcbit_dev *dev) +static void +pcbit_l2_error(struct pcbit_dev *dev) { - if (dev->l2_state == L2_RUNNING) { + if (dev->l2_state == L2_RUNNING) { - printk(KERN_INFO "pcbit: layer 2 error\n"); + printk(KERN_INFO "pcbit: layer 2 error\n"); #ifdef DEBUG - log_state(dev); + log_state(dev); #endif - - dev->l2_state = L2_DOWN; - init_timer(&dev->error_recover_timer); - dev->error_recover_timer.function = &pcbit_l2_err_recover; - dev->error_recover_timer.data = (ulong) dev; - dev->error_recover_timer.expires = jiffies + ERRTIME; - add_timer(&dev->error_recover_timer); - } + dev->l2_state = L2_DOWN; + + init_timer(&dev->error_recover_timer); + dev->error_recover_timer.function = &pcbit_l2_err_recover; + dev->error_recover_timer.data = (ulong) dev; + dev->error_recover_timer.expires = jiffies + ERRTIME; + add_timer(&dev->error_recover_timer); + } } /* @@ -751,58 +712,52 @@ * call pcbit_transmit to write possible queued frames */ -static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack) +static void +pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack) { - int i, count; - int unacked; + int i, + count; + int unacked; - unacked = (dev->send_seq + (8 - dev->unack_seq) ) & 0x07; + unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07; - /* dev->unack_seq < ack <= dev->send_seq; */ + /* dev->unack_seq < ack <= dev->send_seq; */ - if (unacked) - { + if (unacked) { if (dev->send_seq > dev->unack_seq) - if (ack <= dev->unack_seq || ack > dev->send_seq) - { - printk(KERN_DEBUG - "layer 2 ack unacceptable - dev %d", + if (ack <= dev->unack_seq || ack > dev->send_seq) { + printk(KERN_DEBUG + "layer 2 ack unacceptable - dev %d", dev->id); - pcbit_l2_error(dev); - } - else - if (ack > dev->send_seq && ack <= dev->unack_seq) - { - printk(KERN_DEBUG - "layer 2 ack unacceptable - dev %d", - dev->id); - pcbit_l2_error(dev); - } - - /* ack is acceptable */ - - - i = dev->unack_seq; - - do { - dev->unack_seq = i = (i + 1) % 8; - dev->free += dev->fsize[i]; - } while (i != ack); - - count = 0; - while (count < 7 && dev->write_queue) - { + pcbit_l2_error(dev); + } else if (ack > dev->send_seq && ack <= dev->unack_seq) { + printk(KERN_DEBUG + "layer 2 ack unacceptable - dev %d", + dev->id); + pcbit_l2_error(dev); + } + /* ack is acceptable */ + + + i = dev->unack_seq; + + do { + dev->unack_seq = i = (i + 1) % 8; + dev->free += dev->fsize[i]; + } while (i != ack); + + count = 0; + while (count < 7 && dev->write_queue) { u8 lsend_seq = dev->send_seq; - pcbit_transmit(dev); + pcbit_transmit(dev); if (dev->send_seq == lsend_seq) break; - count++; - } - } - else - printk(KERN_DEBUG "recv_ack: unacked = 0\n"); + count++; + } + } else + printk(KERN_DEBUG "recv_ack: unacked = 0\n"); } diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/pcbit/module.c linux/drivers/isdn/pcbit/module.c --- v2.1.26/linux/drivers/isdn/pcbit/module.c Fri Dec 27 02:03:22 1996 +++ linux/drivers/isdn/pcbit/module.c Tue Feb 25 17:12:50 1997 @@ -1,13 +1,13 @@ /* * Copyright (C) 1996 Universidade de Lisboa - * + * * Written by Pedro Roque Marques (roque@di.fc.ul.pt) * - * This software may be used and distributed according to the terms of + * This software may be used and distributed according to the terms of * the GNU Public License, incorporated herein by reference. */ -/* +/* * PCBIT-D module support */ @@ -35,7 +35,10 @@ extern int pcbit_init_dev(int board, int mem_base, int irq); #ifdef MODULE -EXPORT_NO_SYMBOLS; +#if (LINUX_VERSION_CODE > 0x020111) +MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i"); +MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i"); +#endif #define pcbit_init init_module #endif @@ -45,11 +48,11 @@ num_boards = 0; - printk(KERN_INFO + printk(KERN_INFO "PCBIT-D device driver v 0.5 - " "Copyright (C) 1996 Universidade de Lisboa\n"); - if (mem[0] || irq[0]) + if (mem[0] || irq[0]) { for (board=0; board < MAX_PCBIT_CARDS && mem[board] && irq[board]; board++) { @@ -57,14 +60,14 @@ mem[board] = 0xD0000; if (!irq[board]) irq[board] = 5; - + if (pcbit_init_dev(board, mem[board], irq[board]) == 0) num_boards++; - - else + + else { - printk(KERN_WARNING - "pcbit_init failed for dev %d", + printk(KERN_WARNING + "pcbit_init failed for dev %d", board + 1); return -EIO; } @@ -75,7 +78,7 @@ if (!num_boards) { - printk(KERN_INFO + printk(KERN_INFO "Trying to detect board using default settings\n"); if (pcbit_init_dev(0, 0xD0000, 5) == 0) num_boards++; @@ -83,6 +86,13 @@ return -EIO; } + /* No symbols to export, hide all symbols */ +#if (LINUX_VERSION_CODE < 0x020111) + register_symtab(NULL); +#else + EXPORT_NO_SYMBOLS; +#endif + return 0; } @@ -93,7 +103,7 @@ for (board = 0; board < num_boards; board++) pcbit_terminate(board); - printk(KERN_INFO + printk(KERN_INFO "PCBIT-D module unloaded\n"); } @@ -112,7 +122,7 @@ mem[i] = ints[j]; j++; argc--; } - + if (argc) { irq[i] = ints[j]; j++; argc--; @@ -122,3 +132,6 @@ } } #endif + + + diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/sc/Makefile linux/drivers/isdn/sc/Makefile --- v2.1.26/linux/drivers/isdn/sc/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/sc/Makefile Tue Feb 25 17:12:50 1997 @@ -0,0 +1,44 @@ +# +# $Id: Makefile.kernel,v 1.1 1996/11/07 13:07:40 fritz Exp $ +# Copyright (C) 1996 SpellCaster Telecommunications Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# For more information, please contact gpl-info@spellcast.com or write: +# +# SpellCaster Telecommunications Inc. +# 5621 Finch Avenue East, Unit #3 +# Scarborough, Ontario Canada +# M1B 2T9 +# +1 (416) 297-8565 +# +1 (416) 297-6433 Facsimile +# + +L_OBJS := +M_OBJS := +O_OBJS := shmem.o init.o debug.o packet.o command.o event.o \ + ioctl.o interrupt.o message.o timer.o + +O_TARGET := +ifeq ($(CONFIG_ISDN_DRV_SC),y) + O_TARGET += sc.o +else + ifeq ($(CONFIG_ISDN_DRV_SC),m) + O_TARGET += sc.o + M_OBJS += sc.o + endif +endif + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/sc/card.h linux/drivers/isdn/sc/card.h --- v2.1.26/linux/drivers/isdn/sc/card.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/sc/card.h Tue Feb 25 17:12:50 1997 @@ -0,0 +1,110 @@ +/* + * $Id: card.h,v 1.1 1996/11/07 13:07:40 fritz Exp $ + * Copyright (C) 1996 SpellCaster Telecommunications Inc. + * + * card.h - Driver parameters for SpellCaster ISA ISDN adapters + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * For more information, please contact gpl-info@spellcast.com or write: + * + * SpellCaster Telecommunications Inc. + * 5621 Finch Avenue East, Unit #3 + * Scarborough, Ontario Canada + * M1B 2T9 + * +1 (416) 297-8565 + * +1 (416) 297-6433 Facsimile + */ + +#ifndef CARD_H +#define CARD_H + +/* + * We need these if they're not already included + */ +#include +#include +#include "message.h" + +/* + * Amount of time to wait for a reset to complete + */ +#define CHECKRESET_TIME milliseconds(4000) + +/* + * Amount of time between line status checks + */ +#define CHECKSTAT_TIME milliseconds(8000) + +/* + * The maximum amount of time to wait for a message response + * to arrive. Use exclusively by send_and_receive + */ +#define SAR_TIMEOUT milliseconds(10000) + +/* + * Macro to determine is a card id is valid + */ +#define IS_VALID_CARD(x) ((x >= 0) && (x <= cinst)) + +/* + * Per channel status and configuration + */ +typedef struct { + int l2_proto; + int l3_proto; + char dn[50]; + unsigned long first_sendbuf; /* Offset of first send buffer */ + unsigned int num_sendbufs; /* Number of send buffers */ + unsigned int free_sendbufs; /* Number of free sendbufs */ + unsigned int next_sendbuf; /* Next sequential buffer */ + char eazlist[50]; /* Set with SETEAZ */ + char sillist[50]; /* Set with SETSIL */ + int eazclear; /* Don't accept calls if TRUE */ +} bchan; + +/* + * Everything you want to know about the adapter ... + */ +typedef struct { + int model; + int driverId; /* LL Id */ + char devicename[20]; /* The device name */ + isdn_if *card; /* ISDN4Linux structure */ + bchan *channel; /* status of the B channels */ + char nChannels; /* Number of channels */ + unsigned int interrupt; /* Interrupt number */ + int iobase; /* I/O Base address */ + int ioport[MAX_IO_REGS]; /* Index to I/O ports */ + int shmem_pgport; /* port for the exp mem page reg. */ + int shmem_magic; /* adapter magic number */ + unsigned int rambase; /* Shared RAM base address */ + unsigned int ramsize; /* Size of shared memory */ + RspMessage async_msg; /* Async response message */ + int want_async_messages; /* Snoop the Q ? */ + unsigned char seq_no; /* Next send seq. number */ + struct timer_list reset_timer; /* Check reset timer */ + struct timer_list stat_timer; /* Check startproc timer */ + unsigned char nphystat; /* Latest PhyStat info */ + unsigned char phystat; /* Last PhyStat info */ + HWConfig_pl hwconfig; /* Hardware config info */ + char load_ver[11]; /* CommManage Version string */ + char proc_ver[11]; /* CommEngine Version */ + int StartOnReset; /* Indicates startproc after reset */ + int EngineUp; /* Indicates CommEngine Up */ + int trace_mode; /* Indicate if tracing is on */ +} board; + +#endif /* CARD_H */ diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/sc/command.c linux/drivers/isdn/sc/command.c --- v2.1.26/linux/drivers/isdn/sc/command.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/sc/command.c Tue Feb 25 17:12:50 1997 @@ -0,0 +1,566 @@ +/* + * $Id: command.c,v 1.3 1997/02/11 22:53:40 fritz Exp $ + * Copyright (C) 1996 SpellCaster Telecommunications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * For more information, please contact gpl-info@spellcast.com or write: + * + * SpellCaster Telecommunications Inc. + * 5621 Finch Avenue East, Unit #3 + * Scarborough, Ontario Canada + * M1B 2T9 + * +1 (416) 297-8565 + * +1 (416) 297-6433 Facsimile + */ + +#define __NO_VERSION__ +#include "includes.h" /* This must be first */ +#include "hardware.h" +#include "message.h" +#include "card.h" +#include "scioc.h" + +int dial(int card, unsigned long channel, setup_parm setup); +int hangup(int card, unsigned long channel); +int answer(int card, unsigned long channel); +int clreaz(int card, unsigned long channel); +int seteaz(int card, unsigned long channel, char *); +int geteaz(int card, unsigned long channel, char *); +int setsil(int card, unsigned long channel, char *); +int getsil(int card, unsigned long channel, char *); +int setl2(int card, unsigned long arg); +int getl2(int card, unsigned long arg); +int setl3(int card, unsigned long arg); +int getl3(int card, unsigned long arg); +int lock(void); +int unlock(void); +int acceptb(int card, unsigned long channel); + +extern int cinst; +extern board *adapter[]; + +extern int sc_ioctl(int, scs_ioctl *); +extern int setup_buffers(int, int, unsigned int); +extern int indicate_status(int, int,ulong,char*); +extern void check_reset(unsigned long); +extern int send_and_receive(int, unsigned int, unsigned char, unsigned char, + unsigned char, unsigned char, unsigned char, unsigned char *, + RspMessage *, int); +extern int sendmessage(int, unsigned int, unsigned int, unsigned int, + unsigned int, unsigned int, unsigned int, unsigned int *); +extern inline void pullphone(char *, char *); + +#ifdef DEBUG +/* + * Translate command codes to strings + */ +static char *commands[] = { "ISDN_CMD_IOCTL", + "ISDN_CMD_DIAL", + "ISDN_CMD_ACCEPTB", + "ISDN_CMD_ACCEPTB", + "ISDN_CMD_HANGUP", + "ISDN_CMD_CLREAZ", + "ISDN_CMD_SETEAZ", + "ISDN_CMD_GETEAZ", + "ISDN_CMD_SETSIL", + "ISDN_CMD_GETSIL", + "ISDN_CMD_SETL2", + "ISDN_CMD_GETL2", + "ISDN_CMD_SETL3", + "ISDN_CMD_GETL3", + "ISDN_CMD_LOCK", + "ISDN_CMD_UNLOCK", + "ISDN_CMD_SUSPEND", + "ISDN_CMD_RESUME" }; + +/* + * Translates ISDN4Linux protocol codes to strings for debug messages + */ +static char *l3protos[] = { "ISDN_PROTO_L3_TRANS" }; +static char *l2protos[] = { "ISDN_PROTO_L2_X75I", + "ISDN_PROTO_L2_X75UI", + "ISDN_PROTO_L2_X75BUI", + "ISDN_PROTO_L2_HDLC", + "ISDN_PROTO_L2_TRANS" }; +#endif + +int get_card_from_id(int driver) +{ + int i; + + for(i = 0 ; i < cinst ; i++) { + if(adapter[i]->driverId == driver) + return i; + } + return -NODEV; +} + +/* + * command + */ + +int command(isdn_ctrl *cmd) +{ + int card; + + card = get_card_from_id(cmd->driver); + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + pr_debug("%s: Received %s command from Link Layer\n", + adapter[card]->devicename, commands[cmd->command]); + + /* + * Dispatch the command + */ + switch(cmd->command) { + case ISDN_CMD_IOCTL: + { + unsigned long cmdptr; + scs_ioctl ioc; + int err; + + memcpy(&cmdptr, cmd->parm.num, sizeof(unsigned long)); + if((err = verify_area(VERIFY_READ, + (scs_ioctl *) cmdptr, sizeof(scs_ioctl)))) { + pr_debug("%s: Failed to verify user space 0x%x\n", + adapter[card]->devicename, cmdptr); + return err; + + } + copy_from_user(&ioc, (scs_ioctl *) cmdptr, + sizeof(scs_ioctl)); + return sc_ioctl(card, &ioc); + } + case ISDN_CMD_DIAL: + return dial(card, cmd->arg, cmd->parm.setup); + case ISDN_CMD_HANGUP: + return hangup(card, cmd->arg); + case ISDN_CMD_ACCEPTD: + return answer(card, cmd->arg); + case ISDN_CMD_ACCEPTB: + return acceptb(card, cmd->arg); + case ISDN_CMD_CLREAZ: + return clreaz(card, cmd->arg); + case ISDN_CMD_SETEAZ: + return seteaz(card, cmd->arg, cmd->parm.num); + case ISDN_CMD_GETEAZ: + return geteaz(card, cmd->arg, cmd->parm.num); + case ISDN_CMD_SETSIL: + return setsil(card, cmd->arg, cmd->parm.num); + case ISDN_CMD_GETSIL: + return getsil(card, cmd->arg, cmd->parm.num); + case ISDN_CMD_SETL2: + return setl2(card, cmd->arg); + case ISDN_CMD_GETL2: + return getl2(card, cmd->arg); + case ISDN_CMD_SETL3: + return setl3(card, cmd->arg); + case ISDN_CMD_GETL3: + return getl3(card, cmd->arg); + case ISDN_CMD_LOCK: + return lock(); + case ISDN_CMD_UNLOCK: + return unlock(); + default: + return -EINVAL; + } + return 0; +} + +/* + * Confirm our ability to communicate with the board. This test assumes no + * other message activity is present + */ +int loopback(int card) +{ + + int status; + static char testmsg[] = "Test Message"; + RspMessage rspmsg; + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + pr_debug("%s: Sending loopback message\n", adapter[card]->devicename); + + + /* + * Send the loopback message to confirm that memory transfer is + * operational + */ + status = send_and_receive(card, CMPID, cmReqType1, + cmReqClass0, + cmReqMsgLpbk, + 0, + (unsigned char) strlen(testmsg), + (unsigned char *)testmsg, + &rspmsg, SAR_TIMEOUT); + + + if (!status) { + pr_debug("%s: Loopback message successfully sent\n", + adapter[card]->devicename); + if(strcmp(rspmsg.msg_data.byte_array, testmsg)) { + pr_debug("%s: Loopback return != sent\n", + adapter[card]->devicename); + return -EIO; + } + return 0; + } + else { + pr_debug("%s: Send loopback message failed\n", + adapter[card]->devicename); + return -EIO; + } + +} + +/* + * start the onboard firmware + */ +int startproc(int card) +{ + int status; + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + /* + * send start msg + */ + status = sendmessage(card, CMPID,cmReqType2, + cmReqClass0, + cmReqStartProc, + 0,0,0); + pr_debug("%s: Sent startProc\n", adapter[card]->devicename); + + return status; +} + + +int loadproc(int card, char *data) +{ + return -1; +} + + +/* + * Dials the number passed in + */ +int dial(int card, unsigned long channel, setup_parm setup) +{ + int status; + char Phone[48]; + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + /*extract ISDN number to dial from eaz/msn string*/ + strcpy(Phone,setup.phone); + + /*send the connection message*/ + status = sendmessage(card, CEPID,ceReqTypePhy, + ceReqClass1, + ceReqPhyConnect, + (unsigned char) channel+1, + strlen(Phone), + (unsigned int *) Phone); + + pr_debug("%s: Dialing %s on channel %d\n", + adapter[card]->devicename, Phone, channel+1); + + return status; +} + +/* + * Answer an incoming call + */ +int answer(int card, unsigned long channel) +{ + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + if(setup_buffers(card, channel+1, BUFFER_SIZE)) { + hangup(card, channel+1); + return -ENOBUFS; + } + + indicate_status(card, ISDN_STAT_BCONN,channel,NULL); + pr_debug("%s: Answered incoming call on channel %s\n", + adapter[card]->devicename, channel+1); + return 0; +} + +/* + * Hangup up the call on specified channel + */ +int hangup(int card, unsigned long channel) +{ + int status; + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + status = sendmessage(card, CEPID, ceReqTypePhy, + ceReqClass1, + ceReqPhyDisconnect, + (unsigned char) channel+1, + 0, + NULL); + pr_debug("%s: Sent HANGUP message to channel %d\n", + adapter[card]->devicename, channel+1); + return status; +} + +/* + * Set the layer 2 protocol (X.25, HDLC, Raw) + */ +int setl2(int card, unsigned long arg) +{ + int status =0; + int protocol,channel; + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + protocol = arg >> 8; + channel = arg & 0xff; + adapter[card]->channel[channel].l2_proto = protocol; + pr_debug("%s: Level 2 protocol for channel %d set to %s from %d\n", + adapter[card]->devicename, channel+1,l2protos[adapter[card]->channel[channel].l2_proto],protocol); + + /* + * check that the adapter is also set to the correct protocol + */ + pr_debug("%s: Sending GetFrameFormat for channel %d\n", + adapter[card]->devicename, channel+1); + status = sendmessage(card, CEPID, ceReqTypeCall, + ceReqClass0, + ceReqCallGetFrameFormat, + (unsigned char)channel+1, + 1, + (unsigned int *) protocol); + if(status) + return status; + return 0; +} + +/* + * Get the layer 2 protocol + */ +int getl2(int card, unsigned long channel) { + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + pr_debug("%s: Level 2 protocol for channel %d reported as %s\n", + adapter[card]->devicename, channel+1, + l2protos[adapter[card]->channel[channel].l2_proto]); + + return adapter[card]->channel[channel].l2_proto; +} + +/* + * Set the layer 3 protocol + */ +int setl3(int card, unsigned long channel) +{ + int protocol = channel >> 8; + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + adapter[card]->channel[channel].l3_proto = protocol; + pr_debug("%s: Level 3 protocol for channel %d set to %s\n", + adapter[card]->devicename, channel+1, l3protos[protocol]); + return 0; +} + +/* + * Get the layer 3 protocol + */ +int getl3(int card, unsigned long arg) +{ + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + pr_debug("%s: Level 3 protocol for channel %d reported as %s\n", + adapter[card]->devicename, arg+1, + l3protos[adapter[card]->channel[arg].l3_proto]); + return adapter[card]->channel[arg].l3_proto; +} + + +int acceptb(int card, unsigned long channel) +{ + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + if(setup_buffers(card, channel+1, BUFFER_SIZE)) + { + hangup(card, channel+1); + return -ENOBUFS; + } + + pr_debug("%s: B-Channel connection accepted on channel %d\n", + adapter[card]->devicename, channel+1); + indicate_status(card, ISDN_STAT_BCONN, channel, NULL); + return 0; +} + +int clreaz(int card, unsigned long arg) +{ + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + strcpy(adapter[card]->channel[arg].eazlist, ""); + adapter[card]->channel[arg].eazclear = 1; + pr_debug("%s: EAZ List cleared for channel %d\n", + adapter[card]->devicename, arg+1); + return 0; +} + +int seteaz(int card, unsigned long arg, char *num) +{ + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + strcpy(adapter[card]->channel[arg].eazlist, num); + adapter[card]->channel[arg].eazclear = 0; + pr_debug("%s: EAZ list for channel %d set to: %s\n", + adapter[card]->devicename, arg+1, + adapter[card]->channel[arg].eazlist); + return 0; +} + +int geteaz(int card, unsigned long arg, char *num) +{ + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + strcpy(num, adapter[card]->channel[arg].eazlist); + pr_debug("%s: EAZ List for channel %d reported: %s\n", + adapter[card]->devicename, arg+1, + adapter[card]->channel[arg].eazlist); + return 0; +} + +int setsil(int card, unsigned long arg, char *num) +{ + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + strcpy(adapter[card]->channel[arg].sillist, num); + pr_debug("%s: Service Indicators for channel %d set: %s\n", + adapter[card]->devicename, arg+1, + adapter[card]->channel[arg].sillist); + return 0; +} + +int getsil(int card, unsigned long arg, char *num) +{ + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + strcpy(num, adapter[card]->channel[arg].sillist); + pr_debug("%s: SIL for channel %d reported: %s\n", + adapter[card]->devicename, arg+1, + adapter[card]->channel[arg].sillist); + return 0; +} + + +int lock() +{ + MOD_INC_USE_COUNT; + return 0; +} + +int unlock() +{ + MOD_DEC_USE_COUNT; + return 0; +} + +int reset(int card) +{ + unsigned long flags; + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + indicate_status(card, ISDN_STAT_STOP, 0, NULL); + + if(adapter[card]->EngineUp) { + del_timer(&adapter[card]->stat_timer); + } + + adapter[card]->EngineUp = 0; + + save_flags(flags); + cli(); + init_timer(&adapter[card]->reset_timer); + adapter[card]->reset_timer.function = check_reset; + adapter[card]->reset_timer.data = card; + adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME; + add_timer(&adapter[card]->reset_timer); + restore_flags(flags); + + outb(0x1,adapter[card]->ioport[SFT_RESET]); + + pr_debug("%s: Adapter Reset\n", adapter[card]->devicename); + return 0; +} + +void flushreadfifo (int card) +{ + while(inb(adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA) + inb(adapter[card]->ioport[FIFO_READ]); +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/sc/debug.c linux/drivers/isdn/sc/debug.c --- v2.1.26/linux/drivers/isdn/sc/debug.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/sc/debug.c Tue Feb 25 17:12:50 1997 @@ -0,0 +1,80 @@ +/* + * $Id: debug.c,v 1.2 1996/11/20 17:49:50 fritz Exp $ + * Copyright (C) 1996 SpellCaster Telecommunications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * For more information, please contact gpl-info@spellcast.com or write: + * + * SpellCaster Telecommunications Inc. + * 5621 Finch Avenue East, Unit #3 + * Scarborough, Ontario Canada + * M1B 2T9 + * +1 (416) 297-8565 + * +1 (416) 297-6433 Facsimile + */ +#include + +#define NULL 0x0 + +#if LINUX_VERSION_CODE < 66363 /* Linux 1.3.59 there was a change to interrupts */ + #define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d) + #define FREE_IRQ(a,b) free_irq(a) +#else + #define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e) + #define FREE_IRQ(a,b) free_irq(a,b) +#endif + +inline char *strcpy(char *, const char *); + +int dbg_level = 0; +static char dbg_funcname[255]; + +void dbg_endfunc(void) +{ + if (dbg_level) { + printk("<-- Leaving function %s\n", dbg_funcname); + strcpy(dbg_funcname, ""); + } +} + +void dbg_func(char *func) +{ + strcpy(dbg_funcname, func); + if(dbg_level) + printk("--> Entering function %s\n", dbg_funcname); +} + +inline char *strcpy(char *dest, const char *src) +{ + char *i = dest; + char *j = (char *) src; + + while(*j) { + *i = *j; + i++; j++; + } + *(++i) = NULL; + return dest; +} + +inline void pullphone(char *dn, char *str) +{ + int i = 0; + + while(dn[i] != ',') + str[i] = dn[i++]; + str[i] = 0x0; +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/sc/debug.h linux/drivers/isdn/sc/debug.h --- v2.1.26/linux/drivers/isdn/sc/debug.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/sc/debug.h Tue Feb 25 17:12:50 1997 @@ -0,0 +1,35 @@ +/* + * $Id: debug.h,v 1.1 1996/11/07 13:07:42 fritz Exp $ + * Copyright (C) 1996 SpellCaster Telecommunications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * For more information, please contact gpl-info@spellcast.com or write: + * + * SpellCaster Telecommunications Inc. + * 5621 Finch Avenue East, Unit #3 + * Scarborough, Ontario Canada + * M1B 2T9 + * +1 (416) 297-8565 + * +1 (416) 297-6433 Facsimile + */ + +#if LINUX_VERSION_CODE < 131072 + #error You cant use this driver on kernels older than 2.0 +#else + #define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e) + #define FREE_IRQ(a,b) free_irq(a,b) +#endif + diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/sc/event.c linux/drivers/isdn/sc/event.c --- v2.1.26/linux/drivers/isdn/sc/event.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/sc/event.c Tue Feb 25 17:12:50 1997 @@ -0,0 +1,75 @@ +/* + * $Id: event.c,v 1.3 1997/02/11 22:53:41 fritz Exp $ + * Copyright (C) 1996 SpellCaster Telecommunications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * For more information, please contact gpl-info@spellcast.com or write: + * + * SpellCaster Telecommunications Inc. + * 5621 Finch Avenue East, Unit #3 + * Scarborough, Ontario Canada + * M1B 2T9 + * +1 (416) 297-8565 + * +1 (416) 297-6433 Facsimile + */ + +#define __NO_VERSION__ +#include "includes.h" +#include "hardware.h" +#include "message.h" +#include "card.h" + +extern int cinst; +extern board *adapter[]; + +#ifdef DEBUG +static char *events[] = { "ISDN_STAT_STAVAIL", + "ISDN_STAT_ICALL", + "ISDN_STAT_RUN", + "ISDN_STAT_STOP", + "ISDN_STAT_DCONN", + "ISDN_STAT_BCONN", + "ISDN_STAT_DHUP", + "ISDN_STAT_BHUP", + "ISDN_STAT_CINF", + "ISDN_STAT_LOAD", + "ISDN_STAT_UNLOAD", + "ISDN_STAT_BSENT", + "ISDN_STAT_NODCH", + "ISDN_STAT_ADDCH", + "ISDN_STAT_CAUSE" }; +#endif + +int indicate_status(int card, int event,ulong Channel,char *Data) +{ + isdn_ctrl cmd; + + pr_debug("%s: Indicating event %s on Channel %d\n", + adapter[card]->devicename, events[event-256], Channel); + if (Data != NULL){ + pr_debug("%s: Event data: %s\n", adapter[card]->devicename, + Data); + if (event == ISDN_STAT_ICALL) + memcpy(&cmd.parm.setup, Data, sizeof(cmd.parm.setup)); + else + strcpy(cmd.parm.num, Data); + } + + cmd.command = event; + cmd.driver = adapter[card]->driverId; + cmd.arg = Channel; + return adapter[card]->card->statcallb(&cmd); +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/sc/hardware.h linux/drivers/isdn/sc/hardware.h --- v2.1.26/linux/drivers/isdn/sc/hardware.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/sc/hardware.h Tue Feb 25 17:12:50 1997 @@ -0,0 +1,117 @@ +/* + * Hardware specific macros, defines and structures + */ + +#ifndef HARDWARE_H +#define HARDWARE_H + +#include /* For HZ */ + +/* + * General hardware parameters common to all ISA adapters + */ + +#define MAX_CARDS 4 /* The maximum number of cards to + control or probe for. If you change + this, you must also change the number + of elements in io, irq, and ram to + match. Initialized in init.c */ +/* +extern unsigned int io[]; +extern unsigned char irq[]; +extern unsigned long ram[]; +*/ + +#define SIGNATURE 0x87654321 /* Board reset signature */ +#define SIG_OFFSET 0x1004 /* Where to find signature in shared RAM */ +#define TRACE_OFFSET 0x1008 /* Trace enable word offset in shared RAM */ +#define BUFFER_OFFSET 0x1800 /* Beginning of buffers */ + +/* I/O Port parameters */ +#define IOBASE_MIN 0x180 /* Lowest I/O port address */ +#define IOBASE_MAX 0x3C0 /* Highest I/O port address */ +#define IOBASE_OFFSET 0x20 /* Inter-board I/O port gap used during + probing */ +#define FIFORD_OFFSET 0x0 +#define FIFOWR_OFFSET 0x400 +#define FIFOSTAT_OFFSET 0x1000 +#define RESET_OFFSET 0x2800 +#define PG0_OFFSET 0x3000 /* Offset from I/O Base for Page 0 register */ +#define PG1_OFFSET 0x3400 /* Offset from I/O Base for Page 1 register */ +#define PG2_OFFSET 0x3800 /* Offset from I/O Base for Page 2 register */ +#define PG3_OFFSET 0x3C00 /* Offset from I/O Base for Page 3 register */ + +#define FIFO_READ 0 /* FIFO Read register */ +#define FIFO_WRITE 1 /* FIFO Write rgister */ +#define LO_ADDR_PTR 2 /* Extended RAM Low Addr Pointer */ +#define HI_ADDR_PTR 3 /* Extended RAM High Addr Pointer */ +#define NOT_USED_1 4 +#define FIFO_STATUS 5 /* FIFO Status Register */ +#define NOT_USED_2 6 +#define MEM_OFFSET 7 +#define SFT_RESET 10 /* Reset Register */ +#define EXP_BASE 11 /* Shared RAM Base address */ +#define EXP_PAGE0 12 /* Shared RAM Page0 register */ +#define EXP_PAGE1 13 /* Shared RAM Page1 register */ +#define EXP_PAGE2 14 /* Shared RAM Page2 register */ +#define EXP_PAGE3 15 /* Shared RAM Page3 register */ +#define IRQ_SELECT 16 /* IRQ selection register */ +#define MAX_IO_REGS 17 /* Total number of I/O ports */ + +/* FIFO register values */ +#define RF_HAS_DATA 0x01 /* fifo has data */ +#define RF_QUART_FULL 0x02 /* fifo quarter full */ +#define RF_HALF_FULL 0x04 /* fifo half full */ +#define RF_NOT_FULL 0x08 /* fifo not full */ +#define WF_HAS_DATA 0x10 /* fifo has data */ +#define WF_QUART_FULL 0x20 /* fifo quarter full */ +#define WF_HALF_FULL 0x40 /* fifo half full */ +#define WF_NOT_FULL 0x80 /* fifo not full */ + +/* Shared RAM parameters */ +#define SRAM_MIN 0xC0000 /* Lowest host shared RAM address */ +#define SRAM_MAX 0xEFFFF /* Highest host shared RAM address */ +#define SRAM_PAGESIZE 0x4000 /* Size of one RAM page (16K) */ + +/* Shared RAM buffer parameters */ +#define BUFFER_SIZE 0x800 /* The size of a buffer in bytes */ +#define BUFFER_BASE BUFFER_OFFSET /* Offset from start of shared RAM + where buffer start */ +#define BUFFERS_MAX 16 /* Maximum number of send/receive + buffers per channel */ +#define HDLC_PROTO 0x01 /* Frame Format for Layer 2 */ + +#define BRI_BOARD 0 +#define POTS_BOARD 1 +#define PRI_BOARD 2 + +/* + * Specific hardware parameters for the DataCommute/BRI + */ +#define BRI_CHANNELS 2 /* Number of B channels */ +#define BRI_BASEPG_VAL 0x98 +#define BRI_MAGIC 0x60000 /* Magic Number */ +#define BRI_MEMSIZE 0x10000 /* Ammount of RAM (64K) */ +#define BRI_PARTNO "72-029" +#define BRI_FEATURES ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L3_TRANS; +/* + * Specific hardware parameters for the DataCommute/PRI + */ +#define PRI_CHANNELS 23 /* Number of B channels */ +#define PRI_BASEPG_VAL 0x88 +#define PRI_MAGIC 0x20000 /* Magic Number */ +#define PRI_MEMSIZE 0x100000 /* Amount of RAM (1M) */ +#define PRI_PARTNO "72-030" +#define PRI_FEATURES ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L3_TRANS; + +/* + * Some handy macros + */ + +/* Return the number of jiffies in a given number of msecs */ +#define milliseconds(x) (x/(1000/HZ)) + +/* Determine if a channel number is valid for the adapter */ +#define IS_VALID_CHANNEL(y,x) ((x>0) && (x <= adapter[y]->channels)) + +#endif diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/sc/includes.h linux/drivers/isdn/sc/includes.h --- v2.1.26/linux/drivers/isdn/sc/includes.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/sc/includes.h Tue Feb 25 17:12:50 1997 @@ -0,0 +1,15 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "debug.h" diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/sc/init.c linux/drivers/isdn/sc/init.c --- v2.1.26/linux/drivers/isdn/sc/init.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/sc/init.c Tue Feb 25 17:12:50 1997 @@ -0,0 +1,599 @@ +#include "includes.h" +#include "hardware.h" +#include "card.h" + +board *adapter[MAX_CARDS]; +int cinst; + +static char devname[] = "scX"; +const char version[] = "2.0b1"; + +const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCommute/BRI" }; + +/* insmod set parameters */ +unsigned int io[] = {0,0,0,0}; +unsigned char irq[] = {0,0,0,0}; +unsigned long ram[] = {0,0,0,0}; +int do_reset = 0; + +static int sup_irq[] = { 11, 10, 9, 5, 12, 14, 7, 3, 4, 6 }; +#define MAX_IRQS 10 + +extern void interrupt_handler(int, void *, struct pt_regs *); +extern int sndpkt(int, int, struct sk_buff *); +extern int command(isdn_ctrl *); +extern int indicate_status(int, int, ulong, char*); +extern int reset(int); + +int identify_board(unsigned long, unsigned int); + +int irq_supported(int irq_x) +{ + int i; + for(i=0 ; i < MAX_IRQS ; i++) { + if(sup_irq[i] == irq_x) + return 1; + } + return 0; +} + +#ifdef MODULE +#if (LINUX_VERSION_CODE > 0x020111) +MODULE_PARM(io, "1-4i"); +MODULE_PARM(irq, "1-4i"); +MODULE_PARM(ram, "1-4i"); +MODULE_PARM(do_reset, "i"); +#endif +#define init_sc init_module +#else +/* +Initialization code for non-module version to be included + +void sc_setup(char *str, int *ints) +{ +} +*/ +#endif + +int init_sc(void) +{ + int b = -1; + int i, j; + int status = -ENODEV; + + unsigned long memsize = 0; + unsigned long features = 0; + isdn_if *interface; + unsigned char channels; + unsigned char pgport; + unsigned long magic; + int model; + int last_base = IOBASE_MIN; + int probe_exhasted = 0; + +#ifdef MODULE + pr_info("SpellCaster ISA ISDN Adapter Driver rev. %s Loaded\n", version); +#else + pr_info("SpellCaster ISA ISDN Adapter Driver rev. %s\n", version); +#endif + pr_info("Copyright (C) 1996 SpellCaster Telecommunications Inc.\n"); + + while(b++ < MAX_CARDS - 1) { + pr_debug("Probing for adapter #%d\n", b); + /* + * Initialize reusable variables + */ + model = -1; + magic = 0; + channels = 0; + pgport = 0; + + /* + * See if we should probe for IO base + */ + pr_debug("I/O Base for board %d is 0x%x, %s probe\n", b, io[b], + io[b] == 0 ? "will" : "won't"); + if(io[b]) { + /* + * No, I/O Base has been provided + */ + for (i = 0 ; i < MAX_IO_REGS - 1 ; i++) { + if(check_region(io[b] + i * 0x400, 1)) { + pr_debug("check_region for 0x%x failed\n", io[b] + i * 0x400); + io[b] = 0; + break; + } + } + + /* + * Confirm the I/O Address with a test + */ + if(io[b] == 0) { + pr_debug("I/O Address 0x%x is in use.\n"); + continue; + } + + outb(0x18, io[b] + 0x400 * EXP_PAGE0); + if(inb(io[b] + 0x400 * EXP_PAGE0) != 0x18) { + pr_debug("I/O Base 0x%x fails test\n"); + continue; + } + } + else { + /* + * Yes, probe for I/O Base + */ + if(probe_exhasted) { + pr_debug("All probe addresses exhasted, skipping\n"); + continue; + } + pr_debug("Probing for I/O...\n"); + for (i = last_base ; i <= IOBASE_MAX ; i += IOBASE_OFFSET) { + int found_io = 1; + if (i == IOBASE_MAX) { + probe_exhasted = 1; /* No more addresses to probe */ + pr_debug("End of Probes\n"); + } + last_base = i + IOBASE_OFFSET; + pr_debug(" checking 0x%x...", i); + for ( j = 0 ; j < MAX_IO_REGS - 1 ; j++) { + if(check_region(i + j * 0x400, 1)) { + pr_debug("Failed\n"); + found_io = 0; + break; + } + } + + if(found_io) { + io[b] = i; + outb(0x18, io[b] + 0x400 * EXP_PAGE0); + if(inb(io[b] + 0x400 * EXP_PAGE0) != 0x18) { + pr_debug("Failed by test\n"); + continue; + } + pr_debug("Passed\n"); + break; + } + } + if(probe_exhasted) { + continue; + } + } + + /* + * See if we should probe for shared RAM + */ + if(do_reset) { + pr_debug("Doing a SAFE probe reset\n"); + outb(0xFF, io[b] + RESET_OFFSET); + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + milliseconds(10000); + schedule(); + } + pr_debug("RAM Base for board %d is 0x%x, %s probe\n", b, ram[b], + ram[b] == 0 ? "will" : "won't"); + + if(ram[b]) { + /* + * No, the RAM base has been provided + * Just look for a signature and ID the + * board model + */ + if(!check_region(ram[b], SRAM_PAGESIZE)) { + pr_debug("check_region for RAM base 0x%x succeeded\n", ram[b]); + model = identify_board(ram[b], io[b]); + } + } + else { + /* + * Yes, probe for free RAM and look for + * a signature and id the board model + */ + for (i = SRAM_MIN ; i < SRAM_MAX ; i += SRAM_PAGESIZE) { + pr_debug("Checking RAM address 0x%x...\n", i); + if(!check_region(i, SRAM_PAGESIZE)) { + pr_debug(" check_region succeeded\n"); + model = identify_board(i, io[b]); + if (model >= 0) { + pr_debug(" Identified a %s\n", + boardname[model]); + ram[b] = i; + break; + } + pr_debug(" Unidentifed or inaccessible\n"); + continue; + } + pr_debug(" check_region failed\n"); + } + } + /* + * See if we found free RAM and the board model + */ + if(!ram[b] || model < 0) { + /* + * Nope, there was no place in RAM for the + * board, or it couldn't be identified + */ + pr_debug("Failed to find an adapter at 0x%x\n", ram[b]); + continue; + } + + /* + * Set the board's magic number, memory size and page register + */ + switch(model) { + case PRI_BOARD: + channels = 23; + magic = 0x20000; + memsize = 0x100000; + features = PRI_FEATURES; + break; + + case BRI_BOARD: + case POTS_BOARD: + channels = 2; + magic = 0x60000; + memsize = 0x10000; + features = BRI_FEATURES; + break; + } + switch(ram[b] >> 12 & 0x0F) { + case 0x0: + pr_debug("RAM Page register set to EXP_PAGE0\n"); + pgport = EXP_PAGE0; + break; + + case 0x4: + pr_debug("RAM Page register set to EXP_PAGE1\n"); + pgport = EXP_PAGE1; + break; + + case 0x8: + pr_debug("RAM Page register set to EXP_PAGE2\n"); + pgport = EXP_PAGE2; + break; + + case 0xC: + pr_debug("RAM Page register set to EXP_PAGE3\n"); + pgport = EXP_PAGE3; + break; + + default: + pr_debug("RAM base address doesn't fall on 16K boundary\n"); + continue; + } + + pr_debug("current IRQ: %d b: %d\n",irq[b],b); + /* + * See if we should probe for an irq + */ + if(irq[b]) { + /* + * No we were given one + * See that it is supported and free + */ + pr_debug("Trying for IRQ: %d\n",irq[b]); + if (irq_supported(irq[b])) { + if(REQUEST_IRQ(irq[b], interrupt_handler, + SA_PROBE, "sc_probe", NULL)) { + pr_debug("IRQ %d is already in use\n", + irq[b]); + continue; + } + FREE_IRQ(irq[b], NULL); + } + } + else { + /* + * Yes, we need to probe for an IRQ + */ + pr_debug("Probing for IRQ...\n"); + for (i = 0; i < MAX_IRQS ; i++) { + if(!REQUEST_IRQ(sup_irq[i], interrupt_handler, SA_PROBE, "sc_probe", NULL)) { + pr_debug("Probed for and found IRQ %d\n", sup_irq[i]); + FREE_IRQ(sup_irq[i], NULL); + irq[b] = sup_irq[i]; + break; + } + } + } + + /* + * Make sure we got an IRQ + */ + if(!irq[b]) { + /* + * No interrupt could be used + */ + pr_debug("Failed to aquire an IRQ line\n"); + continue; + } + + /* + * Horray! We found a board, Make sure we can register + * it with ISDN4Linux + */ + interface = kmalloc(sizeof(isdn_if), GFP_KERNEL); + if (interface == NULL) { + /* + * Oops, can't malloc isdn_if + */ + continue; + } + memset(interface, 0, sizeof(isdn_if)); + + interface->hl_hdrlen = 0; + interface->channels = channels; + interface->maxbufsize = BUFFER_SIZE; + interface->features = features; + interface->writebuf_skb = sndpkt; + interface->writecmd = NULL; + interface->command = command; + strcpy(interface->id, devname); + interface->id[2] = '0' + cinst; + + /* + * Allocate the board structure + */ + adapter[cinst] = kmalloc(sizeof(board), GFP_KERNEL); + if (adapter[cinst] == NULL) { + /* + * Oops, can't alloc memory for the board + */ + kfree(interface); + continue; + } + memset(adapter[cinst], 0, sizeof(board)); + + if(!register_isdn(interface)) { + /* + * Oops, couldn't register for some reason + */ + kfree(interface); + kfree(adapter[cinst]); + continue; + } + + adapter[cinst]->card = interface; + adapter[cinst]->driverId = interface->channels; + strcpy(adapter[cinst]->devicename, interface->id); + adapter[cinst]->nChannels = channels; + adapter[cinst]->ramsize = memsize; + adapter[cinst]->shmem_magic = magic; + adapter[cinst]->shmem_pgport = pgport; + adapter[cinst]->StartOnReset = 1; + + /* + * Allocate channels status structures + */ + adapter[cinst]->channel = kmalloc(sizeof(bchan) * channels, GFP_KERNEL); + if (adapter[cinst]->channel == NULL) { + /* + * Oops, can't alloc memory for the channels + */ + indicate_status(cinst, ISDN_STAT_UNLOAD, 0, NULL); /* Fix me */ + kfree(interface); + kfree(adapter[cinst]); + continue; + } + memset(adapter[cinst]->channel, 0, sizeof(bchan) * channels); + + /* + * Lock down the hardware resources + */ + adapter[cinst]->interrupt = irq[b]; + REQUEST_IRQ(adapter[cinst]->interrupt, interrupt_handler, SA_INTERRUPT, + interface->id, NULL); + adapter[cinst]->iobase = io[b]; + for(i = 0 ; i < MAX_IO_REGS - 1 ; i++) { + adapter[cinst]->ioport[i] = io[b] + i * 0x400; + request_region(adapter[cinst]->ioport[i], 1, interface->id); + pr_debug("Requesting I/O Port %#x\n", adapter[cinst]->ioport[i]); + } + adapter[cinst]->ioport[IRQ_SELECT] = io[b] + 0x2; + request_region(adapter[cinst]->ioport[IRQ_SELECT], 1, interface->id); + pr_debug("Requesting I/O Port %#x\n", adapter[cinst]->ioport[IRQ_SELECT]); + adapter[cinst]->rambase = ram[b]; + request_region(adapter[cinst]->rambase, SRAM_PAGESIZE, interface->id); + + pr_info(" %s (%d) - %s %d channels IRQ %d, I/O Base 0x%x, RAM Base 0x%lx\n", + adapter[cinst]->devicename, adapter[cinst]->driverId, + boardname[model], channels, irq[b], io[b], ram[b]); + + /* + * reset the adapter to put things in motion + */ + reset(cinst); + + cinst++; + status = 0; + } + if (status) + pr_info("Failed to find any adapters, driver unloaded\n"); + return status; +} + +#ifdef MODULE +void cleanup_module(void) +{ + int i, j; + + for(i = 0 ; i < cinst ; i++) { + pr_debug("Cleaning up after adapter %d\n", i); + /* + * kill the timers + */ + del_timer(&(adapter[i]->reset_timer)); + del_timer(&(adapter[i]->stat_timer)); + + /* + * Tell I4L we're toast + */ + indicate_status(i, ISDN_STAT_STOP, 0, NULL); + indicate_status(i, ISDN_STAT_UNLOAD, 0, NULL); + + /* + * Release shared RAM + */ + release_region(adapter[i]->rambase, SRAM_PAGESIZE); + + /* + * Release the IRQ + */ + FREE_IRQ(adapter[i]->interrupt, NULL); + + /* + * Reset for a clean start + */ + outb(0xFF, adapter[i]->ioport[SFT_RESET]); + + /* + * Release the I/O Port regions + */ + for(j = 0 ; j < MAX_IO_REGS - 1; j++) { + release_region(adapter[i]->ioport[j], 1); + pr_debug("Releasing I/O Port %#x\n", adapter[i]->ioport[j]); + } + release_region(adapter[i]->ioport[IRQ_SELECT], 1); + pr_debug("Releasing I/O Port %#x\n", adapter[i]->ioport[IRQ_SELECT]); + + /* + * Release any memory we alloced + */ + kfree(adapter[i]->channel); + kfree(adapter[i]->card); + kfree(adapter[i]); + } + pr_info("SpellCaster ISA ISDN Adapter Driver Unloaded.\n"); +} +#endif + +int identify_board(unsigned long rambase, unsigned int iobase) +{ + unsigned int pgport; + unsigned long sig; + DualPortMemory *dpm; + RspMessage rcvmsg; + ReqMessage sndmsg; + HWConfig_pl hwci; + int x; + + pr_debug("Attempting to identify adapter @ 0x%x io 0x%x\n", + rambase, iobase); + + /* + * Enable the base pointer + */ + outb(rambase >> 12, iobase + 0x2c00); + + switch(rambase >> 12 & 0x0F) { + case 0x0: + pgport = iobase + PG0_OFFSET; + pr_debug("Page Register offset is 0x%x\n", PG0_OFFSET); + break; + + case 0x4: + pgport = iobase + PG1_OFFSET; + pr_debug("Page Register offset is 0x%x\n", PG1_OFFSET); + break; + + case 0x8: + pgport = iobase + PG2_OFFSET; + pr_debug("Page Register offset is 0x%x\n", PG2_OFFSET); + break; + + case 0xC: + pgport = iobase + PG3_OFFSET; + pr_debug("Page Register offset is 0x%x\n", PG3_OFFSET); + break; + default: + pr_debug("Invalid rambase 0x%lx\n", rambase); + return -1; + } + + /* + * Try to identify a PRI card + */ + outb(PRI_BASEPG_VAL, pgport); + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + HZ; + schedule(); + sig = readl(rambase + SIG_OFFSET); + pr_debug("Looking for a signature, got 0x%x\n", sig); +#if 0 +/* + * For Gary: + * If it's a timing problem, it should be gone with the above schedule() + * Another possible reason may be the missing volatile in the original + * code. readl() does this for us. + */ + printk(""); /* Hack! Doesn't work without this !!!??? */ +#endif + if(sig == SIGNATURE) + return PRI_BOARD; + + /* + * Try to identify a PRI card + */ + outb(BRI_BASEPG_VAL, pgport); + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + HZ; + schedule(); + sig = readl(rambase + SIG_OFFSET); + pr_debug("Looking for a signature, got 0x%x\n", sig); +#if 0 + printk(""); /* Hack! Doesn't work without this !!!??? */ +#endif + if(sig == SIGNATURE) + return BRI_BOARD; + + return -1; + + /* + * Try to spot a card + */ + sig = readl(rambase + SIG_OFFSET); + pr_debug("Looking for a signature, got 0x%x\n", sig); + if(sig != SIGNATURE) + return -1; + + dpm = (DualPortMemory *) rambase; + + memset(&sndmsg, 0, MSG_LEN); + sndmsg.msg_byte_cnt = 3; + sndmsg.type = cmReqType1; + sndmsg.class = cmReqClass0; + sndmsg.code = cmReqHWConfig; + memcpy_toio(&(dpm->req_queue[dpm->req_head++]), &sndmsg, MSG_LEN); + outb(0, iobase + 0x400); + pr_debug("Sent HWConfig message\n"); + /* + * Wait for the response + */ + x = 0; + while((inb(iobase + FIFOSTAT_OFFSET) & RF_HAS_DATA) && x < 100) { + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + 1; + schedule(); + x++; + } + if(x == 100) { + pr_debug("Timeout waiting for response\n"); + return -1; + } + + memcpy_fromio(&rcvmsg, &(dpm->rsp_queue[dpm->rsp_tail]), MSG_LEN); + pr_debug("Got HWConfig response, status = 0x%x\n", rcvmsg.rsp_status); + memcpy(&hwci, &(rcvmsg.msg_data.HWCresponse), sizeof(HWConfig_pl)); + pr_debug("Hardware Config: Interface: %s, RAM Size: %d, Serial: %s\n" + " Part: %s, Rev: %s\n", + hwci.st_u_sense ? "S/T" : "U", hwci.ram_size, + hwci.serial_no, hwci.part_no, hwci.rev_no); + + if(!strncmp(PRI_PARTNO, hwci.part_no, 6)) + return PRI_BOARD; + if(!strncmp(BRI_PARTNO, hwci.part_no, 6)) + return BRI_BOARD; + + return -1; +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/sc/interrupt.c linux/drivers/isdn/sc/interrupt.c --- v2.1.26/linux/drivers/isdn/sc/interrupt.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/sc/interrupt.c Tue Feb 25 17:12:50 1997 @@ -0,0 +1,258 @@ +/* + * $Id: interrupt.c,v 1.3 1997/02/11 22:53:43 fritz Exp $ + * Copyright (C) 1996 SpellCaster Telecommunications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * For more information, please contact gpl-info@spellcast.com or write: + * + * SpellCaster Telecommunications Inc. + * 5621 Finch Avenue East, Unit #3 + * Scarborough, Ontario Canada + * M1B 2T9 + * +1 (416) 297-8565 + * +1 (416) 297-6433 Facsimile + */ + +#define __NO_VERSION__ +#include "includes.h" +#include "hardware.h" +#include "message.h" +#include "card.h" + +extern indicate_status(int, int, ulong, char *); +extern void check_phystat(unsigned long); +extern void dump_messages(int); +extern int receivemessage(int, RspMessage *); +extern int sendmessage(int, unsigned int, unsigned int, unsigned int, + unsigned int, unsigned int, unsigned int, unsigned int *); +extern void rcvpkt(int, RspMessage *); + +extern int cinst; +extern board *adapter[]; + +int get_card_from_irq(int irq) +{ + int i; + + for(i = 0 ; i < cinst ; i++) { + if(adapter[i]->interrupt == irq) + return i; + } + return -1; +} + +/* + * + */ +void interrupt_handler(int interrupt, void * cardptr, struct pt_regs *regs ) { + + RspMessage rcvmsg; + int channel; + int card; + + card = get_card_from_irq(interrupt); + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return; + } + + pr_debug("%s: Entered Interrupt handler\n", adapter[card]->devicename); + + /* + * Pull all of the waiting messages off the response queue + */ + while (!receivemessage(card, &rcvmsg)) { + /* + * Push the message to the adapter structure for + * send_and_receive to snoop + */ + if(adapter[card]->want_async_messages) + memcpy(&(adapter[card]->async_msg), &rcvmsg, sizeof(RspMessage)); + + channel = (unsigned int) rcvmsg.phy_link_no; + + /* + * Trap Invalid request messages + */ + if(IS_CM_MESSAGE(rcvmsg, 0, 0, Invalid)) { + pr_debug("%s: Invalid request Message, rsp_status = %d\n", + adapter[card]->devicename, rcvmsg.rsp_status); + break; + } + + /* + * Check for a linkRead message + */ + if (IS_CE_MESSAGE(rcvmsg, Lnk, 1, Read)) + { + pr_debug("%s: Received packet 0x%x bytes long at 0x%x\n", + adapter[card]->devicename, + rcvmsg.msg_data.response.msg_len, + rcvmsg.msg_data.response.buff_offset); + rcvpkt(card, &rcvmsg); + continue; + + } + + /* + * Handle a write acknoledgement + */ + if(IS_CE_MESSAGE(rcvmsg, Lnk, 1, Write)) { + pr_debug("%s: Packet Send ACK on channel %d\n", adapter[card]->devicename, + rcvmsg.phy_link_no); + adapter[card]->channel[rcvmsg.phy_link_no-1].free_sendbufs++; + continue; + } + + /* + * Handle a connection message + */ + if (IS_CE_MESSAGE(rcvmsg, Phy, 1, Connect)) + { + unsigned int callid; + setup_parm setup; + pr_debug("%s: Connect message: line %d: status %d: cause 0x%x\n", + adapter[card]->devicename, + rcvmsg.phy_link_no, + rcvmsg.rsp_status, + rcvmsg.msg_data.byte_array[2]); + + memcpy(&callid,rcvmsg.msg_data.byte_array,sizeof(int)); + if(callid>=0x8000 && callid<=0xFFFF) + { + pr_debug("%s: Got Dial-Out Rsp\n", adapter[card]->devicename); + indicate_status(card, ISDN_STAT_DCONN, + (unsigned long)rcvmsg.phy_link_no-1,NULL); + + } + else if(callid>=0x0000 && callid<=0x7FFF) + { + pr_debug("%s: Got Incomming Call\n", adapter[card]->devicename); + strcpy(setup.phone,&(rcvmsg.msg_data.byte_array[4])); + strcpy(setup.eazmsn,adapter[card]->channel[rcvmsg.phy_link_no-1].dn); + setup.si1 = 7; + setup.si2 = 0; + setup.plan = 0; + setup.screen = 0; + + indicate_status(card, ISDN_STAT_ICALL,(unsigned long)rcvmsg.phy_link_no-1,(char *)&setup); + indicate_status(card, ISDN_STAT_DCONN,(unsigned long)rcvmsg.phy_link_no-1,NULL); + } + continue; + } + + /* + * Handle a disconnection message + */ + if (IS_CE_MESSAGE(rcvmsg, Phy, 1, Disconnect)) + { + pr_debug("%s: disconnect message: line %d: status %d: cause 0x%x\n", + adapter[card]->devicename, + rcvmsg.phy_link_no, + rcvmsg.rsp_status, + rcvmsg.msg_data.byte_array[2]); + + indicate_status(card, ISDN_STAT_BHUP,(unsigned long)rcvmsg.phy_link_no-1,NULL); + indicate_status(card, ISDN_STAT_DHUP,(unsigned long)rcvmsg.phy_link_no-1,NULL); + continue; + + } + + /* + * Handle a startProc engine up message + */ + if (IS_CM_MESSAGE(rcvmsg, 5, 0, MiscEngineUp)) { + pr_debug("%s: Received EngineUp message\n", adapter[card]->devicename); + adapter[card]->EngineUp = 1; + sendmessage(card, CEPID,ceReqTypeCall,ceReqClass0,ceReqCallGetMyNumber,1,0,NULL); + sendmessage(card, CEPID,ceReqTypeCall,ceReqClass0,ceReqCallGetMyNumber,2,0,NULL); + init_timer(&adapter[card]->stat_timer); + adapter[card]->stat_timer.function = check_phystat; + adapter[card]->stat_timer.data = card; + adapter[card]->stat_timer.expires = jiffies + CHECKSTAT_TIME; + add_timer(&adapter[card]->stat_timer); + continue; + } + + /* + * Start proc response + */ + if (IS_CM_MESSAGE(rcvmsg, 2, 0, StartProc)) { + pr_debug("%s: StartProc Response Status %d\n", adapter[card]->devicename, + rcvmsg.rsp_status); + continue; + } + + /* + * Handle a GetMyNumber Rsp + */ + if (IS_CE_MESSAGE(rcvmsg,Call,0,GetMyNumber)){ + strcpy(adapter[card]->channel[rcvmsg.phy_link_no-1].dn,rcvmsg.msg_data.byte_array); + continue; + } + + /* + * PhyStatus response + */ + if(IS_CE_MESSAGE(rcvmsg, Phy, 2, Status)) { + unsigned int b1stat, b2stat; + + /* + * Covert the message data to the adapter->phystat code + */ + b1stat = (unsigned int) rcvmsg.msg_data.byte_array[0]; + b2stat = (unsigned int) rcvmsg.msg_data.byte_array[1]; + + adapter[card]->nphystat = (b2stat >> 8) | b1stat; /* endian?? */ + pr_debug("%s: PhyStat is 0x%2x\n", adapter[card]->devicename, + adapter[card]->nphystat); + continue; + } + + + /* + * Handle a GetFramFormat + */ + if(IS_CE_MESSAGE(rcvmsg, Call, 0, GetFrameFormat)) { + if(rcvmsg.msg_data.byte_array[0] != HDLC_PROTO) { + unsigned int proto = HDLC_PROTO; + /* + * Set board format to HDLC if it wasn't already + */ + pr_debug("%s: current frame format: 0x%x, will change to HDLC\n", + adapter[card]->devicename, + rcvmsg.msg_data.byte_array[0]); + sendmessage(card, CEPID, ceReqTypeCall, + ceReqClass0, + ceReqCallSetFrameFormat, + (unsigned char) channel +1, + 1,&proto); + } + continue; + } + + /* + * Hmm... + */ + pr_debug("%s: Received unhandled message (%d,%d,%d) link %d\n", + adapter[card]->devicename, rcvmsg.type, rcvmsg.class, rcvmsg.code, + rcvmsg.phy_link_no); + + } /* while */ + + pr_debug("%s: Exiting Interrupt Handler\n", adapter[card]->devicename); +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/sc/ioctl.c linux/drivers/isdn/sc/ioctl.c --- v2.1.26/linux/drivers/isdn/sc/ioctl.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/sc/ioctl.c Tue Feb 25 17:12:50 1997 @@ -0,0 +1,525 @@ +#define __NO_VERSION__ +#include "includes.h" +#include "hardware.h" +#include "message.h" +#include "card.h" +#include "scioc.h" + +extern int indicate_status(int, int, unsigned long, char *); +extern int startproc(int); +extern int loadproc(int, char *record); +extern int reset(int); +extern int send_and_receive(int, unsigned int, unsigned char,unsigned char, + unsigned char,unsigned char, + unsigned char, unsigned char *, RspMessage *, int); + +extern board *adapter[]; + +#if 0 +static char *ChannelStates[] = { "Idle", "Ready", "Connecting", "Connected", "Disconnecting" }; +#endif + +int GetStatus(int card, boardInfo *); + +/* + * Process private IOCTL messages (typically from scctrl) + */ +int sc_ioctl(int card, scs_ioctl *data) +{ + switch(data->command) { + case SCIOCRESET: /* Perform a hard reset of the adapter */ + { + pr_debug("%s: SCIOCRESET: ioctl received\n", adapter[card]->devicename); + adapter[card]->StartOnReset = 0; + return (reset(card)); + } + + case SCIOCLOAD: + { + RspMessage rcvmsg; + char srec[SCIOC_SRECSIZE]; + int status, err; + + pr_debug("%s: SCIOLOAD: ioctl received\n", adapter[card]->devicename); + if(adapter[card]->EngineUp) { + pr_debug("%s: SCIOCLOAD: Command Failed, LoadProc while engine running.\n", + adapter[card]->devicename); + return -1; + } + + /* + * Get the SRec from user space + */ + if((err = verify_area(VERIFY_READ, (char *) data->dataptr, sizeof(srec)))) + return err; + copy_from_user(srec, (char *) data->dataptr, sizeof(srec)); + + status = send_and_receive(card, CMPID, cmReqType2, cmReqClass0, cmReqLoadProc, + 0, sizeof(srec), srec, &rcvmsg, SAR_TIMEOUT); + if(status) { + pr_debug("%s: SCIOCLOAD: Command Failed, status = %d\n", + adapter[card]->devicename, status); + return -1; + } + else { + pr_debug("%s: SCIOCLOAD: Command Sucessful\n", adapter[card]->devicename); + return 0; + } + } + + case SCIOCSTART: + { + pr_debug("%s: SCIOSTART: ioctl received\n", adapter[card]->devicename); + if(adapter[card]->EngineUp) { + pr_debug("%s: SCIOCSTART: Command Failed, Engine already running.\n", + adapter[card]->devicename); + return -1; + } + + adapter[card]->StartOnReset = 1; + startproc(card); + return 0; + } + + case SCIOCSETSWITCH: + { + RspMessage rcvmsg; + char switchtype; + int status, err; + + pr_debug("%s: SCIOSETSWITCH: ioctl received\n", adapter[card]->devicename); + + /* + * Get the switch type from user space + */ + if((err = verify_area(VERIFY_READ, (char *) data->dataptr, sizeof(char)))) + return err; + copy_from_user(&switchtype, (char *) data->dataptr, sizeof(char)); + + pr_debug("%s: SCIOCSETSWITCH: Setting switch type to %d\n", adapter[card]->devicename, + switchtype); + status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallSetSwitchType, + 0, sizeof(char),&switchtype,&rcvmsg, SAR_TIMEOUT); + if(!status && !rcvmsg.rsp_status) { + pr_debug("%s: SCIOCSETSWITCH: Command Successful\n", adapter[card]->devicename); + return 0; + } + else { + pr_debug("%s: SCIOCSETSWITCH: Command Failed (status = %d)\n", + adapter[card]->devicename, status); + return status; + } + } + + case SCIOCGETSWITCH: + { + RspMessage rcvmsg; + char switchtype; + int status, err; + + pr_debug("%s: SCIOGETSWITCH: ioctl received\n", adapter[card]->devicename); + + /* + * Get the switch type from the board + */ + status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, + ceReqCallGetSwitchType, 0, 0, 0, &rcvmsg, SAR_TIMEOUT); + if (!status && !rcvmsg.rsp_status) { + pr_debug("%s: SCIOCGETSWITCH: Command Sucessful\n", adapter[card]->devicename); + } + else { + pr_debug("%s: SCIOCGETSWITCH: Command Failed (status = %d)\n", + adapter[card]->devicename, status); + return status; + } + + switchtype = rcvmsg.msg_data.byte_array[0]; + + /* + * Package the switch type and send to user space + */ + if((err = verify_area(VERIFY_WRITE, (char *) data->dataptr, sizeof(char)))) + return err; + copy_to_user((char *) data->dataptr, &switchtype, sizeof(char)); + + return 0; + } + + case SCIOCGETSPID: + { + RspMessage rcvmsg; + char spid[SCIOC_SPIDSIZE]; + int status, err; + + pr_debug("%s: SCIOGETSPID: ioctl received\n", adapter[card]->devicename); + + /* + * Get the spid from the board + */ + status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallGetSPID, + data->channel, 0, 0, &rcvmsg, SAR_TIMEOUT); + if (!status) { + pr_debug("%s: SCIOCGETSPID: Command Sucessful\n", adapter[card]->devicename); + } + else { + pr_debug("%s: SCIOCGETSPID: Command Failed (status = %d)\n", + adapter[card]->devicename, status); + return status; + } + strcpy(spid, rcvmsg.msg_data.byte_array); + + /* + * Package the switch type and send to user space + */ + if((err = verify_area(VERIFY_WRITE, (char *) data->dataptr, sizeof(spid)))) + return err; + copy_to_user((char *) data->dataptr, spid, sizeof(spid)); + + return 0; + } + + case SCIOCSETSPID: + { + RspMessage rcvmsg; + char spid[SCIOC_SPIDSIZE]; + int status, err; + + pr_debug("%s: DCBIOSETSPID: ioctl received\n", adapter[card]->devicename); + + /* + * Get the spid from user space + */ + if((err = verify_area(VERIFY_READ, (char *) data->dataptr, + sizeof(spid)))) + return err; + copy_from_user(spid, (char *) data->dataptr, sizeof(spid)); + + pr_debug("%s: SCIOCSETSPID: Setting channel %d spid to %s\n", + adapter[card]->devicename, data->channel, spid); + status = send_and_receive(card, CEPID, ceReqTypeCall, + ceReqClass0, ceReqCallSetSPID, data->channel, + strlen(spid), spid, &rcvmsg, SAR_TIMEOUT); + if(!status && !rcvmsg.rsp_status) { + pr_debug("%s: SCIOCSETSPID: Command Successful\n", + adapter[card]->devicename); + return 0; + } + else { + pr_debug("%s: SCIOCSETSPID: Command Failed (status = %d)\n", + adapter[card]->devicename, status); + return status; + } + } + + case SCIOCGETDN: + { + RspMessage rcvmsg; + char dn[SCIOC_DNSIZE]; + int status, err; + + pr_debug("%s: SCIOGETDN: ioctl received\n", adapter[card]->devicename); + + /* + * Get the dn from the board + */ + status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallGetMyNumber, + data->channel, 0, 0, &rcvmsg, SAR_TIMEOUT); + if (!status) { + pr_debug("%s: SCIOCGETDN: Command Sucessful\n", adapter[card]->devicename); + } + else { + pr_debug("%s: SCIOCGETDN: Command Failed (status = %d)\n", + adapter[card]->devicename, status); + return status; + } + + strcpy(dn, rcvmsg.msg_data.byte_array); + + /* + * Package the dn and send to user space + */ + if((err = verify_area(VERIFY_WRITE, (char *) data->dataptr, sizeof(dn)))) + return err; + copy_to_user((char *) data->dataptr, dn, sizeof(dn)); + + return 0; + } + + case SCIOCSETDN: + { + RspMessage rcvmsg; + char dn[SCIOC_DNSIZE]; + int status, err; + + pr_debug("%s: SCIOSETDN: ioctl received\n", adapter[card]->devicename); + + /* + * Get the spid from user space + */ + if((err = verify_area(VERIFY_READ, (char *) data->dataptr, + sizeof(dn)))) + return err; + copy_from_user(dn, (char *) data->dataptr, sizeof(dn)); + + pr_debug("%s: SCIOCSETDN: Setting channel %d dn to %s\n", + adapter[card]->devicename, data->channel, dn); + status = send_and_receive(card, CEPID, ceReqTypeCall, + ceReqClass0, ceReqCallSetMyNumber, data->channel, + strlen(dn),dn,&rcvmsg, SAR_TIMEOUT); + if(!status && !rcvmsg.rsp_status) { + pr_debug("%s: SCIOCSETDN: Command Successful\n", + adapter[card]->devicename); + return 0; + } + else { + pr_debug("%s: SCIOCSETDN: Command Failed (status = %d)\n", + adapter[card]->devicename, status); + return status; + } + } + + case SCIOCTRACE: + + pr_debug("%s: SCIOTRACE: ioctl received\n", adapter[card]->devicename); +/* adapter[card]->trace = !adapter[card]->trace; + pr_debug("%s: SCIOCTRACE: Tracing turned %s\n", adapter[card]->devicename, + adapter[card]->trace ? "ON" : "OFF"); */ + break; + + case SCIOCSTAT: + { + boardInfo bi; + int err; + + pr_debug("%s: SCIOSTAT: ioctl received\n", adapter[card]->devicename); + GetStatus(card, &bi); + if((err = verify_area(VERIFY_WRITE, (boardInfo *) data->dataptr, + sizeof(boardInfo)))) + return err; + + copy_to_user((boardInfo *) data->dataptr, &bi, sizeof(boardInfo)); + + return 0; + } + + case SCIOCGETSPEED: + { + RspMessage rcvmsg; + char speed; + int status, err; + + pr_debug("%s: SCIOGETSPEED: ioctl received\n", adapter[card]->devicename); + + /* + * Get the speed from the board + */ + status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, + ceReqCallGetCallType, data->channel, 0, 0, &rcvmsg, SAR_TIMEOUT); + if (!status && !rcvmsg.rsp_status) { + pr_debug("%s: SCIOCGETSPEED: Command Sucessful\n", + adapter[card]->devicename); + } + else { + pr_debug("%s: SCIOCGETSPEED: Command Failed (status = %d)\n", + adapter[card]->devicename, status); + return status; + } + + speed = rcvmsg.msg_data.byte_array[0]; + + /* + * Package the switch type and send to user space + */ + if((err = verify_area(VERIFY_WRITE, (char *) data->dataptr, sizeof(char)))) + return err; + copy_to_user((char *) data->dataptr, &speed, sizeof(char)); + + return 0; + } + + case SCIOCSETSPEED: + pr_debug("%s: SCIOCSETSPEED: ioctl received\n", adapter[card]->devicename); + break; + + case SCIOCLOOPTST: + pr_debug("%s: SCIOCLOOPTST: ioctl received\n", adapter[card]->devicename); + break; + + default: + return -1; + } + + return 0; +} + +int GetStatus(int card, boardInfo *bi) +{ + RspMessage rcvmsg; + int i, status; + + /* + * Fill in some of the basic info about the board + */ + bi->modelid = adapter[card]->model; + strcpy(bi->serial_no, adapter[card]->hwconfig.serial_no); + strcpy(bi->part_no, adapter[card]->hwconfig.part_no); + bi->iobase = adapter[card]->iobase; + bi->rambase = adapter[card]->rambase; + bi->irq = adapter[card]->interrupt; + bi->ramsize = adapter[card]->hwconfig.ram_size; + bi->interface = adapter[card]->hwconfig.st_u_sense; + strcpy(bi->load_ver, adapter[card]->load_ver); + strcpy(bi->proc_ver, adapter[card]->proc_ver); + + /* + * Get the current PhyStats and LnkStats + */ + status = send_and_receive(card, CEPID, ceReqTypePhy, ceReqClass2, + ceReqPhyStatus, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); + if(!status) { + if(adapter[card]->model < PRI_BOARD) { + bi->l1_status = rcvmsg.msg_data.byte_array[2]; + for(i = 0 ; i < BRI_CHANNELS ; i++) + bi->status.bristats[i].phy_stat = + rcvmsg.msg_data.byte_array[i]; + } + else { + bi->l1_status = rcvmsg.msg_data.byte_array[0]; + bi->l2_status = rcvmsg.msg_data.byte_array[1]; + for(i = 0 ; i < PRI_CHANNELS ; i++) + bi->status.pristats[i].phy_stat = + rcvmsg.msg_data.byte_array[i+2]; + } + } + + /* + * Get the call types for each channel + */ + for (i = 0 ; i < adapter[card]->nChannels ; i++) { + status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, + ceReqCallGetCallType, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); + if(!status) { + if (adapter[card]->model == PRI_BOARD) { + bi->status.pristats[i].call_type = + rcvmsg.msg_data.byte_array[0]; + } + else { + bi->status.bristats[i].call_type = + rcvmsg.msg_data.byte_array[0]; + } + } + } + + /* + * If PRI, get the call states and service states for each channel + */ + if (adapter[card]->model == PRI_BOARD) { + /* + * Get the call states + */ + status = send_and_receive(card, CEPID, ceReqTypeStat, ceReqClass2, + ceReqPhyChCallState, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); + if(!status) { + for( i = 0 ; i < PRI_CHANNELS ; i++ ) + bi->status.pristats[i].call_state = + rcvmsg.msg_data.byte_array[i]; + } + + /* + * Get the service states + */ + status = send_and_receive(card, CEPID, ceReqTypeStat, ceReqClass2, + ceReqPhyChServState, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); + if(!status) { + for( i = 0 ; i < PRI_CHANNELS ; i++ ) + bi->status.pristats[i].serv_state = + rcvmsg.msg_data.byte_array[i]; + } + + /* + * Get the link stats for the channels + */ + for (i = 1 ; i <= PRI_CHANNELS ; i++) { + status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0, + ceReqLnkGetStats, i, 0, NULL, &rcvmsg, SAR_TIMEOUT); + if (!status) { + bi->status.pristats[i-1].link_stats.tx_good = + (unsigned long)rcvmsg.msg_data.byte_array[0]; + bi->status.pristats[i-1].link_stats.tx_bad = + (unsigned long)rcvmsg.msg_data.byte_array[4]; + bi->status.pristats[i-1].link_stats.rx_good = + (unsigned long)rcvmsg.msg_data.byte_array[8]; + bi->status.pristats[i-1].link_stats.rx_bad = + (unsigned long)rcvmsg.msg_data.byte_array[12]; + } + } + + /* + * Link stats for the D channel + */ + status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0, + ceReqLnkGetStats, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); + if (!status) { + bi->dch_stats.tx_good = (unsigned long)rcvmsg.msg_data.byte_array[0]; + bi->dch_stats.tx_bad = (unsigned long)rcvmsg.msg_data.byte_array[4]; + bi->dch_stats.rx_good = (unsigned long)rcvmsg.msg_data.byte_array[8]; + bi->dch_stats.rx_bad = (unsigned long)rcvmsg.msg_data.byte_array[12]; + } + + return 0; + } + + /* + * If BRI or POTS, Get SPID, DN and call types for each channel + */ + + /* + * Get the link stats for the channels + */ + status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0, + ceReqLnkGetStats, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); + if (!status) { + bi->dch_stats.tx_good = (unsigned long)rcvmsg.msg_data.byte_array[0]; + bi->dch_stats.tx_bad = (unsigned long)rcvmsg.msg_data.byte_array[4]; + bi->dch_stats.rx_good = (unsigned long)rcvmsg.msg_data.byte_array[8]; + bi->dch_stats.rx_bad = (unsigned long)rcvmsg.msg_data.byte_array[12]; + bi->status.bristats[0].link_stats.tx_good = + (unsigned long)rcvmsg.msg_data.byte_array[16]; + bi->status.bristats[0].link_stats.tx_bad = + (unsigned long)rcvmsg.msg_data.byte_array[20]; + bi->status.bristats[0].link_stats.rx_good = + (unsigned long)rcvmsg.msg_data.byte_array[24]; + bi->status.bristats[0].link_stats.rx_bad = + (unsigned long)rcvmsg.msg_data.byte_array[28]; + bi->status.bristats[1].link_stats.tx_good = + (unsigned long)rcvmsg.msg_data.byte_array[32]; + bi->status.bristats[1].link_stats.tx_bad = + (unsigned long)rcvmsg.msg_data.byte_array[36]; + bi->status.bristats[1].link_stats.rx_good = + (unsigned long)rcvmsg.msg_data.byte_array[40]; + bi->status.bristats[1].link_stats.rx_bad = + (unsigned long)rcvmsg.msg_data.byte_array[44]; + } + + /* + * Get the SPIDs + */ + for (i = 0 ; i < BRI_CHANNELS ; i++) { + status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, + ceReqCallGetSPID, i+1, 0, NULL, &rcvmsg, SAR_TIMEOUT); + if (!status) + strcpy(bi->status.bristats[i].spid, rcvmsg.msg_data.byte_array); + } + + /* + * Get the DNs + */ + for (i = 0 ; i < BRI_CHANNELS ; i++) { + status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, + ceReqCallGetMyNumber, i+1, 0, NULL, &rcvmsg, SAR_TIMEOUT); + if (!status) + strcpy(bi->status.bristats[i].dn, rcvmsg.msg_data.byte_array); + } + + return 0; +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/sc/message.c linux/drivers/isdn/sc/message.c --- v2.1.26/linux/drivers/isdn/sc/message.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/sc/message.c Tue Feb 25 17:12:50 1997 @@ -0,0 +1,300 @@ +/* + * $Id: message.c,v 1.2 1996/11/20 17:49:54 fritz Exp $ + * Copyright (C) 1996 SpellCaster Telecommunications Inc. + * + * message.c - functions for sending and receiving control messages + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * For more information, please contact gpl-info@spellcast.com or write: + * + * SpellCaster Telecommunications Inc. + * 5621 Finch Avenue East, Unit #3 + * Scarborough, Ontario Canada + * M1B 2T9 + * +1 (416) 297-8565 + * +1 (416) 297-6433 Facsimile + */ + +#define __NO_VERSION__ +#include "includes.h" +#include "hardware.h" +#include "message.h" +#include "card.h" + +extern board *adapter[]; +extern unsigned int cinst; + +/* + * Obligitory function prototypes + */ +extern int indicate_status(int,ulong,char*); +extern int scm_command(isdn_ctrl *); +extern void *memcpy_fromshmem(int, void *, const void *, size_t); + +/* + * Dump message queue in shared memory to screen + */ +void dump_messages(int card) +{ + DualPortMemory dpm; + unsigned long flags; + + int i =0; + + if (!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + } + + save_flags(flags); + cli(); + outb(adapter[card]->ioport[adapter[card]->shmem_pgport], + (adapter[card]->shmem_magic >> 14) | 0x80); + memcpy_fromshmem(card, &dpm, 0, sizeof(dpm)); + restore_flags(flags); + + pr_debug("%s: Dumping Request Queue\n", adapter[card]->devicename); + for (i = 0; i < dpm.req_head; i++) { + pr_debug("%s: Message #%d: (%d,%d,%d), link: %d\n", + adapter[card]->devicename, i, + dpm.req_queue[i].type, + dpm.req_queue[i].class, + dpm.req_queue[i].code, + dpm.req_queue[i].phy_link_no); + } + + pr_debug("%s: Dumping Response Queue\n", adapter[card]->devicename); + for (i = 0; i < dpm.rsp_head; i++) { + pr_debug("%s: Message #%d: (%d,%d,%d), link: %d, status: %d\n", + adapter[card]->devicename, i, + dpm.rsp_queue[i].type, + dpm.rsp_queue[i].class, + dpm.rsp_queue[i].code, + dpm.rsp_queue[i].phy_link_no, + dpm.rsp_queue[i].rsp_status); + } + +} + +/* + * receive a message from the board + */ +int receivemessage(int card, RspMessage *rspmsg) +{ + DualPortMemory *dpm; + unsigned long flags; + + if (!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -EINVAL; + } + + pr_debug("%s: Entered receivemessage\n",adapter[card]->devicename); + + /* + * See if there are messages waiting + */ + if (inb(adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA) { + /* + * Map in the DPM to the base page and copy the message + */ + save_flags(flags); + cli(); + outb((adapter[card]->shmem_magic >> 14) | 0x80, + adapter[card]->ioport[adapter[card]->shmem_pgport]); + dpm = (DualPortMemory *) adapter[card]->rambase; + memcpy_fromio(rspmsg, &(dpm->rsp_queue[dpm->rsp_tail]), + MSG_LEN); + dpm->rsp_tail = (dpm->rsp_tail+1) % MAX_MESSAGES; + inb(adapter[card]->ioport[FIFO_READ]); + restore_flags(flags); + + /* + * Tell the board that the message is received + */ + pr_debug("%s: Received Message seq:%d pid:%d time:%d cmd:%d " + "cnt:%d (type,class,code):(%d,%d,%d) " + "link:%d stat:0x%x\n", + adapter[card]->devicename, + rspmsg->sequence_no, + rspmsg->process_id, + rspmsg->time_stamp, + rspmsg->cmd_sequence_no, + rspmsg->msg_byte_cnt, + rspmsg->type, + rspmsg->class, + rspmsg->code, + rspmsg->phy_link_no, + rspmsg->rsp_status); + + return 0; + } + return -ENOMSG; +} + +/* + * send a message to the board + */ +int sendmessage(int card, + unsigned int procid, + unsigned int type, + unsigned int class, + unsigned int code, + unsigned int link, + unsigned int data_len, + unsigned int *data) +{ + DualPortMemory *dpm; + ReqMessage sndmsg; + unsigned long flags; + + if (!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -EINVAL; + } + + /* + * Make sure we only send CEPID messages when the engine is up + * and CMPID messages when it is down + */ + if(adapter[card]->EngineUp && procid == CMPID) { + pr_debug("%s: Attempt to send CM message with engine up\n", + adapter[card]->devicename); + return -ESRCH; + } + + if(!adapter[card]->EngineUp && procid == CEPID) { + pr_debug("%s: Attempt to send CE message with engine down\n", + adapter[card]->devicename); + return -ESRCH; + } + + memset(&sndmsg, 0, MSG_LEN); + sndmsg.msg_byte_cnt = 4; + sndmsg.type = type; + sndmsg.class = class; + sndmsg.code = code; + sndmsg.phy_link_no = link; + + if (data_len > 0) { + if (data_len > MSG_DATA_LEN) + data_len = MSG_DATA_LEN; + memcpy(&(sndmsg.msg_data), data, data_len); + sndmsg.msg_byte_cnt = data_len + 8; + } + + sndmsg.process_id = procid; + sndmsg.sequence_no = adapter[card]->seq_no++ % 256; + + /* + * wait for an empty slot in the queue + */ + while (!(inb(adapter[card]->ioport[FIFO_STATUS]) & WF_NOT_FULL)) + SLOW_DOWN_IO; + + /* + * Disable interrupts and map in shared memory + */ + save_flags(flags); + cli(); + outb((adapter[card]->shmem_magic >> 14) | 0x80, + adapter[card]->ioport[adapter[card]->shmem_pgport]); + dpm = (DualPortMemory *) adapter[card]->rambase; /* Fix me */ + memcpy_toio(&(dpm->req_queue[dpm->req_head]),&sndmsg,MSG_LEN); + dpm->req_head = (dpm->req_head+1) % MAX_MESSAGES; + outb(sndmsg.sequence_no, adapter[card]->ioport[FIFO_WRITE]); + restore_flags(flags); + + pr_debug("%s: Sent Message seq:%d pid:%d time:%d " + "cnt:%d (type,class,code):(%d,%d,%d) " + "link:%d\n ", + adapter[card]->devicename, + sndmsg.sequence_no, + sndmsg.process_id, + sndmsg.time_stamp, + sndmsg.msg_byte_cnt, + sndmsg.type, + sndmsg.class, + sndmsg.code, + sndmsg.phy_link_no); + + return 0; +} + +int send_and_receive(int card, + unsigned int procid, + unsigned char type, + unsigned char class, + unsigned char code, + unsigned char link, + unsigned char data_len, + unsigned char *data, + RspMessage *mesgdata, + int timeout) +{ + int retval; + int tries; + + if (!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -EINVAL; + } + + adapter[card]->want_async_messages = 1; + retval = sendmessage(card, procid, type, class, code, link, + data_len, (unsigned int *) data); + + if (retval) { + pr_debug("%s: SendMessage failed in SAR\n", + adapter[card]->devicename); + adapter[card]->want_async_messages = 0; + return -EIO; + } + + tries = 0; + /* wait for the response */ + while (tries < timeout) { + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + 1; + schedule(); + + pr_debug("SAR waiting..\n"); + + /* + * See if we got our message back + */ + if ((adapter[card]->async_msg.type == type) && + (adapter[card]->async_msg.class == class) && + (adapter[card]->async_msg.code == code) && + (adapter[card]->async_msg.phy_link_no == link)) { + + /* + * Got it! + */ + pr_debug("%s: Got ASYNC message\n", + adapter[card]->devicename); + memcpy(mesgdata, &(adapter[card]->async_msg), + sizeof(RspMessage)); + adapter[card]->want_async_messages = 0; + return 0; + } + + tries++; + } + + pr_debug("%s: SAR message timeout\n", adapter[card]->devicename); + adapter[card]->want_async_messages = 0; + return -ETIME; +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/sc/message.h linux/drivers/isdn/sc/message.h --- v2.1.26/linux/drivers/isdn/sc/message.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/sc/message.h Tue Feb 25 17:12:50 1997 @@ -0,0 +1,256 @@ +/* + * $Id: message.h,v 1.1 1996/11/07 13:07:47 fritz Exp $ + * Copyright (C) 1996 SpellCaster Telecommunications Inc. + * + * message.h - structures, macros and defines useful for sending + * messages to the adapter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * For more information, please contact gpl-info@spellcast.com or write: + * + * SpellCaster Telecommunications Inc. + * 5621 Finch Avenue East, Unit #3 + * Scarborough, Ontario Canada + * M1B 2T9 + * +1 (416) 297-8565 + * +1 (416) 297-6433 Facsimile + */ + +/* + * Board message macros, defines and structures + */ + +#ifndef MESSAGE_H +#define MESSAGE_H + +#define MAX_MESSAGES 32 /* Maximum messages that can be + queued */ +#define MSG_DATA_LEN 48 /* Maximum size of message payload */ +#define MSG_LEN 64 /* Size of a message */ +#define CMPID 0 /* Loader message process ID */ +#define CEPID 64 /* Firmware message process ID */ + +/* + * Macro to determine if a message is a loader message + */ +#define IS_CM_MESSAGE(mesg, tx, cx, dx) \ + ((mesg.type == cmRspType##tx) \ + &&(mesg.class == cmRspClass##cx) \ + &&(mesg.code == cmRsp##dx)) + +/* + * Macro to determine if a message is a firmware message + */ +#define IS_CE_MESSAGE(mesg, tx, cx, dx) \ + ((mesg.type == ceRspType##tx) \ + &&(mesg.class == ceRspClass##cx) \ + &&(mesg.code == ceRsp##tx##dx)) + +/* + * Loader Request and Response Messages + */ + +/* message types */ +#define cmReqType1 1 +#define cmReqType2 2 +#define cmRspType0 0 +#define cmRspType1 1 +#define cmRspType2 2 +#define cmRspType5 5 + +/* message classes */ +#define cmReqClass0 0 +#define cmRspClass0 0 + +/* message codes */ +#define cmReqHWConfig 1 /* 1,0,1 */ +#define cmReqMsgLpbk 2 /* 1,0,2 */ +#define cmReqVersion 3 /* 1,0,3 */ +#define cmReqLoadProc 1 /* 2,0,1 */ +#define cmReqStartProc 2 /* 2,0,2 */ +#define cmReqReadMem 6 /* 2,0,6 */ +#define cmRspHWConfig cmReqHWConfig +#define cmRspMsgLpbk cmReqMsgLpbk +#define cmRspVersion cmReqVersion +#define cmRspLoadProc cmReqLoadProc +#define cmRspStartProc cmReqStartProc +#define cmRspReadMem cmReqReadMem +#define cmRspMiscEngineUp 1 /* 5,0,1 */ +#define cmRspInvalid 0 /* 0,0,0 */ + + +/* + * Firmware Request and Response Messages + */ + +/* message types */ +#define ceReqTypePhy 1 +#define ceReqTypeLnk 2 +#define ceReqTypeCall 3 +#define ceReqTypeStat 1 +#define ceRspTypeErr 0 +#define ceRspTypePhy ceReqTypePhy +#define ceRspTypeLnk ceReqTypeLnk +#define ceRspTypeCall ceReqTypeCall +#define ceRspTypeStat ceReqTypeStat + +/* message classes */ +#define ceReqClass0 0 +#define ceReqClass1 1 +#define ceReqClass2 2 +#define ceReqClass3 3 +#define ceRspClass0 ceReqClass0 +#define ceRspClass1 ceReqClass1 +#define ceRspClass2 ceReqClass2 +#define ceRspClass3 ceReqClass3 + +/* message codes (B) = BRI only, (P) = PRI only, (V) = POTS only */ +#define ceReqPhyProcInfo 1 /* 1,0,1 */ +#define ceReqPhyConnect 1 /* 1,1,1 */ +#define ceReqPhyDisconnect 2 /* 1,1,2 */ +#define ceReqPhySetParams 3 /* 1,1,3 (P) */ +#define ceReqPhyGetParams 4 /* 1,1,4 (P) */ +#define ceReqPhyStatus 1 /* 1,2,1 */ +#define ceReqPhyAcfaStatus 2 /* 1,2,2 (P) */ +#define ceReqPhyChCallState 3 /* 1,2,3 (P) */ +#define ceReqPhyChServState 4 /* 1,2,4 (P) */ +#define ceReqPhyRLoopBack 1 /* 1,3,1 */ +#define ceRspPhyProcInfo ceReqPhyProcInfo +#define ceRspPhyConnect ceReqPhyConnect +#define ceRspPhyDisconnect ceReqPhyDisconnect +#define ceRspPhySetParams ceReqPhySetParams +#define ceRspPhyGetParams ceReqPhyGetParams +#define ceRspPhyStatus ceReqPhyStatus +#define ceRspPhyAcfaStatus ceReqPhyAcfaStatus +#define ceRspPhyChCallState ceReqPhyChCallState +#define ceRspPhyChServState ceReqPhyChServState +#define ceRspPhyRLoopBack ceReqphyRLoopBack +#define ceReqLnkSetParam 1 /* 2,0,1 */ +#define ceReqLnkGetParam 2 /* 2,0,2 */ +#define ceReqLnkGetStats 3 /* 2,0,3 */ +#define ceReqLnkWrite 1 /* 2,1,1 */ +#define ceReqLnkRead 2 /* 2,1,2 */ +#define ceReqLnkFlush 3 /* 2,1,3 */ +#define ceReqLnkWrBufTrc 4 /* 2,1,4 */ +#define ceReqLnkRdBufTrc 5 /* 2,1,5 */ +#define ceRspLnkSetParam ceReqLnkSetParam +#define ceRspLnkGetParam ceReqLnkGetParam +#define ceRspLnkGetStats ceReqLnkGetStats +#define ceRspLnkWrite ceReqLnkWrite +#define ceRspLnkRead ceReqLnkRead +#define ceRspLnkFlush ceReqLnkFlush +#define ceRspLnkWrBufTrc ceReqLnkWrBufTrc +#define ceRspLnkRdBufTrc ceReqLnkRdBufTrc +#define ceReqCallSetSwitchType 1 /* 3,0,1 */ +#define ceReqCallGetSwitchType 2 /* 3,0,2 */ +#define ceReqCallSetFrameFormat 3 /* 3,0,3 */ +#define ceReqCallGetFrameFormat 4 /* 3,0,4 */ +#define ceReqCallSetCallType 5 /* 3,0,5 */ +#define ceReqCallGetCallType 6 /* 3,0,6 */ +#define ceReqCallSetSPID 7 /* 3,0,7 (!P) */ +#define ceReqCallGetSPID 8 /* 3,0,8 (!P) */ +#define ceReqCallSetMyNumber 9 /* 3,0,9 (!P) */ +#define ceReqCallGetMyNumber 10 /* 3,0,10 (!P) */ +#define ceRspCallSetSwitchType ceReqCallSetSwitchType +#define ceRspCallGetSwitchType ceReqCallSetSwitchType +#define ceRspCallSetFrameFormat ceReqCallSetFrameFormat +#define ceRspCallGetFrameFormat ceReqCallGetFrameFormat +#define ceRspCallSetCallType ceReqCallSetCallType +#define ceRspCallGetCallType ceReqCallGetCallType +#define ceRspCallSetSPID ceReqCallSetSPID +#define ceRspCallGetSPID ceReqCallGetSPID +#define ceRspCallSetMyNumber ceReqCallSetMyNumber +#define ceRspCallGetMyNumber ceReqCallGetMyNumber +#define ceRspStatAcfaStatus 2 +#define ceRspStat +#define ceRspErrError 0 /* 0,0,0 */ + +/* + * Call Types + */ +#define CALLTYPE_64K 0 +#define CALLTYPE_56K 1 +#define CALLTYPE_SPEECH 2 +#define CALLTYPE_31KHZ 3 + +/* + * Link Level data contains a pointer to and the length of + * a buffer in shared RAM. Used by LnkRead and LnkWrite message + * types. Part of RspMsgStruct and ReqMsgStruct. + */ +typedef struct { + unsigned long buff_offset; + unsigned short msg_len; +} LLData; + + +/* + * Message payload template for an HWConfig message + */ +typedef struct { + char st_u_sense; + char powr_sense; + char sply_sense; + unsigned char asic_id; + long ram_size; + char serial_no[13]; + char part_no[13]; + char rev_no[2]; +} HWConfig_pl; + +/* + * A Message + */ +struct message { + unsigned char sequence_no; + unsigned char process_id; + unsigned char time_stamp; + unsigned char cmd_sequence_no; /* Rsp messages only */ + unsigned char reserved1[3]; + unsigned char msg_byte_cnt; + unsigned char type; + unsigned char class; + unsigned char code; + unsigned char phy_link_no; + unsigned char rsp_status; /* Rsp messages only */ + unsigned char reseved2[3]; + union { + unsigned char byte_array[MSG_DATA_LEN]; + LLData response; + HWConfig_pl HWCresponse; + } msg_data; +}; + +typedef struct message ReqMessage; /* Request message */ +typedef struct message RspMessage; /* Response message */ + +/* + * The first 5010 bytes of shared memory contain the message queues, + * indexes and other data. This structure is its template + */ +typedef struct { + volatile ReqMessage req_queue[MAX_MESSAGES]; + volatile RspMessage rsp_queue[MAX_MESSAGES]; + volatile unsigned char req_head; + volatile unsigned char req_tail; + volatile unsigned char rsp_head; + volatile unsigned char rsp_tail; + volatile unsigned long signature; + volatile unsigned long trace_enable; + volatile unsigned char reserved[4]; +} DualPortMemory; + +#endif diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/sc/packet.c linux/drivers/isdn/sc/packet.c --- v2.1.26/linux/drivers/isdn/sc/packet.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/sc/packet.c Tue Feb 25 17:12:50 1997 @@ -0,0 +1,228 @@ +/* + * $Id: packet.c,v 1.2 1996/11/20 17:49:55 fritz Exp $ + * Copyright (C) 1996 SpellCaster Telecommunications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * For more information, please contact gpl-info@spellcast.com or write: + * + * SpellCaster Telecommunications Inc. + * 5621 Finch Avenue East, Unit #3 + * Scarborough, Ontario Canada + * M1B 2T9 + * +1 (416) 297-8565 + * +1 (416) 297-6433 Facsimile + */ + +#define __NO_VERSION__ +#include "includes.h" +#include "hardware.h" +#include "message.h" +#include "card.h" + +extern board *adapter[]; +extern unsigned int cinst; + +extern int get_card_from_id(int); +extern int indicate_status(int, int,ulong,char*); +extern void *memcpy_toshmem(int, void *, const void *, size_t); +extern void *memcpy_fromshmem(int, void *, const void *, size_t); +extern int sendmessage(int, unsigned int, unsigned int, unsigned int, + unsigned int, unsigned int, unsigned int, unsigned int *); + +int sndpkt(int devId, int channel, struct sk_buff *data) +{ + LLData ReqLnkWrite; + int status; + int card; + + card = get_card_from_id(devId); + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + pr_debug("%s: Send Packet: frst = 0x%x nxt = %d f = %d n = %d\n", + adapter[card]->devicename, + adapter[card]->channel[channel].first_sendbuf, + adapter[card]->channel[channel].next_sendbuf, + adapter[card]->channel[channel].free_sendbufs, + adapter[card]->channel[channel].num_sendbufs); + + if(!adapter[card]->channel[channel].free_sendbufs) { + pr_debug("%s: Out out TX buffers\n", adapter[card]->devicename); + return -EINVAL; + } + + if(data->len > BUFFER_SIZE) { + pr_debug("%s: Data overflows buffer size (data > buffer)\n", adapter[card]->devicename); + return -EINVAL; + } + + ReqLnkWrite.buff_offset = adapter[card]->channel[channel].next_sendbuf * + BUFFER_SIZE + adapter[card]->channel[channel].first_sendbuf; + ReqLnkWrite.msg_len = data->len; /* sk_buff size */ + pr_debug("%s: Writing %d bytes to buffer offset 0x%x\n", adapter[card]->devicename, + ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset); + memcpy_toshmem(card, (char *)ReqLnkWrite.buff_offset, data->data, ReqLnkWrite.msg_len); + + /* + * sendmessage + */ + pr_debug("%s: Send Packet size=%d, buf_offset=0x%x buf_indx=%d\n", + adapter[card]->devicename, + ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset, + adapter[card]->channel[channel].next_sendbuf); + + status = sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkWrite, + channel+1, sizeof(LLData), (unsigned int*)&ReqLnkWrite); + if(status) { + pr_debug("%s: Failed to send packet, status = %d\n", adapter[card]->devicename, status); + return -1; + } + else { + adapter[card]->channel[channel].free_sendbufs--; + adapter[card]->channel[channel].next_sendbuf = + ++adapter[card]->channel[channel].next_sendbuf == + adapter[card]->channel[channel].num_sendbufs ? 0 : + adapter[card]->channel[channel].next_sendbuf; + pr_debug("%s: Packet sent successfully\n", adapter[card]->devicename); + dev_kfree_skb(data, FREE_WRITE); + indicate_status(card,ISDN_STAT_BSENT,channel,NULL); + } + return data->len; +} + +void rcvpkt(int card, RspMessage *rcvmsg) +{ + LLData newll; + struct sk_buff *skb; + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return; + } + + switch(rcvmsg->rsp_status){ + case 0x01: + case 0x02: + case 0x70: + pr_debug("%s: Error status code: 0x%x\n", adapter[card]->devicename, rcvmsg->rsp_status); + return; + case 0x00: + if (!(skb = dev_alloc_skb(rcvmsg->msg_data.response.msg_len))) { + printk(KERN_WARNING "%s: rcvpkt out of memory, dropping packet\n", + adapter[card]->devicename); + return; + } + skb_put(skb, rcvmsg->msg_data.response.msg_len); + pr_debug("%s: getting data from offset: 0x%x\n", + adapter[card]->devicename,rcvmsg->msg_data.response.buff_offset); + memcpy_fromshmem(card, + skb_put(skb, rcvmsg->msg_data.response.msg_len), + (char *)rcvmsg->msg_data.response.buff_offset, + rcvmsg->msg_data.response.msg_len); + adapter[card]->card->rcvcallb_skb(adapter[card]->driverId, + rcvmsg->phy_link_no-1, skb); + + case 0x03: + /* + * Recycle the buffer + */ + pr_debug("%s: Buffer size : %d\n", adapter[card]->devicename, BUFFER_SIZE); +/* memset_shmem(card, rcvmsg->msg_data.response.buff_offset, 0, BUFFER_SIZE); */ + newll.buff_offset = rcvmsg->msg_data.response.buff_offset; + newll.msg_len = BUFFER_SIZE; + pr_debug("%s: recycled buffer at offset 0x%x size %d\n", adapter[card]->devicename, + newll.buff_offset, newll.msg_len); + sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkRead, + rcvmsg->phy_link_no, sizeof(LLData), (unsigned int *)&newll); + } + +} + +int setup_buffers(int card, int c) +{ + unsigned int nBuffers, i, cBase; + unsigned int buffer_size; + LLData RcvBuffOffset; + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return -ENODEV; + } + + /* + * Calculate the buffer offsets (send/recv/send/recv) + */ + pr_debug("%s: Seting up channel buffer space in shared RAM\n", adapter[card]->devicename); + buffer_size = BUFFER_SIZE; + nBuffers = ((adapter[card]->ramsize - BUFFER_BASE) / buffer_size) / 2; + nBuffers = nBuffers > BUFFERS_MAX ? BUFFERS_MAX : nBuffers; + pr_debug("%s: Calculating buffer space: %d buffers, %d big\n", adapter[card]->devicename, + nBuffers, buffer_size); + if(nBuffers < 2) { + pr_debug("%s: Not enough buffer space\n", adapter[card]->devicename); + return -1; + } + cBase = (nBuffers * buffer_size) * (c - 1); + pr_debug("%s: Channel buffer offset from Shared RAM: 0x%x\n", adapter[card]->devicename, cBase); + adapter[card]->channel[c-1].first_sendbuf = BUFFER_BASE + cBase; + adapter[card]->channel[c-1].num_sendbufs = nBuffers / 2; + adapter[card]->channel[c-1].free_sendbufs = nBuffers / 2; + adapter[card]->channel[c-1].next_sendbuf = 0; + pr_debug("%s: Send buffer setup complete: first=0x%x n=%d f=%d, nxt=%d\n", + adapter[card]->devicename, + adapter[card]->channel[c-1].first_sendbuf, + adapter[card]->channel[c-1].num_sendbufs, + adapter[card]->channel[c-1].free_sendbufs, + adapter[card]->channel[c-1].next_sendbuf); + + /* + * Prep the receive buffers + */ + pr_debug("%s: Adding %d RecvBuffers:\n", adapter[card]->devicename, nBuffers /2); + for (i = 0 ; i < nBuffers / 2; i++) { + RcvBuffOffset.buff_offset = + ((adapter[card]->channel[c-1].first_sendbuf + + (nBuffers / 2) * buffer_size) + (buffer_size * i)); + RcvBuffOffset.msg_len = buffer_size; + pr_debug("%s: Adding RcvBuffer #%d offset=0x%x sz=%d buffsz:%d\n", + adapter[card]->devicename, + i + 1, RcvBuffOffset.buff_offset, + RcvBuffOffset.msg_len,buffer_size); + sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkRead, + c, sizeof(LLData), (unsigned int *)&RcvBuffOffset); + } + return 0; +} + +int print_skb(int card,char *skb_p, int len){ + int i,data; + pr_debug("%s: data at 0x%x len: 0x%x\n",adapter[card]->devicename, + skb_p,len); + for(i=1;i<=len;i++,skb_p++){ + data = (int) (0xff & (*skb_p)); + pr_debug("%s: data = 0x%x",adapter[card]->devicename,data); + if(!(i%4)) + pr_debug(" "); + if(!(i%32)) + pr_debug("\n"); + } + pr_debug("\n"); + return 0; +} + diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/sc/scioc.h linux/drivers/isdn/sc/scioc.h --- v2.1.26/linux/drivers/isdn/sc/scioc.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/sc/scioc.h Tue Feb 25 17:12:50 1997 @@ -0,0 +1,101 @@ + +/* + * IOCTL Command Codes + */ +#define SCIOCLOAD 0x01 /* Load a firmware record */ +#define SCIOCRESET 0x02 /* Perform hard reset */ +#define SCIOCDEBUG 0x03 /* Set debug level */ +#define SCIOCREV 0x04 /* Get driver revision(s) */ +#define SCIOCSTART 0x05 /* Start the firmware */ +#define SCIOCGETSWITCH 0x06 /* Get switch type */ +#define SCIOCSETSWITCH 0x07 /* Set switch type */ +#define SCIOCGETSPID 0x08 /* Get channel SPID */ +#define SCIOCSETSPID 0x09 /* Set channel SPID */ +#define SCIOCGETDN 0x0A /* Get channel DN */ +#define SCIOCSETDN 0x0B /* Set channel DN */ +#define SCIOCTRACE 0x0C /* Toggle trace mode */ +#define SCIOCSTAT 0x0D /* Get line status */ +#define SCIOCGETSPEED 0x0E /* Set channel speed */ +#define SCIOCSETSPEED 0x0F /* Set channel speed */ +#define SCIOCLOOPTST 0x10 /* Perform loopback test */ + +typedef struct { + int device; + int channel; + unsigned long command; + void *dataptr; +} scs_ioctl; + +/* Size of strings */ +#define SCIOC_SPIDSIZE 49 +#define SCIOC_DNSIZE SCIOC_SPIDSIZE +#define SCIOC_REVSIZE SCIOC_SPIDSIZE +#define SCIOC_SRECSIZE 49 + +typedef struct { + unsigned long tx_good; + unsigned long tx_bad; + unsigned long rx_good; + unsigned long rx_bad; +} ChLinkStats; + +typedef struct { + char spid[49]; + char dn[49]; + char call_type; + char phy_stat; + ChLinkStats link_stats; +} BRIStat; + +typedef BRIStat POTStat; + +typedef struct { + char call_type; + char call_state; + char serv_state; + char phy_stat; + ChLinkStats link_stats; +} PRIStat; + +typedef char PRIInfo; +typedef char BRIInfo; +typedef char POTInfo; + + +typedef struct { + char acfa_nos; + char acfa_ais; + char acfa_los; + char acfa_rra; + char acfa_slpp; + char acfa_slpn; + char acfa_fsrf; +} ACFAStat; + +typedef struct { + unsigned char modelid; + char serial_no[13]; + char part_no[13]; + char load_ver[11]; + char proc_ver[11]; + int iobase; + long rambase; + char irq; + long ramsize; + char interface; + char switch_type; + char l1_status; + char l2_status; + ChLinkStats dch_stats; + ACFAStat AcfaStats; + union { + PRIStat pristats[23]; + BRIStat bristats[2]; + POTStat potsstats[2]; + } status; + union { + PRIInfo priinfo; + BRIInfo briinfo; + POTInfo potsinfo; + } info; +} boardInfo; diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/sc/shmem.c linux/drivers/isdn/sc/shmem.c --- v2.1.26/linux/drivers/isdn/sc/shmem.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/sc/shmem.c Tue Feb 25 17:12:50 1997 @@ -0,0 +1,165 @@ +/* + * $Id: shmem.c,v 1.2 1996/11/20 17:49:56 fritz Exp $ + * Copyright (C) 1996 SpellCaster Telecommunications Inc. + * + * card.c - Card functions implementing ISDN4Linux functionality + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * For more information, please contact gpl-info@spellcast.com or write: + * + * SpellCaster Telecommunications Inc. + * 5621 Finch Avenue East, Unit #3 + * Scarborough, Ontario Canada + * M1B 2T9 + * +1 (416) 297-8565 + * +1 (416) 297-6433 Facsimile + */ + +#define __NO_VERSION__ +#include "includes.h" /* This must be first */ +#include "hardware.h" +#include "card.h" + +/* + * Main adapter array + */ +extern board *adapter[]; +extern int cinst; + +/* + * + */ +void *memcpy_toshmem(int card, void *dest, const void *src, size_t n) +{ + unsigned long flags; + void *ret; + unsigned char ch; + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return NULL; + } + + if(n > SRAM_PAGESIZE) { + return NULL; + } + + /* + * determine the page to load from the address + */ + ch = (unsigned long) dest / SRAM_PAGESIZE; + pr_debug("%s: loaded page %d\n",adapter[card]->devicename,ch); + /* + * Block interrupts and load the page + */ + save_flags(flags); + cli(); + + outb(((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80, + adapter[card]->ioport[adapter[card]->shmem_pgport]); + pr_debug("%s: set page to %#x\n",adapter[card]->devicename, + ((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80); + ret = memcpy_toio(adapter[card]->rambase + + ((unsigned long) dest % 0x4000), src, n); + pr_debug("%s: copying %d bytes from %#x to %#x\n",adapter[card]->devicename, n, + (unsigned long) src, adapter[card]->rambase + ((unsigned long) dest %0x4000)); + restore_flags(flags); + + return ret; +} + +/* + * Reverse of above + */ +void *memcpy_fromshmem(int card, void *dest, const void *src, size_t n) +{ + unsigned long flags; + void *ret; + unsigned char ch; + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return NULL; + } + + if(n > SRAM_PAGESIZE) { + return NULL; + } + + /* + * determine the page to load from the address + */ + ch = (unsigned long) src / SRAM_PAGESIZE; + pr_debug("%s: loaded page %d\n",adapter[card]->devicename,ch); + + + /* + * Block interrupts and load the page + */ + save_flags(flags); + cli(); + + outb(((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80, + adapter[card]->ioport[adapter[card]->shmem_pgport]); + pr_debug("%s: set page to %#x\n",adapter[card]->devicename, + ((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80); + ret = memcpy_fromio(dest,(void *)(adapter[card]->rambase + + ((unsigned long) src % 0x4000)), n); +/* pr_debug("%s: copying %d bytes from %#x to %#x\n", + adapter[card]->devicename, n, + adapter[card]->rambase + ((unsigned long) src %0x4000), (unsigned long) dest); */ + restore_flags(flags); + + return ret; +} + +void *memset_shmem(int card, void *dest, int c, size_t n) +{ + unsigned long flags; + unsigned char ch; + void *ret; + + if(!IS_VALID_CARD(card)) { + pr_debug("Invalid param: %d is not a valid card id\n", card); + return NULL; + } + + if(n > SRAM_PAGESIZE) { + return NULL; + } + + /* + * determine the page to load from the address + */ + ch = (unsigned long) dest / SRAM_PAGESIZE; + pr_debug("%s: loaded page %d\n",adapter[card]->devicename,ch); + + /* + * Block interrupts and load the page + */ + save_flags(flags); + cli(); + + outb(((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80, + adapter[card]->ioport[adapter[card]->shmem_pgport]); + pr_debug("%s: set page to %#x\n",adapter[card]->devicename, + ((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80); + ret = memset_io(adapter[card]->rambase + + ((unsigned long) dest % 0x4000), c, n); + restore_flags(flags); + + return ret; +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/sc/timer.c linux/drivers/isdn/sc/timer.c --- v2.1.26/linux/drivers/isdn/sc/timer.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/sc/timer.c Tue Feb 25 17:12:50 1997 @@ -0,0 +1,172 @@ +/* + * $Id: timer.c,v 1.2 1996/11/20 17:49:57 fritz Exp $ + * Copyright (C) 1996 SpellCaster Telecommunications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * For more information, please contact gpl-info@spellcast.com or write: + * + * SpellCaster Telecommunications Inc. + * 5621 Finch Avenue East, Unit #3 + * Scarborough, Ontario Canada + * M1B 2T9 + * +1 (416) 297-8565 + * +1 (416) 297-6433 Facsimile + */ + +#define __NO_VERSION__ +#include "includes.h" +#include "hardware.h" +#include "message.h" +#include "card.h" + +extern board *adapter[]; + +extern void flushreadfifo(int); +extern int startproc(int); +extern int indicate_status(int, int, unsigned long, char *); +extern int sendmessage(int, unsigned int, unsigned int, unsigned int, + unsigned int, unsigned int, unsigned int, unsigned int *); + + +/* + * Write the proper values into the I/O ports following a reset + */ +void setup_ports(int card) +{ + + outb((adapter[card]->rambase >> 12), adapter[card]->ioport[EXP_BASE]); + + /* And the IRQ */ + outb((adapter[card]->interrupt | 0x80), + adapter[card]->ioport[IRQ_SELECT]); +} + +/* + * Timed function to check the status of a previous reset + * Must be very fast as this function runs in the context of + * an interrupt handler. + * + * Setup the ioports for the board that were cleared by the reset. + * Then, check to see if the signate has been set. Next, set the + * signature to a known value and issue a startproc if needed. + */ +void check_reset(unsigned long data) +{ + unsigned long flags; + unsigned long sig; + int card = (unsigned int) data; + + pr_debug("%s: check_timer timer called\n", adapter[card]->devicename); + + /* Setup the io ports */ + setup_ports(card); + + save_flags(flags); + cli(); + outb(adapter[card]->ioport[adapter[card]->shmem_pgport], + (adapter[card]->shmem_magic>>14) | 0x80); + sig = (unsigned long) *((unsigned long *)(adapter[card]->rambase + SIG_OFFSET)); + + /* check the signature */ + if(sig == SIGNATURE) { + flushreadfifo(card); + restore_flags(flags); + /* See if we need to do a startproc */ + if (adapter[card]->StartOnReset) + startproc(card); + } + else { + pr_debug("%s: No signature yet, waiting another %d jiffies.\n", + adapter[card]->devicename, CHECKRESET_TIME); + del_timer(&adapter[card]->reset_timer); + adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME; + add_timer(&adapter[card]->reset_timer); + } + restore_flags(flags); + +} + +/* + * Timed function to check the status of a previous reset + * Must be very fast as this function runs in the context of + * an interrupt handler. + * + * Send check adapter->phystat to see if the channels are up + * If they are, tell ISDN4Linux that the board is up. If not, + * tell IADN4Linux that it is up. Always reset the timer to + * fire again (endless loop). + */ +void check_phystat(unsigned long data) +{ + unsigned long flags; + int card = (unsigned int) data; + + pr_debug("%s: Checking status...\n", adapter[card]->devicename); + /* + * check the results of the last PhyStat and change only if + * has changed drastically + */ + if (adapter[card]->nphystat && !adapter[card]->phystat) { /* All is well */ + pr_debug("PhyStat transition to RUN\n"); + pr_info("%s: Switch contacted, transmitter enabled\n", + adapter[card]->devicename); + indicate_status(card, ISDN_STAT_RUN, 0, NULL); + } + else if (!adapter[card]->nphystat && adapter[card]->phystat) { /* All is not well */ + pr_debug("PhyStat transition to STOP\n"); + pr_info("%s: Switch connection lost, transmitter disabled\n", + adapter[card]->devicename); + + indicate_status(card, ISDN_STAT_STOP, 0, NULL); + } + + adapter[card]->phystat = adapter[card]->nphystat; + + /* Reinitialize the timer */ + save_flags(flags); + cli(); + del_timer(&adapter[card]->stat_timer); + adapter[card]->stat_timer.expires = jiffies + CHECKSTAT_TIME; + add_timer(&adapter[card]->stat_timer); + restore_flags(flags); + + /* Send a new cePhyStatus message */ + sendmessage(card, CEPID,ceReqTypePhy,ceReqClass2, + ceReqPhyStatus,0,0,NULL); +} + +/* + * When in trace mode, this callback is used to swap the working shared + * RAM page to the trace page(s) and process all received messages. It + * must be called often enough to get all of the messages out of RAM before + * it loops around. + * Trace messages are \n terminated strings. + * We output the messages in 64 byte chunks through readstat. Each chunk + * is scanned for a \n followed by a time stamp. If the timerstamp is older + * than the current time, scanning stops and the page and offset are recorded + * as the starting point the next time the trace timer is called. The final + * step is to restore the working page and reset the timer. + */ +void trace_timer(unsigned long data) +{ + unsigned long flags; + + /* + * Disable interrupts and swap the first page + */ + save_flags(flags); + cli(); +} diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/teles/callc.c linux/drivers/isdn/teles/callc.c --- v2.1.26/linux/drivers/isdn/teles/callc.c Wed Oct 30 04:26:48 1996 +++ linux/drivers/isdn/teles/callc.c Tue Feb 25 17:12:50 1997 @@ -1,6 +1,15 @@ -/* $Id: callc.c,v 1.13 1996/06/24 17:15:55 fritz Exp $ +/* $Id: callc.c,v 1.16 1997/02/11 01:39:46 keil Exp $ * * $Log: callc.c,v $ + * Revision 1.16 1997/02/11 01:39:46 keil + * Changed setup-interface (incoming and outgoing) + * + * Revision 1.15 1996/11/23 11:32:20 keil + * windowsize = 7 X.75 bugfix Thanks to Martin Maurer + * + * Revision 1.14 1996/10/22 23:14:14 fritz + * Changes for compatibility to 2.0.X and 2.1.X kernels. + * * Revision 1.13 1996/06/24 17:15:55 fritz * corrected return code of teles_writebuf() * @@ -47,7 +56,6 @@ */ #define __NO_VERSION__ #include "teles.h" -#include extern struct IsdnCard cards[]; extern int nrcards; @@ -58,7 +66,6 @@ static int init_ds(int chan, int incoming); static void release_ds(int chan); -static char *strcpyupto(char *dest, char *src, char upto); static struct Fsm callcfsm = {NULL, 0, 0}, lcfsm = @@ -219,19 +226,6 @@ #define LC_D 0 #define LC_B 1 -static int -my_atoi(char *s) -{ - int i, n; - - n = 0; - if (!s) - return -1; - for (i = 0; *s >= '0' && *s <= '9'; i++, s++) - n = 10 * n + (*s - '0'); - return n; -} - /* * Dial out */ @@ -240,23 +234,10 @@ { isdn_ctrl *ic = arg; struct Channel *chanp = fi->userdata; - char *ptr; - char sis[3]; - /* Destination Phone-Number */ - ptr = strcpyupto(chanp->para.called, ic->num, ','); - /* Source Phone-Number */ - ptr = strcpyupto(chanp->para.calling, ptr + 1, ','); - if (!strcmp(chanp->para.calling, "0")) - chanp->para.calling[0] = '\0'; - - /* Service-Indicator 1 */ - ptr = strcpyupto(sis, ptr + 1, ','); - chanp->para.info = my_atoi(sis); - - /* Service-Indicator 2 */ - ptr = strcpyupto(sis, ptr + 1, '\0'); - chanp->para.info2 = my_atoi(sis); + chanp->para.setup = ic->parm.setup; + if (!strcmp(chanp->para.setup.eazmsn, "0")) + chanp->para.setup.eazmsn[0] = '\0'; chanp->l2_active_protocol = chanp->l2_protocol; chanp->incoming = 0; @@ -414,8 +395,7 @@ * No need to return "unknown" for calls without OAD, * cause that's handled in linklevel now (replaced by '0') */ - sprintf(ic.num, "%s,%d,0,%s", chanp->para.calling, chanp->para.info, - chanp->para.called); + ic.parm.setup = chanp->para.setup; iif.statcallb(&ic); } else { chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); @@ -670,7 +650,7 @@ ic.driver = drid; ic.command = ISDN_STAT_CINF; ic.arg = chanp->chan; - sprintf(ic.num, "%d", chanp->para.chargeinfo); + sprintf(ic.parm.num, "%d", chanp->para.chargeinfo); iif.statcallb(&ic); } @@ -1234,7 +1214,7 @@ st->l2.laptype = LAPB; st->l2.orig = !incoming; st->l2.t200 = 1000; /* 1000 milliseconds */ - st->l2.window = 3; + st->l2.window = 7; st->l2.n200 = 4; /* try 4 times */ st->l2.t203 = 5000; /* 5000 milliseconds */ @@ -1327,7 +1307,9 @@ case (ISDN_CMD_DIAL): chanp = chanlist + (ic->arg & 0xff); if (chanp->debug & 1) { - sprintf(tmp, "DIAL %s", ic->num); + sprintf(tmp, "DIAL %s -> %s (%d,%d)", + ic->parm.setup.eazmsn, ic->parm.setup.phone, + ic->parm.setup.si1, ic->parm.setup.si2); command_debug(chanp, tmp); } FsmEvent(&chanp->fi, EV_DIAL, ic); @@ -1353,7 +1335,7 @@ case (ISDN_CMD_SUSPEND): chanp = chanlist + ic->arg; if (chanp->debug & 1) { - sprintf(tmp, "SUSPEND %s", ic->num); + sprintf(tmp, "SUSPEND %s", ic->parm.num); command_debug(chanp, tmp); } FsmEvent(&chanp->fi, EV_SUSPEND, ic); @@ -1361,7 +1343,7 @@ case (ISDN_CMD_RESUME): chanp = chanlist + ic->arg; if (chanp->debug & 1) { - sprintf(tmp, "RESUME %s", ic->num); + sprintf(tmp, "RESUME %s", ic->parm.num); command_debug(chanp, tmp); } FsmEvent(&chanp->fi, EV_RESUME, ic); @@ -1382,14 +1364,14 @@ channel_report(i); break; case (1): - debugflags = *(unsigned int *) ic->num; + debugflags = *(unsigned int *) ic->parm.num; distr_debug(); sprintf(tmp, "debugging flags set to %x\n", debugflags); teles_putstatus(tmp); printk(KERN_DEBUG "%s", tmp); break; case (2): - num = *(unsigned int *) ic->num; + num = *(unsigned int *) ic->parm.num; i = num >> 8; if (i >= chancount) break; @@ -1451,10 +1433,9 @@ ptr += i; - if (user) { - if (copy_from_user(ptr, buf, count)) - return -EFAULT; - } else + if (user) + copy_from_user(ptr, buf, count); + else memcpy(ptr, buf, count); ibh->datasize = count + i; @@ -1469,13 +1450,4 @@ return (0); } -} - -static char * -strcpyupto(char *dest, char *src, char upto) -{ - while (*src && (*src != upto) && (*src != '\0')) - *dest++ = *src++; - *dest = '\0'; - return (src); } diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/teles/card.c linux/drivers/isdn/teles/card.c --- v2.1.26/linux/drivers/isdn/teles/card.c Mon Oct 28 11:43:22 1996 +++ linux/drivers/isdn/teles/card.c Tue Feb 25 17:12:50 1997 @@ -1,4 +1,4 @@ -/* $Id: card.c,v 1.13 1996/07/18 11:21:24 jdenoud Exp $ +/* $Id: card.c,v 1.16 1996/10/22 23:14:16 fritz Exp $ * * card.c low level stuff for the Teles S0 isdn card * @@ -7,6 +7,15 @@ * Beat Doebeli log all D channel traffic * * $Log: card.c,v $ + * Revision 1.16 1996/10/22 23:14:16 fritz + * Changes for compatibility to 2.0.X and 2.1.X kernels. + * + * Revision 1.15 1996/09/29 19:41:56 fritz + * Bugfix: ignore unknown frames. + * + * Revision 1.14 1996/09/23 01:53:49 fritz + * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6). + * * Revision 1.13 1996/07/18 11:21:24 jdenoud * Use small buffers for incoming audio data * @@ -59,13 +68,12 @@ #define __NO_VERSION__ #include "teles.h" +#include "proto.h" #define INCLUDE_INLINE_FUNCS #include #include -#include - #undef DCHAN_VERBOSE extern void tei_handler(struct PStack *st, byte pr, @@ -77,7 +85,7 @@ #define bytein(addr) inb_p(addr) static inline byte -readisac_0(unsigned int cardm, byte offset) +readisac_0(byte * cardm, byte offset) { return readb(cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset); } @@ -92,7 +100,7 @@ ((mbase)?readisac_0(mbase,ofs):readisac_3(ibase,ofs)) static inline void -writeisac_0(unsigned int cardm, byte offset, byte value) +writeisac_0(byte * cardm, byte offset, byte value) { writeb(value, cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset); } @@ -119,7 +127,7 @@ } static inline byte -readhscx_0(unsigned int base, byte hscx, byte offset) +readhscx_0(byte * base, byte hscx, byte offset) { return readb(base + 0x180 + ((offset & 1) ? 0x1FF : 0) + ((hscx & 1) ? 0x40 : 0) + offset); @@ -135,7 +143,7 @@ ((mbase)?readhscx_0(mbase,hscx,ofs):readhscx_3(ibase,hscx,ofs)) static inline void -writehscx_0(unsigned int base, byte hscx, byte offset, byte data) +writehscx_0(byte * base, byte hscx, byte offset, byte data) { writeb(data, base + 0x180 + ((offset & 1) ? 0x1FF : 0) + ((hscx & 1) ? 0x40 : 0) + offset); @@ -201,7 +209,7 @@ #define HSCX_MASK 0x20 static inline void -waitforCEC_0(unsigned int base, byte hscx) +waitforCEC_0(byte * base, byte hscx) { long to = 10; @@ -227,7 +235,7 @@ } static inline void -waitforXFW_0(unsigned int base, byte hscx) +waitforXFW_0(byte * base, byte hscx) { long to = 20; @@ -253,7 +261,7 @@ } static inline void -writehscxCMDR_0(unsigned int base, byte hscx, byte data) +writehscxCMDR_0(byte * base, byte hscx, byte data) { long flags; @@ -1061,7 +1069,7 @@ } static void -initisac(unsigned int cardmem, int iobase) +initisac(byte * cardmem, int iobase) { if (cardmem) { writeisac_0(cardmem, ISAC_MASK, 0xff); @@ -1095,17 +1103,17 @@ struct IsdnCard *card = cards + cardnr; if (card->membase) - if (card->membase < 0x10000) { - card->membase <<= 4; + if ((unsigned long)card->membase < 0x10000) { + (unsigned long)card->membase <<= 4; printk(KERN_INFO - "Teles membase configured DOSish, assuming 0x%x\n", - card->membase); + "Teles membase configured DOSish, assuming 0x%lx\n", + (unsigned long)card->membase); } if (!card->iobase) { if (card->membase) { printk(KERN_NOTICE - "Teles 8 assumed, mem: %x irq: %d proto: %s\n", - card->membase, card->interrupt, + "Teles 8 assumed, mem: %lx irq: %d proto: %s\n", + (long) card->membase, card->interrupt, (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : "EDSS1"); printk(KERN_INFO "HSCX version A:%x B:%x\n", @@ -1188,7 +1196,7 @@ break; } if (card->membase) { - cfval |= (card->membase >> 9) & 0xF0; + cfval |= (((unsigned int) card->membase >> 9) & 0xF0); } if (bytein(card->iobase + 0) != 0x51) { printk(KERN_INFO "XXX Byte at %x is %x\n", @@ -1234,8 +1242,8 @@ if (card->membase) printk(KERN_NOTICE - "Teles 16.0 found, io: %x mem: %x irq: %d proto: %s\n", - card->iobase, card->membase, + "Teles 16.0 found, io: %x mem: %lx irq: %d proto: %s\n", + card->iobase, (long) card->membase, card->interrupt, (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : "EDSS1"); diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/teles/config.c linux/drivers/isdn/teles/config.c --- v2.1.26/linux/drivers/isdn/teles/config.c Mon Oct 28 11:46:22 1996 +++ linux/drivers/isdn/teles/config.c Tue Feb 25 17:12:50 1997 @@ -29,20 +29,20 @@ struct IsdnCard cards[] = { - {0xd0000, 15, 0xd80, ISDN_PTYPE_EURO, NULL}, /* example */ - {0, 0, 0, 0, NULL}, - {0, 0, 0, 0, NULL}, - {0, 0, 0, 0, NULL}, - {0, 0, 0, 0, NULL}, - {0, 0, 0, 0, NULL}, - {0, 0, 0, 0, NULL}, - {0, 0, 0, 0, NULL}, - {0, 0, 0, 0, NULL}, - {0, 0, 0, 0, NULL}, - {0, 0, 0, 0, NULL}, - {0, 0, 0, 0, NULL}, - {0, 0, 0, 0, NULL}, - {0, 0, 0, 0, NULL}, - {0, 0, 0, 0, NULL}, - {0, 0, 0, 0, NULL}, + {(byte *) 0xd0000, 15, 0xd80, ISDN_PTYPE_EURO, NULL}, /* example */ + {NULL, 0, 0, 0, NULL}, + {NULL, 0, 0, 0, NULL}, + {NULL, 0, 0, 0, NULL}, + {NULL, 0, 0, 0, NULL}, + {NULL, 0, 0, 0, NULL}, + {NULL, 0, 0, 0, NULL}, + {NULL, 0, 0, 0, NULL}, + {NULL, 0, 0, 0, NULL}, + {NULL, 0, 0, 0, NULL}, + {NULL, 0, 0, 0, NULL}, + {NULL, 0, 0, 0, NULL}, + {NULL, 0, 0, 0, NULL}, + {NULL, 0, 0, 0, NULL}, + {NULL, 0, 0, 0, NULL}, + {NULL, 0, 0, 0, NULL}, }; diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/teles/fsm.c linux/drivers/isdn/teles/fsm.c --- v2.1.26/linux/drivers/isdn/teles/fsm.c Sun May 19 05:29:30 1996 +++ linux/drivers/isdn/teles/fsm.c Tue Feb 25 17:12:50 1997 @@ -1,6 +1,9 @@ -/* $Id: fsm.c,v 1.2 1996/04/29 22:49:57 fritz Exp $ +/* $Id: fsm.c,v 1.3 1997/02/16 01:04:12 fritz Exp $ * * $Log: fsm.c,v $ + * Revision 1.3 1997/02/16 01:04:12 fritz + * Bugfix: Changed timer handling caused hang with 2.1.X + * * Revision 1.2 1996/04/29 22:49:57 fritz * Removed compatibility-macros. * @@ -91,8 +94,6 @@ void FsmDelTimer(struct FsmTimer *ft, int where) { - long flags; - #if 0 if (ft->fi->debug) { sprintf(str, "FsmDelTimer %lx %d", ft, where); @@ -100,11 +101,7 @@ } #endif - save_flags(flags); - cli(); - if (ft->tl.next) - del_timer(&ft->tl); - restore_flags(flags); + del_timer(&ft->tl); } int @@ -119,7 +116,7 @@ } #endif - if (ft->tl.next) { + if (ft->tl.next || ft->tl.prev) { printk(KERN_WARNING "FsmAddTimer: timer already active!\n"); return -1; } diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/teles/isdnl2.c linux/drivers/isdn/teles/isdnl2.c --- v2.1.26/linux/drivers/isdn/teles/isdnl2.c Sun May 19 05:29:31 1996 +++ linux/drivers/isdn/teles/isdnl2.c Tue Feb 25 17:12:50 1997 @@ -1,6 +1,9 @@ -/* $Id: isdnl2.c,v 1.2 1996/05/17 03:46:15 fritz Exp $ +/* $Id: isdnl2.c,v 1.3 1996/11/23 11:32:57 keil Exp $ * * $Log: isdnl2.c,v $ + * Revision 1.3 1996/11/23 11:32:57 keil + * X.75 bugfixies; Thanks to Martin Maurer + * * Revision 1.2 1996/05/17 03:46:15 fritz * General cleanup. * @@ -319,7 +322,7 @@ if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 10)) return; - i = sethdraddr(&(st->l2), ibh, 0); + i = sethdraddr(&(st->l2), ibh, !0); ptr = DATAPTR(ibh); ptr += i; *ptr = 0x73; @@ -565,7 +568,7 @@ goto noRR; if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 13)) { - i = sethdraddr(&(st->l2), ibh2, p); + i = sethdraddr(&(st->l2), ibh2, !0); ptr = DATAPTR(ibh2); ptr += i; @@ -847,7 +850,7 @@ *ptr++ = (l2->vr << 1) | 0x1; l2->vs = (l2->vs + 1) % 128; } else { - *ptr++ = (l2->vr << 5) | (l2->vs << 1) | 0x10; + *ptr++ = (l2->vr << 5) | (l2->vs << 1); l2->vs = (l2->vs + 1) % 8; } diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/teles/isdnl3.c linux/drivers/isdn/teles/isdnl3.c --- v2.1.26/linux/drivers/isdn/teles/isdnl3.c Fri Jun 7 06:02:42 1996 +++ linux/drivers/isdn/teles/isdnl3.c Tue Feb 25 17:12:50 1997 @@ -1,6 +1,18 @@ -/* $Id: isdnl3.c,v 1.9 1996/06/06 14:22:27 fritz Exp $ +/* $Id: isdnl3.c,v 1.13 1997/02/16 12:12:51 fritz Exp $ * * $Log: isdnl3.c,v $ + * Revision 1.13 1997/02/16 12:12:51 fritz + * Bugfix: SI2 was nont initialized on incoming calls. + * + * Revision 1.12 1997/02/11 01:39:20 keil + * Changed setup-interface (incoming and outgoing) + * + * Revision 1.11 1996/09/29 19:41:58 fritz + * Bugfix: ignore unknown frames. + * + * Revision 1.10 1996/09/25 18:32:43 keil + * response for STATUS_ENQ message added + * * Revision 1.9 1996/06/06 14:22:27 fritz * Changed level of "non-digital call..." message, since * with audio support, this is quite normal. @@ -129,7 +141,7 @@ /* * Set Bearer Capability, Map info from 1TR6-convention to EDSS1 */ - switch (st->pa->info) { + switch (st->pa->setup.si1) { case 1: /* Telephony */ *p++ = 0x4; /* BC-IE-code */ *p++ = 0x3; /* Length */ @@ -149,21 +161,21 @@ /* * What about info2? Mapping to High-Layer-Compatibility? */ - if (st->pa->calling[0] != '\0') { + if (st->pa->setup.eazmsn[0] != '\0') { *p++ = 0x6c; - *p++ = strlen(st->pa->calling) + 1; + *p++ = strlen(st->pa->setup.eazmsn) + 1; /* Classify as AnyPref. */ *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ - teln = st->pa->calling; + teln = st->pa->setup.eazmsn; while (*teln) *p++ = *teln++ & 0x7f; } *p++ = 0x70; - *p++ = strlen(st->pa->called) + 1; + *p++ = strlen(st->pa->setup.phone) + 1; /* Classify as AnyPref. */ *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ - teln = st->pa->called; + teln = st->pa->setup.phone; while (*teln) *p++ = *teln++ & 0x7f; @@ -249,8 +261,8 @@ p = DATAPTR(ibh); if (st->protocol == ISDN_PTYPE_1TR6) { if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x01, 6))) { - st->pa->info = p[2]; - st->pa->info2 = p[3]; + st->pa->setup.si1 = p[2]; + st->pa->setup.si2 = p[3]; } else printk(KERN_WARNING "l3s12(1TR6): ServiceIndicator not found\n"); } else { @@ -258,31 +270,32 @@ * Bearer Capabilities */ if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x04, 0))) { + st->pa->setup.si2 = 0; switch (p[2] & 0x1f) { case 0x00: /* Speech */ case 0x10: /* 3.1 Khz audio */ - st->pa->info = 1; + st->pa->setup.si1 = 1; break; case 0x08: /* Unrestricted digital information */ - st->pa->info = 7; + st->pa->setup.si1 = 7; break; case 0x09: /* Restricted digital information */ - st->pa->info = 2; + st->pa->setup.si1 = 2; break; case 0x11: /* Unrestr. digital information with tones/announcements */ - st->pa->info = 3; + st->pa->setup.si1 = 3; break; case 0x18: /* Video */ - st->pa->info = 4; + st->pa->setup.si1 = 4; break; default: - st->pa->info = 0; + st->pa->setup.si1 = 0; } } else printk(KERN_WARNING "l3s12: Bearer capabilities not found\n"); @@ -291,26 +304,29 @@ p = DATAPTR(ibh); if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x70, 0))) - iecpy(st->pa->called, p, 1); + iecpy(st->pa->setup.eazmsn, p, 1); else - strcpy(st->pa->called, ""); + strcpy(st->pa->setup.eazmsn, ""); p = DATAPTR(ibh); if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x6c, 0))) { - if (st->protocol == ISDN_PTYPE_1TR6) - iecpy(st->pa->calling, p, 1); - else - iecpy(st->pa->calling, p, 2); + st->pa->setup.plan = p[2]; + if (st->protocol == ISDN_PTYPE_1TR6) { + iecpy(st->pa->setup.phone, p, 1); + } else { + st->pa->setup.screen = p[3]; + iecpy(st->pa->setup.phone, p, 2); + } } else - strcpy(st->pa->calling, ""); + strcpy(st->pa->setup.phone, ""); BufPoolRelease(ibh); if (bcfound) { - if (st->pa->info != 7) { + if (st->pa->setup.si1 != 7) { printk(KERN_DEBUG "non-digital call: %s -> %s\n", - st->pa->calling, - st->pa->called); + st->pa->setup.phone, + st->pa->setup.eazmsn); } newl3state(st, 6); st->l3.l3l4(st, CC_SETUP_IND, NULL); @@ -391,6 +407,42 @@ newl3state(st, 7); } +static void +l3s21(struct PStack *st, byte pr, void *arg) +{ + struct BufHeader *dibh=arg; + byte *p; + int size; + + BufPoolRelease(dibh); + + BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20); + p = DATAPTR(dibh); + p += st->l2.ihsize; + size = st->l2.ihsize; + + *p++ = 0x8; + *p++ = 0x1; + *p++ = st->l3.callref; + *p++ = MT_STATUS; + size += 4; + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = 0x9E; /* answer status enquire */ + size += 4; + + *p++ = 0x14; /* CallState */ + *p++ = 0x1; + *p++ = st->l3.state & 0x3f; /* ISO L3 CallState */ + size += 3; + + dibh->datasize = size; + i_down(st, dibh); + +} + struct stateentry { int state; byte primitive; @@ -432,34 +484,44 @@ static struct stateentry datastatelist[] = { + {0,MT_STATUS_ENQUIRY,l3s21}, {0,MT_SETUP,l3s12}, + {1,MT_STATUS_ENQUIRY,l3s21}, {1,MT_CALL_PROCEEDING,l3s6}, {1,MT_SETUP_ACKNOWLEDGE,l3s6}, {1,MT_RELEASE_COMPLETE,l3s4}, {1,MT_RELEASE,l3s19}, {1,MT_DISCONNECT,l3s7}, + {3,MT_STATUS_ENQUIRY,l3s21}, {3,MT_DISCONNECT,l3s7}, {3,MT_CONNECT,l3s8}, {3,MT_ALERTING,l3s11}, {3,MT_RELEASE,l3s19}, {3,MT_RELEASE_COMPLETE,l3s4}, + {4,MT_STATUS_ENQUIRY,l3s21}, {4,MT_CONNECT,l3s8}, {4,MT_DISCONNECT,l3s7}, {4,MT_RELEASE,l3s19}, {4,MT_RELEASE_COMPLETE,l3s4}, + {8,MT_STATUS_ENQUIRY,l3s21}, {6,MT_SETUP,l3s12}, + {8,MT_STATUS_ENQUIRY,l3s21}, {7,MT_RELEASE,l3s19}, {7,MT_RELEASE_COMPLETE,l3s4_1}, {7,MT_DISCONNECT,l3s7}, + {8,MT_STATUS_ENQUIRY,l3s21}, {8,MT_RELEASE,l3s19}, {8,MT_CONNECT_ACKNOWLEDGE,l3s17}, {8,MT_DISCONNECT,l3s7}, {8,MT_RELEASE_COMPLETE,l3s4_1}, + {10,MT_STATUS_ENQUIRY,l3s21}, {10,MT_DISCONNECT,l3s7}, {10,MT_RELEASE,l3s19}, {10,MT_RELEASE_COMPLETE,l3s4_1}, + {11,MT_STATUS_ENQUIRY,l3s21}, {11,MT_RELEASE,l3s19}, {11,MT_RELEASE_COMPLETE,l3s4}, + {19,MT_STATUS_ENQUIRY,l3s21}, {19,MT_RELEASE_COMPLETE,l3s4}, }; @@ -502,7 +564,7 @@ datastatelist_1tr6t[i].rout(st, pr, ibh); break; #endif - default: /* E-DSS1 */ + case PROTO_EURO: /* E-DSS1 */ for (i = 0; i < datasllen; i++) if ((st->l3.state == datastatelist[i].state) && (mt == datastatelist[i].primitive)) @@ -514,6 +576,10 @@ st->l3.state, mt); } else datastatelist[i].rout(st, pr, ibh); + break; + default: + BufPoolRelease(ibh); + break; } } else if (pr == DL_UNIT_DATA) { ptr = DATAPTR(ibh); @@ -540,7 +606,7 @@ datastatelist_1tr6t[i].rout(st, pr, ibh); break; #endif - default: /* E-DSS1 */ + case PROTO_EURO: /* E-DSS1 */ for (i = 0; i < datasllen; i++) if ((st->l3.state == datastatelist[i].state) && (mt == datastatelist[i].primitive)) @@ -552,6 +618,10 @@ st->l3.state, mt); } else datastatelist[i].rout(st, pr, ibh); + break; + default: + BufPoolRelease(ibh); + break; } } } diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/teles/l3_1TR6.c linux/drivers/isdn/teles/l3_1TR6.c --- v2.1.26/linux/drivers/isdn/teles/l3_1TR6.c Fri Jun 7 06:02:42 1996 +++ linux/drivers/isdn/teles/l3_1TR6.c Tue Feb 25 17:12:50 1997 @@ -1,6 +1,15 @@ -/* $Id: l3_1TR6.c,v 1.4 1996/06/06 14:22:28 fritz Exp $ +/* $Id: l3_1TR6.c,v 1.7 1997/02/11 01:38:55 keil Exp $ * * $Log: l3_1TR6.c,v $ + * Revision 1.7 1997/02/11 01:38:55 keil + * Changed setup-interface (incoming and outgoing) + * + * Revision 1.6 1996/09/25 18:34:57 keil + * missing states in 1TR6 Statemachine added + * + * Revision 1.5 1996/09/23 01:53:51 fritz + * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6). + * * Revision 1.4 1996/06/06 14:22:28 fritz * Changed level of "non-digital call..." message, since * with audio support, this is quite normal. @@ -19,6 +28,8 @@ * */ +#include "proto.h" + static void l3_1TR6_message(struct PStack *st, int mt, int pd) { @@ -55,37 +66,37 @@ *p++ = st->l3.callref; *p++ = MT_N1_SETUP; - if ('S' == (st->pa->called[0] & 0x5f)) { /* SPV ??? */ + if ('S' == (st->pa->setup.phone[0] & 0x5f)) { /* SPV ??? */ /* NSF SPV */ *p++ = WE0_netSpecFac; *p++ = 4; /* Laenge */ *p++ = 0; *p++ = FAC_SPV; /* SPV */ - *p++ = st->pa->info; /* 0 for all Services */ - *p++ = st->pa->info2; /* 0 for all Services */ + *p++ = st->pa->setup.si1; /* 0 for all Services */ + *p++ = st->pa->setup.si2; /* 0 for all Services */ *p++ = WE0_netSpecFac; *p++ = 4; /* Laenge */ *p++ = 0; *p++ = FAC_Activate; /* aktiviere SPV (default) */ - *p++ = st->pa->info; /* 0 for all Services */ - *p++ = st->pa->info2; /* 0 for all Services */ + *p++ = st->pa->setup.si1; /* 0 for all Services */ + *p++ = st->pa->setup.si2; /* 0 for all Services */ } - if (st->pa->calling[0] != '\0') { + if (st->pa->setup.eazmsn[0]) { *p++ = WE0_origAddr; - *p++ = strlen(st->pa->calling) + 1; + *p++ = strlen(st->pa->setup.eazmsn) + 1; /* Classify as AnyPref. */ *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ - teln = st->pa->calling; + teln = st->pa->setup.eazmsn; while (*teln) *p++ = *teln++ & 0x7f; } *p++ = WE0_destAddr; - teln = st->pa->called; - if ('S' != (st->pa->called[0] & 0x5f)) { /* Keine SPV ??? */ - *p++ = strlen(st->pa->called) + 1; + teln = st->pa->setup.phone; + if ('S' != (st->pa->setup.phone[0] & 0x5f)) { /* Keine SPV ??? */ + *p++ = strlen(st->pa->setup.phone) + 1; st->pa->spv = 0; } else { /* SPV */ - *p++ = strlen(st->pa->called); + *p++ = strlen(st->pa->setup.phone); teln++; /* skip S */ st->pa->spv = 1; } @@ -98,8 +109,8 @@ /* Codesatz 6 fuer Service */ *p++ = WE6_serviceInd; *p++ = 2; /* len=2 info,info2 */ - *p++ = st->pa->info; - *p++ = st->pa->info2; + *p++ = st->pa->setup.si1; + *p++ = st->pa->setup.si2; dibh->datasize = p - DATAPTR(dibh); @@ -130,24 +141,24 @@ p = DATAPTR(ibh); if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, WE6_serviceInd, 6))) { - st->pa->info = p[2]; - st->pa->info2 = p[3]; + st->pa->setup.si1 = p[2]; + st->pa->setup.si2 = p[3]; } else printk(KERN_INFO "l3s12(1TR6): ServiceIndicator not found\n"); p = DATAPTR(ibh); if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, WE0_destAddr, 0))) - iecpy(st->pa->called, p, 1); + iecpy(st->pa->setup.eazmsn, p, 1); else - strcpy(st->pa->called, ""); + strcpy(st->pa->setup.eazmsn, ""); p = DATAPTR(ibh); if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, WE0_origAddr, 0))) { - iecpy(st->pa->calling, p, 1); + iecpy(st->pa->setup.phone, p, 1); } else - strcpy(st->pa->calling, ""); + strcpy(st->pa->setup.phone, ""); p = DATAPTR(ibh); st->pa->spv = 0; @@ -159,10 +170,10 @@ BufPoolRelease(ibh); /* Signal all services, linklevel takes care of Service-Indicator */ - if (st->pa->info != 7) { + if (st->pa->setup.si1 != 7) { printk(KERN_DEBUG "non-digital call: %s -> %s\n", - st->pa->calling, - st->pa->called); + st->pa->setup.phone, + st->pa->setup.eazmsn); } newl3state(st, 6); st->l3.l3l4(st, CC_SETUP_IND, NULL); @@ -387,14 +398,14 @@ *p++ = 4; /* Laenge */ *p++ = 0; *p++ = FAC_SPV; /* SPV */ - *p++ = st->pa->info; - *p++ = st->pa->info2; + *p++ = st->pa->setup.si1; + *p++ = st->pa->setup.si2; *p++ = WE0_netSpecFac; *p++ = 4; /* Laenge */ *p++ = 0; *p++ = FAC_Activate; /* aktiviere SPV */ - *p++ = st->pa->info; - *p++ = st->pa->info2; + *p++ = st->pa->setup.si1; + *p++ = st->pa->setup.si2; } dibh->datasize = p - DATAPTR(dibh); @@ -404,7 +415,7 @@ } static void -l3_1tr6_ignore(struct PStack *st, byte pr, void *arg) +l3_1tr6_reset(struct PStack *st, byte pr, void *arg) { newl3state(st, 0); } @@ -453,16 +464,36 @@ static struct stateentry downstatelist_1tr6t[] = { {0, CC_SETUP_REQ, l3_1tr6_setup}, + {1, CC_DISCONNECT_REQ, l3_1tr6_disconn_req}, + {1, CC_RELEASE_REQ, l3_1tr6_rel_req}, + {1, CC_DLRL, l3_1tr6_reset}, + {2, CC_DISCONNECT_REQ, l3_1tr6_disconn_req}, + {2, CC_RELEASE_REQ, l3_1tr6_rel_req}, + {2, CC_DLRL, l3_1tr6_reset}, + {3, CC_DISCONNECT_REQ, l3_1tr6_disconn_req}, + {3, CC_RELEASE_REQ, l3_1tr6_rel_req}, + {3, CC_DLRL, l3_1tr6_reset}, {4, CC_DISCONNECT_REQ, l3_1tr6_disconn_req}, - {6, CC_REJECT_REQ, l3_1tr6_ignore}, + {4, CC_RELEASE_REQ, l3_1tr6_rel_req}, + {4, CC_DLRL, l3_1tr6_reset}, + {6, CC_REJECT_REQ, l3_1tr6_reset}, + {6, CC_RELEASE_REQ, l3_1tr6_rel_req}, {6, CC_SETUP_RSP, l3_1tr6_conn}, {6, CC_ALERTING_REQ, l3_1tr6_alert}, + {6, CC_DLRL, l3_1tr6_reset}, {7, CC_SETUP_RSP, l3_1tr6_conn}, + {7, CC_RELEASE_REQ, l3_1tr6_rel_req}, {7, CC_DISCONNECT_REQ, l3_1tr6_disconn_req}, - {7, CC_DLRL, l3_1tr6_disconn_req}, + {7, CC_DLRL, l3_1tr6_reset}, {8, CC_DISCONNECT_REQ, l3_1tr6_disconn_req}, + {8, CC_RELEASE_REQ, l3_1tr6_rel_req}, + {8, CC_DLRL, l3_1tr6_reset}, {10, CC_DISCONNECT_REQ, l3_1tr6_disconn_req}, - {12, CC_RELEASE_REQ, l3_1tr6_rel_req} + {10, CC_RELEASE_REQ, l3_1tr6_rel_req}, + {10, CC_DLRL, l3_1tr6_reset}, + {12, CC_RELEASE_REQ, l3_1tr6_rel_req}, + {12, CC_DLRL, l3_1tr6_reset}, + {19, CC_DLRL, l3_1tr6_reset}, }; static int downsl_1tr6t_len = sizeof(downstatelist_1tr6t) / diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/teles/l3_1TR6.h linux/drivers/isdn/teles/l3_1TR6.h --- v2.1.26/linux/drivers/isdn/teles/l3_1TR6.h Sun May 19 05:29:31 1996 +++ linux/drivers/isdn/teles/l3_1TR6.h Tue Feb 25 17:12:50 1997 @@ -1,6 +1,9 @@ -/* $Id: l3_1TR6.h,v 1.3 1996/04/30 21:53:48 isdn4dev Exp $ +/* $Id: l3_1TR6.h,v 1.4 1996/09/23 01:53:52 fritz Exp $ * * $Log: l3_1TR6.h,v $ + * Revision 1.4 1996/09/23 01:53:52 fritz + * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6). + * * Revision 1.3 1996/04/30 21:53:48 isdn4dev * Bugs, SPV, Logging in q931.c Karsten Keil * @@ -11,9 +14,6 @@ */ #ifndef l3_1TR6 #define l3_1TR6 - -#define PROTO_DIS_N0 0x40 -#define PROTO_DIS_N1 0x41 /* * MsgType N0 diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/teles/llglue.c linux/drivers/isdn/teles/llglue.c --- v2.1.26/linux/drivers/isdn/teles/llglue.c Mon Oct 28 10:57:46 1996 +++ linux/drivers/isdn/teles/llglue.c Tue Feb 25 17:12:50 1997 @@ -1,6 +1,9 @@ -/* $Id: llglue.c,v 1.6 1996/06/03 20:03:39 fritz Exp $ +/* $Id: llglue.c,v 1.7 1996/10/22 23:14:17 fritz Exp $ * * $Log: llglue.c,v $ + * Revision 1.7 1996/10/22 23:14:17 fritz + * Changes for compatibility to 2.0.X and 2.1.X kernels. + * * Revision 1.6 1996/06/03 20:03:39 fritz * Fixed typos. * @@ -46,10 +49,9 @@ byte *p; for (p = buf, count = 0; count < len; p++, count++) { - if (user) { - put_user(*teles_status_read, p); - teles_status_read++; - } else + if (user) + put_user(*teles_status_read++, p); + else *p++ = *teles_status_read++; if (teles_status_read > teles_status_end) teles_status_read = teles_status_buf; diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/teles/mod.c linux/drivers/isdn/teles/mod.c --- v2.1.26/linux/drivers/isdn/teles/mod.c Fri Dec 27 02:03:22 1996 +++ linux/drivers/isdn/teles/mod.c Tue Feb 25 17:12:50 1997 @@ -1,6 +1,12 @@ -/* $Id: mod.c,v 1.1 1996/04/13 10:27:02 fritz Exp $ +/* $Id: mod.c,v 1.3 1997/02/14 12:23:31 fritz Exp $ * * $Log: mod.c,v $ + * Revision 1.3 1997/02/14 12:23:31 fritz + * Added support for new insmod parameter handling. + * + * Revision 1.2 1997/02/10 11:45:14 fritz + * More changes for Kernel 2.1.X compatibility. + * * Revision 1.1 1996/04/13 10:27:02 fritz * Initial revision * @@ -14,7 +20,7 @@ int nrcards; typedef struct { - unsigned int membase; + byte *membase; int interrupt; unsigned int iobase; unsigned int protocol; @@ -40,6 +46,13 @@ {0, 0, 0, 0}, }; +#ifdef MODULE +#if (LINUX_VERSION_CODE > 0x020111) +MODULE_PARM(io, "1-64i"); +MODULE_PARM(teles_id, "s"); +#endif +#endif + void teles_mod_dec_use_count(void) { @@ -53,7 +66,6 @@ } #ifdef MODULE -EXPORT_NO_SYMBOLS; #define teles_init init_module #else void teles_setup(char *str, int *ints) @@ -74,7 +86,7 @@ j++; argc--; } if (argc) { - io[i].membase = ints[j]; + io[i].membase = (byte *)ints[j]; j++; argc--; } if (argc) { @@ -116,7 +128,14 @@ CallcNew(); ll_init(); + /* No symbols to export, hide all symbols */ + #ifdef MODULE +#if (LINUX_VERSION_CODE < 0x020111) + register_symtab(NULL); +#else + EXPORT_NO_SYMBOLS; +#endif printk(KERN_NOTICE "Teles module installed\n"); #endif return (0); diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/teles/q931.c linux/drivers/isdn/teles/q931.c --- v2.1.26/linux/drivers/isdn/teles/q931.c Fri Jun 7 06:02:42 1996 +++ linux/drivers/isdn/teles/q931.c Tue Feb 25 17:12:50 1997 @@ -1,4 +1,4 @@ -/* $Id: q931.c,v 1.5 1996/06/03 20:03:40 fritz Exp $ +/* $Id: q931.c,v 1.6 1996/09/23 01:53:53 fritz Exp $ * * q931.c code to decode ITU Q.931 call control messages * @@ -14,6 +14,9 @@ * * * $Log: q931.c,v $ + * Revision 1.6 1996/09/23 01:53:53 fritz + * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6). + * * Revision 1.5 1996/06/03 20:03:40 fritz * Fixed typos. * @@ -35,6 +38,7 @@ #define __NO_VERSION__ #include "teles.h" +#include "proto.h" #include "l3_1TR6.h" byte * @@ -1083,7 +1087,7 @@ } buf += buf[1] + 2; } - } else { /* EURO */ + } else if (buf[0]==PROTO_EURO) { /* EURO */ /* locate message type */ for (i = 0; i < MTSIZE; i++) if (mtlist[i].nr == buf[3]) @@ -1144,6 +1148,8 @@ buf += buf[1] + 2; } } + else dp += sprintf(dp,"Unnown frame type %.2x, ignored\n",buf[0]); + dp += sprintf(dp, "\n"); teles_putstatus(sp->dlogspace); } diff -u --recursive --new-file v2.1.26/linux/drivers/isdn/teles/teles.h linux/drivers/isdn/teles/teles.h --- v2.1.26/linux/drivers/isdn/teles/teles.h Mon Oct 28 11:48:39 1996 +++ linux/drivers/isdn/teles/teles.h Tue Feb 25 17:12:50 1997 @@ -1,6 +1,9 @@ -/* $Id: teles.h,v 1.2 1996/04/30 21:52:04 isdn4dev Exp $ +/* $Id: teles.h,v 1.3 1997/02/11 01:40:36 keil Exp $ * * $Log: teles.h,v $ + * Revision 1.3 1997/02/11 01:40:36 keil + * New Param structure + * * Revision 1.2 1996/04/30 21:52:04 isdn4dev * SPV for 1TR6 - Karsten * @@ -14,6 +17,8 @@ #include #include #include +#include +#include #include #include #include @@ -26,9 +31,6 @@ #include #include -#include -#include - #define PH_ACTIVATE 1 #define PH_DATA 2 #define PH_DEACTIVATE 3 @@ -284,11 +286,7 @@ int cause; int bchannel; int callref; /* TEI-Number */ - int itc; - int info; /* Service-Indicator */ - int info2; /* Service-Indicator, second octet */ - char calling[40]; /* Called Id */ - char called[40]; /* Caller Id */ + setup_parm setup; /* from isdnif.h numbers and Serviceindicator */ int chargeinfo; /* Charge Info - only for 1tr6 in * the moment */ @@ -307,7 +305,7 @@ }; struct HscxState { - unsigned int membase; + byte *membase; int iobase; int inuse, init, active; struct BufPool sbufpool, rbufpool, smallpool; @@ -330,7 +328,7 @@ #ifdef DEBUG_MAGIC int magic; #endif - unsigned int membase; + byte *membase; int iobase; struct BufPool sbufpool, rbufpool, smallpool; struct PStack *stlist; @@ -352,7 +350,7 @@ }; struct IsdnCard { - unsigned int membase; + byte *membase; int interrupt; unsigned int iobase; int protocol; /* EDSS1 or 1TR6 */ diff -u --recursive --new-file v2.1.26/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.1.26/linux/drivers/net/3c59x.c Sun Feb 2 05:18:35 1997 +++ linux/drivers/net/3c59x.c Fri Feb 21 14:58:33 1997 @@ -36,8 +36,12 @@ #include #include #include + +#ifdef CONFIG_PCI #include #include +#endif + #include #include #include @@ -79,7 +83,10 @@ int vortex_debug = 1; #endif +#ifdef CONFIG_PCI static int product_ids[] = {0x5900, 0x5950, 0x5951, 0x5952, 0, 0}; +#endif + static const char *product_names[] = { "3c590 Vortex 10Mbps", "3c595 Vortex 100baseTX", @@ -336,6 +343,7 @@ { int cards_found = 0; +#ifdef CONFIG_PCI if (pcibios_present()) { static int pci_index = 0; static int board_index = 0; @@ -388,6 +396,7 @@ } } } +#endif /* CONFIG_PCI */ /* Now check all slots of the EISA bus. */ if (EISA_bus) { diff -u --recursive --new-file v2.1.26/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.1.26/linux/drivers/net/Config.in Sun Feb 2 05:18:35 1997 +++ linux/drivers/net/Config.in Fri Feb 21 14:58:33 1997 @@ -137,12 +137,11 @@ bool 'Soundmodem support for Soundblaster and compatible cards' CONFIG_SOUNDMODEM_SBC bool 'Soundmodem support for WSS and Crystal cards' CONFIG_SOUNDMODEM_WSS bool 'Soundmodem support for 1200 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK1200 + bool 'Soundmodem support for 4800 baud HAPN-1 modulation' CONFIG_SOUNDMODEM_HAPN4800 + bool 'Soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600 if [ "$CONFIG_M586" = "y" -o "$CONFIG_M686" = "y" ]; then - if [ "$CONFIG_SOUNDMODEM_AFSK1200" != "n" ]; then - bool 'Soundmodem 1200 baud AFSK using floating point' CONFIG_SOUNDMODEM_AFSK1200_FP - fi + bool 'Soundmodem using floating point' CONFIG_SOUNDMODEM_FLOAT fi - bool 'Soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600 fi fi tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP diff -u --recursive --new-file v2.1.26/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.1.26/linux/drivers/net/Makefile Sun Feb 2 05:18:36 1997 +++ linux/drivers/net/Makefile Fri Feb 21 14:58:33 1997 @@ -7,6 +7,10 @@ # are difficult for users to deal with. include CONFIG +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + L_TARGET := net.a L_OBJS := auto_irq.o M_OBJS := @@ -649,12 +653,14 @@ endif ifeq ($(CONFIG_SOUNDMODEM),y) -L_OBJS += soundmodem.o +ALL_SUB_DIRS += soundmodem +SUB_DIRS += soundmodem CONFIG_HDLCDRV_BUILTIN = y else ifeq ($(CONFIG_SOUNDMODEM),m) CONFIG_HDLCDRV_MODULE = y - M_OBJS += soundmodem.o + ALL_SUB_DIRS += soundmodem + MOD_SUB_DIRS += soundmodem endif endif @@ -667,7 +673,6 @@ MX_OBJS += hdlcdrv.o endif endif - ifeq ($(CONFIG_VENDOR_SANGOMA),y) M_OBJS += sdladrv.o diff -u --recursive --new-file v2.1.26/linux/drivers/net/baycom.c linux/drivers/net/baycom.c --- v2.1.26/linux/drivers/net/baycom.c Tue Dec 31 00:30:00 1996 +++ linux/drivers/net/baycom.c Fri Feb 21 14:58:34 1997 @@ -73,7 +73,6 @@ /*****************************************************************************/ #include - #include #include #include @@ -85,7 +84,6 @@ #include #include #include -#include #include #include #include @@ -94,6 +92,48 @@ /* --------------------------------------------------------------------- */ +/* + * currently this module is supposed to support both module styles, i.e. + * the old one present up to about 2.1.9, and the new one functioning + * starting with 2.1.21. The reason is I have a kit allowing to compile + * this module also under 2.0.x which was requested by several people. + * This will go in 2.2 + */ +#include + +#if LINUX_VERSION_CODE >= 0x20100 +#include +#else +#include +#include + +#undef put_user +#undef get_user + +#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; }) +#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; }) + +extern inline int copy_from_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_READ, from, n); + if (i) + return i; + memcpy_fromfs(to, from, n); + return 0; +} + +extern inline int copy_to_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_WRITE, to, n); + if (i) + return i; + memcpy_tofs(to, from, n); + return 0; +} +#endif + +/* --------------------------------------------------------------------- */ + #define BAYCOM_DEBUG /* @@ -101,7 +141,6 @@ */ #define BAYCOM_OPTIONS_SOFTDCD 1 - /* --------------------------------------------------------------------- */ static const char bc_drvname[] = "baycom"; @@ -897,9 +936,6 @@ /* --------------------------------------------------------------------- */ -#ifdef MODULE -static -#endif /* MODULE */ int baycom_init(void) { int i, j, found = 0; @@ -946,12 +982,23 @@ /* * command line settable parameters */ -char *mode = NULL; -int iobase = 0x3f8; -int irq = 4; +static char *mode = NULL; +static int iobase = 0x3f8; +static int irq = 4; + +#if LINUX_VERSION_CODE >= 0x20115 + MODULE_PARM(mode, "s"); +MODULE_PARM_DESC(mode, "baycom operating mode; eg. ser12* or par96"); MODULE_PARM(iobase, "i"); +MODULE_PARM_DESC(iobase, "baycom io base address"); MODULE_PARM(irq, "i"); +MODULE_PARM_DESC(irq, "baycom irq number"); + +MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); +MODULE_DESCRIPTION("Baycom ser12, par96 and picpar amateur radio modem driver"); + +#endif int init_module(void) { @@ -996,7 +1043,7 @@ int i; for (i = 0; (i < NR_PORTS) && (baycom_ports[i].mode); i++); - if ((i >= NR_PORTS) || (ints[0] < 3)) { + if ((i >= NR_PORTS) || (ints[0] < 2)) { printk(KERN_INFO "%s: too many or invalid interface " "specifications\n", bc_drvname); return; diff -u --recursive --new-file v2.1.26/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c --- v2.1.26/linux/drivers/net/cs89x0.c Sun Feb 2 05:18:36 1997 +++ linux/drivers/net/cs89x0.c Fri Feb 21 14:58:34 1997 @@ -1180,3 +1180,4 @@ * tab-width: 8 * End: * + */ diff -u --recursive --new-file v2.1.26/linux/drivers/net/dlci.c linux/drivers/net/dlci.c --- v2.1.26/linux/drivers/net/dlci.c Sun Feb 2 05:18:39 1997 +++ linux/drivers/net/dlci.c Fri Feb 21 14:58:34 1997 @@ -296,7 +296,7 @@ if (!get) { if(copy_from_user(&config, conf, sizeof(struct dlci_conf))) - return -FAULT; + return -EFAULT; if (config.flags & ~DLCI_VALID_FLAGS) return(-EINVAL); memcpy(&dlp->config, &config, sizeof(struct dlci_conf)); diff -u --recursive --new-file v2.1.26/linux/drivers/net/hdlcdrv.c linux/drivers/net/hdlcdrv.c --- v2.1.26/linux/drivers/net/hdlcdrv.c Sun Feb 2 05:18:40 1997 +++ linux/drivers/net/hdlcdrv.c Fri Feb 21 14:58:34 1997 @@ -44,13 +44,16 @@ #include #include #include -#include + #include #include #include #include #include -#include +#ifdef CONFIG_AX25 +/* prototypes for ax25_encapsulate and ax25_rebuild_header */ +#include +#endif /* CONFIG_AX25 */ /* make genksyms happy */ #include @@ -61,6 +64,61 @@ /* --------------------------------------------------------------------- */ /* + * currently this module is supposed to support both module styles, i.e. + * the old one present up to about 2.1.9, and the new one functioning + * starting with 2.1.21. The reason is I have a kit allowing to compile + * this module also under 2.0.x which was requested by several people. + * This will go in 2.2 + */ +#include + +#if LINUX_VERSION_CODE >= 0x20100 +#include +#else +#include +#include + +#undef put_user +#undef get_user + +#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; }) +#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; }) + +extern inline int copy_from_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_READ, from, n); + if (i) + return i; + memcpy_fromfs(to, from, n); + return 0; +} + +extern inline int copy_to_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_WRITE, to, n); + if (i) + return i; + memcpy_tofs(to, from, n); + return 0; +} +#endif + +/* --------------------------------------------------------------------- */ + +#if LINUX_VERSION_CODE < 0x20115 +extern __inline__ void dev_init_buffers(struct device *dev) +{ + int i; + for(i=0;ibuffs[i]); + } +} +#endif + +/* --------------------------------------------------------------------- */ + +/* * The name of the card. Is used for messages and in the requests for * io regions, irqs and dma channels */ @@ -518,7 +576,11 @@ /* --------------------------------------------------------------------- */ +#if LINUX_VERSION_CODE >= 0x20119 static struct net_device_stats *hdlcdrv_get_stats(struct device *dev) +#else +static struct enet_statistics *hdlcdrv_get_stats(struct device *dev) +#endif { struct hdlcdrv_state *sm; @@ -743,7 +805,9 @@ */ static int hdlcdrv_probe(struct device *dev) { - struct hdlcdrv_channel_params dflt_ch_params = { 20, 2, 10, 40, 0 }; + const struct hdlcdrv_channel_params dflt_ch_params = { + 20, 2, 10, 40, 0 + }; struct hdlcdrv_state *s; if (!dev) @@ -887,21 +951,49 @@ /* --------------------------------------------------------------------- */ +#if LINUX_VERSION_CODE >= 0x20115 + EXPORT_SYMBOL(hdlcdrv_receiver); EXPORT_SYMBOL(hdlcdrv_transmitter); EXPORT_SYMBOL(hdlcdrv_arbitrate); EXPORT_SYMBOL(hdlcdrv_register_hdlcdrv); EXPORT_SYMBOL(hdlcdrv_unregister_hdlcdrv); +#else + +static struct symbol_table hdlcdrv_syms = { +#include + X(hdlcdrv_receiver), + X(hdlcdrv_transmitter), + X(hdlcdrv_arbitrate), + X(hdlcdrv_register_hdlcdrv), + X(hdlcdrv_unregister_hdlcdrv), +#include +}; + +#endif + /* --------------------------------------------------------------------- */ #ifdef MODULE +#if LINUX_VERSION_CODE >= 0x20115 + +MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); +MODULE_DESCRIPTION("Packet Radio network interface HDLC encoder/decoder"); + +#endif + +/* --------------------------------------------------------------------- */ + int init_module(void) { printk(KERN_INFO "hdlcdrv: (C) 1996 Thomas Sailer HB9JNX/AE4WA\n"); printk(KERN_INFO "hdlcdrv: version 0.2 compiled %s %s\n", __TIME__, __DATE__); +#if LINUX_VERSION_CODE < 0x20115 + register_symtab(&hdlcdrv_syms); +#endif return 0; } diff -u --recursive --new-file v2.1.26/linux/drivers/net/ltpc.c linux/drivers/net/ltpc.c --- v2.1.26/linux/drivers/net/ltpc.c Sun Feb 2 05:18:40 1997 +++ linux/drivers/net/ltpc.c Fri Feb 21 14:58:34 1997 @@ -830,6 +830,15 @@ /* Actually netatalk needs fixing! */ } +static int ltpc_hard_header (struct sk_buff *skb, struct device *dev, + unsigned short type, void *daddr, void *saddr, unsigned len) +{ + if(debug&DEBUG_VERBOSE) + printk("ltpc_hard_header called for device %s\n", + dev->name); + return 0; +} + static int ltpc_init(struct device *dev) { /* Initialize the device structure. */ @@ -837,6 +846,7 @@ /* Fill in the fields of the device structure with ethernet-generic values. */ ltalk_setup(dev); dev->hard_start_xmit = ltpc_xmit; + dev->hard_header = ltpc_hard_header; dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); if(!dev->priv) @@ -855,6 +865,8 @@ dev->do_ioctl = <pc_ioctl; dev->set_multicast_list = &set_multicast_list; + dev->mc_list = NULL; + return 0; } @@ -874,23 +886,23 @@ ltpc_poll_counter--; } - if (!dev) return; /* we've been downed */ + if (!dev) + return; /* we've been downed */ - if (dev->irq) { + if (dev->irq) + { /* we're set up for interrupts */ if (0xf8 != inb_p(dev->base_addr+7)) { /* trigger an interrupt */ (void) inb_p(dev->base_addr+6); } - ltpc_timer.expires = 100; + ltpc_timer.expires = jiffies+100; } else { /* we're strictly polling mode */ idle(dev); - ltpc_timer.expires = 5; + ltpc_timer.expires = jiffies+5; } - ltpc_timer.expires += jiffies; /* 1.2 to 1.3 change... */ - add_timer(<pc_timer); } @@ -1188,6 +1200,8 @@ ltpc_timer.expires = 5; /* polled mode -- 20 times per second */ } + + ltpc_timer.expires += jiffies; /* 1.2 to 1.3 change... */ add_timer(<pc_timer); diff -u --recursive --new-file v2.1.26/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c --- v2.1.26/linux/drivers/net/myri_sbus.c Sun Feb 2 05:18:40 1997 +++ linux/drivers/net/myri_sbus.c Fri Feb 21 14:58:34 1997 @@ -742,6 +742,7 @@ if (ndisc_eth_hook) return (ndisc_eth_hook(eth->h_dest, dev, skb)); #endif + break; #endif default: printk(KERN_DEBUG diff -u --recursive --new-file v2.1.26/linux/drivers/net/ne.c linux/drivers/net/ne.c --- v2.1.26/linux/drivers/net/ne.c Tue Dec 31 00:30:01 1996 +++ linux/drivers/net/ne.c Fri Feb 21 14:58:34 1997 @@ -75,6 +75,7 @@ {PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8029}, {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940}, {PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_RL2000}, + {PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_ET32P2}, {0,} }; #endif diff -u --recursive --new-file v2.1.26/linux/drivers/net/ni52.c linux/drivers/net/ni52.c --- v2.1.26/linux/drivers/net/ni52.c Sun Feb 2 05:18:40 1997 +++ linux/drivers/net/ni52.c Fri Feb 21 14:58:34 1997 @@ -164,7 +164,7 @@ #define DELAY_18(); { __delay( (loops_per_sec>>18)+1 ); } /* wait for command with timeout: */ -#define WAIT_4_SCB_CMD() +#define WAIT_4_SCB_CMD() \ { int i; \ for(i=0;i<16384;i++) { \ if(!p->scb->cmd_cuc) break; \ diff -u --recursive --new-file v2.1.26/linux/drivers/net/sdla.c linux/drivers/net/sdla.c --- v2.1.26/linux/drivers/net/sdla.c Sun Feb 2 05:18:41 1997 +++ linux/drivers/net/sdla.c Fri Feb 21 14:58:34 1997 @@ -432,7 +432,7 @@ cmd_buf->flags = flags; if (inbuf) - amemcpy(cmd_buf->data, inbuf, inlen); + memcpy(cmd_buf->data, inbuf, inlen); cmd_buf->length = inlen; @@ -1103,7 +1103,7 @@ { struct frad_local *flp; struct conf_data data; - int i, err; + int i; short size; if (dev->type == 0xFFFF) diff -u --recursive --new-file v2.1.26/linux/drivers/net/sm_afsk1200.h linux/drivers/net/sm_afsk1200.h --- v2.1.26/linux/drivers/net/sm_afsk1200.h Sat Dec 21 09:08:38 1996 +++ linux/drivers/net/sm_afsk1200.h Wed Dec 31 16:00:00 1969 @@ -1,304 +0,0 @@ -/*****************************************************************************/ - -/* - * sm_afsk1200.h -- soundcard radio modem driver, 1200 baud AFSK modem - * - * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Please note that the GPL allows you to use the driver, NOT the radio. - * In order to use the radio, you need a license from the communications - * authority of your country. - * - */ - -#include - -/* --------------------------------------------------------------------- */ - -struct demod_state_afsk12 { - unsigned int shreg; - unsigned int bit_pll; - unsigned char last_sample; - unsigned int dcd_shreg; - int dcd_sum0, dcd_sum1, dcd_sum2; - unsigned int dcd_time; - unsigned char last_rxbit; - union { - signed char c[8]; - float f[8]; - } filt; -}; - -struct mod_state_afsk12 { - unsigned int shreg; - unsigned char tx_bit; - unsigned int bit_pll; -}; - -#define DEMOD_STATE ((struct demod_state_afsk12 *)(&sm->d)) -#define MOD_STATE ((struct mod_state_afsk12 *)(&sm->m)) - -/* --------------------------------------------------------------------- */ - -static const char sinetab[] = { - 128, 140, 152, 164, 176, 187, 198, 208, - 217, 226, 233, 240, 245, 249, 252, 254, - 255, 254, 252, 249, 245, 240, 233, 226, - 217, 208, 198, 187, 176, 164, 152, 140, - 128, 116, 104, 92, 80, 69, 58, 48, - 39, 30, 23, 16, 11, 7, 4, 2, - 1, 2, 4, 7, 11, 16, 23, 30, - 39, 48, 58, 69, 80, 92, 104, 116 -}; - -/* --------------------------------------------------------------------- */ - -static void modulator_1200(struct sm_state *sm, unsigned char *buf, int buflen) -{ - static const int dds_inc[2] = { 8192, 15019 }; - int j, k; - - for (; buflen >= 8; buflen -= 8) { - if (MOD_STATE->shreg <= 1) - MOD_STATE->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - MOD_STATE->tx_bit = (MOD_STATE->tx_bit ^ - (!(MOD_STATE->shreg & 1))) & 1; - MOD_STATE->shreg >>= 1; - k = dds_inc[MOD_STATE->tx_bit & 1]; - for (j = 0; j < 8; j++) { - *buf++ = sinetab[(MOD_STATE->bit_pll >> 10) & 0x3f]; - MOD_STATE->bit_pll += k; - } - } -} - -/* --------------------------------------------------------------------- */ - -/* - * should eventually move to an asm header file - */ -#if defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && (defined(CONFIG_M586) || defined(CONFIG_M686)) - -#define ENV_STORAGE unsigned char fpu_save[108]; - -#define ENV_SAVE asm("fsave %0;\n\tfninit;\n\t" : "=m" (*fpu_save) : : "memory"); -#define ENV_RESTORE asm("frstor %0;\n\t" : : "m" (*fpu_save)); - -static const float tx_lo_i_f[] = { - 1.000000, 0.707107, 0.000000, -0.707107, -1.000000, -0.707107, -0.000000, 0.707107 -}; - -static const float tx_lo_q_f[] = { - 0.000000, 0.707107, 1.000000, 0.707107, 0.000000, -0.707107, -1.000000, -0.707107 -}; - -static const float tx_hi_i_f[] = { - 1.000000, 0.130526, -0.965926, -0.382683, 0.866025, 0.608761, -0.707107, -0.793353 -}; - -static const float tx_hi_q_f[] = { - 0.000000, 0.991445, 0.258819, -0.923880, -0.500000, 0.793353, 0.707107, -0.608761 -}; - -static inline float convolution8(const float *st, const float *coeff) -{ - float f; - - /* - * from Phil Karn, KA9Q's home page - */ - asm volatile ("flds (%1);\n\t" - "fmuls (%2);\n\t" - "flds 4(%1);\n\t" - "fmuls 4(%2);\n\t" - "flds 8(%1);\n\t" - "fmuls 8(%2);\n\t" - "fxch %%st(2);\n\t" - "faddp;\n\t" - "flds 12(%1);\n\t" - "fmuls 12(%2);\n\t" - "fxch %%st(2);\n\t" - "faddp;\n\t" - "flds 16(%1);\n\t" - "fmuls 16(%2);\n\t" - "fxch %%st(2);\n\t" - "faddp;\n\t" - "flds 20(%1);\n\t" - "fmuls 20(%2);\n\t" - "fxch %%st(2);\n\t" - "faddp;\n\t" - "flds 24(%1);\n\t" - "fmuls 24(%2);\n\t" - "fxch %%st(2);\n\t" - "faddp;\n\t" - "flds 28(%1);\n\t" - "fmuls 28(%2);\n\t" - "fxch %%st(2);\n\t" - "faddp;\n\t" - "faddp;\n\t" - "fmul %%st(0),%%st;\n\t" : - "=t" (f) : - "r" (st), - "r" (coeff) : "memory"); - - return f; -} - -static inline int do_filter_1200(struct sm_state *sm, unsigned char newval) -{ - float sum; - - memmove(DEMOD_STATE->filt.f+1, DEMOD_STATE->filt.f, - sizeof(DEMOD_STATE->filt.f) - sizeof(DEMOD_STATE->filt.f[0])); - DEMOD_STATE->filt.f[0] = (((int)newval)-0x80); - - sum = convolution8(DEMOD_STATE->filt.f, tx_lo_i); - sum += convolution8(DEMOD_STATE->filt.f, tx_lo_q); - sum -= convolution8(DEMOD_STATE->filt.f, tx_hi_i); - sum -= convolution8(DEMOD_STATE->filt.f, tx_hi_q); - return sum; -} - -#else /* defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */ - -#define ENV_STORAGE -#define ENV_SAVE -#define ENV_RESTORE - -static const char tx_lo_i[] = { 127, 89, 0, -89, -127, -89, 0, 89 }; -static const char tx_lo_q[] = { 0, 89, 127, 89, 0, -89, -127, -89 }; -static const char tx_hi_i[] = { 127, 16, -122, -48, 109, 77, -89, -100 }; -static const char tx_hi_q[] = { 0, 125, 32, -117, -63, 100, 89, -77 }; - -static inline void datamove8(signed char *st, unsigned char newval) -{ - memmove(st+1, st, 7); - *st = newval - 0x80; -} - -static inline int convolution8(const signed char *st, const signed char *coeff) -{ - int sum = (st[0] * coeff[0]); - - sum += (st[1] * coeff[1]); - sum += (st[2] * coeff[2]); - sum += (st[3] * coeff[3]); - sum += (st[4] * coeff[4]); - sum += (st[5] * coeff[5]); - sum += (st[6] * coeff[6]); - sum += (st[7] * coeff[7]); - - sum >>= 7; - return sum * sum; -} - -static inline int do_filter_1200(struct sm_state *sm, unsigned char newval) -{ - int sum; - - datamove8(DEMOD_STATE->filt.c, newval); - - sum = convolution8(DEMOD_STATE->filt.c, tx_lo_i); - sum += convolution8(DEMOD_STATE->filt.c, tx_lo_q); - sum -= convolution8(DEMOD_STATE->filt.c, tx_hi_i); - sum -= convolution8(DEMOD_STATE->filt.c, tx_hi_q); - return sum; -} - -#endif /* defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */ - - -/* --------------------------------------------------------------------- */ - -static void demodulator_1200(struct sm_state *sm, unsigned char *buf, int buflen) -{ - static const int pll_corr[2] = { -0x1000, 0x1000 }; - int j; - int sum; - unsigned char newsample; - ENV_STORAGE; - - ENV_SAVE; - for (; buflen > 0; buflen--, buf++) { - sum = do_filter_1200(sm, *buf); - DEMOD_STATE->dcd_shreg <<= 1; - DEMOD_STATE->bit_pll += 0x2000; - newsample = (sum > 0); - if (DEMOD_STATE->last_sample ^ newsample) { - DEMOD_STATE->last_sample = newsample; - DEMOD_STATE->dcd_shreg |= 1; - DEMOD_STATE->bit_pll += pll_corr - [DEMOD_STATE->bit_pll < 0x9000]; - j = 4 * hweight8(DEMOD_STATE->dcd_shreg & 0x38) - - hweight16(DEMOD_STATE->dcd_shreg & 0x7c0); - DEMOD_STATE->dcd_sum0 += j; - } - hdlcdrv_channelbit(&sm->hdrv, DEMOD_STATE->last_sample); - if ((--DEMOD_STATE->dcd_time) <= 0) { - hdlcdrv_setdcd(&sm->hdrv, (DEMOD_STATE->dcd_sum0 + - DEMOD_STATE->dcd_sum1 + - DEMOD_STATE->dcd_sum2) < 0); - DEMOD_STATE->dcd_sum2 = DEMOD_STATE->dcd_sum1; - DEMOD_STATE->dcd_sum1 = DEMOD_STATE->dcd_sum0; - DEMOD_STATE->dcd_sum0 = 2; /* slight bias */ - DEMOD_STATE->dcd_time = 120; - } - if (DEMOD_STATE->bit_pll >= 0x10000) { - DEMOD_STATE->bit_pll &= 0xffff; - DEMOD_STATE->shreg >>= 1; - DEMOD_STATE->shreg |= (!(DEMOD_STATE->last_rxbit ^ - DEMOD_STATE->last_sample)) << 16; - DEMOD_STATE->last_rxbit = DEMOD_STATE->last_sample; - diag_trigger(sm); - if (DEMOD_STATE->shreg & 1) { - hdlcdrv_putbits(&sm->hdrv, DEMOD_STATE->shreg >> 1); - DEMOD_STATE->shreg = 0x10000; - } - } - diag_add(sm, (((int)*buf)-0x80) << 8, sum); - } - ENV_RESTORE; -} - -/* --------------------------------------------------------------------- */ - -static void demod_init_1200(struct sm_state *sm) -{ - DEMOD_STATE->dcd_time = 120; - DEMOD_STATE->dcd_sum0 = 2; -} - -/* --------------------------------------------------------------------- */ - -static const struct modem_tx_info afsk1200_tx = { - NEXT_TX_INFO, "afsk1200", sizeof(struct mod_state_afsk12), 9600, 1200, 8, - modulator_1200, NULL -}; -#undef NEXT_TX_INFO -#define NEXT_TX_INFO (&afsk1200_tx) - -static const struct modem_rx_info afsk1200_rx = { - NEXT_RX_INFO, "afsk1200", sizeof(struct demod_state_afsk12), 9600, 1200, 8, 8, - demodulator_1200, demod_init_1200 -}; -#undef NEXT_RX_INFO -#define NEXT_RX_INFO (&afsk1200_rx) - -/* --------------------------------------------------------------------- */ - -#undef DEMOD_STATE -#undef MOD_STATE diff -u --recursive --new-file v2.1.26/linux/drivers/net/sm_fsk9600.h linux/drivers/net/sm_fsk9600.h --- v2.1.26/linux/drivers/net/sm_fsk9600.h Fri Dec 20 03:16:51 1996 +++ linux/drivers/net/sm_fsk9600.h Wed Dec 31 16:00:00 1969 @@ -1,552 +0,0 @@ -/*****************************************************************************/ - -/* - * sm_fsk9600.h -- soundcard radio modem driver, - * 9600 baud G3RUH compatible FSK modem - * - * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Please note that the GPL allows you to use the driver, NOT the radio. - * In order to use the radio, you need a license from the communications - * authority of your country. - * - */ - -/* --------------------------------------------------------------------- */ - -struct demod_state_fsk96 { - unsigned int shreg; - unsigned long descram; - unsigned int bit_pll; - unsigned char last_sample; - unsigned int dcd_shreg; - int dcd_sum0, dcd_sum1, dcd_sum2; - unsigned int dcd_time; -}; - -struct mod_state_fsk96 { - unsigned int shreg; - unsigned long scram; - unsigned char tx_bit; -}; - -#define DEMOD_STATE ((struct demod_state_fsk96 *)(&sm->d)) -#define MOD_STATE ((struct mod_state_fsk96 *)(&sm->m)) - -/* --------------------------------------------------------------------- */ - -#define DESCRAM_TAP1 0x20000 -#define DESCRAM_TAP2 0x01000 -#define DESCRAM_TAP3 0x00001 - -#define DESCRAM_TAPSH1 17 -#define DESCRAM_TAPSH2 12 -#define DESCRAM_TAPSH3 0 - -#define SCRAM_TAP1 0x20000 /* X^17 */ -#define SCRAM_TAPN 0x00021 /* X^0+X^5 */ - -/* --------------------------------------------------------------------- */ - -static unsigned char tx_filter_9k6_4[] = { - 65, 66, 63, 63, 76, 76, 73, 73, - 54, 54, 51, 51, 64, 65, 61, 62, - 214, 214, 211, 211, 224, 225, 221, 222, - 202, 202, 199, 200, 213, 213, 210, 210, - 38, 38, 35, 35, 48, 49, 45, 46, - 26, 27, 23, 24, 37, 37, 34, 34, - 186, 187, 183, 184, 197, 197, 194, 194, - 175, 175, 172, 172, 185, 185, 182, 182, - 73, 74, 70, 71, 84, 84, 81, 81, - 62, 62, 59, 59, 72, 72, 69, 69, - 221, 222, 218, 219, 232, 232, 229, 229, - 210, 210, 207, 207, 220, 221, 217, 218, - 46, 46, 43, 43, 56, 56, 53, 53, - 34, 34, 31, 31, 44, 45, 41, 42, - 194, 194, 191, 191, 204, 205, 201, 202, - 182, 183, 179, 180, 193, 193, 190, 190, - 65, 65, 62, 62, 75, 76, 72, 73, - 53, 54, 50, 51, 64, 64, 61, 61, - 213, 214, 210, 211, 224, 224, 221, 221, - 202, 202, 199, 199, 212, 212, 209, 209, - 37, 38, 34, 35, 48, 48, 45, 45, - 26, 26, 23, 23, 36, 37, 33, 34, - 186, 186, 183, 183, 196, 196, 193, 193, - 174, 174, 171, 171, 184, 185, 181, 182, - 73, 73, 70, 70, 83, 83, 80, 80, - 61, 61, 58, 58, 71, 72, 68, 69, - 221, 221, 218, 218, 231, 232, 228, 229, - 209, 210, 206, 207, 220, 220, 217, 217, - 45, 45, 42, 42, 55, 56, 53, 53, - 33, 34, 30, 31, 44, 44, 41, 41, - 193, 194, 190, 191, 204, 204, 201, 201, - 182, 182, 179, 179, 192, 192, 189, 190, - 65, 66, 62, 63, 67, 68, 64, 64, - 103, 104, 100, 101, 105, 106, 101, 102, - 168, 169, 164, 165, 169, 170, 166, 167, - 205, 206, 202, 203, 207, 208, 204, 205, - 49, 50, 46, 46, 51, 51, 47, 48, - 87, 88, 83, 84, 88, 89, 85, 86, - 151, 152, 148, 149, 153, 154, 149, 150, - 189, 190, 186, 187, 191, 192, 187, 188, - 66, 67, 63, 64, 68, 69, 64, 65, - 104, 105, 100, 101, 105, 106, 102, 103, - 168, 169, 165, 166, 170, 171, 167, 167, - 206, 207, 203, 204, 208, 209, 204, 205, - 50, 51, 46, 47, 51, 52, 48, 49, - 87, 88, 84, 85, 89, 90, 85, 86, - 152, 153, 149, 149, 154, 154, 150, 151, - 190, 191, 186, 187, 191, 192, 188, 189, - 66, 67, 63, 64, 68, 69, 64, 65, - 104, 105, 101, 101, 106, 106, 102, 103, - 169, 170, 165, 166, 170, 171, 167, 168, - 206, 207, 203, 204, 208, 209, 204, 205, - 50, 51, 46, 47, 51, 52, 48, 49, - 88, 88, 84, 85, 89, 90, 86, 87, - 152, 153, 149, 150, 154, 155, 150, 151, - 190, 191, 186, 187, 191, 192, 188, 189, - 67, 68, 63, 64, 68, 69, 65, 66, - 105, 106, 101, 102, 106, 107, 103, 104, - 169, 170, 166, 167, 171, 172, 167, 168, - 207, 208, 204, 204, 209, 209, 205, 206, - 50, 51, 47, 48, 52, 53, 49, 50, - 88, 89, 85, 86, 90, 91, 86, 87, - 153, 154, 149, 150, 154, 155, 151, 152, - 191, 191, 187, 188, 192, 193, 189, 190, - 65, 66, 66, 67, 49, 50, 50, 50, - 168, 169, 168, 169, 151, 152, 152, 153, - 103, 104, 104, 105, 87, 88, 87, 88, - 205, 206, 206, 207, 189, 190, 190, 191, - 67, 68, 68, 68, 51, 51, 51, 52, - 169, 170, 170, 171, 153, 154, 154, 154, - 105, 106, 105, 106, 88, 89, 89, 90, - 207, 208, 208, 209, 191, 191, 191, 192, - 62, 63, 63, 63, 46, 46, 46, 47, - 164, 165, 165, 166, 148, 149, 149, 149, - 100, 101, 100, 101, 83, 84, 84, 85, - 202, 203, 203, 204, 186, 186, 186, 187, - 64, 64, 64, 65, 47, 48, 48, 49, - 166, 167, 167, 167, 149, 150, 150, 151, - 101, 102, 102, 103, 85, 86, 85, 86, - 204, 204, 204, 205, 187, 188, 188, 189, - 66, 67, 67, 68, 50, 51, 51, 51, - 169, 170, 169, 170, 152, 153, 153, 154, - 104, 105, 105, 106, 88, 88, 88, 89, - 206, 207, 207, 208, 190, 191, 191, 191, - 68, 69, 69, 69, 51, 52, 52, 53, - 170, 171, 171, 172, 154, 155, 154, 155, - 106, 106, 106, 107, 89, 90, 90, 91, - 208, 209, 209, 209, 192, 192, 192, 193, - 63, 64, 64, 64, 46, 47, 47, 48, - 165, 166, 166, 167, 149, 150, 149, 150, - 101, 101, 101, 102, 84, 85, 85, 86, - 203, 204, 204, 204, 187, 187, 187, 188, - 64, 65, 65, 66, 48, 49, 49, 50, - 167, 168, 167, 168, 150, 151, 151, 152, - 102, 103, 103, 104, 86, 87, 86, 87, - 205, 205, 205, 206, 188, 189, 189, 190, - 65, 65, 73, 73, 38, 37, 46, 45, - 214, 213, 221, 221, 186, 186, 194, 193, - 54, 53, 62, 61, 26, 26, 34, 33, - 202, 202, 210, 209, 175, 174, 182, 182, - 76, 75, 84, 83, 48, 48, 56, 55, - 224, 224, 232, 231, 197, 196, 204, 204, - 64, 64, 72, 71, 37, 36, 44, 44, - 213, 212, 220, 220, 185, 184, 193, 192, - 63, 62, 70, 70, 35, 34, 43, 42, - 211, 210, 218, 218, 183, 183, 191, 190, - 51, 50, 59, 58, 23, 23, 31, 30, - 199, 199, 207, 206, 172, 171, 179, 179, - 73, 72, 81, 80, 45, 45, 53, 53, - 221, 221, 229, 228, 194, 193, 201, 201, - 61, 61, 69, 68, 34, 33, 41, 41, - 210, 209, 217, 217, 182, 181, 190, 189, - 66, 65, 74, 73, 38, 38, 46, 45, - 214, 214, 222, 221, 187, 186, 194, 194, - 54, 54, 62, 61, 27, 26, 34, 34, - 202, 202, 210, 210, 175, 174, 183, 182, - 76, 76, 84, 83, 49, 48, 56, 56, - 225, 224, 232, 232, 197, 196, 205, 204, - 65, 64, 72, 72, 37, 37, 45, 44, - 213, 212, 221, 220, 185, 185, 193, 192, - 63, 62, 71, 70, 35, 35, 43, 42, - 211, 211, 219, 218, 184, 183, 191, 191, - 51, 51, 59, 58, 24, 23, 31, 31, - 200, 199, 207, 207, 172, 171, 180, 179, - 73, 73, 81, 80, 46, 45, 53, 53, - 222, 221, 229, 229, 194, 193, 202, 201, - 62, 61, 69, 69, 34, 34, 42, 41, - 210, 209, 218, 217, 182, 182, 190, 190 -}; - -static unsigned char tx_filter_9k6_5[] = { - 78, 78, 75, 76, 85, 85, 82, 83, - 71, 72, 69, 69, 78, 78, 76, 76, - 193, 193, 190, 191, 199, 200, 197, 198, - 186, 187, 184, 184, 193, 193, 190, 191, - 58, 59, 56, 57, 65, 66, 63, 63, - 52, 52, 49, 50, 58, 59, 56, 57, - 173, 174, 171, 171, 180, 180, 177, 178, - 166, 167, 164, 165, 173, 174, 171, 171, - 85, 86, 83, 83, 92, 92, 89, 90, - 79, 79, 76, 77, 85, 86, 83, 83, - 200, 200, 198, 198, 207, 207, 204, 205, - 193, 194, 191, 191, 200, 201, 198, 198, - 66, 66, 63, 64, 72, 73, 70, 70, - 59, 60, 57, 57, 66, 66, 63, 64, - 180, 181, 178, 179, 187, 188, 185, 185, - 174, 174, 171, 172, 180, 181, 178, 179, - 76, 77, 74, 75, 83, 84, 81, 81, - 70, 70, 67, 68, 76, 77, 74, 75, - 191, 192, 189, 189, 198, 198, 195, 196, - 185, 185, 182, 183, 191, 192, 189, 189, - 57, 57, 54, 55, 64, 64, 61, 62, - 50, 51, 48, 48, 57, 57, 55, 55, - 172, 172, 169, 170, 178, 179, 176, 177, - 165, 166, 163, 163, 172, 172, 169, 170, - 84, 84, 81, 82, 90, 91, 88, 89, - 77, 78, 75, 75, 84, 84, 81, 82, - 198, 199, 196, 197, 205, 206, 203, 203, - 192, 192, 189, 190, 198, 199, 196, 197, - 64, 65, 62, 62, 71, 71, 68, 69, - 57, 58, 55, 56, 64, 65, 62, 62, - 179, 179, 177, 177, 186, 186, 183, 184, - 172, 173, 170, 170, 179, 180, 177, 177, - 78, 79, 76, 77, 79, 79, 77, 77, - 99, 100, 97, 98, 100, 100, 98, 98, - 171, 172, 169, 170, 172, 173, 170, 171, - 192, 193, 190, 191, 193, 194, 191, 192, - 59, 60, 57, 58, 60, 61, 58, 59, - 81, 81, 79, 79, 81, 82, 79, 80, - 153, 153, 151, 151, 153, 154, 151, 152, - 174, 175, 172, 173, 175, 175, 173, 173, - 82, 83, 80, 81, 83, 83, 81, 81, - 103, 104, 101, 102, 104, 105, 102, 103, - 175, 176, 173, 174, 176, 177, 174, 175, - 197, 197, 195, 195, 197, 198, 195, 196, - 64, 64, 62, 62, 64, 65, 62, 63, - 85, 85, 83, 83, 85, 86, 83, 84, - 157, 158, 155, 156, 158, 158, 156, 156, - 178, 179, 176, 177, 179, 179, 177, 177, - 78, 78, 76, 76, 78, 79, 76, 77, - 99, 99, 97, 97, 99, 100, 97, 98, - 171, 172, 169, 170, 172, 172, 170, 170, - 192, 193, 190, 191, 193, 193, 191, 191, - 59, 60, 57, 58, 60, 60, 58, 58, - 80, 81, 78, 79, 81, 82, 79, 80, - 152, 153, 150, 151, 153, 154, 151, 152, - 174, 174, 172, 172, 174, 175, 172, 173, - 82, 82, 80, 80, 82, 83, 80, 81, - 103, 104, 101, 102, 104, 104, 102, 102, - 175, 176, 173, 174, 176, 176, 174, 174, - 196, 197, 194, 195, 197, 198, 195, 196, - 63, 64, 61, 62, 64, 65, 62, 63, - 84, 85, 82, 83, 85, 86, 83, 84, - 157, 157, 155, 155, 157, 158, 155, 156, - 178, 178, 176, 176, 178, 179, 176, 177, - 78, 78, 78, 79, 69, 69, 69, 69, - 136, 136, 136, 137, 127, 127, 127, 128, - 136, 136, 136, 137, 127, 127, 127, 128, - 194, 195, 195, 195, 185, 185, 185, 186, - 69, 69, 69, 69, 59, 60, 60, 60, - 127, 127, 127, 128, 117, 118, 118, 118, - 127, 127, 127, 128, 117, 118, 118, 118, - 185, 185, 185, 186, 175, 176, 176, 176, - 78, 79, 79, 79, 69, 69, 69, 70, - 136, 137, 137, 137, 127, 128, 127, 128, - 136, 137, 137, 137, 127, 128, 127, 128, - 195, 195, 195, 195, 185, 186, 186, 186, - 69, 69, 69, 70, 60, 60, 60, 60, - 127, 128, 127, 128, 118, 118, 118, 119, - 127, 128, 127, 128, 118, 118, 118, 119, - 185, 186, 186, 186, 176, 176, 176, 177, - 78, 79, 79, 79, 69, 69, 69, 70, - 136, 137, 137, 137, 127, 128, 128, 128, - 136, 137, 137, 137, 127, 128, 128, 128, - 195, 195, 195, 195, 185, 186, 186, 186, - 69, 69, 69, 70, 60, 60, 60, 60, - 127, 128, 128, 128, 118, 118, 118, 119, - 127, 128, 128, 128, 118, 118, 118, 119, - 185, 186, 186, 186, 176, 176, 176, 177, - 79, 79, 79, 80, 69, 70, 70, 70, - 137, 137, 137, 138, 128, 128, 128, 128, - 137, 137, 137, 138, 128, 128, 128, 128, - 195, 195, 195, 196, 186, 186, 186, 186, - 69, 70, 70, 70, 60, 60, 60, 61, - 128, 128, 128, 128, 118, 119, 119, 119, - 128, 128, 128, 128, 118, 119, 119, 119, - 186, 186, 186, 186, 176, 177, 177, 177, - 78, 78, 82, 82, 59, 59, 64, 63, - 171, 171, 175, 175, 153, 152, 157, 157, - 99, 99, 103, 103, 81, 80, 85, 84, - 192, 192, 197, 196, 174, 174, 178, 178, - 79, 78, 83, 82, 60, 60, 64, 64, - 172, 172, 176, 176, 153, 153, 158, 157, - 100, 99, 104, 104, 81, 81, 85, 85, - 193, 193, 197, 197, 175, 174, 179, 178, - 76, 76, 80, 80, 57, 57, 62, 61, - 169, 169, 173, 173, 151, 150, 155, 155, - 97, 97, 101, 101, 79, 78, 83, 82, - 190, 190, 195, 194, 172, 172, 176, 176, - 77, 76, 81, 80, 58, 58, 62, 62, - 170, 170, 174, 174, 151, 151, 156, 155, - 98, 97, 102, 102, 79, 79, 83, 83, - 191, 191, 195, 195, 173, 172, 177, 176, - 79, 78, 83, 82, 60, 60, 64, 64, - 172, 172, 176, 176, 153, 153, 158, 157, - 100, 99, 104, 104, 81, 81, 85, 85, - 193, 193, 197, 197, 175, 174, 179, 178, - 79, 79, 83, 83, 61, 60, 65, 65, - 173, 172, 177, 176, 154, 154, 158, 158, - 100, 100, 105, 104, 82, 82, 86, 86, - 194, 193, 198, 198, 175, 175, 179, 179, - 77, 76, 81, 80, 58, 58, 62, 62, - 170, 170, 174, 174, 151, 151, 156, 155, - 98, 97, 102, 102, 79, 79, 83, 83, - 191, 191, 195, 195, 173, 172, 177, 176, - 77, 77, 81, 81, 59, 58, 63, 63, - 171, 170, 175, 174, 152, 152, 156, 156, - 98, 98, 103, 102, 80, 80, 84, 84, - 192, 191, 196, 196, 173, 173, 177, 177, - 78, 76, 85, 84, 58, 57, 66, 64, - 193, 191, 200, 198, 173, 172, 180, 179, - 71, 70, 79, 77, 52, 50, 59, 57, - 186, 185, 193, 192, 166, 165, 174, 172, - 85, 83, 92, 90, 65, 64, 72, 71, - 199, 198, 207, 205, 180, 178, 187, 186, - 78, 76, 85, 84, 58, 57, 66, 64, - 193, 191, 200, 198, 173, 172, 180, 179, - 75, 74, 83, 81, 56, 54, 63, 62, - 190, 189, 198, 196, 171, 169, 178, 177, - 69, 67, 76, 75, 49, 48, 57, 55, - 184, 182, 191, 189, 164, 163, 171, 170, - 82, 81, 89, 88, 63, 61, 70, 68, - 197, 195, 204, 203, 177, 176, 185, 183, - 76, 74, 83, 81, 56, 55, 63, 62, - 190, 189, 198, 196, 171, 169, 178, 177, - 78, 77, 86, 84, 59, 57, 66, 65, - 193, 192, 200, 199, 174, 172, 181, 179, - 72, 70, 79, 78, 52, 51, 60, 58, - 187, 185, 194, 192, 167, 166, 174, 173, - 85, 84, 92, 91, 66, 64, 73, 71, - 200, 198, 207, 206, 180, 179, 188, 186, - 78, 77, 86, 84, 59, 57, 66, 65, - 193, 192, 201, 199, 174, 172, 181, 180, - 76, 75, 83, 82, 57, 55, 64, 62, - 191, 189, 198, 197, 171, 170, 179, 177, - 69, 68, 77, 75, 50, 48, 57, 56, - 184, 183, 191, 190, 165, 163, 172, 170, - 83, 81, 90, 89, 63, 62, 70, 69, - 198, 196, 205, 203, 178, 177, 185, 184, - 76, 75, 83, 82, 57, 55, 64, 62, - 191, 189, 198, 197, 171, 170, 179, 177 -}; - -/* --------------------------------------------------------------------- */ - -static void modulator_9600_4(struct sm_state *sm, unsigned char *buf, int buflen) -{ - int j; - const unsigned char *cp; - - for (; buflen >= 4; buflen -= 4) { - if (MOD_STATE->shreg <= 1) - MOD_STATE->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - MOD_STATE->scram = ((MOD_STATE->scram << 1) | - (MOD_STATE->scram & 1)); - MOD_STATE->scram ^= (!(MOD_STATE->shreg & 1)); - MOD_STATE->shreg >>= 1; - if (MOD_STATE->scram & (SCRAM_TAP1 << 1)) - MOD_STATE->scram ^= (SCRAM_TAPN << 1); - MOD_STATE->tx_bit = (MOD_STATE->tx_bit << 1) | - (!!(MOD_STATE->scram & (SCRAM_TAP1 << 2))); - cp = tx_filter_9k6_4 + (MOD_STATE->tx_bit & 0xff); - for (j = 0; j < 4; j++) { - *buf++ = *cp; - cp += 0x100; - } - } -} - -/* --------------------------------------------------------------------- */ - -static void demodulator_9600_4(struct sm_state *sm, unsigned char *buf, int buflen) -{ - static const int pll_corr[2] = { -0x1000, 0x1000 }; - unsigned char curbit; - unsigned int descx; - - for (; buflen > 0; buflen--, buf++) { - DEMOD_STATE->dcd_shreg <<= 1; - DEMOD_STATE->bit_pll += 0x4000; - curbit = (*buf >= 0x80); - if (DEMOD_STATE->last_sample ^ curbit) { - DEMOD_STATE->dcd_shreg |= 1; - DEMOD_STATE->bit_pll += pll_corr - [DEMOD_STATE->bit_pll < 0xa000]; - DEMOD_STATE->dcd_sum0 += 8 * - hweight8(DEMOD_STATE->dcd_shreg & 0x0c) - - !!(DEMOD_STATE->dcd_shreg & 0x10); - } - DEMOD_STATE->last_sample = curbit; - hdlcdrv_channelbit(&sm->hdrv, DEMOD_STATE->last_sample); - if ((--DEMOD_STATE->dcd_time) <= 0) { - hdlcdrv_setdcd(&sm->hdrv, (DEMOD_STATE->dcd_sum0 + - DEMOD_STATE->dcd_sum1 + - DEMOD_STATE->dcd_sum2) < 0); - DEMOD_STATE->dcd_sum2 = DEMOD_STATE->dcd_sum1; - DEMOD_STATE->dcd_sum1 = DEMOD_STATE->dcd_sum0; - DEMOD_STATE->dcd_sum0 = 2; /* slight bias */ - DEMOD_STATE->dcd_time = 240; - } - if (DEMOD_STATE->bit_pll >= 0x10000) { - DEMOD_STATE->bit_pll &= 0xffff; - DEMOD_STATE->descram = (DEMOD_STATE->descram << 1) | curbit; - descx = DEMOD_STATE->descram ^ (DEMOD_STATE->descram >> 1); - descx ^= ((descx >> DESCRAM_TAPSH1) ^ - (descx >> DESCRAM_TAPSH2)); - DEMOD_STATE->shreg >>= 1; - DEMOD_STATE->shreg |= (!(descx & 1)) << 16; - if (DEMOD_STATE->shreg & 1) { - hdlcdrv_putbits(&sm->hdrv, DEMOD_STATE->shreg >> 1); - DEMOD_STATE->shreg = 0x10000; - } - diag_trigger(sm); - } - diag_add_one(sm, ((short)(*buf - 0x80)) << 8); - } -} - -/* --------------------------------------------------------------------- */ - -static void modulator_9600_5(struct sm_state *sm, unsigned char *buf, int buflen) -{ - int j; - const unsigned char *cp; - - for (; buflen >= 5; buflen -= 5) { - if (MOD_STATE->shreg <= 1) - MOD_STATE->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - MOD_STATE->scram = ((MOD_STATE->scram << 1) | - (MOD_STATE->scram & 1)); - MOD_STATE->scram ^= (!(MOD_STATE->shreg & 1)); - MOD_STATE->shreg >>= 1; - if (MOD_STATE->scram & (SCRAM_TAP1 << 1)) - MOD_STATE->scram ^= (SCRAM_TAPN << 1); - MOD_STATE->tx_bit = (MOD_STATE->tx_bit << 1) | - (!!(MOD_STATE->scram & (SCRAM_TAP1 << 2))); - cp = tx_filter_9k6_5 + (MOD_STATE->tx_bit & 0xff); - for (j = 0; j < 5; j++) { - *buf++ = *cp; - cp += 0x100; - } - } -} - -/* --------------------------------------------------------------------- */ - -static void demodulator_9600_5(struct sm_state *sm, unsigned char *buf, int buflen) -{ - static const int pll_corr[2] = { -0x1000, 0x1000 }; - unsigned char curbit; - unsigned int descx; - - for (; buflen > 0; buflen--, buf++) { - DEMOD_STATE->dcd_shreg <<= 1; - DEMOD_STATE->bit_pll += 0x3333; - curbit = (*buf >= 0x80); - if (DEMOD_STATE->last_sample ^ curbit) { - DEMOD_STATE->dcd_shreg |= 1; - DEMOD_STATE->bit_pll += pll_corr - [DEMOD_STATE->bit_pll < 0x9999]; - DEMOD_STATE->dcd_sum0 += 16 * - hweight8(DEMOD_STATE->dcd_shreg & 0x0c) - - hweight8(DEMOD_STATE->dcd_shreg & 0x70); - } - DEMOD_STATE->last_sample = curbit; - hdlcdrv_channelbit(&sm->hdrv, DEMOD_STATE->last_sample); - if ((--DEMOD_STATE->dcd_time) <= 0) { - hdlcdrv_setdcd(&sm->hdrv, (DEMOD_STATE->dcd_sum0 + - DEMOD_STATE->dcd_sum1 + - DEMOD_STATE->dcd_sum2) < 0); - DEMOD_STATE->dcd_sum2 = DEMOD_STATE->dcd_sum1; - DEMOD_STATE->dcd_sum1 = DEMOD_STATE->dcd_sum0; - DEMOD_STATE->dcd_sum0 = 2; /* slight bias */ - DEMOD_STATE->dcd_time = 240; - } - if (DEMOD_STATE->bit_pll >= 0x10000) { - DEMOD_STATE->bit_pll &= 0xffff; - DEMOD_STATE->descram = (DEMOD_STATE->descram << 1) | curbit; - descx = DEMOD_STATE->descram ^ (DEMOD_STATE->descram >> 1); - descx ^= ((descx >> DESCRAM_TAPSH1) ^ - (descx >> DESCRAM_TAPSH2)); - DEMOD_STATE->shreg >>= 1; - DEMOD_STATE->shreg |= (!(descx & 1)) << 16; - if (DEMOD_STATE->shreg & 1) { - hdlcdrv_putbits(&sm->hdrv, DEMOD_STATE->shreg >> 1); - DEMOD_STATE->shreg = 0x10000; - } - diag_trigger(sm); - } - diag_add_one(sm, ((short)(*buf - 0x80)) << 8); - } -} - -/* --------------------------------------------------------------------- */ - -static void demod_init_9600(struct sm_state *sm) -{ - DEMOD_STATE->dcd_time = 240; - DEMOD_STATE->dcd_sum0 = 2; -} - -/* --------------------------------------------------------------------- */ - -static const struct modem_tx_info fsk9600_4_tx = { - NEXT_TX_INFO, "fsk9600", sizeof(struct mod_state_fsk96), 38400, 9600, 4, - modulator_9600_4, NULL -}; -#undef NEXT_TX_INFO -#define NEXT_TX_INFO (&fsk9600_4_tx) - -static const struct modem_rx_info fsk9600_4_rx = { - NEXT_RX_INFO, "fsk9600", sizeof(struct demod_state_fsk96), 38400, 9600, 4, 4, - demodulator_9600_4, demod_init_9600 -}; -#undef NEXT_RX_INFO -#define NEXT_RX_INFO (&fsk9600_4_rx) - -/* --------------------------------------------------------------------- */ - -static const struct modem_tx_info fsk9600_5_tx = { - NEXT_TX_INFO, "fsk9600", sizeof(struct mod_state_fsk96), 48000, 9600, 5, - modulator_9600_5, NULL -}; -#undef NEXT_TX_INFO -#define NEXT_TX_INFO (&fsk9600_5_tx) - -static const struct modem_rx_info fsk9600_5_rx = { - NEXT_RX_INFO, "fsk9600", sizeof(struct demod_state_fsk96), 48000, 9600, 5, 5, - demodulator_9600_5, demod_init_9600 -}; -#undef NEXT_RX_INFO -#define NEXT_RX_INFO (&fsk9600_5_rx) - -/* --------------------------------------------------------------------- */ - -#undef DEMOD_STATE -#undef MOD_STATE diff -u --recursive --new-file v2.1.26/linux/drivers/net/sm_sbc.h linux/drivers/net/sm_sbc.h --- v2.1.26/linux/drivers/net/sm_sbc.h Fri Dec 20 03:16:51 1996 +++ linux/drivers/net/sm_sbc.h Wed Dec 31 16:00:00 1969 @@ -1,482 +0,0 @@ -/*****************************************************************************/ - -/* - * sm_sbc.h -- soundcard radio modem driver soundblaster hardware driver - * - * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Please note that the GPL allows you to use the driver, NOT the radio. - * In order to use the radio, you need a license from the communications - * authority of your country. - * - */ - -/* --------------------------------------------------------------------- */ - -struct sc_state_sbc { - unsigned char revhi, revlo; - unsigned char fmt[2]; - unsigned int dmabuflen; - unsigned char *dmabuf; - unsigned char dmabufidx; - unsigned char ptt; -}; - -#define SCSTATE ((struct sc_state_sbc *)(&sm->hw)) - -/* --------------------------------------------------------------------- */ -/* - * the sbc converter's registers - */ -#define DSP_RESET(iobase) (iobase+0x6) -#define DSP_READ_DATA(iobase) (iobase+0xa) -#define DSP_WRITE_DATA(iobase) (iobase+0xc) -#define DSP_WRITE_STATUS(iobase) (iobase+0xc) -#define DSP_DATA_AVAIL(iobase) (iobase+0xe) -#define DSP_MIXER_ADDR(iobase) (iobase+0x4) -#define DSP_MIXER_DATA(iobase) (iobase+0x5) -#define SBC_EXTENT 16 - -/* --------------------------------------------------------------------- */ -/* - * SBC commands - */ -#define SBC_OUTPUT 0x14 -#define SBC_INPUT 0x24 -#define SBC_BLOCKSIZE 0x48 -#define SBC_HI_OUTPUT 0x91 -#define SBC_HI_INPUT 0x99 -#define SBC_LO_OUTPUT_AUTOINIT 0x1c -#define SBC_LO_INPUT_AUTOINIT 0x2c -#define SBC_HI_OUTPUT_AUTOINIT 0x90 -#define SBC_HI_INPUT_AUTOINIT 0x98 -#define SBC_IMMED_INT 0xf2 -#define SBC_GET_REVISION 0xe1 -#define ESS_GET_REVISION 0xe7 -#define SBC_SPEAKER_ON 0xd1 -#define SBC_SPEAKER_OFF 0xd3 -#define SBC_DMA_ON 0xd0 -#define SBC_DMA_OFF 0xd4 -#define SBC_SAMPLE_RATE 0x40 -#define SBC_MONO_8BIT 0xa0 -#define SBC_MONO_16BIT 0xa4 -#define SBC_STEREO_8BIT 0xa8 -#define SBC_STEREO_16BIT 0xac - -#define SBC4_OUT8_AI 0xc6 -#define SBC4_IN8_AI 0xce -#define SBC4_MODE_UNS_MONO 0x00 - -/* --------------------------------------------------------------------- */ - -static int inline reset_dsp(struct device *dev) -{ - int i; - - outb(1, DSP_RESET(dev->base_addr)); - for (i = 0; i < 0x100; i++) - SLOW_DOWN_IO; - outb(0, DSP_RESET(dev->base_addr)); - for (i = 0; i < 0xffff; i++) - if (inb(DSP_DATA_AVAIL(dev->base_addr)) & 0x80) - if (inb(DSP_READ_DATA(dev->base_addr)) == 0xaa) - return 1; - return 0; -} - -/* --------------------------------------------------------------------- */ - -static void inline write_dsp(struct device *dev, unsigned char data) -{ - int i; - - for (i = 0; i < 0xffff; i++) - if (!(inb(DSP_WRITE_STATUS(dev->base_addr)) & 0x80)) { - outb(data, DSP_WRITE_DATA(dev->base_addr)); - return; - } -} - -/* --------------------------------------------------------------------- */ - -static int inline read_dsp(struct device *dev, unsigned char *data) -{ - int i; - - if (!data) - return 0; - for (i = 0; i < 0xffff; i++) - if (inb(DSP_DATA_AVAIL(dev->base_addr)) & 0x80) { - *data = inb(DSP_READ_DATA(dev->base_addr)); - return 1; - } - return 0; -} - -/* --------------------------------------------------------------------- */ - -static void inline sbc_int_ack(struct device *dev) -{ - inb(DSP_DATA_AVAIL(dev->base_addr)); -} - -/* --------------------------------------------------------------------- */ - -static void setup_dma_dsp(struct device *dev, struct sm_state *sm, int send) -{ - unsigned long flags; - static const unsigned char sbcmode[2][2] = { - { SBC_LO_INPUT_AUTOINIT, SBC_LO_OUTPUT_AUTOINIT }, - { SBC_HI_INPUT_AUTOINIT, SBC_HI_OUTPUT_AUTOINIT } - }; - static const unsigned char sbc4mode[2] = { SBC4_IN8_AI, SBC4_OUT8_AI }; - static const unsigned char dmamode[2] = { - DMA_MODE_READ | DMA_MODE_AUTOINIT, DMA_MODE_WRITE | DMA_MODE_AUTOINIT - }; - static const unsigned char sbcskr[2] = { SBC_SPEAKER_OFF, SBC_SPEAKER_ON }; - unsigned long dmabufaddr = virt_to_bus(SCSTATE->dmabuf); - - send = !!send; - if (!reset_dsp(dev)) { - printk(KERN_ERR "%s: sbc: cannot reset sb dsp\n", sm_drvname); - return; - } - if ((dmabufaddr & 0xffff) + SCSTATE->dmabuflen > 0x10000) - panic("sm: DMA buffer violates DMA boundary!"); - save_flags(flags); - cli(); - sbc_int_ack(dev); - write_dsp(dev, SBC_SAMPLE_RATE); /* set sampling rate */ - write_dsp(dev, SCSTATE->fmt[send]); - write_dsp(dev, sbcskr[send]); - disable_dma(dev->dma); - clear_dma_ff(dev->dma); - set_dma_mode(dev->dma, dmamode[send]); - set_dma_addr(dev->dma, dmabufaddr); - set_dma_count(dev->dma, SCSTATE->dmabuflen); - enable_dma(dev->dma); - sbc_int_ack(dev); - if (SCSTATE->revhi >= 4) { - write_dsp(dev, sbc4mode[send]); - write_dsp(dev, SBC4_MODE_UNS_MONO); - write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); - write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); - } else { - write_dsp(dev, SBC_BLOCKSIZE); - write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); - write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); - write_dsp(dev, sbcmode[SCSTATE->fmt[send] >= 180][send]); - /* hispeed mode if sample rate > 13kHz */ - } - restore_flags(flags); -} - -/* --------------------------------------------------------------------- */ - -static void sbc_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct device *dev = (struct device *)dev_id; - struct sm_state *sm = (struct sm_state *)dev->priv; - unsigned char new_ptt; - unsigned char *buf; - - if (!dev || !sm || sm->hdrv.magic != HDLCDRV_MAGIC) - return; - new_ptt = hdlcdrv_ptt(&sm->hdrv); - sbc_int_ack(dev); - buf = SCSTATE->dmabuf; - if (SCSTATE->dmabufidx) - buf += SCSTATE->dmabuflen/2; - SCSTATE->dmabufidx = !SCSTATE->dmabufidx; - sm_int_freq(sm); - sti(); - if (new_ptt && !SCSTATE->ptt) { - /* starting to transmit */ - disable_dma(dev->dma); - SCSTATE->dmabufidx = 0; - time_exec(sm->debug_vals.demod_cyc, - sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2)); - time_exec(sm->debug_vals.mod_cyc, - sm->mode_tx->modulator(sm, SCSTATE->dmabuf, - SCSTATE->dmabuflen/2)); - setup_dma_dsp(dev, sm, 1); - time_exec(sm->debug_vals.mod_cyc, - sm->mode_tx->modulator(sm, SCSTATE->dmabuf + - SCSTATE->dmabuflen/2, - SCSTATE->dmabuflen/2)); - } else if (SCSTATE->ptt == 1 && !new_ptt) { - /* stopping transmission */ - disable_dma(dev->dma); - SCSTATE->dmabufidx = 0; - setup_dma_dsp(dev, sm, 0); - SCSTATE->ptt = 0; - } else if (SCSTATE->ptt) { - SCSTATE->ptt--; - time_exec(sm->debug_vals.mod_cyc, - sm->mode_tx->modulator(sm, buf, SCSTATE->dmabuflen/2)); - } else { - time_exec(sm->debug_vals.demod_cyc, - sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2)); - hdlcdrv_arbitrate(dev, &sm->hdrv); - } - if (new_ptt) - SCSTATE->ptt = 2; - output_status(sm); - hdlcdrv_transmitter(dev, &sm->hdrv); - hdlcdrv_receiver(dev, &sm->hdrv); -} - -/* --------------------------------------------------------------------- */ - -static int sbc_open(struct device *dev, struct sm_state *sm) -{ - if (sizeof(sm->m) < sizeof(struct sc_state_sbc)) { - printk(KERN_ERR "sm sbc: sbc state too big: %d > %d\n", - sizeof(struct sc_state_sbc), sizeof(sm->m)); - return -ENODEV; - } - if (!dev || !sm) - return -ENXIO; - if (dev->base_addr <= 0 || dev->base_addr > 0x1000-SBC_EXTENT || - dev->irq < 2 || dev->irq > 15 || dev->dma > 3) - return -ENXIO; - if (check_region(dev->base_addr, SBC_EXTENT)) - return -EACCES; - /* - * check if a card is available - */ - if (!reset_dsp(dev)) - return -ENODEV; - write_dsp(dev, SBC_GET_REVISION); - if (!read_dsp(dev, &SCSTATE->revhi) || - !read_dsp(dev, &SCSTATE->revlo)) - return -ENODEV; - if (SCSTATE->revhi < 2) { - printk(KERN_ERR "%s: your card is an antiquity, at least DSP " - "rev 2.00 required\n", sm_drvname); - return -ENODEV; - } - if (SCSTATE->revhi < 3 && - (SCSTATE->fmt[0] >= 180 || SCSTATE->fmt[1] >= 180)) { - printk(KERN_ERR "%s: sbc io 0x%lx: DSP rev %d.%02d too " - "old, at least 3.00 required\n", sm_drvname, - dev->base_addr, SCSTATE->revhi, SCSTATE->revlo); - return -ENODEV; - } - /* - * initialize some variables - */ - if (!(SCSTATE->dmabuf = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA))) - return -ENOMEM; - SCSTATE->dmabufidx = SCSTATE->ptt = 0; - - memset(&sm->m, 0, sizeof(sm->m)); - memset(&sm->d, 0, sizeof(sm->d)); - if (sm->mode_tx->init) - sm->mode_tx->init(sm); - if (sm->mode_rx->init) - sm->mode_rx->init(sm); - - if (request_dma(dev->dma, sm->hwdrv->hw_name)) { - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); - return -EBUSY; - } - if (request_irq(dev->irq, sbc_interrupt, SA_INTERRUPT, - sm->hwdrv->hw_name, dev)) { - free_dma(dev->dma); - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); - return -EBUSY; - } - request_region(dev->base_addr, SBC_EXTENT, sm->hwdrv->hw_name); - setup_dma_dsp(dev, sm, 0); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int sbc_close(struct device *dev, struct sm_state *sm) -{ - if (!dev || !sm) - return -EINVAL; - /* - * disable interrupts - */ - disable_dma(dev->dma); - reset_dsp(dev); - free_irq(dev->irq, dev); - free_dma(dev->dma); - release_region(dev->base_addr, SBC_EXTENT); - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int sbc_sethw(struct device *dev, struct sm_state *sm, char *mode) -{ - char *cp = strchr(mode, '.'); - const struct modem_tx_info *mtp = modem_tx_base; - const struct modem_rx_info *mrp; - int dv; - - if (!strcmp(mode, "off")) { - sm->mode_tx = NULL; - sm->mode_rx = NULL; - return 0; - } - if (cp) - *cp++ = '\0'; - else - cp = mode; - for (; mtp; mtp = mtp->next) { - if (mtp->loc_storage > sizeof(sm->m)) { - printk(KERN_ERR "%s: insufficient storage for modulator %s (%d)\n", - sm_drvname, mtp->name, mtp->loc_storage); - continue; - } - if (!mtp->name || strcmp(mtp->name, mode)) - continue; - if (mtp->srate < 5000 || mtp->srate > 44100) - continue; - for (mrp = modem_rx_base; mrp; mrp = mrp->next) { - if (mrp->loc_storage > sizeof(sm->d)) { - printk(KERN_ERR "%s: insufficient storage for demodulator %s (%d)\n", - sm_drvname, mrp->name, mrp->loc_storage); - continue; - } - if (mrp->name && !strcmp(mrp->name, cp) && - mrp->srate >= 5000 && mrp->srate <= 44100) { - sm->mode_tx = mtp; - sm->mode_rx = mrp; - SCSTATE->fmt[0] = 256-((1000000L+mtp->srate/2)/ - mrp->srate); - SCSTATE->fmt[1] = 256-((1000000L+mtp->srate/2)/ - mtp->srate); - dv = lcm(sm->mode_tx->dmabuflenmodulo, - sm->mode_rx->dmabuflenmodulo); - SCSTATE->dmabuflen = sm->mode_rx->srate/100+dv-1; - SCSTATE->dmabuflen /= dv; - SCSTATE->dmabuflen *= 2*dv; /* make sure DMA buf is even */ - printk(KERN_DEBUG "sm sbc: modtx %u modrx %u srt %u buflen %u srate %u div %u srate %u div %u\n", - sm->mode_tx->dmabuflenmodulo, sm->mode_rx->dmabuflenmodulo, - sm->mode_rx->srate, SCSTATE->dmabuflen, mrp->srate, SCSTATE->fmt[0], mtp->srate, SCSTATE->fmt[1]); - return 0; - } - } - } - return -EINVAL; -} - -/* --------------------------------------------------------------------- */ - -static int sbc_ioctl(struct device *dev, struct sm_state *sm, struct ifreq *ifr, - struct hdlcdrv_ioctl *hi, int cmd) -{ - struct sm_ioctl bi; - unsigned long flags; - int i; - - if (cmd != SIOCDEVPRIVATE) - return -ENOIOCTLCMD; - - if (hi->cmd == HDLCDRVCTL_MODEMPARMASK) - return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ | - HDLCDRV_PARMASK_DMA | HDLCDRV_PARMASK_SERIOBASE | - HDLCDRV_PARMASK_PARIOBASE | HDLCDRV_PARMASK_MIDIIOBASE; - - if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) - return -EFAULT; - - switch (bi.cmd) { - default: - return -ENOIOCTLCMD; - - case SMCTL_GETMIXER: - i = 0; - bi.data.mix.sample_rate = sm->mode_rx->srate; - bi.data.mix.bit_rate = sm->hdrv.par.bitrate; - switch (SCSTATE->revhi) { - case 2: - bi.data.mix.mixer_type = SM_MIXER_CT1335; - break; - case 3: - bi.data.mix.mixer_type = SM_MIXER_CT1345; - break; - case 4: - bi.data.mix.mixer_type = SM_MIXER_CT1745; - break; - } - if (bi.data.mix.mixer_type != SM_MIXER_INVALID && - bi.data.mix.reg < 0x80) { - save_flags(flags); - cli(); - outb(bi.data.mix.reg, DSP_MIXER_ADDR(dev->base_addr)); - bi.data.mix.data = inb(DSP_MIXER_DATA(dev->base_addr)); - restore_flags(flags); - i = 1; - } - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return i; - - case SMCTL_SETMIXER: - if (!suser()) - return -EACCES; - switch (SCSTATE->revhi) { - case 2: - if (bi.data.mix.mixer_type != SM_MIXER_CT1335) - return -EINVAL; - break; - case 3: - if (bi.data.mix.mixer_type != SM_MIXER_CT1345) - return -EINVAL; - break; - case 4: - if (bi.data.mix.mixer_type != SM_MIXER_CT1745) - return -EINVAL; - break; - default: - return -ENODEV; - } - if (bi.data.mix.reg >= 0x80) - return -EACCES; - save_flags(flags); - cli(); - outb(bi.data.mix.reg, DSP_MIXER_ADDR(dev->base_addr)); - outb(bi.data.mix.data, DSP_MIXER_DATA(dev->base_addr)); - restore_flags(flags); - return 0; - - } - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return 0; - -} - -/* --------------------------------------------------------------------- */ - -struct hardware_info hw_sbc = { - NEXT_HW_INFO, "sbc", sizeof(struct sc_state_sbc), - sbc_open, sbc_close, sbc_ioctl, sbc_sethw -}; -#undef NEXT_HW_INFO -#define NEXT_HW_INFO (&hw_sbc) - -/* --------------------------------------------------------------------- */ - -#undef SCSTATE diff -u --recursive --new-file v2.1.26/linux/drivers/net/sm_wss.h linux/drivers/net/sm_wss.h --- v2.1.26/linux/drivers/net/sm_wss.h Fri Dec 20 03:16:51 1996 +++ linux/drivers/net/sm_wss.h Wed Dec 31 16:00:00 1969 @@ -1,910 +0,0 @@ -/*****************************************************************************/ - -/* - * sm_wss.h -- soundcard radio modem driver, WSS (half duplex) driver - * - * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Please note that the GPL allows you to use the driver, NOT the radio. - * In order to use the radio, you need a license from the communications - * authority of your country. - * - */ - -/* --------------------------------------------------------------------- */ - -struct sc_state_wss { - unsigned char revwss, revid, revv, revcid; - unsigned char fmt[2]; - unsigned char crystal; - unsigned int dmabuflen; - unsigned char *dmabuf; - unsigned char dmabufidx; - unsigned char ptt; - /* Full Duplex extensions */ - unsigned char *dmabuf2; -}; - -#define SCSTATE ((struct sc_state_wss *)(&sm->hw)) - -/* --------------------------------------------------------------------- */ - -#define WSS_CONFIG(iobase) (iobase+0) -#define WSS_STATUS(iobase) (iobase+3) -#define WSS_CODEC_IA(iobase) (iobase+4) -#define WSS_CODEC_ID(iobase) (iobase+5) -#define WSS_CODEC_STATUS(iobase) (iobase+6) -#define WSS_CODEC_DATA(iobase) (iobase+7) - -#define WSS_EXTENT 8 - -/* --------------------------------------------------------------------- */ - -static void write_codec(struct device *dev, unsigned char idx, - unsigned char data) -{ - int timeout = 900000; - - /* wait until codec ready */ - while (timeout > 0 && inb(WSS_CODEC_IA(dev->base_addr)) & 0x80) - timeout--; - outb(idx, WSS_CODEC_IA(dev->base_addr)); - outb(data, WSS_CODEC_ID(dev->base_addr)); -} - - -/* --------------------------------------------------------------------- */ - -static unsigned char read_codec(struct device *dev, unsigned char idx) -{ - int timeout = 900000; - - /* wait until codec ready */ - while (timeout > 0 && inb(WSS_CODEC_IA(dev->base_addr)) & 0x80) - timeout--; - outb(idx & 0x1f, WSS_CODEC_IA(dev->base_addr)); - return inb(WSS_CODEC_ID(dev->base_addr)); -} - -/* --------------------------------------------------------------------- */ - -extern void inline wss_ack_int(struct device *dev) -{ - outb(0, WSS_CODEC_STATUS(dev->base_addr)); -} - -/* --------------------------------------------------------------------- */ - -static int wss_srate_tab[16] = { - 8000, 5510, 16000, 11025, 27420, 18900, 32000, 22050, - -1, 37800, -1, 44100, 48000, 33075, 9600, 6620 -}; - -static int wss_srate_index(int srate) -{ - int i; - - for (i = 0; i < (sizeof(wss_srate_tab)/sizeof(wss_srate_tab[0])); i++) - if (srate == wss_srate_tab[i] && wss_srate_tab[i] > 0) - return i; - return -1; -} - -/* --------------------------------------------------------------------- */ - -static int wss_set_codec_fmt(struct device *dev, struct sm_state *sm, - unsigned char fmt, char fdx, char fullcalib) -{ - unsigned long time; - unsigned long flags; - - save_flags(flags); - cli(); - /* Clock and data format register */ - write_codec(dev, 0x48, fmt); - if (SCSTATE->crystal) { - write_codec(dev, 0x5c, fmt & 0xf0); - /* MCE and interface config reg */ - write_codec(dev, 0x49, (fdx ? 0 : 0x4) | (fullcalib ? 0x18 : 0)); - } else - /* MCE and interface config reg */ - write_codec(dev, 0x49, fdx ? 0x8 : 0xc); - outb(0xb, WSS_CODEC_IA(dev->base_addr)); /* leave MCE */ - /* - * wait for ACI start - */ - time = 1000; - while (!(read_codec(dev, 0x0b) & 0x20)) - if (!(--time)) { - printk(KERN_WARNING "%s: ad1848 auto calibration timed out (1)\n", - sm_drvname); - restore_flags(flags); - return -1; - } - /* - * wait for ACI end - */ - sti(); - time = jiffies + HZ/4; - while ((read_codec(dev, 0x0b) & 0x20) && ((signed)(jiffies - time) < 0)); - restore_flags(flags); - if ((signed)(jiffies - time) >= 0) { - printk(KERN_WARNING "%s: ad1848 auto calibration timed out (2)\n", - sm_drvname); - return -1; - } - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int wss_init_codec(struct device *dev, struct sm_state *sm, char fdx, - unsigned char src_l, unsigned char src_r, - int igain_l, int igain_r, - int ogain_l, int ogain_r) -{ - unsigned char tmp, reg0, reg1, reg6, reg7; - static const signed char irqtab[16] = - { -1, -1, 0x10, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20, -1, -1, - -1, -1 }; - static const signed char dmatab[4] = { 1, 2, -1, 3 }; - - tmp = inb(WSS_STATUS(dev->base_addr)); - if ((tmp & 0x3f) != 0x04 && (tmp & 0x3f) != 0x00 && - (tmp & 0x3f) != 0x0f) { - printk(KERN_WARNING "sm: WSS card id register not found, " - "address 0x%lx, ID register 0x%02x\n", - dev->base_addr, (int)tmp); - /* return -1; */ - SCSTATE->revwss = 0; - } else { - if ((tmp & 0x80) && ((dev->dma == 0) || - ((dev->irq >= 8) && (dev->irq != 9)))) { - printk(KERN_ERR "%s: WSS: DMA0 and/or IRQ8..IRQ15 " - "(except IRQ9) cannot be used on an 8bit " - "card\n", sm_drvname); - return -1; - } - if (dev->irq > 15 || irqtab[dev->irq] == -1) { - printk(KERN_ERR "%s: WSS: invalid interrupt %d\n", - sm_drvname, (int)dev->irq); - return -1; - } - if (dev->dma > 3 || dmatab[dev->dma] == -1) { - printk(KERN_ERR "%s: WSS: invalid dma channel %d\n", - sm_drvname, (int)dev->dma); - return -1; - } - tmp = irqtab[dev->irq] | dmatab[dev->dma]; - /* irq probe */ - outb((tmp & 0x38) | 0x40, WSS_CONFIG(dev->base_addr)); - if (!(inb(WSS_STATUS(dev->base_addr)) & 0x40)) { - outb(0, WSS_CONFIG(dev->base_addr)); - printk(KERN_ERR "%s: WSS: IRQ%d is not free!\n", - sm_drvname, dev->irq); - } - outb(tmp, WSS_CONFIG(dev->base_addr)); - SCSTATE->revwss = inb(WSS_STATUS(dev->base_addr)) & 0x3f; - } - /* - * initialize the codec - */ - if (igain_l < 0) - igain_l = 0; - if (igain_r < 0) - igain_r = 0; - if (ogain_l > 0) - ogain_l = 0; - if (ogain_r > 0) - ogain_r = 0; - reg0 = (src_l << 6) & 0xc0; - reg1 = (src_r << 6) & 0xc0; - if (reg0 == 0x80 && igain_l >= 20) { - reg0 |= 0x20; - igain_l -= 20; - } - if (reg1 == 0x80 && igain_r >= 20) { - reg1 |= 0x20; - igain_r -= 20; - } - if (igain_l > 23) - igain_l = 23; - if (igain_r > 23) - igain_r = 23; - reg0 |= igain_l * 2 / 3; - reg1 |= igain_r * 2 / 3; - reg6 = (ogain_l < -95) ? 0x80 : (ogain_l * (-2) / 3); - reg7 = (ogain_r < -95) ? 0x80 : (ogain_r * (-2) / 3); - write_codec(dev, 9, 0); - write_codec(dev, 0, 0x45); - if (read_codec(dev, 0) != 0x45) - goto codec_err; - write_codec(dev, 0, 0xaa); - if (read_codec(dev, 0) != 0xaa) - goto codec_err; - write_codec(dev, 12, 0x40); /* enable MODE2 */ - write_codec(dev, 16, 0); - write_codec(dev, 0, 0x45); - SCSTATE->crystal = (read_codec(dev, 16) != 0x45); - write_codec(dev, 0, 0xaa); - SCSTATE->crystal &= (read_codec(dev, 16) != 0xaa); - if (SCSTATE->crystal) { - SCSTATE->revcid = read_codec(dev, 0x19); - SCSTATE->revv = (SCSTATE->revcid >> 5) & 7; - SCSTATE->revcid &= 7; - write_codec(dev, 0x10, 0x80); /* maximum output level */ - write_codec(dev, 0x11, 0x02); /* xtal enable and no HPF */ - write_codec(dev, 0x12, 0x80); /* left line input control */ - write_codec(dev, 0x13, 0x80); /* right line input control */ - write_codec(dev, 0x16, 0); /* disable alternative freq sel */ - write_codec(dev, 0x1a, 0xe0); /* mono IO disable */ - write_codec(dev, 0x1b, 0x00); /* left out no att */ - write_codec(dev, 0x1d, 0x00); /* right out no att */ - } - - if (wss_set_codec_fmt(dev, sm, SCSTATE->fmt[0], fdx, 1)) - goto codec_err; - - write_codec(dev, 0, reg0); /* left input control */ - write_codec(dev, 1, reg1); /* right input control */ - write_codec(dev, 2, 0x80); /* left aux#1 input control */ - write_codec(dev, 3, 0x80); /* right aux#1 input control */ - write_codec(dev, 4, 0x80); /* left aux#2 input control */ - write_codec(dev, 5, 0x80); /* right aux#2 input control */ - write_codec(dev, 6, reg6); /* left dac control */ - write_codec(dev, 7, reg7); /* right dac control */ - write_codec(dev, 0xa, 0x2); /* pin control register */ - write_codec(dev, 0xd, 0x0); /* digital mix control */ - SCSTATE->revid = read_codec(dev, 0xc) & 0xf; - /* - * print revisions - */ - if (SCSTATE->crystal) - printk(KERN_INFO "%s: Crystal CODEC ID %d, Chip revision %d, " - " Chip ID %d\n", sm_drvname, (int)SCSTATE->revid, - (int)SCSTATE->revv, (int)SCSTATE->revcid); - else - printk(KERN_INFO "%s: WSS revision %d, CODEC revision %d\n", - sm_drvname, (int)SCSTATE->revwss, - (int)SCSTATE->revid); - return 0; - codec_err: - outb(0, WSS_CONFIG(dev->base_addr)); - printk(KERN_ERR "%s: no WSS soundcard found at address 0x%lx\n", - sm_drvname, dev->base_addr); - return -1; -} - -/* --------------------------------------------------------------------- */ - -static void setup_dma_wss(struct device *dev, struct sm_state *sm, int send) -{ - unsigned long flags; - static const unsigned char codecmode[2] = { 0x0e, 0x0d }; - static const unsigned char dmamode[2] = { - DMA_MODE_READ | DMA_MODE_AUTOINIT, - DMA_MODE_WRITE | DMA_MODE_AUTOINIT - }; - unsigned char oldcodecmode; - long abrt; - unsigned long dmabufaddr = virt_to_bus(SCSTATE->dmabuf); - - if ((dmabufaddr & 0xffffu) + SCSTATE->dmabuflen > 0x10000) - panic("%s: DMA buffer violates DMA boundary!", sm_drvname); - send = !!send; - save_flags(flags); - cli(); - /* - * perform the final DMA sequence to disable the codec request - */ - oldcodecmode = read_codec(dev, 9); - write_codec(dev, 9, 0xc); /* disable codec */ - wss_ack_int(dev); - if (read_codec(dev, 11) & 0x10) { - disable_dma(dev->dma); - clear_dma_ff(dev->dma); - set_dma_mode(dev->dma, dmamode[oldcodecmode & 1]); - set_dma_addr(dev->dma, dmabufaddr); - set_dma_count(dev->dma, SCSTATE->dmabuflen); - enable_dma(dev->dma); - abrt = 0; - while ((read_codec(dev, 11) & 0x10) || ((++abrt) >= 0x10000)); - } - disable_dma(dev->dma); - if (read_codec(dev, 0x8) != SCSTATE->fmt[send]) - wss_set_codec_fmt(dev, sm, SCSTATE->fmt[send], 0, 0); - clear_dma_ff(dev->dma); - set_dma_mode(dev->dma, dmamode[send]); - set_dma_addr(dev->dma, dmabufaddr); - set_dma_count(dev->dma, SCSTATE->dmabuflen); - enable_dma(dev->dma); - write_codec(dev, 15, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); - write_codec(dev, 14, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); - if (SCSTATE->crystal) { - write_codec(dev, 31, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); - write_codec(dev, 30, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); - } - write_codec(dev, 9, codecmode[send]); - restore_flags(flags); - printk("sm: wss: %cx fmt: 0x%02x ifc: 0x%02x\n", "rt"[send], - read_codec(dev, 0x8), read_codec(dev, 0x9)); -} - -/* --------------------------------------------------------------------- */ - -static void wss_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct device *dev = (struct device *)dev_id; - struct sm_state *sm = (struct sm_state *)dev->priv; - unsigned char new_ptt; - unsigned char *buf; - int dmares; - - if (!dev || !sm || !sm->mode_rx || !sm->mode_tx || - sm->hdrv.magic != HDLCDRV_MAGIC) - return; - new_ptt = hdlcdrv_ptt(&sm->hdrv); - cli(); - wss_ack_int(dev); - disable_dma(dev->dma); - clear_dma_ff(dev->dma); - dmares = get_dma_residue(dev->dma); - if (dmares <= 0) - dmares = SCSTATE->dmabuflen; - buf = SCSTATE->dmabuf; - if (dmares > SCSTATE->dmabuflen/2) { - buf += SCSTATE->dmabuflen/2; - dmares -= SCSTATE->dmabuflen/2; - } -#ifdef SM_DEBUG - if (!sm->debug_vals.dma_residue || - dmares < sm->debug_vals.dma_residue) - sm->debug_vals.dma_residue = dmares; -#endif /* SM_DEBUG */ - dmares--; - write_codec(dev, 15, dmares & 0xff); - write_codec(dev, 14, dmares >> 8); - if (SCSTATE->crystal) { - write_codec(dev, 31, dmares & 0xff); - write_codec(dev, 30, dmares >> 8); - } - enable_dma(dev->dma); - sm_int_freq(sm); - sti(); - if (new_ptt && !SCSTATE->ptt) { - /* starting to transmit */ - disable_dma(dev->dma); - sti(); - SCSTATE->dmabufidx = 0; - time_exec(sm->debug_vals.demod_cyc, - sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2)); - time_exec(sm->debug_vals.mod_cyc, - sm->mode_tx->modulator(sm, SCSTATE->dmabuf, - SCSTATE->dmabuflen/2)); - setup_dma_wss(dev, sm, 1); - time_exec(sm->debug_vals.mod_cyc, - sm->mode_tx->modulator(sm, SCSTATE->dmabuf + - SCSTATE->dmabuflen/2, - SCSTATE->dmabuflen/2)); - } else if (SCSTATE->ptt == 1 && !new_ptt) { - /* stopping transmission */ - disable_dma(dev->dma); - sti(); - SCSTATE->dmabufidx = 0; - setup_dma_wss(dev, sm, 0); - SCSTATE->ptt = 0; - } else if (SCSTATE->ptt) { - SCSTATE->ptt--; - time_exec(sm->debug_vals.mod_cyc, - sm->mode_tx->modulator(sm, buf, SCSTATE->dmabuflen/2)); - } else { - time_exec(sm->debug_vals.demod_cyc, - sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2)); - hdlcdrv_arbitrate(dev, &sm->hdrv); - } - if (new_ptt) - SCSTATE->ptt = 2; - output_status(sm); - hdlcdrv_transmitter(dev, &sm->hdrv); - hdlcdrv_receiver(dev, &sm->hdrv); -} - -/* --------------------------------------------------------------------- */ - -static int wss_open(struct device *dev, struct sm_state *sm) -{ - if (sizeof(sm->m) < sizeof(struct sc_state_wss)) { - printk(KERN_ERR "sm wss: wss state too big: %d > %d\n", - sizeof(struct sc_state_wss), sizeof(sm->m)); - return -ENODEV; - } - if (!dev || !sm || !sm->mode_rx || !sm->mode_tx) - return -ENXIO; - if (dev->base_addr <= 0 || dev->base_addr > 0x1000-WSS_EXTENT || - dev->irq < 2 || dev->irq > 15 || dev->dma > 3) - return -ENXIO; - if (check_region(dev->base_addr, WSS_EXTENT)) - return -EACCES; - /* - * check if a card is available - */ - if (wss_init_codec(dev, sm, 0, 1, 1, 0, 0, -45, -45)) - return -ENODEV; - /* - * initialize some variables - */ - if (!(SCSTATE->dmabuf = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA))) - return -ENOMEM; - SCSTATE->dmabufidx = SCSTATE->ptt = 0; - - memset(&sm->m, 0, sizeof(sm->m)); - memset(&sm->d, 0, sizeof(sm->d)); - if (sm->mode_tx->init) - sm->mode_tx->init(sm); - if (sm->mode_rx->init) - sm->mode_rx->init(sm); - - if (request_dma(dev->dma, sm->hwdrv->hw_name)) { - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); - return -EBUSY; - } - if (request_irq(dev->irq, wss_interrupt, SA_INTERRUPT, - sm->hwdrv->hw_name, dev)) { - free_dma(dev->dma); - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); - return -EBUSY; - } - request_region(dev->base_addr, WSS_EXTENT, sm->hwdrv->hw_name); - setup_dma_wss(dev, sm, 0); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int wss_close(struct device *dev, struct sm_state *sm) -{ - if (!dev || !sm) - return -EINVAL; - /* - * disable interrupts - */ - disable_dma(dev->dma); - write_codec(dev, 9, 0xc); /* disable codec */ - free_irq(dev->irq, dev); - free_dma(dev->dma); - release_region(dev->base_addr, WSS_EXTENT); - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int wss_sethw(struct device *dev, struct sm_state *sm, char *mode) -{ - char *cp = strchr(mode, '.'); - const struct modem_tx_info *mtp = modem_tx_base; - const struct modem_rx_info *mrp; - int i, j, dv; - - if (!strcmp(mode, "off")) { - sm->mode_tx = NULL; - sm->mode_rx = NULL; - return 0; - } - if (cp) - *cp++ = '\0'; - else - cp = mode; - for (; mtp; mtp = mtp->next) { - if (mtp->loc_storage > sizeof(sm->m)) { - printk(KERN_ERR "%s: insufficient storage for modulator %s (%d)\n", - sm_drvname, mtp->name, mtp->loc_storage); - continue; - } - if (!mtp->name || strcmp(mtp->name, mode)) - continue; - if ((i = wss_srate_index(mtp->srate)) < 0) - continue; - for (mrp = modem_rx_base; mrp; mrp = mrp->next) { - if (mrp->loc_storage > sizeof(sm->d)) { - printk(KERN_ERR "%s: insufficient storage for demodulator %s (%d)\n", - sm_drvname, mrp->name, mrp->loc_storage); - continue; - } - if (mrp->name && !strcmp(mrp->name, cp) && - ((j = wss_srate_index(mrp->srate)) >= 0)) { - sm->mode_tx = mtp; - sm->mode_rx = mrp; - SCSTATE->fmt[0] = j; - SCSTATE->fmt[1] = i; - dv = lcm(sm->mode_tx->dmabuflenmodulo, - sm->mode_rx->dmabuflenmodulo); - SCSTATE->dmabuflen = sm->mode_rx->srate/100+dv-1; - SCSTATE->dmabuflen /= dv; - SCSTATE->dmabuflen *= 2*dv; /* make sure DMA buf is even */ - printk(KERN_DEBUG "sm wss: modtx %u modrx %u srt %u buflen %u\n", - sm->mode_tx->dmabuflenmodulo, sm->mode_rx->dmabuflenmodulo, - sm->mode_rx->srate, SCSTATE->dmabuflen); - return 0; - } - } - } - return -EINVAL; -} - -/* --------------------------------------------------------------------- */ - -static int wss_ioctl(struct device *dev, struct sm_state *sm, struct ifreq *ifr, - struct hdlcdrv_ioctl *hi, int cmd) -{ - struct sm_ioctl bi; - int i; - - if (cmd != SIOCDEVPRIVATE) - return -ENOIOCTLCMD; - - if (hi->cmd == HDLCDRVCTL_MODEMPARMASK) - return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ | - HDLCDRV_PARMASK_DMA | HDLCDRV_PARMASK_SERIOBASE | - HDLCDRV_PARMASK_PARIOBASE | HDLCDRV_PARMASK_MIDIIOBASE; - - if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) - return -EFAULT; - - switch (bi.cmd) { - default: - return -ENOIOCTLCMD; - - case SMCTL_GETMIXER: - i = 0; - bi.data.mix.sample_rate = sm->mode_rx->srate; - bi.data.mix.bit_rate = sm->hdrv.par.bitrate; - bi.data.mix.mixer_type = SCSTATE->crystal ? - SM_MIXER_CRYSTAL : SM_MIXER_AD1848; - if (((SCSTATE->crystal ? 0x2c0c20fflu: 0x20fflu) - >> bi.data.mix.reg) & 1) { - bi.data.mix.data = read_codec(dev, bi.data.mix.reg); - i = 1; - } - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return i; - - case SMCTL_SETMIXER: - if (!suser()) - return -EACCES; - if ((bi.data.mix.mixer_type != SM_MIXER_CRYSTAL || - !SCSTATE->crystal) && - (bi.data.mix.mixer_type != SM_MIXER_AD1848 || - bi.data.mix.reg >= 0x10)) - return -EINVAL; - if (!((0x2c0c20fflu >> bi.data.mix.reg) & 1)) - return -EACCES; - write_codec(dev, bi.data.mix.reg, bi.data.mix.data); - return 0; - - } - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return 0; - -} - -/* --------------------------------------------------------------------- */ - -struct hardware_info hw_wss = { - NEXT_HW_INFO, "wss", sizeof(struct sc_state_wss), - wss_open, wss_close, wss_ioctl, wss_sethw -}; -#undef NEXT_HW_INFO -#define NEXT_HW_INFO (&hw_wss) - -/* --------------------------------------------------------------------- */ - -static void setup_fdx_dma_wss(struct device *dev, struct sm_state *sm) -{ - unsigned long flags; - unsigned char oldcodecmode, codecdma; - long abrt; - unsigned long dmabufaddr1 = virt_to_bus(SCSTATE->dmabuf); - unsigned long dmabufaddr2 = virt_to_bus(SCSTATE->dmabuf2); - - if (((dmabufaddr1 & 0xffffu) + SCSTATE->dmabuflen > 0x10000) || - ((dmabufaddr2 & 0xffffu) + SCSTATE->dmabuflen > 0x10000)) - panic("%s: DMA buffer violates DMA boundary!", sm_drvname); - save_flags(flags); - cli(); - /* - * perform the final DMA sequence to disable the codec request - */ - oldcodecmode = read_codec(dev, 9); - write_codec(dev, 9, 0); /* disable codec DMA */ - wss_ack_int(dev); - if ((codecdma = read_codec(dev, 11)) & 0x10) { - disable_dma(dev->dma); - disable_dma(sm->hdrv.ptt_out.dma2); - clear_dma_ff(dev->dma); - set_dma_mode(dev->dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT); - set_dma_addr(dev->dma, dmabufaddr1); - set_dma_count(dev->dma, SCSTATE->dmabuflen); - clear_dma_ff(sm->hdrv.ptt_out.dma2); - set_dma_mode(sm->hdrv.ptt_out.dma2, DMA_MODE_READ | DMA_MODE_AUTOINIT); - set_dma_addr(sm->hdrv.ptt_out.dma2, dmabufaddr2); - set_dma_count(sm->hdrv.ptt_out.dma2, SCSTATE->dmabuflen); - enable_dma(dev->dma); - enable_dma(sm->hdrv.ptt_out.dma2); - abrt = 0; - while (((codecdma = read_codec(dev, 11)) & 0x10) || - ((++abrt) >= 0x10000)); - } - disable_dma(dev->dma); - disable_dma(sm->hdrv.ptt_out.dma2); - clear_dma_ff(dev->dma); - set_dma_mode(dev->dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT); - set_dma_addr(dev->dma, dmabufaddr1); - set_dma_count(dev->dma, SCSTATE->dmabuflen); - clear_dma_ff(sm->hdrv.ptt_out.dma2); - set_dma_mode(sm->hdrv.ptt_out.dma2, DMA_MODE_READ | DMA_MODE_AUTOINIT); - set_dma_addr(sm->hdrv.ptt_out.dma2, dmabufaddr2); - set_dma_count(sm->hdrv.ptt_out.dma2, SCSTATE->dmabuflen); - enable_dma(dev->dma); - enable_dma(sm->hdrv.ptt_out.dma2); - write_codec(dev, 15, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); - write_codec(dev, 14, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); - if (SCSTATE->crystal) { - write_codec(dev, 31, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); - write_codec(dev, 30, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); - } - write_codec(dev, 9, 3); - restore_flags(flags); -} - -/* --------------------------------------------------------------------- */ - -static void wssfdx_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct device *dev = (struct device *)dev_id; - struct sm_state *sm = (struct sm_state *)dev->priv; - unsigned char *buf1; - unsigned char *buf2; - unsigned long flags; - int dmares1, dmares2; - - if (!dev || !sm || !sm->mode_rx || !sm->mode_tx || - sm->hdrv.magic != HDLCDRV_MAGIC) - return; - save_flags(flags); - cli(); - if (SCSTATE->crystal && (!(read_codec(dev, 0x18) & 0x20))) { - /* only regard Crystal Playback interrupts! */ - wss_ack_int(dev); - return; - } - wss_ack_int(dev); - disable_dma(dev->dma); - disable_dma(sm->hdrv.ptt_out.dma2); - clear_dma_ff(dev->dma); - dmares1 = get_dma_residue(dev->dma); - clear_dma_ff(sm->hdrv.ptt_out.dma2); - dmares2 = get_dma_residue(sm->hdrv.ptt_out.dma2); - if (dmares1 <= 0) - dmares1 = SCSTATE->dmabuflen; - buf1 = SCSTATE->dmabuf; - if (dmares1 > SCSTATE->dmabuflen/2) { - buf1 += SCSTATE->dmabuflen/2; - dmares1 -= SCSTATE->dmabuflen/2; - } - if (dmares2 <= 0) - dmares2 = SCSTATE->dmabuflen; - buf2 = SCSTATE->dmabuf2; - if (dmares2 > SCSTATE->dmabuflen/2) { - buf2 += SCSTATE->dmabuflen/2; - dmares2 -= SCSTATE->dmabuflen/2; - } -#ifdef SM_DEBUG - if (!sm->debug_vals.dma_residue || - dmares1 < sm->debug_vals.dma_residue) - sm->debug_vals.dma_residue = dmares1; -#endif /* SM_DEBUG */ - dmares1--; - dmares2--; - write_codec(dev, 15, dmares1 & 0xff); - write_codec(dev, 14, dmares1 >> 8); - if (SCSTATE->crystal) { - write_codec(dev, 31, dmares2 & 0xff); - write_codec(dev, 30, dmares2 >> 8); - } - enable_dma(dev->dma); - enable_dma(sm->hdrv.ptt_out.dma2); - restore_flags(flags); - sm_int_freq(sm); - sti(); - if ((SCSTATE->ptt = hdlcdrv_ptt(&sm->hdrv))) - time_exec(sm->debug_vals.mod_cyc, - sm->mode_tx->modulator(sm, buf1, SCSTATE->dmabuflen/2)); - else - time_exec(sm->debug_vals.mod_cyc, - memset(buf1, 0x80, SCSTATE->dmabuflen/2)); - time_exec(sm->debug_vals.demod_cyc, - sm->mode_rx->demodulator(sm, buf2, SCSTATE->dmabuflen/2)); - hdlcdrv_arbitrate(dev, &sm->hdrv); - output_status(sm); - hdlcdrv_transmitter(dev, &sm->hdrv); - hdlcdrv_receiver(dev, &sm->hdrv); -} - -/* --------------------------------------------------------------------- */ - -static int wssfdx_open(struct device *dev, struct sm_state *sm) -{ - if (!dev || !sm || !sm->mode_rx || !sm->mode_tx) - return -ENXIO; - if (dev->base_addr <= 0 || dev->base_addr > 0x1000-WSS_EXTENT || - dev->irq < 2 || dev->irq > 15 || dev->dma > 3) - return -ENXIO; - if (check_region(dev->base_addr, WSS_EXTENT)) - return -EACCES; - /* - * check if a card is available - */ - if (wss_init_codec(dev, sm, 1, 1, 1, 0, 0, -45, -45)) - return -ENODEV; - /* - * initialize some variables - */ - if (!(SCSTATE->dmabuf = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA))) - return -ENOMEM; - if (!(SCSTATE->dmabuf2 = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA))) { - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); - return -ENOMEM; - } - SCSTATE->dmabufidx = SCSTATE->ptt = 0; - - memset(&sm->m, 0, sizeof(sm->m)); - memset(&sm->d, 0, sizeof(sm->d)); - if (sm->mode_tx->init) - sm->mode_tx->init(sm); - if (sm->mode_rx->init) - sm->mode_rx->init(sm); - - if (request_dma(dev->dma, sm->hwdrv->hw_name)) { - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); - kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen); - return -EBUSY; - } - if (request_dma(sm->hdrv.ptt_out.dma2, sm->hwdrv->hw_name)) { - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); - kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen); - free_dma(dev->dma); - return -EBUSY; - } - if (request_irq(dev->irq, wssfdx_interrupt, SA_INTERRUPT, - sm->hwdrv->hw_name, dev)) { - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); - kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen); - free_dma(dev->dma); - free_dma(sm->hdrv.ptt_out.dma2); - return -EBUSY; - } - request_region(dev->base_addr, WSS_EXTENT, sm->hwdrv->hw_name); - setup_fdx_dma_wss(dev, sm); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int wssfdx_close(struct device *dev, struct sm_state *sm) -{ - if (!dev || !sm) - return -EINVAL; - /* - * disable interrupts - */ - disable_dma(dev->dma); - write_codec(dev, 9, 0xc); /* disable codec */ - free_irq(dev->irq, dev); - free_dma(dev->dma); - free_dma(sm->hdrv.ptt_out.dma2); - release_region(dev->base_addr, WSS_EXTENT); - kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); - kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int wssfdx_sethw(struct device *dev, struct sm_state *sm, char *mode) -{ - char *cp = strchr(mode, '.'); - const struct modem_tx_info *mtp = modem_tx_base; - const struct modem_rx_info *mrp; - int i, dv; - - if (!strcmp(mode, "off")) { - sm->mode_tx = NULL; - sm->mode_rx = NULL; - return 0; - } - if (cp) - *cp++ = '\0'; - else - cp = mode; - for (; mtp; mtp = mtp->next) { - if (mtp->loc_storage > sizeof(sm->m)) { - printk(KERN_ERR "%s: insufficient storage for modulator %s (%d)\n", - sm_drvname, mtp->name, mtp->loc_storage); - continue; - } - if (!mtp->name || strcmp(mtp->name, mode)) - continue; - if ((i = wss_srate_index(mtp->srate)) < 0) - continue; - for (mrp = modem_rx_base; mrp; mrp = mrp->next) { - if (mrp->loc_storage > sizeof(sm->d)) { - printk(KERN_ERR "%s: insufficient storage for demodulator %s (%d)\n", - sm_drvname, mrp->name, mrp->loc_storage); - continue; - } - if (mrp->name && !strcmp(mrp->name, cp) && - mtp->srate == mrp->srate) { - sm->mode_tx = mtp; - sm->mode_rx = mrp; - SCSTATE->fmt[0] = SCSTATE->fmt[1] = i; - dv = lcm(sm->mode_tx->dmabuflenmodulo, - sm->mode_rx->dmabuflenmodulo); - SCSTATE->dmabuflen = sm->mode_rx->srate/100+dv-1; - SCSTATE->dmabuflen /= dv; - SCSTATE->dmabuflen *= 2*dv; /* make sure DMA buf is even */ - printk(KERN_DEBUG "sm wssfdx: modtx %u modrx %u srt %u buflen %u\n", - sm->mode_tx->dmabuflenmodulo, sm->mode_rx->dmabuflenmodulo, - sm->mode_rx->srate, SCSTATE->dmabuflen); - return 0; - } - } - } - return -EINVAL; -} - -/* --------------------------------------------------------------------- */ - -static int wssfdx_ioctl(struct device *dev, struct sm_state *sm, struct ifreq *ifr, - struct hdlcdrv_ioctl *hi, int cmd) -{ - if (cmd != SIOCDEVPRIVATE) - return -ENOIOCTLCMD; - - if (hi->cmd == HDLCDRVCTL_MODEMPARMASK) - return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ | - HDLCDRV_PARMASK_DMA | HDLCDRV_PARMASK_DMA2 | - HDLCDRV_PARMASK_SERIOBASE | HDLCDRV_PARMASK_PARIOBASE | - HDLCDRV_PARMASK_MIDIIOBASE; - - return wss_ioctl(dev, sm, ifr, hi, cmd); -} - -/* --------------------------------------------------------------------- */ - -struct hardware_info hw_wssfdx = { - NEXT_HW_INFO, "wssfdx", sizeof(struct sc_state_wss), - wssfdx_open, wssfdx_close, wssfdx_ioctl, wssfdx_sethw -}; -#undef NEXT_HW_INFO -#define NEXT_HW_INFO (&hw_wssfdx) - -/* --------------------------------------------------------------------- */ - -#undef SCSTATE diff -u --recursive --new-file v2.1.26/linux/drivers/net/soundmodem/Makefile linux/drivers/net/soundmodem/Makefile --- v2.1.26/linux/drivers/net/soundmodem/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/soundmodem/Makefile Fri Feb 21 14:58:35 1997 @@ -0,0 +1,50 @@ +# +# Makefile for the soundmodem device driver. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now inherited from the +# parent makes.. +# + +O_TARGET := soundmodem.o + +O_OBJS := sm.o +ifeq ($(CONFIG_SOUNDMODEM_SBC),y) +O_OBJS += sm_sbc.o +endif +ifeq ($(CONFIG_SOUNDMODEM_WSS),y) +O_OBJS += sm_wss.o +endif +ifeq ($(CONFIG_SOUNDMODEM_AFSK1200),y) +O_OBJS += sm_afsk1200.o +endif +ifeq ($(CONFIG_SOUNDMODEM_AFSK2666),y) +O_OBJS += sm_afsk2666.o +endif +ifeq ($(CONFIG_SOUNDMODEM_HAPN4800),y) +O_OBJS += sm_hapn4800.o +endif +ifeq ($(CONFIG_SOUNDMODEM_PSK4800),y) +O_OBJS += sm_psk4800.o +endif +ifeq ($(CONFIG_SOUNDMODEM_FSK9600),y) +O_OBJS += sm_fsk9600.o +endif + +M_OBJS := $(O_TARGET) + +gentbl: gentbl.c + $(HOSTCC) -Wall $< -o $@ -lm + +TBLHDR := sm_tbl_afsk1200.h sm_tbl_afsk2666.h sm_tbl_psk4800.h +TBLHDR += sm_tbl_hapn4800.h sm_tbl_fsk9600.h + +$(TBLHDR): gentbl + ./gentbl + +fastdep: $(TBLHDR) + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.26/linux/drivers/net/soundmodem/gentbl.c linux/drivers/net/soundmodem/gentbl.c --- v2.1.26/linux/drivers/net/soundmodem/gentbl.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/soundmodem/gentbl.c Fri Feb 21 14:58:35 1997 @@ -0,0 +1,629 @@ +/*****************************************************************************/ + +/* + * gentbl.c -- soundcard radio modem driver table generator. + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + */ + +#include +#include +#include + +/* -------------------------------------------------------------------- */ + +#define OFFSCOSTABBITS 6 +#define OFFSCOSTABSIZE (1<>%d)&0x%x]\n\n", + 16-OFFSCOSTABBITS, OFFSCOSTABSIZE-1); +} + +/* -------------------------------------------------------------------- */ + +#define AFSK12_SAMPLE_RATE 9600 +#define AFSK12_TX_FREQ_LO 1200 +#define AFSK12_TX_FREQ_HI 2200 +#define AFSK12_CORRLEN 8 + +static void gentbl_afsk1200(FILE *f) +{ + int i; + +#define ARGLO(x) 2.0*M_PI*(double)x*(double)AFSK12_TX_FREQ_LO/(double)AFSK12_SAMPLE_RATE +#define ARGHI(x) 2.0*M_PI*(double)x*(double)AFSK12_TX_FREQ_HI/(double)AFSK12_SAMPLE_RATE + + fprintf(f, "\n/*\n * afsk1200 specific tables\n */\n" + "#define AFSK12_SAMPLE_RATE %u\n" + "#define AFSK12_TX_FREQ_LO %u\n" + "#define AFSK12_TX_FREQ_HI %u\n" + "#define AFSK12_CORRLEN %u\n\n", + AFSK12_SAMPLE_RATE, AFSK12_TX_FREQ_LO, + AFSK12_TX_FREQ_HI, AFSK12_CORRLEN); + fprintf(f, "#if defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && " + "(defined(CONFIG_M586) || defined(CONFIG_M686))\n\n" + "static const float afsk12_tx_lo_i_f[] = {\n\t"); + for(i = 0; i < AFSK12_CORRLEN; i++) + fprintf(f, " %7f%c", cos(ARGLO(i)), + (i < AFSK12_CORRLEN-1) ? ',' : ' '); + fprintf(f, "\n};\n\nstatic const float afsk12_tx_lo_q_f[] = {\n\t"); + for(i = 0; i < AFSK12_CORRLEN; i++) + fprintf(f, " %7f%c", sin(ARGLO(i)), + (i < AFSK12_CORRLEN-1) ? ',' : ' '); + fprintf(f, "\n};\n\nstatic const float afsk12_tx_hi_i_f[] = {\n\t"); + for(i = 0; i < AFSK12_CORRLEN; i++) + fprintf(f, " %7f%c", cos(ARGHI(i)), + (i < AFSK12_CORRLEN-1) ? ',' : ' '); + fprintf(f, "\n};\n\nstatic const float afsk12_tx_hi_q_f[] = {\n\t"); + for(i = 0; i < AFSK12_CORRLEN; i++) + fprintf(f, " %7f%c", sin(ARGHI(i)), + (i < AFSK12_CORRLEN-1) ? ',' : ' '); + fprintf(f, "\n};\n\n#else /* CONFIG_SOUNDMODEM_AFSK1200_FP */\n\n" + "static const signed char afsk12_tx_lo_i[] = {\n\t"); + for(i = 0; i < AFSK12_CORRLEN; i++) + fprintf(f, " %4i%c", (int)(127.0*cos(ARGLO(i))), + (i < AFSK12_CORRLEN-1) ? ',' : ' '); + fprintf(f, "\n};\n\nstatic const signed char afsk12_tx_lo_q[] = {\n\t"); + for(i = 0; i < AFSK12_CORRLEN; i++) + fprintf(f, " %4i%c", (int)(127.0*sin(ARGLO(i))), + (i < AFSK12_CORRLEN-1) ? ',' : ' '); + fprintf(f, "\n};\n\nstatic const signed char afsk12_tx_hi_i[] = {\n\t"); + for(i = 0; i < AFSK12_CORRLEN; i++) + fprintf(f, " %4i%c", (int)(127.0*cos(ARGHI(i))), + (i < AFSK12_CORRLEN-1) ? ',' : ' '); + fprintf(f, "\n};\n\nstatic const signed char afsk12_tx_hi_q[] = {\n\t"); + for(i = 0; i < AFSK12_CORRLEN; i++) + fprintf(f, " %4i%c", (int)(127.0*sin(ARGHI(i))), + (i < AFSK12_CORRLEN-1) ? ',' : ' '); + fprintf(f, "\n};\n\n#endif /* CONFIG_SOUNDMODEM_AFSK1200_FP */\n\n"); +#undef ARGLO +#undef ARGHI +} + +/* -------------------------------------------------------------------- */ + +static const float fsk96_tx_coeff_4[32] = { + -0.001152, 0.000554, 0.002698, 0.002753, + -0.002033, -0.008861, -0.008002, 0.006607, + 0.023727, 0.018905, -0.018056, -0.057957, + -0.044368, 0.055683, 0.207667, 0.322048, + 0.322048, 0.207667, 0.055683, -0.044368, + -0.057957, -0.018056, 0.018905, 0.023727, + 0.006607, -0.008002, -0.008861, -0.002033, + 0.002753, 0.002698, 0.000554, -0.001152 +}; + +static const float fsk96_tx_coeff_5[40] = { + -0.001009, -0.000048, 0.001376, 0.002547, + 0.002061, -0.001103, -0.005795, -0.008170, + -0.004017, 0.006924, 0.018225, 0.019238, + 0.002925, -0.025777, -0.048064, -0.039683, + 0.013760, 0.104144, 0.200355, 0.262346, + 0.262346, 0.200355, 0.104144, 0.013760, + -0.039683, -0.048064, -0.025777, 0.002925, + 0.019238, 0.018225, 0.006924, -0.004017, + -0.008170, -0.005795, -0.001103, 0.002061, + 0.002547, 0.001376, -0.000048, -0.001009 +}; + +#define HAMMING(x) (0.54-0.46*cos(2*M_PI*(x))); + +static inline float hamming(float x) +{ + return 0.54-0.46*cos(2*M_PI*x); +} + +static inline float sinc(float x) +{ + if (x == 0) + return 1; + x *= M_PI; + return sin(x)/x; +} + +static void gentbl_fsk9600(FILE *f) +{ + int i, j, k, l, m; + float s; + float c[44]; + float min, max; + + fprintf(f, "\n/*\n * fsk9600 specific tables\n */\n"); + min = max = 0; + memset(c, 0, sizeof(c)); +#if 0 + memcpy(c+2, fsk96_tx_coeff_4, sizeof(fsk96_tx_coeff_4)); +#else + for (i = 0; i < 29; i++) + c[3+i] = sinc(1.2*((i-14.0)/4.0))*hamming(i/28.0)/3.5; +#endif + fprintf(f, "static unsigned char fsk96_txfilt_4[] = {\n\t"); + for (i = 0; i < 4; i++) { + for (j = 0; j < 256; j++) { + for (k = 1, s = 0, l = i; k < 256; k <<= 1) { + if (j & k) { + for (m = 0; m < 4; m++, l++) + s += c[l]; + } else { + for (m = 0; m < 4; m++, l++) + s -= c[l]; + } + } + s *= 0.75; + if (s > max) + max = s; + if (s < min) + min = s; + fprintf(f, "%4d", (int)(128+127*s)); + if (i < 3 || j < 255) + fprintf(f, ",%s", (j & 7) == 7 + ? "\n\t" : ""); + } + } + fprintf(stderr, "fsk9600: txfilt4: min = %f; max = %f\n", min, max); + fprintf(f, "\n};\n\n"); + min = max = 0; + memset(c, 0, sizeof(c)); +#if 0 + memcpy(c+2, fsk96_tx_coeff_5, sizeof(fsk96_tx_coeff_5)); +#else + for (i = 0; i < 36; i++) + c[4+i] = sinc(1.2*((i-17.5)/5.0))*hamming(i/35.0)/4.5; +#endif + fprintf(f, "static unsigned char fsk96_txfilt_5[] = {\n\t"); + for (i = 0; i < 5; i++) { + for (j = 0; j < 256; j++) { + for (k = 1, s = 0, l = i; k < 256; k <<= 1) { + if (j & k) { + for (m = 0; m < 5; m++, l++) + s += c[l]; + } else { + for (m = 0; m < 5; m++, l++) + s -= c[l]; + } + } + s *= 0.75; + if (s > max) + max = s; + if (s < min) + min = s; + fprintf(f, "%4d", (int)(128+127*s)); + if (i < 4 || j < 255) + fprintf(f, ",%s", (j & 7) == 7 + ? "\n\t" : ""); + } + } + fprintf(stderr, "fsk9600: txfilt5: min = %f; max = %f\n", min, max); + fprintf(f, "\n};\n\n"); +} + +/* -------------------------------------------------------------------- */ + +#define AFSK26_SAMPLERATE 16000 + +#define AFSK26_NUMCAR 2 +#define AFSK26_FIRSTCAR 2000 +#define AFSK26_MSK_LEN 6 +#define AFSK26_RXOVER 2 + +#define AFSK26_DEMCORRLEN (2*AFSK26_MSK_LEN) + +#define AFSK26_WINDOW(x) ((1-cos(2.0*M_PI*(x)))/2.0) + +#define AFSK26_AMPL(x) (((x)?1.0:0.7)) + +#undef AFSK26_AMPL +#define AFSK26_AMPL(x) 1 + +static void gentbl_afsk2666(FILE *f) +{ + int i, j, k, l, o; + float window[AFSK26_DEMCORRLEN*AFSK26_RXOVER]; + int cfreq[AFSK26_NUMCAR]; + + fprintf(f, "\n/*\n * afsk2666 specific tables\n */\n" + "#define AFSK26_DEMCORRLEN %d\n" + "#define AFSK26_SAMPLERATE %d\n\n", AFSK26_DEMCORRLEN, + AFSK26_SAMPLERATE); + fprintf(f, "static const unsigned int afsk26_carfreq[%d] = { ", + AFSK26_NUMCAR); + for (i = 0; i < AFSK26_NUMCAR; i++) { + cfreq[i] = 0x10000*AFSK26_FIRSTCAR/AFSK26_SAMPLERATE+ + 0x10000*i/AFSK26_MSK_LEN/2; + fprintf(f, "0x%x", cfreq[i]); + if (i < AFSK26_NUMCAR-1) + fprintf(f, ", "); + } + fprintf(f, " };\n\n"); + for (i = 0; i < AFSK26_DEMCORRLEN*AFSK26_RXOVER; i++) + window[i] = AFSK26_WINDOW(((float)i)/(AFSK26_DEMCORRLEN* + AFSK26_RXOVER)) * 127.0; + fprintf(f, "\nstatic const struct {\n\t" + "signed char i[%d];\n\tsigned char q[%d];\n} afsk26_dem_tables[%d][2] = {\n", + AFSK26_DEMCORRLEN, AFSK26_DEMCORRLEN, AFSK26_RXOVER); + for (o = AFSK26_RXOVER-1; o >= 0; o--) { + fprintf(f, "\t{\n"); + for (i = 0; i < AFSK26_NUMCAR; i++) { + j = cfreq[i]; + fprintf(f, "\t\t{{ "); + for (l = AFSK26_DEMCORRLEN-1, + k = (j * o)/AFSK26_RXOVER; l >= 0; + l--, k = (k+j)&0xffffu) + fprintf(f, "%6d%s", (int) + (AFSK26_AMPL(i)* + window[l*AFSK26_RXOVER+o]* + cos(M_PI*k/32768.0)), + l ? ", " : " }, { "); + for (l = AFSK26_DEMCORRLEN-1, + k = (j * o)/AFSK26_RXOVER; l >= 0; + l--, k = (k+j)&0xffffu) + fprintf(f, "%6d%s", (int) + (AFSK26_AMPL(i)* + window[l*AFSK26_RXOVER+o]* + sin(M_PI*k/32768.0)), + l ? ", " : " }}"); + if (i < 1) + fprintf(f, ","); + fprintf(f, "\n"); + } + fprintf(f, "\t}%s\n", o ? "," : ""); + } + fprintf(f, "};\n\n"); +} + +/* -------------------------------------------------------------------- */ + +#define COSTABBITS 8 + +static void gentbl_costab(FILE *f) +{ + int i; + + fprintf(f, "\n/*\n * more accurate cosine table\n */\n\n" + "static const short costab[%d] = {", (1<>%d)&0x%x]\n" + "#define SIN(x) COS((x)+0xc000)\n\n", 16-COSTABBITS, + (1< max) + max = s; + if (s < min) + min = s; + fprintf(f, "%4d", (int)(128+127*s)); + if (i < 7 || j < 15) + fprintf(f, ",%s", (j & 7) == 7 + ? "\n\t" : ""); + } + } + fprintf(stderr, "hapn4800: txfilt8: min = %f; max = %f\n", min, max); + fprintf(f, "\n};\n\n"); + min = max = 0; + memset(c, 0, sizeof(c)); + for (i = 0; i < 30; i++) + c[10+i] = sinc(1.5*((i-14.5)/10.0))*hamming(i/29.0)/2.4; + for (i = 0; i < 30; i++) + c[i] -= c[i+10]; + fprintf(f, "static unsigned char hapn48_txfilt_10[] = {\n\t"); + for (i = 0; i < 10; i++) { + for (j = 0; j < 16; j++) { + for (k = 1, s = 0, l = i; k < 16; k <<= 1, l += 10) { + if (j & k) + s += c[l]; + else + s -= c[l]; + } + if (s > max) + max = s; + if (s < min) + min = s; + fprintf(f, "%4d", (int)(128+127*s)); + if (i < 9 || j < 15) + fprintf(f, ",%s", (j & 7) == 7 + ? "\n\t" : ""); + } + } + fprintf(stderr, "hapn4800: txfilt10: min = %f; max = %f\n", min, max); + fprintf(f, "\n};\n\n"); + /* + * secondly generate tables for the PM transmitter modulator + */ + min = max = 0; + memset(c, 0, sizeof(c)); + for (i = 0; i < 25; i++) + c[i] = sinc(1.4*((i-12.0)/8.0))*hamming(i/24.0)/6.3; + for (i = 0; i < 25; i++) + for (j = 1; j < 8; j++) + c[i] += c[i+j]; + fprintf(f, "static unsigned char hapn48_txfilt_pm8[] = {\n\t"); + for (i = 0; i < 8; i++) { + for (j = 0; j < 16; j++) { + for (k = 1, s = 0, l = i; k < 16; k <<= 1, l += 8) { + if (j & k) + s += c[l]; + else + s -= c[l]; + } + if (s > max) + max = s; + if (s < min) + min = s; + fprintf(f, "%4d", (int)(128+127*s)); + if (i < 7 || j < 15) + fprintf(f, ",%s", (j & 7) == 7 + ? "\n\t" : ""); + } + } + fprintf(stderr, "hapn4800: txfiltpm8: min = %f; max = %f\n", min, max); + fprintf(f, "\n};\n\n"); + min = max = 0; + memset(c, 0, sizeof(c)); + for (i = 0; i < 31; i++) + c[10+i] = sinc(1.4*((i-15.0)/10.0))*hamming(i/30.0)/7.9; + for (i = 0; i < 31; i++) + for (j = 1; j < 10; j++) + c[i] += c[i+j]; + fprintf(f, "static unsigned char hapn48_txfilt_pm10[] = {\n\t"); + for (i = 0; i < 10; i++) { + for (j = 0; j < 16; j++) { + for (k = 1, s = 0, l = i; k < 16; k <<= 1, l += 10) { + if (j & k) + s += c[l]; + else + s -= c[l]; + } + if (s > max) + max = s; + if (s < min) + min = s; + fprintf(f, "%4d", (int)(128+127*s)); + if (i < 9 || j < 15) + fprintf(f, ",%s", (j & 7) == 7 + ? "\n\t" : ""); + } + } + fprintf(stderr, "hapn4800: txfiltpm10: min = %f; max = %f\n", min, max); + fprintf(f, "\n};\n\n"); + +} + +/* -------------------------------------------------------------------- */ + +static char *progname; + +static void gentbl_banner(FILE *f) +{ + fprintf(f, "/*\n * THIS FILE IS GENERATED AUTOMATICALLY BY %s, " + "DO NOT EDIT!\n */\n\n", progname); +} + +/* -------------------------------------------------------------------- */ + +void main(int argc, char *argv[]) +{ + FILE *f; + + progname = argv[0]; + if (!(f = fopen("sm_tbl_afsk1200.h", "w"))) + exit(1); + gentbl_banner(f); + gentbl_offscostab(f); + gentbl_afsk1200(f); + fclose(f); + if (!(f = fopen("sm_tbl_afsk2666.h", "w"))) + exit(1); + gentbl_banner(f); + gentbl_offscostab(f); + gentbl_afsk2666(f); + fclose(f); + if (!(f = fopen("sm_tbl_psk4800.h", "w"))) + exit(1); + gentbl_banner(f); + gentbl_psk4800(f); + gentbl_costab(f); + gentbl_atantab(f); + fclose(f); + if (!(f = fopen("sm_tbl_hapn4800.h", "w"))) + exit(1); + gentbl_banner(f); + gentbl_hapn4800(f); + fclose(f); + if (!(f = fopen("sm_tbl_fsk9600.h", "w"))) + exit(1); + gentbl_banner(f); + gentbl_fsk9600(f); + fclose(f); + exit(0); +} + + +/* -------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.26/linux/drivers/net/soundmodem/sm.c linux/drivers/net/soundmodem/sm.c --- v2.1.26/linux/drivers/net/soundmodem/sm.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/soundmodem/sm.c Fri Feb 21 14:58:35 1997 @@ -0,0 +1,815 @@ +/*****************************************************************************/ + +/* + * sm.c -- soundcard radio modem driver. + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + * + * Command line options (insmod command line) + * + * mode mode string; eg. "wss:afsk1200" + * iobase base address of the soundcard; common values are 0x220 for sbc, + * 0x530 for wss + * irq interrupt number; common values are 7 or 5 for sbc, 11 for wss + * dma dma number; common values are 0 or 1 + * + * + * History: + * 0.1 21.09.96 Started + * 18.10.96 Changed to new user space access routines (copy_{to,from}_user) + * 0.4 21.01.97 Separately compileable soundcard/modem modules + */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sm.h" + +/* --------------------------------------------------------------------- */ + +/* + * currently this module is supposed to support both module styles, i.e. + * the old one present up to about 2.1.9, and the new one functioning + * starting with 2.1.21. The reason is I have a kit allowing to compile + * this module also under 2.0.x which was requested by several people. + * This will go in 2.2 + */ +#include + +#if LINUX_VERSION_CODE >= 0x20100 +#include +#else +#include +#include + +#undef put_user +#undef get_user + +#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; }) +#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; }) + +extern inline int copy_from_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_READ, from, n); + if (i) + return i; + memcpy_fromfs(to, from, n); + return 0; +} + +extern inline int copy_to_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_WRITE, to, n); + if (i) + return i; + memcpy_tofs(to, from, n); + return 0; +} +#endif + +/* --------------------------------------------------------------------- */ + +static const char sm_drvname[] = "soundmodem"; +static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996 Thomas Sailer, HB9JNX/AE4WA\n" +KERN_INFO "soundmodem: version 0.4 compiled " __TIME__ " " __DATE__ "\n"; + +/* --------------------------------------------------------------------- */ + +static const struct modem_tx_info *sm_modem_tx_table[] = { +#ifdef CONFIG_SOUNDMODEM_AFSK1200 + &sm_afsk1200_tx, +#endif /* CONFIG_SOUNDMODEM_AFSK1200 */ +#ifdef CONFIG_SOUNDMODEM_AFSK2666 + &sm_afsk2666_tx, +#endif /* CONFIG_SOUNDMODEM_AFSK2666 */ +#ifdef CONFIG_SOUNDMODEM_PSK4800 + &sm_psk4800_tx, +#endif /* CONFIG_SOUNDMODEM_PSK4800 */ +#ifdef CONFIG_SOUNDMODEM_HAPN4800 + &sm_hapn4800_8_tx, + &sm_hapn4800_10_tx, + &sm_hapn4800_pm8_tx, + &sm_hapn4800_pm10_tx, +#endif /* CONFIG_SOUNDMODEM_HAPN4800 */ +#ifdef CONFIG_SOUNDMODEM_FSK9600 + &sm_fsk9600_4_tx, + &sm_fsk9600_5_tx, +#endif /* CONFIG_SOUNDMODEM_FSK9600 */ + NULL +}; + +static const struct modem_rx_info *sm_modem_rx_table[] = { +#ifdef CONFIG_SOUNDMODEM_AFSK1200 + &sm_afsk1200_rx, +#endif /* CONFIG_SOUNDMODEM_AFSK1200 */ +#ifdef CONFIG_SOUNDMODEM_AFSK2666 + &sm_afsk2666_rx, +#endif /* CONFIG_SOUNDMODEM_AFSK2666 */ +#ifdef CONFIG_SOUNDMODEM_PSK4800 + &sm_psk4800_rx, +#endif /* CONFIG_SOUNDMODEM_PSK4800 */ +#ifdef CONFIG_SOUNDMODEM_HAPN4800 + &sm_hapn4800_8_rx, + &sm_hapn4800_10_rx, + &sm_hapn4800_pm8_rx, + &sm_hapn4800_pm10_rx, +#endif /* CONFIG_SOUNDMODEM_HAPN4800 */ +#ifdef CONFIG_SOUNDMODEM_FSK9600 + &sm_fsk9600_4_rx, + &sm_fsk9600_5_rx, +#endif /* CONFIG_SOUNDMODEM_FSK9600 */ + NULL +}; + +static const struct hardware_info *sm_hardware_table[] = { +#ifdef CONFIG_SOUNDMODEM_SBC + &sm_hw_sbc, +#endif /* CONFIG_SOUNDMODEM_SBC */ +#ifdef CONFIG_SOUNDMODEM_WSS + &sm_hw_wss, + &sm_hw_wssfdx, +#endif /* CONFIG_SOUNDMODEM_WSS */ + NULL +}; + +/* --------------------------------------------------------------------- */ + +#define NR_PORTS 4 + +/* --------------------------------------------------------------------- */ + +static struct device sm_device[NR_PORTS]; + +static struct { + char *mode; + int iobase, irq, dma, dma2, seriobase, pariobase, midiiobase; +} sm_ports[NR_PORTS] = { + { NULL, -1, 0, 0, 0, -1, -1, -1 }, +}; + +/* --------------------------------------------------------------------- */ + +#define UART_RBR(iobase) (iobase+0) +#define UART_THR(iobase) (iobase+0) +#define UART_IER(iobase) (iobase+1) +#define UART_IIR(iobase) (iobase+2) +#define UART_FCR(iobase) (iobase+2) +#define UART_LCR(iobase) (iobase+3) +#define UART_MCR(iobase) (iobase+4) +#define UART_LSR(iobase) (iobase+5) +#define UART_MSR(iobase) (iobase+6) +#define UART_SCR(iobase) (iobase+7) +#define UART_DLL(iobase) (iobase+0) +#define UART_DLM(iobase) (iobase+1) + +#define SER_EXTENT 8 + +#define LPT_DATA(iobase) (iobase+0) +#define LPT_STATUS(iobase) (iobase+1) +#define LPT_CONTROL(iobase) (iobase+2) +#define LPT_IRQ_ENABLE 0x10 + +#define LPT_EXTENT 3 + +#define MIDI_DATA(iobase) (iobase) +#define MIDI_STATUS(iobase) (iobase+1) +#define MIDI_READ_FULL 0x80 /* attention: negative logic!! */ +#define MIDI_WRITE_EMPTY 0x40 /* attention: negative logic!! */ + +#define MIDI_EXTENT 2 + +/* ---------------------------------------------------------------------- */ + +#define PARAM_TXDELAY 1 +#define PARAM_PERSIST 2 +#define PARAM_SLOTTIME 3 +#define PARAM_TXTAIL 4 +#define PARAM_FULLDUP 5 +#define PARAM_HARDWARE 6 +#define PARAM_RETURN 255 + +#define SP_SER 1 +#define SP_PAR 2 +#define SP_MIDI 4 + +/* --------------------------------------------------------------------- */ +/* + * ===================== port checking routines ======================== + */ + +static int check_lpt(unsigned int iobase) +{ + unsigned char b1,b2; + int i; + + if (iobase <= 0 || iobase > 0x1000-LPT_EXTENT) + return 0; + if (check_region(iobase, LPT_EXTENT)) + return 0; + b1 = inb(LPT_DATA(iobase)); + b2 = inb(LPT_CONTROL(iobase)); + outb(0xaa, LPT_DATA(iobase)); + i = inb(LPT_DATA(iobase)) == 0xaa; + outb(0x55, LPT_DATA(iobase)); + i &= inb(LPT_DATA(iobase)) == 0x55; + outb(0x0a, LPT_CONTROL(iobase)); + i &= (inb(LPT_CONTROL(iobase)) & 0xf) == 0x0a; + outb(0x05, LPT_CONTROL(iobase)); + i &= (inb(LPT_CONTROL(iobase)) & 0xf) == 0x05; + outb(b1, LPT_DATA(iobase)); + outb(b2, LPT_CONTROL(iobase)); + return !i; +} + +/* --------------------------------------------------------------------- */ + +enum uart { c_uart_unknown, c_uart_8250, + c_uart_16450, c_uart_16550, c_uart_16550A}; +static const char *uart_str[] = + { "unknown", "8250", "16450", "16550", "16550A" }; + +static enum uart check_uart(unsigned int iobase) +{ + unsigned char b1,b2,b3; + enum uart u; + enum uart uart_tab[] = + { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A }; + + if (iobase <= 0 || iobase > 0x1000-SER_EXTENT) + return c_uart_unknown; + if (check_region(iobase, SER_EXTENT)) + return c_uart_unknown; + b1 = inb(UART_MCR(iobase)); + outb(b1 | 0x10, UART_MCR(iobase)); /* loopback mode */ + b2 = inb(UART_MSR(iobase)); + outb(0x1a, UART_MCR(iobase)); + b3 = inb(UART_MSR(iobase)) & 0xf0; + outb(b1, UART_MCR(iobase)); /* restore old values */ + outb(b2, UART_MSR(iobase)); + if (b3 != 0x90) + return c_uart_unknown; + inb(UART_RBR(iobase)); + inb(UART_RBR(iobase)); + outb(0x01, UART_FCR(iobase)); /* enable FIFOs */ + u = uart_tab[(inb(UART_IIR(iobase)) >> 6) & 3]; + if (u == c_uart_16450) { + outb(0x5a, UART_SCR(iobase)); + b1 = inb(UART_SCR(iobase)); + outb(0xa5, UART_SCR(iobase)); + b2 = inb(UART_SCR(iobase)); + if ((b1 != 0x5a) || (b2 != 0xa5)) + u = c_uart_8250; + } + return u; +} + +/* --------------------------------------------------------------------- */ + +static int check_midi(unsigned int iobase) +{ + unsigned long timeout; + unsigned long flags; + unsigned char b; + + if (iobase <= 0 || iobase > 0x1000-MIDI_EXTENT) + return 0; + if (check_region(iobase, MIDI_EXTENT)) + return 0; + timeout = jiffies + (HZ / 100); + while (inb(MIDI_STATUS(iobase)) & MIDI_WRITE_EMPTY) + if ((signed)(jiffies - timeout) > 0) + return 0; + save_flags(flags); + cli(); + outb(0xff, MIDI_DATA(iobase)); + b = inb(MIDI_STATUS(iobase)); + restore_flags(flags); + if (!(b & MIDI_WRITE_EMPTY)) + return 0; + while (inb(MIDI_STATUS(iobase)) & MIDI_WRITE_EMPTY) + if ((signed)(jiffies - timeout) > 0) + return 0; + return 1; +} + +/* --------------------------------------------------------------------- */ + +void sm_output_status(struct sm_state *sm) +{ + int invert_dcd = 0; + int invert_ptt = 0; + + int ptt = hdlcdrv_ptt(&sm->hdrv) ^ invert_ptt; + int dcd = (!!sm->hdrv.hdlcrx.dcd) ^ invert_dcd; + + if (sm->hdrv.ptt_out.flags & SP_SER) { + outb(dcd | (ptt << 1), UART_MCR(sm->hdrv.ptt_out.seriobase)); + outb(0x40 & (-ptt), UART_LCR(sm->hdrv.ptt_out.seriobase)); + } + if (sm->hdrv.ptt_out.flags & SP_PAR) { + outb(ptt | (dcd << 1), LPT_DATA(sm->hdrv.ptt_out.pariobase)); + } + if (sm->hdrv.ptt_out.flags & SP_MIDI && hdlcdrv_ptt(&sm->hdrv)) { + outb(0, MIDI_DATA(sm->hdrv.ptt_out.midiiobase)); + } +} + +/* --------------------------------------------------------------------- */ + +static void sm_output_open(struct sm_state *sm) +{ + enum uart u = c_uart_unknown; + + sm->hdrv.ptt_out.flags = 0; + if (sm->hdrv.ptt_out.seriobase > 0 && + sm->hdrv.ptt_out.seriobase <= 0x1000-SER_EXTENT && + ((u = check_uart(sm->hdrv.ptt_out.seriobase))) != c_uart_unknown) { + sm->hdrv.ptt_out.flags |= SP_SER; + request_region(sm->hdrv.ptt_out.seriobase, SER_EXTENT, "sm ser ptt"); + outb(0, UART_IER(sm->hdrv.ptt_out.seriobase)); + /* 5 bits, 1 stop, no parity, no break, Div latch access */ + outb(0x80, UART_LCR(sm->hdrv.ptt_out.seriobase)); + outb(0, UART_DLM(sm->hdrv.ptt_out.seriobase)); + outb(1, UART_DLL(sm->hdrv.ptt_out.seriobase)); /* as fast as possible */ + /* LCR and MCR set by output_status */ + } + if (sm->hdrv.ptt_out.pariobase > 0 && + sm->hdrv.ptt_out.pariobase <= 0x1000-LPT_EXTENT && + check_lpt(sm->hdrv.ptt_out.pariobase)) { + sm->hdrv.ptt_out.flags |= SP_PAR; + request_region(sm->hdrv.ptt_out.pariobase, LPT_EXTENT, "sm par ptt"); + } + if (sm->hdrv.ptt_out.midiiobase > 0 && + sm->hdrv.ptt_out.midiiobase <= 0x1000-MIDI_EXTENT && + check_midi(sm->hdrv.ptt_out.midiiobase)) { + sm->hdrv.ptt_out.flags |= SP_MIDI; + request_region(sm->hdrv.ptt_out.midiiobase, MIDI_EXTENT, + "sm midi ptt"); + } + sm_output_status(sm); + + printk(KERN_INFO "%s: ptt output:", sm_drvname); + if (sm->hdrv.ptt_out.flags & SP_SER) + printk(" serial interface at 0x%x, uart %s", sm->hdrv.ptt_out.seriobase, + uart_str[u]); + if (sm->hdrv.ptt_out.flags & SP_PAR) + printk(" parallel interface at 0x%x", sm->hdrv.ptt_out.pariobase); + if (sm->hdrv.ptt_out.flags & SP_MIDI) + printk(" mpu401 (midi) interface at 0x%x", sm->hdrv.ptt_out.midiiobase); + if (!sm->hdrv.ptt_out.flags) + printk(" none"); + printk("\n"); +} + +/* --------------------------------------------------------------------- */ + +static void sm_output_close(struct sm_state *sm) +{ + /* release regions used for PTT output */ + sm->hdrv.hdlctx.ptt = sm->hdrv.hdlctx.calibrate = 0; + sm_output_status(sm); + if (sm->hdrv.ptt_out.flags & SP_SER) + release_region(sm->hdrv.ptt_out.seriobase, SER_EXTENT); + if (sm->hdrv.ptt_out.flags & SP_PAR) + release_region(sm->hdrv.ptt_out.pariobase, LPT_EXTENT); + if (sm->hdrv.ptt_out.flags & SP_MIDI) + release_region(sm->hdrv.ptt_out.midiiobase, MIDI_EXTENT); + sm->hdrv.ptt_out.flags = 0; +} + +/* --------------------------------------------------------------------- */ + +static int sm_open(struct device *dev); +static int sm_close(struct device *dev); +static int sm_ioctl(struct device *dev, struct ifreq *ifr, + struct hdlcdrv_ioctl *hi, int cmd); + +/* --------------------------------------------------------------------- */ + +static const struct hdlcdrv_ops sm_ops = { + sm_drvname, sm_drvinfo, sm_open, sm_close, sm_ioctl +}; + +/* --------------------------------------------------------------------- */ + +static int sm_open(struct device *dev) +{ + struct sm_state *sm; + int err; + + if (!dev || !dev->priv || + ((struct sm_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { + printk(KERN_ERR "sm_open: invalid device struct\n"); + return -EINVAL; + } + sm = (struct sm_state *)dev->priv; + + if (!sm->mode_tx || !sm->mode_rx || !sm->hwdrv || !sm->hwdrv->open) + return -ENODEV; + sm->hdrv.par.bitrate = sm->mode_rx->bitrate; + err = sm->hwdrv->open(dev, sm); + if (err) + return err; + sm_output_open(sm); + MOD_INC_USE_COUNT; + printk(KERN_INFO "%s: %s mode %s.%s at iobase 0x%lx irq %u dma %u\n", + sm_drvname, sm->hwdrv->hw_name, sm->mode_tx->name, + sm->mode_rx->name, dev->base_addr, dev->irq, dev->dma); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int sm_close(struct device *dev) +{ + struct sm_state *sm; + int err = -ENODEV; + + if (!dev || !dev->priv || + ((struct sm_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { + printk(KERN_ERR "sm_close: invalid device struct\n"); + return -EINVAL; + } + sm = (struct sm_state *)dev->priv; + + + if (sm->hwdrv && sm->hwdrv->close) + err = sm->hwdrv && sm->hwdrv->close(dev, sm); + sm_output_close(sm); + MOD_DEC_USE_COUNT; + printk(KERN_INFO "%s: close %s at iobase 0x%lx irq %u dma %u\n", + sm_drvname, sm->hwdrv->hw_name, dev->base_addr, dev->irq, dev->dma); + return err; +} + +/* --------------------------------------------------------------------- */ + +static int sethw(struct device *dev, struct sm_state *sm, char *mode) +{ + char *cp = strchr(mode, ':'); + const struct hardware_info **hwp = sm_hardware_table; + + if (!cp) + cp = mode; + else { + *cp++ = '\0'; + while (hwp && (*hwp) && (*hwp)->hw_name && strcmp((*hwp)->hw_name, mode)) + hwp++; + if (!hwp || !*hwp || !(*hwp)->hw_name) + return -EINVAL; + if ((*hwp)->loc_storage > sizeof(sm->hw)) { + printk(KERN_ERR "%s: insufficient storage for hw driver %s (%d)\n", + sm_drvname, (*hwp)->hw_name, (*hwp)->loc_storage); + return -EINVAL; + } + sm->hwdrv = *hwp; + } + if (!*cp) + return 0; + if (sm->hwdrv && sm->hwdrv->sethw) + return sm->hwdrv->sethw(dev, sm, cp); + return -EINVAL; +} + +/* --------------------------------------------------------------------- */ + +static int sm_ioctl(struct device *dev, struct ifreq *ifr, + struct hdlcdrv_ioctl *hi, int cmd) +{ + struct sm_state *sm; + struct sm_ioctl bi; + unsigned long flags; + unsigned int newdiagmode; + unsigned int newdiagflags; + char *cp; + const struct modem_tx_info **mtp = sm_modem_tx_table; + const struct modem_rx_info **mrp = sm_modem_rx_table; + const struct hardware_info **hwp = sm_hardware_table; + + if (!dev || !dev->priv || + ((struct sm_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { + printk(KERN_ERR "sm_ioctl: invalid device struct\n"); + return -EINVAL; + } + sm = (struct sm_state *)dev->priv; + + if (cmd != SIOCDEVPRIVATE) { + if (!sm->hwdrv || !sm->hwdrv->ioctl) + return sm->hwdrv->ioctl(dev, sm, ifr, hi, cmd); + return -ENOIOCTLCMD; + } + switch (hi->cmd) { + default: + if (sm->hwdrv && sm->hwdrv->ioctl) + return sm->hwdrv->ioctl(dev, sm, ifr, hi, cmd); + return -ENOIOCTLCMD; + + case HDLCDRVCTL_GETMODE: + cp = hi->data.modename; + if (sm->hwdrv && sm->hwdrv->hw_name) + cp += sprintf(cp, "%s:", sm->hwdrv->hw_name); + else + cp += sprintf(cp, ":"); + if (sm->mode_tx && sm->mode_tx->name) + cp += sprintf(cp, "%s", sm->mode_tx->name); + else + cp += sprintf(cp, ""); + if (!sm->mode_rx || !sm->mode_rx || + strcmp(sm->mode_rx->name, sm->mode_tx->name)) { + if (sm->mode_rx && sm->mode_rx->name) + cp += sprintf(cp, ",%s", sm->mode_rx->name); + else + cp += sprintf(cp, ","); + } + if (copy_to_user(ifr->ifr_data, hi, sizeof(*hi))) + return -EFAULT; + return 0; + + case HDLCDRVCTL_SETMODE: + if (!suser() || dev->start) + return -EACCES; + hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; + return sethw(dev, sm, hi->data.modename); + + case HDLCDRVCTL_MODELIST: + cp = hi->data.modename; + while (*hwp) { + if ((*hwp)->hw_name) + cp += sprintf("%s:,", (*hwp)->hw_name); + hwp++; + } + while (*mtp) { + if ((*mtp)->name) + cp += sprintf(">%s,", (*mtp)->name); + mtp++; + } + while (*mrp) { + if ((*mrp)->name) + cp += sprintf("<%s,", (*mrp)->name); + mrp++; + } + cp[-1] = '\0'; + if (copy_to_user(ifr->ifr_data, hi, sizeof(*hi))) + return -EFAULT; + return 0; + +#ifdef SM_DEBUG + case SMCTL_GETDEBUG: + if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) + return -EFAULT; + bi.data.dbg.int_rate = sm->debug_vals.last_intcnt; + bi.data.dbg.mod_cycles = sm->debug_vals.mod_cyc; + bi.data.dbg.demod_cycles = sm->debug_vals.demod_cyc; + bi.data.dbg.dma_residue = sm->debug_vals.dma_residue; + sm->debug_vals.mod_cyc = sm->debug_vals.demod_cyc = + sm->debug_vals.dma_residue = 0; + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return 0; +#endif /* SM_DEBUG */ + + case SMCTL_DIAGNOSE: + if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) + return -EFAULT; + newdiagmode = bi.data.diag.mode; + newdiagflags = bi.data.diag.flags; + if (newdiagmode > SM_DIAGMODE_CONSTELLATION) + return -EINVAL; + bi.data.diag.mode = sm->diag.mode; + bi.data.diag.flags = sm->diag.flags; + bi.data.diag.samplesperbit = sm->mode_rx->sperbit; + if (sm->diag.mode != newdiagmode) { + save_flags(flags); + cli(); + sm->diag.ptr = -1; + sm->diag.flags = newdiagflags & ~SM_DIAGFLAG_VALID; + sm->diag.mode = newdiagmode; + restore_flags(flags); + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return 0; + } + if (sm->diag.ptr < 0 || sm->diag.mode == SM_DIAGMODE_OFF) { + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return 0; + } + if (bi.data.diag.datalen > DIAGDATALEN) + bi.data.diag.datalen = DIAGDATALEN; + if (sm->diag.ptr < bi.data.diag.datalen) { + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return 0; + } + if (copy_to_user(bi.data.diag.data, sm->diag.data, + bi.data.diag.datalen * sizeof(short))) + return -EFAULT; + bi.data.diag.flags |= SM_DIAGFLAG_VALID; + save_flags(flags); + cli(); + sm->diag.ptr = -1; + sm->diag.flags = newdiagflags & ~SM_DIAGFLAG_VALID; + sm->diag.mode = newdiagmode; + restore_flags(flags); + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return 0; + } +} + +/* --------------------------------------------------------------------- */ + +#ifdef MODULE +static +#endif /* MODULE */ +int sm_init(void) +{ + int i, j, found = 0; + char set_hw = 1; + struct sm_state *sm; + char ifname[HDLCDRV_IFNAMELEN]; + + printk(sm_drvinfo); + /* + * register net devices + */ + for (i = 0; i < NR_PORTS; i++) { + struct device *dev = sm_device+i; + sprintf(ifname, "sm%d", i); + + if (!sm_ports[i].mode) + set_hw = 0; + if (!set_hw) + sm_ports[i].iobase = sm_ports[i].irq = 0; + j = hdlcdrv_register_hdlcdrv(dev, &sm_ops, sizeof(struct sm_state), + ifname, sm_ports[i].iobase, + sm_ports[i].irq, sm_ports[i].dma); + if (!j) { + sm = (struct sm_state *)dev->priv; + sm->hdrv.ptt_out.dma2 = sm_ports[i].dma2; + sm->hdrv.ptt_out.seriobase = sm_ports[i].seriobase; + sm->hdrv.ptt_out.pariobase = sm_ports[i].pariobase; + sm->hdrv.ptt_out.midiiobase = sm_ports[i].midiiobase; + if (set_hw && sethw(dev, sm, sm_ports[i].mode)) + set_hw = 0; + found++; + } else { + printk(KERN_WARNING "%s: cannot register net device\n", + sm_drvname); + } + } + if (!found) + return -ENXIO; + return 0; +} + +/* --------------------------------------------------------------------- */ + +#ifdef MODULE + +/* + * command line settable parameters + */ +static char *mode = NULL; +static int iobase = -1; +static int irq = -1; +static int dma = -1; +static int dma2 = -1; +static int serio = 0; +static int pario = 0; +static int midiio = 0; + +#if LINUX_VERSION_CODE >= 0x20115 + +MODULE_PARM(mode, "s"); +MODULE_PARM_DESC(mode, "soundmodem operating mode; eg. sbc:afsk1200 or wss:fsk9600"); +MODULE_PARM(iobase, "i"); +MODULE_PARM_DESC(iobase, "soundmodem base address"); +MODULE_PARM(irq, "i"); +MODULE_PARM_DESC(irq, "soundmodem interrupt"); +MODULE_PARM(dma, "i"); +MODULE_PARM_DESC(dma, "soundmodem dma channel"); +MODULE_PARM(dma2, "i"); +MODULE_PARM_DESC(dma2, "soundmodem 2nd dma channel; full duplex only"); +MODULE_PARM(serio, "i"); +MODULE_PARM_DESC(serio, "soundmodem PTT output on serial port"); +MODULE_PARM(pario, "i"); +MODULE_PARM_DESC(pario, "soundmodem PTT output on parallel port"); +MODULE_PARM(midiio, "i"); +MODULE_PARM_DESC(midiio, "soundmodem PTT output on midi port"); + +MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); +MODULE_DESCRIPTION("Soundcard amateur radio modem driver"); + +#endif + +int init_module(void) +{ + if (mode) { + if (iobase == -1) + iobase = (!strncmp(mode, "sbc", 3)) ? 0x220 : 0x530; + if (irq == -1) + irq = (!strncmp(mode, "sbc", 3)) ? 5 : 11; + if (dma == -1) + dma = 1; + } + sm_ports[0].mode = mode; + sm_ports[0].iobase = iobase; + sm_ports[0].irq = irq; + sm_ports[0].dma = dma; + sm_ports[0].dma2 = dma2; + sm_ports[0].seriobase = serio; + sm_ports[0].pariobase = pario; + sm_ports[0].midiiobase = midiio; + sm_ports[1].mode = NULL; + + return sm_init(); +} + +/* --------------------------------------------------------------------- */ + +void cleanup_module(void) +{ + int i; + + printk(KERN_INFO "sm: cleanup_module called\n"); + + for(i = 0; i < NR_PORTS; i++) { + struct device *dev = sm_device+i; + struct sm_state *sm = (struct sm_state *)dev->priv; + + if (sm) { + if (sm->hdrv.magic != HDLCDRV_MAGIC) + printk(KERN_ERR "sm: invalid magic in " + "cleanup_module\n"); + else + hdlcdrv_unregister_hdlcdrv(dev); + } + } +} + +#else /* MODULE */ +/* --------------------------------------------------------------------- */ +/* + * format: sm=io,irq,dma[,dma2[,serio[,pario]]],mode + * mode: hw:modem + * hw: sbc, wss, wssfdx + * modem: afsk1200, fsk9600 + */ + +void sm_setup(char *str, int *ints) +{ + int i; + + for (i = 0; (i < NR_PORTS) && (sm_ports[i].mode); i++); + if ((i >= NR_PORTS) || (ints[0] < 3)) { + printk(KERN_INFO "%s: too many or invalid interface " + "specifications\n", sm_drvname); + return; + } + sm_ports[i].mode = str; + sm_ports[i].iobase = ints[1]; + sm_ports[i].irq = ints[2]; + sm_ports[i].dma = ints[3]; + sm_ports[i].dma2 = (ints[0] >= 4) ? ints[4] : 0; + sm_ports[i].seriobase = (ints[0] >= 5) ? ints[5] : 0; + sm_ports[i].pariobase = (ints[0] >= 6) ? ints[6] : 0; + sm_ports[i].midiiobase = (ints[0] >= 7) ? ints[7] : 0; + if (i < NR_PORTS-1) + sm_ports[i+1].mode = NULL; +} + +#endif /* MODULE */ +/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.26/linux/drivers/net/soundmodem/sm.h linux/drivers/net/soundmodem/sm.h --- v2.1.26/linux/drivers/net/soundmodem/sm.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/soundmodem/sm.h Fri Feb 21 14:58:35 1997 @@ -0,0 +1,360 @@ +/*****************************************************************************/ + +/* + * sm.h -- soundcard radio modem driver internal header. + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + */ + +#ifndef _SM_H +#define _SM_H + +/* ---------------------------------------------------------------------- */ + +#include +#include +#include + +#define SM_DEBUG + +/* --------------------------------------------------------------------- */ + +#define DMA_MODE_AUTOINIT 0x10 + +/* ---------------------------------------------------------------------- */ +/* + * Information that need to be kept for each board. + */ + +struct sm_state { + struct hdlcdrv_state hdrv; + + const struct modem_tx_info *mode_tx; + const struct modem_rx_info *mode_rx; + + const struct hardware_info *hwdrv; + + /* + * Hardware (soundcard) access routines state + */ + union { + long hw[32/sizeof(long)]; + } hw; + + /* + * state of the modem code + */ + union { + long m[32/sizeof(long)]; + } m; + union { + long d[256/sizeof(long)]; + } d; + +#define DIAGDATALEN 64 + struct diag_data { + unsigned int mode; + unsigned int flags; + volatile int ptr; + short data[DIAGDATALEN]; + } diag; + + +#ifdef SM_DEBUG + struct debug_vals { + unsigned long last_jiffies; + unsigned cur_intcnt; + unsigned last_intcnt; + unsigned mod_cyc; + unsigned demod_cyc; + unsigned dma_residue; + } debug_vals; +#endif /* SM_DEBUG */ +}; + +/* ---------------------------------------------------------------------- */ +/* + * Mode definition structure + */ + +struct modem_tx_info { + const char *name; + unsigned int loc_storage; + int srate; + int bitrate; + unsigned int dmabuflenmodulo; + void (*modulator)(struct sm_state *, unsigned char *, int); + void (*init)(struct sm_state *); +}; + +struct modem_rx_info { + const char *name; + unsigned int loc_storage; + int srate; + int bitrate; + unsigned int dmabuflenmodulo; + unsigned int sperbit; + void (*demodulator)(struct sm_state *, unsigned char *, int); + void (*init)(struct sm_state *); +}; + +/* ---------------------------------------------------------------------- */ +/* + * Soundcard driver definition structure + */ + +struct hardware_info { + char *hw_name; /* used for request_{region,irq,dma} */ + unsigned int loc_storage; + /* + * mode specific open/close + */ + int (*open)(struct device *, struct sm_state *); + int (*close)(struct device *, struct sm_state *); + int (*ioctl)(struct device *, struct sm_state *, struct ifreq *, + struct hdlcdrv_ioctl *, int); + int (*sethw)(struct device *, struct sm_state *, char *); +}; + +/* --------------------------------------------------------------------- */ + +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#define max(a, b) (((a) > (b)) ? (a) : (b)) + +/* --------------------------------------------------------------------- */ + +extern const char sm_drvname[]; +extern const char sm_drvinfo[]; + +/* --------------------------------------------------------------------- */ +/* + * ===================== diagnostics stuff =============================== + */ + +extern inline void diag_trigger(struct sm_state *sm) +{ + if (sm->diag.ptr < 0) + if (!(sm->diag.flags & SM_DIAGFLAG_DCDGATE) || sm->hdrv.hdlcrx.dcd) + sm->diag.ptr = 0; +} + +/* --------------------------------------------------------------------- */ + +#define SHRT_MAX ((short)(((unsigned short)(~0U))>>1)) +#define SHRT_MIN (-SHRT_MAX-1) + +extern inline void diag_add(struct sm_state *sm, int valinp, int valdemod) +{ + int val; + + if ((sm->diag.mode != SM_DIAGMODE_INPUT && + sm->diag.mode != SM_DIAGMODE_DEMOD) || + sm->diag.ptr >= DIAGDATALEN || sm->diag.ptr < 0) + return; + val = (sm->diag.mode == SM_DIAGMODE_DEMOD) ? valdemod : valinp; + /* clip */ + if (val > SHRT_MAX) + val = SHRT_MAX; + if (val < SHRT_MIN) + val = SHRT_MIN; + sm->diag.data[sm->diag.ptr++] = val; +} + +/* --------------------------------------------------------------------- */ + +extern inline void diag_add_one(struct sm_state *sm, int val) +{ + if ((sm->diag.mode != SM_DIAGMODE_INPUT && + sm->diag.mode != SM_DIAGMODE_DEMOD) || + sm->diag.ptr >= DIAGDATALEN || sm->diag.ptr < 0) + return; + /* clip */ + if (val > SHRT_MAX) + val = SHRT_MAX; + if (val < SHRT_MIN) + val = SHRT_MIN; + sm->diag.data[sm->diag.ptr++] = val; +} + +/* --------------------------------------------------------------------- */ + +static inline void diag_add_constellation(struct sm_state *sm, int vali, int valq) +{ + if ((sm->diag.mode != SM_DIAGMODE_CONSTELLATION) || + sm->diag.ptr >= DIAGDATALEN-1 || sm->diag.ptr < 0) + return; + /* clip */ + if (vali > SHRT_MAX) + vali = SHRT_MAX; + if (vali < SHRT_MIN) + vali = SHRT_MIN; + if (valq > SHRT_MAX) + valq = SHRT_MAX; + if (valq < SHRT_MIN) + valq = SHRT_MIN; + sm->diag.data[sm->diag.ptr++] = vali; + sm->diag.data[sm->diag.ptr++] = valq; +} + +/* --------------------------------------------------------------------- */ +/* + * ===================== utility functions =============================== + */ + +extern inline unsigned int hweight32(unsigned int w) + __attribute__ ((unused)); +extern inline unsigned int hweight16(unsigned short w) + __attribute__ ((unused)); +extern inline unsigned int hweight8(unsigned char w) + __attribute__ ((unused)); + +extern inline unsigned int hweight32(unsigned int w) +{ + unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); + res = (res & 0x33333333) + ((res >> 2) & 0x33333333); + res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); + res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); + return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); +} + +extern inline unsigned int hweight16(unsigned short w) +{ + unsigned short res = (w & 0x5555) + ((w >> 1) & 0x5555); + res = (res & 0x3333) + ((res >> 2) & 0x3333); + res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F); + return (res & 0x00FF) + ((res >> 8) & 0x00FF); +} + +extern inline unsigned int hweight8(unsigned char w) +{ + unsigned short res = (w & 0x55) + ((w >> 1) & 0x55); + res = (res & 0x33) + ((res >> 2) & 0x33); + return (res & 0x0F) + ((res >> 4) & 0x0F); +} + +extern inline unsigned int gcd(unsigned int x, unsigned int y) + __attribute__ ((unused)); +extern inline unsigned int lcm(unsigned int x, unsigned int y) + __attribute__ ((unused)); + +extern inline unsigned int gcd(unsigned int x, unsigned int y) +{ + for (;;) { + if (!x) + return y; + if (!y) + return x; + if (x > y) + x %= y; + else + y %= x; + } +} + +extern inline unsigned int lcm(unsigned int x, unsigned int y) +{ + return x * y / gcd(x, y); +} + +/* --------------------------------------------------------------------- */ +/* + * ===================== profiling ======================================= + */ + + +#if defined(SM_DEBUG) && (defined(CONFIG_M586) || defined(CONFIG_M686)) + +/* + * only do 32bit cycle counter arithmetic; we hope we won't overflow :-) + * in fact, overflowing modems would require over 2THz clock speeds :-) + */ + +#define time_exec(var,cmd) \ +({ \ + unsigned int cnt1, cnt2, cnt3; \ + __asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt3)); \ + cmd; \ + __asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt3)); \ + var = cnt2-cnt1; \ +}) +#else /* defined(SM_DEBUG) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */ + +#define time_exec(var,cmd) cmd + +#endif /* defined(SM_DEBUG) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */ + +/* --------------------------------------------------------------------- */ + +extern const struct modem_tx_info sm_afsk1200_tx; +extern const struct modem_tx_info sm_afsk2666_tx; +extern const struct modem_tx_info sm_psk4800_tx; +extern const struct modem_tx_info sm_hapn4800_8_tx; +extern const struct modem_tx_info sm_hapn4800_10_tx; +extern const struct modem_tx_info sm_hapn4800_pm8_tx; +extern const struct modem_tx_info sm_hapn4800_pm10_tx; +extern const struct modem_tx_info sm_fsk9600_4_tx; +extern const struct modem_tx_info sm_fsk9600_5_tx; + +extern const struct modem_rx_info sm_afsk1200_rx; +extern const struct modem_rx_info sm_afsk2666_rx; +extern const struct modem_rx_info sm_psk4800_rx; +extern const struct modem_rx_info sm_hapn4800_8_rx; +extern const struct modem_rx_info sm_hapn4800_10_rx; +extern const struct modem_rx_info sm_hapn4800_pm8_rx; +extern const struct modem_rx_info sm_hapn4800_pm10_rx; +extern const struct modem_rx_info sm_fsk9600_4_rx; +extern const struct modem_rx_info sm_fsk9600_5_rx; + +extern const struct hardware_info sm_hw_sbc; +extern const struct hardware_info sm_hw_wss; +extern const struct hardware_info sm_hw_wssfdx; + +extern const struct modem_tx_info *sm_modem_tx_table[]; +extern const struct modem_rx_info *sm_modem_rx_table[]; +extern const struct hardware_info *sm_hardware_table[]; + +/* --------------------------------------------------------------------- */ + +void sm_output_status(struct sm_state *sm); +/*void sm_output_open(struct sm_state *sm);*/ +/*void sm_output_close(struct sm_state *sm);*/ + +/* --------------------------------------------------------------------- */ + +extern void inline sm_int_freq(struct sm_state *sm) +{ +#ifdef SM_DEBUG + unsigned long cur_jiffies = jiffies; + /* + * measure the interrupt frequency + */ + sm->debug_vals.cur_intcnt++; + if ((cur_jiffies - sm->debug_vals.last_jiffies) >= HZ) { + sm->debug_vals.last_jiffies = cur_jiffies; + sm->debug_vals.last_intcnt = sm->debug_vals.cur_intcnt; + sm->debug_vals.cur_intcnt = 0; + } +#endif /* SM_DEBUG */ +} + +/* --------------------------------------------------------------------- */ +#endif /* _SM_H */ diff -u --recursive --new-file v2.1.26/linux/drivers/net/soundmodem/sm_afsk1200.c linux/drivers/net/soundmodem/sm_afsk1200.c --- v2.1.26/linux/drivers/net/soundmodem/sm_afsk1200.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/soundmodem/sm_afsk1200.c Fri Feb 21 14:58:35 1997 @@ -0,0 +1,273 @@ +/*****************************************************************************/ + +/* + * sm_afsk1200.h -- soundcard radio modem driver, 1200 baud AFSK modem + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + */ + +#include "sm.h" +#include "sm_tbl_afsk1200.h" + +/* --------------------------------------------------------------------- */ + +struct demod_state_afsk12 { + unsigned int shreg; + unsigned int bit_pll; + unsigned char last_sample; + unsigned int dcd_shreg; + int dcd_sum0, dcd_sum1, dcd_sum2; + unsigned int dcd_time; + unsigned char last_rxbit; + union { + signed char c[8]; + float f[8]; + } filt; +}; + +struct mod_state_afsk12 { + unsigned int shreg; + unsigned char tx_bit; + unsigned int bit_pll; +}; + +/* --------------------------------------------------------------------- */ + +static void modulator_1200(struct sm_state *sm, unsigned char *buf, int buflen) +{ + struct mod_state_afsk12 *st = (struct mod_state_afsk12 *)(&sm->m); + static const int dds_inc[2] = { AFSK12_TX_FREQ_LO*0x10000/AFSK12_SAMPLE_RATE, + AFSK12_TX_FREQ_HI*0x10000/AFSK12_SAMPLE_RATE }; + int j, k; + + for (; buflen >= 8; buflen -= 8) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit ^ + (!(st->shreg & 1))) & 1; + st->shreg >>= 1; + k = dds_inc[st->tx_bit & 1]; + for (j = 0; j < 8; j++) { + *buf++ = OFFSCOS(st->bit_pll); + st->bit_pll += k; + } + } +} + +/* --------------------------------------------------------------------- */ + + +/* + * should eventually move to an asm header file + */ + + + + +#if defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && (defined(CONFIG_M586) || defined(CONFIG_M686)) + + + +#define ENV_STORAGE unsigned char fpu_save[108]; + +#define ENV_SAVE asm("fsave %0;\n\tfninit;\n\t" : "=m" (*fpu_save) : : "memory"); +#define ENV_RESTORE asm("frstor %0;\n\t" : : "m" (*fpu_save)); + +static inline float convolution8(const float *st, const float *coeff) +{ + float f; + + /* + * from Phil Karn, KA9Q's home page + */ + asm volatile ("flds (%1);\n\t" + "fmuls (%2);\n\t" + "flds 4(%1);\n\t" + "fmuls 4(%2);\n\t" + "flds 8(%1);\n\t" + "fmuls 8(%2);\n\t" + "fxch %%st(2);\n\t" + "faddp;\n\t" + "flds 12(%1);\n\t" + "fmuls 12(%2);\n\t" + "fxch %%st(2);\n\t" + "faddp;\n\t" + "flds 16(%1);\n\t" + "fmuls 16(%2);\n\t" + "fxch %%st(2);\n\t" + "faddp;\n\t" + "flds 20(%1);\n\t" + "fmuls 20(%2);\n\t" + "fxch %%st(2);\n\t" + "faddp;\n\t" + "flds 24(%1);\n\t" + "fmuls 24(%2);\n\t" + "fxch %%st(2);\n\t" + "faddp;\n\t" + "flds 28(%1);\n\t" + "fmuls 28(%2);\n\t" + "fxch %%st(2);\n\t" + "faddp;\n\t" + "faddp;\n\t" + "fmul %%st(0),%%st;\n\t" : + "=t" (f) : + "r" (st), + "r" (coeff) : "memory"); + + return f; +} + +static inline int do_filter_1200(struct demod_state_afsk12 *st, unsigned char newval) +{ + float sum; + + memmove(st->filt.f+1, st->filt.f,sizeof(st->filt.f) - sizeof(st->filt.f[0])); + st->filt.f[0] = (((int)newval)-0x80); + + sum = convolution8(st->filt.f, afsk12_tx_lo_i); + sum += convolution8(st->filt.f, afsk12_tx_lo_q); + sum -= convolution8(st->filt.f, afsk12_tx_hi_i); + sum -= convolution8(st->filt.f, afsk12_tx_hi_q); + return sum; +} + +#else /* defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */ + +#define ENV_STORAGE +#define ENV_SAVE +#define ENV_RESTORE + +static inline void datamove8(signed char *st, unsigned char newval) +{ + memmove(st+1, st, 7); + *st = newval - 0x80; +} + +static inline int convolution8(const signed char *st, const signed char *coeff) +{ + int sum = (st[0] * coeff[0]); + + sum += (st[1] * coeff[1]); + sum += (st[2] * coeff[2]); + sum += (st[3] * coeff[3]); + sum += (st[4] * coeff[4]); + sum += (st[5] * coeff[5]); + sum += (st[6] * coeff[6]); + sum += (st[7] * coeff[7]); + + sum >>= 7; + return sum * sum; +} + +static inline int do_filter_1200(struct demod_state_afsk12 *st, unsigned char newval) +{ + int sum; + + datamove8(st->filt.c, newval); + + sum = convolution8(st->filt.c, afsk12_tx_lo_i); + sum += convolution8(st->filt.c, afsk12_tx_lo_q); + sum -= convolution8(st->filt.c, afsk12_tx_hi_i); + sum -= convolution8(st->filt.c, afsk12_tx_hi_q); + return sum; +} + +#endif /* defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */ + + +/* --------------------------------------------------------------------- */ + +static void demodulator_1200(struct sm_state *sm, unsigned char *buf, int buflen) +{ + struct demod_state_afsk12 *st = (struct demod_state_afsk12 *)(&sm->d); + static const int pll_corr[2] = { -0x1000, 0x1000 }; + int j; + int sum; + unsigned char newsample; + ENV_STORAGE; + + ENV_SAVE; + for (; buflen > 0; buflen--, buf++) { + sum = do_filter_1200(st, *buf); + st->dcd_shreg <<= 1; + st->bit_pll += 0x2000; + newsample = (sum > 0); + if (st->last_sample ^ newsample) { + st->last_sample = newsample; + st->dcd_shreg |= 1; + st->bit_pll += pll_corr + [st->bit_pll < 0x9000]; + j = 4 * hweight8(st->dcd_shreg & 0x38) + - hweight16(st->dcd_shreg & 0x7c0); + st->dcd_sum0 += j; + } + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 120; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->shreg >>= 1; + st->shreg |= (!(st->last_rxbit ^ + st->last_sample)) << 16; + st->last_rxbit = st->last_sample; + diag_trigger(sm); + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + } + diag_add(sm, (((int)*buf)-0x80) << 8, sum); + } + ENV_RESTORE; +} + +/* --------------------------------------------------------------------- */ + +static void demod_init_1200(struct sm_state *sm) +{ + struct demod_state_afsk12 *st = (struct demod_state_afsk12 *)(&sm->d); + + st->dcd_time = 120; + st->dcd_sum0 = 2; +} + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_afsk1200_tx = { + "afsk1200", sizeof(struct mod_state_afsk12), + AFSK12_SAMPLE_RATE, 1200, AFSK12_SAMPLE_RATE/1200, modulator_1200, NULL +}; + +const struct modem_rx_info sm_afsk1200_rx = { + "afsk1200", sizeof(struct demod_state_afsk12), + AFSK12_SAMPLE_RATE, 1200, AFSK12_SAMPLE_RATE/1200, + AFSK12_SAMPLE_RATE/1200, demodulator_1200, demod_init_1200 +}; + +/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.26/linux/drivers/net/soundmodem/sm_fsk9600.c linux/drivers/net/soundmodem/sm_fsk9600.c --- v2.1.26/linux/drivers/net/soundmodem/sm_fsk9600.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/soundmodem/sm_fsk9600.c Fri Feb 21 14:58:35 1997 @@ -0,0 +1,239 @@ +/*****************************************************************************/ + +/* + * sm_fsk9600.h -- soundcard radio modem driver, + * 9600 baud G3RUH compatible FSK modem + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + */ + +#include "sm.h" +#include "sm_tbl_fsk9600.h" + +/* --------------------------------------------------------------------- */ + +struct demod_state_fsk96 { + unsigned int shreg; + unsigned long descram; + unsigned int bit_pll; + unsigned char last_sample; + unsigned int dcd_shreg; + int dcd_sum0, dcd_sum1, dcd_sum2; + unsigned int dcd_time; +}; + +struct mod_state_fsk96 { + unsigned int shreg; + unsigned long scram; + unsigned char tx_bit; +}; + +/* --------------------------------------------------------------------- */ + +#define DESCRAM_TAP1 0x20000 +#define DESCRAM_TAP2 0x01000 +#define DESCRAM_TAP3 0x00001 + +#define DESCRAM_TAPSH1 17 +#define DESCRAM_TAPSH2 12 +#define DESCRAM_TAPSH3 0 + +#define SCRAM_TAP1 0x20000 /* X^17 */ +#define SCRAM_TAPN 0x00021 /* X^0+X^5 */ + +/* --------------------------------------------------------------------- */ + +static void modulator_9600_4(struct sm_state *sm, unsigned char *buf, int buflen) +{ + struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m); + int j; + const unsigned char *cp; + + for (; buflen >= 4; buflen -= 4) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->scram = (st->scram << 1) | (st->scram & 1); + st->scram ^= !(st->shreg & 1); + st->shreg >>= 1; + if (st->scram & (SCRAM_TAP1 << 1)) + st->scram ^= SCRAM_TAPN << 1; + st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2))); + cp = fsk96_txfilt_4 + (st->tx_bit & 0xff); + for (j = 0; j < 4; j++, cp += 0x100) + *buf++ = *cp; + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_9600_4(struct sm_state *sm, unsigned char *buf, int buflen) +{ + struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d); + static const int pll_corr[2] = { -0x1000, 0x1000 }; + unsigned char curbit; + unsigned int descx; + + for (; buflen > 0; buflen--, buf++) { + st->dcd_shreg <<= 1; + st->bit_pll += 0x4000; + curbit = (*buf >= 0x80); + if (st->last_sample ^ curbit) { + st->dcd_shreg |= 1; + st->bit_pll += pll_corr[st->bit_pll < 0xa000]; + st->dcd_sum0 += 8 * hweight8(st->dcd_shreg & 0x0c) - + !!(st->dcd_shreg & 0x10); + } + st->last_sample = curbit; + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 240; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->descram = (st->descram << 1) | curbit; + descx = st->descram ^ (st->descram >> 1); + descx ^= ((descx >> DESCRAM_TAPSH1) ^ + (descx >> DESCRAM_TAPSH2)); + st->shreg >>= 1; + st->shreg |= (!(descx & 1)) << 16; + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + diag_trigger(sm); + } + diag_add_one(sm, ((short)(*buf - 0x80)) << 8); + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_9600_5(struct sm_state *sm, unsigned char *buf, int buflen) +{ + struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m); + int j; + const unsigned char *cp; + + for (; buflen >= 5; buflen -= 5) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->scram = (st->scram << 1) | (st->scram & 1); + st->scram ^= !(st->shreg & 1); + st->shreg >>= 1; + if (st->scram & (SCRAM_TAP1 << 1)) + st->scram ^= SCRAM_TAPN << 1; + st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2))); + cp = fsk96_txfilt_5 + (st->tx_bit & 0xff); + for (j = 0; j < 5; j++, cp += 0x100) + *buf++ = *cp; + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_9600_5(struct sm_state *sm, unsigned char *buf, int buflen) +{ + struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d); + static const int pll_corr[2] = { -0x1000, 0x1000 }; + unsigned char curbit; + unsigned int descx; + + for (; buflen > 0; buflen--, buf++) { + st->dcd_shreg <<= 1; + st->bit_pll += 0x3333; + curbit = (*buf >= 0x80); + if (st->last_sample ^ curbit) { + st->dcd_shreg |= 1; + st->bit_pll += pll_corr[st->bit_pll < 0x9999]; + st->dcd_sum0 += 16 * hweight8(st->dcd_shreg & 0x0c) - + hweight8(st->dcd_shreg & 0x70); + } + st->last_sample = curbit; + hdlcdrv_channelbit(&sm->hdrv, st->last_sample); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 240; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->descram = (st->descram << 1) | curbit; + descx = st->descram ^ (st->descram >> 1); + descx ^= ((descx >> DESCRAM_TAPSH1) ^ + (descx >> DESCRAM_TAPSH2)); + st->shreg >>= 1; + st->shreg |= (!(descx & 1)) << 16; + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + diag_trigger(sm); + } + diag_add_one(sm, ((short)(*buf - 0x80)) << 8); + } +} + +/* --------------------------------------------------------------------- */ + +static void demod_init_9600(struct sm_state *sm) +{ + struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d); + + st->dcd_time = 240; + st->dcd_sum0 = 2; +} + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_fsk9600_4_tx = { + "fsk9600", sizeof(struct mod_state_fsk96), 38400, 9600, 4, + modulator_9600_4, NULL +}; + +const struct modem_rx_info sm_fsk9600_4_rx = { + "fsk9600", sizeof(struct demod_state_fsk96), 38400, 9600, 4, 4, + demodulator_9600_4, demod_init_9600 +}; + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_fsk9600_5_tx = { + "fsk9600", sizeof(struct mod_state_fsk96), 48000, 9600, 5, + modulator_9600_5, NULL +}; + +const struct modem_rx_info sm_fsk9600_5_rx = { + "fsk9600", sizeof(struct demod_state_fsk96), 48000, 9600, 5, 5, + demodulator_9600_5, demod_init_9600 +}; + +/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.26/linux/drivers/net/soundmodem/sm_hapn4800.c linux/drivers/net/soundmodem/sm_hapn4800.c --- v2.1.26/linux/drivers/net/soundmodem/sm_hapn4800.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/soundmodem/sm_hapn4800.c Fri Feb 21 14:58:35 1997 @@ -0,0 +1,347 @@ +/*****************************************************************************/ + +/* + * sm_hapn4800.h -- soundcard radio modem driver, 4800 baud HAPN modem + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + * + * This module implements a (hopefully) HAPN (Hamilton Area Packet + * Network) compatible 4800 baud modem. + * The HAPN modem uses kind of "duobinary signalling" (not really, + * duobinary signalling gives ... 0 0 -1 0 1 0 0 ... at the sampling + * instants, whereas HAPN signalling gives ... 0 0 -1 1 0 0 ..., see + * Proakis, Digital Communications). + * The code is untested. It is compatible with itself (i.e. it can decode + * the packets it sent), but I could not test if it is compatible with + * any "real" HAPN modem, since noone uses it in my region of the world. + * Feedback therefore welcome. + */ + +#include "sm.h" +#include "sm_tbl_hapn4800.h" + +/* --------------------------------------------------------------------- */ + +struct demod_state_hapn48 { + unsigned int shreg; + unsigned int bit_pll; + unsigned char last_bit; + unsigned char last_bit2; + unsigned int dcd_shreg; + int dcd_sum0, dcd_sum1, dcd_sum2; + unsigned int dcd_time; + int inphist[5]; + int lvlhi, lvllo; +}; + +struct mod_state_hapn48 { + unsigned int shreg; + unsigned char tx_bit; +}; + +/* --------------------------------------------------------------------- */ + +static void modulator_hapn4800_10(struct sm_state *sm, unsigned char *buf, int buflen) +{ + struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); + int j; + const unsigned char *cp; + + for (; buflen >= 10; buflen -= 10) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = ((st->tx_bit << 1) | + (st->tx_bit & 1)); + st->tx_bit ^= (!(st->shreg & 1)); + st->shreg >>= 1; + cp = hapn48_txfilt_10 + (st->tx_bit & 0xf); + for (j = 0; j < 10; j++, cp += 0x10) + *buf++ = *cp; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_hapn4800_8(struct sm_state *sm, unsigned char *buf, int buflen) +{ + struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); + int j; + const unsigned char *cp; + + for (; buflen >= 8; buflen -= 8) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1); + st->tx_bit ^= !(st->shreg & 1); + st->shreg >>= 1; + cp = hapn48_txfilt_8 + (st->tx_bit & 0xf); + for (j = 0; j < 8; j++, cp += 0x10) + *buf++ = *cp; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_hapn4800_pm10(struct sm_state *sm, unsigned char *buf, int buflen) +{ + struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); + int j; + const unsigned char *cp; + + for (; buflen >= 10; buflen -= 10) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = ((st->tx_bit << 1) | + (st->tx_bit & 1)); + st->tx_bit ^= (!(st->shreg & 1)); + st->shreg >>= 1; + cp = hapn48_txfilt_pm10 + (st->tx_bit & 0xf); + for (j = 0; j < 10; j++, cp += 0x10) + *buf++ = *cp; + } +} + +/* --------------------------------------------------------------------- */ + +static void modulator_hapn4800_pm8(struct sm_state *sm, unsigned char *buf, int buflen) +{ + struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m); + int j; + const unsigned char *cp; + + for (; buflen >= 8; buflen -= 8) { + if (st->shreg <= 1) + st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; + st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1); + st->tx_bit ^= !(st->shreg & 1); + st->shreg >>= 1; + cp = hapn48_txfilt_pm8 + (st->tx_bit & 0xf); + for (j = 0; j < 8; j++, cp += 0x10) + *buf++ = *cp; + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_hapn4800_10(struct sm_state *sm, unsigned char *buf, int buflen) +{ + struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d); + static const int pll_corr[2] = { -0x800, 0x800 }; + int curst, cursync; + + for (; buflen > 0; buflen--, buf++) { + st->inphist[4] = st->inphist[3]; + st->inphist[3] = st->inphist[2]; + st->inphist[2] = st->inphist[1]; + st->inphist[1] = st->inphist[0]; + st->inphist[0] = ((int)(*buf)-0x80) << 8; + st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */ + st->lvllo = (st->lvllo * 65309) >> 16; /* decay */ + if (st->inphist[2] > st->lvlhi) + st->lvlhi = st->inphist[2]; + if (st->inphist[2] < st->lvllo) + st->lvllo = st->inphist[2]; + if (buflen & 1) + st->dcd_shreg <<= 1; + st->bit_pll += 0x199a; + curst = cursync = 0; + if (st->inphist[2] > st->lvlhi >> 1) { + curst = 1; + cursync = (st->inphist[2] > st->inphist[1] && + st->inphist[2] > st->inphist[3] && + st->inphist[2] > st->inphist[0] && + st->inphist[2] > st->inphist[4]); + } else if (st->inphist[2] < st->lvllo >> 1) { + curst = -1; + cursync = (st->inphist[2] < st->inphist[1] && + st->inphist[2] < st->inphist[3] && + st->inphist[2] < st->inphist[0] && + st->inphist[2] < st->inphist[4]); + } + if (cursync) { + st->dcd_shreg |= cursync; + st->bit_pll += pll_corr[((st->bit_pll - 0x8000u) & 0xffffu) < 0x8ccdu]; + st->dcd_sum0 += 16 * hweight32(st->dcd_shreg & 0x18c6318c) - + hweight32(st->dcd_shreg & 0xe739ce70); + } + hdlcdrv_channelbit(&sm->hdrv, cursync); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 240; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->last_bit2 = st->last_bit; + if (curst < 0) + st->last_bit = 0; + else if (curst > 0) + st->last_bit = 1; + st->shreg >>= 1; + st->shreg |= ((st->last_bit ^ st->last_bit2 ^ 1) & 1) << 16; + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + diag_trigger(sm); + } + diag_add_one(sm, st->inphist[2]); + } +} + +/* --------------------------------------------------------------------- */ + +static void demodulator_hapn4800_8(struct sm_state *sm, unsigned char *buf, int buflen) +{ + struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d); + static const int pll_corr[2] = { -0x800, 0x800 }; + int curst, cursync; + + for (; buflen > 0; buflen--, buf++) { + st->inphist[4] = st->inphist[3]; + st->inphist[3] = st->inphist[2]; + st->inphist[2] = st->inphist[1]; + st->inphist[1] = st->inphist[0]; + st->inphist[0] = ((int)(*buf)-0x80) << 8; + st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */ + st->lvllo = (st->lvllo * 65309) >> 16; /* decay */ + if (st->inphist[2] > st->lvlhi) + st->lvlhi = st->inphist[2]; + if (st->inphist[2] < st->lvllo) + st->lvllo = st->inphist[2]; + if (buflen & 1) + st->dcd_shreg <<= 1; + st->bit_pll += 0x2000; + curst = cursync = 0; + if (st->inphist[2] > st->lvlhi >> 1) { + curst = 1; + cursync = (st->inphist[2] > st->inphist[1] && + st->inphist[2] > st->inphist[3] && + st->inphist[2] > st->inphist[0] && + st->inphist[2] > st->inphist[4]); + } else if (st->inphist[2] < st->lvllo >> 1) { + curst = -1; + cursync = (st->inphist[2] < st->inphist[1] && + st->inphist[2] < st->inphist[3] && + st->inphist[2] < st->inphist[0] && + st->inphist[2] < st->inphist[4]); + } + if (cursync) { + st->dcd_shreg |= cursync; + st->bit_pll += pll_corr[((st->bit_pll - 0x8000u) & 0xffffu) < 0x9000u]; + st->dcd_sum0 += 16 * hweight32(st->dcd_shreg & 0x44444444) - + hweight32(st->dcd_shreg & 0xbbbbbbbb); + } + hdlcdrv_channelbit(&sm->hdrv, cursync); + if ((--st->dcd_time) <= 0) { + hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + + st->dcd_sum1 + + st->dcd_sum2) < 0); + st->dcd_sum2 = st->dcd_sum1; + st->dcd_sum1 = st->dcd_sum0; + st->dcd_sum0 = 2; /* slight bias */ + st->dcd_time = 240; + } + if (st->bit_pll >= 0x10000) { + st->bit_pll &= 0xffff; + st->last_bit2 = st->last_bit; + if (curst < 0) + st->last_bit = 0; + else if (curst > 0) + st->last_bit = 1; + st->shreg >>= 1; + st->shreg |= ((st->last_bit ^ st->last_bit2 ^ 1) & 1) << 16; + if (st->shreg & 1) { + hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); + st->shreg = 0x10000; + } + diag_trigger(sm); + } + diag_add_one(sm, st->inphist[2]); + } +} + +/* --------------------------------------------------------------------- */ + +static void demod_init_hapn4800(struct sm_state *sm) +{ + struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d); + + st->dcd_time = 120; + st->dcd_sum0 = 2; +} + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_hapn4800_8_tx = { + "hapn4800", sizeof(struct mod_state_hapn48), + 38400, 4800, 8, modulator_hapn4800_8, NULL +}; + +const struct modem_rx_info sm_hapn4800_8_rx = { + "hapn4800", sizeof(struct demod_state_hapn48), + 38400, 4800, 8, 8, demodulator_hapn4800_8, demod_init_hapn4800 +}; + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_hapn4800_10_tx = { + "hapn4800", sizeof(struct mod_state_hapn48), + 48000, 4800, 10, + modulator_hapn4800_10, NULL +}; + +const struct modem_rx_info sm_hapn4800_10_rx = { + "hapn4800", sizeof(struct demod_state_hapn48), + 48000, 4800, 10, 10, demodulator_hapn4800_10, demod_init_hapn4800 +}; + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_hapn4800_pm8_tx = { + "hapn4800pm", sizeof(struct mod_state_hapn48), + 38400, 4800, 8, modulator_hapn4800_pm8, NULL +}; + +const struct modem_rx_info sm_hapn4800_pm8_rx = { + "hapn4800pm", sizeof(struct demod_state_hapn48), + 38400, 4800, 8, 8, demodulator_hapn4800_8, demod_init_hapn4800 +}; + +/* --------------------------------------------------------------------- */ + +const struct modem_tx_info sm_hapn4800_pm10_tx = { + "hapn4800pm", sizeof(struct mod_state_hapn48), + 48000, 4800, 10, + modulator_hapn4800_pm10, NULL +}; + +const struct modem_rx_info sm_hapn4800_pm10_rx = { + "hapn4800pm", sizeof(struct demod_state_hapn48), + 48000, 4800, 10, 10, demodulator_hapn4800_10, demod_init_hapn4800 +}; + +/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.26/linux/drivers/net/soundmodem/sm_sbc.c linux/drivers/net/soundmodem/sm_sbc.c --- v2.1.26/linux/drivers/net/soundmodem/sm_sbc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/soundmodem/sm_sbc.c Fri Feb 21 14:58:35 1997 @@ -0,0 +1,525 @@ +/*****************************************************************************/ + +/* + * sm_sbc.h -- soundcard radio modem driver soundblaster hardware driver + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + */ + +#include +#include +#include +#include +#include +#include +#include "sm.h" + +/* --------------------------------------------------------------------- */ + +/* + * currently this module is supposed to support both module styles, i.e. + * the old one present up to about 2.1.9, and the new one functioning + * starting with 2.1.21. The reason is I have a kit allowing to compile + * this module also under 2.0.x which was requested by several people. + * This will go in 2.2 + */ +#include + +#if LINUX_VERSION_CODE >= 0x20100 +#include +#else +#include +#include + +#undef put_user +#undef get_user + +#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; }) +#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; }) + +extern inline int copy_from_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_READ, from, n); + if (i) + return i; + memcpy_fromfs(to, from, n); + return 0; +} + +extern inline int copy_to_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_WRITE, to, n); + if (i) + return i; + memcpy_tofs(to, from, n); + return 0; +} +#endif + +/* --------------------------------------------------------------------- */ + +struct sc_state_sbc { + unsigned char revhi, revlo; + unsigned char fmt[2]; + unsigned int dmabuflen; + unsigned char *dmabuf; + unsigned char dmabufidx; + unsigned char ptt; +}; + +#define SCSTATE ((struct sc_state_sbc *)(&sm->hw)) + +/* --------------------------------------------------------------------- */ +/* + * the sbc converter's registers + */ +#define DSP_RESET(iobase) (iobase+0x6) +#define DSP_READ_DATA(iobase) (iobase+0xa) +#define DSP_WRITE_DATA(iobase) (iobase+0xc) +#define DSP_WRITE_STATUS(iobase) (iobase+0xc) +#define DSP_DATA_AVAIL(iobase) (iobase+0xe) +#define DSP_MIXER_ADDR(iobase) (iobase+0x4) +#define DSP_MIXER_DATA(iobase) (iobase+0x5) +#define SBC_EXTENT 16 + +/* --------------------------------------------------------------------- */ +/* + * SBC commands + */ +#define SBC_OUTPUT 0x14 +#define SBC_INPUT 0x24 +#define SBC_BLOCKSIZE 0x48 +#define SBC_HI_OUTPUT 0x91 +#define SBC_HI_INPUT 0x99 +#define SBC_LO_OUTPUT_AUTOINIT 0x1c +#define SBC_LO_INPUT_AUTOINIT 0x2c +#define SBC_HI_OUTPUT_AUTOINIT 0x90 +#define SBC_HI_INPUT_AUTOINIT 0x98 +#define SBC_IMMED_INT 0xf2 +#define SBC_GET_REVISION 0xe1 +#define ESS_GET_REVISION 0xe7 +#define SBC_SPEAKER_ON 0xd1 +#define SBC_SPEAKER_OFF 0xd3 +#define SBC_DMA_ON 0xd0 +#define SBC_DMA_OFF 0xd4 +#define SBC_SAMPLE_RATE 0x40 +#define SBC_MONO_8BIT 0xa0 +#define SBC_MONO_16BIT 0xa4 +#define SBC_STEREO_8BIT 0xa8 +#define SBC_STEREO_16BIT 0xac + +#define SBC4_OUT8_AI 0xc6 +#define SBC4_IN8_AI 0xce +#define SBC4_MODE_UNS_MONO 0x00 + +/* --------------------------------------------------------------------- */ + +static int inline reset_dsp(struct device *dev) +{ + int i; + + outb(1, DSP_RESET(dev->base_addr)); + for (i = 0; i < 0x100; i++) + SLOW_DOWN_IO; + outb(0, DSP_RESET(dev->base_addr)); + for (i = 0; i < 0xffff; i++) + if (inb(DSP_DATA_AVAIL(dev->base_addr)) & 0x80) + if (inb(DSP_READ_DATA(dev->base_addr)) == 0xaa) + return 1; + return 0; +} + +/* --------------------------------------------------------------------- */ + +static void inline write_dsp(struct device *dev, unsigned char data) +{ + int i; + + for (i = 0; i < 0xffff; i++) + if (!(inb(DSP_WRITE_STATUS(dev->base_addr)) & 0x80)) { + outb(data, DSP_WRITE_DATA(dev->base_addr)); + return; + } +} + +/* --------------------------------------------------------------------- */ + +static int inline read_dsp(struct device *dev, unsigned char *data) +{ + int i; + + if (!data) + return 0; + for (i = 0; i < 0xffff; i++) + if (inb(DSP_DATA_AVAIL(dev->base_addr)) & 0x80) { + *data = inb(DSP_READ_DATA(dev->base_addr)); + return 1; + } + return 0; +} + +/* --------------------------------------------------------------------- */ + +static void inline sbc_int_ack(struct device *dev) +{ + inb(DSP_DATA_AVAIL(dev->base_addr)); +} + +/* --------------------------------------------------------------------- */ + +static void setup_dma_dsp(struct device *dev, struct sm_state *sm, int send) +{ + unsigned long flags; + static const unsigned char sbcmode[2][2] = { + { SBC_LO_INPUT_AUTOINIT, SBC_LO_OUTPUT_AUTOINIT }, + { SBC_HI_INPUT_AUTOINIT, SBC_HI_OUTPUT_AUTOINIT } + }; + static const unsigned char sbc4mode[2] = { SBC4_IN8_AI, SBC4_OUT8_AI }; + static const unsigned char dmamode[2] = { + DMA_MODE_READ | DMA_MODE_AUTOINIT, DMA_MODE_WRITE | DMA_MODE_AUTOINIT + }; + static const unsigned char sbcskr[2] = { SBC_SPEAKER_OFF, SBC_SPEAKER_ON }; + unsigned long dmabufaddr = virt_to_bus(SCSTATE->dmabuf); + + send = !!send; + if (!reset_dsp(dev)) { + printk(KERN_ERR "%s: sbc: cannot reset sb dsp\n", sm_drvname); + return; + } + if ((dmabufaddr & 0xffff) + SCSTATE->dmabuflen > 0x10000) + panic("sm: DMA buffer violates DMA boundary!"); + save_flags(flags); + cli(); + sbc_int_ack(dev); + write_dsp(dev, SBC_SAMPLE_RATE); /* set sampling rate */ + write_dsp(dev, SCSTATE->fmt[send]); + write_dsp(dev, sbcskr[send]); + disable_dma(dev->dma); + clear_dma_ff(dev->dma); + set_dma_mode(dev->dma, dmamode[send]); + set_dma_addr(dev->dma, dmabufaddr); + set_dma_count(dev->dma, SCSTATE->dmabuflen); + enable_dma(dev->dma); + sbc_int_ack(dev); + if (SCSTATE->revhi >= 4) { + write_dsp(dev, sbc4mode[send]); + write_dsp(dev, SBC4_MODE_UNS_MONO); + write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); + write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); + } else { + write_dsp(dev, SBC_BLOCKSIZE); + write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); + write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); + write_dsp(dev, sbcmode[SCSTATE->fmt[send] >= 180][send]); + /* hispeed mode if sample rate > 13kHz */ + } + restore_flags(flags); +} + +/* --------------------------------------------------------------------- */ + +static void sbc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *)dev_id; + struct sm_state *sm = (struct sm_state *)dev->priv; + unsigned char new_ptt; + unsigned char *buf; + + if (!dev || !sm || sm->hdrv.magic != HDLCDRV_MAGIC) + return; + new_ptt = hdlcdrv_ptt(&sm->hdrv); + sbc_int_ack(dev); + buf = SCSTATE->dmabuf; + if (SCSTATE->dmabufidx) + buf += SCSTATE->dmabuflen/2; + SCSTATE->dmabufidx = !SCSTATE->dmabufidx; + sm_int_freq(sm); + sti(); + if (new_ptt && !SCSTATE->ptt) { + /* starting to transmit */ + disable_dma(dev->dma); + SCSTATE->dmabufidx = 0; + time_exec(sm->debug_vals.demod_cyc, + sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2)); + time_exec(sm->debug_vals.mod_cyc, + sm->mode_tx->modulator(sm, SCSTATE->dmabuf, + SCSTATE->dmabuflen/2)); + setup_dma_dsp(dev, sm, 1); + time_exec(sm->debug_vals.mod_cyc, + sm->mode_tx->modulator(sm, SCSTATE->dmabuf + + SCSTATE->dmabuflen/2, + SCSTATE->dmabuflen/2)); + } else if (SCSTATE->ptt == 1 && !new_ptt) { + /* stopping transmission */ + disable_dma(dev->dma); + SCSTATE->dmabufidx = 0; + setup_dma_dsp(dev, sm, 0); + SCSTATE->ptt = 0; + } else if (SCSTATE->ptt) { + SCSTATE->ptt--; + time_exec(sm->debug_vals.mod_cyc, + sm->mode_tx->modulator(sm, buf, SCSTATE->dmabuflen/2)); + } else { + time_exec(sm->debug_vals.demod_cyc, + sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2)); + hdlcdrv_arbitrate(dev, &sm->hdrv); + } + if (new_ptt) + SCSTATE->ptt = 2; + sm_output_status(sm); + hdlcdrv_transmitter(dev, &sm->hdrv); + hdlcdrv_receiver(dev, &sm->hdrv); +} + +/* --------------------------------------------------------------------- */ + +static int sbc_open(struct device *dev, struct sm_state *sm) +{ + if (sizeof(sm->m) < sizeof(struct sc_state_sbc)) { + printk(KERN_ERR "sm sbc: sbc state too big: %d > %d\n", + sizeof(struct sc_state_sbc), sizeof(sm->m)); + return -ENODEV; + } + if (!dev || !sm) + return -ENXIO; + if (dev->base_addr <= 0 || dev->base_addr > 0x1000-SBC_EXTENT || + dev->irq < 2 || dev->irq > 15 || dev->dma > 3) + return -ENXIO; + if (check_region(dev->base_addr, SBC_EXTENT)) + return -EACCES; + /* + * check if a card is available + */ + if (!reset_dsp(dev)) + return -ENODEV; + write_dsp(dev, SBC_GET_REVISION); + if (!read_dsp(dev, &SCSTATE->revhi) || + !read_dsp(dev, &SCSTATE->revlo)) + return -ENODEV; + if (SCSTATE->revhi < 2) { + printk(KERN_ERR "%s: your card is an antiquity, at least DSP " + "rev 2.00 required\n", sm_drvname); + return -ENODEV; + } + if (SCSTATE->revhi < 3 && + (SCSTATE->fmt[0] >= 180 || SCSTATE->fmt[1] >= 180)) { + printk(KERN_ERR "%s: sbc io 0x%lx: DSP rev %d.%02d too " + "old, at least 3.00 required\n", sm_drvname, + dev->base_addr, SCSTATE->revhi, SCSTATE->revlo); + return -ENODEV; + } + /* + * initialize some variables + */ + if (!(SCSTATE->dmabuf = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA))) + return -ENOMEM; + SCSTATE->dmabufidx = SCSTATE->ptt = 0; + + memset(&sm->m, 0, sizeof(sm->m)); + memset(&sm->d, 0, sizeof(sm->d)); + if (sm->mode_tx->init) + sm->mode_tx->init(sm); + if (sm->mode_rx->init) + sm->mode_rx->init(sm); + + if (request_dma(dev->dma, sm->hwdrv->hw_name)) { + kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + return -EBUSY; + } + if (request_irq(dev->irq, sbc_interrupt, SA_INTERRUPT, + sm->hwdrv->hw_name, dev)) { + free_dma(dev->dma); + kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + return -EBUSY; + } + request_region(dev->base_addr, SBC_EXTENT, sm->hwdrv->hw_name); + setup_dma_dsp(dev, sm, 0); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int sbc_close(struct device *dev, struct sm_state *sm) +{ + if (!dev || !sm) + return -EINVAL; + /* + * disable interrupts + */ + disable_dma(dev->dma); + reset_dsp(dev); + free_irq(dev->irq, dev); + free_dma(dev->dma); + release_region(dev->base_addr, SBC_EXTENT); + kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int sbc_sethw(struct device *dev, struct sm_state *sm, char *mode) +{ + char *cp = strchr(mode, '.'); + const struct modem_tx_info **mtp = sm_modem_tx_table; + const struct modem_rx_info **mrp; + int dv; + + if (!strcmp(mode, "off")) { + sm->mode_tx = NULL; + sm->mode_rx = NULL; + return 0; + } + if (cp) + *cp++ = '\0'; + else + cp = mode; + for (; *mtp; mtp++) { + if ((*mtp)->loc_storage > sizeof(sm->m)) { + printk(KERN_ERR "%s: insufficient storage for modulator %s (%d)\n", + sm_drvname, (*mtp)->name, (*mtp)->loc_storage); + continue; + } + if (!(*mtp)->name || strcmp((*mtp)->name, mode)) + continue; + if ((*mtp)->srate < 5000 || (*mtp)->srate > 44100) + continue; + for (mrp = sm_modem_rx_table; *mrp; mrp++) { + if ((*mrp)->loc_storage > sizeof(sm->d)) { + printk(KERN_ERR "%s: insufficient storage for demodulator %s (%d)\n", + sm_drvname, (*mrp)->name, (*mrp)->loc_storage); + continue; + } + if ((*mrp)->name && !strcmp((*mrp)->name, cp) && + (*mrp)->srate >= 5000 && (*mrp)->srate <= 44100) { + sm->mode_tx = *mtp; + sm->mode_rx = *mrp; + SCSTATE->fmt[0] = 256-((1000000L+sm->mode_rx->srate/2)/ + sm->mode_rx->srate); + SCSTATE->fmt[1] = 256-((1000000L+sm->mode_tx->srate/2)/ + sm->mode_tx->srate); + dv = lcm(sm->mode_tx->dmabuflenmodulo, + sm->mode_rx->dmabuflenmodulo); + SCSTATE->dmabuflen = sm->mode_rx->srate/100+dv-1; + SCSTATE->dmabuflen /= dv; + SCSTATE->dmabuflen *= 2*dv; /* make sure DMA buf is even */ + return 0; + } + } + } + return -EINVAL; +} + +/* --------------------------------------------------------------------- */ + +static int sbc_ioctl(struct device *dev, struct sm_state *sm, struct ifreq *ifr, + struct hdlcdrv_ioctl *hi, int cmd) +{ + struct sm_ioctl bi; + unsigned long flags; + int i; + + if (cmd != SIOCDEVPRIVATE) + return -ENOIOCTLCMD; + + if (hi->cmd == HDLCDRVCTL_MODEMPARMASK) + return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ | + HDLCDRV_PARMASK_DMA | HDLCDRV_PARMASK_SERIOBASE | + HDLCDRV_PARMASK_PARIOBASE | HDLCDRV_PARMASK_MIDIIOBASE; + + if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) + return -EFAULT; + + switch (bi.cmd) { + default: + return -ENOIOCTLCMD; + + case SMCTL_GETMIXER: + i = 0; + bi.data.mix.sample_rate = sm->mode_rx->srate; + bi.data.mix.bit_rate = sm->hdrv.par.bitrate; + switch (SCSTATE->revhi) { + case 2: + bi.data.mix.mixer_type = SM_MIXER_CT1335; + break; + case 3: + bi.data.mix.mixer_type = SM_MIXER_CT1345; + break; + case 4: + bi.data.mix.mixer_type = SM_MIXER_CT1745; + break; + } + if (bi.data.mix.mixer_type != SM_MIXER_INVALID && + bi.data.mix.reg < 0x80) { + save_flags(flags); + cli(); + outb(bi.data.mix.reg, DSP_MIXER_ADDR(dev->base_addr)); + bi.data.mix.data = inb(DSP_MIXER_DATA(dev->base_addr)); + restore_flags(flags); + i = 1; + } + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return i; + + case SMCTL_SETMIXER: + if (!suser()) + return -EACCES; + switch (SCSTATE->revhi) { + case 2: + if (bi.data.mix.mixer_type != SM_MIXER_CT1335) + return -EINVAL; + break; + case 3: + if (bi.data.mix.mixer_type != SM_MIXER_CT1345) + return -EINVAL; + break; + case 4: + if (bi.data.mix.mixer_type != SM_MIXER_CT1745) + return -EINVAL; + break; + default: + return -ENODEV; + } + if (bi.data.mix.reg >= 0x80) + return -EACCES; + save_flags(flags); + cli(); + outb(bi.data.mix.reg, DSP_MIXER_ADDR(dev->base_addr)); + outb(bi.data.mix.data, DSP_MIXER_DATA(dev->base_addr)); + restore_flags(flags); + return 0; + + } + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return 0; + +} + +/* --------------------------------------------------------------------- */ + +const struct hardware_info sm_hw_sbc = { + "sbc", sizeof(struct sc_state_sbc), + sbc_open, sbc_close, sbc_ioctl, sbc_sethw +}; + +/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.26/linux/drivers/net/soundmodem/sm_wss.c linux/drivers/net/soundmodem/sm_wss.c --- v2.1.26/linux/drivers/net/soundmodem/sm_wss.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/soundmodem/sm_wss.c Fri Feb 21 14:58:35 1997 @@ -0,0 +1,948 @@ +/*****************************************************************************/ + +/* + * sm_wss.c -- soundcard radio modem driver, WSS (half duplex) driver + * + * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + */ + +#include +#include +#include +#include +#include +#include +#include "sm.h" + +/* --------------------------------------------------------------------- */ + +/* + * currently this module is supposed to support both module styles, i.e. + * the old one present up to about 2.1.9, and the new one functioning + * starting with 2.1.21. The reason is I have a kit allowing to compile + * this module also under 2.0.x which was requested by several people. + * This will go in 2.2 + */ +#include + +#if LINUX_VERSION_CODE >= 0x20100 +#include +#else +#include +#include + +#undef put_user +#undef get_user + +#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; }) +#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; }) + +extern inline int copy_from_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_READ, from, n); + if (i) + return i; + memcpy_fromfs(to, from, n); + return 0; +} + +extern inline int copy_to_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_WRITE, to, n); + if (i) + return i; + memcpy_tofs(to, from, n); + return 0; +} +#endif + +/* --------------------------------------------------------------------- */ + +struct sc_state_wss { + unsigned char revwss, revid, revv, revcid; + unsigned char fmt[2]; + unsigned char crystal; + unsigned int dmabuflen; + unsigned char *dmabuf; + unsigned char dmabufidx; + unsigned char ptt; + /* Full Duplex extensions */ + unsigned char *dmabuf2; +}; + +#define SCSTATE ((struct sc_state_wss *)(&sm->hw)) + +/* --------------------------------------------------------------------- */ + +#define WSS_CONFIG(iobase) (iobase+0) +#define WSS_STATUS(iobase) (iobase+3) +#define WSS_CODEC_IA(iobase) (iobase+4) +#define WSS_CODEC_ID(iobase) (iobase+5) +#define WSS_CODEC_STATUS(iobase) (iobase+6) +#define WSS_CODEC_DATA(iobase) (iobase+7) + +#define WSS_EXTENT 8 + +/* --------------------------------------------------------------------- */ + +static void write_codec(struct device *dev, unsigned char idx, + unsigned char data) +{ + int timeout = 900000; + + /* wait until codec ready */ + while (timeout > 0 && inb(WSS_CODEC_IA(dev->base_addr)) & 0x80) + timeout--; + outb(idx, WSS_CODEC_IA(dev->base_addr)); + outb(data, WSS_CODEC_ID(dev->base_addr)); +} + + +/* --------------------------------------------------------------------- */ + +static unsigned char read_codec(struct device *dev, unsigned char idx) +{ + int timeout = 900000; + + /* wait until codec ready */ + while (timeout > 0 && inb(WSS_CODEC_IA(dev->base_addr)) & 0x80) + timeout--; + outb(idx & 0x1f, WSS_CODEC_IA(dev->base_addr)); + return inb(WSS_CODEC_ID(dev->base_addr)); +} + +/* --------------------------------------------------------------------- */ + +extern void inline wss_ack_int(struct device *dev) +{ + outb(0, WSS_CODEC_STATUS(dev->base_addr)); +} + +/* --------------------------------------------------------------------- */ + +static int wss_srate_tab[16] = { + 8000, 5510, 16000, 11025, 27420, 18900, 32000, 22050, + -1, 37800, -1, 44100, 48000, 33075, 9600, 6620 +}; + +static int wss_srate_index(int srate) +{ + int i; + + for (i = 0; i < (sizeof(wss_srate_tab)/sizeof(wss_srate_tab[0])); i++) + if (srate == wss_srate_tab[i] && wss_srate_tab[i] > 0) + return i; + return -1; +} + +/* --------------------------------------------------------------------- */ + +static int wss_set_codec_fmt(struct device *dev, struct sm_state *sm, + unsigned char fmt, char fdx, char fullcalib) +{ + unsigned long time; + unsigned long flags; + + save_flags(flags); + cli(); + /* Clock and data format register */ + write_codec(dev, 0x48, fmt); + if (SCSTATE->crystal) { + write_codec(dev, 0x5c, fmt & 0xf0); + /* MCE and interface config reg */ + write_codec(dev, 0x49, (fdx ? 0 : 0x4) | (fullcalib ? 0x18 : 0)); + } else + /* MCE and interface config reg */ + write_codec(dev, 0x49, fdx ? 0x8 : 0xc); + outb(0xb, WSS_CODEC_IA(dev->base_addr)); /* leave MCE */ + /* + * wait for ACI start + */ + time = 1000; + while (!(read_codec(dev, 0x0b) & 0x20)) + if (!(--time)) { + printk(KERN_WARNING "%s: ad1848 auto calibration timed out (1)\n", + sm_drvname); + restore_flags(flags); + return -1; + } + /* + * wait for ACI end + */ + sti(); + time = jiffies + HZ/4; + while ((read_codec(dev, 0x0b) & 0x20) && ((signed)(jiffies - time) < 0)); + restore_flags(flags); + if ((signed)(jiffies - time) >= 0) { + printk(KERN_WARNING "%s: ad1848 auto calibration timed out (2)\n", + sm_drvname); + return -1; + } + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int wss_init_codec(struct device *dev, struct sm_state *sm, char fdx, + unsigned char src_l, unsigned char src_r, + int igain_l, int igain_r, + int ogain_l, int ogain_r) +{ + unsigned char tmp, reg0, reg1, reg6, reg7; + static const signed char irqtab[16] = + { -1, -1, 0x10, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20, -1, -1, + -1, -1 }; + static const signed char dmatab[4] = { 1, 2, -1, 3 }; + + tmp = inb(WSS_STATUS(dev->base_addr)); + if ((tmp & 0x3f) != 0x04 && (tmp & 0x3f) != 0x00 && + (tmp & 0x3f) != 0x0f) { + printk(KERN_WARNING "sm: WSS card id register not found, " + "address 0x%lx, ID register 0x%02x\n", + dev->base_addr, (int)tmp); + /* return -1; */ + SCSTATE->revwss = 0; + } else { + if ((tmp & 0x80) && ((dev->dma == 0) || + ((dev->irq >= 8) && (dev->irq != 9)))) { + printk(KERN_ERR "%s: WSS: DMA0 and/or IRQ8..IRQ15 " + "(except IRQ9) cannot be used on an 8bit " + "card\n", sm_drvname); + return -1; + } + if (dev->irq > 15 || irqtab[dev->irq] == -1) { + printk(KERN_ERR "%s: WSS: invalid interrupt %d\n", + sm_drvname, (int)dev->irq); + return -1; + } + if (dev->dma > 3 || dmatab[dev->dma] == -1) { + printk(KERN_ERR "%s: WSS: invalid dma channel %d\n", + sm_drvname, (int)dev->dma); + return -1; + } + tmp = irqtab[dev->irq] | dmatab[dev->dma]; + /* irq probe */ + outb((tmp & 0x38) | 0x40, WSS_CONFIG(dev->base_addr)); + if (!(inb(WSS_STATUS(dev->base_addr)) & 0x40)) { + outb(0, WSS_CONFIG(dev->base_addr)); + printk(KERN_ERR "%s: WSS: IRQ%d is not free!\n", + sm_drvname, dev->irq); + } + outb(tmp, WSS_CONFIG(dev->base_addr)); + SCSTATE->revwss = inb(WSS_STATUS(dev->base_addr)) & 0x3f; + } + /* + * initialize the codec + */ + if (igain_l < 0) + igain_l = 0; + if (igain_r < 0) + igain_r = 0; + if (ogain_l > 0) + ogain_l = 0; + if (ogain_r > 0) + ogain_r = 0; + reg0 = (src_l << 6) & 0xc0; + reg1 = (src_r << 6) & 0xc0; + if (reg0 == 0x80 && igain_l >= 20) { + reg0 |= 0x20; + igain_l -= 20; + } + if (reg1 == 0x80 && igain_r >= 20) { + reg1 |= 0x20; + igain_r -= 20; + } + if (igain_l > 23) + igain_l = 23; + if (igain_r > 23) + igain_r = 23; + reg0 |= igain_l * 2 / 3; + reg1 |= igain_r * 2 / 3; + reg6 = (ogain_l < -95) ? 0x80 : (ogain_l * (-2) / 3); + reg7 = (ogain_r < -95) ? 0x80 : (ogain_r * (-2) / 3); + write_codec(dev, 9, 0); + write_codec(dev, 0, 0x45); + if (read_codec(dev, 0) != 0x45) + goto codec_err; + write_codec(dev, 0, 0xaa); + if (read_codec(dev, 0) != 0xaa) + goto codec_err; + write_codec(dev, 12, 0x40); /* enable MODE2 */ + write_codec(dev, 16, 0); + write_codec(dev, 0, 0x45); + SCSTATE->crystal = (read_codec(dev, 16) != 0x45); + write_codec(dev, 0, 0xaa); + SCSTATE->crystal &= (read_codec(dev, 16) != 0xaa); + if (SCSTATE->crystal) { + SCSTATE->revcid = read_codec(dev, 0x19); + SCSTATE->revv = (SCSTATE->revcid >> 5) & 7; + SCSTATE->revcid &= 7; + write_codec(dev, 0x10, 0x80); /* maximum output level */ + write_codec(dev, 0x11, 0x02); /* xtal enable and no HPF */ + write_codec(dev, 0x12, 0x80); /* left line input control */ + write_codec(dev, 0x13, 0x80); /* right line input control */ + write_codec(dev, 0x16, 0); /* disable alternative freq sel */ + write_codec(dev, 0x1a, 0xe0); /* mono IO disable */ + write_codec(dev, 0x1b, 0x00); /* left out no att */ + write_codec(dev, 0x1d, 0x00); /* right out no att */ + } + + if (wss_set_codec_fmt(dev, sm, SCSTATE->fmt[0], fdx, 1)) + goto codec_err; + + write_codec(dev, 0, reg0); /* left input control */ + write_codec(dev, 1, reg1); /* right input control */ + write_codec(dev, 2, 0x80); /* left aux#1 input control */ + write_codec(dev, 3, 0x80); /* right aux#1 input control */ + write_codec(dev, 4, 0x80); /* left aux#2 input control */ + write_codec(dev, 5, 0x80); /* right aux#2 input control */ + write_codec(dev, 6, reg6); /* left dac control */ + write_codec(dev, 7, reg7); /* right dac control */ + write_codec(dev, 0xa, 0x2); /* pin control register */ + write_codec(dev, 0xd, 0x0); /* digital mix control */ + SCSTATE->revid = read_codec(dev, 0xc) & 0xf; + /* + * print revisions + */ + if (SCSTATE->crystal) + printk(KERN_INFO "%s: Crystal CODEC ID %d, Chip revision %d, " + " Chip ID %d\n", sm_drvname, (int)SCSTATE->revid, + (int)SCSTATE->revv, (int)SCSTATE->revcid); + else + printk(KERN_INFO "%s: WSS revision %d, CODEC revision %d\n", + sm_drvname, (int)SCSTATE->revwss, + (int)SCSTATE->revid); + return 0; + codec_err: + outb(0, WSS_CONFIG(dev->base_addr)); + printk(KERN_ERR "%s: no WSS soundcard found at address 0x%lx\n", + sm_drvname, dev->base_addr); + return -1; +} + +/* --------------------------------------------------------------------- */ + +static void setup_dma_wss(struct device *dev, struct sm_state *sm, int send) +{ + unsigned long flags; + static const unsigned char codecmode[2] = { 0x0e, 0x0d }; + static const unsigned char dmamode[2] = { + DMA_MODE_READ | DMA_MODE_AUTOINIT, + DMA_MODE_WRITE | DMA_MODE_AUTOINIT + }; + unsigned char oldcodecmode; + long abrt; + unsigned long dmabufaddr = virt_to_bus(SCSTATE->dmabuf); + + if ((dmabufaddr & 0xffffu) + SCSTATE->dmabuflen > 0x10000) + panic("%s: DMA buffer violates DMA boundary!", sm_drvname); + send = !!send; + save_flags(flags); + cli(); + /* + * perform the final DMA sequence to disable the codec request + */ + oldcodecmode = read_codec(dev, 9); + write_codec(dev, 9, 0xc); /* disable codec */ + wss_ack_int(dev); + if (read_codec(dev, 11) & 0x10) { + disable_dma(dev->dma); + clear_dma_ff(dev->dma); + set_dma_mode(dev->dma, dmamode[oldcodecmode & 1]); + set_dma_addr(dev->dma, dmabufaddr); + set_dma_count(dev->dma, SCSTATE->dmabuflen); + enable_dma(dev->dma); + abrt = 0; + while ((read_codec(dev, 11) & 0x10) || ((++abrt) >= 0x10000)); + } + disable_dma(dev->dma); + if (read_codec(dev, 0x8) != SCSTATE->fmt[send]) + wss_set_codec_fmt(dev, sm, SCSTATE->fmt[send], 0, 0); + clear_dma_ff(dev->dma); + set_dma_mode(dev->dma, dmamode[send]); + set_dma_addr(dev->dma, dmabufaddr); + set_dma_count(dev->dma, SCSTATE->dmabuflen); + enable_dma(dev->dma); + write_codec(dev, 15, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); + write_codec(dev, 14, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); + if (SCSTATE->crystal) { + write_codec(dev, 31, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); + write_codec(dev, 30, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); + } + write_codec(dev, 9, codecmode[send]); + restore_flags(flags); +} + +/* --------------------------------------------------------------------- */ + +static void wss_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *)dev_id; + struct sm_state *sm = (struct sm_state *)dev->priv; + unsigned char new_ptt; + unsigned char *buf; + int dmares; + + if (!dev || !sm || !sm->mode_rx || !sm->mode_tx || + sm->hdrv.magic != HDLCDRV_MAGIC) + return; + new_ptt = hdlcdrv_ptt(&sm->hdrv); + cli(); + wss_ack_int(dev); + disable_dma(dev->dma); + clear_dma_ff(dev->dma); + dmares = get_dma_residue(dev->dma); + if (dmares <= 0) + dmares = SCSTATE->dmabuflen; + buf = SCSTATE->dmabuf; + if (dmares > SCSTATE->dmabuflen/2) { + buf += SCSTATE->dmabuflen/2; + dmares -= SCSTATE->dmabuflen/2; + } +#ifdef SM_DEBUG + if (!sm->debug_vals.dma_residue || + dmares < sm->debug_vals.dma_residue) + sm->debug_vals.dma_residue = dmares; +#endif /* SM_DEBUG */ + dmares--; + write_codec(dev, 15, dmares & 0xff); + write_codec(dev, 14, dmares >> 8); + if (SCSTATE->crystal) { + write_codec(dev, 31, dmares & 0xff); + write_codec(dev, 30, dmares >> 8); + } + enable_dma(dev->dma); + sm_int_freq(sm); + sti(); + if (new_ptt && !SCSTATE->ptt) { + /* starting to transmit */ + disable_dma(dev->dma); + sti(); + SCSTATE->dmabufidx = 0; + time_exec(sm->debug_vals.demod_cyc, + sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2)); + time_exec(sm->debug_vals.mod_cyc, + sm->mode_tx->modulator(sm, SCSTATE->dmabuf, + SCSTATE->dmabuflen/2)); + setup_dma_wss(dev, sm, 1); + time_exec(sm->debug_vals.mod_cyc, + sm->mode_tx->modulator(sm, SCSTATE->dmabuf + + SCSTATE->dmabuflen/2, + SCSTATE->dmabuflen/2)); + } else if (SCSTATE->ptt == 1 && !new_ptt) { + /* stopping transmission */ + disable_dma(dev->dma); + sti(); + SCSTATE->dmabufidx = 0; + setup_dma_wss(dev, sm, 0); + SCSTATE->ptt = 0; + } else if (SCSTATE->ptt) { + SCSTATE->ptt--; + time_exec(sm->debug_vals.mod_cyc, + sm->mode_tx->modulator(sm, buf, SCSTATE->dmabuflen/2)); + } else { + time_exec(sm->debug_vals.demod_cyc, + sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2)); + hdlcdrv_arbitrate(dev, &sm->hdrv); + } + if (new_ptt) + SCSTATE->ptt = 2; + sm_output_status(sm); + hdlcdrv_transmitter(dev, &sm->hdrv); + hdlcdrv_receiver(dev, &sm->hdrv); +} + +/* --------------------------------------------------------------------- */ + +static int wss_open(struct device *dev, struct sm_state *sm) +{ + if (sizeof(sm->m) < sizeof(struct sc_state_wss)) { + printk(KERN_ERR "sm wss: wss state too big: %d > %d\n", + sizeof(struct sc_state_wss), sizeof(sm->m)); + return -ENODEV; + } + if (!dev || !sm || !sm->mode_rx || !sm->mode_tx) + return -ENXIO; + if (dev->base_addr <= 0 || dev->base_addr > 0x1000-WSS_EXTENT || + dev->irq < 2 || dev->irq > 15 || dev->dma > 3) + return -ENXIO; + if (check_region(dev->base_addr, WSS_EXTENT)) + return -EACCES; + /* + * check if a card is available + */ + if (wss_init_codec(dev, sm, 0, 1, 1, 0, 0, -45, -45)) + return -ENODEV; + /* + * initialize some variables + */ + if (!(SCSTATE->dmabuf = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA))) + return -ENOMEM; + SCSTATE->dmabufidx = SCSTATE->ptt = 0; + + memset(&sm->m, 0, sizeof(sm->m)); + memset(&sm->d, 0, sizeof(sm->d)); + if (sm->mode_tx->init) + sm->mode_tx->init(sm); + if (sm->mode_rx->init) + sm->mode_rx->init(sm); + + if (request_dma(dev->dma, sm->hwdrv->hw_name)) { + kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + return -EBUSY; + } + if (request_irq(dev->irq, wss_interrupt, SA_INTERRUPT, + sm->hwdrv->hw_name, dev)) { + free_dma(dev->dma); + kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + return -EBUSY; + } + request_region(dev->base_addr, WSS_EXTENT, sm->hwdrv->hw_name); + setup_dma_wss(dev, sm, 0); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int wss_close(struct device *dev, struct sm_state *sm) +{ + if (!dev || !sm) + return -EINVAL; + /* + * disable interrupts + */ + disable_dma(dev->dma); + write_codec(dev, 9, 0xc); /* disable codec */ + free_irq(dev->irq, dev); + free_dma(dev->dma); + release_region(dev->base_addr, WSS_EXTENT); + kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int wss_sethw(struct device *dev, struct sm_state *sm, char *mode) +{ + char *cp = strchr(mode, '.'); + const struct modem_tx_info **mtp = sm_modem_tx_table; + const struct modem_rx_info **mrp; + int i, j, dv; + + if (!strcmp(mode, "off")) { + sm->mode_tx = NULL; + sm->mode_rx = NULL; + return 0; + } + if (cp) + *cp++ = '\0'; + else + cp = mode; + for (; *mtp; mtp++) { + if ((*mtp)->loc_storage > sizeof(sm->m)) { + printk(KERN_ERR "%s: insufficient storage for modulator %s (%d)\n", + sm_drvname, (*mtp)->name, (*mtp)->loc_storage); + continue; + } + if (!(*mtp)->name || strcmp((*mtp)->name, mode)) + continue; + if ((i = wss_srate_index((*mtp)->srate)) < 0) + continue; + for (mrp = sm_modem_rx_table; *mrp; mrp++) { + if ((*mrp)->loc_storage > sizeof(sm->d)) { + printk(KERN_ERR "%s: insufficient storage for demodulator %s (%d)\n", + sm_drvname, (*mrp)->name, (*mrp)->loc_storage); + continue; + } + if ((*mrp)->name && !strcmp((*mrp)->name, cp) && + ((j = wss_srate_index((*mrp)->srate)) >= 0)) { + sm->mode_tx = *mtp; + sm->mode_rx = *mrp; + SCSTATE->fmt[0] = j; + SCSTATE->fmt[1] = i; + dv = lcm(sm->mode_tx->dmabuflenmodulo, + sm->mode_rx->dmabuflenmodulo); + SCSTATE->dmabuflen = sm->mode_rx->srate/100+dv-1; + SCSTATE->dmabuflen /= dv; + SCSTATE->dmabuflen *= 2*dv; /* make sure DMA buf is even */ + return 0; + } + } + } + return -EINVAL; +} + +/* --------------------------------------------------------------------- */ + +static int wss_ioctl(struct device *dev, struct sm_state *sm, struct ifreq *ifr, + struct hdlcdrv_ioctl *hi, int cmd) +{ + struct sm_ioctl bi; + int i; + + if (cmd != SIOCDEVPRIVATE) + return -ENOIOCTLCMD; + + if (hi->cmd == HDLCDRVCTL_MODEMPARMASK) + return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ | + HDLCDRV_PARMASK_DMA | HDLCDRV_PARMASK_SERIOBASE | + HDLCDRV_PARMASK_PARIOBASE | HDLCDRV_PARMASK_MIDIIOBASE; + + if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) + return -EFAULT; + + switch (bi.cmd) { + default: + return -ENOIOCTLCMD; + + case SMCTL_GETMIXER: + i = 0; + bi.data.mix.sample_rate = sm->mode_rx->srate; + bi.data.mix.bit_rate = sm->hdrv.par.bitrate; + bi.data.mix.mixer_type = SCSTATE->crystal ? + SM_MIXER_CRYSTAL : SM_MIXER_AD1848; + if (((SCSTATE->crystal ? 0x2c0c20fflu: 0x20fflu) + >> bi.data.mix.reg) & 1) { + bi.data.mix.data = read_codec(dev, bi.data.mix.reg); + i = 1; + } + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return i; + + case SMCTL_SETMIXER: + if (!suser()) + return -EACCES; + if ((bi.data.mix.mixer_type != SM_MIXER_CRYSTAL || + !SCSTATE->crystal) && + (bi.data.mix.mixer_type != SM_MIXER_AD1848 || + bi.data.mix.reg >= 0x10)) + return -EINVAL; + if (!((0x2c0c20fflu >> bi.data.mix.reg) & 1)) + return -EACCES; + write_codec(dev, bi.data.mix.reg, bi.data.mix.data); + return 0; + + } + if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) + return -EFAULT; + return 0; + +} + +/* --------------------------------------------------------------------- */ + +const struct hardware_info sm_hw_wss = { + "wss", sizeof(struct sc_state_wss), + wss_open, wss_close, wss_ioctl, wss_sethw +}; + +/* --------------------------------------------------------------------- */ + +static void setup_fdx_dma_wss(struct device *dev, struct sm_state *sm) +{ + unsigned long flags; + unsigned char oldcodecmode, codecdma; + long abrt; + unsigned long dmabufaddr1 = virt_to_bus(SCSTATE->dmabuf); + unsigned long dmabufaddr2 = virt_to_bus(SCSTATE->dmabuf2); + + if (((dmabufaddr1 & 0xffffu) + SCSTATE->dmabuflen > 0x10000) || + ((dmabufaddr2 & 0xffffu) + SCSTATE->dmabuflen > 0x10000)) + panic("%s: DMA buffer violates DMA boundary!", sm_drvname); + save_flags(flags); + cli(); + /* + * perform the final DMA sequence to disable the codec request + */ + oldcodecmode = read_codec(dev, 9); + write_codec(dev, 9, 0); /* disable codec DMA */ + wss_ack_int(dev); + if ((codecdma = read_codec(dev, 11)) & 0x10) { + disable_dma(dev->dma); + disable_dma(sm->hdrv.ptt_out.dma2); + clear_dma_ff(dev->dma); + set_dma_mode(dev->dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT); + set_dma_addr(dev->dma, dmabufaddr1); + set_dma_count(dev->dma, SCSTATE->dmabuflen); + clear_dma_ff(sm->hdrv.ptt_out.dma2); + set_dma_mode(sm->hdrv.ptt_out.dma2, DMA_MODE_READ | DMA_MODE_AUTOINIT); + set_dma_addr(sm->hdrv.ptt_out.dma2, dmabufaddr2); + set_dma_count(sm->hdrv.ptt_out.dma2, SCSTATE->dmabuflen); + enable_dma(dev->dma); + enable_dma(sm->hdrv.ptt_out.dma2); + abrt = 0; + while (((codecdma = read_codec(dev, 11)) & 0x10) || + ((++abrt) >= 0x10000)); + } + disable_dma(dev->dma); + disable_dma(sm->hdrv.ptt_out.dma2); + clear_dma_ff(dev->dma); + set_dma_mode(dev->dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT); + set_dma_addr(dev->dma, dmabufaddr1); + set_dma_count(dev->dma, SCSTATE->dmabuflen); + clear_dma_ff(sm->hdrv.ptt_out.dma2); + set_dma_mode(sm->hdrv.ptt_out.dma2, DMA_MODE_READ | DMA_MODE_AUTOINIT); + set_dma_addr(sm->hdrv.ptt_out.dma2, dmabufaddr2); + set_dma_count(sm->hdrv.ptt_out.dma2, SCSTATE->dmabuflen); + enable_dma(dev->dma); + enable_dma(sm->hdrv.ptt_out.dma2); + write_codec(dev, 15, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); + write_codec(dev, 14, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); + if (SCSTATE->crystal) { + write_codec(dev, 31, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); + write_codec(dev, 30, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); + } + write_codec(dev, 9, 3); + restore_flags(flags); +} + +/* --------------------------------------------------------------------- */ + +static void wssfdx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *)dev_id; + struct sm_state *sm = (struct sm_state *)dev->priv; + unsigned char *buf1; + unsigned char *buf2; + unsigned long flags; + int dmares1, dmares2; + + if (!dev || !sm || !sm->mode_rx || !sm->mode_tx || + sm->hdrv.magic != HDLCDRV_MAGIC) + return; + save_flags(flags); + cli(); + if (SCSTATE->crystal && (!(read_codec(dev, 0x18) & 0x20))) { + /* only regard Crystal Playback interrupts! */ + wss_ack_int(dev); + return; + } + wss_ack_int(dev); + disable_dma(dev->dma); + disable_dma(sm->hdrv.ptt_out.dma2); + clear_dma_ff(dev->dma); + dmares1 = get_dma_residue(dev->dma); + clear_dma_ff(sm->hdrv.ptt_out.dma2); + dmares2 = get_dma_residue(sm->hdrv.ptt_out.dma2); + if (dmares1 <= 0) + dmares1 = SCSTATE->dmabuflen; + buf1 = SCSTATE->dmabuf; + if (dmares1 > SCSTATE->dmabuflen/2) { + buf1 += SCSTATE->dmabuflen/2; + dmares1 -= SCSTATE->dmabuflen/2; + } + if (dmares2 <= 0) + dmares2 = SCSTATE->dmabuflen; + buf2 = SCSTATE->dmabuf2; + if (dmares2 > SCSTATE->dmabuflen/2) { + buf2 += SCSTATE->dmabuflen/2; + dmares2 -= SCSTATE->dmabuflen/2; + } +#ifdef SM_DEBUG + if (!sm->debug_vals.dma_residue || + dmares1 < sm->debug_vals.dma_residue) + sm->debug_vals.dma_residue = dmares1; +#endif /* SM_DEBUG */ + dmares1--; + dmares2--; + write_codec(dev, 15, dmares1 & 0xff); + write_codec(dev, 14, dmares1 >> 8); + if (SCSTATE->crystal) { + write_codec(dev, 31, dmares2 & 0xff); + write_codec(dev, 30, dmares2 >> 8); + } + enable_dma(dev->dma); + enable_dma(sm->hdrv.ptt_out.dma2); + restore_flags(flags); + sm_int_freq(sm); + sti(); + if ((SCSTATE->ptt = hdlcdrv_ptt(&sm->hdrv))) + time_exec(sm->debug_vals.mod_cyc, + sm->mode_tx->modulator(sm, buf1, SCSTATE->dmabuflen/2)); + else + time_exec(sm->debug_vals.mod_cyc, + memset(buf1, 0x80, SCSTATE->dmabuflen/2)); + time_exec(sm->debug_vals.demod_cyc, + sm->mode_rx->demodulator(sm, buf2, SCSTATE->dmabuflen/2)); + hdlcdrv_arbitrate(dev, &sm->hdrv); + sm_output_status(sm); + hdlcdrv_transmitter(dev, &sm->hdrv); + hdlcdrv_receiver(dev, &sm->hdrv); +} + +/* --------------------------------------------------------------------- */ + +static int wssfdx_open(struct device *dev, struct sm_state *sm) +{ + if (!dev || !sm || !sm->mode_rx || !sm->mode_tx) + return -ENXIO; + if (dev->base_addr <= 0 || dev->base_addr > 0x1000-WSS_EXTENT || + dev->irq < 2 || dev->irq > 15 || dev->dma > 3) + return -ENXIO; + if (check_region(dev->base_addr, WSS_EXTENT)) + return -EACCES; + /* + * check if a card is available + */ + if (wss_init_codec(dev, sm, 1, 1, 1, 0, 0, -45, -45)) + return -ENODEV; + /* + * initialize some variables + */ + if (!(SCSTATE->dmabuf = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA))) + return -ENOMEM; + if (!(SCSTATE->dmabuf2 = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA))) { + kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + return -ENOMEM; + } + SCSTATE->dmabufidx = SCSTATE->ptt = 0; + + memset(&sm->m, 0, sizeof(sm->m)); + memset(&sm->d, 0, sizeof(sm->d)); + if (sm->mode_tx->init) + sm->mode_tx->init(sm); + if (sm->mode_rx->init) + sm->mode_rx->init(sm); + + if (request_dma(dev->dma, sm->hwdrv->hw_name)) { + kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen); + return -EBUSY; + } + if (request_dma(sm->hdrv.ptt_out.dma2, sm->hwdrv->hw_name)) { + kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen); + free_dma(dev->dma); + return -EBUSY; + } + if (request_irq(dev->irq, wssfdx_interrupt, SA_INTERRUPT, + sm->hwdrv->hw_name, dev)) { + kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen); + free_dma(dev->dma); + free_dma(sm->hdrv.ptt_out.dma2); + return -EBUSY; + } + request_region(dev->base_addr, WSS_EXTENT, sm->hwdrv->hw_name); + setup_fdx_dma_wss(dev, sm); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int wssfdx_close(struct device *dev, struct sm_state *sm) +{ + if (!dev || !sm) + return -EINVAL; + /* + * disable interrupts + */ + disable_dma(dev->dma); + write_codec(dev, 9, 0xc); /* disable codec */ + free_irq(dev->irq, dev); + free_dma(dev->dma); + free_dma(sm->hdrv.ptt_out.dma2); + release_region(dev->base_addr, WSS_EXTENT); + kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int wssfdx_sethw(struct device *dev, struct sm_state *sm, char *mode) +{ + char *cp = strchr(mode, '.'); + const struct modem_tx_info **mtp = sm_modem_tx_table; + const struct modem_rx_info **mrp; + int i, dv; + + if (!strcmp(mode, "off")) { + sm->mode_tx = NULL; + sm->mode_rx = NULL; + return 0; + } + if (cp) + *cp++ = '\0'; + else + cp = mode; + for (; *mtp; mtp++) { + if ((*mtp)->loc_storage > sizeof(sm->m)) { + printk(KERN_ERR "%s: insufficient storage for modulator %s (%d)\n", + sm_drvname, (*mtp)->name, (*mtp)->loc_storage); + continue; + } + if (!(*mtp)->name || strcmp((*mtp)->name, mode)) + continue; + if ((i = wss_srate_index((*mtp)->srate)) < 0) + continue; + for (mrp = sm_modem_rx_table; *mrp; mrp++) { + if ((*mrp)->loc_storage > sizeof(sm->d)) { + printk(KERN_ERR "%s: insufficient storage for demodulator %s (%d)\n", + sm_drvname, (*mrp)->name, (*mrp)->loc_storage); + continue; + } + if ((*mrp)->name && !strcmp((*mrp)->name, cp) && + (*mtp)->srate == (*mrp)->srate) { + sm->mode_tx = *mtp; + sm->mode_rx = *mrp; + SCSTATE->fmt[0] = SCSTATE->fmt[1] = i; + dv = lcm(sm->mode_tx->dmabuflenmodulo, + sm->mode_rx->dmabuflenmodulo); + SCSTATE->dmabuflen = sm->mode_rx->srate/100+dv-1; + SCSTATE->dmabuflen /= dv; + SCSTATE->dmabuflen *= 2*dv; /* make sure DMA buf is even */ + return 0; + } + } + } + return -EINVAL; +} + +/* --------------------------------------------------------------------- */ + +static int wssfdx_ioctl(struct device *dev, struct sm_state *sm, struct ifreq *ifr, + struct hdlcdrv_ioctl *hi, int cmd) +{ + if (cmd != SIOCDEVPRIVATE) + return -ENOIOCTLCMD; + + if (hi->cmd == HDLCDRVCTL_MODEMPARMASK) + return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ | + HDLCDRV_PARMASK_DMA | HDLCDRV_PARMASK_DMA2 | + HDLCDRV_PARMASK_SERIOBASE | HDLCDRV_PARMASK_PARIOBASE | + HDLCDRV_PARMASK_MIDIIOBASE; + + return wss_ioctl(dev, sm, ifr, hi, cmd); +} + +/* --------------------------------------------------------------------- */ + +const struct hardware_info sm_hw_wssfdx = { + "wssfdx", sizeof(struct sc_state_wss), + wssfdx_open, wssfdx_close, wssfdx_ioctl, wssfdx_sethw +}; + +/* --------------------------------------------------------------------- */ + +#undef SCSTATE diff -u --recursive --new-file v2.1.26/linux/drivers/net/soundmodem.c linux/drivers/net/soundmodem.c --- v2.1.26/linux/drivers/net/soundmodem.c Tue Dec 31 00:30:04 1996 +++ linux/drivers/net/soundmodem.c Wed Dec 31 16:00:00 1969 @@ -1,1022 +0,0 @@ -/*****************************************************************************/ - -/* - * soundmodem.c -- soundcard radio modem driver. - * - * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Please note that the GPL allows you to use the driver, NOT the radio. - * In order to use the radio, you need a license from the communications - * authority of your country. - * - * - * Command line options (insmod command line) - * - * hardware hardware type; 0=sbc, 1=wss, any other value invalid - * mode mode type; 0=1200 baud AFSK, 1=9600 baud FSK, any other - * value invalid - * iobase base address of the soundcard; common values are 0x220 for sbc, - * 0x530 for wss - * irq interrupt number; common values are 7 or 5 for sbc, 11 for wss - * dma dma number; common values are 0 or 1 - * - * - * History: - * 0.1 21.09.96 Started - * 18.10.96 Changed to new user space access routines (copy_{to,from}_user) - */ - -/*****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* --------------------------------------------------------------------- */ - -static const char sm_drvname[] = "soundmodem"; -static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996 Thomas Sailer, HB9JNX/AE4WA\n" -KERN_INFO "soundmodem: version 0.3 compiled " __TIME__ " " __DATE__ "\n"; ; - -/* --------------------------------------------------------------------- */ - -#define NR_PORTS 4 - -#define SM_DEBUG - -/* --------------------------------------------------------------------- */ - -static struct device sm_device[NR_PORTS]; - -static struct { - char *mode; - int iobase, irq, dma, dma2, seriobase, pariobase, midiiobase; -} sm_ports[NR_PORTS] = { - { NULL, -1, 0, 0, 0, -1, -1, -1 }, -}; - -/* --------------------------------------------------------------------- */ - -#define DMA_MODE_AUTOINIT 0x10 - -/* --------------------------------------------------------------------- */ - -#define UART_RBR(iobase) (iobase+0) -#define UART_THR(iobase) (iobase+0) -#define UART_IER(iobase) (iobase+1) -#define UART_IIR(iobase) (iobase+2) -#define UART_FCR(iobase) (iobase+2) -#define UART_LCR(iobase) (iobase+3) -#define UART_MCR(iobase) (iobase+4) -#define UART_LSR(iobase) (iobase+5) -#define UART_MSR(iobase) (iobase+6) -#define UART_SCR(iobase) (iobase+7) -#define UART_DLL(iobase) (iobase+0) -#define UART_DLM(iobase) (iobase+1) - -#define SER_EXTENT 8 - -#define LPT_DATA(iobase) (iobase+0) -#define LPT_STATUS(iobase) (iobase+1) -#define LPT_CONTROL(iobase) (iobase+2) -#define LPT_IRQ_ENABLE 0x10 - -#define LPT_EXTENT 3 - -#define MIDI_DATA(iobase) (iobase) -#define MIDI_STATUS(iobase) (iobase+1) -#define MIDI_READ_FULL 0x80 /* attention: negative logic!! */ -#define MIDI_WRITE_EMPTY 0x40 /* attention: negative logic!! */ - -#define MIDI_EXTENT 2 - -/* ---------------------------------------------------------------------- */ - -#define PARAM_TXDELAY 1 -#define PARAM_PERSIST 2 -#define PARAM_SLOTTIME 3 -#define PARAM_TXTAIL 4 -#define PARAM_FULLDUP 5 -#define PARAM_HARDWARE 6 -#define PARAM_RETURN 255 - -#define SP_SER 1 -#define SP_PAR 2 -#define SP_MIDI 4 - -/* ---------------------------------------------------------------------- */ -/* - * Information that need to be kept for each board. - */ - -struct sm_state { - struct hdlcdrv_state hdrv; - - const struct modem_tx_info *mode_tx; - const struct modem_rx_info *mode_rx; - - const struct hardware_info *hwdrv; - - /* - * Hardware (soundcard) access routines state - */ - union { - long hw[32/sizeof(long)]; - } hw; - - /* - * state of the modem code - */ - union { - long m[32/sizeof(long)]; - } m; - union { - long d[256/sizeof(long)]; - } d; - -#define DIAGDATALEN 64 - struct diag_data { - unsigned int mode; - unsigned int flags; - volatile int ptr; - short data[DIAGDATALEN]; - } diag; - - -#ifdef SM_DEBUG - struct debug_vals { - unsigned long last_jiffies; - unsigned cur_intcnt; - unsigned last_intcnt; - unsigned mod_cyc; - unsigned demod_cyc; - unsigned dma_residue; - } debug_vals; -#endif /* SM_DEBUG */ -}; - -/* ---------------------------------------------------------------------- */ -/* - * Mode definition structure - */ - -struct modem_tx_info { - const struct modem_tx_info *next; - const char *name; - unsigned int loc_storage; - int srate; - int bitrate; - unsigned int dmabuflenmodulo; - void (*modulator)(struct sm_state *, unsigned char *, int); - void (*init)(struct sm_state *); -}; -#define NEXT_TX_INFO NULL - -extern const struct modem_tx_info *modem_tx_base; - -struct modem_rx_info { - const struct modem_rx_info *next; - const char *name; - unsigned int loc_storage; - int srate; - int bitrate; - unsigned int dmabuflenmodulo; - unsigned int sperbit; - void (*demodulator)(struct sm_state *, unsigned char *, int); - void (*init)(struct sm_state *); -}; -#define NEXT_RX_INFO NULL - -extern const struct modem_rx_info *modem_rx_base; - -/* ---------------------------------------------------------------------- */ -/* - * Soundcard driver definition structure - */ - -struct hardware_info { - const struct hardware_info *next; - char *hw_name; /* used for request_{region,irq,dma} */ - unsigned int loc_storage; - /* - * mode specific open/close - */ - int (*open)(struct device *, struct sm_state *); - int (*close)(struct device *, struct sm_state *); - int (*ioctl)(struct device *, struct sm_state *, struct ifreq *, - struct hdlcdrv_ioctl *, int); - int (*sethw)(struct device *, struct sm_state *, char *); -}; -#define NEXT_HW_INFO NULL - -extern const struct hardware_info *hardware_base; - -/* --------------------------------------------------------------------- */ - -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#define max(a, b) (((a) > (b)) ? (a) : (b)) - -/* --------------------------------------------------------------------- */ - -static void inline sm_int_freq(struct sm_state *sm) -{ -#ifdef SM_DEBUG - unsigned long cur_jiffies = jiffies; - /* - * measure the interrupt frequency - */ - sm->debug_vals.cur_intcnt++; - if ((cur_jiffies - sm->debug_vals.last_jiffies) >= HZ) { - sm->debug_vals.last_jiffies = cur_jiffies; - sm->debug_vals.last_intcnt = sm->debug_vals.cur_intcnt; - sm->debug_vals.cur_intcnt = 0; - } -#endif /* SM_DEBUG */ -} - -/* --------------------------------------------------------------------- */ -/* - * ===================== port checking routines ======================== - */ - -static int check_lpt(unsigned int iobase) -{ - unsigned char b1,b2; - int i; - - if (iobase <= 0 || iobase > 0x1000-LPT_EXTENT) - return 0; - if (check_region(iobase, LPT_EXTENT)) - return 0; - b1 = inb(LPT_DATA(iobase)); - b2 = inb(LPT_CONTROL(iobase)); - outb(0xaa, LPT_DATA(iobase)); - i = inb(LPT_DATA(iobase)) == 0xaa; - outb(0x55, LPT_DATA(iobase)); - i &= inb(LPT_DATA(iobase)) == 0x55; - outb(0x0a, LPT_CONTROL(iobase)); - i &= (inb(LPT_CONTROL(iobase)) & 0xf) == 0x0a; - outb(0x05, LPT_CONTROL(iobase)); - i &= (inb(LPT_CONTROL(iobase)) & 0xf) == 0x05; - outb(b1, LPT_DATA(iobase)); - outb(b2, LPT_CONTROL(iobase)); - return !i; -} - -/* --------------------------------------------------------------------- */ - -enum uart { c_uart_unknown, c_uart_8250, - c_uart_16450, c_uart_16550, c_uart_16550A}; -static const char *uart_str[] = - { "unknown", "8250", "16450", "16550", "16550A" }; - -static enum uart check_uart(unsigned int iobase) -{ - unsigned char b1,b2,b3; - enum uart u; - enum uart uart_tab[] = - { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A }; - - if (iobase <= 0 || iobase > 0x1000-SER_EXTENT) - return c_uart_unknown; - if (check_region(iobase, SER_EXTENT)) - return c_uart_unknown; - b1 = inb(UART_MCR(iobase)); - outb(b1 | 0x10, UART_MCR(iobase)); /* loopback mode */ - b2 = inb(UART_MSR(iobase)); - outb(0x1a, UART_MCR(iobase)); - b3 = inb(UART_MSR(iobase)) & 0xf0; - outb(b1, UART_MCR(iobase)); /* restore old values */ - outb(b2, UART_MSR(iobase)); - if (b3 != 0x90) - return c_uart_unknown; - inb(UART_RBR(iobase)); - inb(UART_RBR(iobase)); - outb(0x01, UART_FCR(iobase)); /* enable FIFOs */ - u = uart_tab[(inb(UART_IIR(iobase)) >> 6) & 3]; - if (u == c_uart_16450) { - outb(0x5a, UART_SCR(iobase)); - b1 = inb(UART_SCR(iobase)); - outb(0xa5, UART_SCR(iobase)); - b2 = inb(UART_SCR(iobase)); - if ((b1 != 0x5a) || (b2 != 0xa5)) - u = c_uart_8250; - } - return u; -} - -/* --------------------------------------------------------------------- */ - -static int check_midi(unsigned int iobase) -{ - unsigned long timeout; - unsigned long flags; - unsigned char b; - - if (iobase <= 0 || iobase > 0x1000-MIDI_EXTENT) - return 0; - if (check_region(iobase, MIDI_EXTENT)) - return 0; - timeout = jiffies + (HZ / 100); - while (inb(MIDI_STATUS(iobase)) & MIDI_WRITE_EMPTY) - if ((signed)(jiffies - timeout) > 0) - return 0; - save_flags(flags); - cli(); - outb(0xff, MIDI_DATA(iobase)); - b = inb(MIDI_STATUS(iobase)); - restore_flags(flags); - if (!(b & MIDI_WRITE_EMPTY)) - return 0; - while (inb(MIDI_STATUS(iobase)) & MIDI_WRITE_EMPTY) - if ((signed)(jiffies - timeout) > 0) - return 0; - return 1; -} - -/* --------------------------------------------------------------------- */ - -extern void inline output_status(struct sm_state *sm) -{ - int invert_dcd = 0; - int invert_ptt = 0; - - int ptt = hdlcdrv_ptt(&sm->hdrv) ^ invert_ptt; - int dcd = (!!sm->hdrv.hdlcrx.dcd) ^ invert_dcd; - - if (sm->hdrv.ptt_out.flags & SP_SER) { - outb(dcd | (ptt << 1), UART_MCR(sm->hdrv.ptt_out.seriobase)); - outb(0x40 & (-ptt), UART_LCR(sm->hdrv.ptt_out.seriobase)); - } - if (sm->hdrv.ptt_out.flags & SP_PAR) { - outb(ptt | (dcd << 1), LPT_DATA(sm->hdrv.ptt_out.pariobase)); - } - if (sm->hdrv.ptt_out.flags & SP_MIDI && hdlcdrv_ptt(&sm->hdrv)) { - outb(0, MIDI_DATA(sm->hdrv.ptt_out.midiiobase)); - } -} - -/* --------------------------------------------------------------------- */ - -static void output_open(struct sm_state *sm) -{ - enum uart u = c_uart_unknown; - - sm->hdrv.ptt_out.flags = 0; - if (sm->hdrv.ptt_out.seriobase > 0 && - sm->hdrv.ptt_out.seriobase <= 0x1000-SER_EXTENT && - ((u = check_uart(sm->hdrv.ptt_out.seriobase))) != c_uart_unknown) { - sm->hdrv.ptt_out.flags |= SP_SER; - request_region(sm->hdrv.ptt_out.seriobase, SER_EXTENT, "sm ser ptt"); - outb(0, UART_IER(sm->hdrv.ptt_out.seriobase)); - /* 5 bits, 1 stop, no parity, no break, Div latch access */ - outb(0x80, UART_LCR(sm->hdrv.ptt_out.seriobase)); - outb(0, UART_DLM(sm->hdrv.ptt_out.seriobase)); - outb(1, UART_DLL(sm->hdrv.ptt_out.seriobase)); /* as fast as possible */ - /* LCR and MCR set by output_status */ - } - if (sm->hdrv.ptt_out.pariobase > 0 && - sm->hdrv.ptt_out.pariobase <= 0x1000-LPT_EXTENT && - check_lpt(sm->hdrv.ptt_out.pariobase)) { - sm->hdrv.ptt_out.flags |= SP_PAR; - request_region(sm->hdrv.ptt_out.pariobase, LPT_EXTENT, "sm par ptt"); - } - if (sm->hdrv.ptt_out.midiiobase > 0 && - sm->hdrv.ptt_out.midiiobase <= 0x1000-MIDI_EXTENT && - check_midi(sm->hdrv.ptt_out.midiiobase)) { - sm->hdrv.ptt_out.flags |= SP_MIDI; - request_region(sm->hdrv.ptt_out.midiiobase, MIDI_EXTENT, - "sm midi ptt"); - } - output_status(sm); - - printk(KERN_INFO "%s: ptt output:", sm_drvname); - if (sm->hdrv.ptt_out.flags & SP_SER) - printk(" serial interface at 0x%x, uart %s", sm->hdrv.ptt_out.seriobase, - uart_str[u]); - if (sm->hdrv.ptt_out.flags & SP_PAR) - printk(" parallel interface at 0x%x", sm->hdrv.ptt_out.pariobase); - if (sm->hdrv.ptt_out.flags & SP_MIDI) - printk(" mpu401 (midi) interface at 0x%x", sm->hdrv.ptt_out.midiiobase); - if (!sm->hdrv.ptt_out.flags) - printk(" none"); - printk("\n"); -} - -/* --------------------------------------------------------------------- */ - -static void output_close(struct sm_state *sm) -{ - /* release regions used for PTT output */ - sm->hdrv.hdlctx.ptt = sm->hdrv.hdlctx.calibrate = 0; - output_status(sm); - if (sm->hdrv.ptt_out.flags & SP_SER) - release_region(sm->hdrv.ptt_out.seriobase, SER_EXTENT); - if (sm->hdrv.ptt_out.flags & SP_PAR) - release_region(sm->hdrv.ptt_out.pariobase, LPT_EXTENT); - if (sm->hdrv.ptt_out.flags & SP_MIDI) - release_region(sm->hdrv.ptt_out.midiiobase, MIDI_EXTENT); - sm->hdrv.ptt_out.flags = 0; -} - -/* --------------------------------------------------------------------- */ -/* - * ===================== diagnostics stuff =============================== - */ - -extern inline void diag_trigger(struct sm_state *sm) -{ - if (sm->diag.ptr < 0) - if (!(sm->diag.flags & SM_DIAGFLAG_DCDGATE) || sm->hdrv.hdlcrx.dcd) - sm->diag.ptr = 0; -} - -/* --------------------------------------------------------------------- */ - -extern inline void diag_add(struct sm_state *sm, int valinp, int valdemod) -{ - int val; - - if ((sm->diag.mode != SM_DIAGMODE_INPUT && - sm->diag.mode != SM_DIAGMODE_DEMOD) || - sm->diag.ptr >= DIAGDATALEN || sm->diag.ptr < 0) - return; - val = (sm->diag.mode == SM_DIAGMODE_DEMOD) ? valdemod : valinp; - /* clip */ - if (val > SHRT_MAX) - val = SHRT_MAX; - if (val < SHRT_MIN) - val = SHRT_MIN; - sm->diag.data[sm->diag.ptr++] = val; -} - -/* --------------------------------------------------------------------- */ - -extern inline void diag_add_one(struct sm_state *sm, int val) -{ - if ((sm->diag.mode != SM_DIAGMODE_INPUT && - sm->diag.mode != SM_DIAGMODE_DEMOD) || - sm->diag.ptr >= DIAGDATALEN || sm->diag.ptr < 0) - return; - /* clip */ - if (val > SHRT_MAX) - val = SHRT_MAX; - if (val < SHRT_MIN) - val = SHRT_MIN; - sm->diag.data[sm->diag.ptr++] = val; -} - -/* --------------------------------------------------------------------- */ - -static inline void diag_add_constellation(struct sm_state *sm, int vali, int valq) -{ - if ((sm->diag.mode != SM_DIAGMODE_CONSTELLATION) || - sm->diag.ptr >= DIAGDATALEN-1 || sm->diag.ptr < 0) - return; - /* clip */ - if (vali > SHRT_MAX) - vali = SHRT_MAX; - if (vali < SHRT_MIN) - vali = SHRT_MIN; - if (valq > SHRT_MAX) - valq = SHRT_MAX; - if (valq < SHRT_MIN) - valq = SHRT_MIN; - sm->diag.data[sm->diag.ptr++] = vali; - sm->diag.data[sm->diag.ptr++] = valq; -} - -/* --------------------------------------------------------------------- */ -/* - * ===================== utility functions =============================== - */ - -extern inline unsigned int hweight32(unsigned int w) - __attribute__ ((unused)); -extern inline unsigned int hweight16(unsigned short w) - __attribute__ ((unused)); -extern inline unsigned int hweight8(unsigned char w) - __attribute__ ((unused)); - -extern inline unsigned int hweight32(unsigned int w) -{ - unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); - res = (res & 0x33333333) + ((res >> 2) & 0x33333333); - res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); - res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); - return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); -} - -extern inline unsigned int hweight16(unsigned short w) -{ - unsigned short res = (w & 0x5555) + ((w >> 1) & 0x5555); - res = (res & 0x3333) + ((res >> 2) & 0x3333); - res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F); - return (res & 0x00FF) + ((res >> 8) & 0x00FF); -} - -extern inline unsigned int hweight8(unsigned char w) -{ - unsigned short res = (w & 0x55) + ((w >> 1) & 0x55); - res = (res & 0x33) + ((res >> 2) & 0x33); - return (res & 0x0F) + ((res >> 4) & 0x0F); -} - -extern inline unsigned int gcd(unsigned int x, unsigned int y) - __attribute__ ((unused)); -extern inline unsigned int lcm(unsigned int x, unsigned int y) - __attribute__ ((unused)); - -extern inline unsigned int gcd(unsigned int x, unsigned int y) -{ - for (;;) { - if (!x) - return y; - if (!y) - return x; - if (x > y) - x %= y; - else - y %= x; - } -} - -extern inline unsigned int lcm(unsigned int x, unsigned int y) -{ - return x * y / gcd(x, y); -} - -/* --------------------------------------------------------------------- */ -/* - * ===================== profiling ======================================= - */ - - -#if defined(SM_DEBUG) && (defined(CONFIG_M586) || defined(CONFIG_M686)) - -/* - * only do 32bit cycle counter arithmetic; we hope we won't overflow :-) - * in fact, overflowing modems would require over 2THz clock speeds :-) - */ - -#define time_exec(var,cmd) \ -({ \ - unsigned int cnt1, cnt2, cnt3; \ - __asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt3)); \ - cmd; \ - __asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt3)); \ - var = cnt2-cnt1; \ -}) -#else /* defined(SM_DEBUG) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */ - -#define time_exec(var,cmd) cmd - -#endif /* defined(SM_DEBUG) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */ - -/* --------------------------------------------------------------------- */ - -#ifdef CONFIG_SOUNDMODEM_WSS -#include "sm_wss.h" -#endif /* CONFIG_SOUNDMODEM_WSS */ -#ifdef CONFIG_SOUNDMODEM_SBC -#include "sm_sbc.h" -#endif /* CONFIG_SOUNDMODEM_SBC */ - -#ifdef CONFIG_SOUNDMODEM_AFSK1200 -#include "sm_afsk1200.h" -#endif /* CONFIG_SOUNDMODEM_AFSK1200 */ -#ifdef CONFIG_SOUNDMODEM_FSK9600 -#include "sm_fsk9600.h" -#endif /* CONFIG_SOUNDMODEM_FSK9600 */ -#ifdef CONFIG_SOUNDMODEM_AFSK2666 -#include "sm_afsk2666.h" -#endif /* CONFIG_SOUNDMODEM_AFSK2666 */ -#ifdef CONFIG_SOUNDMODEM_PSK4800 -#include "sm_psk4800.h" -#endif /* CONFIG_SOUNDMODEM_PSK4800 */ - -/* --------------------------------------------------------------------- */ - -static int sm_open(struct device *dev); -static int sm_close(struct device *dev); -static int sm_ioctl(struct device *dev, struct ifreq *ifr, - struct hdlcdrv_ioctl *hi, int cmd); - -/* --------------------------------------------------------------------- */ - -const struct modem_tx_info *modem_tx_base = NEXT_TX_INFO; -const struct modem_rx_info *modem_rx_base = NEXT_RX_INFO; -const struct hardware_info *hardware_base = NEXT_HW_INFO; - -static const struct hdlcdrv_ops sm_ops = { - sm_drvname, sm_drvinfo, sm_open, sm_close, sm_ioctl -}; - -/* --------------------------------------------------------------------- */ - -static int sm_open(struct device *dev) -{ - struct sm_state *sm; - int err; - - if (!dev || !dev->priv || - ((struct sm_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { - printk(KERN_ERR "sm_open: invalid device struct\n"); - return -EINVAL; - } - sm = (struct sm_state *)dev->priv; - - if (!sm->mode_tx || !sm->mode_rx || !sm->hwdrv || !sm->hwdrv->open) - return -ENODEV; - sm->hdrv.par.bitrate = sm->mode_rx->bitrate; - err = sm->hwdrv->open(dev, sm); - if (err) - return err; - output_open(sm); - MOD_INC_USE_COUNT; - printk(KERN_INFO "%s: %s mode %s.%s at iobase 0x%lx irq %u dma %u\n", - sm_drvname, sm->hwdrv->hw_name, sm->mode_tx->name, - sm->mode_rx->name, dev->base_addr, dev->irq, dev->dma); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static int sm_close(struct device *dev) -{ - struct sm_state *sm; - int err = -ENODEV; - - if (!dev || !dev->priv || - ((struct sm_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { - printk(KERN_ERR "sm_close: invalid device struct\n"); - return -EINVAL; - } - sm = (struct sm_state *)dev->priv; - - - if (sm->hwdrv && sm->hwdrv->close) - err = sm->hwdrv && sm->hwdrv->close(dev, sm); - output_close(sm); - MOD_DEC_USE_COUNT; - printk(KERN_INFO "%s: close %s at iobase 0x%lx irq %u dma %u\n", - sm_drvname, sm->hwdrv->hw_name, dev->base_addr, dev->irq, dev->dma); - return err; -} - -/* --------------------------------------------------------------------- */ - -static int sethw(struct device *dev, struct sm_state *sm, char *mode) -{ - char *cp = strchr(mode, ':'); - const struct hardware_info *hwp = hardware_base; - - if (!cp) - cp = mode; - else { - *cp++ = '\0'; - while (hwp && hwp->hw_name && strcmp(hwp->hw_name, mode)) - hwp = hwp->next; - if (!hwp || !hwp->hw_name) - return -EINVAL; - if (hwp->loc_storage > sizeof(sm->hw)) { - printk(KERN_ERR "%s: insufficient storage for hw driver %s (%d)\n", - sm_drvname, hwp->hw_name, hwp->loc_storage); - return -EINVAL; - } - sm->hwdrv = hwp; - } - if (!*cp) - return 0; - if (sm->hwdrv && sm->hwdrv->sethw) - return sm->hwdrv->sethw(dev, sm, cp); - return -EINVAL; -} - -/* --------------------------------------------------------------------- */ - -static int sm_ioctl(struct device *dev, struct ifreq *ifr, - struct hdlcdrv_ioctl *hi, int cmd) -{ - struct sm_state *sm; - struct sm_ioctl bi; - unsigned long flags; - unsigned int newdiagmode; - unsigned int newdiagflags; - char *cp; - const struct modem_tx_info *mtp = modem_tx_base; - const struct modem_rx_info *mrp = modem_rx_base; - const struct hardware_info *hwp = hardware_base; - - if (!dev || !dev->priv || - ((struct sm_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) { - printk(KERN_ERR "sm_ioctl: invalid device struct\n"); - return -EINVAL; - } - sm = (struct sm_state *)dev->priv; - - if (cmd != SIOCDEVPRIVATE) { - if (!sm->hwdrv || !sm->hwdrv->ioctl) - return sm->hwdrv->ioctl(dev, sm, ifr, hi, cmd); - return -ENOIOCTLCMD; - } - switch (hi->cmd) { - default: - if (sm->hwdrv && sm->hwdrv->ioctl) - return sm->hwdrv->ioctl(dev, sm, ifr, hi, cmd); - return -ENOIOCTLCMD; - - case HDLCDRVCTL_GETMODE: - cp = hi->data.modename; - if (sm->hwdrv && sm->hwdrv->hw_name) - cp += sprintf(cp, "%s:", sm->hwdrv->hw_name); - else - cp += sprintf(cp, ":"); - if (sm->mode_tx && sm->mode_tx->name) - cp += sprintf(cp, "%s", sm->mode_tx->name); - else - cp += sprintf(cp, ""); - if (!sm->mode_rx || !sm->mode_rx || - strcmp(sm->mode_rx->name, sm->mode_tx->name)) { - if (sm->mode_rx && sm->mode_rx->name) - cp += sprintf(cp, ",%s", sm->mode_rx->name); - else - cp += sprintf(cp, ","); - } - if (copy_to_user(ifr->ifr_data, hi, sizeof(*hi))) - return -EFAULT; - return 0; - - case HDLCDRVCTL_SETMODE: - if (!suser() || dev->start) - return -EACCES; - hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; - return sethw(dev, sm, hi->data.modename); - - case HDLCDRVCTL_MODELIST: - cp = hi->data.modename; - while (hwp) { - if (hwp->hw_name) - cp += sprintf("%s:,", hwp->hw_name); - hwp = hwp->next; - } - while (mtp) { - if (mtp->name) - cp += sprintf(">%s,", mtp->name); - mtp = mtp->next; - } - while (mrp) { - if (mrp->name) - cp += sprintf("<%s,", mrp->name); - mrp = mrp->next; - } - cp[-1] = '\0'; - if (copy_to_user(ifr->ifr_data, hi, sizeof(*hi))) - return -EFAULT; - return 0; - -#ifdef SM_DEBUG - case SMCTL_GETDEBUG: - if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) - return -EFAULT; - bi.data.dbg.int_rate = sm->debug_vals.last_intcnt; - bi.data.dbg.mod_cycles = sm->debug_vals.mod_cyc; - bi.data.dbg.demod_cycles = sm->debug_vals.demod_cyc; - bi.data.dbg.dma_residue = sm->debug_vals.dma_residue; - sm->debug_vals.mod_cyc = sm->debug_vals.demod_cyc = - sm->debug_vals.dma_residue = 0; - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return 0; -#endif /* SM_DEBUG */ - - case SMCTL_DIAGNOSE: - if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) - return -EFAULT; - newdiagmode = bi.data.diag.mode; - newdiagflags = bi.data.diag.flags; - if (newdiagmode > SM_DIAGMODE_CONSTELLATION) - return -EINVAL; - bi.data.diag.mode = sm->diag.mode; - bi.data.diag.flags = sm->diag.flags; - bi.data.diag.samplesperbit = sm->mode_rx->sperbit; - if (sm->diag.mode != newdiagmode) { - save_flags(flags); - cli(); - sm->diag.ptr = -1; - sm->diag.flags = newdiagflags & ~SM_DIAGFLAG_VALID; - sm->diag.mode = newdiagmode; - restore_flags(flags); - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return 0; - } - if (sm->diag.ptr < 0 || sm->diag.mode == SM_DIAGMODE_OFF) { - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return 0; - } - if (bi.data.diag.datalen > DIAGDATALEN) - bi.data.diag.datalen = DIAGDATALEN; - if (sm->diag.ptr < bi.data.diag.datalen) { - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return 0; - } - if (copy_to_user(bi.data.diag.data, sm->diag.data, - bi.data.diag.datalen * sizeof(short))) - return -EFAULT; - bi.data.diag.flags |= SM_DIAGFLAG_VALID; - save_flags(flags); - cli(); - sm->diag.ptr = -1; - sm->diag.flags = newdiagflags & ~SM_DIAGFLAG_VALID; - sm->diag.mode = newdiagmode; - restore_flags(flags); - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return 0; - } -} - -/* --------------------------------------------------------------------- */ - -#ifdef MODULE -static -#endif /* MODULE */ -int sm_init(void) -{ - int i, j, found = 0; - char set_hw = 1; - struct sm_state *sm; - char ifname[HDLCDRV_IFNAMELEN]; - - printk(sm_drvinfo); - /* - * register net devices - */ - for (i = 0; i < NR_PORTS; i++) { - struct device *dev = sm_device+i; - sprintf(ifname, "sm%d", i); - - if (!sm_ports[i].mode) - set_hw = 0; - if (!set_hw) - sm_ports[i].iobase = sm_ports[i].irq = 0; - j = hdlcdrv_register_hdlcdrv(dev, &sm_ops, sizeof(struct sm_state), - ifname, sm_ports[i].iobase, - sm_ports[i].irq, sm_ports[i].dma); - if (!j) { - sm = (struct sm_state *)dev->priv; - sm->hdrv.ptt_out.dma2 = sm_ports[i].dma2; - sm->hdrv.ptt_out.seriobase = sm_ports[i].seriobase; - sm->hdrv.ptt_out.pariobase = sm_ports[i].pariobase; - sm->hdrv.ptt_out.midiiobase = sm_ports[i].midiiobase; - if (set_hw && sethw(dev, sm, sm_ports[i].mode)) - set_hw = 0; - found++; - } else { - printk(KERN_WARNING "%s: cannot register net device\n", - sm_drvname); - } - } - if (!found) - return -ENXIO; - return 0; -} - -/* --------------------------------------------------------------------- */ - -#ifdef MODULE - -/* - * command line settable parameters - */ -char *mode = NULL; -int iobase = -1; -int irq = -1; -int dma = -1; -int dma2 = -1; -int serio = 0; -int pario = 0; -int midiio = 0; - -MODULE_PARM(mode, "s"); -MODULE_PARM(iobase, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(dma, "i"); -MODULE_PARM(dma2, "i"); -MODULE_PARM(serio, "i"); -MODULE_PARM(pario, "i"); -MODULE_PARM(midiio, "i"); - -int init_module(void) -{ - if (mode) { - if (iobase == -1) - iobase = (!strncmp(mode, "sbc", 3)) ? 0x220 : 0x530; - if (irq == -1) - irq = (!strncmp(mode, "sbc", 3)) ? 5 : 11; - if (dma == -1) - dma = 1; - } - sm_ports[0].mode = mode; - sm_ports[0].iobase = iobase; - sm_ports[0].irq = irq; - sm_ports[0].dma = dma; - sm_ports[0].dma2 = dma2; - sm_ports[0].seriobase = serio; - sm_ports[0].pariobase = pario; - sm_ports[0].midiiobase = midiio; - sm_ports[1].mode = NULL; - - return sm_init(); -} - -/* --------------------------------------------------------------------- */ - -void cleanup_module(void) -{ - int i; - - printk(KERN_INFO "sm: cleanup_module called\n"); - - for(i = 0; i < NR_PORTS; i++) { - struct device *dev = sm_device+i; - struct sm_state *sm = (struct sm_state *)dev->priv; - - if (sm) { - if (sm->hdrv.magic != HDLCDRV_MAGIC) - printk(KERN_ERR "sm: invalid magic in " - "cleanup_module\n"); - else - hdlcdrv_unregister_hdlcdrv(dev); - } - } -} - -#else /* MODULE */ -/* --------------------------------------------------------------------- */ -/* - * format: sm=io,irq,dma[,dma2[,serio[,pario]]],mode - * mode: hw:modem - * hw: sbc, wss, wssfdx - * modem: afsk1200, fsk9600 - */ - -void sm_setup(char *str, int *ints) -{ - int i; - - for (i = 0; (i < NR_PORTS) && (sm_ports[i].mode); i++); - if ((i >= NR_PORTS) || (ints[0] < 4)) { - printk(KERN_INFO "%s: too many or invalid interface " - "specifications\n", sm_drvname); - return; - } - sm_ports[i].mode = str; - sm_ports[i].iobase = ints[1]; - sm_ports[i].irq = ints[2]; - sm_ports[i].dma = ints[3]; - sm_ports[i].dma2 = (ints[0] >= 5) ? ints[4] : 0; - sm_ports[i].seriobase = (ints[0] >= 6) ? ints[5] : 0; - sm_ports[i].pariobase = (ints[0] >= 7) ? ints[6] : 0; - sm_ports[i].midiiobase = (ints[0] >= 8) ? ints[7] : 0; - if (i < NR_PORTS-1) - sm_ports[i+1].mode = NULL; -} - -#endif /* MODULE */ -/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.26/linux/drivers/net/strip.c linux/drivers/net/strip.c --- v2.1.26/linux/drivers/net/strip.c Sun Feb 2 05:18:42 1997 +++ linux/drivers/net/strip.c Fri Feb 21 14:58:35 1997 @@ -1621,7 +1621,7 @@ */ if (haddr.c[0] == 0xFF) { - memcpy(haddr.c, dev->broadcast, sizeof(haddr)); + memcpy(haddr.c, strip_info->dev.broadcast, sizeof(haddr)); if (haddr.c[0] == 0xFF) { strip_info->tx_dropped++; diff -u --recursive --new-file v2.1.26/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.1.26/linux/drivers/pci/pci.c Fri Feb 7 04:36:07 1997 +++ linux/drivers/pci/pci.c Fri Feb 21 14:58:35 1997 @@ -256,6 +256,7 @@ DEVICE( INTEL, INTEL_82371SB_2,"82371SB Natoma/Triton II PIIX3"), DEVICE( INTEL, INTEL_82437VX, "82437VX Triton II"), DEVICE( INTEL, INTEL_P6, "Orion P6"), + DEVICE( KTI, KTI_ET32P2, "ET32P2"), DEVICE( ADAPTEC, ADAPTEC_7850, "AIC-7850"), DEVICE( ADAPTEC, ADAPTEC_7855, "AIC-7855"), DEVICE( ADAPTEC, ADAPTEC_7860, "AIC-7860"), @@ -546,6 +547,7 @@ case PCI_VENDOR_ID_AVANCE: return "Avance"; case PCI_VENDOR_ID_S3: return "S3 Inc."; case PCI_VENDOR_ID_INTEL: return "Intel"; + case PCI_VENDOR_ID_KTI: return "KTI"; case PCI_VENDOR_ID_ADAPTEC: return "Adaptec"; case PCI_VENDOR_ID_ATRONICS: return "Atronics"; case PCI_VENDOR_ID_ARK: return "ARK Logic"; diff -u --recursive --new-file v2.1.26/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c --- v2.1.26/linux/drivers/scsi/eata.c Tue Jan 14 02:48:50 1997 +++ linux/drivers/scsi/eata.c Wed Feb 26 10:56:28 1997 @@ -1,6 +1,25 @@ /* * eata.c - Low-level driver for EATA/DMA SCSI host adapters. * + * 24 Feb 1997 rev. 3.00 for linux 2.0.29 and 2.1.26 + * When loading as a module, parameter passing is now supported + * both in 2.0 and in 2.1 style. + * Fixed data transfer direction for some SCSI opcodes. + * Immediate acknowledge to request sense commands. + * Linked commands to each disk device are now reordered by elevator + * sorting. Rare cases in which reordering of write requests could + * cause wrong results are managed. + * Fixed spurious timeouts caused by long simple queue tag sequences. + * New command line option (tm:[0-3]) to choose the type of tags: + * 0 -> mixed (default); 1 -> simple; 2 -> head; 3 -> ordered. + * + * 18 Jan 1997 rev. 2.60 for linux 2.1.21 and 2.0.28 + * Added command line options to enable/disable linked commands + * (lc:[y|n]), tagged commands (tc:[y|n]) and to set the max queue + * depth (mq:xx). Default is "eata=lc:n,tc:n,mq:16". + * Improved command linking. + * Documented how to setup RAID-0 with DPT SmartRAID boards. + * * 8 Jan 1997 rev. 2.50 for linux 2.1.20 and 2.0.27 * Added linked command support. * Improved detection of PCI boards using ISA base addresses. @@ -12,7 +31,7 @@ * When CONFIG_PCI is defined, BIOS32 is used to include in the * list of i/o ports to be probed all the PCI SCSI controllers. * The list of i/o ports to be probed can be overwritten by the - * "eata=port0, port1,...." boot command line option. + * "eata=port0,port1,...." boot command line option. * Scatter/gather lists are now allocated by a number of kmalloc * calls, in order to avoid the previous size limit of 64Kb. * @@ -129,13 +148,16 @@ * v003.D0, firmware v07G.0). * * DPT SmartRAID boards support "Hardware Array" - a group of disk drives - * which are all members of the same RAID-1 or RAID-5 array implemented + * which are all members of the same RAID-0, RAID-1 or RAID-5 array implemented * in host adapter hardware. Hardware Arrays are fully compatible with this * driver, since they look to it as a single disk drive. - * By contrast RAID-0 are implemented as "Array Group", which does not - * seem to be supported correctly by the actual SCSI subsystem. - * To get RAID-0 functionality, the linux MD driver must be used instead of - * the DPT "Array Group" feature. + * + * WARNING: to create a RAID-0 "Hardware Array" you must select "Other Unix" + * as the current OS in the DPTMGR "Initial System Installation" menu. + * Otherwise RAID-0 is generated as an "Array Group" (i.e. software RAID-0), + * which is not supported by the actual SCSI subsystem. + * To get the "Array Group" functionality, the Linux MD driver must be used + * instead of the DPT "Array Group" feature. * * Multiple ISA, EISA and PCI boards can be configured in the same system. * It is suggested to put all the EISA boards on the same IRQ level, all @@ -167,21 +189,86 @@ * - ISA 0x170, 0x230, 0x330. * * The above list of detection probes can be totally replaced by the - * boot command line option: "eata=port0, port1, port2,...", where the + * boot command line option: "eata=port0,port1,port2,...", where the * port0, port1... arguments are ISA/EISA/PCI addresses to be probed. - * For example using "eata=0x7410, 0x7450, 0x230", the driver probes + * For example using "eata=0x7410,0x7450,0x230", the driver probes * only the two PCI addresses 0x7410 and 0x7450 and the ISA address 0x230, * in this order; "eata=0" totally disables this driver. * + * After the optional list of detection probes, other possible command line + * options are: + * + * lc:y enables linked commands; + * lc:n disables linked commands; + * tc:y enables tagged commands; + * tc:n disables tagged commands; + * tm:0 use head/simple/ordered queue tag sequences for reads and ordered + * queue tags for writes; + * tm:1 use only simple queue tags; + * tm:2 use only head of queue tags; + * tm:3 use only ordered queue tags; + * mq:xx set the max queue depth to the value xx (2 <= xx <= 32). + * + * The default value is: "eata=lc:n,tc:n,mq:16,tm:0". An example using + * the list of detection probes could be: "eata=0x7410,0x230,lc:y,tc:n,mq:4". + * + * When loading as a module, parameters can be specified as well. + * The above example would be (use 1 in place of y and 0 in place of n): + * + * modprobe eata io_port=0x7410,0x230 linked_comm=1 tagged_comm=0 \ + * max_queue_depth=4 tag_mode=0 + * + * ---------------------------------------------------------------------------- + * In this implementation, linked commands are designed to work with any DISK + * or CD-ROM, since this linking has only the intent of clustering (time-wise) + * and reordering by elevator sorting commands directed to each device, + * without any relation with the actual SCSI protocol between the controller + * and the device. + * If Q is the queue depth reported at boot time for each device (also named + * cmds/lun) and Q > 2, whenever there is already an active command to the + * device all other commands to the same device (up to Q-1) are kept waiting + * in the elevator sorting queue. When the active command completes, the + * commands in this queue are sorted by sector address. The sort is chosen + * between increasing or decreasing by minimizing the seek distance between + * the sector of the commands just completed and the sector of the first + * command in the list to be sorted. + * Trivial math assures that if there are (Q-1) outstanding request for + * random seeks over S sectors, the unsorted average seek distance is S/2, + * while the sorted average seek distance is S/(Q-1). The seek distance is + * hence divided by a factor (Q-1)/2. + * The above pure geometric remarks are valid in all cases and the + * driver effectively reduces the seek distance by the predicted factor + * when there are Q concurrent read i/o operations on the device, but this + * does not necessarily results in a noticeable performance improvement: + * your mileage may vary.... + * + * Note: command reordering inside a batch of queued commands could cause + * wrong results only if there is at least one write request and the + * intersection (sector-wise) of all requests is not empty. + * When the driver detects a batch including overlapping requests + * (a really rare event) strict serial (pid) order is enforced. + * ---------------------------------------------------------------------------- + * * The boards are named EATA0, EATA1,... according to the detection order. * * In order to support multiple ISA boards in a reliable way, * the driver sets host->wish_block = TRUE for all ISA boards. */ +#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) +#define MAX_INT_PARAM 10 #if defined(MODULE) #include #include +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,26) +MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM) "i"); +MODULE_PARM(linked_comm, "i"); +MODULE_PARM(tagged_comm, "i"); +MODULE_PARM(link_statistics, "i"); +MODULE_PARM(max_queue_depth, "i"); +MODULE_PARM(tag_mode, "i"); +MODULE_AUTHOR("Dario Ballabio"); +#endif #endif #include @@ -235,9 +322,9 @@ #define MAX_LARGE_SGLIST 252 #define MAX_INTERNAL_RETRIES 64 #define MAX_CMD_PER_LUN 2 -#define MAX_TAGGED_CMD_PER_LUN 16 +#define MAX_TAGGED_CMD_PER_LUN (MAX_MAILBOXES - MAX_CMD_PER_LUN) -#define SKIP 1 +#define SKIP UINT_MAX #define FALSE 0 #define TRUE 1 #define FREE 0 @@ -249,6 +336,10 @@ #define ABORTING 6 #define NO_DMA 0xff #define MAXLOOP 200000 +#define TAG_MIXED 0 +#define TAG_SIMPLE 1 +#define TAG_HEAD 2 +#define TAG_ORDERED 3 #define REG_CMD 7 #define REG_STATUS 7 @@ -281,6 +372,8 @@ #define ASST 0x01 #define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0]) +#define YESNO(a) ((a) ? 'y' : 'n') +#define TLDEV(type) ((type) == TYPE_DISK || (type) == TYPE_ROM) /* "EATA", in Big Endian format */ #define EATA_SIGNATURE 0x41544145 @@ -298,7 +391,8 @@ version:4; /* EATA version, should be 0x1 */ unchar ocsena:1, /* Overlap Command Support Enabled */ tarsup:1, /* Target Mode Supported */ - :2, + trnxfr:1, /* Truncate Transfer Cmd NOT Necessary */ + morsup:1, /* More Supported */ dmasup:1, /* DMA Supported */ drqvld:1, /* DRQ Index (DRQX) is valid */ ata:1, /* This is an ATA device */ @@ -327,10 +421,13 @@ /* Structure extension defined in EATA 2.0C */ unchar max_lun; /* Max SCSI LUN number */ - unchar :6, + unchar :4, + m1:1, /* This is a PCI with an M1 chip installed */ + idquest:1, /* RAIDNUM returned is questionable */ pci:1, /* This board is PCI */ eisa:1; /* This board is EISA */ - unchar notused[2]; + unchar raidnum; /* Uniquely identifies this HBA in a system */ + unchar notused; ushort ipad[247]; }; @@ -373,9 +470,13 @@ dout:1, /* Direction of Transfer is Out (Host to Target) */ din:1; /* Direction of Transfer is In (Target to Host) */ unchar sense_len; /* Request Sense Length */ - unchar unused[4]; + unchar unused[3]; + unchar fwnest:1, /* Send command to a component of an Array Group */ + :7; unchar phsunit:1, /* Send to Target Physical Unit (bypass RAID) */ - notused:7; + iat:1, /* Inhibit Address Translation */ + hbaci:1, /* Inhibit HBA Caching for this command */ + :5; unchar target:5, /* SCSI target ID */ channel:3; /* SCSI channel number */ unchar lun:5, /* SCSI logical unit number */ @@ -390,7 +491,6 @@ ulong sp_addr; /* Address where sp is DMA'ed when cp completes */ ulong sense_addr; /* Address where Sense Data is DMA'ed on error */ unsigned int index; /* cp index */ - unsigned int link_id; /* reference cp for linked commands */ struct sg_list *sglist; }; @@ -417,14 +517,18 @@ static const char *driver_name = "EATA"; static unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ]; -static unsigned int io_port[MAX_BOARDS + 1] = { +static unsigned int io_port[] = { + + /* Space for MAX_INT_PARAM ports usable while loading as a module */ + SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, + SKIP, SKIP, /* First ISA */ 0x1f0, /* Space for MAX_PCI ports possibly reported by PCI_BIOS */ - SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, - SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, + SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, + SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, /* MAX_EISA ports */ 0x1c88, 0x2c88, 0x3c88, 0x4c88, 0x5c88, 0x6c88, 0x7c88, 0x8c88, @@ -446,19 +550,22 @@ #define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0) static void eata2x_interrupt_handler(int, void *, struct pt_regs *); +static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int); static int do_trace = FALSE; static int setup_done = FALSE; +static int link_statistics = 0; +static int tag_mode = TAG_MIXED; #if defined (CONFIG_SCSI_EATA_TAGGED_QUEUE) -static int tagged_commands = TRUE; +static int tagged_comm = TRUE; #else -static int tagged_commands = FALSE; +static int tagged_comm = FALSE; #endif #if defined (CONFIG_SCSI_EATA_LINKED_COMMANDS) -static int linked_commands = TRUE; +static int linked_comm = TRUE; #else -static int linked_commands = FALSE; +static int linked_comm = FALSE; #endif #if defined CONFIG_SCSI_EATA_MAX_TAGS @@ -481,37 +588,50 @@ if (dev->host != host) continue; - if (dev->tagged_supported) ntag++; - else nuntag++; + if (TLDEV(dev->type) && (dev->tagged_supported || linked_comm)) + ntag++; + else + nuntag++; } utqd = MAX_CMD_PER_LUN; - tqd = (host->can_queue - utqd * nuntag) / (ntag + 1); + tqd = (host->can_queue - utqd * nuntag) / (ntag ? ntag : 1); if (tqd > max_queue_depth) tqd = max_queue_depth; if (tqd < MAX_CMD_PER_LUN) tqd = MAX_CMD_PER_LUN; for(dev = devlist; dev; dev = dev->next) { - char *tag_suffix = ""; + char *tag_suffix = "", *link_suffix = ""; if (dev->host != host) continue; - if (dev->tagged_supported) dev->queue_depth = tqd; - else dev->queue_depth = utqd; + if (TLDEV(dev->type) && (dev->tagged_supported || linked_comm)) + dev->queue_depth = tqd; + else + dev->queue_depth = utqd; - if (tagged_commands && dev->tagged_supported) { + if (TLDEV(dev->type)) { + if (linked_comm && dev->queue_depth > 2) + link_suffix = ", linked"; + else + link_suffix = ", unlinked"; + } + + if (tagged_comm && dev->tagged_supported && TLDEV(dev->type)) { dev->tagged_queue = 1; dev->current_tag = 1; } - if (dev->tagged_supported && dev->tagged_queue) tag_suffix = ", tagged"; - else if (dev->tagged_supported) tag_suffix = ", untagged"; + if (dev->tagged_supported && TLDEV(dev->type) && dev->tagged_queue) + tag_suffix = ", tagged"; + else if (dev->tagged_supported && TLDEV(dev->type)) + tag_suffix = ", untagged"; - printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s.\n", + printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s%s.\n", BN(j), host->host_no, dev->channel, dev->id, dev->lun, - dev->queue_depth, tag_suffix); + dev->queue_depth, link_suffix, tag_suffix); } restore_flags(flags); @@ -563,7 +683,7 @@ unsigned char irq, dma_channel, subversion, i; unsigned char protocol_rev; struct eata_info info; - char *bus_type, dma_name[16]; + char *bus_type, dma_name[16], tag_type; /* Allowed DMA channels for ISA (0 indicates reserved) */ unsigned char dma_channel_table[4] = { 5, 6, 7, 0 }; @@ -779,10 +899,18 @@ if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN; - printk("%s: 2.0%c, %s 0x%03x, IRQ %u, %s, SG %d, MB %d, TC %d, LC %d, "\ - "MQ %d.\n", BN(j), HD(j)->protocol_rev, bus_type, sh[j]->io_port, + if (tagged_comm) { + if (tag_mode == TAG_SIMPLE) tag_type = '1'; + else if (tag_mode == TAG_HEAD) tag_type = '2'; + else if (tag_mode == TAG_ORDERED) tag_type = '3'; + else tag_type = 'y'; + } + else tag_type = 'n'; + + printk("%s: 2.0%c, %s 0x%03x, IRQ %u, %s, SG %d, MB %d, tc:%c, lc:%c, "\ + "mq:%d.\n", BN(j), HD(j)->protocol_rev, bus_type, sh[j]->io_port, sh[j]->irq, dma_name, sh[j]->sg_tablesize, sh[j]->can_queue, - tagged_commands, linked_commands, max_queue_depth); + tag_type, YESNO(linked_comm), max_queue_depth); if (sh[j]->max_id > 8 || sh[j]->max_lun > 8) printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n", @@ -793,10 +921,11 @@ BN(j), i, info.host_addr[3 - i]); #if defined (DEBUG_DETECT) - printk("%s: Vers. 0x%x, ocs %u, tar %u, SYNC 0x%x, sec. %u, "\ - "infol %ld, cpl %ld spl %ld.\n", name, info.version, - info.ocsena, info.tarsup, info.sync, info.second, - DEV2H(info.data_len), DEV2H(info.cp_len), DEV2H(info.sp_len)); + printk("%s: Vers. 0x%x, ocs %u, tar %u, trnxfr %u, more %u, SYNC 0x%x, "\ + "sec. %u, infol %ld, cpl %ld spl %ld.\n", name, info.version, + info.ocsena, info.tarsup, info.trnxfr, info.morsup, info.sync, + info.second, DEV2H(info.data_len), DEV2H(info.cp_len), + DEV2H(info.sp_len)); if (protocol_rev == 'B' || protocol_rev == 'C') printk("%s: isaena %u, forcaddr %u, max_id %u, max_chan %u, "\ @@ -804,8 +933,9 @@ info.max_id, info.max_chan, info.large_sg, info.res1); if (protocol_rev == 'C') - printk("%s: max_lun %u, pci %u, eisa %u.\n", name, - info.max_lun, info.pci, info.eisa); + printk("%s: max_lun %u, m1 %u, idquest %u, pci %u, eisa %u, "\ + "raidnum %u.\n", name, info.max_lun, info.m1, info.idquest, + info.pci, info.eisa, info.raidnum); #endif return TRUE; @@ -813,15 +943,34 @@ void eata2x_setup(char *str, int *ints) { int i, argc = ints[0]; + char *cur = str, *pc; - if (argc <= 0) return; + if (argc > 0) { - if (argc > MAX_BOARDS) argc = MAX_BOARDS; + if (argc > MAX_INT_PARAM) argc = MAX_INT_PARAM; - for (i = 0; i < argc; i++) io_port[i] = ints[i + 1]; + for (i = 0; i < argc; i++) io_port[i] = ints[i + 1]; - io_port[i] = 0; - setup_done = TRUE; + io_port[i] = 0; + setup_done = TRUE; + } + + while (cur && (pc = strchr(cur, ':'))) { + int val = 0, c = *++pc; + + if (c == 'n' || c == 'N') val = FALSE; + else if (c == 'y' || c == 'Y') val = TRUE; + else val = (int) simple_strtoul(pc, NULL, 0); + + if (!strncmp(cur, "lc:", 3)) linked_comm = val; + else if (!strncmp(cur, "tc:", 3)) tagged_comm = val; + else if (!strncmp(cur, "tm:", 3)) tag_mode = val; + else if (!strncmp(cur, "mq:", 3)) max_queue_depth = val; + else if (!strncmp(cur, "ls:", 3)) link_statistics = val; + + if ((cur = strchr(cur, ','))) ++cur; + } + return; } @@ -852,7 +1001,7 @@ continue; /* Reverse the returned address order */ - io_port[MAX_PCI - k] = + io_port[MAX_INT_PARAM + MAX_PCI - k] = (addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0; } #endif @@ -869,6 +1018,14 @@ save_flags(flags); cli(); +#if defined(MODULE) + /* io_port could have been modified when loading as a module */ + if(io_port[0] != SKIP) { + setup_done = TRUE; + io_port[MAX_INT_PARAM] = 0; + } +#endif + for (k = 0; k < MAX_IRQ; k++) { irqlist[k] = 0; calls[k] = 0; @@ -914,9 +1071,15 @@ struct mssp *spp; static const unsigned char data_out_cmds[] = { - 0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x0b, 0x10, 0x16, 0x18, 0x1d, - 0x24, 0x2b, 0x2e, 0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, - 0x3f, 0x40, 0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea + 0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e, + 0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40, + 0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b + }; + + static const unsigned char data_none_cmds[] = { + 0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e, + 0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47, + 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5 }; save_flags(flags); @@ -926,6 +1089,16 @@ if (!done) panic("%s: qcomm, pid %ld, null done.\n", BN(j), SCpnt->pid); + if (SCpnt->cmnd[0] == REQUEST_SENSE && SCpnt->sense_buffer[0]) { + SCpnt->result = DID_OK << 16; + SCpnt->host_scribble = NULL; + printk("%s: qcomm, target %d.%d:%d, pid %ld, request sense ignored.\n", + BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid); + restore_flags(flags); + done(SCpnt); + return 0; + } + /* i is the mailbox number, look for the first free mailbox starting from last_cp_used */ i = HD(j)->last_cp_used + 1; @@ -984,7 +1157,13 @@ break; } - cpp->din = !cpp->dout; + if ((cpp->din = !cpp->dout)) + for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++) + if (SCpnt->cmnd[0] == data_none_cmds[k]) { + cpp->din = FALSE; + break; + } + cpp->reqsen = TRUE; cpp->dispri = TRUE; cpp->one = TRUE; @@ -997,11 +1176,20 @@ if (SCpnt->device->tagged_queue) { - if (HD(j)->target_redo[SCpnt->target][SCpnt->channel] || - HD(j)->target_to[SCpnt->target][SCpnt->channel]) + if (HD(j)->target_redo[SCpnt->target][SCpnt->channel] || + HD(j)->target_to[SCpnt->target][SCpnt->channel]) cpp->mess[0] = ORDERED_QUEUE_TAG; - else + else if (tag_mode == TAG_SIMPLE) cpp->mess[0] = SIMPLE_QUEUE_TAG; + else if (tag_mode == TAG_HEAD) cpp->mess[0] = HEAD_OF_QUEUE_TAG; + else if (tag_mode == TAG_ORDERED) cpp->mess[0] = ORDERED_QUEUE_TAG; + else if ((SCpnt->device->current_tag % SCpnt->device->queue_depth) == 0) + cpp->mess[0] = ORDERED_QUEUE_TAG; + else if ((SCpnt->device->current_tag % SCpnt->device->queue_depth) == 1) + cpp->mess[0] = HEAD_OF_QUEUE_TAG; + else if (cpp->din) cpp->mess[0] = SIMPLE_QUEUE_TAG; + else + cpp->mess[0] = ORDERED_QUEUE_TAG; cpp->mess[1] = SCpnt->device->current_tag++; } @@ -1017,27 +1205,13 @@ memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len); - if (linked_commands && SCpnt->device->tagged_supported - && !HD(j)->target_to[SCpnt->target][SCpnt->channel] - && !HD(j)->target_redo[SCpnt->target][SCpnt->channel]) - - for (k = 0; k < sh[j]->can_queue; k++) { - - if (HD(j)->cp_stat[k] != IN_USE) continue; - - if ((&HD(j)->cp[k])->SCpnt->device != SCpnt->device) continue; - - cpp->link_id = k; - HD(j)->cp_stat[i] = READY; - -#if defined (DEBUG_LINKED_COMMANDS) - printk("%s: qcomm, target %d.%d:%d, pid %ld, Mbox %d ready.\n", - BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, - SCpnt->pid, i); -#endif - restore_flags(flags); - return 0; - } + if (linked_comm && SCpnt->device->queue_depth > 2 + && TLDEV(SCpnt->device->type)) { + HD(j)->cp_stat[i] = READY; + flush_dev(SCpnt->device, 0, j, FALSE); + restore_flags(flags); + return 0; + } /* Send control packet to the board */ if (do_dma(sh[j]->io_port, (unsigned int) cpp, SEND_CP_DMA)) { @@ -1273,38 +1447,152 @@ } } -static inline void process_ready_list(unsigned int i, unsigned int j) { +static void sort(unsigned long sk[], unsigned int da[], unsigned int n, + unsigned int rev) { + unsigned int i, j, k, y; + unsigned long x; + + for (i = 0; i < n - 1; i++) { + k = i; + + for (j = k + 1; j < n; j++) + if (rev) { + if (sk[j] > sk[k]) k = j; + } + else { + if (sk[j] < sk[k]) k = j; + } + + if (k != i) { + x = sk[k]; sk[k] = sk[i]; sk[i] = x; + y = da[k]; da[k] = da[i]; da[i] = y; + } + } + + return; + } + +static inline void reorder(unsigned int j, unsigned long cursec, + unsigned int ihdlr, unsigned int il[], unsigned int n_ready) { Scsi_Cmnd *SCpnt; - unsigned int k, n_ready = 0; struct mscp *cpp; + unsigned int k, n; + unsigned int rev = FALSE, s = TRUE, r = TRUE; + unsigned int input_only = TRUE, overlap = FALSE; + unsigned long sl[n_ready], pl[n_ready], ll[n_ready]; + unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0; + + static unsigned int flushcount = 0, batchcount = 0, sortcount = 0; + static unsigned int readycount = 0, ovlcount = 0, inputcount = 0; + static unsigned int readysorted = 0, revcount = 0; + static unsigned long seeksorted = 0, seeknosort = 0; + + if (link_statistics && !(++flushcount % link_statistics)) + printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"\ + " av %ldK as %ldK.\n", flushcount, batchcount, inputcount, + ovlcount, readycount, readysorted, sortcount, revcount, + seeknosort / (readycount - batchcount + 1), + seeksorted / (readycount - batchcount + 1)); + + if (n_ready <= 1) return; + + for (n = 0; n < n_ready; n++) { + k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; + + if (!cpp->din) input_only = FALSE; + + if (SCpnt->request.sector < minsec) minsec = SCpnt->request.sector; + if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector; + + sl[n] = SCpnt->request.sector; + + if (!n) continue; + + if (sl[n] < sl[n - 1]) s = FALSE; + if (sl[n] > sl[n - 1]) r = FALSE; + + if (link_statistics) { + if (sl[n] > sl[n - 1]) + seek += sl[n] - sl[n - 1]; + else + seek += sl[n - 1] - sl[n]; + } + + } + + if (cursec > ((maxsec + minsec) / 2)) rev = TRUE; + + if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev); + + if (!input_only) for (n = 0; n < n_ready; n++) { + k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; + ll[n] = SCpnt->request.nr_sectors; pl[n] = SCpnt->pid; + + if (!n) continue; + + if ((sl[n] == sl[n - 1]) || (!rev && ((sl[n - 1] + ll[n - 1]) > sl[n])) + || (rev && ((sl[n] + ll[n]) > sl[n - 1]))) overlap = TRUE; + } + + if (overlap) sort(pl, il, n_ready, FALSE); + + if (link_statistics) { + batchcount++; readycount += n_ready, seeknosort += seek / 1024; + if (input_only) inputcount++; + if (overlap) { ovlcount++; seeksorted += seek / 1024; } + else seeksorted += (maxsec - minsec) / 1024; + if (rev && !r) { revcount++; readysorted += n_ready; } + if (!rev && !s) { sortcount++; readysorted += n_ready; } + } + +#if defined (DEBUG_LINKED_COMMANDS) + if (link_statistics && (overlap || !(flushcount % link_statistics))) + for (n = 0; n < n_ready; n++) { + k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; + printk("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %ld"\ + " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", + (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target, + SCpnt->lun, SCpnt->pid, k, flushcount, n_ready, + SCpnt->request.sector, SCpnt->request.nr_sectors, cursec, + YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), + YESNO(overlap), cpp->din); + } +#endif +} + +static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j, + unsigned int ihdlr) { + Scsi_Cmnd *SCpnt; + struct mscp *cpp; + unsigned int k, n, n_ready = 0, il[MAX_MAILBOXES]; for (k = 0; k < sh[j]->can_queue; k++) { - if (HD(j)->cp_stat[k] != READY) continue; + if (HD(j)->cp_stat[k] != READY && HD(j)->cp_stat[k] != IN_USE) continue; - cpp = &HD(j)->cp[k]; + cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - if (cpp->link_id != i) continue; + if (SCpnt->device != dev) continue; - SCpnt = cpp->SCpnt; - n_ready++; + if (HD(j)->cp_stat[k] == IN_USE) return; + + il[n_ready++] = k; + } + + reorder(j, cursec, ihdlr, il, n_ready); + + for (n = 0; n < n_ready; n++) { + k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; if (do_dma(sh[j]->io_port, (unsigned int) cpp, SEND_CP_DMA)) { - printk("%s: ihdlr, target %d.%d:%d, pid %ld, Mbox %d, link_id %d, "\ - "n_ready %d, adapter busy, will abort.\n", BN(j), - SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, - k, i, n_ready); + printk("%s: %s, target %d.%d:%d, pid %ld, Mbox %d, adapter"\ + " busy, will abort.\n", BN(j), (ihdlr ? "ihdlr" : "qcomm"), + SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, k); HD(j)->cp_stat[k] = ABORTING; continue; } HD(j)->cp_stat[k] = IN_USE; - -#if defined (DEBUG_LINKED_COMMANDS) - printk("%s: ihdlr, target %d.%d:%d, pid %ld, Mbox %d in use, link_id %d," - " n_ready %d.\n", BN(j), SCpnt->channel, SCpnt->target, - SCpnt->lun, SCpnt->pid, k, i, n_ready); -#endif } } @@ -1313,7 +1601,7 @@ struct pt_regs *regs) { Scsi_Cmnd *SCpnt; unsigned long flags; - unsigned int i, j, k, c, status, tstatus, loops, total_loops = 0; + unsigned int i, j, k, c, status, tstatus, loops, total_loops = 0, reg; struct mssp *spp; struct mscp *cpp; @@ -1345,7 +1633,7 @@ BN(j), HD(j)->iocount); /* Read the status register to clear the interrupt indication */ - inb(sh[j]->io_port + REG_STATUS); + reg = inb(sh[j]->io_port + REG_STATUS); /* Service all mailboxes of this board */ for (i = 0; i < sh[j]->can_queue; i++) { @@ -1356,8 +1644,6 @@ spp->eoc = FALSE; - if (linked_commands) process_ready_list(i, j); - if (HD(j)->cp_stat[i] == IGNORE) { HD(j)->cp_stat[i] = FREE; continue; @@ -1398,6 +1684,10 @@ " irq %d.\n", BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble, irq); + if (linked_comm && SCpnt->device->queue_depth > 2 + && TLDEV(SCpnt->device->type)) + flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE); + tstatus = status_byte(spp->target_status); switch (spp->adapter_status) { @@ -1466,14 +1756,14 @@ status = DID_ERROR << 16; break; - case 0x07: /* Bus Parity Error */ - case 0x0c: /* Controller Ram Parity */ case 0x05: /* Unexpected Bus Phase */ case 0x06: /* Unexpected Bus Free */ + case 0x07: /* Bus Parity Error */ case 0x08: /* SCSI Hung */ case 0x09: /* Unexpected Message Reject */ case 0x0a: /* SCSI Bus Reset Stuck */ case 0x0b: /* Auto Request-Sense Failed */ + case 0x0c: /* Controller Ram Parity Error */ default: status = DID_ERROR << 16; break; @@ -1493,10 +1783,10 @@ do_trace || msg_byte(spp->target_status)) #endif printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"\ - " target %d.%d:%d, pid %ld, count %d.\n", + " target %d.%d:%d, pid %ld, reg 0x%x, count %d.\n", BN(j), i, spp->adapter_status, spp->target_status, SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, - HD(j)->iocount); + reg, HD(j)->iocount); /* Set the command state to inactive */ SCpnt->host_scribble = NULL; diff -u --recursive --new-file v2.1.26/linux/drivers/scsi/eata.h linux/drivers/scsi/eata.h --- v2.1.26/linux/drivers/scsi/eata.h Tue Jan 14 02:48:50 1997 +++ linux/drivers/scsi/eata.h Wed Feb 26 10:56:28 1997 @@ -12,7 +12,7 @@ int eata2x_abort(Scsi_Cmnd *); int eata2x_reset(Scsi_Cmnd *, unsigned int); -#define EATA_VERSION "2.50.00" +#define EATA_VERSION "3.00.09" #define EATA { \ diff -u --recursive --new-file v2.1.26/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c --- v2.1.26/linux/drivers/scsi/u14-34f.c Tue Jan 14 02:48:50 1997 +++ linux/drivers/scsi/u14-34f.c Wed Feb 26 10:56:28 1997 @@ -1,6 +1,21 @@ /* * u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters. * + * 24 Feb 1997 rev. 3.00 for linux 2.0.29 and 2.1.26 + * When loading as a module, parameter passing is now supported + * both in 2.0 and in 2.1 style. + * Fixed data transfer direction for some SCSI opcodes. + * Immediate acknowledge to request sense commands. + * Linked commands to each disk device are now reordered by elevator + * sorting. Rare cases in which reordering of write requests could + * cause wrong results are managed. + * + * 18 Jan 1997 rev. 2.60 for linux 2.1.21 and 2.0.28 + * Added command line options to enable/disable linked commands + * (lc:[y|n]), old firmware support (of:[y|n]) and to set the max + * queue depth (mq:xx). Default is "u14-34f=lc:n,of:n,mq:8". + * Improved command linking. + * * 8 Jan 1997 rev. 2.50 for linux 2.1.20 and 2.0.27 * Added linked command support. * @@ -9,7 +24,7 @@ * * 22 Nov 1996 rev. 2.30 for linux 2.1.12 and 2.0.26 * The list of i/o ports to be probed can be overwritten by the - * "u14-34f=port0, port1,...." boot command line option. + * "u14-34f=port0,port1,...." boot command line option. * Scatter/gather lists are now allocated by a number of kmalloc * calls, in order to avoid the previous size limit of 64Kb. * @@ -118,8 +133,8 @@ * * Here a sample configuration using two U14F boards: * - U14F0: ISA 0x330, BIOS 0xc8000, IRQ 11, DMA 5, SG 32, MB 16, UC 1, LC 1, MQ 8. - U14F1: ISA 0x340, BIOS 0x00000, IRQ 10, DMA 6, SG 32, MB 16, UC 1, LC 1, MQ 8. + U14F0: ISA 0x330, BIOS 0xc8000, IRQ 11, DMA 5, SG 32, MB 16, of:n, lc:y, mq:8. + U14F1: ISA 0x340, BIOS 0x00000, IRQ 10, DMA 6, SG 32, MB 16, of:n, lc:y, mq:8. * * The boot controller must have its BIOS enabled, while other boards can * have their BIOS disabled, or enabled to an higher address. @@ -167,21 +182,80 @@ * problems when using more then 16 scatter/gather lists. * * The list of i/o ports to be probed can be totally replaced by the - * boot command line option: "u14-34f=port0, port1, port2,...", where the + * boot command line option: "u14-34f=port0,port1,port2,...", where the * port0, port1... arguments are ISA/VESA addresses to be probed. - * For example using "u14-34f=0x230, 0x340", the driver probes only the two + * For example using "u14-34f=0x230,0x340", the driver probes only the two * addresses 0x230 and 0x340 in this order; "u14-34f=0" totally disables * this driver. * + * After the optional list of detection probes, other possible command line + * options are: + * + * lc:y enables linked commands; + * lc:n disables linked commands; + * of:y enables old firmware support; + * of:n disables old firmware support; + * mq:xx set the max queue depth to the value xx (2 <= xx <= 8). + * + * The default value is: "u14-34f=lc:n,of:n,mq:8". An example using the list + * of detection probes could be: "u14-34f=0x230,0x340,lc:y,of:n,mq:4". + * + * When loading as a module, parameters can be specified as well. + * The above example would be (use 1 in place of y and 0 in place of n): + * + * modprobe u14-34f io_port=0x230,0x340 linked_comm=1 have_old_firmware=0 \ + * max_queue_depth=4 + * + * ---------------------------------------------------------------------------- + * In this implementation, linked commands are designed to work with any DISK + * or CD-ROM, since this linking has only the intent of clustering (time-wise) + * and reordering by elevator sorting commands directed to each device, + * without any relation with the actual SCSI protocol between the controller + * and the device. + * If Q is the queue depth reported at boot time for each device (also named + * cmds/lun) and Q > 2, whenever there is already an active command to the + * device all other commands to the same device (up to Q-1) are kept waiting + * in the elevator sorting queue. When the active command completes, the + * commands in this queue are sorted by sector address. The sort is chosen + * between increasing or decreasing by minimizing the seek distance between + * the sector of the commands just completed and the sector of the first + * command in the list to be sorted. + * Trivial math assures that if there are (Q-1) outstanding request for + * random seeks over S sectors, the unsorted average seek distance is S/2, + * while the sorted average seek distance is S/(Q-1). The seek distance is + * hence divided by a factor (Q-1)/2. + * The above pure geometric remarks are valid in all cases and the + * driver effectively reduces the seek distance by the predicted factor + * when there are Q concurrent read i/o operations on the device, but this + * does not necessarily results in a noticeable performance improvement: + * your mileage may vary.... + * + * Note: command reordering inside a batch of queued commands could cause + * wrong results only if there is at least one write request and the + * intersection (sector-wise) of all requests is not empty. + * When the driver detects a batch including overlapping requests + * (a really rare event) strict serial (pid) order is enforced. + * ---------------------------------------------------------------------------- + * * The boards are named Ux4F0, Ux4F1,... according to the detection order. * * In order to support multiple ISA boards in a reliable way, * the driver sets host->wish_block = TRUE for all ISA boards. */ +#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) +#define MAX_INT_PARAM 10 #if defined(MODULE) #include #include +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,26) +MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM) "i"); +MODULE_PARM(linked_comm, "i"); +MODULE_PARM(have_old_firmware, "i"); +MODULE_PARM(link_statistics, "i"); +MODULE_PARM(max_queue_depth, "i"); +MODULE_AUTHOR("Dario Ballabio"); +#endif #endif #include @@ -247,8 +321,9 @@ #define MAX_SAFE_SGLIST 16 #define MAX_INTERNAL_RETRIES 64 #define MAX_CMD_PER_LUN 2 -#define MAX_TAGGED_CMD_PER_LUN 8 +#define MAX_TAGGED_CMD_PER_LUN (MAX_MAILBOXES - MAX_CMD_PER_LUN) +#define SKIP UINT_MAX #define FALSE 0 #define TRUE 1 #define FREE 0 @@ -282,6 +357,8 @@ #define ASST 0x91 #define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0]) +#define YESNO(a) ((a) ? 'y' : 'n') +#define TLDEV(type) ((type) == TYPE_DISK || (type) == TYPE_ROM) #define PACKED __attribute__((packed)) @@ -313,7 +390,6 @@ unsigned int sense_addr PACKED; Scsi_Cmnd *SCpnt; unsigned int index; /* cp index */ - unsigned int link_id; /* reference cp for linked commands */ struct sg_list *sglist; }; @@ -343,12 +419,18 @@ static const char *driver_name = "Ux4F"; static unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ]; -static unsigned int io_port[] = { - 0x330, 0x340, 0x230, 0x240, 0x210, 0x130, 0x140, +static unsigned int io_port[] = { - /* End of list */ - 0x0 - }; + /* Space for MAX_INT_PARAM ports usable while loading as a module */ + SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, + SKIP, SKIP, + + /* Possible ISA/VESA ports */ + 0x330, 0x340, 0x230, 0x240, 0x210, 0x130, 0x140, + + /* End of list */ + 0x0 + }; #define HD(board) ((struct hostdata *) &sh[board]->hostdata) #define BN(board) (HD(board)->board_name) @@ -370,13 +452,21 @@ #define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0) static void u14_34f_interrupt_handler(int, void *, struct pt_regs *); +static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int); static int do_trace = FALSE; static int setup_done = FALSE; +static int link_statistics = 0; + +#if defined (HAVE_OLD_UX4F_FIRMWARE) +static int have_old_firmware = TRUE; +#else +static int have_old_firmware = FALSE; +#endif #if defined (CONFIG_SCSI_U14_34F_LINKED_COMMANDS) -static int linked_commands = TRUE; +static int linked_comm = TRUE; #else -static int linked_commands = FALSE; +static int linked_comm = FALSE; #endif #if defined CONFIG_SCSI_U14_34F_MAX_TAGS @@ -399,32 +489,45 @@ if (dev->host != host) continue; - if (dev->tagged_supported) ntag++; - else nuntag++; + if (TLDEV(dev->type) && (dev->tagged_supported || linked_comm)) + ntag++; + else + nuntag++; } utqd = MAX_CMD_PER_LUN; - tqd = (host->can_queue - utqd * nuntag) / (ntag + 1); + tqd = (host->can_queue - utqd * nuntag) / (ntag ? ntag : 1); if (tqd > max_queue_depth) tqd = max_queue_depth; if (tqd < MAX_CMD_PER_LUN) tqd = MAX_CMD_PER_LUN; for(dev = devlist; dev; dev = dev->next) { - char *tag_suffix = ""; + char *tag_suffix = "", *link_suffix = ""; if (dev->host != host) continue; - if (dev->tagged_supported) dev->queue_depth = tqd; - else dev->queue_depth = utqd; + if (TLDEV(dev->type) && (dev->tagged_supported || linked_comm)) + dev->queue_depth = tqd; + else + dev->queue_depth = utqd; - if (dev->tagged_supported && dev->tagged_queue) tag_suffix = ", tagged"; - else if (dev->tagged_supported) tag_suffix = ", untagged"; + if (TLDEV(dev->type)) { + if (linked_comm && dev->queue_depth > 2) + link_suffix = ", linked"; + else + link_suffix = ", unlinked"; + } - printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s.\n", + if (dev->tagged_supported && TLDEV(dev->type) && dev->tagged_queue) + tag_suffix = ", tagged"; + else if (dev->tagged_supported && TLDEV(dev->type)) + tag_suffix = ", untagged"; + + printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s%s.\n", BN(j), host->host_no, dev->channel, dev->id, dev->lun, - dev->queue_depth, tag_suffix); + dev->queue_depth, link_suffix, tag_suffix); } restore_flags(flags); @@ -606,32 +709,26 @@ HD(j)->board_number = j; irqlist[irq]++; - if (HD(j)->subversion == ESA) { + if (have_old_firmware) sh[j]->sg_tablesize = MAX_SAFE_SGLIST; -#if defined (HAVE_OLD_UX4F_FIRMWARE) - sh[j]->sg_tablesize = MAX_SAFE_SGLIST; -#endif - - sh[j]->dma_channel = NO_DMA; + if (HD(j)->subversion == ESA) { sh[j]->unchecked_isa_dma = FALSE; + sh[j]->dma_channel = NO_DMA; sprintf(BN(j), "U34F%d", j); bus_type = "VESA"; } else { sh[j]->wish_block = TRUE; - -#if defined (HAVE_OLD_UX4F_FIRMWARE) - sh[j]->hostt->use_clustering = DISABLE_CLUSTERING; - sh[j]->sg_tablesize = MAX_SAFE_SGLIST; -#endif - - sh[j]->dma_channel = dma_channel; sh[j]->unchecked_isa_dma = TRUE; - sprintf(BN(j), "U14F%d", j); disable_dma(dma_channel); clear_dma_ff(dma_channel); set_dma_mode(dma_channel, DMA_MODE_CASCADE); enable_dma(dma_channel); + + if (have_old_firmware) sh[j]->hostt->use_clustering = DISABLE_CLUSTERING; + + sh[j]->dma_channel = dma_channel; + sprintf(BN(j), "U14F%d", j); bus_type = "ISA"; } @@ -668,10 +765,10 @@ if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN; - printk("%s: %s 0x%03x, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d, UC %d, "\ - "LC %d, MQ %d.\n", BN(j), bus_type, sh[j]->io_port, (int)sh[j]->base, + printk("%s: %s 0x%03x, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d, of:%c, "\ + "lc:%c, mq:%d.\n", BN(j), bus_type, sh[j]->io_port, (int)sh[j]->base, sh[j]->irq, dma_name, sh[j]->sg_tablesize, sh[j]->can_queue, - sh[j]->hostt->use_clustering, linked_commands, max_queue_depth); + YESNO(have_old_firmware), YESNO(linked_comm), max_queue_depth); if (sh[j]->max_id > 8 || sh[j]->max_lun > 8) printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n", @@ -686,15 +783,33 @@ void u14_34f_setup(char *str, int *ints) { int i, argc = ints[0]; + char *cur = str, *pc; - if (argc <= 0) return; + if (argc > 0) { - if (argc > MAX_BOARDS) argc = MAX_BOARDS; + if (argc > MAX_INT_PARAM) argc = MAX_INT_PARAM; - for (i = 0; i < argc; i++) io_port[i] = ints[i + 1]; + for (i = 0; i < argc; i++) io_port[i] = ints[i + 1]; - io_port[i] = 0; - setup_done = TRUE; + io_port[i] = 0; + setup_done = TRUE; + } + + while (cur && (pc = strchr(cur, ':'))) { + int val = 0, c = *++pc; + + if (c == 'n' || c == 'N') val = FALSE; + else if (c == 'y' || c == 'Y') val = TRUE; + else val = (int) simple_strtoul(pc, NULL, 0); + + if (!strncmp(cur, "lc:", 3)) linked_comm = val; + else if (!strncmp(cur, "of:", 3)) have_old_firmware = val; + else if (!strncmp(cur, "mq:", 3)) max_queue_depth = val; + else if (!strncmp(cur, "ls:", 3)) link_statistics = val; + + if ((cur = strchr(cur, ','))) ++cur; + } + return; } @@ -707,6 +822,14 @@ save_flags(flags); cli(); +#if defined(MODULE) + /* io_port could have been modified when loading as a module */ + if(io_port[0] != SKIP) { + setup_done = TRUE; + io_port[MAX_INT_PARAM] = 0; + } +#endif + for (k = 0; k < MAX_IRQ; k++) { irqlist[k] = 0; calls[k] = 0; @@ -714,8 +837,12 @@ for (k = 0; k < MAX_BOARDS + 1; k++) sh[k] = NULL; - for (k = 0; io_port[k]; k++) + for (k = 0; io_port[k]; k++) { + + if (io_port[k] == SKIP) continue; + if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++; + } if (j > 0) printk("UltraStor 14F/34F: Copyright (C) 1994-1997 Dario Ballabio.\n"); @@ -747,9 +874,15 @@ struct mscp *cpp; static const unsigned char data_out_cmds[] = { - 0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x0b, 0x10, 0x16, 0x18, 0x1d, - 0x24, 0x2b, 0x2e, 0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, - 0x3f, 0x40, 0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea + 0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e, + 0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40, + 0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b + }; + + static const unsigned char data_none_cmds[] = { + 0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e, + 0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47, + 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5 }; save_flags(flags); @@ -759,6 +892,16 @@ if (!done) panic("%s: qcomm, pid %ld, null done.\n", BN(j), SCpnt->pid); + if (SCpnt->cmnd[0] == REQUEST_SENSE && SCpnt->sense_buffer[0]) { + SCpnt->result = DID_OK << 16; + SCpnt->host_scribble = NULL; + printk("%s: qcomm, target %d.%d:%d, pid %ld, request sense ignored.\n", + BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid); + restore_flags(flags); + done(SCpnt); + return 0; + } + /* i is the mailbox number, look for the first free mailbox starting from last_cp_used */ i = HD(j)->last_cp_used + 1; @@ -805,10 +948,17 @@ cpp->xdir = DTD_IN; for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++) - if (SCpnt->cmnd[0] == data_out_cmds[k]) { - cpp->xdir = DTD_OUT; - break; - } + if (SCpnt->cmnd[0] == data_out_cmds[k]) { + cpp->xdir = DTD_OUT; + break; + } + + if (cpp->xdir == DTD_IN) + for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++) + if (SCpnt->cmnd[0] == data_none_cmds[k]) { + cpp->xdir = DTD_NONE; + break; + } cpp->opcode = OP_SCSI; cpp->channel = SCpnt->channel; @@ -830,27 +980,13 @@ cpp->scsi_cdbs_len = SCpnt->cmd_len; memcpy(cpp->scsi_cdbs, SCpnt->cmnd, cpp->scsi_cdbs_len); - if (linked_commands && SCpnt->device->tagged_supported - && !HD(j)->target_to[SCpnt->target][SCpnt->channel] - && !HD(j)->target_redo[SCpnt->target][SCpnt->channel]) - - for (k = 0; k < sh[j]->can_queue; k++) { - - if (HD(j)->cp_stat[k] != IN_USE) continue; - - if ((&HD(j)->cp[k])->SCpnt->device != SCpnt->device) continue; - - cpp->link_id = k; - HD(j)->cp_stat[i] = READY; - -#if defined (DEBUG_LINKED_COMMANDS) - printk("%s: qcomm, target %d.%d:%d, pid %ld, Mbox %d ready.\n", - BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun, - SCpnt->pid, i); -#endif - restore_flags(flags); - return 0; - } + if (linked_comm && SCpnt->device->queue_depth > 2 + && TLDEV(SCpnt->device->type)) { + HD(j)->cp_stat[i] = READY; + flush_dev(SCpnt->device, 0, j, FALSE); + restore_flags(flags); + return 0; + } if (wait_on_busy(sh[j]->io_port)) { SCpnt->result = DID_ERROR << 16; @@ -1102,27 +1238,147 @@ return FALSE; } -static inline void process_ready_list(unsigned int i, unsigned int j) { +static void sort(unsigned long sk[], unsigned int da[], unsigned int n, + unsigned int rev) { + unsigned int i, j, k, y; + unsigned long x; + + for (i = 0; i < n - 1; i++) { + k = i; + + for (j = k + 1; j < n; j++) + if (rev) { + if (sk[j] > sk[k]) k = j; + } + else { + if (sk[j] < sk[k]) k = j; + } + + if (k != i) { + x = sk[k]; sk[k] = sk[i]; sk[i] = x; + y = da[k]; da[k] = da[i]; da[i] = y; + } + } + + return; + } + +static inline void reorder(unsigned int j, unsigned long cursec, + unsigned int ihdlr, unsigned int il[], unsigned int n_ready) { Scsi_Cmnd *SCpnt; - unsigned int k, n_ready = 0; struct mscp *cpp; + unsigned int k, n; + unsigned int rev = FALSE, s = TRUE, r = TRUE; + unsigned int input_only = TRUE, overlap = FALSE; + unsigned long sl[n_ready], pl[n_ready], ll[n_ready]; + unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0; + + static unsigned int flushcount = 0, batchcount = 0, sortcount = 0; + static unsigned int readycount = 0, ovlcount = 0, inputcount = 0; + static unsigned int readysorted = 0, revcount = 0; + static unsigned long seeksorted = 0, seeknosort = 0; + + if (link_statistics && !(++flushcount % link_statistics)) + printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"\ + " av %ldK as %ldK.\n", flushcount, batchcount, inputcount, + ovlcount, readycount, readysorted, sortcount, revcount, + seeknosort / (readycount - batchcount + 1), + seeksorted / (readycount - batchcount + 1)); + + if (n_ready <= 1) return; + + for (n = 0; n < n_ready; n++) { + k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; + + if (!(cpp->xdir == DTD_IN)) input_only = FALSE; + + if (SCpnt->request.sector < minsec) minsec = SCpnt->request.sector; + if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector; + + sl[n] = SCpnt->request.sector; + + if (!n) continue; + + if (sl[n] < sl[n - 1]) s = FALSE; + if (sl[n] > sl[n - 1]) r = FALSE; + + if (link_statistics) { + if (sl[n] > sl[n - 1]) + seek += sl[n] - sl[n - 1]; + else + seek += sl[n - 1] - sl[n]; + } + + } + + if (cursec > ((maxsec + minsec) / 2)) rev = TRUE; + + if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev); + + if (!input_only) for (n = 0; n < n_ready; n++) { + k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; + ll[n] = SCpnt->request.nr_sectors; pl[n] = SCpnt->pid; + + if (!n) continue; + + if ((sl[n] == sl[n - 1]) || (!rev && ((sl[n - 1] + ll[n - 1]) > sl[n])) + || (rev && ((sl[n] + ll[n]) > sl[n - 1]))) overlap = TRUE; + } + + if (overlap) sort(pl, il, n_ready, FALSE); + + if (link_statistics) { + batchcount++; readycount += n_ready, seeknosort += seek / 1024; + if (input_only) inputcount++; + if (overlap) { ovlcount++; seeksorted += seek / 1024; } + else seeksorted += (maxsec - minsec) / 1024; + if (rev && !r) { revcount++; readysorted += n_ready; } + if (!rev && !s) { sortcount++; readysorted += n_ready; } + } + +#if defined (DEBUG_LINKED_COMMANDS) + if (link_statistics && (overlap || !(flushcount % link_statistics))) + for (n = 0; n < n_ready; n++) { + k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; + printk("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %ld"\ + " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", + (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target, + SCpnt->lun, SCpnt->pid, k, flushcount, n_ready, + SCpnt->request.sector, SCpnt->request.nr_sectors, cursec, + YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), + YESNO(overlap), cpp->xdir); + } +#endif +} + +static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j, + unsigned int ihdlr) { + Scsi_Cmnd *SCpnt; + struct mscp *cpp; + unsigned int k, n, n_ready = 0, il[MAX_MAILBOXES]; for (k = 0; k < sh[j]->can_queue; k++) { - if (HD(j)->cp_stat[k] != READY) continue; + if (HD(j)->cp_stat[k] != READY && HD(j)->cp_stat[k] != IN_USE) continue; + + cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; + + if (SCpnt->device != dev) continue; - cpp = &HD(j)->cp[k]; + if (HD(j)->cp_stat[k] == IN_USE) return; - if (cpp->link_id != i) continue; + il[n_ready++] = k; + } - SCpnt = cpp->SCpnt; - n_ready++; + reorder(j, cursec, ihdlr, il, n_ready); + + for (n = 0; n < n_ready; n++) { + k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; if (wait_on_busy(sh[j]->io_port)) { - printk("%s: ihdlr, target %d.%d:%d, pid %ld, Mbox %d, link_id %d, "\ - "n_ready %d, adapter busy, will abort.\n", BN(j), - SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, - k, i, n_ready); + printk("%s: %s, target %d.%d:%d, pid %ld, Mbox %d, adapter"\ + " busy, will abort.\n", BN(j), (ihdlr ? "ihdlr" : "qcomm"), + SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, k); HD(j)->cp_stat[k] = ABORTING; continue; } @@ -1130,21 +1386,14 @@ outl(V2DEV(cpp), sh[j]->io_port + REG_OGM); outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR); HD(j)->cp_stat[k] = IN_USE; - -#if defined (DEBUG_LINKED_COMMANDS) - printk("%s: ihdlr, target %d.%d:%d, pid %ld, Mbox %d in use, link_id %d," - " n_ready %d.\n", BN(j), SCpnt->channel, SCpnt->target, - SCpnt->lun, SCpnt->pid, k, i, n_ready); -#endif } - } static void u14_34f_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs) { Scsi_Cmnd *SCpnt; unsigned long flags; - unsigned int i, j, k, c, status, tstatus, loops, total_loops = 0, ret; + unsigned int i, j, k, c, status, tstatus, loops, total_loops = 0, reg, ret; struct mscp *spp; save_flags(flags); @@ -1167,7 +1416,7 @@ loops = 0; /* Loop until all interrupts for a board are serviced */ - while (inb(sh[j]->io_port + REG_SYS_INTR) & IRQ_ASSERTED) { + while ((reg = inb(sh[j]->io_port + REG_SYS_INTR)) & IRQ_ASSERTED) { total_loops++; loops++; @@ -1186,8 +1435,6 @@ panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n", BN(j), (void *)ret, HD(j)->cp); - if (linked_commands) process_ready_list(i, j); - if (HD(j)->cp_stat[i] == IGNORE) { HD(j)->cp_stat[i] = FREE; continue; @@ -1223,6 +1470,10 @@ " irq %d.\n", BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble, irq); + if (linked_comm && SCpnt->device->queue_depth > 2 + && TLDEV(SCpnt->device->type)) + flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE); + tstatus = status_byte(spp->target_status); switch (spp->adapter_status) { @@ -1321,10 +1572,10 @@ do_trace || msg_byte(spp->target_status)) #endif printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"\ - " target %d.%d:%d, pid %ld, count %d.\n", + " target %d.%d:%d, pid %ld, reg 0x%x, count %d.\n", BN(j), i, spp->adapter_status, spp->target_status, SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, - HD(j)->iocount); + reg, HD(j)->iocount); /* Set the command state to inactive */ SCpnt->host_scribble = NULL; diff -u --recursive --new-file v2.1.26/linux/drivers/scsi/u14-34f.h linux/drivers/scsi/u14-34f.h --- v2.1.26/linux/drivers/scsi/u14-34f.h Tue Jan 14 02:48:50 1997 +++ linux/drivers/scsi/u14-34f.h Wed Feb 26 10:56:28 1997 @@ -11,7 +11,7 @@ int u14_34f_reset(Scsi_Cmnd *, unsigned int); int u14_34f_biosparam(Disk *, kdev_t, int *); -#define U14_34F_VERSION "2.50.00" +#define U14_34F_VERSION "3.00.09" #define ULTRASTOR_14_34F { \ NULL, /* Ptr for modules */ \ diff -u --recursive --new-file v2.1.26/linux/fs/dcache.c linux/fs/dcache.c --- v2.1.26/linux/fs/dcache.c Mon Dec 23 00:08:12 1996 +++ linux/fs/dcache.c Tue Feb 25 16:34:44 1997 @@ -21,6 +21,8 @@ #include #include +#include + /* * Don't bother caching long names.. They just take up space in the cache, and * for a name cache you just want to cache the "normal" names anyway which tend @@ -28,6 +30,7 @@ */ #define DCACHE_NAME_LEN 15 #define DCACHE_SIZE 1024 +#define DCACHE_HASH_QUEUES 256 struct hash_list { struct dir_cache_entry * next; @@ -69,7 +72,6 @@ * The hash-queues are also doubly-linked circular lists, but the head is * itself on the doubly-linked list, not just a pointer to the first entry. */ -#define DCACHE_HASH_QUEUES 32 #define hash_fn(dev,dir,namehash) ((HASHDEV(dev) ^ (dir) ^ (namehash)) % DCACHE_HASH_QUEUES) static struct hash_list hash_table[DCACHE_HASH_QUEUES]; @@ -109,6 +111,10 @@ */ static inline unsigned long namehash(const char * name, int len) { + if (len >= sizeof(unsigned long)) + return len + + get_unaligned((unsigned long *) name) + + get_unaligned((unsigned long *) (name + len - sizeof(unsigned long))); return len + ((const unsigned char *) name)[0]+ ((const unsigned char *) name)[len-1]; @@ -143,16 +149,22 @@ */ static inline struct dir_cache_entry * find_entry(struct inode * dir, const char * name, int len, struct hash_list * hash) { - struct dir_cache_entry * de = hash->next; + struct dir_cache_entry * nextde = hash->next; + + for (;;) { + struct dir_cache_entry * de; - for (de = hash->next ; de != (struct dir_cache_entry *) hash ; de = de->h.next) { + if (nextde == (struct dir_cache_entry *) hash) + break; + de = nextde; + nextde = nextde->h.next; + if (de->name_len != (unsigned char) len) + continue; if (de->dc_dev != dir->i_dev) continue; if (de->dir != dir->i_ino) continue; if (de->version != dir->i_version) - continue; - if (de->name_len != len) continue; if (memcmp(de->name, name, len)) continue; diff -u --recursive --new-file v2.1.26/linux/fs/filesystems.c linux/fs/filesystems.c --- v2.1.26/linux/fs/filesystems.c Sun Jan 26 02:07:44 1997 +++ linux/fs/filesystems.c Fri Feb 21 14:58:35 1997 @@ -54,6 +54,10 @@ init_minix_fs(); #endif +#ifdef CONFIG_ROMFS_FS + init_romfs_fs(); +#endif + #ifdef CONFIG_UMSDOS_FS init_umsdos_fs(); #endif @@ -104,10 +108,6 @@ #ifdef CONFIG_UFS_FS init_ufs_fs(); -#endif - -#ifdef CONFIG_ROMFS_FS - init_romfs_fs(); #endif mount_root(); diff -u --recursive --new-file v2.1.26/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c --- v2.1.26/linux/fs/nfs/nfsroot.c Fri Feb 7 05:54:54 1997 +++ linux/fs/nfs/nfsroot.c Fri Feb 21 14:58:35 1997 @@ -1351,6 +1351,7 @@ root_dev->pa_addr | ~root_dev->pa_mask; devinet_ioctl(SIOCSIFBRDADDR, &ifr); } + netmask.sin_addr.s_addr = root_dev->pa_mask; set_fs(fs); /* diff -u --recursive --new-file v2.1.26/linux/include/asm-i386/irq.h linux/include/asm-i386/irq.h --- v2.1.26/linux/include/asm-i386/irq.h Sun Jan 26 02:07:46 1997 +++ linux/include/asm-i386/irq.h Fri Feb 21 14:58:35 1997 @@ -164,7 +164,7 @@ "addl $8,%esp\n\t" \ "cli\n\t" \ UNBLK_##chip(mask) \ - "jmp ret_from_sys_call\n" \ + "jmp ret_from_intr\n" \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ SAVE_MOST \ @@ -195,7 +195,7 @@ "call "SYMBOL_NAME_STR(smp_reschedule_irq)"\n\t" \ "addl $8,%esp\n\t" \ "cli\n\t" \ - "jmp ret_from_sys_call\n"); + "jmp ret_from_intr\n"); #endif /* __SMP__ */ @@ -217,7 +217,7 @@ "addl $8,%esp\n\t" \ "cli\n\t" \ UNBLK_##chip(mask) \ - "jmp ret_from_sys_call\n" \ + "jmp ret_from_intr\n" \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ SAVE_MOST \ @@ -253,6 +253,6 @@ "addl $8,%esp\n\t" \ "cli\n\t" \ UNBLK_##chip(mask) \ - "jmp ret_from_sys_call\n"); + "jmp ret_from_intr\n"); #endif /* _ASM_IRQ_H */ diff -u --recursive --new-file v2.1.26/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h --- v2.1.26/linux/include/asm-i386/smp.h Sun Jan 26 05:36:05 1997 +++ linux/include/asm-i386/smp.h Tue Feb 25 13:17:42 1997 @@ -227,10 +227,11 @@ * cpu id from the config and set up a fake apic_reg pointer so that before we activate * the apic we get the right answer). Hopefully other processors are more sensible 8) */ - + extern __inline int smp_processor_id(void) { - return GET_APIC_ID(apic_read(APIC_ID)); + /* we don't want to mark this access volatile - bad code generation */ + return GET_APIC_ID(*(unsigned long *)(apic_reg+APIC_ID)); } /* These read/change the "processes available" counter in the scheduler. */ diff -u --recursive --new-file v2.1.26/linux/include/asm-i386/string-486.h linux/include/asm-i386/string-486.h --- v2.1.26/linux/include/asm-i386/string-486.h Mon Oct 28 05:02:57 1996 +++ linux/include/asm-i386/string-486.h Fri Feb 21 14:58:35 1997 @@ -339,7 +339,9 @@ "cmpl $-1,%2\n\t" "jne 1b\n" "3:\tsubl %1,%0" - :"=a" (__res):"c" (s),"d" (count)); + :"=a" (__res) + :"c" (s),"d" (count) + :"dx"); return __res; } /* end of additional stuff */ diff -u --recursive --new-file v2.1.26/linux/include/linux/ax25.h linux/include/linux/ax25.h --- v2.1.26/linux/include/linux/ax25.h Sun Feb 2 05:18:47 1997 +++ linux/include/linux/ax25.h Tue Feb 25 17:12:50 1997 @@ -19,7 +19,6 @@ #define AX25_HDRINCL 8 #define AX25_IDLE 9 #define AX25_PACLEN 10 -#define AX25_MAXQUEUE 11 #define AX25_IAMDIGI 12 #define AX25_KILL 99 diff -u --recursive --new-file v2.1.26/linux/include/linux/hdlcdrv.h linux/include/linux/hdlcdrv.h --- v2.1.26/linux/include/linux/hdlcdrv.h Fri Dec 20 03:17:18 1996 +++ linux/include/linux/hdlcdrv.h Fri Feb 21 14:58:35 1997 @@ -8,7 +8,10 @@ #define _HDLCDRV_H #include +#include +#if LINUX_VERSION_CODE < 0x20119 #include +#endif #include /* -------------------------------------------------------------------- */ @@ -39,7 +42,11 @@ int ptt; int dcd; int ptt_keyed; +#if LINUX_VERSION_CODE < 0x20119 struct enet_statistics stats; +#else + struct net_device_stats stats; +#endif }; struct hdlcdrv_ioctl { @@ -231,7 +238,11 @@ struct hdlcdrv_bitbuffer bitbuf_hdlc; #endif /* HDLCDRV_DEBUG */ +#if LINUX_VERSION_CODE < 0x20119 struct enet_statistics stats; +#else + struct net_device_stats stats; +#endif int ptt_keyed; struct sk_buff_head send_queue; /* Packets awaiting transmission */ diff -u --recursive --new-file v2.1.26/linux/include/linux/if_tr.h linux/include/linux/if_tr.h --- v2.1.26/linux/include/linux/if_tr.h Fri Feb 7 05:54:55 1997 +++ linux/include/linux/if_tr.h Fri Feb 21 14:58:36 1997 @@ -35,6 +35,7 @@ /* These are some defined Ethernet Protocol ID's. */ +/* FIXME: should use the definitions in if_ether.h!!! */ #define ETH_P_IP 0x0800 /* Internet Protocol packet */ #define ETH_P_ARP 0x0806 /* Address Resolution packet */ #define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */ diff -u --recursive --new-file v2.1.26/linux/include/linux/interrupt.h linux/include/linux/interrupt.h --- v2.1.26/linux/include/linux/interrupt.h Fri Dec 20 02:06:14 1996 +++ linux/include/linux/interrupt.h Wed Feb 26 13:35:27 1997 @@ -4,6 +4,7 @@ #include #include +#include struct irqaction { void (*handler)(int, void *, struct pt_regs *); @@ -14,7 +15,7 @@ struct irqaction *next; }; -extern unsigned long intr_count; +extern atomic_t intr_count; extern int bh_mask_count[32]; extern unsigned long bh_active; @@ -75,14 +76,14 @@ */ extern inline void start_bh_atomic(void) { - intr_count++; + atomic_inc(&intr_count); barrier(); } extern inline void end_bh_atomic(void) { barrier(); - intr_count--; + atomic_dec(&intr_count); } /* diff -u --recursive --new-file v2.1.26/linux/include/linux/ipv6_route.h linux/include/linux/ipv6_route.h --- v2.1.26/linux/include/linux/ipv6_route.h Tue Nov 26 00:46:41 1996 +++ linux/include/linux/ipv6_route.h Fri Feb 21 14:58:36 1997 @@ -13,8 +13,6 @@ #ifndef _LINUX_IPV6_ROUTE_H #define _LINUX_IPV6_ROUTE_H -#include - #define RTI_DEVRT 0x00010000 /* route lookup, dev must match */ #define RTI_ALLONLINK 0x00020000 /* all destinations on link */ #define RTI_DCACHE RTF_DCACHE /* rt6_info is a dcache entry */ diff -u --recursive --new-file v2.1.26/linux/include/linux/isdn.h linux/include/linux/isdn.h --- v2.1.26/linux/include/linux/isdn.h Sat Aug 31 09:01:49 1996 +++ linux/include/linux/isdn.h Tue Feb 25 17:12:50 1997 @@ -1,4 +1,4 @@ -/* $Id: isdn.h,v 1.16 1996/08/12 16:20:56 hipp Exp $ +/* $Id: isdn.h,v 1.23 1997/02/10 22:07:13 fritz Exp $ * * Main header for the Linux ISDN subsystem (linklevel). * @@ -21,6 +21,29 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn.h,v $ + * Revision 1.23 1997/02/10 22:07:13 fritz + * Added 2 modem registers for numbering plan and screening info. + * + * Revision 1.22 1997/02/03 23:42:08 fritz + * Added ISDN_TIMER_RINGING + * Misc. changes for Kernel 2.1.X compatibility + * + * Revision 1.21 1997/01/17 01:19:10 fritz + * Applied chargeint patch. + * + * Revision 1.20 1997/01/17 00:41:19 fritz + * Increased TTY_DV. + * + * Revision 1.19 1997/01/14 01:41:07 fritz + * Added ATI2 related variables. + * Added variables for audio support in skbuffs. + * + * Revision 1.18 1996/11/06 17:37:50 keil + * more changes for 2.1.X + * + * Revision 1.17 1996/09/07 12:53:57 hipp + * moved a few isdn_ppp.c specific defines to drives/isdn/isdn_ppp.h + * * Revision 1.16 1996/08/12 16:20:56 hipp * renamed ppp_minor to ppp_slot * @@ -153,7 +176,7 @@ #define ISDN_USAGE_EXCLUSIVE 64 /* This bit is set, if channel is exclusive */ #define ISDN_USAGE_OUTGOING 128 /* This bit is set, if channel is outgoing */ -#define ISDN_MODEM_ANZREG 21 /* Number of Modem-Registers */ +#define ISDN_MODEM_ANZREG 22 /* Number of Modem-Registers */ #define ISDN_MSNLEN 20 typedef struct { @@ -173,8 +196,8 @@ int outgoing; } isdn_net_ioctl_phone; -#define NET_DV 0x01 /* Data version for net_cfg */ -#define TTY_DV 0x01 /* Data version for iprofd etc. */ +#define NET_DV 0x02 /* Data version for net_cfg */ +#define TTY_DV 0x03 /* Data version for iprofd etc. */ typedef struct { char name[10]; /* Name of interface */ @@ -197,6 +220,7 @@ int callback; /* Flag: Callback */ int cbhup; /* Flag: Reject Call before Callback */ int pppbind; /* ippp device for bindings */ + int chargeint; /* Use fixed charge interval length */ } isdn_net_ioctl_cfg; #ifdef __KERNEL__ @@ -212,7 +236,6 @@ #include #include #include -#include #include #include #include @@ -274,6 +297,7 @@ #define ISDN_TIMER_RES 3 /* Main Timer-Resolution */ #define ISDN_TIMER_02SEC (HZ/(ISDN_TIMER_RES+1)/5) /* Slow-Timer1 .2 sec */ #define ISDN_TIMER_1SEC (HZ/(ISDN_TIMER_RES+1)) /* Slow-Timer2 1 sec */ +#define ISDN_TIMER_RINGING 5 /* tty RINGs = ISDN_TIMER_1SEC * this factor */ #define ISDN_TIMER_MODEMREAD 1 #define ISDN_TIMER_MODEMPLUS 2 #define ISDN_TIMER_MODEMRING 4 @@ -356,6 +380,7 @@ /* bit0: chargeint is invalid */ /* bit1: Getting charge-interval */ /* bit2: Do charge-unit-hangup */ + /* bit3: Do hangup even on incoming */ int outgoing; /* Flag: outgoing call */ int onhtime; /* Time to keep link up */ int chargeint; /* Interval between charge-infos */ @@ -377,11 +402,21 @@ struct isdn_net_dev_s *netdev; /* Ptr to netdev */ struct sk_buff *first_skb; /* Ptr to skb that triggers dialing */ struct sk_buff *sav_skb; /* Ptr to skb, rejected by LL-driver*/ +#if (LINUX_VERSION_CODE < 0x02010F) /* Ptr to orig. header_cache_bind */ - void (*org_hcb)(struct hh_cache **, struct device *, - unsigned short, __u32); + void (*org_hcb)(struct hh_cache **, + struct device *, + unsigned short, + __u32); +#else + /* Ptr to orig. hard_header_cache */ + int (*org_hhc)(struct dst_entry *dst, + struct dst_entry *neigh, + struct hh_cache *hh); +#endif /* Ptr to orig. header_cache_update */ - void (*org_hcu)(struct hh_cache *, struct device *, + void (*org_hcu)(struct hh_cache *, + struct device *, unsigned char *); int pppbind; /* ippp device for bindings */ } isdn_net_local; @@ -430,6 +465,20 @@ #define ISDN_SERIAL_TYPE_NORMAL 1 #define ISDN_SERIAL_TYPE_CALLOUT 2 +/* For using sk_buffs with audio we need some private variables + * within each sk_buff. For this purpose, we declare a struct here, + * and put it always at skb->head. A few macros help accessing the + * variables. Of course, we need to check skb_headroom prior to + * any access. + */ +typedef struct isdn_audio_skb { + unsigned short dle_count; + unsigned char lock; +} isdn_audio_skb; + +#define ISDN_AUDIO_SKB_DLECOUNT(skb) (((isdn_audio_skb*)skb->head)->dle_count) +#define ISDN_AUDIO_SKB_LOCK(skb) (((isdn_audio_skb*)skb->head)->lock) + /* Private data of AT-command-interpreter */ typedef struct atemu { u_char profile[ISDN_MODEM_ANZREG]; /* Modem-Regs. Profile 0 */ @@ -465,6 +514,12 @@ int isdn_channel; /* Index to isdn-channel */ int drv_index; /* Index to dev->usage */ int ncarrier; /* Flag: schedule NO CARRIER */ + unsigned char last_cause[8]; /* Last cause message */ + unsigned char last_num[20]; /* Last phone-number */ + unsigned char last_l2; /* Last layer-2 protocol */ + unsigned char last_si; /* Last service */ + unsigned char last_lhup; /* Last hangup local? */ + unsigned char last_dir; /* Last direction (in or out) */ struct timer_list nc_timer; /* Timer for delayed NO CARRIER */ int send_outstanding;/* # of outstanding send-requests */ int xmit_size; /* max. # of chars in xmit_buf */ @@ -503,11 +558,6 @@ #define NUM_RCV_BUFFS 64 #define PPP_HARD_HDR_LEN 4 - -#define IPPP_OPEN 0x1 -#define IPPP_CONNECT 0x2 -#define IPPP_CLOSEWAIT 0x4 -#define IPPP_NOBLOCK 0x8 #ifdef CONFIG_ISDN_PPP diff -u --recursive --new-file v2.1.26/linux/include/linux/isdn_ppp.h linux/include/linux/isdn_ppp.h --- v2.1.26/linux/include/linux/isdn_ppp.h Sun May 19 05:29:31 1996 +++ linux/include/linux/isdn_ppp.h Tue Feb 25 17:12:50 1997 @@ -4,18 +4,20 @@ extern int isdn_ppp_dial_slave(char *); extern int isdn_ppp_hangup_slave(char *); -struct pppinfo +#define CALLTYPE_INCOMING 0x1 +#define CALLTYPE_OUTGOING 0x2 +#define CALLTYPE_CALLBACK 0x4 + +struct pppcallinfo { - int type; /* set by user */ - union { - char clid[32]; /* calling ID */ - int bundles; - int linknumber; - } info; + int calltype; + unsigned char local_num[64]; + unsigned char remote_num[64]; + int charge_units; }; -#define PPPIOCLINKINFO _IOWR('t',128,struct pppinfo) +#define PPPIOCGCALLINFO _IOWR('t',128,struct pppcallinfo) #define PPPIOCBUNDLE _IOW('t',129,int) #define PPPIOCGMPFLAGS _IOR('t',130,int) #define PPPIOCSMPFLAGS _IOW('t',131,int) diff -u --recursive --new-file v2.1.26/linux/include/linux/isdnif.h linux/include/linux/isdnif.h --- v2.1.26/linux/include/linux/isdnif.h Fri Jun 7 06:02:43 1996 +++ linux/include/linux/isdnif.h Tue Feb 25 17:12:50 1997 @@ -1,4 +1,4 @@ -/* $Id: isdnif.h,v 1.9 1996/06/06 21:24:24 fritz Exp $ +/* $Id: isdnif.h,v 1.17 1997/02/10 21:12:53 fritz Exp $ * * Linux ISDN subsystem * @@ -22,6 +22,30 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdnif.h,v $ + * Revision 1.17 1997/02/10 21:12:53 fritz + * More setup-interface changes. + * + * Revision 1.16 1997/02/10 19:42:57 fritz + * New interface for reporting incoming calls. + * + * Revision 1.15 1997/02/09 00:18:42 keil + * leased line support + * + * Revision 1.14 1997/02/03 23:43:00 fritz + * Misc changes for Kernel 2.1.X compatibility. + * + * Revision 1.13 1996/11/13 02:39:59 fritz + * More compatibility changes. + * + * Revision 1.12 1996/11/06 17:38:48 keil + * more changes for 2.1.X + * + * Revision 1.11 1996/10/23 11:59:42 fritz + * More compatibility changes. + * + * Revision 1.10 1996/10/22 23:14:19 fritz + * Changes for compatibility to 2.0.X and 2.1.X kernels. + * * Revision 1.9 1996/06/06 21:24:24 fritz * Started adding support for suspend/resume. * @@ -64,6 +88,7 @@ #define ISDN_PTYPE_UNKNOWN 0 /* Protocol undefined */ #define ISDN_PTYPE_1TR6 1 /* german 1TR6-protocol */ #define ISDN_PTYPE_EURO 2 /* EDSS1-protocol */ +#define ISDN_PTYPE_LEASED 3 /* for leased lines */ /* * Values for Layer-2-protocol-selection @@ -145,6 +170,15 @@ #define ISDN_FEATURE_P_1TR6 (0x1000 << ISDN_PTYPE_1TR6) #define ISDN_FEATURE_P_EURO (0x1000 << ISDN_PTYPE_EURO) +typedef struct setup_parm { + char phone[32]; /* Remote Phone-Number */ + char eazmsn[32]; /* Local EAZ or MSN */ + unsigned char si1; /* Service Indicator 1 */ + unsigned char si2; /* Service Indicator 2 */ + unsigned char plan; /* Numbering plan */ + unsigned char screen; /* Screening info */ +} setup_parm; + /* * Structure for exchanging above infos * @@ -153,7 +187,10 @@ int driver; /* Lowlevel-Driver-ID */ int command; /* Command or Status (see above) */ ulong arg; /* Additional Data */ - char num[50]; /* Additional Data */ + union { + char num[50]; /* Additional Data */ + setup_parm setup; + } parm; } isdn_ctrl; /* @@ -302,6 +339,35 @@ */ extern int register_isdn(isdn_if*); +/* Compatibility Linux-2.0.X <-> Linux-2.1.X */ + +#ifndef LINUX_VERSION_CODE +#include +#endif +#if (LINUX_VERSION_CODE < 0x020100) +#include +#define copy_from_user memcpy_fromfs +#define copy_to_user memcpy_tofs +#define GET_USER(x, addr) ( x = get_user(addr) ) +#define RWTYPE int +#define LSTYPE int +#define RWARG int +#define LSARG off_t +#define SET_SKB_FREE(x) ( x->free = 1 ) +#else +#include +#define GET_USER get_user +#define PUT_USER put_user +#define RWTYPE long +#define LSTYPE long long +#define RWARG unsigned long +#define LSARG long long +#if (LINUX_VERSION_CODE < 0x02010F) +#define SET_SKB_FREE(x) ( x->free = 1 ) +#else +#define SET_SKB_FREE(x) +#endif +#endif + #endif /* __KERNEL__ */ #endif /* isdnif_h */ - diff -u --recursive --new-file v2.1.26/linux/include/linux/netrom.h linux/include/linux/netrom.h --- v2.1.26/linux/include/linux/netrom.h Sun Jan 19 05:47:26 1997 +++ linux/include/linux/netrom.h Fri Feb 21 14:58:36 1997 @@ -14,7 +14,6 @@ #define NETROM_T2 2 #define NETROM_N2 3 #define NETROM_HDRINCL 4 -#define NETROM_PACLEN 5 #define NETROM_T4 6 #define NETROM_IDLE 7 diff -u --recursive --new-file v2.1.26/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.1.26/linux/include/linux/pci.h Fri Feb 7 05:54:55 1997 +++ linux/include/linux/pci.h Fri Feb 21 14:58:36 1997 @@ -589,6 +589,9 @@ #define PCI_DEVICE_ID_INTEL_82437VX 0x7030 #define PCI_DEVICE_ID_INTEL_P6 0x84c4 +#define PCI_VENDOR_ID_KTI 0x8e2e +#define PCI_DEVICE_ID_KTI_ET32P2 0x3000 + #define PCI_VENDOR_ID_ADAPTEC 0x9004 #define PCI_DEVICE_ID_ADAPTEC_7850 0x5078 #define PCI_DEVICE_ID_ADAPTEC_7855 0x5578 diff -u --recursive --new-file v2.1.26/linux/include/linux/sysctl.h linux/include/linux/sysctl.h --- v2.1.26/linux/include/linux/sysctl.h Fri Feb 7 05:54:55 1997 +++ linux/include/linux/sysctl.h Tue Feb 25 17:12:50 1997 @@ -69,6 +69,7 @@ #define VM_FREEPG 3 /* struct: Set free page thresholds */ #define VM_BDFLUSH 4 /* struct: Control buffer cache flushing */ #define VM_MAXID 5 +#define VM_OVERCOMMIT_MEMORY 7 /* Turn off the virtual memory safety limit */ /* CTL_NET names: */ #define NET_CORE 1 @@ -144,7 +145,21 @@ }; /* /proc/sys/net/ax25 */ -/* Values are generated dynamically */ +enum { + NET_AX25_IP_DEFAULT_MODE = 1, + NET_AX25_DEFAULT_MODE, + NET_AX25_BACKOFF_TYPE, + NET_AX25_CONNECT_MODE, + NET_AX25_STANDARD_WINDOW, + NET_AX25_EXTENDED_WINDOW, + NET_AX25_T1_TIMEOUT, + NET_AX25_T2_TIMEOUT, + NET_AX25_T3_TIMEOUT, + NET_AX25_IDLE_TIMEOUT, + NET_AX25_N2, + NET_AX25_PACLEN, + NET_AX25_PROTOCOL +}; /* /proc/sys/net/rose */ enum { diff -u --recursive --new-file v2.1.26/linux/include/net/ax25.h linux/include/net/ax25.h --- v2.1.26/linux/include/net/ax25.h Thu Feb 6 02:55:48 1997 +++ linux/include/net/ax25.h Wed Feb 26 14:08:31 1997 @@ -101,42 +101,43 @@ #define AX25_RESPONSE 2 /* Define Link State constants. */ -#define AX25_STATE_0 0 -#define AX25_STATE_1 1 -#define AX25_STATE_2 2 -#define AX25_STATE_3 3 -#define AX25_STATE_4 4 -#define AX25_MAX_DEVICES 20 /* Max No of AX.25 devices */ +enum { + AX25_STATE_0, + AX25_STATE_1, + AX25_STATE_2, + AX25_STATE_3, + AX25_STATE_4 +}; #define AX25_MODULUS 8 /* Standard AX.25 modulus */ #define AX25_EMODULUS 128 /* Extended AX.25 modulus */ -#define AX25_DIGI_INBAND 0x01 /* Allow digipeating within port **/ -#define AX25_DIGI_XBAND 0x02 /* Allow digipeating across ports **/ - -#define AX25_VALUES_IPDEFMODE 0 /* 0=DG 1=VC */ -#define AX25_VALUES_AXDEFMODE 1 /* 0=Normal 1=Extended Seq Nos */ -#define AX25_VALUES_TEXT 2 /* Allow PID=Text - 0=No 1=Yes */ -#define AX25_VALUES_BACKOFF 3 /* 0=None 1=Linear 2=Exponential */ -#define AX25_VALUES_CONMODE 4 /* Allow connected modes - 0=No 1=Yes */ -#define AX25_VALUES_WINDOW 5 /* Default window size for standard AX.25 */ -#define AX25_VALUES_EWINDOW 6 /* Default window size for extended AX.25 */ -#define AX25_VALUES_T1 7 /* Default T1 timeout value */ -#define AX25_VALUES_T2 8 /* Default T2 timeout value */ -#define AX25_VALUES_T3 9 /* Default T3 timeout value */ -#define AX25_VALUES_IDLE 10 /* mode vc idle timer */ -#define AX25_VALUES_N2 11 /* Default N2 value */ -#define AX25_VALUES_PACLEN 12 /* AX.25 MTU */ -#define AX25_VALUES_MAXQUEUE 13 /* Maximum number of buffers enqueued */ -#define AX25_VALUES_DIGI 14 /* Digipeat mode */ -#define AX25_MAX_VALUES 15 +#define AX25_PROTO_STD 0 +#define AX25_PROTO_DAMA_SLAVE 1 +#define AX25_PROTO_DAMA_MASTER 2 + +enum { + AX25_VALUES_IPDEFMODE, /* 0=DG 1=VC */ + AX25_VALUES_AXDEFMODE, /* 0=Normal 1=Extended Seq Nos */ + AX25_VALUES_BACKOFF, /* 0=None 1=Linear 2=Exponential */ + AX25_VALUES_CONMODE, /* Allow connected modes - 0=No 1=no "PID text" 2=all PIDs */ + AX25_VALUES_WINDOW, /* Default window size for standard AX.25 */ + AX25_VALUES_EWINDOW, /* Default window size for extended AX.25 */ + AX25_VALUES_T1, /* Default T1 timeout value */ + AX25_VALUES_T2, /* Default T2 timeout value */ + AX25_VALUES_T3, /* Default T3 timeout value */ + AX25_VALUES_IDLE, /* Connected mode idle timer */ + AX25_VALUES_N2, /* Default N2 value */ + AX25_VALUES_PACLEN, /* AX.25 MTU */ + AX25_VALUES_PROTOCOL, /* Std AX.25, DAMA Slave, DAMA Master */ + AX25_MAX_VALUES /* THIS MUST REMAIN THE LAST ENTRY OF THIS LIST */ +}; #define AX25_DEF_IPDEFMODE 0 /* Datagram */ #define AX25_DEF_AXDEFMODE 0 /* Normal */ -#define AX25_DEF_TEXT 1 /* PID=Text allowed */ #define AX25_DEF_BACKOFF 1 /* Linear backoff */ -#define AX25_DEF_CONMODE 1 /* Connected mode allowed */ +#define AX25_DEF_CONMODE 2 /* Connected mode allowed */ #define AX25_DEF_WINDOW 2 /* Window=2 */ #define AX25_DEF_EWINDOW 32 /* Module-128 Window=32 */ #define AX25_DEF_T1 (10 * AX25_SLOWHZ) /* T1=10s */ @@ -145,27 +146,47 @@ #define AX25_DEF_N2 10 /* N2=10 */ #define AX25_DEF_IDLE (20 * 60 * AX25_SLOWHZ) /* Idle=20 mins */ #define AX25_DEF_PACLEN 256 /* Paclen=256 */ -#define AX25_DEF_MAXQUEUE 2 /* 1 * ax25->window */ -#define AX25_DEF_DIGI 0x03 /* All digis alowed */ +#define AX25_DEF_PROTOCOL AX25_PROTO_STD /* Standard AX.25 */ typedef struct ax25_uid_assoc { - struct ax25_uid_assoc *next; - uid_t uid; - ax25_address call; + struct ax25_uid_assoc *next; + uid_t uid; + ax25_address call; } ax25_uid_assoc; typedef struct { - ax25_address calls[AX25_MAX_DIGIS]; - unsigned char repeated[AX25_MAX_DIGIS]; - unsigned char ndigi; - char lastrepeat; + ax25_address calls[AX25_MAX_DIGIS]; + unsigned char repeated[AX25_MAX_DIGIS]; + unsigned char ndigi; + char lastrepeat; } ax25_digi; +typedef struct ax25_route { + struct ax25_route *next; + ax25_address callsign; + struct device *dev; + ax25_digi *digipeat; + char ip_mode; +} ax25_route; + +#ifndef _LINUX_SYSCTL_H +#include +#endif + +typedef struct ax25_dev { + struct ax25_dev *next; + struct device *dev; + struct device *forward; + struct ctl_table systable[AX25_MAX_VALUES+1]; + int values[AX25_MAX_VALUES]; +} ax25_dev; + typedef struct ax25_cb { struct ax25_cb *next; ax25_address source_addr, dest_addr; - struct device *device; - unsigned char dama_slave, iamdigi; + ax25_digi *digipeat; + ax25_dev *ax25_dev; + unsigned char iamdigi; unsigned char state, modulus, hdrincl; unsigned short vs, vr, va; unsigned char condition, backoff; @@ -173,9 +194,7 @@ unsigned short t1, t2, t3, idle, rtt; unsigned short t1timer, t2timer, t3timer, idletimer; unsigned short paclen; - unsigned short maxqueue; unsigned short fragno, fraglen; - ax25_digi *digipeat; struct sk_buff_head write_queue; struct sk_buff_head reseq_queue; struct sk_buff_head ack_queue; @@ -185,68 +204,110 @@ struct sock *sk; /* Backlink to socket */ } ax25_cb; -struct ax25_dev { - char name[20]; - struct device *dev; - struct device *forward; - int values[AX25_MAX_VALUES]; -}; - /* af_ax25.c */ +extern ax25_cb *volatile ax25_list; +extern void ax25_free_cb(ax25_cb *); +extern void ax25_insert_socket(ax25_cb *); +struct sock *ax25_find_listener(ax25_address *, int, struct device *, int); +struct sock *ax25_find_socket(ax25_address *, ax25_address *, int); +extern ax25_cb *ax25_find_cb(ax25_address *, ax25_address *, ax25_digi *, struct device *); +extern struct sock *ax25_addr_match(ax25_address *); +extern void ax25_send_to_raw(struct sock *, struct sk_buff *, int); +extern void ax25_destroy_socket(ax25_cb *); +extern ax25_cb *ax25_create_cb(void); +extern void ax25_fillin_cb(ax25_cb *, ax25_dev *); +extern int ax25_create(struct socket *, int); +extern struct sock *ax25_make_new(struct sock *, struct device *); + +/* ax25_addr.c */ extern ax25_address null_ax25_address; extern char *ax2asc(ax25_address *); extern ax25_address *asc2ax(char *); extern int ax25cmp(ax25_address *, ax25_address *); -extern int ax25_send_frame(struct sk_buff *, int, ax25_address *, ax25_address *, ax25_digi *, struct device *); -extern int ax25_link_up(ax25_address *, ax25_address *, struct device *); -extern void ax25_destroy_socket(ax25_cb *); -extern struct device *ax25rtr_get_dev(ax25_address *); -extern int ax25_encapsulate(struct sk_buff *, struct device *, unsigned short, - void *, void *, unsigned int); -extern int ax25_rebuild_header(struct sk_buff *); -extern ax25_uid_assoc *ax25_uid_list; -extern int ax25_uid_policy; -extern ax25_address *ax25_findbyuid(uid_t); -extern void ax25_queue_xmit(struct sk_buff *); -extern int ax25_dev_is_dama_slave(struct device *); /* dl1bke 951121 */ +extern int ax25digicmp(ax25_digi *, ax25_digi *); +extern unsigned char *ax25_addr_parse(unsigned char *, int, ax25_address *, ax25_address *, ax25_digi *, int *, int *); +extern int ax25_addr_build(unsigned char *, ax25_address *, ax25_address *, ax25_digi *, int, int); +extern int ax25_addr_size(ax25_digi *); +extern void ax25_digi_invert(ax25_digi *, ax25_digi *); + +/* ax25_dev.c */ +extern ax25_dev *ax25_dev_list; +extern ax25_dev *ax25_dev_ax25dev(struct device *); +extern ax25_dev *ax25_addr_ax25dev(ax25_address *); +extern void ax25_dev_device_up(struct device *); +extern void ax25_dev_device_down(struct device *); +extern int ax25_fwd_ioctl(unsigned int, struct ax25_fwd_struct *); +extern struct device *ax25_fwd_dev(struct device *); +extern void ax25_dev_free(void); + +/* ax25_ds_in.c */ +extern int ax25_ds_frame_in(ax25_cb *, struct sk_buff *, int); + +/* ax25_ds_subr.c */ +extern void ax25_ds_nr_error_recovery(ax25_cb *); +extern void ax25_ds_enquiry_response(ax25_cb *); +extern void ax25_ds_establish_data_link(ax25_cb *); +extern void ax25_dama_on(ax25_cb *); +extern void ax25_dama_off(ax25_cb *); + +/* ax25_ds_timer.c */ +extern void ax25_ds_timer(ax25_cb *); +extern void ax25_ds_t1_timeout(ax25_cb *); #include +/* ax25_iface.c */ +extern int ax25_protocol_register(unsigned int, int (*)(struct sk_buff *, ax25_cb *)); +extern void ax25_protocol_release(unsigned int); +extern int ax25_linkfail_register(void (*)(ax25_address *, struct device *)); +extern void ax25_linkfail_release(void (*)(ax25_address *, struct device *)); +extern int ax25_listen_register(ax25_address *, struct device *); +extern void ax25_listen_release(ax25_address *, struct device *); +extern int (*ax25_protocol_function(unsigned int))(struct sk_buff *, ax25_cb *); +extern int ax25_listen_mine(ax25_address *, struct device *); +extern void ax25_link_failed(ax25_address *, struct device *); +extern int ax25_link_up(ax25_address *, ax25_address *, ax25_digi *, struct device *); +extern int ax25_protocol_is_registered(unsigned int); + /* ax25_in.c */ -extern int ax25_process_rx_frame(ax25_cb *, struct sk_buff *, int, int); +extern int ax25_rx_iframe(ax25_cb *, struct sk_buff *); +extern int ax25_kiss_rcv(struct sk_buff *, struct device *, struct packet_type *); + +/* ax25_ip.c */ +extern int ax25_encapsulate(struct sk_buff *, struct device *, unsigned short, void *, void *, unsigned int); +extern int ax25_rebuild_header(struct sk_buff *); /* ax25_out.c */ +extern int ax25_send_frame(struct sk_buff *, int, ax25_address *, ax25_address *, ax25_digi *, struct device *); extern void ax25_output(ax25_cb *, int, struct sk_buff *); extern void ax25_kick(ax25_cb *); extern void ax25_transmit_buffer(ax25_cb *, struct sk_buff *, int); -extern void ax25_nr_error_recovery(ax25_cb *); -extern void ax25_establish_data_link(ax25_cb *); -extern void ax25_transmit_enquiry(ax25_cb *); -extern void ax25_enquiry_response(ax25_cb *); -extern void ax25_timeout_response(ax25_cb *); +extern void ax25_queue_xmit(struct sk_buff *); extern void ax25_check_iframes_acked(ax25_cb *, unsigned short); -extern void ax25_check_need_response(ax25_cb *, int, int); -extern void dama_enquiry_response(ax25_cb *); /* dl1bke 960114 */ -extern void dama_check_need_response(ax25_cb *, int, int); /* dl1bke 960114 */ -extern void dama_establish_data_link(ax25_cb *); /* ax25_route.c */ -extern struct ax25_dev ax25_device[]; +extern void ax25_rt_device_down(struct device *); +extern int ax25_rt_ioctl(unsigned int, void *); extern int ax25_rt_get_info(char *, char **, off_t, int, int); -extern int ax25_cs_get_info(char *, char **, off_t, int, int); extern int ax25_rt_autobind(ax25_cb *, ax25_address *); extern void ax25_rt_build_path(ax25_cb *, ax25_address *, struct device *); extern void ax25_dg_build_path(struct sk_buff *, ax25_address *, struct device *); -extern void ax25_rt_device_down(struct device *); -extern int ax25_rt_ioctl(unsigned int, void *); extern char ax25_ip_mode_get(ax25_address *, struct device *); -extern int ax25_dev_get_value(struct device *, int); -extern void ax25_dev_device_up(struct device *); -extern void ax25_dev_device_down(struct device *); -extern int ax25_fwd_ioctl(unsigned int, struct ax25_fwd_struct *); -extern struct device *ax25_fwd_dev(struct device *); extern void ax25_rt_free(void); +/* ax25_std_in.c */ +extern int ax25_std_frame_in(ax25_cb *, struct sk_buff *, int); + +/* ax25_std_subr.c */ +extern void ax25_std_nr_error_recovery(ax25_cb *); +extern void ax25_std_establish_data_link(ax25_cb *); +extern void ax25_std_transmit_enquiry(ax25_cb *); +extern void ax25_std_enquiry_response(ax25_cb *); +extern void ax25_std_timeout_response(ax25_cb *); + +/* ax25_std_timer.c */ +extern void ax25_std_timer(ax25_cb *); + /* ax25_subr.c */ extern void ax25_clear_queues(ax25_cb *); extern void ax25_frames_acked(ax25_cb *, unsigned short); @@ -254,41 +315,22 @@ extern int ax25_validate_nr(ax25_cb *, unsigned short); extern int ax25_decode(ax25_cb *, struct sk_buff *, int *, int *, int *); extern void ax25_send_control(ax25_cb *, int, int, int); +extern void ax25_return_dm(struct device *, ax25_address *, ax25_address *, ax25_digi *); extern unsigned short ax25_calculate_t1(ax25_cb *); extern void ax25_calculate_rtt(ax25_cb *); -extern unsigned char *ax25_parse_addr(unsigned char *, int, ax25_address *, - ax25_address *, ax25_digi *, int *, int *); /* dl1bke 951121 */ -extern int build_ax25_addr(unsigned char *, ax25_address *, ax25_address *, - ax25_digi *, int, int); -extern int size_ax25_addr(ax25_digi *); -extern void ax25_digi_invert(ax25_digi *, ax25_digi *); -extern void ax25_return_dm(struct device *, ax25_address *, ax25_address *, ax25_digi *); -extern int ax25_queue_length(ax25_cb *, struct sk_buff *); /* dl1bke 960327 */ -extern void ax25_dama_on(ax25_cb *); /* dl1bke 951121 */ -extern void ax25_dama_off(ax25_cb *); /* dl1bke 951121 */ /* ax25_timer.c */ extern void ax25_set_timer(ax25_cb *); -extern void ax25_t1_timeout(ax25_cb *); -extern void ax25_link_failed(ax25_address *, struct device *); -extern int (*ax25_protocol_function(unsigned int))(struct sk_buff *, ax25_cb *); -extern int ax25_listen_mine(ax25_address *, struct device *); + +/* ax25_uid.c */ +extern int ax25_uid_policy; +extern ax25_address *ax25_findbyuid(uid_t); +extern int ax25_uid_ioctl(int, struct sockaddr_ax25 *); +extern int ax25_uid_get_info(char *, char **, off_t, int, int); +extern void ax25_uid_free(void); /* sysctl_net_ax25.c */ extern void ax25_register_sysctl(void); extern void ax25_unregister_sysctl(void); - -/* ... */ - -extern ax25_cb *volatile ax25_list; - -/* support routines for modules that use AX.25, in ax25_timer.c */ -extern int ax25_protocol_register(unsigned int, int (*)(struct sk_buff *, ax25_cb *)); -extern void ax25_protocol_release(unsigned int); -extern int ax25_linkfail_register(void (*)(ax25_address *, struct device *)); -extern void ax25_linkfail_release(void (*)(ax25_address *, struct device *)); -extern int ax25_listen_register(ax25_address *, struct device *); -extern void ax25_listen_release(ax25_address *, struct device *); -extern int ax25_protocol_is_registered(unsigned int); #endif diff -u --recursive --new-file v2.1.26/linux/include/net/lapb.h linux/include/net/lapb.h --- v2.1.26/linux/include/net/lapb.h Tue Feb 4 06:44:24 1997 +++ linux/include/net/lapb.h Fri Feb 21 14:58:36 1997 @@ -31,6 +31,11 @@ #define LAPB_SPF 0x10 /* Poll/final bit for standard LAPB */ #define LAPB_EPF 0x01 /* Poll/final bit for extended LAPB */ +#define LAPB_FRMR_W 0x01 /* Control field invalid */ +#define LAPB_FRMR_X 0x02 /* I field invalid */ +#define LAPB_FRMR_Y 0x04 /* I field too long */ +#define LAPB_FRMR_Z 0x08 /* Invalid N(R) */ + #define LAPB_POLLOFF 0 #define LAPB_POLLON 1 @@ -44,11 +49,13 @@ #define LAPB_ADDR_D 0x07 /* Define Link State constants. */ -#define LAPB_STATE_0 0 /* Disconnected State */ -#define LAPB_STATE_1 1 /* Awaiting Connection State */ -#define LAPB_STATE_2 2 /* Awaiting Disconnection State */ -#define LAPB_STATE_3 3 /* Data Transfer State */ -#define LAPB_STATE_4 4 /* Frame Reject State */ +enum { + LAPB_STATE_0, /* Disconnected State */ + LAPB_STATE_1, /* Awaiting Connection State */ + LAPB_STATE_2, /* Awaiting Disconnection State */ + LAPB_STATE_3, /* Data Transfer State */ + LAPB_STATE_4 /* Frame Reject State */ +}; #define LAPB_DEFAULT_MODE (LAPB_STANDARD | LAPB_SLP | LAPB_DTE) #define LAPB_DEFAULT_WINDOW 7 /* Window=7 */ @@ -59,9 +66,25 @@ #define LAPB_SMODULUS 8 #define LAPB_EMODULUS 128 +/* + * Information about the current frame. + */ +struct lapb_frame { + unsigned short type; /* Parsed type */ + unsigned short nr, ns; /* N(R), N(S) */ + unsigned char cr; /* Command/Response */ + unsigned char pf; /* Poll/Final */ + unsigned char control[2]; /* Original control data*/ +}; + +/* + * The per LAPB connection control structure. + */ typedef struct lapb_cb { struct lapb_cb *next; void *token; + + /* Link status fields */ unsigned int mode; unsigned char state; unsigned short vs, vr, va; @@ -69,12 +92,18 @@ unsigned short n2, n2count; unsigned short t1, t2; unsigned short t1timer, t2timer; + + /* Internal control information */ struct sk_buff_head input_queue; struct sk_buff_head write_queue; struct sk_buff_head ack_queue; unsigned char window; struct timer_list timer; struct lapb_register_struct callbacks; + + /* FRMR control information */ + struct lapb_frame frmr_data; + unsigned char frmr_type; } lapb_cb; /* lapb_iface.c */ @@ -102,8 +131,9 @@ extern void lapb_frames_acked(lapb_cb *, unsigned short); extern void lapb_requeue_frames(lapb_cb *); extern int lapb_validate_nr(lapb_cb *, unsigned short); -extern int lapb_decode(lapb_cb *, struct sk_buff *, int *, int *, int *, int *); +extern void lapb_decode(lapb_cb *, struct sk_buff *, struct lapb_frame *); extern void lapb_send_control(lapb_cb *, int, int, int); +extern void lapb_transmit_frmr(lapb_cb *); /* lapb_timer.c */ extern void lapb_set_timer(lapb_cb *); diff -u --recursive --new-file v2.1.26/linux/include/net/netrom.h linux/include/net/netrom.h --- v2.1.26/linux/include/net/netrom.h Sun Feb 2 05:18:47 1997 +++ linux/include/net/netrom.h Fri Feb 21 14:58:36 1997 @@ -28,11 +28,12 @@ #define NR_MORE_FLAG 0x20 /* Define Link State constants. */ - -#define NR_STATE_0 0 -#define NR_STATE_1 1 -#define NR_STATE_2 2 -#define NR_STATE_3 3 +enum { + NR_STATE_0, + NR_STATE_1, + NR_STATE_2, + NR_STATE_3 +}; #define NR_COND_ACK_PENDING 0x01 #define NR_COND_REJECT 0x02 diff -u --recursive --new-file v2.1.26/linux/include/net/rose.h linux/include/net/rose.h --- v2.1.26/linux/include/net/rose.h Sun Feb 2 05:18:47 1997 +++ linux/include/net/rose.h Fri Feb 21 14:58:36 1997 @@ -40,11 +40,13 @@ /* Define Link State constants. */ -#define ROSE_STATE_0 0 /* Ready */ -#define ROSE_STATE_1 1 /* Awaiting Call Accepted */ -#define ROSE_STATE_2 2 /* Awaiting Clear Confirmation */ -#define ROSE_STATE_3 3 /* Data Transfer */ -#define ROSE_STATE_4 4 /* Awaiting Reset Confirmation */ +enum { + ROSE_STATE_0, /* Ready */ + ROSE_STATE_1, /* Awaiting Call Accepted */ + ROSE_STATE_2, /* Awaiting Clear Confirmation */ + ROSE_STATE_3, /* Data Transfer */ + ROSE_STATE_4 /* Awaiting Reset Confirmation */ +}; #define ROSE_DEFAULT_T0 (180 * ROSE_SLOWHZ) /* Default T10 T20 value */ #define ROSE_DEFAULT_T1 (200 * ROSE_SLOWHZ) /* Default T11 T21 value */ diff -u --recursive --new-file v2.1.26/linux/include/net/sock.h linux/include/net/sock.h --- v2.1.26/linux/include/net/sock.h Thu Feb 6 02:55:48 1997 +++ linux/include/net/sock.h Wed Feb 26 14:08:33 1997 @@ -700,7 +700,11 @@ int noblock, int *errcode); extern int sock_no_fcntl(struct socket *, unsigned int, unsigned long); - +extern int sock_no_getsockopt(struct socket *, int , int, + char *, int *); +extern int sock_no_setsockopt(struct socket *, int, int, + char *, int); +extern int sock_no_listen(struct socket *, int); /* * Default socket callbacks and setup code */ diff -u --recursive --new-file v2.1.26/linux/include/net/x25.h linux/include/net/x25.h --- v2.1.26/linux/include/net/x25.h Sun Jan 19 05:47:27 1997 +++ linux/include/net/x25.h Fri Feb 21 14:58:36 1997 @@ -52,17 +52,20 @@ #define X25_COND_PEER_RX_BUSY 0x04 /* Define Link State constants. */ +enum { + X25_STATE_0, /* Ready */ + X25_STATE_1, /* Awaiting Call Accepted */ + X25_STATE_2, /* Awaiting Clear Confirmation */ + X25_STATE_3, /* Data Transfer */ + X25_STATE_4 /* Awaiting Reset Confirmation */ +}; -#define X25_STATE_0 0 /* Ready */ -#define X25_STATE_1 1 /* Awaiting Call Accepted */ -#define X25_STATE_2 2 /* Awaiting Clear Confirmation */ -#define X25_STATE_3 3 /* Data Transfer */ -#define X25_STATE_4 4 /* Awaiting Reset Confirmation */ - -#define X25_LINK_STATE_0 0 -#define X25_LINK_STATE_1 1 -#define X25_LINK_STATE_2 2 -#define X25_LINK_STATE_3 3 +enum { + X25_LINK_STATE_0, + X25_LINK_STATE_1, + X25_LINK_STATE_2, + X25_LINK_STATE_3 +}; #define X25_DEFAULT_T20 (180 * X25_SLOWHZ) /* Default T20 value */ #define X25_DEFAULT_T21 (200 * X25_SLOWHZ) /* Default T21 value */ diff -u --recursive --new-file v2.1.26/linux/init/main.c linux/init/main.c --- v2.1.26/linux/init/main.c Sun Feb 2 05:53:10 1997 +++ linux/init/main.c Tue Feb 25 17:12:50 1997 @@ -166,6 +166,12 @@ #ifdef CONFIG_ISDN_DRV_TELES extern void teles_setup(char *str, int *ints); #endif +#ifdef CONFIG_ISDN_DRV_HISAX +extern void HiSax_setup(char *str, int *ints); +#endif +#ifdef CONFIG_ISDN_DRV_PCBIT +extern void pcbit_setup(char *str, int *ints); +#endif #ifdef CONFIG_ATARIMOUSE extern void atari_mouse_setup (char *str, int *ints); @@ -182,9 +188,6 @@ #ifdef CONFIG_DIGI extern void pcxx_setup(char *str, int *ints); #endif -#ifdef CONFIG_ISDN_DRV_PCBIT -extern void pcbit_setup(char *str, int *ints); -#endif #ifdef CONFIG_RISCOM8 extern void riscom8_setup(char *str, int *ints); #endif @@ -437,6 +440,10 @@ #endif #ifdef CONFIG_ISDN_DRV_TELES { "teles=", teles_setup }, +#endif +#ifdef CONFIG_ISDN_DRV_HISAX + { "hisax=", HiSax_setup }, + { "HiSax=", HiSax_setup }, #endif #ifdef CONFIG_ISDN_DRV_PCBIT { "pcbit=", pcbit_setup }, diff -u --recursive --new-file v2.1.26/linux/kernel/sched.c linux/kernel/sched.c --- v2.1.26/linux/kernel/sched.c Fri Feb 7 05:54:55 1997 +++ linux/kernel/sched.c Fri Feb 21 14:58:36 1997 @@ -99,7 +99,12 @@ unsigned long volatile jiffies=0; -struct task_struct *current_set[NR_CPUS]; +/* + * Init task must be ok at boot for the ix86 as we will check its signals + * via the SMP irq return path. + */ + +struct task_struct *current_set[NR_CPUS] = {&init_task, }; struct task_struct *last_task_used_math = NULL; struct task_struct * task[NR_TASKS] = {&init_task, }; diff -u --recursive --new-file v2.1.26/linux/kernel/signal.c linux/kernel/signal.c --- v2.1.26/linux/kernel/signal.c Tue Feb 4 06:44:25 1997 +++ linux/kernel/signal.c Tue Feb 25 13:24:34 1997 @@ -27,42 +27,41 @@ * This call isn't used by all ports, in particular, the Alpha * uses osf_sigprocmask instead. Maybe it should be moved into * arch-dependent dir? + * + * We don't need to get the kernel lock - this is all local to this + * particular thread.. (and that's good, because this is _heavily_ + * used by various programs) */ asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset) { - sigset_t new_set, old_set = current->blocked; - int error; + sigset_t old_set = current->blocked; - lock_kernel(); if (set) { - error = get_user(new_set, set); + sigset_t new_set; + int error = get_user(new_set, set); if (error) - goto out; + return error; new_set &= _BLOCKABLE; switch (how) { + default: + return -EINVAL; case SIG_BLOCK: - current->blocked |= new_set; + new_set |= old_set; break; case SIG_UNBLOCK: - current->blocked &= ~new_set; + new_set = old_set & ~new_set; break; case SIG_SETMASK: - current->blocked = new_set; break; - default: - error = -EINVAL; - goto out; } + current->blocked = new_set; } if (oset) { - error = put_user(old_set, oset); + int error = put_user(old_set, oset); if (error) - goto out; + return error; } - error = 0; -out: - unlock_kernel(); - return error; + return 0; } /* diff -u --recursive --new-file v2.1.26/linux/kernel/softirq.c linux/kernel/softirq.c --- v2.1.26/linux/kernel/softirq.c Sun Jan 26 02:07:49 1997 +++ linux/kernel/softirq.c Wed Feb 26 14:05:16 1997 @@ -22,8 +22,9 @@ #include #include #include +#include -unsigned long intr_count = 0; +atomic_t intr_count = 0; int bh_mask_count[32]; unsigned long bh_active = 0; @@ -31,32 +32,52 @@ void (*bh_base[32])(void); -asmlinkage void do_bottom_half(void) +/* + * This needs to make sure that only one bottom half handler + * is ever active at a time. We do this without locking by + * doing an atomic increment on the intr_count, and checking + * (nonatomically) against 1. Only if it's 1 do we schedule + * the bottom half. + * + * Note that the non-atomicity of the test (as opposed to the + * actual update) means that the test may fail, and _nobody_ + * runs the handlers if there is a race that makes multiple + * CPU's get here at the same time. That's ok, we'll run them + * next time around. + */ +static inline void run_bottom_halves(void) { unsigned long active; unsigned long mask, left; void (**bh)(void); - lock_kernel(); - intr_count=1; + cli(); + active = bh_active & bh_mask; + bh_active &= ~active; sti(); bh = bh_base; - active = bh_active & bh_mask; for (mask = 1, left = ~0 ; left & active ; bh++,mask += mask,left += left) { if (mask & active) { - void (*fn)(void); - bh_active &= ~mask; - fn = *bh; - if (!fn) - goto bad_bh; - fn(); + (*bh)(); } } - goto out; -bad_bh: - printk ("irq.c:bad bottom half entry %08lx\n", mask); -out: - intr_count=0; +} + +/* + * We really shouldn't need to get the kernel lock here, + * but we do it the easy way for now (the scheduler gets + * upset if somebody messes with intr_count without having + * the kernel lock). + * + * Get rid of the kernel lock here at the same time we + * make interrupt handling sane. + */ +asmlinkage void do_bottom_half(void) +{ + lock_kernel(); + atomic_inc(&intr_count); + if (intr_count == 1) + run_bottom_halves(); + atomic_dec(&intr_count); unlock_kernel(); - return; } diff -u --recursive --new-file v2.1.26/linux/kernel/sysctl.c linux/kernel/sysctl.c --- v2.1.26/linux/kernel/sysctl.c Sun Jan 26 02:07:49 1997 +++ linux/kernel/sysctl.c Tue Feb 25 17:12:51 1997 @@ -102,6 +102,7 @@ void *, size_t, void **); extern char binfmt_java_interpreter[], binfmt_java_appletviewer[]; +extern int sysctl_overcommit_memory; #ifdef __sparc__ extern char reboot_command []; @@ -172,6 +173,8 @@ {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, &bdflush_min, &bdflush_max}, + {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory, + sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec}, {0} }; diff -u --recursive --new-file v2.1.26/linux/mm/mmap.c linux/mm/mmap.c --- v2.1.26/linux/mm/mmap.c Sun Jan 26 02:07:49 1997 +++ linux/mm/mmap.c Tue Feb 25 17:12:51 1997 @@ -46,6 +46,8 @@ /* SLAB cache for vm_area_struct's. */ kmem_cache_t *vm_area_cachep; +int sysctl_overcommit_memory; + /* * Check that a process has enough memory to allocate a * new virtual mapping. @@ -58,6 +60,11 @@ * fool it, but this should catch most mistakes. */ long freepages; + + /* sometimes we want to use more memory than we have. */ + if (sysctl_overcommit_memory) + return 1; + freepages = buffermem >> PAGE_SHIFT; freepages += page_cache_size; freepages >>= 1; diff -u --recursive --new-file v2.1.26/linux/net/802/cl2llc.c linux/net/802/cl2llc.c --- v2.1.26/linux/net/802/cl2llc.c Thu Jan 2 05:13:27 1997 +++ linux/net/802/cl2llc.c Tue Feb 25 17:12:51 1997 @@ -21,6 +21,7 @@ * Changes * Alan Cox : Chainsawed into Linux format * Modified to use llc_ names + * Changed callbacks * * This file must be processed by sed before it can be compiled. */ diff -u --recursive --new-file v2.1.26/linux/net/802/cl2llc.pre linux/net/802/cl2llc.pre --- v2.1.26/linux/net/802/cl2llc.pre Thu Jan 2 05:13:27 1997 +++ linux/net/802/cl2llc.pre Tue Feb 25 17:12:51 1997 @@ -23,9 +23,6 @@ * Modified to use llc_ names * Changed callbacks * - * Note: TST/XID stuff is broken at the moment. The - * buffer is freed before being passed up. - * * This file must be processed by sed before it can be compiled. */ diff -u --recursive --new-file v2.1.26/linux/net/802/fddi.c linux/net/802/fddi.c --- v2.1.26/linux/net/802/fddi.c Tue Feb 4 06:44:25 1997 +++ linux/net/802/fddi.c Fri Feb 21 14:58:37 1997 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.1.26/linux/net/802/llc_macinit.c linux/net/802/llc_macinit.c --- v2.1.26/linux/net/802/llc_macinit.c Sun Jan 19 05:47:27 1997 +++ linux/net/802/llc_macinit.c Tue Feb 25 17:12:51 1997 @@ -51,6 +51,8 @@ frameptr fr; int free=1; + lp->inc_skb=NULL; + /* * Truncate buffer to true 802.3 length * [FIXME: move to 802.2 demux] @@ -87,6 +89,7 @@ case TEST_RSP: lp->llc_callbacks|=LLC_TEST_INDICATION; lp->inc_skb=skb; + free=0; break; case XID_CMD: /* @@ -110,12 +113,14 @@ } lp->llc_callbacks|=LLC_XID_INDICATION; lp->inc_skb=skb; + free=0; break; case UI_CMD: lp->llc_callbacks|=LLC_UI_DATA; skb_pull(skb,3); lp->inc_skb=skb; + free=0; break; default: diff -u --recursive --new-file v2.1.26/linux/net/Config.in linux/net/Config.in --- v2.1.26/linux/net/Config.in Sun Feb 2 05:18:48 1997 +++ linux/net/Config.in Tue Feb 25 17:12:51 1997 @@ -31,6 +31,8 @@ fi tristate 'Amateur Radio AX.25 Level 2' CONFIG_AX25 if [ "$CONFIG_AX25" != "n" ]; then +# bool 'AX.25 DAMA Slave support' CONFIG_AX25_DAMA_SLAVE +# bool 'AX.25 DAMA Master support' CONFIG_AX25_DAMA_MASTER dep_tristate 'Amateur Radio NET/ROM' CONFIG_NETROM $CONFIG_AX25 dep_tristate 'Amateur Radio X.25 PLP (Rose)' CONFIG_ROSE $CONFIG_AX25 fi diff -u --recursive --new-file v2.1.26/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c --- v2.1.26/linux/net/appletalk/ddp.c Sun Feb 2 05:18:48 1997 +++ linux/net/appletalk/ddp.c Tue Feb 25 17:12:51 1997 @@ -23,6 +23,7 @@ * Alan Cox : Hooks for PPP (based on the * localtalk hook). * Alan Cox : Posix bits + * Alan Cox/Mike Freeman : Possible fix to NBP problems * Bradford Johnson : IP-over-DDP (experimental) * * This program is free software; you can redistribute it and/or @@ -126,7 +127,8 @@ if ( to->sat_addr.s_net == s->protinfo.af_at.src_net && (to->sat_addr.s_node == s->protinfo.af_at.src_node - ||to->sat_addr.s_node == ATADDR_BCAST )) + ||to->sat_addr.s_node == ATADDR_BCAST + ||to->sat_addr.s_node == ATADDR_ANYNODE )) { break; } @@ -428,8 +430,10 @@ struct atalk_iface *iface; for(iface=atalk_iface_list;iface!=NULL;iface=iface->next) { - if((node==ATADDR_BCAST || iface->address.s_node==node) - && iface->address.s_net==net && !(iface->status&ATIF_PROBE)) + if((node==ATADDR_BCAST || node==ATADDR_ANYNODE + || iface->address.s_node==node) + && iface->address.s_net==net + && !(iface->status&ATIF_PROBE)) return iface; } return NULL; @@ -916,36 +920,6 @@ } /* - * Set 'magic' options for appletalk. If we don't have any this is fine - * as it is. - */ - -static int atalk_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) -{ - return -EOPNOTSUPP; -} - - -/* - * Get any magic options. Comment above applies. - */ - -static int atalk_getsockopt(struct socket *sock, int level, int optname, - char *optval, int *optlen) -{ - return -ENOPROTOOPT; -} - -/* - * Only for connection oriented sockets - ignore - */ - -static int atalk_listen(struct socket *sock, int backlog) -{ - return -EOPNOTSUPP; -} - -/* * Create a socket. Initialise the socket, blank the addresses * set the state. */ @@ -2004,10 +1978,10 @@ atalk_getname, datagram_poll, atalk_ioctl, - atalk_listen, + sock_no_listen, atalk_shutdown, - atalk_setsockopt, - atalk_getsockopt, + sock_no_setsockopt, + sock_no_getsockopt, sock_no_fcntl, atalk_sendmsg, atalk_recvmsg diff -u --recursive --new-file v2.1.26/linux/net/ax25/Makefile linux/net/ax25/Makefile --- v2.1.26/linux/net/ax25/Makefile Sun Nov 10 09:12:57 1996 +++ linux/net/ax25/Makefile Tue Feb 25 17:12:51 1997 @@ -9,7 +9,9 @@ O_TARGET := ax25.o -O_OBJS := sysctl_net_ax25.o ax25_in.o ax25_out.o ax25_route.o ax25_subr.o ax25_timer.o +O_OBJS := ax25_addr.o ax25_dev.o ax25_iface.o ax25_in.o ax25_ip.o ax25_out.o \ + ax25_route.o ax25_std_in.o ax25_std_subr.o ax25_std_timer.o \ + ax25_subr.o ax25_timer.o ax25_uid.o sysctl_net_ax25.o M_OBJS := $(O_TARGET) OX_OBJS += af_ax25.o diff -u --recursive --new-file v2.1.26/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c --- v2.1.26/linux/net/ax25/af_ax25.c Sun Feb 2 05:18:48 1997 +++ linux/net/ax25/af_ax25.c Tue Feb 25 17:12:51 1997 @@ -1,5 +1,5 @@ /* - * AX.25 release 035 + * AX.25 release 036 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. @@ -92,11 +92,7 @@ * Alan(GW4PTS) Added asynchronous support. * Frederic(F1OAT) Support for pseudo-digipeating. * Jonathan(G4KLX) Support for packet forwarding. - * - * To do: - * Restructure the ax25_rcv code to be cleaner/faster and - * copy only when needed. - * Consider better arbitrary protocol support. + * AX.25 036 Jonathan(G4KLX) Major restructuring. */ #include @@ -132,128 +128,15 @@ #include #include -/* - * The null address is defined as a callsign of all spaces with an - * SSID of zero. - */ -ax25_address null_ax25_address = {{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}}; - ax25_cb *volatile ax25_list = NULL; static struct proto_ops ax25_proto_ops; /* - * ax25 -> ascii conversion - */ -char *ax2asc(ax25_address *a) -{ - static char buf[11]; - char c, *s; - int n; - - for (n = 0, s = buf; n < 6; n++) { - c = (a->ax25_call[n] >> 1) & 0x7F; - - if (c != ' ') *s++ = c; - } - - *s++ = '-'; - - if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) { - *s++ = '1'; - n -= 10; - } - - *s++ = n + '0'; - *s++ = '\0'; - - if (*buf == '\0' || *buf == '-') - return "*"; - - return buf; - -} - -/* - * ascii -> ax25 conversion - */ -ax25_address *asc2ax(char *callsign) -{ - static ax25_address addr; - char *s; - int n; - - for (s = callsign, n = 0; n < 6; n++) { - if (*s != '\0' && *s != '-') - addr.ax25_call[n] = *s++; - else - addr.ax25_call[n] = ' '; - addr.ax25_call[n] <<= 1; - addr.ax25_call[n] &= 0xFE; - } - - if (*s++ == '\0') { - addr.ax25_call[6] = 0x00; - return &addr; - } - - addr.ax25_call[6] = *s++ - '0'; - - if (*s != '\0') { - addr.ax25_call[6] *= 10; - addr.ax25_call[6] += *s++ - '0'; - } - - addr.ax25_call[6] <<= 1; - addr.ax25_call[6] &= 0x1E; - - return &addr; -} - -/* - * Compare two ax.25 addresses - */ -int ax25cmp(ax25_address *a, ax25_address *b) -{ - int ct = 0; - - while (ct < 6) { - if ((a->ax25_call[ct] & 0xFE) != (b->ax25_call[ct] & 0xFE)) /* Clean off repeater bits */ - return 1; - ct++; - } - - if ((a->ax25_call[ct] & 0x1E) == (b->ax25_call[ct] & 0x1E)) /* SSID without control bit */ - return 0; - - return 2; /* Partial match */ -} - -/* - * Compare two AX.25 digipeater paths. - */ -static int ax25digicmp(ax25_digi *digi1, ax25_digi *digi2) -{ - int i; - - if (digi1->ndigi != digi2->ndigi) - return 1; - - if (digi1->lastrepeat != digi2->lastrepeat) - return 1; - - for (i = 0; i < digi1->ndigi; i++) - if (ax25cmp(&digi1->calls[i], &digi2->calls[i]) != 0) - return 1; - - return 0; -} - -/* * Free an allocated ax25 control block. This is done to centralise * the MOD count code. */ -static void ax25_free_cb(ax25_cb *ax25) +void ax25_free_cb(ax25_cb *ax25) { if (ax25->digipeat != NULL) { kfree_s(ax25->digipeat, sizeof(ax25_digi)); @@ -300,12 +183,16 @@ */ static void ax25_kill_by_device(struct device *dev) { + ax25_dev *ax25_dev; ax25_cb *s; + if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) + return; + for (s = ax25_list; s != NULL; s = s->next) { - if (s->device == dev) { - s->state = AX25_STATE_0; - s->device = NULL; + if (s->ax25_dev == ax25_dev) { + s->state = AX25_STATE_0; + s->ax25_dev = NULL; if (s->sk != NULL) { s->sk->state = TCP_CLOSE; s->sk->err = ENETUNREACH; @@ -348,7 +235,7 @@ /* * Add a socket to the bound sockets list. */ -static void ax25_insert_socket(ax25_cb *ax25) +void ax25_insert_socket(ax25_cb *ax25) { unsigned long flags; @@ -365,7 +252,7 @@ * Find a socket that wants to accept the SABM we have just * received. */ -static struct sock *ax25_find_listener(ax25_address *addr, int digi, struct device *dev, int type) +struct sock *ax25_find_listener(ax25_address *addr, int digi, struct device *dev, int type) { unsigned long flags; ax25_cb *s; @@ -378,7 +265,7 @@ continue; if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && s->sk->type == type && s->sk->state == TCP_LISTEN) { /* If device is null we match any device */ - if (s->device == NULL || s->device == dev) { + if (s->ax25_dev == NULL || s->ax25_dev->dev == dev) { restore_flags(flags); return s->sk; } @@ -392,7 +279,7 @@ /* * Find an AX.25 socket given both ends. */ -static struct sock *ax25_find_socket(ax25_address *my_addr, ax25_address *dest_addr, int type) +struct sock *ax25_find_socket(ax25_address *my_addr, ax25_address *dest_addr, int type) { ax25_cb *s; unsigned long flags; @@ -416,7 +303,7 @@ * Find an AX.25 control block given both ends. It will only pick up * floating AX.25 control blocks or non Raw socket bound control blocks. */ -static ax25_cb *ax25_find_cb(ax25_address *my_addr, ax25_address *dest_addr, ax25_digi *digi, struct device *dev) +ax25_cb *ax25_find_cb(ax25_address *my_addr, ax25_address *dest_addr, ax25_digi *digi, struct device *dev) { ax25_cb *s; unsigned long flags; @@ -427,7 +314,7 @@ for (s = ax25_list; s != NULL; s = s->next) { if (s->sk != NULL && s->sk->type != SOCK_SEQPACKET) continue; - if (ax25cmp(&s->source_addr, my_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->device == dev) { + if (ax25cmp(&s->source_addr, my_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->ax25_dev->dev == dev) { if (digi != NULL) { if (s->digipeat == NULL && digi->ndigi != 0) continue; @@ -447,7 +334,7 @@ /* * Look for any matching address - RAW sockets can bind to arbitrary names */ -static struct sock *ax25_addr_match(ax25_address *addr) +struct sock *ax25_addr_match(ax25_address *addr) { unsigned long flags; ax25_cb *s; @@ -467,7 +354,7 @@ return NULL; } -static void ax25_send_to_raw(struct sock *sk, struct sk_buff *skb, int proto) +void ax25_send_to_raw(struct sock *sk, struct sk_buff *skb, int proto) { struct sk_buff *copy; @@ -529,7 +416,7 @@ } if (ax25->sk != NULL) { - if (ax25->sk->wmem_alloc > 0 || ax25->sk->rmem_alloc > 0) { /* Defer: outstanding buffers */ + if (ax25->sk->wmem_alloc != 0 || ax25->sk->rmem_alloc != 0) { /* Defer: outstanding buffers */ init_timer(&ax25->timer); ax25->timer.expires = jiffies + 10 * HZ; ax25->timer.function = ax25_destroy_timer; @@ -547,80 +434,6 @@ } /* - * Callsign/UID mapper. This is in kernel space for security on multi-amateur machines. - */ - -ax25_uid_assoc *ax25_uid_list; - -int ax25_uid_policy = 0; - -ax25_address *ax25_findbyuid(uid_t uid) -{ - ax25_uid_assoc *a; - - for (a = ax25_uid_list; a != NULL; a = a->next) { - if (a->uid == uid) - return &a->call; - } - - return NULL; -} - -static int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) -{ - ax25_uid_assoc *a; - - switch (cmd) { - case SIOCAX25GETUID: - for (a = ax25_uid_list; a != NULL; a = a->next) { - if (ax25cmp(&sax->sax25_call, &a->call) == 0) - return a->uid; - } - return -ENOENT; - - case SIOCAX25ADDUID: - if (!suser()) - return -EPERM; - if (ax25_findbyuid(sax->sax25_uid)) - return -EEXIST; - if (sax->sax25_uid == 0) - return -EINVAL; - a = (ax25_uid_assoc *)kmalloc(sizeof(*a), GFP_KERNEL); - if (a == NULL) - return -ENOMEM; - a->uid = sax->sax25_uid; - a->call = sax->sax25_call; - a->next = ax25_uid_list; - ax25_uid_list = a; - return 0; - - case SIOCAX25DELUID: { - ax25_uid_assoc **l; - - if (!suser()) - return -EPERM; - l = &ax25_uid_list; - while ((*l) != NULL) { - if (ax25cmp(&((*l)->call), &(sax->sax25_call)) == 0) { - a = *l; - *l = (*l)->next; - kfree_s(a, sizeof(*a)); - return 0; - } - - l = &((*l)->next); - } - return -ENOENT; - } - - default: - return -EINVAL; - } - - return -EINVAL; /*NOTREACHED */ -} - -/* * dl1bke 960311: set parameters for existing AX.25 connections, * includes a KILL command to abort any connection. * VERY useful for debugging ;-) @@ -628,7 +441,7 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg) { struct ax25_ctl_struct ax25_ctl; - struct device *dev; + ax25_dev *ax25_dev; ax25_cb *ax25; unsigned long flags; int err; @@ -638,10 +451,10 @@ copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl)); - if ((dev = ax25rtr_get_dev(&ax25_ctl.port_addr)) == NULL) + if ((ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr)) == NULL) return -ENODEV; - if ((ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, NULL, dev)) == NULL) + if ((ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, NULL, ax25_dev->dev)) == NULL) return -ENOTCONN; switch (ax25_ctl.cmd) { @@ -659,7 +472,10 @@ ax25->sk->dead = 1; } - ax25_dama_off(ax25); +#ifdef CONFIG_AX25_DAMA_SLAVE + if (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE) + ax25_dama_off(ax25); +#endif ax25_set_timer(ax25); break; @@ -725,19 +541,9 @@ case AX25_PACLEN: if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535) return -EINVAL; -#if 0 - if (ax25_ctl.arg > 256) /* we probably want this */ - printk(KERN_WARNING "ax25_ctl_ioctl: Warning --- huge paclen %d\n", (int)ax25_ctl.arg); -#endif ax25->paclen = ax25_ctl.arg; break; - case AX25_MAXQUEUE: - if (ax25_ctl.arg < 1) - return -EINVAL; - ax25->maxqueue = ax25_ctl.arg; - break; - default: return -EINVAL; } @@ -748,11 +554,11 @@ /* * Create an empty AX.25 control block. */ -static ax25_cb *ax25_create_cb(void) +ax25_cb *ax25_create_cb(void) { ax25_cb *ax25; - if ((ax25 = (ax25_cb *)kmalloc(sizeof(*ax25), GFP_ATOMIC)) == NULL) + if ((ax25 = kmalloc(sizeof(*ax25), GFP_ATOMIC)) == NULL) return NULL; MOD_INC_USE_COUNT; @@ -772,7 +578,6 @@ ax25->t3 = AX25_DEF_T3; ax25->n2 = AX25_DEF_N2; ax25->paclen = AX25_DEF_PACLEN; - ax25->maxqueue= AX25_DEF_MAXQUEUE; ax25->idle = AX25_DEF_IDLE; if (AX25_DEF_AXDEFMODE) { @@ -790,150 +595,30 @@ } /* - * Find out if we are a DAMA slave for this device and count the - * number of connections. - * - * dl1bke 951121 - */ -int ax25_dev_is_dama_slave(struct device *dev) -{ - ax25_cb *ax25; - int count = 0; - - for (ax25 = ax25_list; ax25 != NULL; ax25 = ax25->next) { - if (ax25->device == dev && ax25->dama_slave) { - count++; - break; - } - } - - return count; -} - -/* * Fill in a created AX.25 created control block with the default * values for a particular device. */ -static void ax25_fillin_cb(ax25_cb *ax25, struct device *dev) +void ax25_fillin_cb(ax25_cb *ax25, ax25_dev *ax25_dev) { - ax25->device = dev; + ax25->ax25_dev = ax25_dev; - ax25->rtt = ax25_dev_get_value(dev, AX25_VALUES_T1); - ax25->t1 = ax25_dev_get_value(dev, AX25_VALUES_T1); - ax25->t2 = ax25_dev_get_value(dev, AX25_VALUES_T2); - ax25->t3 = ax25_dev_get_value(dev, AX25_VALUES_T3); - ax25->n2 = ax25_dev_get_value(dev, AX25_VALUES_N2); - ax25->paclen = ax25_dev_get_value(dev, AX25_VALUES_PACLEN); - ax25->maxqueue = ax25_dev_get_value(dev, AX25_VALUES_MAXQUEUE); - ax25->idle = ax25_dev_get_value(dev, AX25_VALUES_IDLE); + ax25->rtt = ax25_dev->values[AX25_VALUES_T1]; + ax25->t1 = ax25_dev->values[AX25_VALUES_T1]; + ax25->t2 = ax25_dev->values[AX25_VALUES_T2]; + ax25->t3 = ax25_dev->values[AX25_VALUES_T3]; + ax25->n2 = ax25_dev->values[AX25_VALUES_N2]; + ax25->paclen = ax25_dev->values[AX25_VALUES_PACLEN]; + ax25->idle = ax25_dev->values[AX25_VALUES_IDLE]; - if (ax25_dev_get_value(dev, AX25_VALUES_AXDEFMODE)) { + if (ax25_dev->values[AX25_VALUES_AXDEFMODE]) { ax25->modulus = AX25_EMODULUS; - ax25->window = ax25_dev_get_value(dev, AX25_VALUES_EWINDOW); + ax25->window = ax25_dev->values[AX25_VALUES_EWINDOW]; } else { ax25->modulus = AX25_MODULUS; - ax25->window = ax25_dev_get_value(dev, AX25_VALUES_WINDOW); - } - - ax25->backoff = ax25_dev_get_value(dev, AX25_VALUES_BACKOFF); -} - -int ax25_send_frame(struct sk_buff *skb, int fragment, ax25_address *src, ax25_address *dest, - ax25_digi *digi, struct device *dev) -{ - ax25_cb *ax25; - - if (skb == NULL) - return 0; - - /* - * Look for an existing connection. - */ - for (ax25 = ax25_list; ax25 != NULL; ax25 = ax25->next) { - if (ax25->sk != NULL && ax25->sk->type != SOCK_SEQPACKET) - continue; - - if (ax25cmp(&ax25->source_addr, src) == 0 && ax25cmp(&ax25->dest_addr, dest) == 0 && ax25->device == dev) { - if (ax25_queue_length(ax25, skb) > ax25->maxqueue * ax25->window) { - kfree_skb(skb, FREE_WRITE); - } else { - ax25_output(ax25, fragment, skb); - } - ax25->idletimer = ax25->idle; - return 1; /* It already existed */ - } - } - - if ((ax25 = ax25_create_cb()) == NULL) - return 0; - - ax25_fillin_cb(ax25, dev); - - ax25->source_addr = *src; - ax25->dest_addr = *dest; - - if (digi != NULL) { - if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { - ax25_free_cb(ax25); - return 0; - } - *ax25->digipeat = *digi; - } else { - ax25_rt_build_path(ax25, dest, dev); - } - - if (ax25_dev_is_dama_slave(ax25->device)) - dama_establish_data_link(ax25); - else - ax25_establish_data_link(ax25); - - /* idle timeouts only for mode vc connections */ - - ax25->idletimer = ax25->idle; - - ax25_insert_socket(ax25); - - ax25->state = AX25_STATE_1; - - ax25_set_timer(ax25); - - ax25_output(ax25, fragment, skb); - - return 1; /* We had to create it */ -} - -/* - * Return the state of an AX.25 link given source, destination, and - * device. - */ -int ax25_link_up(ax25_address *src, ax25_address *dest, struct device *dev) -{ - ax25_cb *ax25; - - for (ax25 = ax25_list; ax25 != NULL; ax25 = ax25->next) { - if (ax25->sk != NULL && ax25->sk->type != SOCK_SEQPACKET) - continue; - - if (ax25cmp(&ax25->source_addr, src) == 0 && ax25cmp(&ax25->dest_addr, dest) == 0 && ax25->device == dev) - return 1; + ax25->window = ax25_dev->values[AX25_VALUES_WINDOW]; } - return 0; -} - -/* - * Find the AX.25 device that matches the hardware address supplied. - */ -struct device *ax25rtr_get_dev(ax25_address *addr) -{ - struct device *dev; - - for (dev = dev_base; dev != NULL; dev = dev->next) - if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25 && - ax25cmp(addr, (ax25_address*) dev->dev_addr) == 0) - return dev; - - return NULL; + ax25->backoff = ax25_dev->values[AX25_VALUES_BACKOFF]; } /* @@ -941,24 +626,22 @@ * AX25 socket object */ -static int ax25_setsockopt(struct socket *sock, int level, int optname, - char *optval, int optlen) +static int ax25_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) { struct sock *sk = sock->sk; - int err, opt; + int opt; if (level != SOL_AX25) - return -EOPNOTSUPP; + return -ENOPROTOOPT; - if (optval == NULL) + if(optlenprotinfo.ax25->modulus == AX25_MODULUS) { if (opt < 1 || opt > 7) @@ -1029,15 +712,18 @@ } } -static int ax25_getsockopt(struct socket *sock, int level, int optname, - char *optval, int *optlen) +static int ax25_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) { struct sock *sk = sock->sk; int val = 0; int err; + int len; if (level != SOL_AX25) - return -EOPNOTSUPP; + return -ENOPROTOOPT; + + if(get_user(len,optlen)) + return -EFAULT; switch (optname) { case AX25_WINDOW: @@ -1088,16 +774,11 @@ return -ENOPROTOOPT; } - if ((err = verify_area(VERIFY_WRITE, optlen, sizeof(int))) != 0) - return err; - - put_user(sizeof(int), optlen); - - if ((err = verify_area(VERIFY_WRITE, optval, sizeof(int))) != 0) - return err; - - put_user(val, (int *)optval); - + len=min(len,sizeof(int)); + if(put_user(len, optlen)) + return -EFAULT; + if(copy_to_user(optval, &val, len)) + return -EFAULT; return 0; } @@ -1114,7 +795,7 @@ return -EOPNOTSUPP; } -static int ax25_create(struct socket *sock, int protocol) +int ax25_create(struct socket *sock, int protocol) { struct sock *sk; ax25_cb *ax25; @@ -1182,7 +863,7 @@ return 0; } -static struct sock *ax25_make_new(struct sock *osk, struct device *dev) +struct sock *ax25_make_new(struct sock *osk, struct device *dev) { struct sock *sk; ax25_cb *ax25; @@ -1195,8 +876,6 @@ return NULL; } - ax25_fillin_cb(ax25, dev); - switch (osk->type) { case SOCK_DGRAM: break; @@ -1233,14 +912,13 @@ ax25->n2 = osk->protinfo.ax25->n2; ax25->idle = osk->protinfo.ax25->idle; ax25->paclen = osk->protinfo.ax25->paclen; + ax25->window = osk->protinfo.ax25->window; - ax25->window = osk->protinfo.ax25->window; - ax25->maxqueue = osk->protinfo.ax25->maxqueue; - + ax25->ax25_dev = osk->protinfo.ax25->ax25_dev; ax25->source_addr = osk->protinfo.ax25->source_addr; if (osk->protinfo.ax25->digipeat != NULL) { - if ((ax25->digipeat = (ax25_digi *)kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { + if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { sk_free(sk); ax25_free_cb(ax25); return NULL; @@ -1282,20 +960,9 @@ break; case AX25_STATE_1: - ax25_send_control(sk->protinfo.ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - sk->protinfo.ax25->state = AX25_STATE_0; - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); - sk->dead = 1; - ax25_destroy_socket(sk->protinfo.ax25); - break; - case AX25_STATE_2: - if (sk->protinfo.ax25->dama_slave) - ax25_send_control(sk->protinfo.ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - else - ax25_send_control(sk->protinfo.ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE); + ax25_clear_queues(sk->protinfo.ax25); + ax25_send_control(sk->protinfo.ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); sk->protinfo.ax25->state = AX25_STATE_0; sk->state = TCP_CLOSE; sk->shutdown |= SEND_SHUTDOWN; @@ -1308,11 +975,16 @@ case AX25_STATE_4: ax25_clear_queues(sk->protinfo.ax25); sk->protinfo.ax25->n2count = 0; - if (!sk->protinfo.ax25->dama_slave) { - ax25_send_control(sk->protinfo.ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - sk->protinfo.ax25->t3timer = 0; - } else { - sk->protinfo.ax25->t3timer = sk->protinfo.ax25->t3; /* DAMA slave timeout */ + switch (sk->protinfo.ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { + case AX25_PROTO_STD: + ax25_send_control(sk->protinfo.ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); + sk->protinfo.ax25->t3timer = 0; + break; +#ifdef AX25_CONFIG_DAMA_SLAVE + case AX25_PROTO_DAMA_SLAVE: + sk->protinfo.ax25->t3timer = sk->protinfo.ax25->t3; /* DAMA slave timeout */ + break; +#endif } sk->protinfo.ax25->t1timer = sk->protinfo.ax25->t1 = ax25_calculate_t1(sk->protinfo.ax25); sk->protinfo.ax25->state = AX25_STATE_2; @@ -1350,8 +1022,8 @@ { struct sock *sk = sock->sk; struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr; - struct device *dev; ax25_address *call; + ax25_dev *ax25_dev = NULL; if (sk->zapped == 0) return -EINVAL; @@ -1375,24 +1047,26 @@ if (addr_len == sizeof(struct full_sockaddr_ax25) && addr->fsa_ax25.sax25_ndigis == 1) { if (ax25cmp(&addr->fsa_digipeater[0], &null_ax25_address) == 0) { - dev = NULL; + ax25_dev = NULL; SOCK_DEBUG(sk, "AX25: bound to any device\n"); } else { - if ((dev = ax25rtr_get_dev(&addr->fsa_digipeater[0])) == NULL) { + if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_digipeater[0])) == NULL) { SOCK_DEBUG(sk, "AX25: bind failed - no device\n"); return -EADDRNOTAVAIL; } - SOCK_DEBUG(sk, "AX25: bound to device %s\n", dev->name); + SOCK_DEBUG(sk, "AX25: bound to device %s\n", ax25_dev->dev->name); } } else { - if ((dev = ax25rtr_get_dev(&addr->fsa_ax25.sax25_call)) == NULL) { + if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_ax25.sax25_call)) == NULL) { SOCK_DEBUG(sk, "AX25: bind failed - no device\n"); return -EADDRNOTAVAIL; } - SOCK_DEBUG(sk, "AX25: bound to device %s\n", dev->name); + SOCK_DEBUG(sk, "AX25: bound to device %s\n", ax25_dev->dev->name); } - ax25_fillin_cb(sk->protinfo.ax25, dev); + if (ax25_dev != NULL) + ax25_fillin_cb(sk->protinfo.ax25, ax25_dev); + ax25_insert_socket(sk->protinfo.ax25); sk->zapped = 0; @@ -1403,8 +1077,7 @@ /* * FIXME: nonblock behaviour looks like it may have a bug. */ -static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, - int addr_len, int flags) +static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) { struct sock *sk = sock->sk; struct sockaddr_ax25 *addr = (struct sockaddr_ax25 *)uaddr; @@ -1444,7 +1117,7 @@ return -EINVAL; if (sk->protinfo.ax25->digipeat == NULL) { - if ((sk->protinfo.ax25->digipeat = (ax25_digi *)kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) + if ((sk->protinfo.ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) return -ENOBUFS; } @@ -1471,14 +1144,14 @@ if (sk->zapped) { if ((err = ax25_rt_autobind(sk->protinfo.ax25, &addr->sax25_call)) < 0) return err; - ax25_fillin_cb(sk->protinfo.ax25, sk->protinfo.ax25->device); + ax25_fillin_cb(sk->protinfo.ax25, sk->protinfo.ax25->ax25_dev); ax25_insert_socket(sk->protinfo.ax25); } else { - if (sk->protinfo.ax25->device == NULL) + if (sk->protinfo.ax25->ax25_dev == NULL) return -EHOSTUNREACH; } - if (sk->type == SOCK_SEQPACKET && ax25_find_cb(&sk->protinfo.ax25->source_addr, &addr->sax25_call, NULL, sk->protinfo.ax25->device) != NULL) + if (sk->type == SOCK_SEQPACKET && ax25_find_cb(&sk->protinfo.ax25->source_addr, &addr->sax25_call, NULL, sk->protinfo.ax25->ax25_dev->dev) != NULL) return -EADDRINUSE; /* Already such a connection */ sk->protinfo.ax25->dest_addr = addr->sax25_call; @@ -1494,10 +1167,16 @@ sock->state = SS_CONNECTING; sk->state = TCP_SYN_SENT; - if (ax25_dev_is_dama_slave(sk->protinfo.ax25->device)) - dama_establish_data_link(sk->protinfo.ax25); - else - ax25_establish_data_link(sk->protinfo.ax25); + switch (sk->protinfo.ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { + case AX25_PROTO_STD: + ax25_std_establish_data_link(sk->protinfo.ax25); + break; +#ifdef CONFIG_AX25_DAMA_SLAVE + case AX25_PROTO_DAMA_SLAVE: + ax25_ds_establish_data_link(sk->protinfo.ax25); + break; +#endif + } sk->protinfo.ax25->state = AX25_STATE_1; ax25_set_timer(sk->protinfo.ax25); /* Start going SABM SABM until a UA or a give up and DM */ @@ -1588,8 +1267,7 @@ return 0; } -static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, - int *uaddr_len, int peer) +static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { struct full_sockaddr_ax25 *sax = (struct full_sockaddr_ax25 *)uaddr; struct sock *sk = sock->sk; @@ -1616,8 +1294,8 @@ sax->fsa_ax25.sax25_ndigis = 1; *uaddr_len = sizeof(struct full_sockaddr_ax25); - if (sk->protinfo.ax25->device != NULL) - memcpy(&sax->fsa_digipeater[0], sk->protinfo.ax25->device->dev_addr, AX25_ADDR_LEN); + if (sk->protinfo.ax25->ax25_dev != NULL) + memcpy(&sax->fsa_digipeater[0], sk->protinfo.ax25->ax25_dev->dev->dev_addr, AX25_ADDR_LEN); else sax->fsa_digipeater[0] = null_ax25_address; } @@ -1625,324 +1303,7 @@ return 0; } -static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_addr, struct packet_type *ptype) -{ - struct sock *make; - struct sock *sk; - int type = 0; - ax25_digi dp, reverse_dp; - ax25_cb *ax25; - ax25_address src, dest; - ax25_address *next_digi = NULL; - struct sock *raw; - int mine = 0; - int dama; - - /* - * Process the AX.25/LAPB frame. - */ - - skb->h.raw = skb->data; - -#ifdef CONFIG_FIREWALL - if (call_in_firewall(PF_AX25, skb->dev, skb->h.raw, NULL) != FW_ACCEPT) { - kfree_skb(skb, FREE_READ); - return 0; - } -#endif - - /* - * Parse the address header. - */ - - if (ax25_parse_addr(skb->data, skb->len, &src, &dest, &dp, &type, &dama) == NULL) { - kfree_skb(skb, FREE_READ); - return 0; - } - - /* - * Ours perhaps ? - */ - if (dp.lastrepeat + 1 < dp.ndigi) { /* Not yet digipeated completely */ - next_digi = &dp.calls[dp.lastrepeat + 1]; - if (ax25cmp(&dp.calls[dp.lastrepeat + 1], dev_addr) == 0) { - struct device *dev_out = dev; - - if ((skb = skb_unshare(skb, GFP_ATOMIC, FREE_READ)) == NULL) - return 0; - - /* We are the digipeater. Mark ourselves as repeated - and throw the packet back out of the same device */ - dp.lastrepeat++; - dp.repeated[(int)dp.lastrepeat] = 1; - - if (ax25_dev_get_value(dev, AX25_VALUES_DIGI) & AX25_DIGI_XBAND) { - while (dp.lastrepeat + 1 < dp.ndigi) { - struct device *dev_scan; - if ((dev_scan = ax25rtr_get_dev(&dp.calls[dp.lastrepeat + 1])) == NULL) - break; - dp.lastrepeat++; - dp.repeated[(int)dp.lastrepeat] = 1; - dev_out = dev_scan; - } - if (dev != dev_out && (ax25_dev_get_value(dev_out, AX25_VALUES_DIGI) & AX25_DIGI_XBAND) == 0) { - kfree_skb(skb, FREE_READ); - return 0; - } - } - - if (dev == dev_out && (ax25_dev_get_value(dev, AX25_VALUES_DIGI) & AX25_DIGI_INBAND) == 0) { - kfree_skb(skb, FREE_READ); - return 0; - } - - build_ax25_addr(skb->data, &src, &dest, &dp, type, AX25_MODULUS); -#ifdef CONFIG_FIREWALL - if (call_fw_firewall(PF_AX25, skb->dev, skb->data, NULL) != FW_ACCEPT) { - kfree_skb(skb, FREE_READ); - return 0; - } -#endif - skb->dev = dev_out; - skb->priority = SOPRI_NORMAL; - - ax25_queue_xmit(skb); - - return 0; - } - } - - /* - * Pull of the AX.25 headers leaving the CTRL/PID bytes - */ - skb_pull(skb, size_ax25_addr(&dp)); - - /* For our port addresses ? */ - if (ax25cmp(&dest, dev_addr) == 0 && dp.lastrepeat + 1 == dp.ndigi) - mine = 1; - - /* Also match on any registered callsign from L3/4 */ - if (!mine && ax25_listen_mine(&dest, dev) && dp.lastrepeat + 1 == dp.ndigi) - mine = 1; - - /* UI frame - bypass LAPB processing */ - if ((*skb->data & ~0x10) == AX25_UI && dp.lastrepeat + 1 == dp.ndigi) { - skb->h.raw = skb->data + 2; /* skip control and pid */ - - if ((raw = ax25_addr_match(&dest)) != NULL) - ax25_send_to_raw(raw, skb, skb->data[1]); - - if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) { - kfree_skb(skb, FREE_READ); - return 0; - } - - /* Now we are pointing at the pid byte */ - switch (skb->data[1]) { -#ifdef CONFIG_INET - case AX25_P_IP: - skb_pull(skb,2); /* drop PID/CTRL */ - skb->h.raw = skb->data; - skb->nh.raw = skb->data; - skb->dev = dev; - skb->pkt_type = PACKET_HOST; - ip_rcv(skb, dev, ptype); /* Note ptype here is the wrong one, fix me later */ - break; - - case AX25_P_ARP: - skb_pull(skb,2); - skb->h.raw = skb->data; - skb->nh.raw = skb->data; - skb->dev = dev; - skb->pkt_type = PACKET_HOST; - arp_rcv(skb, dev, ptype); /* Note ptype here is wrong... */ - break; -#endif - case AX25_P_TEXT: - /* Now find a suitable dgram socket */ - if ((sk = ax25_find_socket(&dest, &src, SOCK_DGRAM)) != NULL) { - if (sk->rmem_alloc >= sk->rcvbuf) { - kfree_skb(skb, FREE_READ); - } else { - /* - * Remove the control and PID. - */ - skb_pull(skb, 2); - if (sock_queue_rcv_skb(sk, skb) != 0) - kfree_skb(skb, FREE_READ); - } - } else { - kfree_skb(skb, FREE_READ); - } - break; - - default: - kfree_skb(skb, FREE_READ); /* Will scan SOCK_AX25 RAW sockets */ - break; - } - - return 0; - } - - /* - * Is connected mode supported on this device ? - * If not, should we DM the incoming frame (except DMs) or - * silently ignore them. For now we stay quiet. - */ - if (!ax25_dev_get_value(dev, AX25_VALUES_CONMODE)) { - kfree_skb(skb, FREE_READ); - return 0; - } - - /* LAPB */ - - /* AX.25 state 1-4 */ - - ax25_digi_invert(&dp, &reverse_dp); - - if ((ax25 = ax25_find_cb(&dest, &src, &reverse_dp, dev)) != NULL) { - /* - * Process the frame. If it is queued up internally it returns one otherwise we - * free it immediately. This routine itself wakes the user context layers so we - * do no further work - */ - if (ax25_process_rx_frame(ax25, skb, type, dama) == 0) - kfree_skb(skb, FREE_READ); - - return 0; - } - - /* AX.25 state 0 (disconnected) */ - - /* a) received not a SABM(E) */ - - if ((*skb->data & ~AX25_PF) != AX25_SABM && (*skb->data & ~AX25_PF) != AX25_SABME) { - /* - * Never reply to a DM. Also ignore any connects for - * addresses that are not our interfaces and not a socket. - */ - if ((*skb->data & ~AX25_PF) != AX25_DM && mine) - ax25_return_dm(dev, &src, &dest, &dp); - - kfree_skb(skb, FREE_READ); - return 0; - } - - /* b) received SABM(E) */ - - if (dp.lastrepeat + 1 == dp.ndigi) - sk = ax25_find_listener(&dest, 0, dev, SOCK_SEQPACKET); - else - sk = ax25_find_listener(next_digi, 1, dev, SOCK_SEQPACKET); - - if (sk != NULL) { - if (sk->ack_backlog == sk->max_ack_backlog || (make = ax25_make_new(sk, dev)) == NULL) { - if (mine) - ax25_return_dm(dev, &src, &dest, &dp); - - kfree_skb(skb, FREE_READ); - return 0; - } - - ax25 = make->protinfo.ax25; - - skb_queue_head(&sk->receive_queue, skb); - - skb->sk = make; - make->state = TCP_ESTABLISHED; - make->pair = sk; - - sk->ack_backlog++; - } else { - if (!mine) { - kfree_skb(skb, FREE_READ); - return 0; - } - - if ((ax25 = ax25_create_cb()) == NULL) { - ax25_return_dm(dev, &src, &dest, &dp); - kfree_skb(skb, FREE_READ); - return 0; - } - - ax25_fillin_cb(ax25, dev); - ax25->idletimer = ax25->idle; - } - - ax25->source_addr = dest; - ax25->dest_addr = src; - - /* - * Sort out any digipeated paths. - */ - if (dp.ndigi != 0 && ax25->digipeat == NULL && (ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { - kfree_skb(skb, FREE_READ); - ax25_destroy_socket(ax25); - return 0; - } - - if (dp.ndigi == 0) { - if (ax25->digipeat != NULL) { - kfree_s(ax25->digipeat, sizeof(ax25_digi)); - ax25->digipeat = NULL; - } - } else { - /* Reverse the source SABM's path */ - *ax25->digipeat = reverse_dp; - } - - if ((*skb->data & ~AX25_PF) == AX25_SABME) { - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25_dev_get_value(dev, AX25_VALUES_EWINDOW); - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25_dev_get_value(dev, AX25_VALUES_WINDOW); - } - - ax25->device = dev; - - ax25_send_control(ax25, AX25_UA, AX25_POLLON, AX25_RESPONSE); - - if (dama) ax25_dama_on(ax25); /* bke 951121 */ - - ax25->dama_slave = dama; - ax25->t3timer = ax25->t3; - ax25->state = AX25_STATE_3; - - ax25_insert_socket(ax25); - - ax25_set_timer(ax25); - - if (sk != NULL) { - if (!sk->dead) - sk->data_ready(sk, skb->len); - } else { - kfree_skb(skb, FREE_READ); - } - - return 0; -} - -/* - * Receive an AX.25 frame via a SLIP interface. - */ -static int kiss_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *ptype) -{ - skb->sk = NULL; /* Initially we don't know who it's for */ - - if ((*skb->data & 0x0F) != 0) { - kfree_skb(skb, FREE_READ); /* Not a KISS data frame */ - return 0; - } - - skb_pull(skb, AX25_KISS_HEADER_LEN); /* Remove the KISS byte */ - - return ax25_rcv(skb, dev, (ax25_address *)dev->dev_addr, ptype); -} - - -static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, - struct scm_cookie *scm) +static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) { struct sock *sk = sock->sk; struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name; @@ -1967,7 +1328,7 @@ return -EPIPE; } - if (sk->protinfo.ax25->device == NULL) + if (sk->protinfo.ax25->ax25_dev == NULL) return -ENETUNREACH; if (usax != NULL) { @@ -2020,7 +1381,7 @@ SOCK_DEBUG(sk, "AX.25: sendto: building packet.\n"); /* Assume the worst case */ - size = len + 3 + size_ax25_addr(dp) + AX25_BPQ_HEADER_LEN; + size = len + 3 + ax25_addr_size(dp) + AX25_BPQ_HEADER_LEN; if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) return err; @@ -2045,11 +1406,11 @@ return -ENOTCONN; } - ax25_output(sk->protinfo.ax25, 1, skb); /* Shove it onto the queue and kick */ + ax25_output(sk->protinfo.ax25, sk->protinfo.ax25->paclen, skb); /* Shove it onto the queue and kick */ return len; } else { - asmptr = skb_push(skb, 1 + size_ax25_addr(dp)); + asmptr = skb_push(skb, 1 + ax25_addr_size(dp)); SOCK_DEBUG(sk, "Building AX.25 Header (dp=%p).\n", dp); @@ -2057,7 +1418,7 @@ SOCK_DEBUG(sk, "Num digipeaters=%d\n", dp->ndigi); /* Build an AX.25 header */ - asmptr += (lv = build_ax25_addr(asmptr, &sk->protinfo.ax25->source_addr, &sax.sax25_call, dp, AX25_COMMAND, AX25_MODULUS)); + asmptr += (lv = ax25_addr_build(asmptr, &sk->protinfo.ax25->source_addr, &sax.sax25_call, dp, AX25_COMMAND, AX25_MODULUS)); SOCK_DEBUG(sk, "Built header (%d bytes)\n",lv); @@ -2068,7 +1429,7 @@ *asmptr = AX25_UI; /* Datagram frames go straight out of the door as UI */ - skb->dev = sk->protinfo.ax25->device; + skb->dev = sk->protinfo.ax25->ax25_dev->dev; skb->priority = SOPRI_NORMAL; ax25_queue_xmit(skb); @@ -2077,8 +1438,7 @@ } } -static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, - struct scm_cookie *scm) +static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm) { struct sock *sk = sock->sk; struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name; @@ -2120,7 +1480,7 @@ ax25_digi digi; ax25_address dest; - ax25_parse_addr(skb->data, skb->len, NULL, &dest, &digi, NULL, &dama); + ax25_addr_parse(skb->data, skb->len, NULL, &dest, &digi, NULL, &dama); sax->sax25_family = AF_AX25; /* We set this correctly, even though we may not let the @@ -2275,11 +1635,9 @@ return 0; } - static int ax25_get_info(char *buffer, char **start, off_t offset, int length, int dummy) { ax25_cb *ax25; - struct device *dev; const char *devname; int len = 0; off_t pos = 0; @@ -2287,13 +1645,13 @@ cli(); - len += sprintf(buffer, "dest_addr src_addr dev st vs vr va t1 t2 t3 idle n2 rtt wnd paclen dama Snd-Q Rcv-Q\n"); + len += sprintf(buffer, "dest_addr src_addr dev st vs vr va t1 t2 t3 idle n2 rtt wnd paclen Snd-Q Rcv-Q\n"); for (ax25 = ax25_list; ax25 != NULL; ax25 = ax25->next) { - if ((dev = ax25->device) == NULL) + if (ax25->ax25_dev == NULL) devname = "???"; else - devname = dev->name; + devname = ax25->ax25_dev->dev->name; len += sprintf(buffer + len, "%-9s ", ax2asc(&ax25->dest_addr)); @@ -2314,8 +1672,6 @@ ax25->window, ax25->paclen); - len += sprintf(buffer + len, " %s", ax25->dama_slave ? " slave" : " no"); - if (ax25->sk != NULL) { len += sprintf(buffer + len, " %5d %5d\n", ax25->sk->wmem_alloc, @@ -2379,7 +1735,7 @@ { 0, /* MUTTER ntohs(ETH_P_AX25),*/ 0, /* copy */ - kiss_rcv, + ax25_kiss_rcv, NULL, NULL, }; @@ -2423,7 +1779,7 @@ PROC_NET_AX25_CALLS, 10, "ax25_calls", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, - ax25_cs_get_info + ax25_uid_get_info }; #endif @@ -2441,157 +1797,9 @@ proc_net_register(&proc_ax25_calls); #endif - printk(KERN_INFO "G4KLX/GW4PTS AX.25 for Linux. Version 0.35 for Linux NET3.038 (Linux 2.1)\n"); -} - -/* - * A small shim to dev_queue_xmit to add the KISS control byte, and do - * any packet forwarding in operation. - */ -void ax25_queue_xmit(struct sk_buff *skb) -{ - unsigned char *ptr; - -#ifdef CONFIG_FIREWALL - if (call_out_firewall(PF_AX25, skb->dev, skb->data, NULL) != FW_ACCEPT) { - dev_kfree_skb(skb, FREE_WRITE); - return; - } -#endif - - skb->protocol = htons(ETH_P_AX25); - skb->dev = ax25_fwd_dev(skb->dev); - skb->arp = 1; - - ptr = skb_push(skb, 1); - *ptr++ = 0x00; /* KISS */ - - dev_queue_xmit(skb); -} - -/* - * IP over AX.25 encapsulation. - */ - -/* - * Shove an AX.25 UI header on an IP packet and handle ARP - */ - -#ifdef CONFIG_INET - -int ax25_encapsulate(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, - void *saddr, unsigned len) -{ - /* header is an AX.25 UI frame from us to them */ - unsigned char *buff = skb_push(skb, AX25_HEADER_LEN); - - *buff++ = 0; /* KISS DATA */ - - if (daddr != NULL) - memcpy(buff, daddr, dev->addr_len); /* Address specified */ - - buff[6] &= ~AX25_CBIT; - buff[6] &= ~AX25_EBIT; - buff[6] |= AX25_SSSID_SPARE; - buff += AX25_ADDR_LEN; - - if (saddr != NULL) - memcpy(buff, saddr, dev->addr_len); - else - memcpy(buff, dev->dev_addr, dev->addr_len); - - buff[6] &= ~AX25_CBIT; - buff[6] |= AX25_EBIT; - buff[6] |= AX25_SSSID_SPARE; - buff += AX25_ADDR_LEN; - - *buff++ = AX25_UI; /* UI */ - - /* Append a suitable AX.25 PID */ - switch (type) { - case ETH_P_IP: - *buff++ = AX25_P_IP; - break; - case ETH_P_ARP: - *buff++ = AX25_P_ARP; - break; - default: - printk(KERN_ERR "AX.25 wrong protocol type 0x%x2.2\n", type); - *buff++ = 0; - break; - } - - if (daddr != NULL) - return AX25_HEADER_LEN; - - return -AX25_HEADER_LEN; /* Unfinished header */ + printk(KERN_INFO "G4KLX/GW4PTS AX.25 for Linux. Version 0.36 for Linux NET3.038 (Linux 2.1)\n"); } -int ax25_rebuild_header(struct sk_buff *skb) -{ - struct sk_buff *ourskb; - int mode; - unsigned char *bp = skb->data; - struct device *dev = skb->dev; - - if (arp_find(bp + 1, skb)) - return 1; - - if (bp[16] == AX25_P_IP) { - mode = ax25_ip_mode_get((ax25_address *)(bp + 1), dev); - if (mode == 'V' || (mode == ' ' && ax25_dev_get_value(dev, AX25_VALUES_IPDEFMODE))) { - /* - * We clone the buffer and release the original thereby - * keeping it straight - * - * Note: we report 1 back so the caller will - * not feed the frame direct to the physical device - * We don't want that to happen. (It won't be upset - * as we have pulled the frame from the queue by - * freeing it). - */ - if ((ourskb = skb_clone(skb, GFP_ATOMIC)) == NULL) { - dev_kfree_skb(skb, FREE_WRITE); - return 1; - } - - if (skb->sk != NULL) - skb_set_owner_w(ourskb, skb->sk); - - kfree_skb(skb, FREE_WRITE); - - skb_pull(ourskb, AX25_HEADER_LEN - 1); /* Keep PID */ - - ax25_send_frame(ourskb, 1, (ax25_address *)(bp + 8), (ax25_address *)(bp + 1), NULL, dev); - - return 1; - } - } - - bp[7] &= ~AX25_CBIT; - bp[7] &= ~AX25_EBIT; - bp[7] |= AX25_SSSID_SPARE; - - bp[14] &= ~AX25_CBIT; - bp[14] |= AX25_EBIT; - bp[14] |= AX25_SSSID_SPARE; - - /* - * dl1bke 960317: we use ax25_queue_xmit here to allow mode datagram - * over ethernet. I don't know if this is valid, though. - */ - ax25_dg_build_path(skb, (ax25_address *)(bp + 1), dev); - - skb->dev = dev; - skb->priority = SOPRI_NORMAL; - - ax25_queue_xmit(skb); - - return 1; -} - -#endif - #ifdef MODULE int init_module(void) { @@ -2609,6 +1817,8 @@ proc_net_unregister(PROC_NET_AX25_ROUTE); #endif ax25_rt_free(); + ax25_uid_free(); + ax25_dev_free(); ax25_unregister_sysctl(); diff -u --recursive --new-file v2.1.26/linux/net/ax25/ax25_addr.c linux/net/ax25/ax25_addr.c --- v2.1.26/linux/net/ax25/ax25_addr.c Wed Dec 31 16:00:00 1969 +++ linux/net/ax25/ax25_addr.c Tue Feb 25 17:12:51 1997 @@ -0,0 +1,311 @@ +/* + * AX.25 release 036 + * + * This is ALPHA test software. This code may break your machine, randomly fail to work with new + * releases, misbehave and/or generally screw up. It might even work. + * + * This code REQUIRES 2.1.15 or higher/ NET3.038 + * + * This module: + * This module is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Most of this code is based on the SDL diagrams published in the 7th + * ARRL Computer Networking Conference papers. The diagrams have mistakes + * in them, but are mostly correct. Before you modify the code could you + * read the SDL diagrams as the code is not obvious and probably very + * easy to break; + * + * History + * AX.25 036 Jonathan(G4KLX) Split from ax25_subr.c. + */ + +#include +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The null address is defined as a callsign of all spaces with an + * SSID of zero. + */ +ax25_address null_ax25_address = {{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}}; + +/* + * ax25 -> ascii conversion + */ +char *ax2asc(ax25_address *a) +{ + static char buf[11]; + char c, *s; + int n; + + for (n = 0, s = buf; n < 6; n++) { + c = (a->ax25_call[n] >> 1) & 0x7F; + + if (c != ' ') *s++ = c; + } + + *s++ = '-'; + + if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) { + *s++ = '1'; + n -= 10; + } + + *s++ = n + '0'; + *s++ = '\0'; + + if (*buf == '\0' || *buf == '-') + return "*"; + + return buf; + +} + +/* + * ascii -> ax25 conversion + */ +ax25_address *asc2ax(char *callsign) +{ + static ax25_address addr; + char *s; + int n; + + for (s = callsign, n = 0; n < 6; n++) { + if (*s != '\0' && *s != '-') + addr.ax25_call[n] = *s++; + else + addr.ax25_call[n] = ' '; + addr.ax25_call[n] <<= 1; + addr.ax25_call[n] &= 0xFE; + } + + if (*s++ == '\0') { + addr.ax25_call[6] = 0x00; + return &addr; + } + + addr.ax25_call[6] = *s++ - '0'; + + if (*s != '\0') { + addr.ax25_call[6] *= 10; + addr.ax25_call[6] += *s++ - '0'; + } + + addr.ax25_call[6] <<= 1; + addr.ax25_call[6] &= 0x1E; + + return &addr; +} + +/* + * Compare two ax.25 addresses + */ +int ax25cmp(ax25_address *a, ax25_address *b) +{ + int ct = 0; + + while (ct < 6) { + if ((a->ax25_call[ct] & 0xFE) != (b->ax25_call[ct] & 0xFE)) /* Clean off repeater bits */ + return 1; + ct++; + } + + if ((a->ax25_call[ct] & 0x1E) == (b->ax25_call[ct] & 0x1E)) /* SSID without control bit */ + return 0; + + return 2; /* Partial match */ +} + +/* + * Compare two AX.25 digipeater paths. + */ +int ax25digicmp(ax25_digi *digi1, ax25_digi *digi2) +{ + int i; + + if (digi1->ndigi != digi2->ndigi) + return 1; + + if (digi1->lastrepeat != digi2->lastrepeat) + return 1; + + for (i = 0; i < digi1->ndigi; i++) + if (ax25cmp(&digi1->calls[i], &digi2->calls[i]) != 0) + return 1; + + return 0; +} + +/* + * Given an AX.25 address pull of to, from, digi list, command/response and the start of data + * + */ +unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags, int *dama) +{ + int d = 0; + + if (len < 14) return NULL; + + if (flags != NULL) { + *flags = 0; + + if (buf[6] & AX25_CBIT) + *flags = AX25_COMMAND; + if (buf[13] & AX25_CBIT) + *flags = AX25_RESPONSE; + } + + if (dama != NULL) + *dama = ~buf[13] & AX25_DAMA_FLAG; + + /* Copy to, from */ + if (dest != NULL) + memcpy(dest, buf + 0, AX25_ADDR_LEN); + + if (src != NULL) + memcpy(src, buf + 7, AX25_ADDR_LEN); + + buf += 2 * AX25_ADDR_LEN; + len -= 2 * AX25_ADDR_LEN; + digi->lastrepeat = -1; + digi->ndigi = 0; + + while (!(buf[-1] & AX25_EBIT)) { + if (d >= AX25_MAX_DIGIS) return NULL; /* Max of 6 digis */ + if (len < 7) return NULL; /* Short packet */ + + if (digi != NULL) { + memcpy(&digi->calls[d], buf, AX25_ADDR_LEN); + digi->ndigi = d + 1; + if (buf[6] & AX25_HBIT) { + digi->repeated[d] = 1; + digi->lastrepeat = d; + } else { + digi->repeated[d] = 0; + } + } + + buf += AX25_ADDR_LEN; + len -= AX25_ADDR_LEN; + d++; + } + + return buf; +} + +/* + * Assemble an AX.25 header from the bits + */ +int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, ax25_digi *d, int flag, int modulus) +{ + int len = 0; + int ct = 0; + + memcpy(buf, dest, AX25_ADDR_LEN); + buf[6] &= ~(AX25_EBIT | AX25_CBIT); + buf[6] |= AX25_SSSID_SPARE; + + if (flag == AX25_COMMAND) buf[6] |= AX25_CBIT; + + buf += AX25_ADDR_LEN; + len += AX25_ADDR_LEN; + + memcpy(buf, src, AX25_ADDR_LEN); + buf[6] &= ~(AX25_EBIT | AX25_CBIT); + buf[6] &= ~AX25_SSSID_SPARE; + + if (modulus == AX25_MODULUS) + buf[6] |= AX25_SSSID_SPARE; + else + buf[6] |= AX25_ESSID_SPARE; + + if (flag == AX25_RESPONSE) buf[6] |= AX25_CBIT; + + /* + * Fast path the normal digiless path + */ + if (d == NULL || d->ndigi == 0) { + buf[6] |= AX25_EBIT; + return 2 * AX25_ADDR_LEN; + } + + buf += AX25_ADDR_LEN; + len += AX25_ADDR_LEN; + + while (ct < d->ndigi) { + memcpy(buf, &d->calls[ct], AX25_ADDR_LEN); + + if (d->repeated[ct]) + buf[6] |= AX25_HBIT; + else + buf[6] &= ~AX25_HBIT; + + buf[6] &= ~AX25_EBIT; + buf[6] |= AX25_SSSID_SPARE; + + buf += AX25_ADDR_LEN; + len += AX25_ADDR_LEN; + ct++; + } + + buf[-1] |= AX25_EBIT; + + return len; +} + +int ax25_addr_size(ax25_digi *dp) +{ + if (dp == NULL) + return 2 * AX25_ADDR_LEN; + + return AX25_ADDR_LEN * (2 + dp->ndigi); +} + +/* + * Reverse Digipeat List. May not pass both parameters as same struct + */ +void ax25_digi_invert(ax25_digi *in, ax25_digi *out) +{ + int ct = 0; + + out->ndigi = in->ndigi; + out->lastrepeat = in->ndigi - in->lastrepeat - 2; + + /* Invert the digipeaters */ + + while (ct < in->ndigi) { + out->calls[ct] = in->calls[in->ndigi - ct - 1]; + if (ct <= out->lastrepeat) { + out->calls[ct].ax25_call[6] |= AX25_HBIT; + out->repeated[ct] = 1; + } else { + out->calls[ct].ax25_call[6] &= ~AX25_HBIT; + out->repeated[ct] = 0; + } + ct++; + } +} + +#endif diff -u --recursive --new-file v2.1.26/linux/net/ax25/ax25_dev.c linux/net/ax25/ax25_dev.c --- v2.1.26/linux/net/ax25/ax25_dev.c Wed Dec 31 16:00:00 1969 +++ linux/net/ax25/ax25_dev.c Tue Feb 25 17:12:51 1997 @@ -0,0 +1,215 @@ +/* + * AX.25 release 036 + * + * This is ALPHA test software. This code may break your machine, randomly fail to work with new + * releases, misbehave and/or generally screw up. It might even work. + * + * This code REQUIRES 2.1.15 or higher/ NET3.038 + * + * This module: + * This module is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Other kernels modules in this kit are generally BSD derived. See the copyright headers. + * + * + * History + * AX.25 036 Jonathan(G4KLX) Split from ax25_route.c. + */ + +#include +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ax25_dev *ax25_dev_list = NULL; + +ax25_dev *ax25_dev_ax25dev(struct device *dev) +{ + ax25_dev *ax25_dev; + + for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) + if (ax25_dev->dev == dev) + return ax25_dev; + + return NULL; +} + +ax25_dev *ax25_addr_ax25dev(ax25_address *addr) +{ + ax25_dev *ax25_dev; + + for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) + if (ax25cmp(addr, (ax25_address *)ax25_dev->dev->dev_addr) == 0) + return ax25_dev; + + return NULL; +} + +/* + * This is called when an interface is brought up. These are + * reasonable defaults. + */ +void ax25_dev_device_up(struct device *dev) +{ + ax25_dev *ax25_dev; + unsigned long flags; + + if ((ax25_dev = kmalloc(sizeof(*ax25_dev), GFP_ATOMIC)) == NULL) { + printk(KERN_ERR "ax25_dev_device_up out of memory\n"); + return; + } + + ax25_unregister_sysctl(); + + ax25_dev->dev = dev; + ax25_dev->forward = NULL; + + ax25_dev->values[AX25_VALUES_IPDEFMODE] = AX25_DEF_IPDEFMODE; + ax25_dev->values[AX25_VALUES_AXDEFMODE] = AX25_DEF_AXDEFMODE; + ax25_dev->values[AX25_VALUES_BACKOFF] = AX25_DEF_BACKOFF; + ax25_dev->values[AX25_VALUES_CONMODE] = AX25_DEF_CONMODE; + ax25_dev->values[AX25_VALUES_WINDOW] = AX25_DEF_WINDOW; + ax25_dev->values[AX25_VALUES_EWINDOW] = AX25_DEF_EWINDOW; + ax25_dev->values[AX25_VALUES_T1] = AX25_DEF_T1; + ax25_dev->values[AX25_VALUES_T2] = AX25_DEF_T2; + ax25_dev->values[AX25_VALUES_T3] = AX25_DEF_T3; + ax25_dev->values[AX25_VALUES_IDLE] = AX25_DEF_IDLE; + ax25_dev->values[AX25_VALUES_N2] = AX25_DEF_N2; + ax25_dev->values[AX25_VALUES_PACLEN] = AX25_DEF_PACLEN; + ax25_dev->values[AX25_VALUES_PROTOCOL] = AX25_DEF_PROTOCOL; + + save_flags(flags); cli(); + ax25_dev->next = ax25_dev_list; + ax25_dev_list = ax25_dev; + restore_flags(flags); + + ax25_register_sysctl(); +} + +void ax25_dev_device_down(struct device *dev) +{ + ax25_dev *s, *ax25_dev; + unsigned long flags; + + if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) + return; + + ax25_unregister_sysctl(); + + save_flags(flags); cli(); + + /* + * Remove any packet forwarding that points to this device. + */ + for (s = ax25_dev_list; s != NULL; s = s->next) + if (s->forward == dev) + s->forward = NULL; + + if ((s = ax25_dev_list) == ax25_dev) { + ax25_dev_list = s->next; + restore_flags(flags); + kfree_s(ax25_dev, sizeof(ax25_dev)); + ax25_register_sysctl(); + return; + } + + while (s != NULL && s->next != NULL) { + if (s->next == ax25_dev) { + s->next = ax25_dev->next; + restore_flags(flags); + kfree_s(ax25_dev, sizeof(ax25_dev)); + ax25_register_sysctl(); + return; + } + + s = s->next; + } + + restore_flags(flags); + ax25_register_sysctl(); +} + +int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd) +{ + ax25_dev *ax25_dev, *fwd_dev; + + if ((ax25_dev = ax25_addr_ax25dev(&fwd->port_from)) == NULL) + return -EINVAL; + + switch (cmd) { + case SIOCAX25ADDFWD: + if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL) + return -EINVAL; + if (ax25_dev->forward != NULL) + return -EINVAL; + ax25_dev->forward = fwd_dev->dev; + break; + + case SIOCAX25DELFWD: + if (ax25_dev->forward == NULL) + return -EINVAL; + ax25_dev->forward = NULL; + break; + + default: + return -EINVAL; + } + + return 0; +} + +struct device *ax25_fwd_dev(struct device *dev) +{ + ax25_dev *ax25_dev; + + if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) + return dev; + + if (ax25_dev->forward == NULL) + return dev; + + return ax25_dev->forward; +} + +#ifdef MODULE + +/* + * Free all memory associated with device structures. + */ +void ax25_dev_free(void) +{ + ax25_dev *s, *ax25_dev = ax25_dev_list; + + while (ax25_dev != NULL) { + s = ax25_dev; + ax25_dev = ax25_dev->next; + + kfree_s(s, sizeof(ax25_dev)); + } +} + +#endif + +#endif diff -u --recursive --new-file v2.1.26/linux/net/ax25/ax25_iface.c linux/net/ax25/ax25_iface.c --- v2.1.26/linux/net/ax25/ax25_iface.c Wed Dec 31 16:00:00 1969 +++ linux/net/ax25/ax25_iface.c Tue Feb 25 17:12:51 1997 @@ -0,0 +1,282 @@ +/* + * AX.25 release 036 + * + * This is ALPHA test software. This code may break your machine, randomly fail to work with new + * releases, misbehave and/or generally screw up. It might even work. + * + * This code REQUIRES 2.1.15 or higher/ NET3.038 + * + * This module: + * This module is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * History + * AX.25 036 Jonathan(G4KLX) Split from ax25_timer.c. + */ + +#include +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct protocol_struct { + struct protocol_struct *next; + unsigned int pid; + int (*func)(struct sk_buff *, ax25_cb *); +} *protocol_list = NULL; + +static struct linkfail_struct { + struct linkfail_struct *next; + void (*func)(ax25_address *, struct device *); +} *linkfail_list = NULL; + +static struct listen_struct { + struct listen_struct *next; + ax25_address callsign; + struct device *dev; +} *listen_list = NULL; + +int ax25_protocol_register(unsigned int pid, int (*func)(struct sk_buff *, ax25_cb *)) +{ + struct protocol_struct *protocol; + unsigned long flags; + + if (pid == AX25_P_TEXT || pid == AX25_P_SEGMENT) + return 0; +#ifdef CONFIG_INET + if (pid == AX25_P_IP || pid == AX25_P_ARP) + return 0; +#endif + if ((protocol = kmalloc(sizeof(*protocol), GFP_ATOMIC)) == NULL) + return 0; + + protocol->pid = pid; + protocol->func = func; + + save_flags(flags); + cli(); + + protocol->next = protocol_list; + protocol_list = protocol; + + restore_flags(flags); + + return 1; +} + +void ax25_protocol_release(unsigned int pid) +{ + struct protocol_struct *s, *protocol = protocol_list; + unsigned long flags; + + if (protocol == NULL) + return; + + save_flags(flags); + cli(); + + if (protocol->pid == pid) { + protocol_list = protocol->next; + restore_flags(flags); + kfree_s(protocol, sizeof(struct protocol_struct)); + return; + } + + while (protocol != NULL && protocol->next != NULL) { + if (protocol->next->pid == pid) { + s = protocol->next; + protocol->next = protocol->next->next; + restore_flags(flags); + kfree_s(s, sizeof(struct protocol_struct)); + return; + } + + protocol = protocol->next; + } + + restore_flags(flags); +} + +int ax25_linkfail_register(void (*func)(ax25_address *, struct device *)) +{ + struct linkfail_struct *linkfail; + unsigned long flags; + + if ((linkfail = kmalloc(sizeof(*linkfail), GFP_ATOMIC)) == NULL) + return 0; + + linkfail->func = func; + + save_flags(flags); + cli(); + + linkfail->next = linkfail_list; + linkfail_list = linkfail; + + restore_flags(flags); + + return 1; +} + +void ax25_linkfail_release(void (*func)(ax25_address *, struct device *)) +{ + struct linkfail_struct *s, *linkfail = linkfail_list; + unsigned long flags; + + if (linkfail == NULL) + return; + + save_flags(flags); + cli(); + + if (linkfail->func == func) { + linkfail_list = linkfail->next; + restore_flags(flags); + kfree_s(linkfail, sizeof(struct linkfail_struct)); + return; + } + + while (linkfail != NULL && linkfail->next != NULL) { + if (linkfail->next->func == func) { + s = linkfail->next; + linkfail->next = linkfail->next->next; + restore_flags(flags); + kfree_s(s, sizeof(struct linkfail_struct)); + return; + } + + linkfail = linkfail->next; + } + + restore_flags(flags); +} + +int ax25_listen_register(ax25_address *callsign, struct device *dev) +{ + struct listen_struct *listen; + unsigned long flags; + + if (ax25_listen_mine(callsign, dev)) + return 0; + + if ((listen = kmalloc(sizeof(*listen), GFP_ATOMIC)) == NULL) + return 0; + + listen->callsign = *callsign; + listen->dev = dev; + + save_flags(flags); + cli(); + + listen->next = listen_list; + listen_list = listen; + + restore_flags(flags); + + return 1; +} + +void ax25_listen_release(ax25_address *callsign, struct device *dev) +{ + struct listen_struct *s, *listen = listen_list; + unsigned long flags; + + if (listen == NULL) + return; + + save_flags(flags); + cli(); + + if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) { + listen_list = listen->next; + restore_flags(flags); + kfree_s(listen, sizeof(struct listen_struct)); + return; + } + + while (listen != NULL && listen->next != NULL) { + if (ax25cmp(&listen->next->callsign, callsign) == 0 && listen->next->dev == dev) { + s = listen->next; + listen->next = listen->next->next; + restore_flags(flags); + kfree_s(s, sizeof(struct listen_struct)); + return; + } + + listen = listen->next; + } + + restore_flags(flags); +} + +int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *) +{ + struct protocol_struct *protocol; + + for (protocol = protocol_list; protocol != NULL; protocol = protocol->next) + if (protocol->pid == pid) + return protocol->func; + + return NULL; +} + +int ax25_listen_mine(ax25_address *callsign, struct device *dev) +{ + struct listen_struct *listen; + + for (listen = listen_list; listen != NULL; listen = listen->next) + if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL)) + return 1; + + return 0; +} + +void ax25_link_failed(ax25_address *callsign, struct device *dev) +{ + struct linkfail_struct *linkfail; + + for (linkfail = linkfail_list; linkfail != NULL; linkfail = linkfail->next) + (linkfail->func)(callsign, dev); +} + +/* + * Return the state of an AX.25 link given source, destination, and + * device. + */ +int ax25_link_up(ax25_address *src, ax25_address *dest, ax25_digi *digi, struct device *dev) +{ + return ax25_find_cb(src, dest, digi, dev) != NULL; +} + +int ax25_protocol_is_registered(unsigned int pid) +{ + struct protocol_struct *protocol; + + for (protocol = protocol_list; protocol != NULL; protocol = protocol->next) + if (protocol->pid == pid) + return 1; + + return 0; +} + +#endif diff -u --recursive --new-file v2.1.26/linux/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c --- v2.1.26/linux/net/ax25/ax25_in.c Sun Feb 2 05:18:48 1997 +++ linux/net/ax25/ax25_in.c Tue Feb 25 17:12:51 1997 @@ -1,5 +1,5 @@ /* - * AX.25 release 035 + * AX.25 release 036 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. @@ -36,6 +36,7 @@ * AX.25 033 Jonathan(G4KLX) Remove auto-router. * Modularisation changes. * AX.25 035 Hans(PE1AYX) Fixed interface to IP layer. + * AX.25 036 Jonathan(G4KLX) Move DAMA code into own file. */ #include @@ -54,16 +55,16 @@ #include #include #include +#include #include #include /* For ip_rcv */ +#include /* For arp_rcv */ #include #include #include #include #include -static int ax25_rx_iframe(ax25_cb *, struct sk_buff *); - /* * Given a fragment, queue it on the fragment queue and if the fragment * is complete, send it back to ax25_rx_iframe. @@ -90,7 +91,7 @@ return 1; } - skbn->dev = ax25->device; + skbn->dev = ax25->ax25_dev->dev; skb_reserve(skbn, AX25_MAX_HEADER_LEN); @@ -143,7 +144,7 @@ * This is where all valid I frames are sent to, to be dispatched to * whichever protocol requires them. */ -static int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb) +int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb) { int (*func)(struct sk_buff *, ax25_cb *); volatile int queued = 0; @@ -160,9 +161,9 @@ skb_pull(skb, 1); /* Remove PID */ skb->h.raw = skb->data; skb->nh.raw = skb->data; - skb->dev = ax25->device; + skb->dev = ax25->ax25_dev->dev; skb->pkt_type = PACKET_HOST; - ip_rcv(skb, ax25->device, NULL); /* Wrong ptype */ + ip_rcv(skb, skb->dev, NULL); /* Wrong ptype */ return 1; } #endif @@ -176,7 +177,7 @@ return (*func)(skb, ax25); } - if (ax25->sk != NULL && ax25_dev_get_value(ax25->device, AX25_VALUES_TEXT) && ax25->sk->protocol == pid) { + if (ax25->sk != NULL && ax25->ax25_dev->values[AX25_VALUES_CONMODE] == 2 && ax25->sk->protocol == pid) { if (sock_queue_rcv_skb(ax25->sk, skb) == 0) queued = 1; else @@ -187,552 +188,304 @@ } /* - * State machine for state 1, Awaiting Connection State. - * The handling of the timer(s) is in file ax25_timer.c. - * Handling of state 0 and connection release is in ax25.c. + * Higher level upcall for a LAPB frame */ -static int ax25_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type, int dama) +static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type) { - switch (frametype) { - case AX25_SABM: - ax25->modulus = AX25_MODULUS; - ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW); - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - break; + int queued = 0; - case AX25_SABME: - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW); - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - break; + if (ax25->state == AX25_STATE_0) + return 0; - case AX25_DISC: - ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); - break; + del_timer(&ax25->timer); - case AX25_UA: - if (pf || dama) { - if (dama) ax25_dama_on(ax25); /* bke */ - ax25_calculate_rtt(ax25); - ax25->t1timer = 0; - ax25->t3timer = ax25->t3; - ax25->idletimer = ax25->idle; - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; - ax25->state = AX25_STATE_3; - ax25->n2count = 0; - ax25->dama_slave = dama; /* bke */ - if (ax25->sk != NULL) { - ax25->sk->state = TCP_ESTABLISHED; - /* For WAIT_SABM connections we will produce an accept ready socket here */ - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - } - } + switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { + case AX25_PROTO_STD: + queued = ax25_std_frame_in(ax25, skb, type); + break; +#ifdef CONFIG_AX25_DAMA_SLAVE + case AX25_PROTO_DAMA_SLAVE: + queued = ax25_ds_frame_in(ax25, skb, type); break; +#endif + } + + ax25_set_timer(ax25); + + return queued; +} - case AX25_DM: - if (pf) { - if (ax25->modulus == AX25_MODULUS) { - ax25_clear_queues(ax25); - ax25->state = AX25_STATE_0; - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = ECONNREFUSED; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; +static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_addr, struct packet_type *ptype) +{ + struct sock *make; + struct sock *sk; + int type = 0; + ax25_digi dp, reverse_dp; + ax25_cb *ax25; + ax25_address src, dest; + ax25_address *next_digi = NULL; + ax25_dev *ax25_dev; + struct sock *raw; + int mine = 0; + int dama; + + /* + * Process the AX.25/LAPB frame. + */ + + skb->h.raw = skb->data; + + if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) { + kfree_skb(skb, FREE_READ); + return 0; + } + +#ifdef CONFIG_FIREWALL + if (call_in_firewall(PF_AX25, skb->dev, skb->h.raw, NULL) != FW_ACCEPT) { + kfree_skb(skb, FREE_READ); + return 0; + } +#endif + + /* + * Parse the address header. + */ + + if (ax25_addr_parse(skb->data, skb->len, &src, &dest, &dp, &type, &dama) == NULL) { + kfree_skb(skb, FREE_READ); + return 0; + } + + /* + * Ours perhaps ? + */ + if (dp.lastrepeat + 1 < dp.ndigi) /* Not yet digipeated completely */ + next_digi = &dp.calls[dp.lastrepeat + 1]; + + /* + * Pull of the AX.25 headers leaving the CTRL/PID bytes + */ + skb_pull(skb, ax25_addr_size(&dp)); + + /* For our port addresses ? */ + if (ax25cmp(&dest, dev_addr) == 0 && dp.lastrepeat + 1 == dp.ndigi) + mine = 1; + + /* Also match on any registered callsign from L3/4 */ + if (!mine && ax25_listen_mine(&dest, dev) && dp.lastrepeat + 1 == dp.ndigi) + mine = 1; + + /* UI frame - bypass LAPB processing */ + if ((*skb->data & ~0x10) == AX25_UI && dp.lastrepeat + 1 == dp.ndigi) { + skb->h.raw = skb->data + 2; /* skip control and pid */ + + if ((raw = ax25_addr_match(&dest)) != NULL) + ax25_send_to_raw(raw, skb, skb->data[1]); + + if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) { + kfree_skb(skb, FREE_READ); + return 0; + } + + /* Now we are pointing at the pid byte */ + switch (skb->data[1]) { +#ifdef CONFIG_INET + case AX25_P_IP: + skb_pull(skb,2); /* drop PID/CTRL */ + skb->h.raw = skb->data; + skb->nh.raw = skb->data; + skb->dev = dev; + skb->pkt_type = PACKET_HOST; + ip_rcv(skb, dev, ptype); /* Note ptype here is the wrong one, fix me later */ + break; + + case AX25_P_ARP: + skb_pull(skb,2); + skb->h.raw = skb->data; + skb->nh.raw = skb->data; + skb->dev = dev; + skb->pkt_type = PACKET_HOST; + arp_rcv(skb, dev, ptype); /* Note ptype here is wrong... */ + break; +#endif + case AX25_P_TEXT: + /* Now find a suitable dgram socket */ + if ((sk = ax25_find_socket(&dest, &src, SOCK_DGRAM)) != NULL) { + if (sk->rmem_alloc >= sk->rcvbuf) { + kfree_skb(skb, FREE_READ); + } else { + /* + * Remove the control and PID. + */ + skb_pull(skb, 2); + if (sock_queue_rcv_skb(sk, skb) != 0) + kfree_skb(skb, FREE_READ); } } else { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW); + kfree_skb(skb, FREE_READ); } - } - break; + break; - default: - if (dama && pf) - ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); - break; + default: + kfree_skb(skb, FREE_READ); /* Will scan SOCK_AX25 RAW sockets */ + break; + } + + return 0; } - return 0; -} + /* + * Is connected mode supported on this device ? + * If not, should we DM the incoming frame (except DMs) or + * silently ignore them. For now we stay quiet. + */ + if (ax25_dev->values[AX25_VALUES_CONMODE] == 0) { + kfree_skb(skb, FREE_READ); + return 0; + } -/* - * State machine for state 2, Awaiting Release State. - * The handling of the timer(s) is in file ax25_timer.c - * Handling of state 0 and connection release is in ax25.c. - */ -static int ax25_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) -{ - switch (frametype) { - case AX25_SABM: - case AX25_SABME: - ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); - if (ax25->dama_slave) - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - break; + /* LAPB */ - case AX25_DISC: - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - if (ax25->dama_slave) { - ax25->state = AX25_STATE_0; - ax25_dama_off(ax25); - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = 0; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - } - } - break; + /* AX.25 state 1-4 */ - case AX25_DM: - case AX25_UA: - if (pf) { - ax25->state = AX25_STATE_0; - ax25_dama_off(ax25); - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = 0; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - } - } - break; + ax25_digi_invert(&dp, &reverse_dp); - case AX25_I: - case AX25_REJ: - case AX25_RNR: - case AX25_RR: - if (pf) { - if (ax25->dama_slave) - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - else - ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE); - } - break; + if ((ax25 = ax25_find_cb(&dest, &src, &reverse_dp, dev)) != NULL) { + /* + * Process the frame. If it is queued up internally it returns one otherwise we + * free it immediately. This routine itself wakes the user context layers so we + * do no further work + */ + if (ax25_process_rx_frame(ax25, skb, type) == 0) + kfree_skb(skb, FREE_READ); - default: - break; + return 0; } - return 0; -} + /* AX.25 state 0 (disconnected) */ -/* - * State machine for state 3, Connected State. - * The handling of the timer(s) is in file ax25_timer.c - * Handling of state 0 and connection release is in ax25.c. - */ -static int ax25_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type, int dama) -{ - int queued = 0; + /* a) received not a SABM(E) */ - switch (frametype) { - case AX25_SABM: - case AX25_SABME: - if (dama) ax25_dama_on(ax25); - if (frametype == AX25_SABM) { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW); - } else { - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW); - } - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - ax25->condition = 0x00; - ax25->t1timer = 0; - ax25->t3timer = ax25->t3; - ax25->idletimer = ax25->idle; - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; - ax25->dama_slave = dama; - ax25_requeue_frames(ax25); - break; + if ((*skb->data & ~AX25_PF) != AX25_SABM && (*skb->data & ~AX25_PF) != AX25_SABME) { + /* + * Never reply to a DM. Also ignore any connects for + * addresses that are not our interfaces and not a socket. + */ + if ((*skb->data & ~AX25_PF) != AX25_DM && mine) + ax25_return_dm(dev, &src, &dest, &dp); - case AX25_DISC: - ax25_clear_queues(ax25); - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - ax25->t3timer = 0; - ax25->state = AX25_STATE_0; - ax25_dama_off(ax25); - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = 0; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - } - break; + kfree_skb(skb, FREE_READ); + return 0; + } - case AX25_DM: - ax25_clear_queues(ax25); - ax25->t3timer = 0; - ax25->state = AX25_STATE_0; - ax25_dama_off(ax25); - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = ECONNRESET; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - } - break; + /* b) received SABM(E) */ - case AX25_RR: - case AX25_RNR: - if (frametype == AX25_RR) - ax25->condition &= ~AX25_COND_PEER_RX_BUSY; - else - ax25->condition |= AX25_COND_PEER_RX_BUSY; - ax25_check_need_response(ax25, type, pf); - if (ax25_validate_nr(ax25, nr)) { - ax25_check_iframes_acked(ax25, nr); - dama_check_need_response(ax25, type, pf); - } else { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; + if (dp.lastrepeat + 1 == dp.ndigi) + sk = ax25_find_listener(&dest, 0, dev, SOCK_SEQPACKET); + else + sk = ax25_find_listener(next_digi, 1, dev, SOCK_SEQPACKET); + + if (sk != NULL) { + if (sk->ack_backlog == sk->max_ack_backlog || (make = ax25_make_new(sk, dev)) == NULL) { + if (mine) ax25_return_dm(dev, &src, &dest, &dp); + kfree_skb(skb, FREE_READ); + return 0; + } - case AX25_REJ: - ax25->condition &= ~AX25_COND_PEER_RX_BUSY; - ax25_check_need_response(ax25, type, pf); - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - ax25_calculate_rtt(ax25); - ax25->t1timer = 0; - ax25->t3timer = ax25->t3; - ax25_requeue_frames(ax25); - dama_check_need_response(ax25, type, pf); - } else { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; + ax25 = make->protinfo.ax25; - case AX25_I: - if (!ax25_validate_nr(ax25, nr)) { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - break; - } - if (ax25->condition & AX25_COND_PEER_RX_BUSY) { - ax25_frames_acked(ax25, nr); - } else { - ax25_check_iframes_acked(ax25, nr); - } - if (ax25->condition & AX25_COND_OWN_RX_BUSY) { - if (pf) { - if (ax25->dama_slave) - dama_enquiry_response(ax25); - else - ax25_enquiry_response(ax25); - } - break; - } - if (ns == ax25->vr) { - ax25->vr = (ax25->vr + 1) % ax25->modulus; - queued = ax25_rx_iframe(ax25, skb); - if (ax25->condition & AX25_COND_OWN_RX_BUSY) { - ax25->vr = ns; /* ax25->vr - 1 */ - if (pf) { - if (ax25->dama_slave) - dama_enquiry_response(ax25); - else - ax25_enquiry_response(ax25); - } - break; - } - ax25->condition &= ~AX25_COND_REJECT; - if (pf) { - if (ax25->dama_slave) - dama_enquiry_response(ax25); - else - ax25_enquiry_response(ax25); - } else { - if (!(ax25->condition & AX25_COND_ACK_PENDING)) { - ax25->t2timer = ax25->t2; - ax25->condition |= AX25_COND_ACK_PENDING; - } - } - } else { - if (ax25->condition & AX25_COND_REJECT) { - if (pf) { - if (ax25->dama_slave) - dama_enquiry_response(ax25); - else - ax25_enquiry_response(ax25); - } - } else { - ax25->condition |= AX25_COND_REJECT; - if (ax25->dama_slave) - dama_enquiry_response(ax25); - else - ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE); - ax25->condition &= ~AX25_COND_ACK_PENDING; - } - } - break; + skb_queue_head(&sk->receive_queue, skb); - case AX25_FRMR: - case AX25_ILLEGAL: - ax25_establish_data_link(ax25); - ax25->state = AX25_STATE_1; - break; + skb->sk = make; + make->state = TCP_ESTABLISHED; + make->pair = sk; - default: - break; + sk->ack_backlog++; + } else { + if (!mine) { + kfree_skb(skb, FREE_READ); + return 0; + } + + if ((ax25 = ax25_create_cb()) == NULL) { + ax25_return_dm(dev, &src, &dest, &dp); + kfree_skb(skb, FREE_READ); + return 0; + } + + ax25_fillin_cb(ax25, ax25_dev); + ax25->idletimer = ax25->idle; } - return queued; -} + ax25->source_addr = dest; + ax25->dest_addr = src; -/* - * State machine for state 4, Timer Recovery State. - * The handling of the timer(s) is in file ax25_timer.c - * Handling of state 0 and connection release is in ax25.c. - */ -static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type, int dama) -{ - int queued = 0; + /* + * Sort out any digipeated paths. + */ + if (dp.ndigi != 0 && ax25->digipeat == NULL && (ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { + kfree_skb(skb, FREE_READ); + ax25_destroy_socket(ax25); + return 0; + } - switch (frametype) { - case AX25_SABM: - case AX25_SABME: - if (dama) ax25_dama_on(ax25); - if (frametype == AX25_SABM) { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW); - } else { - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW); - } - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - ax25->condition = 0x00; - ax25->t1timer = 0; - ax25->t3timer = ax25->t3; - ax25->idletimer = ax25->idle; - ax25->vs = 0; - ax25->va = 0; - ax25->vr = 0; - ax25->state = AX25_STATE_3; - ax25->n2count = 0; - ax25->dama_slave = dama; - ax25_requeue_frames(ax25); - break; + if (dp.ndigi == 0) { + if (ax25->digipeat != NULL) { + kfree_s(ax25->digipeat, sizeof(ax25_digi)); + ax25->digipeat = NULL; + } + } else { + /* Reverse the source SABM's path */ + *ax25->digipeat = reverse_dp; + } - case AX25_DISC: - ax25_clear_queues(ax25); - ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); - ax25->t3timer = 0; - ax25->state = AX25_STATE_0; - ax25_dama_off(ax25); - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = 0; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - } - break; + if ((*skb->data & ~AX25_PF) == AX25_SABME) { + ax25->modulus = AX25_EMODULUS; + ax25->window = ax25_dev->values[AX25_VALUES_EWINDOW]; + } else { + ax25->modulus = AX25_MODULUS; + ax25->window = ax25_dev->values[AX25_VALUES_WINDOW]; + } - case AX25_DM: - ax25_clear_queues(ax25); - ax25->t3timer = 0; - ax25->state = AX25_STATE_0; - ax25_dama_off(ax25); - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = ECONNRESET; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - } - break; + ax25_send_control(ax25, AX25_UA, AX25_POLLON, AX25_RESPONSE); - case AX25_RR: - case AX25_RNR: - if (frametype == AX25_RR) - ax25->condition &= ~AX25_COND_PEER_RX_BUSY; - else - ax25->condition |= AX25_COND_PEER_RX_BUSY; - if (type == AX25_RESPONSE && pf) { - ax25->t1timer = 0; - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - if (ax25->vs == ax25->va) { - ax25->t3timer = ax25->t3; - ax25->n2count = 0; - ax25->state = AX25_STATE_3; - } - } else { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - } - ax25_check_need_response(ax25, type, pf); - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - dama_check_need_response(ax25, type, pf); - } else { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; +#ifdef CONFIG_AX25_DAMA_SLAVE + if (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE) + ax25_dama_on(ax25); +#endif - case AX25_REJ: - ax25->condition &= ~AX25_COND_PEER_RX_BUSY; - if (pf && (type == AX25_RESPONSE || (ax25->dama_slave && type == AX25_COMMAND))) { - ax25->t1timer = 0; - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - if (ax25->vs == ax25->va) { - ax25->t3timer = ax25->t3; - ax25->n2count = 0; - ax25->state = AX25_STATE_3; - } else { - ax25_requeue_frames(ax25); - } - dama_check_need_response(ax25, type, pf); - } else { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - } - ax25_check_need_response(ax25, type, pf); - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - if(ax25->vs != ax25->va) { - ax25_requeue_frames(ax25); - } - dama_check_need_response(ax25, type, pf); - } else { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; + ax25->t3timer = ax25->t3; + ax25->state = AX25_STATE_3; - case AX25_I: - if (!ax25_validate_nr(ax25, nr)) { - ax25_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - break; - } - ax25_frames_acked(ax25, nr); - if (ax25->condition & AX25_COND_OWN_RX_BUSY) { - if (pf) { - if (ax25->dama_slave) - ax25_enquiry_response(ax25); - else - dama_enquiry_response(ax25); - } - break; - } - if (ns == ax25->vr) { - ax25->vr = (ax25->vr + 1) % ax25->modulus; - queued = ax25_rx_iframe(ax25, skb); - if (ax25->condition & AX25_COND_OWN_RX_BUSY) { - ax25->vr = ns; /* ax25->vr - 1 */ - if (pf) { - if (ax25->dama_slave) - dama_enquiry_response(ax25); - else - ax25_enquiry_response(ax25); - } - break; - } - ax25->condition &= ~AX25_COND_REJECT; - if (pf) { - if (ax25->dama_slave) - dama_enquiry_response(ax25); - else - ax25_enquiry_response(ax25); - } else { - if (!(ax25->condition & AX25_COND_ACK_PENDING)) { - ax25->t2timer = ax25->t2; - ax25->condition |= AX25_COND_ACK_PENDING; - } - } - } else { - if (ax25->condition & AX25_COND_REJECT) { - if (pf) { - if (ax25->dama_slave) - dama_enquiry_response(ax25); - else - ax25_enquiry_response(ax25); - } - } else { - ax25->condition |= AX25_COND_REJECT; - if (ax25->dama_slave) - dama_enquiry_response(ax25); - else - ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE); - ax25->condition &= ~AX25_COND_ACK_PENDING; - } - } - break; + ax25_insert_socket(ax25); - case AX25_FRMR: - case AX25_ILLEGAL: - ax25_establish_data_link(ax25); - ax25->state = AX25_STATE_1; - break; + ax25_set_timer(ax25); - default: - break; + if (sk != NULL) { + if (!sk->dead) + sk->data_ready(sk, skb->len); + } else { + kfree_skb(skb, FREE_READ); } - return queued; + return 0; } /* - * Higher level upcall for a LAPB frame + * Receive an AX.25 frame via a SLIP interface. */ -int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, int dama) +int ax25_kiss_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *ptype) { - int queued = 0, frametype, ns, nr, pf; + skb->sk = NULL; /* Initially we don't know who it's for */ - if (ax25->state == AX25_STATE_0) + if ((*skb->data & 0x0F) != 0) { + kfree_skb(skb, FREE_READ); /* Not a KISS data frame */ return 0; - - del_timer(&ax25->timer); - - frametype = ax25_decode(ax25, skb, &ns, &nr, &pf); - - switch (ax25->state) { - case AX25_STATE_1: - queued = ax25_state1_machine(ax25, skb, frametype, pf, type, dama); - break; - case AX25_STATE_2: - queued = ax25_state2_machine(ax25, skb, frametype, pf, type); - break; - case AX25_STATE_3: - queued = ax25_state3_machine(ax25, skb, frametype, ns, nr, pf, type, dama); - break; - case AX25_STATE_4: - queued = ax25_state4_machine(ax25, skb, frametype, ns, nr, pf, type, dama); - break; } - ax25_set_timer(ax25); + skb_pull(skb, AX25_KISS_HEADER_LEN); /* Remove the KISS byte */ - return queued; + return ax25_rcv(skb, dev, (ax25_address *)dev->dev_addr, ptype); } #endif diff -u --recursive --new-file v2.1.26/linux/net/ax25/ax25_ip.c linux/net/ax25/ax25_ip.c --- v2.1.26/linux/net/ax25/ax25_ip.c Wed Dec 31 16:00:00 1969 +++ linux/net/ax25/ax25_ip.c Tue Feb 25 17:12:51 1997 @@ -0,0 +1,173 @@ +/* + * AX.25 release 036 + * + * This is ALPHA test software. This code may break your machine, randomly fail to work with new + * releases, misbehave and/or generally screw up. It might even work. + * + * This code REQUIRES 2.1.15 or higher/ NET3.038 + * + * This module: + * This module is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * History + * AX.25 036 Jonathan(G4KLX) Split from af_ax25.c. + */ + +#include +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For TIOCINQ/OUTQ */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * IP over AX.25 encapsulation. + */ + +/* + * Shove an AX.25 UI header on an IP packet and handle ARP + */ + +#ifdef CONFIG_INET + +int ax25_encapsulate(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len) +{ + /* header is an AX.25 UI frame from us to them */ + unsigned char *buff = skb_push(skb, AX25_HEADER_LEN); + + *buff++ = 0x00; /* KISS DATA */ + + if (daddr != NULL) + memcpy(buff, daddr, dev->addr_len); /* Address specified */ + + buff[6] &= ~AX25_CBIT; + buff[6] &= ~AX25_EBIT; + buff[6] |= AX25_SSSID_SPARE; + buff += AX25_ADDR_LEN; + + if (saddr != NULL) + memcpy(buff, saddr, dev->addr_len); + else + memcpy(buff, dev->dev_addr, dev->addr_len); + + buff[6] &= ~AX25_CBIT; + buff[6] |= AX25_EBIT; + buff[6] |= AX25_SSSID_SPARE; + buff += AX25_ADDR_LEN; + + *buff++ = AX25_UI; /* UI */ + + /* Append a suitable AX.25 PID */ + switch (type) { + case ETH_P_IP: + *buff++ = AX25_P_IP; + break; + case ETH_P_ARP: + *buff++ = AX25_P_ARP; + break; + default: + printk(KERN_ERR "AX.25 wrong protocol type 0x%x2.2\n", type); + *buff++ = 0; + break; + } + + if (daddr != NULL) + return AX25_HEADER_LEN; + + return -AX25_HEADER_LEN; /* Unfinished header */ +} + +int ax25_rebuild_header(struct sk_buff *skb) +{ + struct sk_buff *ourskb; + int mode; + unsigned char *bp = skb->data; + struct device *dev = skb->dev; + ax25_dev *ax25_dev; + + if (arp_find(bp + 1, skb)) + return 1; + + if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) + return 1; + + if (bp[16] == AX25_P_IP) { + mode = ax25_ip_mode_get((ax25_address *)(bp + 1), dev); + if (mode == 'V' || (mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) { + /* + * We clone the buffer and release the original thereby + * keeping it straight + * + * Note: we report 1 back so the caller will + * not feed the frame direct to the physical device + * We don't want that to happen. (It won't be upset + * as we have pulled the frame from the queue by + * freeing it). + */ + if ((ourskb = skb_clone(skb, GFP_ATOMIC)) == NULL) { + dev_kfree_skb(skb, FREE_WRITE); + return 1; + } + + if (skb->sk != NULL) + skb_set_owner_w(ourskb, skb->sk); + + kfree_skb(skb, FREE_WRITE); + + skb_pull(ourskb, AX25_HEADER_LEN - 1); /* Keep PID */ + + ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], (ax25_address *)(bp + 8), (ax25_address *)(bp + 1), NULL, dev); + + return 1; + } + } + + bp[7] &= ~AX25_CBIT; + bp[7] &= ~AX25_EBIT; + bp[7] |= AX25_SSSID_SPARE; + + bp[14] &= ~AX25_CBIT; + bp[14] |= AX25_EBIT; + bp[14] |= AX25_SSSID_SPARE; + + ax25_dg_build_path(skb, (ax25_address *)(bp + 1), dev); + + skb->dev = dev; + skb->priority = SOPRI_NORMAL; + + ax25_queue_xmit(skb); + + return 1; +} + +#endif + +#endif diff -u --recursive --new-file v2.1.26/linux/net/ax25/ax25_out.c linux/net/ax25/ax25_out.c --- v2.1.26/linux/net/ax25/ax25_out.c Sun Feb 2 05:18:48 1997 +++ linux/net/ax25/ax25_out.c Tue Feb 25 17:12:51 1997 @@ -1,5 +1,5 @@ /* - * AX.25 release 035 + * AX.25 release 036 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -54,32 +55,94 @@ #include #include +int ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_address *dest, ax25_digi *digi, struct device *dev) +{ + ax25_dev *ax25_dev; + ax25_cb *ax25; + + if (skb == NULL) + return 0; + + /* + * Look for an existing connection. + */ + if ((ax25 = ax25_find_cb(src, dest, digi, dev)) != NULL) { + ax25_output(ax25, paclen, skb); + ax25->idletimer = ax25->idle; + return 1; /* It already existed */ + } + + if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) + return 0; + + if ((ax25 = ax25_create_cb()) == NULL) + return 0; + + ax25_fillin_cb(ax25, ax25_dev); + + ax25->source_addr = *src; + ax25->dest_addr = *dest; + + if (digi != NULL) { + if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { + ax25_free_cb(ax25); + return 0; + } + *ax25->digipeat = *digi; + } else { + ax25_rt_build_path(ax25, dest, dev); + } + + switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { + case AX25_PROTO_STD: + ax25_std_establish_data_link(ax25); + break; +#ifdef AX25_CONFIG_DAMA_SLAVE + case AX25_PROTO_DAMA_SLAVE: + ax25_ds_establish_data_link(ax25); + break; +#endif + } + + /* idle timeouts only for mode vc connections */ + + ax25->idletimer = ax25->idle; + + ax25_insert_socket(ax25); + + ax25->state = AX25_STATE_1; + + ax25_set_timer(ax25); + + ax25_output(ax25, paclen, skb); + + return 1; /* We had to create it */ +} + /* * All outgoing AX.25 I frames pass via this routine. Therefore this is * where the fragmentation of frames takes place. If fragment is set to * zero then we are not allowed to do fragmentation, even if the frame * is too large. */ -void ax25_output(ax25_cb *ax25, int fragment, struct sk_buff *skb) +void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb) { struct sk_buff *skbn; unsigned char *p; - int frontlen, mtu, len, fragno, ka9qfrag, first = 1; + int frontlen, len, fragno, ka9qfrag, first = 1; long flags; - mtu = ax25->paclen; - - if ((skb->len - 1) > mtu && fragment) { + if ((skb->len - 1) > paclen) { if (*skb->data == AX25_P_TEXT) { skb_pull(skb, 1); /* skip PID */ ka9qfrag = 0; } else { - mtu -= 2; /* Allow for fragment control info */ + paclen -= 2; /* Allow for fragment control info */ ka9qfrag = 1; } - fragno = skb->len / mtu; - if (skb->len % mtu == 0) fragno--; + fragno = skb->len / paclen; + if (skb->len % paclen == 0) fragno--; frontlen = skb_headroom(skb); /* Address space + CTRL */ @@ -87,7 +150,7 @@ save_flags(flags); cli(); - if ((skbn = alloc_skb(mtu + 2 + frontlen, GFP_ATOMIC)) == NULL) { + if ((skbn = alloc_skb(paclen + 2 + frontlen, GFP_ATOMIC)) == NULL) { restore_flags(flags); printk(KERN_DEBUG "ax25_output: alloc_skb returned NULL\n"); return; @@ -98,7 +161,7 @@ restore_flags(flags); - len = (mtu > skb->len) ? skb->len : mtu; + len = (paclen > skb->len) ? skb->len : paclen; if (ka9qfrag == 1) { skb_reserve(skbn, frontlen + 2); @@ -129,9 +192,9 @@ skb_queue_tail(&ax25->write_queue, skb); /* Throw it on the queue */ } - if (ax25->state == AX25_STATE_3 || ax25->state == AX25_STATE_4) { - if (!ax25->dama_slave) /* bke 960114: we aren't allowed to transmit */ - ax25_kick(ax25); /* in DAMA mode unless we received a Poll */ + if (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_STD) { + if (ax25->state == AX25_STATE_3 || ax25->state == AX25_STATE_4) + ax25_kick(ax25); } } @@ -210,7 +273,16 @@ * bke 960114: do not set the Poll bit on the last frame * in DAMA mode. */ - ax25_send_iframe(ax25, skbn, (last && !ax25->dama_slave) ? AX25_POLLON : AX25_POLLOFF); + switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { + case AX25_PROTO_STD: + ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF); + break; +#ifdef CONFIG_AX25_DAMA_SLAVE + case AX25_PROTO_DAMA_SLAVE: + ax25_send_iframe(ax25, skbn, AX25_POLLOFF); + break; +#endif + } ax25->vs = next; @@ -236,7 +308,7 @@ { unsigned char *ptr; - if (ax25->device == NULL) { + if (ax25->ax25_dev == NULL) { if (ax25->sk != NULL) { ax25->sk->state = TCP_CLOSE; ax25->sk->err = ENETUNREACH; @@ -248,76 +320,44 @@ return; } - if (skb_headroom(skb) < size_ax25_addr(ax25->digipeat)) { + if (skb_headroom(skb) < ax25_addr_size(ax25->digipeat)) { printk(KERN_CRIT "ax25_transmit_buffer: not enough room for digi-peaters\n"); kfree_skb(skb, FREE_WRITE); return; } - ptr = skb_push(skb, size_ax25_addr(ax25->digipeat)); - build_ax25_addr(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus); + ptr = skb_push(skb, ax25_addr_size(ax25->digipeat)); + ax25_addr_build(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus); - skb->dev = ax25->device; + skb->dev = ax25->ax25_dev->dev; skb->priority = SOPRI_NORMAL; ax25_queue_xmit(skb); } /* - * The following routines are taken from page 170 of the 7th ARRL Computer - * Networking Conference paper, as is the whole state machine. + * A small shim to dev_queue_xmit to add the KISS control byte, and do + * any packet forwarding in operation. */ - -void ax25_nr_error_recovery(ax25_cb *ax25) -{ - ax25_establish_data_link(ax25); -} - -void ax25_establish_data_link(ax25_cb *ax25) -{ - ax25->condition = 0x00; - ax25->n2count = 0; - - if (ax25->modulus == AX25_MODULUS) - ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); - else - ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND); - - ax25->t3timer = 0; - ax25->t2timer = 0; - ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25); -} - -void ax25_transmit_enquiry(ax25_cb *ax25) +void ax25_queue_xmit(struct sk_buff *skb) { - if (ax25->condition & AX25_COND_OWN_RX_BUSY) - ax25_send_control(ax25, AX25_RNR, AX25_POLLON, AX25_COMMAND); - else - ax25_send_control(ax25, AX25_RR, AX25_POLLON, AX25_COMMAND); - - ax25->condition &= ~AX25_COND_ACK_PENDING; + unsigned char *ptr; - ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25); -} - -void ax25_enquiry_response(ax25_cb *ax25) -{ - if (ax25->condition & AX25_COND_OWN_RX_BUSY) - ax25_send_control(ax25, AX25_RNR, AX25_POLLON, AX25_RESPONSE); - else - ax25_send_control(ax25, AX25_RR, AX25_POLLON, AX25_RESPONSE); +#ifdef CONFIG_FIREWALL + if (call_out_firewall(PF_AX25, skb->dev, skb->data, NULL) != FW_ACCEPT) { + dev_kfree_skb(skb, FREE_WRITE); + return; + } +#endif - ax25->condition &= ~AX25_COND_ACK_PENDING; -} + skb->protocol = htons(ETH_P_AX25); + skb->dev = ax25_fwd_dev(skb->dev); + skb->arp = 1; -void ax25_timeout_response(ax25_cb *ax25) -{ - if (ax25->condition & AX25_COND_OWN_RX_BUSY) - ax25_send_control(ax25, AX25_RNR, AX25_POLLOFF, AX25_RESPONSE); - else - ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE); + ptr = skb_push(skb, 1); + *ptr = 0x00; /* KISS */ - ax25->condition &= ~AX25_COND_ACK_PENDING; + dev_queue_xmit(skb); } void ax25_check_iframes_acked(ax25_cb *ax25, unsigned short nr) @@ -333,97 +373,6 @@ ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25); } } -} - -/* - * dl1bke 960114: shouldn't ax25/dama_check_need_response reside as - * static inline void ...() in ax25.h, should it? ;-) - */ -void ax25_check_need_response(ax25_cb *ax25, int type, int pf) -{ - if (!ax25->dama_slave && type == AX25_COMMAND && pf) - ax25_enquiry_response(ax25); -} - -/* - * dl1bke 960114: transmit I frames on DAMA poll - */ -void dama_enquiry_response(ax25_cb *ax25) -{ - ax25_cb *ax25o; - - if (!(ax25->condition & AX25_COND_PEER_RX_BUSY)) { - ax25_requeue_frames(ax25); - ax25_kick(ax25); - } - - if (ax25->state == AX25_STATE_1 || ax25->state == AX25_STATE_2 || skb_peek(&ax25->ack_queue) != NULL) - ax25_t1_timeout(ax25); - else - ax25->n2count = 0; - - ax25->t3timer = ax25->t3; - - /* The FLEXNET DAMA master implementation refuses to send us ANY */ - /* I frame for this connection if we send a REJ here, probably */ - /* due to its frame collector scheme? A simple RR or RNR will */ - /* invoke the retransmission, and in fact REJs are superfluous */ - /* in DAMA mode anyway... */ - -#if 0 - if (ax25->condition & AX25_COND_REJECT) - ax25_send_control(ax25, AX25_REJ, AX25_POLLOFF, AX25_RESPONSE); - else -#endif - ax25_enquiry_response(ax25); - - /* Note that above response to the poll could be sent behind the */ - /* transmissions of the other channels as well... This version */ - /* gives better performance on FLEXNET nodes. (Why, Gunter?) */ - - for (ax25o = ax25_list; ax25o != NULL; ax25o = ax25o->next) { - if (ax25o == ax25) - continue; - - if (ax25o->device != ax25->device) - continue; - - if (ax25o->state == AX25_STATE_1 || ax25o->state == AX25_STATE_2) { - ax25_t1_timeout(ax25o); - continue; - } - - if (!ax25o->dama_slave) - continue; - - if (!(ax25o->condition & AX25_COND_PEER_RX_BUSY) && - (ax25o->state == AX25_STATE_3 || - (ax25o->state == AX25_STATE_4 && ax25o->t1timer == 0))) { - ax25_requeue_frames(ax25o); - ax25_kick(ax25o); - } - - if (ax25o->state == AX25_STATE_1 || ax25o->state == AX25_STATE_2 || skb_peek(&ax25o->ack_queue) != NULL) - ax25_t1_timeout(ax25o); - - ax25o->t3timer = ax25o->t3; - } -} - -void dama_check_need_response(ax25_cb *ax25, int type, int pf) -{ - if (ax25->dama_slave && type == AX25_COMMAND && pf) - dama_enquiry_response(ax25); -} - -void dama_establish_data_link(ax25_cb *ax25) -{ - ax25->condition = 0x00; - ax25->n2count = 0; - - ax25->t3timer = ax25->t3; - ax25->t2timer = 0; - ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25); } #endif diff -u --recursive --new-file v2.1.26/linux/net/ax25/ax25_route.c linux/net/ax25/ax25_route.c --- v2.1.26/linux/net/ax25/ax25_route.c Sun Feb 2 05:18:48 1997 +++ linux/net/ax25/ax25_route.c Tue Feb 25 17:12:51 1997 @@ -1,5 +1,5 @@ /* - * AX.25 release 035 + * AX.25 release 036 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. @@ -67,22 +67,9 @@ #include #include -static struct ax25_route { - struct ax25_route *next; - ax25_address callsign; - struct device *dev; - ax25_digi *digipeat; - char ip_mode; -} *ax25_route = NULL; - -struct ax25_dev ax25_device[AX25_MAX_DEVICES] = { - {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}, - {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}, - {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}, - {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL} -}; +static ax25_route *ax25_route_list = NULL; -static struct ax25_route *ax25_find_route(ax25_address *, struct device *); +static ax25_route *ax25_find_route(ax25_address *, struct device *); /* * small macro to drop non-digipeated digipeaters and reverse path @@ -102,25 +89,25 @@ void ax25_rt_device_down(struct device *dev) { - struct ax25_route *s, *t, *ax25_rt = ax25_route; + ax25_route *s, *t, *ax25_rt = ax25_route_list; while (ax25_rt != NULL) { s = ax25_rt; ax25_rt = ax25_rt->next; if (s->dev == dev) { - if (ax25_route == s) { - ax25_route = s->next; + if (ax25_route_list == s) { + ax25_route_list = s->next; if (s->digipeat != NULL) - kfree_s((void *)s->digipeat, sizeof(ax25_digi)); - kfree_s((void *)s, (sizeof *s)); + kfree_s(s->digipeat, sizeof(ax25_digi)); + kfree_s(s, sizeof(ax25_route)); } else { - for (t = ax25_route; t != NULL; t = t->next) { + for (t = ax25_route_list; t != NULL; t = t->next) { if (t->next == s) { t->next = s->next; if (s->digipeat != NULL) - kfree_s((void *)s->digipeat, sizeof(ax25_digi)); - kfree_s((void *)s, sizeof(*s)); + kfree_s(s->digipeat, sizeof(ax25_digi)); + kfree_s(s, sizeof(ax25_route)); break; } } @@ -132,10 +119,10 @@ int ax25_rt_ioctl(unsigned int cmd, void *arg) { unsigned long flags; - struct ax25_route *s, *t, *ax25_rt; + ax25_route *s, *t, *ax25_rt; struct ax25_routes_struct route; struct ax25_route_opt_struct rt_option; - struct device *dev; + ax25_dev *ax25_dev; int i, err; switch (cmd) { @@ -143,12 +130,12 @@ if ((err = verify_area(VERIFY_READ, arg, sizeof(route))) != 0) return err; copy_from_user(&route, arg, sizeof(route)); - if ((dev = ax25rtr_get_dev(&route.port_addr)) == NULL) + if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL) return -EINVAL; if (route.digi_count > AX25_MAX_DIGIS) return -EINVAL; - for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) { - if (ax25cmp(&ax25_rt->callsign, &route.dest_addr) == 0 && ax25_rt->dev == dev) { + for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) { + if (ax25cmp(&ax25_rt->callsign, &route.dest_addr) == 0 && ax25_rt->dev == ax25_dev->dev) { if (ax25_rt->digipeat != NULL) { kfree_s(ax25_rt->digipeat, sizeof(ax25_digi)); ax25_rt->digipeat = NULL; @@ -166,15 +153,15 @@ return 0; } } - if ((ax25_rt = (struct ax25_route *)kmalloc(sizeof(struct ax25_route), GFP_ATOMIC)) == NULL) + if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) return -ENOMEM; ax25_rt->callsign = route.dest_addr; - ax25_rt->dev = dev; + ax25_rt->dev = ax25_dev->dev; ax25_rt->digipeat = NULL; ax25_rt->ip_mode = ' '; if (route.digi_count != 0) { if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { - kfree_s(ax25_rt, sizeof(struct ax25_route)); + kfree_s(ax25_rt, sizeof(ax25_route)); return -ENOMEM; } ax25_rt->digipeat->lastrepeat = -1; @@ -184,10 +171,9 @@ ax25_rt->digipeat->calls[i] = route.digi_addr[i]; } } - save_flags(flags); - cli(); - ax25_rt->next = ax25_route; - ax25_route = ax25_rt; + save_flags(flags); cli(); + ax25_rt->next = ax25_route_list; + ax25_route_list = ax25_rt; restore_flags(flags); break; @@ -195,25 +181,25 @@ if ((err = verify_area(VERIFY_READ, arg, sizeof(route))) != 0) return err; copy_from_user(&route, arg, sizeof(route)); - if ((dev = ax25rtr_get_dev(&route.port_addr)) == NULL) + if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL) return -EINVAL; - ax25_rt = ax25_route; + ax25_rt = ax25_route_list; while (ax25_rt != NULL) { s = ax25_rt; ax25_rt = ax25_rt->next; - if (s->dev == dev && ax25cmp(&route.dest_addr, &s->callsign) == 0) { - if (ax25_route == s) { - ax25_route = s->next; + if (s->dev == ax25_dev->dev && ax25cmp(&route.dest_addr, &s->callsign) == 0) { + if (ax25_route_list == s) { + ax25_route_list = s->next; if (s->digipeat != NULL) - kfree_s((void *)s->digipeat, sizeof(ax25_digi)); - kfree_s((void *)s, (sizeof *s)); + kfree_s(s->digipeat, sizeof(ax25_digi)); + kfree_s(s, sizeof(ax25_route)); } else { - for (t = ax25_route; t != NULL; t = t->next) { + for (t = ax25_route_list; t != NULL; t = t->next) { if (t->next == s) { t->next = s->next; if (s->digipeat != NULL) - kfree_s((void *)s->digipeat, sizeof(ax25_digi)); - kfree_s((void *)s, sizeof(*s)); + kfree_s(s->digipeat, sizeof(ax25_digi)); + kfree_s(s, sizeof(ax25_route)); break; } } @@ -226,10 +212,10 @@ if ((err = verify_area(VERIFY_READ, arg, sizeof(rt_option))) != 0) return err; copy_from_user(&rt_option, arg, sizeof(rt_option)); - if ((dev = ax25rtr_get_dev(&rt_option.port_addr)) == NULL) + if ((ax25_dev = ax25_addr_ax25dev(&rt_option.port_addr)) == NULL) return -EINVAL; - for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) { - if (ax25_rt->dev == dev && ax25cmp(&rt_option.dest_addr, &ax25_rt->callsign) == 0) { + for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) { + if (ax25_rt->dev == ax25_dev->dev && ax25cmp(&rt_option.dest_addr, &ax25_rt->callsign) == 0) { switch (rt_option.cmd) { case AX25_SET_RT_IPMODE: switch (rt_option.arg) { @@ -258,7 +244,7 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length, int dummy) { - struct ax25_route *ax25_rt; + ax25_route *ax25_rt; int len = 0; off_t pos = 0; off_t begin = 0; @@ -269,7 +255,7 @@ len += sprintf(buffer, "callsign dev mode digipeaters\n"); - for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) { + for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) { if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0) callsign = "default"; else @@ -317,55 +303,20 @@ return len; } -int ax25_cs_get_info(char *buffer, char **start, off_t offset, int length, int dummy) -{ - ax25_uid_assoc *pt; - int len = 0; - off_t pos = 0; - off_t begin = 0; - - cli(); - - len += sprintf(buffer, "Policy: %d\n", ax25_uid_policy); - - for (pt = ax25_uid_list; pt != NULL; pt = pt->next) { - len += sprintf(buffer + len, "%6d %s\n", pt->uid, ax2asc(&pt->call)); - - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - - if (pos > offset + length) - break; - } - - sti(); - - *start = buffer + (offset - begin); - len -= offset - begin; - - if (len > length) len = length; - - return len; -} - /* * Find AX.25 route */ -static struct ax25_route *ax25_find_route(ax25_address *addr, struct device *dev) +static ax25_route *ax25_find_route(ax25_address *addr, struct device *dev) { - struct ax25_route *ax25_spe_rt = NULL; - struct ax25_route *ax25_def_rt = NULL; - struct ax25_route *ax25_rt; + ax25_route *ax25_spe_rt = NULL; + ax25_route *ax25_def_rt = NULL; + ax25_route *ax25_rt; /* * Bind to the physical interface we heard them on, or the default * route if none is found; */ - for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) { + for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) { if (dev == NULL) { if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL) ax25_spe_rt = ax25_rt; @@ -408,18 +359,19 @@ */ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr) { - struct ax25_route *ax25_rt; + ax25_route *ax25_rt; ax25_address *call; if ((ax25_rt = ax25_find_route(addr, NULL)) == NULL) return -EHOSTUNREACH; - ax25->device = ax25_rt->dev; + if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL) + return -EHOSTUNREACH; if ((call = ax25_findbyuid(current->euid)) == NULL) { if (ax25_uid_policy && !suser()) return -EPERM; - call = (ax25_address *)ax25->device->dev_addr; + call = (ax25_address *)ax25->ax25_dev->dev->dev_addr; } ax25->source_addr = *call; @@ -443,7 +395,7 @@ */ void ax25_rt_build_path(ax25_cb *ax25, ax25_address *addr, struct device *dev) { - struct ax25_route *ax25_rt; + ax25_route *ax25_rt; if ((ax25_rt = ax25_find_route(addr, dev)) == NULL) return; @@ -454,14 +406,16 @@ if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) return; - ax25->device = ax25_rt->dev; + if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL) + return; + *ax25->digipeat = *ax25_rt->digipeat; ax25_adjust_path(addr, ax25->digipeat); } void ax25_dg_build_path(struct sk_buff *skb, ax25_address *addr, struct device *dev) { - struct ax25_route *ax25_rt; + ax25_route *ax25_rt; ax25_digi digipeat; ax25_address src, dest; unsigned char *bp; @@ -491,7 +445,7 @@ bp = skb_push(skb, len); - build_ax25_addr(bp, &src, &dest, ax25_rt->digipeat, AX25_COMMAND, AX25_MODULUS); + ax25_addr_build(bp, &src, &dest, ax25_rt->digipeat, AX25_COMMAND, AX25_MODULUS); } /* @@ -499,154 +453,23 @@ */ char ax25_ip_mode_get(ax25_address *callsign, struct device *dev) { - struct ax25_route *ax25_rt; + ax25_route *ax25_rt; - for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) + for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) if (ax25cmp(&ax25_rt->callsign, callsign) == 0 && ax25_rt->dev == dev) return ax25_rt->ip_mode; return ' '; } -static struct ax25_dev *ax25_dev_get_dev(struct device *dev) -{ - int i; - - for (i = 0; i < AX25_MAX_DEVICES; i++) - if (ax25_device[i].dev != NULL && ax25_device[i].dev == dev) - return ax25_device + i; - - return NULL; -} - -/* - * Wow, a bit of data hiding. Is this C++ or what ? - */ -int ax25_dev_get_value(struct device *dev, int valueno) -{ - struct ax25_dev *ax25_dev; - - if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL) { - printk(KERN_WARNING "ax25_dev_get_value called with invalid device\n"); - return 1; - } - - return ax25_dev->values[valueno]; -} - -/* - * This is called when an interface is brought up. These are - * reasonable defaults. - */ -void ax25_dev_device_up(struct device *dev) -{ - struct ax25_dev *ax25_dev = NULL; - int i; - - for (i = 0; i < AX25_MAX_DEVICES; i++) { - if (ax25_device[i].dev == NULL) { - ax25_dev = ax25_device + i; - break; - } - } - - if (ax25_dev == NULL) { - printk(KERN_ERR "ax25_dev_device_up cannot find free AX.25 device\n"); - return; - } - - ax25_unregister_sysctl(); - - sprintf(ax25_dev->name, "%s.parms", dev->name); - - ax25_dev->dev = dev; - ax25_dev->forward = NULL; - - ax25_dev->values[AX25_VALUES_IPDEFMODE] = AX25_DEF_IPDEFMODE; - ax25_dev->values[AX25_VALUES_AXDEFMODE] = AX25_DEF_AXDEFMODE; - ax25_dev->values[AX25_VALUES_TEXT] = AX25_DEF_TEXT; - ax25_dev->values[AX25_VALUES_BACKOFF] = AX25_DEF_BACKOFF; - ax25_dev->values[AX25_VALUES_CONMODE] = AX25_DEF_CONMODE; - ax25_dev->values[AX25_VALUES_WINDOW] = AX25_DEF_WINDOW; - ax25_dev->values[AX25_VALUES_EWINDOW] = AX25_DEF_EWINDOW; - ax25_dev->values[AX25_VALUES_T1] = AX25_DEF_T1; - ax25_dev->values[AX25_VALUES_T2] = AX25_DEF_T2; - ax25_dev->values[AX25_VALUES_T3] = AX25_DEF_T3; - ax25_dev->values[AX25_VALUES_IDLE] = AX25_DEF_IDLE; - ax25_dev->values[AX25_VALUES_N2] = AX25_DEF_N2; - ax25_dev->values[AX25_VALUES_DIGI] = AX25_DEF_DIGI; - ax25_dev->values[AX25_VALUES_PACLEN] = AX25_DEF_PACLEN; - ax25_dev->values[AX25_VALUES_MAXQUEUE] = AX25_DEF_MAXQUEUE; - - ax25_register_sysctl(); -} - -void ax25_dev_device_down(struct device *dev) -{ - struct ax25_dev *ax25_dev; - - ax25_unregister_sysctl(); - - if ((ax25_dev = ax25_dev_get_dev(dev)) != NULL) - ax25_dev->dev = NULL; - - ax25_register_sysctl(); -} - -int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd) -{ - struct device *dev; - struct ax25_dev *ax25_dev; - - if ((dev = ax25rtr_get_dev(&fwd->port_from)) == NULL) - return -EINVAL; - - if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL) - return -EINVAL; - - switch (cmd) { - case SIOCAX25ADDFWD: - if ((dev = ax25rtr_get_dev(&fwd->port_to)) == NULL) - return -EINVAL; - if (ax25_dev->forward != NULL) - return -EINVAL; - ax25_dev->forward = dev; - break; - - case SIOCAX25DELFWD: - if (ax25_dev->forward == NULL) - return -EINVAL; - ax25_dev->forward = NULL; - break; - - default: - return -EINVAL; - } - - return 0; -} - -struct device *ax25_fwd_dev(struct device *dev) -{ - struct ax25_dev *ax25_dev; - - if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL) - return dev; - - if (ax25_dev->forward == NULL) - return dev; - - return ax25_dev->forward; -} - #ifdef MODULE /* - * Free all memory associated with routing and device structures. + * Free all memory associated with routing structures. */ void ax25_rt_free(void) { - struct ax25_route *s, *ax25_rt = ax25_route; + ax25_route *s, *ax25_rt = ax25_route_list; while (ax25_rt != NULL) { s = ax25_rt; @@ -655,7 +478,7 @@ if (s->digipeat != NULL) kfree_s(s->digipeat, sizeof(ax25_digi)); - kfree_s(s, sizeof(struct ax25_route)); + kfree_s(s, sizeof(ax25_route)); } } diff -u --recursive --new-file v2.1.26/linux/net/ax25/ax25_std_in.c linux/net/ax25/ax25_std_in.c --- v2.1.26/linux/net/ax25/ax25_std_in.c Wed Dec 31 16:00:00 1969 +++ linux/net/ax25/ax25_std_in.c Tue Feb 25 17:12:51 1997 @@ -0,0 +1,542 @@ +/* + * AX.25 release 036 + * + * This is ALPHA test software. This code may break your machine, randomly fail to work with new + * releases, misbehave and/or generally screw up. It might even work. + * + * This code REQUIRES 2.1.15 or higher/ NET3.038 + * + * This module: + * This module is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Most of this code is based on the SDL diagrams published in the 7th + * ARRL Computer Networking Conference papers. The diagrams have mistakes + * in them, but are mostly correct. Before you modify the code could you + * read the SDL diagrams as the code is not obvious and probably very + * easy to break; + * + * History + * AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams. + * AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from + * the sock structure. + * AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names. + * Jonathan(G4KLX) Added IP mode registration. + * AX.25 030 Jonathan(G4KLX) Added AX.25 fragment reception. + * Upgraded state machine for SABME. + * Added arbitrary protocol id support. + * AX.25 031 Joerg(DL1BKE) Added DAMA support + * HaJo(DD8NE) Added Idle Disc Timer T5 + * Joerg(DL1BKE) Renamed it to "IDLE" with a slightly + * different behaviour. Fixed defrag + * routine (I hope) + * AX.25 032 Darryl(G7LED) AX.25 segmentation fixed. + * AX.25 033 Jonathan(G4KLX) Remove auto-router. + * Modularisation changes. + * AX.25 035 Hans(PE1AYX) Fixed interface to IP layer. + * AX.25 036 Jonathan(G4KLX) Cloned from ax25_in.c. + */ + +#include +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For ip_rcv */ +#include +#include +#include +#include +#include + +/* + * State machine for state 1, Awaiting Connection State. + * The handling of the timer(s) is in file ax25_std_timer.c. + * Handling of state 0 and connection release is in ax25.c. + */ +static int ax25_std_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) +{ + switch (frametype) { + case AX25_SABM: + ax25->modulus = AX25_MODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; + ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + break; + + case AX25_SABME: + ax25->modulus = AX25_EMODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; + ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + break; + + case AX25_DISC: + ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); + break; + + case AX25_UA: + if (pf) { + ax25_calculate_rtt(ax25); + ax25->t1timer = 0; + ax25->t3timer = ax25->t3; + ax25->idletimer = ax25->idle; + ax25->vs = 0; + ax25->va = 0; + ax25->vr = 0; + ax25->state = AX25_STATE_3; + ax25->n2count = 0; + if (ax25->sk != NULL) { + ax25->sk->state = TCP_ESTABLISHED; + /* For WAIT_SABM connections we will produce an accept ready socket here */ + if (!ax25->sk->dead) + ax25->sk->state_change(ax25->sk); + } + } + break; + + case AX25_DM: + if (pf) { + if (ax25->modulus == AX25_MODULUS) { + ax25_clear_queues(ax25); + ax25->state = AX25_STATE_0; + if (ax25->sk != NULL) { + ax25->sk->state = TCP_CLOSE; + ax25->sk->err = ECONNREFUSED; + ax25->sk->shutdown |= SEND_SHUTDOWN; + if (!ax25->sk->dead) + ax25->sk->state_change(ax25->sk); + ax25->sk->dead = 1; + } + } else { + ax25->modulus = AX25_MODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; + } + } + break; + + default: + break; + } + + return 0; +} + +/* + * State machine for state 2, Awaiting Release State. + * The handling of the timer(s) is in file ax25_std_timer.c + * Handling of state 0 and connection release is in ax25.c. + */ +static int ax25_std_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type) +{ + switch (frametype) { + case AX25_SABM: + case AX25_SABME: + ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE); + break; + + case AX25_DISC: + ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + ax25->state = AX25_STATE_0; + if (ax25->sk != NULL) { + ax25->sk->state = TCP_CLOSE; + ax25->sk->err = 0; + ax25->sk->shutdown |= SEND_SHUTDOWN; + if (!ax25->sk->dead) + ax25->sk->state_change(ax25->sk); + ax25->sk->dead = 1; + } + break; + + case AX25_DM: + case AX25_UA: + if (pf) { + ax25->state = AX25_STATE_0; + if (ax25->sk != NULL) { + ax25->sk->state = TCP_CLOSE; + ax25->sk->err = 0; + ax25->sk->shutdown |= SEND_SHUTDOWN; + if (!ax25->sk->dead) + ax25->sk->state_change(ax25->sk); + ax25->sk->dead = 1; + } + } + break; + + case AX25_I: + case AX25_REJ: + case AX25_RNR: + case AX25_RR: + if (pf) ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE); + break; + + default: + break; + } + + return 0; +} + +/* + * State machine for state 3, Connected State. + * The handling of the timer(s) is in file ax25_std_timer.c + * Handling of state 0 and connection release is in ax25.c. + */ +static int ax25_std_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type) +{ + int queued = 0; + + switch (frametype) { + case AX25_SABM: + case AX25_SABME: + if (frametype == AX25_SABM) { + ax25->modulus = AX25_MODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; + } else { + ax25->modulus = AX25_EMODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; + } + ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + ax25->condition = 0x00; + ax25->t1timer = 0; + ax25->t3timer = ax25->t3; + ax25->idletimer = ax25->idle; + ax25->vs = 0; + ax25->va = 0; + ax25->vr = 0; + ax25_requeue_frames(ax25); + break; + + case AX25_DISC: + ax25_clear_queues(ax25); + ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + ax25->t3timer = 0; + ax25->state = AX25_STATE_0; + if (ax25->sk != NULL) { + ax25->sk->state = TCP_CLOSE; + ax25->sk->err = 0; + ax25->sk->shutdown |= SEND_SHUTDOWN; + if (!ax25->sk->dead) + ax25->sk->state_change(ax25->sk); + ax25->sk->dead = 1; + } + break; + + case AX25_DM: + ax25_clear_queues(ax25); + ax25->t3timer = 0; + ax25->state = AX25_STATE_0; + if (ax25->sk != NULL) { + ax25->sk->state = TCP_CLOSE; + ax25->sk->err = ECONNRESET; + ax25->sk->shutdown |= SEND_SHUTDOWN; + if (!ax25->sk->dead) + ax25->sk->state_change(ax25->sk); + ax25->sk->dead = 1; + } + break; + + case AX25_RR: + case AX25_RNR: + if (frametype == AX25_RR) + ax25->condition &= ~AX25_COND_PEER_RX_BUSY; + else + ax25->condition |= AX25_COND_PEER_RX_BUSY; + if (type == AX25_COMMAND && pf) + ax25_std_enquiry_response(ax25); + if (ax25_validate_nr(ax25, nr)) { + ax25_check_iframes_acked(ax25, nr); + } else { + ax25_std_nr_error_recovery(ax25); + ax25->state = AX25_STATE_1; + } + break; + + case AX25_REJ: + ax25->condition &= ~AX25_COND_PEER_RX_BUSY; + if (type == AX25_COMMAND && pf) + ax25_std_enquiry_response(ax25); + if (ax25_validate_nr(ax25, nr)) { + ax25_frames_acked(ax25, nr); + ax25_calculate_rtt(ax25); + ax25->t1timer = 0; + ax25->t3timer = ax25->t3; + ax25_requeue_frames(ax25); + } else { + ax25_std_nr_error_recovery(ax25); + ax25->state = AX25_STATE_1; + } + break; + + case AX25_I: + if (!ax25_validate_nr(ax25, nr)) { + ax25_std_nr_error_recovery(ax25); + ax25->state = AX25_STATE_1; + break; + } + if (ax25->condition & AX25_COND_PEER_RX_BUSY) { + ax25_frames_acked(ax25, nr); + } else { + ax25_check_iframes_acked(ax25, nr); + } + if (ax25->condition & AX25_COND_OWN_RX_BUSY) { + if (pf) ax25_std_enquiry_response(ax25); + break; + } + if (ns == ax25->vr) { + ax25->vr = (ax25->vr + 1) % ax25->modulus; + queued = ax25_rx_iframe(ax25, skb); + if (ax25->condition & AX25_COND_OWN_RX_BUSY) { + ax25->vr = ns; /* ax25->vr - 1 */ + if (pf) ax25_std_enquiry_response(ax25); + break; + } + ax25->condition &= ~AX25_COND_REJECT; + if (pf) { + ax25_std_enquiry_response(ax25); + } else { + if (!(ax25->condition & AX25_COND_ACK_PENDING)) { + ax25->t2timer = ax25->t2; + ax25->condition |= AX25_COND_ACK_PENDING; + } + } + } else { + if (ax25->condition & AX25_COND_REJECT) { + if (pf) ax25_std_enquiry_response(ax25); + } else { + ax25->condition |= AX25_COND_REJECT; + ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE); + ax25->condition &= ~AX25_COND_ACK_PENDING; + } + } + break; + + case AX25_FRMR: + case AX25_ILLEGAL: + ax25_std_establish_data_link(ax25); + ax25->state = AX25_STATE_1; + break; + + default: + break; + } + + return queued; +} + +/* + * State machine for state 4, Timer Recovery State. + * The handling of the timer(s) is in file ax25_std_timer.c + * Handling of state 0 and connection release is in ax25.c. + */ +static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type) +{ + int queued = 0; + + switch (frametype) { + case AX25_SABM: + case AX25_SABME: + if (frametype == AX25_SABM) { + ax25->modulus = AX25_MODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; + } else { + ax25->modulus = AX25_EMODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW]; + } + ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + ax25->condition = 0x00; + ax25->t1timer = 0; + ax25->t3timer = ax25->t3; + ax25->idletimer = ax25->idle; + ax25->vs = 0; + ax25->va = 0; + ax25->vr = 0; + ax25->state = AX25_STATE_3; + ax25->n2count = 0; + ax25_requeue_frames(ax25); + break; + + case AX25_DISC: + ax25_clear_queues(ax25); + ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); + ax25->t3timer = 0; + ax25->state = AX25_STATE_0; + if (ax25->sk != NULL) { + ax25->sk->state = TCP_CLOSE; + ax25->sk->err = 0; + ax25->sk->shutdown |= SEND_SHUTDOWN; + if (!ax25->sk->dead) + ax25->sk->state_change(ax25->sk); + ax25->sk->dead = 1; + } + break; + + case AX25_DM: + ax25_clear_queues(ax25); + ax25->t3timer = 0; + ax25->state = AX25_STATE_0; + if (ax25->sk != NULL) { + ax25->sk->state = TCP_CLOSE; + ax25->sk->err = ECONNRESET; + ax25->sk->shutdown |= SEND_SHUTDOWN; + if (!ax25->sk->dead) + ax25->sk->state_change(ax25->sk); + ax25->sk->dead = 1; + } + break; + + case AX25_RR: + case AX25_RNR: + if (frametype == AX25_RR) + ax25->condition &= ~AX25_COND_PEER_RX_BUSY; + else + ax25->condition |= AX25_COND_PEER_RX_BUSY; + if (type == AX25_RESPONSE && pf) { + ax25->t1timer = 0; + if (ax25_validate_nr(ax25, nr)) { + ax25_frames_acked(ax25, nr); + if (ax25->vs == ax25->va) { + ax25->t3timer = ax25->t3; + ax25->n2count = 0; + ax25->state = AX25_STATE_3; + } else { + ax25_requeue_frames(ax25); + } + } else { + ax25_std_nr_error_recovery(ax25); + ax25->state = AX25_STATE_1; + } + break; + } + if (type == AX25_COMMAND && pf) + ax25_std_enquiry_response(ax25); + if (ax25_validate_nr(ax25, nr)) { + ax25_frames_acked(ax25, nr); + } else { + ax25_std_nr_error_recovery(ax25); + ax25->state = AX25_STATE_1; + } + break; + + case AX25_REJ: + ax25->condition &= ~AX25_COND_PEER_RX_BUSY; + if (pf && type == AX25_RESPONSE) { + ax25->t1timer = 0; + if (ax25_validate_nr(ax25, nr)) { + ax25_frames_acked(ax25, nr); + if (ax25->vs == ax25->va) { + ax25->t3timer = ax25->t3; + ax25->n2count = 0; + ax25->state = AX25_STATE_3; + } else { + ax25_requeue_frames(ax25); + } + } else { + ax25_std_nr_error_recovery(ax25); + ax25->state = AX25_STATE_1; + } + break; + } + if (type == AX25_COMMAND && pf) + ax25_std_enquiry_response(ax25); + if (ax25_validate_nr(ax25, nr)) { + ax25_frames_acked(ax25, nr); + ax25_requeue_frames(ax25); + } else { + ax25_std_nr_error_recovery(ax25); + ax25->state = AX25_STATE_1; + } + break; + + case AX25_I: + if (!ax25_validate_nr(ax25, nr)) { + ax25_std_nr_error_recovery(ax25); + ax25->state = AX25_STATE_1; + break; + } + ax25_frames_acked(ax25, nr); + if (ax25->condition & AX25_COND_OWN_RX_BUSY) { + if (pf) ax25_std_enquiry_response(ax25); + break; + } + if (ns == ax25->vr) { + ax25->vr = (ax25->vr + 1) % ax25->modulus; + queued = ax25_rx_iframe(ax25, skb); + if (ax25->condition & AX25_COND_OWN_RX_BUSY) { + ax25->vr = ns; /* ax25->vr - 1 */ + if (pf) ax25_std_enquiry_response(ax25); + break; + } + ax25->condition &= ~AX25_COND_REJECT; + if (pf) { + ax25_std_enquiry_response(ax25); + } else { + if (!(ax25->condition & AX25_COND_ACK_PENDING)) { + ax25->t2timer = ax25->t2; + ax25->condition |= AX25_COND_ACK_PENDING; + } + } + } else { + if (ax25->condition & AX25_COND_REJECT) { + if (pf) ax25_std_enquiry_response(ax25); + } else { + ax25->condition |= AX25_COND_REJECT; + ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE); + ax25->condition &= ~AX25_COND_ACK_PENDING; + } + } + break; + + case AX25_FRMR: + case AX25_ILLEGAL: + ax25_std_establish_data_link(ax25); + ax25->state = AX25_STATE_1; + break; + + default: + break; + } + + return queued; +} + +/* + * Higher level upcall for a LAPB frame + */ +int ax25_std_frame_in(ax25_cb *ax25, struct sk_buff *skb, int type) +{ + int queued = 0, frametype, ns, nr, pf; + + frametype = ax25_decode(ax25, skb, &ns, &nr, &pf); + + switch (ax25->state) { + case AX25_STATE_1: + queued = ax25_std_state1_machine(ax25, skb, frametype, pf, type); + break; + case AX25_STATE_2: + queued = ax25_std_state2_machine(ax25, skb, frametype, pf, type); + break; + case AX25_STATE_3: + queued = ax25_std_state3_machine(ax25, skb, frametype, ns, nr, pf, type); + break; + case AX25_STATE_4: + queued = ax25_std_state4_machine(ax25, skb, frametype, ns, nr, pf, type); + break; + } + + return queued; +} + +#endif diff -u --recursive --new-file v2.1.26/linux/net/ax25/ax25_std_subr.c linux/net/ax25/ax25_std_subr.c --- v2.1.26/linux/net/ax25/ax25_std_subr.c Wed Dec 31 16:00:00 1969 +++ linux/net/ax25/ax25_std_subr.c Tue Feb 25 17:12:51 1997 @@ -0,0 +1,105 @@ +/* + * AX.25 release 036 + * + * This is ALPHA test software. This code may break your machine, randomly fail to work with new + * releases, misbehave and/or generally screw up. It might even work. + * + * This code REQUIRES 2.1.15 or higher/ NET3.038 + * + * This module: + * This module is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Most of this code is based on the SDL diagrams published in the 7th + * ARRL Computer Networking Conference papers. The diagrams have mistakes + * in them, but are mostly correct. Before you modify the code could you + * read the SDL diagrams as the code is not obvious and probably very + * easy to break; + * + * History + * AX.25 036 Jonathan(G4KLX) Split from ax25_out.c. + */ + +#include +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The following routines are taken from page 170 of the 7th ARRL Computer + * Networking Conference paper, as is the whole state machine. + */ + +void ax25_std_nr_error_recovery(ax25_cb *ax25) +{ + ax25_std_establish_data_link(ax25); +} + +void ax25_std_establish_data_link(ax25_cb *ax25) +{ + ax25->condition = 0x00; + ax25->n2count = 0; + + if (ax25->modulus == AX25_MODULUS) + ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); + else + ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND); + + ax25->t3timer = 0; + ax25->t2timer = 0; + ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25); +} + +void ax25_std_transmit_enquiry(ax25_cb *ax25) +{ + if (ax25->condition & AX25_COND_OWN_RX_BUSY) + ax25_send_control(ax25, AX25_RNR, AX25_POLLON, AX25_COMMAND); + else + ax25_send_control(ax25, AX25_RR, AX25_POLLON, AX25_COMMAND); + + ax25->condition &= ~AX25_COND_ACK_PENDING; + + ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25); +} + +void ax25_std_enquiry_response(ax25_cb *ax25) +{ + if (ax25->condition & AX25_COND_OWN_RX_BUSY) + ax25_send_control(ax25, AX25_RNR, AX25_POLLON, AX25_RESPONSE); + else + ax25_send_control(ax25, AX25_RR, AX25_POLLON, AX25_RESPONSE); + + ax25->condition &= ~AX25_COND_ACK_PENDING; +} + +void ax25_std_timeout_response(ax25_cb *ax25) +{ + if (ax25->condition & AX25_COND_OWN_RX_BUSY) + ax25_send_control(ax25, AX25_RNR, AX25_POLLOFF, AX25_RESPONSE); + else + ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE); + + ax25->condition &= ~AX25_COND_ACK_PENDING; +} + +#endif diff -u --recursive --new-file v2.1.26/linux/net/ax25/ax25_std_timer.c linux/net/ax25/ax25_std_timer.c --- v2.1.26/linux/net/ax25/ax25_std_timer.c Wed Dec 31 16:00:00 1969 +++ linux/net/ax25/ax25_std_timer.c Tue Feb 25 17:12:51 1997 @@ -0,0 +1,217 @@ +/* + * AX.25 release 036 + * + * This is ALPHA test software. This code may break your machine, randomly fail to work with new + * releases, misbehave and/or generally screw up. It might even work. + * + * This code REQUIRES 2.1.15 or higher/ NET3.038 + * + * This module: + * This module is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * History + * AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams. + * AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from the + * sock structure. + * AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names. + * AX.25 031 Joerg(DL1BKE) Added DAMA support + * AX.25 032 Joerg(DL1BKE) Fixed DAMA timeout bug + * AX.25 033 Jonathan(G4KLX) Modularisation functions. + * AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating. + * AX.25 036 Jonathan(G4KLX) Split from ax25_timer.c. + */ + +#include +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void ax25_std_timer(ax25_cb *ax25) +{ + switch (ax25->state) { + case AX25_STATE_0: + /* Magic here: If we listen() and a new link dies before it + is accepted() it isn't 'dead' so doesn't get removed. */ + if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) { + del_timer(&ax25->timer); + ax25_destroy_socket(ax25); + return; + } + break; + + case AX25_STATE_3: + case AX25_STATE_4: + /* + * Check the state of the receive buffer. + */ + if (ax25->sk != NULL) { + if (ax25->sk->rmem_alloc < (ax25->sk->rcvbuf / 2) && (ax25->condition & AX25_COND_OWN_RX_BUSY)) { + ax25->condition &= ~AX25_COND_OWN_RX_BUSY; + ax25->condition &= ~AX25_COND_ACK_PENDING; + ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE); + break; + } + } + /* + * Check for frames to transmit. + */ + ax25_kick(ax25); + break; + + default: + break; + } + + if (ax25->t2timer > 0 && --ax25->t2timer == 0) { + if (ax25->state == AX25_STATE_3 || ax25->state == AX25_STATE_4) { + if (ax25->condition & AX25_COND_ACK_PENDING) { + ax25->condition &= ~AX25_COND_ACK_PENDING; + ax25_std_timeout_response(ax25); + } + } + } + + if (ax25->t3timer > 0 && --ax25->t3timer == 0) { + if (ax25->state == AX25_STATE_3) { + ax25->n2count = 0; + ax25_std_transmit_enquiry(ax25); + ax25->state = AX25_STATE_4; + } + ax25->t3timer = ax25->t3; + } + + if (ax25->idletimer > 0 && --ax25->idletimer == 0) { + /* dl1bke 960228: close the connection when IDLE expires */ + /* similar to DAMA T3 timeout but with */ + /* a "clean" disconnect of the connection */ + + ax25_clear_queues(ax25); + + ax25->n2count = 0; + ax25->t3timer = 0; + ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); + ax25->state = AX25_STATE_2; + ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25); + + if (ax25->sk != NULL) { + ax25->sk->state = TCP_CLOSE; + ax25->sk->err = 0; + ax25->sk->shutdown |= SEND_SHUTDOWN; + if (!ax25->sk->dead) + ax25->sk->state_change(ax25->sk); + ax25->sk->dead = 1; + ax25->sk->destroy = 1; + } + } + + if (ax25->t1timer == 0 || --ax25->t1timer > 0) { + ax25_set_timer(ax25); + return; + } + + switch (ax25->state) { + case AX25_STATE_1: + if (ax25->n2count == ax25->n2) { + if (ax25->modulus == AX25_MODULUS) { + ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev); + ax25_clear_queues(ax25); + ax25->state = AX25_STATE_0; + if (ax25->sk != NULL) { + ax25->sk->state = TCP_CLOSE; + ax25->sk->err = ETIMEDOUT; + ax25->sk->shutdown |= SEND_SHUTDOWN; + if (!ax25->sk->dead) + ax25->sk->state_change(ax25->sk); + ax25->sk->dead = 1; + } + } else { + ax25->modulus = AX25_MODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; + ax25->n2count = 0; + ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); + } + } else { + ax25->n2count++; + if (ax25->modulus == AX25_MODULUS) + ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); + else + ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND); + } + break; + + case AX25_STATE_2: + if (ax25->n2count == ax25->n2) { + ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev); + ax25_clear_queues(ax25); + ax25->state = AX25_STATE_0; + ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); + + if (ax25->sk != NULL) { + ax25->sk->state = TCP_CLOSE; + ax25->sk->err = ETIMEDOUT; + ax25->sk->shutdown |= SEND_SHUTDOWN; + if (!ax25->sk->dead) + ax25->sk->state_change(ax25->sk); + ax25->sk->dead = 1; + } + } else { + ax25->n2count++; + ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); + } + break; + + case AX25_STATE_3: + ax25->n2count = 1; + ax25_std_transmit_enquiry(ax25); + ax25->state = AX25_STATE_4; + break; + + case AX25_STATE_4: + if (ax25->n2count == ax25->n2) { + ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev); + ax25_clear_queues(ax25); + ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE); + ax25->state = AX25_STATE_0; + if (ax25->sk != NULL) { + SOCK_DEBUG(ax25->sk, "AX.25 link Failure\n"); + ax25->sk->state = TCP_CLOSE; + ax25->sk->err = ETIMEDOUT; + ax25->sk->shutdown |= SEND_SHUTDOWN; + if (!ax25->sk->dead) + ax25->sk->state_change(ax25->sk); + ax25->sk->dead = 1; + } + } else { + ax25->n2count++; + ax25_std_transmit_enquiry(ax25); + } + break; + } + + ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25); + + ax25_set_timer(ax25); +} + +#endif diff -u --recursive --new-file v2.1.26/linux/net/ax25/ax25_subr.c linux/net/ax25/ax25_subr.c --- v2.1.26/linux/net/ax25/ax25_subr.c Sun Feb 2 05:18:48 1997 +++ linux/net/ax25/ax25_subr.c Tue Feb 25 17:12:51 1997 @@ -1,5 +1,5 @@ /* - * AX.25 release 035 + * AX.25 release 036 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. @@ -95,17 +95,10 @@ skb = skb_dequeue(&ax25->ack_queue); kfree_skb(skb, FREE_WRITE); ax25->va = (ax25->va + 1) % ax25->modulus; - if (ax25->dama_slave) - ax25->n2count = 0; } } } -/* - * Maybe this should be your ax25_invoke_retransmission(), which appears - * to be used but not do anything. ax25_invoke_retransmission() used to - * be in AX 0.29, but has now gone in 0.30. - */ void ax25_requeue_frames(ax25_cb *ax25) { struct sk_buff *skb, *skb_prev = NULL; @@ -200,15 +193,11 @@ { struct sk_buff *skb; unsigned char *dptr; - struct device *dev; - if ((dev = ax25->device) == NULL) - return; /* Route died */ - - if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + size_ax25_addr(ax25->digipeat) + 2, GFP_ATOMIC)) == NULL) + if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + ax25_addr_size(ax25->digipeat) + 2, GFP_ATOMIC)) == NULL) return; - skb_reserve(skb, AX25_BPQ_HEADER_LEN + size_ax25_addr(ax25->digipeat)); + skb_reserve(skb, AX25_BPQ_HEADER_LEN + ax25_addr_size(ax25->digipeat)); /* Assume a response - address structure for DTE */ if (ax25->modulus == AX25_MODULUS) { @@ -247,10 +236,10 @@ if (dev == NULL) return; - if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + size_ax25_addr(digi) + 1, GFP_ATOMIC)) == NULL) + if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + ax25_addr_size(digi) + 1, GFP_ATOMIC)) == NULL) return; /* Next SABM will get DM'd */ - skb_reserve(skb, AX25_BPQ_HEADER_LEN + size_ax25_addr(digi)); + skb_reserve(skb, AX25_BPQ_HEADER_LEN + ax25_addr_size(digi)); ax25_digi_invert(digi, &retdigi); @@ -261,8 +250,8 @@ /* * Do the address ourselves */ - dptr = skb_push(skb, size_ax25_addr(digi)); - dptr += build_ax25_addr(dptr, dest, src, &retdigi, AX25_RESPONSE, AX25_MODULUS); + dptr = skb_push(skb, ax25_addr_size(digi)); + dptr += ax25_addr_build(dptr, dest, src, &retdigi, AX25_RESPONSE, AX25_MODULUS); skb->dev = dev; skb->priority = SOPRI_NORMAL; @@ -308,249 +297,6 @@ if (ax25->rtt > AX25_T1CLAMPHI) ax25->rtt = AX25_T1CLAMPHI; -} - -/* - * Digipeated address processing - */ - - -/* - * Given an AX.25 address pull of to, from, digi list, command/response and the start of data - * - */ -unsigned char *ax25_parse_addr(unsigned char *buf, int len, ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags, int *dama) -{ - int d = 0; - - if (len < 14) return NULL; - - if (flags != NULL) { - *flags = 0; - - if (buf[6] & AX25_CBIT) - *flags = AX25_COMMAND; - if (buf[13] & AX25_CBIT) - *flags = AX25_RESPONSE; - } - - if (dama != NULL) - *dama = ~buf[13] & AX25_DAMA_FLAG; - - /* Copy to, from */ - if (dest != NULL) - memcpy(dest, buf + 0, AX25_ADDR_LEN); - - if (src != NULL) - memcpy(src, buf + 7, AX25_ADDR_LEN); - - buf += 2 * AX25_ADDR_LEN; - len -= 2 * AX25_ADDR_LEN; - digi->lastrepeat = -1; - digi->ndigi = 0; - - while (!(buf[-1] & AX25_EBIT)) { - if (d >= AX25_MAX_DIGIS) return NULL; /* Max of 6 digis */ - if (len < 7) return NULL; /* Short packet */ - - if (digi != NULL) { - memcpy(&digi->calls[d], buf, AX25_ADDR_LEN); - digi->ndigi = d + 1; - if (buf[6] & AX25_HBIT) { - digi->repeated[d] = 1; - digi->lastrepeat = d; - } else { - digi->repeated[d] = 0; - } - } - - buf += AX25_ADDR_LEN; - len -= AX25_ADDR_LEN; - d++; - } - - return buf; -} - -/* - * Assemble an AX.25 header from the bits - */ -int build_ax25_addr(unsigned char *buf, ax25_address *src, ax25_address *dest, ax25_digi *d, int flag, int modulus) -{ - int len = 0; - int ct = 0; - - memcpy(buf, dest, AX25_ADDR_LEN); - buf[6] &= ~(AX25_EBIT | AX25_CBIT); - buf[6] |= AX25_SSSID_SPARE; - - if (flag == AX25_COMMAND) buf[6] |= AX25_CBIT; - - buf += AX25_ADDR_LEN; - len += AX25_ADDR_LEN; - - memcpy(buf, src, AX25_ADDR_LEN); - buf[6] &= ~(AX25_EBIT | AX25_CBIT); - buf[6] &= ~AX25_SSSID_SPARE; - - if (modulus == AX25_MODULUS) - buf[6] |= AX25_SSSID_SPARE; - else - buf[6] |= AX25_ESSID_SPARE; - - if (flag == AX25_RESPONSE) buf[6] |= AX25_CBIT; - - /* - * Fast path the normal digiless path - */ - if (d == NULL || d->ndigi == 0) { - buf[6] |= AX25_EBIT; - return 2 * AX25_ADDR_LEN; - } - - buf += AX25_ADDR_LEN; - len += AX25_ADDR_LEN; - - while (ct < d->ndigi) { - memcpy(buf, &d->calls[ct], AX25_ADDR_LEN); - - if (d->repeated[ct]) - buf[6] |= AX25_HBIT; - else - buf[6] &= ~AX25_HBIT; - - buf[6] &= ~AX25_EBIT; - buf[6] |= AX25_SSSID_SPARE; - - buf += AX25_ADDR_LEN; - len += AX25_ADDR_LEN; - ct++; - } - - buf[-1] |= AX25_EBIT; - - return len; -} - -int size_ax25_addr(ax25_digi *dp) -{ - if (dp == NULL) - return 2 * AX25_ADDR_LEN; - - return AX25_ADDR_LEN * (2 + dp->ndigi); -} - -/* - * Reverse Digipeat List. May not pass both parameters as same struct - */ -void ax25_digi_invert(ax25_digi *in, ax25_digi *out) -{ - int ct = 0; - - out->ndigi = in->ndigi; - out->lastrepeat = in->ndigi - in->lastrepeat - 2; - - /* Invert the digipeaters */ - - while (ct < in->ndigi) { - out->calls[ct] = in->calls[in->ndigi - ct - 1]; - if (ct <= out->lastrepeat) { - out->calls[ct].ax25_call[6] |= AX25_HBIT; - out->repeated[ct] = 1; - } else { - out->calls[ct].ax25_call[6] &= ~AX25_HBIT; - out->repeated[ct] = 0; - } - ct++; - } -} - -/* - * count the number of buffers on a list belonging to the same - * socket as skb - */ -static int ax25_list_length(struct sk_buff_head *list, struct sk_buff *skb) -{ - int count = 0; - long flags; - struct sk_buff *skbq; - - save_flags(flags); - cli(); - - if (list == NULL) { - restore_flags(flags); - return 0; - } - - for (skbq = list->next; skbq != (struct sk_buff *)list; skbq = skbq->next) - if (skb->sk == skbq->sk) - count++; - - restore_flags(flags); - - return count; -} - -/* - * count the number of buffers of one socket on the write/ack-queue - */ -int ax25_queue_length(ax25_cb *ax25, struct sk_buff *skb) -{ - return ax25_list_length(&ax25->write_queue, skb) + ax25_list_length(&ax25->ack_queue, skb); -} - -/* - * :::FIXME::: - * This is ****NOT**** the right approach. Not all drivers do kiss. We - * need a driver level request to switch duplex mode, that does either - * SCC changing, PI config or KISS as required. - * - * Not to mention this request isn't currently reliable. - */ -void ax25_kiss_cmd(ax25_cb *ax25, unsigned char cmd, unsigned char param) -{ - struct sk_buff *skb; - unsigned char *p; - - if (ax25->device == NULL) - return; - - if ((skb = alloc_skb(2, GFP_ATOMIC)) == NULL) - return; - - p = skb_put(skb, 2); - - *p++ = cmd; - *p++ = param; - - skb->arp = 1; - skb->dev = ax25->device; - skb->priority = SOPRI_NORMAL; - skb->protocol = htons(ETH_P_AX25); - - dev_queue_xmit(skb); -} - -void ax25_dama_on(ax25_cb *ax25) -{ - if (ax25_dev_is_dama_slave(ax25->device) == 0) { - SOCK_DEBUG(ax25->sk, "ax25_dama_on: DAMA on\n"); - ax25_kiss_cmd(ax25, 5, 1); - } -} - -void ax25_dama_off(ax25_cb *ax25) -{ - if (ax25->dama_slave == 0) - return; - - ax25->dama_slave = 0; - - if (ax25_dev_is_dama_slave(ax25->device) == 0) { - SOCK_DEBUG(ax25->sk, "ax25_dama_off: DAMA off\n"); - ax25_kiss_cmd(ax25, 5, 0); - } } #endif diff -u --recursive --new-file v2.1.26/linux/net/ax25/ax25_timer.c linux/net/ax25/ax25_timer.c --- v2.1.26/linux/net/ax25/ax25_timer.c Sun Feb 2 05:18:48 1997 +++ linux/net/ax25/ax25_timer.c Tue Feb 25 17:12:51 1997 @@ -1,5 +1,5 @@ /* - * AX.25 release 035 + * AX.25 release 036 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. @@ -21,6 +21,7 @@ * AX.25 032 Joerg(DL1BKE) Fixed DAMA timeout bug * AX.25 033 Jonathan(G4KLX) Modularisation functions. * AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating. + * AX.25 036 Jonathan(G4KLX) Split Standard and DAMA code into seperate files. */ #include @@ -76,463 +77,16 @@ { ax25_cb *ax25 = (ax25_cb *)param; - switch (ax25->state) { - case AX25_STATE_0: - /* Magic here: If we listen() and a new link dies before it - is accepted() it isn't 'dead' so doesn't get removed. */ - if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) { - del_timer(&ax25->timer); - ax25_destroy_socket(ax25); - return; - } + switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { + case AX25_PROTO_STD: + ax25_std_timer(ax25); + break; +#ifdef CONFIG_AX25_DAMA_SLAVE + case AX25_PROTO_DAMA_SLAVE: + ax25_ds_timer(ax25); break; - - case AX25_STATE_3: - case AX25_STATE_4: - /* - * Check the state of the receive buffer. - */ - if (ax25->sk != NULL) { - if (ax25->sk->rmem_alloc < (ax25->sk->rcvbuf / 2) && (ax25->condition & AX25_COND_OWN_RX_BUSY)) { - ax25->condition &= ~AX25_COND_OWN_RX_BUSY; - ax25->condition &= ~AX25_COND_ACK_PENDING; - if (!ax25->dama_slave) - ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE); - break; - } - } - /* - * Check for frames to transmit. - */ - if (!ax25->dama_slave) - ax25_kick(ax25); - break; - - default: - break; - } - - if (ax25->t2timer > 0 && --ax25->t2timer == 0) { - if (ax25->state == AX25_STATE_3 || ax25->state == AX25_STATE_4) { - if (ax25->condition & AX25_COND_ACK_PENDING) { - ax25->condition &= ~AX25_COND_ACK_PENDING; - if (!ax25->dama_slave) - ax25_timeout_response(ax25); - } - } - } - - if (ax25->t3timer > 0 && --ax25->t3timer == 0) { - /* dl1bke 960114: T3 expires and we are in DAMA mode: */ - /* send a DISC and abort the connection */ - if (ax25->dama_slave) { - ax25_link_failed(&ax25->dest_addr, ax25->device); - ax25_clear_queues(ax25); - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - - ax25->state = AX25_STATE_0; - if (ax25->sk != NULL) { - SOCK_DEBUG(ax25->sk, "AX.25 T3 Timeout\n"); - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = ETIMEDOUT; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - } - - ax25_set_timer(ax25); - return; - } - - if (ax25->state == AX25_STATE_3) { - ax25->n2count = 0; - ax25_transmit_enquiry(ax25); - ax25->state = AX25_STATE_4; - } - ax25->t3timer = ax25->t3; - } - - if (ax25->idletimer > 0 && --ax25->idletimer == 0) { - /* dl1bke 960228: close the connection when IDLE expires */ - /* similar to DAMA T3 timeout but with */ - /* a "clean" disconnect of the connection */ - - ax25_clear_queues(ax25); - - ax25->n2count = 0; - if (!ax25->dama_slave) { - ax25->t3timer = 0; - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - } else { - ax25->t3timer = ax25->t3; - } - - /* state 1 or 2 should not happen, but... */ - - if (ax25->state == AX25_STATE_1 || ax25->state == AX25_STATE_2) - ax25->state = AX25_STATE_0; - else - ax25->state = AX25_STATE_2; - - ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25); - - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = 0; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - ax25->sk->destroy = 1; - } - } - - /* dl1bke 960114: DAMA T1 timeouts are handled in ax25_dama_slave_transmit */ - /* nevertheless we have to re-enqueue the timer struct... */ - if (ax25->t1timer == 0 || --ax25->t1timer > 0) { - ax25_set_timer(ax25); - return; - } - - if (!ax25_dev_is_dama_slave(ax25->device)) { - if (ax25->dama_slave) - ax25->dama_slave = 0; - ax25_t1_timeout(ax25); - } -} - - -/* dl1bke 960114: The DAMA protocol requires to send data and SABM/DISC - * within the poll of any connected channel. Remember - * that we are not allowed to send anything unless we - * get polled by the Master. - * - * Thus we'll have to do parts of our T1 handling in - * ax25_enquiry_response(). - */ -void ax25_t1_timeout(ax25_cb *ax25) -{ - switch (ax25->state) { - case AX25_STATE_1: - if (ax25->n2count == ax25->n2) { - if (ax25->modulus == AX25_MODULUS) { - ax25_link_failed(&ax25->dest_addr, ax25->device); - ax25_clear_queues(ax25); - ax25->state = AX25_STATE_0; - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = ETIMEDOUT; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - } - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW); - ax25->n2count = 0; - ax25_send_control(ax25, AX25_SABM, ax25_dev_is_dama_slave(ax25->device) ? AX25_POLLOFF : AX25_POLLON, AX25_COMMAND); - } - } else { - ax25->n2count++; - if (ax25->modulus == AX25_MODULUS) - ax25_send_control(ax25, AX25_SABM, ax25_dev_is_dama_slave(ax25->device) ? AX25_POLLOFF : AX25_POLLON, AX25_COMMAND); - else - ax25_send_control(ax25, AX25_SABME, ax25_dev_is_dama_slave(ax25->device) ? AX25_POLLOFF : AX25_POLLON, AX25_COMMAND); - } - break; - - case AX25_STATE_2: - if (ax25->n2count == ax25->n2) { - ax25_link_failed(&ax25->dest_addr, ax25->device); - ax25_clear_queues(ax25); - ax25->state = AX25_STATE_0; - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - - if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = ETIMEDOUT; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - } - } else { - ax25->n2count++; - if (!ax25_dev_is_dama_slave(ax25->device)) - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - } - break; - - case AX25_STATE_3: - ax25->n2count = 1; - if (!ax25->dama_slave) - ax25_transmit_enquiry(ax25); - ax25->state = AX25_STATE_4; - break; - - case AX25_STATE_4: - if (ax25->n2count == ax25->n2) { - ax25_link_failed(&ax25->dest_addr, ax25->device); - ax25_clear_queues(ax25); - ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE); - ax25->state = AX25_STATE_0; - if (ax25->sk != NULL) { - SOCK_DEBUG(ax25->sk, "AX.25 link Failure\n"); - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = ETIMEDOUT; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!ax25->sk->dead) - ax25->sk->state_change(ax25->sk); - ax25->sk->dead = 1; - } - } else { - ax25->n2count++; - if (!ax25->dama_slave) - ax25_transmit_enquiry(ax25); - } - break; - } - - ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25); - - ax25_set_timer(ax25); -} - -/************************************************************************/ -/* Module support functions follow. */ -/************************************************************************/ - -static struct protocol_struct { - struct protocol_struct *next; - unsigned int pid; - int (*func)(struct sk_buff *, ax25_cb *); -} *protocol_list = NULL; - -static struct linkfail_struct { - struct linkfail_struct *next; - void (*func)(ax25_address *, struct device *); -} *linkfail_list = NULL; - -static struct listen_struct { - struct listen_struct *next; - ax25_address callsign; - struct device *dev; -} *listen_list = NULL; - -int ax25_protocol_register(unsigned int pid, int (*func)(struct sk_buff *, ax25_cb *)) -{ - struct protocol_struct *protocol; - unsigned long flags; - - if (pid == AX25_P_TEXT || pid == AX25_P_SEGMENT) - return 0; -#ifdef CONFIG_INET - if (pid == AX25_P_IP || pid == AX25_P_ARP) - return 0; #endif - if ((protocol = (struct protocol_struct *)kmalloc(sizeof(*protocol), GFP_ATOMIC)) == NULL) - return 0; - - protocol->pid = pid; - protocol->func = func; - - save_flags(flags); - cli(); - - protocol->next = protocol_list; - protocol_list = protocol; - - restore_flags(flags); - - return 1; -} - -void ax25_protocol_release(unsigned int pid) -{ - struct protocol_struct *s, *protocol = protocol_list; - unsigned long flags; - - if (protocol == NULL) - return; - - save_flags(flags); - cli(); - - if (protocol->pid == pid) { - protocol_list = protocol->next; - restore_flags(flags); - kfree_s(protocol, sizeof(struct protocol_struct)); - return; - } - - while (protocol != NULL && protocol->next != NULL) { - if (protocol->next->pid == pid) { - s = protocol->next; - protocol->next = protocol->next->next; - restore_flags(flags); - kfree_s(s, sizeof(struct protocol_struct)); - return; - } - - protocol = protocol->next; } - - restore_flags(flags); -} - -int ax25_linkfail_register(void (*func)(ax25_address *, struct device *)) -{ - struct linkfail_struct *linkfail; - unsigned long flags; - - if ((linkfail = (struct linkfail_struct *)kmalloc(sizeof(*linkfail), GFP_ATOMIC)) == NULL) - return 0; - - linkfail->func = func; - - save_flags(flags); - cli(); - - linkfail->next = linkfail_list; - linkfail_list = linkfail; - - restore_flags(flags); - - return 1; -} - -void ax25_linkfail_release(void (*func)(ax25_address *, struct device *)) -{ - struct linkfail_struct *s, *linkfail = linkfail_list; - unsigned long flags; - - if (linkfail == NULL) - return; - - save_flags(flags); - cli(); - - if (linkfail->func == func) { - linkfail_list = linkfail->next; - restore_flags(flags); - kfree_s(linkfail, sizeof(struct linkfail_struct)); - return; - } - - while (linkfail != NULL && linkfail->next != NULL) { - if (linkfail->next->func == func) { - s = linkfail->next; - linkfail->next = linkfail->next->next; - restore_flags(flags); - kfree_s(s, sizeof(struct linkfail_struct)); - return; - } - - linkfail = linkfail->next; - } - - restore_flags(flags); -} - -int ax25_listen_register(ax25_address *callsign, struct device *dev) -{ - struct listen_struct *listen; - unsigned long flags; - - if (ax25_listen_mine(callsign, dev)) - return 0; - - if ((listen = (struct listen_struct *)kmalloc(sizeof(*listen), GFP_ATOMIC)) == NULL) - return 0; - - listen->callsign = *callsign; - listen->dev = dev; - - save_flags(flags); - cli(); - - listen->next = listen_list; - listen_list = listen; - - restore_flags(flags); - - return 1; -} - -void ax25_listen_release(ax25_address *callsign, struct device *dev) -{ - struct listen_struct *s, *listen = listen_list; - unsigned long flags; - - if (listen == NULL) - return; - - save_flags(flags); - cli(); - - if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) { - listen_list = listen->next; - restore_flags(flags); - kfree_s(listen, sizeof(struct listen_struct)); - return; - } - - while (listen != NULL && listen->next != NULL) { - if (ax25cmp(&listen->next->callsign, callsign) == 0 && listen->next->dev == dev) { - s = listen->next; - listen->next = listen->next->next; - restore_flags(flags); - kfree_s(s, sizeof(struct listen_struct)); - return; - } - - listen = listen->next; - } - - restore_flags(flags); -} - -int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *) -{ - struct protocol_struct *protocol; - - for (protocol = protocol_list; protocol != NULL; protocol = protocol->next) - if (protocol->pid == pid) - return protocol->func; - - return NULL; -} - -int ax25_listen_mine(ax25_address *callsign, struct device *dev) -{ - struct listen_struct *listen; - - for (listen = listen_list; listen != NULL; listen = listen->next) - if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL)) - return 1; - - return 0; -} - -void ax25_link_failed(ax25_address *callsign, struct device *dev) -{ - struct linkfail_struct *linkfail; - - for (linkfail = linkfail_list; linkfail != NULL; linkfail = linkfail->next) - (linkfail->func)(callsign, dev); -} - -int ax25_protocol_is_registered(unsigned int pid) -{ - struct protocol_struct *protocol; - - for (protocol = protocol_list; protocol != NULL; protocol = protocol->next) - if (protocol->pid == pid) - return 1; - - return 0; } #endif diff -u --recursive --new-file v2.1.26/linux/net/ax25/ax25_uid.c linux/net/ax25/ax25_uid.c --- v2.1.26/linux/net/ax25/ax25_uid.c Wed Dec 31 16:00:00 1969 +++ linux/net/ax25/ax25_uid.c Tue Feb 25 17:12:51 1997 @@ -0,0 +1,189 @@ +/* + * AX.25 release 036 + * + * This is ALPHA test software. This code may break your machine, randomly fail to work with new + * releases, misbehave and/or generally screw up. It might even work. + * + * This code REQUIRES 2.1.15 or higher/ NET3.038 + * + * This module: + * This module is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * History + * AX.25 036 Jonathan(G4KLX) Split from af_ax25.c. + */ + +#include +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Callsign/UID mapper. This is in kernel space for security on multi-amateur machines. + */ + +static ax25_uid_assoc *ax25_uid_list = NULL; + +int ax25_uid_policy = 0; + +ax25_address *ax25_findbyuid(uid_t uid) +{ + ax25_uid_assoc *ax25_uid; + + for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { + if (ax25_uid->uid == uid) + return &ax25_uid->call; + } + + return NULL; +} + +int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) +{ + ax25_uid_assoc *s, *ax25_uid; + unsigned long flags; + + switch (cmd) { + case SIOCAX25GETUID: + for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { + if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) + return ax25_uid->uid; + } + return -ENOENT; + + case SIOCAX25ADDUID: + if (!suser()) + return -EPERM; + if (ax25_findbyuid(sax->sax25_uid)) + return -EEXIST; + if (sax->sax25_uid == 0) + return -EINVAL; + if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL) + return -ENOMEM; + ax25_uid->uid = sax->sax25_uid; + ax25_uid->call = sax->sax25_call; + save_flags(flags); cli(); + ax25_uid->next = ax25_uid_list; + ax25_uid_list = ax25_uid; + restore_flags(flags); + return 0; + + case SIOCAX25DELUID: + if (!suser()) + return -EPERM; + for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { + if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) + break; + } + if (ax25_uid == NULL) + return -ENOENT; + save_flags(flags); cli(); + if ((s = ax25_uid_list) == ax25_uid) { + ax25_uid_list = s->next; + restore_flags(flags); + kfree_s(ax25_uid, sizeof(ax25_uid_assoc)); + return 0; + } + while (s != NULL && s->next != NULL) { + if (s->next == ax25_uid) { + s->next = ax25_uid->next; + restore_flags(flags); + kfree_s(ax25_uid, sizeof(ax25_uid_assoc)); + return 0; + } + s = s->next; + } + restore_flags(flags); + return -ENOENT; + + default: + return -EINVAL; + } + + return -EINVAL; /*NOTREACHED */ +} + +int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length, int dummy) +{ + ax25_uid_assoc *pt; + int len = 0; + off_t pos = 0; + off_t begin = 0; + + cli(); + + len += sprintf(buffer, "Policy: %d\n", ax25_uid_policy); + + for (pt = ax25_uid_list; pt != NULL; pt = pt->next) { + len += sprintf(buffer + len, "%6d %s\n", pt->uid, ax2asc(&pt->call)); + + pos = begin + len; + + if (pos < offset) { + len = 0; + begin = pos; + } + + if (pos > offset + length) + break; + } + + sti(); + + *start = buffer + (offset - begin); + len -= offset - begin; + + if (len > length) len = length; + + return len; +} + +#ifdef MODULE + +/* + * Free all memory associated with UID/Callsign structures. + */ +void ax25_uid_free(void) +{ + ax25_uid_assoc *s, *ax25_uid = ax25_uid_list; + + while (ax25_uid != NULL) { + s = ax25_uid; + ax25_uid = ax25_uid->next; + + kfree_s(s, sizeof(ax25_uid_assoc)); + } +} + +#endif + +#endif diff -u --recursive --new-file v2.1.26/linux/net/ax25/sysctl_net_ax25.c linux/net/ax25/sysctl_net_ax25.c --- v2.1.26/linux/net/ax25/sysctl_net_ax25.c Sun Feb 2 05:18:48 1997 +++ linux/net/ax25/sysctl_net_ax25.c Tue Feb 25 17:12:51 1997 @@ -9,17 +9,27 @@ #include #include -static int min_ax25[] = {0, 0, 0, 0, 0, 1, 1, 1, 1, - 0, 0, 1, 1, 1, 0x00}; -static int max_ax25[] = {1, 1, 1, 2, 1, 7, 63, 30 * AX25_SLOWHZ, 20 * AX25_SLOWHZ, - 3600 * AX25_SLOWHZ, 65535 * AX25_SLOWHZ, 31, 512, 20, 0x03}; +static int min_ipdefmode[] = {0}, max_ipdefmode[] = {1}; +static int min_axdefmode[] = {0}, max_axdefmode[] = {1}; +static int min_backoff[] = {0}, max_backoff[] = {2}; +static int min_conmode[] = {0}, max_conmode[] = {2}; +static int min_window[] = {1}, max_window[] = {7}; +static int min_ewindow[] = {1}, max_ewindow[] = {63}; +static int min_t1[] = {1}, max_t1[] = {30 * AX25_SLOWHZ}; +static int min_t2[] = {1}, max_t2[] = {20 * AX25_SLOWHZ}; +static int min_t3[] = {0}, max_t3[] = {3600 * AX25_SLOWHZ}; +static int min_idle[] = {0}, max_idle[] = {65535 * AX25_SLOWHZ}; +static int min_n2[] = {1}, max_n2[] = {31}; +static int min_paclen[] = {1}, max_paclen[] = {512}; +static int min_proto[] = {0}, max_proto[] = {2}; static struct ctl_table_header *ax25_table_header; -static ctl_table ax25_table[AX25_MAX_DEVICES + 1]; +static ctl_table *ax25_table = NULL; +static int ax25_table_size = 0; static ctl_table ax25_dir_table[] = { - {NET_AX25, "ax25", NULL, 0, 0555, ax25_table}, + {NET_AX25, "ax25", NULL, 0, 0555, NULL}, {0} }; @@ -28,33 +38,104 @@ {0} }; +static const ctl_table ax25_param_table[] = { + {NET_AX25_IP_DEFAULT_MODE, "ip_default_mode", + NULL, sizeof(int), 0644, NULL, + &proc_dointvec_minmax, &sysctl_intvec, NULL, + &min_ipdefmode, &max_ipdefmode}, + {NET_AX25_DEFAULT_MODE, "ax25_default_mode", + NULL, sizeof(int), 0644, NULL, + &proc_dointvec_minmax, &sysctl_intvec, NULL, + &min_axdefmode, &max_axdefmode}, + {NET_AX25_BACKOFF_TYPE, "backoff_type", + NULL, sizeof(int), 0644, NULL, + &proc_dointvec_minmax, &sysctl_intvec, NULL, + &min_backoff, &max_backoff}, + {NET_AX25_CONNECT_MODE, "connect_mode", + NULL, sizeof(int), 0644, NULL, + &proc_dointvec_minmax, &sysctl_intvec, NULL, + &min_conmode, &max_conmode}, + {NET_AX25_STANDARD_WINDOW, "standard_window_size", + NULL, sizeof(int), 0644, NULL, + &proc_dointvec_minmax, &sysctl_intvec, NULL, + &min_window, &max_window}, + {NET_AX25_EXTENDED_WINDOW, "extended_window_size", + NULL, sizeof(int), 0644, NULL, + &proc_dointvec_minmax, &sysctl_intvec, NULL, + &min_ewindow, &max_ewindow}, + {NET_AX25_T1_TIMEOUT, "t1_timeout", + NULL, sizeof(int), 0644, NULL, + &proc_dointvec_minmax, &sysctl_intvec, NULL, + &min_t1, &max_t1}, + {NET_AX25_T2_TIMEOUT, "t2_timeout", + NULL, sizeof(int), 0644, NULL, + &proc_dointvec_minmax, &sysctl_intvec, NULL, + &min_t2, &max_t2}, + {NET_AX25_T3_TIMEOUT, "t3_timeout", + NULL, sizeof(int), 0644, NULL, + &proc_dointvec_minmax, &sysctl_intvec, NULL, + &min_t3, &max_t3}, + {NET_AX25_IDLE_TIMEOUT, "idle_timeout", + NULL, sizeof(int), 0644, NULL, + &proc_dointvec_minmax, &sysctl_intvec, NULL, + &min_idle, &max_idle}, + {NET_AX25_N2, "maximum_retry_count", + NULL, sizeof(int), 0644, NULL, + &proc_dointvec_minmax, &sysctl_intvec, NULL, + &min_n2, &max_n2}, + {NET_AX25_PACLEN, "maximum_packet_length", + NULL, sizeof(int), 0644, NULL, + &proc_dointvec_minmax, &sysctl_intvec, NULL, + &min_paclen, &max_paclen}, + {NET_AX25_PROTOCOL, "protocol", + NULL, sizeof(int), 0644, NULL, + &proc_dointvec_minmax, &sysctl_intvec, NULL, + &min_proto, &max_proto}, + {0} /* that's all, folks! */ +}; + void ax25_register_sysctl(void) { - int i, n; + ax25_dev *ax25_dev; + int n, k; + + for (ax25_table_size = sizeof(ctl_table), ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) + ax25_table_size += sizeof(ctl_table); + + if ((ax25_table = kmalloc(ax25_table_size, GFP_ATOMIC)) == NULL) + return; + + memset(ax25_table, 0x00, ax25_table_size); + + for (n = 0, ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) { + ax25_table[n].ctl_name = n + 1; + ax25_table[n].procname = ax25_dev->dev->name; + ax25_table[n].data = NULL; + ax25_table[n].maxlen = 0; + ax25_table[n].mode = 0555; + ax25_table[n].child = ax25_dev->systable; + ax25_table[n].proc_handler = NULL; - memset(ax25_table, 0x00, (AX25_MAX_DEVICES + 1) * sizeof(ctl_table)); + memcpy(ax25_dev->systable, ax25_param_table, sizeof(ax25_dev->systable)); - for (n = 0, i = 0; i < AX25_MAX_DEVICES; i++) { - if (ax25_device[i].dev != NULL) { - ax25_table[n].ctl_name = n + 1; - ax25_table[n].procname = ax25_device[i].name; - ax25_table[n].data = &ax25_device[i].values; - ax25_table[n].maxlen = AX25_MAX_VALUES * sizeof(int); - ax25_table[n].mode = 0644; - ax25_table[n].child = NULL; - ax25_table[n].proc_handler = &proc_dointvec_minmax; - ax25_table[n].strategy = &sysctl_intvec; - ax25_table[n].de = NULL; - ax25_table[n].extra1 = &min_ax25; - ax25_table[n].extra2 = &max_ax25; - n++; - } + ax25_dev->systable[AX25_MAX_VALUES].ctl_name = 0; /* just in case... */ + + for (k = 0; k < AX25_MAX_VALUES; k++) + ax25_dev->systable[k].data = &ax25_dev->values[k]; + + n++; } + ax25_dir_table[0].child = ax25_table; + ax25_table_header = register_sysctl_table(ax25_root_table, 1); } void ax25_unregister_sysctl(void) { unregister_sysctl_table(ax25_table_header); + + kfree_s(ax25_table, ax25_table_size); + + ax25_dir_table[0].child = NULL; } diff -u --recursive --new-file v2.1.26/linux/net/core/sock.c linux/net/core/sock.c --- v2.1.26/linux/net/core/sock.c Tue Feb 4 06:44:25 1997 +++ linux/net/core/sock.c Tue Feb 25 17:12:51 1997 @@ -145,7 +145,7 @@ } #endif - if (optval == NULL) + if(optlendebug=valbool; @@ -186,9 +186,10 @@ val = 65535; sk->sndbuf = val; /* - * FIXME: Wake up sending tasks if we + * Wake up sending tasks if we * upped the value. */ + sk->write_space(sk); break; case SO_RCVBUF: @@ -221,17 +222,15 @@ case SO_PRIORITY: if (val >= 0 && val < DEV_NUMBUFFS) - { sk->priority = val; - } else - { return(-EINVAL); - } break; case SO_LINGER: + if(optlenpasscred = valbool; break; - /* We implementation the SO_SNDLOWAT etc to + /* We implement the SO_SNDLOWAT etc to not be settable (1003.1g 5.3) */ default: return(-ENOPROTOOPT); @@ -269,8 +268,11 @@ { struct sock *sk = sock->sk; int val; - int err; struct linger ling; + int len; + + if(get_user(len,optlen)) + return -EFAULT; switch(optname) { @@ -325,15 +327,19 @@ break; case SO_LINGER: - err = put_user(sizeof(ling), optlen); + { + int err; + len=min(len,sizeof(ling)); + if (put_user(len, optlen)) if (!err) { ling.l_onoff=sk->linger; ling.l_linger=sk->lingertime; - err = copy_to_user(optval,&ling,sizeof(ling)); + err = copy_to_user(optval,&ling,len); if (err) err = -EFAULT; } return err; + } case SO_BSDCOMPAT: val = sk->bsdism; @@ -343,8 +349,10 @@ case SO_SNDTIMEO: { static struct timeval tm={0,0}; - int err=copy_to_user(optval,&tm,sizeof(tm)); - if(err!=sizeof(struct timeval)) + len=min(len, sizeof(struct timeval)); + if(put_user(len,optlen)) + return -EFAULT; + if(copy_to_user(optval,&tm,len)) return -EFAULT; return 0; } @@ -357,19 +365,22 @@ break; case SO_PEERCRED: - err = put_user(sizeof(sk->peercred), optlen); - if (!err) - err = copy_to_user((void*)optval, &sk->peercred, sizeof(struct ucred)); - return err; - + len=min(len, sizeof(sk->peercred)); + if(put_user(len, optlen)) + return -EFAULT; + if(copy_to_user((void*)optval, &sk->peercred, len)) + return -EFAULT; + return 0; default: return(-ENOPROTOOPT); } - err = put_user(sizeof(int), optlen); - if (!err) - err = put_user(val,(unsigned int *)optval); + len=min(len,sizeof(int)); + if(put_user(len, optlen)) + return -EFAULT; + if(copy_to_user(optval,&val,len)) + return -EFAULT; - return err; + return 0; } static kmem_cache_t *sk_cachep; @@ -743,6 +754,27 @@ default: return(-EINVAL); } +} + +/* + * Default socket getsockopt / setsockopt + */ + +int sock_no_setsockopt(struct socket *sock, int level, int optname, + char *optval, int optlen) +{ + return -EOPNOTSUPP; +} + +int sock_no_getsockopt(struct socket *sock, int level, int optname, + char *optval, int *optlen) +{ + return -EOPNOTSUPP; +} + +int sock_no_listen(struct socket *sock, int backlog) +{ + return -EOPNOTSUPP; } /* diff -u --recursive --new-file v2.1.26/linux/net/ethernet/eth.c linux/net/ethernet/eth.c --- v2.1.26/linux/net/ethernet/eth.c Sun Jan 26 02:07:50 1997 +++ linux/net/ethernet/eth.c Fri Feb 21 14:58:38 1997 @@ -182,6 +182,7 @@ if (ndisc_eth_hook) return (ndisc_eth_hook(eth->h_dest, dev, skb)); #endif + break; #endif default: printk(KERN_DEBUG diff -u --recursive --new-file v2.1.26/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v2.1.26/linux/net/ipv4/af_inet.c Sun Feb 2 05:18:49 1997 +++ linux/net/ipv4/af_inet.c Tue Feb 25 17:12:51 1997 @@ -1612,7 +1612,7 @@ inet_getname, datagram_poll, inet_ioctl, - NULL, + sock_no_listen, inet_shutdown, inet_setsockopt, inet_getsockopt, diff -u --recursive --new-file v2.1.26/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c --- v2.1.26/linux/net/ipv4/igmp.c Thu Dec 12 06:54:23 1996 +++ linux/net/ipv4/igmp.c Fri Feb 21 14:58:38 1997 @@ -64,6 +64,7 @@ * Alexey Kuznetsov: Wrong group leaving behaviour, backport * fix from pending 2.1.x patches. * Alan Cox: Forget to enable FDDI support earlier. + * Alexey Kuznetsov: Fixed leaving groups on device down. */ @@ -553,12 +554,16 @@ { struct ip_mc_list *i; struct ip_mc_list *j; + start_bh_atomic(); for(i=dev->ip_mc_list;i!=NULL;i=j) { j=i->next; + if(i->tm_running) + del_timer(&i->timer); kfree_s(i,sizeof(*i)); } dev->ip_mc_list=NULL; + end_bh_atomic(); } /* diff -u --recursive --new-file v2.1.26/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c --- v2.1.26/linux/net/ipv4/ip_fw.c Sun Feb 2 05:18:49 1997 +++ linux/net/ipv4/ip_fw.c Tue Feb 25 17:12:51 1997 @@ -571,7 +571,7 @@ answer = FW_BLOCK; #ifdef CONFIG_IP_FIREWALL_NETLINK - if(answer == FW_REJECT || answer == FW_BLOCK) + if((policy&IP_FW_F_PRN) && (answer == FW_REJECT || answer == FW_BLOCK)) { struct sk_buff *skb=alloc_skb(128, GFP_ATOMIC); if(skb) @@ -1320,4 +1320,8 @@ /* Register for device up/down reports */ register_netdevice_notifier(&ipfw_dev_notifier); #endif + +#ifdef CONFIG_IP_FIREWALL_NETLINK + netlink_attach(NETLINK_FIREWALL, netlink_donothing); /* XXX */ +#endif /* CONFIG_IP_FIREWALL_NETLINK */ } diff -u --recursive --new-file v2.1.26/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c --- v2.1.26/linux/net/ipv4/ip_output.c Thu Dec 12 06:54:24 1996 +++ linux/net/ipv4/ip_output.c Fri Feb 21 14:58:38 1997 @@ -972,12 +972,16 @@ if (dev->family != AF_INET) return NOTIFY_DONE; - if(event==NETDEV_UP) { -/* - * Join the initial group if multicast. - */ + if(event==NETDEV_UP) + { + /* + * Join the initial group if multicast. + */ ip_mc_allhost(dev); } + if(event==NETDEV_DOWN) + ip_mc_drop_device(dev); + return ip_rt_event(event, dev); } diff -u --recursive --new-file v2.1.26/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c --- v2.1.26/linux/net/ipv4/ip_sockglue.c Sun Jan 26 02:07:50 1997 +++ linux/net/ipv4/ip_sockglue.c Tue Feb 25 17:12:51 1997 @@ -169,27 +169,22 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) { - int val,err; + int val=0,err; unsigned char ucval = 0; + int len; #if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT) struct ip_fw tmp_fw; #endif - if (optval == NULL) - { - val=0; - ucval=0; - } - else - { - err = get_user(val, (int *) optval); - if (!err) - err = get_user(ucval, (unsigned char *) optval); - if (err) - return err; - } + + if(get_user(len, optval)) + return -EFAULT; + if(len>=sizeof(int) && get_user(val, (int *) optval)) + return -EFAULT; + if(len>=sizeof(char) && get_user(ucval, (unsigned char *) optval)) + return -EFAULT; if(level!=SOL_IP) - return -EOPNOTSUPP; + return -ENOPROTOOPT; #ifdef CONFIG_IP_MROUTE if(optname>=MRT_BASE && optname <=MRT_BASE+10) { @@ -200,51 +195,61 @@ switch(optname) { case IP_OPTIONS: - { - struct ip_options * opt = NULL; - struct ip_options * old_opt; - if (optlen > 40 || optlen < 0) - return -EINVAL; - err = ip_options_get(&opt, optval, optlen, 1); - if (err) - return err; - /* - * ANK: I'm afraid that receive handler may change - * options from under us. - */ - cli(); - old_opt = sk->opt; - sk->opt = opt; - sti(); - if (old_opt) - kfree_s(old_opt, sizeof(struct optlen) + old_opt->optlen); - return 0; - } + { + struct ip_options * opt = NULL; + struct ip_options * old_opt; + if (optlen > 40 || optlen < 0) + return -EINVAL; + err = ip_options_get(&opt, optval, optlen, 1); + if (err) + return err; + /* + * ANK: I'm afraid that receive handler may change + * options from under us. + */ + cli(); + old_opt = sk->opt; + sk->opt = opt; + sti(); + if (old_opt) + kfree_s(old_opt, sizeof(struct optlen) + old_opt->optlen); + return 0; + } case IP_RXINFO: + if (optlen<4) + return -EINVAL; if (val) sk->ip_cmsg_flags |= 1; else sk->ip_cmsg_flags &= ~1; return 0; case IP_LOCALADDR: + if (optlen<4) + return -EINVAL; if (val) sk->ip_cmsg_flags |= 2; else sk->ip_cmsg_flags &= ~2; return 0; case IP_RECVOPTS: + if (optlen<4) + return -EINVAL; if (val) sk->ip_cmsg_flags |= 4; else sk->ip_cmsg_flags &= ~4; return 0; case IP_RETOPTS: + if (optlen<4) + return -EINVAL; if (val) sk->ip_cmsg_flags |= 8; else sk->ip_cmsg_flags &= ~8; return 0; case IP_RECVDSTADDR: + if (optlen<4) + return -EINVAL; if (val) sk->ip_cmsg_flags |= 0x10; else @@ -252,6 +257,8 @@ return 0; case IP_TOS: /* This sets both TOS and Precedence */ /* Reject setting of unused bits */ + if (optlen<4) + return -EINVAL; if (val & ~(IPTOS_TOS_MASK|IPTOS_PREC_MASK)) return -EINVAL; if (IPTOS_PREC(val) >= IPTOS_PREC_CRITIC_ECP && !suser()) @@ -260,21 +267,29 @@ sk->priority = rt_tos2priority(val); return 0; case IP_TTL: + if (optlen<4) + return -EINVAL; if(val<1||val>255) return -EINVAL; sk->ip_ttl=val; return 0; case IP_HDRINCL: + if (optlen<4) + return -EINVAL; if(sk->type!=SOCK_RAW) return -ENOPROTOOPT; sk->ip_hdrincl=val?1:0; return 0; case IP_PMTUDISC: + if (optlen<4) + return -EINVAL; if (val<0 || val>2) return -EINVAL; sk->ip_pmtudisc = val; return 0; case IP_RECVERR: + if (optlen<4) + return -EINVAL; if (sk->type==SOCK_STREAM) return -ENOPROTOOPT; lock_sock(sk); @@ -290,9 +305,13 @@ release_sock(sk); return 0; case IP_MULTICAST_TTL: + if (optlen<1) + return -EINVAL; sk->ip_mc_ttl=(int)ucval; return 0; case IP_MULTICAST_LOOP: + if (optlen<1) + return -EINVAL; if(ucval!=0 && ucval!=1) return -EINVAL; sk->ip_mc_loop=(int)ucval; @@ -306,8 +325,10 @@ * Check the arguments are allowable */ - err = copy_from_user(&addr,optval,sizeof(addr)); - if (err) + if(optlensizeof(tmp_fw) || optlen<1) return -EINVAL; - err = copy_from_user(&tmp_fw,optval,optlen); - if (err) - return -EFAULT; + if(copy_from_user(&tmp_fw,optval,optlen)) + return -EFAULT; err=ip_fw_ctl(optname, &tmp_fw,optlen); return -err; /* -0 is 0 after all */ @@ -527,11 +552,10 @@ case IP_ACCT_FLUSH: case IP_ACCT_ZERO: if(!suser()) - return -EPERM; + return -EACCES; if(optlen>sizeof(tmp_fw) || optlen<1) return -EINVAL; - err = copy_from_user(&tmp_fw, optval,optlen); - if (err) + if(copy_from_user(&tmp_fw, optval,optlen)) return -EFAULT; err=ip_acct_ctl(optname, &tmp_fw,optlen); return -err; /* -0 is 0 after all */ @@ -561,6 +585,9 @@ } #endif + if(get_user(len,optlen)) + return -EFAULT; + switch(optname) { case IP_OPTIONS: @@ -577,15 +604,13 @@ ip_options_undo(opt); - err = put_user(opt->optlen, optlen); - if (!err) - { - if(copy_to_user(optval, opt->__data, opt->optlen)) - err = -EFAULT; - } - return err; + len=min(len, opt->optlen); + if(put_user(len, optlen)) + return -EFAULT; + if(copy_to_user(optval, opt->__data, len)) + return -EFAULT; + return 0; } - return 0; case IP_RXINFO: val = (sk->ip_cmsg_flags & 1) != 0; return 0; @@ -625,33 +650,32 @@ case IP_MULTICAST_IFN: { struct ip_mreqn mreq; - len = sizeof(struct ip_mreqn); - err = put_user(len, optlen); + len = min(len,sizeof(struct ip_mreqn)); + if(put_user(len, optlen)) + return -EFAULT; mreq.imr_ifindex = sk->ip_mc_index; mreq.imr_address.s_addr = sk->ip_mc_addr; mreq.imr_multiaddr.s_addr = 0; - if (!err) { - err = copy_to_user((void *)optval, &mreq, len); - if (err) - err = -EFAULT; - } - return err; + if(copy_to_user((void *)optval, &mreq, len)) + return -EFAULT; + return 0; } case IP_MULTICAST_IF: { struct device *dev = dev_get_by_index(sk->ip_mc_index); - if (dev == NULL) { + if (dev == NULL) + { len = 0; return put_user(len, optlen); } dev_lock_list(); - len = strlen(dev->name); + len = min(len,strlen(dev->name)); err = put_user(len, optlen); if (!err) { err = copy_to_user((void *)optval,dev->name, len); - if (err) - err = -EFAULT; + if(err) + err=-EFAULT; } dev_unlock_list(); return err; @@ -659,10 +683,12 @@ default: return(-ENOPROTOOPT); } - err = put_user(sizeof(int), optlen); - if (err) - return err; - return put_user(val,(int *) optval); - - return(0); + + len=min(sizeof(int),len); + + if(put_user(len, optlen)) + return -EFAULT; + if(copy_to_user(optval,&val,len)) + return -EFAULT; + return 0; } diff -u --recursive --new-file v2.1.26/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c --- v2.1.26/linux/net/ipv4/ipmr.c Thu Dec 12 06:54:24 1996 +++ linux/net/ipv4/ipmr.c Fri Feb 21 14:58:38 1997 @@ -550,6 +550,8 @@ */ case MRT_ADD_MFC: case MRT_DEL_MFC: + if(optlen!=sizeof(mfc)) + return -EINVAL; err = copy_from_user(&mfc,optval, sizeof(mfc)); return err ? -EFAULT : ipmr_mfc_modify(optname, &mfc); /* @@ -558,9 +560,6 @@ case MRT_ASSERT: { int v; - if(optlen!=sizeof(int)) - return -EINVAL; - if(get_user(v,(int *)optval)) return -EFAULT; mroute_do_pim=(v)?1:0; @@ -571,7 +570,7 @@ * set. */ default: - return -EOPNOTSUPP; + return -ENOPROTOOPT; } } @@ -582,26 +581,26 @@ int ip_mroute_getsockopt(struct sock *sk,int optname,char *optval,int *optlen) { int olr; - int err; + int val; if(sk!=mroute_socket) return -EACCES; if(optname!=MRT_VERSION && optname!=MRT_ASSERT) - return -EOPNOTSUPP; + return -ENOPROTOOPT; - err = get_user(olr, optlen); - if (err) - return err; - if(olr!=sizeof(int)) - return -EINVAL; - err = put_user(sizeof(int),optlen); - if (err) - return err; + if(get_user(olr, optlen)) + return -EFAULT; + + olr=min(olr,sizeof(int)); + if(put_user(olr,optlen)) + return -EFAULT; if(optname==MRT_VERSION) - err = put_user(0x0305,(int *)optval); + val=0x0305; else - err = put_user(mroute_do_pim,(int *)optval); - return err; + val=mroute_do_pim; + if(copy_to_user(optval,&val,olr)) + return -EFAULT; + return 0; } /* diff -u --recursive --new-file v2.1.26/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.1.26/linux/net/ipv4/tcp.c Fri Feb 7 05:54:55 1997 +++ linux/net/ipv4/tcp.c Fri Feb 21 14:58:38 1997 @@ -1777,13 +1777,11 @@ int val; if (level != SOL_TCP) - { return tp->af_specific->setsockopt(sk, level, optname, optval, optlen); - } - - if (optval == NULL) - return(-EINVAL); + + if(optlentp_pinfo.af_tcp); - int val,err; + int val; + int len; if(level != SOL_TCP) { return tp->af_specific->getsockopt(sk, level, optname, optval, optlen); } + + if(get_user(len,optlen)) + return -EFAULT; + + len=min(len,sizeof(int)); switch(optname) { @@ -1832,11 +1836,11 @@ return(-ENOPROTOOPT); } - err = put_user(sizeof(int),(int *) optlen); - if (!err) - err = put_user(val,(int *)optval); - - return err; + if(put_user(len, optlen)) + return -EFAULT; + if(copy_to_user(optval, &val,len)) + return -EFAULT; + return 0; } void tcp_set_keepalive(struct sock *sk, int val) diff -u --recursive --new-file v2.1.26/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c --- v2.1.26/linux/net/ipv6/addrconf.c Sun Jan 19 05:47:28 1997 +++ linux/net/ipv6/addrconf.c Fri Feb 21 14:58:39 1997 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.1.26/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c --- v2.1.26/linux/net/ipv6/af_inet6.c Sun Feb 2 05:18:51 1997 +++ linux/net/ipv6/af_inet6.c Tue Feb 25 17:12:51 1997 @@ -751,7 +751,7 @@ inet6_getname, datagram_poll, /* ok */ inet6_ioctl, /* must change */ - inet_listen, /* ok */ + sock_no_listen, /* ok */ inet_shutdown, /* ok */ inet_setsockopt, /* ok */ inet_getsockopt, /* ok */ diff -u --recursive --new-file v2.1.26/linux/net/ipv6/datagram.c linux/net/ipv6/datagram.c --- v2.1.26/linux/net/ipv6/datagram.c Sun Jan 19 05:47:28 1997 +++ linux/net/ipv6/datagram.c Fri Feb 21 14:58:40 1997 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.1.26/linux/net/ipv6/ipv6_sockglue.c linux/net/ipv6/ipv6_sockglue.c --- v2.1.26/linux/net/ipv6/ipv6_sockglue.c Mon Jan 13 22:16:49 1997 +++ linux/net/ipv6/ipv6_sockglue.c Fri Feb 21 14:58:40 1997 @@ -13,6 +13,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. + * + * FIXME: Make the setsockopt code POSIX compliant: That is + * + * o Return -EINVAL for setsockopt of short lengths + * o Truncate getsockopt returns + * o Return an optlen of the truncated length if need be */ #include @@ -67,7 +73,7 @@ { struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6; int val, err; - int retv = -EOPNOTSUPP; + int retv = -ENOPROTOOPT; if(level!=SOL_IPV6) goto out; diff -u --recursive --new-file v2.1.26/linux/net/ipv6/mcast.c linux/net/ipv6/mcast.c --- v2.1.26/linux/net/ipv6/mcast.c Sun Nov 3 01:04:46 1996 +++ linux/net/ipv6/mcast.c Fri Feb 21 14:58:40 1997 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.1.26/linux/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c --- v2.1.26/linux/net/ipv6/ndisc.c Thu Jan 2 04:07:39 1997 +++ linux/net/ipv6/ndisc.c Fri Feb 21 14:58:40 1997 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -1847,6 +1848,9 @@ #else proc_net_register(&ndisc_proc_entry); #endif +#endif +#ifdef CONFIG_IPV6_MODULE + ndisc_eth_hook = ndisc_eth_resolv; #endif } diff -u --recursive --new-file v2.1.26/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c --- v2.1.26/linux/net/ipx/af_ipx.c Fri Feb 7 05:54:55 1997 +++ linux/net/ipx/af_ipx.c Tue Feb 25 17:12:51 1997 @@ -1721,7 +1721,7 @@ sk=sock->sk; - if (optval==NULL) + if (optlen!=sizeof(int)) return(-EINVAL); err = get_user(opt, (unsigned int *)optval); @@ -1737,12 +1737,12 @@ sk->protinfo.af_ipx.type=opt; return 0; default: - return -EOPNOTSUPP; + return -ENOPROTOOPT; } break; default: - return -EOPNOTSUPP; + return -ENOPROTOOPT; } } @@ -1751,7 +1751,7 @@ { struct sock *sk; int val=0; - int err; + int len; sk=sock->sk; @@ -1770,17 +1770,16 @@ break; default: - return -EOPNOTSUPP; + return -ENOPROTOOPT; } - err = put_user(sizeof(int), optlen); - if (!err) - err = put_user(val, (int *)optval); - return err; -} - -static int ipx_listen(struct socket *sock, int backlog) -{ - return -EOPNOTSUPP; + if(get_user(len,optlen)) + return -EFAULT; + len=min(len,sizeof(int)); + if(put_user(len, optlen)) + return -EFAULT; + if(copy_to_user(optval,&val,len)) + return -EFAULT; + return 0; } static int ipx_create(struct socket *sock, int protocol) @@ -2334,7 +2333,7 @@ ipx_getname, datagram_poll, ipx_ioctl, - ipx_listen, + sock_no_listen, ipx_shutdown, ipx_setsockopt, ipx_getsockopt, diff -u --recursive --new-file v2.1.26/linux/net/lapb/lapb_iface.c linux/net/lapb/lapb_iface.c --- v2.1.26/linux/net/lapb/lapb_iface.c Tue Feb 4 06:44:25 1997 +++ linux/net/lapb/lapb_iface.c Fri Feb 21 14:58:40 1997 @@ -14,9 +14,6 @@ * * History * LAPB 001 Jonathan Naylor Started Coding - * - * TODO - * Add FRMRs. */ #include diff -u --recursive --new-file v2.1.26/linux/net/lapb/lapb_in.c linux/net/lapb/lapb_in.c --- v2.1.26/linux/net/lapb/lapb_in.c Tue Feb 4 06:44:25 1997 +++ linux/net/lapb/lapb_in.c Fri Feb 21 14:58:40 1997 @@ -43,26 +43,26 @@ * State machine for state 0, Disconnected State. * The handling of the timer(s) is in file lapb_timer.c. */ -static void lapb_state0_machine(lapb_cb *lapb, struct sk_buff *skb, int frametype, int pf) +static void lapb_state0_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) { - switch (frametype) { + switch (frame->type) { case LAPB_SABM: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S0 RX SABM(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S0 RX SABM(%d)\n", lapb->token, frame->pf); #endif if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n", lapb->token, frame->pf); #endif - lapb_send_control(lapb, LAPB_DM, pf, LAPB_RESPONSE); + lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); } else { #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n", lapb->token, frame->pf); #endif #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n", lapb->token); #endif - lapb_send_control(lapb, LAPB_UA, pf, LAPB_RESPONSE); + lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb->state = LAPB_STATE_3; lapb->condition = 0x00; lapb->t1timer = 0; @@ -77,16 +77,16 @@ case LAPB_SABME: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S0 RX SABME(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S0 RX SABME(%d)\n", lapb->token, frame->pf); #endif if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n", lapb->token, frame->pf); #endif #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n", lapb->token); #endif - lapb_send_control(lapb, LAPB_UA, pf, LAPB_RESPONSE); + lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb->state = LAPB_STATE_3; lapb->condition = 0x00; lapb->t1timer = 0; @@ -98,18 +98,18 @@ lapb_connect_indication(lapb, LAPB_OK); } else { #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n", lapb->token, frame->pf); #endif - lapb_send_control(lapb, LAPB_DM, pf, LAPB_RESPONSE); + lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); } break; case LAPB_DISC: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S0 RX DISC(%d)\n", lapb->token, pf); - printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S0 RX DISC(%d)\n", lapb->token, frame->pf); + printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n", lapb->token, frame->pf); #endif - lapb_send_control(lapb, LAPB_UA, pf, LAPB_RESPONSE); + lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); break; default: @@ -123,56 +123,56 @@ * State machine for state 1, Awaiting Connection State. * The handling of the timer(s) is in file lapb_timer.c. */ -static void lapb_state1_machine(lapb_cb *lapb, struct sk_buff *skb, int frametype, int pf) +static void lapb_state1_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) { - switch (frametype) { + switch (frame->type) { case LAPB_SABM: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S1 RX SABM(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S1 RX SABM(%d)\n", lapb->token, frame->pf); #endif if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", lapb->token, frame->pf); #endif - lapb_send_control(lapb, LAPB_DM, pf, LAPB_RESPONSE); + lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); } else { #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n", lapb->token, frame->pf); #endif - lapb_send_control(lapb, LAPB_UA, pf, LAPB_RESPONSE); + lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); } break; case LAPB_SABME: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S1 RX SABME(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S1 RX SABME(%d)\n", lapb->token, frame->pf); #endif if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n", lapb->token, frame->pf); #endif - lapb_send_control(lapb, LAPB_UA, pf, LAPB_RESPONSE); + lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); } else { #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", lapb->token, frame->pf); #endif - lapb_send_control(lapb, LAPB_DM, pf, LAPB_RESPONSE); + lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); } break; case LAPB_DISC: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S1 RX DISC(%d)\n", lapb->token, pf); - printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S1 RX DISC(%d)\n", lapb->token, frame->pf); + printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", lapb->token, frame->pf); #endif - lapb_send_control(lapb, LAPB_DM, pf, LAPB_RESPONSE); + lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); break; case LAPB_UA: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S1 RX UA(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S1 RX UA(%d)\n", lapb->token, frame->pf); #endif - if (pf) { + if (frame->pf) { #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S1 -> S3\n", lapb->token); #endif @@ -190,9 +190,9 @@ case LAPB_DM: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S1 RX DM(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S1 RX DM(%d)\n", lapb->token, frame->pf); #endif - if (pf) { + if (frame->pf) { #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token); #endif @@ -215,31 +215,31 @@ * State machine for state 2, Awaiting Release State. * The handling of the timer(s) is in file lapb_timer.c */ -static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, int frametype, int pf) +static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) { - switch (frametype) { + switch (frame->type) { case LAPB_SABM: case LAPB_SABME: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S2 RX {SABM,SABME}(%d)\n", lapb->token, pf); - printk(KERN_DEBUG "lapb: (%p) S2 TX DM(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S2 RX {SABM,SABME}(%d)\n", lapb->token, frame->pf); + printk(KERN_DEBUG "lapb: (%p) S2 TX DM(%d)\n", lapb->token, frame->pf); #endif - lapb_send_control(lapb, LAPB_DM, pf, LAPB_RESPONSE); + lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); break; case LAPB_DISC: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S2 RX DISC(%d)\n", lapb->token, pf); - printk(KERN_DEBUG "lapb: (%p) S2 TX UA(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S2 RX DISC(%d)\n", lapb->token, frame->pf); + printk(KERN_DEBUG "lapb: (%p) S2 TX UA(%d)\n", lapb->token, frame->pf); #endif - lapb_send_control(lapb, LAPB_UA, pf, LAPB_RESPONSE); + lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); break; case LAPB_UA: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S2 RX UA(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S2 RX UA(%d)\n", lapb->token, frame->pf); #endif - if (pf) { + if (frame->pf) { #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token); #endif @@ -252,9 +252,9 @@ case LAPB_DM: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n", lapb->token, frame->pf); #endif - if (pf) { + if (frame->pf) { #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token); #endif @@ -270,10 +270,10 @@ case LAPB_RNR: case LAPB_RR: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S2 RX {I,REJ,RNR,RR}(%d)\n", lapb->token, pf); - printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S2 RX {I,REJ,RNR,RR}(%d)\n", lapb->token, frame->pf); + printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n", lapb->token, frame->pf); #endif - if (pf) lapb_send_control(lapb, LAPB_DM, pf, LAPB_RESPONSE); + if (frame->pf) lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); break; default: @@ -287,28 +287,28 @@ * State machine for state 3, Connected State. * The handling of the timer(s) is in file lapb_timer.c */ -static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type) +static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) { int queued = 0; int modulus; modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS; - switch (frametype) { + switch (frame->type) { case LAPB_SABM: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S3 RX SABM(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S3 RX SABM(%d)\n", lapb->token, frame->pf); #endif if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n", lapb->token, frame->pf); #endif - lapb_send_control(lapb, LAPB_DM, pf, LAPB_RESPONSE); + lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); } else { #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n", lapb->token, frame->pf); #endif - lapb_send_control(lapb, LAPB_UA, pf, LAPB_RESPONSE); + lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb->condition = 0x00; lapb->t1timer = 0; lapb->t2timer = 0; @@ -322,13 +322,13 @@ case LAPB_SABME: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S3 RX SABME(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S3 RX SABME(%d)\n", lapb->token, frame->pf); #endif if (lapb->mode & LAPB_EXTENDED) { #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n", lapb->token, frame->pf); #endif - lapb_send_control(lapb, LAPB_UA, pf, LAPB_RESPONSE); + lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb->condition = 0x00; lapb->t1timer = 0; lapb->t2timer = 0; @@ -339,21 +339,21 @@ lapb_requeue_frames(lapb); } else { #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n", lapb->token, frame->pf); #endif - lapb_send_control(lapb, LAPB_DM, pf, LAPB_RESPONSE); + lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); } break; case LAPB_DISC: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S3 RX DISC(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S3 RX DISC(%d)\n", lapb->token, frame->pf); #endif #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->token); #endif lapb_clear_queues(lapb); - lapb_send_control(lapb, LAPB_UA, pf, LAPB_RESPONSE); + lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb->state = LAPB_STATE_0; lapb->t1timer = lapb->t1; lapb->t2timer = 0; @@ -362,7 +362,7 @@ case LAPB_DM: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S3 RX DM(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S3 RX DM(%d)\n", lapb->token, frame->pf); #endif #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->token); @@ -376,80 +376,100 @@ case LAPB_RNR: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S3 RX RNR(%d) R%d\n", lapb->token, pf, nr); + printk(KERN_DEBUG "lapb: (%p) S3 RX RNR(%d) R%d\n", lapb->token, frame->pf, frame->nr); #endif lapb->condition |= LAPB_PEER_RX_BUSY_CONDITION; - lapb_check_need_response(lapb, type, pf); - if (lapb_validate_nr(lapb, nr)) { - lapb_check_iframes_acked(lapb, nr); - } else { + lapb_check_need_response(lapb, frame->cr, frame->pf); + if (lapb_validate_nr(lapb, frame->nr)) { + lapb_check_iframes_acked(lapb, frame->nr); + } else { + lapb->frmr_data = *frame; + lapb->frmr_type = LAPB_FRMR_Z; + lapb_transmit_frmr(lapb); #if LAPB_DEBUG > 0 - printk(KERN_DEBUG "lapb: (%p) S3 -> S1\n", lapb->token); + printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token); #endif - lapb_establish_data_link(lapb); - lapb->state = LAPB_STATE_1; + lapb->state = LAPB_STATE_4; + lapb->t1timer = lapb->t1; + lapb->t2timer = 0; + lapb->n2count = 0; } break; case LAPB_RR: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S3 RX RR(%d) R%d\n", lapb->token, pf, nr); + printk(KERN_DEBUG "lapb: (%p) S3 RX RR(%d) R%d\n", lapb->token, frame->pf, frame->nr); #endif lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION; - lapb_check_need_response(lapb, type, pf); - if (lapb_validate_nr(lapb, nr)) { - lapb_check_iframes_acked(lapb, nr); - } else { + lapb_check_need_response(lapb, frame->cr, frame->pf); + if (lapb_validate_nr(lapb, frame->nr)) { + lapb_check_iframes_acked(lapb, frame->nr); + } else { + lapb->frmr_data = *frame; + lapb->frmr_type = LAPB_FRMR_Z; + lapb_transmit_frmr(lapb); #if LAPB_DEBUG > 0 - printk(KERN_DEBUG "lapb: (%p) S3 -> S1\n", lapb->token); + printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token); #endif - lapb_establish_data_link(lapb); - lapb->state = LAPB_STATE_1; + lapb->state = LAPB_STATE_4; + lapb->t1timer = lapb->t1; + lapb->t2timer = 0; + lapb->n2count = 0; } break; case LAPB_REJ: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S3 RX REJ(%d) R%d\n", lapb->token, pf, nr); + printk(KERN_DEBUG "lapb: (%p) S3 RX REJ(%d) R%d\n", lapb->token, frame->pf, frame->nr); #endif lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION; - lapb_check_need_response(lapb, type, pf); - if (lapb_validate_nr(lapb, nr)) { - lapb_frames_acked(lapb, nr); + lapb_check_need_response(lapb, frame->cr, frame->pf); + if (lapb_validate_nr(lapb, frame->nr)) { + lapb_frames_acked(lapb, frame->nr); lapb->t1timer = 0; lapb->n2count = 0; lapb_requeue_frames(lapb); } else { + lapb->frmr_data = *frame; + lapb->frmr_type = LAPB_FRMR_Z; + lapb_transmit_frmr(lapb); #if LAPB_DEBUG > 0 - printk(KERN_DEBUG "lapb: (%p) S3 -> S1\n", lapb->token); + printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token); #endif - lapb_establish_data_link(lapb); - lapb->state = LAPB_STATE_1; + lapb->state = LAPB_STATE_4; + lapb->t1timer = lapb->t1; + lapb->t2timer = 0; + lapb->n2count = 0; } break; case LAPB_I: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S3 RX I(%d) S%d R%d\n", lapb->token, pf, ns, nr); + printk(KERN_DEBUG "lapb: (%p) S3 RX I(%d) S%d R%d\n", lapb->token, frame->pf, frame->ns, frame->nr); #endif - if (!lapb_validate_nr(lapb, nr)) { + if (!lapb_validate_nr(lapb, frame->nr)) { + lapb->frmr_data = *frame; + lapb->frmr_type = LAPB_FRMR_Z; + lapb_transmit_frmr(lapb); #if LAPB_DEBUG > 0 - printk(KERN_DEBUG "lapb: (%p) S3 -> S1\n", lapb->token); + printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token); #endif - lapb_establish_data_link(lapb); - lapb->state = LAPB_STATE_1; + lapb->state = LAPB_STATE_4; + lapb->t1timer = lapb->t1; + lapb->t2timer = 0; + lapb->n2count = 0; break; } if (lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) { - lapb_frames_acked(lapb, nr); + lapb_frames_acked(lapb, frame->nr); } else { - lapb_check_iframes_acked(lapb, nr); + lapb_check_iframes_acked(lapb, frame->nr); } - if (ns == lapb->vr) { + if (frame->ns == lapb->vr) { lapb->vr = (lapb->vr + 1) % modulus; queued = lapb_data_indication(lapb, skb); lapb->condition &= ~LAPB_REJECT_CONDITION; - if (pf) { + if (frame->pf) { lapb_enquiry_response(lapb); } else { if (!(lapb->condition & LAPB_ACK_PENDING_CONDITION)) { @@ -459,31 +479,47 @@ } } else { if (lapb->condition & LAPB_REJECT_CONDITION) { - if (pf) + if (frame->pf) lapb_enquiry_response(lapb); } else { #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S3 TX REJ(%d) R%d\n", lapb->token, pf, lapb->vr); + printk(KERN_DEBUG "lapb: (%p) S3 TX REJ(%d) R%d\n", lapb->token, frame->pf, lapb->vr); #endif lapb->condition |= LAPB_REJECT_CONDITION; - lapb_send_control(lapb, LAPB_REJ, pf, LAPB_RESPONSE); + lapb_send_control(lapb, LAPB_REJ, frame->pf, LAPB_RESPONSE); lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; } } break; case LAPB_FRMR: - case LAPB_ILLEGAL: #if LAPB_DEBUG > 1 - printk(KERN_DEBUG "lapb: (%p) S3 RX {FRMR,ILLEGAL}(%d)\n", lapb->token, pf); + printk(KERN_DEBUG "lapb: (%p) S3 RX FRMR(%d) %02X %02X %02X %02X %02X\n", lapb->token, frame->pf, skb->data[0], skb->data[1], skb->data[2], skb->data[3], skb->data[4]); #endif + lapb_establish_data_link(lapb); #if LAPB_DEBUG > 0 printk(KERN_DEBUG "lapb: (%p) S3 -> S1\n", lapb->token); #endif - lapb_establish_data_link(lapb); + lapb_requeue_frames(lapb); lapb->state = LAPB_STATE_1; break; + case LAPB_ILLEGAL: +#if LAPB_DEBUG > 1 + printk(KERN_DEBUG "lapb: (%p) S3 RX ILLEGAL(%d)\n", lapb->token, frame->pf); +#endif + lapb->frmr_data = *frame; + lapb->frmr_type = LAPB_FRMR_W; + lapb_transmit_frmr(lapb); +#if LAPB_DEBUG > 0 + printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token); +#endif + lapb->state = LAPB_STATE_4; + lapb->t1timer = lapb->t1; + lapb->t2timer = 0; + lapb->n2count = 0; + break; + default: break; } @@ -493,32 +529,103 @@ } /* + * State machine for state 4, Frame Reject State. + * The handling of the timer(s) is in file lapb_timer.c. + */ +static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) +{ + switch (frame->type) { + case LAPB_SABM: +#if LAPB_DEBUG > 1 + printk(KERN_DEBUG "lapb: (%p) S4 RX SABM(%d)\n", lapb->token, frame->pf); +#endif + if (lapb->mode & LAPB_EXTENDED) { +#if LAPB_DEBUG > 1 + printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n", lapb->token, frame->pf); +#endif + lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); + } else { +#if LAPB_DEBUG > 1 + printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n", lapb->token, frame->pf); +#endif +#if LAPB_DEBUG > 0 + printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n", lapb->token); +#endif + lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); + lapb->state = LAPB_STATE_3; + lapb->condition = 0x00; + lapb->t1timer = 0; + lapb->t2timer = 0; + lapb->n2count = 0; + lapb->vs = 0; + lapb->vr = 0; + lapb->va = 0; + lapb_connect_indication(lapb, LAPB_OK); + } + break; + + case LAPB_SABME: +#if LAPB_DEBUG > 1 + printk(KERN_DEBUG "lapb: (%p) S4 RX SABME(%d)\n", lapb->token, frame->pf); +#endif + if (lapb->mode & LAPB_EXTENDED) { +#if LAPB_DEBUG > 1 + printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n", lapb->token, frame->pf); +#endif +#if LAPB_DEBUG > 0 + printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n", lapb->token); +#endif + lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); + lapb->state = LAPB_STATE_3; + lapb->condition = 0x00; + lapb->t1timer = 0; + lapb->t2timer = 0; + lapb->n2count = 0; + lapb->vs = 0; + lapb->vr = 0; + lapb->va = 0; + lapb_connect_indication(lapb, LAPB_OK); + } else { +#if LAPB_DEBUG > 1 + printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n", lapb->token, frame->pf); +#endif + lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); + } + break; + + default: + break; + } + + kfree_skb(skb, FREE_READ); +} + +/* * Process an incoming LAPB frame */ void lapb_data_input(lapb_cb *lapb, struct sk_buff *skb) { - int frametype, ns, nr, pf, type; - - del_timer(&lapb->timer); + struct lapb_frame frame; - frametype = lapb_decode(lapb, skb, &ns, &nr, &pf, &type); + lapb_decode(lapb, skb, &frame); switch (lapb->state) { case LAPB_STATE_0: - lapb_state0_machine(lapb, skb, frametype, pf); + lapb_state0_machine(lapb, skb, &frame); break; case LAPB_STATE_1: - lapb_state1_machine(lapb, skb, frametype, pf); + lapb_state1_machine(lapb, skb, &frame); break; case LAPB_STATE_2: - lapb_state2_machine(lapb, skb, frametype, pf); + lapb_state2_machine(lapb, skb, &frame); break; case LAPB_STATE_3: - lapb_state3_machine(lapb, skb, frametype, ns, nr, pf, type); + lapb_state3_machine(lapb, skb, &frame); + break; + case LAPB_STATE_4: + lapb_state4_machine(lapb, skb, &frame); break; } - - lapb_set_timer(lapb); } #endif diff -u --recursive --new-file v2.1.26/linux/net/lapb/lapb_subr.c linux/net/lapb/lapb_subr.c --- v2.1.26/linux/net/lapb/lapb_subr.c Tue Feb 4 06:44:26 1997 +++ linux/net/lapb/lapb_subr.c Fri Feb 21 14:58:40 1997 @@ -122,11 +122,9 @@ * This routine is the centralised routine for parsing the control * information for the different frame formats. */ -int lapb_decode(lapb_cb *lapb, struct sk_buff *skb, int *ns, int *nr, int *pf, int *type) +void lapb_decode(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) { - int frametype = LAPB_ILLEGAL; - - *ns = *nr = *pf = *type = 0; + frame->type = LAPB_ILLEGAL; #if LAPB_DEBUG > 2 printk(KERN_DEBUG "lapb: (%p) S%d RX %02X %02X %02X\n", lapb->token, lapb->state, skb->data[0], skb->data[1], skb->data[2]); @@ -135,26 +133,26 @@ if (lapb->mode & LAPB_MLP) { if (lapb->mode & LAPB_DCE) { if (skb->data[0] == LAPB_ADDR_D) - *type = LAPB_COMMAND; + frame->cr = LAPB_COMMAND; if (skb->data[0] == LAPB_ADDR_C) - *type = LAPB_RESPONSE; + frame->cr = LAPB_RESPONSE; } else { if (skb->data[0] == LAPB_ADDR_C) - *type = LAPB_COMMAND; + frame->cr = LAPB_COMMAND; if (skb->data[0] == LAPB_ADDR_D) - *type = LAPB_RESPONSE; + frame->cr = LAPB_RESPONSE; } } else { if (lapb->mode & LAPB_DCE) { if (skb->data[0] == LAPB_ADDR_B) - *type = LAPB_COMMAND; + frame->cr = LAPB_COMMAND; if (skb->data[0] == LAPB_ADDR_A) - *type = LAPB_RESPONSE; + frame->cr = LAPB_RESPONSE; } else { if (skb->data[0] == LAPB_ADDR_A) - *type = LAPB_COMMAND; + frame->cr = LAPB_COMMAND; if (skb->data[0] == LAPB_ADDR_B) - *type = LAPB_RESPONSE; + frame->cr = LAPB_RESPONSE; } } @@ -162,46 +160,53 @@ if (lapb->mode & LAPB_EXTENDED) { if ((skb->data[0] & LAPB_S) == 0) { - frametype = LAPB_I; /* I frame - carries NR/NS/PF */ - *ns = (skb->data[0] >> 1) & 0x7F; - *nr = (skb->data[1] >> 1) & 0x7F; - *pf = skb->data[1] & LAPB_EPF; + frame->type = LAPB_I; /* I frame - carries NR/NS/PF */ + frame->ns = (skb->data[0] >> 1) & 0x7F; + frame->nr = (skb->data[1] >> 1) & 0x7F; + frame->pf = skb->data[1] & LAPB_EPF; + frame->control[0] = skb->data[0]; + frame->control[1] = skb->data[1]; skb_pull(skb, 2); } else if ((skb->data[0] & LAPB_U) == 1) { /* S frame - take out PF/NR */ - frametype = skb->data[0] & 0x0F; - *nr = (skb->data[1] >> 1) & 0x7F; - *pf = skb->data[1] & LAPB_EPF; + frame->type = skb->data[0] & 0x0F; + frame->nr = (skb->data[1] >> 1) & 0x7F; + frame->pf = skb->data[1] & LAPB_EPF; + frame->control[0] = skb->data[0]; + frame->control[1] = skb->data[1]; skb_pull(skb, 2); } else if ((skb->data[0] & LAPB_U) == 3) { /* U frame - take out PF */ - frametype = skb->data[0] & ~LAPB_SPF; - *pf = skb->data[0] & LAPB_SPF; + frame->type = skb->data[0] & ~LAPB_SPF; + frame->pf = skb->data[0] & LAPB_SPF; + frame->control[0] = skb->data[0]; + frame->control[1] = 0x00; skb_pull(skb, 1); } } else { if ((skb->data[0] & LAPB_S) == 0) { - frametype = LAPB_I; /* I frame - carries NR/NS/PF */ - *ns = (skb->data[0] >> 1) & 0x07; - *nr = (skb->data[0] >> 5) & 0x07; - *pf = skb->data[0] & LAPB_SPF; + frame->type = LAPB_I; /* I frame - carries NR/NS/PF */ + frame->ns = (skb->data[0] >> 1) & 0x07; + frame->nr = (skb->data[0] >> 5) & 0x07; + frame->pf = skb->data[0] & LAPB_SPF; } else if ((skb->data[0] & LAPB_U) == 1) { /* S frame - take out PF/NR */ - frametype = skb->data[0] & 0x0F; - *nr = (skb->data[0] >> 5) & 0x07; - *pf = skb->data[0] & LAPB_SPF; + frame->type = skb->data[0] & 0x0F; + frame->nr = (skb->data[0] >> 5) & 0x07; + frame->pf = skb->data[0] & LAPB_SPF; } else if ((skb->data[0] & LAPB_U) == 3) { /* U frame - take out PF */ - frametype = skb->data[0] & ~LAPB_SPF; - *pf = skb->data[0] & LAPB_SPF; + frame->type = skb->data[0] & ~LAPB_SPF; + frame->pf = skb->data[0] & LAPB_SPF; } + frame->control[0] = skb->data[0]; + skb_pull(skb, 1); } - - return frametype; } /* * This routine is called when the HDLC layer internally generates a * command or response for the remote machine ( eg. RR, UA etc. ). - * Only supervisory or unnumbered frames are processed. + * Only supervisory or unnumbered frames are processed, FRMRs are handled + * by lapb_transmit_frmr below. */ void lapb_send_control(lapb_cb *lapb, int frametype, int poll_bit, int type) { @@ -213,27 +218,74 @@ skb_reserve(skb, LAPB_HEADER_LEN + 1); - /* Assume a response - address structure for DTE */ if (lapb->mode & LAPB_EXTENDED) { if ((frametype & LAPB_U) == LAPB_U) { - dptr = skb_put(skb, 1); - *dptr = frametype; + dptr = skb_put(skb, 1); + *dptr = frametype; *dptr |= (poll_bit) ? LAPB_SPF : 0; } else { - dptr = skb_put(skb, 2); - dptr[0] = frametype; - dptr[1] = (lapb->vr << 1); + dptr = skb_put(skb, 2); + dptr[0] = frametype; + dptr[1] = (lapb->vr << 1); dptr[1] |= (poll_bit) ? LAPB_EPF : 0; } } else { - dptr = skb_put(skb, 1); - *dptr = frametype; + dptr = skb_put(skb, 1); + *dptr = frametype; *dptr |= (poll_bit) ? LAPB_SPF : 0; if ((frametype & LAPB_U) == LAPB_S) /* S frames carry NR */ *dptr |= (lapb->vr << 5); } lapb_transmit_buffer(lapb, skb, type); +} + +/* + * This routine generates FRMRs based on information previously stored in + * the LAPB control block. + */ +void lapb_transmit_frmr(lapb_cb *lapb) +{ + struct sk_buff *skb; + unsigned char *dptr; + + if ((skb = alloc_skb(LAPB_HEADER_LEN + 7, GFP_ATOMIC)) == NULL) + return; + + skb_reserve(skb, LAPB_HEADER_LEN + 1); + + if (lapb->mode & LAPB_EXTENDED) { + dptr = skb_put(skb, 6); + *dptr++ = LAPB_FRMR; + *dptr++ = lapb->frmr_data.control[0]; + *dptr++ = lapb->frmr_data.control[1]; + *dptr++ = (lapb->vs << 1) & 0xFE; + *dptr = (lapb->vr << 1) & 0xFE; + if (lapb->frmr_data.cr == LAPB_RESPONSE) + *dptr |= 0x01; + dptr++; + *dptr++ = lapb->frmr_type; + +#if LAPB_DEBUG > 1 + printk(KERN_DEBUG "lapb: (%p) S%d TX FRMR %02X %02X %02X %02X %02X\n", lapb->token, lapb->state, skb->data[1], skb->data[2], skb->data[3], skb->data[4], skb->data[5]); +#endif + } else { + dptr = skb_put(skb, 4); + *dptr++ = LAPB_FRMR; + *dptr++ = lapb->frmr_data.control[0]; + *dptr = (lapb->vs << 1) & 0x0E; + *dptr |= (lapb->vr << 5) & 0xE0; + if (lapb->frmr_data.cr == LAPB_RESPONSE) + *dptr |= 0x10; + dptr++; + *dptr++ = lapb->frmr_type; + +#if LAPB_DEBUG > 1 + printk(KERN_DEBUG "lapb: (%p) S%d TX FRMR %02X %02X %02X\n", lapb->token, lapb->state, skb->data[1], skb->data[2], skb->data[3]); +#endif + } + + lapb_transmit_buffer(lapb, skb, LAPB_RESPONSE); } #endif diff -u --recursive --new-file v2.1.26/linux/net/lapb/lapb_timer.c linux/net/lapb/lapb_timer.c --- v2.1.26/linux/net/lapb/lapb_timer.c Tue Feb 4 06:44:26 1997 +++ linux/net/lapb/lapb_timer.c Fri Feb 21 14:58:40 1997 @@ -180,6 +180,24 @@ lapb_requeue_frames(lapb); } break; + + /* + * Frame reject state, restransmit FRMR frames, up to N2 times. + */ + case LAPB_STATE_4: + if (lapb->n2count == lapb->n2) { + lapb_clear_queues(lapb); + lapb->state = LAPB_STATE_0; + lapb->t2timer = 0; + lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); +#if LAPB_DEBUG > 0 + printk(KERN_DEBUG "lapb: (%p) S4 -> S0\n", lapb->token); +#endif + } else { + lapb->n2count++; + lapb_transmit_frmr(lapb); + } + break; } lapb->t1timer = lapb->t1; diff -u --recursive --new-file v2.1.26/linux/net/netbeui/af_netbeui.c linux/net/netbeui/af_netbeui.c --- v2.1.26/linux/net/netbeui/af_netbeui.c Wed Dec 31 16:00:00 1969 +++ linux/net/netbeui/af_netbeui.c Tue Feb 25 17:12:51 1997 @@ -0,0 +1,658 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For TIOCOUTQ/INQ */ +#include +#include +#include +#include +#include +#include +#include +#include + + +#undef NETBEUI_DEBUG + + +#ifdef NETBEUI_DEBUG +#define DPRINT(x) print(x) +#else +#define DPRINT(x) +#endif + +#define min(a,b) (((a)<(b))?(a):(b)) + +/***********************************************************************************************************************\ +* * +* Handlers for the socket list. * +* * +\***********************************************************************************************************************/ + +static netbeui_socket *netbeui_socket_list=NULL; + +/* + * Note: Sockets may not be removed _during_ an interrupt or inet_bh + * handler using this technique. They can be added although we do not + * use this facility. + */ + +extern inline void netbeui_remove_socket(netbeui_socket *sk) +{ + sklist_remove_socket(&netbeui_socket_list,sk); +} + +extenr inline void netbeui_insert_socket(netbeui_socket *sk) +{ + sklist_insert_socket(&netbeui_socket_list,sk); + netbeui_socket_list=sk; + restore_flags(flags); +} + +static void netbeui_destroy_socket(netbeui_socket *sk) +{ + /* + * Release netbios logical channels first + */ + if(sk->af_nb.nb_link) + { + netbeui_delete_channel(sk->af_nb.nb_link); + sk->af_nb.nb_link=NULL; + } + if(sk->af_nb.src_name) + { + netbeui_release_name(sk->af_nb.src_name); + sk->af_nb.src_name=NULL; + } + if(sk->af_nb.dst_name) + { + netbeui_release_name(sk->af_nb.dst_name); + sk->af_nb.dst_name=NULL; + } + netbeui_remove_listener(sk); + sklist_destroy_socket(&netbeui_socket,sk); +} + +/* + * Called from proc fs + */ + +int netbeui_get_info(char *buffer, char **start, off_t offset, int length, int dummy) +{ + return 0; +} + +/* + * A device event has occurred. Watch for devices going down and + * delete our use of them (iface and route). + */ + +static int nb_device_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + if(event==NETDEV_DOWN) + { + /* Discard any use of this */ + netbeui_drop_device((struct device *)ptr); + } + return NOTIFY_DONE; +} + +/*******************************************************************************************************************\ +* * +* Handling for system calls applied via the various interfaces to a netbeui socket object * +* * +\*******************************************************************************************************************/ + +static int netbeui_listen(struct socket *sock, int backlog) +{ + struct sock *sk=(netbeui_socket *)sock->data; + if(sk->state!=TCP_CLOSED) + return -EINVAL; + if(backlog<0) + return -EINVAL; + if(backlog<128) + sk->backlog=backlog; + else + sk->backlog=128; + sk->state=TCP_LISTEN; + sk->state_change(sk); + netbeui_add_listener(sk); + return 0; +} + +/* + * Create a socket. Initialise the socket, blank the addresses + * set the state. + */ + +static int netbeui_create(struct socket *sock, int protocol) +{ + netbeui_socket *sk; + sk=(netbeui_socket *)sk_alloc(GFP_KERNEL); + if(sk==NULL) + return(-ENOBUFS); + switch(sock->type) + { + case SOCK_DGRAM: + break; + case SOCK_SEQPACKET: + break; + default: + sk_free((void *)sk); + return(-ESOCKTNOSUPPORT); + } + + MOD_INC_USE_COUNT; + + sock_init_data(sock,sk); + sk->mtu=1500; + return(0); +} + +/* + * Copy a socket. No work needed. + */ + +static int netbeui_dup(struct socket *newsock,struct socket *oldsock) +{ + return(netbeui_create(newsock,oldsock->type)); +} + +/* + * Free a socket. No work needed + */ + +static int netbeui_release(struct socket *sock, struct socket *peer) +{ + netbeui_socket *sk=(netbeui_socket *)sock->data; + if(sk==NULL) + return(0); + if(!sk->dead) + sk->state_change(sk); + sk->dead=1; + sock->data=NULL; + netbeui_destroy_socket(sk); + return(0); +} + +/* + * Set the address 'our end' of the connection. + */ + +static int netbeui_bind(struct socket *sock, struct sockaddr *uaddr,size_t addr_len) +{ + netbeui_socket *sk; + struct sockaddr_netbeui *addr=(struct sockaddr_netbeui *)uaddr; + int err; + + sk=(netbeui_socket *)sock->data; + + if(sk->zapped==0) + return(-EINVAL); + + if(addr_len!=sizeof(struct sockaddr_netbeui)) + return -EINVAL; + + if(addr->snb_family!=AF_NETBEUI) + return -EAFNOSUPPORT; + + /* + * This will sleep. To meet POSIX it is non interruptible. + * Someone should give the 1003.1g authors an injection of + * imagination... + */ + + if(sk->af_nb.src_name!=NULL) + return -EINVAL; + + /* + * Try and get the name. It may return various 'invalid' name + * problem reports or EADDRINUSE if we or another node holds + * the desired name. + */ + + sk->af_nb.src_name=netbeui_alloc_name(addr, &err); + if(sk->af_nb.src_name==NULL) + return err; + /* + * Add us to the active socket list + */ + netbeui_insert_socket(sk); + sk->zapped=0; + return(0); +} + +/* + * Set the address we talk to. + */ + +static int netbeui_connect(struct socket *sock, struct sockaddr *uaddr, + size_t addr_len, int flags) +{ + netbeui_socket *sk=(netbeui_socket *)sock->data; + struct sockaddr_netbeui *addr=(struct sockaddr_netbeui *)uaddr; + + /* + * Check pending operations + */ + + if(sk->state==TCP_ESTABLISHED && sock->state == SS_CONNECTING) + { + sock->state==SS_CONNECTED; + return 0; + } + + if(sk->state == TCP_CLOSE & sock->state == SS_CONNECTING) + { + sock->state==SS_UNCONNECTED; + return -ECONNREFUSED; + } + + if(sock->state == SS_CONNECTING && (flags & O_NONBLOCK)) + return -EINPROGRESS; + + if(sk->state==TCP_ESTABLISHED) + return -EISCONN; + + /* + * If this is new it must really be new... + */ + + if(sk->af_nb.dst_name==NULL) + { + if(addr_len != sizeof(struct sockaddr_nb)) + return -EINVAL; + if(addr->snb_family!=AF_NETBEUI) + return -EAFNOSUPPORT; + /* + * Try and find the name + */ + } +} + +/* + * Not relevant + */ + +static int netbeui_socketpair(struct socket *sock1, struct socket *sock2) +{ + return(-EOPNOTSUPP); +} + +/* + * WRITE ME + */ + +static int netbeui_accept(struct socket *sock, struct socket *newsock, int flags) +{ + if(newsock->data) + sk_free(newsock->data); + return -EOPNOTSUPP; +} + +/* + * Find the name of a netbeui socket. Just copy the right + * fields into the sockaddr. + */ + +static int netbeui_getname(struct socket *sock, struct sockaddr *uaddr, + size_t *uaddr_len, int peer) +{ + struct sockaddr_netbeui snb; + netbeui_socket *sk; + + sk=(netbeui_socket *)sock->data; + if(sk->zapped) + { + return -EINVAL; + } + + *uaddr_len = sizeof(struct sockaddr_netbeui); + + if(peer) + { + if(sk->state!=TCP_ESTABLISHED) + return -ENOTCONN; + } + else + { + } + snb.snb_family = AF_NETBEUI; + memcpy(uaddr,&snb,sizeof(snb)); + return(0); +} + +/* + * Receive a packet (in skb) from device dev. + */ + +static int netbeui_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) +{ + return nb_llc_rcv(skb); +} + +static int netbeui_sendmsg(struct socket *sock, struct msghdr *msg, int len, int nonblock, int flags) +{ + netbeui_socket *sk=(netbeui_socket *)sock->data; + struct sockaddr_nb *usnb=(struct sockaddr_nb *)msg->msg_name; + struct sk_buff *skb; + struct device *dev; + struct nbhdr *nbp; + int size; + struct netbeui_route *rt; + int loopback=0; + int err; + + if(flags) + return -EINVAL; + + if(len>1500) /* - headers!! */ + return -EMSGSIZE; + + if(usnb) + { + if(sk->zapped) + { + if(netbeui_autobind(sk)<0) + return -EBUSY; + } + + if(msg->msg_namelen snb_family != AF_NETBEUI) + return -EINVAL; + /* Check broadcast */ + } + else + { + if(sk->state!=TCP_ESTABLISHED) + return -ENOTCONN; + /* Connected .. */ + } + + /* Build a packet */ + SOCK_DEBUG(sk, "SK %p: Got address.\n",sk); + size=sizeof(struct nbhdr)+len+nb_dl->header_length; /* For headers */ + + SOCK_DEBUG(sk, "SK %p: Size needed %d, device %s\n", sk, size, dev->name); + size += dev->hard_header_len; + skb = sock_alloc_send_skb(sk, size, 0, 0 , &err); + if(skb==NULL) + return err; + + skb->sk=sk; + skb->free=1; + skb->arp=1; + skb_reserve(skb,nb_dl->header_length); + skb_reserve(skb,dev->hard_header_len); + skb->dev=dev; + SOCK_DEBUG(sk, "SK %p: Begin build.\n", sk); + nbp=(struct nbhdr *)skb_put(skb,sizeof(struct nbhdr)); + SOCK_DEBUG(sk, "SK %p: Copy user data (%d bytes).\n", sk, len); + err = memcpy_fromiovec(skb_put(skb,len),msg->msg_iov,len); + if (err) + { + kfree_skb(skb, FREE_WRITE); + return -EFAULT; + } + +#ifdef CONFIG_FIREWALL + + if(call_out_firewall(AF_NETBEUI, skb->dev, nbp, NULL)!=FW_ACCEPT) + { + kfree_skb(skb, FREE_WRITE); + return -EPERM; + } + +#endif + + if(nb_send_low(dev,skb,&usat->sat_addr, NULL)==-1) + kfree_skb(skb, FREE_WRITE); + SOCK_DEBUG(sk, "SK %p: Done write (%d).\n", sk, len); + return len; +} + + +static int netbeui_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len) +{ + netbeui_socket *sk=(netbeui_socket *)sock->data; + struct sockaddr_nb *snb=(struct sockaddr_nb *)msg->msg_name; + struct nbphdr *nbp = NULL; + int copied = 0; + struct sk_buff *skb; + int er = 0; + + if(addr_len) + *addr_len=sizeof(*snb); + + skb=skb_recv_datagram(sk,flags,noblock,&er); + if(skb==NULL) + return er; + + snb = (struct nbphdr *)(skb->h.raw); + if(sk->type==SOCK_RAW) + { + copied=skb->len + if(copied > size) + { + copied=size; + msg->msg_flags|=MSG_TRUNC; + } + er = skb_copy_datagram_iovec(skb,0,msg->msg_iov,copied); + if (er) + goto out; + } + else + { + copied=skb->len - sizeof(*nbp); + if (copied > size) + { + copied = size; + msg->msg_flags|=MSG_TRUNC; + } + er = skb_copy_datagram_iovec(skb,sizeof(*nbp),msg->msg_iov,copied); + if (er) + goto out; + } + if(snb) + { + sat->sat_family=AF_NETBEUI; + /* Copy name over */ + } +out: + skb_free_datagram(sk, skb); + return er ? er : (copied); +} + + +static int netbeui_shutdown(struct socket *sk,int how) +{ + return -EOPNOTSUPP; +} + +static int netbeui_poll(struct socket *sock, poll_table *wait) +{ + netbeui_socket *sk=(netbeui_socket *)sock->data; + + return datagram_poll(sk,wait); +} + +/* + * Netbeui ioctl calls. + */ + +static int netbeui_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) +{ + long amount=0; + netbeui_socket *sk=(netbeui_socket *)sock->data; + + switch(cmd) + { + /* + * Protocol layer + */ + case TIOCOUTQ: + amount=sk->sndbuf-sk->wmem_alloc; + if(amount<0) + amount=0; + break; + case TIOCINQ: + { + struct sk_buff *skb; + /* These two are safe on a single CPU system as only user tasks fiddle here */ + if((skb=skb_peek(&sk->receive_queue))!=NULL) + amount=skb->len-sizeof(struct ddpehdr); + break; + } + case SIOCGSTAMP: + if (sk) + { + if(sk->stamp.tv_sec==0) + return -ENOENT; + return copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval)) ? -EFAULT : 0; + } + return -EINVAL; + /* + * Routing + */ + case SIOCADDRT: + case SIOCDELRT: + if(!suser()) + return -EPERM; + return(nbrtr_ioctl(cmd,(void *)arg)); + /* + * Interface + */ + case SIOCGIFADDR: + case SIOCSIFADDR: + case SIOCGIFBRDADDR: + return nbif_ioctl(cmd,(void *)arg); + /* + * Physical layer ioctl calls + */ + case SIOCSIFLINK: + case SIOCGIFHWADDR: + case SIOCSIFHWADDR: + case SIOCGIFFLAGS: + case SIOCSIFFLAGS: + case SIOCGIFMTU: + case SIOCGIFCONF: + case SIOCADDMULTI: + case SIOCDELMULTI: + + return(dev_ioctl(cmd,(void *) arg)); + + case SIOCSIFMETRIC: + case SIOCSIFBRDADDR: + case SIOCGIFNETMASK: + case SIOCSIFNETMASK: + case SIOCGIFMEM: + case SIOCSIFMEM: + case SIOCGIFDSTADDR: + case SIOCSIFDSTADDR: + return -EINVAL; + + default: + return -EINVAL; + } + return put_user(amount, (int *)arg); +} + +static struct proto_ops netbeui_proto_ops = { + AF_NETBEUI, + + netbeui_create, + netbeui_dup, + netbeui_release, + netbeui_bind, + netbeui_connect, + netbeui_socketpair, + netbeui_accept, + netbeui_getname, + netbeui_poll, + netbeui_ioctl, + netbeui_listen, + netbeui_shutdown, + sock_no_setsockopt, + sock_no_getsockopt, + sock_no_fcntl, + netbeui_sendmsg, + netbeui_recvmsg +}; + +static struct notifier_block nb_notifier={ + nb_device_event, + NULL, + 0 +}; + +static char nb_snap_id[]={0x08,0x00,0x07,0x80,0x9B}; + +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry proc_netbeui = { + PROC_NET_NETBEUI, 9, "netbeui", + S_IFREG | S_IRUGO, 1, 0, 0 + 0, &proc_net_inode_operations, + netbeui_get_info +}; +#endif + +/* Called by proto.c on kernel start up */ + +void netbeui_proto_init(struct net_proto *pro) +{ + (void) sock_register(netbeui_proto_ops.family, &netbeui_proto_ops); + if ((nb_dl = register_8022_client(nb_8022_id, netbeui_rcv)) == NULL) + printk(KERN_CRIT "Unable to register Netbeui with 802.2.\n"); + + register_netdevice_notifier(&nb_notifier); + +#ifdef CONFIG_PROC_FS + proc_net_register(&proc_netbeui); +#endif + + printk(KERN_INFO "NetBEUI 0.03 for Linux NET3.037\n"); +} + +#ifdef MODULE +EXPORT_NO_SYMBOLS; + +int init_module(void) +{ + netbeui_proto_init(NULL); + return 0; +} + +void cleanup_module(void) +{ + unsigned long flags; +#ifdef CONFIG_PROC_FS + proc_net_unregister(PROC_NET_NETBEUI); +#endif + unregister_netdevice_notifier(&nb_notifier); + unregister_snap_client(nb_snap_id); + sock_unregister(netbeui_proto_ops.family); +} + +#endif /* MODULE */ diff -u --recursive --new-file v2.1.26/linux/net/netbeui/netbeui.c linux/net/netbeui/netbeui.c --- v2.1.26/linux/net/netbeui/netbeui.c Mon Jan 27 01:04:48 1997 +++ linux/net/netbeui/netbeui.c Wed Dec 31 16:00:00 1969 @@ -1,861 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* For TIOCOUTQ/INQ */ -#include -#include -#include -#include -#include -#include -#include -#include - - -#undef NETBEUI_DEBUG - - -#ifdef NETBEUI_DEBUG -#define DPRINT(x) print(x) -#else -#define DPRINT(x) -#endif - -#define min(a,b) (((a)<(b))?(a):(b)) - -/***********************************************************************************************************************\ -* * -* Handlers for the socket list. * -* * -\***********************************************************************************************************************/ - -static netbeui_socket *netbeui_socket_list=NULL; - -/* - * Note: Sockets may not be removed _during_ an interrupt or inet_bh - * handler using this technique. They can be added although we do not - * use this facility. - */ - -extern inline void netbeui_remove_socket(netbeui_socket *sk) -{ - sklist_remove_socket(&netbeui_socket_list,sk); -} - -extenr inline void netbeui_insert_socket(netbeui_socket *sk) -{ - sklist_insert_socket(&netbeui_socket_list,sk); - netbeui_socket_list=sk; - restore_flags(flags); -} - -static void netbeui_destroy_socket(netbeui_socket *sk) -{ - /* - * Release netbios logical channels first - */ - if(sk->af_nb.nb_link) - { - netbeui_delete_channel(sk->af_nb.nb_link); - sk->af_nb.nb_link=NULL; - } - if(sk->af_nb.src_name) - { - netbeui_release_name(sk->af_nb.src_name); - sk->af_nb.src_name=NULL; - } - if(sk->af_nb.dst_name) - { - netbeui_release_name(sk->af_nb.dst_name); - sk->af_nb.dst_name=NULL; - } - netbeui_remove_listener(sk); - sklist_destroy_socket(&netbeui_socket,sk); -} - -/* - * Called from proc fs - */ - -int netbeui_get_info(char *buffer, char **start, off_t offset, int length, int dummy) -{ - netbeui_socket *s; - int len=0; - off_t pos=0; - off_t begin=0; - - /* - * Output the netbeui data for the /proc virtual fs. - */ - - len += sprintf (buffer,"Type local_addr remote_addr tx_queue rx_queue st uid\n"); - for (s = netbeui_socket_list; s != NULL; s = s->next) - { - len += sprintf (buffer+len,"%02X ", s->type); - len += sprintf (buffer+len,"%s ", - s->af_nb.src_name->text); - len += sprintf (buffer+len,"%s ", - s->af_nb.dst_name->text); - len += sprintf (buffer+len,"%08X:%08X ", s->wmem_alloc, s->rmem_alloc); - len += sprintf (buffer+len,"%02X %d\n", s->state, SOCK_INODE(s->socket)->i_uid); - - /* Are we still dumping unwanted data then discard the record */ - pos=begin+len; - - if(posoffset+length) /* We have dumped enough */ - break; - } - - /* The data in question runs from begin to begin+len */ - *start=buffer+(offset-begin); /* Start of wanted data */ - len-=(offset-begin); /* Remove unwanted header data from length */ - if(len>length) - len=length; /* Remove unwanted tail data from length */ - - return len; -} - -/* - * A device event has occurred. Watch for devices going down and - * delete our use of them (iface and route). - */ - -static int nb_device_event(struct notifier_block *this, unsigned long event, void *ptr) -{ - if(event==NETDEV_DOWN) - { - /* Discard any use of this */ - netbeui_drop_device((struct device *)ptr); - } - return NOTIFY_DONE; -} - -/*******************************************************************************************************************\ -* * -* Handling for system calls applied via the various interfaces to a netbeui socket object * -* * -\*******************************************************************************************************************/ - -/* - * Set 'magic' options for netbeui. If we don't have any this is fine - * as it is. - */ - -static int netbeui_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) -{ - netbeui_socket *sk; - int err,opt; - - sk=(netbeui_socket *)sock->data; - - if(optval==NULL) - return(-EINVAL); - - err = get_user(opt, (int *)optval); - if (err) - return err; - - switch(level) - { - case SOL_NETBEUI: - switch(optname) - { - default: - return -EOPNOTSUPP; - } - break; - - default: - return -EOPNOTSUPP; - } -} - - -/* - * Get any magic options. Comment above applies. - */ - -static int netbeui_getsockopt(struct socket *sock, int level, int optname, - char *optval, int *optlen) -{ - netbeui_socket *sk; - int val=0; - int err; - - sk=(netbeui_socket *)sock->data; - - switch(level) - { - - case SOL_NETBEUI: - switch(optname) - { - default: - return -ENOPROTOOPT; - } - break; - - default: - return -EOPNOTSUPP; - } - err = put_user(sizeof(int),optlen); - if (!err) - err = put_user(val, (int *) optval); - return err; -} - -/* - * Only for connection oriented sockets - ignore - */ - -static int netbeui_listen(struct socket *sock, int backlog) -{ - struct sock *sk=(netbeui_socket *)sock->data; - if(sk->state!=TCP_CLOSED) - return -EINVAL; - if(backlog<0) - return -EINVAL; - if(backlog<128) - sk->backlog=backlog; - else - sk->backlog=128; - sk->state=TCP_LISTEN; - sk->state_change(sk); - netbeui_add_listener(sk); - return 0; -} - -/* - * Create a socket. Initialise the socket, blank the addresses - * set the state. - */ - -static int netbeui_create(struct socket *sock, int protocol) -{ - netbeui_socket *sk; - sk=(netbeui_socket *)sk_alloc(GFP_KERNEL); - if(sk==NULL) - return(-ENOBUFS); - switch(sock->type) - { - case SOCK_DGRAM: - break; - case SOCK_SEQPACKET: - break; - default: - sk_free((void *)sk); - return(-ESOCKTNOSUPPORT); - } - - MOD_INC_USE_COUNT; - - sock_init_data(sock,sk); - sk->mtu=1500; - return(0); -} - -/* - * Copy a socket. No work needed. - */ - -static int netbeui_dup(struct socket *newsock,struct socket *oldsock) -{ - return(netbeui_create(newsock,oldsock->type)); -} - -/* - * Free a socket. No work needed - */ - -static int netbeui_release(struct socket *sock, struct socket *peer) -{ - netbeui_socket *sk=(netbeui_socket *)sock->data; - if(sk==NULL) - return(0); - if(!sk->dead) - sk->state_change(sk); - sk->dead=1; - sock->data=NULL; - netbeui_destroy_socket(sk); - return(0); -} - -/* - * Set the address 'our end' of the connection. - */ - -static int netbeui_bind(struct socket *sock, struct sockaddr *uaddr,size_t addr_len) -{ - netbeui_socket *sk; - struct sockaddr_netbeui *addr=(struct sockaddr_netbeui *)uaddr; - int err; - - sk=(netbeui_socket *)sock->data; - - if(sk->zapped==0) - return(-EINVAL); - - if(addr_len!=sizeof(struct sockaddr_netbeui)) - return -EINVAL; - - if(addr->snb_family!=AF_NETBEUI) - return -EAFNOSUPPORT; - - /* - * This will sleep. To meet POSIX it is non interruptible. - * Someone should give the 1003.1g authors an injection of - * imagination... - */ - - if(sk->af_nb.src_name!=NULL) - return -EINVAL; - - /* - * Try and get the name. It may return various 'invalid' name - * problem reports or EADDRINUSE if we or another node holds - * the desired name. - */ - - sk->af_nb.src_name=netbeui_alloc_name(addr, &err); - if(sk->af_nb.src_name==NULL) - return err; - /* - * Add us to the active socket list - */ - netbeui_insert_socket(sk); - sk->zapped=0; - return(0); -} - -/* - * Set the address we talk to. - */ - -static int netbeui_connect(struct socket *sock, struct sockaddr *uaddr, - size_t addr_len, int flags) -{ - netbeui_socket *sk=(netbeui_socket *)sock->data; - struct sockaddr_netbeui *addr=(struct sockaddr_netbeui *)uaddr; - - /* - * Check pending operations - */ - - if(sk->state==TCP_ESTABLISHED && sock->state == SS_CONNECTING) - { - sock->state==SS_CONNECTED; - return 0; - } - - if(sk->state == TCP_CLOSE & sock->state == SS_CONNECTING) - { - sock->state==SS_UNCONNECTED; - return -ECONNREFUSED; - } - - if(sock->state == SS_CONNECTING && (flags & O_NONBLOCK)) - return -EINPROGRESS; - - if(sk->state==TCP_ESTABLISHED) - return -EISCONN; - - /* - * If this is new it must really be new... - */ - - if(sk->af_nb.dst_name==NULL) - { - if(addr_len != sizeof(struct sockaddr_nb)) - return -EINVAL; - if(addr->snb_family!=AF_NETBEUI) - return -EAFNOSUPPORT; - /* - * Try and find the name - */ - } -} - -/* - * Not relevant - */ - -static int netbeui_socketpair(struct socket *sock1, struct socket *sock2) -{ - return(-EOPNOTSUPP); -} - -/* - * WRITE ME - */ - -static int netbeui_accept(struct socket *sock, struct socket *newsock, int flags) -{ - if(newsock->data) - sk_free(newsock->data); - return -EOPNOTSUPP; -} - -/* - * Find the name of a netbeui socket. Just copy the right - * fields into the sockaddr. - */ - -static int netbeui_getname(struct socket *sock, struct sockaddr *uaddr, - size_t *uaddr_len, int peer) -{ - struct sockaddr_netbeui snb; - netbeui_socket *sk; - - sk=(netbeui_socket *)sock->data; - if(sk->zapped) - { - return -EINVAL; - } - - *uaddr_len = sizeof(struct sockaddr_netbeui); - - if(peer) - { - if(sk->state!=TCP_ESTABLISHED) - return -ENOTCONN; - } - else - { - } - snb.snb_family = AF_NETBEUI; - memcpy(uaddr,&snb,sizeof(snb)); - return(0); -} - -/* - * Receive a packet (in skb) from device dev. - */ - -static int netbeui_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) -{ - netbeui_socket *sock; -} - -static int netbeui_sendmsg(struct socket *sock, struct msghdr *msg, int len, int nonblock, int flags) -{ - netbeui_socket *sk=(netbeui_socket *)sock->data; - struct sockaddr_at *usat=(struct sockaddr_at *)msg->msg_name; - struct sockaddr_at local_snetbeui, gsat; - struct sk_buff *skb; - struct device *dev; - struct ddpehdr *ddp; - int size; - struct netbeui_route *rt; - int loopback=0; - int err; - - if(flags) - return -EINVAL; - - if(len>587) - return -EMSGSIZE; - - if(usat) - { - if(sk->zapped) - { - if(netbeui_autobind(sk)<0) - return -EBUSY; - } - - if(msg->msg_namelen sat_family != AF_NETBEUI) - return -EINVAL; -#if 0 /* netnetbeui doesn't implement this check */ - if(usat->sat_addr.s_node==ATADDR_BCAST && !sk->broadcast) - return -EPERM; -#endif - } - else - { - if(sk->state!=TCP_ESTABLISHED) - return -ENOTCONN; - usat=&local_snetbeui; - usat->sat_family=AF_NETBEUI; - usat->sat_port=sk->protinfo.af_at.dest_port; - usat->sat_addr.s_node=sk->protinfo.af_at.dest_node; - usat->sat_addr.s_net=sk->protinfo.af_at.dest_net; - } - - /* Build a packet */ - SOCK_DEBUG(sk, "SK %p: Got address.\n",sk); - size=sizeof(struct ddpehdr)+len+nb_dl->header_length; /* For headers */ - - if(usat->sat_addr.s_net!=0 || usat->sat_addr.s_node == ATADDR_ANYNODE) - { - rt=atrtr_find(&usat->sat_addr); - if(rt==NULL) - return -ENETUNREACH; - dev=rt->dev; - } - else - { - struct at_addr at_hint; - at_hint.s_node=0; - at_hint.s_net=sk->protinfo.af_at.src_net; - rt=atrtr_find(&at_hint); - if(rt==NULL) - return -ENETUNREACH; - dev=rt->dev; - } - SOCK_DEBUG(sk, "SK %p: Size needed %d, device %s\n", sk, size, dev->name); - size += dev->hard_header_len; - skb = sock_alloc_send_skb(sk, size, 0, 0 , &err); - if(skb==NULL) - return err; - - skb->sk=sk; - skb->free=1; - skb->arp=1; - skb_reserve(skb,nb_dl->header_length); - skb_reserve(skb,dev->hard_header_len); - skb->dev=dev; - SOCK_DEBUG(sk, "SK %p: Begin build.\n", sk); - ddp=(struct ddpehdr *)skb_put(skb,sizeof(struct ddpehdr)); - ddp->deh_pad=0; - ddp->deh_hops=0; - ddp->deh_len=len+sizeof(*ddp); - /* - * Fix up the length field [Ok this is horrible but otherwise - * I end up with unions of bit fields and messy bit field order - * compiler/endian dependencies.. - */ - *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); - - ddp->deh_dnet=usat->sat_addr.s_net; - ddp->deh_snet=sk->protinfo.af_at.src_net; - ddp->deh_dnode=usat->sat_addr.s_node; - ddp->deh_snode=sk->protinfo.af_at.src_node; - ddp->deh_dport=usat->sat_port; - ddp->deh_sport=sk->protinfo.af_at.src_port; - SOCK_DEBUG(sk, "SK %p: Copy user data (%d bytes).\n", sk, len); - err = memcpy_fromiovec(skb_put(skb,len),msg->msg_iov,len); - if (err) - { - kfree_skb(skb, FREE_WRITE); - return -EFAULT; - } - - if(sk->no_check==1) - ddp->deh_sum=0; - else - ddp->deh_sum=netbeui_checksum(ddp, len+sizeof(*ddp)); - -#ifdef CONFIG_FIREWALL - - if(call_out_firewall(AF_NETBEUI, skb->dev, ddp, NULL)!=FW_ACCEPT) - { - kfree_skb(skb, FREE_WRITE); - return -EPERM; - } - -#endif - - /* - * Loopback broadcast packets to non gateway targets (ie routes - * to group we are in) - */ - - if(ddp->deh_dnode==ATADDR_BCAST) - { - if((!(rt->flags&RTF_GATEWAY))&&(!(dev->flags&IFF_LOOPBACK))) - { - struct sk_buff *skb2=skb_clone(skb, GFP_KERNEL); - if(skb2) - { - loopback=1; - SOCK_DEBUG(sk, "SK %p: send out(copy).\n", sk); - if(aarp_send_ddp(dev,skb2,&usat->sat_addr, NULL)==-1) - kfree_skb(skb2, FREE_WRITE); - /* else queued/sent above in the aarp queue */ - } - } - } - - if((dev->flags&IFF_LOOPBACK) || loopback) - { - SOCK_DEBUG(sk, "SK %p: Loop back.\n", sk); - /* loop back */ - atomic_sub(skb->truesize, &sk->wmem_alloc); - nb_dl->datalink_header(nb_dl, skb, dev->dev_addr); - skb->sk = NULL; - skb->mac.raw=skb->data; - skb->h.raw = skb->data + nb_dl->header_length + dev->hard_header_len; - skb_pull(skb,dev->hard_header_len); - skb_pull(skb,nb_dl->header_length); - netbeui_rcv(skb,dev,NULL); - } - else - { - SOCK_DEBUG(sk, "SK %p: send out.\n", sk); - if ( rt->flags & RTF_GATEWAY ) { - gsat.sat_addr = rt->gateway; - usat = &gsat; - } - - if(nb_send_low(dev,skb,&usat->sat_addr, NULL)==-1) - kfree_skb(skb, FREE_WRITE); - /* else queued/sent above in the aarp queue */ - } - SOCK_DEBUG(sk, "SK %p: Done write (%d).\n", sk, len); - return len; -} - - -static int netbeui_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len) -{ - netbeui_socket *sk=(netbeui_socket *)sock->data; - struct sockaddr_at *sat=(struct sockaddr_at *)msg->msg_name; - struct ddpehdr *ddp = NULL; - int copied = 0; - struct sk_buff *skb; - int er = 0; - - if(addr_len) - *addr_len=sizeof(*sat); - - skb=skb_recv_datagram(sk,flags,noblock,&er); - if(skb==NULL) - return er; - - ddp = (struct ddpehdr *)(skb->h.raw); - if(sk->type==SOCK_RAW) - { - copied=ddp->deh_len; - if(copied > size) - { - copied=size; - msg->msg_flags|=MSG_TRUNC; - } - er = skb_copy_datagram_iovec(skb,0,msg->msg_iov,copied); - if (er) - goto out; - } - else - { - copied=ddp->deh_len - sizeof(*ddp); - if (copied > size) - { - copied = size; - msg->msg_flags|=MSG_TRUNC; - } - er = skb_copy_datagram_iovec(skb,sizeof(*ddp),msg->msg_iov,copied); - if (er) - goto out; - } - if(sat) - { - sat->sat_family=AF_NETBEUI; - sat->sat_port=ddp->deh_sport; - sat->sat_addr.s_node=ddp->deh_snode; - sat->sat_addr.s_net=ddp->deh_snet; - } -out: - skb_free_datagram(sk, skb); - return er ? er : (copied); -} - - -static int netbeui_shutdown(struct socket *sk,int how) -{ - return -EOPNOTSUPP; -} - -static int netbeui_poll(struct socket *sock, poll_table *wait) -{ - netbeui_socket *sk=(netbeui_socket *)sock->data; - - return datagram_poll(sk,wait); -} - -/* - * Netbeui ioctl calls. - */ - -static int netbeui_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) -{ - long amount=0; - netbeui_socket *sk=(netbeui_socket *)sock->data; - - switch(cmd) - { - /* - * Protocol layer - */ - case TIOCOUTQ: - amount=sk->sndbuf-sk->wmem_alloc; - if(amount<0) - amount=0; - break; - case TIOCINQ: - { - struct sk_buff *skb; - /* These two are safe on a single CPU system as only user tasks fiddle here */ - if((skb=skb_peek(&sk->receive_queue))!=NULL) - amount=skb->len-sizeof(struct ddpehdr); - break; - } - case SIOCGSTAMP: - if (sk) - { - if(sk->stamp.tv_sec==0) - return -ENOENT; - return copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval)) ? -EFAULT : 0; - } - return -EINVAL; - /* - * Routing - */ - case SIOCADDRT: - case SIOCDELRT: - if(!suser()) - return -EPERM; - return(atrtr_ioctl(cmd,(void *)arg)); - /* - * Interface - */ - case SIOCGIFADDR: - case SIOCSIFADDR: - case SIOCGIFBRDADDR: - return atif_ioctl(cmd,(void *)arg); - /* - * Physical layer ioctl calls - */ - case SIOCSIFLINK: - case SIOCGIFHWADDR: - case SIOCSIFHWADDR: - case SIOCGIFFLAGS: - case SIOCSIFFLAGS: - case SIOCGIFMTU: - case SIOCGIFCONF: - case SIOCADDMULTI: - case SIOCDELMULTI: - - return(dev_ioctl(cmd,(void *) arg)); - - case SIOCSIFMETRIC: - case SIOCSIFBRDADDR: - case SIOCGIFNETMASK: - case SIOCSIFNETMASK: - case SIOCGIFMEM: - case SIOCSIFMEM: - case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: - return -EINVAL; - - default: - return -EINVAL; - } - return put_user(amount, (int *)arg); -} - -static struct proto_ops netbeui_proto_ops = { - AF_NETBEUI, - - netbeui_create, - netbeui_dup, - netbeui_release, - netbeui_bind, - netbeui_connect, - netbeui_socketpair, - netbeui_accept, - netbeui_getname, - netbeui_poll, - netbeui_ioctl, - netbeui_listen, - netbeui_shutdown, - netbeui_setsockopt, - netbeui_getsockopt, - sock_no_fcntl, - netbeui_sendmsg, - netbeui_recvmsg -}; - -static struct notifier_block nb_notifier={ - nb_device_event, - NULL, - 0 -}; - -static char nb_snap_id[]={0x08,0x00,0x07,0x80,0x9B}; - -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry proc_netbeui = { - PROC_NET_NETBEUI, 9, "netbeui", - S_IFREG | S_IRUGO, 1, 0, 0 - 0, &proc_net_inode_operations, - netbeui_get_info -}; -#endif - -/* Called by proto.c on kernel start up */ - -void netbeui_proto_init(struct net_proto *pro) -{ - (void) sock_register(netbeui_proto_ops.family, &netbeui_proto_ops); -/* ddp? isn't it atalk too? 8) */ - if ((nb_dl = register_snap_client(nb_snap_id, netbeui_rcv)) == NULL) - printk(KERN_CRIT "Unable to register DDP with SNAP.\n"); - - register_netdevice_notifier(&nb_notifier); - -#ifdef CONFIG_PROC_FS - proc_net_register(&proc_netbeui); -#endif - - printk(KERN_INFO "NetBEUI 0.02 for Linux NET3.037\n"); -} - -#ifdef MODULE -EXPORT_NO_SYMBOLS; - -int init_module(void) -{ - netbeui_proto_init(NULL); - return 0; -} - -void cleanup_module(void) -{ - unsigned long flags; -#ifdef CONFIG_PROC_FS - proc_net_unregister(PROC_NET_NETBEUI); -#endif - unregister_netdevice_notifier(&nb_notifier); - unregister_snap_client(nb_snap_id); - sock_unregister(netbeui_proto_ops.family); -} - -#endif /* MODULE */ diff -u --recursive --new-file v2.1.26/linux/net/netbeui/netbeui_llc.c linux/net/netbeui/netbeui_llc.c --- v2.1.26/linux/net/netbeui/netbeui_llc.c Thu Jan 2 05:13:29 1997 +++ linux/net/netbeui/netbeui_llc.c Tue Feb 25 17:12:51 1997 @@ -70,6 +70,11 @@ * See what has occured */ + + /* + * Connect completion confirmation + */ + if(llc->llc_callbacks&LLC_CONN_CONFIRM) { /* @@ -93,7 +98,13 @@ */ if(llc->llc_callbacks&LLC_DATA_INDIC) + { netbeu_rcv_stream(llc,llc->inc_skb); + /* + * Frame free is controlled by our stream processor + */ + return; + } /* * We got disconnected @@ -113,6 +124,10 @@ } } + /* + * Miscellaneous burps + */ + if(llc->llc_callbacks&(LLC_RESET_INDIC_LOC|LLC_RESET_INDIC_REM| LLC_RST_CONFIRM)) { @@ -124,6 +139,10 @@ */ } + /* + * Track link busy status + */ + if(llc->llc_callbacks&LLC_REMOTE_BUSY) nb->busy=1; /* Send no more for a bit */ if(llc->llc_callbacks&LLC_REMOTE_NOTBUSY) @@ -136,10 +155,15 @@ * UI frames are passed to the upper netbeui layer. */ if(llc->llc_callbacks&LLC_UI_DATA) + { netbeui_rcv_dgram(llc,llc->inc_skb); + return; + } /* We ignore TST, XID, FRMR stuff */ /* FIXME: We need to free frames here once I fix the callback! */ + if(llc->inc_skb) + kfree_skb(skb, FREE_READ); } /* diff -u --recursive --new-file v2.1.26/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c --- v2.1.26/linux/net/netrom/af_netrom.c Sun Feb 2 05:18:52 1997 +++ linux/net/netrom/af_netrom.c Fri Feb 21 14:58:40 1997 @@ -308,7 +308,7 @@ kfree_skb(skb, FREE_READ); } - if (sk->wmem_alloc > 0 || sk->rmem_alloc > 0) { /* Defer: outstanding buffers */ + if (sk->wmem_alloc != 0 || sk->rmem_alloc != 0) { /* Defer: outstanding buffers */ init_timer(&sk->timer); sk->timer.expires = jiffies + 10 * HZ; sk->timer.function = nr_destroy_timer; @@ -421,17 +421,16 @@ int err, opt; if (level != SOL_NETROM) - return -EOPNOTSUPP; + return -ENOPROTOOPT; - if (optval == NULL) + if(optlensk; int val = 0; - int err; + int len; if (level != SOL_NETROM) - return -EOPNOTSUPP; + return -ENOPROTOOPT; + + if(get_user(len,optlen)) + return -EFAULT; switch (optname) { case NETROM_T1: @@ -510,16 +512,11 @@ return -ENOPROTOOPT; } - if ((err = verify_area(VERIFY_WRITE, optlen, sizeof(int))) != 0) - return err; - - put_user(sizeof(int), optlen); - - if ((err = verify_area(VERIFY_WRITE, optval, sizeof(int))) != 0) - return err; - - put_user(val, (int *)optval); - + len=min(len,sizeof(int)); + if(put_user(len, optlen)) + return -EFAULT; + if(copy_to_user(optval,&val,len)) + return -EFAULT; return 0; } diff -u --recursive --new-file v2.1.26/linux/net/netrom/nr_dev.c linux/net/netrom/nr_dev.c --- v2.1.26/linux/net/netrom/nr_dev.c Tue Feb 4 06:44:26 1997 +++ linux/net/netrom/nr_dev.c Tue Feb 25 17:12:51 1997 @@ -23,6 +23,8 @@ #include #if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE) +#define __NO_VERSION__ +#include #include #include #include @@ -173,7 +175,7 @@ { dev->tbusy = 0; dev->start = 1; - + MOD_INC_USE_COUNT; ax25_listen_register((ax25_address *)dev->dev_addr, NULL); return 0; @@ -183,9 +185,8 @@ { dev->tbusy = 1; dev->start = 0; - ax25_listen_release((ax25_address *)dev->dev_addr, NULL); - + MOD_DEC_USE_COUNT; return 0; } diff -u --recursive --new-file v2.1.26/linux/net/netrom/nr_route.c linux/net/netrom/nr_route.c --- v2.1.26/linux/net/netrom/nr_route.c Sun Feb 2 05:18:52 1997 +++ linux/net/netrom/nr_route.c Tue Feb 25 17:12:51 1997 @@ -698,7 +698,7 @@ if (ax25 != NULL) nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat, - ax25->device, 0, sysctl_netrom_obsolescence_count_initialiser); + ax25->ax25_dev->dev, 0, sysctl_netrom_obsolescence_count_initialiser); if ((dev = nr_dev_get(nr_dest)) != NULL) /* Its for me */ return nr_rx_frame(skb, dev); @@ -730,7 +730,7 @@ dptr = skb_push(skb, 1); *dptr = AX25_P_NETROM; - return ax25_send_frame(skb, 0, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev); + return ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev); } int nr_nodes_get_info(char *buffer, char **start, off_t offset, diff -u --recursive --new-file v2.1.26/linux/net/rose/af_rose.c linux/net/rose/af_rose.c --- v2.1.26/linux/net/rose/af_rose.c Sun Feb 2 05:18:52 1997 +++ linux/net/rose/af_rose.c Tue Feb 25 17:12:51 1997 @@ -357,7 +357,7 @@ kfree_skb(skb, FREE_READ); } - if (sk->wmem_alloc > 0 || sk->rmem_alloc > 0) { /* Defer: outstanding buffers */ + if (sk->wmem_alloc != 0 || sk->rmem_alloc != 0) { /* Defer: outstanding buffers */ init_timer(&sk->timer); sk->timer.expires = jiffies + 10 * HZ; sk->timer.function = rose_destroy_timer; @@ -464,20 +464,18 @@ char *optval, int optlen) { struct sock *sk = sock->sk; - int err, opt; + int opt; if (level != SOL_ROSE) - return -EOPNOTSUPP; + return -ENOPROTOOPT; - if (optval == NULL) + if(optlensk; int val = 0; - int err; + int len; if (level != SOL_ROSE) - return -EOPNOTSUPP; + return -ENOPROTOOPT; + + if(get_user(len,optlen)) + return -EFAULT; switch (optname) { case ROSE_T1: @@ -556,16 +557,11 @@ return -ENOPROTOOPT; } - if ((err = verify_area(VERIFY_WRITE, optlen, sizeof(int))) != 0) - return err; - - put_user(sizeof(int), (unsigned long *)optlen); - - if ((err = verify_area(VERIFY_WRITE, optval, sizeof(int))) != 0) - return err; - - put_user(val, (unsigned long *)optval); - + len=min(len,sizeof(int)); + if(put_user(len,optlen)) + return -EFAULT; + if(copy_to_user(optval,&val,len)) + return -EFAULT; return 0; } @@ -685,15 +681,6 @@ rose_destroy_socket(sk); break; - case ROSE_STATE_1: - sk->protinfo.rose->state = ROSE_STATE_0; - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); - sk->dead = 1; - rose_destroy_socket(sk); - break; - case ROSE_STATE_2: sk->protinfo.rose->state = ROSE_STATE_0; sk->state = TCP_CLOSE; @@ -703,6 +690,7 @@ rose_destroy_socket(sk); break; + case ROSE_STATE_1: case ROSE_STATE_3: case ROSE_STATE_4: rose_clear_queues(sk); diff -u --recursive --new-file v2.1.26/linux/net/rose/rose_dev.c linux/net/rose/rose_dev.c --- v2.1.26/linux/net/rose/rose_dev.c Tue Feb 4 06:44:27 1997 +++ linux/net/rose/rose_dev.c Tue Feb 25 17:12:51 1997 @@ -19,6 +19,8 @@ #include #if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE) +#define __NO_VERSION__ +#include #include #include #include @@ -143,6 +145,7 @@ static int rose_open(struct device *dev) { + MOD_INC_USE_COUNT; dev->tbusy = 0; dev->start = 1; @@ -153,6 +156,7 @@ static int rose_close(struct device *dev) { + MOD_DEC_USE_COUNT; dev->tbusy = 1; dev->start = 0; diff -u --recursive --new-file v2.1.26/linux/net/rose/rose_in.c linux/net/rose/rose_in.c --- v2.1.26/linux/net/rose/rose_in.c Sun Feb 2 05:18:52 1997 +++ linux/net/rose/rose_in.c Fri Feb 21 14:58:40 1997 @@ -106,6 +106,7 @@ case ROSE_CLEAR_REQUEST: rose_clear_queues(sk); + rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); sk->protinfo.rose->state = ROSE_STATE_0; sk->state = TCP_CLOSE; sk->err = ECONNREFUSED; @@ -133,7 +134,9 @@ switch (frametype) { case ROSE_CLEAR_REQUEST: + rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); case ROSE_CLEAR_CONFIRMATION: + rose_clear_queues(sk); sk->protinfo.rose->state = ROSE_STATE_0; sk->state = TCP_CLOSE; sk->err = 0; @@ -163,7 +166,6 @@ switch (frametype) { case ROSE_RESET_REQUEST: - rose_clear_queues(sk); rose_write_internal(sk, ROSE_RESET_CONFIRMATION); sk->protinfo.rose->condition = 0x00; sk->protinfo.rose->timer = 0; @@ -270,8 +272,9 @@ { switch (frametype) { - case ROSE_RESET_CONFIRMATION: case ROSE_RESET_REQUEST: + rose_write_internal(sk, ROSE_RESET_CONFIRMATION); + case ROSE_RESET_CONFIRMATION: sk->protinfo.rose->timer = 0; sk->protinfo.rose->condition = 0x00; sk->protinfo.rose->va = 0; diff -u --recursive --new-file v2.1.26/linux/net/rose/rose_link.c linux/net/rose/rose_link.c --- v2.1.26/linux/net/rose/rose_link.c Sun Feb 2 05:18:52 1997 +++ linux/net/rose/rose_link.c Tue Feb 25 17:12:51 1997 @@ -103,7 +103,7 @@ else rose_call = &rose_callsign; - return ax25_send_frame(skb, 0, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev); + return ax25_send_frame(skb, 256, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev); } /* @@ -120,7 +120,7 @@ else rose_call = &rose_callsign; - return ax25_link_up(rose_call, &neigh->callsign, neigh->dev); + return ax25_link_up(rose_call, &neigh->callsign, neigh->digipeat, neigh->dev); } /* diff -u --recursive --new-file v2.1.26/linux/net/rose/rose_route.c linux/net/rose/rose_route.c --- v2.1.26/linux/net/rose/rose_route.c Sun Feb 2 05:18:52 1997 +++ linux/net/rose/rose_route.c Tue Feb 25 17:12:51 1997 @@ -556,7 +556,7 @@ dest_addr = (rose_address *)(skb->data + 4); for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) - if (ax25cmp(&ax25->dest_addr, &rose_neigh->callsign) == 0 && ax25->device == rose_neigh->dev) + if (ax25cmp(&ax25->dest_addr, &rose_neigh->callsign) == 0 && ax25->ax25_dev->dev == rose_neigh->dev) break; if (rose_neigh == NULL) diff -u --recursive --new-file v2.1.26/linux/net/socket.c linux/net/socket.c --- v2.1.26/linux/net/socket.c Fri Feb 7 05:57:06 1997 +++ linux/net/socket.c Fri Feb 21 14:58:40 1997 @@ -38,6 +38,7 @@ * Alan Cox : Added thread locking to sys_* calls * for sockets. May have errors at the * moment. + * Kevin Buhr : Fixed the dumb errors in the above. * * * This program is free software; you can redistribute it and/or @@ -1222,7 +1223,7 @@ } if (msg_sys.msg_iovlen>UIO_MAXIOV) { - err=-EFAULT; + err=-EINVAL; goto out; } diff -u --recursive --new-file v2.1.26/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v2.1.26/linux/net/unix/af_unix.c Sat Jan 25 13:46:14 1997 +++ linux/net/unix/af_unix.c Tue Feb 25 17:12:51 1997 @@ -1433,8 +1433,8 @@ unix_ioctl, unix_listen, unix_shutdown, - NULL, - NULL, + sock_no_setsockopt, + sock_no_getsockopt, sock_no_fcntl, unix_stream_sendmsg, unix_stream_recvmsg @@ -1452,10 +1452,10 @@ unix_getname, datagram_poll, unix_ioctl, - NULL, + sock_no_listen, unix_shutdown, - NULL, - NULL, + sock_no_setsockopt, + sock_no_getsockopt, sock_no_fcntl, unix_dgram_sendmsg, unix_dgram_recvmsg diff -u --recursive --new-file v2.1.26/linux/net/x25/af_x25.c linux/net/x25/af_x25.c --- v2.1.26/linux/net/x25/af_x25.c Sun Feb 2 05:18:53 1997 +++ linux/net/x25/af_x25.c Fri Feb 21 14:58:40 1997 @@ -328,7 +328,7 @@ kfree_skb(skb, FREE_READ); } - if (sk->wmem_alloc || sk->rmem_alloc) { /* Defer: outstanding buffers */ + if (sk->wmem_alloc != 0 || sk->rmem_alloc != 0) { /* Defer: outstanding buffers */ init_timer(&sk->timer); sk->timer.expires = jiffies + 10 * HZ; sk->timer.function = x25_destroy_timer; @@ -355,21 +355,18 @@ int err, opt; if (level != SOL_X25) - return -EOPNOTSUPP; + return -ENOPROTOOPT; - if (optval == NULL) - return -EINVAL; - - if ((err = verify_area(VERIFY_READ, optval, sizeof(int))) != 0) - return err; - - get_user(opt, (int *)optval); + if(optlenprotinfo.x25->qbitincl = opt ? 1 : 0; return 0; - default: return -ENOPROTOOPT; } @@ -380,12 +377,16 @@ { struct sock *sk = sock->sk; int val = 0; - int err; - + int len; + if (level != SOL_X25) - return -EOPNOTSUPP; + return -ENOPROTOOPT; - switch (optname) { + if(get_user(len,optlen)) + return -EFAULT; + + switch (optname) + { case X25_QBITINCL: val = sk->protinfo.x25->qbitincl; break; @@ -394,16 +395,11 @@ return -ENOPROTOOPT; } - if ((err = verify_area(VERIFY_WRITE, optlen, sizeof(int))) != 0) - return err; - - put_user(sizeof(int), (unsigned long *)optlen); - - if ((err = verify_area(VERIFY_WRITE, optval, sizeof(int))) != 0) - return err; - - put_user(val, (unsigned long *)optval); - + len=min(len,sizeof(int)); + if(put_user(len, optlen)) + return -EFAULT; + if(copy_to_user(optval,&val,len)) + return -EFAULT; return 0; } @@ -548,15 +544,6 @@ x25_destroy_socket(sk); break; - case X25_STATE_1: - sk->protinfo.x25->state = X25_STATE_0; - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); - sk->dead = 1; - x25_destroy_socket(sk); - break; - case X25_STATE_2: sk->protinfo.x25->state = X25_STATE_0; sk->state = TCP_CLOSE; @@ -566,6 +553,7 @@ x25_destroy_socket(sk); break; + case X25_STATE_1: case X25_STATE_3: case X25_STATE_4: x25_clear_queues(sk); diff -u --recursive --new-file v2.1.26/linux/net/x25/x25_in.c linux/net/x25/x25_in.c --- v2.1.26/linux/net/x25/x25_in.c Sun Jan 19 05:47:30 1997 +++ linux/net/x25/x25_in.c Fri Feb 21 14:58:40 1997 @@ -117,6 +117,7 @@ case X25_CLEAR_REQUEST: x25_clear_queues(sk); + x25_write_internal(sk, X25_CLEAR_CONFIRMATION); sk->protinfo.x25->state = X25_STATE_0; sk->state = TCP_CLOSE; sk->err = ECONNREFUSED; @@ -144,7 +145,9 @@ switch (frametype) { case X25_CLEAR_REQUEST: + x25_write_internal(sk, X25_CLEAR_CONFIRMATION); case X25_CLEAR_CONFIRMATION: + x25_clear_queues(sk); sk->protinfo.x25->state = X25_STATE_0; sk->state = TCP_CLOSE; sk->err = 0; @@ -177,7 +180,6 @@ switch (frametype) { case X25_RESET_REQUEST: - x25_clear_queues(sk); x25_write_internal(sk, X25_RESET_CONFIRMATION); sk->protinfo.x25->condition = 0x00; sk->protinfo.x25->timer = 0; @@ -306,8 +308,9 @@ { switch (frametype) { - case X25_RESET_CONFIRMATION: case X25_RESET_REQUEST: + x25_write_internal(sk, X25_RESET_CONFIRMATION); + case X25_RESET_CONFIRMATION: sk->protinfo.x25->timer = 0; sk->protinfo.x25->condition = 0x00; sk->protinfo.x25->va = 0; diff -u --recursive --new-file v2.1.26/linux/scripts/Configure linux/scripts/Configure --- v2.1.26/linux/scripts/Configure Fri Feb 7 05:54:55 1997 +++ linux/scripts/Configure Fri Feb 21 14:58:40 1997 @@ -1,3 +1,4 @@ + #! /bin/sh # # This script is used to configure the linux kernel. @@ -56,6 +57,16 @@ # Enable function cacheing. set -f -h +# Newer shellutils have a more POSIX compliant behavior which is +# sadly not backward compatible. +if expr "$(expr --version)" : '.*1\.1[56]' > /dev/null; then + INT_FILTER='0$\|-\?[1-9][0-9]*$' + HEX_FILTER='[0-9a-fA-F]\+$' +else + INT_FILTER='0$\|-?[1-9][0-9]*$' + HEX_FILTER='[0-9a-fA-F]+$' +fi + # # Dummy functions for use with a config.in modified for menuconf # @@ -288,7 +299,7 @@ def=${old:-$3} while :; do readln "$1 ($2) [$def] " "$def" "$old" - if expr "$ans" : '0$\|-\?[1-9][0-9]*$' > /dev/null; then + if expr "$ans" : $INT_FILTER > /dev/null; then define_int "$2" "$ans" break else @@ -319,7 +330,7 @@ while :; do readln "$1 ($2) [$def] " "$def" "$old" ans=${ans#*[x,X]} - if expr "$ans" : '[0-9a-fA-F]\+$' > /dev/null; then + if expr "$ans" : $HEX_FILTER > /dev/null; then define_hex "$2" "$ans" break else