Added controller disconnect handling
This commit is contained in:
parent
f1417511e5
commit
b5bbf48d80
7 changed files with 83 additions and 86 deletions
|
@ -25,6 +25,8 @@
|
|||
|
||||
Controller::Controller() :
|
||||
m_msg_cb(),
|
||||
m_disconnect_cb(),
|
||||
m_is_disconnected(false),
|
||||
m_udev_device()
|
||||
{
|
||||
}
|
||||
|
@ -51,7 +53,7 @@ Controller::set_udev_device(udev_device* udev_dev)
|
|||
}
|
||||
|
||||
void
|
||||
Controller::set_message_cb(boost::function<void(const XboxGenericMsg&)> msg_cb)
|
||||
Controller::set_message_cb(const boost::function<void(const XboxGenericMsg&)>& msg_cb)
|
||||
{
|
||||
m_msg_cb = msg_cb;
|
||||
}
|
||||
|
@ -62,4 +64,23 @@ Controller::get_udev_device() const
|
|||
return m_udev_device;
|
||||
}
|
||||
|
||||
bool
|
||||
Controller::is_disconnected() const
|
||||
{
|
||||
return m_is_disconnected;
|
||||
}
|
||||
|
||||
void
|
||||
Controller::set_disconnect_cb(const boost::function<void ()>& callback)
|
||||
{
|
||||
m_disconnect_cb = callback;
|
||||
}
|
||||
|
||||
void
|
||||
Controller::send_disconnect()
|
||||
{
|
||||
m_is_disconnected = true;
|
||||
m_disconnect_cb();
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -30,8 +30,10 @@ struct XboxGenericMsg;
|
|||
|
||||
class Controller
|
||||
{
|
||||
private:
|
||||
protected:
|
||||
boost::function<void (const XboxGenericMsg&)> m_msg_cb;
|
||||
boost::function<void ()> m_disconnect_cb;
|
||||
bool m_is_disconnected;
|
||||
udev_device* m_udev_device;
|
||||
|
||||
public:
|
||||
|
@ -42,13 +44,17 @@ public:
|
|||
virtual void set_led(uint8_t status) =0;
|
||||
|
||||
virtual bool is_active() const { return true; }
|
||||
virtual void set_activation_cb(const boost::function<void ()> callback) {}
|
||||
virtual void set_activation_cb(const boost::function<void ()>& callback) {}
|
||||
|
||||
virtual bool is_disconnected() const;
|
||||
virtual void set_disconnect_cb(const boost::function<void ()>& callback);
|
||||
virtual void send_disconnect();
|
||||
|
||||
virtual std::string get_usbpath() const { return "-1:-1"; }
|
||||
virtual std::string get_usbid() const { return "-1:-1"; }
|
||||
virtual std::string get_name() const { return "<not implemented>"; }
|
||||
|
||||
void set_message_cb(boost::function<void(const XboxGenericMsg&)> msg_cb);
|
||||
void set_message_cb(const boost::function<void(const XboxGenericMsg&)>& msg_cb);
|
||||
|
||||
void set_udev_device(udev_device* udev_dev);
|
||||
udev_device* get_udev_device() const;
|
||||
|
|
|
@ -78,6 +78,7 @@ USBController::USBController(libusb_device* dev) :
|
|||
|
||||
USBController::~USBController()
|
||||
{
|
||||
log_tmp("~USBController");
|
||||
libusb_close(m_handle);
|
||||
}
|
||||
|
||||
|
@ -189,17 +190,21 @@ USBController::on_write_data(libusb_transfer* transfer)
|
|||
void
|
||||
USBController::usb_cancel_read()
|
||||
{
|
||||
assert(m_read_transfer);
|
||||
libusb_cancel_transfer(m_read_transfer);
|
||||
libusb_free_transfer(m_read_transfer);
|
||||
m_read_transfer = 0;
|
||||
if (m_read_transfer)
|
||||
{
|
||||
libusb_cancel_transfer(m_read_transfer);
|
||||
libusb_free_transfer(m_read_transfer);
|
||||
m_read_transfer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
USBController::on_read_data(libusb_transfer *transfer)
|
||||
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))
|
||||
|
@ -215,11 +220,16 @@ USBController::on_read_data(libusb_transfer *transfer)
|
|||
{
|
||||
int ret;
|
||||
ret = libusb_submit_transfer(transfer);
|
||||
if (ret != LIBUSB_SUCCESS)
|
||||
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);
|
||||
// FIXME: must signal somebody that the controller is no longer usable
|
||||
m_read_transfer = 0;
|
||||
|
||||
send_disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,30 +156,6 @@ XboxdrvDaemon::run()
|
|||
}
|
||||
}
|
||||
|
||||
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::process_match(struct udev_device* device)
|
||||
{
|
||||
|
@ -291,58 +267,12 @@ bool
|
|||
XboxdrvDaemon::on_wakeup()
|
||||
{
|
||||
log_info("got a wakeup call");
|
||||
cleanup_threads();
|
||||
check_thread_status();
|
||||
|
||||
on_controller_disconnect();
|
||||
|
||||
return false; // remove the registered idle callback
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
ControllerSlotPtr
|
||||
XboxdrvDaemon::find_free_slot(udev_device* dev)
|
||||
{
|
||||
|
@ -397,6 +327,8 @@ XboxdrvDaemon::launch_controller_thread(udev_device* udev_dev,
|
|||
{
|
||||
ControllerPtr& controller = *i;
|
||||
|
||||
controller->set_disconnect_cb(boost::bind(&XboxdrvDaemon::wakeup, this));
|
||||
|
||||
// FIXME: Little dirty hack
|
||||
controller->set_udev_device(udev_dev);
|
||||
|
||||
|
@ -529,6 +461,24 @@ XboxdrvDaemon::on_disconnect(ControllerSlotPtr slot)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
XboxdrvDaemon::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())
|
||||
{
|
||||
disconnect(*i); // discard the ControllerPtr
|
||||
}
|
||||
}
|
||||
|
||||
// cleanup inactive controllers
|
||||
m_inactive_controllers.erase(std::remove_if(m_inactive_controllers.begin(), m_inactive_controllers.end(),
|
||||
boost::bind(&Controller::is_disconnected, _1)),
|
||||
m_inactive_controllers.end());
|
||||
}
|
||||
|
||||
void
|
||||
XboxdrvDaemon::wakeup()
|
||||
{
|
||||
|
|
|
@ -68,14 +68,12 @@ private:
|
|||
|
||||
ControllerSlotPtr find_free_slot(udev_device* dev);
|
||||
|
||||
void cleanup_threads();
|
||||
void process_match(struct udev_device* device);
|
||||
void print_info(struct udev_device* device);
|
||||
void launch_controller_thread(udev_device* dev,
|
||||
const XPadDevice& dev_type,
|
||||
uint8_t busnum, uint8_t devnum);
|
||||
int get_free_slot_count() const;
|
||||
void check_thread_status();
|
||||
|
||||
void connect(ControllerSlotPtr slot, ControllerPtr controller);
|
||||
ControllerPtr disconnect(ControllerSlotPtr slot);
|
||||
|
@ -83,6 +81,8 @@ private:
|
|||
void on_connect(ControllerSlotPtr slot);
|
||||
void on_disconnect(ControllerSlotPtr slot);
|
||||
|
||||
void on_controller_disconnect();
|
||||
|
||||
void wakeup();
|
||||
|
||||
private:
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#include "controller_factory.hpp"
|
||||
#include "evdev_controller.hpp"
|
||||
|
@ -132,12 +133,19 @@ XboxdrvMain::init_controller(const ControllerPtr& controller)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
XboxdrvMain::on_controller_disconnect()
|
||||
{
|
||||
shutdown();
|
||||
}
|
||||
|
||||
void
|
||||
XboxdrvMain::run()
|
||||
{
|
||||
USBSubsystem usb_subsystem;
|
||||
|
||||
ControllerPtr controller = create_controller();
|
||||
controller->set_disconnect_cb(boost::bind(&XboxdrvMain::on_controller_disconnect, this));
|
||||
std::auto_ptr<MessageProcessor> message_proc;
|
||||
init_controller(controller);
|
||||
|
||||
|
|
|
@ -71,6 +71,8 @@ private:
|
|||
|
||||
static void on_sigint(int);
|
||||
|
||||
void on_controller_disconnect();
|
||||
|
||||
void on_child_watch(GPid pid, gint status);
|
||||
static void on_child_watch_wrap(GPid pid, gint status, gpointer data) {
|
||||
static_cast<XboxdrvMain*>(data)->on_child_watch(pid, status);
|
||||
|
|
Loading…
Add table
Reference in a new issue