Sync to p4

- Add support for devices that handle set and clear stall in hardware.
 - Add missing get timestamp function
 - Add more xfer flags

Submitted by:	Hans Petter Selasky
Approved by:	re (kib)
This commit is contained in:
Andrew Thompson 2009-06-27 21:23:30 +00:00
parent 7e6e6b6766
commit 29bd7d7e9a
13 changed files with 82 additions and 23 deletions

View File

@ -1227,7 +1227,7 @@ at91dci_device_done(struct usb_xfer *xfer, usb_error_t error)
static void static void
at91dci_set_stall(struct usb_device *udev, struct usb_xfer *xfer, at91dci_set_stall(struct usb_device *udev, struct usb_xfer *xfer,
struct usb_endpoint *ep) struct usb_endpoint *ep, uint8_t *did_stall)
{ {
struct at91dci_softc *sc; struct at91dci_softc *sc;
uint32_t csr_val; uint32_t csr_val;

View File

@ -1113,7 +1113,7 @@ atmegadci_device_done(struct usb_xfer *xfer, usb_error_t error)
static void static void
atmegadci_set_stall(struct usb_device *udev, struct usb_xfer *xfer, atmegadci_set_stall(struct usb_device *udev, struct usb_xfer *xfer,
struct usb_endpoint *ep) struct usb_endpoint *ep, uint8_t *did_stall)
{ {
struct atmegadci_softc *sc; struct atmegadci_softc *sc;
uint8_t ep_no; uint8_t ep_no;

View File

@ -1081,7 +1081,7 @@ avr32dci_device_done(struct usb_xfer *xfer, usb_error_t error)
static void static void
avr32dci_set_stall(struct usb_device *udev, struct usb_xfer *xfer, avr32dci_set_stall(struct usb_device *udev, struct usb_xfer *xfer,
struct usb_endpoint *ep) struct usb_endpoint *ep, uint8_t *did_stall)
{ {
struct avr32dci_softc *sc; struct avr32dci_softc *sc;
uint8_t ep_no; uint8_t ep_no;

View File

@ -1473,7 +1473,7 @@ musbotg_device_done(struct usb_xfer *xfer, usb_error_t error)
static void static void
musbotg_set_stall(struct usb_device *udev, struct usb_xfer *xfer, musbotg_set_stall(struct usb_device *udev, struct usb_xfer *xfer,
struct usb_endpoint *ep) struct usb_endpoint *ep, uint8_t *did_stall)
{ {
struct musbotg_softc *sc; struct musbotg_softc *sc;
uint8_t ep_no; uint8_t ep_no;

View File

@ -1202,7 +1202,7 @@ uss820dci_device_done(struct usb_xfer *xfer, usb_error_t error)
static void static void
uss820dci_set_stall(struct usb_device *udev, struct usb_xfer *xfer, uss820dci_set_stall(struct usb_device *udev, struct usb_xfer *xfer,
struct usb_endpoint *ep) struct usb_endpoint *ep, uint8_t *did_stall)
{ {
struct uss820dci_softc *sc; struct uss820dci_softc *sc;
uint8_t ep_no; uint8_t ep_no;

View File

@ -764,7 +764,7 @@ cdce_intr_write_callback(struct usb_xfer *xfer, usb_error_t error)
static int static int
cdce_handle_request(device_t dev, cdce_handle_request(device_t dev,
const void *req, void **pptr, uint16_t *plen, const void *req, void **pptr, uint16_t *plen,
uint16_t offset, uint8_t is_complete) uint16_t offset, uint8_t *pstate)
{ {
return (ENXIO); /* use builtin handler */ return (ENXIO); /* use builtin handler */
} }

View File

@ -475,10 +475,11 @@ ustorage_fs_transfer_stop(struct ustorage_fs_softc *sc)
static int static int
ustorage_fs_handle_request(device_t dev, ustorage_fs_handle_request(device_t dev,
const void *preq, void **pptr, uint16_t *plen, const void *preq, void **pptr, uint16_t *plen,
uint16_t offset, uint8_t is_complete) uint16_t offset, uint8_t *pstate)
{ {
struct ustorage_fs_softc *sc = device_get_softc(dev); struct ustorage_fs_softc *sc = device_get_softc(dev);
const struct usb_device_request *req = preq; const struct usb_device_request *req = preq;
uint8_t is_complete = *pstate;
if (!is_complete) { if (!is_complete) {
if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) && if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&

View File

@ -96,7 +96,7 @@ struct usb_bus_methods {
/* USB Device mode only - Mandatory */ /* USB Device mode only - Mandatory */
void (*get_hw_ep_profile) (struct usb_device *udev, const struct usb_hw_ep_profile **ppf, uint8_t ep_addr); void (*get_hw_ep_profile) (struct usb_device *udev, const struct usb_hw_ep_profile **ppf, uint8_t ep_addr);
void (*set_stall) (struct usb_device *udev, struct usb_xfer *xfer, struct usb_endpoint *ep); void (*set_stall) (struct usb_device *udev, struct usb_xfer *xfer, struct usb_endpoint *ep, uint8_t *did_stall);
void (*clear_stall) (struct usb_device *udev, struct usb_endpoint *ep); void (*clear_stall) (struct usb_device *udev, struct usb_endpoint *ep);
}; };

View File

@ -936,7 +936,7 @@ usbd_set_endpoint_stall(struct usb_device *udev, struct usb_endpoint *ep,
* complete the USB transfer like in case of a timeout * complete the USB transfer like in case of a timeout
* setting the error code "USB_ERR_STALLED". * setting the error code "USB_ERR_STALLED".
*/ */
(udev->bus->methods->set_stall) (udev, xfer, ep); (udev->bus->methods->set_stall) (udev, xfer, ep, &do_stall);
} }
if (!do_stall) { if (!do_stall) {
ep->toggle_next = 0; /* reset data toggle */ ep->toggle_next = 0; /* reset data toggle */

View File

@ -198,6 +198,7 @@ usb_handle_iface_request(struct usb_xfer *xfer,
struct usb_device *udev = xfer->xroot->udev; struct usb_device *udev = xfer->xroot->udev;
int error; int error;
uint8_t iface_index; uint8_t iface_index;
uint8_t temp_state;
if ((req.bmRequestType & 0x1F) == UT_INTERFACE) { if ((req.bmRequestType & 0x1F) == UT_INTERFACE) {
iface_index = req.wIndex[0]; /* unicast */ iface_index = req.wIndex[0]; /* unicast */
@ -222,6 +223,10 @@ usb_handle_iface_request(struct usb_xfer *xfer,
/* end of interfaces non-existing interface */ /* end of interfaces non-existing interface */
goto tr_stalled; goto tr_stalled;
} }
/* set initial state */
temp_state = state;
/* forward request to interface, if any */ /* forward request to interface, if any */
if ((error != 0) && if ((error != 0) &&
@ -233,7 +238,7 @@ usb_handle_iface_request(struct usb_xfer *xfer,
#endif #endif
error = USB_HANDLE_REQUEST(iface->subdev, error = USB_HANDLE_REQUEST(iface->subdev,
&req, ppdata, plen, &req, ppdata, plen,
off, state); off, &temp_state);
} }
iface_parent = usbd_get_iface(udev, iface->parent_iface_index); iface_parent = usbd_get_iface(udev, iface->parent_iface_index);
@ -252,14 +257,18 @@ usb_handle_iface_request(struct usb_xfer *xfer,
(iface_parent->subdev != iface->subdev) && (iface_parent->subdev != iface->subdev) &&
device_is_attached(iface_parent->subdev)) { device_is_attached(iface_parent->subdev)) {
error = USB_HANDLE_REQUEST(iface_parent->subdev, error = USB_HANDLE_REQUEST(iface_parent->subdev,
&req, ppdata, plen, off, &req, ppdata, plen, off, &temp_state);
state);
} }
if (error == 0) { if (error == 0) {
/* negativly adjust pointer and length */ /* negativly adjust pointer and length */
*ppdata = ((uint8_t *)(*ppdata)) - off; *ppdata = ((uint8_t *)(*ppdata)) - off;
*plen += off; *plen += off;
goto tr_valid;
if ((state == USB_HR_NOT_COMPLETE) &&
(temp_state == USB_HR_COMPLETE_OK))
goto tr_short;
else
goto tr_valid;
} else if (error == ENOTTY) { } else if (error == ENOTTY) {
goto tr_stalled; goto tr_stalled;
} }
@ -337,6 +346,12 @@ usb_handle_iface_request(struct usb_xfer *xfer,
USB_XFER_LOCK(xfer); USB_XFER_LOCK(xfer);
return (0); return (0);
tr_short:
mtx_unlock(&Giant);
sx_unlock(udev->default_sx + 1);
USB_XFER_LOCK(xfer);
return (USB_ERR_SHORT_XFER);
tr_stalled: tr_stalled:
mtx_unlock(&Giant); mtx_unlock(&Giant);
sx_unlock(udev->default_sx + 1); sx_unlock(udev->default_sx + 1);
@ -444,6 +459,7 @@ usb_handle_request(struct usb_xfer *xfer)
uint16_t wValue; uint16_t wValue;
uint16_t wIndex; uint16_t wIndex;
uint8_t state; uint8_t state;
uint8_t is_complete = 1;
usb_error_t err; usb_error_t err;
union { union {
uWord wStatus; uWord wStatus;
@ -596,6 +612,9 @@ usb_handle_request(struct usb_xfer *xfer)
USB_ADD_BYTES(&src_zcopy, 0), USB_ADD_BYTES(&src_zcopy, 0),
&max_len, req, off, state); &max_len, req, off, state);
if (err == 0) { if (err == 0) {
is_complete = 0;
goto tr_valid;
} else if (err == USB_ERR_SHORT_XFER) {
goto tr_valid; goto tr_valid;
} }
/* /*
@ -735,7 +754,7 @@ usb_handle_request(struct usb_xfer *xfer)
if (rem > xfer->max_data_length) { if (rem > xfer->max_data_length) {
rem = usbd_xfer_max_len(xfer); rem = usbd_xfer_max_len(xfer);
} }
if (rem != max_len) { if ((rem != max_len) && (is_complete != 0)) {
/* /*
* If we don't transfer the data we can transfer, then * If we don't transfer the data we can transfer, then
* the transfer is short ! * the transfer is short !

View File

@ -36,6 +36,11 @@ INTERFACE usb;
# The device received a control request # The device received a control request
# #
# The value pointed to by "pstate" can be updated to
# "USB_HR_COMPLETE_OK" to indicate that the control
# read transfer is complete, in case of short USB
# control transfers.
#
# Return values: # Return values:
# 0: Success # 0: Success
# ENOTTY: Transaction stalled # ENOTTY: Transaction stalled
@ -47,5 +52,5 @@ METHOD int handle_request {
void **pptr; /* data pointer */ void **pptr; /* data pointer */
uint16_t *plen; /* maximum transfer length */ uint16_t *plen; /* maximum transfer length */
uint16_t offset; /* data offset */ uint16_t offset; /* data offset */
uint8_t is_complete; /* set if transfer is complete, see USB_HR_XXX */ uint8_t *pstate; /* set if transfer is complete, see USB_HR_XXX */
}; };

View File

@ -2352,29 +2352,37 @@ usbd_pipe_start(struct usb_xfer_queue *pq)
(type == UE_INTERRUPT)) { (type == UE_INTERRUPT)) {
struct usb_device *udev; struct usb_device *udev;
struct usb_xfer_root *info; struct usb_xfer_root *info;
uint8_t did_stall;
info = xfer->xroot; info = xfer->xroot;
udev = info->udev; udev = info->udev;
ep->is_stalled = 1; did_stall = 1;
if (udev->flags.usb_mode == USB_MODE_DEVICE) { if (udev->flags.usb_mode == USB_MODE_DEVICE) {
(udev->bus->methods->set_stall) ( (udev->bus->methods->set_stall) (
udev, NULL, ep); udev, NULL, ep, &did_stall);
} else if (udev->default_xfer[1]) { } else if (udev->default_xfer[1]) {
info = udev->default_xfer[1]->xroot; info = udev->default_xfer[1]->xroot;
if (usb_proc_msignal( usb_proc_msignal(
&info->bus->non_giant_callback_proc, &info->bus->non_giant_callback_proc,
&udev->cs_msg[0], &udev->cs_msg[1])) { &udev->cs_msg[0], &udev->cs_msg[1]);
/* ignore */
}
} else { } else {
/* should not happen */ /* should not happen */
DPRINTFN(0, "No stall handler!\n"); DPRINTFN(0, "No stall handler!\n");
} }
/* /*
* We get started again when the stall is cleared! * Check if we should stall. Some USB hardware
* handles set- and clear-stall in hardware.
*/ */
return; if (did_stall) {
/*
* The transfer will be continued when
* the clear-stall control endpoint
* message is received.
*/
ep->is_stalled = 1;
return;
}
} }
} }
/* Set or clear stall complete - special case */ /* Set or clear stall complete - special case */
@ -2966,6 +2974,12 @@ usbd_xfer_set_flag(struct usb_xfer *xfer, int flag)
case USB_SHORT_XFER_OK: case USB_SHORT_XFER_OK:
xfer->flags.short_xfer_ok = 1; xfer->flags.short_xfer_ok = 1;
break; break;
case USB_MULTI_SHORT_OK:
xfer->flags.short_frames_ok = 1;
break;
case USB_MANUAL_STATUS:
xfer->flags.manual_status = 1;
break;
} }
} }
@ -2979,5 +2993,22 @@ usbd_xfer_clr_flag(struct usb_xfer *xfer, int flag)
case USB_SHORT_XFER_OK: case USB_SHORT_XFER_OK:
xfer->flags.short_xfer_ok = 0; xfer->flags.short_xfer_ok = 0;
break; break;
case USB_MULTI_SHORT_OK:
xfer->flags.short_frames_ok = 0;
break;
case USB_MANUAL_STATUS:
xfer->flags.manual_status = 0;
break;
} }
} }
/*
* The following function returns in milliseconds when the isochronous
* transfer was completed by the hardware. The returned value wraps
* around 65536 milliseconds.
*/
uint16_t
usbd_xfer_get_timestamp(struct usb_xfer *xfer)
{
return (xfer->isoc_time_complete);
}

View File

@ -78,6 +78,8 @@ typedef enum { /* keep in sync with usb_errstr_table */
#define USB_SHORT_XFER_OK 0x0004 /* allow short reads */ #define USB_SHORT_XFER_OK 0x0004 /* allow short reads */
#define USB_DELAY_STATUS_STAGE 0x0010 /* insert delay before STATUS stage */ #define USB_DELAY_STATUS_STAGE 0x0010 /* insert delay before STATUS stage */
#define USB_USER_DATA_PTR 0x0020 /* internal flag */ #define USB_USER_DATA_PTR 0x0020 /* internal flag */
#define USB_MULTI_SHORT_OK 0x0040 /* allow multiple short frames */
#define USB_MANUAL_STATUS 0x0080 /* manual ctrl status */
#define USB_NO_TIMEOUT 0 #define USB_NO_TIMEOUT 0
#define USB_DEFAULT_TIMEOUT 5000 /* 5000 ms = 5 seconds */ #define USB_DEFAULT_TIMEOUT 5000 /* 5000 ms = 5 seconds */
@ -486,6 +488,7 @@ void usbd_xfer_set_stall(struct usb_xfer *xfer);
int usbd_xfer_is_stalled(struct usb_xfer *xfer); int usbd_xfer_is_stalled(struct usb_xfer *xfer);
void usbd_xfer_set_flag(struct usb_xfer *xfer, int flag); void usbd_xfer_set_flag(struct usb_xfer *xfer, int flag);
void usbd_xfer_clr_flag(struct usb_xfer *xfer, int flag); void usbd_xfer_clr_flag(struct usb_xfer *xfer, int flag);
uint16_t usbd_xfer_get_timestamp(struct usb_xfer *xfer);
void usbd_copy_in(struct usb_page_cache *cache, usb_frlength_t offset, void usbd_copy_in(struct usb_page_cache *cache, usb_frlength_t offset,
const void *ptr, usb_frlength_t len); const void *ptr, usb_frlength_t len);