Skip to content

Commit

Permalink
MFC
Browse files Browse the repository at this point in the history
  • Loading branch information
Attilio Rao authored and Attilio Rao committed Jun 6, 2011
2 parents 81c0253 + 2906af2 commit 9c68ff4
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 8 deletions.
2 changes: 2 additions & 0 deletions sys/dev/usb/usb_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ struct usb_device {
struct usb_host_endpoint *linux_endpoint_end;
uint16_t devnum;
#endif

uint32_t clear_stall_errors; /* number of clear-stall failures */
};

/* globals */
Expand Down
1 change: 1 addition & 0 deletions sys/dev/usb/usb_freebsd.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@

#define USB_HUB_MAX_DEPTH 5
#define USB_EP0_BUFSIZE 1024 /* bytes */
#define USB_CS_RESET_LIMIT 20 /* failures = 20 * 50 ms = 1sec */

typedef uint32_t usb_timeout_t; /* milliseconds */
typedef uint32_t usb_frlength_t; /* bytes */
Expand Down
6 changes: 2 additions & 4 deletions sys/dev/usb/usb_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -966,10 +966,8 @@ ugen_re_enumerate(struct usb_fifo *f)
/* ignore any errors */
DPRINTFN(6, "no FIFOs\n");
}
if (udev->re_enumerate_wait == 0) {
udev->re_enumerate_wait = 1;
usb_needs_explore(udev->bus, 0);
}
/* start re-enumeration of device */
usbd_start_re_enumerate(udev);
return (0);
}

