Changes in uspace/drv/bus/usb/uhci/hc.c [b7fd2a0:5a6cc679] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/uhci/hc.c
rb7fd2a0 r5a6cc679 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> 52 54 53 55 #include "uhci_batch.h" 56 #include "transfer_list.h" 54 57 #include "hc.h" 55 58 … … 107 110 * @return Error code. 108 111 */ 109 errno_t uhci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq)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) 110 113 { 111 114 assert(code); … … 140 143 code->cmds[3].addr = (void*)®isters->usbsts; 141 144 142 usb_log_debug("I/O regs at %p (size %zu), IRQ %d. \n",145 usb_log_debug("I/O regs at %p (size %zu), IRQ %d.", 143 146 RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]); 144 147 … … 157 160 * - resume from suspend state (not implemented) 158 161 */ 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); 162 static void hc_interrupt(bus_t *bus, uint32_t status) 163 { 164 hc_t *instance = bus_to_hc(bus); 165 164 166 /* Lower 2 bits are transaction error and transaction complete */ 165 167 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 } 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 183 174 /* Resume interrupts are not supported */ 184 175 if (status & UHCI_STATUS_RESUME) { 185 usb_log_error("Resume interrupt! \n");176 usb_log_error("Resume interrupt!"); 186 177 } 187 178 188 179 /* Bits 4 and 5 indicate hc error */ 189 180 if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) { 190 usb_log_error("UHCI hardware failure!. \n");181 usb_log_error("UHCI hardware failure!."); 191 182 ++instance->hw_failures; 192 183 transfer_list_abort_all(&instance->transfers_interrupt); … … 199 190 hc_init_hw(instance); 200 191 } else { 201 usb_log_fatal("Too many UHCI hardware failures!. \n");202 hc_ fini(instance);192 usb_log_fatal("Too many UHCI hardware failures!."); 193 hc_gone(&instance->base); 203 194 } 204 195 } … … 216 207 * interrupt fibrils. 217 208 */ 218 errno_t hc_ init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)219 { 220 assert(instance);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); 221 212 assert(hw_res); 222 213 if (hw_res->io_ranges.count != 1 || … … 224 215 return EINVAL; 225 216 226 instance->hw_interrupts = interrupts;227 217 instance->hw_failures = 0; 228 218 … … 231 221 (void **) &instance->registers); 232 222 if (ret != EOK) { 233 usb_log_error("Failed to gain access to registers: %s. \n",223 usb_log_error("Failed to gain access to registers: %s.", 234 224 str_error(ret)); 235 225 return ret; 236 226 } 237 227 238 usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible. \n",228 usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.", 239 229 hw_res->io_ranges.ranges[0].address.absolute, 240 230 hw_res->io_ranges.ranges[0].size); … … 242 232 ret = hc_init_mem_structures(instance); 243 233 if (ret != EOK) { 244 usb_log_error("Failed to init UHCI memory structures: %s. \n",234 usb_log_error("Failed to init UHCI memory structures: %s.", 245 235 str_error(ret)); 246 236 // TODO: we should disable pio here … … 248 238 } 249 239 240 return EOK; 241 } 242 243 int hc_start(hc_device_t *hcd) 244 { 245 hc_t *instance = hcd_to_hc(hcd); 250 246 hc_init_hw(instance); 251 247 (void)hc_debug_checker; 252 248 253 uhci_rh_init(&instance->rh, instance->registers->ports, "uhci"); 254 255 return EOK; 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); 256 255 } 257 256 … … 260 259 * @param[in] instance Host controller structure to use. 261 260 */ 262 void hc_fini(hc_t *instance)261 int hc_gone(hc_device_t *instance) 263 262 { 264 263 assert(instance); 265 264 //TODO Implement 265 return ENOTSUP; 266 266 } 267 267 … … 293 293 pio_write_32(®isters->flbaseadd, pa); 294 294 295 if (instance-> hw_interrupts) {295 if (instance->base.irq_cap >= 0) { 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. \n", cmd);303 usb_log_warning("Previous command value: %x.", 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 not 341 * fail early, because that would block any device with these 342 * endpoints from connecting. Instead, make sure these transfers 343 * 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 lists 357 if (ep->device->address == uhci_rh_get_address(&hc->rh)) { 358 // FIXME: We shall check the roothub for active transfer. But 359 // 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 possible 401 * that HC has it in its caches. Better wait a while before we release 402 * 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 310 441 /** Initialize UHCI hc memory structures. 311 442 * … … 321 452 { 322 453 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); 323 461 324 462 /* Init USB frame list page */ … … 327 465 return ENOMEM; 328 466 } 329 usb_log_debug("Initialized frame list at %p. \n", instance->frame_list);467 usb_log_debug("Initialized frame list at %p.", instance->frame_list); 330 468 331 469 /* Init transfer lists */ 332 470 errno_t ret = hc_init_transfer_lists(instance); 333 471 if (ret != EOK) { 334 usb_log_error("Failed to initialize transfer lists. \n");472 usb_log_error("Failed to initialize transfer lists."); 335 473 return_page(instance->frame_list); 336 474 return ENOMEM; 337 475 } 338 usb_log_debug("Initialized transfer lists.\n"); 476 list_initialize(&instance->pending_endpoints); 477 usb_log_debug("Initialized transfer lists."); 339 478 340 479 … … 366 505 errno_t ret = transfer_list_init(&instance->transfers_##type, name); \ 367 506 if (ret != EOK) { \ 368 usb_log_error("Failed to setup %s transfer list: %s. \n", \507 usb_log_error("Failed to setup %s transfer list: %s.", \ 369 508 name, str_error(ret)); \ 370 509 transfer_list_fini(&instance->transfers_bulk_full); \ … … 411 550 } 412 551 413 errno_t uhci_hc_status(hcd_t *hcd, uint32_t *status)414 { 415 assert(hcd);552 static errno_t hc_status(bus_t *bus, uint32_t *status) 553 { 554 hc_t *instance = bus_to_hc(bus); 416 555 assert(status); 417 hc_t *instance = hcd_get_driver_data(hcd);418 assert(instance);419 556 420 557 *status = 0; … … 427 564 } 428 565 429 /** Schedule batch for execution. 566 /** 567 * Schedule batch for execution. 430 568 * 431 569 * @param[in] instance UHCI structure to use. 432 570 * @param[in] batch Transfer batch to schedule. 433 571 * @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 572 */ 573 static errno_t hc_schedule(usb_transfer_batch_t *batch) 574 { 447 575 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; 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); 459 593 } 460 594 … … 479 613 480 614 if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) { 481 usb_log_debug2("Command: %X Status: %X Intr: %x \n",615 usb_log_debug2("Command: %X Status: %X Intr: %x", 482 616 cmd, sts, intr); 483 617 } … … 486 620 pio_read_32(&instance->registers->flbaseadd) & ~0xfff; 487 621 if (frame_list != addr_to_phys(instance->frame_list)) { 488 usb_log_debug("Framelist address: %p vs. %p. \n",622 usb_log_debug("Framelist address: %p vs. %p.", 489 623 (void *) frame_list, 490 624 (void *) addr_to_phys(instance->frame_list)); … … 497 631 uintptr_t real_pa = addr_to_phys(QH(interrupt)); 498 632 if (expected_pa != real_pa) { 499 usb_log_debug("Interrupt QH: %p (frame %d) vs. %p. \n",633 usb_log_debug("Interrupt QH: %p (frame %d) vs. %p.", 500 634 (void *) expected_pa, frnum, (void *) real_pa); 501 635 } … … 504 638 real_pa = addr_to_phys(QH(control_slow)); 505 639 if (expected_pa != real_pa) { 506 usb_log_debug("Control Slow QH: %p vs. %p. \n",640 usb_log_debug("Control Slow QH: %p vs. %p.", 507 641 (void *) expected_pa, (void *) real_pa); 508 642 } … … 511 645 real_pa = addr_to_phys(QH(control_full)); 512 646 if (expected_pa != real_pa) { 513 usb_log_debug("Control Full QH: %p vs. %p. \n",647 usb_log_debug("Control Full QH: %p vs. %p.", 514 648 (void *) expected_pa, (void *) real_pa); 515 649 } … … 518 652 real_pa = addr_to_phys(QH(bulk_full)); 519 653 if (expected_pa != real_pa ) { 520 usb_log_debug("Bulk QH: %p vs. %p. \n",654 usb_log_debug("Bulk QH: %p vs. %p.", 521 655 (void *) expected_pa, (void *) real_pa); 522 656 }
Note:
See TracChangeset
for help on using the changeset viewer.