From be39c5db495927095390462887b30fe2dd93ca21 Mon Sep 17 00:00:00 2001 From: Ingo Ruhnke Date: Mon, 23 May 2011 14:38:12 +0200 Subject: [PATCH] Fixed issues with Controller activation, moved activation code into Controller --- src/controller.cpp | 22 +++++++ src/controller.hpp | 13 +++- src/xbox360_wireless_controller.cpp | 27 ++------ src/xbox360_wireless_controller.hpp | 8 --- src/xboxdrv_daemon.cpp | 96 ++++++++++++++++++++++++----- src/xboxdrv_daemon.hpp | 15 +++-- 6 files changed, 129 insertions(+), 52 deletions(-) diff --git a/src/controller.cpp b/src/controller.cpp index e32c8fc..28c0c5f 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -26,7 +26,9 @@ Controller::Controller() : m_msg_cb(), m_disconnect_cb(), + m_activation_cb(), m_is_disconnected(false), + m_is_active(true), m_udev_device() { } @@ -64,6 +66,26 @@ Controller::get_udev_device() const return m_udev_device; } +void +Controller::set_active(bool v) +{ + if (m_is_active != v) + { + log_debug("activation status: " << v << " " << m_activation_cb); + m_is_active = v; + if (m_activation_cb) + { + m_activation_cb(); + } + } +} + +void +Controller::set_activation_cb(const boost::function& callback) +{ + m_activation_cb = callback; +} + bool Controller::is_disconnected() const { diff --git a/src/controller.hpp b/src/controller.hpp index b69d53f..58258f4 100644 --- a/src/controller.hpp +++ b/src/controller.hpp @@ -33,7 +33,9 @@ class Controller protected: boost::function m_msg_cb; boost::function m_disconnect_cb; + boost::function m_activation_cb; bool m_is_disconnected; + bool m_is_active; udev_device* m_udev_device; public: @@ -43,9 +45,16 @@ public: virtual void set_rumble(uint8_t left, uint8_t right) =0; virtual void set_led(uint8_t status) =0; - virtual bool is_active() const { return true; } - virtual void set_activation_cb(const boost::function& callback) {} + /** Wireless Controller start out inactive when they are not synced + with their receiver and become active after the sync. Regular + USB controller are always active. Active controllers can become + inactive and vice versa. */ + virtual bool is_active() const { return m_is_active; } + virtual void set_active(bool v); + virtual void set_activation_cb(const boost::function& callback); + /** Controllers with a disconnect status have been unplugged and are + not coming back, thus the Controller object can be destroyed */ virtual bool is_disconnected() const; virtual void set_disconnect_cb(const boost::function& callback); virtual void send_disconnect(); diff --git a/src/xbox360_wireless_controller.cpp b/src/xbox360_wireless_controller.cpp index 014b1db..5a3e1fc 100644 --- a/src/xbox360_wireless_controller.cpp +++ b/src/xbox360_wireless_controller.cpp @@ -30,14 +30,15 @@ Xbox360WirelessController::Xbox360WirelessController(libusb_device* dev, int controller_id, bool try_detach) : USBController(dev), - m_active(false), m_endpoint(), m_interface(), m_battery_status(), m_serial(), - m_led_status(0), - m_activation_cb() + m_led_status(0) { + // FIXME: A little bit of a hack + m_is_active = false; + assert(controller_id >= 0 && controller_id < 4); // FIXME: Is hardcoding those ok? @@ -200,24 +201,4 @@ Xbox360WirelessController::parse(uint8_t* data, int len, XboxGenericMsg* msg_out return false; } -void -Xbox360WirelessController::set_active(bool v) -{ - if (m_active != v) - { - log_debug("activation status: " << v); - m_active = v; - if (m_activation_cb) - { - m_activation_cb(); - } - } -} - -void -Xbox360WirelessController::set_activation_cb(const boost::function callback) -{ - m_activation_cb = callback; -} - /* EOF */ diff --git a/src/xbox360_wireless_controller.hpp b/src/xbox360_wireless_controller.hpp index f72bfda..13c8706 100644 --- a/src/xbox360_wireless_controller.hpp +++ b/src/xbox360_wireless_controller.hpp @@ -30,15 +30,12 @@ struct XPadDevice; class Xbox360WirelessController : public USBController { private: - bool m_active; int m_endpoint; int m_interface; int m_battery_status; std::string m_serial; int m_led_status; - boost::function m_activation_cb; - public: Xbox360WirelessController(libusb_device* dev, int controller_id, bool try_detach); virtual ~Xbox360WirelessController(); @@ -48,12 +45,7 @@ public: void set_rumble(uint8_t left, uint8_t right); void set_led(uint8_t status); uint8_t get_battery_status() const; - bool is_active() const { return m_active; } - void set_activation_cb(const boost::function callback); -private: - void set_active(bool v); - private: Xbox360WirelessController (const Xbox360WirelessController&); Xbox360WirelessController& operator= (const Xbox360WirelessController&); diff --git a/src/xboxdrv_daemon.cpp b/src/xboxdrv_daemon.cpp index 0f87cc5..3f4fd2e 100644 --- a/src/xboxdrv_daemon.cpp +++ b/src/xboxdrv_daemon.cpp @@ -268,16 +268,6 @@ XboxdrvDaemon::create_pid_file() } } -bool -XboxdrvDaemon::on_wakeup() -{ - log_info("got a wakeup call"); - - on_controller_disconnect(); - - return false; // remove the registered idle callback -} - ControllerSlotPtr XboxdrvDaemon::find_free_slot(udev_device* dev) { @@ -332,7 +322,8 @@ XboxdrvDaemon::launch_controller_thread(udev_device* udev_dev, { ControllerPtr& controller = *i; - controller->set_disconnect_cb(boost::bind(&XboxdrvDaemon::wakeup, this)); + controller->set_disconnect_cb(boost::bind(&g_idle_add, &XboxdrvDaemon::on_controller_disconnect_wrap, this)); + controller->set_activation_cb(boost::bind(&g_idle_add, &XboxdrvDaemon::on_controller_activate_wrap, this)); // FIXME: Little dirty hack controller->set_udev_device(udev_dev); @@ -358,7 +349,6 @@ XboxdrvDaemon::launch_controller_thread(udev_device* udev_dev, } else // if (!controller->is_active()) { - controller->set_activation_cb(boost::bind(&XboxdrvDaemon::wakeup, this)); m_inactive_controllers.push_back(controller); } } @@ -469,10 +459,12 @@ XboxdrvDaemon::on_disconnect(ControllerSlotPtr slot) void XboxdrvDaemon::on_controller_disconnect() { + log_tmp("on_controller_disconnect"); + // cleanup active controllers in slots for(ControllerSlots::iterator i = m_controller_slots.begin(); i != m_controller_slots.end(); ++i) { - if ((*i)->get_controller()->is_disconnected()) + if ((*i)->get_controller() && (*i)->get_controller()->is_disconnected()) { disconnect(*i); // discard the ControllerPtr } @@ -485,9 +477,12 @@ XboxdrvDaemon::on_controller_disconnect() } void -XboxdrvDaemon::wakeup() +XboxdrvDaemon::on_controller_activate() { - g_idle_add(&XboxdrvDaemon::on_wakeup_wrap, this); + log_tmp("on_controller_activate"); + + cleanup_threads(); + check_thread_status(); } std::string @@ -541,4 +536,75 @@ XboxdrvDaemon::on_sigint(int) XboxdrvDaemon::current()->shutdown(); } +void +XboxdrvDaemon::cleanup_threads() +{ + int count = 0; + + for(ControllerSlots::iterator i = m_controller_slots.begin(); i != m_controller_slots.end(); ++i) + { + if ((*i)->is_connected()) + { + count += 1; + on_disconnect(*i); + + // disconnect slot and put the controller back into the inactive group + m_inactive_controllers.push_back((*i)->disconnect()); + } + } + + if (count > 0) + { + log_info("cleaned up " << count << " thread(s), free slots: " << + get_free_slot_count() << "/" << m_controller_slots.size()); + } +} + +void +XboxdrvDaemon::check_thread_status() +{ + // check for inactive controller and free the slots + for(ControllerSlots::iterator i = m_controller_slots.begin(); i != m_controller_slots.end(); ++i) + { + // if a slot contains an inactive controller, disconnect it and save + // the controller for later when it might be active again + if ((*i)->get_controller() && !(*i)->get_controller()->is_active()) + { + ControllerPtr controller = disconnect(*i); + m_inactive_controllers.push_back(controller); + } + } + + // check for activated controller and connect them to a slot + for(Controllers::iterator i = m_inactive_controllers.begin(); i != m_inactive_controllers.end(); ++i) + { + if (!*i) + { + log_error("NULL in m_inactive_controllers, shouldn't happen"); + } + else + { + if ((*i)->is_active()) + { + ControllerSlotPtr slot = find_free_slot((*i)->get_udev_device()); + if (!slot) + { + log_info("couldn't find a free slot for activated controller"); + } + else + { + connect(slot, *i); + + // successfully connected the controller, so set it to NULL and cleanup later + *i = ControllerPtr(); + } + } + } + } + + // cleanup inactive controller + m_inactive_controllers.erase(std::remove(m_inactive_controllers.begin(), m_inactive_controllers.end(), ControllerPtr()), + m_inactive_controllers.end()); +} + /* EOF */ diff --git a/src/xboxdrv_daemon.hpp b/src/xboxdrv_daemon.hpp index e01aebe..206f232 100644 --- a/src/xboxdrv_daemon.hpp +++ b/src/xboxdrv_daemon.hpp @@ -82,13 +82,20 @@ private: void on_disconnect(ControllerSlotPtr slot); void on_controller_disconnect(); + void on_controller_activate(); - void wakeup(); + void check_thread_status(); + void cleanup_threads(); private: - bool on_wakeup(); - static gboolean on_wakeup_wrap(gpointer data) { - return static_cast(data)->on_wakeup(); + static gboolean on_controller_disconnect_wrap(gpointer data) { + static_cast(data)->on_controller_disconnect(); + return false; + } + + static gboolean on_controller_activate_wrap(gpointer data) { + static_cast(data)->on_controller_activate(); + return false; } private: