Added hotplug support to "xboxdrv --daemon" via libudev
This commit is contained in:
parent
52de13c105
commit
e977466574
17 changed files with 461 additions and 130 deletions
6
TODO
6
TODO
|
@ -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
42
src/log.cpp
Normal 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
44
src/log.hpp
Normal 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 */
|
|
@ -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(),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
74
src/xbox_controller_factory.cpp
Normal file
74
src/xbox_controller_factory.cpp
Normal 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 */
|
44
src/xbox_controller_factory.hpp
Normal file
44
src/xbox_controller_factory.hpp
Normal 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 */
|
|
@ -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
|
||||
|
|
|
@ -57,9 +57,6 @@ public:
|
|||
~Xboxdrv();
|
||||
|
||||
int main(int argc, char** argv);
|
||||
|
||||
private:
|
||||
libusb_context* m_libusb_ctx;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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&);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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&);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue