Added hotplug support to "xboxdrv --daemon" via libudev

This commit is contained in:
Ingo Ruhnke 2011-01-14 19:04:25 +01:00
parent 52de13c105
commit e977466574
17 changed files with 461 additions and 130 deletions

6
TODO
View file

@ -16,6 +16,8 @@ git push --tags
Ubuntu Package:
===============
add libudev, libusb-1.0 to builddependencies
# Ubuntu 10.10
$ cd ../debian/
@ -40,6 +42,10 @@ $ dput my-ppa ../xboxdrv_0.6.4-2~lucid1_source.changes
Stuff to do before 0.6.5 release:
=================================
* uinput must be made threadsafe
* write/recycle a proper logging class
* improve output on which uinput devices are created
* add --list-keys --list-x11-keys --list-abs --list-rel --list-button --list-axis etc.

42
src/log.cpp Normal file
View file

@ -0,0 +1,42 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "log.hpp"
#include <sstream>
std::string log_pretty_print(const std::string& str)
{
// FIXME: very basic, might not work with complex return types
std::string::size_type function_start = 0;
for(std::string::size_type i = 0; i < str.size(); ++i)
{
if (str[i] == ' ')
{
function_start = i+1;
}
else if (str[i] == '(')
{
return str.substr(function_start, i - function_start) + "()";
}
}
return str.substr(function_start);
}
/* EOF */

44
src/log.hpp Normal file
View file

@ -0,0 +1,44 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HEADER_XBOXDRV_LOG_HPP
#define HEADER_XBOXDRV_LOG_HPP
#include <iostream>
/** Takes __PRETTY_FUNCTION__ and tries to shorten it to the form:
Classname::function() */
std::string log_pretty_print(const std::string& str);
/** informal status messages that don't indicate a fault in the
program */
#define log_info (std::cout << log_pretty_print(__PRETTY_FUNCTION__) << ": ")
/** messages that indicate an recoverable error (i.e. a catched
exceptions) */
#define log_warning (std::cout << log_pretty_print(__PRETTY_FUNCTION__) << ": ")
/** things that shouldn't happen (i.e. a catched exceptions) */
#define log_error (std::cout << log_pretty_print(__PRETTY_FUNCTION__) << ": ")
/** extra verbose debugging messages */
#define log_debug (std::cout << log_pretty_print(__PRETTY_FUNCTION__) << ": ")
#endif
/* EOF */

View file

@ -45,7 +45,7 @@ uInput::is_keyboard_button(int ev_code)
return (ev_code < 256);
}
uInput::uInput(GamepadType type, int vendor_id, int product_id, uInputCfg config_) :
uInput::uInput(int vendor_id, int product_id, uInputCfg config_) :
m_vendor_id(vendor_id),
m_product_id(product_id),
uinput_devs(),

View file

@ -66,7 +66,7 @@ public:
static bool is_keyboard_button(int ev_code);
public:
uInput(GamepadType type, int vendor_id, int product_id, uInputCfg cfg = uInputCfg());
uInput(int vendor_id, int product_id, uInputCfg cfg = uInputCfg());
~uInput();
void send(XboxGenericMsg& msg);

View file

@ -74,4 +74,27 @@ const char* usb_strerror(int err)
}
}
libusb_device* usb_find_device_by_path(uint8_t busnum, uint8_t devnum)
{
libusb_device* ret_device = 0;
libusb_device** list;
ssize_t num_devices = libusb_get_device_list(NULL, &list);
for(ssize_t dev_it = 0; dev_it < num_devices; ++dev_it)
{
libusb_device* dev = list[dev_it];
if (busnum == libusb_get_bus_number(dev) &&
devnum == libusb_get_device_address(dev))
{
ret_device = dev;
libusb_ref_device(ret_device);
break;
}
}
libusb_free_device_list(list, 1 /* unref_devices */);
return ret_device;
}
/* EOF */

View file

@ -19,8 +19,11 @@
#ifndef HEADER_XBOXDRV_USB_HELPER_HPP
#define HEADER_XBOXDRV_USB_HELPER_HPP
#include <libusb.h>
int usb_claim_n_detach_interface(struct libusb_device_handle* handle, int interface, bool try_detach);
const char* usb_strerror(int err);
libusb_device* usb_find_device_by_path(uint8_t busnum, uint8_t devnum);
#endif

View file

