summaryrefslogtreecommitdiffstats
path: root/sys/i4b/capi/iavc/iavc_lli.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/i4b/capi/iavc/iavc_lli.c')
-rw-r--r--sys/i4b/capi/iavc/iavc_lli.c834
1 files changed, 834 insertions, 0 deletions
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
OpenPOWER on IntegriCloud