From 7ec53fa23a476eaf71d71cf30a77767c4bc4b226 Mon Sep 17 00:00:00 2001
From: Ingo Ruhnke <grumbel@gmx.de>
Date: Tue, 25 Jan 2011 23:34:18 +0100
Subject: [PATCH] Splitted Options related stuff into separate files

---
 src/command_line_options.cpp    |  12 ++++
 src/controller_config.cpp       |   1 +
 src/controller_config_set.cpp   |   7 ++-
 src/controller_config_set.hpp   |   2 +-
 src/controller_match_rule.cpp   |  50 ++++++++++++++++
 src/controller_match_rule.hpp   |  58 ++++++++++++++++++
 src/controller_options.cpp      |  39 ++++++++++++
 src/controller_options.hpp      |  56 +++++++++++++++++
 src/controller_slot_options.cpp |  69 +++++++++++++++++++++
 src/controller_slot_options.hpp |  51 ++++++++++++++++
 src/helper.cpp                  |  21 +++++++
 src/helper.hpp                  |   2 +
 src/options.cpp                 | 103 ++++++++++++++++++++++++--------
 src/options.hpp                 |  40 +++----------
 src/xboxdrv_daemon.cpp          |   3 +-
 src/xboxdrv_daemon.hpp          |   7 +++
 16 files changed, 459 insertions(+), 62 deletions(-)
 create mode 100644 src/controller_match_rule.cpp
 create mode 100644 src/controller_match_rule.hpp
 create mode 100644 src/controller_options.cpp
 create mode 100644 src/controller_options.hpp
 create mode 100644 src/controller_slot_options.cpp
 create mode 100644 src/controller_slot_options.hpp

