copied glibusb in and started making it compile
diff --git a/aos/common/glibusb/CMakeLists.txt b/aos/common/glibusb/CMakeLists.txt
new file mode 100644
index 0000000..11151fe
--- /dev/null
+++ b/aos/common/glibusb/CMakeLists.txt
@@ -0,0 +1,93 @@
+cmake_minimum_required(VERSION 2.8)
+project(glibusb)
+
+enable_testing()
+
+find_package(Boost REQUIRED COMPONENTS thread date_time)	# need >= 1.48
+find_package(PkgConfig REQUIRED)
+#pkg_check_modules(LIBUSB REQUIRED libusb-1.0)
+pkg_check_modules(GFLAGS REQUIRED libgflags)
+pkg_check_modules(GLOG REQUIRED libglog)
+
+add_definitions("-std=c++11 -Wall -Wextra")
+
+set(GTEST_INCLUDEDIR "/usr/src/gtest")
+set(GTEST_SRCS
+  /usr/src/gtest/src/gtest_main.cc
+  /usr/src/gtest/src/gtest-all.cc
+)
+
+
+include_directories(
+  ${Boost_INCLUDE_DIRS}
+  /usr/include/libusb-1.0
+  ${GFLAGS_INCLUDE_DIRS}
+  ${GLOG_INCLUDE_DIRS}
+  ${GTEST_INCLUDEDIR}
+)
+
+link_directories(
+  ${Boost_LIBRARY_DIRS}
+  ${GFLAGS_LIBRARY_DIRS}
+  ${GLOG_LIBRARY_DIRS}
+)
+
+set(LIBRARIES
+  ${Boost_LIBRARIES}
+  usb-1.0
+  ${GFLAGS_LIBRARIES}
+  ${GLOG_LIBRARIES}
+  pthread
+)
+
+set(HEADERS
+  gbuffer.h
+  ghexdump.h
+  glibusb_device_internal.h
+  glibusb_endpoint.h
+  glibusb_endpoint_internal.h
+  glibusb.h
+  glibusb_internal.h
+  glibusb_transfer.h
+)
+
+#
+add_library(glibusb
+  gbuffer.cc
+  glibusb.cc
+  glibusb_device.cc
+  glibusb_endpoint.cc
+  glibusb_internal.cc
+  glibusb_transfer.cc
+  ghexdump.cc
+)
+target_link_libraries(glibusb ${LIBRARIES})
+
+#
+add_executable(gbuffer_test
+  testing/gbuffer_test.cc
+  ${GTEST_SRCS}
+)
+target_link_libraries(gbuffer_test glibusb ${LIBRARIES})
+add_test(gbuffer_test gbuffer_test)
+
+#
+add_executable(glibusb_test
+  testing/glibusb_test.cc
+  ${GTEST_SRCS}
+)
+target_link_libraries(glibusb_test glibusb ${LIBRARIES})
+add_test(glibusb_test glibusb_test)
+
+install(TARGETS glibusb 
+  LIBRARY DESTINATION lib COMPONENT Runtime
+  ARCHIVE DESTINATION lib COMPONENT Runtime
+)
+install(FILES ${HEADERS}
+  DESTINATION /usr/include/glibusb
+  COMPONENT Development)
+
+set(CPACK_GENERATOR DEB)
+set(CPACK_PACKAGE_VERSION "1.0.14")
+set(CPACK_PACKAGE_CONTACT "charliehotel@google.com")
+include(CPack)
diff --git a/aos/common/glibusb/LICENSE b/aos/common/glibusb/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/aos/common/glibusb/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/aos/common/glibusb/NOTICE b/aos/common/glibusb/NOTICE
new file mode 100644
index 0000000..a0af402
--- /dev/null
+++ b/aos/common/glibusb/NOTICE
@@ -0,0 +1 @@
+This code is originally from <https://code.google.com/p/google-libusb/>.
diff --git a/aos/common/glibusb/gbuffer.cc b/aos/common/glibusb/gbuffer.cc
new file mode 100644
index 0000000..b675953
--- /dev/null
+++ b/aos/common/glibusb/gbuffer.cc
@@ -0,0 +1,323 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Modified by FRC Team 971.
+//
+
+#include "gbuffer.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <cstring>
+
+#include "aos/common/logging/logging.h"
+
+#include "ghexdump.h"
+
+namespace glibusb {
+
+Buffer::Buffer() {}
+
+Buffer::~Buffer() {}
+
+Buffer::Buffer(const void *src, Buffer::size_type length) {
+  buffer_.resize(length);
+  if (length > 0) {
+    uint8_t *dst = &(buffer_[0]);
+    memcpy(dst, src, length);
+  }
+}
+
+bool Buffer::operator==(const Buffer &other) const {
+  return buffer_ == other.buffer_;
+}
+
+bool Buffer::operator!=(const Buffer &other) const {
+  return !(*this == other);
+}
+
+Buffer *Buffer::MakeSlice(Buffer::size_type offset,
+                          Buffer::size_type length) const {
+  CHECK_LE(offset + length, buffer_.size());
+  if (length == 0) {
+    return new Buffer();
+  } else {
+    const uint8_t *p = &(buffer_[offset]);
+    return new Buffer(p, length);
+  }
+}
+
+void Buffer::Clear() {
+  buffer_.clear();
+}
+
+void Buffer::Resize(Buffer::size_type length) {
+  buffer_.resize(length);
+}
+
+void *Buffer::GetBufferPointer(Buffer::size_type length) {
+  return GetBufferPointer(0, length);
+}
+
+const void *Buffer::GetBufferPointer(Buffer::size_type length) const {
+  return GetBufferPointer(0, length);
+}
+
+void *Buffer::GetBufferPointer(Buffer::size_type offset,
+                               Buffer::size_type length) {
+  if (length == 0) {
+    return NULL;
+  } else {
+    CHECK_LE(offset + length, buffer_.size());
+    uint8_t *p = &(buffer_[offset]);
+    return static_cast<void *>(p);
+  }
+}
+
+const void *Buffer::GetBufferPointer(Buffer::size_type offset,
+                                     Buffer::size_type length) const {
+  if (length == 0) {
+    return NULL;
+  } else {
+    CHECK_LE(offset + length, buffer_.size());
+    const uint8_t *p = &(buffer_[offset]);
+    return static_cast<const void *>(p);
+  }
+}
+
+// Specialized template for Get
+template <>
+Buffer::size_type Buffer::Get(Buffer::size_type byte_offset,
+                              uint8_t *value_out) const {
+  CHECK_LT(byte_offset, buffer_.size());
+  *CHECK_NOTNULL(value_out) = buffer_[byte_offset];
+  return sizeof(uint8_t);
+}
+
+// Specialized template for Get
+template <>
+Buffer::size_type Buffer::Get(Buffer::size_type byte_offset,
+                              int8_t *value_out) const {
+  uint8_t value;
+  Get(byte_offset, &value);
+  *CHECK_NOTNULL(value_out) = static_cast<int8_t>(value);
+  return sizeof(int8_t);
+}
+
+// Specialized template for Get
+template <>
+Buffer::size_type Buffer::Get(Buffer::size_type byte_offset,
+                              uint16_t *value_out) const {
+  CHECK_LT(byte_offset + 1, buffer_.size());
+  uint16_t byte0 = static_cast<uint16_t>(buffer_[byte_offset]);
+  uint16_t byte1 = static_cast<uint16_t>(buffer_[byte_offset + 1]);
+  uint16_t value = byte0 | (byte1 << 8);
+  *CHECK_NOTNULL(value_out) = value;
+  return sizeof(uint16_t);
+}
+
+// Specialized template for Get
+template <>
+Buffer::size_type Buffer::Get(Buffer::size_type byte_offset,
+                              int16_t *value_out) const {
+  uint16_t value;
+  Get(byte_offset, &value);
+  *CHECK_NOTNULL(value_out) = static_cast<int16_t>(value);
+  return sizeof(int16_t);
+}
+
+// Specialized template for Get
+template <>
+Buffer::size_type Buffer::Get(Buffer::size_type byte_offset,
+                              uint32_t *value_out) const {
+  CHECK_LT(byte_offset + 3, buffer_.size());
+  uint32_t byte0 = static_cast<uint32_t>(buffer_[byte_offset]);
+  uint32_t byte1 = static_cast<uint32_t>(buffer_[byte_offset + 1]);
+  uint32_t byte2 = static_cast<uint32_t>(buffer_[byte_offset + 2]);
+  uint32_t byte3 = static_cast<uint32_t>(buffer_[byte_offset + 3]);
+  uint32_t value = byte0 | (byte1 << 8) | (byte2 << 16) | (byte3 << 24);
+  *CHECK_NOTNULL(value_out) = value;
+  return sizeof(uint32_t);
+}
+
+// Specialized template for Get
+template <>
+Buffer::size_type Buffer::Get(Buffer::size_type byte_offset,
+                              int32_t *value_out) const {
+  uint32_t value;
+  Get(byte_offset, &value);
+  *CHECK_NOTNULL(value_out) = static_cast<int32_t>(value);
+  return sizeof(int32_t);
+}
+
+// Specialized template for Get
+template <>
+Buffer::size_type Buffer::Get(Buffer::size_type byte_offset,
+                              uint64_t *value_out) const {
+  CHECK_LT(byte_offset + 7, buffer_.size());
+  uint64_t byte0 = static_cast<uint64_t>(buffer_[byte_offset]);
+  uint64_t byte1 = static_cast<uint64_t>(buffer_[byte_offset + 1]);
+  uint64_t byte2 = static_cast<uint64_t>(buffer_[byte_offset + 2]);
+  uint64_t byte3 = static_cast<uint64_t>(buffer_[byte_offset + 3]);
+  uint64_t byte4 = static_cast<uint64_t>(buffer_[byte_offset + 4]);
+  uint64_t byte5 = static_cast<uint64_t>(buffer_[byte_offset + 5]);
+  uint64_t byte6 = static_cast<uint64_t>(buffer_[byte_offset + 6]);
+  uint64_t byte7 = static_cast<uint64_t>(buffer_[byte_offset + 7]);
+  uint64_t value =
+      byte0 | (byte1 << 8) | (byte2 << 16) | (byte3 << 24) |
+      (byte4 << 32) | (byte5 << 40) | (byte6 << 48) | (byte7 << 56);
+  *CHECK_NOTNULL(value_out) = value;
+  return sizeof(uint64_t);
+}
+
+// Specialized template for Get
+template <>
+Buffer::size_type Buffer::Get(Buffer::size_type byte_offset,
+                              int64_t *value_out) const {
+  uint64_t value;
+  Get(byte_offset, &value);
+  *CHECK_NOTNULL(value_out) = static_cast<int64_t>(value);
+  return sizeof(int64_t);
+}
+
+Buffer::size_type Buffer::Get(Buffer::size_type byte_offset,
+                              std::string *out) const {
+  CHECK_NOTNULL(out);
+  out->clear();
+  size_type n = 0;
+  for (size_t i = byte_offset; /**/; ++i, ++n) {
+    uint8_t p;
+    Get(i, &p);
+    if (!p) {
+      break;
+    }
+    out->push_back(static_cast<char>(p));
+  }
+
+  // strings are always padded out to 4 bytes
+  n = (n + 3) & ~3;
+  return n;
+}
+
+// Specialized template for Put
+template <>
+Buffer::size_type Buffer::Put(Buffer::size_type byte_offset, uint8_t value) {
+  CHECK_LT(byte_offset, buffer_.size());
+  buffer_[byte_offset] = value;
+  return sizeof(uint8_t);
+}
+
+// Specialized template for Put
+template <>
+Buffer::size_type Buffer::Put(Buffer::size_type byte_offset, int8_t value) {
+  return Put(byte_offset, static_cast<uint8_t>(value));
+}
+
+// Specialized template for Put
+template <>
+Buffer::size_type Buffer::Put(Buffer::size_type byte_offset, uint16_t value) {
+  CHECK_LT(byte_offset + 1, buffer_.size());
+  uint8_t byte_0 = static_cast<uint8_t>(value & 0xff);
+  uint8_t byte_1 = static_cast<uint8_t>((value >> 8) & 0xff);
+  buffer_[byte_offset] = byte_0;
+  buffer_[byte_offset + 1] = byte_1;
+  return sizeof(uint16_t);
+}
+
+// Specialized template for Put
+template <>
+Buffer::size_type Buffer::Put(Buffer::size_type byte_offset, int16_t value) {
+  return Put(byte_offset, static_cast<uint16_t>(value));
+}
+
+// Specialized template for Put
+template <>
+Buffer::size_type Buffer::Put(Buffer::size_type byte_offset, uint32_t value) {
+  CHECK_LT(byte_offset + 3, buffer_.size());
+  uint8_t byte_0 = static_cast<uint8_t>(value & 0xff);
+  uint8_t byte_1 = static_cast<uint8_t>((value >> 8) & 0xff);
+  uint8_t byte_2 = static_cast<uint8_t>((value >> 16) & 0xff);
+  uint8_t byte_3 = static_cast<uint8_t>((value >> 24) & 0xff);
+  buffer_[byte_offset] = byte_0;
+  buffer_[byte_offset + 1] = byte_1;
+  buffer_[byte_offset + 2] = byte_2;
+  buffer_[byte_offset + 3] = byte_3;
+  return sizeof(uint32_t);
+}
+
+// Specialized template for Put
+template <>
+Buffer::size_type Buffer::Put(Buffer::size_type byte_offset, int32_t value) {
+  return Put(byte_offset, static_cast<uint32_t>(value));
+}
+
+// Specialized template for Put
+template <>
+Buffer::size_type Buffer::Put(Buffer::size_type byte_offset, uint64_t value) {
+  CHECK_LT(byte_offset + 7, buffer_.size());
+  uint8_t byte_0 = static_cast<uint8_t>(value & 0xff);
+  uint8_t byte_1 = static_cast<uint8_t>((value >> 8) & 0xff);
+  uint8_t byte_2 = static_cast<uint8_t>((value >> 16) & 0xff);
+  uint8_t byte_3 = static_cast<uint8_t>((value >> 24) & 0xff);
+  uint8_t byte_4 = static_cast<uint8_t>((value >> 32) & 0xff);
+  uint8_t byte_5 = static_cast<uint8_t>((value >> 40) & 0xff);
+  uint8_t byte_6 = static_cast<uint8_t>((value >> 48) & 0xff);
+  uint8_t byte_7 = static_cast<uint8_t>((value >> 56) & 0xff);
+  buffer_[byte_offset] = byte_0;
+  buffer_[byte_offset + 1] = byte_1;
+  buffer_[byte_offset + 2] = byte_2;
+  buffer_[byte_offset + 3] = byte_3;
+  buffer_[byte_offset + 4] = byte_4;
+  buffer_[byte_offset + 5] = byte_5;
+  buffer_[byte_offset + 6] = byte_6;
+  buffer_[byte_offset + 7] = byte_7;
+  return sizeof(uint64_t);
+}
+
+// Specialized template for Put
+template <>
+Buffer::size_type Buffer::Put(Buffer::size_type byte_offset, int64_t value) {
+  return Put(byte_offset, static_cast<uint64_t>(value));
+}
+
+void Buffer::Append(const Buffer &source) {
+  buffer_.insert(buffer_.end(), source.buffer_.begin(), source.buffer_.end());
+}
+
+void Buffer::AddHeader(Buffer::size_type length) {
+  buffer_.insert(buffer_.begin(), length, 0);
+}
+
+void Buffer::RemoveHeader(Buffer::size_type length) {
+  if (length > 0) {
+    CHECK_LE(length, buffer_.size());
+    buffer_.erase(buffer_.begin(), buffer_.begin() + length);
+  }
+}
+
+void Buffer::Copy(const Buffer &source) {
+  buffer_.assign(source.buffer_.begin(), source.buffer_.end());
+}
+
+#if 0
+void Buffer::WriteOrDie(File *fp) const {
+  size_type n = Length();
+  const void *p = GetBufferPointer(n);
+  fp->WriteOrDie(p, n);
+}
+
+void Buffer::WriteToPathOrDie(const char *name) const {
+  FileCloser file(File::OpenOrDie(name, "w"));
+  WriteOrDie(file.get());
+}
+#endif
+
+std::string Buffer::Dump() const {
+  size_type n = Length();
+  if (n == 0) {
+    return "";
+  } else {
+    return glibusb::Dump(&(buffer_[0]), n);
+  }
+}
+
+}  // namespace glibusb
diff --git a/aos/common/glibusb/gbuffer.h b/aos/common/glibusb/gbuffer.h
new file mode 100644
index 0000000..5c1d8c6
--- /dev/null
+++ b/aos/common/glibusb/gbuffer.h
@@ -0,0 +1,130 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// A buffer for dealing with data.  Some special support for PTP is
+// available.
+
+#ifndef _GLIBUSB_GBUFFER_H_
+#define _GLIBUSB_GBUFFER_H_
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+namespace glibusb {
+
+// Buffer of bytes.
+class Buffer {
+ public:
+  // Underlying byte store type.
+  typedef std::vector<uint8_t> ByteBuffer;
+  typedef ByteBuffer::size_type size_type;
+
+  // Destructor.
+  ~Buffer();
+
+  // Constructs an empty buffer.
+  Buffer();
+
+  // Constructs a buffer from memory of given length.  Data is copied.
+  // (This is an interface to C functions, chiefly, libusb, and should
+  // only be used for such purposes.)
+  Buffer(const void *src, size_type length);
+
+  // Returns true iff the buffers contain the same data.
+  bool operator==(const Buffer &other) const;
+
+  // Returns true iff the buffer does not contain the same data.
+  bool operator!=(const Buffer &other) const;
+
+  // Returns a new allocated slice of the buffer.
+  Buffer *MakeSlice(size_type offset, size_type length) const;
+
+  // Returns the length.
+  size_type Length() const { return buffer_.size(); }
+
+  // Clears (as in std::vector) the buffer.
+  void Clear();
+
+  // Resizes (as in std::vector) the buffer.
+  void Resize(size_type length);
+
+  // Returns a pointer to the underlying store that of a guaranteed
+  // length (or CHECK), possibly beginning at a given offset.  (These
+  // are interfaces to C functions, chiefly, libusb, and should only
+  // be used for such purposes.)
+  void *GetBufferPointer(size_type length);
+  const void *GetBufferPointer(size_type length) const;
+  void *GetBufferPointer(size_type offset, size_type length);
+  const void *GetBufferPointer(size_type offset, size_type length) const;
+
+  // Gets the value of integral type T from the buffer at the offset
+  // byte_offset, places it in value_out, and returns the length of
+  // the marshalled data.  The integer is expected to be in little
+  // endian format. This template is specialized for
+  // {int,uint}{8,16,32,64}_t.
+  template <class T>
+  size_type Get(size_type byte_offset, T *value_out) const;
+
+  // Gets an ASCII string from the buffer at the offset byte_offset,
+  // places it in value_out, and returns the length of the marshalled
+  // data.  The string data in the buffer is expected to be
+  // null-terminated.
+  size_type Get(size_type byte_offset, std::string *value_out) const;
+
+  // Puts the value of integral type T into the buffer offset
+  // byte_offset and returns the length of the marshalled data.  Data
+  // are put in little endian format. This template is specialized for
+  // {int,uint}{8,16,32,64}_t.
+  template <class T>
+  size_type Put(size_type byte_offset, T value);
+
+  // Appends the value of type T into the buffer offset byte_offset
+  // and returns the length of the marshalled data.  Data are appended
+  // in little endian format.  This template is available for
+  // {int,uint}{8,16,32,64}_t.
+  template <class T> void Append(const T value);
+
+  // Append a buffer.
+  void Append(const Buffer &buffer);
+
+  // Inserts length bytes of (uninitialized) space at the beginning of
+  // the buffer.
+  void AddHeader(size_type length);
+
+  // Removes length bytes of space from the beginning of the buffer.
+  void RemoveHeader(size_type length);
+
+  // Copies the source buffer.
+  void Copy(const Buffer &source);
+
+#if 0
+  // Writes the contents of the buffer to the file, or dies.
+  void WriteOrDie(File *fp) const;
+
+  // Writes the contents of the buffer to the path, or dies.
+  void WriteToPathOrDie(const char *name) const;
+#endif
+
+  // Returns a hex dump of the buffer.
+  std::string Dump() const;
+
+ private:
+  // The underlying byte store.
+  ByteBuffer buffer_;
+
+  Buffer(const Buffer &) = delete;
+  void operator=(const Buffer &) = delete;
+};
+
+
+// Template for Buffer::Append for integral values.
+template <typename T>
+void Buffer::Append(const T value) {
+  size_type offset = Length();
+  Resize(offset + sizeof(T));
+  Put(offset, value);
+}
+
+}  // namespace glibusb
+
+#endif  // _GLIBUSB_GBUFFER_H_
diff --git a/aos/common/glibusb/gbuffer_test.cc b/aos/common/glibusb/gbuffer_test.cc
new file mode 100644
index 0000000..0e6733f
--- /dev/null
+++ b/aos/common/glibusb/gbuffer_test.cc
@@ -0,0 +1,570 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+// Author: charliehotel@google.com (Christopher Hoover)
+//
+// Tests for Buffer.
+
+#include "../gbuffer.h"
+
+#include <stdint.h>
+#include <limits>
+
+#include <boost/scoped_ptr.hpp>
+#include <gtest/gtest.h>
+
+#define GG_LONGLONG(x) x##LL
+#define GG_ULONGLONG(x) x##ULL
+#define ARRAYSIZE(x) (static_cast<int>(sizeof(x)/sizeof(x[0])))
+
+namespace glibusb {
+namespace {
+
+typedef ::testing::Types<int8_t, int16_t, int32_t, int64_t,
+                         uint8_t, uint16_t, uint32_t, uint64_t> AllIntegerTypes;
+
+// Tests that a newly constructed buffer is empty.
+TEST(BufferTest, EmptyBufferLength) {
+  Buffer buffer;
+  EXPECT_EQ(0, buffer.Length());
+}
+
+// Tests clearing.
+TEST(BufferTest, EmptyBufferClear) {
+  Buffer buffer;
+  buffer.Append(uint8_t(1));
+  buffer.Clear();
+  EXPECT_EQ(0, buffer.Length());
+}
+
+// Tests resizing.
+TEST(BufferTest, EmptyBufferResize) {
+  Buffer buffer;
+  const int kSize = 100;
+  buffer.Resize(kSize);
+  EXPECT_EQ(kSize, buffer.Length());
+}
+
+// Tests getting a pointer on an empty buffer.
+TEST(BufferTest, EmptyBufferGetPointer) {
+  Buffer buffer;
+  void *p;
+  const void *cp;
+  p = buffer.GetBufferPointer(0);
+  EXPECT_EQ(NULL, p);
+  cp = buffer.GetBufferPointer(0);
+  EXPECT_EQ(NULL, cp);
+  p = buffer.GetBufferPointer(0, 0);
+  EXPECT_EQ(NULL, p);
+  cp = buffer.GetBufferPointer(0, 0);
+  EXPECT_EQ(NULL, cp);
+}
+
+// Tests getting a pointer on an empty buffer.
+TEST(BufferTest, ConstEmptyBufferGetPointer) {
+  const Buffer buffer;
+  const void *cp;
+  cp = buffer.GetBufferPointer(0);
+  EXPECT_EQ(NULL, cp);
+  cp = buffer.GetBufferPointer(0, 0);
+  EXPECT_EQ(NULL, cp);
+}
+
+
+// Tests Get on an empty buffer.
+template <typename T>
+class EmptyBufferGetDeathTest : public ::testing::Test {
+ public:
+  void Check() {
+    Buffer buffer;
+    T value;
+    EXPECT_DEATH(buffer.Get(0, &value), "Check failed");
+  }
+};
+
+// Tests Get for all types on an empty bufer.
+TYPED_TEST_CASE(EmptyBufferGetDeathTest, AllIntegerTypes);
+TYPED_TEST(EmptyBufferGetDeathTest, Check) {
+  this->Check();
+}
+
+
+// Tests Put on an empty buffer.
+template <typename T>
+class EmptyBufferPutDeathTest : public ::testing::Test {
+ public:
+  void Check() {
+    Buffer buffer;
+    T value(0);
+    EXPECT_DEATH(buffer.Put(0, value), "Check failed");
+  }
+};
+
+// Tests Put for all types on an empty bufer.
+TYPED_TEST_CASE(EmptyBufferPutDeathTest, AllIntegerTypes);
+TYPED_TEST(EmptyBufferPutDeathTest, Check) {
+  this->Check();
+}
+
+
+// Tests getting a string on an empty buffer.
+TEST(BufferDeathTest, EmptyBufferGetString) {
+  Buffer buffer;
+  std::string s;
+  EXPECT_DEATH(buffer.Get(0, &s), "Check failed");
+}
+
+
+// Tests removing the header from an empty buffer.
+TEST(BufferDeathTest, EmptyBufferRemoveHeader) {
+  Buffer buffer;
+  buffer.RemoveHeader(0);
+  EXPECT_EQ(0, buffer.Length());
+  EXPECT_DEATH(buffer.RemoveHeader(1), "Check failed");
+}
+
+
+// Tests adding a header of size 0.
+TEST(BufferTest, EmptyBufferAddHeader) {
+  Buffer buffer;
+  buffer.AddHeader(0);
+  EXPECT_EQ(0, buffer.Length());
+}
+
+
+// Tests adding a header of size > 0.
+TEST(BufferTest, EmptyBufferAddHeader2) {
+  Buffer buffer;
+  const int kSize = 100;
+  buffer.AddHeader(kSize);
+  EXPECT_EQ(kSize, buffer.Length());
+}
+
+
+// Tests copying an empty buffer.
+TEST(BufferTest, EmptyBufferCopy) {
+  Buffer buffer;
+  Buffer buffer2;
+  buffer2.Append(uint8_t(1));
+  buffer2.Copy(buffer);
+  EXPECT_EQ(0, buffer2.Length());
+}
+
+// Tests dumping an empty buffer.
+TEST(BufferTest, EmptyBufferDump) {
+  Buffer buffer;
+  std::string s = buffer.Dump();
+  EXPECT_EQ("", s);
+}
+
+
+// Tests slicing an empty buffer.
+TEST(BufferTest, EmptyBufferSlice) {
+  Buffer buffer;
+  boost::scoped_ptr<Buffer> slice(buffer.MakeSlice(0, 0));
+  EXPECT_EQ(slice->Length(), 0);
+}
+
+
+// Tests Get, Put and Append for signed and unsigned integers.
+template <typename T>
+class PutGetAppendIntegerTest : public ::testing::Test {
+ public:
+  void Check() {
+    static const T kValues[] = {
+      std::numeric_limits<T>::max(),
+      T(0),
+      std::numeric_limits<T>::min()
+    };
+
+    for (int i = 0; i < ARRAYSIZE(kValues); ++i) {
+      const T kValue = kValues[i];
+
+      // Tests Put - Get
+      {
+        Buffer buffer;
+        buffer.Resize(sizeof(T));
+        buffer.Put(0, kValue);
+        T check;
+        buffer.Get(0, &check);
+        EXPECT_EQ(kValue, check);
+      }
+
+      // Tests Append - Get
+      {
+        Buffer buffer;
+        buffer.Append(kValue);
+        T check;
+        buffer.Get(0, &check);
+        EXPECT_EQ(kValue, check);
+      }
+    }
+  }
+};
+
+// Tests Get, Put and Append for all signed integers.
+TYPED_TEST_CASE(PutGetAppendIntegerTest, AllIntegerTypes);
+TYPED_TEST(PutGetAppendIntegerTest, Check) {
+  this->Check();
+}
+
+const uint8_t kDeadBeef[] = {
+  0xef, 0xbe, 0xad, 0xde
+};
+
+// Test harness for a buffer construct from "C" data.
+class ConstructedFromDataBufferTest : public testing::Test {
+ protected:
+  void SetUp() {
+    buffer.reset(new Buffer(kDeadBeef, sizeof(kDeadBeef)));
+  }
+
+  boost::scoped_ptr<Buffer> buffer;
+};
+
+typedef ConstructedFromDataBufferTest ConstructedFromDataBufferDeathTest;
+
+// Tests constructing a buffer from "C" data.
+TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataBufferLength) {
+  EXPECT_EQ(sizeof(kDeadBeef), buffer->Length());
+}
+
+// Tests that a buffer constructed from "C" data contains the right
+// data.
+TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataByteAccess) {
+  for (int i = 0; i < ARRAYSIZE(kDeadBeef); ++i) {
+    uint8_t u8;
+    buffer->Get(i, &u8);
+    EXPECT_EQ(kDeadBeef[i], u8);
+  }
+}
+
+// Tests clearing.
+TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataClear) {
+  buffer->Clear();
+  EXPECT_EQ(0, buffer->Length());
+}
+
+// Tests resizing.
+TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataResize) {
+  const int kSize = 100;
+  buffer->Resize(kSize);
+  EXPECT_EQ(kSize, buffer->Length());
+}
+
+// Tests that getting a pointer works.
+TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataGetPointer) {
+  void *p;
+  const void *cp;
+  p = buffer->GetBufferPointer(0);
+  EXPECT_EQ(NULL, p);
+  cp = buffer->GetBufferPointer(0);
+  EXPECT_EQ(NULL, cp);
+  p = buffer->GetBufferPointer(0, 0);
+  EXPECT_EQ(NULL, p);
+  cp = buffer->GetBufferPointer(0, 0);
+  EXPECT_EQ(NULL, cp);
+
+  p = buffer->GetBufferPointer(2);
+  EXPECT_TRUE(p != NULL);
+  EXPECT_EQ(kDeadBeef[0], *static_cast<uint8_t *>(p));
+  EXPECT_EQ(kDeadBeef[1], *(static_cast<uint8_t *>(p) + 1));
+  cp = buffer->GetBufferPointer(2);
+  EXPECT_TRUE(p != NULL);
+  EXPECT_EQ(kDeadBeef[0], *static_cast<uint8_t *>(p));
+  EXPECT_EQ(kDeadBeef[1], *(static_cast<uint8_t *>(p) + 1));
+
+  p = buffer->GetBufferPointer(1, 2);
+  EXPECT_TRUE(p != NULL);
+  EXPECT_EQ(kDeadBeef[1], *static_cast<uint8_t *>(p));
+  EXPECT_EQ(kDeadBeef[2], *(static_cast<uint8_t *>(p) + 1));
+  cp = buffer->GetBufferPointer(1, 2);
+  EXPECT_TRUE(p != NULL);
+  EXPECT_EQ(kDeadBeef[1], *static_cast<uint8_t *>(p));
+  EXPECT_EQ(kDeadBeef[2], *(static_cast<uint8_t *>(p) + 1));
+
+  const Buffer &const_buffer(*buffer);
+  cp = const_buffer.GetBufferPointer(1, 2);
+  EXPECT_TRUE(p != NULL);
+  EXPECT_EQ(kDeadBeef[1], *static_cast<uint8_t *>(p));
+  EXPECT_EQ(kDeadBeef[2], *(static_cast<uint8_t *>(p) + 1));
+}
+
+// Tests that Get{S,U}{8,16,32,64} work on zero.
+TEST(BufferTest, GetZero) {
+  boost::scoped_ptr<Buffer> buffer(new Buffer());
+  for (int i = 0; i < 8; ++i) {
+    buffer->Append(uint8_t(0));
+  }
+  int8_t s8;
+  uint8_t u8;
+  int16_t s16;
+  uint16_t u16;
+  int32_t s32;
+  uint32_t u32;
+  int64_t s64;
+  uint64_t u64;
+  buffer->Get(0, &s8);
+  EXPECT_EQ(0, s8);
+  buffer->Get(0, &u8);
+  EXPECT_EQ(0, u8);
+  buffer->Get(0, &s16);
+  EXPECT_EQ(0, s16);
+  buffer->Get(0, &u16);
+  EXPECT_EQ(0, u16);
+  buffer->Get(0, &s32);
+  EXPECT_EQ(0, s32);
+  buffer->Get(0, &u32);
+  EXPECT_EQ(0, u32);
+  buffer->Get(0, &s64);
+  EXPECT_EQ(0, s64);
+  buffer->Get(0, &u64);
+  EXPECT_EQ(0, u64);
+}
+
+// Tests that GetU{8,16,32,64} work.
+TEST(BufferTest, GetUXX) {
+  boost::scoped_ptr<Buffer> buffer(new Buffer());
+  buffer->Append(uint8_t(0x88));
+  buffer->Append(uint8_t(0x77));
+  buffer->Append(uint8_t(0x66));
+  buffer->Append(uint8_t(0x55));
+  buffer->Append(uint8_t(0x44));
+  buffer->Append(uint8_t(0x33));
+  buffer->Append(uint8_t(0x22));
+  buffer->Append(uint8_t(0x11));
+  uint8_t u8;
+  uint16_t u16;
+  uint32_t u32;
+  uint64_t u64;
+  buffer->Get(0, &u8);
+  EXPECT_EQ(0x88, u8);
+  buffer->Get(0, &u16);
+  EXPECT_EQ(0x7788, u16);
+  buffer->Get(0, &u32);
+  EXPECT_EQ(0x55667788, u32);
+  buffer->Get(0, &u64);
+  EXPECT_EQ(GG_ULONGLONG(0x1122334455667788), u64);
+}
+
+// Tests that GetS{8,16,32,64} work for positive values.
+TEST(BufferTest, GetSXXPositive) {
+  boost::scoped_ptr<Buffer> buffer(new Buffer());
+  buffer->Append(uint8_t(0x08));
+  buffer->Append(uint8_t(0x07));
+  buffer->Append(uint8_t(0x06));
+  buffer->Append(uint8_t(0x05));
+  buffer->Append(uint8_t(0x04));
+  buffer->Append(uint8_t(0x03));
+  buffer->Append(uint8_t(0x02));
+  buffer->Append(uint8_t(0x01));
+  int8_t s8;
+  int16_t s16;
+  int32_t s32;
+  int64_t s64;
+  buffer->Get(0, &s8);
+  EXPECT_EQ(0x08, s8);
+  buffer->Get(0, &s16);
+  EXPECT_EQ(0x0708, s16);
+  buffer->Get(0, &s32);
+  EXPECT_EQ(0x05060708, s32);
+  buffer->Get(0, &s64);
+  EXPECT_EQ(GG_ULONGLONG(0x0102030405060708), s64);
+}
+
+// Tests that GetS{8,16,32,64} work for negative values.
+TEST(BufferTest, GetSXXNegative) {
+  boost::scoped_ptr<Buffer> buffer(new Buffer());
+  buffer->Append(uint8_t(0xF8));
+  buffer->Append(uint8_t(0xF7));
+  buffer->Append(uint8_t(0x06));
+  buffer->Append(uint8_t(0xF5));
+  buffer->Append(uint8_t(0x04));
+  buffer->Append(uint8_t(0x03));
+  buffer->Append(uint8_t(0x02));
+  buffer->Append(uint8_t(0xF1));
+
+  // Calculate directly the the signed (2's complement) value that we
+  // should expect.
+  const int8_t kExpected8 = 0xF8 - 0xFF - 1;
+  int8_t s8;
+  buffer->Get(0, &s8);
+  EXPECT_EQ(kExpected8, s8);
+
+  const int16_t kExpected16 = 0xF7F8 - 0xFFFF - 1;
+  int16_t s16;
+  buffer->Get(0, &s16);
+  EXPECT_EQ(kExpected16, s16);
+
+  const int32_t kExpected32 = 0xF506F7F8 - 0xFFFFFFFF - 1;
+  int32_t s32;
+  buffer->Get(0, &s32);
+  EXPECT_EQ(kExpected32, s32);
+
+  const int64_t kExpected64 = (GG_LONGLONG(0xF1020304F506F7F8) -
+                               GG_LONGLONG(0xFFFFFFFFFFFFFFFF) -
+                               GG_LONGLONG(1));
+  int64_t s64;
+  buffer->Get(0, &s64);
+  EXPECT_EQ(kExpected64, s64);
+}
+
+// Tests that getting a string works.
+TEST_F(ConstructedFromDataBufferDeathTest, ConstructedFromDataGetString) {
+  std::string s;
+  EXPECT_DEATH(buffer->Get(0, &s), "Check failed");
+  buffer->Append(uint8_t(0));
+  Buffer::size_type n = buffer->Get(0, &s);
+  EXPECT_STREQ("\xEF\xBE\xAD\xDE", s.c_str());
+  EXPECT_EQ(4, n);
+  n = buffer->Get(1, &s);
+  EXPECT_STREQ("\xBE\xAD\xDE", s.c_str());
+  EXPECT_EQ(4, n);
+}
+
+// Tests removing a header.
+TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataRemoveHeader) {
+  buffer->RemoveHeader(0);
+  EXPECT_EQ(sizeof(kDeadBeef), buffer->Length());
+  buffer->RemoveHeader(2);
+  EXPECT_EQ(sizeof(kDeadBeef) - 2, buffer->Length());
+  uint16_t u16;
+  buffer->Get(0, &u16);
+  EXPECT_EQ(0xdead, u16);
+}
+
+// Tests adding a zero-length header.
+TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataAddHeader) {
+  buffer->AddHeader(0);
+  EXPECT_EQ(sizeof(kDeadBeef), buffer->Length());
+}
+
+// Tests adding a header of size > 0.
+TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataAddHeader2) {
+  const int kSize = 100;
+  buffer->AddHeader(kSize);
+  EXPECT_EQ(sizeof(kDeadBeef) + kSize, buffer->Length());
+  uint32_t u32;
+  buffer->Get(kSize, &u32);
+  EXPECT_EQ(0xdeadbeef, u32);
+}
+
+// Tests copying.
+TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataCopy) {
+  buffer->Append(uint8_t(0));
+  std::string s;
+  buffer->Get(0, &s);
+
+  Buffer buffer2;
+  buffer2.Copy(*buffer);
+  std::string s2;
+  buffer2.Get(0, &s2);
+
+  EXPECT_STREQ(s.c_str(), s2.c_str());
+}
+
+// Tests dumping.
+TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataDump) {
+  const char kExpected[] =
+      "0x00000000: ef be ad de                                      | ....\n";
+  std::string s = buffer->Dump();
+  EXPECT_STREQ(kExpected, s.c_str());
+}
+
+// Tests emtpy slicing.
+TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataSlice) {
+  boost::scoped_ptr<Buffer> slice(buffer->MakeSlice(0, 0));
+  EXPECT_EQ(slice->Length(), 0);
+}
+
+// Tests slicing.
+TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataSlice2) {
+  boost::scoped_ptr<Buffer> slice(buffer->MakeSlice(0, 2));
+  EXPECT_EQ(slice->Length(), 2);
+  uint16_t u16;
+  slice->Get(0, &u16);
+  EXPECT_EQ(0xbeef, u16);
+}
+
+// Tests dumping.
+TEST(BufferTest, DumpTest) {
+  const char kData[] = "Hello";
+  const char kExpected[] =
+      "0x00000000: 48 65 6c 6c 6f 00                       "
+      "         | Hello.\n";
+  Buffer buffer(kData, sizeof(kData));
+  std::string s = buffer.Dump();
+  EXPECT_STREQ(kExpected, s.c_str());
+}
+
+#if 0
+// Tests writing to a file.
+TEST(BufferTest, FileTest) {
+  const char kData[] = "Hello";
+  Buffer buffer(kData, sizeof(kData));
+  string out;
+  FileCloser file(MutableStringFile("file", &out,
+                                    DO_NOT_TAKE_OWNERSHIP,
+                                    DO_NOT_ALLOW_MMAP));
+  buffer.WriteOrDie(file.get());
+  EXPECT_STREQ(kData, out.c_str());
+}
+
+TEST(BufferTest, WritePathOrDieTest) {
+  const char kData[] = "Hello";
+  Buffer buffer(kData, sizeof(kData));
+  buffer.WriteToPathOrDie("/dev/null");
+}
+#endif
+
+// Tests appending.
+TEST(BufferTest, AppendBuffer) {
+  const char kData1[] = "Hello ";
+  const char kData2[] = "World";
+  Buffer buffer1(kData1, sizeof(kData1) - 1);
+  EXPECT_EQ(sizeof(kData1) - 1, buffer1.Length());
+  Buffer buffer2(kData2, sizeof(kData2));
+  EXPECT_EQ(sizeof(kData2), buffer2.Length());
+  Buffer buffer;
+  EXPECT_EQ(0, buffer.Length());
+  buffer.Append(Buffer());
+  buffer.Append(buffer1);
+  buffer.Append(buffer2);
+  std::string s;
+  buffer.Get(0, &s);
+  EXPECT_STREQ("Hello World", s.c_str());
+}
+
+// Tests operator==
+TEST(Buffer, OpEqualTrue) {
+  Buffer b1;
+  Buffer b2;
+  EXPECT_EQ(b1, b2);
+  b1.Append(uint8_t(1));
+  b2.Append(uint8_t(1));
+  EXPECT_EQ(b1, b2);
+}
+
+// Tests operator==
+TEST(Buffer, OpEqualFalse) {
+  Buffer empty;
+  Buffer b1;
+  Buffer b2;
+  Buffer b12;
+  b1.Append(uint8_t(1));
+  b2.Append(uint8_t(2));
+  b12.Append(uint8_t(1));
+  b12.Append(uint8_t(2));
+  EXPECT_NE(empty, b1);
+  EXPECT_NE(b1, empty);
+  EXPECT_NE(b1, b2);
+  EXPECT_NE(b1, b12);
+  EXPECT_NE(b12, b1);
+}
+
+TEST(Buffer, Dump) {
+  Buffer b;
+  b.Append(uint8_t(1));
+  std::string s = b.Dump();
+}
+
+}  // namespace
+}  // namespace glibusb
diff --git a/aos/common/glibusb/ghexdump.cc b/aos/common/glibusb/ghexdump.cc
new file mode 100644
index 0000000..66b22a3
--- /dev/null
+++ b/aos/common/glibusb/ghexdump.cc
@@ -0,0 +1,53 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Modified by FRC Team 971.
+//
+
+#include "ghexdump.h"
+
+#include <sstream>
+#include <iomanip>
+#include <stddef.h>
+#include <stdint.h>
+#include <cstring>
+
+namespace glibusb {
+
+std::string Dump(const void *buf, size_t n) {
+  const int kBytesPerRow = 16;
+  const uint8_t *p = static_cast<const uint8_t *>(CHECK_NOTNULL(buf));
+  std::stringstream dump;
+  for (uint32_t i = 0; i < n;) {
+    dump << "0x" 
+	 << std::hex << std::setw(8) << std::setfill('0') << i
+	 << ": ";
+    for (int j = 0; j < kBytesPerRow; ++j) {
+      auto o = i + j;
+      if (o < n) {
+	auto b = p[o];
+	dump << std::hex << std::setw(2) << std::setfill('0') << int(b) << ' ';
+      } else {
+	dump << "   ";
+      }
+    }
+    dump << " | ";
+    for (int j = 0; j < kBytesPerRow; ++j) {
+      auto o = i + j;
+      if (o == n) {
+	break;
+      }
+      auto b = p[o];
+      if (b > ' ' && b <= '~') {
+	dump << char(b);
+      } else {
+	dump << '.';
+      }
+    }
+    dump << std::endl;
+    i += kBytesPerRow;
+  }
+  return dump.str();
+}
+
+}  // namespace glibusb
+
diff --git a/aos/common/glibusb/ghexdump.h b/aos/common/glibusb/ghexdump.h
new file mode 100644
index 0000000..e775ce8
--- /dev/null
+++ b/aos/common/glibusb/ghexdump.h
@@ -0,0 +1,15 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+
+#ifndef _GLIBUSB_GHEXDUMP_H_
+#define _GLIBUSB_GHEXDUMP_H_
+
+#include <stddef.h>
+#include <string>
+
+namespace glibusb {
+
+std::string Dump(const void *buf, size_t n);
+
+}  // namespace glibusb
+
+#endif  // _GLIBUSB_GHEXDUMP_H_
diff --git a/aos/common/glibusb/glibusb.cc b/aos/common/glibusb/glibusb.cc
new file mode 100644
index 0000000..576e35c
--- /dev/null
+++ b/aos/common/glibusb/glibusb.cc
@@ -0,0 +1,316 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+
+#include "glibusb.h"
+
+#include <cstdio>
+#include <sstream>
+#include <iomanip>
+#include <string>
+#include <glog/logging.h>
+#include <libusb.h>
+
+#include "glibusb_device_internal.h"
+
+namespace glibusb {
+
+namespace {
+bool safe_strtou32(const std::string &s, uint32_t *value) {
+  CHECK_NOTNULL(value);
+  std::stringstream stream(s);
+  stream >> std::dec;
+  return stream >> *value;
+}
+
+bool safe_strtou32_hex(const std::string &s, uint32_t *value) {
+  CHECK_NOTNULL(value);
+  std::stringstream stream(s);
+  stream >> std::hex;
+  return stream >> *value;
+}
+}
+
+std::string DeviceLocation::ToString() const 
+{
+  return DeviceLocationToString(*this);
+}
+
+std::string DeviceLocationToString(const DeviceLocation &location) {
+  std::stringstream stream;
+  stream 
+    << std::dec << std::setw(3) << std::setfill('0')
+    << static_cast<int>(location.bus_number)
+    << ":"
+    << std::dec << std::setw(3) << std::setfill('0')
+    << static_cast<int>(location.device_address);
+  return stream.str();
+}
+
+std::ostream &operator <<(std::ostream &out,
+			  const DeviceLocation &location) {
+  out << DeviceLocationToString(location);
+  return out;
+}
+
+std::string VendorProductIdToString(const VendorProductId &vendor_product_id) {
+  std::stringstream stream;
+  stream 
+    << std::hex << std::setw(4) << std::setfill('0')
+    << static_cast<int>(vendor_product_id.vendor_id)
+    << ":"
+    << std::hex << std::setw(4) << std::setfill('0')
+    << static_cast<int>(vendor_product_id.product_id);
+  return stream.str();
+}
+
+std::string DeviceLocationAndId::ToString() const 
+{
+  return DeviceLocationAndIdToString(*this);
+}
+
+std::string DeviceLocationAndIdToString(const DeviceLocationAndId &location_and_id) {
+  return DeviceLocationToString(location_and_id.location) + " " +
+      VendorProductIdToString(location_and_id.id);
+}
+
+std::ostream &operator <<(std::ostream &out,
+			  const DeviceLocationAndId &location_and_id) {
+  out << DeviceLocationAndIdToString(location_and_id);
+  return out;
+}
+
+//////////////////////////////////////////////////////////////////////
+
+Libusb::Libusb() {
+  CHECK_EQ(libusb_init(&libusb_context_), 0);
+}
+
+Libusb::~Libusb() {
+  libusb_exit(libusb_context_);
+}
+
+void Libusb::SetDebug(int level) {
+  libusb_set_debug(libusb_context_, level);
+}
+
+void Libusb::FindDeviceLocationAndId(std::vector<DeviceLocationAndId> *result) {
+  CHECK_NOTNULL(result);
+  struct libusb_device **devices_head;
+  CHECK_GE(libusb_get_device_list(libusb_context_, &devices_head), 0);
+  CHECK_NOTNULL(devices_head);
+
+  for (struct libusb_device **devices = devices_head;
+       *devices != NULL; ++devices) {
+    struct libusb_device_descriptor descriptor;
+    CHECK_GE(libusb_get_device_descriptor(*devices, &descriptor), 0);
+    VLOG(2) << "idVendor = 0x" << std::hex << descriptor.idVendor
+            << " idProduct = 0x" << std::hex << descriptor.idProduct;
+    DeviceLocationAndId dev_location_id;
+    dev_location_id.location.bus_number = libusb_get_bus_number(*devices);
+    dev_location_id.location.device_address =
+        libusb_get_device_address(*devices);
+    dev_location_id.id.vendor_id = descriptor.idVendor;
+    dev_location_id.id.product_id = descriptor.idProduct;
+    result->push_back(dev_location_id);
+  }
+  libusb_free_device_list(devices_head, /*unref_devices=*/ 1);
+}
+
+// Find a single device that matches the vendor_id and product_id, and
+// optionally bus_number and device_address.  CHECK if more than one device is
+// found or no devices are found.
+//
+// This is the implementation behind FindSingleMatchingDeviceAtLocationOrLose()
+// and FindSingleMatchingDeviceOrLose().
+static libusb_device_handle *FindSingleDevice(
+    struct libusb_context *context,
+    bool match_location,
+    const DeviceLocationAndId &dev_location_id) {
+  struct libusb_device **devices_head;
+  CHECK_GE(libusb_get_device_list(context, &devices_head), 0);
+  CHECK_NOTNULL(devices_head);
+
+  struct libusb_device *matching_device = NULL;
+  for (struct libusb_device **devices = devices_head;
+       *devices != NULL; ++devices) {
+    if (match_location) {
+      uint8_t device_bus_number = libusb_get_bus_number(*devices);
+      uint8_t device_device_address = libusb_get_device_address(*devices);
+      if (device_bus_number != dev_location_id.location.bus_number ||
+          device_device_address != dev_location_id.location.device_address)
+        continue;
+    }
+
+    struct libusb_device_descriptor descriptor;
+    CHECK_GE(libusb_get_device_descriptor(*devices, &descriptor), 0);
+    VLOG(2) << "idVendor = 0x" << std::hex << descriptor.idVendor
+            << " idProduct = 0x" << std::hex << descriptor.idProduct;
+    if (descriptor.idVendor == dev_location_id.id.vendor_id &&
+        descriptor.idProduct == dev_location_id.id.product_id) {
+      CHECK(matching_device == NULL) << ": found multiple matching devices";
+      matching_device = *devices;
+    }
+  }
+  if (match_location) {
+    int bus_number = static_cast<int>(dev_location_id.location.bus_number);
+    int device_address =
+        static_cast<int>(dev_location_id.location.device_address);
+    CHECK(matching_device != NULL)
+        << ": no matching device found for "
+        << "vid=" << std::hex << dev_location_id.id.vendor_id << ", "
+        << "pid=" << std::hex << dev_location_id.id.product_id << ", "
+        << "bus_number=" << std::dec << bus_number << ", "
+        << "device_address=" << std::dec << device_address;
+  } else {
+    const int vendor_id = dev_location_id.id.vendor_id;
+    const int product_id = dev_location_id.id.product_id;
+    CHECK(matching_device != NULL) << ": no matching device found for "
+                                   << "vid=" << std::hex << vendor_id << ", "
+                                   << "pid=" << std::hex << product_id;
+  }
+
+  struct libusb_device_handle *handle = NULL;
+  if (matching_device != NULL) {
+    int return_value = libusb_open(matching_device, &handle);
+    if (return_value < 0) {
+      // TODO(charliehotel): this must not be FATAL.
+      LOG(FATAL) << "Failed to open device: "
+                 << libusb_error_name(return_value);
+    }
+    CHECK_NOTNULL(handle);           // should never happen
+  }
+  libusb_free_device_list(devices_head, /*unref_devices=*/ 1);
+  return handle;
+}
+
+UsbDevice *Libusb::FindSingleMatchingDeviceAtLocationOrLose(
+    const DeviceLocationAndId &dev_location_id) {
+  return CHECK_NOTNULL(FindSingleMatchingDeviceAtLocation(dev_location_id));
+}
+
+UsbDevice *Libusb::FindSingleMatchingDeviceAtLocation(
+    const DeviceLocationAndId &dev_location_id) {
+  auto handle = FindSingleDevice(libusb_context_,
+				 /* match_location= */ true,
+				 dev_location_id);
+  if (handle == NULL) {
+    return NULL;
+  } else {
+    return new PhysicalUsbDevice(libusb_context_, handle);
+  }
+}
+
+UsbDevice *Libusb::FindSingleMatchingDeviceOrLose(
+    const VendorProductId &id) {
+  return CHECK_NOTNULL(FindSingleMatchingDeviceOrLose(id));
+}
+
+UsbDevice *Libusb::FindSingleMatchingDevice(
+    const VendorProductId &id) {
+  DeviceLocationAndId dev_location_id;
+  dev_location_id.id = id;
+  auto handle = FindSingleDevice(libusb_context_,
+				 /* match_location= */ false,
+				 dev_location_id);
+  if (handle == NULL) {
+    return NULL;
+  } else {
+    return new PhysicalUsbDevice(libusb_context_, handle);
+  }
+}
+
+void Libusb::FindDeviceBySpecification(
+    const std::string &target_vendor_product_id,
+    const std::string &target_device_location,
+    DeviceLocationAndId *dev_location_id) {
+  std::vector<VendorProductId> target_ids;
+  ParseProductVendorString(target_vendor_product_id, &target_ids);
+  FindSingleDeviceMatchingTargetIds(target_ids, target_device_location,
+                                    dev_location_id);
+}
+
+/*static*/ void Libusb::ParseProductVendorString(
+    const std::string &target_vendor_product_id,
+    std::vector<VendorProductId> *target_ids) {
+  CHECK_NE(target_vendor_product_id, "");
+  CHECK_EQ(target_vendor_product_id.size(), 9);
+  CHECK_EQ(target_vendor_product_id[4], ':');
+  uint32_t vendor_id;
+  CHECK(safe_strtou32_hex(
+      target_vendor_product_id.substr(0, 4), &vendor_id));
+  uint32_t product_id;
+  CHECK(safe_strtou32_hex(
+      target_vendor_product_id.substr(5, 4), &product_id));
+  VendorProductId temp;
+  temp.vendor_id = vendor_id;
+  temp.product_id = product_id;
+  target_ids->push_back(temp);
+}
+
+/*static*/ void Libusb::ParseDeviceLocationString(
+    const std::string &target_device_location, DeviceLocation *location) {
+  CHECK_EQ(target_device_location.size(), 7);
+  CHECK_EQ(target_device_location[3], ':');
+  uint32_t parsed_bus_number;
+  CHECK(safe_strtou32(
+      target_device_location.substr(0, 3), &parsed_bus_number));
+  uint32_t parsed_device_address;
+  CHECK(safe_strtou32(
+      target_device_location.substr(4, 3), &parsed_device_address));
+  location->bus_number = parsed_bus_number;
+  location->device_address = parsed_device_address;
+}
+
+/*static*/ void Libusb::FindSingleDeviceMatchingTargetId(
+    const VendorProductId &target_id,
+    const std::string &target_device_location,
+    DeviceLocationAndId *dev_location_id) {
+  std::vector<VendorProductId> target_ids;
+  target_ids.push_back(target_id);
+  FindSingleDeviceMatchingTargetIds(
+      target_ids, target_device_location, dev_location_id);
+}
+
+void Libusb::FindSingleDeviceMatchingTargetIds(
+    const std::vector<VendorProductId> &target_ids,
+    const std::string &target_device_location,
+    DeviceLocationAndId *result_dev_location_id) {
+
+  bool have_target_device_location = (target_device_location != "");
+  DeviceLocation location;
+  if (have_target_device_location) {
+    ParseDeviceLocationString(target_device_location, &location);
+  }
+
+  // Get the location and vendor/product IDs for all attached devices.
+  std::vector<DeviceLocationAndId> dev_location_ids;
+  FindDeviceLocationAndId(&dev_location_ids);
+
+  // Filter the list by target parameters.  Make sure that exactly one device
+  // is found.
+  bool found_exactly_one_device = false;
+  for (const auto &dev_location_id : dev_location_ids) {
+    if (have_target_device_location) {
+      if (dev_location_id.location.bus_number != location.bus_number ||
+          dev_location_id.location.device_address != location.device_address)
+        continue;
+    }
+
+    bool found_matching_product_vendor_id = false;
+    for (const auto &target : target_ids) {
+      if (target.vendor_id == dev_location_id.id.vendor_id &&
+          target.product_id == dev_location_id.id.product_id) {
+        found_matching_product_vendor_id = true;
+        break;
+      }
+    }
+    if (!found_matching_product_vendor_id)
+      continue;
+
+    CHECK(!found_exactly_one_device);
+    found_exactly_one_device = true;
+    *result_dev_location_id = dev_location_id;
+  }
+  CHECK(found_exactly_one_device);
+}
+
+}  // namespace glibusb
diff --git a/aos/common/glibusb/glibusb.gyp b/aos/common/glibusb/glibusb.gyp
new file mode 100644
index 0000000..e081d67
--- /dev/null
+++ b/aos/common/glibusb/glibusb.gyp
@@ -0,0 +1,26 @@
+{
+  'targets': [
+    {
+      'target_name': 'gbuffer',
+      'type': 'static_library',
+      'sources': [
+        'gbuffer.cc',
+        'ghexdump.cc',
+      ],
+      'dependencies': [
+        '<(AOS)/build/aos.gyp:logging',
+      ],
+    },
+    {
+      'target_name': 'gbuffer_test',
+      'type': 'executable',
+      'sources': [
+        'gbuffer_test.cc',
+      ],
+      'dependencies': [
+        'gbuffer',
+        '<(EXTERNALS):gtest',
+      ],
+    },
+  ],
+}
diff --git a/aos/common/glibusb/glibusb.h b/aos/common/glibusb/glibusb.h
new file mode 100644
index 0000000..e2afb0f
--- /dev/null
+++ b/aos/common/glibusb/glibusb.h
@@ -0,0 +1,229 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Wrapper for libusb.
+
+#ifndef _GLIBUSB_GLIBUSB_H_
+#define _GLIBUSB_GLIBUSB_H_
+
+#include <stdint.h>
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "glibusb_endpoint.h"
+
+extern "C" {
+struct libusb_context;
+}
+
+namespace glibusb {
+
+// Structure to hold the physical location on the USB bus of the device.
+struct DeviceLocation {
+  DeviceLocation() : bus_number(0), device_address(0) {}
+  DeviceLocation(uint8_t new_bus_number, uint8_t new_device_address) 
+   : bus_number(new_bus_number), device_address(new_device_address) {}
+
+  bool operator==(const struct DeviceLocation &rhs) const {
+    return ((bus_number == rhs.bus_number) &&
+	    (device_address == rhs.device_address));
+  }
+
+  std::string ToString() const;
+
+  uint8_t bus_number;
+  uint8_t device_address;
+};
+
+// Returns a string representing the DeviceLocation.
+std::string DeviceLocationToString(const DeviceLocation &location);
+std::ostream &operator <<(std::ostream &out,
+			  const DeviceLocation &location);
+
+
+// Structure to hold the USB vendor and product ids for a device.
+struct VendorProductId {
+  VendorProductId() : vendor_id(0), product_id(0) {}
+  VendorProductId(uint16_t new_vendor_id, uint16_t new_product_id)
+      : vendor_id(new_vendor_id), product_id(new_product_id) {}
+
+  bool operator==(const struct VendorProductId &rhs) const {
+    return ((vendor_id == rhs.vendor_id) &&
+	    (product_id == rhs.product_id));
+  }
+
+  std::string ToString() const;
+
+  uint16_t vendor_id;
+  uint16_t product_id;
+};
+
+// Returns a string representing the VendorProductId.
+std::string VendorProductIdToString(const VendorProductId &vendor_product_id);
+
+// Structure to hold the location and id of a device.  This is enough to
+// uniquely identify the device redundantly.
+struct DeviceLocationAndId {
+  DeviceLocationAndId() {}
+  DeviceLocationAndId(const DeviceLocation &new_location,
+		      const VendorProductId &new_id)
+    : location(new_location), id(new_id)
+  {}
+
+  bool operator==(const struct DeviceLocationAndId &rhs) const {
+    return ((location == rhs.location) &&
+	    (id == rhs.id));
+  }
+
+  std::string ToString() const;
+
+  DeviceLocation location;
+  VendorProductId id;
+};
+
+// Returns a string representing the DeviceLocation and provides a stream
+// operator for logging.
+std::string DeviceLocationAndIdToString(const DeviceLocationAndId &location_and_id);
+std::ostream &operator <<(std::ostream &out,
+			  const DeviceLocationAndId &location_and_id);
+
+
+
+// Provides an interface to an individual USB device.
+class UsbDevice {
+ public:
+  explicit UsbDevice(VendorProductId vendor_product_id)
+      : vendor_product_id_(vendor_product_id) {}
+  virtual ~UsbDevice() {}
+
+  // Activates an alternate setting; returns true on success.
+  bool SetAlternateSetting(int setting) {
+    return DoSetAlternateSetting(setting);
+  }
+
+  // Returns the first endpoint to match the direction and transfer types.
+  // Caller is responsible for freeing the endpoint.
+  UsbInEndpoint *FindInEndpoint(UsbEndpoint::TransferType endpoint) {
+    return DoFindInEndpoint(endpoint);
+  }
+  UsbOutEndpoint *FindOutEndpoint(UsbEndpoint::TransferType endpoint) {
+    return DoFindOutEndpoint(endpoint);
+  }
+
+  // Returns the endpoint at the specified address.
+  // Caller is responsible for freeing the endpoint.
+  // Virtual for testing.
+  UsbInEndpoint *InEndpoint(int number) { return DoInEndpoint(number); }
+  UsbOutEndpoint *OutEndpoint(int number) { return DoOutEndpoint(number); }
+
+  // Returns the vendor and product ids.
+  VendorProductId GetVendorAndProductId() { return vendor_product_id_; }
+
+  struct DeviceLocationAndId Id() { return DoDeviceLocationAndId(); }
+
+ protected:
+  VendorProductId vendor_product_id_;
+
+ private:
+  friend class Libusb;  // For private constructor.
+
+  virtual bool DoSetAlternateSetting(int setting) = 0;
+  virtual UsbInEndpoint *DoFindInEndpoint(
+      UsbEndpoint::TransferType endpoint) = 0;
+  virtual UsbOutEndpoint *DoFindOutEndpoint(
+      UsbEndpoint::TransferType endpoint) = 0;
+  virtual UsbInEndpoint *DoInEndpoint(int number) = 0;
+  virtual UsbOutEndpoint *DoOutEndpoint(int number) = 0;
+  virtual struct DeviceLocationAndId DoDeviceLocationAndId() = 0;
+
+  UsbDevice(const UsbDevice &) = delete;
+  void operator=(const UsbDevice &) = delete;
+};
+
+
+// Provides RAII-style libusb initialization.
+class Libusb {
+ public:
+  Libusb();
+  ~Libusb();
+
+  // Sets the debug level.
+  void SetDebug(int level);
+
+  // Returns the locations, vendor ids, and product ids of all attached devices.
+  void FindDeviceLocationAndId(std::vector<DeviceLocationAndId> *result);
+
+  // Finds and returns exactly one device with the matching vendor and
+  // product ID or CHECKs.
+  UsbDevice *FindSingleMatchingDeviceOrLose(const VendorProductId &id);
+  // Does the same,  but returns NULL on failure rather than CHECKing.
+  UsbDevice *FindSingleMatchingDevice(const VendorProductId &id);
+
+  // Finds and returns exactly one device with the matching vendor and
+  // product ID, at the specified bus number and device address, or CHECKs.
+  UsbDevice *FindSingleMatchingDeviceAtLocationOrLose(
+      const DeviceLocationAndId &dev_location_id);
+  // Does the same, but returns NULL on failure rather than CHECKing.
+  UsbDevice *FindSingleMatchingDeviceAtLocation(
+      const DeviceLocationAndId &dev_location_id);
+
+  // Finds exactly one device that matches whatever parameters were specified,
+  // or CHECKs.
+  //
+  // Args:
+  //   target_vendor_product_id: a vendor/product ID pair to search for,
+  //       or empty string.
+  //   target_device_location: a device location to search for, or empty string.
+  //   [out] dev_location_id: The location and Ids of the chosen device.
+  void FindDeviceBySpecification(
+      const std::string &target_vendor_product_id,
+      const std::string &target_device_location,
+      DeviceLocationAndId *dev_location_id);
+
+  // Finds exactly one device matching the specified parameters or checks.
+  //
+  // Args:
+  //   target_ids: a list of product and vendor ids that match.
+  //   target_device_location: a string with the device location, or an empty
+  //       string to search all locations.
+  //   [out] dev_location_id: The location and Ids of the chosen device.
+  void FindSingleDeviceMatchingTargetId(
+      const VendorProductId &target_id,
+      const std::string &target_device_location,
+      DeviceLocationAndId *dev_location_id);
+
+  // Finds exactly one device matching the specified parameters or checks.
+  //
+  // Args:
+  //   target_ids: a list of product and vendor ids that match.
+  //   target_device_location: a string with the device location, or an empty
+  //       string to search all locations.
+  //   [out] dev_location_id: The location and Ids of the chosen device.
+  void FindSingleDeviceMatchingTargetIds(
+      const std::vector<VendorProductId> &target_ids,
+      const std::string &target_device_location,
+      DeviceLocationAndId *dev_location_id);
+
+  // Parses a vendor id and product id string, and appends the result on
+  // target_ids.
+  // The string must be in the form VVVV:PPPP, where VVVV is a 4-digit hex
+  // vendor id and PPPP is a 4-digit hex product id.
+  static void ParseProductVendorString(const std::string &target_vendor_product_id,
+                                       std::vector<VendorProductId> *target_ids);
+
+  static void ParseDeviceLocationString(const std::string &target_device_location,
+                                        DeviceLocation *location);
+
+  // TODO(charliehotel): add richer ways to retrieve device handles.
+
+ private:
+  // Libusb handle
+  struct libusb_context *libusb_context_;
+
+  Libusb(const Libusb &) = delete;
+  void operator=(const Libusb &) = delete;
+};
+
+}  // namespace glibusb
+
+#endif  // _GLIBUSB_GLIBUSB_H_
diff --git a/aos/common/glibusb/glibusb_device.cc b/aos/common/glibusb/glibusb_device.cc
new file mode 100644
index 0000000..9fc8df3
--- /dev/null
+++ b/aos/common/glibusb/glibusb_device.cc
@@ -0,0 +1,227 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+
+#include <stddef.h>
+#include <glog/logging.h>
+#include <boost/function.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <libusb.h>
+
+#include "glibusb.h"
+#include "glibusb_device_internal.h"
+#include "glibusb_endpoint.h"
+#include "glibusb_endpoint_internal.h"
+#include "glibusb_internal.h"
+
+namespace glibusb {
+
+namespace {
+VendorProductId GetVendorAndProductIdInternal(
+  struct libusb_device_handle *device_handle) {
+  CHECK_NOTNULL(device_handle);
+  libusb_device_descriptor desc;
+  libusb_device *dev = libusb_get_device(device_handle);
+  libusb_get_device_descriptor(dev, &desc);
+  return VendorProductId(desc.idVendor, desc.idProduct);
+}
+}  // namespace
+
+PhysicalUsbDevice::PhysicalUsbDevice(struct libusb_context *context,
+                                     struct libusb_device_handle *handle)
+    : UsbDevice(GetVendorAndProductIdInternal(handle)),
+      libusb_context_(CHECK_NOTNULL(context)),
+      device_handle_(CHECK_NOTNULL(handle)) {
+  int r = libusb_claim_interface(device_handle_, 0);
+  // TODO(charliehotel): this must not be FATAL.
+  CHECK_GE(r, 0) << ": libusb_claim_interface failed, r=" << std::dec << r;
+
+  struct libusb_device *dev = libusb_get_device(device_handle_);
+  // TODO(charliehotel): this must not be FATAL.
+  CHECK(dev != NULL) << ": libusb_get_device failed";
+
+  struct libusb_device_descriptor desc;
+  r = libusb_get_device_descriptor(dev, &desc);
+  // TODO(charliehotel): this must not be FATAL.
+  CHECK_GE(r, 0) << ": libusb_get_device_descriptor failed";
+
+  VLOG(2) << "vid=0x" << std::hex << desc.idVendor
+	  << ", pid=0x" << desc.idProduct;
+  VLOG(2) << "  # of configurations = "
+	  << static_cast<int>(desc.bNumConfigurations);
+
+  struct libusb_config_descriptor *config;
+  r = libusb_get_active_config_descriptor(dev, &config);
+  // TODO(charliehotel): this must not be FATAL.
+  CHECK_GE(r, 0) << ": libusb_get_active_config_descriptor failed";
+  // TODO(charliehotel): this must not be FATAL.
+  CHECK_NOTNULL(config);
+
+  if (config->bNumInterfaces != 1) {
+    VLOG(2) << "config->bNumInterfaces="
+	    << static_cast<int>(config->bNumInterfaces)
+	    << ", expected ony one";
+  }
+
+  if (VLOG_IS_ON(2)) {
+    for (int i = 0; i < config->bNumInterfaces; ++i) {
+      const struct libusb_interface *interface = config->interface + i;
+      const struct libusb_interface_descriptor *setting = interface->altsetting;
+
+      VLOG(2) << "bInterfaceNumber="
+              << static_cast<int>(setting->bInterfaceNumber);
+      VLOG(2) << "bAlternateSetting="
+              << static_cast<int>(setting->bAlternateSetting);
+      VLOG(2) << "bNumEndpoints="
+              << static_cast<int>(setting->bNumEndpoints);
+
+      for (int j = 0; j < setting->bNumEndpoints; ++j) {
+        const struct libusb_endpoint_descriptor *endpoint =
+            setting->endpoint + j;
+        switch (endpoint->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) {
+          case LIBUSB_TRANSFER_TYPE_CONTROL:
+            VLOG(2) << "control";
+            break;
+          case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+            VLOG(2) << "iso";
+            break;
+          case LIBUSB_TRANSFER_TYPE_BULK:
+            VLOG(2) << "bulk";
+            break;
+          case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+            VLOG(2) << "interrupt";
+            break;
+          default:
+            LOG(FATAL) << "unknown transfer type";
+        }
+        if ((endpoint->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) ==
+            LIBUSB_ENDPOINT_IN) {
+          VLOG(2) << " ep: 0x"
+                  << std::hex << static_cast<int>(endpoint->bEndpointAddress)
+                  << " (in)";
+        } else {
+          VLOG(2) << " ep: 0x"
+                  << std::hex << static_cast<int>(endpoint->bEndpointAddress)
+                  << " (out)";
+        }
+        VLOG(2) << "   packet size="
+                << std::dec << static_cast<int>(endpoint->wMaxPacketSize);
+        VLOG(2) << "   interval="
+                << std::dec << static_cast<int>(endpoint->bInterval);
+      }
+    }
+  }
+  libusb_free_config_descriptor(config);
+}
+
+PhysicalUsbDevice::~PhysicalUsbDevice() {
+  CHECK_NOTNULL(device_handle_);
+  libusb_close(device_handle_);
+  device_handle_ = nullptr;
+}
+
+bool PhysicalUsbDevice::DoSetAlternateSetting(int setting) {
+  CHECK_NOTNULL(device_handle_);
+  int r = libusb_set_interface_alt_setting(device_handle_, 0, setting);
+  return r == 0;
+}
+
+template <class UsbEndpointType>
+UsbEndpointType *PhysicalUsbDevice::MatchEndpoint(EndpointMatcher matcher) {
+  CHECK_NOTNULL(device_handle_);
+  struct libusb_config_descriptor *config;
+  libusb_device *dev = libusb_get_device(device_handle_);
+  const int r = libusb_get_active_config_descriptor(dev, &config);
+  // TODO(charliehotel): this must not be FATAL.
+  CHECK_GE(r, 0) << ": libusb_get_active_config_descriptor failed";
+  // TODO(charliehotel): this must not be FATAL.
+  CHECK_NOTNULL(config);
+  const struct libusb_interface *interface = config->interface;
+  const struct libusb_interface_descriptor *setting = interface->altsetting;
+  for (int j = 0; j < setting->bNumEndpoints; ++j) {
+    const struct libusb_endpoint_descriptor *descriptor = setting->endpoint + j;
+    if (matcher(descriptor)) {
+      UsbEndpointType *ans = new UsbEndpointType(
+          libusb_context_, device_handle_, descriptor);
+      libusb_free_config_descriptor(config);
+      return ans;
+    }
+  }
+  libusb_free_config_descriptor(config);
+  return NULL;
+}
+
+namespace {
+
+struct DescriptorHasAddressAndDirection {
+  DescriptorHasAddressAndDirection(int address, UsbEndpoint::DirectionType direction)
+    : address_(address), direction_(direction) {}
+
+  // Returns true if the descriptor provided has an address equal to the number
+  bool operator()(const struct libusb_endpoint_descriptor *descriptor) {
+    return (DescriptorToAddress(descriptor) == address_ &&
+	    DescriptorToDirection(descriptor) == direction_);
+  }
+
+  int address_;
+  UsbEndpoint::DirectionType direction_;
+};
+
+// Returns true if the descriptor has a transfer type and direction equal to the
+// provided type and direction.
+struct DescriptorIsOfTypeAndDirection {
+  DescriptorIsOfTypeAndDirection(UsbEndpoint::TransferType transfer_type,
+				 UsbEndpoint::DirectionType direction)
+    : transfer_type_(transfer_type), direction_(direction) {}
+
+  bool operator()(const struct libusb_endpoint_descriptor *descriptor) {
+    return (DescriptorToTransfer(descriptor) == transfer_type_ &&
+	    DescriptorToDirection(descriptor) == direction_);
+  }
+
+  UsbEndpoint::TransferType transfer_type_;
+  UsbEndpoint::DirectionType direction_;
+};
+
+}  // namespace
+
+UsbInEndpoint *PhysicalUsbDevice::DoInEndpoint(int number) {
+  CHECK_EQ(number & LIBUSB_ENDPOINT_ADDRESS_MASK, number)
+      << ": Endpoint out of range.";
+
+  DescriptorHasAddressAndDirection matcher(number, UsbEndpoint::kIn);
+  return MatchEndpoint<PhysicalUsbInEndpoint>(matcher);
+}
+
+UsbOutEndpoint *PhysicalUsbDevice::DoOutEndpoint(int number) {
+  CHECK_EQ(number & LIBUSB_ENDPOINT_ADDRESS_MASK, number)
+      << ": Endpoint out of range.";
+
+  DescriptorHasAddressAndDirection matcher(number, UsbEndpoint::kOut);
+  return MatchEndpoint<PhysicalUsbOutEndpoint>(matcher);
+}
+
+UsbInEndpoint *PhysicalUsbDevice::DoFindInEndpoint(
+    UsbEndpoint::TransferType endpoint) {
+
+  DescriptorIsOfTypeAndDirection matcher(endpoint, UsbEndpoint::kIn);
+  return MatchEndpoint<PhysicalUsbInEndpoint>(matcher);
+}
+
+UsbOutEndpoint *PhysicalUsbDevice::DoFindOutEndpoint(
+    UsbEndpoint::TransferType endpoint) {
+
+  DescriptorIsOfTypeAndDirection matcher(endpoint, UsbEndpoint::kOut);
+  return MatchEndpoint<PhysicalUsbOutEndpoint>(matcher);
+}
+
+struct DeviceLocationAndId PhysicalUsbDevice::DoDeviceLocationAndId() {
+  CHECK_NOTNULL(device_handle_);
+  libusb_device *device = ::libusb_get_device(device_handle_);
+  CHECK_NOTNULL(device);
+  struct DeviceLocationAndId dlid;
+  dlid.location.bus_number = ::libusb_get_bus_number(device);
+  dlid.location.device_address = ::libusb_get_device_address(device);
+  dlid.id = vendor_product_id_;
+  return dlid;
+}
+
+}  // namespace glibusb
diff --git a/aos/common/glibusb/glibusb_device_internal.h b/aos/common/glibusb/glibusb_device_internal.h
new file mode 100644
index 0000000..4f2ad7f
--- /dev/null
+++ b/aos/common/glibusb/glibusb_device_internal.h
@@ -0,0 +1,55 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Wrapper for libusb's device that implements the UsbDevice interface.
+
+#ifndef _GLIBUSB_GLIBUSB_DEVICE_INTERNAL_H_
+#define _GLIBUSB_GLIBUSB_DEVICE_INTERNAL_H_
+
+#include <stdint.h>
+#include <utility>
+#include <boost/function.hpp>
+
+#include "glibusb.h"
+#include "glibusb_endpoint.h"
+
+namespace glibusb {
+
+// Provides an interface to an individual USB device.
+class PhysicalUsbDevice : public UsbDevice {
+ public:
+  virtual ~PhysicalUsbDevice();
+
+ private:
+  friend class Libusb;  // For private constructor.
+  // Constructs a device given the context and handle.
+  // Frees the handle on destruction.
+  PhysicalUsbDevice(struct libusb_context *context,
+                    struct libusb_device_handle *handle);
+
+  typedef boost::function<bool(const struct libusb_endpoint_descriptor *)>
+    EndpointMatcher;
+
+  // Iterates through all the endpoint descriptors for this device
+  // and allocates and allocates a UsbEndpointType for the first
+  // endpoint for which the matcher returns true.
+  template <class UsbEndpointType>
+    UsbEndpointType *MatchEndpoint(EndpointMatcher matcher);
+
+  virtual bool DoSetAlternateSetting(int setting);
+  virtual UsbInEndpoint *DoFindInEndpoint(UsbEndpoint::TransferType endpoint);
+  virtual UsbOutEndpoint *DoFindOutEndpoint(UsbEndpoint::TransferType endpoint);
+  virtual UsbInEndpoint *DoInEndpoint(int number);
+  virtual UsbOutEndpoint *DoOutEndpoint(int number);
+  virtual struct DeviceLocationAndId DoDeviceLocationAndId();
+
+  // Libusb context and handle used to interact with libusb.
+  struct libusb_context *libusb_context_;
+  struct libusb_device_handle *device_handle_;
+
+  PhysicalUsbDevice(const PhysicalUsbDevice &) = delete;
+  void operator=(const PhysicalUsbDevice &) = delete;
+};
+
+}  // namespace glibusb
+
+#endif  // _GLIBUSB_GLIBUSB_DEVICE_INTERNAL_H_
diff --git a/aos/common/glibusb/glibusb_endpoint.cc b/aos/common/glibusb/glibusb_endpoint.cc
new file mode 100644
index 0000000..30c8bd7
--- /dev/null
+++ b/aos/common/glibusb/glibusb_endpoint.cc
@@ -0,0 +1,362 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+
+#include "glibusb_endpoint.h"
+
+#include <stddef.h>
+#include <glog/logging.h>
+#include <boost/scoped_ptr.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+
+#include "gbuffer.h"
+#include "glibusb_endpoint_internal.h"
+#include "glibusb_internal.h"
+#include "glibusb_transfer.h"
+
+namespace glibusb {
+
+namespace {
+int LibusbGetMaxPacketSize(libusb_device_handle *handle,
+		     unsigned char endpoint) 
+{
+  libusb_device *device = CHECK_NOTNULL(libusb_get_device(handle));
+  return libusb_get_max_packet_size(device, endpoint);
+}
+
+int LibusbGetMaxIsoPacketSize(libusb_device_handle *handle,
+		     unsigned char endpoint) 
+{
+  libusb_device *device = CHECK_NOTNULL(libusb_get_device(handle));
+  return libusb_get_max_iso_packet_size(device, endpoint);
+}
+}  // namespace
+
+Notification::Notification(bool prenotify)
+  : notified_(prenotify) {}
+
+bool Notification::HasBeenNotified() const {
+  boost::lock_guard<boost::mutex> lock(mutex_);
+  return notified_;
+}
+
+void Notification::WaitForNotification() const {
+  boost::unique_lock<boost::mutex> lock(mutex_);
+  notified_changed_.wait(
+      lock, 
+      boost::bind(&Notification::HasBeenNotifiedUnlocked, this));
+}
+
+bool Notification::WaitForNotificationWithTimeout(int64_t milliseconds) const {
+  boost::unique_lock<boost::mutex> lock(mutex_);
+  auto timeout = boost::posix_time::milliseconds(milliseconds);
+  notified_changed_.timed_wait(
+      lock, timeout,
+      boost::bind(&Notification::HasBeenNotifiedUnlocked, this));
+  return notified_;
+}
+
+void Notification::Notify() {
+  boost::lock_guard<boost::mutex> lock(mutex_);
+  CHECK(!notified_) << ": already notified";
+  notified_ = true;
+  notified_changed_.notify_all();
+}
+
+bool Notification::HasBeenNotifiedUnlocked() const {
+  return notified_;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+const int32_t UsbEndpoint::kMaxBulkTransferBytes;
+
+UsbEndpoint::UsbEndpoint(DirectionType direction, TransferType transfer,
+			 int endpoint_address)
+    : direction_(direction),
+      transfer_(transfer),
+      endpoint_address_and_direction_(endpoint_address | direction) {
+  CHECK_EQ(endpoint_address_and_direction_ & 0x80, direction)
+      << ": Direction in address doesn't match specified direction.";
+  CHECK_EQ(endpoint_address_and_direction_ & 0x8f,
+           endpoint_address_and_direction_)
+      << ": Invalid endpoint address.";
+}
+
+////////////////////////////////////////////////////////////////////////
+
+UsbInEndpoint::UsbInEndpoint(TransferType transfer, int endpoint_address)
+    : UsbEndpoint(UsbEndpoint::kIn, transfer, endpoint_address) {
+}
+
+bool UsbInEndpoint::Read(Buffer *out) {
+  IoStatus status = ReadAtMostWithTimeout(kMaxBulkTransferBytes, 0, out);
+  return status == kSuccess;
+}
+
+UsbEndpoint::IoStatus
+UsbInEndpoint::ReadWithTimeout(int32_t timeout_milliseconds,
+			       Buffer *out) {
+  return ReadAtMostWithTimeout(kMaxBulkTransferBytes,
+                               timeout_milliseconds, out);
+}
+
+bool UsbInEndpoint::ReadAtMost(uint32_t length, Buffer *out) {
+  IoStatus status = ReadAtMostWithTimeout(length, 0, out);
+  return status == kSuccess;
+}
+
+UsbEndpoint::IoStatus UsbInEndpoint::ReadAtMostWithTimeout(
+    uint32_t length, int32_t timeout_milliseconds, Buffer *out) {
+  return DoRead(length, timeout_milliseconds, out, NULL);
+}
+
+UsbEndpoint::IoStatus UsbInEndpoint::ReadAtMostWithTimeoutAndNotification(
+    uint32_t length, int32_t timeout_milliseconds, Buffer *out,
+    Notification *quit) {
+  CHECK_NOTNULL(quit);
+  return DoRead(length, timeout_milliseconds, out, quit);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+UsbOutEndpoint::UsbOutEndpoint(TransferType transfer, int endpoint_address)
+    : UsbEndpoint(UsbEndpoint::kOut, transfer, endpoint_address) {
+}
+
+bool UsbOutEndpoint::Write(const Buffer &buffer) {
+  IoStatus status = DoWrite(buffer, 0);
+  return status == kSuccess;
+}
+
+UsbEndpoint::IoStatus UsbOutEndpoint::WriteWithTimeout(const Buffer &buffer,
+				      int32_t timeout_milliseconds) {
+  return DoWrite(buffer, timeout_milliseconds);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+PhysicalUsbInEndpoint::PhysicalUsbInEndpoint(
+    struct libusb_context *context,
+    struct libusb_device_handle *handle,
+    const struct libusb_endpoint_descriptor *descriptor)
+    : UsbInEndpoint(DescriptorToTransfer(descriptor),
+                    DescriptorToAddress(descriptor)),
+      libusb_context_(CHECK_NOTNULL(context)),
+      handle_(CHECK_NOTNULL(handle)) {
+  VLOG(1) << "0x" << std::hex << static_cast<int>(endpoint_address_and_direction())
+          << ", max_packet_size " << std::dec << descriptor->wMaxPacketSize;
+  CHECK_EQ(DescriptorToDirection(descriptor), UsbEndpoint::kIn);
+}
+
+PhysicalUsbInEndpoint::~PhysicalUsbInEndpoint() {
+  CHECK_NOTNULL(handle_);
+  handle_ = nullptr;
+  libusb_context_ = nullptr;
+}
+
+int PhysicalUsbInEndpoint::DoGetMaxPacketSize() {
+  CHECK_NOTNULL(handle_);
+  return LibusbGetMaxPacketSize(handle_, endpoint_address());
+}
+
+int PhysicalUsbInEndpoint::DoGetMaxIsoPacketSize() {
+  CHECK_NOTNULL(handle_);
+  return LibusbGetMaxIsoPacketSize(handle_, endpoint_address());
+}
+
+namespace {
+unsigned char LibUsbTransferType(int transfer_type) {
+  switch (transfer_type) {
+  case UsbEndpoint::kControl:
+    return LIBUSB_TRANSFER_TYPE_CONTROL;
+  case UsbEndpoint::kBulk:
+    return LIBUSB_TRANSFER_TYPE_BULK;
+  case UsbEndpoint::kInterrupt:
+    return LIBUSB_TRANSFER_TYPE_INTERRUPT;
+  case UsbEndpoint::kIsochronous:
+    return LIBUSB_TRANSFER_TYPE_ISOCHRONOUS;
+  default:
+    LOG(FATAL) << "transfer_type " << transfer_type << " is bogus";
+  }
+}
+
+const char kTransferTypeNameControl[] = "control";
+const char kTransferTypeNameBulk[] = "bulk";
+const char kTransferTypeNameInterrupt[] = "interrupt";
+const char kTransferTypeNameIsochronous[] = "isochronous";
+
+const char *TransferTypeName(int transfer_type) {
+  switch (transfer_type) {
+  case UsbEndpoint::kControl:
+    return kTransferTypeNameControl;
+  case UsbEndpoint::kBulk:
+    return kTransferTypeNameBulk;
+  case UsbEndpoint::kInterrupt:
+    return kTransferTypeNameInterrupt;
+  case UsbEndpoint::kIsochronous:
+    return kTransferTypeNameIsochronous;
+  default:
+    LOG(FATAL) << "transfer_type " << transfer_type << " is bogus";
+  }
+}
+}  // namespace
+
+UsbEndpoint::IoStatus PhysicalUsbInEndpoint::DoRead(
+    uint32_t length, int32_t timeout_milliseconds, Buffer *out,
+    Notification *quit) {
+  CHECK_NOTNULL(handle_);
+  CHECK_GE(timeout_milliseconds, 0);
+  CHECK_NOTNULL(out);
+
+  VLOG(2) << "read on 0x" << std::hex << endpoint_address_and_direction()
+          <<  ", size 0x" << std::hex << length
+          << ", timeout " << std::dec << timeout_milliseconds << " [ms]";
+
+  boost::scoped_ptr<Buffer> whole_buffer(new Buffer());
+  whole_buffer->Resize(length);
+  void *p = whole_buffer->GetBufferPointer(length);
+  int transferred;
+  const unsigned int timeout = static_cast<unsigned int>(timeout_milliseconds);
+  int r;
+
+  unsigned char transfer_type = LibUsbTransferType(transfer());
+  r = do_sync_bulk_transfer(libusb_context_,
+                            handle_, endpoint_address_and_direction(),
+                            static_cast<unsigned char *>(p), length,
+                            &transferred, timeout, transfer_type,
+                            quit);
+
+  switch (r) {
+  case LIBUSB_SUCCESS:
+    {
+      size_t size_transferred = static_cast<size_t>(transferred);
+      whole_buffer->Resize(size_transferred);
+
+      VLOG(2)
+        << "read on 0x"
+        << std::hex << static_cast<int>(endpoint_address_and_direction())
+        << ", size_transferred=0x" << std::hex << size_transferred;
+      out->Copy(*whole_buffer);
+      return kSuccess;
+    }
+  case LIBUSB_ERROR_TIMEOUT:
+    VLOG(2) << "libusb_" << TransferTypeName(transfer())
+	    << "_transfer timeout";
+    return kTimeout;
+  case LIBUSB_ERROR_IO:
+    VLOG(1) << "Device i/o error.";
+    return kFail;
+  case LIBUSB_ERROR_NO_DEVICE:
+    VLOG(1) << "Device disconnected.";
+    return kNoDevice;
+  case LIBUSB_ERROR_OTHER:
+    LOG(INFO) << "libusb_" << TransferTypeName(transfer())
+	      << "_transfer failed with r=" << std::dec << r;
+    return kUnknown;
+  default:
+    // Most of these are more esoteric.
+    LOG(INFO) << "libusb_" << TransferTypeName(transfer())
+	      << "_transfer failed with r=" << std::dec << r;
+    return kFail;
+  }
+}
+
+////////////////////////////////////////////////////////////////////////
+
+PhysicalUsbOutEndpoint::PhysicalUsbOutEndpoint(
+    struct libusb_context *context,
+    struct libusb_device_handle *handle,
+    const struct libusb_endpoint_descriptor *descriptor)
+    : UsbOutEndpoint(DescriptorToTransfer(descriptor),
+                     DescriptorToAddress(descriptor)),
+      libusb_context_(CHECK_NOTNULL(context)),
+      handle_(CHECK_NOTNULL(handle)) {
+  VLOG(1) << "0x" << std::hex << static_cast<int>(endpoint_address_and_direction())
+          << ", max_packet_size " << std::dec << descriptor->wMaxPacketSize;
+  CHECK_EQ(DescriptorToDirection(descriptor), UsbEndpoint::kOut);
+}
+
+PhysicalUsbOutEndpoint::~PhysicalUsbOutEndpoint() {
+  CHECK_NOTNULL(handle_);
+  handle_ = nullptr;
+  libusb_context_ = nullptr;
+}
+
+int PhysicalUsbOutEndpoint::DoGetMaxPacketSize() {
+  CHECK_NOTNULL(handle_);
+  return LibusbGetMaxPacketSize(handle_, endpoint_address());
+}
+
+int PhysicalUsbOutEndpoint::DoGetMaxIsoPacketSize() {
+  CHECK_NOTNULL(handle_);
+  return LibusbGetMaxIsoPacketSize(handle_, endpoint_address());
+}
+
+UsbEndpoint::IoStatus PhysicalUsbOutEndpoint::DoWrite(
+    const Buffer &buffer, int32_t timeout_milliseconds) {
+  CHECK_NOTNULL(handle_);
+  CHECK_EQ(direction(), kOut);
+
+  VLOG(2) << "writing on 0x" << std::hex << endpoint_address_and_direction()
+          << ", length=" << std::dec << buffer.Length()
+	  << ", timeout " << std::dec << timeout_milliseconds << " [ms]";
+
+  size_t length = buffer.Length();
+  const unsigned char *p =
+      static_cast<const unsigned char *>(buffer.GetBufferPointer(length));
+  const unsigned int timeout = static_cast<unsigned int>(timeout_milliseconds);
+
+  int transferred;
+  int r;
+
+  switch (transfer()) {
+    case kBulk:
+      VLOG(2) << "libusb_bulk_transfer, length=" << std::dec << length;
+      r = libusb_bulk_transfer(handle_, endpoint_address_and_direction(),
+                               const_cast<unsigned char *>(p),
+                               length, &transferred,
+                               timeout);
+      VLOG(2) << "libusb_bulk_transfer, r=" << std::dec << r
+              << ", transferred=" << std::dec << transferred;
+      break;
+    case kInterrupt:
+      VLOG(2) << "libusb_interrupt_transfer, length="
+              << std::dec << length;
+      r = libusb_interrupt_transfer(handle_, endpoint_address_and_direction(),
+                                    const_cast<unsigned char *>(p),
+                                    length, &transferred,
+                                    timeout);
+      VLOG(2) << "libusb_interrupt_transfer, r=" << std::dec << r
+              << ", transferred=" << std::dec << transferred;
+      break;
+    default:
+      LOG(FATAL) << "bogus transfer() value";
+  }
+
+  size_t size_transferred;
+
+  switch (r) {
+  case LIBUSB_SUCCESS:
+    size_transferred = static_cast<size_t>(transferred);
+    CHECK_EQ(size_transferred, length);
+    return kSuccess;
+  case LIBUSB_ERROR_TIMEOUT:
+    VLOG(2) << "libusb_" << TransferTypeName(transfer()) << "_transfer timeout";
+    return kTimeout;
+  case LIBUSB_ERROR_IO:
+    VLOG(1) << "Device i/o error.";
+    return kFail;
+  case LIBUSB_ERROR_NO_DEVICE:
+    VLOG(1) << "Device disconnected.";
+    return kNoDevice;
+  case LIBUSB_ERROR_OTHER:
+    LOG(INFO) << "libusb_" << TransferTypeName(transfer())
+	      << "_transfer failed with r=" << std::dec << r;
+    return kUnknown;
+  default:
+    VLOG(1) << "libusb_" << TransferTypeName(transfer())
+	    << "_transfer failed, r=" << std::dec << r;
+    return kFail;
+  }
+}
+
+}  // namespace glibusb
diff --git a/aos/common/glibusb/glibusb_endpoint.h b/aos/common/glibusb/glibusb_endpoint.h
new file mode 100644
index 0000000..6b1b1a7
--- /dev/null
+++ b/aos/common/glibusb/glibusb_endpoint.h
@@ -0,0 +1,181 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Usb Endpoint Interfaces.
+
+#ifndef _GLIBUSB_GLIBUSB_ENDPOINT_H_
+#define _GLIBUSB_GLIBUSB_ENDPOINT_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <libusb.h>
+#include <boost/bind.hpp>
+#include <boost/thread.hpp>
+#include <boost/thread/condition.hpp>
+
+#include "gbuffer.h"
+
+#ifndef MAX_ISO_BUFFER_LENGTH
+#define MAX_ISO_BUFFER_LENGTH 32768
+#endif
+
+#ifndef MAX_BULK_BUFFER_LENGTH
+#define MAX_BULK_BUFFER_LENGTH 16384
+#endif
+
+#ifndef MAX_CTRL_BUFFER_LENGTH
+#define MAX_CTRL_BUFFER_LENGTH 4096
+#endif
+
+namespace glibusb {
+
+// Provides a base-class for all endpoints.
+class Buffer;
+
+class Notification {
+ public:
+  explicit Notification(bool prenotify = false);
+  bool HasBeenNotified() const;
+  void WaitForNotification() const;
+  bool WaitForNotificationWithTimeout(int64_t milliseconds) const;
+  void Notify();
+
+ private:
+  bool HasBeenNotifiedUnlocked() const;
+
+  mutable boost::mutex mutex_;
+  mutable boost::condition notified_changed_;
+  bool notified_;
+
+  Notification(const Notification &) = delete;
+  void operator=(const Notification &) = delete;
+};
+
+
+class UsbEndpoint {
+ public:
+  // The values for Direction are defined by the USB spec and must not be
+  // modified.
+  enum DirectionType { kIn = 0x80, kOut = 0x00 };
+  enum TransferType { kControl, kBulk, kInterrupt, kIsochronous };
+  enum IoStatus { kSuccess, kFail, kTimeout, kAbort, kNoDevice, kUnknown };
+
+  // The max transfer (in bytes) that the kernel supports.
+  static const int32_t kMaxBulkTransferBytes = MAX_BULK_BUFFER_LENGTH;
+
+  virtual ~UsbEndpoint() {}
+
+  // Returns the endpoint number.
+  int endpoint_address() const {
+    return endpoint_address_and_direction_ & LIBUSB_ENDPOINT_ADDRESS_MASK;
+  }
+
+  // Returns the direction.
+  DirectionType direction() const { return direction_; }
+
+  // Returns the transfer type.
+  TransferType transfer() const { return transfer_; }
+
+  // Returns the wMaxPacketSize value for this endpoint in the
+  // active device configuration.
+  int GetMaxPacketSize() { return DoGetMaxPacketSize(); }
+
+  // Returns the maximum packet size for this endpoint that
+  // can be sent or received during one microframe.
+  int GetMaxIsoPacketSize() { return DoGetMaxIsoPacketSize(); }
+
+ protected:
+  // Constructs an endpoint with the provided tranfser type and address.
+  UsbEndpoint(DirectionType direction, TransferType transfer,
+              int endpoint_address);
+
+  // Returns the address that libusb uses to refer to the endpoint.  This
+  // includes the direction as the highest bit.
+  int endpoint_address_and_direction() const {
+    return endpoint_address_and_direction_;
+  }
+
+ private:
+  virtual int DoGetMaxPacketSize() = 0;
+  virtual int DoGetMaxIsoPacketSize() = 0;
+
+  // Endpoint type and direction.
+  DirectionType direction_;
+  TransferType transfer_;
+
+  // Endpoint address.
+  int endpoint_address_and_direction_;
+
+  UsbEndpoint(const UsbEndpoint &) = delete;
+  void operator=(const UsbEndpoint &) = delete;
+};
+
+// Provides an interface to allow reading from a USB endpoint.
+class UsbInEndpoint : public UsbEndpoint {
+ public:
+  // Constructs an endpoint with the provided transfer type and address.
+  UsbInEndpoint(TransferType transfer, int endpoint_address);
+  virtual ~UsbInEndpoint() {}
+
+  // Reads into the buffer from the endpoint until the transfer limit is
+  // reached, or a zero length packet/non full packet is received.
+  // Returns true on success.  Waits forever.
+  bool Read(Buffer *out);
+
+  // Reads into the buffer from the endpoint until the transfer limit is
+  // reached, or a zero length packet/non full packet is received.
+  IoStatus ReadWithTimeout(int32_t timeout_milliseconds, Buffer *out);
+
+  // Reads into the buffer from the endpoint until the length is
+  // reached, or a zero length packet/non full packet is received.
+  // Returns true on success.
+  bool ReadAtMost(uint32_t length, Buffer *out);
+
+  // Reads into the buffer from the endpoint until the length is
+  // reached, or a zero length packet/non full packet is received.
+  IoStatus ReadAtMostWithTimeout(
+      uint32_t length, int32_t timeout_milliseconds, Buffer *out);
+
+  // Reads into the buffer from the endpoint until the length is
+  // reached, or a zero length packet/non full packet is received.
+  // Cancels the request when the notification is notified.
+  IoStatus ReadAtMostWithTimeoutAndNotification(
+      uint32_t length, int32_t timeout_milliseconds, Buffer *out,
+      Notification *quit);
+
+ private:
+  // Actually executes the read, with the length, timeout, buffer, and
+  // notification.
+  virtual IoStatus DoRead(
+      uint32_t length, int32_t timeout_milliseconds, Buffer *out,
+      Notification *quit) = 0;
+
+  UsbInEndpoint(const UsbInEndpoint &) = delete;
+  void operator=(const UsbInEndpoint &) = delete;
+};
+
+// Provides an interface to allow writing to a USB endpoint.
+class UsbOutEndpoint : public UsbEndpoint {
+ public:
+  // Constructs an endpoint with the provided tranfser type and address.
+  UsbOutEndpoint(TransferType transfer, int endpoint_address);
+  virtual ~UsbOutEndpoint() {}
+
+  // Writes the buffer to the endpoint.  Returns true on success.
+  bool Write(const Buffer &buffer);
+
+  // Writes the buffer to the endpoint with timeout.
+  IoStatus WriteWithTimeout(const Buffer &buffer, int timeout_milliseconds);
+
+ private:
+  // Implements the actual write.
+  virtual IoStatus DoWrite(const Buffer &buffer,
+			   int32_t timeout_milliseconds) = 0;
+
+  UsbOutEndpoint(const UsbOutEndpoint &) = delete;
+  void operator=(const UsbOutEndpoint &) = delete;
+};
+
+}  // namespace glibusb
+
+#endif  // _GLIBUSB_GLIBUSB_ENDPOINT_H_
diff --git a/aos/common/glibusb/glibusb_endpoint_internal.h b/aos/common/glibusb/glibusb_endpoint_internal.h
new file mode 100644
index 0000000..f19899e
--- /dev/null
+++ b/aos/common/glibusb/glibusb_endpoint_internal.h
@@ -0,0 +1,83 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Wrapper for libusb's endpoints.
+
+#ifndef _GLIBUSB_GLIBUSB_ENDPOINT_INTERNAL_H_
+#define _GLIBUSB_GLIBUSB_ENDPOINT_INTERNAL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <libusb.h>
+
+#include "glibusb_endpoint.h"
+
+class Notification;
+
+namespace glibusb {
+
+class Buffer;
+
+
+// Provides an interface to allow reading from a USB endpoint.
+class PhysicalUsbInEndpoint : public UsbInEndpoint {
+ public:
+  virtual ~PhysicalUsbInEndpoint();
+
+ private:
+  friend class PhysicalUsbDevice;  // For constructor
+  // Constructs an endpoint given the context, handle, and a descriptor of the
+  // endpoint.  The context and handle must remain valid throughout the
+  // lifetime of this object.
+  PhysicalUsbInEndpoint(struct libusb_context *context,
+                        struct libusb_device_handle *handle,
+                        const struct libusb_endpoint_descriptor *descriptor);
+
+  virtual int DoGetMaxPacketSize();
+  virtual int DoGetMaxIsoPacketSize();
+
+  // Actually executes the read, with the length, timeout, buffer, and
+  // notification.
+  virtual IoStatus DoRead(
+      uint32_t length, int32_t timeout_milliseconds, Buffer *out,
+      Notification *quit);
+
+  // Libusb handles and endpoint information.
+  struct libusb_context *libusb_context_;
+  struct libusb_device_handle *handle_;
+
+  PhysicalUsbInEndpoint(const PhysicalUsbInEndpoint &) = delete;
+  void operator=(const PhysicalUsbInEndpoint &) = delete;
+};
+
+// Provides an interface to allow writing to a USB endpoint.
+class PhysicalUsbOutEndpoint : public UsbOutEndpoint {
+ public:
+  virtual ~PhysicalUsbOutEndpoint();
+
+ private:
+  friend class PhysicalUsbDevice;  // For constructor
+  // Constructs an endpoint given the context, handle, and a descriptor of the
+  // endpoint.  The context and handle must remain valid throughout the
+  // lifetime of this object.
+  PhysicalUsbOutEndpoint(struct libusb_context *context,
+                         struct libusb_device_handle *handle,
+                         const struct libusb_endpoint_descriptor *descriptor);
+
+  virtual int DoGetMaxPacketSize();
+  virtual int DoGetMaxIsoPacketSize();
+
+  // Implements the actual write.
+  virtual IoStatus DoWrite(const Buffer &buffer,
+			   int32_t timeout_milliseconds);
+
+  // Libusb handles and endpoint information.
+  struct libusb_context *libusb_context_;
+  struct libusb_device_handle *handle_;
+
+  PhysicalUsbOutEndpoint(const PhysicalUsbOutEndpoint &) = delete;
+  void operator=(const PhysicalUsbOutEndpoint &) = delete;
+};
+
+}  // namespace glibusb
+
+#endif  // _GLIBUSB_GLIBUSB_ENDPOINT_INTERNAL_H_
diff --git a/aos/common/glibusb/glibusb_internal.cc b/aos/common/glibusb/glibusb_internal.cc
new file mode 100644
index 0000000..f55dc2e
--- /dev/null
+++ b/aos/common/glibusb/glibusb_internal.cc
@@ -0,0 +1,49 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+
+#include "glibusb_internal.h"
+
+#include <libusb.h>
+
+#include "glog/logging.h"
+#include "glibusb_endpoint.h"
+
+namespace glibusb {
+
+// Converts libusb endpoint address to integer
+int DescriptorToAddress(const struct libusb_endpoint_descriptor *descriptor) {
+  return descriptor->bEndpointAddress & LIBUSB_ENDPOINT_ADDRESS_MASK;
+}
+
+// Converts libusb direction to UsbEndpoint direction.
+UsbEndpoint::DirectionType DescriptorToDirection(
+    const struct libusb_endpoint_descriptor *descriptor) {
+  if ((descriptor->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) ==
+      LIBUSB_ENDPOINT_IN) {
+    return UsbEndpoint::kIn;
+  } else {
+    return UsbEndpoint::kOut;
+  }
+}
+
+// Converts libusb transfer type to UsbEndpoint transfer type.
+UsbEndpoint::TransferType DescriptorToTransfer(
+    const struct libusb_endpoint_descriptor *descriptor) {
+  switch (descriptor->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) {
+    case LIBUSB_TRANSFER_TYPE_CONTROL:
+      return UsbEndpoint::kControl;
+      break;
+    case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+      return UsbEndpoint::kIsochronous;
+      break;
+    case LIBUSB_TRANSFER_TYPE_BULK:
+      return UsbEndpoint::kBulk;
+      break;
+    case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+      return UsbEndpoint::kInterrupt;
+      break;
+    default:
+      LOG(FATAL) << "bogus transfer type";
+  }
+}
+
+}  // namespace glibusb
diff --git a/aos/common/glibusb/glibusb_internal.h b/aos/common/glibusb/glibusb_internal.h
new file mode 100644
index 0000000..8c34e5d
--- /dev/null
+++ b/aos/common/glibusb/glibusb_internal.h
@@ -0,0 +1,25 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Internal conversions between libusb descriptors and enums.
+
+#ifndef _GLIBUSB_GLIBUSB_INTERNAL_H_
+#define _GLIBUSB_GLIBUSB_INTERNAL_H_
+
+#include "glibusb_endpoint.h"
+
+namespace glibusb {
+
+// Converts libusb endpoint address to integer
+int DescriptorToAddress(const struct libusb_endpoint_descriptor *descriptor);
+
+// Converts libusb direction to UsbEndpoint direction.
+UsbEndpoint::DirectionType DescriptorToDirection(
+    const struct libusb_endpoint_descriptor *descriptor);
+
+// Converts libusb transfer type to UsbEndpoint transfer type.
+UsbEndpoint::TransferType DescriptorToTransfer(
+    const struct libusb_endpoint_descriptor *descriptor);
+
+}  // namespace glibusb
+
+#endif  // _GLIBUSB_GLIBUSB_INTERNAL_H_
diff --git a/aos/common/glibusb/glibusb_test.cc b/aos/common/glibusb/glibusb_test.cc
new file mode 100644
index 0000000..7a569cf
--- /dev/null
+++ b/aos/common/glibusb/glibusb_test.cc
@@ -0,0 +1,37 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+// Author: charliehotel@google.com (Christopher Hoover)
+
+#include "../glibusb.h"
+
+#include <sstream>
+#include <gtest/gtest.h>
+
+namespace glibusb {
+namespace testing {
+
+// Tests that DeviceLocationAndId gets streamed correctly.
+TEST(LibusbTest, LogsLocationAndID) {
+  DeviceLocationAndId location_and_id;
+  location_and_id.location.bus_number = 10;
+  location_and_id.location.device_address = 20;
+  location_and_id.id.vendor_id = 0x30;
+  location_and_id.id.product_id = 0x40;
+
+  std::stringstream out;
+  out << location_and_id;
+  EXPECT_EQ("010:020 0030:0040", out.str());
+}
+
+// Tests setup and teardown.
+TEST(LibusbTest, SetupTeardown) {
+  Libusb libusb;
+}
+
+// Tests SetDebug
+TEST(LibusbTest, SetDebug) {
+  Libusb libusb;
+  libusb.SetDebug(1);
+}
+
+}  // namespace testing
+}  // namespace glibusb
diff --git a/aos/common/glibusb/glibusb_transfer.cc b/aos/common/glibusb/glibusb_transfer.cc
new file mode 100644
index 0000000..a700cf2
--- /dev/null
+++ b/aos/common/glibusb/glibusb_transfer.cc
@@ -0,0 +1,136 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Alternative libusb call to do transfers that quits when
+// a notification is notified.
+//
+// This code was originally from third_party/libusb/libusb1/sync.c
+// and has been slightly modified to poll the notification.
+
+#include "glibusb_transfer.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <gflags/gflags.h>
+#include <glog/logging.h>
+#include <libusb.h>
+
+#include "glibusb_endpoint.h"
+
+
+DEFINE_int32(notification_poll,
+             60,
+             "Time in seconds to wait between checking the quit notification "
+             "when waiting for USB messages.");
+
+namespace {
+
+static bool GEQZero(const char* flagname, int32_t value) {
+  if (value < 0) {
+    printf("Invalid value for --%s: %d\n", flagname, value);
+    return false;
+  }
+  return true;
+}
+
+static const bool notification_poll_dummy = google::RegisterFlagValidator(
+  &FLAGS_notification_poll, &GEQZero);
+
+}  // namespace
+
+
+namespace glibusb {
+
+namespace {
+// Static code from libusb1/sync.c
+void bulk_transfer_cb(struct libusb_transfer *transfer) {
+  int *completed = static_cast<int*>(transfer->user_data);
+  *completed = 1;
+  VLOG(3) << "actual_length=" << transfer->actual_length;
+  /* caller interprets results and frees transfer */
+}
+}  // namespace
+
+int do_sync_bulk_transfer(
+    struct libusb_context *context,
+    struct libusb_device_handle *dev_handle,
+    unsigned char endpoint, unsigned char *buffer, int length,
+    int *transferred, unsigned int timeout, unsigned char type,
+    Notification *quit) {
+  struct libusb_transfer *transfer = libusb_alloc_transfer(0);
+  int completed = 0;
+  int r;
+
+  if (!transfer)
+    return LIBUSB_ERROR_NO_MEM;
+
+  libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length,
+    bulk_transfer_cb, &completed, timeout);
+  transfer->type = type;
+
+  r = libusb_submit_transfer(transfer);
+  if (r < 0) {
+    libusb_free_transfer(transfer);
+    return r;
+  }
+
+  while (!completed) {
+    struct timeval tv;
+    tv.tv_sec = 1;
+    tv.tv_usec = 0;
+    r = libusb_handle_events_timeout_completed(context, &tv, &completed);
+    if (quit != NULL && quit->HasBeenNotified()) {
+      LOG(WARNING) << "Caught quit notification.  Canceling transfer.";
+      r = LIBUSB_ERROR_TIMEOUT;
+    }
+    if (r < 0) {
+      if (r == LIBUSB_ERROR_INTERRUPTED) {
+        continue;
+      }
+      libusb_cancel_transfer(transfer);
+      while (!completed) {
+        struct timeval cancel_tv;
+        cancel_tv.tv_sec = (quit == NULL ? FLAGS_notification_poll : 60);
+        cancel_tv.tv_usec = 0;
+        if (libusb_handle_events_timeout_completed(context, &cancel_tv,
+                                                   &completed) < 0) {
+          break;
+        }
+      }
+      libusb_free_transfer(transfer);
+      return r;
+    }
+  }
+
+  *transferred = transfer->actual_length;
+  switch (transfer->status) {
+    case LIBUSB_TRANSFER_COMPLETED:
+      r = 0;
+      break;
+    case LIBUSB_TRANSFER_TIMED_OUT:
+      r = LIBUSB_ERROR_TIMEOUT;
+      break;
+    case LIBUSB_TRANSFER_STALL:
+      r = LIBUSB_ERROR_PIPE;
+      break;
+    case LIBUSB_TRANSFER_OVERFLOW:
+      r = LIBUSB_ERROR_OVERFLOW;
+      break;
+    case LIBUSB_TRANSFER_NO_DEVICE:
+      r = LIBUSB_ERROR_NO_DEVICE;
+      break;
+    case LIBUSB_TRANSFER_ERROR:
+    case LIBUSB_TRANSFER_CANCELLED:
+      r = LIBUSB_ERROR_IO;
+      break;
+    default:
+      LOG(WARNING) << "unrecognised status code " << transfer->status;
+      r = LIBUSB_ERROR_OTHER;
+  }
+
+  libusb_free_transfer(transfer);
+  return r;
+}
+
+}  // namespace glibusb
diff --git a/aos/common/glibusb/glibusb_transfer.h b/aos/common/glibusb/glibusb_transfer.h
new file mode 100644
index 0000000..9218049
--- /dev/null
+++ b/aos/common/glibusb/glibusb_transfer.h
@@ -0,0 +1,33 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Alternative libusb call to do transfers that quits when
+// a notification is notified.
+
+#ifndef _GLIBUSB_GLIBUSB_TRANSFER_H_
+#define _GLIBUSB_GLIBUSB_TRANSFER_H_
+
+extern "C" {
+struct libusb_context;
+struct libusb_device_handle;
+}
+
+class Notification;
+
+namespace glibusb {
+
+// Bulk transfer code cribbed from libusb1/sync.c
+// The difference between this and the original code is that the
+// transfer now accepts a notification to poll for the quit message.
+// When it receives a quit message on the notification, it cancels the transfer.
+// The provided API's don't support better reuse of the existing code from what
+// I can tell.
+int do_sync_bulk_transfer(
+    struct libusb_context *context,
+    struct libusb_device_handle *dev_handle,
+    unsigned char endpoint, unsigned char *buffer, int length,
+    int *transferred, unsigned int timeout, unsigned char type,
+    Notification *quit);
+
+}  // namespace glibusb
+
+#endif  // _GLIBUSB_GLIBUSB_TRANSFER_H_