source: mainline/uspace/drv/bus/usb/xhci/bus.c@ 5dfb70c9

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5dfb70c9 was deb2e55, checked in by Petr Manek <petr.manek@…>, 8 years ago

usbhost: refactoring

Moved the "online" attribute from xhci_device_t to device_t. Changed
USB2 bus implementation to produce online devices (not to break
functionality on older buses).

  • Property mode set to 100644
File size: 15.5 KB
RevLine 
[a5976973]1/*
2 * Copyright (c) 2017 Ondrej Hlavaty <aearsis@eideo.cz>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28/** @addtogroup libusbhost
29 * @{
30 */
31/** @file
32 * HC Endpoint management.
33 */
34
[20eaa82]35#include <usb/host/ddf_helpers.h>
[a5976973]36#include <usb/host/endpoint.h>
[20eaa82]37#include <usb/host/hcd.h>
[a5976973]38#include <usb/debug.h>
39
40#include <assert.h>
41#include <errno.h>
[20eaa82]42#include <str_error.h>
[a5976973]43#include <macros.h>
44#include <stdbool.h>
45
[2cf28b9]46#include "hc.h"
[a5976973]47#include "bus.h"
48#include "endpoint.h"
[5fd9c30]49#include "transfers.h"
[a5976973]50
[0206d35]51
[95a62dc]52/** Initial descriptor used for control endpoint 0 before more configuration is retrieved. */
[306a36d]53static const usb_endpoint_desc_t ep0_initial_desc = {
[0206d35]54 .endpoint_no = 0,
55 .direction = USB_DIRECTION_BOTH,
56 .transfer_type = USB_TRANSFER_CONTROL,
57 .max_packet_size = CTRL_PIPE_MIN_PACKET_SIZE,
58 .packets = 1,
59};
60
[6832245]61static endpoint_t *endpoint_create(device_t *, const usb_endpoint_desc_t *);
[0206d35]62
[95a62dc]63/** Assign address and control endpoint to a new XHCI device.
64 * @param[in] bus XHCI bus, in which the address is assigned.
65 * @param[in] dev New device to address and configure.
66 *
67 * @return Error code.
68 */
[6832245]69static int address_device(xhci_bus_t *bus, xhci_device_t *dev)
[0206d35]70{
71 int err;
72
73 /* Enable new slot. */
[6832245]74 if ((err = hc_enable_slot(bus->hc, &dev->slot_id)) != EOK)
[0206d35]75 return err;
76 usb_log_debug2("Obtained slot ID: %u.\n", dev->slot_id);
77
78 /* Create and configure control endpoint. */
[6832245]79 endpoint_t *ep0_base = endpoint_create(&dev->base, &ep0_initial_desc);
[0206d35]80 if (!ep0_base)
81 goto err_slot;
82
83 /* Temporary reference */
84 endpoint_add_ref(ep0_base);
85
86 xhci_endpoint_t *ep0 = xhci_endpoint_get(ep0_base);
87
[6832245]88 if ((err = xhci_endpoint_alloc_transfer_ds(ep0)))
[0206d35]89 goto err_ep;
90
[8b8c164]91 /* Register EP0 */
92 if ((err = xhci_device_add_endpoint(dev, ep0)))
93 goto err_prepared;
94
[0206d35]95 /* Address device */
[6832245]96 if ((err = hc_address_device(bus->hc, dev, ep0)))
[8b8c164]97 goto err_added;
[0206d35]98
[8b8c164]99 /* Temporary reference */
100 endpoint_del_ref(ep0_base);
[0206d35]101 return EOK;
102
[8b8c164]103err_added:
104 xhci_device_remove_endpoint(ep0);
105err_prepared:
[0206d35]106 xhci_endpoint_free_transfer_ds(ep0);
107err_ep:
[8b8c164]108 /* Temporary reference */
[0206d35]109 endpoint_del_ref(ep0_base);
110err_slot:
[6832245]111 hc_disable_slot(bus->hc, dev);
[0206d35]112 return err;
113}
114
[95a62dc]115/** Retrieve and set maximum packet size for endpoint zero of a XHCI device.
116 * @param[in] hc Host controller, which manages the device.
117 * @param[in] dev Device with operational endpoint zero.
118 *
119 * @return Error code.
120 */
[306a36d]121static int setup_ep0_packet_size(xhci_hc_t *hc, xhci_device_t *dev)
122{
123 int err;
124
125 uint16_t max_packet_size;
[32fb6bce]126 if ((err = hcd_get_ep0_max_packet_size(&max_packet_size, (bus_t *) &hc->bus, &dev->base)))
[306a36d]127 return err;
128
129 xhci_endpoint_t *ep0 = dev->endpoints[0];
130 assert(ep0);
131
132 if (ep0->base.max_packet_size == max_packet_size)
133 return EOK;
134
135 ep0->base.max_packet_size = max_packet_size;
136
137 xhci_ep_ctx_t ep_ctx;
138 xhci_setup_endpoint_context(ep0, &ep_ctx);
139
140 if ((err = hc_update_endpoint(hc, dev->slot_id, 0, &ep_ctx)))
141 return err;
142
143 return EOK;
144}
145
[95a62dc]146/** Respond to a new device on the XHCI bus. Address it, negotiate packet size
147 * and retrieve USB descriptors.
148 * @param[in] bus XHCI bus, where the new device emerged.
149 * @param[in] dev XHCI device, which has appeared on the bus.
150 *
151 * @return Error code.
152 */
[6832245]153int xhci_bus_enumerate_device(xhci_bus_t *bus, device_t *dev)
[20eaa82]154{
155 int err;
[2b61945]156 xhci_device_t *xhci_dev = xhci_device_get(dev);
[20eaa82]157
[ff14aede]158 hcd_setup_device_tt(dev);
[20eaa82]159
[2cf28b9]160 /* Calculate route string */
161 xhci_device_t *xhci_hub = xhci_device_get(dev->hub);
162 xhci_dev->tier = xhci_hub->tier + 1;
163 xhci_dev->route_str = xhci_hub->route_str;
164
165 /* Roothub port is not part of the route string */
166 if (xhci_dev->tier >= 2) {
167 const unsigned offset = 4 * (xhci_dev->tier - 2);
168 xhci_dev->route_str |= (dev->port & 0xf) << offset;
[62558202]169 xhci_dev->rh_port = xhci_hub->rh_port;
[2cf28b9]170 }
171
[20eaa82]172 /* Assign an address to the device */
[6832245]173 if ((err = address_device(bus, xhci_dev))) {
[20eaa82]174 usb_log_error("Failed to setup address of the new device: %s", str_error(err));
175 return err;
176 }
177
[53db806]178 /* Setup EP0 might already need to issue a transfer. */
179 fibril_mutex_lock(&bus->base.guard);
180 assert(bus->devices_by_slot[xhci_dev->slot_id] == NULL);
181 bus->devices_by_slot[xhci_dev->slot_id] = xhci_dev;
182 fibril_mutex_unlock(&bus->base.guard);
183
[6832245]184 if ((err = setup_ep0_packet_size(bus->hc, xhci_dev))) {
[306a36d]185 usb_log_error("Failed to setup control endpoint of the new device: %s", str_error(err));
186 goto err_address;
187 }
[0206d35]188
[20eaa82]189 /* Read the device descriptor, derive the match ids */
[32fb6bce]190 if ((err = hcd_device_explore(dev))) {
[20eaa82]191 usb_log_error("Device(%d): Failed to explore device: %s", dev->address, str_error(err));
[327f147]192 goto err_address;
[20eaa82]193 }
194
195 return EOK;
[2b61945]196
197err_address:
[10cd715]198 // TODO: deaddress device
[2b61945]199 return err;
[20eaa82]200}
201
[6832245]202static int endpoint_unregister(endpoint_t *);
[0206d35]203
[95a62dc]204/** Remove device from XHCI bus. Transition it to the offline state, abort all
205 * ongoing transfers and unregister all of its endpoints.
206 * @param[in] bus XHCI bus, from which the device is removed.
207 * @param[in] dev XHCI device, which is removed from the bus.
208 *
209 * @return Error code.
210 */
[6832245]211int xhci_bus_remove_device(xhci_bus_t *bus, device_t *dev)
[20eaa82]212{
[40a3bfa]213 int err;
[2b61945]214 xhci_device_t *xhci_dev = xhci_device_get(dev);
215
[40a3bfa]216 /* Block creation of new endpoints and transfers. */
[9620a54]217 usb_log_debug2("Device " XHCI_DEV_FMT " going offline.", XHCI_DEV_ARGS(*xhci_dev));
[40a3bfa]218 fibril_mutex_lock(&dev->guard);
[deb2e55]219 dev->online = false;
[40a3bfa]220 fibril_mutex_unlock(&dev->guard);
221
222 /* Abort running transfers. */
[9620a54]223 usb_log_debug2("Aborting all active transfers to device " XHCI_DEV_FMT ".", XHCI_DEV_ARGS(*xhci_dev));
[40a3bfa]224 for (size_t i = 0; i < ARRAY_SIZE(xhci_dev->endpoints); ++i) {
225 xhci_endpoint_t *ep = xhci_dev->endpoints[i];
[17873ac7]226 if (!ep)
[40a3bfa]227 continue;
228
[17873ac7]229 endpoint_abort(&ep->base);
[40a3bfa]230 }
231
232 /* TODO: Figure out how to handle errors here. So far, they are reported and skipped. */
233
234 /* Make DDF (and all drivers) forget about the device. */
235 if ((err = ddf_fun_unbind(dev->fun))) {
[9620a54]236 usb_log_warning("Failed to unbind DDF function of device " XHCI_DEV_FMT ": %s",
237 XHCI_DEV_ARGS(*xhci_dev), str_error(err));
[40a3bfa]238 }
239
[9620a54]240 /* Disable the slot, dropping all endpoints. */
241 const uint32_t slot_id = xhci_dev->slot_id;
[6832245]242 if ((err = hc_disable_slot(bus->hc, xhci_dev))) {
[9620a54]243 usb_log_warning("Failed to disable slot of device " XHCI_DEV_FMT ": %s",
244 XHCI_DEV_ARGS(*xhci_dev), str_error(err));
245 }
246
247 bus->devices_by_slot[slot_id] = NULL;
248
249 /* Unregister remaining endpoints, freeing memory. */
[0206d35]250 for (unsigned i = 0; i < ARRAY_SIZE(xhci_dev->endpoints); ++i) {
[a4e26882]251 if (!xhci_dev->endpoints[i])
252 continue;
253
[6832245]254 if ((err = endpoint_unregister(&xhci_dev->endpoints[i]->base))) {
[9620a54]255 usb_log_warning("Failed to unregister endpoint " XHCI_EP_FMT ": %s",
256 XHCI_EP_ARGS(*xhci_dev->endpoints[i]), str_error(err));
[40a3bfa]257 }
[a4e26882]258 }
[2b61945]259
[6b2930b]260 /* Destroy DDF device. */
261 /* XXX: Not a good idea, this method should not destroy devices. */
[32fb6bce]262 hcd_ddf_fun_destroy(dev);
[6b2930b]263
[31cca4f3]264 return EOK;
[20eaa82]265}
266
[a5976973]267/** Ops receive generic bus_t pointer. */
268static inline xhci_bus_t *bus_to_xhci_bus(bus_t *bus_base)
269{
270 assert(bus_base);
271 return (xhci_bus_t *) bus_base;
272}
273
[95a62dc]274// TODO: Fill in docstrings for XHCI bus callbacks once generic bus callbacks get their docstrings.
275
[6832245]276static int device_enumerate(device_t *dev)
[8ea7459]277{
[6832245]278 xhci_bus_t *bus = bus_to_xhci_bus(dev->bus);
279 return xhci_bus_enumerate_device(bus, dev);
[8ea7459]280}
281
[6832245]282static int device_remove(device_t *dev)
[8ea7459]283{
[6832245]284 xhci_bus_t *bus = bus_to_xhci_bus(dev->bus);
285 return xhci_bus_remove_device(bus, dev);
[8ea7459]286}
287
[6832245]288static int device_online(device_t *dev_base)
[d37514e]289{
290 int err;
291
[6832245]292 xhci_bus_t *bus = bus_to_xhci_bus(dev_base->bus);
[d37514e]293 assert(bus);
294
295 xhci_device_t *dev = xhci_device_get(dev_base);
296 assert(dev);
297
[6b2930b]298 /* Transition the device from the Addressed to the Configured state. */
[6832245]299 if ((err = hc_configure_device(bus->hc, dev->slot_id))) {
[9620a54]300 usb_log_warning("Failed to configure device " XHCI_DEV_FMT ".", XHCI_DEV_ARGS(*dev));
[6b2930b]301 }
302
[67d58e8]303 /* Allow creation of new endpoints and transfers. */
[9620a54]304 usb_log_debug2("Device " XHCI_DEV_FMT " going online.", XHCI_DEV_ARGS(*dev));
[6b2930b]305 fibril_mutex_lock(&dev_base->guard);
[deb2e55]306 dev_base->online = true;
[6b2930b]307 fibril_mutex_unlock(&dev_base->guard);
[d37514e]308
309 if ((err = ddf_fun_online(dev_base->fun))) {
310 return err;
311 }
312
313 return EOK;
314}
315
[6832245]316static int device_offline(device_t *dev_base)
[d37514e]317{
318 int err;
319
[6832245]320 xhci_bus_t *bus = bus_to_xhci_bus(dev_base->bus);
[d37514e]321 assert(bus);
322
323 xhci_device_t *dev = xhci_device_get(dev_base);
324 assert(dev);
325
326 /* Tear down all drivers working with the device. */
327 if ((err = ddf_fun_offline(dev_base->fun))) {
328 return err;
329 }
330
[6b2930b]331 /* Block creation of new endpoints and transfers. */
[9620a54]332 usb_log_debug2("Device " XHCI_DEV_FMT " going offline.", XHCI_DEV_ARGS(*dev));
[6b2930b]333 fibril_mutex_lock(&dev_base->guard);
[deb2e55]334 dev_base->online = false;
[6b2930b]335 fibril_mutex_unlock(&dev_base->guard);
336
337 /* We will need the endpoint array later for DS deallocation. */
338 xhci_endpoint_t *endpoints[ARRAY_SIZE(dev->endpoints)];
339 memcpy(endpoints, dev->endpoints, sizeof(dev->endpoints));
340
341 /* Remove all endpoints except zero. */
342 for (unsigned i = 1; i < ARRAY_SIZE(endpoints); ++i) {
343 if (!endpoints[i])
344 continue;
345
346 /* FIXME: Asserting here that the endpoint is not active. If not, EBUSY? */
347
348 xhci_device_remove_endpoint(endpoints[i]);
349 }
350
351 /* Issue one HC command to simultaneously drop all endpoints except zero. */
[6832245]352 if ((err = hc_deconfigure_device(bus->hc, dev->slot_id))) {
[9620a54]353 usb_log_warning("Failed to deconfigure device " XHCI_DEV_FMT ".",
354 XHCI_DEV_ARGS(*dev));
[6b2930b]355 }
356
357 /* Tear down TRB ring / PSA. */
358 for (unsigned i = 1; i < ARRAY_SIZE(endpoints); ++i) {
359 if (!endpoints[i])
360 continue;
361
[9620a54]362 xhci_endpoint_free_transfer_ds(endpoints[i]);
[6b2930b]363 }
364
365 /* FIXME: What happens to unregistered endpoints now? Destroy them? */
[d37514e]366
367 return EOK;
368}
369
[6832245]370static endpoint_t *endpoint_create(device_t *dev, const usb_endpoint_desc_t *desc)
[a5976973]371{
[2b61945]372 xhci_endpoint_t *ep = calloc(1, sizeof(xhci_endpoint_t));
[a5976973]373 if (!ep)
374 return NULL;
375
[6832245]376 if (xhci_endpoint_init(ep, dev, desc)) {
[a5976973]377 free(ep);
378 return NULL;
379 }
380
381 return &ep->base;
382}
383
[6832245]384static void endpoint_destroy(endpoint_t *ep)
[a5976973]385{
386 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(ep);
387
388 xhci_endpoint_fini(xhci_ep);
389 free(xhci_ep);
390}
391
[6832245]392static int endpoint_register(endpoint_t *ep_base)
[add878aa]393{
[0206d35]394 int err;
[6832245]395 xhci_bus_t *bus = bus_to_xhci_bus(endpoint_get_bus(ep_base));
[8b8c164]396 xhci_endpoint_t *ep = xhci_endpoint_get(ep_base);
[a8435eb5]397
[6832245]398 xhci_device_t *dev = xhci_device_get(ep_base->device);
[56db65d]399
[6832245]400 if ((err = xhci_endpoint_alloc_transfer_ds(ep)))
[0206d35]401 return err;
[56db65d]402
[8b8c164]403 if ((err = xhci_device_add_endpoint(dev, ep)))
404 goto err_prepared;
405
[9620a54]406 usb_log_info("Endpoint " XHCI_EP_FMT " registered to XHCI bus.", XHCI_EP_ARGS(*ep));
[8b8c164]407
408 xhci_ep_ctx_t ep_ctx;
409 xhci_setup_endpoint_context(ep, &ep_ctx);
410
411 if ((err = hc_add_endpoint(bus->hc, dev->slot_id, xhci_endpoint_index(ep), &ep_ctx)))
412 goto err_added;
413
414 return EOK;
415
416err_added:
417 xhci_device_remove_endpoint(ep);
418err_prepared:
419 xhci_endpoint_free_transfer_ds(ep);
420 return err;
[add878aa]421}
422
[6832245]423static int endpoint_unregister(endpoint_t *ep_base)
[add878aa]424{
[8b8c164]425 int err;
[6832245]426 xhci_bus_t *bus = bus_to_xhci_bus(endpoint_get_bus(ep_base));
[8b8c164]427 xhci_endpoint_t *ep = xhci_endpoint_get(ep_base);
428 xhci_device_t *dev = xhci_device_get(ep_base->device);
[a8435eb5]429
[9620a54]430 usb_log_info("Endpoint " XHCI_EP_FMT " unregistered from XHCI bus.", XHCI_EP_ARGS(*ep));
[9b2f69e]431
[8b8c164]432 xhci_device_remove_endpoint(ep);
433
[9620a54]434 /* If device slot is still available, drop the endpoint. */
435 if (dev->slot_id) {
436 if ((err = hc_drop_endpoint(bus->hc, dev->slot_id, xhci_endpoint_index(ep)))) {
437 usb_log_error("Failed to drop endpoint " XHCI_EP_FMT ": %s", XHCI_EP_ARGS(*ep), str_error(err));
438 }
439 } else {
440 usb_log_debug("Not going to drop endpoint " XHCI_EP_FMT " because"
441 " the slot has already been disabled.", XHCI_EP_ARGS(*ep));
[8b8c164]442 }
443
444 /* Tear down TRB ring / PSA. */
[9620a54]445 xhci_endpoint_free_transfer_ds(ep);
[c10daa8]446
[a8435eb5]447 return EOK;
[add878aa]448}
449
[6832245]450static endpoint_t* device_find_endpoint(device_t *dev_base, usb_target_t target, usb_direction_t direction)
[add878aa]451{
[327f147]452 xhci_device_t *dev = xhci_device_get(dev_base);
[a4e26882]453
[327f147]454 xhci_endpoint_t *ep = xhci_device_get_endpoint(dev, target.endpoint);
455 if (!ep)
[a8435eb5]456 return NULL;
457
[c10daa8]458 return &ep->base;
[add878aa]459}
460
[17873ac7]461static int reset_toggle(bus_t *bus_base, usb_target_t target, toggle_reset_mode_t mode)
[add878aa]462{
463 // TODO: Implement me!
464 return ENOTSUP;
465}
466
467/* Endpoint ops, optional (have generic fallback) */
[e6b9182]468static bool endpoint_get_toggle(endpoint_t *ep)
[add878aa]469{
470 // TODO: Implement me!
471 return ENOTSUP;
472}
473
[e6b9182]474static void endpoint_set_toggle(endpoint_t *ep, bool toggle)
[add878aa]475{
476 // TODO: Implement me!
477}
478
[10cd715]479static int reserve_default_address(bus_t *bus_base, usb_speed_t speed)
[2cf28b9]480{
481 xhci_bus_t *xhci_bus = bus_to_xhci_bus(bus_base);
482
483 if (xhci_bus->default_address_speed != USB_SPEED_MAX)
484 /* Already allocated */
485 return ENOENT;
486
487 xhci_bus->default_address_speed = speed;
488 return EOK;
489}
490
[10cd715]491static int release_default_address(bus_t *bus_base)
[2cf28b9]492{
493 xhci_bus_t *xhci_bus = bus_to_xhci_bus(bus_base);
494
495 xhci_bus->default_address_speed = USB_SPEED_MAX;
496 return EOK;
497}
498
[6832245]499static usb_transfer_batch_t *batch_create(endpoint_t *ep)
[5fd9c30]500{
501 xhci_transfer_t *transfer = xhci_transfer_create(ep);
502 return &transfer->batch;
503}
504
[6832245]505static void batch_destroy(usb_transfer_batch_t *batch)
[5fd9c30]506{
507 xhci_transfer_destroy(xhci_transfer_from_batch(batch));
508}
509
[95a62dc]510/** Structure binding XHCI static callbacks to generic bus callbacks. */
[a5976973]511static const bus_ops_t xhci_bus_ops = {
[95a62dc]512// TODO: Is it good idea to use this macro? It blurrs the fact that the callbacks and static functions are called the same.
[9868982]513#define BIND_OP(op) .op = op,
[10cd715]514 BIND_OP(reserve_default_address)
515 BIND_OP(release_default_address)
516 BIND_OP(reset_toggle)
[a5976973]517
[6832245]518 BIND_OP(device_enumerate)
519 BIND_OP(device_remove)
520 BIND_OP(device_online)
521 BIND_OP(device_offline)
522 BIND_OP(device_find_endpoint)
523
524 BIND_OP(endpoint_create)
525 BIND_OP(endpoint_destroy)
526 BIND_OP(endpoint_register)
527 BIND_OP(endpoint_unregister)
[9868982]528 BIND_OP(endpoint_get_toggle)
529 BIND_OP(endpoint_set_toggle)
[5fd9c30]530
[6832245]531 BIND_OP(batch_create)
532 BIND_OP(batch_destroy)
[9868982]533#undef BIND_OP
[32fb6bce]534
535 .interrupt = hc_interrupt,
536 .status = hc_status,
537 .batch_schedule = hc_schedule,
[a5976973]538};
539
[95a62dc]540/** Initialize XHCI bus.
541 * @param[in] bus Allocated XHCI bus to initialize.
542 * @param[in] hc Associated host controller, which manages the bus.
543 *
544 * @return Error code.
545 */
[2b61945]546int xhci_bus_init(xhci_bus_t *bus, xhci_hc_t *hc)
[a5976973]547{
548 assert(bus);
549
[32fb6bce]550 bus_init(&bus->base, sizeof(xhci_device_t));
[2b61945]551
552 bus->devices_by_slot = calloc(hc->max_slots, sizeof(xhci_device_t *));
553 if (!bus->devices_by_slot)
554 return ENOMEM;
[a5976973]555
[25251bb]556 bus->hc = hc;
[6832245]557 bus->base.ops = &xhci_bus_ops;
[2cf28b9]558 bus->default_address_speed = USB_SPEED_MAX;
[a5976973]559 return EOK;
560}
[a8435eb5]561
[95a62dc]562/** Finalize XHCI bus.
563 * @param[in] bus XHCI bus to finalize.
564 */
[a8435eb5]565void xhci_bus_fini(xhci_bus_t *bus)
566{
[95a62dc]567 // FIXME: Deallocate bus->devices_by_slot?
568 // FIXME: Should there be some bus_fini() to call?
569 // FIXME: Something else we forgot?
[a8435eb5]570}
[20eaa82]571
[a5976973]572/**
573 * @}
574 */
Note: See TracBrowser for help on using the repository browser.