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.5 2006/10/16 13:00:36 pooka 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.5 2006/10/16 13:00:36 pooka 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 <machine/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("%s: reset card ....\n", sc->sc_dev.dv_xname);
  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("%s: start loading %d bytes firmware\n",
  336       sc->sc_dev.dv_xname, len);
  337 
  338     while (len && b1io_save_put_byte(sc, *cp++) == 0)
  339         len--;
  340 
  341     if (len) {
  342         aprint_error("%s: loading failed, can't write to card, len = %d\n",
  343             sc->sc_dev.dv_xname, len);
  344         return (EIO);
  345     }
  346 
  347     aprint_debug("%s: firmware loaded, wait for ACK\n", sc->sc_dev.dv_xname);
  348 
  349     if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA)
  350             iavc_put_byte(sc, SEND_POLL);
  351     else
  352             iavc_put_byte(sc, SEND_POLLACK);
  353 
  354     for (len = 0; len < 1000 && !iavc_rx_full(sc); len++)
  355         DELAY(100);
  356 
  357     if (!iavc_rx_full(sc)) {
  358         aprint_error("%s: loading failed, no ack\n", sc->sc_dev.dv_xname);
  359         return (EIO);
  360     }
  361 
  362     val = iavc_get_byte(sc);
  363 
  364     if ((sc->sc_dma && val != RECEIVE_POLLDWORD) ||
  365       (!sc->sc_dma && val != RECEIVE_POLL)) {
  366         aprint_error("%s: loading failed, bad ack = %02x\n",
  367           sc->sc_dev.dv_xname, val);
  368         return (EIO);
  369     }
  370 
  371     aprint_debug("%s: got ACK = 0x%02x\n", sc->sc_dev.dv_xname, val);
  372 
  373     /* Start the DMA engine */
  374     if (sc->sc_dma) {
  375         int s;
  376 
  377         s = splnet();
  378 
  379         sc->sc_csr = AVM_FLAG;
  380         AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
  381         AMCC_WRITE(sc, AMCC_MCSR, (EN_A2P_TRANSFERS|EN_P2A_TRANSFERS|
  382                                    A2P_HI_PRIORITY|P2A_HI_PRIORITY|
  383                                    RESET_A2P_FLAGS|RESET_P2A_FLAGS));
  384 
  385         iavc_write_port(sc, 0x07, 0x30); /* XXX magic numbers from */
  386         iavc_write_port(sc, 0x10, 0xf0); /* XXX the linux driver */
  387 
  388         bus_dmamap_sync(sc->dmat, sc->rx_map, 0, sc->rx_map->dm_mapsize,
  389           BUS_DMASYNC_PREREAD);
  390 
  391         sc->sc_recv1 = 0;
  392         AMCC_WRITE(sc, AMCC_RXPTR, sc->rx_map->dm_segs[0].ds_addr);
  393         AMCC_WRITE(sc, AMCC_RXLEN, 4);
  394         sc->sc_csr |= EN_RX_TC_INT|EN_TX_TC_INT;
  395         AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
  396 
  397         splx(s);
  398     }
  399 
  400 #ifdef notyet
  401     /* good happy place */
  402     if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA)
  403         b1isa_setup_irq(sc);
  404 #endif
  405 
  406     iavc_send_init(sc);
  407 
  408     return 0;
  409 }
  410 
  411 int iavc_register(capi_softc_t *capi_sc, int applid, int nchan)
  412 {
  413     iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
  414     struct mbuf *m = i4b_Dgetmbuf(23);
  415     u_int8_t *p;
  416 
  417     if (!m) {
  418         aprint_error("iavc%d: can't get memory\n", sc->sc_unit);
  419         return (ENOMEM);
  420     }
  421 
  422     /*
  423      * byte  0x12 = SEND_REGISTER
  424      * dword ApplId
  425      * dword NumMessages
  426      * dword NumB3Connections 0..nbch
  427      * dword NumB3Blocks
  428      * dword B3Size
  429      */
  430 
  431     p = amcc_put_byte(mtod(m, u_int8_t*), 0);
  432     p = amcc_put_byte(p, 0);
  433     p = amcc_put_byte(p, SEND_REGISTER);
  434     p = amcc_put_word(p, applid);
  435 #if 0
  436     p = amcc_put_word(p, 1024 + (nchan + 1));
  437 #else
  438     p = amcc_put_word(p, 1024 * (nchan + 1));
  439 #endif
  440     p = amcc_put_word(p, nchan);
  441     p = amcc_put_word(p, 8);
  442     p = amcc_put_word(p, 2048);
  443 
  444     IF_ENQUEUE(&sc->sc_txq, m);
  445 
  446     iavc_start_tx(sc);
  447 
  448     return 0;
  449 }
  450 
  451 int iavc_release(capi_softc_t *capi_sc, int applid)
  452 {
  453     iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
  454     struct mbuf *m = i4b_Dgetmbuf(7);
  455     u_int8_t *p;
  456 
  457     if (!m) {
  458         printf("%s: can't get memory\n", sc->sc_dev.dv_xname);
  459         return (ENOMEM);
  460     }
  461 
  462     /*
  463      * byte  0x14 = SEND_RELEASE
  464      * dword ApplId
  465      */
  466 
  467     p = amcc_put_byte(mtod(m, u_int8_t*), 0);
  468     p = amcc_put_byte(p, 0);
  469     p = amcc_put_byte(p, SEND_RELEASE);
  470     p = amcc_put_word(p, applid);
  471 
  472     IF_ENQUEUE(&sc->sc_txq, m);
  473 
  474     iavc_start_tx(sc);
  475     return 0;
  476 }
  477 
  478 int iavc_send(capi_softc_t *capi_sc, struct mbuf *m)
  479 {
  480     iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
  481 
  482     if (sc->sc_state != IAVC_UP) {
  483         printf("%s: attempt to send before device up\n", sc->sc_dev.dv_xname);
  484 
  485         if (m->m_next) i4b_Bfreembuf(m->m_next);
  486         i4b_Dfreembuf(m);
  487 
  488         return (ENXIO);
  489     }
  490 
  491     if (IF_QFULL(&sc->sc_txq)) {
  492         IF_DROP(&sc->sc_txq);
  493 
  494         printf("%s: tx overflow, message dropped\n", sc->sc_dev.dv_xname);
  495 
  496         if (m->m_next) i4b_Bfreembuf(m->m_next);
  497         i4b_Dfreembuf(m);
  498 
  499     } else {
  500         IF_ENQUEUE(&sc->sc_txq, m);
  501 
  502         iavc_start_tx(sc);
  503     }
  504 
  505     return 0;
  506 }
  507 
  508 /*
  509 //  Functions called by ourself during the initialization sequence:
  510 //  ---------------------------------------------------------------
  511 //
  512 //  iavc_send_init
  513 //      Sends the system initialization message to a newly loaded
  514 //      board, and sets state to INIT.
  515 */
  516 
  517 static int iavc_send_init(iavc_softc_t *sc)
  518 {
  519     struct mbuf *m = i4b_Dgetmbuf(15);
  520     u_int8_t *p;
  521     int s;
  522 
  523     if (!m) {
  524         printf("%s: can't get memory\n", sc->sc_dev.dv_xname);
  525         return (ENOMEM);
  526     }
  527 
  528     /*
  529      * byte  0x11 = SEND_INIT
  530      * dword NumApplications
  531      * dword NumNCCIs
  532      * dword BoardNumber
  533      */
  534 
  535     p = amcc_put_byte(mtod(m, u_int8_t*), 0);
  536     p = amcc_put_byte(p, 0);
  537     p = amcc_put_byte(p, SEND_INIT);
  538     p = amcc_put_word(p, 1); /* XXX MaxAppl XXX */
  539     p = amcc_put_word(p, sc->sc_capi.sc_nbch);
  540     p = amcc_put_word(p, sc->sc_unit);
  541 
  542     s = splnet();
  543     IF_ENQUEUE(&sc->sc_txq, m);
  544 
  545     iavc_start_tx(sc);
  546 
  547     sc->sc_state = IAVC_INIT;
  548     splx(s);
  549     return 0;
  550 }
  551 
  552 /*
  553 //  Functions called during normal operation:
  554 //  -----------------------------------------
  555 //
  556 //  iavc_receive_init
  557 //      Reads the initialization reply and calls capi_ll_control().
  558 //
  559 //  iavc_receive_new_ncci
  560 //      Reads a new NCCI notification and calls capi_ll_control().
  561 //
  562 //  iavc_receive_free_ncci
  563 //      Reads a freed NCCI notification and calls capi_ll_control().
  564 //
  565 //  iavc_receive_task_ready
  566 //      Reads a task ready message -- which should not occur XXX.
  567 //
  568 //  iavc_receive_debugmsg
  569 //      Reads a debug message -- which should not occur XXX.
  570 //
  571 //  iavc_receive_start
  572 //      Reads a START TRANSMIT message and unblocks device.
  573 //
  574 //  iavc_receive_stop
  575 //      Reads a STOP TRANSMIT message and blocks device.
  576 //
  577 //  iavc_receive
  578 //      Reads an incoming message and calls capi_ll_receive().
  579 */
  580 
  581 static int iavc_receive_init(iavc_softc_t *sc, u_int8_t *dmabuf)
  582 {
  583     u_int32_t Length;
  584     u_int8_t *p;
  585     u_int8_t *cardtype, *serial, *profile, *vers, *caps, *prot;
  586 
  587     if (sc->sc_dma) {
  588         p = amcc_get_word(dmabuf, &Length);
  589     } else {
  590         Length = iavc_get_slice(sc, sc->sc_recvbuf);
  591         p = sc->sc_recvbuf;
  592     }
  593 
  594 #if 0
  595     {
  596         int len = 0;
  597         printf("%s: rx_init: ", sc->sc_dev.dv_xname);
  598             while (len < Length) {
  599                 printf(" %02x", p[len]);
  600                 if (len && (len % 16) == 0) printf("\n");
  601                 len++;
  602             }
  603             if (len % 16) printf("\n");
  604     }
  605 #endif
  606 
  607     vers = (p + 1);
  608     p += (*p + 1); /* driver version */
  609     cardtype = (p + 1);
  610     p += (*p + 1); /* card type */
  611     p += (*p + 1); /* hardware ID */
  612     serial = (p + 1);
  613     p += (*p + 1); /* serial number */
  614     caps = (p + 1);
  615     p += (*p + 1); /* supported options */
  616     prot = (p + 1);
  617     p += (*p + 1); /* supported protocols */
  618     profile = (p + 1);
  619 
  620     if (cardtype && serial && profile) {
  621         int nbch = ((profile[3]<<8) | profile[2]);
  622 
  623         aprint_normal("%s: AVM %s, s/n %s, %d chans, f/w rev %s, prot %s\n",
  624                 sc->sc_dev.dv_xname, cardtype, serial, nbch, vers, prot);
  625         aprint_verbose("%s: %s\n", sc->sc_dev.dv_xname, caps);
  626 
  627         capi_ll_control(&sc->sc_capi, CAPI_CTRL_PROFILE, (int) profile);
  628 
  629     } else {
  630         printf("%s: no profile data in info response?\n", sc->sc_dev.dv_xname);
  631     }
  632 
  633     sc->sc_blocked = 1; /* controller will send START when ready */
  634     return 0;
  635 }
  636 
  637 static int iavc_receive_start(iavc_softc_t *sc)
  638 {
  639     struct mbuf *m = i4b_Dgetmbuf(3);
  640     u_int8_t *p;
  641 
  642     if (sc->sc_blocked && sc->sc_state == IAVC_UP)
  643         printf("%s: receive_start\n", sc->sc_dev.dv_xname);
  644 
  645     if (!m) {
  646         printf("%s: can't get memory\n", sc->sc_dev.dv_xname);
  647         return (ENOMEM);
  648     }
  649 
  650     /*
  651      * byte  0x73 = SEND_POLLACK
  652      */
  653 
  654     p = amcc_put_byte(mtod(m, u_int8_t*), 0);
  655     p = amcc_put_byte(p, 0);
  656     p = amcc_put_byte(p, SEND_POLLACK);
  657 
  658     IF_PREPEND(&sc->sc_txq, m);
  659 
  660     NDBGL4(L4_IAVCDBG, "%s: blocked = %d, state = %d",
  661       sc->sc_dev.dv_xname, sc->sc_blocked, sc->sc_state);
  662 
  663     sc->sc_blocked = 0;
  664     iavc_start_tx(sc);
  665 
  666     /* If this was our first START, register our readiness */
  667     if (sc->sc_state != IAVC_UP) {
  668         sc->sc_state = IAVC_UP;
  669         capi_ll_control(&sc->sc_capi, CAPI_CTRL_READY, 1);
  670     }
  671 
  672     return 0;
  673 }
  674 
  675 static int iavc_receive_stop(iavc_softc_t *sc)
  676 {
  677     printf("%s: receive_stop\n", sc->sc_dev.dv_xname);
  678     sc->sc_blocked = 1;
  679     return 0;
  680 }
  681 
  682 static int iavc_receive_new_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
  683 {
  684     u_int32_t ApplId, NCCI, WindowSize;
  685 
  686     if (sc->sc_dma) {
  687         dmabuf = amcc_get_word(dmabuf, &ApplId);
  688         dmabuf = amcc_get_word(dmabuf, &NCCI);
  689         dmabuf = amcc_get_word(dmabuf, &WindowSize);
  690     } else {
  691         ApplId = iavc_get_word(sc);
  692         NCCI   = iavc_get_word(sc);
  693         WindowSize = iavc_get_word(sc);
  694     }
  695 
  696     capi_ll_control(&sc->sc_capi, CAPI_CTRL_NEW_NCCI, NCCI);
  697     return 0;
  698 }
  699 
  700 static int iavc_receive_free_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
  701 {
  702     u_int32_t ApplId, NCCI;
  703 
  704     if (sc->sc_dma) {
  705         dmabuf = amcc_get_word(dmabuf, &ApplId);
  706         dmabuf = amcc_get_word(dmabuf, &NCCI);
  707     } else {
  708         ApplId = iavc_get_word(sc);
  709         NCCI   = iavc_get_word(sc);
  710     }
  711 
  712     capi_ll_control(&sc->sc_capi, CAPI_CTRL_FREE_NCCI, NCCI);
  713     return 0;
  714 }
  715 
  716 static int iavc_receive_task_ready(iavc_softc_t *sc, u_int8_t *dmabuf)
  717 {
  718     u_int32_t TaskId, Length;
  719     u_int8_t *p;
  720     printf("%s: receive_task_ready\n", sc->sc_dev.dv_xname);
  721 
  722     if (sc->sc_dma) {
  723         p = amcc_get_word(dmabuf, &TaskId);
  724         p = amcc_get_word(p, &Length);
  725     } else {
  726         TaskId = iavc_get_word(sc);
  727         Length = iavc_get_slice(sc, sc->sc_recvbuf);
  728         p = sc->sc_recvbuf;
  729     }
  730 
  731     /* XXX could show the message if trace enabled? XXX */
  732     return 0;
  733 }
  734 
  735 static int iavc_receive_debugmsg(iavc_softc_t *sc, u_int8_t *dmabuf)
  736 {
  737     u_int32_t Length;
  738     u_int8_t *p;
  739     printf("%s: receive_debugmsg\n", sc->sc_dev.dv_xname);
  740 
  741     if (sc->sc_dma) {
  742         p = amcc_get_word(dmabuf, &Length);
  743     } else {
  744         Length = iavc_get_slice(sc, sc->sc_recvbuf);
  745         p = sc->sc_recvbuf;
  746     }
  747 
  748     /* XXX could show the message if trace enabled? XXX */
  749     return 0;
  750 }
  751 
  752 static int iavc_receive(iavc_softc_t *sc, u_int8_t *dmabuf, int b3data)
  753 {
  754     struct mbuf *m;
  755     u_int32_t ApplId, Length;
  756 
  757     /*
  758      * byte  0x21 = RECEIVE_MESSAGE
  759      * dword ApplId
  760      * dword length
  761      * ...   CAPI msg
  762      *
  763      * --or--
  764      *
  765      * byte  0x22 = RECEIVE_DATA_B3_IND
  766      * dword ApplId
  767      * dword length
  768      * ...   CAPI msg
  769      * dword datalen
  770      * ...   B3 data
  771      */
  772 
  773     if (sc->sc_dma) {
  774         dmabuf = amcc_get_word(dmabuf, &ApplId);
  775         dmabuf = amcc_get_word(dmabuf, &Length);
  776     } else {
  777         ApplId = iavc_get_word(sc);
  778         Length = iavc_get_slice(sc, sc->sc_recvbuf);
  779         dmabuf = sc->sc_recvbuf;
  780     }
  781 
  782     m = i4b_Dgetmbuf(Length);
  783     if (!m) {
  784         printf("%s: can't get memory for receive\n", sc->sc_dev.dv_xname);
  785         return (ENOMEM);
  786     }
  787 
  788     memcpy(mtod(m, u_int8_t*), dmabuf, Length);
  789 
  790 #if 0
  791         {
  792             u_int8_t *p = mtod(m, u_int8_t*);
  793             int len = 0;
  794             printf("%s: applid=%d, len=%d\n", sc->sc_dev.dv_xname,
  795               ApplId, Length);
  796             while (len < m->m_len) {
  797                 printf(" %02x", p[len]);
  798                 if (len && (len % 16) == 0) printf("\n");
  799                 len++;
  800             }
  801             if (len % 16) printf("\n");
  802         }
  803 #endif
  804 
  805     if (b3data) {
  806         if (sc->sc_dma) {
  807             dmabuf = amcc_get_word(dmabuf + Length, &Length);
  808         } else {
  809             Length = iavc_get_slice(sc, sc->sc_recvbuf);
  810             dmabuf = sc->sc_recvbuf;
  811         }
  812 
  813         m->m_next = i4b_Bgetmbuf(Length);
  814         if (!m->m_next) {
  815             printf("%s: can't get memory for receive\n", sc->sc_dev.dv_xname);
  816             i4b_Dfreembuf(m);
  817             return (ENOMEM);
  818         }
  819 
  820         memcpy(mtod(m->m_next, u_int8_t*), dmabuf, Length);
  821     }
  822 
  823     capi_ll_receive(&sc->sc_capi, m);
  824     return 0;
  825 }
  826 
  827 /*
  828 //  iavc_handle_intr
  829 //      Checks device interrupt status and calls iavc_handle_{rx,tx}()
  830 //      as necessary.
  831 //
  832 //  iavc_handle_rx
  833 //      Reads in the command byte and calls the subroutines above.
  834 //
  835 //  iavc_start_tx
  836 //      Initiates DMA on the next queued message if possible.
  837 */
  838 
  839 int iavc_handle_intr(iavc_softc_t *sc)
  840 {
  841     u_int32_t status;
  842     u_int32_t newcsr;
  843 
  844     if (!sc->sc_dma) {
  845         while (iavc_rx_full(sc))
  846             iavc_handle_rx(sc);
  847         return 0;
  848     }
  849 
  850     status = AMCC_READ(sc, AMCC_INTCSR);
  851     if ((status & ANY_S5933_INT) == 0)
  852         return 0;
  853 
  854     newcsr = sc->sc_csr | (status & ALL_INT);
  855     if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
  856     if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
  857     AMCC_WRITE(sc, AMCC_INTCSR, newcsr);
  858     sc->sc_intr = 1;
  859 
  860     if (status & RX_TC_INT) {
  861         u_int32_t rxlen;
  862 
  863         bus_dmamap_sync(sc->dmat, sc->rx_map, 0, sc->rx_map->dm_mapsize,
  864           BUS_DMASYNC_POSTREAD);
  865 
  866         if (sc->sc_recv1 == 0) {
  867             sc->sc_recv1 = *(u_int32_t*)(sc->sc_recvbuf);
  868             rxlen = (sc->sc_recv1 + 3) & ~3;
  869 
  870             AMCC_WRITE(sc, AMCC_RXPTR, sc->rx_map->dm_segs[0].ds_addr);
  871             AMCC_WRITE(sc, AMCC_RXLEN, rxlen ? rxlen : 4);
  872         } else {
  873             iavc_handle_rx(sc);
  874             sc->sc_recv1 = 0;
  875             AMCC_WRITE(sc, AMCC_RXPTR, sc->rx_map->dm_segs[0].ds_addr);
  876             AMCC_WRITE(sc, AMCC_RXLEN, 4);
  877         }
  878     }
  879 
  880     if (status & TX_TC_INT) {
  881         bus_dmamap_sync(sc->dmat, sc->tx_map, 0, sc->tx_map->dm_mapsize,
  882           BUS_DMASYNC_POSTWRITE);
  883         sc->sc_csr &= ~EN_TX_TC_INT;
  884         iavc_start_tx(sc);
  885     }
  886 
  887     AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
  888     sc->sc_intr = 0;
  889 
  890     return 0;
  891 }
  892 
  893 static void iavc_handle_rx(iavc_softc_t *sc)
  894 {
  895     u_int8_t *dmabuf = 0, cmd;
  896 
  897     if (sc->sc_dma) {
  898         dmabuf = amcc_get_byte(&sc->sc_recvbuf[0], &cmd);
  899     } else {
  900         cmd = iavc_get_byte(sc);
  901     }
  902 
  903     NDBGL4(L4_IAVCDBG, "iavc%d: command = 0x%02x", sc->sc_unit, cmd);
  904 
  905     switch (cmd) {
  906     case RECEIVE_DATA_B3_IND:
  907         iavc_receive(sc, dmabuf, 1);
  908         break;
  909 
  910     case RECEIVE_MESSAGE:
  911         iavc_receive(sc, dmabuf, 0);
  912         break;
  913 
  914     case RECEIVE_NEW_NCCI:
  915         iavc_receive_new_ncci(sc, dmabuf);
  916         break;
  917 
  918     case RECEIVE_FREE_NCCI:
  919         iavc_receive_free_ncci(sc, dmabuf);
  920         break;
  921 
  922     case RECEIVE_START:
  923         iavc_receive_start(sc);
  924         break;
  925 
  926     case RECEIVE_STOP:
  927         iavc_receive_stop(sc);
  928         break;
  929 
  930     case RECEIVE_INIT:
  931         iavc_receive_init(sc, dmabuf);
  932         break;
  933 
  934     case RECEIVE_TASK_READY:
  935         iavc_receive_task_ready(sc, dmabuf);
  936         break;
  937 
  938     case RECEIVE_DEBUGMSG:
  939         iavc_receive_debugmsg(sc, dmabuf);
  940         break;
  941 
  942     default:
  943         printf("%s: unknown msg %02x\n", sc->sc_dev.dv_xname, cmd);
  944     }
  945 }
  946 
  947 static void iavc_start_tx(iavc_softc_t *sc)
  948 {
  949     struct mbuf *m;
  950     u_int32_t txlen;
  951 
  952     /* If device has put us on hold, punt. */
  953 
  954     if (sc->sc_blocked) {
  955         return;
  956     }
  957 
  958     /* If using DMA and transmitter busy, punt. */
  959     if (sc->sc_dma && (sc->sc_csr & EN_TX_TC_INT)) {
  960         return;
  961     }
  962 
  963     /* Else, see if we have messages to send. */
  964     IF_DEQUEUE(&sc->sc_txq, m);
  965     if (!m) {
  966         return;
  967     }
  968 
  969     /* Have message, will send. */
  970     if (CAPIMSG_LEN(m->m_data)) {
  971         /* A proper CAPI message, possibly with B3 data */
  972         txlen = iavc_tx_capimsg(sc, m);
  973     } else {
  974         /* A board control message to be sent as is */
  975         txlen = iavc_tx_ctrlmsg(sc, m);
  976     }
  977 
  978     if (m->m_next) {
  979         i4b_Bfreembuf(m->m_next);
  980         m->m_next = NULL;
  981     }
  982     i4b_Dfreembuf(m);
  983 
  984     /* Kick DMA into motion if applicable */
  985     if (sc->sc_dma) {
  986         txlen = (txlen + 3) & ~3;
  987 
  988         bus_dmamap_sync(sc->dmat, sc->tx_map, 0, txlen,
  989           BUS_DMASYNC_PREWRITE);
  990 
  991         AMCC_WRITE(sc, AMCC_TXPTR, sc->tx_map->dm_segs[0].ds_addr);
  992         AMCC_WRITE(sc, AMCC_TXLEN, txlen);
  993         sc->sc_csr |= EN_TX_TC_INT;
  994 
  995         if (!sc->sc_intr)
  996             AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
  997     }
  998 }
  999 
 1000 static uint32_t
 1001 iavc_tx_capimsg(iavc_softc_t *sc, struct mbuf *m)
 1002 {
 1003     uint32_t txlen = 0;
 1004     u_int8_t *dmabuf;
 1005 
 1006     if (sc->sc_dma) {
 1007         /* Copy message to DMA buffer. */
 1008 
 1009         if (m->m_next)
 1010             dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_DATA_B3_REQ);
 1011         else
 1012             dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_MESSAGE);
 1013 
 1014         dmabuf = amcc_put_word(dmabuf, m->m_len);
 1015         memcpy(dmabuf, m->m_data, m->m_len);
 1016         dmabuf += m->m_len;
 1017         txlen = 5 + m->m_len;
 1018 
 1019         if (m->m_next) {
 1020             dmabuf = amcc_put_word(dmabuf, m->m_next->m_len);
 1021             memcpy(dmabuf, m->m_next->m_data, m->m_next->m_len);
 1022             txlen += 4 + m->m_next->m_len;
 1023         }
 1024 
 1025     } else {
 1026         /* Use PIO. */
 1027 
 1028         if (m->m_next) {
 1029             iavc_put_byte(sc, SEND_DATA_B3_REQ);
 1030             NDBGL4(L4_IAVCDBG, "iavc%d: tx SDB3R msg, len = %d",
 1031               sc->sc_unit, m->m_len);
 1032         } else {
 1033             iavc_put_byte(sc, SEND_MESSAGE);
 1034             NDBGL4(L4_IAVCDBG, "iavc%d: tx SM msg, len = %d",
 1035               sc->sc_unit, m->m_len);
 1036         }
 1037 #if 0
 1038     {
 1039         u_int8_t *p = mtod(m, u_int8_t*);
 1040         int len;
 1041         for (len = 0; len < m->m_len; len++) {
 1042             printf(" %02x", *p++);
 1043             if (len && (len % 16) == 0)
 1044                 printf("\n");
 1045         }
 1046         if (len % 16)
 1047             printf("\n");
 1048     }
 1049 #endif
 1050 
 1051         iavc_put_slice(sc, m->m_data, m->m_len);
 1052 
 1053         if (m->m_next)
 1054             iavc_put_slice(sc, m->m_next->m_data, m->m_next->m_len);
 1055     }
 1056 
 1057     return txlen;
 1058 }
 1059 
 1060 static uint32_t
 1061 iavc_tx_ctrlmsg(iavc_softc_t *sc, struct mbuf *m)
 1062 {
 1063     uint32_t txlen = 0;
 1064     uint8_t *dmabuf;
 1065 
 1066     if (sc->sc_dma) {
 1067         memcpy(&sc->sc_sendbuf[0], m->m_data + 2, m->m_len - 2);
 1068         txlen = m->m_len - 2;
 1069     } else {
 1070 
 1071 #if 0
 1072         {
 1073         u_int8_t *p = mtod(m, u_int8_t*) + 2;
 1074         int len;
 1075 
 1076         printf("%s: tx BDC msg, len = %d, msg =", sc->sc_dev.dv_xname,
 1077           m->m_len-2);
 1078         for (len = 0; len < m->m_len-2; len++) {
 1079                 printf(" %02x", *p++);
 1080                 if (len && (len % 16) == 0) printf("\n");
 1081         }
 1082         if (len % 16)
 1083                 printf("\n");
 1084         }
 1085 #endif
 1086 
 1087         /* no DMA */
 1088         txlen = m->m_len - 2;
 1089         dmabuf = mtod(m, char*) + 2;
 1090         while(txlen--)
 1091             b1io_put_byte(sc, *dmabuf++);
 1092     }
 1093 
 1094     return txlen;
 1095 }

Cache object: fe21c6cde7812ae7063c8a632a0767f6


[ 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.