Taken under CVS control

This commit is contained in:
Fritz Elfert 1996-04-28 12:25:50 +00:00
parent 35eacd14a3
commit d06a7653be
29 changed files with 6201 additions and 0 deletions

View File

@ -0,0 +1,45 @@
I want to thank all who contributed to this project and especially to:
(in alphabetical order)
Thomas Bogendörfer (tsbogend@bigbug.franken.de)
Tester, lots of bugfixes and hints.
Alan Cox (alan@cymru.net)
For help getting into standard-kernel.
Volker Götz (volker@oops.franken.de)
For contribution of man-pages, the imontty-tool and a perfect
maintaining of the mailing-list at hub-wue.
Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
For his Sync-PPP-code.
Karsten Keil (isdn4@temic-ech.spacenet.de)
For adding 1TR6-support to the Teles-driver.
Michael Knigge (knick@cove.han.de)
For contributing the imon-tool
Andreas Kool (akool@Kool.f.EUnet.de)
For contribution of the isdnlog/isdnrep-tool
Pedro Roque Marques (roque@di.fc.ul.pt)
For lot of new ideas and the pcbit driver.
Eberhard Moenkeberg (emoenke@gwdg.de)
For testing and help to get into kernel.
Jan den Ouden (denouden@groovin.xs4all.nl)
For contribution of the teles-driver
Max Riegel (riegel@max.franken.de)
For making the ICN hardware-documentation and test-equipment available.
Gerhard 'Fido' Schneider (fido@wuff.franken.de)
For heavy-duty-beta-testing with his BBS ;)
Thomas Uhl (uhl@hn-net.de)
For distributing the cards.
For pushing me to work ;-)

View File

@ -0,0 +1,609 @@
Description of the Interface between Linklevel and Hardwarelevel
of isdn4linux:
The Communication between Linklevel (LL) and Hardwarelevel (HL)
is based on the struct isdn_if (defined in isdnif.h).
An HL-driver can register itself at LL by calling the function
register_isdn() with a pointer to that struct. Prior to that, it has
to preset some of the fields of isdn_if. The LL sets the rest of
the fields. All further communication is done via callbacks using
the function-pointers defined in isdn_if.
ATTENTION, CHANGES since version 0.6 are marked with "***CHANGE0.6"!
ATTENTION, CHANGES since version 0.7 are marked with "***CHANGE0.7"!
ATTENTION, CHANGES since version 0.71 are marked with "***CHANGE0.7.1"!
1. Description of the fields of isdn_if:
int channels;
This field has to be set by the HL-driver to the number of channels
supported prior to calling register_isdn(). Upon return of the call,
the LL puts an id there, which has to be used by the HL-driver when
invoking the other callbacks.
int maxbufsize;
***CHANGE0.6: New since this version.
Also to be preset by the HL-driver. With this value the HL-driver
tells to the LL the maximum size of a data-packet it will accept.
unsigned long features;
To be preset by the HL-driver. Using this field, the HL-driver
announces the features supported. At the moment this is limited to
report the supported layer2 and layer3-protocols. For setting this
field the constants ISDN_FEATURE..., declared in isdnif.h have to be
used.
***CHANGE0.7.1: The line type (1TR6, EDSS1) has to be set.
unsigned short hl_hdrlen;
***CHANGED.7.4: New field.
To be preset by the HL-driver, if it supports sk_buff's. The driver
should put here the amount of additional space needed in sk-buff's for
it's internal purposes. Drivers not supporting sk_buff's should put
initialize this field to 0.
void (*rcvcallb)(int, int, u_char*, int);
This field will be set by LL. The HL-driver delivers received data-
packets by calling this function.
Parameter:
int driver-Id
int Channel-number locally to the driver. (starting with 0)
u_char Pointer to received data. (in kernel-space)
int length of data-packet.
void (*rcvcallb_skb)(int, int, struct sk_buff *)
***CHANGED.7.4: New field.
This field will be set by LL. The HL-driver delivers received data-
packets by calling this function. Upon calling, the HL-driver must
already have it's private data pulled off the head of the sk_buff.
Parameter:
int driver-Id
int Channel-number locally to the driver. (starting with 0)
struct sk_buff * Pointer to sk_buff, containing received data.
int (*statcallb)(isdn_ctrl*);
This field will be set by LL. This function has to be called by the
HL-driver for signaling status-changes or other events to the LL.
Parameter:
isdn_ctrl*
The struct isdn_ctrl also defined in isdn_if. The exact meaning of it's
fields is described together with the descriptions of the possible
events. Here is only a short description of the fields:
driver = driver Id.
command = event-type. (one of the constants ISDN_STAT_...)
arg = depends on event-type.
num = depends on event-type.
Returnvalue:
0 on success, else -1
int (*command)(isdn_ctrl*);
This field has to be preset by the HL-driver. It points to a function,
to be called by LL to perform functions like dialing, B-channel
setup, etc. The exact meaning of the parameters is described with the
descriptions of the possible commands.
Parameter:
isdn_ctrl*
driver = driver-Id
command = command to perform. (one of the constants ISDN_CMD_...)
arg = depends on command.
num = depends on command.
Returnvalue:
>=0 on success, else error-code (-ENODEV etc.)
int (*writebuf)(int, int, u_char*, int, int);
This field has to be preset by the HL-driver. The given function will
be called by the LL for delivering data to be send via B-Channel.
Parameter:
int driver-Id ***CHANGE.7.4: New parameter.
int channel-number locally to the HL-driver. (starts with 0)
u_char* pointer to data.
int length of data-packet.
int flag: 0 = call from within kernel-space. (HL-driver must use
memcpy, may NOT use schedule())
1 = call from user-space. (HL-driver must use
memcpy_fromfs, use of schedule() allowed)
Returnvalue:
Length of data accepted on success, else error-code (-EINVAL on
oversized packets etc.)
int (*writebuf_skb)(int, int, struct sk_buff *)
***CHANGED.7.4: New field.
This field has to be preset by the HL-driver. The given function will
be called by the LL for delivering data to be send via B-Channel.
Parameter:
int driver-Id ***CHANGE.7.4: New parameter.
int channel-number locally to the HL-driver. (starts with 0)
struct sk_buff * Pointer to sk_buff containing data to be send via
B-channel.
Returnvalue:
Length of data accepted on success, else error-code (-EINVAL on
oversized packets etc.)
NOTE on writebuf and writebuf_skb:
The HL-driver may initialize one of the fields to NULL, in which case
the LL will call the non-NULL function only.
int (*writecmd)(u_char*, int, int);
This field has to be preset by the HL-driver. The given function will be
called to perform write-requests on /dev/isdnctrl (i.e. sending commands
to the card) The data-format is hardware-specific. This function is
intended for debugging only. It is not necessary for normal operation
and never will be called by the tty-emulation- or network-code. If
this function is not supported, the driver has to set NULL here.
Parameter:
u_char* pointer to data.
int length of data.
int flag: 0 = call from within kernel-space. (HL-driver must use
memcpy, may NOT use schedule())
1 = call from user-space. (HL-driver must use
memcpy_fromfs, use of schedule() allowed)
Returnvalue:
Length of data accepted on success, else error-code (-EINVAL etc.)
int (*readstat)(u_char*, int, int);
This field has to be preset by the HL-driver. The given function will be
called to perform read-requests on /dev/isdnctrl (i.e. reading replies
from the card) The data-format is hardware-specific. This function is
intended for debugging only. It is not necessary for normal operation
and never will be called by the tty-emulation- or network-code. If
this function is not supported, the driver has to set NULL here.
Parameter:
u_char* pointer to data.
int length of data.
int flag: 0 = call from within kernel-space. (HL-driver must use
memcpy, may NOT use schedule())
1 = call from user-space. (HL-driver must use
memcpy_fromfs, use of schedule() allowed)
Returnvalue:
Length of data on success, else error-code (-EINVAL etc.)
char id[20];
***CHANGE0.7: New since this version.
This string has to be preset by the HL-driver. It's purpose is for
identification of the driver by the user. Eg.: it is shown in the
status-info of /dev/isdninfo. Furthermore it is used as Id for binding
net-interfaces to a specific channel. If a string of length zero is
given, upon return, isdn4linux will replace it by a generic name. (line0,
line1 etc.) It is recommended to make this string configurable during
module-load-time. (copy a global variable to this string.) For doing that,
modules 1.2.8 or newer are necessary.
2. Description of the commands, a HL-driver has to support:
All commands will be performed by calling the function command() described
above from within the LL. The field command of the struct-parameter will
contain the desired command, the field driver always is set to the
appropriate driver-Id.
Until now, the following commands are defined:
ISDN_CMD_IOCTL:
This command is intended for performing ioctl-calls for configuring
hardware or similar purposes (setting port-addresses, loading firmware
etc.) For this purpose, in the LL all ioctl-calls with an argument
>= ISDN_IOCTL_DRVIOCTL (0x100) will be handed transparently to this
function after subtracting 0x100 and placing the result in arg.
Example:
If a userlevel-program calls ioctl(0x101,...) the function gets
called with the field command set to 1.
Parameter:
driver = driver-Id.
command = ISDN_CMD_IOCTL
arg = Original ioctl-cmd - ISDN_IOCTL_DRVIOCTL
num = first bytes filled with (unsigned long)arg
Returnvalue:
Depending on driver.
ISDN_CMD_DIAL:
This command is used to tell the HL-driver it should dial a given
number.
Parameter:
driver = driver-Id.
command = ISDN_CMD_DIAL
arg = channel-number locally to the driver. (starting with 0)
num = An ASCII-String containing the number to dial, the own
EAZ or MSN, the Service-Indicator and the Additional
Info. Format:
"%s,%s,%d,%d" RemotePhoneNumber,EazOrMsn,SI,AI
If the Line has been designed as SPV (a special german
feature, meaning semi-leased-line) the number has to
start with an "S".
***CHANGE0.6: In previous versions the EAZ has been given in the
highbyte of arg.
***CHANGE0.7.1: New since this version: ServiceIndicator and AddInfo.
ISDN_CMD_ACCEPTD:
With this command, the HL-driver is told to accept a D-Channel-setup.
(Response to an incoming call)
Parameter:
driver = driver-Id.
command = ISDN_CMD_ACCEPTD
arg = channel-number locally to the driver. (starting with 0)
num = unused.
ISDN_CMD_ACCEPTB:
With this command, the HL-driver is told to perform a B-Channel-setup.
(after establishing D-Channel-Connection)
Parameter:
driver = driver-Id.
command = ISDN_CMD_ACCEPTB
arg = channel-number locally to the driver. (starting with 0)
num = unused.
ISDN_CMD_HANGUP:
With this command, the HL-driver is told to hangup (B-Channel if
established first, then D-Channel). This command is also used for
actively rejecting an incoming call.
Parameter:
driver = driver-Id.
command = ISDN_CMD_HANGUP
arg = channel-number locally to the driver. (starting with 0)
num = unused.
ISDN_CMD_CLREAZ:
With this command, the HL-driver is told not to signal incoming
calls to the LL.
Parameter:
driver = driver-Id.
command = ISDN_CMD_CLREAZ
arg = channel-number locally to the driver. (starting with 0)
num = unused.
ISDN_CMD_SETEAZ:
With this command, the HL-driver is told to signal incoming calls for
the given EAZs/MSNs to the LL.
Parameter:
driver = driver-Id.
command = ISDN_CMD_SETEAZ
arg = channel-number locally to the driver. (starting with 0)
num = ASCII-String, containing the desired EAZ's/MSN's
(comma-separated). If an empty String is given, the
HL-driver should respond to ALL incoming calls,
regardless of the destination-address.
***CHANGE0.6: New since this version the "empty-string"-feature.
ISDN_CMD_GETEAZ: (currently unused)
With this command, the HL-driver is told to report the current setting
given with ISDN_CMD_SETEAZ.
Parameter:
driver = driver-Id.
command = ISDN_CMD_GETEAZ
arg = channel-number locally to the driver. (starting with 0)
num = ASCII-String, containing the current EAZ's/MSN's
ISDN_CMD_SETSIL: (currently unused)
With this command, the HL-driver is told to signal only incoming
calls with the given Service-Indicators.
Parameter:
driver = driver-Id.
command = ISDN_CMD_SETSIL
arg = channel-number locally to the driver. (starting with 0)
num = ASCII-String, containing the desired Service-Indicators.
ISDN_CMD_GETSIL: (currently unused)
With this command, the HL-driver is told to return the current
Service-Indicators it will respond to.
Parameter:
driver = driver-Id.
command = ISDN_CMD_SETSIL
arg = channel-number locally to the driver. (starting with 0)
num = ASCII-String, containing the current Service-Indicators.
ISDN_CMD_SETL2:
With this command, the HL-driver is told to select the given Layer-2-
protocol. This command is issued by the LL prior to ISDN_CMD_DIAL or
ISDN_CMD_ACCEPTD.
Parameter:
driver = driver-Id.
command = ISDN_CMD_SETL2
arg = channel-number locally to the driver. (starting with 0)
logical or'ed with (protocol-Id << 8)
protocol-Id is one of the constants ISDN_PROTO_L2...
num = unused.
ISDN_CMD_GETL2: (currently unused)
With this command, the HL-driver is told to return the current
setting of the Layer-2-protocol.
Parameter:
driver = driver-Id.
command = ISDN_CMD_GETL2
arg = channel-number locally to the driver. (starting with 0)
num = unused.
Returnvalue:
current protocol-Id (one of the constants ISDN_L2_PROTO)
ISDN_CMD_SETL3:
With this command, the HL-driver is told to select the given Layer-3-
protocol. This command is issued by the LL prior to ISDN_CMD_DIAL or
ISDN_CMD_ACCEPTD.
Parameter:
driver = driver-Id.
command = ISDN_CMD_SETL3
arg = channel-number locally to the driver. (starting with 0)
logical or'ed with (protocol-Id << 8)
protocol-Id is one of the constants ISDN_PROTO_L3...
num = unused.
ISDN_CMD_GETL2: (currently unused)
With this command, the HL-driver is told to return the current
setting of the Layer-3-protocol.
Parameter:
driver = driver-Id.
command = ISDN_CMD_GETL3
arg = channel-number locally to the driver. (starting with 0)
num = unused.
Returnvalue:
current protocol-Id (one of the constants ISDN_L3_PROTO)
ISDN_CMD_LOCK:
With this command the HL-driver is told, that it will be used by the
LL and therefore may not be unloaded. The HL-driver should use
MOD_INC_USE_COUNT to tell that to the kernel.
Parameter:
driver = driver-Id.
command = ISDN_CMD_LOCK
arg = unused.
num = unused.
ISDN_CMD_UNLOCK:
With this command the HL-driver is told, that it is no more used by the
LL and therefore may be unloaded. The HL-driver should use
DEC_INC_USE_COUNT to tell that to the kernel.
Parameter:
driver = driver-Id.
command = ISDN_CMD_UNLOCK
arg = unused.
num = unused.
3. Description of the events to be signaled by the HL-driver to th LL.
All status-changes are signaled via calling the previously described
function statcallb(). The field command of the struct isdn_cmd has
to be set by the HL-driver with the appropriate Status-Id (event-number).
The field arg has to be set to the channel-number (locally to the driver,
starting with 0) to which this event applies. (Exception: STAVAIL-event)
Until now, the following Status-Ids are defined:
ISDN_STAT_AVAIL:
With this call, the HL-driver signals the availability of new data
for readstat(). Used only for debugging-purposes, see description
of readstat().
Parameter:
driver = driver-Id
command = ISDN_STAT_STAVAIL
arg = length of available data.
num = unused.
ISDN_STAT_ICALL:
With this call, the HL-driver signals an incoming call to the LL.
Parameter:
driver = driver-Id
command = ISDN_STAT_ICALL
arg = channel-number, locally to the driver. (starting with 0)
num = ASCII-String in the following format:
"%s,%d,%d,%s",CallerNumber,ServiceIndicator,AddInfo,
CalledNumber.
ISDN_STAT_RUN:
With this call, the HL-driver signals availability of the ISDN-card.
(after initializing, loading firmware)
Parameter:
driver = driver-Id
command = ISDN_STAT_RUN
arg = unused.
num = unused.
ISDN_STAT_STOP:
With this call, the HL-driver signals unavailability of the ISDN-card.
(before unloading, while resetting/reconfiguring the card)
Parameter:
driver = driver-Id
command = ISDN_STAT_STOP
arg = unused.
num = unused.
ISDN_STAT_DCONN:
With this call, the HL-driver signals the successful establishment of
a D-Channel-connection. (Response to ISDN_CMD_ACCEPTD or ISDN_CMD_DIAL)
Parameter:
driver = driver-Id
command = ISDN_STAT_DCONN
arg = channel-number, locally to the driver. (starting with 0)
num = unused.
ISDN_STAT_BCONN:
With this call, the HL-driver signals the successful establishment of
a B-Channel-connection. (Response to ISDN_CMD_ACCEPTB or because the
remote-station has initiated establishment)
Parameter:
driver = driver-Id
command = ISDN_STAT_BCONN
arg = channel-number, locally to the driver. (starting with 0)
num = unused.
ISDN_STAT_DHUP:
With this call, the HL-driver signals the shutdown of a
D-Channel-connection. This could be a response to a prior ISDN_CMD_HANGUP,
or caused by a remote-hangup or if the remote-station has actively
rejected a call.
Parameter:
driver = driver-Id
command = ISDN_STAT_DHUP
arg = channel-number, locally to the driver. (starting with 0)
num = unused.
ISDN_STAT_BHUP:
With this call, the HL-driver signals the shutdown of a
B-Channel-connection. This could be a response to a prior ISDN_CMD_HANGUP,
or caused by a remote-hangup.
Parameter:
driver = driver-Id
command = ISDN_STAT_BHUP
arg = channel-number, locally to the driver. (starting with 0)
num = unused.
ISDN_STAT_CINF:
With this call, the HL-driver delivers charge-unit information to the
LL.
Parameter:
driver = driver-Id
command = ISDN_STAT_CINF
arg = channel-number, locally to the driver. (starting with 0)
num = ASCII string containing charge-units (digits only).
ISDN_STAT_LOAD: (currently unused)
ISDN_STAT_UNLOAD:
With this call, the HL-driver signals that it will be unloaded now. This
tells the LL to release all corresponding data-structures.
Parameter:
driver = driver-Id
command = ISDN_STAT_UNLOAD
arg = unused.
num = unused.
ISDN_STAT_BSENT:
With this call the HL-driver signals the delivery of a data-packet.
This callback is used by the network-interfaces only, tty-Emulation
does not need this call.
Parameter:
driver = driver-Id
command = ISDN_STAT_BSENT
arg = channel-number, locally to the driver. (starting with 0)
num = unused.
ISDN_STAT_NODCH:
With this call, the driver has to respond to a prior ISDN_CMD_DIAL, if
no D-Channel is available.
Parameter:
driver = driver-Id
command = ISDN_STAT_NODCH
arg = channel-number, locally to the driver. (starting with 0)
num = unused.
ISDN_STAT_ADDCH: (currently unused)
This call is planned for HL-drivers, which are unable to check card-type
or numbers of supported channels before they have loaded any firmware
using ioctl. Those HL-driver simply set the channel-parameter to zero
or a minimum channel-number when registering, and later if they know
the real amount, perform this call, allocating additional channels.
Parameter:
driver = driver-Id
command = ISDN_STAT_ADDCH
arg = to be defined.
num = to be defined.
ISDN_STAT_CAUSE:
With this call, the HL-driver delivers CAUSE-messages to the LL.
Currently the LL does not use this messages. Their contents is simply
logged via kernel-messages. Therefore, currently the format of the
messages is currently completely free. However they should be printable.
Parameter:
driver = driver-Id
command = ISDN_STAT_NODCH
arg = channel-number, locally to the driver. (starting with 0)
num = ASCII string containing CAUSE-message.

