Taken under CVS control
This commit is contained in:
parent
35eacd14a3
commit
d06a7653be
|
@ -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 ;-)
|
||||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
@ -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!
|
||||
|
|
@ -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>
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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] *~
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue