Added additional bookkeeping to USBController to allow clean shutdowns with libusbx

Fixes 
This commit is contained in:
Ingo Ruhnke 2012-12-19 11:39:31 +01:00
parent d9d6dfbf89
commit 27cdd9c6a9
9 changed files with 72 additions and 59 deletions

View file

@ -99,8 +99,6 @@ FirestormDualController::FirestormDualController(libusb_device* dev, bool is_vsb
FirestormDualController::~FirestormDualController()
{
usb_cancel_read();
usb_release_interface(0);
}
void

View file

@ -62,8 +62,6 @@ GenericUSBController::GenericUSBController(libusb_device* dev,
GenericUSBController::~GenericUSBController()
{
usb_cancel_read();
usb_release_interface(m_interface);
}
void

View file

@ -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

View file

@ -66,8 +66,6 @@ SaitekP2500Controller::SaitekP2500Controller(libusb_device* dev, bool try_detach
SaitekP2500Controller::~SaitekP2500Controller()
{
usb_cancel_read();
usb_release_interface(0);
}
void

View file

@ -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)
{

View file

@ -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,

View file

@ -86,8 +86,6 @@ Xbox360Controller::Xbox360Controller(libusb_device* dev,
Xbox360Controller::~Xbox360Controller()
{
usb_cancel_read();
usb_release_interface(0);
}
void

View file

@ -50,8 +50,6 @@ Xbox360WirelessController::Xbox360WirelessController(libusb_device* dev, int con
Xbox360WirelessController::~Xbox360WirelessController()
{
usb_cancel_read();
usb_release_interface(m_interface);
}
void

View file

@ -41,8 +41,6 @@ XboxController::XboxController(libusb_device* dev, bool try_detach) :
XboxController::~XboxController()
{
usb_cancel_read();
usb_release_interface(0);
}
void