600
Documentation/isdn/README Normal file
View File

@ -0,0 +1,600 @@
README for the ISDN-subsystem
1. Preface
1.1 Introduction
This README describes how to set up and how to use the different parts
of the ISDN-subsystem.
For using the ISDN-subsystem, some additional userlevel programs are
necessary. Those programs and some contributed utilities are available
at
ftp.franken.de
/pub/isdn4linux/isdn4k-utils-<VersionNumber>.tar.gz
We also have set up a mailing-list:
The isdn4linux-project originates in Germany, and therefore by historical
reasons, the mailing-list's primary language is german. However mails
written in english have been welcome all the time.
to subscribe: write a email to majordomo@hub-wue.franken.de,
Subject irrelevant, in the message body:
subscribe isdn4linux <your_email_address>
To write to the mailing-list, write to isdn4linux@hub-wue.franken.de
1.1 Technical details
In the following Text, the terms MSN and EAZ are used.
MSN is the abbreviation for (M)ultiple(S)ubscriber(N)umber, and applies
to Euro(EDSS1)-type lines. Usually it is simply the phone-number.
EAZ is the abbreviation of (E)ndgeraete(A)uswahl(Z)iffer and
applies to German 1TR6-type lines. This is a one-digit string,
simply appended to the base phone-number
The internal handling is nearly identical, so replace the appropriate
term to that one, which applies to your local ISDN-environment.
When the link-level-module isdn.o is loaded, it supports up to 16
low-level-modules with up to 64 channels. (The number 64 is arbitrarily
chosen and can be configured at compile-time --ISDN_MAX in isdn.h).
A low-level-driver can register itself through an interface (which is
defined in isdnif.h) and gets assigned a slot.
The following char-devices are made available for each channel:
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
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.
O N L Y !!! for debugging (no locking against other devices):
One raw-data-device with the following functions:
write: data to B-channel.
read: data from B-channel.
In addition the following devices are made available:
128 tty-devices (64 cuix and 64 ttyIx) with integrated modem-emulator:
The functionality is almost the same as that of a serial device
(the line-discs are handled by the kernel, which lets you run
SLIP, CSLIP and asynchronous PPP through the devices. We have tested
Seyon, minicom, CSLIP (uri-dip) PPP and mgetty (compiled with NO_FAX),
XCept.
The modem-emulation supports the following:
1.3.1 Commands:
ATA Answer incoming call.
ATD<No.> Dial, the number may contain:
[0-9] and [,#.*WPT-S]
the latter are ignored until 'S'.
The 'S' must precede the number, if
the line is a SPV (German 1TR6).
ATE0 Echo off.
ATE1 Echo on (default).
ATH Hang-up.
ATH1 Off hook (ignored).
ATH0 Hang-up.
ATI Return "ISDN for Linux...".
ATI0 "
ATI1 "
ATO On line (data mode).
ATQ0 Enable result codes (default).
ATQ1 Disable result codes (default).
ATSx=y Set register x to y.
ATSx? Show contents of register x.
ATV0 Numeric responses.
ATV1 English responses (default).
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-
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
driver may not be selected (see "Automatic
Assignment") however the size of outgoing packets
will be limited correctly.
AT&D2 DTR-low-edge: Hang up and return to
command mode (default).
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&V Show all settings.
AT&W0 Write registers and EAZ/MSN to profile. See also
iprofd (5.c in this README).
AT&X0 BTX-mode off (default)
AT&X1 BTX-mode on. (S13.1=1, S14=0, S16=7, S18=7, S19=0)
1.3.2 Escape sequence:
During a connection, the emulation reacts just like
a normal modem to the escape sequence <DELAY>+++<DELAY>.
(The escape character - default '+' - can be set in the
register 2).
The DELAY must at least be 1.5 seconds long and delay
between the escape characters must not exceed 0.5 seconds.
1.3.3 Registers:
Nr. Default Description
0 0 Answer on ring number.
(no auto-answer if S0=0).
1 0 Count of rings.
2 43 Escape character.
(a value >= 128 disables the escape sequence).
3 13 Carriage return character (ASCII).
4 10 Line feed character (ASCII).
5 8 Backspace character (ASCII).
6 3 Delay in seconds before dialing.
7 60 Wait for carrier (ignored).
8 2 Pause time for comma (ignored)
9 6 Carrier detect time (ignored)
10 7 Carrier loss to disconnect time (ignored).
11 70 Touch tone timing (ignored).
12 69 Bit coded register:
Bit 0: 0 = Suppress response messages.
1 = Show response messages.
Bit 1: 0 = English response messages.
1 = Numeric response messages.
Bit 2: 0 = Echo off.
1 = Echo on.
Bit 3 0 = DCD always on.
1 = DCD follows carrier.
Bit 4 0 = CTS follows RTS
1 = Ignore RTS, CTS always on.
Bit 5 0 = Low-edge on DTR: Hang up and
return to command mode.
1 = Same as 0 but also resets all
registers.
Bit 6 0 = DSR always on.
1 = DSR only on if channel is available.
Bit 7 0 = Cisco-PPP-flag-hack off (default).
1 = Cisco-PPP-flag-hack on.
13 0 Bit coded register:
Bit 0: 0 = Use delayed tty-send-algorithm
1 = Direct tty-send.
Bit 1: 0 = T.70 protocol (Only for BTX!) off
1 = T.70 protocol (Only for BTX!) on
14 0 Layer-2 protocol: (with the ICN-driver
currently always 0)
0 = X75/LAPB with I-frames
1 = X75/LAPB with UI-frames
2 = X75/LAPB with BUI-frames
3 = HDLC
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)
18 7 Service-Octet-1
19 0 Service-Octet-2
Last but not least a (at the moment fairly primitive) device to request
the line-status (/dev/isdninfo) is made available.
Automatic assignment of devices to lines:
All inactive physical lines are listening to all EAZs for incoming
calls and are NOT assigned to a specific tty or network interface.
When an incoming call is detected, the driver looks first for a network
interfaces and then for an opened tty which:
1. is configured for the same EAZ.
2. has the same protocol settings for the B-channel.
3. (only for network interfaces if the security flag is set)
contains the caller number in its access list.
4. Either the channel is not bound exclusively to another Net-interface, or
it is bound AND the other checks apply to exact this Interface.
(For usage of the bind-features, refer to the isdnctrl-man-page)
Only when a matching interface or tty is found, the call is accepted
and the "connection" between the low-level-layer and the link-level-layer
is established and kept until the end of the connection.
In all other cases no connection is established. Isdn4linux can be
configured to either do NOTHING in this case (which is useful, if
other, external devices with the same EAZ/MSN are connected to the bus)
or to reject the call actively. (isdnctrl busreject ...)
For an outgoing call, the inactive physical lines are searched.
The call is placed on the first physical line, which supports the
requested protocols for the B-channel. If a net-interface, however
is pre-bound to a channel, this channel is used directly.
This makes it possible to configure several network interfaces and ttys
for one EAZ, if the network interfaces are set to secure operation.
If an incoming call matches one network interface, it gets connected to it.
If another incoming call for the same EAZ arrives, which does not match
a network interface, the first tty gets a "RING" and so on.
As soon as voice gets supported (with the availability of the Diehl-driver),
the service-identifier will be evaluated in addition.
2 System prerequisites:
ATTENTION! The program "insmod" from the Package "modules-1.2.8" (It's
on nearly all newer distributions) has a bug, which makes
it impossible to set both driver-Id's when loading the
icn-module for the Double-ICN-Card. A patch is supplied
in the utility-package called "insmod-1.2.8.patch". Change into
the source-directory of insmod, and type
"patch < insmod-1.2.8.patch". Then recompile it. This will fix
the bug.
This bug does NOT occur when using insmod with the Teles-driver
or a single ICN-card.
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. The manual tells the port has to be 0x180. THIS IS WRONG!!
0xd80 is the correct value! 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!
The ICN driver supports only one card at the moment. If you like to
use more than one card, build the modularized version, loading it
more than one time, each module driving a single card.
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 it's 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 it's 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!
The ICN driver supports only one card at the moment. If you like to
use more than one card, build the modularized version, loading it
more than one time, each module driving a single card.
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.
4. Device-inodes
The major and minor-numbers and it's names are described in
Documentation/devices.txt. The major-numbers are:
43 for the ISDN-tty's.
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-2B, 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-2B: 4 LEDs) must be
blinking intermittently now. If a connection is up, the corresponding
led is lit continuously.
b) If you only intend to use ttys, you are nearly ready now.
c) If you want to have really permanent "Modem"-settings on disk, you
can start the daemon iprofd. Give it a path to a file at the command-
line. It will store the profile-settings in this file every time
an AT&W0 is performed on any ISDN-tty. If the file already exists,
all profiles are initialized from this file. If you want to unload
any of the modules, kill iprofd first.
d) For networking, continue: Create an interface:
isdnctrl addif isdn0
e) Set the EAZ (or MSN for Euro-ISDN):
isdnctrl eaz isdn0 2
(For 1TR6 a single digit is allowed, for Euro-ISDN the number is your
real MSN e.g.: Phone-Number)
f) Set the number for outgoing calls on the interface:
isdnctrl addphone isdn0 out 1234567
... (this can be executed more than once, all assigned numbers are
tried in order)
and the number(s) for incoming calls:
isdnctrl addphone isdn0 in 1234567
g) Set the timeout for hang-up:
isdnctrl huptimeout isdn0 <timeout_in_seconds>
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.):
isdnctrl chargehup isdn0 on
i) Setup the interface with ifconfig as usual, and set a route to it.
j) (optional) If you run X11 and have Tcl/Tk-wish Version4.0, you can use
the script tools/tcltk/isdnmon. You can add actions for line-status
changes. See the comments at the beginning of the script for how to
do that. There are other tty-based tools in the tools-subdirectory
contributed by Michael Knigge (imon), Volker Götz (imontty) and
Andreas Kool (isdnmon).
k) For initial testing, you can set the verbose-level to 2 (default: 0).
Then all incoming calls are logged, even if they are not addressed
to one of the configured net-interfaces:
isdnctrl verbose 2
Now you are ready! A ping to the set address should now result in a
dial-out (look at syslog kernel-messages).
The phone-numbers and EAZs can be assigned at any time with isdnctrl.
You can add as many interfaces as you like with addif following the
directions above. Of course, there may be some limitations. But we have
tested as many as 20 interfaces without any problem. However, if you
don't give an interface name to addif, the kernel will assign a name
which starts with "eth". The number of "eth"-interfaces is limited by
the kernel.
5. Additional options for isdnctrl:
"isdnctrl secure <InterfaceName> on"
Only incoming calls, for which the caller-id is listed in the access
list of the interface are accepted. You can add caller-id's With the
command "isdnctrl addphone <InterfaceName> in <caller-id>"
Euro-ISDN does not transmit the leading '0' of the caller-id for an
incoming call, therefore you should configure it accordingly.
If the real number for the dialout e.g. is "09311234567" the the number
to configure here is "9311234567". The pattern-match function
works similar to the shell mechanism.
? one arbitrary digit
* zero or arbitrary many digits
[123] one of the digits in the list
[1-5] one digit between '1' and '5'
a '^' as the first character in a list inverts the list
"isdnctrl secure <InterfaceName> off"
Switch of secure operation (default).
"isdnctrl ihup <InterfaceName> [on|off]"
Switch the hang-up-timer for incoming calls on or off.
"isdnctrl eaz <InterfaceName>"
Returns the EAZ of an interface.
"isdnctrl delphone <InterfaceName> in|out <number>"
Deletes a number from one of the the access-lists of the interface.
"isdnctrl delif <InterfaceName>"
Removes the interface (and possible slaves) from the kernel.
(You have to unregister it with "ifconfig <InterfaceName> down" before).
"isdnctrl callback <InterfaceName> [on|off]"
Switches an interface to callback-mode. In this mode, an incoming call
will be rejected and after this the remote-station will be called. If
you test this feature by using ping, some routers will re-dial very
quickly, so that the callback from isdn4linux may not be recognized.
In this case use ping with the option -i <sec> to increase the interval
between echo-packets.
"isdnctrl cbdelay <InterfaceName> [seconds]"
Sets the delay (default 5 sec) between an incoming call and start of
dialing when callback is enabled.
"isdnctrl cbhup <InterfaceName> [on|off]"
This enables (default) or disables an active hangup (reject) when getting an
incoming call for an interface which is configured for callback.
"isdnctrl encap <InterfaceName> <EncapType>"
Selects the type of packet-encapsulation. The encapsulation can be changed
only while an interface is down.
At the moment th following Values are supported:
rawip (Default) Selects raw-IP-encapsulation. This means, MAC-headers
are stripped off.
ip IP with type-field. Same as IP but the type-field of the MAC-header
is preserved.
cisco-h A special-mode for communicating with a Cisco, which is configured
to do "hdlc"
ethernet No stripping. Packets are sent with full MAC-header.
The Ethernet-address of the interface is faked, from it's
IP-address: fc:fc:i1:i2:i3:i4, where i1-4 are the IP-addr.-values.
syncppp Synchronous PPP
uihdlc HDLC with UI-frame-header (for use with DOS ISPA, option -h1)
Watching packets, using standard-tcpdump will fail for all encapsulations
except ethernet because tcpdump does not know how to handle packets
without MAC-header. A patch for tcpdump is included in the utility-package
mentioned above.
"isdnctrl l2_prot <InterfaceName> <L2-ProtocolName>"
Selects a layer-2-protocol.
(With the ICN-driver and the Teles-driver, "x75i" and "hdlc" is available.
With other drivers, "x75ui", "x75bui" may be possible too.)
isdnctrl l3_prot <InterfaceName> <L3-ProtocolName>
The same for layer-3. (At the moment only "trans" is allowed)
"isdnctrl list <InterfaceName>"
Shows all parameters of an interface and the charge-info.
Try "all" as the interface name.
"isdnctrl hangup <InterfaceName>"
Forces hangup of an interface.
"isdnctrl bind <InterfaceName> <DriverId>,<ChannelNumber> [exclusive]"
If you are using more than one ISDN-Card, it is sometimes necessary to
dial out using a specific Card or even preserve a specific Channel for
Dialout of a specific net-interface. This can be done with the above
command. Replace <DriverId> by whatever you assigned while loading the
module. The <ChannelNumber> is counting from zero. the upper Limit
depends on the card used. At the Moment no card supports more than
2 Channels, so the upper limit is one.
"isdnctrl unbind <InterfaceName>"
unbinds a previously bound interface.
"isdnctrl busreject <DriverId> on|off"
If switched on, isdn4linux replies a REJECT to incoming calls, it
cannot match to any configured interface.
If switched off, nothing happens in this case.
You normally should NOT enable this feature, if the ISDN-adaptor is not
the only device, connected to the S0-bus. Otherwise it could happen, that
isdn4linux rejects an incoming call, which belongs to another device on
the bus.
"isdnctrl addslave <InterfaceName> <SlaveName>
Creates a slave interface for channel-bundling. Slave interfaces are
not seen by the kernel, but their ISDN-part can be configured with
isdnctrl as usual. (Phone numbers, EAZ/MSN, timeouts etc.) If more
than two channels are to be bundled, feel free to create as many as you
want. InterfaceName must be a real interface, NOT a slave. Slave interfaces
start dialing, if the master interface resp. the previous slave interface
has a load of more than 7000 cps. They hangup if the load goes under 7000
cps, according to their "huptimeout"-parameter.
"isdnctrl sdelay <InterfaceName> secs."
This sets the minimum time an Interface has to be fully loaded, until
it sends an dial-request to it's slave.
"isdnctrl dial <InterfaceName>"
Forces an interface to start dialing even if no packets are to be
transferred.
"isdnctrl mapping <DriverId> MSN0,MSN1,MSN2,...MSN9"
This installs a mapping table for EAZ<->MSN-mapping for a single line.
Missing MSN's have to be given as "-" or can be omitted, if at the end
of the commandline.
With this command, it's now possible to have an interface listening to
mixed 1TR6- and Euro-Type lines. In this case, the interface has to be
configured to a 1TR6-type EAZ (one digit). The mapping is also valid
for tty-emulation. Seen from the interface/tty-level the mapping
CAN be used, however it's possible to use single tty's/interfaces with
real MSN's (more digits) also, in which case the mapping will be ignored.
Here is an example:
You have a 1TR6-type line with base-nr. 1234567 and a Euro-line with
MSN's 987654, 987655 and 987656. The DriverId for the Euro-line is "EURO".
isdnctrl mapping EURO -,987654,987655,987656,-,987655
...
isdnctrl eaz isdn0 1 # listen on 12345671(1tr6) and 987654(euro)
...
isdnctrl eaz isdn1 4 # listen on 12345674(1tr6) only.
...
isdnctrl eaz isdn2 987654 # listen on 987654(euro) only.
Same scheme is used with AT&E... at the tty's.
6. If you want to write a new low-level-driver, you are welcome.
The interface to the link-level-module is described in the file INTERFACE.
If the interface should be expanded for any reason, don't do it
on your own, send me a mail containing the proposed changes and
some reasoning about them.
If other drivers will not be affected, I will include the changes
in the next release.
For developers only, there is a second mailing-list. Write to me
(fritz@wuemaus.franken.de), if you want to join that list.
Have fun!
-Fritz