Expand Down
27 changes: 24 additions & 3 deletions sys/dev/usb/usb_hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,9 +242,14 @@ uhub_explore_sub(struct uhub_softc *sc, struct usb_port *up)
if (child->flags.usb_mode == USB_MODE_HOST) {
usbd_enum_lock(child);
if (child->re_enumerate_wait) {
err = usbd_set_config_index(child, USB_UNCONFIG_INDEX);
if (err == 0)
err = usbd_req_re_enumerate(child, NULL);
err = usbd_set_config_index(child,
USB_UNCONFIG_INDEX);
if (err != 0) {
DPRINTF("Unconfigure failed: "
"%s: Ignored.\n",
usbd_errstr(err));
}
err = usbd_req_re_enumerate(child, NULL);
if (err == 0)
err = usbd_set_config_index(child, 0);
if (err == 0) {
Expand Down Expand Up @@ -2471,3 +2476,19 @@ usbd_filter_power_mode(struct usb_device *udev, uint8_t power_mode)
/* use fixed power mode given by hardware driver */
return (temp);
}

/*------------------------------------------------------------------------*
* usbd_start_re_enumerate
*
* This function starts re-enumeration of the given USB device. This
* function does not need to be called BUS-locked. This function does
* not wait until the re-enumeration is completed.
*------------------------------------------------------------------------*/
void
usbd_start_re_enumerate(struct usb_device *udev)
{
if (udev->re_enumerate_wait == 0) {
udev->re_enumerate_wait = 1;
usb_needs_explore(udev->bus, 0);
}
}
100 changes: 99 additions & 1 deletion sys/dev/usb/usb_request.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,10 @@ usb_do_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error)

switch (USB_GET_STATE(xfer)) {
case USB_ST_TRANSFERRED:

/* reset error counter */
udev->clear_stall_errors = 0;

if (ep == NULL)
goto tr_setup; /* device was unconfigured */
if (ep->edesc &&
Expand Down Expand Up @@ -289,8 +293,23 @@ usb_do_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error)
goto tr_setup;

default:
if (xfer->error == USB_ERR_CANCELLED) {
if (error == USB_ERR_CANCELLED)
break;

DPRINTF("Clear stall failed.\n");
if (udev->clear_stall_errors == USB_CS_RESET_LIMIT)
goto tr_setup;

if (error == USB_ERR_TIMEOUT) {
udev->clear_stall_errors = USB_CS_RESET_LIMIT;
DPRINTF("Trying to re-enumerate.\n");
usbd_start_re_enumerate(udev);
} else {
udev->clear_stall_errors++;
if (udev->clear_stall_errors == USB_CS_RESET_LIMIT) {
DPRINTF("Trying to re-enumerate.\n");
usbd_start_re_enumerate(udev);
}
}
goto tr_setup;
}
Expand Down Expand Up @@ -1936,6 +1955,23 @@ usbd_req_re_enumerate(struct usb_device *udev, struct mtx *mtx)
return (USB_ERR_INVAL);
}
retry:
/*
* Try to reset the High Speed parent HUB of a LOW- or FULL-
* speed device, if any.
*/
if (udev->parent_hs_hub != NULL &&
udev->speed != USB_SPEED_HIGH) {
DPRINTF("Trying to reset parent High Speed TT.\n");
err = usbd_req_reset_tt(udev->parent_hs_hub, NULL,
udev->hs_port_no);
if (err) {
DPRINTF("Resetting parent High "
"Speed TT failed (%s).\n",
usbd_errstr(err));
}
}

/* Try to reset the parent HUB port. */
err = usbd_req_reset_port(parent_hub, mtx, udev->port_no);
if (err) {
DPRINTFN(0, "addr=%d, port reset failed, %s\n",
Expand Down Expand Up @@ -2033,3 +2069,65 @@ usbd_req_set_device_feature(struct usb_device *udev, struct mtx *mtx,
USETW(req.wLength, 0);
return (usbd_do_request(udev, mtx, &req, 0));
}

/*------------------------------------------------------------------------*
* usbd_req_reset_tt
*
* Returns:
* 0: Success
* Else: Failure
*------------------------------------------------------------------------*/
usb_error_t
usbd_req_reset_tt(struct usb_device *udev, struct mtx *mtx,
uint8_t port)
{
struct usb_device_request req;

/* For single TT HUBs the port should be 1 */

if (udev->ddesc.bDeviceClass == UDCLASS_HUB &&
udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT)
port = 1;

req.bmRequestType = UT_WRITE_CLASS_OTHER;
req.bRequest = UR_RESET_TT;
USETW(req.wValue, 0);
req.wIndex[0] = port;
req.wIndex[1] = 0;
USETW(req.wLength, 0);
return (usbd_do_request(udev, mtx, &req, 0));
}

/*------------------------------------------------------------------------*
* usbd_req_clear_tt_buffer
*
* For single TT HUBs the port should be 1.
*
* Returns:
* 0: Success
* Else: Failure
*------------------------------------------------------------------------*/
usb_error_t
usbd_req_clear_tt_buffer(struct usb_device *udev, struct mtx *mtx,
uint8_t port, uint8_t addr, uint8_t type, uint8_t endpoint)
{
struct usb_device_request req;
uint16_t wValue;

/* For single TT HUBs the port should be 1 */

if (udev->ddesc.bDeviceClass == UDCLASS_HUB &&
udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT)
port = 1;

wValue = (endpoint & 0xF) | ((addr & 0x7F) << 4) |
((endpoint & 0x80) << 8) | ((type & 3) << 12);

req.bmRequestType = UT_WRITE_CLASS_OTHER;
req.bRequest = UR_CLEAR_TT_BUFFER;
USETW(req.wValue, wValue);
req.wIndex[0] = port;
req.wIndex[1] = 0;
USETW(req.wLength, 0);
return (usbd_do_request(udev, mtx, &req, 0));
}
4 changes: 4 additions & 0 deletions sys/dev/usb/usb_request.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,9 @@ usb_error_t usbd_req_set_hub_u2_timeout(struct usb_device *udev,
struct mtx *mtx, uint8_t port, uint8_t timeout);
usb_error_t usbd_req_set_hub_depth(struct usb_device *udev,
struct mtx *mtx, uint16_t depth);
usb_error_t usbd_req_reset_tt(struct usb_device *udev, struct mtx *mtx,
uint8_t port);
usb_error_t usbd_req_clear_tt_buffer(struct usb_device *udev, struct mtx *mtx,
uint8_t port, uint8_t addr, uint8_t type, uint8_t endpoint);

#endif /* _USB_REQUEST_H_ */
5 changes: 5 additions & 0 deletions sys/dev/usb/usb_transfer.c
Original file line number Diff line number Diff line change
Expand Up @@ -2927,6 +2927,11 @@ usbd_ctrl_transfer_setup(struct usb_device *udev)
*/
usbd_transfer_unsetup(udev->ctrl_xfer, USB_CTRL_XFER_MAX);

/*
* Reset clear stall error counter.
*/
udev->clear_stall_errors = 0;

/*
* Try to setup a new USB transfer for the
* default control endpoint:
Expand Down
1 change: 1 addition & 0 deletions sys/dev/usb/usbdi.h
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,7 @@ void usbd_m_copy_in(struct usb_page_cache *cache, usb_frlength_t dst_offset,
struct mbuf *m, usb_size_t src_offset, usb_frlength_t src_len);
void usbd_frame_zero(struct usb_page_cache *cache, usb_frlength_t offset,
usb_frlength_t len);
void usbd_start_re_enumerate(struct usb_device *udev);

int usb_fifo_attach(struct usb_device *udev, void *priv_sc,
struct mtx *priv_mtx, struct usb_fifo_methods *pm,
Expand Down
1 change: 1 addition & 0 deletions sys/netinet/in_pcb.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include <sys/_rwlock.h>

#ifdef _KERNEL
#include <sys/lock.h>
#include <sys/rwlock.h>
#include <net/vnet.h>
#include <vm/uma.h>
Expand Down

0 comments on commit 9c68ff4

Please sign in to comment.