blob: 5b8d2f453edec87653e74ef3c139cfe5b3293371 [file] [log] [blame]
commit 27cdd9c6a994f3059b8ae683adb711169341ffa5
Author: Ingo Ruhnke <grumbel@gmail.com>
Date: Wed Dec 19 11:39:31 2012 +0100
Added additional bookkeeping to USBController to allow clean shutdowns with libusbx
Fixes #28
--- a/src/firestorm_dual_controller.cpp
+++ b/src/firestorm_dual_controller.cpp
@@ -99,8 +99,6 @@ FirestormDualController::FirestormDualController(libusb_device* dev, bool is_vsb
FirestormDualController::~FirestormDualController()
{
- usb_cancel_read();
- usb_release_interface(0);
}
void
--- a/src/generic_usb_controller.cpp
+++ b/src/generic_usb_controller.cpp
@@ -62,8 +62,6 @@ GenericUSBController::GenericUSBController(libusb_device* dev,
GenericUSBController::~GenericUSBController()
{
- usb_cancel_read();
- usb_release_interface(m_interface);
}
void
--- a/src/playstation3_usb_controller.cpp
+++ b/src/playstation3_usb_controller.cpp
@@ -37,8 +37,6 @@ Playstation3USBController::Playstation3USBController(libusb_device* dev, bool tr
Playstation3USBController::~Playstation3USBController()
{
- usb_cancel_read();
- usb_release_interface(0);
}
#define HID_GET_REPORT 0x01
--- a/src/saitek_p2500_controller.cpp
+++ b/src/saitek_p2500_controller.cpp
@@ -66,8 +66,6 @@ SaitekP2500Controller::SaitekP2500Controller(libusb_device* dev, bool try_detach
SaitekP2500Controller::~SaitekP2500Controller()
{
- usb_cancel_read();
- usb_release_interface(0);
}
void
--- a/src/usb_controller.cpp
+++ b/src/usb_controller.cpp
@@ -28,7 +28,8 @@
USBController::USBController(libusb_device* dev) :
m_dev(dev),
m_handle(0),
- m_read_transfer(),
+ m_transfers(),
+ m_interfaces(),
m_usbpath(),
m_usbid(),
m_name()
@@ -78,7 +79,29 @@ USBController::USBController(libusb_device* dev) :
USBController::~USBController()
{
- //log_tmp("~USBController");
+ // cancel all transfers
+ for(std::set<libusb_transfer*>::iterator it = m_transfers.begin(); it != m_transfers.end(); ++it)
+ {
+ libusb_cancel_transfer(*it);
+ }
+
+ // wait for cancel to succeed
+ while (!m_transfers.empty())
+ {
+ int ret = libusb_handle_events(NULL);
+ if (ret != 0)
+ {
+ log_error("libusb_handle_events() failure: " << ret);
+ }
+ }
+
+ // release all claimed interfaces
+ for(std::set<int>::iterator it = m_interfaces.begin(); it != m_interfaces.end(); ++it)
+ {
+ libusb_release_interface(m_handle, *it);
+ }
+
+ // read and write transfers might still be going on and might need to be canceled
libusb_close(m_handle);
}
@@ -103,23 +126,26 @@ USBController::get_name() const
void
USBController::usb_submit_read(int endpoint, int len)
{
- assert(!m_read_transfer);
-
- m_read_transfer = libusb_alloc_transfer(0);
+ libusb_transfer* transfer = libusb_alloc_transfer(0);
uint8_t* data = static_cast<uint8_t*>(malloc(sizeof(uint8_t) * len));
- m_read_transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER;
- libusb_fill_interrupt_transfer(m_read_transfer, m_handle,
+ transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER;
+ libusb_fill_interrupt_transfer(transfer, m_handle,
endpoint | LIBUSB_ENDPOINT_IN,
data, len,
&USBController::on_read_data_wrap, this,
0); // timeout
int ret;
- ret = libusb_submit_transfer(m_read_transfer);
+ ret = libusb_submit_transfer(transfer);
if (ret != LIBUSB_SUCCESS)
{
+ libusb_free_transfer(transfer);
raise_exception(std::runtime_error, "libusb_submit_transfer(): " << usb_strerror(ret));
}
+ else
+ {
+ m_transfers.insert(transfer);
+ }
}
void
@@ -127,7 +153,6 @@ USBController::usb_write(int endpoint, uint8_t* data_in, int len)
{
libusb_transfer* transfer = libusb_alloc_transfer(0);
transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER;
- transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
// copy data into a newly allocated buffer
uint8_t* data = static_cast<uint8_t*>(malloc(sizeof(uint8_t) * len));
@@ -143,8 +168,13 @@ USBController::usb_write(int endpoint, uint8_t* data_in, int len)
ret = libusb_submit_transfer(transfer);
if (ret != LIBUSB_SUCCESS)
{
+ libusb_free_transfer(transfer);
raise_exception(std::runtime_error, "libusb_submit_transfer(): " << usb_strerror(ret));
}
+ else
+ {
+ m_transfers.insert(transfer);
+ }
}
void
@@ -154,7 +184,6 @@ USBController::usb_control(uint8_t bmRequestType, uint8_t bRequest,
{
libusb_transfer* transfer = libusb_alloc_transfer(0);
transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER;
- transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
// create and fill control buffer
uint8_t* data = static_cast<uint8_t*>(malloc(wLength + 8));
@@ -168,14 +197,22 @@ USBController::usb_control(uint8_t bmRequestType, uint8_t bRequest,
ret = libusb_submit_transfer(transfer);
if (ret != LIBUSB_SUCCESS)
{
+ libusb_free_transfer(transfer);
raise_exception(std::runtime_error, "libusb_submit_transfer(): " << usb_strerror(ret));
}
+ else
+ {
+ m_transfers.insert(transfer);
+ }
}
void
USBController::on_control(libusb_transfer* transfer)
{
log_debug("control transfer");
+
+ m_transfers.erase(transfer);
+ libusb_free_transfer(transfer);
}
void
@@ -183,19 +220,12 @@ USBController::on_write_data(libusb_transfer* transfer)
{
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
{
- log_error("USB write failure: " << transfer->length << ": " << usb_transfer_strerror(transfer->status));
+ if (transfer->status != LIBUSB_TRANSFER_CANCELLED)
+ log_error("USB write failure: " << transfer->length << ": " << usb_transfer_strerror(transfer->status));
}
-}
-void
-USBController::usb_cancel_read()
-{
- if (m_read_transfer)
- {
- libusb_cancel_transfer(m_read_transfer);
- libusb_free_transfer(m_read_transfer);
- m_read_transfer = 0;
- }
+ m_transfers.erase(transfer);
+ libusb_free_transfer(transfer);
}
void
@@ -203,31 +233,30 @@ USBController::on_read_data(libusb_transfer* transfer)
{
assert(transfer);
- // FIXME: check for LIBUSB_TRANSFER_COMPLETED
-
- // process data
- XboxGenericMsg msg;
- if (parse(transfer->buffer, transfer->actual_length, &msg))
+ if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
{
- submit_msg(msg);
- }
+ if (transfer->status != LIBUSB_TRANSFER_CANCELLED)
+ log_error("USB read failure: " << transfer->length << ": " << usb_transfer_strerror(transfer->status));
- if (false) // cleanup
- {
+ m_transfers.erase(transfer);
libusb_free_transfer(transfer);
}
- else // resubmit
- {
+ else
+ {
+ // process data
+ XboxGenericMsg msg;
+ if (parse(transfer->buffer, transfer->actual_length, &msg))
+ {
+ submit_msg(msg);
+ }
+
int ret;
ret = libusb_submit_transfer(transfer);
if (ret != LIBUSB_SUCCESS) // could also check for LIBUSB_ERROR_NO_DEVICE
{
log_error("failed to resubmit USB transfer: " << usb_strerror(ret));
- assert(m_read_transfer == transfer);
-
libusb_free_transfer(transfer);
- m_read_transfer = 0;
send_disconnect();
}
@@ -237,6 +266,11 @@ USBController::on_read_data(libusb_transfer* transfer)
void
USBController::usb_claim_interface(int ifnum, bool try_detach)
{
+ // keep track of all claimed interfaces so they can be released in
+ // the destructor
+ assert(m_interfaces.find(ifnum) == m_interfaces.end());
+ m_interfaces.insert(ifnum);
+
int err = usb_claim_n_detach_interface(m_handle, ifnum, try_detach);
if (err != 0)
{
@@ -247,13 +281,6 @@ USBController::usb_claim_interface(int ifnum, bool try_detach)
}
}
-void
-USBController::usb_release_interface(int ifnum)
-{
- // should be called before closing the device handle
- libusb_release_interface(m_handle, ifnum);
-}
-
int
USBController::usb_find_ep(int direction, uint8_t if_class, uint8_t if_subclass, uint8_t if_protocol)
{
--- a/src/usb_controller.hpp
+++ b/src/usb_controller.hpp
@@ -22,6 +22,7 @@
#include <libusb.h>
#include <string>
#include <memory>
+#include <set>
#include "controller.hpp"
@@ -31,7 +32,8 @@ protected:
libusb_device* m_dev;
libusb_device_handle* m_handle;
- libusb_transfer* m_read_transfer;
+ std::set<libusb_transfer*> m_transfers;
+ std::set<int> m_interfaces;
std::string m_usbpath;
std::string m_usbid;
@@ -50,10 +52,8 @@ public:
int usb_find_ep(int direction, uint8_t if_class, uint8_t if_subclass, uint8_t if_protocol);
void usb_claim_interface(int ifnum, bool try_detach);
- void usb_release_interface(int ifnum);
void usb_submit_read(int endpoint, int len);
- void usb_cancel_read();
void usb_write(int endpoint, uint8_t* data, int len);
void usb_control(uint8_t bmRequestType, uint8_t bRequest,
--- a/src/xbox360_controller.cpp
+++ b/src/xbox360_controller.cpp
@@ -86,8 +86,6 @@ Xbox360Controller::Xbox360Controller(libusb_device* dev,
Xbox360Controller::~Xbox360Controller()
{
- usb_cancel_read();
- usb_release_interface(0);
}
void
--- a/src/xbox360_wireless_controller.cpp
+++ b/src/xbox360_wireless_controller.cpp
@@ -50,8 +50,6 @@ Xbox360WirelessController::Xbox360WirelessController(libusb_device* dev, int con
Xbox360WirelessController::~Xbox360WirelessController()
{
- usb_cancel_read();
- usb_release_interface(m_interface);
}
void
--- a/src/xbox_controller.cpp
+++ b/src/xbox_controller.cpp
@@ -41,8 +41,6 @@ XboxController::XboxController(libusb_device* dev, bool try_detach) :
XboxController::~XboxController()
{
- usb_cancel_read();
- usb_release_interface(0);
}
void