View File

@ -0,0 +1,61 @@
You can get the ICN-ISDN-card from:
Thinking Objects Software GmbH
Obere Heerbergstr. 17
97078 Würzburg
Tel: +49 931 2877950
Fax: +49 931 2877951
email uhl@think.de
WWW http:/www.think.de
The card communicates with the PC by two interfaces:
1. A range of 4 successive port-addresses, whose base address can be
configured with the switches.
2. A memory window with 16KB-256KB size, which can be setup in 16k steps
over the whole range of 16MB. Isdn4linux only uses a 16k window.
The base address of the window can be configured when loading
the lowlevel-module (see README).
Setting up the IO-address dipswitches for the ICN-ISDN-card:
Two types of cards exist, one with dip-switches and one with
hook-switches.
1. Setting for the card with hook-switches:
(0 = switch closed, 1 = switch open)
S3 S2 S1 Base-address
0 0 0 0x300
0 0 1 0x310
0 1 0 0x320 (Default for isdn4linux)
0 1 1 0x330
1 0 0 0x340
1 0 1 0x350
1 1 0 0x360
1 1 1 NOT ALLOWED!
2. Setting for the card with dip-switches:
(0 = switch closed, 1 = switch open)
S1 S2 S3 S4 Base-Address
0 0 0 0 0x300
0 0 0 1 0x310
0 0 1 0 0x320 (Default for isdn4linux)
0 0 1 1 0x330
0 1 0 0 0x340
0 1 0 1 0x350
0 1 1 0 0x360
0 1 1 1 NOT ALLOWED!
1 0 0 0 0x308
1 0 0 1 0x318
1 0 1 0 0x328
1 0 1 1 0x338
1 1 0 0 0x348
1 1 0 1 0x358
1 1 1 0 0x368
1 1 1 1 NOT ALLOWED!

View File

@ -0,0 +1,40 @@
------------------------------------------------------------------------------
README file for the PCBIT-D Device Driver.
------------------------------------------------------------------------------
The PCBIT is a Euro ISDN adapter manufactured in Portugal by Octal and
developed in cooperation with Portugal Telecom and Inesc.
The driver interfaces with the standard kernel isdn facilities
originaly developed by Fritz Elfert in the isdn4linux project.
The common versions of the pcbit board require a firmware that is
distributed (and copyrighted) by the manufacturer. To load this
firmware you need "pcbitctl" availiable on the standard isdn4k-utils
package or in the pcbit package availiable in:
ftp://ftp.di.fc.ul.pt/pub/systems/Linux/isdn
Known Limitations:
- The board reset proceeding is at the moment incorrect and will only
allow you to load the firmware after a hard reset.
- Only HDLC in B-channels is supported at the moment. There is now
current support to X.25 in B or D channels nor LAPD in B
channels. The main reason is that this two other protocol modes have,
to my knowledge, very little use. If you want to see them implemented
*do* send me a mail.
- The driver often triggers errors in the board that i and the
manufacturer believe to be caused by bugs in the firmware. The current
version includes several proceedings for error recovery that should
allow normal operation. Plans for the future include cooperation with
the manufacturer in order to solve this problems.
Information/hints/help can be obtained in the linux isdn
mailing list (isdn4linux@hub-wue.franken.de) or directly from me.
regards,
Pedro.
<roque@di.fc.ul.pt>

View File

@ -0,0 +1,55 @@
Some additional information for setting up a syncPPP
connection using network interfaces.
---------------------------------------------------------------
You need one thing beside the isdn4linux package:
a patched pppd .. (I called it ipppd to show the difference)
Compiling isdn4linux with sync PPP:
-----------------------------------
To compile isdn4linux with the sync PPP part, you have
to answer the appropriate question when doing a "make config"
Don't forget to load the slhc.o
module before the isdn.o module, if VJ-compression support
is not compiled into your kernel. (e.g if you have PPP or
CSLIP in the kernel)
Using isdn4linux with sync PPP:
-------------------------------
Sync PPP is just another encapsulation for isdn4linux. The
name to enable sync PPP encapsulation is 'syncppp' .. e.g:
isdn/isdnctrl encap ippp0 syncppp
The name of the interface is here 'ippp0'. You need
one interface with the name 'ippp0' to saturate the
ipppd, which checks the ppp version via this interface.
To set up a PPP connection you need the ipppd .. You must start
the ipppd once after installing the modules. The ipppd
communicates with the isdn4linux link-level driver using the
/dev/ippp0 to /dev/ippp15 devices. One ipppd can handle
all devices at once. If you want to use two PPP connections
at the same time, you have to connect the ipppd to two
devices .. and so on.
I've implemented one additional option for the ipppd:
'useifip' will get (if set to not 0.0.0.0) the IP address
for the negotiation from the attached network-interface.
(also: ipppd will try to negotiate pointopoint IP as remote IP)
You must disable BSD-compression, this implementation can't
handle compressed packets.
Check the etc/rc.isdn.syncppp in the isdn4kernel-util package
for an example setup script.
To use the MPPP stuff, you must configure a slave device
with isdn4linux. Now call the ipppd with the '+mp' option.
To increase the number of links, you must use the
'addlink' option of the isdnctrl tool.
enjoy it,
michael

View File

@ -0,0 +1,72 @@
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=<SomeString> 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 <DriverId> 1 <debugging_flags>
where <debugging_flags> 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
For example 'teles/telesctrl MyTeles 1 31' 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

View File

@ -0,0 +1,50 @@
simple isdn4linux PPP FAQ .. to be continued .. not 'debugged'
Q: pppd,ipppd, syncPPP , asyncPPP .. what is that ?
what should I use?
A: The pppd is for asynchronous PPP .. asynchron means
here, the framing is character based. (e.g when
using ttyI* or tty* devices)
The ipppd handles PPP packets coming in HDLC
frames (bit based protocol) ... The PPP driver
in isdn4linux pushs all IP packets direct
to the network layer and all PPP protocol
frames to the /dev/ippp* device.
So, the ipppd is a simple externel network
protocol handler.
If you login into a remote machine using the
/dev/ttyI* devices and then enable PPP on the
remote terminal server -> use the 'old' pppd
If your remote side immediately starts to send
frames ... you probably connect to a
syncPPP machine .. use the network device part
of isdn4linux with the 'syncppp' encapsulation
and make sure, that the ipppd is running and
conneted to at least one /dev/ippp*. Check the
isdn4linux manual on how to configure a network device.
Q: when I start the ipppd .. I only get the
error message "this systems lacks PPP support"
A: check that at least the device 'ippp0' exists.
(you can check this e.g with the program 'ifconfig')
The ipppd NEEDS this device under THIS name ..
If this device doesn't exists, use:
isdnctrl addif ippp0
isdnctrl encap ippp0 syncppp
... (see isdn4linux doc for more) ...
A: Maybe you have compiled the ipppd with another
kernel source tree than the kernel you currently
run ...
Q: when I list the netdevices with ifconfig I see, that
my ISDN interface has a HWaddr and IRQ=0 and Base
address = 0
A: The device is a fake ethernetdevice .. ignore IRQ and baseaddr
You need the HWaddr only for ethernet encapsulation.

26
Makefile Normal file
View File

