1/* @title: USB */
2#pragma once
3#include <compiler.h>
4#include <linker/symbols.h>
5#include <log.h>
6#include <stdatomic.h>
7#include <stdbool.h>
8#include <stddef.h>
9#include <stdint.h>
10#include <structures/list.h>
11#include <types/refcount.h>
12struct usb_controller;
13struct usb_device;
14struct usb_request;
15struct io_wait_token;
16
17/* Defines generic USB constants, functions, and structures */
18
19/* All page numbers are for the USB 2.0 Specification */
20
21/* Page 279 - Descriptor types */
22#define USB_DESC_TYPE_DEVICE 1
23#define USB_DESC_TYPE_CONFIG 2
24#define USB_DESC_TYPE_STRING 3
25#define USB_DESC_TYPE_INTERFACE 4
26#define USB_DESC_TYPE_ENDPOINT 5
27#define USB_DESC_TYPE_DEV_QUALIFIER 6
28#define USB_DESC_TYPE_OTHER_SPEED_CONFIG 7
29#define USB_DESC_TYPE_INTERFACE_POWER 8
30
31#define USB_DESC_TYPE_SHIFT 8
32
33/* Request bitmap field definitions */
34#define USB_REQUEST_TRANS_HTD 0
35#define USB_REQUEST_TRANS_DTH 1
36
37#define USB_REQUEST_TYPE_STANDARD 0
38#define USB_REQUEST_TYPE_CLASS 1
39#define USB_REQUEST_TYPE_VENDOR 2
40
41#define USB_REQUEST_RECIPIENT_DEVICE 0
42#define USB_REQUEST_RECIPIENT_INTERFACE 1
43#define USB_REQUEST_RECIPIENT_ENDPOINT 2
44#define USB_REQUEST_RECIPIENT_OTHER 3
45
46#define USB_REQUEST_TRANSFER_SHIFT 7
47#define USB_REQUEST_TRANSFER_MASK 1
48
49#define USB_REQUEST_TYPE_SHIFT 5
50#define USB_REQUEST_TYPE_MASK 3
51
52#define USB_REQUEST_RECIPIENT_MASK 0x1F
53
54#define USB_REQUEST_TRANSFER(byte) ((byte >> 7) & 1)
55#define USB_REQUEST_TYPE(byte) ((byte >> 5) & 3)
56#define USB_REQUEST_RECIPIENT(byte) (byte & 0x1F)
57
58/* Config bitmap definitions */
59#define USB_CONFIG_SELF_POWERED (1 << 7)
60#define USB_CONFIG_REMOTE_WAKEUP (1 << 6)
61
62/* Endpoint address bitmap definitions */
63#define USB_ENDPOINT_ADDR_EP_DIRECTION_OUT 0
64#define USB_ENDPOINT_ADDR_EP_DIRECTION_IN 1
65#define USB_ENDPOINT_ADDR_EP_NUM(byte) (byte & 0xF)
66#define USB_ENDPOINT_ADDR_EP_DIRECTION(byte) ((byte >> 7) & 1)
67
68/* Endpoint attribute bitmap definitions */
69#define USB_ENDPOINT_ATTR_TRANS_TYPE_CONTROL 0
70#define USB_ENDPOINT_ATTR_TRANS_TYPE_ISOCHRONOUS 1
71#define USB_ENDPOINT_ATTR_TRANS_TYPE_BULK 2
72#define USB_ENDPOINT_ATTR_TRANS_TYPE_INTERRUPT 3
73
74#define USB_ENDPOINT_ATTR_SYNC_TYPE_NO_SYNC 0
75#define USB_ENDPOINT_ATTR_SYNC_TYPE_ASYNC 1
76#define USB_ENDPOINT_ATTR_SYNC_TYPE_ADAPTIVE 2
77#define USB_ENDPOINT_ATTR_SYNC_TYPE_SYNC 3
78
79#define USB_ENDPOINT_ATTR_USAGE_TYPE_DATA 0
80#define USB_ENDPOINT_ATTR_USAGE_TYPE_FEEDBACK 1
81#define USB_ENDPOINT_ATTR_USAGE_TYPE_IMPLICIT_FEEDBACK_DATA 2
82
83#define USB_ENDPOINT_ATTR_TRANS_TYPE(byte) (byte & 3)
84#define USB_ENDPOINT_ATTR_SYNC_TYPE(byte) ((byte >> 2) & 3)
85#define USB_ENDPOINT_ATTR_USAGE_TYPE(byte) ((byte >> 4) & 3)
86
87/* Endpoint max packet size bitmap definitions */
88#define USB_ENDPOINT_MAX_PACKET_SIZE_SIZE(byte) (byte & 0x3FF)
89#define USB_ENDPOINT_MAX_PACKET_SIZE_TRANSACT_OPP(byte) ((byte >> 11) & 3)
90
91#define USB_ENDPOINT_MAX_PACKET_SIZE_TRANSACT_OPP_NUM(num) (num + 1)
92
93/* Endpoint interval conversion definitions */
94#define USB_ENDPOINT_INTERVAL_TO_INTEGER_LOW_SPEED(num) (num)
95#define USB_ENDPOINT_INTEGER_TO_INTERVAL_LOW_SPEED(num) (num)
96
97#define USB_ENDPOINT_INTERVAL_TO_INTEGER_HIGH_SPEED(num) (2 << (num - 2))
98
99/* Subclass codes are not defined in a centralized place. Add them as needed */
100#define USB_CLASS_AUDIO 0x1
101/* Audio subclasses go here */
102
103#define USB_CLASS_COMMS 0x2
104/* Comms subclasses go here */
105
106#define USB_CLASS_HID 0x3
107
108#define USB_SUBCLASS_HID_NONE 0x0
109#define USB_SUBCLASS_HID_BOOT_INTERFACE 0x1
110/* 2 - 225 reserved for HID */
111
112#define USB_PROTOCOL_HID_NONE 0x0
113#define USB_PROTOCOL_HID_KEYBOARD 0x1
114#define USB_PROTOCOL_HID_MOUSE 0x2
115/* 3 - 225 reserved */
116
117#define USB_CLASS_PHYSICAL 0x5
118#define USB_CLASS_IMAGE 0x6
119#define USB_CLASS_PRINTER 0x7
120#define USB_CLASS_MASS_STORAGE 0x8
121#define USB_CLASS_HUB 0x9
122#define USB_CLASS_DATA 0xA
123#define USB_CLASS_SMART_CARD 0xB
124#define USB_CLASS_CONTENT_SECURITY 0xD
125#define USB_CLASS_VIDEO 0xE
126#define USB_CLASS_PERSONAL_HEALTHCARE 0xF
127#define USB_CLASS_AUDIO_VIDEO 0x10
128#define USB_CLASS_BILLBOARD 0x11
129#define USB_CLASS_USB_TYPE_C 0x12
130#define USB_CLASS_BULK_DISPLAY 0x13
131#define USB_CLASS_MCTP_OVER_USB 0x14
132#define USB_CLASS_I3C_DEVICE 0x3C
133#define USB_CLASS_DIAGNOSTIC_DEVICE 0xDC
134#define USB_CLASS_WIRELESS 0xE0
135#define USB_CLASS_MISC 0xEF
136#define USB_CLASS_APPLICATION_SPECIFIC 0xFE
137#define USB_CLASS_VENDOR_SPECIFIC 0xFF
138
139LOG_SITE_EXTERN(usb);
140LOG_HANDLE_EXTERN(usb);
141
142#define usb_log(lvl, fmt, ...) \
143 log(LOG_SITE(usb), LOG_HANDLE(usb), lvl, fmt, ##__VA_ARGS__)
144
145#define usb_err(fmt, ...) usb_log(LOG_ERROR, fmt, ##__VA_ARGS__)
146#define usb_warn(fmt, ...) usb_log(LOG_WARN, fmt, ##__VA_ARGS__)
147#define usb_info(fmt, ...) usb_log(LOG_INFO, fmt, ##__VA_ARGS__)
148#define usb_debug(fmt, ...) usb_log(LOG_DEBUG, fmt, ##__VA_ARGS__)
149#define usb_trace(fmt, ...) usb_log(LOG_TRACE, fmt, ##__VA_ARGS__)
150
151/* Request codes */
152enum usb_rq_code : uint8_t {
153 USB_RQ_CODE_GET_STATUS = 0, /* Page 282 */
154 USB_RQ_CODE_CLEAR_FEATURE = 1, /* Page 280 */
155 USB_RQ_CODE_SET_FEATURE = 3, /* Page 286 */
156 USB_RQ_CODE_SET_ADDR = 5, /* Page 284 */
157
158 USB_RQ_CODE_GET_DESCRIPTOR = 6, /* Page 281 */
159 USB_RQ_CODE_SET_DESCRIPTOR = 7, /* Page 285 */
160
161 USB_RQ_CODE_GET_CONFIG = 8, /* Page 281 */
162 USB_RQ_CODE_SET_CONFIG = 9, /* Page 285 */
163
164 USB_RQ_CODE_GET_INTERFACE = 10, /* Page 282 */
165 USB_RQ_CODE_SET_INTERFACE = 11, /* Page 287 */
166
167 USB_RQ_CODE_SYNCH_FRAME = 12, /* Page 288 */
168};
169
170enum usb_controller_type {
171 USB_CONTROLLER_UHCI,
172 USB_CONTROLLER_EHCI,
173 USB_CONTROLLER_XHCI,
174};
175
176enum usb_transfer_type {
177 USB_TRANSFER_CONTROL,
178 USB_TRANSFER_BULK,
179 USB_TRANSFER_INTERRUPT,
180};
181
182enum usb_error {
183 USB_OK = 0,
184 USB_ERR_STALL,
185 USB_ERR_TIMEOUT,
186 USB_ERR_DISCONNECT,
187 USB_ERR_OVERFLOW,
188 USB_ERR_CRC,
189 USB_ERR_IO,
190 USB_ERR_PROTO,
191 USB_ERR_NO_DEVICE,
192 USB_ERR_CANCELLED,
193 USB_ERR_OOM,
194 USB_ERR_INVALID_ARGUMENT,
195 USB_ERR_NO_ENDPOINT,
196};
197
198enum usb_dev_status {
199 USB_DEV_UNDEF,
200 USB_DEV_DISCONNECTED,
201 USB_DEV_CONNECTED,
202 USB_DEV_ENABLED,
203 USB_DEV_RESETTING,
204 USB_DEV_ERROR,
205};
206
207struct usb_setup_packet { /* Refer to page 276 */
208 uint8_t bitmap_request_type; /* Characteristics */
209 enum usb_rq_code request; /* Specific request */
210 uint16_t value; /* Varies according to request */
211
212 union {
213 uint16_t index;
214 uint16_t offset;
215 };
216
217 uint16_t length; /* Number of bytes if there is a data stage */
218
219} __packed;
220static_assert_struct_size_eq(usb_setup_packet, 8);
221
222struct usb_device_descriptor { /* Refer to page 290 */
223 uint8_t length;
224 uint8_t type;
225 uint16_t usb_num_bcd; /* USB number in binary coded
226 * decimal. 2.10 is 210H */
227
228 uint8_t class; /* Class code */
229 uint8_t subclass; /* Subclass code */
230 uint8_t protocol;
231 uint8_t max_packet_size; /* Only 8, 16, 32, or 64 are valid */
232
233 uint16_t vendor_id;
234 uint16_t product_id;
235 uint16_t device_num_bcd; /* Device number in binary coded decimal */
236
237 uint8_t manufacturer; /* Index of string desc. describing manufacturer */
238 uint8_t product; /* Index of string desc. describing product */
239 uint8_t serial_num; /* Index of string desc. describing serial number */
240
241 uint8_t num_configs; /* Number of possible configurations */
242} __packed;
243static_assert_struct_size_eq(usb_device_descriptor, 18);
244
245struct usb_interface_descriptor { /* Page 296 */
246 uint8_t length;
247 uint8_t type;
248 uint8_t interface_number; /* zero-based value ident. the index
249 * in the array of concurrent interfaces */
250
251 uint8_t alternate_setting; /* Select this alternate
252 * setting for the interface */
253
254 uint8_t num_endpoints; /* Number of endpoings excluding EP0 */
255 uint8_t class; /* Interface class code */
256 uint8_t subclass; /* Interface subclass code */
257
258 uint8_t protocol; /* Interface protocol code qualified by `class` and
259 `subclass` */
260
261 uint8_t interface; /* Index of string desc. describing this interface */
262
263} __packed;
264static_assert_struct_size_eq(usb_interface_descriptor, 9);
265
266struct usb_config_descriptor { /* Page 293 */
267 uint8_t length;
268 uint8_t descriptor_type;
269 uint16_t total_length; /* Total length of data for this config */
270 uint8_t num_interfaces;
271 uint8_t configuration_value; /* Value to use as argument
272 * to SetConfig() request */
273
274 uint8_t configuration; /* Index of string desc. describing this config */
275 uint8_t bitmap_attributes; /* Bits 7 and 0..4 are reserved */
276
277 uint8_t max_power; /* Max power of USB device in milliamps */
278} __packed;
279static_assert_struct_size_eq(usb_config_descriptor, 9);
280
281struct usb_endpoint_descriptor { /* Page 297 */
282 uint8_t length;
283 uint8_t type;
284 uint8_t address; /* 3..0 is EP number, 7 is direction */
285 uint8_t attributes; /* Refer to definitions */
286
287 uint16_t max_packet_size; /* Max packet size as a bitmap */
288
289 uint8_t interval; /* Interval for polling this EP for data transfer */
290} __packed;
291static_assert_struct_size_eq(usb_endpoint_descriptor, 7);
292
293struct usb_endpoint {
294 struct usb_endpoint_descriptor *desc;
295
296 /* Putting these here so code won't look like
297 * ep->desc.type, I think that looks bad */
298 uint8_t type;
299 uint8_t number;
300 bool in; /* true - in, false - out */
301 uint8_t *transfer_buffer;
302 uint16_t transfer_len;
303 uint16_t max_packet_size;
304 uint8_t address;
305 uint8_t attributes;
306 uint8_t interval;
307
308 void *hc_data;
309};
310
311struct usb_controller_ops {
312 enum usb_error (*submit_control_transfer)(struct usb_request *);
313 enum usb_error (*submit_bulk_transfer)(struct usb_request *);
314 enum usb_error (*submit_interrupt_transfer)(struct usb_request *);
315 void (*reset_slot)(struct usb_device *dev);
316 enum usb_error (*configure_endpoint)(struct usb_device *dev);
317 void (*poll_ports)(struct usb_controller *);
318};
319
320struct usb_controller { /* Generic USB controller */
321 enum usb_controller_type type;
322 struct usb_controller_ops *ops;
323 void *driver_data;
324};
325
326struct usb_driver {
327 const char *name;
328 uint8_t class_code;
329 uint8_t subclass;
330 uint8_t protocol;
331
332 enum usb_error (*bringup)(struct usb_device *dev); /* Called on connect */
333 void (*teardown)(struct usb_device *dev); /* Called on disconnect */
334 void (*free)(struct usb_device *dev); /* Called on last ref drop */
335};
336
337struct usb_device {
338 struct list_head hc_list;
339 _Atomic enum usb_dev_status status;
340 char manufacturer[128];
341 char product[128];
342 char config_str[128];
343 uint8_t address;
344 uint8_t speed;
345 uint8_t port; /* Port number on the root hub */
346 void *slot;
347 uint8_t max_packet_size;
348
349 struct usb_device_descriptor *descriptor;
350 struct usb_config_descriptor config;
351
352 struct usb_endpoint **endpoints; /* List of endpoints */
353 uint8_t num_endpoints;
354
355 struct usb_controller *host;
356
357 struct usb_interface_descriptor **interfaces; /* List of interfaces */
358 uint8_t num_interfaces;
359
360 struct usb_driver *driver; /* Attached driver */
361
362 void *driver_private;
363
364 bool configured;
365 refcount_t refcount;
366 atomic_bool alive;
367
368 void (*teardown)(struct usb_device *dev); /* called during disconnect */
369 void (*free)(struct usb_device *dev); /* called during last rc drop */
370};
371
372struct usb_request {
373 struct usb_device *dev;
374 struct usb_endpoint *ep;
375 enum usb_transfer_type type;
376 struct usb_setup_packet *setup;
377
378 void *buffer;
379 size_t length;
380
381 volatile enum usb_error status;
382
383 uint32_t flags;
384 uint64_t timeout_ns;
385
386 void (*complete)(struct usb_request *);
387 void *context;
388 bool direction_in;
389
390 /* Controller-private data */
391 void *hc_priv;
392};
393#define USB_REQ_INIT(_req, _dev) \
394 do { \
395 memset((_req), 0, sizeof(*(_req))); \
396 (_req)->dev = (_dev); \
397 } while (0)
398
399REFCOUNT_GENERATE_GET_FOR_STRUCT_WITH_FAILURE_COND(usb_device, refcount, status,
400 == USB_DEV_DISCONNECTED);
401
402void usb_free_device(struct usb_device *dev);
403static inline void usb_device_put(struct usb_device *dev) {
404 if (refcount_dec_and_test(rc: &dev->refcount))
405 usb_free_device(dev);
406}
407
408void usb_teardown_device(struct usb_device *dev);
409enum usb_error usb_get_string_descriptor(struct usb_device *dev,
410 uint8_t string_idx, char *out,
411 size_t max_len);
412enum usb_error usb_get_device_descriptor(struct usb_device *dev);
413enum usb_error usb_parse_config_descriptor(struct usb_device *dev);
414enum usb_error usb_set_configuration(struct usb_device *dev);
415enum usb_error usb_init_device(struct usb_device *dev);
416void usb_try_bind_driver(struct usb_device *dev);
417uint8_t usb_construct_rq_bitmap(uint8_t transfer, uint8_t type, uint8_t recip);
418enum usb_error usb_transfer_sync(enum usb_error (*fn)(struct usb_request *),
419 struct usb_request *request,
420 struct io_wait_token *tok);
421void usb_print_device(struct usb_device *dev);
422struct usb_interface_descriptor *usb_find_interface(struct usb_device *dev,
423 uint8_t class,
424 uint8_t subclass,
425 uint8_t protocol);
426
427static inline uint8_t get_ep_index(struct usb_endpoint *ep) {
428 return (ep->number * 2) + (ep->in ? 1 : 0);
429}
430
431static inline const char *usb_rq_code_str(const enum usb_rq_code code) {
432 switch (code) {
433 case USB_RQ_CODE_GET_STATUS: return "GET_STATUS";
434 case USB_RQ_CODE_CLEAR_FEATURE: return "CLEAR_FEATURE";
435 case USB_RQ_CODE_SET_FEATURE: return "SET_FEATURE";
436 case USB_RQ_CODE_SET_ADDR: return "SET_ADDR";
437 case USB_RQ_CODE_GET_DESCRIPTOR: return "GET_DESCRIPTOR";
438 case USB_RQ_CODE_SET_DESCRIPTOR: return "SET_DESCRIPTOR";
439 case USB_RQ_CODE_GET_CONFIG: return "GET_CONFIG";
440 case USB_RQ_CODE_SET_CONFIG: return "SET_CONFIG";
441 case USB_RQ_CODE_GET_INTERFACE: return "GET_INTERFACE";
442 case USB_RQ_CODE_SET_INTERFACE: return "SET_INTERFACE";
443 case USB_RQ_CODE_SYNCH_FRAME: return "SYNCH_FRAME";
444 default: return "UNKNOWN_CODE";
445 }
446}
447
448static inline const char *
449usb_transfer_type_str(const enum usb_transfer_type type) {
450 switch (type) {
451 case USB_TRANSFER_CONTROL: return "USB TRANSFER CONTROL";
452 case USB_TRANSFER_BULK: return "USB TRANSFER BULK";
453 case USB_TRANSFER_INTERRUPT: return "USB TRANSFER INTERRUPT";
454 default: return "UNKNOWN";
455 }
456}
457
458static inline const char *usb_error_str(const enum usb_error err) {
459 switch (err) {
460 case USB_OK: return "USB OK";
461 case USB_ERR_STALL: return "USB ERR STALL";
462 case USB_ERR_TIMEOUT: return "USB ERR TIMEOUT";
463 case USB_ERR_DISCONNECT: return "USB ERR DISCONNECT";
464 case USB_ERR_OVERFLOW: return "USB ERR OVERFLOW";
465 case USB_ERR_CRC: return "USB ERR CRC";
466 case USB_ERR_IO: return "USB ERR IO";
467 case USB_ERR_PROTO: return "USB ERR PROTO";
468 case USB_ERR_NO_DEVICE: return "USB ERR NO DEVICE";
469 case USB_ERR_CANCELLED: return "USB ERR CANCELLED";
470 case USB_ERR_OOM: return "USB ERR OOM";
471 case USB_ERR_INVALID_ARGUMENT: return "USB ERR INVALID ARGUMENT";
472 case USB_ERR_NO_ENDPOINT: return "USB ERR NO ENDPOINT";
473 default: return "UNKNOWN ERROR";
474 }
475}
476
477LINKER_SECTION_DEFINE(struct usb_driver, usb_drivers);
478#define USB_DRIVER_REGISTER(n, cc, sc, proto, bringup_fn, teardown_fn, \
479 free_fn) \
480 LINKER_SECTION_OBJECT(struct usb_driver, usb_drivers) \
481 usb_driver_##n = {.name = #n, \
482 .class_code = cc, \
483 .subclass = sc, \
484 .protocol = proto, \
485 .bringup = bringup_fn, \
486 .teardown = teardown_fn, \
487 .free = free_fn};
488