diff -u --recursive --new-file v2.1.41/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.41/linux/Documentation/Configure.help Sat May 24 09:10:22 1997 +++ linux/Documentation/Configure.help Wed May 28 10:49:07 1997 @@ -4756,8 +4756,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 and - HiSax drivers are the only voice-supporting drivers. See + supported by the lowlevel driver also. Currently, the HiSax driver is + the only voice-supporting driver. See Documentation/isdn/README.audio for more information. ICN 2B and 4B support @@ -4772,18 +4772,6 @@ 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 icn.o. - -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. - 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 to work. - 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 diff -u --recursive --new-file v2.1.41/linux/Documentation/isdn/00-INDEX linux/Documentation/isdn/00-INDEX --- v2.1.41/linux/Documentation/isdn/00-INDEX Thu Jun 6 04:57:43 1996 +++ linux/Documentation/isdn/00-INDEX Wed May 28 10:49:07 1997 @@ -10,12 +10,13 @@ - info for running audio over ISDN. README.icn - info on the ICN-ISDN-card and its driver. +README.HiSax + - info on the HiSax driver which replaces the old teles. README.pcbit - info on the PCBIT-D ISDN adapter and driver. README.syncppp - info on running Sync PPP over ISDN. -README.teles - - info on driver for Teles compatible ISDN cards. syncPPP.FAQ - frequently asked questions about running PPP over ISDN. - +README.avmb1 + - info on driver for AVM-B1 ISDN card diff -u --recursive --new-file v2.1.41/linux/Documentation/isdn/CREDITS linux/Documentation/isdn/CREDITS --- v2.1.41/linux/Documentation/isdn/CREDITS Thu Feb 27 10:57:29 1997 +++ linux/Documentation/isdn/CREDITS Wed May 28 10:49:07 1997 @@ -50,3 +50,5 @@ For distributing the cards. For pushing me to work ;-) +Carsten Paeth (calle@calle.in-berlin.de) + For the AVM-B1-CAPI2.0 driver diff -u --recursive --new-file v2.1.41/linux/Documentation/isdn/README linux/Documentation/isdn/README --- v2.1.41/linux/Documentation/isdn/README Thu Feb 27 10:57:29 1997 +++ linux/Documentation/isdn/README Wed May 28 10:49:07 1997 @@ -60,7 +60,7 @@ A raw-control-device with the following functions: write: raw D-channel-messages (format: depends on driver). read: raw D-channel-messages (format: depends on driver). - ioctl: depends on driver, for the ICN-driver, the base-address of + ioctl: depends on driver, i.e. for the ICN-driver, the base-address of the ports and the shared memory on the card can be set and read also the boot-code an the protocol software can be loaded into the card. @@ -107,7 +107,7 @@ ATZ Load registers and EAZ/MSN from Profile. AT&Bx Set Send-Packet-size to x (max. 4000) The real packet-size may be limited by the - low-level-driver used. i.e.: the Teles-Module- + low-level-driver used. i.e.: the HiSax-Module- limit is 2000. You will get NO Error-Message, if you set it to higher Values, because at the time of giving this command the corresponding @@ -120,8 +120,7 @@ AT&D3 Same as AT&D2 but also resets all registers. AT&Ex Set the EAZ/MSN for this channel to x. AT&F Reset all registers and profile to "factory-defaults" - AT&Sx Set window-size for Teles-driver (x = 1..8) (not yet - implemented) + AT&Sx Set window-size (x = 1..8) (not yet implemented) AT&V Show all settings. AT&W0 Write registers and EAZ/MSN to profile. See also iprofd (5.c in this README). @@ -194,7 +193,7 @@ 15 0 Layer-3 protocol: (at the moment always 0) 0 = transparent 16 250 Send-Packet-size/16 - 17 8 Window-size for Teles-driver (not yet implemented) + 17 8 Window-size (not yet implemented) 18 4 Bit coded register, Service-Octet-1 to accept, or to be used on dialout: Bit 0: Service 1 (audio) when set. @@ -271,111 +270,8 @@ 3. Lowlevel-driver configuration. - Configuration depends on how the drivers are built. - - 3.1 Drivers built into the kernel. - - 3.1.1 Teles driver. - - The Teles driver can be configured using the commandline-feature - while loading the kernel with LILO or LOADLIN. It accepts the - following syntax: - - teles=p0,i0,m0,d0[,p1,i1,m1,d1 ... ,pn,in,mn,dn][,idstring] - - where - - p0 = portbase of 1st card. (default: 0xd80) - i0 = irq of 1st card. (default: 15) - m0 = shared memory of 1st card. (default: 0xd0000) - d0 = D-channel protocol of 1st card. 1=1TR6, 2=EDSS1 (default: 2) - - p1,i1,m1,d1 = Parameters of second card (defaults: none) - pn,in,mn,d1 = 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: none) - idstring must start with a character! - - The type of the card is determined by the port, irq and shared memory: - - port == 0, shared memory != 0 -> Teles S0-8 - port != 0, shared memory != 0 -> Teles S0-16.0 - port != 0, shared memory == 0 -> Teles S0-16.3 - - ATTENTION: - - Due to limited hardware-capabilities, there is no way to check the - existence of a card. Therefore you need to be sure your card's setup - is correct. Also there are bugs in the printed manual of some newer - 16.3 cards. Have a look to the kernel-syslog. With most of the cards, - you should see a line "HSCX version A:5 B:5" there. - - 3.1.2 ICN driver. - - The ICN driver can be configured using the commandline-feature while - loading the kernel with LILO or LOADLIN. It accepts the following - syntax - - icn=p,m[,idstring1[,idstring2]] - - where - - p = portbase (default: 0x320) - m = shared memory (default: 0xd0000) - - When using the ICN double card, you MUST define TWO idstrings. - idstring must start with a character! - - If you like to use more than one card, you can use the program - "icnctrl" from the utility-package to configure additional cards. - You need to configure shared memory only once, since the icn-driver - maps all cards into the same address-space. - - Using the "icnctrl"-utility, portbase and shared memory can also be - changed during runtime. - - The D-channel protocol is configured by loading different firmware - into the card's memory using the "icnctrl"-utility. - - - 3.2 Drivers built as modules. - - 3.2.1 Teles driver. - - The module teles.o can be configured during "insmod'ing" it by - appending its parameters to the insmod-commandline. The following - syntax is accepted: - - io=m0,i0,p0,d0[,m1,i1,p1,d1 ... ,mn,in,pn,dn] teles_id=idstring - - where - - m0,i0,p0,d0 ... mn,in,pn,dn have the same meanings like the - parameters described for the kernel- - version above. Watch out: different - sequence! - - 3.2.2 ICN driver. - - The module icn.o can be configured during "insmod'ing" it by - appending its parameters to the insmod-commandline. The following - syntax is accepted: - - portbase=p membase=m icn_id=idstring icn_id2=idstring2 - - where p, m, idstring1 and idstring2 have the same meanings like - parameters described for the kernel- - version above. - - When using the ICN double card, you MUST define TWO idstrings. - idstring must start with a character! - - Using the "icnctrl"-utility, the same features apply to the modularized - version like to the kernel-builtin one. - - The D-channel protocol is configured by loading different firmware - into the card's memory using the "icnctrl"-utility. + Configuration depends on how the drivers are built. See the + README. for information on driver-specific setup. 4. Device-inodes @@ -386,26 +282,11 @@ 44 for the ISDN-callout-tty's. 45 for control/info/debug devices. - 5. Application - a) (Only for ICN-cards) Load the firmware into the card: - - cd icn - For 1TR6: - icnctrl [-d IDstring] load download/loadpg.bin download/pc_1t_ca.bin - For Euro-ISDN: - icnctrl [-d IDstring] load download/loadpg.bin download/pc_eu_ca.bin - - When using the ICN-4B, the protocol-software for the second half of - the card must be appended to the command line. - - -> The two LEDs at the back cover of the card (ICN-4B: 4 LEDs) must be - blinking intermittently now. If a connection is up, the corresponding - led is lit continuously. - - For loading pcbit-firmware, refer to Documentation/isdn/README.pcbit - and the pcbit manpage, included in the utility-package. + a) For some card-types, firmware has to be loaded into the cards, before + proceeding with device-independant setup. See README. + for how to do that. b) If you only intend to use ttys, you are nearly ready now. @@ -437,8 +318,7 @@ h) additionally you may activate charge-hang-up (= Hang up before next charge-info, this only works, if your isdn-provider transmits - the charge-info during and after the connection, it does NOT work - with the Teles on an EDSS1-Line.): + the charge-info during and after the connection): isdnctrl chargehup isdn0 on i) Setup the interface with ifconfig as usual, and set a route to it. @@ -542,7 +422,7 @@ "isdnctrl l2_prot " Selects a layer-2-protocol. - (With the ICN-driver and the Teles-driver, "x75i" and "hdlc" is available. + (With the ICN-driver and the HiSax-driver, "x75i" and "hdlc" is available. With other drivers, "x75ui", "x75bui" may be possible too.) isdnctrl l3_prot diff -u --recursive --new-file v2.1.41/linux/Documentation/isdn/README.HiSax linux/Documentation/isdn/README.HiSax --- v2.1.41/linux/Documentation/isdn/README.HiSax Thu Feb 27 10:57:29 1997 +++ linux/Documentation/isdn/README.HiSax Wed May 28 10:49:07 1997 @@ -1,7 +1,7 @@ -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 +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 +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 @@ -19,37 +19,46 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -Supported Cards +Supported cards --------------- -Teles 8.0/16.0/16.3 and compatible +Teles 8.0/16.0/16.3 and compatible ones Teles S0/PCMCIA Creatix PnP S0 AVM A1 (Fritz) -ELSA Microlink PCC-16 PCF PCF-Pro PCC-8 +ELSA Microlink PCC-16, PCF, PCF-Pro, PCC-8 ELSA Quickstep 1000 +ELSA PCMCIA ITK ix1-micro Rev.2 -Note: PCF PCF-Pro only the ISDN part is supported yet - PCC-8 not tested yet +Note: PCF, PCF-Pro: up to now, only the ISDN part is supported + 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. +You can combine any card, if there is no conflict between the ressources +(io, mem, irq), with one exception: The ELSA PCMCIA cannot work with an other +non PCMCIA ELSA card at the same time. You cannot select ELSA ISA and ELSA +PCMCIA support at the same time during kernel config. -Configuring the Driver +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. +The HiSax driver can either be built directly into the kernel or as a module. +It 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. +There is also some config needed before you compile the kernel and/or +modules. It is enclose in the normal "make [menu]config" target at the +kernel. Don't forget it, especially to select the right D-channel protocol. -As Module ---------- +Please note: All PnP cards need to be configured with isapnp and will work +only with the HiSax driver used as a module. + +a) when built as a module +------------------------- insmod/modprobe hisax.o \ io=iobase irq=IRQ mem=membase type=card_type \ @@ -58,37 +67,38 @@ or, if several cards are installed: insmod/modprobe hisax.o \ - io=iobase1,iobase2,... mem=membase1,membase2,... \ + io=iobase1,iobase2,... irq=IRQ1,IRQ2,... 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 +where "iobaseN" represents the I/O base address of the Nth card, "membaseN" +the memory base address of the Nth card, etc. + +The reason for the delimiter "%" being used in the idstrings is that "," +won't work with the current modules package. + +The parameters may be specified in any order. For example, the "io" +parameter may precede the "irq" parameter, or vice versa. If several +cards are installed, the ordering within the comma separated parameter +lists must of course be consistent. + +Only parameters applicable to the card type need to be specified. For +example, the Teles 16.3 card is not memory-mapped, so the "mem" +parameter may be omitted for this card. Sometimes it may be 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: +is listed after a Teles 16.3 card, a dummy memory base parameter of 0 +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 parameter for the D-Channel protocol may be omitted if you selected the +correct one during kernel config. Valid values are "1" for German 1TR6, +"2" for EDSS1 (Euro ISDN) and "3" for leased lines (no D-Channel). + +The Creatix/Teles PnP cards use io1= and io2= instead of io= for specifying the I/O addresses of the ISAC and HSCX chips, respectively. Card types: @@ -101,14 +111,18 @@ 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 + required only if you have more than one ELSA card in your PC) 7 ELSA Quickstep 1000 irq, io (from isapnp setup) + 7 ELSA PCMCIA irq, io (set with card manager) 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. +Note: For using the ELSA PCMCIA you need the cardmanager under MSDOS for +enabling in the moment, then boot linux with loadlin. + Examples for module loading @@ -121,133 +135,143 @@ 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 +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 + modprobe hisax type=4 protocol=2 irq=10 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. + Please note the dummy 0 memory address for the Teles 16.3, used as a + placeholder as described above, in the last example. -7. Teles PCMCIA EURO 180 hex IRQ 15 (default values) +7. Teles PCMCIA, Euro ISDN, I/O base 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: +b) using LILO/LOADLIN, with the driver compiled directly 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! + typ1 = type of 1st card (default depends on kernel settings) + dp1 = D-Channel protocol of 1st card. 1=1TR6, 2=EDSS1, 3=leased + pa_1 = 1st parameter (depending on the type of the card) + pb_1 = 2nd parameter ( " " " " " " " ) + pc_1 = 3rd parameter ( " " " " " " " ) + + typ2,dp2,pa_2,pb_2,pc_2 = Parameters of the second card (defaults: none) + typn,dpn,pa_n,pb_n,pc_n = Parameters of the n'th card (up to 16 cards are + supported) + + idstring = Driver ID for accessing the particular card with utility + programs and for identification when using a line monitor + (default: "HiSax") + + Note: the ID string must start with an alphabetical character! Card types: - typ + type 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 ! + 4 Creatix/Teles PNP ONLY WORKS AS A 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 ! + 6 ELSA PCC/PCF cards pa=iobase or nothing for autodetect + 7 ELSA Quickstep 1000 ONLY WORKS AS A MODULE ! + 7 ELSA PCMCIA irq, io (set with card manager) 8 Teles S0 PCMCIA pa=irq pb=iobase 9 ITK ix1-micro Rev.2 pa=irq pb=iobase -Running -------- +Running the driver +------------------ -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: +When you insmod isdn.o and hisax.o (or with the in-kernel version, during +boot time), 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 +Apr 13 21:01:59 kke01 kernel: HiSax: Driver for Siemens chip set ISDN cards +Apr 13 21:01:59 kke01 kernel: HiSax: Version 2.1 +Apr 13 21:01:59 kke01 kernel: HiSax: Revisions 1.14/1.9/1.10/1.25/1.8 +Apr 13 21:01:59 kke01 kernel: HiSax: Total 1 card defined +Apr 13 21:01:59 kke01 kernel: HiSax: Card 1 Protocol EDSS1 Id=HiSax1 (0) +Apr 13 21:01:59 kke01 kernel: HiSax: Elsa driver Rev. 1.13 ... -Oct 13 20:46:41 kke01 kernel: Elsa: PCC16 found at 0x360 Rev.:B IRQ 9 +Apr 13 21:01:59 kke01 kernel: Elsa: PCF-Pro found at 0x360 Rev.:C IRQ 10 +Apr 13 21:01:59 kke01 kernel: Elsa: timer OK; resetting card +Apr 13 21:01:59 kke01 kernel: Elsa: HSCX version A: V2.1 B: V2.1 +Apr 13 21:01:59 kke01 kernel: Elsa: ISAC 2086/2186 V1.1 ... -Oct 13 20:46:41 kke01 kernel: HiSax: 2 channels available -Oct 13 20:46:41 kke01 kernel: HiSax: module installed +Apr 13 21:01:59 kke01 kernel: HiSax: DSS1 Rev. 1.14 +Apr 13 21:01:59 kke01 kernel: HiSax: 2 channels added This means that the card is ready for use. -Cabling problems or line downs are not detected, ELSA can detect the -S0 power. +Cabling problems or line-downs are not detected, and only ELSA cards 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 +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 command line. 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 +At 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 +DebugCmd is 1 for generic debugging + 11 for layer 1 development debugging + 13 for layer 3 development debugging where is the integer sum of the following debugging options you wish enabled: -With DebugCmd 1 is +With DebugCmd set to 1: - 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 + 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 debugging + 256 B-Channel link state debugging + 512 TEI debug 1024 LOCK debug in callc.c + 2048 More paranoid debug in callc.c (not for normal use) -With DebugCmd 11 is +With DebugCmd set to 11: - 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 + 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 +With DebugCmd set to 13: - 1 Warnings (default on) + 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. + 4 l3 state machine + 8 charge info debugging (1TR6) +For example, 'telesctrl HiSax 1 0x3ff' enables full generic debugging. Warning @@ -256,13 +280,16 @@ 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) +At this time, HiSax only works on Euro ISDN lines and German 1TR6 lines. + Bugs ---- -If you find any please let me know. +If you find any, please let me know. + Thanks ------ @@ -270,16 +297,16 @@ Emil Stephan for the name HiSax which is a mix of HSCX and ISAC. - Fritz Elfert, Jan den Ouden, Michael Hipp, Michael Wein, + 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), + 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 + 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 + My girl friend and partner in life Ute for her patience with me. Enjoy, @@ -287,57 +314,10 @@ 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 */ -} ------------------------------------------------------------------------- +Appendix: Teles PCMCIA driver +----------------------------- -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) +See + http://www.stud.uni-wuppertal.de/~ea0141/pcmcia.html +for instructions. diff -u --recursive --new-file v2.1.41/linux/Documentation/isdn/README.audio linux/Documentation/isdn/README.audio --- v2.1.41/linux/Documentation/isdn/README.audio Thu Feb 27 10:57:29 1997 +++ linux/Documentation/isdn/README.audio Wed May 28 10:49:08 1997 @@ -1,4 +1,4 @@ -$Id: README.audio,v 1.4 1997/02/03 23:43:47 fritz Exp $ +$Id: README.audio,v 1.5 1997/02/23 23:53:46 fritz Exp $ ISDN subsystem for Linux. Description of audio mode. @@ -12,7 +12,7 @@ AT+FCLASS=8 Enable audio mode. This affects the following registers: - S18: Bits 0 and 3 are set. + S18: Bits 0 and 2 are set. S16: Set to 48 and any further change to larger values is blocked. AT+FCLASS=0 Disable audio mode. diff -u --recursive --new-file v2.1.41/linux/Documentation/isdn/README.avmb1 linux/Documentation/isdn/README.avmb1 --- v2.1.41/linux/Documentation/isdn/README.avmb1 Wed Dec 31 16:00:00 1969 +++ linux/Documentation/isdn/README.avmb1 Wed May 28 10:49:08 1997 @@ -0,0 +1,62 @@ +The driver provides a kernel capi2.0 Interface (kernelcapi) and +on top of this a User-Level-CAPI2.0-interface (capi) +and a driver to connect isdn4linux with CAPI2.0 (capidrv). + +The Author can be reached at calle@calle.in-berlin.de +The command avmcapictrl is part of the isdn4linux-utils. +t4-files can be found at ftp.avm.de. + +Installing +---------- + +You need at least /dev/capi20 to load the firmware. + +mknod /dev/capi20 c 68 0 +mknod /dev/capi20.00 c 68 1 +mknod /dev/capi20.01 c 68 2 +. +. +. +mknod /dev/capi20.19 c 68 20 + +Running +------- + +To use the card you need the t4-files to download the firmware. +AVM GmbH provides several t4-files for the different D-channel +protocols (b1.t4 for Euro-ISDN). Install these file in /lib/isdn. + +If you not compile the driver as modules, you have to add the +card(s) and load them after booting: + +avmcapictrl add 0x150 15 +avmcapictrl load /lib/isdn/b1.t4 1 + +if you configure as modules you have two possibilities: + +insmod /lib/modules/current/misc/capiutil.o +insmod /lib/modules/current/misc/kernelcapi.o portbase=0x150 irq=15 +insmod /lib/modules/current/misc/capidrv.o +insmod /lib/modules/current/misc/capi.o +avmcapictrl load /lib/isdn/b1.t4 + +or + +insmod /lib/modules/current/misc/capiutil.o +insmod /lib/modules/current/misc/kernelcapi.o +insmod /lib/modules/current/misc/capidrv.o +insmod /lib/modules/current/misc/capi.o +avmcapictrl add 0x150 15 +avmcapictrl load /lib/isdn/b1.t4 + +Questions +--------- +Check out the FAQ (ftp.franken.de). + +Bugs +---- +If you find any please let me know. + +Enjoy, + +Carsten Paeth (calle@calle.in-berlin.de) diff -u --recursive --new-file v2.1.41/linux/Documentation/isdn/README.icn linux/Documentation/isdn/README.icn --- v2.1.41/linux/Documentation/isdn/README.icn Fri Jun 7 06:02:39 1996 +++ linux/Documentation/isdn/README.icn Wed May 28 10:49:08 1997 @@ -1,9 +1,9 @@ -$Id: README.icn,v 1.4 1996/06/03 19:57:07 fritz Exp $ +$Id: README.icn,v 1.5 1997/04/23 18:55:55 fritz Exp $ You can get the ICN-ISDN-card from: Thinking Objects Software GmbH -Obere Heerbergstr. 17 +Versbacher Röthe 159 97078 Würzburg Tel: +49 931 2877950 Fax: +49 931 2877951 @@ -61,4 +61,88 @@ 1 1 0 1 0x358 1 1 1 0 0x368 1 1 1 1 NOT ALLOWED! + +The ICN driver either may be build into kernel or as a module. Initialization +depends on how the drive is built: + +Driver built into the kernel: + + The ICN driver can be configured using the commandline-feature while + loading the kernel with LILO or LOADLIN. It accepts the following syntax: + + icn=p,m[,idstring1[,idstring2]] + + where + + p = portbase (default: 0x320) + m = shared memory (default: 0xd0000) + + When using the ICN double card (4B), you MUST define TWO idstrings. + idstring must start with a character! There is no way for the driver + to distinguish between a 2B and 4B type card. Therefore, by supplying + TWO idstrings, you tell the driver that you have a 4B installed. + + If you like to use more than one card, you can use the program + "icnctrl" from the utility-package to configure additional cards. + You need to configure shared memory only once, since the icn-driver + maps all cards into the same address-space. + + Using the "icnctrl"-utility, portbase and shared memory can also be + changed during runtime. + + The D-channel protocol is configured by loading different firmware + into the card's memory using the "icnctrl"-utility. + + +Driver built as module: + + The module icn.o can be configured during "insmod'ing" it by + appending its parameters to the insmod-commandline. The following + syntax is accepted: + + portbase=p membase=m icn_id=idstring [icn_id2=idstring2] + + where p, m, idstring1 and idstring2 have the same meanings like + parameters described for the kernel-version above. + + When using the ICN double card (4B), you MUST define TWO idstrings. + idstring must start with a character! There is no way for the driver + to distinguish between a 2B and 4B type card. Therefore, by supplying + TWO idstrings, you tell the driver that you have a 4B installed. + + Using the "icnctrl"-utility, the same features apply to the modularized + version like to the kernel-builtin one. + + The D-channel protocol is configured by loading different firmware + into the card's memory using the "icnctrl"-utility. + +Loading the firmware into the card: + + The firmware is supplied together with the isdn4k-utils package. It + can be found in the subdirectory icnctrl/firmware/ + + There are 3 files: + + loadpg.bin - Image of the bootstrap loader. + pc_1t_ca.bin - Image of firmware for german 1TR6 protocol. + pc_eu_ca.bin - Image if firmware for EDSS1 (Euro-ISDN) protocol. + + Assumed you have installed the utility-package correctly, the firmware + will be downloaded into the 2B-card using the following command: + + icnctrl -d Idstring load /etc/isdn/loadpg.bin /etc/isdn/pc_XX_ca.bin + + where XX is either "1t" or "eu", depending of the D-Channel protocol + used on your S0-bus and Idstring is the Name of the card, given during + insmod-time or (for kernel-builtin driver) on the kernel commandline. + + To load a 4B-card, the same command is used, except a second firmware + file is appended to the commandline of icnctrl. + + -> After dowloading firmware, the two LEDs at the back cover of the card + (ICN-4B: 4 LEDs) must be blinking intermittently now. If a connection + is up, the corresponding led is lit continuously. + + For further documentation (adding more ICN-cards), refer to the manpage + icnctrl.8 which is included in the isdn4k-utils package. diff -u --recursive --new-file v2.1.41/linux/Documentation/isdn/README.teles linux/Documentation/isdn/README.teles --- v2.1.41/linux/Documentation/isdn/README.teles Sat Jun 29 10:36:22 1996 +++ linux/Documentation/isdn/README.teles Wed Dec 31 16:00:00 1969 @@ -1,73 +0,0 @@ -This is my Linux hardware level driver for Teles compatible ISDN cards. It is -meant to be used with isdn4isdn4linux, an ISDN Link-level module for Linux written -by Fritz Elfert. - -Isdn4linux can be obtained from ftp.franken.de:/pub/isdn4linux. The most recent -Teles driver can be found on my homepage, http://www.xs4all.nl:/~jdo. - -Warning -------- -Teles4isdn4linux 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 ------------ -Teles4isdn4linux only works on Euro ISDN lines and german 1TR6-lines. - -For the B channel transparent (HDLC) protocol and X.75 have been implemented. - -Running -------- -When you insmod isdn.o and teles.o (or with the kernel-version, during boottime) -a few lines should appear in your syslog. Look for something like: - -Oct 11 16:53:30 jedi kernel: channels 2 -Oct 11 16:53:31 jedi kernel: Teles module installed - -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 teles_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. Debugging messages are enabled with the telesctrl tool: - - teles/telesctrl 1 - -where is the integer sum of the following debugging -options you wish enabled: - - 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 Lowlevel (irq and Layer1 stuff) - -For example 'teles/telesctrl MyTeles 1 63' enables full -debugging. - -Questions ---------- -Check out the FAQ (ftp.franken.de). - -Bugs ----- -If you find any please let me know. - -Thanks ------- -Special thanks to: - - Erik Bos,Beat Doebeli,Fritz Elfert, - Pauline Middelink,Paula de Nie, - Bernd Oerding,Stephan Seidl,Matthias Urlichs, - Rogier Wolff - - - -Enjoy, - -Jan den Ouden denouden@groovin.xs4all.nl - diff -u --recursive --new-file v2.1.41/linux/Makefile linux/Makefile --- v2.1.41/linux/Makefile Wed May 28 10:51:31 1997 +++ linux/Makefile Wed May 28 11:29:35 1997 @@ -1,8 +1,8 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 41 +SUBLEVEL = 42 -ARCH := $(shell uname -m | sed s/i.86/i386/ | sed s/sun4u/sparc64/) +ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) # # For SMP kernels, set this. We don't want to have this in the config file diff -u --recursive --new-file v2.1.41/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.1.41/linux/arch/alpha/kernel/entry.S Tue May 13 22:41:00 1997 +++ linux/arch/alpha/kernel/entry.S Wed May 28 10:49:08 1997 @@ -247,6 +247,7 @@ bis $10,$10,$16 /* get arg */ bic $30,$8,$8 /* get current */ jsr $26,($27) + ldgp $29,0($26) bis $0,$0,$16 jsr $26,sys_exit call_pal PAL_halt @@ -519,6 +520,7 @@ beq $4,1f ldq $27,0($5) 1: jsr $26,($27),do_entSys + ldgp $29,0($26) blt $0,syscall_error /* the call failed */ stq $0,0($30) stq $31,72($30) /* a3=0 => no error */ @@ -578,6 +580,7 @@ beq $1,1f ldq $27,0($2) 1: jsr $26,($27),do_entSys + ldgp $29,0($26) /* check return.. */ blt $0,strace_error /* the call failed */ diff -u --recursive --new-file v2.1.41/linux/arch/i386/boot/tools/build.c linux/arch/i386/boot/tools/build.c --- v2.1.41/linux/arch/i386/boot/tools/build.c Wed Apr 16 14:14:59 1997 +++ linux/arch/i386/boot/tools/build.c Wed May 28 10:49:08 1997 @@ -1,5 +1,5 @@ /* - * arch/i386/boot/tools/build.c + * $Id: build.c,v 1.5 1997/05/19 12:29:58 mj Exp $ * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1997 Martin Mares @@ -170,7 +170,8 @@ fprintf (stderr, "System is %d kB\n", sz/1024); sys_size = (sz + 15) / 16; if (sys_size > (is_big_kernel ? 0xffff : DEF_SYSSIZE)) - die("System is too big"); + die("System is too big. Try using %smodules.", + is_big_kernel ? "" : "bzImage or "); while (sz > 0) { int l, n; diff -u --recursive --new-file v2.1.41/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.1.41/linux/arch/i386/kernel/i386_ksyms.c Sat May 24 09:10:22 1997 +++ linux/arch/i386/kernel/i386_ksyms.c Wed May 28 11:24:39 1997 @@ -25,6 +25,7 @@ #endif /* platform dependent support */ +EXPORT_SYMBOL(x86); EXPORT_SYMBOL(EISA_bus); EXPORT_SYMBOL(MCA_bus); EXPORT_SYMBOL(wp_works_ok); diff -u --recursive --new-file v2.1.41/linux/arch/i386/kernel/sys_i386.c linux/arch/i386/kernel/sys_i386.c --- v2.1.41/linux/arch/i386/kernel/sys_i386.c Thu Feb 27 10:57:29 1997 +++ linux/arch/i386/kernel/sys_i386.c Wed May 28 11:02:55 1997 @@ -58,23 +58,24 @@ asmlinkage int old_mmap(struct mmap_arg_struct *arg) { - int error = -EFAULT; struct file * file = NULL; struct mmap_arg_struct a; - lock_kernel(); if (copy_from_user(&a, arg, sizeof(a))) - goto out; + return -EFAULT; if (!(a.flags & MAP_ANONYMOUS)) { - error = -EBADF; if (a.fd >= NR_OPEN || !(file = current->files->fd[a.fd])) - goto out; + return -EBADF; } a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset); -out: - unlock_kernel(); - return error; + { + unsigned long retval; + struct semaphore *sem = ¤t->mm->mmap_sem; + down(sem); + retval = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset); + up(sem); + return retval; + } } extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); diff -u --recursive --new-file v2.1.41/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- v2.1.41/linux/arch/i386/mm/fault.c Thu May 15 16:48:01 1997 +++ linux/arch/i386/mm/fault.c Wed May 28 11:02:55 1997 @@ -83,6 +83,10 @@ * bit 0 == 0 means no page found, 1 means protection fault * bit 1 == 0 means read, 1 means write * bit 2 == 0 means kernel, 1 means user-mode + * + * NOTE! This all needs to be SMP-safe. Happily, we're only really touching + * per-thread data that we can know is valid (except for the "mm" structure + * that is shared - which is protected by the mm->mmap_sem semaphore). */ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) { @@ -94,8 +98,6 @@ unsigned long fixup; int write; - lock_kernel(); - /* get the address */ __asm__("movl %%cr2,%0":"=r" (address)); down(&mm->mmap_sem); @@ -152,7 +154,7 @@ if (bit < 32) tsk->tss.screen_bitmap |= 1 << bit; } - goto out; + return; /* * Something tried to access memory that isn't in our memory map.. @@ -168,7 +170,7 @@ regs->eip, fixup); regs->eip = fixup; - goto out; + return; } if (error_code & 4) { @@ -176,7 +178,7 @@ tsk->tss.error_code = error_code; tsk->tss.trap_no = 14; force_sig(SIGSEGV, tsk); - goto out; + return; } /* * Oops. The kernel tried to access some bad page. We'll have to @@ -188,7 +190,7 @@ wp_works_ok = 1; pg0[0] = pte_val(mk_pte(0, PAGE_SHARED)); flush_tlb(); - goto out; + return; } if (address < PAGE_SIZE) { printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); @@ -209,6 +211,4 @@ } die_if_kernel("Oops", regs, error_code); do_exit(SIGKILL); -out: - unlock_kernel(); } diff -u --recursive --new-file v2.1.41/linux/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c --- v2.1.41/linux/arch/m68k/amiga/config.c Tue May 13 22:41:01 1997 +++ linux/arch/m68k/amiga/config.c Wed May 28 10:49:08 1997 @@ -12,7 +12,6 @@ * Miscellaneous Amiga stuff */ -#include #include #include #include diff -u --recursive --new-file v2.1.41/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c --- v2.1.41/linux/arch/sparc/kernel/setup.c Thu May 15 16:48:01 1997 +++ linux/arch/sparc/kernel/setup.c Wed May 28 10:49:08 1997 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.84 1997/05/08 17:45:16 davem Exp $ +/* $Id: setup.c,v 1.85 1997/05/27 06:45:54 davem Exp $ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -79,7 +79,6 @@ void prom_sync_me(void) { unsigned long prom_tbr, flags; - int cpu = smp_processor_id(); #ifdef __SMP__ global_irq_holder = NO_PROC_ID; diff -u --recursive --new-file v2.1.41/linux/arch/sparc/lib/blockops.S linux/arch/sparc/lib/blockops.S --- v2.1.41/linux/arch/sparc/lib/blockops.S Thu May 15 16:48:01 1997 +++ linux/arch/sparc/lib/blockops.S Wed May 28 10:49:08 1997 @@ -1,4 +1,4 @@ -/* $Id: blockops.S,v 1.6 1997/05/03 02:01:54 davem Exp $ +/* $Id: blockops.S,v 1.7 1997/05/20 07:58:28 jj Exp $ * blockops.S: Common block zero optimized routines. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -45,8 +45,11 @@ .text .align 4 + .globl C_LABEL(bzero_1page), C_LABEL(__copy_1page) -generic_bzero_1page: +C_LABEL(bzero_1page): +/* NOTE: If you change the number of insns of this routine, please check + * arch/sparc/mm/hypersparc.S */ /* %o0 = buf */ or %g0, %g0, %g1 or %o0, %g0, %o1 @@ -63,7 +66,9 @@ retl nop -__generic_copy_1page: +C_LABEL(__copy_1page): +/* NOTE: If you change the number of insns of this routine, please check + * arch/sparc/mm/hypersparc.S */ /* %o0 = dst, %o1 = src */ or %g0, 0x10, %g1 1: @@ -82,9 +87,3 @@ retl nop - - .data - .align 4 - .globl C_LABEL(bzero_1page), C_LABEL(__copy_1page) -C_LABEL(bzero_1page): .word generic_bzero_1page -C_LABEL(__copy_1page): .word __generic_copy_1page diff -u --recursive --new-file v2.1.41/linux/arch/sparc/mm/hypersparc.S linux/arch/sparc/mm/hypersparc.S --- v2.1.41/linux/arch/sparc/mm/hypersparc.S Thu May 15 16:48:02 1997 +++ linux/arch/sparc/mm/hypersparc.S Wed May 28 10:49:08 1997 @@ -1,4 +1,4 @@ -/* $Id: hypersparc.S,v 1.7 1997/05/03 05:09:12 davem Exp $ +/* $Id: hypersparc.S,v 1.10 1997/05/27 19:29:58 jj Exp $ * hypersparc.S: High speed Hypersparc mmu/cache operations. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -9,6 +9,7 @@ #include #include #include +#include #define WINDOW_FLUSH(tmp1, tmp2) \ mov 0, tmp1; \ @@ -335,17 +336,19 @@ retl sta %g5, [%g1] ASI_M_MMUREGS + __INIT + /* High speed page clear/copy. */ - .globl hypersparc_bzero_1page, hypersparc_copy_1page hypersparc_bzero_1page: +/* NOTE: This routine has to be shorter than 40insns --jj */ clr %g1 mov 32, %g2 - add %g2, %g2, %g3 - add %g2, %g3, %g4 - add %g2, %g4, %g5 - add %g2, %g5, %g7 - add %g2, %g7, %o2 - add %g2, %o2, %o3 + mov 64, %g3 + mov 96, %g4 + mov 128, %g5 + mov 160, %g7 + mov 192, %o2 + mov 224, %o3 mov 16, %o1 1: stda %g0, [%o0 + %g0] ASI_M_BFILL @@ -364,6 +367,7 @@ nop hypersparc_copy_1page: +/* NOTE: This routine has to be shorter than 70insns --jj */ sub %o1, %o0, %o2 ! difference mov 16, %g1 1: @@ -386,5 +390,37 @@ bne 1b add %o0, 32, %o0 + retl + nop + + .globl hypersparc_setup_blockops +hypersparc_setup_blockops: + sethi %hi(bzero_1page), %o0 + or %o0, %lo(bzero_1page), %o0 + sethi %hi(hypersparc_bzero_1page), %o1 + or %o1, %lo(hypersparc_bzero_1page), %o1 + sethi %hi(hypersparc_copy_1page), %o2 + or %o2, %lo(hypersparc_copy_1page), %o2 + ld [%o1], %o4 +1: + add %o1, 4, %o1 + st %o4, [%o0] + add %o0, 4, %o0 + cmp %o1, %o2 + bne 1b + ld [%o1], %o4 + sethi %hi(__copy_1page), %o0 + or %o0, %lo(__copy_1page), %o0 + sethi %hi(hypersparc_setup_blockops), %o2 + or %o2, %lo(hypersparc_setup_blockops), %o2 + ld [%o1], %o4 +1: + add %o1, 4, %o1 + st %o4, [%o0] + add %o0, 4, %o0 + cmp %o1, %o2 + bne 1b + ld [%o1], %o4 + sta %g0, [%g0] ASI_M_FLUSH_IWHOLE retl nop diff -u --recursive --new-file v2.1.41/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v2.1.41/linux/arch/sparc/mm/srmmu.c Sat May 24 09:10:23 1997 +++ linux/arch/sparc/mm/srmmu.c Wed May 28 10:49:08 1997 @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.146 1997/05/18 21:11:09 davem Exp $ +/* $Id: srmmu.c,v 1.147 1997/05/20 07:58:42 jj Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1239,8 +1239,7 @@ extern void hypersparc_flush_tlb_mm(struct mm_struct *mm); extern void hypersparc_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end); extern void hypersparc_flush_tlb_page(struct vm_area_struct *vma, unsigned long page); -extern void hypersparc_bzero_1page(void *); -extern void hypersparc_copy_1page(void *, const void *); +extern void hypersparc_setup_blockops(void); static void srmmu_set_pte_nocache_hyper(pte_t *ptep, pte_t pteval) { @@ -2411,13 +2410,7 @@ sparc_update_rootmmu_dir = hypersparc_update_rootmmu_dir; poke_srmmu = poke_hypersparc; - /* High performance page copy/clear. */ - { extern void (*__copy_1page)(void *, const void *); - extern void (*bzero_1page)(void *); - - __copy_1page = hypersparc_copy_1page; - bzero_1page = hypersparc_bzero_1page; - } + hypersparc_setup_blockops(); } static void poke_cypress(void) diff -u --recursive --new-file v2.1.41/linux/arch/sparc/prom/memory.c linux/arch/sparc/prom/memory.c --- v2.1.41/linux/arch/sparc/prom/memory.c Thu Mar 27 14:40:00 1997 +++ linux/arch/sparc/prom/memory.c Wed May 28 10:49:08 1997 @@ -1,4 +1,4 @@ -/* $Id: memory.c,v 1.10 1997/03/18 17:58:27 jj Exp $ +/* $Id: memory.c,v 1.12 1997/05/27 06:45:57 davem Exp $ * memory.c: Prom routine for acquiring various bits of information * about RAM on the machine, both virtual and physical. * @@ -116,7 +116,7 @@ num_regs = (num_regs/sizeof(struct linux_prom_registers)); for(iter=0; iter #include +/* define SYSCALL_TRACING */ + #define curptr g6 #define NR_SYSCALLS 256 /* Each OS is different... */ @@ -52,6 +54,11 @@ b,a,pt %xcc, 1f sparc64_dtlb_refbit_catch: + srlx %g5, 9, %g4 + and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4 + cmp %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9) + be,a,pt %xcc, 2f + mov 1, %g4 wr %g0, ASI_DMMU, %asi rdpr %pstate, %g1 wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate @@ -75,6 +82,11 @@ ba,a,pt %xcc, rtrap sparc64_itlb_refbit_catch: + srlx %g5, 9, %g4 + and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4 + cmp %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9) + be,a,pt %xcc, 3f + mov 1, %g4 rdpr %pstate, %g1 wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate ba,pt %xcc, etrap @@ -89,6 +101,22 @@ add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr ba,a,pt %xcc, rtrap +2: + sllx %g4, 63, %g4 ! _PAGE_VALID + or %g5, _PAGE_ACCESSED, %g5 + or %g5, %g4, %g5 + stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE + stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load + retry + +3: + sllx %g4, 63, %g4 ! _PAGE_VALID + or %g5, _PAGE_ACCESSED, %g5 + or %g5, %g4, %g5 + stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE + stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load + retry + /* Note check out head.h, this code isn't even used for UP, * for SMP things will be different. In particular the data * registers for cross calls will be: @@ -161,6 +189,7 @@ .globl sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall .globl sys_sigsuspend, sys_sigreturn + .globl sys32_execve, sys_ptrace sys_pipe: sethi %hi(sparc_pipe), %g1 @@ -180,6 +209,12 @@ jmpl %g1 + %lo(sparc_execve), %g0 add %sp, STACK_BIAS + REGWIN_SZ, %o0 +sys32_execve: + sethi %hi(sparc32_execve), %g1 + add %g1, %g4, %g1 + jmpl %g1 + %lo(sparc32_execve), %g0 + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + sys_sigpause: /* NOTE: %o0 has a correct value already */ call do_sigpause @@ -199,7 +234,7 @@ ld [%curptr + AOFF_task_flags], %l5 andcc %l5, 0x20, %g0 - be,pt %icc, ret_sys_call + be,pt %icc, rtrap nop call syscall_trace nop @@ -211,13 +246,25 @@ ld [%curptr + AOFF_task_flags], %l5 andcc %l5, 0x20, %g0 - be,pt %icc, ret_sys_call + be,pt %icc, rtrap nop call syscall_trace nop ba,a,pt %xcc, rtrap - /* This is how fork() was meant to be done, 11 instruction entry. -DaveM */ +sys_ptrace: + call do_ptrace + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + + ld [%curptr + AOFF_task_flags], %l5 + andcc %l5, 0x20, %g0 + be,pt %icc, rtrap + nop + call syscall_trace + nop + ba,a,pt %xcc, rtrap + + /* This is how fork() was meant to be done, 10 instruction entry. -DaveM */ .globl sys_fork, sys_vfork, sys_clone sys_fork: sys_vfork: @@ -228,13 +275,12 @@ flushw rdpr %cwp, %o4 add %sp, STACK_BIAS + REGWIN_SZ, %o2 - brz,a %o1, 1f - mov %fp, %o1 -1: + movrz %o1, %fp, %o1 + /* Don't try this at home. */ stx %o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0] call do_fork - add %l5, 8, %o7 + mov %l5, %o7 linux_sparc_ni_syscall: sethi %hi(sys_ni_syscall), %l7 @@ -281,6 +327,11 @@ .globl syscall_is_too_hard syscall_is_too_hard: +#ifdef SYSCALL_TRACING /* Debugging... */ + mov %g1, %o0 ! o0=scall, o1=ptregs + call syscall_trace_entry + add %sp, STACK_BIAS + REGWIN_SZ, %o1 +#endif mov %i0, %o0 mov %i1, %o1 mov %i2, %o2 @@ -295,13 +346,12 @@ call %l7 mov %i5, %o5 - stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] -#if 0 - /* Debugging... */ - call syscall_trace_exit - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0 +#ifdef SYSCALL_TRACING /* Debugging... */ + call syscall_trace_exit ! o0=sysret, o1=ptregs + add %sp, STACK_BIAS + REGWIN_SZ, %o1 #endif + stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] + .globl ret_sys_call ret_sys_call: ldx [%curptr + AOFF_task_flags], %l6 diff -u --recursive --new-file v2.1.41/linux/arch/sparc64/kernel/etrap.S linux/arch/sparc64/kernel/etrap.S --- v2.1.41/linux/arch/sparc64/kernel/etrap.S Sat May 24 09:10:23 1997 +++ linux/arch/sparc64/kernel/etrap.S Wed May 28 10:49:08 1997 @@ -1,4 +1,4 @@ -/* $Id: etrap.S,v 1.17 1997/05/18 22:52:09 davem Exp $ +/* $Id: etrap.S,v 1.18 1997/05/19 05:58:51 davem Exp $ * etrap.S: Preparing for entry into the kernel on Sparc V9. * * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -29,59 +29,39 @@ rdpr %tstate, %g1 sllx %g2, 20, %g2 or %g1, %g2, %g1 - - /* What happens more often? etrap when already in priv or from userland? */ andcc %g1, TSTATE_PRIV, %g0 bne,a,pn %xcc, 1f sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 + rd %pic, %g3 - /* Just when going from userland to privileged mode, - * we have to change this stuff. - * - * Setup to run in NUCLEUS context, stash user context in - * secondary for later trap return. Note we must not change - * trap level until PRIMARY_CONTEXT is set to zero, else - * we fall out of NUCLEUS too soon and crash hard. - */ - mov PRIMARY_CONTEXT, %g1 - ldxa [%g1] ASI_DMMU, %g2 - stxa %g0, [%g1] ASI_DMMU - - mov SECONDARY_CONTEXT, %g1 - stxa %g2, [%g1] ASI_DMMU - - rd %pic, %g1 sethi %hi((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ), %g2 or %g2, %lo((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ), %g2 - add %g1, %g2, %g2 - rdpr %tstate, %g1 -1: - stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE] + add %g3, %g2, %g2 +1: stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE] rdpr %tpc, %g1 rdpr %tnpc, %g3 stx %g1, [%g2 + REGWIN_SZ + PT_V9_TPC] rd %y, %g1 + stx %g3, [%g2 + REGWIN_SZ + PT_V9_TNPC] stx %g1, [%g2 + REGWIN_SZ + PT_V9_Y] - - wrpr %g0, 0x0, %tl rdpr %pstate, %g1 save %g2, -STACK_BIAS, %sp - - /* Must guarentee that here andcc of TSTATE_PRIV at the top is - * still valid in %ccr register. Don't show this trick to your - * mom. -DaveM - */ bne,pn %xcc, 1f rdpr %canrestore, %g3 + rdpr %wstate, %g6 wrpr %g0, 0, %canrestore - wrpr %g3, 0, %otherwin - rdpr %wstate, %g6 sll %g6, 3, %g6 + wrpr %g3, 0, %otherwin wrpr %g6, %wstate - + sethi %uhi(KERNBASE), %g3 + sllx %g3, 32, %g3 + mov PRIMARY_CONTEXT, %g2 + stxa %g0, [%g2] ASI_DMMU + flush %g3 1: + wrpr %g0, 0x0, %tl mov %g1, %l1 mov %g4, %l4 mov %g5, %l5 @@ -89,6 +69,7 @@ wrpr %l1, PSTATE_AG, %pstate stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1] stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2] + stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3] stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4] stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5] @@ -97,19 +78,24 @@ stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2] + stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3] stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4] stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5] stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6] stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7] wrpr %l1, (PSTATE_IE | PSTATE_AG), %pstate - srlx %sp, 43, %g4 + sethi %uhi(KERNBASE), %g4 rd %pic, %g6 + jmpl %l2 + 0x4, %g0 - sllx %g4, 43, %g4 + sllx %g4, 32, %g4 .globl etraptl1 etraptl1: rdpr %tstate, %g1 ba,pt %xcc, 1b sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 + nop + nop + nop diff -u --recursive --new-file v2.1.41/linux/arch/sparc64/kernel/hack.S linux/arch/sparc64/kernel/hack.S --- v2.1.41/linux/arch/sparc64/kernel/hack.S Sat May 24 09:10:23 1997 +++ linux/arch/sparc64/kernel/hack.S Wed May 28 10:49:08 1997 @@ -10,28 +10,16 @@ do_cee: retl;nop .globl do_cee_tl1 do_cee_tl1: retl;nop - .globl do_dae -do_dae: retl;nop .globl do_dae_tl1 do_dae_tl1: retl;nop - .globl do_div0 -do_div0: retl;nop .globl do_div0_tl1 do_div0_tl1: retl;nop - .globl do_fpdis -do_fpdis: retl;nop .globl do_fpdis_tl1 do_fpdis_tl1: retl;nop - .globl do_fpieee -do_fpieee: retl;nop .globl do_fpieee_tl1 do_fpieee_tl1: retl;nop - .globl do_fpother -do_fpother: retl;nop .globl do_fpother_tl1 do_fpother_tl1: retl;nop - .globl do_iae -do_iae: retl;nop .globl do_iae_tl1 do_iae_tl1: retl;nop .globl do_ill_tl1 @@ -50,16 +38,10 @@ do_paw: retl;nop .globl do_paw_tl1 do_paw_tl1: retl;nop - .globl do_privact -do_privact: retl;nop - .globl do_privop -do_privop: retl;nop .globl do_stdfmna do_stdfmna: retl;nop .globl do_stdfmna_tl1 do_stdfmna_tl1: retl;nop - .globl do_tof -do_tof: retl;nop .globl do_tof_tl1 do_tof_tl1: retl;nop .globl do_vaw @@ -190,9 +172,3 @@ sunos_write: retl;nop .globl sunos_writev sunos_writev: retl;nop - .globl sys_ptrace -sys_ptrace: retl;nop - .globl syscall_trace -syscall_trace: retl;nop - .globl sys32_ptrace -sys32_ptrace: retl;nop diff -u --recursive --new-file v2.1.41/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.1.41/linux/arch/sparc64/kernel/ioctl32.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/ioctl32.c Wed May 28 10:49:08 1997 @@ -0,0 +1,50 @@ +/* $Id: ioctl32.c,v 1.3 1997/05/27 19:30:13 jj Exp $ + * ioctl32.c: Conversion between 32bit and 64bit native ioctls. + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * + * These routines maintain argument size conversion between 32bit and 64bit + * ioctls. + */ + +#include +#include +#include +#include +#include + +#include +#include + +/* As gcc will warn about casting u32 to some ptr, we have to cast it to unsigned long first, and that's what is A() for. + * You just do (void *)A(x), instead of having to type (void *)((unsigned long)x) or instead of just (void *)x, which will + * produce warnings */ +#define A(x) ((unsigned long)x) + +extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); + +asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) +{ + struct file * filp; + int error = -EBADF; + + lock_kernel(); + if (fd >= NR_OPEN || !(filp = current->files->fd[fd])) + goto out; + if (!filp->f_op || !filp->f_op->ioctl) { + error = sys_ioctl (fd, cmd, (unsigned long)arg); + goto out; + } + error = 0; + switch (cmd) { + default: + error = sys_ioctl (fd, cmd, (unsigned long)arg); + goto out; + } +out: + if (error == -EINVAL) { + printk ("sys32_ioctl on %016lx's %08x returns EINVAL\n", filp->f_op ? (long)filp->f_op->ioctl : 0UL, cmd); + } + unlock_kernel(); + return error; +} diff -u --recursive --new-file v2.1.41/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c --- v2.1.41/linux/arch/sparc64/kernel/irq.c Wed Apr 23 19:01:16 1997 +++ linux/arch/sparc64/kernel/irq.c Wed May 28 10:49:08 1997 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.12 1997/04/16 05:56:20 davem Exp $ +/* $Id: irq.c,v 1.13 1997/05/27 07:54:28 davem Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -382,15 +382,15 @@ /* Per-processor IRQ locking depth, both SMP and non-SMP code use this. */ unsigned int local_irq_count[NR_CPUS]; -atomic_t __sparc64_bh_counter = ATOMIC_INIT(0); -#ifdef __SMP__ -#error SMP not supported on sparc64 just yet -#else +#ifndef __SMP__ +int __sparc64_bh_counter = 0; #define irq_enter(cpu, irq) (local_irq_count[cpu]++) #define irq_exit(cpu, irq) (local_irq_count[cpu]--) +#else +#error SMP not supported on sparc64 just yet #endif /* __SMP__ */ void report_spurious_ivec(struct pt_regs *regs) diff -u --recursive --new-file v2.1.41/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c --- v2.1.41/linux/arch/sparc64/kernel/process.c Sat May 24 09:10:23 1997 +++ linux/arch/sparc64/kernel/process.c Wed May 28 10:49:08 1997 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.11 1997/05/18 22:52:19 davem Exp $ +/* $Id: process.c,v 1.12 1997/05/23 09:35:43 jj Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) @@ -355,6 +355,7 @@ get_mmu_context(current); } current->tss.current_ds = USER_DS; + spitfire_set_secondary_context (current->mm->context); } static __inline__ void copy_regs(struct pt_regs *dst, struct pt_regs *src) diff -u --recursive --new-file v2.1.41/linux/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c --- v2.1.41/linux/arch/sparc64/kernel/ptrace.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/ptrace.c Wed May 28 10:49:08 1997 @@ -0,0 +1,1028 @@ +/* ptrace.c: Sparc process tracing support. + * + * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * + * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson, + * and David Mosberger. + * + * Added Linux support -miguel (wierd, eh?, the orignal code was meant + * to emulate SunOS). + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MAGIC_CONSTANT 0x80000000 + +/* + * This routine gets a long from any process space by following the page + * tables. NOTE! You should check that the long isn't on a page boundary, + * and that it is in the task area before calling this: this routine does + * no checking. + */ +static pte_t *get_page(struct task_struct * tsk, + struct vm_area_struct * vma, unsigned long addr, int write) +{ + pgd_t * pgdir; + pmd_t * pgmiddle; + pte_t * pgtable; + +repeat: + pgdir = pgd_offset(vma->vm_mm, addr); + if (pgd_none(*pgdir)) { + handle_mm_fault(tsk, vma, addr, write); + goto repeat; + } + if (pgd_bad(*pgdir)) { + printk("ptrace: bad page directory %016lx\n", pgd_val(*pgdir)); + pgd_clear(pgdir); + return 0; + } + pgmiddle = pmd_offset(pgdir, addr); + if (pmd_none(*pgmiddle)) { + handle_mm_fault(tsk, vma, addr, write); + goto repeat; + } + if (pmd_bad(*pgmiddle)) { + printk("ptrace: bad page middle %016lx\n", pmd_val(*pgmiddle)); + pmd_clear(pgmiddle); + return 0; + } + pgtable = pte_offset(pgmiddle, addr); + if (!pte_present(*pgtable)) { + handle_mm_fault(tsk, vma, addr, write); + goto repeat; + } + if (write && !pte_write(*pgtable)) { + handle_mm_fault(tsk, vma, addr, write); + goto repeat; + } + return pgtable; +} + +static inline unsigned long get_long(struct task_struct * tsk, + struct vm_area_struct * vma, unsigned long addr) +{ + pte_t * pgtable; + unsigned long page, retval; + + if (!(pgtable = get_page (tsk, vma, addr, 0))) return 0; + page = pte_page(*pgtable); +/* this is a hack for non-kernel-mapped video buffers and similar */ + if (MAP_NR(page) >= max_mapnr) + return 0; + page += addr & ~PAGE_MASK; + retval = *(unsigned long *) page; + flush_page_to_ram(page); + return retval; +} + +static inline void put_long(struct task_struct * tsk, struct vm_area_struct * vma, + unsigned long addr, unsigned long data) +{ + pte_t *pgtable; + unsigned long page; + + if (!(pgtable = get_page (tsk, vma, addr, 1))) return; + page = pte_page(*pgtable); +/* this is a hack for non-kernel-mapped video buffers and similar */ + flush_cache_page(vma, addr); + if (MAP_NR(page) < max_mapnr) { + *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data; + flush_page_to_ram(page); + } +/* we're bypassing pagetables, so we have to set the dirty bit ourselves */ +/* this should also re-instate whatever read-only mode there was before */ + set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); + flush_tlb_page(vma, addr); +} + +static inline unsigned int get_int(struct task_struct * tsk, + struct vm_area_struct * vma, unsigned long addr) +{ + pte_t * pgtable; + unsigned long page; + unsigned int retval; + + if (!(pgtable = get_page (tsk, vma, addr, 0))) return 0; + page = pte_page(*pgtable); +/* this is a hack for non-kernel-mapped video buffers and similar */ + if (MAP_NR(page) >= max_mapnr) + return 0; + page += addr & ~PAGE_MASK; + retval = *(unsigned int *) page; + flush_page_to_ram(page); + return retval; +} + +static inline void put_int(struct task_struct * tsk, struct vm_area_struct * vma, + unsigned long addr, unsigned int data) +{ + pte_t *pgtable; + unsigned long page; + + if (!(pgtable = get_page (tsk, vma, addr, 1))) return; + page = pte_page(*pgtable); +/* this is a hack for non-kernel-mapped video buffers and similar */ + flush_cache_page(vma, addr); + if (MAP_NR(page) < max_mapnr) { + *(unsigned int *) (page + (addr & ~PAGE_MASK)) = data; + flush_page_to_ram(page); + } +/* we're bypassing pagetables, so we have to set the dirty bit ourselves */ +/* this should also re-instate whatever read-only mode there was before */ + set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); + flush_tlb_page(vma, addr); +} + +static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, + unsigned long addr) +{ + struct vm_area_struct * vma; + + addr &= PAGE_MASK; + vma = find_vma(tsk->mm,addr); + if (!vma) + return NULL; + if (vma->vm_start <= addr) + return vma; + if (!(vma->vm_flags & VM_GROWSDOWN)) + return NULL; + if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur) + return NULL; + vma->vm_offset -= vma->vm_start - addr; + vma->vm_start = addr; + return vma; +} + +/* + * This routine checks the page boundaries, and that the offset is + * within the task area. It then calls get_long() to read a long. + */ +static int read_long(struct task_struct * tsk, unsigned long addr, + unsigned long * result) +{ + struct vm_area_struct * vma = find_extend_vma(tsk, addr); + + if (!vma) + return -EIO; + *result = get_long(tsk, vma, addr); + return 0; +} + +/* + * This routine checks the page boundaries, and that the offset is + * within the task area. It then calls get_int() to read a int. + */ +static int read_int(struct task_struct * tsk, unsigned long addr, + unsigned int * result) +{ + struct vm_area_struct * vma = find_extend_vma(tsk, addr); + + if (!vma) + return -EIO; + *result = get_int(tsk, vma, addr); + return 0; +} + +/* + * This routine checks the page boundaries, and that the offset is + * within the task area. It then calls put_long() to write a long. + */ +static int write_long(struct task_struct * tsk, unsigned long addr, + unsigned long data) +{ + struct vm_area_struct * vma = find_extend_vma(tsk, addr); + + if (!vma) + return -EIO; + put_long(tsk, vma, addr, data); + return 0; +} + +/* + * This routine checks the page boundaries, and that the offset is + * within the task area. It then calls put_int() to write a int. + */ +static int write_int(struct task_struct * tsk, unsigned long addr, + unsigned int data) +{ + struct vm_area_struct * vma = find_extend_vma(tsk, addr); + + if (!vma) + return -EIO; + put_int(tsk, vma, addr, data); + return 0; +} + +/* Returning from ptrace is a bit tricky because the syscall return + * low level code assumes any value returned which is negative and + * is a valid errno will mean setting the condition codes to indicate + * an error return. This doesn't work, so we have this hook. + */ +static inline void pt_error_return(struct pt_regs *regs, unsigned long error) +{ + regs->u_regs[UREG_I0] = error; + regs->tstate |= (TSTATE_ICARRY | TSTATE_XCARRY); + regs->tpc = regs->tnpc; + regs->tnpc += 4; +} + +static inline void pt_succ_return(struct pt_regs *regs, unsigned long value) +{ + regs->u_regs[UREG_I0] = value; + regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY); + regs->tpc = regs->tnpc; + regs->tnpc += 4; +} + +static inline void +pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long *addr) +{ + if (current->tss.flags & SPARC_FLAG_32BIT) { + if(put_user(value, (unsigned int *)addr)) + return pt_error_return(regs, EFAULT); + } else { + if(put_user(value, addr)) + return pt_error_return(regs, EFAULT); + } + regs->u_regs[UREG_I0] = 0; + regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY); + regs->tpc = regs->tnpc; + regs->tnpc += 4; +} + +static void +pt_os_succ_return (struct pt_regs *regs, unsigned long val, long *addr) +{ + if (current->personality & PER_BSD) + pt_succ_return (regs, val); + else + pt_succ_return_linux (regs, val, addr); +} + +#if 0 +/* XXX: Implement this some day */ +/* Fuck me gently with a chainsaw... */ +static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset, + struct task_struct *tsk, long *addr) +{ + struct pt_regs *cregs = tsk->tss.kregs; + struct thread_struct *t = &tsk->tss; + int v; + + if(offset >= 1024) + offset -= 1024; /* whee... */ + if(offset & ((sizeof(unsigned int) - 1))) { + pt_error_return(regs, EIO); + return; + } + if(offset >= 16 && offset < 784) { + offset -= 16; offset >>= 2; + pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr); + return; + } + if(offset >= 784 && offset < 832) { + offset -= 784; offset >>= 2; + pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr); + return; + } + switch(offset) { + case 0: + v = t->ksp; + break; + case 4: + v = t->kpc; + break; + case 8: + v = t->kpsr; + break; + case 12: + v = t->uwinmask; + break; + case 832: + v = t->w_saved; + break; + case 896: + v = cregs->u_regs[UREG_I0]; + break; + case 900: + v = cregs->u_regs[UREG_I1]; + break; + case 904: + v = cregs->u_regs[UREG_I2]; + break; + case 908: + v = cregs->u_regs[UREG_I3]; + break; + case 912: + v = cregs->u_regs[UREG_I4]; + break; + case 916: + v = cregs->u_regs[UREG_I5]; + break; + case 920: + v = cregs->u_regs[UREG_I6]; + break; + case 924: + if(tsk->tss.flags & MAGIC_CONSTANT) + v = cregs->u_regs[UREG_G1]; + else + v = 0; + break; + case 940: + v = cregs->u_regs[UREG_I0]; + break; + case 944: + v = cregs->u_regs[UREG_I1]; + break; + + case 948: + /* Isn't binary compatibility _fun_??? */ + if(cregs->psr & PSR_C) + v = cregs->u_regs[UREG_I0] << 24; + else + v = 0; + break; + + /* Rest of them are completely unsupported. */ + default: + printk("%s [%d]: Wants to read user offset %ld\n", + current->comm, current->pid, offset); + pt_error_return(regs, EIO); + return; + } + pt_os_succ_return_linux (regs, v, addr); + return; +} + +static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset, + struct task_struct *tsk) +{ + struct pt_regs *cregs = tsk->tss.kregs; + struct thread_struct *t = &tsk->tss; + unsigned int value = regs->u_regs[UREG_I3]; + + if(offset >= 1024) + offset -= 1024; /* whee... */ + if(offset & ((sizeof(unsigned long) - 1))) + goto failure; + if(offset >= 16 && offset < 784) { + offset -= 16; offset >>= 2; + *(((unsigned long *)(&t->reg_window[0]))+offset) = value; + goto success; + } + if(offset >= 784 && offset < 832) { + offset -= 784; offset >>= 2; + *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value; + goto success; + } + switch(offset) { + case 896: + cregs->u_regs[UREG_I0] = value; + break; + case 900: + cregs->u_regs[UREG_I1] = value; + break; + case 904: + cregs->u_regs[UREG_I2] = value; + break; + case 908: + cregs->u_regs[UREG_I3] = value; + break; + case 912: + cregs->u_regs[UREG_I4] = value; + break; + case 916: + cregs->u_regs[UREG_I5] = value; + break; + case 920: + cregs->u_regs[UREG_I6] = value; + break; + case 924: + cregs->u_regs[UREG_I7] = value; + break; + case 940: + cregs->u_regs[UREG_I0] = value; + break; + case 944: + cregs->u_regs[UREG_I1] = value; + break; + + /* Rest of them are completely unsupported or "no-touch". */ + default: + printk("%s [%d]: Wants to write user offset %ld\n", + current->comm, current->pid, offset); + goto failure; + } +success: + pt_succ_return(regs, 0); + return; +failure: + pt_error_return(regs, EIO); + return; +} +#endif + +/* #define ALLOW_INIT_TRACING */ +/* #define DEBUG_PTRACE */ + +#ifdef DEBUG_PTRACE +char *pt_rq [] = { +"TRACEME", +"PEEKTEXT", +"PEEKDATA", +"PEEKUSR", +"POKETEXT", +"POKEDATA", +"POKEUSR", +"CONT", +"KILL", +"SINGLESTEP", +"SUNATTACH", +"SUNDETACH", +"GETREGS", +"SETREGS", +"GETFPREGS", +"SETFPREGS", +"READDATA", +"WRITEDATA", +"READTEXT", +"WRITETEXT", +"GETFPAREGS", +"SETFPAREGS", +"" +}; +#endif + +asmlinkage void do_ptrace(struct pt_regs *regs) +{ + int request = regs->u_regs[UREG_I0]; + pid_t pid = regs->u_regs[UREG_I1]; + unsigned long addr = regs->u_regs[UREG_I2]; + unsigned long data = regs->u_regs[UREG_I3]; + unsigned long addr2 = regs->u_regs[UREG_I4]; + struct task_struct *child; + + if (current->tss.flags & SPARC_FLAG_32BIT) { + addr &= 0xffffffffUL; + data &= 0xffffffffUL; + addr2 &= 0xffffffffUL; + } + lock_kernel(); +#ifdef DEBUG_PTRACE + { + char *s; + + if ((request > 0) && (request < 21)) + s = pt_rq [request]; + else + s = "unknown"; + + if (request == PTRACE_POKEDATA && data == 0x91d02001){ + printk ("do_ptrace: breakpoint pid=%d, addr=%016lx addr2=%016lx\n", + pid, addr, addr2); + } else + printk("do_ptrace: rq=%s(%d) pid=%d addr=%016lx data=%016lx addr2=%016lx\n", + s, request, pid, addr, data, addr2); + } +#endif + if(request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->flags & PF_PTRACED) { + pt_error_return(regs, EPERM); + goto out; + } + /* set the ptrace bit in the process flags. */ + current->flags |= PF_PTRACED; + pt_succ_return(regs, 0); + goto out; + } +#ifndef ALLOW_INIT_TRACING + if(pid == 1) { + /* Can't dork with init. */ + pt_error_return(regs, EPERM); + goto out; + } +#endif + if(!(child = find_task_by_pid(pid))) { + pt_error_return(regs, ESRCH); + goto out; + } + + if (((current->personality & PER_BSD) && (request == PTRACE_SUNATTACH)) + || (!(current->personality & PER_BSD) && (request == PTRACE_ATTACH))) { + if(child == current) { + /* Try this under SunOS/Solaris, bwa haha + * You'll never be able to kill the process. ;-) + */ + pt_error_return(regs, EPERM); + goto out; + } + if((!child->dumpable || + (current->uid != child->euid) || + (current->uid != child->uid) || + (current->gid != child->egid) || + (current->gid != child->gid)) && !suser()) { + pt_error_return(regs, EPERM); + goto out; + } + /* the same process cannot be attached many times */ + if (child->flags & PF_PTRACED) { + pt_error_return(regs, EPERM); + goto out; + } + child->flags |= PF_PTRACED; + if(child->p_pptr != current) { + REMOVE_LINKS(child); + child->p_pptr = current; + SET_LINKS(child); + } + send_sig(SIGSTOP, child, 1); + pt_succ_return(regs, 0); + goto out; + } + if (!(child->flags & PF_PTRACED) + && ((current->personality & PER_BSD) && (request != PTRACE_SUNATTACH)) + && (!(current->personality & PER_BSD) && (request != PTRACE_ATTACH))) { + pt_error_return(regs, ESRCH); + goto out; + } + if(child->state != TASK_STOPPED) { + if(request != PTRACE_KILL) { + pt_error_return(regs, ESRCH); + goto out; + } + } + if(child->p_pptr != current) { + pt_error_return(regs, ESRCH); + goto out; + } + switch(request) { + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + int res; + +#if 0 + /* XXX Find out what is really going on. */ + flush_cache_all(); +#endif + /* Non-word alignment _not_ allowed on Sparc. */ + if (current->tss.flags & SPARC_FLAG_32BIT) { + unsigned int x; + if(addr & (sizeof(unsigned int) - 1)) { + pt_error_return(regs, EINVAL); + goto out; + } + res = read_int(child, addr, &x); + tmp = x; + } else { + if(addr & (sizeof(unsigned long) - 1)) { + pt_error_return(regs, EINVAL); + goto out; + } + res = read_long(child, addr, &tmp); + } + if (res < 0) { + pt_error_return(regs, -res); + goto out; + } + pt_os_succ_return(regs, tmp, (long *) data); + goto out; + } + + case PTRACE_PEEKUSR: +#if 0 + read_sunos_user(regs, addr, child, (long *) data); +#endif + goto out; + + case PTRACE_POKEUSR: +#if 0 + write_sunos_user(regs, addr, child); +#endif + goto out; + + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: { + int res; + + /* Non-word alignment _not_ allowed on Sparc. */ + if (current->tss.flags & SPARC_FLAG_32BIT) { + if(addr & (sizeof(unsigned int) - 1)) { + pt_error_return(regs, EINVAL); + goto out; + } + res = write_int(child, addr, data); + } else { + if(addr & (sizeof(unsigned long) - 1)) { + pt_error_return(regs, EINVAL); + goto out; + } + res = write_long(child, addr, data); + } + if(res < 0) + pt_error_return(regs, -res); + else + pt_succ_return(regs, res); + goto out; + } + + case PTRACE_GETREGS: + if (current->tss.flags & SPARC_FLAG_32BIT) { + struct pt_regs32 *pregs = (struct pt_regs32 *) addr; + struct pt_regs *cregs = child->tss.kregs; + int rval; + + if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) || + __put_user(cregs->tpc, (&pregs->pc)) || + __put_user(cregs->tnpc, (&pregs->npc)) || + __put_user(cregs->y, (&pregs->y))) { + pt_error_return(regs, EFAULT); + goto out; + } + for(rval = 1; rval < 16; rval++) + if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) { + pt_error_return(regs, EFAULT); + goto out; + } + pt_succ_return(regs, 0); +#ifdef DEBUG_PTRACE + printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]); +#endif + goto out; + } else { + struct pt_regs *pregs = (struct pt_regs *) addr; + struct pt_regs *cregs = child->tss.kregs; + int rval; + + if (__put_user(cregs->tstate, (&pregs->tstate)) || + __put_user(cregs->tpc, (&pregs->tpc)) || + __put_user(cregs->tnpc, (&pregs->tnpc)) || + __put_user(cregs->y, (&pregs->y))) { + pt_error_return(regs, EFAULT); + goto out; + } + for(rval = 1; rval < 16; rval++) + if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) { + pt_error_return(regs, EFAULT); + goto out; + } + pt_succ_return(regs, 0); +#ifdef DEBUG_PTRACE + printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]); +#endif + goto out; + } + + case PTRACE_SETREGS: + if (current->tss.flags & SPARC_FLAG_32BIT) { + struct pt_regs32 *pregs = (struct pt_regs32 *) addr; + struct pt_regs *cregs = child->tss.kregs; + unsigned int psr, pc, npc, y; + int i; + + /* Must be careful, tracing process can only set certain + * bits in the psr. + */ + if (__get_user(psr, (&pregs->psr)) || + __get_user(pc, (&pregs->pc)) || + __get_user(npc, (&pregs->npc)) || + __get_user(y, (&pregs->y))) { + pt_error_return(regs, EFAULT); + goto out; + } + cregs->tstate &= ~(TSTATE_ICC); + cregs->tstate |= psr_to_tstate_icc(psr); + if(!((pc | npc) & 3)) { + cregs->tpc = pc; + cregs->tpc = npc; + } + cregs->y = y; + for(i = 1; i < 16; i++) + if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { + pt_error_return(regs, EFAULT); + goto out; + } + pt_succ_return(regs, 0); + goto out; + } else { + struct pt_regs *pregs = (struct pt_regs *) addr; + struct pt_regs *cregs = child->tss.kregs; + unsigned long tstate, tpc, tnpc, y; + int i; + + /* Must be careful, tracing process can only set certain + * bits in the psr. + */ + if (__get_user(tstate, (&pregs->tstate)) || + __get_user(tpc, (&pregs->tpc)) || + __get_user(tnpc, (&pregs->tnpc)) || + __get_user(y, (&pregs->y))) { + pt_error_return(regs, EFAULT); + goto out; + } + tstate &= (TSTATE_ICC | TSTATE_XCC); + cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); + cregs->tstate |= tstate; + if(!((tpc | tnpc) & 3)) { + cregs->tpc = tpc; + cregs->tnpc = tnpc; + } + cregs->y = y; + for(i = 1; i < 16; i++) + if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { + pt_error_return(regs, EFAULT); + goto out; + } + pt_succ_return(regs, 0); + goto out; + } + + case PTRACE_GETFPREGS: + if (current->tss.flags & SPARC_FLAG_32BIT) { + struct fps { + unsigned int regs[32]; + unsigned int fsr; + unsigned int flags; + unsigned int extra; + unsigned int fpqd; + struct fq { + unsigned int insnaddr; + unsigned int insn; + } fpq[16]; + } *fps = (struct fps *) addr; + + if (copy_to_user(&fps->regs[0], &child->tss.float_regs[0], (32 * sizeof(unsigned int))) || + __put_user(child->tss.fsr, (&fps->fsr)) || + __put_user(0, (&fps->fpqd)) || + __put_user(0, (&fps->flags)) || + __put_user(0, (&fps->extra)) || + clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) { + pt_error_return(regs, EFAULT); + goto out; + } + pt_succ_return(regs, 0); + goto out; + } else { + struct fps { + unsigned int regs[64]; + unsigned long fsr; + } *fps = (struct fps *) addr; + + if (copy_to_user(&fps->regs[0], &child->tss.float_regs[0], (64 * sizeof(unsigned int))) || + __put_user(child->tss.fsr, (&fps->fsr))) { + pt_error_return(regs, EFAULT); + goto out; + } + pt_succ_return(regs, 0); + goto out; + } + + case PTRACE_SETFPREGS: + if (current->tss.flags & SPARC_FLAG_32BIT) { + struct fps { + unsigned int regs[32]; + unsigned int fsr; + unsigned int flags; + unsigned int extra; + unsigned int fpqd; + struct fq { + unsigned int insnaddr; + unsigned int insn; + } fpq[16]; + } *fps = (struct fps *) addr; + unsigned fsr; + + if (copy_from_user(&child->tss.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned int))) || + __get_user(fsr, (&fps->fsr))) { + pt_error_return(regs, EFAULT); + goto out; + } + child->tss.fsr &= 0xffffffff00000000UL; + child->tss.fsr |= fsr; + pt_succ_return(regs, 0); + goto out; + } else { + struct fps { + unsigned int regs[64]; + unsigned long fsr; + } *fps = (struct fps *) addr; + + if (copy_from_user(&child->tss.float_regs[0], &fps->regs[0], (64 * sizeof(unsigned int))) || + __get_user(child->tss.fsr, (&fps->fsr))) { + pt_error_return(regs, EFAULT); + goto out; + } + pt_succ_return(regs, 0); + goto out; + } + + case PTRACE_READTEXT: + case PTRACE_READDATA: { + unsigned char *dest = (unsigned char *) addr2; + unsigned long src = addr; + int len = data, curlen; + struct vm_area_struct *vma; + pte_t *pgtable; + unsigned long page; + + while(len) { + vma = find_extend_vma(child, src); + if (!vma) { + pt_error_return(regs, EIO); + goto out; + } + pgtable = get_page (child, vma, src, 0); + if (src & ~PAGE_MASK) { + curlen = PAGE_SIZE - (src & ~PAGE_MASK); + if (curlen > len) curlen = len; + } else if (len > PAGE_SIZE) + curlen = PAGE_SIZE; + else + curlen = len; + if (pgtable && MAP_NR(page = pte_page(*pgtable)) < max_mapnr) { + if (copy_to_user (dest, ((char *)page) + (src & ~PAGE_MASK), curlen)) { + flush_page_to_ram(page); + pt_error_return(regs, EFAULT); + goto out; + } + flush_page_to_ram(page); + } else { + if (clear_user (dest, curlen)) { + pt_error_return(regs, EFAULT); + goto out; + } + } + src += curlen; + dest += curlen; + len -= curlen; + } + pt_succ_return(regs, 0); + goto out; + } + + case PTRACE_WRITETEXT: + case PTRACE_WRITEDATA: { + unsigned char *src = (unsigned char *) addr2; + unsigned long dest = addr; + int len = data, curlen; + struct vm_area_struct *vma; + pte_t *pgtable; + unsigned long page; + + while(len) { + vma = find_extend_vma(child, dest); + if (!vma) { + pt_error_return(regs, EIO); + goto out; + } + pgtable = get_page (child, vma, dest, 1); + if (dest & ~PAGE_MASK) { + curlen = PAGE_SIZE - (dest & ~PAGE_MASK); + if (curlen > len) curlen = len; + } else if (len > PAGE_SIZE) + curlen = PAGE_SIZE; + else + curlen = len; + if (pgtable && MAP_NR(page = pte_page(*pgtable)) < max_mapnr) { + flush_cache_page(vma, dest); + if (copy_from_user (((char *)page) + (dest & ~PAGE_MASK), src, curlen)) { + flush_page_to_ram(page); + set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); + flush_tlb_page(vma, dest); + pt_error_return(regs, EFAULT); + goto out; + } + flush_page_to_ram(page); + set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); + flush_tlb_page(vma, dest); + } + src += curlen; + dest += curlen; + len -= curlen; + } + pt_succ_return(regs, 0); + goto out; + } + + case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */ + addr = 1; + + case PTRACE_CONT: { /* restart after signal. */ + if (data > NSIG) { + pt_error_return(regs, EIO); + goto out; + } + if (addr != 1) { + if (addr & 3) { + pt_error_return(regs, EINVAL); + goto out; + } +#ifdef DEBUG_PTRACE + printk ("Original: %016lx %016lx\n", child->tss.kregs->tpc, child->tss.kregs->tnpc); + printk ("Continuing with %016lx %016lx\n", addr, addr+4); +#endif + child->tss.kregs->tpc = addr; + child->tss.kregs->tnpc = addr + 4; + } + + if (request == PTRACE_SYSCALL) + child->flags |= PF_TRACESYS; + else + child->flags &= ~PF_TRACESYS; + + child->exit_code = data; +#ifdef DEBUG_PTRACE + printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", child->comm, + child->pid, child->exit_code, + child->tss.kregs->tpc, + child->tss.kregs->tnpc); + +#endif + wake_up_process(child); + pt_succ_return(regs, 0); + goto out; + } + +/* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: { + if (child->state == TASK_ZOMBIE) { /* already dead */ + pt_succ_return(regs, 0); + goto out; + } + wake_up_process(child); + child->exit_code = SIGKILL; + pt_succ_return(regs, 0); + goto out; + } + + case PTRACE_SUNDETACH: { /* detach a process that was attached. */ + if ((unsigned long) data > NSIG) { + pt_error_return(regs, EIO); + goto out; + } + child->flags &= ~(PF_PTRACED|PF_TRACESYS); + wake_up_process(child); + child->exit_code = data; + REMOVE_LINKS(child); + child->p_pptr = child->p_opptr; + SET_LINKS(child); + pt_succ_return(regs, 0); + goto out; + } + + /* PTRACE_DUMPCORE unsupported... */ + + default: + pt_error_return(regs, EIO); + goto out; + } +out: + unlock_kernel(); +} + +asmlinkage void syscall_trace(void) +{ +#ifdef DEBUG_PTRACE + printk("%s [%d]: syscall_trace\n", current->comm, current->pid); +#endif + if ((current->flags & (PF_PTRACED|PF_TRACESYS)) + != (PF_PTRACED|PF_TRACESYS)) + return; + current->exit_code = SIGTRAP; + current->state = TASK_STOPPED; + current->tss.flags ^= MAGIC_CONSTANT; + notify_parent(current); + schedule(); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ +#ifdef DEBUG_PTRACE + printk("%s [%d]: syscall_trace exit= %x\n", current->comm, + current->pid, current->exit_code); +#endif + if (current->exit_code) { + set_bit(current->exit_code + 31, ¤t->signal); + } + current->exit_code = 0; +} diff -u --recursive --new-file v2.1.41/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S --- v2.1.41/linux/arch/sparc64/kernel/rtrap.S Sat May 24 09:10:23 1997 +++ linux/arch/sparc64/kernel/rtrap.S Wed May 28 10:49:08 1997 @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.14 1997/05/18 08:42:14 davem Exp $ +/* $Id: rtrap.S,v 1.18 1997/05/27 06:28:05 davem Exp $ * rtrap.S: Preparing for return from trap on Sparc V9. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -9,11 +9,14 @@ #include #include #include +#include -/* We assume here this is entered with AG, MG and IG bits in pstate clear */ + /* We assume here that this is entered with AG, MG and IG bits + * in pstate clear. + */ .text - .align 4 + .align 32 .globl rtrap rtrap: sethi %hi(bh_active), %l2 @@ -23,24 +26,26 @@ ldx [%l2 + %g4], %l3 ldx [%l1 + %g4], %l4 andcc %l3, %l4, %g0 + nop + be,pt %xcc, 2f nop call do_bottom_half nop -2: - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %l1 - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %l2 +2: ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %l1 sethi %hi(0xf << 20), %l4 andcc %l1, TSTATE_PRIV, %l3 and %l1, %l4, %l4 + rdpr %pstate, %l7 - andn %l1, %l4, %l1 /* XXX May not be needed -DaveM */ + andn %l1, %l4, %l1 be,pt %icc, to_user andn %l7, PSTATE_IE, %l7 -3: +3: ldx [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l6 ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1], %g1 ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2], %g2 ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3], %g3 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4], %g4 ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5], %g5 ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6], %g6 @@ -49,54 +54,54 @@ ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1], %i1 ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2], %i2 ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3], %i3 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4], %i4 ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5], %i5 ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6], %i6 ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7], %i7 ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_Y], %o3 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %l2 ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %o2 - rdpr %tl, %o4 wr %o3, %g0, %y - add %o4, 1, %o4 srl %l4, 20, %l4 wrpr %l7, %g0, %pstate wrpr %l4, 0x0, %pil - wrpr %o4, %g0, %tl + wrpr %g0, 0x1, %tl wrpr %l1, %g0, %tstate wrpr %l2, %g0, %tpc brnz,pn %l3, 1f wrpr %o2, %g0, %tnpc - /* We came here from to_user, ie. we have now AG. - * Also have to push user context back into primary. - */ - mov SECONDARY_CONTEXT, %g6 - mov PRIMARY_CONTEXT, %g7 - ldxa [%g6] ASI_DMMU, %g4 - stxa %g4, [%g7] ASI_DMMU - membar #Sync /* XXX flushi would be better -DaveM */ - - rdpr %wstate, %g1 - rdpr %otherwin, %g2 - srl %g1, 3, %g1 - wrpr %g2, %g0, %canrestore - wrpr %g1, %g0, %wstate + mov PRIMARY_CONTEXT, %l7 + sethi %uhi(KERNBASE), %l5 + sllx %l5, 32, %l5 + stxa %l6, [%l7] ASI_DMMU + flush %l5 + rdpr %wstate, %l1 + rdpr %otherwin, %l2 + srl %l1, 3, %l1 + + wrpr %l2, %g0, %canrestore + wrpr %l1, %g0, %wstate wrpr %g0, %g0, %otherwin -1: - restore +1: restore retry to_user: sethi %hi(need_resched), %l0 or %l0, %lo(need_resched), %l0 ld [%l0 + %g4], %l0 + wrpr %l7, PSTATE_IE, %pstate - brz,pt %l0, 1f + brz,pt %l0, check_signal ldx [%g6 + AOFF_task_signal], %l0 call schedule nop -1: + ldx [%g6 + AOFF_task_signal], %l0 + nop +check_signal: ldx [%g6 + AOFF_task_blocked], %o0 + or %l7, PSTATE_AG, %l7 ! Will need this for setting back wstate andncc %l0, %o0, %g0 be,pt %xcc, check_user_wins @@ -105,8 +110,17 @@ call do_signal add %sp, STACK_BIAS + REGWIN_SZ, %o1 check_user_wins: +#if 0 + call user_rtrap_report + add %sp, STACK_BIAS + REGWIN_SZ, %o0 +#endif ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 + brz,pt %o2, 3b add %sp, STACK_BIAS + REGWIN_SZ, %o1 call fault_in_user_windows add %o7, 3b-.-4, %o7 + nop + nop + nop + nop diff -u --recursive --new-file v2.1.41/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c --- v2.1.41/linux/arch/sparc64/kernel/setup.c Thu May 15 16:48:02 1997 +++ linux/arch/sparc64/kernel/setup.c Wed May 28 10:49:08 1997 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.6 1997/05/04 07:21:04 davem Exp $ +/* $Id: setup.c,v 1.7 1997/05/20 07:58:56 jj Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -247,6 +248,10 @@ char saved_command_line[256]; char reboot_command[256]; +#ifdef CONFIG_ROOT_NFS +extern char nfs_root_addrs[]; +#endif + unsigned long phys_base; static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 }; @@ -345,6 +350,31 @@ init_task.mm->mmap->vm_end = *memory_end_p; init_task.mm->context = (unsigned long) NO_CONTEXT; init_task.tss.kregs = &fake_swapper_regs; + +#ifdef CONFIG_ROOT_NFS + if (!*nfs_root_addrs) { + int chosen = prom_finddevice ("/chosen"); + u32 cl, sv, gw; + char *p = nfs_root_addrs; + + cl = prom_getintdefault (chosen, "client-ip", 0); + sv = prom_getintdefault (chosen, "server-ip", 0); + gw = prom_getintdefault (chosen, "gateway-ip", 0); + if (cl && sv) { + strcpy (p, in_ntoa (cl)); + p += strlen (p); + *p++ = ':'; + strcpy (p, in_ntoa (sv)); + p += strlen (p); + *p++ = ':'; + if (gw) { + strcpy (p, in_ntoa (gw)); + p += strlen (p); + } + strcpy (p, "::::none"); + } + } +#endif #ifdef CONFIG_SUN_SERIAL *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */ diff -u --recursive --new-file v2.1.41/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c --- v2.1.41/linux/arch/sparc64/kernel/signal.c Sat May 24 09:10:23 1997 +++ linux/arch/sparc64/kernel/signal.c Wed May 28 10:49:08 1997 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.2 1997/05/18 08:42:15 davem Exp $ +/* $Id: signal.c,v 1.4 1997/05/27 06:28:05 davem Exp $ * arch/sparc64/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -61,7 +61,7 @@ */ asmlinkage void _sigpause_common(unsigned int set, struct pt_regs *regs) { - unsigned int mask; + unsigned long mask; #ifdef CONFIG_SPARC32_COMPAT if (current->tss.flags & SPARC_FLAG_32BIT) { @@ -134,7 +134,7 @@ struct new_signal_frame *sf; unsigned long tpc, tnpc, tstate; __siginfo_fpu_t *fpu_save; - int mask; + unsigned long mask; #ifdef CONFIG_SPARC32_COMPAT if (current->tss.flags & SPARC_FLAG_32BIT) { @@ -270,8 +270,15 @@ regs->tnpc = (regs->tpc + 4); /* Flush instruction space. */ - __asm__ __volatile__ ("flush %0; flush %0 + 4" : : "r" (&(sf->insns[0]))); - + __asm__ __volatile__(" + membar #StoreStore + stxa %%g0, [%0] %2 + stxa %%g0, [%1] %2 + flush %%g4 + " : /* no outputs */ + : "r" (((unsigned long)&(sf->insns[0])) & ~(PAGE_MASK)), + "r" ((((unsigned long)&(sf->insns[0])) & ~(PAGE_MASK)) + PAGE_SIZE), + "i" (ASI_IC_TAG)); } static inline void handle_signal(unsigned long signr, struct sigaction *sa, @@ -323,7 +330,7 @@ #endif while ((signr = current->signal & mask) != 0) { signr = ffz(~signr); - clear_bit(signr, ¤t->signal); + clear_bit(signr + 32, ¤t->signal); sa = current->sig->action + signr; signr++; if ((current->flags & PF_PTRACED) && signr != SIGKILL) { diff -u --recursive --new-file v2.1.41/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c --- v2.1.41/linux/arch/sparc64/kernel/signal32.c Sat May 24 09:10:23 1997 +++ linux/arch/sparc64/kernel/signal32.c Wed May 28 10:49:08 1997 @@ -1,4 +1,4 @@ -/* $Id: signal32.c,v 1.8 1997/05/18 08:42:15 davem Exp $ +/* $Id: signal32.c,v 1.10 1997/05/27 06:28:07 davem Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -398,8 +398,15 @@ regs->tnpc = (regs->tpc + 4); /* Flush instruction space. */ - __asm__ __volatile__ ("flush %0; flush %0 + 4" : : "r" (&(sf->insns[0]))); - + __asm__ __volatile__(" + membar #StoreStore + stxa %%g0, [%0] %2 + stxa %%g0, [%1] %2 + flush %%g4 + " : /* no outputs */ + : "r" (((unsigned long)&(sf->insns[0])) & ~(PAGE_MASK)), + "r" ((((unsigned long)&(sf->insns[0])) & ~(PAGE_MASK)) + PAGE_SIZE), + "i" (ASI_IC_TAG)); } /* Setup a Solaris stack frame */ @@ -677,7 +684,7 @@ while ((signr = current->signal & mask) != 0) { signr = ffz(~signr); - clear_bit(signr, ¤t->signal); + clear_bit(signr + 32, ¤t->signal); sa = current->sig->action + signr; signr++; if ((current->flags & PF_PTRACED) && signr != SIGKILL) { diff -u --recursive --new-file v2.1.41/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.1.41/linux/arch/sparc64/kernel/sys_sparc32.c Sat May 24 09:10:23 1997 +++ linux/arch/sparc64/kernel/sys_sparc32.c Wed May 28 10:49:08 1997 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.13 1997/05/18 04:16:44 davem Exp $ +/* $Id: sys_sparc32.c,v 1.18 1997/05/27 06:28:08 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -48,7 +48,6 @@ extern asmlinkage int sys_bdflush(int func, long data); extern asmlinkage int sys_uselib(const char * library); extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg); -extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); extern asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev); extern asmlinkage int sys_mkdir(const char * pathname, int mode); extern asmlinkage int sys_rmdir(const char * pathname); @@ -147,6 +146,69 @@ extern asmlinkage int sys_socketpair(int family, int type, int protocol, int usockvec[2]); extern asmlinkage int sys_shutdown(int fd, int how); +/* + * In order to reduce some races, while at the same time doing additional + * checking and hopefully speeding things up, we copy filenames to the + * kernel data space before using them.. + * + * POSIX.1 2.4: an empty pathname is invalid (ENOENT). + */ +static inline int do_getname32(u32 filename, char *page) +{ + int retval; + + /* 32bit pointer will be always far below TASK_SIZE :)) */ + retval = strncpy_from_user((char *)page, (char *)A(filename), PAGE_SIZE); + if (retval > 0) { + if (retval < PAGE_SIZE) + return 0; + return -ENAMETOOLONG; + } else if (!retval) + retval = -ENOENT; + return retval; +} + +/* + * This is a single page for faster getname. + * If the page is available when entering getname, use it. + * If the page is not available, call __get_free_page instead. + * This works even though do_getname can block (think about it). + * -- Michael Chastain, based on idea of Linus Torvalds, 1 Dec 1996. + * We don't use the common getname/putname from namei.c, so that + * this still works well, as every routine which calls getname32 + * will then call getname, then putname and then putname32. + */ +static unsigned long name_page_cache32 = 0; + +void putname32(char * name) +{ + if (name_page_cache32 == 0) + name_page_cache32 = (unsigned long) name; + else + free_page((unsigned long) name); +} + +int getname32(u32 filename, char **result) +{ + unsigned long page; + int retval; + + page = name_page_cache32; + name_page_cache32 = 0; + if (!page) { + page = __get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + } + + retval = do_getname32(filename, (char *) page); + if (retval < 0) + putname32( (char *) page ); + else + *result = (char *) page; + return retval; +} + asmlinkage int sys32_ioperm(u32 from, u32 num, int on) { return sys_ioperm((unsigned long)from, (unsigned long)num, on); @@ -558,13 +620,6 @@ } } -/* Conversion of args should be probably done in all the locations where it is handled, - using if (current->tss.flags & SPARC_FLAG_32BIT */ -asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) -{ - return sys_ioctl(fd, cmd, (unsigned long)arg); -} - asmlinkage int sys32_mknod(u32 filename, int mode, __kernel_dev_t32 dev) { return sys_mknod((const char *)A(filename), mode, dev); @@ -704,14 +759,21 @@ struct utimbuf t; unsigned long old_fs; int ret; + char *filenam; + if (!times) + return sys_utime((char *)A(filename), NULL); if (get_user (t.actime, &(((struct utimbuf32 *)A(times))->actime)) || __get_user (t.modtime, &(((struct utimbuf32 *)A(times))->modtime))) return -EFAULT; - old_fs = get_fs(); - set_fs (KERNEL_DS); - ret = sys_utime((char *)A(filename), &t); - set_fs (old_fs); + ret = getname32 (filename, &filenam); + if (!ret) { + old_fs = get_fs(); + set_fs (KERNEL_DS); + ret = sys_utime(filenam, &t); + set_fs (old_fs); + putname32 (filenam); + } return ret; } @@ -992,6 +1054,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp) { + struct timeval kern_tv, *ktvp; unsigned long old_fs; char *p; u32 *q; @@ -1015,9 +1078,15 @@ __get_user (q[PAGE_SIZE/2], Exp+1)) goto out; } + ktvp = NULL; + if(tvp) { + if(copy_from_user(&kern_tv, (struct timeval *)A(tvp), sizeof(*ktvp))) + goto out; + ktvp = &kern_tv; + } old_fs = get_fs (); set_fs (KERNEL_DS); - ret = sys_select(n, (fd_set *)p, (fd_set *)(p + PAGE_SIZE/4), (fd_set *)(p + PAGE_SIZE/2), (struct timeval *)A(tvp)); + ret = sys_select(n, (fd_set *)p, (fd_set *)(p + PAGE_SIZE/4), (fd_set *)(p + PAGE_SIZE/2), ktvp); set_fs (old_fs); q = (u32 *)p; Inp = (u32 *)A(inp); Outp = (u32 *)A(outp); Exp = (u32 *)A(exp); @@ -1065,12 +1134,17 @@ { int ret; struct stat s; + char *filenam; unsigned long old_fs = get_fs(); - set_fs (KERNEL_DS); - ret = sys_newstat((char *)A(filename), &s); - set_fs (old_fs); - if (putstat (statbuf, &s)) return -EFAULT; + ret = getname32 (filename, &filenam); + if (!ret) { + set_fs (KERNEL_DS); + ret = sys_newstat(filenam, &s); + set_fs (old_fs); + putname32 (filenam); + if (putstat (statbuf, &s)) return -EFAULT; + } return ret; } @@ -1078,12 +1152,17 @@ { int ret; struct stat s; + char *filenam; unsigned long old_fs = get_fs(); - set_fs (KERNEL_DS); - ret = sys_newlstat((char *)A(filename), &s); - set_fs (old_fs); - if (putstat (statbuf, &s)) return -EFAULT; + ret = getname32 (filename, &filenam); + if (!ret) { + set_fs (KERNEL_DS); + ret = sys_newlstat(filenam, &s); + set_fs (old_fs); + putname32 (filenam); + if (putstat (statbuf, &s)) return -EFAULT; + } return ret; } @@ -1985,6 +2064,144 @@ { /* XXX handle argp and resp args */ return sys_nfsservctl(cmd, (void *)A(argp), (void *)A(resp)); +} + +/* + * count32() counts the number of arguments/envelopes + */ +static int count32(u32 * argv) +{ + int i = 0; + + if (argv != NULL) { + for (;;) { + u32 p; int error; + + error = get_user(p,argv); + if (error) return error; + if (!p) break; + argv++; i++; + } + } + return i; +} + +/* + * 'copy_string32()' copies argument/envelope strings from user + * memory to free pages in kernel mem. These are in a format ready + * to be put directly into the top of new user memory. + */ +static unsigned long +copy_strings32(int argc,u32 * argv,unsigned long *page, + unsigned long p) +{ + u32 str; + + if (!p) return 0; /* bullet-proofing */ + while (argc-- > 0) { + int len; + unsigned long pos; + + get_user(str, argv+argc); + if (!str) panic("VFS: argc is wrong"); + len = strlen_user((char *)A(str)); /* includes the '\0' */ + if (p < len) /* this shouldn't happen - 128kB */ + return 0; + p -= len; pos = p; + while (len) { + char *pag; + int offset, bytes_to_copy; + + offset = pos % PAGE_SIZE; + if (!(pag = (char *) page[pos/PAGE_SIZE]) && + !(pag = (char *) page[pos/PAGE_SIZE] = + (unsigned long *) get_free_page(GFP_USER))) + return 0; + bytes_to_copy = PAGE_SIZE - offset; + if (bytes_to_copy > len) + bytes_to_copy = len; + copy_from_user(pag + offset, (char *)A(str), bytes_to_copy); + pos += bytes_to_copy; + str += bytes_to_copy; + len -= bytes_to_copy; + } + } + return p; +} + +/* + * sys32_execve() executes a new program. + */ +static inline int +do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs) +{ + struct linux_binprm bprm; + int retval; + int i; + + bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); + for (i=0 ; i=0) { + bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p, 2); + bprm.exec = bprm.p; + bprm.p = copy_strings32(bprm.envc,envp,bprm.page,bprm.p); + bprm.p = copy_strings32(bprm.argc,argv,bprm.page,bprm.p); + if (!bprm.p) + retval = -E2BIG; + } + + if(retval>=0) + retval = search_binary_handler(&bprm,regs); + if(retval>=0) + /* execve success */ + return retval; + + /* Something went wrong, return the inode and free the argument pages*/ + if(!bprm.dont_iput) + iput(bprm.inode); + for (i=0 ; iu_regs[UREG_G1] == 0) + base = 1; + + error = getname((char *)(unsigned long)(u32)regs->u_regs[base + UREG_I0], &filename); + if(error) + return error; + error = do_execve32(filename, + (u32 *)A((u32)regs->u_regs[base + UREG_I1]), + (u32 *)A((u32)regs->u_regs[base + UREG_I2]), regs); + putname(filename); + return error; } struct ncp_mount_data32 { diff -u --recursive --new-file v2.1.41/linux/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S --- v2.1.41/linux/arch/sparc64/kernel/systbls.S Wed Apr 23 19:01:16 1997 +++ linux/arch/sparc64/kernel/systbls.S Wed May 28 10:49:08 1997 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.8 1997/04/21 08:34:23 jj Exp $ +/* $Id: systbls.S,v 1.11 1997/05/27 19:30:20 jj Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -22,13 +22,13 @@ /*10*/ .xword sys32_unlink, sunos_execv, sys32_chdir, sys_nis_syscall, sys32_mknod /*15*/ .xword sys32_chmod, sys32_chown, sparc32_brk, sys_nis_syscall, sys32_lseek /*20*/ .xword sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid -/*25*/ .xword sys32_time, sys32_ptrace, sys_alarm, sys_nis_syscall, sys_pause +/*25*/ .xword sys32_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause /*30*/ .xword sys32_utime, sys_stty, sys_gtty, sys32_access, sys_nice .xword sys_ftime, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall /*40*/ .xword sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_profil .xword sys_nis_syscall, sys_setgid, sys_getgid, sys32_signal, sys_geteuid /*50*/ .xword sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl - .xword sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys_execve + .xword sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys32_execve /*60*/ .xword sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize .xword sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall /*70*/ .xword sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect @@ -61,7 +61,7 @@ .xword sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall /*210*/ .xword sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo .xword sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex -/*220*/ .xword sys_sigprocmask, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getpgid +/*220*/ .xword sys32_sigprocmask, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getpgid .xword sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid /*230*/ .xword sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall .xword sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall @@ -153,7 +153,7 @@ /*50*/ .xword sunos_nosys, sys_acct, sunos_nosys .xword sunos_mctl, sunos_ioctl, sys_reboot .xword sunos_nosys, sys_symlink, sys_readlink - .xword sys_execve, sys_umask, sys_chroot + .xword sys32_execve, sys_umask, sys_chroot .xword sys_newfstat, sunos_nosys, sys_getpagesize .xword sys_msync, sys_vfork, sunos_nosys .xword sunos_nosys, sunos_sbrk, sunos_sstk diff -u --recursive --new-file v2.1.41/linux/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c --- v2.1.41/linux/arch/sparc64/kernel/traps.c Sat May 24 09:10:23 1997 +++ linux/arch/sparc64/kernel/traps.c Wed May 28 10:49:08 1997 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.10 1997/05/18 08:42:16 davem Exp $ +/* $Id: traps.c,v 1.13 1997/05/27 19:30:08 jj Exp $ * arch/sparc/kernel/traps.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -24,76 +24,271 @@ #include #include -/* #define TRAP_DEBUG */ +/* #define SYSCALL_TRACING */ +/* #define VERBOSE_SYSCALL_TRACING */ -struct trap_trace_entry { - unsigned long pc; - unsigned long type; +#ifdef SYSCALL_TRACING +#ifdef VERBOSE_SYSCALL_TRACING +struct sdesc { + int scall_num; + char *name; + int num_args; + char arg_is_string[6]; +} sdesc_entries[] = { + { 0, "setup", 0, }, + { 1, "exit", 1, { 0, } }, + { 2, "fork", 0, }, + { 3, "read", 3, { 0, 0, 0, } }, + { 4, "write", 3, { 0, 0, 0, } }, + { 5, "open", 3, { 1, 0, 0, } }, + { 6, "close", 1, { 0, } }, + { 7, "wait4", 4, { 0, 0, 0, 0, } }, + { 8, "creat", 2, { 1, 0, } }, + { 9, "link", 2, { 1, 1, } }, + { 10, "unlink", 1, { 1, } }, + { 11, "execv", 2, { 1, 0, } }, + { 12, "chdir", 1, { 1, } }, + { 15, "chmod", 2, { 1, 0, } }, + { 16, "chown", 3, { 1, 0, 0, } }, + { 17, "brk", 1, { 0, } }, + { 19, "lseek", 3, { 0, 0, 0, } }, + { 27, "alarm", 1, { 0, } }, + { 29, "pause", 0, }, + { 33, "access", 2, { 1, 0, } }, + { 36, "sync", 0, }, + { 37, "kill", 2, { 0, 0, } }, + { 38, "stat", 2, { 1, 0, } }, + { 40, "lstat", 2, { 1, 0, } }, + { 41, "dup", 1, { 0, } }, + { 42, "pipd", 0, }, + { 54, "ioctl", 3, { 0, 0, 0, } }, + { 57, "symlink", 2, { 1, 1, } }, + { 58, "readlink", 3, { 1, 0, 0, } }, + { 59, "execve", 3, { 1, 0, 0, } }, + { 60, "umask", 1, { 0, } }, + { 62, "fstat", 2, { 0, 0, } }, + { 64, "getpagesize", 0, }, + { 71, "mmap", 6, { 0, 0, 0, 0, 0, 0, } }, + { 73, "munmap", 2, { 0, 0, } }, + { 74, "mprotect", 3, { 0, 0, 0, } }, + { 83, "setitimer", 3, { 0, 0, 0, } }, + { 90, "dup2", 2, { 0, 0, } }, + { 92, "fcntl", 3, { 0, 0, 0, } }, + { 93, "select", 5, { 0, 0, 0, 0, 0, } }, + { 97, "socket", 3, { 0, 0, 0, } }, + { 98, "connect", 3, { 0, 0, 0, } }, + { 99, "accept", 3, { 0, 0, 0, } }, + { 101, "send", 4, { 0, 0, 0, 0, } }, + { 102, "recv", 4, { 0, 0, 0, 0, } }, + { 104, "bind", 3, { 0, 0, 0, } }, + { 105, "setsockopt", 5, { 0, 0, 0, 0, 0, } }, + { 106, "listen", 2, { 0, 0, } }, + { 120, "readv", 3, { 0, 0, 0, } }, + { 121, "writev", 3, { 0, 0, 0, } }, + { 123, "fchown", 3, { 0, 0, 0, } }, + { 124, "fchmod", 2, { 0, 0, } }, + { 128, "rename", 2, { 1, 1, } }, + { 129, "truncate", 2, { 1, 0, } }, + { 130, "ftruncate", 2, { 0, 0, } }, + { 131, "flock", 2, { 0, 0, } }, + { 136, "mkdir", 2, { 1, 0, } }, + { 137, "rmdir", 1, { 1, } }, + { 146, "killpg", 1, { 0, } }, + { 157, "statfs", 2, { 1, 0, } }, + { 158, "fstatfs", 2, { 0, 0, } }, + { 159, "umount", 1, { 1, } }, + { 167, "mount", 5, { 1, 1, 1, 0, 0, } }, + { 174, "getdents", 3, { 0, 0, 0, } }, + { 176, "fchdir", 2, { 0, 0, } }, + { 198, "sigaction", 3, { 0, 0, 0, } }, + { 201, "sigsuspend", 1, { 0, } }, + { 206, "socketcall", 2, { 0, 0, } }, + { 216, "sigreturn", 0, }, + { 230, "newselect", 5, { 0, 0, 0, 0, 0, } }, + { 236, "llseek", 5, { 0, 0, 0, 0, 0, } }, + { 251, "sysctl", 1, { 0, } }, }; +#define NUM_SDESC_ENTRIES (sizeof(sdesc_entries) / sizeof(sdesc_entries[0])) +#endif -int trap_curbuf = 0; -struct trap_trace_entry trapbuf[1024]; - -void syscall_trace_entry(struct pt_regs *regs) -{ - printk("%s[%d]: ", current->comm, current->pid); - printk("scall<%ld> (could be %ld)\n", (long) regs->u_regs[UREG_G1], - (long) regs->u_regs[UREG_I0]); -} +#ifdef VERBOSE_SYSCALL_TRACING +static char scall_strbuf[512]; +#endif -void syscall_trace_exit(struct pt_regs *regs) +void syscall_trace_entry(unsigned long g1, struct pt_regs *regs) { - printk("Syscall return check, reg dump.\n"); - show_regs(regs); -} +#ifdef VERBOSE_SYSCALL_TRACING + struct sdesc *sdp; + int i; +#endif -void sparc64_dtlb_fault_handler (void) -{ - printk ("sparc64_dtlb_fault_handler\n"); - while (1); - /* Die for now... */ + printk("SYS[%s:%d]: <%d> ", current->comm, current->pid, (int)g1); +#ifdef VERBOSE_SYSCALL_TRACING + sdp = NULL; + for(i = 0; i < NUM_SDESC_ENTRIES; i++) + if(sdesc_entries[i].scall_num == g1) { + sdp = &sdesc_entries[i]; + break; + } + if(sdp) { + printk("%s(", sdp->name); + for(i = 0; i < sdp->num_args; i++) { + if(i) + printk(","); + if(!sdp->arg_is_string[i]) + printk("%08x", (unsigned int)regs->u_regs[UREG_I0 + i]); + else { + strncpy_from_user(scall_strbuf, + (char *)regs->u_regs[UREG_I0 + i], + 512); + printk("%s", scall_strbuf); + } + } + printk(") "); + } +#endif } -void sparc64_dtlb_refbit_handler (struct pt_regs *regs) +unsigned long syscall_trace_exit(unsigned long retval, struct pt_regs *regs) { - printk ("sparc64_dtlb_refbit_handler[%016lx]\n", regs->tpc); - while (1); - /* Die for now... */ + printk("ret[%08x]\n", (unsigned int) retval); + return retval; } +#endif /* SYSCALL_TRACING */ -void sparc64_itlb_refbit_handler (void) -{ - printk ("sparc64_itlb_refbit_handler\n"); - while (1); - /* Die for now... */ +#if 0 +void user_rtrap_report(struct pt_regs *regs) +{ + static int hits = 0; + + /* Bwahhhhrggg... */ + if(regs->tpc == 0x1f294UL && ++hits == 2) { + register unsigned long ctx asm("o4"); + register unsigned long paddr asm("o5"); + unsigned long cwp, wstate; + + printk("RT[%016lx:%016lx] ", regs->tpc, regs->u_regs[UREG_I6]); + __asm__ __volatile__("rdpr %%cwp, %0" : "=r" (cwp)); + __asm__ __volatile__("rdpr %%wstate, %0" : "=r" (wstate)); + printk("CWP[%d] WSTATE[%016lx]\n" + "TSS( ksp[%016lx] kpc[%016lx] wstate[%016lx] w_saved[%d] flgs[%x]" + " cur_ds[%d] )\n", cwp, wstate, + current->tss.ksp, current->tss.kpc, current->tss.wstate, + (int) current->tss.w_saved, current->tss.flags, + current->tss.current_ds); + __asm__ __volatile__(" + rdpr %%pstate, %%o3 + wrpr %%o3, %2, %%pstate + mov %%g7, %%o5 + mov 0x10, %%o4 + ldxa [%%o4] %3, %%o4 + wrpr %%o3, 0x0, %%pstate + " : "=r" (ctx), "=r" (paddr) + : "i" (PSTATE_MG|PSTATE_IE), "i" (ASI_DMMU)); + + printk("MMU[ppgd(%016lx)sctx(%d)] ", paddr, ctx); + printk("mm->context(%016lx) mm->pgd(%p)\n", + current->mm->context, current->mm->pgd); + printk("TASK: signal[%016lx] blocked[%016lx]\n", + current->signal, current->blocked); + show_regs(regs); + while(1) + barrier(); + } } +#endif void bad_trap (struct pt_regs *regs, long lvl) { - printk ("Bad trap %d (tstate %016lx tpc %016lx tnpc %016lx)\n", lvl, regs->tstate, regs->tpc, regs->tnpc); - while (1); - /* Die for now... */ + lock_kernel (); + if (lvl < 0x100) { + char buffer[24]; + + sprintf (buffer, "Bad hw trap %lx at tl0\n", lvl); + die_if_kernel (buffer, regs); + } + if (regs->tstate & TSTATE_PRIV) + die_if_kernel ("Kernel bad trap", regs); + current->tss.sig_desc = SUBSIG_BADTRAP(lvl - 0x100); + current->tss.sig_address = regs->tpc; + send_sig(SIGILL, current, 1); + unlock_kernel (); } void bad_trap_tl1 (struct pt_regs *regs, long lvl) { - printk ("Bad trap %d at tl1+ (tstate %016lx tpc %016lx tnpc %016lx)\n", lvl, regs->tstate, regs->tpc, regs->tnpc); - while (1); - /* Die for now... */ + char buffer[24]; + + lock_kernel (); + sprintf (buffer, "Bad trap %lx at tl>0", lvl); + die_if_kernel (buffer, regs); } void data_access_exception (struct pt_regs *regs) { - printk ("Unhandled data access exception sfsr %016lx sfar %016lx\n", spitfire_get_dsfsr(), spitfire_get_sfar()); + lock_kernel (); + printk ("Unhandled data access exception "); + printk("sfsr %016lx sfar %016lx\n", spitfire_get_dsfsr(), spitfire_get_sfar()); die_if_kernel("Data access exception", regs); } +void do_dae(struct pt_regs *regs) +{ + printk("DAE: at %016lx\n", regs->tpc); + while(1) + barrier(); +} + void instruction_access_exception (struct pt_regs *regs) { - printk ("Unhandled instruction access exception sfsr %016lx\n", spitfire_get_isfsr()); + lock_kernel (); + printk ("Unhandled instruction access exception "); + printk("sfsr %016lx\n", spitfire_get_isfsr()); die_if_kernel("Instruction access exception", regs); } +void do_iae(struct pt_regs *regs) +{ + printk("IAE at %016lx\n", regs->tpc); + while(1) + barrier(); +} + +void do_fpdis(struct pt_regs *regs) +{ + printk("FPDIS: at %016lx\n", regs->tpc); + while(1) + barrier(); +} + +void do_fpieee(struct pt_regs *regs) +{ + printk("FPIEEE: at %016lx\n", regs->tpc); + while(1) + barrier(); +} + +void do_fpother(struct pt_regs *regs) +{ + printk("FPOTHER: at %016lx\n", regs->tpc); + while(1) + barrier(); +} + +void do_tof(struct pt_regs *regs) +{ + printk("TOF: at %016lx\n", regs->tpc); + while(1) + barrier(); +} + +void do_div0(struct pt_regs *regs) +{ + printk("DIV0: at %016lx\n", regs->tpc); + while(1) + barrier(); +} + void instruction_dump (unsigned int *pc) { int i; @@ -116,11 +311,27 @@ " \\__U_/\n"); printk("%s(%d): %s\n", current->comm, current->pid, str); + __asm__ __volatile__("flushw"); show_regs(regs); + { + struct reg_window *rw = (struct reg_window *) + (regs->u_regs[UREG_FP] + STACK_BIAS); + + if(rw) { + printk("Caller[%016lx]\n", rw->ins[7]); + rw = (struct reg_window *) + (rw->ins[6] + STACK_BIAS); + if(rw) { + printk("Caller[%016lx]\n", rw->ins[7]); + rw = (struct reg_window *) + (rw->ins[6] + STACK_BIAS); + if(rw) + printk("Caller[%016lx]\n", rw->ins[7]); + } + } + } printk("Instruction DUMP:"); instruction_dump ((unsigned int *) regs->tpc); - while(1) - barrier(); if(regs->tstate & TSTATE_PRIV) do_exit(SIGKILL); do_exit(SIGSEGV); @@ -156,6 +367,20 @@ { printk("AIEEE: do_mna at %016lx\n", regs->tpc); show_regs(regs); + while(1) + barrier(); +} + +void do_privop(struct pt_regs *regs) +{ + printk("PRIVOP: at %016lx\n", regs->tpc); + while(1) + barrier(); +} + +void do_privact(struct pt_regs *regs) +{ + printk("PRIVACT: at %016lx\n", regs->tpc); while(1) barrier(); } diff -u --recursive --new-file v2.1.41/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c --- v2.1.41/linux/arch/sparc64/mm/fault.c Sat May 24 09:10:23 1997 +++ linux/arch/sparc64/mm/fault.c Wed May 28 10:49:08 1997 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.8 1997/05/18 04:16:52 davem Exp $ +/* $Id: fault.c,v 1.9 1997/05/19 05:58:54 davem Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -150,13 +150,13 @@ static unsigned long last_addr = 0; static int rcnt = 0; - printk("do_sparc64_fault(PC[%016lx],t[%d],w[%d],addr[%016lx]tag[%016lx]" - "sfar[%016lx])\n", regs->tpc, text_fault, write, address, tag, sfsr); + printk("FAULT(PC[%016lx],t[%d],w[%d],addr[%016lx])\n", + regs->tpc, text_fault, write, address); if(address == last_addr && rcnt++ > 5) { printk("Wheee lotsa bogus faults, something wrong, spinning\n"); while(1) barrier(); - } + } else rcnt = 0; last_addr = address; #endif lock_kernel (); diff -u --recursive --new-file v2.1.41/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c --- v2.1.41/linux/arch/sparc64/mm/init.c Sat May 24 09:10:23 1997 +++ linux/arch/sparc64/mm/init.c Wed May 28 10:49:08 1997 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.28 1997/05/18 04:16:53 davem Exp $ +/* $Id: init.c,v 1.29 1997/05/27 06:28:13 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -269,10 +269,14 @@ } } +static char sfmmuinfo[512]; + char *mmu_info(void) { - /* XXX */ - return "MMU Type: Spitfire\n\tFIXME: Write this\n"; + /* We'll do the rest later to make it nice... -DaveM */ + sprintf(sfmmuinfo, "MMU Type\t: Spitfire\n"); + + return sfmmuinfo; } static unsigned long mempool; diff -u --recursive --new-file v2.1.41/linux/drivers/block/ez.c linux/drivers/block/ez.c --- v2.1.41/linux/drivers/block/ez.c Tue May 13 22:41:04 1997 +++ linux/drivers/block/ez.c Wed May 28 11:26:08 1997 @@ -176,7 +176,7 @@ static void do_ez_request(void); static int ez_ioctl(struct inode *inode,struct file *file, unsigned int cmd, unsigned long arg); -static void ez_release (struct inode *inode, struct file *file); +static int ez_release (struct inode *inode, struct file *file); static int ez_revalidate(kdev_t dev); static int ez_check_media(kdev_t dev); static void ez_get_capacity( void ); @@ -387,7 +387,7 @@ } } -static void ez_release (struct inode *inode, struct file *file) +static int ez_release (struct inode *inode, struct file *file) { kdev_t devp; @@ -400,6 +400,7 @@ if (!ez_access) ez_doorlock(IDE_DOORUNLOCK); MOD_DEC_USE_COUNT; } + return 0; } static int ez_check_media( kdev_t dev) diff -u --recursive --new-file v2.1.41/linux/drivers/cdrom/bpcd.c linux/drivers/cdrom/bpcd.c --- v2.1.41/linux/drivers/cdrom/bpcd.c Tue May 13 22:41:06 1997 +++ linux/drivers/cdrom/bpcd.c Wed May 28 11:26:08 1997 @@ -149,7 +149,7 @@ static void do_bp_read(void); static int bp_ioctl(struct inode *inode,struct file *file, unsigned int cmd, unsigned long arg); -static void bp_release (struct inode *inode, struct file *file); +static int bp_release (struct inode *inode, struct file *file); static int bp_detect(void); static int bp_lock(void); @@ -277,7 +277,7 @@ } } -static void bp_release (struct inode *inode, struct file *file) +static int bp_release (struct inode *inode, struct file *file) { kdev_t devp; @@ -290,6 +290,7 @@ bp_unlock(); } MOD_DEC_USE_COUNT; + return 0; } #ifdef MODULE diff -u --recursive --new-file v2.1.41/linux/drivers/char/istallion.c linux/drivers/char/istallion.c --- v2.1.41/linux/drivers/char/istallion.c Tue May 13 22:41:07 1997 +++ linux/drivers/char/istallion.c Wed May 28 11:26:08 1997 @@ -2450,7 +2450,7 @@ if (! ((portp->flags & ASYNC_CALLOUT_ACTIVE) && (portp->flags & ASYNC_CALLOUT_NOHUP))) { if (tty != (struct tty_struct *) NULL) - queue_task_irq_off(&portp->tqhangup, &tq_scheduler); + queue_task(&portp->tqhangup, &tq_scheduler); } } } diff -u --recursive --new-file v2.1.41/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c --- v2.1.41/linux/drivers/char/pc_keyb.c Sat May 24 09:10:23 1997 +++ linux/drivers/char/pc_keyb.c Wed May 28 10:49:08 1997 @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.1.41/linux/drivers/char/riscom8.c linux/drivers/char/riscom8.c --- v2.1.41/linux/drivers/char/riscom8.c Tue May 13 22:41:07 1997 +++ linux/drivers/char/riscom8.c Wed May 28 11:26:08 1997 @@ -337,7 +337,7 @@ * Still hope this will be changed in near future. */ set_bit(event, &port->event); - queue_task_irq_off(&port->tqueue, &tq_riscom); + queue_task(&port->tqueue, &tq_riscom); mark_bh(RISCOM8_BH); } @@ -419,7 +419,7 @@ *tty->flip.char_buf_ptr++ = ch; tty->flip.count++; - queue_task_irq_off(&tty->flip.tqueue, &tq_timer); + queue_task(&tty->flip.tqueue, &tq_timer); } extern inline void rc_receive(struct riscom_board const * bp) @@ -449,7 +449,7 @@ *tty->flip.flag_buf_ptr++ = 0; tty->flip.count++; } - queue_task_irq_off(&tty->flip.tqueue, &tq_timer); + queue_task(&tty->flip.tqueue, &tq_timer); } extern inline void rc_transmit(struct riscom_board const * bp) @@ -538,8 +538,7 @@ wake_up_interruptible(&port->open_wait); else if (!((port->flags & ASYNC_CALLOUT_ACTIVE) && (port->flags & ASYNC_CALLOUT_NOHUP))) - queue_task_irq_off(&port->tqueue_hangup, - &tq_scheduler); + queue_task(&port->tqueue_hangup, &tq_scheduler); } #ifdef RISCOM_BRAIN_DAMAGED_CTS diff -u --recursive --new-file v2.1.41/linux/drivers/char/selection.c linux/drivers/char/selection.c --- v2.1.41/linux/drivers/char/selection.c Mon Apr 14 16:28:11 1997 +++ linux/drivers/char/selection.c Wed May 28 10:49:08 1997 @@ -92,10 +92,11 @@ /* set inwordLut contents. Invoked by ioctl(). */ int sel_loadlut(const unsigned long arg) { - int i = verify_area(VERIFY_READ, (char *) arg, 36); - if (i) - return i; - copy_from_user(inwordLut, (u32 *)(arg+4), 32); + int err; + + err = copy_from_user(inwordLut, (u32 *)(arg+4), 32); + if (err) + return -EFAULT; return 0; } @@ -120,10 +121,15 @@ int sel_mode, new_sel_start, new_sel_end, spc; char *bp, *obp; int i, ps, pe; + unsigned long num_lines, num_columns, size_row; do_unblank_screen(); poke_blanked_console(); + num_lines = get_video_num_lines(fg_console); + num_columns = get_video_num_columns(fg_console); + size_row = get_video_size_row(fg_console); + { unsigned short *args, xs, ys, xe, ye; args = (unsigned short *)(arg + 1); @@ -145,12 +151,12 @@ sel_mode = *args; } xs--; ys--; xe--; ye--; - xs = limit(xs, video_num_columns - 1); - ys = limit(ys, video_num_lines - 1); - xe = limit(xe, video_num_columns - 1); - ye = limit(ye, video_num_lines - 1); - ps = ys * video_size_row + (xs << 1); - pe = ye * video_size_row + (xe << 1); + xs = limit(xs, num_columns - 1); + ys = limit(ys, num_lines - 1); + xe = limit(xe, num_columns - 1); + ye = limit(ye, num_lines - 1); + ps = ys * size_row + (xs << 1); + pe = ye * size_row + (xe << 1); if (sel_mode == 4) { /* useful for screendump without selection highlights */ @@ -190,7 +196,7 @@ (!spc && !inword(sel_pos(ps)))) break; new_sel_start = ps; - if (!(ps % video_size_row)) + if (!(ps % size_row)) break; } spc = isspace(sel_pos(pe)); @@ -200,14 +206,14 @@ (!spc && !inword(sel_pos(pe)))) break; new_sel_end = pe; - if (!((pe + 2) % video_size_row)) + if (!((pe + 2) % size_row)) break; } break; case 2: /* line-by-line selection */ - new_sel_start = ps - ps % video_size_row; - new_sel_end = pe + video_size_row - - pe % video_size_row - 2; + new_sel_start = ps - ps % size_row; + new_sel_end = pe + size_row + - pe % size_row - 2; break; case 3: highlight_pointer(pe); @@ -268,7 +274,7 @@ *bp = sel_pos(i); if (!isspace(*bp++)) obp = bp; - if (! ((i + 2) % video_size_row)) { + if (! ((i + 2) % size_row)) { /* strip trailing blanks from line and add newline, unless non-space at end of line. */ if (obp != bp) { diff -u --recursive --new-file v2.1.41/linux/drivers/char/selection.h linux/drivers/char/selection.h --- v2.1.41/linux/drivers/char/selection.h Thu Feb 6 02:55:00 1997 +++ linux/drivers/char/selection.h Wed May 28 11:31:11 1997 @@ -3,6 +3,9 @@ * * Interface between console.c, tty_io.c, vt.c, vc_screen.c and selection.c */ + +#include + extern int sel_cons; extern void clear_selection(void); @@ -11,6 +14,16 @@ extern int sel_loadlut(const unsigned long arg); extern int mouse_reporting(void); extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry); + +#ifdef CONFIG_FB_CONSOLE +extern unsigned long get_video_num_columns(unsigned int console); +extern unsigned long get_video_num_lines(unsigned int console); +extern unsigned long get_video_size_row(unsigned int console); +#else +#define get_video_num_columns(dummy) video_num_columns +#define get_video_num_lines(dummy) video_num_lines +#define get_video_size_row(dummy) video_size_row +#endif extern unsigned long video_num_columns; extern unsigned long video_num_lines; diff -u --recursive --new-file v2.1.41/linux/drivers/char/stallion.c linux/drivers/char/stallion.c --- v2.1.41/linux/drivers/char/stallion.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/char/stallion.c Wed May 28 11:26:08 1997 @@ -3301,7 +3301,7 @@ len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)); if ((len == 0) || ((len < STL_TXBUFLOW) && (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { set_bit(ASYI_TXLOW, &portp->istate); - queue_task_irq_off(&portp->tqueue, &tq_scheduler); + queue_task(&portp->tqueue, &tq_scheduler); } if (len == 0) { @@ -3479,7 +3479,7 @@ misr = inb(ioaddr + EREG_DATA); if (misr & MISR_DCD) { set_bit(ASYI_DCDCHANGE, &portp->istate); - queue_task_irq_off(&portp->tqueue, &tq_scheduler); + queue_task(&portp->tqueue, &tq_scheduler); portp->stats.modem++; } @@ -4159,7 +4159,7 @@ len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)); if ((len == 0) || ((len < STL_TXBUFLOW) && (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { set_bit(ASYI_TXLOW, &portp->istate); - queue_task_irq_off(&portp->tqueue, &tq_scheduler); + queue_task(&portp->tqueue, &tq_scheduler); } if (len == 0) { @@ -4377,7 +4377,7 @@ ipr = stl_sc26198getreg(portp, IPR); if (ipr & IPR_DCDCHANGE) { set_bit(ASYI_DCDCHANGE, &portp->istate); - queue_task_irq_off(&portp->tqueue, &tq_scheduler); + queue_task(&portp->tqueue, &tq_scheduler); portp->stats.modem++; } break; diff -u --recursive --new-file v2.1.41/linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c --- v2.1.41/linux/drivers/char/vc_screen.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/char/vc_screen.c Wed May 28 10:49:08 1997 @@ -61,7 +61,19 @@ /* Multimon patch */ if (!vc_cons[currcons].d) return 0; #endif - size= video_num_lines * video_num_columns; +#ifdef CONFIG_FB_CONSOLE + int cons = MINOR(inode->i_rdev) & 127; + + if (cons == 0) + cons = fg_console; + else + cons--; + if (!vc_cons_allocated(cons)) + return -ENXIO; +#endif + + size = get_video_num_lines(cons) * get_video_num_columns(cons); + if (MINOR(inode->i_rdev) & 128) size = 2*size + HEADER_SIZE; return size; @@ -128,8 +140,8 @@ } else { if (p < HEADER_SIZE) { char header[HEADER_SIZE]; - header[0] = (char) video_num_lines; - header[1] = (char) video_num_columns; + header[0] = (char) get_video_num_lines(currcons); + header[1] = (char) get_video_num_columns(currcons); getconsxy(currcons, header+2); while (p < HEADER_SIZE && count > 0) { count--; put_user(header[p++], buf++); } diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/Config.in linux/drivers/isdn/Config.in --- v2.1.41/linux/drivers/isdn/Config.in Tue May 13 22:41:07 1997 +++ linux/drivers/isdn/Config.in Wed May 28 10:49:08 1997 @@ -16,11 +16,17 @@ 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 Elsa ISA cards' CONFIG_HISAX_ELSA_PCC + bool 'HiSax Support for Elsa PCMCIA card' CONFIG_HISAX_ELSA_PCMCIA 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 US/NI-1' CONFIG_HISAX_NI1 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 +dep_tristate 'AVM-B1 with CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN +if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then + bool 'Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON fi diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/Makefile linux/drivers/isdn/Makefile --- v2.1.41/linux/drivers/isdn/Makefile Tue May 13 22:41:07 1997 +++ linux/drivers/isdn/Makefile Wed May 28 10:49:08 1997 @@ -1,6 +1,6 @@ SUB_DIRS := MOD_SUB_DIRS := -ALL_SUB_DIRS := icn pcbit hisax +ALL_SUB_DIRS := icn pcbit hisax avmb1 L_OBJS := LX_OBJS := @@ -73,6 +73,26 @@ else ifeq ($(CONFIG_ISDN_DRV_SC),m) MOD_SUB_DIRS += sc + endif +endif + +ifeq ($(CONFIG_ISDN_DRV_AVMB1),y) + L_OBJS += avmb1/avmb1.o + SUB_DIRS += avmb1 + MOD_SUB_DIRS += avmb1 +else + ifeq ($(CONFIG_ISDN_DRV_AVMB1),m) + MOD_SUB_DIRS += avmb1 + endif +endif + +ifeq ($(CONFIG_ISDN_DRV_LOOP),y) + L_OBJS += isdnloop/isdnloop.o + SUB_DIRS += isdnloop + MOD_SUB_DIRS += isdnloop +else + ifeq ($(CONFIG_ISDN_DRV_LOOP),m) + MOD_SUB_DIRS += isdnloop endif endif diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/avmb1/Makefile linux/drivers/isdn/avmb1/Makefile --- v2.1.41/linux/drivers/isdn/avmb1/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/Makefile Wed May 28 10:49:09 1997 @@ -0,0 +1,77 @@ +# +# $Id: Makefile,v 1.4 1997/03/30 17:10:40 calle Exp $ +# +# Makefile for the CAPI and AVM-B1 device drivers. +# +# 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.. +# +# $Log: Makefile,v $ +# Revision 1.4 1997/03/30 17:10:40 calle +# added support for AVM-B1-PCI card. +# +# Revision 1.3 1997/03/22 02:00:57 fritz +# -Reworked toplevel Makefile. From now on, no different Makefiles +# for standalone- and in-kernel-compilation are needed any more. +# -Added local Rules.make for above reason. +# -Experimental changes in teles3.c for enhanced IRQ-checking with +# 2.1.X and SMP kernels. +# -Removed diffstd-script, same functionality is in stddiff -r. +# -Enhanced scripts std2kern and stddiff. +# +# Revision 1.1 1997/03/05 21:26:14 fritz +# Renamed, according naming conventions in CVS tree. +# +# Revision 1.1 1997/03/04 21:50:26 calle +# Frirst version in isdn4linux +# +# Revision 2.2 1997/02/12 09:31:39 calle +# +# Revision 1.1 1997/01/31 10:32:20 calle +# Initial revision +# +# + +# +# Objects that don't export a symtab +# +L_OBJS := # used as component of an L_TARGET +O_OBJS := # used as component of an O_TARGET +M_OBJS := # used as module +# +# Objects that do export a symtab +# +LX_OBJS := # used as component of an L_TARGET +OX_OBJS := # used as component of an O_TARGET +MX_OBJS := # used as module +# +# Targets, created by linking others +# +O_TARGET := # used for .o targets (from O and OX objects) +L_TARGET := # used for .a targets (from L and LX objects) + +ifeq ($(CONFIG_ISDN_DRV_AVMB1),y) + O_TARGET += avmb1.o + O_OBJS += capi.o b1lli.o + OX_OBJS += capiutil.o b1capi.o capidrv.o + ifdef CONFIG_PCI + OX_OBJS += b1pci.o + endif +else + ifeq ($(CONFIG_ISDN_DRV_AVMB1),m) + O_TARGET += kernelcapi.o + O_OBJS += b1lli.o + OX_OBJS += b1capi.o + M_OBJS += capi.o kernelcapi.o + MX_OBJS += capiutil.o capidrv.o + ifdef CONFIG_PCI + MX_OBJS += b1pci.o + endif + endif +endif + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/avmb1/b1capi.c linux/drivers/isdn/avmb1/b1capi.c --- v2.1.41/linux/drivers/isdn/avmb1/b1capi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/b1capi.c Wed May 28 10:49:09 1997 @@ -0,0 +1,946 @@ +/* + * $Id: b1capi.c,v 1.4 1997/05/27 15:17:45 fritz Exp $ + * + * CAPI 2.0 Module for AVM B1-card. + * + * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: b1capi.c,v $ + * Revision 1.4 1997/05/27 15:17:45 fritz + * Added changes for recent 2.1.x kernels: + * changed return type of isdn_close + * queue_task_* -> queue_task + * clear/set_bit -> test_and_... where apropriate. + * changed type of hard_header_cache parameter. + * + * Revision 1.3 1997/05/18 09:24:09 calle + * added verbose disconnect reason reporting to avmb1. + * some fixes in capi20 interface. + * changed info messages for B1-PCI + * + * Revision 1.2 1997/03/05 21:20:41 fritz + * Removed include of config.h (mkdep stated this is unneded). + * + * Revision 1.1 1997/03/04 21:50:27 calle + * Frirst version in isdn4linux + * + * Revision 2.2 1997/02/12 09:31:39 calle + * new version + * + * Revision 1.1 1997/01/31 10:32:20 calle + * Initial revision + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "compat.h" +#include "capicmd.h" +#include "capiutil.h" + +static char *revision = "$Revision: 1.4 $"; + +/* ------------------------------------------------------------- */ + +int portbase = 0x150; +int irq = 15; +int showcapimsgs = 0; /* used in lli.c */ +int loaddebug = 0; + +#ifdef HAS_NEW_SYMTAB +MODULE_AUTHOR("Carsten Paeth "); +MODULE_PARM(portbase, "i"); +MODULE_PARM(irq, "2-15i"); +MODULE_PARM(showcapimsgs, "0-3i"); +MODULE_PARM(loaddebug, "0-1i"); +#endif + +/* ------------------------------------------------------------- */ + +struct msgidqueue { + struct msgidqueue *next; + __u16 msgid; +}; + +typedef struct avmb1_ncci { + struct avmb1_ncci *next; + __u16 applid; + __u32 ncci; + __u32 winsize; + struct msgidqueue *msgidqueue; + struct msgidqueue *msgidlast; + struct msgidqueue *msgidfree; + struct msgidqueue msgidpool[CAPI_MAXDATAWINDOW]; +} avmb1_ncci; + +typedef struct avmb1_appl { + __u16 applid; + capi_register_params rparam; + int releasing; + __u32 param; + void (*signal) (__u16 applid, __u32 param); + struct sk_buff_head recv_queue; + struct avmb1_ncci *nccilist; +} avmb1_appl; + +/* ------------------------------------------------------------- */ + +static struct capi_version driver_version = {2, 0, 0, 9}; +static char driver_serial[CAPI_SERIAL_LEN] = "4711"; +static char capi_manufakturer[64] = "AVM Berlin"; + +#define APPL(a) (&applications[(a)-1]) +#define VALID_APPLID(a) ((a) && (a) <= CAPI_MAXAPPL && APPL(a)->applid == a) +#define APPL_IS_FREE(a) (APPL(a)->applid == 0) +#define APPL_MARK_FREE(a) do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0); +#define APPL_MARK_USED(a) do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0); + +#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f) + +#define VALID_CARD(c) ((c) > 0 && (c) <= ncards) +#define CARD(c) (&cards[(c)-1]) +#define CARDNR(cp) ((cards-(cp))+1) + +static avmb1_appl applications[CAPI_MAXAPPL]; +static avmb1_card cards[CAPI_MAXCONTR]; +static int ncards = 0; +static struct sk_buff_head recv_queue; +static struct capi_interface_user *capi_users = 0; +static long notify_up_set = 0; +static long notify_down_set = 0; + +static struct tq_struct tq_state_notify; +static struct tq_struct tq_recv_notify; + +/* -------- util functions ------------------------------------ */ + +static inline int capi_cmd_valid(__u8 cmd) +{ + switch (cmd) { + case CAPI_ALERT: + case CAPI_CONNECT: + case CAPI_CONNECT_ACTIVE: + case CAPI_CONNECT_B3_ACTIVE: + case CAPI_CONNECT_B3: + case CAPI_CONNECT_B3_T90_ACTIVE: + case CAPI_DATA_B3: + case CAPI_DISCONNECT_B3: + case CAPI_DISCONNECT: + case CAPI_FACILITY: + case CAPI_INFO: + case CAPI_LISTEN: + case CAPI_MANUFACTURER: + case CAPI_RESET_B3: + case CAPI_SELECT_B_PROTOCOL: + return 1; + } + return 0; +} + +static inline int capi_subcmd_valid(__u8 subcmd) +{ + switch (subcmd) { + case CAPI_REQ: + case CAPI_CONF: + case CAPI_IND: + case CAPI_RESP: + return 1; + } + return 0; +} + +/* -------- NCCI Handling ------------------------------------- */ + +static inline void mq_init(avmb1_ncci * np) +{ + int i; + np->msgidqueue = 0; + np->msgidlast = 0; + memset(np->msgidpool, 0, sizeof(np->msgidpool)); + np->msgidfree = &np->msgidpool[0]; + for (i = 1; i < np->winsize; i++) { + np->msgidpool[i].next = np->msgidfree; + np->msgidfree = &np->msgidpool[i]; + } +} + +static inline int mq_enqueue(avmb1_ncci * np, __u16 msgid) +{ + struct msgidqueue *mq; + if ((mq = np->msgidfree) == 0) + return 0; + np->msgidfree = mq->next; + mq->msgid = msgid; + mq->next = 0; + if (np->msgidlast) + np->msgidlast->next = mq; + np->msgidlast = mq; + if (!np->msgidqueue) + np->msgidqueue = mq; + return 1; +} + +static inline int mq_dequeue(avmb1_ncci * np, __u16 msgid) +{ + struct msgidqueue **pp; + for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) { + if ((*pp)->msgid == msgid) { + struct msgidqueue *mq = *pp; + *pp = mq->next; + if (mq == np->msgidlast) + np->msgidlast = 0; + mq->next = np->msgidfree; + np->msgidfree = mq; + return 1; + } + } + return 0; +} + +void avmb1_handle_new_ncci(avmb1_card * card, + __u16 appl, __u32 ncci, __u32 winsize) +{ + avmb1_ncci *np; + if (!VALID_APPLID(appl)) { + printk(KERN_ERR "avmb1_handle_new_ncci: illegal appl %d\n", appl); + return; + } + if ((np = (avmb1_ncci *) kmalloc(sizeof(avmb1_ncci), GFP_ATOMIC)) == 0) { + printk(KERN_ERR "avmb1_handle_new_ncci: alloc failed ncci 0x%x\n", ncci); + return; + } + if (winsize > CAPI_MAXDATAWINDOW) { + printk(KERN_ERR "avmb1_handle_new_ncci: winsize %d too big, set to %d\n", + winsize, CAPI_MAXDATAWINDOW); + winsize = CAPI_MAXDATAWINDOW; + } + np->applid = appl; + np->ncci = ncci; + np->winsize = winsize; + mq_init(np); + np->next = APPL(appl)->nccilist; + APPL(appl)->nccilist = np; + printk(KERN_INFO "b1capi: appl %d ncci 0x%x up\n", appl, ncci); + +} + +void avmb1_handle_free_ncci(avmb1_card * card, + __u16 appl, __u32 ncci) +{ + if (!VALID_APPLID(appl)) { + printk(KERN_ERR "avmb1_handle_free_ncci: illegal appl %d\n", appl); + return; + } + if (ncci != 0xffffffff) { + avmb1_ncci **pp; + for (pp = &APPL(appl)->nccilist; *pp; pp = &(*pp)->next) { + if ((*pp)->ncci == ncci) { + avmb1_ncci *np = *pp; + *pp = np->next; + kfree(np); + printk(KERN_INFO "b1capi: appl %d ncci 0x%x down\n", appl, ncci); + return; + } + } + printk(KERN_ERR "avmb1_handle_free_ncci: ncci 0x%x not found\n", ncci); + } else { + avmb1_ncci **pp, **nextpp; + for (pp = &APPL(appl)->nccilist; *pp; pp = nextpp) { + if (NCCI2CTRL((*pp)->ncci) == card->cnr) { + avmb1_ncci *np = *pp; + *pp = np->next; + printk(KERN_INFO "b1capi: appl %d ncci 0x%x down!\n", appl, np->ncci); + kfree(np); + nextpp = pp; + } else { + nextpp = &(*pp)->next; + } + } + APPL(appl)->releasing--; + if (APPL(appl)->releasing == 0) { + APPL(appl)->signal = 0; + APPL_MARK_FREE(appl); + printk(KERN_INFO "b1capi: appl %d down\n", appl); + } + } +} + +static avmb1_ncci *find_ncci(avmb1_appl * app, __u32 ncci) +{ + avmb1_ncci *np; + for (np = app->nccilist; np; np = np->next) { + if (np->ncci == ncci) + return np; + } + return 0; +} + +/* -------- Receiver ------------------------------------------ */ + + +static void recv_handler(void *dummy) +{ + struct sk_buff *skb; + + while ((skb = skb_dequeue(&recv_queue)) != 0) { + __u16 appl = CAPIMSG_APPID(skb->data); + struct avmb1_ncci *np; + if (!VALID_APPLID(appl)) { + printk(KERN_ERR "b1capi: recv_handler: applid %d ? (%s)\n", + appl, capi_message2str(skb->data)); + kfree_skb(skb, FREE_READ); + continue; + } + if (APPL(appl)->signal == 0) { + printk(KERN_ERR "b1capi: recv_handler: applid %d has no signal function\n", + appl); + kfree_skb(skb, FREE_READ); + continue; + } + if ( CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3 + && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF + && (np = find_ncci(APPL(appl), CAPIMSG_NCCI(skb->data))) != 0 + && mq_dequeue(np, CAPIMSG_MSGID(skb->data)) == 0) { + printk(KERN_ERR "b1capi: msgid %hu ncci 0x%x not on queue\n", + CAPIMSG_MSGID(skb->data), np->ncci); + } + skb_queue_tail(&APPL(appl)->recv_queue, skb); + (APPL(appl)->signal) (APPL(appl)->applid, APPL(appl)->param); + } +} + + +void avmb1_handle_capimsg(avmb1_card * card, __u16 appl, struct sk_buff *skb) +{ + if (card->cardstate != CARD_RUNNING) { + printk(KERN_INFO "b1capi: controller %d not active, got: %s", + card->cnr, capi_message2str(skb->data)); + goto error; + return; + } + skb_queue_tail(&recv_queue, skb); + queue_task(&tq_recv_notify, &tq_immediate); + mark_bh(IMMEDIATE_BH); + return; + + error: + kfree_skb(skb, FREE_READ); +} + +void avmb1_interrupt(int interrupt, void *devptr, struct pt_regs *regs) +{ + avmb1_card *card; + + card = (avmb1_card *) devptr; + + if (!card) { + printk(KERN_WARNING "avmb1_interrupt: wrong device\n"); + return; + } + if (card->interrupt) { + printk(KERN_ERR "avmb1_interrupt: reentering interrupt hander\n"); + return; + } + + card->interrupt = 1; + + B1_handle_interrupt(card); + + card->interrupt = 0; +} + +/* -------- Notifier ------------------------------------------ */ + +static void notify_up(__u16 contr) +{ + struct capi_interface_user *p; + + for (p = capi_users; p; p = p->next) { + if (p->callback) + (*p->callback) (KCI_CONTRUP, contr, + (capi_profile *) + CARD(contr)->version[VER_PROFILE]); + } +} + +static void notify_down(__u16 contr) +{ + struct capi_interface_user *p; + for (p = capi_users; p; p = p->next) { + if (p->callback) + (*p->callback) (KCI_CONTRDOWN, contr, 0); + } +} + +static void notify_handler(void *dummy) +{ + __u16 contr; + + for (contr=1; VALID_CARD(contr); contr++) + if (test_and_clear_bit(contr, ¬ify_up_set)) + notify_up(contr); + for (contr=1; VALID_CARD(contr); contr++) + if (test_and_clear_bit(contr, ¬ify_down_set)) + notify_down(contr); +} + +/* -------- card ready callback ------------------------------- */ + +void avmb1_card_ready(avmb1_card * card) +{ + __u16 appl; + + card->cversion.majorversion = 2; + card->cversion.minorversion = 0; + card->cversion.majormanuversion = (card->version[VER_DRIVER][0] - '0') << 4; + card->cversion.majormanuversion |= (card->version[VER_DRIVER][2] - '0'); + card->cversion.minormanuversion = (card->version[VER_DRIVER][3] - '0') << 4; + card->cversion.minormanuversion |= (card->version[VER_DRIVER][5] - '0') * 10; + card->cversion.minormanuversion |= (card->version[VER_DRIVER][6] - '0'); + card->cardstate = CARD_RUNNING; + + + for (appl = 1; appl <= CAPI_MAXAPPL; appl++) { + if (VALID_APPLID(appl) && !APPL(appl)->releasing) { + B1_send_register(card->port, appl, + 1024 * (APPL(appl)->rparam.level3cnt+1), + APPL(appl)->rparam.level3cnt, + APPL(appl)->rparam.datablkcnt, + APPL(appl)->rparam.datablklen); + } + } + + set_bit(CARDNR(card), ¬ify_up_set); + queue_task(&tq_state_notify, &tq_scheduler); +} + +/* ------------------------------------------------------------- */ + +int avmb1_addcard(int port, int irq) +{ + struct avmb1_card *card; + int irqval; + + + card = &cards[ncards]; + memset(card, 0, sizeof(avmb1_card)); + sprintf(card->name, "avmb1-%d", ncards + 1); + + request_region(port, AVMB1_PORTLEN, card->name); + + if ((irqval = request_irq(irq, avmb1_interrupt, SA_SHIRQ, card->name, card)) != 0) { + printk(KERN_ERR "b1capi: unable to get IRQ %d (irqval=%d).\n", + irq, irqval); + release_region((unsigned short) port, AVMB1_PORTLEN); + return -EIO; + } + ncards++; + card->cnr = ncards; + card->port = port; + card->irq = irq; + card->cardstate = CARD_DETECTED; + return 0; +} + +int avmb1_probecard(int port, int irq) +{ + int rc; + + if (check_region((unsigned short) port, AVMB1_PORTLEN)) { + printk(KERN_WARNING + "b1capi: ports 0x%03x-0x%03x in use.\n", + portbase, portbase + AVMB1_PORTLEN); + return -EIO; + } + if (!B1_valid_irq(irq)) { + printk(KERN_WARNING "b1capi: irq %d not valid.\n", irq); + return -EIO; + } + if ((rc = B1_detect(port)) != 0) { + printk(KERN_NOTICE "b1capi: NO card at 0x%x (%d)\n", port, rc); + return -EIO; + } + B1_reset(port); + printk(KERN_NOTICE "b1capi: AVM-B1-Controller detected at 0x%x\n", port); + + return 0; +} + +/* ------------------------------------------------------------- */ +/* -------- CAPI2.0 Interface ---------------------------------- */ +/* ------------------------------------------------------------- */ + +static int capi_installed(void) +{ + int i; + for (i = 0; i < ncards; i++) { + if (cards[i].cardstate == CARD_RUNNING) + return 1; + } + return 0; +} + +static __u16 capi_register(capi_register_params * rparam, __u16 * applidp) +{ + int i; + int appl; + + if (rparam->datablklen < 128) + return CAPI_LOGBLKSIZETOSMALL; + + for (appl = 1; appl <= CAPI_MAXAPPL; appl++) { + if (APPL_IS_FREE(appl)) + break; + } + if (appl > CAPI_MAXAPPL) + return CAPI_TOOMANYAPPLS; + + APPL_MARK_USED(appl); + skb_queue_head_init(&APPL(appl)->recv_queue); + + memcpy(&APPL(appl)->rparam, rparam, sizeof(capi_register_params)); + + for (i = 0; i < ncards; i++) { + if (cards[i].cardstate != CARD_RUNNING) + continue; + B1_send_register(cards[i].port, appl, + 1024 * (APPL(appl)->rparam.level3cnt + 1), + APPL(appl)->rparam.level3cnt, + APPL(appl)->rparam.datablkcnt, + APPL(appl)->rparam.datablklen); + } + *applidp = appl; + printk(KERN_INFO "b1capi: appl %d up\n", appl); + + return CAPI_NOERROR; +} + +static __u16 capi_release(__u16 applid) +{ + struct sk_buff *skb; + int i; + + if (ncards == 0) + return CAPI_REGNOTINSTALLED; + if (!VALID_APPLID(applid) || APPL(applid)->releasing) + return CAPI_ILLAPPNR; + while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0) + kfree_skb(skb, FREE_READ); + for (i = 0; i < ncards; i++) { + if (cards[i].cardstate != CARD_RUNNING) + continue; + APPL(applid)->releasing++; + B1_send_release(cards[i].port, applid); + } + if (APPL(applid)->releasing == 0) { + APPL(applid)->signal = 0; + APPL_MARK_FREE(applid); + printk(KERN_INFO "b1capi: appl %d down\n", applid); + } + return CAPI_NOERROR; +} + +static __u16 capi_put_message(__u16 applid, struct sk_buff *skb) +{ + avmb1_ncci *np; + int contr; + if (ncards == 0) + return CAPI_REGNOTINSTALLED; + if (!VALID_APPLID(applid)) + return CAPI_ILLAPPNR; + if (skb->len < 12 + || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data)) + || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data))) + return CAPI_ILLCMDORSUBCMDORMSGTOSMALL; + contr = CAPIMSG_CONTROLLER(skb->data); + if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) { + contr = 1; + if (CARD(contr)->cardstate != CARD_RUNNING) + return CAPI_REGNOTINSTALLED; + } + if (CARD(contr)->blocked) + return CAPI_SENDQUEUEFULL; + + if ( CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3 + && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_REQ + && (np = find_ncci(APPL(applid), CAPIMSG_NCCI(skb->data))) != 0 + && mq_enqueue(np, CAPIMSG_MSGID(skb->data)) == 0) + return CAPI_SENDQUEUEFULL; + + B1_send_message(CARD(contr)->port, skb); + return CAPI_NOERROR; +} + +static __u16 capi_get_message(__u16 applid, struct sk_buff **msgp) +{ + struct sk_buff *skb; + + if (!VALID_APPLID(applid)) + return CAPI_ILLAPPNR; + if ((skb = skb_dequeue(&APPL(applid)->recv_queue)) == 0) + return CAPI_RECEIVEQUEUEEMPTY; + *msgp = skb; + return CAPI_NOERROR; +} + +static __u16 capi_set_signal(__u16 applid, + void (*signal) (__u16 applid, __u32 param), + __u32 param) +{ + if (!VALID_APPLID(applid)) + return CAPI_ILLAPPNR; + APPL(applid)->signal = signal; + APPL(applid)->param = param; + return CAPI_NOERROR; +} + +static __u16 capi_get_manufacturer(__u16 contr, __u8 buf[CAPI_MANUFACTURER_LEN]) +{ + if (contr == 0) { + strncpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN); + return CAPI_NOERROR; + } + if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) + return 0x2002; + + strncpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN); + return CAPI_NOERROR; +} + +static __u16 capi_get_version(__u16 contr, struct capi_version *verp) +{ + if (contr == 0) { + *verp = driver_version; + return CAPI_NOERROR; + } + if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) + return 0x2002; + + memcpy((void *) verp, CARD(contr)->version[VER_SERIAL], + sizeof(capi_version)); + return CAPI_NOERROR; +} + +static __u16 capi_get_serial(__u16 contr, __u8 serial[CAPI_SERIAL_LEN]) +{ + if (contr == 0) { + strncpy(serial, driver_serial, 8); + return CAPI_NOERROR; + } + if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) + return 0x2002; + + memcpy((void *) serial, CARD(contr)->version[VER_SERIAL], + CAPI_SERIAL_LEN); + serial[CAPI_SERIAL_LEN - 1] = 0; + return CAPI_NOERROR; +} + +static __u16 capi_get_profile(__u16 contr, struct capi_profile *profp) +{ + if (contr == 0) { + profp->ncontroller = ncards; + return CAPI_NOERROR; + } + if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) + return 0x2002; + + memcpy((void *) profp, CARD(contr)->version[VER_PROFILE], + sizeof(struct capi_profile)); + return CAPI_NOERROR; +} + +static int capi_manufacturer(unsigned int cmd, void *data) +{ + unsigned long flags; + avmb1_loaddef ldef; + avmb1_carddef cdef; + avmb1_resetdef rdef; + avmb1_card *card; + int rc; + + switch (cmd) { + case AVMB1_ADDCARD: + if ((rc = copy_from_user((void *) &cdef, data, + sizeof(avmb1_carddef)))) + return rc; + if (!B1_valid_irq(cdef.irq)) + return -EINVAL; + + if ((rc = avmb1_probecard(cdef.port, cdef.irq)) != 0) + return rc; + + return avmb1_addcard(cdef.port, cdef.irq); + + case AVMB1_LOAD: + + if ((rc = copy_from_user((void *) &ldef, data, + sizeof(avmb1_loaddef)))) + return rc; + if (!VALID_CARD(ldef.contr) || ldef.t4file.len <= 0) { + if (loaddebug) + printk(KERN_DEBUG "b1capi: load: invalid parameter contr=%d len=%d\n", ldef.contr, ldef.t4file.len); + return -EINVAL; + } + + card = CARD(ldef.contr); + save_flags(flags); + cli(); + if (card->cardstate != CARD_DETECTED) { + restore_flags(flags); + if (loaddebug) + printk(KERN_DEBUG "b1capi: load: contr=%d not in detect state\n", ldef.contr); + return -EBUSY; + } + card->cardstate = CARD_LOADING; + restore_flags(flags); + + if (loaddebug) { + printk(KERN_DEBUG "b1capi: load: reseting contr %d\n", + ldef.contr); + } + + B1_reset(card->port); + if ((rc = B1_load_t4file(card->port, &ldef.t4file))) { + B1_reset(card->port); + printk(KERN_ERR "b1capi: failed to load t4file!!\n"); + card->cardstate = CARD_DETECTED; + return rc; + } + B1_disable_irq(card->port); + if (loaddebug) { + printk(KERN_DEBUG "b1capi: load: ready contr %d: checking\n", + ldef.contr); + } + + if (!B1_loaded(card->port)) { + card->cardstate = CARD_DETECTED; + printk(KERN_ERR "b1capi: failed to load t4file.\n"); + return -EIO; + } + /* + * enable interrupt + */ + + card->cardstate = CARD_INITSTATE; + save_flags(flags); + cli(); + B1_assign_irq(card->port, card->irq); + B1_enable_irq(card->port); + restore_flags(flags); + + if (loaddebug) { + printk(KERN_DEBUG "b1capi: load: irq enabled contr %d\n", + ldef.contr); + } + + /* + * init card + */ + B1_send_init(card->port, AVM_NAPPS, AVM_NNCCI, card->cnr - 1); + + if (loaddebug) { + printk(KERN_DEBUG "b1capi: load: waiting for init reply contr %d\n", + ldef.contr); + } + + while (card->cardstate != CARD_RUNNING) { + + current->timeout = jiffies + HZ / 10; /* 0.1 sec */ + current->state = TASK_INTERRUPTIBLE; + schedule(); + + if (current->signal & ~current->blocked) + return -EINTR; + } + return 0; + case AVMB1_RESETCARD: + if ((rc = copy_from_user((void *) &rdef, data, + sizeof(avmb1_resetdef)))) + return rc; + + if (!VALID_CARD(rdef.contr)) + return -EINVAL; + + card = CARD(rdef.contr); + + if (card->cardstate == CARD_RUNNING) + return -EBUSY; + + B1_reset(card->port); + B1_reset(card->port); + + card->cardstate = CARD_DETECTED; + return 0; + } + return -EINVAL; +} + +struct capi_interface avmb1_interface = +{ + capi_installed, + capi_register, + capi_release, + capi_put_message, + capi_get_message, + capi_set_signal, + capi_get_manufacturer, + capi_get_version, + capi_get_serial, + capi_get_profile, + capi_manufacturer +}; + +/* ------------------------------------------------------------- */ +/* -------- Exported Functions --------------------------------- */ +/* ------------------------------------------------------------- */ + +struct capi_interface *attach_capi_interface(struct capi_interface_user *userp) +{ + struct capi_interface_user *p; + + for (p = capi_users; p; p = p->next) { + if (p == userp) { + printk(KERN_ERR "b1capi: double attach from %s\n", + userp->name); + return 0; + } + } + userp->next = capi_users; + capi_users = userp; + MOD_INC_USE_COUNT; + + return &avmb1_interface; +} + +int detach_capi_interface(struct capi_interface_user *userp) +{ + struct capi_interface_user **pp; + + for (pp = &capi_users; *pp; pp = &(*pp)->next) { + if (*pp == userp) { + *pp = userp->next; + userp->next = 0; + MOD_DEC_USE_COUNT; + return 0; + } + } + printk(KERN_ERR "b1capi: double detach from %s\n", userp->name); + return -1; +} + +/* ------------------------------------------------------------- */ +/* -------- Init & Cleanup ------------------------------------- */ +/* ------------------------------------------------------------- */ + +#ifdef HAS_NEW_SYMTAB +EXPORT_SYMBOL(attach_capi_interface); +EXPORT_SYMBOL(detach_capi_interface); +EXPORT_SYMBOL(avmb1_addcard); +EXPORT_SYMBOL(avmb1_probecard); +#else +static struct symbol_table capidev_syms = +{ +#include + X(attach_capi_interface), + X(detach_capi_interface), + X(avmb1_addcard), + X(avmb1_probecard), +#include +}; +#endif + + +/* + * init / exit functions + */ + +#ifdef MODULE +#define avmb1_init init_module +#endif + +int avmb1_init(void) +{ + char *p; + char rev[10]; + + +#ifndef HAS_NEW_SYMTAB + /* No symbols to export, hide all symbols */ + register_symtab(&capidev_syms); +#endif + skb_queue_head_init(&recv_queue); + /* init_bh(CAPI_BH, do_capi_bh); */ + + tq_state_notify.routine = notify_handler; + tq_state_notify.data = 0; + + tq_recv_notify.routine = recv_handler; + tq_recv_notify.data = 0; + + + if ((p = strchr(revision, ':'))) { + strcpy(rev, p + 1); + p = strchr(rev, '$'); + *p = 0; + } else + strcpy(rev, " ??? "); + +#ifdef MODULE + if (portbase) { + int rc; + if ((rc = avmb1_probecard(portbase, irq)) != 0) + return rc; + if ((rc = avmb1_addcard(portbase, irq)) != 0) + return rc; + } else { + printk(KERN_NOTICE "AVM-B1-CAPI-driver Rev%s: loaded\n", rev); + } +#else + printk(KERN_NOTICE "AVM-B1-CAPI-driver Rev%s: started\n", rev); +#endif + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + char rev[10]; + char *p; + int i; + + if ((p = strchr(revision, ':'))) { + strcpy(rev, p + 1); + p = strchr(rev, '$'); + *p = 0; + } else { + strcpy(rev, " ??? "); + } + + for (i = 0; i < ncards; i++) { + /* + * disable card + */ + B1_disable_irq(cards[i].port); + B1_reset(cards[i].port); + B1_reset(cards[i].port); + /* + * free kernel resources + */ + free_irq(cards[i].irq, &cards[i]); + release_region(cards[i].port, AVMB1_PORTLEN); + + } + printk(KERN_NOTICE "AVM-B1-CAPI-driver Rev%s: unloaded\n", rev); +} +#endif diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/avmb1/b1lli.c linux/drivers/isdn/avmb1/b1lli.c --- v2.1.41/linux/drivers/isdn/avmb1/b1lli.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/b1lli.c Wed May 28 10:49:09 1997 @@ -0,0 +1,594 @@ +/* + * $Id: b1lli.c,v 1.1 1997/03/04 21:50:28 calle Exp $ + * + * ISDN lowlevel-module for AVM B1-card. + * + * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: b1lli.c,v $ + * Revision 1.1 1997/03/04 21:50:28 calle + * Frirst version in isdn4linux + * + * Revision 2.2 1997/02/12 09:31:39 calle + * new version + * + * Revision 1.1 1997/01/31 10:32:20 calle + * Initial revision + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "compat.h" +#include "capicmd.h" +#include "capiutil.h" + +/* + * LLI Messages to the ISDN-ControllerISDN Controller + */ + +#define SEND_POLL 0x72 /* + * after load <- RECEIVE_POLL + */ +#define SEND_INIT 0x11 /* + * first message <- RECEIVE_INIT + * int32 NumApplications int32 + * NumNCCIs int32 BoardNumber + */ +#define SEND_REGISTER 0x12 /* + * register an application int32 + * ApplIDId int32 NumMessages + * int32 NumB3Connections int32 + * NumB3Blocks int32 B3Size + * + * AnzB3Connection != 0 && + * AnzB3Blocks >= 1 && B3Size >= 1 + */ +#define SEND_RELEASE 0x14 /* + * deregister an application int32 + * ApplID + */ +#define SEND_MESSAGE 0x15 /* + * send capi-message int32 length + * capi-data ... + */ +#define SEND_DATA_B3_REQ 0x13 /* + * send capi-data-message int32 + * MsgLength capi-data ... int32 + * B3Length data .... + */ + +/* + * LLI Messages from the ISDN-ControllerISDN Controller + */ + +#define RECEIVE_POLL 0x32 /* + * <- after SEND_POLL + */ +#define RECEIVE_INIT 0x27 /* + * <- after SEND_INIT int32 length + * byte total length b1struct board + * driver revision b1struct card + * type b1struct reserved b1struct + * serial number b1struct driver + * capability b1struct d-channel + * protocol b1struct CAPI-2.0 + * profile b1struct capi version + */ +#define RECEIVE_MESSAGE 0x21 /* + * <- after SEND_MESSAGE int32 + * AppllID int32 Length capi-data + * .... + */ +#define RECEIVE_DATA_B3_IND 0x22 /* + * received data int32 AppllID + * int32 Length capi-data ... + * int32 B3Length data ... + */ +#define RECEIVE_START 0x23 /* + * Handshake + */ +#define RECEIVE_STOP 0x24 /* + * Handshake + */ +#define RECEIVE_NEW_NCCI 0x25 /* + * int32 AppllID int32 NCCI int32 + * WindowSize + */ +#define RECEIVE_FREE_NCCI 0x26 /* + * int32 AppllID int32 NCCI + */ +#define RECEIVE_RELEASE 0x26 /* + * int32 AppllID int32 0xffffffff + */ + +/* + * port offsets + */ + +#define B1_READ 0x00 +#define B1_WRITE 0x01 +#define B1_INSTAT 0x02 +#define B1_OUTSTAT 0x03 +#define B1_RESET 0x10 +#define B1_ANALYSE 0x04 + + + +static inline unsigned char b1outp(unsigned short base, + unsigned short offset, + unsigned char value) +{ + outb(value, base + offset); + return inb(base + B1_ANALYSE); +} + +static int irq_table[16] = +{0, + 0, + 0, + 192, /* irq 3 */ + 32, /* irq 4 */ + 160, /* irq 5 */ + 96, /* irq 6 */ + 224, /* irq 7 */ + 0, + 64, /* irq 9 */ + 80, /* irq 10 */ + 208, /* irq 11 */ + 48, /* irq 12 */ + 0, + 0, + 112, /* irq 15 */ +}; + +int B1_valid_irq(unsigned irq) +{ + return irq_table[irq] != 0; +} + +unsigned char B1_assign_irq(unsigned short base, unsigned irq) +{ + return b1outp(base, B1_RESET, irq_table[irq]); +} + +unsigned char B1_enable_irq(unsigned short base) +{ + return b1outp(base, B1_INSTAT, 0x02); +} + +unsigned char B1_disable_irq(unsigned short base) +{ + return b1outp(base, B1_INSTAT, 0x00); +} + +void B1_reset(unsigned short base) +{ + b1outp(base, B1_RESET, 0); + udelay(55 * 2 * 1000); /* 2 TIC's */ + + b1outp(base, B1_RESET, 1); + udelay(55 * 2 * 1000); /* 2 TIC's */ + + b1outp(base, B1_RESET, 0); + udelay(55 * 2 * 1000); /* 2 TIC's */ +} + +int B1_detect(unsigned short base) +{ + /* + * Statusregister 0000 00xx + */ + if ((inb(base + B1_INSTAT) & 0xfc) + || (inb(base + B1_OUTSTAT) & 0xfc)) + return 1; + + /* + * Statusregister 0000 001x + */ + b1outp(base, B1_INSTAT, 0x2); /* enable irq */ + b1outp(base, B1_OUTSTAT, 0x2); + if ((inb(base + B1_INSTAT) & 0xfe) != 0x2 + || (inb(base + B1_OUTSTAT) & 0xfe) != 0x2) + return 2; + + /* + * Statusregister 0000 000x + */ + b1outp(base, B1_INSTAT, 0x0); /* disable irq */ + b1outp(base, B1_OUTSTAT, 0x0); + if ((inb(base + B1_INSTAT) & 0xfe) + || (inb(base + B1_OUTSTAT) & 0xfe)) + return 3; + + return 0; +} + +static inline int B1_rx_full(unsigned short base) +{ + return inb(base + B1_INSTAT) & 0x1; +} + +static inline unsigned char B1_get_byte(unsigned short base) +{ + unsigned long i = jiffies + 5 * HZ; /* maximum wait time 5 sec */ + while (!B1_rx_full(base) && i > jiffies); + if (B1_rx_full(base)) + return inb(base + B1_READ); + printk(KERN_CRIT "b1lli: rx not full after 5 second\n"); + return 0; +} + +static inline unsigned int B1_get_word(unsigned short base) +{ + unsigned int val = 0; + val |= B1_get_byte(base); + val |= (B1_get_byte(base) << 8); + val |= (B1_get_byte(base) << 16); + val |= (B1_get_byte(base) << 24); + return val; +} + +static inline int B1_tx_empty(unsigned short base) +{ + return inb(base + B1_OUTSTAT) & 0x1; +} + +static inline void B1_put_byte(unsigned short base, unsigned char val) +{ + while (!B1_tx_empty(base)); + b1outp(base, B1_WRITE, val); +} + +static inline void B1_put_word(unsigned short base, unsigned int val) +{ + B1_put_byte(base, val & 0xff); + B1_put_byte(base, (val >> 8) & 0xff); + B1_put_byte(base, (val >> 16) & 0xff); + B1_put_byte(base, (val >> 24) & 0xff); +} + +static inline unsigned int B1_get_slice(unsigned short base, + unsigned char *dp) +{ + unsigned int len, i; + + len = i = B1_get_word(base); + while (i-- > 0) + *dp++ = B1_get_byte(base); + return len; +} + +static inline void B1_put_slice(unsigned short base, + unsigned char *dp, unsigned int len) +{ + B1_put_word(base, len); + while (len-- > 0) + B1_put_byte(base, *dp++); +} + +extern int loaddebug; + +int B1_load_t4file(unsigned short base, avmb1_t4file * t4file) +{ + /* + * Data is in user space !!! + */ + unsigned char buf[256]; + unsigned char *dp; + int i, left, retval; + + + dp = t4file->data; + left = t4file->len; + while (left > sizeof(buf)) { + retval = copy_from_user(buf, dp, sizeof(buf)); + if (retval) + return -EFAULT; + if (loaddebug) + printk(KERN_DEBUG "b1capi: loading: %d bytes ..", sizeof(buf)); + for (i = 0; i < sizeof(buf); i++) + B1_put_byte(base, buf[i]); + if (loaddebug) + printk("ok\n"); + left -= sizeof(buf); + dp += sizeof(buf); + } + if (left) { + retval = copy_from_user(buf, dp, left); + if (retval) + return -EFAULT; + if (loaddebug) + printk(KERN_DEBUG "b1capi: loading: %d bytes ..", left); + for (i = 0; i < left; i++) + B1_put_byte(base, buf[i]); + if (loaddebug) + printk("ok\n"); + } + return 0; +} + +int B1_loaded(unsigned short base) +{ + int i; + unsigned char ans; + + if (loaddebug) + printk(KERN_DEBUG "b1capi: loaded: wait 1 ..\n"); + for (i = jiffies + 10 * HZ; i > jiffies;) { + if (B1_tx_empty(base)) + break; + } + if (!B1_tx_empty(base)) { + printk(KERN_ERR "b1lli: B1_loaded: timeout tx\n"); + return 0; + } + B1_put_byte(base, SEND_POLL); + printk(KERN_DEBUG "b1capi: loaded: wait 2 ..\n"); + for (i = jiffies + 10 * HZ; i > jiffies;) { + if (B1_rx_full(base)) { + if ((ans = B1_get_byte(base)) == RECEIVE_POLL) { + if (loaddebug) + printk(KERN_DEBUG "b1capi: loaded: ok\n"); + return 1; + } + printk(KERN_ERR "b1lli: B1_loaded: got 0x%x ???\n", ans); + return 0; + } + } + printk(KERN_ERR "b1lli: B1_loaded: timeout rx\n"); + return 0; +} + +/* + * ------------------------------------------------------------------- + */ +static inline void parse_version(avmb1_card * card) +{ + int i, j; + for (j = 0; j < AVM_MAXVERSION; j++) + card->version[j] = "\0\0" + 1; + for (i = 0, j = 0; + j < AVM_MAXVERSION && i < card->versionlen; + j++, i += card->versionbuf[i] + 1) + card->version[j] = &card->versionbuf[i + 1]; +} +/* + * ------------------------------------------------------------------- + */ + +void B1_send_init(unsigned short port, + unsigned int napps, unsigned int nncci, unsigned int cardnr) +{ + unsigned long flags; + + save_flags(flags); + cli(); + B1_put_byte(port, SEND_INIT); + B1_put_word(port, napps); + B1_put_word(port, nncci); + B1_put_word(port, cardnr); + restore_flags(flags); +} + +void B1_send_register(unsigned short port, + __u16 appid, __u32 nmsg, + __u32 nb3conn, __u32 nb3blocks, __u32 b3bsize) +{ + unsigned long flags; + + save_flags(flags); + cli(); + B1_put_byte(port, SEND_REGISTER); + B1_put_word(port, appid); + B1_put_word(port, nmsg); + B1_put_word(port, nb3conn); + B1_put_word(port, nb3blocks); + B1_put_word(port, b3bsize); + restore_flags(flags); +} + +void B1_send_release(unsigned short port, + __u16 appid) +{ + unsigned long flags; + + save_flags(flags); + cli(); + B1_put_byte(port, SEND_RELEASE); + B1_put_word(port, appid); + restore_flags(flags); +} + +extern int showcapimsgs; + +void B1_send_message(unsigned short port, struct sk_buff *skb) +{ + unsigned long flags; + __u16 len = CAPIMSG_LEN(skb->data); + __u8 cmd = CAPIMSG_COMMAND(skb->data); + __u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data); + __u32 contr = CAPIMSG_CONTROL(skb->data); + + if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { + __u16 dlen = CAPIMSG_DATALEN(skb->data); + + if (showcapimsgs > 2) { + if (showcapimsgs & 1) { + printk(KERN_DEBUG "b1lli: Put [0x%lx] id#%d %s len=%u\n", + (unsigned long) contr, + CAPIMSG_APPID(skb->data), + capi_cmd2str(cmd, subcmd), len); + } else { + printk(KERN_DEBUG "b1lli: Put %s\n", capi_message2str(skb->data)); + } + + } + save_flags(flags); + cli(); + B1_put_byte(port, SEND_DATA_B3_REQ); + B1_put_slice(port, skb->data, len); + B1_put_slice(port, skb->data + len, dlen); + restore_flags(flags); + } else { + if (showcapimsgs) { + + if (showcapimsgs & 1) { + printk(KERN_DEBUG "b1lli: Put [0x%lx] id#%d %s len=%u\n", + (unsigned long) contr, + CAPIMSG_APPID(skb->data), + capi_cmd2str(cmd, subcmd), len); + } else { + printk(KERN_DEBUG "b1lli: Put %s\n", capi_message2str(skb->data)); + } + } + save_flags(flags); + cli(); + B1_put_byte(port, SEND_MESSAGE); + B1_put_slice(port, skb->data, len); + restore_flags(flags); + } + dev_kfree_skb(skb, FREE_WRITE); +} + +/* + * ------------------------------------------------------------------- + */ + +void B1_handle_interrupt(avmb1_card * card) +{ + unsigned char b1cmd; + struct sk_buff *skb; + + unsigned ApplId; + unsigned MsgLen; + unsigned DataB3Len; + unsigned NCCI; + unsigned WindowSize; + + if (!B1_rx_full(card->port)) + return; + + b1cmd = B1_get_byte(card->port); + + switch (b1cmd) { + + case RECEIVE_DATA_B3_IND: + + ApplId = (unsigned) B1_get_word(card->port); + MsgLen = B1_get_slice(card->port, card->msgbuf); + DataB3Len = B1_get_slice(card->port, card->databuf); + + if (showcapimsgs > 2) { + __u8 cmd = CAPIMSG_COMMAND(card->msgbuf); + __u8 subcmd = CAPIMSG_SUBCOMMAND(card->msgbuf); + __u32 contr = CAPIMSG_CONTROL(card->msgbuf); + CAPIMSG_SETDATA(card->msgbuf, card->databuf); + if (showcapimsgs & 1) { + printk(KERN_DEBUG "b1lli: Got [0x%lx] id#%d %s len=%u/%u\n", + (unsigned long) contr, + CAPIMSG_APPID(card->msgbuf), + capi_cmd2str(cmd, subcmd), + MsgLen, DataB3Len); + } else { + printk(KERN_DEBUG "b1lli: Got %s\n", capi_message2str(card->msgbuf)); + } + } + if (!(skb = dev_alloc_skb(DataB3Len + MsgLen))) { + printk(KERN_ERR "b1lli: incoming packet dropped\n"); + } else { + SET_SKB_FREE(skb); + memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); + memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len); + CAPIMSG_SETDATA(skb->data, skb->data + MsgLen); + avmb1_handle_capimsg(card, ApplId, skb); + } + break; + + case RECEIVE_MESSAGE: + + ApplId = (unsigned) B1_get_word(card->port); + MsgLen = B1_get_slice(card->port, card->msgbuf); + if (showcapimsgs) { + __u8 cmd = CAPIMSG_COMMAND(card->msgbuf); + __u8 subcmd = CAPIMSG_SUBCOMMAND(card->msgbuf); + __u32 contr = CAPIMSG_CONTROL(card->msgbuf); + if (showcapimsgs & 1) { + printk(KERN_DEBUG "b1lli: Got [0x%lx] id#%d %s len=%u\n", + (unsigned long) contr, + CAPIMSG_APPID(card->msgbuf), + capi_cmd2str(cmd, subcmd), + MsgLen); + } else { + printk(KERN_DEBUG "b1lli: Got %s\n", capi_message2str(card->msgbuf)); + } + + } + if (!(skb = dev_alloc_skb(MsgLen))) { + printk(KERN_ERR "b1lli: incoming packet dropped\n"); + } else { + SET_SKB_FREE(skb); + memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); + avmb1_handle_capimsg(card, ApplId, skb); + } + break; + + case RECEIVE_NEW_NCCI: + + ApplId = B1_get_word(card->port); + NCCI = B1_get_word(card->port); + WindowSize = B1_get_word(card->port); + + if (showcapimsgs) + printk(KERN_DEBUG "b1lli: NEW_NCCI app %u ncci 0x%x\n", ApplId, NCCI); + + avmb1_handle_new_ncci(card, ApplId, NCCI, WindowSize); + + break; + + case RECEIVE_FREE_NCCI: + + ApplId = B1_get_word(card->port); + NCCI = B1_get_word(card->port); + + if (showcapimsgs) + printk(KERN_DEBUG "b1lli: FREE_NCCI app %u ncci 0x%x\n", ApplId, NCCI); + + avmb1_handle_free_ncci(card, ApplId, NCCI); + break; + + case RECEIVE_START: + if (card->blocked) + printk(KERN_DEBUG "b1lli: RESTART\n"); + card->blocked = 0; + break; + + case RECEIVE_STOP: + printk(KERN_DEBUG "b1lli: STOP\n"); + card->blocked = 1; + break; + + case RECEIVE_INIT: + + card->versionlen = B1_get_slice(card->port, card->versionbuf); + card->cardstate = CARD_ACTIVE; + parse_version(card); + printk(KERN_INFO "b1lli: %s-card (%s) with %s now active\n", + card->version[VER_CARDTYPE], + card->version[VER_DRIVER], + card->version[VER_PROTO]); + avmb1_card_ready(card); + break; + default: + printk(KERN_ERR "b1lli: B1_handle_interrupt: 0x%x ???\n", b1cmd); + break; + } +} diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/avmb1/b1pci.c linux/drivers/isdn/avmb1/b1pci.c --- v2.1.41/linux/drivers/isdn/avmb1/b1pci.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/b1pci.c Wed May 28 10:49:09 1997 @@ -0,0 +1,121 @@ +/* + * $Id: b1pci.c,v 1.2 1997/05/18 09:24:13 calle Exp $ + * + * Module for AVM B1 PCI-card. + * + * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: b1pci.c,v $ + * Revision 1.2 1997/05/18 09:24:13 calle + * added verbose disconnect reason reporting to avmb1. + * some fixes in capi20 interface. + * changed info messages for B1-PCI + * + * Revision 1.1 1997/03/30 17:10:42 calle + * added support for AVM-B1-PCI card. + * + */ + +#include +#include +#include +#include +#include +#include +#include "compat.h" +#include +#include + +#ifndef PCI_VENDOR_ID_AVM +#define PCI_VENDOR_ID_AVM 0x1244 +#endif + +#ifndef PCI_DEVICE_ID_AVM_B1 +#define PCI_DEVICE_ID_AVM_B1 0x700 +#endif + +static char *revision = "$Revision: 1.2 $"; + +/* ------------------------------------------------------------- */ + +#ifdef HAS_NEW_SYMTAB +MODULE_AUTHOR("Carsten Paeth "); +#endif + +/* ------------------------------------------------------------- */ + +/* ------------------------------------------------------------- */ +/* -------- Init & Cleanup ------------------------------------- */ +/* ------------------------------------------------------------- */ + +/* + * init / exit functions + */ + +#ifdef MODULE +#define b1pci_init init_module +#endif + +int b1pci_init(void) +{ + char *p; + char rev[10]; + int rc; + int pci_index; + + if ((p = strchr(revision, ':'))) { + strcpy(rev, p + 1); + p = strchr(rev, '$'); + *p = 0; + } else + strcpy(rev, " ??? "); + + +#ifdef CONFIG_PCI + if (!pcibios_present()) { + printk(KERN_ERR "b1pci: no PCI-BIOS present\n"); + return -EIO; + } + + printk(KERN_INFO "b1pci: revision %s\n", rev); + + for (pci_index = 0; pci_index < 8; pci_index++) { + unsigned char pci_bus, pci_device_fn; + unsigned int ioaddr; + unsigned char irq; + + if (pcibios_find_device (PCI_VENDOR_ID_AVM, + PCI_DEVICE_ID_AVM_B1, pci_index, + &pci_bus, &pci_device_fn) != 0) { + continue; + } + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, &irq); + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_1, &ioaddr); + /* Strip the I/O address out of the returned value */ + ioaddr &= PCI_BASE_ADDRESS_IO_MASK; + printk(KERN_INFO + "b1pci: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n", + ioaddr, irq); + if ((rc = avmb1_probecard(ioaddr, irq)) != 0) { + printk(KERN_ERR + "b1pci: no AVM-B1 at i/o %#x, irq %d detected\n", + ioaddr, irq); + return rc; + } + if ((rc = avmb1_addcard(ioaddr, irq)) != 0) + return rc; + } + return 0; +#else + printk(KERN_ERR "b1pci: kernel not compiled with PCI.\n"); + return -EIO; +#endif +} + +#ifdef MODULE +void cleanup_module(void) +{ +} +#endif diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c --- v2.1.41/linux/drivers/isdn/avmb1/capi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/capi.c Wed May 28 10:49:09 1997 @@ -0,0 +1,540 @@ +/* + * $Id: capi.c,v 1.4 1997/05/27 15:17:50 fritz Exp $ + * + * CAPI 2.0 Interface for Linux + * + * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: capi.c,v $ + * Revision 1.4 1997/05/27 15:17:50 fritz + * Added changes for recent 2.1.x kernels: + * changed return type of isdn_close + * queue_task_* -> queue_task + * clear/set_bit -> test_and_... where apropriate. + * changed type of hard_header_cache parameter. + * + * Revision 1.3 1997/05/18 09:24:14 calle + * added verbose disconnect reason reporting to avmb1. + * some fixes in capi20 interface. + * changed info messages for B1-PCI + * + * Revision 1.2 1997/03/05 21:17:59 fritz + * Added capi_poll for compiling under 2.1.27 + * + * Revision 1.1 1997/03/04 21:50:29 calle + * Frirst version in isdn4linux + * + * Revision 2.2 1997/02/12 09:31:39 calle + * new version + * + * Revision 1.1 1997/01/31 10:32:20 calle + * Initial revision + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE >= 0x020117) +#include +#endif +#include +#include + +#include "compat.h" +#include "capiutil.h" +#include "capicmd.h" +#include "capidev.h" + +#ifdef HAS_NEW_SYMTAB +MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)"); +#endif + +/* -------- driver information -------------------------------------- */ + +int capi_major = 68; /* allocated */ + +#ifdef HAS_NEW_SYMTAB +MODULE_PARM(capi_major, "i"); +#endif + +/* -------- global variables ---------------------------------------- */ + +static struct capidev capidevs[CAPI_MAXMINOR + 1]; +struct capi_interface *capifuncs; + +/* -------- function called by lower level -------------------------- */ + +static void capi_signal(__u16 applid, __u32 minor) +{ + struct capidev *cdev; + struct sk_buff *skb = 0; + + if (minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) { + printk(KERN_ERR "BUG: capi_signal: illegal minor %d\n", minor); + return; + } + cdev = &capidevs[minor]; + (void) (*capifuncs->capi_get_message) (applid, &skb); + if (skb) { + skb_queue_tail(&cdev->recv_queue, skb); + wake_up_interruptible(&cdev->recv_wait); + } else { + printk(KERN_ERR "BUG: capi_signal: no skb\n"); + } +} + +/* -------- file_operations ----------------------------------------- */ + +#if LINUX_VERSION_CODE < 0x020100 +static int capi_lseek(struct inode *inode, struct file *file, + off_t offset, int origin) +{ + return -ESPIPE; +} +#else +static long long capi_llseek(struct inode *inode, struct file *file, + long long offset, int origin) +{ + return -ESPIPE; +} +#endif + +#if LINUX_VERSION_CODE < 0x020100 +static int capi_read(struct inode *inode, struct file *file, + char *buf, int count) +#else +static long capi_read(struct inode *inode, struct file *file, + char *buf, unsigned long count) +#endif +{ + unsigned int minor = MINOR(inode->i_rdev); + struct capidev *cdev; + struct sk_buff *skb; + int retval; + size_t copied; + + if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) + return -ENODEV; + + cdev = &capidevs[minor]; + + if ((skb = skb_dequeue(&cdev->recv_queue)) == 0) { + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + for (;;) { + interruptible_sleep_on(&cdev->recv_wait); + if ((skb = skb_dequeue(&cdev->recv_queue)) != 0) + break; + if (current->signal & ~current->blocked) + break; + } + if (skb == 0) + return -ERESTARTNOHAND; + } + if (skb->len > count) { + skb_queue_head(&cdev->recv_queue, skb); + return -EMSGSIZE; + } + if (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3 + && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) + CAPIMSG_SETDATA(skb->data, buf + CAPIMSG_LEN(skb->data)); + retval = copy_to_user(buf, skb->data, skb->len); + if (retval) { + skb_queue_head(&cdev->recv_queue, skb); + return retval; + } + copied = skb->len; + + + kfree_skb(skb, FREE_READ); + + return copied; +} + +#if LINUX_VERSION_CODE < 0x020100 +static int capi_write(struct inode *inode, struct file *file, + const char *buf, int count) +#else +static long capi_write(struct inode *inode, struct file *file, + const char *buf, unsigned long count) +#endif +{ + unsigned int minor = MINOR(inode->i_rdev); + struct capidev *cdev; + struct sk_buff *skb; + int retval; + __u8 cmd; + __u8 subcmd; + __u16 mlen; + + if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) + return -ENODEV; + + cdev = &capidevs[minor]; + + skb = alloc_skb(count, GFP_USER); + + if ((retval = copy_from_user(skb_put(skb, count), buf, count))) { + dev_kfree_skb(skb, FREE_WRITE); + return retval; + } + cmd = CAPIMSG_COMMAND(skb->data); + subcmd = CAPIMSG_SUBCOMMAND(skb->data); + mlen = CAPIMSG_LEN(skb->data); + if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) { + __u16 dlen = CAPIMSG_DATALEN(skb->data); + if (mlen + dlen != count) { + dev_kfree_skb(skb, FREE_WRITE); + return -EINVAL; + } + } else if (mlen != count) { + dev_kfree_skb(skb, FREE_WRITE); + return -EINVAL; + } + CAPIMSG_SETAPPID(skb->data, cdev->applid); + + cdev->errcode = (*capifuncs->capi_put_message) (cdev->applid, skb); + + if (cdev->errcode) { + dev_kfree_skb(skb, FREE_WRITE); + return -EIO; + } + return count; +} + +#if (LINUX_VERSION_CODE < 0x020117) +static int capi_select(struct inode *inode, struct file *file, + int sel_type, select_table * wait) +{ + unsigned int minor = MINOR(inode->i_rdev); + struct capidev *cdev; + + if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) + return -ENODEV; + + cdev = &capidevs[minor]; + + switch (sel_type) { + case SEL_IN: + if (!skb_queue_empty(&cdev->recv_queue)) + return 1; + /* fall througth */ + case SEL_EX: + /* error conditions ? */ + + select_wait(&cdev->recv_wait, wait); + return 0; + case SEL_OUT: + /* + if (!queue_full()) + return 1; + select_wait(&cdev->send_wait, wait); + return 0; + */ + return 1; + } + return 1; +} +#else +static unsigned int +capi_poll(struct file *file, poll_table * wait) +{ + unsigned int mask = 0; + unsigned int minor = MINOR(file->f_inode->i_rdev); + struct capidev *cdev; + + if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) + return POLLERR; + + cdev = &capidevs[minor]; + poll_wait(&(cdev->recv_wait), wait); + mask = POLLOUT | POLLWRNORM; + if (!skb_queue_empty(&cdev->recv_queue)) + mask |= POLLIN | POLLRDNORM; + return mask; +} +#endif + +static int capi_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned int minor = MINOR(inode->i_rdev); + struct capidev *cdev; + capi_ioctl_struct data; + int retval; + + + if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open) + return -ENODEV; + + cdev = &capidevs[minor]; + + switch (cmd) { + case CAPI_REGISTER: + { + if (!minor) + return -EINVAL; + retval = copy_from_user((void *) &data.rparams, + (void *) arg, sizeof(struct capi_register_params)); + if (retval) + return -EFAULT; + if (cdev->is_registered) + return -EEXIST; + cdev->errcode = (*capifuncs->capi_register) (&data.rparams, + &cdev->applid); + if (cdev->errcode) + return -EIO; + (void) (*capifuncs->capi_set_signal) (cdev->applid, capi_signal, minor); + cdev->is_registered = 1; + } + return 0; + + case CAPI_GET_VERSION: + { + retval = copy_from_user((void *) &data.contr, + (void *) arg, + sizeof(data.contr)); + if (retval) + return -EFAULT; + cdev->errcode = (*capifuncs->capi_get_version) (data.contr, &data.version); + if (cdev->errcode) + return -EIO; + retval = copy_to_user((void *) arg, + (void *) &data.version, + sizeof(data.version)); + if (retval) + return -EFAULT; + } + return 0; + + case CAPI_GET_SERIAL: + { + retval = copy_from_user((void *) &data.contr, + (void *) arg, + sizeof(data.contr)); + if (retval) + return -EFAULT; + cdev->errcode = (*capifuncs->capi_get_serial) (data.contr, data.serial); + if (cdev->errcode) + return -EIO; + retval = copy_to_user((void *) arg, + (void *) data.serial, + sizeof(data.serial)); + if (retval) + return -EFAULT; + } + return 0; + case CAPI_GET_PROFILE: + { + retval = copy_from_user((void *) &data.contr, + (void *) arg, + sizeof(data.contr)); + if (retval) + return -EFAULT; + + if (data.contr == 0) { + cdev->errcode = (*capifuncs->capi_get_profile) (data.contr, &data.profile); + if (cdev->errcode) + return -EIO; + + retval = copy_to_user((void *) arg, + (void *) &data.profile.ncontroller, + sizeof(data.profile.ncontroller)); + + } else { + cdev->errcode = (*capifuncs->capi_get_profile) (data.contr, &data.profile); + if (cdev->errcode) + return -EIO; + + retval = copy_to_user((void *) arg, + (void *) &data.profile, + sizeof(data.profile)); + } + if (retval) + return -EFAULT; + } + return 0; + + case CAPI_GET_MANUFACTURER: + { + retval = copy_from_user((void *) &data.contr, + (void *) arg, + sizeof(data.contr)); + if (retval) + return -EFAULT; + cdev->errcode = (*capifuncs->capi_get_manufacturer) (data.contr, data.manufacturer); + if (cdev->errcode) + return -EIO; + + retval = copy_to_user((void *) arg, (void *) data.manufacturer, + sizeof(data.manufacturer)); + if (retval) + return -EFAULT; + + } + return 0; + case CAPI_GET_ERRCODE: + data.errcode = cdev->errcode; + cdev->errcode = CAPI_NOERROR; + if (arg) { + retval = copy_to_user((void *) arg, + (void *) &data.errcode, + sizeof(data.errcode)); + if (retval) + return -EFAULT; + } + return data.errcode; + + case CAPI_INSTALLED: + if ((*capifuncs->capi_installed) ()) + return 0; + return -ENXIO; + + case CAPI_MANUFACTURER_CMD: + { + struct capi_manufacturer_cmd mcmd; + if (minor) + return -EINVAL; + if (!suser()) + return -EPERM; + retval = copy_from_user((void *) &mcmd, (void *) arg, + sizeof(mcmd)); + if (retval) + return -EFAULT; + return (*capifuncs->capi_manufacturer) (mcmd.cmd, mcmd.data); + } + return 0; + } + return -EINVAL; +} + +static int capi_open(struct inode *inode, struct file *file) +{ + unsigned int minor = MINOR(inode->i_rdev); + + if (minor >= CAPI_MAXMINOR) + return -ENXIO; + + if (minor) { + if (capidevs[minor].is_open) + return -EEXIST; + + capidevs[minor].is_open = 1; + skb_queue_head_init(&capidevs[minor].recv_queue); + MOD_INC_USE_COUNT; + + } else { + + if (!capidevs[minor].is_open) { + capidevs[minor].is_open = 1; + MOD_INC_USE_COUNT; + } + } + + + return 0; +} + +static CLOSETYPE +capi_release(struct inode *inode, struct file *file) +{ + unsigned int minor = MINOR(inode->i_rdev); + struct capidev *cdev; + struct sk_buff *skb; + + if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open) { + printk(KERN_ERR "capi20: release minor %d ???\n", minor); + return CLOSEVAL; + } + cdev = &capidevs[minor]; + + if (minor) { + + if (cdev->is_registered) + (*capifuncs->capi_release) (cdev->applid); + + cdev->is_registered = 0; + cdev->applid = 0; + + while ((skb = skb_dequeue(&cdev->recv_queue)) != 0) + kfree_skb(skb, FREE_READ); + } + cdev->is_open = 0; + + MOD_DEC_USE_COUNT; + return CLOSEVAL; +} + +static struct file_operations capi_fops = +{ +#if LINUX_VERSION_CODE < 0x020100 + capi_lseek, +#else + capi_llseek, +#endif + capi_read, + capi_write, + NULL, /* capi_readdir */ +#if (LINUX_VERSION_CODE < 0x020117) + capi_select, +#else + capi_poll, +#endif + capi_ioctl, + NULL, /* capi_mmap */ + capi_open, + capi_release, + NULL, /* capi_fsync */ + NULL, /* capi_fasync */ +}; + + +/* -------- init function and module interface ---------------------- */ + +#ifdef MODULE +#define capi_init init_module +#endif + +static struct capi_interface_user cuser = { + "capi20", + 0, +}; + +int capi_init(void) +{ + memset(capidevs, 0, sizeof(capidevs)); + + if (register_chrdev(capi_major, "capi20", &capi_fops)) { + printk(KERN_ERR "capi20: unable to get major %d\n", capi_major); + return -EIO; + } + printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major); + + if ((capifuncs = attach_capi_interface(&cuser)) == 0) { + unregister_chrdev(capi_major, "capi20"); + return -EIO; + } + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + unregister_chrdev(capi_major, "capi20"); + (void) detach_capi_interface(&cuser); +} + +#endif diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/avmb1/capicmd.h linux/drivers/isdn/avmb1/capicmd.h --- v2.1.41/linux/drivers/isdn/avmb1/capicmd.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/capicmd.h Wed May 28 10:49:09 1997 @@ -0,0 +1,119 @@ +/* + * $Id: capicmd.h,v 1.1 1997/03/04 21:50:30 calle Exp $ + * + * CAPI 2.0 Interface for Linux + * + * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: capicmd.h,v $ + * Revision 1.1 1997/03/04 21:50:30 calle + * Frirst version in isdn4linux + * + * Revision 2.2 1997/02/12 09:31:39 calle + * new version + * + * Revision 1.1 1997/01/31 10:32:20 calle + * Initial revision + * + * + */ +#ifndef __CAPICMD_H__ +#define __CAPICMD_H__ + +/*----- CAPI commands -----*/ +#define CAPI_ALERT 0x01 +#define CAPI_CONNECT 0x02 +#define CAPI_CONNECT_ACTIVE 0x03 +#define CAPI_CONNECT_B3_ACTIVE 0x83 +#define CAPI_CONNECT_B3 0x82 +#define CAPI_CONNECT_B3_T90_ACTIVE 0x88 +#define CAPI_DATA_B3 0x86 +#define CAPI_DISCONNECT_B3 0x84 +#define CAPI_DISCONNECT 0x04 +#define CAPI_FACILITY 0x80 +#define CAPI_INFO 0x08 +#define CAPI_LISTEN 0x05 +#define CAPI_MANUFACTURER 0xff +#define CAPI_RESET_B3 0x87 +#define CAPI_SELECT_B_PROTOCOL 0x41 + +/*----- CAPI subcommands -----*/ + +#define CAPI_REQ 0x80 +#define CAPI_CONF 0x81 +#define CAPI_IND 0x82 +#define CAPI_RESP 0x83 + +/*----- CAPI combined commands -----*/ + +#define CAPICMD(cmd,subcmd) (((cmd)<<8)|(subcmd)) + +#define CAPI_DISCONNECT_REQ CAPICMD(CAPI_DISCONNECT,CAPI_REQ) +#define CAPI_DISCONNECT_CONF CAPICMD(CAPI_DISCONNECT,CAPI_CONF) +#define CAPI_DISCONNECT_IND CAPICMD(CAPI_DISCONNECT,CAPI_IND) +#define CAPI_DISCONNECT_RESP CAPICMD(CAPI_DISCONNECT,CAPI_RESP) + +#define CAPI_ALERT_REQ CAPICMD(CAPI_ALERT,CAPI_REQ) +#define CAPI_ALERT_CONF CAPICMD(CAPI_ALERT,CAPI_CONF) + +#define CAPI_CONNECT_REQ CAPICMD(CAPI_CONNECT,CAPI_REQ) +#define CAPI_CONNECT_CONF CAPICMD(CAPI_CONNECT,CAPI_CONF) +#define CAPI_CONNECT_IND CAPICMD(CAPI_CONNECT,CAPI_IND) +#define CAPI_CONNECT_RESP CAPICMD(CAPI_CONNECT,CAPI_RESP) + +#define CAPI_CONNECT_ACTIVE_REQ CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_REQ) +#define CAPI_CONNECT_ACTIVE_CONF CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_CONF) +#define CAPI_CONNECT_ACTIVE_IND CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_IND) +#define CAPI_CONNECT_ACTIVE_RESP CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_RESP) + +#define CAPI_SELECT_B_PROTOCOL_REQ CAPICMD(CAPI_SELECT_B_PROTOCOL,CAPI_REQ) +#define CAPI_SELECT_B_PROTOCOL_CONF CAPICMD(CAPI_SELECT_B_PROTOCOL,CAPI_CONF) + +#define CAPI_CONNECT_B3_ACTIVE_REQ CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_REQ) +#define CAPI_CONNECT_B3_ACTIVE_CONF CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_CONF) +#define CAPI_CONNECT_B3_ACTIVE_IND CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_IND) +#define CAPI_CONNECT_B3_ACTIVE_RESP CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_RESP) + +#define CAPI_CONNECT_B3_REQ CAPICMD(CAPI_CONNECT_B3,CAPI_REQ) +#define CAPI_CONNECT_B3_CONF CAPICMD(CAPI_CONNECT_B3,CAPI_CONF) +#define CAPI_CONNECT_B3_IND CAPICMD(CAPI_CONNECT_B3,CAPI_IND) +#define CAPI_CONNECT_B3_RESP CAPICMD(CAPI_CONNECT_B3,CAPI_RESP) + + +#define CAPI_CONNECT_B3_T90_ACTIVE_IND CAPICMD(CAPI_CONNECT_B3_T90_ACTIVE,CAPI_IND) +#define CAPI_CONNECT_B3_T90_ACTIVE_RESP CAPICMD(CAPI_CONNECT_B3_T90_ACTIVE,CAPI_RESP) + +#define CAPI_DATA_B3_REQ CAPICMD(CAPI_DATA_B3,CAPI_REQ) +#define CAPI_DATA_B3_CONF CAPICMD(CAPI_DATA_B3,CAPI_CONF) +#define CAPI_DATA_B3_IND CAPICMD(CAPI_DATA_B3,CAPI_IND) +#define CAPI_DATA_B3_RESP CAPICMD(CAPI_DATA_B3,CAPI_RESP) + +#define CAPI_DISCONNECT_B3_REQ CAPICMD(CAPI_DISCONNECT_B3,CAPI_REQ) +#define CAPI_DISCONNECT_B3_CONF CAPICMD(CAPI_DISCONNECT_B3,CAPI_CONF) +#define CAPI_DISCONNECT_B3_IND CAPICMD(CAPI_DISCONNECT_B3,CAPI_IND) +#define CAPI_DISCONNECT_B3_RESP CAPICMD(CAPI_DISCONNECT_B3,CAPI_RESP) + +#define CAPI_RESET_B3_REQ CAPICMD(CAPI_RESET_B3,CAPI_REQ) +#define CAPI_RESET_B3_CONF CAPICMD(CAPI_RESET_B3,CAPI_CONF) +#define CAPI_RESET_B3_IND CAPICMD(CAPI_RESET_B3,CAPI_IND) +#define CAPI_RESET_B3_RESP CAPICMD(CAPI_RESET_B3,CAPI_RESP) + +#define CAPI_LISTEN_REQ CAPICMD(CAPI_LISTEN,CAPI_REQ) +#define CAPI_LISTEN_CONF CAPICMD(CAPI_LISTEN,CAPI_CONF) + +#define CAPI_MANUFACTURER_REQ CAPICMD(CAPI_MANUFACTURER,CAPI_REQ) +#define CAPI_MANUFACTURER_CONF CAPICMD(CAPI_MANUFACTURER,CAPI_CONF) +#define CAPI_MANUFACTURER_IND CAPICMD(CAPI_MANUFACTURER,CAPI_IND) +#define CAPI_MANUFACTURER_RESP CAPICMD(CAPI_MANUFACTURER,CAPI_RESP) + +#define CAPI_FACILITY_REQ CAPICMD(CAPI_FACILITY,CAPI_REQ) +#define CAPI_FACILITY_CONF CAPICMD(CAPI_FACILITY,CAPI_CONF) +#define CAPI_FACILITY_IND CAPICMD(CAPI_FACILITY,CAPI_IND) +#define CAPI_FACILITY_RESP CAPICMD(CAPI_FACILITY,CAPI_RESP) + +#define CAPI_INFO_REQ CAPICMD(CAPI_INFO,CAPI_REQ) +#define CAPI_INFO_CONF CAPICMD(CAPI_INFO,CAPI_CONF) +#define CAPI_INFO_IND CAPICMD(CAPI_INFO,CAPI_IND) +#define CAPI_INFO_RESP CAPICMD(CAPI_INFO,CAPI_RESP) + +#endif /* __CAPICMD_H__ */ diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/avmb1/capidev.h linux/drivers/isdn/avmb1/capidev.h --- v2.1.41/linux/drivers/isdn/avmb1/capidev.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/capidev.h Wed May 28 10:49:09 1997 @@ -0,0 +1,29 @@ +/* + * $Id: capidev.h,v 1.1 1997/03/04 21:50:30 calle Exp $ + * + * CAPI 2.0 Interface for Linux + * + * (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: capidev.h,v $ + * Revision 1.1 1997/03/04 21:50:30 calle + * Frirst version in isdn4linux + * + * Revision 2.2 1997/02/12 09:31:39 calle + * new version + * + * Revision 1.1 1997/01/31 10:32:20 calle + * Initial revision + * + */ + +struct capidev { + int is_open; + int is_registered; + __u16 applid; + struct sk_buff_head recv_queue; + struct wait_queue *recv_wait; + __u16 errcode; +}; + +#define CAPI_MAXMINOR CAPI_MAXAPPL diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/avmb1/capidrv.c linux/drivers/isdn/avmb1/capidrv.c --- v2.1.41/linux/drivers/isdn/avmb1/capidrv.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/capidrv.c Wed May 28 10:49:09 1997 @@ -0,0 +1,1764 @@ +/* + * $Id: capidrv.c,v 1.3 1997/05/18 09:24:15 calle Exp $ + * + * ISDN4Linux Driver, using capi20 interface (kernelcapi) + * + * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: capidrv.c,v $ + * Revision 1.3 1997/05/18 09:24:15 calle + * added verbose disconnect reason reporting to avmb1. + * some fixes in capi20 interface. + * changed info messages for B1-PCI + * + * Revision 1.2 1997/03/05 21:19:59 fritz + * Removed include of config.h (mkdep stated this is unneded). + * + * Revision 1.1 1997/03/04 21:50:31 calle + * Frirst version in isdn4linux + * + * Revision 2.2 1997/02/12 09:31:39 calle + * new version + * + * Revision 1.1 1997/01/31 10:32:20 calle + * Initial revision + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "compat.h" +#include "capiutil.h" +#include "capicmd.h" +#include "capidrv.h" + +static char *revision = "$Revision: 1.3 $"; +int debugmode = 0; + +#ifdef HAS_NEW_SYMTAB +MODULE_AUTHOR("Carsten Paeth "); +MODULE_PARM(debugmode, "i"); +#endif + +/* -------- type definitions ----------------------------------------- */ + + +struct capidrv_contr { + + struct capidrv_contr *next; + + __u32 contrnr; + char name[20]; + + /* + * for isdn4linux + */ + isdn_if interface; + int myid; + + /* + * LISTEN state + */ + int state; + __u32 cipmask; + __u32 cipmask2; + + /* + * ID of capi message sent + */ + __u16 msgid; + + /* + * B-Channels + */ + int nbchan; + struct capidrv_bchan { + struct capidrv_contr *contr; + __u8 msn[ISDN_MSNLEN]; + int l2; + int l3; + __u8 num[ISDN_MSNLEN]; + __u8 mynum[ISDN_MSNLEN]; + int si1; + int si2; + int incoming; + int disconnecting; + struct capidrv_plci { + struct capidrv_plci *next; + __u32 plci; + __u32 ncci; /* ncci for CONNECT_ACTIVE_IND */ + __u16 msgid; /* to identfy CONNECT_CONF */ + int chan; + int state; + struct capidrv_ncci { + struct capidrv_ncci *next; + struct capidrv_plci *plcip; + __u32 ncci; + __u16 msgid; /* to identfy CONNECT_B3_CONF */ + int chan; + int state; + int oldstate; + /* */ + __u16 datahandle; + } *ncci_list; + } *plcip; + struct capidrv_ncci *nccip; + } *bchans; + + struct capidrv_plci *plci_list; +}; + +struct capidrv_data { + __u16 appid; + int ncontr; + struct capidrv_contr *contr_list; +}; + +typedef struct capidrv_plci capidrv_plci; +typedef struct capidrv_ncci capidrv_ncci; +typedef struct capidrv_contr capidrv_contr; +typedef struct capidrv_data capidrv_data; +typedef struct capidrv_bchan capidrv_bchan; + +/* -------- data definitions ----------------------------------------- */ + +static capidrv_data global; +static struct capi_interface *capifuncs; + +/* -------- convert functions ---------------------------------------- */ + +static inline __u32 b1prot(int l2, int l3) +{ + switch (l2) { + case ISDN_PROTO_L2_X75I: + case ISDN_PROTO_L2_X75UI: + case ISDN_PROTO_L2_X75BUI: + return 0; + case ISDN_PROTO_L2_HDLC: + default: + return 0; + case ISDN_PROTO_L2_TRANS: + return 1; + } +} + +static inline __u32 b2prot(int l2, int l3) +{ + switch (l2) { + case ISDN_PROTO_L2_X75I: + case ISDN_PROTO_L2_X75UI: + case ISDN_PROTO_L2_X75BUI: + default: + return 0; + case ISDN_PROTO_L2_HDLC: + return 1; + case ISDN_PROTO_L2_TRANS: + return 0; + } +} + +static inline __u32 b3prot(int l2, int l3) +{ + switch (l2) { + case ISDN_PROTO_L2_X75I: + case ISDN_PROTO_L2_X75UI: + case ISDN_PROTO_L2_X75BUI: + case ISDN_PROTO_L2_HDLC: + case ISDN_PROTO_L2_TRANS: + default: + return 0; + } +} + +static inline __u16 si2cip(__u8 si1, __u8 si2) +{ + static const __u8 cip[17][5] = + { + /* 0 1 2 3 4 */ + {0, 0, 0, 0, 0}, /*0 */ + {16, 16, 4, 26, 16}, /*1 */ + {17, 17, 17, 4, 4}, /*2 */ + {2, 2, 2, 2, 2}, /*3 */ + {18, 18, 18, 18, 18}, /*4 */ + {2, 2, 2, 2, 2}, /*5 */ + {0, 0, 0, 0, 0}, /*6 */ + {2, 2, 2, 2, 2}, /*7 */ + {2, 2, 2, 2, 2}, /*8 */ + {21, 21, 21, 21, 21}, /*9 */ + {19, 19, 19, 19, 19}, /*10 */ + {0, 0, 0, 0, 0}, /*11 */ + {0, 0, 0, 0, 0}, /*12 */ + {0, 0, 0, 0, 0}, /*13 */ + {0, 0, 0, 0, 0}, /*14 */ + {22, 22, 22, 22, 22}, /*15 */ + {27, 27, 27, 28, 27} /*16 */ + }; + if (si1 > 16) + si1 = 0; + if (si2 > 4) + si2 = 0; + + return (__u16) cip[si1][si2]; +} + +static inline __u8 cip2si1(__u16 cipval) +{ + static const __u8 si[32] = + {7, 1, 7, 7, 1, 1, 7, 7, /*0-7 */ + 7, 1, 0, 0, 0, 0, 0, 0, /*8-15 */ + 1, 2, 4, 10, 9, 9, 15, 7, /*16-23 */ + 7, 7, 1, 16, 16, 0, 0, 0}; /*24-31 */ + + if (cipval > 31) + cipval = 0; /* .... */ + return si[cipval]; +} + +static inline __u8 cip2si2(__u16 cipval) +{ + static const __u8 si[32] = + {0, 0, 0, 0, 2, 3, 0, 0, /*0-7 */ + 0, 3, 0, 0, 0, 0, 0, 0, /*8-15 */ + 1, 2, 0, 0, 9, 0, 0, 0, /*16-23 */ + 0, 0, 3, 2, 3, 0, 0, 0}; /*24-31 */ + + if (cipval > 31) + cipval = 0; /* .... */ + return si[cipval]; +} + + +/* -------- controller managment ------------------------------------- */ + +static inline capidrv_contr *findcontrbydriverid(int driverid) +{ + capidrv_contr *p = global.contr_list; + + while (p) { + if (p->myid == driverid) + return p; + p = p->next; + } + return (capidrv_contr *) 0; +} + +static capidrv_contr *findcontrbynumber(__u32 contr) +{ + capidrv_contr *p = global.contr_list; + + while (p) { + if (p->contrnr == contr) + return p; + p = p->next; + } + return (capidrv_contr *) 0; +} + + +/* -------- plci management ------------------------------------------ */ + +static capidrv_plci *new_plci(capidrv_contr * card, int chan) +{ + capidrv_plci *plcip; + + plcip = (capidrv_plci *) kmalloc(sizeof(capidrv_plci), GFP_ATOMIC); + + if (plcip == 0) + return 0; + + memset(plcip, 0, sizeof(capidrv_plci)); + plcip->state = ST_PLCI_NONE; + plcip->plci = 0; + plcip->msgid = 0; + plcip->chan = chan; + plcip->next = card->plci_list; + card->plci_list = plcip; + card->bchans[chan].plcip = plcip; + + return plcip; +} + +static capidrv_plci *find_plci_by_plci(capidrv_contr * card, __u32 plci) +{ + capidrv_plci *p; + for (p = card->plci_list; p; p = p->next) + if (p->plci == plci) + return p; + return 0; +} + +static capidrv_plci *find_plci_by_msgid(capidrv_contr * card, __u16 msgid) +{ + capidrv_plci *p; + for (p = card->plci_list; p; p = p->next) + if (p->msgid == msgid) + return p; + return 0; +} + +static capidrv_plci *find_plci_by_ncci(capidrv_contr * card, __u32 ncci) +{ + capidrv_plci *p; + for (p = card->plci_list; p; p = p->next) + if (p->plci == (ncci & 0xffff)) + return p; + return 0; +} + +static void free_plci(capidrv_contr * card, capidrv_plci * plcip) +{ + capidrv_plci **pp; + + for (pp = &card->plci_list; *pp; pp = &(*pp)->next) { + if (*pp == plcip) { + *pp = (*pp)->next; + card->bchans[plcip->chan].plcip = 0; + card->bchans[plcip->chan].disconnecting = 0; + card->bchans[plcip->chan].incoming = 0; + kfree(plcip); + return; + } + } + printk(KERN_ERR "capidrv: free_plci %p (0x%x) not found, Huh?\n", + plcip, plcip->plci); +} + +/* -------- ncci management ------------------------------------------ */ + +static inline capidrv_ncci *new_ncci(capidrv_contr * card, + capidrv_plci * plcip, + __u32 ncci) +{ + capidrv_ncci *nccip; + + nccip = (capidrv_ncci *) kmalloc(sizeof(capidrv_ncci), GFP_ATOMIC); + + if (nccip == 0) + return 0; + + memset(nccip, 0, sizeof(capidrv_ncci)); + nccip->ncci = ncci; + nccip->state = ST_NCCI_NONE; + nccip->plcip = plcip; + nccip->chan = plcip->chan; + nccip->datahandle = 0; + + nccip->next = plcip->ncci_list; + plcip->ncci_list = nccip; + + card->bchans[plcip->chan].nccip = nccip; + + return nccip; +} + +static inline capidrv_ncci *find_ncci(capidrv_contr * card, __u32 ncci) +{ + capidrv_plci *plcip; + capidrv_ncci *p; + + if ((plcip = find_plci_by_ncci(card, ncci)) == 0) + return 0; + + for (p = plcip->ncci_list; p; p = p->next) + if (p->ncci == ncci) + return p; + return 0; +} + +static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr * card, + __u32 ncci, __u16 msgid) +{ + capidrv_plci *plcip; + capidrv_ncci *p; + + if ((plcip = find_plci_by_ncci(card, ncci)) == 0) + return 0; + + for (p = plcip->ncci_list; p; p = p->next) + if (p->msgid == msgid) + return p; + return 0; +} + +static void free_ncci(capidrv_contr * card, struct capidrv_ncci *nccip) +{ + struct capidrv_ncci **pp; + + for (pp = &(nccip->plcip->ncci_list); *pp; pp = &(*pp)->next) { + if (*pp == nccip) { + *pp = (*pp)->next; + break; + } + } + card->bchans[nccip->chan].nccip = 0; + kfree(nccip); +} + +/* -------- convert and send capi message ---------------------------- */ + +static void send_message(capidrv_contr * card, _cmsg * cmsg) +{ + struct sk_buff *skb; + size_t len; + capi_cmsg2message(cmsg, cmsg->buf); + len = CAPIMSG_LEN(cmsg->buf); + skb = dev_alloc_skb(len); + SET_SKB_FREE(skb); + memcpy(skb_put(skb, len), cmsg->buf, len); + (*capifuncs->capi_put_message) (global.appid, skb); +} + +/* -------- state machine -------------------------------------------- */ + +struct listenstatechange { + int actstate; + int nextstate; + int event; +}; + +static struct listenstatechange listentable[] = +{ + {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ}, + {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ}, + {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR}, + {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR}, + {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, + {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, + {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, + {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, + {}, +}; + +static void listen_change_state(capidrv_contr * card, int event) +{ + struct listenstatechange *p = listentable; + while (p->event) { + if (card->state == p->actstate && p->event == event) { + if (debugmode) + printk(KERN_DEBUG "capidrv: listen_change_state %d -> %d\n", + card->state, p->nextstate); + card->state = p->nextstate; + return; + } + p++; + } + printk(KERN_ERR "capidrv: listen_change_state state=%d event=%d ????\n", + card->state, event); + +} + +/* ------------------------------------------------------------------ */ + +static void p0(capidrv_contr * card, capidrv_plci * plci) +{ + isdn_ctrl cmd; + + card->bchans[plci->chan].contr = 0; + cmd.command = ISDN_STAT_DHUP; + cmd.driver = card->myid; + cmd.arg = plci->chan; + card->interface.statcallb(&cmd); + free_plci(card, plci); +} + +/* ------------------------------------------------------------------ */ + +struct plcistatechange { + int actstate; + int nextstate; + int event; + void (*changefunc) (capidrv_contr * card, capidrv_plci * plci); +}; + +static struct plcistatechange plcitable[] = +{ + /* P-0 */ + {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, 0}, + {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, 0}, + {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, 0}, + /* P-0.1 */ + {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0}, + {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, 0}, + {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + /* P-1 */ + {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0}, + {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, +{ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + /* P-ACT */ + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + /* P-2 */ + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0}, + {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, 0}, + {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, 0}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + /* P-3 */ +{ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0}, +{ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, 0}, +{ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + /* P-4 */ + {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0}, + {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, +{ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + /* P-5 */ +{ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + /* P-6 */ + {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0}, + {}, +}; + +static void plci_change_state(capidrv_contr * card, capidrv_plci * plci, int event) +{ + struct plcistatechange *p = plcitable; + while (p->event) { + if (plci->state == p->actstate && p->event == event) { + if (debugmode) + printk(KERN_DEBUG "capidrv: plci_change_state:0x%x %d -> %d\n", + plci->plci, plci->state, p->nextstate); + plci->state = p->nextstate; + if (p->changefunc) + p->changefunc(card, plci); + return; + } + p++; + } + printk(KERN_ERR "capidrv: plci_change_state:0x%x state=%d event=%d ????\n", + plci->plci, plci->state, event); +} + +/* ------------------------------------------------------------------ */ + +static _cmsg cmsg; + +static void n0(capidrv_contr * card, capidrv_ncci * ncci) +{ + isdn_ctrl cmd; + + capi_fill_DISCONNECT_REQ(&cmsg, + global.appid, + card->msgid++, + ncci->plcip->plci, + 0, /* BChannelinformation */ + 0, /* Keypadfacility */ + 0, /* Useruserdata */ + 0 /* Facilitydataarray */ + ); + send_message(card, &cmsg); + plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ); + + cmd.command = ISDN_STAT_BHUP; + cmd.driver = card->myid; + cmd.arg = ncci->chan; + card->interface.statcallb(&cmd); + free_ncci(card, ncci); +} + +/* ------------------------------------------------------------------ */ + +struct nccistatechange { + int actstate; + int nextstate; + int event; + void (*changefunc) (capidrv_contr * card, capidrv_ncci * ncci); +}; + +static struct nccistatechange nccitable[] = +{ + /* N-0 */ + {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, 0}, + {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, 0}, + /* N-0.1 */ + {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, 0}, + {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, 0}, + /* N-1 */ + {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, 0}, + {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, 0}, + {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, + {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + /* N-2 */ + {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, 0}, + {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, +{ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + /* N-ACT */ + {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, 0}, + {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, + {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + /* N-3 */ + {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0}, + {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, + {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + /* N-4 */ + {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, + {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR, 0}, + /* N-5 */ + {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0}, + {}, +}; + +static void ncci_change_state(capidrv_contr * card, capidrv_ncci * ncci, int event) +{ + struct nccistatechange *p = nccitable; + while (p->event) { + if (ncci->state == p->actstate && p->event == event) { + if (debugmode) + printk(KERN_DEBUG "capidrv: ncci_change_state:0x%x %d -> %d\n", + ncci->ncci, ncci->state, p->nextstate); + if (p->nextstate == ST_NCCI_PREVIOUS) { + ncci->state = ncci->oldstate; + ncci->oldstate = p->actstate; + } else { + ncci->oldstate = p->actstate; + ncci->state = p->nextstate; + } + if (p->changefunc) + p->changefunc(card, ncci); + return; + } + p++; + } + printk(KERN_ERR "capidrv: ncci_change_state:0x%x state=%d event=%d ????\n", + ncci->ncci, ncci->state, event); +} + +/* ------------------------------------------------------------------- */ + +static inline int new_bchan(capidrv_contr * card) +{ + int i; + for (i = 0; i < card->nbchan; i++) { + if (card->bchans[i].plcip == 0) { + card->bchans[i].disconnecting = 0; + return i; + } + } + return -1; +} + +/* ------------------------------------------------------------------- */ + +static void handle_controller(_cmsg * cmsg) +{ + capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f); + + if (!card) { + printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrController & 0x7f); + return; + } + switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) { + + case CAPI_LISTEN_CONF: /* Controller */ + if (debugmode) + printk(KERN_DEBUG "capidrv: listenconf Info=0x%4x (%s) cipmask=0x%x\n", + cmsg->Info, capi_info2str(cmsg->Info), card->cipmask); + if (cmsg->Info) { + listen_change_state(card, EV_LISTEN_CONF_ERROR); + } else if (card->cipmask == 0) { + listen_change_state(card, EV_LISTEN_CONF_EMPTY); + } else { + listen_change_state(card, EV_LISTEN_CONF_OK); + } + break; + + case CAPI_MANUFACTURER_IND: /* Controller */ + goto ignored; + case CAPI_MANUFACTURER_CONF: /* Controller */ + goto ignored; + case CAPI_FACILITY_IND: /* Controller/plci/ncci */ + goto ignored; + case CAPI_FACILITY_CONF: /* Controller/plci/ncci */ + goto ignored; + case CAPI_INFO_IND: /* Controller/plci */ + goto ignored; + case CAPI_INFO_CONF: /* Controller/plci */ + goto ignored; + + default: + printk(KERN_ERR "capidrv: got %s from controller 0x%x ???", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrController); + } + return; + + ignored: + printk(KERN_INFO "capidrv: %s from controller 0x%x ignored\n", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrController); +} + +static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg) +{ + capidrv_plci *plcip; + capidrv_bchan *bchan; + isdn_ctrl cmd; + int chan; + + if ((chan = new_bchan(card)) == -1) { + printk(KERN_ERR "capidrv: incoming call on not existing bchan ?\n"); + return; + } + bchan = &card->bchans[chan]; + if ((plcip = new_plci(card, chan)) == 0) { + printk(KERN_ERR "capidrv: incoming call: no memory, sorry.\n"); + return; + } + bchan->incoming = 1; + plcip->plci = cmsg->adr.adrPLCI; + plci_change_state(card, plcip, EV_PLCI_CONNECT_IND); + + cmd.command = ISDN_STAT_ICALL; + cmd.driver = card->myid; + cmd.arg = chan; + memset(&cmd.parm.setup, 0, sizeof(cmd.parm.setup)); + strncpy(cmd.parm.setup.phone, + cmsg->CallingPartyNumber + 3, + cmsg->CallingPartyNumber[0] - 2); + strncpy(cmd.parm.setup.eazmsn, + cmsg->CalledPartyNumber + 2, + cmsg->CalledPartyNumber[0] - 1); + cmd.parm.setup.si1 = cip2si1(cmsg->CIPValue); + cmd.parm.setup.si2 = cip2si2(cmsg->CIPValue); + cmd.parm.setup.plan = cmsg->CallingPartyNumber[1]; + cmd.parm.setup.screen = cmsg->CallingPartyNumber[2]; + + printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s\n", + cmd.parm.setup.phone, + cmd.parm.setup.si1, + cmd.parm.setup.si2, + cmd.parm.setup.eazmsn); + + switch (card->interface.statcallb(&cmd)) { + case 0: + /* No device matching this call. + * and isdn_common.c has send a HANGUP command + * which is ignored in state ST_PLCI_INCOMING, + * so we send RESP to ignore the call + */ + capi_cmsg_answer(cmsg); + cmsg->Reject = 1; /* ignore */ + send_message(card, cmsg); + plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT); + printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s ignored\n", + cmd.parm.setup.phone, + cmd.parm.setup.si1, + cmd.parm.setup.si2, + cmd.parm.setup.eazmsn); + break; + case 1: + /* At least one device matching this call (RING on ttyI) + * HL-driver may send ALERTING on the D-channel in this + * case. + * really means: RING on ttyI or a net interface + * accepted this call already. + * + * If the call was accepted, state has already changed, + * and CONNECT_RESP already sent. + */ + if (plcip->state == ST_PLCI_INCOMING) { + printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s tty alerting\n", + cmd.parm.setup.phone, + cmd.parm.setup.si1, + cmd.parm.setup.si2, + cmd.parm.setup.eazmsn); + capi_fill_ALERT_REQ(cmsg, + global.appid, + card->msgid++, + plcip->plci, /* adr */ + 0, /* BChannelinformation */ + 0, /* Keypadfacility */ + 0, /* Useruserdata */ + 0 /* Facilitydataarray */ + ); + plcip->msgid = cmsg->Messagenumber; + send_message(card, cmsg); + } else { + printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s on netdev\n", + cmd.parm.setup.phone, + cmd.parm.setup.si1, + cmd.parm.setup.si2, + cmd.parm.setup.eazmsn); + } + break; + + case 2: /* Call will be rejected. */ + capi_cmsg_answer(cmsg); + cmsg->Reject = 2; /* reject call, normal call clearing */ + send_message(card, cmsg); + plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT); + break; + + default: + /* An error happened. (Invalid parameters for example.) */ + capi_cmsg_answer(cmsg); + cmsg->Reject = 8; /* reject call, + destination out of order */ + send_message(card, cmsg); + plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT); + break; + } + return; +} + +static void handle_plci(_cmsg * cmsg) +{ + capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f); + capidrv_plci *plcip; + isdn_ctrl cmd; + + if (!card) { + printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrController & 0x7f); + return; + } + switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) { + + case CAPI_DISCONNECT_IND: /* plci */ + if (cmsg->Reason) { + printk(KERN_INFO "capidrv: %s reason 0x%x (%s) for plci 0x%x\n", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI); + } + if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) { + capi_cmsg_answer(cmsg); + send_message(card, cmsg); + goto notfound; + } + card->bchans[plcip->chan].disconnecting = 1; + plci_change_state(card, plcip, EV_PLCI_DISCONNECT_IND); + capi_cmsg_answer(cmsg); + send_message(card, cmsg); + plci_change_state(card, plcip, EV_PLCI_DISCONNECT_RESP); + break; + + case CAPI_DISCONNECT_CONF: /* plci */ + if (cmsg->Info) { + printk(KERN_INFO "capidrv: %s info 0x%x (%s) for plci 0x%x\n", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->Info, capi_info2str(cmsg->Info), + cmsg->adr.adrPLCI); + } + if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) + goto notfound; + + card->bchans[plcip->chan].disconnecting = 1; + break; + + case CAPI_ALERT_CONF: /* plci */ + if (cmsg->Info) { + printk(KERN_INFO "capidrv: %s info 0x%x (%s) for plci 0x%x\n", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->Info, capi_info2str(cmsg->Info), + cmsg->adr.adrPLCI); + } + break; + + case CAPI_CONNECT_IND: /* plci */ + handle_incoming_call(card, cmsg); + break; + + case CAPI_CONNECT_CONF: /* plci */ + if (cmsg->Info) { + printk(KERN_INFO "capidrv: %s info 0x%x (%s) for plci 0x%x\n", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->Info, capi_info2str(cmsg->Info), + cmsg->adr.adrPLCI); + } + if (!(plcip = find_plci_by_msgid(card, cmsg->Messagenumber))) + goto notfound; + + plcip->plci = cmsg->adr.adrPLCI; + if (cmsg->Info) { + plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_ERROR); + } else { + plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_OK); + } + break; + + case CAPI_CONNECT_ACTIVE_IND: /* plci */ + + if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) + goto notfound; + + if (card->bchans[plcip->chan].incoming) { + capi_cmsg_answer(cmsg); + send_message(card, cmsg); + plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND); + } else { + capidrv_ncci *nccip; + capi_cmsg_answer(cmsg); + send_message(card, cmsg); + + nccip = new_ncci(card, plcip, cmsg->adr.adrPLCI); + + if (!nccip) { + printk(KERN_ERR "capidrv: no mem for ncci, sorry\n"); + break; /* $$$$ */ + } + capi_fill_CONNECT_B3_REQ(cmsg, + global.appid, + card->msgid++, + plcip->plci, /* adr */ + 0 /* NCPI */ + ); + nccip->msgid = cmsg->Messagenumber; + send_message(card, cmsg); + cmd.command = ISDN_STAT_DCONN; + cmd.driver = card->myid; + cmd.arg = plcip->chan; + card->interface.statcallb(&cmd); + plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND); + ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ); + } + break; + + case CAPI_INFO_IND: /* Controller/plci */ + + if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) + goto notfound; + + if (cmsg->InfoNumber == 0x4000) { + if (cmsg->InfoElement[0] == 4) { + cmd.command = ISDN_STAT_CINF; + cmd.driver = card->myid; + cmd.arg = plcip->chan; + sprintf(cmd.parm.num, "%lu", + (unsigned long) + ((__u32) cmsg->InfoElement[1] + | ((__u32) (cmsg->InfoElement[2]) << 8) + | ((__u32) (cmsg->InfoElement[3]) << 16) + | ((__u32) (cmsg->InfoElement[4]) << 24))); + card->interface.statcallb(&cmd); + break; + } + } + printk(KERN_ERR "capidrv: %s\n", capi_cmsg2str(cmsg)); + break; + + case CAPI_CONNECT_ACTIVE_CONF: /* plci */ + goto ignored; + case CAPI_SELECT_B_PROTOCOL_CONF: /* plci */ + goto ignored; + case CAPI_FACILITY_IND: /* Controller/plci/ncci */ + goto ignored; + case CAPI_FACILITY_CONF: /* Controller/plci/ncci */ + goto ignored; + + case CAPI_INFO_CONF: /* Controller/plci */ + goto ignored; + + default: + printk(KERN_ERR "capidrv: got %s for plci 0x%x ???", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrPLCI); + } + return; + ignored: + printk(KERN_INFO "capidrv: %s for plci 0x%x ignored\n", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrPLCI); + return; + notfound: + printk(KERN_ERR "capidrv: %s: plci 0x%x not found\n", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrPLCI); + return; +} + +static void handle_ncci(_cmsg * cmsg) +{ + capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f); + capidrv_plci *plcip; + capidrv_ncci *nccip; + isdn_ctrl cmd; + + if (!card) { + printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrController & 0x7f); + return; + } + switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) { + + case CAPI_CONNECT_B3_ACTIVE_IND: /* ncci */ + if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) + goto notfound; + + capi_cmsg_answer(cmsg); + send_message(card, cmsg); + ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_ACTIVE_IND); + + cmd.command = ISDN_STAT_BCONN; + cmd.driver = card->myid; + cmd.arg = nccip->chan; + card->interface.statcallb(&cmd); + + printk(KERN_INFO "capidrv: chan %d up with ncci 0x%x\n", + nccip->chan, nccip->ncci); + break; + + case CAPI_CONNECT_B3_ACTIVE_CONF: /* ncci */ + goto ignored; + + case CAPI_CONNECT_B3_IND: /* ncci */ + + plcip = find_plci_by_ncci(card, cmsg->adr.adrNCCI); + if (plcip) { + nccip = new_ncci(card, plcip, cmsg->adr.adrNCCI); + if (nccip) { + ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_IND); + capi_fill_CONNECT_B3_RESP(cmsg, + global.appid, + card->msgid++, + nccip->ncci, /* adr */ + 0, /* Reject */ + 0 /* NCPI */ + ); + send_message(card, cmsg); + ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP); + break; + } + printk(KERN_ERR "capidrv: no mem for ncci, sorry\n"); + } else { + printk(KERN_ERR "capidrv: %s: plci for ncci 0x%x not found\n", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrNCCI); + } + capi_fill_CONNECT_B3_RESP(cmsg, + global.appid, + card->msgid++, + cmsg->adr.adrNCCI, + 2, /* Reject */ + 0 /* NCPI */ + ); + send_message(card, cmsg); + break; + + case CAPI_CONNECT_B3_CONF: /* ncci */ + + if (!(nccip = find_ncci_by_msgid(card, + cmsg->adr.adrNCCI, + cmsg->Messagenumber))) + goto notfound; + + nccip->ncci = cmsg->adr.adrNCCI; + if (cmsg->Info) { + printk(KERN_INFO "capidrv: %s info 0x%x (%s) for ncci 0x%x\n", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->Info, capi_info2str(cmsg->Info), + cmsg->adr.adrNCCI); + } + + if (cmsg->Info) + ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_ERROR); + else + ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_OK); + break; + + case CAPI_CONNECT_B3_T90_ACTIVE_IND: /* ncci */ + capi_cmsg_answer(cmsg); + send_message(card, cmsg); + break; + + case CAPI_DATA_B3_IND: /* ncci */ + /* handled in handle_data() */ + goto ignored; + + case CAPI_DATA_B3_CONF: /* ncci */ + if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) + goto notfound; + + cmd.command = ISDN_STAT_BSENT; + cmd.driver = card->myid; + cmd.arg = nccip->chan; + card->interface.statcallb(&cmd); + + break; + + case CAPI_DISCONNECT_B3_IND: /* ncci */ + if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) + goto notfound; + + card->bchans[nccip->chan].disconnecting = 1; + ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_IND); + capi_cmsg_answer(cmsg); + send_message(card, cmsg); + ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_RESP); + break; + + case CAPI_DISCONNECT_B3_CONF: /* ncci */ + if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) + goto notfound; + if (cmsg->Info) { + printk(KERN_INFO "capidrv: %s info 0x%x (%s) for ncci 0x%x\n", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->Info, capi_info2str(cmsg->Info), + cmsg->adr.adrNCCI); + ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_CONF_ERROR); + } + break; + + case CAPI_RESET_B3_IND: /* ncci */ + capi_cmsg_answer(cmsg); + send_message(card, cmsg); + break; + + case CAPI_RESET_B3_CONF: /* ncci */ + goto ignored; /* $$$$ */ + + case CAPI_FACILITY_IND: /* Controller/plci/ncci */ + goto ignored; + case CAPI_FACILITY_CONF: /* Controller/plci/ncci */ + goto ignored; + + default: + printk(KERN_ERR "capidrv: got %s for ncci 0x%x ???", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrNCCI); + } + return; + ignored: + printk(KERN_INFO "capidrv: %s for ncci 0x%x ignored\n", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrNCCI); + return; + notfound: + printk(KERN_ERR "capidrv: %s: ncci 0x%x not found\n", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrNCCI); +} + + +static void handle_data(_cmsg * cmsg, struct sk_buff *skb) +{ + capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f); + capidrv_ncci *nccip; + + if (!card) { + printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrController & 0x7f); + return; + } + if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) { + printk(KERN_ERR "capidrv: %s: ncci 0x%x not found\n", + capi_cmd2str(cmsg->Command, cmsg->Subcommand), + cmsg->adr.adrNCCI); + kfree_skb(skb, FREE_READ); + return; + } + (void) skb_pull(skb, CAPIMSG_LEN(skb->data)); + card->interface.rcvcallb_skb(card->myid, nccip->chan, skb); + capi_cmsg_answer(cmsg); + send_message(card, cmsg); +} + +static _cmsg s_cmsg; + +static void capidrv_signal(__u16 applid, __u32 dummy) +{ + struct sk_buff *skb = 0; + + while ((*capifuncs->capi_get_message) (global.appid, &skb) == CAPI_NOERROR) { + capi_message2cmsg(&s_cmsg, skb->data); + if (debugmode > 1) + printk(KERN_DEBUG "capidrv_signal: %s\n", capi_cmsg2str(&s_cmsg)); + + if (s_cmsg.Command == CAPI_DATA_B3 + && s_cmsg.Subcommand == CAPI_IND) { + handle_data(&s_cmsg, skb); + continue; + } + kfree_skb(skb, FREE_READ); + if ((s_cmsg.adr.adrController & 0xffffff00) == 0) + handle_controller(&s_cmsg); + else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0) + handle_plci(&s_cmsg); + else + handle_ncci(&s_cmsg); + } +} + +/* ------------------------------------------------------------------- */ + +static _cmsg cmdcmsg; + +static int capidrv_ioctl(isdn_ctrl * c, capidrv_contr * card) +{ + switch (c->arg) { + default: + printk(KERN_DEBUG "capidrv: capidrv_ioctl(%ld) called ??\n", c->arg); + return -EINVAL; + } + return -EINVAL; +} + +static int capidrv_command(isdn_ctrl * c, capidrv_contr * card) +{ + isdn_ctrl cmd; + struct capidrv_bchan *bchan; + struct capidrv_plci *plcip; + + if (c->command == ISDN_CMD_IOCTL) + return capidrv_ioctl(c, card); + + switch (c->command) { + case ISDN_CMD_DIAL:{ + __u8 calling[ISDN_MSNLEN + 3]; + __u8 called[ISDN_MSNLEN + 2]; + + if (debugmode) + printk(KERN_DEBUG "capidrv: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n", + c->arg, + c->parm.setup.phone, + c->parm.setup.si1, + c->parm.setup.si2, + c->parm.setup.eazmsn); + + bchan = &card->bchans[c->arg % card->nbchan]; + + if (bchan->plcip) { + printk(KERN_ERR "capidrv: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n", + c->arg, + c->parm.setup.phone, + c->parm.setup.si1, + c->parm.setup.si2, + c->parm.setup.eazmsn, + bchan->plcip->plci); + return 0; + } + bchan->si1 = c->parm.setup.si1; + bchan->si2 = c->parm.setup.si2; + + strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num)); + strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum)); + + calling[0] = strlen(bchan->mynum) + 2; + calling[1] = 0; + calling[2] = 0x80; + strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN); + + called[0] = strlen(bchan->num) + 1; + called[1] = 0x80; + strncpy(called + 2, bchan->num, ISDN_MSNLEN); + + capi_fill_CONNECT_REQ(&cmdcmsg, + global.appid, + card->msgid++, + 1, /* adr */ + si2cip(bchan->si1, bchan->si2), /* cipvalue */ + called, /* CalledPartyNumber */ + calling, /* CallingPartyNumber */ + 0, /* CalledPartySubaddress */ + 0, /* CallingPartySubaddress */ + b1prot(bchan->l2, bchan->l3), /* B1protocol */ + b2prot(bchan->l2, bchan->l3), /* B2protocol */ + b3prot(bchan->l2, bchan->l3), /* B3protocol */ + 0, /* B1configuration */ + 0, /* B2configuration */ + 0, /* B3configuration */ + 0, /* BC */ + 0, /* LLC */ + 0, /* HLC */ + 0, /* BChannelinformation */ + 0, /* Keypadfacility */ + 0, /* Useruserdata */ + 0 /* Facilitydataarray */ + ); + if ((plcip = new_plci(card, (c->arg % card->nbchan))) == 0) { + cmd.command = ISDN_STAT_DHUP; + cmd.driver = card->myid; + cmd.arg = (c->arg % card->nbchan); + card->interface.statcallb(&cmd); + return -1; + } + plcip->msgid = cmdcmsg.Messagenumber; + plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ); + send_message(card, &cmdcmsg); + return 0; + } + + case ISDN_CMD_ACCEPTD: + + if (debugmode) + printk(KERN_DEBUG "capidrv: ISDN_CMD_ACCEPTD(ch=%ld)\n", + c->arg); + bchan = &card->bchans[c->arg % card->nbchan]; + + capi_fill_CONNECT_RESP(&cmdcmsg, + global.appid, + card->msgid++, + bchan->plcip->plci, /* adr */ + 0, /* Reject */ + b1prot(bchan->l2, bchan->l3), /* B1protocol */ + b2prot(bchan->l2, bchan->l3), /* B2protocol */ + b3prot(bchan->l2, bchan->l3), /* B3protocol */ + 0, /* B1configuration */ + 0, /* B2configuration */ + 0, /* B3configuration */ + 0, /* ConnectedNumber */ + 0, /* ConnectedSubaddress */ + 0, /* LLC */ + 0, /* BChannelinformation */ + 0, /* Keypadfacility */ + 0, /* Useruserdata */ + 0 /* Facilitydataarray */ + ); + capi_cmsg2message(&cmdcmsg, cmdcmsg.buf); + plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP); + send_message(card, &cmdcmsg); + return 0; + + case ISDN_CMD_ACCEPTB: + if (debugmode) + printk(KERN_DEBUG "capidrv: ISDN_CMD_ACCEPTB(ch=%ld)\n", + c->arg); + return -ENOSYS; + + case ISDN_CMD_HANGUP: + if (debugmode) + printk(KERN_DEBUG "capidrv: ISDN_CMD_HANGUP(ch=%ld)\n", + c->arg); + bchan = &card->bchans[c->arg % card->nbchan]; + + if (bchan->disconnecting) { + if (debugmode) + printk(KERN_DEBUG "capidrv: chan %ld already disconnecting ...\n", + c->arg); + return 0; + } + if (bchan->nccip) { + bchan->disconnecting = 1; + capi_fill_DISCONNECT_B3_REQ(&cmdcmsg, + global.appid, + card->msgid++, + bchan->nccip->ncci, + 0 /* NCPI */ + ); + ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ); + send_message(card, &cmdcmsg); + } else if (bchan->plcip) { + bchan->disconnecting = 1; + if (bchan->plcip->state == ST_PLCI_INCOMING) { + /* just ignore, we a called from isdn_status_callback(), + * which will return 0 or 2, this is handled by the + * CONNECT_IND handler + */ + } else { + capi_fill_DISCONNECT_REQ(&cmdcmsg, + global.appid, + card->msgid++, + bchan->plcip->plci, + 0, /* BChannelinformation */ + 0, /* Keypadfacility */ + 0, /* Useruserdata */ + 0 /* Facilitydataarray */ + ); + plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ); + send_message(card, &cmdcmsg); + } + } +/* ready */ + + case ISDN_CMD_SETL2: + if (debugmode) + printk(KERN_DEBUG "capidrv: set L2 on chan %ld to %ld\n", + (c->arg & 0xff), (c->arg >> 8)); + bchan = &card->bchans[c->arg % card->nbchan]; + bchan->l2 = (c->arg >> 8); + return 0; + + case ISDN_CMD_SETL3: + if (debugmode) + printk(KERN_DEBUG "capidrv: set L3 on chan %ld to %ld\n", + (c->arg & 0xff), (c->arg >> 8)); + bchan = &card->bchans[c->arg % card->nbchan]; + bchan->l3 = (c->arg >> 8); + return 0; + + case ISDN_CMD_SETEAZ: + if (debugmode) + printk(KERN_DEBUG "capidrv: set EAZ \"%s\" on chan %ld\n", + c->parm.num, c->arg); + bchan = &card->bchans[c->arg % card->nbchan]; + strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN); + return 0; + + case ISDN_CMD_CLREAZ: + if (debugmode) + printk(KERN_DEBUG "capidrv: clearing EAZ on chan %ld\n", c->arg); + bchan = &card->bchans[c->arg % card->nbchan]; + bchan->msn[0] = 0; + return 0; + + case ISDN_CMD_LOCK: + if (debugmode > 1) + printk(KERN_DEBUG "capidrv: ISDN_CMD_LOCK (%ld)\n", c->arg); + MOD_INC_USE_COUNT; + break; + + case ISDN_CMD_UNLOCK: + if (debugmode > 1) + printk(KERN_DEBUG "capidrv: ISDN_CMD_UNLOCK (%ld)\n", c->arg); + MOD_DEC_USE_COUNT; + break; + +/* never called */ + case ISDN_CMD_GETL2: + if (debugmode) + printk(KERN_DEBUG "capidrv: ISDN_CMD_GETL2\n"); + return -ENODEV; + case ISDN_CMD_GETL3: + if (debugmode) + printk(KERN_DEBUG "capidrv: ISDN_CMD_GETL3\n"); + return -ENODEV; + case ISDN_CMD_GETEAZ: + if (debugmode) + printk(KERN_DEBUG "capidrv: ISDN_CMD_GETEAZ\n"); + return -ENODEV; + case ISDN_CMD_SETSIL: + if (debugmode) + printk(KERN_DEBUG "capidrv: ISDN_CMD_SETSIL\n"); + return -ENODEV; + case ISDN_CMD_GETSIL: + if (debugmode) + printk(KERN_DEBUG "capidrv: ISDN_CMD_GETSIL\n"); + return -ENODEV; + default: + printk(KERN_ERR "capidrv: ISDN_CMD_%d, Huh?\n", c->command); + return -EINVAL; + } + return 0; +} + +static int if_command(isdn_ctrl * c) +{ + capidrv_contr *card = findcontrbydriverid(c->driver); + + if (card) + return capidrv_command(c, card); + + printk(KERN_ERR + "capidrv: if_command %d called with invalid driverId %d!\n", + c->command, c->driver); + return -ENODEV; +} + +static _cmsg sendcmsg; + +static int if_sendbuf(int id, int channel, struct sk_buff *skb) +{ + capidrv_contr *card = findcontrbydriverid(id); + capidrv_bchan *bchan; + capidrv_ncci *nccip; + int len = skb->len; + size_t msglen; + __u16 errcode; + + if (!card) { + printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n", + id); + return 0; + } + bchan = &card->bchans[channel % card->nbchan]; + nccip = bchan->nccip; + if (!nccip || nccip->state != ST_NCCI_ACTIVE) { + printk(KERN_ERR "capidrv: if_sendbuf: %s:%d: chan not up!\n", + card->name, channel); + return 0; + } + capi_fill_DATA_B3_REQ(&sendcmsg, global.appid, card->msgid++, + nccip->ncci, /* adr */ + (__u32) skb->data, /* Data */ + skb->len, /* DataLength */ + nccip->datahandle++, /* DataHandle */ + 0 /* Flags */ + ); + capi_cmsg2message(&sendcmsg, sendcmsg.buf); + msglen = CAPIMSG_LEN(sendcmsg.buf); + if (skb_headroom(skb) < msglen) { + struct sk_buff *nskb = dev_alloc_skb(msglen + skb->len); + if (!nskb) { + printk(KERN_ERR "capidrv: if_sendbuf: no memory\n"); + return 0; + } +#if 0 + printk(KERN_DEBUG "capidrv: only %d bytes headroom\n", + skb_headroom(skb)); +#endif + SET_SKB_FREE(nskb); + memcpy(skb_put(nskb, msglen), sendcmsg.buf, msglen); + memcpy(skb_put(nskb, skb->len), skb->data, skb->len); + errcode = (*capifuncs->capi_put_message) (global.appid, nskb); + switch (errcode) { + case CAPI_NOERROR: + dev_kfree_skb(skb, FREE_WRITE); + return len; + case CAPI_SENDQUEUEFULL: + dev_kfree_skb(nskb, FREE_WRITE); + return 0; + default: + return -1; + } + } else { + memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen); + errcode = (*capifuncs->capi_put_message) (global.appid, skb); + switch (errcode) { + case CAPI_NOERROR: + return len; + case CAPI_SENDQUEUEFULL: + return 0; + default: + return -1; + } + } +} + +static int capidrv_addcontr(__u16 contr, struct capi_profile *profp) +{ + capidrv_contr *card; + isdn_ctrl cmd; + char id[20]; + int i; + + sprintf(id, "capidrv-%d", contr); + if (!(card = (capidrv_contr *) kmalloc(sizeof(capidrv_contr), GFP_ATOMIC))) { + printk(KERN_WARNING + "capidrv: (%s) Could not allocate contr-struct.\n", id); + return -1; + } + memset(card, 0, sizeof(capidrv_contr)); + strcpy(card->name, id); + card->contrnr = contr; + card->nbchan = profp->nbchannel; + card->bchans = (capidrv_bchan *) kmalloc(sizeof(capidrv_bchan) * card->nbchan, GFP_ATOMIC); + if (!card->bchans) { + printk(KERN_WARNING + "capidrv: (%s) Could not allocate bchan-structs.\n", id); + kfree(card); + return -1; + } + card->interface.channels = profp->nbchannel; + card->interface.maxbufsize = 2048; + card->interface.command = if_command; + card->interface.writebuf_skb = if_sendbuf; + card->interface.writecmd = 0; + card->interface.readstat = 0; + card->interface.features = ISDN_FEATURE_L2_X75I | + ISDN_FEATURE_L2_X75UI | + ISDN_FEATURE_L2_X75BUI | + ISDN_FEATURE_L2_HDLC | + ISDN_FEATURE_L2_TRANS | + ISDN_FEATURE_L3_TRANS | + ISDN_FEATURE_P_UNKNOWN; + card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */ + strncpy(card->interface.id, id, sizeof(card->interface.id) - 1); + card->next = global.contr_list; + global.contr_list = card; + global.ncontr++; + + if (!register_isdn(&card->interface)) { + global.contr_list = global.contr_list->next; + printk(KERN_ERR "capidrv: Unable to register contr %s\n", id); + kfree(card->bchans); + kfree(card); + return -1; + } + card->myid = card->interface.channels; + + memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan); + for (i = 0; i < card->nbchan; i++) { + card->bchans[i].contr = card; + } + + cmd.driver = card->myid; + cmd.command = ISDN_STAT_RUN; + card->interface.statcallb(&cmd); + + card->cipmask = 1; /* any */ + card->cipmask2 = 0; + + capi_fill_LISTEN_REQ(&cmdcmsg, global.appid, + card->msgid++, + contr, /* controller */ + 1 << 6, /* Infomask */ + card->cipmask, + card->cipmask2, + 0, 0); + send_message(card, &cmdcmsg); + listen_change_state(card, EV_LISTEN_REQ); + + printk(KERN_INFO "%s: now up (%d B channels)\n", + card->name, card->nbchan); + + return 0; +} + +static int capidrv_delcontr(__u16 contr) +{ + capidrv_contr **pp, *card; + isdn_ctrl cmd; + int i; + + for (pp = &global.contr_list; *pp; pp = &(*pp)->next) { + if ((*pp)->contrnr == contr) + break; + } + if (!*pp) { + printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr); + return -1; + } + card = *pp; + *pp = (*pp)->next; + global.ncontr--; + + for (i = 0; i < card->nbchan; i++) { + if (card->bchans[i].nccip) + free_ncci(card, card->bchans[i].nccip); + if (card->bchans[i].plcip) + free_plci(card, card->bchans[i].plcip); + if (card->plci_list) + printk(KERN_ERR "capidrv: bug in free_plci()\n"); + } + kfree(card->bchans); + + cmd.command = ISDN_STAT_UNLOAD; + cmd.driver = card->myid; + card->interface.statcallb(&cmd); + + printk(KERN_INFO "%s: now down.\n", card->name); + + kfree(card); + + return 0; +} + + +static void lower_callback(unsigned int cmd, __u16 contr, void *data) +{ + switch (cmd) { + case KCI_CONTRUP: + (void) capidrv_addcontr(contr, (capi_profile *) data); + break; + case KCI_CONTRDOWN: + (void) capidrv_delcontr(contr); + break; + } +} + +static struct capi_interface_user cuser = { + "capidrv", + lower_callback +}; + +#ifdef MODULE +#define capidrv_init init_module +#endif + +int capidrv_init(void) +{ + struct capi_register_params rparam; + capi_profile profile; + char rev[10]; + char *p; + __u32 ncontr, contr; + __u16 errcode; + + capifuncs = attach_capi_interface(&cuser); + + if (!capifuncs) + return -EIO; + +#ifndef HAS_NEW_SYMTAB + /* No symbols to export, hide all symbols */ + register_symtab(NULL); +#endif + + if ((p = strchr(revision, ':'))) { + strcpy(rev, p + 1); + p = strchr(rev, '$'); + *p = 0; + } else + strcpy(rev, " ??? "); + + rparam.level3cnt = 2; + rparam.datablkcnt = 8; + rparam.datablklen = 2048; + errcode = (*capifuncs->capi_register) (&rparam, &global.appid); + if (errcode) { + detach_capi_interface(&cuser); + return -EIO; + } + + errcode = (*capifuncs->capi_get_profile) (0, &profile); + if (errcode != CAPI_NOERROR) { + (void) (*capifuncs->capi_release) (global.appid); + detach_capi_interface(&cuser); + return -EIO; + } + + (void) (*capifuncs->capi_set_signal) (global.appid, capidrv_signal, 0); + + ncontr = profile.ncontroller; + for (contr = 1; contr <= ncontr; contr++) { + errcode = (*capifuncs->capi_get_profile) (contr, &profile); + if (errcode != CAPI_NOERROR) + continue; + (void) capidrv_addcontr(contr, &profile); + } + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + capidrv_contr *card, *next; + char rev[10]; + char *p; + + if ((p = strchr(revision, ':'))) { + strcpy(rev, p + 1); + p = strchr(rev, '$'); + *p = 0; + } else { + strcpy(rev, " ??? "); + } + + for (card = global.contr_list; card; card = next) { + next = card->next; + capidrv_delcontr(card->contrnr); + } + + (void) (*capifuncs->capi_release) (global.appid); + detach_capi_interface(&cuser); + + printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev); +} + +#endif diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/avmb1/capidrv.h linux/drivers/isdn/avmb1/capidrv.h --- v2.1.41/linux/drivers/isdn/avmb1/capidrv.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/capidrv.h Wed May 28 10:49:09 1997 @@ -0,0 +1,111 @@ +/* + * $Id: capidrv.h,v 1.1 1997/03/04 21:50:33 calle Exp $ + * + * ISDN4Linux Driver, using capi20 interface (kernelcapi) + * + * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: capidrv.h,v $ + * Revision 1.1 1997/03/04 21:50:33 calle + * Frirst version in isdn4linux + * + * Revision 2.2 1997/02/12 09:31:39 calle + * new version + * + * Revision 1.1 1997/01/31 10:32:20 calle + * Initial revision + * + */ +#ifndef __CAPIDRV_H__ +#define __CAPIDRV_H__ + +/* + * LISTEN state machine + */ +#define ST_LISTEN_NONE 0 /* L-0 */ +#define ST_LISTEN_WAIT_CONF 1 /* L-0.1 */ +#define ST_LISTEN_ACTIVE 2 /* L-1 */ +#define ST_LISTEN_ACTIVE_WAIT_CONF 3 /* L-1.1 */ + + +#define EV_LISTEN_REQ 1 /* L-0 -> L-0.1 + L-1 -> L-1.1 */ +#define EV_LISTEN_CONF_ERROR 2 /* L-0.1 -> L-0 + L-1.1 -> L-1 */ +#define EV_LISTEN_CONF_EMPTY 3 /* L-0.1 -> L-0 + L-1.1 -> L-0 */ +#define EV_LISTEN_CONF_OK 4 /* L-0.1 -> L-1 + L-1.1 -> L.1 */ + +/* + * per plci state machine + */ +#define ST_PLCI_NONE 0 /* P-0 */ +#define ST_PLCI_OUTGOING 1 /* P-0.1 */ +#define ST_PLCI_ALLOCATED 2 /* P-1 */ +#define ST_PLCI_ACTIVE 3 /* P-ACT */ +#define ST_PLCI_INCOMING 4 /* P-2 */ +#define ST_PLCI_FACILITY_IND 5 /* P-3 */ +#define ST_PLCI_ACCEPTING 6 /* P-4 */ +#define ST_PLCI_DISCONNECTING 7 /* P-5 */ +#define ST_PLCI_DISCONNECTED 8 /* P-6 */ + +#define EV_PLCI_CONNECT_REQ 1 /* P-0 -> P-0.1 */ +#define EV_PLCI_CONNECT_CONF_ERROR 2 /* P-0.1 -> P-0 */ +#define EV_PLCI_CONNECT_CONF_OK 3 /* P-0.1 -> P-1 */ +#define EV_PLCI_FACILITY_IND_UP 4 /* P-0 -> P-1 */ +#define EV_PLCI_CONNECT_IND 5 /* P-0 -> P-2 */ +#define EV_PLCI_CONNECT_ACTIVE_IND 6 /* P-1 -> P-ACT */ +#define EV_PLCI_CONNECT_REJECT 7 /* P-2 -> P-5 + P-3 -> P-5 */ +#define EV_PLCI_DISCONNECT_REQ 8 /* P-1 -> P-5 + P-2 -> P-5 + P-3 -> P-5 + P-4 -> P-5 + P-ACT -> P-5 */ +#define EV_PLCI_DISCONNECT_IND 9 /* P-1 -> P-6 + P-2 -> P-6 + P-3 -> P-6 + P-4 -> P-6 + P-5 -> P-6 + P-ACT -> P-6 */ +#define EV_PLCI_FACILITY_IND_DOWN 10 /* P-0.1 -> P-5 + P-1 -> P-5 + P-ACT -> P-5 + P-2 -> P-5 + P-3 -> P-5 + P-4 -> P-5 */ +#define EV_PLCI_DISCONNECT_RESP 11 /* P-6 -> P-0 */ +#define EV_PLCI_CONNECT_RESP 12 /* P-6 -> P-0 */ + +/* + * per ncci state machine + */ +#define ST_NCCI_PREVIOUS -1 +#define ST_NCCI_NONE 0 /* N-0 */ +#define ST_NCCI_OUTGOING 1 /* N-0.1 */ +#define ST_NCCI_INCOMING 2 /* N-1 */ +#define ST_NCCI_ALLOCATED 3 /* N-2 */ +#define ST_NCCI_ACTIVE 4 /* N-ACT */ +#define ST_NCCI_RESETING 5 /* N-3 */ +#define ST_NCCI_DISCONNECTING 6 /* N-4 */ +#define ST_NCCI_DISCONNECTED 7 /* N-5 */ + +#define EV_NCCI_CONNECT_B3_REQ 1 /* N-0 -> N-0.1 */ +#define EV_NCCI_CONNECT_B3_IND 2 /* N-0 -> N.1 */ +#define EV_NCCI_CONNECT_B3_CONF_OK 3 /* N-0.1 -> N.2 */ +#define EV_NCCI_CONNECT_B3_CONF_ERROR 4 /* N-0.1 -> N.0 */ +#define EV_NCCI_CONNECT_B3_REJECT 5 /* N-1 -> N-4 */ +#define EV_NCCI_CONNECT_B3_RESP 6 /* N-1 -> N-2 */ +#define EV_NCCI_CONNECT_B3_ACTIVE_IND 7 /* N-2 -> N-ACT */ +#define EV_NCCI_RESET_B3_REQ 8 /* N-ACT -> N-3 */ +#define EV_NCCI_RESET_B3_IND 9 /* N-3 -> N-ACT */ +#define EV_NCCI_DISCONNECT_B3_IND 10 /* N-4 -> N.5 */ +#define EV_NCCI_DISCONNECT_B3_CONF_ERROR 11 /* N-4 -> previous */ +#define EV_NCCI_DISCONNECT_B3_REQ 12 /* N-1 -> N-4 + N-2 -> N-4 + N-3 -> N-4 + N-ACT -> N-4 */ +#define EV_NCCI_DISCONNECT_B3_RESP 13 /* N-5 -> N-0 */ + +#endif /* __CAPIDRV_H__ */ diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/avmb1/capiutil.c linux/drivers/isdn/avmb1/capiutil.c --- v2.1.41/linux/drivers/isdn/avmb1/capiutil.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/capiutil.c Wed May 28 10:49:09 1997 @@ -0,0 +1,974 @@ +/* + * $Id: capiutil.c,v 1.3 1997/05/18 09:24:18 calle Exp $ + * + * CAPI 2.0 convert capi message to capi message struct + * + * From CAPI 2.0 Development Kit AVM 1995 (msg.c) + * Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: capiutil.c,v $ + * Revision 1.3 1997/05/18 09:24:18 calle + * added verbose disconnect reason reporting to avmb1. + * some fixes in capi20 interface. + * changed info messages for B1-PCI + * + * Revision 1.2 1997/03/05 21:22:13 fritz + * Fix: Symbols have to be exported unconditionally. + * + * Revision 1.1 1997/03/04 21:50:34 calle + * Frirst version in isdn4linux + * + * Revision 2.2 1997/02/12 09:31:39 calle + * new version + * + * Revision 1.1 1997/01/31 10:32:20 calle + * Initial revision + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include "compat.h" +#include "capiutil.h" + +/* from CAPI2.0 DDK AVM Berlin GmbH */ + +#ifndef CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON +char *capi_info2str(__u16 reason) +{ + return ".."; +} +#else +char *capi_info2str(__u16 reason) +{ + switch (reason) { + +/*-- informative values (corresponding message was processed) -----*/ + case 0x0001: + return "NCPI not supported by current protocol, NCPI ignored"; + case 0x0002: + return "Flags not supported by current protocol, flags ignored"; + case 0x0003: + return "Alert already sent by another application"; + +/*-- error information concerning CAPI_REGISTER -----*/ + case 0x1001: + return "Too many applications"; + case 0x1002: + return "Logical block size to small, must be at least 128 Bytes"; + case 0x1003: + return "Buffer exceeds 64 kByte"; + case 0x1004: + return "Message buffer size too small, must be at least 1024 Bytes"; + case 0x1005: + return "Max. number of logical connections not supported"; + case 0x1006: + return "Reserved"; + case 0x1007: + return "The message could not be accepted because of an internal busy condition"; + case 0x1008: + return "OS resource error (no memory ?)"; + case 0x1009: + return "CAPI not installed"; + case 0x100A: + return "Controller does not support external equipment"; + case 0x100B: + return "Controller does only support external equipment"; + +/*-- error information concerning message exchange functions -----*/ + case 0x1101: + return "Illegal application number"; + case 0x1102: + return "Illegal command or subcommand or message length less than 12 bytes"; + case 0x1103: + return "The message could not be accepted because of a queue full condition !! The error code does not imply that CAPI cannot receive messages directed to another controller, PLCI or NCCI"; + case 0x1104: + return "Queue is empty"; + case 0x1105: + return "Queue overflow, a message was lost !! This indicates a configuration error. The only recovery from this error is to perform a CAPI_RELEASE"; + case 0x1106: + return "Unknown notification parameter"; + case 0x1107: + return "The Message could not be accepted because of an internal busy condition"; + case 0x1108: + return "OS Resource error (no memory ?)"; + case 0x1109: + return "CAPI not installed"; + case 0x110A: + return "Controller does not support external equipment"; + case 0x110B: + return "Controller does only support external equipment"; + +/*-- error information concerning resource / coding problems -----*/ + case 0x2001: + return "Message not supported in current state"; + case 0x2002: + return "Illegal Controller / PLCI / NCCI"; + case 0x2003: + return "Out of PLCI"; + case 0x2004: + return "Out of NCCI"; + case 0x2005: + return "Out of LISTEN"; + case 0x2006: + return "Out of FAX resources (protocol T.30)"; + case 0x2007: + return "Illegal message parameter coding"; + +/*-- error information concerning requested services -----*/ + case 0x3001: + return "B1 protocol not supported"; + case 0x3002: + return "B2 protocol not supported"; + case 0x3003: + return "B3 protocol not supported"; + case 0x3004: + return "B1 protocol parameter not supported"; + case 0x3005: + return "B2 protocol parameter not supported"; + case 0x3006: + return "B3 protocol parameter not supported"; + case 0x3007: + return "B protocol combination not supported"; + case 0x3008: + return "NCPI not supported"; + case 0x3009: + return "CIP Value unknown"; + case 0x300A: + return "Flags not supported (reserved bits)"; + case 0x300B: + return "Facility not supported"; + case 0x300C: + return "Data length not supported by current protocol"; + case 0x300D: + return "Reset procedure not supported by current protocol"; + +/*-- informations about the clearing of a physical connection -----*/ + case 0x3301: + return "Protocol error layer 1 (broken line or B-channel removed by signalling protocol)"; + case 0x3302: + return "Protocol error layer 2"; + case 0x3303: + return "Protocol error layer 3"; + case 0x3304: + return "Another application got that call"; +/*-- T.30 specific reasons -----*/ + case 0x3311: + return "Connecting not successful (remote station is no FAX G3 machine)"; + case 0x3312: + return "Connecting not successful (training error)"; + case 0x3313: + return "Disconnected before transfer (remote station does not support transfer mode, e.g. resolution)"; + case 0x3314: + return "Disconnected during transfer (remote abort)"; + case 0x3315: + return "Disconnected during transfer (remote procedure error, e.g. unsuccessful repetition of T.30 commands)"; + case 0x3316: + return "Disconnected during transfer (local tx data underrun)"; + case 0x3317: + return "Disconnected during transfer (local rx data overflow)"; + case 0x3318: + return "Disconnected during transfer (local abort)"; + case 0x3319: + return "Illegal parameter coding (e.g. SFF coding error)"; + +/*-- disconnect causes from the network according to ETS 300 102-1/Q.931 -----*/ + case 0x3481: return "Unallocated (unassigned) number"; + case 0x3482: return "No route to specified transit network"; + case 0x3483: return "No route to destination"; + case 0x3486: return "Channel unacceptable"; + case 0x3487: + return "Call awarded and being delivered in an established channel"; + case 0x3490: return "Normal call clearing"; + case 0x3491: return "User busy"; + case 0x3492: return "No user responding"; + case 0x3493: return "No answer from user (user alerted)"; + case 0x3495: return "Call rejected"; + case 0x3496: return "Number changed"; + case 0x349A: return "Non-selected user clearing"; + case 0x349B: return "Destination out of order"; + case 0x349C: return "Invalid number format"; + case 0x349D: return "Facility rejected"; + case 0x349E: return "Response to STATUS ENQUIRY"; + case 0x349F: return "Normal, unspecified"; + case 0x34A2: return "No circuit / channel available"; + case 0x34A6: return "Network out of order"; + case 0x34A9: return "Temporary failure"; + case 0x34AA: return "Switching equipment congestion"; + case 0x34AB: return "Access information discarded"; + case 0x34AC: return "Requested circuit / channel not available"; + case 0x34AF: return "Resources unavailable, unspecified"; + case 0x34B1: return "Quality of service unavailable"; + case 0x34B2: return "Requested facility not subscribed"; + case 0x34B9: return "Bearer capability not authorized"; + case 0x34BA: return "Bearer capability not presently available"; + case 0x34BF: return "Service or option not available, unspecified"; + case 0x34C1: return "Bearer capability not implemented"; + case 0x34C2: return "Channel type not implemented"; + case 0x34C5: return "Requested facility not implemented"; + case 0x34C6: return "Only restricted digital information bearer capability is available"; + case 0x34CF: return "Service or option not implemented, unspecified"; + case 0x34D1: return "Invalid call reference value"; + case 0x34D2: return "Identified channel does not exist"; + case 0x34D3: return "A suspended call exists, but this call identity does not"; + case 0x34D4: return "Call identity in use"; + case 0x34D5: return "No call suspended"; + case 0x34D6: return "Call having the requested call identity has been cleared"; + case 0x34D8: return "Incompatible destination"; + case 0x34DB: return "Invalid transit network selection"; + case 0x34DF: return "Invalid message, unspecified"; + case 0x34E0: return "Mandatory information element is missing"; + case 0x34E1: return "Message type non-existent or not implemented"; + case 0x34E2: return "Message not compatible with call state or message type non-existent or not implemented"; + case 0x34E3: return "Information element non-existent or not implemented"; + case 0x34E4: return "Invalid information element contents"; + case 0x34E5: return "Message not compatible with call state"; + case 0x34E6: return "Recovery on timer expiry"; + case 0x34EF: return "Protocol error, unspecified"; + case 0x34FF: return "Interworking, unspecified"; + + default: return "No additional information"; + } +} +#endif + +typedef struct { + int typ; + size_t off; +} _cdef; + +#define _CBYTE 1 +#define _CWORD 2 +#define _CDWORD 3 +#define _CSTRUCT 4 +#define _CMSTRUCT 5 +#define _CEND 6 + +static _cdef cdef[] = +{ + /*00 */ + {_CEND}, + /*01 */ + {_CEND}, + /*02 */ + {_CEND}, + /*03 */ + {_CDWORD, offsetof(_cmsg, adr.adrController)}, + /*04 */ + {_CMSTRUCT, offsetof(_cmsg, AdditionalInfo)}, + /*05 */ + {_CSTRUCT, offsetof(_cmsg, B1configuration)}, + /*06 */ + {_CWORD, offsetof(_cmsg, B1protocol)}, + /*07 */ + {_CSTRUCT, offsetof(_cmsg, B2configuration)}, + /*08 */ + {_CWORD, offsetof(_cmsg, B2protocol)}, + /*09 */ + {_CSTRUCT, offsetof(_cmsg, B3configuration)}, + /*0a */ + {_CWORD, offsetof(_cmsg, B3protocol)}, + /*0b */ + {_CSTRUCT, offsetof(_cmsg, BC)}, + /*0c */ + {_CSTRUCT, offsetof(_cmsg, BChannelinformation)}, + /*0d */ + {_CMSTRUCT, offsetof(_cmsg, BProtocol)}, + /*0e */ + {_CSTRUCT, offsetof(_cmsg, CalledPartyNumber)}, + /*0f */ + {_CSTRUCT, offsetof(_cmsg, CalledPartySubaddress)}, + /*10 */ + {_CSTRUCT, offsetof(_cmsg, CallingPartyNumber)}, + /*11 */ + {_CSTRUCT, offsetof(_cmsg, CallingPartySubaddress)}, + /*12 */ + {_CDWORD, offsetof(_cmsg, CIPmask)}, + /*13 */ + {_CDWORD, offsetof(_cmsg, CIPmask2)}, + /*14 */ + {_CWORD, offsetof(_cmsg, CIPValue)}, + /*15 */ + {_CDWORD, offsetof(_cmsg, Class)}, + /*16 */ + {_CSTRUCT, offsetof(_cmsg, ConnectedNumber)}, + /*17 */ + {_CSTRUCT, offsetof(_cmsg, ConnectedSubaddress)}, + /*18 */ + {_CDWORD, offsetof(_cmsg, Data)}, + /*19 */ + {_CWORD, offsetof(_cmsg, DataHandle)}, + /*1a */ + {_CWORD, offsetof(_cmsg, DataLength)}, + /*1b */ + {_CSTRUCT, offsetof(_cmsg, FacilityConfirmationParameter)}, + /*1c */ + {_CSTRUCT, offsetof(_cmsg, Facilitydataarray)}, + /*1d */ + {_CSTRUCT, offsetof(_cmsg, FacilityIndicationParameter)}, + /*1e */ + {_CSTRUCT, offsetof(_cmsg, FacilityRequestParameter)}, + /*1f */ + {_CWORD, offsetof(_cmsg, FacilitySelector)}, + /*20 */ + {_CWORD, offsetof(_cmsg, Flags)}, + /*21 */ + {_CDWORD, offsetof(_cmsg, Function)}, + /*22 */ + {_CSTRUCT, offsetof(_cmsg, HLC)}, + /*23 */ + {_CWORD, offsetof(_cmsg, Info)}, + /*24 */ + {_CSTRUCT, offsetof(_cmsg, InfoElement)}, + /*25 */ + {_CDWORD, offsetof(_cmsg, InfoMask)}, + /*26 */ + {_CWORD, offsetof(_cmsg, InfoNumber)}, + /*27 */ + {_CSTRUCT, offsetof(_cmsg, Keypadfacility)}, + /*28 */ + {_CSTRUCT, offsetof(_cmsg, LLC)}, + /*29 */ + {_CSTRUCT, offsetof(_cmsg, ManuData)}, + /*2a */ + {_CDWORD, offsetof(_cmsg, ManuID)}, + /*2b */ + {_CSTRUCT, offsetof(_cmsg, NCPI)}, + /*2c */ + {_CWORD, offsetof(_cmsg, Reason)}, + /*2d */ + {_CWORD, offsetof(_cmsg, Reason_B3)}, + /*2e */ + {_CWORD, offsetof(_cmsg, Reject)}, + /*2f */ + {_CSTRUCT, offsetof(_cmsg, Useruserdata)} +}; + +static unsigned char *cpars[] = +{ + /*00 */ 0, + /*01 ALERT_REQ */ (unsigned char *) "\x03\x04\x0c\x27\x2f\x1c\x01\x01", + /*02 CONNECT_REQ */ (unsigned char *) "\x03\x14\x0e\x10\x0f\x11\x0d\x06\x08\x0a\x05\x07\x09\x01\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01", + /*03 */ 0, + /*04 DISCONNECT_REQ */ (unsigned char *) "\x03\x04\x0c\x27\x2f\x1c\x01\x01", + /*05 LISTEN_REQ */ (unsigned char *) "\x03\x25\x12\x13\x10\x11\x01", + /*06 */ 0, + /*07 */ 0, + /*08 INFO_REQ */ (unsigned char *) "\x03\x0e\x04\x0c\x27\x2f\x1c\x01\x01", + /*09 FACILITY_REQ */ (unsigned char *) "\x03\x1f\x1e\x01", + /*0a SELECT_B_PROTOCOL_REQ */ (unsigned char *) "\x03\x0d\x06\x08\x0a\x05\x07\x09\x01\x01", + /*0b CONNECT_B3_REQ */ (unsigned char *) "\x03\x2b\x01", + /*0c */ 0, + /*0d DISCONNECT_B3_REQ */ (unsigned char *) "\x03\x2b\x01", + /*0e */ 0, + /*0f DATA_B3_REQ */ (unsigned char *) "\x03\x18\x1a\x19\x20\x01", + /*10 RESET_B3_REQ */ (unsigned char *) "\x03\x2b\x01", + /*11 */ 0, + /*12 */ 0, + /*13 ALERT_CONF */ (unsigned char *) "\x03\x23\x01", + /*14 CONNECT_CONF */ (unsigned char *) "\x03\x23\x01", + /*15 */ 0, + /*16 DISCONNECT_CONF */ (unsigned char *) "\x03\x23\x01", + /*17 LISTEN_CONF */ (unsigned char *) "\x03\x23\x01", + /*18 MANUFACTURER_REQ */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01", + /*19 */ 0, + /*1a INFO_CONF */ (unsigned char *) "\x03\x23\x01", + /*1b FACILITY_CONF */ (unsigned char *) "\x03\x23\x1f\x1b\x01", + /*1c SELECT_B_PROTOCOL_CONF */ (unsigned char *) "\x03\x23\x01", + /*1d CONNECT_B3_CONF */ (unsigned char *) "\x03\x23\x01", + /*1e */ 0, + /*1f DISCONNECT_B3_CONF */ (unsigned char *) "\x03\x23\x01", + /*20 */ 0, + /*21 DATA_B3_CONF */ (unsigned char *) "\x03\x19\x23\x01", + /*22 RESET_B3_CONF */ (unsigned char *) "\x03\x23\x01", + /*23 */ 0, + /*24 */ 0, + /*25 */ 0, + /*26 CONNECT_IND */ (unsigned char *) "\x03\x14\x0e\x10\x0f\x11\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01", + /*27 CONNECT_ACTIVE_IND */ (unsigned char *) "\x03\x16\x17\x28\x01", + /*28 DISCONNECT_IND */ (unsigned char *) "\x03\x2c\x01", + /*29 */ 0, + /*2a MANUFACTURER_CONF */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01", + /*2b */ 0, + /*2c INFO_IND */ (unsigned char *) "\x03\x26\x24\x01", + /*2d FACILITY_IND */ (unsigned char *) "\x03\x1f\x1d\x01", + /*2e */ 0, + /*2f CONNECT_B3_IND */ (unsigned char *) "\x03\x2b\x01", + /*30 CONNECT_B3_ACTIVE_IND */ (unsigned char *) "\x03\x2b\x01", + /*31 DISCONNECT_B3_IND */ (unsigned char *) "\x03\x2d\x2b\x01", + /*32 */ 0, + /*33 DATA_B3_IND */ (unsigned char *) "\x03\x18\x1a\x19\x20\x01", + /*34 RESET_B3_IND */ (unsigned char *) "\x03\x2b\x01", + /*35 CONNECT_B3_T90_ACTIVE_IND */ (unsigned char *) "\x03\x2b\x01", + /*36 */ 0, + /*37 */ 0, + /*38 CONNECT_RESP */ (unsigned char *) "\x03\x2e\x0d\x06\x08\x0a\x05\x07\x09\x01\x16\x17\x28\x04\x0c\x27\x2f\x1c\x01\x01", + /*39 CONNECT_ACTIVE_RESP */ (unsigned char *) "\x03\x01", + /*3a DISCONNECT_RESP */ (unsigned char *) "\x03\x01", + /*3b */ 0, + /*3c MANUFACTURER_IND */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01", + /*3d */ 0, + /*3e INFO_RESP */ (unsigned char *) "\x03\x01", + /*3f FACILITY_RESP */ (unsigned char *) "\x03\x1f\x01", + /*40 */ 0, + /*41 CONNECT_B3_RESP */ (unsigned char *) "\x03\x2e\x2b\x01", + /*42 CONNECT_B3_ACTIVE_RESP */ (unsigned char *) "\x03\x01", + /*43 DISCONNECT_B3_RESP */ (unsigned char *) "\x03\x01", + /*44 */ 0, + /*45 DATA_B3_RESP */ (unsigned char *) "\x03\x19\x01", + /*46 RESET_B3_RESP */ (unsigned char *) "\x03\x01", + /*47 CONNECT_B3_T90_ACTIVE_RESP */ (unsigned char *) "\x03\x01", + /*48 */ 0, + /*49 */ 0, + /*4a */ 0, + /*4b */ 0, + /*4c */ 0, + /*4d */ 0, + /*4e MANUFACTURER_RESP */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01", +}; + +/*-------------------------------------------------------*/ + +#define byteTLcpy(x,y) *(__u8 *)(x)=*(__u8 *)(y); +#define wordTLcpy(x,y) *(__u16 *)(x)=*(__u16 *)(y); +#define dwordTLcpy(x,y) memcpy(x,y,4); +#define structTLcpy(x,y,l) memcpy (x,y,l) +#define structTLcpyovl(x,y,l) memmove (x,y,l) + +#define byteTRcpy(x,y) *(__u8 *)(y)=*(__u8 *)(x); +#define wordTRcpy(x,y) *(__u16 *)(y)=*(__u16 *)(x); +#define dwordTRcpy(x,y) memcpy(y,x,4); +#define structTRcpy(x,y,l) memcpy (y,x,l) +#define structTRcpyovl(x,y,l) memmove (y,x,l) + +/*-------------------------------------------------------*/ +static unsigned command_2_index(unsigned c, unsigned sc) +{ + if (c & 0x80) + c = 0x9 + (c & 0x0f); + else if (c <= 0x0f); + else if (c == 0x41) + c = 0x9 + 0x1; + else if (c == 0xff) + c = 0x00; + return (sc & 3) * (0x9 + 0x9) + c; +} + +/*-------------------------------------------------------*/ +#define TYP (cdef[cmsg->par[cmsg->p]].typ) +#define OFF (((__u8 *)cmsg)+cdef[cmsg->par[cmsg->p]].off) + +static void jumpcstruct(_cmsg * cmsg) +{ + unsigned layer; + for (cmsg->p++, layer = 1; layer;) { + /* $$$$$ assert (cmsg->p); */ + cmsg->p++; + switch (TYP) { + case _CMSTRUCT: + layer++; + break; + case _CEND: + layer--; + break; + } + } +} +/*-------------------------------------------------------*/ +static void pars_2_message(_cmsg * cmsg) +{ + + for (; TYP != _CEND; cmsg->p++) { + switch (TYP) { + case _CBYTE: + byteTLcpy(cmsg->m + cmsg->l, OFF); + cmsg->l++; + break; + case _CWORD: + wordTLcpy(cmsg->m + cmsg->l, OFF); + cmsg->l += 2; + break; + case _CDWORD: + dwordTLcpy(cmsg->m + cmsg->l, OFF); + cmsg->l += 4; + break; + case _CSTRUCT: + if (*(__u8 **) OFF == 0) { + *(cmsg->m + cmsg->l) = '\0'; + cmsg->l++; + } else if (**(_cstruct *) OFF != 0xff) { + structTLcpy(cmsg->m + cmsg->l, *(_cstruct *) OFF, 1 + **(_cstruct *) OFF); + cmsg->l += 1 + **(_cstruct *) OFF; + } else { + _cstruct s = *(_cstruct *) OFF; + structTLcpy(cmsg->m + cmsg->l, s, 3 + *(__u16 *) (s + 1)); + cmsg->l += 3 + *(__u16 *) (s + 1); + } + break; + case _CMSTRUCT: +/*----- Metastruktur 0 -----*/ + if (*(_cmstruct *) OFF == CAPI_DEFAULT) { + *(cmsg->m + cmsg->l) = '\0'; + cmsg->l++; + jumpcstruct(cmsg); + } +/*----- Metastruktur wird composed -----*/ + else { + unsigned _l = cmsg->l; + unsigned _ls; + cmsg->l++; + cmsg->p++; + pars_2_message(cmsg); + _ls = cmsg->l - _l - 1; + if (_ls < 255) + (cmsg->m + _l)[0] = (__u8) _ls; + else { + structTLcpyovl(cmsg->m + _l + 3, cmsg->m + _l + 1, _ls); + (cmsg->m + _l)[0] = 0xff; + wordTLcpy(cmsg->m + _l + 1, &_ls); + } + } + break; + } + } +} + +/*-------------------------------------------------------*/ +unsigned capi_cmsg2message(_cmsg * cmsg, __u8 * msg) +{ + cmsg->m = msg; + cmsg->l = 8; + cmsg->p = 0; + cmsg->par = cpars[command_2_index(cmsg->Command, cmsg->Subcommand)]; + + pars_2_message(cmsg); + + wordTLcpy(msg + 0, &cmsg->l); + byteTLcpy(cmsg->m + 4, &cmsg->Command); + byteTLcpy(cmsg->m + 5, &cmsg->Subcommand); + wordTLcpy(cmsg->m + 2, &cmsg->ApplId); + wordTLcpy(cmsg->m + 6, &cmsg->Messagenumber); + + return 0; +} + +/*-------------------------------------------------------*/ +static void message_2_pars(_cmsg * cmsg) +{ + for (; TYP != _CEND; cmsg->p++) { + + switch (TYP) { + case _CBYTE: + byteTRcpy(cmsg->m + cmsg->l, OFF); + cmsg->l++; + break; + case _CWORD: + wordTRcpy(cmsg->m + cmsg->l, OFF); + cmsg->l += 2; + break; + case _CDWORD: + dwordTRcpy(cmsg->m + cmsg->l, OFF); + cmsg->l += 4; + break; + case _CSTRUCT: + *(__u8 **) OFF = cmsg->m + cmsg->l; + + if (cmsg->m[cmsg->l] != 0xff) + cmsg->l += 1 + cmsg->m[cmsg->l]; + else + cmsg->l += 3 + *(__u16 *) (cmsg->m + cmsg->l + 1); + break; + case _CMSTRUCT: +/*----- Metastruktur 0 -----*/ + if (cmsg->m[cmsg->l] == '\0') { + *(_cmstruct *) OFF = CAPI_DEFAULT; + cmsg->l++; + jumpcstruct(cmsg); + } else { + unsigned _l = cmsg->l; + *(_cmstruct *) OFF = CAPI_COMPOSE; + cmsg->l = (cmsg->m + _l)[0] == 255 ? cmsg->l + 3 : cmsg->l + 1; + cmsg->p++; + message_2_pars(cmsg); + } + break; + } + } +} + +/*-------------------------------------------------------*/ +unsigned capi_message2cmsg(_cmsg * cmsg, __u8 * msg) +{ + memset(cmsg, 0, sizeof(_cmsg)); + cmsg->m = msg; + cmsg->l = 8; + cmsg->p = 0; + byteTRcpy(cmsg->m + 4, &cmsg->Command); + byteTRcpy(cmsg->m + 5, &cmsg->Subcommand); + cmsg->par = cpars[command_2_index(cmsg->Command, cmsg->Subcommand)]; + + message_2_pars(cmsg); + + wordTRcpy(msg + 0, &cmsg->l); + wordTRcpy(cmsg->m + 2, &cmsg->ApplId); + wordTRcpy(cmsg->m + 6, &cmsg->Messagenumber); + + return 0; +} + +/*-------------------------------------------------------*/ +unsigned capi_cmsg_header(_cmsg * cmsg, __u16 _ApplId, + __u8 _Command, __u8 _Subcommand, + __u16 _Messagenumber, __u32 _Controller) +{ + memset(cmsg, 0, sizeof(_cmsg)); + cmsg->ApplId = _ApplId; + cmsg->Command = _Command; + cmsg->Subcommand = _Subcommand; + cmsg->Messagenumber = _Messagenumber; + cmsg->adr.adrController = _Controller; + return 0; +} + +/*-------------------------------------------------------*/ + +static char *mnames[] = +{ + 0, + "ALERT_REQ", + "CONNECT_REQ", + 0, + "DISCONNECT_REQ", + "LISTEN_REQ", + 0, + 0, + "INFO_REQ", + "FACILITY_REQ", + "SELECT_B_PROTOCOL_REQ", + "CONNECT_B3_REQ", + 0, + "DISCONNECT_B3_REQ", + 0, + "DATA_B3_REQ", + "RESET_B3_REQ", + 0, + 0, + "ALERT_CONF", + "CONNECT_CONF", + 0, + "DISCONNECT_CONF", + "LISTEN_CONF", + "MANUFACTURER_REQ", + 0, + "INFO_CONF", + "FACILITY_CONF", + "SELECT_B_PROTOCOL_CONF", + "CONNECT_B3_CONF", + 0, + "DISCONNECT_B3_CONF", + 0, + "DATA_B3_CONF", + "RESET_B3_CONF", + 0, + 0, + 0, + "CONNECT_IND", + "CONNECT_ACTIVE_IND", + "DISCONNECT_IND", + 0, + "MANUFACTURER_CONF", + 0, + "INFO_IND", + "FACILITY_IND", + 0, + "CONNECT_B3_IND", + "CONNECT_B3_ACTIVE_IND", + "DISCONNECT_B3_IND", + 0, + "DATA_B3_IND", + "RESET_B3_IND", + "CONNECT_B3_T90_ACTIVE_IND", + 0, + 0, + "CONNECT_RESP", + "CONNECT_ACTIVE_RESP", + "DISCONNECT_RESP", + 0, + "MANUFACTURER_IND", + 0, + "INFO_RESP", + "FACILITY_RESP", + 0, + "CONNECT_B3_RESP", + "CONNECT_B3_ACTIVE_RESP", + "DISCONNECT_B3_RESP", + 0, + "DATA_B3_RESP", + "RESET_B3_RESP", + "CONNECT_B3_T90_ACTIVE_RESP", + 0, + 0, + 0, + 0, + 0, + 0, + "MANUFACTURER_RESP" +}; + +char *capi_cmd2str(__u8 cmd, __u8 subcmd) +{ + return mnames[command_2_index(cmd, subcmd)]; +} + + +/*-------------------------------------------------------*/ +/*-------------------------------------------------------*/ + +static char *pnames[] = +{ + /*00 */ 0, + /*01 */ 0, + /*02 */ 0, + /*03 */ "Controller/PLCI/NCCI", + /*04 */ "AdditionalInfo", + /*05 */ "B1configuration", + /*06 */ "B1protocol", + /*07 */ "B2configuration", + /*08 */ "B2protocol", + /*09 */ "B3configuration", + /*0a */ "B3protocol", + /*0b */ "BC", + /*0c */ "BChannelinformation", + /*0d */ "BProtocol", + /*0e */ "CalledPartyNumber", + /*0f */ "CalledPartySubaddress", + /*10 */ "CallingPartyNumber", + /*11 */ "CallingPartySubaddress", + /*12 */ "CIPmask", + /*13 */ "CIPmask2", + /*14 */ "CIPValue", + /*15 */ "Class", + /*16 */ "ConnectedNumber", + /*17 */ "ConnectedSubaddress", + /*18 */ "Data", + /*19 */ "DataHandle", + /*1a */ "DataLength", + /*1b */ "FacilityConfirmationParameter", + /*1c */ "Facilitydataarray", + /*1d */ "FacilityIndicationParameter", + /*1e */ "FacilityRequestParameter", + /*1f */ "FacilitySelector", + /*20 */ "Flags", + /*21 */ "Function", + /*22 */ "HLC", + /*23 */ "Info", + /*24 */ "InfoElement", + /*25 */ "InfoMask", + /*26 */ "InfoNumber", + /*27 */ "Keypadfacility", + /*28 */ "LLC", + /*29 */ "ManuData", + /*2a */ "ManuID", + /*2b */ "NCPI", + /*2c */ "Reason", + /*2d */ "Reason_B3", + /*2e */ "Reject", + /*2f */ "Useruserdata" +}; + + +static char buf[8192]; +static char *p = 0; + +#include + +/*-------------------------------------------------------*/ +static void bufprint(char *fmt,...) +{ + va_list f; + va_start(f, fmt); + vsprintf(p, fmt, f); + va_end(f); + p += strlen(p); +} + +static void printstructlen(__u8 * m, unsigned len) +{ + unsigned hex = 0; + for (; len; len--, m++) + if (isalnum(*m) || *m == ' ') { + if (hex) + bufprint(">"); + bufprint("%c", *m); + hex = 0; + } else { + if (!hex) + bufprint("<%02x", *m); + else + bufprint(" %02x", *m); + hex = 1; + } + if (hex) + bufprint(">"); +} + +static void printstruct(__u8 * m) +{ + unsigned len; + if (m[0] != 0xff) { + len = m[0]; + m += 1; + } else { + len = ((__u16 *) (m + 1))[0]; + m += 3; + } + printstructlen(m, len); +} + +/*-------------------------------------------------------*/ +#define NAME (pnames[cmsg->par[cmsg->p]]) + +static void protocol_message_2_pars(_cmsg * cmsg, int level) +{ + for (; TYP != _CEND; cmsg->p++) { + int slen = 29 + 3 - level; + int i; + + bufprint(" "); + for (i = 0; i < level - 1; i++) + bufprint(" "); + + switch (TYP) { + case _CBYTE: + bufprint("%-*s = 0x%x\n", slen, NAME, *(__u8 *) (cmsg->m + cmsg->l)); + cmsg->l++; + break; + case _CWORD: + bufprint("%-*s = 0x%x\n", slen, NAME, *(__u16 *) (cmsg->m + cmsg->l)); + cmsg->l += 2; + break; + case _CDWORD: + if (strcmp(NAME, "Data") == 0) { + bufprint("%-*s = ", slen, NAME); + printstructlen((__u8 *) * (__u32 *) (cmsg->m + cmsg->l), + *(__u16 *) (cmsg->m + cmsg->l + sizeof(__u32))); + bufprint("\n"); + } else + bufprint("%-*s = 0x%lx\n", slen, NAME, *(__u32 *) (cmsg->m + cmsg->l)); + cmsg->l += 4; + break; + case _CSTRUCT: + bufprint("%-*s = ", slen, NAME); + if (cmsg->m[cmsg->l] == '\0') + bufprint("default"); + else + printstruct(cmsg->m + cmsg->l); + bufprint("\n"); + if (cmsg->m[cmsg->l] != 0xff) + cmsg->l += 1 + cmsg->m[cmsg->l]; + else + cmsg->l += 3 + *(__u16 *) (cmsg->m + cmsg->l + 1); + + break; + + case _CMSTRUCT: +/*----- Metastruktur 0 -----*/ + if (cmsg->m[cmsg->l] == '\0') { + bufprint("%-*s = default\n", slen, NAME); + cmsg->l++; + jumpcstruct(cmsg); + } else { + char *name = NAME; + unsigned _l = cmsg->l; + bufprint("%-*s\n", slen, name); + cmsg->l = (cmsg->m + _l)[0] == 255 ? cmsg->l + 3 : cmsg->l + 1; + cmsg->p++; + protocol_message_2_pars(cmsg, level + 1); + } + break; + } + } +} +/*-------------------------------------------------------*/ +char *capi_message2str(__u8 * msg) +{ + + _cmsg cmsg; + p = buf; + p[0] = 0; + + cmsg.m = msg; + cmsg.l = 8; + cmsg.p = 0; + byteTRcpy(cmsg.m + 4, &cmsg.Command); + byteTRcpy(cmsg.m + 5, &cmsg.Subcommand); + cmsg.par = cpars[command_2_index(cmsg.Command, cmsg.Subcommand)]; + + bufprint("%-26s ID=%03d #0x%04x LEN=%04d\n", + mnames[command_2_index(cmsg.Command, cmsg.Subcommand)], + ((unsigned short *) msg)[1], + ((unsigned short *) msg)[3], + ((unsigned short *) msg)[0]); + + protocol_message_2_pars(&cmsg, 1); + return buf; +} + +char *capi_cmsg2str(_cmsg * cmsg) +{ + p = buf; + p[0] = 0; + cmsg->l = 8; + cmsg->p = 0; + bufprint("%s ID=%03d #0x%04x LEN=%04d\n", + mnames[command_2_index(cmsg->Command, cmsg->Subcommand)], + ((__u16 *) cmsg->m)[1], + ((__u16 *) cmsg->m)[3], + ((__u16 *) cmsg->m)[0]); + protocol_message_2_pars(cmsg, 1); + return buf; +} + + +#ifdef HAS_NEW_SYMTAB +EXPORT_SYMBOL(capi_cmsg2message); +EXPORT_SYMBOL(capi_message2cmsg); +EXPORT_SYMBOL(capi_cmsg_header); +EXPORT_SYMBOL(capi_cmd2str); +EXPORT_SYMBOL(capi_cmsg2str); +EXPORT_SYMBOL(capi_message2str); +#else +static struct symbol_table capifunc_syms = +{ +#include + X(capi_cmsg2message), + X(capi_message2cmsg), + X(capi_cmsg_header), + X(capi_cmd2str), + X(capi_cmsg2str), + X(capi_message2str), + X(capi_info2str), +#include +}; +#endif + +#ifdef MODULE + +int init_module(void) +{ +#ifndef HAS_NEW_SYMTAB + register_symtab(&capifunc_syms); +#endif + return 0; +} + +void cleanup_module(void) +{ +} + +#endif diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/avmb1/capiutil.h linux/drivers/isdn/avmb1/capiutil.h --- v2.1.41/linux/drivers/isdn/avmb1/capiutil.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/capiutil.h Wed May 28 10:49:09 1997 @@ -0,0 +1,501 @@ +/* + * $Id: capiutil.h,v 1.2 1997/05/18 09:24:19 calle Exp $ + * + * CAPI 2.0 defines & types + * + * From CAPI 2.0 Development Kit AVM 1995 (capi20.h) + * Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: capiutil.h,v $ + * Revision 1.2 1997/05/18 09:24:19 calle + * added verbose disconnect reason reporting to avmb1. + * some fixes in capi20 interface. + * changed info messages for B1-PCI + * + * Revision 1.1 1997/03/04 21:50:35 calle + * Frirst version in isdn4linux + * + * Revision 2.2 1997/02/12 09:31:39 calle + * new version + * + * Revision 1.1 1997/01/31 10:32:20 calle + * Initial revision + * + * + */ +#ifndef __CAPIUTIL_H__ +#define __CAPIUTIL_H__ + +#include + +#define CAPIMSG_LEN(m) (m[0] | (m[1] << 8)) +#define CAPIMSG_APPID(m) (m[2] | (m[3] << 8)) +#define CAPIMSG_COMMAND(m) (m[4]) +#define CAPIMSG_SUBCOMMAND(m) (m[5]) +#define CAPIMSG_MSGID(m) (m[6] | (m[7] << 8)) +#define CAPIMSG_CONTROLLER(m) (m[8] & 0x7f) +#define CAPIMSG_CONTROL(m) (m[8]|(m[9]<<8)|(m[10]<<16)|(m[11]<<24)) +#define CAPIMSG_NCCI(m) CAPIMSG_CONTROL(m) +#define CAPIMSG_DATA(m) (m[12]|(m[13]<<8)|(m[14]<<16)|(m[15]<<24)) +#define CAPIMSG_DATALEN(m) (m[16] | (m[17]<<8)) + +#define CAPIMSG_SETAPPID(m, applid) \ + do { \ + ((__u8 *)m)[2] = (__u16)(applid) & 0xff; \ + ((__u8 *)m)[3] = ((__u16)(applid) >> 8) & 0xff; \ + } while (0) + +#define CAPIMSG_SETDATA(m, data) \ + do { \ + ((__u8 *)m)[12] = (__u32)(data) & 0xff; \ + ((__u8 *)m)[13] = ((__u32)(data) >> 8) & 0xff; \ + ((__u8 *)m)[14] = ((__u32)(data) >> 16) & 0xff; \ + ((__u8 *)m)[15] = ((__u32)(data) >> 24) & 0xff; \ + } while (0) + +/*----- basic-type definitions -----*/ + +typedef __u8 *_cstruct; + +typedef enum { + CAPI_COMPOSE, + CAPI_DEFAULT +} _cmstruct; + +/* + The _cmsg structure contains all possible CAPI 2.0 parameter. + All parameters are stored here first. The function CAPI_CMSG_2_MESSAGE + assembles the parameter and builds CAPI2.0 conform messages. + CAPI_MESSAGE_2_CMSG disassembles CAPI 2.0 messages and stores the + parameter in the _cmsg structure + */ + +typedef struct { + /* Header */ + __u16 ApplId; + __u8 Command; + __u8 Subcommand; + __u16 Messagenumber; + + /* Parameter */ + union { + __u32 adrController; + __u32 adrPLCI; + __u32 adrNCCI; + } adr; + + _cmstruct AdditionalInfo; + _cstruct B1configuration; + __u16 B1protocol; + _cstruct B2configuration; + __u16 B2protocol; + _cstruct B3configuration; + __u16 B3protocol; + _cstruct BC; + _cstruct BChannelinformation; + _cmstruct BProtocol; + _cstruct CalledPartyNumber; + _cstruct CalledPartySubaddress; + _cstruct CallingPartyNumber; + _cstruct CallingPartySubaddress; + __u32 CIPmask; + __u32 CIPmask2; + __u16 CIPValue; + __u32 Class; + _cstruct ConnectedNumber; + _cstruct ConnectedSubaddress; + __u32 Data; + __u16 DataHandle; + __u16 DataLength; + _cstruct FacilityConfirmationParameter; + _cstruct Facilitydataarray; + _cstruct FacilityIndicationParameter; + _cstruct FacilityRequestParameter; + __u16 FacilitySelector; + __u16 Flags; + __u32 Function; + _cstruct HLC; + __u16 Info; + _cstruct InfoElement; + __u32 InfoMask; + __u16 InfoNumber; + _cstruct Keypadfacility; + _cstruct LLC; + _cstruct ManuData; + __u32 ManuID; + _cstruct NCPI; + __u16 Reason; + __u16 Reason_B3; + __u16 Reject; + _cstruct Useruserdata; + + /* intern */ + unsigned l, p; + unsigned char *par; + __u8 *m; + + /* buffer to construct message */ + __u8 buf[180]; + +} _cmsg; + +/* + * capi_cmsg2message() assembles the parameter from _cmsg to a CAPI 2.0 + * conform message + */ +unsigned capi_cmsg2message(_cmsg * cmsg, __u8 * msg); + +/* + * capi_message2cmsg disassembles a CAPI message an writes the parameter + * into _cmsg for easy access + */ +unsigned capi_message2cmsg(_cmsg * cmsg, __u8 * msg); + +/* + * capi_cmsg_header() fills the _cmsg structure with default values, so only + * parameter with non default values must be changed before sending the + * message. + */ +unsigned capi_cmsg_header(_cmsg * cmsg, __u16 _ApplId, + __u8 _Command, __u8 _Subcommand, + __u16 _Messagenumber, __u32 _Controller); + +/* + * capi_info2str generated a readable string for Capi2.0 reasons. + */ +char *capi_info2str(__u16 reason); + +/*-----------------------------------------------------------------------*/ + +/* + * Debugging / Tracing functions + */ +char *capi_cmd2str(__u8 cmd, __u8 subcmd); +char *capi_cmsg2str(_cmsg * cmsg); +char *capi_message2str(__u8 * msg); + +/*-----------------------------------------------------------------------*/ + +static inline void capi_cmsg_answer(_cmsg * cmsg) +{ + cmsg->Subcommand |= 0x01; +} + +/*-----------------------------------------------------------------------*/ + +static inline void capi_fill_CONNECT_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr, + _cstruct NCPI) +{ + capi_cmsg_header(cmsg, ApplId, 0x82, 0x80, Messagenumber, adr); + cmsg->NCPI = NCPI; +} + +static inline void capi_fill_FACILITY_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr, + __u16 FacilitySelector, + _cstruct FacilityRequestParameter) +{ + capi_cmsg_header(cmsg, ApplId, 0x80, 0x80, Messagenumber, adr); + cmsg->FacilitySelector = FacilitySelector; + cmsg->FacilityRequestParameter = FacilityRequestParameter; +} + +static inline void capi_fill_INFO_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr, + _cstruct CalledPartyNumber, + _cstruct BChannelinformation, + _cstruct Keypadfacility, + _cstruct Useruserdata, + _cstruct Facilitydataarray) +{ + capi_cmsg_header(cmsg, ApplId, 0x08, 0x80, Messagenumber, adr); + cmsg->CalledPartyNumber = CalledPartyNumber; + cmsg->BChannelinformation = BChannelinformation; + cmsg->Keypadfacility = Keypadfacility; + cmsg->Useruserdata = Useruserdata; + cmsg->Facilitydataarray = Facilitydataarray; +} + +static inline void capi_fill_LISTEN_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr, + __u32 InfoMask, + __u32 CIPmask, + __u32 CIPmask2, + _cstruct CallingPartyNumber, + _cstruct CallingPartySubaddress) +{ + capi_cmsg_header(cmsg, ApplId, 0x05, 0x80, Messagenumber, adr); + cmsg->InfoMask = InfoMask; + cmsg->CIPmask = CIPmask; + cmsg->CIPmask2 = CIPmask2; + cmsg->CallingPartyNumber = CallingPartyNumber; + cmsg->CallingPartySubaddress = CallingPartySubaddress; +} + +static inline void capi_fill_ALERT_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr, + _cstruct BChannelinformation, + _cstruct Keypadfacility, + _cstruct Useruserdata, + _cstruct Facilitydataarray) +{ + capi_cmsg_header(cmsg, ApplId, 0x01, 0x80, Messagenumber, adr); + cmsg->BChannelinformation = BChannelinformation; + cmsg->Keypadfacility = Keypadfacility; + cmsg->Useruserdata = Useruserdata; + cmsg->Facilitydataarray = Facilitydataarray; +} + +static inline void capi_fill_CONNECT_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr, + __u16 CIPValue, + _cstruct CalledPartyNumber, + _cstruct CallingPartyNumber, + _cstruct CalledPartySubaddress, + _cstruct CallingPartySubaddress, + __u16 B1protocol, + __u16 B2protocol, + __u16 B3protocol, + _cstruct B1configuration, + _cstruct B2configuration, + _cstruct B3configuration, + _cstruct BC, + _cstruct LLC, + _cstruct HLC, + _cstruct BChannelinformation, + _cstruct Keypadfacility, + _cstruct Useruserdata, + _cstruct Facilitydataarray) +{ + + capi_cmsg_header(cmsg, ApplId, 0x02, 0x80, Messagenumber, adr); + cmsg->CIPValue = CIPValue; + cmsg->CalledPartyNumber = CalledPartyNumber; + cmsg->CallingPartyNumber = CallingPartyNumber; + cmsg->CalledPartySubaddress = CalledPartySubaddress; + cmsg->CallingPartySubaddress = CallingPartySubaddress; + cmsg->B1protocol = B1protocol; + cmsg->B2protocol = B2protocol; + cmsg->B3protocol = B3protocol; + cmsg->B1configuration = B1configuration; + cmsg->B2configuration = B2configuration; + cmsg->B3configuration = B3configuration; + cmsg->BC = BC; + cmsg->LLC = LLC; + cmsg->HLC = HLC; + cmsg->BChannelinformation = BChannelinformation; + cmsg->Keypadfacility = Keypadfacility; + cmsg->Useruserdata = Useruserdata; + cmsg->Facilitydataarray = Facilitydataarray; +} + +static inline void capi_fill_DATA_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr, + __u32 Data, + __u16 DataLength, + __u16 DataHandle, + __u16 Flags) +{ + + capi_cmsg_header(cmsg, ApplId, 0x86, 0x80, Messagenumber, adr); + cmsg->Data = Data; + cmsg->DataLength = DataLength; + cmsg->DataHandle = DataHandle; + cmsg->Flags = Flags; +} + +static inline void capi_fill_DISCONNECT_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr, + _cstruct BChannelinformation, + _cstruct Keypadfacility, + _cstruct Useruserdata, + _cstruct Facilitydataarray) +{ + + capi_cmsg_header(cmsg, ApplId, 0x04, 0x80, Messagenumber, adr); + cmsg->BChannelinformation = BChannelinformation; + cmsg->Keypadfacility = Keypadfacility; + cmsg->Useruserdata = Useruserdata; + cmsg->Facilitydataarray = Facilitydataarray; +} + +static inline void capi_fill_DISCONNECT_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr, + _cstruct NCPI) +{ + + capi_cmsg_header(cmsg, ApplId, 0x84, 0x80, Messagenumber, adr); + cmsg->NCPI = NCPI; +} + +static inline void capi_fill_MANUFACTURER_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr, + __u32 ManuID, + __u32 Class, + __u32 Function, + _cstruct ManuData) +{ + + capi_cmsg_header(cmsg, ApplId, 0xff, 0x80, Messagenumber, adr); + cmsg->ManuID = ManuID; + cmsg->Class = Class; + cmsg->Function = Function; + cmsg->ManuData = ManuData; +} + +static inline void capi_fill_RESET_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr, + _cstruct NCPI) +{ + + capi_cmsg_header(cmsg, ApplId, 0x87, 0x80, Messagenumber, adr); + cmsg->NCPI = NCPI; +} + +static inline void capi_fill_SELECT_B_PROTOCOL_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr, + __u16 B1protocol, + __u16 B2protocol, + __u16 B3protocol, + _cstruct B1configuration, + _cstruct B2configuration, + _cstruct B3configuration) +{ + + capi_cmsg_header(cmsg, ApplId, 0x41, 0x80, Messagenumber, adr); + cmsg->B1protocol = B1protocol; + cmsg->B2protocol = B2protocol; + cmsg->B3protocol = B3protocol; + cmsg->B1configuration = B1configuration; + cmsg->B2configuration = B2configuration; + cmsg->B3configuration = B3configuration; +} + +static inline void capi_fill_CONNECT_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr, + __u16 Reject, + __u16 B1protocol, + __u16 B2protocol, + __u16 B3protocol, + _cstruct B1configuration, + _cstruct B2configuration, + _cstruct B3configuration, + _cstruct ConnectedNumber, + _cstruct ConnectedSubaddress, + _cstruct LLC, + _cstruct BChannelinformation, + _cstruct Keypadfacility, + _cstruct Useruserdata, + _cstruct Facilitydataarray) +{ + capi_cmsg_header(cmsg, ApplId, 0x02, 0x83, Messagenumber, adr); + cmsg->Reject = Reject; + cmsg->B1protocol = B1protocol; + cmsg->B2protocol = B2protocol; + cmsg->B3protocol = B3protocol; + cmsg->B1configuration = B1configuration; + cmsg->B2configuration = B2configuration; + cmsg->B3configuration = B3configuration; + cmsg->ConnectedNumber = ConnectedNumber; + cmsg->ConnectedSubaddress = ConnectedSubaddress; + cmsg->LLC = LLC; + cmsg->BChannelinformation = BChannelinformation; + cmsg->Keypadfacility = Keypadfacility; + cmsg->Useruserdata = Useruserdata; + cmsg->Facilitydataarray = Facilitydataarray; +} + +static inline void capi_fill_CONNECT_ACTIVE_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr) +{ + + capi_cmsg_header(cmsg, ApplId, 0x03, 0x83, Messagenumber, adr); +} + +static inline void capi_fill_CONNECT_B3_ACTIVE_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr) +{ + + capi_cmsg_header(cmsg, ApplId, 0x83, 0x83, Messagenumber, adr); +} + +static inline void capi_fill_CONNECT_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr, + __u16 Reject, + _cstruct NCPI) +{ + capi_cmsg_header(cmsg, ApplId, 0x82, 0x83, Messagenumber, adr); + cmsg->Reject = Reject; + cmsg->NCPI = NCPI; +} + +static inline void capi_fill_CONNECT_B3_T90_ACTIVE_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr) +{ + + capi_cmsg_header(cmsg, ApplId, 0x88, 0x83, Messagenumber, adr); +} + +static inline void capi_fill_DATA_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr, + __u16 DataHandle) +{ + + capi_cmsg_header(cmsg, ApplId, 0x86, 0x83, Messagenumber, adr); + cmsg->DataHandle = DataHandle; +} + +static inline void capi_fill_DISCONNECT_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr) +{ + + capi_cmsg_header(cmsg, ApplId, 0x84, 0x83, Messagenumber, adr); +} + +static inline void capi_fill_DISCONNECT_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr) +{ + + capi_cmsg_header(cmsg, ApplId, 0x04, 0x83, Messagenumber, adr); +} + +static inline void capi_fill_FACILITY_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr, + __u16 FacilitySelector) +{ + + capi_cmsg_header(cmsg, ApplId, 0x80, 0x83, Messagenumber, adr); + cmsg->FacilitySelector = FacilitySelector; +} + +static inline void capi_fill_INFO_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr) +{ + + capi_cmsg_header(cmsg, ApplId, 0x08, 0x83, Messagenumber, adr); +} + +static inline void capi_fill_MANUFACTURER_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr, + __u32 ManuID, + __u32 Class, + __u32 Function, + _cstruct ManuData) +{ + + capi_cmsg_header(cmsg, ApplId, 0xff, 0x83, Messagenumber, adr); + cmsg->ManuID = ManuID; + cmsg->Class = Class; + cmsg->Function = Function; + cmsg->ManuData = ManuData; +} + +static inline void capi_fill_RESET_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber, + __u32 adr) +{ + + capi_cmsg_header(cmsg, ApplId, 0x87, 0x83, Messagenumber, adr); +} + +#endif /* __CAPIUTIL_H__ */ diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/avmb1/compat.h linux/drivers/isdn/avmb1/compat.h --- v2.1.41/linux/drivers/isdn/avmb1/compat.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/compat.h Wed May 28 10:49:09 1997 @@ -0,0 +1,30 @@ +/* + * $Id: compat.h,v 1.1 1997/03/04 21:50:36 calle Exp $ + * + * Headerfile for Compartibility between different kernel versions + * + * (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: compat.h,v $ + * Revision 1.1 1997/03/04 21:50:36 calle + * Frirst version in isdn4linux + * + * Revision 2.2 1997/02/12 09:31:39 calle + * new version + * + * Revision 1.1 1997/01/31 10:32:20 calle + * Initial revision + * + * + */ +#ifndef __COMPAT_H__ +#define __COMPAT_H__ + +#include +#include + +#if LINUX_VERSION_CODE >= 0x020112 /* 2.1.18 */ +#define HAS_NEW_SYMTAB +#endif + +#endif /* __COMPAT_H__ */ diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/Makefile linux/drivers/isdn/hisax/Makefile --- v2.1.41/linux/drivers/isdn/hisax/Makefile Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/Makefile Wed May 28 10:49:09 1997 @@ -1,6 +1,6 @@ L_OBJS := M_OBJS := -O_OBJS := isdnl1.o config.o buffers.o tei.o isdnl2.o isdnl3.o \ +O_OBJS := isdnl1.o config.o tei.o isdnl2.o isdnl3.o \ q931.o callc.o fsm.o # EXTRA_CFLAGS += -S @@ -9,6 +9,10 @@ O_OBJS += l3dss1.o endif +ifeq ($(CONFIG_HISAX_NI1),y) + O_OBJS += l3ni1.o +endif + ifeq ($(CONFIG_HISAX_1TR6),y) O_OBJS += l3_1tr6.o endif @@ -26,6 +30,10 @@ endif ifeq ($(CONFIG_HISAX_ELSA_PCC),y) + O_OBJS += elsa.o +endif + +ifeq ($(CONFIG_HISAX_ELSA_PCMCIA),y) O_OBJS += elsa.o endif diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/avm_a1.c linux/drivers/isdn/hisax/avm_a1.c --- v2.1.41/linux/drivers/isdn/hisax/avm_a1.c Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/avm_a1.c Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: avm_a1.c,v 1.4 1997/01/27 15:50:21 keil Exp $ +/* $Id: avm_a1.c,v 1.6 1997/04/13 19:54:07 keil Exp $ * avm_a1.c low level stuff for AVM A1 (Fritz) isdn cards * @@ -6,6 +6,12 @@ * * * $Log: avm_a1.c,v $ + * Revision 1.6 1997/04/13 19:54:07 keil + * Change in IRQ check delay for SMP + * + * Revision 1.5 1997/04/06 22:54:10 keil + * Using SKB's + * * Revision 1.4 1997/01/27 15:50:21 keil * SMP proof,cosmetics * @@ -28,32 +34,32 @@ #include extern const char *CardType[]; -const char *avm_revision = "$Revision: 1.4 $"; +const char *avm_revision = "$Revision: 1.6 $"; #define byteout(addr,val) outb_p(val,addr) #define bytein(addr) inb_p(addr) -static inline byte -readreg(unsigned int adr, byte off) +static inline u_char +readreg(unsigned int adr, u_char off) { return (bytein(adr + off)); } static inline void -writereg(unsigned int adr, byte off, byte data) +writereg(unsigned int adr, u_char off, u_char data) { byteout(adr + off, data); } static inline void -read_fifo(unsigned int adr, byte * data, int size) +read_fifo(unsigned int adr, u_char * data, int size) { insb(adr - 0x400, data, size); } static void -write_fifo(unsigned int adr, byte * data, int size) +write_fifo(unsigned int adr, u_char * data, int size) { outsb(adr - 0x400, data, size); } @@ -84,8 +90,9 @@ if (!to) printk(KERN_WARNING "AVM A1: waitforXFW timeout\n"); } + static inline void -writehscxCMDR(int adr, byte data) +writehscxCMDR(int adr, u_char data) { long flags; @@ -127,25 +134,22 @@ static void hscx_empty_fifo(struct HscxState *hsp, int count) { - byte *ptr; + u_char *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 (hsp->rcvidx + count > HSCX_BUFMAX) { if (sp->debug & L1_DEB_WARN) debugl1(sp, "hscx_empty_fifo: incoming packet too large"); writehscxCMDR(sp->hscx[hsp->hscx], 0x80); + hsp->rcvidx = 0; return; } - ptr = DATAPTR(ibh); - ptr += hsp->rcvptr; - - hsp->rcvptr += count; + ptr = hsp->rcvbuf + hsp->rcvidx; + hsp->rcvidx += count; save_flags(flags); cli(); read_fifo(sp->hscx[hsp->hscx], ptr, count); @@ -166,34 +170,32 @@ hscx_fill_fifo(struct HscxState *hsp) { struct IsdnCardState *sp = hsp->sp; - struct BufHeader *ibh; int more, count; - byte *ptr; + u_char *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) + if (!hsp->tx_skb) return; - - count = ibh->datasize - hsp->sendptr; - if (count <= 0) + if (hsp->tx_skb->len <= 0) return; more = (hsp->mode == 1) ? 1 : 0; - if (count > 32) { + if (hsp->tx_skb->len > 32) { more = !0; count = 32; - } - ptr = DATAPTR(ibh); - ptr += hsp->sendptr; - hsp->sendptr += count; + } else + count = hsp->tx_skb->len; waitforXFW(sp->hscx[hsp->hscx]); save_flags(flags); cli(); + ptr = hsp->tx_skb->data; + skb_pull(hsp->tx_skb, count); + hsp->tx_cnt -= count; + hsp->count += count; write_fifo(sp->hscx[hsp->hscx], ptr, count); writehscxCMDR(sp->hscx[hsp->hscx], more ? 0x8 : 0xa); restore_flags(flags); @@ -209,11 +211,12 @@ } static inline void -hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx) +hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx) { - byte r; + u_char r; struct HscxState *hsp = sp->hs + hscx; - int count, err; + struct sk_buff *skb; + int count; char tmp[32]; if (!hsp->init) @@ -235,79 +238,57 @@ 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; + } else { + count = readreg(sp->hscx[hsp->hscx], HSCX_RBCL) & 0x1f; + if (count == 0) + count = 32; + hscx_empty_fifo(hsp, count); + if ((count = hsp->rcvidx - 1) > 0) { + if (!(skb = dev_alloc_skb(count))) + printk(KERN_WARNING "AVM: receive out of memory\n"); + else { + memcpy(skb_put(skb, count), hsp->rcvbuf, count); + skb_queue_tail(&hsp->rqueue, skb); + } + } } - 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; + hsp->rcvidx = 0; 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; + if (!(skb = dev_alloc_skb(32))) + printk(KERN_WARNING "AVM: receive out of memory\n"); + else { + memcpy(skb_put(skb, 32), hsp->rcvbuf, 32); + skb_queue_tail(&hsp->rqueue, skb); + } + hsp->rcvidx = 0; hscx_sched_event(hsp, HSCX_RCVBUFREADY); } } - afterRPF: if (val & 0x10) { /* XPR */ - if (hsp->xmtibh) - if (hsp->xmtibh->datasize > hsp->sendptr) { + if (hsp->tx_skb) + if (hsp->tx_skb->len) { hscx_fill_fifo(hsp); - goto afterXPR; + return; } else { - if (hsp->releasebuf) - BufPoolRelease(hsp->xmtibh); - hsp->sendptr = 0; + SET_SKB_FREE(hsp->tx_skb); + dev_kfree_skb(hsp->tx_skb, FREE_WRITE); + hsp->count = 0; if (hsp->st->l4.l1writewakeup) hsp->st->l4.l1writewakeup(hsp->st); - hsp->xmtibh = NULL; + hsp->tx_skb = NULL; } - if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) { - hsp->releasebuf = !0; + if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) { + hsp->count = 0; hscx_fill_fifo(hsp); } else hscx_sched_event(hsp, HSCX_XMTBUFREADY); } - afterXPR: } /* @@ -317,26 +298,26 @@ static void isac_empty_fifo(struct IsdnCardState *sp, int count) { - byte *ptr; - struct BufHeader *ibh = sp->rcvibh; + u_char *ptr; 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->rcvidx + count) >= MAX_DFRAME_LEN) { if (sp->debug & L1_DEB_WARN) { char tmp[40]; - sprintf(tmp, "isac_empty_fifo rcvptr %d", sp->rcvptr); + sprintf(tmp, "isac_empty_fifo overrun %d", + sp->rcvidx + count); debugl1(sp, tmp); } + writereg(sp->isac, ISAC_CMDR, 0x80); + sp->rcvidx = 0; return; } - ptr = DATAPTR(ibh); - ptr += sp->rcvptr; - sp->rcvptr += count; - + ptr = sp->rcvbuf + sp->rcvidx; + sp->rcvidx += count; save_flags(flags); cli(); read_fifo(sp->isac, ptr, count); @@ -355,35 +336,30 @@ static void isac_fill_fifo(struct IsdnCardState *sp) { - struct BufHeader *ibh; int count, more; - byte *ptr; + u_char *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) + if (!sp->tx_skb) return; - count = ibh->datasize - sp->sendptr; + count = sp->tx_skb->len; 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(); + ptr = sp->tx_skb->data; + skb_pull(sp->tx_skb, count); + sp->tx_cnt += count; write_fifo(sp->isac, ptr, count); writereg(sp->isac, ISAC_CMDR, more ? 0x8 : 0xa); restore_flags(flags); @@ -410,9 +386,10 @@ static inline void -isac_interrupt(struct IsdnCardState *sp, byte val) +isac_interrupt(struct IsdnCardState *sp, u_char val) { - byte exval; + u_char exval; + struct sk_buff *skb; unsigned int count; char tmp[32]; @@ -429,62 +406,45 @@ 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; + } else { + count = readreg(sp->isac, ISAC_RBCL) & 0x1f; + if (count == 0) + count = 32; + isac_empty_fifo(sp, count); + if ((count = sp->rcvidx) > 0) { + if (!(skb = alloc_skb(count, GFP_ATOMIC))) + printk(KERN_WARNING "AVM: D receive out of memory\n"); + else { + memcpy(skb_put(skb, count), sp->rcvbuf, count); + skb_queue_tail(&sp->rq, skb); + } + } } - 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; + sp->rcvidx = 0; 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) { + if (sp->tx_skb) + if (sp->tx_skb->len) { isac_fill_fifo(sp); goto afterXPR; } else { - if (sp->releasebuf) - BufPoolRelease(sp->xmtibh); - sp->xmtibh = NULL; - sp->sendptr = 0; + SET_SKB_FREE(sp->tx_skb); + dev_kfree_skb(sp->tx_skb, FREE_WRITE); + sp->tx_cnt = 0; + sp->tx_skb = NULL; } - if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) { - sp->releasebuf = !0; + if ((sp->tx_skb = skb_dequeue(&sp->sq))) { + sp->tx_cnt = 0; isac_fill_fifo(sp); } else isac_sched_event(sp, ISAC_XMTBUFREADY); @@ -514,10 +474,10 @@ } static inline void -hscx_int_main(struct IsdnCardState *sp, byte val) +hscx_int_main(struct IsdnCardState *sp, u_char val) { - byte exval; + u_char exval; struct HscxState *hsp; char tmp[32]; @@ -532,7 +492,11 @@ /* Here we lost an TX interrupt, so * restart transmitting the whole frame. */ - hsp->sendptr = 0; + if (hsp->tx_skb) { + skb_push(hsp->tx_skb, hsp->count); + hsp->tx_cnt += hsp->count; + hsp->count = 0; + } writehscxCMDR(sp->hscx[hsp->hscx], 0x01); if (sp->debug & L1_DEB_WARN) { sprintf(tmp, "HSCX B EXIR %x Lost TX", exval); @@ -561,7 +525,11 @@ /* Here we lost an TX interrupt, so * restart transmitting the whole frame. */ - hsp->sendptr = 0; + if (hsp->tx_skb) { + skb_push(hsp->tx_skb, hsp->count); + hsp->tx_cnt += hsp->count; + hsp->count = 0; + } writehscxCMDR(sp->hscx[hsp->hscx], 0x01); if (sp->debug & L1_DEB_WARN) { sprintf(tmp, "HSCX A EXIR %x Lost TX", exval); @@ -587,7 +555,7 @@ avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *sp; - byte val, sval, stat = 0; + u_char val, sval, stat = 0; char tmp[32]; sp = (struct IsdnCardState *) irq2dev_map[intno]; @@ -675,48 +643,48 @@ 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 { + case (0): 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_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, 0x8c); - writereg(sp->hscx[hscx], HSCX_CMDR, 0x41); - break; + 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); } @@ -801,6 +769,7 @@ initavm_a1(struct IsdnCardState *sp) { int ret; + int loop = 0; char tmp[40]; sp->counter = kstat.interrupts[sp->irq]; @@ -812,6 +781,16 @@ initisac(sp); sp->modehscx(sp->hs, 0, 0); sp->modehscx(sp->hs + 1, 0, 0); + while (loop++ < 10) { + /* At least 1-3 irqs must happen + * (one from HSCX A, one from HSCX B, 3rd from ISAC) + */ + if (kstat.interrupts[sp->irq] > sp->counter) + break; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + 1; + schedule(); + } sprintf(tmp, "IRQ %d count %d", sp->irq, kstat.interrupts[sp->irq]); debugl1(sp, tmp); @@ -830,7 +809,7 @@ int setup_avm_a1(struct IsdnCard *card) { - byte val, verA, verB; + u_char val, verA, verB; struct IsdnCardState *sp = card->sp; long flags; char tmp[64]; diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/callc.c linux/drivers/isdn/hisax/callc.c --- v2.1.41/linux/drivers/isdn/hisax/callc.c Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/callc.c Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: callc.c,v 1.20 1997/02/17 00:32:47 keil Exp $ +/* $Id: callc.c,v 1.29 1997/04/23 20:09:49 fritz Exp $ * Author Karsten Keil (keil@temic-ech.spacenet.de) * based on the teles driver from Jan den Ouden @@ -7,6 +7,34 @@ * Fritz Elfert * * $Log: callc.c,v $ + * Revision 1.29 1997/04/23 20:09:49 fritz + * Removed tmp, used by removed debugging code. + * + * Revision 1.28 1997/04/21 13:42:25 keil + * Remove unneeded debug + * + * Revision 1.27 1997/04/16 14:21:01 keil + * remove unused variable + * + * Revision 1.26 1997/04/13 19:55:21 keil + * Changes in debugging code + * + * Revision 1.25 1997/04/06 22:54:08 keil + * Using SKB's + * + * Revision 1.24 1997/03/05 11:28:03 keil + * fixed undefined l2tei procedure + * a layer1 release delete now the drel timer + * + * Revision 1.23 1997/03/04 23:07:42 keil + * bugfix dial parameter + * + * Revision 1.22 1997/02/27 13:51:55 keil + * Reset B-channel (dlc) statemachine in every release + * + * Revision 1.21 1997/02/19 09:24:27 keil + * Bugfix: Hangup to LL if a ttyI rings + * * Revision 1.20 1997/02/17 00:32:47 keil * Bugfix: No Busy reported to LL * @@ -81,7 +109,7 @@ #endif #endif /* MODULE */ -const char *l4_revision = "$Revision: 1.20 $"; +const char *l4_revision = "$Revision: 1.29 $"; extern struct IsdnCard cards[]; extern int nrcards; @@ -304,18 +332,18 @@ l4_deliver_cause(struct Channel *chanp) { isdn_ctrl ic; - - if (chanp->para.cause<0) + + 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); + sprintf(ic.parm.num, "E%02X%02X", chanp->para.loc & 0x7f, + chanp->para.cause & 0x7f); else - sprintf(ic.parm.num, "%02X%02X", chanp->para.loc, - chanp->para.cause); + sprintf(ic.parm.num, "%02X%02X", chanp->para.loc & 0x7f, + chanp->para.cause & 0x7f); chanp->sp->iif.statcallb(&ic); } @@ -325,15 +353,11 @@ 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; @@ -614,8 +638,9 @@ { struct Channel *chanp = fi->userdata; - chanp->Flags = 0; FsmChangeState(fi, ST_NULL); + chanp->Flags = 0; + FsmDelTimer(&chanp->drel_timer, 63); } static void @@ -718,11 +743,9 @@ release_ds(chanp); RESBIT(chanp->Flags, FLG_START_B); } - if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND)) { + if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND | FLG_CALL_ALERT)) { 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; @@ -734,6 +757,8 @@ RESBIT(chanp->Flags, FLG_DISC_SEND); RESBIT(chanp->Flags, FLG_CALL_REC); RESBIT(chanp->Flags, FLG_CALL_ALERT); + RESBIT(chanp->Flags, FLG_LL_DCONN); + RESBIT(chanp->Flags, FLG_CALL_SEND); } static void @@ -762,11 +787,9 @@ release_ds(chanp); RESBIT(chanp->Flags, FLG_START_B); } - if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND)) { + if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND | FLG_CALL_ALERT)) { 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; @@ -778,6 +801,8 @@ RESBIT(chanp->Flags, FLG_DISC_SEND); RESBIT(chanp->Flags, FLG_CALL_REC); RESBIT(chanp->Flags, FLG_CALL_ALERT); + RESBIT(chanp->Flags, FLG_LL_DCONN); + RESBIT(chanp->Flags, FLG_CALL_SEND); } static void @@ -802,18 +827,17 @@ release_ds(chanp); RESBIT(chanp->Flags, FLG_START_B); } - if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND)) { + if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND | FLG_CALL_ALERT)) { 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_LL_DCONN); + RESBIT(chanp->Flags, FLG_CALL_SEND); RESBIT(chanp->Flags, FLG_CALL_ALERT); chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL); } @@ -964,11 +988,11 @@ 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; + chanp->para.cause = 0x2f; + chanp->para.loc = 0; } else { - chanp->para.cause = 0x70; - chanp->para.loc = 0; + chanp->para.cause = 0x70; + chanp->para.loc = 0; } l4_deliver_cause(chanp); ic.driver = chanp->sp->myid; @@ -986,6 +1010,7 @@ {ST_NULL, EV_DIAL, l4_prep_dialout}, {ST_NULL, EV_SETUP_IND, l4_start_dchan}, {ST_NULL, EV_SHUTDOWN_D, l4_shutdown_d}, + {ST_NULL, EV_DLRL, l4_go_null}, {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}, @@ -1057,10 +1082,6 @@ - - - - #define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode)) static void @@ -1194,6 +1215,9 @@ + + + #define LC_FN_COUNT (sizeof(LcFnList)/sizeof(struct FsmNode)) void @@ -1240,6 +1264,9 @@ releasestack_transl2(st); break; } + /* Reset B-Channel Statemachine */ + FsmDelTimer(&chanp->lc_b.act_timer, 79); + FsmChangeState(&chanp->lc_b.lcfi, ST_LC_NULL); } static void @@ -1306,8 +1333,18 @@ } static void -ll_handler(struct PStack *st, int pr, - struct BufHeader *ibh) +l2tei_dummy(struct PStack *st, int pr, void *arg) +{ + struct Channel *chanp = (struct Channel *) st->l4.userdata; + char tmp[64], tm[32]; + + jiftime(tm, jiffies); + sprintf(tmp, "%s Channel %d Warning! Dummy l2tei called pr=%d\n", tm, chanp->chan, pr); + HiSax_putstatus(chanp->sp, tmp); +} + +static void +ll_handler(struct PStack *st, int pr, void *arg) { struct Channel *chanp = (struct Channel *) st->l4.userdata; char tmp[64], tm[32]; @@ -1347,9 +1384,12 @@ 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); + if (chanp->debug & 2048) { + jiftime(tm, jiffies); + sprintf(tmp, "%s Channel %d L3->L4 unknown primitiv %d\n", + tm, chanp->chan, pr); + HiSax_putstatus(chanp->sp, tmp); + } } } @@ -1525,7 +1565,6 @@ releasestack_isdnl2(st); releasestack_isdnl3(st); HiSax_rmlist(st->l1.hardware, st); - BufQueueRelease(&st->l2.i_queue); } void @@ -1546,23 +1585,19 @@ } static void -lldata_handler(struct PStack *st, int pr, - void *arg) +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; + struct sk_buff *skb = 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); + if (chanp->data_open) + chanp->sp->iif.rcvcallb_skb(chanp->sp->myid, chanp->chan, skb); + else { + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); } - BufPoolRelease(ibh); break; default: printk(KERN_WARNING "lldata_handler unknown primitive %d\n", @@ -1572,19 +1607,19 @@ } static void -lltrans_handler(struct PStack *st, int pr, - struct BufHeader *ibh) +lltrans_handler(struct PStack *st, int pr, void *arg) { struct Channel *chanp = (struct Channel *) st->l4.userdata; - byte *ptr; + struct sk_buff *skb = arg; switch (pr) { case (PH_DATA): - if (chanp->data_open) { - ptr = DATAPTR(ibh); - chanp->sp->iif.rcvcallb(chanp->sp->myid, chanp->chan, ptr, ibh->datasize); + if (chanp->data_open) + chanp->sp->iif.rcvcallb_skb(chanp->sp->myid, chanp->chan, skb); + else { + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); } - BufPoolRelease(ibh); break; default: printk(KERN_WARNING "lltrans_handler unknown primitive %d\n", @@ -1616,7 +1651,6 @@ st->l1.hardware = sp; hsp->mode = 2; - hsp->transbufsize = 4000; if (setstack_hscx(st, hsp)) return (-1); @@ -1637,6 +1671,7 @@ st->l2.l2l3 = lldata_handler; st->l1.l1man = dcc_l1man; st->l2.l2man = dcc_l2man; + st->l2.l2tei = l2tei_dummy; st->l4.userdata = chanp; st->l4.l1writewakeup = NULL; st->l4.l2writewakeup = ll_writewakeup; @@ -1726,16 +1761,19 @@ 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); + ic->parm.setup.si1, ic->parm.setup.si2); link_debug(chanp, tmp, 1); } + chanp->para.setup = ic->parm.setup; + if (!strcmp(chanp->para.setup.eazmsn, "0")) + chanp->para.setup.eazmsn[0] = '\0'; /* 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); + FsmEvent(&chanp->fi, EV_DIAL, NULL); } else { FsmDelTimer(&chanp->dial_timer, 70); - FsmAddTimer(&chanp->dial_timer, 50, EV_DIAL, ic, 71); + FsmAddTimer(&chanp->dial_timer, 50, EV_DIAL, NULL, 71); } break; case (ISDN_CMD_ACCEPTB): @@ -1849,7 +1887,7 @@ 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); + csta->cardnr + 1, csta->debug); HiSax_putstatus(cards[0].sp, tmp); printk(KERN_DEBUG "HiSax: %s", tmp); break; @@ -1875,14 +1913,14 @@ } int -HiSax_writebuf(int id, int chan, const u_char * buf, int count, int user) +HiSax_writebuf_skb(int id, int chan, struct sk_buff *skb) { struct IsdnCardState *csta = hisax_findcard(id); struct Channel *chanp; struct PStack *st; - struct BufHeader *ibh; - int err, i; - byte *ptr; + int len = skb->len; + unsigned long flags; + struct sk_buff *nskb; char tmp[64]; if (!csta) { @@ -1896,51 +1934,38 @@ 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); + if (len > MAX_DATA_SIZE) { + sprintf(tmp, "writebuf: packet too large (%d bytes)", len); printk(KERN_WARNING "HiSax_%s !\n", tmp); link_debug(chanp, tmp, 1); - return (-EINVAL); + 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); + if (len) { + if ((len + csta->hs[chanp->hscx].tx_cnt) > MAX_DATA_MEM) { + /* Must return 0 here, since this is not an error + * but a temporary lack of resources. + */ + if (chanp->debug & 2048) { + sprintf(tmp, "writebuf: no buffers for %d bytes", len); + link_debug(chanp, tmp, 1); + } + return 0; + } + save_flags(flags); + cli(); + nskb = skb_clone(skb, GFP_ATOMIC); + if (nskb) { + if (chanp->lc_b.l2_establish) { + csta->hs[chanp->hscx].tx_cnt += len + st->l2.ihsize; + chanp->ds.l3.l3l2(&chanp->ds, DL_DATA, nskb); + } else { + csta->hs[chanp->hscx].tx_cnt += len; + chanp->ds.l2.l2l1(&chanp->ds, PH_DATA, nskb); + } + dev_kfree_skb(skb, FREE_WRITE); + } else + len = 0; + restore_flags(flags); } + return (len); } diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c --- v2.1.41/linux/drivers/isdn/hisax/config.c Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/config.c Wed May 28 10:49:09 1997 @@ -1,10 +1,22 @@ -/* $Id: config.c,v 1.11 1997/02/14 12:23:12 fritz Exp $ +/* $Id: config.c,v 1.15 1997/04/06 22:57:24 keil Exp $ * Author Karsten Keil (keil@temic-ech.spacenet.de) * based on the teles driver from Jan den Ouden * * * $Log: config.c,v $ + * Revision 1.15 1997/04/06 22:57:24 keil + * Hisax version 2.1 + * + * Revision 1.14 1997/03/25 23:11:22 keil + * US NI-1 protocol + * + * Revision 1.13 1997/03/23 21:45:49 keil + * Add support for ELSA PCMCIA + * + * Revision 1.12 1997/03/11 21:01:43 keil + * nzproto is only used with modules + * * Revision 1.11 1997/02/14 12:23:12 fritz * Added support for new insmod parameter handling. * @@ -63,11 +75,12 @@ * 5 AVM A1 (Fritz) p0=irq p1=iobase * 6 ELSA PC [p0=iobase] or nothing (autodetect) * 7 ELSA Quickstep p0=irq p1=iobase + * ELSA PCMCIA 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 + * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1 * * */ @@ -76,6 +89,10 @@ #define DEFAULT_CARD ISDN_CTYPE_ELSA #define DEFAULT_CFG {0,0,0} #endif +#ifdef CONFIG_HISAX_ELSA_PCMCIA +#define DEFAULT_CARD ISDN_CTYPE_ELSA_QS1000 +#define DEFAULT_CFG {3,0x2f8,0} +#endif #ifdef CONFIG_HISAX_AVM_A1 #undef DEFAULT_CARD #undef DEFAULT_CFG @@ -112,6 +129,12 @@ #undef DEFAULT_PROTO_NAME #define DEFAULT_PROTO_NAME "EURO" #endif +#ifdef CONFIG_HISAX_NI1 +#undef DEFAULT_PROTO +#define DEFAULT_PROTO ISDN_PTYPE_NI1 +#undef DEFAULT_PROTO_NAME +#define DEFAULT_PROTO_NAME "NI1" +#endif #ifndef DEFAULT_PROTO #define DEFAULT_PROTO ISDN_PTYPE_UNKNOWN #define DEFAULT_PROTO_NAME "UNKNOWN" @@ -280,8 +303,9 @@ int i; char tmp[64], rev[64]; char *r = rev; +#ifdef MODULE int nzproto = 0; - +#endif nrcards = 0; strcpy(tmp, l1_revision); r += sprintf(r, "%s/", HiSax_getrev(tmp)); @@ -295,7 +319,7 @@ 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: Version 2.1\n"); printk(KERN_NOTICE "HiSax: Revisions %s\n", rev); #ifdef MODULE diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/elsa.c linux/drivers/isdn/hisax/elsa.c --- v2.1.41/linux/drivers/isdn/hisax/elsa.c Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/elsa.c Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: elsa.c,v 1.8 1997/01/27 15:51:48 keil Exp $ +/* $Id: elsa.c,v 1.14 1997/04/13 19:53:25 keil Exp $ * elsa.c low level stuff for Elsa isdn cards * @@ -8,6 +8,24 @@ * * * $Log: elsa.c,v $ + * Revision 1.14 1997/04/13 19:53:25 keil + * Fixed QS1000 init, change in IRQ check delay for SMP + * + * Revision 1.13 1997/04/07 22:58:07 keil + * need include config.h + * + * Revision 1.12 1997/04/06 22:54:14 keil + * Using SKB's + * + * Revision 1.11 1997/03/23 21:45:46 keil + * Add support for ELSA PCMCIA + * + * Revision 1.10 1997/03/12 21:42:19 keil + * Bugfix: IRQ hangs with QS1000 + * + * Revision 1.9 1997/03/04 15:57:39 keil + * bugfix IRQ reset Quickstep, ELSA PC changes, some stuff for new cards + * * Revision 1.8 1997/01/27 15:51:48 keil * SMP proof,cosmetics * @@ -38,6 +56,7 @@ #define ARCOFI_USE 0 #define __NO_VERSION__ +#include #include "siemens.h" #include "hisax.h" #include "elsa.h" @@ -46,18 +65,22 @@ extern const char *CardType[]; -const char *Elsa_revision = "$Revision: 1.8 $"; +const char *Elsa_revision = "$Revision: 1.14 $"; const char *Elsa_Types[] = -{"None", "PCC-8", "PCF-Pro", "PCC-16", "PCF", - "QS 1000"}; +{"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", + "PCMCIA", "QS 1000", "QS 3000"}; + +const char *ITACVer[] = +{"?0?", "?1?", "?2?", "?3?", "?4?", "V2.2", + "B1", "A1"}; #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) +static inline u_char +readhscx(unsigned int adr, int hscx, u_char off) { - register byte ret; + register u_char ret; long flags; save_flags(flags); @@ -69,7 +92,7 @@ } static inline void -read_fifo_hscx(unsigned int adr, int hscx, byte * data, int size) +read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size) { /* fifo read without cli because it's allready done */ @@ -79,7 +102,7 @@ static inline void -writehscx(unsigned int adr, int hscx, byte off, byte data) +writehscx(unsigned int adr, int hscx, u_char off, u_char data) { long flags; @@ -91,74 +114,103 @@ } static inline void -write_fifo_hscx(unsigned int adr, int hscx, byte * data, int size) +write_fifo_hscx(unsigned int adr, int hscx, u_char * 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) +static inline u_char +readisac(unsigned int adr, u_char off) { - register byte ret; + register u_char ret; long flags; save_flags(flags); cli(); byteout(adr + CARD_ALE, off + 0x20); - ret = bytein(adr); + ret = bytein(adr + CARD_ISAC); restore_flags(flags); return (ret); } static inline void -read_fifo_isac(unsigned int adr, byte * data, int size) +read_fifo_isac(unsigned int adr, u_char * data, int size) { /* fifo read without cli because it's allready done */ byteout(adr + CARD_ALE, 0); - insb(adr, data, size); + insb(adr + CARD_ISAC, data, size); } static inline void -writeisac(unsigned int adr, byte off, byte data) +writeisac(unsigned int adr, u_char off, u_char data) { long flags; save_flags(flags); cli(); byteout(adr + CARD_ALE, off + 0x20); - byteout(adr, data); + byteout(adr + CARD_ISAC, data); restore_flags(flags); } static inline void -write_fifo_isac(unsigned int adr, byte * data, int size) +write_fifo_isac(unsigned int adr, u_char * data, int size) { /* fifo write without cli because it's allready done */ byteout(adr + CARD_ALE, 0); - outsb(adr, data, size); + outsb(adr + CARD_ISAC, data, size); +} + +#ifdef CONFIG_HISAX_ELSA_PCC +static inline u_char +readitac(unsigned int adr, u_char off) +{ + register u_char ret; + long flags; + + save_flags(flags); + cli(); + byteout(adr + CARD_ALE, off); + ret = bytein(adr + CARD_ITAC); + restore_flags(flags); + return (ret); +} + +static inline void +writeitac(unsigned int adr, u_char off, u_char data) +{ + long flags; + + save_flags(flags); + cli(); + byteout(adr + CARD_ALE, off); + byteout(adr + CARD_ITAC, data); + restore_flags(flags); } static inline int TimerRun(struct IsdnCardState *sp) { - register byte val; + register u_char val; val = bytein(sp->cfg_reg + CARD_CONFIG); if (sp->subtyp == ELSA_QS1000) return (0 == (val & TIMER_RUN)); - return ((val & TIMER_RUN)); + else if (sp->subtyp == ELSA_PCC8) + return (val & TIMER_RUN_PCC8); + return (val & TIMER_RUN); } static inline void elsa_led_handler(struct IsdnCardState *sp) { - byte outval = 0xf0; + u_char outval = 0xf0; int stat = 0, cval; @@ -172,49 +224,50 @@ } 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) + case 0: + if (!stat) outval |= STAT_LED; - if (stat & 4) + 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; - } - break; - case 2: - if (!stat) - outval |= STAT_LED; - else if (stat == 1) - outval |= 0; - else { - if (stat & 2) + 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; - if (stat & 4) + 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; - case 3: - if (!stat) - outval |= LINE_LED; - break; + break; } byteout(sp->cfg_reg + CARD_CONTROL, outval); } +#endif static inline void waitforCEC(int adr, int hscx) @@ -244,7 +297,7 @@ } static inline void -writehscxCMDR(int adr, int hscx, byte data) +writehscxCMDR(int adr, int hscx, u_char data) { long flags; @@ -287,25 +340,22 @@ static void hscx_empty_fifo(struct HscxState *hsp, int count) { - byte *ptr; + u_char *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 (hsp->rcvidx + count > HSCX_BUFMAX) { if (sp->debug & L1_DEB_WARN) debugl1(sp, "hscx_empty_fifo: incoming packet too large"); writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80); + hsp->rcvidx = 0; return; } - ptr = DATAPTR(ibh); - ptr += hsp->rcvptr; - - hsp->rcvptr += count; + ptr = hsp->rcvbuf + hsp->rcvidx; + hsp->rcvidx += count; save_flags(flags); cli(); read_fifo_hscx(sp->cfg_reg, hsp->hscx, ptr, count); @@ -326,34 +376,33 @@ hscx_fill_fifo(struct HscxState *hsp) { struct IsdnCardState *sp = hsp->sp; - struct BufHeader *ibh; int more, count; - byte *ptr; + u_char *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) + if (!hsp->tx_skb) return; - - count = ibh->datasize - hsp->sendptr; - if (count <= 0) + if (hsp->tx_skb->len <= 0) return; more = (hsp->mode == 1) ? 1 : 0; - if (count > 32) { + if (hsp->tx_skb->len > 32) { more = !0; count = 32; - } - ptr = DATAPTR(ibh); - ptr += hsp->sendptr; - hsp->sendptr += count; + } else + count = hsp->tx_skb->len; waitforXFW(sp->cfg_reg, hsp->hscx); save_flags(flags); cli(); + ptr = hsp->tx_skb->data; + skb_pull(hsp->tx_skb, count); + hsp->tx_cnt -= count; + hsp->count += count; write_fifo_hscx(sp->cfg_reg, hsp->hscx, ptr, count); writehscxCMDR(sp->cfg_reg, hsp->hscx, more ? 0x8 : 0xa); restore_flags(flags); @@ -369,11 +418,12 @@ } static inline void -hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx) +hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx) { - byte r; + u_char r; struct HscxState *hsp = sp->hs + hscx; - int count, err; + struct sk_buff *skb; + int count; char tmp[32]; if (!hsp->init) @@ -395,79 +445,61 @@ 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; + } else { + count = readhscx(sp->cfg_reg, hsp->hscx, HSCX_RBCL) & 0x1f; + if (count == 0) + count = 32; + hscx_empty_fifo(hsp, count); + if ((count = hsp->rcvidx - 1) > 0) { + if (sp->debug & L1_DEB_HSCX_FIFO) { + sprintf(tmp, "HX Frame %d", count); + debugl1(sp, tmp); + } + if (!(skb = dev_alloc_skb(count))) + printk(KERN_WARNING "Elsa: receive out of memory\n"); + else { + memcpy(skb_put(skb, count), hsp->rcvbuf, count); + skb_queue_tail(&hsp->rqueue, skb); + } + } } - 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; + hsp->rcvidx = 0; 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; + if (!(skb = dev_alloc_skb(32))) + printk(KERN_WARNING "elsa: receive out of memory\n"); + else { + memcpy(skb_put(skb, 32), hsp->rcvbuf, 32); + skb_queue_tail(&hsp->rqueue, skb); + } + hsp->rcvidx = 0; hscx_sched_event(hsp, HSCX_RCVBUFREADY); } } - afterRPF: if (val & 0x10) { /* XPR */ - if (hsp->xmtibh) - if (hsp->xmtibh->datasize > hsp->sendptr) { + if (hsp->tx_skb) + if (hsp->tx_skb->len) { hscx_fill_fifo(hsp); - goto afterXPR; + return; } else { - if (hsp->releasebuf) - BufPoolRelease(hsp->xmtibh); - hsp->sendptr = 0; + SET_SKB_FREE(hsp->tx_skb); + dev_kfree_skb(hsp->tx_skb, FREE_WRITE); + hsp->count = 0; if (hsp->st->l4.l1writewakeup) hsp->st->l4.l1writewakeup(hsp->st); - hsp->xmtibh = NULL; + hsp->tx_skb = NULL; } - if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) { - hsp->releasebuf = !0; + if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) { + hsp->count = 0; hscx_fill_fifo(hsp); } else hscx_sched_event(hsp, HSCX_XMTBUFREADY); } - afterXPR: } /* @@ -477,25 +509,25 @@ static void isac_empty_fifo(struct IsdnCardState *sp, int count) { - byte *ptr; - struct BufHeader *ibh = sp->rcvibh; + u_char *ptr; 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->rcvidx + count) >= MAX_DFRAME_LEN) { if (sp->debug & L1_DEB_WARN) { char tmp[40]; - sprintf(tmp, "isac_empty_fifo rcvptr %d", sp->rcvptr); + sprintf(tmp, "isac_empty_fifo overrun %d", + sp->rcvidx + count); debugl1(sp, tmp); } + writeisac(sp->cfg_reg, ISAC_CMDR, 0x80); + sp->rcvidx = 0; return; } - ptr = DATAPTR(ibh); - ptr += sp->rcvptr; - sp->rcvptr += count; - + ptr = sp->rcvbuf + sp->rcvidx; + sp->rcvidx += count; save_flags(flags); cli(); read_fifo_isac(sp->cfg_reg, ptr, count); @@ -514,35 +546,30 @@ static void isac_fill_fifo(struct IsdnCardState *sp) { - struct BufHeader *ibh; int count, more; - byte *ptr; + u_char *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) + if (!sp->tx_skb) return; - count = ibh->datasize - sp->sendptr; + count = sp->tx_skb->len; 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(); + ptr = sp->tx_skb->data; + skb_pull(sp->tx_skb, count); + sp->tx_cnt += count; write_fifo_isac(sp->cfg_reg, ptr, count); writeisac(sp->cfg_reg, ISAC_CMDR, more ? 0x8 : 0xa); restore_flags(flags); @@ -568,14 +595,15 @@ } static inline void -isac_interrupt(struct IsdnCardState *sp, byte val) +isac_interrupt(struct IsdnCardState *sp, u_char val) { - byte exval, v1; + u_char exval, v1; + struct sk_buff *skb; unsigned int count; char tmp[32]; #if ARCOFI_USE struct BufHeader *ibh; - byte *ptr; + u_char *ptr; #endif if (sp->debug & L1_DEB_ISAC) { @@ -591,62 +619,46 @@ 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; + } else { + count = readisac(sp->cfg_reg, ISAC_RBCL) & 0x1f; + if (count == 0) + count = 32; + isac_empty_fifo(sp, count); + if ((count = sp->rcvidx) > 0) { + sp->rcvidx = 0; + if (!(skb = alloc_skb(count, GFP_ATOMIC))) + printk(KERN_WARNING "Elsa: D receive out of memory\n"); + else { + memcpy(skb_put(skb, count), sp->rcvbuf, count); + skb_queue_tail(&sp->rq, skb); + } + } } - 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; + sp->rcvidx = 0; 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) { + if (sp->tx_skb) + if (sp->tx_skb->len) { isac_fill_fifo(sp); goto afterXPR; } else { - if (sp->releasebuf) - BufPoolRelease(sp->xmtibh); - sp->xmtibh = NULL; - sp->sendptr = 0; + SET_SKB_FREE(sp->tx_skb); + dev_kfree_skb(sp->tx_skb, FREE_WRITE); + sp->tx_cnt = 0; + sp->tx_skb = NULL; } - if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) { - sp->releasebuf = !0; + if ((sp->tx_skb = skb_dequeue(&sp->sq))) { + sp->tx_cnt = 0; isac_fill_fifo(sp); } else isac_sched_event(sp, ISAC_XMTBUFREADY); @@ -793,14 +805,13 @@ } static inline void -hscx_int_main(struct IsdnCardState *sp, byte val) +hscx_int_main(struct IsdnCardState *sp, u_char val) { - byte exval; + u_char exval; struct HscxState *hsp; char tmp[32]; - if (val & 0x01) { hsp = sp->hs + 1; exval = readhscx(sp->cfg_reg, 1, HSCX_EXIR); @@ -811,7 +822,11 @@ /* Here we lost an TX interrupt, so * restart transmitting the whole frame. */ - hsp->sendptr = 0; + if (hsp->tx_skb) { + skb_push(hsp->tx_skb, hsp->count); + hsp->tx_cnt += hsp->count; + hsp->count = 0; + } writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x01); if (sp->debug & L1_DEB_WARN) { sprintf(tmp, "HSCX B EXIR %x Lost TX", exval); @@ -840,7 +855,11 @@ /* Here we lost an TX interrupt, so * restart transmitting the whole frame. */ - hsp->sendptr = 0; + if (hsp->tx_skb) { + skb_push(hsp->tx_skb, hsp->count); + hsp->tx_cnt += hsp->count; + hsp->count = 0; + } writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x01); if (sp->debug & L1_DEB_WARN) { sprintf(tmp, "HSCX A EXIR %x Lost TX", exval); @@ -866,7 +885,7 @@ elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *sp; - byte val, sval, stat = 0; + u_char val; sp = (struct IsdnCardState *) irq2dev_map[intno]; @@ -874,32 +893,31 @@ printk(KERN_WARNING "Elsa: Spurious interrupt!\n"); return; } - sval = bytein(sp->cfg_reg + CARD_CONFIG); +#ifdef CONFIG_HISAX_ELSA_PCC INT_RESTART: if (!TimerRun(sp)) { /* Timer Restart */ - bytein(sp->cfg_reg + CARD_START_TIMER); + byteout(sp->cfg_reg + CARD_START_TIMER, 0); if (!(sp->counter++ & 0x3f)) { /* Call LEDs all 64 tics */ elsa_led_handler(sp); } } +#endif 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); +#ifdef CONFIG_HISAX_ELSA_PCC if (!TimerRun(sp)) goto INT_RESTART; - +#endif val = readhscx(sp->cfg_reg, 1, HSCX_ISTA); if (val) { if (sp->debug & L1_DEB_HSCX) @@ -912,17 +930,18 @@ 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); + writehscx(sp->cfg_reg, 0, HSCX_MASK, 0xFF); + writehscx(sp->cfg_reg, 1, HSCX_MASK, 0xFF); + writeisac(sp->cfg_reg, ISAC_MASK, 0xFF); +#ifdef CONFIG_HISAX_ELSA_PCC + if (sp->subtyp == ELSA_QS1000) { + byteout(sp->cfg_reg + CARD_START_TIMER, 0); + byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff); } - byteout(sp->cfg_reg + 7, 0xff); +#endif + writehscx(sp->cfg_reg, 0, HSCX_MASK, 0x0); + writehscx(sp->cfg_reg, 1, HSCX_MASK, 0x0); + writeisac(sp->cfg_reg, ISAC_MASK, 0x0); } @@ -967,39 +986,39 @@ 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; + 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); } @@ -1016,9 +1035,86 @@ } static void +reset_elsa(struct IsdnCardState *sp) +{ +#ifdef CONFIG_HISAX_ELSA_PCC + /* Wait 1 Timer */ + byteout(sp->cfg_reg + CARD_START_TIMER, 0); + while (TimerRun(sp)); + byteout(sp->cfg_reg + CARD_CONTROL, 0x00); /* Reset On */ + /* Wait 1 Timer */ + byteout(sp->cfg_reg + CARD_START_TIMER, 0); + while (TimerRun(sp)); + byteout(sp->cfg_reg + CARD_CONTROL, ISDN_RESET); /* Reset Off */ + /* Wait 1 Timer */ + byteout(sp->cfg_reg + CARD_START_TIMER, 0); + while (TimerRun(sp)); + byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff); +#endif +} + +static void clear_pending_ints(struct IsdnCardState *sp) { - writeisac(sp->cfg_reg, ISAC_MASK, 0); +#ifdef CONFIG_HISAX_ELSA_PCMCIA + int val; + char tmp[64]; + + val = readhscx(sp->cfg_reg, 1, HSCX_ISTA); + sprintf(tmp, "HSCX B ISTA %x", val); + debugl1(sp, tmp); + if (val & 0x01) { + val = readhscx(sp->cfg_reg, 1, HSCX_EXIR); + sprintf(tmp, "HSCX B EXIR %x", val); + debugl1(sp, tmp); + } else if (val & 0x02) { + val = readhscx(sp->cfg_reg, 0, HSCX_EXIR); + sprintf(tmp, "HSCX A EXIR %x", val); + debugl1(sp, tmp); + } + val = readhscx(sp->cfg_reg, 0, HSCX_ISTA); + sprintf(tmp, "HSCX A ISTA %x", val); + debugl1(sp, tmp); + val = readhscx(sp->cfg_reg, 1, HSCX_STAR); + sprintf(tmp, "HSCX B STAR %x", val); + debugl1(sp, tmp); + val = readhscx(sp->cfg_reg, 0, HSCX_STAR); + sprintf(tmp, "HSCX A STAR %x", val); + debugl1(sp, tmp); + val = readisac(sp->cfg_reg, ISAC_STAR); + sprintf(tmp, "ISAC STAR %x", val); + debugl1(sp, tmp); + val = readisac(sp->cfg_reg, ISAC_MODE); + sprintf(tmp, "ISAC MODE %x", val); + debugl1(sp, tmp); + val = readisac(sp->cfg_reg, ISAC_ADF2); + sprintf(tmp, "ISAC ADF2 %x", val); + debugl1(sp, tmp); + val = readisac(sp->cfg_reg, ISAC_ISTA); + sprintf(tmp, "ISAC ISTA %x", val); + debugl1(sp, tmp); + if (val & 0x01) { + val = readisac(sp->cfg_reg, ISAC_EXIR); + sprintf(tmp, "ISAC EXIR %x", val); + debugl1(sp, tmp); + } else if (val & 0x04) { + val = readisac(sp->cfg_reg, ISAC_CIR0); + sprintf(tmp, "ISAC CIR0 %x", val); + debugl1(sp, tmp); + } +#endif + writehscx(sp->cfg_reg, 0, HSCX_MASK, 0xFF); + writehscx(sp->cfg_reg, 1, HSCX_MASK, 0xFF); + writeisac(sp->cfg_reg, ISAC_MASK, 0xFF); +#ifdef CONFIG_HISAX_ELSA_PCC + if (sp->subtyp == ELSA_QS1000) { + byteout(sp->cfg_reg + CARD_START_TIMER, 0); + byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff); + } +#endif + writehscx(sp->cfg_reg, 0, HSCX_MASK, 0x0); + writehscx(sp->cfg_reg, 1, HSCX_MASK, 0x0); + writeisac(sp->cfg_reg, ISAC_MASK, 0x0); writeisac(sp->cfg_reg, ISAC_CMDR, 0x41); } @@ -1026,11 +1122,11 @@ check_arcofi(struct IsdnCardState *sp) { #if 0 - byte val; + u_char val; char tmp[40]; char *t; long flags; - byte *p; + u_char *p; if (BufPoolGet(&(sp->mon_tx), &(sp->sbufpool), GFP_ATOMIC, (void *) 1, 3)) { @@ -1081,55 +1177,70 @@ int initelsa(struct IsdnCardState *sp) { - int ret, irq_cnt; + int ret, irq_cnt, cnt = 3; 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) { +#ifdef CONFIG_HISAX_ELSA_PCC + byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff); +#endif + while (ret && cnt) { + sp->counter = 0; + clear_pending_ints(sp); initisac(sp); sp->modehscx(sp->hs, 0, 0); sp->modehscx(sp->hs + 1, 0, 0); save_flags(flags); sp->counter = 0; sti(); +#ifdef CONFIG_HISAX_ELSA_PCC byteout(sp->cfg_reg + CARD_CONTROL, ISDN_RESET | ENABLE_TIM_INT); - bytein(sp->cfg_reg + CARD_START_TIMER); - HZDELAY(11); /* Warte 110 ms */ + byteout(sp->cfg_reg + CARD_START_TIMER, 0); + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + (110 * HZ) / 1000; /* Timeout 110ms */ + schedule(); restore_flags(flags); printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n", sp->counter); - if (abs(sp->counter - 12) < 3) { + if (abs(sp->counter - 13) < 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); + "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n", + sp->counter, sp->irq); } +#endif 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); + "Elsa: IRQ(%d) getting no interrupts during init %d\n", + sp->irq, 4 - cnt); + if (cnt == 1) { + irq2dev_map[sp->irq] = NULL; + free_irq(sp->irq, NULL); + return (0); + } else { + reset_elsa(sp); + cnt--; + } + } else { + check_arcofi(sp); + cnt = 0; } - check_arcofi(sp); } sp->counter = 0; return (ret); } +#ifdef CONFIG_HISAX_ELSA_PCC 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; + int i, in1, in2, p16_1 = 0, p16_2 = 0, p8_1 = 0, p8_2 = 0, pc_1 = 0, + pc_2 = 0, pfp_1 = 0, pfp_2 = 0; long flags; if (check_region(adr, 8)) { @@ -1145,8 +1256,10 @@ in2 = inb(adr + CARD_CONFIG); /* jedem Zugriff */ p16_1 += 0x04 & in1; p16_2 += 0x04 & in2; - pcc_1 += 0x01 & in1; - pcc_2 += 0x01 & in2; + p8_1 += 0x02 & in1; + p8_2 += 0x02 & in2; + pc_1 += 0x01 & in1; + pc_2 += 0x01 & in2; pfp_1 += 0x40 & in1; pfp_2 += 0x40 & in2; } @@ -1154,13 +1267,16 @@ printk(KERN_INFO "Elsa: Probing IO 0x%x", adr); if (65 == ++p16_1 * ++p16_2) { printk(" PCC-16/PCF found\n"); - return (3); + return (ELSA_PCC16); } else if (1025 == ++pfp_1 * ++pfp_2) { printk(" PCF-Pro found\n"); - return (2); - } else if (17 == ++pcc_1 * ++pcc_2) { + return (ELSA_PCFPRO); + } else if (33 == ++p8_1 * ++p8_2) { printk(" PCC8 found\n"); - return (1); + return (ELSA_PCC8); + } else if (17 == ++pc_1 * ++pc_2) { + printk(" PC found\n"); + return (ELSA_PC); } else { printk(" failed\n"); return (0); @@ -1180,25 +1296,29 @@ } return (CARD_portlist[i]); } +#endif int setup_elsa(struct IsdnCard *card) { +#ifdef CONFIG_HISAX_ELSA_PCC long flags; +#endif int bytecnt; - byte val, verA, verB; + u_char 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)); +#ifdef CONFIG_HISAX_ELSA_PCC if (sp->typ == ISDN_CTYPE_ELSA) { sp->cfg_reg = card->para[0]; - printk(KERN_INFO "Elsa: Mircolink IO probing\n"); + printk(KERN_INFO "Elsa: Microlink 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", + "Elsa: no Elsa Microlink at 0x%x\n", sp->cfg_reg); return (0); } @@ -1206,14 +1326,18 @@ 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] = + if (sp->subtyp == ELSA_PC) { + const u_char CARD_IrqTab[8] = + {7, 3, 5, 9, 0, 0, 0, 0}; + sp->irq = CARD_IrqTab[(val & IRQ_INDEX_PC) >> 2]; + } else if (sp->subtyp == ELSA_PCC8) { + const u_char CARD_IrqTab[8] = {7, 3, 5, 9, 0, 0, 0, 0}; - sp->irq = CARD_IrqTab[(val & 0x0c) >> 2]; + sp->irq = CARD_IrqTab[(val & IRQ_INDEX_PCC8) >> 4]; } else { - const byte CARD_IrqTab[8] = + const u_char CARD_IrqTab[8] = {15, 10, 15, 3, 11, 5, 11, 9}; - sp->irq = CARD_IrqTab[(val & 0x38) >> 3]; + sp->irq = CARD_IrqTab[(val & IRQ_INDEX) >> 3]; } val = bytein(sp->cfg_reg + CARD_ALE) & 0x7; if (val < 3) @@ -1231,39 +1355,64 @@ val = bytein(sp->cfg_reg + CARD_ALE) & 0x08; if (val) printk(KERN_WARNING - "Elsa: Mircolink S0 bus power bad\n"); + "Elsa: Microlink S0 bus power bad\n"); } else { printk(KERN_WARNING - "No Elsa Mircolink found\n"); + "No Elsa Microlink 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; + printk(KERN_INFO + "Elsa: %s found at 0x%x IRQ %d\n", + Elsa_Types[sp->subtyp], + sp->cfg_reg, + sp->irq); } else return (0); +#endif +#ifdef CONFIG_HISAX_ELSA_PCMCIA + if (sp->typ == ISDN_CTYPE_ELSA_QS1000) { + sp->cfg_reg = card->para[1]; + sp->irq = card->para[0]; + sp->subtyp = ELSA_PCMCIA; + printk(KERN_INFO + "Elsa: %s found at 0x%x IRQ %d\n", + Elsa_Types[sp->subtyp], + sp->cfg_reg, + sp->irq); + } else + return (0); +#endif 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); + case ELSA_PC: + bytecnt = 8; + break; + case ELSA_PCC8: + 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; + case ELSA_PCMCIA: + bytecnt = 8; + break; + default: + printk(KERN_WARNING + "Unknown ELSA subtype %d\n", sp->subtyp); + return (0); } if (check_region((sp->cfg_reg), bytecnt)) { @@ -1278,9 +1427,11 @@ } /* Teste Timer */ - bytein(sp->cfg_reg + CARD_START_TIMER); +#ifdef CONFIG_HISAX_ELSA_PCC + byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff); + byteout(sp->cfg_reg + CARD_START_TIMER, 0); if (!TimerRun(sp)) { - bytein(sp->cfg_reg + CARD_START_TIMER); /* 2. Versuch */ + byteout(sp->cfg_reg + CARD_START_TIMER, 0); /* 2. Versuch */ if (!TimerRun(sp)) { printk(KERN_WARNING "Elsa: timer do not start\n"); @@ -1298,18 +1449,8 @@ 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)); - + reset_elsa(sp); +#endif 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", @@ -1318,6 +1459,26 @@ printk(KERN_INFO "Elsa: ISAC %s\n", ISACVersion(val)); +#ifdef CONFIG_HISAX_ELSA_PCMCIA + if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) { + printk(KERN_WARNING + "Elsa: wrong HSCX versions check IO address\n"); + release_io_elsa(card); + return (0); + } +#endif + +#ifdef CONFIG_HISAX_ELSA_PCC + if (sp->subtyp == ELSA_PC) { + val = readitac(sp->cfg_reg, ITAC_SYS); + printk(KERN_INFO "Elsa: ITAC version %s\n", ITACVer[val & 7]); + writeitac(sp->cfg_reg, ITAC_ISEN, 0); + writeitac(sp->cfg_reg, ITAC_RFIE, 0); + writeitac(sp->cfg_reg, ITAC_XFIE, 0); + writeitac(sp->cfg_reg, ITAC_SCIE, 0); + writeitac(sp->cfg_reg, ITAC_STIE, 0); + } +#endif sp->modehscx = &modehscx; sp->ph_command = &ph_command; sp->hscx_fill_fifo = &hscx_fill_fifo; diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/elsa.h linux/drivers/isdn/hisax/elsa.h --- v2.1.41/linux/drivers/isdn/hisax/elsa.h Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/elsa.h Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: elsa.h,v 1.4 1997/01/21 22:21:05 keil Exp $ +/* $Id: elsa.h,v 1.6 1997/03/23 21:45:48 keil Exp $ * * elsa.h Header for Elsa ISDN cards * @@ -8,6 +8,12 @@ * * * $Log: elsa.h,v $ + * Revision 1.6 1997/03/23 21:45:48 keil + * Add support for ELSA PCMCIA + * + * Revision 1.5 1997/03/04 15:58:13 keil + * ELSA PC changes, some stuff for new cards + * * Revision 1.4 1997/01/21 22:21:05 keil * Elsa Quickstep support * @@ -22,20 +28,39 @@ * * */ +#include +#ifdef CONFIG_HISAX_ELSA_PCMCIA +#define CARD_ISAC 1 +#define CARD_HSCX 2 +#define CARD_ALE 4 +#else #define CARD_ISAC 0 +#define CARD_ITAC 1 #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 +#endif -#define ELSA_PCC 1 -#define ELSA_PCFPRO 2 +#define ELSA_PC 1 +#define ELSA_PCC8 2 #define ELSA_PCC16 3 #define ELSA_PCF 4 -#define ELSA_QS1000 5 +#define ELSA_PCFPRO 5 +#define ELSA_PCMCIA 6 +#define ELSA_QS1000 7 +#define ELSA_QS3000 8 + +/* ITAC Registeradressen (only Microlink PC) */ +#define ITAC_SYS 0x34 +#define ITAC_ISEN 0x48 +#define ITAC_RFIE 0x4A +#define ITAC_XFIE 0x4C +#define ITAC_SCIE 0x4E +#define ITAC_STIE 0x46 /*** *** *** Makros als Befehle fuer die Kartenregister *** @@ -44,8 +69,10 @@ /* 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 TIMER_RUN_PCC8 0x01 /* Bit 0 des Config-Reg bei PCC */ #define IRQ_INDEX 0x38 /* Bit 3,4,5 des Config-Reg */ +#define IRQ_INDEX_PCC8 0x30 /* Bit 4,5 des Config-Reg */ +#define IRQ_INDEX_PC 0x0c /* Bit 2,3 des Config-Reg */ /* Control-Register (Write) */ #define LINE_LED 0x02 /* Bit 1 Gelbe LED */ diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/fsm.c linux/drivers/isdn/hisax/fsm.c --- v2.1.41/linux/drivers/isdn/hisax/fsm.c Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/fsm.c Wed May 28 10:49:09 1997 @@ -1,5 +1,5 @@ -/* $Id: fsm.c,v 1.3 1997/02/16 01:04:08 fritz Exp $ - * +/* $Id: fsm.c,v 1.4 1997/04/06 22:56:42 keil Exp $ + * Author Karsten Keil (keil@temic-ech.spacenet.de) * based on the teles driver from Jan den Ouden * @@ -7,6 +7,9 @@ * Fritz Elfert * * $Log: fsm.c,v $ + * Revision 1.4 1997/04/06 22:56:42 keil + * Some cosmetic changes + * * Revision 1.3 1997/02/16 01:04:08 fritz * Bugfix: Changed timer handling caused hang with 2.1.X * @@ -27,10 +30,10 @@ FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount) { - int i; + int i; - fsm->jumpmatrix = (int *) Smalloc(4L * fsm->state_count * fsm->event_count, - GFP_KERNEL, "Fsm jumpmatrix"); + fsm->jumpmatrix = (int *) + kmalloc(4L * fsm->state_count * fsm->event_count, GFP_KERNEL); memset(fsm->jumpmatrix, 0, 4L * fsm->state_count * fsm->event_count); for (i = 0; i < fncount; i++) @@ -41,14 +44,14 @@ void FsmFree(struct Fsm *fsm) { - Sfree((void *) fsm->jumpmatrix); + kfree((void *) fsm->jumpmatrix); } int FsmEvent(struct FsmInst *fi, int event, void *arg) { - void (*r) (struct FsmInst *, int, void *); - char str[80]; + void (*r) (struct FsmInst *, int, void *); + char str[80]; r = (void (*)) fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state]; if (r) { @@ -74,7 +77,7 @@ void FsmChangeState(struct FsmInst *fi, int newstate) { - char str[80]; + char str[80]; fi->state = newstate; if (fi->debug) { @@ -90,7 +93,7 @@ #if FSM_TIMER_DEBUG if (ft->fi->debug) { char str[40]; - sprintf(str, "FsmExpireTimer %lx", (long)ft); + sprintf(str, "FsmExpireTimer %lx", (long) ft); ft->fi->printdebug(ft->fi, str); } #endif @@ -106,7 +109,7 @@ #if FSM_TIMER_DEBUG if (ft->fi->debug) { char str[40]; - sprintf(str, "FsmInitTimer %lx", (long)ft); + sprintf(str, "FsmInitTimer %lx", (long) ft); ft->fi->printdebug(ft->fi, str); } #endif @@ -119,7 +122,7 @@ #if FSM_TIMER_DEBUG if (ft->fi->debug) { char str[40]; - sprintf(str, "FsmDelTimer %lx %d", (long)ft, where); + sprintf(str, "FsmDelTimer %lx %d", (long) ft, where); ft->fi->printdebug(ft->fi, str); } #endif @@ -134,7 +137,7 @@ #if FSM_TIMER_DEBUG if (ft->fi->debug) { char str[40]; - sprintf(str, "FsmAddTimer %lx %d %d", (long)ft, millisec, where); + sprintf(str, "FsmAddTimer %lx %d %d", (long) ft, millisec, where); ft->fi->printdebug(ft->fi, str); } #endif diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h --- v2.1.41/linux/drivers/isdn/hisax/hisax.h Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/hisax.h Wed May 28 10:49:09 1997 @@ -1,8 +1,14 @@ -/* $Id: hisax.h,v 1.11 1997/02/11 01:36:02 keil Exp $ +/* $Id: hisax.h,v 1.13 1997/04/06 22:54:12 keil Exp $ * Basic declarations, defines and prototypes * * $Log: hisax.h,v $ + * Revision 1.13 1997/04/06 22:54:12 keil + * Using SKB's + * + * Revision 1.12 1997/03/23 21:45:45 keil + * Add support for ELSA PCMCIA + * * Revision 1.11 1997/02/11 01:36:02 keil * New Param structure * @@ -182,36 +188,12 @@ #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); +#define MAX_DFRAME_LEN 3072 +#define HSCX_BUFMAX 4096 +#define MAX_DATA_SIZE (HSCX_BUFMAX - 4) +#define MAX_DATA_MEM (HSCX_BUFMAX * 2) +#define MAX_HEADER_LEN 4 +#define MAX_WINDOW 8 /* * Statemachine @@ -249,48 +231,12 @@ 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 (*l1l2) (struct PStack *, int, void *); void (*l1man) (struct PStack *, int, void *); int hscxmode, hscxchannel, requestpull; }; @@ -300,14 +246,14 @@ int extended, laptype; int uihsize, ihsize; int vs, va, vr; - struct BufQueue i_queue; + struct sk_buff_head i_queue; int window, orig; int rejexp; int debug; - struct BufHeader *windowar[MAX_WINDOW]; + struct sk_buff *windowar[MAX_WINDOW]; int sow; struct FsmInst l2m; - void (*l2l1) (struct PStack *, int, struct BufHeader *); + void (*l2l1) (struct PStack *, int, void *); void (*l2l1discardq) (struct PStack *, int, void *, int); void (*l2man) (struct PStack *, int, void *); void (*l2l3) (struct PStack *, int, void *); @@ -319,7 +265,7 @@ }; struct Layer3 { - void (*l3l4) (struct PStack *, int, struct BufHeader *); + void (*l3l4) (struct PStack *, int, void *); void (*l3l2) (struct PStack *, int, void *); int state, callref; struct L3Timer timer; @@ -347,7 +293,7 @@ int loc; int bchannel; int callref; /* Callreferenz Number */ - setup_parm setup; /* from isdnif.h numbers and Serviceindicator */ + setup_parm setup; /* from isdnif.h numbers and Serviceindicator */ int chargeinfo; /* Charge Info - only for 1tr6 in * the moment */ @@ -367,17 +313,18 @@ 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; + u_char *rcvbuf; /* B-Channel receive Buffer */ + int rcvidx; /* B-Channel receive Buffer Index */ + struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ + int tx_cnt; /* B-Channel transmit counter */ + int count; /* Current skb sent count */ + struct sk_buff_head rqueue; /* B-Channel receive Queue */ + struct sk_buff_head squeue; /* B-Channel receive Queue */ struct PStack *st; struct tq_struct tqueue; int event; - struct BufQueue rq, sq; - int releasebuf; #ifdef DEBUG_MAGIC int magic; /* 301270 */ #endif @@ -431,27 +378,26 @@ 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; + int myid; + isdn_if iif; + u_char *status_buf; + u_char *status_read; + u_char *status_write; + u_char *status_end; 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; + u_char *rcvbuf; + int rcvidx; + struct sk_buff *tx_skb; + int tx_cnt; int event; struct tq_struct tqueue; int ph_active; - struct BufQueue rq, sq; + struct sk_buff_head rq, sq; /* D-channel queues */ int cardnr; int ph_state; struct PStack *teistack; @@ -459,7 +405,6 @@ int dlogflag; char *dlogspace; int debug; - int releasebuf; unsigned int CallFlags; }; @@ -505,6 +450,15 @@ #define CARD_ELSA 0 #endif +#ifdef CONFIG_HISAX_ELSA_PCMCIA +#if CARD_ELSA +#error "You can't use a ELSA ISA card and a ELSA PCMCIA card with the same driver" +#else +#undef CARD_ELSA +#define CARD_ELSA (1<< ISDN_CTYPE_ELSA_QS1000) +#endif +#endif + #ifdef CONFIG_HISAX_IX1MICROR2 #define CARD_IX1MICROR2 (1 << ISDN_CTYPE_IX1MICROR2) #else @@ -521,37 +475,20 @@ 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 l2down(struct PStack *st, u_char pr, struct sk_buff *skb); +void l2up(struct PStack *st, u_char pr, struct sk_buff *skb); +void acceptph(struct PStack *st, struct sk_buff *skb); 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 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); @@ -559,8 +496,8 @@ 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); +u_char *findie(u_char * p, int size, u_char ie, int wanted_set); +int getcallref(u_char * p); void FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount); void FsmFree(struct Fsm *fsm); @@ -574,26 +511,17 @@ 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); +int HiSax_writebuf_skb(int id, int chan, struct sk_buff *skb); 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); +int QuickHex(char *txt, u_char * p, int cnt); +void LogFrame(struct IsdnCardState *sp, u_char * p, int size); +void dlogframe(struct IsdnCardState *sp, u_char * p, int size, char *comment); +void iecpy(u_char * dest, u_char * 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< queue_task + * clear/set_bit -> test_and_... where apropriate. + * changed type of hard_header_cache parameter. + * + * Revision 1.14 1997/04/07 23:00:08 keil + * GFP_KERNEL ---> GFP_ATOMIC + * + * Revision 1.13 1997/04/06 22:55:50 keil + * Using SKB's + * + * Revision 1.12 1997/03/26 13:43:57 keil + * small cosmetics + * + * Revision 1.11 1997/03/25 23:11:23 keil + * US NI-1 protocol + * + * Revision 1.10 1997/03/13 14:45:05 keil + * using IRQ proof queue_task + * + * Revision 1.9 1997/03/12 21:44:21 keil + * change Interrupt routine from atomic quick to normal + * * Revision 1.8 1997/02/09 00:24:31 keil * new interface handling, one interface per card * @@ -39,9 +64,10 @@ * */ -const char *l1_revision = "$Revision: 1.8 $"; +const char *l1_revision = "$Revision: 1.15 $"; #define __NO_VERSION__ +#include #include "hisax.h" #include "isdnl1.h" @@ -65,6 +91,9 @@ #include "ix1_micro.h" #endif +/* #define I4L_IRQ_FLAG SA_INTERRUPT */ +#define I4L_IRQ_FLAG 0 + #define HISAX_STATUS_BUFSIZE 4096 #define INCLUDE_INLINE_FUNCS @@ -73,7 +102,12 @@ const char *CardType[] = {"No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3", - "Creatix PnP", "AVM A1", "Elsa ML", "Elsa Quickstep", + "Creatix/Teles PnP", "AVM A1", "Elsa ML", +#ifdef CONFIG_HISAX_ELSA_PCMCIA + "Elsa PCMCIA", +#else + "Elsa Quickstep", +#endif "Teles PCMCIA", "ITK ix1-micro Rev.2"}; static char *HSCXVer[] = @@ -84,8 +118,6 @@ {"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; @@ -107,10 +139,10 @@ } int -HiSax_readstatus(byte * buf, int len, int user, int id, int channel) +HiSax_readstatus(u_char * buf, int len, int user, int id, int channel) { int count; - byte *p; + u_char *p; struct IsdnCardState *csta = hisax_findcard(id); if (csta) { @@ -135,7 +167,7 @@ { long flags; int len, count, i; - byte *p; + u_char *p; isdn_ctrl ic; save_flags(flags); @@ -198,11 +230,11 @@ ic.driver = csta->myid; csta->iif.statcallb(&ic); if (csta->status_buf) - Sfree(csta->status_buf); + kfree(csta->status_buf); csta->status_read = NULL; csta->status_write = NULL; csta->status_end = NULL; - Sfree(csta->dlogspace); + kfree(csta->dlogspace); } void @@ -221,7 +253,7 @@ char * -HscxVersion(byte v) +HscxVersion(u_char v) { return (HSCXVer[v & 0xf]); } @@ -230,7 +262,7 @@ hscx_sched_event(struct HscxState *hsp, int event) { hsp->event |= 1 << event; - queue_task_irq_off(&hsp->tqueue, &tq_immediate); + queue_task(&hsp->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH); } @@ -239,7 +271,7 @@ */ char * -ISACVersion(byte v) +ISACVersion(u_char v) { return (ISACVer[(v >> 5) & 3]); } @@ -248,7 +280,7 @@ isac_sched_event(struct IsdnCardState *sp, int event) { sp->event |= 1 << event; - queue_task_irq_off(&sp->tqueue, &tq_immediate); + queue_task(&sp->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH); } @@ -301,21 +333,23 @@ 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) + if (!sp->tx_skb) + sp->tx_skb = skb_dequeue(&sp->sq); + if (sp->tx_skb) { + sp->tx_cnt = 0; 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) + if (!sp->tx_skb) + sp->tx_skb = skb_dequeue(&sp->sq); + if (sp->tx_skb) { + sp->tx_cnt = 0; sp->isac_fill_fifo(sp); + } break; case (4): case (8): @@ -372,7 +406,7 @@ { struct PStack *stptr; - if (sp->xmtibh) + if (sp->tx_skb) return; stptr = sp->stlist; @@ -388,48 +422,44 @@ static void process_rcv(struct IsdnCardState *sp) { - struct BufHeader *ibh, *cibh; + struct sk_buff *skb, *nskb; struct PStack *stptr; - byte *ptr; int found, broadc; char tmp[64]; - while (!BufQueueUnlink(&ibh, &sp->rq)) { + while ((skb = skb_dequeue(&sp->rq))) { #ifdef L2FRAME_DEBUG /* psa */ if (sp->debug & L1_DEB_LAPD) - Logl2Frame(sp, ibh, "PH_DATA", 1); + Logl2Frame(sp, skb, "PH_DATA", 1); #endif stptr = sp->stlist; - ptr = DATAPTR(ibh); - broadc = (ptr[1] >> 1) == 127; + broadc = (skb->data[1] >> 1) == 127; if (broadc) { - if (!(ptr[0] >> 2)) { /* sapi 0 */ + if (!(skb->data[0] >> 2)) { /* sapi 0 */ sp->CallFlags = 3; if (sp->dlogflag) { - LogFrame(sp, ptr, ibh->datasize); - dlogframe(sp, ptr + 3, ibh->datasize - 3, + LogFrame(sp, skb->data, skb->len); + dlogframe(sp, skb->data + 3, skb->len - 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 + if ((skb->data[0] >> 2) == stptr->l2.sap) + if ((nskb = skb_clone(skb, GFP_ATOMIC))) + stptr->l1.l1l2(stptr, PH_DATA, nskb); + else printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n"); stptr = stptr->next; } - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); } 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); + if (((skb->data[0] >> 2) == stptr->l2.sap) && + ((skb->data[1] >> 1) == stptr->l2.tei)) { + stptr->l1.l1l2(stptr, PH_DATA, skb); found = !0; break; } else @@ -440,14 +470,15 @@ * by isdn4linux */ - if ((!(ptr[0] >> 2)) && (!(ptr[2] & 0x01))) { + if ((!(skb->data[0] >> 2)) && (!(skb->data[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); + skb->data[1] >> 1); + LogFrame(sp, skb->data, skb->len); + dlogframe(sp, skb->data + 4, skb->len - 4, tmp); } - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); } } @@ -470,65 +501,62 @@ } static void -l2l1(struct PStack *st, int pr, - struct BufHeader *ibh) +l2l1(struct PStack *st, int pr, void *arg) { struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware; - byte *ptr = DATAPTR(ibh); + struct sk_buff *skb = arg; char str[64]; switch (pr) { case (PH_DATA): - if (sp->xmtibh) { - BufQueueLink(&sp->sq, ibh); + if (sp->tx_skb) { + skb_queue_tail(&sp->sq, skb); #ifdef L2FRAME_DEBUG /* psa */ if (sp->debug & L1_DEB_LAPD) - Logl2Frame(sp, ibh, "PH_DATA Queued", 0); + Logl2Frame(sp, skb, "PH_DATA Queued", 0); #endif } else { - if ((sp->dlogflag) && (!(ptr[2] & 1))) { /* I-FRAME */ - LogFrame(sp, ptr, ibh->datasize); + if ((sp->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */ + LogFrame(sp, skb->data, skb->len); sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei); - dlogframe(sp, ptr + st->l2.ihsize, ibh->datasize - st->l2.ihsize, + dlogframe(sp, skb->data + st->l2.ihsize, skb->len - st->l2.ihsize, str); } - sp->xmtibh = ibh; - sp->sendptr = 0; - sp->releasebuf = !0; - sp->isac_fill_fifo(sp); + sp->tx_skb = skb; + sp->tx_cnt = 0; #ifdef L2FRAME_DEBUG /* psa */ if (sp->debug & L1_DEB_LAPD) - Logl2Frame(sp, ibh, "PH_DATA", 0); + Logl2Frame(sp, skb, "PH_DATA", 0); #endif + sp->isac_fill_fifo(sp); } break; case (PH_DATA_PULLED): - if (sp->xmtibh) { + if (sp->tx_skb) { if (sp->debug & L1_DEB_WARN) - debugl1(sp, " l2l1 xmtibh exist this shouldn't happen"); + debugl1(sp, " l2l1 tx_skb exist this shouldn't happen"); break; } - if ((sp->dlogflag) && (!(ptr[2] & 1))) { /* I-FRAME */ - LogFrame(sp, ptr, ibh->datasize); + if ((sp->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */ + LogFrame(sp, skb->data, skb->len); sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei); - dlogframe(sp, ptr + st->l2.ihsize, ibh->datasize - st->l2.ihsize, + dlogframe(sp, skb->data + st->l2.ihsize, skb->len - st->l2.ihsize, str); } - sp->xmtibh = ibh; - sp->sendptr = 0; - sp->releasebuf = 0; - sp->isac_fill_fifo(sp); + sp->tx_skb = skb; + sp->tx_cnt = 0; #ifdef L2FRAME_DEBUG /* psa */ if (sp->debug & L1_DEB_LAPD) - Logl2Frame(sp, ibh, "PH_DATA_PULLED", 0); + Logl2Frame(sp, skb, "PH_DATA_PULLED", 0); #endif + sp->isac_fill_fifo(sp); break; case (PH_REQUEST_PULL): #ifdef L2FRAME_DEBUG /* psa */ if (sp->debug & L1_DEB_LAPD) debugl1(sp, "-> PH_REQUEST_PULL"); #endif - if (!sp->xmtibh) { + if (!sp->tx_skb) { st->l1.requestpull = 0; st->l1.l1l2(st, PH_PULL_ACK, NULL); } else @@ -543,7 +571,7 @@ { struct PStack *st = hsp->st; - if (hsp->xmtibh) + if (hsp->tx_skb) return; if (st->l1.requestpull) { @@ -551,14 +579,14 @@ st->l1.l1l2(st, PH_PULL_ACK, NULL); } if (!hsp->active) - if ((!hsp->xmtibh) && (!hsp->sq.head)) + if ((!hsp->tx_skb) && (!skb_queue_len(&hsp->squeue))) hsp->sp->modehscx(hsp, 0, 0); } static void hscx_process_rcv(struct HscxState *hsp) { - struct BufHeader *ibh; + struct sk_buff *skb; #ifdef DEBUG_MAGIC if (hsp->magic != 301270) { @@ -566,8 +594,8 @@ return; } #endif - while (!BufQueueUnlink(&ibh, &hsp->rq)) { - hsp->st->l1.l1l2(hsp->st, PH_DATA, ibh); + while ((skb = skb_dequeue(&hsp->rqueue))) { + hsp->st->l1.l1l2(hsp->st, PH_DATA, skb); } } @@ -675,6 +703,7 @@ void *heldby, int releasetoo) { struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware; + struct sk_buff *skb; #ifdef DEBUG_MAGIC if (sp->magic != 301271) { @@ -683,16 +712,16 @@ } #endif - BufQueueDiscard(&sp->sq, pr, heldby, releasetoo); + while ((skb = skb_dequeue(&sp->sq))) { + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_WRITE); + } } 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); @@ -737,7 +766,7 @@ save_flags(flags); cli(); if (request_irq(card->sp->irq, routine, - SA_INTERRUPT, "HiSax", NULL)) { + I4L_IRQ_FLAG, "HiSax", NULL)) { printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n", card->sp->irq); restore_flags(flags); @@ -760,13 +789,28 @@ void close_hscxstate(struct HscxState *hs) { + struct sk_buff *skb; + hs->sp->modehscx(hs, 0, 0); hs->inuse = 0; - if (hs->init) { - BufPoolFree(&hs->smallpool); - BufPoolFree(&hs->rbufpool); - BufPoolFree(&hs->sbufpool); + if (hs->rcvbuf) { + kfree(hs->rcvbuf); + hs->rcvbuf = NULL; + } + while ((skb = skb_dequeue(&hs->rqueue))) { + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); + } + while ((skb = skb_dequeue(&hs->squeue))) { + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_WRITE); + } + if (hs->tx_skb) { + SET_SKB_FREE(hs->tx_skb); + dev_kfree_skb(hs->tx_skb, FREE_WRITE); + hs->tx_skb = NULL; + } } hs->init = 0; } @@ -775,14 +819,28 @@ closecard(int cardnr) { struct IsdnCardState *csta = cards[cardnr].sp; - - BufPoolFree(&csta->smallpool); - BufPoolFree(&csta->rbufpool); - BufPoolFree(&csta->sbufpool); + struct sk_buff *skb; close_hscxstate(csta->hs + 1); close_hscxstate(csta->hs); + if (csta->rcvbuf) { + kfree(csta->rcvbuf); + csta->rcvbuf = NULL; + } + while ((skb = skb_dequeue(&csta->rq))) { + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); + } + while ((skb = skb_dequeue(&csta->sq))) { + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_WRITE); + } + if (csta->tx_skb) { + SET_SKB_FREE(csta->tx_skb); + dev_kfree_skb(csta->tx_skb, FREE_WRITE); + csta->tx_skb = NULL; + } switch (csta->typ) { #if CARD_TELES0 case ISDN_CTYPE_16_0: @@ -830,8 +888,7 @@ save_flags(flags); cli(); if (!(sp = (struct IsdnCardState *) - Smalloc(sizeof(struct IsdnCardState), GFP_KERNEL, - "struct IsdnCardState"))) { + kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC))) { printk(KERN_WARNING "HiSax: No memory for IsdnCardState(card %d)\n", cardnr + 1); @@ -858,18 +915,18 @@ restore_flags(flags); return (0); } - if (!(sp->dlogspace = Smalloc(4096, GFP_KERNEL, "dlogspace"))) { + if (!(sp->dlogspace = kmalloc(4096, GFP_ATOMIC))) { 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"))) { + if (!(sp->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) { printk(KERN_WARNING "HiSax: No memory for status_buf(card %d)\n", cardnr + 1); - Sfree(sp->dlogspace); + kfree(sp->dlogspace); restore_flags(flags); return (0); } @@ -880,7 +937,8 @@ 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.maxbufsize = MAX_DATA_SIZE; + sp->iif.hl_hdrlen = MAX_HEADER_LEN; sp->iif.features = ISDN_FEATURE_L2_X75I | ISDN_FEATURE_L2_HDLC | @@ -892,12 +950,15 @@ #ifdef CONFIG_HISAX_EURO ISDN_FEATURE_P_EURO | #endif +#ifdef CONFIG_HISAX_NI1 + ISDN_FEATURE_P_NI1 | +#endif 0; sp->iif.command = HiSax_command; - sp->iif.writebuf = HiSax_writebuf; + sp->iif.writebuf = NULL; sp->iif.writecmd = NULL; - sp->iif.writebuf_skb = NULL; + sp->iif.writebuf_skb = HiSax_writebuf_skb; sp->iif.readstat = HiSax_readstatus; register_isdn(&sp->iif); sp->myid = sp->iif.channels; @@ -907,6 +968,7 @@ (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" : (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" : + (card->protocol == ISDN_PTYPE_NI1) ? "NI1" : "NONE", sp->iif.id, sp->myid); switch (card->typ) { #if CARD_TELES0 @@ -948,35 +1010,27 @@ 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; + if (!(sp->rcvbuf = kmalloc(MAX_DFRAME_LEN, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for isac rcvbuf\n"); + return (1); + } + sp->rcvidx = 0; + sp->tx_skb = NULL; + sp->tx_cnt = 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); + skb_queue_head_init(&sp->rq); + skb_queue_head_init(&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 @@ -1075,7 +1129,7 @@ printk(KERN_WARNING "HiSax: Card %s not installed !\n", CardType[cards[i].typ]); if (cards[i].sp) - Sfree((void *) cards[i].sp); + kfree((void *) cards[i].sp); cards[i].sp = NULL; HiSax_shiftcards(i); } @@ -1098,7 +1152,7 @@ release_tei(cards[i].sp); release_irq(i); closecard(i); - Sfree((void *) cards[i].sp); + kfree((void *) cards[i].sp); cards[i].sp = NULL; } Isdnl2Free(); @@ -1107,11 +1161,10 @@ } static void -hscx_l2l1(struct PStack *st, int pr, - struct BufHeader *ibh) +hscx_l2l1(struct PStack *st, int pr, void *arg) { - struct IsdnCardState *sp = (struct IsdnCardState *) - st->l1.hardware; + struct sk_buff *skb = arg; + struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware; struct HscxState *hsp = sp->hs + st->l1.hscx; long flags; @@ -1119,29 +1172,27 @@ case (PH_DATA): save_flags(flags); cli(); - if (hsp->xmtibh) { - BufQueueLink(&hsp->sq, ibh); + if (hsp->tx_skb) { + skb_queue_tail(&hsp->squeue, skb); restore_flags(flags); } else { restore_flags(flags); - hsp->xmtibh = ibh; - hsp->sendptr = 0; - hsp->releasebuf = !0; + hsp->tx_skb = skb; + hsp->count = 0; sp->hscx_fill_fifo(hsp); } break; case (PH_DATA_PULLED): - if (hsp->xmtibh) { + if (hsp->tx_skb) { printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n"); break; } - hsp->xmtibh = ibh; - hsp->sendptr = 0; - hsp->releasebuf = 0; + hsp->tx_skb = skb; + hsp->count = 0; sp->hscx_fill_fifo(hsp); break; case (PH_REQUEST_PULL): - if (!hsp->xmtibh) { + if (!hsp->tx_skb) { st->l1.requestpull = 0; st->l1.l1l2(st, PH_PULL_ACK, NULL); } else @@ -1159,6 +1210,7 @@ struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware; struct HscxState *hsp = sp->hs + st->l1.hscx; + struct sk_buff *skb; #ifdef DEBUG_MAGIC if (hsp->magic != 301270) { @@ -1167,7 +1219,10 @@ } #endif - BufQueueDiscard(&hsp->sq, pr, heldby, releasetoo); + while ((skb = skb_dequeue(&hsp->squeue))) { + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_WRITE); + } } static int @@ -1177,24 +1232,20 @@ 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); + if (!(hsp->rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for hscx_rcvbuf\n"); + return (1); + } + skb_queue_head_init(&hsp->rqueue); + skb_queue_head_init(&hsp->squeue); } 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->tx_skb = NULL; hsp->event = 0; + hsp->rcvidx = 0; + hsp->tx_cnt = 0; return (0); } @@ -1212,7 +1263,7 @@ st->l1.l1man(st, PH_ACTIVATE, NULL); break; case (PH_DEACTIVATE): - if (!hsp->xmtibh) + if (!hsp->tx_skb) sp->modehscx(hsp, 0, 0); hsp->active = 0; @@ -1231,9 +1282,6 @@ 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; @@ -1256,7 +1304,7 @@ #ifdef L2FRAME_DEBUG /* psa */ char * -l2cmd(byte cmd) +l2cmd(u_char cmd) { switch (cmd & ~0x10) { case 1: @@ -1290,7 +1338,7 @@ static char tmp[20]; char * -l2frames(byte * ptr) +l2frames(u_char * ptr) { switch (ptr[2] & ~0x10) { case 1: @@ -1320,12 +1368,12 @@ } void -Logl2Frame(struct IsdnCardState *sp, struct BufHeader *ibh, char *buf, int dir) +Logl2Frame(struct IsdnCardState *sp, struct sk_buff *skb, char *buf, int dir) { char tmp[132]; - byte *ptr; + u_char *ptr; - ptr = DATAPTR(ibh); + ptr = skb->data; if (ptr[0] & 1 || !(ptr[1] & 1)) debugl1(sp, "Addres not LAPD"); diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/isdnl1.h linux/drivers/isdn/hisax/isdnl1.h --- v2.1.41/linux/drivers/isdn/hisax/isdnl1.h Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/isdnl1.h Wed May 28 10:49:09 1997 @@ -1,6 +1,9 @@ -/* $Id: isdnl1.h,v 1.3 1996/12/08 19:41:55 keil Exp $ +/* $Id: isdnl1.h,v 1.4 1997/04/06 22:55:52 keil Exp $ * * $Log: isdnl1.h,v $ + * Revision 1.4 1997/04/06 22:55:52 keil + * Using SKB's + * * Revision 1.3 1996/12/08 19:41:55 keil * L2FRAME_DEBUG * @@ -36,10 +39,13 @@ #define HSCX_XMTBUFREADY 1 extern void debugl1(struct IsdnCardState *sp, char *msg); -extern char *HscxVersion(byte v); -extern char *ISACVersion(byte v); +extern char *HscxVersion(u_char v); +extern char *ISACVersion(u_char 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); + +#ifdef L2FRAME_DEBUG +extern void Logl2Frame(struct IsdnCardState *sp, struct sk_buff *skb, char *buf, int dir); +#endif diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/isdnl2.c linux/drivers/isdn/hisax/isdnl2.c --- v2.1.41/linux/drivers/isdn/hisax/isdnl2.c Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/isdnl2.c Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: isdnl2.c,v 1.7 1997/02/09 00:25:44 keil Exp $ +/* $Id: isdnl2.c,v 1.10 1997/05/06 09:38:13 keil Exp $ * Author Karsten Keil (keil@temic-ech.spacenet.de) * based on the teles driver from Jan den Ouden @@ -7,6 +7,19 @@ * Fritz Elfert * * $Log: isdnl2.c,v $ + * Revision 1.10 1997/05/06 09:38:13 keil + * Bugfixes: - clear ack queue entries after resend + * - acknowlege each frame to linklevel + * - UA for SABM is Response, not command + * - only RR was send as supervisor frame (X.75 hangs after a + * sequence error) + * + * Revision 1.9 1997/04/07 23:02:11 keil + * missing braces + * + * Revision 1.8 1997/04/06 22:59:59 keil + * Using SKB's; changing function names; some minor changes + * * Revision 1.7 1997/02/09 00:25:44 keil * new interface handling, one interface per card * @@ -35,14 +48,12 @@ #include "hisax.h" #include "isdnl2.h" -#define TIMER_1 2000 - -const char *l2_revision = "$Revision: 1.7 $"; +const char *l2_revision = "$Revision: 1.10 $"; static void l2m_debug(struct FsmInst *fi, char *s); struct Fsm l2fsm = -{NULL, 0, 0}; +{NULL, 0, 0, NULL, NULL}; enum { ST_L2_1, @@ -118,6 +129,33 @@ static int l2addrsize(struct Layer2 *tsp); +static void +InitWin(struct Layer2 *l2) +{ + int i; + + for (i = 0; i < MAX_WINDOW; i++) + l2->windowar[i] = NULL; +} + +static void +ReleaseWin(struct Layer2 *l2) +{ + int i, cnt = 0; + + + for (i = 0; i < MAX_WINDOW; i++) { + if (l2->windowar[i]) { + cnt++; + SET_SKB_FREE(l2->windowar[i]); + dev_kfree_skb(l2->windowar[i], FREE_WRITE); + l2->windowar[i] = NULL; + } + } + if (cnt) + printk(KERN_WARNING "isdl2 freed %d skbuffs in release\n", cnt); +} + static int cansend(struct PStack *st) { @@ -130,10 +168,12 @@ static void discard_i_queue(struct PStack *st) { - struct BufHeader *ibh; + struct sk_buff *skb; - while (!BufQueueUnlink(&ibh, &st->l2.i_queue)) - BufPoolRelease(ibh); + while ((skb = skb_dequeue(&st->l2.i_queue))) { + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); + } } int @@ -150,9 +190,9 @@ static int sethdraddr(struct Layer2 *tsp, - struct BufHeader *ibh, int rsp) + u_char * header, int rsp) { - byte *ptr = DATAPTR(ibh); + u_char *ptr = header; int crbit; if (tsp->laptype == LAPD) { @@ -176,16 +216,16 @@ static void enqueue_ui(struct PStack *st, - struct BufHeader *ibh) + struct sk_buff *skb) { - st->l2.l2l1(st, PH_DATA, ibh); + st->l2.l2l1(st, PH_DATA, skb); } static void enqueue_super(struct PStack *st, - struct BufHeader *ibh) + struct sk_buff *skb) { - st->l2.l2l1(st, PH_DATA, ibh); + st->l2.l2l1(st, PH_DATA, skb); } static int @@ -207,11 +247,13 @@ if (l2->va != nr) { while (l2->va != nr) { l2->va = (l2->va + 1) % (l2->extended ? 128 : 8); - BufPoolRelease(l2->windowar[l2->sow]); + SET_SKB_FREE(l2->windowar[l2->sow]); + dev_kfree_skb(l2->windowar[l2->sow], FREE_WRITE); + l2->windowar[l2->sow] = NULL; l2->sow = (l2->sow + 1) % l2->window; + if (st->l4.l2writewakeup) + st->l4.l2writewakeup(st); } - if (st->l4.l2writewakeup) - st->l4.l2writewakeup(st); } } @@ -225,38 +267,51 @@ } static void -l2s2(struct FsmInst *fi, int event, void *arg) +l2_send_ui(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; - - byte *ptr; + struct sk_buff *skb = arg; + u_char header[MAX_HEADER_LEN]; int i; - i = sethdraddr(&(st->l2), ibh, CMD); - ptr = DATAPTR(ibh); - ptr += i; - *ptr = UI; - - enqueue_ui(st, ibh); + i = sethdraddr(&(st->l2), header, CMD); + header[i++] = UI; + memcpy(skb_push(skb, i), header, i); + enqueue_ui(st, skb); } static void -l2s3(struct FsmInst *fi, int event, void *arg) +l2_receive_ui(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; + struct sk_buff *skb = arg; - st->l2.l2l3(st, DL_UNIT_DATA, ibh); + skb_pull(skb, l2headersize(&st->l2, 1)); + st->l2.l2l3(st, DL_UNIT_DATA, skb); +} + +inline void +send_uframe(struct PStack *st, u_char cmd, u_char cr) +{ + struct sk_buff *skb; + u_char tmp[MAX_HEADER_LEN]; + int i; + + i = sethdraddr(&st->l2, tmp, cr); + tmp[i++] = cmd; + if (!(skb = alloc_skb(i, GFP_ATOMIC))) { + printk(KERN_WARNING "isdl2 can't alloc sbbuff for send_uframe\n"); + return; + } + memcpy(skb_put(skb, i), tmp, i); + enqueue_super(st, skb); } static void establishlink(struct FsmInst *fi) { struct PStack *st = fi->userdata; - struct BufHeader *ibh; - int i; - byte *ptr; + u_char cmd; FsmChangeState(fi, ST_L2_5); st->l2.rc = 0; @@ -266,34 +321,21 @@ 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); + cmd = (st->l2.extended ? SABME : SABM) | 0x10; + send_uframe(st, cmd, CMD); } static void -l2s11(struct FsmInst *fi, int event, void *arg) +l2_establish(struct FsmInst *fi, int event, void *arg) { establishlink(fi); } static void -l2s13(struct FsmInst *fi, int event, void *arg) +l2_send_disconn(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); @@ -308,70 +350,71 @@ l2m_debug(&st->l2.l2m, "FAT 2"); - if ((chanp->impair == 2) && (st->l2.laptype == LAPB)) - goto nodisc; + if (!((chanp->impair == 2) && (st->l2.laptype == LAPB))) + send_uframe(st, DISC | 0x10, CMD); - 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) +l2_got_SABMX(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); + struct sk_buff *skb = arg; + int est = 1, state; + u_char PollFlag; + + state = fi->state; + + skb_pull(skb, l2addrsize(&(st->l2))); + PollFlag = *skb->data & 0x10; + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); + + if (ST_L2_4 != state) + if (st->l2.vs != st->l2.va) { + discard_i_queue(st); + est = 1; + } else + est = 0; st->l2.vs = 0; st->l2.va = 0; st->l2.vr = 0; st->l2.sow = 0; - FsmChangeState(fi, ST_L2_7); + if (ST_L2_7 != state) + FsmChangeState(fi, ST_L2_7); + + send_uframe(st, UA | PollFlag, RSP); + + if (st->l2.t200_running) { + 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 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); + if (est) + st->l2.l2man(st, DL_ESTABLISH, NULL); + if (ST_L2_8 == state) + if (skb_queue_len(&st->l2.i_queue) && cansend(st)) + st->l2.l2l1(st, PH_REQUEST_PULL, NULL); } static void -l2s14(struct FsmInst *fi, int event, void *arg) +l2_got_disconn(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; + struct sk_buff *skb = arg; struct Channel *chanp = st->l4.userdata; - byte *ptr; - int i, p; + u_char PollFlag; - ptr = DATAPTR(ibh); - ptr += l2addrsize(&(st->l2)); - p = (*ptr) & 0x10; - BufPoolRelease(ibh); + skb_pull(skb, l2addrsize(&(st->l2))); + PollFlag = *skb->data & 0x10; + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); FsmChangeState(fi, ST_L2_4); @@ -380,68 +423,41 @@ 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); + if (!((chanp->impair == 1) && (st->l2.laptype == LAPB))) + send_uframe(st, UA | PollFlag, RSP); - noresponse: st->l2.l2man(st, DL_RELEASE, NULL); - } static void -l2s14_1(struct FsmInst *fi, int event, void *arg) +l2_got_st4_disc(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; + struct sk_buff *skb = 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); + u_char PollFlag; - ibh->datasize = i + 1; - enqueue_super(st, ibh); + skb_pull(skb, l2addrsize(&(st->l2))); + PollFlag = *skb->data & 0x10; + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); - noresponse: + if (!((chanp->impair == 1) && (st->l2.laptype == LAPB))) + send_uframe(st, DM | (PollFlag ? 0x10 : 0x0), RSP); } static void -l2s5(struct FsmInst *fi, int event, void *arg) +l2_got_ua_establish(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); + struct sk_buff *skb = arg; + u_char f; + skb_pull(skb, l2addrsize(&(st->l2))); + f = *skb->data & 0x10; + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); if (f) { st->l2.vs = 0; st->l2.va = 0; @@ -454,25 +470,21 @@ 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) +l2_got_ua_disconn(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); + struct sk_buff *skb = arg; + u_char f; + skb_pull(skb, l2addrsize(&(st->l2))); + f = *skb->data & 0x10; + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); if (f) { FsmDelTimer(&st->l2.t200_timer, 6); FsmChangeState(fi, ST_L2_4); @@ -480,31 +492,39 @@ } } -static void -enquiry_response(struct PStack *st) +inline void +enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf) { - struct BufHeader *ibh2; - int i; - byte *ptr; + struct sk_buff *skb; struct Layer2 *l2; + u_char tmp[MAX_HEADER_LEN]; + int i; 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); + i = sethdraddr(l2, tmp, cr); + if (l2->extended) { + tmp[i++] = typ; + tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0); + } else + tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0); + if (!(skb = alloc_skb(i, GFP_ATOMIC))) { + printk(KERN_WARNING "isdl2 can't alloc sbbuff for enquiry_cr\n"); + return; } + memcpy(skb_put(skb, i), tmp, i); + enqueue_super(st, skb); +} + +inline void +enquiry_response(struct PStack *st, u_char typ, u_char final) +{ + enquiry_cr(st, typ, RSP, final); +} + +inline void +enquiry_command(struct PStack *st, u_char typ, u_char poll) +{ + enquiry_cr(st, typ, CMD, poll); } static void @@ -515,88 +535,74 @@ } static void -l2s6(struct FsmInst *fi, int event, void *arg) +l2_got_st7_RR(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 sk_buff *skb = arg; + int PollFlag, seq, rsp; 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->laptype == LAPD) + rsp = *skb->data & 0x2; + else + rsp = *skb->data == 0x3; + if (l2->orig) + rsp = !rsp; + skb_pull(skb, l2addrsize(l2)); if (l2->extended) { - p = (ptr[1] & 0x1) == 0x1; - seq = ptr[1] >> 1; + PollFlag = (skb->data[1] & 0x1) == 0x1; + seq = skb->data[1] >> 1; } else { - p = (ptr[0] & 0x10); - seq = (ptr[0] >> 5) & 0x7; + PollFlag = (skb->data[0] & 0x10); + seq = (skb->data[0] >> 5) & 0x7; } - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); - if ((chanp->impair == 4) && (st->l2.laptype == LAPB)) - goto noresp; + if (!((chanp->impair == 4) && (st->l2.laptype == LAPB))) + if ((!rsp) && PollFlag) + enquiry_response(st, RR, PollFlag); - if ((!rsp) && p) - enquiry_response(st); - - noresp: if (legalnr(st, seq)) { - if (seq == st->l2.vs) { + if (seq == 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) + FsmDelTimer(&l2->t200_timer, 7); + l2->t200_running = 0; + FsmDelTimer(&l2->t203_timer, 8); + if (FsmAddTimer(&l2->t203_timer, l2->t203, EV_L2_T203, NULL, 5)) + if (l2->l2m.debug) l2m_debug(&st->l2.l2m, "FAT 5"); - if (st->l2.i_queue.head) + if (skb_queue_len(&st->l2.i_queue)) st->l2.l2l1(st, PH_REQUEST_PULL, NULL); - } else if (st->l2.va != seq) { + } else if (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) + if (skb_queue_len(&st->l2.i_queue)) st->l2.l2l1(st, PH_REQUEST_PULL, NULL); } } else nrerrorrecovery(fi); - if ((fi->userint & LC_FLUSH_WAIT) && rsp && !l2->i_queue.head) { + if ((fi->userint & LC_FLUSH_WAIT) && rsp && !(skb_queue_len(&st->l2.i_queue))) { fi->userint &= ~LC_FLUSH_WAIT; st->l2.l2man(st, DL_FLUSH, NULL); } } static void -l2s7(struct FsmInst *fi, int event, void *arg) +l2_feed_iqueue(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; - int i; - byte *ptr; + struct sk_buff *skb = arg; - i = sethdraddr(&st->l2, ibh, CMD); - ptr = DATAPTR(ibh); - BufQueueLink(&st->l2.i_queue, ibh); + skb_queue_tail(&st->l2.i_queue, skb); st->l2.l2l1(st, PH_REQUEST_PULL, NULL); } @@ -605,24 +611,21 @@ { struct PStack *st = fi->userdata; struct Channel *chanp = st->l4.userdata; - struct BufHeader *ibh = arg; - byte *ptr; - struct BufHeader *ibh2; + struct sk_buff *skb = arg; 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); + i = l2addrsize(l2); if (l2->extended) { - p = (ptr[1] & 0x1) == 0x1; - seq = ptr[0] >> 1; - *nr = (ptr[1] >> 1) & 0x7f; + p = (skb->data[i + 1] & 0x1) == 0x1; + seq = skb->data[i] >> 1; + *nr = (skb->data[i + 1] >> 1) & 0x7f; } else { - p = (ptr[0] & 0x10); - seq = (ptr[0] >> 1) & 0x7; - *nr = (ptr[0] >> 5) & 0x7; + p = (skb->data[i] & 0x10); + seq = (skb->data[i] >> 1) & 0x7; + *nr = (skb->data[i] >> 5) & 0x7; } if (l2->vr == seq) { @@ -631,72 +634,39 @@ 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); + LogFrame(st->l1.hardware, skb->data, skb->len); sprintf(str, "Q.931 frame network->user tei %d", st->l2.tei); - dlogframe(st->l1.hardware, ptr + l2->ihsize, - ibh->datasize - l2->ihsize, str); + dlogframe(st->l1.hardware, skb->data + l2->ihsize, + skb->len - 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: - } + if (!((chanp->impair == 3) && (st->l2.laptype == LAPB))) + if (p || (!skb_queue_len(&st->l2.i_queue))) + enquiry_response(st, RR, p); + skb_pull(skb, l2headersize(l2, 0)); } else { /* n(s)!=v(r) */ wasok = 0; - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); if (st->l2.rejexp) { if (p) - goto label8_1; + if (!((chanp->impair == 3) && (st->l2.laptype == LAPB))) + enquiry_response(st, RR, p); } 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); - } + enquiry_command(st, REJ, 1); } } - return wasok; - } static void -l2s8(struct FsmInst *fi, int event, void *arg) +l2_got_st7_data(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; + struct sk_buff *skb = arg; int nr, wasok; wasok = icommandreceived(fi, event, arg, &nr); @@ -711,7 +681,7 @@ if (st->l2.l2m.debug) l2m_debug(&st->l2.l2m, "FAT 5"); - if (st->l2.i_queue.head) + if (skb_queue_len(&st->l2.i_queue)) st->l2.l2l1(st, PH_REQUEST_PULL, NULL); } else if (nr != st->l2.va) { setva(st, nr); @@ -720,38 +690,38 @@ if (st->l2.l2m.debug) l2m_debug(&st->l2.l2m, "FAT 6"); - if (st->l2.i_queue.head) + if (skb_queue_len(&st->l2.i_queue)) st->l2.l2l1(st, PH_REQUEST_PULL, NULL); } } else nrerrorrecovery(fi); if (wasok) - st->l2.l2l3(st, DL_DATA, ibh); + st->l2.l2l3(st, DL_DATA, skb); } static void -l2s8_1(struct FsmInst *fi, int event, void *arg) +l2_got_st8_data(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; + struct sk_buff *skb = arg; int nr, wasok; wasok = icommandreceived(fi, event, arg, &nr); if (legalnr(st, nr)) { setva(st, nr); - if (st->l2.i_queue.head) + if (skb_queue_len(&st->l2.i_queue)) st->l2.l2l1(st, PH_REQUEST_PULL, NULL); } else nrerrorrecovery(fi); if (wasok) - st->l2.l2l3(st, DL_DATA, ibh); + st->l2.l2l3(st, DL_DATA, skb); } static void -l2s17(struct FsmInst *fi, int event, void *arg) +l2_got_tei(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -777,70 +747,61 @@ p1 += l2->extended ? 128 : 8; p1 = (p1 + l2->sow) % l2->window; - BufQueueLinkFront(&l2->i_queue, l2->windowar[p1]); + skb_queue_head(&l2->i_queue, l2->windowar[p1]); + l2->windowar[p1] = NULL; } st->l2.l2l1(st, PH_REQUEST_PULL, NULL); } } static void -l2s16(struct FsmInst *fi, int event, void *arg) +l2_got_st7_rej(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; - int p, seq, rsp; - byte *ptr; + struct sk_buff *skb = arg; + int PollFlag, seq, rsp; 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); + l2 = &st->l2; + if (l2->laptype == LAPD) + rsp = *skb->data & 0x2; + else + rsp = *skb->data == 0x3; + if (l2->orig) + rsp = !rsp; + skb_pull(skb, l2addrsize(l2)); if (l2->extended) { - p = (ptr[1] & 0x1) == 0x1; - seq = ptr[1] >> 1; + PollFlag = (skb->data[1] & 0x1) == 0x1; + seq = skb->data[1] >> 1; } else { - p = (ptr[0] & 0x10); - seq = (ptr[0] >> 5) & 0x7; + PollFlag = (skb->data[0] & 0x10); + seq = (skb->data[0] >> 5) & 0x7; } - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); - if ((!rsp) && p) - enquiry_response(st); + if ((!rsp) && PollFlag) + enquiry_response(st, RR, PollFlag); if (!legalnr(st, seq)) return; setva(st, seq); invoke_retransmission(st, seq); - } static void -l2s19(struct FsmInst *fi, int event, void *arg) +l2_no_tei(struct FsmInst *fi, int event, void *arg) { FsmChangeState(fi, ST_L2_4); } static void -l2s20(struct FsmInst *fi, int event, void *arg) +l2_st5_tout_200(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - int i; - struct BufHeader *ibh; - byte *ptr; + u_char cmd; if (st->l2.rc == st->l2.n200) { FsmChangeState(fi, ST_L2_4); @@ -853,29 +814,16 @@ 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); + cmd = (st->l2.extended ? SABME : SABM) | 0x10; + send_uframe(st, cmd, CMD); } } static void -l2s21(struct FsmInst *fi, int event, void *arg) +l2_st6_tout_200(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); @@ -888,59 +836,53 @@ 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: + if (!((chanp->impair == 2) && (st->l2.laptype == LAPB))) + send_uframe(st, DISC | 0x10, CMD); } } static void -l2s22(struct FsmInst *fi, int event, void *arg) +l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct BufHeader *ibh; + struct sk_buff *skb; struct Layer2 *l2 = &st->l2; - byte *ptr; - int p1; + u_char header[MAX_HEADER_LEN]; + int p1, i; if (!cansend(st)) return; - if (BufQueueUnlink(&ibh, &l2->i_queue)) + skb = skb_dequeue(&l2->i_queue); + if (!skb) return; - p1 = l2->vs - l2->va; if (p1 < 0) p1 += l2->extended ? 128 : 8; p1 = (p1 + l2->sow) % l2->window; - l2->windowar[p1] = ibh; + if (l2->windowar[p1]) { + printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n", + p1); + SET_SKB_FREE(l2->windowar[p1]); + dev_kfree_skb(l2->windowar[p1], FREE_WRITE); + } + l2->windowar[p1] = skb_clone(skb, GFP_ATOMIC); - ptr = DATAPTR(ibh); - ptr += l2addrsize(l2); + i = sethdraddr(&st->l2, header, CMD); if (l2->extended) { - *ptr++ = l2->vs << 1; - *ptr++ = l2->vr << 1; + header[i++] = l2->vs << 1; + header[i++] = l2->vr << 1; l2->vs = (l2->vs + 1) % 128; } else { - *ptr++ = (l2->vr << 5) | (l2->vs << 1); + header[i++] = (l2->vr << 5) | (l2->vs << 1); l2->vs = (l2->vs + 1) % 8; } - st->l2.l2l1(st, PH_DATA_PULLED, ibh); - + memcpy(skb_push(skb, i), header, i); + st->l2.l2l1(st, PH_DATA_PULLED, skb); 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)) @@ -949,38 +891,24 @@ st->l2.t200_running = !0; } - if (l2->i_queue.head && cansend(st)) + if (skb_queue_len(&l2->i_queue) && 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"); + enquiry_command(st, RR, 1); + 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; - } + st->l2.t200_running = !0; } static void -l2s23(struct FsmInst *fi, int event, void *arg) +l2_st7_tout_200(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -992,40 +920,33 @@ } static void -l2s24(struct FsmInst *fi, int event, void *arg) +l2_got_st8_rr_rej(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; - int p, seq, rsp; - byte *ptr; + struct sk_buff *skb = arg; + int PollFlag, seq, rsp; 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->laptype == LAPD) + rsp = *skb->data & 0x2; + else + rsp = *skb->data == 0x3; + if (l2->orig) + rsp = !rsp; + skb_pull(skb, l2addrsize(l2)); if (l2->extended) { - p = (ptr[1] & 0x1) == 0x1; - seq = ptr[1] >> 1; + PollFlag = (skb->data[1] & 0x1) == 0x1; + seq = skb->data[1] >> 1; } else { - p = (ptr[0] & 0x10); - seq = (ptr[0] >> 5) & 0x7; + PollFlag = (skb->data[0] & 0x10); + seq = (skb->data[0] >> 5) & 0x7; } - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); - if (rsp && p) { + if (rsp && PollFlag) { if (legalnr(st, seq)) { FsmChangeState(fi, ST_L2_7); setva(st, seq); @@ -1039,7 +960,7 @@ invoke_retransmission(st, seq); - if (l2->i_queue.head && cansend(st)) + if (skb_queue_len(&l2->i_queue) && cansend(st)) st->l2.l2l1(st, PH_REQUEST_PULL, NULL); else if (fi->userint & LC_FLUSH_WAIT) { fi->userint &= ~LC_FLUSH_WAIT; @@ -1047,8 +968,8 @@ } } } else { - if (!rsp && p) - enquiry_response(st); + if (!rsp && PollFlag) + enquiry_response(st, RR, PollFlag); if (legalnr(st, seq)) { setva(st, seq); } @@ -1056,7 +977,7 @@ } static void -l2s25(struct FsmInst *fi, int event, void *arg) +l2_st7_tout_203(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -1066,7 +987,7 @@ } static void -l2s26(struct FsmInst *fi, int event, void *arg) +l2_st8_tout_200(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -1079,92 +1000,30 @@ } static void -l2s27(struct FsmInst *fi, int event, void *arg) +l2_got_FRMR(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; + struct sk_buff *skb = arg; char tmp[64]; - ptr = DATAPTR(ibh); - ptr += l2addrsize(&st->l2); - ptr++; - + skb_pull(skb, l2addrsize(&st->l2)); 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]); + skb->data[0], skb->data[1], skb->data[2], + skb->data[3], skb->data[4]); else sprintf(tmp, "FRMR information %2x %2x %2x", - ptr[0], ptr[1], ptr[2]); + skb->data[0], skb->data[1], skb->data[2]); l2m_debug(&st->l2.l2m, tmp); } - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); } static void -l2s30(struct FsmInst *fi, int event, void *arg) +l2_tei_remove(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -1188,26 +1047,26 @@ FsmChangeState(fi, ST_L2_1); } -static int -IsUI(byte * data, int ext) +inline int +IsUI(u_char * data, int ext) { return ((data[0] & 0xef) == UI); } -static int -IsUA(byte * data, int ext) +inline int +IsUA(u_char * data, int ext) { return ((data[0] & 0xef) == UA); } -static int -IsDISC(byte * data, int ext) +inline int +IsDISC(u_char * data, int ext) { return ((data[0] & 0xef) == DISC); } -static int -IsRR(byte * data, int ext) +inline int +IsRR(u_char * data, int ext) { if (ext) return (data[0] == RR); @@ -1215,32 +1074,34 @@ return ((data[0] & 0xf) == 1); } -static int -IsI(byte * data, int ext) +inline int +IsI(u_char * data, int ext) { return ((data[0] & 0x1) == 0x0); } -static int -IsSABMX(byte * data, int ext) +inline int +IsSABMX(u_char * data, int ext) { - return (ext ? (data[0] & ~0x10) == SABME : data[0] == 0x3f); + u_char d = data[0] & ~0x10; + + return (ext ? d == SABME : d == SABM); } -static int -IsREJ(byte * data, int ext) +inline int +IsREJ(u_char * data, int ext) { return (ext ? data[0] == REJ : (data[0] & 0xf) == 0x9); } -static int -IsFRMR(byte * data, int ext) +inline int +IsFRMR(u_char * data, int ext) { return ((data[0] & 0xef) == FRMR); } -static int -IsRNR(byte * data, int ext) +inline int +IsRNR(u_char * data, int ext) { if (ext) return (data[0] == RNR); @@ -1251,91 +1112,89 @@ 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}, + {ST_L2_1, EV_L2_MDL_NOTEIPROC, l2_no_tei}, + {ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei}, + {ST_L2_4, EV_L2_DL_UNIT_DATA, l2_send_ui}, + {ST_L2_4, EV_L2_DL_ESTABLISH, l2_establish}, + {ST_L2_7, EV_L2_DL_UNIT_DATA, l2_send_ui}, + {ST_L2_7, EV_L2_DL_DATA, l2_feed_iqueue}, + {ST_L2_7, EV_L2_DL_RELEASE, l2_send_disconn}, + {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue}, + {ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue}, + {ST_L2_8, EV_L2_DL_RELEASE, l2_send_disconn}, + + {ST_L2_1, EV_L2_UI, l2_receive_ui}, + {ST_L2_4, EV_L2_UI, l2_receive_ui}, + {ST_L2_4, EV_L2_SABMX, l2_got_SABMX}, + {ST_L2_4, EV_L2_DISC, l2_got_st4_disc}, + {ST_L2_5, EV_L2_UA, l2_got_ua_establish}, + {ST_L2_6, EV_L2_UA, l2_got_ua_disconn}, + {ST_L2_7, EV_L2_UI, l2_receive_ui}, + {ST_L2_7, EV_L2_DISC, l2_got_disconn}, + {ST_L2_7, EV_L2_I, l2_got_st7_data}, + {ST_L2_7, EV_L2_RR, l2_got_st7_RR}, + {ST_L2_7, EV_L2_REJ, l2_got_st7_rej}, + {ST_L2_7, EV_L2_SABMX, l2_got_SABMX}, + {ST_L2_7, EV_L2_FRMR, l2_got_FRMR}, + {ST_L2_8, EV_L2_RR, l2_got_st8_rr_rej}, + {ST_L2_8, EV_L2_REJ, l2_got_st8_rr_rej}, + {ST_L2_8, EV_L2_SABMX, l2_got_SABMX}, + {ST_L2_8, EV_L2_DISC, l2_got_disconn}, + {ST_L2_8, EV_L2_FRMR, l2_got_FRMR}, + {ST_L2_8, EV_L2_I, l2_got_st8_data}, + + {ST_L2_5, EV_L2_T200, l2_st5_tout_200}, + {ST_L2_6, EV_L2_T200, l2_st6_tout_200}, + {ST_L2_7, EV_L2_T200, l2_st7_tout_200}, + {ST_L2_7, EV_L2_T203, l2_st7_tout_203}, + {ST_L2_8, EV_L2_T200, l2_st8_tout_200}, + + {ST_L2_1, EV_L2_MDL_REMOVE, l2_tei_remove}, + {ST_L2_3, EV_L2_MDL_REMOVE, l2_tei_remove}, + {ST_L2_4, EV_L2_MDL_REMOVE, l2_tei_remove}, + {ST_L2_5, EV_L2_MDL_REMOVE, l2_tei_remove}, + {ST_L2_6, EV_L2_MDL_REMOVE, l2_tei_remove}, + {ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove}, + {ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove}, }; #define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode)) static void -isdnl2_l1l2(struct PStack *st, int pr, struct BufHeader *arg) +isdnl2_l1l2(struct PStack *st, int pr, void *arg) { - struct BufHeader *ibh; - byte *datap; + struct sk_buff *skb = arg; + u_char *datap; int ret = !0; switch (pr) { case (PH_DATA): - - ibh = arg; - datap = DATAPTR(ibh); + datap = skb->data; datap += l2addrsize(&st->l2); if (IsI(datap, st->l2.extended)) - ret = FsmEvent(&st->l2.l2m, EV_L2_I, ibh); + ret = FsmEvent(&st->l2.l2m, EV_L2_I, skb); else if (IsRR(datap, st->l2.extended)) - ret = FsmEvent(&st->l2.l2m, EV_L2_RR, ibh); + ret = FsmEvent(&st->l2.l2m, EV_L2_RR, skb); else if (IsUI(datap, st->l2.extended)) - ret = FsmEvent(&st->l2.l2m, EV_L2_UI, ibh); + ret = FsmEvent(&st->l2.l2m, EV_L2_UI, skb); else if (IsSABMX(datap, st->l2.extended)) - ret = FsmEvent(&st->l2.l2m, EV_L2_SABMX, ibh); + ret = FsmEvent(&st->l2.l2m, EV_L2_SABMX, skb); else if (IsUA(datap, st->l2.extended)) - ret = FsmEvent(&st->l2.l2m, EV_L2_UA, ibh); + ret = FsmEvent(&st->l2.l2m, EV_L2_UA, skb); else if (IsDISC(datap, st->l2.extended)) - ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, ibh); + ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, skb); else if (IsREJ(datap, st->l2.extended)) - ret = FsmEvent(&st->l2.l2m, EV_L2_REJ, ibh); + ret = FsmEvent(&st->l2.l2m, EV_L2_REJ, skb); else if (IsFRMR(datap, st->l2.extended)) - ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, ibh); + ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, skb); else if (IsRNR(datap, st->l2.extended)) - ret = FsmEvent(&st->l2.l2m, EV_L2_RNR, ibh); - - if (ret) - BufPoolRelease(ibh); + ret = FsmEvent(&st->l2.l2m, EV_L2_RNR, skb); + if (ret) { + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); + } break; case (PH_PULL_ACK): FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg); @@ -1344,24 +1203,26 @@ } static void -isdnl2_l3l2(struct PStack *st, int pr, - void *arg) +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); + if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg)) { + SET_SKB_FREE(((struct sk_buff *) arg)); + dev_kfree_skb((struct sk_buff *) arg, FREE_READ); + } break; case (DL_UNIT_DATA): - if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg)) - BufPoolRelease((struct BufHeader *) arg); + if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg)) { + SET_SKB_FREE(((struct sk_buff *) arg)); + dev_kfree_skb((struct sk_buff *) arg, FREE_READ); + } break; } } static void -isdnl2_manl2(struct PStack *st, int pr, - void *arg) +isdnl2_manl2(struct PStack *st, int pr, void *arg) { switch (pr) { case (DL_ESTABLISH): @@ -1380,8 +1241,7 @@ } static void -isdnl2_teil2(struct PStack *st, int pr, - void *arg) +isdnl2_teil2(struct PStack *st, int pr, void *arg) { switch (pr) { case (MDL_ASSIGN): @@ -1398,6 +1258,8 @@ { FsmDelTimer(&st->l2.t200_timer, 15); FsmDelTimer(&st->l2.t203_timer, 16); + discard_i_queue(st); + ReleaseWin(&st->l2); } static void @@ -1421,7 +1283,8 @@ st->l2.uihsize = l2headersize(&st->l2, !0); st->l2.ihsize = l2headersize(&st->l2, 0); - BufQueueInit(&(st->l2.i_queue)); + skb_queue_head_init(&st->l2.i_queue); + InitWin(&st->l2); st->l2.rejexp = 0; st->l2.debug = 0; diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/isdnl2.h linux/drivers/isdn/hisax/isdnl2.h --- v2.1.41/linux/drivers/isdn/hisax/isdnl2.h Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/isdnl2.h Wed May 28 10:49:09 1997 @@ -4,6 +4,7 @@ #define RNR 0x05 #define REJ 0x09 #define SABME 0x6f +#define SABM 0x2f #define DM 0x0f #define UI 0x03 #define DISC 0x43 diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/isdnl3.c linux/drivers/isdn/hisax/isdnl3.c --- v2.1.41/linux/drivers/isdn/hisax/isdnl3.c Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/isdnl3.c Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: isdnl3.c,v 1.6 1997/02/16 01:04:08 fritz Exp $ +/* $Id: isdnl3.c,v 1.10 1997/04/06 22:54:16 keil Exp $ * Author Karsten Keil (keil@temic-ech.spacenet.de) * based on the teles driver from Jan den Ouden @@ -7,6 +7,18 @@ * Fritz Elfert * * $Log: isdnl3.c,v $ + * Revision 1.10 1997/04/06 22:54:16 keil + * Using SKB's + * + * Revision 1.9 1997/03/25 23:11:25 keil + * US NI-1 protocol + * + * Revision 1.8 1997/03/21 18:53:44 keil + * Report no protocol error to syslog too + * + * Revision 1.7 1997/03/17 18:34:38 keil + * fixed oops if no protocol selected during config + * * Revision 1.6 1997/02/16 01:04:08 fritz * Bugfix: Changed timer handling caused hang with 2.1.X * @@ -34,7 +46,7 @@ #include "isdnl3.h" #include -const char *l3_revision = "$Revision: 1.6 $"; +const char *l3_revision = "$Revision: 1.10 $"; void l3_debug(struct PStack *st, char *s) @@ -102,20 +114,39 @@ L3DelTimer(&st->l3.timer); } +struct sk_buff * +l3_alloc_skb(int len) +{ + struct sk_buff *skb; + + if (!(skb = alloc_skb(len + MAX_HEADER_LEN, GFP_ATOMIC))) { + printk(KERN_WARNING "HiSax: No skb for D-channel\n"); + return (NULL); + } + skb_reserve(skb, MAX_HEADER_LEN); + return (skb); +} + static void no_l3_proto(struct PStack *st, int pr, void *arg) { - struct BufHeader *ibh = arg; + struct sk_buff *skb = arg; l3_debug(st, "no protocol"); - if (ibh) - BufPoolRelease(ibh); + if (skb) { + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); + } } #ifdef CONFIG_HISAX_EURO extern void setstack_dss1(struct PStack *st); #endif +#ifdef CONFIG_HISAX_NI1 +extern void setstack_ni1(struct PStack *st); +#endif + #ifdef CONFIG_HISAX_1TR6 extern void setstack_1tr6(struct PStack *st); #endif @@ -134,6 +165,11 @@ setstack_dss1(st); } else #endif +#ifdef CONFIG_HISAX_NI1 + if (st->protocol == ISDN_PTYPE_NI1) { + setstack_ni1(st); + } else +#endif #ifdef CONFIG_HISAX_1TR6 if (st->protocol == ISDN_PTYPE_1TR6) { setstack_1tr6(st); @@ -144,10 +180,14 @@ st->l2.l2l3 = no_l3_proto; printk(KERN_NOTICE "HiSax: Leased line mode\n"); } else { + st->l4.l4l3 = no_l3_proto; + st->l2.l2l3 = no_l3_proto; sprintf(tmp, "protocol %s not supported", (st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" : (st->protocol == ISDN_PTYPE_EURO) ? "euro" : + (st->protocol == ISDN_PTYPE_NI1) ? "ni1" : "unknown"); + printk(KERN_WARNING "HiSax: %s\n", tmp); l3_debug(st, tmp); st->protocol = -1; } diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/isdnl3.h linux/drivers/isdn/hisax/isdnl3.h --- v2.1.41/linux/drivers/isdn/hisax/isdnl3.h Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/isdnl3.h Wed May 28 10:49:09 1997 @@ -1,6 +1,9 @@ -/* $Id: isdnl3.h,v 1.2 1997/01/21 22:31:28 keil Exp $ +/* $Id: isdnl3.h,v 1.3 1997/04/06 22:54:17 keil Exp $ * * $Log: isdnl3.h,v $ + * Revision 1.3 1997/04/06 22:54:17 keil + * Using SKB's + * * Revision 1.2 1997/01/21 22:31:28 keil * new statemachine; L3 timers * @@ -21,9 +24,9 @@ #define L3_DEB_CHARGE 0x08 struct stateentry { - int state; - byte primitive; - void (*rout) (struct PStack *, byte, void *); + int state; + u_char primitive; + void (*rout) (struct PStack *, u_char, void *); }; extern void l3_debug(struct PStack *st, char *s); @@ -32,3 +35,4 @@ extern void L3DelTimer(struct L3Timer *t); extern int L3AddTimer(struct L3Timer *t, int millisec, int event); extern void StopAllL3Timer(struct PStack *st); +extern struct sk_buff *l3_alloc_skb(int len); diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/ix1_micro.c linux/drivers/isdn/hisax/ix1_micro.c --- v2.1.41/linux/drivers/isdn/hisax/ix1_micro.c Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/ix1_micro.c Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: ix1_micro.c,v 1.1 1997/01/27 15:43:10 keil Exp $ +/* $Id: ix1_micro.c,v 1.3 1997/04/13 19:54:02 keil Exp $ * ix1_micro.c low level stuff for ITK ix1-micro Rev.2 isdn cards * derived from the original file teles3.c from Karsten Keil @@ -11,6 +11,12 @@ * Beat Doebeli * * $Log: ix1_micro.c,v $ + * Revision 1.3 1997/04/13 19:54:02 keil + * Change in IRQ check delay for SMP + * + * Revision 1.2 1997/04/06 22:54:21 keil + * Using SKB's + * * Revision 1.1 1997/01/27 15:43:10 keil * first version * @@ -55,7 +61,7 @@ #include extern const char *CardType[]; -const char *ix1_revision = "$Revision: 1.1 $"; +const char *ix1_revision = "$Revision: 1.3 $"; #define byteout(addr,val) outb_p(val,addr) #define bytein(addr) inb_p(addr) @@ -72,15 +78,15 @@ #define TIMEOUT 50 -static inline byte -IsacReadReg(unsigned int adr, byte off) +static inline u_char +IsacReadReg(unsigned int adr, u_char 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) +IsacWriteReg(unsigned int adr, u_char off, u_char data) { byteout(adr + ISAC_COMMAND_OFFSET, off + 0x20); byteout(adr + ISAC_DATA_OFFSET, data); @@ -89,15 +95,15 @@ #define HSCX_OFFSET(WhichHscx,offset) \ ( (WhichHscx) ? (offset+0x60) : (offset+0x20) ) -static inline byte -HscxReadReg(unsigned int adr, int WhichHscx, byte off) +static inline u_char +HscxReadReg(unsigned int adr, int WhichHscx, u_char 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) +HscxWriteReg(unsigned int adr, int WhichHscx, u_char off, u_char data) { byteout(adr + HSCX_COMMAND_OFFSET, HSCX_OFFSET(WhichHscx, off)); byteout(adr + HSCX_DATA_OFFSET, data); @@ -105,7 +111,7 @@ static inline void -IsacReadFifo(unsigned int adr, byte * data, int size) +IsacReadFifo(unsigned int adr, u_char * data, int size) { byteout(adr + ISAC_COMMAND_OFFSET, 0); while (size--) @@ -113,7 +119,7 @@ } static void -IsacWriteFifo(unsigned int adr, byte * data, int size) +IsacWriteFifo(unsigned int adr, u_char * data, int size) { byteout(adr + ISAC_COMMAND_OFFSET, 0); while (size--) { @@ -123,7 +129,7 @@ } static inline void -HscxReadFifo(unsigned int adr, int WhichHscx, byte * data, int size) +HscxReadFifo(unsigned int adr, int WhichHscx, u_char * data, int size) { byteout(adr + HSCX_COMMAND_OFFSET, (WhichHscx) ? 0x40 : 0x00); while (size--) @@ -131,7 +137,7 @@ } static void -HscxWriteFifo(unsigned int adr, int WhichHscx, byte * data, int size) +HscxWriteFifo(unsigned int adr, int WhichHscx, u_char * data, int size) { byteout(adr + HSCX_COMMAND_OFFSET, (WhichHscx) ? 0x40 : 0x00); while (size--) { @@ -168,7 +174,7 @@ } static inline void -writehscxCMDR(int adr, int WhichHscx, byte data) +writehscxCMDR(int adr, int WhichHscx, u_char data) { long flags; @@ -210,25 +216,22 @@ static void hscx_empty_fifo(struct HscxState *hsp, int count) { - byte *ptr; + u_char *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 (hsp->rcvidx + count > HSCX_BUFMAX) { if (sp->debug & L1_DEB_WARN) debugl1(sp, "hscx_empty_fifo: incoming packet too large"); writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x80); + hsp->rcvidx = 0; return; } - ptr = DATAPTR(ibh); - ptr += hsp->rcvptr; - - hsp->rcvptr += count; + ptr = hsp->rcvbuf + hsp->rcvidx; + hsp->rcvidx += count; save_flags(flags); cli(); HscxReadFifo(sp->hscx[hsp->hscx], hsp->hscx, ptr, count); @@ -249,34 +252,32 @@ hscx_fill_fifo(struct HscxState *hsp) { struct IsdnCardState *sp = hsp->sp; - struct BufHeader *ibh; int more, count; - byte *ptr; + u_char *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) + if (!hsp->tx_skb) return; - - count = ibh->datasize - hsp->sendptr; - if (count <= 0) + if (hsp->tx_skb->len <= 0) return; more = (hsp->mode == 1) ? 1 : 0; - if (count > 32) { + if (hsp->tx_skb->len > 32) { more = !0; count = 32; - } - ptr = DATAPTR(ibh); - ptr += hsp->sendptr; - hsp->sendptr += count; + } else + count = hsp->tx_skb->len; waitforXFW(sp->hscx[hsp->hscx], hsp->hscx); save_flags(flags); cli(); + ptr = hsp->tx_skb->data; + skb_pull(hsp->tx_skb, count); + hsp->tx_cnt -= count; + hsp->count += count; HscxWriteFifo(sp->hscx[hsp->hscx], hsp->hscx, ptr, count); writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, more ? 0x8 : 0xa); restore_flags(flags); @@ -292,11 +293,12 @@ } static inline void -hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx) +hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx) { - byte r; + u_char r; struct HscxState *hsp = sp->hs + hscx; - int count, err; + struct sk_buff *skb; + int count; char tmp[32]; if (!hsp->init) @@ -318,79 +320,61 @@ 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; + } else { + count = HscxReadReg(sp->hscx[hsp->hscx], hscx, HSCX_RBCL) & 0x1f; + if (count == 0) + count = 32; + hscx_empty_fifo(hsp, count); + if ((count = hsp->rcvidx - 1) > 0) { + if (sp->debug & L1_DEB_HSCX_FIFO) { + sprintf(tmp, "HX Frame %d", count); + debugl1(sp, tmp); + } + if (!(skb = dev_alloc_skb(count))) + printk(KERN_WARNING "IX1: receive out of memory\n"); + else { + memcpy(skb_put(skb, count), hsp->rcvbuf, count); + skb_queue_tail(&hsp->rqueue, skb); + } + } } - 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; + hsp->rcvidx = 0; 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; + if (!(skb = dev_alloc_skb(32))) + printk(KERN_WARNING "IX1: receive out of memory\n"); + else { + memcpy(skb_put(skb, 32), hsp->rcvbuf, 32); + skb_queue_tail(&hsp->rqueue, skb); + } + hsp->rcvidx = 0; hscx_sched_event(hsp, HSCX_RCVBUFREADY); } } - afterRPF: if (val & 0x10) { /* XPR */ - if (hsp->xmtibh) - if (hsp->xmtibh->datasize > hsp->sendptr) { + if (hsp->tx_skb) + if (hsp->tx_skb->len) { hscx_fill_fifo(hsp); - goto afterXPR; + return; } else { - if (hsp->releasebuf) - BufPoolRelease(hsp->xmtibh); - hsp->sendptr = 0; + SET_SKB_FREE(hsp->tx_skb); + dev_kfree_skb(hsp->tx_skb, FREE_WRITE); + hsp->count = 0; if (hsp->st->l4.l1writewakeup) hsp->st->l4.l1writewakeup(hsp->st); - hsp->xmtibh = NULL; + hsp->tx_skb = NULL; } - if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) { - hsp->releasebuf = !0; + if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) { + hsp->count = 0; hscx_fill_fifo(hsp); } else hscx_sched_event(hsp, HSCX_XMTBUFREADY); } - afterXPR: } /* @@ -400,26 +384,26 @@ static void isac_empty_fifo(struct IsdnCardState *sp, int count) { - byte *ptr; - struct BufHeader *ibh = sp->rcvibh; + u_char *ptr; 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->rcvidx + count) >= MAX_DFRAME_LEN) { if (sp->debug & L1_DEB_WARN) { char tmp[40]; - sprintf(tmp, "isac_empty_fifo rcvptr %d", sp->rcvptr); + sprintf(tmp, "isac_empty_fifo overrun %d", + sp->rcvidx + count); debugl1(sp, tmp); } + IsacWriteReg(sp->isac, ISAC_CMDR, 0x80); + sp->rcvidx = 0; return; } - ptr = DATAPTR(ibh); - ptr += sp->rcvptr; - sp->rcvptr += count; - + ptr = sp->rcvbuf + sp->rcvidx; + sp->rcvidx += count; save_flags(flags); cli(); IsacReadFifo(sp->isac, ptr, count); @@ -438,35 +422,30 @@ static void isac_fill_fifo(struct IsdnCardState *sp) { - struct BufHeader *ibh; int count, more; - byte *ptr; + u_char *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) + if (!sp->tx_skb) return; - count = ibh->datasize - sp->sendptr; + count = sp->tx_skb->len; 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(); + ptr = sp->tx_skb->data; + skb_pull(sp->tx_skb, count); + sp->tx_cnt += count; IsacWriteFifo(sp->isac, ptr, count); IsacWriteReg(sp->isac, ISAC_CMDR, more ? 0x8 : 0xa); restore_flags(flags); @@ -493,9 +472,10 @@ static inline void -isac_interrupt(struct IsdnCardState *sp, byte val) +isac_interrupt(struct IsdnCardState *sp, u_char val) { - byte exval; + u_char exval; + struct sk_buff *skb; unsigned int count; char tmp[32]; @@ -512,62 +492,46 @@ 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; + } else { + count = IsacReadReg(sp->isac, ISAC_RBCL) & 0x1f; + if (count == 0) + count = 32; + isac_empty_fifo(sp, count); + if ((count = sp->rcvidx) > 0) { + sp->rcvidx = 0; + if (!(skb = alloc_skb(count, GFP_ATOMIC))) + printk(KERN_WARNING "IX1: D receive out of memory\n"); + else { + memcpy(skb_put(skb, count), sp->rcvbuf, count); + skb_queue_tail(&sp->rq, skb); + } + } } - 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; + sp->rcvidx = 0; 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) { + if (sp->tx_skb) + if (sp->tx_skb->len) { isac_fill_fifo(sp); goto afterXPR; } else { - if (sp->releasebuf) - BufPoolRelease(sp->xmtibh); - sp->xmtibh = NULL; - sp->sendptr = 0; + SET_SKB_FREE(sp->tx_skb); + dev_kfree_skb(sp->tx_skb, FREE_WRITE); + sp->tx_cnt = 0; + sp->tx_skb = NULL; } - if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) { - sp->releasebuf = !0; + if ((sp->tx_skb = skb_dequeue(&sp->sq))) { + sp->tx_cnt = 0; isac_fill_fifo(sp); } else isac_sched_event(sp, ISAC_XMTBUFREADY); @@ -597,10 +561,10 @@ } static inline void -hscx_int_main(struct IsdnCardState *sp, byte val) +hscx_int_main(struct IsdnCardState *sp, u_char val) { - byte exval; + u_char exval; struct HscxState *hsp; char tmp[32]; @@ -615,7 +579,11 @@ /* Here we lost an TX interrupt, so * restart transmitting the whole frame. */ - hsp->sendptr = 0; + if (hsp->tx_skb) { + skb_push(hsp->tx_skb, hsp->count); + hsp->tx_cnt += hsp->count; + hsp->count = 0; + } writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x01); if (sp->debug & L1_DEB_WARN) { sprintf(tmp, "HSCX B EXIR %x Lost TX", exval); @@ -644,7 +612,11 @@ /* Here we lost an TX interrupt, so * restart transmitting the whole frame. */ - hsp->sendptr = 0; + if (hsp->tx_skb) { + skb_push(hsp->tx_skb, hsp->count); + hsp->tx_cnt += hsp->count; + hsp->count = 0; + } writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x01); if (sp->debug & L1_DEB_WARN) { sprintf(tmp, "HSCX A EXIR %x Lost TX", exval); @@ -670,7 +642,7 @@ ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *sp; - byte val, stat = 0; + u_char val, stat = 0; sp = (struct IsdnCardState *) irq2dev_map[intno]; @@ -757,48 +729,48 @@ 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 { + case 0: 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_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, 0x8c); - HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CMDR, 0x41); - break; + 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); } @@ -866,6 +838,7 @@ initix1micro(struct IsdnCardState *sp) { int ret; + int loop = 0; char tmp[40]; sp->counter = kstat.interrupts[sp->irq]; @@ -877,6 +850,16 @@ initisac(sp); sp->modehscx(sp->hs, 0, 0); sp->modehscx(sp->hs + 1, 0, 0); + while (loop++ < 10) { + /* At least 1-3 irqs must happen + * (one from HSCX A, one from HSCX B, 3rd from ISAC) + */ + if (kstat.interrupts[sp->irq] > sp->counter) + break; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + 1; + schedule(); + } sprintf(tmp, "IRQ %d count %d", sp->irq, kstat.interrupts[sp->irq]); debugl1(sp, tmp); @@ -895,7 +878,7 @@ int setup_ix1micro(struct IsdnCard *card) { - byte val, verA, verB; + u_char val, verA, verB; struct IsdnCardState *sp = card->sp; long flags; char tmp[64]; diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/l3_1tr6.c linux/drivers/isdn/hisax/l3_1tr6.c --- v2.1.41/linux/drivers/isdn/hisax/l3_1tr6.c Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/l3_1tr6.c Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: l3_1tr6.c,v 1.9 1997/02/11 01:37:40 keil Exp $ +/* $Id: l3_1tr6.c,v 1.11 1997/04/06 22:54:18 keil Exp $ * German 1TR6 D-channel protocol * @@ -6,6 +6,12 @@ * * * $Log: l3_1tr6.c,v $ + * Revision 1.11 1997/04/06 22:54:18 keil + * Using SKB's + * + * Revision 1.10 1997/03/13 20:37:58 keil + * channel request added + * * Revision 1.9 1997/02/11 01:37:40 keil * Changed setup-interface (incoming and outgoing) * @@ -40,9 +46,10 @@ #include "hisax.h" #include "l3_1tr6.h" #include "isdnl3.h" +#include extern char *HiSax_getrev(const char *revision); -const char *l3_1tr6_revision = "$Revision: 1.9 $"; +const char *l3_1tr6_revision = "$Revision: 1.11 $"; #define MsgHead(ptr, cref, mty, dis) \ *ptr++ = dis; \ @@ -51,36 +58,63 @@ *ptr++ = mty static void -l3_1TR6_message(struct PStack *st, byte mt, byte pd) +l3_1TR6_message(struct PStack *st, u_char mt, u_char pd) { - struct BufHeader *dibh; - byte *p; - - BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18); - p = DATAPTR(dibh); - p += st->l2.ihsize; + struct sk_buff *skb; + u_char *p; + if (!(skb = l3_alloc_skb(4))) + return; + p = skb_put(skb, 4); MsgHead(p, st->l3.callref, mt, pd); - - dibh->datasize = p - DATAPTR(dibh); - st->l3.l3l2(st, DL_DATA, dibh); + st->l3.l3l2(st, DL_DATA, skb); } static void -l3_1tr6_setup_req(struct PStack *st, byte pr, void *arg) +l3_1tr6_setup_req(struct PStack *st, u_char pr, void *arg) { - struct BufHeader *dibh; - byte *p; - char *teln; + struct sk_buff *skb; + u_char tmp[128]; + u_char *p = tmp; + u_char *teln; + u_char *eaz; + u_char channel = 0; + int l; - st->l3.callref = st->pa->callref; - BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19); - p = DATAPTR(dibh); - p += st->l2.ihsize; + st->l3.callref = st->pa->callref; MsgHead(p, st->l3.callref, MT_N1_SETUP, PROTO_DIS_N1); - if ('S' == (st->pa->setup.phone[0] & 0x5f)) { /* SPV ? */ + teln = st->pa->setup.phone; + st->pa->spv = 0; + if (!isdigit(*teln)) { + switch (0x5f & *teln) { + case 'S': + st->pa->spv = 1; + break; + case 'C': + channel = 0x08; + case 'P': + channel |= 0x80; + teln++; + if (*teln == '1') + channel |= 0x01; + else + channel |= 0x02; + break; + default: + if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "Wrong MSN Code"); + break; + } + teln++; + } + if (channel) { + *p++ = 0x18; /* channel indicator */ + *p++ = 1; + *p++ = channel; + } + if (st->pa->spv) { /* SPV ? */ /* NSF SPV */ *p++ = WE0_netSpecFac; *p++ = 4; /* Laenge */ @@ -95,25 +129,17 @@ *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') { + eaz = st->pa->setup.eazmsn; + if (*eaz) { *p++ = WE0_origAddr; - *p++ = strlen(st->pa->setup.eazmsn) + 1; + *p++ = strlen(eaz) + 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; + while (*eaz) + *p++ = *eaz++ & 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; - } + *p++ = strlen(teln) + 1; /* Classify as AnyPref. */ *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ while (*teln) @@ -126,67 +152,64 @@ *p++ = st->pa->setup.si1; *p++ = st->pa->setup.si2; - dibh->datasize = p - DATAPTR(dibh); - + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); L3DelTimer(&st->l3.timer); L3AddTimer(&st->l3.timer, st->l3.t303, CC_T303); newl3state(st, 1); - st->l3.l3l2(st, DL_DATA, dibh); + st->l3.l3l2(st, DL_DATA, skb); } static void -l3_1tr6_setup(struct PStack *st, byte pr, void *arg) +l3_1tr6_setup(struct PStack *st, u_char pr, void *arg) { - byte *p; + u_char *p; int bcfound = 0; char tmp[80]; - struct BufHeader *ibh = arg; + struct sk_buff *skb = arg; - p = DATAPTR(ibh); - p += st->l2.uihsize; + p = skb->data; 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))) { + p = skb->data; + if ((p = findie(p, skb->len, 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))) { + p = skb->data; + if ((p = findie(p, skb->len, 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))) + p = skb->data; + if ((p = findie(p, skb->len, 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))) { + p = skb->data; + if ((p = findie(p, skb->len, WE0_origAddr, 0))) { iecpy(st->pa->setup.phone, p, 1); } else st->pa->setup.phone[0] = 0; - p = DATAPTR(ibh); + p = skb->data; st->pa->spv = 0; - if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, - WE0_netSpecFac, 0))) { + if ((p = findie(p, skb->len, WE0_netSpecFac, 0))) { if ((FAC_SPV == p[3]) || (FAC_Activate == p[3])) st->pa->spv = 1; } - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); /* Signal all services, linklevel takes care of Service-Indicator */ if (bcfound) { @@ -202,67 +225,65 @@ } static void -l3_1tr6_setup_ack(struct PStack *st, byte pr, void *arg) +l3_1tr6_setup_ack(struct PStack *st, u_char pr, void *arg) { - byte *p; - struct BufHeader *ibh = arg; + u_char *p; + struct sk_buff *skb = arg; L3DelTimer(&st->l3.timer); + p = skb->data; newl3state(st, 2); - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, - WE0_chanID, 0))) { + if ((p = findie(p, skb->len, 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); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); 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) +l3_1tr6_call_sent(struct PStack *st, u_char pr, void *arg) { - byte *p; - struct BufHeader *ibh = arg; + u_char *p; + struct sk_buff *skb = arg; L3DelTimer(&st->l3.timer); - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, - WE0_chanID, 0))) { + p = skb->data; + if ((p = findie(p, skb->len, 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); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); 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) +l3_1tr6_alert(struct PStack *st, u_char pr, void *arg) { - struct BufHeader *ibh = arg; + struct sk_buff *skb = arg; - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); 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) +l3_1tr6_info(struct PStack *st, u_char pr, void *arg) { - byte *p; + u_char *p; int i, tmpcharge = 0; char a_charge[8], tmp[32]; - struct BufHeader *ibh = arg; + struct sk_buff *skb = arg; - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, - WE6_chargingInfo, 6))) { + p = skb->data; + if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) { iecpy(a_charge, p, 1); for (i = 0; i < strlen(a_charge); i++) { tmpcharge *= 10; @@ -278,39 +299,41 @@ } } else if (st->l3.debug & L3_DEB_CHARGE) l3_debug(st, "charging info not found"); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); - BufPoolRelease(ibh); } static void -l3_1tr6_info_s2(struct PStack *st, byte pr, void *arg) +l3_1tr6_info_s2(struct PStack *st, u_char pr, void *arg) { - struct BufHeader *ibh = arg; + struct sk_buff *skb = arg; - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); } static void -l3_1tr6_connect(struct PStack *st, byte pr, void *arg) +l3_1tr6_connect(struct PStack *st, u_char pr, void *arg) { - struct BufHeader *ibh = arg; + struct sk_buff *skb = arg; L3DelTimer(&st->l3.timer); /* T310 */ newl3state(st, 10); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); 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) +l3_1tr6_rel(struct PStack *st, u_char 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))) { + struct sk_buff *skb = arg; + u_char *p; + + p = skb->data; + if ((p = findie(p, skb->len, WE0_cause, 0))) { if (p[1] > 0) { st->pa->cause = p[2]; if (p[1] > 1) @@ -321,9 +344,10 @@ st->pa->cause = 0; st->pa->loc = 0; } - } else + } else st->pa->cause = -1; - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); StopAllL3Timer(st); newl3state(st, 0); l3_1TR6_message(st, MT_N1_REL_ACK, PROTO_DIS_N1); @@ -331,11 +355,12 @@ } static void -l3_1tr6_rel_ack(struct PStack *st, byte pr, void *arg) +l3_1tr6_rel_ack(struct PStack *st, u_char pr, void *arg) { - struct BufHeader *ibh = arg; + struct sk_buff *skb = arg; - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); StopAllL3Timer(st); newl3state(st, 0); st->pa->cause = -1; @@ -343,17 +368,16 @@ } static void -l3_1tr6_disc(struct PStack *st, byte pr, void *arg) +l3_1tr6_disc(struct PStack *st, u_char pr, void *arg) { - struct BufHeader *ibh = arg; - byte *p; + struct sk_buff *skb = arg; + u_char *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))) { + p = skb->data; + if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) { iecpy(a_charge, p, 1); for (i = 0; i < strlen(a_charge); i++) { tmpcharge *= 10; @@ -371,9 +395,8 @@ 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))) { + p = skb->data; + if ((p = findie(p, skb->len, WE0_cause, 0))) { if (p[1] > 0) { st->pa->cause = p[2]; if (p[1] > 1) @@ -389,18 +412,20 @@ l3_debug(st, "cause not found"); st->pa->cause = -1; } - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); newl3state(st, 12); st->l3.l3l4(st, CC_DISCONNECT_IND, NULL); } static void -l3_1tr6_connect_ack(struct PStack *st, byte pr, void *arg) +l3_1tr6_connect_ack(struct PStack *st, u_char pr, void *arg) { - struct BufHeader *ibh = arg; + struct sk_buff *skb = arg; - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); newl3state(st, 10); st->pa->chargeinfo = 0; L3DelTimer(&st->l3.timer); @@ -408,23 +433,20 @@ } static void -l3_1tr6_alert_req(struct PStack *st, byte pr, - void *arg) +l3_1tr6_alert_req(struct PStack *st, u_char 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) +l3_1tr6_setup_rsp(struct PStack *st, u_char pr, void *arg) { - struct BufHeader *dibh; - byte *p; + struct sk_buff *skb; + u_char tmp[24]; + u_char *p = tmp; + int l; - 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 */ @@ -442,54 +464,59 @@ *p++ = st->pa->setup.si2; } newl3state(st, 8); - dibh->datasize = p - DATAPTR(dibh); - st->l3.l3l2(st, DL_DATA, dibh); + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + st->l3.l3l2(st, DL_DATA, skb); 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) +l3_1tr6_reset(struct PStack *st, u_char pr, void *arg) { newl3state(st, 0); } static void -l3_1tr6_disconnect_req(struct PStack *st, byte pr, void *arg) +l3_1tr6_disconnect_req(struct PStack *st, u_char pr, void *arg) { - struct BufHeader *dibh; - byte *p; - byte cause = 0x10; - byte clen = 1; + struct sk_buff *skb; + u_char tmp[16]; + u_char *p = tmp; + int l; + u_char cause = 0x10; + u_char 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; + 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); + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + st->l3.l3l2(st, DL_DATA, skb); L3AddTimer(&st->l3.timer, st->l3.t305, CC_T305); } static void -l3_1tr6_release_req(struct PStack *st, byte pr, void *arg) +l3_1tr6_release_req(struct PStack *st, u_char pr, void *arg) { StopAllL3Timer(st); newl3state(st, 19); @@ -498,7 +525,7 @@ } static void -l3_1tr6_t303(struct PStack *st, byte pr, void *arg) +l3_1tr6_t303(struct PStack *st, u_char pr, void *arg) { if (st->l3.n_t303 > 0) { st->l3.n_t303--; @@ -513,7 +540,7 @@ } static void -l3_1tr6_t304(struct PStack *st, byte pr, void *arg) +l3_1tr6_t304(struct PStack *st, u_char pr, void *arg) { L3DelTimer(&st->l3.timer); st->pa->cause = 0xE6; @@ -523,41 +550,43 @@ } static void -l3_1tr6_t305(struct PStack *st, byte pr, void *arg) +l3_1tr6_t305(struct PStack *st, u_char pr, void *arg) { - struct BufHeader *dibh; - byte *p; - byte cause = 0x90; - byte clen = 1; + struct sk_buff *skb; + u_char tmp[16]; + u_char *p = tmp; + int l; + u_char cause = 0x90; + u_char 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; + case 0x10: + clen = 0; + break; + case 0x15: + cause = CAUSE_CallRejected; + break; + } 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); + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + st->l3.l3l2(st, DL_DATA, skb); L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_1); } static void -l3_1tr6_t310(struct PStack *st, byte pr, void *arg) +l3_1tr6_t310(struct PStack *st, u_char pr, void *arg) { L3DelTimer(&st->l3.timer); st->pa->cause = 0xE6; @@ -566,7 +595,7 @@ } static void -l3_1tr6_t313(struct PStack *st, byte pr, void *arg) +l3_1tr6_t313(struct PStack *st, u_char pr, void *arg) { L3DelTimer(&st->l3.timer); st->pa->cause = 0xE6; @@ -575,7 +604,7 @@ } static void -l3_1tr6_t308_1(struct PStack *st, byte pr, void *arg) +l3_1tr6_t308_1(struct PStack *st, u_char pr, void *arg) { L3DelTimer(&st->l3.timer); l3_1TR6_message(st, MT_N1_REL, PROTO_DIS_N1); @@ -584,13 +613,13 @@ } static void -l3_1tr6_t308_2(struct PStack *st, byte pr, void *arg) +l3_1tr6_t308_2(struct PStack *st, u_char pr, void *arg) { L3DelTimer(&st->l3.timer); st->l3.l3l4(st, CC_RELEASE_ERR, NULL); newl3state(st, 0); } - +/* *INDENT-OFF* */ static struct stateentry downstl[] = { {SBIT(0), @@ -637,8 +666,8 @@ 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(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), @@ -649,70 +678,55 @@ 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(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} }; +/* *INDENT-ON* */ + static int datastln1_len = sizeof(datastln1) / sizeof(struct stateentry); static void -up1tr6(struct PStack *st, - int pr, void *arg) +up1tr6(struct PStack *st, int pr, void *arg) { - int i, mt, size; - byte *ptr; - struct BufHeader *ibh = arg; + int i, mt; + struct sk_buff *skb = 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 ((skb->data[0] & 0xfe) != PROTO_DIS_N0) { if (st->l3.debug & L3_DEB_PROTERR) { - sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %d state %d", + sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %ld state %d", (pr == DL_DATA) ? " " : "(broadcast) ", - ptr[0], size, st->l3.state); + skb->data[0], skb->len, st->l3.state); l3_debug(st, tmp); } - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); return; } - mt = ptr[3]; - - if (ptr[0] == PROTO_DIS_N0) { - BufPoolRelease(ibh); + mt = skb->data[skb->data[1] + 2]; + if (skb->data[0] == PROTO_DIS_N0) { + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); 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) { + } else if (skb->data[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); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); if (st->l3.debug & L3_DEB_STATE) { sprintf(tmp, "up1tr6%sstate %d mt %x unhandled", (pr == DL_DATA) ? " " : "(broadcast) ", @@ -727,17 +741,15 @@ st->l3.state, mt); l3_debug(st, tmp); } - datastln1[i].rout(st, pr, ibh); + datastln1[i].rout(st, pr, skb); } } } static void -down1tr6(struct PStack *st, - int pr, void *arg) +down1tr6(struct PStack *st, int pr, void *arg) { int i; - struct BufHeader *ibh = arg; char tmp[80]; for (i = 0; i < downstl_len; i++) @@ -756,7 +768,7 @@ st->l3.state, pr); l3_debug(st, tmp); } - downstl[i].rout(st, pr, ibh); + downstl[i].rout(st, pr, arg); } } diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/l3dss1.c linux/drivers/isdn/hisax/l3dss1.c --- v2.1.41/linux/drivers/isdn/hisax/l3dss1.c Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/l3dss1.c Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: l3dss1.c,v 1.12 1997/02/17 00:34:26 keil Exp $ +/* $Id: l3dss1.c,v 1.15 1997/04/17 11:50:48 keil Exp $ * EURO/DSS1 D-channel protocol * @@ -9,6 +9,15 @@ * Fritz Elfert * * $Log: l3dss1.c,v $ + * Revision 1.15 1997/04/17 11:50:48 keil + * pa->loc was undefined, if it was not send by the exchange + * + * Revision 1.14 1997/04/06 22:54:20 keil + * Using SKB's + * + * Revision 1.13 1997/03/13 20:37:28 keil + * CLIR and channel request added + * * Revision 1.12 1997/02/17 00:34:26 keil * Bugfix: Wrong cause delivered * @@ -52,9 +61,10 @@ #define __NO_VERSION__ #include "hisax.h" #include "isdnl3.h" +#include extern char *HiSax_getrev(const char *revision); -const char *dss1_revision = "$Revision: 1.12 $"; +const char *dss1_revision = "$Revision: 1.15 $"; #define MsgHead(ptr, cref, mty) \ *ptr++ = 0x8; \ @@ -63,23 +73,20 @@ *ptr++ = mty static void -l3dss1_message(struct PStack *st, byte mt) +l3dss1_message(struct PStack *st, u_char mt) { - struct BufHeader *dibh; - byte *p; - - BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18); - p = DATAPTR(dibh); - p += st->l2.ihsize; + struct sk_buff *skb; + u_char *p; + if (!(skb = l3_alloc_skb(4))) + return; + p = skb_put(skb, 4); MsgHead(p, st->l3.callref, mt); - - dibh->datasize = p - DATAPTR(dibh); - st->l3.l3l2(st, DL_DATA, dibh); + st->l3.l3l2(st, DL_DATA, skb); } static void -l3dss1_release_req(struct PStack *st, byte pr, void *arg) +l3dss1_release_req(struct PStack *st, u_char pr, void *arg) { StopAllL3Timer(st); newl3state(st, 19); @@ -88,21 +95,22 @@ } static void -l3dss1_release_cmpl(struct PStack *st, byte pr, void *arg) +l3dss1_release_cmpl(struct PStack *st, u_char pr, void *arg) { - byte *p; - struct BufHeader *ibh = arg; + u_char *p; + struct sk_buff *skb = arg; int cause = -1; - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, - IE_CAUSE, 0))) { + p = skb->data; + st->pa->loc = 0; + if ((p = findie(p, skb->len, IE_CAUSE, 0))) { p++; - if (*p++ == 2) + if (*p++ == 2) st->pa->loc = *p++; cause = *p & 0x7f; } - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); StopAllL3Timer(st); st->pa->cause = cause; newl3state(st, 0); @@ -110,179 +118,217 @@ } static void -l3dss1_setup_req(struct PStack *st, byte pr, +l3dss1_setup_req(struct PStack *st, u_char pr, void *arg) { - struct BufHeader *dibh; - byte *p; - char *teln; + struct sk_buff *skb; + u_char tmp[128]; + u_char *p = tmp; + u_char channel = 0; + u_char screen = 0; + u_char *teln; + u_char *msn; + int l; 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; + *p++ = 0xa1; /* complete indicator */ 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; + 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]) { + teln = st->pa->setup.phone; + if (*teln) { + /* parse number for special things */ + if (!isdigit(*teln)) { + switch (0x5f & *teln) { + case 'C': + channel = 0x08; + case 'P': + channel |= 0x80; + teln++; + if (*teln == '1') + channel |= 0x01; + else + channel |= 0x02; + break; + case 'R': + screen = 0xA0; + break; + case 'D': + screen = 0x80; + break; + default: + if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "Wrong MSN Code"); + break; + } + teln++; + } + } + if (channel) { + *p++ = 0x18; /* channel indicator */ + *p++ = 1; + *p++ = channel; + } + msn = st->pa->setup.eazmsn; + if (*msn) { *p++ = 0x6c; - *p++ = strlen(st->pa->setup.eazmsn) + 1; + *p++ = strlen(msn) + (screen ? 2 : 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; + if (screen) { + *p++ = 0x01; /* Ext = '0'B, Type = '000'B, Plan = '0001'B. */ + *p++ = screen; + } else + *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ + while (*msn) + *p++ = *msn++ & 0x7f; } *p++ = 0x70; - *p++ = strlen(st->pa->setup.phone) + 1; + *p++ = strlen(teln) + 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); + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); L3DelTimer(&st->l3.timer); L3AddTimer(&st->l3.timer, st->l3.t303, CC_T303); newl3state(st, 1); - st->l3.l3l2(st, DL_DATA, dibh); + st->l3.l3l2(st, DL_DATA, skb); } static void -l3dss1_call_proc(struct PStack *st, byte pr, void *arg) +l3dss1_call_proc(struct PStack *st, u_char pr, void *arg) { - byte *p; - struct BufHeader *ibh = arg; + u_char *p; + struct sk_buff *skb = arg; L3DelTimer(&st->l3.timer); - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, - 0x18, 0))) { + p = skb->data; + if ((p = findie(p, skb->len, 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); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); 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) +l3dss1_setup_ack(struct PStack *st, u_char pr, void *arg) { - byte *p; - struct BufHeader *ibh = arg; + u_char *p; + struct sk_buff *skb = arg; L3DelTimer(&st->l3.timer); - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, - 0x18, 0))) { + p = skb->data; + if ((p = findie(p, skb->len, 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); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); 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) +l3dss1_disconnect(struct PStack *st, u_char pr, void *arg) { - byte *p; - struct BufHeader *ibh = arg; + u_char *p; + struct sk_buff *skb = 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 = skb->data; + st->pa->loc = 0; + if ((p = findie(p, skb->len, IE_CAUSE, 0))) { p++; if (*p++ == 2) st->pa->loc = *p++; cause = *p & 0x7f; } - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); 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) +l3dss1_connect(struct PStack *st, u_char pr, void *arg) { - struct BufHeader *ibh = arg; - + struct sk_buff *skb = arg; - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); 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) +l3dss1_alerting(struct PStack *st, u_char pr, void *arg) { - struct BufHeader *ibh = arg; + struct sk_buff *skb = arg; - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); 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) +l3dss1_setup(struct PStack *st, u_char pr, void *arg) { - byte *p; + u_char *p; int bcfound = 0; char tmp[80]; - struct BufHeader *ibh = arg; + struct sk_buff *skb = arg; - p = DATAPTR(ibh); - p += st->l2.uihsize; + p = skb->data; 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))) { + p = skb->data; + if ((p = findie(p, skb->len, 0x18, 0))) { st->pa->bchannel = p[2] & 0x3; if (st->pa->bchannel) bcfound++; @@ -291,51 +337,49 @@ } 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))) { + p = skb->data; + if ((p = findie(p, skb->len, 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; + 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))) + p = skb->data; + if ((p = findie(p, skb->len, 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))) { + p = skb->data; + if ((p = findie(p, skb->len, 0x6c, 0))) { st->pa->setup.plan = p[2]; if (p[2] & 0x80) { iecpy(st->pa->setup.phone, p, 1); @@ -349,7 +393,8 @@ st->pa->setup.plan = 0; st->pa->setup.screen = 0; } - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); if (bcfound) { if ((st->pa->setup.si1 != 7) && (st->l3.debug & L3_DEB_WARN)) { @@ -364,14 +409,14 @@ } static void -l3dss1_reset(struct PStack *st, byte pr, void *arg) +l3dss1_reset(struct PStack *st, u_char pr, void *arg) { StopAllL3Timer(st); newl3state(st, 0); } static void -l3dss1_setup_rsp(struct PStack *st, byte pr, +l3dss1_setup_rsp(struct PStack *st, u_char pr, void *arg) { newl3state(st, 8); @@ -381,30 +426,30 @@ } static void -l3dss1_connect_ack(struct PStack *st, byte pr, void *arg) +l3dss1_connect_ack(struct PStack *st, u_char pr, void *arg) { - struct BufHeader *ibh = arg; + struct sk_buff *skb = arg; - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); 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) +l3dss1_disconnect_req(struct PStack *st, u_char pr, void *arg) { - struct BufHeader *dibh; - byte *p; - byte cause = 0x10; + struct sk_buff *skb; + u_char tmp[16]; + u_char *p = tmp; + int l; + u_char 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); @@ -413,26 +458,27 @@ *p++ = 0x80; *p++ = cause | 0x80; - dibh->datasize = p - DATAPTR(dibh); + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); newl3state(st, 11); - st->l3.l3l2(st, DL_DATA, dibh); + st->l3.l3l2(st, DL_DATA, skb); L3AddTimer(&st->l3.timer, st->l3.t305, CC_T305); } static void -l3dss1_reject_req(struct PStack *st, byte pr, void *arg) +l3dss1_reject_req(struct PStack *st, u_char pr, void *arg) { - struct BufHeader *dibh; - byte *p; - byte cause = 0x95; + struct sk_buff *skb; + u_char tmp[16]; + u_char *p = tmp; + int l; + u_char 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; @@ -440,28 +486,31 @@ *p++ = 0x80; *p++ = cause; - dibh->datasize = p - DATAPTR(dibh); + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); newl3state(st, 0); - st->l3.l3l2(st, DL_DATA, dibh); + st->l3.l3l2(st, DL_DATA, skb); st->l3.l3l4(st, CC_RELEASE_IND, NULL); } static void -l3dss1_release(struct PStack *st, byte pr, void *arg) +l3dss1_release(struct PStack *st, u_char pr, void *arg) { - byte *p; - struct BufHeader *ibh = arg; + u_char *p; + struct sk_buff *skb = arg; int cause = -1; - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, - IE_CAUSE, 0))) { + p = skb->data; + if ((p = findie(p, skb->len, IE_CAUSE, 0))) { p++; if (*p++ == 2) st->pa->loc = *p++; cause = *p & 0x7f; } - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); StopAllL3Timer(st); st->pa->cause = cause; newl3state(st, 0); @@ -470,7 +519,7 @@ } static void -l3dss1_alert_req(struct PStack *st, byte pr, +l3dss1_alert_req(struct PStack *st, u_char pr, void *arg) { newl3state(st, 7); @@ -478,16 +527,15 @@ } static void -l3dss1_status_enq(struct PStack *st, byte pr, void *arg) +l3dss1_status_enq(struct PStack *st, u_char pr, void *arg) { - struct BufHeader *dibh = arg; - byte *p; - - BufPoolRelease(dibh); + u_char tmp[16]; + u_char *p = tmp; + int l; + struct sk_buff *skb = arg; - BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 22); - p = DATAPTR(dibh); - p += st->l2.ihsize; + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); MsgHead(p, st->l3.callref, MT_STATUS); @@ -500,12 +548,15 @@ *p++ = 0x1; *p++ = st->l3.state & 0x3f; - dibh->datasize = p - DATAPTR(dibh); - st->l3.l3l2(st, DL_DATA, dibh); + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + st->l3.l3l2(st, DL_DATA, skb); } static void -l3dss1_t303(struct PStack *st, byte pr, void *arg) +l3dss1_t303(struct PStack *st, u_char pr, void *arg) { if (st->l3.n_t303 > 0) { st->l3.n_t303--; @@ -520,7 +571,7 @@ } static void -l3dss1_t304(struct PStack *st, byte pr, void *arg) +l3dss1_t304(struct PStack *st, u_char pr, void *arg) { L3DelTimer(&st->l3.timer); st->pa->cause = 0xE6; @@ -530,20 +581,18 @@ } static void -l3dss1_t305(struct PStack *st, byte pr, void *arg) +l3dss1_t305(struct PStack *st, u_char pr, void *arg) { - struct BufHeader *dibh; - byte *p; - byte cause = 0x90; + u_char tmp[16]; + u_char *p = tmp; + int l; + struct sk_buff *skb; + u_char 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; @@ -551,14 +600,17 @@ *p++ = 0x80; *p++ = cause; - dibh->datasize = p - DATAPTR(dibh); + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); newl3state(st, 19); - st->l3.l3l2(st, DL_DATA, dibh); + st->l3.l3l2(st, DL_DATA, skb); L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_1); } static void -l3dss1_t310(struct PStack *st, byte pr, void *arg) +l3dss1_t310(struct PStack *st, u_char pr, void *arg) { L3DelTimer(&st->l3.timer); st->pa->cause = 0xE6; @@ -567,7 +619,7 @@ } static void -l3dss1_t313(struct PStack *st, byte pr, void *arg) +l3dss1_t313(struct PStack *st, u_char pr, void *arg) { L3DelTimer(&st->l3.timer); st->pa->cause = 0xE6; @@ -576,7 +628,7 @@ } static void -l3dss1_t308_1(struct PStack *st, byte pr, void *arg) +l3dss1_t308_1(struct PStack *st, u_char pr, void *arg) { newl3state(st, 19); L3DelTimer(&st->l3.timer); @@ -585,13 +637,13 @@ } static void -l3dss1_t308_2(struct PStack *st, byte pr, void *arg) +l3dss1_t308_2(struct PStack *st, u_char pr, void *arg) { newl3state(st, 0); L3DelTimer(&st->l3.timer); st->l3.l3l4(st, CC_RELEASE_ERR, NULL); } - +/* *INDENT-OFF* */ static struct stateentry downstatelist[] = { {SBIT(0), @@ -647,60 +699,45 @@ {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) | 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}, }; +/* *INDENT-ON* */ + static int datasllen = sizeof(datastatelist) / sizeof(struct stateentry); static void -dss1up(struct PStack *st, - int pr, void *arg) +dss1up(struct PStack *st, int pr, void *arg) { - int i, mt, size; - byte *ptr; - struct BufHeader *ibh = arg; + int i, mt; + struct sk_buff *skb = 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 (skb->data[0] != PROTO_DIS_EURO) { if (st->l3.debug & L3_DEB_PROTERR) { - sprintf(tmp, "dss1up%sunexpected discriminator %x message len %d state %d", + sprintf(tmp, "dss1up%sunexpected discriminator %x message len %ld state %d", (pr == DL_DATA) ? " " : "(broadcast) ", - ptr[0], size, st->l3.state); + skb->data[0], skb->len, st->l3.state); l3_debug(st, tmp); } - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); return; } - mt = ptr[3]; + mt = skb->data[skb->data[1] + 2]; for (i = 0; i < datasllen; i++) if ((mt == datastatelist[i].primitive) && ((1 << st->l3.state) & datastatelist[i].state)) break; if (i == datasllen) { - BufPoolRelease(ibh); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); if (st->l3.debug & L3_DEB_STATE) { sprintf(tmp, "dss1up%sstate %d mt %x unhandled", (pr == DL_DATA) ? " " : "(broadcast) ", @@ -715,16 +752,14 @@ st->l3.state, mt); l3_debug(st, tmp); } - datastatelist[i].rout(st, pr, ibh); + datastatelist[i].rout(st, pr, skb); } } static void -dss1down(struct PStack *st, - int pr, void *arg) +dss1down(struct PStack *st, int pr, void *arg) { int i; - struct BufHeader *ibh = arg; char tmp[80]; for (i = 0; i < downsllen; i++) @@ -743,7 +778,7 @@ st->l3.state, pr); l3_debug(st, tmp); } - downstatelist[i].rout(st, pr, ibh); + downstatelist[i].rout(st, pr, arg); } } diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/q931.c linux/drivers/isdn/hisax/q931.c --- v2.1.41/linux/drivers/isdn/hisax/q931.c Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/q931.c Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: q931.c,v 1.4 1997/02/09 00:29:11 keil Exp $ +/* $Id: q931.c,v 1.5 1997/04/06 22:56:43 keil Exp $ * q931.c code to decode ITU Q.931 call control messages * @@ -14,6 +14,9 @@ * * * $Log: q931.c,v $ + * Revision 1.5 1997/04/06 22:56:43 keil + * Some cosmetic changes + * * Revision 1.4 1997/02/09 00:29:11 keil * new interface handling, one interface per card * @@ -34,11 +37,11 @@ #include "hisax.h" #include "l3_1tr6.h" -byte * -findie(byte * p, int size, byte ie, int wanted_set) +u_char * +findie(u_char * p, int size, u_char ie, int wanted_set) { int l, codeset, maincodeset; - byte *pend = p + size; + u_char *pend = p + size; /* skip protocol discriminator, callref and message type */ p++; @@ -73,9 +76,9 @@ } void -iecpy(byte * dest, byte * iestart, int ieoffset) +iecpy(u_char * dest, u_char * iestart, int ieoffset) { - byte *p; + u_char *p; int l; p = iestart + ieoffset + 2; @@ -86,7 +89,7 @@ } int -getcallref(byte * p) +getcallref(u_char * p) { p++; /* prot discr */ p++; /* callref length */ @@ -98,7 +101,7 @@ */ static struct MessageType { - byte nr; + u_char nr; char *descr; } mtlist[] = { @@ -265,7 +268,7 @@ static int -prbits(char *dest, byte b, int start, int len) +prbits(char *dest, u_char b, int start, int len) { char *dp = dest; @@ -281,8 +284,8 @@ } static -byte * -skipext(byte * p) +u_char * +skipext(u_char * p) { while (!(*p++ & 0x80)); return (p); @@ -297,7 +300,7 @@ static struct CauseValue { - byte nr; + u_char nr; char *edescr; char *ddescr; } cvlist[] = { @@ -509,9 +512,9 @@ static int -prcause(char *dest, byte * p) +prcause(char *dest, u_char * p) { - byte *end; + u_char *end; char *dp = dest; int i, cause; @@ -586,7 +589,7 @@ int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType)); static int -prcause_1tr6(char *dest, byte * p) +prcause_1tr6(char *dest, u_char * p) { char *dp = dest; int i, cause; @@ -621,7 +624,7 @@ } static int -prchident(char *dest, byte * p) +prchident(char *dest, u_char * p) { char *dp = dest; @@ -633,7 +636,7 @@ } static int -prcalled(char *dest, byte * p) +prcalled(char *dest, u_char * p) { int l; char *dp = dest; @@ -650,7 +653,7 @@ return (dp - dest); } static int -prcalling(char *dest, byte * p) +prcalling(char *dest, u_char * p) { int l; char *dp = dest; @@ -677,7 +680,7 @@ static int -prbearer(char *dest, byte * p) +prbearer(char *dest, u_char * p) { char *dp = dest, ch; @@ -723,7 +726,7 @@ } static int -general(char *dest, byte * p) +general(char *dest, u_char * p) { char *dp = dest; char ch = ' '; @@ -750,7 +753,7 @@ } static int -prcharge(char *dest, byte * p) +prcharge(char *dest, u_char * p) { char *dp = dest; int l; @@ -767,7 +770,7 @@ return (dp - dest); } static int -prtext(char *dest, byte * p) +prtext(char *dest, u_char * p) { char *dp = dest; int l; @@ -782,7 +785,7 @@ return (dp - dest); } static int -display(char *dest, byte * p) +display(char *dest, u_char * p) { char *dp = dest; char ch = ' '; @@ -811,7 +814,7 @@ } int -prfacility(char *dest, byte * p) +prfacility(char *dest, u_char * p) { char *dp = dest; int l, l2; @@ -842,9 +845,9 @@ static struct InformationElement { - byte nr; + u_char nr; char *descr; - int (*f) (char *, byte *); + int (*f) (char *, u_char *); } ielist[] = { { @@ -980,11 +983,11 @@ static int we_6_len = (sizeof(we_6) / sizeof(struct InformationElement)); int -QuickHex(char *txt, byte * p, int cnt) +QuickHex(char *txt, u_char * p, int cnt) { register int i; register char *t = txt; - register byte w; + register u_char w; for (i = 0; i < cnt; i++) { *t++ = ' '; @@ -1004,7 +1007,7 @@ } void -LogFrame(struct IsdnCardState *sp, byte * buf, int size) +LogFrame(struct IsdnCardState *sp, u_char * buf, int size) { char *dp; @@ -1024,9 +1027,9 @@ } void -dlogframe(struct IsdnCardState *sp, byte * buf, int size, char *comment) +dlogframe(struct IsdnCardState *sp, u_char * buf, int size, char *comment) { - byte *bend = buf + size; + u_char *bend = buf + size; char *dp; unsigned char pd, cr_l, cr, mt; int i, cs = 0, cs_old = 0, cs_fest = 0; diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/tei.c linux/drivers/isdn/hisax/tei.c --- v2.1.41/linux/drivers/isdn/hisax/tei.c Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/tei.c Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: tei.c,v 1.6 1997/02/09 00:25:12 keil Exp $ +/* $Id: tei.c,v 1.8 1997/04/07 22:59:08 keil Exp $ * Author Karsten Keil (keil@temic-ech.spacenet.de) * based on the teles driver from Jan den Ouden @@ -7,6 +7,12 @@ * Fritz Elfert * * $Log: tei.c,v $ + * Revision 1.8 1997/04/07 22:59:08 keil + * GFP_KERNEL --> GFP_ATOMIC + * + * Revision 1.7 1997/04/06 22:54:03 keil + * Using SKB's + * * Revision 1.6 1997/02/09 00:25:12 keil * new interface handling, one interface per card * @@ -34,7 +40,7 @@ extern struct IsdnCard cards[]; extern int nrcards; -const char *tei_revision = "$Revision: 1.6 $"; +const char *tei_revision = "$Revision: 1.8 $"; static struct PStack * findces(struct PStack *st, int ces) @@ -66,26 +72,27 @@ } static void -mdl_unit_data_res(struct PStack *st, unsigned int ri, byte mt, byte ai) +mdl_unit_data_res(struct PStack *st, unsigned int ri, u_char mt, u_char ai) { - struct BufHeader *ibh; - byte *bp; + struct sk_buff *skb; + u_char *bp; - if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 7)) + if (!(skb = alloc_skb(6 + MAX_HEADER_LEN, GFP_ATOMIC))) { + printk(KERN_WARNING "HiSax: No skb for TEI manager\n"); return; - bp = DATAPTR(ibh); - bp += 3; + } + skb_reserve(skb, MAX_HEADER_LEN); + bp = skb_put(skb, 5); 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); + st->l3.l3l2(st, DL_UNIT_DATA, skb); } static void -mdl_unit_data_ind(struct PStack *st, unsigned int ri, byte mt, byte ai) +mdl_unit_data_ind(struct PStack *st, unsigned int ri, u_char mt, u_char ai) { unsigned int tces; struct PStack *otsp, *ptr; @@ -194,15 +201,15 @@ void tei_handler(struct PStack *st, - byte pr, struct BufHeader *ibh) + u_char pr, struct sk_buff *skb) { - byte *bp; + u_char *bp; unsigned int data; char tmp[32]; switch (pr) { case (MDL_ASSIGN): - data = (unsigned int) ibh; + data = (unsigned int) skb; if (st->l3.debug) { sprintf(tmp, "ces %d assign request", data); st->l2.l2m.printdebug(&st->l2.l2m, tmp); @@ -210,7 +217,7 @@ mdl_unit_data_res(st, data, 1, 127); break; case (MDL_VERIFY): - data = (unsigned int) ibh; + data = (unsigned int) skb; if (st->l3.debug) { sprintf(tmp, "%d id verify request", data); st->l2.l2m.printdebug(&st->l2.l2m, tmp); @@ -218,17 +225,15 @@ mdl_unit_data_res(st, 0, 7, data); break; case (DL_UNIT_DATA): - bp = DATAPTR(ibh); - bp += 3; + bp = skb->data; 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); + } else + mdl_unit_data_ind(st, (bp[1] << 8) | bp[2], bp[3], bp[4] >> 1); + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_READ); break; default: break; @@ -270,8 +275,7 @@ struct PStack *st; char tmp[128]; - st = (struct PStack *) Smalloc(sizeof(struct PStack), GFP_KERNEL, - "struct PStack"); + st = (struct PStack *) kmalloc(sizeof(struct PStack), GFP_ATOMIC); setstack_HiSax(st, sp); st->l2.extended = !0; st->l2.laptype = LAPD; @@ -281,7 +285,6 @@ /* * the following is not necessary for tei mng. (broadcast only) */ - st->l2.t200 = 500; /* 500 milliseconds */ st->l2.n200 = 4; /* try 4 times */ @@ -310,5 +313,5 @@ struct PStack *st = sp->teistack; HiSax_rmlist(sp, st); - Sfree((void *) st); + kfree((void *) st); } diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/teles0.c linux/drivers/isdn/hisax/teles0.c --- v2.1.41/linux/drivers/isdn/hisax/teles0.c Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/teles0.c Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: teles0.c,v 1.6 1997/01/27 15:52:18 keil Exp $ +/* $Id: teles0.c,v 1.8 1997/04/13 19:54:04 keil Exp $ * teles0.c low level stuff for Teles Memory IO isdn cards * based on the teles driver from Jan den Ouden @@ -10,6 +10,12 @@ * Beat Doebeli * * $Log: teles0.c,v $ + * Revision 1.8 1997/04/13 19:54:04 keil + * Change in IRQ check delay for SMP + * + * Revision 1.7 1997/04/06 22:54:04 keil + * Using SKB's + * * Revision 1.6 1997/01/27 15:52:18 keil * SMP proof,cosmetics * @@ -40,70 +46,70 @@ extern const char *CardType[]; -const char *teles0_revision = "$Revision: 1.6 $"; +const char *teles0_revision = "$Revision: 1.8 $"; #define byteout(addr,val) outb_p(val,addr) #define bytein(addr) inb_p(addr) -static inline byte -readisac(unsigned int adr, byte off) +static inline u_char +readisac(unsigned int adr, u_char off) { return readb(adr + 0x120 + ((off & 1) ? 0x1ff : 0) + off); } static inline void -writeisac(unsigned int adr, byte off, byte data) +writeisac(unsigned int adr, u_char off, u_char data) { writeb(data, adr + 0x120 + ((off & 1) ? 0x1ff : 0) + off); } -static inline byte -readhscx(unsigned int adr, int hscx, byte off) +static inline u_char +readhscx(unsigned int adr, int hscx, u_char 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) +writehscx(unsigned int adr, int hscx, u_char off, u_char 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) +read_fifo_isac(unsigned int adr, u_char * data, int size) { register int i; - register byte *ad = (byte *) (adr + 0x100); + register u_char *ad = (u_char *) (adr + 0x100); for (i = 0; i < size; i++) data[i] = readb(ad); } static void -write_fifo_isac(unsigned int adr, byte * data, int size) +write_fifo_isac(unsigned int adr, u_char * data, int size) { register int i; - register byte *ad = (byte *) (adr + 0x100); + register u_char *ad = (u_char *) (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) +read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size) { register int i; - register byte *ad = (byte *) (adr + (hscx ? 0x1c0 : 0x180)); + register u_char *ad = (u_char *) (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) +write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size) { int i; - register byte *ad = (byte *) (adr + (hscx ? 0x1c0 : 0x180)); + register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180)); for (i = 0; i < size; i++) writeb(data[i], ad); } @@ -135,7 +141,7 @@ } static inline void -writehscxCMDR(int adr, int hscx, byte data) +writehscxCMDR(int adr, int hscx, u_char data) { long flags; @@ -178,25 +184,22 @@ static void hscx_empty_fifo(struct HscxState *hsp, int count) { - byte *ptr; + u_char *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 (hsp->rcvidx + count > HSCX_BUFMAX) { if (sp->debug & L1_DEB_WARN) debugl1(sp, "hscx_empty_fifo: incoming packet too large"); writehscxCMDR(sp->membase, hsp->hscx, 0x80); + hsp->rcvidx = 0; return; } - ptr = DATAPTR(ibh); - ptr += hsp->rcvptr; - - hsp->rcvptr += count; + ptr = hsp->rcvbuf + hsp->rcvidx; + hsp->rcvidx += count; save_flags(flags); cli(); read_fifo_hscx(sp->membase, hsp->hscx, ptr, count); @@ -217,34 +220,32 @@ hscx_fill_fifo(struct HscxState *hsp) { struct IsdnCardState *sp = hsp->sp; - struct BufHeader *ibh; int more, count; - byte *ptr; + u_char *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) + if (!hsp->tx_skb) return; - - count = ibh->datasize - hsp->sendptr; - if (count <= 0) + if (hsp->tx_skb->len <= 0) return; more = (hsp->mode == 1) ? 1 : 0; - if (count > 32) { + if (hsp->tx_skb->len > 32) { more = !0; count = 32; - } - ptr = DATAPTR(ibh); - ptr += hsp->sendptr; - hsp->sendptr += count; + } else + count = hsp->tx_skb->len; waitforXFW(sp->membase, hsp->hscx); save_flags(flags); cli(); + ptr = hsp->tx_skb->data; + skb_pull(hsp->tx_skb, count); + hsp->tx_cnt -= count; + hsp->count += count; write_fifo_hscx(sp->membase, hsp->hscx, ptr, count); writehscxCMDR(sp->membase, hsp->hscx, more ? 0x8 : 0xa); restore_flags(flags); @@ -260,11 +261,12 @@ } static inline void -hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx) +hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx) { - byte r; + u_char r; struct HscxState *hsp = sp->hs + hscx; - int count, err; + struct sk_buff *skb; + int count; char tmp[32]; if (!hsp->init) @@ -286,79 +288,57 @@ 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; + } else { + count = readhscx(sp->membase, hsp->hscx, HSCX_RBCL) & 0x1f; + if (count == 0) + count = 32; + hscx_empty_fifo(hsp, count); + if ((count = hsp->rcvidx - 1) > 0) { + if (!(skb = dev_alloc_skb(count))) + printk(KERN_WARNING "AVM: receive out of memory\n"); + else { + memcpy(skb_put(skb, count), hsp->rcvbuf, count); + skb_queue_tail(&hsp->rqueue, skb); + } + } } - 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; + hsp->rcvidx = 0; 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; + if (!(skb = dev_alloc_skb(32))) + printk(KERN_WARNING "AVM: receive out of memory\n"); + else { + memcpy(skb_put(skb, 32), hsp->rcvbuf, 32); + skb_queue_tail(&hsp->rqueue, skb); + } + hsp->rcvidx = 0; hscx_sched_event(hsp, HSCX_RCVBUFREADY); } } - afterRPF: if (val & 0x10) { /* XPR */ - if (hsp->xmtibh) - if (hsp->xmtibh->datasize > hsp->sendptr) { + if (hsp->tx_skb) + if (hsp->tx_skb->len) { hscx_fill_fifo(hsp); - goto afterXPR; + return; } else { - if (hsp->releasebuf) - BufPoolRelease(hsp->xmtibh); - hsp->sendptr = 0; + SET_SKB_FREE(hsp->tx_skb); + dev_kfree_skb(hsp->tx_skb, FREE_WRITE); + hsp->count = 0; if (hsp->st->l4.l1writewakeup) hsp->st->l4.l1writewakeup(hsp->st); - hsp->xmtibh = NULL; + hsp->tx_skb = NULL; } - if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) { - hsp->releasebuf = !0; + if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) { + hsp->count = 0; hscx_fill_fifo(hsp); } else hscx_sched_event(hsp, HSCX_XMTBUFREADY); } - afterXPR: } /* @@ -368,25 +348,25 @@ static void isac_empty_fifo(struct IsdnCardState *sp, int count) { - byte *ptr; - struct BufHeader *ibh = sp->rcvibh; + u_char *ptr; 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->rcvidx + count) >= MAX_DFRAME_LEN) { if (sp->debug & L1_DEB_WARN) { char tmp[40]; - sprintf(tmp, "isac_empty_fifo rcvptr %d", sp->rcvptr); + sprintf(tmp, "isac_empty_fifo overrun %d", + sp->rcvidx + count); debugl1(sp, tmp); } + writeisac(sp->membase, ISAC_CMDR, 0x80); + sp->rcvidx = 0; return; } - ptr = DATAPTR(ibh); - ptr += sp->rcvptr; - sp->rcvptr += count; - + ptr = sp->rcvbuf + sp->rcvidx; + sp->rcvidx += count; save_flags(flags); cli(); read_fifo_isac(sp->membase, ptr, count); @@ -405,35 +385,30 @@ static void isac_fill_fifo(struct IsdnCardState *sp) { - struct BufHeader *ibh; int count, more; - byte *ptr; + u_char *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) + if (!sp->tx_skb) return; - count = ibh->datasize - sp->sendptr; + count = sp->tx_skb->len; 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(); + ptr = sp->tx_skb->data; + skb_pull(sp->tx_skb, count); + sp->tx_cnt += count; write_fifo_isac(sp->membase, ptr, count); writeisac(sp->membase, ISAC_CMDR, more ? 0x8 : 0xa); restore_flags(flags); @@ -459,9 +434,10 @@ } static inline void -isac_interrupt(struct IsdnCardState *sp, byte val) +isac_interrupt(struct IsdnCardState *sp, u_char val) { - byte exval; + u_char exval; + struct sk_buff *skb; unsigned int count; char tmp[32]; @@ -478,62 +454,45 @@ 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; + } else { + count = readisac(sp->membase, ISAC_RBCL) & 0x1f; + if (count == 0) + count = 32; + isac_empty_fifo(sp, count); + if ((count = sp->rcvidx) > 0) { + if (!(skb = alloc_skb(count, GFP_ATOMIC))) + printk(KERN_WARNING "AVM: D receive out of memory\n"); + else { + memcpy(skb_put(skb, count), sp->rcvbuf, count); + skb_queue_tail(&sp->rq, skb); + } + } } - 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; + sp->rcvidx = 0; 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) { + if (sp->tx_skb) + if (sp->tx_skb->len) { isac_fill_fifo(sp); goto afterXPR; } else { - if (sp->releasebuf) - BufPoolRelease(sp->xmtibh); - sp->xmtibh = NULL; - sp->sendptr = 0; + SET_SKB_FREE(sp->tx_skb); + dev_kfree_skb(sp->tx_skb, FREE_WRITE); + sp->tx_cnt = 0; + sp->tx_skb = NULL; } - if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) { - sp->releasebuf = !0; + if ((sp->tx_skb = skb_dequeue(&sp->sq))) { + sp->tx_cnt = 0; isac_fill_fifo(sp); } else isac_sched_event(sp, ISAC_XMTBUFREADY); @@ -563,10 +522,10 @@ } static inline void -hscx_int_main(struct IsdnCardState *sp, byte val) +hscx_int_main(struct IsdnCardState *sp, u_char val) { - byte exval; + u_char exval; struct HscxState *hsp; char tmp[32]; @@ -581,7 +540,11 @@ /* Here we lost an TX interrupt, so * restart transmitting the whole frame. */ - hsp->sendptr = 0; + if (hsp->tx_skb) { + skb_push(hsp->tx_skb, hsp->count); + hsp->tx_cnt += hsp->count; + hsp->count = 0; + } writehscxCMDR(sp->membase, hsp->hscx, 0x01); if (sp->debug & L1_DEB_WARN) { sprintf(tmp, "HSCX B EXIR %x Lost TX", exval); @@ -610,7 +573,11 @@ /* Here we lost an TX interrupt, so * restart transmitting the whole frame. */ - hsp->sendptr = 0; + if (hsp->tx_skb) { + skb_push(hsp->tx_skb, hsp->count); + hsp->tx_cnt += hsp->count; + hsp->count = 0; + } writehscxCMDR(sp->membase, hsp->hscx, 0x01); if (sp->debug & L1_DEB_WARN) { sprintf(tmp, "HSCX A EXIR %x Lost TX", exval); @@ -636,7 +603,7 @@ telesS0_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *sp; - byte val, stat = 0; + u_char val, stat = 0; sp = (struct IsdnCardState *) irq2dev_map[intno]; @@ -723,48 +690,48 @@ 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 { + case (0): 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_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, 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_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); } @@ -832,6 +799,7 @@ initteles0(struct IsdnCardState *sp) { int ret; + int loop = 0; char tmp[40]; sp->counter = kstat.interrupts[sp->irq]; @@ -843,6 +811,16 @@ initisac(sp); sp->modehscx(sp->hs, 0, 0); sp->modehscx(sp->hs + 1, 0, 0); + while (loop++ < 10) { + /* At least 1-3 irqs must happen + * (one from HSCX A, one from HSCX B, 3rd from ISAC) + */ + if (kstat.interrupts[sp->irq] > sp->counter) + break; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + 1; + schedule(); + } sprintf(tmp, "IRQ %d count %d", sp->irq, kstat.interrupts[sp->irq]); debugl1(sp, tmp); @@ -861,7 +839,7 @@ int setup_teles0(struct IsdnCard *card) { - byte cfval, val, verA, verB; + u_char cfval, val, verA, verB; struct IsdnCardState *sp = card->sp; long flags; char tmp[64]; @@ -897,33 +875,33 @@ } } 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; + 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) { diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/hisax/teles3.c linux/drivers/isdn/hisax/teles3.c --- v2.1.41/linux/drivers/isdn/hisax/teles3.c Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/teles3.c Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: teles3.c,v 1.7 1997/01/28 22:48:33 keil Exp $ +/* $Id: teles3.c,v 1.11 1997/04/13 19:54:05 keil Exp $ * teles3.c low level stuff for Teles 16.3 & PNP isdn cards * @@ -11,6 +11,24 @@ * Beat Doebeli * * $Log: teles3.c,v $ + * Revision 1.11 1997/04/13 19:54:05 keil + * Change in IRQ check delay for SMP + * + * Revision 1.10 1997/04/06 22:54:05 keil + * Using SKB's + * + * Revision 1.9 1997/03/22 02:01:07 fritz + * -Reworked toplevel Makefile. From now on, no different Makefiles + * for standalone- and in-kernel-compilation are needed any more. + * -Added local Rules.make for above reason. + * -Experimental changes in teles3.c for enhanced IRQ-checking with + * 2.1.X and SMP kernels. + * -Removed diffstd-script, same functionality is in stddiff -r. + * -Enhanced scripts std2kern and stddiff. + * + * Revision 1.8 1997/02/23 18:43:55 fritz + * Added support for Teles-Vision. + * * Revision 1.7 1997/01/28 22:48:33 keil * fixes for Teles PCMCIA (Christof Petig) * @@ -43,32 +61,32 @@ #include extern const char *CardType[]; -const char *teles3_revision = "$Revision: 1.7 $"; +const char *teles3_revision = "$Revision: 1.11 $"; #define byteout(addr,val) outb_p(val,addr) #define bytein(addr) inb_p(addr) -static inline byte -readreg(unsigned int adr, byte off) +static inline u_char +readreg(unsigned int adr, u_char off) { return (bytein(adr + off)); } static inline void -writereg(unsigned int adr, byte off, byte data) +writereg(unsigned int adr, u_char off, u_char data) { byteout(adr + off, data); } static inline void -read_fifo(unsigned int adr, byte * data, int size) +read_fifo(unsigned int adr, u_char * data, int size) { insb(adr + 0x1e, data, size); } static void -write_fifo(unsigned int adr, byte * data, int size) +write_fifo(unsigned int adr, u_char * data, int size) { outsb(adr + 0x1e, data, size); } @@ -100,7 +118,7 @@ printk(KERN_WARNING "Teles3: waitforXFW timeout\n"); } static inline void -writehscxCMDR(int adr, byte data) +writehscxCMDR(int adr, u_char data) { long flags; @@ -142,25 +160,22 @@ static void hscx_empty_fifo(struct HscxState *hsp, int count) { - byte *ptr; + u_char *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 (hsp->rcvidx + count > HSCX_BUFMAX) { if (sp->debug & L1_DEB_WARN) debugl1(sp, "hscx_empty_fifo: incoming packet too large"); writehscxCMDR(sp->hscx[hsp->hscx], 0x80); + hsp->rcvidx = 0; return; } - ptr = DATAPTR(ibh); - ptr += hsp->rcvptr; - - hsp->rcvptr += count; + ptr = hsp->rcvbuf + hsp->rcvidx; + hsp->rcvidx += count; save_flags(flags); cli(); read_fifo(sp->hscx[hsp->hscx], ptr, count); @@ -181,34 +196,32 @@ hscx_fill_fifo(struct HscxState *hsp) { struct IsdnCardState *sp = hsp->sp; - struct BufHeader *ibh; int more, count; - byte *ptr; + u_char *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) + if (!hsp->tx_skb) return; - - count = ibh->datasize - hsp->sendptr; - if (count <= 0) + if (hsp->tx_skb->len <= 0) return; more = (hsp->mode == 1) ? 1 : 0; - if (count > 32) { + if (hsp->tx_skb->len > 32) { more = !0; count = 32; - } - ptr = DATAPTR(ibh); - ptr += hsp->sendptr; - hsp->sendptr += count; + } else + count = hsp->tx_skb->len; waitforXFW(sp->hscx[hsp->hscx]); save_flags(flags); cli(); + ptr = hsp->tx_skb->data; + skb_pull(hsp->tx_skb, count); + hsp->tx_cnt -= count; + hsp->count += count; write_fifo(sp->hscx[hsp->hscx], ptr, count); writehscxCMDR(sp->hscx[hsp->hscx], more ? 0x8 : 0xa); restore_flags(flags); @@ -224,11 +237,12 @@ } static inline void -hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx) +hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx) { - byte r; + u_char r; struct HscxState *hsp = sp->hs + hscx; - int count, err; + struct sk_buff *skb; + int count; char tmp[32]; if (!hsp->init) @@ -250,79 +264,57 @@ 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; + } else { + count = readreg(sp->hscx[hsp->hscx], HSCX_RBCL) & 0x1f; + if (count == 0) + count = 32; + hscx_empty_fifo(hsp, count); + if ((count = hsp->rcvidx - 1) > 0) { + if (!(skb = dev_alloc_skb(count))) + printk(KERN_WARNING "AVM: receive out of memory\n"); + else { + memcpy(skb_put(skb, count), hsp->rcvbuf, count); + skb_queue_tail(&hsp->rqueue, skb); + } + } } - 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; + hsp->rcvidx = 0; 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; + if (!(skb = dev_alloc_skb(32))) + printk(KERN_WARNING "AVM: receive out of memory\n"); + else { + memcpy(skb_put(skb, 32), hsp->rcvbuf, 32); + skb_queue_tail(&hsp->rqueue, skb); + } + hsp->rcvidx = 0; hscx_sched_event(hsp, HSCX_RCVBUFREADY); } } - afterRPF: if (val & 0x10) { /* XPR */ - if (hsp->xmtibh) - if (hsp->xmtibh->datasize > hsp->sendptr) { + if (hsp->tx_skb) + if (hsp->tx_skb->len) { hscx_fill_fifo(hsp); - goto afterXPR; + return; } else { - if (hsp->releasebuf) - BufPoolRelease(hsp->xmtibh); - hsp->sendptr = 0; + SET_SKB_FREE(hsp->tx_skb); + dev_kfree_skb(hsp->tx_skb, FREE_WRITE); + hsp->count = 0; if (hsp->st->l4.l1writewakeup) hsp->st->l4.l1writewakeup(hsp->st); - hsp->xmtibh = NULL; + hsp->tx_skb = NULL; } - if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) { - hsp->releasebuf = !0; + if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) { + hsp->count = 0; hscx_fill_fifo(hsp); } else hscx_sched_event(hsp, HSCX_XMTBUFREADY); } - afterXPR: } /* @@ -332,26 +324,26 @@ static void isac_empty_fifo(struct IsdnCardState *sp, int count) { - byte *ptr; - struct BufHeader *ibh = sp->rcvibh; + u_char *ptr; 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->rcvidx + count) >= MAX_DFRAME_LEN) { if (sp->debug & L1_DEB_WARN) { char tmp[40]; - sprintf(tmp, "isac_empty_fifo rcvptr %d", sp->rcvptr); + sprintf(tmp, "isac_empty_fifo overrun %d", + sp->rcvidx + count); debugl1(sp, tmp); } + writereg(sp->isac, ISAC_CMDR, 0x80); + sp->rcvidx = 0; return; } - ptr = DATAPTR(ibh); - ptr += sp->rcvptr; - sp->rcvptr += count; - + ptr = sp->rcvbuf + sp->rcvidx; + sp->rcvidx += count; save_flags(flags); cli(); read_fifo(sp->isac, ptr, count); @@ -370,35 +362,30 @@ static void isac_fill_fifo(struct IsdnCardState *sp) { - struct BufHeader *ibh; int count, more; - byte *ptr; + u_char *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) + if (!sp->tx_skb) return; - count = ibh->datasize - sp->sendptr; + count = sp->tx_skb->len; 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(); + ptr = sp->tx_skb->data; + skb_pull(sp->tx_skb, count); + sp->tx_cnt += count; write_fifo(sp->isac, ptr, count); writereg(sp->isac, ISAC_CMDR, more ? 0x8 : 0xa); restore_flags(flags); @@ -425,9 +412,10 @@ static inline void -isac_interrupt(struct IsdnCardState *sp, byte val) +isac_interrupt(struct IsdnCardState *sp, u_char val) { - byte exval; + u_char exval; + struct sk_buff *skb; unsigned int count; char tmp[32]; @@ -444,62 +432,45 @@ 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; + } else { + count = readreg(sp->isac, ISAC_RBCL) & 0x1f; + if (count == 0) + count = 32; + isac_empty_fifo(sp, count); + if ((count = sp->rcvidx) > 0) { + if (!(skb = alloc_skb(count, GFP_ATOMIC))) + printk(KERN_WARNING "AVM: D receive out of memory\n"); + else { + memcpy(skb_put(skb, count), sp->rcvbuf, count); + skb_queue_tail(&sp->rq, skb); + } + } } - 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; + sp->rcvidx = 0; 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) { + if (sp->tx_skb) + if (sp->tx_skb->len) { isac_fill_fifo(sp); goto afterXPR; } else { - if (sp->releasebuf) - BufPoolRelease(sp->xmtibh); - sp->xmtibh = NULL; - sp->sendptr = 0; + SET_SKB_FREE(sp->tx_skb); + dev_kfree_skb(sp->tx_skb, FREE_WRITE); + sp->tx_cnt = 0; + sp->tx_skb = NULL; } - if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) { - sp->releasebuf = !0; + if ((sp->tx_skb = skb_dequeue(&sp->sq))) { + sp->tx_cnt = 0; isac_fill_fifo(sp); } else isac_sched_event(sp, ISAC_XMTBUFREADY); @@ -529,10 +500,10 @@ } static inline void -hscx_int_main(struct IsdnCardState *sp, byte val) +hscx_int_main(struct IsdnCardState *sp, u_char val) { - byte exval; + u_char exval; struct HscxState *hsp; char tmp[32]; @@ -547,7 +518,11 @@ /* Here we lost an TX interrupt, so * restart transmitting the whole frame. */ - hsp->sendptr = 0; + if (hsp->tx_skb) { + skb_push(hsp->tx_skb, hsp->count); + hsp->tx_cnt += hsp->count; + hsp->count = 0; + } writehscxCMDR(sp->hscx[hsp->hscx], 0x01); if (sp->debug & L1_DEB_WARN) { sprintf(tmp, "HSCX B EXIR %x Lost TX", exval); @@ -576,7 +551,11 @@ /* Here we lost an TX interrupt, so * restart transmitting the whole frame. */ - hsp->sendptr = 0; + if (hsp->tx_skb) { + skb_push(hsp->tx_skb, hsp->count); + hsp->tx_cnt += hsp->count; + hsp->count = 0; + } writehscxCMDR(sp->hscx[hsp->hscx], 0x01); if (sp->debug & L1_DEB_WARN) { sprintf(tmp, "HSCX A EXIR %x Lost TX", exval); @@ -601,8 +580,10 @@ static void teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs) { +#define MAXCOUNT 20 struct IsdnCardState *sp; - byte val, stat = 0; + u_char val, stat = 0; + int count = 0; sp = (struct IsdnCardState *) irq2dev_map[intno]; @@ -622,18 +603,21 @@ isac_interrupt(sp, val); stat |= 2; } + count++; val = readreg(sp->hscx[1], HSCX_ISTA); - if (val) { + if (val && count < MAXCOUNT) { if (sp->debug & L1_DEB_HSCX) debugl1(sp, "HSCX IntStat after IntRoutine"); goto Start_HSCX; } val = readreg(sp->isac, ISAC_ISTA); - if (val) { + if (val && count < MAXCOUNT) { if (sp->debug & L1_DEB_ISAC) debugl1(sp, "ISAC IntStat after IntRoutine"); goto Start_ISAC; } + if (count >= MAXCOUNT) + printk(KERN_WARNING "Teles3: more than %d loops in teles3_interrupt\n", count); if (stat & 1) { writereg(sp->hscx[0], HSCX_MASK, 0xFF); writereg(sp->hscx[1], HSCX_MASK, 0xFF); @@ -689,48 +673,48 @@ 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 { + case (0): 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_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, 0x8c); - writereg(sp->hscx[hscx], HSCX_CMDR, 0x41); - break; + 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); } @@ -814,6 +798,7 @@ initteles3(struct IsdnCardState *sp) { int ret; + int loop = 0; char tmp[40]; sp->counter = kstat.interrupts[sp->irq]; @@ -824,11 +809,23 @@ if (ret) { initisac(sp); sp->modehscx(sp->hs, 0, 0); + writereg(sp->hscx[sp->hs->hscx], HSCX_CMDR, 0x01); sp->modehscx(sp->hs + 1, 0, 0); - sprintf(tmp, "IRQ %d count %d", sp->irq, - kstat.interrupts[sp->irq]); + writereg(sp->hscx[(sp->hs + 1)->hscx], HSCX_CMDR, 0x01); + while (loop++ < 10) { + /* At least 1-3 irqs must happen + * (one from HSCX A, one from HSCX B, 3rd from ISAC) + */ + if (kstat.interrupts[sp->irq] > sp->counter) + break; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + 1; + schedule(); + } + sprintf(tmp, "IRQ %d count %d loop %d", sp->irq, + kstat.interrupts[sp->irq], loop); debugl1(sp, tmp); - if (kstat.interrupts[sp->irq] == sp->counter) { + if (kstat.interrupts[sp->irq] <= sp->counter) { printk(KERN_WARNING "Teles3: IRQ(%d) getting no interrupts during init\n", sp->irq); @@ -843,7 +840,7 @@ int setup_teles3(struct IsdnCard *card) { - byte cfval = 0, val, verA, verB; + u_char cfval = 0, val, verA, verB; struct IsdnCardState *sp = card->sp; long flags; char tmp[64]; @@ -857,11 +854,11 @@ 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; + case 0x180: + case 0x280: + case 0x380: + sp->cfg_reg |= 0xc00; + break; } sp->isac = sp->cfg_reg - 0x400; sp->hscx[0] = sp->cfg_reg - 0xc00; @@ -943,33 +940,33 @@ 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; + 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) { @@ -988,8 +985,9 @@ val = bytein(sp->cfg_reg + 2); /* 0x1e=without AB * 0x1f=with AB * 0x1c 16.3 ??? + * 0x46 16.3 with AB + Video (Teles-Vision) */ - if (val != 0x1c && val != 0x1e && val != 0x1f) { + if (val != 0x46 && 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); diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c --- v2.1.41/linux/drivers/isdn/icn/icn.c Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/icn/icn.c Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: icn.c,v 1.38 1997/02/11 18:29:31 fritz Exp $ +/* $Id: icn.c,v 1.44 1997/03/30 16:51:26 calle Exp $ * ISDN low-level module for the ICN active ISDN-Card. * @@ -19,6 +19,25 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.c,v $ + * Revision 1.44 1997/03/30 16:51:26 calle + * changed calls to copy_from_user/copy_to_user and removed verify_area + * were possible. + * + * Revision 1.43 1997/03/21 18:27:04 fritz + * Corrected parsing of incoming setup. + * + * Revision 1.42 1997/03/05 21:13:18 fritz + * Bugfix: sndcount was not reset on hangup. + * + * Revision 1.41 1997/02/24 23:34:29 fritz + * Bugfix in Layer1 error-recovery. + * + * Revision 1.40 1997/02/23 23:34:45 fritz + * Minor bugfixes in debugging code. + * + * Revision 1.39 1997/02/23 16:21:56 fritz + * Bugfix: Check for NULL pointer in icn_parse_status(). + * * Revision 1.38 1997/02/11 18:29:31 fritz * Bugfix in D64S initialization. * @@ -171,22 +190,25 @@ #undef MAP_DEBUG static char -*revision = "$Revision: 1.38 $"; +*revision = "$Revision: 1.44 $"; static int icn_addcard(int, char *, char *); /* - * Free queue completely. + * Free send-queue completely. * Parameter: - * queue = pointer to queue-head + * card = pointer to card struct + * channel = channel number */ static void -icn_free_queue(struct sk_buff_head *queue) +icn_free_queue(icn_card * card, int channel) { + struct sk_buff_head *queue = &card->spqueue[channel]; struct sk_buff *skb; while ((skb = skb_dequeue(queue))) dev_kfree_skb(skb, FREE_WRITE); + card->sndcount[channel] = 0; } /* Put a value into a shift-register, highest bit first. @@ -235,7 +257,7 @@ 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; @@ -275,7 +297,7 @@ } 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, dev.channel); #endif } restore_flags(flags); @@ -291,7 +313,7 @@ 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", dev.chanlock); #endif save_flags(flags); cli(); @@ -501,7 +523,6 @@ int command; int action; } icn_stat; - /* *INDENT-OFF* */ static icn_stat icn_stat_table[] = { @@ -519,10 +540,13 @@ {"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 */ + {"E_L1: ACTIVATION FAILED", + ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */ {NULL, 0, -1} }; /* *INDENT-ON* */ + /* * Check Statusqueue-Pointer from isdn-cards. * If there are new status-replies from the interface, check @@ -562,7 +586,7 @@ case 2: card->flags &= ~((channel) ? ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE); - icn_free_queue(&card->spqueue[channel]); + icn_free_queue(card, channel); save_flags(flags); cli(); card->rcvidx[channel] = 0; @@ -571,20 +595,28 @@ 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)) + char *t = status + 6; + char *s = strpbrk(t, ","); + + *s++ = '\0'; + strncpy(cmd.parm.setup.phone, t, + sizeof(cmd.parm.setup.phone)); + s = strpbrk(t = s, ","); + *s++ = '\0'; + if (!strlen(t)) cmd.parm.setup.si1 = 0; else - cmd.parm.setup.si1 = simple_strtoul(s, NULL, 10); - s = strtok(NULL, ","); - if (!strlen(s)) + cmd.parm.setup.si1 = + simple_strtoul(t, NULL, 10); + s = strpbrk(t = s, ","); + *s++ = '\0'; + if (!strlen(t)) 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.si2 = + simple_strtoul(t, NULL, 10); + strncpy(cmd.parm.setup.eazmsn, s, + sizeof(cmd.parm.setup.eazmsn)); } cmd.parm.setup.plan = 0; cmd.parm.setup.screen = 0; @@ -613,6 +645,13 @@ strncpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num) - 1); break; case 8: + dflag = 3; + card->flags &= ~ICN_FLAGS_B1ACTIVE; + icn_free_queue(card, 0); + save_flags(flags); + cli(); + card->rcvidx[0] = 0; + restore_flags(flags); cmd.arg = 0; cmd.driver = card->myid; card->interface.statcallb(&cmd); @@ -621,6 +660,12 @@ cmd.driver = card->myid; card->interface.statcallb(&cmd); cmd.command = ISDN_STAT_BHUP; + card->flags &= ~ICN_FLAGS_B2ACTIVE; + icn_free_queue(card, 1); + save_flags(flags); + cli(); + card->rcvidx[1] = 0; + restore_flags(flags); cmd.arg = 1; cmd.driver = card->myid; card->interface.statcallb(&cmd); @@ -867,12 +912,14 @@ #ifdef BOOT_DEBUG 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; } + if ((ret = copy_from_user(codebuf, buffer, ICN_CODE_STAGE1))) { + kfree(codebuf); + return ret; + } save_flags(flags); cli(); if (!card->rvalid) { @@ -920,7 +967,6 @@ 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"); @@ -992,7 +1038,10 @@ while (left) { if (sbfree) { /* If there is a free buffer... */ cnt = MIN(256, left); - copy_from_user(codebuf, p, cnt); + if (copy_from_user(codebuf, p, cnt)) { + icn_maprelease_channel(card, 0); + return -EFAULT; + } memcpy_toio(&sbuf_l, codebuf, cnt); /* copy data */ sbnext; /* switch to next buffer */ p += cnt; @@ -1290,17 +1339,15 @@ case ICN_IOCTL_GETDOUBLE: return (int) card->doubleS0; case ICN_IOCTL_DEBUGVAR: - if ((i = verify_area(VERIFY_WRITE, - (void *) a, - sizeof(ulong) * 2))) + if ((i = copy_to_user((char *) a, + (char *) &card, sizeof(ulong)))) 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)); + if ((i = copy_to_user((char *) a, + (char *) &l, sizeof(ulong)))) + return i; } return 0; case ICN_IOCTL_LOADBOOT: @@ -1321,9 +1368,8 @@ case ICN_IOCTL_ADDCARD: if (!dev.firstload) return -EBUSY; - if ((i = verify_area(VERIFY_READ, (void *) a, sizeof(icn_cdef)))) + if ((i = copy_from_user((char *) &cdef, (char *) a, sizeof(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: @@ -1774,7 +1820,7 @@ card->rvalid = 0; } for (i = 0; i < ICN_BCH; i++) - icn_free_queue(&card->spqueue[i]); + icn_free_queue(card, i); } card = card->next; } diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/isdn_audio.c linux/drivers/isdn/isdn_audio.c --- v2.1.41/linux/drivers/isdn/isdn_audio.c Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/isdn_audio.c Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: isdn_audio.c,v 1.7 1997/02/03 22:44:11 fritz Exp $ +/* $Id: isdn_audio.c,v 1.8 1997/03/02 14:29:16 fritz Exp $ * Linux ISDN subsystem, audio conversion and compression (linklevel). * @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_audio.c,v $ + * Revision 1.8 1997/03/02 14:29:16 fritz + * More ttyI related cleanup. + * * Revision 1.7 1997/02/03 22:44:11 fritz * Reformatted according CodingStyle * @@ -50,7 +53,7 @@ #include "isdn_audio.h" #include "isdn_common.h" -char *isdn_audio_revision = "$Revision: 1.7 $"; +char *isdn_audio_revision = "$Revision: 1.8 $"; /* * Misc. lookup-tables. @@ -529,14 +532,7 @@ 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++) { @@ -597,6 +593,14 @@ *p++ = 0x10; *p = what; skb_trim(skb, 2); + if (skb_headroom(skb) < sizeof(isdn_audio_skb)) { + printk(KERN_WARNING + "isdn_audio: insufficient skb_headroom, dropping\n"); + kfree_skb(skb, FREE_READ); + return; + } + ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; + ISDN_AUDIO_SKB_LOCK(skb) = 0; save_flags(flags); cli(); di = info->isdn_driver; diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/isdn_cards.c linux/drivers/isdn/isdn_cards.c --- v2.1.41/linux/drivers/isdn/isdn_cards.c Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/isdn_cards.c Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: isdn_cards.c,v 1.3 1997/02/03 23:31:14 fritz Exp $ +/* $Id: isdn_cards.c,v 1.6 1997/04/23 18:56:03 fritz Exp $ * Linux ISDN subsystem, initialization for non-modularized drivers. * @@ -19,6 +19,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_cards.c,v $ + * Revision 1.6 1997/04/23 18:56:03 fritz + * Old Teles driver removed, Changed doc and scripts accordingly. + * + * Revision 1.5 1997/03/30 17:10:36 calle + * added support for AVM-B1-PCI card. + * + * Revision 1.4 1997/03/04 21:59:44 calle + * Added AVM-B1-CAPI2.0 driver + * * Revision 1.3 1997/02/03 23:31:14 fritz * Reformatted according CodingStyle * @@ -36,10 +45,6 @@ extern void icn_init(void); #endif -#ifdef CONFIG_ISDN_DRV_TELES -extern void teles_init(void); -#endif - #ifdef CONFIG_ISDN_DRV_HISAX extern void HiSax_init(void); #endif @@ -48,19 +53,33 @@ extern void pcbit_init(void); #endif +#ifdef CONFIG_ISDN_DRV_AVMB1 +extern void avmb1_init(void); +extern void capi_init(void); +extern void capidrv_init(void); +#ifdef CONFIG_PCI +extern int b1pci_init(void); +#endif +#endif + void isdn_cards_init(void) { #if CONFIG_ISDN_DRV_ICN icn_init(); #endif -#if CONFIG_ISDN_DRV_TELES - teles_init(); -#endif #ifdef CONFIG_ISDN_DRV_HISAX HiSax_init(); #endif #if CONFIG_ISDN_DRV_PCBIT pcbit_init(); +#endif +#ifdef CONFIG_ISDN_DRV_AVMB1 + avmb1_init(); +#ifdef CONFIG_PCI + b1pci_init(); +#endif + capi_init(); + capidrv_init(); #endif } diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- v2.1.41/linux/drivers/isdn/isdn_common.c Fri Apr 4 08:52:19 1997 +++ linux/drivers/isdn/isdn_common.c Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.34 1997/02/10 20:12:43 fritz Exp $ +/* $Id: isdn_common.c,v 1.44 1997/05/27 15:17:23 fritz Exp $ * Linux ISDN subsystem, common used functions (linklevel). * @@ -21,6 +21,43 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_common.c,v $ + * Revision 1.44 1997/05/27 15:17:23 fritz + * Added changes for recent 2.1.x kernels: + * changed return type of isdn_close + * queue_task_* -> queue_task + * clear/set_bit -> test_and_... where apropriate. + * changed type of hard_header_cache parameter. + * + * Revision 1.43 1997/03/31 14:09:43 fritz + * Fixed memory leak in isdn_close(). + * + * Revision 1.42 1997/03/30 16:51:08 calle + * changed calls to copy_from_user/copy_to_user and removed verify_area + * were possible. + * + * Revision 1.41 1997/03/24 22:54:41 fritz + * Some small fixes in debug code. + * + * Revision 1.40 1997/03/08 08:13:51 fritz + * Bugfix: IIOCSETMAP (Set mapping) was broken. + * + * Revision 1.39 1997/03/07 01:32:54 fritz + * Added proper ifdef's for CONFIG_ISDN_AUDIO + * + * Revision 1.38 1997/03/05 21:15:02 fritz + * Fix: reduced stack usage of isdn_ioctl() and isdn_set_allcfg() + * + * Revision 1.37 1997/03/02 14:29:18 fritz + * More ttyI related cleanup. + * + * Revision 1.36 1997/02/28 02:32:40 fritz + * Cleanup: Moved some tty related stuff from isdn_common.c + * to isdn_tty.c + * Bugfix: Bisync protocol did not behave like documented. + * + * Revision 1.35 1997/02/21 13:01:19 fritz + * Changes CAUSE message output in kernel log. + * * Revision 1.34 1997/02/10 20:12:43 fritz * Changed interface for reporting incoming calls. * @@ -177,12 +214,11 @@ #include "isdn_cards.h" /* Debugflags */ -#undef ISDN_DEBUG_STATCALLB -#define NEW_ISDN_TIMER_CTRL +#undef ISDN_DEBUG_STATCALLB isdn_dev *dev = (isdn_dev *) 0; -static char *isdn_revision = "$Revision: 1.34 $"; +static char *isdn_revision = "$Revision: 1.44 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -299,9 +335,6 @@ save_flags(flags); cli(); del_timer(&dev->timer); -#ifndef NEW_ISDN_TIMER_CTRL - dev->timer.function = isdn_timer_funct; -#endif dev->timer.expires = jiffies + ISDN_TIMER_RES; add_timer(&dev->timer); restore_flags(flags); @@ -324,20 +357,11 @@ dev->tflags |= tf; else 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; add_timer(&dev->timer); } -#else - if (dev->tflags) { - del_timer(&dev->timer); - dev->timer.function = isdn_timer_funct; - dev->timer.expires = jiffies + ISDN_TIMER_RES; - add_timer(&dev->timer); - } -#endif restore_flags(flags); } @@ -347,13 +371,7 @@ static void isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb) { - ulong flags; int i; - int midx; -#ifdef CONFIG_ISDN_AUDIO - int ifmt; -#endif - modem_info *info; if ((i = isdn_dc2minor(di, channel)) == -1) { isdn_trash_skb(skb, FREE_READ); @@ -367,86 +385,8 @@ /* No network-device found, deliver to tty or raw-channel */ 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); + if (isdn_tty_rcv_skb(i, di, channel, skb)) return; - } - info = &dev->mdm.info[midx]; -#ifdef CONFIG_ISDN_AUDIO - ifmt = 1; - - 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); - 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; - } - 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); @@ -470,12 +410,10 @@ isdn_status_callback(isdn_ctrl * c) { int di; - int mi; ulong flags; int i; int r; int retval = 0; - modem_info *info; isdn_ctrl cmd; di = c->driver; @@ -488,7 +426,8 @@ return 0; if (isdn_net_stat_callback(i, c->command)) return 0; - isdn_tty_bsent(di, c->arg); + if (isdn_tty_stat_callback(i, c)) + return 0; wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]); break; case ISDN_STAT_STAVAIL: @@ -511,7 +450,7 @@ 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->parm.num); #endif if (dev->global_flags & ISDN_GLOBAL_STOPPED) { cmd.driver = di; @@ -528,16 +467,12 @@ 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. + /* No network-device replies. + * Try ttyI's */ - 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); + if (isdn_tty_find_icall(di, c->arg, c->parm.setup) >= 0) retval = 1; - } else if (dev->drv[di]->reject_bus) { + else if (dev->drv[di]->reject_bus) { cmd.driver = di; cmd.arg = c->arg; cmd.command = ISDN_CMD_HANGUP; @@ -582,7 +517,7 @@ 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->parm.num); #endif if (dev->global_flags & ISDN_GLOBAL_STOPPED) return 0; @@ -591,14 +526,11 @@ 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->parm.num); #endif - 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); - } + printk(KERN_INFO "isdn: %s,ch%ld cause: %s\n", + dev->drvid[di], c->arg, c->parm.num); + isdn_tty_stat_callback(i, c); break; case ISDN_STAT_DCONN: if (i < 0) @@ -608,24 +540,16 @@ #endif if (dev->global_flags & ISDN_GLOBAL_STOPPED) return 0; - /* Find any network-device, waiting for D-channel setup */ + /* Find any net-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]; - if (info->flags & - (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) { - if (info->dialing == 1) { - info->dialing = 2; - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_ACCEPTB; - dev->drv[di]->interface->command(&cmd); - return 0; - } - } + /* Find any ttyI, waiting for D-channel setup */ + if (isdn_tty_stat_callback(i, c)) { + cmd.driver = di; + cmd.arg = c->arg; + cmd.command = ISDN_CMD_ACCEPTB; + dev->drv[di]->interface->command(&cmd); + break; } break; case ISDN_STAT_DHUP: @@ -641,24 +565,8 @@ /* 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]; - if (info->flags & - (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) { - if (info->dialing == 1) { - info->dialing = 0; - isdn_tty_modem_result(7, info); - } - if (info->online) - isdn_tty_modem_result(3, info); -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n"); -#endif - isdn_tty_modem_hup(info, 0); - return 0; - } - } + if (isdn_tty_stat_callback(i, c)) + break; break; case ISDN_STAT_BCONN: if (i < 0) @@ -673,26 +581,8 @@ 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]; - if (info->flags & - (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) { - info->msr |= UART_MSR_DCD; - 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 (isdn_tty_stat_callback(i, c)) + break; break; case ISDN_STAT_BHUP: if (i < 0) @@ -704,20 +594,8 @@ 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]; - if (info->flags & - (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) { - if (info->msr & UART_MSR_DCD) - isdn_tty_modem_result(3, info); - info->msr &= ~(UART_MSR_DCD | UART_MSR_RI); -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n"); -#endif - isdn_tty_modem_hup(info, 0); - } - } + if (isdn_tty_stat_callback(i, c)) + break; break; case ISDN_STAT_NODCH: if (i < 0) @@ -729,47 +607,20 @@ return 0; if (isdn_net_stat_callback(i, c->command)) break; - if ((mi = dev->m_idx[i]) >= 0) { - 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; - if (info->online) { - isdn_tty_modem_result(3, info); - info->online = 0; - } - } - } + if (isdn_tty_stat_callback(i, c)) + break; break; case ISDN_STAT_ADDCH: break; case ISDN_STAT_UNLOAD: save_flags(flags); cli(); + isdn_tty_stat_callback(i, c); 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); @@ -835,6 +686,7 @@ while (left) { if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel]))) break; +#ifdef CONFIG_ISDN_AUDIO if (ISDN_AUDIO_SKB_LOCK(skb)) break; ISDN_AUDIO_SKB_LOCK(skb) = 1; @@ -868,6 +720,7 @@ if (count_pull >= skb->len) dflag = 1; } else { +#endif /* No DLE's in buff, so simply copy it */ dflag = 1; if ((count_pull = skb->len) > left) { @@ -881,7 +734,9 @@ memcpy(cp, skb->data, count_put); cp += count_put; left -= count_put; +#ifdef CONFIG_ISDN_AUDIO } +#endif count += count_put; if (fp) { memset(fp, 0, count_put); @@ -893,7 +748,9 @@ */ if (fp) *(fp - 1) = 0xff; +#ifdef CONFIG_ISDN_AUDIO ISDN_AUDIO_SKB_LOCK(skb) = 0; +#endif skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]); isdn_trash_skb(skb, FREE_READ); } else { @@ -902,7 +759,9 @@ * but we pull off the data we got until now. */ skb_pull(skb, count_pull); +#ifdef CONFIG_ISDN_AUDIO ISDN_AUDIO_SKB_LOCK(skb) = 0; +#endif } dev->drv[di]->rcvcount[channel] -= count_put; } @@ -1008,7 +867,8 @@ p = isdn_statstr(); file->private_data = 0; if ((len = strlen(p)) <= count) { - copy_to_user(buf, p, len); + if (copy_to_user(buf, p, len)) + return -EFAULT; file->f_pos += len; return len; } @@ -1190,29 +1050,24 @@ int ret; int i; ulong flags; - char buf[1024]; isdn_net_ioctl_cfg cfg; isdn_net_ioctl_phone phone; if ((ret = isdn_net_rmall())) return ret; + if ((ret = copy_from_user((char *) &i, src, sizeof(int)))) + return ret; save_flags(flags); cli(); - 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; + int phone_len; + int out_flag; - if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(cfg)))) { + if ((ret = copy_from_user((char *) &cfg, 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); @@ -1222,49 +1077,31 @@ 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) { - if ((c2 = strchr(c, ' '))) - *c2++ = '\0'; - strcpy(phone.phone, c); - strcpy(phone.name, cfg.name); - phone.outgoing = 0; - if ((ret = isdn_net_addphone(&phone))) { + phone_len = out_flag = 0; + while (out_flag < 2) { + if ((ret = verify_area(VERIFY_READ, src, 1))) { restore_flags(flags); return ret; } - if (c2) - c = c2; - else - c += strlen(c); - } - 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) { - if ((c2 = strchr(c, ' '))) - *c2++ = '\0'; - strcpy(phone.phone, c); - strcpy(phone.name, cfg.name); - phone.outgoing = 1; - if ((ret = isdn_net_addphone(&phone))) { - restore_flags(flags); - return ret; + GET_USER(phone.phone[phone_len], src++); + if ((phone.phone[phone_len] == ' ') || + (phone.phone[phone_len] == '\0')) { + if (phone_len) { + phone.phone[phone_len] = '\0'; + strcpy(phone.name, cfg.name); + phone.outgoing = out_flag; + if ((ret = isdn_net_addphone(&phone))) { + restore_flags(flags); + return ret; + } + } else + out_flag++; + phone_len = 0; } - if (c2) - c = c2; - else - c += strlen(c); + if (++phone_len >= sizeof(phone.phone)) + printk(KERN_WARNING + "%s: IIOCSETSET phone number too long, ignored\n", + cfg.name); } i--; } @@ -1307,9 +1144,15 @@ 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); + if (copy_to_user(dest, p->local.name, 10)) { + restore_flags(flags); + return -EFAULT; + } dest += 10; - copy_to_user(dest, (char *) &cfg, sizeof(cfg)); + if (copy_to_user(dest, (char *) &cfg, sizeof(cfg))) { + restore_flags(flags); + return -EFAULT; + } dest += sizeof(cfg); strcpy(phone.name, p->local.name); phone.outgoing = 0; @@ -1340,12 +1183,22 @@ int drvidx; int chidx; int ret; + int i; + char *p; char *s; - char name[10]; - char bname[21]; - isdn_ioctl_struct iocts; - isdn_net_ioctl_phone phone; - isdn_net_ioctl_cfg cfg; + union iocpar { + char name[10]; + char bname[22]; + isdn_ioctl_struct iocts; + isdn_net_ioctl_phone phone; + isdn_net_ioctl_cfg cfg; + } iocpar; + +#define name iocpar.name +#define bname iocpar.bname +#define iocts iocpar.iocts +#define phone iocpar.phone +#define cfg iocpar.cfg if (minor == ISDN_MINOR_STATUS) { switch (cmd) { @@ -1389,62 +1242,54 @@ case IIOCNETAIF: /* Add a network-interface */ if (arg) { - if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name)))) + if ((ret = copy_from_user(name, (char *) 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))) + if ((ret = copy_to_user((char *) arg, s, 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)))) + if ((ret = copy_from_user(bname, (char *) arg, sizeof(bname) - 1))) 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))) + if ((ret = copy_to_user((char *) arg, s, 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)))) + if ((ret = copy_from_user(name, (char *) 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)))) + if ((ret = copy_from_user((char *) &cfg, (char *) 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)))) + if ((ret = copy_from_user((char *) &cfg, (char *) 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)))) + if ((ret = copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg)))) return ret; - copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg)); } return ret; } else @@ -1452,70 +1297,56 @@ case IIOCNETANM: /* Add a phone-number to a network-interface */ if (arg) { - if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone)))) + if ((ret = copy_from_user((char *) &phone, (char *) 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)))) + if ((ret = copy_from_user((char *) &phone, (char *) 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)))) + if ((ret = copy_from_user((char *) &phone, (char *) 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)))) + if ((ret = copy_from_user(name, (char *) 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) { - if ((ret = verify_area(VERIFY_READ, - (void *) arg, - sizeof(name)))) - return ret; - } else + if (!arg) return -EINVAL; - copy_from_user(name, (char *) arg, sizeof(name)); + if ((ret = copy_from_user(name, (char *) arg, sizeof(name)))) + return ret; return isdn_ppp_dial_slave(name); case IIOCNETDLN: - if (arg) { - if ((ret = verify_area(VERIFY_READ, - (void *) arg, - sizeof(name)))) - return ret; - } else + if (!arg) return -EINVAL; - copy_from_user(name, (char *) arg, sizeof(name)); + if ((ret = copy_from_user(name, (char *) arg, sizeof(name)))) + return ret; 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 + if (!arg) return -EINVAL; + if ((ret = copy_from_user(name, (char *) arg, sizeof(name)))) + return ret; + return isdn_net_force_hangup(name); break; #endif /* CONFIG_NETDEVICES */ case IIOCSETVER: @@ -1535,11 +1366,9 @@ if (arg) { int i; char *p; - if ((ret = verify_area(VERIFY_READ, (void *) arg, - sizeof(isdn_ioctl_struct)))) + if ((ret = copy_from_user((char *) &iocts, (char *) 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; @@ -1587,10 +1416,12 @@ return ret; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - copy_to_user(p, dev->mdm.info[i].emu.profile, - ISDN_MODEM_ANZREG); + if (copy_to_user(p, dev->mdm.info[i].emu.profile, + ISDN_MODEM_ANZREG)) + return -EFAULT; p += ISDN_MODEM_ANZREG; - copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN); + 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; @@ -1609,10 +1440,12 @@ return ret; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - copy_from_user(dev->mdm.info[i].emu.profile, p, - ISDN_MODEM_ANZREG); + if ((ret = copy_from_user(dev->mdm.info[i].emu.profile, p, + ISDN_MODEM_ANZREG))) + return ret; p += ISDN_MODEM_ANZREG; - copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN); + if ((ret = copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))) + return ret; p += ISDN_MSNLEN; } return 0; @@ -1623,14 +1456,11 @@ 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, + if ((ret = copy_from_user((char *) &iocts, + (char *) 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++) @@ -1643,37 +1473,54 @@ 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, ","); + int loop = 1; + + p = (char *) iocts.arg; i = 0; - while ((p) && (i < 10)) { - strcpy(dev->drv[drvidx]->msn2eaz[i++], p); - p = strtok(NULL, ","); + while (loop) { + int j = 0; + + while (1) { + if ((ret = verify_area(VERIFY_READ, p, 1))) + return ret; + GET_USER(bname[j], p++); + switch (bname[j]) { + case '\0': + loop = 0; + /* Fall through */ + case ',': + bname[j] = '\0'; + strcpy(dev->drv[drvidx]->msn2eaz[i], bname); + j = ISDN_MSNLEN; + break; + default: + j++; + } + if (j >= ISDN_MSNLEN) + break; + } + if (++i > 9) + break; } } 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); + p = (char *) iocts.arg; + for (i = 0; i < 10; i++) { + sprintf(bname, "%s%s", + strlen(dev->drv[drvidx]->msn2eaz[i]) ? + dev->drv[drvidx]->msn2eaz[i] : "-", + (i < 9) ? "," : "\0"); + if ((ret = copy_to_user(p, bname, strlen(bname) + 1))) + return ret; + p += strlen(bname); + } } return 0; } else return -EINVAL; case IIOCDBGVAR: if (arg) { - if ((ret = verify_area(VERIFY_WRITE, (void *) arg, sizeof(ulong)))) + if ((ret = copy_to_user((char *) arg, (char *) &dev, sizeof(ulong)))) return ret; - copy_to_user((char *) arg, (char *) &dev, sizeof(ulong)); return 0; } else return -EINVAL; @@ -1686,10 +1533,8 @@ if (arg) { int i; char *p; - if ((ret = verify_area(VERIFY_READ, (void *) arg, - sizeof(isdn_ioctl_struct)))) + if ((ret = copy_from_user((char *) &iocts, (char *) 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; @@ -1712,7 +1557,8 @@ 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)); + if ((copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct)))) + return -EFAULT; return ret; } else return -EINVAL; @@ -1723,6 +1569,12 @@ return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg)); #endif return -ENODEV; + +#undef name +#undef bname +#undef iocts +#undef phone +#undef cfg } /* @@ -1790,7 +1642,7 @@ return -ENODEV; } -static int +static CLOSETYPE isdn_close(struct inode *ino, struct file *filep) { uint minor = MINOR(ino->i_rdev); @@ -1807,39 +1659,40 @@ q->next = p->next; else dev->infochain = (infostruct *) (p->next); - return 0; + kfree(p); + return CLOSEVAL; } q = p; p = (infostruct *) (p->next); } printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n"); - return 0; + return CLOSEVAL; } if (minor < ISDN_MINOR_CTRL) { drvidx = isdn_minor2drv(minor); if (drvidx < 0) - return; + return CLOSEVAL; c.command = ISDN_CMD_UNLOCK; c.driver = drvidx; (void) dev->drv[drvidx]->interface->command(&c); - return 0; + return CLOSEVAL; } if (minor <= ISDN_MINOR_CTRLMAX) { drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); if (drvidx < 0) - return 0; + return CLOSEVAL; if (dev->profd == current) dev->profd = NULL; c.command = ISDN_CMD_UNLOCK; c.driver = drvidx; (void) dev->drv[drvidx]->interface->command(&c); - return 0; + return CLOSEVAL; } #ifdef CONFIG_ISDN_PPP if (minor <= ISDN_MINOR_PPPMAX) isdn_ppp_release(minor - ISDN_MINOR_PPP, filep); #endif - return 0; + return CLOSEVAL; } static struct file_operations isdn_fops = @@ -2238,10 +2091,8 @@ return -EIO; } memset((char *) dev, 0, sizeof(isdn_dev)); -#ifdef NEW_ISDN_TIMER_CTRL init_timer(&dev->timer); dev->timer.function = isdn_timer_funct; -#endif for (i = 0; i < ISDN_MAX_CHANNELS; i++) { dev->drvmap[i] = -1; dev->chanmap[i] = -1; diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/isdn_common.h linux/drivers/isdn/isdn_common.h --- v2.1.41/linux/drivers/isdn/isdn_common.h Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/isdn_common.h Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: isdn_common.h,v 1.5 1997/02/10 10:05:45 fritz Exp $ +/* $Id: isdn_common.h,v 1.6 1997/02/28 02:32:44 fritz Exp $ * header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel). * @@ -21,6 +21,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_common.h,v $ + * Revision 1.6 1997/02/28 02:32:44 fritz + * Cleanup: Moved some tty related stuff from isdn_common.c + * to isdn_tty.c + * Bugfix: Bisync protocol did not behave like documented. + * * Revision 1.5 1997/02/10 10:05:45 fritz * More changes for Kernel 2.1.X * Symbol information moved to isdn_syms.c @@ -45,6 +50,7 @@ #undef ISDN_DEBUG_MODEM_HUP #undef ISDN_DEBUG_MODEM_ICALL #undef ISDN_DEBUG_MODEM_DUMP +#undef ISDN_DEBUG_MODEM_VOICE #undef ISDN_DEBUG_AT #undef ISDN_DEBUG_NET_DUMP #undef ISDN_DEBUG_NET_DIAL diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c --- v2.1.41/linux/drivers/isdn/isdn_net.c Wed May 28 10:51:31 1997 +++ linux/drivers/isdn/isdn_net.c Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.37 1997/02/11 18:32:51 fritz Exp $ +/* $Id: isdn_net.c,v 1.44 1997/05/27 15:17:26 fritz Exp $ * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -21,6 +21,32 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.c,v $ + * Revision 1.44 1997/05/27 15:17:26 fritz + * Added changes for recent 2.1.x kernels: + * changed return type of isdn_close + * queue_task_* -> queue_task + * clear/set_bit -> test_and_... where apropriate. + * changed type of hard_header_cache parameter. + * + * Revision 1.43 1997/03/30 16:51:13 calle + * changed calls to copy_from_user/copy_to_user and removed verify_area + * were possible. + * + * Revision 1.42 1997/03/11 08:43:51 fritz + * Perform a hangup if number is deleted while dialing. + * + * Revision 1.41 1997/03/08 08:16:31 fritz + * Bugfix: Deleting a phone number during dial gave unpredictable results. + * + * Revision 1.40 1997/03/05 21:16:08 fritz + * Fix: did not compile with 2.1.27 + * + * Revision 1.39 1997/03/04 21:36:52 fritz + * Added sending ICMP messages when no connetion is possible. + * + * Revision 1.38 1997/02/23 23:41:14 fritz + * Bugfix: Slave interfaces have to be hung up before master. + * * Revision 1.37 1997/02/11 18:32:51 fritz * Bugfix in isdn_ppp_free_mpqueue(). * @@ -170,6 +196,7 @@ #include #include #include +#include #include "isdn_common.h" #include "isdn_net.h" #ifdef CONFIG_ISDN_PPP @@ -184,13 +211,25 @@ static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *); static void dev_purge_queues(struct device *dev); /* move this to net/core/dev.c */ -char *isdn_net_revision = "$Revision: 1.37 $"; +char *isdn_net_revision = "$Revision: 1.44 $"; /* * Code for raw-networking over ISDN */ static void +isdn_net_unreachable(struct device *dev, struct sk_buff *skb, char *reason) +{ + printk(KERN_DEBUG "isdn_net: %s: %s, send ICMP\n", + dev->name, reason); + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0 +#if (LINUX_VERSION_CODE < 0x02010f) /* 2.1.15 */ + ,dev +#endif + ); +} + +static void isdn_net_reset(struct device *dev) { ulong flags; @@ -513,6 +552,7 @@ isdn_net_dev *p = dev->netdev; int anymore = 0; int i; + int flags; isdn_ctrl cmd; while (p) { @@ -528,7 +568,16 @@ /* Initiate dialout. Set phone-number-pointer to first number * of interface. */ + save_flags(flags); + cli(); p->local.dial = p->local.phone[1]; + restore_flags(flags); + if (!p->local.dial) { + printk(KERN_WARNING "%s: phone number deleted?\n", + p->local.name); + isdn_net_hangup(&p->dev); + break; + } anymore = 1; p->local.dialstate++; /* Fall through */ @@ -560,39 +609,41 @@ 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; + save_flags(flags); + cli(); + if (!p->local.dial) { + restore_flags(flags); + printk(KERN_WARNING "%s: phone number deleted?\n", + p->local.name); + isdn_net_hangup(&p->dev); + break; } if (!strcmp(p->local.dial->num, "LEASED")) { + restore_flags(flags); p->local.dialstate = 4; printk(KERN_INFO "%s: Open leased line ...\n", p->local.name); } else { + sprintf(cmd.parm.setup.phone, "%s", 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++; + } + restore_flags(flags); 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); + strcpy(dev->num[i], cmd.parm.setup.phone); 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.dialretry - 1, cmd.parm.setup.phone); p->local.dtimer = 0; #ifdef ISDN_DEBUG_NET_DIAL printk(KERN_DEBUG "dial: d=%d c=%d\n", p->local.isdn_device, @@ -600,6 +651,15 @@ #endif dev->drv[p->local.isdn_device]->interface->command(&cmd); } + 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; + } anymore = 1; p->local.dialstate = (p->local.cbdelay && @@ -956,13 +1016,21 @@ lp->l3_proto, lp->pre_device, lp->pre_channel)) < 0) { + restore_flags(flags); +#if 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 */ return 1; +#else + isdn_net_unreachable(ndev, skb, + "No channel"); + dev_kfree_skb(skb, FREE_WRITE); + ndev->tbusy = 0; + return 0; +#endif } /* Log packet, which triggered dialing */ if (dev->net_verbose) @@ -1000,20 +1068,8 @@ 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); + isdn_net_unreachable(ndev, skb, + "No phone number"); dev_kfree_skb(skb, FREE_WRITE); ndev->tbusy = 0; return 0; @@ -1045,7 +1101,6 @@ dev->tbusy = 1; dev->start = 0; - isdn_net_hangup(dev); if ((p = (((isdn_net_local *) dev->priv)->slave))) { /* If this interface has slaves, stop them also */ while (p) { @@ -1055,6 +1110,7 @@ p = (((isdn_net_local *) p->priv)->slave); } } + isdn_net_hangup(dev); isdn_MOD_DEC_USE_COUNT(); return 0; } @@ -2314,11 +2370,10 @@ put_user(' ', phones++); count++; } - if ((ret = verify_area(VERIFY_WRITE, (void *) phones, strlen(n->num) + 1))) { + if ((ret = copy_to_user(phones, n->num, strlen(n->num) + 1))) { restore_flags(flags); return ret; } - copy_to_user(phones, n->num, strlen(n->num) + 1); phones += strlen(n->num); count += strlen(n->num); more = 1; @@ -2340,12 +2395,17 @@ int inout = phone->outgoing & 1; isdn_net_phone *n; isdn_net_phone *m; + int flags; if (p) { + save_flags(flags); + cli(); n = p->local.phone[inout]; m = NULL; while (n) { if (!strcmp(n->num, phone->phone)) { + if (p->local.dial == n) + p->local.dial = n->next; if (m) m->next = n->next; else @@ -2356,6 +2416,7 @@ m = n; n = (isdn_net_phone *) n->next; } + restore_flags(flags); return -EINVAL; } return -ENODEV; @@ -2383,6 +2444,7 @@ } p->local.phone[i] = NULL; } + p->local.dial = NULL; restore_flags(flags); return 0; } @@ -2399,13 +2461,13 @@ if (p) { 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. */ while (q) { isdn_net_hangup(q); q = (((isdn_net_local *) q->priv)->slave); } + isdn_net_hangup(&p->dev); return 0; } return -ENODEV; diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c --- v2.1.41/linux/drivers/isdn/isdn_ppp.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/isdn_ppp.c Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.c,v 1.25 1997/02/12 20:37:35 hipp Exp $ +/* $Id: isdn_ppp.c,v 1.27 1997/03/30 16:51:17 calle Exp $ * * Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -19,6 +19,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ppp.c,v $ + * Revision 1.27 1997/03/30 16:51:17 calle + * changed calls to copy_from_user/copy_to_user and removed verify_area + * were possible. + * + * Revision 1.26 1997/02/23 16:53:44 hipp + * minor cleanup + * some initial changes for future PPP compresion + * added AC,PC compression for outgoing frames + * * Revision 1.25 1997/02/12 20:37:35 hipp * New ioctl() PPPIOCGCALLINFO, minor cleanup * @@ -138,6 +147,7 @@ static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto); static int isdn_ppp_if_get_unit(char *namebuf); +static int isdn_ppp_set_compressor(struct ippp_struct *is,int num); #ifdef CONFIG_ISDN_MPP static int isdn_ppp_bundle(struct ippp_struct *, int unit); @@ -150,9 +160,10 @@ static void isdn_ppp_free_mpqueue(isdn_net_dev *); #endif -char *isdn_ppp_revision = "$Revision: 1.25 $"; +char *isdn_ppp_revision = "$Revision: 1.27 $"; static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; +static struct isdn_ppp_compressor *ipc_head = NULL; extern int isdn_net_force_dial_lp(isdn_net_local *); @@ -371,6 +382,7 @@ if (is->debug & 0x1) printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, min, is->state); + is->compressor = NULL; is->lp = NULL; is->mp_seqno = 0; /* MP sequence number */ is->pppcfg = 0; /* ppp configuration */ @@ -451,9 +463,8 @@ int r; if (len <= 0) len = sizeof(unsigned long); - if ((r = verify_area(VERIFY_READ, (void *) b, len))) + if ((r = copy_from_user((void *) val, b, len))) return r; - copy_from_user((void *) val, b, len); return 0; } @@ -465,13 +476,11 @@ { int r; if (!str) { - if ((r = verify_area(VERIFY_WRITE, b, 4))) + if ((r = copy_to_user(b, (void *) &val, 4))) return r; - copy_to_user(b, (void *) &val, 4); } else { - if ((r = verify_area(VERIFY_WRITE, b, val))) + if ((r = copy_to_user(b, str, val))) return r; - copy_to_user(b, str, val); } return 0; } @@ -483,7 +492,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) { unsigned long val; - int r; + int num,r; struct ippp_struct *is; isdn_net_local *lp; @@ -592,16 +601,22 @@ return r; is->debug = val; break; - case PPPIOCSCOMPRESS: -#if 0 + case PPPIOCGCOMPRESSORS: { - struct ppp_option_data pod; - r = get_arg((void *) arg, &pod, sizeof(struct ppp_option_data)); - if (r) + unsigned long protos = 0; + struct isdn_ppp_compressor *ipc = ipc_head; + while(ipc) { + protos |= (0x1<num); + ipc = ipc->next; + } + if ((r = set_arg((void *) arg, protos, 0))) return r; - ippp_set_compression(is, &pod); } -#endif + break; + case PPPIOCSCOMPRESSOR: + if ((r = get_arg((void *) arg, &num, sizeof(int)))) + return r; + return isdn_ppp_set_compressor(is, num); break; case PPPIOCGCALLINFO: { @@ -789,9 +804,6 @@ if (!(is->state & IPPP_OPEN)) return 0; - if ((r = verify_area(VERIFY_WRITE, (void *) buf, count))) - return r; - save_flags(flags); cli(); @@ -802,7 +814,10 @@ } if (b->len < count) count = b->len; - copy_to_user(buf, b->buf, count); + if ((r = copy_to_user(buf, b->buf, count))) { + restore_flags(flags); + return r; + } kfree(b->buf); b->buf = NULL; is->first = b; @@ -839,7 +854,8 @@ * Don't reset huptimer for * LCP packets. (Echo requests). */ - copy_from_user(protobuf, buf, 4); + if (copy_from_user(protobuf, buf, 4)) + return -EFAULT; proto = PPP_PROTOCOL(protobuf); if (proto != PPP_LCP) lp->huptimer = 0; @@ -857,7 +873,8 @@ return count; } SET_SKB_FREE(skb); - copy_from_user(skb_put(skb, count), buf, count); + if (copy_from_user(skb_put(skb, count), buf, count)) + return -EFAULT; if (is->debug & 0x40) { printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len); isdn_ppp_frame_log("xmit", skb->data, skb->len, 32); @@ -1209,7 +1226,7 @@ isdn_net_local *lp, *mlp; isdn_net_dev *nd; - int proto = PPP_IP; /* 0x21 */ + unsigned int proto = PPP_IP; /* 0x21 */ struct ippp_struct *ipt, *ipts; @@ -1240,7 +1257,8 @@ 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(ipts->debug & 0x4) + 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); @@ -1248,7 +1266,7 @@ } } } - /* dstaddr change not so improtant */ + /* dstaddr change not so important */ #endif break; case ETH_P_IPX: @@ -1331,27 +1349,36 @@ ipts->mp_seqno++; nd->queue = nd->queue->next; if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) { - skb_push(skb, 3); + unsigned char *data = skb_push(skb, 3); mp_seqno &= 0xfff; - skb->data[0] = MP_BEGIN_FRAG | MP_END_FRAG | (mp_seqno >> 8); /* (B)egin & (E)ndbit .. */ - skb->data[1] = mp_seqno & 0xff; - skb->data[2] = proto; /* PID compression */ + data[0] = MP_BEGIN_FRAG | MP_END_FRAG | (mp_seqno >> 8); /* (B)egin & (E)ndbit .. */ + data[1] = mp_seqno & 0xff; + data[2] = proto; /* PID compression */ } else { - skb_push(skb, 5); - skb->data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */ - skb->data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */ - skb->data[2] = (mp_seqno >> 8) & 0xff; - skb->data[3] = (mp_seqno >> 0) & 0xff; - skb->data[4] = proto; /* PID compression */ + unsigned char *data = skb_push(skb, 5); + data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */ + data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */ + data[2] = (mp_seqno >> 8) & 0xff; + data[3] = (mp_seqno >> 0) & 0xff; + data[4] = proto; /* PID compression */ } proto = PPP_MP; /* MP Protocol, 0x003d */ } #endif - 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; + if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) { + unsigned char *data = skb_push(skb,1); + data[0] = proto & 0xff; + } + else { + unsigned char *data = skb_push(skb,2); + data[0] = (proto >> 8) & 0xff; + data[1] = proto & 0xff; + } + if(!(ipt->pppcfg & SC_COMP_AC)) { + unsigned char *data = skb_push(skb,2); + data[0] = 0xff; /* All Stations */ + data[1] = 0x03; /* Unnumbered information */ + } /* tx-stats are now updated via BSENT-callback */ @@ -1755,9 +1782,7 @@ } #endif } - copy_to_user(res, &t, sizeof(struct ppp_stats)); - return 0; - + return copy_to_user(res, &t, sizeof(struct ppp_stats)); } int @@ -1779,9 +1804,7 @@ case SIOCGPPPVER: r = (char *) ifr->ifr_ifru.ifru_data; len = strlen(PPP_VERSION) + 1; - error = verify_area(VERIFY_WRITE, r, len); - if (!error) - copy_to_user(r, PPP_VERSION, len); + error = copy_to_user(r, PPP_VERSION, len); break; case SIOCGPPPSTATS: error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev); @@ -1882,6 +1905,45 @@ #endif } + +int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc) +{ + ipc->next = ipc_head; + ipc->prev = NULL; + if(ipc_head) { + ipc_head->prev = ipc; + } + ipc_head = ipc; + return 0; +} + +int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc) +{ + if(ipc->prev) + ipc->prev->next = ipc->next; + else + ipc_head = ipc->next; + if(ipc->next) + ipc->next->prev = ipc->prev; + ipc->prev = ipc->next = NULL; + return 0; +} + +static int isdn_ppp_set_compressor(struct ippp_struct *is,int num) +{ + struct isdn_ppp_compressor *ipc = ipc_head; + + while(ipc) { + if(ipc->num == num) { + return 0; + is->compressor = ipc; + } + ipc = ipc->next; + } + return -EINVAL; +} + + #if 0 static struct symbol_table isdn_ppp_syms = { @@ -1891,3 +1953,7 @@ #include }; #endif + + + + diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c --- v2.1.41/linux/drivers/isdn/isdn_tty.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/isdn_tty.c Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.c,v 1.29 1997/02/16 12:11:51 fritz Exp $ +/* $Id: isdn_tty.c,v 1.41 1997/05/27 15:17:31 fritz Exp $ * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * @@ -20,6 +20,55 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.c,v $ + * Revision 1.41 1997/05/27 15:17:31 fritz + * Added changes for recent 2.1.x kernels: + * changed return type of isdn_close + * queue_task_* -> queue_task + * clear/set_bit -> test_and_... where apropriate. + * changed type of hard_header_cache parameter. + * + * Revision 1.40 1997/03/24 22:55:27 fritz + * Added debug code for status callbacks. + * + * Revision 1.39 1997/03/21 18:25:56 fritz + * Corrected CTS handling. + * + * Revision 1.38 1997/03/07 12:13:35 fritz + * Bugfix: Send audio in adpcm format was broken. + * Bugfix: CTS handling was wrong. + * + * Revision 1.37 1997/03/07 01:37:34 fritz + * Bugfix: Did not compile with CONFIG_ISDN_AUDIO disabled. + * Bugfix: isdn_tty_tint() did not handle lowlevel errors correctly. + * Bugfix: conversion was wrong when sending ulaw audio. + * Added proper ifdef's for CONFIG_ISDN_AUDIO + * + * Revision 1.36 1997/03/04 21:41:55 fritz + * Fix: Excessive stack usage of isdn_tty_senddown() + * and isdn_tty_end_vrx() could lead to problems. + * + * Revision 1.35 1997/03/02 19:05:52 fritz + * Bugfix: Avoid recursion. + * + * Revision 1.34 1997/03/02 14:29:22 fritz + * More ttyI related cleanup. + * + * Revision 1.33 1997/02/28 02:32:45 fritz + * Cleanup: Moved some tty related stuff from isdn_common.c + * to isdn_tty.c + * Bugfix: Bisync protocol did not behave like documented. + * + * Revision 1.32 1997/02/23 15:43:03 fritz + * Small change in handling of incoming calls + * documented in newest version of ttyI.4 + * + * Revision 1.31 1997/02/21 13:05:57 fritz + * Bugfix: Remote hangup did not set location-info on ttyI's + * + * Revision 1.30 1997/02/18 09:41:05 fritz + * Added support for bitwise access to modem registers (ATSx.y=n, ATSx.y?). + * Beautified output of AT&V. + * * Revision 1.29 1997/02/16 12:11:51 fritz * Added S13,Bit4 option. * @@ -136,6 +185,7 @@ * Initial revision * */ +#undef ISDN_TTY_STAT_DEBUG #define __NO_VERSION__ #include @@ -157,6 +207,10 @@ 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 *); +static void isdn_tty_modem_result(int, modem_info *); +#ifdef CONFIG_ISDN_AUDIO +static int isdn_tty_countDLE(unsigned char *, int); +#endif /* Leave this unchanged unless you know what you do! */ #define MODEM_PARANOIA_CHECK @@ -169,13 +223,13 @@ static int si2bit[8] = {4, 1, 4, 4, 4, 4, 4, 4}; -char *isdn_tty_revision = "$Revision: 1.29 $"; +char *isdn_tty_revision = "$Revision: 1.41 $"; #define DLE 0x10 #define ETX 0x03 #define DC4 0x14 -/* isdn_tty_try_read() is called from within isdn_receive_callback() +/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb() * to stuff incoming data directly into a tty's flip-buffer. This * is done to speed up tty-receiving if the receive-queue is empty. * This routine MUST be called with interrupts off. @@ -184,7 +238,7 @@ * 0 = Failure, data has to be buffered and later processed by * isdn_tty_readmodem(). */ -int +static int isdn_tty_try_read(modem_info * info, struct sk_buff *skb) { int c; @@ -195,24 +249,32 @@ if ((tty = info->tty)) { if (info->mcr & UART_MCR_RTS) { c = TTY_FLIPBUF_SIZE - tty->flip.count; - len = skb->len + ISDN_AUDIO_SKB_DLECOUNT(skb); + len = skb->len +#ifdef CONFIG_ISDN_AUDIO + + ISDN_AUDIO_SKB_DLECOUNT(skb) +#endif + ; if (c >= len) { +#ifdef CONFIG_ISDN_AUDIO 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 { +#endif 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; +#ifdef CONFIG_ISDN_AUDIO } +#endif if (info->emu.mdmreg[12] & 128) tty->flip.flag_buf_ptr[len - 1] = 0xff; - queue_task_irq_off(&tty->flip.tqueue, &tq_timer); + queue_task(&tty->flip.tqueue, &tq_timer); SET_SKB_FREE(skb); kfree_skb(skb, FREE_READ); return 1; @@ -263,7 +325,7 @@ tty->flip.flag_buf_ptr += r; tty->flip.char_buf_ptr += r; if (r) - queue_task_irq_off(&tty->flip.tqueue, &tq_timer); + queue_task(&tty->flip.tqueue, &tq_timer); restore_flags(flags); } } else @@ -282,6 +344,107 @@ isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0); } +int +isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb) +{ + ulong flags; + int midx; +#ifdef CONFIG_ISDN_AUDIO + int ifmt; +#endif + modem_info *info; + + if ((midx = dev->m_idx[i]) < 0) { + /* if midx is invalid, packet is not for tty */ + return 0; + } + info = &dev->mdm.info[midx]; +#ifdef CONFIG_ISDN_AUDIO + ifmt = 1; + + if (info->vonline) + isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt); +#endif + if ((info->online < 2) +#ifdef CONFIG_ISDN_AUDIO + && (!(info->vonline & 1)) +#endif + ) { + /* If Modem not listening, drop data */ + SET_SKB_FREE(skb); + kfree_skb(skb, FREE_READ); + return 1; + } + 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); +#ifdef CONFIG_ISDN_AUDIO + if (skb_headroom(skb) < sizeof(isdn_audio_skb)) { + printk(KERN_WARNING + "isdn_audio: insufficient skb_headroom, dropping\n"); + SET_SKB_FREE(skb); + kfree_skb(skb, FREE_READ); + return 1; + } + ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; + ISDN_AUDIO_SKB_LOCK(skb) = 0; + 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 1; + } + /* 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 +#ifdef CONFIG_ISDN_AUDIO + + ISDN_AUDIO_SKB_DLECOUNT(skb) +#endif + ); + restore_flags(flags); + /* Schedule dequeuing */ + if ((dev->modempoll) && (info->rcvsched)) + isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); + return 1; +} + void isdn_tty_cleanup_xmit(modem_info * info) { @@ -295,11 +458,13 @@ SET_SKB_FREE(skb); kfree_skb(skb, FREE_WRITE); } +#ifdef CONFIG_ISDN_AUDIO if (skb_queue_len(&info->dtmf_queue)) while ((skb = skb_dequeue(&info->dtmf_queue))) { SET_SKB_FREE(skb); kfree_skb(skb, FREE_WRITE); } +#endif restore_flags(flags); } @@ -314,7 +479,7 @@ return; len = skb->len; if ((slen = isdn_writebuf_skb_stub(info->isdn_driver, - info->isdn_channel, skb)) == len) { + info->isdn_channel, skb)) == len) { struct tty_struct *tty = info->tty; info->send_outstanding++; info->msr |= UART_MSR_CTS; @@ -325,13 +490,19 @@ wake_up_interruptible(&tty->write_wait); return; } - if (slen > 0) + if (slen < 0) { + /* Error: no channel, already shutdown, or wrong parameter */ + SET_SKB_FREE(skb); + dev_kfree_skb(skb, FREE_WRITE); + return; + } + if (slen) skb_pull(skb, slen); skb_queue_head(&info->xmit_queue, skb); } #ifdef CONFIG_ISDN_AUDIO -int +static int isdn_tty_countDLE(unsigned char *buf, int len) { int count = 0; @@ -369,9 +540,20 @@ case DC4: /* Abort RX */ info->vonline &= ~1; +#ifdef ISDN_DEBUG_MODEM_VOICE + printk(KERN_DEBUG + "DLEdown: got DLE-DC4, send DLE-ETX on ttyI%d\n", + info->line); +#endif isdn_tty_at_cout("\020\003", info); - if (!info->vonline) + if (!info->vonline) { +#ifdef ISDN_DEBUG_MODEM_VOICE + printk(KERN_DEBUG + "DLEdown: send VCON on ttyI%d\n", + info->line); +#endif isdn_tty_at_cout("\r\nVCON\r\n", info); + } /* Fall through */ case 'q': case 's': @@ -404,28 +586,22 @@ static int isdn_tty_end_vrx(const char *buf, int c, int from_user) { - char tmpbuf[VBUF]; - char *p; + char ch; - 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)) + if (from_user) + GET_USER(ch, buf); + else + ch = *buf; + if ((ch != 0x11) && (ch != 0x13)) return 1; - p++; + buf++; } return 0; } static int voice_cf[7] = -{1, 1, 4, 3, 2, 1, 1}; +{0, 0, 4, 3, 2, 0, 0}; #endif /* CONFIG_ISDN_AUDIO */ @@ -437,18 +613,36 @@ static void isdn_tty_senddown(modem_info * info) { - unsigned char *buf = info->xmit_buf; int buflen; int skb_res; +#ifdef CONFIG_ISDN_AUDIO + int audio_len; +#endif struct sk_buff *skb; unsigned long flags; +#ifdef CONFIG_ISDN_AUDIO + if (info->vonline & 4) { + info->vonline &= ~6; + if (!info->vonline) { +#ifdef ISDN_DEBUG_MODEM_VOICE + printk(KERN_DEBUG + "senddown: send VCON on ttyI%d\n", + info->line); +#endif + isdn_tty_at_cout("\r\nVCON\r\n", info); + } + } +#endif save_flags(flags); cli(); if (!(buflen = info->xmit_count)) { restore_flags(flags); return; } + if ((info->emu.mdmreg[12] & 0x10) != 0) + info->msr &= ~UART_MSR_CTS; + info->lsr &= ~UART_LSR_TEMT; if (info->isdn_driver < 0) { info->xmit_count = 0; restore_flags(flags); @@ -456,6 +650,26 @@ } skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4; #ifdef CONFIG_ISDN_AUDIO + if (info->vonline & 2) + audio_len = buflen * voice_cf[info->emu.vpar[3]]; + else + audio_len = 0; + skb = dev_alloc_skb(skb_res + buflen + audio_len); +#else + skb = dev_alloc_skb(skb_res + buflen); +#endif + if (!skb) { + restore_flags(flags); + printk(KERN_WARNING + "isdn_tty: Out of memory in ttyI%d senddown\n", + info->line); + return; + } + skb_reserve(skb, skb_res); + memcpy(skb_put(skb, buflen), info->xmit_buf, buflen); + info->xmit_count = 0; + restore_flags(flags); +#ifdef CONFIG_ISDN_AUDIO if (info->vonline & 2) { /* For now, ifmt is fixed to 1 (alaw), since this * is used with ISDN everywhere in the world, except @@ -464,21 +678,8 @@ * 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: @@ -486,55 +687,34 @@ /* 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); + audio_len = isdn_audio_adpcm2xlaw(info->adpcms, + ifmt, + skb->data, + skb_put(skb, audio_len), + buflen); + skb_pull(skb, buflen); + skb_trim(skb, audio_len); break; case 5: /* a-law */ if (!ifmt) - isdn_audio_alaw2ulaw(hbuf, buflen); - memcpy(skb_put(skb, buflen), hbuf, buflen); + isdn_audio_alaw2ulaw(skb->data, + buflen); break; case 6: /* u-law */ if (ifmt) - isdn_audio_ulaw2alaw(hbuf, buflen); - memcpy(skb_put(skb, buflen), hbuf, buflen); + isdn_audio_ulaw2alaw(skb->data, + 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 +#endif /* CONFIG_ISDN_AUDIO */ 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; } /************************************************************ @@ -566,7 +746,6 @@ 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; @@ -652,7 +831,7 @@ * ISDN-line (hangup). The usage-status is cleared * and some cleanup is done also. */ -void +static void isdn_tty_modem_hup(modem_info * info, int local) { isdn_ctrl cmd; @@ -664,20 +843,15 @@ printk(KERN_DEBUG "Mhup ttyI%d\n", info->line); #endif 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); + if (info->online) { + info->last_lhup = local; + info->online = 0; + /* NO CARRIER message */ + isdn_tty_modem_result(3, info); } - info->vonline = 0; #ifdef CONFIG_ISDN_AUDIO + info->vonline = 0; if (info->dtmf_state) { kfree(info->dtmf_state); info->dtmf_state = NULL; @@ -694,10 +868,12 @@ 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); + if (local) { + 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); info->emu.mdmreg[1] = 0; usage = (info->emu.mdmreg[20] == 1) ? @@ -888,11 +1064,16 @@ c = MIN(c, dev->drv[info->isdn_driver]->maxbufsize); if (c <= 0) break; - if ((info->online > 1) || - (info->vonline & 2)) { + if ((info->online > 1) +#ifdef CONFIG_ISDN_AUDIO + || (info->vonline & 3) +#endif + ) { atemu *m = &info->emu; - if (!(info->vonline & 2)) +#ifdef CONFIG_ISDN_AUDIO + if (!info->vonline) +#endif isdn_tty_check_esc(buf, m->mdmreg[2], c, &(m->pluscount), &(m->lastplus), @@ -902,21 +1083,36 @@ else memcpy(&(info->xmit_buf[info->xmit_count]), buf, c); #ifdef CONFIG_ISDN_AUDIO - 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 (info->vonline) { + int cc = isdn_tty_handleDLEdown(info, m, c); + if (info->vonline & 2) { + if (!cc) { + /* 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; + } + if ((info->vonline & 3) == 1) { + /* Do NOT handle Ctrl-Q or Ctrl-S + * when in full-duplex audio mode. */ - 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; + if (isdn_tty_end_vrx(buf, c, from_user)) { + info->vonline &= ~1; +#ifdef ISDN_DEBUG_MODEM_VOICE + printk(KERN_DEBUG + "got !^Q/^S, send DLE-ETX,VCON on ttyI%d\n", + info->line); +#endif + isdn_tty_at_cout("\020\003\r\nVCON\r\n", info); + } } - info->xmit_count += cc; } else #endif info->xmit_count += c; @@ -927,17 +1123,6 @@ } else { info->msr |= UART_MSR_CTS; info->lsr |= UART_LSR_TEMT; -#ifdef CONFIG_ISDN_AUDIO - 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; #ifdef ISDN_DEBUG_MODEM_HUP @@ -1623,6 +1808,7 @@ m->pmsn[0] = '\0'; } +#ifdef CONFIG_ISDN_AUDIO static void isdn_tty_modem_reset_vpar(atemu * m) { @@ -1631,6 +1817,7 @@ m->vpar[2] = 70; /* Silence interval (7 sec. ) */ m->vpar[3] = 2; /* Compression type (1 = ADPCM-2 ) */ } +#endif static void isdn_tty_modem_reset_regs(modem_info * info, int force) @@ -1641,7 +1828,9 @@ memcpy(m->msn, m->pmsn, ISDN_MSNLEN); info->xmit_size = m->mdmreg[16] * 16; } +#ifdef CONFIG_ISDN_AUDIO isdn_tty_modem_reset_vpar(m); +#endif m->mdmcmdl = 0; } @@ -1735,7 +1924,9 @@ info->drv_index = -1; info->xmit_size = ISDN_SERIAL_XMIT_SIZE; skb_queue_head_init(&info->xmit_queue); +#ifdef CONFIG_ISDN_AUDIO skb_queue_head_init(&info->dtmf_queue); +#endif if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_SIZE + 5, GFP_KERNEL))) { printk(KERN_ERR "Could not allocate modem xmit-buffer\n"); return -3; @@ -1817,6 +2008,9 @@ restore_flags(flags); printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr, info->line); + info->msr |= UART_MSR_RI; + isdn_tty_modem_result(2, info); + isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1); return info->line; } } @@ -1827,6 +2021,140 @@ return -1; } +#define TTY_IS_ACTIVE(info) \ + (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) + +int +isdn_tty_stat_callback(int i, isdn_ctrl * c) +{ + int mi; + modem_info *info; + + if (i < 0) + return 0; + if ((mi = dev->m_idx[i]) >= 0) { + info = &dev->mdm.info[mi]; + switch (c->command) { + case ISDN_STAT_BSENT: +#ifdef ISDN_TTY_STAT_DEBUG + printk(KERN_DEBUG "tty_STAT_BSENT ttyI%d\n", info->line); +#endif + if ((info->isdn_driver == c->driver) && + (info->isdn_channel == c->arg)) { + info->msr |= UART_MSR_CTS; + if (info->send_outstanding) + if (!(--info->send_outstanding)) + info->lsr |= UART_LSR_TEMT; + isdn_tty_tint(info); + return 1; + } + break; + case ISDN_STAT_CAUSE: +#ifdef ISDN_TTY_STAT_DEBUG + printk(KERN_DEBUG "tty_STAT_CAUSE ttyI%d\n", info->line); +#endif + /* Signal cause to tty-device */ + strncpy(info->last_cause, c->parm.num, 5); + return 1; + case ISDN_STAT_DCONN: +#ifdef ISDN_TTY_STAT_DEBUG + printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line); +#endif + if (TTY_IS_ACTIVE(info)) { + if (info->dialing == 1) { + info->dialing = 2; + return 1; + } + } + break; + case ISDN_STAT_DHUP: +#ifdef ISDN_TTY_STAT_DEBUG + printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line); +#endif + if (TTY_IS_ACTIVE(info)) { + if (info->dialing == 1) { + info->dialing = 0; + isdn_tty_modem_result(7, info); + } +#ifdef ISDN_DEBUG_MODEM_HUP + printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n"); +#endif + isdn_tty_modem_hup(info, 0); + return 1; + } + break; + case ISDN_STAT_BCONN: +#ifdef ISDN_TTY_STAT_DEBUG + printk(KERN_DEBUG "tty_STAT_BCONN ttyI%d\n", info->line); +#endif + /* Schedule CONNECT-Message to any tty + * waiting for it and + * set DCD-bit of its modem-status. + */ + if (TTY_IS_ACTIVE(info)) { + info->msr |= UART_MSR_DCD; + 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); + return 1; + } + break; + case ISDN_STAT_BHUP: +#ifdef ISDN_TTY_STAT_DEBUG + printk(KERN_DEBUG "tty_STAT_BHUP ttyI%d\n", info->line); +#endif + if (TTY_IS_ACTIVE(info)) { +#ifdef ISDN_DEBUG_MODEM_HUP + printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n"); +#endif + isdn_tty_modem_hup(info, 0); + return 1; + } + break; + case ISDN_STAT_NODCH: +#ifdef ISDN_TTY_STAT_DEBUG + printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line); +#endif + if (TTY_IS_ACTIVE(info)) { + 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; + if (info->online) { + isdn_tty_modem_result(3, info); + info->online = 0; + } + return 1; + } + break; + case ISDN_STAT_UNLOAD: +#ifdef ISDN_TTY_STAT_DEBUG + printk(KERN_DEBUG "tty_STAT_UNLOAD ttyI%d\n", info->line); +#endif + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + info = &dev->mdm.info[i]; + if (info->isdn_driver == c->driver) { + if (info->online) + isdn_tty_modem_hup(info, 1); + } + } + return 1; + } + } + return 0; +} + /********************************************************************* Modem-Emulator-Routines *********************************************************************/ @@ -1889,7 +2217,6 @@ #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, 1); } } @@ -1959,7 +2286,7 @@ * For CONNECT-messages also switch to online-mode. * For RING-message handle auto-ATA if register 0 != 0 */ -void +static void isdn_tty_modem_result(int code, modem_info * info) { atemu *m = &info->emu; @@ -1979,27 +2306,39 @@ 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 + save_flags(flags); + cli(); + m->mdmreg[1] = 0; + del_timer(&info->nc_timer); + info->ncarrier = 0; if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) { restore_flags(flags); return; } restore_flags(flags); +#ifdef CONFIG_ISDN_AUDIO if (info->vonline & 1) { +#ifdef ISDN_DEBUG_MODEM_VOICE + printk(KERN_DEBUG "res3: send DLE-ETX on ttyI%d\n", + info->line); +#endif /* voice-recording, add DLE-ETX */ isdn_tty_at_cout("\020\003", info); } if (info->vonline & 2) { +#ifdef ISDN_DEBUG_MODEM_VOICE + printk(KERN_DEBUG "res3: send DLE-DC4 on ttyI%d\n", + info->line); +#endif /* voice-playing, add DLE-DC4 */ isdn_tty_at_cout("\020\024", info); } +#endif break; case 1: case 5: @@ -2008,6 +2347,10 @@ info->online = 2; break; case 11: +#ifdef ISDN_DEBUG_MODEM_VOICE + printk(KERN_DEBUG "res3: send VCON on ttyI%d\n", + info->line); +#endif sprintf(info->last_cause, "0000"); if (!info->online) info->online = 1; @@ -2240,9 +2583,10 @@ case 'V': /* &V - Show registers */ p[0]++; + isdn_tty_at_cout("\r\n", info); for (i = 0; i < ISDN_MODEM_ANZREG; i++) { - sprintf(rb, "S%d=%d%s", i, - m->mdmreg[i], (i == 6) ? "\r\n" : " "); + sprintf(rb, "S%02d=%03d%s", i, + m->mdmreg[i], ((i + 1) % 10) ? " " : "\r\n"); isdn_tty_at_cout(rb, info); } sprintf(rb, "\r\nEAZ/MSN: %s\r\n", @@ -2286,6 +2630,33 @@ return 0; } +static int +isdn_tty_check_ats(int mreg, int mval, modem_info * info, atemu * m) +{ + /* Some plausibility checks */ + switch (mreg) { + case 14: + if (mval > ISDN_PROTO_L2_TRANS) + return 1; + break; + case 16: + if ((mval * 16) > ISDN_SERIAL_XMIT_SIZE) + return 1; +#ifdef CONFIG_ISDN_AUDIO + if ((m->mdmreg[18] & 1) && (mval > VBUFX)) + return 1; +#endif + info->xmit_size = mval * 16; + break; + case 20: + case 21: + case 22: + /* readonly registers */ + return 1; + } + return 0; +} + /* * Perform ATS command */ @@ -2293,8 +2664,10 @@ isdn_tty_cmd_ATS(char **p, modem_info * info) { atemu *m = &info->emu; + int bitpos; int mreg; int mval; + int bval; mreg = isdn_getnum(p); if (mreg < 0 || mreg > ISDN_MODEM_ANZREG) @@ -2305,25 +2678,39 @@ 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) + if (isdn_tty_check_ats(mreg, mval, info, m)) + PARSE_ERROR1; + m->mdmreg[mreg] = mval; + break; + case '.': + /* Set/Clear a single bit */ + p[0]++; + bitpos = isdn_getnum(p); + if ((bitpos < 0) || (bitpos > 7)) + PARSE_ERROR1; + switch (*p[0]) { + case '=': + p[0]++; + bval = isdn_getnum(p); + if (bval < 0 || bval > 1) PARSE_ERROR1; -#ifdef CONFIG_ISDN_AUDIO - if ((m->mdmreg[18] & 1) && (mval > VBUFX)) + if (bval) + mval = m->mdmreg[mreg] | (1 << bitpos); + else + mval = m->mdmreg[mreg] & ~(1 << bitpos); + if (isdn_tty_check_ats(mreg, mval, info, m)) PARSE_ERROR1; -#endif - info->xmit_size = mval * 16; + m->mdmreg[mreg] = mval; break; - case 20: + case '?': + p[0]++; + isdn_tty_at_cout("\r\n", info); + isdn_tty_at_cout((m->mdmreg[mreg] & (1 << bitpos)) ? "1" : "0", + info); + break; + default: PARSE_ERROR1; } - m->mdmreg[mreg] = mval; break; case '?': p[0]++; @@ -2355,9 +2742,12 @@ 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[18] & m->mdmreg[20]) != m->mdmreg[18]) { if (m->mdmreg[20] == 1) l2 = 4; + else + l2 = 0; + } #endif cmd.driver = info->isdn_driver; cmd.command = ISDN_CMD_SETL2; @@ -2709,7 +3099,7 @@ else if (strlen(ds)) isdn_tty_dial(ds, info, m); else - isdn_tty_modem_result(4, info); + PARSE_ERROR; return; case 'E': /* E - Turn Echo on/off */ @@ -2822,6 +3212,8 @@ if (isdn_tty_cmd_PLUSV(&p, info)) return; break; + default: + PARSE_ERROR; } break; #endif /* CONFIG_ISDN_AUDIO */ @@ -2831,11 +3223,13 @@ return; break; default: - isdn_tty_modem_result(4, info); - return; + PARSE_ERROR; } } - isdn_tty_modem_result(0, info); +#ifdef CONFIG_ISDN_AUDIO + if (!info->vonline) +#endif + isdn_tty_modem_result(0, info); } /* Need own toupper() because standard-toupper is not available @@ -2986,28 +3380,4 @@ } } isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton); -} - -/* - * A packet has been output successfully. - * 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) -{ - 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); - } - } - return; } diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/isdn_tty.h linux/drivers/isdn/isdn_tty.h --- v2.1.41/linux/drivers/isdn/isdn_tty.h Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/isdn_tty.h Wed May 28 10:49:09 1997 @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.h,v 1.8 1997/02/10 20:12:50 fritz Exp $ +/* $Id: isdn_tty.h,v 1.10 1997/03/02 14:29:26 fritz Exp $ * header for Linux ISDN subsystem, tty related functions (linklevel). * @@ -20,6 +20,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.h,v $ + * Revision 1.10 1997/03/02 14:29:26 fritz + * More ttyI related cleanup. + * + * Revision 1.9 1997/02/28 02:32:49 fritz + * Cleanup: Moved some tty related stuff from isdn_common.c + * to isdn_tty.c + * Bugfix: Bisync protocol did not behave like documented. + * * Revision 1.8 1997/02/10 20:12:50 fritz * Changed interface for reporting incoming calls. * @@ -46,15 +54,12 @@ * */ -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 *); +extern int isdn_tty_stat_callback(int, isdn_ctrl *); +extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *); diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/pcbit/drv.c linux/drivers/isdn/pcbit/drv.c --- v2.1.41/linux/drivers/isdn/pcbit/drv.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/pcbit/drv.c Wed May 28 10:49:10 1997 @@ -449,14 +449,8 @@ for (i=0; i < len; i++) { for(j=0; j < LOAD_RETRY; j++) - { - __volatile__ unsigned char * ptr; - - ptr = dev->sh_mem + dev->loadptr; - if (*ptr == 0) + if (!(readb(dev->sh_mem + dev->loadptr))) break; - - } if (j == LOAD_RETRY) { diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/sc/Makefile linux/drivers/isdn/sc/Makefile --- v2.1.41/linux/drivers/isdn/sc/Makefile Tue May 13 22:41:08 1997 +++ linux/drivers/isdn/sc/Makefile Wed May 28 10:49:10 1997 @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.2 1997/05/01 08:53:47 davem Exp $ +# $Id: Makefile,v 1.3 1997/05/27 23:25:01 fritz Exp $ # Copyright (C) 1996 SpellCaster Telecommunications Inc. # # This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/sc/command.c linux/drivers/isdn/sc/command.c --- v2.1.41/linux/drivers/isdn/sc/command.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/sc/command.c Wed May 28 10:49:10 1997 @@ -1,5 +1,5 @@ /* - * $Id: command.c,v 1.3 1997/02/11 22:53:40 fritz Exp $ + * $Id: command.c,v 1.4 1997/03/30 16:51:34 calle Exp $ * Copyright (C) 1996 SpellCaster Telecommunications Inc. * * This program is free software; you can redistribute it and/or modify @@ -136,15 +136,12 @@ int err; memcpy(&cmdptr, cmd->parm.num, sizeof(unsigned long)); - if((err = verify_area(VERIFY_READ, - (scs_ioctl *) cmdptr, sizeof(scs_ioctl)))) { + if((err = copy_from_user(&ioc, (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: diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/sc/init.c linux/drivers/isdn/sc/init.c --- v2.1.41/linux/drivers/isdn/sc/init.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/isdn/sc/init.c Wed May 28 10:49:10 1997 @@ -305,7 +305,7 @@ /* * No interrupt could be used */ - pr_debug("Failed to acquire an IRQ line\n"); + pr_debug("Failed to aquire an IRQ line\n"); continue; } diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/sc/ioctl.c linux/drivers/isdn/sc/ioctl.c --- v2.1.41/linux/drivers/isdn/sc/ioctl.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/sc/ioctl.c Wed May 28 10:49:10 1997 @@ -50,9 +50,8 @@ /* * Get the SRec from user space */ - if((err = verify_area(VERIFY_READ, (char *) data->dataptr, sizeof(srec)))) + if ((err = copy_from_user(srec, (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); @@ -92,9 +91,8 @@ /* * Get the switch type from user space */ - if((err = verify_area(VERIFY_READ, (char *) data->dataptr, sizeof(char)))) + if ((err = copy_from_user(&switchtype, (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); @@ -138,9 +136,8 @@ /* * Package the switch type and send to user space */ - if((err = verify_area(VERIFY_WRITE, (char *) data->dataptr, sizeof(char)))) + if ((err = copy_to_user((char *) data->dataptr, &switchtype, sizeof(char)))) return err; - copy_to_user((char *) data->dataptr, &switchtype, sizeof(char)); return 0; } @@ -171,9 +168,8 @@ /* * Package the switch type and send to user space */ - if((err = verify_area(VERIFY_WRITE, (char *) data->dataptr, sizeof(spid)))) + if ((err = copy_to_user((char *) data->dataptr, spid, sizeof(spid)))) return err; - copy_to_user((char *) data->dataptr, spid, sizeof(spid)); return 0; } @@ -189,10 +185,8 @@ /* * Get the spid from user space */ - if((err = verify_area(VERIFY_READ, (char *) data->dataptr, - sizeof(spid)))) + if ((err = copy_from_user(spid, (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); @@ -238,9 +232,8 @@ /* * Package the dn and send to user space */ - if((err = verify_area(VERIFY_WRITE, (char *) data->dataptr, sizeof(dn)))) + if ((err = copy_to_user((char *) data->dataptr, dn, sizeof(dn)))) return err; - copy_to_user((char *) data->dataptr, dn, sizeof(dn)); return 0; } @@ -256,10 +249,8 @@ /* * Get the spid from user space */ - if((err = verify_area(VERIFY_READ, (char *) data->dataptr, - sizeof(dn)))) + if ((err = copy_from_user(dn, (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); @@ -293,11 +284,9 @@ 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)); + if ((err = copy_to_user((boardInfo *) data->dataptr, &bi, sizeof(boardInfo)))) + return err; return 0; } @@ -330,9 +319,8 @@ /* * Package the switch type and send to user space */ - if((err = verify_area(VERIFY_WRITE, (char *) data->dataptr, sizeof(char)))) + if ((err = copy_to_user((char *) data->dataptr, &speed, sizeof(char)))) return err; - copy_to_user((char *) data->dataptr, &speed, sizeof(char)); return 0; } diff -u --recursive --new-file v2.1.41/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.1.41/linux/drivers/net/Config.in Wed Apr 23 19:01:18 1997 +++ linux/drivers/net/Config.in Wed May 28 10:49:10 1997 @@ -180,9 +180,13 @@ fi fi fi - +# +# X.25 network drivers +# if [ "$CONFIG_X25" != "n" ]; then - tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER - tristate 'X.25 async driver' CONFIG_X25_ASY +if [ "$CONFIG_LAPB" != "n" ]; then + dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB + dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB +fi fi diff -u --recursive --new-file v2.1.41/linux/drivers/net/apricot.c linux/drivers/net/apricot.c --- v2.1.41/linux/drivers/net/apricot.c Tue May 13 22:41:08 1997 +++ linux/drivers/net/apricot.c Wed May 28 11:26:08 1997 @@ -299,7 +299,7 @@ i596_add_cmd(dev, &lp->tdr); boguscnt = 200; - while (lp->scb.status, lp->scb.command) + while (lp->scb.command) if (--boguscnt == 0) { printk("%s: receive unit start timed out with status %4.4x, cmd %4.4x.\n", @@ -311,7 +311,7 @@ outw(0, ioaddr+4); boguscnt = 200; - while (lp->scb.status, lp->scb.command) + while (lp->scb.command) if (--boguscnt == 0) { printk("i82596 init timed out with status %4.4x, cmd %4.4x.\n", @@ -427,7 +427,7 @@ } } - while (lp->scb.status, lp->scb.command) + while (lp->scb.command) if (--boguscnt == 0) { printk("i596_cleanup_cmd timed out with status %4.4x, cmd %4.4x.\n", @@ -445,7 +445,7 @@ if (i596_debug > 4) printk ("i596_reset\n"); - while (lp->scb.status, lp->scb.command) + while (lp->scb.command) if (--boguscnt == 0) { printk("i596_reset timed out with status %4.4x, cmd %4.4x.\n", @@ -462,7 +462,7 @@ /* wait for shutdown */ boguscnt = 400; - while ((lp->scb.status, lp->scb.command) || lp->scb.command) + while (lp->scb.command) if (--boguscnt == 0) { printk("i596_reset 2 timed out with status %4.4x, cmd %4.4x.\n", @@ -499,7 +499,7 @@ else { lp->cmd_head = cmd; - while (lp->scb.status, lp->scb.command) + while (lp->scb.command) if (--boguscnt == 0) { printk("i596_add_cmd timed out with status %4.4x, cmd %4.4x.\n", @@ -768,7 +768,7 @@ lp = (struct i596_private *)dev->priv; - while (lp->scb.status, lp->scb.command) + while (lp->scb.command) if (--boguscnt == 0) { printk("%s: i596 interrupt, timeout status %4.4x command %4.4x.\n", dev->name, lp->scb.status, lp->scb.command); @@ -827,8 +827,6 @@ } case CmdMulticastList: { - unsigned short count = *((unsigned short *) (ptr + 1)); - ptr->next = (struct i596_cmd * ) I596_NULL; kfree(ptr); break; @@ -890,7 +888,7 @@ if ((lp->scb.cmd != (struct i596_cmd *) I596_NULL) && (dev->start)) ack_cmd | = CUC_START; */ boguscnt = 100; - while (lp->scb.status, lp->scb.command) + while (lp->scb.command) if (--boguscnt == 0) { printk("%s: i596 interrupt, timeout status %4.4x command %4.4x.\n", dev->name, lp->scb.status, lp->scb.command); @@ -928,7 +926,7 @@ i596_cleanup_cmd(lp); - while (lp->scb.status, lp->scb.command) + while (lp->scb.command) if (--boguscnt == 0) { printk("%s: close timed timed out with status %4.4x, cmd %4.4x.\n", @@ -1033,7 +1031,7 @@ cleanup_module(void) { unregister_netdev(&dev_apricot); - kfree(dev_apricot.mem_start); + kfree((void*)dev_apricot.mem_start); dev_apricot.priv = NULL; /* If we don't do this, we can't re-insmod it later. */ diff -u --recursive --new-file v2.1.41/linux/drivers/net/bpqether.c linux/drivers/net/bpqether.c --- v2.1.41/linux/drivers/net/bpqether.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/net/bpqether.c Wed May 28 10:49:10 1997 @@ -1,10 +1,6 @@ /* * G8BPQ compatible "AX.25 via ethernet" driver release 003 * - * 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.0.0 or higher/ NET3.029 * * This module: @@ -268,6 +264,7 @@ */ static int bpq_xmit(struct sk_buff *skb, struct device *dev) { + struct sk_buff *newskb; unsigned char *ptr; struct bpqdev *bpq; int size; @@ -278,7 +275,7 @@ */ if (!dev->start) { bpq_check_devices(dev); - dev_kfree_skb(skb, FREE_WRITE); + kfree_skb(skb, FREE_WRITE); return -ENODEV; } @@ -290,21 +287,16 @@ * sendto() does not. */ if (skb_headroom(skb) < AX25_BPQ_HEADER_LEN) { /* Ough! */ - struct sk_buff *newskb = alloc_skb(skb->len + AX25_BPQ_HEADER_LEN, GFP_ATOMIC); - - if (newskb == NULL) { /* Argh! */ - printk(KERN_WARNING "bpq_xmit: not enough space to add BPQ Ether header\n"); - dev_kfree_skb(skb, FREE_WRITE); + if ((newskb = skb_realloc_headroom(skb, AX25_BPQ_HEADER_LEN)) == NULL) { + printk(KERN_WARNING "bpqether: out of memory\n"); + kfree_skb(skb, FREE_WRITE); return -ENOMEM; } - newskb->arp = 1; - if (skb->sk) + if (skb->sk != NULL) skb_set_owner_w(newskb, skb->sk); - skb_reserve(newskb, AX25_BPQ_HEADER_LEN); - memcpy(skb_put(newskb, size), skb->data, size); - dev_kfree_skb(skb, FREE_WRITE); + kfree_skb(skb, FREE_WRITE); skb = newskb; } @@ -319,7 +311,7 @@ if ((dev = bpq_get_ether_dev(dev)) == NULL) { bpq->stats.tx_dropped++; - dev_kfree_skb(skb, FREE_WRITE); + kfree_skb(skb, FREE_WRITE); return -ENODEV; } @@ -509,7 +501,7 @@ unsigned char *buf; struct bpqdev *bpq, *bpq2; - if ((bpq = (struct bpqdev *)kmalloc(sizeof(struct bpqdev), GFP_KERNEL)) == NULL) + if ((bpq = kmalloc(sizeof(struct bpqdev), GFP_KERNEL)) == NULL) return -ENOMEM; memset(bpq, 0, sizeof(struct bpqdev)); @@ -523,7 +515,7 @@ memcpy(bpq->acpt_addr, bcast_addr, sizeof(bpq_eth_addr)); dev = &bpq->axdev; - buf = (unsigned char *)kmalloc(14, GFP_KERNEL); + buf = kmalloc(14, GFP_KERNEL); for (k = 0; k < MAXBPQDEV; k++) { struct device *odev; @@ -562,12 +554,13 @@ /* preset with reasonable values */ -#if CONFIG_INET dev->flags = 0; dev->family = AF_INET; - dev->pa_addr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; + +#ifdef CONFIG_INET + dev->pa_addr = in_aton("192.168.0.1"); + dev->pa_brdaddr = in_aton("192.168.0.255"); + dev->pa_mask = in_aton("255.255.255.0"); dev->pa_alen = 4; #endif @@ -663,6 +656,9 @@ #ifdef MODULE EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("Joerg Reuter DL1BKE "); +MODULE_DESCRIPTION("Transmit and receive AX.25 packets over Ethernet"); int init_module(void) { diff -u --recursive --new-file v2.1.41/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c --- v2.1.41/linux/drivers/net/dgrs.c Wed Apr 23 19:01:19 1997 +++ linux/drivers/net/dgrs.c Wed May 28 11:26:08 1997 @@ -844,7 +844,7 @@ { DGRS_PRIV *privN = (DGRS_PRIV *) devN->priv; DGRS_IOCTL ioc; - int i, rc; + int i; if (cmd != DGRSIOCTL) return -EINVAL; diff -u --recursive --new-file v2.1.41/linux/drivers/net/lapbether.c linux/drivers/net/lapbether.c --- v2.1.41/linux/drivers/net/lapbether.c Wed Apr 23 19:01:19 1997 +++ linux/drivers/net/lapbether.c Wed May 28 10:49:10 1997 @@ -1,10 +1,6 @@ /* * "LAPB via ethernet" driver release 001 * - * 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: @@ -226,7 +222,7 @@ */ if (!dev->start) { lapbeth_check_devices(dev); - dev_kfree_skb(skb, FREE_WRITE); + kfree_skb(skb, FREE_WRITE); return -ENODEV; } @@ -427,7 +423,7 @@ unsigned char *buf; struct lapbethdev *lapbeth, *lapbeth2; - if ((lapbeth = (struct lapbethdev *)kmalloc(sizeof(struct lapbethdev), GFP_KERNEL)) == NULL) + if ((lapbeth = kmalloc(sizeof(struct lapbethdev), GFP_KERNEL)) == NULL) return -ENOMEM; memset(lapbeth, 0, sizeof(struct lapbethdev)); @@ -438,7 +434,7 @@ strncpy(lapbeth->ethname, dev->name, sizeof(lapbeth->ethname)-1); dev = &lapbeth->axdev; - buf = (unsigned char *)kmalloc(14, GFP_KERNEL); + buf = kmalloc(14, GFP_KERNEL); for (k = 0; k < MAXLAPBDEV; k++) { struct device *odev; @@ -474,12 +470,13 @@ /* preset with reasonable values */ -#if CONFIG_INET dev->flags = 0; dev->family = AF_INET; - dev->pa_addr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; + +#ifdef CONFIG_INET + dev->pa_addr = in_aton("192.168.0.1"); + dev->pa_brdaddr = in_aton("192.168.0.255"); + dev->pa_mask = in_aton("255.255.255.0"); dev->pa_alen = 4; #endif @@ -561,6 +558,9 @@ #ifdef MODULE EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("Jonathan Naylor "); +MODULE_DESCRIPTION("The unofficial LAPB over Ethernet driver"); int init_module(void) { diff -u --recursive --new-file v2.1.41/linux/drivers/net/mkiss.c linux/drivers/net/mkiss.c --- v2.1.41/linux/drivers/net/mkiss.c Tue May 13 22:41:09 1997 +++ linux/drivers/net/mkiss.c Wed May 28 10:49:10 1997 @@ -15,7 +15,7 @@ * This method clears the way to implement other kiss protocols * like mkiss smack g8bpq ..... so far only mkiss is implemented. * - * Hans Alblas Hansa@cuci.nl + * Hans Alblas * * History * Jonathan (G4KLX) Fixed to match Linux networking changes - 2.1.15. @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -75,8 +76,8 @@ } ax25_ctrl_t; static ax25_ctrl_t **ax25_ctrls = NULL; + int ax25_maxdev = AX25_MAXDEV; /* Can be overridden with insmod! */ -MODULE_PARM(ax25_maxdev, "i"); static struct tty_ldisc ax_ldisc; static struct tty_driver mkiss_driver; @@ -118,7 +119,7 @@ return NULL; /* If no channels are available, allocate one */ - if (axp == NULL && (ax25_ctrls[i] = (ax25_ctrl_t *)kmalloc(sizeof(ax25_ctrl_t), GFP_KERNEL)) != NULL) { + if (axp == NULL && (ax25_ctrls[i] = kmalloc(sizeof(ax25_ctrl_t), GFP_KERNEL)) != NULL) { axp = ax25_ctrls[i]; memset(axp, 0, sizeof(ax25_ctrl_t)); @@ -148,7 +149,7 @@ return &axp->ctrl; } else { clear_bit(AXF_INUSE,&axp->ctrl.flags); - printk(KERN_ERR "ax_alloc() - register_netdev() failure.\n"); + printk(KERN_ERR "mkiss: ax_alloc() - register_netdev() failure.\n"); } } @@ -166,7 +167,7 @@ kfree(ax->xbuff); ax->xbuff = NULL; if (!test_and_clear_bit(AXF_INUSE, &ax->flags)) - printk(KERN_ERR "%s: ax_free for already free unit.\n", ax->dev->name); + printk(KERN_ERR "mkiss: %s: ax_free for already free unit.\n", ax->dev->name); } static void ax_changedmtu(struct ax_disp *ax) @@ -186,11 +187,11 @@ if (len < 576 * 2) len = 576 * 2; - xbuff = (unsigned char *)kmalloc(len + 4, GFP_ATOMIC); - rbuff = (unsigned char *)kmalloc(len + 4, GFP_ATOMIC); + xbuff = kmalloc(len + 4, GFP_ATOMIC); + rbuff = kmalloc(len + 4, GFP_ATOMIC); if (xbuff == NULL || rbuff == NULL) { - printk(KERN_ERR "%s: unable to grow ax25 buffers, MTU change cancelled.\n", + printk(KERN_ERR "mkiss: %s: unable to grow ax25 buffers, MTU change cancelled.\n", ax->dev->name); dev->mtu = ax->mtu; if (xbuff != NULL) @@ -245,7 +246,7 @@ static inline void ax_lock(struct ax_disp *ax) { if (test_and_set_bit(0, (void *)&ax->dev->tbusy)) - printk(KERN_ERR "%s: trying to lock already locked device!\n", ax->dev->name); + printk(KERN_ERR "mkiss: %s: trying to lock already locked device!\n", ax->dev->name); } @@ -253,7 +254,7 @@ static inline void ax_unlock(struct ax_disp *ax) { if (!test_and_clear_bit(0, (void *)&ax->dev->tbusy)) - printk(KERN_ERR "%s: trying to unlock already unlocked device!\n", ax->dev->name); + printk(KERN_ERR "mkiss: %s: trying to unlock already unlocked device!\n", ax->dev->name); } /* Send one completely decapsulated AX.25 packet to the AX.25 layer. */ @@ -277,7 +278,7 @@ count = ax->rcount; if ((skb = dev_alloc_skb(count)) == NULL) { - printk(KERN_ERR "%s: memory squeeze, dropping packet.\n", ax->dev->name); + printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n", ax->dev->name); ax->rx_dropped++; return; } @@ -302,7 +303,7 @@ if (len > ax->mtu) { /* Sigh, shouldn't occur BUT ... */ len = ax->mtu; - printk(KERN_ERR "%s: truncating oversized transmit packet!\n", ax->dev->name); + printk(KERN_ERR "mkiss: %s: truncating oversized transmit packet!\n", ax->dev->name); ax->tx_dropped++; ax_unlock(ax); return; @@ -380,7 +381,7 @@ } if (!dev->start) { - printk(KERN_ERR "%s: xmit call when iface is down\n", dev->name); + printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name); return 1; } @@ -404,7 +405,7 @@ return 1; } - printk(KERN_ERR "%s: transmit timed out, %s?\n", dev->name, + printk(KERN_ERR "mkiss: %s: transmit timed out, %s?\n", dev->name, (ax->tty->driver.chars_in_buffer(ax->tty) || ax->xleft) ? "bad line quality" : "driver error"); @@ -419,7 +420,7 @@ if (tmp_ax != NULL) ax_lock(tmp_ax); ax_encaps(ax, skb->data, skb->len); - dev_kfree_skb(skb, FREE_WRITE); + kfree_skb(skb, FREE_WRITE); } return 0; @@ -476,10 +477,10 @@ if (len < 576 * 2) len = 576 * 2; - if ((ax->rbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL)) == NULL) + if ((ax->rbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL) goto norbuff; - if ((ax->xbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL)) == NULL) + if ((ax->xbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL) goto noxbuff; ax->mtu = dev->mtu + 73; @@ -823,7 +824,7 @@ if (ax25_maxdev < 4) ax25_maxdev = 4; /* Sanity */ - if ((ax25_ctrls = (ax25_ctrl_t **)kmalloc(sizeof(void*) * ax25_maxdev, GFP_KERNEL)) == NULL) { + if ((ax25_ctrls = kmalloc(sizeof(void*) * ax25_maxdev, GFP_KERNEL)) == NULL) { printk(KERN_ERR "mkiss: Can't allocate ax25_ctrls[] array ! No mkiss available\n"); return -ENOMEM; } @@ -910,10 +911,13 @@ /* New-style flags. */ dev->flags = 0; dev->family = AF_INET; - dev->pa_addr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; + +#ifdef CONFIG_INET + dev->pa_addr = in_aton("192.168.0.1"); + dev->pa_brdaddr = in_aton("192.168.0.255"); + dev->pa_mask = in_aton("255.255.255.0"); dev->pa_alen = 4; +#endif return 0; } @@ -1080,7 +1084,7 @@ mkiss_driver.put_char = mkiss_dummy2; if (tty_register_driver(&mkiss_driver)) { - printk(KERN_ERR "Couldn't register Mkiss device\n"); + printk(KERN_ERR "mkiss: couldn't register Mkiss device\n"); return -EIO; } @@ -1091,6 +1095,12 @@ #ifdef MODULE EXPORT_NO_SYMBOLS; + +MODULE_PARM(ax25_maxdev, "i"); +MODULE_PARM_DESC(ax25_maxdev, "number of MKISS devices"); + +MODULE_AUTHOR("Hans Albas PE1AYX "); +MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs"); int init_module(void) { diff -u --recursive --new-file v2.1.41/linux/drivers/net/pi2.c linux/drivers/net/pi2.c --- v2.1.41/linux/drivers/net/pi2.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/pi2.c Wed May 28 10:49:10 1997 @@ -332,11 +332,6 @@ wrtscc(lp->cardbase, lp->base + CTL, R0, RES_EXT_INT); } -static void free_p(struct sk_buff *skb) -{ - dev_kfree_skb(skb, FREE_WRITE); -} - static void a_txint(struct pi_local *lp) { int cmd; @@ -413,7 +408,7 @@ } switch (lp->tstate) { case ACTIVE: - free_p(lp->sndbuf); + kfree_skb(lp->sndbuf, FREE_WRITE); lp->sndbuf = NULL; lp->tstate = FLAGOUT; tdelay(lp, lp->squeldelay); @@ -731,7 +726,7 @@ /* stuffing a char satisfies Interrupt condition */ } else { /* No more to send */ - free_p(lp->sndbuf); + kfree_skb(lp->sndbuf, FREE_WRITE); lp->sndbuf = NULL; if ((rdscc(lp->cardbase, cmd, R0) & 0x40)) { /* Did we underrun? */ @@ -783,7 +778,7 @@ switch (lp->tstate) { case ACTIVE: /* Unexpected underrun */ - free_p(lp->sndbuf); + kfree_skb(lp->sndbuf, FREE_WRITE); lp->sndbuf = NULL; wrtscc(lp->cardbase, cmd, R0, SEND_ABORT); lp->tstate = FLAGOUT; @@ -1565,7 +1560,7 @@ /* Free any buffers left in the hardware transmit queue */ while ((ptr = skb_dequeue(&lp->sndq)) != NULL) - free_p(ptr); + kfree_skb(ptr, FREE_WRITE); restore_flags(flags); @@ -1665,6 +1660,9 @@ #ifdef MODULE EXPORT_NO_SYMBOLS; +MODULE_AUTHOR("David Perry "); +MODULE_DESCRIPTION("AX.25 driver for the Ottawa PI and PI/2 HDLC cards"); + int init_module(void) { return pi_init(); @@ -1685,12 +1683,3 @@ unregister_netdev(&pi0b); } #endif - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c skeleton.c" - * version-control: t - * kept-new-versions: 5 - * tab-width: 4 - * End: - */ diff -u --recursive --new-file v2.1.41/linux/drivers/net/pt.c linux/drivers/net/pt.c --- v2.1.41/linux/drivers/net/pt.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/pt.c Wed May 28 10:49:10 1997 @@ -26,7 +26,7 @@ * 03/03/95 cs Painfully found out (after 3 days) SERIAL_CFG is write only * created image of it and DMA_CFG * 21/06/95 cs Upgraded to suit PI driver 0.8 ALPHA - * 22/08/95 cs Changed it all around to make it like pi driver + * 22/08/95 cs Changed it all around to make it like pi driver * 23/08/95 cs It now works, got caught again by TMR2 and we must have * auto-enables for daughter boards. * 07/10/95 cs Fixed for 1.3.30 (hopefully) @@ -318,12 +318,6 @@ restore_flags(flags); } -static void free_p(struct sk_buff *skb) -{ - dev_kfree_skb(skb, FREE_WRITE); -} - - /* * This sets up all the registers in the SCC for the given channel * based upon tsync_hwint() @@ -979,7 +973,7 @@ /* Free any buffers left in the hardware transmit queue */ while ((ptr = skb_dequeue(&lp->sndq)) != NULL) - free_p(ptr); + kfree_skb(ptr, FREE_WRITE); restore_flags(flags); @@ -1197,7 +1191,7 @@ /* stuffing a char satisfies interrupt condition */ } else { /* No more to send */ - free_p(lp->sndbuf); + kfree_skb(lp->sndbuf, FREE_WRITE); lp->sndbuf = NULL; if ((rdscc(lp->cardbase, cmd, R0) & TxEOM)) { @@ -1552,7 +1546,7 @@ #ifdef PT_DEBUG printk(KERN_DEBUG "PT: exisr(): unexpected underrun detected.\n"); #endif - free_p(lp->sndbuf); + kfree_skb(lp->sndbuf, FREE_WRITE); lp->sndbuf = NULL; if (!lp->dmachan) { @@ -1765,6 +1759,9 @@ #ifdef MODULE EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("Craig Small VK2XLZ "); +MODULE_DESCRIPTION("AX.25 driver for the Gracillis PacketTwin HDLC card"); int init_module(void) { diff -u --recursive --new-file v2.1.41/linux/drivers/net/soundmodem/sm.c linux/drivers/net/soundmodem/sm.c --- v2.1.41/linux/drivers/net/soundmodem/sm.c Tue May 13 22:41:11 1997 +++ linux/drivers/net/soundmodem/sm.c Wed May 28 10:49:10 1997 @@ -158,6 +158,7 @@ static const struct hardware_info *sm_hardware_table[] = { #ifdef CONFIG_SOUNDMODEM_SBC &sm_hw_sbc, + &sm_hw_sbcfdx, #endif /* CONFIG_SOUNDMODEM_SBC */ #ifdef CONFIG_SOUNDMODEM_WSS &sm_hw_wss, diff -u --recursive --new-file v2.1.41/linux/drivers/net/soundmodem/sm.h linux/drivers/net/soundmodem/sm.h --- v2.1.41/linux/drivers/net/soundmodem/sm.h Thu Feb 27 10:57:31 1997 +++ linux/drivers/net/soundmodem/sm.h Wed May 28 10:49:10 1997 @@ -325,6 +325,7 @@ 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_sbcfdx; extern const struct hardware_info sm_hw_wss; extern const struct hardware_info sm_hw_wssfdx; diff -u --recursive --new-file v2.1.41/linux/drivers/net/soundmodem/sm_afsk1200.c linux/drivers/net/soundmodem/sm_afsk1200.c --- v2.1.41/linux/drivers/net/soundmodem/sm_afsk1200.c Thu Mar 27 14:40:04 1997 +++ linux/drivers/net/soundmodem/sm_afsk1200.c Wed May 28 10:49:10 1997 @@ -1,7 +1,7 @@ /*****************************************************************************/ /* - * sm_afsk1200.h -- soundcard radio modem driver, 1200 baud AFSK modem + * sm_afsk1200.c -- soundcard radio modem driver, 1200 baud AFSK modem * * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) * diff -u --recursive --new-file v2.1.41/linux/drivers/net/soundmodem/sm_fsk9600.c linux/drivers/net/soundmodem/sm_fsk9600.c --- v2.1.41/linux/drivers/net/soundmodem/sm_fsk9600.c Thu Feb 27 10:57:31 1997 +++ linux/drivers/net/soundmodem/sm_fsk9600.c Wed May 28 10:49:10 1997 @@ -1,7 +1,7 @@ /*****************************************************************************/ /* - * sm_fsk9600.h -- soundcard radio modem driver, + * sm_fsk9600.c -- soundcard radio modem driver, * 9600 baud G3RUH compatible FSK modem * * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) diff -u --recursive --new-file v2.1.41/linux/drivers/net/soundmodem/sm_hapn4800.c linux/drivers/net/soundmodem/sm_hapn4800.c --- v2.1.41/linux/drivers/net/soundmodem/sm_hapn4800.c Thu Feb 27 10:57:31 1997 +++ linux/drivers/net/soundmodem/sm_hapn4800.c Wed May 28 10:49:10 1997 @@ -1,7 +1,7 @@ /*****************************************************************************/ /* - * sm_hapn4800.h -- soundcard radio modem driver, 4800 baud HAPN modem + * sm_hapn4800.c -- soundcard radio modem driver, 4800 baud HAPN modem * * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) * diff -u --recursive --new-file v2.1.41/linux/drivers/net/soundmodem/sm_sbc.c linux/drivers/net/soundmodem/sm_sbc.c --- v2.1.41/linux/drivers/net/soundmodem/sm_sbc.c Thu Mar 27 14:40:04 1997 +++ linux/drivers/net/soundmodem/sm_sbc.c Wed May 28 10:49:10 1997 @@ -1,7 +1,7 @@ /*****************************************************************************/ /* - * sm_sbc.h -- soundcard radio modem driver soundblaster hardware driver + * sm_sbc.c -- soundcard radio modem driver soundblaster hardware driver * * Copyright (C) 1996 Thomas Sailer (sailer@ife.ee.ethz.ch) * @@ -80,9 +80,12 @@ struct sc_state_sbc { unsigned char revhi, revlo; unsigned char fmt[2]; + unsigned int sr[2]; unsigned int dmabuflen; unsigned char *dmabuf; + unsigned char *dmabuf2; unsigned char dmabufidx; + unsigned char dma2bufidx; unsigned char ptt; }; @@ -99,6 +102,7 @@ #define DSP_DATA_AVAIL(iobase) (iobase+0xe) #define DSP_MIXER_ADDR(iobase) (iobase+0x4) #define DSP_MIXER_DATA(iobase) (iobase+0x5) +#define DSP_INTACK_16BIT(iobase) (iobase+0xf) #define SBC_EXTENT 16 /* --------------------------------------------------------------------- */ @@ -122,6 +126,8 @@ #define SBC_DMA_ON 0xd0 #define SBC_DMA_OFF 0xd4 #define SBC_SAMPLE_RATE 0x40 +#define SBC_SAMPLE_RATE_OUT 0x41 +#define SBC_SAMPLE_RATE_IN 0x42 #define SBC_MONO_8BIT 0xa0 #define SBC_MONO_16BIT 0xa4 #define SBC_STEREO_8BIT 0xa8 @@ -131,6 +137,9 @@ #define SBC4_IN8_AI 0xce #define SBC4_MODE_UNS_MONO 0x00 +#define SBC4_OUT16_AI 0xb6 +#define SBC4_IN16_AI 0xbe + /* --------------------------------------------------------------------- */ static int inline reset_dsp(struct device *dev) @@ -179,13 +188,102 @@ /* --------------------------------------------------------------------- */ -static void inline sbc_int_ack(struct device *dev) +static int config_resources(struct device *dev, struct sm_state *sm, int fdx) +{ + unsigned char irqreg = 0, dmareg = 0, realirq, realdma; + unsigned long flags; + + switch (dev->irq) { + case 2: + case 9: + irqreg |= 0x01; + break; + + case 5: + irqreg |= 0x02; + break; + + case 7: + irqreg |= 0x04; + break; + + case 10: + irqreg |= 0x08; + break; + + default: + return -ENODEV; + } + + switch (dev->dma) { + case 0: + dmareg |= 0x01; + break; + + case 1: + dmareg |= 0x02; + break; + + case 3: + dmareg |= 0x08; + break; + + default: + return -ENODEV; + } + + if (fdx) { + switch (sm->hdrv.ptt_out.dma2) { + case 5: + dmareg |= 0x20; + break; + + case 6: + dmareg |= 0x40; + break; + + case 7: + dmareg |= 0x80; + break; + + default: + return -ENODEV; + } + } + save_flags(flags); + cli(); + outb(0x80, DSP_MIXER_ADDR(dev->base_addr)); + outb(irqreg, DSP_MIXER_DATA(dev->base_addr)); + realirq = inb(DSP_MIXER_DATA(dev->base_addr)); + outb(0x81, DSP_MIXER_ADDR(dev->base_addr)); + outb(dmareg, DSP_MIXER_DATA(dev->base_addr)); + realdma = inb(DSP_MIXER_DATA(dev->base_addr)); + restore_flags(flags); + if ((~realirq) & irqreg || (~realdma) & dmareg) { + printk(KERN_ERR "%s: sbc resource registers cannot be set; " + "PnP device and IRQ/DMA specified wrongly?\n", + sm_drvname); + return -EINVAL; + } + return 0; +} + +/* --------------------------------------------------------------------- */ + +static void inline sbc_int_ack_8bit(struct device *dev) { inb(DSP_DATA_AVAIL(dev->base_addr)); } /* --------------------------------------------------------------------- */ +static void inline sbc_int_ack_16bit(struct device *dev) +{ + inb(DSP_INTACK_16BIT(dev->base_addr)); +} + +/* --------------------------------------------------------------------- */ + static void setup_dma_dsp(struct device *dev, struct sm_state *sm, int send) { unsigned long flags; @@ -209,7 +307,7 @@ panic("sm: DMA buffer violates DMA boundary!"); save_flags(flags); cli(); - sbc_int_ack(dev); + sbc_int_ack_8bit(dev); write_dsp(dev, SBC_SAMPLE_RATE); /* set sampling rate */ write_dsp(dev, SCSTATE->fmt[send]); write_dsp(dev, sbcskr[send]); @@ -219,7 +317,7 @@ set_dma_addr(dev->dma, dmabufaddr); set_dma_count(dev->dma, SCSTATE->dmabuflen); enable_dma(dev->dma); - sbc_int_ack(dev); + sbc_int_ack_8bit(dev); if (SCSTATE->revhi >= 4) { write_dsp(dev, sbc4mode[send]); write_dsp(dev, SBC4_MODE_UNS_MONO); @@ -247,7 +345,7 @@ if (!dev || !sm || sm->hdrv.magic != HDLCDRV_MAGIC) return; new_ptt = hdlcdrv_ptt(&sm->hdrv); - sbc_int_ack(dev); + sbc_int_ack_8bit(dev); buf = SCSTATE->dmabuf; if (SCSTATE->dmabufidx) buf += SCSTATE->dmabuflen/2; @@ -294,6 +392,8 @@ static int sbc_open(struct device *dev, struct sm_state *sm) { + int err; + 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)); @@ -327,6 +427,11 @@ dev->base_addr, SCSTATE->revhi, SCSTATE->revlo); return -ENODEV; } + if (SCSTATE->revhi >= 4 && + (err = config_resources(dev, sm, 0))) { + printk(KERN_ERR "%s: invalid IRQ and/or DMA specified\n", sm_drvname); + return err; + } /* * initialize some variables */ @@ -521,6 +626,282 @@ const struct hardware_info sm_hw_sbc = { "sbc", sizeof(struct sc_state_sbc), sbc_open, sbc_close, sbc_ioctl, sbc_sethw +}; + +/* --------------------------------------------------------------------- */ + +static void setup_dma_fdx_dsp(struct device *dev, struct sm_state *sm) +{ + unsigned long flags; + unsigned long dmabufaddr = virt_to_bus(SCSTATE->dmabuf); + unsigned long dmabuf2addr = virt_to_bus(SCSTATE->dmabuf2); + + if (!reset_dsp(dev)) { + printk(KERN_ERR "%s: sbc: cannot reset sb dsp\n", sm_drvname); + return; + } + if (((dmabufaddr & 0xffff) + SCSTATE->dmabuflen > 0x10000) || + ((dmabuf2addr & 0xffff) + 2*(SCSTATE->dmabuflen) > 0x10000)) + panic("sm: DMA buffer violates DMA boundary!"); + save_flags(flags); + cli(); + sbc_int_ack_8bit(dev); + sbc_int_ack_16bit(dev); + /* should eventually change to set rates individually by SBC_SAMPLE_RATE_{IN/OUT} */ + write_dsp(dev, SBC_SAMPLE_RATE); /* set sampling rate */ + write_dsp(dev, SCSTATE->fmt[0]); + write_dsp(dev, SBC_SPEAKER_ON); + /* + * DMA channel 1 (8bit) does input (capture), + * DMA channel 2 (16bit) does output (playback) + */ + disable_dma(dev->dma); + disable_dma(sm->hdrv.ptt_out.dma2); + clear_dma_ff(dev->dma); + set_dma_mode(dev->dma, DMA_MODE_READ | DMA_MODE_AUTOINIT); + set_dma_addr(dev->dma, dmabufaddr); + 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_WRITE | DMA_MODE_AUTOINIT); + set_dma_addr(sm->hdrv.ptt_out.dma2, dmabuf2addr); + set_dma_count(sm->hdrv.ptt_out.dma2, SCSTATE->dmabuflen); + enable_dma(dev->dma); + enable_dma(sm->hdrv.ptt_out.dma2); + sbc_int_ack_8bit(dev); + sbc_int_ack_16bit(dev); + write_dsp(dev, SBC4_IN8_AI); + write_dsp(dev, SBC4_MODE_UNS_MONO); + write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); + write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); + write_dsp(dev, SBC4_OUT16_AI); + write_dsp(dev, SBC4_MODE_UNS_MONO); + write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff); + write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) >> 8); + restore_flags(flags); +} + +/* --------------------------------------------------------------------- */ + +static void sbcfdx_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 *buf; + unsigned char *buf2; + unsigned char intsrc; + + if (!dev || !sm || sm->hdrv.magic != HDLCDRV_MAGIC) + return; + buf = SCSTATE->dmabuf; + buf2 = SCSTATE->dmabuf2; + outb(0x82, DSP_MIXER_ADDR(dev->base_addr)); + intsrc = inb(DSP_MIXER_DATA(dev->base_addr)); + if (intsrc & 0x01) { + sbc_int_ack_8bit(dev); + if (SCSTATE->dmabufidx) + buf += SCSTATE->dmabuflen/2; + SCSTATE->dmabufidx = !SCSTATE->dmabufidx; + } + if (intsrc & 0x02) { + sbc_int_ack_16bit(dev); + if (SCSTATE->dma2bufidx) + buf2 += SCSTATE->dmabuflen/2; + SCSTATE->dma2bufidx = !SCSTATE->dma2bufidx; + } + sm_int_freq(sm); + sti(); + if (intsrc & 0x02) { + if ((SCSTATE->ptt = hdlcdrv_ptt(&sm->hdrv))) + time_exec(sm->debug_vals.mod_cyc, + sm->mode_tx->modulator(sm, buf2, SCSTATE->dmabuflen/2)); + else + time_exec(sm->debug_vals.mod_cyc, + memset(buf2, 0x80, SCSTATE->dmabuflen/2)); + } + if (intsrc & 0x01) { + time_exec(sm->debug_vals.demod_cyc, + sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2)); + hdlcdrv_arbitrate(dev, &sm->hdrv); + } + sm_output_status(sm); + hdlcdrv_transmitter(dev, &sm->hdrv); + hdlcdrv_receiver(dev, &sm->hdrv); +} + +/* --------------------------------------------------------------------- */ + +static int sbcfdx_open(struct device *dev, struct sm_state *sm) +{ + int err; + + 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 < 4) { + printk(KERN_ERR "%s: at least DSP rev 4.00 required\n", sm_drvname); + return -ENODEV; + } + if ((err = config_resources(dev, sm, 1))) { + printk(KERN_ERR "%s: invalid IRQ and/or DMA specified\n", sm_drvname); + return err; + } + /* + * 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->dma2bufidx = 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, sbcfdx_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, SBC_EXTENT, sm->hwdrv->hw_name); + setup_dma_fdx_dsp(dev, sm); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int sbcfdx_close(struct device *dev, struct sm_state *sm) +{ + if (!dev || !sm) + return -EINVAL; + /* + * disable interrupts + */ + disable_dma(dev->dma); + disable_dma(sm->hdrv.ptt_out.dma2); + reset_dsp(dev); + free_irq(dev->irq, dev); + free_dma(dev->dma); + free_dma(sm->hdrv.ptt_out.dma2); + release_region(dev->base_addr, SBC_EXTENT); + kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen); + kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int sbcfdx_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) && + (*mtp)->srate >= 5000 && (*mtp)->srate <= 44100 && + (*mrp)->srate == (*mtp)->srate) { + sm->mode_tx = *mtp; + sm->mode_rx = *mrp; + SCSTATE->sr[0] = sm->mode_rx->srate; + SCSTATE->sr[1] = sm->mode_tx->srate; + dv = lcm(sm->mode_tx->dmabuflenmodulo, + sm->mode_rx->dmabuflenmodulo); + if (dv & 1) + dv <<= 1; /* dmabuflen must be a multiple of 4 */ + 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 sbcfdx_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 sbc_ioctl(dev, sm, ifr, hi, cmd); +} + +/* --------------------------------------------------------------------- */ + +const struct hardware_info sm_hw_sbcfdx = { + "sbcfdx", sizeof(struct sc_state_sbc), + sbcfdx_open, sbcfdx_close, sbcfdx_ioctl, sbcfdx_sethw }; /* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.41/linux/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c --- v2.1.41/linux/drivers/sbus/char/sunserial.c Thu May 15 16:48:03 1997 +++ linux/drivers/sbus/char/sunserial.c Wed May 28 10:49:10 1997 @@ -1,4 +1,4 @@ -/* $Id: sunserial.c,v 1.41 1997/05/14 20:46:51 davem Exp $ +/* $Id: sunserial.c,v 1.42 1997/05/26 20:10:20 davem Exp $ * serial.c: Serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1062,7 +1062,7 @@ /* * zs_console_print is registered for printk. */ -static void zs_console_print(const char *s, int count) +static void zs_console_print(const char *s, unsigned count) { int i; @@ -1867,7 +1867,7 @@ static void show_serial_version(void) { - char *revision = "$Revision: 1.41 $"; + char *revision = "$Revision: 1.42 $"; char *version, *p; version = strchr(revision, ' '); @@ -2198,7 +2198,7 @@ o = 1; /* double whee.. */ if(!consout_registered) { - extern void serial_finish_init (void (*)(const char *, int count)); + extern void serial_finish_init (void (*)(const char *, unsigned count)); serial_finish_init (zs_console_print); register_console(&console); diff -u --recursive --new-file v2.1.41/linux/drivers/scsi/g_NCR5380.c linux/drivers/scsi/g_NCR5380.c --- v2.1.41/linux/drivers/scsi/g_NCR5380.c Wed Apr 23 19:01:22 1997 +++ linux/drivers/scsi/g_NCR5380.c Wed May 28 11:26:08 1997 @@ -617,10 +617,8 @@ unsigned char status; int i; struct Scsi_Host *scsi_ptr; - Scsi_Device *dev; Scsi_Cmnd *ptr; struct NCR5380_hostdata *hostdata; - extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; cli(); diff -u --recursive --new-file v2.1.41/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c --- v2.1.41/linux/drivers/scsi/qlogicpti.c Thu May 15 16:48:03 1997 +++ linux/drivers/scsi/qlogicpti.c Wed May 28 10:49:10 1997 @@ -976,6 +976,7 @@ host_status = DID_ERROR; break; case CS_RESET_OCCURRED: + case CS_BUS_RESET: host_status = DID_RESET; break; case CS_ABORTED: @@ -1105,7 +1106,7 @@ struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata; int return_status = SCSI_ABORT_SUCCESS; - printk(KERN_EMERG "qlogicpti : Aborting cmd for tgt[%d] lun[%d]\n", + printk(KERN_WARNING "qlogicpti : Aborting cmd for tgt[%d] lun[%d]\n", (int)Cmnd->target, (int)Cmnd->lun); qlogicpti_disable_irqs(qpti->qregs); param[0] = MBOX_ABORT; @@ -1128,7 +1129,7 @@ struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata; int return_status = SCSI_RESET_SUCCESS; - printk(KERN_EMERG "qlogicpti : Resetting SCSI bus!\n"); + printk(KERN_WARNING "qlogicpti : Resetting SCSI bus!\n"); qlogicpti_disable_irqs(qpti->qregs); param[0] = MBOX_BUS_RESET; param[1] = qpti->host_param.bus_reset_delay; diff -u --recursive --new-file v2.1.41/linux/drivers/scsi/qlogicpti.h linux/drivers/scsi/qlogicpti.h --- v2.1.41/linux/drivers/scsi/qlogicpti.h Mon Apr 14 16:28:16 1997 +++ linux/drivers/scsi/qlogicpti.h Wed May 28 10:49:10 1997 @@ -328,6 +328,7 @@ #define CS_ID_MSG_FAILED 0x0013 #define CS_UNEXP_BUS_FREE 0x0014 #define CS_DATA_UNDERRUN 0x0015 +#define CS_BUS_RESET 0x001c /* status entry state flag definitions */ #define SF_GOT_BUS 0x0100 diff -u --recursive --new-file v2.1.41/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v2.1.41/linux/drivers/scsi/scsi.h Sat May 24 09:10:24 1997 +++ linux/drivers/scsi/scsi.h Wed May 28 11:31:47 1997 @@ -24,6 +24,7 @@ #include #include +#include /* * Some defs, in case these are not defined elsewhere. @@ -221,7 +222,7 @@ #ifdef __mc68000__ #include #define CONTIGUOUS_BUFFERS(X,Y) \ - (VTOP((X)->b_data+(X)->b_size-1)+1 == VTOP((Y)->b_data)) + (virt_to_phys((X)->b_data+(X)->b_size-1)+1==virt_to_phys((Y)->b_data)) #else #define CONTIGUOUS_BUFFERS(X,Y) ((X->b_data+X->b_size) == Y->b_data) #endif diff -u --recursive --new-file v2.1.41/linux/drivers/sound/.version.orig linux/drivers/sound/.version.orig --- v2.1.41/linux/drivers/sound/.version.orig Tue Mar 4 10:25:24 1997 +++ linux/drivers/sound/.version.orig Wed Dec 31 16:00:00 1969 @@ -1,2 +0,0 @@ -3.8-beta9 -0x030803 diff -u --recursive --new-file v2.1.41/linux/fs/autofs/autofs_i.h linux/fs/autofs/autofs_i.h --- v2.1.41/linux/fs/autofs/autofs_i.h Wed May 28 10:51:33 1997 +++ linux/fs/autofs/autofs_i.h Wed May 28 11:33:11 1997 @@ -12,7 +12,7 @@ /* Internal header file for autofs */ -#define DEBUG_WAITLIST 1 +/* #define DEBUG_WAITLIST 1 */ #include diff -u --recursive --new-file v2.1.41/linux/fs/buffer.c linux/fs/buffer.c --- v2.1.41/linux/fs/buffer.c Mon May 19 12:57:39 1997 +++ linux/fs/buffer.c Wed May 28 11:01:16 1997 @@ -685,6 +685,9 @@ needed -= PAGE_SIZE; repeat: + if(needed <= 0) + return; + /* OK, we cannot grow the buffer cache, now try to get some * from the lru list. * @@ -692,9 +695,6 @@ * should be quick nearly all of the time. */ - if(needed <= 0) - return; - for(i=0; i= 0) - goto repeat; + goto repeat; } - if(needed <= 0) - return; - /* Too bad, that was not enough. Try a little harder to grow some. */ if (nr_free_pages > min_free_pages + 5) { if (grow_buffers(GFP_BUFFER, size)) { @@ -747,9 +743,10 @@ } /* And repeat until we find something good. */ - if (!grow_buffers(GFP_ATOMIC, size)) + if (grow_buffers(GFP_ATOMIC, size)) + needed -= PAGE_SIZE; + else wakeup_bdflush(1); - needed -= PAGE_SIZE; goto repeat; } @@ -995,6 +992,7 @@ kmem_cache_free(bh_cachep, bh); return; } + memset(bh,0,sizeof(*bh)); nr_unused_buffer_heads++; bh->b_next_free = unused_list; @@ -1034,24 +1032,17 @@ * fields after the final unlock. So, the device driver puts them on * the reuse_list instead once IO completes, and we recover these to * the unused_list here. - * - * The reuse_list receives buffers from interrupt routines, so we need - * to be IRQ-safe here (but note that interrupts only _add_ to the - * reuse_list, never take away. So we don't need to worry about the - * reuse_list magically emptying). */ static inline void recover_reusable_buffer_heads(void) { - if (reuse_list) { - struct buffer_head *head; + struct buffer_head *head; - head = xchg(&reuse_list, NULL); + head = xchg(&reuse_list, NULL); - do { - struct buffer_head *bh = head; - head = head->b_next_free; - put_unused_buffer_head(bh); - } while (head); + while (head) { + struct buffer_head *bh = head; + head = head->b_next_free; + put_unused_buffer_head(bh); } } @@ -1139,7 +1130,7 @@ "async IO mismatch on page.\n"); return; } - tmp->b_next_free = reuse_list; + tmp->b_next_free = xchg(&reuse_list, NULL); reuse_list = tmp; clear_bit(BH_FreeOnIO, &tmp->b_state); tmp = tmp->b_this_page; diff -u --recursive --new-file v2.1.41/linux/fs/filesystems.c linux/fs/filesystems.c --- v2.1.41/linux/fs/filesystems.c Wed Apr 23 19:01:23 1997 +++ linux/fs/filesystems.c Wed May 28 10:49:10 1997 @@ -30,22 +30,16 @@ #ifdef CONFIG_KERNELD #include #endif +#include +#include +#include extern void device_setup(void); extern void binfmt_setup(void); extern void free_initmem(void); -/* This may be used only once, enforced by 'static int callable' */ -asmlinkage int sys_setup(void) +__initfunc(static void do_sys_setup(void)) { - static int callable = 1; - int err = -1; - - lock_kernel(); - if (!callable) - goto out; - callable = 0; - device_setup(); binfmt_setup(); @@ -123,11 +117,28 @@ #endif mount_root(); - - free_initmem(); - - err = 0; -out: +} + +int initmem_freed = 0; + +/* This may be used only twice, enforced by 'static int callable' */ +asmlinkage int sys_setup(int magic) +{ + static int callable = 1; + int err = -1; + + lock_kernel(); + if (magic) { + if (!initmem_freed) { + initmem_freed = 1; + free_initmem (); + err = 0; + } + } else if (callable) { + callable = 0; + do_sys_setup(); + err = 0; + } unlock_kernel(); return err; } diff -u --recursive --new-file v2.1.41/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c --- v2.1.41/linux/fs/nfs/nfsroot.c Thu May 15 16:48:04 1997 +++ linux/fs/nfs/nfsroot.c Wed May 28 10:49:10 1997 @@ -1,10 +1,10 @@ /* - * linux/fs/nfs/nfsroot.c -- version 2.3 + * $Id: nfsroot.c,v 1.36 1997/05/27 15:57:47 mj Exp $ * * Copyright (C) 1995, 1996 Gero Kuhlmann * * For parts of this file: - * Copyright (C) 1996 Martin Mares + * Copyright (C) 1996, 1997 Martin Mares * * Allow an NFS filesystem to be mounted as root. The way this works is: * (1) Determine the local IP address via RARP or BOOTP or from the @@ -54,6 +54,9 @@ * Jacek Zapala : Fixed a bug which prevented server-ip address * from nfsroot parameter from being used. * Olaf Kirch : Adapted to new NFS code. + * Jakub Jelinek : Free used code segment. + * Marko Kohtala : Fixed some bugs. + * Martin Mares : Debug message cleanup * */ @@ -71,6 +74,7 @@ #include #include #include +#include #include #include @@ -120,28 +124,28 @@ struct open_dev *next; }; -static struct open_dev *open_base = NULL; +static struct open_dev *open_base __initdata = NULL; /* IP configuration */ -static struct device *root_dev = NULL; /* Device selected for booting */ -static char user_dev_name[IFNAMSIZ]; /* Name of user-selected boot device */ -static __u32 myaddr; /* My IP address */ -static __u32 servaddr; /* Server IP address */ -static __u32 gateway; /* Gateway IP address */ -static __u32 netmask; /* Netmask for local subnet */ +static struct device *root_dev __initdata = NULL; /* Device selected for booting */ +static char user_dev_name[IFNAMSIZ] __initdata = { 0, };/* Name of user-selected boot device */ +static __u32 myaddr __initdata = 0; /* My IP address */ +static __u32 servaddr __initdata = 0; /* Server IP address */ +static __u32 gateway __initdata = 0; /* Gateway IP address */ +static __u32 netmask __initdata = 0; /* Netmask for local subnet */ /* BOOTP/RARP variables */ -static int bootp_flag; /* User said: Use BOOTP! */ -static int rarp_flag; /* User said: Use RARP! */ -static int bootp_dev_count = 0; /* Number of devices allowing BOOTP */ -static int rarp_dev_count = 0; /* Number of devices allowing RARP */ -static __u32 rarp_serv; /* IP address of RARP server */ +static int bootp_flag __initdata = 0; /* User said: Use BOOTP! */ +static int rarp_flag __initdata = 0; /* User said: Use RARP! */ +static int bootp_dev_count __initdata = 0; /* Number of devices allowing BOOTP */ +static int rarp_dev_count __initdata = 0; /* Number of devices allowing RARP */ +static __u32 rarp_serv __initdata = 0; /* IP address of RARP server */ #if defined(CONFIG_RNFS_BOOTP) || defined(CONFIG_RNFS_RARP) -#define CONFIG_RNFS_DYNAMIC /* Enable dynamic IP config */ -static volatile int pkt_arrived; /* BOOTP/RARP packet detected */ +#define CONFIG_RNFS_DYNAMIC /* Enable dynamic IP config */ +static volatile int pkt_arrived __initdata = 0; /* BOOTP/RARP packet detected */ #define ARRIVED_BOOTP 1 #define ARRIVED_RARP 2 @@ -149,10 +153,10 @@ /* NFS-related data */ -static struct nfs_mount_data nfs_data; /* NFS mount info */ -static char nfs_path[NFS_MAXPATHLEN]; /* Name of directory to mount */ -static int nfs_port; /* Port to connect to for NFS */ -static int mount_port; /* Mount daemon port number */ +static struct nfs_mount_data nfs_data __initdata = { 0, };/* NFS mount info */ +static char nfs_path[NFS_MAXPATHLEN] __initdata = { 0, };/* Name of directory to mount */ +static int nfs_port __initdata = 0; /* Port to connect to for NFS */ +static int mount_port __initdata = 0; /* Mount daemon port number */ /* Yes, we use sys_socket, but there's no include file for it */ @@ -170,7 +174,7 @@ * Setup and initialize all network devices. If there is a user-preferred * interface, ignore all other interfaces. */ -static int root_dev_open(void) +__initfunc(static int root_dev_open(void)) { struct open_dev *openp, **last; struct device *dev; @@ -221,8 +225,8 @@ sin->sin_port = port; } -static int -root_dev_chg_route(int op, struct device *dev, __u32 dest, __u32 mask, __u32 gw) +__initfunc(static int +root_dev_chg_route(int op, struct device *dev, __u32 dest, __u32 mask, __u32 gw)) { struct rtentry route; unsigned long oldfs; @@ -250,26 +254,28 @@ err = ip_rt_ioctl(op, &route); set_fs(oldfs); +#ifdef NFSROOT_DEBUG /* in_ntoa in ipv4/utils.c uses a single static buffer, so * must make multiple printk calls, one for each in_ntoa * invocation... */ - printk(KERN_NOTICE "%s route ", (op == SIOCADDRT ? "addr" : "del")); + printk(KERN_NOTICE "%s route ", (op == SIOCADDRT ? "add" : "del")); printk("%s ", in_ntoa(dest)); printk("%s ", in_ntoa(mask)); printk("%s: res %d\n", in_ntoa(gw), err); +#endif return err; } -static int -root_dev_add_route(struct device *dev, __u32 dest, __u32 mask, __u32 gateway) +__initfunc(static int +root_dev_add_route(struct device *dev, __u32 dest, __u32 mask, __u32 gateway)) { return root_dev_chg_route(SIOCADDRT, dev, dest, mask, gateway); } -static int -root_dev_del_route(struct device *dev, __u32 dest, __u32 mask, __u32 gateway) +__initfunc(static int +root_dev_del_route(struct device *dev, __u32 dest, __u32 mask, __u32 gateway)) { return root_dev_chg_route(SIOCDELRT, dev, dest, mask, gateway); } @@ -278,7 +284,7 @@ * Restore the state of all devices. However, keep the root device open * for the upcoming mount. */ -static void root_dev_close(void) +__initfunc(static void root_dev_close(void)) { struct open_dev *openp; struct open_dev *nextp; @@ -318,7 +324,7 @@ struct packet_type *pt); -static struct packet_type rarp_packet_type = { +static struct packet_type rarp_packet_type __initdata = { 0, /* Should be: __constant_htons(ETH_P_RARP) * - but this _doesn't_ come out constant! */ NULL, /* Listen to all devices */ @@ -331,7 +337,7 @@ /* * Register the packet type for RARP */ -static void root_rarp_open(void) +__initfunc(static void root_rarp_open(void)) { rarp_packet_type.type = htons(ETH_P_RARP); dev_add_pack(&rarp_packet_type); @@ -341,7 +347,7 @@ /* * Deregister the RARP packet type */ -static void root_rarp_close(void) +__initfunc(static void root_rarp_close(void)) { rarp_packet_type.type = htons(ETH_P_RARP); dev_remove_pack(&rarp_packet_type); @@ -351,7 +357,8 @@ /* * Receive RARP packets. */ -static int root_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) +__initfunc(static int +root_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)) { struct arphdr *rarp = (struct arphdr *)skb->h.raw; unsigned char *rarp_ptr = (unsigned char *) (rarp + 1); @@ -428,7 +435,7 @@ /* * Send RARP request packet over all devices which allow RARP. */ -static void root_rarp_send(void) +__initfunc(static void root_rarp_send(void)) { struct open_dev *openp; struct device *dev; @@ -455,10 +462,10 @@ #ifdef CONFIG_RNFS_BOOTP -static struct device *bootp_dev = NULL; /* Device selected as best BOOTP target */ +static struct device *bootp_dev __initdata = NULL; /* Device selected as best BOOTP target */ -static struct socket *bootp_xmit_sock; /* BOOTP send socket */ -static struct socket *bootp_recv_sock; /* BOOTP receive socket */ +static struct socket *bootp_xmit_sock __initdata = NULL;/* BOOTP send socket */ +static struct socket *bootp_recv_sock __initdata = NULL;/* BOOTP receive socket */ struct bootp_pkt { /* BOOTP packet format */ u8 op; /* 1=request, 2=reply */ @@ -481,16 +488,16 @@ #define BOOTP_REQUEST 1 #define BOOTP_REPLY 2 -static struct bootp_pkt *xmit_bootp; /* Packet being transmitted */ -static struct bootp_pkt *recv_bootp; /* Packet being received */ +static struct bootp_pkt *xmit_bootp __initdata = NULL; /* Packet being transmitted */ +static struct bootp_pkt *recv_bootp __initdata = NULL; /* Packet being received */ -static int bootp_have_route = 0; /* BOOTP route installed */ +static int bootp_have_route __initdata = 0; /* BOOTP route installed */ /* * Free BOOTP packet buffers */ -static void root_free_bootp(void) +__initfunc(static void root_free_bootp(void)) { if (xmit_bootp) { kfree_s(xmit_bootp, sizeof(struct bootp_pkt)); @@ -510,7 +517,7 @@ { if (!(xmit_bootp = kmalloc(sizeof(struct bootp_pkt), GFP_KERNEL)) || !(recv_bootp = kmalloc(sizeof(struct bootp_pkt), GFP_KERNEL))) { - printk("BOOTP: Out of memory!"); + printk(KERN_ERR "BOOTP: Out of memory!\n"); return -1; } return 0; @@ -520,7 +527,7 @@ /* * Create default route for BOOTP sending */ -static int root_add_bootp_route(void) +__initfunc(static int root_add_bootp_route(void)) { if (root_dev_add_route(bootp_dev, 0, 0, 0) < 0) { printk(KERN_ERR "BOOTP: Failed to add route\n"); @@ -534,7 +541,7 @@ /* * Delete default route for BOOTP sending */ -static int root_del_bootp_route(void) +__initfunc(static int root_del_bootp_route(void)) { if (bootp_have_route && root_dev_del_route(bootp_dev, 0, 0, 0) < 0) { printk(KERN_ERR "BOOTP: Deleting of route failed!\n"); @@ -548,7 +555,7 @@ /* * Open UDP socket. */ -static int root_open_udp_sock(struct socket **sock) +__initfunc(static int root_open_udp_sock(struct socket **sock)) { int err; @@ -561,12 +568,13 @@ /* * Connect UDP socket. */ -static int root_connect_udp_sock(struct socket *sock, u32 addr, u16 port) +__initfunc(static int +root_connect_udp_sock(struct socket *sock, u32 addr, u16 port)) { struct sockaddr_in sa; int result; - set_sockaddr(&sa, htonl(addr), htonl(port)); + set_sockaddr(&sa, htonl(addr), htons(port)); result = sock->ops->connect(sock, (struct sockaddr *) &sa, sizeof(sa), 0); if (result < 0) { printk(KERN_ERR "BOOTP: connect() failed\n"); @@ -579,12 +587,13 @@ /* * Bind UDP socket. */ -static int root_bind_udp_sock(struct socket *sock, u32 addr, u16 port) +__initfunc(static int +root_bind_udp_sock(struct socket *sock, u32 addr, u16 port)) { struct sockaddr_in sa; int result; - set_sockaddr(&sa, htonl(addr), htonl(port)); + set_sockaddr(&sa, htonl(addr), htons(port)); result = sock->ops->bind(sock, (struct sockaddr *) &sa, sizeof(sa)); if (result < 0) { printk(KERN_ERR "BOOTP: bind() failed\n"); @@ -645,7 +654,7 @@ /* * Initialize BOOTP extension fields in the request. */ -static void root_bootp_init_ext(u8 *e) +__initfunc(static void root_bootp_init_ext(u8 *e)) { *e++ = 99; /* RFC1048 Magic Cookie */ *e++ = 130; @@ -673,7 +682,7 @@ /* * Deinitialize the BOOTP mechanism. */ -static void root_bootp_close(void) +__initfunc(static void root_bootp_close(void)) { if (bootp_xmit_sock) sock_release(bootp_xmit_sock); @@ -687,7 +696,7 @@ /* * Initialize the BOOTP mechanism. */ -static int root_bootp_open(void) +__initfunc(static int root_bootp_open(void)) { struct open_dev *openp; struct device *dev, *best_dev; @@ -767,7 +776,7 @@ /* * Send BOOTP request. */ -static int root_bootp_send(u32 jiffies) +__initfunc(static int root_bootp_send(u32 jiffies)) { xmit_bootp->secs = htons(jiffies / HZ); return root_send_udp(bootp_xmit_sock, xmit_bootp, sizeof(struct bootp_pkt)); @@ -777,7 +786,8 @@ /* * Copy BOOTP-supplied string if not already set. */ -static int root_bootp_string(char *dest, char *src, int len, int max) +__initfunc(static int +root_bootp_string(char *dest, char *src, int len, int max)) { if (*dest || !len) return 0; @@ -792,12 +802,12 @@ /* * Process BOOTP extension. */ -static void root_do_bootp_ext(u8 *ext) +__initfunc(static void root_do_bootp_ext(u8 *ext)) { #ifdef NFSROOT_BOOTP_DEBUG u8 *c; - printk("BOOTP: Got extension %02x",*ext); + printk(KERN_DEBUG "BOOTP: Got extension %02x",*ext); for(c=ext+2; c - use both protocols to determine my own address */ -static void root_nfs_addrs(char *addrs) +__initfunc(static void root_nfs_addrs(char *addrs)) { char *cp, *ip, *dp; int num = 0; @@ -1314,7 +1326,7 @@ /* * Set the interface address and configure a route to the server. */ -static int root_nfs_setup(void) +__initfunc(static int root_nfs_setup(void)) { /* Set the default system name in case none was previously found */ if (!system_utsname.nodename[0]) { @@ -1372,7 +1384,7 @@ * Get the necessary IP addresses and prepare for mounting the required * NFS filesystem. */ -int nfs_root_init(char *nfsname, char *nfsaddrs) +__initfunc(int nfs_root_init(char *nfsname, char *nfsaddrs)) { #ifdef NFSROOT_DEBUG nfs_debug |= NFSDBG_ROOT; @@ -1461,14 +1473,14 @@ /* * Query server portmapper for the port of a daemon program */ -static int root_nfs_getport(int program, int version) +__initfunc(static int root_nfs_getport(int program, int version)) { struct sockaddr_in sin; -printk(KERN_NOTICE "Looking up port of RPC %d/%d on %s\n", - program, version, in_ntoa(servaddr)); - set_sockaddr(&sin, servaddr, 0); - return rpc_getport_external(&sin, program, version, IPPROTO_UDP); + printk(KERN_NOTICE "Looking up port of RPC %d/%d on %s\n", + program, version, in_ntoa(servaddr)); + set_sockaddr(&sin, servaddr, 0); + return rpc_getport_external(&sin, program, version, IPPROTO_UDP); } @@ -1478,7 +1490,7 @@ * keep this code is that we may want to use fallback ports. But is there * actually someone who does not run portmap? */ -static int root_nfs_ports(void) +__initfunc(static int root_nfs_ports(void)) { int port; @@ -1488,7 +1500,7 @@ "number from server, using default\n"); port = NFS_PORT; } - nfs_port = port; + nfs_port = htons(port); dprintk("Root-NFS: Portmapper on server returned %d " "as nfsd port\n", port); } @@ -1511,7 +1523,7 @@ * Get a file handle from the server for the directory which is to be * mounted */ -static int root_nfs_get_handle(void) +__initfunc(static int root_nfs_get_handle(void)) { struct sockaddr_in sin; int status; @@ -1529,7 +1541,7 @@ /* * Now actually mount the given directory */ -static int root_nfs_do_mount(struct super_block *sb) +__initfunc(static int root_nfs_do_mount(struct super_block *sb)) { /* Pass the server address to NFS */ set_sockaddr((struct sockaddr_in *) &nfs_data.addr, servaddr, nfs_port); @@ -1545,7 +1557,7 @@ * Get the NFS port numbers and file handle, and then read the super- * block for mounting. */ -int nfs_root_mount(struct super_block *sb) +__initfunc(int nfs_root_mount(struct super_block *sb)) { if (root_nfs_ports() < 0) return -1; diff -u --recursive --new-file v2.1.41/linux/fs/super.c linux/fs/super.c --- v2.1.41/linux/fs/super.c Tue May 13 22:41:15 1997 +++ linux/fs/super.c Wed May 28 10:49:10 1997 @@ -938,11 +938,7 @@ return retval; } -#ifdef CONFIG_BLK_DEV_INITRD -static void do_mount_root(void) -#else __initfunc(static void do_mount_root(void)) -#endif { struct file_system_type * fs_type; struct super_block * sb; @@ -1060,7 +1056,9 @@ #ifdef CONFIG_BLK_DEV_INITRD -int change_root(kdev_t new_root_dev,const char *put_old) +extern int initmem_freed; + +__initfunc(static int do_change_root(kdev_t new_root_dev,const char *put_old)) { kdev_t old_root_dev; struct vfsmount *vfsmnt; @@ -1112,6 +1110,15 @@ } inode->i_mount = old_root; return 0; +} + +int change_root(kdev_t new_root_dev,const char *put_old) +{ + if (initmem_freed) { + printk (KERN_CRIT "Initmem has been already freed. Staying in initrd\n"); + return -EBUSY; + } + return do_change_root(new_root_dev, put_old); } #endif diff -u --recursive --new-file v2.1.41/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h --- v2.1.41/linux/include/asm-alpha/unistd.h Fri Apr 4 08:52:25 1997 +++ linux/include/asm-alpha/unistd.h Wed May 28 10:49:10 1997 @@ -352,10 +352,10 @@ sys_idle(); } -extern int sys_setup(void); -static inline int setup(void) +extern int sys_setup(int); +static inline int setup(int magic) { - return sys_setup(); + return sys_setup(magic); } extern int sys_open(const char *, int, int); diff -u --recursive --new-file v2.1.41/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h --- v2.1.41/linux/include/asm-i386/unistd.h Fri Apr 4 08:52:25 1997 +++ linux/include/asm-i386/unistd.h Wed May 28 10:49:10 1997 @@ -271,7 +271,7 @@ static inline _syscall0(int,fork) static inline _syscall2(int,clone,unsigned long,flags,char *,esp) static inline _syscall0(int,pause) -static inline _syscall0(int,setup) +static inline _syscall1(int,setup,int,magic) static inline _syscall0(int,sync) static inline _syscall0(pid_t,setsid) static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) diff -u --recursive --new-file v2.1.41/linux/include/asm-m68k/unistd.h linux/include/asm-m68k/unistd.h --- v2.1.41/linux/include/asm-m68k/unistd.h Sat May 24 09:10:24 1997 +++ linux/include/asm-m68k/unistd.h Wed May 28 10:49:10 1997 @@ -293,7 +293,7 @@ static inline _syscall0(int,fork) static inline _syscall2(int,clone,unsigned long,flags,char *,usp) static inline _syscall0(int,pause) -static inline _syscall0(int,setup) +static inline _syscall1(int,setup,int,magic) static inline _syscall0(int,sync) static inline _syscall0(pid_t,setsid) static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) diff -u --recursive --new-file v2.1.41/linux/include/asm-mips/unistd.h linux/include/asm-mips/unistd.h --- v2.1.41/linux/include/asm-mips/unistd.h Tue May 13 22:41:17 1997 +++ linux/include/asm-mips/unistd.h Wed May 28 10:49:10 1997 @@ -1297,7 +1297,7 @@ static inline _syscall0(int,fork) static inline _syscall2(int,clone,unsigned long,flags,char *,esp) static inline _syscall0(int,pause) -static inline _syscall0(int,setup) +static inline _syscall1(int,setup,int,magic) static inline _syscall0(int,sync) static inline _syscall0(pid_t,setsid) static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) diff -u --recursive --new-file v2.1.41/linux/include/asm-ppc/unistd.h linux/include/asm-ppc/unistd.h --- v2.1.41/linux/include/asm-ppc/unistd.h Fri Apr 4 08:52:25 1997 +++ linux/include/asm-ppc/unistd.h Wed May 28 10:49:10 1997 @@ -329,7 +329,7 @@ static inline _syscall0(int,idle) /* made inline "just in case" -- Cort */ static inline _syscall0(int,fork) /* needs to be inline */ static inline _syscall0(int,pause) /* needs to be inline */ -static inline _syscall0(int,setup) /* called in init before execve */ +static inline _syscall1(int,setup,int,magic) /* called in init before execve */ static inline _syscall0(int,sync) static inline _syscall0(pid_t,setsid) static /*inline*/ _syscall3(int,write,int,fd,const char *,buf,off_t,count) diff -u --recursive --new-file v2.1.41/linux/include/asm-sparc/byteorder.h linux/include/asm-sparc/byteorder.h --- v2.1.41/linux/include/asm-sparc/byteorder.h Thu Dec 19 01:03:37 1996 +++ linux/include/asm-sparc/byteorder.h Wed May 28 10:49:10 1997 @@ -1,17 +1,17 @@ -/* $Id: byteorder.h,v 1.12 1996/12/19 08:08:20 davem Exp $ */ +/* $Id: byteorder.h,v 1.13 1997/05/26 23:37:46 davem Exp $ */ #ifndef _SPARC_BYTEORDER_H #define _SPARC_BYTEORDER_H -#define ntohl(x) (x) -#define ntohs(x) (x) -#define htonl(x) (x) -#define htons(x) (x) +#define ntohl(x) ((unsigned long int)(x)) +#define ntohs(x) ((unsigned short int)(x)) +#define htonl(x) ((unsigned long int)(x)) +#define htons(x) ((unsigned short int)(x)) /* Some programs depend upon these being around. */ -#define __constant_ntohl(x) (x) -#define __constant_ntohs(x) (x) -#define __constant_htonl(x) (x) -#define __constant_htons(x) (x) +#define __constant_ntohl(x) ((unsigned long int)(x)) +#define __constant_ntohs(x) ((unsigned short int)(x)) +#define __constant_htonl(x) ((unsigned long int)(x)) +#define __constant_htons(x) ((unsigned short int)(x)) #ifndef __BIG_ENDIAN #define __BIG_ENDIAN 4321 diff -u --recursive --new-file v2.1.41/linux/include/asm-sparc/irq.h linux/include/asm-sparc/irq.h --- v2.1.41/linux/include/asm-sparc/irq.h Thu May 15 16:48:04 1997 +++ linux/include/asm-sparc/irq.h Wed May 28 10:49:10 1997 @@ -1,4 +1,4 @@ -/* $Id: irq.h,v 1.19 1997/05/08 20:57:39 davem Exp $ +/* $Id: irq.h,v 1.20 1997/05/28 05:25:07 davem Exp $ * irq.h: IRQ registers on the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -24,7 +24,7 @@ extern void irq_enter(int cpu, int irq, void *regs); extern void irq_exit(int cpu, int irq); #else -extern __inline__ void irq_enter(int cpu, int irq) +extern __inline__ void irq_enter(int cpu, int irq, void *regs) { register int proc asm("g1"); proc = cpu; @@ -51,8 +51,8 @@ } #endif /* DEBUG_IRQLOCK */ #else -#define irq_enter(cpu, irq) (local_irq_count[cpu]++) -#define irq_exit(cpu, irq) (local_irq_count[cpu]--) +#define irq_enter(cpu, irq, regs) (local_irq_count[cpu]++) +#define irq_exit(cpu, irq) (local_irq_count[cpu]--) #endif /* Dave Redman (djhr@tadpole.co.uk) diff -u --recursive --new-file v2.1.41/linux/include/asm-sparc/semaphore.h linux/include/asm-sparc/semaphore.h --- v2.1.41/linux/include/asm-sparc/semaphore.h Tue May 13 22:41:18 1997 +++ linux/include/asm-sparc/semaphore.h Wed May 28 10:49:10 1997 @@ -9,12 +9,12 @@ struct semaphore { atomic_t count; - atomic_t waking; + int waking; struct wait_queue * wait; }; -#define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL }) -#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL }) +#define MUTEX ((struct semaphore) { ATOMIC_INIT(1), 0, NULL }) +#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), 0, NULL }) extern void __down(struct semaphore * sem); extern int __down_interruptible(struct semaphore * sem); @@ -22,23 +22,24 @@ #define sema_init(sem, val) atomic_set(&((sem)->count), val) -#define wake_one_more(sem) atomic_inc(&sem->waking); +#define wake_one_more(sem) \ +do { \ + unsigned long flags; \ + save_and_cli(flags); \ + sem->waking++; \ + restore_flags(flags); \ +} while(0) -/* XXX Put this in raw assembler for SMP case so that the atomic_t - * XXX spinlock can allow this to be done without grabbing the IRQ - * XXX global lock. - */ -#define waking_non_zero(sem) \ -({ unsigned long flags; \ - int ret = 0; \ - save_flags(flags); \ - cli(); \ - if (atomic_read(&sem->waking) > 0) { \ - atomic_dec(&sem->waking); \ - ret = 1; \ - } \ - restore_flags(flags); \ - ret; \ +#define waking_non_zero(sem) \ +({ unsigned long flags; \ + int ret = 0; \ + save_and_cli(flags); \ + if (sem->waking > 0) { \ + sem->waking--; \ + ret = 1; \ + } \ + restore_flags(flags); \ + ret; \ }) /* This isn't quite as clever as the x86 side, I'll be fixing this diff -u --recursive --new-file v2.1.41/linux/include/asm-sparc/string.h linux/include/asm-sparc/string.h --- v2.1.41/linux/include/asm-sparc/string.h Thu May 15 16:48:04 1997 +++ linux/include/asm-sparc/string.h Wed May 28 10:49:10 1997 @@ -1,4 +1,4 @@ -/* $Id: string.h,v 1.31 1997/05/03 02:02:12 davem Exp $ +/* $Id: string.h,v 1.32 1997/05/20 07:58:59 jj Exp $ * string.h: External definitions for optimized assembly string * routines for the Linux Kernel. * @@ -34,7 +34,7 @@ extern inline void *__constant_memcpy(void *to, const void *from, __kernel_size_t n) { - extern void (*__copy_1page)(void *, const void *); + extern void __copy_1page(void *, const void *); if(n <= 32) { __builtin_memcpy(to, from, n); @@ -67,7 +67,7 @@ extern inline void *__constant_c_and_count_memset(void *s, char c, __kernel_size_t count) { - extern void (*bzero_1page)(void *); + extern void bzero_1page(void *); extern __kernel_size_t __bzero(void *, __kernel_size_t); if(!c) { diff -u --recursive --new-file v2.1.41/linux/include/asm-sparc/unistd.h linux/include/asm-sparc/unistd.h --- v2.1.41/linux/include/asm-sparc/unistd.h Mon Apr 14 16:28:21 1997 +++ linux/include/asm-sparc/unistd.h Wed May 28 10:49:11 1997 @@ -1,4 +1,4 @@ -/* $Id: unistd.h,v 1.32 1997/04/11 00:42:23 davem Exp $ */ +/* $Id: unistd.h,v 1.33 1997/05/21 10:21:55 jj Exp $ */ #ifndef _SPARC_UNISTD_H #define _SPARC_UNISTD_H @@ -428,7 +428,7 @@ static __inline__ _syscall0(int,fork) static __inline__ _syscall2(int,clone,unsigned long,flags,char *,ksp) static __inline__ _syscall0(int,pause) -static __inline__ _syscall0(int,setup) +static __inline__ _syscall1(int,setup,int,magic) static __inline__ _syscall0(int,sync) static __inline__ _syscall0(pid_t,setsid) static __inline__ _syscall3(int,write,int,fd,__const__ char *,buf,off_t,count) diff -u --recursive --new-file v2.1.41/linux/include/asm-sparc64/asm_offsets.h linux/include/asm-sparc64/asm_offsets.h --- v2.1.41/linux/include/asm-sparc64/asm_offsets.h Thu May 15 16:48:04 1997 +++ linux/include/asm-sparc64/asm_offsets.h Wed May 28 10:49:11 1997 @@ -228,6 +228,8 @@ #define ASIZ_thread_wstate 0x00000008 #define AOFF_thread_cwp 0x00000120 #define ASIZ_thread_cwp 0x00000008 +#define AOFF_thread_ctx 0x00000128 +#define ASIZ_thread_ctx 0x00000008 #define AOFF_thread_reg_window 0x00000130 #define ASIZ_thread_reg_window 0x00000400 #define AOFF_thread_rwbuf_stkptrs 0x00000530 diff -u --recursive --new-file v2.1.41/linux/include/asm-sparc64/bitops.h linux/include/asm-sparc64/bitops.h --- v2.1.41/linux/include/asm-sparc64/bitops.h Thu May 15 16:48:04 1997 +++ linux/include/asm-sparc64/bitops.h Wed May 28 10:49:11 1997 @@ -1,4 +1,4 @@ -/* $Id: bitops.h,v 1.12 1997/05/14 20:48:04 davem Exp $ +/* $Id: bitops.h,v 1.13 1997/05/27 06:47:16 davem Exp $ * bitops.h: Bit string operations on the V9. * * Copyright 1996 David S. Miller (davem@caip.rutgers.edu) @@ -109,12 +109,24 @@ /* The easy/cheese version for now. */ extern __inline__ unsigned long ffz(unsigned long word) { - unsigned long result = 0; + unsigned long result; +#ifdef ULTRA_HAS_POPULATION_COUNT /* Thanks for nothing Sun... */ + __asm__ __volatile__(" + brz,pn %0, 1f + neg %0, %%g1 + xnor %0, %%g1, %%g2 + popc %%g2, %0 +1: " : "=&r" (result) + : "0" (word) + : "g1", "g2"); +#else + result = 0; while(word & 1) { result++; word >>= 1; } +#endif return result; } diff -u --recursive --new-file v2.1.41/linux/include/asm-sparc64/byteorder.h linux/include/asm-sparc64/byteorder.h --- v2.1.41/linux/include/asm-sparc64/byteorder.h Thu Mar 27 14:40:09 1997 +++ linux/include/asm-sparc64/byteorder.h Wed May 28 10:49:11 1997 @@ -1,17 +1,17 @@ -/* $Id: byteorder.h,v 1.3 1997/03/14 21:05:31 jj Exp $ */ +/* $Id: byteorder.h,v 1.4 1997/05/26 23:37:47 davem Exp $ */ #ifndef _SPARC64_BYTEORDER_H #define _SPARC64_BYTEORDER_H -#define ntohl(x) (x) -#define ntohs(x) (x) -#define htonl(x) (x) -#define htons(x) (x) +#define ntohl(x) ((unsigned long int)(x)) +#define ntohs(x) ((unsigned short int)(x)) +#define htonl(x) ((unsigned long int)(x)) +#define htons(x) ((unsigned short int)(x)) /* Some programs depend upon these being around. */ -#define __constant_ntohl(x) (x) -#define __constant_ntohs(x) (x) -#define __constant_htonl(x) (x) -#define __constant_htons(x) (x) +#define __constant_ntohl(x) ((unsigned long int)(x)) +#define __constant_ntohs(x) ((unsigned short int)(x)) +#define __constant_htonl(x) ((unsigned long int)(x)) +#define __constant_htons(x) ((unsigned short int)(x)) #ifndef __BIG_ENDIAN #define __BIG_ENDIAN 4321 diff -u --recursive --new-file v2.1.41/linux/include/asm-sparc64/cache.h linux/include/asm-sparc64/cache.h --- v2.1.41/linux/include/asm-sparc64/cache.h Thu Mar 27 14:40:09 1997 +++ linux/include/asm-sparc64/cache.h Wed May 28 10:49:11 1997 @@ -4,9 +4,8 @@ #ifndef __ARCH_SPARC64_CACHE_H #define __ARCH_SPARC64_CACHE_H -/* FIXME: Should look at this soon */ /* bytes per L1 cache line */ -#define L1_CACHE_BYTES 32 /* a guess */ +#define L1_CACHE_BYTES 32 /* Two 16-byte sub-blocks per line. */ #define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) diff -u --recursive --new-file v2.1.41/linux/include/asm-sparc64/hardirq.h linux/include/asm-sparc64/hardirq.h --- v2.1.41/linux/include/asm-sparc64/hardirq.h Mon Apr 14 16:28:22 1997 +++ linux/include/asm-sparc64/hardirq.h Wed May 28 10:49:11 1997 @@ -10,11 +10,8 @@ extern unsigned int local_irq_count[NR_CPUS]; #define in_interrupt() (local_irq_count[smp_processor_id()] != 0) -#define hardirq_depth() (local_irq_count[smp_processor_id()]) -#ifdef __SMP__ -#error SMP not supported on sparc64 -#else /* !(__SMP__) */ +#ifndef __SMP__ #define hardirq_trylock(cpu) (++local_irq_count[cpu], (cpu)==0) #define hardirq_endlock(cpu) (--local_irq_count[cpu]) @@ -23,6 +20,62 @@ #define hardirq_exit(cpu) (local_irq_count[cpu]--) #define synchronize_irq() do { } while(0) + +#else /* (__SMP__) */ + +#include +#include +#include +#include + +extern unsigned char global_irq_holder; +extern spinlock_t global_irq_lock; +extern atomic_t global_irq_count; + +static inline void release_irqlock(int cpu) +{ + /* if we didn't own the irq lock, just ignore... */ + if(global_irq_holder == (unsigned char) cpu) { + global_irq_holder = NO_PROC_ID; + spin_unlock(&global_irq_lock); + } +} + +static inline void hardirq_enter(int cpu) +{ + ++local_irq_count[cpu]; + atomic_inc(&global_irq_count); +} + +static inline void hardirq_exit(int cpu) +{ + atomic_dec(&global_irq_count); + --local_irq_count[cpu]; +} + +static inline int hardirq_trylock(int cpu) +{ + unsigned long flags; + + __save_and_cli(flags); + if(atomic_add_return(1, &global_irq_count) != 1 || + *(((unsigned char *)(&global_irq_lock)))) { + atomic_dec(&global_irq_count); + __restore_flags(flags); + return 0; + } + ++local_irq_count[cpu]; + return 1; +} + +static inline void hardirq_endlock(int cpu) +{ + __cli(); + hardirq_exit(cpu); + __sti(); +} + +extern void synchronize_irq(void); #endif /* __SMP__ */ diff -u --recursive --new-file v2.1.41/linux/include/asm-sparc64/head.h linux/include/asm-sparc64/head.h --- v2.1.41/linux/include/asm-sparc64/head.h Sat May 24 09:10:25 1997 +++ linux/include/asm-sparc64/head.h Wed May 28 10:49:11 1997 @@ -1,4 +1,4 @@ -/* $Id: head.h,v 1.19 1997/05/18 08:42:18 davem Exp $ */ +/* $Id: head.h,v 1.21 1997/05/27 06:28:17 davem Exp $ */ #ifndef _SPARC64_HEAD_H #define _SPARC64_HEAD_H @@ -143,9 +143,15 @@ #define BTRAPTL1(lvl) TRAPTL1_ARG(bad_trap_tl1, lvl) -#define FLUSH_WINDOW_TRAP \ - flushw; \ - done; nop; nop; nop; nop; nop; nop; +#define FLUSH_WINDOW_TRAP \ + ba,pt %xcc, etrap; \ + rd %pc, %g7; \ + flushw; \ + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1; \ + add %l1, 4, %l2; \ + stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]; \ + ba,pt %xcc, rtrap; \ + stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]; /* Before touching these macros, you owe it to yourself to go and * see how arch/sparc64/kernel/winfixup.S works... -DaveM diff -u --recursive --new-file v2.1.41/linux/include/asm-sparc64/mmu_context.h linux/include/asm-sparc64/mmu_context.h --- v2.1.41/linux/include/asm-sparc64/mmu_context.h Sat May 24 09:10:25 1997 +++ linux/include/asm-sparc64/mmu_context.h Wed May 28 10:49:11 1997 @@ -1,4 +1,4 @@ -/* $Id: mmu_context.h,v 1.8 1997/05/18 20:44:23 davem Exp $ */ +/* $Id: mmu_context.h,v 1.10 1997/05/23 09:35:55 jj Exp $ */ #ifndef __SPARC64_MMU_CONTEXT_H #define __SPARC64_MMU_CONTEXT_H @@ -20,8 +20,6 @@ extern unsigned long tlb_context_cache; -#define MAX_CTX PAGE_SIZE - #define CTX_VERSION_SHIFT PAGE_SHIFT #define CTX_VERSION_MASK ((~0UL) << CTX_VERSION_SHIFT) #define CTX_FIRST_VERSION ((1UL << CTX_VERSION_SHIFT) + 1UL) @@ -29,7 +27,7 @@ extern __inline__ void get_new_mmu_context(struct mm_struct *mm, unsigned long ctx) { - if((ctx & ~CTX_VERSION_MASK) > MAX_CTX) { + if((ctx & ~(CTX_VERSION_MASK)) == 0) { unsigned long flags; int entry; @@ -68,7 +66,9 @@ flushw_user(); if((mm->context ^ ctx) & CTX_VERSION_MASK) get_new_mmu_context(mm, ctx); - spitfire_set_secondary_context(mm->context); + tsk->tss.ctx = (mm->context & 0x1fff); + spitfire_set_secondary_context(tsk->tss.current_ds ? + mm->context : 0); paddr = __pa(mm->pgd); __asm__ __volatile__(" rdpr %%pstate, %%o4 diff -u --recursive --new-file v2.1.41/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h --- v2.1.41/linux/include/asm-sparc64/pgtable.h Sat May 24 09:10:25 1997 +++ linux/include/asm-sparc64/pgtable.h Wed May 28 10:49:11 1997 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.31 1997/05/18 21:11:42 davem Exp $ +/* $Id: pgtable.h,v 1.32 1997/05/26 23:39:20 davem Exp $ * pgtable.h: SpitFire page table operations. * * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -440,7 +440,7 @@ paddr = __pa(pgdir); - if(tsk->mm == current->mm) { + if(tsk == current) { __asm__ __volatile__ (" rdpr %%pstate, %%o4 wrpr %%o4, %1, %%pstate diff -u --recursive --new-file v2.1.41/linux/include/asm-sparc64/processor.h linux/include/asm-sparc64/processor.h --- v2.1.41/linux/include/asm-sparc64/processor.h Sat May 24 09:10:25 1997 +++ linux/include/asm-sparc64/processor.h Wed May 28 10:49:11 1997 @@ -1,4 +1,4 @@ -/* $Id: processor.h,v 1.26 1997/05/17 05:59:10 davem Exp $ +/* $Id: processor.h,v 1.27 1997/05/23 09:35:52 jj Exp $ * include/asm-sparc64/processor.h * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -41,7 +41,7 @@ unsigned long fsr; /* Context switch saved kernel state. */ - unsigned long ksp, kpc, wstate, cwp; + unsigned long ksp, kpc, wstate, cwp, ctx; /* Storage for windows when user stack is bogus. */ struct reg_window reg_window[NSWINS] __attribute__ ((aligned (16))); @@ -80,8 +80,8 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \ /* FPU status */ \ 0, \ -/* ksp, kpc, wstate, cwp */ \ - 0, 0, 0, 0, \ +/* ksp, kpc, wstate, cwp, secctx */ \ + 0, 0, 0, 0, 0, \ /* reg_window */ \ { { { 0, }, { 0, } }, }, \ /* rwbuf_stkptrs */ \ diff -u --recursive --new-file v2.1.41/linux/include/asm-sparc64/ptrace.h linux/include/asm-sparc64/ptrace.h --- v2.1.41/linux/include/asm-sparc64/ptrace.h Mon Mar 17 14:54:34 1997 +++ linux/include/asm-sparc64/ptrace.h Wed May 28 10:49:11 1997 @@ -1,4 +1,4 @@ -/* $Id: ptrace.h,v 1.7 1997/03/04 16:27:32 jj Exp $ */ +/* $Id: ptrace.h,v 1.8 1997/05/27 19:30:27 jj Exp $ */ #ifndef _SPARC64_PTRACE_H #define _SPARC64_PTRACE_H @@ -250,5 +250,21 @@ #define SF_XARG4 0x54 #define SF_XARG5 0x58 #define SF_XXARG 0x5c + +/* Stuff for the ptrace system call */ +#define PTRACE_SUNATTACH 10 +#define PTRACE_SUNDETACH 11 +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#define PTRACE_GETFPREGS 14 +#define PTRACE_SETFPREGS 15 +#define PTRACE_READDATA 16 +#define PTRACE_WRITEDATA 17 +#define PTRACE_READTEXT 18 +#define PTRACE_WRITETEXT 19 +#define PTRACE_GETFPAREGS 20 +#define PTRACE_SETFPAREGS 21 + +#define PTRACE_GETUCODE 29 /* stupid bsd-ism */ #endif /* !(_SPARC64_PTRACE_H) */ diff -u --recursive --new-file v2.1.41/linux/include/asm-sparc64/softirq.h linux/include/asm-sparc64/softirq.h --- v2.1.41/linux/include/asm-sparc64/softirq.h Wed Apr 23 19:01:28 1997 +++ linux/include/asm-sparc64/softirq.h Wed May 28 10:49:11 1997 @@ -13,18 +13,15 @@ * is entirely private to an implementation, it should not be * referenced at all outside of this file. */ -extern atomic_t __sparc64_bh_counter; #define get_active_bhs() (bh_mask & bh_active) -#ifdef __SMP__ -#error SMP not supported on sparc64 yet -#else - -#define softirq_trylock() (atomic_read(&__sparc64_bh_counter) ? \ - 0 : \ - ((atomic_set(&__sparc64_bh_counter,1)),1)) -#define softirq_endlock() (atomic_set(&__sparc64_bh_counter, 0)) +#ifndef __SMP__ + +extern int __sparc64_bh_counter; + +#define softirq_trylock() (__sparc64_bh_counter ? 0 : (__sparc64_bh_counter=1)) +#define softirq_endlock() (__sparc64_bh_counter = 0) #define clear_active_bhs(x) (bh_active &= ~(x)) #define init_bh(nr, routine) \ @@ -54,11 +51,82 @@ bh_mask |= 1 << ent; \ } while(0) +#define start_bh_atomic() do { __sparc64_bh_counter++; barrier(); } while(0) + +#define end_bh_atomic() do { barrier(); __sparc64_bh_counter--; } while(0) + +#else /* (__SMP__) */ + +extern atomic_t __sparc64_bh_counter; + #define start_bh_atomic() \ do { atomic_inc(&__sparc64_bh_counter); synchronize_irq(); } while(0) -#define end_bh_atomic() do { atomic_dec(&__sparc64_bh_counter); } while(0) +#define end_bh_atomic() atomic_dec(&__sparc64_bh_counter) + +#include + +#define init_bh(nr, routine) \ +do { unsigned long flags; \ + int ent = nr; \ + spin_lock_irqsave(&global_bh_lock, flags); \ + bh_base[ent] = routine; \ + bh_mask_count[ent] = 0; \ + bh_mask |= 1 << ent; \ + spin_unlock_irqrestore(&global_bh_lock, flags); \ +} while(0) + +#define remove_bh(nr) \ +do { unsigned long flags; \ + int ent = nr; \ + spin_lock_irqsave(&global_bh_lock, flags); \ + bh_base[ent] = NULL; \ + bh_mask &= ~(1 << ent); \ + spin_unlock_irqrestore(&global_bh_lock, flags); \ +} while(0) + +#define mark_bh(nr) \ +do { unsigned long flags; \ + spin_lock_irqsave(&global_bh_lock, flags); \ + bh_active |= (1 << nr); \ + spin_unlock_irqrestore(&global_bh_lock, flags); \ +} while(0) + +#define disable_bh(nr) \ +do { unsigned long flags; \ + int ent = nr; \ + spin_lock_irqsave(&global_bh_lock, flags); \ + bh_mask &= ~(1 << ent); \ + bh_mask_count[ent]++; \ + spin_unlock_irqrestore(&global_bh_lock, flags); \ +} while(0) + +#define enable_bh(nr) \ +do { unsigned long flags; \ + int ent = nr; \ + spin_lock_irqsave(&global_bh_lock, flags); \ + if (!--bh_mask_count[ent]) \ + bh_mask |= 1 << ent; \ + spin_unlock_irqrestore(&global_bh_lock, flags); \ +} while(0) + +#define softirq_trylock() \ +({ \ + int ret = 1; \ + if(atomic_add_return(1, &__sparc_bh_counter) != 1) { \ + atomic_dec(&__sparc_bh_counter); \ + ret = 0; \ + } \ + ret; \ +}) +#define softirq_endlock() atomic_dec(&__sparc_bh_counter) +#define clear_active_bhs(mask) \ +do { unsigned long flags; \ + spin_lock_irqsave(&global_bh_lock, flags); \ + bh_active &= ~(mask); \ + spin_unlock_irqrestore(&global_bh_lock, flags); \ +} while(0) -#endif /* !(__SMP__) */ +#endif /* (__SMP__) */ #endif /* !(__SPARC64_SOFTIRQ_H) */ diff -u --recursive --new-file v2.1.41/linux/include/asm-sparc64/spinlock.h linux/include/asm-sparc64/spinlock.h --- v2.1.41/linux/include/asm-sparc64/spinlock.h Wed Apr 23 19:01:28 1997 +++ linux/include/asm-sparc64/spinlock.h Wed May 28 10:49:11 1997 @@ -52,9 +52,206 @@ #define write_unlock_irqrestore(lock, flags) restore_flags(flags) #else /* !(__SMP__) */ -#error SMP not supported on sparc64 + +typedef unsigned char spinlock_t; +#define SPIN_LOCK_UNLOCKED 0 +#define spin_lock_init(lock) (*(lock) = 0) +#define spin_unlock_wait(lock) do { barrier(); } while(*(volatile spinlock_t *)lock) + +extern __inline__ void spin_lock(spinlock_t *lock) +{ + __asm__ __volatile__(" +1: ldstub [%0], %%g2 + brnz,a,pn %%g2, 2f + ldub [%0], %%g2 + .text 2 +2: brnz,a,pt 2b + ldub [%0], %%g2 + b,a,pt %%xcc, 1b + .previous +" : /* no outputs */ + : "r" (lock) + : "g2", "memory"); +} + +extern __inline__ int spin_trylock(spinlock_t *lock) +{ + unsigned int result; + __asm__ __volatile__("ldstub [%1], %0" + : "=r" (result) + : "r" (lock) + : "memory"); + return (result == 0); +} + +extern __inline__ void spin_unlock(spinlock_t *lock) +{ + __asm__ __volatile__("stb %%g0, [%0]" : : "r" (lock) : "memory"); +} + +extern __inline__ void spin_lock_irq(spinlock_t *lock) +{ + __asm__ __volatile__(" + wrpr %%g0, 15, %%pil + ldstub [%0], %%g2 + brnz,a,pn %%g2, 2f + ldub [%0], %%g2 + .text 2 +2: brnz,a,pt 2b + ldub [%0], %%g2 + b,a,pt %%xcc, 1b + .previous +" : /* no outputs */ + : "r" (lock) + : "g2", "memory"); +} + +extern __inline__ void spin_unlock_irq(spinlock_t *lock) +{ + __asm__ __volatile__(" + stb %%g0, [%0] + wrpr %%g0, 0x0, %%pil +" : /* no outputs */ + : "r" (lock) + : "memory"); +} + +#define spin_lock_irqsave(lock, flags) \ +do { register spinlock_t *lp asm("g1"); \ + lp = lock; \ + __asm__ __volatile__( \ + " rdpr %%pil, %0\n\t" \ + " wrpr %%g0, 15, %%pil\n\t" \ + "1: ldstub [%1], %%g2\n\t" \ + " brnz,a,pnt %%g2, 2f\n\t" \ + " ldub [%1], %%g2\n\t" \ + " .text 2\n\t" \ + "2: brnz,a,pt %%g2, 2b\n\t" \ + " ldub [%1], %%g2\n\t" \ + " b,a,pt %%xcc, 1b\n\t" \ + " .previous\n" \ + : "=r" (flags) \ + : "r" (lp) \ + : "g2", "memory"); \ +} while(0) + +extern __inline__ void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) +{ + __asm__ __volatile__(" + stb %%g0, [%0] + wrpr %1, 0x0, %%pil +" : /* no outputs */ + : "r" (lock), "r" (flags) + : "memory"); +} + +/* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */ + +typedef unsigned long rwlock_t; +#define RW_LOCK_UNLOCKED 0 + +extern __inline__ void read_lock(rwlock_t *rw) +{ + __asm__ __volatile__(" + ldx [%0], %%g2 +1: + brlz,pn %%g2, 2f +4: add %%g2, 1, %%g3 + casx [%0], %%g2, %%g3 + cmp %%g2, %%g3 + bne,a,pn %%xcc, 1b + ldx [%0],%%g2 + .text 2 +2: ldx [%0], %%g2 +3: brlz,pt %%g2, 3b + ldx [%0], %%g2 + b,a,pt %%xcc, 4b + .previous +" : /* no outputs */ + : "r" (rw) + : "g2", "g3", "memory"); +} + +extern __inline__ void read_unlock(rwlock_t *rw) +{ + __asm__ __volatile__(" + ldx [%0], %%g2 +1: + sub %%g2, 1, %%g3 + casx [%0], %%g2, %%g3 + cmp %%g2, %%g3 + bne,a,pn %%xcc, 1b + ldx [%0], %%g2 +" : /* no outputs */ + : "r" (rw) + : "g2", "g3", "memory"); +} + +extern __inline__ void write_lock(rwlock_t *rw) +{ + __asm__ __volatile__(" + sethi %%uhi(0x8000000000000000), %%g5 + ldx [%0] %%g2 + sllx %%g5, 32, %%g5 +1: + brlz,pn %%g2, 5f +4: or %%g2, %%g5, %%g3 + casx [%0], %%g2, %%g3 + cmp %%g2, %%g3 + bne,a,pn %%xcc, 1b + ldx [%0], %%g2 + andncc %%g3, %%g5, %%g0 + bne,a,pn %%xcc, 3f + ldx [%0], %%g2 + .text 2 +3: + andn %%g2, %%g5, %%g3 + casx [%0], %%g2, %%g3 + cmp %%g2, %%g3 + bne,a,pn %%xcc, 3b + ldx [%0], %%g2 +5: ldx [%0], %%g2 +6: brlz,pt %%g2, 6b + ldx [%0], %%g2 + b,a,pt %%xcc, 4b +" : /* no outputs */ + : "r" (rw) + : "g2", "g3", "g5", "memory", "cc"); +} + +extern __inline__ void write_unlock(rwlock_t *rw) +{ + __asm__ __volatile__(" + sethi %%uhi(0x8000000000000000), %%g5 + ldx [%0], %%g2 + sllx %%g5, 32, %%g5 +1: + andn %%g2, %%g5, %%g3 + casx [%0], %%g2, %%g3 + cmp %%g2, %%g3 + bne,a,pn %%xcc, 1b + ldx [%0], %%g2 +" : /* no outputs */ + : "r" (rw) + : "g2", "g3", "g5", "memory", "cc"); +} + +#define read_lock_irq(lock) do { __cli(); read_lock(lock); } while (0) +#define read_unlock_irq(lock) do { read_unlock(lock); __sti(); } while (0) +#define write_lock_irq(lock) do { __cli(); write_lock(lock); } while (0) +#define write_unlock_irq(lock) do { write_unlock(lock); __sti(); } while (0) + +#define read_lock_irqsave(lock, flags) \ + do { __save_and_cli(flags); read_lock(lock); } while (0) +#define read_unlock_irqrestore(lock, flags) \ + do { read_unlock(lock); __restore_flags(flags); } while (0) +#define write_lock_irqsave(lock, flags) \ + do { __save_and_cli(flags); write_lock(lock); } while (0) +#define write_unlock_irqrestore(lock, flags) \ + do { write_unlock(lock); __restore_flags(flags); } while (0) + #endif /* __SMP__ */ #endif /* !(__ASSEMBLY__) */ -#endif /* !(__SPARC64_SPINLOCK_H) */ +#endif /* !(__SPARC64_SPIN%0_H) */ diff -u --recursive --new-file v2.1.41/linux/include/asm-sparc64/unistd.h linux/include/asm-sparc64/unistd.h --- v2.1.41/linux/include/asm-sparc64/unistd.h Wed Apr 23 19:01:28 1997 +++ linux/include/asm-sparc64/unistd.h Wed May 28 10:49:11 1997 @@ -1,4 +1,4 @@ -/* $Id: unistd.h,v 1.4 1997/04/19 08:52:25 jj Exp $ */ +/* $Id: unistd.h,v 1.5 1997/05/21 10:21:57 jj Exp $ */ #ifndef _SPARC64_UNISTD_H #define _SPARC64_UNISTD_H @@ -416,7 +416,7 @@ static __inline__ _syscall0(int,fork) static __inline__ _syscall2(int,clone,unsigned long,flags,char *,ksp) static __inline__ _syscall0(int,pause) -static __inline__ _syscall0(int,setup) +static __inline__ _syscall1(int,setup,int,magic) static __inline__ _syscall0(int,sync) static __inline__ _syscall0(pid_t,setsid) static __inline__ _syscall3(int,write,int,fd,__const__ char *,buf,off_t,count) diff -u --recursive --new-file v2.1.41/linux/include/linux/ax25.h linux/include/linux/ax25.h --- v2.1.41/linux/include/linux/ax25.h Thu Feb 27 10:57:31 1997 +++ linux/include/linux/ax25.h Wed May 28 10:49:11 1997 @@ -16,7 +16,7 @@ #define AX25_T2 5 #define AX25_BACKOFF 6 #define AX25_EXTSEQ 7 -#define AX25_HDRINCL 8 +#define AX25_PIDINCL 8 #define AX25_IDLE 9 #define AX25_PACLEN 10 #define AX25_IAMDIGI 12 diff -u --recursive --new-file v2.1.41/linux/include/linux/b1lli.h linux/include/linux/b1lli.h --- v2.1.41/linux/include/linux/b1lli.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/b1lli.h Wed May 28 10:49:11 1997 @@ -0,0 +1,141 @@ +/* + * $Id: b1lli.h,v 1.1 1997/03/04 21:27:32 calle Exp $ + * + * ISDN lowlevel-module for AVM B1-card. + * + * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: b1lli.h,v $ + * Revision 1.1 1997/03/04 21:27:32 calle + * First version in isdn4linux + * + * Revision 2.2 1997/02/12 09:31:39 calle + * new version + * + * Revision 1.1 1997/01/31 10:32:20 calle + * Initial revision + * + */ + +#ifndef _B1LLI_H_ +#define _B1LLI_H_ +/* + * struct for loading t4 file + */ +typedef struct avmb1_t4file { + int len; + unsigned char *data; +} avmb1_t4file; + +typedef struct avmb1_loaddef { + int contr; + avmb1_t4file t4file; +} avmb1_loaddef; + +typedef struct avmb1_resetdef { + int contr; +} avmb1_resetdef; + +/* + * struct for adding new cards + */ +typedef struct avmb1_carddef { + int port; + int irq; +} avmb1_carddef; + +#define AVMB1_LOAD 0 /* load image to card */ +#define AVMB1_ADDCARD 1 /* add a new card */ +#define AVMB1_RESETCARD 2 /* reset a card */ + + + +#ifdef __KERNEL__ + +/* + * card states for startup + */ + +#define CARD_NONE 0 +#define CARD_DETECTED 1 +#define CARD_LOADING 2 +#define CARD_INITSTATE 4 +#define CARD_RUNNING 5 +#define CARD_ACTIVE 6 + +#define AVMB1_PORTLEN 0x1f + +#define AVM_MAXVERSION 8 +#define AVM_NBCHAN 2 + +#define AVM_NAPPS 30 +#define AVM_NPLCI 5 +#define AVM_NNCCI 6 + +/* + * Main driver data + */ + +typedef struct avmb1_card { + struct avmb1_card *next; + int cnr; + unsigned short port; + unsigned irq; + volatile unsigned short cardstate; + int interrupt; + int blocked; + int versionlen; + char versionbuf[1024]; + char *version[AVM_MAXVERSION]; + char msgbuf[128]; /* capimsg msg part */ + char databuf[2048]; /* capimsg data part */ + capi_version cversion; + char name[10]; +} avmb1_card; + +/* + * Versions + */ + +#define VER_DRIVER 0 +#define VER_CARDTYPE 1 +#define VER_HWID 2 +#define VER_SERIAL 3 +#define VER_OPTION 4 +#define VER_PROTO 5 +#define VER_PROFILE 6 +#define VER_CAPI 7 + + +/* b1lli.c */ +int B1_detect(unsigned short base); +void B1_reset(unsigned short base); +int B1_load_t4file(unsigned short base, avmb1_t4file * t4file); +int B1_loaded(unsigned short base); +unsigned char B1_assign_irq(unsigned short base, unsigned irq); +unsigned char B1_enable_irq(unsigned short base); +unsigned char B1_disable_irq(unsigned short base); +int B1_valid_irq(unsigned irq); +void B1_handle_interrupt(avmb1_card * card); +void B1_send_init(unsigned short port, + unsigned int napps, unsigned int nncci, unsigned int cardnr); +void B1_send_register(unsigned short port, + __u16 appid, __u32 nmsg, + __u32 nb3conn, __u32 nb3blocks, __u32 b3bsize); +void B1_send_release(unsigned short port, __u16 appid); +void B1_send_message(unsigned short port, struct sk_buff *skb); + +/* b1capi.c */ +void avmb1_handle_new_ncci(avmb1_card * card, + __u16 appl, __u32 ncci, __u32 winsize); +void avmb1_handle_free_ncci(avmb1_card * card, + __u16 appl, __u32 ncci); +void avmb1_handle_capimsg(avmb1_card * card, __u16 appl, struct sk_buff *skb); +void avmb1_card_ready(avmb1_card * card); + +int avmb1_addcard(int port, int irq); +int avmb1_probecard(int port, int irq); + +#endif /* __KERNEL__ */ + +#endif /* _B1LLI_H_ */ diff -u --recursive --new-file v2.1.41/linux/include/linux/capi.h linux/include/linux/capi.h --- v2.1.41/linux/include/linux/capi.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/capi.h Wed May 28 10:49:11 1997 @@ -0,0 +1,127 @@ +/* + * $Id: capi.h,v 1.1 1997/03/04 21:27:33 calle Exp $ + * + * CAPI 2.0 Interface for Linux + * + * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: capi.h,v $ + * Revision 1.1 1997/03/04 21:27:33 calle + * First version in isdn4linux + * + * Revision 2.2 1997/02/12 09:31:39 calle + * new version + * + * Revision 1.1 1997/01/31 10:32:20 calle + * Initial revision + * + * + */ + +#ifndef __LINUX_CAPI_H__ +#define __LINUX_CAPI_H__ + +#include +#include +#ifndef __KERNEL__ +#include +#endif + +/* + * CAPI_REGISTER + */ + +typedef struct capi_register_params { /* CAPI_REGISTER */ + __u32 level3cnt; /* No. of simulatneous user data connections */ + __u32 datablkcnt; /* No. of buffered data messages */ + __u32 datablklen; /* Size of buffered data messages */ +} capi_register_params; + +#define CAPI_REGISTER _IOW('C',0x01,struct capi_register_params) + +/* + * CAPI_GET_MANUFACTURER + */ + +#define CAPI_MANUFACTURER_LEN 64 + +#define CAPI_GET_MANUFACTURER _IOWR('C',0x06,CAPI_MANUFACTURER_LEN) + +/* + * CAPI_GET_VERSION + */ + +typedef struct capi_version { + __u32 majorversion; + __u32 minorversion; + __u32 majormanuversion; + __u32 minormanuversion; +} capi_version; + +#define CAPI_GET_VERSION _IOWR('C',0x07,struct capi_version) + +/* + * CAPI_GET_SERIAL + */ + +#define CAPI_SERIAL_LEN 8 +#define CAPI_GET_SERIAL _IOWR('C',0x08, CAPI_SERIAL_LEN) + +/* + * CAPI_GET_PROFILE + */ + +typedef struct capi_profile { + __u16 ncontroller; /* number of installed controller */ + __u16 nbchannel; /* number of B-Channels */ + __u32 goptions; /* global options */ + __u32 support1; /* B1 protocols support */ + __u32 support2; /* B2 protocols support */ + __u32 support3; /* B3 protocols support */ + __u32 reserved[6]; /* reserved */ + __u32 manu[5]; /* manufacturer specific information */ +} capi_profile; + +#define CAPI_GET_PROFILE _IOWR('C',0x09,struct capi_profile) + +typedef struct capi_manufacturer_cmd { + unsigned long cmd; + void *data; +} capi_manufacturer_cmd; + +/* + * CAPI_MANUFACTURER_CMD + */ + +#define CAPI_MANUFACTURER_CMD _IOWR('C',0x20, struct capi_manufacturer_cmd) + +/* + * CAPI_GET_ERRCODE + * capi errcode is set, * if read, write, or ioctl returns EIO, + * ioctl returns errcode directly, and in arg, if != 0 + */ + +#define CAPI_GET_ERRCODE _IOR('C',0x21, __u16) + +/* + * CAPI_INSTALLED + */ +#define CAPI_INSTALLED _IOR('C',0x22, __u16) + +/* + * member contr is input for + * CAPI_GET_MANUFACTURER, CAPI_VERSION, CAPI_GET_SERIAL + * and CAPI_GET_PROFILE + */ +typedef union capi_ioctl_struct { + __u32 contr; + capi_register_params rparams; + __u8 manufacturer[CAPI_MANUFACTURER_LEN]; + capi_version version; + __u8 serial[CAPI_SERIAL_LEN]; + capi_profile profile; + capi_manufacturer_cmd cmd; + __u16 errcode; +} capi_ioctl_struct; + +#endif /* __LINUX_CAPI_H__ */ diff -u --recursive --new-file v2.1.41/linux/include/linux/elf.h linux/include/linux/elf.h --- v2.1.41/linux/include/linux/elf.h Sat May 24 09:10:25 1997 +++ linux/include/linux/elf.h Wed May 28 10:49:11 1997 @@ -1,6 +1,7 @@ #ifndef _LINUX_ELF_H #define _LINUX_ELF_H +#include #include /* 32-bit ELF base types. */ diff -u --recursive --new-file v2.1.41/linux/include/linux/isdn.h linux/include/linux/isdn.h --- v2.1.41/linux/include/linux/isdn.h Thu Feb 27 10:57:31 1997 +++ linux/include/linux/isdn.h Wed May 28 10:49:11 1997 @@ -1,4 +1,4 @@ -/* $Id: isdn.h,v 1.23 1997/02/10 22:07:13 fritz Exp $ +/* $Id: isdn.h,v 1.29 1997/05/27 15:18:02 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.29 1997/05/27 15:18:02 fritz + * Added changes for recent 2.1.x kernels: + * changed return type of isdn_close + * queue_task_* -> queue_task + * clear/set_bit -> test_and_... where apropriate. + * changed type of hard_header_cache parameter. + * + * Revision 1.28 1997/03/07 01:33:01 fritz + * Added proper ifdef's for CONFIG_ISDN_AUDIO + * + * Revision 1.27 1997/03/05 21:11:49 fritz + * Minor fixes. + * + * Revision 1.26 1997/02/28 02:37:53 fritz + * Added some comments. + * + * Revision 1.25 1997/02/23 16:54:23 hipp + * some initial changes for future PPP compresion + * + * Revision 1.24 1997/02/18 09:42:45 fritz + * Bugfix: Increased ISDN_MODEM_ANZREG. + * Increased TTY_DV. + * * Revision 1.23 1997/02/10 22:07:13 fritz * Added 2 modem registers for numbering plan and screening info. * @@ -176,7 +199,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 22 /* Number of Modem-Registers */ +#define ISDN_MODEM_ANZREG 23 /* Number of Modem-Registers */ #define ISDN_MSNLEN 20 typedef struct { @@ -192,12 +215,12 @@ typedef struct { char name[10]; - char phone[20]; + char phone[ISDN_MSNLEN]; int outgoing; } isdn_net_ioctl_phone; #define NET_DV 0x02 /* Data version for net_cfg */ -#define TTY_DV 0x03 /* Data version for iprofd etc. */ +#define TTY_DV 0x04 /* Data version for iprofd etc. */ typedef struct { char name[10]; /* Name of interface */ @@ -336,7 +359,7 @@ /* Phone-list-element */ typedef struct { void *next; - char num[20]; + char num[ISDN_MSNLEN]; } isdn_net_phone; /* Local interface-data */ @@ -409,10 +432,17 @@ unsigned short, __u32); #else +#if (LINUX_VERSION_CODE < 0x2011E) /* Ptr to orig. hard_header_cache */ int (*org_hhc)(struct dst_entry *dst, struct dst_entry *neigh, struct hh_cache *hh); +#else + /* Ptr to orig. hard_header_cache */ + int (*org_hhc)(struct dst_entry *dst, + struct neighbour *neigh, + struct hh_cache *hh); +#endif #endif /* Ptr to orig. header_cache_update */ void (*org_hcu)(struct hh_cache *, @@ -465,6 +495,7 @@ #define ISDN_SERIAL_TYPE_NORMAL 1 #define ISDN_SERIAL_TYPE_CALLOUT 2 +#ifdef CONFIG_ISDN_AUDIO /* 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 @@ -478,6 +509,7 @@ #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) +#endif /* Private data of AT-command-interpreter */ typedef struct atemu { @@ -485,11 +517,13 @@ u_char mdmreg[ISDN_MODEM_ANZREG]; /* Modem-Registers */ char pmsn[ISDN_MSNLEN]; /* EAZ/MSNs Profile 0 */ char msn[ISDN_MSNLEN];/* EAZ/MSN */ +#ifdef CONFIG_ISDN_AUDIO u_char vpar[10]; /* Voice-parameters */ + int lastDLE; /* Flag for voice-coding: DLE seen */ +#endif int mdmcmdl; /* Length of Modem-Commandbuffer */ int pluscount; /* Counter for +++ sequence */ int lastplus; /* Timestamp of last + */ - int lastDLE; /* Flag for voice-coding: DLE seen */ char mdmcmd[255]; /* Modem-Commandbuffer */ } atemu; @@ -506,8 +540,8 @@ int blocked_open; /* # of blocked opens */ long session; /* Session of opening process */ long pgrp; /* pgrp of opening process */ - int online; /* B-Channel is up */ - int vonline; /* Voice-channel status */ + int online; /* 1 = B-Channel is up, drop data */ + /* 2 = B-Channel is up, deliver d.*/ int dialing; /* Dial in progress */ int rcvsched; /* Receive needs schedule */ int isdn_driver; /* Index to isdn-driver */ @@ -515,7 +549,8 @@ 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_num[ISDN_MSNLEN]; + /* Last phone-number */ unsigned char last_l2; /* Last layer-2 protocol */ unsigned char last_si; /* Last service */ unsigned char last_lhup; /* Last hangup local? */ @@ -526,12 +561,18 @@ int xmit_count; /* # of chars in xmit_buf */ unsigned char *xmit_buf; /* transmit buffer */ struct sk_buff_head xmit_queue; /* transmit queue */ +#ifdef CONFIG_ISDN_AUDIO + int vonline; /* Voice-channel status */ + /* Bit 0 = recording */ + /* Bit 1 = playback */ + /* Bit 2 = playback, DLE-ETX seen */ struct sk_buff_head dtmf_queue; /* queue for dtmf results */ - struct tty_struct *tty; /* Pointer to corresponding tty */ - atemu emu; /* AT-emulator data */ void *adpcms; /* state for adpcm decompression */ void *adpcmr; /* state for adpcm compression */ void *dtmf_state; /* state for dtmf decoder */ +#endif + struct tty_struct *tty; /* Pointer to corresponding tty */ + atemu emu; /* AT-emulator data */ struct termios normal_termios; /* For saving termios structs */ struct termios callout_termios; struct wait_queue *open_wait; @@ -611,6 +652,7 @@ struct slcompress *slcomp; #endif unsigned long debug; + struct isdn_ppp_compressor *compressor; }; #endif @@ -638,7 +680,9 @@ isdn_if *interface; /* Interface to driver */ int *rcverr; /* Error-counters for B-Ch.-receive */ int *rcvcount; /* Byte-counters for B-Ch.-receive */ +#ifdef CONFIG_ISDN_AUDIO unsigned long DLEflag; /* Flags: Insert DLE at next read */ +#endif struct sk_buff_head *rpqueue; /* Pointers to start of Rcv-Queue */ struct wait_queue **rcv_waitq; /* Wait-Queues for B-Channel-Reads */ struct wait_queue **snd_waitq; /* Wait-Queue for B-Channel-Send's */ @@ -662,7 +706,8 @@ int chanmap[ISDN_MAX_CHANNELS];/* Map minor->device-channel */ int drvmap[ISDN_MAX_CHANNELS]; /* Map minor->driver-index */ int usage[ISDN_MAX_CHANNELS]; /* Used by tty/ip/voice */ - char num[ISDN_MAX_CHANNELS][20];/* Remote number of active ch.*/ + char num[ISDN_MAX_CHANNELS][ISDN_MSNLEN]; + /* Remote number of active ch.*/ int m_idx[ISDN_MAX_CHANNELS]; /* Index for mdm.... */ driver *drv[ISDN_MAX_DRIVERS]; /* Array of drivers */ isdn_net_dev *netdev; /* Linked list of net-if's */ diff -u --recursive --new-file v2.1.41/linux/include/linux/isdn_ppp.h linux/include/linux/isdn_ppp.h --- v2.1.41/linux/include/linux/isdn_ppp.h Thu Feb 27 10:57:31 1997 +++ linux/include/linux/isdn_ppp.h Wed May 28 10:49:11 1997 @@ -1,8 +1,23 @@ #ifndef _LINUX_ISDN_PPP_H #define _LINUX_ISDN_PPP_H +struct isdn_ppp_compressor +{ + struct isdn_ppp_compressor *next,*prev; + int num; /* proto num */ + void *priv; /* private data for compressor */ + int (*open)(struct isdn_ppp_compressor *); + int (*close)(struct isdn_ppp_compressor *); + int (*reset)(struct isdn_ppp_compressor *,int type); + int (*config)(struct isdn_ppp_compressor *,void *data,int data_len); + struct sk_buff *(*compress)(struct isdn_ppp_compressor *,struct sk_buff *); + struct sk_buff *(*uncompress)(struct isdn_ppp_compressor *,struct sk_buff *); +}; + extern int isdn_ppp_dial_slave(char *); extern int isdn_ppp_hangup_slave(char *); +extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *); +extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *); #define CALLTYPE_INCOMING 0x1 #define CALLTYPE_OUTGOING 0x2 @@ -23,6 +38,9 @@ #define PPPIOCSMPFLAGS _IOW('t',131,int) #define PPPIOCSMPMTU _IOW('t',132,int) #define PPPIOCSMPMRU _IOW('t',133,int) + +#define PPPIOCGCOMPRESSORS _IOR('t',134,unsigned long) +#define PPPIOCSCOMPRESSOR _IOW('t',135,int) #define PPP_MP 0x003d diff -u --recursive --new-file v2.1.41/linux/include/linux/isdnif.h linux/include/linux/isdnif.h --- v2.1.41/linux/include/linux/isdnif.h Thu Feb 27 10:57:31 1997 +++ linux/include/linux/isdnif.h Wed May 28 10:49:11 1997 @@ -1,4 +1,4 @@ -/* $Id: isdnif.h,v 1.17 1997/02/10 21:12:53 fritz Exp $ +/* $Id: isdnif.h,v 1.20 1997/05/27 15:18:06 fritz Exp $ * * Linux ISDN subsystem * @@ -22,6 +22,20 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdnif.h,v $ + * Revision 1.20 1997/05/27 15:18:06 fritz + * Added changes for recent 2.1.x kernels: + * changed return type of isdn_close + * queue_task_* -> queue_task + * clear/set_bit -> test_and_... where apropriate. + * changed type of hard_header_cache parameter. + * + * Revision 1.19 1997/03/25 23:13:56 keil + * NI-1 US protocol + * + * Revision 1.18 1997/03/04 22:09:18 calle + * Change macros copy_from_user and copy_to_user in inline function. + * These are now correct replacements of the functions for 2.1.xx + * * Revision 1.17 1997/02/10 21:12:53 fritz * More setup-interface changes. * @@ -89,6 +103,7 @@ #define ISDN_PTYPE_1TR6 1 /* german 1TR6-protocol */ #define ISDN_PTYPE_EURO 2 /* EDSS1-protocol */ #define ISDN_PTYPE_LEASED 3 /* for leased lines */ +#define ISDN_PTYPE_NI1 4 /* US NI-1 protocol */ /* * Values for Layer-2-protocol-selection @@ -169,6 +184,7 @@ #define ISDN_FEATURE_P_UNKNOWN (0x1000 << ISDN_PTYPE_UNKNOWN) #define ISDN_FEATURE_P_1TR6 (0x1000 << ISDN_PTYPE_1TR6) #define ISDN_FEATURE_P_EURO (0x1000 << ISDN_PTYPE_EURO) +#define ISDN_FEATURE_P_NI1 (0x1000 << ISDN_PTYPE_NI1) typedef struct setup_parm { char phone[32]; /* Remote Phone-Number */ @@ -346,14 +362,30 @@ #endif #if (LINUX_VERSION_CODE < 0x020100) #include -#define copy_from_user memcpy_fromfs -#define copy_to_user memcpy_tofs + +static inline unsigned long copy_from_user(void *to, const void *from, unsigned long n) +{ + int i; + if ((i = verify_area(VERIFY_READ, from, n)) != 0) + return i; + memcpy_fromfs(to, from, n); + return 0; +} + +static inline unsigned long copy_to_user(void *to, const void *from, unsigned long n) +{ + int i; + if ((i = verify_area(VERIFY_WRITE, to, n)) != 0) + return i; + memcpy_tofs(to, from, n); + return 0; +} + #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 @@ -362,11 +394,25 @@ #define LSTYPE long long #define RWARG unsigned long #define LSARG long long +#endif + #if (LINUX_VERSION_CODE < 0x02010F) #define SET_SKB_FREE(x) ( x->free = 1 ) #else #define SET_SKB_FREE(x) #endif + +#if (LINUX_VERSION_CODE < 0x02011F) +#define CLOSETYPE void +#define CLOSEVAL +#else +#define CLOSETYPE int +#define CLOSEVAL (0) +#endif + +#if (LINUX_VERSION_CODE < 0x020125) +#define test_and_clear_bit clear_bit +#define test_and_set_bit set_bit #endif #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.1.41/linux/include/linux/kernelcapi.h linux/include/linux/kernelcapi.h --- v2.1.41/linux/include/linux/kernelcapi.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/kernelcapi.h Wed May 28 10:49:11 1997 @@ -0,0 +1,96 @@ +/* + * $Id: kernelcapi.h,v 1.1 1997/03/04 21:27:33 calle Exp $ + * + * Kernel CAPI 2.0 Interface for Linux + * + * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: kernelcapi.h,v $ + * Revision 1.1 1997/03/04 21:27:33 calle + * First version in isdn4linux + * + * Revision 2.2 1997/02/12 09:31:39 calle + * new version + * + * Revision 1.1 1997/01/31 10:32:20 calle + * Initial revision + * + * + */ +#ifndef __KERNEL_CAPI_H__ +#define __KERNEL_CAPI_H__ + +#define CAPI_MAXAPPL 20 /* + * maximum number of applications + */ +#define CAPI_MAXCONTR 4 /* + * maximum number of controller + */ +#define CAPI_MAXDATAWINDOW 8 + +#ifdef __KERNEL__ + +struct capi_interface { + int (*capi_installed) (void); + + __u16(*capi_register) (capi_register_params * rparam, __u16 * applidp); + __u16(*capi_release) (__u16 applid); + __u16(*capi_put_message) (__u16 applid, struct sk_buff * msg); + __u16(*capi_get_message) (__u16 applid, struct sk_buff ** msgp); + __u16(*capi_set_signal) (__u16 applid, + void (*signal) (__u16 applid, __u32 param), + __u32 param); + __u16(*capi_get_manufacturer) (__u16 contr, __u8 buf[CAPI_MANUFACTURER_LEN]); + __u16(*capi_get_version) (__u16 contr, struct capi_version * verp); + __u16(*capi_get_serial) (__u16 contr, __u8 serial[CAPI_SERIAL_LEN]); + __u16(*capi_get_profile) (__u16 contr, struct capi_profile * profp); + + /* + * to init controllers, data is always in user memory + */ + int (*capi_manufacturer) (unsigned int cmd, void *data); + +}; + +#define KCI_CONTRUP 0 +#define KCI_CONTRDOWN 1 + +struct capi_interface_user { + char name[20]; + void (*callback) (unsigned int cmd, __u16 contr, void *data); + struct capi_interface_user *next; +}; + +struct capi_interface *attach_capi_interface(struct capi_interface_user *); +int detach_capi_interface(struct capi_interface_user *); + + +#define CAPI_NOERROR 0x0000 + +#define CAPI_TOOMANYAPPLS 0x1001 +#define CAPI_LOGBLKSIZETOSMALL 0x1002 +#define CAPI_BUFFEXECEEDS64K 0x1003 +#define CAPI_MSGBUFSIZETOOSMALL 0x1004 +#define CAPI_ANZLOGCONNNOTSUPPORTED 0x1005 +#define CAPI_REGRESERVED 0x1006 +#define CAPI_REGBUSY 0x1007 +#define CAPI_REGOSRESOURCEERR 0x1008 +#define CAPI_REGNOTINSTALLED 0x1009 +#define CAPI_REGCTRLERNOTSUPPORTEXTEQUIP 0x100a +#define CAPI_REGCTRLERONLYSUPPORTEXTEQUIP 0x100b + +#define CAPI_ILLAPPNR 0x1101 +#define CAPI_ILLCMDORSUBCMDORMSGTOSMALL 0x1102 +#define CAPI_SENDQUEUEFULL 0x1103 +#define CAPI_RECEIVEQUEUEEMPTY 0x1104 +#define CAPI_RECEIVEOVERFLOW 0x1105 +#define CAPI_UNKNOWNNOTPAR 0x1106 +#define CAPI_MSGBUSY 0x1107 +#define CAPI_MSGOSRESOURCEERR 0x1108 +#define CAPI_MSGNOTINSTALLED 0x1109 +#define CAPI_MSGCTRLERNOTSUPPORTEXTEQUIP 0x110a +#define CAPI_MSGCTRLERONLYSUPPORTEXTEQUIP 0x110b + +#endif /* __KERNEL__ */ + +#endif /* __KERNEL_CAPI_H__ */ diff -u --recursive --new-file v2.1.41/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.1.41/linux/include/linux/mm.h Thu May 15 16:48:05 1997 +++ linux/include/linux/mm.h Wed May 28 11:30:32 1997 @@ -275,13 +275,14 @@ /* mmap.c */ extern void vma_init(void); -extern unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, unsigned long off); extern void merge_segments(struct mm_struct *, unsigned long, unsigned long); extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *); extern void exit_mmap(struct mm_struct *); -extern int do_munmap(unsigned long, size_t); extern unsigned long get_unmapped_area(unsigned long, unsigned long); + +extern unsigned long do_mmap(struct file *, unsigned long, unsigned long, + unsigned long, unsigned long, unsigned long); +extern int do_munmap(unsigned long, size_t); /* filemap.c */ extern unsigned long page_unuse(unsigned long); diff -u --recursive --new-file v2.1.41/linux/include/linux/netrom.h linux/include/linux/netrom.h --- v2.1.41/linux/include/linux/netrom.h Thu Feb 27 10:57:31 1997 +++ linux/include/linux/netrom.h Wed May 28 10:49:11 1997 @@ -13,14 +13,10 @@ #define NETROM_T1 1 #define NETROM_T2 2 #define NETROM_N2 3 -#define NETROM_HDRINCL 4 #define NETROM_T4 6 #define NETROM_IDLE 7 -#define NETROM_KILL 99 - #define SIOCNRDECOBS (SIOCPROTOPRIVATE+2) -#define SIOCNRCTLCON (SIOCPROTOPRIVATE+4) struct nr_route_struct { #define NETROM_NEIGH 0 @@ -34,13 +30,6 @@ unsigned int obs_count; unsigned int ndigis; ax25_address digipeaters[AX25_MAX_DIGIS]; -}; - -struct nr_ctl_struct { - unsigned char index; - unsigned char id; - unsigned int cmd; - unsigned long arg; }; #endif diff -u --recursive --new-file v2.1.41/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h --- v2.1.41/linux/include/linux/proc_fs.h Sat May 24 09:10:25 1997 +++ linux/include/linux/proc_fs.h Wed May 28 11:30:40 1997 @@ -130,7 +130,6 @@ PROC_NET_RS_ROUTES, PROC_NET_RS, PROC_NET_CL2LLC, - PROC_NET_X25_LINKS, PROC_NET_X25_ROUTES, PROC_NET_X25, PROC_NET_TR_RIF, diff -u --recursive --new-file v2.1.41/linux/include/linux/rose.h linux/include/linux/rose.h --- v2.1.41/linux/include/linux/rose.h Sun Feb 2 05:18:47 1997 +++ linux/include/linux/rose.h Wed May 28 10:49:11 1997 @@ -14,12 +14,9 @@ #define ROSE_T2 3 #define ROSE_T3 4 #define ROSE_IDLE 5 -#define ROSE_HDRINCL 6 +#define ROSE_QBITINCL 6 #define ROSE_HOLDBACK 7 -#define ROSE_KILL 99 - -#define SIOCRSCTLCON (SIOCPROTOPRIVATE+1) #define SIOCRSL2CALL (SIOCPROTOPRIVATE+2) typedef struct { @@ -41,13 +38,6 @@ char device[16]; unsigned char ndigis; ax25_address digipeaters[AX25_MAX_DIGIS]; -}; - -struct rose_ctl_struct { - unsigned int lci; - char dev[20]; - unsigned int cmd; - unsigned long arg; }; #endif diff -u --recursive --new-file v2.1.41/linux/include/linux/sysctl.h linux/include/linux/sysctl.h --- v2.1.41/linux/include/linux/sysctl.h Sat May 24 09:10:25 1997 +++ linux/include/linux/sysctl.h Wed May 28 10:49:11 1997 @@ -220,7 +220,9 @@ NET_ROSE_NO_ACTIVITY_TIMEOUT, NET_ROSE_ACK_HOLD_BACK_TIMEOUT, NET_ROSE_ROUTING_CONTROL, - NET_ROSE_LINK_FAIL_TIMEOUT + NET_ROSE_LINK_FAIL_TIMEOUT, + NET_ROSE_MAX_VCS, + NET_ROSE_WINDOW_SIZE }; /* /proc/sys/net/x25 */ diff -u --recursive --new-file v2.1.41/linux/include/net/ax25.h linux/include/net/ax25.h --- v2.1.41/linux/include/net/ax25.h Thu Mar 27 14:40:11 1997 +++ linux/include/net/ax25.h Wed May 28 11:31:40 1997 @@ -46,32 +46,12 @@ #define AX25_COND_REJECT 0x02 #define AX25_COND_PEER_RX_BUSY 0x04 #define AX25_COND_OWN_RX_BUSY 0x08 +#define AX25_COND_DAMA_MODE 0x10 #ifndef _LINUX_NETDEVICE_H #include #endif -/* - * These headers are taken from the KA9Q package by Phil Karn. These specific - * files have been placed under the GPL (not the whole package) by Phil. - * - * - * Copyright 1991 Phil Karn, KA9Q - * - * 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; version 2 dated June, 1991. - * - * 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. - */ - /* Upper sub-layer (LAPB) definitions */ /* Control field templates */ @@ -149,7 +129,7 @@ #define AX25_DEF_T2 (3 * AX25_SLOWHZ) /* T2=3s */ #define AX25_DEF_T3 (300 * AX25_SLOWHZ) /* T3=300s */ #define AX25_DEF_N2 10 /* N2=10 */ -#define AX25_DEF_IDLE (20 * 60 * AX25_SLOWHZ) /* Idle=20 mins */ +#define AX25_DEF_IDLE (0 * 60 * AX25_SLOWHZ) /* Idle=None */ #define AX25_DEF_PACLEN 256 /* Paclen=256 */ #define AX25_DEF_PROTOCOL AX25_PROTO_STD_SIMPLEX /* Standard AX.25 */ #define AX25_DEF_DS_TIMEOUT (3 * 60 * AX25_SLOWHZ) /* DAMA timeout 3 minutes */ @@ -202,17 +182,13 @@ ax25_digi *digipeat; ax25_dev *ax25_dev; unsigned char iamdigi; - unsigned char state, modulus, hdrincl; + unsigned char state, modulus, pidincl; unsigned short vs, vr, va; unsigned char condition, backoff; unsigned char n2, n2count; -#ifdef CONFIG_AX25_DAMA_SLAVE - unsigned char dama_slave; -#endif unsigned short t1, t2, t3, idle, rtt; unsigned short t1timer, t2timer, t3timer, idletimer; - unsigned short paclen; - unsigned short fragno, fraglen; + unsigned short paclen, fragno, fraglen; struct sk_buff_head write_queue; struct sk_buff_head reseq_queue; struct sk_buff_head ack_queue; @@ -235,7 +211,7 @@ 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 *); +extern struct sock *ax25_make_new(struct sock *, struct ax25_dev *); /* ax25_addr.c */ extern ax25_address null_ax25_address; @@ -313,7 +289,7 @@ extern int ax25_rt_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 struct sk_buff *ax25_dg_build_path(struct sk_buff *, ax25_address *, struct device *); extern char ax25_ip_mode_get(ax25_address *, struct device *); extern void ax25_rt_free(void); diff -u --recursive --new-file v2.1.41/linux/include/net/netrom.h linux/include/net/netrom.h --- v2.1.41/linux/include/net/netrom.h Thu Feb 27 10:57:31 1997 +++ linux/include/net/netrom.h Wed May 28 10:49:11 1997 @@ -61,7 +61,7 @@ struct device *device; unsigned char my_index, my_id; unsigned char your_index, your_id; - unsigned char state, condition, bpqext, hdrincl, window; + unsigned char state, condition, bpqext, window; unsigned short vs, vr, va, vl; unsigned char n2, n2count; unsigned short t1, t2, t4, idle; diff -u --recursive --new-file v2.1.41/linux/include/net/rose.h linux/include/net/rose.h --- v2.1.41/linux/include/net/rose.h Thu Feb 27 10:57:31 1997 +++ linux/include/net/rose.h Wed May 28 10:49:11 1997 @@ -56,10 +56,11 @@ #define ROSE_DEFAULT_IDLE (20 * 60 * ROSE_SLOWHZ) /* Default No Activity value */ #define ROSE_DEFAULT_ROUTING 1 /* Default routing flag */ #define ROSE_DEFAULT_FAIL_TIMEOUT (120 * ROSE_SLOWHZ) /* Time until link considered usable */ +#define ROSE_DEFAULT_MAXVC 50 /* Maximum number of VCs per neighbour */ +#define ROSE_DEFAULT_WINDOW_SIZE 3 /* Default window size */ #define ROSE_MODULUS 8 -#define ROSE_MAX_WINDOW_SIZE 2 /* Maximum Window Allowable */ -#define ROSE_MAX_PACKET_SIZE 128 /* Maximum Packet Length */ +#define ROSE_MAX_PACKET_SIZE 256 /* Maximum packet size */ #define ROSE_COND_ACK_PENDING 0x01 #define ROSE_COND_PEER_RX_BUSY 0x02 @@ -77,31 +78,42 @@ #define FAC_CCITT_SRC_NSAP 0xCB struct rose_neigh { - struct rose_neigh *next; - ax25_address callsign; - ax25_digi *digipeat; - struct device *dev; - unsigned short count; - unsigned int number; - int restarted; - struct sk_buff_head queue; - unsigned short t0timer, ftimer; - struct timer_list timer; + struct rose_neigh *next; + ax25_address callsign; + ax25_digi *digipeat; + struct device *dev; + unsigned short count; + unsigned int number; + char restarted; + char dce_mode; + struct sk_buff_head queue; + unsigned short t0timer, ftimer; + struct timer_list timer; }; struct rose_node { - struct rose_node *next; - rose_address address; - unsigned short mask; - unsigned char count; - struct rose_neigh *neighbour[3]; + struct rose_node *next; + rose_address address; + unsigned short mask; + unsigned char count; + struct rose_neigh *neighbour[3]; }; struct rose_route { - struct rose_route *next; - unsigned int lci1, lci2; - struct rose_neigh *neigh1, *neigh2; - unsigned int rand; + struct rose_route *next; + unsigned int lci1, lci2; + rose_address src_addr, dest_addr; + ax25_address src_call, dest_call; + struct rose_neigh *neigh1, *neigh2; + unsigned int rand; +}; + +struct rose_facilities { + rose_address source_addr, dest_addr; + ax25_address source_call, dest_call; + unsigned char source_ndigis, dest_ndigis; + ax25_address source_digi, dest_digi; + unsigned int rand; }; typedef struct { @@ -112,7 +124,7 @@ struct rose_neigh *neighbour; struct device *device; unsigned int lci, rand; - unsigned char state, condition, hdrincl; + unsigned char state, condition, qbitincl; unsigned short vs, vr, va, vl; unsigned short timer; unsigned short t1, t2, t3, hb, idle; @@ -131,11 +143,14 @@ extern int sysctl_rose_ack_hold_back_timeout; extern int sysctl_rose_routing_control; extern int sysctl_rose_link_fail_timeout; +extern int sysctl_rose_maximum_vcs; +extern int sysctl_rose_window_size; extern int rosecmp(rose_address *, rose_address *); extern int rosecmpm(rose_address *, rose_address *, unsigned short); extern char *rose2asc(rose_address *); -extern struct sock *rose_find_socket(unsigned int, struct device *); -extern unsigned int rose_new_lci(struct device *); +extern struct sock *rose_find_socket(unsigned int, struct rose_neigh *); +extern void rose_kill_by_neigh(struct rose_neigh *); +extern unsigned int rose_new_lci(struct rose_neigh *); extern int rose_rx_call_request(struct sk_buff *, struct device *, struct rose_neigh *, unsigned int); extern void rose_destroy_socket(struct sock *); @@ -168,6 +183,7 @@ extern void rose_link_device_down(struct device *); extern struct device *rose_dev_first(void); extern struct device *rose_dev_get(rose_address *); +extern struct rose_route *rose_route_free_lci(unsigned int, struct rose_neigh *); extern struct device *rose_ax25_dev_get(char *); extern struct rose_neigh *rose_get_neigh(rose_address *); extern int rose_rt_ioctl(unsigned int, void *); @@ -183,7 +199,7 @@ extern int rose_validate_nr(struct sock *, unsigned short); extern void rose_write_internal(struct sock *, int); extern int rose_decode(struct sk_buff *, int *, int *, int *, int *, int *); -extern int rose_parse_facilities(struct sk_buff *, rose_cb *); +extern int rose_parse_facilities(struct sk_buff *, struct rose_facilities *); extern int rose_create_facilities(unsigned char *, rose_cb *); /* rose_timer.c */ diff -u --recursive --new-file v2.1.41/linux/include/net/sock.h linux/include/net/sock.h --- v2.1.41/linux/include/net/sock.h Tue May 13 22:41:19 1997 +++ linux/include/net/sock.h Wed May 28 11:31:42 1997 @@ -296,20 +296,23 @@ * sockmem [mem, proto, callbacks] * * union or struct { - * netrom; - * ax_25; + * ax25; * } ll_pinfo; * * union { * ipv4; * ipv6; * ipx; + * netrom; + * rose; + * x25; * } net_pinfo; * * union { * tcp; * udp; * spx; + * netrom; * } tp_pinfo; * * } diff -u --recursive --new-file v2.1.41/linux/include/net/x25.h linux/include/net/x25.h --- v2.1.41/linux/include/net/x25.h Thu Feb 27 10:57:31 1997 +++ linux/include/net/x25.h Wed May 28 10:49:11 1997 @@ -157,6 +157,11 @@ extern void x25_establish_link(struct x25_neigh *); extern void x25_terminate_link(struct x25_neigh *); +/* x25_facilities.c */ +extern int x25_parse_facilities(struct sk_buff *, struct x25_facilities *); +extern int x25_create_facilities(unsigned char *, struct x25_facilities *); +extern int x25_negotiate_facilities(struct sk_buff *, struct sock *, struct x25_facilities *); + /* x25_in.c */ extern int x25_process_rx_frame(struct sock *, struct sk_buff *); @@ -173,7 +178,6 @@ extern void x25_transmit_link(struct sk_buff *, struct x25_neigh *); extern int x25_subscr_ioctl(unsigned int, void *); extern struct x25_neigh *x25_get_neigh(struct device *); -extern int x25_link_get_info(char *, char **, off_t, int, int); extern void x25_link_free(void); /* x25_out.c */ @@ -195,8 +199,6 @@ extern int x25_validate_nr(struct sock *, unsigned short); extern void x25_write_internal(struct sock *, int); extern int x25_decode(struct sock *, struct sk_buff *, int *, int *, int *, int *, int *); -extern int x25_parse_facilities(struct sk_buff *, struct x25_facilities *); -extern int x25_create_facilities(unsigned char *, struct x25_facilities *); /* x25_timer.c */ extern void x25_set_timer(struct sock *); diff -u --recursive --new-file v2.1.41/linux/init/main.c linux/init/main.c --- v2.1.41/linux/init/main.c Sat May 24 09:10:25 1997 +++ linux/init/main.c Wed May 28 10:49:11 1997 @@ -169,9 +169,6 @@ #ifdef CONFIG_ISDN_DRV_ICN extern void icn_setup(char *str, int *ints); #endif -#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 @@ -459,9 +456,6 @@ #ifdef CONFIG_ISDN_DRV_ICN { "icn=", icn_setup }, #endif -#ifdef CONFIG_ISDN_DRV_TELES - { "teles=", teles_setup }, -#endif #ifdef CONFIG_ISDN_DRV_HISAX { "hisax=", HiSax_setup }, { "HiSax=", HiSax_setup }, @@ -974,7 +968,7 @@ if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY; else mount_initrd =0; #endif - setup(); + setup(0); #ifdef __SMP__ /* @@ -1018,6 +1012,8 @@ } #endif + setup(1); + if (open("/dev/console",O_RDWR,0) < 0) printk("Unable to open an initial console.\n"); diff -u --recursive --new-file v2.1.41/linux/ipc/shm.c linux/ipc/shm.c --- v2.1.41/linux/ipc/shm.c Tue May 13 22:41:19 1997 +++ linux/ipc/shm.c Wed May 28 11:02:55 1997 @@ -136,7 +136,7 @@ struct shmid_ds *shp; int err, id = 0; - lock_kernel(); + down(¤t->mm->mmap_sem); if (size < 0 || size > SHMMAX) { err = -EINVAL; } else if (key == IPC_PRIVATE) { @@ -159,7 +159,7 @@ else err = (int) shp->shm_perm.seq * SHMMNI + id; } - unlock_kernel(); + up(¤t->mm->mmap_sem); return err; } @@ -482,7 +482,7 @@ unsigned long addr; unsigned long len; - lock_kernel(); + down(¤t->mm->mmap_sem); if (shmid < 0) { /* printk("shmat() -> EINVAL because shmid = %d < 0\n",shmid); */ goto out; @@ -575,7 +575,7 @@ *raddr = addr; err = 0; out: - unlock_kernel(); + up(¤t->mm->mmap_sem); return err; } @@ -626,12 +626,14 @@ { struct vm_area_struct *shmd, *shmdnext; + down(¤t->mm->mmap_sem); for (shmd = current->mm->mmap; shmd; shmd = shmdnext) { shmdnext = shmd->vm_next; if (shmd->vm_ops == &shm_vm_ops && shmd->vm_start - shmd->vm_offset == (ulong) shmaddr) do_munmap(shmd->vm_start, shmd->vm_end - shmd->vm_start); } + up(¤t->mm->mmap_sem); return 0; } diff -u --recursive --new-file v2.1.41/linux/mm/filemap.c linux/mm/filemap.c --- v2.1.41/linux/mm/filemap.c Tue May 13 22:41:20 1997 +++ linux/mm/filemap.c Wed May 28 11:02:55 1997 @@ -1210,7 +1210,9 @@ return 0; if (vma->vm_ops->sync) { int error; + lock_kernel(); /* Horrible */ error = vma->vm_ops->sync(vma, start, end-start, flags); + unlock_kernel(); /* Horrible */ if (error) return error; if (flags & MS_SYNC) @@ -1226,7 +1228,7 @@ struct vm_area_struct * vma; int unmapped_error, error = -EINVAL; - lock_kernel(); + down(¤t->mm->mmap_sem); if (start & ~PAGE_MASK) goto out; len = (len + ~PAGE_MASK) & PAGE_MASK; @@ -1272,7 +1274,7 @@ vma = vma->vm_next; } out: - unlock_kernel(); + up(¤t->mm->mmap_sem); return error; } diff -u --recursive --new-file v2.1.41/linux/mm/memory.c linux/mm/memory.c --- v2.1.41/linux/mm/memory.c Sat May 24 09:10:25 1997 +++ linux/mm/memory.c Wed May 28 11:04:03 1997 @@ -44,6 +44,8 @@ #include #include #include +#include +#include #include #include @@ -863,6 +865,9 @@ do_wp_page(tsk, vma, address, write_access, pte); } +/* + * By the time we get here, we already have the mm semaphore. + */ void handle_mm_fault(struct task_struct *tsk, struct vm_area_struct * vma, unsigned long address, int write_access) { @@ -877,8 +882,10 @@ pte = pte_alloc(pmd, address); if (!pte) goto no_memory; + lock_kernel(); /* Horrible */ handle_pte_fault(tsk, vma, address, write_access, pte); update_mmu_cache(vma, address, *pte); + unlock_kernel(); /* Horrible */ return; no_memory: oom(tsk); diff -u --recursive --new-file v2.1.41/linux/mm/mlock.c linux/mm/mlock.c --- v2.1.41/linux/mm/mlock.c Sun Jan 26 02:07:49 1997 +++ linux/mm/mlock.c Wed May 28 11:02:55 1997 @@ -191,7 +191,7 @@ unsigned long lock_limit; int error = -ENOMEM; - lock_kernel(); + down(¤t->mm->mmap_sem); len = (len + (start & ~PAGE_MASK) + ~PAGE_MASK) & PAGE_MASK; start &= PAGE_MASK; @@ -212,7 +212,7 @@ error = do_mlock(start, len, 1); out: - unlock_kernel(); + up(¤t->mm->mmap_sem); return error; } @@ -220,11 +220,11 @@ { int ret; - lock_kernel(); + down(¤t->mm->mmap_sem); len = (len + (start & ~PAGE_MASK) + ~PAGE_MASK) & PAGE_MASK; start &= PAGE_MASK; ret = do_mlock(start, len, 0); - unlock_kernel(); + up(¤t->mm->mmap_sem); return ret; } @@ -262,7 +262,7 @@ unsigned long lock_limit; int ret = -EINVAL; - lock_kernel(); + down(¤t->mm->mmap_sem); if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE))) goto out; @@ -280,7 +280,7 @@ ret = do_mlockall(flags); out: - unlock_kernel(); + up(¤t->mm->mmap_sem); return ret; } @@ -288,8 +288,8 @@ { int ret; - lock_kernel(); + down(¤t->mm->mmap_sem); ret = do_mlockall(0); - unlock_kernel(); + up(¤t->mm->mmap_sem); return ret; } diff -u --recursive --new-file v2.1.41/linux/mm/mmap.c linux/mm/mmap.c --- v2.1.41/linux/mm/mmap.c Thu May 15 16:48:05 1997 +++ linux/mm/mmap.c Wed May 28 11:02:55 1997 @@ -91,7 +91,7 @@ unsigned long newbrk, oldbrk; struct mm_struct *mm = current->mm; - lock_kernel(); + down(&mm->mmap_sem); retval = mm->brk; if (brk < mm->end_code) goto out; @@ -126,13 +126,13 @@ goto out; /* Ok, looks good - let it rip. */ - if(do_mmap(NULL, oldbrk, newbrk-oldbrk, + if (do_mmap(NULL, oldbrk, newbrk-oldbrk, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0) == oldbrk) mm->brk = brk; retval = mm->brk; out: - unlock_kernel(); + up(&mm->mmap_sem); return retval; } @@ -158,7 +158,8 @@ #undef _trans } -unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len, +unsigned long do_mmap(struct file * file, + unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long off) { struct mm_struct * mm = current->mm; @@ -317,6 +318,15 @@ if ((flags & VM_LOCKED) && !(flags & VM_IO)) { unsigned long start = addr; mm->locked_vm += len >> PAGE_SHIFT; + +/* + * This used to be just ugly, now it's downright broken - we can't do + * this when we're holding the mm semaphore (because the page fault + * will also try to get the semaphore - quite correctly). Besides, this + * never worked correctly anyway (we may not have read permission to + * the area in the first place). + */ +#if 0 do { char c; get_user(c,(char *) start); @@ -324,6 +334,7 @@ start += PAGE_SIZE; __asm__ __volatile__("": :"r" (c)); } while (len > 0); +#endif } return addr; } @@ -430,16 +441,6 @@ insert_vm_struct(current->mm, mpnt); } -asmlinkage int sys_munmap(unsigned long addr, size_t len) -{ - int ret; - - lock_kernel(); - ret = do_munmap(addr, len); - unlock_kernel(); - return ret; -} - /* Munmap is split into 2 main parts -- this part which finds * what needs doing, and the areas themselves, which do the * work. This now handles partial unmappings. @@ -518,6 +519,16 @@ return 0; } +asmlinkage int sys_munmap(unsigned long addr, size_t len) +{ + int ret; + + down(¤t->mm->mmap_sem); + ret = do_munmap(addr, len); + up(¤t->mm->mmap_sem); + return ret; +} + /* Release all mmaps. */ void exit_mmap(struct mm_struct * mm) { @@ -590,8 +601,6 @@ { struct vm_area_struct *prev, *mpnt, *next; - down(&mm->mmap_sem); - prev = NULL; mpnt = mm->mmap; while(mpnt && mpnt->vm_end <= start_addr) { @@ -599,7 +608,7 @@ mpnt = mpnt->vm_next; } if (!mpnt) - goto no_vma; + return; next = mpnt->vm_next; @@ -651,8 +660,6 @@ mpnt = prev; } mm->mmap_cache = NULL; /* Kill the cache. */ -no_vma: - up(&mm->mmap_sem); } __initfunc(void vma_init(void)) diff -u --recursive --new-file v2.1.41/linux/mm/mprotect.c linux/mm/mprotect.c --- v2.1.41/linux/mm/mprotect.c Sun Jan 26 02:07:49 1997 +++ linux/mm/mprotect.c Wed May 28 11:02:55 1997 @@ -206,20 +206,20 @@ { unsigned long nstart, end, tmp; struct vm_area_struct * vma, * next; - int error = -EINVAL; + int error; - lock_kernel(); if (start & ~PAGE_MASK) - goto out; + return -EINVAL; len = (len + ~PAGE_MASK) & PAGE_MASK; end = start + len; if (end < start) - goto out; + return -EINVAL; if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) - goto out; - error = 0; + return -EINVAL; if (end == start) - goto out; + return 0; + + down(¤t->mm->mmap_sem); vma = find_vma(current->mm, start); error = -EFAULT; if (!vma || vma->vm_start > start) @@ -255,6 +255,6 @@ } merge_segments(current->mm, start, end); out: - unlock_kernel(); + up(¤t->mm->mmap_sem); return error; } diff -u --recursive --new-file v2.1.41/linux/mm/mremap.c linux/mm/mremap.c --- v2.1.41/linux/mm/mremap.c Sun Jan 26 02:07:49 1997 +++ linux/mm/mremap.c Wed May 28 11:02:55 1997 @@ -21,6 +21,8 @@ #include #include +extern int do_munmap(unsigned long addr, size_t len); + static inline pte_t *get_one_pte(struct mm_struct *mm, unsigned long addr) { pgd_t * pgd; @@ -166,7 +168,7 @@ struct vm_area_struct *vma; unsigned long ret = -EINVAL; - lock_kernel(); + down(¤t->mm->mmap_sem); if (addr & ~PAGE_MASK) goto out; old_len = PAGE_ALIGN(old_len); @@ -231,6 +233,6 @@ else ret = -ENOMEM; out: - unlock_kernel(); + up(¤t->mm->mmap_sem); return ret; } diff -u --recursive --new-file v2.1.41/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c --- v2.1.41/linux/net/ax25/af_ax25.c Tue May 13 22:41:20 1997 +++ linux/net/ax25/af_ax25.c Wed May 28 10:49:11 1997 @@ -1,9 +1,6 @@ /* * 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: @@ -94,6 +91,7 @@ * Jonathan(G4KLX) Support for packet forwarding. * AX.25 036 Jonathan(G4KLX) Major restructuring. * Joerg(DL1BKE) Fixed DAMA Slave. + * Jonathan(G4KLX) Fix widlcard listen parameter setting. */ #include @@ -141,11 +139,11 @@ void ax25_free_cb(ax25_cb *ax25) { if (ax25->digipeat != NULL) { - kfree_s(ax25->digipeat, sizeof(ax25_digi)); + kfree(ax25->digipeat); ax25->digipeat = NULL; } - kfree_s(ax25, sizeof(ax25_cb)); + kfree(ax25); MOD_DEC_USE_COUNT; } @@ -472,7 +470,6 @@ if (ax25_dev->dama.slave && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE) ax25_dama_off(ax25); #endif - if (ax25->sk != NULL) { ax25->sk->state = TCP_CLOSE; ax25->sk->err = ENETRESET; @@ -481,9 +478,8 @@ ax25->sk->state_change(ax25->sk); ax25->sk->dead = 1; } - ax25_set_timer(ax25); - break; + break; case AX25_WINDOW: if (ax25->modulus == AX25_MODULUS) { @@ -558,6 +554,51 @@ } /* + * Fill in a created AX.25 created control block with the default + * values for a particular device. + */ +void ax25_fillin_cb(ax25_cb *ax25, ax25_dev *ax25_dev) +{ + ax25->ax25_dev = ax25_dev; + + if (ax25->ax25_dev != NULL) { + ax25->rtt = ax25_dev->values[AX25_VALUES_T1] / 2; + 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]; + ax25->backoff = ax25_dev->values[AX25_VALUES_BACKOFF]; + + if (ax25_dev->values[AX25_VALUES_AXDEFMODE]) { + 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]; + } + } else { + ax25->rtt = AX25_DEF_T1 / 2; + ax25->t1 = AX25_DEF_T1; + ax25->t2 = AX25_DEF_T2; + ax25->t3 = AX25_DEF_T3; + ax25->n2 = AX25_DEF_N2; + ax25->paclen = AX25_DEF_PACLEN; + ax25->idle = AX25_DEF_IDLE; + ax25->backoff = AX25_DEF_BACKOFF; + + if (AX25_DEF_AXDEFMODE) { + ax25->modulus = AX25_EMODULUS; + ax25->window = AX25_DEF_EWINDOW; + } else { + ax25->modulus = AX25_MODULUS; + ax25->window = AX25_DEF_WINDOW; + } + } +} + +/* * Create an empty AX.25 control block. */ ax25_cb *ax25_create_cb(void) @@ -578,56 +619,14 @@ init_timer(&ax25->timer); - ax25->rtt = AX25_DEF_T1 / 2; - ax25->t1 = AX25_DEF_T1; - ax25->t2 = AX25_DEF_T2; - ax25->t3 = AX25_DEF_T3; - ax25->n2 = AX25_DEF_N2; - ax25->paclen = AX25_DEF_PACLEN; - ax25->idle = AX25_DEF_IDLE; - - if (AX25_DEF_AXDEFMODE) { - ax25->modulus = AX25_EMODULUS; - ax25->window = AX25_DEF_EWINDOW; - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = AX25_DEF_WINDOW; - } + ax25_fillin_cb(ax25, NULL); - ax25->backoff = AX25_DEF_BACKOFF; - ax25->state = AX25_STATE_0; + ax25->state = AX25_STATE_0; return ax25; } /* - * Fill in a created AX.25 created control block with the default - * values for a particular device. - */ -void ax25_fillin_cb(ax25_cb *ax25, ax25_dev *ax25_dev) -{ - ax25->ax25_dev = ax25_dev; - - 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->values[AX25_VALUES_AXDEFMODE]) { - 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]; - } - - ax25->backoff = ax25_dev->values[AX25_VALUES_BACKOFF]; -} - -/* * Handling for system calls applied via the various interfaces to an * AX25 socket object */ @@ -698,8 +697,8 @@ sk->protinfo.ax25->modulus = opt ? AX25_EMODULUS : AX25_MODULUS; return 0; - case AX25_HDRINCL: - sk->protinfo.ax25->hdrincl = opt ? 1 : 0; + case AX25_PIDINCL: + sk->protinfo.ax25->pidincl = opt ? 1 : 0; return 0; case AX25_IAMDIGI: @@ -762,8 +761,8 @@ val = (sk->protinfo.ax25->modulus == AX25_EMODULUS); break; - case AX25_HDRINCL: - val = sk->protinfo.ax25->hdrincl; + case AX25_PIDINCL: + val = sk->protinfo.ax25->pidincl; break; case AX25_IAMDIGI: @@ -870,7 +869,7 @@ return 0; } -struct sock *ax25_make_new(struct sock *osk, struct device *dev) +struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) { struct sock *sk; ax25_cb *ax25; @@ -910,7 +909,7 @@ ax25->modulus = osk->protinfo.ax25->modulus; ax25->backoff = osk->protinfo.ax25->backoff; - ax25->hdrincl = osk->protinfo.ax25->hdrincl; + ax25->pidincl = osk->protinfo.ax25->pidincl; ax25->iamdigi = osk->protinfo.ax25->iamdigi; ax25->rtt = osk->protinfo.ax25->rtt; ax25->t1 = osk->protinfo.ax25->t1; @@ -921,7 +920,7 @@ ax25->paclen = osk->protinfo.ax25->paclen; ax25->window = osk->protinfo.ax25->window; - ax25->ax25_dev = osk->protinfo.ax25->ax25_dev; + ax25->ax25_dev = ax25_dev; ax25->source_addr = osk->protinfo.ax25->source_addr; if (osk->protinfo.ax25->digipeat != NULL) { @@ -1183,6 +1182,8 @@ #ifdef CONFIG_AX25_DAMA_SLAVE case AX25_PROTO_DAMA_SLAVE: + ax25->modulus = AX25_MODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; if (sk->protinfo.ax25->ax25_dev->dama.slave) ax25_ds_establish_data_link(sk->protinfo.ax25); else @@ -1406,9 +1407,11 @@ /* User data follows immediately after the AX.25 data */ memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); - /* Add the PID, usually AX25_TEXT */ - asmptr = skb_push(skb, 1); - *asmptr = sk->protocol; + /* Add the PID if one is not supplied by the user in the skb */ + if (!sk->protinfo.ax25->pidincl) { + asmptr = skb_push(skb, 1); + *asmptr = sk->protocol; + } SOCK_DEBUG(sk, "AX.25: Transmitting buffer\n"); @@ -1455,10 +1458,9 @@ { struct sock *sk = sock->sk; struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name; - int copied, length; + int copied; struct sk_buff *skb; int er; - int dama; /* * This works for seqpacket too. The receiver has ordered the @@ -1471,16 +1473,11 @@ if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL) return er; - if (sk->protinfo.ax25->hdrincl) { - length = skb->len + (skb->data - skb->h.raw); - } else { - if (sk->type == SOCK_SEQPACKET) - skb_pull(skb, 1); /* Remove PID */ - length = skb->len; - skb->h.raw = skb->data; - } + if (!sk->protinfo.ax25->pidincl) + skb_pull(skb, 1); /* Remove PID */ - copied = length; + skb->h.raw = skb->data; + copied = skb->len; if (copied > size) { copied = size; @@ -1492,6 +1489,7 @@ if (sax != NULL) { ax25_digi digi; ax25_address dest; + int dama; ax25_addr_parse(skb->data, skb->len, NULL, &dest, &digi, NULL, &dama); @@ -1816,6 +1814,9 @@ } #ifdef MODULE +MODULE_AUTHOR("Jonathan Naylor G4KLX "); +MODULE_DESCRIPTION("The amateur radio AX.25 link layer protocol"); + int init_module(void) { ax25_proto_init(NULL); diff -u --recursive --new-file v2.1.41/linux/net/ax25/ax25_addr.c linux/net/ax25/ax25_addr.c --- v2.1.41/linux/net/ax25/ax25_addr.c Thu Feb 27 10:57:32 1997 +++ linux/net/ax25/ax25_addr.c Wed May 28 10:49:11 1997 @@ -1,9 +1,6 @@ /* * 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: diff -u --recursive --new-file v2.1.41/linux/net/ax25/ax25_dev.c linux/net/ax25/ax25_dev.c --- v2.1.41/linux/net/ax25/ax25_dev.c Mon Apr 7 11:35:32 1997 +++ linux/net/ax25/ax25_dev.c Wed May 28 10:49:11 1997 @@ -1,9 +1,6 @@ /* * 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: @@ -77,7 +74,7 @@ unsigned long flags; if ((ax25_dev = kmalloc(sizeof(*ax25_dev), GFP_ATOMIC)) == NULL) { - printk(KERN_ERR "ax25_dev_device_up out of memory\n"); + printk(KERN_ERR "AX.25: ax25_dev_device_up - out of memory\n"); return; } @@ -102,11 +99,7 @@ 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; -#ifdef CONFIG_AX25_DAMA_SLAVE - ax25_dev->values[AX25_VALUES_PROTOCOL] = AX25_PROTO_DAMA_SLAVE; -#else ax25_dev->values[AX25_VALUES_PROTOCOL] = AX25_DEF_PROTOCOL; -#endif ax25_dev->values[AX25_VALUES_DS_TIMEOUT]= AX25_DEF_DS_TIMEOUT; save_flags(flags); cli(); @@ -147,7 +140,7 @@ if ((s = ax25_dev_list) == ax25_dev) { ax25_dev_list = s->next; restore_flags(flags); - kfree_s(ax25_dev, sizeof(ax25_dev)); + kfree(ax25_dev); #ifdef CONFIG_SYSCTL ax25_register_sysctl(); #endif @@ -158,7 +151,7 @@ if (s->next == ax25_dev) { s->next = ax25_dev->next; restore_flags(flags); - kfree_s(ax25_dev, sizeof(ax25_dev)); + kfree(ax25_dev); #ifdef CONFIG_SYSCTL ax25_register_sysctl(); #endif @@ -229,7 +222,7 @@ s = ax25_dev; ax25_dev = ax25_dev->next; - kfree_s(s, sizeof(ax25_dev)); + kfree(s); } } diff -u --recursive --new-file v2.1.41/linux/net/ax25/ax25_ds_in.c linux/net/ax25/ax25_ds_in.c --- v2.1.41/linux/net/ax25/ax25_ds_in.c Thu Mar 27 14:40:13 1997 +++ linux/net/ax25/ax25_ds_in.c Wed May 28 10:49:11 1997 @@ -1,9 +1,6 @@ /* * 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: @@ -61,12 +58,6 @@ 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; @@ -100,20 +91,15 @@ 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]; + 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; } } break; @@ -136,9 +122,7 @@ { switch (frametype) { case AX25_SABM: - case AX25_SABME: ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - ax25->dama_slave = 0; ax25_dama_off(ax25); break; @@ -146,7 +130,6 @@ ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); ax25->state = AX25_STATE_0; ax25_dama_off(ax25); - if (ax25->sk != NULL) { ax25->sk->state = TCP_CLOSE; ax25->sk->err = 0; @@ -162,7 +145,6 @@ if (pf) { ax25->state = AX25_STATE_0; ax25_dama_off(ax25); - if (ax25->sk != NULL) { ax25->sk->state = TCP_CLOSE; ax25->sk->err = 0; @@ -180,7 +162,6 @@ case AX25_RR: if (pf) { ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - ax25->dama_slave = 0; ax25_dama_off(ax25); } break; @@ -203,14 +184,8 @@ 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->modulus = AX25_MODULUS; + ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE); ax25->condition = 0x00; ax25->t1timer = 0; @@ -229,7 +204,6 @@ 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; @@ -245,7 +219,6 @@ 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; @@ -306,193 +279,7 @@ 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_ds_enquiry_response(ax25); - break; - } - ax25->condition &= ~AX25_COND_REJECT; - if (pf) { - ax25_ds_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_ds_enquiry_response(ax25); - } else { - ax25->condition |= AX25_COND_REJECT; - ax25_ds_enquiry_response(ax25); - ax25->condition &= ~AX25_COND_ACK_PENDING; - } - } - break; - - case AX25_FRMR: - case AX25_ILLEGAL: - ax25_ds_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_timer.c - * Handling of state 0 and connection release is in ax25.c. - */ -static int ax25_ds_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); - ax25_dama_on(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; - 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; - - 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; - - 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); - ax25->n2count = 0; - if (ax25->vs == ax25->va) { - ax25->t3timer = ax25->t3; - ax25->state = AX25_STATE_3; - } else { - ax25_requeue_frames(ax25); - } - } else { - ax25_ds_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - } - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - ax25->n2count = 0; - if (type == AX25_COMMAND && pf) - ax25_ds_enquiry_response(ax25); - } else { - ax25_ds_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - - case AX25_REJ: - ax25->condition &= ~AX25_COND_PEER_RX_BUSY; - if (pf) { - ax25->t1timer = 0; - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - ax25->n2count = 0; - if (ax25->vs == ax25->va) { - ax25->t3timer = ax25->t3; - ax25->state = AX25_STATE_3; - } else { - ax25_requeue_frames(ax25); - } - if (type == AX25_COMMAND && pf) - ax25_ds_enquiry_response(ax25); - } else { - ax25_ds_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - } - if (ax25_validate_nr(ax25, nr)) { - ax25_frames_acked(ax25, nr); - ax25->n2count = 0; - ax25_requeue_frames(ax25); - if (type == AX25_COMMAND && pf) - ax25_ds_enquiry_response(ax25); - } else { - ax25_ds_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - } - break; - - case AX25_I: - if (!ax25_validate_nr(ax25, nr)) { - ax25_ds_nr_error_recovery(ax25); - ax25->state = AX25_STATE_1; - break; - } - ax25_frames_acked(ax25, nr); - ax25->n2count = 0; - if (ax25->condition & AX25_COND_OWN_RX_BUSY) { - if (pf) ax25_ds_enquiry_response(ax25); - break; - } - if (ns == ax25->vr) { - ax25->vr = (ax25->vr + 1) % ax25->modulus; + 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 */ @@ -550,9 +337,6 @@ break; case AX25_STATE_3: queued = ax25_ds_state3_machine(ax25, skb, frametype, ns, nr, pf, type); - break; - case AX25_STATE_4: - queued = ax25_ds_state4_machine(ax25, skb, frametype, ns, nr, pf, type); break; } diff -u --recursive --new-file v2.1.41/linux/net/ax25/ax25_ds_subr.c linux/net/ax25/ax25_ds_subr.c --- v2.1.41/linux/net/ax25/ax25_ds_subr.c Thu Mar 27 14:40:13 1997 +++ linux/net/ax25/ax25_ds_subr.c Wed May 28 10:49:11 1997 @@ -1,9 +1,6 @@ /* * 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: @@ -109,9 +106,7 @@ continue; } - if (!(ax25o->condition & AX25_COND_PEER_RX_BUSY) && - (ax25o->state == AX25_STATE_3 || - (ax25o->state == AX25_STATE_4 && ax25o->t1timer == 0))) { + if (!(ax25o->condition & AX25_COND_PEER_RX_BUSY) && ax25o->state == AX25_STATE_3) { ax25_requeue_frames(ax25o); ax25_kick(ax25o); } @@ -125,12 +120,11 @@ void ax25_ds_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); + ax25->condition &= AX25_COND_DAMA_MODE; + ax25->n2count = 0; + ax25->t3timer = ax25->t3; + ax25->t2timer = 0; + ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25); } /* @@ -139,7 +133,6 @@ * We need a driver level request to switch duplex mode, that does * either SCC changing, PI config or KISS as required. Currently * this request isn't reliable. - * */ static void ax25_kiss_cmd(ax25_dev *ax25_dev, unsigned char cmd, unsigned char param) { @@ -173,13 +166,12 @@ * ax25->dama_slave=1 and look on every disconnect if still slave * connections exist. */ - static int ax25_check_dama_slave(ax25_dev *ax25_dev) { ax25_cb *ax25; for (ax25 = ax25_list; ax25 != NULL ; ax25 = ax25->next) - if (ax25->ax25_dev == ax25_dev && ax25->dama_slave && ax25->state > AX25_STATE_1) + if (ax25->ax25_dev == ax25_dev && (ax25->condition & AX25_COND_DAMA_MODE) && ax25->state > AX25_STATE_1) return 1; return 0; @@ -202,8 +194,7 @@ if (ax25_dev == NULL) return; - if (ax25_dev->dama.slave && !ax25_check_dama_slave(ax25_dev)) - { + if (ax25_dev->dama.slave && !ax25_check_dama_slave(ax25_dev)) { ax25_kiss_cmd(ax25_dev, 5, 0); ax25_dev->dama.slave = 0; ax25_ds_del_timer(ax25_dev); @@ -213,13 +204,13 @@ void ax25_dama_on(ax25_cb *ax25) { ax25_dev_dama_on(ax25->ax25_dev); - ax25->dama_slave = 1; + ax25->condition |= AX25_COND_DAMA_MODE; } void ax25_dama_off(ax25_cb *ax25) { ax25_dev_dama_off(ax25->ax25_dev); - ax25->dama_slave = 0; + ax25->condition &= ~AX25_COND_DAMA_MODE; } #endif diff -u --recursive --new-file v2.1.41/linux/net/ax25/ax25_ds_timer.c linux/net/ax25/ax25_ds_timer.c --- v2.1.41/linux/net/ax25/ax25_ds_timer.c Mon Apr 14 16:28:27 1997 +++ linux/net/ax25/ax25_ds_timer.c Wed May 28 10:49:11 1997 @@ -1,9 +1,6 @@ /* * 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: @@ -87,15 +84,13 @@ if (ax25_dev == NULL || !ax25_dev->dama.slave) return; /* Yikes! */ - if (!ax25_dev->dama.slave_timeout || --ax25_dev->dama.slave_timeout) - { + if (!ax25_dev->dama.slave_timeout || --ax25_dev->dama.slave_timeout) { ax25_ds_set_timer(ax25_dev); return; } - for (ax25=ax25_list; ax25 != NULL; ax25 = ax25->next) - { - if (ax25->ax25_dev != ax25_dev || !ax25->dama_slave) + for (ax25=ax25_list; ax25 != NULL; ax25 = ax25->next) { + if (ax25->ax25_dev != ax25_dev || !(ax25->condition & AX25_COND_DAMA_MODE)) continue; ax25_link_failed(&ax25->dest_addr, ax25_dev->dev); @@ -103,8 +98,7 @@ ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); ax25->state = AX25_STATE_0; - if (ax25->sk != NULL) - { + if (ax25->sk != NULL) { SOCK_DEBUG(ax25->sk, "AX.25 DAMA Slave Timeout\n"); ax25->sk->state = TCP_CLOSE; ax25->sk->err = ETIMEDOUT; @@ -120,7 +114,6 @@ ax25_dev_dama_off(ax25_dev); } - /* * AX.25 TIMER * @@ -141,7 +134,6 @@ break; case AX25_STATE_3: - case AX25_STATE_4: /* * Check the state of the receive buffer. */ @@ -279,12 +271,7 @@ } break; - case AX25_STATE_3: - ax25->n2count = 1; - ax25->state = AX25_STATE_4; - break; - - case AX25_STATE_4: + case AX25_STATE_3: if (ax25->n2count == ax25->n2) { ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev); ax25_clear_queues(ax25); diff -u --recursive --new-file v2.1.41/linux/net/ax25/ax25_iface.c linux/net/ax25/ax25_iface.c --- v2.1.41/linux/net/ax25/ax25_iface.c Thu Feb 27 10:57:32 1997 +++ linux/net/ax25/ax25_iface.c Wed May 28 10:49:11 1997 @@ -1,9 +1,6 @@ /* * 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: @@ -98,7 +95,7 @@ if (protocol->pid == pid) { protocol_list = protocol->next; restore_flags(flags); - kfree_s(protocol, sizeof(struct protocol_struct)); + kfree(protocol); return; } @@ -107,7 +104,7 @@ s = protocol->next; protocol->next = protocol->next->next; restore_flags(flags); - kfree_s(s, sizeof(struct protocol_struct)); + kfree(s); return; } @@ -152,7 +149,7 @@ if (linkfail->func == func) { linkfail_list = linkfail->next; restore_flags(flags); - kfree_s(linkfail, sizeof(struct linkfail_struct)); + kfree(linkfail); return; } @@ -161,7 +158,7 @@ s = linkfail->next; linkfail->next = linkfail->next->next; restore_flags(flags); - kfree_s(s, sizeof(struct linkfail_struct)); + kfree(s); return; } @@ -210,7 +207,7 @@ if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) { listen_list = listen->next; restore_flags(flags); - kfree_s(listen, sizeof(struct listen_struct)); + kfree(listen); return; } @@ -219,7 +216,7 @@ s = listen->next; listen->next = listen->next->next; restore_flags(flags); - kfree_s(s, sizeof(struct listen_struct)); + kfree(s); return; } diff -u --recursive --new-file v2.1.41/linux/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c --- v2.1.41/linux/net/ax25/ax25_in.c Mon Apr 14 16:28:27 1997 +++ linux/net/ax25/ax25_in.c Wed May 28 10:49:11 1997 @@ -1,9 +1,6 @@ /* * 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: @@ -73,7 +70,6 @@ static int ax25_rx_fragment(ax25_cb *ax25, struct sk_buff *skb) { struct sk_buff *skbn, *skbo; - int hdrlen, nhdrlen; if (ax25->fragno != 0) { if (!(*skb->data & AX25_SEG_FIRST)) { @@ -92,29 +88,16 @@ return 1; } - skbn->dev = ax25->ax25_dev->dev; - skb_reserve(skbn, AX25_MAX_HEADER_LEN); - /* Get first fragment from queue */ - skbo = skb_dequeue(&ax25->frag_queue); - hdrlen = skbo->data - skbo->h.raw; - nhdrlen = hdrlen - 2; - - skb_push(skbo, hdrlen); - skb_push(skbn, nhdrlen); + skbn->dev = ax25->ax25_dev->dev; skbn->h.raw = skbn->data; - /* Copy AX.25 headers */ - memcpy(skbn->data, skbo->data, nhdrlen); - skb_pull(skbn, nhdrlen); - skb_pull(skbo, hdrlen); - /* Copy data from the fragments */ - do { + while ((skbo = skb_dequeue(&ax25->frag_queue)) != NULL) { memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len); kfree_skb(skbo, FREE_READ); - } while ((skbo = skb_dequeue(&ax25->frag_queue)) != NULL); + } ax25->fraglen = 0; @@ -188,11 +171,13 @@ return (*func)(skb, ax25); } - 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 - ax25->condition |= AX25_COND_OWN_RX_BUSY; + if (ax25->sk != NULL && ax25->ax25_dev->values[AX25_VALUES_CONMODE] == 2) { + if ((!ax25->pidincl && ax25->sk->protocol == pid) || ax25->pidincl) { + if (sock_queue_rcv_skb(ax25->sk, skb) == 0) + queued = 1; + else + ax25->condition |= AX25_COND_OWN_RX_BUSY; + } } return queued; @@ -256,7 +241,7 @@ return 0; } - if (call_in_firewall(PF_AX25, skb->dev, skb->h.raw, NULL,&skb) != FW_ACCEPT) { + if (call_in_firewall(PF_AX25, skb->dev, skb->h.raw, NULL, &skb) != FW_ACCEPT) { kfree_skb(skb, FREE_READ); return 0; } @@ -400,7 +385,7 @@ 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 (sk->ack_backlog == sk->max_ack_backlog || (make = ax25_make_new(sk, ax25_dev)) == NULL) { if (mine) ax25_return_dm(dev, &src, &dest, &dp); kfree_skb(skb, FREE_READ); return 0; @@ -445,7 +430,7 @@ if (dp.ndigi == 0) { if (ax25->digipeat != NULL) { - kfree_s(ax25->digipeat, sizeof(ax25_digi)); + kfree(ax25->digipeat); ax25->digipeat = NULL; } } else { diff -u --recursive --new-file v2.1.41/linux/net/ax25/ax25_ip.c linux/net/ax25/ax25_ip.c --- v2.1.41/linux/net/ax25/ax25_ip.c Thu Mar 27 14:40:14 1997 +++ linux/net/ax25/ax25_ip.c Wed May 28 10:49:11 1997 @@ -1,9 +1,6 @@ /* * 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: @@ -94,7 +91,7 @@ *buff++ = AX25_P_ARP; break; default: - printk(KERN_ERR "AX.25 wrong protocol type 0x%x2.2\n", type); + printk(KERN_ERR "AX.25: ax25_encapsulate - wrong protocol type 0x%x2.2\n", type); *buff++ = 0; break; } @@ -138,7 +135,7 @@ * gets fixed. */ if ((ourskb = skb_copy(skb, GFP_ATOMIC)) == NULL) { - dev_kfree_skb(skb, FREE_WRITE); + kfree_skb(skb, FREE_WRITE); return 1; } @@ -163,12 +160,15 @@ bp[14] |= AX25_EBIT; bp[14] |= AX25_SSSID_SPARE; - ax25_dg_build_path(skb, (ax25_address *)(bp + 1), dev); + if ((ourskb = ax25_dg_build_path(skb, (ax25_address *)(bp + 1), dev)) == NULL) { + kfree_skb(skb, FREE_WRITE); + return 1; + } - skb->dev = dev; - skb->priority = SOPRI_NORMAL; + ourskb->dev = dev; + ourskb->priority = SOPRI_NORMAL; - ax25_queue_xmit(skb); + ax25_queue_xmit(ourskb); return 1; } diff -u --recursive --new-file v2.1.41/linux/net/ax25/ax25_out.c linux/net/ax25/ax25_out.c --- v2.1.41/linux/net/ax25/ax25_out.c Thu Mar 27 14:40:14 1997 +++ linux/net/ax25/ax25_out.c Wed May 28 10:49:11 1997 @@ -1,9 +1,6 @@ /* * 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: @@ -157,7 +154,7 @@ if ((skbn = alloc_skb(paclen + 2 + frontlen, GFP_ATOMIC)) == NULL) { restore_flags(flags); - printk(KERN_DEBUG "ax25_output: alloc_skb returned NULL\n"); + printk(KERN_CRIT "AX.25: ax25_output - out of memory\n"); return; } @@ -314,7 +311,9 @@ void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type) { + struct sk_buff *skbn; unsigned char *ptr; + int headroom; if (ax25->ax25_dev == NULL) { if (ax25->sk != NULL) { @@ -328,13 +327,24 @@ return; } - if (skb_headroom(skb) < ax25_addr_size(ax25->digipeat)) { - printk(KERN_CRIT "ax25_transmit_buffer: not enough room for digi-peaters\n"); + headroom = ax25_addr_size(ax25->digipeat); + + if (skb_headroom(skb) < headroom) { + if ((skbn = skb_realloc_headroom(skb, headroom)) == NULL) { + printk(KERN_CRIT "AX.25: ax25_transmit_buffer - out of memory\n"); + kfree_skb(skb, FREE_WRITE); + return; + } + + if (skb->sk != NULL) + skb_set_owner_w(skbn, skb->sk); + kfree_skb(skb, FREE_WRITE); - return; + skb = skbn; } - ptr = skb_push(skb, ax25_addr_size(ax25->digipeat)); + ptr = skb_push(skb, headroom); + ax25_addr_build(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus); skb->dev = ax25->ax25_dev->dev; @@ -352,7 +362,7 @@ unsigned char *ptr; if (call_out_firewall(PF_AX25, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) { - dev_kfree_skb(skb, FREE_WRITE); + kfree_skb(skb, FREE_WRITE); return; } diff -u --recursive --new-file v2.1.41/linux/net/ax25/ax25_route.c linux/net/ax25/ax25_route.c --- v2.1.41/linux/net/ax25/ax25_route.c Thu Feb 27 10:57:32 1997 +++ linux/net/ax25/ax25_route.c Wed May 28 10:49:11 1997 @@ -1,9 +1,6 @@ /* * 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: @@ -99,15 +96,15 @@ if (ax25_route_list == s) { ax25_route_list = s->next; if (s->digipeat != NULL) - kfree_s(s->digipeat, sizeof(ax25_digi)); - kfree_s(s, sizeof(ax25_route)); + kfree(s->digipeat); + kfree(s); } else { for (t = ax25_route_list; t != NULL; t = t->next) { if (t->next == s) { t->next = s->next; if (s->digipeat != NULL) - kfree_s(s->digipeat, sizeof(ax25_digi)); - kfree_s(s, sizeof(ax25_route)); + kfree(s->digipeat); + kfree(s); break; } } @@ -137,7 +134,7 @@ 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)); + kfree(ax25_rt->digipeat); ax25_rt->digipeat = NULL; } if (route.digi_count != 0) { @@ -161,7 +158,7 @@ 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(ax25_route)); + kfree(ax25_rt); return -ENOMEM; } ax25_rt->digipeat->lastrepeat = -1; @@ -191,15 +188,15 @@ if (ax25_route_list == s) { ax25_route_list = s->next; if (s->digipeat != NULL) - kfree_s(s->digipeat, sizeof(ax25_digi)); - kfree_s(s, sizeof(ax25_route)); + kfree(s->digipeat); + kfree(s); } else { for (t = ax25_route_list; t != NULL; t = t->next) { if (t->next == s) { t->next = s->next; if (s->digipeat != NULL) - kfree_s(s->digipeat, sizeof(ax25_digi)); - kfree_s(s, sizeof(ax25_route)); + kfree(s->digipeat); + kfree(s); break; } } @@ -413,8 +410,9 @@ ax25_adjust_path(addr, ax25->digipeat); } -void ax25_dg_build_path(struct sk_buff *skb, ax25_address *addr, struct device *dev) +struct sk_buff *ax25_dg_build_path(struct sk_buff *skb, ax25_address *addr, struct device *dev) { + struct sk_buff *skbn; ax25_route *ax25_rt; ax25_digi digipeat; ax25_address src, dest; @@ -424,10 +422,10 @@ skb_pull(skb, 1); /* skip KISS command */ if ((ax25_rt = ax25_find_route(addr, dev)) == NULL) - return; + return skb; if (ax25_rt->digipeat == NULL) - return; + return skb; digipeat = *ax25_rt->digipeat; @@ -436,8 +434,17 @@ len = ax25_rt->digipeat->ndigi * AX25_ADDR_LEN; if (skb_headroom(skb) < len) { - printk(KERN_CRIT "ax25_dg_build_path: not enough headroom for digis in skb\n"); - return; + if ((skbn = skb_realloc_headroom(skb, len)) == NULL) { + printk(KERN_CRIT "AX.25: ax25_dg_build_path - out of memory\n"); + return NULL; + } + + if (skb->sk != NULL) + skb_set_owner_w(skbn, skb->sk); + + kfree_skb(skb, FREE_WRITE); + + skb = skbn; } memcpy(&dest, skb->data + 0, AX25_ADDR_LEN); @@ -446,6 +453,8 @@ bp = skb_push(skb, len); ax25_addr_build(bp, &src, &dest, ax25_rt->digipeat, AX25_COMMAND, AX25_MODULUS); + + return skb; } /* @@ -476,9 +485,9 @@ ax25_rt = ax25_rt->next; if (s->digipeat != NULL) - kfree_s(s->digipeat, sizeof(ax25_digi)); + kfree(s->digipeat); - kfree_s(s, sizeof(ax25_route)); + kfree(s); } } diff -u --recursive --new-file v2.1.41/linux/net/ax25/ax25_std_in.c linux/net/ax25/ax25_std_in.c --- v2.1.41/linux/net/ax25/ax25_std_in.c Thu Feb 27 10:57:32 1997 +++ linux/net/ax25/ax25_std_in.c Wed May 28 10:49:11 1997 @@ -1,9 +1,6 @@ /* * 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: diff -u --recursive --new-file v2.1.41/linux/net/ax25/ax25_std_subr.c linux/net/ax25/ax25_std_subr.c --- v2.1.41/linux/net/ax25/ax25_std_subr.c Thu Feb 27 10:57:32 1997 +++ linux/net/ax25/ax25_std_subr.c Wed May 28 10:49:11 1997 @@ -1,9 +1,6 @@ /* * 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: diff -u --recursive --new-file v2.1.41/linux/net/ax25/ax25_std_timer.c linux/net/ax25/ax25_std_timer.c --- v2.1.41/linux/net/ax25/ax25_std_timer.c Mon Apr 14 16:28:27 1997 +++ linux/net/ax25/ax25_std_timer.c Wed May 28 10:49:11 1997 @@ -1,9 +1,6 @@ /* * 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: diff -u --recursive --new-file v2.1.41/linux/net/ax25/ax25_subr.c linux/net/ax25/ax25_subr.c --- v2.1.41/linux/net/ax25/ax25_subr.c Thu Feb 27 10:57:32 1997 +++ linux/net/ax25/ax25_subr.c Wed May 28 10:49:11 1997 @@ -1,9 +1,6 @@ /* * 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: @@ -289,6 +286,9 @@ */ void ax25_calculate_rtt(ax25_cb *ax25) { + if (ax25->backoff == 0) + return; + if (ax25->t1timer > 0 && ax25->n2count == 0) ax25->rtt = (9 * ax25->rtt + ax25->t1 - ax25->t1timer) / 10; diff -u --recursive --new-file v2.1.41/linux/net/ax25/ax25_timer.c linux/net/ax25/ax25_timer.c --- v2.1.41/linux/net/ax25/ax25_timer.c Thu Mar 27 14:40:14 1997 +++ linux/net/ax25/ax25_timer.c Wed May 28 10:49:11 1997 @@ -1,9 +1,6 @@ /* * 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: diff -u --recursive --new-file v2.1.41/linux/net/ax25/ax25_uid.c linux/net/ax25/ax25_uid.c --- v2.1.41/linux/net/ax25/ax25_uid.c Thu Feb 27 10:57:32 1997 +++ linux/net/ax25/ax25_uid.c Wed May 28 10:49:11 1997 @@ -1,9 +1,6 @@ /* * 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: @@ -110,14 +107,14 @@ if ((s = ax25_uid_list) == ax25_uid) { ax25_uid_list = s->next; restore_flags(flags); - kfree_s(ax25_uid, sizeof(ax25_uid_assoc)); + kfree(ax25_uid); 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)); + kfree(ax25_uid); return 0; } s = s->next; @@ -180,7 +177,7 @@ s = ax25_uid; ax25_uid = ax25_uid->next; - kfree_s(s, sizeof(ax25_uid_assoc)); + kfree(s); } } diff -u --recursive --new-file v2.1.41/linux/net/ax25/sysctl_net_ax25.c linux/net/ax25/sysctl_net_ax25.c --- v2.1.41/linux/net/ax25/sysctl_net_ax25.c Mon Apr 14 16:28:27 1997 +++ linux/net/ax25/sysctl_net_ax25.c Wed May 28 10:49:11 1997 @@ -5,6 +5,7 @@ * Added /proc/sys/net/ax25 directory entry (empty =) ). [MS] */ +#include #include #include #include @@ -123,7 +124,7 @@ ax25_table[n].proc_handler = NULL; memcpy(ax25_dev->systable, ax25_param_table, sizeof(ax25_dev->systable)); - + #ifndef CONFIG_AX25_DAMA_SLAVE /* * We do not wish to have a representation of this parameter @@ -151,7 +152,7 @@ { unregister_sysctl_table(ax25_table_header); - kfree_s(ax25_table, ax25_table_size); + kfree(ax25_table); ax25_dir_table[0].child = NULL; } diff -u --recursive --new-file v2.1.41/linux/net/lapb/lapb_iface.c linux/net/lapb/lapb_iface.c --- v2.1.41/linux/net/lapb/lapb_iface.c Tue May 13 22:41:24 1997 +++ linux/net/lapb/lapb_iface.c Wed May 28 10:49:12 1997 @@ -50,7 +50,7 @@ */ static void lapb_free_cb(lapb_cb *lapb) { - kfree_s(lapb, sizeof(lapb_cb)); + kfree(lapb); MOD_DEC_USE_COUNT; } @@ -123,7 +123,7 @@ { lapb_cb *lapb; - if ((lapb = (lapb_cb *)kmalloc(sizeof(*lapb), GFP_ATOMIC)) == NULL) + if ((lapb = kmalloc(sizeof(*lapb), GFP_ATOMIC)) == NULL) return NULL; MOD_INC_USE_COUNT; @@ -404,6 +404,9 @@ } #ifdef MODULE +MODULE_AUTHOR("Jonathan Naylor "); +MODULE_DESCRIPTION("The X.25 Link Access Procedure B link layer protocol"); + int init_module(void) { lapb_proto_init(NULL); diff -u --recursive --new-file v2.1.41/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c --- v2.1.41/linux/net/netrom/af_netrom.c Tue May 13 22:41:24 1997 +++ linux/net/netrom/af_netrom.c Wed May 28 10:49:12 1997 @@ -1,9 +1,6 @@ /* * NET/ROM release 006 * - * 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: @@ -30,6 +27,7 @@ * NET/ROM 005 Jonathan(G4KLX) Linux 2.1 * Alan(GW4PTS) Started POSIXisms * NET/ROM 006 Alan(GW4PTS) Brought in line with the ANK changes + * Jonathan(G4KLX) Removed hdrincl. */ #include @@ -66,6 +64,8 @@ #include #include +int nr_ndevs = 4; + int sysctl_netrom_default_path_quality = NR_DEFAULT_QUAL; int sysctl_netrom_obsolescence_count_initialiser = NR_DEFAULT_OBS; int sysctl_netrom_network_ttl_initialiser = NR_DEFAULT_TTL; @@ -86,7 +86,7 @@ static void nr_free_sock(struct sock *sk) { - kfree_s(sk->protinfo.nr, sizeof(*sk->protinfo.nr)); + kfree(sk->protinfo.nr); sk_free(sk); @@ -101,7 +101,7 @@ if ((sk = sk_alloc(GFP_ATOMIC)) == NULL) return NULL; - if ((nr = (nr_cb *)kmalloc(sizeof(*nr), GFP_ATOMIC)) == NULL) { + if ((nr = kmalloc(sizeof(*nr), GFP_ATOMIC)) == NULL) { sk_free(sk); return NULL; } @@ -328,94 +328,6 @@ * NET/ROM socket object. */ -/* - * dl1bke 960311: set parameters for existing NET/ROM connections, - * includes a KILL command to abort any connection. - * VERY useful for debugging ;-) - */ -static int nr_ctl_ioctl(const unsigned int cmd, void *arg) -{ - struct nr_ctl_struct nr_ctl; - struct sock *sk; - unsigned long flags; - int err; - - if ((err = verify_area(VERIFY_READ, arg, sizeof(nr_ctl))) != 0) - return err; - - copy_from_user(&nr_ctl, arg, sizeof(nr_ctl)); - - if ((sk = nr_find_socket(nr_ctl.index, nr_ctl.id)) == NULL) - return -ENOTCONN; - - switch (nr_ctl.cmd) { - case NETROM_KILL: - nr_clear_queues(sk); - nr_write_internal(sk, NR_DISCREQ); - sk->protinfo.nr->state = NR_STATE_0; - sk->state = TCP_CLOSE; - sk->err = ENETRESET; - sk->shutdown |= SEND_SHUTDOWN; - if (!sk->dead) - sk->state_change(sk); - sk->dead = 1; - nr_set_timer(sk); - break; - - case NETROM_T1: - if (nr_ctl.arg < 1) - return -EINVAL; - sk->protinfo.nr->t1 = nr_ctl.arg * NR_SLOWHZ; - save_flags(flags); cli(); - if (sk->protinfo.nr->t1timer > sk->protinfo.nr->t1) - sk->protinfo.nr->t1timer = sk->protinfo.nr->t1; - restore_flags(flags); - break; - - case NETROM_T2: - if (nr_ctl.arg < 1) - return -EINVAL; - save_flags(flags); cli(); - sk->protinfo.nr->t2 = nr_ctl.arg * NR_SLOWHZ; - if (sk->protinfo.nr->t2timer > sk->protinfo.nr->t2) - sk->protinfo.nr->t2timer = sk->protinfo.nr->t2; - restore_flags(flags); - break; - - case NETROM_N2: - if (nr_ctl.arg < 1 || nr_ctl.arg > 10) - return -EINVAL; - sk->protinfo.nr->n2count = 0; - sk->protinfo.nr->n2 = nr_ctl.arg; - break; - - case NETROM_T4: - if (nr_ctl.arg < 1) - return -EINVAL; - save_flags(flags); cli(); - sk->protinfo.nr->t4 = nr_ctl.arg * NR_SLOWHZ; - if (sk->protinfo.nr->t4timer > sk->protinfo.nr->t4) - sk->protinfo.nr->t4timer = sk->protinfo.nr->t4; - restore_flags(flags); - break; - - case NETROM_IDLE: - if (nr_ctl.arg < 1) - return -EINVAL; - save_flags(flags); cli(); - sk->protinfo.nr->idle = nr_ctl.arg * 60 * NR_SLOWHZ; - if (sk->protinfo.nr->idletimer > sk->protinfo.nr->idle) - sk->protinfo.nr->idletimer = sk->protinfo.nr->idle; - restore_flags(flags); - break; - - default: - return -EINVAL; - } - - return 0; -} - static int nr_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) { @@ -462,10 +374,6 @@ sk->protinfo.nr->idle = opt * 60 * NR_SLOWHZ; return 0; - case NETROM_HDRINCL: - sk->protinfo.nr->hdrincl = opt ? 1 : 0; - return 0; - default: return -ENOPROTOOPT; } @@ -505,10 +413,6 @@ val = sk->protinfo.nr->idle / (NR_SLOWHZ * 60); break; - case NETROM_HDRINCL: - val = sk->protinfo.nr->hdrincl; - break; - default: return -ENOPROTOOPT; } @@ -614,7 +518,6 @@ nr->device = osk->protinfo.nr->device; nr->bpqext = osk->protinfo.nr->bpqext; - nr->hdrincl = osk->protinfo.nr->hdrincl; return sk; } @@ -1122,7 +1025,6 @@ return len; } - static int nr_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm) { @@ -1144,12 +1046,8 @@ if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL) return er; - if (!sk->protinfo.nr->hdrincl) { - skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN); - skb->h.raw = skb->data; - } - - copied = skb->len; + skb->h.raw = skb->data; + copied = skb->len; if (copied > size) { copied = size; @@ -1231,10 +1129,6 @@ if (!suser()) return -EPERM; return nr_rt_ioctl(cmd, (void *)arg); - case SIOCNRCTLCON: - if (!suser()) return -EPERM; - return nr_ctl_ioctl(cmd, (void *)arg); - default: return dev_ioctl(cmd, (void *)arg); } @@ -1355,28 +1249,32 @@ }; #endif -static struct device dev_nr[] = { - {"nr0", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, nr_init}, - {"nr1", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, nr_init}, - {"nr2", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, nr_init}, - {"nr3", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, nr_init} -}; +static struct device *dev_nr; __initfunc(void nr_proto_init(struct net_proto *pro)) { int i; + if ((dev_nr = kmalloc(nr_ndevs * sizeof(struct device), GFP_KERNEL)) == NULL) { + printk(KERN_ERR "NET/ROM: nr_proto_init - unable to allocate device structure\n"); + return; + } + + memset(dev_nr, 0x00, nr_ndevs * sizeof(struct device)); + + for (i = 0; i < nr_ndevs; i++) { + dev_nr[i].name = kmalloc(20, GFP_KERNEL); + sprintf(dev_nr[i].name, "nr%d", i); + dev_nr[i].init = nr_init; + register_netdev(&dev_nr[i]); + } + sock_register(&nr_family_ops); register_netdevice_notifier(&nr_dev_notifier); printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.6 for AX25.035 Linux 2.1\n"); - if (!ax25_protocol_register(AX25_P_NETROM, nr_route_frame)) - printk(KERN_ERR "NET/ROM unable to register protocol with AX.25\n"); - if (!ax25_linkfail_register(nr_link_failed)) - printk(KERN_ERR "NET/ROM unable to register linkfail handler with AX.25\n"); - - for (i = 0; i < 4; i++) - register_netdev(&dev_nr[i]); + ax25_protocol_register(AX25_P_NETROM, nr_route_frame); + ax25_linkfail_register(nr_link_failed); #ifdef CONFIG_SYSCTL nr_register_sysctl(); @@ -1392,6 +1290,12 @@ #ifdef MODULE EXPORT_NO_SYMBOLS; +MODULE_PARM(nr_ndevs, "i"); +MODULE_PARM_DESC(nr_ndevs, "number of NET/ROM devices"); + +MODULE_AUTHOR("Jonathan Naylor G4KLX "); +MODULE_DESCRIPTION("The amateur radio NET/ROM network and transport layer protocol"); + int init_module(void) { nr_proto_init(NULL); @@ -1420,13 +1324,16 @@ #endif sock_unregister(AF_NETROM); - for (i = 0; i < 4; i++) { + for (i = 0; i < nr_ndevs; i++) { if (dev_nr[i].priv != NULL) { kfree(dev_nr[i].priv); dev_nr[i].priv = NULL; unregister_netdev(&dev_nr[i]); } + kfree(dev_nr[i].name); } + + kfree(dev_nr); } #endif diff -u --recursive --new-file v2.1.41/linux/net/netrom/nr_dev.c linux/net/netrom/nr_dev.c --- v2.1.41/linux/net/netrom/nr_dev.c Thu Mar 27 14:40:17 1997 +++ linux/net/netrom/nr_dev.c Wed May 28 10:49:12 1997 @@ -1,9 +1,6 @@ /* * NET/ROM release 006 * - * 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: @@ -123,7 +120,7 @@ struct sk_buff *skbn; unsigned char *bp = skb->data; - if (!arp_find(bp + 7, skb)) { + if (arp_find(bp + 7, skb)) { kfree_skb(skb, FREE_WRITE); return 1; } @@ -203,7 +200,7 @@ return 0; if (!dev->start) { - printk(KERN_ERR "netrom: xmit call when iface is down\n"); + printk(KERN_ERR "NET/ROM: nr_xmit - called when iface is down\n"); return 1; } @@ -254,10 +251,12 @@ dev->flags = 0; dev->family = AF_INET; - dev->pa_addr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; - dev->pa_alen = sizeof(unsigned long); +#ifdef CONFIG_INET + dev->pa_addr = in_aton("192.168.0.1"); + dev->pa_brdaddr = in_aton("192.168.0.255"); + dev->pa_mask = in_aton("255.255.255.0"); + dev->pa_alen = 4; +#endif if ((dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL)) == NULL) return -ENOMEM; diff -u --recursive --new-file v2.1.41/linux/net/netrom/nr_in.c linux/net/netrom/nr_in.c --- v2.1.41/linux/net/netrom/nr_in.c Sun Feb 2 05:18:52 1997 +++ linux/net/netrom/nr_in.c Wed May 28 10:49:12 1997 @@ -1,9 +1,6 @@ /* * NET/ROM release 006 * - * 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: @@ -23,6 +20,7 @@ * NET/ROM 003 Jonathan(G4KLX) Added NET/ROM fragment reception. * Darryl(G7LED) Added missing INFO with NAK case, optimized * INFOACK handling, removed reconnect on error. + * NET/ROM 006 Jonathan(G4KLX) Hdrincl removal changes. */ #include @@ -54,6 +52,8 @@ { struct sk_buff *skbo, *skbn = skb; + skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN); + if (more) { sk->protinfo.nr->fraglen += skb->len; skb_queue_tail(&sk->protinfo.nr->frag_queue, skb); @@ -69,12 +69,7 @@ skbn->h.raw = skbn->data; - skbo = skb_dequeue(&sk->protinfo.nr->frag_queue); - memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len); - kfree_skb(skbo, FREE_READ); - while ((skbo = skb_dequeue(&sk->protinfo.nr->frag_queue)) != NULL) { - skb_pull(skbo, NR_NETWORK_LEN + NR_TRANSPORT_LEN); memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len); kfree_skb(skbo, FREE_READ); } diff -u --recursive --new-file v2.1.41/linux/net/netrom/nr_out.c linux/net/netrom/nr_out.c --- v2.1.41/linux/net/netrom/nr_out.c Sun Feb 2 05:18:52 1997 +++ linux/net/netrom/nr_out.c Wed May 28 10:49:12 1997 @@ -1,9 +1,6 @@ /* * NET/ROM release 006 * - * 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: diff -u --recursive --new-file v2.1.41/linux/net/netrom/nr_route.c linux/net/netrom/nr_route.c --- v2.1.41/linux/net/netrom/nr_route.c Thu Mar 27 14:40:17 1997 +++ linux/net/netrom/nr_route.c Wed May 28 10:49:12 1997 @@ -1,9 +1,6 @@ /* * NET/ROM release 006 * - * 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: @@ -91,7 +88,7 @@ return 0; if (nr_neigh == NULL) { - if ((nr_neigh = (struct nr_neigh *)kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL) + if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL) return -ENOMEM; nr_neigh->callsign = *ax25; @@ -105,7 +102,7 @@ if (ax25_digi != NULL && ax25_digi->ndigi > 0) { if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) { - kfree_s(nr_neigh, sizeof(*nr_neigh)); + kfree(nr_neigh); return -ENOMEM; } *nr_neigh->digipeat = *ax25_digi; @@ -120,11 +117,11 @@ restore_flags(flags); } - if (quality != 0 && ax25cmp(nr, ax25) == 0) + if (quality != 0 && ax25cmp(nr, ax25) == 0 && !nr_neigh->locked) nr_neigh->quality = quality; if (nr_node == NULL) { - if ((nr_node = (struct nr_node *)kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL) + if ((nr_node = kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL) return -ENOMEM; nr_node->callsign = *nr; @@ -252,7 +249,7 @@ if ((s = nr_node_list) == nr_node) { nr_node_list = nr_node->next; restore_flags(flags); - kfree_s(nr_node, sizeof(struct nr_node)); + kfree(nr_node); return; } @@ -260,7 +257,7 @@ if (s->next == nr_node) { s->next = nr_node->next; restore_flags(flags); - kfree_s(nr_node, sizeof(struct nr_node)); + kfree(nr_node); return; } @@ -282,8 +279,8 @@ nr_neigh_list = nr_neigh->next; restore_flags(flags); if (nr_neigh->digipeat != NULL) - kfree_s(nr_neigh->digipeat, sizeof(ax25_digi)); - kfree_s(nr_neigh, sizeof(struct nr_neigh)); + kfree(nr_neigh->digipeat); + kfree(nr_neigh); return; } @@ -292,8 +289,8 @@ s->next = nr_neigh->next; restore_flags(flags); if (nr_neigh->digipeat != NULL) - kfree_s(nr_neigh->digipeat, sizeof(ax25_digi)); - kfree_s(nr_neigh, sizeof(struct nr_neigh)); + kfree(nr_neigh->digipeat); + kfree(nr_neigh); return; } @@ -370,7 +367,7 @@ } } - if ((nr_neigh = (struct nr_neigh *)kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL) + if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL) return -ENOMEM; nr_neigh->callsign = *callsign; @@ -384,7 +381,7 @@ if (ax25_digi != NULL && ax25_digi->ndigi > 0) { if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) { - kfree_s(nr_neigh, sizeof(*nr_neigh)); + kfree(nr_neigh); return -ENOMEM; } *nr_neigh->digipeat = *ax25_digi; @@ -688,6 +685,7 @@ if (ax25 != NULL && call_in_firewall(PF_NETROM, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) return 0; + if (ax25 == NULL && call_out_firewall(PF_NETROM, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) return 0; diff -u --recursive --new-file v2.1.41/linux/net/netrom/nr_subr.c linux/net/netrom/nr_subr.c --- v2.1.41/linux/net/netrom/nr_subr.c Sun Feb 2 05:18:52 1997 +++ linux/net/netrom/nr_subr.c Wed May 28 10:49:12 1997 @@ -1,9 +1,6 @@ /* * NET/ROM release 006 * - * 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: @@ -158,7 +155,7 @@ case NR_INFOACK: break; default: - printk(KERN_ERR "nr_write_internal: invalid frame type %d\n", frametype); + printk(KERN_ERR "NET/ROM: nr_write_internal - invalid frame type %d\n", frametype); return; } diff -u --recursive --new-file v2.1.41/linux/net/netrom/nr_timer.c linux/net/netrom/nr_timer.c --- v2.1.41/linux/net/netrom/nr_timer.c Mon Apr 14 16:28:28 1997 +++ linux/net/netrom/nr_timer.c Wed May 28 10:49:12 1997 @@ -1,9 +1,6 @@ /* * NET/ROM release 006 * - * 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: diff -u --recursive --new-file v2.1.41/linux/net/netsyms.c linux/net/netsyms.c --- v2.1.41/linux/net/netsyms.c Thu May 15 16:48:06 1997 +++ linux/net/netsyms.c Wed May 28 10:49:12 1997 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -163,6 +164,8 @@ EXPORT_SYMBOL(ip_fragment); EXPORT_SYMBOL(ip_dev_find_tunnel); EXPORT_SYMBOL(inet_family_ops); +EXPORT_SYMBOL(in_aton); +EXPORT_SYMBOL(in_ntoa); #ifdef CONFIG_IPV6_MODULE /* inet functions common to v4 and v6 */ diff -u --recursive --new-file v2.1.41/linux/net/rose/af_rose.c linux/net/rose/af_rose.c --- v2.1.41/linux/net/rose/af_rose.c Tue May 13 22:41:24 1997 +++ linux/net/rose/af_rose.c Wed May 28 10:49:12 1997 @@ -1,8 +1,5 @@ /* - * Rose release 001 - * - * 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. + * ROSE release 002 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -13,10 +10,13 @@ * 2 of the License, or (at your option) any later version. * * History - * Rose 001 Jonathan(G4KLX) Cloned from af_netrom.c. + * ROSE 001 Jonathan(G4KLX) Cloned from af_netrom.c. * Alan(GW4PTS) Hacked up for newer API stuff * Terry (VK2KTJ) Added support for variable length * address masks. + * ROSE 002 Jonathan(G4KLX) Changed hdrincl to qbitincl. + * Added random number facilities entry. + * Variable number of ROSE devices. */ #include @@ -54,6 +54,8 @@ #include #include +int rose_ndevs = 6; + int sysctl_rose_restart_request_timeout = ROSE_DEFAULT_T0; int sysctl_rose_call_request_timeout = ROSE_DEFAULT_T1; int sysctl_rose_reset_request_timeout = ROSE_DEFAULT_T2; @@ -62,8 +64,8 @@ int sysctl_rose_ack_hold_back_timeout = ROSE_DEFAULT_HB; int sysctl_rose_routing_control = ROSE_DEFAULT_ROUTING; int sysctl_rose_link_fail_timeout = ROSE_DEFAULT_FAIL_TIMEOUT; - -static unsigned int lci = 1; +int sysctl_rose_maximum_vcs = ROSE_DEFAULT_MAXVC; +int sysctl_rose_window_size = ROSE_DEFAULT_WINDOW_SIZE; static struct sock *volatile rose_list = NULL; @@ -72,7 +74,7 @@ ax25_address rose_callsign; /* - * Convert a Rose address into text. + * Convert a ROSE address into text. */ char *rose2asc(rose_address *addr) { @@ -94,7 +96,7 @@ } /* - * Compare two Rose addresses, 0 == equal. + * Compare two ROSE addresses, 0 == equal. */ int rosecmp(rose_address *addr1, rose_address *addr2) { @@ -108,7 +110,7 @@ } /* - * Compare two Rose addresses for only mask digits, 0 == equal. + * Compare two ROSE addresses for only mask digits, 0 == equal. */ int rosecmpm(rose_address *addr1, rose_address *addr2, unsigned short mask) { @@ -134,7 +136,7 @@ static void rose_free_sock(struct sock *sk) { - kfree_s(sk->protinfo.rose, sizeof(*sk->protinfo.rose)); + kfree(sk->protinfo.rose); sk_free(sk); @@ -149,7 +151,7 @@ if ((sk = sk_alloc(GFP_ATOMIC)) == NULL) return NULL; - if ((rose = (rose_cb *)kmalloc(sizeof(*rose), GFP_ATOMIC)) == NULL) { + if ((rose = kmalloc(sizeof(*rose), GFP_ATOMIC)) == NULL) { sk_free(sk); return NULL; } @@ -195,6 +197,27 @@ } /* + * Kill all bound sockets on a broken link layer connection to a + * particular neighbour. + */ +void rose_kill_by_neigh(struct rose_neigh *neigh) +{ + struct sock *s; + + for (s = rose_list; s != NULL; s = s->next) { + if (s->protinfo.rose->neighbour == neigh) { + s->protinfo.rose->state = ROSE_STATE_0; + s->protinfo.rose->neighbour = NULL; + s->state = TCP_CLOSE; + s->err = ENETUNREACH; + s->shutdown |= SEND_SHUTDOWN; + s->state_change(s); + s->dead = 1; + } + } +} + +/* * Kill all bound sockets on a dropped device. */ static void rose_kill_by_device(struct device *dev) @@ -224,9 +247,15 @@ if (event != NETDEV_DOWN) return NOTIFY_DONE; - rose_kill_by_device(dev); - rose_rt_device_down(dev); - rose_link_device_down(dev); + switch (dev->type) { + case ARPHRD_ROSE: + rose_kill_by_device(dev); + break; + case ARPHRD_AX25: + rose_link_device_down(dev); + rose_rt_device_down(dev); + break; + } return NOTIFY_DONE; } @@ -251,7 +280,7 @@ * Find a socket that wants to accept the Call Request we just * received. */ -static struct sock *rose_find_listener(ax25_address *call) +static struct sock *rose_find_listener(rose_address *addr, ax25_address *call) { unsigned long flags; struct sock *s; @@ -260,14 +289,14 @@ cli(); for (s = rose_list; s != NULL; s = s->next) { - if (ax25cmp(&s->protinfo.rose->source_call, call) == 0 && s->protinfo.rose->source_ndigis == 0 && s->state == TCP_LISTEN) { + if (rosecmp(&s->protinfo.rose->source_addr, addr) == 0 && ax25cmp(&s->protinfo.rose->source_call, call) == 0 && s->protinfo.rose->source_ndigis == 0 && s->state == TCP_LISTEN) { restore_flags(flags); return s; } } for (s = rose_list; s != NULL; s = s->next) { - if (ax25cmp(&s->protinfo.rose->source_call, &null_ax25_address) == 0 && s->state == TCP_LISTEN) { + if (rosecmp(&s->protinfo.rose->source_addr, addr) == 0 && ax25cmp(&s->protinfo.rose->source_call, &null_ax25_address) == 0 && s->state == TCP_LISTEN) { restore_flags(flags); return s; } @@ -278,9 +307,9 @@ } /* - * Find a connected Rose socket given my LCI and device. + * Find a connected ROSE socket given my LCI and device. */ -struct sock *rose_find_socket(unsigned int lci, struct device *dev) +struct sock *rose_find_socket(unsigned int lci, struct rose_neigh *neigh) { struct sock *s; unsigned long flags; @@ -289,7 +318,7 @@ cli(); for (s = rose_list; s != NULL; s = s->next) { - if (s->protinfo.rose->lci == lci && s->protinfo.rose->neighbour->dev == dev) { + if (s->protinfo.rose->lci == lci && s->protinfo.rose->neighbour == neigh) { restore_flags(flags); return s; } @@ -303,17 +332,21 @@ /* * Find a unique LCI for a given device. */ -unsigned int rose_new_lci(struct device *dev) +unsigned int rose_new_lci(struct rose_neigh *neigh) { - lci++; - if (lci > 4095) lci = 1; + int lci; - while (rose_find_socket(lci, dev) != NULL) { - lci++; - if (lci > 4095) lci = 1; + if (neigh->dce_mode) { + for (lci = 1; lci <= sysctl_rose_maximum_vcs; lci++) + if (rose_find_socket(lci, neigh) == NULL && rose_route_free_lci(lci, neigh) == NULL) + return lci; + } else { + for (lci = sysctl_rose_maximum_vcs; lci > 0; lci--) + if (rose_find_socket(lci, neigh) == NULL && rose_route_free_lci(lci, neigh) == NULL) + return lci; } - return lci; + return 0; } /* @@ -374,94 +407,9 @@ /* * Handling for system calls applied via the various interfaces to a - * Rose socket object. + * ROSE socket object. */ -/* - * dl1bke 960311: set parameters for existing Rose connections, - * includes a KILL command to abort any connection. - * VERY useful for debugging ;-) - */ -static int rose_ctl_ioctl(const unsigned int cmd, void *arg) -{ - struct rose_ctl_struct rose_ctl; - struct sock *sk; - unsigned long flags; - struct device *dev; - int err; - - if ((err = verify_area(VERIFY_READ, arg, sizeof(rose_ctl))) != 0) - return err; - - copy_from_user(&rose_ctl, arg, sizeof(rose_ctl)); - - if ((dev = rose_ax25_dev_get(rose_ctl.dev)) == NULL) - return -EINVAL; - - if ((sk = rose_find_socket(rose_ctl.lci, dev)) == NULL) - return -ENOTCONN; - - switch (rose_ctl.cmd) { - case ROSE_KILL: - rose_clear_queues(sk); - rose_write_internal(sk, ROSE_CLEAR_REQUEST); - sk->protinfo.rose->state = ROSE_STATE_0; - sk->state = TCP_CLOSE; - sk->err = ENETRESET; - sk->shutdown |= SEND_SHUTDOWN; - if (!sk->dead) - sk->state_change(sk); - sk->dead = 1; - rose_set_timer(sk); - break; - - case ROSE_T1: - if (rose_ctl.arg < 1) - return -EINVAL; - save_flags(flags); cli(); - sk->protinfo.rose->t1 = rose_ctl.arg * ROSE_SLOWHZ; - restore_flags(flags); - break; - - case ROSE_T2: - if (rose_ctl.arg < 1) - return -EINVAL; - save_flags(flags); cli(); - sk->protinfo.rose->t2 = rose_ctl.arg * ROSE_SLOWHZ; - restore_flags(flags); - break; - - case ROSE_T3: - if (rose_ctl.arg < 1) - return -EINVAL; - save_flags(flags); cli(); - sk->protinfo.rose->t3 = rose_ctl.arg * ROSE_SLOWHZ; - restore_flags(flags); - break; - - case ROSE_HOLDBACK: - if (rose_ctl.arg < 1) - return -EINVAL; - save_flags(flags); cli(); - sk->protinfo.rose->hb = rose_ctl.arg * ROSE_SLOWHZ; - restore_flags(flags); - break; - - case ROSE_IDLE: - if (rose_ctl.arg < 1) - return -EINVAL; - save_flags(flags); cli(); - sk->protinfo.rose->idle = rose_ctl.arg * 60 * ROSE_SLOWHZ; - restore_flags(flags); - break; - - default: - return -EINVAL; - } - - return 0; -} - static int rose_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) { @@ -508,8 +456,8 @@ sk->protinfo.rose->idle = opt * 60 * ROSE_SLOWHZ; return 0; - case ROSE_HDRINCL: - sk->protinfo.rose->hdrincl = opt ? 1 : 0; + case ROSE_QBITINCL: + sk->protinfo.rose->qbitincl = opt ? 1 : 0; return 0; default: @@ -551,8 +499,8 @@ val = sk->protinfo.rose->idle / (ROSE_SLOWHZ * 60); break; - case ROSE_HDRINCL: - val = sk->protinfo.rose->hdrincl; + case ROSE_QBITINCL: + val = sk->protinfo.rose->qbitincl; break; default: @@ -654,8 +602,8 @@ rose->hb = osk->protinfo.rose->hb; rose->idle = osk->protinfo.rose->idle; - rose->device = osk->protinfo.rose->device; - rose->hdrincl = osk->protinfo.rose->hdrincl; + rose->device = osk->protinfo.rose->device; + rose->qbitincl = osk->protinfo.rose->qbitincl; return sk; } @@ -736,7 +684,7 @@ return -EINVAL; if ((dev = rose_dev_get(&addr->srose_addr)) == NULL) { - SOCK_DEBUG(sk, "Rose: bind failed: invalid address\n"); + SOCK_DEBUG(sk, "ROSE: bind failed: invalid address\n"); return -EADDRNOTAVAIL; } @@ -760,7 +708,7 @@ rose_insert_socket(sk); sk->zapped = 0; - SOCK_DEBUG(sk, "Rose: socket is bound\n"); + SOCK_DEBUG(sk, "ROSE: socket is bound\n"); return 0; } @@ -793,7 +741,10 @@ if (addr->srose_family != AF_ROSE) return -EINVAL; - if ((sk->protinfo.rose->neighbour = rose_get_neigh(&addr->srose_addr)) == NULL) + if ((sk->protinfo.rose->neighbour = rose_get_neigh(&addr->srose_addr)) == NULL) + return -ENETUNREACH; + + if ((sk->protinfo.rose->lci = rose_new_lci(sk->protinfo.rose->neighbour)) == 0) return -ENETUNREACH; if (sk->zapped) { /* Must bind first - autobinding in this may or may not work */ @@ -814,11 +765,12 @@ sk->protinfo.rose->dest_addr = addr->srose_addr; sk->protinfo.rose->dest_call = addr->srose_call; + sk->protinfo.rose->rand = ((int)sk->protinfo.rose & 0xFFFF) + sk->protinfo.rose->lci; + if (addr->srose_ndigis == 1) { sk->protinfo.rose->dest_ndigis = 1; sk->protinfo.rose->dest_digi = addr->srose_digi; } - sk->protinfo.rose->lci = rose_new_lci(sk->protinfo.rose->neighbour->dev); /* Move to connecting socket, start sending Connect Requests */ sock->state = SS_CONNECTING; @@ -954,7 +906,7 @@ { struct sock *sk; struct sock *make; - rose_cb rose; + struct rose_facilities facilities; skb->sk = NULL; /* Initially we don't know who it's for */ @@ -965,11 +917,11 @@ /* * XXX This is an error. */ - if (!rose_parse_facilities(skb, &rose)) { + if (!rose_parse_facilities(skb, &facilities)) { return 0; } - sk = rose_find_listener(&rose.source_call); + sk = rose_find_listener(&facilities.source_addr, &facilities.source_call); /* * We can't accept the Call Request. @@ -983,14 +935,14 @@ make->state = TCP_ESTABLISHED; make->protinfo.rose->lci = lci; - make->protinfo.rose->dest_addr = rose.dest_addr; - make->protinfo.rose->dest_call = rose.dest_call; - make->protinfo.rose->dest_ndigis = rose.dest_ndigis; - make->protinfo.rose->dest_digi = rose.dest_digi; - make->protinfo.rose->source_addr = rose.source_addr; - make->protinfo.rose->source_call = rose.source_call; - make->protinfo.rose->source_ndigis = rose.source_ndigis; - make->protinfo.rose->source_digi = rose.source_digi; + make->protinfo.rose->dest_addr = facilities.dest_addr; + make->protinfo.rose->dest_call = facilities.dest_call; + make->protinfo.rose->dest_ndigis = facilities.dest_ndigis; + make->protinfo.rose->dest_digi = facilities.dest_digi; + make->protinfo.rose->source_addr = facilities.source_addr; + make->protinfo.rose->source_call = facilities.source_call; + make->protinfo.rose->source_ndigis = facilities.source_ndigis; + make->protinfo.rose->source_digi = facilities.source_digi; make->protinfo.rose->neighbour = neigh; make->protinfo.rose->device = dev; @@ -1026,7 +978,7 @@ struct sockaddr_rose srose; struct sk_buff *skb; unsigned char *asmptr; - int size; + int size, qbit = 0; if (msg->msg_flags & ~MSG_DONTWAIT) return -EINVAL; @@ -1039,7 +991,7 @@ return -EPIPE; } - if (sk->protinfo.rose->device == NULL) + if (sk->protinfo.rose->neighbour == NULL || sk->protinfo.rose->device == NULL) return -ENETUNREACH; if (usrose != NULL) { @@ -1069,44 +1021,55 @@ srose.srose_digi = sk->protinfo.rose->dest_digi; } } - SOCK_DEBUG(sk, "Rose: sendto: Addresses built.\n"); + + SOCK_DEBUG(sk, "ROSE: sendto: Addresses built.\n"); /* Build a packet */ - SOCK_DEBUG(sk, "Rose: sendto: building packet.\n"); + SOCK_DEBUG(sk, "ROSE: sendto: building packet.\n"); size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN; if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) return err; - skb_reserve(skb, size - len); + skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN); /* - * Push down the Rose header + * Put the data on the end */ + SOCK_DEBUG(sk, "ROSE: Appending user data\n"); - asmptr = skb_push(skb, ROSE_MIN_LEN); - SOCK_DEBUG(sk, "Building Rose Header.\n"); + asmptr = skb->h.raw = skb_put(skb, len); - /* Build a Rose Transport header */ + memcpy_fromiovec(asmptr, msg->msg_iov, len); - *asmptr++ = ((sk->protinfo.rose->lci >> 8) & 0x0F) | ROSE_GFI; - *asmptr++ = (sk->protinfo.rose->lci >> 0) & 0xFF; - *asmptr++ = ROSE_DATA; - SOCK_DEBUG(sk, "Built header.\n"); + /* + * If the Q BIT Include socket option is in force, the first + * byte of the user data is the logical value of the Q Bit. + */ + if (sk->protinfo.rose->qbitincl) { + qbit = skb->data[0]; + skb_pull(skb, 1); + } /* - * Put the data on the end + * Push down the ROSE header */ + asmptr = skb_push(skb, ROSE_MIN_LEN); - skb->h.raw = skb_put(skb, len); + SOCK_DEBUG(sk, "ROSE: Building Network Header.\n"); - asmptr = skb->h.raw; - SOCK_DEBUG(sk, "Rose: Appending user data\n"); + /* Build a ROSE Network header */ + asmptr[0] = ((sk->protinfo.rose->lci >> 8) & 0x0F) | ROSE_GFI; + asmptr[1] = (sk->protinfo.rose->lci >> 0) & 0xFF; + asmptr[2] = ROSE_DATA; - /* User data follows immediately after the Rose transport header */ - memcpy_fromiovec(asmptr, msg->msg_iov, len); - SOCK_DEBUG(sk, "Rose: Transmitting buffer\n"); + if (qbit) + asmptr[0] |= ROSE_Q_BIT; + + SOCK_DEBUG(sk, "ROSE: Built header.\n"); + SOCK_DEBUG(sk, "ROSE: Transmitting buffer\n"); + if (sk->state != TCP_ESTABLISHED) { kfree_skb(skb, FREE_WRITE); return -ENOTCONN; @@ -1123,7 +1086,8 @@ { struct sock *sk = sock->sk; struct sockaddr_rose *srose = (struct sockaddr_rose *)msg->msg_name; - int copied; + int copied, qbit; + unsigned char *asmptr; struct sk_buff *skb; int er; @@ -1138,12 +1102,17 @@ if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL) return er; - if (!sk->protinfo.rose->hdrincl) { - skb_pull(skb, ROSE_MIN_LEN); - skb->h.raw = skb->data; + qbit = (skb->data[0] & ROSE_Q_BIT) == ROSE_Q_BIT; + + skb_pull(skb, ROSE_MIN_LEN); + + if (sk->protinfo.rose->qbitincl) { + asmptr = skb_push(skb, 1); + *asmptr = qbit; } - copied = skb->len; + skb->h.raw = skb->data; + copied = skb->len; if (copied > size) { copied = size; @@ -1231,10 +1200,6 @@ if (!suser()) return -EPERM; return rose_rt_ioctl(cmd, (void *)arg); - case SIOCRSCTLCON: - if (!suser()) return -EPERM; - return rose_ctl_ioctl(cmd, (void *)arg); - case SIOCRSL2CALL: if (!suser()) return -EPERM; if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(ax25_address))) != 0) @@ -1373,14 +1338,7 @@ }; #endif -static struct device dev_rose[] = { - {"rose0", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, rose_init}, - {"rose1", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, rose_init}, - {"rose2", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, rose_init}, - {"rose3", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, rose_init}, - {"rose4", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, rose_init}, - {"rose5", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, rose_init} -}; +static struct device *dev_rose; __initfunc(void rose_proto_init(struct net_proto *pro)) { @@ -1388,17 +1346,26 @@ rose_callsign = null_ax25_address; - sock_register(&rose_family_ops); - register_netdevice_notifier(&rose_dev_notifier); - printk(KERN_INFO "G4KLX Rose for Linux. Version 0.1 for AX25.035 Linux 2.1\n"); + if ((dev_rose = kmalloc(rose_ndevs * sizeof(struct device), GFP_KERNEL)) == NULL) { + printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate device structure\n"); + return; + } - if (!ax25_protocol_register(AX25_P_ROSE, rose_route_frame)) - printk(KERN_ERR "Rose unable to register protocol with AX.25\n"); - if (!ax25_linkfail_register(rose_link_failed)) - printk(KERN_ERR "Rose unable to register linkfail handler with AX.25\n"); + memset(dev_rose, 0x00, rose_ndevs * sizeof(struct device)); - for (i = 0; i < 6; i++) + for (i = 0; i < rose_ndevs; i++) { + dev_rose[i].name = kmalloc(20, GFP_KERNEL); + sprintf(dev_rose[i].name, "rose%d", i); + dev_rose[i].init = rose_init; register_netdev(&dev_rose[i]); + } + + sock_register(&rose_family_ops); + register_netdevice_notifier(&rose_dev_notifier); + printk(KERN_INFO "G4KLX ROSE for Linux. Version 0.2 for AX25.035 Linux 2.1\n"); + + ax25_protocol_register(AX25_P_ROSE, rose_route_frame); + ax25_linkfail_register(rose_link_failed); #ifdef CONFIG_SYSCTL rose_register_sysctl(); @@ -1415,6 +1382,12 @@ #ifdef MODULE EXPORT_NO_SYMBOLS; +MODULE_PARM(rose_ndevs, "i"); +MODULE_PARM_DESC(rose_ndevs, "number of ROSE devices"); + +MODULE_AUTHOR("Jonathan Naylor G4KLX "); +MODULE_DESCRIPTION("The amateur radio ROSE network layer protocol"); + int init_module(void) { rose_proto_init(NULL); @@ -1447,13 +1420,16 @@ sock_unregister(AF_ROSE); - for (i = 0; i < 6; i++) { + for (i = 0; i < rose_ndevs; i++) { if (dev_rose[i].priv != NULL) { kfree(dev_rose[i].priv); dev_rose[i].priv = NULL; unregister_netdev(&dev_rose[i]); } + kfree(dev_rose[i].name); } + + kfree(dev_rose); } #endif diff -u --recursive --new-file v2.1.41/linux/net/rose/rose_dev.c linux/net/rose/rose_dev.c --- v2.1.41/linux/net/rose/rose_dev.c Thu Mar 27 14:40:17 1997 +++ linux/net/rose/rose_dev.c Wed May 28 10:49:12 1997 @@ -1,8 +1,5 @@ /* - * Rose release 001 - * - * 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. + * ROSE release 002 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -13,7 +10,7 @@ * 2 of the License, or (at your option) any later version. * * History - * Rose 001 Jonathan(G4KLX) Cloned from nr_dev.c. + * ROSE 001 Jonathan(G4KLX) Cloned from nr_dev.c. * Hans(PE1AYX) Fixed interface to IP layer. */ @@ -52,7 +49,7 @@ #include /* - * Only allow IP over Rose frames through if the netrom device is up. + * Only allow IP over ROSE frames through if the netrom device is up. */ int rose_rx_ip(struct sk_buff *skb, struct device *dev) @@ -175,7 +172,7 @@ return 0; if (!dev->start) { - printk(KERN_ERR "rose: xmit call when iface is down\n"); + printk(KERN_ERR "ROSE: rose_xmit - called when iface is down\n"); return 1; } @@ -226,10 +223,12 @@ dev->flags = 0; dev->family = AF_INET; - dev->pa_addr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; - dev->pa_alen = sizeof(unsigned long); +#ifdef CONFIG_INET + dev->pa_addr = in_aton("192.168.0.1"); + dev->pa_brdaddr = in_aton("192.168.0.255"); + dev->pa_mask = in_aton("255.255.255.0"); + dev->pa_alen = 4; +#endif if ((dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL)) == NULL) return -ENOMEM; diff -u --recursive --new-file v2.1.41/linux/net/rose/rose_in.c linux/net/rose/rose_in.c --- v2.1.41/linux/net/rose/rose_in.c Thu Feb 27 10:57:32 1997 +++ linux/net/rose/rose_in.c Wed May 28 10:49:12 1997 @@ -1,8 +1,5 @@ /* - * Rose release 001 - * - * 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. + * ROSE release 002 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -19,7 +16,7 @@ * easy to break; * * History - * Rose 001 Jonathan(G4KLX) Cloned from nr_in.c + * ROSE 001 Jonathan(G4KLX) Cloned from nr_in.c */ #include @@ -116,8 +113,7 @@ sk->dead = 1; break; - default: /* XXX */ - printk(KERN_WARNING "rose: unknown %02X in state 1\n", frametype); + default: break; } @@ -146,8 +142,7 @@ sk->dead = 1; break; - default: /* XXX */ - printk(KERN_WARNING "rose: unknown %02X in state 2\n", frametype); + default: break; } @@ -245,7 +240,7 @@ * If the window is full, ack the frame, else start the * acknowledge hold back timer. */ - if (((sk->protinfo.rose->vl + ROSE_MAX_WINDOW_SIZE) % ROSE_MODULUS) == sk->protinfo.rose->vr) { + if (((sk->protinfo.rose->vl + sysctl_rose_window_size) % ROSE_MODULUS) == sk->protinfo.rose->vr) { sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING; sk->protinfo.rose->timer = 0; rose_enquiry_response(sk); @@ -256,7 +251,7 @@ break; default: - printk(KERN_WARNING "rose: unknown %02X in state 3\n", frametype); + printk(KERN_WARNING "ROSE: unknown %02X in state 3\n", frametype); break; } @@ -297,8 +292,7 @@ sk->dead = 1; break; - default: /* XXX */ - printk(KERN_WARNING "rose: unknown %02X in state 4\n", frametype); + default: break; } diff -u --recursive --new-file v2.1.41/linux/net/rose/rose_link.c linux/net/rose/rose_link.c --- v2.1.41/linux/net/rose/rose_link.c Thu Mar 27 14:40:17 1997 +++ linux/net/rose/rose_link.c Wed May 28 10:49:12 1997 @@ -1,8 +1,5 @@ /* - * Rose release 001 - * - * 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. + * ROSE release 002 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -13,7 +10,7 @@ * 2 of the License, or (at your option) any later version. * * History - * Rose 001 Jonathan(G4KLX) Cloned from rose_timer.c + * ROSE 001 Jonathan(G4KLX) Cloned from rose_timer.c */ #include @@ -62,7 +59,7 @@ } /* - * Rose Link Timer + * ROSE Link Timer * * This routine is called every 100ms. Decrement timer by this * amount - if expired then process the event. @@ -79,7 +76,8 @@ if (neigh->t0timer == 0) { rose_transmit_restart_request(neigh); - neigh->t0timer = sysctl_rose_restart_request_timeout; + neigh->dce_mode = 0; + neigh->t0timer = sysctl_rose_restart_request_timeout; } } @@ -134,6 +132,7 @@ case ROSE_RESTART_REQUEST: neigh->t0timer = 0; neigh->restarted = 1; + neigh->dce_mode = (skb->data[3] == 0x00); del_timer(&neigh->timer); rose_transmit_restart_confirmation(neigh); break; @@ -145,11 +144,11 @@ break; case ROSE_DIAGNOSTIC: - printk(KERN_WARNING "rose: diagnostic #%d\n", skb->data[3]); + printk(KERN_WARNING "ROSE: received diagnostic #%d - %02X %02X %02X\n", skb->data[3], skb->data[4], skb->data[5], skb->data[6]); break; default: - printk(KERN_WARNING "rose: received unknown %02X with LCI 000\n", frametype); + printk(KERN_WARNING "ROSE: received unknown %02X with LCI 000\n", frametype); break; } @@ -278,8 +277,10 @@ { unsigned char *dptr; - if (call_fw_firewall(PF_ROSE, skb->dev, skb->data, NULL,&skb) != FW_ACCEPT) + if (call_fw_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) { + kfree_skb(skb, FREE_WRITE); return; + } if (!rose_link_up(neigh)) neigh->restarted = 0; @@ -295,7 +296,8 @@ if (neigh->t0timer == 0) { rose_transmit_restart_request(neigh); - neigh->t0timer = sysctl_rose_restart_request_timeout; + neigh->dce_mode = 0; + neigh->t0timer = sysctl_rose_restart_request_timeout; rose_link_set_timer(neigh); } } diff -u --recursive --new-file v2.1.41/linux/net/rose/rose_out.c linux/net/rose/rose_out.c --- v2.1.41/linux/net/rose/rose_out.c Sun Feb 2 05:18:52 1997 +++ linux/net/rose/rose_out.c Wed May 28 10:49:12 1997 @@ -1,8 +1,5 @@ /* - * Rose release 001 - * - * 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. + * ROSE release 002 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -13,7 +10,7 @@ * 2 of the License, or (at your option) any later version. * * History - * Rose 001 Jonathan(G4KLX) Cloned from nr_out.c + * ROSE 001 Jonathan(G4KLX) Cloned from nr_out.c */ #include @@ -41,7 +38,7 @@ #include /* - * This is where all Rose frames pass; + * This is where all ROSE frames pass; */ void rose_output(struct sock *sk, struct sk_buff *skb) { @@ -109,7 +106,7 @@ del_timer(&sk->timer); - end = (sk->protinfo.rose->va + ROSE_MAX_WINDOW_SIZE) % ROSE_MODULUS; + end = (sk->protinfo.rose->va + sysctl_rose_window_size) % ROSE_MODULUS; if (!(sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) && sk->protinfo.rose->vs != end && diff -u --recursive --new-file v2.1.41/linux/net/rose/rose_route.c linux/net/rose/rose_route.c --- v2.1.41/linux/net/rose/rose_route.c Thu Mar 27 14:40:17 1997 +++ linux/net/rose/rose_route.c Wed May 28 10:49:12 1997 @@ -1,8 +1,5 @@ /* - * Rose release 001 - * - * 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. + * ROSE release 002 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -13,9 +10,11 @@ * 2 of the License, or (at your option) any later version. * * History - * Rose 001 Jonathan(G4KLX) Cloned from nr_route.c. + * ROSE 001 Jonathan(G4KLX) Cloned from nr_route.c. * Terry(VK2KTJ) Added support for variable length * address masks. + * ROSE 002 Jonathan(G4KLX) Uprated through routing of packets. + * Routing loop detection. */ #include @@ -76,13 +75,14 @@ break; if (rose_neigh == NULL) { - if ((rose_neigh = (struct rose_neigh *)kmalloc(sizeof(*rose_neigh), GFP_ATOMIC)) == NULL) + if ((rose_neigh = kmalloc(sizeof(*rose_neigh), GFP_ATOMIC)) == NULL) return -ENOMEM; rose_neigh->callsign = rose_route->neighbour; rose_neigh->digipeat = NULL; rose_neigh->dev = dev; rose_neigh->count = 0; + rose_neigh->dce_mode = 0; rose_neigh->number = rose_neigh_no++; rose_neigh->restarted = 0; skb_queue_head_init(&rose_neigh->queue); @@ -92,7 +92,7 @@ if (rose_route->ndigis != 0) { if ((rose_neigh->digipeat = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) { - kfree_s(rose_neigh, sizeof(*rose_neigh)); + kfree(rose_neigh); return -ENOMEM; } rose_neigh->digipeat->ndigi = rose_route->ndigis; @@ -127,7 +127,7 @@ } /* create new node */ - if ((rose_node = (struct rose_node *)kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL) + if ((rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL) return -ENOMEM; rose_node->address = rose_route->address; @@ -183,7 +183,7 @@ if ((s = rose_node_list) == rose_node) { rose_node_list = rose_node->next; restore_flags(flags); - kfree_s(rose_node, sizeof(struct rose_node)); + kfree(rose_node); return; } @@ -191,7 +191,7 @@ if (s->next == rose_node) { s->next = rose_node->next; restore_flags(flags); - kfree_s(rose_node, sizeof(struct rose_node)); + kfree(rose_node); return; } @@ -219,8 +219,8 @@ rose_neigh_list = rose_neigh->next; restore_flags(flags); if (rose_neigh->digipeat != NULL) - kfree_s(rose_neigh->digipeat, sizeof(ax25_digi)); - kfree_s(rose_neigh, sizeof(struct rose_neigh)); + kfree(rose_neigh->digipeat); + kfree(rose_neigh); return; } @@ -229,8 +229,8 @@ s->next = rose_neigh->next; restore_flags(flags); if (rose_neigh->digipeat != NULL) - kfree_s(rose_neigh->digipeat, sizeof(ax25_digi)); - kfree_s(rose_neigh, sizeof(struct rose_neigh)); + kfree(rose_neigh->digipeat); + kfree(rose_neigh); return; } @@ -251,7 +251,7 @@ if ((s = rose_route_list) == rose_route) { rose_route_list = rose_route->next; restore_flags(flags); - kfree_s(rose_route, sizeof(struct rose_route)); + kfree(rose_route); return; } @@ -259,7 +259,7 @@ if (s->next == rose_route) { s->next = rose_route->next; restore_flags(flags); - kfree_s(rose_route, sizeof(struct rose_route)); + kfree(rose_route); return; } @@ -372,7 +372,7 @@ struct rose_route *s, *rose_route = rose_route_list; while (rose_route != NULL) { - s = rose_route; + s = rose_route; rose_route = rose_route->next; if (s->neigh1->dev == dev || s->neigh2->dev == dev) @@ -397,7 +397,7 @@ } /* - * Find the first active Rose device, usually "rose0". + * Find the first active ROSE device, usually "rose0". */ struct device *rose_dev_first(void) { @@ -412,7 +412,7 @@ } /* - * Find the Rose device for the given address. + * Find the ROSE device for the given address. */ struct device *rose_dev_get(rose_address *addr) { @@ -425,23 +425,34 @@ return NULL; } +struct rose_route *rose_route_free_lci(unsigned int lci, struct rose_neigh *neigh) +{ + struct rose_route *rose_route; + + for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) + if ((rose_route->neigh1 == neigh && rose_route->lci1 == lci) || + (rose_route->neigh2 == neigh && rose_route->lci2 == lci)) + return rose_route; + + return NULL; +} + /* - * Find a neighbour given a Rose address. + * Find a neighbour given a ROSE address. */ struct rose_neigh *rose_get_neigh(rose_address *addr) { struct rose_node *node; int i; - for (node = rose_node_list; node != NULL; node = node->next) - if (rosecmpm(addr, &node->address, node->mask) == 0) - break; - - if (node == NULL) return NULL; - - for (i = 0; i < node->count; i++) - if (node->neighbour[i]->ftimer == 0) - return node->neighbour[i]; + for (node = rose_node_list; node != NULL; node = node->next) { + if (rosecmpm(addr, &node->address, node->mask) == 0) { + for (i = 0; i < node->count; i++) { + if (node->neighbour[i]->ftimer == 0) + return node->neighbour[i]; + } + } + } return NULL; } @@ -485,14 +496,54 @@ return 0; } +static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh) +{ + struct rose_route *rose_route, *s; + struct sk_buff *skb; + + rose_neigh->restarted = 0; + rose_neigh->t0timer = 0; + rose_neigh->ftimer = sysctl_rose_link_fail_timeout; + + rose_link_set_timer(rose_neigh); + + while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL) + kfree_skb(skb, FREE_WRITE); + + rose_route = rose_route_list; + + while (rose_route != NULL) { + if ((rose_route->neigh1 == rose_neigh && rose_route->neigh2 == rose_neigh) || + (rose_route->neigh1 == rose_neigh && rose_route->neigh2 == NULL) || + (rose_route->neigh2 == rose_neigh && rose_route->neigh1 == NULL)) { + s = rose_route->next; + rose_remove_route(rose_route); + rose_route = s; + continue; + } + + if (rose_route->neigh1 == rose_neigh) { + rose_route->neigh1 = NULL; + rose_transmit_clear_request(rose_route->neigh2, rose_route->lci2, 0x0D); + } + + if (rose_route->neigh2 == rose_neigh) { + rose_route->neigh2 = NULL; + rose_transmit_clear_request(rose_route->neigh1, rose_route->lci1, 0x0D); + } + + rose_route = rose_route->next; + } +} + /* * A level 2 link has timed out, therefore it appears to be a poor link, - * then don't use that neighbour until it is reset. XXX others. + * then don't use that neighbour until it is reset. Blow away all through + * routes and connections using this route. */ void rose_link_failed(ax25_address *callsign, struct device *dev) { struct rose_neigh *rose_neigh; - struct sk_buff *skb; for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) if (ax25cmp(&rose_neigh->callsign, callsign) == 0 && rose_neigh->dev == dev) @@ -500,33 +551,22 @@ if (rose_neigh == NULL) return; - rose_neigh->restarted = 0; - rose_neigh->t0timer = 0; - rose_neigh->ftimer = sysctl_rose_link_fail_timeout; - - rose_link_set_timer(rose_neigh); - - while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL) - kfree_skb(skb, FREE_WRITE); + rose_del_route_by_neigh(rose_neigh); + rose_kill_by_neigh(rose_neigh); } /* - * A device has been "downed" remove its link status. XXX others. + * A device has been "downed" remove its link status. Blow away all + * through routes and connections that use this device. */ void rose_link_device_down(struct device *dev) { struct rose_neigh *rose_neigh; - struct sk_buff *skb; for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) { if (rose_neigh->dev == dev) { - rose_neigh->restarted = 0; - rose_neigh->t0timer = 0; - rose_neigh->ftimer = 0; - del_timer(&rose_neigh->timer); - - while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL) - kfree_skb(skb, FREE_WRITE); + rose_del_route_by_neigh(rose_neigh); + rose_kill_by_neigh(rose_neigh); } } } @@ -538,10 +578,11 @@ { struct rose_neigh *rose_neigh, *new_neigh; struct rose_route *rose_route; + struct rose_facilities facilities; rose_address *src_addr, *dest_addr; struct sock *sk; unsigned short frametype; - unsigned int lci; + unsigned int lci, new_lci; struct device *dev; unsigned long flags; @@ -577,7 +618,7 @@ /* * Find an existing socket. */ - if ((sk = rose_find_socket(lci, rose_neigh->dev)) != NULL) { + if ((sk = rose_find_socket(lci, rose_neigh)) != NULL) { skb->h.raw = skb->data; return rose_process_rx_frame(sk, skb); } @@ -597,29 +638,36 @@ /* * Route it to the next in line if we have an entry for it. */ - - /* - * We should check for the random number in the facilities - * here. XXX. - */ for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) { if (rose_route->lci1 == lci && rose_route->neigh1 == rose_neigh) { - skb->data[0] &= 0xF0; - skb->data[0] |= (rose_route->lci2 >> 8) & 0x0F; - skb->data[1] = (rose_route->lci2 >> 0) & 0xFF; - rose_transmit_link(skb, rose_route->neigh2); - if (frametype == ROSE_CLEAR_CONFIRMATION) - rose_remove_route(rose_route); - return 1; + if (rose_route->neigh2 != NULL) { + skb->data[0] &= 0xF0; + skb->data[0] |= (rose_route->lci2 >> 8) & 0x0F; + skb->data[1] = (rose_route->lci2 >> 0) & 0xFF; + rose_transmit_link(skb, rose_route->neigh2); + if (frametype == ROSE_CLEAR_CONFIRMATION) + rose_remove_route(rose_route); + return 1; + } else { + if (frametype == ROSE_CLEAR_CONFIRMATION) + rose_remove_route(rose_route); + return 0; + } } if (rose_route->lci2 == lci && rose_route->neigh2 == rose_neigh) { - skb->data[0] &= 0xF0; - skb->data[0] |= (rose_route->lci1 >> 8) & 0x0F; - skb->data[1] = (rose_route->lci1 >> 0) & 0xFF; - rose_transmit_link(skb, rose_route->neigh1); - if (frametype == ROSE_CLEAR_CONFIRMATION) - rose_remove_route(rose_route); - return 1; + if (rose_route->neigh1 != NULL) { + skb->data[0] &= 0xF0; + skb->data[0] |= (rose_route->lci1 >> 8) & 0x0F; + skb->data[1] = (rose_route->lci1 >> 0) & 0xFF; + rose_transmit_link(skb, rose_route->neigh1); + if (frametype == ROSE_CLEAR_CONFIRMATION) + rose_remove_route(rose_route); + return 1; + } else { + if (frametype == ROSE_CLEAR_CONFIRMATION) + rose_remove_route(rose_route); + return 0; + } } } @@ -631,20 +679,49 @@ if (frametype != ROSE_CALL_REQUEST) /* XXX */ return 0; + rose_parse_facilities(skb, &facilities); + + /* + * Check for routing loops. + */ + for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) { + if (rose_route->rand == facilities.rand && + rosecmp(src_addr, &rose_route->src_addr) == 0 && + ax25cmp(&facilities.dest_call, &rose_route->src_call) == 0 && + ax25cmp(&facilities.source_call, &rose_route->dest_call) == 0) { + printk(KERN_DEBUG "ROSE: routing loop from %s\n", rose2asc(src_addr)); + printk(KERN_DEBUG "ROSE: to %s\n", rose2asc(dest_addr)); + rose_transmit_clear_request(rose_neigh, lci, 0x0D); + return 0; + } + } + if ((new_neigh = rose_get_neigh(dest_addr)) == NULL) { + printk(KERN_DEBUG "ROSE: no route to %s\n", rose2asc(dest_addr)); rose_transmit_clear_request(rose_neigh, lci, 0x0D); return 0; } - if ((rose_route = (struct rose_route *)kmalloc(sizeof(*rose_route), GFP_ATOMIC)) == NULL) { + if ((new_lci = rose_new_lci(new_neigh)) == 0) { + printk(KERN_DEBUG "ROSE: no spare VCs to %s\n", rose2asc(dest_addr)); rose_transmit_clear_request(rose_neigh, lci, 0x0D); return 0; } - rose_route->lci1 = lci; - rose_route->neigh1 = rose_neigh; - rose_route->lci2 = rose_new_lci(new_neigh->dev); - rose_route->neigh2 = new_neigh; + if ((rose_route = kmalloc(sizeof(*rose_route), GFP_ATOMIC)) == NULL) { + rose_transmit_clear_request(rose_neigh, lci, 0x0D); + return 0; + } + + rose_route->lci1 = lci; + rose_route->src_addr = *src_addr; + rose_route->dest_addr = *dest_addr; + rose_route->src_call = facilities.dest_call; + rose_route->dest_call = facilities.source_call; + rose_route->rand = facilities.rand; + rose_route->neigh1 = rose_neigh; + rose_route->lci2 = new_lci; + rose_route->neigh2 = new_neigh; save_flags(flags); cli(); rose_route->next = rose_route_list; @@ -716,14 +793,15 @@ cli(); - len += sprintf(buffer, "addr callsign dev count restart t0 tf\n"); + len += sprintf(buffer, "addr callsign dev count mode restart t0 tf\n"); for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next) { - len += sprintf(buffer + len, "%05d %-9s %-4s %3d %3s %3d %3d\n", + len += sprintf(buffer + len, "%05d %-9s %-4s %3d %3s %3s %3d %3d\n", rose_neigh->number, ax2asc(&rose_neigh->callsign), rose_neigh->dev ? rose_neigh->dev->name : "???", rose_neigh->count, + (rose_neigh->dce_mode) ? "DCE" : "DTE", (rose_neigh->restarted) ? "yes" : "no", rose_neigh->t0timer / ROSE_SLOWHZ, rose_neigh->ftimer / ROSE_SLOWHZ); @@ -759,17 +837,28 @@ cli(); - len += sprintf(buffer, "lci callsign dev <-> lci callsign dev\n"); + len += sprintf(buffer, "lci address callsign neigh <-> lci address callsign neigh\n"); for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) { - len += sprintf(buffer + len, "%3.3X %-9s %-4s ", - rose_route->lci1, - ax2asc(&rose_route->neigh1->callsign), - rose_route->neigh1->dev ? rose_route->neigh1->dev->name : "???"); - len += sprintf(buffer + len, "%3.3X %-9s %-4s\n", - rose_route->lci2, - ax2asc(&rose_route->neigh2->callsign), - rose_route->neigh2->dev ? rose_route->neigh2->dev->name : "???"); + if (rose_route->neigh1 != NULL) { + len += sprintf(buffer + len, "%3.3X %-10s %-9s %05d ", + rose_route->lci1, + rose2asc(&rose_route->src_addr), + ax2asc(&rose_route->src_call), + rose_route->neigh1->number); + } else { + len += sprintf(buffer + len, "000 * * 00000 "); + } + + if (rose_route->neigh2 != NULL) { + len += sprintf(buffer + len, "%3.3X %-10s %-9s %05d\n", + rose_route->lci2, + rose2asc(&rose_route->dest_addr), + ax2asc(&rose_route->dest_call), + rose_route->neigh2->number); + } else { + len += sprintf(buffer + len, "000 * * 00000\n"); + } pos = begin + len; @@ -795,7 +884,7 @@ #ifdef MODULE /* - * Release all memory associated with Rose routing structures. + * Release all memory associated with ROSE routing structures. */ void rose_rt_free(void) { @@ -811,7 +900,7 @@ } while (rose_node != NULL) { - t = rose_node; + t = rose_node; rose_node = rose_node->next; rose_remove_node(t); diff -u --recursive --new-file v2.1.41/linux/net/rose/rose_subr.c linux/net/rose/rose_subr.c --- v2.1.41/linux/net/rose/rose_subr.c Sun Jan 19 05:47:29 1997 +++ linux/net/rose/rose_subr.c Wed May 28 10:49:12 1997 @@ -1,8 +1,5 @@ /* - * Rose release 001 - * - * 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. + * ROSE release 002 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -13,7 +10,7 @@ * 2 of the License, or (at your option) any later version. * * History - * Rose 001 Jonathan(G4KLX) Cloned from nr_subr.c + * ROSE 001 Jonathan(G4KLX) Cloned from nr_subr.c */ #include @@ -173,7 +170,7 @@ break; default: - printk(KERN_ERR "rose_write_internal: invalid frametype %02X\n", frametype); + printk(KERN_ERR "ROSE: rose_write_internal - invalid frametype %02X\n", frametype); kfree_skb(skb, FREE_WRITE); return; } @@ -227,7 +224,7 @@ return ROSE_ILLEGAL; } -static int rose_parse_national(unsigned char *p, rose_cb *rose, int len) +static int rose_parse_national(unsigned char *p, struct rose_facilities *facilities, int len) { unsigned char l, n = 0; @@ -241,7 +238,7 @@ case 0x40: if (*p == FAC_NATIONAL_RAND) - rose->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF); + facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF); p += 3; n += 3; len -= 3; @@ -256,12 +253,12 @@ case 0xC0: l = p[1]; if (*p == FAC_NATIONAL_DEST_DIGI) { - memcpy(&rose->source_digi, p + 2, AX25_ADDR_LEN); - rose->source_ndigis = 1; + memcpy(&facilities->source_digi, p + 2, AX25_ADDR_LEN); + facilities->source_ndigis = 1; } if (*p == FAC_NATIONAL_SRC_DIGI) { - memcpy(&rose->dest_digi, p + 2, AX25_ADDR_LEN); - rose->dest_ndigis = 1; + memcpy(&facilities->dest_digi, p + 2, AX25_ADDR_LEN); + facilities->dest_ndigis = 1; } p += l + 2; n += l + 2; @@ -273,7 +270,7 @@ return n; } -static int rose_parse_ccitt(unsigned char *p, rose_cb *rose, int len) +static int rose_parse_ccitt(unsigned char *p, struct rose_facilities *facilities, int len) { unsigned char l, n = 0; char callsign[11]; @@ -301,16 +298,16 @@ case 0xC0: l = p[1]; if (*p == FAC_CCITT_DEST_NSAP) { - memcpy(&rose->source_addr, p + 7, ROSE_ADDR_LEN); + memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN); memcpy(callsign, p + 12, l - 10); callsign[l - 10] = '\0'; - rose->source_call = *asc2ax(callsign); + facilities->source_call = *asc2ax(callsign); } if (*p == FAC_CCITT_SRC_NSAP) { - memcpy(&rose->dest_addr, p + 7, ROSE_ADDR_LEN); + memcpy(&facilities->dest_addr, p + 7, ROSE_ADDR_LEN); memcpy(callsign, p + 12, l - 10); callsign[l - 10] = '\0'; - rose->dest_call = *asc2ax(callsign); + facilities->dest_call = *asc2ax(callsign); } p += l + 2; n += l + 2; @@ -322,12 +319,12 @@ return n; } -int rose_parse_facilities(struct sk_buff *skb, rose_cb *rose) +int rose_parse_facilities(struct sk_buff *skb, struct rose_facilities *facilities) { int facilities_len, len; unsigned char *p; - memset(rose, 0x00, sizeof(rose_cb)); + memset(facilities, 0x00, sizeof(struct rose_facilities)); len = (((skb->data[3] >> 4) & 0x0F) + 1) / 2; len += (((skb->data[3] >> 0) & 0x0F) + 1) / 2; @@ -346,19 +343,19 @@ switch (*p) { case FAC_NATIONAL: /* National */ - len = rose_parse_national(p + 1, rose, facilities_len - 1); + len = rose_parse_national(p + 1, facilities, facilities_len - 1); facilities_len -= len + 1; p += len + 1; break; case FAC_CCITT: /* CCITT */ - len = rose_parse_ccitt(p + 1, rose, facilities_len - 1); + len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1); facilities_len -= len + 1; p += len + 1; break; default: - printk(KERN_DEBUG "rose_parse_facilities: unknown facilities family %02X\n", *p); + printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p); facilities_len--; p++; break; diff -u --recursive --new-file v2.1.41/linux/net/rose/rose_timer.c linux/net/rose/rose_timer.c --- v2.1.41/linux/net/rose/rose_timer.c Mon Apr 14 16:28:28 1997 +++ linux/net/rose/rose_timer.c Wed May 28 10:49:12 1997 @@ -1,8 +1,5 @@ /* - * Rose release 001 - * - * 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. + * ROSE release 002 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * @@ -13,7 +10,7 @@ * 2 of the License, or (at your option) any later version. * * History - * Rose 001 Jonathan(G4KLX) Cloned from nr_timer.c + * ROSE 001 Jonathan(G4KLX) Cloned from nr_timer.c */ #include @@ -61,7 +58,7 @@ } /* - * Rose Timer + * ROSE Timer * * This routine is called every 100ms. Decrement timer by this * amount - if expired then process the event. diff -u --recursive --new-file v2.1.41/linux/net/rose/sysctl_net_rose.c linux/net/rose/sysctl_net_rose.c --- v2.1.41/linux/net/rose/sysctl_net_rose.c Tue May 13 22:41:24 1997 +++ linux/net/rose/sysctl_net_rose.c Wed May 28 10:49:12 1997 @@ -1,5 +1,5 @@ /* -*- linux-c -*- - * sysctl_net_rose.c: sysctl interface to net Rose subsystem. + * sysctl_net_rose.c: sysctl interface to net ROSE subsystem. * * Begun April 1, 1996, Mike Shaver. * Added /proc/sys/net/rose directory entry (empty =) ). [MS] @@ -18,6 +18,8 @@ static int min_route[] = {0}, max_route[] = {1}; static int min_ftimer[] = {60 * ROSE_SLOWHZ}; static int max_ftimer[] = {600 * ROSE_SLOWHZ}; +static int min_maxvcs[] = {1}, max_maxvcs[] = {254}; +static int min_window[] = {1}, max_window[] = {7}; static struct ctl_table_header *rose_table_header; @@ -46,6 +48,12 @@ {NET_ROSE_LINK_FAIL_TIMEOUT, "link_fail_timeout", &sysctl_rose_link_fail_timeout, sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_ftimer, &max_ftimer}, + {NET_ROSE_MAX_VCS, "maximum_virtual_circuits", + &sysctl_rose_maximum_vcs, sizeof(int), 0644, NULL, + &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_maxvcs, &max_maxvcs}, + {NET_ROSE_WINDOW_SIZE, "window_size", + &sysctl_rose_window_size, sizeof(int), 0644, NULL, + &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_window, &max_window}, {0} }; diff -u --recursive --new-file v2.1.41/linux/net/x25/Makefile linux/net/x25/Makefile --- v2.1.41/linux/net/x25/Makefile Mon Apr 7 11:35:33 1997 +++ linux/net/x25/Makefile Wed May 28 10:49:12 1997 @@ -8,7 +8,8 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := x25.o -O_OBJS := af_x25.o x25_dev.o x25_in.o x25_link.o x25_out.o x25_route.o x25_subr.o x25_timer.o +O_OBJS := af_x25.o x25_dev.o x25_facilities.o x25_in.o x25_link.o x25_out.o \ + x25_route.o x25_subr.o x25_timer.o M_OBJS := $(O_TARGET) ifeq ($(CONFIG_SYSCTL),y) diff -u --recursive --new-file v2.1.41/linux/net/x25/af_x25.c linux/net/x25/af_x25.c --- v2.1.41/linux/net/x25/af_x25.c Tue May 13 22:41:25 1997 +++ linux/net/x25/af_x25.c Wed May 28 10:49:12 1997 @@ -60,6 +60,8 @@ static struct proto_ops x25_proto_ops; +static x25_address null_x25_address = {" "}; + int x25_addr_ntoa(unsigned char *p, x25_address *called_addr, x25_address *calling_addr) { int called_len, calling_len; @@ -116,16 +118,16 @@ if (i % 2 != 0) { *p |= (*called++ - '0') << 0; p++; - *p = 0x00; } else { + *p = 0x00; *p |= (*called++ - '0') << 4; } } else { if (i % 2 != 0) { *p |= (*calling++ - '0') << 0; p++; - *p = 0x00; } else { + *p = 0x00; *p |= (*calling++ - '0') << 4; } } @@ -239,7 +241,9 @@ cli(); for (s = x25_list; s != NULL; s = s->next) { - if (strcmp(s->protinfo.x25->source_addr.x25_addr, addr->x25_addr) == 0 && s->state == TCP_LISTEN) { + if ((strcmp(addr->x25_addr, s->protinfo.x25->source_addr.x25_addr) == 0 || + strcmp(addr->x25_addr, null_x25_address.x25_addr) == 0) && + s->state == TCP_LISTEN) { restore_flags(flags); return s; } @@ -337,7 +341,7 @@ sk->timer.data = (unsigned long)sk; add_timer(&sk->timer); } else { - kfree_s(sk->protinfo.x25, sizeof(*sk->protinfo.x25)); + kfree(sk->protinfo.x25); sk_free(sk); MOD_DEC_USE_COUNT; } @@ -430,7 +434,7 @@ if ((sk = sk_alloc(GFP_ATOMIC)) == NULL) return NULL; - if ((x25 = (x25_cb *)kmalloc(sizeof(*x25), GFP_ATOMIC)) == NULL) { + if ((x25 = kmalloc(sizeof(*x25), GFP_ATOMIC)) == NULL) { sk_free(sk); return NULL; } @@ -601,7 +605,9 @@ x25_insert_socket(sk); sk->zapped = 0; + SOCK_DEBUG(sk, "x25_bind: socket is bound\n"); + return 0; } @@ -642,6 +648,9 @@ if (sk->zapped) /* Must bind first - autobinding does not work */ return -EINVAL; + if (strcmp(sk->protinfo.x25->source_addr.x25_addr, null_x25_address.x25_addr) == 0) + memset(&sk->protinfo.x25->source_addr, '\0', X25_ADDR_LEN); + sk->protinfo.x25->dest_addr = addr->sx25_addr; sk->protinfo.x25->lci = x25_new_lci(); @@ -662,7 +671,7 @@ cli(); /* To avoid races on the sleep */ /* - * A Connect Ack with Choke or timeout or failed routing will go to closed. + * A Clear Request or timeout or failed routing will go to closed. */ while (sk->state == TCP_SYN_SENT) { interruptible_sleep_on(sk->sleep); @@ -767,6 +776,7 @@ struct sock *make; x25_address source_addr, dest_addr; struct x25_facilities facilities; + int len; /* * Remove the LCI and frame type. @@ -787,16 +797,31 @@ /* * We can't accept the Call Request. */ - if (sk == NULL || sk->ack_backlog == sk->max_ack_backlog || (make = x25_make_new(sk)) == NULL) { + if (sk == NULL || sk->ack_backlog == sk->max_ack_backlog) { + x25_transmit_clear_request(neigh, lci, 0x01); + return 0; + } + + /* + * Try to reach a compromise on the requested facilities. + */ + if ((len = x25_negotiate_facilities(skb, sk, &facilities)) == -1) { + x25_transmit_clear_request(neigh, lci, 0x01); + return 0; + } + + /* + * Try to create a new socket. + */ + if ((make = x25_make_new(sk)) == NULL) { x25_transmit_clear_request(neigh, lci, 0x01); return 0; } /* - * Parse the facilities, and remove them, leaving any Call User - * Data. + * Remove the facilities, leaving any Call User Data. */ - skb_pull(skb, x25_parse_facilities(skb, &facilities)); + skb_pull(skb, len); skb->sk = make; make->state = TCP_ESTABLISHED; @@ -805,11 +830,6 @@ make->protinfo.x25->dest_addr = dest_addr; make->protinfo.x25->source_addr = source_addr; make->protinfo.x25->neighbour = neigh; - - /* - * This implies that we accept all the incoming facilities - * values (if any). This needs fixing. XXX - */ make->protinfo.x25->facilities = facilities; x25_write_internal(make, X25_CALL_ACCEPTED); @@ -883,10 +903,12 @@ sx25.sx25_family = AF_X25; sx25.sx25_addr = sk->protinfo.x25->dest_addr; } + SOCK_DEBUG(sk, "x25_sendmsg: sendto: Addresses built.\n"); /* Build a packet */ SOCK_DEBUG(sk, "x25_sendmsg: sendto: building packet.\n"); + if ((msg->msg_flags & MSG_OOB) && len > 32) len = 32; @@ -901,8 +923,8 @@ * Put the data on the end */ SOCK_DEBUG(sk, "x25_sendmsg: Copying user data\n"); - skb->h.raw = skb_put(skb, len); - asmptr = skb->h.raw; + + asmptr = skb->h.raw = skb_put(skb, len); memcpy_fromiovec(asmptr, msg->msg_iov, len); @@ -919,6 +941,7 @@ * Push down the X.25 header */ SOCK_DEBUG(sk, "x25_sendmsg: Building X.25 Header.\n"); + if (msg->msg_flags & MSG_OOB) { if (sk->protinfo.x25->neighbour->extended) { asmptr = skb_push(skb, X25_STD_MIN_LEN); @@ -950,6 +973,7 @@ if (qbit) skb->data[0] |= X25_Q_BIT; } + SOCK_DEBUG(sk, "x25_sendmsg: Built header.\n"); SOCK_DEBUG(sk, "x25_sendmsg: Transmitting buffer\n"); @@ -1078,7 +1102,7 @@ case SIOCGSTAMP: if (sk != NULL) { - if (sk->stamp.tv_sec==0) + if (sk->stamp.tv_sec == 0) return -ENOENT; if ((err = verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval))) != 0) return err; @@ -1270,12 +1294,6 @@ 0, &proc_net_inode_operations, x25_get_info }; -static struct proc_dir_entry proc_net_x25_links = { - PROC_NET_X25_LINKS, 9, "x25_links", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_net_inode_operations, - x25_link_get_info -}; static struct proc_dir_entry proc_net_x25_routes = { PROC_NET_X25_ROUTES, 10, "x25_routes", S_IFREG | S_IRUGO, 1, 0, 0, @@ -1301,7 +1319,6 @@ #ifdef CONFIG_PROC_FS proc_net_register(&proc_net_x25); - proc_net_register(&proc_net_x25_links); proc_net_register(&proc_net_x25_routes); #endif } @@ -1309,6 +1326,9 @@ #ifdef MODULE EXPORT_NO_SYMBOLS; +MODULE_AUTHOR("Jonathan Naylor "); +MODULE_DESCRIPTION("The X.25 Packet Layer network layer protocol"); + int init_module(void) { struct device *dev; @@ -1334,7 +1354,6 @@ #ifdef CONFIG_PROC_FS proc_net_unregister(PROC_NET_X25); - proc_net_unregister(PROC_NET_X25_LINKS); proc_net_unregister(PROC_NET_X25_ROUTES); #endif diff -u --recursive --new-file v2.1.41/linux/net/x25/x25_facilities.c linux/net/x25/x25_facilities.c --- v2.1.41/linux/net/x25/x25_facilities.c Wed Dec 31 16:00:00 1969 +++ linux/net/x25/x25_facilities.c Wed May 28 10:49:12 1997 @@ -0,0 +1,203 @@ +/* + * X.25 Packet Layer release 001 + * + * 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 + * + * 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 + * X.25 001 Split from x25_subr.c + */ + +#include +#if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Parse a set of facilities into the facilities structure. Unrecognised + * facilities are written to the debug log file. + */ +int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities) +{ + unsigned int len; + unsigned char *p = skb->data; + + len = *p++; + + while (len > 0) { + switch (*p & X25_FAC_CLASS_MASK) { + case X25_FAC_CLASS_A: + switch (*p) { + case X25_FAC_REVERSE: + facilities->reverse = (p[1] & 0x01); + break; + case X25_FAC_THROUGHPUT: + facilities->throughput = p[1]; + break; + default: + printk(KERN_DEBUG "X.25: unknown facility %02X, value %02X\n", p[0], p[1]); + break; + } + p += 2; + len -= 2; + break; + + case X25_FAC_CLASS_B: + switch (*p) { + case X25_FAC_PACKET_SIZE: + facilities->pacsize_in = p[1]; + facilities->pacsize_out = p[2]; + break; + case X25_FAC_WINDOW_SIZE: + facilities->winsize_in = p[1]; + facilities->winsize_out = p[2]; + break; + default: + printk(KERN_DEBUG "X.25: unknown facility %02X, values %02X, %02X\n", p[0], p[1], p[2]); + break; + } + p += 3; + len -= 3; + break; + + case X25_FAC_CLASS_C: + printk(KERN_DEBUG "X.25: unknown facility %02X, values %02X, %02X, %02X\n", p[0], p[1], p[2], p[3]); + p += 4; + len -= 4; + break; + + case X25_FAC_CLASS_D: + printk(KERN_DEBUG "X.25: unknown facility %02X, length %d, values %02X, %02X, %02X, %02X\n", p[0], p[1], p[2], p[3], p[4], p[5]); + p += p[1] + 2; + len -= p[1] + 2; + break; + } + } + + return p - skb->data; +} + +/* + * Create a set of facilities. + */ +int x25_create_facilities(unsigned char *buffer, struct x25_facilities *facilities) +{ + unsigned char *p = buffer + 1; + int len; + + if (facilities->reverse != 0) { + *p++ = X25_FAC_REVERSE; + *p++ = (facilities->reverse) ? 0x01 : 0x00; + } + + if (facilities->throughput != 0) { + *p++ = X25_FAC_THROUGHPUT; + *p++ = facilities->throughput; + } + + if (facilities->pacsize_in != 0 || facilities->pacsize_out != 0) { + *p++ = X25_FAC_PACKET_SIZE; + *p++ = (facilities->pacsize_in == 0) ? facilities->pacsize_out : facilities->pacsize_in; + *p++ = (facilities->pacsize_out == 0) ? facilities->pacsize_in : facilities->pacsize_out; + } + + if (facilities->winsize_in != 0 || facilities->winsize_out != 0) { + *p++ = X25_FAC_WINDOW_SIZE; + *p++ = (facilities->winsize_in == 0) ? facilities->winsize_out : facilities->winsize_in; + *p++ = (facilities->winsize_out == 0) ? facilities->winsize_in : facilities->winsize_out; + } + + len = p - buffer; + buffer[0] = len - 1; + + return len; +} + +/* + * Try to reach a compromise on a set of facilities. + * + * The only real problem is with reverse charging. + */ +int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, struct x25_facilities *new) +{ + struct x25_facilities *ours; + struct x25_facilities theirs; + int len; + + memset(&theirs, 0x00, sizeof(struct x25_facilities)); + + ours = &sk->protinfo.x25->facilities; + + *new = *ours; + + len = x25_parse_facilities(skb, &theirs); + + /* + * They want reverse charging, we won't accept it. + */ + if (theirs.reverse != 0 && ours->reverse == 0) { + SOCK_DEBUG(sk, "X.25: rejecting reverse charging request"); + return -1; + } + + new->reverse = theirs.reverse; + + if (theirs.throughput != 0) { + if (theirs.throughput < ours->throughput) { + SOCK_DEBUG(sk, "X.25: throughput negotiated down"); + new->throughput = theirs.throughput; + } + } + + if (theirs.pacsize_in != 0 && theirs.pacsize_out != 0) { + if (theirs.pacsize_in < ours->pacsize_in) { + SOCK_DEBUG(sk, "X.25: packet size inwards negotiated down"); + new->pacsize_in = theirs.pacsize_in; + } + if (theirs.pacsize_out < ours->pacsize_out) { + SOCK_DEBUG(sk, "X.25: packet size outwards negotiated down"); + new->pacsize_out = theirs.pacsize_out; + } + } + + if (theirs.winsize_in != 0 && theirs.winsize_out != 0) { + if (theirs.winsize_in < ours->winsize_in) { + SOCK_DEBUG(sk, "X.25: window size inwards negotiated down"); + new->winsize_in = theirs.winsize_in; + } + if (theirs.winsize_out < ours->winsize_out) { + SOCK_DEBUG(sk, "X.25: window size outwards negotiated down"); + new->winsize_out = theirs.winsize_out; + } + } + + return len; +} + +#endif diff -u --recursive --new-file v2.1.41/linux/net/x25/x25_in.c linux/net/x25/x25_in.c --- v2.1.41/linux/net/x25/x25_in.c Thu Feb 27 10:57:32 1997 +++ linux/net/x25/x25_in.c Wed May 28 10:49:12 1997 @@ -84,7 +84,6 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype) { x25_address source_addr, dest_addr; - struct x25_facilities facilities; switch (frametype) { @@ -102,9 +101,8 @@ */ skb_pull(skb, X25_STD_MIN_LEN); skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr)); - skb_pull(skb, x25_parse_facilities(skb, &facilities)); + skb_pull(skb, x25_parse_facilities(skb, &sk->protinfo.x25->facilities)); /* - * Facilities XXX * Copy any Call User Data. */ if (skb->len >= 0) { @@ -128,7 +126,6 @@ break; default: - printk(KERN_WARNING "x25: unknown %02X in state 1\n", frametype); break; } @@ -158,7 +155,6 @@ break; default: - printk(KERN_WARNING "x25: unknown %02X in state 2\n", frametype); break; } @@ -334,7 +330,6 @@ break; default: - printk(KERN_WARNING "x25: unknown %02X in state 4\n", frametype); break; } diff -u --recursive --new-file v2.1.41/linux/net/x25/x25_link.c linux/net/x25/x25_link.c --- v2.1.41/linux/net/x25/x25_link.c Thu Mar 27 14:40:18 1997 +++ linux/net/x25/x25_link.c Wed May 28 10:49:12 1997 @@ -110,7 +110,7 @@ break; case X25_DIAGNOSTIC: - printk(KERN_WARNING "x25: diagnostic #%d\n", skb->data[3]); + printk(KERN_WARNING "x25: diagnostic #%d - %02X %02X %02X\n", skb->data[3], skb->data[4], skb->data[5], skb->data[6]); break; default: @@ -240,8 +240,10 @@ void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *neigh) { - if (call_fw_firewall(PF_X25, skb->dev, skb->data, NULL,&skb) != FW_ACCEPT) + if (call_fw_firewall(PF_X25, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) { + kfree_skb(skb, FREE_WRITE); return; + } switch (neigh->state) { case X25_LINK_STATE_0: @@ -294,7 +296,7 @@ struct x25_neigh *x25_neigh; unsigned long flags; - if ((x25_neigh = (struct x25_neigh *)kmalloc(sizeof(*x25_neigh), GFP_ATOMIC)) == NULL) + if ((x25_neigh = kmalloc(sizeof(*x25_neigh), GFP_ATOMIC)) == NULL) return; skb_queue_head_init(&x25_neigh->queue); @@ -329,7 +331,7 @@ if ((s = x25_neigh_list) == x25_neigh) { x25_neigh_list = x25_neigh->next; restore_flags(flags); - kfree_s(x25_neigh, sizeof(struct x25_neigh)); + kfree(x25_neigh); return; } @@ -337,7 +339,7 @@ if (s->next == x25_neigh) { s->next = x25_neigh->next; restore_flags(flags); - kfree_s(x25_neigh, sizeof(struct x25_neigh)); + kfree(x25_neigh); return; } @@ -419,46 +421,6 @@ return 0; } - -int x25_link_get_info(char *buffer, char **start, off_t offset, int length, int dummy) -{ - struct x25_neigh *x25_neigh; - int len = 0; - off_t pos = 0; - off_t begin = 0; - - cli(); - - len += sprintf(buffer, "device st t20 ext\n"); - - for (x25_neigh = x25_neigh_list; x25_neigh != NULL; x25_neigh = x25_neigh->next) { - len += sprintf(buffer + len, "%-6s %2d %3d/%03d %d\n", - x25_neigh->dev->name, - x25_neigh->state, - x25_neigh->t20timer / X25_SLOWHZ, - x25_neigh->t20 / X25_SLOWHZ, - x25_neigh->extended); - - 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 diff -u --recursive --new-file v2.1.41/linux/net/x25/x25_route.c linux/net/x25/x25_route.c --- v2.1.41/linux/net/x25/x25_route.c Sun Jan 19 05:47:30 1997 +++ linux/net/x25/x25_route.c Wed May 28 10:49:12 1997 @@ -59,7 +59,7 @@ if (memcmp(&x25_route->address, address, sigdigits) == 0 && x25_route->sigdigits == sigdigits) return -EINVAL; - if ((x25_route = (struct x25_route *)kmalloc(sizeof(*x25_route), GFP_ATOMIC)) == NULL) + if ((x25_route = kmalloc(sizeof(*x25_route), GFP_ATOMIC)) == NULL) return -ENOMEM; strcpy(x25_route->address.x25_addr, "000000000000000"); @@ -87,7 +87,7 @@ if ((s = x25_route_list) == x25_route) { x25_route_list = x25_route->next; restore_flags(flags); - kfree_s(x25_route, sizeof(struct x25_route)); + kfree(x25_route); return; } @@ -95,7 +95,7 @@ if (s->next == x25_route) { s->next = x25_route->next; restore_flags(flags); - kfree_s(x25_route, sizeof(struct x25_route)); + kfree(x25_route); return; } diff -u --recursive --new-file v2.1.41/linux/net/x25/x25_subr.c linux/net/x25/x25_subr.c --- v2.1.41/linux/net/x25/x25_subr.c Sun Jan 19 05:47:30 1997 +++ linux/net/x25/x25_subr.c Wed May 28 10:49:12 1997 @@ -281,106 +281,4 @@ return X25_ILLEGAL; } -/* - * Parse a set of facilities into the facilities structure. Unrecognised - * facilities are written to the debug log file. - */ -int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities) -{ - unsigned int len; - unsigned char *p = skb->data; - - memset(facilities, 0x00, sizeof(struct x25_facilities)); - - len = *p++; - - while (len > 0) { - switch (*p & X25_FAC_CLASS_MASK) { - case X25_FAC_CLASS_A: - switch (*p) { - case X25_FAC_REVERSE: - facilities->reverse = (p[1] & 0x01); - break; - case X25_FAC_THROUGHPUT: - facilities->throughput = p[1]; - break; - default: - printk(KERN_DEBUG "X.25: unknown facility %02X, value %02X\n", p[0], p[1]); - break; - } - p += 2; - len -= 2; - break; - - case X25_FAC_CLASS_B: - switch (*p) { - case X25_FAC_PACKET_SIZE: - facilities->pacsize_in = p[1]; - facilities->pacsize_out = p[2]; - break; - case X25_FAC_WINDOW_SIZE: - facilities->winsize_in = p[1]; - facilities->winsize_out = p[2]; - break; - default: - printk(KERN_DEBUG "X.25: unknown facility %02X, values %02X, %02X\n", p[0], p[1], p[2]); - break; - } - p += 3; - len -= 3; - break; - - case X25_FAC_CLASS_C: - printk(KERN_DEBUG "X.25: unknown facility %02X, values %02X, %02X, %02X\n", p[0], p[1], p[2], p[3]); - p += 4; - len -= 4; - break; - - case X25_FAC_CLASS_D: - printk(KERN_DEBUG "X.25: unknown facility %02X, length %d, values %02X, %02X, %02X, %02X\n", p[0], p[1], p[2], p[3], p[4], p[5]); - p += p[1] + 2; - len -= p[1] + 2; - break; - } - } - - return p - skb->data; -} - -/* - * Create a set of facilities. - */ -int x25_create_facilities(unsigned char *buffer, struct x25_facilities *facilities) -{ - unsigned char *p = buffer + 1; - int len; - - if (facilities->reverse != 0) { - *p++ = X25_FAC_REVERSE; - *p++ = (facilities->reverse) ? 0x01 : 0x00; - } - - if (facilities->throughput != 0) { - *p++ = X25_FAC_THROUGHPUT; - *p++ = facilities->throughput; - } - - if (facilities->pacsize_in != 0 || facilities->pacsize_out != 0) { - *p++ = X25_FAC_PACKET_SIZE; - *p++ = (facilities->pacsize_in == 0) ? facilities->pacsize_out : facilities->pacsize_in; - *p++ = (facilities->pacsize_out == 0) ? facilities->pacsize_in : facilities->pacsize_out; - } - - if (facilities->winsize_in != 0 || facilities->winsize_out != 0) { - *p++ = X25_FAC_WINDOW_SIZE; - *p++ = (facilities->winsize_in == 0) ? facilities->winsize_out : facilities->winsize_in; - *p++ = (facilities->winsize_out == 0) ? facilities->winsize_in : facilities->winsize_out; - } - - len = p - buffer; - buffer[0] = len - 1; - - return len; -} - #endif