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