/* * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1998-2003 Apple Computer, Inc. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include #include #include #include "AppleUSBEHCI.h" #include "AppleEHCIedMemoryBlock.h" #include "AppleEHCItdMemoryBlock.h" #include "AppleEHCIitdMemoryBlock.h" #include "AppleEHCIsitdMemoryBlock.h" #include "AppleUSBEHCIHubInfo.h" #define super IOUSBControllerV2 #define self this #define NUM_BUFFER_PAGES 9 // 54 #define NUM_TDS 255 // 1500 #define NUM_EDS 256 // 1500 #define NUM_ITDS 192 // 1300 // TDs per page == 85 // EDs per page == 128 // ITDs per page == 64 OSDefineMetaClassAndStructors(AppleUSBEHCI, IOUSBControllerV2) bool AppleUSBEHCI::init(OSDictionary * propTable) { if (!super::init(propTable)) return false; _ehciBusState = kEHCIBusStateOff; _ehciAvailable = true; _hasPCIPwrMgmt = false; _intLock = IOLockAlloc(); if (!_intLock) return(false); _controllerSpeed = kUSBDeviceSpeedHigh; // This needs to be set before start. // super uses it during start method _wdhLock = IOSimpleLockAlloc(); if (!_wdhLock) return(false); _isochScheduleLock = IOSimpleLockAlloc(); if (!_isochScheduleLock) return(false); _uimInitialized = false; // Initialize our consumer and producer counts. // _producerCount = 1; _consumerCount = 1; return (true); } void AppleUSBEHCI::free() { // Free our locks // IOLockFree( _intLock ); IOSimpleLockFree( _wdhLock ); IOSimpleLockFree( _isochScheduleLock ); if (_processDoneQueueThread) { thread_call_cancel(_processDoneQueueThread); thread_call_free(_processDoneQueueThread); } super::free(); } void AppleUSBEHCI::showRegisters(char *s) { int i; USBLog(3,"EHCIUIM -- showRegisters %s version: 0x%x", s, USBToHostWord(_pEHCICapRegisters->HCIVersion)); USBLog(3,"USBCMD: %p", (void*)USBToHostLong(_pEHCIRegisters->USBCMD)); USBLog(3,"USBSTS: %p", (void*)USBToHostLong(_pEHCIRegisters->USBSTS)); USBLog(3,"USBIntr: %p", (void*)USBToHostLong(_pEHCIRegisters->USBIntr)); USBLog(3,"FRIndex: %p", (void*)USBToHostLong(_pEHCIRegisters->FRIndex)); USBLog(3,"CTRLDSSeg: %p", (void*)USBToHostLong(_pEHCIRegisters->CTRLDSSegment)); USBLog(3,"PerListBase: %p", (void*)USBToHostLong(_pEHCIRegisters->PeriodicListBase)); USBLog(3,"AsyncListAd: %p", (void*)USBToHostLong(_pEHCIRegisters->AsyncListAddr)); USBLog(3,"ConfFlg: %p", (void*)USBToHostLong(_pEHCIRegisters->ConfigFlag)); for(i=0;i<5;i++) { UInt32 x; x = USBToHostLong(_pEHCIRegisters->PortSC[i]); if(x != 0x1000) USBLog(3,"PortSC[%d]: 0x%lx", i+1, x); } } bool AppleUSBEHCI::start( IOService * provider ) { USBLog(7, "+%s[%p]::start", getName(), this); if( !super::start(provider)) return (false); // initialize power management initForPM(_device); // allocate a thread_call structure _processDoneQueueThread = thread_call_allocate((thread_call_func_t)ProcessDoneQueueEntry, (thread_call_param_t)this); if ( !_processDoneQueueThread ) { USBError(1, "%s[%p] could not allocate thread callout function. Aborting start", getName(), this); return false; } USBLog(7, "-%s[%p]::start", getName(), this); return true; } IOReturn AppleUSBEHCI::UIMInitialize(IOService * provider) { UInt32 CapLength, USBCmd, hccparams; IOReturn err = kIOReturnSuccess; UInt32 lvalue; int i; USBLog(7, "%s[%p]::UIMInitialize", getName(), this); _device = OSDynamicCast(IOPCIDevice, provider); if(_device == NULL) return kIOReturnBadArgument; do { if (!(_deviceBase = provider->mapDeviceMemoryWithIndex(0))) { USBError(1, "%s[%p]::UIMInitialize - unable to get device memory", getName(), this); err = kIOReturnNoResources; break; } USBLog(3, "%s: config @ %lx (%lx)\n", getName(), (long)_deviceBase->getVirtualAddress(), _deviceBase->getPhysicalAddress()); SetVendorInfo(); // Set up a filter interrupt source (this process both primary (thru filter function) and secondary (thru action function) // interrupts. // _filterInterruptSource = IOFilterInterruptEventSource::filterInterruptEventSource(this, AppleUSBEHCI::InterruptHandler, AppleUSBEHCI::PrimaryInterruptFilter, _device ); if ( !_filterInterruptSource ) { USBError(1,"%s[%p]: unable to get filterInterruptEventSource", getName(), this); err = kIOReturnNoResources; break; } err = _workLoop->addEventSource(_filterInterruptSource); if ( err != kIOReturnSuccess ) { USBError(1,"%s[%p]: unable to add filter event source: 0x%x", getName(), this, err); err = kIOReturnNoResources; break; } /* * Initialize my data and the hardware */ _errataBits = GetErrataBits(_vendorID, _deviceID, _revisionID); USBLog(7, "%s[%p]::UIMInitialize - errata bits=%p", getName(), this, (void*)_errataBits); _pageSize = PAGE_SIZE; _pEHCICapRegisters = (EHCICapRegistersPtr) _deviceBase->getVirtualAddress(); // enable the card registers lvalue = _device->configRead32(cwCommand); _device->configWrite32(cwCommand, (lvalue & 0xffff0000) | (cwCommandEnableMemorySpace)); err = AcquireOSOwnership(); if ( err != kIOReturnSuccess ) { USBError(1,"%s[%p]: unable to obtain ownership: 0x%x", getName(), this, err); break; } // determine whether this is a 32 bit or 64 bit machine hccparams = USBToHostLong(_pEHCICapRegisters->HCCParams); if (hccparams & kEHCI64Bit) _is64bit = true; else _is64bit = false; CapLength = _pEHCICapRegisters->CapLength; _pEHCIRegisters = (EHCIRegistersPtr) ( ((UInt32)_pEHCICapRegisters) + CapLength); // Enable the interrupt delivery. _workLoop->enableAllInterrupts(); _rootHubFuncAddress = 1; // reset the chip and make sure that all is well if (_is64bit) _pEHCIRegisters->CTRLDSSegment = 0; // Set upper address bits to 0 _pEHCIRegisters->USBCMD = 0; // this sets r/s to stop IOSync(); for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIHCHaltedBit); i++) IOSleep(1); if (i >= 100) { USBError(1, "%s[%p]::UIMInitialize - could not get chip to halt within 100 ms", getName(), this); err = kIOReturnInternalError; break; } _pEHCIRegisters->USBCMD = HostToUSBLong(kEHCICMDHCReset); // set the reset bit IOSync(); for (i=0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBCMD) & kEHCICMDHCReset); i++) IOSleep(1); if (i >= 100) { USBError(1, "%s[%p]::UIMInitialize - could not get chip to come out of reset within 100 ms", getName(), this); err = kIOReturnInternalError; break; } _pEHCIRegisters->PeriodicListBase = 0; // no periodic list as yet _pEHCIRegisters->AsyncListAddr = 0; // no async list as yet IOSync(); // enable card bus mastering lvalue = _device->configRead32(cwCommand); _device->configWrite32(cwCommand, (lvalue & 0xffff0000) | (cwCommandEnableBusMaster | cwCommandEnableMemorySpace)); // turn on transaction completion/error interrupts _pEHCIRegisters->USBIntr = HostToUSBLong(kEHCICompleteIntBit | kEHCIErrorIntBit | kEHCIHostErrorIntBit | kEHCIFrListRolloverIntBit); IOSync(); USBCmd = USBToHostLong(_pEHCIRegisters->USBCMD); // check to make sure we have the correct Frame List Size _frameListSize = (USBCmd & kEHCICMDFrameListSizeMask) >> kEHCICMDFrameListSizeOffset; if (_frameListSize) { // at this time we only support a 1K frame list USBError(1, "%s[%p]::UIMInitialize - bad _frameListSize", getName(), this); err = kIOReturnInternalError; break; } _frameListSize = 1024; USBCmd |= kEHCICMDRunStop; _ehciBusState = kEHCIBusStateRunning; // this command will change the park mode from 3 to 2 //USBCmd &= ~kEHCICMDAsyncParkModeCountMask; // USBCmd |= (2 << kEHCICMDAsyncParkModeCountMaskPhase); // this line will eliminate park mode completely // USBCmd &= ~kEHCICMDAsyncParkModeEnable; USBCmd |= 8 << kEHCICMDIntThresholdOffset; // Interrupt every 8 micro frames (1 frame) _pEHCIRegisters->USBCMD = USBToHostLong(USBCmd); // start your engines _pEHCIRegisters->ConfigFlag = HostToUSBLong(kEHCIPortRoutingBit); // Route ports to EHCI IOSync(); IOSleep(1); if (_errataBits & kErrataNECIncompleteWrite) { UInt32 newValue = 0, count = 0; newValue = USBToHostLong(_pEHCIRegisters->ConfigFlag); while ((count++ < 10) && (newValue != kEHCIPortRoutingBit)) { USBError(1, "EHCI driver: UIMInitialize - ConfigFlag bit not sticking. Retrying."); _pEHCIRegisters->ConfigFlag = HostToUSBLong(kEHCIPortRoutingBit); IOSync(); newValue = USBToHostLong(_pEHCIRegisters->ConfigFlag); } } // _pEHCIRegisters->PortSC // Let root hub play with this. // Should revisit the Isoc bandwidth issue sometime. _isochBandwidthAvail = 5 *1024; _outSlot = kEHCIPeriodicListEntries+1; /* No Isoc transactions currently. */ _frameNumber = 0; if ((err = InterruptInitialize())) continue; _uimInitialized = true; // showRegisters("UIMInitialize"); registerService(); // allows the UHCI driver to know we are here return kIOReturnSuccess; } while (false); USBError(1, "%s[%p]::UIMInitialize - Error occurred (0x%x)", getName(), this, err); UIMFinalize(); if (_filterInterruptSource) _filterInterruptSource->release(); return(err); } IOReturn AppleUSBEHCI::AcquireOSOwnership(void) { UInt32 hccparams = USBToHostLong(_pEHCICapRegisters->HCCParams & kEHCIEECPMask); UInt32 eecp; UInt32 data; USBLog(2, "Attempting to get EHCI Controller from BIOS"); eecp = (hccparams & kEHCIEECPMask) >> kEHCIEECPPhase; // if there is no eecp register, then we can assume we have ownership if (eecp < 0x40) return kIOReturnSuccess; data = _device->configRead32(eecp); if ((data & 0xFF) == kEHCI_USBLEGSUP_ID) { USBLog(2, "Found USBLEGSUP_ID - value %p - writing OSOwned", (void*)data); _device->configWrite32(eecp, data | kEHCI_USBLEGSUP_OSOwned); // wait for kEHCI_USBLEGSUP_BIOSOwned bit to clear for (int i = 0; i < 25; i++) { data = _device->configRead32(eecp); if ((data & kEHCI_USBLEGSUP_BIOSOwned) == 0) break; IOSleep(10); } if ((_device->configRead32(eecp) & kEHCI_USBLEGSUP_BIOSOwned) != 0) { USBError(1, "EHCI controller unable to take control from BIOS"); return kIOReturnNoResources; } else USBLog(2, "acquireOSOwnership done - value %p", (void*)_device->configRead32(eecp)); } else { // on the NEC controllers, the eecp contains a 0, so we assume we have ownership USBLog(2, "EHCI controller has wrong value in EECP register"); } return kIOReturnSuccess; } IOReturn AppleUSBEHCI::AsyncInitialize (void) { _AsyncHead = NULL; return kIOReturnSuccess; } IOReturn AppleUSBEHCI::InterruptInitialize (void) { int i; UInt32 termBit, *list; AppleEHCIListElement **logical; IOPhysicalAddress physPtr; _periodicList = (UInt32 *)IOMallocContiguous(kEHCIPeriodicFrameListsize, kEHCIPageSize, &physPtr); if(_periodicList == NULL) { return kIOReturnNoResources; } _pEHCIRegisters->PeriodicListBase = HostToUSBLong(physPtr); _logicalPeriodicList = (AppleEHCIListElement **)IOMalloc(kEHCIPeriodicFrameListsize); if(_logicalPeriodicList == NULL) { _periodicList = NULL; return kIOReturnNoResources; } // Set all the entries in the periodic list to invalid termBit = HostToUSBLong(kEHCITermFlag); list = (UInt32 *)_periodicList; logical = _logicalPeriodicList; for(i= 0; igetVirtualAddress(), _deviceBase->getPhysicalAddress()); // Disable the interrupt delivery // if ( _workLoop ) _workLoop->disableAllInterrupts(); // Wait for the interrupts to propagate // IOSleep(2); // Clean up our power down notifier. That will release it. // if ( _powerDownNotifier ) { _powerDownNotifier->remove(); _powerDownNotifier = NULL; } USBLog(1, "%s[%p]: UIMFinalize %x %p %p", getName(), this, isInactive(), _pEHCIRegisters, _device); // If we are NOT being terminated, then talk to the EHCI controller and // set up all the registers to be off // if ( !isInactive() && _pEHCIRegisters && _device ) { // Disable All EHCI Interrupts // _pEHCIRegisters->USBIntr = 0x0; IOSync(); // reset the chip and make sure that all is well if (_is64bit) _pEHCIRegisters->CTRLDSSegment = 0; // Set upper address bits to 0 _pEHCIRegisters->USBCMD = 0; // this sets r/s to stop IOSync(); for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIHCHaltedBit); i++) IOSleep(1); if (i >= 100) { USBError(1, "%s[%p]::UIMFinalize - could not get chip to halt within 100 ms", getName(), this); err = kIOReturnInternalError; goto ErrorExit; } _pEHCIRegisters->USBCMD = HostToUSBLong(kEHCICMDHCReset); // set the reset bit IOSync(); for (i=0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBCMD) & kEHCICMDHCReset); i++) IOSleep(1); if (i >= 100) { USBError(1, "%s[%p]::UIMFinalize - could not get chip to come out of reset within 100 ms", getName(), this); err = kIOReturnInternalError; goto ErrorExit; } // Route ports back to companion controller _pEHCIRegisters->ConfigFlag = 0; IOSync(); if (_errataBits & kErrataNECIncompleteWrite) { UInt32 newValue = 0, count = 0; newValue = USBToHostLong(_pEHCIRegisters->ConfigFlag); while ((count++ < 10) && (newValue != 0)) { USBError(1, "EHCI driver: UIMFinalize - ConfigFlag bit not sticking. Retrying."); _pEHCIRegisters->ConfigFlag = 0; IOSync(); newValue = USBToHostLong(_pEHCIRegisters->ConfigFlag); } } // Take away the controllers ability be a bus master. // _device->configWrite32(cwCommand, cwCommandEnableMemorySpace); _pEHCIRegisters->PeriodicListBase = 0;// no periodic list as yet _pEHCIRegisters->AsyncListAddr = 0; // no async list as yet IOSync(); } // Free the memory allocated in the InterruptInitialize() // if ( _periodicList ) IOFree( _periodicList, kEHCIPeriodicFrameListsize ); if ( _logicalPeriodicList ) IOFree( _logicalPeriodicList, kEHCIPeriodicFrameListsize ); // Need to Free any Isoch Endpoints // // Remove the interruptEventSource we created // if ( _filterInterruptSource && _workLoop ) { _workLoop->removeEventSource(_filterInterruptSource); _filterInterruptSource->release(); _filterInterruptSource = NULL; } ErrorExit: _uimInitialized = false; return err; } UInt32 AppleUSBEHCI::GetBandwidthAvailable() { USBLog(7, "%s[%p]::GetBandwidthAvailable -- returning %d", getName(), this, (int)_isochBandwidthAvail); return _isochBandwidthAvail; } UInt32 AppleUSBEHCI::GetFrameNumber32() { UInt32 temp1, temp2; register UInt32 frindex; // First, get a snapshot but make sure that we haven't wrapped around and not processed the new value. Note that the // rollover bit is processed at primary interrupt time, so we don't need to take that into account in this calculation. // do { temp1 = (UInt32)_frameNumber; frindex = HostToUSBLong(_pEHCIRegisters->FRIndex); IOSync(); temp2 = (UInt32)_frameNumber; } while ((temp1 != temp2) || (frindex == 0) ); // Shift out the microframes // frindex = frindex >> 3; USBLog(7, "%s[%p]::GetFrameNumber32 -- returning %d (%p)", getName(), this, (int)(temp1+frindex), (void*)(temp1+frindex)); return (UInt32)(temp1 + frindex); } UInt64 AppleUSBEHCI::GetFrameNumber() { UInt64 temp1, temp2; register UInt32 frindex; // First, get a snapshot but make sure that we haven't wrapped around and not processed the new value. Note that the // rollover bit is processed at primary interrupt time, so we don't need to take that into account in this calculation. // do { temp1 = _frameNumber; frindex = HostToUSBLong(_pEHCIRegisters->FRIndex); // IOSync(); temp2 = _frameNumber; } while ( (temp1 != temp2) || (frindex == 0) ); // Shift out the microframes // frindex = frindex >> 3; // USBLog(7, "%s[%p]::GetFrameNumber -- returning %Ld (0x%Lx)", getName(), this, temp1+frindex, temp1+frindex); return (temp1 + frindex); } UInt64 AppleUSBEHCI::GetMicroFrameNumber() { UInt64 temp1, temp2; register UInt32 frindex; // First, get a snapshot but make sure that we haven't wrapped around and not processed the new value. Note that the // rollover bit is processed at primary interrupt time, so we don't need to take that into account in this calculation. // do { temp1 = _frameNumber; frindex = HostToUSBLong(_pEHCIRegisters->FRIndex); IOSync(); temp2 = _frameNumber; } while ( (temp1 != temp2) || (frindex == 0) ); // since this frindex has the lower 3 bits of the microframe, we need to adjust the upper 61 bits // by shifting them up temp1 = temp1 << 3; USBLog(7, "%s[%p]::GetMicroFrameNumber -- returning %Ld (0x%Lx)", getName(), this, temp1+frindex, temp1+frindex); return (temp1 + frindex); } void AppleUSBEHCI::SetVendorInfo(void) { OSData *vendProp, *deviceProp, *revisionProp; // get this chips vendID, deviceID, revisionID vendProp = OSDynamicCast(OSData, _device->getProperty( "vendor-id" )); if (vendProp) _vendorID = *((UInt32 *) vendProp->getBytesNoCopy()); deviceProp = OSDynamicCast(OSData, _device->getProperty( "device-id" )); if (deviceProp) _deviceID = *((UInt32 *) deviceProp->getBytesNoCopy()); revisionProp = OSDynamicCast(OSData, _device->getProperty( "revision-id" )); if (revisionProp) _revisionID = *((UInt32 *) revisionProp->getBytesNoCopy()); } AppleEHCIQueueHead * AppleUSBEHCI::AllocateQH(void) { AppleEHCIQueueHead *freeQH; // Pop a ED off the freeQH list // If freeQH == NULL return Error freeQH = _pFreeQH; if (freeQH == NULL) { // i need to allocate another page of EDs AppleEHCIedMemoryBlock *memBlock; UInt32 numEDs, i; memBlock = AppleEHCIedMemoryBlock::NewMemoryBlock(); if (!memBlock) { USBLog(1, "%s[%p]::AllocateED - unable to allocate a new memory block!", getName(), this); return NULL; } // link it in to my list of ED memory blocks memBlock->SetNextBlock(_edMBHead); _edMBHead = memBlock; numEDs = memBlock->NumEDs(); _pLastFreeQH = AppleEHCIQueueHead::WithSharedMemory(memBlock->GetLogicalPtr(0), memBlock->GetPhysicalPtr(0)); _pFreeQH = _pLastFreeQH; for (i=1; i < numEDs; i++) { freeQH = AppleEHCIQueueHead::WithSharedMemory(memBlock->GetLogicalPtr(i), memBlock->GetPhysicalPtr(i)); if (!freeQH) { USBLog(1, "%s[%p]::AllocateED - hmm. ran out of EDs in a memory block", getName(), this); freeQH = _pFreeQH; break; } freeQH->_logicalNext = _pFreeQH; _pFreeQH = freeQH; // in a normal loop termination, freeQH and _pFreeQH are the same, just like when we don't use this code } } if (freeQH) { _pFreeQH = OSDynamicCast(AppleEHCIQueueHead, freeQH->_logicalNext); // if we use the last one, then we need to zero out the end pointer as well if (!_pFreeQH) _pLastFreeQH = NULL; freeQH->_logicalNext = NULL; } return freeQH; } IOReturn AppleUSBEHCI::DeallocateTD (EHCIGeneralTransferDescriptorPtr pTD) { UInt32 physical; //zero out all unnecessary fields physical = pTD->pPhysical; // bzero(pTD, sizeof(*pTD)); pTD->pLogicalNext = NULL; pTD->pPhysical = physical; if (_pLastFreeTD) { _pLastFreeTD->pLogicalNext = pTD; _pLastFreeTD = pTD; } else { // list is currently empty _pLastFreeTD = pTD; _pFreeTD = pTD; } return kIOReturnSuccess; } IOReturn AppleUSBEHCI::DeallocateED (AppleEHCIQueueHead *pED) { USBLog(7, "%s[%p]::DeallocateED - deallocating %p", getName(), this, pED); pED->_logicalNext = NULL; if (_pLastFreeQH) { _pLastFreeQH->_logicalNext = pED; _pLastFreeQH = pED; } else { // list is currently empty _pLastFreeQH = pED; _pFreeQH = pED; } return (kIOReturnSuccess); } EHCIGeneralTransferDescriptorPtr AppleUSBEHCI::AllocateTD(void) { EHCIGeneralTransferDescriptorPtr freeTD; // Pop a ED off the FreeED list // If FreeED == NULL return Error freeTD = _pFreeTD; if (freeTD == NULL) { // i need to allocate another page of EDs AppleEHCItdMemoryBlock *memBlock; UInt32 numTDs, i; memBlock = AppleEHCItdMemoryBlock::NewMemoryBlock(); if (!memBlock) { USBError(1, "%s[%p]::AllocateTD - unable to allocate a new memory block!", getName(), this); return NULL; } // link it in to my list of ED memory blocks memBlock->SetNextBlock(_tdMBHead); _tdMBHead = memBlock; numTDs = memBlock->NumTDs(); _pLastFreeTD = memBlock->GetTD(0); // the first will be last.. for (i=0; i < numTDs; i++) { freeTD = memBlock->GetTD(i); if (!freeTD) { USBError(1, "%s[%p]::AllocateTD - hmm. ran out of TDs in a memory block", getName(), this); freeTD = _pFreeTD; break; } freeTD->pLogicalNext = _pFreeTD; _pFreeTD = freeTD; // in a normal loop termination, freeED and _pFreeED are the same, just like when we don't use this code } } if (freeTD) { _pFreeTD = freeTD->pLogicalNext; // if we use the last one, then we need to zero out the end pointer as well if (!_pFreeTD) _pLastFreeTD = NULL; freeTD->pLogicalNext = NULL; freeTD->lastFrame = 0; freeTD->lastRemaining = 0; freeTD->command = NULL; } return freeTD; } AppleEHCIIsochTransferDescriptor * AppleUSBEHCI::AllocateITD(void) { AppleEHCIIsochTransferDescriptor *freeITD; // Pop a ED off the FreeED list // If FreeED == NULL return Error freeITD = _pFreeITD; if (freeITD == NULL) { // i need to allocate another page of EDs AppleEHCIitdMemoryBlock *memBlock; UInt32 numTDs, i; memBlock = AppleEHCIitdMemoryBlock::NewMemoryBlock(); if (!memBlock) { USBError(1, "%s[%p]::AllocateITD - unable to allocate a new memory block!", getName(), this); return NULL; } // link it in to my list of ED memory blocks memBlock->SetNextBlock(_itdMBHead); _itdMBHead = memBlock; numTDs = memBlock->NumTDs(); _pLastFreeITD = AppleEHCIIsochTransferDescriptor::WithSharedMemory(memBlock->GetLogicalPtr(0), memBlock->GetPhysicalPtr(0)); _pFreeITD = _pLastFreeITD; for (i=1; i < numTDs; i++) { freeITD = AppleEHCIIsochTransferDescriptor::WithSharedMemory(memBlock->GetLogicalPtr(i), memBlock->GetPhysicalPtr(i)); if (!freeITD) { USBError(1, "%s[%p]::AllocateTD - hmm. ran out of TDs in a memory block", getName(), this); freeITD = _pFreeITD; break; } freeITD->_logicalNext = _pFreeITD; _pFreeITD = freeITD; // in a normal loop termination, freeED and _pFreeED are the same, just like when we don't use this code } } if (freeITD) { _pFreeITD = OSDynamicCast(AppleEHCIIsochTransferDescriptor, freeITD->_logicalNext); freeITD->_logicalNext = NULL; if (!_pFreeITD) _pLastFreeITD = NULL; } USBLog(7, "%s[%p]::AllocateITD - returning %p", getName(), this, freeITD); return freeITD; } IOReturn AppleUSBEHCI::DeallocateITD (AppleEHCIIsochTransferDescriptor *pTD) { USBLog(7, "%s[%p]::DeallocateITD - deallocating %p", getName(), this, pTD); pTD->_logicalNext = NULL; if (_pLastFreeITD) { _pLastFreeITD->_logicalNext = pTD; _pLastFreeITD = pTD; } else { // list is currently empty _pLastFreeITD = pTD; _pFreeITD = pTD; } return kIOReturnSuccess; } AppleEHCISplitIsochTransferDescriptor * AppleUSBEHCI::AllocateSITD(void) { AppleEHCISplitIsochTransferDescriptor *freeSITD; // Pop a ED off the FreeED list // If FreeED == NULL return Error freeSITD = _pFreeSITD; if (freeSITD == NULL) { // i need to allocate another page of EDs AppleEHCIsitdMemoryBlock *memBlock; UInt32 numTDs, i; memBlock = AppleEHCIsitdMemoryBlock::NewMemoryBlock(); if (!memBlock) { USBError(1, "%s[%p]::AllocateTD - unable to allocate a new memory block!", getName(), this); return NULL; } // link it in to my list of ED memory blocks memBlock->SetNextBlock(_sitdMBHead); _sitdMBHead = memBlock; numTDs = memBlock->NumTDs(); USBLog(3, "%s[%p]::AllocateSITD - got new memory block (%p) with %d SITDs in it", getName(), this, memBlock, (int)numTDs); _pLastFreeSITD = AppleEHCISplitIsochTransferDescriptor::WithSharedMemory(memBlock->GetLogicalPtr(0), memBlock->GetPhysicalPtr(0)); _pFreeSITD = _pLastFreeSITD; for (i=1; i < numTDs; i++) { freeSITD = AppleEHCISplitIsochTransferDescriptor::WithSharedMemory(memBlock->GetLogicalPtr(i), memBlock->GetPhysicalPtr(i)); if (!freeSITD) { USBError(1, "%s[%p]::AllocateTD - hmm. ran out of TDs in a memory block", getName(), this); freeSITD = _pFreeSITD; break; } freeSITD->_logicalNext = _pFreeSITD; _pFreeSITD = freeSITD; // in a normal loop termination, freeED and _pFreeED are the same, just like when we don't use this code } } if (freeSITD) { _pFreeSITD = OSDynamicCast(AppleEHCISplitIsochTransferDescriptor, freeSITD->_logicalNext); if (!_pFreeSITD) _pLastFreeSITD = NULL; freeSITD->_logicalNext = NULL; freeSITD->_isDummySITD = false; } USBLog(7, "%s[%p]::AllocateSITD - returning %p", getName(), this, freeSITD); return freeSITD; } IOReturn AppleUSBEHCI::DeallocateSITD (AppleEHCISplitIsochTransferDescriptor *pTD) { USBLog(7, "%s[%p]::DeallocateSITD - deallocating %p", getName(), this, pTD); pTD->_logicalNext = NULL; if (_pLastFreeSITD) { _pLastFreeSITD->_logicalNext = pTD; _pLastFreeSITD = pTD; } else { // list is currently empty _pLastFreeSITD = pTD; _pFreeSITD = pTD; } return kIOReturnSuccess; } AppleEHCIIsochEndpointPtr AppleUSBEHCI::AllocateIsochEP() { AppleEHCIIsochEndpointPtr pEP; pEP = _freeIsochEPList; if (!pEP) { pEP = (AppleEHCIIsochEndpointPtr)IOMalloc(sizeof(AppleEHCIIsochEndpointStruct)); if (pEP) pEP->nextEP = NULL; } if (pEP) { _freeIsochEPList = pEP->nextEP; } return pEP; } IOReturn AppleUSBEHCI::DeallocateIsochEP(AppleEHCIIsochEndpointPtr pEP) { pEP->nextEP = _freeIsochEPList; _freeIsochEPList = pEP; return kIOReturnSuccess; } /* * got an error on a TD with no completion routine. * Search for a later TD on the same end point which does have one, * so we can tell upper layes of the error. */ void AppleUSBEHCI::doCallback(EHCIGeneralTransferDescriptorPtr nextTD, UInt32 transferStatus, UInt32 bufferSizeRemaining) { USBError(1, "%s[%p]::doCallback unimemented *************", getName(), this); } //============================================================================================= // // UIMInitializeForPowerUp // // This routine is called for a controller that cannot survive sleep (mostly because it loses // power across sleep. It will re-intialize the EHCI registers and do everything needed to get // the card up. The one thing that it does not do is do any memory allocations, as those have // already been done and we don't need to do it again. This routine is essentially the same as // UIMInitialize w/out the memory allocations. // // To Do: Verify that we do need to call the ControlInintialize(), BulkInitialize(), etc. I'm // not sure that we do. // //============================================================================================= // IOReturn AppleUSBEHCI::UIMInitializeForPowerUp(void) { UInt32 CapLength, USBCmd; IOReturn err = kIOReturnSuccess; UInt32 lvalue; int i; USBLog(5, "%s[%p]:UIMInitializeForPowerUp - @ %p (%p)", getName(), this, (void*)_deviceBase->getVirtualAddress(), (void*)_deviceBase->getPhysicalAddress()); do { // enable the card registers lvalue = _device->configRead32(cwCommand); _device->configWrite32(cwCommand, (lvalue & 0xffff0000) | (cwCommandEnableMemorySpace)); CapLength = _pEHCICapRegisters->CapLength; _pEHCIRegisters = (EHCIRegistersPtr) ( ((UInt32)_pEHCICapRegisters) + CapLength); // Enable the interrupt delivery. _workLoop->enableAllInterrupts(); _rootHubFuncAddress = 1; // reset the chip and make sure that all is well // _pEHCIRegisters->USBCMD = 0; // this sets r/s to stop IOSync(); for ( i = 0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIHCHaltedBit); i++ ) IOSleep(1); if ( i >= 100 ) { USBError(1, "%s[%p]::UIMInitialize - could not get chip to halt within 100 ms", getName(), this); err = kIOReturnInternalError; break; } // set the reset bit // _pEHCIRegisters->USBCMD = HostToUSBLong(kEHCICMDHCReset); IOSync(); for ( i = 0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBCMD) & kEHCICMDHCReset); i++ ) IOSleep(1); if ( i >= 100 ) { USBError(1, "%s[%p]::UIMInitializeForPowerUp - could not get chip to come out of reset within 100 ms", getName(), this); err = kIOReturnInternalError; break; } // restore saved periodic list // if (_pEHCIRegisters->PeriodicListBase != _savedPeriodicListBase) { USBLog(1, "%s[%p]::UIMInitializeForPowerUp - restoring PeriodicListBase[from %p to %p]", getName(), this, _pEHCIRegisters->PeriodicListBase, _savedPeriodicListBase); _pEHCIRegisters->PeriodicListBase = _savedPeriodicListBase; IOSync(); } if (_pEHCIRegisters->AsyncListAddr != _savedAsyncListAddr) { USBLog(1, "%s[%p]::UIMInitializeForPowerUp - restoring AsyncListAddr[from %p to %p]", getName(), this, _pEHCIRegisters->AsyncListAddr, _savedAsyncListAddr); _pEHCIRegisters->AsyncListAddr = _savedAsyncListAddr; IOSync(); } // enable card bus mastering lvalue = _device->configRead32(cwCommand); _device->configWrite32(cwCommand, (lvalue & 0xffff0000) | (cwCommandEnableBusMaster | cwCommandEnableMemorySpace)); // turn on transaction completion/error interrupts // _pEHCIRegisters->USBIntr = HostToUSBLong(kEHCICompleteIntBit | kEHCIErrorIntBit | kEHCIHostErrorIntBit | kEHCIFrListRolloverIntBit); IOSync(); USBCmd = USBToHostLong(_pEHCIRegisters->USBCMD); // check to make sure we have the correct Frame List Size // _frameListSize = (USBCmd & kEHCICMDFrameListSizeMask) >> kEHCICMDFrameListSizeOffset; if (_frameListSize) { // at this time we only support a 1K frame list // USBError(1, "%s[%p]::UIMInitialize - bad _frameListSize", getName(), this); err = kIOReturnInternalError; break; } _frameListSize = 1024; USBCmd |= kEHCICMDRunStop; _ehciBusState = kEHCIBusStateRunning; //USBCmd &= ~kEHCICMDAsyncParkModeCountMask; //USBCmd |= (2 << kEHCICMDAsyncParkModeCountMaskPhase); // this line will eliminate park mode completely // USBCmd &= ~kEHCICMDAsyncParkModeEnable; USBCmd |= 8 << kEHCICMDIntThresholdOffset; // Interrupt every 8 micro frames (1 frame) _pEHCIRegisters->USBCMD = USBToHostLong(USBCmd); // start your engines _pEHCIRegisters->ConfigFlag = HostToUSBLong(kEHCIPortRoutingBit); // Route ports to EHCI IOSync(); if (_errataBits & kErrataNECIncompleteWrite) { UInt32 newValue = 0, count = 0; newValue = USBToHostLong(_pEHCIRegisters->ConfigFlag); while ((count++ < 10) && (newValue != kEHCIPortRoutingBit)) { USBError(1, "EHCI driver: UIMInitializeForPowerUp - ConfigFlag bit not sticking. Retrying."); _pEHCIRegisters->ConfigFlag = HostToUSBLong(kEHCIPortRoutingBit); IOSync(); newValue = USBToHostLong(_pEHCIRegisters->ConfigFlag); } } // _pEHCIRegisters->PortSC // Let root hub play with this. // Should revisit the Isoc bandwidth issue sometime. // _isochBandwidthAvail = 5 *1024; _outSlot = kEHCIPeriodicListEntries+1; /* No Isoc transactions currently. */ _frameNumber = 0; _uimInitialized = true; // showRegisters("After"); return kIOReturnSuccess; } while (false); USBError(1, "%s[%p]::UIMInitializeForPowerUp - Error occurred (0x%x)", getName(), this, err); UIMFinalize(); if (_filterInterruptSource) _filterInterruptSource->release(); return err; } //============================================================================================= // // UIMFinalizeForPowerDown // // This routine is called for a controller that cannot survive sleep (mostly because the power // is turned off across sleep. It will disable the OHCI controller and turn off its power. // It will NOT deallocate any memory. This routine is very similar to UIMFinalize(), except that // it does not deallocate memory. // // To do: Make sure that all transactions have been completed or aborted. This should happen // as a result of the terminate issued to the root hub device, but we need to make sure. // //============================================================================================= // IOReturn AppleUSBEHCI::UIMFinalizeForPowerDown(void) { int i; IOReturn err; if ( _deviceBase ) USBLog (3, "%s[%p]: @ %lx (%lx)(turning off HW)",getName(), this, (long)_deviceBase->getVirtualAddress(), _deviceBase->getPhysicalAddress()); // showRegisters("Before"); // Disable the interrupt delivery // if ( _workLoop ) _workLoop->disableAllInterrupts(); // Wait for the interrupts to propagate // IOSleep(2); if ( _pEHCIRegisters && _device ) { // If we are NOT being terminated, then talk to the OHCI controller and // set up all the registers to be off // // Disable All EHCI Interrupts // _pEHCIRegisters->USBIntr = 0x0; IOSync(); _savedPeriodicListBase = _pEHCIRegisters->PeriodicListBase; _savedAsyncListAddr = _pEHCIRegisters->AsyncListAddr; // reset the chip and make sure that all is well _pEHCIRegisters->USBCMD = 0; // this sets r/s to stop for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIHCHaltedBit); i++) IOSleep(1); if (i >= 100) { USBError(1, "%s[%p]::UIMInitializeForPowerUp - could not get chip to halt within 100 ms", getName(), this); err = kIOReturnInternalError; goto ErrorExit; } _pEHCIRegisters->USBCMD = HostToUSBLong(kEHCICMDHCReset); // set the reset bit for (i=0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBCMD) & kEHCICMDHCReset); i++) IOSleep(1); if (i >= 100) { USBError(1, "%s[%p]::UIMInitializeForPowerUp - could not get chip to come out of reset within 100 ms", getName(), this); err = kIOReturnInternalError; goto ErrorExit; } // Route ports back to companion controller _pEHCIRegisters->ConfigFlag = 0; IOSync(); IOSleep(1); if (_errataBits & kErrataNECIncompleteWrite) { UInt32 newValue = 0, count = 0; newValue = USBToHostLong(_pEHCIRegisters->ConfigFlag); while ((count++ < 10) && (newValue != 0)) { USBError(1, "EHCI driver: UIMFinalizeForPowerDown - ConfigFlag bit not sticking. Retrying."); _pEHCIRegisters->ConfigFlag = 0; IOSync(); newValue = USBToHostLong(_pEHCIRegisters->ConfigFlag); } } // Take away the controllers ability be a bus master. // _device->configWrite32(cwCommand, cwCommandEnableMemorySpace); _pEHCIRegisters->PeriodicListBase = 0; // no periodic list as yet _pEHCIRegisters->AsyncListAddr = 0; // no async list as yet IOSync(); } ErrorExit: _uimInitialized = false; return kIOReturnSuccess; } IOReturn AppleUSBEHCI::EnableAsyncSchedule(void) { int i; IOReturn stat = kIOReturnSuccess; if (!(_pEHCIRegisters->USBCMD & HostToUSBLong(kEHCICMDAsyncEnable))) { // first make certain that it really is disabled for (i=0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSAsyncScheduleStatus); i++) IOSleep(1); if (i) { if (i >= 100) { USBLog(1, "%s[%p]::EnableAsyncSchedule: ERROR: USBCMD and USBSTS won't synchronize OFF", getName(), this); stat = kIOReturnInternalError; } else { USBLog(7, "%s[%p]::EnableAsyncSchedule: had to wait %d ms for CMD and STS to synch up OFF", getName(), this, i); } } if (!stat) { if (_errataBits & kErrataAgereEHCIAsyncSched) { _pEHCIRegisters->USBCMD &= HostToUSBLong(~kEHCICMDRunStop); while (!(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIHCHaltedBit)) ; _pEHCIRegisters->USBCMD |= HostToUSBLong(kEHCICMDAsyncEnable | kEHCICMDRunStop); } else { _pEHCIRegisters->USBCMD |= HostToUSBLong(kEHCICMDAsyncEnable); } for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSAsyncScheduleStatus); i++) IOSleep(1); if (i) { if (i >= 100) { USBError(1, "%s[%p]::EnableAsyncSchedule: ERROR: USBCMD and USBSTS won't synchronize ON - cannot enable USB list processing", getName(), this); stat = kIOReturnInternalError; } else { USBLog(7, "%s[%p]::EnableAsyncSchedule: had to wait %d ms for CMD and STS to synch up ON", getName(), this, i); } } } } else { USBLog(7, "%s[%p]::EnableAsyncSchedule: schedule was already enabled", getName(), this); } if (stat) { USBLog(1, "%s[%p]::EnableAsyncSchedule: returning status %x", getName(), this, stat); } else { USBLog(7, "%s[%p]::EnableAsyncSchedule: schedule enabled cleanly", getName(), this); } return stat; } IOReturn AppleUSBEHCI::DisableAsyncSchedule(void) { int i; IOReturn stat = kIOReturnSuccess; if (_pEHCIRegisters->USBCMD & HostToUSBLong(kEHCICMDAsyncEnable)) { // first make certain that it really is enabled for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSAsyncScheduleStatus); i++) IOSleep(1); if (i) { if (i >= 100) { USBLog(1, "%s[%p]::DisableAsyncSchedule: ERROR: USBCMD and USBSTS won't synchronize ON", getName(), this); stat = kIOReturnInternalError; } else { USBLog(7, "%s[%p]::DisableAsyncSchedule: had to wait %d ms for CMD and STS to synch up ON", getName(), this, i); } } if (!stat) { _pEHCIRegisters->USBCMD &= HostToUSBLong(~kEHCICMDAsyncEnable); for (i=0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSAsyncScheduleStatus); i++) IOSleep(1); if (i) { if (i >= 100) { USBLog(1, "%s[%p]::DisableAsyncSchedule: ERROR: USBCMD and USBSTS won't synchronize OFF", getName(), this); stat = kIOReturnInternalError; } else { USBLog(7, "%s[%p]::DisableAsyncSchedule: had to wait %d ms for CMD and STS to synch up OFF", getName(), this, i); } } } } else { USBLog(7, "%s[%p]::DisableAsyncSchedule: schedule was already disabled", getName(), this); } if (stat) { USBLog(1, "%s[%p]::DisableAsyncSchedule: returning status %x", getName(), this, stat); } else { USBLog(7, "%s[%p]::DisableAsyncSchedule: schedule disabled cleanly", getName(), this); } return stat; } IOReturn AppleUSBEHCI::EnablePeriodicSchedule(void) { int i; IOReturn stat = kIOReturnSuccess; if (_inAbortIsochEP) { USBLog(2, "EnablePeriodicSchedule - not doing in AbortIsochEP"); return stat; } if (!(_pEHCIRegisters->USBCMD & HostToUSBLong(kEHCICMDPeriodicEnable))) { // first make certain that it really is disabled for (i=0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSPeriodicScheduleStatus); i++) IOSleep(1); if (i) { if (i >= 100) { USBLog(1, "%s[%p]::EnablePeriodicSchedule: ERROR: USBCMD and USBSTS won't synchronize OFF", getName(), this); stat = kIOReturnInternalError; } else { USBLog(7, "%s[%p]::EnablePeriodicSchedule: had to wait %d ms for CMD and STS to synch up OFF", getName(), this, i); } } if (!stat) { _pEHCIRegisters->USBCMD |= HostToUSBLong(kEHCICMDPeriodicEnable); for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSPeriodicScheduleStatus); i++) IOSleep(1); if (i) { if (i >= 100) { USBLog(1, "%s[%p]::EnablePeriodicSchedule: ERROR: USBCMD and USBSTS won't synchronize ON", getName(), this); stat = kIOReturnInternalError; } else { USBLog(7, "%s[%p]::EnablePeriodicSchedule: had to wait %d ms for CMD and STS to synch up ON", getName(), this, i); } } } } else { USBLog(7, "%s[%p]::EnablePeriodicSchedule: schedule was already enabled", getName(), this); } if (stat) { USBLog(1, "%s[%p]::EnablePeriodicSchedule: returning status %x", getName(), this, stat); } else { USBLog(7, "%s[%p]::EnablePeriodicSchedule: schedule enabled cleanly", getName(), this); } return stat; } IOReturn AppleUSBEHCI::DisablePeriodicSchedule(void) { int i; IOReturn stat = kIOReturnSuccess; if (_pEHCIRegisters->USBCMD & HostToUSBLong(kEHCICMDPeriodicEnable)) { // first make certain that it really is enabled for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSPeriodicScheduleStatus); i++) IOSleep(1); if (i) { if (i >= 100) { USBLog(1, "%s[%p]::DisablePeriodicSchedule: ERROR: USBCMD and USBSTS won't synchronize ON", getName(), this); stat = kIOReturnInternalError; } else { USBLog(7, "%s[%p]::DisablePeriodicSchedule: had to wait %d ms for CMD and STS to synch up ON", getName(), this, i); } } if (!stat) { _pEHCIRegisters->USBCMD &= HostToUSBLong(~kEHCICMDPeriodicEnable); for (i=0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSPeriodicScheduleStatus); i++) IOSleep(1); if (i) { if (i >= 100) { USBLog(1, "%s[%p]::DisablePeriodicSchedule: ERROR: USBCMD and USBSTS won't synchronize OFF", getName(), this); stat = kIOReturnInternalError; } else { USBLog(7, "%s[%p]::DisablePeriodicSchedule: had to wait %d ms for CMD and STS to synch up OFF", getName(), this, i); } } } } else { USBLog(7, "%s[%p]::DisablePeriodicSchedule: schedule was already disabled", getName(), this); } if (stat) { USBLog(1, "%s[%p]::DisablePeriodicSchedule: returning status %x", getName(), this, stat); } else { USBLog(7, "%s[%p]::DisablePeriodicSchedule: schedule disabled cleanly", getName(), this); } return stat; } AppleEHCIIsochEndpointPtr AppleUSBEHCI::FindIsochronousEndpoint( short functionAddress, short endpointNumber, short direction, AppleEHCIIsochEndpointPtr *ppEPBack) { AppleEHCIIsochEndpointPtr pEP, pBack; pEP = _isochEPList; pBack = NULL; while (pEP) { if ((pEP->functionAddress == functionAddress) && (pEP->endpointNumber == endpointNumber) && (pEP->direction == direction)) break; pBack = pEP; pEP = pEP->nextEP; } if (pEP && ppEPBack) *ppEPBack = pBack; return pEP; } AppleEHCIIsochEndpointPtr AppleUSBEHCI::CreateIsochronousEndpoint(short functionAddress, short endpointNumber, short direction, USBDeviceAddress highSpeedHub, int highSpeedPort) { AppleEHCIIsochEndpointPtr pEP; int i; pEP = AllocateIsochEP(); if (pEP) { pEP->toDoList = NULL; pEP->toDoEnd = NULL; pEP->doneQueue = NULL; pEP->doneEnd = NULL; pEP->deferredQueue = NULL; pEP->deferredEnd = NULL; pEP->firstAvailableFrame = 0; pEP->accumulatedStatus = kIOReturnSuccess; pEP->inSlot = 0; pEP->activeTDs = 0; pEP->onToDoList = 0; pEP->onDoneQueue = 0; pEP->scheduledTDs = 0; pEP->deferredTDs = 0; pEP->onProducerQ = 0; pEP->onReversedList = 0; pEP->functionAddress = functionAddress; pEP->endpointNumber = endpointNumber; pEP->direction = direction; pEP->highSpeedHub = highSpeedHub; pEP->highSpeedPort = highSpeedPort; pEP->hiPtr = NULL; for (i=0;i<8;i++) pEP->bandwidthUsed[i]=0; pEP->useBackPtr = false; pEP->aborting = false; pEP->nextEP = _isochEPList; _isochEPList = pEP; } return pEP; } IOReturn AppleUSBEHCI::message( UInt32 type, IOService * provider, void * argument ) { cs_event_t pccardevent; // Let our superclass decide handle this method // messages // if ( type == kIOPCCardCSEventMessage) { pccardevent = (UInt32) argument; if ( pccardevent == CS_EVENT_CARD_REMOVAL ) { // Should return all transactions in any endpoints // USBLog(5,"%s[%p]: Received kIOPCCardCSEventMessage Need to return all transactions",getName(),this); _pcCardEjected = true; } } USBLog(6, "%s[%p]::message type: %p, isInactive = %d", getName(), this, (void*)type, isInactive()); return super::message( type, provider, argument ); }