@ -0,0 +1,26 @@
VERSION=3.1.91
SUBDIRS=drivers/isdn
# Where to install the modules ($KERNELDIR/modules)
export KERNELDIR = /usr/src/linux
export INCLUDES=../../include
export CC = gcc -I $(INCLUDES)
export MCFLAGS = -m486 -O6 -Wall -D__KERNEL__ -DLINUX -DMODULE
#
# Use next Definition of CFLAGS to get Assembler-Listings for extensive
# debugging
#export MCFLAGS = -m486 -g -v --save-temps -O6 -Wall -D__KERNEL__ -DLINUX -DMODULE
export PCFLAGS = -O2 -Wall
all: subdirs
subdirs:
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
clean:
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i clean; done
rm -f *.[iso] *~ core include/*~
install: all
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i install; done
cd $(KERNELDIR); make modules_install; /sbin/depmod -a

26
diffstd Executable file
View File

@ -0,0 +1,26 @@
#!/bin/sh
KERNELDIR=/usr/src/linux
if [ $# != 0 ]; then
for i in $* ; do
diff -u $KERNELDIR/$i $i
done
else
for i in drivers/isdn/isdn_*.[ch] ; do
diff -u $KERNELDIR/$i $i
done
for i in drivers/isdn/icn/icn.[ch] ; do
diff -u $KERNELDIR/$i $i
done
for i in drivers/isdn/teles/*.[ch] ; do
diff -u $KERNELDIR/$i $i
done
for i in drivers/isdn/pcbit/*.[ch] ; do
diff -u $KERNELDIR/$i $i
done
for i in include/linux/isdn*.h ; do
diff -u $KERNELDIR/$i $i
done
fi

38
drivers/isdn/Makefile Normal file
View File

@ -0,0 +1,38 @@
MODULES=isdn.o
OBJS=isdn_common.o isdn_net.o isdn_tty.o isdn_ppp.o
PROGS=debugvar
SUBDIRS=teles icn pcbit
CFLAGS=$(MCFLAGS)
all: $(MODULES) $(PROGS) subdirs
subdirs:
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
isdn.o: $(OBJS)
ld -r -o isdn.o $(OBJS)
isdn_common.o: isdn_common.c $(INCLUDES)/linux/isdn.h $(INCLUDES)/linux/isdnif.h
$(CC) $(CFLAGS) -c $<
isdn_net.o: isdn_net.c $(INCLUDES)/linux/isdn.h $(INCLUDES)/linux/isdnif.h
$(CC) $(CFLAGS) -c $<
isdn_tty.o: isdn_tty.c $(INCLUDES)/linux/isdn.h $(INCLUDES)/linux/isdnif.h
$(CC) $(CFLAGS) -c $<
isdn_ppp.o: isdn_ppp.c $(INCLUDES)/linux/isdn.h $(INCLUDES)/linux/isdnif.h
$(CC) $(CFLAGS) -c $<
debugvar: debugvar.c $(INCLUDES)/linux/isdn.h $(INCLUDES)/linux/isdnif.h
$(CC) -m486 -O6 -Wall -D__KERNEL__ -DLINUX -D__DEBUGVAR__ -o debugvar debugvar.c
install: all
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i install; done
install -o root -g bin -m 0750 $(PROGS) /sbin
install -o root -g root -m 0644 $(MODULES) $(KERNELDIR)/modules
clean:
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i clean; done
rm -f *.[iso] $(PROGS) *~ core

13
drivers/isdn/icn/Makefile Normal file
View File

@ -0,0 +1,13 @@
MODULES=icn.o
CFLAGS=$(MCFLAGS) -I../$(INCLUDES)
all: $(MODULES)
icn.o: icn.c icn.h ../$(INCLUDES)/linux/isdnif.h
$(CC) $(CFLAGS) -c icn.c
install: all
install -o root -g root -m 0644 $(MODULES) $(KERNELDIR)/modules
clean:
rm -f *.[iso] *~ core

246
drivers/isdn/isdn_audio.c Normal file
View File

@ -0,0 +1,246 @@
/* $Id$
*
* Linux ISDN subsystem, audio conversion and compression (linklevel).
*
* Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
*/
/*
* 8-bit-linear <-> alaw conversion stuff
* This is simply done with lookup-tables.
*/
static unsigned char isdn_audio_a2ltable[] = {
45,214,122,133, 0,255,107,149, 86,171,126,129, 0,255,117,138,
13,246,120,135, 0,255, 99,157, 70,187,124,131, 0,255,113,142,
61,198,123,132, 0,255,111,145, 94,163,127,128, 0,255,119,136,
29,230,121,134, 0,255,103,153, 78,179,125,130, 0,255,115,140,
37,222,122,133, 0,255,105,151, 82,175,126,129, 0,255,116,139,
5,254,120,135, 0,255, 97,159, 66,191,124,131, 0,255,112,143,
53,206,123,132, 0,255,109,147, 90,167,127,128, 0,255,118,137,
21,238,121,134, 0,255,101,155, 74,183,125,130, 0,255,114,141,
49,210,123,133, 0,255,108,148, 88,169,127,129, 0,255,118,138,
17,242,121,135, 0,255,100,156, 72,185,125,131, 0,255,114,142,
64,194,124,132, 0,255,112,144, 96,161,128,128, 1,255,120,136,
33,226,122,134, 0,255,104,152, 80,177,126,130, 0,255,116,140,
41,218,122,133, 0,255,106,150, 84,173,126,129, 0,255,117,139,
9,250,120,135, 0,255, 98,158, 68,189,124,131, 0,255,113,143,
57,202,123,132, 0,255,110,146, 92,165,127,128, 0,255,119,137,
25,234,121,134, 0,255,102,154, 76,181,125,130, 0,255,115,141
};
static unsigned char isdn_audio_l2atable[] = {
252,172,172,172,172, 80, 80, 80, 80,208,208,208,208, 16, 16, 16,
16,144,144,144,144,112,112,112,112,240,240,240,240, 48, 48, 48,
48,176,176,176,176, 64, 64, 64, 64,192,192,192,192, 0, 0, 0,
0,128,128,128,128, 96, 96, 96, 96,224,224,224,224, 32, 32, 32,
160,160, 88, 88,216,216, 24, 24,152,152,120,120,248,248, 56, 56,
184,184, 72, 72,200,200, 8, 8,136,136,104,104,232,232, 40, 40,
168, 86,214, 22,150,118,246, 54,182, 70,198, 6,134,102,230, 38,
166,222,158,254,190,206,142,238,210,242,194,226,218,250,202,234,
235,203,251,219,227,195,243,211,175,239,143,207,191,255,159,223,
167, 39,231,103,135, 7,199, 71,183, 55,247,119,151, 23,215, 87,
87,169,169, 41, 41,233,233,105,105,137,137, 9, 9,201,201, 73,
73,185,185, 57, 57,249,249,121,121,153,153, 25, 25,217,217, 89,
89, 89,161,161,161,161, 33, 33, 33, 33,225,225,225,225, 97, 97,
97, 97,129,129,129,129, 1, 1, 1, 1,193,193,193,193, 65, 65,
65, 65,177,177,177,177, 49, 49, 49, 49,241,241,241,241,113,113,
113,113,145,145,145,145, 17, 17, 17, 17,209,209,209,209, 81,253
};
#if ((CPU == 386) || (CPU == 486) || (CPU == 586))
static inline void isdn_audio_transasm(const void *table, void *buff, unsigned long n)
{
__asm__("cld\n"
"1:\tlodsb\n\t"
"xlatb\n\t"
"stosb\n\t"
"loop 1b\n\t"
::"b" ((long)table), "c" (n), "D" ((long)buff), "S" ((long)buff)
:"bx","cx","di","si","ax");
}
static inline void isdn_audio_a2l(unsigned char *buff, unsigned long len)
{
isdn_audio_transasm(isdn_audio_a2ltable, buff, len)
}
static inline void isdn_audio_l2a(unsigned char *buff, unsigned long len)
{
isdn_audio_transasm(isdn_audio_l2atable, buff, len)
}
#else
static inline void isdn_audio_a2l(unsigned char *buff, unsigned long len)
{
while (len--) {
*buff = isdn_audio_a2ltable[*buff];
buff++;
}
}
static inline void isdn_audio_l2a(unsigned char *buff, unsigned long len)
{
while (len--) {
*buff = isdn_audio_l2atable[*buff];
buff++;
}
}
#endif
/*
* linear <-> adpcm conversion stuff
* Parts from the mgetty-package (C) by Gert Doering and Klaus Weidner
* Used by permission of Gert Doering
*/
typedef struct adpcm_state {
int a;
int d;
int word;
int nleft;
} adpcm_state;
static state_t state_init = { 0x0000, 0 };
static int Mx[3][8] = {
{ 0x3800, 0x5600, 0,0,0,0,0,0 },
{ 0x399a, 0x3a9f, 0x4d14, 0x6607, 0,0,0,0 },
{ 0x3556, 0x3556, 0x399A, 0x3A9F, 0x4200, 0x4D14, 0x6607, 0x6607 },
};
static int bitmask[9] = { 0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
static int
get_bits (int nbits, adpcm_state *s, FILE *in)
{
while( s->nleft < nbits) {
int d=getc(in);
if (d==EOF) return EOF;
s->word = (s->word<<8) | d;
s->nleft+=8;
}
s->nleft -= nbits;
return (s->word >> s->nleft) & bitmask[nbits];
}
static void
put_bits (int data, int nbits, adpcm_state *s, FILE *out)
{
s->word = (s->word<<nbits) | (data & bitmask[nbits]);
s->nleft += nbits;
while(s->nleft>=8) {
int d = (s->word >> (s->nleft-8));
putc(d&255, out);
s->nleft-=8;
}
}
static void
isdn_audio_adpcm2lin (int nbits, adpcm_state *s FILE *in, FILE *out)
{
int a = s->a;
int d = s->d;
while (1) {
int sign;
int e = get_bits(nbits, s, in);
if (e == EOF) break;
if( nbits == 4 && e == 0) d = 4;
sign = ( e>>(nbits-1) ) ? -1 : 1 ;
e &= bitmask[nbits-1];
#if 0
if (rom >= 610 && rom < 612) {
/* modified conversion algorithm for ROM >= 6.10 */
a = (a * 3973 + 2048) >>12;
} else if (rom>=612) {
/* modified conversion algorithm for ROM >= 6.12 */
a = (a * 4093 + 2048) >>12;
}
#endif
a += sign * ((e<<1)+1) * d >>1;
if ( (d&1) ) a++;
zput(a<<2, out);
d = (d * Mx[nbits-2][ e ] + 0x2000) >>14;
if ( d < 5 ) d=5;
}
}
static void
isdn_audio_lin2adpcm (int nbits, adpcm_state *s, FILE *in, FILE *out)
{
while (len--) {
int e = 0, nmax = 1 << (nbits-1);
int sign, delta;
delta = (zget(in) >> 2) - a;
if(feof(in))
break;
if(delta<0) {
e = nmax;
delta = -delta;
}
while( --nmax && delta > d ) {
delta -= d;
e++;
}
if(nbits==4 && ((e&0x0f) == 0)) e=0x08;
put_bits( e, nbits, &s, out);
#if 0
if(rom >= 610 && rom < 612) {
/* modified conversion algorithm for ROM >= 6.10 */
a = (a * 3973 + 2048) >>12;
} else if(rom>=612) {
/* modified conversion algorithm for ROM >= 6.12 */
a = (a * 4093 + 2048) >>12;
}
#endif
sign = ( e>>(nbits-1) ) ? -1 : 1 ;
e = e&bitmask[nbits-1];
a += sign * ((e<<1)+1) * d >>1;
if ( (d&1) ) a++;
d = (d*Mx[nbits-2][ e ] + 0x2000) >>14;
if ( d < 5 ) d=5;
}
if(s.nleft) put_bits(0, 8-s.nleft, &s, out);
}
int
pvfadpcm (int argc, char **argv )
{
FILE *in=stdin, *out=stdout;
int nbits;
nbits= argv[0][strlen(argv[0])-1] -'0';
if(nbits>=2 && nbits <=4) {
pvftoadpcm(nbits, in, out);
} else {
adpcmtopvf(nbits, in, out);
}
return 0;
}

View File

@ -0,0 +1,22 @@
HDRS=pcbit.h edss1.h callbacks.h layer2.h capi.h
SRCS=module.c edss1.c drv.c layer2.c capi.c callbacks.c
OBJS=module.o edss1.o drv.o layer2.o capi.o callbacks.o
CFLAGS=$(MCFLAGS) -I../$(INCLUDES)
#-DDEBUG
NFLAGS=-g -I../$(INCLUDES) -DDEBUG
all: pcbit.o
pcbit.o: $(OBJS)
ld -r -o pcbit.o $(OBJS)
module.o: pcbit.h
layer2.o: pcbit.h layer2.h
drv.o: pcbit.h edss1.h callbacks.h layer2.h capi.h
edss1.o: pcbit.h edss1.h callbacks.h
capi.o: pcbit.h capi.h edss1.h
callbacks.o: pcbit.h edss1.h callbacks.h layer2.h capi.h
clean:
rm -f $(OBJS) *.[iso] *~

View File

@ -0,0 +1,361 @@
/*
* Copyright (C) 1996 Universidade de Lisboa
*
* Writen by Pedro Roque Marques (roque@di.fc.ul.pt)
*
* This software may be used and distributed according to the terms of
* the GNU Public License, incorporated herein by reference.
*/
/*
* callbacks for the FSM
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/tqueue.h>
#include <linux/skbuff.h>
#include <asm/io.h>
#include <linux/isdnif.h>
#include "pcbit.h"
#include "layer2.h"
#include "edss1.h"
#include "callbacks.h"
#include "capi.h"
ushort last_ref_num = 1;
/*
* send_conn_req
*
*/
void cb_out_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *cbdata)
{
struct sk_buff *skb;
int len;
ushort refnum;
#ifdef DEBUG
printk(KERN_DEBUG "Called Party Number: %s\n",
cbdata->data.setup.CalledPN);
#endif
/*
* hdr - kmalloc in capi_conn_req
* - kfree when msg has been sent
*/
if ((len = capi_conn_req(cbdata->data.setup.CalledPN, &skb)) < 0)
{
printk("capi_conn_req failed\n");
return;
}
refnum = last_ref_num++ & 0x7fffU;
chan->callref = 0;
chan->layer2link = 0;
chan->snum = 0;
chan->s_refnum = refnum;
pcbit_l2_write(dev, MSG_CONN_REQ, refnum, skb, len);
}
/*
* rcv CONNECT
* will go into ACTIVE state
* send CONN_ACTIVE_RESP
* send Select protocol request
*/
void cb_out_2(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data)
{
isdn_ctrl ictl;
struct sk_buff *skb;
int len;
ushort refnum;
if ((len=capi_conn_active_resp(chan, &skb)) < 0)
{
printk("capi_conn_active_req failed\n");
return;
}
refnum = last_ref_num++ & 0x7fffU;
chan->s_refnum = refnum;
pcbit_l2_write(dev, MSG_CONN_ACTV_RESP, refnum, skb, len);
ictl.command = ISDN_STAT_DCONN;
ictl.driver=dev->id;
ictl.arg=chan->id;
dev->dev_if->statcallb(&ictl);
/* ACTIVE D-channel */
/* Select protocol */
if ((len=capi_select_proto_req(chan, &skb, 1 /*outgoing*/)) < 0) {
printk("capi_select_proto_req failed\n");
return;
}
refnum = last_ref_num++ & 0x7fffU;
chan->s_refnum = refnum;
pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len);
}
/*
* Disconnect received (actualy RELEASE COMPLETE)
* This means we where not hable to establish connection with remote
* Inform the big boss above
*/
void cb_out_3(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data)
{
isdn_ctrl ictl;
ictl.command = ISDN_STAT_DHUP;
ictl.driver=dev->id;
ictl.arg=chan->id;
dev->dev_if->statcallb(&ictl);
}
/*
* Incomming call received
* inform user
*/
void cb_in_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *cbdata)
{
isdn_ctrl ictl;
unsigned short refnum;
struct sk_buff *skb;
int len;
ictl.command = ISDN_STAT_ICALL;
ictl.driver=dev->id;
ictl.arg=chan->id;
/*
* ictl.num >= strlen() + strlen() + 5
*/
if (cbdata->data.setup.CalledPN)
sprintf(ictl.num, "%s,%d,%d,%s",
cbdata->data.setup.CallingPN,
7, 0,
cbdata->data.setup.CalledPN);
else
sprintf(ictl.num, "%s,%d,%d,%s",
cbdata->data.setup.CallingPN,
7, 0,
"0");
#ifdef DEBUG
printk(KERN_DEBUG "statstr: %s\n", ictl.num);
#endif
dev->dev_if->statcallb(&ictl);
if ((len=capi_conn_resp(chan, &skb)) < 0) {
printk(KERN_DEBUG "capi_conn_resp failed\n");
return;
}
refnum = last_ref_num++ & 0x7fffU;
chan->s_refnum = refnum;
pcbit_l2_write(dev, MSG_CONN_RESP, refnum, skb, len);
}
/*
* user has replyed
* open the channel
* send CONNECT message CONNECT_ACTIVE_REQ in CAPI
*/
void cb_in_2(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data)
{
unsigned short refnum;
struct sk_buff *skb;
int len;
if ((len = capi_conn_active_req(chan, &skb)) < 0) {
printk(KERN_DEBUG "capi_conn_active_req failed\n");
return;
}
refnum = last_ref_num++ & 0x7fffU;
chan->s_refnum = refnum;
printk(KERN_DEBUG "sending MSG_CONN_ACTV_REQ\n");
pcbit_l2_write(dev, MSG_CONN_ACTV_REQ, refnum, skb, len);
}
/*
* CONN_ACK arrived
* start b-proto selection
*
*/
void cb_in_3(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data)
{
unsigned short refnum;
struct sk_buff *skb;
int len;
if ((len = capi_select_proto_req(chan, &skb, 0 /*incoming*/)) < 0)
{
printk("capi_select_proto_req failed\n");
return;
}
refnum = last_ref_num++ & 0x7fffU;
chan->s_refnum = refnum;
pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len);
}
/*
* Received disconnect ind on active state
* send disconnect resp
* send msg to user
*/
void cb_disc_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data)
{
struct sk_buff *skb;
int len;
ushort refnum;
isdn_ctrl ictl;
if ((len = capi_disc_resp(chan, &skb)) < 0) {
printk("capi_disc_resp failed\n");
return;
}
refnum = last_ref_num++ & 0x7fffU;
chan->s_refnum = refnum;
pcbit_l2_write(dev, MSG_DISC_RESP, refnum, skb, len);
ictl.command = ISDN_STAT_BHUP;
ictl.driver=dev->id;
ictl.arg=chan->id;
dev->dev_if->statcallb(&ictl);
}
/*
* User HANGUP on active/call proceding state
* send disc.req
*/
void cb_disc_2(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data)
{
struct sk_buff *skb;
int len;
ushort refnum;
if ((len = capi_disc_req(chan->callref, &skb, CAUSE_NORMAL)) < 0)
{
printk("capi_disc_req failed\n");
return;
}
refnum = last_ref_num++ & 0x7fffU;
chan->s_refnum = refnum;
pcbit_l2_write(dev, MSG_DISC_REQ, refnum, skb, len);
}
/*
* Disc confirm received send BHUP
* Problem: when the HL driver sends the disc req itself
* LL receives BHUP
*/
void cb_disc_3(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data)
{
isdn_ctrl ictl;
ictl.command = ISDN_STAT_BHUP;
ictl.driver=dev->id;
ictl.arg=chan->id;
dev->dev_if->statcallb(&ictl);
}
void cb_notdone(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data)
{
}
/*
* send activate b-chan protocol
*/
void cb_selp_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data)
{
struct sk_buff *skb;
int len;
ushort refnum;
if ((len = capi_activate_transp_req(chan, &skb)) < 0)
{
printk("capi_conn_activate_transp_req failed\n");
return;
}
refnum = last_ref_num++ & 0x7fffU;
chan->s_refnum = refnum;
pcbit_l2_write(dev, MSG_ACT_TRANSP_REQ, refnum, skb, len);
}
/*
* Inform User that the B-channel is availiable
*/
void cb_open(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data)
{
isdn_ctrl ictl;
ictl.command = ISDN_STAT_BCONN;
ictl.driver=dev->id;
ictl.arg=chan->id;
dev->dev_if->statcallb(&ictl);
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 1996 Universidade de Lisboa
*
* Writen by Pedro Roque Marques (roque@di.fc.ul.pt)
*
* This software may be used and distributed according to the terms of
* the GNU Public License, incorporated herein by reference.
*/
/*
* Callbacks prototypes for FSM
*
*/
#ifndef CALLBACKS_H
#define CALLBACKS_H
extern void cb_out_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data);
extern void cb_out_2(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data);
extern void cb_out_3(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data);
extern void cb_in_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data);
extern void cb_in_2(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data);
extern void cb_in_3(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data);
extern void cb_disc_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data);
extern void cb_disc_2(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data);
extern void cb_disc_3(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data);
extern void cb_notdone(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data);
extern void cb_selp_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data);
extern void cb_open(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data);
#endif

663
drivers/isdn/pcbit/capi.c Normal file
View File

