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