summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/udbp.4104
-rw-r--r--sys/amd64/conf/GENERIC1
-rw-r--r--sys/conf/NOTES2
-rw-r--r--sys/conf/files1
-rw-r--r--sys/dev/usb/udbp.c814
-rw-r--r--sys/dev/usb/udbp.h82
-rw-r--r--sys/i386/conf/GENERIC1
-rw-r--r--sys/i386/conf/LINT2
-rw-r--r--sys/i386/conf/NOTES2
-rw-r--r--sys/modules/Makefile2
-rw-r--r--sys/modules/udbp/Makefile14
11 files changed, 1024 insertions, 1 deletions
diff --git a/share/man/man4/udbp.4 b/share/man/man4/udbp.4
new file mode 100644
index 0000000..6e17ee0
--- /dev/null
+++ b/share/man/man4/udbp.4
@@ -0,0 +1,104 @@
+.\" Copyright (c) 1999
+.\" Nick Hibma <hibma@skylink.it>. 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. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Bill Paul.
+.\" 4. Neither the name of the author nor the names of any co-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 NICK HIBMA OR THE VOICES IN HIS HEAD
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 30, 2000
+.Dt UDBP 4
+.Os FreeBSD
+.Sh NAME
+.Nm udbp
+.Nd USB Double Bulk Pipe driver
+.Sh SYNOPSIS
+.Cd "device udbp"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for host-to-host cables that contain at least two
+bulk pipes, one for each direction, like for example the EzLink cable and
+the NetChip 1080 chip.
+.Pp
+It requires netgraph to be avalable. This can be done either by adding
+.Cd "options NETGRAPH"
+to your kernel configuration file, or alternatively loading
+.Nm netgraph
+as a module either from
+.Pa /boot/loader.conf
+or from the command line, before the udbp module.
+.Sh EXAMPLE
+.Dl options NETGRAPH
+.Dl device udbp
+.Pp
+Add the
+.Nm udbp
+driver to the kernel.
+.Pp
+.Dl kldload netgraph
+.Dl kldload udbp
+.Pp
+Load the
+.Nm netgraph
+module and then the
+.Nm udbp
+driver.
+.Pp
+.Dl ngctl mkpeer udbp0: iface data inet
+.Dl ifconfig ng0 10.0.0.1 10.0.0.2
+.Pp
+Create a new network interface node node and connect it's inet hook to the data
+hook of the
+.Nm udbp
+node. Ifconfig configures the resulting network interface ng0 with a local
+IP address of 10.0.0.1 and a remote 10.0.0.2. On the remote host the two
+IP addresses should of course be reversed.
+.Pp
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ohci 4 ,
+.Xr uhci 4 ,
+.Xr usb 4 ,
+.Xr ngctl 8 ,
+.Xr ng_iface 8 ,
+.Sh HISTORY
+The
+.Nm udbp
+driver first appeared in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Nm udbp
+driver was written by
+.An Doug Ambrisko Aq ambrisko@whistle.com ,
+.An Julian Elischer Aq julian@whistle.com
+and
+.An Nick Hibma Aq n_hibma@freebsd.org .
+.Pp
+This manual page was written by
+.An Nick Hibma Aq hibma@skylink.it .
diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC
index a493058..56b9607 100644
--- a/sys/amd64/conf/GENERIC
+++ b/sys/amd64/conf/GENERIC
@@ -221,6 +221,7 @@ pseudo-device bpf # Berkeley packet filter
#device uhci # UHCI PCI->USB interface
#device ohci # OHCI PCI->USB interface
#device usb # USB Bus (required)
+#device udbp # USB Double Bulk Pipe devices
#device ugen # Generic
#device uhid # "Human Interface Devices"
#device ukbd # Keyboard
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index 3df5e53..954f8a9 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -2235,6 +2235,8 @@ device ohci
# General USB code (mandatory for USB)
device usb
#
+# USB Double Bulk Pipe devices
+device udbp
# Generic USB device driver
device ugen
# Human Interface Device (anything with buttons and dials)
diff --git a/sys/conf/files b/sys/conf/files
index 1168ea6..eb64072 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -268,6 +268,7 @@ dev/usb/if_aue.c optional aue
dev/usb/if_cue.c optional cue
dev/usb/if_kue.c optional kue
dev/usb/ohci.c optional ohci
+dev/usb/udbp.c optional udbp
dev/usb/ugen.c optional ugen
dev/usb/uhci.c optional uhci
dev/usb/uhid.c optional uhid
diff --git a/sys/dev/usb/udbp.c b/sys/dev/usb/udbp.c
new file mode 100644
index 0000000..044331d
--- /dev/null
+++ b/sys/dev/usb/udbp.c
@@ -0,0 +1,814 @@
+/*
+ * 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.
+ *
+ * $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/select.h>
+#include <sys/proc.h>
+#include <sys/poll.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ctype.h>
+#include <sys/errno.h>
+#include <net/if.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 <dev/usb/usbdevs.h>
+
+
+#include <netgraph/ng_message.h>
+#include <netgraph/ng_parse.h>
+#include <dev/usb/udbp.h>
+#include <netgraph/netgraph.h>
+
+#ifdef UDBP_DEBUG
+#define DPRINTF(x) if (udbpdebug) logprintf x
+#define DPRINTFN(n,x) if (udbpdebug>(n)) logprintf x
+int udbpdebug = 9;
+#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_info
+ ng_udbp_stat_type_info = NG_UDBP_STATS_TYPE_INFO;
+static const struct ng_parse_type ng_udbp_stat_type = {
+ &ng_parse_struct_type,
+ &ng_udbp_stat_type_info
+};
+
+/* 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 = {
+ NG_VERSION,
+ NG_UDBP_NODE_TYPE,
+ NULL,
+ ng_udbp_constructor,
+ ng_udbp_rcvmsg,
+ ng_udbp_rmnode,
+ ng_udbp_newhook,
+ NULL,
+ ng_udbp_connect,
+ ng_udbp_rcvdata,
+ ng_udbp_rcvdata,
+ ng_udbp_disconnect,
+ ng_udbp_cmdlist
+};
+
+static int udbp_setup_in_transfer __P((udbp_p sc));
+static void udbp_in_transfer_cb __P((usbd_xfer_handle xfer,
+ usbd_private_handle priv,
+ usbd_status err));
+
+static int udbp_setup_out_transfer __P((udbp_p sc));
+static void udbp_out_transfer_cb __P((usbd_xfer_handle xfer,
+ usbd_private_handle priv,
+ usbd_status err));
+
+USB_DECLARE_DRIVER(udbp);
+
+USB_MATCH(udbp)
+{
+ USB_MATCH_START(udbp, uaa);
+ 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_ANCHOR &&
+ uaa->product == USB_PRODUCT_ANCHOR_EZLINK))
+ return(UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
+
+ return (UMATCH_NONE);
+}
+
+USB_ATTACH(udbp)
+{
+ USB_ATTACH_START(udbp, sc, uaa);
+ 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;
+ char devinfo[1024];
+ 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);
+ usbd_devinfo(uaa->device, 0, devinfo);
+ USB_ATTACH_SETUP;
+ printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev),
+ devinfo, id->bInterfaceClass, id->bInterfaceSubClass);
+
+ /* Find the two first bulk endpoints */
+ for (i = 0 ; i < id->bNumEndpoints; i++) {
+ ed = usbd_interface2endpoint_descriptor(iface, i);
+ if (!ed) {
+ printf("%s: could not read endpoint descriptor\n",
+ USBDEVNAME(sc->sc_dev));
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ 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) {
+ printf("%s: bulk-in and/or bulk-out endpoint not found\n",
+ USBDEVNAME(sc->sc_dev));
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ if (ed_bulkin->wMaxPacketSize[0] != ed_bulkout->wMaxPacketSize[0] ||
+ ed_bulkin->wMaxPacketSize[1] != ed_bulkout->wMaxPacketSize[1]) {
+ printf("%s: bulk-in and bulk-out have different packet sizes %d %d %d %d\n",
+ USBDEVNAME(sc->sc_dev),
+ ed_bulkin->wMaxPacketSize[0],
+ ed_bulkout->wMaxPacketSize[0],
+ ed_bulkin->wMaxPacketSize[1],
+ ed_bulkout->wMaxPacketSize[1]);
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ 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",
+ USBDEVNAME(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) {
+ printf("%s: cannot open bulk-in pipe (addr %d)\n",
+ USBDEVNAME(sc->sc_dev), sc->sc_bulkin);
+ goto bad;
+ }
+ err = usbd_open_pipe(iface, sc->sc_bulkout,
+ USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
+ if (err) {
+ printf("%s: cannot open bulk-out pipe (addr %d)\n",
+ USBDEVNAME(sc->sc_dev), 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];
+ sc->node->private = sc;
+ sc->xmitq.ifq_maxlen = IFQ_MAXLEN;
+ sc->xmitq_hipri.ifq_maxlen = IFQ_MAXLEN;
+ sprintf(nodename, "%s", USBDEVNAME(sc->sc_dev));
+ if ((err = ng_name_node(sc->node, nodename))) {
+ ng_rmnode(sc->node);
+ ng_unref(sc->node);
+ } else {
+ /* something to note it's done */
+ }
+ }
+ if (err) {
+ goto bad;
+ }
+ 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;
+ }
+ USB_ATTACH_SUCCESS_RETURN;
+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);
+ USB_ATTACH_ERROR_RETURN;
+}
+
+
+USB_DETACH(udbp)
+{
+ USB_DETACH_START(udbp, sc);
+
+ sc->flags |= DISCONNECTED;
+
+ DPRINTF(("%s: disconnected\n", USBDEVNAME(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_unname(sc->node);
+ ng_udbp_rmnode(sc->node);
+ sc->node->private = NULL;
+ ng_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",
+ USBDEVNAME(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;
+ meta_p meta = NULL;
+ struct mbuf *m;
+
+ if (err) {
+ if (err != USBD_CANCELLED) {
+ DPRINTF(("%s: bulk-out transfer failed: %s\n",
+ USBDEVNAME(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_DATAQ(err, sc->hook, m, meta);
+ }
+ 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) {
+ printf("%s: Packet too large, %d > %d\n",
+ USBDEVNAME(sc->sc_dev), 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",
+ USBDEVNAME(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",
+ USBDEVNAME(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);
+
+
+/***********************************************************************
+ * 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 *nodep)
+{
+ 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 = node->private;
+
+#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) {
+ /* do something specific to a debug connection */
+ sc->hook = hook;
+ hook->private = 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,
+ struct ng_mesg *msg, const char *retaddr, struct ng_mesg **rptr,
+ hook_p lasthook)
+{
+ const udbp_p sc = node->private;
+ struct ng_mesg *resp = NULL;
+ int error = 0;
+
+ /* 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 */
+ if (rptr)
+ *rptr = resp;
+ else if (resp)
+ FREE(resp, M_NETGRAPH);
+
+ /* Free the message and return */
+ FREE(msg, M_NETGRAPH);
+ return(error);
+}
+
+/*
+ * Accept data from the hook and queue it for output.
+ */
+static int
+ng_udbp_rcvdata(hook_p hook, struct mbuf *m, meta_p meta,
+ struct mbuf **ret_m, meta_p *ret_meta)
+{
+ const udbp_p sc = hook->node->private;
+ int error;
+ struct ifqueue *xmitq_p;
+ int s;
+
+ /*
+ * Now queue the data for when it can be sent
+ */
+ if (meta && meta->priority > 0) {
+ xmitq_p = (&sc->xmitq_hipri);
+ } else {
+ xmitq_p = (&sc->xmitq);
+ }
+ s = splusb();
+ if (IF_QFULL(xmitq_p)) {
+ IF_DROP(xmitq_p);
+ splx(s);
+ error = ENOBUFS;
+ goto bad;
+ }
+ IF_ENQUEUE(xmitq_p, m);
+ 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_DATA(m, meta);
+ 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 = node->private;
+ struct mbuf *m;
+
+ node->flags |= NG_INVALID;
+ ng_cutlinks(node);
+
+ /* Drain the queues */
+ do {
+ IF_DEQUEUE(&sc->xmitq_hipri, m);
+ if (m)
+ m_freem(m);
+ } while (m);
+ do {
+ IF_DEQUEUE(&sc->xmitq, m);
+ if (m)
+ m_freem(m);
+ } while (m);
+
+ sc->packets_in = 0; /* reset stats */
+ sc->packets_out = 0;
+ node->flags &= ~NG_INVALID; /* reset invalid flag */
+ return (0);
+}
+
+/*
+ * 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)
+{
+ /* 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 = hook->node->private;
+ sc->hook = NULL;
+
+ if (hook->node->numhooks == 0)
+ ng_rmnode(hook->node);
+ return (0);
+}
+
diff --git a/sys/dev/usb/udbp.h b/sys/dev/usb/udbp.h
new file mode 100644
index 0000000..a3b04aa
--- /dev/null
+++ b/sys/dev/usb/udbp.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1996-2000 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file was derived from src/sys/netgraph/ng_sample.h, revision 1.1
+ * written by Julian Elischer, Whistle Communications.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NETGRAPH_UDBP_H_
+#define _NETGRAPH_UDBP_H_
+
+/* Node type name. This should be unique among all netgraph node types */
+#define NG_UDBP_NODE_TYPE "udbp"
+
+/* Node type cookie. Should also be unique. This value MUST change whenever
+ an incompatible change is made to this header file, to insure consistency.
+ The de facto method for generating cookies is to take the output of the
+ date command: date -u +'%s' */
+#define NGM_UDBP_COOKIE 944609300
+
+
+#define NG_UDBP_HOOK_NAME "data"
+
+/* Netgraph commands understood by this node type */
+enum {
+ NGM_UDBP_SET_FLAG = 1,
+ NGM_UDBP_GET_STATUS,
+};
+
+/* This structure is returned by the NGM_UDBP_GET_STATUS command */
+struct ngudbpstat {
+ u_int packets_in; /* packets in from downstream */
+ u_int packets_out; /* packets out towards downstream */
+};
+
+/*
+ * This is used to define the 'parse type' for a struct ngudbpstat, which
+ * is bascially a description of how to convert a binary struct ngudbpstat
+ * to an ASCII string and back. See ng_parse.h for more info.
+ *
+ * This needs to be kept in sync with the above structure definition
+ */
+#define NG_UDBP_STATS_TYPE_INFO { \
+ { \
+ { "packets_in", &ng_parse_int32_type }, \
+ { "packets_out", &ng_parse_int32_type }, \
+ { NULL }, \
+ } \
+}
+
+#endif /* _NETGRAPH_UDBP_H_ */
diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC
index a493058..56b9607 100644
--- a/sys/i386/conf/GENERIC
+++ b/sys/i386/conf/GENERIC
@@ -221,6 +221,7 @@ pseudo-device bpf # Berkeley packet filter
#device uhci # UHCI PCI->USB interface
#device ohci # OHCI PCI->USB interface
#device usb # USB Bus (required)
+#device udbp # USB Double Bulk Pipe devices
#device ugen # Generic
#device uhid # "Human Interface Devices"
#device ukbd # Keyboard
diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT
index 3df5e53..954f8a9 100644
--- a/sys/i386/conf/LINT
+++ b/sys/i386/conf/LINT
@@ -2235,6 +2235,8 @@ device ohci
# General USB code (mandatory for USB)
device usb
#
+# USB Double Bulk Pipe devices
+device udbp
# Generic USB device driver
device ugen
# Human Interface Device (anything with buttons and dials)
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index 3df5e53..954f8a9 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -2235,6 +2235,8 @@ device ohci
# General USB code (mandatory for USB)
device usb
#
+# USB Double Bulk Pipe devices
+device udbp
# Generic USB device driver
device ugen
# Human Interface Device (anything with buttons and dials)
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 5ce53c2..2957ce5 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -6,7 +6,7 @@ SUBDIR= aha amr an aue ccd cd9660 coda cue dc fdesc fxp if_disc if_ef if_ppp \
if_sl if_tun ipfilter ipfw joy kernfs kue \
md mfs mii mlx msdos ncp netgraph nfs ntfs nullfs \
nwfs portal procfs rl sf sis sk ste ti tl tx \
- ugen uhid ukbd ulpt umapfs umass umodem ums union urio usb \
+ udbp ugen uhid ukbd ulpt umapfs umass umodem ums union urio usb \
vinum vn vpo vr wb xl
# XXX some of these can move to the general case when de-i386'ed
diff --git a/sys/modules/udbp/Makefile b/sys/modules/udbp/Makefile
new file mode 100644
index 0000000..3b41de2
--- /dev/null
+++ b/sys/modules/udbp/Makefile
@@ -0,0 +1,14 @@
+# $FreeBSD$
+
+MAINTAINER = n_hibma@freebsd.org
+
+.PATH: ${.CURDIR}/../../dev/usb
+KMOD = udbp
+SRCS = bus_if.h device_if.h \
+ opt_usb.h \
+ udbp.c
+NOMAN =
+
+CFLAGS += -DUDBP_DEBUG
+
+.include <bsd.kmod.mk>
OpenPOWER on IntegriCloud