PERFORCE change 156577 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Fri Jan 23 11:06:02 PST 2009
http://perforce.freebsd.org/chv.cgi?CH=156577
Change 156577 by hselasky at hselasky_laptop001 on 2009/01/23 19:05:38
Fix issues with USB bluetooth negraph node and detach.
- Cleanup code.
- Reduce the number of mutexes.
- Needs review by Maksim.
Affected files ...
.. //depot/projects/usb/src/sys/dev/usb2/bluetooth/ng_ubt2.c#15 edit
.. //depot/projects/usb/src/sys/dev/usb2/bluetooth/ng_ubt2_var.h#7 edit
Differences ...
==== //depot/projects/usb/src/sys/dev/usb2/bluetooth/ng_ubt2.c#15 (text+ko) ====
@@ -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,29 @@
{
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);
}
-
/* Free USB transfers, if any */
usb2_transfer_unsetup(sc->sc_xfer, UBT_N_TRANSFER);
@@ -630,15 +606,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 +631,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 +681,6 @@
UBT_STAT_OERROR(sc);
goto send_next;
}
-
- NG_NODE_UNREF(node); /* cancelled */
break;
}
} /* ubt_ctrl_write_callback */
@@ -740,19 +700,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 +785,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 +803,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 +810,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 +829,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 +913,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 +931,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 +938,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 +954,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 +1000,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 +1018,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 +1025,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 +1041,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 +1064,6 @@
goto read_next;
/* NOT REACHED */
}
-
- NG_NODE_UNREF(node); /* cancelled */
break;
}
} /* ubt_isoc_read_callback */
@@ -1277,24 +1168,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 +1188,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 +1208,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 +1233,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 +1262,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 +1313,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 +1342,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 +1352,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 +1404,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 +1411,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 +1561,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 +1592,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 +1602,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 +1620,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 +1633,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 +1701,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);
-
==== //depot/projects/usb/src/sys/dev/usb2/bluetooth/ng_ubt2_var.h#7 (text+ko) ====
@@ -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,
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list