@ -0,0 +1,663 @@
/*
* Copyright (C) 1996 Universidade de Lisboa
*
* Writen by Pedro Roque Marques (roque@di.fc.ul.pt)
*
* This software may be used and distributed according to the terms of
* the GNU Public License, incorporated herein by reference.
*/
/*
* CAPI encoder/decoder for
* Portugal Telecom CAPI 2.0
*
* Not compatible with the AVM Gmbh. CAPI 2.0
*/
/*
* Documentation:
* - "Common ISDN API - Perfil Português - Versão 2.1",
* Telecom Portugal, Fev 1992.
* - "Common ISDN API - Especificação de protocolos para
* acesso aos canais B", Inesc, Jan 1994.
*/
/*
* TODO: better decoding of Information Elements
* for debug purposes mainly
* encode our number in CallerPN and ConnectedPN
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/tqueue.h>
#include <linux/skbuff.h>
#include <asm/io.h>
#include <asm/string.h>
#include <linux/isdnif.h>
#include "pcbit.h"
#include "edss1.h"
#include "capi.h"
/*
* Encoding of CAPI messages
*
*/
int capi_conn_req(const char * calledPN, struct sk_buff **skb)
{
ushort len;
/*
* length
* AppInfoMask - 2
* BC0 - 3
* BC1 - 1
* Chan - 2
* Keypad - 1
* CPN - 1
* CPSA - 1
* CalledPN - 2 + strlen
* CalledPSA - 1
* rest... - 4
* ----------------
* Total 18 + strlen
*/
len = 18 + strlen(calledPN);
if ((*skb = dev_alloc_skb(len)) == NULL) {
printk(KERN_WARNING "capi_conn_req: alloc_skb failed\n");
return -1;
}
/* InfoElmMask */
*((ushort*) skb_put(*skb, 2)) = AppInfoMask;
/* Bearer Capbility - Mandatory*/
*(skb_put(*skb, 1)) = 2; /* BC0.Length */
*(skb_put(*skb, 1)) = 0x88; /* BC0.Octect3 - Digital Information */
*(skb_put(*skb, 1)) = 0x90; /* BC0.Octect4 - */
/* Bearer Capbility - Optional*/
*(skb_put(*skb, 1)) = 0; /* BC1.Length = 0 */
*(skb_put(*skb, 1)) = 1; /* ChannelID.Length = 1 */
*(skb_put(*skb, 1)) = 0x83; /* Basic Interface - Any Channel */
*(skb_put(*skb, 1)) = 0; /* Keypad.Length = 0 */
*(skb_put(*skb, 1)) = 0; /* CallingPN.Length = 0 */
*(skb_put(*skb, 1)) = 0; /* CallingPSA.Length = 0 */
/* Called Party Number */
*(skb_put(*skb, 1)) = strlen(calledPN) + 1;
*(skb_put(*skb, 1)) = 0x81;
memcpy(skb_put(*skb, strlen(calledPN)), calledPN, strlen(calledPN));
/* '#' */
*(skb_put(*skb, 1)) = 0; /* CalledPSA.Length = 0 */
/* LLC.Length = 0; */
/* HLC0.Length = 0; */
/* HLC1.Length = 0; */
/* UTUS.Length = 0; */
memset(skb_put(*skb, 4), 0, 4);
return len;
}
int capi_conn_resp(struct pcbit_chan* chan, struct sk_buff **skb)
{
if ((*skb = dev_alloc_skb(5)) == NULL) {
printk(KERN_WARNING "capi_conn_resp: alloc_skb failed\n");
return -1;
}
(*skb)->free = 1;
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
*(skb_put(*skb, 1)) = 0x01; /* ACCEPT_CALL */
*(skb_put(*skb, 1)) = 0;
*(skb_put(*skb, 1)) = 0;
return 5;
}
int capi_conn_active_req(struct pcbit_chan* chan, struct sk_buff **skb)
{
/*
* 8 bytes
*/
if ((*skb = dev_alloc_skb(8)) == NULL) {
printk(KERN_WARNING "capi_conn_active_req: alloc_skb failed\n");
return -1;
}
(*skb)->free = 1;
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
#ifdef DEBUG
printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref);
#endif
*(skb_put(*skb, 1)) = 0; /* BC.Length = 0; */
*(skb_put(*skb, 1)) = 0; /* ConnectedPN.Length = 0 */
*(skb_put(*skb, 1)) = 0; /* PSA.Length */
*(skb_put(*skb, 1)) = 0; /* LLC.Length = 0; */
*(skb_put(*skb, 1)) = 0; /* HLC.Length = 0; */
*(skb_put(*skb, 1)) = 0; /* UTUS.Length = 0; */
return 8;
}
int capi_conn_active_resp(struct pcbit_chan* chan, struct sk_buff **skb)
{
/*
* 2 bytes
*/
if ((*skb = dev_alloc_skb(2)) == NULL) {
printk(KERN_WARNING "capi_conn_active_resp: alloc_skb failed\n");
return -1;
}
(*skb)->free = 1;
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
return 2;
}
int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb,
int outgoing)
{
/*
* 18 bytes
*/
if ((*skb = dev_alloc_skb(18)) == NULL) {
printk(KERN_WARNING "capi_select_proto_req: alloc_skb failed\n");
return -1;
}
(*skb)->free = 1;
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
/* Layer2 protocol */
switch (chan->proto) {
case ISDN_PROTO_L2_X75I:
*(skb_put(*skb, 1)) = 0x05; /* LAPB */
break;
case ISDN_PROTO_L2_HDLC:
#ifdef DEBUG
printk(KERN_DEBUG "HDLC\n"); /* HDLC */
#endif
*(skb_put(*skb, 1)) = 0x02;
break;
default:
#ifdef DEBUG
printk(KERN_DEBUG "Transparent\n");
#endif
*(skb_put(*skb, 1)) = 0x03;
break;
}
*(skb_put(*skb, 1)) = (outgoing ? 0x02 : 0x42); /* Don't ask */
*(skb_put(*skb, 1)) = 0x00;
*((ushort *) skb_put(*skb, 2)) = MRU;
*(skb_put(*skb, 1)) = 0x08; /* Modulo */
*(skb_put(*skb, 1)) = 0x07; /* Max Window */
*(skb_put(*skb, 1)) = 0x01; /* No Layer3 Protocol */
/*
* 2 - layer3 MTU [10]
* - Modulo [12]
* - Window
* - layer1 proto [14]
* - bitrate
* - sub-channel [16]
* - layer1dataformat [17]
*/
memset(skb_put(*skb, 8), 0, 8);
return 18;
}
int capi_activate_transp_req(struct pcbit_chan *chan, struct sk_buff **skb)
{
if ((*skb = dev_alloc_skb(7)) == NULL) {
printk(KERN_WARNING "capi_activate_transp_req: alloc_skb failed\n");
return -1;
}
(*skb)->free = 1;
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
*(skb_put(*skb, 1)) = chan->layer2link; /* Layer2 id */
*(skb_put(*skb, 1)) = 0x00; /* Transmit by default */
*((ushort *) skb_put(*skb, 2)) = MRU;
*(skb_put(*skb, 1)) = 0x01; /* Enables reception*/
return 7;
}
int capi_tdata_req(struct pcbit_chan* chan, struct sk_buff *skb)
{
ushort data_len;
/*
* callref - 2
* layer2link - 1
* wBlockLength - 2
* data - 4
* sernum - 1
*/
data_len = skb->len;
skb_push(skb, 10);
*((u16 *) (skb->data)) = chan->callref;
skb->data[2] = chan->layer2link;
*((u16 *) (skb->data + 3)) = data_len;
chan->s_refnum = (chan->s_refnum + 1) % 8;
*((u32 *) (skb->data + 5)) = chan->s_refnum;
skb->data[9] = 0; /* HDLC frame number */
return 10;
}
int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff ** skb)
{
if ((*skb = dev_alloc_skb(4)) == NULL) {
printk(KERN_WARNING "capi_tdata_resp: alloc_skb failed\n");
return -1;
}
(*skb)->free = 1;
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
*(skb_put(*skb, 1)) = chan->layer2link;
*(skb_put(*skb, 1)) = chan->r_refnum;
return (*skb)->len;
}
int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause)
{
if ((*skb = dev_alloc_skb(6)) == NULL) {
printk(KERN_WARNING "capi_disc_req: alloc_skb failed\n");
return -1;
}
(*skb)->free = 1;
*((ushort*) skb_put(*skb, 2) ) = callref;
*(skb_put(*skb, 1)) = 2; /* Cause.Length = 2; */
*(skb_put(*skb, 1)) = 0x80;
*(skb_put(*skb, 1)) = 0x80 | cause;
/*
* Change it: we should send 'Sic transit gloria Mundi' here ;-)
*/
*(skb_put(*skb, 1)) = 0; /* UTUS.Length = 0; */
return 6;
}
int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb)
{
if ((*skb = dev_alloc_skb(2)) == NULL) {
printk(KERN_WARNING "capi_disc_resp: alloc_skb failed\n");
return -1;
}
(*skb)->free = 1;
*((ushort*) skb_put(*skb, 2)) = chan->callref;
return 2;
}
/*
* Decoding of CAPI messages
*
*/
int capi_decode_conn_ind(struct pcbit_chan * chan,
struct sk_buff *skb,
struct callb_data *info)
{
int CIlen, len;
/* Call Reference [CAPI] */
chan->callref = *((ushort*) skb->data);
skb_pull(skb, 2);
#ifdef DEBUG
printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref);
#endif
/* Channel Identification */
/* Expect
Len = 1
Octect 3 = 0100 10CC - [ 7 Basic, 4 , 2-1 chan ]
*/
CIlen = skb->data[0];
#ifdef DEBUG
if (CIlen == 1) {
if ( ((skb->data[1]) & 0xFC) == 0x48 )
printk(KERN_DEBUG "decode_conn_ind: chan ok\n");
printk(KERN_DEBUG "phyChan = %d\n", skb->data[1] & 0x03);
}
else
printk(KERN_DEBUG "conn_ind: CIlen = %d\n", CIlen);
#endif
skb_pull(skb, CIlen + 1);
/* Calling Party Number */
/* An "aditional service" as far as Portugal Telecom is concerned */
len = skb->data[0];
if (len > 0) {
int count = 1;
#ifdef DEBUG
printk(KERN_DEBUG "CPN: Octect 3 %02x\n", skb->data[1]);
#endif
if ((skb->data[1] & 0x80) == 0)
count = 2;
if (!(info->data.setup.CallingPN = kmalloc(len - count + 1, GFP_ATOMIC)))
return -1;
memcpy(info->data.setup.CallingPN, skb->data + count + 1,
len - count);
info->data.setup.CallingPN[len - count] = 0;
}
else {
info->data.setup.CallingPN = NULL;
printk(KERN_DEBUG "NULL CallingPN\n");
}
skb_pull(skb, len + 1);
/* Calling Party Subaddress */
skb_pull(skb, skb->data[0] + 1);
/* Called Party Number */
len = skb->data[0];
if (len > 0) {
int count = 1;
if ((skb->data[1] & 0x80) == 0)
count = 2;
if (!(info->data.setup.CalledPN = kmalloc(len - count + 1, GFP_ATOMIC)))
return -1;
memcpy(info->data.setup.CalledPN, skb->data + count + 1,
len - count);
info->data.setup.CalledPN[len - count] = 0;
}
else {
info->data.setup.CalledPN = NULL;
printk(KERN_DEBUG "NULL CalledPN\n");
}
skb_pull(skb, len + 1);
/* Called Party Subaddress */
skb_pull(skb, skb->data[0] + 1);
/* LLC */
skb_pull(skb, skb->data[0] + 1);
/* HLC */
skb_pull(skb, skb->data[0] + 1);
/* U2U */
skb_pull(skb, skb->data[0] + 1);
return 0;
}
/*
* returns errcode
*/
int capi_decode_conn_conf(struct pcbit_chan * chan, struct sk_buff *skb,
int *complete)
{
int errcode;
chan->callref = *((ushort *) skb->data); /* Update CallReference */
skb_pull(skb, 2);
errcode = *((ushort *) skb->data); /* read errcode */
skb_pull(skb, 2);
*complete = *(skb->data);
skb_pull(skb, 1);
/* FIX ME */
/* This is actualy a firmware bug */
if (!*complete)
{
printk(KERN_DEBUG "complete=%02x\n", *complete);
*complete = 1;
}
/* Optional Bearer Capability */
skb_pull(skb, *(skb->data) + 1);
/* Channel Identification */
skb_pull(skb, *(skb->data) + 1);
/* High Layer Compatibility follows */
skb_pull(skb, *(skb->data) + 1);
return errcode;
}
int capi_decode_conn_actv_ind(struct pcbit_chan * chan, struct sk_buff *skb)
{
ushort len;
#ifdef DEBUG
char str[32];
#endif
/* Yet Another Bearer Capability */
skb_pull(skb, *(skb->data) + 1);
/* Connected Party Number */
len=*(skb->data);
#ifdef DEBUG
if (len > 1 && len < 31) {
memcpy(str, skb->data + 2, len - 1);
str[len] = 0;
printk(KERN_DEBUG "Connected Party Number: %s\n", str);
}
else
printk(KERN_DEBUG "actv_ind CPN len = %d\n", len);
#endif
skb_pull(skb, len + 1);
/* Connected Subaddress */
skb_pull(skb, *(skb->data) + 1);
/* Low Layer Capability */
skb_pull(skb, *(skb->data) + 1);
/* High Layer Capability */
skb_pull(skb, *(skb->data) + 1);
return 0;
}
int capi_decode_conn_actv_conf(struct pcbit_chan * chan, struct sk_buff *skb)
{
ushort errcode;
errcode = *((ushort*) skb->data);
skb_pull(skb, 2);
/* Channel Identification
skb_pull(skb, skb->data[0] + 1);
*/
return errcode;
}
int capi_decode_sel_proto_conf(struct pcbit_chan *chan, struct sk_buff *skb)
{
ushort errcode;
chan->layer2link = *(skb->data);
skb_pull(skb, 1);
errcode = *((ushort*) skb->data);
skb_pull(skb, 2);
return errcode;
}
int capi_decode_actv_trans_conf(struct pcbit_chan *chan, struct sk_buff *skb)
{
ushort errcode;
if (chan->layer2link != *(skb->data) )
printk("capi_decode_actv_trans_conf: layer2link doesn't match\n");
skb_pull(skb, 1);
errcode = *((ushort*) skb->data);
skb_pull(skb, 2);
return errcode;
}
int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb)
{
ushort len;
#ifdef DEBUG
int i;
#endif
/* Cause */
len = *(skb->data);
skb_pull(skb, 1);
#ifdef DEBUG
for (i=0; i<len; i++)
printk(KERN_DEBUG "Cause Octect %d: %02x\n", i+3,
*(skb->data + i));
#endif
skb_pull(skb, len);
return 0;
}
int capi_decode_disc_conf(struct pcbit_chan *chan, struct sk_buff *skb)
{
ushort errcode;
errcode = *((ushort*) skb->data);
skb_pull(skb, 2);
return errcode;
}
#ifdef DEBUG
int capi_decode_debug_188(u_char *hdr, ushort hdrlen)
{
char str[64];
int len;
len = hdr[0];
if (len < 64 && len == hdrlen - 1) {
memcpy(str, hdr + 1, hdrlen - 1);
str[hdrlen - 1] = 0;
printk("%s\n", str);
}
else
printk("debug message incorrect\n");
return 0;
}
#endif

90
drivers/isdn/pcbit/capi.h Normal file
View File

@ -0,0 +1,90 @@
/*
* Copyright (C) 1996 Universidade de Lisboa
*
* Writen by Pedro Roque Marques (roque@di.fc.ul.pt)
*
* This software may be used and distributed according to the terms of
* the GNU Public License, incorporated herein by reference.
*/
/*
* CAPI encode/decode prototypes and defines
*/
#ifndef CAPI_H
#define CAPI_H
#define REQ_CAUSE 0x01
#define REQ_DISPLAY 0x04
#define REQ_USER_TO_USER 0x08
#define AppInfoMask REQ_CAUSE|REQ_DISPLAY|REQ_USER_TO_USER
/* Connection Setup */
extern int capi_conn_req(const char * calledPN, struct sk_buff **buf);
extern int capi_decode_conn_conf(struct pcbit_chan * chan, struct sk_buff *skb,
int *complete);
extern int capi_decode_conn_ind(struct pcbit_chan * chan, struct sk_buff *skb,
struct callb_data *info);
extern int capi_conn_resp(struct pcbit_chan* chan, struct sk_buff **skb);
extern int capi_conn_active_req(struct pcbit_chan* chan, struct sk_buff **skb);
extern int capi_decode_conn_actv_conf(struct pcbit_chan * chan,
struct sk_buff *skb);
extern int capi_decode_conn_actv_ind(struct pcbit_chan * chan,
struct sk_buff *skb);
extern int capi_conn_active_resp(struct pcbit_chan* chan,
struct sk_buff **skb);
/* Data */
extern int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb,
int outgoing);
extern int capi_decode_sel_proto_conf(struct pcbit_chan *chan,
struct sk_buff *skb);
extern int capi_activate_transp_req(struct pcbit_chan *chan,
struct sk_buff **skb);
extern int capi_decode_actv_trans_conf(struct pcbit_chan *chan,
struct sk_buff *skb);
extern int capi_tdata_req(struct pcbit_chan* chan, struct sk_buff *skb);
extern int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff ** skb);
/* Connection Termination */
extern int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause);
extern int capi_decode_disc_conf(struct pcbit_chan *chan, struct sk_buff *skb);
extern int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb);
extern int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb);
#ifdef DEBUG
extern int capi_decode_debug_188(u_char *hdr, ushort hdrlen);
#endif
extern __inline__
struct pcbit_chan *
capi_channel(struct pcbit_dev *dev, struct sk_buff *skb)
{
ushort callref;
callref = *((ushort*) skb->data);
skb_pull(skb, 2);
if (dev->b1->callref == callref)
return dev->b1;
else if (dev->b2->callref == callref)
return dev->b2;
return NULL;
}
#endif

1137
drivers/isdn/pcbit/drv.c Normal file

File diff suppressed because it is too large Load Diff

333
drivers/isdn/pcbit/edss1.c Normal file
View File

