Added --match support to XboxdrvDaemon
This commit is contained in:
parent
6bf60f23e0
commit
c7b7342716
4 changed files with 198 additions and 98 deletions
|
@ -18,6 +18,33 @@
|
|||
|
||||
#include "controller_match_rule.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
bool
|
||||
ControllerMatchRule::match(int vendor, int product,
|
||||
int bus, int dev) const
|
||||
{
|
||||
switch(m_type)
|
||||
{
|
||||
case kMatchEverything:
|
||||
return true;
|
||||
|
||||
case kMatchUSBId:
|
||||
return (vendor == m_vendor && product == m_product);
|
||||
|
||||
case kMatchUSBPath:
|
||||
return (bus == m_bus && dev == m_dev);
|
||||
|
||||
case kMatchEvdevPath:
|
||||
assert(!"not implemented");
|
||||
return false;
|
||||
|
||||
default:
|
||||
assert(!"never reached");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ControllerMatchRule
|
||||
ControllerMatchRule::match_usb_id(int vendor, int product)
|
||||
{
|
||||
|
|
|
@ -48,6 +48,9 @@ public:
|
|||
m_path()
|
||||
{}
|
||||
|
||||
bool match(int vendor, int product,
|
||||
int bus, int dev) const;
|
||||
|
||||
static ControllerMatchRule match_usb_id(int vendor, int product);
|
||||
static ControllerMatchRule match_usb_path(int bus, int dev);
|
||||
static ControllerMatchRule match_evdev_path(const std::string& path);
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "default_message_processor.hpp"
|
||||
#include "dummy_message_processor.hpp"
|
||||
#include "helper.hpp"
|
||||
#include "log.hpp"
|
||||
#include "raise_exception.hpp"
|
||||
#include "uinput.hpp"
|
||||
|
@ -33,6 +34,61 @@
|
|||
|
||||
extern bool global_exit_xboxdrv;
|
||||
|
||||
namespace {
|
||||
|
||||
bool get_usb_id(udev_device* device, uint16_t* vendor_id, uint16_t* product_id)
|
||||
{
|
||||
const char* vendor_id_str = udev_device_get_property_value(device, "ID_VENDOR_ID");
|
||||
if (!vendor_id_str)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*vendor_id = hexstr2int(vendor_id_str);
|
||||
}
|
||||
|
||||
const char* product_id_str = udev_device_get_property_value(device, "ID_MODEL_ID");
|
||||
if (!product_id_str)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*product_id = hexstr2int(product_id_str);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_usb_path(udev_device* device, int* bus, int* dev)
|
||||
{
|
||||
// busnum:devnum are decimal, not hex
|
||||
const char* busnum_str = udev_device_get_property_value(device, "BUSNUM");
|
||||
if (!busnum_str)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*bus = boost::lexical_cast<int>(busnum_str);
|
||||
}
|
||||
|
||||
const char* devnum_str = udev_device_get_property_value(device, "DEVNUM");
|
||||
if (!devnum_str)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dev = boost::lexical_cast<int>(devnum_str);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
XboxdrvDaemon::XboxdrvDaemon() :
|
||||
m_udev(0),
|
||||
m_monitor(0),
|
||||
|
@ -80,72 +136,57 @@ XboxdrvDaemon::cleanup_threads()
|
|||
}
|
||||
|
||||
void
|
||||
XboxdrvDaemon::process_match(const Options& opts, UInput* uinput, struct udev_device* device)
|
||||
XboxdrvDaemon::process_match(const Options& opts, struct udev_device* device)
|
||||
{
|
||||
if (true)
|
||||
{
|
||||
print_info(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"
|
||||
uint16_t vendor;
|
||||
uint16_t product;
|
||||
|
||||
const char* product_str = udev_device_get_property_value(device, "PRODUCT");
|
||||
if (product_str)
|
||||
if (!get_usb_id(device, &vendor, &product))
|
||||
{
|
||||
unsigned int vendor = 0;
|
||||
unsigned int product = 0;
|
||||
unsigned int bcd = 0;
|
||||
if (sscanf(product_str, "%x/%x/%x", &vendor, &product, &bcd) != 3)
|
||||
log_warning << "couldn't get vendor:product" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
XPadDevice dev_type;
|
||||
if (!find_xpad_device(vendor, product, &dev_type))
|
||||
{
|
||||
std::cout << "[XboxdrvDaemon] couldn't parse PRODUCT = " << product_str << std::endl;
|
||||
log_info << "ignoring " << boost::format("%04x:%04x") % vendor % product
|
||||
<< " not a valid Xboxdrv device" << 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)
|
||||
{
|
||||
int bus;
|
||||
int dev;
|
||||
if (!get_usb_path(device, &bus, &dev))
|
||||
{
|
||||
try
|
||||
log_warning << "couldn't get bus:dev" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
ControllerSlot* slot = find_free_slot(vendor, product, bus, dev);
|
||||
if (!slot)
|
||||
{
|
||||
XPadDevice dev_type;
|
||||
if (find_xpad_device(vendor, product, &dev_type))
|
||||
{
|
||||
// 3) Launch thread to handle the device
|
||||
log_info << "controller detected at " << busnum_str << ":" << devnum_str << std::endl;
|
||||
|
||||
try
|
||||
{
|
||||
launch_xboxdrv(uinput,
|
||||
dev_type, opts,
|
||||
boost::lexical_cast<int>(busnum_str),
|
||||
boost::lexical_cast<int>(devnum_str));
|
||||
}
|
||||
catch(const std::exception& err)
|
||||
{
|
||||
log_error << "failed to launch XboxdrvThread: " << err.what() << std::endl;
|
||||
}
|
||||
}
|
||||
log_error << "no free controller slot found, controller will be ignored" << std::endl;
|
||||
}
|
||||
catch(const std::exception& err)
|
||||
else
|
||||
{
|
||||
log_error << "child thread lauch failure: " << err.what() << std::endl;
|
||||
try
|
||||
{
|
||||
launch_xboxdrv(dev_type, opts, bus, dev, *slot);
|
||||
}
|
||||
catch(const std::exception& err)
|
||||
{
|
||||
log_error << "failed to launch XboxdrvThread: " << err.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -180,7 +221,8 @@ XboxdrvDaemon::init_uinput(const Options& opts)
|
|||
controller != opts.controller_slots.end(); ++controller)
|
||||
{
|
||||
log_info << "creating slot: " << slot_count << std::endl;
|
||||
m_controller_slots.push_back(ControllerSlot(ControllerConfigSet::create(*m_uinput, slot_count,
|
||||
m_controller_slots.push_back(ControllerSlot(m_controller_slots.size(),
|
||||
ControllerConfigSet::create(*m_uinput, slot_count,
|
||||
opts.extra_devices,
|
||||
controller->second),
|
||||
controller->second.get_match_rules()));
|
||||
|
@ -241,7 +283,7 @@ XboxdrvDaemon::init_udev_monitor(const Options& opts)
|
|||
//std::cout << "Enum: " << path << std::endl;
|
||||
|
||||
struct udev_device* device = udev_device_new_from_syspath(m_udev, path);
|
||||
process_match(opts, m_uinput.get(), device);
|
||||
process_match(opts, device);
|
||||
udev_device_unref(device);
|
||||
}
|
||||
udev_enumerate_unref(enumerate);
|
||||
|
@ -307,7 +349,7 @@ XboxdrvDaemon::run_loop(const Options& opts)
|
|||
|
||||
if (action && strcmp(action, "add") == 0)
|
||||
{
|
||||
process_match(opts, m_uinput.get(), device);
|
||||
process_match(opts, device);
|
||||
}
|
||||
}
|
||||
udev_device_unref(device);
|
||||
|
@ -390,9 +432,45 @@ XboxdrvDaemon::print_info(struct udev_device* device)
|
|||
std::cout << "\\----------------------------------------------" << std::endl;
|
||||
}
|
||||
|
||||
XboxdrvDaemon::ControllerSlot*
|
||||
XboxdrvDaemon::find_free_slot(uint16_t vendor, uint16_t product,
|
||||
int bus, int dev) const
|
||||
{
|
||||
// first pass, look for slots where the rules match the given vendor:product, bus:dev
|
||||
for(ControllerSlots::const_iterator i = m_controller_slots.begin(); i != m_controller_slots.end(); ++i)
|
||||
{
|
||||
if (i->thread == 0)
|
||||
{
|
||||
// found a free slot, check if the rules match
|
||||
for(std::vector<ControllerMatchRule>::const_iterator rule = i->rules.begin(); rule != i->rules.end(); ++rule)
|
||||
{
|
||||
if (rule->match(vendor, product, bus, dev))
|
||||
{
|
||||
// FIXME: ugly const_cast
|
||||
return const_cast<ControllerSlot*>(&(*i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// second path, look for slots that don't have any rules and thus match everything
|
||||
for(ControllerSlots::const_iterator i = m_controller_slots.begin(); i != m_controller_slots.end(); ++i)
|
||||
{
|
||||
if (i->thread == 0 && i->rules.empty())
|
||||
{
|
||||
// FIXME: ugly const_cast
|
||||
return const_cast<ControllerSlot*>(&(*i));
|
||||
}
|
||||
}
|
||||
|
||||
// no free slot found
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
XboxdrvDaemon::launch_xboxdrv(UInput* uinput, const XPadDevice& dev_type, const Options& opts,
|
||||
uint8_t busnum, uint8_t devnum)
|
||||
XboxdrvDaemon::launch_xboxdrv(const XPadDevice& dev_type, const Options& opts,
|
||||
uint8_t busnum, uint8_t devnum,
|
||||
ControllerSlot& slot)
|
||||
{
|
||||
// FIXME: results must be libusb_unref_device()'ed
|
||||
libusb_device* dev = usb_find_device_by_path(busnum, devnum);
|
||||
|
@ -403,45 +481,28 @@ XboxdrvDaemon::launch_xboxdrv(UInput* uinput, const XPadDevice& dev_type, const
|
|||
}
|
||||
else
|
||||
{
|
||||
ControllerSlots::iterator it = m_controller_slots.end();
|
||||
for(ControllerSlots::iterator i = m_controller_slots.begin(); i != m_controller_slots.end(); ++i)
|
||||
std::auto_ptr<XboxGenericController> controller = XboxControllerFactory::create(dev_type, dev, opts);
|
||||
|
||||
std::auto_ptr<MessageProcessor> message_proc;
|
||||
if (m_uinput.get())
|
||||
{
|
||||
if (i->thread == 0)
|
||||
{
|
||||
it = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (it == m_controller_slots.end())
|
||||
{
|
||||
log_error << "no free controller slot found, controller will be ignored" << std::endl;
|
||||
message_proc.reset(new DefaultMessageProcessor(*m_uinput, slot.config, opts));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::auto_ptr<XboxGenericController> controller = XboxControllerFactory::create(dev_type, dev, opts);
|
||||
|
||||
std::auto_ptr<MessageProcessor> message_proc;
|
||||
if (uinput)
|
||||
{
|
||||
message_proc.reset(new DefaultMessageProcessor(*uinput, it->config, opts));
|
||||
}
|
||||
else
|
||||
{
|
||||
message_proc.reset(new DummyMessageProcessor());
|
||||
}
|
||||
std::auto_ptr<XboxdrvThread> thread(new XboxdrvThread(message_proc, controller, opts));
|
||||
thread->start_thread(opts);
|
||||
it->thread = thread.release();
|
||||
|
||||
log_info << "launched XboxdrvThread for " << boost::format("%03d:%03d")
|
||||
% static_cast<int>(busnum)
|
||||
% static_cast<int>(devnum)
|
||||
<< " in slot " << (it - m_controller_slots.begin())
|
||||
<< ", free slots: "
|
||||
<< get_free_slot_count() << "/" << m_controller_slots.size()
|
||||
<< std::endl;
|
||||
message_proc.reset(new DummyMessageProcessor());
|
||||
}
|
||||
|
||||
std::auto_ptr<XboxdrvThread> thread(new XboxdrvThread(message_proc, controller, opts));
|
||||
thread->start_thread(opts);
|
||||
slot.thread = thread.release();
|
||||
|
||||
log_info << "launched XboxdrvThread for " << boost::format("%03d:%03d")
|
||||
% static_cast<int>(busnum)
|
||||
% static_cast<int>(devnum)
|
||||
<< " in slot " << slot.id << ", free slots: "
|
||||
<< get_free_slot_count() << "/" << m_controller_slots.size()
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,27 +39,32 @@ private:
|
|||
|
||||
struct ControllerSlot
|
||||
{
|
||||
int id;
|
||||
ControllerConfigSetPtr config;
|
||||
std::vector<ControllerMatchRule> match;
|
||||
std::vector<ControllerMatchRule> rules;
|
||||
XboxdrvThread* thread;
|
||||
|
||||
ControllerSlot() :
|
||||
id(),
|
||||
config(),
|
||||
match(),
|
||||
rules(),
|
||||
thread(0)
|
||||
{}
|
||||
|
||||
ControllerSlot(ControllerConfigSetPtr config_,
|
||||
std::vector<ControllerMatchRule> match_,
|
||||
ControllerSlot(int id_,
|
||||
ControllerConfigSetPtr config_,
|
||||
std::vector<ControllerMatchRule> rules_,
|
||||
XboxdrvThread* thread_ = 0) :
|
||||
id(id_),
|
||||
config(config_),
|
||||
match(match_),
|
||||
rules(rules_),
|
||||
thread(thread_)
|
||||
{}
|
||||
|
||||
ControllerSlot(const ControllerSlot& rhs) :
|
||||
id(rhs.id),
|
||||
config(rhs.config),
|
||||
match(rhs.match),
|
||||
rules(rhs.rules),
|
||||
thread(rhs.thread)
|
||||
{}
|
||||
|
||||
|
@ -67,8 +72,9 @@ private:
|
|||
{
|
||||
if (&rhs != this)
|
||||
{
|
||||
id = rhs.id;
|
||||
config = rhs.config;
|
||||
match = rhs.match;
|
||||
rules = rhs.rules;
|
||||
thread = rhs.thread;
|
||||
}
|
||||
return *this;
|
||||
|
@ -94,12 +100,15 @@ private:
|
|||
|
||||
void run_loop(const Options& opts);
|
||||
|
||||
ControllerSlot* find_free_slot(uint16_t vendor, uint16_t product,
|
||||
int bus, int dev) const;
|
||||
|
||||
void cleanup_threads();
|
||||
void process_match(const Options& opts, UInput* uinput, struct udev_device* device);
|
||||
void process_match(const Options& opts, struct udev_device* device);
|
||||
void print_info(struct udev_device* device);
|
||||
void launch_xboxdrv(UInput* uinput,
|
||||
const XPadDevice& dev_type, const Options& opts,
|
||||
uint8_t busnum, uint8_t devnum);
|
||||
void launch_xboxdrv(const XPadDevice& dev_type, const Options& opts,
|
||||
uint8_t busnum, uint8_t devnum,
|
||||
ControllerSlot& slot);
|
||||
int get_free_slot_count() const;
|
||||
|
||||
private:
|
||||
|
|
Loading…
Add table
Reference in a new issue