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