1 /* 2 * Copyright 2005-2008, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Jan-Rixt Van Hoye 7 * Salvatore Benedetto <salvatore.benedetto@gmail.com> 8 */ 9 10 #include <module.h> 11 #include <PCI.h> 12 #include <USB3.h> 13 #include <KernelExport.h> 14 15 #include "ohci.h" 16 17 pci_module_info *OHCI::sPCIModule = NULL; 18 19 20 static int32 21 ohci_std_ops(int32 op, ...) 22 { 23 switch (op) { 24 case B_MODULE_INIT: 25 TRACE(("usb_ohci_module: init module\n")); 26 return B_OK; 27 case B_MODULE_UNINIT: 28 TRACE(("usb_ohci_module: uninit module\n")); 29 return B_OK; 30 } 31 32 return EINVAL; 33 } 34 35 36 host_controller_info ohci_module = { 37 { 38 "busses/usb/ohci", 39 0, 40 ohci_std_ops 41 }, 42 NULL, 43 OHCI::AddTo 44 }; 45 46 47 module_info *modules[] = { 48 (module_info *)&ohci_module, 49 NULL 50 }; 51 52 53 //------------------------------------------------------ 54 // OHCI:: Reverse the bits in a value between 0 and 31 55 // (Section 3.3.2) 56 //------------------------------------------------------ 57 static uint8 revbits[OHCI_NUMBER_OF_INTERRUPTS] = 58 { 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c, 59 0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e, 60 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d, 61 0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f }; 62 63 64 OHCI::OHCI(pci_info *info, Stack *stack) 65 : BusManager(stack), 66 fPCIInfo(info), 67 fStack(stack), 68 fRegisterArea(-1), 69 fHccaArea(-1), 70 fDummyControl(NULL), 71 fDummyBulk(NULL), 72 fDummyIsochronous(NULL), 73 fFirstTransfer(NULL), 74 fLastTransfer(NULL), 75 fFinishThread(-1), 76 fStopFinishThread(false), 77 fRootHub(NULL), 78 fRootHubAddress(0), 79 fPortCount(0) 80 { 81 if (!fInitOK) { 82 TRACE_ERROR(("usb_ohci: bus manager failed to init\n")); 83 return; 84 } 85 86 TRACE(("usb_ohci: constructing new OHCI Host Controller Driver\n")); 87 fInitOK = false; 88 89 // enable busmaster and memory mapped access 90 uint16 command = sPCIModule->read_pci_config(fPCIInfo->bus, 91 fPCIInfo->device, fPCIInfo->function, PCI_command, 2); 92 command &= ~PCI_command_io; 93 command |= PCI_command_master | PCI_command_memory; 94 95 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 96 fPCIInfo->function, PCI_command, 2, command); 97 98 // map the registers 99 uint32 offset = sPCIModule->read_pci_config(fPCIInfo->bus, 100 fPCIInfo->device, fPCIInfo->function, PCI_base_registers, 4); 101 offset &= PCI_address_memory_32_mask; 102 TRACE(("usb_ohci: iospace offset: %lx\n", offset)); 103 fRegisterArea = map_physical_memory("OHCI memory mapped registers", 104 (void *)offset, B_PAGE_SIZE, B_ANY_KERNEL_BLOCK_ADDRESS, 105 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | B_WRITE_AREA, 106 (void **)&fOperationalRegisters); 107 if (fRegisterArea < B_OK) { 108 TRACE_ERROR(("usb_ohci: failed to map register memory\n")); 109 return; 110 } 111 112 TRACE(("usb_ohci: mapped operational registers: 0x%08lx\n", 113 *fOperationalRegisters)); 114 115 // Check the revision of the controller, which should be 10h 116 uint32 revision = _ReadReg(OHCI_REVISION) & 0xff; 117 TRACE(("usb_ohci: version %ld.%ld%s\n", OHCI_REVISION_HIGH(revision), 118 OHCI_REVISION_LOW(revision), OHCI_REVISION_LEGACY(revision) 119 ? ", legacy support" : "")); 120 if (OHCI_REVISION_HIGH(revision) != 1 || OHCI_REVISION_LOW(revision) != 0) { 121 TRACE_ERROR(("usb_ohci: unsupported OHCI revision\n")); 122 return; 123 } 124 125 // Set up the Host Controller Communications Area 126 // which is 256 bytes (2048 bits) and must be aligned 127 void *hccaPhysicalAddress; 128 fHccaArea = fStack->AllocateArea((void **)&fHcca, &hccaPhysicalAddress, 129 2048, "USB OHCI Host Controller Communication Area"); 130 131 if (fHccaArea < B_OK) { 132 TRACE_ERROR(("usb_ohci: unable to create the HCCA block area\n")); 133 return; 134 } 135 136 memset((void *)fHcca, 0, sizeof(ohci_hcca)); 137 138 // Allocate hash tables 139 fHashGenericTable = (ohci_general_td **) 140 malloc(sizeof(ohci_general_td *) * OHCI_HASH_SIZE); 141 if (fHashGenericTable == NULL) { 142 TRACE_ERROR(("usb_ohci: unable to allocate hash generic table\n")); 143 return; 144 } 145 fHashIsochronousTable = (ohci_isochronous_td **) 146 malloc(sizeof(ohci_isochronous_td *) * OHCI_HASH_SIZE); 147 if (fHashIsochronousTable == NULL) { 148 free(fHashGenericTable); 149 TRACE_ERROR(("usb_ohci: unable to allocate hash isochronous table\n")); 150 return; 151 } 152 153 // Set Up Host controller 154 // Dummy endpoints 155 fDummyControl = _AllocateEndpoint(); 156 if (!fDummyControl) 157 return; 158 fDummyControl->flags |= OHCI_ENDPOINT_SKIP; 159 160 fDummyBulk = _AllocateEndpoint(); 161 if (!fDummyBulk) { 162 _FreeEndpoint(fDummyControl); 163 return; 164 } 165 fDummyBulk->flags |= OHCI_ENDPOINT_SKIP; 166 167 fDummyIsochronous = _AllocateEndpoint(); 168 if (!fDummyIsochronous) { 169 _FreeEndpoint(fDummyControl); 170 _FreeEndpoint(fDummyBulk); 171 return; 172 } 173 fDummyIsochronous->flags |= OHCI_ENDPOINT_SKIP; 174 175 // Static endpoints that get linked in the HCCA 176 fInterruptEndpoints = new(std::nothrow) 177 ohci_endpoint_descriptor *[OHCI_NUMBER_OF_INTERRUPTS]; 178 if (!fInterruptEndpoints) { 179 TRACE_ERROR(("ohci_usb: cannot allocate memory for" 180 " fInterruptEndpoints array\n")); 181 _FreeEndpoint(fDummyControl); 182 _FreeEndpoint(fDummyBulk); 183 _FreeEndpoint(fDummyIsochronous); 184 return; 185 } 186 for (uint32 i = 0; i < OHCI_NUMBER_OF_INTERRUPTS; i++) { 187 fInterruptEndpoints[i] = _AllocateEndpoint(); 188 if (!fInterruptEndpoints[i]) { 189 TRACE_ERROR(("ohci_usb: cannot allocate memory for" 190 " fInterruptEndpoints[%ld] endpoint\n", i)); 191 while (--i >= 0) 192 _FreeEndpoint(fInterruptEndpoints[i]); 193 _FreeEndpoint(fDummyBulk); 194 _FreeEndpoint(fDummyControl); 195 _FreeEndpoint(fDummyIsochronous); 196 return; 197 } 198 // Make them point all to the dummy isochronous endpoint 199 fInterruptEndpoints[i]->flags |= OHCI_ENDPOINT_SKIP; 200 fInterruptEndpoints[i]->next_physical_endpoint 201 = fDummyIsochronous->physical_address; 202 } 203 204 // Fill HCCA interrupt table. 205 for (uint32 i = 0; i < OHCI_NUMBER_OF_INTERRUPTS; i++) 206 fHcca->interrupt_table[i] = fInterruptEndpoints[i]->physical_address; 207 208 // Determine in what context we are running (Kindly copied from FreeBSD) 209 uint32 control = _ReadReg(OHCI_CONTROL); 210 if (control & OHCI_INTERRUPT_ROUTING) { 211 TRACE(("usb_ohci: SMM is in control of the host controller\n")); 212 uint32 status = _ReadReg(OHCI_COMMAND_STATUS); 213 _WriteReg(OHCI_COMMAND_STATUS, status | OHCI_OWNERSHIP_CHANGE_REQUEST); 214 for (uint32 i = 0; i < 100 && (control & OHCI_INTERRUPT_ROUTING); i++) { 215 snooze(1000); 216 control = _ReadReg(OHCI_CONTROL); 217 } 218 if (!(control & OHCI_INTERRUPT_ROUTING)) { 219 TRACE(("usb_ohci: SMM does not respond. Resetting...\n")); 220 _WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET); 221 snooze(USB_DELAY_BUS_RESET); 222 } 223 } else { 224 TRACE(("usb_ohci: cold started\n")); 225 snooze(USB_DELAY_BUS_RESET); 226 } 227 228 // This reset should not be necessary according to the OHCI spec, but 229 // without it some controllers do not start. 230 _WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET); 231 snooze(USB_DELAY_BUS_RESET); 232 233 // We now own the host controller and the bus has been reset 234 uint32 frameInterval = _ReadReg(OHCI_FRAME_INTERVAL); 235 uint32 intervalValue = OHCI_GET_INTERVAL_VALUE(frameInterval); 236 237 // Disable interrupts right before we reset 238 cpu_status former = disable_interrupts(); 239 _WriteReg(OHCI_COMMAND_STATUS, OHCI_HOST_CONTROLLER_RESET); 240 // Nominal time for a reset is 10 us 241 uint32 reset = 0; 242 for (uint32 i = 0; i < 10; i++) { 243 spin(10); 244 reset = _ReadReg(OHCI_COMMAND_STATUS) & OHCI_HOST_CONTROLLER_RESET; 245 if (!reset) 246 break; 247 } 248 if (reset) { 249 TRACE_ERROR(("usb_ohci: Error resetting the host controller (timeout)\n")); 250 restore_interrupts(former); 251 return; 252 } 253 254 // The controller is now in SUSPEND state, we have 2ms to go OPERATIONAL. 255 // Interrupts are disabled. 256 257 // Set up host controller register 258 _WriteReg(OHCI_HCCA, (uint32)hccaPhysicalAddress); 259 _WriteReg(OHCI_CONTROL_HEAD_ED, (uint32)fDummyControl->physical_address); 260 _WriteReg(OHCI_BULK_HEAD_ED, (uint32)fDummyBulk->physical_address); 261 // Disable all interrupts and then switch on all desired interrupts 262 _WriteReg(OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTERRUPTS); 263 _WriteReg(OHCI_INTERRUPT_ENABLE, OHCI_NORMAL_INTERRUPTS 264 | OHCI_MASTER_INTERRUPT_ENABLE); 265 // Switch on desired functional features 266 control = _ReadReg(OHCI_CONTROL); 267 control &= ~(OHCI_CONTROL_BULK_SERVICE_RATIO_MASK | OHCI_ENABLE_LIST 268 | OHCI_HC_FUNCTIONAL_STATE_MASK | OHCI_INTERRUPT_ROUTING); 269 control |= OHCI_ENABLE_LIST | OHCI_CONTROL_BULK_RATIO_1_4 270 | OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL; 271 // And finally start the controller 272 _WriteReg(OHCI_CONTROL, control); 273 274 restore_interrupts(former); 275 276 // The controller is now OPERATIONAL. 277 frameInterval = (_ReadReg(OHCI_FRAME_INTERVAL) & OHCI_FRAME_INTERVAL_TOGGLE) 278 ^ OHCI_FRAME_INTERVAL_TOGGLE; 279 frameInterval |= OHCI_FSMPS(intervalValue) | intervalValue; 280 _WriteReg(OHCI_FRAME_INTERVAL, frameInterval); 281 // 90% periodic 282 uint32 periodic = OHCI_PERIODIC(intervalValue); 283 _WriteReg(OHCI_PERIODIC_START, periodic); 284 285 // Fiddle the No Over Current Protection bit to avoid chip bug 286 uint32 desca = _ReadReg(OHCI_RH_DESCRIPTOR_A); 287 _WriteReg(OHCI_RH_DESCRIPTOR_A, desca | OHCI_RH_NO_OVER_CURRENT_PROTECTION); 288 _WriteReg(OHCI_RH_STATUS, OHCI_RH_LOCAL_POWER_STATUS_CHANGE); 289 snooze(OHCI_ENABLE_POWER_DELAY); 290 _WriteReg(OHCI_RH_DESCRIPTOR_A, desca); 291 292 // The AMD756 requires a delay before re-reading the register, 293 // otherwise it will occasionally report 0 ports. 294 uint32 numberOfPorts = 0; 295 for (uint32 i = 0; i < 10 && numberOfPorts == 0; i++) { 296 snooze(OHCI_READ_DESC_DELAY); 297 uint32 descriptor = _ReadReg(OHCI_RH_DESCRIPTOR_A); 298 numberOfPorts = OHCI_RH_GET_PORT_COUNT(descriptor); 299 } 300 fPortCount = numberOfPorts; 301 302 // Create semaphore the finisher thread will wait for 303 fFinishTransfersSem = create_sem(0, "OHCI Finish Transfers"); 304 if (fFinishTransfersSem < B_OK) { 305 TRACE_ERROR(("usb_ohci: failed to create semaphore\n")); 306 return; 307 } 308 309 // Create the finisher service thread 310 fFinishThread = spawn_kernel_thread(_FinishThread, "ohci finish thread", 311 B_URGENT_DISPLAY_PRIORITY, (void *)this); 312 resume_thread(fFinishThread); 313 314 // Install the interrupt handler 315 TRACE(("usb_ohci: installing interrupt handler\n")); 316 install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line, 317 _InterruptHandler, (void *)this, 0); 318 319 TRACE(("usb_ohci: OHCI Host Controller Driver constructed\n")); 320 fInitOK = true; 321 } 322 323 324 OHCI::~OHCI() 325 { 326 int32 result = 0; 327 fStopFinishThread = true; 328 delete_sem(fFinishTransfersSem); 329 wait_for_thread(fFinishThread, &result); 330 331 if (fHccaArea > 0) 332 delete_area(fHccaArea); 333 if (fRegisterArea > 0) 334 delete_area(fRegisterArea); 335 if (fHashGenericTable) 336 free(fHashGenericTable); 337 if (fHashIsochronousTable) 338 free(fHashIsochronousTable); 339 if (fDummyControl) 340 _FreeEndpoint(fDummyControl); 341 if (fDummyBulk) 342 _FreeEndpoint(fDummyBulk); 343 if (fDummyIsochronous) 344 _FreeEndpoint(fDummyIsochronous); 345 if (fRootHub) 346 delete fRootHub; 347 for (int i = 0; i < OHCI_NUMBER_OF_INTERRUPTS; i++) 348 if (fInterruptEndpoints[i]) 349 _FreeEndpoint(fInterruptEndpoints[i]); 350 delete [] fInterruptEndpoints; 351 put_module(B_PCI_MODULE_NAME); 352 } 353 354 355 int32 356 OHCI::_InterruptHandler(void *data) 357 { 358 return ((OHCI *)data)->_Interrupt(); 359 } 360 361 362 int32 363 OHCI::_Interrupt() 364 { 365 static spinlock lock = 0; 366 acquire_spinlock(&lock); 367 368 uint32 status = 0; 369 uint32 acknowledge = 0; 370 bool finishTransfers = false; 371 int32 result = B_HANDLED_INTERRUPT; 372 373 // The LSb of done_head is used to inform the HCD that an interrupt 374 // condition exists for both the done list and for another event recorded in 375 // the HcInterruptStatus register. If done_head is 0, then the interrupt 376 // was caused by other than the HccaDoneHead update and the 377 // HcInterruptStatus register needs to be accessed to determine that exact 378 // interrupt cause. If HccDoneHead is nonzero, then a done list update 379 // interrupt is indicated and if the LSb of the Dword is nonzero, then an 380 // additional interrupt event is indicated and HcInterruptStatus shuold be 381 // checked to determine its cause. 382 uint32 doneHead = fHcca->done_head; 383 if (doneHead != 0) { 384 status = OHCI_WRITEBACK_DONE_HEAD; 385 if (doneHead & OHCI_DONE_INTERRUPTS) 386 status |= _ReadReg(OHCI_INTERRUPT_STATUS) 387 & _ReadReg(OHCI_INTERRUPT_ENABLE); 388 } else { 389 status = _ReadReg(OHCI_INTERRUPT_STATUS) & _ReadReg(OHCI_INTERRUPT_ENABLE) 390 & ~OHCI_WRITEBACK_DONE_HEAD; 391 if (status == 0) { 392 // Nothing to be done (PCI shared interrupt) 393 release_spinlock(&lock); 394 return B_UNHANDLED_INTERRUPT; 395 } 396 } 397 398 if (status & OHCI_SCHEDULING_OVERRUN) { 399 // TODO 400 TRACE(("usb_ohci: scheduling overrun occured\n")); 401 } 402 403 if (status & OHCI_WRITEBACK_DONE_HEAD) { 404 TRACE(("usb_ohci: transfer descriptor processed\n")); 405 // Ack it in the finisher thread, not here. 406 result = B_INVOKE_SCHEDULER; 407 finishTransfers = true; 408 } 409 410 if (status & OHCI_RESUME_DETECTED) { 411 // TODO 412 TRACE(("usb_ohci: resume detected\n")); 413 } 414 415 if (status & OHCI_UNRECOVERABLE_ERROR) { 416 TRACE(("usb_ohci: unrecoverable error. Controller halted\n")); 417 _WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET); 418 // TODO: what else? 419 // Perhaps, clean up all the memory. 420 } 421 422 if (status & OHCI_ROOT_HUB_STATUS_CHANGE) { 423 // TODO 424 TRACE(("usb_ohci: root hub status change\n")); 425 } 426 427 release_spinlock(&lock); 428 429 if (finishTransfers) 430 release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE); 431 432 return result; 433 } 434 435 436 int32 437 OHCI::_FinishThread(void *data) 438 { 439 ((OHCI *)data)->_FinishTransfer(); 440 return B_OK; 441 } 442 443 444 void 445 OHCI::_FinishTransfer() 446 { 447 while (!fStopFinishThread) { 448 if (acquire_sem(fFinishTransfersSem) < B_OK) 449 continue; 450 451 // eat up sems that have been released by multiple interrupts 452 int32 semCount = 0; 453 get_sem_count(fFinishTransfersSem, &semCount); 454 if (semCount > 0) 455 acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0); 456 457 uint32 done_list = fHcca->done_head & ~OHCI_DONE_INTERRUPTS; 458 // If done_head is zero, there are not processed descriptors 459 // in the done list and we have been woken up by CancelQueuedTransfers 460 // or CancelQueuedIsochronousTransfers in order to do some clean up 461 // and back to sleep. 462 if (done_list) { 463 // Pull out the done list and reverse its order 464 // for both general and isochronous descriptors 465 ohci_general_td *current, *top; 466 ohci_isochronous_td *isoCurrent, *isoTop; 467 for ( top = NULL, isoTop = NULL ; done_list != 0; ) { 468 if ((current = _FindDescriptorInHash(done_list))) { 469 done_list = current->next_physical_descriptor; 470 current->next_done_descriptor = (void *)top; 471 top = current; 472 continue; 473 } 474 if ((isoCurrent = _FindIsoDescriptorInHash(done_list))) { 475 done_list = isoCurrent->next_physical_descriptor; 476 isoCurrent->next_done_descriptor = (void *)isoTop; 477 isoTop = isoCurrent; 478 continue; 479 } 480 // TODO: Should I panic here? :) 481 TRACE_ERROR(("usb_ohci: address 0x%08lx not found!\n", 482 done_list)); 483 break; 484 } 485 486 // Acknowledge the interrupt 487 // TODO: Move the acknowledgement in the interrupt handler. 488 // The done_head value can be passed through a shared variable. 489 fHcca->done_head = 0; 490 _WriteReg(OHCI_INTERRUPT_ENABLE, OHCI_WRITEBACK_DONE_HEAD); 491 492 // Process isochronous list first 493 for (isoCurrent = isoTop; isoCurrent != NULL; isoCurrent 494 = (ohci_isochronous_td *)isoCurrent->next_done_descriptor) { 495 // TODO: Process isochronous descriptors 496 } 497 498 // Now process the general list 499 for (current = top; current != NULL; ) { 500 ohci_general_td *next 501 = (ohci_general_td *)current->next_done_descriptor; 502 503 transfer_data *transfer = (transfer_data *)current->transfer; 504 if (transfer->canceled) { 505 // Clear canceled transfer later on 506 current = next; 507 continue; 508 } 509 510 bool transferDone = false; 511 status_t callbackStatus = B_OK; 512 uint32 conditionCode = OHCI_TD_GET_CONDITION_CODE(current->flags); 513 if (conditionCode != OHCI_NO_ERROR) { 514 // Endpoint is halted: unlink all descriptors belonging to 515 // the failed transfer from the endpoint and restart the 516 // endpoint. 517 // NOTE: There can(should) not be more than one 518 // invalid descriptor from the same transfer in the 519 // done list, as the controller halt the endpoint right 520 // away if a descriptor fails. This means that, if we reversed 521 // the order of the done list (which we did), there is 522 // not reason to look for more failed descriptors in the 523 // done list from the same transfer, as *BSD code does. 524 TRACE(("usb_ohci: transfer failed! ohci error code: %d\n", 525 conditionCode)); 526 527 // Remove remaining descriptors from the same transfer 528 if (!current->is_last) 529 _RemoveTransferFromEndpoint(transfer); 530 531 // TODO: Fix the following with the appropriate error 532 callbackStatus = B_DEV_MULTIPLE_ERRORS; 533 transferDone = true; 534 continue; 535 } else if (current->is_last) 536 transferDone = true; 537 538 if (transferDone) { 539 size_t actualLength = 0; 540 if (callbackStatus == B_OK) { 541 if (transfer->data_descriptor && transfer->incoming) { 542 // Read data out 543 } else { 544 // How much was transfer? 545 } 546 if (transfer->transfer->IsFragmented()) { 547 // TODO 548 } 549 } 550 _UnlinkTransfer(transfer); 551 transfer->transfer->Finished(callbackStatus, actualLength); 552 // Update next before current gets deleted 553 next = (ohci_general_td *)current->next_done_descriptor; 554 _FreeDescriptorChain(transfer->first_descriptor); 555 556 delete transfer->transfer; 557 delete transfer; 558 559 } 560 current = next; 561 } 562 563 } 564 565 // Quick look for canceled transfer before 566 // we go back to sleep 567 transfer_data *current = fFirstTransfer; 568 while (current) { 569 transfer_data *next = current->link; 570 if (current->canceled) { 571 _UnlinkTransfer(current); 572 _FreeDescriptorChain(current->first_descriptor); 573 delete current->transfer; 574 delete current; 575 } 576 current = next; 577 } 578 } 579 } 580 581 582 status_t 583 OHCI::_AppendChainDescriptorsToEndpoint(ohci_endpoint_descriptor *endpoint, 584 ohci_general_td *first, ohci_general_td *last) 585 { 586 endpoint->flags |= OHCI_ENDPOINT_SKIP; 587 snooze(1000); 588 589 // TODO: Lock on endpoint 590 ohci_general_td *head = (ohci_general_td *)endpoint->head_logical_descriptor; 591 ohci_general_td *tail = (ohci_general_td *)endpoint->tail_logical_descriptor; 592 if (head != tail) { 593 // Find the last real descriptor 594 ohci_general_td *current = head; 595 while (current->next_logical_descriptor != tail) 596 current = (ohci_general_td *)current->next_logical_descriptor; 597 // Append to current 598 current->next_logical_descriptor = first; 599 current->next_physical_descriptor = first->physical_address; 600 } else { 601 // Endpoint has only the dummy descriptor 602 endpoint->head_logical_descriptor = first; 603 endpoint->head_physical_descriptor = first->physical_address; 604 } 605 606 // Make the last descriptor point to the dummy 607 last->next_logical_descriptor = tail; 608 last->next_physical_descriptor = tail->physical_address; 609 610 endpoint->flags &= ~OHCI_ENDPOINT_SKIP; 611 return B_OK; 612 } 613 614 615 void 616 OHCI::_RemoveTransferFromEndpoint(transfer_data *transfer) 617 { 618 // TODO: Add lock for endpoint 619 ohci_endpoint_descriptor *endpoint = transfer->endpoint; 620 ohci_general_td *next = (ohci_general_td *)endpoint->head_logical_descriptor; 621 622 // Find the first descriptor of a different transfer. 623 // Worst scenario we get the dummy descriptor 624 while ((transfer_data *)next->transfer == transfer) 625 next = (ohci_general_td *)next->next_logical_descriptor; 626 // Update head 627 endpoint->head_logical_descriptor = next; 628 endpoint->head_physical_descriptor = next->physical_address; 629 } 630 631 632 status_t 633 OHCI::_UnlinkTransfer(transfer_data *transfer) 634 { 635 if (Lock()) { 636 if (transfer == fFirstTransfer) { 637 // It was the first element 638 fFirstTransfer = fFirstTransfer->link; 639 if (transfer == fLastTransfer) 640 // Also the only one 641 fLastTransfer = NULL; 642 } else { 643 transfer_data *data = fFirstTransfer->link; 644 transfer_data *previous = fFirstTransfer; 645 while (data != NULL) { 646 if (data == transfer) { 647 previous->link = data->link; 648 if (data == fLastTransfer) 649 fLastTransfer = previous; 650 break; 651 } 652 previous = data; 653 data = data->link; 654 } 655 } 656 Unlock(); 657 return B_OK; 658 } 659 return B_ERROR; 660 } 661 662 663 void 664 OHCI::_AddDescriptorToHash(ohci_general_td *descriptor) 665 { 666 // TODO 667 } 668 669 670 void 671 OHCI::_RemoveDescriptorFromHash(ohci_general_td *descriptor) 672 { 673 // TODO 674 } 675 676 677 ohci_general_td* 678 OHCI::_FindDescriptorInHash(uint32 physicalAddress) 679 { 680 // TODO 681 return NULL; 682 } 683 684 685 void 686 OHCI::_AddIsoDescriptorToHash(ohci_isochronous_td *descriptor) 687 { 688 // TODO 689 } 690 691 692 void 693 OHCI::_RemoveIsoDescriptorFromHash(ohci_isochronous_td *descriptor) 694 { 695 // TODO 696 } 697 698 699 ohci_isochronous_td* 700 OHCI::_FindIsoDescriptorInHash(uint32 physicalAddress) 701 { 702 // TODO 703 return NULL; 704 } 705 706 707 status_t 708 OHCI::Start() 709 { 710 TRACE(("usb_ohci: starting OHCI Host Controller\n")); 711 712 if ((_ReadReg(OHCI_CONTROL) & OHCI_HC_FUNCTIONAL_STATE_MASK) 713 != OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL) { 714 TRACE_ERROR(("usb_ohci: Controller not started!\n")); 715 return B_ERROR; 716 } else { 717 TRACE(("usb_ohci: Controller is OPERATIONAL!\n")); 718 } 719 720 fRootHubAddress = AllocateAddress(); 721 fRootHub = new(std::nothrow) OHCIRootHub(RootObject(), fRootHubAddress); 722 if (!fRootHub) { 723 TRACE_ERROR(("usb_ohci: no memory to allocate root hub\n")); 724 return B_NO_MEMORY; 725 } 726 727 if (fRootHub->InitCheck() < B_OK) { 728 TRACE_ERROR(("usb_ohci: root hub failed init check\n")); 729 return B_ERROR; 730 } 731 732 SetRootHub(fRootHub); 733 TRACE(("usb_ohci: Host Controller started\n")); 734 return BusManager::Start(); 735 } 736 737 738 status_t 739 OHCI::SubmitTransfer(Transfer *transfer) 740 { 741 // short circuit the root hub 742 if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress) 743 return fRootHub->ProcessTransfer(this, transfer); 744 745 uint32 type = transfer->TransferPipe()->Type(); 746 if ((type & USB_OBJECT_CONTROL_PIPE)) { 747 TRACE(("usb_ohci: submitting control request\n")); 748 return _SubmitControlRequest(transfer); 749 } 750 751 if ((type & USB_OBJECT_BULK_PIPE)) { 752 TRACE(("usb_ohci: submitting bulk transfer\n")); 753 return _SubmitBulkTransfer(transfer); 754 } 755 756 if (((type & USB_OBJECT_ISO_PIPE) || (type & USB_OBJECT_INTERRUPT_PIPE))) { 757 TRACE(("usb_ohci: submitting periodic transfer\n")); 758 return _SubmitPeriodicTransfer(transfer); 759 } 760 761 TRACE_ERROR(("usb_ohci: tried to submit transfer for unknown pipe" 762 " type %lu\n", type)); 763 return B_ERROR; 764 } 765 766 767 status_t 768 OHCI::_SubmitControlRequest(Transfer *transfer) 769 { 770 usb_request_data *requestData = transfer->RequestData(); 771 bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0; 772 773 ohci_general_td *setupDescriptor 774 = _CreateGeneralDescriptor(sizeof(usb_request_data)); 775 if (!setupDescriptor) { 776 TRACE_ERROR(("usb_ohci: failed to allocate setup descriptor\n")); 777 return B_NO_MEMORY; 778 } 779 // Flags set up could be moved into _CreateGeneralDescriptor 780 setupDescriptor->flags |= OHCI_TD_DIRECTION_PID_SETUP 781 | OHCI_TD_NO_CONDITION_CODE 782 | OHCI_TD_TOGGLE_0 783 | OHCI_TD_SET_DELAY_INTERRUPT(6); // Not sure about this. 784 785 ohci_general_td *statusDescriptor 786 = _CreateGeneralDescriptor(0); 787 if (!statusDescriptor) { 788 TRACE_ERROR(("usb_ohci: failed to allocate status descriptor\n")); 789 _FreeGeneralDescriptor(setupDescriptor); 790 return B_NO_MEMORY; 791 } 792 statusDescriptor->flags 793 |= (directionIn ? OHCI_TD_DIRECTION_PID_OUT : OHCI_TD_DIRECTION_PID_IN) 794 | OHCI_TD_NO_CONDITION_CODE 795 | OHCI_TD_TOGGLE_1 796 | OHCI_TD_SET_DELAY_INTERRUPT(1); 797 798 iovec vector; 799 vector.iov_base = requestData; 800 vector.iov_len = sizeof(usb_request_data); 801 _WriteDescriptorChain(setupDescriptor, &vector, 1); 802 803 status_t result; 804 ohci_general_td *dataDescriptor = NULL; 805 if (transfer->VectorCount() > 0) { 806 ohci_general_td *lastDescriptor = NULL; 807 result = _CreateDescriptorChain(&dataDescriptor, 808 &lastDescriptor, 809 directionIn ? OHCI_TD_DIRECTION_PID_OUT : OHCI_TD_DIRECTION_PID_IN, 810 transfer->VectorLength()); 811 if (result < B_OK) { 812 _FreeGeneralDescriptor(setupDescriptor); 813 _FreeGeneralDescriptor(statusDescriptor); 814 return result; 815 } 816 817 if (!directionIn) { 818 _WriteDescriptorChain(dataDescriptor, transfer->Vector(), 819 transfer->VectorCount()); 820 } 821 822 _LinkDescriptors(setupDescriptor, dataDescriptor); 823 _LinkDescriptors(lastDescriptor, statusDescriptor); 824 } else { 825 _LinkDescriptors(setupDescriptor, statusDescriptor); 826 } 827 828 // Append Transfer 829 ohci_endpoint_descriptor *endpoint 830 = (ohci_endpoint_descriptor *)transfer->TransferPipe()->ControllerCookie(); 831 result = _AddPendingTransfer(transfer, endpoint, setupDescriptor, 832 dataDescriptor, directionIn); 833 if (result < B_OK) { 834 TRACE_ERROR(("usb_ohci: failed to add pending transfer\n")); 835 _FreeDescriptorChain(setupDescriptor); 836 return result; 837 } 838 839 // Append descriptors chain to the endpoint 840 result = _AppendChainDescriptorsToEndpoint(endpoint, setupDescriptor, 841 statusDescriptor); 842 if (result < B_OK) { 843 TRACE_ERROR(("usb_ohci: failed to append chain descriptors to endpoint\n")); 844 // TODO: Remove transfer_data from list 845 _FreeDescriptorChain(setupDescriptor); 846 } 847 848 // Tell the controller to process the control list 849 _WriteReg(OHCI_COMMAND_STATUS, OHCI_CONTROL_LIST_FILLED); 850 return B_OK; 851 } 852 853 854 status_t 855 OHCI::_SubmitBulkTransfer(Transfer *transfer) 856 { 857 // TODO 858 return B_ERROR; 859 } 860 861 862 status_t 863 OHCI::_AddPendingTransfer(Transfer *transfer, ohci_endpoint_descriptor *endpoint, 864 ohci_general_td *firstDescriptor, ohci_general_td *dataDescriptor, bool directionIn) 865 { 866 if (!transfer || !endpoint || !firstDescriptor) 867 return B_BAD_VALUE; 868 869 transfer_data *data = new(std::nothrow) transfer_data; 870 if (!data) 871 return B_NO_MEMORY; 872 873 status_t result = transfer->InitKernelAccess(); 874 if (result < B_OK) { 875 delete data; 876 return result; 877 } 878 879 data->transfer = transfer; 880 data->endpoint = endpoint; 881 data->first_descriptor = firstDescriptor; 882 data->data_descriptor = dataDescriptor; 883 data->incoming = directionIn; 884 data->canceled = false; 885 data->link = NULL; 886 887 if (!Lock()) { 888 delete data; 889 return B_ERROR; 890 } 891 892 if (fLastTransfer) 893 fLastTransfer->link = data; 894 else 895 fFirstTransfer = data; 896 897 fLastTransfer = data; 898 Unlock(); 899 900 return B_OK; 901 } 902 903 904 status_t 905 OHCI::_SubmitPeriodicTransfer(Transfer *transfer) 906 { 907 return B_ERROR; 908 } 909 910 911 void 912 OHCI::_LinkDescriptors(ohci_general_td *first, ohci_general_td *second) 913 { 914 first->next_physical_descriptor = second->physical_address; 915 first->next_logical_descriptor = second; 916 } 917 918 919 status_t 920 OHCI::_CreateDescriptorChain(ohci_general_td **_firstDescriptor, 921 ohci_general_td **_lastDescriptor, uint8 direction, size_t bufferSize) 922 { 923 return B_ERROR; 924 } 925 926 927 void 928 OHCI::_FreeDescriptorChain(ohci_general_td *topDescriptor) 929 { 930 ohci_general_td *current = topDescriptor; 931 ohci_general_td *next = NULL; 932 933 while (current) { 934 next = (ohci_general_td *)current->next_logical_descriptor; 935 _FreeGeneralDescriptor(current); 936 current = next; 937 } 938 } 939 940 941 size_t 942 OHCI::_WriteDescriptorChain(ohci_general_td *topDescriptor, iovec *vector, 943 size_t vectorCount) 944 { 945 ohci_general_td *current = topDescriptor; 946 size_t actualLength = 0; 947 size_t vectorIndex = 0; 948 size_t vectorOffset = 0; 949 size_t bufferOffset = 0; 950 951 while (current) { 952 if (!current->buffer_logical) 953 break; 954 955 while (true) { 956 size_t length = min_c(current->buffer_size - bufferOffset, 957 vector[vectorIndex].iov_len - vectorOffset); 958 959 TRACE(("usb_ohci: copying %ld bytes to bufferOffset %ld from" 960 " vectorOffset %ld at index %ld of %ld\n", length, bufferOffset, 961 vectorOffset, vectorIndex, vectorCount)); 962 memcpy((uint8 *)current->buffer_logical + bufferOffset, 963 (uint8 *)vector[vectorIndex].iov_base + vectorOffset, length); 964 965 actualLength += length; 966 vectorOffset += length; 967 bufferOffset += length; 968 969 if (vectorOffset >= vector[vectorIndex].iov_len) { 970 if (++vectorIndex >= vectorCount) { 971 TRACE(("usb_ohci: wrote descriptor chain (%ld bytes, no" 972 " more vectors)\n", actualLength)); 973 return actualLength; 974 } 975 976 vectorOffset = 0; 977 } 978 979 if (bufferOffset >= current->buffer_size) { 980 bufferOffset = 0; 981 break; 982 } 983 } 984 985 if (!current->next_logical_descriptor) 986 break; 987 988 current = (ohci_general_td *)current->next_logical_descriptor; 989 } 990 991 TRACE(("usb_ohci: wrote descriptor chain (%ld bytes)\n", actualLength)); 992 return actualLength; 993 } 994 995 996 status_t 997 OHCI::NotifyPipeChange(Pipe *pipe, usb_change change) 998 { 999 TRACE(("usb_ohci: pipe change %d for pipe 0x%08lx\n", change, (uint32)pipe)); 1000 switch (change) { 1001 case USB_CHANGE_CREATED: { 1002 TRACE(("usb_ohci: inserting endpoint\n")); 1003 return _InsertEndpointForPipe(pipe); 1004 } 1005 case USB_CHANGE_DESTROYED: { 1006 TRACE(("usb_ohci: removing endpoint\n")); 1007 return _RemoveEndpointForPipe(pipe); 1008 } 1009 case USB_CHANGE_PIPE_POLICY_CHANGED: { 1010 TRACE(("usb_ohci: pipe policy changing unhandled!\n")); 1011 break; 1012 } 1013 default: { 1014 TRACE_ERROR(("usb_ohci: unknown pipe change!\n")); 1015 return B_ERROR; 1016 } 1017 } 1018 return B_OK; 1019 } 1020 1021 1022 status_t 1023 OHCI::AddTo(Stack *stack) 1024 { 1025 #ifdef TRACE_USB 1026 set_dprintf_enabled(true); 1027 load_driver_symbols("ohci"); 1028 #endif 1029 1030 if (!sPCIModule) { 1031 status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&sPCIModule); 1032 if (status < B_OK) { 1033 TRACE_ERROR(("usb_ohci: getting pci module failed! 0x%08lx\n", 1034 status)); 1035 return status; 1036 } 1037 } 1038 1039 TRACE(("usb_ohci: searching devices\n")); 1040 bool found = false; 1041 pci_info *item = new(std::nothrow) pci_info; 1042 if (!item) { 1043 sPCIModule = NULL; 1044 put_module(B_PCI_MODULE_NAME); 1045 return B_NO_MEMORY; 1046 } 1047 1048 for (uint32 i = 0 ; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) { 1049 1050 if (item->class_base == PCI_serial_bus && item->class_sub == PCI_usb 1051 && item->class_api == PCI_usb_ohci) { 1052 if (item->u.h0.interrupt_line == 0 1053 || item->u.h0.interrupt_line == 0xFF) { 1054 TRACE_ERROR(("usb_ohci: found device with invalid IRQ -" 1055 " check IRQ assignement\n")); 1056 continue; 1057 } 1058 1059 TRACE(("usb_ohci: found device at IRQ %u\n", 1060 item->u.h0.interrupt_line)); 1061 OHCI *bus = new(std::nothrow) OHCI(item, stack); 1062 if (!bus) { 1063 delete item; 1064 sPCIModule = NULL; 1065 put_module(B_PCI_MODULE_NAME); 1066 return B_NO_MEMORY; 1067 } 1068 1069 if (bus->InitCheck() < B_OK) { 1070 TRACE_ERROR(("usb_ohci: bus failed init check\n")); 1071 delete bus; 1072 continue; 1073 } 1074 1075 // the bus took it away 1076 item = new(std::nothrow) pci_info; 1077 1078 bus->Start(); 1079 stack->AddBusManager(bus); 1080 found = true; 1081 } 1082 } 1083 1084 if (!found) { 1085 TRACE_ERROR(("usb_ohci: no devices found\n")); 1086 delete item; 1087 sPCIModule = NULL; 1088 put_module(B_PCI_MODULE_NAME); 1089 return ENODEV; 1090 } 1091 1092 delete item; 1093 return B_OK; 1094 } 1095 1096 1097 status_t 1098 OHCI::GetPortStatus(uint8 index, usb_port_status *status) 1099 { 1100 TRACE(("usb_ohci::%s(%ud, )\n", __FUNCTION__, index)); 1101 if (index >= fPortCount) 1102 return B_BAD_INDEX; 1103 1104 status->status = status->change = 0; 1105 uint32 portStatus = _ReadReg(OHCI_RH_PORT_STATUS(index)); 1106 1107 TRACE(("usb_ohci: RootHub::GetPortStatus: Port %i Value 0x%lx\n", OHCI_RH_PORT_STATUS(index), portStatus)); 1108 1109 // status 1110 if (portStatus & OHCI_RH_PORTSTATUS_CCS) 1111 status->status |= PORT_STATUS_CONNECTION; 1112 if (portStatus & OHCI_RH_PORTSTATUS_PES) 1113 status->status |= PORT_STATUS_ENABLE; 1114 if (portStatus & OHCI_RH_PORTSTATUS_PRS) 1115 status->status |= PORT_STATUS_RESET; 1116 if (portStatus & OHCI_RH_PORTSTATUS_LSDA) 1117 status->status |= PORT_STATUS_LOW_SPEED; 1118 if (portStatus & OHCI_RH_PORTSTATUS_PSS) 1119 status->status |= PORT_STATUS_SUSPEND; 1120 if (portStatus & OHCI_RH_PORTSTATUS_POCI) 1121 status->status |= PORT_STATUS_OVER_CURRENT; 1122 if (portStatus & OHCI_RH_PORTSTATUS_PPS) 1123 status->status |= PORT_STATUS_POWER; 1124 1125 // change 1126 if (portStatus & OHCI_RH_PORTSTATUS_CSC) 1127 status->change |= PORT_STATUS_CONNECTION; 1128 if (portStatus & OHCI_RH_PORTSTATUS_PESC) 1129 status->change |= PORT_STATUS_ENABLE; 1130 if (portStatus & OHCI_RH_PORTSTATUS_PSSC) 1131 status->change |= PORT_STATUS_SUSPEND; 1132 if (portStatus & OHCI_RH_PORTSTATUS_OCIC) 1133 status->change |= PORT_STATUS_OVER_CURRENT; 1134 if (portStatus & OHCI_RH_PORTSTATUS_PRSC) 1135 status->change |= PORT_STATUS_RESET; 1136 1137 return B_OK; 1138 } 1139 1140 1141 status_t 1142 OHCI::SetPortFeature(uint8 index, uint16 feature) 1143 { 1144 TRACE(("OHCI::%s(%ud, %ud)\n", __FUNCTION__, index, feature)); 1145 if (index > fPortCount) 1146 return B_BAD_INDEX; 1147 1148 switch (feature) { 1149 case PORT_RESET: 1150 _WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_RH_PORTSTATUS_PRS); 1151 return B_OK; 1152 1153 case PORT_POWER: 1154 _WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_RH_PORTSTATUS_PPS); 1155 return B_OK; 1156 } 1157 1158 return B_BAD_VALUE; 1159 } 1160 1161 1162 status_t 1163 OHCI::ClearPortFeature(uint8 index, uint16 feature) 1164 { 1165 TRACE(("OHCI::%s(%ud, %ud)\n", __FUNCTION__, index, feature)); 1166 if (index > fPortCount) 1167 return B_BAD_INDEX; 1168 1169 switch (feature) { 1170 case C_PORT_RESET: 1171 _WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_RH_PORTSTATUS_CSC); 1172 return B_OK; 1173 1174 case C_PORT_CONNECTION: 1175 _WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_RH_PORTSTATUS_CSC); 1176 return B_OK; 1177 } 1178 1179 return B_BAD_VALUE; 1180 } 1181 1182 1183 ohci_endpoint_descriptor* 1184 OHCI::_AllocateEndpoint() 1185 { 1186 ohci_endpoint_descriptor *endpoint; 1187 void* physicalAddress; 1188 1189 // Allocate memory chunk 1190 if (fStack->AllocateChunk((void **)&endpoint, &physicalAddress, 1191 sizeof(ohci_endpoint_descriptor)) < B_OK) { 1192 TRACE_ERROR(("usb_ohci: failed to allocate endpoint descriptor\n")); 1193 return NULL; 1194 } 1195 memset((void *)endpoint, 0, sizeof(ohci_endpoint_descriptor)); 1196 1197 endpoint->physical_address = (addr_t)physicalAddress; 1198 1199 endpoint->head_physical_descriptor = NULL; 1200 endpoint->tail_physical_descriptor = NULL; 1201 1202 endpoint->head_logical_descriptor = NULL; 1203 endpoint->tail_logical_descriptor = NULL; 1204 1205 return endpoint; 1206 } 1207 1208 1209 void 1210 OHCI::_FreeEndpoint(ohci_endpoint_descriptor *endpoint) 1211 { 1212 if (!endpoint) 1213 return; 1214 1215 fStack->FreeChunk((void *)endpoint, (void *)endpoint->physical_address, 1216 sizeof(ohci_endpoint_descriptor)); 1217 } 1218 1219 1220 ohci_general_td* 1221 OHCI::_CreateGeneralDescriptor(size_t bufferSize) 1222 { 1223 ohci_general_td *descriptor; 1224 void *physicalAddress; 1225 1226 if (fStack->AllocateChunk((void **)&descriptor, &physicalAddress, 1227 sizeof(ohci_general_td)) != B_OK) { 1228 TRACE_ERROR(("usb_ohci: failed to allocate general descriptor\n")); 1229 return NULL; 1230 } 1231 memset((void *)descriptor, 0, sizeof(ohci_general_td)); 1232 descriptor->physical_address = (addr_t)physicalAddress; 1233 1234 if (!bufferSize) { 1235 descriptor->buffer_physical = 0; 1236 descriptor->buffer_logical = NULL; 1237 descriptor->last_physical_byte_address = 0; 1238 return descriptor; 1239 } 1240 1241 if (fStack->AllocateChunk(&descriptor->buffer_logical, 1242 (void **)&descriptor->buffer_physical, bufferSize) != B_OK) { 1243 TRACE_ERROR(("usb_ohci: failed to allocate space for buffer\n")); 1244 fStack->FreeChunk(descriptor, (void *)descriptor->physical_address, 1245 sizeof(ohci_general_td)); 1246 return NULL; 1247 } 1248 descriptor->last_physical_byte_address 1249 = descriptor->buffer_physical + bufferSize - 1; 1250 1251 return descriptor; 1252 } 1253 1254 1255 void 1256 OHCI::_FreeGeneralDescriptor(ohci_general_td *descriptor) 1257 { 1258 if (!descriptor) 1259 return; 1260 1261 if (descriptor->buffer_logical) { 1262 fStack->FreeChunk(descriptor->buffer_logical, 1263 (void *)descriptor->buffer_physical, descriptor->buffer_size); 1264 } 1265 1266 fStack->FreeChunk((void *)descriptor, (void *)descriptor->physical_address, 1267 sizeof(ohci_general_td)); 1268 } 1269 1270 1271 ohci_isochronous_td* 1272 _CreateIsochronousDescriptor() 1273 { 1274 // TODO 1275 return NULL; 1276 } 1277 1278 1279 void _FreeIsochronousDescriptor(ohci_isochronous_td *descriptor) 1280 { 1281 // TODO 1282 } 1283 1284 1285 status_t 1286 OHCI::_InsertEndpointForPipe(Pipe *pipe) 1287 { 1288 TRACE(("OHCI: Inserting Endpoint for device %u function %u\n", 1289 pipe->DeviceAddress(), pipe->EndpointAddress())); 1290 1291 ohci_endpoint_descriptor *endpoint = _AllocateEndpoint(); 1292 if (!endpoint) { 1293 TRACE_ERROR(("usb_ohci: cannot allocate memory for endpoint\n")); 1294 return B_NO_MEMORY; 1295 } 1296 1297 uint32 flags = 0; 1298 flags |= OHCI_ENDPOINT_SKIP; 1299 1300 // Set up device and endpoint address 1301 flags |= OHCI_ENDPOINT_SET_DEVICE_ADDRESS(pipe->DeviceAddress()) 1302 | OHCI_ENDPOINT_SET_ENDPOINT_NUMBER(pipe->EndpointAddress()); 1303 1304 // Set the direction 1305 switch (pipe->Direction()) { 1306 case Pipe::In: 1307 flags |= OHCI_ENDPOINT_DIRECTION_IN; 1308 break; 1309 case Pipe::Out: 1310 flags |= OHCI_ENDPOINT_DIRECTION_OUT; 1311 break; 1312 case Pipe::Default: 1313 flags |= OHCI_ENDPOINT_DIRECTION_DESCRIPTOR; 1314 break; 1315 default: 1316 TRACE_ERROR(("usb_ohci: direction unknown. Wrong value!\n")); 1317 _FreeEndpoint(endpoint); 1318 return B_ERROR; 1319 } 1320 1321 // Set up the speed 1322 switch (pipe->Speed()) { 1323 case USB_SPEED_LOWSPEED: 1324 flags |= OHCI_ENDPOINT_LOW_SPEED; 1325 break; 1326 case USB_SPEED_FULLSPEED: 1327 flags |= OHCI_ENDPOINT_FULL_SPEED; 1328 break; 1329 case USB_SPEED_HIGHSPEED: 1330 default: 1331 TRACE_ERROR(("usb_ohci: unaccetable speed. Wrong value!\n")); 1332 _FreeEndpoint(endpoint); 1333 return B_ERROR; 1334 } 1335 1336 // Set the maximum packet size 1337 flags |= OHCI_ENDPOINT_SET_MAX_PACKET_SIZE(pipe->MaxPacketSize()); 1338 1339 endpoint->flags = flags; 1340 1341 // Add the endpoint to the appropriate list 1342 ohci_endpoint_descriptor *head = NULL; 1343 switch (pipe->Type()) { 1344 case USB_OBJECT_CONTROL_PIPE: 1345 head = fDummyControl; 1346 break; 1347 case USB_OBJECT_BULK_PIPE: 1348 head = fDummyBulk; 1349 break; 1350 case USB_OBJECT_ISO_PIPE: 1351 // Set the isochronous bit format 1352 endpoint->flags |= OHCI_ENDPOINT_ISOCHRONOUS_FORMAT; 1353 head = fDummyIsochronous; 1354 break; 1355 case USB_OBJECT_INTERRUPT_PIPE: 1356 head = _FindInterruptEndpoint(pipe->Interval()); 1357 break; 1358 default: 1359 TRACE_ERROR(("usb_ohci: unknown type of pipe. Wrong value!\n")); 1360 _FreeEndpoint(endpoint); 1361 return B_ERROR; 1362 } 1363 1364 // Create (necessary) dummy descriptor 1365 if (pipe->Type() & USB_OBJECT_ISO_PIPE) { 1366 // TODO 1367 } else { 1368 ohci_general_td *dummy = _CreateGeneralDescriptor(0); 1369 dummy->next_logical_descriptor = NULL; 1370 dummy->next_physical_descriptor = NULL; 1371 endpoint->head_logical_descriptor 1372 = endpoint->tail_logical_descriptor 1373 = dummy; 1374 endpoint->head_physical_descriptor 1375 = endpoint->tail_physical_descriptor 1376 = dummy->physical_address; 1377 } 1378 1379 // TODO: Change lock lo LockEndpoint() 1380 Lock(); 1381 pipe->SetControllerCookie((void *)endpoint); 1382 endpoint->next_logical_endpoint = head->next_logical_endpoint; 1383 endpoint->next_physical_endpoint = head->next_physical_endpoint; 1384 head->next_logical_endpoint = (void *)endpoint; 1385 head->next_physical_endpoint = (uint32)endpoint->physical_address; 1386 Unlock(); 1387 1388 return B_OK; 1389 } 1390 1391 1392 ohci_endpoint_descriptor* 1393 OHCI::_FindInterruptEndpoint(uint8 interval) 1394 { 1395 return NULL; 1396 } 1397 1398 1399 status_t 1400 OHCI::_RemoveEndpointForPipe(Pipe *pipe) 1401 { 1402 return B_ERROR; 1403 } 1404 1405 1406 inline void 1407 OHCI::_WriteReg(uint32 reg, uint32 value) 1408 { 1409 *(volatile uint32 *)(fOperationalRegisters + reg) = value; 1410 } 1411 1412 1413 inline uint32 1414 OHCI::_ReadReg(uint32 reg) 1415 { 1416 return *(volatile uint32 *)(fOperationalRegisters + reg); 1417 } 1418 1419 1420 status_t 1421 OHCI::CancelQueuedTransfers(Pipe *pipe, bool force) 1422 { 1423 if (pipe->Type() & USB_OBJECT_ISO_PIPE) 1424 return _CancelQueuedIsochronousTransfers(pipe, force); 1425 1426 if (!Lock()) 1427 return B_ERROR; 1428 1429 transfer_data *current = fFirstTransfer; 1430 while (current) { 1431 if (current->transfer->TransferPipe() == pipe) { 1432 // Check if the skip bit is already set 1433 if (!(current->endpoint->flags & OHCI_ENDPOINT_SKIP)) { 1434 current->endpoint->flags |= OHCI_ENDPOINT_SKIP; 1435 // In case the controller is processing 1436 // this endpoint, wait for it to finish 1437 snooze(1000); 1438 } 1439 // Clear the endpoint 1440 current->endpoint->head_physical_descriptor = NULL; 1441 current->endpoint->tail_physical_descriptor = NULL; 1442 current->endpoint->head_logical_descriptor = NULL; 1443 current->endpoint->tail_logical_descriptor = NULL; 1444 1445 if (!force) { 1446 // If the transfer is canceled by force, the one causing the 1447 // cancel is probably not the one who initiated the transfer 1448 // and the callback is likely not safe anymore 1449 current->transfer->Finished(B_CANCELED, 0); 1450 } 1451 current->canceled = true; 1452 } 1453 current = current->link; 1454 } 1455 1456 Unlock(); 1457 1458 // notify the finisher so it can clean up the canceled transfers 1459 release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE); 1460 return B_OK; 1461 } 1462 1463 1464 status_t 1465 OHCI::_CancelQueuedIsochronousTransfers(Pipe *pipe, bool force) 1466 { 1467 // TODO 1468 return B_ERROR; 1469 } 1470