2 * Copyright (c) 2001 Cubical Solutions Ltd. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * capi/iavc/iavc_lli.c
26 * The AVM ISDN controllers' Low Level Interface.
28 * $FreeBSD: src/sys/i4b/capi/iavc/iavc_lli.c,v 1.2.2.1 2001/08/10 14:08:34 obrien Exp $
29 * $DragonFly: src/sys/net/i4b/capi/iavc/iavc_lli.c,v 1.2 2003/06/17 04:28:39 dillon Exp $
36 #if (NIAVC > 0) && (NI4BCAPI > 0)
38 #include <sys/param.h>
39 #include <sys/kernel.h>
40 #include <sys/systm.h>
42 #include <sys/socket.h>
43 #include <sys/malloc.h>
46 #include <machine/clock.h>
48 #include <machine/bus.h>
54 #include <machine/i4b_debug.h>
55 #include <machine/i4b_ioctl.h>
56 #include <machine/i4b_trace.h>
58 #include <i4b/include/i4b_global.h>
59 #include <i4b/include/i4b_l3l4.h>
60 #include <i4b/include/i4b_mbuf.h>
62 #include <i4b/capi/capi.h>
63 #include <i4b/capi/capi_msgs.h>
65 #include <i4b/capi/iavc/iavc.h>
67 /* Forward declarations of local subroutines... */
69 static int iavc_send_init(iavc_softc_t *);
71 static void iavc_handle_rx(iavc_softc_t *);
72 static void iavc_start_tx(iavc_softc_t *);
75 // Callbacks from the upper (capi) layer:
76 // --------------------------------------
79 // Resets the board and loads the firmware, then initiates
83 // Registers a CAPI application id.
86 // Releases a CAPI application id.
89 // Sends a capi message.
92 int iavc_load(capi_softc_t *capi_sc, int len, u_int8_t *cp)
94 iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
98 printf("iavc%d: reset card ....\n", sc->sc_unit);
101 b1dma_reset(sc); /* PCI cards */
103 t1_reset(sc); /* ISA attachment T1 */
105 b1_reset(sc); /* ISA attachment B1 */
110 printf("iavc%d: start loading %d bytes firmware ....\n", sc->sc_unit, len);
112 while (len && b1io_save_put_byte(sc, *cp++) == 0)
116 printf("iavc%d: loading failed, can't write to card, len = %d\n",
122 printf("iavc%d: firmware loaded, wait for ACK ....\n", sc->sc_unit);
124 if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA)
125 iavc_put_byte(sc, SEND_POLL);
127 iavc_put_byte(sc, SEND_POLLACK);
129 for (len = 0; len < 1000 && !iavc_rx_full(sc); len++)
132 if (!iavc_rx_full(sc)) {
133 printf("iavc%d: loading failed, no ack\n", sc->sc_unit);
137 val = iavc_get_byte(sc);
139 if ((sc->sc_dma && val != RECEIVE_POLLDWORD) ||
140 (!sc->sc_dma && val != RECEIVE_POLL)) {
141 printf("iavc%d: loading failed, bad ack = %02x\n", sc->sc_unit, val);
146 printf("iavc%d: got ACK = 0x%02x\n", sc->sc_unit, val);
149 /* Start the DMA engine */
153 sc->sc_csr = AVM_FLAG;
154 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
155 AMCC_WRITE(sc, AMCC_MCSR, (EN_A2P_TRANSFERS|EN_P2A_TRANSFERS|
156 A2P_HI_PRIORITY|P2A_HI_PRIORITY|
157 RESET_A2P_FLAGS|RESET_P2A_FLAGS));
159 iavc_write_port(sc, 0x07, 0x30); /* XXX magic numbers from */
160 iavc_write_port(sc, 0x10, 0xf0); /* XXX the linux driver */
163 AMCC_WRITE(sc, AMCC_RXPTR, vtophys(&sc->sc_recvbuf[0]));
164 AMCC_WRITE(sc, AMCC_RXLEN, 4);
165 sc->sc_csr |= EN_RX_TC_INT|EN_TX_TC_INT;
166 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
171 if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA)
179 int iavc_register(capi_softc_t *capi_sc, int applid, int nchan)
181 iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
182 struct mbuf *m = i4b_Dgetmbuf(23);
186 printf("iavc%d: can't get memory\n", sc->sc_unit);
191 * byte 0x12 = SEND_REGISTER
194 * dword NumB3Connections 0..nbch
199 p = amcc_put_byte(mtod(m, u_int8_t*), 0);
200 p = amcc_put_byte(p, 0);
201 p = amcc_put_byte(p, SEND_REGISTER);
202 p = amcc_put_word(p, applid);
204 p = amcc_put_word(p, 1024 + (nchan + 1));
206 p = amcc_put_word(p, 1024 * (nchan + 1));
208 p = amcc_put_word(p, nchan);
209 p = amcc_put_word(p, 8);
210 p = amcc_put_word(p, 2048);
212 _IF_ENQUEUE(&sc->sc_txq, m);
219 int iavc_release(capi_softc_t *capi_sc, int applid)
221 iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
222 struct mbuf *m = i4b_Dgetmbuf(7);
226 printf("iavc%d: can't get memory\n", sc->sc_unit);
231 * byte 0x14 = SEND_RELEASE
235 p = amcc_put_byte(mtod(m, u_int8_t*), 0);
236 p = amcc_put_byte(p, 0);
237 p = amcc_put_byte(p, SEND_RELEASE);
238 p = amcc_put_word(p, applid);
240 _IF_ENQUEUE(&sc->sc_txq, m);
246 int iavc_send(capi_softc_t *capi_sc, struct mbuf *m)
248 iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
250 if (sc->sc_state != IAVC_UP) {
251 printf("iavc%d: attempt to send before device up\n", sc->sc_unit);
253 if (m->m_next) i4b_Bfreembuf(m->m_next);
259 if (_IF_QFULL(&sc->sc_txq)) {
260 #if defined (__FreeBSD__) && __FreeBSD__ > 4
261 _IF_DROP(&sc->sc_txq);
263 IF_DROP(&sc->sc_txq);
266 printf("iavc%d: tx overflow, message dropped\n", sc->sc_unit);
268 if (m->m_next) i4b_Bfreembuf(m->m_next);
272 _IF_ENQUEUE(&sc->sc_txq, m);
281 // Functions called by ourself during the initialization sequence:
282 // ---------------------------------------------------------------
285 // Sends the system initialization message to a newly loaded
286 // board, and sets state to INIT.
289 static int iavc_send_init(iavc_softc_t *sc)
291 struct mbuf *m = i4b_Dgetmbuf(15);
296 printf("iavc%d: can't get memory\n", sc->sc_unit);
301 * byte 0x11 = SEND_INIT
302 * dword NumApplications
307 p = amcc_put_byte(mtod(m, u_int8_t*), 0);
308 p = amcc_put_byte(p, 0);
309 p = amcc_put_byte(p, SEND_INIT);
310 p = amcc_put_word(p, 1); /* XXX MaxAppl XXX */
311 p = amcc_put_word(p, sc->sc_capi.sc_nbch);
312 p = amcc_put_word(p, sc->sc_unit);
315 _IF_ENQUEUE(&sc->sc_txq, m);
319 sc->sc_state = IAVC_INIT;
325 // Functions called during normal operation:
326 // -----------------------------------------
329 // Reads the initialization reply and calls capi_ll_control().
331 // iavc_receive_new_ncci
332 // Reads a new NCCI notification and calls capi_ll_control().
334 // iavc_receive_free_ncci
335 // Reads a freed NCCI notification and calls capi_ll_control().
337 // iavc_receive_task_ready
338 // Reads a task ready message -- which should not occur XXX.
340 // iavc_receive_debugmsg
341 // Reads a debug message -- which should not occur XXX.
343 // iavc_receive_start
344 // Reads a START TRANSMIT message and unblocks device.
347 // Reads a STOP TRANSMIT message and blocks device.
350 // Reads an incoming message and calls capi_ll_receive().
353 static int iavc_receive_init(iavc_softc_t *sc, u_int8_t *dmabuf)
357 u_int8_t *cardtype, *serial, *profile, *version, *caps, *prot;
360 p = amcc_get_word(dmabuf, &Length);
362 Length = iavc_get_slice(sc, sc->sc_recvbuf);
369 printf("iavc%d: rx_init: ", sc->sc_unit);
370 while (len < Length) {
371 printf(" %02x", p[len]);
372 if (len && (len % 16) == 0) printf("\n");
375 if (len % 16) printf("\n");
380 p += (*p + 1); /* driver version */
382 p += (*p + 1); /* card type */
383 p += (*p + 1); /* hardware ID */
385 p += (*p + 1); /* serial number */
387 p += (*p + 1); /* supported options */
389 p += (*p + 1); /* supported protocols */
392 if (cardtype && serial && profile) {
393 int nbch = ((profile[3]<<8) | profile[2]);
395 printf("iavc%d: AVM %s, s/n %s, %d chans, f/w rev %s, prot %s\n",
396 sc->sc_unit, cardtype, serial, nbch, version, prot);
399 printf("iavc%d: %s\n", sc->sc_unit, caps);
401 capi_ll_control(&sc->sc_capi, CAPI_CTRL_PROFILE, (int) profile);
404 printf("iavc%d: no profile data in info response?\n", sc->sc_unit);
407 sc->sc_blocked = TRUE; /* controller will send START when ready */
411 static int iavc_receive_start(iavc_softc_t *sc, u_int8_t *dmabuf)
413 struct mbuf *m = i4b_Dgetmbuf(3);
416 if (sc->sc_blocked && sc->sc_state == IAVC_UP)
417 printf("iavc%d: receive_start\n", sc->sc_unit);
420 printf("iavc%d: can't get memory\n", sc->sc_unit);
425 * byte 0x73 = SEND_POLLACK
428 p = amcc_put_byte(mtod(m, u_int8_t*), 0);
429 p = amcc_put_byte(p, 0);
430 p = amcc_put_byte(p, SEND_POLLACK);
432 _IF_PREPEND(&sc->sc_txq, m);
434 NDBGL4(L4_IAVCDBG, "iavc%d: blocked = %d, state = %d",
435 sc->sc_unit, sc->sc_blocked, sc->sc_state);
437 sc->sc_blocked = FALSE;
440 /* If this was our first START, register our readiness */
442 if (sc->sc_state != IAVC_UP) {
443 sc->sc_state = IAVC_UP;
444 capi_ll_control(&sc->sc_capi, CAPI_CTRL_READY, TRUE);
450 static int iavc_receive_stop(iavc_softc_t *sc, u_int8_t *dmabuf)
452 printf("iavc%d: receive_stop\n", sc->sc_unit);
453 sc->sc_blocked = TRUE;
457 static int iavc_receive_new_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
459 u_int32_t ApplId, NCCI, WindowSize;
462 dmabuf = amcc_get_word(dmabuf, &ApplId);
463 dmabuf = amcc_get_word(dmabuf, &NCCI);
464 dmabuf = amcc_get_word(dmabuf, &WindowSize);
466 ApplId = iavc_get_word(sc);
467 NCCI = iavc_get_word(sc);
468 WindowSize = iavc_get_word(sc);
471 capi_ll_control(&sc->sc_capi, CAPI_CTRL_NEW_NCCI, NCCI);
475 static int iavc_receive_free_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
477 u_int32_t ApplId, NCCI;
480 dmabuf = amcc_get_word(dmabuf, &ApplId);
481 dmabuf = amcc_get_word(dmabuf, &NCCI);
483 ApplId = iavc_get_word(sc);
484 NCCI = iavc_get_word(sc);
487 capi_ll_control(&sc->sc_capi, CAPI_CTRL_FREE_NCCI, NCCI);
491 static int iavc_receive_task_ready(iavc_softc_t *sc, u_int8_t *dmabuf)
493 u_int32_t TaskId, Length;
495 printf("iavc%d: receive_task_ready\n", sc->sc_unit);
498 p = amcc_get_word(dmabuf, &TaskId);
499 p = amcc_get_word(p, &Length);
501 TaskId = iavc_get_word(sc);
502 Length = iavc_get_slice(sc, sc->sc_recvbuf);
506 /* XXX could show the message if trace enabled? XXX */
510 static int iavc_receive_debugmsg(iavc_softc_t *sc, u_int8_t *dmabuf)
514 printf("iavc%d: receive_debugmsg\n", sc->sc_unit);
517 p = amcc_get_word(dmabuf, &Length);
519 Length = iavc_get_slice(sc, sc->sc_recvbuf);
523 /* XXX could show the message if trace enabled? XXX */
527 static int iavc_receive(iavc_softc_t *sc, u_int8_t *dmabuf, int b3data)
530 u_int32_t ApplId, Length;
533 * byte 0x21 = RECEIVE_MESSAGE
540 * byte 0x22 = RECEIVE_DATA_B3_IND
549 dmabuf = amcc_get_word(dmabuf, &ApplId);
550 dmabuf = amcc_get_word(dmabuf, &Length);
552 ApplId = iavc_get_word(sc);
553 Length = iavc_get_slice(sc, sc->sc_recvbuf);
554 dmabuf = sc->sc_recvbuf;
557 m = i4b_Dgetmbuf(Length);
559 printf("iavc%d: can't get memory for receive\n", sc->sc_unit);
563 bcopy(dmabuf, mtod(m, u_int8_t*), Length);
567 u_int8_t *p = mtod(m, u_int8_t*);
569 printf("iavc%d: applid=%d, len=%d\n", sc->sc_unit, ApplId, Length);
570 while (len < m->m_len) {
571 printf(" %02x", p[len]);
572 if (len && (len % 16) == 0) printf("\n");
575 if (len % 16) printf("\n");
581 dmabuf = amcc_get_word(dmabuf + Length, &Length);
583 Length = iavc_get_slice(sc, sc->sc_recvbuf);
584 dmabuf = sc->sc_recvbuf;
587 m->m_next = i4b_Bgetmbuf(Length);
589 printf("iavc%d: can't get memory for receive\n", sc->sc_unit);
594 bcopy(dmabuf, mtod(m->m_next, u_int8_t*), Length);
597 capi_ll_receive(&sc->sc_capi, m);
603 // Checks device interrupt status and calls iavc_handle_{rx,tx}()
607 // Reads in the command byte and calls the subroutines above.
610 // Initiates DMA on the next queued message if possible.
613 void iavc_handle_intr(iavc_softc_t *sc)
619 while (iavc_rx_full(sc))
624 status = AMCC_READ(sc, AMCC_INTCSR);
625 if ((status & ANY_S5933_INT) == 0)
628 newcsr = sc->sc_csr | (status & ALL_INT);
629 if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
630 if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
631 AMCC_WRITE(sc, AMCC_INTCSR, newcsr);
634 if (status & RX_TC_INT) {
637 if (sc->sc_recvlen == 0) {
638 sc->sc_recvlen = *((u_int32_t*)(&sc->sc_recvbuf[0]));
639 rxlen = (sc->sc_recvlen + 3) & ~3;
640 AMCC_WRITE(sc, AMCC_RXPTR, vtophys(&sc->sc_recvbuf[4]));
641 AMCC_WRITE(sc, AMCC_RXLEN, rxlen);
645 AMCC_WRITE(sc, AMCC_RXPTR, vtophys(&sc->sc_recvbuf[0]));
646 AMCC_WRITE(sc, AMCC_RXLEN, 4);
650 if (status & TX_TC_INT) {
651 sc->sc_csr &= ~EN_TX_TC_INT;
655 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
659 static void iavc_handle_rx(iavc_softc_t *sc)
661 u_int8_t *dmabuf = 0, cmd;
664 dmabuf = amcc_get_byte(&sc->sc_recvbuf[4], &cmd);
666 cmd = iavc_get_byte(sc);
669 NDBGL4(L4_IAVCDBG, "iavc%d: command = 0x%02x", sc->sc_unit, cmd);
672 case RECEIVE_DATA_B3_IND:
673 iavc_receive(sc, dmabuf, TRUE);
676 case RECEIVE_MESSAGE:
677 iavc_receive(sc, dmabuf, FALSE);
680 case RECEIVE_NEW_NCCI:
681 iavc_receive_new_ncci(sc, dmabuf);
684 case RECEIVE_FREE_NCCI:
685 iavc_receive_free_ncci(sc, dmabuf);
689 iavc_receive_start(sc, dmabuf);
693 iavc_receive_stop(sc, dmabuf);
697 iavc_receive_init(sc, dmabuf);
700 case RECEIVE_TASK_READY:
701 iavc_receive_task_ready(sc, dmabuf);
704 case RECEIVE_DEBUGMSG:
705 iavc_receive_debugmsg(sc, dmabuf);
709 printf("iavc%d: unknown msg %02x\n", sc->sc_unit, cmd);
713 static void iavc_start_tx(iavc_softc_t *sc)
719 /* If device has put us on hold, punt. */
721 if (sc->sc_blocked) {
725 /* If using DMA and transmitter busy, punt. */
727 if (sc->sc_dma && (sc->sc_csr & EN_TX_TC_INT)) {
731 /* Else, see if we have messages to send. */
733 _IF_DEQUEUE(&sc->sc_txq, m);
738 /* Have message, will send. */
740 if (CAPIMSG_LEN(m->m_data)) {
741 /* A proper CAPI message, possibly with B3 data */
744 /* Copy message to DMA buffer. */
747 dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_DATA_B3_REQ);
749 dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_MESSAGE);
752 dmabuf = amcc_put_word(dmabuf, m->m_len);
753 bcopy(m->m_data, dmabuf, m->m_len);
755 txlen = 5 + m->m_len;
758 dmabuf = amcc_put_word(dmabuf, m->m_next->m_len);
759 bcopy(m->m_next->m_data, dmabuf, m->m_next->m_len);
760 txlen += 4 + m->m_next->m_len;
767 iavc_put_byte(sc, SEND_DATA_B3_REQ);
768 NDBGL4(L4_IAVCDBG, "iavc%d: tx SDB3R msg, len = %d", sc->sc_unit, m->m_len);
770 iavc_put_byte(sc, SEND_MESSAGE);
771 NDBGL4(L4_IAVCDBG, "iavc%d: tx SM msg, len = %d", sc->sc_unit, m->m_len);
775 u_int8_t *p = mtod(m, u_int8_t*);
777 for (len = 0; len < m->m_len; len++) {
778 printf(" %02x", *p++);
779 if (len && (len % 16) == 0) printf("\n");
781 if (len % 16) printf("\n");
785 iavc_put_slice(sc, m->m_data, m->m_len);
788 iavc_put_slice(sc, m->m_next->m_data, m->m_next->m_len);
793 /* A board control message to be sent as is */
796 bcopy(m->m_data + 2, &sc->sc_sendbuf[0], m->m_len - 2);
797 txlen = m->m_len - 2;
802 u_int8_t *p = mtod(m, u_int8_t*) + 2;
804 printf("iavc%d: tx BDC msg, len = %d, msg =", sc->sc_unit, m->m_len-2);
805 for (len = 0; len < m->m_len-2; len++) {
806 printf(" %02x", *p++);
807 if (len && (len % 16) == 0) printf("\n");
809 if (len % 16) printf("\n");
813 txlen = m->m_len - 2;
814 dmabuf = mtod(m, char*) + 2;
816 b1io_put_byte(sc, *dmabuf++);
821 i4b_Bfreembuf(m->m_next);
827 /* Start transmitter */
829 txlen = (txlen + 3) & ~3;
830 AMCC_WRITE(sc, AMCC_TXPTR, vtophys(&sc->sc_sendbuf[0]));
831 AMCC_WRITE(sc, AMCC_TXLEN, txlen);
832 sc->sc_csr |= EN_TX_TC_INT;
835 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);