1#include <drivers/usb/usb.h>
2#include <log.h>
3#include <mem/alloc.h>
4#include <mem/page.h>
5#include <mem/pmm.h>
6#include <mem/vmm.h>
7#include <sch/sched.h>
8#include <string.h>
9#include <thread/thread.h>
10
11#include "internal.h"
12
13#ifdef DEBUG_USB
14LOG_SITE_DEFINE_PRINT(usb);
15#else
16LOG_SITE_DEFINE_PRINT(usb, .enabled_mask = LOG_SITE_LEVEL(LOG_ERROR));
17#endif
18
19LOG_HANDLE_DEFINE_PRINT(usb);
20
21enum usb_error usb_transfer_sync(enum usb_error (*fn)(struct usb_request *),
22 struct usb_request *request) {
23 request->complete = usb_wake_waiter;
24 request->context = NULL;
25 event_init(e: &request->event, type: EVENT_NOTIFICATION, false);
26
27 enum irql irql = irql_raise(new_level: IRQL_DISPATCH_LEVEL);
28 enum usb_error ret = fn(request);
29 irql_lower(old_level: irql);
30
31 if (ret != USB_OK) {
32 usb_warn("ret != USB_OK");
33 return ret;
34 }
35
36 event_wait(e: &request->event, type: THREAD_WAIT_UNINTERRUPTIBLE,
37 reason: THREAD_BLOCK_REASON_IO);
38
39 return request->status;
40}
41
42void usb_wake_waiter(struct usb_request *rq) {
43 event_set_full(e: &rq->event, reason: THREAD_WAKE_REASON_BLOCKING_IO, NULL);
44}
45
46void usb_destroy(struct usb_request *rq) {
47 vfree(rq);
48}
49
50uint8_t usb_construct_rq_bitmap(uint8_t transfer, uint8_t type, uint8_t recip) {
51 uint8_t bitmap = 0;
52 bitmap |= transfer << USB_REQUEST_TRANSFER_SHIFT;
53 bitmap |= type << USB_REQUEST_TYPE_SHIFT;
54 bitmap |= recip;
55 return bitmap;
56}
57
58static uint8_t usb_get_desc_bitmap(void) {
59 return usb_construct_rq_bitmap(USB_REQUEST_TRANS_DTH,
60 USB_REQUEST_TYPE_STANDARD,
61 USB_REQUEST_RECIPIENT_DEVICE);
62}
63
64enum usb_error usb_get_string_descriptor(struct usb_device *dev,
65 uint8_t string_idx, char *out,
66 size_t max_len) {
67 enum usb_error err = USB_OK;
68 if (!string_idx)
69 return USB_ERR_INVALID_ARGUMENT;
70
71 struct usb_controller *ctrl = dev->host;
72 uint8_t *desc = valloc_aligned(PAGE_SIZE, PAGE_SIZE);
73 if (!desc)
74 return USB_ERR_OOM;
75
76 struct usb_setup_packet setup = {
77 .bitmap_request_type = usb_get_desc_bitmap(),
78 .request = USB_RQ_CODE_GET_DESCRIPTOR,
79 .value = (USB_DESC_TYPE_STRING << USB_DESC_TYPE_SHIFT) | string_idx,
80 .index = 0,
81 .length = 255,
82 };
83
84 struct usb_request req = {
85 .setup = &setup,
86 .buffer = desc,
87 .dev = dev,
88 };
89
90 if ((err = usb_transfer_sync(fn: ctrl->ops->submit_control_transfer, request: &req)) !=
91 USB_OK) {
92 vfree_aligned(desc);
93 return err;
94 }
95
96 uint8_t bLength = desc[0];
97 if (bLength < 2) {
98 vfree_aligned(desc);
99 return USB_ERR_INVALID_ARGUMENT;
100 }
101
102 size_t out_idx = 0;
103 for (size_t i = 2; i < bLength && out_idx < (max_len - 1); i += 2) {
104 out[out_idx++] = (desc[i + 1] == 0) ? desc[i] : '?';
105 }
106 out[out_idx] = '\0';
107
108 vfree_aligned(desc);
109 return err;
110}
111
112enum usb_error usb_get_device_descriptor(struct usb_device *dev) {
113 uint8_t *desc = valloc_aligned(PAGE_SIZE, PAGE_SIZE);
114 if (!desc)
115 return USB_ERR_OOM;
116
117 struct usb_setup_packet setup = {
118 .bitmap_request_type = usb_get_desc_bitmap(),
119 .request = USB_RQ_CODE_GET_DESCRIPTOR,
120 .value = (USB_DESC_TYPE_DEVICE << USB_DESC_TYPE_SHIFT),
121 .index = 0,
122 .length = 18,
123 };
124
125 struct usb_controller *ctrl = dev->host;
126
127 struct usb_request request = {
128 .setup = &setup,
129 .buffer = desc,
130 .dev = dev,
131 };
132
133 enum usb_error err;
134 if ((err = usb_transfer_sync(fn: ctrl->ops->submit_control_transfer,
135 request: &request)) != USB_OK) {
136 vfree_aligned(desc);
137 return err;
138 }
139
140 struct usb_device_descriptor *ddesc = (void *) desc;
141
142 usb_get_string_descriptor(dev, string_idx: ddesc->manufacturer, out: dev->manufacturer,
143 max_len: sizeof(dev->manufacturer));
144 usb_get_string_descriptor(dev, string_idx: ddesc->product, out: dev->product,
145 max_len: sizeof(dev->product));
146
147 dev->descriptor = ddesc;
148 return USB_OK;
149}
150
151static void match_interfaces(struct usb_driver *driver,
152 struct usb_device *dev) {
153 for (uint8_t i = 0; i < dev->num_interfaces; i++) {
154 struct usb_interface_descriptor *in = dev->interfaces[i];
155 bool class, subclass, proto;
156 class = driver->class_code == 0xFF || driver->class_code == in->class;
157 subclass = driver->subclass == 0xFF || driver->subclass == in->subclass;
158 proto = driver->protocol == 0xFF || driver->protocol == in->protocol;
159
160 bool everything_matches = class && subclass && proto;
161 if (everything_matches) {
162 if (driver->bringup) {
163 driver->bringup(dev);
164 dev->driver = driver;
165 dev->free = driver->free;
166 dev->teardown = driver->teardown;
167 return;
168 }
169 }
170 }
171}
172
173void usb_try_bind_driver(struct usb_device *dev) {
174 struct usb_driver *start = __skernel_usb_drivers;
175 struct usb_driver *end = __ekernel_usb_drivers;
176
177 for (struct usb_driver *d = start; d < end; d++)
178 match_interfaces(driver: d, dev);
179}
180
181static enum usb_error
182usb_register_dev_interface(struct usb_device *dev,
183 struct usb_interface_descriptor *interface) {
184 struct usb_interface_descriptor *new_int = vnew(new_int);
185 if (!new_int)
186 return USB_ERR_OOM;
187 memcpy(new_int, interface, sizeof(struct usb_interface_descriptor));
188
189 /* on failure vrenews leaves the old array in place */
190 struct usb_interface_descriptor **grown =
191 vrenews(dev->interfaces, dev->num_interfaces + 1);
192 if (!grown) {
193 vfree(new_int);
194 return USB_ERR_OOM;
195 }
196
197 dev->interfaces = grown;
198 dev->interfaces[dev->num_interfaces++] = new_int;
199 return USB_OK;
200}
201
202static enum usb_error
203usb_register_dev_ep(struct usb_device *dev,
204 struct usb_endpoint_descriptor *endpoint) {
205 struct usb_endpoint *ep = vnew(ep, ALLOC_ZERO);
206 if (!ep)
207 return USB_ERR_OOM;
208
209 ep->type = USB_ENDPOINT_ATTR_TRANS_TYPE(endpoint->attributes);
210 ep->number = USB_ENDPOINT_ADDR_EP_NUM(endpoint->address);
211 ep->address = endpoint->address;
212 ep->max_packet_size = endpoint->max_packet_size;
213 ep->interval = endpoint->interval;
214
215 ep->in = USB_ENDPOINT_ADDR_EP_DIRECTION(endpoint->address);
216
217 struct usb_endpoint **grown =
218 vrenews(dev->endpoints, dev->num_endpoints + 1);
219 if (!grown) {
220 vfree(ep);
221 return USB_ERR_OOM;
222 }
223
224 dev->endpoints = grown;
225 dev->endpoints[dev->num_endpoints++] = ep;
226 return USB_OK;
227}
228
229static enum usb_error setup_config_descriptor(struct usb_device *dev,
230 uint8_t *ptr, uint8_t *end) {
231 enum usb_error err = USB_OK;
232
233 while (ptr < end && err == USB_OK) {
234 uint8_t len = ptr[0];
235 uint8_t dtype = ptr[1];
236
237 if (dtype == USB_DESC_TYPE_INTERFACE) {
238 struct usb_interface_descriptor *iface = (void *) ptr;
239 err = usb_register_dev_interface(dev, interface: iface);
240 } else if (dtype == USB_DESC_TYPE_ENDPOINT) {
241 struct usb_endpoint_descriptor *epd = (void *) ptr;
242 err = usb_register_dev_ep(dev, endpoint: epd);
243 }
244
245 ptr += len;
246 }
247
248 return err;
249}
250
251enum usb_error usb_parse_config_descriptor(struct usb_device *dev) {
252 uint8_t *desc = valloc_aligned(PAGE_SIZE, PAGE_SIZE);
253 if (!desc)
254 return USB_ERR_OOM;
255
256 struct usb_setup_packet setup = {
257 .bitmap_request_type = usb_get_desc_bitmap(),
258 .request = USB_RQ_CODE_GET_DESCRIPTOR,
259 .value = (USB_DESC_TYPE_CONFIG << USB_DESC_TYPE_SHIFT),
260 .index = 0,
261 .length = 18,
262 };
263
264 struct usb_controller *ctrl = dev->host;
265
266 struct usb_request request = {
267 .setup = &setup,
268 .buffer = desc,
269 .dev = dev,
270 };
271
272 enum usb_error err;
273 if ((err = usb_transfer_sync(fn: ctrl->ops->submit_control_transfer,
274 request: &request)) != USB_OK) {
275 vfree_aligned(desc);
276 return err;
277 }
278
279 struct usb_config_descriptor *cdesc = (void *) desc;
280 memcpy(&dev->config, cdesc, sizeof(struct usb_config_descriptor));
281
282 uint16_t total_len = cdesc->total_length;
283 setup.length = total_len;
284
285 if ((err = usb_transfer_sync(fn: ctrl->ops->submit_control_transfer,
286 request: &request)) != USB_OK) {
287 vfree_aligned(desc);
288 return err;
289 }
290
291 if ((err = usb_get_string_descriptor(dev, string_idx: cdesc->configuration,
292 out: dev->config_str,
293 max_len: sizeof(dev->config_str))) != USB_OK) {
294 vfree_aligned(desc);
295 return err;
296 }
297
298 err = setup_config_descriptor(dev, ptr: desc, end: desc + total_len);
299 vfree_aligned(desc);
300 return err;
301}
302
303enum usb_error usb_set_configuration(struct usb_device *dev) {
304 struct usb_controller *ctrl = dev->host;
305
306 uint8_t bitmap = usb_construct_rq_bitmap(USB_REQUEST_TRANS_HTD,
307 USB_REQUEST_TYPE_STANDARD,
308 USB_REQUEST_RECIPIENT_DEVICE);
309
310 struct usb_setup_packet set_cfg = {
311 .bitmap_request_type = bitmap,
312 .request = USB_RQ_CODE_SET_CONFIG,
313 .value = dev->config.configuration_value,
314 .index = 0,
315 .length = 0,
316 };
317
318 struct usb_request request = {
319 .setup = &set_cfg,
320 .buffer = NULL,
321 .dev = dev,
322 };
323
324 enum usb_error err;
325 if ((err = usb_transfer_sync(fn: ctrl->ops->submit_control_transfer,
326 request: &request)) != USB_OK) {
327 return err;
328 }
329
330 return USB_OK;
331}
332
333struct usb_interface_descriptor *usb_find_interface(struct usb_device *dev,
334 uint8_t class,
335 uint8_t subclass,
336 uint8_t protocol) {
337 for (size_t i = 0; i < dev->num_interfaces; i++) {
338 struct usb_interface_descriptor *intf = dev->interfaces[i];
339 if (intf->class == class && intf->subclass == subclass &&
340 intf->protocol == protocol)
341 return intf;
342 }
343 return NULL;
344}
345
346void usb_print_device(struct usb_device *dev) {
347 usb_log(LOG_INFO, "Found device '%s' manufactured by '%s' of type '%s'",
348 dev->product, dev->manufacturer, dev->config_str);
349}
350
351enum usb_error usb_init_device(struct usb_device *dev) {
352 if (!usb_device_getref(obj: dev))
353 return USB_ERR_NO_DEVICE;
354
355 enum usb_error err = USB_OK;
356 usb_trace("get_device_descriptor");
357 if ((err = usb_get_device_descriptor(dev)) != USB_OK) {
358 goto out;
359 }
360
361 usb_trace("parse_config");
362 if ((err = usb_parse_config_descriptor(dev)) != USB_OK) {
363 goto out;
364 }
365
366 usb_trace("set_config");
367 if ((err = usb_set_configuration(dev)) != USB_OK) {
368 goto out;
369 }
370
371 usb_trace("configure_endpoint");
372 if ((err = dev->host->ops->configure_endpoint(dev)) != USB_OK) {
373 goto out;
374 }
375
376 usb_print_device(dev);
377
378 usb_try_bind_driver(dev);
379
380out:
381 if (err != USB_OK) {
382 enforce(thread_get_current()->perceived_prio_class ==
383 THREAD_PRIO_CLASS_TIMESHARE);
384 usb_trace("reset_slot");
385 dev->host->ops->reset_slot(dev);
386 }
387
388 usb_device_putref(dev);
389 usb_trace("ok");
390 return err;
391}
392
393void usb_teardown_device(struct usb_device *dev) {
394 struct usb_driver *driver = dev->driver;
395
396 atomic_store_release(&dev->status, USB_DEV_DISCONNECTED);
397
398 if (driver && dev->teardown)
399 dev->teardown(dev);
400
401 dev->driver = NULL;
402 dev->free = NULL;
403 dev->teardown = NULL;
404
405 usb_device_putref(dev);
406}
407
408void usb_free_device(struct usb_device *dev) {
409 if (dev->free)
410 dev->free(dev);
411
412 for (size_t i = 0; i < dev->num_interfaces; i++) {
413 struct usb_interface_descriptor *infdr = dev->interfaces[i];
414 vfree(infdr);
415 }
416 vfree(dev->interfaces);
417
418 for (size_t i = 0; i < dev->num_endpoints; i++) {
419 struct usb_endpoint *uep = dev->endpoints[i];
420 vfree(uep);
421 }
422 vfree(dev->endpoints);
423 vfree_aligned(dev->descriptor);
424}
425