commit 27cdd9c6a994f3059b8ae683adb711169341ffa5 Author: Ingo Ruhnke 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::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::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(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(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(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 #include #include +#include #include "controller.hpp" @@ -31,7 +32,8 @@ protected: libusb_device* m_dev; libusb_device_handle* m_handle; - libusb_transfer* m_read_transfer; + std::set m_transfers; + std::set 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