Add a USB forwarding application that works on Windows too

It has been tested with a Windows VM sending a few messages. The VM may
have gained some necessary state during testing so it won't work on
other Windows machines, but I've tried to clear it all out and it still
worked.

Change-Id: I814fd57653cd8d86534516e8c4f626746146e626
diff --git a/motors/usb/interrupt_out.cc b/motors/usb/interrupt_out.cc
new file mode 100644
index 0000000..9af650a
--- /dev/null
+++ b/motors/usb/interrupt_out.cc
@@ -0,0 +1,91 @@
+#include "motors/usb/interrupt_out.h"
+
+namespace frc971 {
+namespace teensy {
+
+void InterruptOut::Initialize() {
+  interface_ = AddInterface();
+  endpoint_ = AddEndpoint();
+
+  SetMicrosoftDeviceInterfaceGuids("{D4FA286B-C60D-4B99-B49B-9656139F5771}");
+
+  CreateIadDescriptor(
+      /*first_interface=*/interface_,
+      /*interface_count=*/1,
+      /*function_class=*/vendor_specific_class(),
+      /*function_subclass=*/0,
+      /*function_protocol=*/0, name_);
+
+  {
+    const auto interface_descriptor = CreateDescriptor(
+        interface_descriptor_length(), UsbDescriptorType::kInterface);
+    interface_descriptor->AddByte(interface_);  // bInterfaceNumber
+    interface_descriptor->AddByte(0);           // bAlternateSetting
+    interface_descriptor->AddByte(1);           // bNumEndpoints
+    interface_descriptor->AddByte(vendor_specific_class());  // bInterfaceClass
+    interface_descriptor->AddByte(0x97);  // bInterfaceSubClass
+    interface_descriptor->AddByte(0x97);  // bInterfaceProtocol
+    interface_descriptor->AddByte(device()->AddString(name_));  // iInterface
+  }
+
+  {
+    const auto endpoint_descriptor = CreateDescriptor(
+        endpoint_descriptor_length(), UsbDescriptorType::kEndpoint);
+    endpoint_descriptor->AddByte(endpoint_);  // bEndpointAddress
+    endpoint_descriptor->AddByte(
+        m_endpoint_attributes_interrupt());  // bmAttributes
+    endpoint_descriptor->AddUint16(kSize);   // wMaxPacketSize
+    endpoint_descriptor->AddByte(1);  // bInterval
+  }
+}
+
+void InterruptOut::HandleOutFinished(int endpoint, BdtEntry *bdt_entry) {
+  if (endpoint == endpoint_) {
+
+    DisableInterrupts disable_interrupts;
+    if (first_rx_held_ == nullptr) {
+      first_rx_held_ = bdt_entry;
+    } else {
+      second_rx_held_ = bdt_entry;
+    }
+  }
+}
+
+int InterruptOut::ReceiveData(char *buffer) {
+  DisableInterrupts disable_interrupts;
+  if (first_rx_held_ == nullptr) {
+    return -1;
+  }
+
+  BdtEntry *const bdt_entry = first_rx_held_;
+  const size_t data_size = G_USB_BD_BC(bdt_entry->buffer_descriptor);
+  memcpy(buffer, bdt_entry->address, kSize);
+  dma_memory_barrier();
+
+  first_rx_held_->buffer_descriptor = M_USB_BD_OWN | M_USB_BD_DTS |
+                                      V_USB_BD_BC(kSize) |
+                                      static_cast<uint32_t>(next_rx_toggle_);
+  next_rx_toggle_ = Data01Inverse(next_rx_toggle_);
+
+  first_rx_held_ = second_rx_held_;
+  second_rx_held_ = nullptr;
+  return data_size;
+}
+
+void InterruptOut::HandleConfigured(int endpoint) {
+  if (endpoint == endpoint_) {
+    device()->ConfigureEndpointFor(endpoint_, true, false, true);
+    next_rx_toggle_ = Data01::kData0;
+    device()->SetBdtEntry(
+        endpoint_, Direction::kRx, EvenOdd::kEven,
+        {M_USB_BD_OWN | M_USB_BD_DTS | V_USB_BD_BC(buffers_[0].size()),
+         buffers_[0].data()});
+    device()->SetBdtEntry(endpoint_, Direction::kRx, EvenOdd::kOdd,
+                          {M_USB_BD_OWN | M_USB_BD_DTS |
+                               V_USB_BD_BC(buffers_[1].size()) | M_USB_BD_DATA1,
+                           buffers_[1].data()});
+  }
+}
+
+}  // namespace teensy
+}  // namespace frc971