@ -0,0 +1,74 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "xbox_controller_factory.hpp"
#include <stdexcept>
#include "options.hpp"
#include "xbox360_controller.hpp"
#include "xbox360_wireless_controller.hpp"
#include "saitek_p2500_controller.hpp"
#include "firestorm_dual_controller.hpp"
#include "xbox_controller.hpp"
std::auto_ptr<XboxGenericController>
XboxControllerFactory::create(const XPadDevice& dev_type, libusb_device* dev, const Options& opts)
{
switch (dev_type.type)
{
case GAMEPAD_XBOX360_PLAY_N_CHARGE:
throw std::runtime_error("The Xbox360 Play&Charge cable is for recharging only, it does not transmit data, "
"thus xboxdrv can't support it. You have to get a wireless receiver:\n"
"\n"
" * http://www.xbox.com/en-ca/hardware/x/xbox360wirelessgamingreceiver/");
break;
case GAMEPAD_XBOX:
case GAMEPAD_XBOX_MAT:
return std::auto_ptr<XboxGenericController>(new XboxController(dev, opts.detach_kernel_driver));
case GAMEPAD_XBOX360:
case GAMEPAD_XBOX360_GUITAR:
return std::auto_ptr<XboxGenericController>(new Xbox360Controller(dev,
opts.chatpad, opts.chatpad_no_init, opts.chatpad_debug,
opts.headset,
opts.headset_debug,
opts.headset_dump,
opts.headset_play,
opts.detach_kernel_driver));
break;
case GAMEPAD_XBOX360_WIRELESS:
return std::auto_ptr<XboxGenericController>(new Xbox360WirelessController(dev, opts.wireless_id, opts.detach_kernel_driver));
case GAMEPAD_FIRESTORM:
return std::auto_ptr<XboxGenericController>(new FirestormDualController(dev, false, opts.detach_kernel_driver));
case GAMEPAD_FIRESTORM_VSB:
return std::auto_ptr<XboxGenericController>(new FirestormDualController(dev, true, opts.detach_kernel_driver));
case GAMEPAD_SAITEK_P2500:
return std::auto_ptr<XboxGenericController>(new SaitekP2500Controller(dev, opts.detach_kernel_driver));
default:
assert(!"Unknown gamepad type");
}
}
/* EOF */

View file

@ -0,0 +1,44 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HEADER_XBOXDRV_XBOX_CONTROLLER_FACTORY_HPP
#define HEADER_XBOXDRV_XBOX_CONTROLLER_FACTORY_HPP
#include <memory>
#include <libusb.h>
#include "xpad_device.hpp"
#include "options.hpp"
class XboxGenericController;
class XboxControllerFactory
{
public:
static std::auto_ptr<XboxGenericController> create(const XPadDevice& dev_type,
libusb_device* dev,
const Options& opts);
private:
XboxControllerFactory(const XboxControllerFactory&);
XboxControllerFactory& operator=(const XboxControllerFactory&);
};
#endif
/* EOF */

View file

