From 429d808d4e72e57bbd437991d75d15a19ce7d715 Mon Sep 17 00:00:00 2001
From: Ingo Ruhnke <grumbel@gmx.de>
Date: Thu, 26 May 2011 15:03:34 +0200
Subject: [PATCH] Added try_detach to USBInterface

---
 src/usb_interface.cpp | 27 +++++++++++++++++++++++++--
 src/usb_interface.hpp |  2 +-
 2 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/src/usb_interface.cpp b/src/usb_interface.cpp
index 1f174f3..e7ed5f8 100644
--- a/src/usb_interface.cpp
+++ b/src/usb_interface.cpp
@@ -53,13 +53,36 @@ private:
   USBWriteCallback& operator=(const USBWriteCallback&);
 };
 
-USBInterface::USBInterface(libusb_device_handle* handle, int interface) :
+USBInterface::USBInterface(libusb_device_handle* handle, int interface, bool try_detach) :
   m_handle(handle),
   m_interface(interface),
   m_endpoints()
 {
   int ret = libusb_claim_interface(handle, m_interface);
-  if (ret != LIBUSB_SUCCESS)
+  if (ret == LIBUSB_SUCCESS)
+  {
+    // success
+  }
+  else if (ret == LIBUSB_ERROR_BUSY && try_detach)
+  {
+    // try to detach and then try to reopen
+    ret = libusb_detach_kernel_driver(handle, interface);
+    if (ret != LIBUSB_SUCCESS)
+    {
+      raise_exception(std::runtime_error, "error detaching kernel driver: "
+                      << interface << ": " << usb_strerror(ret));
+    }
+    else
+    {
+      // kernel driver detached, try to claim it again
+      ret = libusb_claim_interface(handle, interface);
+      if (ret != LIBUSB_SUCCESS)
+      {
+        raise_exception(std::runtime_error, "error claiming interface: " << interface << ": " << usb_strerror(ret));
+      }
+    }
+  }
+  else
   {
     raise_exception(std::runtime_error, "error claiming interface: " << interface << ": " << usb_strerror(ret));
   }
diff --git a/src/usb_interface.hpp b/src/usb_interface.hpp
index 09b06df..2dd83b3 100644
--- a/src/usb_interface.hpp
+++ b/src/usb_interface.hpp
@@ -35,7 +35,7 @@ private:
   Endpoints m_endpoints;
 
 public:
-  USBInterface(libusb_device_handle* handle, int interface);
+  USBInterface(libusb_device_handle* handle, int interface, bool try_detach = false);
   ~USBInterface();
 
   void submit_read(int endpoint, int len,