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