Changeset 32fb6bce in mainline for uspace/lib/usbhost
- Timestamp:
- 2017-12-18T22:50:21Z (8 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 7f70d1c
- Parents:
- 1ea0bbf
- git-author:
- Ondřej Hlavatý <aearsis@…> (2017-12-18 22:04:50)
- git-committer:
- Ondřej Hlavatý <aearsis@…> (2017-12-18 22:50:21)
- Location:
- uspace/lib/usbhost
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbhost/include/usb/host/bus.h
r1ea0bbf r32fb6bce 43 43 #define LIBUSBHOST_HOST_BUS_H 44 44 45 #include <usb/usb.h>46 #include <usb/request.h>47 #include <usb/host/hcd.h>48 49 45 #include <assert.h> 50 46 #include <fibril_synch.h> 51 47 #include <stdbool.h> 48 #include <usb/host/hcd.h> 49 #include <usb/request.h> 50 #include <usb/usb.h> 51 #include <usbhc_iface.h> 52 52 53 53 typedef struct hcd hcd_t; … … 94 94 95 95 /* Global operations on the bus */ 96 void (*interrupt)(bus_t *, uint32_t); 97 int (*status)(bus_t *, uint32_t *); 96 98 int (*reserve_default_address)(bus_t *, usb_speed_t); 97 99 int (*release_default_address)(bus_t *); … … 116 118 117 119 /* Operations on batch */ 118 void (*batch_destroy)(usb_transfer_batch_t *); /**< Optional */ 120 void (*batch_destroy)(usb_transfer_batch_t *); /**< Optional */ 121 int (*batch_schedule)(usb_transfer_batch_t *); 119 122 }; 120 123 … … 129 132 fibril_mutex_t guard; 130 133 131 /* TODO: get rid of this one. */ 132 hcd_t *hcd; 133 134 /* Size of the device_t extended structure */ 134 135 size_t device_size; 135 136 … … 140 141 } bus_t; 141 142 142 void bus_init(bus_t *, hcd_t *,size_t);143 void bus_init(bus_t *, size_t); 143 144 int bus_device_init(device_t *, bus_t *); 144 145 … … 150 151 int bus_device_online(device_t *); 151 152 int bus_device_offline(device_t *); 153 154 int bus_device_send_batch(device_t *, usb_target_t, 155 usb_direction_t direction, char *, size_t, uint64_t, 156 usbhc_iface_transfer_callback_t, void *, const char *); 157 158 ssize_t bus_device_send_batch_sync(device_t *, usb_target_t, 159 usb_direction_t direction, char *, size_t, uint64_t, 160 const char *); 152 161 153 162 int bus_endpoint_add(device_t *, const usb_endpoint_desc_t *, endpoint_t **); -
uspace/lib/usbhost/include/usb/host/ddf_helpers.h
r1ea0bbf r32fb6bce 39 39 #include <ddf/driver.h> 40 40 #include <ddf/interrupt.h> 41 #include <device/hw_res_parsed.h>42 41 #include <usb/usb.h> 43 42 44 43 #include <usb/host/hcd.h> 45 44 46 typedef int (*driver_init_t)(hcd_t *, const hw_res_list_parsed_t *, ddf_dev_t *); 47 typedef int (*irq_code_gen_t)(irq_code_t *, hcd_t *, const hw_res_list_parsed_t *); 48 typedef int (*claim_t)(hcd_t *, ddf_dev_t *); 49 typedef int (*driver_start_t)(hcd_t *, bool irq); 50 typedef int (*setup_root_hub_t)(hcd_t *, ddf_dev_t *); 45 int hcd_ddf_setup_hc(ddf_dev_t *, size_t); 46 void hcd_ddf_clean_hc(hc_device_t *); 51 47 52 typedef void (*driver_stop_t)(hcd_t *); 53 typedef void (*driver_fini_t)(hcd_t *); 48 int hcd_setup_virtual_root_hub(hc_device_t *); 54 49 55 /** 56 * All callbacks are optional. 57 */ 58 typedef struct { 59 hcd_ops_t ops; 60 const char *name; 50 device_t *hcd_ddf_fun_create(hc_device_t *); 51 void hcd_ddf_fun_destroy(device_t *); 61 52 62 interrupt_handler_t *irq_handler; /**< Handler of IRQ. Do have generic implementation. */ 53 int hcd_device_explore(device_t *); 63 54 64 /* Initialization sequence: */ 65 driver_init_t init; /**< Initialize internal structures, memory */ 66 claim_t claim; /**< Claim device from BIOS */ 67 irq_code_gen_t irq_code_gen; /**< Generate IRQ handling code */ 68 driver_start_t start; /**< Start the HC */ 69 setup_root_hub_t setup_root_hub; /**< Setup the root hub */ 55 int hcd_ddf_enable_interrupt(hc_device_t *hcd, int); 56 int hcd_ddf_get_registers(hc_device_t *hcd, hw_res_list_parsed_t *hw_res); 70 57 71 /* Destruction sequence: */ 72 driver_stop_t stop; /**< Stop the HC (counterpart of start) */ 73 driver_fini_t fini; /**< Destroy internal structures (counterpart of init) */ 74 } ddf_hc_driver_t; 75 76 int hcd_ddf_add_hc(ddf_dev_t *device, const ddf_hc_driver_t *driver); 77 78 int hcd_ddf_setup_hc(ddf_dev_t *device); 79 void hcd_ddf_clean_hc(ddf_dev_t *device); 80 81 int hcd_setup_virtual_root_hub(hcd_t *, ddf_dev_t *); 82 83 device_t *hcd_ddf_device_create(ddf_dev_t *, bus_t *); 84 void hcd_ddf_device_destroy(device_t *); 85 int hcd_ddf_device_explore(device_t *); 86 int hcd_ddf_device_online(ddf_fun_t *); 87 int hcd_ddf_device_offline(ddf_fun_t *); 88 89 hcd_t *dev_to_hcd(ddf_dev_t *dev); 90 91 int hcd_ddf_enable_interrupt(ddf_dev_t *device, int); 92 int hcd_ddf_get_registers(ddf_dev_t *device, hw_res_list_parsed_t *hw_res); 93 int hcd_ddf_setup_interrupts(ddf_dev_t *device, 94 const hw_res_list_parsed_t *hw_res, 95 interrupt_handler_t handler, 96 irq_code_gen_t gen_irq_code); 97 void ddf_hcd_gen_irq_handler(ipc_callid_t iid, ipc_call_t *call, ddf_dev_t *dev); 58 void hcd_ddf_gen_irq_handler(ipc_callid_t iid, ipc_call_t *call, ddf_dev_t *dev); 98 59 99 60 #endif -
uspace/lib/usbhost/include/usb/host/endpoint.h
r1ea0bbf r32fb6bce 109 109 ssize_t endpoint_count_bw(endpoint_t *, size_t); 110 110 111 int endpoint_send_batch(endpoint_t *, usb_target_t, usb_direction_t, 112 char *, size_t, uint64_t, usbhc_iface_transfer_callback_t, void *, 113 const char *); 114 111 115 static inline bus_t *endpoint_get_bus(endpoint_t *ep) 112 116 { -
uspace/lib/usbhost/include/usb/host/hcd.h
r1ea0bbf r32fb6bce 37 37 #define LIBUSBHOST_HOST_HCD_H 38 38 39 #include <assert.h> 40 #include <mem.h> 41 #include <stddef.h> 42 #include <stdint.h> 43 #include <usb/usb.h> 44 #include <usbhc_iface.h> 39 #include <ddf/driver.h> 40 #include <usb/request.h> 45 41 46 typedef struct h cd hcd_t;42 typedef struct hw_resource_list_parsed hw_res_list_parsed_t; 47 43 typedef struct bus bus_t; 48 44 typedef struct device device_t; 49 typedef struct usb_transfer_batch usb_transfer_batch_t;50 45 51 typedef int (*schedule_hook_t)(hcd_t *, usb_transfer_batch_t *); 52 typedef void (*interrupt_hook_t)(hcd_t *, uint32_t); 53 typedef int (*status_hook_t)(hcd_t *, uint32_t *); 46 /* Treat this header as read-only in driver code. 47 * It could be opaque, but why to complicate matters. 48 */ 49 typedef struct hc_device { 50 /* Bus instance */ 51 bus_t *bus; 54 52 55 typedef struct { 56 /** Transfer scheduling, implement in device driver. */ 57 schedule_hook_t schedule; 58 /** Hook to be called on device interrupt, passes ARG1 */ 59 interrupt_hook_t irq_hook; 60 /** Periodic polling hook */ 61 status_hook_t status_hook; 62 } hcd_ops_t; 53 /* Managed DDF device */ 54 ddf_dev_t *ddf_dev; 63 55 64 /** Generic host controller driver structure. */ 65 struct hcd { 66 /** Endpoint manager. */ 67 bus_t *bus; 56 /* Control function */ 57 ddf_fun_t *ctl_fun; 58 59 /* Result of enabling HW IRQs */ 60 int irq_cap; 68 61 69 62 /** Interrupt replacement fibril */ 70 63 fid_t polling_fibril; 71 64 72 /* * Driver implementation*/73 hcd_ops_t ops;65 /* This structure is meant to be extended by driver code. */ 66 } hc_device_t; 74 67 75 /** Device specific driver data. */ 76 void * driver_data; 77 }; 68 typedef struct hc_driver { 69 const char *name; 78 70 79 extern void hcd_init(hcd_t *); 71 /** Size of the device data to be allocated, and passed as the 72 * hc_device_t. */ 73 size_t hc_device_size; 80 74 81 static inline void hcd_set_implementation(hcd_t *hcd, void *data, 82 const hcd_ops_t *ops, bus_t *bus) 83 { 84 assert(hcd); 85 if (ops) { 86 hcd->driver_data = data; 87 hcd->ops = *ops; 88 hcd->bus = bus; 89 } else { 90 memset(&hcd->ops, 0, sizeof(hcd->ops)); 91 } 75 /** Initialize device structures. */ 76 int (*hc_add)(hc_device_t *, const hw_res_list_parsed_t *); 77 78 /** Generate IRQ code to handle interrupts. */ 79 int (*irq_code_gen)(irq_code_t *, hc_device_t *, const hw_res_list_parsed_t *); 80 81 /** Claim device from BIOS. */ 82 int (*claim)(hc_device_t *); 83 84 /** Start the host controller. */ 85 int (*start)(hc_device_t *); 86 87 /** Setup the virtual roothub. */ 88 int (*setup_root_hub)(hc_device_t *); 89 90 /** Stop the host controller (after start has been called) */ 91 int (*stop)(hc_device_t *); 92 93 /** HC was asked to be removed (after hc_add has been called) */ 94 int (*hc_remove)(hc_device_t *); 95 96 /** HC is gone. */ 97 int (*hc_gone)(hc_device_t *); 98 } hc_driver_t; 99 100 /* Drivers should call this before leaving hc_add */ 101 static inline void hc_device_setup(hc_device_t *hcd, bus_t *bus) { 102 hcd->bus = bus; 92 103 } 93 104 94 static inline void * hcd_get_driver_data(hcd_t *hcd)105 static inline hc_device_t *dev_to_hcd(ddf_dev_t *dev) 95 106 { 96 assert(hcd); 97 return hcd->driver_data; 107 return ddf_dev_data_get(dev); 98 108 } 99 109 100 extern int hcd_get_ep0_max_packet_size(uint16_t *, hcd_t *, device_t *); 110 int hc_driver_main(const hc_driver_t *); 111 112 /* TODO: These are a kind of utility functions, they should probably go 113 * somewhere else. 114 */ 115 extern int hcd_get_ep0_max_packet_size(uint16_t *, bus_t *, device_t *); 101 116 extern void hcd_setup_device_tt(device_t *); 102 103 extern int hcd_send_batch(hcd_t *, device_t *, usb_target_t,104 usb_direction_t direction, char *, size_t, uint64_t,105 usbhc_iface_transfer_callback_t, void *, const char *);106 107 extern ssize_t hcd_send_batch_sync(hcd_t *, device_t *, usb_target_t,108 usb_direction_t direction, char *, size_t, uint64_t,109 const char *);110 117 111 118 /** How many toggles need to be reset */ … … 116 123 } toggle_reset_mode_t; 117 124 125 extern toggle_reset_mode_t hcd_get_request_toggle_reset_mode( 126 const usb_device_request_setup_packet_t *request); 127 118 128 #endif 119 129 -
uspace/lib/usbhost/include/usb/host/usb2_bus.h
r1ea0bbf r32fb6bce 66 66 extern const bus_ops_t usb2_bus_ops; 67 67 68 extern int usb2_bus_init(usb2_bus_t *, hcd_t *,size_t);68 extern int usb2_bus_init(usb2_bus_t *, size_t); 69 69 70 70 #endif -
uspace/lib/usbhost/src/bus.c
r1ea0bbf r32fb6bce 46 46 * Initializes the bus structure. 47 47 */ 48 void bus_init(bus_t *bus, hcd_t *hcd, size_t device_size) 49 { 50 assert(bus); 51 assert(hcd); 48 void bus_init(bus_t *bus, size_t device_size) 49 { 50 assert(bus); 52 51 assert(device_size >= sizeof(device_t)); 53 52 memset(bus, 0, sizeof(bus_t)); 54 53 55 54 fibril_mutex_initialize(&bus->guard); 56 bus->hcd = hcd;57 55 bus->device_size = device_size; 58 56 } … … 61 59 { 62 60 assert(bus); 63 assert(bus->hcd);64 61 65 62 memset(dev, 0, sizeof(*dev)); … … 258 255 } 259 256 257 /** Prepare generic usb_transfer_batch and schedule it. 258 * @param device Device for which to send the batch 259 * @param target address and endpoint number. 260 * @param setup_data Data to use in setup stage (Control communication type) 261 * @param in Callback for device to host communication. 262 * @param out Callback for host to device communication. 263 * @param arg Callback parameter. 264 * @param name Communication identifier (for nicer output). 265 * @return Error code. 266 */ 267 int bus_device_send_batch(device_t *device, usb_target_t target, 268 usb_direction_t direction, char *data, size_t size, uint64_t setup_data, 269 usbhc_iface_transfer_callback_t on_complete, void *arg, const char *name) 270 { 271 assert(device->address == target.address); 272 273 /* Temporary reference */ 274 endpoint_t *ep = bus_find_endpoint(device, target, direction); 275 if (ep == NULL) { 276 usb_log_error("Endpoint(%d:%d) not registered for %s.\n", 277 device->address, target.endpoint, name); 278 return ENOENT; 279 } 280 281 assert(ep->device == device); 282 283 const int err = endpoint_send_batch(ep, target, direction, data, size, setup_data, 284 on_complete, arg, name); 285 286 /* Temporary reference */ 287 endpoint_del_ref(ep); 288 289 return err; 290 } 291 292 typedef struct { 293 fibril_mutex_t done_mtx; 294 fibril_condvar_t done_cv; 295 unsigned done; 296 297 size_t transfered_size; 298 int error; 299 } sync_data_t; 300 301 static int sync_transfer_complete(void *arg, int error, size_t transfered_size) 302 { 303 sync_data_t *d = arg; 304 assert(d); 305 d->transfered_size = transfered_size; 306 d->error = error; 307 fibril_mutex_lock(&d->done_mtx); 308 d->done = 1; 309 fibril_condvar_broadcast(&d->done_cv); 310 fibril_mutex_unlock(&d->done_mtx); 311 return EOK; 312 } 313 314 ssize_t bus_device_send_batch_sync(device_t *device, usb_target_t target, 315 usb_direction_t direction, char *data, size_t size, uint64_t setup_data, 316 const char *name) 317 { 318 sync_data_t sd = { .done = 0 }; 319 fibril_mutex_initialize(&sd.done_mtx); 320 fibril_condvar_initialize(&sd.done_cv); 321 322 const int ret = bus_device_send_batch(device, target, direction, 323 data, size, setup_data, 324 sync_transfer_complete, &sd, name); 325 if (ret != EOK) 326 return ret; 327 328 fibril_mutex_lock(&sd.done_mtx); 329 while (!sd.done) { 330 fibril_condvar_wait_timeout(&sd.done_cv, &sd.done_mtx, 3000000); 331 if (!sd.done) 332 usb_log_debug2("Still waiting..."); 333 } 334 fibril_mutex_unlock(&sd.done_mtx); 335 336 return (sd.error == EOK) 337 ? (ssize_t) sd.transfered_size 338 : (ssize_t) sd.error; 339 } 340 260 341 /** 261 342 * @} -
uspace/lib/usbhost/src/ddf_helpers.c
r1ea0bbf r32fb6bce 53 53 #include "ddf_helpers.h" 54 54 55 typedef struct hc_dev { 56 ddf_fun_t *ctl_fun; 57 hcd_t hcd; 58 } hc_dev_t; 59 60 static hc_dev_t *dev_to_hc_dev(ddf_dev_t *dev) 61 { 62 return ddf_dev_data_get(dev); 63 } 64 65 hcd_t *dev_to_hcd(ddf_dev_t *dev) 66 { 67 hc_dev_t *hc_dev = dev_to_hc_dev(dev); 68 if (!hc_dev) { 69 usb_log_error("Invalid HCD device.\n"); 70 return NULL; 71 } 72 return &hc_dev->hcd; 73 } 74 75 76 static int hcd_ddf_new_device(hcd_t *hcd, ddf_dev_t *hc, device_t *hub_dev, unsigned port); 55 56 static int hcd_ddf_new_device(hc_device_t *hcd, ddf_dev_t *hc, device_t *hub_dev, unsigned port); 77 57 static int hcd_ddf_remove_device(ddf_dev_t *device, device_t *hub, unsigned port); 78 58 … … 89 69 { 90 70 assert(fun); 91 hc d_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));71 hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 92 72 device_t *dev = ddf_fun_data_get(fun); 93 73 assert(hcd); … … 113 93 { 114 94 assert(fun); 115 hc d_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));95 hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 116 96 device_t *dev = ddf_fun_data_get(fun); 117 97 assert(hcd); … … 138 118 { 139 119 assert(fun); 140 hc d_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));120 hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 141 121 device_t *dev = ddf_fun_data_get(fun); 142 122 assert(hcd); … … 152 132 { 153 133 assert(fun); 154 hc d_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));134 hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 155 135 device_t *dev = ddf_fun_data_get(fun); 156 136 assert(hcd); … … 167 147 ddf_dev_t *hc = ddf_fun_get_dev(fun); 168 148 assert(hc); 169 hc d_t *hcd = dev_to_hcd(hc);149 hc_device_t *hcd = dev_to_hcd(hc); 170 150 assert(hcd); 171 151 device_t *hub = ddf_fun_data_get(fun); … … 218 198 { 219 199 assert(fun); 220 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));221 200 device_t *dev = ddf_fun_data_get(fun); 222 201 assert(dev); … … 224 203 target.address = dev->address; 225 204 226 return hcd_send_batch(hcd,dev, target, USB_DIRECTION_IN,205 return bus_device_send_batch(dev, target, USB_DIRECTION_IN, 227 206 data, size, setup_data, 228 207 callback, arg, "READ"); … … 244 223 { 245 224 assert(fun); 246 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));247 225 device_t *dev = ddf_fun_data_get(fun); 248 226 assert(dev); … … 250 228 target.address = dev->address; 251 229 252 return hcd_send_batch(hcd,dev, target, USB_DIRECTION_OUT,230 return bus_device_send_batch(dev, target, USB_DIRECTION_OUT, 253 231 (char *) data, size, setup_data, 254 232 callback, arg, "WRITE"); … … 337 315 assert(device); 338 316 339 hc d_t *hcd = dev_to_hcd(device);317 hc_device_t *hcd = dev_to_hcd(device); 340 318 assert(hcd); 341 319 assert(hcd->bus); 342 343 hc_dev_t *hc_dev = dev_to_hc_dev(device);344 assert(hc_dev);345 320 346 321 fibril_mutex_lock(&hub->guard); … … 374 349 } 375 350 376 device_t *hcd_ddf_ device_create(ddf_dev_t *hc, bus_t *bus)351 device_t *hcd_ddf_fun_create(hc_device_t *hc) 377 352 { 378 353 /* Create DDF function for the new device */ 379 ddf_fun_t *fun = ddf_fun_create(hc , fun_inner, NULL);354 ddf_fun_t *fun = ddf_fun_create(hc->ddf_dev, fun_inner, NULL); 380 355 if (!fun) 381 356 return NULL; … … 384 359 385 360 /* Create USB device node for the new device */ 386 device_t *dev = ddf_fun_data_alloc(fun, bus->device_size);361 device_t *dev = ddf_fun_data_alloc(fun, hc->bus->device_size); 387 362 if (!dev) { 388 363 ddf_fun_destroy(fun); … … 390 365 } 391 366 392 bus_device_init(dev, bus);367 bus_device_init(dev, hc->bus); 393 368 dev->fun = fun; 394 369 return dev; 395 370 } 396 371 397 void hcd_ddf_ device_destroy(device_t *dev)372 void hcd_ddf_fun_destroy(device_t *dev) 398 373 { 399 374 assert(dev); … … 402 377 } 403 378 404 int hcd_d df_device_explore(device_t *device)379 int hcd_device_explore(device_t *device) 405 380 { 406 381 int err; … … 421 396 usb_log_debug("Device(%d): Requesting full device descriptor.", 422 397 device->address); 423 ssize_t got = hcd_send_batch_sync(device->bus->hcd,device, control_ep, USB_DIRECTION_IN,398 ssize_t got = bus_device_send_batch_sync(device, control_ep, USB_DIRECTION_IN, 424 399 (char *) &desc, sizeof(desc), *(uint64_t *)&get_device_desc, 425 400 "read device descriptor"); … … 447 422 } 448 423 449 int hcd_ddf_device_online(ddf_fun_t *fun) 450 { 451 assert(fun); 452 453 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 454 device_t *dev = ddf_fun_data_get(fun); 455 assert(dev); 456 assert(hcd->bus); 457 458 usb_log_info("Device(%d): Requested to be brought online.", dev->address); 459 460 return bus_device_online(dev); 461 } 462 463 int hcd_ddf_device_offline(ddf_fun_t *fun) 464 { 465 assert(fun); 466 467 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 468 device_t *dev = ddf_fun_data_get(fun); 469 assert(dev); 470 assert(hcd->bus); 471 472 usb_log_info("Device(%d): Requested to be taken offline.", dev->address); 473 474 return bus_device_offline(dev); 475 } 476 477 static int hcd_ddf_new_device(hcd_t *hcd, ddf_dev_t *hc, device_t *hub, unsigned port) 424 static int hcd_ddf_new_device(hc_device_t *hcd, ddf_dev_t *hc, device_t *hub, unsigned port) 478 425 { 479 426 int err; … … 483 430 assert(hc); 484 431 485 device_t *dev = hcd_ddf_ device_create(hc, hcd->bus);432 device_t *dev = hcd_ddf_fun_create(hcd); 486 433 if (!dev) { 487 434 usb_log_error("Failed to create USB device function."); … … 516 463 517 464 err_usb_dev: 518 hcd_ddf_ device_destroy(dev);465 hcd_ddf_fun_destroy(dev); 519 466 return err; 520 467 } … … 525 472 * @return Error code 526 473 */ 527 int hcd_setup_virtual_root_hub(hc d_t *hcd, ddf_dev_t *hc)474 int hcd_setup_virtual_root_hub(hc_device_t *hcd) 528 475 { 529 476 int err; 530 477 531 assert(hc); 532 assert(hcd); 533 assert(hcd->bus); 478 assert(hcd); 534 479 535 480 if ((err = bus_reserve_default_address(hcd->bus, USB_SPEED_MAX))) { … … 538 483 } 539 484 540 device_t *dev = hcd_ddf_ device_create(hc, hcd->bus);485 device_t *dev = hcd_ddf_fun_create(hcd); 541 486 if (!dev) { 542 487 usb_log_error("Failed to create function for the root hub."); … … 561 506 562 507 err_usb_dev: 563 hcd_ddf_ device_destroy(dev);508 hcd_ddf_fun_destroy(dev); 564 509 err_default_address: 565 510 bus_release_default_address(hcd->bus); … … 577 522 * This function does all the ddf work for hc driver. 578 523 */ 579 int hcd_ddf_setup_hc(ddf_dev_t *device )524 int hcd_ddf_setup_hc(ddf_dev_t *device, size_t size) 580 525 { 581 526 assert(device); 582 527 583 hc_dev _t *instance = ddf_dev_data_alloc(device, sizeof(hc_dev_t));528 hc_device_t *instance = ddf_dev_data_alloc(device, size); 584 529 if (instance == NULL) { 585 530 usb_log_error("Failed to allocate HCD ddf structure.\n"); 586 531 return ENOMEM; 587 532 } 588 hcd_init(&instance->hcd);533 instance->ddf_dev = device; 589 534 590 535 int ret = ENOMEM; … … 618 563 } 619 564 620 void hcd_ddf_clean_hc(ddf_dev_t *device) 621 { 622 assert(device); 623 hc_dev_t *hc = dev_to_hc_dev(device); 624 assert(hc); 625 const int ret = ddf_fun_unbind(hc->ctl_fun); 626 if (ret == EOK) 627 ddf_fun_destroy(hc->ctl_fun); 628 } 629 630 //TODO: Cache parent session in HCD 565 void hcd_ddf_clean_hc(hc_device_t *hcd) 566 { 567 if (ddf_fun_unbind(hcd->ctl_fun) == EOK) 568 ddf_fun_destroy(hcd->ctl_fun); 569 } 570 631 571 /** Call the parent driver with a request to enable interrupt 632 572 * … … 635 575 * @return Error code. 636 576 */ 637 int hcd_ddf_enable_interrupt( ddf_dev_t *device, int inum)638 { 639 async_sess_t *parent_sess = ddf_dev_parent_sess_get( device);577 int hcd_ddf_enable_interrupt(hc_device_t *hcd, int inum) 578 { 579 async_sess_t *parent_sess = ddf_dev_parent_sess_get(hcd->ddf_dev); 640 580 if (parent_sess == NULL) 641 581 return EIO; … … 644 584 } 645 585 646 //TODO: Cache parent session in HCD 647 int hcd_ddf_get_registers(ddf_dev_t *device, hw_res_list_parsed_t *hw_res) 648 { 649 async_sess_t *parent_sess = ddf_dev_parent_sess_get(device); 586 int hcd_ddf_get_registers(hc_device_t *hcd, hw_res_list_parsed_t *hw_res) 587 { 588 async_sess_t *parent_sess = ddf_dev_parent_sess_get(hcd->ddf_dev); 650 589 if (parent_sess == NULL) 651 590 return EIO; … … 658 597 } 659 598 660 // TODO: move this someplace else661 static inline void irq_code_clean(irq_code_t *code)662 {663 if (code) {664 free(code->ranges);665 free(code->cmds);666 code->ranges = NULL;667 code->cmds = NULL;668 code->rangecount = 0;669 code->cmdcount = 0;670 }671 }672 673 /** Register interrupt handler674 *675 * @param[in] device Host controller DDF device676 * @param[in] regs Register range677 * @param[in] irq Interrupt number678 * @paran[in] handler Interrupt handler679 * @param[in] gen_irq_code IRQ code generator.680 *681 * @return IRQ capability handle on success.682 * @return Negative error code.683 */684 int hcd_ddf_setup_interrupts(ddf_dev_t *device,685 const hw_res_list_parsed_t *hw_res,686 interrupt_handler_t handler,687 irq_code_gen_t gen_irq_code)688 {689 assert(device);690 691 hcd_t *hcd = dev_to_hcd(device);692 693 if (!handler || !gen_irq_code)694 return ENOTSUP;695 696 irq_code_t irq_code = {0};697 698 const int irq = gen_irq_code(&irq_code, hcd, hw_res);699 if (irq < 0) {700 usb_log_error("Failed to generate IRQ code: %s.\n",701 str_error(irq));702 return irq;703 }704 705 /* Register handler to avoid interrupt lockup */706 const int irq_cap = register_interrupt_handler(device, irq, handler,707 &irq_code);708 irq_code_clean(&irq_code);709 if (irq_cap < 0) {710 usb_log_error("Failed to register interrupt handler: %s.\n",711 str_error(irq_cap));712 return irq_cap;713 }714 715 /* Enable interrupts */716 int ret = hcd_ddf_enable_interrupt(device, irq);717 if (ret != EOK) {718 usb_log_error("Failed to enable interrupts: %s.\n",719 str_error(ret));720 unregister_interrupt_handler(device, irq_cap);721 return ret;722 }723 return irq_cap;724 }725 726 /** IRQ handling callback, forward status from call to diver structure.727 *728 * @param[in] dev DDF instance of the device to use.729 * @param[in] iid (Unused).730 * @param[in] call Pointer to the call from kernel.731 */732 void ddf_hcd_gen_irq_handler(ipc_callid_t iid, ipc_call_t *call, ddf_dev_t *dev)733 {734 assert(dev);735 hcd_t *hcd = dev_to_hcd(dev);736 if (!hcd || !hcd->ops.irq_hook) {737 usb_log_error("Interrupt on not yet initialized device.\n");738 return;739 }740 const uint32_t status = IPC_GET_ARG1(*call);741 hcd->ops.irq_hook(hcd, status);742 }743 744 static int interrupt_polling(void *arg)745 {746 hcd_t *hcd = arg;747 assert(hcd);748 if (!hcd->ops.status_hook || !hcd->ops.irq_hook)749 return ENOTSUP;750 uint32_t status = 0;751 while (hcd->ops.status_hook(hcd, &status) == EOK) {752 hcd->ops.irq_hook(hcd, status);753 status = 0;754 /* We should wait 1 frame - 1ms here, but this polling is a755 * lame crutch anyway so don't hog the system. 10ms is still756 * good enough for emergency mode */757 async_usleep(10000);758 }759 return EOK;760 }761 762 /** Initialize hc and rh DDF structures and their respective drivers.763 *764 * @param device DDF instance of the device to use765 * @param speed Maximum supported speed766 * @param bw Available bandwidth (arbitrary units)767 * @param bw_count Bandwidth computing function768 * @param irq_handler IRQ handling function769 * @param gen_irq_code Function to generate IRQ pseudocode770 * (it needs to return used irq number)771 * @param driver_init Function to initialize HC driver772 * @param driver_fini Function to cleanup HC driver773 * @return Error code774 *775 * This function does all the preparatory work for hc and rh drivers:776 * - gets device's hw resources777 * - attempts to enable interrupts778 * - registers interrupt handler779 * - calls driver specific initialization780 * - registers root hub781 */782 int hcd_ddf_add_hc(ddf_dev_t *device, const ddf_hc_driver_t *driver)783 {784 assert(driver);785 786 int ret = EOK;787 788 hw_res_list_parsed_t hw_res;789 ret = hcd_ddf_get_registers(device, &hw_res);790 if (ret != EOK) {791 usb_log_error("Failed to get register memory addresses "792 "for `%s': %s.\n", ddf_dev_get_name(device),793 str_error(ret));794 return ret;795 }796 797 ret = hcd_ddf_setup_hc(device);798 if (ret != EOK) {799 usb_log_error("Failed to setup generic HCD.\n");800 goto err_hw_res;801 }802 803 hcd_t *hcd = dev_to_hcd(device);804 805 if (driver->init)806 ret = driver->init(hcd, &hw_res, device);807 if (ret != EOK) {808 usb_log_error("Failed to init HCD.\n");809 goto err_hcd;810 }811 812 /* Setup interrupts */813 interrupt_handler_t *irq_handler =814 driver->irq_handler ? driver->irq_handler : ddf_hcd_gen_irq_handler;815 const int irq_cap = hcd_ddf_setup_interrupts(device, &hw_res,816 irq_handler, driver->irq_code_gen);817 bool irqs_enabled = !(irq_cap < 0);818 if (irqs_enabled) {819 usb_log_debug("Hw interrupts enabled.\n");820 }821 822 /* Claim the device from BIOS */823 if (driver->claim)824 ret = driver->claim(hcd, device);825 if (ret != EOK) {826 usb_log_error("Failed to claim `%s' for driver `%s': %s",827 ddf_dev_get_name(device), driver->name, str_error(ret));828 goto err_irq;829 }830 831 /* Start hw driver */832 if (driver->start)833 ret = driver->start(hcd, irqs_enabled);834 if (ret != EOK) {835 usb_log_error("Failed to start HCD: %s.\n", str_error(ret));836 goto err_irq;837 }838 839 /* Need working irq replacement to setup root hub */840 if (!irqs_enabled && hcd->ops.status_hook) {841 hcd->polling_fibril = fibril_create(interrupt_polling, hcd);842 if (hcd->polling_fibril == 0) {843 usb_log_error("Failed to create polling fibril\n");844 ret = ENOMEM;845 goto err_started;846 }847 fibril_add_ready(hcd->polling_fibril);848 usb_log_warning("Failed to enable interrupts: %s."849 " Falling back to polling.\n", str_error(irq_cap));850 }851 852 /*853 * Creating root hub registers a new USB device so HC854 * needs to be ready at this time.855 */856 if (driver->setup_root_hub)857 ret = driver->setup_root_hub(hcd, device);858 if (ret != EOK) {859 usb_log_error("Failed to setup HC root hub: %s.\n",860 str_error(ret));861 goto err_polling;862 }863 864 usb_log_info("Controlling new `%s' device `%s'.\n",865 driver->name, ddf_dev_get_name(device));866 return EOK;867 868 err_polling:869 // TODO: Stop the polling fibril (refactor the interrupt_polling func)870 //871 err_started:872 if (driver->stop)873 driver->stop(hcd);874 err_irq:875 unregister_interrupt_handler(device, irq_cap);876 if (driver->fini)877 driver->fini(hcd);878 err_hcd:879 hcd_ddf_clean_hc(device);880 err_hw_res:881 hw_res_list_parsed_clean(&hw_res);882 return ret;883 }884 885 599 /** 886 600 * @} -
uspace/lib/usbhost/src/endpoint.c
r1ea0bbf r32fb6bce 39 39 #include <mem.h> 40 40 #include <stdlib.h> 41 #include <str_error.h> 42 #include <usb/debug.h> 43 #include <usb/host/hcd.h> 41 44 42 45 #include "usb_transfer_batch.h" … … 187 190 } 188 191 192 /** Prepare generic usb_transfer_batch and schedule it. 193 * @param ep Endpoint for which the batch shall be created. 194 * @param target address and endpoint number. 195 * @param setup_data Data to use in setup stage (Control communication type) 196 * @param in Callback for device to host communication. 197 * @param out Callback for host to device communication. 198 * @param arg Callback parameter. 199 * @param name Communication identifier (for nicer output). 200 * @return Error code. 201 */ 202 int endpoint_send_batch(endpoint_t *ep, usb_target_t target, 203 usb_direction_t direction, char *data, size_t size, uint64_t setup_data, 204 usbhc_iface_transfer_callback_t on_complete, void *arg, const char *name) 205 { 206 usb_log_debug2("%s %d:%d %zu(%zu).\n", 207 name, target.address, target.endpoint, size, ep->max_packet_size); 208 209 bus_t *bus = endpoint_get_bus(ep); 210 const bus_ops_t *ops = BUS_OPS_LOOKUP(bus->ops, batch_schedule); 211 if (!ops) { 212 usb_log_error("HCD does not implement scheduler.\n"); 213 return ENOTSUP; 214 } 215 216 const size_t bw = endpoint_count_bw(ep, size); 217 /* Check if we have enough bandwidth reserved */ 218 if (ep->bandwidth < bw) { 219 usb_log_error("Endpoint(%d:%d) %s needs %zu bw " 220 "but only %zu is reserved.\n", 221 ep->device->address, ep->endpoint, name, bw, ep->bandwidth); 222 return ENOSPC; 223 } 224 225 usb_transfer_batch_t *batch = usb_transfer_batch_create(ep); 226 if (!batch) { 227 usb_log_error("Failed to create transfer batch.\n"); 228 return ENOMEM; 229 } 230 231 batch->target = target; 232 batch->buffer = data; 233 batch->buffer_size = size; 234 batch->setup.packed = setup_data; 235 batch->dir = direction; 236 batch->on_complete = on_complete; 237 batch->on_complete_data = arg; 238 239 /* Check for commands that reset toggle bit */ 240 if (ep->transfer_type == USB_TRANSFER_CONTROL) 241 batch->toggle_reset_mode 242 = hcd_get_request_toggle_reset_mode(&batch->setup.packet); 243 244 const int ret = ops->batch_schedule(batch); 245 if (ret != EOK) { 246 usb_log_warning("Batch %p failed to schedule: %s", batch, str_error(ret)); 247 usb_transfer_batch_destroy(batch); 248 } 249 250 return ret; 251 } 252 189 253 /** 190 254 * @} -
uspace/lib/usbhost/src/hcd.c
r1ea0bbf r32fb6bce 36 36 #include <assert.h> 37 37 #include <async.h> 38 #include <ddf/interrupt.h> 38 39 #include <errno.h> 39 40 #include <macros.h> … … 45 46 46 47 #include "bus.h" 48 #include "ddf_helpers.h" 47 49 #include "endpoint.h" 48 50 #include "usb_transfer_batch.h" … … 50 52 #include "hcd.h" 51 53 52 53 /** Initialize hcd_t structure. 54 * Initializes device and endpoint managers. Sets data and hook pointer to NULL. 55 * 56 * @param hcd hcd_t structure to initialize, non-null. 57 * @param max_speed Maximum supported USB speed (full, high). 58 * @param bandwidth Available bandwidth, passed to endpoint manager. 59 * @param bw_count Bandwidth compute function, passed to endpoint manager. 60 */ 61 void hcd_init(hcd_t *hcd) { 54 int hc_dev_add(ddf_dev_t *); 55 int hc_dev_remove(ddf_dev_t *); 56 int hc_dev_gone(ddf_dev_t *); 57 int hc_fun_online(ddf_fun_t *); 58 int hc_fun_offline(ddf_fun_t *); 59 60 static driver_ops_t hc_driver_ops = { 61 .dev_add = hc_dev_add, 62 .dev_remove = hc_dev_remove, 63 .dev_gone = hc_dev_gone, 64 .fun_online = hc_fun_offline, 65 .fun_offline = hc_fun_offline, 66 }; 67 68 static const hc_driver_t *hc_driver; 69 70 int hc_driver_main(const hc_driver_t *driver) 71 { 72 driver_t ddf_driver = { 73 .name = driver->name, 74 .driver_ops = &hc_driver_ops, 75 }; 76 77 /* Remember ops to call. */ 78 hc_driver = driver; 79 80 return ddf_driver_main(&ddf_driver); 81 } 82 83 /** IRQ handling callback, forward status from call to diver structure. 84 * 85 * @param[in] dev DDF instance of the device to use. 86 * @param[in] iid (Unused). 87 * @param[in] call Pointer to the call from kernel. 88 */ 89 static void irq_handler(ipc_callid_t iid, ipc_call_t *call, ddf_dev_t *dev) 90 { 91 assert(dev); 92 hc_device_t *hcd = dev_to_hcd(dev); 93 94 const bus_ops_t *ops = BUS_OPS_LOOKUP(hcd->bus->ops, interrupt); 95 assert(ops); 96 97 const uint32_t status = IPC_GET_ARG1(*call); 98 ops->interrupt(hcd->bus, status); 99 } 100 101 /** Worker for the HW interrupt replacement fibril. 102 */ 103 static int interrupt_polling(void *arg) 104 { 105 hc_device_t *hcd = arg; 62 106 assert(hcd); 63 64 hcd_set_implementation(hcd, NULL, NULL, NULL); 107 bus_t *bus = hcd->bus; 108 109 const bus_ops_t *interrupt_ops = BUS_OPS_LOOKUP(bus->ops, interrupt); 110 const bus_ops_t *status_ops = BUS_OPS_LOOKUP(bus->ops, status); 111 if (!interrupt_ops || !status_ops) 112 return ENOTSUP; 113 114 uint32_t status = 0; 115 while (status_ops->status(bus, &status) == EOK) { 116 interrupt_ops->interrupt(bus, status); 117 status = 0; 118 /* We should wait 1 frame - 1ms here, but this polling is a 119 * lame crutch anyway so don't hog the system. 10ms is still 120 * good enough for emergency mode */ 121 async_usleep(10000); 122 } 123 return EOK; 124 } 125 126 static inline void irq_code_clean(irq_code_t *code) 127 { 128 if (code) { 129 free(code->ranges); 130 free(code->cmds); 131 code->ranges = NULL; 132 code->cmds = NULL; 133 code->rangecount = 0; 134 code->cmdcount = 0; 135 } 136 } 137 138 /** Register interrupt handler 139 * 140 * @param[in] device Host controller DDF device 141 * @param[in] regs Register range 142 * @param[in] irq Interrupt number 143 * @paran[in] handler Interrupt handler 144 * @param[in] gen_irq_code IRQ code generator. 145 * 146 * @return IRQ capability handle on success. 147 * @return Negative error code. 148 */ 149 static int hcd_ddf_setup_interrupts(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res) 150 { 151 assert(hcd); 152 irq_code_t irq_code = {0}; 153 154 if (!hc_driver->irq_code_gen) 155 return ENOTSUP; 156 157 const int irq = hc_driver->irq_code_gen(&irq_code, hcd, hw_res); 158 if (irq < 0) { 159 usb_log_error("Failed to generate IRQ code: %s.\n", 160 str_error(irq)); 161 return irq; 162 } 163 164 /* Register handler to avoid interrupt lockup */ 165 const int irq_cap = register_interrupt_handler(hcd->ddf_dev, irq, irq_handler, &irq_code); 166 irq_code_clean(&irq_code); 167 if (irq_cap < 0) { 168 usb_log_error("Failed to register interrupt handler: %s.\n", 169 str_error(irq_cap)); 170 return irq_cap; 171 } 172 173 /* Enable interrupts */ 174 int ret = hcd_ddf_enable_interrupt(hcd, irq); 175 if (ret != EOK) { 176 usb_log_error("Failed to enable interrupts: %s.\n", 177 str_error(ret)); 178 unregister_interrupt_handler(hcd->ddf_dev, irq_cap); 179 return ret; 180 } 181 return irq_cap; 182 } 183 184 /** Initialize HC in memory of the driver. 185 * 186 * @param device DDF instance of the device to use 187 * @return Error code 188 * 189 * This function does all the preparatory work for hc and rh drivers: 190 * - gets device's hw resources 191 * - attempts to enable interrupts 192 * - registers interrupt handler 193 * - calls driver specific initialization 194 * - registers root hub 195 */ 196 int hc_dev_add(ddf_dev_t *device) 197 { 198 int ret = EOK; 199 assert(device); 200 201 if (!hc_driver->hc_add) { 202 usb_log_error("Driver '%s' does not support adding devices.", hc_driver->name); 203 return ENOTSUP; 204 } 205 206 ret = hcd_ddf_setup_hc(device, hc_driver->hc_device_size); 207 if (ret != EOK) { 208 usb_log_error("Failed to setup HC device.\n"); 209 return ret; 210 } 211 212 hc_device_t *hcd = dev_to_hcd(device); 213 214 hw_res_list_parsed_t hw_res; 215 ret = hcd_ddf_get_registers(hcd, &hw_res); 216 if (ret != EOK) { 217 usb_log_error("Failed to get register memory addresses " 218 "for `%s': %s.\n", ddf_dev_get_name(device), 219 str_error(ret)); 220 goto err_hcd; 221 } 222 223 ret = hc_driver->hc_add(hcd, &hw_res); 224 if (ret != EOK) { 225 usb_log_error("Failed to init HCD.\n"); 226 goto err_hw_res; 227 } 228 229 assert(hcd->bus); 230 231 /* Setup interrupts */ 232 hcd->irq_cap = hcd_ddf_setup_interrupts(hcd, &hw_res); 233 if (hcd->irq_cap >= 0) { 234 usb_log_debug("Hw interrupts enabled.\n"); 235 } 236 237 /* Claim the device from BIOS */ 238 if (hc_driver->claim) 239 ret = hc_driver->claim(hcd); 240 if (ret != EOK) { 241 usb_log_error("Failed to claim `%s' for `%s': %s", 242 ddf_dev_get_name(device), hc_driver->name, str_error(ret)); 243 goto err_irq; 244 } 245 246 /* Start hw */ 247 if (hc_driver->start) 248 ret = hc_driver->start(hcd); 249 if (ret != EOK) { 250 usb_log_error("Failed to start HCD: %s.\n", str_error(ret)); 251 goto err_irq; 252 } 253 254 const bus_ops_t *ops = BUS_OPS_LOOKUP(hcd->bus->ops, status); 255 256 /* Need working irq replacement to setup root hub */ 257 if (hcd->irq_cap < 0 && ops) { 258 hcd->polling_fibril = fibril_create(interrupt_polling, hcd->bus); 259 if (!hcd->polling_fibril) { 260 usb_log_error("Failed to create polling fibril\n"); 261 ret = ENOMEM; 262 goto err_started; 263 } 264 fibril_add_ready(hcd->polling_fibril); 265 usb_log_warning("Failed to enable interrupts: %s." 266 " Falling back to polling.\n", str_error(hcd->irq_cap)); 267 } 268 269 /* 270 * Creating root hub registers a new USB device so HC 271 * needs to be ready at this time. 272 */ 273 if (hc_driver->setup_root_hub) 274 ret = hc_driver->setup_root_hub(hcd); 275 if (ret != EOK) { 276 usb_log_error("Failed to setup HC root hub: %s.\n", 277 str_error(ret)); 278 goto err_polling; 279 } 280 281 usb_log_info("Controlling new `%s' device `%s'.\n", 282 hc_driver->name, ddf_dev_get_name(device)); 283 return EOK; 284 285 err_polling: 286 // TODO: Stop the polling fibril (refactor the interrupt_polling func) 287 // 288 err_started: 289 if (hc_driver->stop) 290 hc_driver->stop(hcd); 291 err_irq: 292 unregister_interrupt_handler(device, hcd->irq_cap); 293 if (hc_driver->hc_remove) 294 hc_driver->hc_remove(hcd); 295 err_hw_res: 296 hw_res_list_parsed_clean(&hw_res); 297 err_hcd: 298 hcd_ddf_clean_hc(hcd); 299 return ret; 300 } 301 302 int hc_dev_remove(ddf_dev_t *dev) 303 { 304 int err; 305 hc_device_t *hcd = dev_to_hcd(dev); 306 307 if (hc_driver->stop) 308 if ((err = hc_driver->stop(hcd))) 309 return err; 310 311 unregister_interrupt_handler(dev, hcd->irq_cap); 312 313 if (hc_driver->hc_remove) 314 if ((err = hc_driver->hc_remove(hcd))) 315 return err; 316 317 hcd_ddf_clean_hc(hcd); 318 319 // TODO probably not complete 320 321 return EOK; 322 } 323 324 int hc_dev_gone(ddf_dev_t *dev) 325 { 326 int err = ENOTSUP; 327 hc_device_t *hcd = dev_to_hcd(dev); 328 329 if (hc_driver->hc_gone) 330 err = hc_driver->hc_gone(hcd); 331 332 hcd_ddf_clean_hc(hcd); 333 334 return err; 335 } 336 337 int hc_fun_online(ddf_fun_t *fun) 338 { 339 assert(fun); 340 341 device_t *dev = ddf_fun_data_get(fun); 342 assert(dev); 343 344 usb_log_info("Device(%d): Requested to be brought online.", dev->address); 345 return bus_device_online(dev); 346 } 347 348 int hc_fun_offline(ddf_fun_t *fun) 349 { 350 assert(fun); 351 352 device_t *dev = ddf_fun_data_get(fun); 353 assert(dev); 354 355 usb_log_info("Device(%d): Requested to be taken offline.", dev->address); 356 return bus_device_offline(dev); 65 357 } 66 358 … … 72 364 * @return Max packet size for EP 0 73 365 */ 74 int hcd_get_ep0_max_packet_size(uint16_t *mps, hcd_t *hcd, device_t *dev)366 int hcd_get_ep0_max_packet_size(uint16_t *mps, bus_t *bus, device_t *dev) 75 367 { 76 368 assert(mps); … … 97 389 98 390 usb_log_debug("Requesting first 8B of device descriptor to determine MPS."); 99 ssize_t got = hcd_send_batch_sync(hcd,dev, control_ep, USB_DIRECTION_IN,391 ssize_t got = bus_device_send_batch_sync(dev, control_ep, USB_DIRECTION_IN, 100 392 (char *) &desc, CTRL_PIPE_MIN_PACKET_SIZE, *(uint64_t *)&get_device_desc_8, 101 393 "read first 8 bytes of dev descriptor"); … … 156 448 * 157 449 */ 158 statictoggle_reset_mode_t hcd_get_request_toggle_reset_mode(450 toggle_reset_mode_t hcd_get_request_toggle_reset_mode( 159 451 const usb_device_request_setup_packet_t *request) 160 452 { … … 186 478 } 187 479 188 /** Prepare generic usb_transfer_batch and schedule it.189 * @param hcd Host controller driver.190 * @param target address and endpoint number.191 * @param setup_data Data to use in setup stage (Control communication type)192 * @param in Callback for device to host communication.193 * @param out Callback for host to device communication.194 * @param arg Callback parameter.195 * @param name Communication identifier (for nicer output).196 * @return Error code.197 */198 int hcd_send_batch(hcd_t *hcd, device_t *device, usb_target_t target,199 usb_direction_t direction, char *data, size_t size, uint64_t setup_data,200 usbhc_iface_transfer_callback_t on_complete, void *arg, const char *name)201 {202 assert(hcd);203 assert(device->address == target.address);204 205 if (!hcd->ops.schedule) {206 usb_log_error("HCD does not implement scheduler.\n");207 return ENOTSUP;208 }209 210 endpoint_t *ep = bus_find_endpoint(device, target, direction);211 if (ep == NULL) {212 usb_log_error("Endpoint(%d:%d) not registered for %s.\n",213 device->address, target.endpoint, name);214 return ENOENT;215 }216 217 // TODO cut here aka provide helper to call with instance of endpoint_t in hand218 assert(ep->device == device);219 220 usb_log_debug2("%s %d:%d %zu(%zu).\n",221 name, target.address, target.endpoint, size, ep->max_packet_size);222 223 const size_t bw = endpoint_count_bw(ep, size);224 /* Check if we have enough bandwidth reserved */225 if (ep->bandwidth < bw) {226 usb_log_error("Endpoint(%d:%d) %s needs %zu bw "227 "but only %zu is reserved.\n",228 device->address, ep->endpoint, name, bw, ep->bandwidth);229 return ENOSPC;230 }231 232 usb_transfer_batch_t *batch = usb_transfer_batch_create(ep);233 if (!batch) {234 usb_log_error("Failed to create transfer batch.\n");235 return ENOMEM;236 }237 238 batch->target = target;239 batch->buffer = data;240 batch->buffer_size = size;241 batch->setup.packed = setup_data;242 batch->dir = direction;243 batch->on_complete = on_complete;244 batch->on_complete_data = arg;245 246 /* Check for commands that reset toggle bit */247 if (ep->transfer_type == USB_TRANSFER_CONTROL)248 batch->toggle_reset_mode249 = hcd_get_request_toggle_reset_mode(&batch->setup.packet);250 251 const int ret = hcd->ops.schedule(hcd, batch);252 if (ret != EOK) {253 usb_log_warning("Batch %p failed to schedule: %s", batch, str_error(ret));254 usb_transfer_batch_destroy(batch);255 }256 257 /* Drop our own reference to ep. */258 endpoint_del_ref(ep);259 260 return ret;261 }262 263 typedef struct {264 fibril_mutex_t done_mtx;265 fibril_condvar_t done_cv;266 unsigned done;267 268 size_t transfered_size;269 int error;270 } sync_data_t;271 272 static int sync_transfer_complete(void *arg, int error, size_t transfered_size)273 {274 sync_data_t *d = arg;275 assert(d);276 d->transfered_size = transfered_size;277 d->error = error;278 fibril_mutex_lock(&d->done_mtx);279 d->done = 1;280 fibril_condvar_broadcast(&d->done_cv);281 fibril_mutex_unlock(&d->done_mtx);282 return EOK;283 }284 285 ssize_t hcd_send_batch_sync(hcd_t *hcd, device_t *device, usb_target_t target,286 usb_direction_t direction, char *data, size_t size, uint64_t setup_data,287 const char *name)288 {289 assert(hcd);290 sync_data_t sd = { .done = 0 };291 fibril_mutex_initialize(&sd.done_mtx);292 fibril_condvar_initialize(&sd.done_cv);293 294 const int ret = hcd_send_batch(hcd, device, target, direction,295 data, size, setup_data,296 sync_transfer_complete, &sd, name);297 if (ret != EOK)298 return ret;299 300 fibril_mutex_lock(&sd.done_mtx);301 while (!sd.done)302 fibril_condvar_wait(&sd.done_cv, &sd.done_mtx);303 fibril_mutex_unlock(&sd.done_mtx);304 305 return (sd.error == EOK)306 ? (ssize_t) sd.transfered_size307 : (ssize_t) sd.error;308 }309 310 480 311 481 /** -
uspace/lib/usbhost/src/usb2_bus.c
r1ea0bbf r32fb6bce 205 205 206 206 usb2_bus_t *bus = (usb2_bus_t *) dev->bus; 207 hcd_t *hcd = (hcd_t *) bus->base.hcd;208 207 209 208 /* The default address is currently reserved for this device */ … … 231 230 232 231 uint16_t max_packet_size; 233 if ((err = hcd_get_ep0_max_packet_size(&max_packet_size, hcd, dev)))232 if ((err = hcd_get_ep0_max_packet_size(&max_packet_size, &bus->base, dev))) 234 233 goto err_address; 235 234 … … 238 237 239 238 usb_log_debug("Device(%d): Setting USB address.", address); 240 err = hcd_send_batch_sync(hcd,dev, usb2_default_target, USB_DIRECTION_OUT,239 err = bus_device_send_batch_sync(dev, usb2_default_target, USB_DIRECTION_OUT, 241 240 NULL, 0, *(uint64_t *)&set_address, "set address"); 242 241 if (err != 0) { … … 315 314 316 315 /* Read the device descriptor, derive the match ids */ 317 if ((err = hcd_d df_device_explore(dev))) {316 if ((err = hcd_device_explore(dev))) { 318 317 usb_log_error("Device(%d): Failed to explore device: %s", dev->address, str_error(err)); 319 318 release_address(bus, dev->address); … … 463 462 * @return Error code. 464 463 */ 465 int usb2_bus_init(usb2_bus_t *bus, hcd_t *hcd,size_t available_bandwidth)464 int usb2_bus_init(usb2_bus_t *bus, size_t available_bandwidth) 466 465 { 467 466 assert(bus); 468 467 469 bus_init(&bus->base, hcd,sizeof(device_t));468 bus_init(&bus->base, sizeof(device_t)); 470 469 bus->base.ops = &usb2_bus_ops; 471 470
Note:
See TracChangeset
for help on using the changeset viewer.