1 //------------------------------------------------------------------------------ 2 // Copyright (c) 2005, Jan-Rixt Van Hoye 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a 5 // copy of this software and associated documentation files (the "Software"), 6 // to deal in the Software without restriction, including without limitation 7 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 // and/or sell copies of the Software, and to permit persons to whom the 9 // Software is furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 // DEALINGS IN THE SOFTWARE. 21 // 22 // explanation of this file: 23 // ------------------------- 24 // 25 // This is the implementation of the OHCI module for the Haiku USB stack 26 // It is bases on the hcir1_0a documentation that can be found on www.usb.org 27 // Some parts are derive from source-files from openbsd, netbsd and linux. 28 // 29 // ------------------------------------------------------------------------ 30 31 // --------------------------- 32 // OHCI:: Includes 33 // --------------------------- 34 #include <module.h> 35 #include <PCI.h> 36 #include <USB3.h> 37 #include <KernelExport.h> 38 #include <stdlib.h> 39 40 // --------------------------- 41 // OHCI:: Local includes 42 // --------------------------- 43 44 #include "ohci.h" 45 #include "ohci_hardware.h" 46 #include "usb_p.h" 47 48 //------------------------------------------------------ 49 // OHCI:: Reverse the bits in a value between 0 and 31 50 // (Section 3.3.2) 51 //------------------------------------------------------ 52 53 static uint8 revbits[OHCI_NO_INTRS] = 54 { 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c, 55 0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e, 56 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d, 57 0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f }; 58 59 //------------------------------------------------------------------------ 60 // OHCI:: These are the OHCI operations that can be done. 61 // 62 // parameters: 63 // - op: operation 64 //------------------------------------------------------------------------ 65 66 static int32 67 ohci_std_ops( int32 op , ... ) 68 { 69 switch (op) 70 { 71 case B_MODULE_INIT: 72 TRACE(("ohci_module: init the module\n")); 73 return B_OK; 74 case B_MODULE_UNINIT: 75 TRACE(("ohci_module: uninit the module\n")); 76 break; 77 default: 78 return EINVAL; 79 } 80 return B_OK; 81 } 82 83 //------------------------------------------------------------------------ 84 // OHCI:: Give an reference of a stack instance to the OHCI module 85 // 86 // parameters: 87 // - &stack: reference to a stack instance form stack.cpp 88 //------------------------------------------------------------------------ 89 90 static status_t 91 ohci_add_to(Stack *stack) 92 { 93 status_t status; 94 pci_info *item; 95 bool found = false; 96 int i; 97 98 #ifdef TRACE_USB 99 set_dprintf_enabled(true); 100 load_driver_symbols("ohci"); 101 #endif 102 103 // 104 // Try if the PCI module is loaded 105 // 106 if( ( status = get_module( B_PCI_MODULE_NAME, (module_info **)&( OHCI::pci_module ) ) ) != B_OK) { 107 TRACE(("USB_ OHCI: init_hardware(): Get PCI module failed! %lu \n", status)); 108 return status; 109 } 110 TRACE(("usb_ohci init_hardware(): Setting up hardware\n")); 111 item = new pci_info; 112 for ( i = 0 ; OHCI::pci_module->get_nth_pci_info( i , item ) == B_OK ; i++ ) { 113 if ( ( item->class_base == PCI_serial_bus ) && ( item->class_sub == PCI_usb ) 114 && ( item->class_api == PCI_usb_ohci ) ) 115 { 116 if ((item->u.h0.interrupt_line == 0) || (item->u.h0.interrupt_line == 0xFF)) { 117 TRACE(("USB OHCI: init_hardware(): found with invalid IRQ - check IRQ assignement\n")); 118 continue; 119 } 120 TRACE(("USB OHCI: init_hardware(): found at IRQ %u \n", item->u.h0.interrupt_line)); 121 OHCI *bus = new(std::nothrow) OHCI(item, stack); 122 123 if (!bus) { 124 delete item; 125 OHCI::pci_module = NULL; 126 put_module(B_PCI_MODULE_NAME); 127 return B_NO_MEMORY; 128 } 129 130 if (bus->InitCheck() != B_OK) { 131 TRACE(("usb_ohci: bus failed to initialize...\n")); 132 delete bus; 133 continue; 134 } 135 136 bus->Start(); 137 stack->AddBusManager( bus ); 138 found = true; 139 } 140 } 141 142 if (!found) { 143 TRACE(("USB OHCI: init hardware(): no devices found\n")); 144 free( item ); 145 put_module( B_PCI_MODULE_NAME ); 146 return ENODEV; 147 } 148 return B_OK; //Hardware found 149 } 150 151 //------------------------------------------------------------------------ 152 // OHCI:: Host controller information 153 // 154 // parameters: none 155 //------------------------------------------------------------------------ 156 157 host_controller_info ohci_module = { 158 { 159 "busses/usb/ohci", 160 0, // No flag like B_KEEP_LOADED : the usb module does that 161 ohci_std_ops 162 }, 163 NULL , 164 ohci_add_to 165 }; 166 167 //------------------------------------------------------------------------ 168 // OHCI:: Module information 169 // 170 // parameters: none 171 //------------------------------------------------------------------------ 172 173 module_info *modules[] = { 174 (module_info *) &ohci_module, 175 NULL 176 }; 177 178 //------------------------------------------------------------------------ 179 // OHCI:: Constructor/Initialisation 180 // 181 // parameters: 182 // - info: pointer to a pci information structure 183 // - stack: pointer to a stack instance 184 //------------------------------------------------------------------------ 185 186 OHCI::OHCI(pci_info *info, Stack *stack) 187 : BusManager(stack), 188 fRegisterArea(-1), 189 fHccaArea(-1), 190 fDummyControl(0), 191 fDummyBulk(0), 192 fDummyIsochronous(0), 193 fRootHub(0), 194 fRootHubAddress(0), 195 fNumPorts(0) 196 { 197 fPcii = info; 198 fStack = stack; 199 int i; 200 TRACE(("USB OHCI: constructing new BusManager\n")); 201 202 fInitOK = false; 203 204 for(i = 0; i < OHCI_NO_EDS; i++) //Clear the interrupt list 205 fInterruptEndpoints[i] = 0; 206 207 // enable busmaster and memory mapped access 208 uint16 cmd = OHCI::pci_module->read_pci_config(fPcii->bus, fPcii->device, fPcii->function, PCI_command, 2); 209 cmd &= ~PCI_command_io; 210 cmd |= PCI_command_master | PCI_command_memory; 211 OHCI::pci_module->write_pci_config(fPcii->bus, fPcii->device, fPcii->function, PCI_command, 2, cmd ); 212 213 // 214 // 5.1.1.2 map the registers 215 // 216 addr_t registeroffset = pci_module->read_pci_config(info->bus, 217 info->device, info->function, PCI_base_registers, 4); 218 registeroffset &= PCI_address_memory_32_mask; 219 TRACE(("OHCI: iospace offset: %lx\n" , registeroffset)); 220 fRegisterArea = map_physical_memory("OHCI base registers", (void *)registeroffset, 221 B_PAGE_SIZE, B_ANY_KERNEL_BLOCK_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | B_WRITE_AREA, (void **)&fRegisters); 222 if (fRegisterArea < B_OK) { 223 TRACE(("USB OHCI: error mapping the registers\n")); 224 return; 225 } 226 227 // Get the revision of the controller 228 uint32 rev = ReadReg(OHCI_REVISION) & 0xff; 229 230 // Check the revision of the controller. The revision should be 10xh 231 TRACE((" OHCI: Version %ld.%ld%s\n", OHCI_REV_HI(rev), OHCI_REV_LO(rev),OHCI_REV_LEGACY(rev) ? ", legacy support" : "")); 232 if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0) { 233 TRACE(("USB OHCI: Unsupported OHCI revision of the ohci device\n")); 234 return; 235 } 236 237 // Set up the Host Controller Communications Area 238 void *hcca_phy; 239 fHccaArea = fStack->AllocateArea((void**)&fHcca, &hcca_phy, 240 B_PAGE_SIZE, "OHCI HCCA"); 241 if (fHccaArea < B_OK) { 242 TRACE(("USB OHCI: Error allocating HCCA block\n")); 243 return; 244 } 245 memset((void*)fHcca, 0, sizeof(ohci_hcca)); 246 247 // 248 // 5.1.1.3 Take control of the host controller 249 // 250 if (ReadReg(OHCI_CONTROL) & OHCI_IR) { 251 TRACE(("USB OHCI: SMM is in control of the host controller\n")); 252 WriteReg(OHCI_COMMAND_STATUS, OHCI_OCR); 253 for (int i = 0; i < 100 && (ReadReg(OHCI_CONTROL) & OHCI_IR); i++) 254 snooze(1000); 255 if (ReadReg(OHCI_CONTROL) & OHCI_IR) 256 TRACE(("USB OHCI: SMM doesn't respond... continueing anyway...\n")); 257 } else if (!(ReadReg(OHCI_CONTROL) & OHCI_HCFS_RESET)) { 258 TRACE(("USB OHCI: BIOS is in control of the host controller\n")); 259 if (!(ReadReg(OHCI_CONTROL) & OHCI_HCFS_OPERATIONAL)) { 260 WriteReg(OHCI_CONTROL, OHCI_HCFS_RESUME); 261 snooze(USB_DELAY_BUS_RESET); 262 } 263 } else if (ReadReg(OHCI_CONTROL) & OHCI_HCFS_RESET) //Only if no BIOS/SMM control 264 snooze(USB_DELAY_BUS_RESET); 265 266 // 267 // 5.1.1.4 Set Up Host controller 268 // 269 // Dummy endpoints 270 fDummyControl = AllocateEndpoint(); 271 if (!fDummyControl) 272 return; 273 fDummyBulk = AllocateEndpoint(); 274 if (!fDummyBulk) 275 return; 276 fDummyIsochronous = AllocateEndpoint(); 277 if (!fDummyIsochronous) 278 return; 279 //Create the interrupt tree 280 //Algorhythm kindly borrowed from NetBSD code 281 for(i = 0; i < OHCI_NO_EDS; i++) { 282 fInterruptEndpoints[i] = AllocateEndpoint(); 283 if (!fInterruptEndpoints[i]) 284 return; 285 if (i != 0) 286 fInterruptEndpoints[i]->SetNext(fInterruptEndpoints[(i-1) / 2]); 287 else 288 fInterruptEndpoints[i]->SetNext(fDummyIsochronous); 289 } 290 for (i = 0; i < OHCI_NO_INTRS; i++) 291 fHcca->hcca_interrupt_table[revbits[i]] = 292 fInterruptEndpoints[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physicaladdress; 293 294 //Go to the hardware part of the initialisation 295 uint32 frameinterval = ReadReg(OHCI_FM_INTERVAL); 296 297 WriteReg(OHCI_COMMAND_STATUS, OHCI_HCR); 298 for (i = 0; i < 10; i++){ 299 snooze(10); //Should be okay in one run: 10 microseconds for reset 300 if (!(ReadReg(OHCI_COMMAND_STATUS) & OHCI_HCR)) 301 break; 302 } 303 if (ReadReg(OHCI_COMMAND_STATUS) & OHCI_HCR) { 304 TRACE(("USB OHCI: Error resetting the host controller\n")); 305 return; 306 } 307 308 WriteReg(OHCI_FM_INTERVAL, frameinterval); 309 //We now have 2 ms to finish the following sequence. 310 //TODO: maybe add spinlock protection??? 311 312 WriteReg(OHCI_CONTROL_HEAD_ED, (uint32)fDummyControl->physicaladdress); 313 WriteReg(OHCI_BULK_HEAD_ED, (uint32)fDummyBulk->physicaladdress); 314 WriteReg(OHCI_HCCA, (uint32)hcca_phy); 315 316 WriteReg(OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); 317 WriteReg(OHCI_INTERRUPT_ENABLE, OHCI_NORMAL_INTRS); 318 319 // 320 // 5.1.1.5 Begin Sending SOFs 321 // 322 uint32 control = ReadReg(OHCI_CONTROL); 323 control &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR); 324 control |= OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE | 325 OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL; 326 WriteReg(OHCI_CONTROL, control); 327 328 //The controller is now operational, end of 2ms block. 329 uint32 interval = OHCI_GET_IVAL(frameinterval); 330 WriteReg(OHCI_PERIODIC_START, OHCI_PERIODIC(interval)); 331 332 //Work on some Roothub settings 333 uint32 desca = ReadReg(OHCI_RH_DESCRIPTOR_A); 334 WriteReg(OHCI_RH_DESCRIPTOR_A, desca | OHCI_NOCP); //FreeBSD source does this to avoid a chip bug 335 //Enable power 336 WriteReg(OHCI_RH_STATUS, OHCI_LPSC); 337 snooze(5000); //Wait for power to stabilize (5ms) 338 WriteReg(OHCI_RH_DESCRIPTOR_A, desca); 339 snooze(5000); //Delay required by the AMD756 because else the # of ports might be misread 340 341 fInitOK = true; 342 } 343 344 OHCI::~OHCI() 345 { 346 if (fHccaArea > 0) 347 delete_area(fHccaArea); 348 if (fRegisterArea > 0) 349 delete_area(fRegisterArea); 350 if (fDummyControl) 351 FreeEndpoint(fDummyControl); 352 if (fDummyBulk) 353 FreeEndpoint(fDummyBulk); 354 if (fDummyIsochronous) 355 FreeEndpoint(fDummyIsochronous); 356 if (fRootHub) 357 delete fRootHub; 358 for (int i = 0; i < OHCI_NO_EDS; i++) 359 if (fInterruptEndpoints[i]) 360 FreeEndpoint(fInterruptEndpoints[i]); 361 } 362 363 status_t 364 OHCI::Start() 365 { 366 if (InitCheck()) 367 return B_ERROR; 368 369 if (!(ReadReg(OHCI_CONTROL) & OHCI_HCFS_OPERATIONAL)) { 370 TRACE(("USB OHCI::Start(): Controller not started. TODO: find out what happens.\n")); 371 return B_ERROR; 372 } 373 374 fRootHubAddress = AllocateAddress(); 375 fNumPorts = OHCI_GET_PORT_COUNT(ReadReg(OHCI_RH_DESCRIPTOR_A)); 376 377 fRootHub = new(std::nothrow) OHCIRootHub(this, fRootHubAddress); 378 if (!fRootHub) { 379 TRACE_ERROR(("USB OHCI::Start(): no memory to allocate root hub\n")); 380 return B_NO_MEMORY; 381 } 382 383 if (fRootHub->InitCheck() < B_OK) { 384 TRACE_ERROR(("USB OHCI::Start(): root hub failed init check\n")); 385 return B_ERROR; 386 } 387 388 SetRootHub(fRootHub); 389 TRACE(("USB OHCI::Start(): Succesful start\n")); 390 return B_OK; 391 } 392 393 status_t OHCI::SubmitTransfer( Transfer *t ) 394 { 395 TRACE(("usb OHCI::SubmitTransfer: called for device %d\n", t->TransferPipe()->DeviceAddress())); 396 397 if (t->TransferPipe()->DeviceAddress() == fRootHubAddress) 398 return fRootHub->ProcessTransfer(t, this); 399 400 return B_ERROR; 401 } 402 403 status_t 404 OHCI::NotifyPipeChange(Pipe *pipe, usb_change change) 405 { 406 if (InitCheck()) 407 return B_ERROR; 408 409 switch (change) { 410 case USB_CHANGE_CREATED: 411 return InsertEndpointForPipe(pipe); 412 case USB_CHANGE_DESTROYED: 413 // Do something 414 return B_ERROR; 415 case USB_CHANGE_PIPE_POLICY_CHANGED: 416 default: 417 break; 418 } 419 return B_ERROR; //We should never go here 420 } 421 422 status_t 423 OHCI::GetPortStatus(uint8 index, usb_port_status *status) 424 { 425 if (index > fNumPorts) 426 return B_BAD_INDEX; 427 428 status->status = status->change = 0; 429 uint32 portStatus = ReadReg(OHCI_RH_PORT_STATUS(index)); 430 431 TRACE(("OHCIRootHub::GetPortStatus: Port %i Value 0x%lx\n", OHCI_RH_PORT_STATUS(index), portStatus)); 432 433 // status 434 if (portStatus & OHCI_PORTSTATUS_CCS) 435 status->status |= PORT_STATUS_CONNECTION; 436 if (portStatus & OHCI_PORTSTATUS_PES) 437 status->status |= PORT_STATUS_ENABLE; 438 if (portStatus & OHCI_PORTSTATUS_PRS) 439 status->status |= PORT_STATUS_RESET; 440 if (portStatus & OHCI_PORTSTATUS_LSDA) 441 status->status |= PORT_STATUS_LOW_SPEED; 442 if (portStatus & OHCI_PORTSTATUS_PSS) 443 status->status |= PORT_STATUS_SUSPEND; 444 if (portStatus & OHCI_PORTSTATUS_POCI) 445 status->status |= PORT_STATUS_OVER_CURRENT; 446 if (portStatus & OHCI_PORTSTATUS_PPS) 447 status->status |= PORT_STATUS_POWER; 448 449 450 // change 451 if (portStatus & OHCI_PORTSTATUS_CSC) 452 status->change |= PORT_STATUS_CONNECTION; 453 if (portStatus & OHCI_PORTSTATUS_PESC) 454 status->change |= PORT_STATUS_ENABLE; 455 if (portStatus & OHCI_PORTSTATUS_PSSC) 456 status->change |= PORT_STATUS_SUSPEND; 457 if (portStatus & OHCI_PORTSTATUS_OCIC) 458 status->change |= PORT_STATUS_OVER_CURRENT; 459 if (portStatus & OHCI_PORTSTATUS_PRSC) 460 status->change |= PORT_STATUS_RESET; 461 462 return B_OK; 463 } 464 465 status_t 466 OHCI::SetPortFeature(uint8 index, uint16 feature) 467 { 468 if (index > fNumPorts) 469 return B_BAD_INDEX; 470 471 switch (feature) { 472 case PORT_RESET: 473 WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_PORTSTATUS_PRS); 474 return B_OK; 475 476 case PORT_POWER: 477 WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_PORTSTATUS_PPS); 478 return B_OK; 479 } 480 481 return B_BAD_VALUE; 482 } 483 484 status_t 485 OHCI::ClearPortFeature(uint8 index, uint16 feature) 486 { 487 if (index > fNumPorts) 488 return B_BAD_INDEX; 489 490 switch (feature) { 491 case C_PORT_RESET: 492 WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_PORTSTATUS_CSC); 493 return B_OK; 494 495 case C_PORT_CONNECTION: 496 WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_PORTSTATUS_CSC); 497 return B_OK; 498 } 499 500 return B_BAD_VALUE; 501 } 502 503 Endpoint * 504 OHCI::AllocateEndpoint() 505 { 506 //Allocate memory chunk 507 Endpoint *endpoint = new(std::nothrow) Endpoint; 508 void *phy; 509 if (fStack->AllocateChunk((void **)&endpoint->ed, &phy, sizeof(ohci_endpoint_descriptor)) != B_OK) { 510 TRACE(("OHCI::AllocateEndpoint(): Error Allocating Endpoint\n")); 511 return 0; 512 } 513 endpoint->physicaladdress = (addr_t)phy; 514 515 //Initialize the physical part 516 memset((void *)endpoint->ed, 0, sizeof(ohci_endpoint_descriptor)); 517 endpoint->ed->flags = OHCI_ENDPOINT_SKIP; 518 519 //Add a NULL list by creating one TransferDescriptor 520 TransferDescriptor *trans = new(std::nothrow) TransferDescriptor; 521 endpoint->head = endpoint->tail = trans; 522 endpoint->ed->headp = endpoint->ed->tailp = trans->physicaladdress; 523 524 return endpoint; 525 } 526 527 void 528 OHCI::FreeEndpoint(Endpoint *end) 529 { 530 fStack->FreeChunk((void *)end->ed, (void *) end->physicaladdress, sizeof(ohci_endpoint_descriptor)); 531 delete end; 532 } 533 534 TransferDescriptor * 535 OHCI::AllocateTransfer() 536 { 537 TransferDescriptor *transfer = new TransferDescriptor; 538 void *phy; 539 if (fStack->AllocateChunk((void **)&transfer->td, &phy, sizeof(ohci_transfer_descriptor)) != B_OK) { 540 TRACE(("OHCI::AllocateTransfer(): Error Allocating Transfer\n")); 541 return 0; 542 } 543 transfer->physicaladdress = (addr_t)phy; 544 memset((void *)transfer->td, 0, sizeof(ohci_transfer_descriptor)); 545 return transfer; 546 } 547 548 void 549 OHCI::FreeTransfer(TransferDescriptor *trans) 550 { 551 fStack->FreeChunk((void *)trans->td, (void *) trans->physicaladdress, sizeof(ohci_transfer_descriptor)); 552 delete trans; 553 } 554 555 status_t 556 OHCI::InsertEndpointForPipe(Pipe *p) 557 { 558 TRACE(("OHCI: Inserting Endpoint for device %u function %u\n", p->DeviceAddress(), p->EndpointAddress())); 559 560 if (InitCheck()) 561 return B_ERROR; 562 563 Endpoint *endpoint = AllocateEndpoint(); 564 if (!endpoint) 565 return B_NO_MEMORY; 566 567 //Set up properties of the endpoint 568 //TODO: does this need its own utility function? 569 { 570 uint32 properties = 0; 571 572 //Set the device address 573 properties |= OHCI_ENDPOINT_SET_FA(p->DeviceAddress()); 574 575 //Set the endpoint number 576 properties |= OHCI_ENDPOINT_SET_EN(p->EndpointAddress()); 577 578 //Set the direction 579 switch (p->Direction()) { 580 case Pipe::In: 581 properties |= OHCI_ENDPOINT_DIR_IN; 582 break; 583 case Pipe::Out: 584 properties |= OHCI_ENDPOINT_DIR_OUT; 585 break; 586 case Pipe::Default: 587 properties |= OHCI_ENDPOINT_DIR_TD; 588 break; 589 default: 590 //TODO: error 591 break; 592 } 593 594 //Set the speed 595 switch (p->Speed()) { 596 case USB_SPEED_LOWSPEED: 597 //the bit is 0 598 break; 599 case USB_SPEED_FULLSPEED: 600 properties |= OHCI_ENDPOINT_SPEED; 601 break; 602 case USB_SPEED_HIGHSPEED: 603 default: 604 //TODO: error 605 break; 606 } 607 608 //Assign the format. Isochronous endpoints require this switch 609 if (p->Type() & USB_OBJECT_ISO_PIPE) 610 properties |= OHCI_ENDPOINT_FORMAT_ISO; 611 612 //Set the maximum packet size 613 properties |= OHCI_ENDPOINT_SET_MAXP(p->MaxPacketSize()); 614 615 endpoint->ed->flags = properties; 616 } 617 618 //Check which list we need to add the endpoint in 619 Endpoint *listhead; 620 if (p->Type() & USB_OBJECT_CONTROL_PIPE) 621 listhead = fDummyControl; 622 else if (p->Type() & USB_OBJECT_BULK_PIPE) 623 listhead = fDummyBulk; 624 else if (p->Type() & USB_OBJECT_ISO_PIPE) 625 listhead = fDummyIsochronous; 626 else { 627 FreeEndpoint(endpoint); 628 return B_ERROR; 629 } 630 631 //Add the endpoint to the queues 632 if ((p->Type() & USB_OBJECT_ISO_PIPE) == 0) { 633 //Link the endpoint into the head of the list 634 endpoint->SetNext(listhead->next); 635 listhead->SetNext(endpoint); 636 } else { 637 //Link the endpoint into the tail of the list 638 Endpoint *tail = listhead; 639 while (tail->next != 0) 640 tail = tail->next; 641 tail->SetNext(endpoint); 642 } 643 644 return B_OK; 645 } 646 647 pci_module_info *OHCI::pci_module = 0; 648 649 void 650 OHCI::WriteReg(uint32 reg, uint32 value) 651 { 652 *(volatile uint32 *)(fRegisters + reg) = value; 653 } 654 655 uint32 656 OHCI::ReadReg(uint32 reg) 657 { 658 return *(volatile uint32 *)(fRegisters + reg); 659 } 660