Changes in uspace/drv/bus/usb/ohci/hc.c [d57122c:f83666c] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/ohci/hc.c
rd57122c rf83666c 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 28 29 /** @addtogroup drvusbohcihc 29 30 * @{ … … 32 33 * @brief OHCI Host controller driver routines 33 34 */ 35 34 36 #include <errno.h> 37 #include <stdbool.h> 35 38 #include <str_error.h> 36 39 #include <adt/list.h> … … 49 52 static const irq_pio_range_t ohci_pio_ranges[] = { 50 53 { 51 .base = 0, /* filled later */54 .base = 0, 52 55 .size = sizeof(ohci_regs_t) 53 56 } … … 55 58 56 59 static const irq_cmd_t ohci_irq_commands[] = { 57 { .cmd = CMD_PIO_READ_32, .dstarg = 1, .addr = NULL /* filled later */ }, 58 { .cmd = CMD_BTEST, .srcarg = 1, .dstarg = 2, .value = OHCI_USED_INTERRUPTS }, 59 { .cmd = CMD_PREDICATE, .srcarg = 2, .value = 2 }, 60 { .cmd = CMD_PIO_WRITE_A_32, .srcarg = 1, .addr = NULL /* filled later */ }, 61 { .cmd = CMD_ACCEPT }, 60 { 61 .cmd = CMD_PIO_READ_32, 62 .dstarg = 1, 63 .addr = NULL 64 }, 65 { 66 .cmd = CMD_AND, 67 .srcarg = 1, 68 .dstarg = 2, 69 .value = 0 70 }, 71 { 72 .cmd = CMD_PREDICATE, 73 .srcarg = 2, 74 .value = 2 75 }, 76 { 77 .cmd = CMD_PIO_WRITE_A_32, 78 .srcarg = 1, 79 .addr = NULL 80 }, 81 { 82 .cmd = CMD_ACCEPT 83 } 84 }; 85 86 enum { 87 /** Number of PIO ranges used in IRQ code */ 88 hc_irq_pio_range_count = 89 sizeof(ohci_pio_ranges) / sizeof(irq_pio_range_t), 90 91 /** Number of commands used in IRQ code */ 92 hc_irq_cmd_count = 93 sizeof(ohci_irq_commands) / sizeof(irq_cmd_t) 62 94 }; 63 95 … … 68 100 static int interrupt_emulator(hc_t *instance); 69 101 static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch); 70 /*----------------------------------------------------------------------------*/ 71 /** Get number of PIO ranges used in IRQ code. 72 * @return Number of ranges. 73 */ 74 size_t hc_irq_pio_range_count(void) 75 { 76 return sizeof(ohci_pio_ranges) / sizeof(irq_pio_range_t); 77 } 78 /*----------------------------------------------------------------------------*/ 79 /*----------------------------------------------------------------------------*/ 80 /** Get number of commands used in IRQ code. 81 * @return Number of commands. 82 */ 83 size_t hc_irq_cmd_count(void) 84 { 85 return sizeof(ohci_irq_commands) / sizeof(irq_cmd_t); 86 } 87 /*----------------------------------------------------------------------------*/ 102 88 103 /** Generate IRQ code. 89 104 * @param[out] ranges PIO ranges buffer. … … 112 127 cmds[0].addr = (void *) ®isters->interrupt_status; 113 128 cmds[3].addr = (void *) ®isters->interrupt_status; 114 115 return EOK; 116 } 117 /*----------------------------------------------------------------------------*/ 129 OHCI_WR(cmds[1].value, OHCI_USED_INTERRUPTS); 130 131 return EOK; 132 } 133 134 /** Register interrupt handler. 135 * 136 * @param[in] device Host controller DDF device 137 * @param[in] reg_base Register range base 138 * @param[in] reg_size Register range size 139 * @param[in] irq Interrupt number 140 * @paran[in] handler Interrupt handler 141 * 142 * @return EOK on success or negative error code 143 */ 144 int hc_register_irq_handler(ddf_dev_t *device, uintptr_t reg_base, size_t reg_size, 145 int irq, interrupt_handler_t handler) 146 { 147 int rc; 148 149 irq_pio_range_t irq_ranges[hc_irq_pio_range_count]; 150 irq_cmd_t irq_cmds[hc_irq_cmd_count]; 151 152 irq_code_t irq_code = { 153 .rangecount = hc_irq_pio_range_count, 154 .ranges = irq_ranges, 155 .cmdcount = hc_irq_cmd_count, 156 .cmds = irq_cmds 157 }; 158 159 rc = hc_get_irq_code(irq_ranges, sizeof(irq_ranges), irq_cmds, 160 sizeof(irq_cmds), reg_base, reg_size); 161 if (rc != EOK) { 162 usb_log_error("Failed to generate IRQ code: %s.\n", 163 str_error(rc)); 164 return rc; 165 } 166 167 /* Register handler to avoid interrupt lockup */ 168 rc = register_interrupt_handler(device, irq, handler, &irq_code); 169 if (rc != EOK) { 170 usb_log_error("Failed to register interrupt handler: %s.\n", 171 str_error(rc)); 172 return rc; 173 } 174 175 return EOK; 176 } 177 118 178 /** Announce OHCI root hub to the DDF 119 179 * … … 124 184 int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun) 125 185 { 186 bool addr_reqd = false; 187 bool ep_added = false; 188 bool fun_bound = false; 189 int rc; 190 126 191 assert(instance); 127 192 assert(hub_fun); … … 129 194 /* Try to get address 1 for root hub. */ 130 195 instance->rh.address = 1; 131 int ret= usb_device_manager_request_address(196 rc = usb_device_manager_request_address( 132 197 &instance->generic.dev_manager, &instance->rh.address, false, 133 198 USB_SPEED_FULL); 134 if (r et!= EOK) {199 if (rc != EOK) { 135 200 usb_log_error("Failed to get OHCI root hub address: %s\n", 136 str_error(ret)); 137 return ret; 138 } 139 140 #define CHECK_RET_UNREG_RETURN(ret, message...) \ 141 if (ret != EOK) { \ 142 usb_log_error(message); \ 143 usb_endpoint_manager_remove_ep( \ 144 &instance->generic.ep_manager, instance->rh.address, 0, \ 145 USB_DIRECTION_BOTH, NULL, NULL); \ 146 usb_device_manager_release_address( \ 147 &instance->generic.dev_manager, instance->rh.address); \ 148 return ret; \ 149 } else (void)0 150 151 ret = usb_endpoint_manager_add_ep( 201 str_error(rc)); 202 goto error; 203 } 204 205 addr_reqd = true; 206 207 rc = usb_endpoint_manager_add_ep( 152 208 &instance->generic.ep_manager, instance->rh.address, 0, 153 209 USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL, USB_SPEED_FULL, 64, 154 210 0, NULL, NULL); 155 CHECK_RET_UNREG_RETURN(ret, 156 "Failed to register root hub control endpoint: %s.\n", 157 str_error(ret)); 158 159 ret = ddf_fun_add_match_id(hub_fun, "usb&class=hub", 100); 160 CHECK_RET_UNREG_RETURN(ret, 161 "Failed to add root hub match-id: %s.\n", str_error(ret)); 162 163 ret = ddf_fun_bind(hub_fun); 164 CHECK_RET_UNREG_RETURN(ret, 165 "Failed to bind root hub function: %s.\n", str_error(ret)); 166 167 ret = usb_device_manager_bind_address(&instance->generic.dev_manager, 168 instance->rh.address, hub_fun->handle); 169 if (ret != EOK) 211 if (rc != EOK) { 212 usb_log_error("Failed to register root hub control endpoint: %s.\n", 213 str_error(rc)); 214 goto error; 215 } 216 217 ep_added = true; 218 219 rc = ddf_fun_add_match_id(hub_fun, "usb&class=hub", 100); 220 if (rc != EOK) { 221 usb_log_error("Failed to add root hub match-id: %s.\n", 222 str_error(rc)); 223 goto error; 224 } 225 226 rc = ddf_fun_bind(hub_fun); 227 if (rc != EOK) { 228 usb_log_error("Failed to bind root hub function: %s.\n", 229 str_error(rc)); 230 goto error; 231 } 232 233 fun_bound = true; 234 235 rc = usb_device_manager_bind_address(&instance->generic.dev_manager, 236 instance->rh.address, ddf_fun_get_handle(hub_fun)); 237 if (rc != EOK) { 170 238 usb_log_warning("Failed to bind root hub address: %s.\n", 171 str_error(ret)); 172 173 return EOK; 174 #undef CHECK_RET_RELEASE 175 } 176 /*----------------------------------------------------------------------------*/ 239 str_error(rc)); 240 } 241 242 return EOK; 243 error: 244 if (fun_bound) 245 ddf_fun_unbind(hub_fun); 246 if (ep_added) { 247 usb_endpoint_manager_remove_ep( 248 &instance->generic.ep_manager, instance->rh.address, 0, 249 USB_DIRECTION_BOTH, NULL, NULL); 250 } 251 if (addr_reqd) { 252 usb_device_manager_release_address( 253 &instance->generic.dev_manager, instance->rh.address); 254 } 255 return rc; 256 } 257 177 258 /** Initialize OHCI hc driver structure 178 259 * … … 187 268 assert(instance); 188 269 189 #define CHECK_RET_RETURN(ret, message...) \ 190 if (ret != EOK) { \ 191 usb_log_error(message); \ 192 return ret; \ 193 } else (void)0 194 195 int ret = 270 int rc = 196 271 pio_enable((void*)regs, reg_size, (void**)&instance->registers); 197 CHECK_RET_RETURN(ret, 198 "Failed to gain access to device registers: %s.\n", str_error(ret)); 272 if (rc != EOK) { 273 usb_log_error("Failed to gain access to device registers: %s.\n", 274 str_error(rc)); 275 return rc; 276 } 199 277 200 278 list_initialize(&instance->pending_batches); … … 207 285 instance->generic.ep_remove_hook = ohci_endpoint_fini; 208 286 209 ret = hc_init_memory(instance); 210 CHECK_RET_RETURN(ret, "Failed to create OHCI memory structures: %s.\n", 211 str_error(ret)); 212 #undef CHECK_RET_RETURN 287 rc = hc_init_memory(instance); 288 if (rc != EOK) { 289 usb_log_error("Failed to create OHCI memory structures: %s.\n", 290 str_error(rc)); 291 return rc; 292 } 213 293 214 294 fibril_mutex_initialize(&instance->guard); … … 227 307 return EOK; 228 308 } 229 /*----------------------------------------------------------------------------*/ 309 230 310 void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep) 231 311 { … … 241 321 switch (ep->transfer_type) { 242 322 case USB_TRANSFER_CONTROL: 243 instance->registers->control &= ~C_CLE;323 OHCI_CLR(instance->registers->control, C_CLE); 244 324 endpoint_list_add_ep(list, ohci_ep); 245 instance->registers->control_current = 0;246 instance->registers->control |= C_CLE;325 OHCI_WR(instance->registers->control_current, 0); 326 OHCI_SET(instance->registers->control, C_CLE); 247 327 break; 248 328 case USB_TRANSFER_BULK: 249 instance->registers->control &= ~C_BLE;329 OHCI_CLR(instance->registers->control, C_BLE); 250 330 endpoint_list_add_ep(list, ohci_ep); 251 instance->registers->control |= C_BLE; 331 OHCI_WR(instance->registers->bulk_current, 0); 332 OHCI_SET(instance->registers->control, C_BLE); 252 333 break; 253 334 case USB_TRANSFER_ISOCHRONOUS: 254 335 case USB_TRANSFER_INTERRUPT: 255 instance->registers->control &= (~C_PLE & ~C_IE);336 OHCI_CLR(instance->registers->control, C_PLE | C_IE); 256 337 endpoint_list_add_ep(list, ohci_ep); 257 instance->registers->control |= C_PLE | C_IE;258 break; 259 } 260 } 261 /*----------------------------------------------------------------------------*/ 338 OHCI_SET(instance->registers->control, C_PLE | C_IE); 339 break; 340 } 341 } 342 262 343 void hc_dequeue_endpoint(hc_t *instance, const endpoint_t *ep) 263 344 { … … 273 354 switch (ep->transfer_type) { 274 355 case USB_TRANSFER_CONTROL: 275 instance->registers->control &= ~C_CLE;356 OHCI_CLR(instance->registers->control, C_CLE); 276 357 endpoint_list_remove_ep(list, ohci_ep); 277 instance->registers->control_current = 0;278 instance->registers->control |= C_CLE;358 OHCI_WR(instance->registers->control_current, 0); 359 OHCI_SET(instance->registers->control, C_CLE); 279 360 break; 280 361 case USB_TRANSFER_BULK: 281 instance->registers->control &= ~C_BLE;362 OHCI_CLR(instance->registers->control, C_BLE); 282 363 endpoint_list_remove_ep(list, ohci_ep); 283 instance->registers->control |= C_BLE; 364 OHCI_WR(instance->registers->bulk_current, 0); 365 OHCI_SET(instance->registers->control, C_BLE); 284 366 break; 285 367 case USB_TRANSFER_ISOCHRONOUS: 286 368 case USB_TRANSFER_INTERRUPT: 287 instance->registers->control &= (~C_PLE & ~C_IE);369 OHCI_CLR(instance->registers->control, C_PLE | C_IE); 288 370 endpoint_list_remove_ep(list, ohci_ep); 289 instance->registers->control |= C_PLE | C_IE;371 OHCI_SET(instance->registers->control, C_PLE | C_IE); 290 372 break; 291 373 default: … … 293 375 } 294 376 } 295 /*----------------------------------------------------------------------------*/ 377 296 378 /** Add USB transfer to the schedule. 297 379 * … … 308 390 /* Check for root hub communication */ 309 391 if (batch->ep->address == instance->rh.address) { 392 usb_log_debug("OHCI root hub request.\n"); 310 393 rh_request(&instance->rh, batch); 311 394 return EOK; … … 323 406 { 324 407 case USB_TRANSFER_CONTROL: 325 instance->registers->command_status |= CS_CLF;408 OHCI_SET(instance->registers->command_status, CS_CLF); 326 409 break; 327 410 case USB_TRANSFER_BULK: 328 instance->registers->command_status |= CS_BLF;411 OHCI_SET(instance->registers->command_status, CS_BLF); 329 412 break; 330 413 default: … … 334 417 return EOK; 335 418 } 336 /*----------------------------------------------------------------------------*/ 419 337 420 /** Interrupt handling routine 338 421 * … … 342 425 void hc_interrupt(hc_t *instance, uint32_t status) 343 426 { 427 status = OHCI_RD(status); 344 428 assert(instance); 345 429 if ((status & ~I_SF) == 0) /* ignore sof status */ … … 352 436 fibril_mutex_lock(&instance->guard); 353 437 usb_log_debug2("HCCA: %p-%#" PRIx32 " (%p).\n", instance->hcca, 354 instance->registers->hcca,438 OHCI_RD(instance->registers->hcca), 355 439 (void *) addr_to_phys(instance->hcca)); 356 440 usb_log_debug2("Periodic current: %#" PRIx32 ".\n", 357 instance->registers->periodic_current);441 OHCI_RD(instance->registers->periodic_current)); 358 442 359 443 link_t *current = list_first(&instance->pending_batches); … … 379 463 380 464 } 381 /*----------------------------------------------------------------------------*/ 465 382 466 /** Check status register regularly 383 467 * … … 397 481 return EOK; 398 482 } 399 /*----------------------------------------------------------------------------*/ 483 400 484 /** Turn off any (BIOS)driver that might be in control of the device. 401 485 * … … 410 494 411 495 usb_log_debug("Requesting OHCI control.\n"); 412 if ( instance->registers->revision& R_LEGACY_FLAG) {496 if (OHCI_RD(instance->registers->revision) & R_LEGACY_FLAG) { 413 497 /* Turn off legacy emulation, it should be enough to zero 414 498 * the lowest bit, but it caused problems. Thus clear all … … 419 503 (uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET); 420 504 usb_log_debug("OHCI legacy register %p: %x.\n", 421 ohci_emulation_reg, *ohci_emulation_reg);505 ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg)); 422 506 /* Zero everything but A20State */ 423 *ohci_emulation_reg &= 0x100;507 OHCI_CLR(*ohci_emulation_reg, ~0x100); 424 508 usb_log_debug( 425 509 "OHCI legacy register (should be 0 or 0x100) %p: %x.\n", 426 ohci_emulation_reg, *ohci_emulation_reg);510 ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg)); 427 511 } 428 512 429 513 /* Interrupt routing enabled => smm driver is active */ 430 if ( instance->registers->control& C_IR) {514 if (OHCI_RD(instance->registers->control) & C_IR) { 431 515 usb_log_debug("SMM driver: request ownership change.\n"); 432 instance->registers->command_status |= CS_OCR;516 OHCI_SET(instance->registers->command_status, CS_OCR); 433 517 /* Hope that SMM actually knows its stuff or we can hang here */ 434 while ( instance->registers->control & C_IR) {518 while (OHCI_RD(instance->registers->control & C_IR)) { 435 519 async_usleep(1000); 436 520 } … … 449 533 return; 450 534 } 451 /* HC is suspended assert resume for 20ms ,*/535 /* HC is suspended assert resume for 20ms */ 452 536 C_HCFS_SET(instance->registers->control, C_HCFS_RESUME); 453 537 async_usleep(20000); … … 461 545 async_usleep(50000); 462 546 } 463 /*----------------------------------------------------------------------------*/ 547 464 548 /** OHCI hw initialization routine. 465 549 * … … 473 557 474 558 /* Save contents of fm_interval register */ 475 const uint32_t fm_interval = instance->registers->fm_interval;559 const uint32_t fm_interval = OHCI_RD(instance->registers->fm_interval); 476 560 usb_log_debug2("Old value of HcFmInterval: %x.\n", fm_interval); 477 561 … … 479 563 usb_log_debug2("HC reset.\n"); 480 564 size_t time = 0; 481 instance->registers->command_status = CS_HCR;482 while ( instance->registers->command_status& CS_HCR) {565 OHCI_WR(instance->registers->command_status, CS_HCR); 566 while (OHCI_RD(instance->registers->command_status) & CS_HCR) { 483 567 async_usleep(10); 484 568 time += 10; … … 487 571 488 572 /* Restore fm_interval */ 489 instance->registers->fm_interval = fm_interval;490 assert(( instance->registers->command_status& CS_HCR) == 0);573 OHCI_WR(instance->registers->fm_interval, fm_interval); 574 assert((OHCI_RD(instance->registers->command_status) & CS_HCR) == 0); 491 575 492 576 /* hc is now in suspend state */ 493 577 usb_log_debug2("HC should be in suspend state(%x).\n", 494 instance->registers->control);578 OHCI_RD(instance->registers->control)); 495 579 496 580 /* Use HCCA */ 497 instance->registers->hcca = addr_to_phys(instance->hcca);581 OHCI_WR(instance->registers->hcca, addr_to_phys(instance->hcca)); 498 582 499 583 /* Use queues */ 500 instance->registers->bulk_head =501 instance->lists[USB_TRANSFER_BULK].list_head_pa ;584 OHCI_WR(instance->registers->bulk_head, 585 instance->lists[USB_TRANSFER_BULK].list_head_pa); 502 586 usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 ").\n", 503 587 instance->lists[USB_TRANSFER_BULK].list_head, 504 588 instance->lists[USB_TRANSFER_BULK].list_head_pa); 505 589 506 instance->registers->control_head =507 instance->lists[USB_TRANSFER_CONTROL].list_head_pa ;590 OHCI_WR(instance->registers->control_head, 591 instance->lists[USB_TRANSFER_CONTROL].list_head_pa); 508 592 usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 ").\n", 509 593 instance->lists[USB_TRANSFER_CONTROL].list_head, … … 511 595 512 596 /* Enable queues */ 513 instance->registers->control |= (C_PLE | C_IE | C_CLE | C_BLE);514 usb_log_debug 2("All queues enabled(%x).\n",515 instance->registers->control);597 OHCI_SET(instance->registers->control, (C_PLE | C_IE | C_CLE | C_BLE)); 598 usb_log_debug("Queues enabled(%x).\n", 599 OHCI_RD(instance->registers->control)); 516 600 517 601 /* Enable interrupts */ 518 instance->registers->interrupt_enable = OHCI_USED_INTERRUPTS;519 usb_log_debug 2("Enabled interrupts: %x.\n",520 instance->registers->interrupt_enable);521 instance->registers->interrupt_enable = I_MI;602 OHCI_WR(instance->registers->interrupt_enable, OHCI_USED_INTERRUPTS); 603 usb_log_debug("Enabled interrupts: %x.\n", 604 OHCI_RD(instance->registers->interrupt_enable)); 605 OHCI_WR(instance->registers->interrupt_enable, I_MI); 522 606 523 607 /* Set periodic start to 90% */ 524 uint32_t frame_length = ((fm_interval >> FMI_FI_SHIFT) & FMI_FI_MASK); 525 instance->registers->periodic_start = (frame_length / 10) * 9; 608 const uint32_t frame_length = 609 (fm_interval >> FMI_FI_SHIFT) & FMI_FI_MASK; 610 OHCI_WR(instance->registers->periodic_start, 611 ((frame_length / 10) * 9) & PS_MASK << PS_SHIFT); 526 612 usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).\n", 527 instance->registers->periodic_start, 528 instance->registers->periodic_start, frame_length); 529 613 OHCI_RD(instance->registers->periodic_start), 614 OHCI_RD(instance->registers->periodic_start), frame_length); 530 615 C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL); 531 616 usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n", 532 instance->registers->control);533 } 534 /*----------------------------------------------------------------------------*/ 617 OHCI_RD(instance->registers->control)); 618 } 619 535 620 /** Initialize schedule queues 536 621 * … … 566 651 return EOK; 567 652 } 568 /*----------------------------------------------------------------------------*/ 653 569 654 /** Initialize memory structures used by the OHCI hcd. 570 655 * … … 576 661 assert(instance); 577 662 578 bzero(&instance->rh, sizeof(instance->rh));663 memset(&instance->rh, 0, sizeof(instance->rh)); 579 664 /* Init queues */ 580 665 const int ret = hc_init_transfer_lists(instance); … … 587 672 if (instance->hcca == NULL) 588 673 return ENOMEM; 589 bzero(instance->hcca, sizeof(hcca_t));590 674 usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca); 591 675 592 for (unsigned i = 0; i < 32; ++i) {593 instance->hcca->int_ep[i] =594 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa ;676 for (unsigned i = 0; i < HCCA_INT_EP_COUNT; ++i) { 677 hcca_set_int_ep(instance->hcca, i, 678 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa); 595 679 } 596 680 usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 ").\n",
Note:
See TracChangeset
for help on using the changeset viewer.