diff options
author | hm <hm@FreeBSD.org> | 2001-05-25 08:43:30 +0000 |
---|---|---|
committer | hm <hm@FreeBSD.org> | 2001-05-25 08:43:30 +0000 |
commit | 7e6e58c4c7f91947ec1f9a10a284f8d9c2fdf1f2 (patch) | |
tree | 6b2ce85b45dc25104f9a4e60d014db8fc3de9b95 /sys/i4b | |
parent | 8094d979ca0adb982d9e0c5482a2825da1b38e11 (diff) | |
download | FreeBSD-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/README | 150 | ||||
-rw-r--r-- | sys/i4b/capi/capi.h | 129 | ||||
-rw-r--r-- | sys/i4b/capi/capi_l4if.c | 450 | ||||
-rw-r--r-- | sys/i4b/capi/capi_llif.c | 166 | ||||
-rw-r--r-- | sys/i4b/capi/capi_msgs.c | 948 | ||||
-rw-r--r-- | sys/i4b/capi/capi_msgs.h | 380 | ||||
-rw-r--r-- | sys/i4b/capi/iavc/iavc.h | 586 | ||||
-rw-r--r-- | sys/i4b/capi/iavc/iavc_card.c | 292 | ||||
-rw-r--r-- | sys/i4b/capi/iavc/iavc_isa.c | 297 | ||||
-rw-r--r-- | sys/i4b/capi/iavc/iavc_lli.c | 834 | ||||
-rw-r--r-- | sys/i4b/capi/iavc/iavc_pci.c | 283 | ||||
-rw-r--r-- | sys/i4b/include/i4b_debug.h | 15 | ||||
-rw-r--r-- | sys/i4b/include/i4b_ioctl.h | 20 | ||||
-rw-r--r-- | sys/i4b/include/i4b_l3l4.h | 6 | ||||
-rw-r--r-- | sys/i4b/layer3/i4b_l3fsm.c | 14 | ||||
-rw-r--r-- | sys/i4b/layer3/i4b_l4if.c | 20 | ||||
-rw-r--r-- | sys/i4b/layer4/i4b_i4bdrv.c | 13 | ||||
-rw-r--r-- | sys/i4b/layer4/i4b_l4.c | 6 |
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, ®, 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, ®, 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) |