Changeset 682c9354 in mainline
- Timestamp:
- 2018-01-20T15:32:12Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- abb5d08
- Parents:
- 129b821f
- Location:
- uspace/drv/bus/usb/xhci
- Files:
-
- 2 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/xhci/Makefile
r129b821f r682c9354 37 37 commands.c \ 38 38 debug.c \ 39 device.c \ 39 40 endpoint.c \ 40 41 hc.c \ -
uspace/drv/bus/usb/xhci/bus.c
r129b821f r682c9354 30 30 */ 31 31 /** @file 32 * HC Endpoint management.32 * xHCI bus interface. 33 33 */ 34 34 35 #include <usb/host/ddf_helpers.h>36 #include <usb/host/endpoint.h>37 #include <usb/host/hcd.h>38 #include <usb/host/utility.h>39 #include <usb/classes/classes.h>40 #include <usb/classes/hub.h>41 35 #include <usb/descriptor.h> 42 #include <usb/debug.h>43 44 #include <assert.h>45 #include <errno.h>46 #include <str_error.h>47 #include <macros.h>48 #include <stdbool.h>49 36 50 37 #include "hc.h" 51 #include " bus.h"38 #include "device.h" 52 39 #include "endpoint.h" 53 40 #include "transfers.h" 54 41 42 #include "bus.h" 55 43 56 /** Initial descriptor used for control endpoint 0 before more configuration is retrieved. */57 static const usb_endpoint_descriptors_t ep0_initial_desc = {58 .endpoint.max_packet_size = CTRL_PIPE_MIN_PACKET_SIZE,59 };60 61 static endpoint_t *endpoint_create(device_t *, const usb_endpoint_descriptors_t *);62 63 /**64 * Assign address and control endpoint to a new XHCI device. Once this function65 * successfully returns, the device is online.66 *67 * @param[in] bus XHCI bus, in which the address is assigned.68 * @param[in] dev New device to address and configure./e69 * @return Error code.70 */71 static int address_device(xhci_device_t *dev)72 {73 int err;74 75 /* Enable new slot. */76 if ((err = hc_enable_slot(dev)) != EOK)77 return err;78 usb_log_debug2("Obtained slot ID: %u.", dev->slot_id);79 80 /* Create and configure control endpoint. */81 endpoint_t *ep0_base = endpoint_create(&dev->base, &ep0_initial_desc);82 if (!ep0_base)83 goto err_slot;84 85 /* Bus reference */86 endpoint_add_ref(ep0_base);87 dev->base.endpoints[0] = ep0_base;88 89 xhci_endpoint_t *ep0 = xhci_endpoint_get(ep0_base);90 91 /* Address device */92 if ((err = hc_address_device(dev, ep0)))93 goto err_added;94 95 return EOK;96 97 err_added:98 /* Bus reference */99 endpoint_del_ref(ep0_base);100 dev->base.endpoints[0] = NULL;101 err_slot:102 hc_disable_slot(dev);103 return err;104 }105 106 /**107 * Retrieve and set maximum packet size for endpoint zero of a XHCI device.108 *109 * @param[in] hc Host controller, which manages the device.110 * @param[in] dev Device with operational endpoint zero.111 * @return Error code.112 */113 static int setup_ep0_packet_size(xhci_hc_t *hc, xhci_device_t *dev)114 {115 int err;116 117 uint16_t max_packet_size;118 if ((err = hc_get_ep0_max_packet_size(&max_packet_size, (bus_t *) &hc->bus, &dev->base)))119 return err;120 121 xhci_endpoint_t *ep0 = xhci_endpoint_get(dev->base.endpoints[0]);122 assert(ep0);123 124 if (ep0->base.max_packet_size == max_packet_size)125 return EOK;126 127 ep0->base.max_packet_size = max_packet_size;128 ep0->base.max_transfer_size = max_packet_size * ep0->base.packets_per_uframe;129 130 xhci_ep_ctx_t ep_ctx;131 xhci_setup_endpoint_context(ep0, &ep_ctx);132 133 if ((err = hc_update_endpoint(dev, 0, &ep_ctx)))134 return err;135 136 return EOK;137 }138 139 /**140 * Check whether the device is a hub and if so, fill its characterstics.141 *142 * If this fails, it does not necessarily mean the device is unusable.143 * Just the TT will not work correctly.144 */145 static int setup_hub(xhci_device_t *dev, usb_standard_device_descriptor_t *desc)146 {147 if (desc->device_class != USB_CLASS_HUB)148 return EOK;149 150 usb_hub_descriptor_header_t hub_desc = { 0 };151 const int err = hc_get_hub_desc(&dev->base, &hub_desc);152 if (err)153 return err;154 155 dev->is_hub = 1;156 dev->num_ports = hub_desc.port_count;157 dev->tt_think_time = 8 +158 8 * !!(hub_desc.characteristics & HUB_CHAR_TT_THINK_8) +159 16 * !!(hub_desc.characteristics & HUB_CHAR_TT_THINK_16);160 161 usb_log_debug2("Device(%u): recognised USB hub with %u ports", dev->base.address, dev->num_ports);162 return EOK;163 }164 165 /**166 * Respond to a new device on the XHCI bus. Address it, negotiate packet size167 * and retrieve USB descriptors.168 *169 * @param[in] bus XHCI bus, where the new device emerged.170 * @param[in] dev XHCI device, which has appeared on the bus.171 *172 * @return Error code.173 */174 static int device_enumerate(device_t *dev)175 {176 int err;177 xhci_bus_t *bus = bus_to_xhci_bus(dev->bus);178 xhci_device_t *xhci_dev = xhci_device_get(dev);179 180 /* Calculate route string */181 xhci_device_t *xhci_hub = xhci_device_get(dev->hub);182 xhci_dev->tier = xhci_hub->tier + 1;183 xhci_dev->route_str = xhci_hub->route_str;184 185 /* Roothub port is not part of the route string */186 if (xhci_dev->tier >= 2) {187 const unsigned offset = 4 * (xhci_dev->tier - 2);188 xhci_dev->route_str |= (dev->port & 0xf) << offset;189 xhci_dev->rh_port = xhci_hub->rh_port;190 }191 192 int retries = 3;193 do {194 /* Assign an address to the device */195 err = address_device(xhci_dev);196 } while (err == ESTALL && --retries > 0);197 198 if (err) {199 usb_log_error("Failed to setup address of the new device: %s", str_error(err));200 return err;201 }202 203 /* Setup EP0 might already need to issue a transfer. */204 fibril_mutex_lock(&bus->base.guard);205 assert(bus->devices_by_slot[xhci_dev->slot_id] == NULL);206 bus->devices_by_slot[xhci_dev->slot_id] = xhci_dev;207 fibril_mutex_unlock(&bus->base.guard);208 209 if ((err = setup_ep0_packet_size(bus->hc, xhci_dev))) {210 usb_log_error("Failed to setup control endpoint of the new device: %s", str_error(err));211 goto err_address;212 }213 214 usb_standard_device_descriptor_t desc = { 0 };215 216 if ((err = hc_get_device_desc(dev, &desc))) {217 usb_log_error("Device(%d): failed to get devices descriptor: %s", dev->address, str_error(err));218 goto err_address;219 }220 221 if ((err = setup_hub(xhci_dev, &desc)))222 usb_log_warning("Device(%d): failed to setup hub characteristics: %s. "223 " Continuing anyway.", dev->address, str_error(err));224 225 if ((err = hcd_ddf_setup_match_ids(dev, &desc))) {226 usb_log_error("Device(%d): failed to setup match IDs: %s", dev->address, str_error(err));227 goto err_address;228 }229 230 return EOK;231 232 err_address:233 // TODO: deaddress device234 return err;235 }236 237 /**238 * Remove device from XHCI bus. Transition it to the offline state, abort all239 * ongoing transfers and unregister all of its endpoints.240 *241 * Bus callback.242 *243 * @param[in] bus XHCI bus, from which the device is removed.244 * @param[in] dev XHCI device, which is removed from the bus.245 * @return Error code.246 */247 static void device_gone(device_t *dev)248 {249 int err;250 xhci_bus_t *bus = bus_to_xhci_bus(dev->bus);251 xhci_device_t *xhci_dev = xhci_device_get(dev);252 253 /* Disable the slot, dropping all endpoints. */254 const uint32_t slot_id = xhci_dev->slot_id;255 if ((err = hc_disable_slot(xhci_dev))) {256 usb_log_warning("Failed to disable slot of device " XHCI_DEV_FMT ": %s",257 XHCI_DEV_ARGS(*xhci_dev), str_error(err));258 }259 260 bus->devices_by_slot[slot_id] = NULL;261 }262 263 /**264 * Reverts things device_offline did, getting the device back up.265 *266 * Bus callback.267 */268 static int device_online(device_t *dev_base)269 {270 int err;271 272 xhci_bus_t *bus = bus_to_xhci_bus(dev_base->bus);273 assert(bus);274 275 xhci_device_t *dev = xhci_device_get(dev_base);276 assert(dev);277 278 /* Transition the device from the Addressed to the Configured state. */279 if ((err = hc_configure_device(dev))) {280 usb_log_warning("Failed to configure device " XHCI_DEV_FMT ".", XHCI_DEV_ARGS(*dev));281 return err;282 }283 284 return EOK;285 }286 287 /**288 * Make given device offline. Offline the DDF function, tear down all289 * endpoints, issue Deconfigure Device command to xHC.290 *291 * Bus callback.292 */293 static void device_offline(device_t *dev_base)294 {295 int err;296 297 xhci_bus_t *bus = bus_to_xhci_bus(dev_base->bus);298 assert(bus);299 300 xhci_device_t *dev = xhci_device_get(dev_base);301 assert(dev);302 303 /* Issue one HC command to simultaneously drop all endpoints except zero. */304 if ((err = hc_deconfigure_device(dev))) {305 usb_log_warning("Failed to deconfigure device " XHCI_DEV_FMT ".",306 XHCI_DEV_ARGS(*dev));307 }308 }309 310 /**311 * Create a new xHCI endpoint structure.312 *313 * Bus callback.314 */315 static endpoint_t *endpoint_create(device_t *dev, const usb_endpoint_descriptors_t *desc)316 {317 const usb_transfer_type_t type = USB_ED_GET_TRANSFER_TYPE(desc->endpoint);318 319 xhci_endpoint_t *ep = calloc(1, sizeof(xhci_endpoint_t)320 + (type == USB_TRANSFER_ISOCHRONOUS) * sizeof(*ep->isoch));321 if (!ep)322 return NULL;323 324 if (xhci_endpoint_init(ep, dev, desc)) {325 free(ep);326 return NULL;327 }328 329 return &ep->base;330 }331 332 /**333 * Destroy given xHCI endpoint structure.334 *335 * Bus callback.336 */337 static void endpoint_destroy(endpoint_t *ep)338 {339 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(ep);340 341 xhci_endpoint_fini(xhci_ep);342 free(xhci_ep);343 }344 345 /**346 * Register an andpoint to the xHC.347 *348 * Bus callback.349 */350 static int endpoint_register(endpoint_t *ep_base)351 {352 int err;353 xhci_endpoint_t *ep = xhci_endpoint_get(ep_base);354 xhci_device_t *dev = xhci_device_get(ep_base->device);355 356 xhci_ep_ctx_t ep_ctx;357 xhci_setup_endpoint_context(ep, &ep_ctx);358 359 if ((err = hc_add_endpoint(dev, xhci_endpoint_index(ep), &ep_ctx)))360 return err;361 362 return EOK;363 }364 365 /**366 * Abort a transfer on an endpoint.367 */368 static int endpoint_abort(endpoint_t *ep)369 {370 xhci_device_t *dev = xhci_device_get(ep->device);371 372 usb_transfer_batch_t *batch = NULL;373 fibril_mutex_lock(&ep->guard);374 if (ep->active_batch) {375 if (dev->slot_id) {376 const int err = hc_stop_endpoint(dev, xhci_endpoint_dci(xhci_endpoint_get(ep)));377 if (err) {378 usb_log_warning("Failed to stop endpoint %u of device " XHCI_DEV_FMT ": %s",379 ep->endpoint, XHCI_DEV_ARGS(*dev), str_error(err));380 }381 382 endpoint_wait_timeout_locked(ep, 2000);383 }384 385 batch = ep->active_batch;386 if (batch) {387 endpoint_deactivate_locked(ep);388 }389 }390 fibril_mutex_unlock(&ep->guard);391 392 if (batch) {393 batch->error = EINTR;394 batch->transfered_size = 0;395 usb_transfer_batch_finish(batch);396 }397 return EOK;398 }399 400 /**401 * Unregister an endpoint. If the device is still available, inform the xHC402 * about it.403 *404 * Bus callback.405 */406 static void endpoint_unregister(endpoint_t *ep_base)407 {408 int err;409 xhci_endpoint_t *ep = xhci_endpoint_get(ep_base);410 xhci_device_t *dev = xhci_device_get(ep_base->device);411 412 endpoint_abort(ep_base);413 414 /* If device slot is still available, drop the endpoint. */415 if (dev->slot_id) {416 417 if ((err = hc_drop_endpoint(dev, xhci_endpoint_index(ep)))) {418 usb_log_error("Failed to drop endpoint " XHCI_EP_FMT ": %s", XHCI_EP_ARGS(*ep), str_error(err));419 }420 } else {421 usb_log_debug("Not going to drop endpoint " XHCI_EP_FMT " because"422 " the slot has already been disabled.", XHCI_EP_ARGS(*ep));423 }424 }425 426 /**427 * Schedule a batch for xHC.428 *429 * Bus callback.430 */431 static int batch_schedule(usb_transfer_batch_t *batch)432 {433 assert(batch);434 xhci_hc_t *hc = bus_to_hc(endpoint_get_bus(batch->ep));435 436 if (!batch->target.address) {437 usb_log_error("Attempted to schedule transfer to address 0.");438 return EINVAL;439 }440 441 return xhci_transfer_schedule(hc, batch);442 }443 44 444 45 static const bus_ops_t xhci_bus_ops = { … … 446 47 .status = hc_status, 447 48 448 .device_enumerate = device_enumerate,449 .device_gone = device_gone,450 .device_online = device_online,451 .device_offline = device_offline,49 .device_enumerate = xhci_device_enumerate, 50 .device_gone = xhci_device_gone, 51 .device_online = xhci_device_online, 52 .device_offline = xhci_device_offline, 452 53 453 .endpoint_create = endpoint_create,454 .endpoint_destroy = endpoint_destroy,455 .endpoint_register = endpoint_register,456 .endpoint_unregister = endpoint_unregister,54 .endpoint_create = xhci_endpoint_create, 55 .endpoint_destroy = xhci_endpoint_destroy, 56 .endpoint_register = xhci_endpoint_register, 57 .endpoint_unregister = xhci_endpoint_unregister, 457 58 458 .batch_schedule = batch_schedule,59 .batch_schedule = xhci_transfer_schedule, 459 60 .batch_create = xhci_transfer_create, 460 61 .batch_destroy = xhci_transfer_destroy, -
uspace/drv/bus/usb/xhci/bus.h
r129b821f r682c9354 38 38 #define XHCI_BUS_H 39 39 40 #include <usb/usb.h>41 40 #include <usb/host/bus.h> 42 41 … … 56 55 void xhci_bus_fini(xhci_bus_t *); 57 56 58 int xhci_bus_enumerate_device(xhci_bus_t *, device_t *);59 int xhci_bus_remove_device(xhci_bus_t *, device_t *);60 61 57 static inline xhci_bus_t *bus_to_xhci_bus(bus_t *bus_base) 62 58 { -
uspace/drv/bus/usb/xhci/endpoint.c
r129b821f r682c9354 39 39 #include <errno.h> 40 40 #include <macros.h> 41 #include <str_error.h> 41 42 42 43 #include "hc.h" 43 44 #include "bus.h" 44 45 #include "commands.h" 46 #include "device.h" 45 47 #include "endpoint.h" 46 48 #include "streams.h" … … 56 58 * @return Error code. 57 59 */ 58 int xhci_endpoint_init(xhci_endpoint_t *xhci_ep, device_t *dev, const usb_endpoint_descriptors_t *desc)60 static int xhci_endpoint_init(xhci_endpoint_t *xhci_ep, device_t *dev, const usb_endpoint_descriptors_t *desc) 59 61 { 60 62 int rc; … … 113 115 114 116 /** 117 * Create a new xHCI endpoint structure. 118 * 119 * Bus callback. 120 */ 121 endpoint_t *xhci_endpoint_create(device_t *dev, const usb_endpoint_descriptors_t *desc) 122 { 123 const usb_transfer_type_t type = USB_ED_GET_TRANSFER_TYPE(desc->endpoint); 124 125 xhci_endpoint_t *ep = calloc(1, sizeof(xhci_endpoint_t) 126 + (type == USB_TRANSFER_ISOCHRONOUS) * sizeof(*ep->isoch)); 127 if (!ep) 128 return NULL; 129 130 if (xhci_endpoint_init(ep, dev, desc)) { 131 free(ep); 132 return NULL; 133 } 134 135 return &ep->base; 136 } 137 138 /** 115 139 * Finalize XHCI endpoint. 116 140 * @param[in] xhci_ep XHCI endpoint to finalize. 117 141 */ 118 void xhci_endpoint_fini(xhci_endpoint_t *xhci_ep)142 static void xhci_endpoint_fini(xhci_endpoint_t *xhci_ep) 119 143 { 120 144 assert(xhci_ep); … … 123 147 124 148 // TODO: Something missed? 149 } 150 151 /** 152 * Destroy given xHCI endpoint structure. 153 * 154 * Bus callback. 155 */ 156 void xhci_endpoint_destroy(endpoint_t *ep) 157 { 158 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(ep); 159 160 xhci_endpoint_fini(xhci_ep); 161 free(xhci_ep); 162 } 163 164 165 /** 166 * Register an andpoint to the xHC. 167 * 168 * Bus callback. 169 */ 170 int xhci_endpoint_register(endpoint_t *ep_base) 171 { 172 int err; 173 xhci_endpoint_t *ep = xhci_endpoint_get(ep_base); 174 xhci_device_t *dev = xhci_device_get(ep_base->device); 175 176 xhci_ep_ctx_t ep_ctx; 177 xhci_setup_endpoint_context(ep, &ep_ctx); 178 179 if ((err = hc_add_endpoint(dev, xhci_endpoint_index(ep), &ep_ctx))) 180 return err; 181 182 return EOK; 183 } 184 185 /** 186 * Abort a transfer on an endpoint. 187 */ 188 static int endpoint_abort(endpoint_t *ep) 189 { 190 xhci_device_t *dev = xhci_device_get(ep->device); 191 192 usb_transfer_batch_t *batch = NULL; 193 fibril_mutex_lock(&ep->guard); 194 if (ep->active_batch) { 195 if (dev->slot_id) { 196 const int err = hc_stop_endpoint(dev, xhci_endpoint_dci(xhci_endpoint_get(ep))); 197 if (err) { 198 usb_log_warning("Failed to stop endpoint %u of device " XHCI_DEV_FMT ": %s", 199 ep->endpoint, XHCI_DEV_ARGS(*dev), str_error(err)); 200 } 201 202 endpoint_wait_timeout_locked(ep, 2000); 203 } 204 205 batch = ep->active_batch; 206 if (batch) { 207 endpoint_deactivate_locked(ep); 208 } 209 } 210 fibril_mutex_unlock(&ep->guard); 211 212 if (batch) { 213 batch->error = EINTR; 214 batch->transfered_size = 0; 215 usb_transfer_batch_finish(batch); 216 } 217 return EOK; 218 } 219 220 /** 221 * Unregister an endpoint. If the device is still available, inform the xHC 222 * about it. 223 * 224 * Bus callback. 225 */ 226 void xhci_endpoint_unregister(endpoint_t *ep_base) 227 { 228 int err; 229 xhci_endpoint_t *ep = xhci_endpoint_get(ep_base); 230 xhci_device_t *dev = xhci_device_get(ep_base->device); 231 232 endpoint_abort(ep_base); 233 234 /* If device slot is still available, drop the endpoint. */ 235 if (dev->slot_id) { 236 237 if ((err = hc_drop_endpoint(dev, xhci_endpoint_index(ep)))) { 238 usb_log_error("Failed to drop endpoint " XHCI_EP_FMT ": %s", XHCI_EP_ARGS(*ep), str_error(err)); 239 } 240 } else { 241 usb_log_debug("Not going to drop endpoint " XHCI_EP_FMT " because" 242 " the slot has already been disabled.", XHCI_EP_ARGS(*ep)); 243 } 125 244 } 126 245 -
uspace/drv/bus/usb/xhci/endpoint.h
r129b821f r682c9354 45 45 #include <ddf/driver.h> 46 46 47 #include "device.h" 47 48 #include "isoch.h" 48 49 #include "transfers.h" … … 105 106 (usb_str_transfer_type((ep).base.transfer_type)) 106 107 107 typedef struct xhci_device {108 device_t base; /**< Inheritance. Keep this first. */109 110 /** Slot ID assigned to the device by xHC. */111 uint32_t slot_id;112 113 /** Corresponding port on RH */114 uint8_t rh_port;115 116 /** USB Tier of the device */117 uint8_t tier;118 119 /** Route string */120 uint32_t route_str;121 122 /** Place to store the allocated context */123 dma_buffer_t dev_ctx;124 125 /** Hub specific information. Valid only if the device is_hub. */126 bool is_hub;127 uint8_t num_ports;128 uint8_t tt_think_time;129 } xhci_device_t;130 131 #define XHCI_DEV_FMT "(%s, slot %d)"132 #define XHCI_DEV_ARGS(dev) ddf_fun_get_name((dev).base.fun), (dev).slot_id133 134 108 int xhci_endpoint_type(xhci_endpoint_t *ep); 135 109 136 int xhci_endpoint_init(xhci_endpoint_t *, device_t *, const usb_endpoint_descriptors_t *); 137 void xhci_endpoint_fini(xhci_endpoint_t *); 110 endpoint_t *xhci_endpoint_create(device_t *, const usb_endpoint_descriptors_t *); 111 int xhci_endpoint_register(endpoint_t *); 112 void xhci_endpoint_unregister(endpoint_t *); 113 void xhci_endpoint_destroy(endpoint_t *); 138 114 139 115 void xhci_endpoint_free_transfer_ds(xhci_endpoint_t *xhci_ep); … … 144 120 void xhci_setup_endpoint_context(xhci_endpoint_t *, xhci_ep_ctx_t *); 145 121 int xhci_endpoint_clear_halt(xhci_endpoint_t *, unsigned); 146 147 static inline xhci_device_t * xhci_device_get(device_t *dev)148 {149 assert(dev);150 return (xhci_device_t *) dev;151 }152 122 153 123 static inline xhci_endpoint_t * xhci_endpoint_get(endpoint_t *ep) -
uspace/drv/bus/usb/xhci/transfers.c
r129b821f r682c9354 416 416 }; 417 417 418 int xhci_transfer_schedule(xhci_hc_t *hc, usb_transfer_batch_t *batch) 419 { 420 assert(hc); 418 /** 419 * Schedule a batch for xHC. 420 * 421 * Bus callback. 422 */ 423 int xhci_transfer_schedule(usb_transfer_batch_t *batch) 424 { 421 425 endpoint_t *ep = batch->ep; 422 426 427 xhci_hc_t *hc = bus_to_hc(endpoint_get_bus(batch->ep)); 423 428 xhci_transfer_t *transfer = xhci_transfer_from_batch(batch); 424 429 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(ep); 425 430 xhci_device_t *xhci_dev = xhci_ep_to_dev(xhci_ep); 431 432 if (!batch->target.address) { 433 usb_log_error("Attempted to schedule transfer to address 0."); 434 return EINVAL; 435 } 426 436 427 437 // FIXME: find a better way to check if the ring is not initialized -
uspace/drv/bus/usb/xhci/transfers.h
r129b821f r682c9354 56 56 57 57 usb_transfer_batch_t* xhci_transfer_create(endpoint_t *); 58 int xhci_transfer_schedule(xhci_hc_t *, usb_transfer_batch_t *); 58 int xhci_transfer_schedule(usb_transfer_batch_t *); 59 59 60 int xhci_handle_transfer_event(xhci_hc_t *, xhci_trb_t *); 60 61 void xhci_transfer_destroy(usb_transfer_batch_t *);
Note:
See TracChangeset
for help on using the changeset viewer.