Some more work towards allowing the daemon to use multiple controller slots

This commit is contained in:
Ingo Ruhnke 2011-01-24 04:35:52 +01:00
parent 198f0324b0
commit 71e0cef5c0
13 changed files with 377 additions and 251 deletions

101
TODO
View file

@ -1,4 +1,4 @@
Pre Release Testing:
slPre Release Testing:
=====================
* check the version number
@ -44,54 +44,10 @@ Stuff to do before 0.7.0 release:
* AxisSensitivity filter has overflow issue
* add support for pairing the controller to the PC (or zero)
--ps3-pair 00:00:00:00:00:00
--ps3-pair-with-bluetooth
* Playstation 3 controller support
- http://www.pabr.org/sixlinux/sixlinux.en.html
- http://www.motioninjoy.com/
- figure out what the remaining unknown bits mean:
data from just pluging the controller in and out a few times
without much pause inbetween:
Dualshock3:
// leaving controller plugged in for a longer time settles to this:
00 00 03 ef 16 00 00 00 00 33 fc 77 01 de
00 00 03 ef 16 00 00 00 00 33 fc 77 01 de
00 00 03 ef 16 00 00 00 00 33 fc 77 01 c0
00 00 02 ee 12 00 00 00 00 12 fc 77 01 de
^^^^^ ^^^^^
00 00 01 ee 12 00 00 00 00 12 fc 77 01 de
00 00 03 ef 16 00 00 00 00 11 fc 77 01 de
00 00 03 ef 16 00 00 00 00 33 fc 77 01 de
00 00 02 ee 12 00 00 00 00 12 fc 77 01 de
wrong ideas: bluetooth master id
00 00 01 ef 16 00 00 00 00 11 fc 77 01 c0
00 00 03 ef 16 00 00 00 00 11 fc 77 01 c0
SIXAXIS:
00 00 06 ee 10 00 00 00 00 06 83 77 01 81
00 00 06 ee 10 00 00 00 00 06 83 77 01
00 00 06 ee 10 00 00 00 00 06 83 77
// taken from: http://www.pabr.org/sixlinux/sixlinux.en.html
00 00 02 ee 10 00 00 00 00 02 b2 77 01 81
random guesses: bluetooth id, serial number, calibration data,
battery status
* fix the FIXME's
* fix event output (have it pre-modifier or post-modifier?)
* fix --no-uinput
* need to hide/disable the toggle button from the UIButtonmap
* move XBOX_BTN_UNKNOWN behind XBOX_BTN_MAX, so iteration can start
@ -101,13 +57,20 @@ Stuff to do before 0.7.0 release:
Daemon Related Stuff
====================
* currently device creation fails as all configurations are assigned
to the same virtual device
* improve output on which uinput devices are created
* fix --no-uinput
* uinput must be thread safe
* implement --on-connect and --on-disconnect for the daemon
- maybe have a more general event interface that allows to run stuff
on configuration changes, controller plug-ins, etc. (notifiy area as example)
- also supply useful information as argument
* uinput must be thread safe
* handle multiple controllers in a sane manner (requires cloning of
modifier maps, also auto increment of "auto" device id's)
@ -155,12 +118,52 @@ List Output
1 hal daemon from Thomas Debouverie <debouverie_thomas@yahoo.fr>
1 Implemented --ui-buttonmap A=BTN_A@{device_id} ??!?!?
* improve output on which uinput devices are created
Stuff to do before 0.7.x release:
=================================
* Playstation 3 controller support
- http://www.pabr.org/sixlinux/sixlinux.en.html
- http://www.motioninjoy.com/
- figure out what the remaining unknown bits mean:
data from just pluging the controller in and out a few times
without much pause inbetween:
Dualshock3:
// leaving controller plugged in for a longer time settles to this:
00 00 03 ef 16 00 00 00 00 33 fc 77 01 de
00 00 03 ef 16 00 00 00 00 33 fc 77 01 de
00 00 03 ef 16 00 00 00 00 33 fc 77 01 c0
00 00 02 ee 12 00 00 00 00 12 fc 77 01 de
^^^^^ ^^^^^
00 00 01 ee 12 00 00 00 00 12 fc 77 01 de
00 00 03 ef 16 00 00 00 00 11 fc 77 01 de
00 00 03 ef 16 00 00 00 00 33 fc 77 01 de
00 00 02 ee 12 00 00 00 00 12 fc 77 01 de
wrong ideas: bluetooth master id
00 00 01 ef 16 00 00 00 00 11 fc 77 01 c0
00 00 03 ef 16 00 00 00 00 11 fc 77 01 c0
SIXAXIS:
00 00 06 ee 10 00 00 00 00 06 83 77 01 81
00 00 06 ee 10 00 00 00 00 06 83 77 01
00 00 06 ee 10 00 00 00 00 06 83 77
// taken from: http://www.pabr.org/sixlinux/sixlinux.en.html
00 00 02 ee 10 00 00 00 00 02 b2 77 01 81
random guesses: bluetooth id, serial number, calibration data,
battery status
* add support for pairing the controller to the PC (or zero)
--ps3-pair 00:00:00:00:00:00
--ps3-pair-with-bluetooth
* allow named sections in INI files:
[controller1/modifier]

View file

@ -18,6 +18,175 @@
#include "controller_config_set.hpp"
#include "uinput.hpp"
#include "options.hpp"
#include "log.hpp"
#include "modifier/dpad_rotation_modifier.hpp"
#include "modifier/four_way_restrictor_modifier.hpp"
#include "modifier/square_axis_modifier.hpp"
ControllerConfigSetPtr
ControllerConfigSet::create(uInput& uinput, const Options::ControllerConfigs& opts)
{
ControllerConfigSetPtr m_config(new ControllerConfigSet);
for(Options::ControllerConfigs::const_iterator i = opts.begin();
i != opts.end(); ++i)
{
const ControllerOptions& ctrl_opt = i->second;
ControllerConfigPtr config(new ControllerConfig(uinput, ctrl_opt));
create_modifier(ctrl_opt, &config->get_modifier());
m_config->add_config(config);
#ifdef FIXME
// introspection of the config
std::cout << "==[[ Active Modifier ]]==" << std::endl;
for(std::vector<ModifierPtr>::iterator mod = config->get_modifier().begin();
mod != config->get_modifier().end();
++mod)
{
std::cout << (*mod)->str() << std::endl;
}
#endif
}
log_info << "UInput finish" << std::endl;
// After all the ControllerConfig registered their events, finish up
// the device creation
uinput.finish();
return m_config;
}
void
ControllerConfigSet::create_modifier(const ControllerOptions& opts, std::vector<ModifierPtr>* modifier)
{
if (!opts.calibration_map.empty())
{
boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier);
for(std::map<XboxAxis, AxisFilterPtr>::const_iterator i = opts.calibration_map.begin();
i != opts.calibration_map.end();
++i)
{
axismap->add_filter(i->first, i->second);
}
modifier->push_back(axismap);
}
if (opts.deadzone)
{
boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier);
XboxAxis axes[] = { XBOX_AXIS_X1,
XBOX_AXIS_Y1,
XBOX_AXIS_X2,
XBOX_AXIS_Y2 };
for(size_t i = 0; i < sizeof(axes)/sizeof(XboxAxis); ++i)
{
axismap->add_filter(axes[i],
AxisFilterPtr(new DeadzoneAxisFilter(-opts.deadzone,
opts.deadzone,
true)));
}
modifier->push_back(axismap);
}
if (opts.deadzone_trigger)
{
boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier);
XboxAxis axes[] = { XBOX_AXIS_LT,
XBOX_AXIS_RT };
for(size_t i = 0; i < sizeof(axes)/sizeof(XboxAxis); ++i)
{
axismap->add_filter(axes[i],
AxisFilterPtr(new DeadzoneAxisFilter(-opts.deadzone_trigger,
opts.deadzone_trigger,
true)));
}
modifier->push_back(axismap);
}
if (opts.square_axis)
{
modifier->push_back(ModifierPtr(new SquareAxisModifier(XBOX_AXIS_X1, XBOX_AXIS_Y1)));
modifier->push_back(ModifierPtr(new SquareAxisModifier(XBOX_AXIS_X2, XBOX_AXIS_Y2)));
}
if (!opts.sensitivity_map.empty())
{
boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier);
for(std::map<XboxAxis, AxisFilterPtr>::const_iterator i = opts.sensitivity_map.begin();
i != opts.sensitivity_map.end(); ++i)
{
axismap->add_filter(i->first, i->second);
}
modifier->push_back(axismap);
}
if (opts.four_way_restrictor)
{
modifier->push_back(ModifierPtr(new FourWayRestrictorModifier(XBOX_AXIS_X1, XBOX_AXIS_Y1)));
modifier->push_back(ModifierPtr(new FourWayRestrictorModifier(XBOX_AXIS_X2, XBOX_AXIS_Y2)));
}
if (!opts.relative_axis_map.empty())
{
boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier);
for(std::map<XboxAxis, AxisFilterPtr>::const_iterator i = opts.relative_axis_map.begin();
i != opts.relative_axis_map.end(); ++i)
{
axismap->add_filter(i->first, i->second);
}
modifier->push_back(axismap);
}
if (opts.dpad_rotation)
{
modifier->push_back(ModifierPtr(new DpadRotationModifier(opts.dpad_rotation)));
}
if (!opts.autofire_map.empty())
{
boost::shared_ptr<ButtonmapModifier> buttonmap(new ButtonmapModifier);
for(std::map<XboxButton, ButtonFilterPtr>::const_iterator i = opts.autofire_map.begin();
i != opts.autofire_map.end(); ++i)
{
buttonmap->add_filter(i->first, i->second);
}
modifier->push_back(buttonmap);
}
// axismap, buttonmap comes last, as otherwise they would mess up the button and axis names
if (!opts.buttonmap->empty())
{
modifier->push_back(opts.buttonmap);
}
if (!opts.axismap->empty())
{
modifier->push_back(opts.axismap);
}
modifier->insert(modifier->end(), opts.modifier.begin(), opts.modifier.end());
}
ControllerConfigSet::ControllerConfigSet() :
m_config(),
m_current_config(0)

