summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorthompsa <thompsa@FreeBSD.org>2009-06-27 21:23:30 +0000
committerthompsa <thompsa@FreeBSD.org>2009-06-27 21:23:30 +0000
commitff880be8b902c41ec399c05ac1f85bf74c0fa6ad (patch)
treeac244c5834e146ddb6b188a14c852ced0d303298
parent6a523f03ea03e31b66264afaf4a531790162a406 (diff)
downloadFreeBSD-src-ff880be8b902c41ec399c05ac1f85bf74c0fa6ad.zip
FreeBSD-src-ff880be8b902c41ec399c05ac1f85bf74c0fa6ad.tar.gz
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)
-rw-r--r--sys/dev/usb/controller/at91dci.c2
-rw-r--r--sys/dev/usb/controller/atmegadci.c2
-rw-r--r--sys/dev/usb/controller/avr32dci.c2
-rw-r--r--sys/dev/usb/controller/musb_otg.c2
-rw-r--r--sys/dev/usb/controller/uss820dci.c2
-rw-r--r--sys/dev/usb/net/if_cdce.c2
-rw-r--r--sys/dev/usb/storage/ustorage_fs.c3
-rw-r--r--sys/dev/usb/usb_controller.h2
-rw-r--r--sys/dev/usb/usb_device.c2
-rw-r--r--sys/dev/usb/usb_handle_request.c29
-rw-r--r--sys/dev/usb/usb_if.m7
-rw-r--r--sys/dev/usb/usb_transfer.c47
-rw-r--r--sys/dev/usb/usbdi.h3
13 files changed, 82 insertions, 23 deletions
diff --git a/sys/dev/usb/controller/at91dci.c b/sys/dev/usb/controller/at91dci.c
index 6c0ae08..210f0e7 100644
--- a/sys/dev/usb/controller/at91dci.c
+++ b/sys/dev/usb/controller/at91dci.c
@@ -1227,7 +1227,7 @@ at91dci_device_done(struct usb_xfer *xfer, usb_error_t error)
static void
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;
uint32_t csr_val;
diff --git a/sys/dev/usb/controller/atmegadci.c b/sys/dev/usb/controller/atmegadci.c
index ef7e643..47e27b5 100644
--- a/sys/dev/usb/controller/atmegadci.c
+++ b/sys/dev/usb/controller/atmegadci.c
@@ -1113,7 +1113,7 @@ atmegadci_device_done(struct usb_xfer *xfer, usb_error_t error)
static void
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;
uint8_t ep_no;
diff --git a/sys/dev/usb/controller/avr32dci.c b/sys/dev/usb/controller/avr32dci.c
index 07bf2ca..156f286 100644
--- a/sys/dev/usb/controller/avr32dci.c
+++ b/sys/dev/usb/controller/avr32dci.c
@@ -1081,7 +1081,7 @@ avr32dci_device_done(struct usb_xfer *xfer, usb_error_t error)
static void
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;
uint8_t ep_no;
diff --git a/sys/dev/usb/controller/musb_otg.c b/sys/dev/usb/controller/musb_otg.c
index c9e4bf6..81332d7 100644
--- a/sys/dev/usb/controller/musb_otg.c
+++ b/sys/dev/usb/controller/musb_otg.c
@@ -1473,7 +1473,7 @@ musbotg_device_done(struct usb_xfer *xfer, usb_error_t error)
static void
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;
uint8_t ep_no;
diff --git a/sys/dev/usb/controller/uss820dci.c b/sys/dev/usb/controller/uss820dci.c
index c1c5b35..1016ed6 100644
--- a/sys/dev/usb/controller/uss820dci.c
+++ b/sys/dev/usb/controller/uss820dci.c
@@ -1202,7 +1202,7 @@ uss820dci_device_done(struct usb_xfer *xfer, usb_error_t error)
static void
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;
uint8_t ep_no;
diff --git a/sys/dev/usb/net/if_cdce.c b/sys/dev/usb/net/if_cdce.c
index ec4cc95..352fcec 100644
--- a/sys/dev/usb/net/if_cdce.c
+++ b/sys/dev/usb/net/if_cdce.c
@@ -764,7 +764,7 @@ tr_setup:
static int
cdce_handle_request(device_t dev,
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 */
}
diff --git a/sys/dev/usb/storage/ustorage_fs.c b/sys/dev/usb/storage/ustorage_fs.c
index b7e64bb..10047e1 100644
--- a/sys/dev/usb/storage/ustorage_fs.c
+++ b/sys/dev/usb/storage/ustorage_fs.c
@@ -475,10 +475,11 @@ ustorage_fs_transfer_stop(struct ustorage_fs_softc *sc)
static int
ustorage_fs_handle_request(device_t dev,
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);
const struct usb_device_request *req = preq;
+ uint8_t is_complete = *pstate;
if (!is_complete) {
if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
diff --git a/sys/dev/usb/usb_controller.h b/sys/dev/usb/usb_controller.h
index 952cd19..fbdfe31 100644
--- a/sys/dev/usb/usb_controller.h
+++ b/sys/dev/usb/usb_controller.h
@@ -96,7 +96,7 @@ struct usb_bus_methods {
/* 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 (*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);
};
diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c
index 8439c69..6617297 100644
--- a/sys/dev/usb/usb_device.c
+++ b/sys/dev/usb/usb_device.c
@@ -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
* 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) {
ep->toggle_next = 0; /* reset data toggle */
diff --git a/sys/dev/usb/usb_handle_request.c b/sys/dev/usb/usb_handle_request.c
index 7f78d92..23486ad 100644
--- a/sys/dev/usb/usb_handle_request.c
+++ b/sys/dev/usb/usb_handle_request.c
@@ -198,6 +198,7 @@ usb_handle_iface_request(struct usb_xfer *xfer,
struct usb_device *udev = xfer->xroot->udev;
int error;
uint8_t iface_index;
+ uint8_t temp_state;
if ((req.bmRequestType & 0x1F) == UT_INTERFACE) {
iface_index = req.wIndex[0]; /* unicast */
@@ -222,6 +223,10 @@ tr_repeat:
/* end of interfaces non-existing interface */
goto tr_stalled;
}
+ /* set initial state */
+
+ temp_state = state;
+
/* forward request to interface, if any */
if ((error != 0) &&
@@ -233,7 +238,7 @@ tr_repeat:
#endif
error = USB_HANDLE_REQUEST(iface->subdev,
&req, ppdata, plen,
- off, state);
+ off, &temp_state);
}
iface_parent = usbd_get_iface(udev, iface->parent_iface_index);
@@ -252,14 +257,18 @@ tr_repeat:
(iface_parent->subdev != iface->subdev) &&
device_is_attached(iface_parent->subdev)) {
error = USB_HANDLE_REQUEST(iface_parent->subdev,
- &req, ppdata, plen, off,
- state);
+ &req, ppdata, plen, off, &temp_state);
}
if (error == 0) {
/* negativly adjust pointer and length */
*ppdata = ((uint8_t *)(*ppdata)) - 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) {
goto tr_stalled;
}
@@ -337,6 +346,12 @@ tr_valid:
USB_XFER_LOCK(xfer);
return (0);
+tr_short:
+ mtx_unlock(&Giant);
+ sx_unlock(udev->default_sx + 1);
+ USB_XFER_LOCK(xfer);
+ return (USB_ERR_SHORT_XFER);
+
tr_stalled:
mtx_unlock(&Giant);
sx_unlock(udev->default_sx + 1);
@@ -444,6 +459,7 @@ usb_handle_request(struct usb_xfer *xfer)
uint16_t wValue;
uint16_t wIndex;
uint8_t state;
+ uint8_t is_complete = 1;
usb_error_t err;
union {
uWord wStatus;
@@ -596,6 +612,9 @@ usb_handle_request(struct usb_xfer *xfer)
USB_ADD_BYTES(&src_zcopy, 0),
&max_len, req, off, state);
if (err == 0) {
+ is_complete = 0;
+ goto tr_valid;
+ } else if (err == USB_ERR_SHORT_XFER) {
goto tr_valid;
}
/*
@@ -735,7 +754,7 @@ tr_valid:
if (rem > xfer->max_data_length) {
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
* the transfer is short !
diff --git a/sys/dev/usb/usb_if.m b/sys/dev/usb/usb_if.m
index 90db14d..926a237 100644
--- a/sys/dev/usb/usb_if.m
+++ b/sys/dev/usb/usb_if.m
@@ -36,6 +36,11 @@ INTERFACE usb;
# 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:
# 0: Success
# ENOTTY: Transaction stalled
@@ -47,5 +52,5 @@ METHOD int handle_request {
void **pptr; /* data pointer */
uint16_t *plen; /* maximum transfer length */
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 */
};
diff --git a/sys/dev/usb/usb_transfer.c b/sys/dev/usb/usb_transfer.c
index ab78b0b..04b462e 100644
--- a/sys/dev/usb/usb_transfer.c
+++ b/sys/dev/usb/usb_transfer.c
@@ -2352,29 +2352,37 @@ usbd_pipe_start(struct usb_xfer_queue *pq)
(type == UE_INTERRUPT)) {
struct usb_device *udev;
struct usb_xfer_root *info;
+ uint8_t did_stall;
info = xfer->xroot;
udev = info->udev;
- ep->is_stalled = 1;
+ did_stall = 1;
if (udev->flags.usb_mode == USB_MODE_DEVICE) {
(udev->bus->methods->set_stall) (
- udev, NULL, ep);
+ udev, NULL, ep, &did_stall);
} else if (udev->default_xfer[1]) {
info = udev->default_xfer[1]->xroot;
- if (usb_proc_msignal(
+ usb_proc_msignal(
&info->bus->non_giant_callback_proc,
- &udev->cs_msg[0], &udev->cs_msg[1])) {
- /* ignore */
- }
+ &udev->cs_msg[0], &udev->cs_msg[1]);
} else {
/* should not happen */
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 */
@@ -2966,6 +2974,12 @@ usbd_xfer_set_flag(struct usb_xfer *xfer, int flag)
case USB_SHORT_XFER_OK:
xfer->flags.short_xfer_ok = 1;
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:
xfer->flags.short_xfer_ok = 0;
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);
+}
diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h
index 850cb97..6ed775e 100644
--- a/sys/dev/usb/usbdi.h
+++ b/sys/dev/usb/usbdi.h
@@ -78,6 +78,8 @@ typedef enum { /* keep in sync with usb_errstr_table */
#define USB_SHORT_XFER_OK 0x0004 /* allow short reads */
#define USB_DELAY_STATUS_STAGE 0x0010 /* insert delay before STATUS stage */
#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_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);
void usbd_xfer_set_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,
const void *ptr, usb_frlength_t len);
OpenPOWER on IntegriCloud