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