View file

@ -19,10 +19,26 @@
#ifndef HEADER_XBOXDRV_CONTROLLER_CONFIG_SET_HPP
#define HEADER_XBOXDRV_CONTROLLER_CONFIG_SET_HPP
#include <boost/shared_ptr.hpp>
#include "controller_config.hpp"
#include "options.hpp"
class Options;
class uInput;
class ControllerConfigSet;
typedef boost::shared_ptr<ControllerConfigSet> ControllerConfigSetPtr;
class ControllerConfigSet
{
public:
/** Creates a ControllerConfigSet from the Options object and connects it to uInput */
static ControllerConfigSetPtr create(uInput& uinput, const Options::ControllerConfigs& opts);
private:
static void create_modifier(const ControllerOptions& options, std::vector<ModifierPtr>* modifier);
private:
std::vector<ControllerConfigPtr> m_config;
int m_current_config;

View file

@ -22,186 +22,24 @@
#include "options.hpp"
#include "uinput.hpp"
#include "modifier/dpad_rotation_modifier.hpp"
#include "modifier/four_way_restrictor_modifier.hpp"
#include "modifier/square_axis_modifier.hpp"
DefaultMessageProcessor::DefaultMessageProcessor(uInput& uinput, const Options& opts) :
DefaultMessageProcessor::DefaultMessageProcessor(uInput& uinput, ControllerConfigSetPtr config,
const Options& opts) :
m_uinput(uinput),
m_config(),
m_config(config),
m_oldmsg(),
m_config_toggle_button(opts.config_toggle_button)
{
memset(&m_oldmsg, 0, sizeof(m_oldmsg));
// create ControllerConfigs
for(Options::ControllerSlots::const_iterator controller = opts.controller_slots.begin();
controller != opts.controller_slots.end(); ++controller)
{
for(Options::ControllerConfigs::const_iterator i = controller->second.begin();
i != controller->second.end(); ++i)
{
const ControllerOptions& ctrl_opt = i->second;
ControllerConfigPtr config(new ControllerConfig(uinput, ctrl_opt));
create_modifier(ctrl_opt, &config->get_modifier());
m_config.add_config(config);
#ifdef FIXME
// introspection of the config
std::cout << "==[[ Active Modifier ]]==" << std::endl;
for(std::vector<ModifierPtr>::iterator mod = config->get_modifier().begin();
mod != config->get_modifier().end();
++mod)
{
std::cout << (*mod)->str() << std::endl;
}
#endif
}
}
log_info << "UInput finish" << std::endl;
// After all the ControllerConfig registered their events, finish up
// the device creation
uinput.finish();
}
DefaultMessageProcessor::~DefaultMessageProcessor()
{
}
void
DefaultMessageProcessor::create_modifier(const ControllerOptions& opts, std::vector<ModifierPtr>* modifier)
{
if (!opts.calibration_map.empty())
{
boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier);
for(std::map<XboxAxis, AxisFilterPtr>::const_iterator i = opts.calibration_map.begin();
i != opts.calibration_map.end();
++i)
{
axismap->add_filter(i->first, i->second);
}
modifier->push_back(axismap);
}
if (opts.deadzone)
{
boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier);
XboxAxis axes[] = { XBOX_AXIS_X1,
XBOX_AXIS_Y1,
XBOX_AXIS_X2,
XBOX_AXIS_Y2 };
for(size_t i = 0; i < sizeof(axes)/sizeof(XboxAxis); ++i)
{
axismap->add_filter(axes[i],
AxisFilterPtr(new DeadzoneAxisFilter(-opts.deadzone,
opts.deadzone,
true)));
}
modifier->push_back(axismap);
}
if (opts.deadzone_trigger)
{
boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier);
XboxAxis axes[] = { XBOX_AXIS_LT,
XBOX_AXIS_RT };
for(size_t i = 0; i < sizeof(axes)/sizeof(XboxAxis); ++i)
{
axismap->add_filter(axes[i],
AxisFilterPtr(new DeadzoneAxisFilter(-opts.deadzone_trigger,
opts.deadzone_trigger,
true)));
}
modifier->push_back(axismap);
}
if (opts.square_axis)
{
modifier->push_back(ModifierPtr(new SquareAxisModifier(XBOX_AXIS_X1, XBOX_AXIS_Y1)));
modifier->push_back(ModifierPtr(new SquareAxisModifier(XBOX_AXIS_X2, XBOX_AXIS_Y2)));
}
if (!opts.sensitivity_map.empty())
{
boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier);
for(std::map<XboxAxis, AxisFilterPtr>::const_iterator i = opts.sensitivity_map.begin();
i != opts.sensitivity_map.end(); ++i)
{
axismap->add_filter(i->first, i->second);
}
modifier->push_back(axismap);
}
if (opts.four_way_restrictor)
{
modifier->push_back(ModifierPtr(new FourWayRestrictorModifier(XBOX_AXIS_X1, XBOX_AXIS_Y1)));
modifier->push_back(ModifierPtr(new FourWayRestrictorModifier(XBOX_AXIS_X2, XBOX_AXIS_Y2)));
}
if (!opts.relative_axis_map.empty())
{
boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier);
for(std::map<XboxAxis, AxisFilterPtr>::const_iterator i = opts.relative_axis_map.begin();
i != opts.relative_axis_map.end(); ++i)
{
axismap->add_filter(i->first, i->second);
}
modifier->push_back(axismap);
}
if (opts.dpad_rotation)
{
modifier->push_back(ModifierPtr(new DpadRotationModifier(opts.dpad_rotation)));
}
if (!opts.autofire_map.empty())
{
boost::shared_ptr<ButtonmapModifier> buttonmap(new ButtonmapModifier);
for(std::map<XboxButton, ButtonFilterPtr>::const_iterator i = opts.autofire_map.begin();
i != opts.autofire_map.end(); ++i)
{
buttonmap->add_filter(i->first, i->second);
}
modifier->push_back(buttonmap);
}
// axismap, buttonmap comes last, as otherwise they would mess up the button and axis names
if (!opts.buttonmap->empty())
{
modifier->push_back(opts.buttonmap);
}
if (!opts.axismap->empty())
{
modifier->push_back(opts.axismap);
}
modifier->insert(modifier->end(), opts.modifier.begin(), opts.modifier.end());
}
void
DefaultMessageProcessor::send(const XboxGenericMsg& msg_in, int msec_delta)
{
if (!m_config.empty())
if (!m_config->empty())
{
XboxGenericMsg msg = msg_in;
@ -214,24 +52,24 @@ DefaultMessageProcessor::send(const XboxGenericMsg& msg_in, int msec_delta)
if (cur && cur != last)
{
// reset old mapping to zero to not get stuck keys/axis
m_config.get_config()->get_uinput().reset_all_outputs();
m_config->get_config()->get_uinput().reset_all_outputs();
// switch to the next input mapping
m_config.next_config();
m_config->next_config();
log_info << "Next Config" << std::endl;
}
}
// run the controller message through all modifier
for(std::vector<ModifierPtr>::iterator i = m_config.get_config()->get_modifier().begin();
i != m_config.get_config()->get_modifier().end();
for(std::vector<ModifierPtr>::iterator i = m_config->get_config()->get_modifier().begin();
i != m_config->get_config()->get_modifier().end();
++i)
{
(*i)->update(msec_delta, msg);
}
m_config.get_config()->get_uinput().update(msec_delta);
m_config->get_config()->get_uinput().update(msec_delta);
// send current Xbox state to uinput
if (memcmp(&msg, &m_oldmsg, sizeof(XboxGenericMsg)) != 0)
@ -242,7 +80,7 @@ DefaultMessageProcessor::send(const XboxGenericMsg& msg_in, int msec_delta)
// too
m_oldmsg = msg;
m_config.get_config()->get_uinput().send(msg);
m_config->get_config()->get_uinput().send(msg);
}
}
}

