The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/iavc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: iavc.c,v 1.7.14.1 2010/12/02 23:42:37 snj Exp $        */
    2 
    3 /*
    4  * Copyright (c) 2001-2003 Cubical Solutions Ltd. All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  *      The AVM ISDN controllers' card specific support routines.
   28  *
   29  * $FreeBSD: src/sys/i4b/capi/iavc/iavc_card.c,v 1.1.2.1 2001/08/10 14:08:34 obrien Exp $
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __KERNEL_RCSID(0, "$NetBSD: iavc.c,v 1.7.14.1 2010/12/02 23:42:37 snj Exp $");
   34 
   35 #include <sys/param.h>
   36 #include <sys/kernel.h>
   37 #include <sys/systm.h>
   38 #include <sys/mbuf.h>
   39 #include <sys/socket.h>
   40 #include <sys/device.h>
   41 #include <sys/callout.h>
   42 #include <sys/reboot.h>
   43 #include <net/if.h>
   44 
   45 #include <sys/bus.h>
   46 
   47 #include <netisdn/i4b_debug.h>
   48 #include <netisdn/i4b_ioctl.h>
   49 #include <netisdn/i4b_trace.h>
   50 #include <netisdn/i4b_global.h>
   51 #include <netisdn/i4b_l3l4.h>
   52 #include <netisdn/i4b_mbuf.h>
   53 #include <netisdn/i4b_capi.h>
   54 #include <netisdn/i4b_capi_msgs.h>
   55 
   56 #include <dev/ic/iavcvar.h>
   57 #include <dev/ic/iavcreg.h>
   58 
   59 /*
   60 //  AVM B1 (active BRI, PIO mode)
   61 */
   62 
   63 int
   64 iavc_b1_detect(iavc_softc_t *sc)
   65 {
   66     if ((iavc_read_port(sc, B1_INSTAT) & 0xfc) ||
   67         (iavc_read_port(sc, B1_OUTSTAT) & 0xfc))
   68         return (1);
   69 
   70     b1io_outp(sc, B1_INSTAT, 0x02);
   71     b1io_outp(sc, B1_OUTSTAT, 0x02);
   72     if ((iavc_read_port(sc, B1_INSTAT) & 0xfe) != 2 ||
   73         (iavc_read_port(sc, B1_OUTSTAT) & 0xfe) != 2)
   74         return (2);
   75 
   76     b1io_outp(sc, B1_INSTAT, 0x00);
   77     b1io_outp(sc, B1_OUTSTAT, 0x00);
   78     if ((iavc_read_port(sc, B1_INSTAT) & 0xfe) ||
   79         (iavc_read_port(sc, B1_OUTSTAT) & 0xfe))
   80         return (3);
   81 
   82     return (0); /* found */
   83 }
   84 
   85 void
   86 iavc_b1_disable_irq(iavc_softc_t *sc)
   87 {
   88     b1io_outp(sc, B1_INSTAT, 0x00);
   89 }
   90 
   91 void
   92 iavc_b1_reset(iavc_softc_t *sc)
   93 {
   94     b1io_outp(sc, B1_RESET, 0);
   95     DELAY(55*2*1000);
   96 
   97     b1io_outp(sc, B1_RESET, 1);
   98     DELAY(55*2*1000);
   99 
  100     b1io_outp(sc, B1_RESET, 0);
  101     DELAY(55*2*1000);
  102 }
  103 
  104 /*
  105 //  Newer PCI-based B1's, and T1's, supports DMA
  106 */
  107 
  108 int
  109 iavc_b1dma_detect(iavc_softc_t *sc)
  110 {
  111     AMCC_WRITE(sc, AMCC_MCSR, 0);
  112     DELAY(10*1000);
  113     AMCC_WRITE(sc, AMCC_MCSR, 0x0f000000);
  114     DELAY(10*1000);
  115     AMCC_WRITE(sc, AMCC_MCSR, 0);
  116     DELAY(42*1000);
  117 
  118     AMCC_WRITE(sc, AMCC_RXLEN, 0);
  119     AMCC_WRITE(sc, AMCC_TXLEN, 0);
  120     sc->sc_csr = 0;
  121     AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
  122 
  123     if (AMCC_READ(sc, AMCC_INTCSR) != 0)
  124         return 1;
  125 
  126     AMCC_WRITE(sc, AMCC_RXPTR, 0xffffffff);
  127     AMCC_WRITE(sc, AMCC_TXPTR, 0xffffffff);
  128     if ((AMCC_READ(sc, AMCC_RXPTR) != 0xfffffffc) ||
  129         (AMCC_READ(sc, AMCC_TXPTR) != 0xfffffffc))
  130         return 2;
  131 
  132     AMCC_WRITE(sc, AMCC_RXPTR, 0);
  133     AMCC_WRITE(sc, AMCC_TXPTR, 0);
  134     if ((AMCC_READ(sc, AMCC_RXPTR) != 0) ||
  135         (AMCC_READ(sc, AMCC_TXPTR) != 0))
  136         return 3;
  137 
  138     iavc_write_port(sc, 0x10, 0x00);
  139     iavc_write_port(sc, 0x07, 0x00);
  140 
  141     iavc_write_port(sc, 0x02, 0x02);
  142     iavc_write_port(sc, 0x03, 0x02);
  143 
  144     if (((iavc_read_port(sc, 0x02) & 0xfe) != 0x02) ||
  145         (iavc_read_port(sc, 0x03) != 0x03))
  146         return 4;
  147 
  148     iavc_write_port(sc, 0x02, 0x00);
  149     iavc_write_port(sc, 0x03, 0x00);
  150 
  151     if (((iavc_read_port(sc, 0x02) & 0xfe) != 0x00) ||
  152         (iavc_read_port(sc, 0x03) != 0x01))
  153         return 5;
  154 
  155     return (0); /* found */
  156 }
  157 
  158 void
  159 iavc_b1dma_reset(iavc_softc_t *sc)
  160 {
  161     int s = splnet();
  162 
  163     sc->sc_csr = 0;
  164     AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
  165     AMCC_WRITE(sc, AMCC_MCSR, 0);
  166     AMCC_WRITE(sc, AMCC_RXLEN, 0);
  167     AMCC_WRITE(sc, AMCC_TXLEN, 0);
  168 
  169     iavc_write_port(sc, 0x10, 0x00); /* XXX magic numbers from */
  170     iavc_write_port(sc, 0x07, 0x00); /* XXX the linux driver */
  171 
  172     splx(s);
  173 
  174     AMCC_WRITE(sc, AMCC_MCSR, 0);
  175     DELAY(10 * 1000);
  176     AMCC_WRITE(sc, AMCC_MCSR, 0x0f000000);
  177     DELAY(10 * 1000);
  178     AMCC_WRITE(sc, AMCC_MCSR, 0);
  179     DELAY(42 * 1000);
  180 }
  181 
  182 /*
  183 //  AVM T1 (active PRI)
  184 */
  185 
  186 #define b1dma_tx_empty(sc) (b1io_read_reg((sc), T1_OUTSTAT) & 1)
  187 #define b1dma_rx_full(sc) (b1io_read_reg((sc), T1_INSTAT) & 1)
  188 
  189 static int b1dma_tolink(iavc_softc_t *sc, void *buf, int len)
  190 {
  191     volatile int spin;
  192     char *s = (char*) buf;
  193     while (len--) {
  194         spin = 0;
  195         while (!b1dma_tx_empty(sc) && spin < 100000)
  196             spin++;
  197         if (!b1dma_tx_empty(sc))
  198             return -1;
  199         t1io_outp(sc, 1, *s++);
  200     }
  201     return 0;
  202 }
  203 
  204 static int b1dma_fromlink(iavc_softc_t *sc, void *buf, int len)
  205 {
  206     volatile int spin;
  207     char *s = (char*) buf;
  208     while (len--) {
  209         spin = 0;
  210         while (!b1dma_rx_full(sc) && spin < 100000)
  211             spin++;
  212         if (!b1dma_rx_full(sc))
  213             return -1;
  214         *s++ = t1io_inp(sc, 0);
  215     }
  216     return 0;
  217 }
  218 
  219 static int WriteReg(iavc_softc_t *sc, u_int32_t reg, u_int8_t val)
  220 {
  221     u_int8_t cmd = 0;
  222     if (b1dma_tolink(sc, &cmd, 1) == 0 &&
  223         b1dma_tolink(sc, &reg, 4) == 0) {
  224         u_int32_t tmp = val;
  225         return b1dma_tolink(sc, &tmp, 4);
  226     }
  227     return -1;
  228 }
  229 
  230 static u_int8_t ReadReg(iavc_softc_t *sc, u_int32_t reg)
  231 {
  232     u_int8_t cmd = 1;
  233     if (b1dma_tolink(sc, &cmd, 1) == 0 &&
  234         b1dma_tolink(sc, &reg, 4) == 0) {
  235         u_int32_t tmp;
  236         if (b1dma_fromlink(sc, &tmp, 4) == 0)
  237             return (u_int8_t) tmp;
  238     }
  239     return 0xff;
  240 }
  241 
  242 int
  243 iavc_t1_detect(iavc_softc_t *sc)
  244 {
  245     int ret = iavc_b1dma_detect(sc);
  246     if (ret) return ret;
  247 
  248     if ((WriteReg(sc, 0x80001000, 0x11) != 0) ||
  249         (WriteReg(sc, 0x80101000, 0x22) != 0) ||
  250         (WriteReg(sc, 0x80201000, 0x33) != 0) ||
  251         (WriteReg(sc, 0x80301000, 0x44) != 0))
  252         return 6;
  253 
  254     if ((ReadReg(sc, 0x80001000) != 0x11) ||
  255         (ReadReg(sc, 0x80101000) != 0x22) ||
  256         (ReadReg(sc, 0x80201000) != 0x33) ||
  257         (ReadReg(sc, 0x80301000) != 0x44))
  258         return 7;
  259 
  260     if ((WriteReg(sc, 0x80001000, 0x55) != 0) ||
  261         (WriteReg(sc, 0x80101000, 0x66) != 0) ||
  262         (WriteReg(sc, 0x80201000, 0x77) != 0) ||
  263         (WriteReg(sc, 0x80301000, 0x88) != 0))
  264         return 8;
  265 
  266     if ((ReadReg(sc, 0x80001000) != 0x55) ||
  267         (ReadReg(sc, 0x80101000) != 0x66) ||
  268         (ReadReg(sc, 0x80201000) != 0x77) ||
  269         (ReadReg(sc, 0x80301000) != 0x88))
  270         return 9;
  271 
  272     return 0; /* found */
  273 }
  274 
  275 void
  276 iavc_t1_disable_irq(iavc_softc_t *sc)
  277 {
  278     iavc_write_port(sc, T1_IRQMASTER, 0x00);
  279 }
  280 
  281 void
  282 iavc_t1_reset(iavc_softc_t *sc)
  283 {
  284     iavc_b1_reset(sc);
  285     iavc_write_port(sc, B1_INSTAT, 0x00);
  286     iavc_write_port(sc, B1_OUTSTAT, 0x00);
  287     iavc_write_port(sc, T1_IRQMASTER, 0x00);
  288     iavc_write_port(sc, T1_RESETBOARD, 0x0f);
  289 }
  290 
  291 /* Forward declarations of local subroutines... */
  292 
  293 static int iavc_send_init(iavc_softc_t *);
  294 
  295 static void iavc_handle_rx(iavc_softc_t *);
  296 static void iavc_start_tx(iavc_softc_t *);
  297 
  298 static uint32_t iavc_tx_capimsg(iavc_softc_t *, struct mbuf *);
  299 static uint32_t iavc_tx_ctrlmsg(iavc_softc_t *, struct mbuf *);
  300 
  301 /*
  302 //  Callbacks from the upper (capi) layer:
  303 //  --------------------------------------
  304 //
  305 //  iavc_load
  306 //      Resets the board and loads the firmware, then initiates
  307 //      board startup.
  308 //
  309 //  iavc_register
  310 //      Registers a CAPI application id.
  311 //
  312 //  iavc_release
  313 //      Releases a CAPI application id.
  314 //
  315 //  iavc_send
  316 //      Sends a capi message.
  317 */
  318 
  319 int iavc_load(capi_softc_t *capi_sc, int len, u_int8_t *cp)
  320 {
  321     iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
  322     u_int8_t val;
  323 
  324     aprint_debug_dev(&sc->sc_dev, "reset card ....\n");
  325 
  326     if (sc->sc_dma)
  327         iavc_b1dma_reset(sc);   /* PCI cards */
  328     else if (sc->sc_t1)
  329         iavc_t1_reset(sc);              /* ISA attachment T1 */
  330     else
  331         iavc_b1_reset(sc);              /* ISA attachment B1 */
  332 
  333     DELAY(1000);
  334 
  335     aprint_debug_dev(&sc->sc_dev, "start loading %d bytes firmware\n", len);
  336 
  337     while (len && b1io_save_put_byte(sc, *cp++) == 0)
  338         len--;
  339 
  340     if (len) {
  341         aprint_error_dev(&sc->sc_dev, "loading failed, can't write to card, len = %d\n", len);
  342         return (EIO);
  343     }
  344 
  345     aprint_debug_dev(&sc->sc_dev, "firmware loaded, wait for ACK\n");
  346 
  347     if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA)
  348             iavc_put_byte(sc, SEND_POLL);
  349     else
  350             iavc_put_byte(sc, SEND_POLLACK);
  351 
  352     for (len = 0; len < 1000 && !iavc_rx_full(sc); len++)
  353         DELAY(100);
  354 
  355     if (!iavc_rx_full(sc)) {
  356         aprint_error_dev(&sc->sc_dev, "loading failed, no ack\n");
  357         return (EIO);
  358     }
  359 
  360     val = iavc_get_byte(sc);
  361 
  362     if ((sc->sc_dma && val != RECEIVE_POLLDWORD) ||
  363       (!sc->sc_dma && val != RECEIVE_POLL)) {
  364         aprint_error_dev(&sc->sc_dev, "loading failed, bad ack = %02x\n", val);
  365         return (EIO);
  366     }
  367 
  368     aprint_debug_dev(&sc->sc_dev, "got ACK = 0x%02x\n", val);
  369 
  370     /* Start the DMA engine */
  371     if (sc->sc_dma) {
  372         int s;
  373 
  374         s = splnet();
  375 
  376         sc->sc_csr = AVM_FLAG;
  377         AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
  378         AMCC_WRITE(sc, AMCC_MCSR, (EN_A2P_TRANSFERS|EN_P2A_TRANSFERS|
  379                                    A2P_HI_PRIORITY|P2A_HI_PRIORITY|
  380                                    RESET_A2P_FLAGS|RESET_P2A_FLAGS));
  381 
  382         iavc_write_port(sc, 0x07, 0x30); /* XXX magic numbers from */
  383         iavc_write_port(sc, 0x10, 0xf0); /* XXX the linux driver */
  384 
  385         bus_dmamap_sync(sc->dmat, sc->rx_map, 0, sc->rx_map->dm_mapsize,
  386           BUS_DMASYNC_PREREAD);
  387 
  388         sc->sc_recv1 = 0;
  389         AMCC_WRITE(sc, AMCC_RXPTR, sc->rx_map->dm_segs[0].ds_addr);
  390         AMCC_WRITE(sc, AMCC_RXLEN, 4);
  391         sc->sc_csr |= EN_RX_TC_INT|EN_TX_TC_INT;
  392         AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
  393 
  394         splx(s);
  395     }
  396 
  397 #ifdef notyet
  398     /* good happy place */
  399     if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA)
  400         b1isa_setup_irq(sc);
  401 #endif
  402 
  403     iavc_send_init(sc);
  404 
  405     return 0;
  406 }
  407 
  408 int iavc_register(capi_softc_t *capi_sc, int applid, int nchan)
  409 {
  410     iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
  411     struct mbuf *m = i4b_Dgetmbuf(23);
  412     u_int8_t *p;
  413 
  414     if (!m) {
  415         aprint_error("iavc%d: can't get memory\n", sc->sc_unit);
  416         return (ENOMEM);
  417     }
  418 
  419     /*
  420      * byte  0x12 = SEND_REGISTER
  421      * dword ApplId
  422      * dword NumMessages
  423      * dword NumB3Connections 0..nbch
  424      * dword NumB3Blocks
  425      * dword B3Size
  426      */
  427 
  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_REGISTER);
  431     p = amcc_put_word(p, applid);
  432 #if 0
  433     p = amcc_put_word(p, 1024 + (nchan + 1));
  434 #else
  435     p = amcc_put_word(p, 1024 * (nchan + 1));
  436 #endif
  437     p = amcc_put_word(p, nchan);
  438     p = amcc_put_word(p, 8);
  439     p = amcc_put_word(p, 2048);
  440 
  441     IF_ENQUEUE(&sc->sc_txq, m);
  442 
  443     iavc_start_tx(sc);
  444 
  445     return 0;
  446 }
  447 
  448 int iavc_release(capi_softc_t *capi_sc, int applid)
  449 {
  450     iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
  451     struct mbuf *m = i4b_Dgetmbuf(7);
  452     u_int8_t *p;
  453 
  454     if (!m) {
  455         aprint_error_dev(&sc->sc_dev, "can't get memory\n");
  456         return (ENOMEM);
  457     }
  458 
  459     /*
  460      * byte  0x14 = SEND_RELEASE
  461      * dword ApplId
  462      */
  463 
  464     p = amcc_put_byte(mtod(m, u_int8_t*), 0);
  465     p = amcc_put_byte(p, 0);
  466     p = amcc_put_byte(p, SEND_RELEASE);
  467     p = amcc_put_word(p, applid);
  468 
  469     IF_ENQUEUE(&sc->sc_txq, m);
  470 
  471     iavc_start_tx(sc);
  472     return 0;
  473 }
  474 
  475 int iavc_send(capi_softc_t *capi_sc, struct mbuf *m)
  476 {
  477     iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
  478 
  479     if (sc->sc_state != IAVC_UP) {
  480         aprint_error_dev(&sc->sc_dev, "attempt to send before device up\n");
  481 
  482         if (m->m_next) i4b_Bfreembuf(m->m_next);
  483         i4b_Dfreembuf(m);
  484 
  485         return (ENXIO);
  486     }
  487 
  488     if (IF_QFULL(&sc->sc_txq)) {
  489         IF_DROP(&sc->sc_txq);
  490 
  491         aprint_error_dev(&sc->sc_dev, "tx overflow, message dropped\n");
  492 
  493         if (m->m_next) i4b_Bfreembuf(m->m_next);
  494         i4b_Dfreembuf(m);
  495 
  496     } else {
  497         IF_ENQUEUE(&sc->sc_txq, m);
  498 
  499         iavc_start_tx(sc);
  500     }
  501 
  502     return 0;
  503 }
  504 
  505 /*
  506 //  Functions called by ourself during the initialization sequence:
  507 //  ---------------------------------------------------------------
  508 //
  509 //  iavc_send_init
  510 //      Sends the system initialization message to a newly loaded
  511 //      board, and sets state to INIT.
  512 */
  513 
  514 static int iavc_send_init(iavc_softc_t *sc)
  515 {
  516     struct mbuf *m = i4b_Dgetmbuf(15);
  517     u_int8_t *p;
  518     int s;
  519 
  520     if (!m) {
  521         aprint_error_dev(&sc->sc_dev, "can't get memory\n");
  522         return (ENOMEM);
  523     }
  524 
  525     /*
  526      * byte  0x11 = SEND_INIT
  527      * dword NumApplications
  528      * dword NumNCCIs
  529      * dword BoardNumber
  530      */
  531 
  532     p = amcc_put_byte(mtod(m, u_int8_t*), 0);
  533     p = amcc_put_byte(p, 0);
  534     p = amcc_put_byte(p, SEND_INIT);
  535     p = amcc_put_word(p, 1); /* XXX MaxAppl XXX */
  536     p = amcc_put_word(p, sc->sc_capi.sc_nbch);
  537     p = amcc_put_word(p, sc->sc_unit);
  538 
  539     s = splnet();
  540     IF_ENQUEUE(&sc->sc_txq, m);
  541 
  542     iavc_start_tx(sc);
  543 
  544     sc->sc_state = IAVC_INIT;
  545     splx(s);
  546     return 0;
  547 }
  548 
  549 /*
  550 //  Functions called during normal operation:
  551 //  -----------------------------------------
  552 //
  553 //  iavc_receive_init
  554 //      Reads the initialization reply and calls capi_ll_control().
  555 //
  556 //  iavc_receive_new_ncci
  557 //      Reads a new NCCI notification and calls capi_ll_control().
  558 //
  559 //  iavc_receive_free_ncci
  560 //      Reads a freed NCCI notification and calls capi_ll_control().
  561 //
  562 //  iavc_receive_task_ready
  563 //      Reads a task ready message -- which should not occur XXX.
  564 //
  565 //  iavc_receive_debugmsg
  566 //      Reads a debug message -- which should not occur XXX.
  567 //
  568 //  iavc_receive_start
  569 //      Reads a START TRANSMIT message and unblocks device.
  570 //
  571 //  iavc_receive_stop
  572 //      Reads a STOP TRANSMIT message and blocks device.
  573 //
  574 //  iavc_receive
  575 //      Reads an incoming message and calls capi_ll_receive().
  576 */
  577 
  578 static int iavc_receive_init(iavc_softc_t *sc, u_int8_t *dmabuf)
  579 {
  580     u_int32_t Length;
  581     u_int8_t *p;
  582     u_int8_t *cardtype, *serial, *profile, *vers, *caps, *prot;
  583 
  584     if (sc->sc_dma) {
  585         p = amcc_get_word(dmabuf, &Length);
  586     } else {
  587         Length = iavc_get_slice(sc, sc->sc_recvbuf);
  588         p = sc->sc_recvbuf;
  589     }
  590 
  591 #if 0
  592     {
  593         int len = 0;
  594         printf("%s: rx_init: ", device_xname(&sc->sc_dev));
  595             while (len < Length) {
  596                 printf(" %02x", p[len]);
  597                 if (len && (len % 16) == 0) printf("\n");
  598                 len++;
  599             }
  600             if (len % 16) printf("\n");
  601     }
  602 #endif
  603 
  604     vers = (p + 1);
  605     p += (*p + 1); /* driver version */
  606     cardtype = (p + 1);
  607     p += (*p + 1); /* card type */
  608     p += (*p + 1); /* hardware ID */
  609     serial = (p + 1);
  610     p += (*p + 1); /* serial number */
  611     caps = (p + 1);
  612     p += (*p + 1); /* supported options */
  613     prot = (p + 1);
  614     p += (*p + 1); /* supported protocols */
  615     profile = (p + 1);
  616 
  617     if (cardtype && serial && profile) {
  618         int nbch = ((profile[3]<<8) | profile[2]);
  619 
  620         aprint_normal_dev(&sc->sc_dev, "AVM %s, s/n %s, %d chans, f/w rev %s, prot %s\n",
  621                 cardtype, serial, nbch, vers, prot);
  622         aprint_verbose_dev(&sc->sc_dev, "%s\n", caps);
  623 
  624         capi_ll_control(&sc->sc_capi, CAPI_CTRL_PROFILE, (int) profile);
  625 
  626     } else {
  627         printf("%s: no profile data in info response?\n", device_xname(&sc->sc_dev));
  628     }
  629 
  630     sc->sc_blocked = 1; /* controller will send START when ready */
  631     return 0;
  632 }
  633 
  634 static int iavc_receive_start(iavc_softc_t *sc)
  635 {
  636     struct mbuf *m = i4b_Dgetmbuf(3);
  637     u_int8_t *p;
  638 
  639     if (sc->sc_blocked && sc->sc_state == IAVC_UP)
  640         printf("%s: receive_start\n", device_xname(&sc->sc_dev));
  641 
  642     if (!m) {
  643         aprint_error_dev(&sc->sc_dev, "can't get memory\n");
  644         return (ENOMEM);
  645     }
  646 
  647     /*
  648      * byte  0x73 = SEND_POLLACK
  649      */
  650 
  651     p = amcc_put_byte(mtod(m, u_int8_t*), 0);
  652     p = amcc_put_byte(p, 0);
  653     p = amcc_put_byte(p, SEND_POLLACK);
  654 
  655     IF_PREPEND(&sc->sc_txq, m);
  656 
  657     NDBGL4(L4_IAVCDBG, "%s: blocked = %d, state = %d",
  658       device_xname(&sc->sc_dev), sc->sc_blocked, sc->sc_state);
  659 
  660     sc->sc_blocked = 0;
  661     iavc_start_tx(sc);
  662 
  663     /* If this was our first START, register our readiness */
  664     if (sc->sc_state != IAVC_UP) {
  665         sc->sc_state = IAVC_UP;
  666         capi_ll_control(&sc->sc_capi, CAPI_CTRL_READY, 1);
  667     }
  668 
  669     return 0;
  670 }
  671 
  672 static int iavc_receive_stop(iavc_softc_t *sc)
  673 {
  674     printf("%s: receive_stop\n", device_xname(&sc->sc_dev));
  675     sc->sc_blocked = 1;
  676     return 0;
  677 }
  678 
  679 static int iavc_receive_new_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
  680 {
  681     u_int32_t ApplId, NCCI, WindowSize;
  682 
  683     if (sc->sc_dma) {
  684         dmabuf = amcc_get_word(dmabuf, &ApplId);
  685         dmabuf = amcc_get_word(dmabuf, &NCCI);
  686         dmabuf = amcc_get_word(dmabuf, &WindowSize);
  687     } else {
  688         ApplId = iavc_get_word(sc);
  689         NCCI   = iavc_get_word(sc);
  690         WindowSize = iavc_get_word(sc);
  691     }
  692 
  693     capi_ll_control(&sc->sc_capi, CAPI_CTRL_NEW_NCCI, NCCI);
  694     return 0;
  695 }
  696 
  697 static int iavc_receive_free_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
  698 {
  699     u_int32_t ApplId, NCCI;
  700 
  701     if (sc->sc_dma) {
  702         dmabuf = amcc_get_word(dmabuf, &ApplId);
  703         dmabuf = amcc_get_word(dmabuf, &NCCI);
  704     } else {
  705         ApplId = iavc_get_word(sc);
  706         NCCI   = iavc_get_word(sc);
  707     }
  708 
  709     capi_ll_control(&sc->sc_capi, CAPI_CTRL_FREE_NCCI, NCCI);
  710     return 0;
  711 }
  712 
  713 static int iavc_receive_task_ready(iavc_softc_t *sc, u_int8_t *dmabuf)
  714 {
  715     u_int32_t TaskId, Length;
  716     u_int8_t *p;
  717     printf("%s: receive_task_ready\n", device_xname(&sc->sc_dev));
  718 
  719     if (sc->sc_dma) {
  720         p = amcc_get_word(dmabuf, &TaskId);
  721         p = amcc_get_word(p, &Length);
  722     } else {
  723         TaskId = iavc_get_word(sc);
  724         Length = iavc_get_slice(sc, sc->sc_recvbuf);
  725         p = sc->sc_recvbuf;
  726     }
  727 
  728     /* XXX could show the message if trace enabled? XXX */
  729     return 0;
  730 }
  731 
  732 static int iavc_receive_debugmsg(iavc_softc_t *sc, u_int8_t *dmabuf)
  733 {
  734     u_int32_t Length;
  735     u_int8_t *p;
  736     printf("%s: receive_debugmsg\n", device_xname(&sc->sc_dev));
  737 
  738     if (sc->sc_dma) {
  739         p = amcc_get_word(dmabuf, &Length);
  740     } else {
  741         Length = iavc_get_slice(sc, sc->sc_recvbuf);
  742         p = sc->sc_recvbuf;
  743     }
  744 
  745     /* XXX could show the message if trace enabled? XXX */
  746     return 0;
  747 }
  748 
  749 static int iavc_receive(iavc_softc_t *sc, u_int8_t *dmabuf, int b3data)
  750 {
  751     struct mbuf *m;
  752     u_int32_t ApplId, Length;
  753 
  754     /*
  755      * byte  0x21 = RECEIVE_MESSAGE
  756      * dword ApplId
  757      * dword length
  758      * ...   CAPI msg
  759      *
  760      * --or--
  761      *
  762      * byte  0x22 = RECEIVE_DATA_B3_IND
  763      * dword ApplId
  764      * dword length
  765      * ...   CAPI msg
  766      * dword datalen
  767      * ...   B3 data
  768      */
  769 
  770     if (sc->sc_dma) {
  771         dmabuf = amcc_get_word(dmabuf, &ApplId);
  772         dmabuf = amcc_get_word(dmabuf, &Length);
  773     } else {
  774         ApplId = iavc_get_word(sc);
  775         Length = iavc_get_slice(sc, sc->sc_recvbuf);
  776         dmabuf = sc->sc_recvbuf;
  777     }
  778 
  779     m = i4b_Dgetmbuf(Length);
  780     if (!m) {
  781         aprint_error_dev(&sc->sc_dev, "can't get memory for receive\n");
  782         return (ENOMEM);
  783     }
  784 
  785     memcpy(mtod(m, u_int8_t*), dmabuf, Length);
  786 
  787 #if 0
  788         {
  789             u_int8_t *p = mtod(m, u_int8_t*);
  790             int len = 0;
  791             printf("%s: applid=%d, len=%d\n", device_xname(&sc->sc_dev),
  792               ApplId, Length);
  793             while (len < m->m_len) {
  794                 printf(" %02x", p[len]);
  795                 if (len && (len % 16) == 0) printf("\n");
  796                 len++;
  797             }
  798             if (len % 16) printf("\n");
  799         }
  800 #endif
  801 
  802     if (b3data) {
  803         if (sc->sc_dma) {
  804             dmabuf = amcc_get_word(dmabuf + Length, &Length);
  805         } else {
  806             Length = iavc_get_slice(sc, sc->sc_recvbuf);
  807             dmabuf = sc->sc_recvbuf;
  808         }
  809 
  810         m->m_next = i4b_Bgetmbuf(Length);
  811         if (!m->m_next) {
  812             aprint_error_dev(&sc->sc_dev, "can't get memory for receive\n");
  813             i4b_Dfreembuf(m);
  814             return (ENOMEM);
  815         }
  816 
  817         memcpy(mtod(m->m_next, u_int8_t*), dmabuf, Length);
  818     }
  819 
  820     capi_ll_receive(&sc->sc_capi, m);
  821     return 0;
  822 }
  823 
  824 /*
  825 //  iavc_handle_intr
  826 //      Checks device interrupt status and calls iavc_handle_{rx,tx}()
  827 //      as necessary.
  828 //
  829 //  iavc_handle_rx
  830 //      Reads in the command byte and calls the subroutines above.
  831 //
  832 //  iavc_start_tx
  833 //      Initiates DMA on the next queued message if possible.
  834 */
  835 
  836 int iavc_handle_intr(iavc_softc_t *sc)
  837 {
  838     u_int32_t status;
  839     u_int32_t newcsr;
  840 
  841     if (!sc->sc_dma) {
  842         while (iavc_rx_full(sc))
  843             iavc_handle_rx(sc);
  844         return 0;
  845     }
  846 
  847     status = AMCC_READ(sc, AMCC_INTCSR);
  848     if ((status & ANY_S5933_INT) == 0)
  849         return 0;
  850 
  851     newcsr = sc->sc_csr | (status & ALL_INT);
  852     if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
  853     if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
  854     AMCC_WRITE(sc, AMCC_INTCSR, newcsr);
  855     sc->sc_intr = 1;
  856 
  857     if (status & RX_TC_INT) {
  858         u_int32_t rxlen;
  859 
  860         bus_dmamap_sync(sc->dmat, sc->rx_map, 0, sc->rx_map->dm_mapsize,
  861           BUS_DMASYNC_POSTREAD);
  862 
  863         if (sc->sc_recv1 == 0) {
  864             sc->sc_recv1 = *(u_int32_t*)(sc->sc_recvbuf);
  865             rxlen = (sc->sc_recv1 + 3) & ~3;
  866 
  867             AMCC_WRITE(sc, AMCC_RXPTR, sc->rx_map->dm_segs[0].ds_addr);
  868             AMCC_WRITE(sc, AMCC_RXLEN, rxlen ? rxlen : 4);
  869         } else {
  870             iavc_handle_rx(sc);
  871             sc->sc_recv1 = 0;
  872             AMCC_WRITE(sc, AMCC_RXPTR, sc->rx_map->dm_segs[0].ds_addr);
  873             AMCC_WRITE(sc, AMCC_RXLEN, 4);
  874         }
  875     }
  876 
  877     if (status & TX_TC_INT) {
  878         bus_dmamap_sync(sc->dmat, sc->tx_map, 0, sc->tx_map->dm_mapsize,
  879           BUS_DMASYNC_POSTWRITE);
  880         sc->sc_csr &= ~EN_TX_TC_INT;
  881         iavc_start_tx(sc);
  882     }
  883 
  884     AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
  885     sc->sc_intr = 0;
  886 
  887     return 0;
  888 }
  889 
  890 static void iavc_handle_rx(iavc_softc_t *sc)
  891 {
  892     u_int8_t *dmabuf = 0, cmd;
  893 
  894     if (sc->sc_dma) {
  895         dmabuf = amcc_get_byte(sc->sc_recvbuf, &cmd);
  896     } else {
  897         cmd = iavc_get_byte(sc);
  898     }
  899 
  900     NDBGL4(L4_IAVCDBG, "iavc%d: command = 0x%02x", sc->sc_unit, cmd);
  901 
  902     switch (cmd) {
  903     case RECEIVE_DATA_B3_IND:
  904         iavc_receive(sc, dmabuf, 1);
  905         break;
  906 
  907     case RECEIVE_MESSAGE:
  908         iavc_receive(sc, dmabuf, 0);
  909         break;
  910 
  911     case RECEIVE_NEW_NCCI:
  912         iavc_receive_new_ncci(sc, dmabuf);
  913         break;
  914 
  915     case RECEIVE_FREE_NCCI:
  916         iavc_receive_free_ncci(sc, dmabuf);
  917         break;
  918 
  919     case RECEIVE_START:
  920         iavc_receive_start(sc);
  921         break;
  922 
  923     case RECEIVE_STOP:
  924         iavc_receive_stop(sc);
  925         break;
  926 
  927     case RECEIVE_INIT:
  928         iavc_receive_init(sc, dmabuf);
  929         break;
  930 
  931     case RECEIVE_TASK_READY:
  932         iavc_receive_task_ready(sc, dmabuf);
  933         break;
  934 
  935     case RECEIVE_DEBUGMSG:
  936         iavc_receive_debugmsg(sc, dmabuf);
  937         break;
  938 
  939     default:
  940         aprint_error_dev(&sc->sc_dev, "unknown msg %02x\n", cmd);
  941     }
  942 }
  943 
  944 static void iavc_start_tx(iavc_softc_t *sc)
  945 {
  946     struct mbuf *m;
  947     u_int32_t txlen;
  948 
  949     /* If device has put us on hold, punt. */
  950 
  951     if (sc->sc_blocked) {
  952         return;
  953     }
  954 
  955     /* If using DMA and transmitter busy, punt. */
  956     if (sc->sc_dma && (sc->sc_csr & EN_TX_TC_INT)) {
  957         return;
  958     }
  959 
  960     /* Else, see if we have messages to send. */
  961     IF_DEQUEUE(&sc->sc_txq, m);
  962     if (!m) {
  963         return;
  964     }
  965 
  966     /* Have message, will send. */
  967     if (CAPIMSG_LEN(m->m_data)) {
  968         /* A proper CAPI message, possibly with B3 data */
  969         txlen = iavc_tx_capimsg(sc, m);
  970     } else {
  971         /* A board control message to be sent as is */
  972         txlen = iavc_tx_ctrlmsg(sc, m);
  973     }
  974 
  975     if (m->m_next) {
  976         i4b_Bfreembuf(m->m_next);
  977         m->m_next = NULL;
  978     }
  979     i4b_Dfreembuf(m);
  980 
  981     /* Kick DMA into motion if applicable */
  982     if (sc->sc_dma) {
  983         txlen = (txlen + 3) & ~3;
  984 
  985         bus_dmamap_sync(sc->dmat, sc->tx_map, 0, txlen,
  986           BUS_DMASYNC_PREWRITE);
  987 
  988         AMCC_WRITE(sc, AMCC_TXPTR, sc->tx_map->dm_segs[0].ds_addr);
  989         AMCC_WRITE(sc, AMCC_TXLEN, txlen);
  990         sc->sc_csr |= EN_TX_TC_INT;
  991 
  992         if (!sc->sc_intr)
  993             AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
  994     }
  995 }
  996 
  997 static uint32_t
  998 iavc_tx_capimsg(iavc_softc_t *sc, struct mbuf *m)
  999 {
 1000     uint32_t txlen = 0;
 1001     u_int8_t *dmabuf;
 1002 
 1003     if (sc->sc_dma) {
 1004         /* Copy message to DMA buffer. */
 1005 
 1006         if (m->m_next)
 1007             dmabuf = amcc_put_byte(sc->sc_sendbuf, SEND_DATA_B3_REQ);
 1008         else
 1009             dmabuf = amcc_put_byte(sc->sc_sendbuf, SEND_MESSAGE);
 1010 
 1011         dmabuf = amcc_put_word(dmabuf, m->m_len);
 1012         memcpy(dmabuf, m->m_data, m->m_len);
 1013         dmabuf += m->m_len;
 1014         txlen = 5 + m->m_len;
 1015 
 1016         if (m->m_next) {
 1017             dmabuf = amcc_put_word(dmabuf, m->m_next->m_len);
 1018             memcpy(dmabuf, m->m_next->m_data, m->m_next->m_len);
 1019             txlen += 4 + m->m_next->m_len;
 1020         }
 1021 
 1022     } else {
 1023         /* Use PIO. */
 1024 
 1025         if (m->m_next) {
 1026             iavc_put_byte(sc, SEND_DATA_B3_REQ);
 1027             NDBGL4(L4_IAVCDBG, "iavc%d: tx SDB3R msg, len = %d",
 1028               sc->sc_unit, m->m_len);
 1029         } else {
 1030             iavc_put_byte(sc, SEND_MESSAGE);
 1031             NDBGL4(L4_IAVCDBG, "iavc%d: tx SM msg, len = %d",
 1032               sc->sc_unit, m->m_len);
 1033         }
 1034 #if 0
 1035     {
 1036         u_int8_t *p = mtod(m, u_int8_t*);
 1037         int len;
 1038         for (len = 0; len < m->m_len; len++) {
 1039             printf(" %02x", *p++);
 1040             if (len && (len % 16) == 0)
 1041                 printf("\n");
 1042         }
 1043         if (len % 16)
 1044             printf("\n");
 1045     }
 1046 #endif
 1047 
 1048         iavc_put_slice(sc, m->m_data, m->m_len);
 1049 
 1050         if (m->m_next)
 1051             iavc_put_slice(sc, m->m_next->m_data, m->m_next->m_len);
 1052     }
 1053 
 1054     return txlen;
 1055 }
 1056 
 1057 static uint32_t
 1058 iavc_tx_ctrlmsg(iavc_softc_t *sc, struct mbuf *m)
 1059 {
 1060     uint32_t txlen = 0;
 1061     uint8_t *dmabuf;
 1062 
 1063     if (sc->sc_dma) {
 1064         memcpy(sc->sc_sendbuf, m->m_data + 2, m->m_len - 2);
 1065         txlen = m->m_len - 2;
 1066     } else {
 1067 
 1068 #if 0
 1069         {
 1070         u_int8_t *p = mtod(m, u_int8_t*) + 2;
 1071         int len;
 1072 
 1073         printf("%s: tx BDC msg, len = %d, msg =", device_xname(&sc->sc_dev),
 1074           m->m_len-2);
 1075         for (len = 0; len < m->m_len-2; len++) {
 1076                 printf(" %02x", *p++);
 1077                 if (len && (len % 16) == 0) printf("\n");
 1078         }
 1079         if (len % 16)
 1080                 printf("\n");
 1081         }
 1082 #endif
 1083 
 1084         /* no DMA */
 1085         txlen = m->m_len - 2;
 1086         dmabuf = mtod(m, char*) + 2;
 1087         while(txlen--)
 1088             b1io_put_byte(sc, *dmabuf++);
 1089     }
 1090 
 1091     return txlen;
 1092 }

Cache object: d92b82d8a5f745fa1fa2612ca683a40c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.