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/usb/misc/udbp.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 /*-
    2  * SPDX-License-Identifier: BSD-3-Clause
    3  *
    4  * Copyright (c) 1996-2000 Whistle Communications, Inc.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of author nor the names of its
   16  *    contributors may be used to endorse or promote products derived
   17  *    from this software without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY NICK HIBMA AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  *
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 /* Driver for arbitrary double bulk pipe devices.
   37  * The driver assumes that there will be the same driver on the other side.
   38  *
   39  * XXX Some more information on what the framing of the IP packets looks like.
   40  *
   41  * To take full advantage of bulk transmission, packets should be chosen
   42  * between 1k and 5k in size (1k to make sure the sending side starts
   43  * streaming, and <5k to avoid overflowing the system with small TDs).
   44  */
   45 
   46 /* probe/attach/detach:
   47  *  Connect the driver to the hardware and netgraph
   48  *
   49  *  The reason we submit a bulk in transfer is that USB does not know about
   50  *  interrupts. The bulk transfer continuously polls the device for data.
   51  *  While the device has no data available, the device NAKs the TDs. As soon
   52  *  as there is data, the transfer happens and the data comes flowing in.
   53  *
   54  *  In case you were wondering, interrupt transfers happen exactly that way.
   55  *  It therefore doesn't make sense to use the interrupt pipe to signal
   56  *  'data ready' and then schedule a bulk transfer to fetch it. That would
   57  *  incur a 2ms delay at least, without reducing bandwidth requirements.
   58  *
   59  */
   60 
   61 #include <sys/stdint.h>
   62 #include <sys/stddef.h>
   63 #include <sys/param.h>
   64 #include <sys/queue.h>
   65 #include <sys/types.h>
   66 #include <sys/systm.h>
   67 #include <sys/kernel.h>
   68 #include <sys/bus.h>
   69 #include <sys/module.h>
   70 #include <sys/lock.h>
   71 #include <sys/mutex.h>
   72 #include <sys/condvar.h>
   73 #include <sys/sysctl.h>
   74 #include <sys/sx.h>
   75 #include <sys/unistd.h>
   76 #include <sys/callout.h>
   77 #include <sys/malloc.h>
   78 #include <sys/priv.h>
   79 
   80 #include <dev/usb/usb.h>
   81 #include <dev/usb/usbdi.h>
   82 #include <dev/usb/usbdi_util.h>
   83 #include "usbdevs.h"
   84 
   85 #define USB_DEBUG_VAR udbp_debug
   86 #include <dev/usb/usb_debug.h>
   87 
   88 #include <sys/mbuf.h>
   89 
   90 #include <netgraph/ng_message.h>
   91 #include <netgraph/netgraph.h>
   92 #include <netgraph/ng_parse.h>
   93 #include <netgraph/bluetooth/include/ng_bluetooth.h>
   94 
   95 #include <dev/usb/misc/udbp.h>
   96 
   97 #ifdef USB_DEBUG
   98 static int udbp_debug = 0;
   99 
  100 static SYSCTL_NODE(_hw_usb, OID_AUTO, udbp, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
  101     "USB udbp");
  102 SYSCTL_INT(_hw_usb_udbp, OID_AUTO, debug, CTLFLAG_RWTUN,
  103     &udbp_debug, 0, "udbp debug level");
  104 #endif
  105 
  106 #define UDBP_TIMEOUT    2000            /* timeout on outbound transfers, in
  107                                          * msecs */
  108 #define UDBP_BUFFERSIZE MCLBYTES        /* maximum number of bytes in one
  109                                          * transfer */
  110 #define UDBP_T_WR       0
  111 #define UDBP_T_RD       1
  112 #define UDBP_T_WR_CS    2
  113 #define UDBP_T_RD_CS    3
  114 #define UDBP_T_MAX      4
  115 #define UDBP_Q_MAXLEN   50
  116 
  117 struct udbp_softc {
  118         struct mtx sc_mtx;
  119         struct ng_bt_mbufq sc_xmitq_hipri;      /* hi-priority transmit queue */
  120         struct ng_bt_mbufq sc_xmitq;    /* low-priority transmit queue */
  121 
  122         struct usb_xfer *sc_xfer[UDBP_T_MAX];
  123         node_p  sc_node;                /* back pointer to node */
  124         hook_p  sc_hook;                /* pointer to the hook */
  125         struct mbuf *sc_bulk_in_buffer;
  126 
  127         uint32_t sc_packets_in;         /* packets in from downstream */
  128         uint32_t sc_packets_out;        /* packets out towards downstream */
  129 
  130         uint8_t sc_flags;
  131 #define UDBP_FLAG_READ_STALL    0x01    /* read transfer stalled */
  132 #define UDBP_FLAG_WRITE_STALL   0x02    /* write transfer stalled */
  133 
  134         uint8_t sc_name[16];
  135 };
  136 
  137 /* prototypes */
  138 
  139 static int udbp_modload(module_t mod, int event, void *data);
  140 
  141 static device_probe_t udbp_probe;
  142 static device_attach_t udbp_attach;
  143 static device_detach_t udbp_detach;
  144 
  145 static usb_callback_t udbp_bulk_read_callback;
  146 static usb_callback_t udbp_bulk_read_clear_stall_callback;
  147 static usb_callback_t udbp_bulk_write_callback;
  148 static usb_callback_t udbp_bulk_write_clear_stall_callback;
  149 
  150 static void     udbp_bulk_read_complete(node_p, hook_p, void *, int);
  151 
  152 static ng_constructor_t ng_udbp_constructor;
  153 static ng_rcvmsg_t      ng_udbp_rcvmsg;
  154 static ng_shutdown_t    ng_udbp_rmnode;
  155 static ng_newhook_t     ng_udbp_newhook;
  156 static ng_connect_t     ng_udbp_connect;
  157 static ng_rcvdata_t     ng_udbp_rcvdata;
  158 static ng_disconnect_t  ng_udbp_disconnect;
  159 
  160 /* Parse type for struct ngudbpstat */
  161 static const struct ng_parse_struct_field
  162         ng_udbp_stat_type_fields[] = NG_UDBP_STATS_TYPE_INFO;
  163 
  164 static const struct ng_parse_type ng_udbp_stat_type = {
  165         &ng_parse_struct_type,
  166         &ng_udbp_stat_type_fields
  167 };
  168 
  169 /* List of commands and how to convert arguments to/from ASCII */
  170 static const struct ng_cmdlist ng_udbp_cmdlist[] = {
  171         {
  172                 NGM_UDBP_COOKIE,
  173                 NGM_UDBP_GET_STATUS,
  174                 "getstatus",
  175                 NULL,
  176                 &ng_udbp_stat_type,
  177         },
  178         {
  179                 NGM_UDBP_COOKIE,
  180                 NGM_UDBP_SET_FLAG,
  181                 "setflag",
  182                 &ng_parse_int32_type,
  183                 NULL
  184         },
  185         {0}
  186 };
  187 
  188 /* Netgraph node type descriptor */
  189 static struct ng_type ng_udbp_typestruct = {
  190         .version = NG_ABI_VERSION,
  191         .name = NG_UDBP_NODE_TYPE,
  192         .constructor = ng_udbp_constructor,
  193         .rcvmsg = ng_udbp_rcvmsg,
  194         .shutdown = ng_udbp_rmnode,
  195         .newhook = ng_udbp_newhook,
  196         .connect = ng_udbp_connect,
  197         .rcvdata = ng_udbp_rcvdata,
  198         .disconnect = ng_udbp_disconnect,
  199         .cmdlist = ng_udbp_cmdlist,
  200 };
  201 
  202 /* USB config */
  203 static const struct usb_config udbp_config[UDBP_T_MAX] = {
  204         [UDBP_T_WR] = {
  205                 .type = UE_BULK,
  206                 .endpoint = UE_ADDR_ANY,
  207                 .direction = UE_DIR_OUT,
  208                 .bufsize = UDBP_BUFFERSIZE,
  209                 .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
  210                 .callback = &udbp_bulk_write_callback,
  211                 .timeout = UDBP_TIMEOUT,
  212         },
  213 
  214         [UDBP_T_RD] = {
  215                 .type = UE_BULK,
  216                 .endpoint = UE_ADDR_ANY,
  217                 .direction = UE_DIR_IN,
  218                 .bufsize = UDBP_BUFFERSIZE,
  219                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
  220                 .callback = &udbp_bulk_read_callback,
  221         },
  222 
  223         [UDBP_T_WR_CS] = {
  224                 .type = UE_CONTROL,
  225                 .endpoint = 0x00,       /* Control pipe */
  226                 .direction = UE_DIR_ANY,
  227                 .bufsize = sizeof(struct usb_device_request),
  228                 .callback = &udbp_bulk_write_clear_stall_callback,
  229                 .timeout = 1000,        /* 1 second */
  230                 .interval = 50, /* 50ms */
  231         },
  232 
  233         [UDBP_T_RD_CS] = {
  234                 .type = UE_CONTROL,
  235                 .endpoint = 0x00,       /* Control pipe */
  236                 .direction = UE_DIR_ANY,
  237                 .bufsize = sizeof(struct usb_device_request),
  238                 .callback = &udbp_bulk_read_clear_stall_callback,
  239                 .timeout = 1000,        /* 1 second */
  240                 .interval = 50, /* 50ms */
  241         },
  242 };
  243 
  244 static device_method_t udbp_methods[] = {
  245         /* Device interface */
  246         DEVMETHOD(device_probe, udbp_probe),
  247         DEVMETHOD(device_attach, udbp_attach),
  248         DEVMETHOD(device_detach, udbp_detach),
  249 
  250         DEVMETHOD_END
  251 };
  252 
  253 static driver_t udbp_driver = {
  254         .name = "udbp",
  255         .methods = udbp_methods,
  256         .size = sizeof(struct udbp_softc),
  257 };
  258 
  259 static const STRUCT_USB_HOST_ID udbp_devs[] = {
  260         {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U258, 0)},
  261         {USB_VPI(USB_VENDOR_NETCHIP, USB_PRODUCT_NETCHIP_TURBOCONNECT, 0)},
  262         {USB_VPI(USB_VENDOR_NETCHIP, USB_PRODUCT_NETCHIP_GADGETZERO, 0)},
  263         {USB_VPI(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2301, 0)},
  264         {USB_VPI(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2302, 0)},
  265         {USB_VPI(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL27A1, 0)},
  266         {USB_VPI(USB_VENDOR_ANCHOR, USB_PRODUCT_ANCHOR_EZLINK, 0)},
  267         {USB_VPI(USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL620USB, 0)},
  268 };
  269 
  270 DRIVER_MODULE(udbp, uhub, udbp_driver, udbp_modload, NULL);
  271 MODULE_DEPEND(udbp, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION);
  272 MODULE_DEPEND(udbp, usb, 1, 1, 1);
  273 MODULE_VERSION(udbp, 1);
  274 USB_PNP_HOST_INFO(udbp_devs);
  275 
  276 static int
  277 udbp_modload(module_t mod, int event, void *data)
  278 {
  279         int error;
  280 
  281         switch (event) {
  282         case MOD_LOAD:
  283                 error = ng_newtype(&ng_udbp_typestruct);
  284                 if (error != 0) {
  285                         printf("%s: Could not register "
  286                             "Netgraph node type, error=%d\n",
  287                             NG_UDBP_NODE_TYPE, error);
  288                 }
  289                 break;
  290 
  291         case MOD_UNLOAD:
  292                 error = ng_rmtype(&ng_udbp_typestruct);
  293                 break;
  294 
  295         default:
  296                 error = EOPNOTSUPP;
  297                 break;
  298         }
  299         return (error);
  300 }
  301 
  302 static int
  303 udbp_probe(device_t dev)
  304 {
  305         struct usb_attach_arg *uaa = device_get_ivars(dev);
  306 
  307         if (uaa->usb_mode != USB_MODE_HOST)
  308                 return (ENXIO);
  309         if (uaa->info.bConfigIndex != 0)
  310                 return (ENXIO);
  311         if (uaa->info.bIfaceIndex != 0)
  312                 return (ENXIO);
  313 
  314         return (usbd_lookup_id_by_uaa(udbp_devs, sizeof(udbp_devs), uaa));
  315 }
  316 
  317 static int
  318 udbp_attach(device_t dev)
  319 {
  320         struct usb_attach_arg *uaa = device_get_ivars(dev);
  321         struct udbp_softc *sc = device_get_softc(dev);
  322         int error;
  323 
  324         device_set_usb_desc(dev);
  325 
  326         snprintf(sc->sc_name, sizeof(sc->sc_name),
  327             "%s", device_get_nameunit(dev));
  328 
  329         mtx_init(&sc->sc_mtx, "udbp lock", NULL, MTX_DEF | MTX_RECURSE);
  330 
  331         error = usbd_transfer_setup(uaa->device, &uaa->info.bIfaceIndex,
  332             sc->sc_xfer, udbp_config, UDBP_T_MAX, sc, &sc->sc_mtx);
  333         if (error) {
  334                 DPRINTF("error=%s\n", usbd_errstr(error));
  335                 goto detach;
  336         }
  337         NG_BT_MBUFQ_INIT(&sc->sc_xmitq, UDBP_Q_MAXLEN);
  338 
  339         NG_BT_MBUFQ_INIT(&sc->sc_xmitq_hipri, UDBP_Q_MAXLEN);
  340 
  341         /* create Netgraph node */
  342 
  343         if (ng_make_node_common(&ng_udbp_typestruct, &sc->sc_node) != 0) {
  344                 printf("%s: Could not create Netgraph node\n",
  345                     sc->sc_name);
  346                 sc->sc_node = NULL;
  347                 goto detach;
  348         }
  349         /* name node */
  350 
  351         if (ng_name_node(sc->sc_node, sc->sc_name) != 0) {
  352                 printf("%s: Could not name node\n",
  353                     sc->sc_name);
  354                 NG_NODE_UNREF(sc->sc_node);
  355                 sc->sc_node = NULL;
  356                 goto detach;
  357         }
  358         NG_NODE_SET_PRIVATE(sc->sc_node, sc);
  359 
  360         /* the device is now operational */
  361 
  362         return (0);                     /* success */
  363 
  364 detach:
  365         udbp_detach(dev);
  366         return (ENOMEM);                /* failure */
  367 }
  368 
  369 static int
  370 udbp_detach(device_t dev)
  371 {
  372         struct udbp_softc *sc = device_get_softc(dev);
  373 
  374         /* destroy Netgraph node */
  375 
  376         if (sc->sc_node != NULL) {
  377                 NG_NODE_SET_PRIVATE(sc->sc_node, NULL);
  378                 ng_rmnode_self(sc->sc_node);
  379                 sc->sc_node = NULL;
  380         }
  381         /* free USB transfers, if any */
  382 
  383         usbd_transfer_unsetup(sc->sc_xfer, UDBP_T_MAX);
  384 
  385         mtx_destroy(&sc->sc_mtx);
  386 
  387         /* destroy queues */
  388 
  389         NG_BT_MBUFQ_DESTROY(&sc->sc_xmitq);
  390         NG_BT_MBUFQ_DESTROY(&sc->sc_xmitq_hipri);
  391 
  392         /* extra check */
  393 
  394         if (sc->sc_bulk_in_buffer) {
  395                 m_freem(sc->sc_bulk_in_buffer);
  396                 sc->sc_bulk_in_buffer = NULL;
  397         }
  398         return (0);                     /* success */
  399 }
  400 
  401 static void
  402 udbp_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
  403 {
  404         struct udbp_softc *sc = usbd_xfer_softc(xfer);
  405         struct usb_page_cache *pc;
  406         struct mbuf *m;
  407         int actlen;
  408 
  409         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
  410 
  411         switch (USB_GET_STATE(xfer)) {
  412         case USB_ST_TRANSFERRED:
  413 
  414                 /* allocate new mbuf */
  415 
  416                 MGETHDR(m, M_NOWAIT, MT_DATA);
  417 
  418                 if (m == NULL) {
  419                         goto tr_setup;
  420                 }
  421 
  422                 if (!(MCLGET(m, M_NOWAIT))) {
  423                         m_freem(m);
  424                         goto tr_setup;
  425                 }
  426                 m->m_pkthdr.len = m->m_len = actlen;
  427 
  428                 pc = usbd_xfer_get_frame(xfer, 0);
  429                 usbd_copy_out(pc, 0, m->m_data, actlen);
  430 
  431                 sc->sc_bulk_in_buffer = m;
  432 
  433                 DPRINTF("received package %d bytes\n", actlen);
  434 
  435         case USB_ST_SETUP:
  436 tr_setup:
  437                 if (sc->sc_bulk_in_buffer) {
  438                         ng_send_fn(sc->sc_node, NULL, &udbp_bulk_read_complete, NULL, 0);
  439                         return;
  440                 }
  441                 if (sc->sc_flags & UDBP_FLAG_READ_STALL) {
  442                         usbd_transfer_start(sc->sc_xfer[UDBP_T_RD_CS]);
  443                         return;
  444                 }
  445                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
  446                 usbd_transfer_submit(xfer);
  447                 return;
  448 
  449         default:                        /* Error */
  450                 if (error != USB_ERR_CANCELLED) {
  451                         /* try to clear stall first */
  452                         sc->sc_flags |= UDBP_FLAG_READ_STALL;
  453                         usbd_transfer_start(sc->sc_xfer[UDBP_T_RD_CS]);
  454                 }
  455                 return;
  456         }
  457 }
  458 
  459 static void
  460 udbp_bulk_read_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error)
  461 {
  462         struct udbp_softc *sc = usbd_xfer_softc(xfer);
  463         struct usb_xfer *xfer_other = sc->sc_xfer[UDBP_T_RD];
  464 
  465         if (usbd_clear_stall_callback(xfer, xfer_other)) {
  466                 DPRINTF("stall cleared\n");
  467                 sc->sc_flags &= ~UDBP_FLAG_READ_STALL;
  468                 usbd_transfer_start(xfer_other);
  469         }
  470 }
  471 
  472 static void
  473 udbp_bulk_read_complete(node_p node, hook_p hook, void *arg1, int arg2)
  474 {
  475         struct udbp_softc *sc = NG_NODE_PRIVATE(node);
  476         struct mbuf *m;
  477         int error;
  478 
  479         if (sc == NULL) {
  480                 return;
  481         }
  482         mtx_lock(&sc->sc_mtx);
  483 
  484         m = sc->sc_bulk_in_buffer;
  485 
  486         if (m) {
  487                 sc->sc_bulk_in_buffer = NULL;
  488 
  489                 if ((sc->sc_hook == NULL) ||
  490                     NG_HOOK_NOT_VALID(sc->sc_hook)) {
  491                         DPRINTF("No upstream hook\n");
  492                         goto done;
  493                 }
  494                 sc->sc_packets_in++;
  495 
  496                 NG_SEND_DATA_ONLY(error, sc->sc_hook, m);
  497 
  498                 m = NULL;
  499         }
  500 done:
  501         if (m) {
  502                 m_freem(m);
  503         }
  504         /* start USB bulk-in transfer, if not already started */
  505 
  506         usbd_transfer_start(sc->sc_xfer[UDBP_T_RD]);
  507 
  508         mtx_unlock(&sc->sc_mtx);
  509 }
  510 
  511 static void
  512 udbp_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
  513 {
  514         struct udbp_softc *sc = usbd_xfer_softc(xfer);
  515         struct usb_page_cache *pc;
  516         struct mbuf *m;
  517 
  518         switch (USB_GET_STATE(xfer)) {
  519         case USB_ST_TRANSFERRED:
  520 
  521                 sc->sc_packets_out++;
  522 
  523         case USB_ST_SETUP:
  524                 if (sc->sc_flags & UDBP_FLAG_WRITE_STALL) {
  525                         usbd_transfer_start(sc->sc_xfer[UDBP_T_WR_CS]);
  526                         return;
  527                 }
  528                 /* get next mbuf, if any */
  529 
  530                 NG_BT_MBUFQ_DEQUEUE(&sc->sc_xmitq_hipri, m);
  531                 if (m == NULL) {
  532                         NG_BT_MBUFQ_DEQUEUE(&sc->sc_xmitq, m);
  533                         if (m == NULL) {
  534                                 DPRINTF("Data queue is empty\n");
  535                                 return;
  536                         }
  537                 }
  538                 if (m->m_pkthdr.len > MCLBYTES) {
  539                         DPRINTF("truncating large packet "
  540                             "from %d to %d bytes\n", m->m_pkthdr.len,
  541                             MCLBYTES);
  542                         m->m_pkthdr.len = MCLBYTES;
  543                 }
  544                 pc = usbd_xfer_get_frame(xfer, 0);
  545                 usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
  546 
  547                 usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len);
  548 
  549                 DPRINTF("packet out: %d bytes\n", m->m_pkthdr.len);
  550 
  551                 m_freem(m);
  552 
  553                 usbd_transfer_submit(xfer);
  554                 return;
  555 
  556         default:                        /* Error */
  557                 if (error != USB_ERR_CANCELLED) {
  558                         /* try to clear stall first */
  559                         sc->sc_flags |= UDBP_FLAG_WRITE_STALL;
  560                         usbd_transfer_start(sc->sc_xfer[UDBP_T_WR_CS]);
  561                 }
  562                 return;
  563         }
  564 }
  565 
  566 static void
  567 udbp_bulk_write_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error)
  568 {
  569         struct udbp_softc *sc = usbd_xfer_softc(xfer);
  570         struct usb_xfer *xfer_other = sc->sc_xfer[UDBP_T_WR];
  571 
  572         if (usbd_clear_stall_callback(xfer, xfer_other)) {
  573                 DPRINTF("stall cleared\n");
  574                 sc->sc_flags &= ~UDBP_FLAG_WRITE_STALL;
  575                 usbd_transfer_start(xfer_other);
  576         }
  577 }
  578 
  579 /***********************************************************************
  580  * Start of Netgraph methods
  581  **********************************************************************/
  582 
  583 /*
  584  * If this is a device node so this work is done in the attach()
  585  * routine and the constructor will return EINVAL as you should not be able
  586  * to create nodes that depend on hardware (unless you can add the hardware :)
  587  */
  588 static int
  589 ng_udbp_constructor(node_p node)
  590 {
  591         return (EINVAL);
  592 }
  593 
  594 /*
  595  * Give our ok for a hook to be added...
  596  * If we are not running this might kick a device into life.
  597  * Possibly decode information out of the hook name.
  598  * Add the hook's private info to the hook structure.
  599  * (if we had some). In this example, we assume that there is a
  600  * an array of structs, called 'channel' in the private info,
  601  * one for each active channel. The private
  602  * pointer of each hook points to the appropriate UDBP_hookinfo struct
  603  * so that the source of an input packet is easily identified.
  604  */
  605 static int
  606 ng_udbp_newhook(node_p node, hook_p hook, const char *name)
  607 {
  608         struct udbp_softc *sc = NG_NODE_PRIVATE(node);
  609         int32_t error = 0;
  610 
  611         if (strcmp(name, NG_UDBP_HOOK_NAME)) {
  612                 return (EINVAL);
  613         }
  614         mtx_lock(&sc->sc_mtx);
  615 
  616         if (sc->sc_hook != NULL) {
  617                 error = EISCONN;
  618         } else {
  619                 sc->sc_hook = hook;
  620                 NG_HOOK_SET_PRIVATE(hook, NULL);
  621         }
  622 
  623         mtx_unlock(&sc->sc_mtx);
  624 
  625         return (error);
  626 }
  627 
  628 /*
  629  * Get a netgraph control message.
  630  * Check it is one we understand. If needed, send a response.
  631  * We could save the address for an async action later, but don't here.
  632  * Always free the message.
  633  * The response should be in a malloc'd region that the caller can 'free'.
  634  * A response is not required.
  635  * Theoretically you could respond defferently to old message types if
  636  * the cookie in the header didn't match what we consider to be current
  637  * (so that old userland programs could continue to work).
  638  */
  639 static int
  640 ng_udbp_rcvmsg(node_p node, item_p item, hook_p lasthook)
  641 {
  642         struct udbp_softc *sc = NG_NODE_PRIVATE(node);
  643         struct ng_mesg *resp = NULL;
  644         int error = 0;
  645         struct ng_mesg *msg;
  646 
  647         NGI_GET_MSG(item, msg);
  648         /* Deal with message according to cookie and command */
  649         switch (msg->header.typecookie) {
  650         case NGM_UDBP_COOKIE:
  651                 switch (msg->header.cmd) {
  652                 case NGM_UDBP_GET_STATUS:
  653                         {
  654                                 struct ngudbpstat *stats;
  655 
  656                                 NG_MKRESPONSE(resp, msg, sizeof(*stats), M_NOWAIT);
  657                                 if (!resp) {
  658                                         error = ENOMEM;
  659                                         break;
  660                                 }
  661                                 stats = (struct ngudbpstat *)resp->data;
  662                                 mtx_lock(&sc->sc_mtx);
  663                                 stats->packets_in = sc->sc_packets_in;
  664                                 stats->packets_out = sc->sc_packets_out;
  665                                 mtx_unlock(&sc->sc_mtx);
  666                                 break;
  667                         }
  668                 case NGM_UDBP_SET_FLAG:
  669                         if (msg->header.arglen != sizeof(uint32_t)) {
  670                                 error = EINVAL;
  671                                 break;
  672                         }
  673                         DPRINTF("flags = 0x%08x\n",
  674                             *((uint32_t *)msg->data));
  675                         break;
  676                 default:
  677                         error = EINVAL; /* unknown command */
  678                         break;
  679                 }
  680                 break;
  681         default:
  682                 error = EINVAL;         /* unknown cookie type */
  683                 break;
  684         }
  685 
  686         /* Take care of synchronous response, if any */
  687         NG_RESPOND_MSG(error, node, item, resp);
  688         NG_FREE_MSG(msg);
  689         return (error);
  690 }
  691 
  692 /*
  693  * Accept data from the hook and queue it for output.
  694  */
  695 static int
  696 ng_udbp_rcvdata(hook_p hook, item_p item)
  697 {
  698         struct udbp_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
  699         struct ng_bt_mbufq *queue_ptr;
  700         struct mbuf *m;
  701         struct ng_tag_prio *ptag;
  702         int error;
  703 
  704         if (sc == NULL) {
  705                 NG_FREE_ITEM(item);
  706                 return (EHOSTDOWN);
  707         }
  708         NGI_GET_M(item, m);
  709         NG_FREE_ITEM(item);
  710 
  711         /*
  712          * Now queue the data for when it can be sent
  713          */
  714         ptag = (void *)m_tag_locate(m, NGM_GENERIC_COOKIE,
  715             NG_TAG_PRIO, NULL);
  716 
  717         if (ptag && (ptag->priority > NG_PRIO_CUTOFF))
  718                 queue_ptr = &sc->sc_xmitq_hipri;
  719         else
  720                 queue_ptr = &sc->sc_xmitq;
  721 
  722         mtx_lock(&sc->sc_mtx);
  723 
  724         if (NG_BT_MBUFQ_FULL(queue_ptr)) {
  725                 NG_BT_MBUFQ_DROP(queue_ptr);
  726                 NG_FREE_M(m);
  727                 error = ENOBUFS;
  728         } else {
  729                 NG_BT_MBUFQ_ENQUEUE(queue_ptr, m);
  730                 /*
  731                  * start bulk-out transfer, if not already started:
  732                  */
  733                 usbd_transfer_start(sc->sc_xfer[UDBP_T_WR]);
  734                 error = 0;
  735         }
  736 
  737         mtx_unlock(&sc->sc_mtx);
  738 
  739         return (error);
  740 }
  741 
  742 /*
  743  * Do local shutdown processing..
  744  * We are a persistent device, we refuse to go away, and
  745  * only remove our links and reset ourself.
  746  */
  747 static int
  748 ng_udbp_rmnode(node_p node)
  749 {
  750         struct udbp_softc *sc = NG_NODE_PRIVATE(node);
  751 
  752         /* Let old node go */
  753         NG_NODE_SET_PRIVATE(node, NULL);
  754         NG_NODE_UNREF(node);            /* forget it ever existed */
  755 
  756         if (sc == NULL) {
  757                 goto done;
  758         }
  759         /* Create Netgraph node */
  760         if (ng_make_node_common(&ng_udbp_typestruct, &sc->sc_node) != 0) {
  761                 printf("%s: Could not create Netgraph node\n",
  762                     sc->sc_name);
  763                 sc->sc_node = NULL;
  764                 goto done;
  765         }
  766         /* Name node */
  767         if (ng_name_node(sc->sc_node, sc->sc_name) != 0) {
  768                 printf("%s: Could not name Netgraph node\n",
  769                     sc->sc_name);
  770                 NG_NODE_UNREF(sc->sc_node);
  771                 sc->sc_node = NULL;
  772                 goto done;
  773         }
  774         NG_NODE_SET_PRIVATE(sc->sc_node, sc);
  775 
  776 done:
  777         if (sc) {
  778                 mtx_unlock(&sc->sc_mtx);
  779         }
  780         return (0);
  781 }
  782 
  783 /*
  784  * This is called once we've already connected a new hook to the other node.
  785  * It gives us a chance to balk at the last minute.
  786  */
  787 static int
  788 ng_udbp_connect(hook_p hook)
  789 {
  790         struct udbp_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
  791 
  792         /* probably not at splnet, force outward queueing */
  793         NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
  794 
  795         mtx_lock(&sc->sc_mtx);
  796 
  797         sc->sc_flags |= (UDBP_FLAG_READ_STALL |
  798             UDBP_FLAG_WRITE_STALL);
  799 
  800         /* start bulk-in transfer */
  801         usbd_transfer_start(sc->sc_xfer[UDBP_T_RD]);
  802 
  803         /* start bulk-out transfer */
  804         usbd_transfer_start(sc->sc_xfer[UDBP_T_WR]);
  805 
  806         mtx_unlock(&sc->sc_mtx);
  807 
  808         return (0);
  809 }
  810 
  811 /*
  812  * Dook disconnection
  813  *
  814  * For this type, removal of the last link destroys the node
  815  */
  816 static int
  817 ng_udbp_disconnect(hook_p hook)
  818 {
  819         struct udbp_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
  820         int error = 0;
  821 
  822         if (sc != NULL) {
  823                 mtx_lock(&sc->sc_mtx);
  824 
  825                 if (hook != sc->sc_hook) {
  826                         error = EINVAL;
  827                 } else {
  828                         /* stop bulk-in transfer */
  829                         usbd_transfer_stop(sc->sc_xfer[UDBP_T_RD_CS]);
  830                         usbd_transfer_stop(sc->sc_xfer[UDBP_T_RD]);
  831 
  832                         /* stop bulk-out transfer */
  833                         usbd_transfer_stop(sc->sc_xfer[UDBP_T_WR_CS]);
  834                         usbd_transfer_stop(sc->sc_xfer[UDBP_T_WR]);
  835 
  836                         /* cleanup queues */
  837                         NG_BT_MBUFQ_DRAIN(&sc->sc_xmitq);
  838                         NG_BT_MBUFQ_DRAIN(&sc->sc_xmitq_hipri);
  839 
  840                         if (sc->sc_bulk_in_buffer) {
  841                                 m_freem(sc->sc_bulk_in_buffer);
  842                                 sc->sc_bulk_in_buffer = NULL;
  843                         }
  844                         sc->sc_hook = NULL;
  845                 }
  846 
  847                 mtx_unlock(&sc->sc_mtx);
  848         }
  849         if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
  850             && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
  851                 ng_rmnode_self(NG_HOOK_NODE(hook));
  852 
  853         return (error);
  854 }

Cache object: 7e8314a35263eb356fb950e9fb93ac4c


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