Changes in uspace/drv/bus/usb/ohci/hc.c [b7fd2a0:5a6cc679] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/ohci/hc.c
rb7fd2a0 r5a6cc679 45 45 46 46 #include <usb/debug.h> 47 #include <usb/host/utility.h> 47 48 #include <usb/usb.h> 48 49 49 #include "ohci_ endpoint.h"50 #include "ohci_bus.h" 50 51 #include "ohci_batch.h" 51 52 … … 89 90 }; 90 91 91 static void hc_gain_control(hc_t *instance);92 static void hc_start(hc_t *instance);93 92 static errno_t hc_init_transfer_lists(hc_t *instance); 94 93 static errno_t hc_init_memory(hc_t *instance); … … 103 102 * @return Error code. 104 103 */ 105 errno_t ohci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq)104 errno_t hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq) 106 105 { 107 106 assert(code); … … 138 137 OHCI_WR(code->cmds[1].value, OHCI_USED_INTERRUPTS); 139 138 140 usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d. \n",139 usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.", 141 140 RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]); 142 141 … … 152 151 * @return Error code 153 152 */ 154 errno_t hc_ init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)155 { 156 assert(instance);153 errno_t hc_add(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res) 154 { 155 hc_t *instance = hcd_to_hc(hcd); 157 156 assert(hw_res); 158 157 if (hw_res->mem_ranges.count != 1 || … … 163 162 (void **) &instance->registers); 164 163 if (ret != EOK) { 165 usb_log_error("Failed to gain access to registers: %s. \n",164 usb_log_error("Failed to gain access to registers: %s.", 166 165 str_error(ret)); 167 166 return ret; 168 167 } 169 usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible. \n",168 usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.", 170 169 hw_res->mem_ranges.ranges[0].address.absolute, 171 170 hw_res->mem_ranges.ranges[0].size); 172 171 173 list_initialize(&instance->pending_ batches);172 list_initialize(&instance->pending_endpoints); 174 173 fibril_mutex_initialize(&instance->guard); 175 instance->hw_interrupts = interrupts;176 174 177 175 ret = hc_init_memory(instance); 178 176 if (ret != EOK) { 179 usb_log_error("Failed to create OHCI memory structures: %s. \n",177 usb_log_error("Failed to create OHCI memory structures: %s.", 180 178 str_error(ret)); 181 179 // TODO: We should disable pio access here … … 183 181 } 184 182 185 hc_gain_control(instance);186 187 ohci_rh_init(&instance->rh, instance->registers, "ohci rh");188 hc_start(instance);189 190 183 return EOK; 191 184 } … … 195 188 * @param[in] instance Host controller structure to use. 196 189 */ 197 void hc_fini(hc_t *instance)190 int hc_gone(hc_device_t *instance) 198 191 { 199 192 assert(instance); 200 193 /* TODO: implement*/ 201 }; 194 return ENOTSUP; 195 } 202 196 203 197 void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep) … … 269 263 } 270 264 271 errno_t ohci_hc_status( hcd_t *hcd, uint32_t *status)272 { 273 assert( hcd);265 errno_t ohci_hc_status(bus_t *bus_base, uint32_t *status) 266 { 267 assert(bus_base); 274 268 assert(status); 275 hc_t *instance = hcd_get_driver_data(hcd); 276 assert(instance); 277 278 if (instance->registers){ 279 *status = OHCI_RD(instance->registers->interrupt_status); 280 OHCI_WR(instance->registers->interrupt_status, *status); 269 270 ohci_bus_t *bus = (ohci_bus_t *) bus_base; 271 hc_t *hc = bus->hc; 272 assert(hc); 273 274 if (hc->registers){ 275 *status = OHCI_RD(hc->registers->interrupt_status); 276 OHCI_WR(hc->registers->interrupt_status, *status); 281 277 } 282 278 return EOK; … … 289 285 * @return Error code. 290 286 */ 291 errno_t ohci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch) 292 { 293 assert(hcd); 294 hc_t *instance = hcd_get_driver_data(hcd); 295 assert(instance); 287 errno_t ohci_hc_schedule(usb_transfer_batch_t *batch) 288 { 289 assert(batch); 290 291 ohci_bus_t *bus = (ohci_bus_t *) endpoint_get_bus(batch->ep); 292 hc_t *hc = bus->hc; 293 assert(hc); 296 294 297 295 /* Check for root hub communication */ 298 if (batch->ep->address == ohci_rh_get_address(&instance->rh)) { 299 usb_log_debug("OHCI root hub request.\n"); 300 return ohci_rh_schedule(&instance->rh, batch); 301 } 296 if (batch->target.address == ohci_rh_get_address(&hc->rh)) { 297 usb_log_debug("OHCI root hub request."); 298 return ohci_rh_schedule(&hc->rh, batch); 299 } 300 301 endpoint_t *ep = batch->ep; 302 ohci_endpoint_t * const ohci_ep = ohci_endpoint_get(ep); 302 303 ohci_transfer_batch_t *ohci_batch = ohci_transfer_batch_get(batch); 303 if (!ohci_batch) 304 return ENOMEM; 305 306 fibril_mutex_lock(&instance->guard); 307 list_append(&ohci_batch->link, &instance->pending_batches); 304 int err; 305 306 fibril_mutex_lock(&hc->guard); 307 if ((err = endpoint_activate_locked(ep, batch))) { 308 fibril_mutex_unlock(&hc->guard); 309 return err; 310 } 311 312 if ((err = ohci_transfer_batch_prepare(ohci_batch))) 313 return err; 314 308 315 ohci_transfer_batch_commit(ohci_batch); 316 list_append(&ohci_ep->pending_link, &hc->pending_endpoints); 317 fibril_mutex_unlock(&hc->guard); 309 318 310 319 /* Control and bulk schedules need a kick to start working */ … … 312 321 { 313 322 case USB_TRANSFER_CONTROL: 314 OHCI_SET( instance->registers->command_status, CS_CLF);323 OHCI_SET(hc->registers->command_status, CS_CLF); 315 324 break; 316 325 case USB_TRANSFER_BULK: 317 OHCI_SET( instance->registers->command_status, CS_BLF);326 OHCI_SET(hc->registers->command_status, CS_BLF); 318 327 break; 319 328 default: 320 329 break; 321 330 } 322 fibril_mutex_unlock(&instance->guard); 331 323 332 return EOK; 324 333 } … … 329 338 * @param[in] status Value of the status register at the time of interrupt. 330 339 */ 331 void ohci_hc_interrupt(hcd_t *hcd, uint32_t status) 332 { 333 assert(hcd); 334 hc_t *instance = hcd_get_driver_data(hcd); 340 void ohci_hc_interrupt(bus_t *bus_base, uint32_t status) 341 { 342 assert(bus_base); 343 344 ohci_bus_t *bus = (ohci_bus_t *) bus_base; 345 hc_t *hc = bus->hc; 346 assert(hc); 347 335 348 status = OHCI_RD(status); 336 assert( instance);349 assert(hc); 337 350 if ((status & ~I_SF) == 0) /* ignore sof status */ 338 351 return; 339 usb_log_debug2("OHCI(%p) interrupt: %x. \n", instance, status);352 usb_log_debug2("OHCI(%p) interrupt: %x.", hc, status); 340 353 if (status & I_RHSC) 341 ohci_rh_interrupt(& instance->rh);354 ohci_rh_interrupt(&hc->rh); 342 355 343 356 if (status & I_WDH) { 344 fibril_mutex_lock(&instance->guard); 345 usb_log_debug2("HCCA: %p-%#" PRIx32 " (%p).\n", instance->hcca, 346 OHCI_RD(instance->registers->hcca), 347 (void *) addr_to_phys(instance->hcca)); 348 usb_log_debug2("Periodic current: %#" PRIx32 ".\n", 349 OHCI_RD(instance->registers->periodic_current)); 350 351 link_t *current = list_first(&instance->pending_batches); 352 while (current && current != &instance->pending_batches.head) { 353 link_t *next = current->next; 354 ohci_transfer_batch_t *batch = 355 ohci_transfer_batch_from_link(current); 356 357 if (ohci_transfer_batch_is_complete(batch)) { 357 fibril_mutex_lock(&hc->guard); 358 usb_log_debug2("HCCA: %p-%#" PRIx32 " (%p).", hc->hcca, 359 OHCI_RD(hc->registers->hcca), 360 (void *) addr_to_phys(hc->hcca)); 361 usb_log_debug2("Periodic current: %#" PRIx32 ".", 362 OHCI_RD(hc->registers->periodic_current)); 363 364 list_foreach_safe(hc->pending_endpoints, current, next) { 365 ohci_endpoint_t *ep 366 = list_get_instance(current, ohci_endpoint_t, pending_link); 367 368 ohci_transfer_batch_t *batch 369 = ohci_transfer_batch_get(ep->base.active_batch); 370 assert(batch); 371 372 if (ohci_transfer_batch_check_completed(batch)) { 373 endpoint_deactivate_locked(&ep->base); 358 374 list_remove(current); 359 ohci_transfer_batch_finish_dispose(batch); 375 hc_reset_toggles(&batch->base, &ohci_ep_toggle_reset); 376 usb_transfer_batch_finish(&batch->base); 360 377 } 361 362 current = next;363 378 } 364 fibril_mutex_unlock(& instance->guard);379 fibril_mutex_unlock(&hc->guard); 365 380 } 366 381 367 382 if (status & I_UE) { 368 usb_log_fatal("Error like no other! \n");369 hc_start( instance);383 usb_log_fatal("Error like no other!"); 384 hc_start(&hc->base); 370 385 } 371 386 … … 379 394 * @param[in] instance OHCI hc driver structure. 380 395 */ 381 void hc_gain_control(hc_t *instance)382 { 383 assert(instance);384 385 usb_log_debug("Requesting OHCI control. \n");396 int hc_gain_control(hc_device_t *hcd) 397 { 398 hc_t *instance = hcd_to_hc(hcd); 399 400 usb_log_debug("Requesting OHCI control."); 386 401 if (OHCI_RD(instance->registers->revision) & R_LEGACY_FLAG) { 387 402 /* Turn off legacy emulation, it should be enough to zero … … 392 407 volatile uint32_t *ohci_emulation_reg = 393 408 (uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET); 394 usb_log_debug("OHCI legacy register %p: %x. \n",409 usb_log_debug("OHCI legacy register %p: %x.", 395 410 ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg)); 396 411 /* Zero everything but A20State */ … … 398 413 OHCI_CLR(*ohci_emulation_reg, ~0x100); 399 414 usb_log_debug( 400 "OHCI legacy register (should be 0 or 0x100) %p: %x. \n",415 "OHCI legacy register (should be 0 or 0x100) %p: %x.", 401 416 ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg)); 402 417 } … … 404 419 /* Interrupt routing enabled => smm driver is active */ 405 420 if (OHCI_RD(instance->registers->control) & C_IR) { 406 usb_log_debug("SMM driver: request ownership change. \n");421 usb_log_debug("SMM driver: request ownership change."); 407 422 // TODO: should we ack interrupts before doing this? 408 423 OHCI_SET(instance->registers->command_status, CS_OCR); … … 411 426 async_usleep(1000); 412 427 } 413 usb_log_info("SMM driver: Ownership taken. \n");428 usb_log_info("SMM driver: Ownership taken."); 414 429 C_HCFS_SET(instance->registers->control, C_HCFS_RESET); 415 430 async_usleep(50000); 416 return ;431 return EOK; 417 432 } 418 433 … … 420 435 /* Interrupt routing disabled && status != USB_RESET => BIOS active */ 421 436 if (hc_status != C_HCFS_RESET) { 422 usb_log_debug("BIOS driver found. \n");437 usb_log_debug("BIOS driver found."); 423 438 if (hc_status == C_HCFS_OPERATIONAL) { 424 usb_log_info("BIOS driver: HC operational. \n");425 return ;439 usb_log_info("BIOS driver: HC operational."); 440 return EOK; 426 441 } 427 442 /* HC is suspended assert resume for 20ms */ 428 443 C_HCFS_SET(instance->registers->control, C_HCFS_RESUME); 429 444 async_usleep(20000); 430 usb_log_info("BIOS driver: HC resumed. \n");431 return ;445 usb_log_info("BIOS driver: HC resumed."); 446 return EOK; 432 447 } 433 448 434 449 /* HC is in reset (hw startup) => no other driver 435 450 * maintain reset for at least the time specified in USB spec (50 ms)*/ 436 usb_log_debug("Host controller found in reset state. \n");451 usb_log_debug("Host controller found in reset state."); 437 452 async_usleep(50000); 453 return EOK; 438 454 } 439 455 … … 442 458 * @param[in] instance OHCI hc driver structure. 443 459 */ 444 void hc_start(hc_t *instance) 445 { 460 int hc_start(hc_device_t *hcd) 461 { 462 hc_t *instance = hcd_to_hc(hcd); 463 ohci_rh_init(&instance->rh, instance->registers, &instance->guard, "ohci rh"); 464 446 465 /* OHCI guide page 42 */ 447 466 assert(instance); 448 usb_log_debug2("Started hc initialization routine. \n");467 usb_log_debug2("Started hc initialization routine."); 449 468 450 469 /* Save contents of fm_interval register */ 451 470 const uint32_t fm_interval = OHCI_RD(instance->registers->fm_interval); 452 usb_log_debug2("Old value of HcFmInterval: %x. \n", fm_interval);471 usb_log_debug2("Old value of HcFmInterval: %x.", fm_interval); 453 472 454 473 /* Reset hc */ 455 usb_log_debug2("HC reset. \n");474 usb_log_debug2("HC reset."); 456 475 size_t time = 0; 457 476 OHCI_WR(instance->registers->command_status, CS_HCR); … … 460 479 time += 10; 461 480 } 462 usb_log_debug2("HC reset complete in %zu us. \n", time);481 usb_log_debug2("HC reset complete in %zu us.", time); 463 482 464 483 /* Restore fm_interval */ … … 467 486 468 487 /* hc is now in suspend state */ 469 usb_log_debug2("HC should be in suspend state(%x). \n",488 usb_log_debug2("HC should be in suspend state(%x).", 470 489 OHCI_RD(instance->registers->control)); 471 490 … … 476 495 OHCI_WR(instance->registers->bulk_head, 477 496 instance->lists[USB_TRANSFER_BULK].list_head_pa); 478 usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 "). \n",497 usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 ").", 479 498 instance->lists[USB_TRANSFER_BULK].list_head, 480 499 instance->lists[USB_TRANSFER_BULK].list_head_pa); … … 482 501 OHCI_WR(instance->registers->control_head, 483 502 instance->lists[USB_TRANSFER_CONTROL].list_head_pa); 484 usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 "). \n",503 usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 ").", 485 504 instance->lists[USB_TRANSFER_CONTROL].list_head, 486 505 instance->lists[USB_TRANSFER_CONTROL].list_head_pa); … … 488 507 /* Enable queues */ 489 508 OHCI_SET(instance->registers->control, (C_PLE | C_IE | C_CLE | C_BLE)); 490 usb_log_debug("Queues enabled(%x). \n",509 usb_log_debug("Queues enabled(%x).", 491 510 OHCI_RD(instance->registers->control)); 492 511 493 512 /* Enable interrupts */ 494 if (instance-> hw_interrupts) {513 if (instance->base.irq_cap >= 0) { 495 514 OHCI_WR(instance->registers->interrupt_enable, 496 515 OHCI_USED_INTERRUPTS); 497 usb_log_debug("Enabled interrupts: %x. \n",516 usb_log_debug("Enabled interrupts: %x.", 498 517 OHCI_RD(instance->registers->interrupt_enable)); 499 518 OHCI_WR(instance->registers->interrupt_enable, I_MI); … … 505 524 OHCI_WR(instance->registers->periodic_start, 506 525 ((frame_length / 10) * 9) & PS_MASK << PS_SHIFT); 507 usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d). \n",526 usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).", 508 527 OHCI_RD(instance->registers->periodic_start), 509 528 OHCI_RD(instance->registers->periodic_start), frame_length); 510 529 C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL); 511 usb_log_debug("OHCI HC up and running (ctl_reg=0x%x). \n",530 usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).", 512 531 OHCI_RD(instance->registers->control)); 532 533 return EOK; 534 } 535 536 /** 537 * Setup roothub as a virtual hub. 538 */ 539 int hc_setup_roothub(hc_device_t *hcd) 540 { 541 return hc_setup_virtual_root_hub(hcd, USB_SPEED_FULL); 513 542 } 514 543 … … 526 555 const errno_t ret = endpoint_list_init(&instance->lists[type], name); \ 527 556 if (ret != EOK) { \ 528 usb_log_error("Failed to setup %s endpoint list: %s. \n", \557 usb_log_error("Failed to setup %s endpoint list: %s.", \ 529 558 name, str_error(ret)); \ 530 559 endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\ … … 558 587 memset(&instance->rh, 0, sizeof(instance->rh)); 559 588 /* Init queues */ 560 consterrno_t ret = hc_init_transfer_lists(instance);589 errno_t ret = hc_init_transfer_lists(instance); 561 590 if (ret != EOK) { 562 591 return ret; … … 567 596 if (instance->hcca == NULL) 568 597 return ENOMEM; 569 usb_log_debug2("OHCI HCCA initialized at %p. \n", instance->hcca);598 usb_log_debug2("OHCI HCCA initialized at %p.", instance->hcca); 570 599 571 600 for (unsigned i = 0; i < HCCA_INT_EP_COUNT; ++i) { … … 573 602 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa); 574 603 } 575 usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 "). \n",604 usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 ").", 576 605 instance->lists[USB_TRANSFER_INTERRUPT].list_head, 577 606 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa); 578 607 608 if ((ret = ohci_bus_init(&instance->bus, instance))) { 609 usb_log_error("HC(%p): Failed to setup bus : %s", 610 instance, str_error(ret)); 611 return ret; 612 } 613 614 hc_device_setup(&instance->base, (bus_t *) &instance->bus); 615 579 616 return EOK; 580 617 }
Note:
See TracChangeset
for help on using the changeset viewer.