From d047b207ee5668f1d2eb862168c6b36af3ab9458 Mon Sep 17 00:00:00 2001
From: Ingo Ruhnke <grumbel@gmx.de>
Date: Wed, 29 Jul 2009 15:43:23 +0200
Subject: [PATCH] Some experimental work on using threads for reading from USB

---
 src/usb_read_thread.cpp | 96 +++++++++++++++++++++++++++++++++++++++++
 src/usb_read_thread.hpp | 63 +++++++++++++++++++++++++++
 2 files changed, 159 insertions(+)
 create mode 100644 src/usb_read_thread.cpp
 create mode 100644 src/usb_read_thread.hpp

diff --git a/src/usb_read_thread.cpp b/src/usb_read_thread.cpp
new file mode 100644
index 0000000..9be1d32
--- /dev/null
+++ b/src/usb_read_thread.cpp
@@ -0,0 +1,96 @@
+/* 
+**  Xbox/Xbox360 USB Gamepad Userspace Driver
+**  Copyright (C) 2008 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 <assert.h>
+#include <boost/thread/thread.hpp>
+#include <usb.h>
+#include "usb_read_thread.hpp"
+
+USBReadThread::USBReadThread(struct usb_dev_handle* handle, int endpoint, int len) : 
+  m_handle(handle),
+  m_read_endpoint(endpoint),
+  m_read_length(len),
+  m_stop(false)
+{
+}
+
+USBReadThread::~USBReadThread()
+{
+}
+  
+void
+USBReadThread::start_thread()
+{
+  m_stop = false;
+  m_thread = boost::thread(boost::bind(&USBReadThread::run, this));
+}
+
+void
+USBReadThread::stop_thread()
+{
+  m_stop = true;
+  m_thread.join();
+}
+
+int
+USBReadThread::read(uint8_t* data, int len)
+{
+  boost::mutex::scoped_lock lock(m_read_buffer_mutex);
+
+  if (m_read_buffer.empty())
+    {
+      return 0;
+    }
+  else
+    {
+      assert(len == m_read_length);
+
+      Paket& paket = m_read_buffer.front();
+
+      memcpy(data, paket.data, m_read_length);
+      delete[] paket.data;
+      int ret = paket.length;
+
+      m_read_buffer.pop_front();
+  
+      return ret;
+    }
+}
+
+void
+USBReadThread::run()
+{
+  while(!m_stop)
+    {
+      uint8_t* data = new uint8_t[m_read_length];
+
+      int ret = usb_interrupt_read(m_handle, m_read_endpoint, (char*)data, sizeof(data), 0 /*timeout*/);
+
+      {
+        boost::mutex::scoped_lock lock(m_read_buffer_mutex);
+
+        Paket paket;
+        paket.data   = data;
+        paket.length = ret;
+
+        m_read_buffer.push_back(paket);
+      }
+    }
+}
+
+/* EOF */
diff --git a/src/usb_read_thread.hpp b/src/usb_read_thread.hpp
new file mode 100644
index 0000000..318716a
--- /dev/null
+++ b/src/usb_read_thread.hpp
@@ -0,0 +1,63 @@
+/*
+**  Windstille - A Sci-Fi Action-Adventure Game
+**  Copyright (C) 2009 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_USB_READ_THREAD_HPP
+#define HEADER_USB_READ_THREAD_HPP
+
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/thread.hpp>
+#include <list>
+
+class USBReadThread
+{
+private:
+  struct usb_dev_handle* m_handle;
+  const int m_read_endpoint;
+  const int m_read_length;
+
+  struct Paket {
+    uint8_t* data;
+    int      length;
+  };
+
+  std::list<Paket> m_read_buffer;
+  boost::mutex m_read_buffer_mutex;
+  boost::thread m_thread;
+
+  bool m_stop;
+
+public:
+  USBReadThread(struct usb_dev_handle* handle, int endpoint, int len);
+  ~USBReadThread();
+
+  int read(uint8_t* data, int len);
+
+  void start_thread();
+  void stop_thread();
+
+private:
+  void run();
+
+private:
+  USBReadThread(const USBReadThread&);
+  USBReadThread& operator=(const USBReadThread&);
+};
+
+#endif
+
+/* EOF */