[PATCH2] for ng_ubt2 stalled transfers



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.

--HPS
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;
_______________________________________________
freebsd-current@xxxxxxxxxxx mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to "freebsd-current-unsubscribe@xxxxxxxxxxx"

Relevant Pages

  • Re: [PATCH2] for ng_ubt2 stalled transfers
    ... Bluetooth has worked fine with the new USB stack aswell. ... Hunk #1 succeeded at 28. ... * spin lock. ... callbacks run in this context. ...
    (freebsd-current)
  • Re: miibus + USB = problem
    ... The problem is that the USB ... During the 'tick' routine. ... detach, it unregisters the timeout. ... with the lock held, thus ensuring deadlock if the timeout fires after ...
    (freebsd-hackers)
  • Re: Locking devices down
    ... third party controls if you want to maintain some level of security on the ... network or consider disabling the USB ports in cmos, ... password protect cmos, lock the computer case covers, and use ps2 keyboards ...
    (microsoft.public.security)
  • Re: CCriticalSection - does my thread already have a lock?
    ... Then the object cannot become invalid even after you release the list lock. ... When a worker thread wakes up from the IOCP it does the following: ... hunts for the appropriate context, validates that the context is still ...
    (microsoft.public.vc.mfc)
  • Re: Windows CE 6.0 locks up when certain USB flash drives are inse
    ... The lock up only occurs during device insertion and only with certain USB ... I tried debugging the USB with all debug zones enabled, ... I believe the problem exists in the mass storage client driver, ...
    (microsoft.public.windowsce.platbuilder)