Changeset 159100a in mainline for uspace/drv/bus/usb/ohci/hc.c
- Timestamp:
- 2011-07-13T22:19:26Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- ef9460b
- Parents:
- 3e5c48c9 (diff), 5d36062 (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. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/ohci/hc.c
r3e5c48c9 r159100a 46 46 #define OHCI_USED_INTERRUPTS \ 47 47 (I_SO | I_WDH | I_UE | I_RHSC) 48 static int interrupt_emulator(hc_t *instance); 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 49 58 static void hc_gain_control(hc_t *instance); 59 static void hc_start(hc_t *instance); 50 60 static int hc_init_transfer_lists(hc_t *instance); 51 61 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 mappings 91 * 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 replaced 100 * NOTE: Compiler won't remove this as ohci_regs_t members 101 * are declared volatile. 102 * 103 * Introducing CMD_MEM set of IRQ code commands broke 104 * 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 } 52 117 /*----------------------------------------------------------------------------*/ 53 118 /** Announce OHCI root hub to the DDF … … 83 148 int ret = hc_add_endpoint(instance, hub_address, 0, USB_SPEED_FULL, 84 149 USB_TRANSFER_CONTROL, USB_DIRECTION_BOTH, 64, 0, 0); 85 CHECK_RET_RELEASE(ret, "Failed(%d) to add OHCI rh endpoint 0.\n", ret); 150 CHECK_RET_RELEASE(ret, 151 "Failed to add OHCI root hub endpoint 0: %s.\n", str_error(ret)); 86 152 87 153 char *match_str = NULL; 88 /* DDF needs heap allocated string */154 /* DDF needs heap allocated string. */ 89 155 ret = asprintf(&match_str, "usb&class=hub"); 90 156 ret = ret > 0 ? 0 : ret; 91 CHECK_RET_RELEASE(ret, "Failed(%d) to create match-id string.\n", ret); 157 CHECK_RET_RELEASE(ret, 158 "Failed to create match-id string: %s.\n", str_error(ret)); 92 159 93 160 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); 161 CHECK_RET_RELEASE(ret, 162 "Failed to add root hub match-id: %s.\n", str_error(ret)); 95 163 96 164 ret = ddf_fun_bind(hub_fun); 97 CHECK_RET_RELEASE(ret, "Failed(%d) to bind root hub function.\n", ret); 165 CHECK_RET_RELEASE(ret, 166 "Failed to bind root hub function: %s.\n", str_error(ret)); 98 167 99 168 return EOK; … … 112 181 { 113 182 assert(instance); 114 int ret = EOK; 183 115 184 #define CHECK_RET_RETURN(ret, message...) \ 116 185 if (ret != EOK) { \ … … 119 188 } else (void)0 120 189 121 ret = pio_enable((void*)regs, reg_size, (void**)&instance->registers); 190 int ret = 191 pio_enable((void*)regs, reg_size, (void**)&instance->registers); 122 192 CHECK_RET_RETURN(ret, 123 "Failed(%d) to gain access to device registers: %s.\n", 124 ret, str_error(ret)); 193 "Failed to gain access to device registers: %s.\n", str_error(ret)); 125 194 126 195 list_initialize(&instance->pending_batches); 127 196 usb_device_keeper_init(&instance->manager); 197 128 198 ret = usb_endpoint_manager_init(&instance->ep_manager, 129 199 BANDWIDTH_AVAILABLE_USB11); … … 137 207 138 208 fibril_mutex_initialize(&instance->guard); 209 139 210 hc_gain_control(instance); 140 141 rh_init(&instance->rh, instance->registers);142 211 143 212 if (!interrupts) { … … 147 216 } 148 217 149 return EOK; 150 } 151 /*----------------------------------------------------------------------------*/ 152 /** Create end register endpoint structures 218 rh_init(&instance->rh, instance->registers); 219 hc_start(instance); 220 221 return EOK; 222 } 223 /*----------------------------------------------------------------------------*/ 224 /** Create and register endpoint structures. 153 225 * 154 226 * @param[in] instance OHCI driver structure. … … 168 240 size_t mps, size_t size, unsigned interval) 169 241 { 170 endpoint_t *ep = malloc(sizeof(endpoint_t)); 242 endpoint_t *ep = 243 endpoint_get(address, endpoint, direction, type, speed, mps); 171 244 if (ep == NULL) 172 245 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 }179 246 180 247 hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep); … … 184 251 } 185 252 186 ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size); 253 int ret = 254 usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size); 187 255 if (ret != EOK) { 188 256 hcd_endpoint_clear(ep); … … 212 280 &instance->lists[ep->transfer_type], hcd_ep); 213 281 instance->registers->control |= C_PLE | C_IE; 214 break;215 default:216 282 break; 217 283 } … … 312 378 /* Check for root hub communication */ 313 379 if (batch->ep->address == instance->rh.address) { 314 return rh_request(&instance->rh, batch); 380 rh_request(&instance->rh, batch); 381 return EOK; 315 382 } 316 383 … … 374 441 375 442 if (status & I_UE) { 376 hc_start _hw(instance);443 hc_start(instance); 377 444 } 378 445 … … 399 466 /** Turn off any (BIOS)driver that might be in control of the device. 400 467 * 468 * This function implements routines described in chapter 5.1.1.3 of the OHCI 469 * specification (page 40, pdf page 54). 470 * 401 471 * @param[in] instance OHCI hc driver structure. 402 472 */ … … 404 474 { 405 475 assert(instance); 476 406 477 usb_log_debug("Requesting OHCI control.\n"); 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); 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 } 416 494 417 495 /* Interrupt routing enabled => smm driver is active */ … … 419 497 usb_log_debug("SMM driver: request ownership change.\n"); 420 498 instance->registers->command_status |= CS_OCR; 499 /* Hope that SMM actually knows its stuff or we can hang here */ 421 500 while (instance->registers->control & C_IR) { 422 501 async_usleep(1000); 423 502 } 424 503 usb_log_info("SMM driver: Ownership taken.\n"); 425 instance->registers->control &= (C_HCFS_RESET << C_HCFS_SHIFT);504 C_HCFS_SET(instance->registers->control, C_HCFS_RESET); 426 505 async_usleep(50000); 427 506 return; 428 507 } 429 508 430 const unsigned hc_status = 431 (instance->registers->control >> C_HCFS_SHIFT) & C_HCFS_MASK; 509 const unsigned hc_status = C_HCFS_GET(instance->registers->control); 432 510 /* Interrupt routing disabled && status != USB_RESET => BIOS active */ 433 511 if (hc_status != C_HCFS_RESET) { … … 437 515 return; 438 516 } 439 /* HC is suspended assert resume for 20ms */440 instance->registers->control &= (C_HCFS_RESUME << C_HCFS_SHIFT);517 /* HC is suspended assert resume for 20ms, */ 518 C_HCFS_SET(instance->registers->control, C_HCFS_RESUME); 441 519 async_usleep(20000); 442 520 usb_log_info("BIOS driver: HC resumed.\n"); … … 454 532 * @param[in] instance OHCI hc driver structure. 455 533 */ 456 void hc_start _hw(hc_t *instance)534 void hc_start(hc_t *instance) 457 535 { 458 536 /* OHCI guide page 42 */ … … 516 594 instance->registers->periodic_start, frame_length); 517 595 518 instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT);596 C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL); 519 597 usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n", 520 598 instance->registers->control); … … 534 612 int ret = endpoint_list_init(&instance->lists[type], name); \ 535 613 if (ret != EOK) { \ 536 usb_log_error("Failed (%d) to setup %s endpoint list.\n", \537 ret, name); \614 usb_log_error("Failed to setup %s endpoint list: %s.\n", \ 615 name, str_error(ret)); \ 538 616 endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\ 539 617 endpoint_list_fini(&instance->lists[USB_TRANSFER_INTERRUPT]); \ … … 587 665 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa); 588 666 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 621 return EOK; 622 } 667 return EOK; 668 } 669 623 670 /** 624 671 * @}
Note:
See TracChangeset
for help on using the changeset viewer.