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