Restructured how ControllerMatchRule's work, implemented --match-group

This commit is contained in:
Ingo Ruhnke 2011-01-28 19:30:42 +01:00
parent dd02607153
commit e92a50979f
8 changed files with 217 additions and 149 deletions

View file

@ -228,7 +228,7 @@ CommandLineParser::init_argp()
.add_option(OPTION_CONTROLLER_SLOT, 0, "controller-slot", "N", "Use controller slot N")
.add_option(OPTION_NEXT_CONTROLLER, 0, "next-controller", "", "Create a new controller entry")
.add_option(OPTION_DAEMON_MATCH, 0, "match", "RULES", "Only allow controllers that match any of RULES")
//FIXME: .add_option(OPTION_DAEMON_MATCH_GROUP, 0, "match-group", "RULES", "Only allow controllers that match all of RULES")
.add_option(OPTION_DAEMON_MATCH_GROUP, 0, "match-group", "RULES", "Only allow controllers that match all of RULES")
.add_newline()
.add_text("Config Slot Options: ")

View file

@ -19,12 +19,80 @@
#include "controller_match_rule.hpp"
#include <assert.h>
#include <boost/tokenizer.hpp>
#include "raise_exception.hpp"
class ControllerMatchRuleProperty : public ControllerMatchRule
{
private:
std::string m_name;
std::string m_value;
public:
ControllerMatchRuleProperty(const std::string& name,
const std::string& value) :
m_name(name),
m_value(value)
{}
bool match(udev_device* device) const
{
const char* str = udev_device_get_property_value(device, m_name.c_str());
log_debug("matching property '" << m_name << "' with value '" << (str?str:"(null)") <<
"' against '" << m_value);
if (!str)
{
return false;
}
else
{
return (m_value == str);
}
}
};
ControllerMatchRuleGroup::ControllerMatchRuleGroup() :
m_rules()
{}
void
ControllerMatchRuleGroup::add_rule(ControllerMatchRulePtr rule)
{
m_rules.push_back(rule);
}
void
ControllerMatchRuleGroup::add_rule_from_string(const std::string& lhs, const std::string& rhs)
{
m_rules.push_back(ControllerMatchRule::from_string(lhs, rhs));
}
bool
ControllerMatchRule::match(int vendor, int product,
int bus, int dev,
const char* serial) const
ControllerMatchRuleGroup::match(udev_device* device) const
{
log_debug("matching group rule");
for(Rules::const_iterator i = m_rules.begin(); i != m_rules.end(); ++i)
{
if (!(*i)->match(device))
{
return false;
}
}
return true;
}
bool
ControllerMatchRule::match(udev_device* device) const
{
assert(!"implement me");
return false;
#if 0
const char* serial = udev_device_get_property_value(device, "ID_SERIAL_SHORT");
switch(m_type)
{
case kMatchEverything:
@ -47,44 +115,108 @@ ControllerMatchRule::match(int vendor, int product,
assert(!"never reached");
return false;
}
#endif
}
ControllerMatchRule
ControllerMatchRule::create_usb_id(int vendor, int product)
ControllerMatchRulePtr
ControllerMatchRule::from_string(const std::string& lhs,
const std::string& rhs)
{
ControllerMatchRule rule;
rule.m_type = kMatchUSBId;
rule.m_vendor = vendor;
rule.m_product = product;
return rule;
}
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer tokens(rhs, boost::char_separator<char>(":", "", boost::keep_empty_tokens));
std::vector<std::string> args(tokens.begin(), tokens.end());
ControllerMatchRule
ControllerMatchRule::create_usb_path(int bus, int dev)
{
ControllerMatchRule rule;
rule.m_type = kMatchUSBPath;
rule.m_bus = bus;
rule.m_dev = dev;
return rule;
if (lhs == "usbid")
{
if (args.size() != 2)
{
raise_exception(std::runtime_error, "usbid requires VENDOR:PRODUCT argument");
}
else
{
boost::shared_ptr<ControllerMatchRuleGroup> group(new ControllerMatchRuleGroup);
group->add_rule(ControllerMatchRulePtr(new ControllerMatchRuleProperty("ID_VENDOR_ID", args[0])));
group->add_rule(ControllerMatchRulePtr(new ControllerMatchRuleProperty("ID_MODEL_ID", args[1])));
return group;
}
}
else if (lhs == "vendor")
{
if (args.size() != 1)
{
raise_exception(std::runtime_error, "vendor requires an argument");
}
else
{
return ControllerMatchRulePtr(new ControllerMatchRuleProperty("ID_VENDOR_ID", args[0]));
}
}
else if (lhs == "property")
{
if (args.size() != 1)
{
raise_exception(std::runtime_error, "property two arguments");
}
else
{
return ControllerMatchRulePtr(new ControllerMatchRuleProperty(args[0], args[1]));
}
}
else if (lhs == "product")
{
if (args.size() != 1)
{
raise_exception(std::runtime_error, "product requires an argument");
}
else
{
return ControllerMatchRulePtr(new ControllerMatchRuleProperty("ID_MODEL_ID", args[0]));
}
}
else if (lhs == "usbpath")
{
if (args.size() != 2)
{
raise_exception(std::runtime_error, "usbpath requires BUS:DEV argument");
}
else
{
boost::shared_ptr<ControllerMatchRuleGroup> group(new ControllerMatchRuleGroup);
group->add_rule(ControllerMatchRulePtr(new ControllerMatchRuleProperty("BUSNUM", args[0])));
group->add_rule(ControllerMatchRulePtr(new ControllerMatchRuleProperty("DEVNUM", args[1])));
return group;
}
}
else if (lhs == "usbserial")
{
if (args.size() != 1)
{
raise_exception(std::runtime_error, "usbserial rule requires SERIAL argument");
}
else
{
return ControllerMatchRulePtr(new ControllerMatchRuleProperty("ID_SERIAL_SHORT", args[0]));
}
}
else if (lhs == "evdev")
{
if (args.size() != 1)
{
raise_exception(std::runtime_error, "evdev rule requires PATH argument");
}
else
{
raise_exception(std::runtime_error, "evdev rule not yet implemented");
}
}
else
{
raise_exception(std::runtime_error, "'" << lhs << "' not a valid match rule name");
}
}
ControllerMatchRule
ControllerMatchRule::create_usb_serial(const std::string& serial)
{
ControllerMatchRule rule;
rule.m_type = kMatchUSBSerial;
rule.m_serial = serial;
return rule;
}
ControllerMatchRule
ControllerMatchRule::create_evdev_path(const std::string& path)
{
ControllerMatchRule rule;
rule.m_type = kMatchEvdevPath;
rule.m_path = path;
return rule;
}
/* EOF */

View file

@ -19,49 +19,42 @@
#ifndef HEADER_XBOXDRV_CONTROLLER_MATCH_RULE_HPP
#define HEADER_XBOXDRV_CONTROLLER_MATCH_RULE_HPP
#include <boost/shared_ptr.hpp>
#include <libudev.h>
#include <string>
#include <vector>
struct udev_device;
class ControllerMatchRule;
typedef boost::shared_ptr<ControllerMatchRule> ControllerMatchRulePtr;
class ControllerMatchRule
{
public:
enum {
kMatchEverything,
kMatchUSBId,
kMatchUSBPath,
kMatchUSBSerial,
kMatchEvdevPath
} m_type;
static ControllerMatchRulePtr from_string(const std::string& lhs,
const std::string& rhs);
int m_bus;
int m_dev;
int m_vendor;
int m_product;
public:
ControllerMatchRule() {}
virtual ~ControllerMatchRule() {}
std::string m_path;
std::string m_serial;
ControllerMatchRule() :
m_type(kMatchEverything),
m_bus(),
m_dev(),
m_vendor(),
m_product(),
m_path(),
m_serial()
{}
bool match(int vendor, int product,
int bus, int dev,
const char* serial) const;
static ControllerMatchRule create_usb_id(int vendor, int product);
static ControllerMatchRule create_usb_path(int bus, int dev);
static ControllerMatchRule create_usb_serial(const std::string& serial);
static ControllerMatchRule create_evdev_path(const std::string& path);
virtual bool match(udev_device* device) const =0;
};
class ControllerMatchRuleGroup : public ControllerMatchRule
{
private:
typedef std::vector<ControllerMatchRulePtr> Rules;
Rules m_rules;
public:
ControllerMatchRuleGroup();
void add_rule(ControllerMatchRulePtr rule);
void add_rule_from_string(const std::string& lhs, const std::string& rhs);
bool match(udev_device* device) const;
};
#endif
/* EOF */

View file

@ -50,12 +50,12 @@ ControllerSlotOptions::get_options(int num) const
}
void
ControllerSlotOptions::add_match_rule(const ControllerMatchRule& rule)
ControllerSlotOptions::add_match_rule(ControllerMatchRulePtr rule)
{
m_match_rules.push_back(rule);
}
const std::vector<ControllerMatchRule>&
const std::vector<ControllerMatchRulePtr>&
ControllerSlotOptions::get_match_rules() const
{
return m_match_rules;

View file

@ -33,12 +33,12 @@ public:
public:
ControllerSlotOptions();
void add_match_rule(const ControllerMatchRule& rule);
void add_match_rule(ControllerMatchRulePtr rule);
ControllerOptions& get_options(int num);
const ControllerOptions& get_options(int num) const;
const std::vector<ControllerMatchRule>& get_match_rules() const;
const std::vector<ControllerMatchRulePtr>& get_match_rules() const;
const std::map<int, ControllerOptions>& get_options() const;
void set_force_feedback(bool value) { m_force_feedback = value; }
@ -48,7 +48,7 @@ public:
private:
std::map<int, ControllerOptions> m_options;
std::vector<ControllerMatchRule> m_match_rules;
std::vector<ControllerMatchRulePtr> m_match_rules;
bool m_force_feedback;
};