@ -0,0 +1,333 @@
/*
* Copyright (C) 1996 Universidade de Lisboa
*
* Writen by Pedro Roque Marques (roque@di.fc.ul.pt)
*
* This software may be used and distributed according to the terms of
* the GNU Public License, incorporated herein by reference.
*/
/*
* DSS.1 Finite State Machine
* base: ITU-T Rec Q.931
*/
/*
* TODO: complete the FSM
* move state/event descriptions to a user space logger
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/tqueue.h>
#include <linux/skbuff.h>
#include <linux/timer.h>
#include <asm/io.h>
#include <linux/isdnif.h>
#include "pcbit.h"
#include "edss1.h"
#include "layer2.h"
#include "callbacks.h"
extern void pcbit_state_change(struct pcbit_dev *, struct pcbit_chan *,
unsigned short i, unsigned short ev,
unsigned short f);
extern struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS];
char * isdn_state_table[] = {
"Closed",
"Call initiated",
"Overlap sending",
"Outgoing call proceeding",
"NOT DEFINED",
"Call delivered",
"Call present",
"Call received",
"Connect request",
"Incoming call proceeding",
"Active",
"Disconnect request",
"Disconnect indication",
"NOT DEFINED",
"NOT DEFINED",
"Suspend request",
"NOT DEFINED",
"Resume request",
"NOT DEFINED",
"Release Request",
"NOT DEFINED",
"NOT DEFINED",
"NOT DEFINED",
"NOT DEFINED",
"NOT DEFINED",
"Overlap receiving",
"Select protocol on B-Channel",
"Activate B-channel protocol"
};
#ifdef DEBUG_ERRS
static
struct CauseValue {
byte nr;
char *descr;
} cvlist[]={
{0x01,"Unallocated (unassigned) number"},
{0x02,"No route to specified transit network"},
{0x03,"No route to destination"},
{0x04,"Send special information tone"},
{0x05,"Misdialled trunk prefix"},
{0x06,"Channel unacceptable"},
{0x07,"Channel awarded and being delivered in an established channel"},
{0x08,"Preemption"},
{0x09,"Preemption - circuit reserved for reuse"},
{0x10,"Normal call clearing"},
{0x11,"User busy"},
{0x12,"No user responding"},
{0x13,"No answer from user (user alerted)"},
{0x14,"Subscriber absent"},
{0x15,"Call rejected"},
{0x16,"Number changed"},
{0x1a,"non-selected user clearing"},
{0x1b,"Destination out of order"},
{0x1c,"Invalid number format (address incomplete)"},
{0x1d,"Facility rejected"},
{0x1e,"Response to Status enuiry"},
{0x1f,"Normal, unspecified"},
{0x22,"No circuit/channel available"},
{0x26,"Network out of order"},
{0x27,"Permanent frame mode connection out-of-service"},
{0x28,"Permanent frame mode connection operational"},
{0x29,"Temporary failure"},
{0x2a,"Switching equipment congestion"},
{0x2b,"Access information discarded"},
{0x2c,"Requested circuit/channel not available"},
{0x2e,"Precedence call blocked"},
{0x2f,"Resource unavailable, unspecified"},
{0x31,"Quality of service unavailable"},
{0x32,"Requested facility not subscribed"},
{0x35,"Outgoing calls barred within CUG"},
{0x37,"Incoming calls barred within CUG"},
{0x39,"Bearer capability not auhorized"},
{0x3a,"Bearer capability not presently available"},
{0x3e,"Inconsistency in designated outgoing access information and subscriber class"},
{0x3f,"Service or option not available, unspecified"},
{0x41,"Bearer capability not implemented"},
{0x42,"Channel type not implemented"},
{0x43,"Requested facility not implemented"},
{0x44,"Only restricted digital information bearer capability is available"},
{0x4f,"Service or option not implemented"},
{0x51,"Invalid call reference value"},
{0x52,"Identified channel does not exist"},
{0x53,"A suspended call exists, but this call identity does not"},
{0x54,"Call identity in use"},
{0x55,"No call suspended"},
{0x56,"Call having the requested call identity has been cleared"},
{0x57,"User not member of CUG"},
{0x58,"Incompatible destination"},
{0x5a,"Non-existent CUG"},
{0x5b,"Invalid transit network selection"},
{0x5f,"Invalid message, unspecified"},
{0x60,"Mandatory information element is missing"},
{0x61,"Message type non-existent or not implemented"},
{0x62,"Message not compatible with call state or message type non-existent or not implemented"},
{0x63,"Information element/parameter non-existent or not implemented"},
{0x64,"Invalid information element contents"},
{0x65,"Message not compatible with call state"},
{0x66,"Recovery on timer expiry"},
{0x67,"Parameter non-existent or not implemented - passed on"},
{0x6e,"Message with unrecognized parameter discarded"},
{0x6f,"Protocol error, unspecified"},
{0x7f,"Interworking, unspecified"}
};
#endif
static struct isdn_event_desc {
unsigned short ev;
char * desc;
} isdn_event_table [] = {
{EV_USR_SETUP_REQ, "CC->L3: Setup Request"},
{EV_USR_SETUP_RESP, "CC->L3: Setup Response"},
{EV_USR_PROCED_REQ, "CC->L3: Proceeding Request"},
{EV_USR_RELEASE_REQ, "CC->L3: Release Request"},
{EV_NET_SETUP, "NET->TE: setup "},
{EV_NET_CALL_PROC, "NET->TE: call proceding"},
{EV_NET_SETUP_ACK, "NET->TE: setup acknowlegde (more info needed)"},
{EV_NET_CONN, "NET->TE: connect"},
{EV_NET_CONN_ACK, "NET->TE: connect aknowlegde"},
{EV_NET_DISC, "NET->TE: disconnect indication"},
{EV_NET_RELEASE, "NET->TE: release"},
{EV_NET_RELEASE_COMP, "NET->TE: release complete"},
{EV_NET_SELP_RESP, "Board: Select B-channel protocol ack"},
{EV_NET_ACTV_RESP, "Board: Activate B-channel protocol ack"},
{EV_TIMER, "Timeout"},
{0, "NULL"}
};
char * strisdnevent(ushort ev)
{
struct isdn_event_desc * entry;
for (entry = isdn_event_table; entry->ev; entry++)
if (entry->ev == ev)
break;
return entry->desc;
}
/*
* Euro ISDN finite state machine
*/
static struct fsm_timer_entry fsm_timers[] = {
{ST_CALL_PROC, 10},
{ST_DISC_REQ, 2},
{ST_ACTIVE_SELP, 5},
{ST_ACTIVE_ACTV, 5},
{ST_INCM_PROC, 10},
{ST_CONN_REQ, 2},
{0xff, 0}
};
static struct fsm_entry fsm_table[] = {
/* Connect Phase */
/* Outgoing */
{ST_NULL, ST_CALL_INIT, EV_USR_SETUP_REQ, cb_out_1},
{ST_CALL_INIT, ST_OVER_SEND, EV_NET_SETUP_ACK, cb_notdone},
{ST_CALL_INIT, ST_CALL_PROC, EV_NET_CALL_PROC, NULL},
{ST_CALL_INIT, ST_NULL, EV_NET_DISC, cb_out_2},
{ST_CALL_PROC, ST_ACTIVE_SELP, EV_NET_CONN, cb_out_2},
{ST_CALL_PROC, ST_NULL, EV_NET_DISC, cb_disc_1},
{ST_CALL_PROC, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
/* Incomming */
{ST_NULL, ST_CALL_PRES, EV_NET_SETUP, NULL},
{ST_CALL_PRES, ST_INCM_PROC, EV_USR_PROCED_REQ, cb_in_1},
{ST_CALL_PRES, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
{ST_INCM_PROC, ST_CONN_REQ, EV_USR_SETUP_RESP, cb_in_2},
{ST_INCM_PROC, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
{ST_CONN_REQ, ST_ACTIVE_SELP, EV_NET_CONN_ACK, cb_in_3},
/* Active */
{ST_ACTIVE, ST_NULL, EV_NET_DISC, cb_disc_1},
{ST_ACTIVE, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
{ST_ACTIVE, ST_NULL, EV_NET_RELEASE, cb_disc_3},
/* Disconnect */
{ST_DISC_REQ, ST_NULL, EV_NET_DISC, cb_disc_1},
{ST_DISC_REQ, ST_NULL, EV_NET_RELEASE, cb_disc_3},
/* protocol selection */
{ST_ACTIVE_SELP, ST_ACTIVE_ACTV, EV_NET_SELP_RESP, cb_selp_1},
{ST_ACTIVE_SELP, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
{ST_ACTIVE_ACTV, ST_ACTIVE, EV_NET_ACTV_RESP, cb_open},
{ST_ACTIVE_ACTV, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
/* Timers */
{ST_CALL_PROC, ST_DISC_REQ, EV_TIMER, cb_disc_2},
{ST_DISC_REQ, ST_NULL, EV_TIMER, cb_disc_3},
{ST_ACTIVE_SELP, ST_DISC_REQ, EV_TIMER, cb_disc_2},
{ST_ACTIVE_ACTV, ST_DISC_REQ, EV_TIMER, cb_disc_2},
{ST_INCM_PROC, ST_DISC_REQ, EV_TIMER, cb_disc_2},
{ST_CONN_REQ, ST_CONN_REQ, EV_TIMER, cb_in_2},
{0xff, 0, 0, NULL}
};
static void pcbit_fsm_timer(unsigned long data)
{
struct pcbit_dev *dev;
struct pcbit_chan *chan;
chan = (struct pcbit_chan *) data;
del_timer(&chan->fsm_timer);
chan->fsm_timer.function = NULL;
dev = chan2dev(chan);
if (dev == NULL) {
printk(KERN_WARNING "pcbit: timer for unkown device\n");
return;
}
pcbit_fsm_event(dev, chan, EV_TIMER, NULL);
}
void pcbit_fsm_event(struct pcbit_dev *dev, struct pcbit_chan *chan,
unsigned short event, struct callb_data *data)
{
struct fsm_entry * action;
struct fsm_timer_entry *tentry;
unsigned long flags;
save_flags(flags);
cli();
if (chan->fsm_timer.function) {
del_timer(&chan->fsm_timer);
chan->fsm_timer.function = NULL;
}
for (action = fsm_table; action->init != 0xff; action++)
if (action->init == chan->fsm_state && action->event == event)
break;
if (action->init == 0xff) {
printk(KERN_DEBUG "fsm error: event %x on state %x\n",
event, chan->fsm_state);
return;
}
chan->fsm_state = action->final;
pcbit_state_change(dev, chan, action->init, event, action->final);
for (tentry = fsm_timers; tentry->init != 0xff; tentry++)
if (tentry->init == chan->fsm_state)
break;
if (tentry->init != 0xff) {
init_timer(&chan->fsm_timer);
chan->fsm_timer.function = &pcbit_fsm_timer;
chan->fsm_timer.data = (ulong) chan;
chan->fsm_timer.expires = jiffies + tentry->timeout * HZ;
add_timer(&chan->fsm_timer);
}
restore_flags(flags);
if (action->callb)
action->callb(dev, chan, data);
}

101
drivers/isdn/pcbit/edss1.h Normal file
View File

@ -0,0 +1,101 @@
/*
* Copyright (C) 1996 Universidade de Lisboa
*
* Writen by Pedro Roque Marques (roque@di.fc.ul.pt)
*
* This software may be used and distributed according to the terms of
* the GNU Public License, incorporated herein by reference.
*/
/*
* DSS.1 module definitions
*/
#ifndef EDSS1_H
#define EDSS1_H
/* ISDN states */
#define ST_NULL 0
#define ST_CALL_INIT 1 /* Call initiated */
#define ST_OVER_SEND 2 /* Overlap sending - Requests More Info 4 call */
#define ST_CALL_PROC 3 /* Call Procceding */
#define ST_CALL_DELV 4
#define ST_CALL_PRES 6 /* Call Present - Received CONN.IND */
#define ST_CALL_RECV 7 /* Alerting sent */
#define ST_CONN_REQ 8 /* Answered - wainting 4 CONN.CONF */
#define ST_INCM_PROC 9
#define ST_ACTIVE 10
#define ST_DISC_REQ 11
#define ST_DISC_IND 12
#define ST_SUSP_REQ 15
#define ST_RESM_REQ 17
#define ST_RELS_REQ 19
#define ST_OVER_RECV 25
#define ST_ACTIVE_SELP 26 /* Select protocol on B-Channel */
#define ST_ACTIVE_ACTV 27 /* Activate B-channel protocol */
#define MAX_STATE ST_ACTIVE_ACTV
#define EV_NULL 0
#define EV_USR_SETUP_REQ 1
#define EV_USR_SETUP_RESP 2
#define EV_USR_PROCED_REQ 3
#define EV_USR_RELEASE_REQ 4
#define EV_USR_REJECT_REQ 4
#define EV_NET_SETUP 16
#define EV_NET_CALL_PROC 17
#define EV_NET_SETUP_ACK 18
#define EV_NET_CONN 19
#define EV_NET_CONN_ACK 20
#define EV_NET_SELP_RESP 21
#define EV_NET_ACTV_RESP 22
#define EV_NET_DISC 23
#define EV_NET_RELEASE 24
#define EV_NET_RELEASE_COMP 25
#define EV_TIMER 26
#define EV_ERROR 32
/*
* Cause values
* only the ones we use
*/
#define CAUSE_NORMAL 0x10U
#define CAUSE_NOCHAN 0x22U
struct callb_data {
unsigned short type;
union {
struct ConnInfo {
char *CalledPN;
char *CallingPN;
} setup;
unsigned short cause;
} data;
};
struct fsm_entry {
unsigned short init;
unsigned short final;
unsigned short event;
void (*callb)(struct pcbit_dev *, struct pcbit_chan *, struct callb_data*);
};
struct fsm_timer_entry {
unsigned short init;
unsigned long timeout; /* in seconds */
};
extern void pcbit_fsm_event(struct pcbit_dev *, struct pcbit_chan *,
unsigned short event, struct callb_data *);
#endif

859
drivers/isdn/pcbit/layer2.c Normal file
View File

@ -0,0 +1,859 @@
/*
* Copyright (C) 1996 Universidade de Lisboa
*
* Writen by Pedro Roque Marques (roque@di.fc.ul.pt)
*
* This software may be used and distributed according to the terms of
* the GNU Public License, incorporated herein by reference.
*/
/*
* PCBIT-D low-layer interface
*/
/*
* Based on documentation provided by Inesc:
* - "Interface com bus do PC para o PCBIT e PCBIT-D", Inesc, Jan 93
*/
/*
* TODO: better handling of errors
* re-write/remove debug printks
*/
#define __NO_VERSION__
#ifdef MODULE
#define INCLUDE_INLINE_FUNCS
#endif
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <linux/tqueue.h>
#include <linux/mm.h>
#include <linux/skbuff.h>
#include <linux/isdnif.h>
#include <asm/system.h>
#include <asm/io.h>
#include "pcbit.h"
#include "layer2.h"
#include "edss1.h"
#undef DEBUG_FRAG
/*
* task queue struct
*/
struct tq_struct *tq_delivery=NULL;
static void do_pcbit_bh(task_queue *list)
{
run_task_queue(list);
}
struct tq_struct run_delivery= {
0, 0, (void *)(void *) do_pcbit_bh, &tq_delivery,
};
/*
* Layer 3 packet demultiplexer
* drv.c
*/
extern void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg,
struct sk_buff * skb,
ushort hdr_len, ushort refnum);
/*
* Prototypes
*/
void pcbit_deliver(void * data);
static void pcbit_transmit(struct pcbit_dev * dev);
static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack);
static void pcbit_frame_read(struct pcbit_dev * dev, unsigned char read_seq);
static void pcbit_l2_error(struct pcbit_dev *dev);
static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info);
static void pcbit_l2_err_recover(unsigned long data);
static void pcbit_firmware_bug(struct pcbit_dev * dev);
static void pcbit_sched_delivery(struct pcbit_dev *dev)
{
queue_task_irq_off(&dev->qdelivery, &tq_delivery);
queue_task_irq_off(&run_delivery, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
/*
* Called from layer3
*/
int pcbit_l2_write(struct pcbit_dev * dev, ulong msg, ushort refnum,
struct sk_buff *skb, unsigned short hdr_len)
{
struct frame_buf * frame, * ptr;
unsigned long flags;
if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) {
dev_kfree_skb(skb, FREE_WRITE);
return -1;
}
if ( (frame = (struct frame_buf *) kmalloc(sizeof(struct frame_buf),
GFP_ATOMIC)) == NULL ) {
printk(KERN_WARNING "pcbit_2_write: kmalloc failed\n");
dev_kfree_skb(skb, FREE_WRITE);
return -1;
}
frame->msg = msg;
frame->refnum = refnum;
frame->copied = 0;
frame->hdr_len = hdr_len;
if (skb) {
frame->dt_len = skb->len - hdr_len;
if (frame->dt_len == 0)
skb->lock++;
}
else
frame->dt_len = 0;
frame->skb = skb;
frame->next = NULL;
save_flags(flags);
cli();
if (dev->write_queue == NULL) {
dev->write_queue = frame;
restore_flags(flags);
pcbit_transmit(dev);
}
else {
for(ptr=dev->write_queue; ptr->next; ptr=ptr->next);
ptr->next = frame;
restore_flags(flags);
}
return 0;
}
static __inline__ void pcbit_tx_update(struct pcbit_dev *dev, ushort len)
{
u_char info;
dev->send_seq = (dev->send_seq + 1) % 8;
dev->fsize[dev->send_seq] = len;
info = 0;
info |= dev->rcv_seq << 3;
info |= dev->send_seq;
writeb(info, dev->sh_mem + BANK4);
}
/*
* called by interrupt service routine or by write_2
*/
static void pcbit_transmit(struct pcbit_dev * dev)
{
struct frame_buf * frame = NULL;
unsigned char unacked;
int flen; /* fragment frame length including all headers */
int totlen; /* non-fragmented frame length */
int free;
int count, cp_len;
unsigned long flags;
unsigned short tt;
if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
return;
unacked = (dev->send_seq + (8 - dev->unack_seq) ) & 0x07;
if (dev->free > 16 && dev->write_queue && unacked < 7) {
save_flags(flags);
cli();
if (!dev->w_busy)
dev->w_busy = 1;
else
{
restore_flags(flags);
return;
}
restore_flags(flags);
frame = dev->write_queue;
free = dev->free;
if (frame->copied == 0) {
/* Type 0 frame */
struct msg_fmt * msg;
if (frame->skb)
totlen = FRAME_HDR_LEN + PREHDR_LEN + frame->skb->len;
else
totlen = FRAME_HDR_LEN + PREHDR_LEN;
flen = MIN(totlen, free);
msg = (struct msg_fmt *) &(frame->msg);
/*
* Board level 2 header
*/
pcbit_writew(dev, flen - FRAME_HDR_LEN);
pcbit_writeb(dev, msg->cpu);
pcbit_writeb(dev, msg->proc);
/* TH */
pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
/* TD */
pcbit_writew(dev, frame->dt_len);
/*
* Board level 3 fixed-header
*/
/* LEN = TH */
pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
/* XX */
pcbit_writew(dev, 0);
/* C + S */
pcbit_writeb(dev, msg->cmd);
pcbit_writeb(dev, msg->scmd);
/* NUM */
pcbit_writew(dev, frame->refnum);
count = FRAME_HDR_LEN + PREHDR_LEN;
}
else {
/* Type 1 frame */
totlen = 2 + (frame->skb->len - frame->copied);
flen = MIN(totlen, free);
/* TT */
tt = ((ushort) (flen - 2)) | 0x8000U; /* Type 1 */
pcbit_writew(dev, tt);
count = 2;
}
if (frame->skb) {
cp_len = MIN(frame->skb->len - frame->copied,
flen - count);
memcpy_topcbit(dev, frame->skb->data + frame->copied,
cp_len);
frame->copied += cp_len;
}
/* bookeeping */
dev->free -= flen;
pcbit_tx_update(dev, flen);
save_flags(flags);
cli();
if (frame->skb == NULL || frame->copied == frame->skb->len) {
dev->write_queue = frame->next;
if (frame->skb != NULL) {
/* free frame */
dev_kfree_skb(frame->skb, FREE_WRITE);
}
kfree(frame);
}
dev->w_busy = 0;
restore_flags(flags);
}
#ifdef DEBUG
else
printk(KERN_DEBUG "unacked %d free %d write_queue %s\n",
unacked, dev->free, dev->write_queue ? "not empty" :
"empty");
#endif
}
/*
* deliver a queued frame to the upper layer
*/
void pcbit_deliver(void * data)
{
struct frame_buf *frame;
unsigned long flags;
struct msg_fmt msg;
struct pcbit_dev *dev = (struct pcbit_dev *) data;
save_flags(flags);
cli();
/* get frame from queue */
if (!(frame=dev->read_queue)) {
restore_flags(flags);
return;
}
dev->read_queue = frame->next;
restore_flags(flags);
msg.cpu = 0;
msg.proc = 0;
msg.cmd = frame->skb->data[2];
msg.scmd = frame->skb->data[3];
frame->refnum = *((ushort*) frame->skb->data + 4);
frame->msg = *((ulong*) &msg);
skb_pull(frame->skb, 6);
pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len,
frame->refnum);
kfree(frame);
}
/*
* Reads BANK 2 & Reassembles
*/
static void pcbit_receive(struct pcbit_dev * dev)
{
unsigned short tt;
u_char cpu, proc;
struct frame_buf * frame = NULL;
unsigned long flags;
u_char type1;
if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
return;
tt = pcbit_readw(dev);
if ((tt & 0x7fffU) > 511) {
printk(KERN_INFO "pcbit: invalid frame length -> TT=%04x\n",
tt);
pcbit_l2_error(dev);
return;
}
if (!(tt & 0x8000U))
{ /* Type 0 */
type1 = 0;
if (dev->read_frame) {
printk(KERN_DEBUG "pcbit_receive: Type 0 frame and read_frame != NULL\n");
#if 0
pcbit_l2_error(dev);
return;
#else
/* discard previous queued frame */
if (dev->read_frame->skb) {
dev->read_frame->skb->free = 1;
kfree_skb(dev->read_frame->skb, FREE_READ);
}
kfree(dev->read_frame);
dev->read_frame = NULL;
#endif
}
frame = kmalloc(sizeof(struct frame_buf), GFP_ATOMIC);
if (frame == NULL) {
printk(KERN_WARNING "kmalloc failed\n");
return;
}
memset(frame, 0, sizeof(struct frame_buf));
cpu = pcbit_readb(dev);
proc = pcbit_readb(dev);
if (cpu != 0x06 && cpu != 0x02)
{
printk (KERN_DEBUG "pcbit: invalid cpu value\n");
kfree(frame);
pcbit_l2_error(dev);
return;
}
/*
* we discard cpu & proc on receiving
* but we read it to update the pointer
*/
frame->hdr_len = pcbit_readw(dev);
frame->dt_len = pcbit_readw(dev);
/*
* 0 sized packet
* I don't know if they are an error or not...
* But they are very frequent
* Not documented
*/
if (frame->hdr_len == 0) {
kfree(frame);
#ifdef DEBUG
printk(KERN_DEBUG "0 sized frame\n");
#endif
pcbit_firmware_bug(dev);
return;
}
/* sanity check the length values */
if (frame->hdr_len > 1024 || frame->dt_len > 2048)
{
#ifdef DEBUG
printk(KERN_DEBUG "length problem: ");
printk(KERN_DEBUG "TH=%04x TD=%04x\n",
frame->hdr_len,
frame->dt_len);
#endif
pcbit_l2_error(dev);
kfree(frame);
return;
}
/* miminum frame read */
frame->skb = dev_alloc_skb(frame->hdr_len + frame->dt_len +
((frame->hdr_len + 15) & ~15));
if (!frame->skb) {
printk(KERN_DEBUG "pcbit_receive: out of memmory\n");
kfree(frame);
return;
}
/* 16 byte aligment for IP */
if (frame->dt_len)
skb_reserve(frame->skb, (frame->hdr_len + 15) & ~15);
}
else {
/* Type 1 */
type1 = 1;
tt &= 0x7fffU;
if (!(frame = dev->read_frame)) {
printk("Type 1 frame and no frame queued\n");
#if 1
/* usualy after an error: toss frame */
dev->readptr += tt;
if (dev->readptr > dev->sh_mem + BANK2 + BANKLEN)
dev->readptr -= BANKLEN;
#else
pcbit_l2_error(dev);
#endif
return;
}
}
memcpy_frompcbit(dev, skb_put(frame->skb, tt), tt);
frame->copied += tt;
if (frame->copied == frame->hdr_len + frame->dt_len) {
save_flags(flags);
cli();
if (type1) {
dev->read_frame = NULL;
}
if (dev->read_queue) {
struct frame_buf *ptr;
for(ptr=dev->read_queue;ptr->next;ptr=ptr->next);
ptr->next = frame;
}
else
dev->read_queue = frame;
pcbit_sched_delivery(dev);
restore_flags(flags);
}
else {
save_flags(flags);
cli();
dev->read_frame = frame;
restore_flags(flags);
}
}
/*
* The board sends 0 sized frames
* They are TDATA_CONFs that get messed up somehow
* gotta send a fake acknowledment to the upper layer somehow
*/
static __inline__ void pcbit_fake_conf(struct pcbit_dev *dev, struct pcbit_chan * chan)
{
isdn_ctrl ictl;
if (chan->queued) {
chan->queued--;
ictl.driver = dev->id;
ictl.command = ISDN_STAT_BSENT;
ictl.arg = chan->id;
dev->dev_if->statcallb(&ictl);
}
}
static void pcbit_firmware_bug(struct pcbit_dev * dev)
{
struct pcbit_chan *chan;
chan = dev->b1;
if (chan->fsm_state == ST_ACTIVE) {
pcbit_fake_conf(dev, chan);
}
chan = dev->b2;
if (chan->fsm_state == ST_ACTIVE) {
pcbit_fake_conf(dev, chan);
}
}
void pcbit_irq_handler(int interrupt, void * devptr, struct pt_regs *regs)
{
struct pcbit_dev * dev;
u_char info, ack_seq, read_seq;
u_char ack_int = 1;
dev = (struct pcbit_dev *) devptr;
if (!dev)
{
printk(KERN_WARNING "pcbit_irq_handler: wrong device\n");
return;
}
if (dev->interrupt) {
printk(KERN_DEBUG "pcbit: reentering interrupt hander\n");
return;
}
dev->interrupt = 1;
info = readb(dev->sh_mem + BANK3);
if (dev->l2_state == L2_STARTING || dev->l2_state == L2_ERROR)
{
pcbit_l2_active_conf(dev, info);
dev->interrupt = 0;
return;
}
if (info & 0x40U) /* E bit set */
{
#ifdef DEBUG
printk(KERN_DEBUG "pcbit_irq_handler: E bit on\n");
#endif
pcbit_l2_error(dev);
dev->interrupt = 0;
return;
}
if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
{
dev->interrupt = 0;
return;
}
ack_seq = (info >> 3) & 0x07U;
read_seq = (info & 0x07U);
dev->interrupt = 0;
sti();
/*
* Bottom Half
* Runs with ints enabled
*/
if (read_seq != dev->rcv_seq)
{
pcbit_frame_read(dev, read_seq);
ack_int = 0;
}
if (ack_seq != dev->unack_seq)
{
pcbit_recv_ack(dev, ack_seq);
ack_int = 0;
}
if (ack_int)
{
info = 0;
info |= dev->rcv_seq << 3;
info |= dev->send_seq;
writeb(info, dev->sh_mem + BANK4);
}
}
static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info)
{
u_char state;
state = dev->l2_state;
#ifdef DEBUG
printk(KERN_DEBUG "layer2_active_confirm\n");
#endif
if (info & 0x80U ) {
dev->rcv_seq = info & 0x07U;
dev->l2_state = L2_RUNNING;
}
else
dev->l2_state = L2_DOWN;
if (state == L2_STARTING)
wake_up_interruptible(&dev->set_running_wq);
if (state == L2_ERROR && dev->l2_state == L2_RUNNING) {
pcbit_transmit(dev);
}
}
static void pcbit_l2_err_recover(unsigned long data)
{
struct pcbit_dev * dev;
struct frame_buf *frame;
dev = (struct pcbit_dev *) data;
del_timer(&dev->error_recover_timer);
if (dev->w_busy || dev->r_busy)
{
init_timer(&dev->error_recover_timer);
dev->error_recover_timer.expires = jiffies + ERRTIME;
add_timer(&dev->error_recover_timer);
return;
}
dev->w_busy = dev->r_busy = 1;
if (dev->read_frame) {
if (dev->read_frame->skb) {
dev->read_frame->skb->free = 1;
kfree_skb(dev->read_frame->skb, FREE_READ);
}
kfree(dev->read_frame);
dev->read_frame = NULL;
}
if (dev->write_queue) {
frame = dev->write_queue;
#ifdef FREE_ON_ERROR
dev->write_queue = dev->write_queue->next;
if (frame->skb) {
dev_kfree_skb(frame->skb, FREE_WRITE);
}
kfree(frame);
#else
frame->copied = 0;
#endif
}
dev->rcv_seq = dev->send_seq = dev->unack_seq = 0;
dev->free = 511;
dev->l2_state = L2_ERROR;
/* this is an hack... */
pcbit_firmware_bug(dev);
dev->writeptr = dev->sh_mem;
dev->readptr = dev->sh_mem + BANK2;
writeb((0x80U | ((dev->rcv_seq & 0x07) << 3) | (dev->send_seq & 0x07)),
dev->sh_mem + BANK4);
dev->w_busy = dev->r_busy = 0;
}
static void pcbit_l2_error(struct pcbit_dev *dev)
{
if (dev->l2_state == L2_RUNNING) {
printk(KERN_INFO "pcbit: layer 2 error\n");
#ifdef DEBUG
log_state(dev);
#endif
dev->l2_state = L2_DOWN;
init_timer(&dev->error_recover_timer);
dev->error_recover_timer.function = &pcbit_l2_err_recover;
dev->error_recover_timer.data = (ulong) dev;
dev->error_recover_timer.expires = jiffies + ERRTIME;
add_timer(&dev->error_recover_timer);
}
}
/*
* Description:
* if board acks frames
* update dev->free
* call pcbit_transmit to write possible queued frames
*/
static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack)
{
int i, count;
int unacked;
unacked = (dev->send_seq + (8 - dev->unack_seq) ) & 0x07;
/* dev->unack_seq < ack <= dev->send_seq; */
if (unacked)
{
if (dev->send_seq > dev->unack_seq)
if (ack <= dev->unack_seq || ack > dev->send_seq)
{
printk("layer 2 ack unacceptable - dev %d", dev->id);
pcbit_l2_error(dev);
}
else
if (ack > dev->send_seq && ack <= dev->unack_seq) {
printk("layer 2 ack unacceptable - dev %d", dev->id);
pcbit_l2_error(dev);
}
/* ack is acceptable */
i = dev->unack_seq;
do {
dev->unack_seq = i = (i + 1) % 8;
dev->free += dev->fsize[i];
} while (i != ack);
count = 0;
while (count < 7 && dev->write_queue)
{
u8 lsend_seq = dev->send_seq;
pcbit_transmit(dev);
if (dev->send_seq == lsend_seq)
break;
count++;
}
if (!count) {
u_char info;
info = 0;
info |= dev->rcv_seq << 3;
info |= dev->send_seq;
writeb(info, dev->sh_mem + BANK4);
}
}
else
printk(KERN_DEBUG "recv_ack: unacked = 0\n");
}
static void pcbit_frame_read(struct pcbit_dev * dev, unsigned char read_seq)
{
unsigned long flags;
int busy;
u_char info;
save_flags(flags);
cli();
if (!(busy=dev->r_busy))
dev->r_busy = 1;
restore_flags(flags);
if (busy)
return;
while (read_seq != dev->rcv_seq) {
pcbit_receive(dev);
dev->rcv_seq = (dev->rcv_seq + 1) % 8;
}
dev->r_busy = 0;
info = 0;
info |= dev->rcv_seq << 3;
info |= dev->send_seq;
writeb(info, dev->sh_mem + BANK4);
}

287
drivers/isdn/pcbit/layer2.h Normal file
View File

@ -0,0 +1,287 @@
/*
* Copyright (C) 1996 Universidade de Lisboa
*
* Writen by Pedro Roque Marques (roque@di.fc.ul.pt)
*
* This software may be used and distributed according to the terms of
* the GNU Public License, incorporated herein by reference.
*/
/*
* PCBIT-D low-layer interface definitions
*/
#ifndef LAYER2_H
#define LAYER2_H
#include <bytesex.h>
#define BANK1 0x0000U /* PC -> Board */
#define BANK2 0x01ffU /* Board -> PC */
#define BANK3 0x03feU /* Att Board */
#define BANK4 0x03ffU /* Att PC */
#define BANKLEN 0x01FFU
#define LOAD_ZONE_START 0x03f8U
#define LOAD_ZONE_END 0x03fdU
#define LOAD_RETRY 18000000
/* TAM - XX - C - S - NUM */
#define PREHDR_LEN 8
/* TT - M - I - TH - TD */
#define FRAME_HDR_LEN 8
#define MSG_CONN_REQ 0x08000100
#define MSG_CONN_CONF 0x00000101
#define MSG_CONN_IND 0x00000102
#define MSG_CONN_RESP 0x08000103
#define MSG_CONN_ACTV_REQ 0x08000300
#define MSG_CONN_ACTV_CONF 0x00000301
#define MSG_CONN_ACTV_IND 0x00000302
#define MSG_CONN_ACTV_RESP 0x08000303
#define MSG_DISC_REQ 0x08000400
#define MSG_DISC_CONF 0x00000401
#define MSG_DISC_IND 0x00000402
#define MSG_DISC_RESP 0x08000403
#define MSG_TDATA_REQ 0x0908E200
#define MSG_TDATA_CONF 0x0000E201
#define MSG_TDATA_IND 0x0000E202
#define MSG_TDATA_RESP 0x0908E203
#define MSG_SELP_REQ 0x09004000
#define MSG_SELP_CONF 0x00004001
#define MSG_ACT_TRANSP_REQ 0x0908E000
#define MSG_ACT_TRANSP_CONF 0x0000E001
#define MSG_STPROT_REQ 0x09004100
#define MSG_STPROT_CONF 0x00004101
#define MSG_PING188_REQ 0x09030500
#define MSG_PING188_CONF 0x000005bc
#define MSG_WATCH188 0x09030400
#define MSG_API_ON 0x08020102
#define MSG_POOL_PCBIT 0x08020400
#define MSG_POOL_PCBIT_CONF 0x00000401
#define MSG_INFO_IND 0x00002602
#define MSG_INFO_RESP 0x08002603
#define MSG_DEBUG_188 0x0000ff00
/*
long 4 3 2 1
Intel 1 2 3 4
*/
struct msg_fmt {
#if __BYTE_ORDER == 1234 /* Little Endian */
u_char scmd;
u_char cmd;
u_char proc;
u_char cpu;
#else
#error "Non-Intel CPU"
u_char cpu;
u_char proc;
u_char cmd;
u_char scmd;
#endif
};
#define MAX_QUEUED 7
#define SCHED_READ 0x01
#define SCHED_WRITE 0x02
#define SET_RUN_TIMEOUT 2*HZ /* 2 seconds */
struct frame_buf {
ulong msg;
unsigned short refnum;
unsigned short dt_len;
unsigned short hdr_len;
struct sk_buff *skb;
unsigned short copied;
struct frame_buf * next;
};
#define MIN(a,b) ((a<b)?a:b)
extern int pcbit_l2_write(struct pcbit_dev * dev, ulong msg, ushort refnum,
struct sk_buff *skb, unsigned short hdr_len);
extern void pcbit_irq_handler(int interrupt, void *, struct pt_regs *regs);
extern struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS];
#ifdef DEBUG
static __inline__ void log_state(struct pcbit_dev *dev) {
printk(KERN_DEBUG "writeptr = %ld\n",
(ulong) (dev->writeptr - dev->sh_mem));
printk(KERN_DEBUG "readptr = %ld\n",
(ulong) (dev->readptr - (dev->sh_mem + BANK2)));
printk(KERN_DEBUG "{rcv_seq=%01x, send_seq=%01x, unack_seq=%01x}\n",
dev->rcv_seq, dev->send_seq, dev->unack_seq);
}
#endif
static __inline__ struct pcbit_dev * chan2dev(struct pcbit_chan * chan)
{
struct pcbit_dev * dev;
int i;
for (i=0; i<MAX_PCBIT_CARDS; i++)
if ((dev=dev_pcbit[i]))
if (dev->b1 == chan || dev->b2 == chan)
return dev;
return NULL;
}
static __inline__ struct pcbit_dev * finddev(int id)
{
struct pcbit_dev * dev;
int i;
for (i=0; i<MAX_PCBIT_CARDS; i++)
if ((dev=dev_pcbit[i]))
if (dev->id == id)
return dev;
return NULL;
}
/*
* Support routines for reading and writing in the board
*/
static __inline__ void pcbit_writeb(struct pcbit_dev *dev, unsigned char dt)
{
writeb(dt, dev->writeptr++);
if (dev->writeptr == dev->sh_mem + BANKLEN)
dev->writeptr = dev->sh_mem;
}
static __inline__ void pcbit_writew(struct pcbit_dev *dev, unsigned short dt)
{
int dist;
dist = BANKLEN - (dev->writeptr - dev->sh_mem);
switch (dist) {
case 2:
writew(dt, dev->writeptr);
dev->writeptr = dev->sh_mem;
break;
case 1:
writeb((u_char) (dt & 0x00ffU), dev->writeptr);
dev->writeptr = dev->sh_mem;
writeb((u_char) (dt >> 8), dev->writeptr++);
break;
default:
writew(dt, dev->writeptr);
dev->writeptr += 2;
break;
};
}
static __inline__ void memcpy_topcbit(struct pcbit_dev * dev, u_char * data,
int len)
{
int diff;
diff = len - (BANKLEN - (dev->writeptr - dev->sh_mem) );
if (diff > 0)
{
memcpy_toio(dev->writeptr, data, len - diff);
memcpy_toio(dev->sh_mem, data + (len - diff), diff);
dev->writeptr = dev->sh_mem + diff;
}
else
{
memcpy_toio(dev->writeptr, data, len);
dev->writeptr += len;
if (diff == 0)
dev->writeptr = dev->sh_mem;
}
}
static __inline__ unsigned char pcbit_readb(struct pcbit_dev *dev)
{
unsigned char val;
val = readb(dev->readptr++);
if (dev->readptr == dev->sh_mem + BANK2 + BANKLEN)
dev->readptr = dev->sh_mem + BANK2;
return val;
}
static __inline__ unsigned short pcbit_readw(struct pcbit_dev *dev)
{
int dist;
unsigned short val;
dist = BANKLEN - ( dev->readptr - (dev->sh_mem + BANK2 ) );
switch (dist) {
case 2:
val = readw(dev->readptr);
dev->readptr = dev->sh_mem + BANK2;
break;
case 1:
val = readb(dev->readptr);
dev->readptr = dev->sh_mem + BANK2;
val = (readb(dev->readptr++) << 8) | val;
break;
default:
val = readw(dev->readptr);
dev->readptr += 2;
break;
};
return val;
}
static __inline__ void memcpy_frompcbit(struct pcbit_dev * dev, u_char * data, int len)
{
int diff;
diff = len - (BANKLEN - (dev->readptr - (dev->sh_mem + BANK2) ) );
if (diff > 0)
{
memcpy_fromio(data, dev->readptr, len - diff);
memcpy_fromio(data + (len - diff), dev->sh_mem + BANK2 , diff);
dev->readptr = dev->sh_mem + BANK2 + diff;
}
else
{
memcpy_fromio(data, dev->readptr, len);
dev->readptr += len;
if (diff == 0)
dev->readptr = dev->sh_mem + BANK2;
}
}
#endif

