102ac6454SAndrew Thompson /*- 202ac6454SAndrew Thompson * Copyright (c) 1996-2000 Whistle Communications, Inc. 302ac6454SAndrew Thompson * All rights reserved. 402ac6454SAndrew Thompson * 502ac6454SAndrew Thompson * Redistribution and use in source and binary forms, with or without 602ac6454SAndrew Thompson * modification, are permitted provided that the following conditions 702ac6454SAndrew Thompson * are met: 802ac6454SAndrew Thompson * 1. Redistributions of source code must retain the above copyright 902ac6454SAndrew Thompson * notice, this list of conditions and the following disclaimer. 1002ac6454SAndrew Thompson * 2. Redistributions in binary form must reproduce the above copyright 1102ac6454SAndrew Thompson * notice, this list of conditions and the following disclaimer in the 1202ac6454SAndrew Thompson * documentation and/or other materials provided with the distribution. 1302ac6454SAndrew Thompson * 3. Neither the name of author nor the names of its 1402ac6454SAndrew Thompson * contributors may be used to endorse or promote products derived 1502ac6454SAndrew Thompson * from this software without specific prior written permission. 1602ac6454SAndrew Thompson * 1702ac6454SAndrew Thompson * THIS SOFTWARE IS PROVIDED BY NICK HIBMA AND CONTRIBUTORS 1802ac6454SAndrew Thompson * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 1902ac6454SAndrew Thompson * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2002ac6454SAndrew Thompson * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 2102ac6454SAndrew Thompson * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2202ac6454SAndrew Thompson * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2302ac6454SAndrew Thompson * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2402ac6454SAndrew Thompson * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2502ac6454SAndrew Thompson * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2602ac6454SAndrew Thompson * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2702ac6454SAndrew Thompson * POSSIBILITY OF SUCH DAMAGE. 2802ac6454SAndrew Thompson * 2902ac6454SAndrew Thompson */ 3002ac6454SAndrew Thompson 3102ac6454SAndrew Thompson #include <sys/cdefs.h> 3202ac6454SAndrew Thompson __FBSDID("$FreeBSD$"); 3302ac6454SAndrew Thompson 3402ac6454SAndrew Thompson /* Driver for arbitrary double bulk pipe devices. 3502ac6454SAndrew Thompson * The driver assumes that there will be the same driver on the other side. 3602ac6454SAndrew Thompson * 3702ac6454SAndrew Thompson * XXX Some more information on what the framing of the IP packets looks like. 3802ac6454SAndrew Thompson * 3902ac6454SAndrew Thompson * To take full advantage of bulk transmission, packets should be chosen 4002ac6454SAndrew Thompson * between 1k and 5k in size (1k to make sure the sending side starts 4102ac6454SAndrew Thompson * streaming, and <5k to avoid overflowing the system with small TDs). 4202ac6454SAndrew Thompson */ 4302ac6454SAndrew Thompson 4402ac6454SAndrew Thompson 4502ac6454SAndrew Thompson /* probe/attach/detach: 4602ac6454SAndrew Thompson * Connect the driver to the hardware and netgraph 4702ac6454SAndrew Thompson * 4802ac6454SAndrew Thompson * The reason we submit a bulk in transfer is that USB does not know about 4902ac6454SAndrew Thompson * interrupts. The bulk transfer continuously polls the device for data. 5002ac6454SAndrew Thompson * While the device has no data available, the device NAKs the TDs. As soon 5102ac6454SAndrew Thompson * as there is data, the transfer happens and the data comes flowing in. 5202ac6454SAndrew Thompson * 5302ac6454SAndrew Thompson * In case you were wondering, interrupt transfers happen exactly that way. 5402ac6454SAndrew Thompson * It therefore doesn't make sense to use the interrupt pipe to signal 5502ac6454SAndrew Thompson * 'data ready' and then schedule a bulk transfer to fetch it. That would 5602ac6454SAndrew Thompson * incur a 2ms delay at least, without reducing bandwidth requirements. 5702ac6454SAndrew Thompson * 5802ac6454SAndrew Thompson */ 5902ac6454SAndrew Thompson 6002ac6454SAndrew Thompson #include "usbdevs.h" 6102ac6454SAndrew Thompson #include <dev/usb/usb.h> 6202ac6454SAndrew Thompson #include <dev/usb/usb_mfunc.h> 6302ac6454SAndrew Thompson #include <dev/usb/usb_error.h> 6402ac6454SAndrew Thompson 6502ac6454SAndrew Thompson #define USB_DEBUG_VAR udbp_debug 6602ac6454SAndrew Thompson 6702ac6454SAndrew Thompson #include <dev/usb/usb_core.h> 6802ac6454SAndrew Thompson #include <dev/usb/usb_debug.h> 6902ac6454SAndrew Thompson #include <dev/usb/usb_parse.h> 7002ac6454SAndrew Thompson #include <dev/usb/usb_lookup.h> 7102ac6454SAndrew Thompson #include <dev/usb/usb_util.h> 7202ac6454SAndrew Thompson #include <dev/usb/usb_busdma.h> 7302ac6454SAndrew Thompson 7402ac6454SAndrew Thompson #include <sys/mbuf.h> 7502ac6454SAndrew Thompson 7602ac6454SAndrew Thompson #include <netgraph/ng_message.h> 7702ac6454SAndrew Thompson #include <netgraph/netgraph.h> 7802ac6454SAndrew Thompson #include <netgraph/ng_parse.h> 7902ac6454SAndrew Thompson #include <netgraph/bluetooth/include/ng_bluetooth.h> 8002ac6454SAndrew Thompson 8102ac6454SAndrew Thompson #include <dev/usb/misc/udbp.h> 8202ac6454SAndrew Thompson 8302ac6454SAndrew Thompson #if USB_DEBUG 8402ac6454SAndrew Thompson static int udbp_debug = 0; 8502ac6454SAndrew Thompson 869360ae40SAndrew Thompson SYSCTL_NODE(_hw_usb, OID_AUTO, udbp, CTLFLAG_RW, 0, "USB udbp"); 879360ae40SAndrew Thompson SYSCTL_INT(_hw_usb_udbp, OID_AUTO, debug, CTLFLAG_RW, 8802ac6454SAndrew Thompson &udbp_debug, 0, "udbp debug level"); 8902ac6454SAndrew Thompson #endif 9002ac6454SAndrew Thompson 9102ac6454SAndrew Thompson #define UDBP_TIMEOUT 2000 /* timeout on outbound transfers, in 9202ac6454SAndrew Thompson * msecs */ 9302ac6454SAndrew Thompson #define UDBP_BUFFERSIZE MCLBYTES /* maximum number of bytes in one 9402ac6454SAndrew Thompson * transfer */ 9502ac6454SAndrew Thompson #define UDBP_T_WR 0 9602ac6454SAndrew Thompson #define UDBP_T_RD 1 9702ac6454SAndrew Thompson #define UDBP_T_WR_CS 2 9802ac6454SAndrew Thompson #define UDBP_T_RD_CS 3 9902ac6454SAndrew Thompson #define UDBP_T_MAX 4 10002ac6454SAndrew Thompson #define UDBP_Q_MAXLEN 50 10102ac6454SAndrew Thompson 10202ac6454SAndrew Thompson struct udbp_softc { 10302ac6454SAndrew Thompson 10402ac6454SAndrew Thompson struct mtx sc_mtx; 10502ac6454SAndrew Thompson struct ng_bt_mbufq sc_xmitq_hipri; /* hi-priority transmit queue */ 10602ac6454SAndrew Thompson struct ng_bt_mbufq sc_xmitq; /* low-priority transmit queue */ 10702ac6454SAndrew Thompson 108760bc48eSAndrew Thompson struct usb_xfer *sc_xfer[UDBP_T_MAX]; 10902ac6454SAndrew Thompson node_p sc_node; /* back pointer to node */ 11002ac6454SAndrew Thompson hook_p sc_hook; /* pointer to the hook */ 11102ac6454SAndrew Thompson struct mbuf *sc_bulk_in_buffer; 11202ac6454SAndrew Thompson 11302ac6454SAndrew Thompson uint32_t sc_packets_in; /* packets in from downstream */ 11402ac6454SAndrew Thompson uint32_t sc_packets_out; /* packets out towards downstream */ 11502ac6454SAndrew Thompson 11602ac6454SAndrew Thompson uint8_t sc_flags; 11702ac6454SAndrew Thompson #define UDBP_FLAG_READ_STALL 0x01 /* read transfer stalled */ 11802ac6454SAndrew Thompson #define UDBP_FLAG_WRITE_STALL 0x02 /* write transfer stalled */ 11902ac6454SAndrew Thompson 12002ac6454SAndrew Thompson uint8_t sc_name[16]; 12102ac6454SAndrew Thompson }; 12202ac6454SAndrew Thompson 12302ac6454SAndrew Thompson /* prototypes */ 12402ac6454SAndrew Thompson 12502ac6454SAndrew Thompson static int udbp_modload(module_t mod, int event, void *data); 12602ac6454SAndrew Thompson 12702ac6454SAndrew Thompson static device_probe_t udbp_probe; 12802ac6454SAndrew Thompson static device_attach_t udbp_attach; 12902ac6454SAndrew Thompson static device_detach_t udbp_detach; 13002ac6454SAndrew Thompson 131e0a69b51SAndrew Thompson static usb_callback_t udbp_bulk_read_callback; 132e0a69b51SAndrew Thompson static usb_callback_t udbp_bulk_read_clear_stall_callback; 133e0a69b51SAndrew Thompson static usb_callback_t udbp_bulk_write_callback; 134e0a69b51SAndrew Thompson static usb_callback_t udbp_bulk_write_clear_stall_callback; 13502ac6454SAndrew Thompson 13602ac6454SAndrew Thompson static void udbp_bulk_read_complete(node_p, hook_p, void *, int); 13702ac6454SAndrew Thompson 13802ac6454SAndrew Thompson static ng_constructor_t ng_udbp_constructor; 13902ac6454SAndrew Thompson static ng_rcvmsg_t ng_udbp_rcvmsg; 14002ac6454SAndrew Thompson static ng_shutdown_t ng_udbp_rmnode; 14102ac6454SAndrew Thompson static ng_newhook_t ng_udbp_newhook; 14202ac6454SAndrew Thompson static ng_connect_t ng_udbp_connect; 14302ac6454SAndrew Thompson static ng_rcvdata_t ng_udbp_rcvdata; 14402ac6454SAndrew Thompson static ng_disconnect_t ng_udbp_disconnect; 14502ac6454SAndrew Thompson 14602ac6454SAndrew Thompson /* Parse type for struct ngudbpstat */ 14702ac6454SAndrew Thompson static const struct ng_parse_struct_field 14802ac6454SAndrew Thompson ng_udbp_stat_type_fields[] = NG_UDBP_STATS_TYPE_INFO; 14902ac6454SAndrew Thompson 15002ac6454SAndrew Thompson static const struct ng_parse_type ng_udbp_stat_type = { 15102ac6454SAndrew Thompson &ng_parse_struct_type, 15202ac6454SAndrew Thompson &ng_udbp_stat_type_fields 15302ac6454SAndrew Thompson }; 15402ac6454SAndrew Thompson 15502ac6454SAndrew Thompson /* List of commands and how to convert arguments to/from ASCII */ 15602ac6454SAndrew Thompson static const struct ng_cmdlist ng_udbp_cmdlist[] = { 15702ac6454SAndrew Thompson { 15802ac6454SAndrew Thompson NGM_UDBP_COOKIE, 15902ac6454SAndrew Thompson NGM_UDBP_GET_STATUS, 16002ac6454SAndrew Thompson "getstatus", 16102ac6454SAndrew Thompson NULL, 16202ac6454SAndrew Thompson &ng_udbp_stat_type, 16302ac6454SAndrew Thompson }, 16402ac6454SAndrew Thompson { 16502ac6454SAndrew Thompson NGM_UDBP_COOKIE, 16602ac6454SAndrew Thompson NGM_UDBP_SET_FLAG, 16702ac6454SAndrew Thompson "setflag", 16802ac6454SAndrew Thompson &ng_parse_int32_type, 16902ac6454SAndrew Thompson NULL 17002ac6454SAndrew Thompson }, 17102ac6454SAndrew Thompson {0} 17202ac6454SAndrew Thompson }; 17302ac6454SAndrew Thompson 17402ac6454SAndrew Thompson /* Netgraph node type descriptor */ 17502ac6454SAndrew Thompson static struct ng_type ng_udbp_typestruct = { 17602ac6454SAndrew Thompson .version = NG_ABI_VERSION, 17702ac6454SAndrew Thompson .name = NG_UDBP_NODE_TYPE, 17802ac6454SAndrew Thompson .constructor = ng_udbp_constructor, 17902ac6454SAndrew Thompson .rcvmsg = ng_udbp_rcvmsg, 18002ac6454SAndrew Thompson .shutdown = ng_udbp_rmnode, 18102ac6454SAndrew Thompson .newhook = ng_udbp_newhook, 18202ac6454SAndrew Thompson .connect = ng_udbp_connect, 18302ac6454SAndrew Thompson .rcvdata = ng_udbp_rcvdata, 18402ac6454SAndrew Thompson .disconnect = ng_udbp_disconnect, 18502ac6454SAndrew Thompson .cmdlist = ng_udbp_cmdlist, 18602ac6454SAndrew Thompson }; 18702ac6454SAndrew Thompson 18802ac6454SAndrew Thompson /* USB config */ 189760bc48eSAndrew Thompson static const struct usb_config udbp_config[UDBP_T_MAX] = { 19002ac6454SAndrew Thompson 19102ac6454SAndrew Thompson [UDBP_T_WR] = { 19202ac6454SAndrew Thompson .type = UE_BULK, 19302ac6454SAndrew Thompson .endpoint = UE_ADDR_ANY, 19402ac6454SAndrew Thompson .direction = UE_DIR_OUT, 1954eae601eSAndrew Thompson .bufsize = UDBP_BUFFERSIZE, 1964eae601eSAndrew Thompson .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 1974eae601eSAndrew Thompson .callback = &udbp_bulk_write_callback, 1984eae601eSAndrew Thompson .timeout = UDBP_TIMEOUT, 19902ac6454SAndrew Thompson }, 20002ac6454SAndrew Thompson 20102ac6454SAndrew Thompson [UDBP_T_RD] = { 20202ac6454SAndrew Thompson .type = UE_BULK, 20302ac6454SAndrew Thompson .endpoint = UE_ADDR_ANY, 20402ac6454SAndrew Thompson .direction = UE_DIR_IN, 2054eae601eSAndrew Thompson .bufsize = UDBP_BUFFERSIZE, 2064eae601eSAndrew Thompson .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 2074eae601eSAndrew Thompson .callback = &udbp_bulk_read_callback, 20802ac6454SAndrew Thompson }, 20902ac6454SAndrew Thompson 21002ac6454SAndrew Thompson [UDBP_T_WR_CS] = { 21102ac6454SAndrew Thompson .type = UE_CONTROL, 21202ac6454SAndrew Thompson .endpoint = 0x00, /* Control pipe */ 21302ac6454SAndrew Thompson .direction = UE_DIR_ANY, 214760bc48eSAndrew Thompson .bufsize = sizeof(struct usb_device_request), 2154eae601eSAndrew Thompson .callback = &udbp_bulk_write_clear_stall_callback, 2164eae601eSAndrew Thompson .timeout = 1000, /* 1 second */ 2174eae601eSAndrew Thompson .interval = 50, /* 50ms */ 21802ac6454SAndrew Thompson }, 21902ac6454SAndrew Thompson 22002ac6454SAndrew Thompson [UDBP_T_RD_CS] = { 22102ac6454SAndrew Thompson .type = UE_CONTROL, 22202ac6454SAndrew Thompson .endpoint = 0x00, /* Control pipe */ 22302ac6454SAndrew Thompson .direction = UE_DIR_ANY, 224760bc48eSAndrew Thompson .bufsize = sizeof(struct usb_device_request), 2254eae601eSAndrew Thompson .callback = &udbp_bulk_read_clear_stall_callback, 2264eae601eSAndrew Thompson .timeout = 1000, /* 1 second */ 2274eae601eSAndrew Thompson .interval = 50, /* 50ms */ 22802ac6454SAndrew Thompson }, 22902ac6454SAndrew Thompson }; 23002ac6454SAndrew Thompson 23102ac6454SAndrew Thompson static devclass_t udbp_devclass; 23202ac6454SAndrew Thompson 23302ac6454SAndrew Thompson static device_method_t udbp_methods[] = { 23402ac6454SAndrew Thompson /* Device interface */ 23502ac6454SAndrew Thompson DEVMETHOD(device_probe, udbp_probe), 23602ac6454SAndrew Thompson DEVMETHOD(device_attach, udbp_attach), 23702ac6454SAndrew Thompson DEVMETHOD(device_detach, udbp_detach), 23802ac6454SAndrew Thompson {0, 0} 23902ac6454SAndrew Thompson }; 24002ac6454SAndrew Thompson 24102ac6454SAndrew Thompson static driver_t udbp_driver = { 24202ac6454SAndrew Thompson .name = "udbp", 24302ac6454SAndrew Thompson .methods = udbp_methods, 24402ac6454SAndrew Thompson .size = sizeof(struct udbp_softc), 24502ac6454SAndrew Thompson }; 24602ac6454SAndrew Thompson 2479aef556dSAndrew Thompson DRIVER_MODULE(udbp, uhub, udbp_driver, udbp_devclass, udbp_modload, 0); 24802ac6454SAndrew Thompson MODULE_DEPEND(udbp, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); 24902ac6454SAndrew Thompson MODULE_DEPEND(udbp, usb, 1, 1, 1); 25002ac6454SAndrew Thompson 25102ac6454SAndrew Thompson static int 25202ac6454SAndrew Thompson udbp_modload(module_t mod, int event, void *data) 25302ac6454SAndrew Thompson { 25402ac6454SAndrew Thompson int error; 25502ac6454SAndrew Thompson 25602ac6454SAndrew Thompson switch (event) { 25702ac6454SAndrew Thompson case MOD_LOAD: 25802ac6454SAndrew Thompson error = ng_newtype(&ng_udbp_typestruct); 25902ac6454SAndrew Thompson if (error != 0) { 26002ac6454SAndrew Thompson printf("%s: Could not register " 26102ac6454SAndrew Thompson "Netgraph node type, error=%d\n", 26202ac6454SAndrew Thompson NG_UDBP_NODE_TYPE, error); 26302ac6454SAndrew Thompson } 26402ac6454SAndrew Thompson break; 26502ac6454SAndrew Thompson 26602ac6454SAndrew Thompson case MOD_UNLOAD: 26702ac6454SAndrew Thompson error = ng_rmtype(&ng_udbp_typestruct); 26802ac6454SAndrew Thompson break; 26902ac6454SAndrew Thompson 27002ac6454SAndrew Thompson default: 27102ac6454SAndrew Thompson error = EOPNOTSUPP; 27202ac6454SAndrew Thompson break; 27302ac6454SAndrew Thompson } 27402ac6454SAndrew Thompson return (error); 27502ac6454SAndrew Thompson } 27602ac6454SAndrew Thompson 27702ac6454SAndrew Thompson static int 27802ac6454SAndrew Thompson udbp_probe(device_t dev) 27902ac6454SAndrew Thompson { 280760bc48eSAndrew Thompson struct usb_attach_arg *uaa = device_get_ivars(dev); 28102ac6454SAndrew Thompson 282f29a0724SAndrew Thompson if (uaa->usb_mode != USB_MODE_HOST) { 28302ac6454SAndrew Thompson return (ENXIO); 28402ac6454SAndrew Thompson } 28502ac6454SAndrew Thompson /* 28602ac6454SAndrew Thompson * XXX Julian, add the id of the device if you have one to test 28702ac6454SAndrew Thompson * things with. run 'usbdevs -v' and note the 3 ID's that appear. 28802ac6454SAndrew Thompson * The Vendor Id and Product Id are in hex and the Revision Id is in 28902ac6454SAndrew Thompson * bcd. But as usual if the revision is 0x101 then you should 29002ac6454SAndrew Thompson * compare the revision id in the device descriptor with 0x101 Or go 29102ac6454SAndrew Thompson * search the file usbdevs.h. Maybe the device is already in there. 29202ac6454SAndrew Thompson */ 29302ac6454SAndrew Thompson if (((uaa->info.idVendor == USB_VENDOR_NETCHIP) && 29402ac6454SAndrew Thompson (uaa->info.idProduct == USB_PRODUCT_NETCHIP_TURBOCONNECT))) 29502ac6454SAndrew Thompson return (0); 29602ac6454SAndrew Thompson 29702ac6454SAndrew Thompson if (((uaa->info.idVendor == USB_VENDOR_PROLIFIC) && 29802ac6454SAndrew Thompson ((uaa->info.idProduct == USB_PRODUCT_PROLIFIC_PL2301) || 29902ac6454SAndrew Thompson (uaa->info.idProduct == USB_PRODUCT_PROLIFIC_PL2302)))) 30002ac6454SAndrew Thompson return (0); 30102ac6454SAndrew Thompson 30202ac6454SAndrew Thompson if ((uaa->info.idVendor == USB_VENDOR_ANCHOR) && 30302ac6454SAndrew Thompson (uaa->info.idProduct == USB_PRODUCT_ANCHOR_EZLINK)) 30402ac6454SAndrew Thompson return (0); 30502ac6454SAndrew Thompson 30602ac6454SAndrew Thompson if ((uaa->info.idVendor == USB_VENDOR_GENESYS) && 30702ac6454SAndrew Thompson (uaa->info.idProduct == USB_PRODUCT_GENESYS_GL620USB)) 30802ac6454SAndrew Thompson return (0); 30902ac6454SAndrew Thompson 31002ac6454SAndrew Thompson return (ENXIO); 31102ac6454SAndrew Thompson } 31202ac6454SAndrew Thompson 31302ac6454SAndrew Thompson static int 31402ac6454SAndrew Thompson udbp_attach(device_t dev) 31502ac6454SAndrew Thompson { 316760bc48eSAndrew Thompson struct usb_attach_arg *uaa = device_get_ivars(dev); 31702ac6454SAndrew Thompson struct udbp_softc *sc = device_get_softc(dev); 31802ac6454SAndrew Thompson int error; 31902ac6454SAndrew Thompson 32002ac6454SAndrew Thompson device_set_usb2_desc(dev); 32102ac6454SAndrew Thompson 32202ac6454SAndrew Thompson snprintf(sc->sc_name, sizeof(sc->sc_name), 32302ac6454SAndrew Thompson "%s", device_get_nameunit(dev)); 32402ac6454SAndrew Thompson 32502ac6454SAndrew Thompson mtx_init(&sc->sc_mtx, "udbp lock", NULL, MTX_DEF | MTX_RECURSE); 32602ac6454SAndrew Thompson 32702ac6454SAndrew Thompson error = usb2_transfer_setup(uaa->device, &uaa->info.bIfaceIndex, 32802ac6454SAndrew Thompson sc->sc_xfer, udbp_config, UDBP_T_MAX, sc, &sc->sc_mtx); 32902ac6454SAndrew Thompson if (error) { 33002ac6454SAndrew Thompson DPRINTF("error=%s\n", usb2_errstr(error)); 33102ac6454SAndrew Thompson goto detach; 33202ac6454SAndrew Thompson } 33302ac6454SAndrew Thompson NG_BT_MBUFQ_INIT(&sc->sc_xmitq, UDBP_Q_MAXLEN); 33402ac6454SAndrew Thompson 33502ac6454SAndrew Thompson NG_BT_MBUFQ_INIT(&sc->sc_xmitq_hipri, UDBP_Q_MAXLEN); 33602ac6454SAndrew Thompson 33702ac6454SAndrew Thompson /* create Netgraph node */ 33802ac6454SAndrew Thompson 33902ac6454SAndrew Thompson if (ng_make_node_common(&ng_udbp_typestruct, &sc->sc_node) != 0) { 34002ac6454SAndrew Thompson printf("%s: Could not create Netgraph node\n", 34102ac6454SAndrew Thompson sc->sc_name); 34202ac6454SAndrew Thompson sc->sc_node = NULL; 34302ac6454SAndrew Thompson goto detach; 34402ac6454SAndrew Thompson } 34502ac6454SAndrew Thompson /* name node */ 34602ac6454SAndrew Thompson 34702ac6454SAndrew Thompson if (ng_name_node(sc->sc_node, sc->sc_name) != 0) { 34802ac6454SAndrew Thompson printf("%s: Could not name node\n", 34902ac6454SAndrew Thompson sc->sc_name); 35002ac6454SAndrew Thompson NG_NODE_UNREF(sc->sc_node); 35102ac6454SAndrew Thompson sc->sc_node = NULL; 35202ac6454SAndrew Thompson goto detach; 35302ac6454SAndrew Thompson } 35402ac6454SAndrew Thompson NG_NODE_SET_PRIVATE(sc->sc_node, sc); 35502ac6454SAndrew Thompson 35602ac6454SAndrew Thompson /* the device is now operational */ 35702ac6454SAndrew Thompson 35802ac6454SAndrew Thompson return (0); /* success */ 35902ac6454SAndrew Thompson 36002ac6454SAndrew Thompson detach: 36102ac6454SAndrew Thompson udbp_detach(dev); 36202ac6454SAndrew Thompson return (ENOMEM); /* failure */ 36302ac6454SAndrew Thompson } 36402ac6454SAndrew Thompson 36502ac6454SAndrew Thompson static int 36602ac6454SAndrew Thompson udbp_detach(device_t dev) 36702ac6454SAndrew Thompson { 36802ac6454SAndrew Thompson struct udbp_softc *sc = device_get_softc(dev); 36902ac6454SAndrew Thompson 37002ac6454SAndrew Thompson /* destroy Netgraph node */ 37102ac6454SAndrew Thompson 37202ac6454SAndrew Thompson if (sc->sc_node != NULL) { 37302ac6454SAndrew Thompson NG_NODE_SET_PRIVATE(sc->sc_node, NULL); 37402ac6454SAndrew Thompson ng_rmnode_self(sc->sc_node); 37502ac6454SAndrew Thompson sc->sc_node = NULL; 37602ac6454SAndrew Thompson } 37702ac6454SAndrew Thompson /* free USB transfers, if any */ 37802ac6454SAndrew Thompson 37902ac6454SAndrew Thompson usb2_transfer_unsetup(sc->sc_xfer, UDBP_T_MAX); 38002ac6454SAndrew Thompson 38102ac6454SAndrew Thompson mtx_destroy(&sc->sc_mtx); 38202ac6454SAndrew Thompson 38302ac6454SAndrew Thompson /* destroy queues */ 38402ac6454SAndrew Thompson 38502ac6454SAndrew Thompson NG_BT_MBUFQ_DESTROY(&sc->sc_xmitq); 38602ac6454SAndrew Thompson NG_BT_MBUFQ_DESTROY(&sc->sc_xmitq_hipri); 38702ac6454SAndrew Thompson 38802ac6454SAndrew Thompson /* extra check */ 38902ac6454SAndrew Thompson 39002ac6454SAndrew Thompson if (sc->sc_bulk_in_buffer) { 39102ac6454SAndrew Thompson m_freem(sc->sc_bulk_in_buffer); 39202ac6454SAndrew Thompson sc->sc_bulk_in_buffer = NULL; 39302ac6454SAndrew Thompson } 39402ac6454SAndrew Thompson return (0); /* success */ 39502ac6454SAndrew Thompson } 39602ac6454SAndrew Thompson 39702ac6454SAndrew Thompson static void 398760bc48eSAndrew Thompson udbp_bulk_read_callback(struct usb_xfer *xfer) 39902ac6454SAndrew Thompson { 40002ac6454SAndrew Thompson struct udbp_softc *sc = xfer->priv_sc; 40102ac6454SAndrew Thompson struct mbuf *m; 40202ac6454SAndrew Thompson 40302ac6454SAndrew Thompson switch (USB_GET_STATE(xfer)) { 40402ac6454SAndrew Thompson case USB_ST_TRANSFERRED: 40502ac6454SAndrew Thompson 40602ac6454SAndrew Thompson /* allocate new mbuf */ 40702ac6454SAndrew Thompson 40802ac6454SAndrew Thompson MGETHDR(m, M_DONTWAIT, MT_DATA); 40902ac6454SAndrew Thompson 41002ac6454SAndrew Thompson if (m == NULL) { 41102ac6454SAndrew Thompson goto tr_setup; 41202ac6454SAndrew Thompson } 41302ac6454SAndrew Thompson MCLGET(m, M_DONTWAIT); 41402ac6454SAndrew Thompson 41502ac6454SAndrew Thompson if (!(m->m_flags & M_EXT)) { 41602ac6454SAndrew Thompson m_freem(m); 41702ac6454SAndrew Thompson goto tr_setup; 41802ac6454SAndrew Thompson } 41902ac6454SAndrew Thompson m->m_pkthdr.len = m->m_len = xfer->actlen; 42002ac6454SAndrew Thompson 42102ac6454SAndrew Thompson usb2_copy_out(xfer->frbuffers, 0, m->m_data, xfer->actlen); 42202ac6454SAndrew Thompson 42302ac6454SAndrew Thompson sc->sc_bulk_in_buffer = m; 42402ac6454SAndrew Thompson 42502ac6454SAndrew Thompson DPRINTF("received package %d " 42602ac6454SAndrew Thompson "bytes\n", xfer->actlen); 42702ac6454SAndrew Thompson 42802ac6454SAndrew Thompson case USB_ST_SETUP: 42902ac6454SAndrew Thompson tr_setup: 43002ac6454SAndrew Thompson if (sc->sc_bulk_in_buffer) { 43102ac6454SAndrew Thompson ng_send_fn(sc->sc_node, NULL, &udbp_bulk_read_complete, NULL, 0); 43202ac6454SAndrew Thompson return; 43302ac6454SAndrew Thompson } 43402ac6454SAndrew Thompson if (sc->sc_flags & UDBP_FLAG_READ_STALL) { 43502ac6454SAndrew Thompson usb2_transfer_start(sc->sc_xfer[UDBP_T_RD_CS]); 43602ac6454SAndrew Thompson return; 43702ac6454SAndrew Thompson } 43802ac6454SAndrew Thompson xfer->frlengths[0] = xfer->max_data_length; 43902ac6454SAndrew Thompson usb2_start_hardware(xfer); 44002ac6454SAndrew Thompson return; 44102ac6454SAndrew Thompson 44202ac6454SAndrew Thompson default: /* Error */ 44302ac6454SAndrew Thompson if (xfer->error != USB_ERR_CANCELLED) { 44402ac6454SAndrew Thompson /* try to clear stall first */ 44502ac6454SAndrew Thompson sc->sc_flags |= UDBP_FLAG_READ_STALL; 44602ac6454SAndrew Thompson usb2_transfer_start(sc->sc_xfer[UDBP_T_RD_CS]); 44702ac6454SAndrew Thompson } 44802ac6454SAndrew Thompson return; 44902ac6454SAndrew Thompson 45002ac6454SAndrew Thompson } 45102ac6454SAndrew Thompson } 45202ac6454SAndrew Thompson 45302ac6454SAndrew Thompson static void 454760bc48eSAndrew Thompson udbp_bulk_read_clear_stall_callback(struct usb_xfer *xfer) 45502ac6454SAndrew Thompson { 45602ac6454SAndrew Thompson struct udbp_softc *sc = xfer->priv_sc; 457760bc48eSAndrew Thompson struct usb_xfer *xfer_other = sc->sc_xfer[UDBP_T_RD]; 45802ac6454SAndrew Thompson 45902ac6454SAndrew Thompson if (usb2_clear_stall_callback(xfer, xfer_other)) { 46002ac6454SAndrew Thompson DPRINTF("stall cleared\n"); 46102ac6454SAndrew Thompson sc->sc_flags &= ~UDBP_FLAG_READ_STALL; 46202ac6454SAndrew Thompson usb2_transfer_start(xfer_other); 46302ac6454SAndrew Thompson } 46402ac6454SAndrew Thompson } 46502ac6454SAndrew Thompson 46602ac6454SAndrew Thompson static void 46702ac6454SAndrew Thompson udbp_bulk_read_complete(node_p node, hook_p hook, void *arg1, int arg2) 46802ac6454SAndrew Thompson { 46902ac6454SAndrew Thompson struct udbp_softc *sc = NG_NODE_PRIVATE(node); 47002ac6454SAndrew Thompson struct mbuf *m; 47102ac6454SAndrew Thompson int error; 47202ac6454SAndrew Thompson 47302ac6454SAndrew Thompson if (sc == NULL) { 47402ac6454SAndrew Thompson return; 47502ac6454SAndrew Thompson } 47602ac6454SAndrew Thompson mtx_lock(&sc->sc_mtx); 47702ac6454SAndrew Thompson 47802ac6454SAndrew Thompson m = sc->sc_bulk_in_buffer; 47902ac6454SAndrew Thompson 48002ac6454SAndrew Thompson if (m) { 48102ac6454SAndrew Thompson 48202ac6454SAndrew Thompson sc->sc_bulk_in_buffer = NULL; 48302ac6454SAndrew Thompson 48402ac6454SAndrew Thompson if ((sc->sc_hook == NULL) || 48502ac6454SAndrew Thompson NG_HOOK_NOT_VALID(sc->sc_hook)) { 48602ac6454SAndrew Thompson DPRINTF("No upstream hook\n"); 48702ac6454SAndrew Thompson goto done; 48802ac6454SAndrew Thompson } 48902ac6454SAndrew Thompson sc->sc_packets_in++; 49002ac6454SAndrew Thompson 49102ac6454SAndrew Thompson NG_SEND_DATA_ONLY(error, sc->sc_hook, m); 49202ac6454SAndrew Thompson 49302ac6454SAndrew Thompson m = NULL; 49402ac6454SAndrew Thompson } 49502ac6454SAndrew Thompson done: 49602ac6454SAndrew Thompson if (m) { 49702ac6454SAndrew Thompson m_freem(m); 49802ac6454SAndrew Thompson } 49902ac6454SAndrew Thompson /* start USB bulk-in transfer, if not already started */ 50002ac6454SAndrew Thompson 50102ac6454SAndrew Thompson usb2_transfer_start(sc->sc_xfer[UDBP_T_RD]); 50202ac6454SAndrew Thompson 50302ac6454SAndrew Thompson mtx_unlock(&sc->sc_mtx); 50402ac6454SAndrew Thompson } 50502ac6454SAndrew Thompson 50602ac6454SAndrew Thompson static void 507760bc48eSAndrew Thompson udbp_bulk_write_callback(struct usb_xfer *xfer) 50802ac6454SAndrew Thompson { 50902ac6454SAndrew Thompson struct udbp_softc *sc = xfer->priv_sc; 51002ac6454SAndrew Thompson struct mbuf *m; 51102ac6454SAndrew Thompson 51202ac6454SAndrew Thompson switch (USB_GET_STATE(xfer)) { 51302ac6454SAndrew Thompson case USB_ST_TRANSFERRED: 51402ac6454SAndrew Thompson 51502ac6454SAndrew Thompson sc->sc_packets_out++; 51602ac6454SAndrew Thompson 51702ac6454SAndrew Thompson case USB_ST_SETUP: 51802ac6454SAndrew Thompson if (sc->sc_flags & UDBP_FLAG_WRITE_STALL) { 51902ac6454SAndrew Thompson usb2_transfer_start(sc->sc_xfer[UDBP_T_WR_CS]); 52002ac6454SAndrew Thompson return; 52102ac6454SAndrew Thompson } 52202ac6454SAndrew Thompson /* get next mbuf, if any */ 52302ac6454SAndrew Thompson 52402ac6454SAndrew Thompson NG_BT_MBUFQ_DEQUEUE(&sc->sc_xmitq_hipri, m); 52502ac6454SAndrew Thompson if (m == NULL) { 52602ac6454SAndrew Thompson NG_BT_MBUFQ_DEQUEUE(&sc->sc_xmitq, m); 52702ac6454SAndrew Thompson if (m == NULL) { 52802ac6454SAndrew Thompson DPRINTF("Data queue is empty\n"); 52902ac6454SAndrew Thompson return; 53002ac6454SAndrew Thompson } 53102ac6454SAndrew Thompson } 53202ac6454SAndrew Thompson if (m->m_pkthdr.len > MCLBYTES) { 53302ac6454SAndrew Thompson DPRINTF("truncating large packet " 53402ac6454SAndrew Thompson "from %d to %d bytes\n", m->m_pkthdr.len, 53502ac6454SAndrew Thompson MCLBYTES); 53602ac6454SAndrew Thompson m->m_pkthdr.len = MCLBYTES; 53702ac6454SAndrew Thompson } 53802ac6454SAndrew Thompson usb2_m_copy_in(xfer->frbuffers, 0, m, 0, m->m_pkthdr.len); 53902ac6454SAndrew Thompson 54002ac6454SAndrew Thompson xfer->frlengths[0] = m->m_pkthdr.len; 54102ac6454SAndrew Thompson 54202ac6454SAndrew Thompson m_freem(m); 54302ac6454SAndrew Thompson 54402ac6454SAndrew Thompson DPRINTF("packet out: %d bytes\n", 54502ac6454SAndrew Thompson xfer->frlengths[0]); 54602ac6454SAndrew Thompson 54702ac6454SAndrew Thompson usb2_start_hardware(xfer); 54802ac6454SAndrew Thompson return; 54902ac6454SAndrew Thompson 55002ac6454SAndrew Thompson default: /* Error */ 55102ac6454SAndrew Thompson if (xfer->error != USB_ERR_CANCELLED) { 55202ac6454SAndrew Thompson /* try to clear stall first */ 55302ac6454SAndrew Thompson sc->sc_flags |= UDBP_FLAG_WRITE_STALL; 55402ac6454SAndrew Thompson usb2_transfer_start(sc->sc_xfer[UDBP_T_WR_CS]); 55502ac6454SAndrew Thompson } 55602ac6454SAndrew Thompson return; 55702ac6454SAndrew Thompson 55802ac6454SAndrew Thompson } 55902ac6454SAndrew Thompson } 56002ac6454SAndrew Thompson 56102ac6454SAndrew Thompson static void 562760bc48eSAndrew Thompson udbp_bulk_write_clear_stall_callback(struct usb_xfer *xfer) 56302ac6454SAndrew Thompson { 56402ac6454SAndrew Thompson struct udbp_softc *sc = xfer->priv_sc; 565760bc48eSAndrew Thompson struct usb_xfer *xfer_other = sc->sc_xfer[UDBP_T_WR]; 56602ac6454SAndrew Thompson 56702ac6454SAndrew Thompson if (usb2_clear_stall_callback(xfer, xfer_other)) { 56802ac6454SAndrew Thompson DPRINTF("stall cleared\n"); 56902ac6454SAndrew Thompson sc->sc_flags &= ~UDBP_FLAG_WRITE_STALL; 57002ac6454SAndrew Thompson usb2_transfer_start(xfer_other); 57102ac6454SAndrew Thompson } 57202ac6454SAndrew Thompson } 57302ac6454SAndrew Thompson 57402ac6454SAndrew Thompson /*********************************************************************** 57502ac6454SAndrew Thompson * Start of Netgraph methods 57602ac6454SAndrew Thompson **********************************************************************/ 57702ac6454SAndrew Thompson 57802ac6454SAndrew Thompson /* 57902ac6454SAndrew Thompson * If this is a device node so this work is done in the attach() 58002ac6454SAndrew Thompson * routine and the constructor will return EINVAL as you should not be able 58102ac6454SAndrew Thompson * to create nodes that depend on hardware (unless you can add the hardware :) 58202ac6454SAndrew Thompson */ 58302ac6454SAndrew Thompson static int 58402ac6454SAndrew Thompson ng_udbp_constructor(node_p node) 58502ac6454SAndrew Thompson { 58602ac6454SAndrew Thompson return (EINVAL); 58702ac6454SAndrew Thompson } 58802ac6454SAndrew Thompson 58902ac6454SAndrew Thompson /* 59002ac6454SAndrew Thompson * Give our ok for a hook to be added... 59102ac6454SAndrew Thompson * If we are not running this might kick a device into life. 59202ac6454SAndrew Thompson * Possibly decode information out of the hook name. 59302ac6454SAndrew Thompson * Add the hook's private info to the hook structure. 59402ac6454SAndrew Thompson * (if we had some). In this example, we assume that there is a 59502ac6454SAndrew Thompson * an array of structs, called 'channel' in the private info, 59602ac6454SAndrew Thompson * one for each active channel. The private 59702ac6454SAndrew Thompson * pointer of each hook points to the appropriate UDBP_hookinfo struct 59802ac6454SAndrew Thompson * so that the source of an input packet is easily identified. 59902ac6454SAndrew Thompson */ 60002ac6454SAndrew Thompson static int 60102ac6454SAndrew Thompson ng_udbp_newhook(node_p node, hook_p hook, const char *name) 60202ac6454SAndrew Thompson { 60302ac6454SAndrew Thompson struct udbp_softc *sc = NG_NODE_PRIVATE(node); 60402ac6454SAndrew Thompson int32_t error = 0; 60502ac6454SAndrew Thompson 60602ac6454SAndrew Thompson if (strcmp(name, NG_UDBP_HOOK_NAME)) { 60702ac6454SAndrew Thompson return (EINVAL); 60802ac6454SAndrew Thompson } 60902ac6454SAndrew Thompson mtx_lock(&sc->sc_mtx); 61002ac6454SAndrew Thompson 61102ac6454SAndrew Thompson if (sc->sc_hook != NULL) { 61202ac6454SAndrew Thompson error = EISCONN; 61302ac6454SAndrew Thompson } else { 61402ac6454SAndrew Thompson sc->sc_hook = hook; 61502ac6454SAndrew Thompson NG_HOOK_SET_PRIVATE(hook, NULL); 61602ac6454SAndrew Thompson } 61702ac6454SAndrew Thompson 61802ac6454SAndrew Thompson mtx_unlock(&sc->sc_mtx); 61902ac6454SAndrew Thompson 62002ac6454SAndrew Thompson return (error); 62102ac6454SAndrew Thompson } 62202ac6454SAndrew Thompson 62302ac6454SAndrew Thompson /* 62402ac6454SAndrew Thompson * Get a netgraph control message. 62502ac6454SAndrew Thompson * Check it is one we understand. If needed, send a response. 62602ac6454SAndrew Thompson * We could save the address for an async action later, but don't here. 62702ac6454SAndrew Thompson * Always free the message. 62802ac6454SAndrew Thompson * The response should be in a malloc'd region that the caller can 'free'. 62902ac6454SAndrew Thompson * A response is not required. 63002ac6454SAndrew Thompson * Theoretically you could respond defferently to old message types if 63102ac6454SAndrew Thompson * the cookie in the header didn't match what we consider to be current 63202ac6454SAndrew Thompson * (so that old userland programs could continue to work). 63302ac6454SAndrew Thompson */ 63402ac6454SAndrew Thompson static int 63502ac6454SAndrew Thompson ng_udbp_rcvmsg(node_p node, item_p item, hook_p lasthook) 63602ac6454SAndrew Thompson { 63702ac6454SAndrew Thompson struct udbp_softc *sc = NG_NODE_PRIVATE(node); 63802ac6454SAndrew Thompson struct ng_mesg *resp = NULL; 63902ac6454SAndrew Thompson int error = 0; 64002ac6454SAndrew Thompson struct ng_mesg *msg; 64102ac6454SAndrew Thompson 64202ac6454SAndrew Thompson NGI_GET_MSG(item, msg); 64302ac6454SAndrew Thompson /* Deal with message according to cookie and command */ 64402ac6454SAndrew Thompson switch (msg->header.typecookie) { 64502ac6454SAndrew Thompson case NGM_UDBP_COOKIE: 64602ac6454SAndrew Thompson switch (msg->header.cmd) { 64702ac6454SAndrew Thompson case NGM_UDBP_GET_STATUS: 64802ac6454SAndrew Thompson { 64902ac6454SAndrew Thompson struct ngudbpstat *stats; 65002ac6454SAndrew Thompson 65102ac6454SAndrew Thompson NG_MKRESPONSE(resp, msg, sizeof(*stats), M_NOWAIT); 65202ac6454SAndrew Thompson if (!resp) { 65302ac6454SAndrew Thompson error = ENOMEM; 65402ac6454SAndrew Thompson break; 65502ac6454SAndrew Thompson } 65602ac6454SAndrew Thompson stats = (struct ngudbpstat *)resp->data; 65702ac6454SAndrew Thompson mtx_lock(&sc->sc_mtx); 65802ac6454SAndrew Thompson stats->packets_in = sc->sc_packets_in; 65902ac6454SAndrew Thompson stats->packets_out = sc->sc_packets_out; 66002ac6454SAndrew Thompson mtx_unlock(&sc->sc_mtx); 66102ac6454SAndrew Thompson break; 66202ac6454SAndrew Thompson } 66302ac6454SAndrew Thompson case NGM_UDBP_SET_FLAG: 66402ac6454SAndrew Thompson if (msg->header.arglen != sizeof(uint32_t)) { 66502ac6454SAndrew Thompson error = EINVAL; 66602ac6454SAndrew Thompson break; 66702ac6454SAndrew Thompson } 66802ac6454SAndrew Thompson DPRINTF("flags = 0x%08x\n", 66902ac6454SAndrew Thompson *((uint32_t *)msg->data)); 67002ac6454SAndrew Thompson break; 67102ac6454SAndrew Thompson default: 67202ac6454SAndrew Thompson error = EINVAL; /* unknown command */ 67302ac6454SAndrew Thompson break; 67402ac6454SAndrew Thompson } 67502ac6454SAndrew Thompson break; 67602ac6454SAndrew Thompson default: 67702ac6454SAndrew Thompson error = EINVAL; /* unknown cookie type */ 67802ac6454SAndrew Thompson break; 67902ac6454SAndrew Thompson } 68002ac6454SAndrew Thompson 68102ac6454SAndrew Thompson /* Take care of synchronous response, if any */ 68202ac6454SAndrew Thompson NG_RESPOND_MSG(error, node, item, resp); 68302ac6454SAndrew Thompson NG_FREE_MSG(msg); 68402ac6454SAndrew Thompson return (error); 68502ac6454SAndrew Thompson } 68602ac6454SAndrew Thompson 68702ac6454SAndrew Thompson /* 68802ac6454SAndrew Thompson * Accept data from the hook and queue it for output. 68902ac6454SAndrew Thompson */ 69002ac6454SAndrew Thompson static int 69102ac6454SAndrew Thompson ng_udbp_rcvdata(hook_p hook, item_p item) 69202ac6454SAndrew Thompson { 69302ac6454SAndrew Thompson struct udbp_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 69402ac6454SAndrew Thompson struct ng_bt_mbufq *queue_ptr; 69502ac6454SAndrew Thompson struct mbuf *m; 69602ac6454SAndrew Thompson struct ng_tag_prio *ptag; 69702ac6454SAndrew Thompson int error; 69802ac6454SAndrew Thompson 69902ac6454SAndrew Thompson if (sc == NULL) { 70002ac6454SAndrew Thompson NG_FREE_ITEM(item); 70102ac6454SAndrew Thompson return (EHOSTDOWN); 70202ac6454SAndrew Thompson } 70302ac6454SAndrew Thompson NGI_GET_M(item, m); 70402ac6454SAndrew Thompson NG_FREE_ITEM(item); 70502ac6454SAndrew Thompson 70602ac6454SAndrew Thompson /* 70702ac6454SAndrew Thompson * Now queue the data for when it can be sent 70802ac6454SAndrew Thompson */ 70902ac6454SAndrew Thompson ptag = (void *)m_tag_locate(m, NGM_GENERIC_COOKIE, 71002ac6454SAndrew Thompson NG_TAG_PRIO, NULL); 71102ac6454SAndrew Thompson 71202ac6454SAndrew Thompson if (ptag && (ptag->priority > NG_PRIO_CUTOFF)) 71302ac6454SAndrew Thompson queue_ptr = &sc->sc_xmitq_hipri; 71402ac6454SAndrew Thompson else 71502ac6454SAndrew Thompson queue_ptr = &sc->sc_xmitq; 71602ac6454SAndrew Thompson 71702ac6454SAndrew Thompson mtx_lock(&sc->sc_mtx); 71802ac6454SAndrew Thompson 71902ac6454SAndrew Thompson if (NG_BT_MBUFQ_FULL(queue_ptr)) { 72002ac6454SAndrew Thompson NG_BT_MBUFQ_DROP(queue_ptr); 72102ac6454SAndrew Thompson NG_FREE_M(m); 72202ac6454SAndrew Thompson error = ENOBUFS; 72302ac6454SAndrew Thompson } else { 72402ac6454SAndrew Thompson NG_BT_MBUFQ_ENQUEUE(queue_ptr, m); 72502ac6454SAndrew Thompson /* 72602ac6454SAndrew Thompson * start bulk-out transfer, if not already started: 72702ac6454SAndrew Thompson */ 72802ac6454SAndrew Thompson usb2_transfer_start(sc->sc_xfer[UDBP_T_WR]); 72902ac6454SAndrew Thompson error = 0; 73002ac6454SAndrew Thompson } 73102ac6454SAndrew Thompson 73202ac6454SAndrew Thompson mtx_unlock(&sc->sc_mtx); 73302ac6454SAndrew Thompson 73402ac6454SAndrew Thompson return (error); 73502ac6454SAndrew Thompson } 73602ac6454SAndrew Thompson 73702ac6454SAndrew Thompson /* 73802ac6454SAndrew Thompson * Do local shutdown processing.. 73902ac6454SAndrew Thompson * We are a persistant device, we refuse to go away, and 74002ac6454SAndrew Thompson * only remove our links and reset ourself. 74102ac6454SAndrew Thompson */ 74202ac6454SAndrew Thompson static int 74302ac6454SAndrew Thompson ng_udbp_rmnode(node_p node) 74402ac6454SAndrew Thompson { 74502ac6454SAndrew Thompson struct udbp_softc *sc = NG_NODE_PRIVATE(node); 74602ac6454SAndrew Thompson 74702ac6454SAndrew Thompson /* Let old node go */ 74802ac6454SAndrew Thompson NG_NODE_SET_PRIVATE(node, NULL); 74902ac6454SAndrew Thompson NG_NODE_UNREF(node); /* forget it ever existed */ 75002ac6454SAndrew Thompson 75102ac6454SAndrew Thompson if (sc == NULL) { 75202ac6454SAndrew Thompson goto done; 75302ac6454SAndrew Thompson } 75402ac6454SAndrew Thompson /* Create Netgraph node */ 75502ac6454SAndrew Thompson if (ng_make_node_common(&ng_udbp_typestruct, &sc->sc_node) != 0) { 75602ac6454SAndrew Thompson printf("%s: Could not create Netgraph node\n", 75702ac6454SAndrew Thompson sc->sc_name); 75802ac6454SAndrew Thompson sc->sc_node = NULL; 75902ac6454SAndrew Thompson goto done; 76002ac6454SAndrew Thompson } 76102ac6454SAndrew Thompson /* Name node */ 76202ac6454SAndrew Thompson if (ng_name_node(sc->sc_node, sc->sc_name) != 0) { 76302ac6454SAndrew Thompson printf("%s: Could not name Netgraph node\n", 76402ac6454SAndrew Thompson sc->sc_name); 76502ac6454SAndrew Thompson NG_NODE_UNREF(sc->sc_node); 76602ac6454SAndrew Thompson sc->sc_node = NULL; 76702ac6454SAndrew Thompson goto done; 76802ac6454SAndrew Thompson } 76902ac6454SAndrew Thompson NG_NODE_SET_PRIVATE(sc->sc_node, sc); 77002ac6454SAndrew Thompson 77102ac6454SAndrew Thompson done: 77202ac6454SAndrew Thompson if (sc) { 77302ac6454SAndrew Thompson mtx_unlock(&sc->sc_mtx); 77402ac6454SAndrew Thompson } 77502ac6454SAndrew Thompson return (0); 77602ac6454SAndrew Thompson } 77702ac6454SAndrew Thompson 77802ac6454SAndrew Thompson /* 77902ac6454SAndrew Thompson * This is called once we've already connected a new hook to the other node. 78002ac6454SAndrew Thompson * It gives us a chance to balk at the last minute. 78102ac6454SAndrew Thompson */ 78202ac6454SAndrew Thompson static int 78302ac6454SAndrew Thompson ng_udbp_connect(hook_p hook) 78402ac6454SAndrew Thompson { 78502ac6454SAndrew Thompson struct udbp_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 78602ac6454SAndrew Thompson 78702ac6454SAndrew Thompson /* probably not at splnet, force outward queueing */ 78802ac6454SAndrew Thompson NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); 78902ac6454SAndrew Thompson 79002ac6454SAndrew Thompson mtx_lock(&sc->sc_mtx); 79102ac6454SAndrew Thompson 79202ac6454SAndrew Thompson sc->sc_flags |= (UDBP_FLAG_READ_STALL | 79302ac6454SAndrew Thompson UDBP_FLAG_WRITE_STALL); 79402ac6454SAndrew Thompson 79502ac6454SAndrew Thompson /* start bulk-in transfer */ 79602ac6454SAndrew Thompson usb2_transfer_start(sc->sc_xfer[UDBP_T_RD]); 79702ac6454SAndrew Thompson 79802ac6454SAndrew Thompson /* start bulk-out transfer */ 79902ac6454SAndrew Thompson usb2_transfer_start(sc->sc_xfer[UDBP_T_WR]); 80002ac6454SAndrew Thompson 80102ac6454SAndrew Thompson mtx_unlock(&sc->sc_mtx); 80202ac6454SAndrew Thompson 80302ac6454SAndrew Thompson return (0); 80402ac6454SAndrew Thompson } 80502ac6454SAndrew Thompson 80602ac6454SAndrew Thompson /* 80702ac6454SAndrew Thompson * Dook disconnection 80802ac6454SAndrew Thompson * 80902ac6454SAndrew Thompson * For this type, removal of the last link destroys the node 81002ac6454SAndrew Thompson */ 81102ac6454SAndrew Thompson static int 81202ac6454SAndrew Thompson ng_udbp_disconnect(hook_p hook) 81302ac6454SAndrew Thompson { 81402ac6454SAndrew Thompson struct udbp_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 81502ac6454SAndrew Thompson int error = 0; 81602ac6454SAndrew Thompson 81702ac6454SAndrew Thompson if (sc != NULL) { 81802ac6454SAndrew Thompson 81902ac6454SAndrew Thompson mtx_lock(&sc->sc_mtx); 82002ac6454SAndrew Thompson 82102ac6454SAndrew Thompson if (hook != sc->sc_hook) { 82202ac6454SAndrew Thompson error = EINVAL; 82302ac6454SAndrew Thompson } else { 82402ac6454SAndrew Thompson 82502ac6454SAndrew Thompson /* stop bulk-in transfer */ 82602ac6454SAndrew Thompson usb2_transfer_stop(sc->sc_xfer[UDBP_T_RD_CS]); 82702ac6454SAndrew Thompson usb2_transfer_stop(sc->sc_xfer[UDBP_T_RD]); 82802ac6454SAndrew Thompson 82902ac6454SAndrew Thompson /* stop bulk-out transfer */ 83002ac6454SAndrew Thompson usb2_transfer_stop(sc->sc_xfer[UDBP_T_WR_CS]); 83102ac6454SAndrew Thompson usb2_transfer_stop(sc->sc_xfer[UDBP_T_WR]); 83202ac6454SAndrew Thompson 83302ac6454SAndrew Thompson /* cleanup queues */ 83402ac6454SAndrew Thompson NG_BT_MBUFQ_DRAIN(&sc->sc_xmitq); 83502ac6454SAndrew Thompson NG_BT_MBUFQ_DRAIN(&sc->sc_xmitq_hipri); 83602ac6454SAndrew Thompson 83702ac6454SAndrew Thompson if (sc->sc_bulk_in_buffer) { 83802ac6454SAndrew Thompson m_freem(sc->sc_bulk_in_buffer); 83902ac6454SAndrew Thompson sc->sc_bulk_in_buffer = NULL; 84002ac6454SAndrew Thompson } 84102ac6454SAndrew Thompson sc->sc_hook = NULL; 84202ac6454SAndrew Thompson } 84302ac6454SAndrew Thompson 84402ac6454SAndrew Thompson mtx_unlock(&sc->sc_mtx); 84502ac6454SAndrew Thompson } 84602ac6454SAndrew Thompson if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 84702ac6454SAndrew Thompson && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 84802ac6454SAndrew Thompson ng_rmnode_self(NG_HOOK_NODE(hook)); 84902ac6454SAndrew Thompson 85002ac6454SAndrew Thompson return (error); 85102ac6454SAndrew Thompson } 852