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