View file

@ -239,62 +239,7 @@ Options::set_quiet()
void
Options::add_match(const std::string& lhs, const std::string& rhs)
{
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer tokens(rhs, boost::char_separator<char>(":", "", boost::keep_empty_tokens));
std::vector<std::string> args(tokens.begin(), tokens.end());
if (lhs == "usbid")
{
if (args.size() != 2)
{
raise_exception(std::runtime_error, "usbid requires VENDOR:PRODUCT argument");
}
else
{
int vendor = hexstr2int(args[0]);
int product = hexstr2int(args[1]);
get_controller_slot().add_match_rule(ControllerMatchRule::create_usb_id(vendor, product));
}
}
else if (lhs == "usbpath")
{
if (args.size() != 2)
{
raise_exception(std::runtime_error, "usbpath requires BUS:DEV argument");
}
else
{
int bus = boost::lexical_cast<int>(args[0]);
int dev = boost::lexical_cast<int>(args[1]);
get_controller_slot().add_match_rule(ControllerMatchRule::create_usb_path(bus, dev));
}
}
else if (lhs == "usbserial")
{
if (args.size() != 1)
{
raise_exception(std::runtime_error, "usbserial rule requires SERIAL argument");
}
else
{
get_controller_slot().add_match_rule(ControllerMatchRule::create_usb_serial(args[0]));
}
}
else if (lhs == "evdev")
{
if (args.size() != 1)
{
raise_exception(std::runtime_error, "evdev rule requires PATH argument");
}
else
{
get_controller_slot().add_match_rule(ControllerMatchRule::create_evdev_path(args[0]));
}
}
else
{
raise_exception(std::runtime_error, "'" << lhs << "' not a valid match rule name");
}
get_controller_slot().add_match_rule(ControllerMatchRule::from_string(lhs, rhs));
}
void
@ -306,8 +251,11 @@ Options::set_match(const std::string& str)
void
Options::set_match_group(const std::string& str)
{
// FIXME: not implied
assert(!"not implemented");
boost::shared_ptr<ControllerMatchRuleGroup> group(new ControllerMatchRuleGroup);
process_name_value_string(str, boost::bind(&ControllerMatchRuleGroup::add_rule_from_string, group, _1, _2));
get_controller_slot().add_match_rule(group);
}
void

