MFp4: //depot/projects/usb@155936
Save an USB transfer in UHUB driver by using the builtin clear-stall mechanism. Submitted by: Hans Petter Selasky
This commit is contained in:
parent
2c8e37aa5c
commit
9d2f688aa3
@ -53,6 +53,7 @@
|
||||
#include <dev/usb2/controller/usb2_bus.h>
|
||||
|
||||
#define UHUB_INTR_INTERVAL 250 /* ms */
|
||||
#define UHUB_N_TRANSFER 1
|
||||
|
||||
#if USB_DEBUG
|
||||
static int uhub_debug = 0;
|
||||
@ -76,10 +77,9 @@ struct uhub_softc {
|
||||
struct uhub_current_state sc_st;/* current state */
|
||||
device_t sc_dev; /* base device */
|
||||
struct usb2_device *sc_udev; /* USB device */
|
||||
struct usb2_xfer *sc_xfer[2]; /* interrupt xfer */
|
||||
struct usb2_xfer *sc_xfer[UHUB_N_TRANSFER]; /* interrupt xfer */
|
||||
uint8_t sc_flags;
|
||||
#define UHUB_FLAG_DID_EXPLORE 0x01
|
||||
#define UHUB_FLAG_INTR_STALL 0x02
|
||||
char sc_name[32];
|
||||
};
|
||||
|
||||
@ -100,12 +100,11 @@ static bus_child_location_str_t uhub_child_location_string;
|
||||
static bus_child_pnpinfo_str_t uhub_child_pnpinfo_string;
|
||||
|
||||
static usb2_callback_t uhub_intr_callback;
|
||||
static usb2_callback_t uhub_intr_clear_stall_callback;
|
||||
|
||||
static void usb2_dev_resume_peer(struct usb2_device *udev);
|
||||
static void usb2_dev_suspend_peer(struct usb2_device *udev);
|
||||
|
||||
static const struct usb2_config uhub_config[2] = {
|
||||
static const struct usb2_config uhub_config[UHUB_N_TRANSFER] = {
|
||||
|
||||
[0] = {
|
||||
.type = UE_INTERRUPT,
|
||||
@ -117,17 +116,6 @@ static const struct usb2_config uhub_config[2] = {
|
||||
.mh.callback = &uhub_intr_callback,
|
||||
.mh.interval = UHUB_INTR_INTERVAL,
|
||||
},
|
||||
|
||||
[1] = {
|
||||
.type = UE_CONTROL,
|
||||
.endpoint = 0,
|
||||
.direction = UE_DIR_ANY,
|
||||
.mh.timeout = 1000, /* 1 second */
|
||||
.mh.interval = 50, /* 50ms */
|
||||
.mh.flags = {},
|
||||
.mh.bufsize = sizeof(struct usb2_device_request),
|
||||
.mh.callback = &uhub_intr_clear_stall_callback,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
@ -159,19 +147,6 @@ static driver_t uhub_driver =
|
||||
DRIVER_MODULE(ushub, usbus, uhub_driver, uhub_devclass, 0, 0);
|
||||
DRIVER_MODULE(ushub, ushub, uhub_driver, uhub_devclass, NULL, 0);
|
||||
|
||||
static void
|
||||
uhub_intr_clear_stall_callback(struct usb2_xfer *xfer)
|
||||
{
|
||||
struct uhub_softc *sc = xfer->priv_sc;
|
||||
struct usb2_xfer *xfer_other = sc->sc_xfer[0];
|
||||
|
||||
if (usb2_clear_stall_callback(xfer, xfer_other)) {
|
||||
DPRINTF("stall cleared\n");
|
||||
sc->sc_flags &= ~UHUB_FLAG_INTR_STALL;
|
||||
usb2_transfer_start(xfer_other);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
uhub_intr_callback(struct usb2_xfer *xfer)
|
||||
{
|
||||
@ -189,21 +164,22 @@ uhub_intr_callback(struct usb2_xfer *xfer)
|
||||
usb2_needs_explore(sc->sc_udev->bus, 0);
|
||||
|
||||
case USB_ST_SETUP:
|
||||
if (sc->sc_flags & UHUB_FLAG_INTR_STALL) {
|
||||
usb2_transfer_start(sc->sc_xfer[1]);
|
||||
} else {
|
||||
xfer->frlengths[0] = xfer->max_data_length;
|
||||
usb2_start_hardware(xfer);
|
||||
}
|
||||
return;
|
||||
xfer->frlengths[0] = xfer->max_data_length;
|
||||
usb2_start_hardware(xfer);
|
||||
break;
|
||||
|
||||
default: /* Error */
|
||||
if (xfer->error != USB_ERR_CANCELLED) {
|
||||
/* start clear stall */
|
||||
sc->sc_flags |= UHUB_FLAG_INTR_STALL;
|
||||
usb2_transfer_start(sc->sc_xfer[1]);
|
||||
/*
|
||||
* Do a clear-stall. The "stall_pipe" flag
|
||||
* will get cleared before next callback by
|
||||
* the USB stack.
|
||||
*/
|
||||
xfer->flags.stall_pipe = 1;
|
||||
xfer->frlengths[0] = xfer->max_data_length;
|
||||
usb2_start_hardware(xfer);
|
||||
}
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -736,7 +712,7 @@ uhub_attach(device_t dev)
|
||||
/* set up interrupt pipe */
|
||||
iface_index = 0;
|
||||
err = usb2_transfer_setup(udev, &iface_index, sc->sc_xfer,
|
||||
uhub_config, 2, sc, &Giant);
|
||||
uhub_config, UHUB_N_TRANSFER, sc, &Giant);
|
||||
if (err) {
|
||||
DPRINTFN(0, "cannot setup interrupt transfer, "
|
||||
"errstr=%s!\n", usb2_errstr(err));
|
||||
@ -821,7 +797,7 @@ uhub_attach(device_t dev)
|
||||
return (0);
|
||||
|
||||
error:
|
||||
usb2_transfer_unsetup(sc->sc_xfer, 2);
|
||||
usb2_transfer_unsetup(sc->sc_xfer, UHUB_N_TRANSFER);
|
||||
|
||||
if (udev->hub) {
|
||||
free(udev->hub, M_USBDEV);
|
||||
@ -864,7 +840,7 @@ uhub_detach(device_t dev)
|
||||
child = NULL;
|
||||
}
|
||||
|
||||
usb2_transfer_unsetup(sc->sc_xfer, 2);
|
||||
usb2_transfer_unsetup(sc->sc_xfer, UHUB_N_TRANSFER);
|
||||
|
||||
free(hub, M_USBDEV);
|
||||
sc->sc_udev->hub = NULL;
|
||||
|
@ -43,25 +43,44 @@
|
||||
* Else: Next descriptor after "desc"
|
||||
*------------------------------------------------------------------------*/
|
||||
struct usb2_descriptor *
|
||||
usb2_desc_foreach(struct usb2_config_descriptor *cd, struct usb2_descriptor *desc)
|
||||
usb2_desc_foreach(struct usb2_config_descriptor *cd,
|
||||
struct usb2_descriptor *_desc)
|
||||
{
|
||||
void *end;
|
||||
uint8_t *desc_next;
|
||||
uint8_t *start;
|
||||
uint8_t *end;
|
||||
uint8_t *desc;
|
||||
|
||||
if (cd == NULL) {
|
||||
/* be NULL safe */
|
||||
if (cd == NULL)
|
||||
return (NULL);
|
||||
}
|
||||
end = USB_ADD_BYTES(cd, UGETW(cd->wTotalLength));
|
||||
|
||||
if (desc == NULL) {
|
||||
desc = USB_ADD_BYTES(cd, 0);
|
||||
} else {
|
||||
desc = USB_ADD_BYTES(desc, desc->bLength);
|
||||
}
|
||||
return (((((void *)desc) >= ((void *)cd)) &&
|
||||
(((void *)desc) < end) &&
|
||||
(USB_ADD_BYTES(desc, desc->bLength) >= ((void *)cd)) &&
|
||||
(USB_ADD_BYTES(desc, desc->bLength) <= end) &&
|
||||
(desc->bLength >= sizeof(*desc))) ? desc : NULL);
|
||||
/* We assume that the "wTotalLength" has been checked. */
|
||||
start = (uint8_t *)cd;
|
||||
end = start + UGETW(cd->wTotalLength);
|
||||
desc = (uint8_t *)_desc;
|
||||
|
||||
/* Get start of next USB descriptor. */
|
||||
if (desc == NULL)
|
||||
desc = start;
|
||||
else
|
||||
desc = desc + desc[0];
|
||||
|
||||
/* Check that the next USB descriptor is within the range. */
|
||||
if ((desc < start) || (desc >= end))
|
||||
return (NULL); /* out of range, or EOD */
|
||||
|
||||
/* Check that the second next USB descriptor is within range. */
|
||||
desc_next = desc + desc[0];
|
||||
if ((desc_next < start) || (desc_next > end))
|
||||
return (NULL); /* out of range */
|
||||
|
||||
/* Check minimum descriptor length. */
|
||||
if (desc[0] < 3)
|
||||
return (NULL); /* too short descriptor */
|
||||
|
||||
/* Return start of next descriptor. */
|
||||
return ((struct usb2_descriptor *)desc);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
@ -140,7 +159,6 @@ usb2_find_edesc(struct usb2_config_descriptor *cd,
|
||||
desc = ((void *)d);
|
||||
|
||||
while ((desc = usb2_desc_foreach(cd, desc))) {
|
||||
|
||||
if (desc->bDescriptorType == UDESC_INTERFACE) {
|
||||
break;
|
||||
}
|
||||
@ -195,7 +213,6 @@ usb2_get_no_alts(struct usb2_config_descriptor *cd, uint8_t ifaceno)
|
||||
uint16_t n = 0;
|
||||
|
||||
while ((desc = usb2_desc_foreach(cd, desc))) {
|
||||
|
||||
if ((desc->bDescriptorType == UDESC_INTERFACE) &&
|
||||
(desc->bLength >= sizeof(*id))) {
|
||||
id = (void *)desc;
|
||||
|
Loading…
Reference in New Issue
Block a user