blob: d885e75f41c72a9d57c93aa5a5c686514ba4e398 [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
Brian Silvermand930f282017-11-04 23:09:12 -040018} // namespace
19
20void HidFunction::Initialize() {
21 interface_ = AddInterface();
22 in_endpoint_ = AddEndpoint();
23
Brian Silverman4aa83042018-01-05 12:47:31 -080024 CreateIadDescriptor(
25 /*first_interface=*/interface_,
26 /*interface_count=*/1,
27 /*function_class=*/hid_class(),
28 /*function_subclass=*/0,
29 /*function_protocol=*/0, "HidIad");
Brian Silvermand930f282017-11-04 23:09:12 -040030
31 {
32 const auto interface_descriptor = CreateDescriptor(
33 interface_descriptor_length(), UsbDescriptorType::kInterface);
34 interface_descriptor->AddByte(interface_); // bInterfaceNumber
35 interface_descriptor->AddByte(0); // bAlternateSetting
36 interface_descriptor->AddByte(1); // bNumEndpoints
37 interface_descriptor->AddByte(hid_class()); // bInterfaceClass
38 interface_descriptor->AddByte(0); // bInterfaceSubClass
39 interface_descriptor->AddByte(0); // bInterfaceProtocol
40 interface_descriptor->AddByte(device()->AddString("Hid")); // iInterface
41 }
42
Brian Silverman587edcc2018-01-15 12:00:22 -080043 {
44 const auto hid_descriptor = hid_descriptor_list_.CreateDescriptor(
45 9, UsbClassDescriptorType::kHidHid);
46 hid_descriptor->AddUint16(0x0110); // bcdHID
47 hid_descriptor->AddByte(0); // bCountryCode
48 hid_descriptor->AddByte(1); // bNumDescriptors
49 hid_descriptor->AddByte(static_cast<uint8_t>(
50 UsbClassDescriptorType::kHidReport)); // bDescriptorType
51 hid_descriptor->AddUint16(report_descriptor_.size()); // wDescriptorLength
52 }
53 AddPremadeDescriptor(hid_descriptor_list_);
Brian Silvermand930f282017-11-04 23:09:12 -040054
55 {
56 const auto endpoint_descriptor = CreateDescriptor(
57 endpoint_descriptor_length(), UsbDescriptorType::kEndpoint);
58 endpoint_descriptor->AddByte(in_endpoint_ |
59 m_endpoint_address_in()); // bEndpointAddress
60 endpoint_descriptor->AddByte(
61 m_endpoint_attributes_interrupt()); // bmAttributes
62 endpoint_descriptor->AddUint16(in_endpoint_max_size()); // wMaxPacketSize
Brian Silverman7c7170e2018-01-13 17:41:21 -080063 endpoint_descriptor->AddByte(0x8); // bInterval
Brian Silvermand930f282017-11-04 23:09:12 -040064 }
65}
66
67UsbFunction::SetupResponse HidFunction::HandleEndpoint0SetupPacket(
68 const UsbDevice::SetupPacket &setup_packet) {
69 if (G_SETUP_REQUEST_TYPE_TYPE(setup_packet.request_type) !=
70 SetupRequestType::kClass) {
71 return SetupResponse::kIgnored;
72 }
73 if (G_SETUP_REQUEST_TYPE_RECIPIENT(setup_packet.request_type) !=
74 standard_setup_recipients::kInterface) {
75 return SetupResponse::kIgnored;
76 }
77 if (setup_packet.index != interface_) {
78 return SetupResponse::kIgnored;
79 }
80 const bool in = setup_packet.request_type & M_SETUP_REQUEST_TYPE_IN;
81 switch (setup_packet.request) {
82 case hid_class_requests::get_report():
83 if (!in) {
84 return SetupResponse::kStall;
85 }
86 // If it's not requesting the only Input report, no idea what the host
87 // wants so stall.
88 if (setup_packet.value != 0x0100) {
89 return SetupResponse::kStall;
90 }
91 {
92 DisableInterrupts disable_interrupts;
93 memcpy(get_report_response_buffer_.data(),
94 report_tx_buffer_being_sent(disable_interrupts), kMaxReportSize);
95 }
96 device()->QueueEndpoint0Data(
97 reinterpret_cast<const char *>(get_report_response_buffer_.data()),
98 ::std::min<uint16_t>(setup_packet.length, report_max_size_));
99 return SetupResponse::kHandled;
100
101 case hid_class_requests::set_idle():
102 // Minimum implementation to make the host stack happy.
103 if (in) {
104 return SetupResponse::kStall;
105 }
106 device()->SendEmptyEndpoint0Packet();
107 return SetupResponse::kHandled;
108
109 // TODO(Brian): Should we actually implement the idle stuff?
110
111 default:
112 return SetupResponse::kStall;
113 }
114}
115
116UsbFunction::SetupResponse HidFunction::HandleGetDescriptor(
117 const UsbDevice::SetupPacket &setup_packet) {
118 const uint8_t recipient =
119 G_SETUP_REQUEST_TYPE_RECIPIENT(setup_packet.request_type);
120 if (recipient != standard_setup_recipients::kInterface) {
121 return SetupResponse::kIgnored;
122 }
123
124 const uint8_t descriptor_type = (setup_packet.value >> 8) & 0xFF;
125 if (G_DESCRIPTOR_TYPE_TYPE(descriptor_type) !=
126 standard_descriptor_type_types::kClass) {
127 return SetupResponse::kIgnored;
128 }
129 if (setup_packet.index != interface_) {
130 return SetupResponse::kIgnored;
131 }
132
133 const uint8_t descriptor_index = setup_packet.value & 0xFF;
134 switch (descriptor_type) {
135 case static_cast<uint8_t>(UsbClassDescriptorType::kHidHid):
136 if (descriptor_index != 0) {
137 return SetupResponse::kStall;
138 }
139 device()->QueueEndpoint0Data(
Brian Silverman587edcc2018-01-15 12:00:22 -0800140 hid_descriptor_list_.GetData(),
141 ::std::min<int>(setup_packet.length,
142 hid_descriptor_list_.CurrentSize()));
Brian Silvermand930f282017-11-04 23:09:12 -0400143 return SetupResponse::kHandled;
144
145 case static_cast<uint8_t>(UsbClassDescriptorType::kHidReport):
146 if (descriptor_index != 0) {
147 return SetupResponse::kStall;
148 }
149 device()->QueueEndpoint0Data(
Brian Silverman587edcc2018-01-15 12:00:22 -0800150 report_descriptor_.data(),
151 ::std::min<int>(setup_packet.length, report_descriptor_.size()));
Brian Silvermand930f282017-11-04 23:09:12 -0400152 return SetupResponse::kHandled;
153
154 case static_cast<uint8_t>(UsbClassDescriptorType::kHidPhysical):
155 static constexpr char kNoPhysicalDescriptors[] = {0, 0, 0};
156 device()->QueueEndpoint0Data(
157 kNoPhysicalDescriptors,
158 ::std::min<int>(setup_packet.length, sizeof(kNoPhysicalDescriptors)));
159 return SetupResponse::kHandled;
160 }
161 return SetupResponse::kStall;
162}
163
164void HidFunction::HandleInFinished(int endpoint, BdtEntry * /*bdt_entry*/,
165 EvenOdd odd) {
166 if (endpoint == in_endpoint_) {
167 DisableInterrupts disable_interrupts;
168 if (odd != BufferStateToEmpty(tx_state_)) {
169 __builtin_trap();
170 }
171
172 // Copy the current one into the just-sent buffer.
173 memcpy(report_tx_buffer_being_sent(disable_interrupts),
174 report_tx_buffer_to_fill(disable_interrupts), kMaxReportSize);
175
176 dma_memory_barrier();
177 device()->SetBdtEntry(
178 in_endpoint_, Direction::kTx, BufferStateToFill(tx_state_),
179 {M_USB_BD_OWN | M_USB_BD_DTS | V_USB_BD_BC(report_max_size_) |
180 static_cast<uint32_t>(next_tx_toggle_),
181 report_tx_buffer_to_fill(disable_interrupts)});
182
183 // Advance the state to indicate we've swapped buffers.
184 tx_state_ = BufferStateAfterFill(BufferStateAfterEmpty(tx_state_));
185 next_tx_toggle_ = Data01Inverse(next_tx_toggle_);
186 }
187}
188
189void HidFunction::HandleConfigured(int endpoint) {
190 if (endpoint == in_endpoint_) {
191 device()->ConfigureEndpointFor(in_endpoint_, false, true, true);
192 DisableInterrupts disable_interrupts;
193 next_tx_toggle_ = Data01::kData0;
194
195 EvenOdd to_fill;
196 if (BufferStateHasFull(tx_state_)) {
197 to_fill = BufferStateToEmpty(tx_state_);
198 } else {
199 to_fill = BufferStateToFill(tx_state_);
200 tx_state_ = BufferStateAfterFill(tx_state_);
201 }
202
203 dma_memory_barrier();
204 device()->SetBdtEntry(
205 in_endpoint_, Direction::kTx, to_fill,
206 {M_USB_BD_OWN | M_USB_BD_DTS | V_USB_BD_BC(report_max_size_) |
207 static_cast<uint32_t>(next_tx_toggle_),
208 report_tx_buffer_to_fill(disable_interrupts)});
209 next_tx_toggle_ = Data01Inverse(next_tx_toggle_);
210 }
211}
212
213} // namespace teensy
214} // namespace frc971