@ -40,15 +40,11 @@
#include "command_line_options.hpp"
#include "evdev_controller.hpp"
#include "evdev_helper.hpp"
#include "firestorm_dual_controller.hpp"
#include "helper.hpp"
#include "options.hpp"
#include "saitek_p2500_controller.hpp"
#include "uinput.hpp"
#include "xbox360_controller.hpp"
#include "xbox360_wireless_controller.hpp"
#include "xbox_controller.hpp"
#include "xbox_generic_controller.hpp"
#include "xbox_controller_factory.hpp"
#include "xboxdrv_daemon.hpp"
#include "xboxdrv_thread.hpp"
#include "xboxmsg.hpp"
@ -90,14 +86,14 @@ void on_sigterm(int)
void
Xboxdrv::run_list_controller()
{
int ret = libusb_init(&m_libusb_ctx);
int ret = libusb_init(NULL);
if (ret != LIBUSB_SUCCESS)
{
throw std::runtime_error("-- failure --"); // FIXME
}
libusb_device** list;
ssize_t num_devices = libusb_get_device_list(m_libusb_ctx, &list);
ssize_t num_devices = libusb_get_device_list(NULL, &list);
int id = 0;
std::cout << " id | wid | idVendor | idProduct | Name" << std::endl;
@ -160,7 +156,7 @@ Xboxdrv::find_controller_by_path(const std::string& busid_str, const std::string
int devid = boost::lexical_cast<int>(devid_str);
libusb_device** list;
ssize_t num_devices = libusb_get_device_list(m_libusb_ctx, &list);
ssize_t num_devices = libusb_get_device_list(NULL, &list);
for(ssize_t dev_it = 0; dev_it < num_devices; ++dev_it)
{
@ -218,7 +214,7 @@ bool
Xboxdrv::find_controller_by_id(int id, int vendor_id, int product_id, libusb_device** xbox_device) const
{
libusb_device** list;
ssize_t num_devices = libusb_get_device_list(m_libusb_ctx, &list);
ssize_t num_devices = libusb_get_device_list(NULL, &list);
int id_count = 0;
for(ssize_t dev_it = 0; dev_it < num_devices; ++dev_it)
@ -256,7 +252,7 @@ bool
Xboxdrv::find_xbox360_controller(int id, libusb_device** xbox_device, XPadDevice* type) const
{
libusb_device** list;
ssize_t num_devices = libusb_get_device_list(m_libusb_ctx, &list);
ssize_t num_devices = libusb_get_device_list(NULL, &list);
int id_count = 0;
for(ssize_t dev_it = 0; dev_it < num_devices; ++dev_it)
@ -390,7 +386,7 @@ Xboxdrv::run_main(const Options& opts)
std::auto_ptr<XboxGenericController> controller;
XPadDevice dev_type;
XPadDevice dev_type;
if (!opts.evdev_device.empty())
{ // normal PC joystick via evdev
@ -408,13 +404,14 @@ Xboxdrv::run_main(const Options& opts)
}
else
{ // regular USB Xbox360 controller
int ret = libusb_init(&m_libusb_ctx);
int ret = libusb_init(NULL);
if (ret != LIBUSB_SUCCESS)
{
throw std::runtime_error("-- failure --"); // FIXME
}
libusb_device* dev = 0; // FIXME: this must be libusb_unref_device()'ed, child code must not keep a copy around
// FIXME: this must be libusb_unref_device()'ed, child code must not keep a copy around
libusb_device* dev = 0;
find_controller(&dev, dev_type, opts);
@ -427,50 +424,7 @@ Xboxdrv::run_main(const Options& opts)
if (!opts.quiet)
print_info(dev, dev_type, opts);
switch (dev_type.type)
{
case GAMEPAD_XBOX360_PLAY_N_CHARGE:
throw std::runtime_error("The Xbox360 Play&Charge cable is for recharging only, it does not transmit data, "
"thus xboxdrv can't support it. You have to get a wireless receiver:\n"
"\n"
" * http://www.xbox.com/en-ca/hardware/x/xbox360wirelessgamingreceiver/");
break;
case GAMEPAD_XBOX:
case GAMEPAD_XBOX_MAT:
controller = std::auto_ptr<XboxGenericController>(new XboxController(dev, opts.detach_kernel_driver));
break;
case GAMEPAD_XBOX360:
case GAMEPAD_XBOX360_GUITAR:
controller = std::auto_ptr<XboxGenericController>(new Xbox360Controller(dev,
opts.chatpad, opts.chatpad_no_init, opts.chatpad_debug,
opts.headset,
opts.headset_debug,
opts.headset_dump,
opts.headset_play,
opts.detach_kernel_driver));
break;
case GAMEPAD_XBOX360_WIRELESS:
controller = std::auto_ptr<XboxGenericController>(new Xbox360WirelessController(dev, opts.wireless_id, opts.detach_kernel_driver));
break;
case GAMEPAD_FIRESTORM:
controller = std::auto_ptr<XboxGenericController>(new FirestormDualController(dev, false, opts.detach_kernel_driver));
break;
case GAMEPAD_FIRESTORM_VSB:
controller = std::auto_ptr<XboxGenericController>(new FirestormDualController(dev, true, opts.detach_kernel_driver));
break;
case GAMEPAD_SAITEK_P2500:
controller = std::auto_ptr<XboxGenericController>(new SaitekP2500Controller(dev, opts.detach_kernel_driver));
break;
default:
assert(!"Unknown gamepad type");
}
controller = XboxControllerFactory::create(dev_type, dev, opts);
}
}
@ -503,7 +457,7 @@ Xboxdrv::run_main(const Options& opts)
{
if (!opts.quiet)
std::cout << "Starting with uinput" << std::endl;
uinput = std::auto_ptr<uInput>(new uInput(dev_type.type, dev_type.idVendor, dev_type.idProduct, opts.uinput_config));
uinput = std::auto_ptr<uInput>(new uInput(dev_type.idVendor, dev_type.idProduct, opts.uinput_config));
if (opts.uinput_config.force_feedback)
{
uinput->set_ff_callback(boost::bind(&set_rumble, controller.get(), opts.rumble_gain, _1, _2));
@ -702,10 +656,16 @@ Xboxdrv::run_help_devices()
void
Xboxdrv::run_daemon(const Options& opts)
{
int ret = libusb_init(NULL);
if (ret != LIBUSB_SUCCESS)
{
throw std::runtime_error("-- failure --"); // FIXME
}
if (true /* no_detatch */)
{
XboxdrvDaemon daemon;
daemon.run();
daemon.run(opts);
}
else
{
@ -732,22 +692,19 @@ Xboxdrv::run_daemon(const Options& opts)
}
XboxdrvDaemon daemon;
daemon.run();
daemon.run(opts);
}
}
libusb_exit(NULL);
}
Xboxdrv::Xboxdrv() :
m_libusb_ctx(0)
Xboxdrv::Xboxdrv()
{
}
Xboxdrv::~Xboxdrv()
{
if (m_libusb_ctx)
{
libusb_exit(m_libusb_ctx);
}
}
int

View file

@ -57,9 +57,6 @@ public:
~Xboxdrv();
int main(int argc, char** argv);
private:
libusb_context* m_libusb_ctx;
};
#endif

View file

@ -23,7 +23,17 @@
#include <string.h>
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/bind.hpp>
#include <stdio.h>
#include <assert.h>
#include "log.hpp"
#include "options.hpp"
#include "uinput.hpp"
#include "usb_helper.hpp"
#include "xbox_controller_factory.hpp"
#include "xboxdrv_thread.hpp"
#include "xpad_device.hpp"
XboxdrvDaemon::XboxdrvDaemon() :
m_udev(0),
@ -37,12 +47,7 @@ XboxdrvDaemon::XboxdrvDaemon() :
}
else
{
// FIXME: add enumerate here, see libudev example on how to avoid
// race condition
m_monitor = udev_monitor_new_from_netlink(m_udev, "udev");
udev_monitor_enable_receiving(m_monitor);
udev_monitor_filter_add_match_subsystem_devtype(m_monitor, "usb", "usb_device");
// do nothing, stuff is done in run()
}
}
@ -53,10 +58,130 @@ XboxdrvDaemon::~XboxdrvDaemon()
}
void
XboxdrvDaemon::run()
XboxdrvDaemon::process_match(const Options& opts, uInput* uinput, struct udev_device* device)
{
// 1) Match vendor/product against the xpad list
// value = udev_device_get_property_value(device, "ID_VENDOR_ID"); // 045e
// value = udev_device_get_property_value(device, "ID_MODEL_ID"); // 028e
// value = udev_device_get_property_value(device, "ID_REVISION"); // 0110 aka bcd
// PRODUCT = "45e/28e/110"
const char* product_str = udev_device_get_property_value(device, "PRODUCT");
if (product_str)
{
unsigned int vendor = 0;
unsigned int product = 0;
unsigned int bcd = 0;
if (sscanf(product_str, "%x/%x/%x", &vendor, &product, &bcd) != 3)
{
std::cout << "[XboxdrvDaemon] couldn't parse PRODUCT = " << product_str << std::endl;
}
else
{
if (false)
std::cout << "Product parse: "
<< boost::format("%03x/%03x/%03x == %s") % vendor % product % bcd % product_str
<< std::endl;
// FIXME: could do this after we know that vendor/product are good
// 2) Get busnum and devnum
// busnum:devnum are decimal, not hex
const char* busnum_str = udev_device_get_property_value(device, "BUSNUM");
const char* devnum_str = udev_device_get_property_value(device, "DEVNUM");
if (busnum_str && devnum_str)
{
try
{
XPadDevice dev_type;
if (find_xpad_device(vendor, product, &dev_type))
{
// 3) Launch thread to handle the device
log_info << "Found a valid Xboxdrv controller: " << busnum_str << ":" << devnum_str
<< " -- "
<< boost::lexical_cast<int>(busnum_str) << ", "
<< boost::lexical_cast<int>(devnum_str)
<< std::endl;
launch_xboxdrv(uinput,
dev_type, opts,
boost::lexical_cast<int>(busnum_str),
boost::lexical_cast<int>(devnum_str));
}
}
catch(const std::exception& err)
{
std::cout << "[XboxdrvDaemon] child thread lauch failure: " << err.what() << std::endl;
}
}
}
}
}
void
XboxdrvDaemon::run(const Options& opts)
{
// Setup uinput
std::auto_ptr<uInput> uinput;
if (!opts.no_uinput)
{
if (!opts.quiet) std::cout << "Starting with uinput" << std::endl;
uinput.reset(new uInput(0, 0, // don't have vendor/product ids, so use zero
opts.uinput_config));
// FIXME:
/* must setup this callback later when we have a controller
if (opts.uinput_config.force_feedback)
{
uinput->set_ff_callback(boost::bind(&set_rumble, controller.get(), opts.rumble_gain, _1, _2));
}
*/
}
else
{
if (!opts.quiet)
std::cout << "Starting without uinput" << 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");
udev_monitor_enable_receiving(m_monitor);
// FIXME: won't we get devices twice that have been plugged in at
// this point? once from the enumeration, once from the monitor
// Enumerate over all devices already connected to the computer
{
struct udev_enumerate* enumerate = udev_enumerate_new(m_udev);
assert(enumerate);
udev_enumerate_add_match_subsystem(enumerate, "usb");
// not available yet: udev_enumerate_add_match_is_initialized(enumerate);
udev_enumerate_scan_devices(enumerate);
struct udev_list_entry* devices;
struct udev_list_entry* dev_list_entry;
devices = udev_enumerate_get_list_entry(enumerate);
udev_list_entry_foreach(dev_list_entry, devices)
{
// name is path, value is NULL
const char* path = udev_list_entry_get_name(dev_list_entry) ;
//const char* value = udev_list_entry_get_value(dev_list_entry);
//std::cout << "Enum: " << path << std::endl;
struct udev_device* device = udev_device_new_from_syspath(m_udev, path);
process_match(opts, uinput.get(), device);
udev_device_unref(device);
}
udev_enumerate_unref(enumerate);
}
while(true)
{
// FIXME: we bust udev_unref_monitor() this
struct udev_device* device = udev_monitor_receive_device(m_monitor);
if (!device)
@ -70,48 +195,7 @@ XboxdrvDaemon::run()
if (action && strcmp(action, "add") == 0)
{
// 1) Match vendor/product against the xpad list
// value = udev_device_get_property_value(device, "ID_VENDOR_ID"); // 045e
// value = udev_device_get_property_value(device, "ID_MODEL_ID"); // 028e
// value = udev_device_get_property_value(device, "ID_REVISION"); // 0110 aka bcd
// PRODUCT = "45e/28e/110"
const char* product_str = udev_device_get_property_value(device, "PRODUCT");
if (product_str)
{
unsigned int vendor = 0;
unsigned int product = 0;
unsigned int bcd = 0;
if (sscanf(product_str, "%x/%x/%x", &vendor, &product, &bcd) != 3)
{
std::cout << "[XboxdrvDaemon] couldn't parse PRODUCT = " << product_str << std::endl;
}
else
{
std::cout << "Product parse: "
<< boost::format("%03x/%03x/%03x == %s") % vendor % product % bcd % product_str
<< std::endl;
// 2) Get busnum and devnum
// FIXME: are those dec or hex?
const char* busnum_str = udev_device_get_property_value(device, "BUSNUM");
const char* devnum_str = udev_device_get_property_value(device, "DEVNUM");
if (busnum_str && devnum_str)
{
try
{
// 3) Launch thread to handle the device
launch_xboxdrv(boost::lexical_cast<int>(busnum_str),
boost::lexical_cast<int>(devnum_str));
}
catch(const std::exception& err)
{
std::cout << "[XboxdrvDaemon] child thread lauch failure: " << err.what() << std::endl;
}
}
}
}
process_match(opts, uinput.get(), device);
}
}
udev_device_unref(device);
@ -195,9 +279,29 @@ XboxdrvDaemon::print_info(struct udev_device* device)
}
void
XboxdrvDaemon::launch_xboxdrv(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") % busnum % devnum << std::endl;
std::cout << "[XboxdrvDaemon] launching " << boost::format("%03d:%03d")
% static_cast<int>(busnum)
% static_cast<int>(devnum)
<< std::endl;
// FIXME: results must be libusb_unref_device()'ed
libusb_device* dev = usb_find_device_by_path(busnum, devnum);
if (!dev)
{
log_error << "USB device disappeared before it could be opened" << std::endl;
}
else
{
// FIXME: we are memory leaking the controller in the thread
std::auto_ptr<XboxGenericController> controller = XboxControllerFactory::create(dev_type, dev, opts);
// FIXME: keep these collected somewhere
XboxdrvThread* loop = new XboxdrvThread();
loop->launch_thread(dev_type.type, uinput, controller.release(), opts);
}
}
/* EOF */

View file

@ -22,6 +22,10 @@
#include <libudev.h>
#include <stdint.h>
class Options;
class uInput;
struct XPadDevice;
class XboxdrvDaemon
{
private:
@ -32,11 +36,14 @@ public:
XboxdrvDaemon();
~XboxdrvDaemon();
void run();
void run(const Options& opts);
private:
void process_match(const Options& opts, uInput* uinput, struct udev_device* device);
void print_info(struct udev_device* device);
void launch_xboxdrv(uint8_t busnum, uint8_t devnum);
void launch_xboxdrv(uInput* uinput,
const XPadDevice& dev_type, const Options& opts,
uint8_t busnum, uint8_t devnum);
private:
XboxdrvDaemon(const XboxdrvDaemon&);

View file

@ -24,6 +24,7 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <vector>
#include <assert.h>
#include "helper.hpp"
#include "modifier.hpp"
@ -51,11 +52,6 @@ XboxdrvThread::XboxdrvThread()
{
}
void
XboxdrvThread::run()
{
}
// FIXME: duplicate code
namespace {
void set_rumble(XboxGenericController* controller, int gain, uint8_t lhs, uint8_t rhs)
@ -233,4 +229,13 @@ XboxdrvThread::controller_loop(GamepadType type, uInput* uinput, XboxGenericCont
}
}
void
XboxdrvThread::launch_thread(GamepadType type, uInput* uinput, XboxGenericController* controller,
const Options& opts)
{
assert(m_thread.get() == 0);
m_thread.reset(new boost::thread(boost::bind(&XboxdrvThread::controller_loop, this,
type, uinput, controller, boost::cref(opts))));
}
/* EOF */

View file

@ -19,6 +19,9 @@
#ifndef HEADER_XBOXDRV_XBOXDRV_THREAD_HPP
#define HEADER_XBOXDRV_XBOXDRV_THREAD_HPP
#include <memory>
#include <boost/thread.hpp>
#include "xboxmsg.hpp"
class Options;
@ -28,13 +31,17 @@ class XboxGenericController;
class XboxdrvThread // FIXME: find a better name, XboxdrvControllerLoop?!
{
private:
std::auto_ptr<boost::thread> m_thread;
public:
XboxdrvThread();
void controller_loop(GamepadType type, uInput* uinput, XboxGenericController* controller,
const Options& opts);
void run();
void launch_thread(GamepadType type, uInput* uinput, XboxGenericController* controller,
const Options& opts);
private:
XboxdrvThread(const XboxdrvThread&);
XboxdrvThread& operator=(const XboxdrvThread&);

View file

@ -93,5 +93,19 @@ XPadDevice xpad_devices[] = {
};
const int xpad_devices_count = sizeof(xpad_devices)/sizeof(XPadDevice);
bool find_xpad_device(uint16_t idVendor, uint16_t idProduct, XPadDevice* dev_type)
{
for(int i = 0; i < xpad_devices_count; ++i)
{
if (idVendor == xpad_devices[i].idVendor &&
idProduct == xpad_devices[i].idProduct)
{
*dev_type = xpad_devices[i];
return true;
}
}
return false;
}
/* EOF */

View file

@ -31,6 +31,10 @@ struct XPadDevice
const char* name;
};
/** Search for an xpad device matching the \a idVendor, \a idProduct
values, the first \a skip matches will be ignored */
bool find_xpad_device(uint16_t idVendor, uint16_t idProduct, XPadDevice* dev_type);
extern XPadDevice xpad_devices[];
extern const int xpad_devices_count;