View file

@ -32,20 +32,18 @@ class DefaultMessageProcessor : public MessageProcessor
{
private:
uInput& m_uinput;
ControllerConfigSet m_config;
ControllerConfigSetPtr m_config;
XboxGenericMsg m_oldmsg; /// last data send to uinput
XboxButton m_config_toggle_button;
public:
DefaultMessageProcessor(uInput& uinput, const Options& opts);
DefaultMessageProcessor(uInput& uinput, ControllerConfigSetPtr config,
const Options& opts);
~DefaultMessageProcessor();
void send(const XboxGenericMsg& msg, int msec_delta);
private:
void create_modifier(const ControllerOptions& options, std::vector<ModifierPtr>* modifier);
private:
DefaultMessageProcessor(const DefaultMessageProcessor&);
DefaultMessageProcessor& operator=(const DefaultMessageProcessor&);

View file

@ -24,6 +24,8 @@
#include <errno.h>
#include <fcntl.h>
#include "evdev_helper.hpp"
#include "log.hpp"
#include "force_feedback_handler.hpp"
LinuxUinput::LinuxUinput(DeviceType device_type, const std::string& name_, uint16_t vendor_, uint16_t product_) :
@ -42,6 +44,8 @@ LinuxUinput::LinuxUinput(DeviceType device_type, const std::string& name_, uint1
ff_callback(),
needs_sync(true)
{
log_info << name << " " << vendor << ":" << product << std::endl;
std::fill_n(abs_lst, ABS_CNT, false);
std::fill_n(rel_lst, REL_CNT, false);
std::fill_n(key_lst, KEY_CNT, false);
@ -93,7 +97,7 @@ LinuxUinput::~LinuxUinput()
void
LinuxUinput::add_abs(uint16_t code, int min, int max, int fuzz, int flat)
{
// std::cout << "add_abs: " << abs2str(code) << " (" << min << ", " << max << ") " << name << std::endl;
log_info << "add_abs: " << abs2str(code) << " (" << min << ", " << max << ") " << name << std::endl;
if (!abs_lst[code])
{
@ -117,7 +121,7 @@ LinuxUinput::add_abs(uint16_t code, int min, int max, int fuzz, int flat)
void
LinuxUinput::add_rel(uint16_t code)
{
// std::cout << "add_rel: " << rel2str(code) << " " << name << std::endl;
log_info << "add_rel: " << rel2str(code) << " " << name << std::endl;
if (!rel_lst[code])
{
@ -136,7 +140,7 @@ LinuxUinput::add_rel(uint16_t code)
void
LinuxUinput::add_key(uint16_t code)
{
// std::cout << "add_key: " << btn2str(code) << " " << name << std::endl;
log_info << "add_key: " << key2str(code) << " " << name << std::endl;
if (!key_lst[code])
{
@ -220,14 +224,26 @@ LinuxUinput::finish()
user_dev.id.vendor = vendor;
user_dev.id.product = product;
log_info << "'" << user_dev.name << "' " << user_dev.id.vendor << ":" << user_dev.id.product << std::endl;
if (ff_bit)
user_dev.ff_effects_max = ff_handler->get_max_effects();
//std::cout << "Finalizing uinput: '" << user_dev.name << "'" << std::endl;
if (write(fd, &user_dev, sizeof(user_dev)) < 0)
throw std::runtime_error("uinput:finish: " + name + ": " + strerror(errno));
{
int write_ret = write(fd, &user_dev, sizeof(user_dev));
if (write_ret < 0)
{
throw std::runtime_error("uinput:finish: " + name + ": " + strerror(errno));
}
else
{
log_info << "write return value: " << write_ret << std::endl;
}
}
log_info << "finish" << std::endl;
if (ioctl(fd, UI_DEV_CREATE))
{
std::ostringstream out;

View file

@ -92,6 +92,20 @@ Options::get_controller_slot()
return controller_slots[controller_slot];
}
const Options::ControllerConfigs&
Options::get_controller_slot() const
{
ControllerSlots::const_iterator it = controller_slots.find(controller_slot);
if (it == controller_slots.end())
{
assert(!"shouldn't happen");
}
else
{
return it->second;
}
}
ControllerOptions&
Options::get_controller_options()
{

View file

@ -146,6 +146,7 @@ public:
Options();
ControllerConfigs& get_controller_slot();
const ControllerConfigs& get_controller_slot() const;
/** Returns the currently active configuration */
ControllerOptions& get_controller_options();

View file

@ -42,7 +42,7 @@ Xbox360Controller::Xbox360Controller(libusb_device* dev_,
m_headset()
{
find_endpoints();
if (true) // FIXME
if (false)
{
std::cout << "EP(IN): " << endpoint_in << std::endl;
std::cout << "EP(OUT): " << endpoint_out << std::endl;
@ -207,7 +207,7 @@ Xbox360Controller::read(XboxGenericMsg& msg, bool verbose, int timeout)
else if (ret != LIBUSB_SUCCESS)
{ // Error
std::ostringstream str;
str << "Xbox360Controller: USBError: " << ret << "\n" << usb_strerror(ret);
str << "Xbox360Controller: libusb_interrupt_transfer(): " << usb_strerror(ret);
throw std::runtime_error(str.str());
}
else if (len == 0)

View file

@ -463,7 +463,8 @@ Xboxdrv::run_main(const Options& opts)
global_exit_xboxdrv = false;
std::auto_ptr<MessageProcessor> message_proc(new DefaultMessageProcessor(*uinput, opts));
ControllerConfigSetPtr config_set = ControllerConfigSet::create(*uinput, opts.get_controller_slot());
std::auto_ptr<MessageProcessor> message_proc(new DefaultMessageProcessor(*uinput, config_set, opts));
XboxdrvThread loop(message_proc, controller, opts);
loop.controller_loop(opts);

View file

@ -33,7 +33,7 @@ extern bool global_exit_xboxdrv;
XboxdrvDaemon::XboxdrvDaemon() :
m_udev(0),
m_monitor(0),
m_threads()
m_controller_slots()
{
m_udev = udev_new();
@ -49,9 +49,10 @@ XboxdrvDaemon::XboxdrvDaemon() :
XboxdrvDaemon::~XboxdrvDaemon()
{
for(Threads::iterator i = m_threads.begin(); i != m_threads.end(); ++i)
for(ControllerSlots::iterator i = m_controller_slots.begin(); i != m_controller_slots.end(); ++i)
{
delete *i;
delete i->thread;
i->thread = 0;
}
udev_monitor_unref(m_monitor);
@ -61,13 +62,20 @@ XboxdrvDaemon::~XboxdrvDaemon()
void
XboxdrvDaemon::cleanup_threads()
{
size_t num_threads = m_threads.size();
m_threads.erase(std::remove_if(m_threads.begin(), m_threads.end(),
boost::bind(&XboxdrvThread::try_join_thread, _1)),
m_threads.end());
if (num_threads != m_threads.size())
int count = 0;
for(ControllerSlots::iterator i = m_controller_slots.begin(); i != m_controller_slots.end(); ++i)
{
log_info << "cleaned up " << (num_threads - m_threads.size()) << " thread(s)" << std::endl;
if (i->thread)
{
i->thread->try_join_thread();
count += 1;
}
}
if (count > 0)
{
log_info << "cleaned up " << count << " thread(s)" << std::endl;
}
}
@ -173,6 +181,20 @@ XboxdrvDaemon::run(const Options& opts)
std::cout << "Starting without uinput" << std::endl;
}
{ // create controller slots
int slot_count = 0;
for(Options::ControllerSlots::const_iterator controller = opts.controller_slots.begin();
controller != opts.controller_slots.end(); ++controller)
{
log_info << "creating slot: " << slot_count << std::endl;
m_controller_slots.push_back(ControllerSlot(ControllerConfigSet::create(*uinput, controller->second)));
slot_count += 1;
}
log_info << "created " << m_controller_slots.size() << " controller slots" << std::endl;
}
// Setup udev monitor and enumerate
m_monitor = udev_monitor_new_from_netlink(m_udev, "udev");
udev_monitor_filter_add_match_subsystem_devtype(m_monitor, "usb", "usb_device");
@ -312,7 +334,8 @@ XboxdrvDaemon::print_info(struct udev_device* device)
}
void
XboxdrvDaemon::launch_xboxdrv(uInput* uinput, const XPadDevice& dev_type, const Options& opts, uint8_t busnum, uint8_t devnum)
XboxdrvDaemon::launch_xboxdrv(uInput* uinput, const XPadDevice& dev_type, const Options& opts,
uint8_t busnum, uint8_t devnum)
{
std::cout << "[XboxdrvDaemon] launching " << boost::format("%03d:%03d")
% static_cast<int>(busnum)
@ -328,11 +351,20 @@ XboxdrvDaemon::launch_xboxdrv(uInput* uinput, const XPadDevice& dev_type, const
}
else
{
std::auto_ptr<XboxGenericController> controller = XboxControllerFactory::create(dev_type, dev, opts);
std::auto_ptr<MessageProcessor> message_proc(new DefaultMessageProcessor(*uinput, opts));
std::auto_ptr<XboxdrvThread> thread(new XboxdrvThread(message_proc, controller, opts));
thread->start_thread(opts);
m_threads.push_back(thread.release());
for(ControllerSlots::iterator i = m_controller_slots.begin(); i != m_controller_slots.end(); ++i)
{
if (i->thread == 0)
{
log_info << "found a free slot: " << (i - m_controller_slots.begin()) << std::endl;
std::auto_ptr<XboxGenericController> controller = XboxControllerFactory::create(dev_type, dev, opts);
std::auto_ptr<MessageProcessor> message_proc(new DefaultMessageProcessor(*uinput, i->config, opts));
std::auto_ptr<XboxdrvThread> thread(new XboxdrvThread(message_proc, controller, opts));
thread->start_thread(opts);
i->thread = thread.release();
break;
}
}
}
}

View file

@ -23,6 +23,8 @@
#include <stdint.h>
#include <vector>
#include "controller_config_set.hpp"
class Options;
class uInput;
struct XPadDevice;
@ -33,8 +35,41 @@ class XboxdrvDaemon
private:
struct udev* m_udev;
struct udev_monitor* m_monitor;
typedef std::vector<XboxdrvThread*> Threads;
Threads m_threads;
struct ControllerSlot
{
ControllerConfigSetPtr config;
XboxdrvThread* thread;
ControllerSlot() :
config(),
thread(0)
{}
ControllerSlot(ControllerConfigSetPtr config_,
XboxdrvThread* thread_ = 0) :
config(config_),
thread(thread_)
{}
ControllerSlot(const ControllerSlot& rhs) :
config(rhs.config),
thread(rhs.thread)
{}
ControllerSlot& operator=(const ControllerSlot& rhs)
{
if (&rhs != this)
{
config = rhs.config;
thread = rhs.thread;
}
return *this;
}
};
typedef std::vector<ControllerSlot> ControllerSlots;
ControllerSlots m_controller_slots;
public:
XboxdrvDaemon();

View file

@ -30,6 +30,9 @@ class Options;
class XboxGenericController;
class MessageProcessor;
/** XboxdrvThread handles a single XboxGenericController controller
(optionally in a separate thread), reads it messages and passes it
to the MessageProcessor */
class XboxdrvThread // FIXME: find a better name, XboxdrvControllerLoop?!
{
private: