diff options
Diffstat (limited to 'sys/dev/usb/udbp.c')
-rw-r--r-- | sys/dev/usb/udbp.c | 860 |
1 files changed, 0 insertions, 860 deletions
diff --git a/sys/dev/usb/udbp.c b/sys/dev/usb/udbp.c deleted file mode 100644 index 523184f..0000000 --- a/sys/dev/usb/udbp.c +++ /dev/null @@ -1,860 +0,0 @@ -/*- - * Copyright (c) 1996-2000 Whistle Communications, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of author nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY NICK HIBMA AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/* Driver for arbitrary double bulk pipe devices. - * The driver assumes that there will be the same driver on the other side. - * - * XXX Some more information on what the framing of the IP packets looks like. - * - * To take full advantage of bulk transmission, packets should be chosen - * between 1k and 5k in size (1k to make sure the sending side starts - * straming, and <5k to avoid overflowing the system with small TDs). - */ - - -/* probe/attach/detach: - * Connect the driver to the hardware and netgraph - * - * udbp_setup_out_transfer(sc); - * Setup an outbound transfer. Only one transmit can be active at the same - * time. - * XXX If it is required that the driver is able to queue multiple requests - * let me know. That is slightly difficult, due to the fact that we - * cannot call usbd_alloc_xfer in int context. - * - * udbp_setup_in_transfer(sc) - * Prepare an in transfer that will be waiting for data to come in. It - * is submitted and sits there until data is available. - * The callback resubmits a new transfer on completion. - * - * The reason we submit a bulk in transfer is that USB does not know about - * interrupts. The bulk transfer continuously polls the device for data. - * While the device has no data available, the device NAKs the TDs. As soon - * as there is data, the transfer happens and the data comes flowing in. - * - * In case you were wondering, interrupt transfers happen exactly that way. - * It therefore doesn't make sense to use the interrupt pipe to signal - * 'data ready' and then schedule a bulk transfer to fetch it. That would - * incur a 2ms delay at least, without reducing bandwidth requirements. - * - */ - - - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/module.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/file.h> -#include <sys/selinfo.h> -#include <sys/poll.h> -#include <sys/mbuf.h> -#include <sys/socket.h> -#include <sys/ctype.h> -#include <sys/errno.h> -#include <sys/sysctl.h> -#include <net/if.h> -#include <machine/bus.h> - -#include <dev/usb/usb.h> -#include <dev/usb/usbdi.h> -#include <dev/usb/usbdi_util.h> -#include <dev/usb/usbdivar.h> -#include <dev/usb/usbhid.h> - -#include "usbdevs.h" - - -#include <netgraph/ng_message.h> -#include <netgraph/ng_parse.h> -#include <dev/usb/udbp.h> -#include <netgraph/netgraph.h> - -#ifdef USB_DEBUG -#define DPRINTF(x) if (udbpdebug) printf x -#define DPRINTFN(n,x) if (udbpdebug>(n)) printf x -int udbpdebug = 0; -SYSCTL_NODE(_hw_usb, OID_AUTO, udbp, CTLFLAG_RW, 0, "USB udbp"); -SYSCTL_INT(_hw_usb_udbp, OID_AUTO, debug, CTLFLAG_RW, - &udbpdebug, 0, "udbp debug level"); -#else -#define DPRINTF(x) -#define DPRINTFN(n,x) -#endif - -#define MS_TO_TICKS(ms) ((ms) * hz / 1000) - -#define UDBP_TIMEOUT 2000 /* timeout on outbound transfers, in msecs */ -#define UDBP_BUFFERSIZE 2048 /* maximum number of bytes in one transfer */ - - -struct udbp_softc { - device_t sc_dev; /* base device */ - usbd_interface_handle sc_iface; - - usbd_pipe_handle sc_bulkin_pipe; - int sc_bulkin; - usbd_xfer_handle sc_bulkin_xfer; - void *sc_bulkin_buffer; - int sc_bulkin_bufferlen; - int sc_bulkin_datalen; - - usbd_pipe_handle sc_bulkout_pipe; - int sc_bulkout; - usbd_xfer_handle sc_bulkout_xfer; - void *sc_bulkout_buffer; - int sc_bulkout_bufferlen; - int sc_bulkout_datalen; - - int flags; -# define DISCONNECTED 0x01 -# define OUT_BUSY 0x02 -# define NETGRAPH_INITIALISED 0x04 - node_p node; /* back pointer to node */ - hook_p hook; /* pointer to the hook */ - u_int packets_in; /* packets in from downstream */ - u_int packets_out; /* packets out towards downstream */ - struct ifqueue xmitq_hipri; /* hi-priority transmit queue */ - struct ifqueue xmitq; /* low-priority transmit queue */ - -}; -typedef struct udbp_softc *udbp_p; - - - -static ng_constructor_t ng_udbp_constructor; -static ng_rcvmsg_t ng_udbp_rcvmsg; -static ng_shutdown_t ng_udbp_rmnode; -static ng_newhook_t ng_udbp_newhook; -static ng_connect_t ng_udbp_connect; -static ng_rcvdata_t ng_udbp_rcvdata; -static ng_disconnect_t ng_udbp_disconnect; - -/* Parse type for struct ngudbpstat */ -static const struct ng_parse_struct_field - ng_udbp_stat_type_fields[] = NG_UDBP_STATS_TYPE_INFO; -static const struct ng_parse_type ng_udbp_stat_type = { - &ng_parse_struct_type, - &ng_udbp_stat_type_fields -}; - -/* List of commands and how to convert arguments to/from ASCII */ -static const struct ng_cmdlist ng_udbp_cmdlist[] = { - { - NGM_UDBP_COOKIE, - NGM_UDBP_GET_STATUS, - "getstatus", - NULL, - &ng_udbp_stat_type, - }, - { - NGM_UDBP_COOKIE, - NGM_UDBP_SET_FLAG, - "setflag", - &ng_parse_int32_type, - NULL - }, - { 0 } -}; - -/* Netgraph node type descriptor */ -static struct ng_type ng_udbp_typestruct = { - .version = NG_ABI_VERSION, - .name = NG_UDBP_NODE_TYPE, - .constructor = ng_udbp_constructor, - .rcvmsg = ng_udbp_rcvmsg, - .shutdown = ng_udbp_rmnode, - .newhook = ng_udbp_newhook, - .connect = ng_udbp_connect, - .rcvdata = ng_udbp_rcvdata, - .disconnect = ng_udbp_disconnect, - .cmdlist = ng_udbp_cmdlist, -}; - -static int udbp_setup_in_transfer (udbp_p sc); -static void udbp_in_transfer_cb (usbd_xfer_handle xfer, - usbd_private_handle priv, - usbd_status err); - -static int udbp_setup_out_transfer (udbp_p sc); -static void udbp_out_transfer_cb (usbd_xfer_handle xfer, - usbd_private_handle priv, - usbd_status err); - -static device_probe_t udbp_match; -static device_attach_t udbp_attach; -static device_detach_t udbp_detach; - -static device_method_t udbp_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, udbp_match), - DEVMETHOD(device_attach, udbp_attach), - DEVMETHOD(device_detach, udbp_detach), - - { 0, 0 } -}; - -static driver_t udbp_driver = { - "udbp", - udbp_methods, - sizeof(struct udbp_softc) -}; - -static devclass_t udbp_devclass; - -static int -udbp_match(device_t self) -{ - struct usb_attach_arg *uaa = device_get_ivars(self); - usb_interface_descriptor_t *id; - if (!uaa->iface) - return (UMATCH_NONE); - id = usbd_get_interface_descriptor(uaa->iface); - - /* XXX Julian, add the id of the device if you have one to test - * things with. run 'usbdevs -v' and note the 3 ID's that appear. - * The Vendor Id and Product Id are in hex and the Revision Id is in - * bcd. But as usual if the revision is 0x101 then you should compare - * the revision id in the device descriptor with 0x101 - * Or go search the file usbdevs.h. Maybe the device is already in - * there. - */ - if ((uaa->vendor == USB_VENDOR_NETCHIP && - uaa->product == USB_PRODUCT_NETCHIP_TURBOCONNECT)) - return (UMATCH_VENDOR_PRODUCT); - - if ((uaa->vendor == USB_VENDOR_PROLIFIC && - (uaa->product == USB_PRODUCT_PROLIFIC_PL2301 || - uaa->product == USB_PRODUCT_PROLIFIC_PL2302))) - return (UMATCH_VENDOR_PRODUCT); - - if ((uaa->vendor == USB_VENDOR_ANCHOR && - uaa->product == USB_PRODUCT_ANCHOR_EZLINK)) - return (UMATCH_VENDOR_PRODUCT); - - if ((uaa->vendor == USB_VENDOR_GENESYS && - uaa->product == USB_PRODUCT_GENESYS_GL620USB)) - return (UMATCH_VENDOR_PRODUCT); - - return (UMATCH_NONE); -} - -static int -udbp_attach(device_t self) -{ - struct udbp_softc *sc = device_get_softc(self); - struct usb_attach_arg *uaa = device_get_ivars(self); - usbd_interface_handle iface = uaa->iface; - usb_interface_descriptor_t *id; - usb_endpoint_descriptor_t *ed, *ed_bulkin = NULL, *ed_bulkout = NULL; - usbd_status err; - int i; - static int ngudbp_done_init=0; - - sc->flags |= DISCONNECTED; - /* fetch the interface handle for the first interface */ - (void) usbd_device2interface_handle(uaa->device, 0, &iface); - id = usbd_get_interface_descriptor(iface); - sc->sc_dev = self; - - /* Find the two first bulk endpoints */ - for (i = 0 ; i < id->bNumEndpoints; i++) { - ed = usbd_interface2endpoint_descriptor(iface, i); - if (!ed) { - device_printf(self, "could not read endpoint descriptor\n"); - return ENXIO; - } - - if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN - && (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { - ed_bulkin = ed; - } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT - && (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { - ed_bulkout = ed; - } - - if (ed_bulkin && ed_bulkout) /* found all we need */ - break; - } - - /* Verify that we goething sensible */ - if (ed_bulkin == NULL || ed_bulkout == NULL) { - device_printf(self, "bulk-in and/or bulk-out endpoint not found\n"); - return ENXIO; - } - - if (ed_bulkin->wMaxPacketSize[0] != ed_bulkout->wMaxPacketSize[0] || - ed_bulkin->wMaxPacketSize[1] != ed_bulkout->wMaxPacketSize[1]) { - device_printf(self, - "bulk-in and bulk-out have different packet sizes %d %d %d %d\n", - ed_bulkin->wMaxPacketSize[0], - ed_bulkout->wMaxPacketSize[0], - ed_bulkin->wMaxPacketSize[1], - ed_bulkout->wMaxPacketSize[1]); - return ENXIO; - } - - sc->sc_bulkin = ed_bulkin->bEndpointAddress; - sc->sc_bulkout = ed_bulkout->bEndpointAddress; - - DPRINTF(("%s: Bulk-in: 0x%02x, bulk-out 0x%02x, packet size = %d\n", - device_get_nameunit(sc->sc_dev), sc->sc_bulkin, sc->sc_bulkout, - ed_bulkin->wMaxPacketSize[0])); - - /* Allocate the in transfer struct */ - sc->sc_bulkin_xfer = usbd_alloc_xfer(uaa->device); - if (!sc->sc_bulkin_xfer) { - goto bad; - } - sc->sc_bulkout_xfer = usbd_alloc_xfer(uaa->device); - if (!sc->sc_bulkout_xfer) { - goto bad; - } - sc->sc_bulkin_buffer = malloc(UDBP_BUFFERSIZE, M_USBDEV, M_WAITOK); - if (!sc->sc_bulkin_buffer) { - goto bad; - } - sc->sc_bulkout_buffer = malloc(UDBP_BUFFERSIZE, M_USBDEV, M_WAITOK); - if (!sc->sc_bulkout_xfer || !sc->sc_bulkout_buffer) { - goto bad; - } - sc->sc_bulkin_bufferlen = UDBP_BUFFERSIZE; - sc->sc_bulkout_bufferlen = UDBP_BUFFERSIZE; - - /* We have decided on which endpoints to use, now open the pipes */ - err = usbd_open_pipe(iface, sc->sc_bulkin, - USBD_EXCLUSIVE_USE, &sc->sc_bulkin_pipe); - if (err) { - device_printf(self, "cannot open bulk-in pipe (addr %d)\n", - sc->sc_bulkin); - goto bad; - } - err = usbd_open_pipe(iface, sc->sc_bulkout, - USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe); - if (err) { - device_printf(self, "cannot open bulk-out pipe (addr %d)\n", - sc->sc_bulkout); - goto bad; - } - - if (!ngudbp_done_init){ - ngudbp_done_init=1; - if (ng_newtype(&ng_udbp_typestruct)) { - printf("ngudbp install failed\n"); - goto bad; - } - } - - if ((err = ng_make_node_common(&ng_udbp_typestruct, &sc->node)) == 0) { - char nodename[128]; - sprintf(nodename, "%s", device_get_nameunit(sc->sc_dev)); - if ((err = ng_name_node(sc->node, nodename))) { - NG_NODE_UNREF(sc->node); - sc->node = NULL; - goto bad; - } else { - NG_NODE_SET_PRIVATE(sc->node, sc); - sc->xmitq.ifq_maxlen = IFQ_MAXLEN; - sc->xmitq_hipri.ifq_maxlen = IFQ_MAXLEN; - mtx_init(&sc->xmitq.ifq_mtx, "usb_xmitq", NULL, - MTX_DEF); - mtx_init(&sc->xmitq_hipri.ifq_mtx, - "usb_xmitq_hipri", NULL, MTX_DEF); - } - } - sc->flags = NETGRAPH_INITIALISED; - /* sc->flags &= ~DISCONNECTED; */ /* XXX */ - - - /* the device is now operational */ - - - /* schedule the first incoming xfer */ - err = udbp_setup_in_transfer(sc); - if (err) { - goto bad; - } - return 0; -bad: -#if 0 /* probably done in udbp_detach() */ - if (sc->sc_bulkout_buffer) { - free(sc->sc_bulkout_buffer, M_USBDEV); - } - if (sc->sc_bulkin_buffer) { - free(sc->sc_bulkin_buffer, M_USBDEV); - } - if (sc->sc_bulkout_xfer) { - usbd_free_xfer(sc->sc_bulkout_xfer); - } - if (sc->sc_bulkin_xfer) { - usbd_free_xfer(sc->sc_bulkin_xfer); - } -#endif - udbp_detach(self); - return ENXIO; -} - - -static int -udbp_detach(device_t self) -{ - struct udbp_softc *sc = device_get_softc(self); - - sc->flags |= DISCONNECTED; - - DPRINTF(("%s: disconnected\n", device_get_nameunit(self))); - - if (sc->sc_bulkin_pipe) { - usbd_abort_pipe(sc->sc_bulkin_pipe); - usbd_close_pipe(sc->sc_bulkin_pipe); - } - if (sc->sc_bulkout_pipe) { - usbd_abort_pipe(sc->sc_bulkout_pipe); - usbd_close_pipe(sc->sc_bulkout_pipe); - } - - if (sc->flags & NETGRAPH_INITIALISED) { - ng_rmnode_self(sc->node); - NG_NODE_SET_PRIVATE(sc->node, NULL); - NG_NODE_UNREF(sc->node); - sc->node = NULL; /* Paranoid */ - } - - if (sc->sc_bulkin_xfer) - usbd_free_xfer(sc->sc_bulkin_xfer); - if (sc->sc_bulkout_xfer) - usbd_free_xfer(sc->sc_bulkout_xfer); - - if (sc->sc_bulkin_buffer) - free(sc->sc_bulkin_buffer, M_USBDEV); - if (sc->sc_bulkout_buffer) - free(sc->sc_bulkout_buffer, M_USBDEV); - return 0; -} - - -static int -udbp_setup_in_transfer(udbp_p sc) -{ - void *priv = sc; /* XXX this should probably be some pointer to - * struct describing the transfer (mbuf?) - * See also below. - */ - usbd_status err; - - /* XXX - * How should we arrange for 2 extra bytes at the start of the - * packet? - */ - - /* Initialise a USB transfer and then schedule it */ - - (void) usbd_setup_xfer( sc->sc_bulkin_xfer, - sc->sc_bulkin_pipe, - priv, - sc->sc_bulkin_buffer, - sc->sc_bulkin_bufferlen, - USBD_SHORT_XFER_OK, - USBD_NO_TIMEOUT, - udbp_in_transfer_cb); - - err = usbd_transfer(sc->sc_bulkin_xfer); - if (err && err != USBD_IN_PROGRESS) { - DPRINTF(("%s: failed to setup in-transfer, %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(err))); - return(err); - } - - return (USBD_NORMAL_COMPLETION); -} - -static void -udbp_in_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv, - usbd_status err) -{ - udbp_p sc = priv; /* XXX see priv above */ - int s; - int len; - struct mbuf *m; - - if (err) { - if (err != USBD_CANCELLED) { - DPRINTF(("%s: bulk-out transfer failed: %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(err))); - } else { - /* USBD_CANCELLED happens at unload of the driver */ - return; - } - - /* Transfer has failed, packet is not received */ - } else { - - len = xfer->actlen; - - s = splimp(); /* block network stuff too */ - if (sc->hook) { - /* get packet from device and send on */ - m = m_devget(sc->sc_bulkin_buffer, len, 0, NULL, NULL); - NG_SEND_DATA_ONLY(err, sc->hook, m); - } - splx(s); - - } - /* schedule the next in transfer */ - udbp_setup_in_transfer(sc); -} - - -static int -udbp_setup_out_transfer(udbp_p sc) -{ - void *priv = sc; /* XXX this should probably be some pointer to - * struct describing the transfer (mbuf?) - * See also below. - */ - int pktlen; - usbd_status err; - int s, s1; - struct mbuf *m; - - - s = splusb(); - if (sc->flags & OUT_BUSY) - panic("out transfer already in use, we should add queuing"); - sc->flags |= OUT_BUSY; - splx(s); - s1 = splimp(); /* Queueing happens at splnet */ - IF_DEQUEUE(&sc->xmitq_hipri, m); - if (m == NULL) { - IF_DEQUEUE(&sc->xmitq, m); - } - splx(s1); - - if (!m) { - sc->flags &= ~OUT_BUSY; - return (USBD_NORMAL_COMPLETION); - } - - pktlen = m->m_pkthdr.len; - if (pktlen > sc->sc_bulkout_bufferlen) { - device_printf(sc->sc_dev, "Packet too large, %d > %d\n", - pktlen, sc->sc_bulkout_bufferlen); - return (USBD_IOERROR); - } - - m_copydata(m, 0, pktlen, sc->sc_bulkout_buffer); - m_freem(m); - - /* Initialise a USB transfer and then schedule it */ - - (void) usbd_setup_xfer( sc->sc_bulkout_xfer, - sc->sc_bulkout_pipe, - priv, - sc->sc_bulkout_buffer, - pktlen, - USBD_SHORT_XFER_OK, - UDBP_TIMEOUT, - udbp_out_transfer_cb); - - err = usbd_transfer(sc->sc_bulkout_xfer); - if (err && err != USBD_IN_PROGRESS) { - DPRINTF(("%s: failed to setup out-transfer, %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(err))); - return(err); - } - - return (USBD_NORMAL_COMPLETION); -} - -static void -udbp_out_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv, - usbd_status err) -{ - udbp_p sc = priv; /* XXX see priv above */ - int s; - - if (err) { - DPRINTF(("%s: bulk-out transfer failed: %s\n", - device_get_nameunit(sc->sc_dev), usbd_errstr(err))); - /* Transfer has failed, packet is not transmitted */ - /* XXX Invalidate packet */ - return; - } - - /* packet has been transmitted */ - - s = splusb(); /* mark the buffer available */ - sc->flags &= ~OUT_BUSY; - udbp_setup_out_transfer(sc); - splx(s); -} - -DRIVER_MODULE(udbp, uhub, udbp_driver, udbp_devclass, usbd_driver_load, 0); -MODULE_DEPEND(udbp, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); -MODULE_DEPEND(udbp, usb, 1, 1, 1); - - -/*********************************************************************** - * Start of Netgraph methods - **********************************************************************/ - -/* - * If this is a device node so this work is done in the attach() - * routine and the constructor will return EINVAL as you should not be able - * to create nodes that depend on hardware (unless you can add the hardware :) - */ -static int -ng_udbp_constructor(node_p node) -{ - return (EINVAL); -} - -/* - * Give our ok for a hook to be added... - * If we are not running this might kick a device into life. - * Possibly decode information out of the hook name. - * Add the hook's private info to the hook structure. - * (if we had some). In this example, we assume that there is a - * an array of structs, called 'channel' in the private info, - * one for each active channel. The private - * pointer of each hook points to the appropriate UDBP_hookinfo struct - * so that the source of an input packet is easily identified. - */ -static int -ng_udbp_newhook(node_p node, hook_p hook, const char *name) -{ - const udbp_p sc = NG_NODE_PRIVATE(node); - -#if 0 - /* Possibly start up the device if it's not already going */ - if ((sc->flags & SCF_RUNNING) == 0) { - ng_udbp_start_hardware(sc); - } -#endif - - if (strcmp(name, NG_UDBP_HOOK_NAME) == 0) { - sc->hook = hook; - NG_HOOK_SET_PRIVATE(hook, NULL); - } else { - return (EINVAL); /* not a hook we know about */ - } - return(0); -} - -/* - * Get a netgraph control message. - * Check it is one we understand. If needed, send a response. - * We could save the address for an async action later, but don't here. - * Always free the message. - * The response should be in a malloc'd region that the caller can 'free'. - * A response is not required. - * Theoretically you could respond defferently to old message types if - * the cookie in the header didn't match what we consider to be current - * (so that old userland programs could continue to work). - */ -static int -ng_udbp_rcvmsg(node_p node, item_p item, hook_p lasthook) -{ - const udbp_p sc = NG_NODE_PRIVATE(node); - struct ng_mesg *resp = NULL; - int error = 0; - struct ng_mesg *msg; - - NGI_GET_MSG(item, msg); - /* Deal with message according to cookie and command */ - switch (msg->header.typecookie) { - case NGM_UDBP_COOKIE: - switch (msg->header.cmd) { - case NGM_UDBP_GET_STATUS: - { - struct ngudbpstat *stats; - - NG_MKRESPONSE(resp, msg, sizeof(*stats), M_NOWAIT); - if (!resp) { - error = ENOMEM; - break; - } - stats = (struct ngudbpstat *) resp->data; - stats->packets_in = sc->packets_in; - stats->packets_out = sc->packets_out; - break; - } - case NGM_UDBP_SET_FLAG: - if (msg->header.arglen != sizeof(u_int32_t)) { - error = EINVAL; - break; - } - sc->flags = *((u_int32_t *) msg->data); - break; - default: - error = EINVAL; /* unknown command */ - break; - } - break; - default: - error = EINVAL; /* unknown cookie type */ - break; - } - - /* Take care of synchronous response, if any */ - NG_RESPOND_MSG(error, node, item, resp); - NG_FREE_MSG(msg); - return(error); -} - -/* - * Accept data from the hook and queue it for output. - */ -static int -ng_udbp_rcvdata(hook_p hook, item_p item) -{ - const udbp_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); - int error; - struct ifqueue *xmitq_p; - int s; - struct mbuf *m; - struct ng_tag_prio *ptag; - - NGI_GET_M(item, m); - NG_FREE_ITEM(item); - - /* - * Now queue the data for when it can be sent - */ - if ((ptag = (struct ng_tag_prio *)m_tag_locate(m, NGM_GENERIC_COOKIE, - NG_TAG_PRIO, NULL)) != NULL && (ptag->priority > NG_PRIO_CUTOFF) ) - xmitq_p = (&sc->xmitq_hipri); - else - xmitq_p = (&sc->xmitq); - - s = splusb(); - IF_LOCK(xmitq_p); - if (_IF_QFULL(xmitq_p)) { - _IF_DROP(xmitq_p); - IF_UNLOCK(xmitq_p); - splx(s); - error = ENOBUFS; - goto bad; - } - _IF_ENQUEUE(xmitq_p, m); - IF_UNLOCK(xmitq_p); - if (!(sc->flags & OUT_BUSY)) - udbp_setup_out_transfer(sc); - splx(s); - return (0); - -bad: /* - * It was an error case. - * check if we need to free the mbuf, and then return the error - */ - NG_FREE_M(m); - return (error); -} - -/* - * Do local shutdown processing.. - * We are a persistant device, we refuse to go away, and - * only remove our links and reset ourself. - */ -static int -ng_udbp_rmnode(node_p node) -{ - const udbp_p sc = NG_NODE_PRIVATE(node); - int err; - - if (sc->flags & DISCONNECTED) { - /* - * WE are really going away.. hardware must have gone. - * Assume that the hardware drive part will clear up the - * sc, in fact it may already have done so.. - * In which case we may have just segfaulted..XXX - */ - return (0); - } - - /* stolen from attach routine */ - /* Drain the queues */ - IF_DRAIN(&sc->xmitq_hipri); - IF_DRAIN(&sc->xmitq); - - sc->packets_in = 0; /* reset stats */ - sc->packets_out = 0; - NG_NODE_UNREF(node); /* forget it ever existed */ - - if ((err = ng_make_node_common(&ng_udbp_typestruct, &sc->node)) == 0) { - char nodename[128]; - sprintf(nodename, "%s", device_get_nameunit(sc->sc_dev)); - if ((err = ng_name_node(sc->node, nodename))) { - NG_NODE_UNREF(sc->node); /* out damned spot! */ - sc->flags &= ~NETGRAPH_INITIALISED; - sc->node = NULL; - } else { - NG_NODE_SET_PRIVATE(sc->node, sc); - } - } - return (err); -} - -/* - * This is called once we've already connected a new hook to the other node. - * It gives us a chance to balk at the last minute. - */ -static int -ng_udbp_connect(hook_p hook) -{ - /* probably not at splnet, force outward queueing */ - NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); - /* be really amiable and just say "YUP that's OK by me! " */ - return (0); -} - -/* - * Dook disconnection - * - * For this type, removal of the last link destroys the node - */ -static int -ng_udbp_disconnect(hook_p hook) -{ - const udbp_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); - sc->hook = NULL; - - if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) - && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) - ng_rmnode_self(NG_HOOK_NODE(hook)); - return (0); -} - |