Date: Fri, 23 Jan 2009 22:49:23 +0100 From: Hans Petter Selasky <hselasky@c2i.net> To: freebsd-current@freebsd.org, Lars Engels <lme@freebsd.org> Cc: current@freebsd.org, Maksim Yevmenkin <maksim.yevmenkin@gmail.com> Subject: [PATCH2] for ng_ubt2 stalled transfers Message-ID: <200901232249.25153.hselasky@c2i.net> In-Reply-To: <20090123213323.GO60948@e.0x20.net> References: <bb4a86c70901231112x693f18cmbb29b966cb972992@mail.gmail.com> <20090123212952.GM60948@e.0x20.net> <20090123213323.GO60948@e.0x20.net>
next in thread | previous in thread | raw e-mail | index | archive | help
--Boundary-00=_ltjeJufHBsVDcXZ
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
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
--Boundary-00=_ltjeJufHBsVDcXZ
Content-Type: text/x-diff;
charset="iso-8859-1";
name="bt_patch.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="bt_patch.diff"
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;
--Boundary-00=_ltjeJufHBsVDcXZ--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200901232249.25153.hselasky>
