root/dev/usb/if_cdce.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cdce_match
  2. cdce_attach
  3. cdce_detach
  4. cdce_start
  5. cdce_encap
  6. cdce_stop
  7. cdce_ioctl
  8. cdce_watchdog
  9. cdce_init
  10. cdce_newbuf
  11. cdce_rx_list_init
  12. cdce_tx_list_init
  13. cdce_rxeof
  14. cdce_txeof
  15. cdce_activate
  16. cdce_intr
  17. cdce_crc32

    1 /*      $OpenBSD: if_cdce.c,v 1.36 2007/07/25 21:22:20 claudio Exp $ */
    2 
    3 /*
    4  * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wpaul@windriver.com>
    5  * Copyright (c) 2003 Craig Boston
    6  * Copyright (c) 2004 Daniel Hartmeier
    7  * All rights reserved.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. All advertising materials mentioning features or use of this software
   18  *    must display the following acknowledgement:
   19  *      This product includes software developed by Bill Paul.
   20  * 4. Neither the name of the author nor the names of any co-contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul, THE VOICES IN HIS HEAD OR
   28  * THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   30  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   31  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   32  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   33  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   34  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   35  */
   36 
   37 /*
   38  * USB Communication Device Class (Ethernet Networking Control Model)
   39  * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf
   40  *
   41  */
   42 
   43 #include <bpfilter.h>
   44 
   45 #include <sys/param.h>
   46 #include <sys/systm.h>
   47 #include <sys/sockio.h>
   48 #include <sys/mbuf.h>
   49 #include <sys/malloc.h>
   50 #include <sys/kernel.h>
   51 #include <sys/socket.h>
   52 #include <sys/device.h>
   53 #include <sys/proc.h>
   54 
   55 #include <net/if.h>
   56 #include <net/if_dl.h>
   57 
   58 #include <net/bpf.h>
   59 #if NBPFILTER > 0
   60 #endif
   61 
   62 #include <netinet/in.h>
   63 #include <netinet/in_systm.h>
   64 #include <netinet/in_var.h>
   65 #include <netinet/ip.h>
   66 #include <netinet/if_ether.h>
   67 
   68 #include <dev/usb/usb.h>
   69 #include <dev/usb/usbdi.h>
   70 #include <dev/usb/usbdi_util.h>
   71 #include <dev/usb/usbdevs.h>
   72 #include <dev/usb/usbcdc.h>
   73 
   74 #include <dev/usb/if_cdcereg.h>
   75 
   76 #ifdef CDCE_DEBUG
   77 #define DPRINTFN(n, x)  do { if (cdcedebug > (n)) printf x; } while (0)
   78 int cdcedebug = 0;
   79 #else
   80 #define DPRINTFN(n, x)
   81 #endif
   82 #define DPRINTF(x)      DPRINTFN(0, x)
   83 
   84 int      cdce_tx_list_init(struct cdce_softc *);
   85 int      cdce_rx_list_init(struct cdce_softc *);
   86 int      cdce_newbuf(struct cdce_softc *, struct cdce_chain *,
   87                     struct mbuf *);
   88 int      cdce_encap(struct cdce_softc *, struct mbuf *, int);
   89 void     cdce_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
   90 void     cdce_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
   91 void     cdce_start(struct ifnet *);
   92 int      cdce_ioctl(struct ifnet *, u_long, caddr_t);
   93 void     cdce_init(void *);
   94 void     cdce_watchdog(struct ifnet *);
   95 void     cdce_stop(struct cdce_softc *);
   96 void     cdce_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
   97 static uint32_t  cdce_crc32(const void *, size_t);
   98 
   99 const struct cdce_type cdce_devs[] = {
  100     {{ USB_VENDOR_ACERLABS, USB_PRODUCT_ACERLABS_M5632 }, 0 },
  101     {{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2501 }, 0 },
  102     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5500 }, CDCE_ZAURUS },
  103     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_A300 }, CDCE_ZAURUS },
  104     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5600 }, CDCE_ZAURUS },
  105     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C700 }, CDCE_ZAURUS },
  106     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C750 }, CDCE_ZAURUS },
  107     {{ USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN }, CDCE_ZAURUS },
  108     {{ USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN2 }, CDCE_ZAURUS },
  109     {{ USB_VENDOR_GMATE, USB_PRODUCT_GMATE_YP3X00 }, 0 },
  110     {{ USB_VENDOR_NETCHIP, USB_PRODUCT_NETCHIP_ETHERNETGADGET }, 0 },
  111     {{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQLINUX }, 0 },
  112     {{ USB_VENDOR_AMBIT, USB_PRODUCT_AMBIT_NTL_250 }, CDCE_SWAPUNION },
  113 };
  114 #define cdce_lookup(v, p) ((const struct cdce_type *)usb_lookup(cdce_devs, v, p))
  115 
  116 int cdce_match(struct device *, void *, void *); 
  117 void cdce_attach(struct device *, struct device *, void *); 
  118 int cdce_detach(struct device *, int); 
  119 int cdce_activate(struct device *, enum devact); 
  120 
  121 struct cfdriver cdce_cd = { 
  122         NULL, "cdce", DV_IFNET 
  123 }; 
  124 
  125 const struct cfattach cdce_ca = { 
  126         sizeof(struct cdce_softc), 
  127         cdce_match, 
  128         cdce_attach, 
  129         cdce_detach, 
  130         cdce_activate, 
  131 };
  132 
  133 int
  134 cdce_match(struct device *parent, void *match, void *aux)
  135 {
  136         struct usb_attach_arg *uaa = aux;
  137         usb_interface_descriptor_t *id;
  138 
  139         if (uaa->iface == NULL)
  140                 return (UMATCH_NONE);
  141 
  142         id = usbd_get_interface_descriptor(uaa->iface);
  143         if (id == NULL)
  144                 return (UMATCH_NONE);
  145 
  146         if (cdce_lookup(uaa->vendor, uaa->product) != NULL)
  147                 return (UMATCH_VENDOR_PRODUCT);
  148 
  149         if (id->bInterfaceClass == UICLASS_CDC && id->bInterfaceSubClass ==
  150             UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL)
  151                 return (UMATCH_IFACECLASS_GENERIC);
  152 
  153         return (UMATCH_NONE);
  154 }
  155 
  156 void
  157 cdce_attach(struct device *parent, struct device *self, void *aux)
  158 {
  159         struct cdce_softc               *sc = (struct cdce_softc *)self;
  160         struct usb_attach_arg           *uaa = aux;
  161         char                             *devinfop;
  162         int                              s;
  163         struct ifnet                    *ifp;
  164         usbd_device_handle               dev = uaa->device;
  165         const struct cdce_type          *t;
  166         usb_interface_descriptor_t      *id;
  167         usb_endpoint_descriptor_t       *ed;
  168         usb_cdc_union_descriptor_t      *ud;
  169         usb_cdc_ethernet_descriptor_t   *ethd;
  170         usb_config_descriptor_t         *cd;
  171         const usb_descriptor_t          *desc;
  172         usbd_desc_iter_t                 iter;
  173         usb_string_descriptor_t          eaddr_str;
  174         u_int16_t                        macaddr_hi;
  175         int                              i, j, numalts, len;
  176         int                              ctl_ifcno = -1;
  177         int                              data_ifcno = -1;
  178 
  179         devinfop = usbd_devinfo_alloc(dev, 0);
  180         printf("\n%s: %s\n", sc->cdce_dev.dv_xname, devinfop);
  181         usbd_devinfo_free(devinfop);
  182 
  183         sc->cdce_udev = uaa->device;
  184         sc->cdce_ctl_iface = uaa->iface;
  185         id = usbd_get_interface_descriptor(sc->cdce_ctl_iface);
  186         ctl_ifcno = id->bInterfaceNumber;
  187 
  188         t = cdce_lookup(uaa->vendor, uaa->product);
  189         if (t)
  190                 sc->cdce_flags = t->cdce_flags;
  191 
  192         /* Get the data interface no. and capabilities */
  193         ethd = NULL;
  194         usb_desc_iter_init(dev, &iter);
  195         desc = usb_desc_iter_next(&iter);
  196         while (desc) {
  197                 if (desc->bDescriptorType != UDESC_CS_INTERFACE) {
  198                         desc = usb_desc_iter_next(&iter);
  199                         continue;
  200                 }
  201                 switch(desc->bDescriptorSubtype) {
  202                 case UDESCSUB_CDC_UNION:
  203                         ud = (usb_cdc_union_descriptor_t *)desc; 
  204                         if ((sc->cdce_flags & CDCE_SWAPUNION) == 0 &&
  205                             ud->bMasterInterface == ctl_ifcno)
  206                                 data_ifcno = ud->bSlaveInterface[0];
  207                         if ((sc->cdce_flags & CDCE_SWAPUNION) &&
  208                             ud->bSlaveInterface[0] == ctl_ifcno)
  209                                 data_ifcno = ud->bMasterInterface;
  210                         break;
  211                 case UDESCSUB_CDC_ENF:
  212                         if (ethd) {
  213                                 printf("%s: ", sc->cdce_dev.dv_xname);
  214                                 printf("extra ethernet descriptor\n");
  215                                 return;
  216                         }
  217                         ethd = (usb_cdc_ethernet_descriptor_t *)desc;
  218                         break;
  219                 }
  220                 desc = usb_desc_iter_next(&iter);
  221         }
  222 
  223         if (data_ifcno == -1) {
  224                 DPRINTF(("cdce_attach: no union interface\n"));
  225                 sc->cdce_data_iface = sc->cdce_ctl_iface;
  226         } else {
  227                 DPRINTF(("cdce_attach: union interface: ctl=%d, data=%d\n",
  228                     ctl_ifcno, data_ifcno));
  229                 for (i = 0; i < uaa->nifaces; i++) {
  230                         if (uaa->ifaces[i] != NULL) {
  231                                 id = usbd_get_interface_descriptor(
  232                                     uaa->ifaces[i]);
  233                                 if (id != NULL && id->bInterfaceNumber ==
  234                                     data_ifcno) {
  235                                         sc->cdce_data_iface = uaa->ifaces[i];
  236                                         uaa->ifaces[i] = NULL;
  237                                 }
  238                         }
  239                 }
  240         }
  241 
  242         if (sc->cdce_data_iface == NULL) {
  243                 printf("%s: no data interface\n", sc->cdce_dev.dv_xname);
  244                 return;
  245         }
  246 
  247         id = usbd_get_interface_descriptor(sc->cdce_ctl_iface);
  248         sc->cdce_intr_no = -1;
  249         for (i = 0; i < id->bNumEndpoints && sc->cdce_intr_no == -1; i++) {
  250                 ed = usbd_interface2endpoint_descriptor(sc->cdce_ctl_iface, i);
  251                 if (!ed) {
  252                         printf("%s: no descriptor for interrupt endpoint %d\n",
  253                             sc->cdce_dev.dv_xname, i);
  254                         return;
  255                 }
  256                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
  257                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
  258                         sc->cdce_intr_no = ed->bEndpointAddress;
  259                         sc->cdce_intr_size = sizeof(sc->cdce_intr_buf);
  260                 }
  261         }
  262 
  263         id = usbd_get_interface_descriptor(sc->cdce_data_iface);
  264         cd = usbd_get_config_descriptor(sc->cdce_udev);
  265         numalts = usbd_get_no_alts(cd, id->bInterfaceNumber);
  266 
  267         for (j = 0; j < numalts; j++) {
  268             if (usbd_set_interface(sc->cdce_data_iface, j)) {
  269                 printf("%s: interface alternate setting %d failed\n", 
  270                     sc->cdce_dev.dv_xname, j);
  271                 return;
  272             } 
  273             /* Find endpoints. */
  274             id = usbd_get_interface_descriptor(sc->cdce_data_iface);
  275             sc->cdce_bulkin_no = sc->cdce_bulkout_no = -1;
  276             for (i = 0; i < id->bNumEndpoints; i++) {
  277                 ed = usbd_interface2endpoint_descriptor(sc->cdce_data_iface, i);
  278                 if (!ed) {
  279                         printf("%s: no descriptor for bulk endpoint %d\n",
  280                             sc->cdce_dev.dv_xname, i);
  281                         return;
  282                 }
  283                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
  284                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
  285                         sc->cdce_bulkin_no = ed->bEndpointAddress;
  286                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
  287                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
  288                         sc->cdce_bulkout_no = ed->bEndpointAddress;
  289                 }
  290 #ifdef CDCE_DEBUG
  291                 else if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN &&
  292                     UE_GET_XFERTYPE(ed->bmAttributes) != UE_INTERRUPT) {
  293                         printf("%s: unexpected endpoint, ep=%x attr=%x\n",
  294                             sc->cdce_dev.dv_xname, ed->bEndpointAddress,
  295                             ed->bmAttributes);
  296                 }
  297 #endif
  298             }
  299             if ((sc->cdce_bulkin_no != -1) && (sc->cdce_bulkout_no != -1)) {
  300                 DPRINTF(("cdce_attach: intr=0x%x, in=0x%x, out=0x%x\n",
  301                     sc->cdce_intr_no, sc->cdce_bulkin_no, sc->cdce_bulkout_no));
  302                 goto found;
  303             }
  304         }
  305         
  306         if (sc->cdce_bulkin_no == -1) {
  307                 printf("%s: could not find data bulk in\n",
  308                     sc->cdce_dev.dv_xname);
  309                 return;
  310         }
  311         if (sc->cdce_bulkout_no == -1 ) {
  312                 printf("%s: could not find data bulk out\n",
  313                     sc->cdce_dev.dv_xname);
  314                 return;
  315         }
  316 
  317 found:
  318         s = splnet();
  319 
  320         if (!ethd || usbd_get_string_desc(sc->cdce_udev, ethd->iMacAddress, 0,
  321             &eaddr_str, &len)) {
  322                 macaddr_hi = htons(0x2acb);
  323                 bcopy(&macaddr_hi, &sc->cdce_arpcom.ac_enaddr[0],
  324                     sizeof(u_int16_t));
  325                 bcopy(&ticks, &sc->cdce_arpcom.ac_enaddr[2], sizeof(u_int32_t));
  326                 sc->cdce_arpcom.ac_enaddr[5] = (u_int8_t)(sc->cdce_unit);
  327         } else {
  328                 for (i = 0; i < ETHER_ADDR_LEN * 2; i++) {
  329                         int c = UGETW(eaddr_str.bString[i]);
  330 
  331                         if ('0' <= c && c <= '9')
  332                                 c -= '0';
  333                         else if ('A' <= c && c <= 'F')
  334                                 c -= 'A' - 10;
  335                         else if ('a' <= c && c <= 'f')
  336                                 c -= 'a' - 10;
  337                         c &= 0xf;
  338                         if (i % 2 == 0)
  339                                 c <<= 4;
  340                         sc->cdce_arpcom.ac_enaddr[i / 2] |= c;
  341                 }
  342         }
  343 
  344         printf("%s: address %s\n", sc->cdce_dev.dv_xname,
  345             ether_sprintf(sc->cdce_arpcom.ac_enaddr));
  346 
  347         ifp = GET_IFP(sc);
  348         ifp->if_softc = sc;
  349         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  350         ifp->if_ioctl = cdce_ioctl;
  351         ifp->if_start = cdce_start;
  352         ifp->if_watchdog = cdce_watchdog;
  353         strlcpy(ifp->if_xname, sc->cdce_dev.dv_xname, IFNAMSIZ);
  354 
  355         IFQ_SET_READY(&ifp->if_snd);
  356 
  357         if_attach(ifp);
  358         ether_ifattach(ifp);
  359 
  360         sc->cdce_attached = 1;
  361         splx(s);
  362 
  363         usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->cdce_udev,
  364             &sc->cdce_dev);
  365 }
  366 
  367 int
  368 cdce_detach(struct device *self, int flags)
  369 {
  370         struct cdce_softc       *sc = (struct cdce_softc *)self;        
  371         struct ifnet            *ifp = GET_IFP(sc);
  372         int                      s;
  373 
  374         s = splusb();
  375 
  376         if (!sc->cdce_attached) {
  377                 splx(s);
  378                 return (0);
  379         }
  380 
  381         if (ifp->if_flags & IFF_RUNNING)
  382                 cdce_stop(sc);
  383 
  384         ether_ifdetach(ifp);
  385 
  386         if_detach(ifp);
  387 
  388         sc->cdce_attached = 0;
  389         splx(s);
  390 
  391         return (0);
  392 }
  393 
  394 void
  395 cdce_start(struct ifnet *ifp)
  396 {
  397         struct cdce_softc       *sc = ifp->if_softc;
  398         struct mbuf             *m_head = NULL;
  399 
  400         if (sc->cdce_dying || (ifp->if_flags & IFF_OACTIVE))
  401                 return;
  402 
  403         IFQ_POLL(&ifp->if_snd, m_head);
  404         if (m_head == NULL)
  405                 return;
  406 
  407         if (cdce_encap(sc, m_head, 0)) {
  408                 ifp->if_flags |= IFF_OACTIVE;
  409                 return;
  410         }
  411 
  412         IFQ_DEQUEUE(&ifp->if_snd, m_head);
  413 
  414 #if NBPFILTER > 0
  415         if (ifp->if_bpf)
  416                 bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
  417 #endif
  418 
  419         ifp->if_flags |= IFF_OACTIVE;
  420 
  421         ifp->if_timer = 6;
  422 }
  423 
  424 int
  425 cdce_encap(struct cdce_softc *sc, struct mbuf *m, int idx)
  426 {
  427         struct cdce_chain       *c;
  428         usbd_status              err;
  429         int                      extra = 0;
  430 
  431         c = &sc->cdce_cdata.cdce_tx_chain[idx];
  432 
  433         m_copydata(m, 0, m->m_pkthdr.len, c->cdce_buf);
  434         if (sc->cdce_flags & CDCE_ZAURUS) {
  435                 /* Zaurus wants a 32-bit CRC appended to every frame */
  436                 u_int32_t crc;
  437 
  438                 crc = cdce_crc32(c->cdce_buf, m->m_pkthdr.len);
  439                 bcopy(&crc, c->cdce_buf + m->m_pkthdr.len, 4);
  440                 extra = 4;
  441         }
  442         c->cdce_mbuf = m;
  443 
  444         usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkout_pipe, c, c->cdce_buf,
  445             m->m_pkthdr.len + extra, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
  446             10000, cdce_txeof);
  447         err = usbd_transfer(c->cdce_xfer);
  448         if (err != USBD_IN_PROGRESS) {
  449                 cdce_stop(sc);
  450                 return (EIO);
  451         }
  452 
  453         sc->cdce_cdata.cdce_tx_cnt++;
  454 
  455         return (0);
  456 }
  457 
  458 void
  459 cdce_stop(struct cdce_softc *sc)
  460 {
  461         usbd_status      err;
  462         struct ifnet    *ifp = GET_IFP(sc);
  463         int              i;
  464 
  465         ifp->if_timer = 0;
  466         ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
  467 
  468         if (sc->cdce_bulkin_pipe != NULL) {
  469                 err = usbd_abort_pipe(sc->cdce_bulkin_pipe);
  470                 if (err)
  471                         printf("%s: abort rx pipe failed: %s\n",
  472                             sc->cdce_dev.dv_xname, usbd_errstr(err));
  473                 err = usbd_close_pipe(sc->cdce_bulkin_pipe);
  474                 if (err)
  475                         printf("%s: close rx pipe failed: %s\n",
  476                             sc->cdce_dev.dv_xname, usbd_errstr(err));
  477                 sc->cdce_bulkin_pipe = NULL;
  478         }
  479 
  480         if (sc->cdce_bulkout_pipe != NULL) {
  481                 err = usbd_abort_pipe(sc->cdce_bulkout_pipe);
  482                 if (err)
  483                         printf("%s: abort tx pipe failed: %s\n",
  484                             sc->cdce_dev.dv_xname, usbd_errstr(err));
  485                 err = usbd_close_pipe(sc->cdce_bulkout_pipe);
  486                 if (err)
  487                         printf("%s: close tx pipe failed: %s\n",
  488                             sc->cdce_dev.dv_xname, usbd_errstr(err));
  489                 sc->cdce_bulkout_pipe = NULL;
  490         }
  491 
  492         if (sc->cdce_intr_pipe != NULL) {
  493                 err = usbd_abort_pipe(sc->cdce_intr_pipe);
  494                 if (err)
  495                         printf("%s: abort interrupt pipe failed: %s\n",
  496                             sc->cdce_dev.dv_xname, usbd_errstr(err));
  497                 err = usbd_close_pipe(sc->cdce_intr_pipe);
  498                 if (err)
  499                         printf("%s: close interrupt pipe failed: %s\n",
  500                             sc->cdce_dev.dv_xname, usbd_errstr(err));
  501                 sc->cdce_intr_pipe = NULL;
  502         }
  503 
  504         for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
  505                 if (sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf != NULL) {
  506                         m_freem(sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf);
  507                         sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf = NULL;
  508                 }
  509                 if (sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer != NULL) {
  510                         usbd_free_xfer(sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer);
  511                         sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer = NULL;
  512                 }
  513         }
  514 
  515         for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
  516                 if (sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf != NULL) {
  517                         m_freem(sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf);
  518                         sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf = NULL;
  519                 }
  520                 if (sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer != NULL) {
  521                         usbd_free_xfer(sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer);
  522                         sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer = NULL;
  523                 }
  524         }
  525 }
  526 
  527 int
  528 cdce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
  529 {
  530         struct cdce_softc       *sc = ifp->if_softc;
  531         struct ifaddr           *ifa = (struct ifaddr *)data;
  532         struct ifreq            *ifr = (struct ifreq *)data;
  533         int                      s, error = 0;
  534 
  535         if (sc->cdce_dying)
  536                 return (EIO);
  537 
  538         s = splnet();
  539 
  540         switch(command) {
  541         case SIOCSIFADDR:
  542                 ifp->if_flags |= IFF_UP;
  543                 cdce_init(sc);
  544                 switch (ifa->ifa_addr->sa_family) {
  545                 case AF_INET:
  546                         arp_ifinit(&sc->cdce_arpcom, ifa);
  547                         break;
  548                 }
  549                 break;
  550 
  551         case SIOCSIFMTU:
  552                 if (ifr->ifr_mtu > ETHERMTU)
  553                         error = EINVAL;
  554                 else
  555                         ifp->if_mtu = ifr->ifr_mtu;
  556                 break;
  557 
  558         case SIOCSIFFLAGS:
  559                 if (ifp->if_flags & IFF_UP) {
  560                         if (!(ifp->if_flags & IFF_RUNNING))
  561                                 cdce_init(sc);
  562                 } else {
  563                         if (ifp->if_flags & IFF_RUNNING)
  564                                 cdce_stop(sc);
  565                 }
  566                 error = 0;
  567                 break;
  568 
  569         case SIOCADDMULTI:
  570         case SIOCDELMULTI:
  571                 error = (command == SIOCADDMULTI) ?
  572                     ether_addmulti(ifr, &sc->cdce_arpcom) :
  573                     ether_delmulti(ifr, &sc->cdce_arpcom);
  574 
  575                 if (error == ENETRESET)
  576                         error = 0;
  577                 break;
  578 
  579         default:
  580                 error = EINVAL;
  581                 break;
  582         }
  583 
  584         splx(s);
  585 
  586         return (error);
  587 }
  588 
  589 void
  590 cdce_watchdog(struct ifnet *ifp)
  591 {
  592         struct cdce_softc       *sc = ifp->if_softc;
  593 
  594         if (sc->cdce_dying)
  595                 return;
  596 
  597         ifp->if_oerrors++;
  598         printf("%s: watchdog timeout\n", sc->cdce_dev.dv_xname);
  599 }
  600 
  601 void
  602 cdce_init(void *xsc)
  603 {
  604         struct cdce_softc       *sc = xsc;
  605         struct ifnet            *ifp = GET_IFP(sc);
  606         struct cdce_chain       *c;
  607         usbd_status              err;
  608         int                      s, i;
  609 
  610         if (ifp->if_flags & IFF_RUNNING)
  611                 return;
  612 
  613         s = splnet();
  614 
  615         if (sc->cdce_intr_no != -1 && sc->cdce_intr_pipe == NULL) {
  616                 DPRINTFN(1, ("cdce_init: establish interrupt pipe\n"));
  617                 err = usbd_open_pipe_intr(sc->cdce_ctl_iface, sc->cdce_intr_no,
  618                     USBD_SHORT_XFER_OK, &sc->cdce_intr_pipe, sc,
  619                     &sc->cdce_intr_buf, sc->cdce_intr_size, cdce_intr,
  620                     USBD_DEFAULT_INTERVAL);
  621                 if (err) {
  622                         printf("%s: open interrupt pipe failed: %s\n",
  623                             sc->cdce_dev.dv_xname, usbd_errstr(err));
  624                         splx(s);
  625                         return;
  626                 }
  627         }
  628 
  629         if (cdce_tx_list_init(sc) == ENOBUFS) {
  630                 printf("%s: tx list init failed\n", sc->cdce_dev.dv_xname);
  631                 splx(s);
  632                 return;
  633         }
  634 
  635         if (cdce_rx_list_init(sc) == ENOBUFS) {
  636                 printf("%s: rx list init failed\n", sc->cdce_dev.dv_xname);
  637                 splx(s);
  638                 return;
  639         }
  640 
  641         /* Maybe set multicast / broadcast here??? */
  642 
  643         err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkin_no,
  644             USBD_EXCLUSIVE_USE, &sc->cdce_bulkin_pipe);
  645         if (err) {
  646                 printf("%s: open rx pipe failed: %s\n", sc->cdce_dev.dv_xname,
  647                     usbd_errstr(err));
  648                 splx(s);
  649                 return;
  650         }
  651 
  652         err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkout_no,
  653             USBD_EXCLUSIVE_USE, &sc->cdce_bulkout_pipe);
  654         if (err) {
  655                 printf("%s: open tx pipe failed: %s\n", sc->cdce_dev.dv_xname,
  656                     usbd_errstr(err));
  657                 splx(s);
  658                 return;
  659         }
  660 
  661         for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
  662                 c = &sc->cdce_cdata.cdce_rx_chain[i];
  663                 usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c,
  664                     c->cdce_buf, CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
  665                     USBD_NO_TIMEOUT, cdce_rxeof);
  666                 usbd_transfer(c->cdce_xfer);
  667         }
  668 
  669         ifp->if_flags |= IFF_RUNNING;
  670         ifp->if_flags &= ~IFF_OACTIVE;
  671 
  672         splx(s);
  673 }
  674 
  675 int
  676 cdce_newbuf(struct cdce_softc *sc, struct cdce_chain *c, struct mbuf *m)
  677 {
  678         struct mbuf     *m_new = NULL;
  679 
  680         if (m == NULL) {
  681                 MGETHDR(m_new, M_DONTWAIT, MT_DATA);
  682                 if (m_new == NULL) {
  683                         printf("%s: no memory for rx list "
  684                             "-- packet dropped!\n", sc->cdce_dev.dv_xname);
  685                         return (ENOBUFS);
  686                 }
  687                 MCLGET(m_new, M_DONTWAIT);
  688                 if (!(m_new->m_flags & M_EXT)) {
  689                         printf("%s: no memory for rx list "
  690                             "-- packet dropped!\n", sc->cdce_dev.dv_xname);
  691                         m_freem(m_new);
  692                         return (ENOBUFS);
  693                 }
  694                 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
  695         } else {
  696                 m_new = m;
  697                 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
  698                 m_new->m_data = m_new->m_ext.ext_buf;
  699         }
  700 
  701         m_adj(m_new, ETHER_ALIGN);
  702         c->cdce_mbuf = m_new;
  703         return (0);
  704 }
  705 
  706 int
  707 cdce_rx_list_init(struct cdce_softc *sc)
  708 {
  709         struct cdce_cdata       *cd;
  710         struct cdce_chain       *c;
  711         int                      i;
  712 
  713         cd = &sc->cdce_cdata;
  714         for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
  715                 c = &cd->cdce_rx_chain[i];
  716                 c->cdce_sc = sc;
  717                 c->cdce_idx = i;
  718                 if (cdce_newbuf(sc, c, NULL) == ENOBUFS)
  719                         return (ENOBUFS);
  720                 if (c->cdce_xfer == NULL) {
  721                         c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
  722                         if (c->cdce_xfer == NULL)
  723                                 return (ENOBUFS);
  724                         c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer, CDCE_BUFSZ);
  725                         if (c->cdce_buf == NULL)
  726                                 return (ENOBUFS);
  727                 }
  728         }
  729 
  730         return (0);
  731 }
  732 
  733 int
  734 cdce_tx_list_init(struct cdce_softc *sc)
  735 {
  736         struct cdce_cdata       *cd;
  737         struct cdce_chain       *c;
  738         int                      i;
  739 
  740         cd = &sc->cdce_cdata;
  741         for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
  742                 c = &cd->cdce_tx_chain[i];
  743                 c->cdce_sc = sc;
  744                 c->cdce_idx = i;
  745                 c->cdce_mbuf = NULL;
  746                 if (c->cdce_xfer == NULL) {
  747                         c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
  748                         if (c->cdce_xfer == NULL)
  749                                 return (ENOBUFS);
  750                         c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer, CDCE_BUFSZ);
  751                         if (c->cdce_buf == NULL)
  752                                 return (ENOBUFS);
  753                 }
  754         }
  755 
  756         return (0);
  757 }
  758 
  759 void
  760 cdce_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
  761 {
  762         struct cdce_chain       *c = priv;
  763         struct cdce_softc       *sc = c->cdce_sc;
  764         struct ifnet            *ifp = GET_IFP(sc);
  765         struct mbuf             *m;
  766         int                      total_len = 0;
  767         int                      s;
  768 
  769         if (sc->cdce_dying || !(ifp->if_flags & IFF_RUNNING))
  770                 return;
  771 
  772         if (status != USBD_NORMAL_COMPLETION) {
  773                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
  774                         return;
  775                 if (sc->cdce_rxeof_errors == 0)
  776                         printf("%s: usb error on rx: %s\n",
  777                             sc->cdce_dev.dv_xname, usbd_errstr(status));
  778                 if (status == USBD_STALLED)
  779                         usbd_clear_endpoint_stall_async(sc->cdce_bulkin_pipe);
  780                 DELAY(sc->cdce_rxeof_errors * 10000);
  781                 if (sc->cdce_rxeof_errors++ > 10) {
  782                         printf("%s: too many errors, disabling\n",
  783                             sc->cdce_dev.dv_xname);
  784                         sc->cdce_dying = 1;
  785                         return;
  786                 }
  787                 goto done;
  788         }
  789 
  790         sc->cdce_rxeof_errors = 0;
  791 
  792         usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
  793         if (sc->cdce_flags & CDCE_ZAURUS)
  794                 total_len -= 4; /* Strip off CRC added by Zaurus */
  795         if (total_len <= 1)
  796                 goto done;
  797 
  798         m = c->cdce_mbuf;
  799         memcpy(mtod(m, char *), c->cdce_buf, total_len);
  800 
  801         if (total_len < sizeof(struct ether_header)) {
  802                 ifp->if_ierrors++;
  803                 goto done;
  804         }
  805 
  806         ifp->if_ipackets++;
  807 
  808         m->m_pkthdr.len = m->m_len = total_len;
  809         m->m_pkthdr.rcvif = ifp;
  810 
  811         s = splnet();
  812 
  813         if (cdce_newbuf(sc, c, NULL) == ENOBUFS) {
  814                 ifp->if_ierrors++;
  815                 goto done1;
  816         }
  817 
  818 #if NBPFILTER > 0
  819         if (ifp->if_bpf)
  820                 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
  821 #endif
  822 
  823         ether_input_mbuf(ifp, m);
  824 
  825 done1:
  826         splx(s);
  827 
  828 done:
  829         /* Setup new transfer. */
  830         usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c, c->cdce_buf,
  831             CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
  832             cdce_rxeof);
  833         usbd_transfer(c->cdce_xfer);
  834 }
  835 
  836 void
  837 cdce_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
  838 {
  839         struct cdce_chain       *c = priv;
  840         struct cdce_softc       *sc = c->cdce_sc;
  841         struct ifnet            *ifp = GET_IFP(sc);
  842         usbd_status              err;
  843         int                      s;
  844 
  845         if (sc->cdce_dying)
  846                 return;
  847 
  848         s = splnet();
  849 
  850         ifp->if_timer = 0;
  851         ifp->if_flags &= ~IFF_OACTIVE;
  852 
  853         if (status != USBD_NORMAL_COMPLETION) {
  854                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
  855                         splx(s);
  856                         return;
  857                 }
  858                 ifp->if_oerrors++;
  859                 printf("%s: usb error on tx: %s\n", sc->cdce_dev.dv_xname,
  860                     usbd_errstr(status));
  861                 if (status == USBD_STALLED)
  862                         usbd_clear_endpoint_stall_async(sc->cdce_bulkout_pipe);
  863                 splx(s);
  864                 return;
  865         }
  866 
  867         usbd_get_xfer_status(c->cdce_xfer, NULL, NULL, NULL, &err);
  868 
  869         if (c->cdce_mbuf != NULL) {
  870                 m_freem(c->cdce_mbuf);
  871                 c->cdce_mbuf = NULL;
  872         }
  873 
  874         if (err)
  875                 ifp->if_oerrors++;
  876         else
  877                 ifp->if_opackets++;
  878 
  879         if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
  880                 cdce_start(ifp);
  881 
  882         splx(s);
  883 }
  884 
  885 int
  886 cdce_activate(struct device *self, enum devact act)
  887 {
  888         struct cdce_softc *sc = (struct cdce_softc *)self;
  889 
  890         switch (act) {
  891         case DVACT_ACTIVATE:
  892                 break;
  893 
  894         case DVACT_DEACTIVATE:
  895                 sc->cdce_dying = 1;
  896                 break;
  897         }
  898         return (0);
  899 }
  900 
  901 void
  902 cdce_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
  903 {
  904         struct cdce_softc       *sc = addr;
  905         usb_cdc_notification_t  *buf = &sc->cdce_intr_buf;
  906         usb_cdc_connection_speed_t      *speed;
  907         u_int32_t                count;
  908 
  909         if (status == USBD_CANCELLED)
  910                 return;
  911 
  912         if (status != USBD_NORMAL_COMPLETION) {
  913                 DPRINTFN(2, ("cdce_intr: status=%d\n", status));
  914                 if (status == USBD_STALLED)
  915                         usbd_clear_endpoint_stall_async(sc->cdce_intr_pipe);
  916                 return;
  917         }
  918 
  919         usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
  920 
  921         if (buf->bmRequestType == UCDC_NOTIFICATION) {
  922                 switch (buf->bNotification) {
  923                     case UCDC_N_NETWORK_CONNECTION:
  924                         DPRINTFN(1, ("cdce_intr: network %s\n",
  925                             UGETW(buf->wValue) ? "connected" : "disconnected"));
  926                         break;
  927                     case UCDC_N_CONNECTION_SPEED_CHANGE:
  928                         speed = (usb_cdc_connection_speed_t *)&buf->data;
  929                         DPRINTFN(1, ("cdce_intr: up=%d, down=%d\n",
  930                             UGETDW(speed->dwUSBitRate),
  931                             UGETDW(speed->dwDSBitRate)));
  932                         break;
  933                     default:
  934                         DPRINTF(("cdce_intr: bNotification 0x%x\n",
  935                             buf->bNotification));
  936                 }
  937         }
  938 #ifdef CDCE_DEBUG
  939         else {
  940                 printf("cdce_intr: bmRequestType=%d ", buf->bmRequestType);
  941                 printf("wValue=%d wIndex=%d wLength=%d\n", UGETW(buf->wValue),
  942                     UGETW(buf->wIndex), UGETW(buf->wLength));
  943         }
  944 #endif
  945 }
  946 
  947 
  948 /*  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
  949  *  code or tables extracted from it, as desired without restriction.
  950  */
  951 
  952 static uint32_t cdce_crc32_tab[] = {
  953         0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
  954         0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
  955         0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
  956         0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
  957         0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
  958         0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
  959         0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
  960         0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
  961         0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
  962         0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
  963         0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
  964         0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
  965         0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
  966         0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
  967         0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
  968         0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
  969         0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
  970         0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
  971         0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
  972         0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
  973         0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
  974         0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
  975         0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
  976         0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
  977         0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
  978         0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
  979         0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
  980         0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
  981         0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
  982         0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
  983         0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
  984         0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
  985         0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
  986         0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
  987         0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
  988         0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
  989         0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
  990         0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
  991         0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
  992         0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
  993         0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
  994         0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
  995         0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
  996 };
  997 
  998 uint32_t
  999 cdce_crc32(const void *buf, size_t size)
 1000 {
 1001         const uint8_t *p;
 1002         uint32_t crc;
 1003 
 1004         p = buf;
 1005         crc = ~0U;
 1006 
 1007         while (size--)
 1008                 crc = cdce_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
 1009 
 1010         return (htole32(crc) ^ ~0U);
 1011 }

/* [<][>][^][v][top][bottom][index][help] */