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