Add a simple HID device

It currently has a hard-coded report of 4 2-byte joystick values
plus 8 buttons.

Also fix a few things I noticed in the CDC code while working on the HID
code.

Change-Id: Icce6c6ad686fdf974924daab6cb40b7b7d0f7996
diff --git a/motors/usb/hid.cc b/motors/usb/hid.cc
new file mode 100644
index 0000000..24ffe24
--- /dev/null
+++ b/motors/usb/hid.cc
@@ -0,0 +1,247 @@
+#include "motors/usb/hid.h"
+
+namespace frc971 {
+namespace teensy {
+namespace {
+
+constexpr uint8_t hid_class() { return 0x03; }
+
+namespace hid_class_requests {
+constexpr uint8_t get_report() { return 0x01; }
+constexpr uint8_t get_idle() { return 0x02; }
+constexpr uint8_t get_protocol() { return 0x03; }
+constexpr uint8_t set_report() { return 0x09; }
+constexpr uint8_t set_idle() { return 0x0a; }
+constexpr uint8_t set_protcol() { return 0x0b; }
+}  // namespace hid_class_requests
+
+// The hard-coded HID report descriptor.
+uint8_t kReportDescriptor[] = {
+    0x05, 0x01,        // Usage Page (Generic Desktop),
+    0x09, 0x04,        // Usage (Joystick),
+    0xA1, 0x01,        // Collection (Application),
+    0x75, 0x10,        //     Report Size (16),
+    0x95, 0x04,        //     Report Count (4),
+    0x15, 0x00,        //     Logical Minimum (0),
+    0x26, 0xFF, 0xFF,  //     Logical Maximum (65535),
+    0x35, 0x00,        //     Physical Minimum (0),
+    0x46, 0xFF, 0xFF,  //     Physical Maximum (65535),
+    0x09, 0x30,        //     Usage (X),
+    0x09, 0x31,        //     Usage (Y),
+    0x09, 0x32,        //     Usage (Z),
+    0x09, 0x35,        //     Usage (Rz),
+    0x81, 0x02,        //     Input (Variable),
+    0x75, 0x01,        //     Report Size (1),
+    0x95, 0x10,        //     Report Count (16),
+    0x25, 0x01,        //     Logical Maximum (1),
+    0x45, 0x01,        //     Physical Maximum (1),
+    0x05, 0x09,        //     Usage Page (Button),
+    0x19, 0x01,        //     Usage Minimum (1),
+    0x29, 0x10,        //     Usage Maximum (16),
+    0x81, 0x02,        //     Input (Variable),
+    0xC0               // End Collection
+};
+
+// The hard-coded HID descriptor.
+uint8_t kHidDescriptor[] = {
+    9,                                                      // bLength
+    static_cast<uint8_t>(UsbClassDescriptorType::kHidHid),  // bDescriptorType
+    0x10, 0x01,                                             // bcdHID
+    0,                                                      // bCountryCode
+    1,                                                      // bNumDescriptors
+    static_cast<uint8_t>(
+        UsbClassDescriptorType::kHidReport),  // bDescriptorType
+    sizeof(kReportDescriptor),  // wDescriptorLength
+    0,
+};
+
+}  // namespace
+
+void HidFunction::Initialize() {
+  interface_ = AddInterface();
+  in_endpoint_ = AddEndpoint();
+
+  {
+    const auto iad_descriptor = CreateDescriptor(
+        iad_descriptor_length(), UsbDescriptorType::kInterfaceAssociation);
+    iad_descriptor->AddByte(interface_);   // bFirstInterface
+    iad_descriptor->AddByte(1);            // bInterfaceCount
+    iad_descriptor->AddByte(hid_class());  // bFunctionClass
+    iad_descriptor->AddByte(0);            // bFunctionSubClass
+    iad_descriptor->AddByte(0);            // bFunctionProtocol
+    iad_descriptor->AddByte(device()->AddString("HidIad"));  // iFunction
+  }
+
+  {
+    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(hid_class());  // bInterfaceClass
+    interface_descriptor->AddByte(0);            // bInterfaceSubClass
+    interface_descriptor->AddByte(0);            // bInterfaceProtocol
+    interface_descriptor->AddByte(device()->AddString("Hid"));  // iInterface
+  }
+
+  AddPremadeDescriptor(kHidDescriptor, sizeof(kHidDescriptor));
+
+  {
+    const auto endpoint_descriptor = CreateDescriptor(
+        endpoint_descriptor_length(), UsbDescriptorType::kEndpoint);
+    endpoint_descriptor->AddByte(in_endpoint_ |
+                                 m_endpoint_address_in());  // bEndpointAddress
+    endpoint_descriptor->AddByte(
+        m_endpoint_attributes_interrupt());                  // bmAttributes
+    endpoint_descriptor->AddUint16(in_endpoint_max_size());  // wMaxPacketSize
+    endpoint_descriptor->AddByte(1);                         // bInterval
+  }
+}
+
+UsbFunction::SetupResponse HidFunction::HandleEndpoint0SetupPacket(
+    const UsbDevice::SetupPacket &setup_packet) {
+  if (G_SETUP_REQUEST_TYPE_TYPE(setup_packet.request_type) !=
+      SetupRequestType::kClass) {
+    return SetupResponse::kIgnored;
+  }
+  if (G_SETUP_REQUEST_TYPE_RECIPIENT(setup_packet.request_type) !=
+      standard_setup_recipients::kInterface) {
+    return SetupResponse::kIgnored;
+  }
+  if (setup_packet.index != interface_) {
+    return SetupResponse::kIgnored;
+  }
+  const bool in = setup_packet.request_type & M_SETUP_REQUEST_TYPE_IN;
+  switch (setup_packet.request) {
+    case hid_class_requests::get_report():
+      if (!in) {
+        return SetupResponse::kStall;
+      }
+      // If it's not requesting the only Input report, no idea what the host
+      // wants so stall.
+      if (setup_packet.value != 0x0100) {
+        return SetupResponse::kStall;
+      }
+      {
+        DisableInterrupts disable_interrupts;
+        memcpy(get_report_response_buffer_.data(),
+               report_tx_buffer_being_sent(disable_interrupts), kMaxReportSize);
+      }
+      device()->QueueEndpoint0Data(
+          reinterpret_cast<const char *>(get_report_response_buffer_.data()),
+          ::std::min<uint16_t>(setup_packet.length, report_max_size_));
+      return SetupResponse::kHandled;
+
+    case hid_class_requests::set_idle():
+      // Minimum implementation to make the host stack happy.
+      if (in) {
+        return SetupResponse::kStall;
+      }
+      device()->SendEmptyEndpoint0Packet();
+      return SetupResponse::kHandled;
+
+      // TODO(Brian): Should we actually implement the idle stuff?
+
+    default:
+      return SetupResponse::kStall;
+  }
+}
+
+UsbFunction::SetupResponse HidFunction::HandleGetDescriptor(
+    const UsbDevice::SetupPacket &setup_packet) {
+  const uint8_t recipient =
+      G_SETUP_REQUEST_TYPE_RECIPIENT(setup_packet.request_type);
+  if (recipient != standard_setup_recipients::kInterface) {
+    return SetupResponse::kIgnored;
+  }
+
+  const uint8_t descriptor_type = (setup_packet.value >> 8) & 0xFF;
+  if (G_DESCRIPTOR_TYPE_TYPE(descriptor_type) !=
+      standard_descriptor_type_types::kClass) {
+    return SetupResponse::kIgnored;
+  }
+  if (setup_packet.index != interface_) {
+    return SetupResponse::kIgnored;
+  }
+
+  const uint8_t descriptor_index = setup_packet.value & 0xFF;
+  switch (descriptor_type) {
+    case static_cast<uint8_t>(UsbClassDescriptorType::kHidHid):
+      if (descriptor_index != 0) {
+        return SetupResponse::kStall;
+      }
+      device()->QueueEndpoint0Data(
+          reinterpret_cast<const char *>(kHidDescriptor),
+          ::std::min<int>(setup_packet.length, sizeof(kHidDescriptor)));
+      return SetupResponse::kHandled;
+
+    case static_cast<uint8_t>(UsbClassDescriptorType::kHidReport):
+      if (descriptor_index != 0) {
+        return SetupResponse::kStall;
+      }
+      device()->QueueEndpoint0Data(
+          reinterpret_cast<const char *>(kReportDescriptor),
+          ::std::min<int>(setup_packet.length, sizeof(kReportDescriptor)));
+      return SetupResponse::kHandled;
+
+    case static_cast<uint8_t>(UsbClassDescriptorType::kHidPhysical):
+      static constexpr char kNoPhysicalDescriptors[] = {0, 0, 0};
+      device()->QueueEndpoint0Data(
+          kNoPhysicalDescriptors,
+          ::std::min<int>(setup_packet.length, sizeof(kNoPhysicalDescriptors)));
+      return SetupResponse::kHandled;
+  }
+  return SetupResponse::kStall;
+}
+
+void HidFunction::HandleInFinished(int endpoint, BdtEntry * /*bdt_entry*/,
+                                   EvenOdd odd) {
+  if (endpoint == in_endpoint_) {
+    DisableInterrupts disable_interrupts;
+    if (odd != BufferStateToEmpty(tx_state_)) {
+      __builtin_trap();
+    }
+
+    // Copy the current one into the just-sent buffer.
+    memcpy(report_tx_buffer_being_sent(disable_interrupts),
+           report_tx_buffer_to_fill(disable_interrupts), kMaxReportSize);
+
+    dma_memory_barrier();
+    device()->SetBdtEntry(
+        in_endpoint_, Direction::kTx, BufferStateToFill(tx_state_),
+        {M_USB_BD_OWN | M_USB_BD_DTS | V_USB_BD_BC(report_max_size_) |
+             static_cast<uint32_t>(next_tx_toggle_),
+         report_tx_buffer_to_fill(disable_interrupts)});
+
+    // Advance the state to indicate we've swapped buffers.
+    tx_state_ = BufferStateAfterFill(BufferStateAfterEmpty(tx_state_));
+    next_tx_toggle_ = Data01Inverse(next_tx_toggle_);
+  }
+}
+
+void HidFunction::HandleConfigured(int endpoint) {
+  if (endpoint == in_endpoint_) {
+    device()->ConfigureEndpointFor(in_endpoint_, false, true, true);
+    DisableInterrupts disable_interrupts;
+    next_tx_toggle_ = Data01::kData0;
+
+    EvenOdd to_fill;
+    if (BufferStateHasFull(tx_state_)) {
+      to_fill = BufferStateToEmpty(tx_state_);
+    } else {
+      to_fill = BufferStateToFill(tx_state_);
+      tx_state_ = BufferStateAfterFill(tx_state_);
+    }
+
+    dma_memory_barrier();
+    device()->SetBdtEntry(
+        in_endpoint_, Direction::kTx, to_fill,
+        {M_USB_BD_OWN | M_USB_BD_DTS | V_USB_BD_BC(report_max_size_) |
+             static_cast<uint32_t>(next_tx_toggle_),
+         report_tx_buffer_to_fill(disable_interrupts)});
+    next_tx_toggle_ = Data01Inverse(next_tx_toggle_);
+  }
+}
+
+}  // namespace teensy
+}  // namespace frc971