134
drivers/isdn/pcbit/module.c Normal file
View File

@ -0,0 +1,134 @@
/*
* Copyright (C) 1996 Universidade de Lisboa
*
* Writen by Pedro Roque Marques (roque@di.fc.ul.pt)
*
* This software may be used and distributed according to the terms of
* the GNU Public License, incorporated herein by reference.
*/
/*
* PCBIT-D module support
*/
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/tqueue.h>
#include <linux/skbuff.h>
#include <linux/isdnif.h>
#include "pcbit.h"
int mem[MAX_PCBIT_CARDS] = {0, };
int irq[MAX_PCBIT_CARDS] = {0, };
int num_boards;
struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS] = {0, 0, 0, 0};
int init_module(void);
void cleanup_module(void);
extern void pcbit_terminate(int board);
extern int pcbit_init_dev(int board, int mem_base, int irq);
#ifdef MODULE
#define pcbit_init init_module
#endif
int pcbit_init(void)
{
int board;
num_boards = 0;
printk(KERN_INFO
"PCBIT-D device driver v 0.5 - "
"Copyright (C) 1996 Universidade de Lisboa\n");
if (mem[0] || irq[0])
{
for (board=0; board < MAX_PCBIT_CARDS && mem[board] && irq[board]; board++)
{
if (!mem[board])
mem[board] = 0xD0000;
if (!irq[board])
irq[board] = 5;
if (pcbit_init_dev(board, mem[board], irq[board]) == 0)
num_boards++;
else
{
printk(KERN_WARNING
"pcbit_init failed for dev %d",
board + 1);
return -EIO;
}
}
}
/* Hardcoded default settings detection */
if (!num_boards)
{
printk(KERN_INFO
"Trying to detect board using default settings\n");
if (pcbit_init_dev(0, 0xD0000, 5) == 0)
num_boards++;
else
return -EIO;
}
/* No symbols to export, hide all symbols */
register_symtab(NULL);
return 0;
}
#ifdef MODULE
void cleanup_module(void)
{
int board;
if (MOD_IN_USE) {
printk(KERN_WARNING "pcbit: device busy, remove cancelled\n");
return;
}
for (board = 0; board < num_boards; board++)
pcbit_terminate(board);
printk(KERN_INFO
"PCBIT-D module unloaded\n");
}
#else
void pcbit_setup(char *str, int *ints)
{
int i, j, argc;
argc = ints[0];
i = 0;
j = 1;
while (argc && (i<MAX_PCBIT_CARDS)) {
if (argc) {
mem[i] = ints[j];
j++; argc--;
}
if (argc) {
irq[i] = ints[j];
j++; argc--;
}
i++;
}
}
#endif

