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