ng_ubt2 patch for stalled transfers
Maksim Yevmenkin
maksim.yevmenkin at gmail.com
Fri Jan 23 11:18:49 PST 2009
dear freebsd-bluetooth@ users,
it has been brought to my attention that recently committed ng_ubt2
(USB2) driver for bluetooth usb dongles may have issues with stalled
transfers. if you are experiencing stalled transfers and crashes with
USB2/ng_ubt2 please try the attached patch and let me know if it makes
it better. the patch probably will not fix stalled transfers, but at
least the system should not be crashing anymore (or so i hope :)
if you are using USB2/ng_usb2 and do not experience stalled transfers,
please try the patch anyway. it should not make any difference, but
i'd like to get as much testing as i can.
thanks,
max
-------------- next part --------------
Index: ng_ubt2.c
===================================================================
--- ng_ubt2.c (revision 187505)
+++ ng_ubt2.c (working copy)
@@ -243,13 +243,11 @@
/* USB methods */
static usb2_callback_t ubt_ctrl_write_callback;
static usb2_callback_t ubt_intr_read_callback;
-static usb2_callback_t ubt_intr_read_clear_stall_callback;
static usb2_callback_t ubt_bulk_read_callback;
-static usb2_callback_t ubt_bulk_read_clear_stall_callback;
static usb2_callback_t ubt_bulk_write_callback;
-static usb2_callback_t ubt_bulk_write_clear_stall_callback;
static usb2_callback_t ubt_isoc_read_callback;
static usb2_callback_t ubt_isoc_write_callback;
+static usb2_callback_t ubt_clear_stall_callback;
static int ubt_isoc_read_one_frame(struct usb2_xfer *, int);
@@ -316,7 +314,7 @@
.endpoint = 0x00, /* control pipe */
.direction = UE_DIR_ANY,
.mh.bufsize = sizeof(struct usb2_device_request),
- .mh.callback = &ubt_bulk_write_clear_stall_callback,
+ .mh.callback = &ubt_clear_stall_callback,
.mh.timeout = 1000, /* 1 second */
.mh.interval = 50, /* 50ms */
},
@@ -326,7 +324,7 @@
.endpoint = 0x00, /* control pipe */
.direction = UE_DIR_ANY,
.mh.bufsize = sizeof(struct usb2_device_request),
- .mh.callback = &ubt_bulk_read_clear_stall_callback,
+ .mh.callback = &ubt_clear_stall_callback,
.mh.timeout = 1000, /* 1 second */
.mh.interval = 50, /* 50ms */
},
@@ -339,7 +337,7 @@
.endpoint = 0x00, /* control pipe */
.direction = UE_DIR_ANY,
.mh.bufsize = sizeof(struct usb2_device_request),
- .mh.callback = &ubt_intr_read_clear_stall_callback,
+ .mh.callback = &ubt_clear_stall_callback,
.mh.timeout = 1000, /* 1 second */
.mh.interval = 50, /* 50ms */
},
@@ -623,6 +621,9 @@
ng_rmnode_self(node);
}
+ /* Make sure ubt_task in gone */
+ taskqueue_drain(taskqueue_swi, &sc->sc_task);
+
/* Free USB transfers, if any */
usb2_transfer_unsetup(sc->sc_xfer, UBT_N_TRANSFER);
@@ -843,35 +844,6 @@
} /* ubt_intr_read_callback */
/*
- * Called when outgoing control transfer initiated to clear stall on
- * interrupt pipe has completed.
- * USB context.
- */
-
-static void
-ubt_intr_read_clear_stall_callback(struct usb2_xfer *xfer)
-{
- node_p node = xfer->priv_sc;
- 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];
-
- if (usb2_clear_stall_callback(xfer, xfer_other)) {
- 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 */
-
-/*
* Called when incoming bulk transfer (ACL packet) has completed, i.e.
* ACL packet was received from the device.
* USB context.
@@ -990,35 +962,6 @@
} /* ubt_bulk_read_callback */
/*
- * Called when outgoing control transfer initiated to clear stall on
- * incoming bulk pipe has completed.
- * USB context.
- */
-
-static void
-ubt_bulk_read_clear_stall_callback(struct usb2_xfer *xfer)
-{
- node_p node = xfer->priv_sc;
- 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];
-
- if (usb2_clear_stall_callback(xfer, xfer_other)) {
- 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 */
-
-/*
* Called when outgoing bulk transfer (ACL packet) has completed, i.e.
* ACL packet was sent to the device.
* USB context.
@@ -1096,35 +1039,6 @@
} /* ubt_bulk_write_callback */
/*
- * Called when outgoing control transfer initiated to clear stall on
- * outgoing bulk pipe has completed.
- * USB context.
- */
-
-static void
-ubt_bulk_write_clear_stall_callback(struct usb2_xfer *xfer)
-{
- node_p node = xfer->priv_sc;
- 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];
-
- if (usb2_clear_stall_callback(xfer, xfer_other)) {
- 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 */
-
-/*
* Called when incoming isoc transfer (SCO packet) has completed, i.e.
* SCO packet was received from the device.
* USB context.
@@ -1361,6 +1275,80 @@
}
}
+/*
+ * Called when an outgoing control transfer to clear stall on another
+ * pipe has been completed. Generic for all clear stall transfers.
+ * USB context.
+ */
+
+static void
+ubt_clear_stall_callback(struct usb2_xfer *xfer)
+{
+ node_p node = xfer->priv_sc;
+ struct ubt_softc *sc;
+ struct usb2_xfer *xfer_other;
+ int flag;
+
+ if (NG_NODE_NOT_VALID(node)) {
+ NG_NODE_UNREF(node);
+ return; /* netgraph node is gone */
+ }
+
+ sc = NG_NODE_PRIVATE(node);
+
+ /*
+ * Figure out which clear stall transfer has completed
+ * and set xfer_other and flag accordingly
+ */
+
+ if (xfer == sc->sc_xfer[UBT_IF_0_BULK_CS_WR]) {
+ xfer_other = sc->sc_xfer[UBT_IF_0_BULK_DT_WR];
+ flag = UBT_FLAG_WRITE_STALL;
+ } else if (xfer == sc->sc_xfer[UBT_IF_0_BULK_CS_RD]) {
+ xfer_other = sc->sc_xfer[UBT_IF_0_BULK_DT_RD];
+ flag = UBT_FLAG_READ_STALL;
+ } else if (xfer == sc->sc_xfer[UBT_IF_0_INTR_CS_RD]) {
+ xfer_other = sc->sc_xfer[UBT_IF_0_INTR_DT_RD];
+ flag = UBT_FLAG_INTR_STALL;
+ } else
+ panic("could not set xfer_other! xfer=%p\n", xfer);
+
+ if (xfer_other == NULL) {
+ UBT_WARN(sc, "other transfer is gone. are we dying?!\n");
+ NG_NODE_UNREF(node);
+ return; /* other transfer is gone. are we dying?! */
+ }
+
+ switch (USB_GET_STATE(xfer)) {
+ case USB_ST_SETUP:
+ /*
+ * Ignore return value from usb2_clear_stall_callback()
+ * as it appears it can not return anything other than
+ * zero in USB_ST_SETUP case
+ */
+ (void) usb2_clear_stall_callback(xfer, xfer_other);
+ break;
+
+ case USB_ST_TRANSFERRED:
+ UBT_INFO(sc, "stall cleared, flag=%#x\n", flag);
+submit_other:
+ sc->sc_flags &= ~flag;
+ usb2_transfer_start(xfer_other);
+ break;
+
+ default:
+ if (xfer->error != USB_ERR_CANCELLED) {
+ UBT_WARN(sc, "clear stall transfer failed: %s, " \
+ "flag=%#x\n", usb2_errstr(xfer->error), flag);
+ goto submit_other;
+ /* NOT REACHED */
+ }
+
+ NG_NODE_UNREF(node); /* cancelled */
+ break;
+ }
+} /* ubt_clear_stall_callback */
+
/****************************************************************************
****************************************************************************
** Glue
More information about the freebsd-bluetooth
mailing list