Changes in uspace/drv/bus/usb/ohci/hc.c [ea8b91d:9d58539] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/ohci/hc.c
rea8b91d r9d58539 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 35 #include <str_error.h> … … 51 49 static const irq_pio_range_t ohci_pio_ranges[] = { 52 50 { 53 .base = 0, 51 .base = 0, /* filled later */ 54 52 .size = sizeof(ohci_regs_t) 55 53 } … … 57 55 58 56 static const irq_cmd_t ohci_irq_commands[] = { 59 { 60 .cmd = CMD_PIO_READ_32, 61 .dstarg = 1, 62 .addr = NULL 63 }, 64 { 65 .cmd = CMD_AND, 66 .srcarg = 1, 67 .dstarg = 2, 68 .value = 0 69 }, 70 { 71 .cmd = CMD_PREDICATE, 72 .srcarg = 2, 73 .value = 2 74 }, 75 { 76 .cmd = CMD_PIO_WRITE_A_32, 77 .srcarg = 1, 78 .addr = NULL 79 }, 80 { 81 .cmd = CMD_ACCEPT 82 } 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 }, 83 62 }; 84 63 … … 89 68 static int interrupt_emulator(hc_t *instance); 90 69 static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch); 91 70 /*----------------------------------------------------------------------------*/ 92 71 /** Get number of PIO ranges used in IRQ code. 93 72 * @return Number of ranges. … … 97 76 return sizeof(ohci_pio_ranges) / sizeof(irq_pio_range_t); 98 77 } 99 78 /*----------------------------------------------------------------------------*/ 79 /*----------------------------------------------------------------------------*/ 100 80 /** Get number of commands used in IRQ code. 101 81 * @return Number of commands. … … 105 85 return sizeof(ohci_irq_commands) / sizeof(irq_cmd_t); 106 86 } 107 87 /*----------------------------------------------------------------------------*/ 108 88 /** Generate IRQ code. 109 89 * @param[out] ranges PIO ranges buffer. … … 132 112 cmds[0].addr = (void *) ®isters->interrupt_status; 133 113 cmds[3].addr = (void *) ®isters->interrupt_status; 134 OHCI_WR(cmds[1].value, OHCI_USED_INTERRUPTS);135 114 136 115 return EOK; 137 116 } 138 117 /*----------------------------------------------------------------------------*/ 139 118 /** Announce OHCI root hub to the DDF 140 119 * … … 195 174 #undef CHECK_RET_RELEASE 196 175 } 197 176 /*----------------------------------------------------------------------------*/ 198 177 /** Initialize OHCI hc driver structure 199 178 * … … 248 227 return EOK; 249 228 } 250 229 /*----------------------------------------------------------------------------*/ 251 230 void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep) 252 231 { … … 262 241 switch (ep->transfer_type) { 263 242 case USB_TRANSFER_CONTROL: 264 OHCI_CLR(instance->registers->control, C_CLE);243 instance->registers->control &= ~C_CLE; 265 244 endpoint_list_add_ep(list, ohci_ep); 266 OHCI_WR(instance->registers->control_current, 0);267 OHCI_SET(instance->registers->control, C_CLE);245 instance->registers->control_current = 0; 246 instance->registers->control |= C_CLE; 268 247 break; 269 248 case USB_TRANSFER_BULK: 270 OHCI_CLR(instance->registers->control, C_BLE);249 instance->registers->control &= ~C_BLE; 271 250 endpoint_list_add_ep(list, ohci_ep); 272 OHCI_WR(instance->registers->bulk_current, 0); 273 OHCI_SET(instance->registers->control, C_BLE); 251 instance->registers->control |= C_BLE; 274 252 break; 275 253 case USB_TRANSFER_ISOCHRONOUS: 276 254 case USB_TRANSFER_INTERRUPT: 277 OHCI_CLR(instance->registers->control, C_PLE |C_IE);255 instance->registers->control &= (~C_PLE & ~C_IE); 278 256 endpoint_list_add_ep(list, ohci_ep); 279 OHCI_SET(instance->registers->control, C_PLE | C_IE);280 break; 281 } 282 } 283 257 instance->registers->control |= C_PLE | C_IE; 258 break; 259 } 260 } 261 /*----------------------------------------------------------------------------*/ 284 262 void hc_dequeue_endpoint(hc_t *instance, const endpoint_t *ep) 285 263 { … … 295 273 switch (ep->transfer_type) { 296 274 case USB_TRANSFER_CONTROL: 297 OHCI_CLR(instance->registers->control, C_CLE);275 instance->registers->control &= ~C_CLE; 298 276 endpoint_list_remove_ep(list, ohci_ep); 299 OHCI_WR(instance->registers->control_current, 0);300 OHCI_SET(instance->registers->control, C_CLE);277 instance->registers->control_current = 0; 278 instance->registers->control |= C_CLE; 301 279 break; 302 280 case USB_TRANSFER_BULK: 303 OHCI_CLR(instance->registers->control, C_BLE);281 instance->registers->control &= ~C_BLE; 304 282 endpoint_list_remove_ep(list, ohci_ep); 305 OHCI_WR(instance->registers->bulk_current, 0); 306 OHCI_SET(instance->registers->control, C_BLE); 283 instance->registers->control |= C_BLE; 307 284 break; 308 285 case USB_TRANSFER_ISOCHRONOUS: 309 286 case USB_TRANSFER_INTERRUPT: 310 OHCI_CLR(instance->registers->control, C_PLE |C_IE);287 instance->registers->control &= (~C_PLE & ~C_IE); 311 288 endpoint_list_remove_ep(list, ohci_ep); 312 OHCI_SET(instance->registers->control, C_PLE | C_IE);289 instance->registers->control |= C_PLE | C_IE; 313 290 break; 314 291 default: … … 316 293 } 317 294 } 318 295 /*----------------------------------------------------------------------------*/ 319 296 /** Add USB transfer to the schedule. 320 297 * … … 331 308 /* Check for root hub communication */ 332 309 if (batch->ep->address == instance->rh.address) { 333 usb_log_debug("OHCI root hub request.\n");334 310 rh_request(&instance->rh, batch); 335 311 return EOK; … … 347 323 { 348 324 case USB_TRANSFER_CONTROL: 349 OHCI_SET(instance->registers->command_status, CS_CLF);325 instance->registers->command_status |= CS_CLF; 350 326 break; 351 327 case USB_TRANSFER_BULK: 352 OHCI_SET(instance->registers->command_status, CS_BLF);328 instance->registers->command_status |= CS_BLF; 353 329 break; 354 330 default: … … 358 334 return EOK; 359 335 } 360 336 /*----------------------------------------------------------------------------*/ 361 337 /** Interrupt handling routine 362 338 * … … 366 342 void hc_interrupt(hc_t *instance, uint32_t status) 367 343 { 368 status = OHCI_RD(status);369 344 assert(instance); 370 345 if ((status & ~I_SF) == 0) /* ignore sof status */ … … 377 352 fibril_mutex_lock(&instance->guard); 378 353 usb_log_debug2("HCCA: %p-%#" PRIx32 " (%p).\n", instance->hcca, 379 OHCI_RD(instance->registers->hcca),354 instance->registers->hcca, 380 355 (void *) addr_to_phys(instance->hcca)); 381 356 usb_log_debug2("Periodic current: %#" PRIx32 ".\n", 382 OHCI_RD(instance->registers->periodic_current));357 instance->registers->periodic_current); 383 358 384 359 link_t *current = list_first(&instance->pending_batches); … … 404 379 405 380 } 406 381 /*----------------------------------------------------------------------------*/ 407 382 /** Check status register regularly 408 383 * … … 422 397 return EOK; 423 398 } 424 399 /*----------------------------------------------------------------------------*/ 425 400 /** Turn off any (BIOS)driver that might be in control of the device. 426 401 * … … 435 410 436 411 usb_log_debug("Requesting OHCI control.\n"); 437 if ( OHCI_RD(instance->registers->revision)& R_LEGACY_FLAG) {412 if (instance->registers->revision & R_LEGACY_FLAG) { 438 413 /* Turn off legacy emulation, it should be enough to zero 439 414 * the lowest bit, but it caused problems. Thus clear all … … 444 419 (uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET); 445 420 usb_log_debug("OHCI legacy register %p: %x.\n", 446 ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg));421 ohci_emulation_reg, *ohci_emulation_reg); 447 422 /* Zero everything but A20State */ 448 OHCI_CLR(*ohci_emulation_reg, ~0x100);423 *ohci_emulation_reg &= 0x100; 449 424 usb_log_debug( 450 425 "OHCI legacy register (should be 0 or 0x100) %p: %x.\n", 451 ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg));426 ohci_emulation_reg, *ohci_emulation_reg); 452 427 } 453 428 454 429 /* Interrupt routing enabled => smm driver is active */ 455 if ( OHCI_RD(instance->registers->control)& C_IR) {430 if (instance->registers->control & C_IR) { 456 431 usb_log_debug("SMM driver: request ownership change.\n"); 457 OHCI_SET(instance->registers->command_status, CS_OCR);432 instance->registers->command_status |= CS_OCR; 458 433 /* Hope that SMM actually knows its stuff or we can hang here */ 459 while ( OHCI_RD(instance->registers->control & C_IR)) {434 while (instance->registers->control & C_IR) { 460 435 async_usleep(1000); 461 436 } … … 474 449 return; 475 450 } 476 /* HC is suspended assert resume for 20ms */451 /* HC is suspended assert resume for 20ms, */ 477 452 C_HCFS_SET(instance->registers->control, C_HCFS_RESUME); 478 453 async_usleep(20000); … … 486 461 async_usleep(50000); 487 462 } 488 463 /*----------------------------------------------------------------------------*/ 489 464 /** OHCI hw initialization routine. 490 465 * … … 498 473 499 474 /* Save contents of fm_interval register */ 500 const uint32_t fm_interval = OHCI_RD(instance->registers->fm_interval);475 const uint32_t fm_interval = instance->registers->fm_interval; 501 476 usb_log_debug2("Old value of HcFmInterval: %x.\n", fm_interval); 502 477 … … 504 479 usb_log_debug2("HC reset.\n"); 505 480 size_t time = 0; 506 OHCI_WR(instance->registers->command_status, CS_HCR);507 while ( OHCI_RD(instance->registers->command_status)& CS_HCR) {481 instance->registers->command_status = CS_HCR; 482 while (instance->registers->command_status & CS_HCR) { 508 483 async_usleep(10); 509 484 time += 10; … … 512 487 513 488 /* Restore fm_interval */ 514 OHCI_WR(instance->registers->fm_interval, fm_interval);515 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); 516 491 517 492 /* hc is now in suspend state */ 518 493 usb_log_debug2("HC should be in suspend state(%x).\n", 519 OHCI_RD(instance->registers->control));494 instance->registers->control); 520 495 521 496 /* Use HCCA */ 522 OHCI_WR(instance->registers->hcca, addr_to_phys(instance->hcca));497 instance->registers->hcca = addr_to_phys(instance->hcca); 523 498 524 499 /* Use queues */ 525 OHCI_WR(instance->registers->bulk_head,526 instance->lists[USB_TRANSFER_BULK].list_head_pa );500 instance->registers->bulk_head = 501 instance->lists[USB_TRANSFER_BULK].list_head_pa; 527 502 usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 ").\n", 528 503 instance->lists[USB_TRANSFER_BULK].list_head, 529 504 instance->lists[USB_TRANSFER_BULK].list_head_pa); 530 505 531 OHCI_WR(instance->registers->control_head,532 instance->lists[USB_TRANSFER_CONTROL].list_head_pa );506 instance->registers->control_head = 507 instance->lists[USB_TRANSFER_CONTROL].list_head_pa; 533 508 usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 ").\n", 534 509 instance->lists[USB_TRANSFER_CONTROL].list_head, … … 536 511 537 512 /* Enable queues */ 538 OHCI_SET(instance->registers->control, (C_PLE | C_IE | C_CLE | C_BLE));539 usb_log_debug ("Queues enabled(%x).\n",540 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); 541 516 542 517 /* Enable interrupts */ 543 OHCI_WR(instance->registers->interrupt_enable, OHCI_USED_INTERRUPTS);544 usb_log_debug ("Enabled interrupts: %x.\n",545 OHCI_RD(instance->registers->interrupt_enable));546 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; 547 522 548 523 /* Set periodic start to 90% */ 549 const uint32_t frame_length = 550 (fm_interval >> FMI_FI_SHIFT) & FMI_FI_MASK; 551 OHCI_WR(instance->registers->periodic_start, 552 ((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; 553 526 usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).\n", 554 OHCI_RD(instance->registers->periodic_start), 555 OHCI_RD(instance->registers->periodic_start), frame_length); 527 instance->registers->periodic_start, 528 instance->registers->periodic_start, frame_length); 529 556 530 C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL); 557 531 usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n", 558 OHCI_RD(instance->registers->control));559 } 560 532 instance->registers->control); 533 } 534 /*----------------------------------------------------------------------------*/ 561 535 /** Initialize schedule queues 562 536 * … … 592 566 return EOK; 593 567 } 594 568 /*----------------------------------------------------------------------------*/ 595 569 /** Initialize memory structures used by the OHCI hcd. 596 570 * … … 613 587 if (instance->hcca == NULL) 614 588 return ENOMEM; 589 bzero(instance->hcca, sizeof(hcca_t)); 615 590 usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca); 616 591 617 for (unsigned i = 0; i < HCCA_INT_EP_COUNT; ++i) {618 hcca_set_int_ep(instance->hcca, i,619 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; 620 595 } 621 596 usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 ").\n",
Note:
See TracChangeset
for help on using the changeset viewer.