Changes in uspace/drv/bus/usb/ohci/hc.c [5d36062:5203e256] in mainline
- File:
-
- 1 edited
-
uspace/drv/bus/usb/ohci/hc.c (modified) (19 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/ohci/hc.c
r5d36062 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)); 85 CHECK_RET_RELEASE(ret, "Failed(%d) to add OHCI rh endpoint 0.\n", ret); 152 86 153 87 char *match_str = NULL; 154 /* DDF needs heap allocated string .*/88 /* DDF needs heap allocated string */ 155 89 ret = asprintf(&match_str, "usb&class=hub"); 156 90 ret = ret > 0 ? 0 : ret; 157 CHECK_RET_RELEASE(ret, 158 "Failed to create match-id string: %s.\n", str_error(ret)); 91 CHECK_RET_RELEASE(ret, "Failed(%d) to create match-id string.\n", ret); 159 92 160 93 ret = ddf_fun_add_match_id(hub_fun, match_str, 100); 161 CHECK_RET_RELEASE(ret, 162 "Failed to add root hub match-id: %s.\n", str_error(ret)); 94 CHECK_RET_RELEASE(ret, "Failed(%d) add root hub match-id.\n", ret); 163 95 164 96 ret = ddf_fun_bind(hub_fun); 165 CHECK_RET_RELEASE(ret, 166 "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); 167 98 168 99 return EOK; … … 181 112 { 182 113 assert(instance); 183 114 int ret = EOK; 184 115 #define CHECK_RET_RETURN(ret, message...) \ 185 116 if (ret != EOK) { \ … … 188 119 } else (void)0 189 120 190 int ret = 191 pio_enable((void*)regs, reg_size, (void**)&instance->registers); 121 ret = pio_enable((void*)regs, reg_size, (void**)&instance->registers); 192 122 CHECK_RET_RETURN(ret, 193 "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)); 194 125 195 126 list_initialize(&instance->pending_batches); 196 127 usb_device_keeper_init(&instance->manager); 197 198 128 ret = usb_endpoint_manager_init(&instance->ep_manager, 199 129 BANDWIDTH_AVAILABLE_USB11); … … 207 137 208 138 fibril_mutex_initialize(&instance->guard); 209 210 139 hc_gain_control(instance); 140 141 rh_init(&instance->rh, instance->registers); 211 142 212 143 if (!interrupts) { … … 216 147 } 217 148 218 rh_init(&instance->rh, instance->registers);219 hc_start(instance);220 221 149 return EOK; 222 150 } 223 151 /*----------------------------------------------------------------------------*/ 224 /** Create and register endpoint structures.152 /** Create end register endpoint structures 225 153 * 226 154 * @param[in] instance OHCI driver structure. … … 240 168 size_t mps, size_t size, unsigned interval) 241 169 { 242 endpoint_t *ep = 243 endpoint_get(address, endpoint, direction, type, speed, mps); 170 endpoint_t *ep = malloc(sizeof(endpoint_t)); 244 171 if (ep == NULL) 245 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 } 246 179 247 180 hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep); … … 251 184 } 252 185 253 int ret = 254 usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size); 186 ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size); 255 187 if (ret != EOK) { 256 188 hcd_endpoint_clear(ep); … … 280 212 &instance->lists[ep->transfer_type], hcd_ep); 281 213 instance->registers->control |= C_PLE | C_IE; 214 break; 215 default: 282 216 break; 283 217 } … … 378 312 /* Check for root hub communication */ 379 313 if (batch->ep->address == instance->rh.address) { 380 rh_request(&instance->rh, batch); 381 return EOK; 314 return rh_request(&instance->rh, batch); 382 315 } 383 316 … … 441 374 442 375 if (status & I_UE) { 443 hc_start (instance);376 hc_start_hw(instance); 444 377 } 445 378 … … 466 399 /** Turn off any (BIOS)driver that might be in control of the device. 467 400 * 468 * This function implements routines described in chapter 5.1.1.3 of the OHCI469 * specification (page 40, pdf page 54).470 *471 401 * @param[in] instance OHCI hc driver structure. 472 402 */ … … 474 404 { 475 405 assert(instance); 476 477 406 usb_log_debug("Requesting OHCI control.\n"); 478 if (instance->registers->revision & R_LEGACY_FLAG) { 479 /* Turn off legacy emulation, it should be enough to zero 480 * the lowest bit, but it caused problems. Thus clear all 481 * except GateA20 (causes restart on some hw). 482 * See page 145 of the specs for details. 483 */ 484 volatile uint32_t *ohci_emulation_reg = 485 (uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET); 486 usb_log_debug("OHCI legacy register %p: %x.\n", 487 ohci_emulation_reg, *ohci_emulation_reg); 488 /* Zero everything but A20State */ 489 *ohci_emulation_reg &= 0x100; 490 usb_log_debug( 491 "OHCI legacy register (should be 0 or 0x100) %p: %x.\n", 492 ohci_emulation_reg, *ohci_emulation_reg); 493 } 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); 494 416 495 417 /* Interrupt routing enabled => smm driver is active */ … … 497 419 usb_log_debug("SMM driver: request ownership change.\n"); 498 420 instance->registers->command_status |= CS_OCR; 499 /* Hope that SMM actually knows its stuff or we can hang here */500 421 while (instance->registers->control & C_IR) { 501 422 async_usleep(1000); 502 423 } 503 424 usb_log_info("SMM driver: Ownership taken.\n"); 504 C_HCFS_SET(instance->registers->control, C_HCFS_RESET);425 instance->registers->control &= (C_HCFS_RESET << C_HCFS_SHIFT); 505 426 async_usleep(50000); 506 427 return; 507 428 } 508 429 509 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; 510 432 /* Interrupt routing disabled && status != USB_RESET => BIOS active */ 511 433 if (hc_status != C_HCFS_RESET) { … … 515 437 return; 516 438 } 517 /* HC is suspended assert resume for 20ms ,*/518 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); 519 441 async_usleep(20000); 520 442 usb_log_info("BIOS driver: HC resumed.\n"); … … 532 454 * @param[in] instance OHCI hc driver structure. 533 455 */ 534 void hc_start (hc_t *instance)456 void hc_start_hw(hc_t *instance) 535 457 { 536 458 /* OHCI guide page 42 */ … … 594 516 instance->registers->periodic_start, frame_length); 595 517 596 C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL);518 instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT); 597 519 usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n", 598 520 instance->registers->control); … … 612 534 int ret = endpoint_list_init(&instance->lists[type], name); \ 613 535 if (ret != EOK) { \ 614 usb_log_error("Failed to setup %s endpoint list: %s.\n", \615 name, str_error(ret)); \536 usb_log_error("Failed(%d) to setup %s endpoint list.\n", \ 537 ret, name); \ 616 538 endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\ 617 539 endpoint_list_fini(&instance->lists[USB_TRANSFER_INTERRUPT]); \ … … 665 587 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa); 666 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 667 621 return EOK; 668 622 } 669 670 623 /** 671 624 * @}
Note:
See TracChangeset
for help on using the changeset viewer.
