Changeset df6ded8 in mainline for uspace/drv/bus/usb/uhci
- 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/drv/bus/usb/uhci
- Files:
-
- 11 edited
-
hc.c (modified) (26 diffs)
-
hc.h (modified) (5 diffs)
-
hw_struct/queue_head.h (modified) (1 diff)
-
hw_struct/transfer_descriptor.c (modified) (2 diffs)
-
hw_struct/transfer_descriptor.h (modified) (1 diff)
-
main.c (modified) (6 diffs)
-
transfer_list.c (modified) (9 diffs)
-
transfer_list.h (modified) (1 diff)
-
uhci_batch.c (modified) (15 diffs)
-
uhci_batch.h (modified) (7 diffs)
-
uhci_rh.c (modified) (12 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/uhci/hc.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek 3 4 * All rights reserved. 4 5 * … … 50 51 #include <usb/usb.h> 51 52 #include <usb/host/utils/malloc32.h> 53 #include <usb/host/bandwidth.h> 54 #include <usb/host/utility.h> 52 55 53 56 #include "uhci_batch.h" 57 #include "transfer_list.h" 54 58 #include "hc.h" 55 59 … … 107 111 * @return Error code. 108 112 */ 109 errno_t uhci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq)113 errno_t hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq) 110 114 { 111 115 assert(code); … … 140 144 code->cmds[3].addr = (void*)®isters->usbsts; 141 145 142 usb_log_debug("I/O regs at %p (size %zu), IRQ %d. \n",146 usb_log_debug("I/O regs at %p (size %zu), IRQ %d.", 143 147 RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]); 144 148 … … 157 161 * - resume from suspend state (not implemented) 158 162 */ 159 void uhci_hc_interrupt(hcd_t *hcd, uint32_t status) 160 { 161 assert(hcd); 162 hc_t *instance = hcd_get_driver_data(hcd); 163 assert(instance); 163 static void hc_interrupt(bus_t *bus, uint32_t status) 164 { 165 hc_t *instance = bus_to_hc(bus); 166 164 167 /* Lower 2 bits are transaction error and transaction complete */ 165 168 if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) { 166 LIST_INITIALIZE(done); 167 transfer_list_remove_finished( 168 &instance->transfers_interrupt, &done); 169 transfer_list_remove_finished( 170 &instance->transfers_control_slow, &done); 171 transfer_list_remove_finished( 172 &instance->transfers_control_full, &done); 173 transfer_list_remove_finished( 174 &instance->transfers_bulk_full, &done); 175 176 list_foreach_safe(done, current, next) { 177 list_remove(current); 178 uhci_transfer_batch_t *batch = 179 uhci_transfer_batch_from_link(current); 180 uhci_transfer_batch_finish_dispose(batch); 181 } 182 } 169 transfer_list_check_finished(&instance->transfers_interrupt); 170 transfer_list_check_finished(&instance->transfers_control_slow); 171 transfer_list_check_finished(&instance->transfers_control_full); 172 transfer_list_check_finished(&instance->transfers_bulk_full); 173 } 174 183 175 /* Resume interrupts are not supported */ 184 176 if (status & UHCI_STATUS_RESUME) { 185 usb_log_error("Resume interrupt! \n");177 usb_log_error("Resume interrupt!"); 186 178 } 187 179 188 180 /* Bits 4 and 5 indicate hc error */ 189 181 if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) { 190 usb_log_error("UHCI hardware failure!. \n");182 usb_log_error("UHCI hardware failure!."); 191 183 ++instance->hw_failures; 192 184 transfer_list_abort_all(&instance->transfers_interrupt); … … 199 191 hc_init_hw(instance); 200 192 } else { 201 usb_log_fatal("Too many UHCI hardware failures!. \n");202 hc_ fini(instance);193 usb_log_fatal("Too many UHCI hardware failures!."); 194 hc_gone(&instance->base); 203 195 } 204 196 } … … 216 208 * interrupt fibrils. 217 209 */ 218 errno_t hc_ init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)219 { 220 assert(instance);210 errno_t hc_add(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res) 211 { 212 hc_t *instance = hcd_to_hc(hcd); 221 213 assert(hw_res); 222 214 if (hw_res->io_ranges.count != 1 || … … 224 216 return EINVAL; 225 217 226 instance->hw_interrupts = interrupts;227 218 instance->hw_failures = 0; 228 219 … … 231 222 (void **) &instance->registers); 232 223 if (ret != EOK) { 233 usb_log_error("Failed to gain access to registers: %s. \n",224 usb_log_error("Failed to gain access to registers: %s.", 234 225 str_error(ret)); 235 226 return ret; 236 227 } 237 228 238 usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible. \n",229 usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.", 239 230 hw_res->io_ranges.ranges[0].address.absolute, 240 231 hw_res->io_ranges.ranges[0].size); … … 242 233 ret = hc_init_mem_structures(instance); 243 234 if (ret != EOK) { 244 usb_log_error("Failed to init UHCI memory structures: %s. \n",235 usb_log_error("Failed to init UHCI memory structures: %s.", 245 236 str_error(ret)); 246 237 // TODO: we should disable pio here … … 248 239 } 249 240 241 return EOK; 242 } 243 244 int hc_start(hc_device_t *hcd) 245 { 246 hc_t *instance = hcd_to_hc(hcd); 250 247 hc_init_hw(instance); 251 248 (void)hc_debug_checker; 252 249 253 uhci_rh_init(&instance->rh, instance->registers->ports, "uhci"); 254 255 return EOK; 250 return uhci_rh_init(&instance->rh, instance->registers->ports, "uhci"); 251 } 252 253 int hc_setup_roothub(hc_device_t *hcd) 254 { 255 return hc_setup_virtual_root_hub(hcd, USB_SPEED_FULL); 256 256 } 257 257 … … 260 260 * @param[in] instance Host controller structure to use. 261 261 */ 262 void hc_fini(hc_t *instance)262 int hc_gone(hc_device_t *instance) 263 263 { 264 264 assert(instance); 265 265 //TODO Implement 266 return ENOTSUP; 266 267 } 267 268 … … 293 294 pio_write_32(®isters->flbaseadd, pa); 294 295 295 if (instance-> hw_interrupts) {296 if (instance->base.irq_cap >= 0) { 296 297 /* Enable all interrupts, but resume interrupt */ 297 298 pio_write_16(&instance->registers->usbintr, … … 301 302 const uint16_t cmd = pio_read_16(®isters->usbcmd); 302 303 if (cmd != 0) 303 usb_log_warning("Previous command value: %x. \n", cmd);304 usb_log_warning("Previous command value: %x.", cmd); 304 305 305 306 /* Start the hc with large(64B) packet FSBR */ … … 308 309 } 309 310 311 static usb_transfer_batch_t *create_transfer_batch(endpoint_t *ep) 312 { 313 uhci_transfer_batch_t *batch = uhci_transfer_batch_create(ep); 314 return &batch->base; 315 } 316 317 static void destroy_transfer_batch(usb_transfer_batch_t *batch) 318 { 319 uhci_transfer_batch_destroy(uhci_transfer_batch_get(batch)); 320 } 321 322 static endpoint_t *endpoint_create(device_t *device, const usb_endpoint_descriptors_t *desc) 323 { 324 endpoint_t *ep = calloc(1, sizeof(uhci_endpoint_t)); 325 if (ep) 326 endpoint_init(ep, device, desc); 327 return ep; 328 } 329 330 static errno_t endpoint_register(endpoint_t *ep) 331 { 332 hc_t * const hc = bus_to_hc(endpoint_get_bus(ep)); 333 334 const errno_t err = usb2_bus_endpoint_register(&hc->bus_helper, ep); 335 if (err) 336 return err; 337 338 transfer_list_t *list = hc->transfers[ep->device->speed][ep->transfer_type]; 339 if (!list) 340 /* 341 * We don't support this combination (e.g. isochronous). Do not 342 * fail early, because that would block any device with these 343 * endpoints from connecting. Instead, make sure these transfers 344 * are denied soon enough with ENOTSUP not to fail on asserts. 345 */ 346 return EOK; 347 348 endpoint_set_online(ep, &list->guard); 349 return EOK; 350 } 351 352 static void endpoint_unregister(endpoint_t *ep) 353 { 354 hc_t * const hc = bus_to_hc(endpoint_get_bus(ep)); 355 usb2_bus_endpoint_unregister(&hc->bus_helper, ep); 356 357 // Check for the roothub, as it does not schedule into lists 358 if (ep->device->address == uhci_rh_get_address(&hc->rh)) { 359 // FIXME: We shall check the roothub for active transfer. But 360 // as it is polling, there is no way to make it stop doing so. 361 // Return after rewriting uhci rh. 362 return; 363 } 364 365 transfer_list_t *list = hc->transfers[ep->device->speed][ep->transfer_type]; 366 if (!list) 367 /* 368 * We don't support this combination (e.g. isochronous), 369 * so no transfer can be active. 370 */ 371 return; 372 373 fibril_mutex_lock(&list->guard); 374 375 endpoint_set_offline_locked(ep); 376 /* From now on, no other transfer will be scheduled. */ 377 378 if (!ep->active_batch) { 379 fibril_mutex_unlock(&list->guard); 380 return; 381 } 382 383 /* First, offer the batch a short chance to be finished. */ 384 endpoint_wait_timeout_locked(ep, 10000); 385 386 if (!ep->active_batch) { 387 fibril_mutex_unlock(&list->guard); 388 return; 389 } 390 391 uhci_transfer_batch_t * const batch = 392 uhci_transfer_batch_get(ep->active_batch); 393 394 /* Remove the batch from the schedule to stop it from being finished. */ 395 endpoint_deactivate_locked(ep); 396 transfer_list_remove_batch(list, batch); 397 398 fibril_mutex_unlock(&list->guard); 399 400 /* 401 * We removed the batch from software schedule only, it's still possible 402 * that HC has it in its caches. Better wait a while before we release 403 * the buffers. 404 */ 405 async_usleep(20000); 406 batch->base.error = EINTR; 407 batch->base.transferred_size = 0; 408 usb_transfer_batch_finish(&batch->base); 409 } 410 411 static int device_enumerate(device_t *dev) 412 { 413 hc_t * const hc = bus_to_hc(dev->bus); 414 return usb2_bus_device_enumerate(&hc->bus_helper, dev); 415 } 416 417 static void device_gone(device_t *dev) 418 { 419 hc_t * const hc = bus_to_hc(dev->bus); 420 usb2_bus_device_gone(&hc->bus_helper, dev); 421 } 422 423 static int hc_status(bus_t *, uint32_t *); 424 static int hc_schedule(usb_transfer_batch_t *); 425 426 static const bus_ops_t uhci_bus_ops = { 427 .interrupt = hc_interrupt, 428 .status = hc_status, 429 430 .device_enumerate = device_enumerate, 431 .device_gone = device_gone, 432 433 .endpoint_create = endpoint_create, 434 .endpoint_register = endpoint_register, 435 .endpoint_unregister = endpoint_unregister, 436 437 .batch_create = create_transfer_batch, 438 .batch_schedule = hc_schedule, 439 .batch_destroy = destroy_transfer_batch, 440 }; 441 310 442 /** Initialize UHCI hc memory structures. 311 443 * … … 321 453 { 322 454 assert(instance); 455 456 usb2_bus_helper_init(&instance->bus_helper, &bandwidth_accounting_usb11); 457 458 bus_init(&instance->bus, sizeof(device_t)); 459 instance->bus.ops = &uhci_bus_ops; 460 461 hc_device_setup(&instance->base, &instance->bus); 323 462 324 463 /* Init USB frame list page */ … … 327 466 return ENOMEM; 328 467 } 329 usb_log_debug("Initialized frame list at %p. \n", instance->frame_list);468 usb_log_debug("Initialized frame list at %p.", instance->frame_list); 330 469 331 470 /* Init transfer lists */ 332 471 errno_t ret = hc_init_transfer_lists(instance); 333 472 if (ret != EOK) { 334 usb_log_error("Failed to initialize transfer lists. \n");473 usb_log_error("Failed to initialize transfer lists."); 335 474 return_page(instance->frame_list); 336 475 return ENOMEM; 337 476 } 338 usb_log_debug("Initialized transfer lists.\n"); 477 list_initialize(&instance->pending_endpoints); 478 usb_log_debug("Initialized transfer lists."); 339 479 340 480 … … 366 506 errno_t ret = transfer_list_init(&instance->transfers_##type, name); \ 367 507 if (ret != EOK) { \ 368 usb_log_error("Failed to setup %s transfer list: %s. \n", \508 usb_log_error("Failed to setup %s transfer list: %s.", \ 369 509 name, str_error(ret)); \ 370 510 transfer_list_fini(&instance->transfers_bulk_full); \ … … 411 551 } 412 552 413 errno_t uhci_hc_status(hcd_t *hcd, uint32_t *status)414 { 415 assert(hcd);553 static errno_t hc_status(bus_t *bus, uint32_t *status) 554 { 555 hc_t *instance = bus_to_hc(bus); 416 556 assert(status); 417 hc_t *instance = hcd_get_driver_data(hcd);418 assert(instance);419 557 420 558 *status = 0; … … 427 565 } 428 566 429 /** Schedule batch for execution. 567 /** 568 * Schedule batch for execution. 430 569 * 431 570 * @param[in] instance UHCI structure to use. 432 571 * @param[in] batch Transfer batch to schedule. 433 572 * @return Error code 434 * 435 * Checks for bandwidth availability and appends the batch to the proper queue. 436 */ 437 errno_t uhci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch) 438 { 439 assert(hcd); 440 hc_t *instance = hcd_get_driver_data(hcd); 441 assert(instance); 442 assert(batch); 443 444 if (batch->ep->address == uhci_rh_get_address(&instance->rh)) 445 return uhci_rh_schedule(&instance->rh, batch); 446 573 */ 574 static errno_t hc_schedule(usb_transfer_batch_t *batch) 575 { 447 576 uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch); 448 if (!uhci_batch) { 449 usb_log_error("Failed to create UHCI transfer structures.\n"); 450 return ENOMEM; 451 } 452 453 transfer_list_t *list = 454 instance->transfers[batch->ep->speed][batch->ep->transfer_type]; 455 assert(list); 456 transfer_list_add_batch(list, uhci_batch); 457 458 return EOK; 577 endpoint_t *ep = batch->ep; 578 hc_t *hc = bus_to_hc(endpoint_get_bus(ep)); 579 580 if (batch->target.address == uhci_rh_get_address(&hc->rh)) 581 return uhci_rh_schedule(&hc->rh, batch); 582 583 transfer_list_t * const list = 584 hc->transfers[ep->device->speed][ep->transfer_type]; 585 586 if (!list) 587 return ENOTSUP; 588 589 errno_t err; 590 if ((err = uhci_transfer_batch_prepare(uhci_batch))) 591 return err; 592 593 return transfer_list_add_batch(list, uhci_batch); 459 594 } 460 595 … … 479 614 480 615 if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) { 481 usb_log_debug2("Command: %X Status: %X Intr: %x \n",616 usb_log_debug2("Command: %X Status: %X Intr: %x", 482 617 cmd, sts, intr); 483 618 } … … 486 621 pio_read_32(&instance->registers->flbaseadd) & ~0xfff; 487 622 if (frame_list != addr_to_phys(instance->frame_list)) { 488 usb_log_debug("Framelist address: %p vs. %p. \n",623 usb_log_debug("Framelist address: %p vs. %p.", 489 624 (void *) frame_list, 490 625 (void *) addr_to_phys(instance->frame_list)); … … 497 632 uintptr_t real_pa = addr_to_phys(QH(interrupt)); 498 633 if (expected_pa != real_pa) { 499 usb_log_debug("Interrupt QH: %p (frame %d) vs. %p. \n",634 usb_log_debug("Interrupt QH: %p (frame %d) vs. %p.", 500 635 (void *) expected_pa, frnum, (void *) real_pa); 501 636 } … … 504 639 real_pa = addr_to_phys(QH(control_slow)); 505 640 if (expected_pa != real_pa) { 506 usb_log_debug("Control Slow QH: %p vs. %p. \n",641 usb_log_debug("Control Slow QH: %p vs. %p.", 507 642 (void *) expected_pa, (void *) real_pa); 508 643 } … … 511 646 real_pa = addr_to_phys(QH(control_full)); 512 647 if (expected_pa != real_pa) { 513 usb_log_debug("Control Full QH: %p vs. %p. \n",648 usb_log_debug("Control Full QH: %p vs. %p.", 514 649 (void *) expected_pa, (void *) real_pa); 515 650 } … … 518 653 real_pa = addr_to_phys(QH(bulk_full)); 519 654 if (expected_pa != real_pa ) { 520 usb_log_debug("Bulk QH: %p vs. %p. \n",655 usb_log_debug("Bulk QH: %p vs. %p.", 521 656 (void *) expected_pa, (void *) real_pa); 522 657 } -
uspace/drv/bus/usb/uhci/hc.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 43 44 #include <ddi.h> 44 45 #include <usb/host/hcd.h> 46 #include <usb/host/usb2_bus.h> 45 47 #include <usb/host/usb_transfer_batch.h> 46 48 … … 99 101 /** Main UHCI driver structure */ 100 102 typedef struct hc { 103 /* Common hc_device header */ 104 hc_device_t base; 105 101 106 uhci_rh_t rh; 107 bus_t bus; 108 usb2_bus_helper_t bus_helper; 109 102 110 /** Addresses of I/O registers */ 103 111 uhci_regs_t *registers; … … 117 125 /** Pointer table to the above lists, helps during scheduling */ 118 126 transfer_list_t *transfers[2][4]; 119 /** Indicator of hw interrupts availability */ 120 bool hw_interrupts; 127 128 /** 129 * Guard for the pending list. Can be locked under EP guard, but not 130 * vice versa. 131 */ 132 fibril_mutex_t guard; 133 /** List of endpoints with a transfer scheduled */ 134 list_t pending_endpoints; 121 135 122 136 /** Number of hw failures detected. */ … … 124 138 } hc_t; 125 139 126 extern errno_t hc_init(hc_t *, const hw_res_list_parsed_t *, bool); 127 extern void hc_fini(hc_t *);140 typedef struct uhci_endpoint { 141 endpoint_t base; 128 142 129 extern errno_t uhci_hc_gen_irq_code(irq_code_t *, const hw_res_list_parsed_t *, int *); 143 bool toggle; 144 } uhci_endpoint_t; 130 145 131 extern void uhci_hc_interrupt(hcd_t *, uint32_t); 132 extern errno_t uhci_hc_status(hcd_t *, uint32_t *); 133 extern errno_t uhci_hc_schedule(hcd_t *, usb_transfer_batch_t *); 146 static inline hc_t *hcd_to_hc(hc_device_t *hcd) 147 { 148 assert(hcd); 149 return (hc_t *) hcd; 150 } 151 152 static inline hc_t *bus_to_hc(bus_t *bus) 153 { 154 assert(bus); 155 return member_to_inst(bus, hc_t, bus); 156 } 157 158 int hc_unschedule_batch(usb_transfer_batch_t *); 159 160 extern errno_t hc_add(hc_device_t *, const hw_res_list_parsed_t *); 161 extern errno_t hc_gen_irq_code(irq_code_t *, hc_device_t *, const hw_res_list_parsed_t *, int *); 162 extern errno_t hc_start(hc_device_t *); 163 extern errno_t hc_setup_roothub(hc_device_t *); 164 extern errno_t hc_gone(hc_device_t *); 134 165 135 166 #endif -
uspace/drv/bus/usb/uhci/hw_struct/queue_head.h
rf5e5f73 rdf6ded8 48 48 /** Pointer to the next entity (another QH or TD */ 49 49 volatile link_pointer_t next; 50 /** Pointer to the contained entities (execution controlled by vertical flag*/ 50 /** 51 * Pointer to the contained entities 52 * (execution controlled by vertical flag) 53 */ 51 54 volatile link_pointer_t element; 52 } __attribute__((packed )) qh_t;55 } __attribute__((packed, aligned(16))) qh_t; 53 56 54 57 /** Initialize queue head structure -
uspace/drv/bus/usb/uhci/hw_struct/transfer_descriptor.c
rf5e5f73 rdf6ded8 104 104 instance->buffer_ptr = addr_to_phys(buffer); 105 105 106 usb_log_debug2("Created TD(%p): %X:%X:%X:%X(%p). \n",106 usb_log_debug2("Created TD(%p): %X:%X:%X:%X(%p).", 107 107 instance, instance->next, instance->status, instance->device, 108 108 instance->buffer_ptr, buffer); 109 109 td_print_status(instance); 110 110 if (pid == USB_PID_SETUP) { 111 usb_log_debug2("SETUP BUFFER: %s \n",111 usb_log_debug2("SETUP BUFFER: %s", 112 112 usb_debug_str_buffer(buffer, 8, 8)); 113 113 } … … 160 160 assert(instance); 161 161 const uint32_t s = instance->status; 162 usb_log_debug2("TD(%p) status(%#" PRIx32 "):%s %d,%s%s%s%s%s%s%s%s%s%s%s %zu. \n",162 usb_log_debug2("TD(%p) status(%#" PRIx32 "):%s %d,%s%s%s%s%s%s%s%s%s%s%s %zu.", 163 163 instance, instance->status, 164 164 (s & TD_STATUS_SPD_FLAG) ? " SPD," : "", -
uspace/drv/bus/usb/uhci/hw_struct/transfer_descriptor.h
rf5e5f73 rdf6ded8 95 95 * memory just needs to be aligned. We don't use it anyway. 96 96 */ 97 } __attribute__((packed )) td_t;97 } __attribute__((packed, aligned(16))) td_t; 98 98 99 99 -
uspace/drv/bus/usb/uhci/main.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Vojtech Horky, Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek 3 4 * All rights reserved. 4 5 * … … 43 44 #include <str_error.h> 44 45 #include <usb/debug.h> 45 #include <usb/host/ ddf_helpers.h>46 #include <usb/host/utility.h> 46 47 47 48 #include "hc.h" … … 49 50 #define NAME "uhci" 50 51 51 static errno_t uhci_driver_init(hcd_t *, const hw_res_list_parsed_t *, bool); 52 static void uhci_driver_fini(hcd_t *); 53 static errno_t disable_legacy(ddf_dev_t *); 52 static errno_t disable_legacy(hc_device_t *); 54 53 55 static const ddf_hc_driver_t uhci_hc_driver = { 56 .claim = disable_legacy, 57 .hc_speed = USB_SPEED_FULL, 58 .irq_code_gen = uhci_hc_gen_irq_code, 59 .init = uhci_driver_init, 60 .fini = uhci_driver_fini, 61 .name = "UHCI", 62 .ops = { 63 .schedule = uhci_hc_schedule, 64 .irq_hook = uhci_hc_interrupt, 65 .status_hook = uhci_hc_status, 66 }, 54 static const hc_driver_t uhci_driver = { 55 .name = NAME, 56 .hc_device_size = sizeof(hc_t), 57 .claim = disable_legacy, 58 .irq_code_gen = hc_gen_irq_code, 59 .hc_add = hc_add, 60 .start = hc_start, 61 .setup_root_hub = hc_setup_roothub, 62 .hc_gone = hc_gone, 67 63 }; 68 69 static errno_t uhci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res, bool irq)70 {71 assert(hcd);72 assert(hcd_get_driver_data(hcd) == NULL);73 74 hc_t *instance = malloc(sizeof(hc_t));75 if (!instance)76 return ENOMEM;77 78 const errno_t ret = hc_init(instance, res, irq);79 if (ret == EOK) {80 hcd_set_implementation(hcd, instance, &uhci_hc_driver.ops);81 } else {82 free(instance);83 }84 return ret;85 }86 87 static void uhci_driver_fini(hcd_t *hcd)88 {89 assert(hcd);90 hc_t *hc = hcd_get_driver_data(hcd);91 if (hc)92 hc_fini(hc);93 94 hcd_set_implementation(hcd, NULL, NULL);95 free(hc);96 }97 64 98 65 /** Call the PCI driver with a request to clear legacy support register … … 101 68 * @return Error code. 102 69 */ 103 static errno_t disable_legacy( ddf_dev_t *device)70 static errno_t disable_legacy(hc_device_t *hcd) 104 71 { 105 assert( device);72 assert(hcd); 106 73 107 async_sess_t *parent_sess = ddf_dev_parent_sess_get( device);74 async_sess_t *parent_sess = ddf_dev_parent_sess_get(hcd->ddf_dev); 108 75 if (parent_sess == NULL) 109 76 return ENOMEM; … … 113 80 return pci_config_space_write_16(parent_sess, 0xc0, 0xaf00); 114 81 } 115 116 /** Initialize a new ddf driver instance for uhci hc and hub.117 *118 * @param[in] device DDF instance of the device to initialize.119 * @return Error code.120 */121 static errno_t uhci_dev_add(ddf_dev_t *device)122 {123 usb_log_debug2("uhci_dev_add() called\n");124 assert(device);125 return hcd_ddf_add_hc(device, &uhci_hc_driver);126 }127 128 static const driver_ops_t uhci_driver_ops = {129 .dev_add = uhci_dev_add,130 };131 132 static const driver_t uhci_driver = {133 .name = NAME,134 .driver_ops = &uhci_driver_ops135 };136 137 82 138 83 /** Initialize global driver structures (NONE). … … 149 94 log_init(NAME); 150 95 logctl_set_log_level(NAME, LVL_NOTE); 151 return ddf_driver_main(&uhci_driver);96 return hc_driver_main(&uhci_driver); 152 97 } 153 98 /** -
uspace/drv/bus/usb/uhci/transfer_list.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek 3 4 * All rights reserved. 4 5 * … … 41 42 #include <usb/host/usb_transfer_batch.h> 42 43 #include <usb/host/utils/malloc32.h> 44 #include <usb/host/utility.h> 43 45 44 46 #include "hw_struct/link_pointer.h" 45 47 #include "transfer_list.h" 46 47 static void transfer_list_remove_batch( 48 transfer_list_t *instance, uhci_transfer_batch_t *uhci_batch); 48 #include "hc.h" 49 49 50 50 /** Initialize transfer list structures. … … 62 62 instance->queue_head = malloc32(sizeof(qh_t)); 63 63 if (!instance->queue_head) { 64 usb_log_error("Failed to allocate queue head. \n");64 usb_log_error("Failed to allocate queue head."); 65 65 return ENOMEM; 66 66 } 67 67 const uint32_t queue_head_pa = addr_to_phys(instance->queue_head); 68 usb_log_debug2("Transfer list %s setup with QH: %p (%#" PRIx32" ). \n",68 usb_log_debug2("Transfer list %s setup with QH: %p (%#" PRIx32" ).", 69 69 name, instance->queue_head, queue_head_pa); 70 70 … … 103 103 } 104 104 105 /** Add transfer batch to the list and queue. 106 * 107 * @param[in] instance List to use. 108 * @param[in] batch Transfer batch to submit. 105 /** 106 * Add transfer batch to the list and queue. 109 107 * 110 108 * The batch is added to the end of the list and queue. 111 */ 112 void transfer_list_add_batch( 109 * 110 * @param[in] instance List to use. 111 * @param[in] batch Transfer batch to submit. After return, the batch must 112 * not be used further. 113 */ 114 int transfer_list_add_batch( 113 115 transfer_list_t *instance, uhci_transfer_batch_t *uhci_batch) 114 116 { 115 117 assert(instance); 116 118 assert(uhci_batch); 117 usb_log_debug2("Batch %p adding to queue %s.\n", 118 uhci_batch->usb_batch, instance->name);119 120 endpoint_t *ep = uhci_batch->base.ep; 119 121 120 122 fibril_mutex_lock(&instance->guard); 123 124 const int err = endpoint_activate_locked(ep, &uhci_batch->base); 125 if (err) { 126 fibril_mutex_unlock(&instance->guard); 127 return err; 128 } 129 130 usb_log_debug2("Batch %p adding to queue %s.", 131 uhci_batch, instance->name); 121 132 122 133 /* Assume there is nothing scheduled */ … … 145 156 146 157 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT 147 " scheduled in queue %s. \n", uhci_batch->usb_batch,148 USB_TRANSFER_BATCH_ARGS( *uhci_batch->usb_batch), instance->name);158 " scheduled in queue %s.", uhci_batch, 159 USB_TRANSFER_BATCH_ARGS(uhci_batch->base), instance->name); 149 160 fibril_mutex_unlock(&instance->guard); 161 return EOK; 162 } 163 164 /** 165 * Reset toggle on endpoint callback. 166 */ 167 static void uhci_reset_toggle(endpoint_t *ep) 168 { 169 uhci_endpoint_t *uhci_ep = (uhci_endpoint_t *) ep; 170 uhci_ep->toggle = 0; 150 171 } 151 172 … … 155 176 * @param[in] done list to fill 156 177 */ 157 void transfer_list_remove_finished(transfer_list_t *instance, list_t *done) 158 { 159 assert(instance); 160 assert(done); 178 void transfer_list_check_finished(transfer_list_t *instance) 179 { 180 assert(instance); 161 181 162 182 fibril_mutex_lock(&instance->guard); 163 link_t *current = list_first(&instance->batch_list); 164 while (current && current != &instance->batch_list.head) { 165 link_t * const next = current->next; 166 uhci_transfer_batch_t *batch = 167 uhci_transfer_batch_from_link(current); 168 169 if (uhci_transfer_batch_is_complete(batch)) { 170 /* Save for processing */ 183 list_foreach_safe(instance->batch_list, current, next) { 184 uhci_transfer_batch_t *batch = uhci_transfer_batch_from_link(current); 185 186 if (uhci_transfer_batch_check_completed(batch)) { 187 assert(batch->base.ep->active_batch == &batch->base); 188 endpoint_deactivate_locked(batch->base.ep); 189 hc_reset_toggles(&batch->base, &uhci_reset_toggle); 171 190 transfer_list_remove_batch(instance, batch); 172 list_append(current, done);191 usb_transfer_batch_finish(&batch->base); 173 192 } 174 current = next;175 193 } 176 194 fibril_mutex_unlock(&instance->guard); … … 186 204 while (!list_empty(&instance->batch_list)) { 187 205 link_t * const current = list_first(&instance->batch_list); 188 uhci_transfer_batch_t *batch = 189 uhci_transfer_batch_from_link(current); 206 uhci_transfer_batch_t *batch = uhci_transfer_batch_from_link(current); 190 207 transfer_list_remove_batch(instance, batch); 191 uhci_transfer_batch_abort(batch);192 208 } 193 209 fibril_mutex_unlock(&instance->guard); … … 209 225 assert(uhci_batch->qh); 210 226 assert(fibril_mutex_is_locked(&instance->guard)); 211 212 usb_log_debug2("Batch %p removing from queue %s.\n", 213 uhci_batch->usb_batch, instance->name); 227 assert(!list_empty(&instance->batch_list)); 228 229 usb_log_debug2("Batch %p removing from queue %s.", 230 uhci_batch, instance->name); 214 231 215 232 /* Assume I'm the first */ … … 233 250 list_remove(&uhci_batch->link); 234 251 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " removed (%s) " 235 "from %s, next: %x. \n", uhci_batch->usb_batch,236 USB_TRANSFER_BATCH_ARGS( *uhci_batch->usb_batch),252 "from %s, next: %x.", uhci_batch, 253 USB_TRANSFER_BATCH_ARGS(uhci_batch->base), 237 254 qpos, instance->name, uhci_batch->qh->next); 238 255 } -
uspace/drv/bus/usb/uhci/transfer_list.h
rf5e5f73 rdf6ded8 56 56 } transfer_list_t; 57 57 58 void transfer_list_fini(transfer_list_t * instance);59 errno_t transfer_list_init(transfer_list_t * instance, const char *name);60 void transfer_list_set_next(transfer_list_t * instance, transfer_list_t *next);61 void transfer_list_add_batch( 62 transfer_list_t *instance, uhci_transfer_batch_t *batch);63 void transfer_list_ remove_finished(transfer_list_t *instance, list_t *done);64 void transfer_list_abort_all(transfer_list_t * instance);58 void transfer_list_fini(transfer_list_t *); 59 errno_t transfer_list_init(transfer_list_t *, const char *); 60 void transfer_list_set_next(transfer_list_t *, transfer_list_t *); 61 errno_t transfer_list_add_batch(transfer_list_t *, uhci_transfer_batch_t *); 62 void transfer_list_remove_batch(transfer_list_t *, uhci_transfer_batch_t *); 63 void transfer_list_check_finished(transfer_list_t *); 64 void transfer_list_abort_all(transfer_list_t *); 65 65 66 66 #endif -
uspace/drv/bus/usb/uhci/uhci_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 * … … 46 47 47 48 #include "uhci_batch.h" 49 #include "hc.h" 48 50 #include "hw_struct/transfer_descriptor.h" 49 51 50 52 #define DEFAULT_ERROR_COUNT 3 51 53 52 /** Safely destructs uhci_transfer_batch_t structure. 54 /** Transfer batch setup table. */ 55 static void (*const batch_setup[])(uhci_transfer_batch_t*); 56 57 /** Destroys uhci_transfer_batch_t structure. 53 58 * 54 59 * @param[in] uhci_batch Instance to destroy. 55 60 */ 56 static void uhci_transfer_batch_dispose(uhci_transfer_batch_t *uhci_batch) 57 { 58 if (uhci_batch) { 59 usb_transfer_batch_destroy(uhci_batch->usb_batch); 60 free32(uhci_batch->device_buffer); 61 free(uhci_batch); 62 } 63 } 64 65 /** Finishes usb_transfer_batch and destroys the structure. 66 * 67 * @param[in] uhci_batch Instance to finish and destroy. 68 */ 69 void uhci_transfer_batch_finish_dispose(uhci_transfer_batch_t *uhci_batch) 61 void uhci_transfer_batch_destroy(uhci_transfer_batch_t *uhci_batch) 70 62 { 71 63 assert(uhci_batch); 72 assert(uhci_batch->usb_batch); 73 assert(!link_in_use(&uhci_batch->link)); 74 usb_transfer_batch_finish(uhci_batch->usb_batch, 75 uhci_transfer_batch_data_buffer(uhci_batch)); 76 uhci_transfer_batch_dispose(uhci_batch); 77 } 78 79 /** Transfer batch setup table. */ 80 static void (*const batch_setup[])(uhci_transfer_batch_t*, usb_direction_t); 64 dma_buffer_free(&uhci_batch->uhci_dma_buffer); 65 free(uhci_batch); 66 } 81 67 82 68 /** Allocate memory and initialize internal data structure. … … 85 71 * @return Valid pointer if all structures were successfully created, 86 72 * NULL otherwise. 73 */ 74 uhci_transfer_batch_t * uhci_transfer_batch_create(endpoint_t *ep) 75 { 76 uhci_transfer_batch_t *uhci_batch = 77 calloc(1, sizeof(uhci_transfer_batch_t)); 78 if (!uhci_batch) { 79 usb_log_error("Failed to allocate UHCI batch."); 80 return NULL; 81 } 82 83 usb_transfer_batch_init(&uhci_batch->base, ep); 84 85 link_initialize(&uhci_batch->link); 86 return uhci_batch; 87 } 88 89 /* Prepares batch for commiting. 87 90 * 88 91 * Determines the number of needed transfer descriptors (TDs). … … 90 93 * Initializes parameters needed for the transfer and callback. 91 94 */ 92 uhci_transfer_batch_t * uhci_transfer_batch_get(usb_transfer_batch_t *usb_batch)95 int uhci_transfer_batch_prepare(uhci_transfer_batch_t *uhci_batch) 93 96 { 94 97 static_assert((sizeof(td_t) % 16) == 0); 95 #define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \ 96 if (ptr == NULL) { \ 97 usb_log_error(message); \ 98 uhci_transfer_batch_dispose(uhci_batch); \ 99 return NULL; \ 100 } else (void)0 101 102 uhci_transfer_batch_t *uhci_batch = 103 calloc(1, sizeof(uhci_transfer_batch_t)); 104 CHECK_NULL_DISPOSE_RETURN(uhci_batch, 105 "Failed to allocate UHCI batch.\n"); 106 link_initialize(&uhci_batch->link); 107 uhci_batch->td_count = 108 (usb_batch->buffer_size + usb_batch->ep->max_packet_size - 1) 109 / usb_batch->ep->max_packet_size; 98 99 usb_transfer_batch_t *usb_batch = &uhci_batch->base; 100 101 uhci_batch->td_count = (usb_batch->size + usb_batch->ep->max_packet_size - 1) 102 / usb_batch->ep->max_packet_size; 103 110 104 if (usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL) { 111 105 uhci_batch->td_count += 2; 112 106 } 113 107 108 const size_t setup_size = (usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL) 109 ? USB_SETUP_PACKET_SIZE 110 : 0; 111 114 112 const size_t total_size = (sizeof(td_t) * uhci_batch->td_count) 115 + sizeof(qh_t) + usb_batch->setup_size + usb_batch->buffer_size; 116 uhci_batch->device_buffer = malloc32(total_size); 117 CHECK_NULL_DISPOSE_RETURN(uhci_batch->device_buffer, 118 "Failed to allocate UHCI buffer.\n"); 119 memset(uhci_batch->device_buffer, 0, total_size); 120 121 uhci_batch->tds = uhci_batch->device_buffer; 122 uhci_batch->qh = 123 (uhci_batch->device_buffer + (sizeof(td_t) * uhci_batch->td_count)); 113 + sizeof(qh_t) + setup_size; 114 115 if (dma_buffer_alloc(&uhci_batch->uhci_dma_buffer, total_size)) { 116 usb_log_error("Failed to allocate UHCI buffer."); 117 return ENOMEM; 118 } 119 memset(uhci_batch->uhci_dma_buffer.virt, 0, total_size); 120 121 uhci_batch->tds = uhci_batch->uhci_dma_buffer.virt; 122 uhci_batch->qh = (qh_t *) &uhci_batch->tds[uhci_batch->td_count]; 124 123 125 124 qh_init(uhci_batch->qh); 126 125 qh_set_element_td(uhci_batch->qh, &uhci_batch->tds[0]); 127 126 128 void *dest = 129 uhci_batch->device_buffer + (sizeof(td_t) * uhci_batch->td_count) 130 + sizeof(qh_t); 127 void *setup_buffer = uhci_transfer_batch_setup_buffer(uhci_batch); 128 assert(setup_buffer == (void *) (uhci_batch->qh + 1)); 131 129 /* Copy SETUP packet data to the device buffer */ 132 memcpy(dest, usb_batch->setup_buffer, usb_batch->setup_size); 133 dest += usb_batch->setup_size; 134 /* Copy generic data unless they are provided by the device */ 135 if (usb_batch->ep->direction != USB_DIRECTION_IN) { 136 memcpy(dest, usb_batch->buffer, usb_batch->buffer_size); 137 } 138 uhci_batch->usb_batch = usb_batch; 130 memcpy(setup_buffer, usb_batch->setup.buffer, setup_size); 131 139 132 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT 140 " memory structures ready. \n", usb_batch,133 " memory structures ready.", usb_batch, 141 134 USB_TRANSFER_BATCH_ARGS(*usb_batch)); 142 135 143 const usb_direction_t dir = usb_transfer_batch_direction(usb_batch);144 145 136 assert(batch_setup[usb_batch->ep->transfer_type]); 146 batch_setup[usb_batch->ep->transfer_type](uhci_batch , dir);147 148 return uhci_batch;137 batch_setup[usb_batch->ep->transfer_type](uhci_batch); 138 139 return EOK; 149 140 } 150 141 … … 158 149 * is reached. 159 150 */ 160 bool uhci_transfer_batch_ is_complete(constuhci_transfer_batch_t *uhci_batch)151 bool uhci_transfer_batch_check_completed(uhci_transfer_batch_t *uhci_batch) 161 152 { 162 153 assert(uhci_batch); 163 assert(uhci_batch->usb_batch);154 usb_transfer_batch_t *batch = &uhci_batch->base; 164 155 165 156 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT 166 " checking %zu transfer(s) for completion.\n", 167 uhci_batch->usb_batch, 168 USB_TRANSFER_BATCH_ARGS(*uhci_batch->usb_batch), 157 " checking %zu transfer(s) for completion.", 158 uhci_batch, USB_TRANSFER_BATCH_ARGS(*batch), 169 159 uhci_batch->td_count); 170 uhci_batch->usb_batch->transfered_size = 0; 160 batch->transferred_size = 0; 161 162 uhci_endpoint_t *uhci_ep = (uhci_endpoint_t *) batch->ep; 171 163 172 164 for (size_t i = 0;i < uhci_batch->td_count; ++i) { … … 175 167 } 176 168 177 uhci_batch->usb_batch->error = td_status(&uhci_batch->tds[i]);178 if ( uhci_batch->usb_batch->error != EOK) {179 assert( uhci_batch->usb_batch->ep != NULL);169 batch->error = td_status(&uhci_batch->tds[i]); 170 if (batch->error != EOK) { 171 assert(batch->ep != NULL); 180 172 181 173 usb_log_debug("Batch %p found error TD(%zu->%p):%" 182 PRIx32 ". \n", uhci_batch->usb_batch, i,174 PRIx32 ".", uhci_batch, i, 183 175 &uhci_batch->tds[i], uhci_batch->tds[i].status); 184 176 td_print_status(&uhci_batch->tds[i]); 185 177 186 endpoint_toggle_set(uhci_batch->usb_batch->ep, 187 td_toggle(&uhci_batch->tds[i])); 188 if (i > 0) 189 goto substract_ret; 190 return true; 178 uhci_ep->toggle = td_toggle(&uhci_batch->tds[i]); 179 goto substract_ret; 191 180 } 192 181 193 uhci_batch->usb_batch->transfered_size182 batch->transferred_size 194 183 += td_act_size(&uhci_batch->tds[i]); 195 184 if (td_is_short(&uhci_batch->tds[i])) … … 197 186 } 198 187 substract_ret: 199 uhci_batch->usb_batch->transfered_size 200 -= uhci_batch->usb_batch->setup_size; 188 if (batch->transferred_size > 0 && batch->ep->transfer_type == USB_TRANSFER_CONTROL) { 189 assert(batch->transferred_size >= USB_SETUP_PACKET_SIZE); 190 batch->transferred_size -= USB_SETUP_PACKET_SIZE; 191 } 192 193 assert(batch->transferred_size <= batch->size); 194 201 195 return true; 202 196 } … … 216 210 * The last transfer is marked with IOC flag. 217 211 */ 218 static void batch_data(uhci_transfer_batch_t *uhci_batch , usb_direction_t dir)212 static void batch_data(uhci_transfer_batch_t *uhci_batch) 219 213 { 220 214 assert(uhci_batch); 221 assert(uhci_batch->usb_batch); 222 assert(uhci_batch->usb_batch->ep);215 216 usb_direction_t dir = uhci_batch->base.dir; 223 217 assert(dir == USB_DIRECTION_OUT || dir == USB_DIRECTION_IN); 224 218 … … 226 220 const usb_packet_id pid = direction_pids[dir]; 227 221 const bool low_speed = 228 uhci_batch->usb_batch->ep->speed == USB_SPEED_LOW; 229 const size_t mps = uhci_batch->usb_batch->ep->max_packet_size; 230 const usb_target_t target = {{ 231 uhci_batch->usb_batch->ep->address, 232 uhci_batch->usb_batch->ep->endpoint }}; 233 234 int toggle = endpoint_toggle_get(uhci_batch->usb_batch->ep); 222 uhci_batch->base.ep->device->speed == USB_SPEED_LOW; 223 const size_t mps = uhci_batch->base.ep->max_packet_size; 224 225 uhci_endpoint_t *uhci_ep = (uhci_endpoint_t *) uhci_batch->base.ep; 226 227 int toggle = uhci_ep->toggle; 235 228 assert(toggle == 0 || toggle == 1); 236 229 237 230 size_t td = 0; 238 size_t remain_size = uhci_batch-> usb_batch->buffer_size;231 size_t remain_size = uhci_batch->base.size; 239 232 char *buffer = uhci_transfer_batch_data_buffer(uhci_batch); 240 233 … … 248 241 td_init( 249 242 &uhci_batch->tds[td], DEFAULT_ERROR_COUNT, packet_size, 250 toggle, false, low_speed, target, pid, buffer, next_td);243 toggle, false, low_speed, uhci_batch->base.target, pid, buffer, next_td); 251 244 252 245 ++td; … … 256 249 } 257 250 td_set_ioc(&uhci_batch->tds[td - 1]); 258 endpoint_toggle_set(uhci_batch->usb_batch->ep, toggle);251 uhci_ep->toggle = toggle; 259 252 usb_log_debug2( 260 "Batch %p %s %s " USB_TRANSFER_BATCH_FMT " initialized. \n", \261 uhci_batch ->usb_batch,262 usb_str_transfer_type(uhci_batch-> usb_batch->ep->transfer_type),263 usb_str_direction(uhci_batch-> usb_batch->ep->direction),264 USB_TRANSFER_BATCH_ARGS( *uhci_batch->usb_batch));253 "Batch %p %s %s " USB_TRANSFER_BATCH_FMT " initialized.", \ 254 uhci_batch, 255 usb_str_transfer_type(uhci_batch->base.ep->transfer_type), 256 usb_str_direction(uhci_batch->base.ep->direction), 257 USB_TRANSFER_BATCH_ARGS(uhci_batch->base)); 265 258 } 266 259 … … 276 269 * The last transfer is marked with IOC. 277 270 */ 278 static void batch_control(uhci_transfer_batch_t *uhci_batch , usb_direction_t dir)271 static void batch_control(uhci_transfer_batch_t *uhci_batch) 279 272 { 280 273 assert(uhci_batch); 281 assert(uhci_batch->usb_batch); 282 assert(uhci_batch->usb_batch->ep);274 275 usb_direction_t dir = uhci_batch->base.dir; 283 276 assert(dir == USB_DIRECTION_OUT || dir == USB_DIRECTION_IN); 284 277 assert(uhci_batch->td_count >= 2); … … 291 284 const usb_packet_id status_stage_pid = status_stage_pids[dir]; 292 285 const bool low_speed = 293 uhci_batch->usb_batch->ep->speed == USB_SPEED_LOW; 294 const size_t mps = uhci_batch->usb_batch->ep->max_packet_size; 295 const usb_target_t target = {{ 296 uhci_batch->usb_batch->ep->address, 297 uhci_batch->usb_batch->ep->endpoint }}; 286 uhci_batch->base.ep->device->speed == USB_SPEED_LOW; 287 const size_t mps = uhci_batch->base.ep->max_packet_size; 288 const usb_target_t target = uhci_batch->base.target; 298 289 299 290 /* setup stage */ 300 291 td_init( 301 292 &uhci_batch->tds[0], DEFAULT_ERROR_COUNT, 302 uhci_batch->usb_batch->setup_size, 0, false,293 USB_SETUP_PACKET_SIZE, 0, false, 303 294 low_speed, target, USB_PID_SETUP, 304 295 uhci_transfer_batch_setup_buffer(uhci_batch), &uhci_batch->tds[1]); … … 307 298 size_t td = 1; 308 299 unsigned toggle = 1; 309 size_t remain_size = uhci_batch-> usb_batch->buffer_size;300 size_t remain_size = uhci_batch->base.size; 310 301 char *buffer = uhci_transfer_batch_data_buffer(uhci_batch); 311 302 … … 333 324 td_set_ioc(&uhci_batch->tds[td]); 334 325 335 usb_log_debug2("Control last TD status: %x. \n",326 usb_log_debug2("Control last TD status: %x.", 336 327 uhci_batch->tds[td].status); 337 328 } 338 329 339 static void (*const batch_setup[])(uhci_transfer_batch_t* , usb_direction_t) =330 static void (*const batch_setup[])(uhci_transfer_batch_t*) = 340 331 { 341 332 [USB_TRANSFER_CONTROL] = batch_control, -
uspace/drv/bus/usb/uhci/uhci_batch.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 43 44 #include <stddef.h> 44 45 #include <usb/host/usb_transfer_batch.h> 46 #include <usb/host/endpoint.h> 45 47 46 48 #include "hw_struct/queue_head.h" … … 49 51 /** UHCI specific data required for USB transfer */ 50 52 typedef struct uhci_transfer_batch { 53 usb_transfer_batch_t base; 54 51 55 /** Queue head 52 56 * This QH is used to maintain UHCI schedule structure and the element … … 58 62 /** Number of TDs used by the transfer */ 59 63 size_t td_count; 60 /* * Data buffer, must be accessible by the UHCI hw*/61 void *device_buffer;62 /** Generic transfer data*/63 usb_transfer_batch_t *usb_batch;64 /* Setup data */ 65 char *setup_buffer; 66 /** Backing TDs + setup_buffer */ 67 dma_buffer_t uhci_dma_buffer; 64 68 /** List element */ 65 69 link_t link; 66 70 } uhci_transfer_batch_t; 67 71 68 uhci_transfer_batch_t * uhci_transfer_batch_get(usb_transfer_batch_t *batch); 69 void uhci_transfer_batch_finish_dispose(uhci_transfer_batch_t *uhci_batch); 70 bool uhci_transfer_batch_is_complete(const uhci_transfer_batch_t *uhci_batch); 72 uhci_transfer_batch_t *uhci_transfer_batch_create(endpoint_t *); 73 int uhci_transfer_batch_prepare(uhci_transfer_batch_t *); 74 bool uhci_transfer_batch_check_completed(uhci_transfer_batch_t *); 75 void uhci_transfer_batch_destroy(uhci_transfer_batch_t *); 71 76 72 77 /** Get offset to setup buffer accessible to the HC hw. … … 74 79 * @return Pointer to the setup buffer. 75 80 */ 76 static inline void * uhci_transfer_batch_setup_buffer(81 static inline void *uhci_transfer_batch_setup_buffer( 77 82 const uhci_transfer_batch_t *uhci_batch) 78 83 { 79 84 assert(uhci_batch); 80 assert(uhci_batch->device_buffer); 81 return uhci_batch->device_buffer + sizeof(qh_t) + 85 return uhci_batch->uhci_dma_buffer.virt + sizeof(qh_t) + 82 86 uhci_batch->td_count * sizeof(td_t); 83 87 } … … 87 91 * @return Pointer to the data buffer. 88 92 */ 89 static inline void * uhci_transfer_batch_data_buffer(93 static inline void *uhci_transfer_batch_data_buffer( 90 94 const uhci_transfer_batch_t *uhci_batch) 91 95 { 92 96 assert(uhci_batch); 93 assert(uhci_batch->usb_batch); 94 return uhci_transfer_batch_setup_buffer(uhci_batch) + 95 uhci_batch->usb_batch->setup_size; 96 } 97 98 /** Aborts the batch. 99 * Sets error to EINTR and size off transferd data to 0, before finishing the 100 * batch. 101 * @param uhci_batch Batch to abort. 102 */ 103 static inline void uhci_transfer_batch_abort(uhci_transfer_batch_t *uhci_batch) 104 { 105 assert(uhci_batch); 106 assert(uhci_batch->usb_batch); 107 uhci_batch->usb_batch->error = EINTR; 108 uhci_batch->usb_batch->transfered_size = 0; 109 uhci_transfer_batch_finish_dispose(uhci_batch); 97 return uhci_batch->base.dma_buffer.virt; 110 98 } 111 99 … … 120 108 } 121 109 110 static inline uhci_transfer_batch_t *uhci_transfer_batch_get( 111 usb_transfer_batch_t *b) 112 { 113 assert(b); 114 return (uhci_transfer_batch_t *) b; 115 } 116 122 117 #endif 123 118 -
uspace/drv/bus/usb/uhci/uhci_rh.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2013 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 39 40 #include <usb/classes/hub.h> 40 41 #include <usb/request.h> 42 #include <usb/host/endpoint.h> 41 43 #include <usb/usb.h> 42 44 … … 103 105 assert(batch); 104 106 105 const usb_target_t target = {{106 .address = batch->ep->address,107 .endpoint = batch->ep->endpoint108 }};109 107 do { 110 batch->error = virthub_base_request(&instance->base, target,111 usb_transfer_batch_direction(batch), (void*)batch->setup_buffer,112 batch-> buffer, batch->buffer_size, &batch->transfered_size);108 batch->error = virthub_base_request(&instance->base, batch->target, 109 batch->dir, (void*) batch->setup.buffer, 110 batch->dma_buffer.virt, batch->size, &batch->transferred_size); 113 111 if (batch->error == ENAK) 114 112 async_usleep(instance->base.endpoint_descriptor.poll_interval * 1000); … … 116 114 //ENAK is technically an error condition 117 115 } while (batch->error == ENAK); 118 usb_transfer_batch_finish(batch, NULL); 119 usb_transfer_batch_destroy(batch); 116 usb_transfer_batch_finish(batch); 120 117 return EOK; 121 118 } … … 206 203 data[0] = ((value & STATUS_LINE_D_MINUS) ? 1 : 0) 207 204 | ((value & STATUS_LINE_D_PLUS) ? 2 : 0); 208 RH_DEBUG(hub, port, "Bus state %" PRIx8 "(source %" PRIx16") \n",205 RH_DEBUG(hub, port, "Bus state %" PRIx8 "(source %" PRIx16")", 209 206 data[0], value); 210 207 *act_size = 1; … … 214 211 #define BIT_VAL(val, bit) \ 215 212 ((val & bit) ? 1 : 0) 216 #define UHCI2USB(val, bit, feat) \217 (BIT_VAL(val, bit) << feat)213 #define UHCI2USB(val, bit, mask) \ 214 (BIT_VAL(val, bit) ? (mask) : 0) 218 215 219 216 /** Port status request handler. … … 240 237 const uint16_t val = pio_read_16(hub->ports[port]); 241 238 const uint32_t status = uint32_host2usb( 242 UHCI2USB(val, STATUS_CONNECTED, USB_HUB_ FEATURE_PORT_CONNECTION) |243 UHCI2USB(val, STATUS_ENABLED, USB_HUB_ FEATURE_PORT_ENABLE) |244 UHCI2USB(val, STATUS_SUSPEND, USB _HUB_FEATURE_PORT_SUSPEND) |245 UHCI2USB(val, STATUS_IN_RESET, USB_HUB_ FEATURE_PORT_RESET) |246 UHCI2USB(val, STATUS_ALWAYS_ONE, USB _HUB_FEATURE_PORT_POWER) |247 UHCI2USB(val, STATUS_LOW_SPEED, USB _HUB_FEATURE_PORT_LOW_SPEED) |248 UHCI2USB(val, STATUS_CONNECTED_CHANGED, USB_HUB_ FEATURE_C_PORT_CONNECTION) |249 UHCI2USB(val, STATUS_ENABLED_CHANGED, USB _HUB_FEATURE_C_PORT_ENABLE) |250 // UHCI2USB(val, STATUS_SUSPEND, USB _HUB_FEATURE_C_PORT_SUSPEND) |251 ( (hub->reset_changed[port] ? 1 : 0) << USB_HUB_FEATURE_C_PORT_RESET)239 UHCI2USB(val, STATUS_CONNECTED, USB_HUB_PORT_STATUS_CONNECTION) | 240 UHCI2USB(val, STATUS_ENABLED, USB_HUB_PORT_STATUS_ENABLE) | 241 UHCI2USB(val, STATUS_SUSPEND, USB2_HUB_PORT_STATUS_SUSPEND) | 242 UHCI2USB(val, STATUS_IN_RESET, USB_HUB_PORT_STATUS_RESET) | 243 UHCI2USB(val, STATUS_ALWAYS_ONE, USB2_HUB_PORT_STATUS_POWER) | 244 UHCI2USB(val, STATUS_LOW_SPEED, USB2_HUB_PORT_STATUS_LOW_SPEED) | 245 UHCI2USB(val, STATUS_CONNECTED_CHANGED, USB_HUB_PORT_STATUS_C_CONNECTION) | 246 UHCI2USB(val, STATUS_ENABLED_CHANGED, USB2_HUB_PORT_STATUS_C_ENABLE) | 247 // UHCI2USB(val, STATUS_SUSPEND, USB2_HUB_PORT_STATUS_C_SUSPEND) | 248 (hub->reset_changed[port] ? USB_HUB_PORT_STATUS_C_RESET : 0) 252 249 ); 253 250 RH_DEBUG(hub, port, "Port status %" PRIx32 " (source %" PRIx16 254 "%s) \n", uint32_usb2host(status), val,251 "%s)", uint32_usb2host(status), val, 255 252 hub->reset_changed[port] ? "-reset" : ""); 256 253 memcpy(data, &status, sizeof(status)); … … 278 275 const uint16_t val = status & (~STATUS_WC_BITS); 279 276 switch (feature) { 280 case USB _HUB_FEATURE_PORT_ENABLE:277 case USB2_HUB_FEATURE_PORT_ENABLE: 281 278 RH_DEBUG(hub, port, "Clear port enable (status %" 282 PRIx16 ") \n", status);279 PRIx16 ")", status); 283 280 pio_write_16(hub->ports[port], val & ~STATUS_ENABLED); 284 281 break; 285 case USB _HUB_FEATURE_PORT_SUSPEND:282 case USB2_HUB_FEATURE_PORT_SUSPEND: 286 283 RH_DEBUG(hub, port, "Clear port suspend (status %" 287 PRIx16 ") \n", status);284 PRIx16 ")", status); 288 285 pio_write_16(hub->ports[port], val & ~STATUS_SUSPEND); 289 286 // TODO we should do resume magic 290 usb_log_warning("Resume is not implemented on port %u \n", port);287 usb_log_warning("Resume is not implemented on port %u", port); 291 288 break; 292 289 case USB_HUB_FEATURE_PORT_POWER: 293 RH_DEBUG(hub, port, "Clear port power (status %" PRIx16 ") \n",290 RH_DEBUG(hub, port, "Clear port power (status %" PRIx16 ")", 294 291 status); 295 292 /* We are always powered */ 296 usb_log_warning("Tried to power off port %u \n", port);293 usb_log_warning("Tried to power off port %u", port); 297 294 break; 298 295 case USB_HUB_FEATURE_C_PORT_CONNECTION: 299 296 RH_DEBUG(hub, port, "Clear port conn change (status %" 300 PRIx16 ") \n", status);297 PRIx16 ")", status); 301 298 pio_write_16(hub->ports[port], val | STATUS_CONNECTED_CHANGED); 302 299 break; 303 300 case USB_HUB_FEATURE_C_PORT_RESET: 304 301 RH_DEBUG(hub, port, "Clear port reset change (status %" 305 PRIx16 ") \n", status);302 PRIx16 ")", status); 306 303 hub->reset_changed[port] = false; 307 304 break; 308 case USB _HUB_FEATURE_C_PORT_ENABLE:305 case USB2_HUB_FEATURE_C_PORT_ENABLE: 309 306 RH_DEBUG(hub, port, "Clear port enable change (status %" 310 PRIx16 ") \n", status);307 PRIx16 ")", status); 311 308 pio_write_16(hub->ports[port], status | STATUS_ENABLED_CHANGED); 312 309 break; 313 case USB _HUB_FEATURE_C_PORT_SUSPEND:310 case USB2_HUB_FEATURE_C_PORT_SUSPEND: 314 311 RH_DEBUG(hub, port, "Clear port suspend change (status %" 315 PRIx16 ") \n", status);312 PRIx16 ")", status); 316 313 //TODO 317 314 return ENOTSUP; 318 315 case USB_HUB_FEATURE_C_PORT_OVER_CURRENT: 319 316 RH_DEBUG(hub, port, "Clear port OC change (status %" 320 PRIx16 ") \n", status);317 PRIx16 ")", status); 321 318 /* UHCI Does not report over current */ 322 319 //TODO: newer chips do, but some have broken wiring … … 324 321 default: 325 322 RH_DEBUG(hub, port, "Clear unknown feature %d (status %" 326 PRIx16 ") \n", feature, status);327 usb_log_warning("Clearing feature %d is unsupported \n",323 PRIx16 ")", feature, status); 324 usb_log_warning("Clearing feature %d is unsupported", 328 325 feature); 329 326 return ESTALL; … … 352 349 case USB_HUB_FEATURE_PORT_RESET: 353 350 RH_DEBUG(hub, port, "Set port reset before (status %" PRIx16 354 ") \n", status);351 ")", status); 355 352 uhci_port_reset_enable(hub->ports[port]); 356 353 hub->reset_changed[port] = true; 357 354 RH_DEBUG(hub, port, "Set port reset after (status %" PRIx16 358 ") \n", pio_read_16(hub->ports[port]));359 break; 360 case USB _HUB_FEATURE_PORT_SUSPEND:355 ")", pio_read_16(hub->ports[port])); 356 break; 357 case USB2_HUB_FEATURE_PORT_SUSPEND: 361 358 RH_DEBUG(hub, port, "Set port suspend (status %" PRIx16 362 ") \n", status);359 ")", status); 363 360 pio_write_16(hub->ports[port], 364 361 (status & ~STATUS_WC_BITS) | STATUS_SUSPEND); 365 usb_log_warning("Suspend is not implemented on port %u \n", port);362 usb_log_warning("Suspend is not implemented on port %u", port); 366 363 break; 367 364 case USB_HUB_FEATURE_PORT_POWER: 368 365 RH_DEBUG(hub, port, "Set port power (status %" PRIx16 369 ") \n", status);366 ")", status); 370 367 /* We are always powered */ 371 usb_log_warning("Tried to power port %u \n", port);368 usb_log_warning("Tried to power port %u", port); 372 369 break; 373 370 case USB_HUB_FEATURE_C_PORT_CONNECTION: 374 case USB _HUB_FEATURE_C_PORT_ENABLE:375 case USB _HUB_FEATURE_C_PORT_SUSPEND:371 case USB2_HUB_FEATURE_C_PORT_ENABLE: 372 case USB2_HUB_FEATURE_C_PORT_SUSPEND: 376 373 case USB_HUB_FEATURE_C_PORT_OVER_CURRENT: 377 374 RH_DEBUG(hub, port, "Set port change flag (status %" PRIx16 378 ") \n", status);375 ")", status); 379 376 /* These are voluntary and don't have to be set 380 377 * there is no way we could do it on UHCI anyway */ … … 382 379 default: 383 380 RH_DEBUG(hub, port, "Set unknown feature %d (status %" PRIx16 384 ") \n", feature, status);385 usb_log_warning("Setting feature %d is unsupported \n",381 ")", feature, status); 382 usb_log_warning("Setting feature %d is unsupported", 386 383 feature); 387 384 return ESTALL; … … 422 419 RH_DEBUG(hub, -1, "Event mask %" PRIx8 423 420 " (status_a %" PRIx16 "%s)," 424 " (status_b %" PRIx16 "%s) \n", status,421 " (status_b %" PRIx16 "%s)", status, 425 422 status_a, hub->reset_changed[0] ? "-reset" : "", 426 423 status_b, hub->reset_changed[1] ? "-reset" : "" );
Note:
See TracChangeset
for help on using the changeset viewer.
