summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Hjelm <hjelmn@me.com>2013-09-12 14:57:01 -0600
committerNathan Hjelm <hjelmn@me.com>2014-05-06 02:21:57 -0600
commite16575ceaf3148c389d66686e51af7cc8dff6053 (patch)
tree9aeb748085695229012e3da1842345ee511d11b0
parent7200c567ea74ef050eb944ef2eb31fccef605732 (diff)
downloadlibusb-e16575ceaf3148c389d66686e51af7cc8dff6053.tar.gz
darwin: Add support for bulk stream transfers.
This commit adds support for bulk streams to the darwin backend. I have not had a chance to fully test this code as I have no access to any devices that use this interface. Signed-off-by: Nathan Hjelm <hjelmn@me.com>
-rw-r--r--libusb/core.c3
-rw-r--r--libusb/os/darwin_usb.c120
-rw-r--r--libusb/version_nano.h2
3 files changed, 122 insertions, 3 deletions
diff --git a/libusb/core.c b/libusb/core.c
index f766e62..ffce020 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -1621,7 +1621,8 @@ int API_EXPORTED libusb_reset_device(libusb_device_handle *dev)
* some protocols require that endpoints are setup with similar stream ids.
* All endpoints passed in must belong to the same interface.
*
- * Note this function may return less streams then requested.
+ * Note this function may return less streams then requested. Also note that the
+ * same number of streams are allocated for each endpoint in the endpoint array.
*
* Stream id 0 is reserved, and should not be used to communicate with devices.
* If libusb_alloc_streams() returns with a value of N, you may use stream ids
diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c
index b66fe80..dc80281 100644
--- a/libusb/os/darwin_usb.c
+++ b/libusb/os/darwin_usb.c
@@ -1483,6 +1483,41 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer) {
return darwin_to_libusb (ret);
}
+#if InterfaceVersion >= 550
+static int submit_stream_transfer(struct usbi_transfer *itransfer) {
+ struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv;
+ struct darwin_interface *cInterface;
+ uint8_t pipeRef, iface;
+ IOReturn ret;
+
+ if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) {
+ usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
+
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ cInterface = &priv->interfaces[iface];
+
+ itransfer->flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT;
+
+ if (IS_XFERIN(transfer))
+ ret = (*(cInterface->interface))->ReadStreamsPipeAsyncTO(cInterface->interface, pipeRef, itransfer->stream_id,
+ transfer->buffer, transfer->length, transfer->timeout,
+ transfer->timeout, darwin_async_io_callback, (void *)itransfer);
+ else
+ ret = (*(cInterface->interface))->WriteStreamsPipeAsyncTO(cInterface->interface, pipeRef, itransfer->stream_id,
+ transfer->buffer, transfer->length, transfer->timeout,
+ transfer->timeout, darwin_async_io_callback, (void *)itransfer);
+
+ if (ret)
+ usbi_err (TRANSFER_CTX (transfer), "bulk stream transfer failed (dir = %s): %s (code = 0x%08x)", IS_XFERIN(transfer) ? "In" : "Out",
+ darwin_error_str(ret), ret);
+
+ return darwin_to_libusb (ret);
+}
+#endif
+
static int submit_iso_transfer(struct usbi_transfer *itransfer) {
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
@@ -1634,6 +1669,13 @@ static int darwin_submit_transfer(struct usbi_transfer *itransfer) {
return submit_bulk_transfer(itransfer);
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
return submit_iso_transfer(itransfer);
+ case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
+#if InterfaceVersion >= 550
+ return submit_stream_transfer(itransfer);
+#else
+ usbi_err (TRANSFER_CTX(transfer), "IOUSBFamily version does not support bulk stream transfers");
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+#endif
default:
usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
return LIBUSB_ERROR_INVALID_PARAM;
@@ -1677,7 +1719,12 @@ static int darwin_abort_transfers (struct usbi_transfer *itransfer) {
usbi_warn (ITRANSFER_CTX (itransfer), "aborting all transactions on interface %d pipe %d", iface, pipeRef);
/* abort transactions */
- (*(cInterface->interface))->AbortPipe (cInterface->interface, pipeRef);
+#if InterfaceVersion >= 550
+ if (LIBUSB_TRANSFER_TYPE_BULK_STREAM == transfer->type)
+ (*(cInterface->interface))->AbortStreamsPipe (cInterface->interface, pipeRef, itransfer->stream_id);
+ else
+#endif
+ (*(cInterface->interface))->AbortPipe (cInterface->interface, pipeRef);
usbi_dbg ("calling clear pipe stall to clear the data toggle bit");
@@ -1859,6 +1906,72 @@ static int darwin_clock_gettime(int clk_id, struct timespec *tp) {
return 0;
}
+#if InterfaceVersion >= 550
+static int darwin_alloc_streams (struct libusb_device_handle *dev_handle, uint32_t num_streams, unsigned char *endpoints,
+ int num_endpoints) {
+ struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *) dev_handle->os_priv;
+ struct darwin_interface *cInterface;
+ uint8_t pipeRef, iface;
+ UInt32 supportsStreams;
+ int rc, i;
+
+ /* find the mimimum number of supported streams on the endpoint list */
+ for (i = 0 ; i < num_endpoints ; ++i) {
+ if (0 != (rc = ep_to_pipeRef (dev_handle, endpoints[i], &pipeRef, &iface))) {
+ return rc;
+ }
+
+ cInterface = &priv->interfaces[iface];
+
+ (*(cInterface->interface))->SupportsStreams (cInterface->interface, pipeRef, &supportsStreams);
+ if (num_streams > supportsStreams)
+ num_streams = supportsStreams;
+ }
+
+ /* it is an error if any endpoint in endpoints does not support streams */
+ if (0 == num_streams)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ /* create the streams */
+ for (i = 0 ; i < num_endpoints ; ++i) {
+ (void) ep_to_pipeRef (dev_handle, endpoints[i], &pipeRef, &iface);
+
+ cInterface = &priv->interfaces[iface];
+
+ rc = (*(cInterface->interface))->CreateStreams (cInterface->interface, pipeRef, num_streams);
+ if (kIOReturnSuccess != rc)
+ return darwin_to_libusb(rc);
+ }
+
+ return num_streams;
+}
+
+static int darwin_free_streams (struct libusb_device_handle *dev_handle, unsigned char *endpoints, int num_endpoints) {
+ struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *) dev_handle->os_priv;
+ struct darwin_interface *cInterface;
+ uint8_t pipeRef, iface;
+ UInt32 supportsStreams;
+ int rc;
+
+ for (int i = 0 ; i < num_endpoints ; ++i) {
+ if (0 != (rc = ep_to_pipeRef (dev_handle, endpoints[i], &pipeRef, &iface)))
+ return rc;
+
+ cInterface = &priv->interfaces[iface];
+
+ (*(cInterface->interface))->SupportsStreams (cInterface->interface, pipeRef, &supportsStreams);
+ if (0 == supportsStreams)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ rc = (*(cInterface->interface))->CreateStreams (cInterface->interface, pipeRef, 0);
+ if (kIOReturnSuccess != rc)
+ return darwin_to_libusb(rc);
+ }
+
+ return LIBUSB_SUCCESS;;
+}
+#endif
+
const struct usbi_os_backend darwin_backend = {
.name = "Darwin",
.caps = 0,
@@ -1880,6 +1993,11 @@ const struct usbi_os_backend darwin_backend = {
.clear_halt = darwin_clear_halt,
.reset_device = darwin_reset_device,
+#if InterfaceVersion >= 550
+ .alloc_streams = darwin_alloc_streams,
+ .free_streams = darwin_free_streams,
+#endif
+
.kernel_driver_active = darwin_kernel_driver_active,
.detach_kernel_driver = darwin_detach_kernel_driver,
.attach_kernel_driver = darwin_attach_kernel_driver,
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index 9516b27..191ac46 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 10882
+#define LIBUSB_NANO 10883