diff --git a/TODO b/TODO
index 626e96d..e8b6ae8 100644
--- a/TODO
+++ b/TODO
@@ -81,6 +81,16 @@ Checklist
 
 * search for "#ifdef FIXME"
 
+* do proper error checking: 
+
+xboxdrv: src/usb_controller.cpp:218: void USBController::on_read_data(libusb_transfer*): Assertion `ret == LIBUSB_SUCCESS' failed.
+Aborted
+
+* exceptions in glib main loop might be dangerous
+
+* invert y axis on --evdev
+
+
 
 Stuff to do before 0.7.4 release:
 =================================
@@ -515,8 +525,6 @@ Stuff to do before 0.7.x release:
 * add extra checks to make sure the evdev buttons and axis given exist
   on the current device when using --evdev
 
-* invert y axis on --evdev
-
 * allow --type to work even when --device-by-id is not given
 
 * axis emulation
diff --git a/src/evdev_controller.cpp b/src/evdev_controller.cpp
index 3f672fb..6c2d258 100644
--- a/src/evdev_controller.cpp
+++ b/src/evdev_controller.cpp
@@ -127,22 +127,25 @@ EvdevController::EvdevController(const std::string& filename,
     m_io_channel = g_io_channel_unix_new(m_fd);
 
     // set encoding to binary
-    GError* error;
+    GError* error = NULL;
     if (g_io_channel_set_encoding(m_io_channel, NULL, &error) != G_IO_STATUS_NORMAL)
     {
       log_error(error->message);
       g_error_free(error);
     }
 
+    g_io_channel_set_buffered(m_io_channel, false);
+
     guint source_id;
-    source_id = g_io_add_watch(m_io_channel, static_cast<GIOCondition>(G_IO_IN | G_IO_ERR),
+    source_id = g_io_add_watch(m_io_channel, 
+                               static_cast<GIOCondition>(G_IO_IN | G_IO_ERR | G_IO_HUP),
                                &EvdevController::on_read_data_wrap, this);
   }
 }
 
 EvdevController::~EvdevController()
 {
-  g_io_channel_close(m_io_channel);
+  g_io_channel_unref(m_io_channel);
 }
 
 void
@@ -158,7 +161,7 @@ EvdevController::set_led(uint8_t status)
 }
 
 bool
-EvdevController::apply(XboxGenericMsg& msg, const struct input_event& ev)
+EvdevController::parse(const struct input_event& ev, XboxGenericMsg& msg_inout) const
 {
   if (m_debug)
   {
@@ -195,10 +198,10 @@ EvdevController::apply(XboxGenericMsg& msg, const struct input_event& ev)
   {
     case EV_KEY:
       {
-        KeyMap::iterator it = m_keymap.find(ev.code);
+        KeyMap::const_iterator it = m_keymap.find(ev.code);
         if (it != m_keymap.end())
         {
-          set_button(msg, it->second, ev.value);
+          set_button(msg_inout, it->second, ev.value);
           return true;
         }
         else
@@ -211,7 +214,7 @@ EvdevController::apply(XboxGenericMsg& msg, const struct input_event& ev)
     case EV_ABS:
       {
         const struct input_absinfo& absinfo = m_absinfo[ev.code];
-        m_absmap.process(msg, ev.code, ev.value, absinfo.minimum, absinfo.maximum);
+        m_absmap.process(msg_inout, ev.code, ev.value, absinfo.minimum, absinfo.maximum);
         return true; // FIXME: wrong
         break;
       }
@@ -223,52 +226,27 @@ EvdevController::apply(XboxGenericMsg& msg, const struct input_event& ev)
   }
 }
 
-void
-EvdevController::read_data_to_buffer()
+gboolean
+EvdevController::on_read_data(GIOChannel* source, GIOCondition condition)
 {
+  // read data
   struct input_event ev[128];
   int rd = 0;
   while((rd = ::read(m_fd, ev, sizeof(struct input_event) * 128)) > 0)
   {
     for (size_t i = 0; i < rd / sizeof(struct input_event); ++i)
     {
-      m_event_buffer.push(ev[i]);
+      if (ev[i].type == EV_SYN)
+      {
+        submit_msg(m_msg);
+      }
+      else
+      {
+        parse(ev[i], m_msg);
+      }
     }
   }
-}
-
-bool
-EvdevController::read(XboxGenericMsg& msg, int timeout)
-{
-  read_data_to_buffer();
-
-  while(!m_event_buffer.empty())
-  {
-    struct input_event ev = m_event_buffer.front();
-    m_event_buffer.pop();
-
-    if (ev.type == EV_SYN)
-    {
-      msg = m_msg;
-      return true;
-    }
-    else
-    {
-      apply(m_msg, ev);
-    }
-  }
-
-  usleep(timeout * 1000);
-
-  return false;
-}
-
-gboolean
-EvdevController::on_read_data(GIOChannel* source, GIOCondition condition)
-{
-  //int fd = g_io_channel_unix_get_fd(source);
   
-  // process data
   return TRUE;
 }
 
diff --git a/src/evdev_controller.hpp b/src/evdev_controller.hpp
index 46e7e8f..70f3cf2 100644
--- a/src/evdev_controller.hpp
+++ b/src/evdev_controller.hpp
@@ -65,12 +65,11 @@ public:
   bool read(XboxGenericMsg& msg, int timeout);
 
 private:
-  bool apply(XboxGenericMsg& msg, const struct input_event& ev);
+  bool parse(const struct input_event& ev, XboxGenericMsg& msg_inout) const;
   void read_data_to_buffer();
 
   gboolean on_read_data(GIOChannel* source,
                         GIOCondition condition);
-
   static gboolean on_read_data_wrap(GIOChannel* source,
                                     GIOCondition condition,
                                     gpointer userdata)