diff --git a/chatpad/SConstruct b/chatpad/SConstruct
new file mode 100644
index 0000000..d293270
--- /dev/null
+++ b/chatpad/SConstruct
@@ -0,0 +1,11 @@
+env = Environment(CXXFLAGS=["-Werror", "-Wall"], LIBS=["usb", "boost_thread"])
+env.Program("chatpad", ["chatpad.cpp"])
+
+env = Environment(CXXFLAGS=["-Werror", "-Wall"], LIBS=["usb-1.0", "boost_thread"])
+env.Program("chatpad2", ["chatpad2.cpp"])
+
+env = Environment(CXXFLAGS=["-Werror", "-Wall"], LIBS=["usb-1.0", "boost_thread"])
+env.Program("reset", ["reset.cpp"])
+
+# EOF #
+
diff --git a/chatpad/chatpad.cpp b/chatpad/chatpad.cpp
new file mode 100644
index 0000000..5a08319
--- /dev/null
+++ b/chatpad/chatpad.cpp
@@ -0,0 +1,114 @@
+#include <boost/thread.hpp>
+#include <boost/format.hpp>
+#include <usb.h>
+#include <iostream>
+#include <stdexcept>
+
+struct usb_device* find_controller()
+{
+  struct usb_bus* busses = usb_get_busses();
+
+  for (struct usb_bus* bus = busses; bus; bus = bus->next)
+  {
+    for (struct usb_device* dev = bus->devices; dev; dev = dev->next)
+    {
+      if (dev->descriptor.idVendor  == 0x045e &&
+          dev->descriptor.idProduct == 0x028e)
+      {
+          return dev;
+      }
+    }
+  }
+  return 0;
+}
+
+void read_thread(struct usb_dev_handle* handle)
+{
+  uint8_t data[5];
+  while(true)
+  {
+    std::cout << "reading" << std::endl;
+    int len = usb_interrupt_read(handle, 6, reinterpret_cast<char*>(data), sizeof(data), 0);
+    if (len < 0)
+    {
+      std::cout << "Error in read_thread" << std::endl;
+      return;
+    }
+    else
+    {
+      std::cout << "read: " << len << "/32: data: " << std::flush;
+      for(int i = 0; i < len; ++i)
+      {
+        std::cout << boost::format("0x%02x ") % int(data[i]);
+      }
+      std::cout << std::endl;
+    }
+  }
+}
+
+int main()
+{
+  try 
+  {
+    usb_init();
+    usb_find_busses();
+    usb_find_devices();
+
+    struct usb_device* dev = find_controller();
+
+    if (!dev)
+    {
+      throw std::runtime_error("Couldn't find controller");
+    }
+    else
+    {
+      std::cout << "Controller found, ready to go" << std::endl;
+
+      struct usb_dev_handle* handle = usb_open(dev);
+      if (!handle)
+      {
+        throw std::runtime_error("Failed to open controller");
+      }
+
+      int err = usb_claim_interface(handle, 2);
+      std::cout << "Claim: " << err << std::endl;
+
+      boost::thread thread(boost::bind(&read_thread, handle));
+
+      while(true)
+      {
+        usb_control_msg(handle, 0x41, 0x0, 0x1f, 0x02, 0, NULL, 0);
+        std::cout << "0x1f" << std::endl;
+        sleep(1);
+       
+        usb_control_msg(handle, 0x41, 0x0, 0x1e, 0x02, 0, NULL, 0);
+        std::cout << "0x1e" << std::endl;
+        sleep(1);
+
+        //usb_control_msg(handle, 0x41, 0x0, 0x15, 0x02, 0, NULL, 0);
+        //std::cout << "led and long sleep" << std::endl;
+        usb_control_msg(handle, 0x41, 0x0, 0x1b, 0x02, 0, NULL, 0);
+        sleep(1);
+
+
+        usb_control_msg(handle, 0x41, 0x0, 0x1b, 0x02, 0, NULL, 0);
+        sleep(1);
+
+        usb_control_msg(handle, 0x41, 0x0, 0x1b, 0x02, 0, NULL, 0);
+        sleep(1);
+
+        //std::usb_reset(usb_dev_handle *dev);
+      }
+
+      usb_close(handle);
+    }
+  }
+  catch(const std::exception& err)
+  {
+    std::cout << "Error: " << err.what() << std::endl;
+  }
+  
+  return 0;
+}
+
+/* EOF */
diff --git a/chatpad/chatpad2.cpp b/chatpad/chatpad2.cpp
new file mode 100644
index 0000000..44a3ad9
--- /dev/null
+++ b/chatpad/chatpad2.cpp
@@ -0,0 +1,286 @@
+#include <boost/thread.hpp>
+#include <boost/format.hpp>
+#include <boost/function.hpp>
+#include <boost/scoped_array.hpp>
+#include <libusb-1.0/libusb.h>
+#include <iostream>
+#include <stdexcept>
+
+class Main
+{
+private:
+  libusb_context*       m_ctx;
+  libusb_device_handle* m_handle;
+
+  uint8_t old_buttons;
+  uint8_t old_dpad;
+
+public:
+  Main() :
+    m_ctx(0),
+    m_handle(0),
+    old_buttons(0),
+    old_dpad(0)
+  {}
+
+  ~Main()
+  {
+  }
+
+  void init_libusb()
+  {    
+    if (libusb_init(&m_ctx) != 0)
+    {
+      throw std::runtime_error("Libusb went wrong");
+    }
+
+    std::cout << "Debug to max" << std::endl;
+    libusb_set_debug(m_ctx, 3);
+  }
+
+  void init_device_handle()
+  {
+    m_handle = libusb_open_device_with_vid_pid(m_ctx, 0x045e, 0x028e);
+
+    std::cout << "handle: " << m_handle << std::endl;
+    if (!m_handle)
+    {
+      throw std::runtime_error("Couldn't find controller");
+    }
+
+    int err = libusb_claim_interface(m_handle, 2);
+    std::cout << "Claim: " << err << std::endl;
+
+    err = libusb_claim_interface(m_handle, 0);
+    std::cout << "Claim: " << err << std::endl;
+  }
+
+  void reset()
+  {
+    std::cout << "reset()" << std::endl;
+    libusb_reset_device(m_handle);
+    libusb_close(m_handle);
+    m_handle = 0;
+    sleep(1);
+    init_device_handle();
+  }
+
+  void ctrl_msg(uint8_t value)
+  {
+    int ret = libusb_control_transfer(m_handle,
+                                      LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_INTERFACE,
+                                      LIBUSB_REQUEST_GET_STATUS,
+                                      value, 0x02, NULL, 0, 0);
+    std::cout << "ctrl_msg: " << ret << boost::format(" %02x") % int(value) << std::endl;
+  }
+
+  void main_loop()
+  {
+    if (0)
+    {
+      ctrl_msg(0x1f);
+      sleep(1);
+      
+      ctrl_msg(0x1e);
+      sleep(1);
+
+      ctrl_msg(0x1b);
+      sleep(1);
+
+      ctrl_msg(0x1b);
+      sleep(1);
+
+      ctrl_msg(0x1f);
+      sleep(1);
+
+      ctrl_msg(0x18);
+      sleep(1);
+
+      ctrl_msg(0x10);
+      sleep(1);
+
+      ctrl_msg(0x03);
+      sleep(1);
+    }
+
+    while(true)
+    {
+      sleep(1);
+    }
+  }
+
+  void read_thread(const std::string& prefix, int endpoint, boost::function<void (uint8_t*)> callback)
+  {
+    boost::scoped_array<uint8_t> data;
+
+    int data_len = 32;
+    if (endpoint == 6)
+    {
+      data.reset(new uint8_t[32]);
+    }
+    else 
+    {
+      data.reset(new uint8_t[32]);
+    }
+
+    while(true)
+    {
+      //std::cout << "reading" << std::endl;
+      int transfered = -1;
+
+      //int ret = libusb_interrupt_transfer(m_handle, 6 | LIBUSB_ENDPOINT_IN, 
+      //data, sizeof(data),
+      //&transfered, 0);
+
+      int ret = libusb_interrupt_transfer(m_handle, endpoint | LIBUSB_ENDPOINT_IN, 
+                                          data.get(), data_len,
+                                          &transfered, 0);
+      switch(ret)
+      {
+        case 0: // success
+          {
+            if (transfered != 20)
+            {
+              std::cout << prefix << "read(" << endpoint << "): " << transfered << "/32: data: " << std::flush;
+              for(int i = 0; i < transfered; ++i)
+              {
+                std::cout << boost::format("0x%02x ") % int(data[i]);
+              }
+              std::cout << std::endl;
+            }
+
+            if (callback)
+            {
+              callback(data.get());
+            }
+          }
+          break;
+
+        case LIBUSB_ERROR_TIMEOUT:
+          std::cout << "read_thread: timeout" << std::endl;
+          break;
+
+        case LIBUSB_ERROR_PIPE:
+          std::cout << "read_thread: pipe" << std::endl;
+          break;
+
+        case LIBUSB_ERROR_OVERFLOW:
+          std::cout << "read_thread: overflow" << std::endl;
+          break;
+
+        case LIBUSB_ERROR_NO_DEVICE:
+          std::cout << "read_thread: no device" << std::endl;
+          break;
+        
+        default:
+          std::cout << "read_thread: unknown: " << ret << std::endl;
+          break;
+      }
+    }
+  }
+
+  void process_input(uint8_t* data)
+  {
+    uint8_t buttons = data[3];
+    uint8_t dpad    = data[2];
+
+    // only keep data that changed
+    buttons = buttons & (buttons ^ old_buttons);
+    dpad    = dpad    & (dpad    ^ old_dpad);
+
+    old_buttons = buttons;
+    old_dpad    = dpad;
+
+    switch(dpad)
+    {
+      case 0x04: // left
+        break;
+
+      case 0x08: // right
+        break;
+
+      case 0x01: // up        
+        break;
+
+      case 0x02: // down
+        break;
+
+      case 0x20: // back
+        break;
+
+      case 0x10: // start
+        break;
+
+      case 0x40: // left stick
+        break;
+
+      case 0x80: // right stick
+        break;
+    }
+
+    switch(buttons)
+    {
+      case 0x10: // a
+        ctrl_msg(0x1f);
+        break;
+
+      case 0x20: // b
+        ctrl_msg(0x1e);
+        break;
+
+      case 0x40: // x
+        ctrl_msg(0x1b);
+        break;
+
+      case 0x80: // y
+        ctrl_msg(0x10);
+        break;
+
+      case 0x01: // lb
+        ctrl_msg(0x05);
+        break;
+
+      case 0x02: // rb
+        ctrl_msg(0x06);
+        break;
+
+      case 0x04: // guide
+        ctrl_msg(0x17);
+        break;
+    }
+  }
+
+  void run()
+  {
+    init_libusb();
+    init_device_handle();
+
+    {
+      boost::thread thread(boost::bind(&Main::read_thread, this, "cpad: ", 6, boost::function<void (uint8_t*)>()));
+      
+      boost::function<void (uint8_t*)> cb = boost::bind(&Main::process_input, this, _1);
+      boost::thread thread2(boost::bind(&Main::read_thread, this, "data: ", 1, cb));
+      main_loop();
+    }
+
+    libusb_close(m_handle);
+    libusb_exit(m_ctx);
+  }
+};
+
+int main()
+{
+  try 
+  {
+    Main app;
+    app.run();
+  }
+  catch(const std::exception& err)
+  {
+    std::cout << "Error: " << err.what() << std::endl;
+  }
+  
+  return 0;
+}
+
+/* EOF */
diff --git a/chatpad/reset.cpp b/chatpad/reset.cpp
new file mode 100644
index 0000000..108ed46
--- /dev/null
+++ b/chatpad/reset.cpp
@@ -0,0 +1,31 @@
+#include <libusb-1.0/libusb.h>
+#include <iostream>
+#include <stdexcept>
+
+int main()
+{
+  libusb_context*       ctx = 0;
+  libusb_device_handle* handle = 0;
+
+  if (libusb_init(&ctx) != 0)
+  {
+    throw std::runtime_error("Libusb went wrong");
+  }
+
+  handle = libusb_open_device_with_vid_pid(ctx, 0x045e, 0x028e);
+
+  if (!handle)
+  {
+    std::cout << "Couldn't find device" << std::endl;
+  }
+  else
+  {
+    std::cout << "Resetting" << std::endl;
+    libusb_reset_device(handle);
+    libusb_close(handle);
+  }
+  libusb_exit(ctx);
+
+  return 0;
+}
+