summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/conf/NOTES20
-rw-r--r--sys/conf/files13
-rw-r--r--sys/i386/conf/NOTES20
-rw-r--r--sys/i386/include/i4b_debug.h15
-rw-r--r--sys/i386/include/i4b_ioctl.h20
-rw-r--r--sys/i4b/capi/README150
-rw-r--r--sys/i4b/capi/capi.h129
-rw-r--r--sys/i4b/capi/capi_l4if.c450
-rw-r--r--sys/i4b/capi/capi_llif.c166
-rw-r--r--sys/i4b/capi/capi_msgs.c948
-rw-r--r--sys/i4b/capi/capi_msgs.h380
-rw-r--r--sys/i4b/capi/iavc/iavc.h586
-rw-r--r--sys/i4b/capi/iavc/iavc_card.c292
-rw-r--r--sys/i4b/capi/iavc/iavc_isa.c297
-rw-r--r--sys/i4b/capi/iavc/iavc_lli.c834
-rw-r--r--sys/i4b/capi/iavc/iavc_pci.c283
-rw-r--r--sys/i4b/include/i4b_debug.h15
-rw-r--r--sys/i4b/include/i4b_ioctl.h20
-rw-r--r--sys/i4b/include/i4b_l3l4.h6
-rw-r--r--sys/i4b/layer3/i4b_l3fsm.c14
-rw-r--r--sys/i4b/layer3/i4b_l4if.c20
-rw-r--r--sys/i4b/layer4/i4b_i4bdrv.c13
-rw-r--r--sys/i4b/layer4/i4b_l4.c6
-rw-r--r--usr.sbin/i4b/isdnd/config.h8
-rw-r--r--usr.sbin/i4b/isdnd/controller.c217
-rw-r--r--usr.sbin/i4b/isdnd/isdnd.h10
-rw-r--r--usr.sbin/i4b/isdnd/isdnd.rc.525
-rw-r--r--usr.sbin/i4b/isdnd/monitor.c13
-rw-r--r--usr.sbin/i4b/isdnd/rc_config.c72
-rw-r--r--usr.sbin/i4b/isdnd/rc_parse.y18
-rw-r--r--usr.sbin/i4b/isdnd/rc_scan.l8
-rw-r--r--usr.sbin/i4b/isdnd/support.c70
-rw-r--r--usr.sbin/i4b/isdndebug/main.c31
-rw-r--r--usr.sbin/i4b/man/Makefile3
-rw-r--r--usr.sbin/i4b/man/i4bcapi.455
-rw-r--r--usr.sbin/i4b/man/iavc.467
36 files changed, 5029 insertions, 265 deletions
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index 117c6fd..5f80699 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -2323,6 +2323,10 @@ hint.pcf.0.irq="5"
# ifpnp - AVM Fritz!Card PnP driver
# itjc - Siemens ISAC / TJNet Tiger300/320 chipset
#
+# i4b active ISDN cards support contains the following hardware drivers:
+#
+# iavc - AVM B1 PCI, AVM B1 ISA, AVM T1
+#
# Note that the ``options'' (if given) and ``device'' lines must BOTH
# be uncommented to enable support for a given card !
#
@@ -2459,6 +2463,17 @@ device iwic
device itjc
#
#---------------------------------------------------------------------------
+# iavc driver (AVM active cards, needs i4bcapi driver!)
+#
+device iavc
+#
+# AVM B1 ISA bus (PnP mode not supported!)
+# ----------------------------------------
+hint.iavc.0.at="isa"
+hint.iavc.0.port="0x150"
+hint.iavc.0.irq="5"
+#
+#---------------------------------------------------------------------------
# ISDN Protocol Stack - mandatory for all hardware drivers
#
# Q.921 / layer 2 - i4b passive cards D channel handling
@@ -2499,9 +2514,12 @@ options IPR_LOG=32
# number of sppp device to be configured
device "i4bisppp" 4
#
-# B-channel inteface to the netgraph subsystem
+# B-channel interface to the netgraph subsystem
device "i4bing" 2
#
+# CAPI driver needed for active ISDN cards (see iavc driver above)
+device "i4bcapi"
+#
#---------------------------------------------------------------------------
# Parallel-Port Bus
diff --git a/sys/conf/files b/sys/conf/files
index ec8ae7b..22c2859 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -654,6 +654,19 @@ i4b/driver/i4b_isppp.c count i4bisppp
i4b/driver/i4b_ispppsubr.c optional i4bisppp
net/slcompress.c optional i4bisppp
#
+# isdn4bsd CAPI driver
+#
+i4b/capi/capi_l4if.c count i4bcapi
+i4b/capi/capi_llif.c optional i4bcapi
+i4b/capi/capi_msgs.c optional i4bcapi
+#
+# isdn4bsd AVM B1/T1 CAPI driver
+#
+i4b/capi/iavc/iavc_pci.c count iavc
+i4b/capi/iavc/iavc_isa.c optional iavc
+i4b/capi/iavc/iavc_lli.c optional iavc
+i4b/capi/iavc/iavc_card.c optional iavc
+#
# isdn4bsd support
#
i4b/layer2/i4b_mbuf.c optional i4btrc
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index 117c6fd..5f80699 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -2323,6 +2323,10 @@ hint.pcf.0.irq="5"
# ifpnp - AVM Fritz!Card PnP driver
# itjc - Siemens ISAC / TJNet Tiger300/320 chipset
#
+# i4b active ISDN cards support contains the following hardware drivers:
+#
+# iavc - AVM B1 PCI, AVM B1 ISA, AVM T1
+#
# Note that the ``options'' (if given) and ``device'' lines must BOTH
# be uncommented to enable support for a given card !
#
@@ -2459,6 +2463,17 @@ device iwic
device itjc
#
#---------------------------------------------------------------------------
+# iavc driver (AVM active cards, needs i4bcapi driver!)
+#
+device iavc
+#
+# AVM B1 ISA bus (PnP mode not supported!)
+# ----------------------------------------
+hint.iavc.0.at="isa"
+hint.iavc.0.port="0x150"
+hint.iavc.0.irq="5"
+#
+#---------------------------------------------------------------------------
# ISDN Protocol Stack - mandatory for all hardware drivers
#
# Q.921 / layer 2 - i4b passive cards D channel handling
@@ -2499,9 +2514,12 @@ options IPR_LOG=32
# number of sppp device to be configured
device "i4bisppp" 4
#
-# B-channel inteface to the netgraph subsystem
+# B-channel interface to the netgraph subsystem
device "i4bing" 2
#
+# CAPI driver needed for active ISDN cards (see iavc driver above)
+device "i4bcapi"
+#
#---------------------------------------------------------------------------
# Parallel-Port Bus
diff --git a/sys/i386/include/i4b_debug.h b/sys/i386/include/i4b_debug.h
index 26bfa50..d9380f7 100644
--- a/sys/i386/include/i4b_debug.h
+++ b/sys/i386/include/i4b_debug.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
+ * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,11 +27,9 @@
* i4b_debug.h - i4b debug header file
* -----------------------------------
*
- * $Id: i4b_debug.h,v 1.32 2000/07/24 12:22:08 hm Exp $
- *
* $FreeBSD$
*
- * last edit-date: [Wed Oct 18 09:48:16 2000]
+ * last edit-date: [Mon May 21 10:05:34 2001]
*
*---------------------------------------------------------------------------*/
@@ -169,13 +167,12 @@ extern unsigned int i4b_l4_debug;
#define L4_RBCHDBG 0x0020 /* rbch driver debug messages */
#define L4_ISPDBG 0x0040 /* isp driver debug messages */
#define L4_TELDBG 0x0080 /* tel driver debug messages */
-#define L4_TINADBG 0x0100 /* tina driver debug messages */
-#define L4_TINAMSG 0x0200 /* tina driver messages */
-#define L4_TINAERR 0x0400 /* tina driver error messages */
-#define L4_INGDBG 0x0800 /* ing driver debug messages */
+#define L4_INGDBG 0x0100 /* ing driver debug messages */
+#define L4_IAVCDBG 0x0200 /* AVM B1 driver debug messages */
+#define L4_CAPIDBG 0x0400 /* CAPI driver debug messages */
#define L4_DEBUG_MAX 0x0fff /* all messages on */
-#define L4_DEBUG_ERR (L4_ERR | L4_TINADBG | L4_TINAMSG | L4_TINAERR)
+#define L4_DEBUG_ERR L4_ERR
#ifndef L4_DEBUG_DEFAULT
#ifdef DO_I4B_MAXDEBUG
diff --git a/sys/i386/include/i4b_ioctl.h b/sys/i386/include/i4b_ioctl.h
index 8070f3e..d357326 100644
--- a/sys/i386/include/i4b_ioctl.h
+++ b/sys/i386/include/i4b_ioctl.h
@@ -29,7 +29,7 @@
*
* $FreeBSD$
*
- * last edit-date: [Fri Jan 26 13:46:50 2001]
+ * last edit-date: [Fri May 25 10:04:37 2001]
*
*---------------------------------------------------------------------------*/
@@ -45,9 +45,9 @@
/*---------------------------------------------------------------------------*
* version and release number for isdn4bsd package
*---------------------------------------------------------------------------*/
-#define VERSION 0 /* version number */
-#define REL 96 /* release number */
-#define STEP 3 /* release step */
+#define VERSION 1 /* version number */
+#define REL 0 /* release number */
+#define STEP 0 /* release step */
/*---------------------------------------------------------------------------*
* date/time format in i4b log messages
@@ -82,7 +82,8 @@
#define CTRL_DAIC 2 /* Diehl active controller cards*/
#define CTRL_TINADD 3 /* Stollmann Tina-dd active card*/
#define CTRL_AVMB1 4 /* AVM B1 active card */
-#define CTRL_NUMTYPES 5 /* number of controller types */
+#define CTRL_CAPI 5 /* cards seen via the CAPI layer*/
+#define CTRL_NUMTYPES 6 /* number of controller types */
/*---------------------------------------------------------------------------*
* CTRL_PASSIVE: driver types
@@ -156,6 +157,14 @@
#define CARD_TYPEA_DAIC_QUAD 4
/*---------------------------------------------------------------------------*
+ * card types for CTRL_CAPI
+ *---------------------------------------------------------------------------*/
+#define CARD_TYPEC_CAPI_UNK 0
+#define CARD_TYPEC_AVM_T1_PCI 1
+#define CARD_TYPEC_AVM_B1_PCI 2
+#define CARD_TYPEC_AVM_B1_ISA 3
+
+/*---------------------------------------------------------------------------*
* max length of some strings
*---------------------------------------------------------------------------*/
#define TELNO_MAX 41 /* max length of a telephone number (+ '\0') */
@@ -592,6 +601,7 @@ typedef struct {
int ctrl_type; /* controller type passive/active */
int card_type; /* brand / version */
int tei; /* tei controller probably has */
+ int nbch; /* number of b channels provided */
} msg_ctrl_info_req_t;
#define I4B_CTRL_INFO_REQ _IOWR('4', 4, msg_ctrl_info_req_t)
diff --git a/sys/i4b/capi/README b/sys/i4b/capi/README
new file mode 100644
index 0000000..9168525
--- /dev/null
+++ b/sys/i4b/capi/README
@@ -0,0 +1,150 @@
+$FreeBSD$
+
+Message-ID: <3AF56886.7D92609A@cubical.fi>
+Date: Sun, 06 May 2001 18:06:47 +0300
+From: Juha-Matti Liukkonen <jml@cubical.fi>
+Organization: Cubical Solutions Ltd
+
+Please find the attached diff and tarball for our support software for
+CAPI 2.0 and AVM's active T1 and T1-B (primary rate) and B1 (basic rate)
+ISDN adapters for isdn4bsd. The implementation has been made from
+scratch by us, based on reverse engineering of the Linux driver provided
+by AVM GmbH and available in ftp.avm.de. Cubical Solutions Ltd offers
+this implementation for the BSD community free of charge and assuming
+absolutely no liabilities whatsoever. Feel free to modify the
+implementation any way you see fit, but please retain our one-liner
+copyright statement somewhere in the comment headers in the capi and
+iavc driver modules.
+
+That said, the attached tarball is i4b-00.96.00-beta with our
+modifications integrated, and the diff contains all modifications we
+have made to the original (including the new capi files). Our mods add
+pseudo-device i4bcapi, which attaches to i4b layer 4, and device iavc0,
+which implements a link layer driver for AVM's active B1 and T1 adapters
+for i4bcapi. There are also a couple of related improvements to isdnd,
+and a number of modifications to isdnd and layer 4 to implement support
+for up to 30 channels per adapter (for primary rate use).
+
+We have developed the software explicitly for our telephony application,
+to be used with AVM's T1 adapters, and the implementation has been
+tested primarily with this functionality in mind. There may be
+interesting side effects with eg. the ipr and isppp drivers; we do not
+use them and therefore their testing has been cursory at best. The
+i4btel driver works well with the T1 (our primary use), and the i4brbch
+driver has been verified to work with T1, T1-B and B1 adapters (ftp'd
+some files over a dialup PPP connection with each adapter). Only the PCI
+versions of the adapters (equipped with the AMCC DMA controller) are
+supported, although the basics (PIO mode communication) for the older
+ISA model support is in place, so only the bus attachment modules should
+be required to support the older hardware.
+
+All of the AVM active adapters use downloadable firmware, which is not
+included in the attached package. The firmware files (t1.t4, t1b.t4,
+b1.t4) can be found from ftp.avm.de in adapter specific subdirectories,
+or from the CDs provided with the adapters (in directory
+'cardware/firmware').
+
+Our primary development platform is our own embedded build (we call it
+'ebsd') based on FreeBSD 4.2-RELEASE. The implementation has also been
+tested on standard FreeBSD 4.2-RELEASE system. The implementation should
+not contain any FreeBSD (or even FreeBSD release) specific issues, but
+it has not been tested or even compiled on any other platforms;
+specifically, only the FreeBSD overinstall.sh script is modified to
+install the capi/iavc support in the kernel source tree.
+
+This code is not under active development here since the functionality
+we use (i4btel, T1) has been working since the beginning of March. We
+are also not planning on any further development (no need seen at this
+point), but I am naturally interested on whatever bugs and development
+ideas pop up on the community and will keep a keen eye on the isdn
+mailing list. I personally may be available for consultation, debugging
+and possibly development projects, but with notable reservations on my
+time (the current IT industry recession seems to be pushing even more
+work for us, which tends to keep us pretty busy these days).
+
+Here are some specific technical notes:
+
+* isdnd supports new keyword 'firmware=</path/to/file>' in section
+'controller'. This keyword is supported for all controller types, and
+causes I4B_CTRL_DOWNLOAD ioctl to be invoked with the specified file as
+an argument. In systems equipped with both active and passive adapters,
+and the passive cards being detected first, dummy 'controller' entries
+are required for the passive cards to get the correct firmwares to
+correct adapters. (I hope you did not have other uses for this ioctl in
+mind?)
+
+* isdnd supports new keyword 'clone=<entry name>' in section 'entry'.
+This causes the entry to be copied from the existing named entry. At
+least entry specific 'name' and 'usrdeviceunit' values should be
+specified after a 'clone'. (Makes configuring 30 or 60 entries way much
+easier.)
+
+* a bug in i4btel driver read routine corrected. The conditions in the
+while() clause caused the receive queue to be referenced before checking
+if a channel is connected, leading to kernel panic (do a 'dd
+if=/dev/i4btel0 of=/dev/null' on an unconnected tel device, panic will
+follow). Correction was to reorder the while clause conditions to check
+for connectedness first.
+
+* isdnd and i4b layer 4 support up to CHANNELS_MAX (=30) channels per
+adapter. The msg_ctrl_info_req_t message reports the number of channels
+provided by the adapter, the number is stored in the nbchan field of the
+controller state structure. The fixed stateb1 and stateb2 entries in
+controller state stuctures are replaced with an array, and all fixed
+references there are replaced with loops up to nbchan. Passive stack
+layer 1 and 2 are not modified, layer 3 sets this field to fixed value 2
+for all adapters (but it could be delegated to the layer 1 driver's
+attach request).
+
+* the i4bcapi driver maps i4b channels to logical channels identified
+with PLCI/NCCI values in the CAPI protocol using the sc_bchan[] array.
+The PLCI/NCCI handling is merged in the channel mapping and is greatly
+simplified from the reference state machine model, because in practice
+there can be only one PLCI/NCCI per channel active at any given time.
+
+* the i4bcapi driver does not provide any kind of user level interface
+(such as the /dev/capi20 interface provided by the linux driver), but
+could relatively easily be extended to do so (and if done, interface
+compatibility with the linux implementation would probably be a good
+goal).
+
+* there are some gritty details in the iavc driver, inherited from the
+linux code. Despite us being a legitimate company in the telecom
+business, AVM failed to produce any programming reference material for
+us (at least in a reasonable time frame), so some guesswork remains due
+to classic reverse engineering process (particularly there are a few
+magic numbers in the card initialization sequence whose meaning I do not
+know).
+
+* pseudo-devices i4bq931, i4bq921 and some passive stack layer 1 driver
+(such as iwic) are required to compile, as the required ctrl_desc[]
+array is in layer 3, which requires layer 2, which requires layer 1.
+Some architectural cleanup would come in handy here, but we did not want
+to start making any major changes (and we use iwic in test setups
+anyway, so we simply always compile it in).
+
+To summarize: unpack, overinstall, add the following lines (with the
+usual passive stack configuration including at least one L1 driver) to
+your kernel configuration file:
+
+pseudo-device "i4bcapi"
+device iavc0
+
+...and the following to your isdnd.rc:
+
+controller
+firmware = /usr/lib/isdn/b1.t4
+
+...compile your new kernel, make sure the firmware file is in
+/usr/lib/isdn, and your B1 adapter should boot up and Just Work (tm). If
+you have multiple adapters, you need a 'controller' section for each to
+have them loaded and booted on isdnd startup.
+
+Have fun -- and let me know if there are any complications, or if I can
+be of further assistance,
+
+ - Juha
+--
+Juha-Matti Liukkonen, Cubical Solutions Ltd
+Phone: +358(0)405280142
+Email: jml@cubical.fi
diff --git a/sys/i4b/capi/capi.h b/sys/i4b/capi/capi.h
new file mode 100644
index 0000000..185d2f7
--- /dev/null
+++ b/sys/i4b/capi/capi.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2001 Cubical Solutions Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * capi/capi.h The CAPI device interface.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _I4B_CAPI_H_
+#define _I4B_CAPI_H_
+
+/*
+// CAPI driver context: B channels and controller softcs.
+*/
+
+#define INVALID -1
+
+enum capi_b_state {
+ B_FREE, /* channel free, ncci invalid */
+ B_CONNECT_CONF, /* wait for CONNECT_CONF */
+ B_CONNECT_IND, /* IND got, wait for appl RESP */
+ B_CONNECT_ACTIVE_IND, /* wait for CONNECT_ACTIVE_IND */
+ B_CONNECT_B3_CONF, /* wait for CONNECT_B3_CONF */
+ B_CONNECT_B3_IND, /* wait for CONNECT_B3_IND */
+ B_CONNECT_B3_ACTIVE_IND, /* wait for CONNECT_B3_ACTIVE_IND */
+ B_CONNECTED, /* channel connected & in use */
+ B_DISCONNECT_CONF, /* wait for DISCONNECT_CONF */
+ B_DISCONNECT_B3_CONF, /* wait for DISCONNECT_B3_CONF */
+ B_DISCONNECT_IND, /* wait for DISCONNECT_IND */
+};
+
+typedef struct capi_bchan
+{
+ /* Channel state */
+
+ int ncci;
+#define CAPI_CTRL_MASK 0x000000ff
+#define CAPI_PLCI_MASK 0x0000ffff
+#define CAPI_NCCI_MASK 0xffff0000
+ u_int16_t msgid;
+ int busy;
+ enum capi_b_state state;
+
+ struct ifqueue tx_queue;
+ struct ifqueue rx_queue;
+ int rxcount;
+ int txcount;
+
+ /* The rest is needed for i4b integration */
+
+ int bprot;
+ int cdid;
+
+ struct mbuf *in_mbuf;
+ isdn_link_t capi_isdn_linktab;
+ drvr_link_t *capi_drvr_linktab;
+} capi_bchan_t;
+
+enum capi_c_state {
+ C_DOWN, /* controller uninitialized */
+ C_READY, /* controller initialized but not listening */
+ C_UP, /* controller listening */
+};
+
+typedef struct capi_softc {
+ int sc_unit; /* index in capi_sc[] */
+ int ctrl_unit; /* index in isdn_ctrl_tab[] */
+ int card_type; /* CARD_TYPEC_xxx, filled by ll driver */
+ int sc_nbch; /* number of b channels on this controller */
+ int sc_enabled; /* is daemon connected TRUE/FALSE */
+ int sc_msgid; /* next CAPI message id */
+ char sc_profile[64];/* CAPI profile data */
+ enum capi_c_state sc_state;
+
+ capi_bchan_t sc_bchan[MAX_BCHAN];
+
+ /* Link layer driver context holder and methods */
+
+ void *ctx;
+
+ int (*load)(struct capi_softc *, int, u_int8_t *);
+ int (*reg_appl)(struct capi_softc *, int, int);
+ int (*rel_appl)(struct capi_softc *, int);
+ int (*send)(struct capi_softc *, struct mbuf *);
+} capi_softc_t;
+
+extern capi_softc_t *capi_sc[];
+extern int ncapi;
+
+/*
+// CAPI upcalls for the link layer.
+*/
+
+#define I4BCAPI_APPLID 1
+
+extern int capi_ll_attach(capi_softc_t *);
+extern int capi_ll_control(capi_softc_t *, int op, int arg);
+
+#define CAPI_CTRL_READY 0 /* ctrl ready, value=TRUE/FALSE */
+#define CAPI_CTRL_PROFILE 1 /* set CAPI profile */
+#define CAPI_CTRL_NEW_NCCI 2 /* new ncci value, assign bchan */
+#define CAPI_CTRL_FREE_NCCI 3 /* free ncci value, clear bchan */
+
+extern int capi_ll_receive(capi_softc_t *, struct mbuf *);
+
+extern int capi_start_tx(capi_softc_t *, int bchan);
+
+#endif /* _I4B_CAPI_H_ */
diff --git a/sys/i4b/capi/capi_l4if.c b/sys/i4b/capi/capi_l4if.c
new file mode 100644
index 0000000..9cb05f2
--- /dev/null
+++ b/sys/i4b/capi/capi_l4if.c
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2001 Cubical Solutions Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * capi/capi_l4if.c The CAPI i4b L4/device interface.
+ *
+ * $FreeBSD$
+ */
+
+#include "i4bcapi.h"
+#if NI4BCAPI > 0
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_cause.h>
+
+#include <i4b/include/i4b_l3l4.h>
+#include <i4b/include/i4b_mbuf.h>
+#include <i4b/include/i4b_global.h>
+
+#include <i4b/layer4/i4b_l4.h>
+
+#include <i4b/capi/capi.h>
+#include <i4b/capi/capi_msgs.h>
+
+static void n_connect_request(u_int cdid);
+static void n_connect_response(u_int cdid, int response, int cause);
+static void n_disconnect_request(u_int cdid, int cause);
+static void n_alert_request(u_int cdid);
+static void n_mgmt_command(int unit, int cmd, void *parm);
+static int n_download(int unit, int, struct isdn_dr_prot *);
+
+capi_softc_t *capi_sc[MAX_CONTROLLERS] = { NULL, };
+int ncapi = 0;
+
+/*
+// i4b_capi_{ret,set}_linktab
+// i4b driver glue.
+//
+// i4b_capi_bch_config
+// Called by i4b driver to flush + {en,dis}able a channel.
+//
+// i4b_capi_bch_start_tx
+// Called by i4b driver to transmit a queued mbuf.
+//
+// i4b_capi_bch_stat
+// Called by i4b driver to obtain statistics information.
+*/
+
+static isdn_link_t *
+i4b_capi_ret_linktab(int unit, int channel)
+{
+ capi_softc_t *sc = capi_sc[unit];
+ return &sc->sc_bchan[channel].capi_isdn_linktab;
+}
+
+static void
+i4b_capi_set_linktab(int unit, int channel, drvr_link_t *dlt)
+{
+ capi_softc_t *sc = capi_sc[unit];
+ sc->sc_bchan[channel].capi_drvr_linktab = dlt;
+}
+
+static void
+i4b_capi_bch_config(int unit, int chan, int bprot, int activate)
+{
+ capi_softc_t *sc = capi_sc[unit];
+
+ i4b_Bcleanifq(&sc->sc_bchan[chan].tx_queue);
+ sc->sc_bchan[chan].tx_queue.ifq_maxlen = IFQ_MAXLEN;
+ sc->sc_bchan[chan].txcount = 0;
+
+ /* The telephony drivers use rx_queue for receive. */
+
+ i4b_Bcleanifq(&sc->sc_bchan[chan].rx_queue);
+ sc->sc_bchan[chan].rx_queue.ifq_maxlen = IFQ_MAXLEN;
+ sc->sc_bchan[chan].rxcount = 0;
+
+ /* HDLC frames are put to in_mbuf */
+
+ i4b_Bfreembuf(sc->sc_bchan[chan].in_mbuf);
+ sc->sc_bchan[chan].in_mbuf = NULL;
+
+ /* Because of the difference, we need to remember the protocol. */
+
+ sc->sc_bchan[chan].bprot = bprot;
+ sc->sc_bchan[chan].busy = 0;
+}
+
+static void
+i4b_capi_bch_start_tx(int unit, int chan)
+{
+ capi_softc_t *sc = capi_sc[unit];
+ int s;
+
+ s = SPLI4B();
+
+ if (sc->sc_bchan[chan].state != B_CONNECTED) {
+ splx(s);
+ printf("capi%d: start_tx on unconnected channel\n", sc->sc_unit);
+ return;
+ }
+
+ if (sc->sc_bchan[chan].busy) {
+ splx(s);
+ return;
+ }
+
+ capi_start_tx(sc, chan);
+
+ splx(s);
+}
+
+static void
+i4b_capi_bch_stat(int unit, int chan, bchan_statistics_t *bsp)
+{
+ capi_softc_t *sc = capi_sc[unit];
+ int s = SPLI4B();
+
+ bsp->outbytes = sc->sc_bchan[chan].txcount;
+ bsp->inbytes = sc->sc_bchan[chan].rxcount;
+
+ sc->sc_bchan[chan].txcount = 0;
+ sc->sc_bchan[chan].rxcount = 0;
+
+ splx(s);
+}
+
+int capi_start_tx(capi_softc_t *sc, int chan)
+{
+ struct mbuf *m_b3;
+ int sent = 0;
+
+ _IF_DEQUEUE(&sc->sc_bchan[chan].tx_queue, m_b3);
+ while (m_b3) {
+ struct mbuf *m = m_b3->m_next;
+
+ sc->sc_bchan[chan].txcount += m_b3->m_len;
+ capi_data_b3_req(sc, chan, m_b3);
+ sent++;
+
+ m_b3 = m;
+ }
+
+ if (sc->sc_bchan[chan].capi_drvr_linktab) {
+ /* Notify i4b driver of activity, and if the queue is drained. */
+
+ if (sent)
+ (*sc->sc_bchan[chan].capi_drvr_linktab->bch_activity)(
+ sc->sc_bchan[chan].capi_drvr_linktab->unit, ACT_TX);
+
+ if (IF_QEMPTY(&sc->sc_bchan[chan].tx_queue))
+ (*sc->sc_bchan[chan].capi_drvr_linktab->bch_tx_queue_empty)(
+ sc->sc_bchan[chan].capi_drvr_linktab->unit);
+ }
+
+ return sent;
+}
+
+/*
+// capi_ll_attach
+// Called by a link layer driver at boot time.
+*/
+
+int
+capi_ll_attach(capi_softc_t *sc)
+{
+ int i;
+
+ if (ncapi == (sizeof(capi_sc) / sizeof(capi_sc[0]))) {
+ printf("capi%d: too many units, increase MAX_CONTROLLERS\n", ncapi);
+ return (ENXIO);
+ }
+
+ /* Unit type and subtype; sc is partly filled by ll driver */
+
+ ctrl_desc[nctrl].unit = ncapi;
+ ctrl_desc[nctrl].ctrl_type = CTRL_CAPI;
+ ctrl_desc[nctrl].card_type = sc->card_type;
+
+ /* L4 callbacks */
+
+ ctrl_types[CTRL_CAPI].get_linktab = i4b_capi_ret_linktab;
+ ctrl_types[CTRL_CAPI].set_linktab = i4b_capi_set_linktab;
+
+ ctrl_desc[nctrl].N_CONNECT_REQUEST = n_connect_request;
+ ctrl_desc[nctrl].N_CONNECT_RESPONSE = n_connect_response;
+ ctrl_desc[nctrl].N_DISCONNECT_REQUEST = n_disconnect_request;
+ ctrl_desc[nctrl].N_ALERT_REQUEST = n_alert_request;
+ ctrl_desc[nctrl].N_DOWNLOAD = n_download;
+ ctrl_desc[nctrl].N_DIAGNOSTICS = NULL; /* XXX todo */
+ ctrl_desc[nctrl].N_MGMT_COMMAND = n_mgmt_command;
+
+ /* Unit state */
+
+ sc->sc_enabled = FALSE;
+ sc->sc_state = C_DOWN;
+ sc->sc_msgid = 0;
+
+ ctrl_desc[nctrl].dl_est = DL_DOWN;
+ ctrl_desc[nctrl].nbch = sc->sc_nbch;
+
+ for (i = 0; i < sc->sc_nbch; i++) {
+ ctrl_desc[nctrl].bch_state[i] = BCH_ST_FREE;
+ sc->sc_bchan[i].ncci = INVALID;
+ sc->sc_bchan[i].msgid = 0;
+ sc->sc_bchan[i].busy = 0;
+ sc->sc_bchan[i].state = B_FREE;
+
+ memset(&sc->sc_bchan[i].tx_queue, 0, sizeof(struct ifqueue));
+ memset(&sc->sc_bchan[i].rx_queue, 0, sizeof(struct ifqueue));
+ sc->sc_bchan[i].tx_queue.ifq_maxlen = IFQ_MAXLEN;
+ sc->sc_bchan[i].rx_queue.ifq_maxlen = IFQ_MAXLEN;
+
+#if defined (__FreeBSD__) && __FreeBSD__ > 4
+ mtx_init(&sc->sc_bchan[i].tx_queue.ifq_mtx, "i4b_capi_tx", MTX_DEF);
+ mtx_init(&sc->sc_bchan[i].rx_queue.ifq_mtx, "i4b_capi_rx", MTX_DEF);
+#endif
+
+ sc->sc_bchan[i].txcount = 0;
+ sc->sc_bchan[i].rxcount = 0;
+
+ sc->sc_bchan[i].cdid = CDID_UNUSED;
+ sc->sc_bchan[i].bprot = BPROT_NONE;
+ sc->sc_bchan[i].in_mbuf = NULL;
+
+ sc->sc_bchan[i].capi_drvr_linktab = NULL;
+
+ sc->sc_bchan[i].capi_isdn_linktab.unit = ncapi;
+ sc->sc_bchan[i].capi_isdn_linktab.channel = i;
+ sc->sc_bchan[i].capi_isdn_linktab.bch_config = i4b_capi_bch_config;
+ sc->sc_bchan[i].capi_isdn_linktab.bch_tx_start = i4b_capi_bch_start_tx;
+ sc->sc_bchan[i].capi_isdn_linktab.bch_stat = i4b_capi_bch_stat;
+ sc->sc_bchan[i].capi_isdn_linktab.tx_queue = &sc->sc_bchan[i].tx_queue;
+ sc->sc_bchan[i].capi_isdn_linktab.rx_queue = &sc->sc_bchan[i].rx_queue;
+ sc->sc_bchan[i].capi_isdn_linktab.rx_mbuf = &sc->sc_bchan[i].in_mbuf;
+ }
+
+ ctrl_desc[nctrl].tei = -1;
+
+ /* Up the controller index and store the softc */
+
+ sc->sc_unit = ncapi;
+ capi_sc[ncapi++] = sc;
+ sc->ctrl_unit = nctrl++;
+
+ printf("capi%d: card type %d attached\n", sc->sc_unit, sc->card_type);
+
+ return(0);
+}
+
+/*
+// n_mgmt_command
+// i4b L4 management command.
+*/
+
+static void
+n_mgmt_command(int unit, int op, void *arg)
+{
+ capi_softc_t *sc = capi_sc[unit];
+
+ printf("capi%d: mgmt command %d\n", sc->sc_unit, op);
+
+ switch(op) {
+ case CMR_DOPEN:
+ sc->sc_enabled = TRUE;
+ break;
+
+ case CMR_DCLOSE:
+ sc->sc_enabled = FALSE;
+ break;
+
+ case CMR_SETTRACE:
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*
+// n_connect_request
+// i4b L4 wants to connect. We assign a B channel to the call,
+// send a CAPI_CONNECT_REQ, and set the channel to B_CONNECT_CONF.
+*/
+
+static void
+n_connect_request(u_int cdid)
+{
+ call_desc_t *cd = cd_by_cdid(cdid);
+ capi_softc_t *sc;
+ int bch, s;
+
+ if (!cd) {
+ printf("capi?: invalid cdid %d\n", cdid);
+ return;
+ }
+
+ sc = capi_sc[ctrl_desc[cd->controller].unit];
+ bch = cd->channelid;
+
+ s = SPLI4B();
+
+ if ((bch < 0) || (bch >= sc->sc_nbch))
+ for (bch = 0; bch < sc->sc_nbch; bch++)
+ if (sc->sc_bchan[bch].state == B_FREE)
+ break;
+
+ if (bch == sc->sc_nbch) {
+ splx(s);
+ printf("capi%d: no free B channel\n", sc->sc_unit);
+ return;
+ }
+
+ cd->channelid = bch;
+
+ capi_connect_req(sc, cd);
+ splx(s);
+}
+
+/*
+// n_connect_response
+// i4b L4 answers a call. We send a CONNECT_RESP with the proper
+// Reject code, and set the channel to B_CONNECT_B3_IND or B_FREE,
+// depending whether we answer or not.
+*/
+
+static void
+n_connect_response(u_int cdid, int response, int cause)
+{
+ call_desc_t *cd = cd_by_cdid(cdid);
+ capi_softc_t *sc;
+ int bch, s;
+
+ if (!cd) {
+ printf("capi?: invalid cdid %d\n", cdid);
+ return;
+ }
+
+ sc = capi_sc[ctrl_desc[cd->controller].unit];
+ bch = cd->channelid;
+
+ T400_stop(cd);
+
+ cd->response = response;
+ cd->cause_out = cause;
+
+ s = SPLI4B();
+ capi_connect_resp(sc, cd);
+ splx(s);
+}
+
+/*
+// n_disconnect_request
+// i4b L4 wants to disconnect. We send a DISCONNECT_REQ and
+// set the channel to B_DISCONNECT_CONF.
+*/
+
+static void
+n_disconnect_request(u_int cdid, int cause)
+{
+ call_desc_t *cd = cd_by_cdid(cdid);
+ capi_softc_t *sc;
+ int bch, s;
+
+ if (!cd) {
+ printf("capi?: invalid cdid %d\n", cdid);
+ return;
+ }
+
+ sc = capi_sc[ctrl_desc[cd->controller].unit];
+ bch = cd->channelid;
+
+ cd->cause_out = cause;
+
+ s = SPLI4B();
+ capi_disconnect_req(sc, cd);
+ splx(s);
+}
+
+/*
+// n_alert_request
+// i4b L4 wants to alert an incoming call. We send ALERT_REQ.
+*/
+
+static void
+n_alert_request(u_int cdid)
+{
+ call_desc_t *cd = cd_by_cdid(cdid);
+ capi_softc_t *sc;
+ int s;
+
+ if (!cd) {
+ printf("capi?: invalid cdid %d\n", cdid);
+ return;
+ }
+
+ sc = capi_sc[ctrl_desc[cd->controller].unit];
+
+ s = SPLI4B();
+ capi_alert_req(sc, cd);
+ splx(s);
+}
+
+/*
+// n_download
+// L4 -> firmware download
+*/
+
+static int
+n_download(int unit, int numprotos, struct isdn_dr_prot *protocols)
+{
+ capi_softc_t *sc = capi_sc[unit];
+
+ if (sc->load) {
+ (*capi_sc[unit]->load)(sc, protocols[0].bytecount,
+ protocols[0].microcode);
+ }
+
+ return(0);
+}
+
+#endif /* NI4BCAPI > 0 */
diff --git a/sys/i4b/capi/capi_llif.c b/sys/i4b/capi/capi_llif.c
new file mode 100644
index 0000000..a022861
--- /dev/null
+++ b/sys/i4b/capi/capi_llif.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2001 Cubical Solutions Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * capi/capi_llif.c The i4b CAPI link layer interface.
+ *
+ * $FreeBSD$
+ */
+
+#include "i4bcapi.h"
+#if NI4BCAPI > 0
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_cause.h>
+
+#include <i4b/include/i4b_l3l4.h>
+#include <i4b/include/i4b_mbuf.h>
+#include <i4b/include/i4b_global.h>
+
+#include <i4b/layer4/i4b_l4.h>
+
+#include <i4b/capi/capi.h>
+#include <i4b/capi/capi_msgs.h>
+
+/*
+// capi_ll_control
+// CAPI link layer control routine. Called by a link layer
+// driver when its state changes.
+*/
+
+int
+capi_ll_control(capi_softc_t *sc, int op, int arg)
+{
+ switch (op) {
+ case CAPI_CTRL_READY:
+ if (arg) {
+ sc->sc_state = C_READY;
+
+ /*
+ * Register our CAPI ApplId and send CAPI_LISTEN_REQ
+ * with CIP Mask value 1 (match all).
+ */
+
+ sc->reg_appl(sc, I4BCAPI_APPLID, sc->sc_nbch);
+ capi_listen_req(sc, 0x10007);
+
+ } else {
+ sc->sc_state = C_DOWN;
+ /* XXX go through cds and notify L4 of pdeact? XXX */
+ }
+ break;
+
+ case CAPI_CTRL_PROFILE:
+ bcopy((char*) arg, &sc->sc_profile, sizeof(sc->sc_profile));
+ break;
+
+ case CAPI_CTRL_NEW_NCCI:
+ case CAPI_CTRL_FREE_NCCI:
+ /* We ignore the controller's NCCI notifications. */
+ break;
+
+ default:
+ printf("capi%d: unknown control %d\n", sc->sc_unit, op);
+ }
+
+ return 0;
+}
+
+/*
+// i4b_capi_handlers
+// Array of message-handler pairs used to dispatch CAPI
+// messages sent to I4BCAPI_APPLID.
+*/
+
+static struct capi_cmdtab {
+ u_int16_t cmd;
+ void (*handler)(capi_softc_t *, struct mbuf *);
+} i4b_capi_handlers[] = {
+ { CAPI_LISTEN_CONF, capi_listen_conf },
+ { CAPI_INFO_IND, capi_info_ind },
+ { CAPI_ALERT_CONF, capi_alert_conf },
+ { CAPI_CONNECT_CONF, capi_connect_conf },
+ { CAPI_CONNECT_IND, capi_connect_ind },
+ { CAPI_CONNECT_ACTIVE_IND, capi_connect_active_ind },
+ { CAPI_CONNECT_B3_CONF, capi_connect_b3_conf },
+ { CAPI_CONNECT_B3_IND, capi_connect_b3_ind },
+ { CAPI_CONNECT_B3_ACTIVE_IND, capi_connect_b3_active_ind },
+ { CAPI_DATA_B3_CONF, capi_data_b3_conf },
+ { CAPI_DATA_B3_IND, capi_data_b3_ind },
+ { CAPI_DISCONNECT_B3_IND, capi_disconnect_b3_ind },
+ { CAPI_DISCONNECT_CONF, capi_disconnect_conf },
+ { CAPI_DISCONNECT_IND, capi_disconnect_ind },
+ { 0, 0 }
+};
+
+/*
+// capi_ll_receive
+// CAPI link layer receive upcall. Called by a link layer
+// driver to dispatch incoming CAPI messages.
+*/
+
+int
+capi_ll_receive(capi_softc_t *sc, struct mbuf *m)
+{
+ u_int8_t *p = mtod(m, u_int8_t*);
+ u_int16_t len, applid, msgid, cmd;
+
+ capimsg_getu16(p + 0, &len);
+ capimsg_getu16(p + 2, &applid);
+ capimsg_getu16(p + 4, &cmd);
+ capimsg_getu16(p + 6, &msgid);
+
+#if 0
+ printf("capi%d: ll_receive hdr %04x %04x %04x %04x\n", sc->sc_unit,
+ len, applid, cmd, msgid);
+#endif
+
+ if (applid == I4BCAPI_APPLID) {
+ struct capi_cmdtab *e;
+ for (e = i4b_capi_handlers; e->cmd && e->cmd != cmd; e++);
+ if (e->cmd) (*e->handler)(sc, m);
+ else printf("capi%d: unknown message %04x\n", sc->sc_unit, cmd);
+
+ } else {
+ /* XXX we could handle arbitrary ApplIds here XXX */
+ printf("capi%d: message %04x for unknown applid %d\n", sc->sc_unit,
+ cmd, applid);
+ }
+
+ if (m->m_next) {
+ i4b_Bfreembuf(m->m_next);
+ m->m_next = NULL;
+ }
+ i4b_Dfreembuf(m);
+ return(0);
+}
+
+#endif /* NI4BCAPI > 0*/
diff --git a/sys/i4b/capi/capi_msgs.c b/sys/i4b/capi/capi_msgs.c
new file mode 100644
index 0000000..a2ce023
--- /dev/null
+++ b/sys/i4b/capi/capi_msgs.c
@@ -0,0 +1,948 @@
+/*
+ * Copyright (c) 2001 Cubical Solutions Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * capi/capi_msgs.c The CAPI i4b message handlers.
+ *
+ * $FreeBSD$
+ */
+
+#include "i4bcapi.h"
+#if NI4BCAPI > 0
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_cause.h>
+
+#include <i4b/include/i4b_l3l4.h>
+#include <i4b/include/i4b_mbuf.h>
+#include <i4b/include/i4b_global.h>
+
+#include <i4b/layer4/i4b_l4.h>
+
+#include <i4b/capi/capi.h>
+#include <i4b/capi/capi_msgs.h>
+
+/*
+// Administrative messages:
+// ------------------------
+*/
+
+void capi_listen_req(capi_softc_t *sc, u_int32_t CIP)
+{
+ struct mbuf *m = i4b_Dgetmbuf(8 + 18);
+ u_int8_t *msg;
+ u_int16_t msgid;
+
+ if (!m) {
+ printf("capi%d: can't get mbuf for listen_req\n", sc->sc_unit);
+ return;
+ }
+
+ msgid = sc->sc_msgid++;
+
+ msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len);
+ msg = capimsg_setu16(msg, I4BCAPI_APPLID);
+ msg = capimsg_setu16(msg, CAPI_LISTEN_REQ);
+ msg = capimsg_setu16(msg, msgid);
+
+ msg = capimsg_setu32(msg, 1); /* Controller */
+ msg = capimsg_setu32(msg, 0); /* Info mask */
+ msg = capimsg_setu32(msg, CIP);
+ msg = capimsg_setu32(msg, 0);
+ msg = capimsg_setu8(msg, 0);
+ msg = capimsg_setu8(msg, 0);
+
+ sc->send(sc, m);
+}
+
+void capi_listen_conf(capi_softc_t *sc, struct mbuf *m_in)
+{
+ u_int8_t *msg = mtod(m_in, u_int8_t*);
+ u_int16_t Info;
+
+ capimsg_getu16(msg + 12, &Info);
+
+ if (Info == 0) {
+ /* We are now listening. */
+
+ sc->sc_state = C_UP;
+ ctrl_desc[sc->ctrl_unit].dl_est = DL_UP;
+
+ i4b_l4_l12stat(sc->ctrl_unit, 1, 1);
+ i4b_l4_l12stat(sc->ctrl_unit, 2, 1);
+
+ } else {
+ /* XXX sc->sc_state = C_DOWN ? XXX */
+ printf("capi%d: can't listen, info=%04x\n", sc->sc_unit, Info);
+ }
+}
+
+void capi_info_ind(capi_softc_t *sc, struct mbuf *m_in)
+{
+ struct mbuf *m = i4b_Dgetmbuf(8 + 4);
+ u_int8_t *msg = mtod(m_in, u_int8_t*);
+ u_int16_t applid, msgid;
+ u_int32_t PLCI;
+
+ if (!m) {
+ printf("capi%d: can't get mbuf for info_resp\n", sc->sc_unit);
+ return;
+ }
+
+ msg = capimsg_getu16(msg + 2, &applid);
+ msg = capimsg_getu16(msg + 2, &msgid);
+ msg = capimsg_getu32(msg, &PLCI);
+
+ /* i4b_l4_info_ind() */
+
+ msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len);
+ msg = capimsg_setu16(msg, applid);
+ msg = capimsg_setu16(msg, CAPI_INFO_RESP);
+ msg = capimsg_setu16(msg, msgid);
+
+ msg = capimsg_setu32(msg, PLCI);
+
+ sc->send(sc, m);
+}
+
+void capi_alert_req(capi_softc_t *sc, call_desc_t *cd)
+{
+ struct mbuf *m = i4b_Dgetmbuf(8 + 5);
+ u_int8_t *msg;
+ u_int16_t msgid;
+ u_int32_t PLCI;
+
+ if (!m) {
+ printf("capi%d: can't get mbuf for alert_req\n", sc->sc_unit);
+ return;
+ }
+
+ msgid = sc->sc_bchan[cd->channelid].msgid = sc->sc_msgid++;
+ PLCI = (sc->sc_bchan[cd->channelid].ncci & CAPI_PLCI_MASK);
+
+ msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len);
+ msg = capimsg_setu16(msg, I4BCAPI_APPLID);
+ msg = capimsg_setu16(msg, CAPI_ALERT_REQ);
+ msg = capimsg_setu16(msg, msgid);
+
+ msg = capimsg_setu32(msg, PLCI);
+ msg = capimsg_setu8(msg, 0);
+
+ sc->send(sc, m);
+}
+
+void capi_alert_conf(capi_softc_t *sc, struct mbuf *m_in)
+{
+ u_int8_t *msg = mtod(m_in, u_int8_t*);
+ u_int16_t Info;
+
+ msg = capimsg_getu16(msg + 12, &Info);
+
+ if (Info) {
+ printf("capi%d: can't alert, info=%04x\n", sc->sc_unit, Info);
+ }
+}
+
+/*
+// Outgoing call setup:
+// --------------------
+//
+// CAPI_CONNECT_REQ -->
+// <-- CAPI_CONNECT_CONF
+// (notify Layer 4)
+// <-- CAPI_CONNECT_ACTIVE_IND
+// CAPI_CONNECT_ACTIVE_RESP -->
+// CAPI_CONNECT_B3_REQ -->
+// <-- CAPI_CONNECT_B3_CONF
+// <-- CAPI_CONNECT_B3_ACTIVE_IND
+// CAPI_CONNECT_B3_ACTIVE_RESP -->
+// (notify Layer 4)
+*/
+
+void capi_connect_req(capi_softc_t *sc, call_desc_t *cd)
+{
+ struct mbuf *m;
+ u_int8_t *msg;
+ u_int16_t msgid;
+ int slen = strlen(cd->src_telno);
+ int dlen = strlen(cd->dst_telno);
+
+ m = i4b_Dgetmbuf(8 + 18 + slen + dlen);
+ if (!m) {
+ printf("capi%d: can't get mbuf for connect_req\n", sc->sc_unit);
+ return;
+ }
+
+ cd->crflag = CRF_ORIG;
+
+ sc->sc_bchan[cd->channelid].cdid = cd->cdid;
+ sc->sc_bchan[cd->channelid].bprot = cd->bprot;
+ sc->sc_bchan[cd->channelid].state = B_CONNECT_CONF;
+ msgid = sc->sc_bchan[cd->channelid].msgid = sc->sc_msgid++;
+ ctrl_desc[sc->ctrl_unit].bch_state[cd->channelid] = BCH_ST_RSVD;
+
+ msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len);
+ msg = capimsg_setu16(msg, I4BCAPI_APPLID);
+ msg = capimsg_setu16(msg, CAPI_CONNECT_REQ);
+ msg = capimsg_setu16(msg, msgid);
+
+ msg = capimsg_setu32(msg, 1); /* Controller */
+
+ switch (cd->bprot) {
+ case BPROT_NONE:
+ msg = capimsg_setu16(msg, 0x0010); /* Telephony */
+ break;
+
+ case BPROT_RHDLC:
+ msg = capimsg_setu16(msg, 0x0002); /* Unrestricted digital */
+ break;
+
+ default:
+ msg = capimsg_setu16(msg, 0x0002); /* Unrestricted digital */
+ }
+
+ msg = capimsg_setu8(msg, 1 + dlen);
+ msg = capimsg_setu8(msg, 0x80);
+ strncpy(msg, cd->dst_telno, dlen);
+
+ msg = capimsg_setu8(msg + dlen, 2 + slen);
+ msg = capimsg_setu8(msg, 0x00);
+ msg = capimsg_setu8(msg, 0x80); /* Presentation and screening indicator */
+ strncpy(msg, cd->src_telno, slen);
+
+ msg = capimsg_setu8(msg + slen, 0); /* Called & */
+ msg = capimsg_setu8(msg, 0); /* Calling party subaddress */
+
+ msg = capimsg_setu8(msg, 15); /* B protocol */
+ if (cd->bprot == BPROT_NONE)
+ msg = capimsg_setu16(msg, 1); /* B1 protocol = transparent */
+ else
+ msg = capimsg_setu16(msg, 0); /* B1 protocol = HDLC */
+ msg = capimsg_setu16(msg, 1); /* B2 protocol = transparent */
+ msg = capimsg_setu16(msg, 0); /* B3 protocol = transparent */
+ msg = capimsg_setu8(msg, 0); /* B1 parameters */
+ msg = capimsg_setu8(msg, 0); /* B2 parameters */
+ msg = capimsg_setu8(msg, 0); /* B3 parameters */
+
+ msg = capimsg_setu8(msg, 0); /* Bearer Capability */
+ msg = capimsg_setu8(msg, 0); /* Low Layer Compatibility */
+ msg = capimsg_setu8(msg, 0); /* High Layer Compatibility */
+ msg = capimsg_setu8(msg, 0); /* Additional Info */
+
+ sc->send(sc, m);
+}
+
+void capi_connect_conf(capi_softc_t *sc, struct mbuf *m_in)
+{
+ u_int8_t *msg = mtod(m_in, u_int8_t*);
+ call_desc_t *cd;
+ u_int16_t msgid;
+ u_int32_t PLCI;
+ u_int16_t Info;
+ int bch;
+
+ msg = capimsg_getu16(msg + 6, &msgid);
+ msg = capimsg_getu32(msg, &PLCI);
+ msg = capimsg_getu16(msg, &Info);
+
+ for (bch = 0; bch < sc->sc_nbch; bch++)
+ if ((sc->sc_bchan[bch].state == B_CONNECT_CONF) &&
+ (sc->sc_bchan[bch].msgid == msgid))
+ break;
+
+ if ((bch == sc->sc_nbch) ||
+ (cd = cd_by_cdid(sc->sc_bchan[bch].cdid)) == NULL) {
+ printf("capi%d: can't find channel for connect_conf PLCI %x\n",
+ sc->sc_unit, PLCI);
+ return;
+ }
+
+ if (Info == 0) {
+ sc->sc_bchan[bch].state = B_CONNECT_ACTIVE_IND;
+ sc->sc_bchan[bch].ncci = PLCI;
+
+ i4b_l4_proceeding_ind(cd);
+
+ } else {
+ SET_CAUSE_TV(cd->cause_out, CAUSET_I4B, CAUSE_I4B_L1ERROR);
+ i4b_l4_disconnect_ind(cd);
+ freecd_by_cd(cd);
+
+ sc->sc_bchan[bch].state = B_FREE;
+ ctrl_desc[sc->ctrl_unit].bch_state[bch] = BCH_ST_FREE;
+
+ printf("capi%d: can't connect out, info=%04x\n", sc->sc_unit, Info);
+ }
+}
+
+void capi_connect_active_ind(capi_softc_t *sc, struct mbuf *m_in)
+{
+ struct mbuf *m = i4b_Dgetmbuf(8 + 4);
+ u_int8_t *msg = mtod(m_in, u_int8_t*);
+ call_desc_t *cd;
+ u_int16_t applid, msgid;
+ u_int32_t PLCI;
+ int bch;
+
+ if (!m) {
+ printf("capi%d: can't get mbuf for active_ind\n", sc->sc_unit);
+ return;
+ }
+
+ msg = capimsg_getu16(msg + 2, &applid);
+ msg = capimsg_getu16(msg + 2, &msgid);
+ msg = capimsg_getu32(msg, &PLCI);
+
+ for (bch = 0; bch < sc->sc_nbch; bch++)
+ if ((sc->sc_bchan[bch].state == B_CONNECT_ACTIVE_IND) &&
+ (sc->sc_bchan[bch].ncci == PLCI))
+ break;
+
+ if ((bch == sc->sc_nbch) ||
+ (cd = cd_by_cdid(sc->sc_bchan[bch].cdid)) == NULL) {
+ printf("capi%d: can't find channel for active_resp, PLCI %x\n",
+ sc->sc_unit, PLCI);
+ return;
+ }
+
+ msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len);
+ msg = capimsg_setu16(msg, applid);
+ msg = capimsg_setu16(msg, CAPI_CONNECT_ACTIVE_RESP);
+ msg = capimsg_setu16(msg, msgid);
+
+ msg = capimsg_setu32(msg, PLCI);
+
+ sc->send(sc, m);
+
+ if (cd->crflag == CRF_ORIG) {
+ capi_connect_b3_req(sc, cd);
+
+ } else {
+ sc->sc_bchan[bch].state = B_CONNECT_B3_IND;
+ }
+}
+
+void capi_connect_b3_req(capi_softc_t *sc, call_desc_t *cd)
+{
+ struct mbuf *m = i4b_Dgetmbuf(8 + 5);
+ u_int8_t *msg;
+ u_int16_t msgid;
+ u_int32_t PLCI;
+
+ if (!m) {
+ printf("capi%d: can't get mbuf for connect_b3_req\n", sc->sc_unit);
+ return;
+ }
+
+ sc->sc_bchan[cd->channelid].state = B_CONNECT_B3_CONF;
+ msgid = sc->sc_bchan[cd->channelid].msgid = sc->sc_msgid++;
+ PLCI = (sc->sc_bchan[cd->channelid].ncci & CAPI_PLCI_MASK);
+
+ msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len);
+ msg = capimsg_setu16(msg, I4BCAPI_APPLID);
+ msg = capimsg_setu16(msg, CAPI_CONNECT_B3_REQ);
+ msg = capimsg_setu16(msg, msgid);
+
+ msg = capimsg_setu32(msg, PLCI);
+ msg = capimsg_setu8(msg, 0); /* NCPI */
+
+ sc->send(sc, m);
+}
+
+void capi_connect_b3_conf(capi_softc_t *sc, struct mbuf *m_in)
+{
+ u_int8_t *msg = mtod(m_in, u_int8_t*);
+ call_desc_t *cd;
+ u_int16_t msgid;
+ u_int32_t NCCI;
+ u_int16_t Info;
+ int bch;
+
+ msg = capimsg_getu16(msg + 6, &msgid);
+ msg = capimsg_getu32(msg, &NCCI);
+ msg = capimsg_getu16(msg, &Info);
+
+ for (bch = 0; bch < sc->sc_nbch; bch++)
+ if ((sc->sc_bchan[bch].state == B_CONNECT_B3_CONF) &&
+ (sc->sc_bchan[bch].ncci == (NCCI & CAPI_PLCI_MASK)))
+ break;
+
+ if ((bch == sc->sc_nbch) ||
+ (cd = cd_by_cdid(sc->sc_bchan[bch].cdid)) == NULL) {
+ printf("capi%d: can't find channel for connect_b3_conf NCCI %x\n",
+ sc->sc_unit, NCCI);
+ return;
+ }
+
+ if (Info == 0) {
+ sc->sc_bchan[bch].ncci = NCCI;
+ sc->sc_bchan[bch].state = B_CONNECT_B3_ACTIVE_IND;
+
+ } else {
+ SET_CAUSE_TV(cd->cause_in, CAUSET_I4B, CAUSE_I4B_OOO); /* XXX */
+ i4b_l4_disconnect_ind(cd);
+ freecd_by_cd(cd);
+
+ ctrl_desc[sc->ctrl_unit].bch_state[bch] = BCH_ST_RSVD;
+
+ printf("capi%d: can't connect_b3 out, info=%04x\n", sc->sc_unit, Info);
+
+ capi_disconnect_req(sc, cd);
+ }
+}
+
+void capi_connect_b3_active_ind(capi_softc_t *sc, struct mbuf *m_in)
+{
+ struct mbuf *m = i4b_Dgetmbuf(8 + 4);
+ u_int8_t *msg = mtod(m_in, u_int8_t*);
+ call_desc_t *cd;
+ u_int16_t applid, msgid;
+ u_int32_t NCCI;
+ int bch;
+
+ if (!m) {
+ printf("capi%d: can't get mbuf for b3_active_ind\n", sc->sc_unit);
+ return;
+ }
+
+ msg = capimsg_getu16(msg + 2, &applid);
+ msg = capimsg_getu16(msg + 2, &msgid);
+ msg = capimsg_getu32(msg, &NCCI);
+
+ for (bch = 0; bch < sc->sc_nbch; bch++)
+ if ((sc->sc_bchan[bch].state == B_CONNECT_B3_ACTIVE_IND) &&
+ (sc->sc_bchan[bch].ncci == NCCI))
+ break;
+
+ if ((bch == sc->sc_nbch) ||
+ (cd = cd_by_cdid(sc->sc_bchan[bch].cdid)) == NULL) {
+ printf("capi%d: can't find channel for b3_active_resp NCCI %x\n",
+ sc->sc_unit, NCCI);
+ return;
+ }
+
+ msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len);
+ msg = capimsg_setu16(msg, I4BCAPI_APPLID);
+ msg = capimsg_setu16(msg, CAPI_CONNECT_B3_ACTIVE_RESP);
+ msg = capimsg_setu16(msg, msgid);
+
+ msg = capimsg_setu32(msg, NCCI);
+
+ sc->send(sc, m);
+
+ sc->sc_bchan[bch].state = B_CONNECTED;
+ i4b_l4_connect_active_ind(cd);
+}
+
+/*
+// Incoming call setup:
+// --------------------
+//
+// <-- CAPI_CONNECT_IND
+// (consult Layer 4)
+// CAPI_CONNECT_RESP -->
+// <-- CAPI_CONNECT_ACTIVE_IND
+// CAPI_CONNECT_ACTIVE_RESP -->
+// <-- CAPI_CONNECT_B3_IND
+// CAPI_CONNECT_B3_RESP -->
+// <-- CAPI_CONNECT_B3_ACTIVE_IND
+// CAPI_CONNECT_B3_ACTIVE_RESP -->
+// (notify Layer 4)
+*/
+
+void capi_connect_ind(capi_softc_t *sc, struct mbuf *m_in)
+{
+ u_int8_t *msg = mtod(m_in, u_int8_t*);
+ call_desc_t *cd;
+ u_int16_t applid, msgid;
+ u_int32_t PLCI;
+ u_int16_t CIP;
+ u_int8_t x, y, z;
+ int bch;
+
+ if ((cd = reserve_cd()) == NULL) {
+ printf("capi%d: can't get cd for connect_ind\n", sc->sc_unit);
+ return;
+ }
+
+ cd->controller = sc->ctrl_unit;
+ cd->channelexcl = FALSE;
+
+ for (bch = 0; bch < sc->sc_nbch; bch++)
+ if (sc->sc_bchan[bch].state == B_FREE) break;
+ sc->sc_bchan[bch].state = B_CONNECT_IND;
+ cd->channelid = bch; /* XXX CHAN_ANY XXX */
+
+ cd->crflag = CRF_DEST;
+ cd->cr = get_rand_cr(sc->sc_unit);
+ cd->scr_ind = SCR_NONE;
+ cd->prs_ind = PRS_NONE;
+ cd->bprot = BPROT_NONE;
+ cd->ilt = NULL;
+ cd->dlt = NULL;
+ cd->display[0] = '\0';
+ cd->datetime[0] = '\0';
+
+ msg = capimsg_getu16(msg + 2, &applid);
+ msg = capimsg_getu16(msg + 2, &msgid);
+ msg = capimsg_getu32(msg, &PLCI);
+ msg = capimsg_getu16(msg, &CIP);
+
+ cd->event = (int) msgid; /* XXX overload */
+ cd->Q931state = (int) PLCI; /* XXX overload */
+
+ switch (CIP) {
+ case 0x0010:
+ case 0x0001: cd->bprot = BPROT_NONE; break;
+ case 0x0002: cd->bprot = BPROT_RHDLC; break;
+ default:
+ NDBGL4(L4_CAPIDBG, "capi%d: unknown CIP = %d", sc->sc_unit, CIP);
+ cd->bprot = BPROT_NONE;
+ }
+
+ msg = capimsg_getu8(msg, &x); /* Called party struct len */
+ if (x) {
+ msg = capimsg_getu8(msg, &y); /* Numbering plan */
+ z = x - 1;
+ if (z >= TELNO_MAX) z = (TELNO_MAX-1);
+ strncpy(cd->dst_telno, msg, z);
+ msg += x;
+ x = z;
+ }
+ cd->dst_telno[x] = '\0';
+
+ msg = capimsg_getu8(msg, &x); /* Calling party struct len */
+ if (x) {
+ msg = capimsg_getu8(msg, &y); /* Numbering plan */
+ msg = capimsg_getu8(msg, &y); /* Screening/Presentation */
+ if ((y & 0x80) == 0) { /* screening used */
+ cd->scr_ind = (y & 3) + SCR_USR_NOSC;
+ cd->prs_ind = ((y >> 5) & 3) + PRS_ALLOWED;
+ }
+ z = x - 2;
+ if (z >= TELNO_MAX) z = (TELNO_MAX-1);
+ strncpy(cd->src_telno, msg, z);
+ msg += x;
+ x = z;
+ }
+ cd->src_telno[x] = '\0';
+
+ i4b_l4_connect_ind(cd);
+}
+
+void capi_connect_resp(capi_softc_t *sc, call_desc_t *cd)
+{
+ struct mbuf *m;
+ u_int8_t *msg;
+ u_int16_t msgid;
+ u_int32_t PLCI;
+ int dlen = strlen(cd->dst_telno);
+
+ m = i4b_Dgetmbuf(8 + 11 + dlen);
+ if (!m) {
+ printf("capi%d: can't get mbuf for connect_resp\n", sc->sc_unit);
+ return;
+ }
+
+ msgid = (u_int16_t) cd->event;
+ PLCI = (u_int32_t) cd->Q931state;
+
+ msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len);
+ msg = capimsg_setu16(msg, I4BCAPI_APPLID);
+ msg = capimsg_setu16(msg, CAPI_CONNECT_RESP);
+ msg = capimsg_setu16(msg, msgid);
+
+ msg = capimsg_setu32(msg, PLCI);
+
+ switch (cd->response) {
+ case SETUP_RESP_ACCEPT:
+ sc->sc_bchan[cd->channelid].cdid = cd->cdid;
+ sc->sc_bchan[cd->channelid].ncci = PLCI;
+ sc->sc_bchan[cd->channelid].state = B_CONNECT_ACTIVE_IND;
+ ctrl_desc[sc->ctrl_unit].bch_state[cd->channelid] = BCH_ST_USED;
+ msg = capimsg_setu16(msg, 0); /* Accept the call */
+ break;
+
+ case SETUP_RESP_REJECT:
+ sc->sc_bchan[cd->channelid].state = B_FREE;
+ ctrl_desc[sc->ctrl_unit].bch_state[cd->channelid] = BCH_ST_FREE;
+ msg = capimsg_setu16(msg, 2); /* Reject, normal call clearing */
+ break;
+
+ case SETUP_RESP_DNTCRE:
+ sc->sc_bchan[cd->channelid].state = B_FREE;
+ ctrl_desc[sc->ctrl_unit].bch_state[cd->channelid] = BCH_ST_FREE;
+ msg = capimsg_setu16(msg, 1); /* Ignore */
+ break;
+
+ default:
+ sc->sc_bchan[cd->channelid].state = B_FREE;
+ ctrl_desc[sc->ctrl_unit].bch_state[cd->channelid] = BCH_ST_FREE;
+ msg = capimsg_setu16(msg, (0x3480|CAUSE_Q850_CALLREJ));
+ }
+
+ msg = capimsg_setu8(msg, 15); /* B protocol */
+ if (cd->bprot == BPROT_NONE)
+ msg = capimsg_setu16(msg, 1); /* B1 protocol = transparent */
+ else
+ msg = capimsg_setu16(msg, 0); /* B1 protocol = HDLC */
+ msg = capimsg_setu16(msg, 1); /* B2 protocol = transparent */
+ msg = capimsg_setu16(msg, 0); /* B3 protocol = transparent */
+ msg = capimsg_setu8(msg, 0); /* B1 parameters */
+ msg = capimsg_setu8(msg, 0); /* B2 parameters */
+ msg = capimsg_setu8(msg, 0); /* B3 parameters */
+
+ msg = capimsg_setu8(msg, 1 + dlen);
+ msg = capimsg_setu8(msg, 0x80); /* Numbering plan */
+ strncpy(msg, cd->dst_telno, dlen);
+ msg = capimsg_setu8(msg + dlen, 0); /* Connected subaddress */
+ msg = capimsg_setu8(msg, 0); /* Low Layer Compatibility */
+ msg = capimsg_setu8(msg, 0); /* Additional Info */
+
+ sc->send(sc, m);
+}
+
+void capi_connect_b3_ind(capi_softc_t *sc, struct mbuf *m_in)
+{
+ struct mbuf *m = i4b_Dgetmbuf(8 + 7);
+ u_int8_t *msg = mtod(m_in, u_int8_t*);
+ u_int16_t applid, msgid;
+ u_int32_t NCCI;
+ int bch;
+
+ if (!m) {
+ printf("capi%d: can't get mbuf for connect_b3_resp\n", sc->sc_unit);
+ return;
+ }
+
+ msg = capimsg_getu16(msg + 2, &applid);
+ msg = capimsg_getu16(msg + 2, &msgid);
+ msg = capimsg_getu32(msg, &NCCI);
+
+ for (bch = 0; bch < sc->sc_nbch; bch++)
+ if ((sc->sc_bchan[bch].state == B_CONNECT_B3_IND) &&
+ (sc->sc_bchan[bch].ncci == (NCCI & CAPI_PLCI_MASK)))
+ break;
+
+ msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len);
+ msg = capimsg_setu16(msg, applid);
+ msg = capimsg_setu16(msg, CAPI_CONNECT_B3_RESP);
+ msg = capimsg_setu16(msg, msgid);
+
+ msg = capimsg_setu32(msg, NCCI);
+
+ if (bch == sc->sc_nbch) {
+ printf("capi%d: can't get cd for connect_b3_resp NCCI %x\n",
+ sc->sc_unit, NCCI);
+ msg = capimsg_setu16(msg, 8); /* Reject, destination OOO */
+
+ } else {
+ sc->sc_bchan[bch].ncci = NCCI;
+ sc->sc_bchan[bch].state = B_CONNECT_B3_ACTIVE_IND;
+ msg = capimsg_setu16(msg, 0); /* Accept */
+ }
+
+ msg = capimsg_setu8(msg, 0); /* NCPI */
+
+ sc->send(sc, m);
+}
+
+/*
+// Data transfer:
+// --------------
+*/
+
+void capi_data_b3_req(capi_softc_t *sc, int chan, struct mbuf *m_b3)
+{
+ struct mbuf *m = i4b_Dgetmbuf(8 + 14);
+ u_int8_t *msg;
+ u_int16_t msgid;
+
+ if (!m) {
+ printf("capi%d: can't get mbuf for data_b3_req\n", sc->sc_unit);
+ return;
+ }
+
+ msgid = sc->sc_bchan[chan].msgid = sc->sc_msgid++;
+ sc->sc_bchan[chan].busy = 1;
+
+ msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len);
+ msg = capimsg_setu16(msg, I4BCAPI_APPLID);
+ msg = capimsg_setu16(msg, CAPI_DATA_B3_REQ);
+ msg = capimsg_setu16(msg, msgid);
+
+ msg = capimsg_setu32(msg, sc->sc_bchan[chan].ncci);
+ msg = capimsg_setu32(msg, (u_int32_t) m_b3->m_data); /* Pointer */
+ msg = capimsg_setu16(msg, m_b3->m_len);
+ msg = capimsg_setu16(msg, chan);
+ msg = capimsg_setu16(msg, 0); /* Flags */
+
+ m->m_next = m_b3;
+
+ sc->send(sc, m);
+}
+
+void capi_data_b3_conf(capi_softc_t *sc, struct mbuf *m_in)
+{
+ u_int8_t *msg = mtod(m_in, u_int8_t*);
+ u_int32_t NCCI;
+ u_int16_t handle;
+ u_int16_t Info;
+
+ msg = capimsg_getu32(msg + 8, &NCCI);
+ msg = capimsg_getu16(msg, &handle);
+ msg = capimsg_getu16(msg, &Info);
+
+ if (Info == 0) {
+ sc->sc_bchan[handle].busy = 0;
+ capi_start_tx(sc, handle);
+
+ } else {
+ printf("capi%d: data_b3_conf NCCI %x handle %x info=%04x\n",
+ sc->sc_unit, NCCI, handle, Info);
+ }
+}
+
+void capi_data_b3_ind(capi_softc_t *sc, struct mbuf *m_in)
+{
+ struct mbuf *m = i4b_Dgetmbuf(8 + 14);
+ u_int8_t *msg = mtod(m_in, u_int8_t*);
+ u_int16_t applid, msgid;
+ u_int32_t NCCI;
+ u_int16_t handle;
+ int bch;
+
+ if (!m) {
+ printf("capi%d: can't get mbuf for data_b3_resp\n", sc->sc_unit);
+ return;
+ }
+
+ msg = capimsg_getu16(msg + 2, &applid);
+ msg = capimsg_getu16(msg + 2, &msgid);
+ msg = capimsg_getu32(msg, &NCCI);
+ msg = capimsg_getu16(msg + 6, &handle);
+
+ for (bch = 0; bch < sc->sc_nbch; bch++)
+ if ((sc->sc_bchan[bch].state == B_CONNECTED) &&
+ (sc->sc_bchan[bch].ncci == NCCI))
+ break;
+
+ if (bch == sc->sc_nbch) {
+ printf("capi%d: can't find channel for data_b3_ind NCCI %x\n",
+ sc->sc_unit, NCCI);
+
+ } else {
+ if (sc->sc_bchan[bch].bprot == BPROT_RHDLC) {
+ /* HDLC drivers use rx_mbuf */
+
+ sc->sc_bchan[bch].in_mbuf = m_in->m_next;
+ sc->sc_bchan[bch].rxcount += m_in->m_next->m_len;
+ m_in->m_next = NULL; /* driver frees */
+
+ (*sc->sc_bchan[bch].capi_drvr_linktab->bch_rx_data_ready)(
+ sc->sc_bchan[bch].capi_drvr_linktab->unit);
+
+ } else {
+ /* Telephony drivers use rx_queue */
+
+ if (!_IF_QFULL(&sc->sc_bchan[bch].rx_queue)) {
+ _IF_ENQUEUE(&sc->sc_bchan[bch].rx_queue, m_in->m_next);
+ sc->sc_bchan[bch].rxcount += m_in->m_next->m_len;
+ m_in->m_next = NULL; /* driver frees */
+ }
+
+ (*sc->sc_bchan[bch].capi_drvr_linktab->bch_rx_data_ready)(
+ sc->sc_bchan[bch].capi_drvr_linktab->unit);
+ }
+ }
+
+ msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len);
+ msg = capimsg_setu16(msg, I4BCAPI_APPLID);
+ msg = capimsg_setu16(msg, CAPI_DATA_B3_RESP);
+ msg = capimsg_setu16(msg, msgid);
+
+ msg = capimsg_setu32(msg, NCCI);
+ msg = capimsg_setu16(msg, handle);
+
+ sc->send(sc, m);
+}
+
+/*
+// Connection teardown:
+// --------------------
+*/
+
+void capi_disconnect_req(capi_softc_t *sc, call_desc_t *cd)
+{
+ struct mbuf *m = i4b_Dgetmbuf(8 + 5);
+ u_int8_t *msg;
+ u_int16_t msgid;
+ u_int32_t PLCI;
+
+ if (!m) {
+ printf("capi%d: can't get mbuf for disconnect_req\n", sc->sc_unit);
+ return;
+ }
+
+ sc->sc_bchan[cd->channelid].state = B_DISCONNECT_CONF;
+ ctrl_desc[sc->ctrl_unit].bch_state[cd->channelid] = BCH_ST_RSVD;
+ msgid = sc->sc_bchan[cd->channelid].msgid = sc->sc_msgid++;
+ PLCI = (sc->sc_bchan[cd->channelid].ncci & CAPI_PLCI_MASK);
+
+ msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len);
+ msg = capimsg_setu16(msg, I4BCAPI_APPLID);
+ msg = capimsg_setu16(msg, CAPI_DISCONNECT_REQ);
+ msg = capimsg_setu16(msg, msgid);
+
+ msg = capimsg_setu32(msg, PLCI);
+ msg = capimsg_setu8(msg, 0); /* Additional Info */
+
+ sc->send(sc, m);
+}
+
+void capi_disconnect_conf(capi_softc_t *sc, struct mbuf *m_in)
+{
+ u_int8_t *msg = mtod(m_in, u_int8_t*);
+ call_desc_t *cd;
+ u_int32_t PLCI;
+ int bch;
+
+ msg = capimsg_getu32(msg + 8, &PLCI);
+
+ for (bch = 0; bch < sc->sc_nbch; bch++)
+ if ((sc->sc_bchan[bch].state == B_DISCONNECT_CONF) &&
+ ((sc->sc_bchan[bch].ncci & CAPI_PLCI_MASK) == PLCI))
+ break;
+
+ if (bch == sc->sc_nbch) {
+ printf("capi%d: can't find channel for disconnect_conf PLCI %x\n",
+ sc->sc_unit, PLCI);
+ return;
+ }
+
+ cd = cd_by_cdid(sc->sc_bchan[bch].cdid);
+ if (!cd) {
+ printf("capi%d: can't find cd for disconnect_conf PLCI %x\n",
+ sc->sc_unit, PLCI);
+ } else {
+ i4b_l4_disconnect_ind(cd);
+ freecd_by_cd(cd);
+ }
+
+ sc->sc_bchan[bch].state = B_FREE;
+ ctrl_desc[sc->ctrl_unit].bch_state[bch] = BCH_ST_FREE;
+}
+
+void capi_disconnect_b3_ind(capi_softc_t *sc, struct mbuf *m_in)
+{
+ struct mbuf *m = i4b_Dgetmbuf(8 + 4);
+ u_int8_t *msg = mtod(m_in, u_int8_t*);
+ u_int16_t applid, msgid;
+ u_int32_t NCCI;
+
+ if (!m) {
+ printf("capi%d: can't get mbuf for disconnect_b3_resp\n", sc->sc_unit);
+ return;
+ }
+
+ msg = capimsg_getu16(msg + 2, &applid);
+ msg = capimsg_getu16(msg + 2, &msgid);
+ msg = capimsg_getu32(msg, &NCCI);
+
+ /* XXX update bchan state? XXX */
+
+ msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len);
+ msg = capimsg_setu16(msg, applid);
+ msg = capimsg_setu16(msg, CAPI_DISCONNECT_B3_RESP);
+ msg = capimsg_setu16(msg, msgid);
+
+ msg = capimsg_setu32(msg, NCCI);
+
+ sc->send(sc, m);
+}
+
+void capi_disconnect_ind(capi_softc_t *sc, struct mbuf *m_in)
+{
+ struct mbuf *m = i4b_Dgetmbuf(8 + 4);
+ u_int8_t *msg = mtod(m_in, u_int8_t*);
+ call_desc_t *cd;
+ u_int16_t applid, msgid;
+ u_int32_t PLCI;
+ u_int16_t Reason;
+ int bch;
+
+ if (!m) {
+ printf("capi%d: can't get mbuf for disconnect_resp\n", sc->sc_unit);
+ return;
+ }
+
+ msg = capimsg_getu16(msg + 2, &applid);
+ msg = capimsg_getu16(msg + 2, &msgid);
+ msg = capimsg_getu32(msg, &PLCI);
+ msg = capimsg_getu16(msg, &Reason);
+
+ for (bch = 0; bch < sc->sc_nbch; bch++)
+ if ((sc->sc_bchan[bch].state != B_FREE) &&
+ ((sc->sc_bchan[bch].ncci & CAPI_PLCI_MASK) == PLCI))
+ break;
+
+ if (bch < sc->sc_nbch) {
+ /* We may not have a bchan assigned if call was ignored. */
+
+ cd = cd_by_cdid(sc->sc_bchan[bch].cdid);
+ sc->sc_bchan[bch].state = B_DISCONNECT_IND;
+ } else cd = NULL;
+
+ if (cd) {
+ if ((Reason & 0xff00) == 0x3400) {
+ SET_CAUSE_TV(cd->cause_in, CAUSET_Q850, (Reason & 0x7f));
+ } else {
+ SET_CAUSE_TV(cd->cause_in, CAUSET_I4B, CAUSE_I4B_NORMAL);
+ }
+
+ i4b_l4_disconnect_ind(cd);
+ freecd_by_cd(cd);
+
+ sc->sc_bchan[bch].state = B_FREE;
+ ctrl_desc[sc->ctrl_unit].bch_state[bch] = BCH_ST_FREE;
+ }
+
+ msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len);
+ msg = capimsg_setu16(msg, applid);
+ msg = capimsg_setu16(msg, CAPI_DISCONNECT_RESP);
+ msg = capimsg_setu16(msg, msgid);
+
+ msg = capimsg_setu32(msg, PLCI);
+
+ sc->send(sc, m);
+}
+
+#endif /* NI4BCAPI > 0 */
diff --git a/sys/i4b/capi/capi_msgs.h b/sys/i4b/capi/capi_msgs.h
new file mode 100644
index 0000000..3cdce35
--- /dev/null
+++ b/sys/i4b/capi/capi_msgs.h
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2001 Cubical Solutions Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * capi/capi_msgs.h The CAPI i4b message and handler declarations.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _I4B_CAPI_MSGS_H_
+#define _I4B_CAPI_MSGS_H_
+
+/* CAPI commands */
+
+#define CAPI_ALERT 0x01
+#define CAPI_CONNECT 0x02
+#define CAPI_CONNECT_ACTIVE 0x03
+#define CAPI_CONNECT_B3 0x82
+#define CAPI_CONNECT_B3_ACTIVE 0x83
+#define CAPI_CONNECT_B3_T90_ACTIVE 0x88
+#define CAPI_DATA_B3 0x86
+#define CAPI_DISCONNECT_B3 0x84
+#define CAPI_DISCONNECT 0x04
+#define CAPI_FACILITY 0x80
+#define CAPI_INFO 0x08
+#define CAPI_LISTEN 0x05
+#define CAPI_MANUFACTURER 0xff
+#define CAPI_RESET_B3 0x87
+#define CAPI_SELECT_B_PROTOCOL 0x41
+
+/* CAPI subcommands */
+
+#define CAPI_REQ 0x80
+#define CAPI_CONF 0x81
+#define CAPI_IND 0x82
+#define CAPI_RESP 0x83
+
+/* CAPI combined commands */
+
+#define CAPICMD(cmd,subcmd) (((subcmd)<<8)|(cmd))
+
+#define CAPI_DISCONNECT_REQ CAPICMD(CAPI_DISCONNECT,CAPI_REQ)
+#define CAPI_DISCONNECT_CONF CAPICMD(CAPI_DISCONNECT,CAPI_CONF)
+#define CAPI_DISCONNECT_IND CAPICMD(CAPI_DISCONNECT,CAPI_IND)
+#define CAPI_DISCONNECT_RESP CAPICMD(CAPI_DISCONNECT,CAPI_RESP)
+
+#define CAPI_ALERT_REQ CAPICMD(CAPI_ALERT,CAPI_REQ)
+#define CAPI_ALERT_CONF CAPICMD(CAPI_ALERT,CAPI_CONF)
+
+#define CAPI_CONNECT_REQ CAPICMD(CAPI_CONNECT,CAPI_REQ)
+#define CAPI_CONNECT_CONF CAPICMD(CAPI_CONNECT,CAPI_CONF)
+#define CAPI_CONNECT_IND CAPICMD(CAPI_CONNECT,CAPI_IND)
+#define CAPI_CONNECT_RESP CAPICMD(CAPI_CONNECT,CAPI_RESP)
+
+#define CAPI_CONNECT_ACTIVE_REQ CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_REQ)
+#define CAPI_CONNECT_ACTIVE_CONF CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_CONF)
+#define CAPI_CONNECT_ACTIVE_IND CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_IND)
+#define CAPI_CONNECT_ACTIVE_RESP CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_RESP)
+
+#define CAPI_SELECT_B_PROTOCOL_REQ CAPICMD(CAPI_SELECT_B_PROTOCOL,CAPI_REQ)
+#define CAPI_SELECT_B_PROTOCOL_CONF CAPICMD(CAPI_SELECT_B_PROTOCOL,CAPI_CONF)
+
+#define CAPI_CONNECT_B3_REQ CAPICMD(CAPI_CONNECT_B3,CAPI_REQ)
+#define CAPI_CONNECT_B3_CONF CAPICMD(CAPI_CONNECT_B3,CAPI_CONF)
+#define CAPI_CONNECT_B3_IND CAPICMD(CAPI_CONNECT_B3,CAPI_IND)
+#define CAPI_CONNECT_B3_RESP CAPICMD(CAPI_CONNECT_B3,CAPI_RESP)
+
+#define CAPI_CONNECT_B3_ACTIVE_REQ CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_REQ)
+#define CAPI_CONNECT_B3_ACTIVE_CONF CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_CONF)
+#define CAPI_CONNECT_B3_ACTIVE_IND CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_IND)
+#define CAPI_CONNECT_B3_ACTIVE_RESP CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_RESP)
+
+#define CAPI_CONNECT_B3_T90_ACTIVE_IND CAPICMD(CAPI_CONNECT_B3_T90_ACTIVE,CAPI_IND)
+#define CAPI_CONNECT_B3_T90_ACTIVE_RESP CAPICMD(CAPI_CONNECT_B3_T90_ACTIVE,CAPI_RESP)
+
+#define CAPI_DATA_B3_REQ CAPICMD(CAPI_DATA_B3,CAPI_REQ)
+#define CAPI_DATA_B3_CONF CAPICMD(CAPI_DATA_B3,CAPI_CONF)
+#define CAPI_DATA_B3_IND CAPICMD(CAPI_DATA_B3,CAPI_IND)
+#define CAPI_DATA_B3_RESP CAPICMD(CAPI_DATA_B3,CAPI_RESP)
+
+#define CAPI_DISCONNECT_B3_REQ CAPICMD(CAPI_DISCONNECT_B3,CAPI_REQ)
+#define CAPI_DISCONNECT_B3_CONF CAPICMD(CAPI_DISCONNECT_B3,CAPI_CONF)
+#define CAPI_DISCONNECT_B3_IND CAPICMD(CAPI_DISCONNECT_B3,CAPI_IND)
+#define CAPI_DISCONNECT_B3_RESP CAPICMD(CAPI_DISCONNECT_B3,CAPI_RESP)
+
+#define CAPI_RESET_B3_REQ CAPICMD(CAPI_RESET_B3,CAPI_REQ)
+#define CAPI_RESET_B3_CONF CAPICMD(CAPI_RESET_B3,CAPI_CONF)
+#define CAPI_RESET_B3_IND CAPICMD(CAPI_RESET_B3,CAPI_IND)
+#define CAPI_RESET_B3_RESP CAPICMD(CAPI_RESET_B3,CAPI_RESP)
+
+#define CAPI_LISTEN_REQ CAPICMD(CAPI_LISTEN,CAPI_REQ)
+#define CAPI_LISTEN_CONF CAPICMD(CAPI_LISTEN,CAPI_CONF)
+
+#define CAPI_MANUFACTURER_REQ CAPICMD(CAPI_MANUFACTURER,CAPI_REQ)
+#define CAPI_MANUFACTURER_CONF CAPICMD(CAPI_MANUFACTURER,CAPI_CONF)
+#define CAPI_MANUFACTURER_IND CAPICMD(CAPI_MANUFACTURER,CAPI_IND)
+#define CAPI_MANUFACTURER_RESP CAPICMD(CAPI_MANUFACTURER,CAPI_RESP)
+
+#define CAPI_FACILITY_REQ CAPICMD(CAPI_FACILITY,CAPI_REQ)
+#define CAPI_FACILITY_CONF CAPICMD(CAPI_FACILITY,CAPI_CONF)
+#define CAPI_FACILITY_IND CAPICMD(CAPI_FACILITY,CAPI_IND)
+#define CAPI_FACILITY_RESP CAPICMD(CAPI_FACILITY,CAPI_RESP)
+
+#define CAPI_INFO_REQ CAPICMD(CAPI_INFO,CAPI_REQ)
+#define CAPI_INFO_CONF CAPICMD(CAPI_INFO,CAPI_CONF)
+#define CAPI_INFO_IND CAPICMD(CAPI_INFO,CAPI_IND)
+#define CAPI_INFO_RESP CAPICMD(CAPI_INFO,CAPI_RESP)
+
+/* CAPI message access helpers */
+
+/*
+ * CAPI message header:
+ * word Length
+ * word ApplId
+ * byte Command
+ * byte Subcommand
+ * word MsgId
+ *
+ * Note that in the following, Controller/PLCI/NCCI is coded as follows:
+ * bits 0..6 = controller, bit 7 = ext/int, bits 8..15 = PLCI, and
+ * bits 16..31 = NCCI value.
+ *
+ * ALERT_REQ, 01 80:
+ * dword PLCI
+ * struct Additional Info
+ *
+ * ALERT_CONF, 01 81:
+ * dword PLCI
+ * word Info (0 = OK, other = cause)
+ *
+ * CONNECT_REQ, 02 80:
+ * dword controller
+ * word CIP
+ * struct Called party number
+ * struct Calling party number
+ * struct Called party subaddress
+ * struct Calling party subaddress
+ * struct Bearer Capability
+ * struct Low Layer Compatibility
+ * struct High Layer Compatibility
+ * struct Additional Info
+ *
+ * CONNECT_CONF, 02 81:
+ * dword PLCI
+ * word Info (0 = OK, other = cause)
+ *
+ * CONNECT_IND, 02 82:
+ * dword PLCI
+ * word CIP
+ * struct Called party number
+ * struct Calling party number
+ * struct Called party subaddress
+ * struct Calling party subaddress
+ * struct Bearer Capability
+ * struct Low Layer Compatibility
+ * struct High Layer Compatibility
+ * struct Additional Info
+ * struct Second Calling party number
+ *
+ * CONNECT_RESP, 02 83:
+ * dword PLCI
+ * word Reject (0 = accept, 1 = ignore, 2 = reject/normal clearing)
+ * struct B protocol
+ * struct Connected number
+ * struct Connected subaddress
+ * struct Low Layer Compatibility
+ * struct Additional Info
+ *
+ * CONNECT_ACTIVE_IND, 03 82:
+ * dword PLCI
+ * struct Connected number
+ * struct Connected subaddress
+ * struct Low Layer Compatibility
+ *
+ * CONNECT_ACTIVE_RESP, 03 83:
+ * dword PLCI
+ *
+ * CONNECT_B3_REQ, 82 80:
+ * dword PLCI
+ * struct NCPI
+ *
+ * CONNECT_B3_CONF, 82 81:
+ * dword NCCI
+ * word Info (0 = connected, other = cause)
+ *
+ * CONNECT_B3_IND, 82 82:
+ * dword NCCI
+ * struct NCPI
+ *
+ * CONNECT_B3_RESP, 82 83:
+ * dword NCCI
+ * word Reject (0 = accept, 2 = reject/normal clearing)
+ * struct NCPI
+ *
+ * CONNECT_B3_ACTIVE_IND, 83 82:
+ * dword NCCI
+ * struct NCPI
+ *
+ * CONNECT_B3_ACTIVE_RESP, 83 83:
+ * dword NCCI
+ *
+ * DATA_B3_REQ, 86 80:
+ * dword NCCI
+ * dword Data pointer
+ * word Data length
+ * word Data handle (packet id)
+ * word Flags (02 = more)
+ *
+ * DATA_B3_CONF, 86 81:
+ * dword NCCI
+ * word Data handle (packet id)
+ * word Info (0 = OK, other = cause)
+ *
+ * DATA_B3_IND, 86 82:
+ * dword NCCI
+ * dword Data pointer
+ * word Data length
+ * word Data handle (packet id)
+ * word Flags (02 = more)
+ *
+ * DATA_B3_RESP, 86 83:
+ * dword NCCI
+ * word Data handle (packet id)
+ *
+ * DISCONNECT_B3_REQ, 84 80:
+ * dword NCCI
+ * struct NCPI
+ *
+ * DISCONNECT_B3_CONF, 84 81:
+ * dword NCCI
+ * word Info (0 = OK, other = cause)
+ *
+ * DISCONNECT_B3_IND, 84 82:
+ * dword NCCI
+ * word Reason
+ * struct NCPI
+ *
+ * DISCONNECT_B3_RESP, 84 83:
+ * dword NCCI
+ *
+ * DISCONNECT_REQ, 04 80:
+ * dword PLCI
+ * struct Additional Info
+ *
+ * DISCONNECT_CONF, 04 81:
+ * dword PLCI
+ * word Info (0 = OK, other = cause)
+ *
+ * DISCONNECT_IND, 04 82:
+ * dword PLCI
+ * word Reason
+ *
+ * DISCONNECT_RESP, 04 83:
+ * dword PLCI
+ *
+ * LISTEN_REQ, 05 80:
+ * dword Controller
+ * dword Info mask (bits 0..9 used)
+ * dword CIP Mask (bit 0 = any match)
+ * dword CIP Mask 2 (bit 0 = any match)
+ * struct Calling party number
+ * struct Calling party subaddress
+ *
+ * LISTEN_CONF, 05 81:
+ * dword Controller
+ * word Info (0 = OK, other = cause)
+ *
+ * INFO_REQ, 08 80:
+ * dword Controller/PLCI
+ * struct Called party number
+ * struct Additional Info
+ *
+ * INFO_CONF, 08 81:
+ * dword Controller/PLCI
+ * word Info (0 = OK, other = cause)
+ *
+ * INFO_IND, 08 82:
+ * dword Controller/PLCI
+ * word Info number
+ * struct Info element
+ *
+ * INFO_RESP, 08 83:
+ * dword Controller/PLCI
+ */
+
+#define CAPIMSG_LEN(msg) (msg[0]|(msg[1]<<8))
+#define CAPIMSG_DATALEN(msg) (msg[16]|(msg[17]<<8))
+
+static __inline u_int8_t* capimsg_getu8(u_int8_t *msg, u_int8_t *val)
+{
+ *val = *msg;
+ return (msg + 1);
+}
+
+static __inline u_int8_t* capimsg_getu16(u_int8_t *msg, u_int16_t *val)
+{
+ *val = (msg[0]|(msg[1]<<8));
+ return (msg + 2);
+}
+
+static __inline u_int8_t* capimsg_getu32(u_int8_t *msg, u_int32_t *val)
+{
+ *val = (msg[0]|(msg[1]<<8)|(msg[2]<<16)|(msg[3]<<24));
+ return (msg + 4);
+}
+
+static __inline u_int8_t* capimsg_setu8(u_int8_t *msg, u_int8_t val)
+{
+ msg[0] = val;
+ return (msg + 1);
+}
+
+static __inline u_int8_t* capimsg_setu16(u_int8_t *msg, u_int16_t val)
+{
+ msg[0] = (val & 0xff);
+ msg[1] = (val >> 8) & 0xff;
+ return (msg + 2);
+}
+
+static __inline u_int8_t* capimsg_setu32(u_int8_t *msg, u_int32_t val)
+{
+ msg[0] = (val & 0xff);
+ msg[1] = (val >> 8) & 0xff;
+ msg[2] = (val >> 16) & 0xff;
+ msg[3] = (val >> 24) & 0xff;
+ return (msg + 4);
+}
+
+/*
+// CAPI message handlers called by higher layers
+*/
+
+extern void capi_listen_req(capi_softc_t *sc, u_int32_t CIP);
+extern void capi_alert_req(capi_softc_t *sc, call_desc_t *cd);
+extern void capi_connect_req(capi_softc_t *sc, call_desc_t *cd);
+extern void capi_connect_b3_req(capi_softc_t *sc, call_desc_t *cd);
+extern void capi_connect_resp(capi_softc_t *sc, call_desc_t *cd);
+extern void capi_data_b3_req(capi_softc_t *sc, int chan, struct mbuf *m);
+extern void capi_disconnect_req(capi_softc_t *sc, call_desc_t *cd);
+
+/*
+// CAPI message handlers called by the receive routine
+*/
+
+extern void capi_listen_conf(capi_softc_t *sc, struct mbuf *m);
+extern void capi_info_ind(capi_softc_t *sc, struct mbuf *m);
+extern void capi_alert_conf(capi_softc_t *sc, struct mbuf *m);
+extern void capi_connect_conf(capi_softc_t *sc, struct mbuf *m);
+extern void capi_connect_active_ind(capi_softc_t *sc, struct mbuf *m);
+extern void capi_connect_b3_conf(capi_softc_t *sc, struct mbuf *m);
+extern void capi_connect_b3_active_ind(capi_softc_t *sc, struct mbuf *m);
+extern void capi_connect_ind(capi_softc_t *sc, struct mbuf *m);
+extern void capi_connect_b3_ind(capi_softc_t *sc, struct mbuf *m);
+extern void capi_data_b3_conf(capi_softc_t *sc, struct mbuf *m);
+extern void capi_data_b3_ind(capi_softc_t *sc, struct mbuf *m);
+extern void capi_disconnect_conf(capi_softc_t *sc, struct mbuf *m);
+extern void capi_disconnect_b3_ind(capi_softc_t *sc, struct mbuf *m);
+extern void capi_disconnect_ind(capi_softc_t *sc, struct mbuf *m);
+
+#endif /* _I4B_CAPI_MSGS_H_ */
diff --git a/sys/i4b/capi/iavc/iavc.h b/sys/i4b/capi/iavc/iavc.h
new file mode 100644
index 0000000..a38ad70
--- /dev/null
+++ b/sys/i4b/capi/iavc/iavc.h
@@ -0,0 +1,586 @@
+/*
+ * Copyright (c) 2001 Cubical Solutions Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * capi/iavc/iavc.h The AVM ISDN controllers' common declarations.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _CAPI_IAVC_H_
+#define _CAPI_IAVC_H_
+
+/* max 4 units supported per machine */
+
+#define IAVC_MAXUNIT 4
+
+/*
+// iavc_softc_t
+// The software context of one AVM T1 controller.
+*/
+
+#define IAVC_IO_BASES 1
+
+typedef struct i4b_info {
+ struct resource * io_base[IAVC_IO_BASES];
+ int io_rid [IAVC_IO_BASES];
+ struct resource * irq;
+ int irq_rid;
+ struct resource * mem;
+ int mem_rid;
+} i4b_info_t;
+
+typedef struct iavc_softc {
+ capi_softc_t sc_capi;
+ int sc_unit;
+ int sc_cardtyp;
+
+ u_int32_t sc_membase;
+ bus_space_handle_t sc_mem_bh;
+ bus_space_tag_t sc_mem_bt;
+ u_int32_t sc_iobase;
+ bus_space_handle_t sc_io_bh;
+ bus_space_tag_t sc_io_bt;
+
+ int sc_state;
+#define IAVC_DOWN 0
+#define IAVC_POLL 1
+#define IAVC_INIT 2
+#define IAVC_UP 3
+ int sc_blocked;
+ int sc_dma;
+ int sc_t1;
+ int sc_intr;
+
+ u_int32_t sc_csr;
+
+ char sc_sendbuf[128+2048];
+ char sc_recvbuf[128+2048];
+ int sc_recvlen;
+
+ struct ifqueue sc_txq;
+
+ i4b_info_t sc_resources;
+} iavc_softc_t;
+
+extern iavc_softc_t iavc_sc[];
+
+#define iavc_find_sc(unit) (&iavc_sc[(unit)])
+
+/*
+// {b1,b1dma,t1}_{detect,reset}
+// Routines to detect and manage the specific type of card.
+*/
+
+extern int b1_detect(iavc_softc_t *sc);
+extern void b1_disable_irq(iavc_softc_t *sc);
+extern void b1_reset(iavc_softc_t *sc);
+
+extern int b1dma_detect(iavc_softc_t *sc);
+extern void b1dma_reset(iavc_softc_t *sc);
+
+extern int t1_detect(iavc_softc_t *sc);
+extern void t1_disable_irq(iavc_softc_t *sc);
+extern void t1_reset(iavc_softc_t *sc);
+
+/*
+// AMCC_{READ,WRITE}
+// Routines to access the memory mapped registers of the
+// S5933 DMA controller.
+*/
+
+static __inline u_int32_t AMCC_READ(iavc_softc_t *sc, int off)
+{
+ return bus_space_read_4(sc->sc_mem_bt, sc->sc_mem_bh, off);
+}
+
+static __inline void AMCC_WRITE(iavc_softc_t *sc, int off, u_int32_t value)
+{
+ bus_space_write_4(sc->sc_mem_bt, sc->sc_mem_bh, off, value);
+}
+
+/*
+// amcc_{put,get}_{byte,word}
+// Routines to access the DMA buffers byte- or wordwise.
+*/
+
+static __inline u_int8_t* amcc_put_byte(u_int8_t *buf, u_int8_t value)
+{
+ *buf++ = value;
+ return buf;
+}
+
+static __inline u_int8_t* amcc_get_byte(u_int8_t *buf, u_int8_t *value)
+{
+ *value = *buf++;
+ return buf;
+}
+
+static __inline u_int8_t* amcc_put_word(u_int8_t *buf, u_int32_t value)
+{
+ *buf++ = (value & 0xff);
+ *buf++ = (value >> 8) & 0xff;
+ *buf++ = (value >> 16) & 0xff;
+ *buf++ = (value >> 24) & 0xff;
+ return buf;
+}
+
+static __inline u_int8_t* amcc_get_word(u_int8_t *buf, u_int32_t *value)
+{
+ *value = *buf++;
+ *value |= (*buf++ << 8);
+ *value |= (*buf++ << 16);
+ *value |= (*buf++ << 24);
+ return buf;
+}
+
+/*
+// Controller LLI message numbers.
+*/
+
+#define SEND_POLL 0x72
+#define SEND_INIT 0x11
+#define SEND_REGISTER 0x12
+#define SEND_DATA_B3_REQ 0x13
+#define SEND_RELEASE 0x14
+#define SEND_MESSAGE 0x15
+#define SEND_CONFIG 0x71
+#define SEND_POLLACK 0x73
+
+#define RECEIVE_POLL 0x32
+#define RECEIVE_INIT 0x27
+#define RECEIVE_MESSAGE 0x21
+#define RECEIVE_DATA_B3_IND 0x22
+#define RECEIVE_START 0x23
+#define RECEIVE_STOP 0x24
+#define RECEIVE_NEW_NCCI 0x25
+#define RECEIVE_FREE_NCCI 0x26
+#define RECEIVE_RELEASE 0x26
+#define RECEIVE_TASK_READY 0x31
+#define RECEIVE_DEBUGMSG 0x71
+#define RECEIVE_POLLDWORD 0x75
+
+/* Operation constants */
+
+#define WRITE_REGISTER 0x00
+#define READ_REGISTER 0x01
+
+/* Port offsets in I/O space */
+
+#define B1_READ 0x00
+#define B1_WRITE 0x01
+#define B1_INSTAT 0x02
+#define B1_OUTSTAT 0x03
+#define B1_ANALYSE 0x04
+#define B1_REVISION 0x05
+#define B1_RESET 0x10
+
+#define T1_FASTLINK 0x00
+#define T1_SLOWLINK 0x08
+
+#define T1_READ B1_READ
+#define T1_WRITE B1_WRITE
+#define T1_INSTAT B1_INSTAT
+#define T1_OUTSTAT B1_OUTSTAT
+#define T1_IRQENABLE 0x05
+#define T1_FIFOSTAT 0x06
+#define T1_RESETLINK 0x10
+#define T1_ANALYSE 0x11
+#define T1_IRQMASTER 0x12
+#define T1_IDENT 0x17
+#define T1_RESETBOARD 0x1f
+
+#define T1F_IREADY 0x01
+#define T1F_IHALF 0x02
+#define T1F_IFULL 0x04
+#define T1F_IEMPTY 0x08
+#define T1F_IFLAGS 0xf0
+
+#define T1F_OREADY 0x10
+#define T1F_OHALF 0x20
+#define T1F_OEMPTY 0x40
+#define T1F_OFULL 0x80
+#define T1F_OFLAGS 0xf0
+
+#define FIFO_OUTBSIZE 256
+#define FIFO_INPBSIZE 512
+
+#define HEMA_VERSION_ID 0
+#define HEMA_PAL_ID 0
+
+/*
+// S5933 DMA controller register offsets in memory, and bitmasks.
+*/
+
+#define AMCC_RXPTR 0x24
+#define AMCC_RXLEN 0x28
+#define AMCC_TXPTR 0x2c
+#define AMCC_TXLEN 0x30
+
+#define AMCC_INTCSR 0x38
+#define EN_READ_TC_INT 0x00008000
+#define EN_WRITE_TC_INT 0x00004000
+#define EN_TX_TC_INT EN_READ_TC_INT
+#define EN_RX_TC_INT EN_WRITE_TC_INT
+#define AVM_FLAG 0x30000000
+
+#define ANY_S5933_INT 0x00800000
+#define READ_TC_INT 0x00080000
+#define WRITE_TC_INT 0x00040000
+#define TX_TC_INT READ_TC_INT
+#define RX_TC_INT WRITE_TC_INT
+#define MASTER_ABORT_INT 0x00100000
+#define TARGET_ABORT_INT 0x00200000
+#define BUS_MASTER_INT 0x00200000
+#define ALL_INT 0x000c0000
+
+#define AMCC_MCSR 0x3c
+#define A2P_HI_PRIORITY 0x00000100
+#define EN_A2P_TRANSFERS 0x00000400
+#define P2A_HI_PRIORITY 0x00001000
+#define EN_P2A_TRANSFERS 0x00004000
+#define RESET_A2P_FLAGS 0x04000000
+#define RESET_P2A_FLAGS 0x02000000
+
+/*
+// (B1IO_WAIT_MAX * B1IO_WAIT_DLY) is the max wait in us for the card
+// to become ready after an I/O operation. The default is 1 ms.
+*/
+
+#define B1IO_WAIT_MAX 1000
+#define B1IO_WAIT_DLY 1
+
+/*
+// b1io_outp
+// Diagnostic output routine, returns the written value via
+// the device's analysis register.
+//
+// b1io_rx_full
+// Returns nonzero if data is readable from the card via the
+// I/O ports.
+//
+// b1io_tx_empty
+// Returns nonzero if data can be written to the card via the
+// I/O ports.
+*/
+
+static __inline u_int8_t b1io_outp(iavc_softc_t *sc, int off, u_int8_t val)
+{
+ bus_space_write_1(sc->sc_io_bt, sc->sc_io_bh, off, val);
+ DELAY(1);
+ return bus_space_read_1(sc->sc_io_bt, sc->sc_io_bh, B1_ANALYSE);
+}
+
+static __inline int b1io_rx_full(iavc_softc_t *sc)
+{
+ u_int8_t val = bus_space_read_1(sc->sc_io_bt, sc->sc_io_bh, B1_INSTAT);
+ return (val & 0x01);
+}
+
+static __inline int b1io_tx_empty(iavc_softc_t *sc)
+{
+ u_int8_t val = bus_space_read_1(sc->sc_io_bt, sc->sc_io_bh, B1_OUTSTAT);
+ return (val & 0x01);
+}
+
+/*
+// b1io_{get,put}_{byte,word}
+// Routines to read and write the device I/O registers byte- or
+// wordwise.
+//
+// b1io_{get,put}_slice
+// Routines to read and write sequential bytes to the device
+// I/O registers.
+*/
+
+static __inline u_int8_t b1io_get_byte(iavc_softc_t *sc)
+{
+ int spin = 0;
+ while (!b1io_rx_full(sc) && spin < B1IO_WAIT_MAX) {
+ spin++; DELAY(B1IO_WAIT_DLY);
+ }
+ if (b1io_rx_full(sc))
+ return bus_space_read_1(sc->sc_io_bt, sc->sc_io_bh, B1_READ);
+ printf("iavc%d: rx not completed\n", sc->sc_unit);
+ return 0xff;
+}
+
+static __inline int b1io_put_byte(iavc_softc_t *sc, u_int8_t val)
+{
+ int spin = 0;
+ while (!b1io_tx_empty(sc) && spin < B1IO_WAIT_MAX) {
+ spin++; DELAY(B1IO_WAIT_DLY);
+ }
+ if (b1io_tx_empty(sc)) {
+ bus_space_write_1(sc->sc_io_bt, sc->sc_io_bh, B1_WRITE, val);
+ return 0;
+ }
+ printf("iavc%d: tx not emptied\n", sc->sc_unit);
+ return -1;
+}
+
+static __inline int b1io_save_put_byte(iavc_softc_t *sc, u_int8_t val)
+{
+ int spin = 0;
+ while (!b1io_tx_empty(sc) && spin < B1IO_WAIT_MAX) {
+ spin++; DELAY(B1IO_WAIT_DLY);
+ }
+ if (b1io_tx_empty(sc)) {
+ b1io_outp(sc, B1_WRITE, val);
+ return 0;
+ }
+ printf("iavc%d: tx not emptied\n", sc->sc_unit);
+ return -1;
+}
+
+static __inline u_int32_t b1io_get_word(iavc_softc_t *sc)
+{
+ u_int32_t val = 0;
+ val |= b1io_get_byte(sc);
+ val |= (b1io_get_byte(sc) << 8);
+ val |= (b1io_get_byte(sc) << 16);
+ val |= (b1io_get_byte(sc) << 24);
+ return val;
+}
+
+static __inline void b1io_put_word(iavc_softc_t *sc, u_int32_t val)
+{
+ b1io_put_byte(sc, (val & 0xff));
+ b1io_put_byte(sc, (val >> 8) & 0xff);
+ b1io_put_byte(sc, (val >> 16) & 0xff);
+ b1io_put_byte(sc, (val >> 24) & 0xff);
+}
+
+static __inline int b1io_get_slice(iavc_softc_t *sc, u_int8_t *dp)
+{
+ int len, i;
+ len = i = b1io_get_word(sc);
+ while (i--) *dp++ = b1io_get_byte(sc);
+ return len;
+}
+
+static __inline void b1io_put_slice(iavc_softc_t *sc, u_int8_t *dp, int len)
+{
+ b1io_put_word(sc, len);
+ while (len--) b1io_put_byte(sc, *dp++);
+}
+
+/*
+// b1io_{read,write}_reg
+// Routines to read and write the device registers via the I/O
+// ports.
+*/
+
+static __inline u_int32_t b1io_read_reg(iavc_softc_t *sc, int reg)
+{
+ b1io_put_byte(sc, READ_REGISTER);
+ b1io_put_word(sc, reg);
+ return b1io_get_word(sc);
+}
+
+static __inline u_int32_t b1io_write_reg(iavc_softc_t *sc, int reg, u_int32_t val)
+{
+ b1io_put_byte(sc, WRITE_REGISTER);
+ b1io_put_word(sc, reg);
+ b1io_put_word(sc, val);
+ return b1io_get_word(sc);
+}
+
+/*
+// t1io_outp
+// I/O port write operation for the T1, which does not seem
+// to have the analysis port.
+*/
+
+static __inline void t1io_outp(iavc_softc_t *sc, int off, u_int8_t val)
+{
+ bus_space_write_1(sc->sc_io_bt, sc->sc_io_bh, off, val);
+}
+
+static __inline u_int8_t t1io_inp(iavc_softc_t *sc, int off)
+{
+ return bus_space_read_1(sc->sc_io_bt, sc->sc_io_bh, off);
+}
+
+static __inline int t1io_isfastlink(iavc_softc_t *sc)
+{
+ return ((bus_space_read_1(sc->sc_io_bt, sc->sc_io_bh, T1_IDENT) & ~0x82) == 1);
+}
+
+static __inline u_int8_t t1io_fifostatus(iavc_softc_t *sc)
+{
+ return bus_space_read_1(sc->sc_io_bt, sc->sc_io_bh, T1_FIFOSTAT);
+}
+
+static __inline int t1io_get_slice(iavc_softc_t *sc, u_int8_t *dp)
+{
+ int len, i;
+ len = i = b1io_get_word(sc);
+ if (t1io_isfastlink(sc)) {
+ int status;
+ while (i) {
+ status = t1io_fifostatus(sc) & (T1F_IREADY|T1F_IHALF);
+ if (i >= FIFO_INPBSIZE) status |= T1F_IFULL;
+
+ switch (status) {
+ case T1F_IREADY|T1F_IHALF|T1F_IFULL:
+ bus_space_read_multi_1(sc->sc_io_bt, sc->sc_io_bh,
+ T1_READ, dp, FIFO_INPBSIZE);
+ dp += FIFO_INPBSIZE;
+ i -= FIFO_INPBSIZE;
+ break;
+
+ case T1F_IREADY|T1F_IHALF:
+ bus_space_read_multi_1(sc->sc_io_bt, sc->sc_io_bh,
+ T1_READ, dp, i);
+ dp += i;
+ i = 0;
+ break;
+
+ default:
+ *dp++ = b1io_get_byte(sc);
+ i--;
+ }
+ }
+ } else { /* not fastlink */
+ if (i--) *dp++ = b1io_get_byte(sc);
+ }
+ return len;
+}
+
+static __inline void t1io_put_slice(iavc_softc_t *sc, u_int8_t *dp, int len)
+{
+ int i = len;
+ b1io_put_word(sc, i);
+ if (t1io_isfastlink(sc)) {
+ int status;
+ while (i) {
+ status = t1io_fifostatus(sc) & (T1F_OREADY|T1F_OHALF);
+ if (i >= FIFO_OUTBSIZE) status |= T1F_OFULL;
+
+ switch (status) {
+ case T1F_OREADY|T1F_OHALF|T1F_OFULL:
+ bus_space_write_multi_1(sc->sc_io_bt, sc->sc_io_bh,
+ T1_WRITE, dp, FIFO_OUTBSIZE);
+ dp += FIFO_OUTBSIZE;
+ i -= FIFO_OUTBSIZE;
+ break;
+
+ case T1F_OREADY|T1F_OHALF:
+ bus_space_write_multi_1(sc->sc_io_bt, sc->sc_io_bh,
+ T1_WRITE, dp, i);
+ dp += i;
+ i = 0;
+ break;
+
+ default:
+ b1io_put_byte(sc, *dp++);
+ i--;
+ }
+ }
+ } else {
+ while (i--) b1io_put_byte(sc, *dp++);
+ }
+}
+
+/*
+// An attempt to bring it all together:
+// ------------------------------------
+//
+// iavc_{read,write}_reg
+// Routines to access the device registers via the I/O port.
+//
+// iavc_{read,write}_port
+// Routines to access the device I/O ports.
+//
+// iavc_tx_empty, iavc_rx_full
+// Routines to check when the device has drained the last written
+// byte, or produced a full byte to read.
+//
+// iavc_{get,put}_byte
+// Routines to read/write byte values to the device via the I/O port.
+//
+// iavc_{get,put}_word
+// Routines to read/write 32-bit words to the device via the I/O port.
+//
+// iavc_{get,put}_slice
+// Routines to read/write {length, data} pairs to the device via the
+// ubiquituous I/O port. Uses the HEMA FIFO on a T1.
+*/
+
+#define iavc_read_reg(sc, reg) b1io_read_reg(sc, reg)
+#define iavc_write_reg(sc, reg, val) b1io_write_reg(sc, reg, val)
+
+#define iavc_read_port(sc, port) \
+ bus_space_read_1(sc->sc_io_bt, sc->sc_io_bh, (port))
+#define iavc_write_port(sc, port, val) \
+ bus_space_write_1(sc->sc_io_bt, sc->sc_io_bh, (port), (val))
+
+#define iavc_tx_empty(sc) b1io_tx_empty(sc)
+#define iavc_rx_full(sc) b1io_rx_full(sc)
+
+#define iavc_get_byte(sc) b1io_get_byte(sc)
+#define iavc_put_byte(sc, val) b1io_put_byte(sc, val)
+#define iavc_get_word(sc) b1io_get_word(sc)
+#define iavc_put_word(sc, val) b1io_put_word(sc, val)
+
+static __inline u_int32_t iavc_get_slice(iavc_softc_t *sc, u_int8_t *dp)
+{
+ if (sc->sc_t1) return t1io_get_slice(sc, dp);
+ else return b1io_get_slice(sc, dp);
+}
+
+static __inline void iavc_put_slice(iavc_softc_t *sc, u_int8_t *dp, int len)
+{
+ if (sc->sc_t1) t1io_put_slice(sc, dp, len);
+ else b1io_put_slice(sc, dp, len);
+}
+
+/*
+// iavc_handle_intr
+// Interrupt handler, called by the bus specific interrupt routine
+// in iavc_<bustype>.c module.
+//
+// iavc_load
+// CAPI callback. Resets device and loads firmware.
+//
+// iavc_register
+// CAPI callback. Registers an application id.
+//
+// iavc_release
+// CAPI callback. Releases an application id.
+//
+// iavc_send
+// CAPI callback. Sends a CAPI message. A B3_DATA_REQ message has
+// m_next point to a data mbuf.
+*/
+
+extern void iavc_handle_intr(iavc_softc_t *);
+extern int iavc_load(capi_softc_t *, int, u_int8_t *);
+extern int iavc_register(capi_softc_t *, int, int);
+extern int iavc_release(capi_softc_t *, int);
+extern int iavc_send(capi_softc_t *, struct mbuf *);
+
+extern void b1isa_setup_irq(struct iavc_softc *sc);
+
+#endif /* _CAPI_IAVC_H_ */
diff --git a/sys/i4b/capi/iavc/iavc_card.c b/sys/i4b/capi/iavc/iavc_card.c
new file mode 100644
index 0000000..831dc68
--- /dev/null
+++ b/sys/i4b/capi/iavc/iavc_card.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2001 Cubical Solutions Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * capi/iavc/iavc_card.c
+ * The AVM ISDN controllers' card specific support routines.
+ *
+ * $FreeBSD$
+ */
+
+#include "iavc.h"
+#include "i4bcapi.h"
+#include "pci.h"
+
+#if (NIAVC > 0) && (NI4BCAPI > 0)
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <machine/clock.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_trace.h>
+
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_l3l4.h>
+#include <i4b/include/i4b_mbuf.h>
+
+#include <i4b/capi/capi.h>
+
+#include <i4b/capi/iavc/iavc.h>
+
+/*
+// AVM B1 (active BRI, PIO mode)
+*/
+
+int b1_detect(iavc_softc_t *sc)
+{
+ if ((iavc_read_port(sc, B1_INSTAT) & 0xfc) ||
+ (iavc_read_port(sc, B1_OUTSTAT) & 0xfc))
+ return (1);
+
+ b1io_outp(sc, B1_INSTAT, 0x02);
+ b1io_outp(sc, B1_OUTSTAT, 0x02);
+ if ((iavc_read_port(sc, B1_INSTAT) & 0xfe) != 2 ||
+ (iavc_read_port(sc, B1_OUTSTAT) & 0xfe) != 2)
+ return (2);
+
+ b1io_outp(sc, B1_INSTAT, 0x00);
+ b1io_outp(sc, B1_OUTSTAT, 0x00);
+ if ((iavc_read_port(sc, B1_INSTAT) & 0xfe) ||
+ (iavc_read_port(sc, B1_OUTSTAT) & 0xfe))
+ return (3);
+
+ return (0); /* found */
+}
+
+void b1_disable_irq(iavc_softc_t *sc)
+{
+ b1io_outp(sc, B1_INSTAT, 0x00);
+}
+
+void b1_reset(iavc_softc_t *sc)
+{
+ b1io_outp(sc, B1_RESET, 0);
+ DELAY(55*2*1000);
+
+ b1io_outp(sc, B1_RESET, 1);
+ DELAY(55*2*1000);
+
+ b1io_outp(sc, B1_RESET, 0);
+ DELAY(55*2*1000);
+}
+
+/*
+// Newer PCI-based B1's, and T1's, supports DMA
+*/
+
+int b1dma_detect(iavc_softc_t *sc)
+{
+ AMCC_WRITE(sc, AMCC_MCSR, 0);
+ DELAY(10*1000);
+ AMCC_WRITE(sc, AMCC_MCSR, 0x0f000000);
+ DELAY(10*1000);
+ AMCC_WRITE(sc, AMCC_MCSR, 0);
+ DELAY(42*1000);
+
+ AMCC_WRITE(sc, AMCC_RXLEN, 0);
+ AMCC_WRITE(sc, AMCC_TXLEN, 0);
+ sc->sc_csr = 0;
+ AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
+
+ if (AMCC_READ(sc, AMCC_INTCSR) != 0)
+ return 1;
+
+ AMCC_WRITE(sc, AMCC_RXPTR, 0xffffffff);
+ AMCC_WRITE(sc, AMCC_TXPTR, 0xffffffff);
+ if ((AMCC_READ(sc, AMCC_RXPTR) != 0xfffffffc) ||
+ (AMCC_READ(sc, AMCC_TXPTR) != 0xfffffffc))
+ return 2;
+
+ AMCC_WRITE(sc, AMCC_RXPTR, 0);
+ AMCC_WRITE(sc, AMCC_TXPTR, 0);
+ if ((AMCC_READ(sc, AMCC_RXPTR) != 0) ||
+ (AMCC_READ(sc, AMCC_TXPTR) != 0))
+ return 3;
+
+ iavc_write_port(sc, 0x10, 0x00);
+ iavc_write_port(sc, 0x07, 0x00);
+
+ iavc_write_port(sc, 0x02, 0x02);
+ iavc_write_port(sc, 0x03, 0x02);
+
+ if (((iavc_read_port(sc, 0x02) & 0xfe) != 0x02) ||
+ (iavc_read_port(sc, 0x03) != 0x03))
+ return 4;
+
+ iavc_write_port(sc, 0x02, 0x00);
+ iavc_write_port(sc, 0x03, 0x00);
+
+ if (((iavc_read_port(sc, 0x02) & 0xfe) != 0x00) ||
+ (iavc_read_port(sc, 0x03) != 0x01))
+ return 5;
+
+ return (0); /* found */
+}
+
+void b1dma_reset(iavc_softc_t *sc)
+{
+ int s = SPLI4B();
+
+ sc->sc_csr = 0;
+ AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
+ AMCC_WRITE(sc, AMCC_MCSR, 0);
+ AMCC_WRITE(sc, AMCC_RXLEN, 0);
+ AMCC_WRITE(sc, AMCC_TXLEN, 0);
+
+ iavc_write_port(sc, 0x10, 0x00); /* XXX magic numbers from */
+ iavc_write_port(sc, 0x07, 0x00); /* XXX the linux driver */
+
+ splx(s);
+
+ AMCC_WRITE(sc, AMCC_MCSR, 0);
+ DELAY(10 * 1000);
+ AMCC_WRITE(sc, AMCC_MCSR, 0x0f000000);
+ DELAY(10 * 1000);
+ AMCC_WRITE(sc, AMCC_MCSR, 0);
+ DELAY(42 * 1000);
+}
+
+/*
+// AVM T1 (active PRI)
+*/
+
+/* XXX how do these differ from b1io_{read,write}_reg()? XXX */
+
+static int b1dma_tx_empty(int iobase)
+{ return inb(iobase + 3) & 1; }
+
+static int b1dma_rx_full(int iobase)
+{ return inb(iobase + 2) & 1; }
+
+static int b1dma_tolink(iavc_softc_t *sc, void *buf, int len)
+{
+ volatile int spin;
+ char *s = (char*) buf;
+ while (len--) {
+ spin = 0;
+ while (!b1dma_tx_empty(sc->sc_iobase) && spin < 100000)
+ spin++;
+ if (!b1dma_tx_empty(sc->sc_iobase))
+ return -1;
+ t1io_outp(sc, 1, *s++);
+ }
+ return 0;
+}
+
+static int b1dma_fromlink(iavc_softc_t *sc, void *buf, int len)
+{
+ volatile int spin;
+ char *s = (char*) buf;
+ while (len--) {
+ spin = 0;
+ while (!b1dma_rx_full(sc->sc_iobase) && spin < 100000)
+ spin++;
+ if (!b1dma_rx_full(sc->sc_iobase))
+ return -1;
+ *s++ = t1io_inp(sc, 0);
+ }
+ return 0;
+}
+
+static int WriteReg(iavc_softc_t *sc, u_int32_t reg, u_int8_t val)
+{
+ u_int8_t cmd = 0;
+ if (b1dma_tolink(sc, &cmd, 1) == 0 &&
+ b1dma_tolink(sc, &reg, 4) == 0) {
+ u_int32_t tmp = val;
+ return b1dma_tolink(sc, &tmp, 4);
+ }
+ return -1;
+}
+
+static u_int8_t ReadReg(iavc_softc_t *sc, u_int32_t reg)
+{
+ u_int8_t cmd = 1;
+ if (b1dma_tolink(sc, &cmd, 1) == 0 &&
+ b1dma_tolink(sc, &reg, 4) == 0) {
+ u_int32_t tmp;
+ if (b1dma_fromlink(sc, &tmp, 4) == 0)
+ return (u_int8_t) tmp;
+ }
+ return 0xff;
+}
+
+int t1_detect(iavc_softc_t *sc)
+{
+ int ret = b1dma_detect(sc);
+ if (ret) return ret;
+
+ if ((WriteReg(sc, 0x80001000, 0x11) != 0) ||
+ (WriteReg(sc, 0x80101000, 0x22) != 0) ||
+ (WriteReg(sc, 0x80201000, 0x33) != 0) ||
+ (WriteReg(sc, 0x80301000, 0x44) != 0))
+ return 6;
+
+ if ((ReadReg(sc, 0x80001000) != 0x11) ||
+ (ReadReg(sc, 0x80101000) != 0x22) ||
+ (ReadReg(sc, 0x80201000) != 0x33) ||
+ (ReadReg(sc, 0x80301000) != 0x44))
+ return 7;
+
+ if ((WriteReg(sc, 0x80001000, 0x55) != 0) ||
+ (WriteReg(sc, 0x80101000, 0x66) != 0) ||
+ (WriteReg(sc, 0x80201000, 0x77) != 0) ||
+ (WriteReg(sc, 0x80301000, 0x88) != 0))
+ return 8;
+
+ if ((ReadReg(sc, 0x80001000) != 0x55) ||
+ (ReadReg(sc, 0x80101000) != 0x66) ||
+ (ReadReg(sc, 0x80201000) != 0x77) ||
+ (ReadReg(sc, 0x80301000) != 0x88))
+ return 9;
+
+ return 0; /* found */
+}
+
+void t1_disable_irq(iavc_softc_t *sc)
+{
+ iavc_write_port(sc, T1_IRQMASTER, 0x00);
+}
+
+void t1_reset(iavc_softc_t *sc)
+{
+ b1_reset(sc);
+ iavc_write_port(sc, B1_INSTAT, 0x00);
+ iavc_write_port(sc, B1_OUTSTAT, 0x00);
+ iavc_write_port(sc, T1_IRQMASTER, 0x00);
+ iavc_write_port(sc, T1_RESETBOARD, 0x0f);
+}
+
+#endif
diff --git a/sys/i4b/capi/iavc/iavc_isa.c b/sys/i4b/capi/iavc/iavc_isa.c
new file mode 100644
index 0000000..96ea1c9
--- /dev/null
+++ b/sys/i4b/capi/iavc/iavc_isa.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2001 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "iavc.h"
+#include "i4bcapi.h"
+
+#if (NIAVC > 0) && (NI4BCAPI > 0)
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <machine/clock.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <isa/isavar.h>
+
+#include <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_trace.h>
+
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_l3l4.h>
+#include <i4b/include/i4b_mbuf.h>
+
+#include <i4b/capi/capi.h>
+
+#include <i4b/capi/iavc/iavc.h>
+
+/* ISA driver linkage */
+
+static void iavc_isa_intr(iavc_softc_t *sc);
+static int iavc_isa_probe(device_t dev);
+static int iavc_isa_attach(device_t dev);
+
+static device_method_t iavc_isa_methods[] =
+{
+ DEVMETHOD(device_probe, iavc_isa_probe),
+ DEVMETHOD(device_attach, iavc_isa_attach),
+ { 0, 0 }
+};
+
+static driver_t iavc_isa_driver =
+{
+ "iavc",
+ iavc_isa_methods,
+ 0
+};
+
+static devclass_t iavc_isa_devclass;
+
+DRIVER_MODULE(iavc, isa, iavc_isa_driver, iavc_isa_devclass, 0, 0);
+
+#define B1_IOLENGTH 0x20
+
+static int b1_irq_table[] =
+{0, 0, 0, 192, 32, 160, 96, 224, 0, 64, 80, 208, 48, 0, 0, 112};
+/* 3 4 5 6 7 9 10 11 12 15 */
+
+/*---------------------------------------------------------------------------*
+ * device probe
+ *---------------------------------------------------------------------------*/
+
+static int
+iavc_isa_probe(device_t dev)
+{
+ struct iavc_softc *sc;
+ int ret = ENXIO;
+ int unit = device_get_unit(dev);
+
+ if(isa_get_vendorid(dev)) /* no PnP probes here */
+ return ENXIO;
+
+ /* check max unit range */
+
+ if (unit >= IAVC_MAXUNIT)
+ {
+ printf("iavc%d: too many units\n", unit);
+ return(ENXIO);
+ }
+
+ sc = iavc_find_sc(unit); /* get softc */
+
+ sc->sc_unit = unit;
+
+ if (!(sc->sc_resources.io_base[0] =
+ bus_alloc_resource(dev, SYS_RES_IOPORT,
+ &sc->sc_resources.io_rid[0],
+ 0UL, ~0UL, B1_IOLENGTH, RF_ACTIVE)))
+ {
+ printf("iavc%d: can't allocate io region\n", unit);
+ return(ENXIO);
+ }
+
+ sc->sc_iobase = rman_get_start(sc->sc_resources.io_base[0]);
+
+ switch(sc->sc_iobase)
+ {
+ case 0x150:
+ case 0x250:
+ case 0x300:
+ case 0x340:
+ break;
+ default:
+ printf("iavc%d: ERROR, invalid i/o base addr 0x%x configured!\n", sc->sc_unit, sc->sc_iobase);
+ bus_release_resource(dev, SYS_RES_IOPORT,
+ sc->sc_resources.io_rid[0],
+ sc->sc_resources.io_base[0]);
+ return(ENXIO);
+ }
+
+ sc->sc_io_bt = rman_get_bustag(sc->sc_resources.io_base[0]);
+ sc->sc_io_bh = rman_get_bushandle(sc->sc_resources.io_base[0]);
+
+ /* setup characteristics */
+
+ sc->sc_t1 = FALSE;
+ sc->sc_dma = FALSE;
+
+ sc->sc_capi.card_type = CARD_TYPEC_AVM_B1_ISA;
+ sc->sc_capi.sc_nbch = 2;
+
+ b1_reset(sc);
+ DELAY(100);
+
+ ret = b1_detect(sc);
+
+ if(ret)
+ {
+ printf("iavc%d: no card ? b1_detect returns 0x02x\n", sc->sc_unit, ret);
+ return(ENXIO);
+ }
+
+ DELAY(100);
+
+ b1_reset(sc);
+
+ DELAY(100);
+
+ if(bootverbose)
+ {
+ printf("iavc%d: class = 0x%02x, rev = 0x%02x\n", sc->sc_unit,
+ iavc_read_port(sc, B1_ANALYSE),
+ iavc_read_port(sc, B1_REVISION));
+ }
+
+ device_set_desc(dev, "AVM B1 ISA");
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * attach
+ *---------------------------------------------------------------------------*/
+static int
+iavc_isa_attach(device_t dev)
+{
+ struct iavc_softc *sc;
+ void *ih = 0;
+ int unit = device_get_unit(dev);
+ int irq;
+
+ sc = iavc_find_sc(unit); /* get softc */
+
+ sc->sc_resources.irq_rid = 0;
+
+ if(!(sc->sc_resources.irq =
+ bus_alloc_resource(dev, SYS_RES_IRQ,
+ &sc->sc_resources.irq_rid,
+ 0UL, ~0UL, 1, RF_ACTIVE)))
+ {
+ printf("iavc%d: can't allocate irq\n",unit);
+ bus_release_resource(dev, SYS_RES_IOPORT,
+ sc->sc_resources.io_rid[0],
+ sc->sc_resources.io_base[0]);
+ return(ENXIO);
+ }
+
+ irq = rman_get_start(sc->sc_resources.irq);
+
+ if(b1_irq_table[irq] == 0)
+ {
+ printf("iavc%d: ERROR, illegal irq %d configured!\n",unit, irq);
+ bus_release_resource(dev, SYS_RES_IOPORT,
+ sc->sc_resources.io_rid[0],
+ sc->sc_resources.io_base[0]);
+ bus_release_resource(dev, SYS_RES_IRQ,
+ sc->sc_resources.irq_rid,
+ sc->sc_resources.irq);
+ return(ENXIO);
+ }
+
+ memset(&sc->sc_txq, 0, sizeof(struct ifqueue));
+ sc->sc_txq.ifq_maxlen = sc->sc_capi.sc_nbch * 4;
+
+#if defined (__FreeBSD__) && __FreeBSD__ > 4
+ mtx_init(&sc->sc_txq.ifq_mtx, "i4b_ivac_isa", MTX_DEF);
+#endif
+
+ sc->sc_intr = FALSE;
+ sc->sc_state = IAVC_DOWN;
+ sc->sc_blocked = FALSE;
+
+ /* setup capi link */
+
+ sc->sc_capi.load = iavc_load;
+ sc->sc_capi.reg_appl = iavc_register;
+ sc->sc_capi.rel_appl = iavc_release;
+ sc->sc_capi.send = iavc_send;
+ sc->sc_capi.ctx = (void*) sc;
+
+ if (capi_ll_attach(&sc->sc_capi))
+ {
+ printf("iavc%d: capi attach failed\n", unit);
+ return(ENXIO);
+ }
+
+ /* setup the interrupt */
+
+ if(bus_setup_intr(dev, sc->sc_resources.irq, INTR_TYPE_NET,
+ (void(*)(void*))iavc_isa_intr,
+ sc, &ih))
+ {
+ printf("iavc%d: irq setup failed\n", unit);
+ bus_release_resource(dev, SYS_RES_IOPORT,
+ sc->sc_resources.io_rid[0],
+ sc->sc_resources.io_base[0]);
+ bus_release_resource(dev, SYS_RES_IRQ,
+ sc->sc_resources.irq_rid,
+ sc->sc_resources.irq);
+ return(ENXIO);
+ }
+
+ /* the board is now ready to be loaded */
+
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * setup interrupt
+ *---------------------------------------------------------------------------*/
+void
+b1isa_setup_irq(struct iavc_softc *sc)
+{
+ int irq = rman_get_start(sc->sc_resources.irq);
+
+ if(bootverbose)
+ printf("iavc%d: using irq %d\n", sc->sc_unit, irq);
+
+ /* enable the interrupt */
+
+ b1io_outp(sc, B1_INSTAT, 0x00);
+ b1io_outp(sc, B1_RESET, b1_irq_table[irq]);
+ b1io_outp(sc, B1_INSTAT, 0x02);
+}
+
+/*---------------------------------------------------------------------------*
+ * IRQ handler
+ *---------------------------------------------------------------------------*/
+static void
+iavc_isa_intr(struct iavc_softc *sc)
+{
+ iavc_handle_intr(sc);
+}
+
+#endif
diff --git a/sys/i4b/capi/iavc/iavc_lli.c b/sys/i4b/capi/iavc/iavc_lli.c
new file mode 100644
index 0000000..7ce7eb4
--- /dev/null
+++ b/sys/i4b/capi/iavc/iavc_lli.c
@@ -0,0 +1,834 @@
+/*
+ * Copyright (c) 2001 Cubical Solutions Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * capi/iavc/iavc_lli.c
+ * The AVM ISDN controllers' Low Level Interface.
+ *
+ * $FreeBSD$
+ */
+
+#include "iavc.h"
+#include "i4bcapi.h"
+#include "pci.h"
+
+#if (NIAVC > 0) && (NI4BCAPI > 0)
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/malloc.h>
+#include <net/if.h>
+
+#include <machine/clock.h>
+
+#include <machine/bus.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_trace.h>
+
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_l3l4.h>
+#include <i4b/include/i4b_mbuf.h>
+
+#include <i4b/capi/capi.h>
+#include <i4b/capi/capi_msgs.h>
+
+#include <i4b/capi/iavc/iavc.h>
+
+/* Forward declarations of local subroutines... */
+
+static int iavc_send_init(iavc_softc_t *);
+
+static void iavc_handle_rx(iavc_softc_t *);
+static void iavc_start_tx(iavc_softc_t *);
+
+/*
+// Callbacks from the upper (capi) layer:
+// --------------------------------------
+//
+// iavc_load
+// Resets the board and loads the firmware, then initiates
+// board startup.
+//
+// iavc_register
+// Registers a CAPI application id.
+//
+// iavc_release
+// Releases a CAPI application id.
+//
+// iavc_send
+// Sends a capi message.
+*/
+
+int iavc_load(capi_softc_t *capi_sc, int len, u_int8_t *cp)
+{
+ iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
+ u_int8_t val;
+
+ if(bootverbose)
+ printf("iavc%d: reset card ....\n", sc->sc_unit);
+
+ if (sc->sc_dma)
+ b1dma_reset(sc); /* PCI cards */
+ else if (sc->sc_t1)
+ t1_reset(sc); /* ISA attachment T1 */
+ else
+ b1_reset(sc); /* ISA attachment B1 */
+
+ DELAY(1000);
+
+ if(bootverbose)
+ printf("iavc%d: start loading %d bytes firmware ....\n", sc->sc_unit, len);
+
+ while (len && b1io_save_put_byte(sc, *cp++) == 0)
+ len--;
+
+ if (len) {
+ printf("iavc%d: loading failed, can't write to card, len = %d\n",
+ sc->sc_unit, len);
+ return (EIO);
+ }
+
+ if(bootverbose)
+ printf("iavc%d: firmware loaded, wait for ACK ....\n", sc->sc_unit);
+
+ if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA)
+ iavc_put_byte(sc, SEND_POLL);
+ else
+ iavc_put_byte(sc, SEND_POLLACK);
+
+ for (len = 0; len < 1000 && !iavc_rx_full(sc); len++)
+ DELAY(100);
+
+ if (!iavc_rx_full(sc)) {
+ printf("iavc%d: loading failed, no ack\n", sc->sc_unit);
+ return (EIO);
+ }
+
+ val = iavc_get_byte(sc);
+
+ if ((sc->sc_dma && val != RECEIVE_POLLDWORD) ||
+ (!sc->sc_dma && val != RECEIVE_POLL)) {
+ printf("iavc%d: loading failed, bad ack = %02x\n", sc->sc_unit, val);
+ return (EIO);
+ }
+
+ if(bootverbose)
+ printf("iavc%d: got ACK = 0x%02x\n", sc->sc_unit, val);
+
+ if (sc->sc_dma) {
+ /* Start the DMA engine */
+
+ int s = SPLI4B();
+
+ sc->sc_csr = AVM_FLAG;
+ AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
+ AMCC_WRITE(sc, AMCC_MCSR, (EN_A2P_TRANSFERS|EN_P2A_TRANSFERS|
+ A2P_HI_PRIORITY|P2A_HI_PRIORITY|
+ RESET_A2P_FLAGS|RESET_P2A_FLAGS));
+
+ iavc_write_port(sc, 0x07, 0x30); /* XXX magic numbers from */
+ iavc_write_port(sc, 0x10, 0xf0); /* XXX the linux driver */
+
+ sc->sc_recvlen = 0;
+ AMCC_WRITE(sc, AMCC_RXPTR, vtophys(&sc->sc_recvbuf[0]));
+ AMCC_WRITE(sc, AMCC_RXLEN, 4);
+ sc->sc_csr |= EN_RX_TC_INT|EN_TX_TC_INT;
+ AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
+
+ splx(s);
+ }
+
+ if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA)
+ b1isa_setup_irq(sc);
+
+ iavc_send_init(sc);
+
+ return 0;
+}
+
+int iavc_register(capi_softc_t *capi_sc, int applid, int nchan)
+{
+ iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
+ struct mbuf *m = i4b_Dgetmbuf(23);
+ u_int8_t *p;
+
+ if (!m) {
+ printf("iavc%d: can't get memory\n", sc->sc_unit);
+ return (ENOMEM);
+ }
+
+ /*
+ * byte 0x12 = SEND_REGISTER
+ * dword ApplId
+ * dword NumMessages
+ * dword NumB3Connections 0..nbch
+ * dword NumB3Blocks
+ * dword B3Size
+ */
+
+ p = amcc_put_byte(mtod(m, u_int8_t*), 0);
+ p = amcc_put_byte(p, 0);
+ p = amcc_put_byte(p, SEND_REGISTER);
+ p = amcc_put_word(p, applid);
+#if 0
+ p = amcc_put_word(p, 1024 + (nchan + 1));
+#else
+ p = amcc_put_word(p, 1024 * (nchan + 1));
+#endif
+ p = amcc_put_word(p, nchan);
+ p = amcc_put_word(p, 8);
+ p = amcc_put_word(p, 2048);
+
+ _IF_ENQUEUE(&sc->sc_txq, m);
+
+ iavc_start_tx(sc);
+
+ return 0;
+}
+
+int iavc_release(capi_softc_t *capi_sc, int applid)
+{
+ iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
+ struct mbuf *m = i4b_Dgetmbuf(7);
+ u_int8_t *p;
+
+ if (!m) {
+ printf("iavc%d: can't get memory\n", sc->sc_unit);
+ return (ENOMEM);
+ }
+
+ /*
+ * byte 0x14 = SEND_RELEASE
+ * dword ApplId
+ */
+
+ p = amcc_put_byte(mtod(m, u_int8_t*), 0);
+ p = amcc_put_byte(p, 0);
+ p = amcc_put_byte(p, SEND_RELEASE);
+ p = amcc_put_word(p, applid);
+
+ _IF_ENQUEUE(&sc->sc_txq, m);
+
+ iavc_start_tx(sc);
+ return 0;
+}
+
+int iavc_send(capi_softc_t *capi_sc, struct mbuf *m)
+{
+ iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
+
+ if (sc->sc_state != IAVC_UP) {
+ printf("iavc%d: attempt to send before device up\n", sc->sc_unit);
+
+ if (m->m_next) i4b_Bfreembuf(m->m_next);
+ i4b_Dfreembuf(m);
+
+ return (ENXIO);
+ }
+
+ if (_IF_QFULL(&sc->sc_txq)) {
+ _IF_DROP(&sc->sc_txq);
+
+ printf("iavc%d: tx overflow, message dropped\n", sc->sc_unit);
+
+ if (m->m_next) i4b_Bfreembuf(m->m_next);
+ i4b_Dfreembuf(m);
+
+ } else {
+ _IF_ENQUEUE(&sc->sc_txq, m);
+
+ iavc_start_tx(sc);
+ }
+
+ return 0;
+}
+
+/*
+// Functions called by ourself during the initialization sequence:
+// ---------------------------------------------------------------
+//
+// iavc_send_init
+// Sends the system initialization message to a newly loaded
+// board, and sets state to INIT.
+*/
+
+static int iavc_send_init(iavc_softc_t *sc)
+{
+ struct mbuf *m = i4b_Dgetmbuf(15);
+ u_int8_t *p;
+ int s;
+
+ if (!m) {
+ printf("iavc%d: can't get memory\n", sc->sc_unit);
+ return (ENOMEM);
+ }
+
+ /*
+ * byte 0x11 = SEND_INIT
+ * dword NumApplications
+ * dword NumNCCIs
+ * dword BoardNumber
+ */
+
+ p = amcc_put_byte(mtod(m, u_int8_t*), 0);
+ p = amcc_put_byte(p, 0);
+ p = amcc_put_byte(p, SEND_INIT);
+ p = amcc_put_word(p, 1); /* XXX MaxAppl XXX */
+ p = amcc_put_word(p, sc->sc_capi.sc_nbch);
+ p = amcc_put_word(p, sc->sc_unit);
+
+ s = SPLI4B();
+ _IF_ENQUEUE(&sc->sc_txq, m);
+
+ iavc_start_tx(sc);
+
+ sc->sc_state = IAVC_INIT;
+ splx(s);
+ return 0;
+}
+
+/*
+// Functions called during normal operation:
+// -----------------------------------------
+//
+// iavc_receive_init
+// Reads the initialization reply and calls capi_ll_control().
+//
+// iavc_receive_new_ncci
+// Reads a new NCCI notification and calls capi_ll_control().
+//
+// iavc_receive_free_ncci
+// Reads a freed NCCI notification and calls capi_ll_control().
+//
+// iavc_receive_task_ready
+// Reads a task ready message -- which should not occur XXX.
+//
+// iavc_receive_debugmsg
+// Reads a debug message -- which should not occur XXX.
+//
+// iavc_receive_start
+// Reads a START TRANSMIT message and unblocks device.
+//
+// iavc_receive_stop
+// Reads a STOP TRANSMIT message and blocks device.
+//
+// iavc_receive
+// Reads an incoming message and calls capi_ll_receive().
+*/
+
+static int iavc_receive_init(iavc_softc_t *sc, u_int8_t *dmabuf)
+{
+ u_int32_t Length;
+ u_int8_t *p;
+ u_int8_t *cardtype, *serial, *profile, *version, *caps, *prot;
+
+ if (sc->sc_dma) {
+ p = amcc_get_word(dmabuf, &Length);
+ } else {
+ Length = iavc_get_slice(sc, sc->sc_recvbuf);
+ p = sc->sc_recvbuf;
+ }
+
+#if 0
+ {
+ int len = 0;
+ printf("iavc%d: rx_init: ", sc->sc_unit);
+ while (len < Length) {
+ printf(" %02x", p[len]);
+ if (len && (len % 16) == 0) printf("\n");
+ len++;
+ }
+ if (len % 16) printf("\n");
+ }
+#endif
+
+ version = (p + 1);
+ p += (*p + 1); /* driver version */
+ cardtype = (p + 1);
+ p += (*p + 1); /* card type */
+ p += (*p + 1); /* hardware ID */
+ serial = (p + 1);
+ p += (*p + 1); /* serial number */
+ caps = (p + 1);
+ p += (*p + 1); /* supported options */
+ prot = (p + 1);
+ p += (*p + 1); /* supported protocols */
+ profile = (p + 1);
+
+ if (cardtype && serial && profile) {
+ int nbch = ((profile[3]<<8) | profile[2]);
+
+ printf("iavc%d: AVM %s, s/n %s, %d chans, f/w rev %s, prot %s\n",
+ sc->sc_unit, cardtype, serial, nbch, version, prot);
+
+ if(bootverbose)
+ printf("iavc%d: %s\n", sc->sc_unit, caps);
+
+ capi_ll_control(&sc->sc_capi, CAPI_CTRL_PROFILE, (int) profile);
+
+ } else {
+ printf("iavc%d: no profile data in info response?\n", sc->sc_unit);
+ }
+
+ sc->sc_blocked = TRUE; /* controller will send START when ready */
+ return 0;
+}
+
+static int iavc_receive_start(iavc_softc_t *sc, u_int8_t *dmabuf)
+{
+ struct mbuf *m = i4b_Dgetmbuf(3);
+ u_int8_t *p;
+
+ if (sc->sc_blocked && sc->sc_state == IAVC_UP)
+ printf("iavc%d: receive_start\n", sc->sc_unit);
+
+ if (!m) {
+ printf("iavc%d: can't get memory\n", sc->sc_unit);
+ return (ENOMEM);
+ }
+
+ /*
+ * byte 0x73 = SEND_POLLACK
+ */
+
+ p = amcc_put_byte(mtod(m, u_int8_t*), 0);
+ p = amcc_put_byte(p, 0);
+ p = amcc_put_byte(p, SEND_POLLACK);
+
+ _IF_PREPEND(&sc->sc_txq, m);
+
+ NDBGL4(L4_IAVCDBG, "iavc%d: blocked = %d, state = %d",
+ sc->sc_unit, sc->sc_blocked, sc->sc_state);
+
+ sc->sc_blocked = FALSE;
+ iavc_start_tx(sc);
+
+ /* If this was our first START, register our readiness */
+
+ if (sc->sc_state != IAVC_UP) {
+ sc->sc_state = IAVC_UP;
+ capi_ll_control(&sc->sc_capi, CAPI_CTRL_READY, TRUE);
+ }
+
+ return 0;
+}
+
+static int iavc_receive_stop(iavc_softc_t *sc, u_int8_t *dmabuf)
+{
+ printf("iavc%d: receive_stop\n", sc->sc_unit);
+ sc->sc_blocked = TRUE;
+ return 0;
+}
+
+static int iavc_receive_new_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
+{
+ u_int32_t ApplId, NCCI, WindowSize;
+
+ if (sc->sc_dma) {
+ dmabuf = amcc_get_word(dmabuf, &ApplId);
+ dmabuf = amcc_get_word(dmabuf, &NCCI);
+ dmabuf = amcc_get_word(dmabuf, &WindowSize);
+ } else {
+ ApplId = iavc_get_word(sc);
+ NCCI = iavc_get_word(sc);
+ WindowSize = iavc_get_word(sc);
+ }
+
+ capi_ll_control(&sc->sc_capi, CAPI_CTRL_NEW_NCCI, NCCI);
+ return 0;
+}
+
+static int iavc_receive_free_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
+{
+ u_int32_t ApplId, NCCI;
+
+ if (sc->sc_dma) {
+ dmabuf = amcc_get_word(dmabuf, &ApplId);
+ dmabuf = amcc_get_word(dmabuf, &NCCI);
+ } else {
+ ApplId = iavc_get_word(sc);
+ NCCI = iavc_get_word(sc);
+ }
+
+ capi_ll_control(&sc->sc_capi, CAPI_CTRL_FREE_NCCI, NCCI);
+ return 0;
+}
+
+static int iavc_receive_task_ready(iavc_softc_t *sc, u_int8_t *dmabuf)
+{
+ u_int32_t TaskId, Length;
+ u_int8_t *p;
+ printf("iavc%d: receive_task_ready\n", sc->sc_unit);
+
+ if (sc->sc_dma) {
+ p = amcc_get_word(dmabuf, &TaskId);
+ p = amcc_get_word(p, &Length);
+ } else {
+ TaskId = iavc_get_word(sc);
+ Length = iavc_get_slice(sc, sc->sc_recvbuf);
+ p = sc->sc_recvbuf;
+ }
+
+ /* XXX could show the message if trace enabled? XXX */
+ return 0;
+}
+
+static int iavc_receive_debugmsg(iavc_softc_t *sc, u_int8_t *dmabuf)
+{
+ u_int32_t Length;
+ u_int8_t *p;
+ printf("iavc%d: receive_debugmsg\n", sc->sc_unit);
+
+ if (sc->sc_dma) {
+ p = amcc_get_word(dmabuf, &Length);
+ } else {
+ Length = iavc_get_slice(sc, sc->sc_recvbuf);
+ p = sc->sc_recvbuf;
+ }
+
+ /* XXX could show the message if trace enabled? XXX */
+ return 0;
+}
+
+static int iavc_receive(iavc_softc_t *sc, u_int8_t *dmabuf, int b3data)
+{
+ struct mbuf *m;
+ u_int32_t ApplId, Length;
+
+ /*
+ * byte 0x21 = RECEIVE_MESSAGE
+ * dword ApplId
+ * dword length
+ * ... CAPI msg
+ *
+ * --or--
+ *
+ * byte 0x22 = RECEIVE_DATA_B3_IND
+ * dword ApplId
+ * dword length
+ * ... CAPI msg
+ * dword datalen
+ * ... B3 data
+ */
+
+ if (sc->sc_dma) {
+ dmabuf = amcc_get_word(dmabuf, &ApplId);
+ dmabuf = amcc_get_word(dmabuf, &Length);
+ } else {
+ ApplId = iavc_get_word(sc);
+ Length = iavc_get_slice(sc, sc->sc_recvbuf);
+ dmabuf = sc->sc_recvbuf;
+ }
+
+ m = i4b_Dgetmbuf(Length);
+ if (!m) {
+ printf("iavc%d: can't get memory for receive\n", sc->sc_unit);
+ return (ENOMEM);
+ }
+
+ bcopy(dmabuf, mtod(m, u_int8_t*), Length);
+
+#if 0
+ {
+ u_int8_t *p = mtod(m, u_int8_t*);
+ int len = 0;
+ printf("iavc%d: applid=%d, len=%d\n", sc->sc_unit, ApplId, Length);
+ while (len < m->m_len) {
+ printf(" %02x", p[len]);
+ if (len && (len % 16) == 0) printf("\n");
+ len++;
+ }
+ if (len % 16) printf("\n");
+ }
+#endif
+
+ if (b3data) {
+ if (sc->sc_dma) {
+ dmabuf = amcc_get_word(dmabuf + Length, &Length);
+ } else {
+ Length = iavc_get_slice(sc, sc->sc_recvbuf);
+ dmabuf = sc->sc_recvbuf;
+ }
+
+ m->m_next = i4b_Bgetmbuf(Length);
+ if (!m->m_next) {
+ printf("iavc%d: can't get memory for receive\n", sc->sc_unit);
+ i4b_Dfreembuf(m);
+ return (ENOMEM);
+ }
+
+ bcopy(dmabuf, mtod(m->m_next, u_int8_t*), Length);
+ }
+
+ capi_ll_receive(&sc->sc_capi, m);
+ return 0;
+}
+
+/*
+// iavc_handle_intr
+// Checks device interrupt status and calls iavc_handle_{rx,tx}()
+// as necessary.
+//
+// iavc_handle_rx
+// Reads in the command byte and calls the subroutines above.
+//
+// iavc_start_tx
+// Initiates DMA on the next queued message if possible.
+*/
+
+void iavc_handle_intr(iavc_softc_t *sc)
+{
+ u_int32_t status;
+ u_int32_t newcsr;
+
+ if (!sc->sc_dma) {
+ while (iavc_rx_full(sc))
+ iavc_handle_rx(sc);
+ return;
+ }
+
+ status = AMCC_READ(sc, AMCC_INTCSR);
+ if ((status & ANY_S5933_INT) == 0)
+ return;
+
+ newcsr = sc->sc_csr | (status & ALL_INT);
+ if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
+ if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
+ AMCC_WRITE(sc, AMCC_INTCSR, newcsr);
+ sc->sc_intr = TRUE;
+
+ if (status & RX_TC_INT) {
+ u_int32_t rxlen;
+
+ if (sc->sc_recvlen == 0) {
+ sc->sc_recvlen = *((u_int32_t*)(&sc->sc_recvbuf[0]));
+ rxlen = (sc->sc_recvlen + 3) & ~3;
+ AMCC_WRITE(sc, AMCC_RXPTR, vtophys(&sc->sc_recvbuf[4]));
+ AMCC_WRITE(sc, AMCC_RXLEN, rxlen);
+ } else {
+ iavc_handle_rx(sc);
+ sc->sc_recvlen = 0;
+ AMCC_WRITE(sc, AMCC_RXPTR, vtophys(&sc->sc_recvbuf[0]));
+ AMCC_WRITE(sc, AMCC_RXLEN, 4);
+ }
+ }
+
+ if (status & TX_TC_INT) {
+ sc->sc_csr &= ~EN_TX_TC_INT;
+ iavc_start_tx(sc);
+ }
+
+ AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
+ sc->sc_intr = FALSE;
+}
+
+static void iavc_handle_rx(iavc_softc_t *sc)
+{
+ u_int8_t *dmabuf = 0, cmd;
+
+ if (sc->sc_dma) {
+ dmabuf = amcc_get_byte(&sc->sc_recvbuf[4], &cmd);
+ } else {
+ cmd = iavc_get_byte(sc);
+ }
+
+ NDBGL4(L4_IAVCDBG, "iavc%d: command = 0x%02x", sc->sc_unit, cmd);
+
+ switch (cmd) {
+ case RECEIVE_DATA_B3_IND:
+ iavc_receive(sc, dmabuf, TRUE);
+ break;
+
+ case RECEIVE_MESSAGE:
+ iavc_receive(sc, dmabuf, FALSE);
+ break;
+
+ case RECEIVE_NEW_NCCI:
+ iavc_receive_new_ncci(sc, dmabuf);
+ break;
+
+ case RECEIVE_FREE_NCCI:
+ iavc_receive_free_ncci(sc, dmabuf);
+ break;
+
+ case RECEIVE_START:
+ iavc_receive_start(sc, dmabuf);
+ break;
+
+ case RECEIVE_STOP:
+ iavc_receive_stop(sc, dmabuf);
+ break;
+
+ case RECEIVE_INIT:
+ iavc_receive_init(sc, dmabuf);
+ break;
+
+ case RECEIVE_TASK_READY:
+ iavc_receive_task_ready(sc, dmabuf);
+ break;
+
+ case RECEIVE_DEBUGMSG:
+ iavc_receive_debugmsg(sc, dmabuf);
+ break;
+
+ default:
+ printf("iavc%d: unknown msg %02x\n", sc->sc_unit, cmd);
+ }
+}
+
+static void iavc_start_tx(iavc_softc_t *sc)
+{
+ struct mbuf *m;
+ u_int8_t *dmabuf;
+ u_int32_t txlen = 0;
+
+ /* If device has put us on hold, punt. */
+
+ if (sc->sc_blocked) {
+ return;
+ }
+
+ /* If using DMA and transmitter busy, punt. */
+
+ if (sc->sc_dma && (sc->sc_csr & EN_TX_TC_INT)) {
+ return;
+ }
+
+ /* Else, see if we have messages to send. */
+
+ _IF_DEQUEUE(&sc->sc_txq, m);
+ if (!m) {
+ return;
+ }
+
+ /* Have message, will send. */
+
+ if (CAPIMSG_LEN(m->m_data)) {
+ /* A proper CAPI message, possibly with B3 data */
+
+ if (sc->sc_dma) {
+ /* Copy message to DMA buffer. */
+
+ if (m->m_next) {
+ dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_DATA_B3_REQ);
+ } else {
+ dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_MESSAGE);
+ }
+
+ dmabuf = amcc_put_word(dmabuf, m->m_len);
+ bcopy(m->m_data, dmabuf, m->m_len);
+ dmabuf += m->m_len;
+ txlen = 5 + m->m_len;
+
+ if (m->m_next) {
+ dmabuf = amcc_put_word(dmabuf, m->m_next->m_len);
+ bcopy(m->m_next->m_data, dmabuf, m->m_next->m_len);
+ txlen += 4 + m->m_next->m_len;
+ }
+
+ } else {
+ /* Use PIO. */
+
+ if (m->m_next) {
+ iavc_put_byte(sc, SEND_DATA_B3_REQ);
+ NDBGL4(L4_IAVCDBG, "iavc%d: tx SDB3R msg, len = %d", sc->sc_unit, m->m_len);
+ } else {
+ iavc_put_byte(sc, SEND_MESSAGE);
+ NDBGL4(L4_IAVCDBG, "iavc%d: tx SM msg, len = %d", sc->sc_unit, m->m_len);
+ }
+#if 0
+ {
+ u_int8_t *p = mtod(m, u_int8_t*);
+ int len;
+ for (len = 0; len < m->m_len; len++) {
+ printf(" %02x", *p++);
+ if (len && (len % 16) == 0) printf("\n");
+ }
+ if (len % 16) printf("\n");
+ }
+#endif
+
+ iavc_put_slice(sc, m->m_data, m->m_len);
+
+ if (m->m_next) {
+ iavc_put_slice(sc, m->m_next->m_data, m->m_next->m_len);
+ }
+ }
+
+ } else {
+ /* A board control message to be sent as is */
+
+ if (sc->sc_dma) {
+ bcopy(m->m_data + 2, &sc->sc_sendbuf[0], m->m_len - 2);
+ txlen = m->m_len - 2;
+
+ } else {
+#if 0
+ {
+ u_int8_t *p = mtod(m, u_int8_t*) + 2;
+ int len;
+ printf("iavc%d: tx BDC msg, len = %d, msg =", sc->sc_unit, m->m_len-2);
+ for (len = 0; len < m->m_len-2; len++) {
+ printf(" %02x", *p++);
+ if (len && (len % 16) == 0) printf("\n");
+ }
+ if (len % 16) printf("\n");
+ }
+#endif
+
+ txlen = m->m_len - 2;
+ dmabuf = mtod(m, char*) + 2;
+ while(txlen--)
+ b1io_put_byte(sc, *dmabuf++);
+ }
+ }
+
+ if (m->m_next) {
+ i4b_Bfreembuf(m->m_next);
+ m->m_next = NULL;
+ }
+ i4b_Dfreembuf(m);
+
+ if (sc->sc_dma) {
+ /* Start transmitter */
+
+ txlen = (txlen + 3) & ~3;
+ AMCC_WRITE(sc, AMCC_TXPTR, vtophys(&sc->sc_sendbuf[0]));
+ AMCC_WRITE(sc, AMCC_TXLEN, txlen);
+ sc->sc_csr |= EN_TX_TC_INT;
+
+ if (!sc->sc_intr)
+ AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
+ }
+}
+
+#endif
diff --git a/sys/i4b/capi/iavc/iavc_pci.c b/sys/i4b/capi/iavc/iavc_pci.c
new file mode 100644
index 0000000..5579a3c
--- /dev/null
+++ b/sys/i4b/capi/iavc/iavc_pci.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2001 Cubical Solutions Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * capi/iavc/iavc_pci.c
+ * The AVM ISDN controllers' PCI bus attachment handling.
+ *
+ * $FreeBSD$
+ */
+
+#include "iavc.h"
+#include "i4bcapi.h"
+#include "pci.h"
+
+#if (NIAVC > 0) && (NI4BCAPI > 0) && (NPCI > 0)
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <machine/clock.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+#include <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_trace.h>
+
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_l3l4.h>
+#include <i4b/include/i4b_mbuf.h>
+
+#include <i4b/capi/capi.h>
+
+#include <i4b/capi/iavc/iavc.h>
+
+/* PCI device ids */
+
+#define PCI_AVM_VID 0x1244
+#define PCI_AVMT1_DID 0x1200
+#define PCI_AVMB1_DID 0x0700
+
+/* PCI driver linkage */
+
+static void iavc_pci_intr(iavc_softc_t *sc);
+static int iavc_pci_probe(device_t dev);
+static int iavc_pci_attach(device_t dev);
+
+static device_method_t iavc_pci_methods[] =
+{
+ DEVMETHOD(device_probe, iavc_pci_probe),
+ DEVMETHOD(device_attach, iavc_pci_attach),
+ { 0, 0 }
+};
+
+static driver_t iavc_pci_driver =
+{
+ "iavc",
+ iavc_pci_methods,
+ 0
+};
+
+static devclass_t iavc_pci_devclass;
+
+DRIVER_MODULE(iavc, pci, iavc_pci_driver, iavc_pci_devclass, 0, 0);
+
+/* Driver soft contexts */
+
+iavc_softc_t iavc_sc[IAVC_MAXUNIT];
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+
+static int
+iavc_pci_probe(device_t dev)
+{
+ u_int16_t did = pci_get_device(dev);
+ u_int16_t vid = pci_get_vendor(dev);
+
+ if ((vid == PCI_AVM_VID) && (did == PCI_AVMT1_DID)) {
+ device_set_desc(dev, "AVM T1 PCI");
+ } else if ((vid == PCI_AVM_VID) && (did == PCI_AVMB1_DID)) {
+ device_set_desc(dev, "AVM B1 PCI");
+ } else {
+ return(ENXIO);
+ }
+
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+
+static int
+iavc_pci_attach(device_t dev)
+{
+ struct iavc_softc *sc;
+ void *ih = 0;
+ u_int16_t did = pci_get_device(dev);
+ int unit = device_get_unit(dev), ret;
+
+ /* check max unit range */
+
+ if (unit >= IAVC_MAXUNIT) {
+ printf("iavc%d: too many units\n", unit);
+ return(ENXIO);
+ }
+
+ sc = iavc_find_sc(unit); /* get softc */
+
+ sc->sc_unit = unit;
+
+ /* use the i/o mapped base address */
+
+ sc->sc_resources.io_rid[0] = 0x14;
+
+ if (!(sc->sc_resources.io_base[0] =
+ bus_alloc_resource(dev, SYS_RES_IOPORT,
+ &sc->sc_resources.io_rid[0],
+ 0UL, ~0UL, 1, RF_ACTIVE))) {
+ printf("iavc%d: can't allocate io region\n", unit);
+ return(ENXIO);
+ }
+
+ sc->sc_iobase = rman_get_start(sc->sc_resources.io_base[0]);
+ sc->sc_io_bt = rman_get_bustag(sc->sc_resources.io_base[0]);
+ sc->sc_io_bh = rman_get_bushandle(sc->sc_resources.io_base[0]);
+
+ /* use the memory mapped DMA controller */
+
+ sc->sc_resources.mem_rid = 0x10;
+
+ if (!(sc->sc_resources.mem =
+ bus_alloc_resource(dev, SYS_RES_MEMORY,
+ &sc->sc_resources.mem_rid,
+ 0UL, ~0UL, 1, RF_ACTIVE))) {
+ printf("iavc%d: can't allocate memory region\n", unit);
+ return(ENXIO);
+ }
+
+ sc->sc_membase = rman_get_start(sc->sc_resources.mem);
+ sc->sc_mem_bt = rman_get_bustag(sc->sc_resources.mem);
+ sc->sc_mem_bh = rman_get_bushandle(sc->sc_resources.mem);
+
+ /* do some detection */
+
+ sc->sc_t1 = FALSE;
+ sc->sc_dma = FALSE;
+ b1dma_reset(sc);
+
+ if (did == PCI_AVMT1_DID) {
+ sc->sc_capi.card_type = CARD_TYPEC_AVM_T1_PCI;
+ sc->sc_capi.sc_nbch = 30;
+ ret = t1_detect(sc);
+ if (ret) {
+ if (ret < 6) {
+ printf("iavc%d: no card detected?\n", sc->sc_unit);
+ } else {
+ printf("iavc%d: black box not on\n", sc->sc_unit);
+ }
+ return(ENXIO);
+ } else {
+ sc->sc_dma = TRUE;
+ sc->sc_t1 = TRUE;
+ }
+
+ } else if (did == PCI_AVMB1_DID) {
+ sc->sc_capi.card_type = CARD_TYPEC_AVM_B1_PCI;
+ sc->sc_capi.sc_nbch = 2;
+ ret = b1dma_detect(sc);
+ if (ret) {
+ ret = b1_detect(sc);
+ if (ret) {
+ printf("iavc%d: no card detected?\n", sc->sc_unit);
+ return(ENXIO);
+ }
+ } else {
+ sc->sc_dma = TRUE;
+ }
+ }
+
+ if (sc->sc_dma) b1dma_reset(sc);
+#if 0
+ if (sc->sc_t1) t1_reset(sc);
+ else b1_reset(sc);
+#endif
+
+ /* of course we need an interrupt */
+
+ sc->sc_resources.irq_rid = 0x00;
+
+ if(!(sc->sc_resources.irq =
+ bus_alloc_resource(dev, SYS_RES_IRQ,
+ &sc->sc_resources.irq_rid,
+ 0UL, ~0UL, 1, RF_SHAREABLE|RF_ACTIVE))) {
+ printf("iavc%d: can't allocate irq\n",unit);
+ return(ENXIO);
+ }
+
+ /* finalize our own context */
+
+ memset(&sc->sc_txq, 0, sizeof(struct ifqueue));
+ sc->sc_txq.ifq_maxlen = sc->sc_capi.sc_nbch * 4;
+
+#if defined (__FreeBSD__) && __FreeBSD__ > 4
+ mtx_init(&sc->sc_txq.ifq_mtx, "i4b_ivac_pci", MTX_DEF);
+#endif
+
+ sc->sc_intr = FALSE;
+ sc->sc_state = IAVC_DOWN;
+ sc->sc_blocked = FALSE;
+
+ /* setup capi link */
+
+ sc->sc_capi.load = iavc_load;
+ sc->sc_capi.reg_appl = iavc_register;
+ sc->sc_capi.rel_appl = iavc_release;
+ sc->sc_capi.send = iavc_send;
+ sc->sc_capi.ctx = (void*) sc;
+
+ if (capi_ll_attach(&sc->sc_capi)) {
+ printf("iavc%d: capi attach failed\n", unit);
+ return(ENXIO);
+ }
+
+ /* setup the interrupt */
+
+ if(bus_setup_intr(dev, sc->sc_resources.irq, INTR_TYPE_NET,
+ (void(*)(void*))iavc_pci_intr,
+ sc, &ih)) {
+ printf("iavc%d: irq setup failed\n", unit);
+ return(ENXIO);
+ }
+
+ /* the board is now ready to be loaded */
+
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * IRQ handler
+ *---------------------------------------------------------------------------*/
+
+static void
+iavc_pci_intr(struct iavc_softc *sc)
+{
+ iavc_handle_intr(sc);
+}
+
+#endif
diff --git a/sys/i4b/include/i4b_debug.h b/sys/i4b/include/i4b_debug.h
index 26bfa50..d9380f7 100644
--- a/sys/i4b/include/i4b_debug.h
+++ b/sys/i4b/include/i4b_debug.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
+ * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,11 +27,9 @@
* i4b_debug.h - i4b debug header file
* -----------------------------------
*
- * $Id: i4b_debug.h,v 1.32 2000/07/24 12:22:08 hm Exp $
- *
* $FreeBSD$
*
- * last edit-date: [Wed Oct 18 09:48:16 2000]
+ * last edit-date: [Mon May 21 10:05:34 2001]
*
*---------------------------------------------------------------------------*/
@@ -169,13 +167,12 @@ extern unsigned int i4b_l4_debug;
#define L4_RBCHDBG 0x0020 /* rbch driver debug messages */
#define L4_ISPDBG 0x0040 /* isp driver debug messages */
#define L4_TELDBG 0x0080 /* tel driver debug messages */
-#define L4_TINADBG 0x0100 /* tina driver debug messages */
-#define L4_TINAMSG 0x0200 /* tina driver messages */
-#define L4_TINAERR 0x0400 /* tina driver error messages */
-#define L4_INGDBG 0x0800 /* ing driver debug messages */
+#define L4_INGDBG 0x0100 /* ing driver debug messages */
+#define L4_IAVCDBG 0x0200 /* AVM B1 driver debug messages */
+#define L4_CAPIDBG 0x0400 /* CAPI driver debug messages */
#define L4_DEBUG_MAX 0x0fff /* all messages on */
-#define L4_DEBUG_ERR (L4_ERR | L4_TINADBG | L4_TINAMSG | L4_TINAERR)
+#define L4_DEBUG_ERR L4_ERR
#ifndef L4_DEBUG_DEFAULT
#ifdef DO_I4B_MAXDEBUG
diff --git a/sys/i4b/include/i4b_ioctl.h b/sys/i4b/include/i4b_ioctl.h
index 8070f3e..d357326 100644
--- a/sys/i4b/include/i4b_ioctl.h
+++ b/sys/i4b/include/i4b_ioctl.h
@@ -29,7 +29,7 @@
*
* $FreeBSD$
*
- * last edit-date: [Fri Jan 26 13:46:50 2001]
+ * last edit-date: [Fri May 25 10:04:37 2001]
*
*---------------------------------------------------------------------------*/
@@ -45,9 +45,9 @@
/*---------------------------------------------------------------------------*
* version and release number for isdn4bsd package
*---------------------------------------------------------------------------*/
-#define VERSION 0 /* version number */
-#define REL 96 /* release number */
-#define STEP 3 /* release step */
+#define VERSION 1 /* version number */
+#define REL 0 /* release number */
+#define STEP 0 /* release step */
/*---------------------------------------------------------------------------*
* date/time format in i4b log messages
@@ -82,7 +82,8 @@
#define CTRL_DAIC 2 /* Diehl active controller cards*/
#define CTRL_TINADD 3 /* Stollmann Tina-dd active card*/
#define CTRL_AVMB1 4 /* AVM B1 active card */
-#define CTRL_NUMTYPES 5 /* number of controller types */
+#define CTRL_CAPI 5 /* cards seen via the CAPI layer*/
+#define CTRL_NUMTYPES 6 /* number of controller types */
/*---------------------------------------------------------------------------*
* CTRL_PASSIVE: driver types
@@ -156,6 +157,14 @@
#define CARD_TYPEA_DAIC_QUAD 4
/*---------------------------------------------------------------------------*
+ * card types for CTRL_CAPI
+ *---------------------------------------------------------------------------*/
+#define CARD_TYPEC_CAPI_UNK 0
+#define CARD_TYPEC_AVM_T1_PCI 1
+#define CARD_TYPEC_AVM_B1_PCI 2
+#define CARD_TYPEC_AVM_B1_ISA 3
+
+/*---------------------------------------------------------------------------*
* max length of some strings
*---------------------------------------------------------------------------*/
#define TELNO_MAX 41 /* max length of a telephone number (+ '\0') */
@@ -592,6 +601,7 @@ typedef struct {
int ctrl_type; /* controller type passive/active */
int card_type; /* brand / version */
int tei; /* tei controller probably has */
+ int nbch; /* number of b channels provided */
} msg_ctrl_info_req_t;
#define I4B_CTRL_INFO_REQ _IOWR('4', 4, msg_ctrl_info_req_t)
diff --git a/sys/i4b/include/i4b_l3l4.h b/sys/i4b/include/i4b_l3l4.h
index 518aa60..d70a211 100644
--- a/sys/i4b/include/i4b_l3l4.h
+++ b/sys/i4b/include/i4b_l3l4.h
@@ -46,7 +46,8 @@
#define T313VAL (hz*4) /* 4 seconds timeout */
#define T400DEF (hz*10) /* 10 seconds timeout */
-#define N_CALL_DESC (MAX_CONTROLLERS*2) /* no of call descriptors */
+#define MAX_BCHAN 30
+#define N_CALL_DESC (MAX_CONTROLLERS*MAX_BCHAN) /* no of call descriptors */
extern int nctrl; /* number of controllers detected in system */
@@ -263,7 +264,8 @@ typedef struct
#define DL_DOWN 0
#define DL_UP 1
- int bch_state[2]; /* states of the b channels */
+ int nbch; /* number of b channels */
+ int bch_state[MAX_BCHAN]; /* states of the b channels */
#define BCH_ST_FREE 0 /* free to be used, idle */
#define BCH_ST_RSVD 1 /* reserved, may become free or used */
#define BCH_ST_USED 2 /* in use for data transfer */
diff --git a/sys/i4b/layer3/i4b_l3fsm.c b/sys/i4b/layer3/i4b_l3fsm.c
index bd60d5a..cde6e7c 100644
--- a/sys/i4b/layer3/i4b_l3fsm.c
+++ b/sys/i4b/layer3/i4b_l3fsm.c
@@ -218,7 +218,7 @@ struct l3state_tab {
/* STATE: ST_U0 ST_U1 ST_U3 ST_U4 ST_U6 ST_U7 ST_U8 ST_U9 ST_U10 ST_U11 ST_U12 ST_U19 ST_IWA ST_IWR ST_OW ST_IWL ST_SUBSET ST_ILL */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
/*EV_DLESTIN*/ {{F_ILL, ST_ILL}, {F_DLEI, ST_U1}, {F_DLEI, ST_U3}, {F_DLEI, ST_U4}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}},
-/*EV_DLRELIN*/ {{F_NCNA, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRIA,ST_U10}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}},
+/*EV_DLRELIN*/ {{F_NCNA, ST_U0}, {F_DLRIA, ST_OW}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRIA,ST_U10}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}},
/*EV_DLESTCF*/ {{F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF2,ST_U8}, {F_DECF3,ST_U0}, {F_DECF1,ST_U1}, {F_DECF4,ST_U7}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}},
/*EV_DLRELCF*/ {{F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}},
/*EV_ILL */ {{F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}
@@ -280,21 +280,25 @@ char *print_l3state(call_desc_t *cd)
*---------------------------------------------------------------------------*/
static void F_00A(call_desc_t *cd)
{
+ int s;
NDBGL3(L3_F_MSG, "FSM function F_00A executing");
+ cd->T303_first_to = 1;
+ T303_start(cd);
+
+ s = SPLI4B();
if(i4b_get_dl_stat(cd) == DL_DOWN)
{
+ splx(s);
DL_Est_Req(ctrl_desc[cd->controller].unit);
cd->Q931state = ST_OW;
}
else
{
- i4b_l3_tx_setup(cd);
cd->Q931state = ST_U1;
+ splx(s);
+ i4b_l3_tx_setup(cd);
}
-
- cd->T303_first_to = 1;
- T303_start(cd);
}
/*---------------------------------------------------------------------------*
diff --git a/sys/i4b/layer3/i4b_l4if.c b/sys/i4b/layer3/i4b_l4if.c
index 112f0a4..3681219 100644
--- a/sys/i4b/layer3/i4b_l4if.c
+++ b/sys/i4b/layer3/i4b_l4if.c
@@ -113,8 +113,10 @@ i4b_mdl_status_ind(int unit, int status, int parm)
/* state fields */
ctrl_desc[nctrl].dl_est = DL_DOWN;
- ctrl_desc[nctrl].bch_state[CHAN_B1] = BCH_ST_FREE;
- ctrl_desc[nctrl].bch_state[CHAN_B2] = BCH_ST_FREE;
+ ctrl_desc[nctrl].nbch = 2; /* XXX extra param? */
+ for (i = 0; i < ctrl_desc[nctrl].nbch; i++)
+ ctrl_desc[nctrl].bch_state[i] = BCH_ST_FREE;
+
ctrl_desc[nctrl].tei = -1;
/* init unit to controller table */
@@ -160,8 +162,8 @@ i4b_mdl_status_ind(int unit, int status, int parm)
}
ctrl_desc[utoc_tab[unit]].dl_est = DL_DOWN;
- ctrl_desc[utoc_tab[unit]].bch_state[CHAN_B1] = BCH_ST_FREE;
- ctrl_desc[utoc_tab[unit]].bch_state[CHAN_B2] = BCH_ST_FREE;
+ for (i = 0; i < ctrl_desc[utoc_tab[unit]].nbch; i++)
+ ctrl_desc[utoc_tab[unit]].bch_state[i] = BCH_ST_FREE;
ctrl_desc[utoc_tab[unit]].tei = -1;
if(sendup)
@@ -189,8 +191,8 @@ i4b_mdl_status_ind(int unit, int status, int parm)
}
ctrl_desc[utoc_tab[unit]].dl_est = DL_DOWN;
- ctrl_desc[utoc_tab[unit]].bch_state[CHAN_B1] = BCH_ST_FREE;
- ctrl_desc[utoc_tab[unit]].bch_state[CHAN_B2] = BCH_ST_FREE;
+ for (i = 0; i < ctrl_desc[utoc_tab[unit]].nbch; i++)
+ ctrl_desc[utoc_tab[unit]].bch_state[i] = BCH_ST_FREE;
ctrl_desc[utoc_tab[unit]].tei = -1;
break;
@@ -224,8 +226,8 @@ n_mgmt_command(int unit, int cmd, void *parm)
}
ctrl_desc[utoc_tab[unit]].dl_est = DL_DOWN;
- ctrl_desc[utoc_tab[unit]].bch_state[CHAN_B1] = BCH_ST_FREE;
- ctrl_desc[utoc_tab[unit]].bch_state[CHAN_B2] = BCH_ST_FREE;
+ for (i = 0; i < ctrl_desc[utoc_tab[unit]].nbch; i++)
+ ctrl_desc[utoc_tab[unit]].bch_state[i] = BCH_ST_FREE;
ctrl_desc[utoc_tab[unit]].tei = -1;
break;
@@ -299,7 +301,7 @@ n_connect_response(u_int cdid, int response, int cause)
break;
}
- if((cd->channelid == CHAN_B1) || (cd->channelid == CHAN_B2))
+ if((cd->channelid >= 0) && (cd->channelid < ctrl_desc[cd->controller].nbch))
{
ctrl_desc[cd->controller].bch_state[cd->channelid] = chstate;
}
diff --git a/sys/i4b/layer4/i4b_i4bdrv.c b/sys/i4b/layer4/i4b_i4bdrv.c
index 29620ad..71c200f 100644
--- a/sys/i4b/layer4/i4b_i4bdrv.c
+++ b/sys/i4b/layer4/i4b_i4bdrv.c
@@ -453,9 +453,16 @@ i4bioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
break;
case CHAN_ANY:
- if((ctrl_desc[mcr->controller].bch_state[CHAN_B1] != BCH_ST_FREE) &&
- (ctrl_desc[mcr->controller].bch_state[CHAN_B2] != BCH_ST_FREE))
+ {
+ int i;
+ for (i = 0;
+ i < ctrl_desc[mcr->controller].nbch &&
+ ctrl_desc[mcr->controller].bch_state[i] != BCH_ST_FREE;
+ i++);
+ if (i == ctrl_desc[mcr->controller].nbch)
SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
+ /* else mcr->channel = i; XXX */
+ }
break;
default:
@@ -560,6 +567,8 @@ i4bioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
ctrl_desc[mcir->controller].ctrl_type;
mcir->card_type =
ctrl_desc[mcir->controller].card_type;
+ mcir->nbch =
+ ctrl_desc[mcir->controller].nbch;
if(ctrl_desc[mcir->controller].ctrl_type == CTRL_PASSIVE)
mcir->tei = ctrl_desc[mcir->controller].tei;
diff --git a/sys/i4b/layer4/i4b_l4.c b/sys/i4b/layer4/i4b_l4.c
index 5430c3a..9cb3f26 100644
--- a/sys/i4b/layer4/i4b_l4.c
+++ b/sys/i4b/layer4/i4b_l4.c
@@ -131,7 +131,7 @@ i4b_l4_pdeact(int controller, int numactive)
i4b_unlink_bchandrvr(cd);
}
- if((cd->channelid == CHAN_B1) || (cd->channelid == CHAN_B2))
+ if((cd->channelid >= 0) & (cd->channelid < ctrl_desc[cd->controller].nbch))
{
ctrl_desc[cd->controller].bch_state[cd->channelid] = BCH_ST_FREE;
}
@@ -438,14 +438,14 @@ i4b_l4_disconnect_ind(call_desc_t *cd)
i4b_unlink_bchandrvr(cd);
}
- if((cd->channelid == CHAN_B1) || (cd->channelid == CHAN_B2))
+ if((cd->channelid >= 0) && (cd->channelid < ctrl_desc[cd->controller].nbch))
{
ctrl_desc[cd->controller].bch_state[cd->channelid] = BCH_ST_FREE;
}
else
{
/* no error, might be hunting call for callback */
- NDBGL4(L4_MSG, "channel free not B1/B2 but %d!", cd->channelid);
+ NDBGL4(L4_MSG, "channel free not valid but %d!", cd->channelid);
}
if((m = i4b_Dgetmbuf(sizeof(msg_disconnect_ind_t))) != NULL)
diff --git a/usr.sbin/i4b/isdnd/config.h b/usr.sbin/i4b/isdnd/config.h
index 4a7aa8c..a4b05f1 100644
--- a/usr.sbin/i4b/isdnd/config.h
+++ b/usr.sbin/i4b/isdnd/config.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 1999 Hellmuth Michaelis. All rights reserved.
+ * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,11 +27,9 @@
* i4b daemon - compile time configuration header file
* ---------------------------------------------------
*
- * $Id: config.h,v 1.8 1999/12/13 21:25:24 hm Exp $
- *
* $FreeBSD$
*
- * last edit-date: [Mon Dec 13 21:45:27 1999]
+ * last edit-date: [Mon May 21 11:21:15 2001]
*
*---------------------------------------------------------------------------*/
@@ -41,7 +39,7 @@
/* general values */
#define UMASK 022 /* file creation perm mask */
-#define CFG_ENTRY_MAX 32 /* max no of config entries */
+#define CFG_ENTRY_MAX 60 /* max no of config entries */
#define ISDN_CTRL_MAX 4 /* max no of controllers */
#define MAX_RE 8 /* max regular expression entries */
diff --git a/usr.sbin/i4b/isdnd/controller.c b/usr.sbin/i4b/isdnd/controller.c
index 9c4fe9e..95f5c90 100644
--- a/usr.sbin/i4b/isdnd/controller.c
+++ b/usr.sbin/i4b/isdnd/controller.c
@@ -29,14 +29,17 @@
*
* $FreeBSD$
*
- * last edit-date: [Fri Jan 26 14:00:10 2001]
+ * last edit-date: [Sun May 20 10:03:53 2001]
*
*---------------------------------------------------------------------------*/
+#include <sys/types.h>
+#include <sys/mman.h>
+
#include "isdnd.h"
static int
-init_controller_state(int controller, int ctrl_type, int card_type, int tei);
+init_controller_state(int controller, int ctrl_type, int card_type, int tei, int nbch);
/*---------------------------------------------------------------------------*
* get name of a controller
@@ -84,6 +87,12 @@ name_of_controller(int ctrl_type, int card_type)
"EICON.Diehl QUADRO",
};
+ static char *capi_card[] = {
+ "AVM T1 PCI",
+ "AVM B1 PCI",
+ "AVM B1 ISA",
+ };
+
if(ctrl_type == CTRL_PASSIVE)
{
int index = card_type - CARD_TYPEP_8;
@@ -100,6 +109,12 @@ name_of_controller(int ctrl_type, int card_type)
{
return "Stollmann tina-dd";
}
+ else if(ctrl_type == CTRL_CAPI)
+ {
+ int index = card_type - CARD_TYPEC_AVM_T1_PCI;
+ if (index >= 0 && index < (sizeof capi_card / sizeof capi_card[0] ))
+ return capi_card[index];
+ }
return "unknown card type";
}
@@ -138,7 +153,7 @@ init_controller(void)
/* init controller tab */
- if((init_controller_state(i, mcir.ctrl_type, mcir.card_type, mcir.tei)) == ERROR)
+ if((init_controller_state(i, mcir.ctrl_type, mcir.card_type, mcir.tei, mcir.nbch)) == ERROR)
{
log(LL_ERR, "init_controller: init_controller_state for controller %d failed", i);
do_exit(1);
@@ -151,8 +166,11 @@ init_controller(void)
* init controller state table entry
*--------------------------------------------------------------------------*/
static int
-init_controller_state(int controller, int ctrl_type, int card_type, int tei)
+init_controller_state(int controller, int ctrl_type, int card_type, int tei,
+ int nbch)
{
+ int i;
+
if((controller < 0) || (controller >= ncontroller))
{
log(LL_ERR, "init_controller_state: invalid controller number [%d]!", controller);
@@ -161,57 +179,49 @@ init_controller_state(int controller, int ctrl_type, int card_type, int tei)
/* init controller tab */
- if(ctrl_type == CTRL_PASSIVE)
- {
+ switch (ctrl_type) {
+ case CTRL_PASSIVE:
if((card_type > CARD_TYPEP_UNK) &&
(card_type <= CARD_TYPEP_MAX))
{
isdn_ctrl_tab[controller].ctrl_type = ctrl_type;
isdn_ctrl_tab[controller].card_type = card_type;
isdn_ctrl_tab[controller].state = CTRL_UP;
- isdn_ctrl_tab[controller].stateb1 = CHAN_IDLE;
- isdn_ctrl_tab[controller].stateb2 = CHAN_IDLE;
- isdn_ctrl_tab[controller].freechans = MAX_CHANCTRL;
- isdn_ctrl_tab[controller].tei = tei;
- isdn_ctrl_tab[controller].l1stat = LAYER_IDLE;
- isdn_ctrl_tab[controller].l2stat = LAYER_IDLE;
- DBGL(DL_RCCF, (log(LL_DBG, "init_controller_state: controller %d is %s",
- controller,
- name_of_controller(isdn_ctrl_tab[controller].ctrl_type,
- isdn_ctrl_tab[controller].card_type))));
}
else
{
log(LL_ERR, "init_controller_state: unknown card type %d", card_type);
return(ERROR);
}
+ break;
- }
- else if(ctrl_type == CTRL_DAIC)
- {
+ case CTRL_DAIC:
isdn_ctrl_tab[controller].ctrl_type = ctrl_type;
isdn_ctrl_tab[controller].card_type = card_type;
isdn_ctrl_tab[controller].state = CTRL_DOWN;
- isdn_ctrl_tab[controller].stateb1 = CHAN_IDLE;
- isdn_ctrl_tab[controller].stateb2 = CHAN_IDLE;
- isdn_ctrl_tab[controller].freechans = MAX_CHANCTRL;
- isdn_ctrl_tab[controller].tei = tei;
- isdn_ctrl_tab[controller].l1stat = LAYER_IDLE;
- isdn_ctrl_tab[controller].l2stat = LAYER_IDLE;
+ break;
- log(LL_DMN, "init_controller_state: controller %d is %s",
- controller,
- name_of_controller(isdn_ctrl_tab[controller].ctrl_type,
- isdn_ctrl_tab[controller].card_type));
- }
- else if(ctrl_type == CTRL_TINADD)
- {
+ case CTRL_TINADD:
isdn_ctrl_tab[controller].ctrl_type = ctrl_type;
isdn_ctrl_tab[controller].card_type = 0;
isdn_ctrl_tab[controller].state = CTRL_DOWN;
- isdn_ctrl_tab[controller].stateb1 = CHAN_IDLE;
- isdn_ctrl_tab[controller].stateb2 = CHAN_IDLE;
- isdn_ctrl_tab[controller].freechans = MAX_CHANCTRL;
+ break;
+
+ case CTRL_CAPI:
+ isdn_ctrl_tab[controller].ctrl_type = ctrl_type;
+ isdn_ctrl_tab[controller].card_type = card_type;
+ isdn_ctrl_tab[controller].state = CTRL_UP;
+ break;
+
+ default:
+ log(LL_ERR, "init_controller_state: unknown controller type %d", ctrl_type);
+ return(ERROR);
+ }
+
+ isdn_ctrl_tab[controller].nbch = nbch;
+ isdn_ctrl_tab[controller].freechans = nbch;
+ for (i = 0; i < nbch; i++)
+ isdn_ctrl_tab[controller].stateb[i] = CHAN_IDLE;
isdn_ctrl_tab[controller].tei = tei;
isdn_ctrl_tab[controller].l1stat = LAYER_IDLE;
isdn_ctrl_tab[controller].l2stat = LAYER_IDLE;
@@ -221,17 +231,11 @@ init_controller_state(int controller, int ctrl_type, int card_type, int tei)
name_of_controller(isdn_ctrl_tab[controller].ctrl_type,
isdn_ctrl_tab[controller].card_type));
- }
- else
- {
- log(LL_ERR, "init_controller_state: unknown controller type %d", ctrl_type);
- return(ERROR);
- }
return(GOOD);
}
/*--------------------------------------------------------------------------*
- * init active controller
+ * init active or capi controller
*--------------------------------------------------------------------------*/
void
init_active_controller(void)
@@ -255,6 +259,54 @@ init_active_controller(void)
do_exit(1);
}
}
+
+ /*
+ * Generic microcode loading. If a controller has
+ * defined a microcode file, load it using the
+ * I4B_CTRL_DOWNLOAD ioctl.
+ */
+
+ if(isdn_ctrl_tab[controller].firmware != NULL)
+ {
+ int fd, ret;
+ struct isdn_dr_prot idp;
+ struct isdn_download_request idr;
+
+ fd = open(isdn_ctrl_tab[controller].firmware, O_RDONLY);
+ if (fd < 0) {
+ log(LL_ERR, "init_active_controller %d: open %s: %s!",
+ controller, isdn_ctrl_tab[controller].firmware,
+ strerror(errno));
+ do_exit(1);
+ }
+
+ idp.bytecount = lseek(fd, 0, SEEK_END);
+ idp.microcode = mmap(0, idp.bytecount, PROT_READ,
+ MAP_SHARED, fd, 0);
+ if (idp.microcode == MAP_FAILED) {
+ log(LL_ERR, "init_active_controller %d: mmap %s: %s!",
+ controller, isdn_ctrl_tab[controller].firmware,
+ strerror(errno));
+ do_exit(1);
+ }
+
+ DBGL(DL_RCCF, (log(LL_DBG, "init_active_controller %d: loading firmware from [%s]", controller, isdn_ctrl_tab[controller].firmware)));
+
+ idr.controller = controller;
+ idr.numprotos = 1;
+ idr.protocols = &idp;
+
+ ret = ioctl(isdnfd, I4B_CTRL_DOWNLOAD, &idr, sizeof(idr));
+ if (ret) {
+ log(LL_ERR, "init_active_controller %d: load %s: %s!",
+ controller, isdn_ctrl_tab[controller].firmware,
+ strerror(errno));
+ do_exit(1);
+ }
+
+ munmap(idp.microcode, idp.bytecount);
+ close(fd);
+ }
}
}
@@ -359,7 +411,7 @@ incr_free_channels(int controller)
log(LL_ERR, "incr_free_channels: invalid controller number [%d]!", controller);
return(ERROR);
}
- if(isdn_ctrl_tab[controller].freechans < MAX_CHANCTRL)
+ if(isdn_ctrl_tab[controller].freechans < isdn_ctrl_tab[controller].nbch)
{
(isdn_ctrl_tab[controller].freechans)++;
DBGL(DL_CNST, (log(LL_DBG, "incr_free_channels: ctrl %d, now %d chan free", controller, isdn_ctrl_tab[controller].freechans)));
@@ -367,7 +419,7 @@ incr_free_channels(int controller)
}
else
{
- log(LL_ERR, "incr_free_channels: controller [%d] already 2 free chans!", controller);
+ log(LL_ERR, "incr_free_channels: controller [%d] already %d free chans!", controller, isdn_ctrl_tab[controller].nbch);
return(ERROR);
}
}
@@ -399,36 +451,20 @@ set_channel_busy(int controller, int channel)
return(ERROR);
}
- switch(channel)
- {
- case CHAN_B1:
- if(isdn_ctrl_tab[controller].stateb1 == CHAN_RUN)
+ if ((channel < 0) || (channel >= isdn_ctrl_tab[controller].nbch))
{
- DBGL(DL_CNST, (log(LL_DBG, "set_channel_busy: controller [%d] channel B1 already busy!", controller)));
- }
- else
- {
- isdn_ctrl_tab[controller].stateb1 = CHAN_RUN;
- DBGL(DL_CNST, (log(LL_DBG, "set_channel_busy: controller [%d] channel B1 set to BUSY!", controller)));
+ log(LL_ERR, "set_channel_busy: controller [%d] invalid channel [%d]!", controller, channel);
+ return(ERROR);
}
- break;
- case CHAN_B2:
- if(isdn_ctrl_tab[controller].stateb2 == CHAN_RUN)
+ if(isdn_ctrl_tab[controller].stateb[channel] == CHAN_RUN)
{
- DBGL(DL_CNST, (log(LL_DBG, "set_channel_busy: controller [%d] channel B2 already busy!", controller)));
+ DBGL(DL_CNST, (log(LL_DBG, "set_channel_busy: controller [%d] channel B%d already busy!", controller, channel+1)));
}
else
{
- isdn_ctrl_tab[controller].stateb2 = CHAN_RUN;
- DBGL(DL_CNST, (log(LL_DBG, "set_channel_busy: controller [%d] channel B2 set to BUSY!", controller)));
- }
- break;
-
- default:
- log(LL_ERR, "set_channel_busy: controller [%d], invalid channel [%d]!", controller, channel);
- return(ERROR);
- break;
+ isdn_ctrl_tab[controller].stateb[channel] = CHAN_RUN;
+ DBGL(DL_CNST, (log(LL_DBG, "set_channel_busy: controller [%d] channel B%d set to BUSY!", controller, channel+1)));
}
return(GOOD);
}
@@ -445,36 +481,20 @@ set_channel_idle(int controller, int channel)
return(ERROR);
}
- switch(channel)
- {
- case CHAN_B1:
- if(isdn_ctrl_tab[controller].stateb1 == CHAN_IDLE)
- {
- DBGL(DL_CNST, (log(LL_DBG, "set_channel_idle: controller [%d] channel B1 already idle!", controller)));
- }
- else
+ if ((channel < 0) || (channel >= isdn_ctrl_tab[controller].nbch))
{
- isdn_ctrl_tab[controller].stateb1 = CHAN_IDLE;
- DBGL(DL_CNST, (log(LL_DBG, "set_channel_idle: controller [%d] channel B1 set to IDLE!", controller)));
+ log(LL_ERR, "set_channel_busy: controller [%d] invalid channel [%d]!", controller, channel);
+ return(ERROR);
}
- break;
- case CHAN_B2:
- if(isdn_ctrl_tab[controller].stateb2 == CHAN_IDLE)
+ if (isdn_ctrl_tab[controller].stateb[channel] == CHAN_IDLE)
{
- DBGL(DL_CNST, (log(LL_DBG, "set_channel_idle: controller [%d] channel B2 already idle!", controller)));
+ DBGL(DL_CNST, (log(LL_DBG, "set_channel_idle: controller [%d] channel B%d already idle!", controller, channel+1)));
}
else
{
- isdn_ctrl_tab[controller].stateb2 = CHAN_IDLE;
- DBGL(DL_CNST, (log(LL_DBG, "set_channel_idle: controller [%d] channel B2 set to IDLE!", controller)));
- }
- break;
-
- default:
- DBGL(DL_CNST, (log(LL_DBG, "set_channel_idle: controller [%d], invalid channel [%d]!", controller, channel)));
- return(ERROR);
- break;
+ isdn_ctrl_tab[controller].stateb[channel] = CHAN_IDLE;
+ DBGL(DL_CNST, (log(LL_DBG, "set_channel_idle: controller [%d] channel B%d set to IDLE!", controller, channel+1)));
}
return(GOOD);
}
@@ -491,22 +511,13 @@ ret_channel_state(int controller, int channel)
return(ERROR);
}
- switch(channel)
+ if ((channel < 0) || (channel >= isdn_ctrl_tab[controller].nbch))
{
- case CHAN_B1:
- return(isdn_ctrl_tab[controller].stateb1);
- break;
-
- case CHAN_B2:
- return(isdn_ctrl_tab[controller].stateb2);
- break;
-
- default:
- log(LL_ERR, "ret_channel_state: controller [%d], invalid channel [%d]!", controller, channel);
+ log(LL_ERR, "set_channel_busy: controller [%d] invalid channel [%d]!", controller, channel);
return(ERROR);
- break;
}
- return(ERROR);
+
+ return(isdn_ctrl_tab[controller].stateb[channel]);
}
/* EOF */
diff --git a/usr.sbin/i4b/isdnd/isdnd.h b/usr.sbin/i4b/isdnd/isdnd.h
index 64abbd9..fb88546 100644
--- a/usr.sbin/i4b/isdnd/isdnd.h
+++ b/usr.sbin/i4b/isdnd/isdnd.h
@@ -502,21 +502,23 @@ typedef struct cfg_entry {
} cfg_entry_t;
/*---------------------------------------------------------------------------*
- * this struct describes state of controller with 2 b channels
+ * this struct describes state of controller with MAX_BCHAN b channels
*---------------------------------------------------------------------------*/
typedef struct isdn_ctrl_state {
int ctrl_type; /* type: active/passive */
int card_type; /* manufacturer (CARD_XXXX) */
int protocol; /* ISDN D-channel protocol */
+ char* firmware; /* loadable fimrware file name */
+
int state; /* controller state */
#define CTRL_DOWN 0 /* controller inoparable */
#define CTRL_UP 1 /* controller may be used */
- int stateb1; /* B-channel 1 */
- int stateb2; /* B-channel 2 */
+#define MAX_BCHAN 30
+ int stateb[MAX_BCHAN]; /* b channel state */
#define CHAN_IDLE 0 /* channel is free for usage */
#define CHAN_RUN 1 /* channel is occupied */
+ int nbch; /* number of b channels */
int freechans; /* number of unused channels */
-#define MAX_CHANCTRL 2 /* free channels per controller */
int tei; /* tei or -1 if invalid */
int l1stat; /* layer 1 state */
int l2stat; /* layer 2 state */
diff --git a/usr.sbin/i4b/isdnd/isdnd.rc.5 b/usr.sbin/i4b/isdnd/isdnd.rc.5
index 2be90a4..17fbec8 100644
--- a/usr.sbin/i4b/isdnd/isdnd.rc.5
+++ b/usr.sbin/i4b/isdnd/isdnd.rc.5
@@ -1,5 +1,5 @@
.\"
-.\" Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
+.\" Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@@ -22,13 +22,11 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" $Id: isdnd.rc.5,v 1.51 2000/10/09 11:17:07 hm Exp $
-.\"
.\" $FreeBSD$
.\"
-.\" last edit-date: [Mon Oct 9 13:12:29 2000]
+.\" last edit-date: [Mon May 21 11:20:26 2001]
.\"
-.Dd October 9, 2000
+.Dd May 21, 2001
.Dt ISDND.RC 5
.Os
.Sh NAME
@@ -295,6 +293,16 @@ ITU Recommendations Q.921 and Q.931.
.It Ar d64s
An ISDN leased line with a single B-channel (called D64S in Germany).
.El
+.It Li firmware
+This is keyword ist used like firmware=/path/to/file to download the
+firmware to active controllers supported by the
+.Em iavc
+driver (AVM B1, T1). This keyword is supported for all controller types,
+and causes I4B_CTRL_DOWNLOAD ioctl to be invoked with the specified file
+as an argument. In systems equipped with both active and passive adapters,
+and the passive cards being detected first, dummy 'controller' entries
+are required for the passive cards to get the correct firmwares to
+correct adapters.
.El
.It Li entry
This keyword starts one configuration entry.
@@ -380,6 +388,11 @@ and calling back the remote site.
The time in seconds to wait for a remote site calling back the local site
after a call from the local site to the remote site has been made.
(optional)
+.It Li clone
+This causes the contents of the specified entry to be copied from the
+existing named entry to the current one.
+When using this feature at least a new entry specific 'name' and
+'usrdeviceunit' value should be specified for the current entry.
.It Li connectprog
specifies a program run every time after a connection is established and
address negotiation is complete (i.e.: the connection is usable).
@@ -982,7 +995,7 @@ ISDN daemon.
The
.Xr isdnd 8
daemon and this manual page were written by
-.An Hellmuth Michaelis Aq hm@kts.org .
+.An Hellmuth Michaelis Aq hm@freebsd.org .
.Pp
Additions to this manual page by
.An Barry Scott Aq barry@scottb.demon.co.uk .
diff --git a/usr.sbin/i4b/isdnd/monitor.c b/usr.sbin/i4b/isdnd/monitor.c
index 2b73066..bd934d1 100644
--- a/usr.sbin/i4b/isdnd/monitor.c
+++ b/usr.sbin/i4b/isdnd/monitor.c
@@ -941,24 +941,21 @@ static void
hangup_channel(int controller, int channel, const char *source)
{
cfg_entry_t * cep = NULL;
+ int i;
if(controller < ncontroller)
{
if(isdn_ctrl_tab[controller].state != CTRL_UP)
return;
- if(isdn_ctrl_tab[controller].stateb1 != CHAN_IDLE)
+ for (i = 0; i < isdn_ctrl_tab[controller].nbch; i++)
{
- cep = get_cep_by_cc(controller, 0);
- if (cep != NULL && cep->isdnchannelused == channel &&
- cep->isdncontrollerused == controller)
- goto found;
- }
- if(isdn_ctrl_tab[controller].stateb2 != CHAN_IDLE)
+ if(isdn_ctrl_tab[controller].stateb[i] != CHAN_IDLE)
{
- cep = get_cep_by_cc(controller, 1);
+ cep = get_cep_by_cc(controller, i);
if (cep != NULL && cep->isdnchannelused == channel &&
cep->isdncontrollerused == controller)
goto found;
+ }
}
}
/* not found */
diff --git a/usr.sbin/i4b/isdnd/rc_config.c b/usr.sbin/i4b/isdnd/rc_config.c
index 2611743..0b63a09 100644
--- a/usr.sbin/i4b/isdnd/rc_config.c
+++ b/usr.sbin/i4b/isdnd/rc_config.c
@@ -170,6 +170,7 @@ set_config_defaults(void)
for(i=0; i < ncontroller; i++)
{
isdn_ctrl_tab[i].protocol = PROTOCOL_DSS1;
+ isdn_ctrl_tab[i].firmware = NULL;
}
/* entry section cleanup */
@@ -568,6 +569,42 @@ cfg_setval(int keyword)
cfg_entry_tab[entrycount].calledbackwait = yylval.num;
break;
+ case CLONE:
+ /*
+ * clone = <entryname>
+ * Loads the entry from the named, existing one.
+ * Fields such as name and usrdeviceunit should
+ * always be specified after clone as they must be
+ * unique.
+ *
+ * NOTE: all malloc()'d fields must be dup()'d here,
+ * we can't have multiple references to same storage.
+ */
+ for (i = 0; i < entrycount; i++)
+ if (!strcmp(cfg_entry_tab[i].name, yylval.str))
+ break;
+ if (i == entrycount) {
+ log(LL_ERR, "entry %d: clone, unknown entry %s!", entrycount, yylval.str);
+ do_exit(1);
+ }
+
+ DBGL(DL_RCCF, (log(LL_DBG, "entry %d: clone = %s", entrycount, yylval.str)));
+
+ memcpy(&cfg_entry_tab[entrycount], &cfg_entry_tab[i],
+ sizeof(cfg_entry_tab[0]));
+
+ if (cfg_entry_tab[entrycount].answerprog)
+ cfg_entry_tab[entrycount].answerprog = strdup(cfg_entry_tab[entrycount].answerprog);
+ if (cfg_entry_tab[entrycount].budget_callbacks_file)
+ cfg_entry_tab[entrycount].budget_callbacks_file = strdup(cfg_entry_tab[entrycount].budget_callbacks_file);
+ if (cfg_entry_tab[entrycount].budget_callouts_file)
+ cfg_entry_tab[entrycount].budget_callouts_file = strdup(cfg_entry_tab[entrycount].budget_callouts_file);
+ if (cfg_entry_tab[entrycount].connectprog)
+ cfg_entry_tab[entrycount].connectprog = strdup(cfg_entry_tab[entrycount].connectprog);
+ if (cfg_entry_tab[entrycount].disconnectprog)
+ cfg_entry_tab[entrycount].disconnectprog = strdup(cfg_entry_tab[entrycount].disconnectprog);
+ break;
+
case CONNECTPROG:
if((cfg_entry_tab[entrycount].connectprog = malloc(strlen(yylval.str)+1)) == NULL)
{
@@ -657,6 +694,11 @@ cfg_setval(int keyword)
extcallattr = yylval.booln;
break;
+ case FIRMWARE:
+ DBGL(DL_RCCF, (log(LL_DBG, "controller %d: firmware = %s", controllercount, yylval.str)));
+ isdn_ctrl_tab[controllercount].firmware = strdup(yylval.str);
+ break;
+
case HOLIDAYFILE:
strcpy(holidayfile, yylval.str);
DBGL(DL_RCCF, (log(LL_DBG, "system: holidayfile = %s", yylval.str)));
@@ -696,25 +738,20 @@ cfg_setval(int keyword)
break;
case ISDNCHANNEL:
- switch(yylval.num)
+ if (yylval.num == 0 || yylval.num == -1)
{
- case 0:
- case -1:
cfg_entry_tab[entrycount].isdnchannel = CHAN_ANY;
DBGL(DL_RCCF, (log(LL_DBG, "entry %d: isdnchannel = any", entrycount)));
- break;
- case 1:
- cfg_entry_tab[entrycount].isdnchannel = CHAN_B1;
- DBGL(DL_RCCF, (log(LL_DBG, "entry %d: isdnchannel = one", entrycount)));
- break;
- case 2:
- cfg_entry_tab[entrycount].isdnchannel = CHAN_B2;
- DBGL(DL_RCCF, (log(LL_DBG, "entry %d: isdnchannel = two", entrycount)));
- break;
- default:
+ }
+ else if (yylval.num > MAX_BCHAN)
+ {
log(LL_DBG, "entry %d: isdnchannel value out of range", entrycount);
config_error_flag++;
- break;
+ }
+ else
+ {
+ cfg_entry_tab[entrycount].isdnchannel = yylval.num-1;
+ DBGL(DL_RCCF, (log(LL_DBG, "entry %d: isdnchannel = B%d", entrycount, yylval.num)));
}
break;
@@ -1523,11 +1560,8 @@ print_config(void)
case CHAN_ANY:
fprintf(PFILE, "-1\t\t# any ISDN B-channel may be used\n");
break;
- case CHAN_B1:
- fprintf(PFILE, "1\t\t# only ISDN B-channel 1 may be used\n");
- break;
- case CHAN_B2:
- fprintf(PFILE, "2\t\t# only ISDN B-channel 2 ay be used\n");
+ default:
+ fprintf(PFILE, "%d\t\t# only ISDN B-channel %d may be used\n", cep->isdnchannel+1, cep->isdnchannel+1);
break;
}
diff --git a/usr.sbin/i4b/isdnd/rc_parse.y b/usr.sbin/i4b/isdnd/rc_parse.y
index 428adc0..2147325 100644
--- a/usr.sbin/i4b/isdnd/rc_parse.y
+++ b/usr.sbin/i4b/isdnd/rc_parse.y
@@ -1,7 +1,7 @@
/*
* Copyright (c) 1997 Joerg Wunsch. All rights reserved.
*
- * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
+ * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,11 +30,9 @@
* i4b daemon - runtime configuration parser
* -----------------------------------------
*
- * $Id: rc_parse.y,v 1.30 2000/10/09 11:17:07 hm Exp $
- *
* $FreeBSD$
*
- * last edit-date: [Mon Oct 2 22:51:23 2000]
+ * last edit-date: [Mon May 21 11:22:21 2001]
*
*---------------------------------------------------------------------------*/
@@ -94,6 +92,7 @@ int controllercount = -1;
%token CALLIN
%token CALLOUT
%token CHANNELSTATE
+%token CLONE
%token CONNECTPROG
%token CONTROLLER
%token DIALOUTTYPE
@@ -106,6 +105,7 @@ int controllercount = -1;
%token EARLYHANGUP
%token ENTRY
%token EXTCALLATTR
+%token FIRMWARE
%token FULLCMD
%token HOLIDAYFILE
%token IDLETIME_IN
@@ -170,7 +170,7 @@ int controllercount = -1;
%type <num> sysfilekeyword sysnumkeyword sysstrkeyword sysboolkeyword
%type <num> filekeyword numkeyword strkeyword boolkeyword monrights monright
-%type <num> cstrkeyword
+%type <num> cstrkeyword cfilekeyword
%type <str> filename
%union {
@@ -441,6 +441,7 @@ strkeyword: ANSWERPROG { $$ = ANSWERPROG; }
| UNITLENGTHSRC { $$ = UNITLENGTHSRC; }
| USRDEVICENAME { $$ = USRDEVICENAME; }
| VALID { $$ = VALID; }
+ | CLONE { $$ = CLONE; }
;
numkeyword: ALERT { $$ = ALERT; }
@@ -502,10 +503,17 @@ strcontroller: cstrkeyword '=' STRING '\n'
{
cfg_setval($1);
}
+ | cfilekeyword '=' filename '\n'
+ {
+ cfg_setval($1);
+ }
;
cstrkeyword: PROTOCOL { $$ = PROTOCOL; }
;
+cfilekeyword: FIRMWARE { $$ = FIRMWARE; }
+ ;
+
%%
diff --git a/usr.sbin/i4b/isdnd/rc_scan.l b/usr.sbin/i4b/isdnd/rc_scan.l
index 92c5189..c9bfce4 100644
--- a/usr.sbin/i4b/isdnd/rc_scan.l
+++ b/usr.sbin/i4b/isdnd/rc_scan.l
@@ -1,7 +1,7 @@
/*
* Copyright (c) 1997 Joerg Wunsch. All rights reserved.
*
- * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
+ * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,11 +30,9 @@
* i4b daemon - runtime configuration lexical analyzer
* ---------------------------------------------------
*
- * $Id: rc_scan.l,v 1.33 2000/10/09 11:17:07 hm Exp $
- *
* $FreeBSD$
*
- * last edit-date: [Wed Jan 10 10:37:11 2001]
+ * last edit-date: [Mon May 21 11:22:38 2001]
*
*---------------------------------------------------------------------------*/
@@ -105,6 +103,7 @@ budget-calloutsfile { return BUDGETCALLOUTSFILE; }
budget-calloutsfile-rotate { return BUDGETCALLOUTSFILEROTATE; }
callbackwait { return CALLBACKWAIT; }
calledbackwait { return CALLEDBACKWAIT; }
+clone { return CLONE; }
connectprog { return CONNECTPROG; }
controller { return CONTROLLER; }
dialin-reaction { return REACTION; }
@@ -118,6 +117,7 @@ downtime { return DOWNTIME; }
earlyhangup { return EARLYHANGUP; }
entry { return ENTRY; }
extcallattr { return EXTCALLATTR; }
+firmware { return FIRMWARE; }
holidayfile { return HOLIDAYFILE; }
idletime-incoming { return IDLETIME_IN; }
idletime-outgoing { return IDLETIME_OUT; }
diff --git a/usr.sbin/i4b/isdnd/support.c b/usr.sbin/i4b/isdnd/support.c
index b078b0d..f9585c3 100644
--- a/usr.sbin/i4b/isdnd/support.c
+++ b/usr.sbin/i4b/isdnd/support.c
@@ -230,6 +230,8 @@ find_by_device_for_dialoutnumber(int drivertype, int driverunit, int cmdlen, cha
int
setup_dialout(cfg_entry_t *cep)
{
+ int i;
+
/* check controller operational */
if((get_controller_state(cep->isdncontroller)) != CTRL_UP)
@@ -244,19 +246,14 @@ setup_dialout(cfg_entry_t *cep)
switch(cep->isdnchannel)
{
- case CHAN_B1:
- case CHAN_B2:
- if((ret_channel_state(cep->isdncontroller, cep->isdnchannel)) != CHAN_IDLE)
+ case CHAN_ANY:
+ for (i = 0; i < isdn_ctrl_tab[cep->isdncontroller].nbch; i++)
{
- DBGL(DL_MSG, (log(LL_DBG, "setup_dialout: entry %s, channel not free", cep->name)));
- return(ERROR);
- }
- cep->isdnchannelused = cep->isdnchannel;
+ if(ret_channel_state(cep->isdncontroller, i) == CHAN_IDLE)
break;
+ }
- case CHAN_ANY:
- if(((ret_channel_state(cep->isdncontroller, CHAN_B1)) != CHAN_IDLE) &&
- ((ret_channel_state(cep->isdncontroller, CHAN_B2)) != CHAN_IDLE))
+ if (i == isdn_ctrl_tab[cep->isdncontroller].nbch)
{
DBGL(DL_MSG, (log(LL_DBG, "setup_dialout: entry %s, no channel free", cep->name)));
return(ERROR);
@@ -265,8 +262,12 @@ setup_dialout(cfg_entry_t *cep)
break;
default:
- DBGL(DL_MSG, (log(LL_DBG, "setup_dialout: entry %s, channel undefined", cep->name)));
+ if((ret_channel_state(cep->isdncontroller, cep->isdnchannel)) != CHAN_IDLE)
+ {
+ DBGL(DL_MSG, (log(LL_DBG, "setup_dialout: entry %s, channel not free", cep->name)));
return(ERROR);
+ }
+ cep->isdnchannelused = cep->isdnchannel;
break;
}
@@ -460,19 +461,14 @@ find_matching_entry_incoming(msg_connect_ind_t *mp)
switch(mp->channel)
{
- case CHAN_B1:
- case CHAN_B2:
- if((ret_channel_state(mp->controller, mp->channel)) != CHAN_IDLE)
+ case CHAN_ANY:
+ for (i = 0; i < isdn_ctrl_tab[mp->controller].nbch; i++)
{
- log(LL_CHD, "%05d %s incoming call, channel %s not free!",
- mp->header.cdid, cep->name, mp->channel == CHAN_B1 ? "B1" : "B2");
- return(NULL);
- }
+ if(ret_channel_state(mp->controller, i) == CHAN_IDLE)
break;
+ }
- case CHAN_ANY:
- if(((ret_channel_state(mp->controller, CHAN_B1)) != CHAN_IDLE) &&
- ((ret_channel_state(mp->controller, CHAN_B2)) != CHAN_IDLE))
+ if (i == isdn_ctrl_tab[mp->controller].nbch)
{
log(LL_CHD, "%05d %s incoming call, no channel free!",
mp->header.cdid, cep->name);
@@ -487,9 +483,12 @@ find_matching_entry_incoming(msg_connect_ind_t *mp)
break;
default:
- log(LL_CHD, "%05d %s incoming call, ERROR, channel undefined!",
- mp->header.cdid, cep->name);
+ if((ret_channel_state(mp->controller, mp->channel)) != CHAN_IDLE)
+ {
+ log(LL_CHD, "%05d %s incoming call, channel B%d not free!",
+ mp->header.cdid, cep->name, mp->channel+1);
return(NULL);
+ }
break;
}
@@ -569,7 +568,7 @@ get_cep_by_cc(int ctrlr, int chan)
{
int i;
- if((chan != CHAN_B1) && (chan != CHAN_B2))
+ if((chan < 0) || (chan >= isdn_ctrl_tab[ctrlr].nbch))
return(NULL);
for(i=0; i < nentries; i++)
@@ -724,7 +723,7 @@ unitlen_chkupd(cfg_entry_t *cep)
void
close_allactive(void)
{
- int i, j;
+ int i, j, k;
cfg_entry_t *cep = NULL;
j = 0;
@@ -734,25 +733,11 @@ close_allactive(void)
if((get_controller_state(i)) != CTRL_UP)
continue;
- if((ret_channel_state(i, CHAN_B1)) == CHAN_RUN)
+ for (k = 0; k < isdn_ctrl_tab[i].nbch; k++)
{
- if((cep = get_cep_by_cc(i, CHAN_B1)) != NULL)
+ if((ret_channel_state(i, k)) == CHAN_RUN)
{
-#ifdef USE_CURSES
- if(do_fullscreen)
- display_disconnect(cep);
-#endif
-#ifdef I4B_EXTERNAL_MONITOR
- monitor_evnt_disconnect(cep);
-#endif
- next_state(cep, EV_DRQ);
- j++;
- }
- }
-
- if((ret_channel_state(i, CHAN_B2)) == CHAN_RUN)
- {
- if((cep = get_cep_by_cc(i, CHAN_B2)) != NULL)
+ if((cep = get_cep_by_cc(i, k)) != NULL)
{
#ifdef USE_CURSES
if(do_fullscreen)
@@ -764,6 +749,7 @@ close_allactive(void)
next_state(cep, EV_DRQ);
j++;
}
+ }
}
}
diff --git a/usr.sbin/i4b/isdndebug/main.c b/usr.sbin/i4b/isdndebug/main.c
index 89a8910..0620b3b 100644
--- a/usr.sbin/i4b/isdndebug/main.c
+++ b/usr.sbin/i4b/isdndebug/main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
+ * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,11 +27,9 @@
* main.c - i4b set debug options
* ------------------------------
*
- * $Id: main.c,v 1.27 2000/07/24 12:22:08 hm Exp $
- *
* $FreeBSD$
*
- * last edit-date: [Thu Oct 26 08:50:30 2000]
+ * last edit-date: [Mon May 21 10:09:23 2001]
*
*---------------------------------------------------------------------------*/
@@ -617,19 +615,18 @@ void
printl4(unsigned long val)
{
printf("\nLayer 4: %s = 0x%lX\n", bin_str(val, 32), val);
- printf(" |||| |||| ||||\n"),
- printf(" |||| |||| |||+- general error messages\n");
- printf(" |||| |||| ||+-- general messages\n");
- printf(" |||| |||| |+--- B-ch timeout messages\n");
- printf(" |||| |||| +---- network driver dial state\n");
- printf(" |||| |||+------ ipr driver debug messages\n");
- printf(" |||| ||+------- rbch driver debug messages\n");
- printf(" |||| |+-------- isp driver debug messages\n");
- printf(" |||| +--------- tel driver debug messages\n");
- printf(" |||+----------- tina driver debug messages\n");
- printf(" ||+------------ tina driver messages\n");
- printf(" |+------------- tina driver error messages\n");
- printf(" +-------------- ing driver debug messages\n");
+ printf(" ||| |||| ||||\n"),
+ printf(" ||| |||| |||+- general error messages\n");
+ printf(" ||| |||| ||+-- general messages\n");
+ printf(" ||| |||| |+--- B-ch timeout messages\n");
+ printf(" ||| |||| +---- network driver dial state\n");
+ printf(" ||| |||+------ ipr driver debug messages\n");
+ printf(" ||| ||+------- rbch driver debug messages\n");
+ printf(" ||| |+-------- isp driver debug messages\n");
+ printf(" ||| +--------- tel driver debug messages\n");
+ printf(" ||+----------- ing driver debug messages\n");
+ printf(" |+------------ iavc driver debug messages\n");
+ printf(" +------------- capi driver debug messages\n");
printf(" ++++-++++-++++-++++-++++---------------- unassigned\n");
}
diff --git a/usr.sbin/i4b/man/Makefile b/usr.sbin/i4b/man/Makefile
index 2600080..f75cd6b 100644
--- a/usr.sbin/i4b/man/Makefile
+++ b/usr.sbin/i4b/man/Makefile
@@ -1,6 +1,7 @@
# $FreeBSD$
MAN = i4b.4 i4bctl.4 i4bipr.4 i4bq921.4 i4bq931.4 i4brbch.4 i4btel.4 \
- i4btrc.4 isic.4 i4bisppp.4 iwic.4 ifpi.4 ifpnp.4 ihfc.4 itjc.4
+ i4btrc.4 isic.4 i4bisppp.4 iwic.4 ifpi.4 ifpnp.4 ihfc.4 itjc.4 \
+ i4bcapi.4 iavc.4
.include <bsd.prog.mk>
diff --git a/usr.sbin/i4b/man/i4bcapi.4 b/usr.sbin/i4b/man/i4bcapi.4
new file mode 100644
index 0000000..3539b03
--- /dev/null
+++ b/usr.sbin/i4b/man/i4bcapi.4
@@ -0,0 +1,55 @@
+.\"
+.\" Copyright (c) 2001 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.\" last edit-date: [Fri May 25 09:38:45 2001]
+.\"
+.Dd May 21, 2001
+.Dt I4BCAPI 4
+.Os
+.Sh NAME
+.Nm i4bcapi
+.Nd CAPI driver for the isdn4bsd kernel part
+.Sh SYNOPSIS
+.Cd device \&"i4bcapi\&"
+.Sh DESCRIPTION
+.Nm
+is a CAPI driver for the
+.Em isdn4bsd
+package. It sits between layer 4 of isdn4bsd and a driver for an active
+ISDN card; currently only the
+.Xr iavc 4
+driver for the AVM B1 and T1 family of active cards is supported.
+.Sh STANDARDS
+CAPI 2.0 (http://www.capi.org/)
+.Sh SEE ALSO
+.Xr iavc 4
+.Sh AUTHORS
+The
+.Nm
+device driver was written by
+.An Juha-Matti Liukkonen (Cubical Solutions Ltd, Finnland) Aq jml@cubical.fi .
+This manpage was written by
+.An Hellmuth Michaelis Aq hm@freebsd.org .
diff --git a/usr.sbin/i4b/man/iavc.4 b/usr.sbin/i4b/man/iavc.4
new file mode 100644
index 0000000..7c68d1d
--- /dev/null
+++ b/usr.sbin/i4b/man/iavc.4
@@ -0,0 +1,67 @@
+.\"
+.\" Copyright (c) 2001 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.\" last edit-date: [Fri May 25 09:45:35 2001]
+.\"
+.Dd May 22, 2001
+.Dt IAVC 4
+.Os
+.Sh NAME
+.Nm iavc
+.Nd isdn4bsd AVM B1/T1 driver
+.Sh SYNOPSIS
+.Cd "device iavc"
+.Pp
+NOTE:
+For the B1 ISA card
+.Pp
+.Dl hint.iavc.0.at="isa"
+.Dl hint.iavc.0.port="0x150"
+.Dl hint.iavc.0.irq="5"
+.Pp
+must be added to
+.Pa /boot/device.hints
+.Pp
+.Sh DESCRIPTION
+The
+.Nm
+driver is used to access the AVM family of active cards to the
+.Xr i4bcapi 4
+driver and the
+.Em isdn4bsd
+package. Currently the AVM B1 PCI, the AVM B1 ISA and the AVM T1 PCI
+cards are supported.
+.Sh STANDARDS
+CAPI 2.0 (http://www.capi.org/)
+.Sh SEE ALSO
+.Xr i4bcapi 4
+.Sh AUTHORS
+The
+.Nm
+device driver was written by
+.An Juha-Matti Liukkonen (Cubical Solutions Ltd, Finnland) Aq jml@cubical.fi .
+This manpage was written by
+.An Hellmuth Michaelis Aq hm@freebsd.org .
OpenPOWER on IntegriCloud