diff --git a/src/command_line_options.cpp b/src/command_line_options.cpp
index 4a9ef6c..bb97cd9 100644
--- a/src/command_line_options.cpp
+++ b/src/command_line_options.cpp
@@ -106,6 +106,8 @@ enum {
   OPTION_DETACH_KERNEL_DRIVER,
   OPTION_DAEMON_DETACH,
   OPTION_DAEMON_PID_FILE,
+  OPTION_DAEMON_MATCH,
+  OPTION_DAEMON_MATCH_GROUP,
   OPTION_HELP_DEVICES,
   OPTION_LIST_ALL,
   OPTION_LIST_ABS,
@@ -167,6 +169,8 @@ CommandLineParser::init_argp()
     .add_option(OPTION_DAEMON_PID_FILE, 0, "pid-file",    "FILE", "Write daemon pid to FILE")
     .add_option(OPTION_DAEMON_ON_CONNECT,    0, "on-connect", "FILE", "Launch EXE when a new controller is connected")
     .add_option(OPTION_DAEMON_ON_DISCONNECT, 0, "on-disconnect", "FILE", "Launch EXE when a controller is disconnected")
+    .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_newline()
 
     .add_text("Device Options: ")
@@ -400,6 +404,14 @@ CommandLineParser::parse_args(int argc, char** argv, Options* options)
         opts.mode = Options::RUN_DAEMON;
         break;
 
+      case OPTION_DAEMON_MATCH:
+        opts.set_match(opt.argument);
+        break;
+
+      case OPTION_DAEMON_MATCH_GROUP:
+        opts.set_match_group(opt.argument);
+        break;
+
       case OPTION_WRITE_CONFIG:
         {
           opts.instant_exit = true;
diff --git a/src/controller_config.cpp b/src/controller_config.cpp
index aff158c..a92f428 100644
--- a/src/controller_config.cpp
+++ b/src/controller_config.cpp
@@ -18,6 +18,7 @@
 
 #include "controller_config.hpp"
 
+#include "controller_options.hpp"
 #include "options.hpp"
 
 ControllerConfig::ControllerConfig(UInput& uinput, int slot, bool extra_devices, const ControllerOptions& opts) :
diff --git a/src/controller_config_set.cpp b/src/controller_config_set.cpp
index c8fd81f..b53122c 100644
--- a/src/controller_config_set.cpp
+++ b/src/controller_config_set.cpp
@@ -19,18 +19,19 @@
 #include "controller_config_set.hpp"
 
 #include "log.hpp"
+#include "controller_options.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, int slot, bool extra_devices, const Options::ControllerConfigs& opts)
+ControllerConfigSet::create(UInput& uinput, int slot, bool extra_devices, const ControllerSlotOptions& opts)
 {  
   ControllerConfigSetPtr m_config(new ControllerConfigSet);
 
-  for(Options::ControllerConfigs::const_iterator i = opts.begin();
-      i != opts.end(); ++i)
+  for(ControllerSlotOptions::Options::const_iterator i = opts.get_options().begin();
+      i != opts.get_options().end(); ++i)
   {
     const ControllerOptions& ctrl_opt = i->second;
 
diff --git a/src/controller_config_set.hpp b/src/controller_config_set.hpp
index 1d47e3e..f813292 100644
--- a/src/controller_config_set.hpp
+++ b/src/controller_config_set.hpp
@@ -33,7 +33,7 @@ class ControllerConfigSet
 public:
   /** Creates a ControllerConfigSet from the Options object and connects it to UInput */
   static ControllerConfigSetPtr create(UInput& uinput, int slot, bool extra_devices, 
-                                       const Options::ControllerConfigs& opts);
+                                       const ControllerSlotOptions& opts);
 
 private:
   static void create_modifier(const ControllerOptions& options, std::vector<ModifierPtr>* modifier);
diff --git a/src/controller_match_rule.cpp b/src/controller_match_rule.cpp
new file mode 100644
index 0000000..aceb45d
--- /dev/null
+++ b/src/controller_match_rule.cpp
@@ -0,0 +1,50 @@
+/*
+**  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 "controller_match_rule.hpp"
+
+ControllerMatchRule
+ControllerMatchRule::match_usb_id(int vendor, int product)
+{
+  ControllerMatchRule rule;
+  rule.m_type = kMatchUSBId;
+  rule.m_vendor = vendor;
+  rule.m_product = product;
+  return rule;
+}
+
+ControllerMatchRule
+ControllerMatchRule::match_usb_path(int bus, int dev)
+{
+  ControllerMatchRule rule;
+  rule.m_type = kMatchUSBPath;
+  rule.m_bus  = bus;
+  rule.m_dev = dev;
+  return rule;
+}
+
+ControllerMatchRule 
+ControllerMatchRule::match_evdev_path(const std::string& path)
+{
+  ControllerMatchRule rule;
+  rule.m_type = kMatchEvdevPath;
+  rule.m_path = path;
+  return rule;
+}
+
+/* EOF */
diff --git a/src/controller_match_rule.hpp b/src/controller_match_rule.hpp
new file mode 100644
index 0000000..c39278b
--- /dev/null
+++ b/src/controller_match_rule.hpp
@@ -0,0 +1,58 @@
+/*
+**  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_CONTROLLER_MATCH_RULE_HPP
+#define HEADER_XBOXDRV_CONTROLLER_MATCH_RULE_HPP
+
+#include <string>
+
+class ControllerMatchRule
+{
+public:
+  enum { 
+    kMatchEverything,
+    kMatchUSBId, 
+    kMatchUSBPath, 
+    kMatchEvdevPath
+  } m_type;
+
+  int m_bus;
+  int m_dev;
+  
+  int m_vendor;
+  int m_product;
+
+  std::string m_path;
+
+  ControllerMatchRule() :
+    m_type(kMatchEverything),
+    m_bus(),
+    m_dev(),
+    m_vendor(),
+    m_product(),
+    m_path()
+  {}
+
+  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);
+};
+
+#endif
+
+/* EOF */
diff --git a/src/controller_options.cpp b/src/controller_options.cpp
new file mode 100644
index 0000000..85529ec
--- /dev/null
+++ b/src/controller_options.cpp
@@ -0,0 +1,39 @@
+/*
+**  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 "controller_options.hpp"
+
+ControllerOptions::ControllerOptions() :
+  uinput(),
+  modifier(),
+  buttonmap(new ButtonmapModifier),
+  axismap(new AxismapModifier),
+  deadzone(0),
+  deadzone_trigger(0),
+  square_axis(false),
+  four_way_restrictor(0),
+  dpad_rotation(0),
+
+  calibration_map(),
+  sensitivity_map(),
+  relative_axis_map(),
+  autofire_map()
+{
+}
+
+/* EOF */
diff --git a/src/controller_options.hpp b/src/controller_options.hpp
new file mode 100644
index 0000000..ab8910d
--- /dev/null
+++ b/src/controller_options.hpp
@@ -0,0 +1,56 @@
+/*
+**  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_CONTROLLER_OPTIONS_HPP
+#define HEADER_XBOXDRV_CONTROLLER_OPTIONS_HPP
+
+#include <vector>
+#include <map>
+
+#include "uinput_options.hpp"
+
+#include "modifier/axismap_modifier.hpp"
+#include "modifier/buttonmap_modifier.hpp"
+
+class ControllerOptions
+{
+public:
+  ControllerOptions();
+
+  UInputOptions uinput;
+  std::vector<ModifierPtr> modifier;
+
+  // everything below gets later converted into modifier
+  boost::shared_ptr<ButtonmapModifier> buttonmap;
+  boost::shared_ptr<AxismapModifier>   axismap;
+
+  int  deadzone;
+  int  deadzone_trigger;
+  bool square_axis;
+  bool four_way_restrictor;
+  int  dpad_rotation;
+
+  std::map<XboxAxis, AxisFilterPtr> calibration_map;
+  std::map<XboxAxis, AxisFilterPtr> sensitivity_map;
+  std::map<XboxAxis, AxisFilterPtr> relative_axis_map;
+  std::map<XboxButton, ButtonFilterPtr> autofire_map;
+};
+
+#endif
+
+/* EOF */
diff --git a/src/controller_slot_options.cpp b/src/controller_slot_options.cpp
new file mode 100644
index 0000000..fff419c
--- /dev/null
+++ b/src/controller_slot_options.cpp
@@ -0,0 +1,69 @@
+/*
+**  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 "controller_slot_options.hpp"
+
+#include <stdexcept>
+
+#include "raise_exception.hpp"
+
+ControllerSlotOptions::ControllerSlotOptions() :
+  m_options(),
+  m_match_rules()
+{
+}
+
+ControllerOptions&
+ControllerSlotOptions::get_options(int num)
+{
+  return m_options[num];
+}
+
+const ControllerOptions&
+ControllerSlotOptions::get_options(int num) const
+{
+  std::map<int, ControllerOptions>::const_iterator it = m_options.find(num);
+  if (it == m_options.end())
+  {
+    raise_exception(std::runtime_error, "illegal option: " << num);
+  }
+  else
+  {
+    return it->second;
+  }
+}
+
+void
+ControllerSlotOptions::add_match_rule(const ControllerMatchRule& rule)
+{
+  m_match_rules.push_back(rule);
+}
+
+const std::vector<ControllerMatchRule>&
+ControllerSlotOptions::get_match_rules() const
+{
+  return m_match_rules;
+}
+
+const std::map<int, ControllerOptions>&
+ControllerSlotOptions::get_options() const
+{
+  return m_options; 
+}
+
+/* EOF */
diff --git a/src/controller_slot_options.hpp b/src/controller_slot_options.hpp
new file mode 100644
index 0000000..1e848f6
--- /dev/null
+++ b/src/controller_slot_options.hpp
@@ -0,0 +1,51 @@
+/*
+**  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_CONTROLLER_SLOT_OPTIONS_HPP
+#define HEADER_XBOXDRV_CONTROLLER_SLOT_OPTIONS_HPP
+
+#include <map>
+#include <vector>
+
+#include "controller_options.hpp"
+#include "controller_match_rule.hpp"
+
+class ControllerSlotOptions
+{
+public:
+  typedef std::map<int, ControllerOptions> Options;
+
+public:
+  ControllerSlotOptions();
+
+  void add_match_rule(const ControllerMatchRule& rule);
+
+  ControllerOptions& get_options(int num);
+  const ControllerOptions& get_options(int num) const;
+
+  const std::vector<ControllerMatchRule>& get_match_rules() const;
+  const std::map<int, ControllerOptions>& get_options() const;
+
+private:
+  std::map<int, ControllerOptions> m_options;
+  std::vector<ControllerMatchRule> m_match_rules;
+};
+
+#endif
+
+/* EOF */
diff --git a/src/helper.cpp b/src/helper.cpp
index 9f9e07f..d43d103 100644
--- a/src/helper.cpp
+++ b/src/helper.cpp
@@ -22,8 +22,29 @@
 #include <boost/format.hpp>
 #include <boost/tokenizer.hpp>
 #include <boost/lexical_cast.hpp>
+#include <stdio.h>
 #include <sys/time.h>
 #include <sys/ioctl.h>
+#include <stdexcept>
+
+#include "raise_exception.hpp"
+
+int hexstr2int(const std::string& str)
+{
+  unsigned int value = 0;
+  if (sscanf(str.c_str(), "%x", &value) == 1)
+  {
+    return value;
+  }
+  else if (sscanf(str.c_str(), "0x%x", &value) == 1)
+  {
+    return value;
+  }
+  else
+  {
+    raise_exception(std::runtime_error, "couldn't convert '" << str << "' to int");
+  }
+}
 
 std::string raw2str(uint8_t* data, int len)
 {
diff --git a/src/helper.hpp b/src/helper.hpp
index 89c0516..19c610f 100644
--- a/src/helper.hpp
+++ b/src/helper.hpp
@@ -21,6 +21,8 @@
 
 #include <boost/function.hpp>
 
+int hexstr2int(const std::string& str);
+
 std::string raw2str(uint8_t* buffer, int len);
 std::string to_lower(const std::string &str);
 bool is_number(const std::string& str);
diff --git a/src/options.cpp b/src/options.cpp
index 8e1e84f..e4008f8 100644
--- a/src/options.cpp
+++ b/src/options.cpp
@@ -18,26 +18,14 @@
 
 #include "options.hpp"
 
+#include <boost/tokenizer.hpp>
+#include <boost/bind.hpp>
+
+#include "helper.hpp"
+#include "raise_exception.hpp"
+
 Options* g_options;
 
-ControllerOptions::ControllerOptions() :
-  uinput(),
-  modifier(),
-  buttonmap(new ButtonmapModifier),
-  axismap(new AxismapModifier),
-  deadzone(0),
-  deadzone_trigger(0),
-  square_axis(false),
-  four_way_restrictor(0),
-  dpad_rotation(0),
-
-  calibration_map(),
-  sensitivity_map(),
-  relative_axis_map(),
-  autofire_map()
-{
-}
-
 Options::Options() :
   mode(RUN_DEFAULT),
   verbose(false),
@@ -84,16 +72,16 @@ Options::Options() :
   extra_devices(true)
 {
   // create the entry if not already available
-  controller_slots[controller_slot][config_slot];
+  controller_slots[controller_slot].get_options(config_slot);
 }
 
-Options::ControllerConfigs&
+ControllerSlotOptions&
 Options::get_controller_slot()
 {
   return controller_slots[controller_slot];
 }
 
-const Options::ControllerConfigs& 
+const ControllerSlotOptions&
 Options::get_controller_slot() const
 {
   ControllerSlots::const_iterator it = controller_slots.find(controller_slot);
@@ -110,7 +98,7 @@ Options::get_controller_slot() const
 ControllerOptions&
 Options::get_controller_options()
 {
-  return controller_slots[controller_slot][config_slot];
+  return controller_slots[controller_slot].get_options(config_slot);
 }
 
 const ControllerOptions&
@@ -123,8 +111,8 @@ Options::get_controller_options() const
   }
   else
   {
-    ControllerConfigs::const_iterator cfg = it->second.find(config_slot);
-    if (cfg == it->second.end())
+    ControllerSlotOptions::Options::const_iterator cfg = it->second.get_options().find(config_slot);
+    if (cfg == it->second.get_options().end())
     {
       assert(!"shouldn't happen either");
     }
@@ -142,7 +130,7 @@ Options::next_controller()
   config_slot = 0;
 
   // create the entry if not already available
-  controller_slots[controller_slot][config_slot];
+  controller_slots[controller_slot].get_options(config_slot);
 }
 
 void
@@ -157,7 +145,7 @@ Options::next_config()
   }
 
   // create the entry if not already available
-  controller_slots[controller_slot][config_slot];
+  controller_slots[controller_slot].get_options(config_slot);
 }
 
 void
@@ -211,4 +199,67 @@ Options::set_mimic_xpad()
   get_controller_options().uinput.mimic_xpad();
 }
 
+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::match_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::match_usb_path(bus, dev));
+    }
+  }
+  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::match_evdev_path(args[0]));
+    }
+  }
+  else
+  {
+    raise_exception(std::runtime_error, "'" << lhs << "' not a valid match rule name");
+  }
+}
+
+void
+Options::set_match(const std::string& str)
+{
+  process_name_value_string(str, boost::bind(&Options::add_match, this, _1, _2));
+}
+
+void
+Options::set_match_group(const std::string& str)
+{
+  // FIXME: not implied
+  assert(!"not implemented");
+}
+
 /* EOF */
