Changes in uspace/drv/bus/usb/uhci/hc.c [5a6cc679:b7fd2a0] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/uhci/hc.c
r5a6cc679 rb7fd2a0 50 50 #include <usb/usb.h> 51 51 #include <usb/host/utils/malloc32.h> 52 #include <usb/host/bandwidth.h>53 #include <usb/host/utility.h>54 52 55 53 #include "uhci_batch.h" 56 #include "transfer_list.h"57 54 #include "hc.h" 58 55 … … 110 107 * @return Error code. 111 108 */ 112 errno_t hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq)109 errno_t uhci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq) 113 110 { 114 111 assert(code); … … 143 140 code->cmds[3].addr = (void*)®isters->usbsts; 144 141 145 usb_log_debug("I/O regs at %p (size %zu), IRQ %d. ",142 usb_log_debug("I/O regs at %p (size %zu), IRQ %d.\n", 146 143 RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]); 147 144 … … 160 157 * - resume from suspend state (not implemented) 161 158 */ 162 static void hc_interrupt(bus_t *bus, uint32_t status) 163 { 164 hc_t *instance = bus_to_hc(bus); 165 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); 166 164 /* Lower 2 bits are transaction error and transaction complete */ 167 165 if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) { 168 transfer_list_check_finished(&instance->transfers_interrupt); 169 transfer_list_check_finished(&instance->transfers_control_slow); 170 transfer_list_check_finished(&instance->transfers_control_full); 171 transfer_list_check_finished(&instance->transfers_bulk_full); 172 } 173 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 } 174 183 /* Resume interrupts are not supported */ 175 184 if (status & UHCI_STATUS_RESUME) { 176 usb_log_error("Resume interrupt! ");185 usb_log_error("Resume interrupt!\n"); 177 186 } 178 187 179 188 /* Bits 4 and 5 indicate hc error */ 180 189 if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) { 181 usb_log_error("UHCI hardware failure!. ");190 usb_log_error("UHCI hardware failure!.\n"); 182 191 ++instance->hw_failures; 183 192 transfer_list_abort_all(&instance->transfers_interrupt); … … 190 199 hc_init_hw(instance); 191 200 } else { 192 usb_log_fatal("Too many UHCI hardware failures!. ");193 hc_ gone(&instance->base);201 usb_log_fatal("Too many UHCI hardware failures!.\n"); 202 hc_fini(instance); 194 203 } 195 204 } … … 207 216 * interrupt fibrils. 208 217 */ 209 errno_t hc_ add(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res)210 { 211 hc_t *instance = hcd_to_hc(hcd);218 errno_t hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts) 219 { 220 assert(instance); 212 221 assert(hw_res); 213 222 if (hw_res->io_ranges.count != 1 || … … 215 224 return EINVAL; 216 225 226 instance->hw_interrupts = interrupts; 217 227 instance->hw_failures = 0; 218 228 … … 221 231 (void **) &instance->registers); 222 232 if (ret != EOK) { 223 usb_log_error("Failed to gain access to registers: %s. ",233 usb_log_error("Failed to gain access to registers: %s.\n", 224 234 str_error(ret)); 225 235 return ret; 226 236 } 227 237 228 usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible. ",238 usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.\n", 229 239 hw_res->io_ranges.ranges[0].address.absolute, 230 240 hw_res->io_ranges.ranges[0].size); … … 232 242 ret = hc_init_mem_structures(instance); 233 243 if (ret != EOK) { 234 usb_log_error("Failed to init UHCI memory structures: %s. ",244 usb_log_error("Failed to init UHCI memory structures: %s.\n", 235 245 str_error(ret)); 236 246 // TODO: we should disable pio here … … 238 248 } 239 249 240 return EOK;241 }242 243 int hc_start(hc_device_t *hcd)244 {245 hc_t *instance = hcd_to_hc(hcd);246 250 hc_init_hw(instance); 247 251 (void)hc_debug_checker; 248 252 249 return uhci_rh_init(&instance->rh, instance->registers->ports, "uhci"); 250 } 251 252 int hc_setup_roothub(hc_device_t *hcd) 253 { 254 return hc_setup_virtual_root_hub(hcd, USB_SPEED_FULL); 253 uhci_rh_init(&instance->rh, instance->registers->ports, "uhci"); 254 255 return EOK; 255 256 } 256 257 … … 259 260 * @param[in] instance Host controller structure to use. 260 261 */ 261 int hc_gone(hc_device_t *instance)262 void hc_fini(hc_t *instance) 262 263 { 263 264 assert(instance); 264 265 //TODO Implement 265 return ENOTSUP;266 266 } 267 267 … … 293 293 pio_write_32(®isters->flbaseadd, pa); 294 294 295 if (instance-> base.irq_cap >= 0) {295 if (instance->hw_interrupts) { 296 296 /* Enable all interrupts, but resume interrupt */ 297 297 pio_write_16(&instance->registers->usbintr, … … 301 301 const uint16_t cmd = pio_read_16(®isters->usbcmd); 302 302 if (cmd != 0) 303 usb_log_warning("Previous command value: %x. ", cmd);303 usb_log_warning("Previous command value: %x.\n", cmd); 304 304 305 305 /* Start the hc with large(64B) packet FSBR */ … … 308 308 } 309 309 310 static usb_transfer_batch_t *create_transfer_batch(endpoint_t *ep)311 {312 uhci_transfer_batch_t *batch = uhci_transfer_batch_create(ep);313 return &batch->base;314 }315 316 static void destroy_transfer_batch(usb_transfer_batch_t *batch)317 {318 uhci_transfer_batch_destroy(uhci_transfer_batch_get(batch));319 }320 321 static endpoint_t *endpoint_create(device_t *device, const usb_endpoint_descriptors_t *desc)322 {323 endpoint_t *ep = calloc(1, sizeof(uhci_endpoint_t));324 if (ep)325 endpoint_init(ep, device, desc);326 return ep;327 }328 329 static errno_t endpoint_register(endpoint_t *ep)330 {331 hc_t * const hc = bus_to_hc(endpoint_get_bus(ep));332 333 const errno_t err = usb2_bus_endpoint_register(&hc->bus_helper, ep);334 if (err)335 return err;336 337 transfer_list_t *list = hc->transfers[ep->device->speed][ep->transfer_type];338 if (!list)339 /*340 * We don't support this combination (e.g. isochronous). Do not341 * fail early, because that would block any device with these342 * endpoints from connecting. Instead, make sure these transfers343 * are denied soon enough with ENOTSUP not to fail on asserts.344 */345 return EOK;346 347 endpoint_set_online(ep, &list->guard);348 return EOK;349 }350 351 static void endpoint_unregister(endpoint_t *ep)352 {353 hc_t * const hc = bus_to_hc(endpoint_get_bus(ep));354 usb2_bus_endpoint_unregister(&hc->bus_helper, ep);355 356 // Check for the roothub, as it does not schedule into lists357 if (ep->device->address == uhci_rh_get_address(&hc->rh)) {358 // FIXME: We shall check the roothub for active transfer. But359 // as it is polling, there is no way to make it stop doing so.360 // Return after rewriting uhci rh.361 return;362 }363 364 transfer_list_t *list = hc->transfers[ep->device->speed][ep->transfer_type];365 if (!list)366 /*367 * We don't support this combination (e.g. isochronous),368 * so no transfer can be active.369 */370 return;371 372 fibril_mutex_lock(&list->guard);373 374 endpoint_set_offline_locked(ep);375 /* From now on, no other transfer will be scheduled. */376 377 if (!ep->active_batch) {378 fibril_mutex_unlock(&list->guard);379 return;380 }381 382 /* First, offer the batch a short chance to be finished. */383 endpoint_wait_timeout_locked(ep, 10000);384 385 if (!ep->active_batch) {386 fibril_mutex_unlock(&list->guard);387 return;388 }389 390 uhci_transfer_batch_t * const batch =391 uhci_transfer_batch_get(ep->active_batch);392 393 /* Remove the batch from the schedule to stop it from being finished. */394 endpoint_deactivate_locked(ep);395 transfer_list_remove_batch(list, batch);396 397 fibril_mutex_unlock(&list->guard);398 399 /*400 * We removed the batch from software schedule only, it's still possible401 * that HC has it in its caches. Better wait a while before we release402 * the buffers.403 */404 async_usleep(20000);405 batch->base.error = EINTR;406 batch->base.transferred_size = 0;407 usb_transfer_batch_finish(&batch->base);408 }409 410 static int device_enumerate(device_t *dev)411 {412 hc_t * const hc = bus_to_hc(dev->bus);413 return usb2_bus_device_enumerate(&hc->bus_helper, dev);414 }415 416 static void device_gone(device_t *dev)417 {418 hc_t * const hc = bus_to_hc(dev->bus);419 usb2_bus_device_gone(&hc->bus_helper, dev);420 }421 422 static int hc_status(bus_t *, uint32_t *);423 static int hc_schedule(usb_transfer_batch_t *);424 425 static const bus_ops_t uhci_bus_ops = {426 .interrupt = hc_interrupt,427 .status = hc_status,428 429 .device_enumerate = device_enumerate,430 .device_gone = device_gone,431 432 .endpoint_create = endpoint_create,433 .endpoint_register = endpoint_register,434 .endpoint_unregister = endpoint_unregister,435 436 .batch_create = create_transfer_batch,437 .batch_schedule = hc_schedule,438 .batch_destroy = destroy_transfer_batch,439 };440 441 310 /** Initialize UHCI hc memory structures. 442 311 * … … 452 321 { 453 322 assert(instance); 454 455 usb2_bus_helper_init(&instance->bus_helper, &bandwidth_accounting_usb11);456 457 bus_init(&instance->bus, sizeof(device_t));458 instance->bus.ops = &uhci_bus_ops;459 460 hc_device_setup(&instance->base, &instance->bus);461 323 462 324 /* Init USB frame list page */ … … 465 327 return ENOMEM; 466 328 } 467 usb_log_debug("Initialized frame list at %p. ", instance->frame_list);329 usb_log_debug("Initialized frame list at %p.\n", instance->frame_list); 468 330 469 331 /* Init transfer lists */ 470 332 errno_t ret = hc_init_transfer_lists(instance); 471 333 if (ret != EOK) { 472 usb_log_error("Failed to initialize transfer lists. ");334 usb_log_error("Failed to initialize transfer lists.\n"); 473 335 return_page(instance->frame_list); 474 336 return ENOMEM; 475 337 } 476 list_initialize(&instance->pending_endpoints); 477 usb_log_debug("Initialized transfer lists."); 338 usb_log_debug("Initialized transfer lists.\n"); 478 339 479 340 … … 505 366 errno_t ret = transfer_list_init(&instance->transfers_##type, name); \ 506 367 if (ret != EOK) { \ 507 usb_log_error("Failed to setup %s transfer list: %s. ", \368 usb_log_error("Failed to setup %s transfer list: %s.\n", \ 508 369 name, str_error(ret)); \ 509 370 transfer_list_fini(&instance->transfers_bulk_full); \ … … 550 411 } 551 412 552 static errno_t hc_status(bus_t *bus, uint32_t *status)553 { 554 hc_t *instance = bus_to_hc(bus);413 errno_t uhci_hc_status(hcd_t *hcd, uint32_t *status) 414 { 415 assert(hcd); 555 416 assert(status); 417 hc_t *instance = hcd_get_driver_data(hcd); 418 assert(instance); 556 419 557 420 *status = 0; … … 564 427 } 565 428 566 /** 567 * Schedule batch for execution. 429 /** Schedule batch for execution. 568 430 * 569 431 * @param[in] instance UHCI structure to use. 570 432 * @param[in] batch Transfer batch to schedule. 571 433 * @return Error code 572 */ 573 static errno_t hc_schedule(usb_transfer_batch_t *batch) 574 { 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 575 447 uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch); 576 endpoint_t *ep = batch->ep; 577 hc_t *hc = bus_to_hc(endpoint_get_bus(ep)); 578 579 if (batch->target.address == uhci_rh_get_address(&hc->rh)) 580 return uhci_rh_schedule(&hc->rh, batch); 581 582 transfer_list_t * const list = 583 hc->transfers[ep->device->speed][ep->transfer_type]; 584 585 if (!list) 586 return ENOTSUP; 587 588 errno_t err; 589 if ((err = uhci_transfer_batch_prepare(uhci_batch))) 590 return err; 591 592 return transfer_list_add_batch(list, uhci_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; 593 459 } 594 460 … … 613 479 614 480 if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) { 615 usb_log_debug2("Command: %X Status: %X Intr: %x ",481 usb_log_debug2("Command: %X Status: %X Intr: %x\n", 616 482 cmd, sts, intr); 617 483 } … … 620 486 pio_read_32(&instance->registers->flbaseadd) & ~0xfff; 621 487 if (frame_list != addr_to_phys(instance->frame_list)) { 622 usb_log_debug("Framelist address: %p vs. %p. ",488 usb_log_debug("Framelist address: %p vs. %p.\n", 623 489 (void *) frame_list, 624 490 (void *) addr_to_phys(instance->frame_list)); … … 631 497 uintptr_t real_pa = addr_to_phys(QH(interrupt)); 632 498 if (expected_pa != real_pa) { 633 usb_log_debug("Interrupt QH: %p (frame %d) vs. %p. ",499 usb_log_debug("Interrupt QH: %p (frame %d) vs. %p.\n", 634 500 (void *) expected_pa, frnum, (void *) real_pa); 635 501 } … … 638 504 real_pa = addr_to_phys(QH(control_slow)); 639 505 if (expected_pa != real_pa) { 640 usb_log_debug("Control Slow QH: %p vs. %p. ",506 usb_log_debug("Control Slow QH: %p vs. %p.\n", 641 507 (void *) expected_pa, (void *) real_pa); 642 508 } … … 645 511 real_pa = addr_to_phys(QH(control_full)); 646 512 if (expected_pa != real_pa) { 647 usb_log_debug("Control Full QH: %p vs. %p. ",513 usb_log_debug("Control Full QH: %p vs. %p.\n", 648 514 (void *) expected_pa, (void *) real_pa); 649 515 } … … 652 518 real_pa = addr_to_phys(QH(bulk_full)); 653 519 if (expected_pa != real_pa ) { 654 usb_log_debug("Bulk QH: %p vs. %p. ",520 usb_log_debug("Bulk QH: %p vs. %p.\n", 655 521 (void *) expected_pa, (void *) real_pa); 656 522 }
Note:
See TracChangeset
for help on using the changeset viewer.