blob: 24ffe24616d2517824c30d811c4fd105cc670f81 [file] [log] [blame]
Brian Silvermand930f282017-11-04 23:09:12 -04001#include "motors/usb/hid.h"
2
3namespace frc971 {
4namespace teensy {
5namespace {
6
7constexpr uint8_t hid_class() { return 0x03; }
8
9namespace hid_class_requests {
10constexpr uint8_t get_report() { return 0x01; }
11constexpr uint8_t get_idle() { return 0x02; }
12constexpr uint8_t get_protocol() { return 0x03; }
13constexpr uint8_t set_report() { return 0x09; }
14constexpr uint8_t set_idle() { return 0x0a; }
15constexpr uint8_t set_protcol() { return 0x0b; }
16} // namespace hid_class_requests
17
18// The hard-coded HID report descriptor.
19uint8_t kReportDescriptor[] = {
20 0x05, 0x01, // Usage Page (Generic Desktop),
21 0x09, 0x04, // Usage (Joystick),
22 0xA1, 0x01, // Collection (Application),
23 0x75, 0x10, // Report Size (16),
24 0x95, 0x04, // Report Count (4),
25 0x15, 0x00, // Logical Minimum (0),
26 0x26, 0xFF, 0xFF, // Logical Maximum (65535),
27 0x35, 0x00, // Physical Minimum (0),
28 0x46, 0xFF, 0xFF, // Physical Maximum (65535),
29 0x09, 0x30, // Usage (X),
30 0x09, 0x31, // Usage (Y),
31 0x09, 0x32, // Usage (Z),
32 0x09, 0x35, // Usage (Rz),
33 0x81, 0x02, // Input (Variable),
34 0x75, 0x01, // Report Size (1),
35 0x95, 0x10, // Report Count (16),
36 0x25, 0x01, // Logical Maximum (1),
37 0x45, 0x01, // Physical Maximum (1),
38 0x05, 0x09, // Usage Page (Button),
39 0x19, 0x01, // Usage Minimum (1),
40 0x29, 0x10, // Usage Maximum (16),
41 0x81, 0x02, // Input (Variable),
42 0xC0 // End Collection
43};
44
45// The hard-coded HID descriptor.
46uint8_t kHidDescriptor[] = {
47 9, // bLength
48 static_cast<uint8_t>(UsbClassDescriptorType::kHidHid), // bDescriptorType
49 0x10, 0x01, // bcdHID
50 0, // bCountryCode
51 1, // bNumDescriptors
52 static_cast<uint8_t>(
53 UsbClassDescriptorType::kHidReport), // bDescriptorType
54 sizeof(kReportDescriptor), // wDescriptorLength
55 0,
56};
57
58} // namespace
59
60void HidFunction::Initialize() {
61 interface_ = AddInterface();
62 in_endpoint_ = AddEndpoint();
63
64 {
65 const auto iad_descriptor = CreateDescriptor(
66 iad_descriptor_length(), UsbDescriptorType::kInterfaceAssociation);
67 iad_descriptor->AddByte(interface_); // bFirstInterface
68 iad_descriptor->AddByte(1); // bInterfaceCount
69 iad_descriptor->AddByte(hid_class()); // bFunctionClass
70 iad_descriptor->AddByte(0); // bFunctionSubClass
71 iad_descriptor->AddByte(0); // bFunctionProtocol
72 iad_descriptor->AddByte(device()->AddString("HidIad")); // iFunction
73 }
74
75 {
76 const auto interface_descriptor = CreateDescriptor(
77 interface_descriptor_length(), UsbDescriptorType::kInterface);
78 interface_descriptor->AddByte(interface_); // bInterfaceNumber
79 interface_descriptor->AddByte(0); // bAlternateSetting
80 interface_descriptor->AddByte(1); // bNumEndpoints
81 interface_descriptor->AddByte(hid_class()); // bInterfaceClass
82 interface_descriptor->AddByte(0); // bInterfaceSubClass
83 interface_descriptor->AddByte(0); // bInterfaceProtocol
84 interface_descriptor->AddByte(device()->AddString("Hid")); // iInterface
85 }
86
87 AddPremadeDescriptor(kHidDescriptor, sizeof(kHidDescriptor));
88
89 {
90 const auto endpoint_descriptor = CreateDescriptor(
91 endpoint_descriptor_length(), UsbDescriptorType::kEndpoint);
92 endpoint_descriptor->AddByte(in_endpoint_ |
93 m_endpoint_address_in()); // bEndpointAddress
94 endpoint_descriptor->AddByte(
95 m_endpoint_attributes_interrupt()); // bmAttributes
96 endpoint_descriptor->AddUint16(in_endpoint_max_size()); // wMaxPacketSize
97 endpoint_descriptor->AddByte(1); // bInterval
98 }
99}
100
101UsbFunction::SetupResponse HidFunction::HandleEndpoint0SetupPacket(
102 const UsbDevice::SetupPacket &setup_packet) {
103 if (G_SETUP_REQUEST_TYPE_TYPE(setup_packet.request_type) !=
104 SetupRequestType::kClass) {
105 return SetupResponse::kIgnored;
106 }
107 if (G_SETUP_REQUEST_TYPE_RECIPIENT(setup_packet.request_type) !=
108 standard_setup_recipients::kInterface) {
109 return SetupResponse::kIgnored;
110 }
111 if (setup_packet.index != interface_) {
112 return SetupResponse::kIgnored;
113 }
114 const bool in = setup_packet.request_type & M_SETUP_REQUEST_TYPE_IN;
115 switch (setup_packet.request) {
116 case hid_class_requests::get_report():
117 if (!in) {
118 return SetupResponse::kStall;
119 }
120 // If it's not requesting the only Input report, no idea what the host
121 // wants so stall.
122 if (setup_packet.value != 0x0100) {
123 return SetupResponse::kStall;
124 }
125 {
126 DisableInterrupts disable_interrupts;
127 memcpy(get_report_response_buffer_.data(),
128 report_tx_buffer_being_sent(disable_interrupts), kMaxReportSize);
129 }
130 device()->QueueEndpoint0Data(
131 reinterpret_cast<const char *>(get_report_response_buffer_.data()),
132 ::std::min<uint16_t>(setup_packet.length, report_max_size_));
133 return SetupResponse::kHandled;
134
135 case hid_class_requests::set_idle():
136 // Minimum implementation to make the host stack happy.
137 if (in) {
138 return SetupResponse::kStall;
139 }
140 device()->SendEmptyEndpoint0Packet();
141 return SetupResponse::kHandled;
142
143 // TODO(Brian): Should we actually implement the idle stuff?
144
145 default:
146 return SetupResponse::kStall;
147 }
148}
149
150UsbFunction::SetupResponse HidFunction::HandleGetDescriptor(
151 const UsbDevice::SetupPacket &setup_packet) {
152 const uint8_t recipient =
153 G_SETUP_REQUEST_TYPE_RECIPIENT(setup_packet.request_type);
154 if (recipient != standard_setup_recipients::kInterface) {
155 return SetupResponse::kIgnored;
156 }
157
158 const uint8_t descriptor_type = (setup_packet.value >> 8) & 0xFF;
159 if (G_DESCRIPTOR_TYPE_TYPE(descriptor_type) !=
160 standard_descriptor_type_types::kClass) {
161 return SetupResponse::kIgnored;
162 }
163 if (setup_packet.index != interface_) {
164 return SetupResponse::kIgnored;
165 }
166
167 const uint8_t descriptor_index = setup_packet.value & 0xFF;
168 switch (descriptor_type) {
169 case static_cast<uint8_t>(UsbClassDescriptorType::kHidHid):
170 if (descriptor_index != 0) {
171 return SetupResponse::kStall;
172 }
173 device()->QueueEndpoint0Data(
174 reinterpret_cast<const char *>(kHidDescriptor),
175 ::std::min<int>(setup_packet.length, sizeof(kHidDescriptor)));
176 return SetupResponse::kHandled;
177
178 case static_cast<uint8_t>(UsbClassDescriptorType::kHidReport):
179 if (descriptor_index != 0) {
180 return SetupResponse::kStall;
181 }
182 device()->QueueEndpoint0Data(
183 reinterpret_cast<const char *>(kReportDescriptor),
184 ::std::min<int>(setup_packet.length, sizeof(kReportDescriptor)));
185 return SetupResponse::kHandled;
186
187 case static_cast<uint8_t>(UsbClassDescriptorType::kHidPhysical):
188 static constexpr char kNoPhysicalDescriptors[] = {0, 0, 0};
189 device()->QueueEndpoint0Data(
190 kNoPhysicalDescriptors,
191 ::std::min<int>(setup_packet.length, sizeof(kNoPhysicalDescriptors)));
192 return SetupResponse::kHandled;
193 }
194 return SetupResponse::kStall;
195}
196
197void HidFunction::HandleInFinished(int endpoint, BdtEntry * /*bdt_entry*/,
198 EvenOdd odd) {
199 if (endpoint == in_endpoint_) {
200 DisableInterrupts disable_interrupts;
201 if (odd != BufferStateToEmpty(tx_state_)) {
202 __builtin_trap();
203 }
204
205 // Copy the current one into the just-sent buffer.
206 memcpy(report_tx_buffer_being_sent(disable_interrupts),
207 report_tx_buffer_to_fill(disable_interrupts), kMaxReportSize);
208
209 dma_memory_barrier();
210 device()->SetBdtEntry(
211 in_endpoint_, Direction::kTx, BufferStateToFill(tx_state_),
212 {M_USB_BD_OWN | M_USB_BD_DTS | V_USB_BD_BC(report_max_size_) |
213 static_cast<uint32_t>(next_tx_toggle_),
214 report_tx_buffer_to_fill(disable_interrupts)});
215
216 // Advance the state to indicate we've swapped buffers.
217 tx_state_ = BufferStateAfterFill(BufferStateAfterEmpty(tx_state_));
218 next_tx_toggle_ = Data01Inverse(next_tx_toggle_);
219 }
220}
221
222void HidFunction::HandleConfigured(int endpoint) {
223 if (endpoint == in_endpoint_) {
224 device()->ConfigureEndpointFor(in_endpoint_, false, true, true);
225 DisableInterrupts disable_interrupts;
226 next_tx_toggle_ = Data01::kData0;
227
228 EvenOdd to_fill;
229 if (BufferStateHasFull(tx_state_)) {
230 to_fill = BufferStateToEmpty(tx_state_);
231 } else {
232 to_fill = BufferStateToFill(tx_state_);
233 tx_state_ = BufferStateAfterFill(tx_state_);
234 }
235
236 dma_memory_barrier();
237 device()->SetBdtEntry(
238 in_endpoint_, Direction::kTx, to_fill,
239 {M_USB_BD_OWN | M_USB_BD_DTS | V_USB_BD_BC(report_max_size_) |
240 static_cast<uint32_t>(next_tx_toggle_),
241 report_tx_buffer_to_fill(disable_interrupts)});
242 next_tx_toggle_ = Data01Inverse(next_tx_toggle_);
243 }
244}
245
246} // namespace teensy
247} // namespace frc971