Changes in uspace/drv/bus/usb/ohci/hc.c [ef9460b:5203e256] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/ohci/hc.c
ref9460b r5203e256 46 46 #define OHCI_USED_INTERRUPTS \ 47 47 (I_SO | I_WDH | I_UE | I_RHSC) 48 49 static const irq_cmd_t ohci_irq_commands[] = 50 { 51 { .cmd = CMD_MEM_READ_32, .dstarg = 1, .addr = NULL /*filled later*/ }, 52 { .cmd = CMD_BTEST, .srcarg = 1, .dstarg = 2, .value = OHCI_USED_INTERRUPTS }, 53 { .cmd = CMD_PREDICATE, .srcarg = 2, .value = 2 }, 54 { .cmd = CMD_MEM_WRITE_A_32, .srcarg = 1, .addr = NULL /*filled later*/ }, 55 { .cmd = CMD_ACCEPT }, 56 }; 57 48 static int interrupt_emulator(hc_t *instance); 58 49 static void hc_gain_control(hc_t *instance); 59 static void hc_start(hc_t *instance);60 50 static int hc_init_transfer_lists(hc_t *instance); 61 51 static int hc_init_memory(hc_t *instance); 62 static int interrupt_emulator(hc_t *instance);63 64 /*----------------------------------------------------------------------------*/65 /** Get number of commands used in IRQ code.66 * @return Number of commands.67 */68 size_t hc_irq_cmd_count(void)69 {70 return sizeof(ohci_irq_commands) / sizeof(irq_cmd_t);71 }72 /*----------------------------------------------------------------------------*/73 /** Generate IRQ code commands.74 * @param[out] cmds Place to store the commands.75 * @param[in] cmd_size Size of the place (bytes).76 * @param[in] regs Physical address of device's registers.77 * @param[in] reg_size Size of the register area (bytes).78 *79 * @return Error code.80 */81 int hc_get_irq_commands(82 irq_cmd_t cmds[], size_t cmd_size, uintptr_t regs, size_t reg_size)83 {84 if (cmd_size < sizeof(ohci_irq_commands)85 || reg_size < sizeof(ohci_regs_t))86 return EOVERFLOW;87 88 /* Create register mapping to use in IRQ handler.89 * This mapping should be present in kernel only.90 * Remove it from here when kernel knows how to create mappings91 * and accepts physical addresses in IRQ code.92 * TODO: remove */93 ohci_regs_t *registers;94 const int ret = pio_enable((void*)regs, reg_size, (void**)®isters);95 if (ret != EOK)96 return ret;97 98 /* Some bogus access to force create mapping. DO NOT remove,99 * unless whole virtual addresses in irq is replaced100 * NOTE: Compiler won't remove this as ohci_regs_t members101 * are declared volatile.102 *103 * Introducing CMD_MEM set of IRQ code commands broke104 * assumption that IRQ code does not cause page faults.105 * If this happens during idling (THREAD == NULL)106 * it causes kernel panic.107 */108 registers->revision;109 110 memcpy(cmds, ohci_irq_commands, sizeof(ohci_irq_commands));111 112 void *address = (void*)®isters->interrupt_status;113 cmds[0].addr = address;114 cmds[3].addr = address;115 return EOK;116 }117 52 /*----------------------------------------------------------------------------*/ 118 53 /** Announce OHCI root hub to the DDF … … 148 83 int ret = hc_add_endpoint(instance, hub_address, 0, USB_SPEED_FULL, 149 84 USB_TRANSFER_CONTROL, USB_DIRECTION_BOTH, 64, 0, 0); 150 CHECK_RET_RELEASE(ret, 151 "Failed to add OHCI root hub endpoint 0: %s.\n", str_error(ret)); 152 153 ret = ddf_fun_add_match_id(hub_fun, "usb&class=hub", 100); 154 CHECK_RET_RELEASE(ret, 155 "Failed to add root hub match-id: %s.\n", str_error(ret)); 85 CHECK_RET_RELEASE(ret, "Failed(%d) to add OHCI rh endpoint 0.\n", ret); 86 87 char *match_str = NULL; 88 /* DDF needs heap allocated string */ 89 ret = asprintf(&match_str, "usb&class=hub"); 90 ret = ret > 0 ? 0 : ret; 91 CHECK_RET_RELEASE(ret, "Failed(%d) to create match-id string.\n", ret); 92 93 ret = ddf_fun_add_match_id(hub_fun, match_str, 100); 94 CHECK_RET_RELEASE(ret, "Failed(%d) add root hub match-id.\n", ret); 156 95 157 96 ret = ddf_fun_bind(hub_fun); 158 CHECK_RET_RELEASE(ret, 159 "Failed to bind root hub function: %s.\n", str_error(ret)); 97 CHECK_RET_RELEASE(ret, "Failed(%d) to bind root hub function.\n", ret); 160 98 161 99 return EOK; … … 174 112 { 175 113 assert(instance); 176 114 int ret = EOK; 177 115 #define CHECK_RET_RETURN(ret, message...) \ 178 116 if (ret != EOK) { \ … … 181 119 } else (void)0 182 120 183 int ret = 184 pio_enable((void*)regs, reg_size, (void**)&instance->registers); 121 ret = pio_enable((void*)regs, reg_size, (void**)&instance->registers); 185 122 CHECK_RET_RETURN(ret, 186 "Failed to gain access to device registers: %s.\n", str_error(ret)); 123 "Failed(%d) to gain access to device registers: %s.\n", 124 ret, str_error(ret)); 187 125 188 126 list_initialize(&instance->pending_batches); 189 127 usb_device_keeper_init(&instance->manager); 190 191 128 ret = usb_endpoint_manager_init(&instance->ep_manager, 192 129 BANDWIDTH_AVAILABLE_USB11); … … 200 137 201 138 fibril_mutex_initialize(&instance->guard); 202 203 139 hc_gain_control(instance); 140 141 rh_init(&instance->rh, instance->registers); 204 142 205 143 if (!interrupts) { … … 209 147 } 210 148 211 rh_init(&instance->rh, instance->registers);212 hc_start(instance);213 214 149 return EOK; 215 150 } 216 151 /*----------------------------------------------------------------------------*/ 217 /** Create and register endpoint structures.152 /** Create end register endpoint structures 218 153 * 219 154 * @param[in] instance OHCI driver structure. … … 233 168 size_t mps, size_t size, unsigned interval) 234 169 { 235 endpoint_t *ep = 236 endpoint_get(address, endpoint, direction, type, speed, mps); 170 endpoint_t *ep = malloc(sizeof(endpoint_t)); 237 171 if (ep == NULL) 238 172 return ENOMEM; 173 int ret = 174 endpoint_init(ep, address, endpoint, direction, type, speed, mps); 175 if (ret != EOK) { 176 free(ep); 177 return ret; 178 } 239 179 240 180 hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep); … … 244 184 } 245 185 246 int ret = 247 usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size); 186 ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size); 248 187 if (ret != EOK) { 249 188 hcd_endpoint_clear(ep); … … 273 212 &instance->lists[ep->transfer_type], hcd_ep); 274 213 instance->registers->control |= C_PLE | C_IE; 214 break; 215 default: 275 216 break; 276 217 } … … 371 312 /* Check for root hub communication */ 372 313 if (batch->ep->address == instance->rh.address) { 373 rh_request(&instance->rh, batch); 374 return EOK; 314 return rh_request(&instance->rh, batch); 375 315 } 376 316 … … 434 374 435 375 if (status & I_UE) { 436 hc_start (instance);376 hc_start_hw(instance); 437 377 } 438 378 … … 459 399 /** Turn off any (BIOS)driver that might be in control of the device. 460 400 * 461 * This function implements routines described in chapter 5.1.1.3 of the OHCI462 * specification (page 40, pdf page 54).463 *464 401 * @param[in] instance OHCI hc driver structure. 465 402 */ … … 467 404 { 468 405 assert(instance); 469 470 406 usb_log_debug("Requesting OHCI control.\n"); 471 if (instance->registers->revision & R_LEGACY_FLAG) { 472 /* Turn off legacy emulation, it should be enough to zero 473 * the lowest bit, but it caused problems. Thus clear all 474 * except GateA20 (causes restart on some hw). 475 * See page 145 of the specs for details. 476 */ 477 volatile uint32_t *ohci_emulation_reg = 478 (uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET); 479 usb_log_debug("OHCI legacy register %p: %x.\n", 480 ohci_emulation_reg, *ohci_emulation_reg); 481 /* Zero everything but A20State */ 482 *ohci_emulation_reg &= 0x100; 483 usb_log_debug( 484 "OHCI legacy register (should be 0 or 0x100) %p: %x.\n", 485 ohci_emulation_reg, *ohci_emulation_reg); 486 } 407 /* Turn off legacy emulation */ 408 volatile uint32_t *ohci_emulation_reg = 409 (uint32_t*)((char*)instance->registers + 0x100); 410 usb_log_debug("OHCI legacy register %p: %x.\n", 411 ohci_emulation_reg, *ohci_emulation_reg); 412 /* Do not change A20 state */ 413 *ohci_emulation_reg &= 0x100; 414 usb_log_debug("OHCI legacy register %p: %x.\n", 415 ohci_emulation_reg, *ohci_emulation_reg); 487 416 488 417 /* Interrupt routing enabled => smm driver is active */ … … 490 419 usb_log_debug("SMM driver: request ownership change.\n"); 491 420 instance->registers->command_status |= CS_OCR; 492 /* Hope that SMM actually knows its stuff or we can hang here */493 421 while (instance->registers->control & C_IR) { 494 422 async_usleep(1000); 495 423 } 496 424 usb_log_info("SMM driver: Ownership taken.\n"); 497 C_HCFS_SET(instance->registers->control, C_HCFS_RESET);425 instance->registers->control &= (C_HCFS_RESET << C_HCFS_SHIFT); 498 426 async_usleep(50000); 499 427 return; 500 428 } 501 429 502 const unsigned hc_status = C_HCFS_GET(instance->registers->control); 430 const unsigned hc_status = 431 (instance->registers->control >> C_HCFS_SHIFT) & C_HCFS_MASK; 503 432 /* Interrupt routing disabled && status != USB_RESET => BIOS active */ 504 433 if (hc_status != C_HCFS_RESET) { … … 508 437 return; 509 438 } 510 /* HC is suspended assert resume for 20ms ,*/511 C_HCFS_SET(instance->registers->control, C_HCFS_RESUME);439 /* HC is suspended assert resume for 20ms */ 440 instance->registers->control &= (C_HCFS_RESUME << C_HCFS_SHIFT); 512 441 async_usleep(20000); 513 442 usb_log_info("BIOS driver: HC resumed.\n"); … … 525 454 * @param[in] instance OHCI hc driver structure. 526 455 */ 527 void hc_start (hc_t *instance)456 void hc_start_hw(hc_t *instance) 528 457 { 529 458 /* OHCI guide page 42 */ … … 587 516 instance->registers->periodic_start, frame_length); 588 517 589 C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL);518 instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT); 590 519 usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n", 591 520 instance->registers->control); … … 605 534 int ret = endpoint_list_init(&instance->lists[type], name); \ 606 535 if (ret != EOK) { \ 607 usb_log_error("Failed to setup %s endpoint list: %s.\n", \608 name, str_error(ret)); \536 usb_log_error("Failed(%d) to setup %s endpoint list.\n", \ 537 ret, name); \ 609 538 endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\ 610 539 endpoint_list_fini(&instance->lists[USB_TRANSFER_INTERRUPT]); \ … … 658 587 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa); 659 588 589 /* Init interrupt code */ 590 instance->interrupt_code.cmds = instance->interrupt_commands; 591 instance->interrupt_code.cmdcount = OHCI_NEEDED_IRQ_COMMANDS; 592 { 593 /* Read status register */ 594 instance->interrupt_commands[0].cmd = CMD_MEM_READ_32; 595 instance->interrupt_commands[0].dstarg = 1; 596 instance->interrupt_commands[0].addr = 597 (void*)&instance->registers->interrupt_status; 598 599 /* Test whether we are the interrupt cause */ 600 instance->interrupt_commands[1].cmd = CMD_BTEST; 601 instance->interrupt_commands[1].value = 602 OHCI_USED_INTERRUPTS; 603 instance->interrupt_commands[1].srcarg = 1; 604 instance->interrupt_commands[1].dstarg = 2; 605 606 /* Predicate cleaning and accepting */ 607 instance->interrupt_commands[2].cmd = CMD_PREDICATE; 608 instance->interrupt_commands[2].value = 2; 609 instance->interrupt_commands[2].srcarg = 2; 610 611 /* Write-clean status register */ 612 instance->interrupt_commands[3].cmd = CMD_MEM_WRITE_A_32; 613 instance->interrupt_commands[3].srcarg = 1; 614 instance->interrupt_commands[3].addr = 615 (void*)&instance->registers->interrupt_status; 616 617 /* Accept interrupt */ 618 instance->interrupt_commands[4].cmd = CMD_ACCEPT; 619 } 620 660 621 return EOK; 661 622 } 662 663 623 /** 664 624 * @}
Note:
See TracChangeset
for help on using the changeset viewer.