175
drivers/isdn/pcbit/pcbit.h Normal file
View File

@ -0,0 +1,175 @@
/*
* Copyright (C) 1996 Universidade de Lisboa
*
* Writen by Pedro Roque Marques (roque@di.fc.ul.pt)
*
* This software may be used and distributed according to the terms of
* the GNU Public License, incorporated herein by reference.
*/
/*
* PCBIT-D device driver definitions
*/
#ifndef PCBIT_H
#define PCBIT_H
#define MAX_PCBIT_CARDS 4
#define BLOCK_TIMER
#ifdef __KERNEL__
struct pcbit_chan {
unsigned short id;
unsigned short callref; /* Call Reference */
unsigned char proto; /* layer2protol */
unsigned char queued; /* unacked data messages */
unsigned char layer2link; /* used in TData */
unsigned char snum; /* used in TData */
unsigned short s_refnum;
unsigned short r_refnum;
unsigned short fsm_state;
struct timer_list fsm_timer;
#ifdef BLOCK_TIMER
struct timer_list block_timer;
#endif
};
struct msn_entry {
char *msn;
struct msn_entry * next;
};
struct pcbit_dev {
/* board */
volatile unsigned char* sh_mem; /* RDP address */
unsigned int irq;
unsigned int id;
unsigned int interrupt; /* set during interrupt
processing */
/* isdn4linux */
struct msn_entry * msn_list; /* ISDN address list */
isdn_if * dev_if;
ushort ll_hdrlen;
ushort hl_hdrlen;
/* link layer */
unsigned char l2_state;
struct frame_buf *read_queue;
struct frame_buf *read_frame;
struct frame_buf *write_queue;
/* Protocol start */
struct wait_queue *set_running_wq;
struct timer_list set_running_timer;
struct timer_list error_recover_timer;
struct tq_struct qdelivery;
u_char w_busy;
u_char r_busy;
volatile unsigned char *readptr;
volatile unsigned char *writeptr;
ushort loadptr;
unsigned short fsize[8]; /* sent layer2 frames size */
unsigned char send_seq;
unsigned char rcv_seq;
unsigned char unack_seq;
unsigned short free;
/* channels */
struct pcbit_chan *b1;
struct pcbit_chan *b2;
};
#define STATS_TIMER (10*HZ)
#define ERRTIME (0.1*HZ)
/* MRU */
#define MAXBUFSIZE 1534
#define MRU MAXBUFSIZE
#define STATBUF_LEN 2048
/*
*
*/
#endif /* __KERNEL__ */
/* isdn_ctrl only allows a long sized argument */
struct pcbit_ioctl {
union {
struct byte_op {
ushort addr;
ushort value;
} rdp_byte;
unsigned long l2_status;
} info;
};
#define PCBIT_IOCTL_GETSTAT 0x01 /* layer2 status */
#define PCBIT_IOCTL_LWMODE 0x02 /* linear write mode */
#define PCBIT_IOCTL_STRLOAD 0x03 /* start load mode */
#define PCBIT_IOCTL_ENDLOAD 0x04 /* end load mode */
#define PCBIT_IOCTL_SETBYTE 0x05 /* set byte */
#define PCBIT_IOCTL_GETBYTE 0x06 /* get byte */
#define PCBIT_IOCTL_RUNNING 0x07 /* set protocol running */
#define PCBIT_IOCTL_WATCH188 0x08 /* set watch 188 */
#define PCBIT_IOCTL_PING188 0x09 /* ping 188 */
#define PCBIT_IOCTL_FWMODE 0x0A /* firmware write mode */
#define PCBIT_IOCTL_STOP 0x0B /* stop protocol */
#define PCBIT_IOCTL_APION 0x0C /* issue API_ON */
#ifndef __KERNEL__
#define PCBIT_GETSTAT (PCBIT_IOCTL_GETSTAT + IIOCDRVCTL)
#define PCBIT_LWMODE (PCBIT_IOCTL_LWMODE + IIOCDRVCTL)
#define PCBIT_STRLOAD (PCBIT_IOCTL_STRLOAD + IIOCDRVCTL)
#define PCBIT_ENDLOAD (PCBIT_IOCTL_ENDLOAD + IIOCDRVCTL)
#define PCBIT_SETBYTE (PCBIT_IOCTL_SETBYTE + IIOCDRVCTL)
#define PCBIT_GETBYTE (PCBIT_IOCTL_GETBYTE + IIOCDRVCTL)
#define PCBIT_RUNNING (PCBIT_IOCTL_RUNNING + IIOCDRVCTL)
#define PCBIT_WATCH188 (PCBIT_IOCTL_WATCH188 + IIOCDRVCTL)
#define PCBIT_PING188 (PCBIT_IOCTL_PING188 + IIOCDRVCTL)
#define PCBIT_FWMODE (PCBIT_IOCTL_FWMODE + IIOCDRVCTL)
#define PCBIT_STOP (PCBIT_IOCTL_STOP + IIOCDRVCTL)
#define PCBIT_APION (PCBIT_IOCTL_APION + IIOCDRVCTL)
#define MAXSUPERLINE 3000
#endif
#define L2_DOWN 0
#define L2_LOADING 1
#define L2_LWMODE 2
#define L2_FWMODE 3
#define L2_STARTING 4
#define L2_RUNNING 5
#define L2_ERROR 6
#endif

View File

@ -0,0 +1,15 @@
CFLAGS=$(MCFLAGS) -I../$(INCLUDES)
OBJS=mod.o card.o config.o buffers.o tei.o isdnl2.o isdnl3.o llglue.o \
q931.o callc.o fsm.o
all: teles.o
isdnl3.o: l3_1TR6.c l3_1TR6.h isdnl3.c
$(OBJS): teles.h
teles.o: $(OBJS)
ld -r -o teles.o $(OBJS)
clean:
rm -f *.[iso] *~ core

30
include/linux/isdn_ppp.h Normal file
View File

@ -0,0 +1,30 @@
extern int isdn_ppp_dial_slave(char *);
struct pppinfo
{
int type; /* set by user */
union {
char clid[32]; /* calling ID */
int bundles;
int linknumber;
} info;
};
#define PPPIOCLINKINFO _IOWR('t',128,struct pppinfo)
#define PPPIOCBUNDLE _IOW('t',129,int)
#define PPPIOCGMPFLAGS _IOR('t',130,int)
#define PPPIOCSMPFLAGS _IOW('t',131,int)
#define PPPIOCSMPMTU _IOW('t',132,int)
#define PPPIOCSMPMRU _IOW('t',133,int)
#define PPP_MP 0x003d
#define SC_MP_PROT 0x00000200
#define SC_REJ_MP_PROT 0x00000400
#define SC_OUT_SHORT_SEQ 0x00000800
#define SC_IN_SHORT_SEQ 0x00004000
#define MP_END_FRAG 0x40
#define MP_BEGIN_FRAG 0x80

35
std2kern Executable file
View File

@ -0,0 +1,35 @@
#!/bin/sh
KERNELDIR=/usr/src/linux
docp() {
if [ $1 -nt $2 ] ; then
echo Copying $1 ...
cp $1 $2
else
echo $2 is up to date, NOT converted
fi
}
if [ $# != 0 ]; then
for i in $* ; do
docp $i $KERNELDIR/$i
done
else
for i in drivers/isdn/isdn_*.[ch] ; do
docp $i $KERNELDIR/$i
done
for i in drivers/isdn/icn/icn.[ch] ; do
docp $i $KERNELDIR/$i
done
for i in drivers/isdn/pcbit/*.[ch] ; do
docp $i $KERNELDIR/$i
done
for i in drivers/isdn/teles/*.[ch] ; do
docp $i $KERNELDIR/$i
done
for i in include/linux/isdn*.h ; do
docp $i $KERNELDIR/$i
done
fi

26
stddiff Executable file
View File

@ -0,0 +1,26 @@
#!/bin/sh
KERNELDIR=/usr/src/linux
if [ $# != 0 ]; then
for i in $* ; do
diff -u $i $KERNELDIR/$i
done
else
for i in drivers/isdn/isdn_*.[ch] ; do
diff -u $i $KERNELDIR/$i
done
for i in drivers/isdn/icn/icn.[ch] ; do
diff -u $i $KERNELDIR/$i
done
for i in drivers/isdn/teles/*.[ch] ; do
diff -u $i $KERNELDIR/$i
done
for i in drivers/isdn/pcbit/*.[ch] ; do
diff -u $i $KERNELDIR/$i
done
for i in include/linux/isdn*.h ; do
diff -u $i $KERNELDIR/$i
done
fi