Changeset df6ded8 in mainline for uspace/lib/usbhost/src
- Timestamp:
- 2018-02-28T16:37:50Z (8 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 1b20da0
- Parents:
- f5e5f73 (diff), b2dca8de (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - git-author:
- Jakub Jermar <jakub@…> (2018-02-28 16:06:42)
- git-committer:
- Jakub Jermar <jakub@…> (2018-02-28 16:37:50)
- Location:
- uspace/lib/usbhost/src
- Files:
-
- 4 added
- 1 deleted
- 4 edited
-
bandwidth.c (added)
-
bus.c (added)
-
ddf_helpers.c (modified) (16 diffs)
-
endpoint.c (modified) (2 diffs)
-
hcd.c (modified) (2 diffs)
-
usb2_bus.c (added)
-
usb_bus.c (deleted)
-
usb_transfer_batch.c (modified) (2 diffs)
-
utility.c (added)
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbhost/src/ddf_helpers.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2013 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty, Michal Staruch, Petr Manek 3 4 * All rights reserved. 4 5 * … … 31 32 */ 32 33 /** @file 33 * 34 */ 35 36 #include <usb/classes/classes.h> 37 #include <usb/debug.h> 38 #include <usb/descriptor.h> 39 #include <usb/request.h> 40 #include <usb/usb.h> 34 * Helpers to work with the DDF interface. 35 */ 41 36 42 37 #include <adt/list.h> … … 47 42 #include <device/hw_res_parsed.h> 48 43 #include <errno.h> 49 #include <fibril_synch.h>50 #include <macros.h>51 #include <stdio.h>52 #include <stdlib.h>53 44 #include <str_error.h> 45 #include <usb/classes/classes.h> 46 #include <usb/debug.h> 47 #include <usb/descriptor.h> 48 #include <usb/usb.h> 49 #include <usb/dma_buffer.h> 54 50 #include <usb_iface.h> 51 #include <usbhc_iface.h> 52 53 #include "bus.h" 54 #include "endpoint.h" 55 55 56 56 #include "ddf_helpers.h" 57 57 58 #define CTRL_PIPE_MIN_PACKET_SIZE 8 59 60 typedef struct usb_dev { 61 link_t link; 62 list_t devices; 63 fibril_mutex_t guard; 64 ddf_fun_t *fun; 65 usb_address_t address; 66 usb_speed_t speed; 67 usb_address_t tt_address; 68 unsigned port; 69 } usb_dev_t; 70 71 typedef struct hc_dev { 72 ddf_fun_t *ctl_fun; 73 hcd_t hcd; 74 usb_dev_t *root_hub; 75 } hc_dev_t; 76 77 static hc_dev_t *dev_to_hc_dev(ddf_dev_t *dev) 78 { 79 return ddf_dev_data_get(dev); 80 } 81 82 hcd_t *dev_to_hcd(ddf_dev_t *dev) 83 { 84 hc_dev_t *hc_dev = dev_to_hc_dev(dev); 85 if (!hc_dev) { 86 usb_log_error("Invalid HCD device.\n"); 87 return NULL; 88 } 89 return &hc_dev->hcd; 90 } 91 92 93 static errno_t hcd_ddf_new_device(ddf_dev_t *device, usb_dev_t *hub, unsigned port); 94 static errno_t hcd_ddf_remove_device(ddf_dev_t *device, usb_dev_t *hub, unsigned port); 95 96 97 /* DDF INTERFACE */ 98 99 /** Register endpoint interface function. 100 * @param fun DDF function. 101 * @param address USB address of the device. 102 * @param endpoint USB endpoint number to be registered. 103 * @param transfer_type Endpoint's transfer type. 104 * @param direction USB communication direction the endpoint is capable of. 105 * @param max_packet_size Maximu size of packets the endpoint accepts. 106 * @param interval Preferred timeout between communication. 58 /** 59 * DDF usbhc_iface callback. Passes the endpoint descriptors, fills the pipe 60 * descriptor according to the contents of the endpoint. 61 * 62 * @param[in] fun DDF function of the device in question. 63 * @param[out] pipe_desc The pipe descriptor to be filled. 64 * @param[in] endpoint_desc Endpoint descriptors from the device. 107 65 * @return Error code. 108 66 */ 109 static errno_t register_endpoint( 110 ddf_fun_t *fun, usb_endpoint_t endpoint, 111 usb_transfer_type_t transfer_type, usb_direction_t direction, 112 size_t max_packet_size, unsigned packets, unsigned interval) 113 { 114 assert(fun); 115 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 116 usb_dev_t *dev = ddf_fun_data_get(fun); 67 static errno_t register_endpoint(ddf_fun_t *fun, usb_pipe_desc_t *pipe_desc, 68 const usb_endpoint_descriptors_t *ep_desc) 69 { 70 assert(fun); 71 hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 72 device_t *dev = ddf_fun_data_get(fun); 117 73 assert(hcd); 74 assert(hcd->bus); 118 75 assert(dev); 119 const size_t size = max_packet_size; 120 const usb_target_t target = 121 {{.address = dev->address, .endpoint = endpoint}}; 122 123 usb_log_debug("Register endpoint %d:%d %s-%s %zuB %ums.\n", 124 dev->address, endpoint, usb_str_transfer_type(transfer_type), 125 usb_str_direction(direction), max_packet_size, interval); 126 127 return hcd_add_ep(hcd, target, direction, transfer_type, 128 max_packet_size, packets, size, dev->tt_address, dev->port); 129 } 130 131 /** Unregister endpoint interface function. 132 * @param fun DDF function. 133 * @param address USB address of the endpoint. 134 * @param endpoint USB endpoint number. 135 * @param direction Communication direction of the enpdoint to unregister. 76 77 endpoint_t *ep; 78 const int err = bus_endpoint_add(dev, ep_desc, &ep); 79 if (err) 80 return err; 81 82 if (pipe_desc) { 83 pipe_desc->endpoint_no = ep->endpoint; 84 pipe_desc->direction = ep->direction; 85 pipe_desc->transfer_type = ep->transfer_type; 86 pipe_desc->max_transfer_size = ep->max_transfer_size; 87 pipe_desc->transfer_buffer_policy = ep->transfer_buffer_policy; 88 } 89 endpoint_del_ref(ep); 90 91 return EOK; 92 } 93 94 /** 95 * DDF usbhc_iface callback. Unregister endpoint that makes the other end of 96 * the pipe described. 97 * 98 * @param fun DDF function of the device in question. 99 * @param pipe_desc Pipe description. 100 * @return Error code. 101 */ 102 static errno_t unregister_endpoint(ddf_fun_t *fun, const usb_pipe_desc_t *pipe_desc) 103 { 104 assert(fun); 105 hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 106 device_t *dev = ddf_fun_data_get(fun); 107 assert(hcd); 108 assert(hcd->bus); 109 assert(dev); 110 111 endpoint_t *ep = bus_find_endpoint(dev, pipe_desc->endpoint_no, pipe_desc->direction); 112 if (!ep) 113 return ENOENT; 114 115 const errno_t err = bus_endpoint_remove(ep); 116 117 endpoint_del_ref(ep); 118 return err; 119 } 120 121 /** 122 * DDF usbhc_iface callback. Calls the respective bus operation directly. 123 * 124 * @param fun DDF function of the device (hub) requesting the address. 125 */ 126 static errno_t default_address_reservation(ddf_fun_t *fun, bool reserve) 127 { 128 assert(fun); 129 hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 130 device_t *dev = ddf_fun_data_get(fun); 131 assert(hcd); 132 assert(hcd->bus); 133 assert(dev); 134 135 usb_log_debug("Device %d %s default address", dev->address, reserve ? "requested" : "releasing"); 136 if (reserve) { 137 return bus_reserve_default_address(hcd->bus, dev); 138 } else { 139 bus_release_default_address(hcd->bus, dev); 140 return EOK; 141 } 142 } 143 144 /** 145 * DDF usbhc_iface callback. Calls the bus operation directly. 146 * 147 * @param fun DDF function of the device (hub) requesting the address. 148 * @param speed USB speed of the new device 149 */ 150 static errno_t device_enumerate(ddf_fun_t *fun, unsigned port, usb_speed_t speed) 151 { 152 assert(fun); 153 ddf_dev_t *hc = ddf_fun_get_dev(fun); 154 assert(hc); 155 hc_device_t *hcd = dev_to_hcd(hc); 156 assert(hcd); 157 device_t *hub = ddf_fun_data_get(fun); 158 assert(hub); 159 160 errno_t err; 161 162 if (!usb_speed_is_valid(speed)) 163 return EINVAL; 164 165 usb_log_debug("Hub %d reported a new %s speed device on port: %u", 166 hub->address, usb_str_speed(speed), port); 167 168 device_t *dev = hcd_ddf_fun_create(hcd, speed); 169 if (!dev) { 170 usb_log_error("Failed to create USB device function."); 171 return ENOMEM; 172 } 173 174 dev->hub = hub; 175 dev->tier = hub->tier + 1; 176 dev->port = port; 177 dev->speed = speed; 178 179 if ((err = bus_device_enumerate(dev))) { 180 usb_log_error("Failed to initialize USB dev memory structures."); 181 goto err_usb_dev; 182 } 183 184 /* If the driver didn't name the dev when enumerating, 185 * do it in some generic way. 186 */ 187 if (!ddf_fun_get_name(dev->fun)) { 188 bus_device_set_default_name(dev); 189 } 190 191 if ((err = ddf_fun_bind(dev->fun))) { 192 usb_log_error("Device(%d): Failed to register: %s.", dev->address, str_error(err)); 193 goto err_usb_dev; 194 } 195 196 return EOK; 197 198 err_usb_dev: 199 hcd_ddf_fun_destroy(dev); 200 return err; 201 } 202 203 static errno_t device_remove(ddf_fun_t *fun, unsigned port) 204 { 205 assert(fun); 206 device_t *hub = ddf_fun_data_get(fun); 207 assert(hub); 208 usb_log_debug("Hub `%s' reported removal of device on port %u", 209 ddf_fun_get_name(fun), port); 210 211 device_t *victim = NULL; 212 213 fibril_mutex_lock(&hub->guard); 214 list_foreach(hub->devices, link, device_t, it) { 215 if (it->port == port) { 216 victim = it; 217 break; 218 } 219 } 220 fibril_mutex_unlock(&hub->guard); 221 222 if (!victim) { 223 usb_log_warning("Hub '%s' tried to remove non-existent" 224 " device.", ddf_fun_get_name(fun)); 225 return ENOENT; 226 } 227 228 assert(victim->fun); 229 assert(victim->port == port); 230 assert(victim->hub == hub); 231 232 bus_device_gone(victim); 233 return EOK; 234 } 235 236 /** 237 * Gets description of the device that is calling. 238 * 239 * @param[in] fun Device function. 240 * @param[out] desc Device descriptor to be filled. 136 241 * @return Error code. 137 242 */ 138 static errno_t unregister_endpoint( 139 ddf_fun_t *fun, usb_endpoint_t endpoint, usb_direction_t direction) 140 { 141 assert(fun); 142 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 143 usb_dev_t *dev = ddf_fun_data_get(fun); 144 assert(hcd); 243 static errno_t get_device_description(ddf_fun_t *fun, usb_device_desc_t *desc) 244 { 245 assert(fun); 246 device_t *dev = ddf_fun_data_get(fun); 145 247 assert(dev); 146 const usb_target_t target = 147 {{.address = dev->address, .endpoint = endpoint}}; 148 usb_log_debug("Unregister endpoint %d:%d %s.\n", 149 dev->address, endpoint, usb_str_direction(direction)); 150 return hcd_remove_ep(hcd, target, direction); 151 } 152 153 static errno_t reserve_default_address(ddf_fun_t *fun, usb_speed_t speed) 154 { 155 assert(fun); 156 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 157 usb_dev_t *dev = ddf_fun_data_get(fun); 158 assert(hcd); 159 assert(dev); 160 161 usb_log_debug("Device %d requested default address at %s speed\n", 162 dev->address, usb_str_speed(speed)); 163 return hcd_reserve_default_address(hcd, speed); 164 } 165 166 static errno_t release_default_address(ddf_fun_t *fun) 167 { 168 assert(fun); 169 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 170 usb_dev_t *dev = ddf_fun_data_get(fun); 171 assert(hcd); 172 assert(dev); 173 174 usb_log_debug("Device %d released default address\n", dev->address); 175 return hcd_release_default_address(hcd); 176 } 177 178 static errno_t device_enumerate(ddf_fun_t *fun, unsigned port) 179 { 180 assert(fun); 181 ddf_dev_t *ddf_dev = ddf_fun_get_dev(fun); 182 usb_dev_t *dev = ddf_fun_data_get(fun); 183 assert(ddf_dev); 184 assert(dev); 185 usb_log_debug("Hub %d reported a new USB device on port: %u\n", 186 dev->address, port); 187 return hcd_ddf_new_device(ddf_dev, dev, port); 188 } 189 190 static errno_t device_remove(ddf_fun_t *fun, unsigned port) 191 { 192 assert(fun); 193 ddf_dev_t *ddf_dev = ddf_fun_get_dev(fun); 194 usb_dev_t *dev = ddf_fun_data_get(fun); 195 assert(ddf_dev); 196 assert(dev); 197 usb_log_debug("Hub `%s' reported removal of device on port %u\n", 198 ddf_fun_get_name(fun), port); 199 return hcd_ddf_remove_device(ddf_dev, dev, port); 200 } 201 202 /** Gets handle of the respective device. 203 * 204 * @param[in] fun Device function. 205 * @param[out] handle Place to write the handle. 206 * @return Error code. 207 */ 208 static errno_t get_my_device_handle(ddf_fun_t *fun, devman_handle_t *handle) 209 { 210 assert(fun); 211 if (handle) 212 *handle = ddf_fun_get_handle(fun); 213 return EOK; 214 } 215 216 /** Inbound communication interface function. 248 249 if (!desc) 250 return EOK; 251 252 *desc = (usb_device_desc_t) { 253 .address = dev->address, 254 .depth = dev->tier, 255 .speed = dev->speed, 256 .handle = ddf_fun_get_handle(fun), 257 .iface = -1, 258 }; 259 return EOK; 260 } 261 262 /** 263 * Transfer issuing interface function. 264 * 217 265 * @param fun DDF function. 218 266 * @param target Communication target. 267 * @param dir Communication direction. 219 268 * @param setup_data Data to use in setup stage (control transfers). 220 269 * @param data Pointer to data buffer. … … 224 273 * @return Error code. 225 274 */ 226 static errno_t dev_read(ddf_fun_t *fun, usb_endpoint_t endpoint, 227 uint64_t setup_data, uint8_t *data, size_t size, 228 usbhc_iface_transfer_in_callback_t callback, void *arg) 229 { 230 assert(fun); 231 usb_dev_t *usb_dev = ddf_fun_data_get(fun); 232 assert(usb_dev); 275 static errno_t transfer(ddf_fun_t *fun, 276 const usbhc_iface_transfer_request_t *ifreq, 277 usbhc_iface_transfer_callback_t callback, void *arg) 278 { 279 assert(fun); 280 device_t *dev = ddf_fun_data_get(fun); 281 assert(dev); 282 233 283 const usb_target_t target = {{ 234 .address = usb_dev->address, 235 .endpoint = endpoint, 284 .address = dev->address, 285 .endpoint = ifreq->endpoint, 286 .stream = ifreq->stream, 236 287 }}; 237 return hcd_send_batch(dev_to_hcd(ddf_fun_get_dev(fun)), target, 238 USB_DIRECTION_IN, data, size, setup_data, callback, NULL, arg, 239 "READ"); 240 } 241 242 /** Outbound communication interface function. 243 * @param fun DDF function. 244 * @param target Communication target. 245 * @param setup_data Data to use in setup stage (control transfers). 246 * @param data Pointer to data buffer. 247 * @param size Size of the data buffer. 248 * @param callback Function to call on communication end. 249 * @param arg Argument passed to the callback function. 250 * @return Error code. 251 */ 252 static errno_t dev_write(ddf_fun_t *fun, usb_endpoint_t endpoint, 253 uint64_t setup_data, const uint8_t *data, size_t size, 254 usbhc_iface_transfer_out_callback_t callback, void *arg) 255 { 256 assert(fun); 257 usb_dev_t *usb_dev = ddf_fun_data_get(fun); 258 assert(usb_dev); 259 const usb_target_t target = {{ 260 .address = usb_dev->address, 261 .endpoint = endpoint, 262 }}; 263 return hcd_send_batch(dev_to_hcd(ddf_fun_get_dev(fun)), 264 target, USB_DIRECTION_OUT, (uint8_t*)data, size, setup_data, NULL, 265 callback, arg, "WRITE"); 288 289 if (!usb_target_is_valid(&target)) 290 return EINVAL; 291 292 if (ifreq->offset > 0 && ifreq->size == 0) 293 return EINVAL; 294 295 if (ifreq->size > 0 && !dma_buffer_is_set(&ifreq->buffer)) 296 return EBADMEM; 297 298 if (!callback && arg) 299 return EBADMEM; 300 301 const transfer_request_t request = { 302 .target = target, 303 .dir = ifreq->dir, 304 .buffer = ifreq->buffer, 305 .offset = ifreq->offset, 306 .size = ifreq->size, 307 .setup = ifreq->setup, 308 .on_complete = callback, 309 .arg = arg, 310 .name = (ifreq->dir == USB_DIRECTION_IN) ? "READ" : "WRITE", 311 }; 312 313 return bus_issue_transfer(dev, &request); 266 314 } 267 315 268 316 /** USB device interface */ 269 317 static usb_iface_t usb_iface = { 270 .get_my_device_handle = get_my_device_handle, 271 272 .reserve_default_address = reserve_default_address, 273 .release_default_address = release_default_address, 318 .get_my_description = get_device_description, 319 }; 320 321 /** USB host controller interface */ 322 static usbhc_iface_t usbhc_iface = { 323 .default_address_reservation = default_address_reservation, 274 324 275 325 .device_enumerate = device_enumerate, … … 279 329 .unregister_endpoint = unregister_endpoint, 280 330 281 .read = dev_read, 282 .write = dev_write, 331 .transfer = transfer, 283 332 }; 284 333 … … 286 335 static ddf_dev_ops_t usb_ops = { 287 336 .interfaces[USB_DEV_IFACE] = &usb_iface, 337 .interfaces[USBHC_DEV_IFACE] = &usbhc_iface, 288 338 }; 289 339 290 340 291 341 /* DDF HELPERS */ 292 293 #define GET_DEVICE_DESC(size) \294 { \295 .request_type = SETUP_REQUEST_TYPE_DEVICE_TO_HOST \296 | (USB_REQUEST_TYPE_STANDARD << 5) \297 | USB_REQUEST_RECIPIENT_DEVICE, \298 .request = USB_DEVREQ_GET_DESCRIPTOR, \299 .value = uint16_host2usb(USB_DESCTYPE_DEVICE << 8), \300 .index = uint16_host2usb(0), \301 .length = uint16_host2usb(size), \302 };303 304 #define SET_ADDRESS(address) \305 { \306 .request_type = SETUP_REQUEST_TYPE_HOST_TO_DEVICE \307 | (USB_REQUEST_TYPE_STANDARD << 5) \308 | USB_REQUEST_RECIPIENT_DEVICE, \309 .request = USB_DEVREQ_SET_ADDRESS, \310 .value = uint16_host2usb(address), \311 .index = uint16_host2usb(0), \312 .length = uint16_host2usb(0), \313 };314 315 static errno_t hcd_ddf_add_device(ddf_dev_t *parent, usb_dev_t *hub_dev,316 unsigned port, usb_address_t address, usb_speed_t speed, const char *name,317 const match_id_list_t *mids)318 {319 assert(parent);320 321 char default_name[10] = { 0 }; /* usbxyz-ss */322 if (!name) {323 snprintf(default_name, sizeof(default_name) - 1,324 "usb%u-%cs", address, usb_str_speed(speed)[0]);325 name = default_name;326 }327 328 ddf_fun_t *fun = ddf_fun_create(parent, fun_inner, name);329 if (!fun)330 return ENOMEM;331 usb_dev_t *info = ddf_fun_data_alloc(fun, sizeof(usb_dev_t));332 if (!info) {333 ddf_fun_destroy(fun);334 return ENOMEM;335 }336 info->address = address;337 info->speed = speed;338 info->fun = fun;339 info->port = port;340 info->tt_address = hub_dev ? hub_dev->tt_address : -1;341 link_initialize(&info->link);342 list_initialize(&info->devices);343 fibril_mutex_initialize(&info->guard);344 345 if (hub_dev && hub_dev->speed == USB_SPEED_HIGH && usb_speed_is_11(speed))346 info->tt_address = hub_dev->address;347 348 ddf_fun_set_ops(fun, &usb_ops);349 list_foreach(mids->ids, link, const match_id_t, mid) {350 ddf_fun_add_match_id(fun, mid->id, mid->score);351 }352 353 errno_t ret = ddf_fun_bind(fun);354 if (ret != EOK) {355 ddf_fun_destroy(fun);356 return ret;357 }358 359 if (hub_dev) {360 fibril_mutex_lock(&hub_dev->guard);361 list_append(&info->link, &hub_dev->devices);362 fibril_mutex_unlock(&hub_dev->guard);363 } else {364 hc_dev_t *hc_dev = dev_to_hc_dev(parent);365 assert(hc_dev->root_hub == NULL);366 hc_dev->root_hub = info;367 }368 return EOK;369 }370 342 371 343 #define ADD_MATCHID_OR_RETURN(list, sc, str, ...) \ … … 394 366 assert(l); 395 367 assert(d); 396 368 397 369 if (d->vendor_id != 0) { 398 370 /* First, with release number. */ … … 401 373 d->vendor_id, d->product_id, (d->device_version >> 8), 402 374 (d->device_version & 0xff)); 403 375 404 376 /* Next, without release number. */ 405 377 ADD_MATCHID_OR_RETURN(l, 90, "usb&vendor=%#04x&product=%#04x", … … 415 387 416 388 return EOK; 417 418 } 419 420 static errno_t hcd_ddf_remove_device(ddf_dev_t *device, usb_dev_t *hub, 421 unsigned port) 422 { 423 assert(device); 424 425 hcd_t *hcd = dev_to_hcd(device); 426 assert(hcd); 427 428 hc_dev_t *hc_dev = dev_to_hc_dev(device); 429 assert(hc_dev); 430 431 fibril_mutex_lock(&hub->guard); 432 433 usb_dev_t *victim = NULL; 434 435 list_foreach(hub->devices, link, usb_dev_t, it) { 436 if (it->port == port) { 437 victim = it; 438 break; 439 } 440 } 441 if (victim) { 442 assert(victim->port == port); 443 list_remove(&victim->link); 444 fibril_mutex_unlock(&hub->guard); 445 const errno_t ret = ddf_fun_unbind(victim->fun); 446 if (ret == EOK) { 447 usb_address_t address = victim->address; 448 ddf_fun_destroy(victim->fun); 449 hcd_release_address(hcd, address); 450 } else { 451 usb_log_warning("Failed to unbind device `%s': %s\n", 452 ddf_fun_get_name(victim->fun), str_error(ret)); 453 } 454 return EOK; 455 } 456 fibril_mutex_unlock(&hub->guard); 457 return ENOENT; 458 } 459 460 static errno_t hcd_ddf_new_device(ddf_dev_t *device, usb_dev_t *hub, unsigned port) 461 { 462 assert(device); 463 464 hcd_t *hcd = dev_to_hcd(device); 465 assert(hcd); 466 467 usb_speed_t speed = USB_SPEED_MAX; 468 469 /* This checks whether the default address is reserved and gets speed */ 470 errno_t ret = usb_bus_get_speed(&hcd->bus, USB_ADDRESS_DEFAULT, &speed); 471 if (ret != EOK) { 472 usb_log_error("Failed to verify speed: %s.", str_error(ret)); 473 return ret; 474 } 475 476 usb_log_debug("Found new %s speed USB device.", usb_str_speed(speed)); 477 478 static const usb_target_t default_target = {{ 479 .address = USB_ADDRESS_DEFAULT, 480 .endpoint = 0, 481 }}; 482 483 usb_address_t address; 484 ret = hcd_request_address(hcd, speed, &address); 485 if (ret != EOK) { 486 usb_log_error("Failed to reserve new address: %s.", 487 str_error(ret)); 488 return ret; 489 } 490 491 usb_log_debug("Reserved new address: %d\n", address); 492 493 const usb_target_t target = {{ 494 .address = address, 495 .endpoint = 0, 496 }}; 497 498 const usb_address_t tt_address = hub ? hub->tt_address : -1; 499 500 /* Add default pipe on default address */ 501 usb_log_debug("Device(%d): Adding default target(0:0)\n", address); 502 ret = hcd_add_ep(hcd, 503 default_target, USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL, 504 CTRL_PIPE_MIN_PACKET_SIZE, CTRL_PIPE_MIN_PACKET_SIZE, 1, 505 tt_address, port); 506 if (ret != EOK) { 507 usb_log_error("Device(%d): Failed to add default target: %s.", 508 address, str_error(ret)); 509 hcd_release_address(hcd, address); 510 return ret; 511 } 512 513 /* Get max packet size for default pipe */ 514 usb_standard_device_descriptor_t desc = { 0 }; 515 const usb_device_request_setup_packet_t get_device_desc_8 = 516 GET_DEVICE_DESC(CTRL_PIPE_MIN_PACKET_SIZE); 517 518 // TODO CALLBACKS 519 usb_log_debug("Device(%d): Requesting first 8B of device descriptor.", 520 address); 521 size_t got; 522 ret = hcd_send_batch_sync(hcd, default_target, USB_DIRECTION_IN, 523 &desc, CTRL_PIPE_MIN_PACKET_SIZE, *(uint64_t *)&get_device_desc_8, 524 "read first 8 bytes of dev descriptor", &got); 525 526 if (ret == EOK && got != CTRL_PIPE_MIN_PACKET_SIZE) { 527 ret = EOVERFLOW; 528 } 529 530 if (ret != EOK) { 531 usb_log_error("Device(%d): Failed to get 8B of dev descr: %s.", 532 address, str_error(ret)); 533 hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH); 534 hcd_release_address(hcd, address); 535 return ret; 536 } 537 538 /* Register EP on the new address */ 539 usb_log_debug("Device(%d): Registering control EP.", address); 540 ret = hcd_add_ep(hcd, target, USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL, 541 ED_MPS_PACKET_SIZE_GET(uint16_usb2host(desc.max_packet_size)), 542 ED_MPS_TRANS_OPPORTUNITIES_GET(uint16_usb2host(desc.max_packet_size)), 543 ED_MPS_PACKET_SIZE_GET(uint16_usb2host(desc.max_packet_size)), 544 tt_address, port); 545 if (ret != EOK) { 546 usb_log_error("Device(%d): Failed to register EP0: %s", 547 address, str_error(ret)); 548 hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH); 549 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH); 550 hcd_release_address(hcd, address); 551 return ret; 552 } 553 554 /* Set new address */ 555 const usb_device_request_setup_packet_t set_address = 556 SET_ADDRESS(target.address); 557 558 usb_log_debug("Device(%d): Setting USB address.", address); 559 ret = hcd_send_batch_sync(hcd, default_target, USB_DIRECTION_OUT, 560 NULL, 0, *(uint64_t *)&set_address, "set address", &got); 561 562 usb_log_debug("Device(%d): Removing default (0:0) EP.", address); 563 hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH); 564 565 if (ret != EOK) { 566 usb_log_error("Device(%d): Failed to set new address: %s.", 567 address, str_error(ret)); 568 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH); 569 hcd_release_address(hcd, address); 570 return ret; 571 } 572 573 /* Get std device descriptor */ 574 const usb_device_request_setup_packet_t get_device_desc = 575 GET_DEVICE_DESC(sizeof(desc)); 576 577 usb_log_debug("Device(%d): Requesting full device descriptor.", 578 address); 579 ret = hcd_send_batch_sync(hcd, target, USB_DIRECTION_IN, 580 &desc, sizeof(desc), *(uint64_t *)&get_device_desc, 581 "read device descriptor", &got); 582 if (ret != EOK) { 583 usb_log_error("Device(%d): Failed to set get dev descriptor: %s", 584 address, str_error(ret)); 585 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH); 586 hcd_release_address(hcd, target.address); 587 return ret; 588 } 389 } 390 391 device_t *hcd_ddf_fun_create(hc_device_t *hc, usb_speed_t speed) 392 { 393 /* Create DDF function for the new device */ 394 ddf_fun_t *fun = ddf_fun_create(hc->ddf_dev, fun_inner, NULL); 395 if (!fun) 396 return NULL; 397 398 ddf_fun_set_ops(fun, &usb_ops); 399 400 /* Create USB device node for the new device */ 401 device_t *dev = ddf_fun_data_alloc(fun, hc->bus->device_size); 402 if (!dev) { 403 ddf_fun_destroy(fun); 404 return NULL; 405 } 406 407 bus_device_init(dev, hc->bus); 408 dev->fun = fun; 409 dev->speed = speed; 410 return dev; 411 } 412 413 void hcd_ddf_fun_destroy(device_t *dev) 414 { 415 assert(dev); 416 assert(dev->fun); 417 ddf_fun_destroy(dev->fun); 418 } 419 420 errno_t hcd_ddf_setup_match_ids(device_t *device, usb_standard_device_descriptor_t *desc) 421 { 422 errno_t err; 423 match_id_list_t mids; 424 425 init_match_ids(&mids); 589 426 590 427 /* Create match ids from the device descriptor */ 591 match_id_list_t mids; 592 init_match_ids(&mids); 593 594 usb_log_debug("Device(%d): Creating match IDs.", address); 595 ret = create_match_ids(&mids, &desc); 596 if (ret != EOK) { 597 usb_log_error("Device(%d): Failed to create match ids: %s", 598 address, str_error(ret)); 599 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH); 600 hcd_release_address(hcd, target.address); 601 return ret; 602 } 603 604 /* Register device */ 605 usb_log_debug("Device(%d): Registering DDF device.", address); 606 ret = hcd_ddf_add_device(device, hub, port, address, speed, NULL, &mids); 607 clean_match_ids(&mids); 608 if (ret != EOK) { 609 usb_log_error("Device(%d): Failed to register: %s.", 610 address, str_error(ret)); 611 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH); 612 hcd_release_address(hcd, target.address); 613 } 614 615 return ret; 616 } 617 618 /** Announce root hub to the DDF 619 * 620 * @param[in] device Host controller ddf device 621 * @return Error code 622 */ 623 errno_t hcd_ddf_setup_root_hub(ddf_dev_t *device) 624 { 625 assert(device); 626 hcd_t *hcd = dev_to_hcd(device); 627 assert(hcd); 628 629 hcd_reserve_default_address(hcd, hcd->bus.max_speed); 630 const errno_t ret = hcd_ddf_new_device(device, NULL, 0); 631 hcd_release_default_address(hcd); 632 return ret; 428 usb_log_debug("Device(%d): Creating match IDs.", device->address); 429 if ((err = create_match_ids(&mids, desc))) { 430 return err; 431 } 432 433 list_foreach(mids.ids, link, const match_id_t, mid) { 434 ddf_fun_add_match_id(device->fun, mid->id, mid->score); 435 } 436 437 return EOK; 633 438 } 634 439 … … 643 448 * This function does all the ddf work for hc driver. 644 449 */ 645 errno_t hcd_ddf_setup_hc(ddf_dev_t *device, usb_speed_t max_speed, 646 size_t bw, bw_count_func_t bw_count) 450 errno_t hcd_ddf_setup_hc(ddf_dev_t *device, size_t size) 647 451 { 648 452 assert(device); 649 453 650 hc_dev _t *instance = ddf_dev_data_alloc(device, sizeof(hc_dev_t));454 hc_device_t *instance = ddf_dev_data_alloc(device, size); 651 455 if (instance == NULL) { 652 usb_log_error("Failed to allocate HCD ddf structure. \n");456 usb_log_error("Failed to allocate HCD ddf structure."); 653 457 return ENOMEM; 654 458 } 655 instance->root_hub = NULL; 656 hcd_init(&instance->hcd, max_speed, bw, bw_count); 459 instance->ddf_dev = device; 657 460 658 461 errno_t ret = ENOMEM; 659 462 instance->ctl_fun = ddf_fun_create(device, fun_exposed, "ctl"); 660 463 if (!instance->ctl_fun) { 661 usb_log_error("Failed to create HCD ddf fun. \n");464 usb_log_error("Failed to create HCD ddf fun."); 662 465 goto err_destroy_fun; 663 466 } … … 665 468 ret = ddf_fun_bind(instance->ctl_fun); 666 469 if (ret != EOK) { 667 usb_log_error("Failed to bind ctl_fun: %s. \n", str_error(ret));470 usb_log_error("Failed to bind ctl_fun: %s.", str_error(ret)); 668 471 goto err_destroy_fun; 669 472 } … … 671 474 ret = ddf_fun_add_to_category(instance->ctl_fun, USB_HC_CATEGORY); 672 475 if (ret != EOK) { 673 usb_log_error("Failed to add fun to category: %s. \n",476 usb_log_error("Failed to add fun to category: %s.", 674 477 str_error(ret)); 675 478 ddf_fun_unbind(instance->ctl_fun); … … 686 489 } 687 490 688 void hcd_ddf_clean_hc(ddf_dev_t *device) 689 { 690 assert(device); 691 hc_dev_t *hc = dev_to_hc_dev(device); 692 assert(hc); 693 const errno_t ret = ddf_fun_unbind(hc->ctl_fun); 694 if (ret == EOK) 695 ddf_fun_destroy(hc->ctl_fun); 696 } 697 698 //TODO: Cache parent session in HCD 491 void hcd_ddf_clean_hc(hc_device_t *hcd) 492 { 493 if (ddf_fun_unbind(hcd->ctl_fun) == EOK) 494 ddf_fun_destroy(hcd->ctl_fun); 495 } 496 699 497 /** Call the parent driver with a request to enable interrupt 700 498 * … … 703 501 * @return Error code. 704 502 */ 705 errno_t hcd_ddf_enable_interrupt( ddf_dev_t *device, int inum)706 { 707 async_sess_t *parent_sess = ddf_dev_parent_sess_get( device);503 errno_t hcd_ddf_enable_interrupt(hc_device_t *hcd, int inum) 504 { 505 async_sess_t *parent_sess = ddf_dev_parent_sess_get(hcd->ddf_dev); 708 506 if (parent_sess == NULL) 709 507 return EIO; … … 712 510 } 713 511 714 //TODO: Cache parent session in HCD 715 errno_t hcd_ddf_get_registers(ddf_dev_t *device, hw_res_list_parsed_t *hw_res) 716 { 717 async_sess_t *parent_sess = ddf_dev_parent_sess_get(device); 512 errno_t hcd_ddf_get_registers(hc_device_t *hcd, hw_res_list_parsed_t *hw_res) 513 { 514 async_sess_t *parent_sess = ddf_dev_parent_sess_get(hcd->ddf_dev); 718 515 if (parent_sess == NULL) 719 516 return EIO; … … 726 523 } 727 524 728 // TODO: move this someplace else729 static inline void irq_code_clean(irq_code_t *code)730 {731 if (code) {732 free(code->ranges);733 free(code->cmds);734 code->ranges = NULL;735 code->cmds = NULL;736 code->rangecount = 0;737 code->cmdcount = 0;738 }739 }740 741 /** Register interrupt handler742 *743 * @param[in] device Host controller DDF device744 * @param[in] regs Register range745 * @param[in] irq Interrupt number746 * @paran[in] handler Interrupt handler747 * @param[in] gen_irq_code IRQ code generator.748 *749 * @param[out] handle IRQ capability handle on success.750 *751 * @return Error code.752 */753 errno_t hcd_ddf_setup_interrupts(ddf_dev_t *device,754 const hw_res_list_parsed_t *hw_res,755 interrupt_handler_t handler,756 errno_t (*gen_irq_code)(irq_code_t *, const hw_res_list_parsed_t *, int *),757 cap_handle_t *handle)758 {759 760 assert(device);761 if (!handler || !gen_irq_code)762 return ENOTSUP;763 764 irq_code_t irq_code = {0};765 766 int irq;767 errno_t ret = gen_irq_code(&irq_code, hw_res, &irq);768 if (ret != EOK) {769 usb_log_error("Failed to generate IRQ code: %s.\n",770 str_error(ret));771 return ret;772 }773 774 /* Register handler to avoid interrupt lockup */775 ret = register_interrupt_handler(device, irq, handler,776 &irq_code, handle);777 irq_code_clean(&irq_code);778 if (ret != EOK) {779 usb_log_error("Failed to register interrupt handler: %s.\n",780 str_error(ret));781 return ret;782 }783 784 /* Enable interrupts */785 ret = hcd_ddf_enable_interrupt(device, irq);786 if (ret != EOK) {787 usb_log_error("Failed to register interrupt handler: %s.\n",788 str_error(ret));789 unregister_interrupt_handler(device, *handle);790 }791 return ret;792 }793 794 /** IRQ handling callback, forward status from call to diver structure.795 *796 * @param[in] dev DDF instance of the device to use.797 * @param[in] call Pointer to the call from kernel.798 */799 void ddf_hcd_gen_irq_handler(ipc_call_t *call, ddf_dev_t *dev)800 {801 assert(dev);802 hcd_t *hcd = dev_to_hcd(dev);803 if (!hcd || !hcd->ops.irq_hook) {804 usb_log_error("Interrupt on not yet initialized device.\n");805 return;806 }807 const uint32_t status = IPC_GET_ARG1(*call);808 hcd->ops.irq_hook(hcd, status);809 }810 811 static errno_t interrupt_polling(void *arg)812 {813 hcd_t *hcd = arg;814 assert(hcd);815 if (!hcd->ops.status_hook || !hcd->ops.irq_hook)816 return ENOTSUP;817 uint32_t status = 0;818 while (hcd->ops.status_hook(hcd, &status) == EOK) {819 hcd->ops.irq_hook(hcd, status);820 status = 0;821 /* We should wait 1 frame - 1ms here, but this polling is a822 * lame crutch anyway so don't hog the system. 10ms is still823 * good enough for emergency mode */824 async_usleep(10000);825 }826 return EOK;827 }828 829 /** Initialize hc and rh DDF structures and their respective drivers.830 *831 * @param device DDF instance of the device to use832 * @param speed Maximum supported speed833 * @param bw Available bandwidth (arbitrary units)834 * @param bw_count Bandwidth computing function835 * @param irq_handler IRQ handling function836 * @param gen_irq_code Function to generate IRQ pseudocode837 * (it needs to return used irq number)838 * @param driver_init Function to initialize HC driver839 * @param driver_fini Function to cleanup HC driver840 * @return Error code841 *842 * This function does all the preparatory work for hc and rh drivers:843 * - gets device's hw resources844 * - attempts to enable interrupts845 * - registers interrupt handler846 * - calls driver specific initialization847 * - registers root hub848 */849 errno_t hcd_ddf_add_hc(ddf_dev_t *device, const ddf_hc_driver_t *driver)850 {851 assert(driver);852 static const struct { size_t bw; bw_count_func_t bw_count; }bw[] = {853 [USB_SPEED_FULL] = { .bw = BANDWIDTH_AVAILABLE_USB11,854 .bw_count = bandwidth_count_usb11 },855 [USB_SPEED_HIGH] = { .bw = BANDWIDTH_AVAILABLE_USB11,856 .bw_count = bandwidth_count_usb11 },857 };858 859 errno_t ret = EOK;860 const usb_speed_t speed = driver->hc_speed;861 if (speed >= ARRAY_SIZE(bw) || bw[speed].bw == 0) {862 usb_log_error("Driver `%s' reported unsupported speed: %s",863 driver->name, usb_str_speed(speed));864 return ENOTSUP;865 }866 867 hw_res_list_parsed_t hw_res;868 ret = hcd_ddf_get_registers(device, &hw_res);869 if (ret != EOK) {870 usb_log_error("Failed to get register memory addresses "871 "for `%s': %s.\n", ddf_dev_get_name(device),872 str_error(ret));873 return ret;874 }875 876 ret = hcd_ddf_setup_hc(device, speed, bw[speed].bw, bw[speed].bw_count);877 if (ret != EOK) {878 usb_log_error("Failed to setup generic HCD.\n");879 hw_res_list_parsed_clean(&hw_res);880 return ret;881 }882 883 interrupt_handler_t *irq_handler =884 driver->irq_handler ? driver->irq_handler : ddf_hcd_gen_irq_handler;885 int irq_cap;886 errno_t irq_ret = hcd_ddf_setup_interrupts(device, &hw_res,887 irq_handler, driver->irq_code_gen, &irq_cap);888 bool irqs_enabled = (irq_ret == EOK);889 if (irqs_enabled) {890 usb_log_debug("Hw interrupts enabled.\n");891 }892 893 if (driver->claim) {894 ret = driver->claim(device);895 if (ret != EOK) {896 usb_log_error("Failed to claim `%s' for driver `%s'",897 ddf_dev_get_name(device), driver->name);898 return ret;899 }900 }901 902 903 /* Init hw driver */904 hcd_t *hcd = dev_to_hcd(device);905 ret = driver->init(hcd, &hw_res, irqs_enabled);906 hw_res_list_parsed_clean(&hw_res);907 if (ret != EOK) {908 usb_log_error("Failed to init HCD: %s.\n", str_error(ret));909 goto irq_unregister;910 }911 912 /* Need working irq replacement to setup root hub */913 if (!irqs_enabled && hcd->ops.status_hook) {914 hcd->polling_fibril = fibril_create(interrupt_polling, hcd);915 if (hcd->polling_fibril == 0) {916 usb_log_error("Failed to create polling fibril\n");917 ret = ENOMEM;918 goto irq_unregister;919 }920 fibril_add_ready(hcd->polling_fibril);921 usb_log_warning("Failed to enable interrupts: %s."922 " Falling back to polling.\n", str_error(irq_ret));923 }924 925 /*926 * Creating root hub registers a new USB device so HC927 * needs to be ready at this time.928 */929 ret = hcd_ddf_setup_root_hub(device);930 if (ret != EOK) {931 usb_log_error("Failed to setup HC root hub: %s.\n",932 str_error(ret));933 driver->fini(dev_to_hcd(device));934 irq_unregister:935 /* Unregistering non-existent should be ok */936 unregister_interrupt_handler(device, irq_cap);937 hcd_ddf_clean_hc(device);938 return ret;939 }940 941 usb_log_info("Controlling new `%s' device `%s'.\n",942 driver->name, ddf_dev_get_name(device));943 return EOK;944 }945 525 /** 946 526 * @} -
uspace/lib/usbhost/src/endpoint.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 34 35 */ 35 36 36 #include <usb/host/endpoint.h>37 38 37 #include <assert.h> 38 #include <atomic.h> 39 #include <mem.h> 39 40 #include <stdlib.h> 40 #include <atomic.h> 41 42 /** Allocate ad initialize endpoint_t structure. 43 * @param address USB address. 44 * @param endpoint USB endpoint number. 45 * @param direction Communication direction. 46 * @param type USB transfer type. 47 * @param speed Communication speed. 48 * @param max_packet_size Maximum size of data packets. 49 * @param bw Required bandwidth. 50 * @return Pointer to initialized endpoint_t structure, NULL on failure. 51 */ 52 endpoint_t * endpoint_create(usb_address_t address, usb_endpoint_t endpoint, 53 usb_direction_t direction, usb_transfer_type_t type, usb_speed_t speed, 54 size_t max_packet_size, unsigned packets, size_t bw, 55 usb_address_t tt_address, unsigned tt_p) 56 { 57 endpoint_t *instance = malloc(sizeof(endpoint_t)); 58 if (instance) { 59 atomic_set(&instance->refcnt, 0); 60 instance->address = address; 61 instance->endpoint = endpoint; 62 instance->direction = direction; 63 instance->transfer_type = type; 64 instance->speed = speed; 65 instance->max_packet_size = max_packet_size; 66 instance->packets = packets; 67 instance->bandwidth = bw; 68 instance->toggle = 0; 69 instance->active = false; 70 instance->tt.address = tt_address; 71 instance->tt.port = tt_p; 72 instance->hc_data.data = NULL; 73 instance->hc_data.toggle_get = NULL; 74 instance->hc_data.toggle_set = NULL; 75 link_initialize(&instance->link); 76 fibril_mutex_initialize(&instance->guard); 77 fibril_condvar_initialize(&instance->avail); 78 } 79 return instance; 80 } 81 82 /** Properly dispose of endpoint_t structure. 83 * @param instance endpoint_t structure. 84 */ 85 void endpoint_destroy(endpoint_t *instance) 86 { 87 assert(instance); 88 assert(!instance->active); 89 assert(instance->hc_data.data == NULL); 90 free(instance); 91 } 92 93 void endpoint_add_ref(endpoint_t *instance) 94 { 95 atomic_inc(&instance->refcnt); 96 } 97 98 void endpoint_del_ref(endpoint_t *instance) 99 { 100 if (atomic_predec(&instance->refcnt) == 0) 101 endpoint_destroy(instance); 102 } 103 104 /** Set device specific data and hooks. 105 * @param instance endpoint_t structure. 106 * @param data device specific data. 107 * @param toggle_get Hook to call when retrieving value of toggle bit. 108 * @param toggle_set Hook to call when setting the value of toggle bit. 109 */ 110 void endpoint_set_hc_data(endpoint_t *instance, 111 void *data, int (*toggle_get)(void *), void (*toggle_set)(void *, int)) 112 { 113 assert(instance); 114 fibril_mutex_lock(&instance->guard); 115 instance->hc_data.data = data; 116 instance->hc_data.toggle_get = toggle_get; 117 instance->hc_data.toggle_set = toggle_set; 118 fibril_mutex_unlock(&instance->guard); 119 } 120 121 /** Clear device specific data and hooks. 122 * @param instance endpoint_t structure. 123 * @note This function does not free memory pointed to by data pointer. 124 */ 125 void endpoint_clear_hc_data(endpoint_t *instance) 126 { 127 assert(instance); 128 endpoint_set_hc_data(instance, NULL, NULL, NULL); 129 } 130 131 /** Mark the endpoint as active and block access for further fibrils. 132 * @param instance endpoint_t structure. 133 */ 134 void endpoint_use(endpoint_t *instance) 135 { 136 assert(instance); 137 /* Add reference for active endpoint. */ 138 endpoint_add_ref(instance); 139 fibril_mutex_lock(&instance->guard); 140 while (instance->active) 141 fibril_condvar_wait(&instance->avail, &instance->guard); 142 instance->active = true; 143 fibril_mutex_unlock(&instance->guard); 144 } 145 146 /** Mark the endpoint as inactive and allow access for further fibrils. 147 * @param instance endpoint_t structure. 148 */ 149 void endpoint_release(endpoint_t *instance) 150 { 151 assert(instance); 152 fibril_mutex_lock(&instance->guard); 153 instance->active = false; 154 fibril_mutex_unlock(&instance->guard); 155 fibril_condvar_signal(&instance->avail); 156 /* Drop reference for active endpoint. */ 157 endpoint_del_ref(instance); 158 } 159 160 /** Get the value of toggle bit. 161 * @param instance endpoint_t structure. 162 * @note Will use provided hook. 163 */ 164 int endpoint_toggle_get(endpoint_t *instance) 165 { 166 assert(instance); 167 fibril_mutex_lock(&instance->guard); 168 if (instance->hc_data.toggle_get) 169 instance->toggle = 170 instance->hc_data.toggle_get(instance->hc_data.data); 171 const int ret = instance->toggle; 172 fibril_mutex_unlock(&instance->guard); 41 #include <str_error.h> 42 #include <usb/debug.h> 43 #include <usb/descriptor.h> 44 #include <usb/host/hcd.h> 45 #include <usb/host/utility.h> 46 47 #include "usb_transfer_batch.h" 48 #include "bus.h" 49 50 #include "endpoint.h" 51 52 /** 53 * Initialize provided endpoint structure. 54 */ 55 void endpoint_init(endpoint_t *ep, device_t *dev, const usb_endpoint_descriptors_t *desc) 56 { 57 memset(ep, 0, sizeof(endpoint_t)); 58 59 assert(dev); 60 ep->device = dev; 61 62 atomic_set(&ep->refcnt, 0); 63 fibril_condvar_initialize(&ep->avail); 64 65 ep->endpoint = USB_ED_GET_EP(desc->endpoint); 66 ep->direction = USB_ED_GET_DIR(desc->endpoint); 67 ep->transfer_type = USB_ED_GET_TRANSFER_TYPE(desc->endpoint); 68 ep->max_packet_size = USB_ED_GET_MPS(desc->endpoint); 69 ep->packets_per_uframe = USB_ED_GET_ADD_OPPS(desc->endpoint) + 1; 70 71 /** Direction both is our construct never present in descriptors */ 72 if (ep->transfer_type == USB_TRANSFER_CONTROL) 73 ep->direction = USB_DIRECTION_BOTH; 74 75 ep->max_transfer_size = ep->max_packet_size * ep->packets_per_uframe; 76 ep->transfer_buffer_policy = DMA_POLICY_STRICT; 77 ep->required_transfer_buffer_policy = DMA_POLICY_STRICT; 78 } 79 80 /** 81 * Get the bus endpoint belongs to. 82 */ 83 static inline const bus_ops_t *get_bus_ops(endpoint_t *ep) 84 { 85 return ep->device->bus->ops; 86 } 87 88 /** 89 * Increase the reference count on endpoint. 90 */ 91 void endpoint_add_ref(endpoint_t *ep) 92 { 93 atomic_inc(&ep->refcnt); 94 } 95 96 /** 97 * Call the desctruction callback. Default behavior is to free the memory directly. 98 */ 99 static inline void endpoint_destroy(endpoint_t *ep) 100 { 101 const bus_ops_t *ops = get_bus_ops(ep); 102 if (ops->endpoint_destroy) { 103 ops->endpoint_destroy(ep); 104 } else { 105 assert(ep->active_batch == NULL); 106 107 /* Assume mostly the eps will be allocated by malloc. */ 108 free(ep); 109 } 110 } 111 112 /** 113 * Decrease the reference count. 114 */ 115 void endpoint_del_ref(endpoint_t *ep) 116 { 117 if (atomic_predec(&ep->refcnt) == 0) { 118 endpoint_destroy(ep); 119 } 120 } 121 122 /** 123 * Mark the endpoint as online. Supply a guard to be used for this endpoint 124 * synchronization. 125 */ 126 void endpoint_set_online(endpoint_t *ep, fibril_mutex_t *guard) 127 { 128 ep->guard = guard; 129 ep->online = true; 130 } 131 132 /** 133 * Mark the endpoint as offline. All other fibrils waiting to activate this 134 * endpoint will be interrupted. 135 */ 136 void endpoint_set_offline_locked(endpoint_t *ep) 137 { 138 assert(ep); 139 assert(fibril_mutex_is_locked(ep->guard)); 140 141 ep->online = false; 142 fibril_condvar_broadcast(&ep->avail); 143 } 144 145 /** 146 * Wait until a transfer finishes. Can be used even when the endpoint is 147 * offline (and is interrupted by the endpoint going offline). 148 */ 149 void endpoint_wait_timeout_locked(endpoint_t *ep, suseconds_t timeout) 150 { 151 assert(ep); 152 assert(fibril_mutex_is_locked(ep->guard)); 153 154 if (ep->active_batch == NULL) 155 return; 156 157 fibril_condvar_wait_timeout(&ep->avail, ep->guard, timeout); 158 } 159 160 /** 161 * Mark the endpoint as active and block access for further fibrils. If the 162 * endpoint is already active, it will block on ep->avail condvar. 163 * 164 * Call only under endpoint guard. After you activate the endpoint and release 165 * the guard, you must assume that particular transfer is already 166 * finished/aborted. 167 * 168 * Activation and deactivation is not done by the library to maximize 169 * performance. The HC might want to prepare some memory buffers prior to 170 * interfering with other world. 171 * 172 * @param batch Transfer batch this endpoint is blocked by. 173 */ 174 int endpoint_activate_locked(endpoint_t *ep, usb_transfer_batch_t *batch) 175 { 176 assert(ep); 177 assert(batch); 178 assert(batch->ep == ep); 179 assert(ep->guard); 180 assert(fibril_mutex_is_locked(ep->guard)); 181 182 while (ep->online && ep->active_batch != NULL) 183 fibril_condvar_wait(&ep->avail, ep->guard); 184 185 if (!ep->online) 186 return EINTR; 187 188 assert(ep->active_batch == NULL); 189 ep->active_batch = batch; 190 return EOK; 191 } 192 193 /** 194 * Mark the endpoint as inactive and allow access for further fibrils. 195 */ 196 void endpoint_deactivate_locked(endpoint_t *ep) 197 { 198 assert(ep); 199 assert(fibril_mutex_is_locked(ep->guard)); 200 201 ep->active_batch = NULL; 202 fibril_condvar_signal(&ep->avail); 203 } 204 205 /** 206 * Initiate a transfer on an endpoint. Creates a transfer batch, checks the 207 * bandwidth requirements and schedules the batch. 208 * 209 * @param endpoint Endpoint for which to send the batch 210 */ 211 errno_t endpoint_send_batch(endpoint_t *ep, const transfer_request_t *req) 212 { 213 assert(ep); 214 assert(req); 215 216 if (ep->transfer_type == USB_TRANSFER_CONTROL) { 217 usb_log_debug("%s %d:%d %zu/%zuB, setup %#016" PRIx64, req->name, 218 req->target.address, req->target.endpoint, 219 req->size, ep->max_packet_size, 220 req->setup); 221 } else { 222 usb_log_debug("%s %d:%d %zu/%zuB", req->name, 223 req->target.address, req->target.endpoint, 224 req->size, ep->max_packet_size); 225 } 226 227 device_t * const device = ep->device; 228 if (!device) { 229 usb_log_warning("Endpoint detached"); 230 return EAGAIN; 231 } 232 233 const bus_ops_t *ops = device->bus->ops; 234 if (!ops->batch_schedule) { 235 usb_log_error("HCD does not implement scheduler."); 236 return ENOTSUP; 237 } 238 239 size_t size = req->size; 240 /* 241 * Limit transfers with reserved bandwidth to the amount reserved. 242 * OUT transfers are rejected, IN can be just trimmed in advance. 243 */ 244 if (size > ep->max_transfer_size && 245 (ep->transfer_type == USB_TRANSFER_INTERRUPT 246 || ep->transfer_type == USB_TRANSFER_ISOCHRONOUS)) { 247 if (req->dir == USB_DIRECTION_OUT) 248 return ENOSPC; 249 else 250 size = ep->max_transfer_size; 251 } 252 253 /* Offline devices don't schedule transfers other than on EP0. */ 254 if (!device->online && ep->endpoint > 0) 255 return EAGAIN; 256 257 usb_transfer_batch_t *batch = usb_transfer_batch_create(ep); 258 if (!batch) { 259 usb_log_error("Failed to create transfer batch."); 260 return ENOMEM; 261 } 262 263 batch->target = req->target; 264 batch->setup.packed = req->setup; 265 batch->dir = req->dir; 266 batch->size = size; 267 batch->offset = req->offset; 268 batch->dma_buffer = req->buffer; 269 270 dma_buffer_acquire(&batch->dma_buffer); 271 272 if (batch->offset != 0) { 273 usb_log_debug("A transfer with nonzero offset requested."); 274 usb_transfer_batch_bounce(batch); 275 } 276 277 if (usb_transfer_batch_bounce_required(batch)) 278 usb_transfer_batch_bounce(batch); 279 280 batch->on_complete = req->on_complete; 281 batch->on_complete_data = req->arg; 282 283 const int ret = ops->batch_schedule(batch); 284 if (ret != EOK) { 285 usb_log_warning("Batch %p failed to schedule: %s", batch, str_error(ret)); 286 usb_transfer_batch_destroy(batch); 287 } 288 173 289 return ret; 174 290 } 175 291 176 /** Set the value of toggle bit.177 * @param instance endpoint_t structure.178 * @note Will use provided hook.179 */180 void endpoint_toggle_set(endpoint_t *instance, int toggle)181 {182 assert(instance);183 assert(toggle == 0 || toggle == 1);184 fibril_mutex_lock(&instance->guard);185 instance->toggle = toggle;186 if (instance->hc_data.toggle_set)187 instance->hc_data.toggle_set(instance->hc_data.data, toggle);188 fibril_mutex_unlock(&instance->guard);189 }190 191 292 /** 192 293 * @} -
uspace/lib/usbhost/src/hcd.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 32 33 /** @file 33 34 * 34 */ 35 36 #include <usb/debug.h> 37 #include <usb/request.h> 35 * Host controller driver framework. Encapsulates DDF device of HC to an 36 * hc_device_t, which is passed to driver implementing hc_driver_t. 37 */ 38 38 39 39 #include <assert.h> 40 40 #include <async.h> 41 #include <ddf/interrupt.h> 41 42 #include <errno.h> 43 #include <macros.h> 44 #include <str_error.h> 45 #include <usb/debug.h> 46 #include <usb/descriptor.h> 47 #include <usb/request.h> 42 48 #include <usb_iface.h> 43 49 50 #include "bus.h" 51 #include "ddf_helpers.h" 52 #include "endpoint.h" 53 #include "usb_transfer_batch.h" 54 44 55 #include "hcd.h" 45 56 46 /** Calls ep_add_hook upon endpoint registration. 47 * @param ep Endpoint to be registered. 48 * @param arg hcd_t in disguise. 49 * @return Error code. 50 */ 51 static errno_t register_helper(endpoint_t *ep, void *arg) 52 { 53 hcd_t *hcd = arg; 54 assert(ep); 57 int hc_dev_add(ddf_dev_t *); 58 int hc_dev_remove(ddf_dev_t *); 59 int hc_dev_gone(ddf_dev_t *); 60 int hc_fun_online(ddf_fun_t *); 61 int hc_fun_offline(ddf_fun_t *); 62 63 static driver_ops_t hc_driver_ops = { 64 .dev_add = hc_dev_add, 65 .dev_remove = hc_dev_remove, 66 .dev_gone = hc_dev_gone, 67 .fun_online = hc_fun_online, 68 .fun_offline = hc_fun_offline, 69 }; 70 71 static const hc_driver_t *hc_driver; 72 73 /** 74 * The main HC driver routine. 75 */ 76 int hc_driver_main(const hc_driver_t *driver) 77 { 78 driver_t ddf_driver = { 79 .name = driver->name, 80 .driver_ops = &hc_driver_ops, 81 }; 82 83 /* Remember ops to call. */ 84 hc_driver = driver; 85 86 return ddf_driver_main(&ddf_driver); 87 } 88 89 /** 90 * IRQ handling callback. Call the bus operation. 91 * 92 * Currently, there is a bus ops lookup to find the interrupt handler. So far, 93 * the mechanism is too flexible, as it allows different instances of HC to 94 * have different IRQ handlers, disallowing us to optimize the lookup here. 95 * TODO: Make the bus mechanism less flexible in irq handling and remove the 96 * lookup. 97 */ 98 static void irq_handler(ipc_call_t *call, ddf_dev_t *dev) 99 { 100 assert(dev); 101 hc_device_t *hcd = dev_to_hcd(dev); 102 103 const uint32_t status = IPC_GET_ARG1(*call); 104 hcd->bus->ops->interrupt(hcd->bus, status); 105 } 106 107 /** 108 * Worker for the HW interrupt replacement fibril. 109 */ 110 static errno_t interrupt_polling(void *arg) 111 { 112 bus_t *bus = arg; 113 assert(bus); 114 115 if (!bus->ops->interrupt || !bus->ops->status) 116 return ENOTSUP; 117 118 uint32_t status = 0; 119 while (bus->ops->status(bus, &status) == EOK) { 120 bus->ops->interrupt(bus, status); 121 status = 0; 122 /* We should wait 1 frame - 1ms here, but this polling is a 123 * lame crutch anyway so don't hog the system. 10ms is still 124 * good enough for emergency mode */ 125 async_usleep(10000); 126 } 127 return EOK; 128 } 129 130 /** 131 * Clean the IRQ code bottom-half. 132 */ 133 static inline void irq_code_clean(irq_code_t *code) 134 { 135 if (code) { 136 free(code->ranges); 137 free(code->cmds); 138 code->ranges = NULL; 139 code->cmds = NULL; 140 code->rangecount = 0; 141 code->cmdcount = 0; 142 } 143 } 144 145 /** 146 * Register an interrupt handler. If there is a callback to setup the bottom half, 147 * invoke it and register it. Register for notifications. 148 * 149 * If this method fails, a polling fibril is started instead. 150 * 151 * @param[in] hcd Host controller device. 152 * @param[in] hw_res Resources to be used. 153 * 154 * @return IRQ capability handle on success. 155 * @return Negative error code. 156 */ 157 static errno_t hcd_ddf_setup_interrupts(hc_device_t *hcd, 158 const hw_res_list_parsed_t *hw_res) 159 { 55 160 assert(hcd); 56 if (hcd->ops.ep_add_hook) 57 return hcd->ops.ep_add_hook(hcd, ep); 161 irq_code_t irq_code = { 0 }; 162 163 if (!hc_driver->irq_code_gen) 164 return ENOTSUP; 165 166 int irq; 167 errno_t ret; 168 ret = hc_driver->irq_code_gen(&irq_code, hcd, hw_res, &irq); 169 if (ret != EOK) { 170 usb_log_error("Failed to generate IRQ code: %s.", 171 str_error(irq)); 172 return irq; 173 } 174 175 /* Register handler to avoid interrupt lockup */ 176 int irq_cap; 177 ret = register_interrupt_handler(hcd->ddf_dev, irq, irq_handler, 178 &irq_code, &irq_cap); 179 irq_code_clean(&irq_code); 180 if (ret != EOK) { 181 usb_log_error("Failed to register interrupt handler: %s.", 182 str_error(irq_cap)); 183 return irq_cap; 184 } 185 186 /* Enable interrupts */ 187 ret = hcd_ddf_enable_interrupt(hcd, irq); 188 if (ret != EOK) { 189 usb_log_error("Failed to enable interrupts: %s.", 190 str_error(ret)); 191 unregister_interrupt_handler(hcd->ddf_dev, irq_cap); 192 return ret; 193 } 194 return irq_cap; 195 } 196 197 /** 198 * Initialize HC in memory of the driver. 199 * 200 * This function does all the preparatory work for hc and rh drivers: 201 * - gets device's hw resources 202 * - attempts to enable interrupts 203 * - registers interrupt handler 204 * - calls driver specific initialization 205 * - registers root hub 206 * 207 * @param device DDF instance of the device to use 208 * @return Error code 209 */ 210 errno_t hc_dev_add(ddf_dev_t *device) 211 { 212 errno_t ret = EOK; 213 assert(device); 214 215 if (!hc_driver->hc_add) { 216 usb_log_error("Driver '%s' does not support adding devices.", 217 hc_driver->name); 218 return ENOTSUP; 219 } 220 221 ret = hcd_ddf_setup_hc(device, hc_driver->hc_device_size); 222 if (ret != EOK) { 223 usb_log_error("Failed to setup HC device."); 224 return ret; 225 } 226 227 hc_device_t *hcd = dev_to_hcd(device); 228 229 hw_res_list_parsed_t hw_res; 230 ret = hcd_ddf_get_registers(hcd, &hw_res); 231 if (ret != EOK) { 232 usb_log_error("Failed to get register memory addresses " 233 "for `%s': %s.", ddf_dev_get_name(device), 234 str_error(ret)); 235 goto err_hcd; 236 } 237 238 ret = hc_driver->hc_add(hcd, &hw_res); 239 if (ret != EOK) { 240 usb_log_error("Failed to init HCD."); 241 goto err_hw_res; 242 } 243 244 assert(hcd->bus); 245 246 /* Setup interrupts */ 247 hcd->irq_cap = hcd_ddf_setup_interrupts(hcd, &hw_res); 248 if (hcd->irq_cap >= 0) { 249 usb_log_debug("Hw interrupts enabled."); 250 } 251 252 /* Claim the device from BIOS */ 253 if (hc_driver->claim) 254 ret = hc_driver->claim(hcd); 255 if (ret != EOK) { 256 usb_log_error("Failed to claim `%s' for `%s': %s", 257 ddf_dev_get_name(device), hc_driver->name, str_error(ret)); 258 goto err_irq; 259 } 260 261 /* Start hw */ 262 if (hc_driver->start) 263 ret = hc_driver->start(hcd); 264 if (ret != EOK) { 265 usb_log_error("Failed to start HCD: %s.", str_error(ret)); 266 goto err_irq; 267 } 268 269 const bus_ops_t *ops = hcd->bus->ops; 270 271 /* Need working irq replacement to setup root hub */ 272 if (hcd->irq_cap < 0 && ops->status) { 273 hcd->polling_fibril = fibril_create(interrupt_polling, hcd->bus); 274 if (!hcd->polling_fibril) { 275 usb_log_error("Failed to create polling fibril"); 276 ret = ENOMEM; 277 goto err_started; 278 } 279 fibril_add_ready(hcd->polling_fibril); 280 usb_log_warning("Failed to enable interrupts: %s." 281 " Falling back to polling.", str_error(hcd->irq_cap)); 282 } 283 284 /* 285 * Creating root hub registers a new USB device so HC 286 * needs to be ready at this time. 287 */ 288 if (hc_driver->setup_root_hub) 289 ret = hc_driver->setup_root_hub(hcd); 290 if (ret != EOK) { 291 usb_log_error("Failed to setup HC root hub: %s.", 292 str_error(ret)); 293 goto err_polling; 294 } 295 296 usb_log_info("Controlling new `%s' device `%s'.", 297 hc_driver->name, ddf_dev_get_name(device)); 58 298 return EOK; 59 } 60 61 /** Calls ep_remove_hook upon endpoint removal. 62 * @param ep Endpoint to be unregistered. 63 * @param arg hcd_t in disguise. 64 */ 65 static void unregister_helper(endpoint_t *ep, void *arg) 66 { 67 hcd_t *hcd = arg; 68 assert(ep); 69 assert(hcd); 70 if (hcd->ops.ep_remove_hook) 71 hcd->ops.ep_remove_hook(hcd, ep); 72 } 73 74 /** Calls ep_remove_hook upon endpoint removal. Prints warning. 75 * * @param ep Endpoint to be unregistered. 76 * * @param arg hcd_t in disguise. 77 * */ 78 static void unregister_helper_warn(endpoint_t *ep, void *arg) 79 { 80 assert(ep); 81 usb_log_warning("Endpoint %d:%d %s was left behind, removing.\n", 82 ep->address, ep->endpoint, usb_str_direction(ep->direction)); 83 unregister_helper(ep, arg); 84 } 85 86 87 /** Initialize hcd_t structure. 88 * Initializes device and endpoint managers. Sets data and hook pointer to NULL. 89 * 90 * @param hcd hcd_t structure to initialize, non-null. 91 * @param max_speed Maximum supported USB speed (full, high). 92 * @param bandwidth Available bandwidth, passed to endpoint manager. 93 * @param bw_count Bandwidth compute function, passed to endpoint manager. 94 */ 95 void hcd_init(hcd_t *hcd, usb_speed_t max_speed, size_t bandwidth, 96 bw_count_func_t bw_count) 97 { 98 assert(hcd); 99 usb_bus_init(&hcd->bus, bandwidth, bw_count, max_speed); 100 101 hcd_set_implementation(hcd, NULL, NULL); 102 } 103 104 errno_t hcd_request_address(hcd_t *hcd, usb_speed_t speed, usb_address_t *address) 105 { 106 assert(hcd); 107 return usb_bus_request_address(&hcd->bus, address, false, speed); 108 } 109 110 errno_t hcd_release_address(hcd_t *hcd, usb_address_t address) 111 { 112 assert(hcd); 113 return usb_bus_remove_address(&hcd->bus, address, 114 unregister_helper_warn, hcd); 115 } 116 117 errno_t hcd_reserve_default_address(hcd_t *hcd, usb_speed_t speed) 118 { 119 assert(hcd); 120 usb_address_t address = 0; 121 return usb_bus_request_address(&hcd->bus, &address, true, speed); 122 } 123 124 errno_t hcd_add_ep(hcd_t *hcd, usb_target_t target, usb_direction_t dir, 125 usb_transfer_type_t type, size_t max_packet_size, unsigned packets, 126 size_t size, usb_address_t tt_address, unsigned tt_port) 127 { 128 assert(hcd); 129 return usb_bus_add_ep(&hcd->bus, target.address, 130 target.endpoint, dir, type, max_packet_size, packets, size, 131 register_helper, hcd, tt_address, tt_port); 132 } 133 134 errno_t hcd_remove_ep(hcd_t *hcd, usb_target_t target, usb_direction_t dir) 135 { 136 assert(hcd); 137 return usb_bus_remove_ep(&hcd->bus, target.address, 138 target.endpoint, dir, unregister_helper, hcd); 139 } 140 141 142 typedef struct { 143 void *original_data; 144 usbhc_iface_transfer_out_callback_t original_callback; 145 usb_target_t target; 146 hcd_t *hcd; 147 } toggle_t; 148 149 static void toggle_reset_callback(errno_t retval, void *arg) 150 { 151 assert(arg); 152 toggle_t *toggle = arg; 153 if (retval == EOK) { 154 usb_log_debug2("Reseting toggle on %d:%d.\n", 155 toggle->target.address, toggle->target.endpoint); 156 usb_bus_reset_toggle(&toggle->hcd->bus, 157 toggle->target, toggle->target.endpoint == 0); 158 } 159 160 toggle->original_callback(retval, toggle->original_data); 161 } 162 163 /** Prepare generic usb_transfer_batch and schedule it. 164 * @param hcd Host controller driver. 165 * @param fun DDF fun 166 * @param target address and endpoint number. 167 * @param setup_data Data to use in setup stage (Control communication type) 168 * @param in Callback for device to host communication. 169 * @param out Callback for host to device communication. 170 * @param arg Callback parameter. 171 * @param name Communication identifier (for nicer output). 172 * @return Error code. 173 */ 174 errno_t hcd_send_batch( 175 hcd_t *hcd, usb_target_t target, usb_direction_t direction, 176 void *data, size_t size, uint64_t setup_data, 177 usbhc_iface_transfer_in_callback_t in, 178 usbhc_iface_transfer_out_callback_t out, void *arg, const char* name) 179 { 180 assert(hcd); 181 182 endpoint_t *ep = usb_bus_find_ep(&hcd->bus, 183 target.address, target.endpoint, direction); 184 if (ep == NULL) { 185 usb_log_error("Endpoint(%d:%d) not registered for %s.\n", 186 target.address, target.endpoint, name); 187 return ENOENT; 188 } 189 190 usb_log_debug2("%s %d:%d %zu(%zu).\n", 191 name, target.address, target.endpoint, size, ep->max_packet_size); 192 193 const size_t bw = bandwidth_count_usb11( 194 ep->speed, ep->transfer_type, size, ep->max_packet_size); 195 /* Check if we have enough bandwidth reserved */ 196 if (ep->bandwidth < bw) { 197 usb_log_error("Endpoint(%d:%d) %s needs %zu bw " 198 "but only %zu is reserved.\n", 199 ep->address, ep->endpoint, name, bw, ep->bandwidth); 200 return ENOSPC; 201 } 202 if (!hcd->ops.schedule) { 203 usb_log_error("HCD does not implement scheduler.\n"); 204 return ENOTSUP; 205 } 206 207 /* Check for commands that reset toggle bit */ 208 if (ep->transfer_type == USB_TRANSFER_CONTROL) { 209 const int reset_toggle = usb_request_needs_toggle_reset( 210 (usb_device_request_setup_packet_t *) &setup_data); 211 if (reset_toggle >= 0) { 212 assert(out); 213 toggle_t *toggle = malloc(sizeof(toggle_t)); 214 if (!toggle) 215 return ENOMEM; 216 toggle->target.address = target.address; 217 toggle->target.endpoint = reset_toggle; 218 toggle->original_callback = out; 219 toggle->original_data = arg; 220 toggle->hcd = hcd; 221 222 arg = toggle; 223 out = toggle_reset_callback; 224 } 225 } 226 227 usb_transfer_batch_t *batch = usb_transfer_batch_create( 228 ep, data, size, setup_data, in, out, arg); 229 if (!batch) { 230 usb_log_error("Failed to create transfer batch.\n"); 231 return ENOMEM; 232 } 233 234 const errno_t ret = hcd->ops.schedule(hcd, batch); 235 if (ret != EOK) 236 usb_transfer_batch_destroy(batch); 237 238 /* Drop our own reference to ep. */ 239 endpoint_del_ref(ep); 240 299 300 err_polling: 301 // TODO: Stop the polling fibril (refactor the interrupt_polling func) 302 // 303 err_started: 304 if (hc_driver->stop) 305 hc_driver->stop(hcd); 306 err_irq: 307 unregister_interrupt_handler(device, hcd->irq_cap); 308 if (hc_driver->hc_remove) 309 hc_driver->hc_remove(hcd); 310 err_hw_res: 311 hw_res_list_parsed_clean(&hw_res); 312 err_hcd: 313 hcd_ddf_clean_hc(hcd); 241 314 return ret; 242 315 } 243 316 244 typedef struct { 245 volatile unsigned done; 246 errno_t ret; 247 size_t size; 248 } sync_data_t; 249 250 static void transfer_in_cb(errno_t ret, size_t size, void* data) 251 { 252 sync_data_t *d = data; 253 assert(d); 254 d->ret = ret; 255 d->done = 1; 256 d->size = size; 257 } 258 259 static void transfer_out_cb(errno_t ret, void* data) 260 { 261 sync_data_t *d = data; 262 assert(data); 263 d->ret = ret; 264 d->done = 1; 265 } 266 267 /** this is really ugly version of sync usb communication */ 268 errno_t hcd_send_batch_sync( 269 hcd_t *hcd, usb_target_t target, usb_direction_t dir, 270 void *data, size_t size, uint64_t setup_data, const char* name, size_t *out_size) 271 { 272 assert(hcd); 273 sync_data_t sd = { .done = 0, .ret = EBUSY, .size = size }; 274 275 const errno_t ret = hcd_send_batch(hcd, target, dir, data, size, setup_data, 276 dir == USB_DIRECTION_IN ? transfer_in_cb : NULL, 277 dir == USB_DIRECTION_OUT ? transfer_out_cb : NULL, &sd, name); 278 if (ret != EOK) 279 return ret; 280 281 while (!sd.done) { 282 async_usleep(1000); 283 } 284 285 if (sd.ret == EOK) 286 *out_size = sd.size; 287 return sd.ret; 317 errno_t hc_dev_remove(ddf_dev_t *dev) 318 { 319 errno_t err; 320 hc_device_t *hcd = dev_to_hcd(dev); 321 322 if (hc_driver->stop) 323 if ((err = hc_driver->stop(hcd))) 324 return err; 325 326 unregister_interrupt_handler(dev, hcd->irq_cap); 327 328 if (hc_driver->hc_remove) 329 if ((err = hc_driver->hc_remove(hcd))) 330 return err; 331 332 hcd_ddf_clean_hc(hcd); 333 334 // TODO probably not complete 335 336 return EOK; 337 } 338 339 errno_t hc_dev_gone(ddf_dev_t *dev) 340 { 341 errno_t err = ENOTSUP; 342 hc_device_t *hcd = dev_to_hcd(dev); 343 344 if (hc_driver->hc_gone) 345 err = hc_driver->hc_gone(hcd); 346 347 hcd_ddf_clean_hc(hcd); 348 349 return err; 350 } 351 352 errno_t hc_fun_online(ddf_fun_t *fun) 353 { 354 assert(fun); 355 356 device_t *dev = ddf_fun_data_get(fun); 357 assert(dev); 358 359 usb_log_info("Device(%d): Requested to be brought online.", dev->address); 360 return bus_device_online(dev); 361 } 362 363 int hc_fun_offline(ddf_fun_t *fun) 364 { 365 assert(fun); 366 367 device_t *dev = ddf_fun_data_get(fun); 368 assert(dev); 369 370 usb_log_info("Device(%d): Requested to be taken offline.", dev->address); 371 return bus_device_offline(dev); 288 372 } 289 373 -
uspace/lib/usbhost/src/usb_transfer_batch.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 33 34 */ 34 35 35 #include <usb/host/usb_transfer_batch.h>36 #include <usb/debug.h>37 38 36 #include <assert.h> 39 37 #include <errno.h> 40 #include <macros.h>41 #include <mem.h>42 38 #include <stdlib.h> 43 #include <usbhc_iface.h> 44 45 /** Allocate and initialize usb_transfer_batch structure. 46 * @param ep endpoint used by the transfer batch. 47 * @param buffer data to send/recieve. 48 * @param buffer_size Size of data buffer. 49 * @param setup_buffer Data to send in SETUP stage of control transfer. 50 * @param func_in callback on IN transfer completion. 51 * @param func_out callback on OUT transfer completion. 52 * @param fun DDF function (passed to callback function). 53 * @param arg Argument to pass to the callback function. 54 * @param private_data driver specific per batch data. 55 * @param private_data_dtor Function to properly destroy private_data. 56 * @return Pointer to valid usb_transfer_batch_t structure, NULL on failure. 57 */ 58 usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *ep, char *buffer, 59 size_t buffer_size, 60 uint64_t setup_buffer, 61 usbhc_iface_transfer_in_callback_t func_in, 62 usbhc_iface_transfer_out_callback_t func_out, 63 void *arg) 64 { 65 if (func_in == NULL && func_out == NULL) 66 return NULL; 67 if (func_in != NULL && func_out != NULL) 68 return NULL; 69 70 usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t)); 71 if (instance) { 72 instance->ep = ep; 73 instance->callback_in = func_in; 74 instance->callback_out = func_out; 75 instance->arg = arg; 76 instance->buffer = buffer; 77 instance->buffer_size = buffer_size; 78 instance->setup_size = 0; 79 instance->transfered_size = 0; 80 instance->error = EOK; 81 if (ep && ep->transfer_type == USB_TRANSFER_CONTROL) { 82 memcpy(instance->setup_buffer, &setup_buffer, 83 USB_SETUP_PACKET_SIZE); 84 instance->setup_size = USB_SETUP_PACKET_SIZE; 39 #include <str_error.h> 40 #include <usb/debug.h> 41 42 #include "endpoint.h" 43 #include "bus.h" 44 45 #include "usb_transfer_batch.h" 46 47 /** 48 * Create a batch on a given endpoint. 49 * 50 * If the bus callback is not defined, it just creates a default batch. 51 */ 52 usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *ep) 53 { 54 assert(ep); 55 56 bus_t *bus = endpoint_get_bus(ep); 57 58 if (!bus->ops->batch_create) { 59 usb_transfer_batch_t *batch = calloc(1, sizeof(usb_transfer_batch_t)); 60 if (!batch) 61 return NULL; 62 usb_transfer_batch_init(batch, ep); 63 return batch; 64 } 65 66 return bus->ops->batch_create(ep); 67 } 68 69 /** 70 * Initialize given batch structure. 71 */ 72 void usb_transfer_batch_init(usb_transfer_batch_t *batch, endpoint_t *ep) 73 { 74 assert(ep); 75 /* Batch reference */ 76 endpoint_add_ref(ep); 77 batch->ep = ep; 78 } 79 80 /** 81 * Destroy the batch. If there's no bus callback, just free it. 82 */ 83 void usb_transfer_batch_destroy(usb_transfer_batch_t *batch) 84 { 85 assert(batch); 86 assert(batch->ep); 87 88 bus_t *bus = endpoint_get_bus(batch->ep); 89 endpoint_t *ep = batch->ep; 90 91 if (bus->ops) { 92 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " destroying.", 93 batch, USB_TRANSFER_BATCH_ARGS(*batch)); 94 bus->ops->batch_destroy(batch); 95 } 96 else { 97 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " disposing.", 98 batch, USB_TRANSFER_BATCH_ARGS(*batch)); 99 free(batch); 100 } 101 102 /* Batch reference */ 103 endpoint_del_ref(ep); 104 } 105 106 bool usb_transfer_batch_bounce_required(usb_transfer_batch_t *batch) 107 { 108 if (!batch->size) 109 return false; 110 111 unsigned flags = batch->dma_buffer.policy & DMA_POLICY_FLAGS_MASK; 112 unsigned required_flags = 113 batch->ep->required_transfer_buffer_policy & DMA_POLICY_FLAGS_MASK; 114 115 if (required_flags & ~flags) 116 return true; 117 118 size_t chunk_mask = dma_policy_chunk_mask(batch->dma_buffer.policy); 119 size_t required_chunk_mask = 120 dma_policy_chunk_mask(batch->ep->required_transfer_buffer_policy); 121 122 /* If the chunks are at least as large as required, we're good */ 123 if ((required_chunk_mask & ~chunk_mask) == 0) 124 return false; 125 126 size_t start_chunk = batch->offset & ~chunk_mask; 127 size_t end_chunk = (batch->offset + batch->size - 1) & ~chunk_mask; 128 129 /* The requested area crosses a chunk boundary */ 130 if (start_chunk != end_chunk) 131 return true; 132 133 return false; 134 } 135 136 errno_t usb_transfer_batch_bounce(usb_transfer_batch_t *batch) 137 { 138 assert(batch); 139 assert(!batch->is_bounced); 140 141 dma_buffer_release(&batch->dma_buffer); 142 143 batch->original_buffer = batch->dma_buffer.virt + batch->offset; 144 145 usb_log_debug("Batch(%p): Buffer cannot be used directly, " 146 "falling back to bounce buffer!", batch); 147 148 const errno_t err = dma_buffer_alloc_policy(&batch->dma_buffer, 149 batch->size, batch->ep->transfer_buffer_policy); 150 if (err) 151 return err; 152 153 /* Copy the data out */ 154 if (batch->dir == USB_DIRECTION_OUT) 155 memcpy(batch->dma_buffer.virt, 156 batch->original_buffer, 157 batch->size); 158 159 batch->is_bounced = true; 160 batch->offset = 0; 161 162 return err; 163 } 164 165 /** 166 * Finish a transfer batch: call handler, destroy batch, release endpoint. 167 * 168 * Call only after the batch have been scheduled && completed! 169 */ 170 void usb_transfer_batch_finish(usb_transfer_batch_t *batch) 171 { 172 assert(batch); 173 assert(batch->ep); 174 175 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " finishing.", 176 batch, USB_TRANSFER_BATCH_ARGS(*batch)); 177 178 if (batch->error == EOK && batch->size > 0) { 179 if (batch->is_bounced) { 180 /* We we're forced to use bounce buffer, copy it back */ 181 if (batch->dir == USB_DIRECTION_IN) 182 memcpy(batch->original_buffer, 183 batch->dma_buffer.virt, 184 batch->transferred_size); 185 186 dma_buffer_free(&batch->dma_buffer); 85 187 } 86 if (instance->ep) 87 endpoint_use(instance->ep); 88 } 89 return instance; 90 } 91 92 /** Correctly dispose all used data structures. 93 * 94 * @param[in] instance Batch structure to use. 95 */ 96 void usb_transfer_batch_destroy(usb_transfer_batch_t *instance) 97 { 98 if (!instance) 99 return; 100 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " disposing.\n", 101 instance, USB_TRANSFER_BATCH_ARGS(*instance)); 102 if (instance->ep) { 103 endpoint_release(instance->ep); 104 } 105 free(instance); 106 } 107 108 /** Prepare data and call the right callback. 109 * 110 * @param[in] instance Batch structure to use. 111 * @param[in] data Data to copy to the output buffer. 112 * @param[in] size Size of @p data. 113 * @param[in] error Error value to use. 114 */ 115 void usb_transfer_batch_finish_error(const usb_transfer_batch_t *instance, 116 const void *data, size_t size, errno_t error) 117 { 118 assert(instance); 119 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " finishing.\n", 120 instance, USB_TRANSFER_BATCH_ARGS(*instance)); 121 122 /* NOTE: Only one of these pointers should be set. */ 123 if (instance->callback_out) { 124 instance->callback_out(error, instance->arg); 125 } 126 127 if (instance->callback_in) { 128 /* We care about the data and there are some to copy */ 129 const size_t safe_size = min(size, instance->buffer_size); 130 if (data) { 131 memcpy(instance->buffer, data, safe_size); 188 else { 189 dma_buffer_release(&batch->dma_buffer); 132 190 } 133 instance->callback_in(error, safe_size, instance->arg); 134 } 135 } 191 } 192 193 if (batch->on_complete) { 194 const int err = batch->on_complete(batch->on_complete_data, batch->error, batch->transferred_size); 195 if (err) 196 usb_log_warning("Batch %p failed to complete: %s", 197 batch, str_error(err)); 198 } 199 200 usb_transfer_batch_destroy(batch); 201 } 202 136 203 /** 137 204 * @}
Note:
See TracChangeset
for help on using the changeset viewer.
