Changeset 8ff0bd2 in mainline for uspace/drv/bus/usb/ohci/hc.c
- Timestamp:
- 2011-09-04T11:30:58Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 03bc76a
- Parents:
- d2c67e7 (diff), deac215e (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 moved
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/ohci/hc.c
rd2c67e7 r8ff0bd2 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 … … 65 130 device_keeper_get_free_address(&instance->manager, USB_SPEED_FULL); 66 131 if (hub_address <= 0) { 67 usb_log_error("Failed (%d) to get OHCI root hub address.\n",68 hub_address);132 usb_log_error("Failed to get OHCI root hub address: %s\n", 133 str_error(hub_address)); 69 134 return hub_address; 70 135 } … … 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); 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); 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)); 95 156 96 157 ret = ddf_fun_bind(hub_fun); 97 CHECK_RET_RELEASE(ret, "Failed(%d) to bind root hub function.\n", ret); 158 CHECK_RET_RELEASE(ret, 159 "Failed to bind root hub function: %s.\n", str_error(ret)); 98 160 99 161 return EOK; … … 112 174 { 113 175 assert(instance); 114 int ret = EOK; 176 115 177 #define CHECK_RET_RETURN(ret, message...) \ 116 178 if (ret != EOK) { \ … … 119 181 } else (void)0 120 182 121 ret = pio_enable((void*)regs, reg_size, (void**)&instance->registers); 183 int ret = 184 pio_enable((void*)regs, reg_size, (void**)&instance->registers); 122 185 CHECK_RET_RETURN(ret, 123 "Failed(%d) to gain access to device registers: %s.\n", 124 ret, str_error(ret)); 186 "Failed to gain access to device registers: %s.\n", str_error(ret)); 125 187 126 188 list_initialize(&instance->pending_batches); 127 189 usb_device_keeper_init(&instance->manager); 190 128 191 ret = usb_endpoint_manager_init(&instance->ep_manager, 129 192 BANDWIDTH_AVAILABLE_USB11); … … 137 200 138 201 fibril_mutex_initialize(&instance->guard); 202 139 203 hc_gain_control(instance); 140 141 rh_init(&instance->rh, instance->registers);142 204 143 205 if (!interrupts) { … … 147 209 } 148 210 149 return EOK; 150 } 151 /*----------------------------------------------------------------------------*/ 152 /** Create end register endpoint structures 211 rh_init(&instance->rh, instance->registers); 212 hc_start(instance); 213 214 return EOK; 215 } 216 /*----------------------------------------------------------------------------*/ 217 /** Create and register endpoint structures. 153 218 * 154 219 * @param[in] instance OHCI driver structure. … … 168 233 size_t mps, size_t size, unsigned interval) 169 234 { 170 endpoint_t *ep = malloc(sizeof(endpoint_t)); 235 endpoint_t *ep = 236 endpoint_get(address, endpoint, direction, type, speed, mps); 171 237 if (ep == NULL) 172 238 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 239 180 240 hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep); … … 184 244 } 185 245 186 ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size); 246 int ret = 247 usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size); 187 248 if (ret != EOK) { 188 249 hcd_endpoint_clear(ep); … … 212 273 &instance->lists[ep->transfer_type], hcd_ep); 213 274 instance->registers->control |= C_PLE | C_IE; 214 break;215 default:216 275 break; 217 276 } … … 312 371 /* Check for root hub communication */ 313 372 if (batch->ep->address == instance->rh.address) { 314 return rh_request(&instance->rh, batch); 373 rh_request(&instance->rh, batch); 374 return EOK; 315 375 } 316 376 … … 357 417 instance->registers->periodic_current); 358 418 359 link_t *current = instance->pending_batches. next;360 while (current != &instance->pending_batches ) {419 link_t *current = instance->pending_batches.head.next; 420 while (current != &instance->pending_batches.head) { 361 421 link_t *next = current->next; 362 422 usb_transfer_batch_t *batch = … … 367 427 usb_transfer_batch_finish(batch); 368 428 } 429 369 430 current = next; 370 431 } … … 373 434 374 435 if (status & I_UE) { 375 hc_start _hw(instance);436 hc_start(instance); 376 437 } 377 438 … … 398 459 /** Turn off any (BIOS)driver that might be in control of the device. 399 460 * 461 * This function implements routines described in chapter 5.1.1.3 of the OHCI 462 * specification (page 40, pdf page 54). 463 * 400 464 * @param[in] instance OHCI hc driver structure. 401 465 */ … … 403 467 { 404 468 assert(instance); 469 405 470 usb_log_debug("Requesting OHCI control.\n"); 406 /* Turn off legacy emulation */ 407 volatile uint32_t *ohci_emulation_reg = 408 (uint32_t*)((char*)instance->registers + 0x100); 409 usb_log_debug("OHCI legacy register %p: %x.\n", 410 ohci_emulation_reg, *ohci_emulation_reg); 411 /* Do not change A20 state */ 412 *ohci_emulation_reg &= 0x100; 413 usb_log_debug("OHCI legacy register %p: %x.\n", 414 ohci_emulation_reg, *ohci_emulation_reg); 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 } 415 487 416 488 /* Interrupt routing enabled => smm driver is active */ … … 418 490 usb_log_debug("SMM driver: request ownership change.\n"); 419 491 instance->registers->command_status |= CS_OCR; 492 /* Hope that SMM actually knows its stuff or we can hang here */ 420 493 while (instance->registers->control & C_IR) { 421 494 async_usleep(1000); 422 495 } 423 496 usb_log_info("SMM driver: Ownership taken.\n"); 424 instance->registers->control &= (C_HCFS_RESET << C_HCFS_SHIFT);497 C_HCFS_SET(instance->registers->control, C_HCFS_RESET); 425 498 async_usleep(50000); 426 499 return; 427 500 } 428 501 429 const unsigned hc_status = 430 (instance->registers->control >> C_HCFS_SHIFT) & C_HCFS_MASK; 502 const unsigned hc_status = C_HCFS_GET(instance->registers->control); 431 503 /* Interrupt routing disabled && status != USB_RESET => BIOS active */ 432 504 if (hc_status != C_HCFS_RESET) { … … 436 508 return; 437 509 } 438 /* HC is suspended assert resume for 20ms */439 instance->registers->control &= (C_HCFS_RESUME << C_HCFS_SHIFT);510 /* HC is suspended assert resume for 20ms, */ 511 C_HCFS_SET(instance->registers->control, C_HCFS_RESUME); 440 512 async_usleep(20000); 441 513 usb_log_info("BIOS driver: HC resumed.\n"); … … 445 517 /* HC is in reset (hw startup) => no other driver 446 518 * maintain reset for at least the time specified in USB spec (50 ms)*/ 447 usb_log_ info("HC found in reset.\n");519 usb_log_debug("Host controller found in reset state.\n"); 448 520 async_usleep(50000); 449 521 } … … 453 525 * @param[in] instance OHCI hc driver structure. 454 526 */ 455 void hc_start _hw(hc_t *instance)527 void hc_start(hc_t *instance) 456 528 { 457 529 /* OHCI guide page 42 */ … … 515 587 instance->registers->periodic_start, frame_length); 516 588 517 instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT);518 usb_log_ info("OHCI HC up and running(%x).\n",589 C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL); 590 usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n", 519 591 instance->registers->control); 520 592 } … … 533 605 int ret = endpoint_list_init(&instance->lists[type], name); \ 534 606 if (ret != EOK) { \ 535 usb_log_error("Failed (%d) to setup %s endpoint list.\n", \536 ret, name); \607 usb_log_error("Failed to setup %s endpoint list: %s.\n", \ 608 name, str_error(ret)); \ 537 609 endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\ 538 610 endpoint_list_fini(&instance->lists[USB_TRANSFER_INTERRUPT]); \ … … 586 658 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa); 587 659 588 /* Init interrupt code */ 589 instance->interrupt_code.cmds = instance->interrupt_commands; 590 instance->interrupt_code.cmdcount = OHCI_NEEDED_IRQ_COMMANDS; 591 { 592 /* Read status register */ 593 instance->interrupt_commands[0].cmd = CMD_MEM_READ_32; 594 instance->interrupt_commands[0].dstarg = 1; 595 instance->interrupt_commands[0].addr = 596 (void*)&instance->registers->interrupt_status; 597 598 /* Test whether we are the interrupt cause */ 599 instance->interrupt_commands[1].cmd = CMD_BTEST; 600 instance->interrupt_commands[1].value = 601 OHCI_USED_INTERRUPTS; 602 instance->interrupt_commands[1].srcarg = 1; 603 instance->interrupt_commands[1].dstarg = 2; 604 605 /* Predicate cleaning and accepting */ 606 instance->interrupt_commands[2].cmd = CMD_PREDICATE; 607 instance->interrupt_commands[2].value = 2; 608 instance->interrupt_commands[2].srcarg = 2; 609 610 /* Write-clean status register */ 611 instance->interrupt_commands[3].cmd = CMD_MEM_WRITE_A_32; 612 instance->interrupt_commands[3].srcarg = 1; 613 instance->interrupt_commands[3].addr = 614 (void*)&instance->registers->interrupt_status; 615 616 /* Accept interrupt */ 617 instance->interrupt_commands[4].cmd = CMD_ACCEPT; 618 } 619 620 return EOK; 621 } 660 return EOK; 661 } 662 622 663 /** 623 664 * @}
Note:
See TracChangeset
for help on using the changeset viewer.