View file

@ -166,9 +166,7 @@ XboxdrvDaemon::process_match(const Options& opts, struct udev_device* device)
}
else
{
const char* serial = udev_device_get_property_value(device, "ID_SERIAL_SHORT");
ControllerSlot* slot = find_free_slot(vendor, product, bus, dev, serial);
ControllerSlot* slot = find_free_slot(device);
if (!slot)
{
log_error("no free controller slot found, controller will be ignored");
@ -431,9 +429,7 @@ XboxdrvDaemon::print_info(struct udev_device* device)
}
XboxdrvDaemon::ControllerSlot*
XboxdrvDaemon::find_free_slot(uint16_t vendor, uint16_t product,
int bus, int dev,
const char* serial) const
XboxdrvDaemon::find_free_slot(udev_device* 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)
@ -441,9 +437,9 @@ XboxdrvDaemon::find_free_slot(uint16_t vendor, uint16_t product,
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)
for(std::vector<ControllerMatchRulePtr>::const_iterator rule = i->rules.begin(); rule != i->rules.end(); ++rule)
{
if (rule->match(vendor, product, bus, dev, serial))
if ((*rule)->match(dev))
{
// FIXME: ugly const_cast
return const_cast<ControllerSlot*>(&(*i));

View file

@ -38,7 +38,7 @@ private:
{
int id;
ControllerSlotConfigPtr config;
std::vector<ControllerMatchRule> rules;
std::vector<ControllerMatchRulePtr> rules;
XboxdrvThread* thread;
ControllerSlot() :
@ -50,7 +50,7 @@ private:
ControllerSlot(int id_,
ControllerSlotConfigPtr config_,
std::vector<ControllerMatchRule> rules_,
std::vector<ControllerMatchRulePtr> rules_,
XboxdrvThread* thread_ = 0) :
id(id_),
config(config_),
@ -97,8 +97,7 @@ private:
void run_loop(const Options& opts);
ControllerSlot* find_free_slot(uint16_t vendor, uint16_t product,
int bus, int dev, const char* serial) const;
ControllerSlot* find_free_slot(udev_device* dev) const;
void cleanup_threads();
void process_match(const Options& opts, struct udev_device* device);