diff --git a/src/options.hpp b/src/options.hpp
index 4d96555..a1d25dd 100644
--- a/src/options.hpp
+++ b/src/options.hpp
@@ -23,37 +23,12 @@
 #include <map>
 #include <vector>
 
+#include "controller_options.hpp"
+#include "controller_slot_options.hpp"
 #include "evdev_absmap.hpp"
 #include "uinput_options.hpp"
 #include "xpad_device.hpp"
 
-#include "modifier/axismap_modifier.hpp"
-#include "modifier/buttonmap_modifier.hpp"
-
-class ControllerOptions
-{
-public:
-  ControllerOptions();
-
-  UInputOptions uinput;
-  std::vector<ModifierPtr> modifier;
-
-  // everything below gets later converted into modifier
-  boost::shared_ptr<ButtonmapModifier> buttonmap;
-  boost::shared_ptr<AxismapModifier>   axismap;
-
-  int  deadzone;
-  int  deadzone_trigger;
-  bool square_axis;
-  bool four_way_restrictor;
-  int  dpad_rotation;
-
-  std::map<XboxAxis, AxisFilterPtr> calibration_map;
-  std::map<XboxAxis, AxisFilterPtr> sensitivity_map;
-  std::map<XboxAxis, AxisFilterPtr> relative_axis_map;
-  std::map<XboxButton, ButtonFilterPtr> autofire_map;
-};
-
 class Options
 {
 public:
@@ -111,8 +86,7 @@ public:
   std::map<int, XboxButton> evdev_keymap;
 
   // controller options
-  typedef std::map<int, ControllerOptions> ControllerConfigs;
-  typedef std::map<int, ControllerConfigs> ControllerSlots;
+  typedef std::map<int, ControllerSlotOptions> ControllerSlots;
   ControllerSlots controller_slots;
 
   // chatpad options
@@ -146,8 +120,8 @@ public:
 public:
   Options();
 
-  ControllerConfigs& get_controller_slot();
-  const ControllerConfigs& get_controller_slot() const;
+  ControllerSlotOptions& get_controller_slot();
+  const ControllerSlotOptions& get_controller_slot() const;
   
   /** Returns the currently active configuration */
   ControllerOptions& get_controller_options();
@@ -165,6 +139,10 @@ public:
   void set_dpad_only();
   void set_force_feedback();
   void set_mimic_xpad();
+
+  void add_match(const std::string& lhs, const std::string& rhs);
+  void set_match(const std::string& str);
+  void set_match_group(const std::string& str);
 };
 
 extern Options* g_options;
