summaryrefslogtreecommitdiffstats
path: root/sys/i4b
diff options
context:
space:
mode:
authorhm <hm@FreeBSD.org>2001-05-25 08:43:30 +0000
committerhm <hm@FreeBSD.org>2001-05-25 08:43:30 +0000
commit7e6e58c4c7f91947ec1f9a10a284f8d9c2fdf1f2 (patch)
tree6b2ce85b45dc25104f9a4e60d014db8fc3de9b95 /sys/i4b
parent8094d979ca0adb982d9e0c5482a2825da1b38e11 (diff)
downloadFreeBSD-src-7e6e58c4c7f91947ec1f9a10a284f8d9c2fdf1f2.zip
FreeBSD-src-7e6e58c4c7f91947ec1f9a10a284f8d9c2fdf1f2.tar.gz
Submitted by: Juha-Matti Liukkonen (Cubical Solutions Ltd) (jml@cubical.fi)
Add a CAPI (hardware independent) driver i4bcapi(4) and hardware driver iavc (4) to support active CAPI-based BRI and PRI cards (currently AVM B1 and T1 cards) to isdn4bsd.
Diffstat (limited to 'sys/i4b')
-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
18 files changed, 4574 insertions, 35 deletions
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)
OpenPOWER on IntegriCloud