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