diff --git a/src/xboxdrv_daemon.cpp b/src/xboxdrv_daemon.cpp
index b76b922..b9a0dc9 100644
--- a/src/xboxdrv_daemon.cpp
+++ b/src/xboxdrv_daemon.cpp
@@ -214,7 +214,8 @@ XboxdrvDaemon::run_real(const Options& opts)
       log_info << "creating slot: " << slot_count << std::endl;
       m_controller_slots.push_back(ControllerSlot(ControllerConfigSet::create(*uinput, slot_count,
                                                                               opts.extra_devices,
-                                                                              controller->second)));
+                                                                              controller->second),
+                                                  controller->second.get_match_rules()));
       slot_count += 1;
     }
 
diff --git a/src/xboxdrv_daemon.hpp b/src/xboxdrv_daemon.hpp
index 8f24bed..21c666e 100644
--- a/src/xboxdrv_daemon.hpp
+++ b/src/xboxdrv_daemon.hpp
@@ -24,6 +24,7 @@
 #include <vector>
 
 #include "controller_config_set.hpp"
+#include "controller_match_rule.hpp"
 
 class Options;
 class UInput;
@@ -39,21 +40,26 @@ private:
   struct ControllerSlot
   {
     ControllerConfigSetPtr config;
+    std::vector<ControllerMatchRule> match;
     XboxdrvThread* thread;
     
     ControllerSlot() :
       config(),
+      match(),
       thread(0)
     {}
 
     ControllerSlot(ControllerConfigSetPtr config_,
+                   std::vector<ControllerMatchRule> match_,
                    XboxdrvThread* thread_ = 0) :
       config(config_),
+      match(match_),
       thread(thread_)
     {}
 
     ControllerSlot(const ControllerSlot& rhs) :
       config(rhs.config),
+      match(rhs.match),
       thread(rhs.thread)
     {}
 
@@ -62,6 +68,7 @@ private:
       if (&rhs != this)
       {
         config = rhs.config;
+        match  = rhs.match;
         thread = rhs.thread;
       }
       return *this;