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/pci/iwic_bchan.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: iwic_bchan.c,v 1.2 2002/09/27 15:37:27 provos Exp $    */
    2 
    3 /*
    4  * Copyright (c) 1999, 2000 Dave Boyce. All rights reserved.
    5  *
    6  * Copyright (c) 2000, 2001 Hellmuth Michaelis. All rights reserved. 
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  *---------------------------------------------------------------------------
   30  *
   31  *      i4b_iwic - isdn4bsd Winbond W6692 driver
   32  *      ----------------------------------------
   33  *
   34  * $FreeBSD$
   35  *
   36  *      last edit-date: [Tue Jan 16 13:21:24 2001]
   37  *
   38  *---------------------------------------------------------------------------*/
   39 
   40 #include <sys/cdefs.h>
   41 __KERNEL_RCSID(0, "$NetBSD: iwic_bchan.c,v 1.2 2002/09/27 15:37:27 provos Exp $");
   42 
   43 #include <sys/param.h>
   44 #include <sys/kernel.h>
   45 #include <sys/systm.h>
   46 #include <sys/mbuf.h>
   47 #include <sys/callout.h>
   48 #include <sys/socket.h>
   49 #include <sys/device.h>
   50 #include <net/if.h>
   51 
   52 #include <machine/bus.h>
   53 
   54 #include <dev/pci/pcireg.h>
   55 #include <dev/pci/pcivar.h>
   56 #include <dev/pci/pcidevs.h>
   57 
   58 #include <dev/pci/iwicreg.h>
   59 #include <dev/pci/iwicvar.h>
   60 
   61 #include <netisdn/i4b_debug.h>
   62 #include <netisdn/i4b_ioctl.h>
   63 #include <netisdn/i4b_trace.h>
   64 
   65 #include <netisdn/i4b_l2.h>
   66 #include <netisdn/i4b_l1l2.h>
   67 #include <netisdn/i4b_mbuf.h>
   68 #include <netisdn/i4b_global.h>
   69 
   70 static void iwic_bchan_init(struct iwic_softc *sc, int chan_no, int activate);
   71 
   72 /*---------------------------------------------------------------------------*
   73  *      B-channel interrupt handler
   74  *---------------------------------------------------------------------------*/
   75 void
   76 iwic_bchan_xirq(struct iwic_softc *sc, int chan_no)
   77 {
   78         int irq_stat;
   79         struct iwic_bchan *chan;
   80         int cmd = 0;
   81         int activity = 0;
   82 
   83         chan = &sc->sc_bchan[chan_no];
   84 
   85         irq_stat = IWIC_READ(sc, chan->offset + B_EXIR);
   86 
   87         NDBGL1(L1_H_IRQ, "irq_stat = 0x%x", irq_stat);
   88         
   89         if((irq_stat & (B_EXIR_RMR | B_EXIR_RME | B_EXIR_RDOV | B_EXIR_XFR | B_EXIR_XDUN)) == 0)
   90         {
   91                 NDBGL1(L1_H_XFRERR, "spurious IRQ!");
   92                 return;
   93         }
   94 
   95         if (irq_stat & B_EXIR_RDOV)
   96         {
   97                 NDBGL1(L1_H_XFRERR, "%s: EXIR B-channel Receive Data Overflow", sc->sc_dev.dv_xname);
   98         }
   99 
  100         if (irq_stat & B_EXIR_XDUN)
  101         {
  102                 NDBGL1(L1_H_XFRERR, "%s: EXIR B-channel Transmit Data Underrun", sc->sc_dev.dv_xname);
  103                 cmd |= (B_CMDR_XRST);   /*XXX must retransmit frame ! */
  104         }
  105 
  106 /* RX message end interrupt */
  107         
  108         if(irq_stat & B_EXIR_RME)
  109         {
  110                 int error;
  111 
  112                 NDBGL1(L1_H_IRQ, "B_EXIR_RME");
  113 
  114                 error = (IWIC_READ(sc,chan->offset+B_STAR) &
  115                          (B_STAR_RDOV | B_STAR_CRCE | B_STAR_RMB));
  116 
  117                 if(error)
  118                 {
  119                         if(error & B_STAR_RDOV)
  120                                 NDBGL1(L1_H_XFRERR, "%s: B-channel Receive Data Overflow", sc->sc_dev.dv_xname);
  121                         if(error & B_STAR_CRCE)
  122                                 NDBGL1(L1_H_XFRERR, "%s: B-channel CRC Error", sc->sc_dev.dv_xname);
  123                         if(error & B_STAR_RMB)
  124                                 NDBGL1(L1_H_XFRERR, "%s: B-channel Receive Message Aborted", sc->sc_dev.dv_xname);
  125                 }
  126 
  127                 /* all error conditions checked, now decide and take action */
  128                 
  129                 if(error == 0)
  130                 {
  131                         register int fifo_data_len;
  132                         fifo_data_len = ((IWIC_READ(sc,chan->offset+B_RBCL)) &
  133                                         ((IWIC_BCHAN_FIFO_LEN)-1));
  134                 
  135                         if(fifo_data_len == 0)
  136                                 fifo_data_len = IWIC_BCHAN_FIFO_LEN;
  137 
  138 
  139                         if(chan->in_mbuf == NULL)
  140                         {
  141                                 if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL)
  142                                         panic("L1 iwic_bchan_irq: RME, cannot allocate mbuf!");
  143                                 chan->in_cbptr = chan->in_mbuf->m_data;
  144                                 chan->in_len = 0;
  145                         }
  146 
  147                         if((chan->in_len + fifo_data_len) <= BCH_MAX_DATALEN)
  148                         {
  149                                 /* read data from fifo */
  150         
  151                                 NDBGL1(L1_H_IRQ, "B_EXIR_RME, rd fifo, len = %d", fifo_data_len);
  152 
  153                                 IWIC_RDBFIFO(sc, chan, chan->in_cbptr, fifo_data_len);
  154 
  155                                 cmd |= (B_CMDR_RACK | B_CMDR_RACT);
  156                                 IWIC_WRITE(sc, chan->offset + B_CMDR, cmd);
  157                                 cmd = 0;
  158                                 
  159                                 chan->in_len += fifo_data_len;
  160                                 chan->rxcount += fifo_data_len;
  161 
  162                                 /* setup mbuf data length */
  163                                         
  164                                 chan->in_mbuf->m_len = chan->in_len;
  165                                 chan->in_mbuf->m_pkthdr.len = chan->in_len;
  166 
  167                                 if(sc->sc_trace & TRACE_B_RX)
  168                                 {
  169                                         i4b_trace_hdr hdr;
  170                                         hdr.type = (chan_no == IWIC_BCH_A ? TRC_CH_B1 : TRC_CH_B2);
  171                                         hdr.dir = FROM_NT;
  172                                         hdr.count = ++sc->sc_bchan[chan_no].sc_trace_bcount;
  173                                         isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr,chan->in_mbuf->m_len, chan->in_mbuf->m_data);
  174                                 }
  175 
  176                                 (*chan->l4_driver->bch_rx_data_ready)(chan->l4_driver_softc);
  177 
  178 
  179                                 activity = ACT_RX;
  180                                 
  181                                 /* mark buffer ptr as unused */
  182                                         
  183                                 chan->in_mbuf = NULL;
  184                                 chan->in_cbptr = NULL;
  185                                 chan->in_len = 0;
  186                         }
  187                         else
  188                         {
  189                                 NDBGL1(L1_H_XFRERR, "RAWHDLC rx buffer overflow in RME, in_len=%d, fifolen=%d", chan->in_len, fifo_data_len);
  190                                 chan->in_cbptr = chan->in_mbuf->m_data;
  191                                 chan->in_len = 0;
  192                                 cmd |= (B_CMDR_RRST | B_CMDR_RACK);
  193                         }
  194                 }
  195                 else
  196                 {
  197                         if (chan->in_mbuf != NULL)
  198                         {
  199                                 i4b_Bfreembuf(chan->in_mbuf);
  200                                 chan->in_mbuf = NULL;
  201                                 chan->in_cbptr = NULL;
  202                                 chan->in_len = 0;
  203                         }
  204                         cmd |= (B_CMDR_RRST | B_CMDR_RACK);
  205                 }
  206         }
  207 
  208 /* RX fifo full interrupt */
  209 
  210         if(irq_stat & B_EXIR_RMR)
  211         {
  212                 NDBGL1(L1_H_IRQ, "B_EXIR_RMR");
  213 
  214                 if(chan->in_mbuf == NULL)
  215                 {
  216                         if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL)
  217                                 panic("L1 iwic_bchan_irq: RMR, cannot allocate mbuf!");
  218                         chan->in_cbptr = chan->in_mbuf->m_data;
  219                         chan->in_len = 0;
  220                 }
  221 
  222                 chan->rxcount += IWIC_BCHAN_FIFO_LEN;
  223                 
  224                 if((chan->in_len + IWIC_BCHAN_FIFO_LEN) <= BCH_MAX_DATALEN)
  225                 {
  226                         /* read data from fifo */
  227 
  228                         NDBGL1(L1_H_IRQ, "B_EXIR_RMR, rd fifo, len = max (64)");
  229                         
  230                         IWIC_RDBFIFO(sc, chan, chan->in_cbptr, IWIC_BCHAN_FIFO_LEN);
  231 
  232                         chan->in_cbptr += IWIC_BCHAN_FIFO_LEN;
  233                         chan->in_len += IWIC_BCHAN_FIFO_LEN;
  234                 }
  235                 else
  236                 {
  237                         if(chan->bprot == BPROT_NONE)
  238                         {
  239                                 /* setup mbuf data length */
  240                                 
  241                                 chan->in_mbuf->m_len = chan->in_len;
  242                                 chan->in_mbuf->m_pkthdr.len = chan->in_len;
  243 
  244                                 if(sc->sc_trace & TRACE_B_RX)
  245                                 {
  246                                         i4b_trace_hdr hdr;
  247                                         hdr.type = (chan_no == IWIC_BCH_A ? TRC_CH_B1 : TRC_CH_B2);
  248                                         hdr.dir = FROM_NT;
  249                                         hdr.count = ++sc->sc_bchan[chan_no].sc_trace_bcount;
  250                                         isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr,chan->in_mbuf->m_len, chan->in_mbuf->m_data);
  251                                 }
  252 
  253                                 /* silence detection */
  254                                 
  255                                 if(!(isdn_bchan_silence(chan->in_mbuf->m_data, chan->in_mbuf->m_len)))
  256                                         activity = ACT_RX;
  257 
  258 #if defined (__FreeBSD__) && __FreeBSD__ > 4
  259                                 (void) IF_HANDOFF(&chan->rx_queue, chan->in_mbuf, NULL);
  260 #else
  261                                 if(!(IF_QFULL(&chan->rx_queue)))
  262                                 {
  263                                         IF_ENQUEUE(&chan->rx_queue, chan->in_mbuf);
  264                                 }
  265                                 else
  266                                 {
  267                                         i4b_Bfreembuf(chan->in_mbuf);
  268                                 }
  269 #endif
  270                                 /* signal upper driver that data is available */
  271 
  272                                 (*chan->l4_driver->bch_rx_data_ready)(chan->l4_driver_softc);
  273                                 
  274                                 /* alloc new buffer */
  275                                 
  276                                 if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL)
  277                                         panic("L1 iwic_bchan_irq: RMR, cannot allocate new mbuf!");
  278         
  279                                 /* setup new data ptr */
  280                                 
  281                                 chan->in_cbptr = chan->in_mbuf->m_data;
  282         
  283                                 /* read data from fifo */
  284         
  285                                 NDBGL1(L1_H_IRQ, "B_EXIR_RMR, rd fifo1, len = max (64)");
  286                                 
  287                                 IWIC_RDBFIFO(sc, chan, chan->in_cbptr, IWIC_BCHAN_FIFO_LEN);
  288 
  289                                 chan->in_cbptr += IWIC_BCHAN_FIFO_LEN;
  290                                 chan->in_len = IWIC_BCHAN_FIFO_LEN;
  291 
  292                                 chan->rxcount += IWIC_BCHAN_FIFO_LEN;
  293                         }
  294                         else
  295                         {
  296                                 NDBGL1(L1_H_XFRERR, "RAWHDLC rx buffer overflow in RPF, in_len=%d", chan->in_len);
  297                                 chan->in_cbptr = chan->in_mbuf->m_data;
  298                                 chan->in_len = 0;
  299                                 cmd |= (B_CMDR_RRST | B_CMDR_RACK);
  300                         }
  301                 }
  302                 
  303                 /* command to release fifo space */
  304                 
  305                 cmd |= B_CMDR_RACK;
  306         }
  307 
  308 /* TX interrupt */
  309         
  310         if (irq_stat & B_EXIR_XFR)
  311         {                       
  312                 /* transmit fifo empty, new data can be written to fifo */
  313 
  314                 int activity = -1;
  315                 int len;
  316                 int nextlen;
  317 
  318                 NDBGL1(L1_H_IRQ, "B_EXIR_XFR");
  319                 
  320                 if(chan->out_mbuf_cur == NULL)  /* last frame is transmitted */
  321                 {
  322                         IF_DEQUEUE(&chan->tx_queue, chan->out_mbuf_head);
  323 
  324                         if(chan->out_mbuf_head == NULL)
  325                         {
  326                                 chan->state &= ~ST_TX_ACTIVE;
  327                                 (*chan->l4_driver->bch_tx_queue_empty)(chan->l4_driver_softc);
  328                         }
  329                         else
  330                         {
  331                                 chan->state |= ST_TX_ACTIVE;
  332                                 chan->out_mbuf_cur = chan->out_mbuf_head;
  333                                 chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
  334                                 chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
  335 
  336                                 if(sc->sc_trace & TRACE_B_TX)
  337                                 {
  338                                         i4b_trace_hdr hdr;
  339                                         hdr.type = (chan_no == IWIC_BCH_A ? TRC_CH_B1 : TRC_CH_B2);
  340                                         hdr.dir = FROM_TE;
  341                                         hdr.count = ++sc->sc_bchan[chan_no].sc_trace_bcount;
  342                                         isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
  343                                 }
  344 
  345                                 if(chan->bprot == BPROT_NONE)
  346                                 {
  347                                         if(!(isdn_bchan_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len)))
  348                                                 activity = ACT_TX;
  349                                 }
  350                                 else
  351                                 {
  352                                         activity = ACT_TX;
  353                                 }
  354                         }
  355                 }
  356                         
  357                 len = 0;
  358 
  359                 while(chan->out_mbuf_cur && len != IWIC_BCHAN_FIFO_LEN)
  360                 {
  361                         nextlen = min(chan->out_mbuf_cur_len, IWIC_BCHAN_FIFO_LEN - len);
  362 
  363                         NDBGL1(L1_H_IRQ, "B_EXIR_XFR, wr fifo, len = %d", nextlen);
  364                         
  365                         IWIC_WRBFIFO(sc, chan, chan->out_mbuf_cur_ptr, nextlen);
  366 
  367                         cmd |= B_CMDR_XMS;
  368         
  369                         len += nextlen;
  370                         chan->txcount += nextlen;
  371         
  372                         chan->out_mbuf_cur_ptr += nextlen;
  373                         chan->out_mbuf_cur_len -= nextlen;
  374                         
  375                         if(chan->out_mbuf_cur_len == 0) 
  376                         {
  377                                 if((chan->out_mbuf_cur = chan->out_mbuf_cur->m_next) != NULL)
  378                                 {
  379                                         chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
  380                                         chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
  381 
  382                                         if(sc->sc_trace & TRACE_B_TX)
  383                                         {
  384                                                 i4b_trace_hdr hdr;
  385                                                 hdr.type = (chan_no == IWIC_BCH_A ? TRC_CH_B1 : TRC_CH_B2);
  386                                                 hdr.dir = FROM_TE;
  387                                                 hdr.count = ++sc->sc_bchan[chan_no].sc_trace_bcount;
  388                                                 isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
  389                                         }
  390                                 }
  391                                 else
  392                                 {
  393                                         if (chan->bprot != BPROT_NONE)
  394                                                 cmd |= B_CMDR_XME;
  395                                         i4b_Bfreembuf(chan->out_mbuf_head);
  396                                         chan->out_mbuf_head = NULL;
  397                                 }
  398                         }
  399                 }
  400         }
  401         if(cmd)
  402         {
  403                 cmd |= B_CMDR_RACT;
  404                 IWIC_WRITE(sc, chan->offset + B_CMDR, cmd);
  405         }
  406 }
  407 
  408 /*---------------------------------------------------------------------------*
  409  *      initialize one B channels rx/tx data structures
  410  *---------------------------------------------------------------------------*/
  411 void
  412 iwic_bchannel_setup(isdn_layer1token t, int chan_no, int bprot, int activate)
  413 {
  414         struct iwic_softc *sc = t;
  415         struct iwic_bchan *chan = &sc->sc_bchan[chan_no];
  416 
  417         int s = splnet();
  418         
  419         NDBGL1(L1_BCHAN, "%s: chan %d, bprot %d, activate %d",
  420             sc->sc_dev.dv_xname, chan_no, bprot, activate);
  421 
  422         /* general part */
  423 
  424         chan->bprot = bprot;            /* B channel protocol */
  425         chan->state = ST_IDLE;          /* B channel state */
  426 
  427         if(activate == 0)
  428         {
  429                 /* deactivation */
  430                 iwic_bchan_init(sc, chan_no, activate);
  431         }
  432                 
  433         /* receiver part */
  434 
  435         chan->rx_queue.ifq_maxlen = IFQ_MAXLEN;
  436 
  437 #if defined (__FreeBSD__) && __FreeBSD__ > 4
  438         if(!mtx_initialized(&chan->rx_queue.ifq_mtx))
  439                 mtx_init(&chan->rx_queue.ifq_mtx, "i4b_iwic_rx", NULL, MTX_DEF);
  440 #endif
  441 
  442         i4b_Bcleanifq(&chan->rx_queue); /* clean rx queue */
  443 
  444         chan->rxcount = 0;              /* reset rx counter */
  445         
  446         i4b_Bfreembuf(chan->in_mbuf);   /* clean rx mbuf */
  447 
  448         chan->in_mbuf = NULL;           /* reset mbuf ptr */
  449         chan->in_cbptr = NULL;          /* reset mbuf curr ptr */
  450         chan->in_len = 0;               /* reset mbuf data len */
  451         
  452         /* transmitter part */
  453 
  454         chan->tx_queue.ifq_maxlen = IFQ_MAXLEN;
  455 
  456 #if defined (__FreeBSD__) && __FreeBSD__ > 4    
  457         if(!mtx_initialized(&chan->tx_queue.ifq_mtx))
  458                 mtx_init(&chan->tx_queue.ifq_mtx, "i4b_iwic_tx", NULL, MTX_DEF);
  459 #endif
  460 
  461         i4b_Bcleanifq(&chan->tx_queue); /* clean tx queue */
  462         
  463         chan->txcount = 0;              /* reset tx counter */
  464         
  465         i4b_Bfreembuf(chan->out_mbuf_head);     /* clean tx mbuf */
  466 
  467         chan->out_mbuf_head = NULL;     /* reset head mbuf ptr */
  468         chan->out_mbuf_cur = NULL;      /* reset current mbuf ptr */    
  469         chan->out_mbuf_cur_ptr = NULL;  /* reset current mbuf data ptr */
  470         chan->out_mbuf_cur_len = 0;     /* reset current mbuf data cnt */
  471         
  472         if(activate != 0)
  473         {
  474                 /* activation */
  475                 iwic_bchan_init(sc, chan_no, activate);
  476         }
  477 
  478         splx(s);
  479 }
  480 
  481 /*---------------------------------------------------------------------------*
  482  *      initalize / deinitialize B-channel hardware
  483  *---------------------------------------------------------------------------*/
  484 static void
  485 iwic_bchan_init(struct iwic_softc *sc, int chan_no, int activate)
  486 {
  487         struct iwic_bchan *bchan = &sc->sc_bchan[chan_no];
  488 
  489         NDBGL1(L1_BCHAN, "chan %d, activate %d", chan_no, activate);
  490 
  491         if(activate)
  492         {
  493                 if(bchan->bprot == BPROT_NONE)
  494                 {
  495                         /* Extended transparent mode */
  496                         IWIC_WRITE(sc, bchan->offset + B_MODE, B_MODE_MMS);
  497                 }
  498                 else
  499                 {
  500                         /* Transparent mode */
  501                         IWIC_WRITE(sc, bchan->offset + B_MODE, 0);
  502                         /* disable address comparation */
  503                         IWIC_WRITE (sc, bchan->offset+B_ADM1, 0xff);
  504                         IWIC_WRITE (sc, bchan->offset+B_ADM2, 0xff);
  505                 }
  506 
  507                 /* reset & start receiver */
  508                 IWIC_WRITE(sc, bchan->offset + B_CMDR, B_CMDR_RRST|B_CMDR_RACT);
  509 
  510                 /* clear irq mask */
  511                 IWIC_WRITE(sc, bchan->offset + B_EXIM, 0);
  512         }
  513         else
  514         {
  515                 /* mask all irqs */             
  516                 IWIC_WRITE(sc, bchan->offset + B_EXIM, 0xff);
  517 
  518                 /* reset mode */
  519                 IWIC_WRITE(sc, bchan->offset + B_MODE, 0);
  520                 
  521                 /* Bring interface down */
  522                 IWIC_WRITE(sc, bchan->offset + B_CMDR, B_CMDR_RRST | B_CMDR_XRST);
  523 
  524                 /* Flush pending interrupts */
  525                 IWIC_READ(sc, bchan->offset + B_EXIR);
  526         }
  527 }
  528 
  529 /*---------------------------------------------------------------------------*
  530  *      start transmission on a b channel
  531  *---------------------------------------------------------------------------*/
  532 static void
  533 iwic_bchannel_start(isdn_layer1token t,int h_chan)
  534 {
  535         struct iwic_softc *sc = (void *)t;
  536         struct iwic_bchan *chan = &sc->sc_bchan[h_chan];
  537         register int len;
  538         register int next_len;
  539 
  540         int s;
  541         int activity = -1;
  542         int cmd = 0;
  543 
  544         s = splnet();                           /* enter critical section */
  545 
  546         NDBGL1(L1_BCHAN, "%s: channel %d", sc->sc_dev.dv_xname, h_chan);
  547 
  548         if(chan->state & ST_TX_ACTIVE)          /* already running ? */
  549         {
  550                 splx(s);
  551                 return;                         /* yes, leave */
  552         }
  553 
  554         /* get next mbuf from queue */
  555         
  556         IF_DEQUEUE(&chan->tx_queue, chan->out_mbuf_head);
  557         
  558         if(chan->out_mbuf_head == NULL)         /* queue empty ? */
  559         {
  560                 splx(s);                        /* leave critical section */
  561                 return;                         /* yes, exit */
  562         }
  563 
  564         /* init current mbuf values */
  565         
  566         chan->out_mbuf_cur = chan->out_mbuf_head;
  567         chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
  568         chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;    
  569         
  570         /* activity indicator for timeout handling */
  571 
  572         if(chan->bprot == BPROT_NONE)
  573         {
  574                 if(!(isdn_bchan_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len)))
  575                         activity = ACT_TX;
  576         }
  577         else
  578         {
  579                 activity = ACT_TX;
  580         }
  581 
  582         chan->state |= ST_TX_ACTIVE;            /* we start transmitting */
  583 
  584         if(sc->sc_trace & TRACE_B_TX)   /* if trace, send mbuf to trace dev */
  585         {
  586                 i4b_trace_hdr hdr;
  587                 hdr.type = (h_chan == IWIC_BCH_A ? TRC_CH_B1 : TRC_CH_B2);
  588                 hdr.dir = FROM_TE;
  589                 hdr.count = ++sc->sc_bchan[h_chan].sc_trace_bcount;
  590                 isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
  591         }
  592 
  593         len = 0;        /* # of chars put into tx fifo this time */
  594 
  595         /*
  596          * fill the tx fifo with data from the current mbuf. if
  597          * current mbuf holds less data than fifo length, try to
  598          * get the next mbuf from (a possible) mbuf chain. if there is
  599          * not enough data in a single mbuf or in a chain, then this
  600          * is the last mbuf and we tell the chip that it has to send
  601          * CRC and closing flag
  602          */
  603          
  604         while((len < IWIC_BCHAN_FIFO_LEN) && chan->out_mbuf_cur)
  605         {
  606                 /*
  607                  * put as much data into the fifo as is
  608                  * available from the current mbuf
  609                  */
  610                  
  611                 if((len + chan->out_mbuf_cur_len) >= IWIC_BCHAN_FIFO_LEN)
  612                         next_len = IWIC_BCHAN_FIFO_LEN - len;
  613                 else
  614                         next_len = chan->out_mbuf_cur_len;
  615 
  616                 /* write what we have from current mbuf to fifo */
  617 
  618                 IWIC_WRBFIFO(sc, chan, chan->out_mbuf_cur_ptr, next_len);
  619                 
  620                 len += next_len;                /* update # of bytes written */
  621                 chan->txcount += next_len;      /* statistics */
  622                 chan->out_mbuf_cur_ptr += next_len;     /* data ptr */
  623                 chan->out_mbuf_cur_len -= next_len;     /* data len */
  624 
  625                 /*
  626                  * in case the current mbuf (of a possible chain) data
  627                  * has been put into the fifo, check if there is a next
  628                  * mbuf in the chain. If there is one, get ptr to it
  629                  * and update the data ptr and the length
  630                  */
  631                  
  632                 if((chan->out_mbuf_cur_len <= 0)        &&
  633                   ((chan->out_mbuf_cur = chan->out_mbuf_cur->m_next) != NULL))
  634                 {
  635                         chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
  636                         chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
  637 
  638                         if(sc->sc_trace & TRACE_B_TX)
  639                         {
  640                                 i4b_trace_hdr hdr;
  641                                 hdr.type = (h_chan == IWIC_BCH_A ? TRC_CH_B1 : TRC_CH_B2);
  642                                 hdr.dir = FROM_TE;
  643                                 hdr.count = ++sc->sc_bchan[h_chan].sc_trace_bcount;
  644                                 isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
  645                         }
  646                 }
  647         }
  648 
  649         /*
  650          * if there is either still data in the current mbuf and/or
  651          * there is a successor on the chain available issue just
  652          * a XTF (transmit) command to the chip. if there is no more
  653          * data available from the current mbuf (-chain), issue
  654          * an XTF and an XME (message end) command which will then
  655          * send the CRC and the closing HDLC flag sequence
  656          */
  657          
  658         if(chan->out_mbuf_cur && (chan->out_mbuf_cur_len > 0))
  659         {
  660                 /*
  661                  * more data available, send current fifo out.
  662                  * next xfer to tx fifo is done in the
  663                  * interrupt routine.
  664                  */
  665                  
  666                 cmd |= B_CMDR_XMS;
  667         }
  668         else
  669         {
  670                 /* end of mbuf chain */
  671         
  672                 if(chan->bprot == BPROT_NONE)
  673                         cmd |= B_CMDR_XMS;
  674                 else
  675                         cmd |= (B_CMDR_XMS | B_CMDR_XME);
  676                 
  677                 i4b_Bfreembuf(chan->out_mbuf_head);     /* free mbuf chain */
  678                 
  679                 chan->out_mbuf_head = NULL;
  680                 chan->out_mbuf_cur = NULL;                      
  681                 chan->out_mbuf_cur_ptr = NULL;
  682                 chan->out_mbuf_cur_len = 0;
  683         }
  684 
  685         /* call timeout handling routine */
  686         
  687         if(activity == ACT_RX || activity == ACT_TX)
  688                 (*chan->l4_driver->bch_activity)(chan->l4_driver_softc, activity);
  689 
  690         if(cmd)
  691         {
  692                 cmd |= B_CMDR_RACT;
  693                 IWIC_WRITE(sc, chan->offset + B_CMDR, cmd);
  694         }
  695                 
  696         splx(s);        
  697 }
  698 
  699 /*---------------------------------------------------------------------------*
  700  *      return B-channel statistics
  701  *---------------------------------------------------------------------------*/
  702 static void
  703 iwic_bchannel_stat(isdn_layer1token t, int h_chan, bchan_statistics_t *bsp)
  704 {
  705         struct iwic_softc *sc = t;
  706         struct iwic_bchan *bchan = &sc->sc_bchan[h_chan];
  707 
  708         int s = splnet();
  709 
  710         bsp->outbytes = bchan->txcount;
  711         bsp->inbytes = bchan->rxcount;
  712 
  713         bchan->txcount = 0;
  714         bchan->rxcount = 0;
  715 
  716         splx(s);
  717 }
  718 
  719 /*---------------------------------------------------------------------------*
  720  *      initialize our local linktab
  721  *---------------------------------------------------------------------------*/
  722 static const struct isdn_l4_bchannel_functions iwic_bchan_driver = {
  723         iwic_bchannel_setup,
  724         iwic_bchannel_start,
  725         iwic_bchannel_stat
  726 };
  727 
  728 void
  729 iwic_init_linktab(struct iwic_softc *sc)
  730 {
  731         struct iwic_bchan *chan;
  732         isdn_link_t *lt;
  733 
  734         /* channel A */
  735         
  736         chan = &sc->sc_bchan[IWIC_BCH_A];
  737         lt = &chan->iwic_isdn_linktab;
  738         
  739         lt->l1token = sc;
  740         lt->channel = IWIC_BCH_A;
  741         lt->bchannel_driver = &iwic_bchan_driver;
  742         lt->tx_queue = &chan->tx_queue;
  743 
  744         /* used by non-HDLC data transfers, i.e. telephony drivers */
  745         lt->rx_queue = &chan->rx_queue;
  746 
  747         /* used by HDLC data transfers, i.e. ipr and isp drivers */     
  748         lt->rx_mbuf = &chan->in_mbuf;   
  749                                                 
  750         /* channel B */
  751         
  752         chan = &sc->sc_bchan[IWIC_BCH_B];
  753         lt = &chan->iwic_isdn_linktab;
  754         
  755         lt->l1token = sc;
  756         lt->channel = IWIC_BCH_B;
  757         lt->bchannel_driver = &iwic_bchan_driver;
  758         lt->tx_queue = &chan->tx_queue;
  759 
  760         /* used by non-HDLC data transfers, i.e. telephony drivers */
  761         lt->rx_queue = &chan->rx_queue;
  762 
  763         /* used by HDLC data transfers, i.e. ipr and isp drivers */     
  764         lt->rx_mbuf = &chan->in_mbuf;   
  765 }

Cache object: 0011732be06dfdaaed7f34c1209f0b17


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