[PATCH2] for ng_ubt2 stalled transfers
Lars Engels
lme at FreeBSD.org
Fri Jan 23 14:17:07 PST 2009
On Fri, Jan 23, 2009 at 10:49:23PM +0100, Hans Petter Selasky wrote:
> On Friday 23 January 2009, Lars Engels wrote:
> > I forgot to mention that both bt devices worked without problems with
> > the old stack, so there is no hardware issue. :)
>
> Hi,
>
> Bluetooth has worked fine with the new USB stack aswell. I have tested this
> myself. It is just some small problems with the latest changes from Maksim
> that needs to be ironed out.
>
> Maybe you can give my patch a try?
>
> cvsup first
>
> Then:
>
> cd /usr/src/sys/dev/usb2/bluetooth; cat bt_patch.diff | patch
>
> recompile "/usr/src/sys/modules/usb2/bluetooth_ng" module only and test,
> assuming you are loading the module.
>
> I'm not sure if my patch is 100% correct, Maksim is the bluetooth+Netgraph
> expert, but at least my bluetooth dongle now works again.
>
This didn't work too well, the patch did not apply:
ng collection src-all/cvs
Checkout src/sys/dev/usb2/bluetooth/TODO.TXT
Checkout src/sys/dev/usb2/bluetooth/ng_ubt2.c
Checkout src/sys/dev/usb2/bluetooth/ng_ubt2_var.h
Checkout src/sys/dev/usb2/bluetooth/ubtbcmfw2.c
Checkout src/sys/dev/usb2/bluetooth/usb2_bluetooth.c
Checkout src/sys/dev/usb2/bluetooth/usb2_bluetooth.h
Shutting down connection to server
Finished successfully
Fri, 23. Jan 2009, 23:14:44 <FreeBSD 8.0-CURRENT> [maggie:/usr/src/sys/dev/usb2/bluetooth] lars at pts/3 # cat ~/local-patches/bt_patch.diff | patch
Hmm... Looks like a unified diff to me...
The text leading up to this was:
--------------------------
|diff -u ng_ubt2.c ng_ubt2.c
|--- ng_ubt2.c Wed Jan 21 17:51:04 2009
|+++ ng_ubt2.c Fri Jan 23 20:17:44 2009
--------------------------
Patching file ng_ubt2.c using Plan A...
Reversed (or previously applied) patch detected! Assume -R? [y] y
Hunk #1 succeeded at 28.
Hunk #2 failed at 37.
Hunk #3 failed at 67.
Hunk #4 failed at 111.
Hunk #5 succeeded at 163 with fuzz 2 (offset 35 lines).
Hunk #6 failed at 314.
Hunk #7 failed at 323.
Hunk #8 failed at 332.
Hunk #9 failed at 341.
Hunk #10 failed at 350.
Hunk #11 failed at 360.
Hunk #12 failed at 373.
Hunk #13 failed at 388.
Hunk #14 failed at 398.
Hunk #15 failed at 408.
Hunk #16 failed at 418.
Hunk #17 failed at 485.
Hunk #18 failed at 518.
Hunk #19 failed at 555.
Hunk #20 failed at 615.
Hunk #21 failed at 629.
Hunk #22 failed at 647.
Hunk #23 failed at 665.
Hunk #24 failed at 692.
Hunk #25 succeeded at 825 with fuzz 2 (offset 106 lines).
Hunk #26 failed at 846.
Hunk #27 failed at 942.
Hunk #28 succeeded at 834 with fuzz 2 (offset -21 lines).
Hunk #29 failed at 846.
Hunk #30 failed at 866.
Hunk #31 failed at 962.
Hunk #32 succeeded at 980 with fuzz 2 (offset -22 lines).
Hunk #33 failed at 992.
Hunk #34 failed at 1009.
Hunk #35 failed at 1067.
Hunk #36 succeeded at 1115 with fuzz 2 (offset 7 lines).
Hunk #37 failed at 1127.
Hunk #38 succeeded at 1121 with fuzz 2 (offset -16 lines).
Hunk #39 failed at 1155.
Hunk #40 failed at 1261.
Hunk #41 failed at 1289.
Hunk #42 failed at 1312.
Hunk #43 failed at 1339.
Hunk #44 failed at 1530.
Hunk #45 failed at 1576.
Hunk #46 failed at 1593.
Hunk #47 failed at 1602.
Hunk #48 failed at 1648.
Hunk #49 failed at 1656.
Hunk #50 failed at 1807.
Hunk #51 failed at 1837.
Hunk #52 failed at 1847.
Hunk #53 failed at 1865.
Hunk #54 failed at 1878.
Hunk #55 succeeded at 2235 (offset 273 lines).
47 out of 55 hunks failed--saving rejects to ng_ubt2.c.rej
Hmm... The next patch looks like a unified diff to me...
The text leading up to this was:
--------------------------
|diff -u ng_ubt2_var.h ng_ubt2_var.h
|--- ng_ubt2_var.h Wed Jan 21 17:51:04 2009
|+++ ng_ubt2_var.h Fri Jan 23 20:08:04 2009
--------------------------
Patching file ng_ubt2_var.h using Plan A...
Reversed (or previously applied) patch detected! Assume -R? [y] y
Hunk #1 succeeded at 28.
Hunk #2 failed at 47.
Hunk #3 failed at 65.
Hunk #4 failed at 89.
Hunk #5 failed at 100.
Hunk #6 failed at 123.
5 out of 6 hunks failed--saving rejects to ng_ubt2_var.h.rej
done
Exit 52
> diff -u ng_ubt2.c ng_ubt2.c
> --- ng_ubt2.c Wed Jan 21 17:51:04 2009
> +++ ng_ubt2.c Fri Jan 23 20:17:44 2009
> @@ -28,7 +28,7 @@
> * SUCH DAMAGE.
> *
> * $Id: ng_ubt.c,v 1.16 2003/10/10 19:15:06 max Exp $
> - * $FreeBSD$
> + * $FreeBSD: src/sys/dev/usb2/bluetooth/ng_ubt2.c,v 1.6 2009/01/20 23:25:27 emax Exp $
> */
>
> /*
> @@ -37,22 +37,12 @@
> * driver will *NOT* create traditional /dev/ enties, only Netgraph
> * node.
> *
> - * NOTE ON LOCKS USED: ng_ubt2 drives uses 3 locks (mutexes)
> + * NOTE ON LOCKS USED: ng_ubt2 drives uses 1 lock
> *
> - * 1) sc_if_mtx[0] - lock for device's interface #0. This lock is used
> - * by USB2 for any USB request going over device's interface #0, i.e.
> - * interrupt, control and bulk transfers.
> - *
> - * 2) sc_if_mtx[1] - lock for device's interface #1. This lock is used
> - * by USB2 for any USB request going over device's interface #1, i.e
> - * isoc. transfers.
> - *
> - * 3) sc_mbufq_mtx - lock for mbufq and task flags. This lock is used
> - * to protect device's outgoing mbuf queues and task flags. This lock
> - * *SHOULD NOT* be grabbed for a long time. In fact, think of it as a
> - * spin lock.
> + * The "sc_mtx" lock protects both USB and Netgraph data. The "sc_mtx"
> + * lock should not be grabbed for a long time.
> *
> - * NOTE ON LOCKING STRATEGY: ng_ubt2 driver operates in 3 different contexts.
> + * NOTE ON LOCKING STRATEGY: ng_ubt2 driver operates in 2 different contexts.
> *
> * 1) USB context. This is where all the USB related stuff happens. All
> * callbacks run in this context. All callbacks are called (by USB2) with
> @@ -67,26 +57,6 @@
> * grab any long-sleep lock in the Netgraph context. In fact, the only
> * lock that is allowed in the Netgraph context is the sc_mbufq_mtx lock.
> *
> - * 3) Taskqueue context. This is where ubt_task runs. Since we are NOT allowed
> - * to grab any locks in the Netgraph context, and, USB2 requires us to
> - * grab interface lock before doing things with transfers, we need to
> - * transition from the Netgraph context to the Taskqueue context before
> - * we can call into USB2 subsystem.
> - *
> - * So, to put everything together, the rules are as follows.
> - * It is OK to call from the USB context or the Taskqueue context into
> - * the Netgraph context (i.e. call NG_SEND_xxx functions). In other words
> - * it is allowed to call into the Netgraph context with locks held.
> - * Is it *NOT* OK to call from the Netgraph context into the USB context,
> - * because USB2 requires us to grab interface locks and we can not do that.
> - * To avoid this, we set task flags to indicate which actions we want to
> - * perform and schedule ubt_task which would run in the Taskqueue context.
> - * Is is OK to call from the Taskqueue context into the USB context,
> - * and, ubt_task does just that (i.e. grabs appropriate interface locks
> - * before calling into USB2).
> - * Access to the outgoing queues and task flags is controlled by the
> - * sc_mbufq_mtx lock. It is an unavoidable evil. Again, sc_mbufq_mtx should
> - * really be a spin lock.
> * All USB callbacks accept Netgraph node pointer as private data. To
> * ensure that Netgraph node pointer remains valid for the duration of the
> * transfer, we grab a referrence to the node. In other words, if transfer is
> @@ -111,7 +81,6 @@
> #include <dev/usb2/core/usb2_transfer.h>
>
> #include <sys/mbuf.h>
> -#include <sys/taskqueue.h>
>
> #include <netgraph/ng_message.h>
> #include <netgraph/netgraph.h>
> @@ -128,10 +97,6 @@
> static device_attach_t ubt_attach;
> static device_detach_t ubt_detach;
>
> -static int ubt_task_schedule(ubt_softc_p, int);
> -static task_fn_t ubt_task;
> -static void ubt_xfer_start(ubt_softc_p, int);
> -
> /* Netgraph methods */
> static ng_constructor_t ng_ubt_constructor;
> static ng_shutdown_t ng_ubt_shutdown;
> @@ -279,6 +244,7 @@
> .type = UE_BULK,
> .endpoint = UE_ADDR_ANY,
> .direction = UE_DIR_OUT,
> + .if_index = 0,
> .mh.bufsize = UBT_BULK_WRITE_BUFFER_SIZE,
> .mh.flags = { .pipe_bof = 1, },
> .mh.callback = &ubt_bulk_write_callback,
> @@ -288,6 +254,7 @@
> .type = UE_BULK,
> .endpoint = UE_ADDR_ANY,
> .direction = UE_DIR_IN,
> + .if_index = 0,
> .mh.bufsize = UBT_BULK_READ_BUFFER_SIZE,
> .mh.flags = { .pipe_bof = 1, .short_xfer_ok = 1, },
> .mh.callback = &ubt_bulk_read_callback,
> @@ -297,6 +264,7 @@
> .type = UE_INTERRUPT,
> .endpoint = UE_ADDR_ANY,
> .direction = UE_DIR_IN,
> + .if_index = 0,
> .mh.flags = { .pipe_bof = 1, .short_xfer_ok = 1, },
> .mh.bufsize = UBT_INTR_BUFFER_SIZE,
> .mh.callback = &ubt_intr_read_callback,
> @@ -306,6 +274,7 @@
> .type = UE_CONTROL,
> .endpoint = 0x00, /* control pipe */
> .direction = UE_DIR_ANY,
> + .if_index = 0,
> .mh.bufsize = UBT_CTRL_BUFFER_SIZE,
> .mh.callback = &ubt_ctrl_write_callback,
> .mh.timeout = 5000, /* 5 seconds */
> @@ -315,6 +284,7 @@
> .type = UE_CONTROL,
> .endpoint = 0x00, /* control pipe */
> .direction = UE_DIR_ANY,
> + .if_index = 0,
> .mh.bufsize = sizeof(struct usb2_device_request),
> .mh.callback = &ubt_bulk_write_clear_stall_callback,
> .mh.timeout = 1000, /* 1 second */
> @@ -325,6 +295,7 @@
> .type = UE_CONTROL,
> .endpoint = 0x00, /* control pipe */
> .direction = UE_DIR_ANY,
> + .if_index = 0,
> .mh.bufsize = sizeof(struct usb2_device_request),
> .mh.callback = &ubt_bulk_read_clear_stall_callback,
> .mh.timeout = 1000, /* 1 second */
> @@ -338,6 +309,7 @@
> .type = UE_CONTROL,
> .endpoint = 0x00, /* control pipe */
> .direction = UE_DIR_ANY,
> + .if_index = 0,
> .mh.bufsize = sizeof(struct usb2_device_request),
> .mh.callback = &ubt_intr_read_clear_stall_callback,
> .mh.timeout = 1000, /* 1 second */
> @@ -353,6 +325,7 @@
> .type = UE_ISOCHRONOUS,
> .endpoint = UE_ADDR_ANY,
> .direction = UE_DIR_IN,
> + .if_index = 1,
> .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */
> .mh.frames = UBT_ISOC_NFRAMES,
> .mh.flags = { .short_xfer_ok = 1, },
> @@ -363,6 +336,7 @@
> .type = UE_ISOCHRONOUS,
> .endpoint = UE_ADDR_ANY,
> .direction = UE_DIR_IN,
> + .if_index = 1,
> .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */
> .mh.frames = UBT_ISOC_NFRAMES,
> .mh.flags = { .short_xfer_ok = 1, },
> @@ -373,6 +347,7 @@
> .type = UE_ISOCHRONOUS,
> .endpoint = UE_ADDR_ANY,
> .direction = UE_DIR_OUT,
> + .if_index = 1,
> .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */
> .mh.frames = UBT_ISOC_NFRAMES,
> .mh.flags = { .short_xfer_ok = 1, },
> @@ -383,6 +358,7 @@
> .type = UE_ISOCHRONOUS,
> .endpoint = UE_ADDR_ANY,
> .direction = UE_DIR_OUT,
> + .if_index = 1,
> .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */
> .mh.frames = UBT_ISOC_NFRAMES,
> .mh.flags = { .short_xfer_ok = 1, },
> @@ -450,7 +426,8 @@
> struct ubt_softc *sc = device_get_softc(dev);
> struct usb2_endpoint_descriptor *ed;
> uint16_t wMaxPacketSize;
> - uint8_t alt_index, iface_index, i, j;
> + uint8_t alt_index, i, j;
> + uint8_t iface_index[2];
>
> device_set_usb2_desc(dev);
>
> @@ -483,28 +460,22 @@
>
> /* state */
> sc->sc_debug = NG_UBT_WARN_LEVEL;
> - sc->sc_flags = 0;
> +
> UBT_STAT_RESET(sc);
>
> /* initialize locks */
> - mtx_init(&sc->sc_mbufq_mtx, "ubt mbufq", NULL, MTX_DEF);
> - mtx_init(&sc->sc_if_mtx[0], "ubt if0", NULL, MTX_DEF | MTX_RECURSE);
> - mtx_init(&sc->sc_if_mtx[1], "ubt if1", NULL, MTX_DEF | MTX_RECURSE);
> + mtx_init(&sc->sc_mtx, "UBT", NULL, MTX_DEF | MTX_RECURSE);
>
> /* initialize packet queues */
> NG_BT_MBUFQ_INIT(&sc->sc_cmdq, UBT_DEFAULT_QLEN);
> NG_BT_MBUFQ_INIT(&sc->sc_aclq, UBT_DEFAULT_QLEN);
> NG_BT_MBUFQ_INIT(&sc->sc_scoq, UBT_DEFAULT_QLEN);
>
> - /* initialize glue task */
> - sc->sc_task_flags = 0;
> - TASK_INIT(&sc->sc_task, 0, ubt_task, sc->sc_node);
> -
> /*
> * Configure Bluetooth USB device. Discover all required USB
> * interfaces and endpoints.
> *
> - * Device is expected to be a high-speed device.
> + * Device is expected to be a full-speed device.
> *
> * USB device must present two interfaces:
> * 1) Interface 0 that has 3 endpoints
> @@ -520,20 +491,11 @@
> * configurations with different packet size.
> */
>
> - bzero(&sc->sc_xfer, sizeof(sc->sc_xfer));
> -
> /*
> * Interface 0
> */
>
> - iface_index = 0;
> - if (usb2_transfer_setup(uaa->device, &iface_index, sc->sc_xfer,
> - ubt_config, UBT_IF_0_N_TRANSFER,
> - sc->sc_node, &sc->sc_if_mtx[0])) {
> - device_printf(dev, "could not allocate transfers for " \
> - "interface 0!\n");
> - goto detach;
> - }
> + iface_index[0] = 0;
>
> /*
> * Interface 1
> @@ -580,13 +542,11 @@
> goto detach;
> }
>
> - iface_index = 1;
> - if (usb2_transfer_setup(uaa->device, &iface_index,
> - &sc->sc_xfer[UBT_IF_0_N_TRANSFER],
> - &ubt_config[UBT_IF_0_N_TRANSFER], UBT_IF_1_N_TRANSFER,
> - sc->sc_node, &sc->sc_if_mtx[1])) {
> - device_printf(dev, "could not allocate transfers for " \
> - "interface 1!\n");
> + iface_index[1] = 1;
> + if (usb2_transfer_setup(uaa->device, iface_index,
> + sc->sc_xfer, ubt_config, UBT_N_TRANSFER,
> + sc->sc_node, &sc->sc_mtx)) {
> + device_printf(dev, "could not allocate transfers\n");
> goto detach;
> }
>
> @@ -594,6 +554,10 @@
> for (i = 1; usb2_get_iface(uaa->device, i) != NULL; i ++)
> usb2_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex);
>
> + UBT_LOCK(sc);
> + sc->sc_flags |= UBT_FLAG_READY;
> + UBT_UNLOCK(sc);
> +
> return (0); /* success */
>
> detach:
> @@ -612,17 +576,33 @@
> {
> struct ubt_softc *sc = device_get_softc(dev);
> node_p node = sc->sc_node;
> + uint8_t i;
> +
> + UBT_LOCK(sc);
> + sc->sc_flags &= ~UBT_FLAG_READY;
> + UBT_UNLOCK(sc);
> +
> + /* make sure that all USB transfers are stopped! */
> + for (i = 0; i != UBT_N_TRANSFER; i++)
> + usb2_transfer_drain(sc->sc_xfer[i]);
>
> /* Destroy Netgraph node */
> if (node != NULL) {
> sc->sc_node = NULL;
>
> - NG_NODE_SET_PRIVATE(node, NULL);
> NG_NODE_REALLY_DIE(node);
> - NG_NODE_REF(node);
> ng_rmnode_self(node);
> - }
>
> + /* Need to wait until Netgraph has shutdown the node! */
> + UBT_LOCK(sc);
> + while (!(sc->sc_flags & UBT_FLAG_SHUTDOWN))
> + usb2_pause_mtx(&sc->sc_mtx, 100);
> + UBT_UNLOCK(sc);
> +
> + /* Check if there is a leftover hook */
> + if (sc->sc_hook != NULL)
> + NG_NODE_UNREF(node);
> + }
> /* Free USB transfers, if any */
> usb2_transfer_unsetup(sc->sc_xfer, UBT_N_TRANSFER);
>
> @@ -630,15 +610,13 @@
> NG_NODE_UNREF(node);
>
> /* Destroy queues */
> - UBT_MBUFQ_LOCK(sc);
> + UBT_LOCK(sc);
> NG_BT_MBUFQ_DESTROY(&sc->sc_cmdq);
> NG_BT_MBUFQ_DESTROY(&sc->sc_aclq);
> NG_BT_MBUFQ_DESTROY(&sc->sc_scoq);
> - UBT_MBUFQ_UNLOCK(sc);
> + UBT_UNLOCK(sc);
>
> - mtx_destroy(&sc->sc_if_mtx[0]);
> - mtx_destroy(&sc->sc_if_mtx[1]);
> - mtx_destroy(&sc->sc_mbufq_mtx);
> + mtx_destroy(&sc->sc_mtx);
>
> return (0);
> } /* ubt_detach */
> @@ -657,37 +635,25 @@
> struct usb2_device_request req;
> struct mbuf *m;
>
> - if (NG_NODE_NOT_VALID(node)) {
> - NG_NODE_UNREF(node);
> - return; /* netgraph node is gone */
> - }
> -
> sc = NG_NODE_PRIVATE(node);
>
> switch (USB_GET_STATE(xfer)) {
> case USB_ST_TRANSFERRED:
> - if (xfer->error != 0)
> - UBT_STAT_OERROR(sc);
> - else {
> - UBT_INFO(sc, "sent %d bytes to control pipe\n",
> - xfer->actlen);
> + UBT_INFO(sc, "sent %d bytes to control pipe\n",
> + xfer->actlen);
> +
> + UBT_STAT_BYTES_SENT(sc, xfer->actlen);
> + UBT_STAT_PCKTS_SENT(sc);
>
> - UBT_STAT_BYTES_SENT(sc, xfer->actlen);
> - UBT_STAT_PCKTS_SENT(sc);
> - }
> /* FALLTHROUGH */
>
> case USB_ST_SETUP:
> send_next:
> /* Get next command mbuf, if any */
> - UBT_MBUFQ_LOCK(sc);
> NG_BT_MBUFQ_DEQUEUE(&sc->sc_cmdq, m);
> - UBT_MBUFQ_UNLOCK(sc);
> -
> if (m == NULL) {
> UBT_INFO(sc, "HCI command queue is empty\n");
> - NG_NODE_UNREF(node);
> - return;
> + break;
> }
>
> /* Initialize a USB control request and then schedule it */
> @@ -719,8 +685,6 @@
> UBT_STAT_OERROR(sc);
> goto send_next;
> }
> -
> - NG_NODE_UNREF(node); /* cancelled */
> break;
> }
> } /* ubt_ctrl_write_callback */
> @@ -740,19 +704,8 @@
> ng_hci_event_pkt_t *hdr;
> int error;
>
> - if (NG_NODE_NOT_VALID(node)) {
> - NG_NODE_UNREF(node);
> - return; /* netgraph node is gone */
> - }
> -
> sc = NG_NODE_PRIVATE(node);
>
> - if ((sc->sc_hook == NULL) || NG_HOOK_NOT_VALID(sc->sc_hook)) {
> - UBT_INFO(sc, "no upstream hook\n");
> - NG_NODE_UNREF(node);
> - return; /* upstream hook is gone */
> - }
> -
> m = NULL;
>
> switch (USB_GET_STATE(xfer)) {
> @@ -836,8 +789,7 @@
> /* Try to clear stall first */
> sc->sc_flags |= UBT_FLAG_INTR_STALL;
> usb2_transfer_start(sc->sc_xfer[UBT_IF_0_INTR_CS_RD]);
> - } else
> - NG_NODE_UNREF(node); /* cancelled */
> + }
> break;
> }
> } /* ubt_intr_read_callback */
> @@ -855,11 +807,6 @@
> struct ubt_softc *sc;
> struct usb2_xfer *xfer_other;
>
> - if (NG_NODE_NOT_VALID(node)) {
> - NG_NODE_UNREF(node);
> - return; /* netgraph node is gone */
> - }
> -
> sc = NG_NODE_PRIVATE(node);
> xfer_other = sc->sc_xfer[UBT_IF_0_INTR_DT_RD];
>
> @@ -867,8 +814,7 @@
> DPRINTF("stall cleared\n");
> sc->sc_flags &= ~UBT_FLAG_INTR_STALL;
> usb2_transfer_start(xfer_other);
> - } else
> - NG_NODE_UNREF(node); /* cant clear stall */
> + }
> } /* ubt_intr_read_clear_stall_callback */
>
> /*
> @@ -887,19 +833,7 @@
> uint16_t len;
> int error;
>
> - if (NG_NODE_NOT_VALID(node)) {
> - NG_NODE_UNREF(node);
> - return; /* netgraph node is gone */
> - }
> -
> sc = NG_NODE_PRIVATE(node);
> -
> - if ((sc->sc_hook == NULL) || NG_HOOK_NOT_VALID(sc->sc_hook)) {
> - UBT_INFO(sc, "no upstream hook\n");
> - NG_NODE_UNREF(node);
> - return; /* upstream hook is gone */
> - }
> -
> m = NULL;
>
> switch (USB_GET_STATE(xfer)) {
> @@ -983,8 +917,7 @@
> /* Try to clear stall first */
> sc->sc_flags |= UBT_FLAG_READ_STALL;
> usb2_transfer_start(sc->sc_xfer[UBT_IF_0_BULK_CS_RD]);
> - } else
> - NG_NODE_UNREF(node); /* cancelled */
> + }
> break;
> }
> } /* ubt_bulk_read_callback */
> @@ -1002,11 +935,6 @@
> struct ubt_softc *sc;
> struct usb2_xfer *xfer_other;
>
> - if (NG_NODE_NOT_VALID(node)) {
> - NG_NODE_UNREF(node);
> - return; /* netgraph node is gone */
> - }
> -
> sc = NG_NODE_PRIVATE(node);
> xfer_other = sc->sc_xfer[UBT_IF_0_BULK_DT_RD];
>
> @@ -1014,8 +942,7 @@
> DPRINTF("stall cleared\n");
> sc->sc_flags &= ~UBT_FLAG_READ_STALL;
> usb2_transfer_start(xfer_other);
> - } else
> - NG_NODE_UNREF(node); /* cant clear stall */
> + }
> } /* ubt_bulk_read_clear_stall_callback */
>
> /*
> @@ -1031,36 +958,24 @@
> struct ubt_softc *sc;
> struct mbuf *m;
>
> - if (NG_NODE_NOT_VALID(node)) {
> - NG_NODE_UNREF(node);
> - return; /* netgraph node is gone */
> - }
> -
> sc = NG_NODE_PRIVATE(node);
>
> switch (USB_GET_STATE(xfer)) {
> case USB_ST_TRANSFERRED:
> - if (xfer->error != 0)
> - UBT_STAT_OERROR(sc);
> - else {
> - UBT_INFO(sc, "sent %d bytes to bulk-out pipe\n",
> - xfer->actlen);
> + UBT_INFO(sc, "sent %d bytes to bulk-out pipe\n",
> + xfer->actlen);
> +
> + UBT_STAT_BYTES_SENT(sc, xfer->actlen);
> + UBT_STAT_PCKTS_SENT(sc);
>
> - UBT_STAT_BYTES_SENT(sc, xfer->actlen);
> - UBT_STAT_PCKTS_SENT(sc);
> - }
> /* FALLTHROUGH */
>
> case USB_ST_SETUP:
> /* Get next mbuf, if any */
> - UBT_MBUFQ_LOCK(sc);
> NG_BT_MBUFQ_DEQUEUE(&sc->sc_aclq, m);
> - UBT_MBUFQ_UNLOCK(sc);
> -
> if (m == NULL) {
> UBT_INFO(sc, "ACL data queue is empty\n");
> - NG_NODE_UNREF(node);
> - return; /* transfer completed */
> + break;
> }
>
> /*
> @@ -1089,8 +1004,7 @@
> /* try to clear stall first */
> sc->sc_flags |= UBT_FLAG_WRITE_STALL;
> usb2_transfer_start(sc->sc_xfer[UBT_IF_0_BULK_CS_WR]);
> - } else
> - NG_NODE_UNREF(node); /* cancelled */
> + }
> break;
> }
> } /* ubt_bulk_write_callback */
> @@ -1108,11 +1022,6 @@
> struct ubt_softc *sc;
> struct usb2_xfer *xfer_other;
>
> - if (NG_NODE_NOT_VALID(node)) {
> - NG_NODE_UNREF(node);
> - return; /* netgraph node is gone */
> - }
> -
> sc = NG_NODE_PRIVATE(node);
> xfer_other = sc->sc_xfer[UBT_IF_0_BULK_DT_WR];
>
> @@ -1120,8 +1029,7 @@
> DPRINTF("stall cleared\n");
> sc->sc_flags &= ~UBT_FLAG_WRITE_STALL;
> usb2_transfer_start(xfer_other);
> - } else
> - NG_NODE_UNREF(node); /* cant clear stall */
> + }
> } /* ubt_bulk_write_clear_stall_callback */
>
> /*
> @@ -1137,19 +1045,8 @@
> struct ubt_softc *sc;
> int n;
>
> - if (NG_NODE_NOT_VALID(node)) {
> - NG_NODE_UNREF(node);
> - return; /* netgraph node is gone */
> - }
> -
> sc = NG_NODE_PRIVATE(node);
>
> - if ((sc->sc_hook == NULL) || NG_HOOK_NOT_VALID(sc->sc_hook)) {
> - UBT_INFO(sc, "no upstream hook\n");
> - NG_NODE_UNREF(node);
> - return; /* upstream hook is gone */
> - }
> -
> switch (USB_GET_STATE(xfer)) {
> case USB_ST_TRANSFERRED:
> for (n = 0; n < xfer->nframes; n ++)
> @@ -1171,8 +1068,6 @@
> goto read_next;
> /* NOT REACHED */
> }
> -
> - NG_NODE_UNREF(node); /* cancelled */
> break;
> }
> } /* ubt_isoc_read_callback */
> @@ -1277,24 +1172,16 @@
> struct mbuf *m;
> int n, space, offset;
>
> - if (NG_NODE_NOT_VALID(node)) {
> - NG_NODE_UNREF(node);
> - return; /* netgraph node is gone */
> - }
> -
> sc = NG_NODE_PRIVATE(node);
>
> switch (USB_GET_STATE(xfer)) {
> case USB_ST_TRANSFERRED:
> - if (xfer->error)
> - UBT_STAT_OERROR(sc);
> - else {
> - UBT_INFO(sc, "sent %d bytes to isoc-out pipe\n",
> - xfer->actlen);
> + UBT_INFO(sc, "sent %d bytes to isoc-out pipe\n",
> + xfer->actlen);
> +
> + UBT_STAT_BYTES_SENT(sc, xfer->actlen);
> + UBT_STAT_PCKTS_SENT(sc);
>
> - UBT_STAT_BYTES_SENT(sc, xfer->actlen);
> - UBT_STAT_PCKTS_SENT(sc);
> - }
> /* FALLTHROUGH */
>
> case USB_ST_SETUP:
> @@ -1305,10 +1192,7 @@
>
> while (space > 0) {
> if (m == NULL) {
> - UBT_MBUFQ_LOCK(sc);
> NG_BT_MBUFQ_DEQUEUE(&sc->sc_scoq, m);
> - UBT_MBUFQ_UNLOCK(sc);
> -
> if (m == NULL)
> break;
> }
> @@ -1328,9 +1212,7 @@
>
> /* Put whatever is left from mbuf back on queue */
> if (m != NULL) {
> - UBT_MBUFQ_LOCK(sc);
> NG_BT_MBUFQ_PREPEND(&sc->sc_scoq, m);
> - UBT_MBUFQ_UNLOCK(sc);
> }
>
> /*
> @@ -1355,174 +1237,12 @@
> goto send_next;
> /* NOT REACHED */
> }
> -
> - NG_NODE_UNREF(node); /* cancelled */
> break;
> }
> }
>
> /****************************************************************************
> ****************************************************************************
> - ** Glue
> - ****************************************************************************
> - ****************************************************************************/
> -
> -/*
> - * Schedule glue task. Should be called with sc_mbufq_mtx held.
> - * Netgraph context.
> - */
> -
> -static int
> -ubt_task_schedule(ubt_softc_p sc, int action)
> -{
> - mtx_assert(&sc->sc_mbufq_mtx, MA_OWNED);
> -
> - if ((sc->sc_task_flags & action) == 0) {
> - /*
> - * Try to handle corner case when "start all" and "stop all"
> - * actions can both be set before task is executed.
> - *
> - * Assume the following:
> - * 1) "stop all" after "start all" cancels "start all", and,
> - * keeps "stop all"
> - *
> - * 2) "start all" after "stop all" is fine because task is
> - * executing "stop all" first
> - */
> -
> - if (action == UBT_FLAG_T_STOP_ALL &&
> - (sc->sc_task_flags & UBT_FLAG_T_START_ALL) != 0)
> - sc->sc_task_flags &= ~UBT_FLAG_T_START_ALL;
> -
> - sc->sc_task_flags |= action;
> - }
> -
> - if (sc->sc_task_flags & UBT_FLAG_T_PENDING)
> - return (1);
> -
> - if (taskqueue_enqueue(taskqueue_swi, &sc->sc_task) == 0) {
> - NG_NODE_REF(sc->sc_node);
> - sc->sc_task_flags |= UBT_FLAG_T_PENDING;
> - return (1);
> - }
> -
> - /* XXX: i think this should never happen */
> -
> - return (0);
> -} /* ubt_task_schedule */
> -
> -/*
> - * Glue task. Examines sc_task_flags and does things depending on it.
> - * Taskqueue context.
> - */
> -
> -static void
> -ubt_task(void *context, int pending)
> -{
> - node_p node = context;
> - ubt_softc_p sc;
> - int task_flags;
> -
> - if (NG_NODE_NOT_VALID(node)) {
> - NG_NODE_UNREF(node);
> - return; /* netgraph node is gone */
> - }
> -
> - sc = NG_NODE_PRIVATE(node);
> -
> - UBT_MBUFQ_LOCK(sc);
> - task_flags = sc->sc_task_flags;
> - sc->sc_task_flags = 0;
> - UBT_MBUFQ_UNLOCK(sc);
> -
> - /* Stop all USB transfers */
> - if (task_flags & UBT_FLAG_T_STOP_ALL) {
> - int i;
> -
> - /*
> - * Interface #0
> - */
> -
> - mtx_lock(&sc->sc_if_mtx[0]);
> -
> - for (i = UBT_IF_0_BULK_DT_WR; i < UBT_IF_0_N_TRANSFER; i ++)
> - usb2_transfer_stop(sc->sc_xfer[i]);
> -
> - mtx_unlock(&sc->sc_if_mtx[0]);
> -
> - /*
> - * Interface #1
> - */
> -
> - mtx_lock(&sc->sc_if_mtx[1]);
> -
> - for (i = UBT_IF_1_ISOC_DT_RD1; i < UBT_N_TRANSFER; i ++)
> - usb2_transfer_stop(sc->sc_xfer[i]);
> -
> - mtx_unlock(&sc->sc_if_mtx[1]);
> - }
> -
> - /* Start all incoming USB transfers */
> - if (task_flags & UBT_FLAG_T_START_ALL) {
> - /*
> - * Interface #0
> - */
> -
> - mtx_lock(&sc->sc_if_mtx[0]);
> - ubt_xfer_start(sc, UBT_IF_0_INTR_DT_RD);
> - ubt_xfer_start(sc, UBT_IF_0_BULK_DT_RD);
> - mtx_unlock(&sc->sc_if_mtx[0]);
> -
> - /*
> - * Interface #1
> - * Start both read and write isoc. transfers by default.
> - * Get them going all the time even if we have nothing
> - * to send to avoid any delays.
> - */
> -
> - mtx_lock(&sc->sc_if_mtx[1]);
> - ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_RD1);
> - ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_RD2);
> - ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_WR1);
> - ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_WR2);
> - mtx_unlock(&sc->sc_if_mtx[1]);
> - }
> -
> - /* Start outgoing control transfer */
> - if (task_flags & UBT_FLAG_T_START_CTRL) {
> - mtx_lock(&sc->sc_if_mtx[0]);
> - ubt_xfer_start(sc, UBT_IF_0_CTRL_DT_WR);
> - mtx_unlock(&sc->sc_if_mtx[0]);
> - }
> -
> - /* Start outgoing bulk transfer */
> - if (task_flags & UBT_FLAG_T_START_BULK) {
> - mtx_lock(&sc->sc_if_mtx[0]);
> - ubt_xfer_start(sc, UBT_IF_0_BULK_DT_WR);
> - mtx_unlock(&sc->sc_if_mtx[0]);
> - }
> -
> - NG_NODE_UNREF(node);
> -} /* ubt_task */
> -
> -/*
> - * Start USB transfer.
> - * Helper function called from ubt_task. Must be called with appropriate
> - * interface lock held.
> - * Taskqueue context.
> - */
> -
> -static void
> -ubt_xfer_start(ubt_softc_p sc, int transfer)
> -{
> - if (!usb2_transfer_pending(sc->sc_xfer[transfer])) {
> - NG_NODE_REF(sc->sc_node);
> - usb2_transfer_start(sc->sc_xfer[transfer]);
> - }
> -} /* ubt_xfer_start */
> -
> -/****************************************************************************
> - ****************************************************************************
> ** Netgraph specific
> ****************************************************************************
> ****************************************************************************/
> @@ -1546,13 +1266,18 @@
> static int
> ng_ubt_shutdown(node_p node)
> {
> + struct ubt_softc *sc = NG_NODE_PRIVATE(node);
> +
> if (node->nd_flags & NGF_REALLY_DIE) {
> /*
> * We came here because the USB device is being
> * detached, so stop being persistant.
> */
> + UBT_LOCK(sc);
> + sc->sc_flags |= UBT_FLAG_SHUTDOWN;
> + UBT_UNLOCK(sc);
> +
> NG_NODE_SET_PRIVATE(node, NULL);
> - NG_NODE_UNREF(node);
> } else
> NG_NODE_REVIVE(node); /* tell ng_rmnode we are persisant */
>
> @@ -1592,9 +1317,21 @@
>
> NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
>
> - UBT_MBUFQ_LOCK(sc);
> - ubt_task_schedule(sc, UBT_FLAG_T_START_ALL);
> - UBT_MBUFQ_UNLOCK(sc);
> + if (!(sc->sc_flags & UBT_FLAG_READY)) {
> + /* called too early */
> + return (EINVAL);
> + }
> +
> + NG_NODE_REF(sc->sc_node);
> +
> + UBT_LOCK(sc);
> + usb2_transfer_start(sc->sc_xfer[UBT_IF_0_INTR_DT_RD]);
> + usb2_transfer_start(sc->sc_xfer[UBT_IF_0_BULK_DT_RD]);
> + usb2_transfer_start(sc->sc_xfer[UBT_IF_1_ISOC_DT_RD1]);
> + usb2_transfer_start(sc->sc_xfer[UBT_IF_1_ISOC_DT_RD2]);
> + usb2_transfer_start(sc->sc_xfer[UBT_IF_1_ISOC_DT_WR1]);
> + usb2_transfer_start(sc->sc_xfer[UBT_IF_1_ISOC_DT_WR2]);
> + UBT_UNLOCK(sc);
>
> return (0);
> } /* ng_ubt_connect */
> @@ -1609,6 +1346,7 @@
> {
> node_p node = NG_HOOK_NODE(hook);
> struct ubt_softc *sc;
> + uint8_t i;
>
> if (NG_NODE_NOT_VALID(node))
> return (0);
> @@ -1618,19 +1356,25 @@
> if (hook != sc->sc_hook)
> return (EINVAL);
>
> + /*
> + * Synchronously drain all USB transfers:
> + * Can take some milliseconds!
> + */
> + for (i = 0; i != UBT_N_TRANSFER; i++)
> + usb2_transfer_drain(sc->sc_xfer[i]);
> +
> sc->sc_hook = NULL;
>
> - UBT_MBUFQ_LOCK(sc);
> + UBT_LOCK(sc);
>
> /* Drain queues */
> NG_BT_MBUFQ_DRAIN(&sc->sc_cmdq);
> NG_BT_MBUFQ_DRAIN(&sc->sc_aclq);
> NG_BT_MBUFQ_DRAIN(&sc->sc_scoq);
>
> - /* Kick off task to stop all USB xfers */
> - ubt_task_schedule(sc, UBT_FLAG_T_STOP_ALL);
> + UBT_UNLOCK(sc);
>
> - UBT_MBUFQ_UNLOCK(sc);
> + NG_NODE_UNREF(node);
>
> return (0);
> } /* ng_ubt_disconnect */
> @@ -1664,7 +1408,6 @@
> "Refs: %d\n" \
> "Hook: %s\n" \
> "Flags: %#x\n" \
> - "Task flags: %#x\n" \
> "Debug: %d\n" \
> "CMD queue: [have:%d,max:%d]\n" \
> "ACL queue: [have:%d,max:%d]\n" \
> @@ -1672,7 +1415,6 @@
> node->nd_refs,
> (sc->sc_hook != NULL) ? NG_UBT_HOOK:"",
> sc->sc_flags,
> - sc->sc_task_flags,
> sc->sc_debug,
> sc->sc_cmdq.len,
> sc->sc_cmdq.maxlen,
> @@ -1823,7 +1565,8 @@
> struct ubt_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
> struct mbuf *m;
> struct ng_bt_mbufq *q;
> - int action, error = 0;
> + int error = 0;
> + uint8_t xfer_action;
>
> if (hook != sc->sc_hook) {
> error = EINVAL;
> @@ -1853,7 +1596,7 @@
> UBT_CTRL_BUFFER_SIZE, m->m_pkthdr.len);
>
> q = &sc->sc_cmdq;
> - action = UBT_FLAG_T_START_CTRL;
> + xfer_action = UBT_IF_0_CTRL_DT_WR;
> break;
>
> case NG_HCI_ACL_DATA_PKT:
> @@ -1863,12 +1606,12 @@
> UBT_BULK_WRITE_BUFFER_SIZE, m->m_pkthdr.len);
>
> q = &sc->sc_aclq;
> - action = UBT_FLAG_T_START_BULK;
> + xfer_action = UBT_IF_0_BULK_DT_WR;
> break;
>
> case NG_HCI_SCO_DATA_PKT:
> q = &sc->sc_scoq;
> - action = 0;
> + xfer_action = 255;
> break;
>
> default:
> @@ -1881,10 +1624,10 @@
> /* NOT REACHED */
> }
>
> - UBT_MBUFQ_LOCK(sc);
> + UBT_LOCK(sc);
> if (NG_BT_MBUFQ_FULL(q)) {
> NG_BT_MBUFQ_DROP(q);
> - UBT_MBUFQ_UNLOCK(sc);
> + UBT_UNLOCK(sc);
>
> UBT_ERR(sc, "Dropping HCI frame 0x%02x, len=%d. Queue full\n",
> *mtod(m, uint8_t *), m->m_pkthdr.len);
> @@ -1894,9 +1637,9 @@
> /* Loose HCI packet type, enqueue mbuf and kick off task */
> m_adj(m, sizeof(uint8_t));
> NG_BT_MBUFQ_ENQUEUE(q, m);
> - ubt_task_schedule(sc, action);
> -
> - UBT_MBUFQ_UNLOCK(sc);
> + if (xfer_action != 255)
> + usb2_transfer_start(sc->sc_xfer[xfer_action]);
> + UBT_UNLOCK(sc);
> }
> done:
> NG_FREE_ITEM(item);
> @@ -1962,4 +1705,3 @@
> MODULE_DEPEND(ng_ubt, ng_hci, NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION);
> MODULE_DEPEND(ng_ubt, usb2_bluetooth, 1, 1, 1);
> MODULE_DEPEND(ng_ubt, usb2_core, 1, 1, 1);
> -
> diff -u ng_ubt2_var.h ng_ubt2_var.h
> --- ng_ubt2_var.h Wed Jan 21 17:51:04 2009
> +++ ng_ubt2_var.h Fri Jan 23 20:08:04 2009
> @@ -28,7 +28,7 @@
> * SUCH DAMAGE.
> *
> * $Id: ng_ubt_var.h,v 1.2 2003/03/22 23:44:36 max Exp $
> - * $FreeBSD$
> + * $FreeBSD: src/sys/dev/usb2/bluetooth/ng_ubt2_var.h,v 1.2 2009/01/20 22:17:05 emax Exp $
> */
>
> #ifndef _NG_UBT_VAR_H_
> @@ -47,8 +47,8 @@
> #define UBT_WARN(...) UBT_DEBUG(NG_UBT_WARN_LEVEL, __VA_ARGS__)
> #define UBT_INFO(...) UBT_DEBUG(NG_UBT_INFO_LEVEL, __VA_ARGS__)
>
> -#define UBT_MBUFQ_LOCK(sc) mtx_lock(&(sc)->sc_mbufq_mtx)
> -#define UBT_MBUFQ_UNLOCK(sc) mtx_unlock(&(sc)->sc_mbufq_mtx)
> +#define UBT_LOCK(sc) mtx_lock(&(sc)->sc_mtx)
> +#define UBT_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
>
> /* Bluetooth USB control request type */
> #define UBT_HCI_REQUEST 0x20
> @@ -65,17 +65,14 @@
> UBT_IF_0_BULK_CS_WR,
> UBT_IF_0_BULK_CS_RD,
> UBT_IF_0_INTR_CS_RD,
> - UBT_IF_0_N_TRANSFER, /* number of interface 0's transfers */
>
> /* Interface #1 transfers */
> - UBT_IF_1_ISOC_DT_RD1 = UBT_IF_0_N_TRANSFER,
> + UBT_IF_1_ISOC_DT_RD1,
> UBT_IF_1_ISOC_DT_RD2,
> UBT_IF_1_ISOC_DT_WR1,
> UBT_IF_1_ISOC_DT_WR2,
>
> UBT_N_TRANSFER, /* total number of transfers */
> -
> - UBT_IF_1_N_TRANSFER = UBT_N_TRANSFER - UBT_IF_1_ISOC_DT_RD1,
> };
>
> /* USB device softc structure */
> @@ -89,6 +86,8 @@
> #define UBT_FLAG_READ_STALL (1 << 0) /* read transfer has stalled */
> #define UBT_FLAG_WRITE_STALL (1 << 1) /* write transfer has stalled */
> #define UBT_FLAG_INTR_STALL (1 << 2) /* inter transfer has stalled */
> +#define UBT_FLAG_READY (1 << 4) /* set when we are ready */
> +#define UBT_FLAG_SHUTDOWN (1 << 5) /* set when we are shutdown */
>
> ng_ubt_node_stat_ep sc_stat; /* statistic */
> #define UBT_STAT_PCKTS_SENT(sc) (sc)->sc_stat.pckts_sent ++
> @@ -100,11 +99,9 @@
> #define UBT_STAT_RESET(sc) bzero(&(sc)->sc_stat, sizeof((sc)->sc_stat))
>
> /* USB device specific */
> - struct mtx sc_if_mtx[2]; /* interface locks */
> + struct mtx sc_mtx;
> struct usb2_xfer *sc_xfer[UBT_N_TRANSFER];
>
> - struct mtx sc_mbufq_mtx; /* lock for all queues */
> -
> /* HCI commands */
> struct ng_bt_mbufq sc_cmdq; /* HCI command queue */
> #define UBT_CTRL_BUFFER_SIZE (sizeof(struct usb2_device_request) + \
> @@ -123,17 +120,6 @@
> /* Netgraph specific */
> node_p sc_node; /* pointer back to node */
> hook_p sc_hook; /* upstream hook */
> -
> - /* Glue */
> - int sc_task_flags; /* task flags */
> -#define UBT_FLAG_T_PENDING (1 << 0) /* task pending */
> -#define UBT_FLAG_T_STOP_ALL (1 << 1) /* stop all xfers */
> -#define UBT_FLAG_T_START_ALL (1 << 2) /* start all read and isoc
> - write xfers */
> -#define UBT_FLAG_T_START_CTRL (1 << 3) /* start control xfer (write) */
> -#define UBT_FLAG_T_START_BULK (1 << 4) /* start bulk xfer (write) */
> -
> - struct task sc_task;
> };
> typedef struct ubt_softc ubt_softc_t;
> typedef struct ubt_softc * ubt_softc_p;
--
Lars Engels
E-Mail: lars.engels at 0x20.net
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 195 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-current/attachments/20090123/221eb5e3/attachment-0002.pgp
More information about the freebsd-current
mailing list