Changes in uspace/drv/bus/usb/uhci/hc.c [b7fd2a0:e0a5d4c] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/uhci/hc.c
rb7fd2a0 re0a5d4c 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 }
Note:
See TracChangeset
for help on using the changeset viewer.