Allow multiple interfaces to be claimed
authorDaniel Drake <dsd@gentoo.org>
Fri, 2 May 2008 16:33:52 +0000 (17:33 +0100)
committerDaniel Drake <dsd@gentoo.org>
Fri, 2 May 2008 16:33:52 +0000 (17:33 +0100)
TODO
libusb/core.c
libusb/libusb.h
libusb/libusbi.h

diff --git a/TODO b/TODO
index 89db498..955e501 100644 (file)
--- a/TODO
+++ b/TODO
@@ -5,6 +5,8 @@ review functionality missing over 0.1
 endianness of control setup, issues when resubmitting transfers
 doxygen warnings
 serialization of handle_events
+0.1 compat layer
+internal docs for OS porters
 
 1.0 API style/naming points to reconsider
 =========================================
index 634bc8b..0f6b22d 100644 (file)
@@ -435,8 +435,14 @@ API_EXPORTED libusb_device_handle *libusb_open(libusb_device *dev)
        if (!handle)
                return NULL;
 
+       r = pthread_mutex_init(&handle->lock, NULL);
+       if (r)
+               return NULL;
+
        handle->dev = libusb_device_ref(dev);
+       handle->claimed_interfaces = 0;
        memset(&handle->os_priv, 0, priv_size);
+
        r = usbi_backend->open(handle);
        if (r < 0) {
                libusb_device_unref(dev);
@@ -534,40 +540,90 @@ API_EXPORTED libusb_device *libusb_get_device(libusb_device_handle *dev_handle)
        return dev_handle->dev;
 }
 
-/* FIXME: what about claiming multiple interfaces? */
 /** \ingroup dev
  * Claim an interface on a given device handle. You must claim the interface
- * you wish to use before you can perform I/O on any of the endpoints.
- * \param iface the <tt>bInterfaceNumber</tt> of the interface you wish to claim
+ * you wish to use before you can perform I/O on any of its endpoints.
+ *
+ * It is legal to attempt to claim an already-claimed interface, in which
+ * case libusb just returns 0 without doing anything.
+ *
  * \param dev a device handle
+ * \param interface_number the <tt>bInterfaceNumber</tt> of the interface you
+ * wish to claim
  * \returns 0 on success, or a LIBUSB_ERROR code on failure
  */
-API_EXPORTED int libusb_claim_interface(libusb_device_handle *dev, int iface)
+API_EXPORTED int libusb_claim_interface(libusb_device_handle *dev,
+       int interface_number)
 {
-       usbi_dbg("interface %d", iface);
-       return usbi_backend->claim_interface(dev, iface);
+       int r = 0;
+
+       usbi_dbg("interface %d", interface_number);
+       if (interface_number >= sizeof(dev->claimed_interfaces) * 8)
+               return LIBUSB_ERROR_INVALID_PARAM;
+
+       pthread_mutex_lock(&dev->lock);
+       if (dev->claimed_interfaces & (1 << interface_number))
+               goto out;
+
+       r = usbi_backend->claim_interface(dev, interface_number);
+       if (r == 0)
+               dev->claimed_interfaces |= 1 << interface_number;
+
+out:
+       pthread_mutex_unlock(&dev->lock);
+       return r;
 }
 
 /** \ingroup dev
  * Release an interface previously claimed with libusb_claim_interface(). You
  * should release all claimed interfaces before closing a device handle.
  * \param dev a device handle
- * \param iface the <tt>bInterfaceNumber</tt> of the previously-claimed
- * interface
- * \returns 0 on success, or a LIBUSB_ERROR code on failure
+ * \param interface_number the <tt>bInterfaceNumber</tt> of the
+ * previously-claimed interface
+ * \returns 0 on success, or a LIBUSB_ERROR code on failure.
+ * LIBUSB_ERROR_NOT_FOUND indicates that the interface was not claimed.
  */
-API_EXPORTED int libusb_release_interface(libusb_device_handle *dev, int iface)
+API_EXPORTED int libusb_release_interface(libusb_device_handle *dev,
+       int interface_number)
 {
-       usbi_dbg("interface %d", iface);
-       return usbi_backend->release_interface(dev, iface);
+       int r;
+
+       usbi_dbg("interface %d", interface_number);
+       if (interface_number >= sizeof(dev->claimed_interfaces) * 8)
+               return LIBUSB_ERROR_INVALID_PARAM;
+
+       pthread_mutex_lock(&dev->lock);
+       if (!(dev->claimed_interfaces & (1 << interface_number))) {
+               r = LIBUSB_ERROR_NOT_FOUND;
+               goto out;
+       }
+
+       r = usbi_backend->release_interface(dev, interface_number);
+       if (r == 0)
+               dev->claimed_interfaces &= ~(1 << interface_number);
+
+out:
+       pthread_mutex_unlock(&dev->lock);
+       return r;
 }
 
 /* FIXME docs */
 API_EXPORTED int libusb_set_interface_altsetting(libusb_device_handle *dev,
-       int iface, int altsetting)
+       int interface_number, int altsetting)
 {
-       usbi_dbg("interface %d altsetting %d", iface, altsetting);
-       return usbi_backend->set_interface_altsetting(dev, iface, altsetting);
+       usbi_dbg("interface %d altsetting %d", interface_number, altsetting);
+       if (interface_number >= sizeof(dev->claimed_interfaces) * 8)
+               return LIBUSB_ERROR_INVALID_PARAM;
+
+       pthread_mutex_lock(&dev->lock);
+       if (!(dev->claimed_interfaces & (1 << interface_number))) {
+               pthread_mutex_unlock(&dev->lock);       
+               return LIBUSB_ERROR_NOT_FOUND;
+       }
+       pthread_mutex_unlock(&dev->lock);
+
+       return usbi_backend->set_interface_altsetting(dev, interface_number,
+               altsetting);
 }
 
 /** \ingroup lib
index aeab1a1..e44019d 100644 (file)
@@ -521,8 +521,9 @@ enum libusb_error {
        LIBUSB_ERROR_IO = -1,
        LIBUSB_ERROR_INVALID_PARAM = -2,
        LIBUSB_ERROR_ACCESS = -3,
-       LIBUSB_ERROR_NOMEM = -4,
-       LIBUSB_ERROR_OTHER = -5,
+       LIBUSB_ERROR_NOT_FOUND = -4,
+       LIBUSB_ERROR_NOMEM = -5,
+       LIBUSB_ERROR_OTHER = -6,
 };
 
 /** \ingroup asyncio
index 196f94f..69e565a 100644 (file)
@@ -159,6 +159,10 @@ struct libusb_device {
 };
 
 struct libusb_device_handle {
+       /* lock protects claimed_interfaces */
+       pthread_mutex_t lock;
+       unsigned long claimed_interfaces;
+
        struct list_head list;
        struct libusb_device *dev;
        unsigned char os_priv[0];