blob: 0c5075ef9b13f37a69d176e3e02e09e7130de4bf [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
Brian Silverman4aa83042018-01-05 12:47:31 -080064 CreateIadDescriptor(
65 /*first_interface=*/interface_,
66 /*interface_count=*/1,
67 /*function_class=*/hid_class(),
68 /*function_subclass=*/0,
69 /*function_protocol=*/0, "HidIad");
Brian Silvermand930f282017-11-04 23:09:12 -040070
71 {
72 const auto interface_descriptor = CreateDescriptor(
73 interface_descriptor_length(), UsbDescriptorType::kInterface);
74 interface_descriptor->AddByte(interface_); // bInterfaceNumber
75 interface_descriptor->AddByte(0); // bAlternateSetting
76 interface_descriptor->AddByte(1); // bNumEndpoints
77 interface_descriptor->AddByte(hid_class()); // bInterfaceClass
78 interface_descriptor->AddByte(0); // bInterfaceSubClass
79 interface_descriptor->AddByte(0); // bInterfaceProtocol
80 interface_descriptor->AddByte(device()->AddString("Hid")); // iInterface
81 }
82
83 AddPremadeDescriptor(kHidDescriptor, sizeof(kHidDescriptor));
84
85 {
86 const auto endpoint_descriptor = CreateDescriptor(
87 endpoint_descriptor_length(), UsbDescriptorType::kEndpoint);
88 endpoint_descriptor->AddByte(in_endpoint_ |
89 m_endpoint_address_in()); // bEndpointAddress
90 endpoint_descriptor->AddByte(
91 m_endpoint_attributes_interrupt()); // bmAttributes
92 endpoint_descriptor->AddUint16(in_endpoint_max_size()); // wMaxPacketSize
93 endpoint_descriptor->AddByte(1); // bInterval
94 }
95}
96
97UsbFunction::SetupResponse HidFunction::HandleEndpoint0SetupPacket(
98 const UsbDevice::SetupPacket &setup_packet) {
99 if (G_SETUP_REQUEST_TYPE_TYPE(setup_packet.request_type) !=
100 SetupRequestType::kClass) {
101 return SetupResponse::kIgnored;
102 }
103 if (G_SETUP_REQUEST_TYPE_RECIPIENT(setup_packet.request_type) !=
104 standard_setup_recipients::kInterface) {
105 return SetupResponse::kIgnored;
106 }
107 if (setup_packet.index != interface_) {
108 return SetupResponse::kIgnored;
109 }
110 const bool in = setup_packet.request_type & M_SETUP_REQUEST_TYPE_IN;
111 switch (setup_packet.request) {
112 case hid_class_requests::get_report():
113 if (!in) {
114 return SetupResponse::kStall;
115 }
116 // If it's not requesting the only Input report, no idea what the host
117 // wants so stall.
118 if (setup_packet.value != 0x0100) {
119 return SetupResponse::kStall;
120 }
121 {
122 DisableInterrupts disable_interrupts;
123 memcpy(get_report_response_buffer_.data(),
124 report_tx_buffer_being_sent(disable_interrupts), kMaxReportSize);
125 }
126 device()->QueueEndpoint0Data(
127 reinterpret_cast<const char *>(get_report_response_buffer_.data()),
128 ::std::min<uint16_t>(setup_packet.length, report_max_size_));
129 return SetupResponse::kHandled;
130
131 case hid_class_requests::set_idle():
132 // Minimum implementation to make the host stack happy.
133 if (in) {
134 return SetupResponse::kStall;
135 }
136 device()->SendEmptyEndpoint0Packet();
137 return SetupResponse::kHandled;
138
139 // TODO(Brian): Should we actually implement the idle stuff?
140
141 default:
142 return SetupResponse::kStall;
143 }
144}
145
146UsbFunction::SetupResponse HidFunction::HandleGetDescriptor(
147 const UsbDevice::SetupPacket &setup_packet) {
148 const uint8_t recipient =
149 G_SETUP_REQUEST_TYPE_RECIPIENT(setup_packet.request_type);
150 if (recipient != standard_setup_recipients::kInterface) {
151 return SetupResponse::kIgnored;
152 }
153
154 const uint8_t descriptor_type = (setup_packet.value >> 8) & 0xFF;
155 if (G_DESCRIPTOR_TYPE_TYPE(descriptor_type) !=
156 standard_descriptor_type_types::kClass) {
157 return SetupResponse::kIgnored;
158 }
159 if (setup_packet.index != interface_) {
160 return SetupResponse::kIgnored;
161 }
162
163 const uint8_t descriptor_index = setup_packet.value & 0xFF;
164 switch (descriptor_type) {
165 case static_cast<uint8_t>(UsbClassDescriptorType::kHidHid):
166 if (descriptor_index != 0) {
167 return SetupResponse::kStall;
168 }
169 device()->QueueEndpoint0Data(
170 reinterpret_cast<const char *>(kHidDescriptor),
171 ::std::min<int>(setup_packet.length, sizeof(kHidDescriptor)));
172 return SetupResponse::kHandled;
173
174 case static_cast<uint8_t>(UsbClassDescriptorType::kHidReport):
175 if (descriptor_index != 0) {
176 return SetupResponse::kStall;
177 }
178 device()->QueueEndpoint0Data(
179 reinterpret_cast<const char *>(kReportDescriptor),
180 ::std::min<int>(setup_packet.length, sizeof(kReportDescriptor)));
181 return SetupResponse::kHandled;
182
183 case static_cast<uint8_t>(UsbClassDescriptorType::kHidPhysical):
184 static constexpr char kNoPhysicalDescriptors[] = {0, 0, 0};
185 device()->QueueEndpoint0Data(
186 kNoPhysicalDescriptors,
187 ::std::min<int>(setup_packet.length, sizeof(kNoPhysicalDescriptors)));
188 return SetupResponse::kHandled;
189 }
190 return SetupResponse::kStall;
191}
192
193void HidFunction::HandleInFinished(int endpoint, BdtEntry * /*bdt_entry*/,
194 EvenOdd odd) {
195 if (endpoint == in_endpoint_) {
196 DisableInterrupts disable_interrupts;
197 if (odd != BufferStateToEmpty(tx_state_)) {
198 __builtin_trap();
199 }
200
201 // Copy the current one into the just-sent buffer.
202 memcpy(report_tx_buffer_being_sent(disable_interrupts),
203 report_tx_buffer_to_fill(disable_interrupts), kMaxReportSize);
204
205 dma_memory_barrier();
206 device()->SetBdtEntry(
207 in_endpoint_, Direction::kTx, BufferStateToFill(tx_state_),
208 {M_USB_BD_OWN | M_USB_BD_DTS | V_USB_BD_BC(report_max_size_) |
209 static_cast<uint32_t>(next_tx_toggle_),
210 report_tx_buffer_to_fill(disable_interrupts)});
211
212 // Advance the state to indicate we've swapped buffers.
213 tx_state_ = BufferStateAfterFill(BufferStateAfterEmpty(tx_state_));
214 next_tx_toggle_ = Data01Inverse(next_tx_toggle_);
215 }
216}
217
218void HidFunction::HandleConfigured(int endpoint) {
219 if (endpoint == in_endpoint_) {
220 device()->ConfigureEndpointFor(in_endpoint_, false, true, true);
221 DisableInterrupts disable_interrupts;
222 next_tx_toggle_ = Data01::kData0;
223
224 EvenOdd to_fill;
225 if (BufferStateHasFull(tx_state_)) {
226 to_fill = BufferStateToEmpty(tx_state_);
227 } else {
228 to_fill = BufferStateToFill(tx_state_);
229 tx_state_ = BufferStateAfterFill(tx_state_);
230 }
231
232 dma_memory_barrier();
233 device()->SetBdtEntry(
234 in_endpoint_, Direction::kTx, to_fill,
235 {M_USB_BD_OWN | M_USB_BD_DTS | V_USB_BD_BC(report_max_size_) |
236 static_cast<uint32_t>(next_tx_toggle_),
237 report_tx_buffer_to_fill(disable_interrupts)});
238 next_tx_toggle_ = Data01Inverse(next_tx_toggle_);
239 }
240}
241
242} // namespace teensy
243} // namespace frc971