AppleUSBXHCIUIM.cpp [plain text]
#include <IOKit/usb/IOUSBRootHubDevice.h>
#include <IOKit/usb/IOUSBHubPolicyMaker.h>
#include <IOKit/usb/IOUSBControllerV3.h>
#include <IOKit/IOTimerEventSource.h>
#include "AppleUSBXHCIUIM.h"
#include "AppleUSBXHCI_IsocQueues.h"
#ifndef XHCI_USE_KPRINTF
#define XHCI_USE_KPRINTF 0
#endif
#if XHCI_USE_KPRINTF
#undef USBLog
#undef USBError
void kprintf(const char *format, ...) __attribute__((format(printf, 1, 2)));
#define USBLog( LEVEL, FORMAT, ARGS... ) if ((LEVEL) <= XHCI_USE_KPRINTF) { kprintf( FORMAT "\n", ## ARGS ) ; }
#define USBLogKP( LEVEL, FORMAT, ARGS... ) if ((LEVEL) <= XHCI_USE_KPRINTF) { kprintf( FORMAT "\n", ## ARGS ) ; }
#define USBError( LEVEL, FORMAT, ARGS... ) { kprintf( FORMAT "\n", ## ARGS ) ; }
#else
#define USBLogKP( LEVEL, FORMAT, ARGS... )
#endif
#define super IOUSBControllerV3
#define _controllerCanSleep _expansionData->_controllerCanSleep
#define CMD_NOT_COMPLETED (-1)
#define kSegmentTableEventRingEntries 4
#define kXHCIHardwareEventRingBufferSize (PAGE_SIZE)
#define kXHCISoftwareEventRingBufferSize (20 * kXHCIHardwareEventRingBufferSize)
OSDefineMetaClassAndStructors(AppleUSBXHCI, IOUSBControllerV3)
#if DEBUG_COMPLETIONS
void AppleUSBXHCI::Complete(
IOUSBCompletion completion,
IOReturn status,
UInt32 actualByteCount )
{
if(actualByteCount == 0)
{
if(status != 0)
{
USBLog(2, "AppleUSBXHCI[%p]::Complete - status: %x", this, status);
}
}
else
{
USBLog(6, "AppleUSBXHCI[%p]::Complete - status: %x, shortfall: %d", this, status, (int)actualByteCount);
}
super::Complete(completion, status, actualByteCount);
}
#endif
#if DEBUG_BUFFER
void AppleUSBXHCI::CheckBuf(IOUSBCommand* command)
{
if(command->GetUIMScratch(kXHCI_ScratchMark))
{
IOMemoryMap *mmap;
UInt32 *mbuf;
int count, count0;
UInt32 pat;
mmap = (IOMemoryMap *)command->GetUIMScratch(kXHCI_ScratchMMap);
mbuf = (UInt32 *)mmap->getVirtualAddress();
pat = command->GetUIMScratch(kXHCI_ScratchPat);
count = command->GetReqCount();
count /= 4;
if(count == 0)
{
return;
}
count0 = count;
mbuf = &mbuf[count-1]; do{
if(*mbuf != pat)
{
break;
}
}while(--count >0);
if(count < count0)
{
USBLog(2, "AppleUSBXHCI[%p]::CheckBuf - potential shortfall: %d", this, (count0-count)*4);
}
else
{
USBLog(2, "AppleUSBXHCI[%p]::CheckBuf - buff fully used", this);
}
mmap->release();
}
}
#else
#define CheckBuf(c)
#endif
static void mset_pattern4(UInt32 *p, UInt32 pat, int bytecount)
{
bytecount /= 4;
while(bytecount-- >0)
{
*(p++) = pat;
}
}
static ErrataListEntry errataList[] = {
{0x1033, 0x0194, 0, 0xffff, kXHCIErrata_NEC}, {0x1b73, 0x1000, 0, 0xffff, kXHCIErrata_NoMSI}, {0x8086, 0x1e31, 0, 0xffff, kXHCIErrataPPT | kXHCIErrataPPTMux | kXHCIErrata_EnableAutoCompliance | kErrataSWAssistXHCIIdle | kXHCIErrata_ParkRing}, {0x1b21, 0, 0, 0xffff, kXHCIErrata_ASMedia}, {0x1b73, 0, 0, 0xffff, kXHCIErrata_FrescoLogic}, {0x1b73, 0x1100, 0, 16, kXHCIErrata_FL1100_Ax}, {0x1b6f, 0x7052, 1, 0xffff, kXHCIErrata_Etron7052}
};
#define errataListLength (sizeof(errataList)/sizeof(ErrataListEntry))
UInt32 AppleUSBXHCI::GetErrataBits(UInt16 vendorID, UInt16 deviceID, UInt16 revisionID)
{
ErrataListEntry *entryPtr;
UInt32 i, errata = 0;
OSBoolean * pciTunneled = kOSBooleanFalse;
for(i = 0, entryPtr = errataList; i < errataListLength; i++, entryPtr++)
{
if (vendorID == entryPtr->vendID &&
((deviceID == entryPtr->deviceID) || (entryPtr->deviceID == 0)) &&
revisionID >= entryPtr->revisionLo &&
revisionID <= entryPtr->revisionHi)
{
errata |= entryPtr->errata;
}
}
pciTunneled = (OSBoolean *) getProperty(kIOPCITunnelledKey, gIOServicePlane);
if ( pciTunneled == kOSBooleanTrue)
{
_v3ExpansionData->_onThunderbolt = true;
requireMaxBusStall(kXHCIIsochMaxBusStall);
}
return errata;
}
UInt8 AppleUSBXHCI::Read8Reg(volatile UInt8 *addr)
{
UInt8 value = 0xFF;
if (!_lostRegisterAccess)
{
value = *addr;
if ( (value == 0xFF) && (_v3ExpansionData->_onThunderbolt) )
{
_lostRegisterAccess = true;
USBLog(3, "AppleUSBXHCI[%p]::Read8Reg got invalid register base = %p reg addr = %p", this, _pXHCICapRegisters, addr);
}
}
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
USBTrace(kUSBTXHCI, kTPXHCIRead8Reg, (uintptr_t)this, (uintptr_t)addr, value, (uintptr_t)_pXHCICapRegisters);
#endif
return value;
}
UInt16 AppleUSBXHCI::Read16Reg(volatile UInt16 *addr)
{
UInt16 value = 0xFFFF;
if (!_lostRegisterAccess)
{
value = OSReadLittleInt16(addr, 0);
if ( (value == 0xFFFF) && (_v3ExpansionData->_onThunderbolt) )
{
_lostRegisterAccess = true;
USBLog(3, "AppleUSBXHCI[%p]::Read16Reg got invalid register base = %p reg addr = %p", this, _pXHCICapRegisters, addr);
}
}
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
USBTrace(kUSBTXHCI, kTPXHCIRead16Reg, (uintptr_t)this, (uintptr_t)addr, value, (uintptr_t)_pXHCICapRegisters);
#endif
return value;
}
UInt32 AppleUSBXHCI::Read32Reg(volatile UInt32 *addr)
{
UInt32 value = (UInt32) -1;
if (!_lostRegisterAccess)
{
value = OSReadLittleInt32(addr, 0);
if ( (value == (UInt32) -1) && (_v3ExpansionData->_onThunderbolt) )
{
_lostRegisterAccess = true;
USBLog(3, "AppleUSBXHCI[%p]::Read32Reg got invalid register base = %p reg addr =%p", this, _pXHCICapRegisters, addr);
}
}
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
USBTrace(kUSBTXHCI, kTPXHCIRead32Reg, (uintptr_t)this, (uintptr_t)addr, value, (uintptr_t)_pXHCICapRegisters);
#endif
return value;
}
UInt64 AppleUSBXHCI::Read64Reg(volatile UInt64 *addr)
{
UInt64 value = -1ULL;
do
{
if (_lostRegisterAccess)
{
break;
}
if(_AC64)
{
#if __LP64__
if ((_errataBits & kXHCIErrata_FrescoLogic) == 0)
{
value = *addr;
if ( (value == (UInt64)-1) && (_v3ExpansionData->_onThunderbolt) )
{
_lostRegisterAccess = true;
USBLog(3, "AppleUSBXHCI[%p]::Read64Reg got invalid register base = %p reg addr = %p", this, _pXHCICapRegisters, addr);
break;
}
}
else
{
UInt32 dwordLo = *(UInt32 *) addr;
if ( (dwordLo == (UInt32)-1) && (_v3ExpansionData->_onThunderbolt) )
{
_lostRegisterAccess = true;
USBLog(3, "AppleUSBXHCI[%p]::Read64Reg Got invalid register base = %p reg addr = %p", this, _pXHCICapRegisters, addr);
break;
}
UInt32 dwordHi = *((UInt32 *)addr + 1);
if ( (dwordHi == (UInt32)-1) && (_v3ExpansionData->_onThunderbolt) )
{
_lostRegisterAccess = true;
USBLog(3, "AppleUSBXHCI[%p]::Read64Reg got invalid register base = %p reg addr =%p", this, _pXHCICapRegisters, addr);
break;
}
value = (((UInt64) dwordHi) << 32) | dwordLo;
}
#else
UInt32 dwordLo = *(UInt32 *) addr;
if ( (dwordLo == (UInt32)-1) && (_v3ExpansionData->_onThunderbolt) )
{
_lostRegisterAccess = true;
USBLog(3, "AppleUSBXHCI[%p]::Read64Reg got invalid register base = %p reg addr = %p", this, _pXHCICapRegisters, addr);
break;
}
UInt32 dwordHi = *((UInt32 *)addr + 1);
if ( (dwordLo == (UInt32)-1) && (_v3ExpansionData->_onThunderbolt) )
{
_lostRegisterAccess = true;
USBLog(3, "AppleUSBXHCI[%p]::Read64Reg got invalid register base = %p reg addr = %p", this, _pXHCICapRegisters, addr);
break;
}
value = (((UInt64) dwordHi) << 32) | dwordLo;
#endif
}
else
{
UInt32 dword = *(UInt32 *)addr;
if ( (dword == (UInt32)-1) && (_v3ExpansionData->_onThunderbolt) )
{
_lostRegisterAccess = true;
USBLog(3, "AppleUSBXHCI[%p]::Read64Reg got invalid register base = %p reg addr =%p", this, _pXHCICapRegisters, addr);
break;
}
value = dword;
}
} while (0);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
USBTrace(kUSBTXHCI, kTPXHCIRead64Reg, (uintptr_t)this, (uintptr_t)addr, OSSwapLittleToHostInt64(value), (uintptr_t)_pXHCICapRegisters);
#endif
return OSSwapLittleToHostInt64(value);
}
void AppleUSBXHCI::Write32Reg(volatile UInt32 *addr, UInt32 value)
{
if(!_lostRegisterAccess)
{
OSWriteLittleInt32(addr, 0, value);
}
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
USBTrace(kUSBTXHCI, kTPXHCIWrite32Reg, (uintptr_t)this, (uintptr_t)addr, value, (uintptr_t)_pXHCICapRegisters);
#endif
}
void AppleUSBXHCI::Write64Reg(volatile UInt64 *addr, UInt64 value, bool quiet)
{
if (_lostRegisterAccess)
{
return;
}
if(_AC64)
{
#if __LP64__
if(!quiet)
{
USBLog(7, "AppleUSBXHCI[%p]::Write64Reg - writing 64bits %llx to offset %x", this, value, (int)((UInt8 *)addr - (UInt8 *)_pXHCICapRegisters));
}
if((_errataBits & kXHCIErrata_FrescoLogic) == 0)
{
OSWriteLittleInt64(addr, 0, value);
}
else
{
value = OSSwapHostToLittleInt64(value);
UInt32 *dwordLo = (UInt32 *) addr;
UInt32 *dwordHi = dwordLo + 1;
*dwordLo = (UInt32)(value & 0xFFFFFFFF);
*dwordHi = (UInt32)((value >> 32) & 0xFFFFFFFF);
}
#else
if(!quiet)
{
USBLog(7, "AppleUSBXHCI[%p]::Write64Reg - writing 2x32bits %llx to offset %x", this, value, (int)((UInt8 *)addr - (UInt8 *)_pXHCICapRegisters));
}
value = OSSwapHostToLittleInt64(value);
UInt32 *dwordLo = (UInt32 *) addr;
UInt32 *dwordHi = dwordLo + 1;
*dwordLo = (UInt32)(value & 0xFFFFFFFF);
*dwordHi = (UInt32)((value >> 32) & 0xFFFFFFFF);
#endif
}
else
{
if(!quiet)
{
USBLog(7, "AppleUSBXHCI[%p]::Write64Reg - writing 32bits %llx to offset %x", this, value, (int)((UInt8 *)addr - (UInt8 *)_pXHCICapRegisters));
}
OSWriteLittleInt32(addr, 0, (UInt32)value);
}
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
USBTrace(kUSBTXHCI, kTPXHCIWrite64Reg, (uintptr_t)this, (uintptr_t)addr, value, (uintptr_t)_pXHCICapRegisters);
#endif
}
#if (DEBUG_REGISTER_READS == 1)
#define Read32Reg(registerPtr, ...) Read32RegWithFileInfo(registerPtr, __FUNCTION__, __FILE__, __LINE__, ##__VA_ARGS__)
#define Read32RegWithFileInfo(registerPtr, function, file, line, ...) ( \
fTempReg = Read32Reg(registerPtr, ##__VA_ARGS__), \
fTempReg = (fTempReg == (typeof (*(registerPtr))) -1) ? \
(kprintf("AppleUSBXHCI[%p]::%s Invalid register at %s:%d %s\n", this,function,file, line,#registerPtr), -1) : fTempReg, \
(typeof(*(registerPtr)))fTempReg)
#define Read64Reg(registerPtr, ...) Read64RegWithFileInfo(registerPtr, __FUNCTION__, __FILE__, __LINE__, ##__VA_ARGS__)
#define Read64RegWithFileInfo(registerPtr, function, file, line, ...) ( \
fTempReg = Read64Reg(registerPtr, ##__VA_ARGS__), \
fTempReg = (fTempReg == (typeof (*(registerPtr))) -1) ? \
(kprintf("AppleUSBXHCI[%p]::%s Invalid register at %s:%d %s\n", this,function,file, line,#registerPtr), -1) : fTempReg, \
(typeof(*(registerPtr)))fTempReg)
#endif
int AppleUSBXHCI::DiffTRBIndex(USBPhysicalAddress64 t1, USBPhysicalAddress64 t2)
{
return( ((int)(t1-t2))/(int)sizeof(TRB));
}
XHCIRing *
AppleUSBXHCI::GetRing(int slotID, int endpointID, UInt32 stream)
{
XHCIRing *ring;
if(stream > _slots[slotID].maxStream[endpointID])
{
return(NULL);
}
ring = _slots[slotID].rings[endpointID];
if(ring == NULL)
{
return(NULL);
}
ring += stream;
return(ring);
}
XHCIRing *
AppleUSBXHCI::CreateRing(int slotID, int endpointID, UInt32 maxStream)
{
XHCIRing *ring;
XHCIRing *ringX;
int lenToAlloc;
lenToAlloc = (int)sizeof(XHCIRing)*(maxStream+1);
ring = (XHCIRing *)IOMalloc(lenToAlloc);
if(ring != NULL)
{
bzero(ring, lenToAlloc);
_slots[slotID].potentialStreams[endpointID] = maxStream;
_slots[slotID].maxStream[endpointID] = 0;
_slots[slotID].rings[endpointID] = ring;
ringX = ring;
for(UInt32 i = 0; i <= maxStream; i++)
{
ringX->slotID = slotID;
ringX->endpointID = endpointID;
ringX++;
}
}
return(ring);
}
XHCIRing *AppleUSBXHCI::FindStream(int slotID, int endpointID, USBPhysicalAddress64 phys, int *index, bool quiet)
{
UInt32 maxStream;
XHCIRing *ring;
int idx;
maxStream = _slots[slotID].maxStream[endpointID];
ring = _slots[slotID].rings[endpointID];
if(!quiet)
{
USBLog(2, "AppleUSBXHCI[%p]::FindStream - %llx (slot:%d, ep:%d) maxstream:%d", this, phys, (int)slotID, (int)endpointID, (int)maxStream);
}
for(UInt32 i = 1; i<=maxStream; i++)
{
ring++;
if(ring->TRBBuffer == NULL)
{
continue;
}
idx = DiffTRBIndex(phys, ring->transferRingPhys);
if(!quiet)
{
USBLog(2, "AppleUSBXHCI[%p]::FindStream - ring:%llx, idx:%d (size:%d)", this, ring->transferRingPhys, (int)idx, (int)ring->transferRingSize);
}
if( (idx >= 0) && (idx < ring->transferRingSize) )
{
*index = idx;
return(ring);
}
}
*index = 0;
return(NULL);
}
IOReturn AppleUSBXHCI::MakeBuffer(IOOptionBits options, mach_vm_size_t size, mach_vm_address_t mask, IOBufferMemoryDescriptor **buffer, void **logical, USBPhysicalAddress64 *physical)
{
IOReturn err;
IODMACommand *dmaCommand = NULL;
UInt64 offset = 0, maxSegmentSize;
IODMACommand::Segment64 segments;
UInt32 numSegments = 1;
IOPhysicalAddress physPtr;
if(!_AC64)
{ mask &= kXHCIAC32Mask;
}
*buffer = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(kernel_task, options, size, mask);
if (*buffer == NULL)
{
USBError(1, "AppleUSBXHCI[%p]::MakeBuffer - IOBufferMemoryDescriptor::inTaskWithPhysicalMask failed", this);
return kIOReturnNoMemory;
}
err = (*buffer)->prepare();
if (err)
{
USBError(1, "AppleUSBXHCI[%p]::MakeBuffer - could not prepare buffer err(%p)", this, (void*)err);
(*buffer)->release();
*buffer = NULL;
return err;
}
*logical = (*buffer)->getBytesNoCopy();
bzero(*logical, (UInt32)size);
maxSegmentSize = PAGE_SIZE;
if( ((options & kIOMemoryPhysicallyContiguous) != 0) || (size < PAGE_SIZE) )
{
maxSegmentSize = size;
}
dmaCommand = IODMACommand::withSpecification(kIODMACommandOutputHost64, 64, size, (IODMACommand::MappingOptions)(IODMACommand::kMapped | IODMACommand::kIterateOnly));
if (!dmaCommand)
{
USBError(1, "AppleUSBXHCI[%p]::MakeBuffer - could not get IODMACommand", this);
(*buffer)->complete();
(*buffer)->release();
(*buffer) = NULL;
return kIOReturnNoMemory;
}
err = dmaCommand->setMemoryDescriptor((*buffer));
if (err)
{
USBError(1, "AppleUSBXHCI[%p]::MakeBuffer - setMemoryDescriptor returned err (%p)", this, (void*)err);
dmaCommand->release();
(*buffer)->complete();
(*buffer)->release();
(*buffer) = NULL;
return err;
}
err = dmaCommand->gen64IOVMSegments(&offset, &segments, &numSegments);
if (err || (numSegments != 1) || (segments.fLength != maxSegmentSize))
{
USBError(1, "AppleUSBXHCI[%p]::MakeBuffer - could not generate segments err (%p) numSegments (%d) fLength (%d)", this, (void*)err, (int)numSegments, (int)segments.fLength);
err = err ? err : kIOReturnInternalError;
dmaCommand->clearMemoryDescriptor();
dmaCommand->release();
(*buffer)->complete();
(*buffer)->release();
(*buffer) = NULL;
return err;
}
physPtr = (IOPhysicalAddress)segments.fIOVMAddr;
*physical = HostToUSBLong(physPtr);
dmaCommand->clearMemoryDescriptor();
dmaCommand->release();
return(kIOReturnSuccess);
}
IOReturn AppleUSBXHCI::AllocStreamsContextArray(XHCIRing *ringX, UInt32 maxStream)
{
IOReturn err;
err = MakeBuffer(kIOMemoryUnshared | kIODirectionInOut | kIOMemoryPhysicallyContiguous, (maxStream+1)*sizeof(StreamContext), kXHCIStreamContextPhysMask,
&ringX->TRBBuffer, (void **)&ringX->transferRing, &ringX->transferRingPhys);
if(err != kIOReturnSuccess)
{
return(kIOReturnNoMemory);
}
ringX->transferRingSize = maxStream+1;
return(err);
}
IOReturn
AppleUSBXHCI::AllocRing(XHCIRing *ringX, int size_in_Pages)
{
IOReturn err;
int amount;
err = MakeBuffer(kIOMemoryUnshared | kIODirectionInOut | kIOMemoryPhysicallyContiguous, size_in_Pages * PAGE_SIZE, kXHCITransferRingPhysMask,
&ringX->TRBBuffer, (void **)&ringX->transferRing, &ringX->transferRingPhys);
if(err != kIOReturnSuccess)
{
return(kIOReturnNoMemory);
}
ringX->transferRingSize = size_in_Pages * PAGE_SIZE/sizeof(TRB);
ringX->transferRingPages = size_in_Pages;
ringX->transferRingPCS = 1;
ringX->transferRingEnqueueIdx = 0;
ringX->transferRingDequeueIdx = 0;
ringX->lastSeenDequeIdx = 0;
ringX->lastSeenFrame = 0;
ringX->nextIsocFrame = 0;
SetTRBAddr64(&ringX->transferRing[ringX->transferRingSize-1], ringX->transferRingPhys);
SetTRBType(&ringX->transferRing[ringX->transferRingSize-1], kXHCITRB_Link);
#if 1
ringX->transferRing[ringX->transferRingSize-1].offsC |= HostToUSBLong(kXHCITRB_TC);
#else
ringX->transferRing[ringX->transferRingSize-1].offsC |= HostToUSBLong(kXHCITRB_TC | kXHCITRB_IOC);
#endif
return(kIOReturnSuccess);
}
#if 0
IOReturn AppleUSBXHCI::ExpandRing(XHCIRing *ringX)
{
IOReturn ret;
int slotID, epIdx, stream;
XHCIRing oldEp, newEP, *ring0;
slotID = ringX->slotID;
epIdx = ringX->endpointID;
ring0 = GetRing(slotID, epIdx, 0);
stream = (int)(ringX - ring0);
if( (stream < 0) || (stream > (int)_slots[slotID].maxStream[epIdx]) )
{
USBLog(1, "AppleUSBXHCI[%p]::ExpandRing - could not find stream", this);
return(kIOReturnNoMemory);
}
if(!IsIsocEP(slotID, epIdx))
{
USBLog(1, "AppleUSBXHCI[%p]::ExpandRing - only for Isoc endpoints currently", this);
return(kIOReturnNoMemory);
}
ret = AllocRing(&newEP, ringX->transferRingPages+1);
if(ret != kIOReturnSuccess)
{
return(ret);
}
USBLog(3, "AppleUSBXHCI[%p]::ExpandRing - slot:%d, ep:%d, stream:%d, newSize:%d", this, slotID, epIdx, stream, newEP.transferRingPages);
StopEndpoint(slotID, epIdx);
oldEp = *ringX;
*ringX = newEP;
USBLog(3, "AppleUSBXHCI[%p]::ExpandRing - ring: %p, phys:%p", this, ringX->transferRing, (void *)ringX->transferRingPhys);
if( (ringX->transferRing == NULL) || (oldEp.transferRing == NULL) )
{
USBLog(1, "AppleUSBXHCI[%p]::ExpandRing - NULL Pointer. (%p, %p)", this, ringX->transferRing, oldEp.transferRing);
return(kIOReturnNoMemory);
}
for (int i = 0; i<oldEp.transferRingSize-2; i++) {
if(oldEp.transferRingDequeueIdx >= oldEp.transferRingSize-1)
{
if(oldEp.transferRingDequeueIdx > oldEp.transferRingSize-1)
{
USBLog(1, "AppleUSBXHCI[%p]::ExpandRing - oldEp.transferRingEnqueueIdx > oldEp.transferRingSize-1 (%d > %d)", this, oldEp.transferRingEnqueueIdx, oldEp.transferRingSize-1);
}
oldEp.transferRingDequeueIdx = 0;
}
ringX->transferRing[i] = oldEp.transferRing[oldEp.transferRingDequeueIdx];
if(GetTRBType(&ringX->transferRing[i]) == kXHCITRB_EventData)
{
SetTRBAddr64(&ringX->transferRing[i], ringX->transferRingPhys + i * sizeof(TRB)); }
SetTRBCycleBit(&ringX->transferRing[i], ringX->transferRingPCS);
oldEp.transferRingDequeueIdx++;
}
ringX->transferRingEnqueueIdx = oldEp.transferRingSize-2;
(void)SetTRDQPtr(ringX, stream, 0, false);
if(IsStreamsEndpoint(slotID, epIdx))
{
RestartStreams(slotID, epIdx, 0);
}
else
{
StartEndpoint(slotID, epIdx);
}
DeallocRing(&oldEp);
return(kIOReturnSuccess);
}
#endif
void AppleUSBXHCI::SetTRBAddr64(TRB * trb, USBPhysicalAddress64 addr)
{
trb->offs0 = HostToUSBLong(addr & 0xffffffff);
trb->offs4 = HostToUSBLong(addr >> 32);
}
void AppleUSBXHCI::SetStreamCtxAddr64(StreamContext * strc, USBPhysicalAddress64 addr, int sct, UInt32 pcs)
{
strc->offs0 = HostToUSBLong( (addr & 0xfffffff0) | ( (sct << kXHCIStrCtx_SCT_Shift) & kXHCIStrCtx_SCT_Mask) | (pcs?(int)kXHCITRB_DCS:0));
strc->offs4 = HostToUSBLong(addr >> 32);
}
void AppleUSBXHCI::SetTRBDCS(TRB * trb, bool DCS)
{
if(DCS)
{
trb->offs0 |= HostToUSBLong(kXHCITRB_DCS);
}
else
{
trb->offs0 &= ~HostToUSBLong(kXHCITRB_DCS);
}
}
void AppleUSBXHCI::SetDCBAAAddr64(USBPhysicalAddress64 * el, USBPhysicalAddress64 addr)
{
UInt32 *p;
p = (UInt32 *)el;
p[0] = HostToUSBLong(addr & 0xffffffC0);
p[1] = HostToUSBLong(addr >> 32);
}
IOReturn AppleUSBXHCI::TestConfiguredEpCount()
{
SInt16 oldEpCount;
oldEpCount = OSIncrementAtomic16(&_configuredEndpointCount);
USBLog(3, "AppleUSBXHCI[%p]::TestConfiguredEpCount - inc++ _configuredEndpointCount, was:(%d) max=%d ", this, oldEpCount, _maxControllerEndpoints);
if (oldEpCount >= _maxControllerEndpoints)
{
oldEpCount= OSDecrementAtomic16(&_configuredEndpointCount);
USBLog(1, "AppleUSBXHCI[%p]::TestConfiguredEpCount (kIOUSBEndpointCountExceeded) - dec-- _configuredEndpointCount, was:(%d)", this, oldEpCount);
return(kIOUSBEndpointCountExceeded);
}
oldEpCount= OSDecrementAtomic16(&_configuredEndpointCount);
USBLog(3, "AppleUSBXHCI[%p]::TestConfiguredEpCount - dec-- _configuredEndpointCount, was:(%d)", this, oldEpCount);
return(kIOReturnSuccess);
}
SInt16 AppleUSBXHCI::IncConfiguredEpCount()
{
SInt16 oldEpCount;
oldEpCount= OSIncrementAtomic16(&_configuredEndpointCount);
USBLog(3, "AppleUSBXHCI[%p]::IncConfiguredEpCount - count now=%d", this, oldEpCount);
if (oldEpCount >= _maxControllerEndpoints)
{
USBLog(1, "AppleUSBXHCI[%p]::IncConfiguredEpCount oldEpCount >= _maxControllerEndpoints", this);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
panic("AppleUSBXHCI - endpoint count exceeded on allocation %d", oldEpCount);
#endif
}
return oldEpCount;
}
SInt16 AppleUSBXHCI::DecConfiguredEpCount()
{
SInt16 oldEpCount;
oldEpCount= OSDecrementAtomic16(&_configuredEndpointCount);
USBLog(3, "AppleUSBXHCI[%p]::DecConfiguredEpCount - count now=%d", this, oldEpCount);
if (oldEpCount <= 0)
{
USBLog(1, "AppleUSBXHCI[%p]::DecConfiguredEpCount (oldEpCount <=0), underflow!", this);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
panic("AppleUSBXHCI - oldEpCount <=0, oldEpCount=%d", oldEpCount);
#endif
}
return oldEpCount;
}
#pragma mark ------------Endpoint Context Accessors---------------------
void AppleUSBXHCI::SetEPCtxDQpAddr64(Context * ctx, USBPhysicalAddress64 addr)
{ ctx->offs08 |= HostToUSBLong( (addr & 0xffffffff) & kXHCIEpCtx_TRDQpLo_Mask);
ctx->offs0C = HostToUSBLong(addr >> 32);
}
USBPhysicalAddress64 AppleUSBXHCI::GetEpCtxDQpAddr64(Context * ctx)
{
return(
(((UInt64)USBToHostLong(ctx->offs0C)) << 32) +
(USBToHostLong(ctx->offs08) & kXHCIEpCtx_TRDQpLo_Mask)
);
}
int AppleUSBXHCI::GetEpCtxEpState(Context * ctx)
{
return USBToHostLong(ctx->offs00) & kXHCIEpCtx_State_Mask;
}
void AppleUSBXHCI::SetEPCtxEpType(Context * ctx, int t)
{
ctx->offs04 |= HostToUSBLong((t << kXHCIEpCtx_EPType_Shift) & kXHCIEpCtx_EPType_Mask);
}
UInt8 AppleUSBXHCI::GetEpCtxEpType(Context * ctx)
{
return( (USBToHostLong(ctx->offs04) & kXHCIEpCtx_EPType_Mask) >> kXHCIEpCtx_EPType_Shift);
}
UInt8 AppleUSBXHCI::GetEPCtxInterval(Context * ctx)
{
return(USBToHostLong((ctx->offs00 & kXHCIEpCtx_Interval_Mask) >> kXHCIEpCtx_Interval_Shift));
}
void AppleUSBXHCI::SetEPCtxInterval(Context * ctx, UInt8 interval)
{
ctx->offs00 |= HostToUSBLong((interval << kXHCIEpCtx_Interval_Shift) & kXHCIEpCtx_Interval_Mask);
}
void AppleUSBXHCI::SetEPCtxMPS(Context * ctx, UInt16 mps)
{
ctx->offs04 |= HostToUSBLong((mps << kXHCIEpCtx_MPS_Shift) & kXHCIEpCtx_MPS_Mask);
}
UInt16 AppleUSBXHCI::GetEpCtxMPS(Context * ctx)
{
UInt16 mps;
mps = USBToHostLong((ctx->offs04 & kXHCIEpCtx_MPS_Mask) >> kXHCIEpCtx_MPS_Shift);
return mps;
}
void AppleUSBXHCI::SetEPCtxMult(Context * ctx, UInt16 mult)
{
ctx->offs00 |= HostToUSBLong((mult << kXHCIEpCtx_Mult_Shift) & kXHCIEpCtx_Mult_Mask);
}
UInt16 AppleUSBXHCI::GetEPCtxMult(Context * ctx)
{
return( (HostToUSBLong(ctx->offs00) & kXHCIEpCtx_Mult_Mask) >> kXHCIEpCtx_Mult_Shift);
}
void AppleUSBXHCI::SetEPCtxMaxBurst(Context * ctx, UInt16 maxBurst)
{
ctx->offs04 |= HostToUSBLong((maxBurst << kXHCIEpCtx_MaxBurst_Shift) & kXHCIEpCtx_MaxBurst_Mask);
}
UInt16 AppleUSBXHCI::GetEPCtxMaxBurst(Context * ctx)
{
return(USBToHostLong((ctx->offs04 & kXHCIEpCtx_MaxBurst_Mask) >> kXHCIEpCtx_MaxBurst_Shift));
}
void AppleUSBXHCI::SetEPCtxCErr(Context * ctx, UInt32 cerr)
{
ctx->offs04 |= HostToUSBLong((cerr << kXHCIEpCtx_CErr_Shift) & kXHCIEpCtx_CErr_Mask);
}
void AppleUSBXHCI::SetEPCtxLSA(Context * ctx, int state)
{
if(state)
{
ctx->offs00 |= HostToUSBLong(kXHCIEpCtx_LSA);
}
else
{
ctx->offs00 &= HostToUSBLong(kXHCIEpCtx_LSA);
}
}
void AppleUSBXHCI::SetEPCtxMaxPStreams(Context * ctx, int maxPStreams)
{
ctx->offs00 |= HostToUSBLong((maxPStreams << kXHCIEpCtx_MaxPStreams_Shift) & kXHCIEpCtx_MaxPStreams_Mask);
}
void AppleUSBXHCI::SetEPCtxDCS(Context * ctx, int state)
{
if(state)
{
ctx->offs08 |= HostToUSBLong(kXHCIEpCtx_DCS);
}
else
{
ctx->offs08 &= HostToUSBLong(~kXHCIEpCtx_DCS);
}
}
void AppleUSBXHCI::SetEPCtxAveTRBLen(Context * ctx, UInt32 len)
{
ctx->offs10 |= HostToUSBLong(len);
}
void AppleUSBXHCI::SetEPCtxMaxESITPayload(Context * ctx, UInt32 len)
{
ctx->offs10 |= HostToUSBLong(len << kXHCIEpCtx_MaxESITPayload_Shift);
}
#pragma mark ------------Slot Context Accessors---------------------
void AppleUSBXHCI::SetSlCtxEntries(Context * ctx, UInt32 entries)
{
ctx->offs00 |= HostToUSBLong((entries << kXHCISlCtx_CtxEnt_Shift) & kXHCISlCtx_CtxEnt_Mask);
}
UInt8 AppleUSBXHCI::GetSlCtxEntries(Context * ctx)
{
return (USBToHostLong(ctx->offs00) & kXHCISlCtx_CtxEnt_Mask) >> kXHCISlCtx_CtxEnt_Shift;
}
void AppleUSBXHCI::SetSlCtxSpeed(Context * ctx, UInt32 speed)
{
ctx->offs00 |= HostToUSBLong((speed << kXHCISlCtx_Speed_Shift) & kXHCISlCtx_Speed_Mask);
}
void AppleUSBXHCI::SetSlCtxRootHubPort(Context *ctx, UInt32 rootHubPort)
{
ctx->offs04 |= HostToUSBLong(rootHubPort << kXHCISlCtx_RHPNum_Shift);
}
UInt32 AppleUSBXHCI::GetSlCtxRootHubPort(Context * ctx)
{
return (USBToHostLong(ctx->offs04) & kXHCISlCtx_RHPNum_Mask) >> kXHCISlCtx_RHPNum_Shift;
}
int AppleUSBXHCI::GetSlCtxSlotState(Context * ctx)
{
return (USBToHostLong(ctx->offs0C) & kXHCISlCtx_SlotState_Mask) >> kXHCISlCtx_SlotState_Shift;
}
int AppleUSBXHCI::GetSlCtxUSBAddress(Context * ctx)
{
return (USBToHostLong(ctx->offs0C) & kXHCISlCtx_USBDeviceAddress_Mask);
}
UInt8 AppleUSBXHCI::GetSlCtxSpeed(Context * ctx)
{
int xSpeed;
xSpeed = (USBToHostLong(ctx->offs00) & kXHCISlCtx_Speed_Mask) >> kXHCISlCtx_Speed_Shift;
switch (xSpeed)
{
case kXHCISpeed_Full:
return(kUSBDeviceSpeedFull);
break;
case kXHCISpeed_Low:
return(kUSBDeviceSpeedLow);
break;
case kXHCISpeed_High:
return(kUSBDeviceSpeedHigh);
break;
case kXHCISpeed_Super:
return(kUSBDeviceSpeedSuper);
break;
default:
return(kUSBDeviceSpeedSuper);
break;
}
}
void AppleUSBXHCI::SetSlCtxTTPort(Context * ctx, UInt32 port)
{
ctx->offs08 |= HostToUSBLong((port << kXHCISlCtx_TTPort_Shift) & kXHCISlCtx_TTPort_Mask);
}
int AppleUSBXHCI::GetSlCtxTTPort(Context * ctx)
{
return (USBToHostLong(ctx->offs08) & kXHCISlCtx_TTPort_Mask) >> kXHCISlCtx_TTPort_Shift;
}
void AppleUSBXHCI::SetSlCtxTTSlot(Context * ctx, UInt32 slot)
{
ctx->offs08 |= HostToUSBLong(slot & kXHCISlCtx_TTSlot_Mask);
}
int AppleUSBXHCI::GetSlCtxTTSlot(Context * ctx)
{
return (USBToHostLong(ctx->offs08) & kXHCISlCtx_TTSlot_Mask);
}
void AppleUSBXHCI::SetSlCtxInterrupter(Context * ctx, UInt32 interrupter)
{
ctx->offs08 |= HostToUSBLong((interrupter << kXHCISlCtx_Interrupter_Shift) & kXHCISlCtx_Interrupter_Mask);
}
UInt32 AppleUSBXHCI::GetSlCtxInterrupter(Context * ctx)
{
return (USBToHostLong(ctx->offs08) & kXHCISlCtx_Interrupter_Mask) >> kXHCISlCtx_Interrupter_Shift;
}
UInt32 AppleUSBXHCI::GetSlCtxRouteString(Context * ctx)
{
return (USBToHostLong(ctx->offs00) & kXHCISlCtx_Route_Mask);
}
void AppleUSBXHCI::SetSlCtxRouteString(Context * ctx, UInt32 string)
{
ctx->offs00 |= HostToUSBLong(string & kXHCISlCtx_Route_Mask);
}
void AppleUSBXHCI::ResetSlCtxNumPorts(Context * ctx, UInt32 num)
{
ctx->offs04 = (ctx->offs04 & ~HostToUSBLong(kXHCISlCtx_NumPorts_Mask)) | HostToUSBLong((num << kXHCISlCtx_NumPorts_Shift) & kXHCISlCtx_NumPorts_Mask);
}
void AppleUSBXHCI::ResetSlCtxTTT(Context * ctx, UInt32 TTT)
{
ctx->offs04 = (ctx->offs04 & ~HostToUSBLong(kXHCISlCtx_TTT_Mask)) | HostToUSBLong((TTT << kXHCISlCtx_TTT_Shift) & kXHCISlCtx_TTT_Mask);
}
void AppleUSBXHCI::SetSlCtxMTT(Context * ctx, bool multiTT)
{
if(multiTT)
{
ctx->offs00 |= HostToUSBLong(kXHCISlCtx_MTTBit); }
else
{
ctx->offs00 &= ~HostToUSBLong(kXHCISlCtx_MTTBit); }
}
bool AppleUSBXHCI::GetSlCtxMTT(Context * ctx)
{
return( (ctx->offs00 & HostToUSBLong(kXHCISlCtx_MTTBit)) != 0);
}
#pragma mark ------------TRB Accessors---------------------
void AppleUSBXHCI::SetTRBType(TRB * trb, int t)
{
trb->offsC |= HostToUSBLong((t << kXHCITRB_Type_Shift) & kXHCITRB_Type_Mask);
}
int AppleUSBXHCI::GetTRBType(TRB * trb)
{
return((USBToHostLong(trb->offsC) & kXHCITRB_Type_Mask) >> kXHCITRB_Type_Shift);
}
int AppleUSBXHCI::GetTRBSlotID(TRB * trb)
{
return((USBToHostLong(trb->offsC) & kXHCITRB_SlotID_Mask) >> kXHCITRB_SlotID_Shift);
}
void AppleUSBXHCI::SetTRBSlotID(TRB * trb, UInt32 slotID)
{
trb->offsC |= HostToUSBLong((slotID << kXHCITRB_SlotID_Shift) & kXHCITRB_SlotID_Mask);
}
void AppleUSBXHCI::SetTRBEpID(TRB * trb, UInt32 slotID)
{
trb->offsC |= HostToUSBLong((slotID << kXHCITRB_Ep_Shift) & kXHCITRB_Ep_Mask);
}
void AppleUSBXHCI::SetTRBStreamID(TRB * trb, UInt32 streamID)
{
trb->offs8 |= HostToUSBLong((streamID << kXHCITRB_Stream_Shift) & kXHCITRB_Stream_Mask);
}
int AppleUSBXHCI::GetTRBCC(TRB * trb)
{
return((USBToHostLong(trb->offs8) & kXHCITRB_CC_Mask) >> kXHCITRB_CC_Shift);
}
bool AppleUSBXHCI::IsIsocEP(int slotID, UInt32 endpointIdx)
{
int epType;
Context * epContext = GetEndpointContext(slotID, endpointIdx);
if(epContext == NULL)
{
return(false);
}
epType = GetEpCtxEpType(epContext);
return( (epType == kXHCIEpCtx_EPType_IsocIn) || (epType == kXHCIEpCtx_EPType_IsocOut) );
}
void AppleUSBXHCI::InitEventRing(int IRQ, bool reinit)
{
int i;
if(reinit)
{
for(i = 0; i<_events[IRQ].numEvents; i++)
{
ClearTRB(&_events[IRQ].EventRing[i], true);
}
}
else
{
for(i = 0; i<(_events[IRQ].numEvents + kSegmentTableEventRingEntries); i++)
{
ClearTRB(&_events[IRQ].EventRing[i], true);
}
_events[IRQ].EventRingSegTablePhys = _events[IRQ].EventRingPhys;
_events[IRQ].EventRingPhys = _events[IRQ].EventRingPhys + (kSegmentTableEventRingEntries * sizeof(TRB));
}
Write64Reg(&_pXHCIRuntimeReg->IR[IRQ].ERDP, _events[IRQ].EventRingPhys);
SetTRBAddr64(&_events[IRQ].EventRing[0], _events[IRQ].EventRingPhys);
if(!reinit)
{
_events[IRQ].EventRing[0].offs8 = HostToUSBLong(_events[IRQ].numEvents);
_events[IRQ].EventRing = &_events[IRQ].EventRing[kSegmentTableEventRingEntries];
}
Write32Reg(&_pXHCIRuntimeReg->IR[IRQ].ERSTSZ, kEntriesInEventRingSegmentTable); Write64Reg(&_pXHCIRuntimeReg->IR[IRQ].ERSTBA, _events[IRQ].EventRingSegTablePhys); Write32Reg(&_pXHCIRuntimeReg->IR[IRQ].IMOD, kInterruptModerationInterval); Write32Reg(&_pXHCIRuntimeReg->IR[IRQ].IMAN, kXHCIIRQ_IE);
_events[IRQ].EventRingDequeueIdx = 0;
_events[IRQ].EventRingCCS = 1;
_events[IRQ].EventRingDPNeedsUpdate = false;
if(!reinit)
{
PrintInterrupter(5, IRQ, "InitEventRing");
}
}
void AppleUSBXHCI::InitCMDRing(void)
{
int i;
for(i = 0; i<_numCMDs; i++)
{
ClearTRB(&_CMDRing[i], true);
}
SetTRBAddr64(&_CMDRing[_numCMDs-1], _CMDRingPhys);
SetTRBType(&_CMDRing[_numCMDs-1], kXHCITRB_Link);
_CMDRing[_numCMDs-1].offsC |= HostToUSBLong(kXHCITRB_TC);
_CMDRingPCS = 1;
_CMDRingEnqueueIdx = 0;
_CMDRingDequeueIdx = _CMDRingEnqueueIdx;
Write64Reg(&_pXHCIRegisters->CRCR, (_CMDRingPhys & ~kXHCICRCRFlags_Mask) | kXHCI_RCS); }
void AppleUSBXHCI::SetTRBCycleBit(TRB *trb, int state)
{
if(state)
{
trb->offsC |= HostToUSBLong(kXHCITRB_C);
}
else
{
trb->offsC &= ~HostToUSBLong(kXHCITRB_C);
}
}
void AppleUSBXHCI::SetTRBChainBit(TRB *trb, int state)
{
if(state)
{
trb->offsC |= HostToUSBLong(kXHCITRB_CH);
}
else
{
trb->offsC &= ~HostToUSBLong(kXHCITRB_CH);
}
}
bool AppleUSBXHCI::GetTRBChainBit(TRB *trb)
{
return( (USBToHostLong(trb->offsC) & kXHCITRB_CH) != 0);
}
void AppleUSBXHCI::SetTRBBSRBit(TRB *trb, int state)
{
if(state)
{
trb->offsC |= HostToUSBLong(kXHCITRB_BSR);
}
else
{
trb->offsC &= ~HostToUSBLong(kXHCITRB_BSR);
}
}
IOReturn AppleUSBXHCI::EnqueCMD(TRB *trb, int type, CMDComplete callBackFn, SInt32 **param)
{
int nextEnqueueIndex;
UInt32 offsC;
if(_CMDRingEnqueueIdx >= _numCMDs-2)
{ if(_CMDRingDequeueIdx == 0)
{
USBLog(1, "AppleUSBXHCI[%p]::EnqueCMD - Ring full 1, enq:%d, deq:%d", this, _CMDRingEnqueueIdx, _CMDRingDequeueIdx);
return kIOReturnNoResources;
}
nextEnqueueIndex = 0;
}
else
{
if(_CMDRingEnqueueIdx+1 == _CMDRingDequeueIdx)
{
USBLog(1, "AppleUSBXHCI[%p]::EnqueCMD - Ring full 2, enq:%d, deq:%d", this, _CMDRingEnqueueIdx, _CMDRingDequeueIdx);
return kIOReturnNoResources;
}
nextEnqueueIndex = _CMDRingEnqueueIdx+1;
}
#if 0
{
USBPhysicalAddress64 phys;
phys = _CMDRingEnqueueIdx*sizeof(TRB)+_CMDRingPhys;
USBLog(3, "AppleUSBXHCI[%p]::EnqueCMD - TRB phys: %08lx", this, (long unsigned int)phys);
}
#endif
_CMDRing[_CMDRingEnqueueIdx].offs0 = trb->offs0;
_CMDRing[_CMDRingEnqueueIdx].offs4 = trb->offs4;
_CMDRing[_CMDRingEnqueueIdx].offs8 = trb->offs8;
_CMDCompletions[_CMDRingEnqueueIdx].completionAction = callBackFn;
_CMDCompletions[_CMDRingEnqueueIdx].parameter = CMD_NOT_COMPLETED;
*param = &_CMDCompletions[_CMDRingEnqueueIdx].parameter;
offsC = trb->offsC;
offsC &= ~(kXHCITRB_Type_Mask | kXHCITRB_C); offsC |= type << kXHCITRB_Type_Shift;
if(_CMDRingPCS)
{
offsC |= kXHCITRB_C;
}
PrintTRB(7, &_CMDRing[_CMDRingEnqueueIdx], "EnqueCMD", offsC);
USBLog(7, "AppleUSBXHCI[%p]::EnqueCMD - offsC: %08lx, TRB phys: %llx", this, (long unsigned int)offsC, _CMDRingPhys+_CMDRingEnqueueIdx*sizeof(TRB));
USBLog(7, "AppleUSBXHCI[%p]::EnqueCMD - _CMDRingEnqueueIdx= %d %p(%p)", this, (int)_CMDRingEnqueueIdx, callBackFn, param);
IOSync();
_CMDRing[_CMDRingEnqueueIdx].offsC = offsC;
IOSync();
if(nextEnqueueIndex == 0)
{
SetTRBCycleBit(&_CMDRing[_numCMDs-1], _CMDRingPCS); _CMDRingPCS = 1 - _CMDRingPCS; }
PrintCommandTRB(&_CMDRing[_CMDRingEnqueueIdx]);
_CMDRingEnqueueIdx = nextEnqueueIndex;
IOSync();
Write32Reg(&_pXHCIDoorbells[0], kXHCIDB_Controller);
IOSync();
return(kIOReturnSuccess);
}
void AppleUSBXHCI::ClearTRB(TRB *trb, bool clearCCS)
{
trb->offs0 = 0;
trb->offs4 = 0;
trb->offs8 = 0;
if(clearCCS)
{
trb->offsC = 0;
}
else
{
trb->offsC &= kXHCITRB_C;
}
}
void AppleUSBXHCI::PrintInterrupter(int level, int IRQ, const char *s)
{
USBLog(level, "AppleUSBXHCI[%p]::PrintInterrupter %s IRQ:%d - IMAN: %08lx IMOD: %08lx ERDP: %08lx", this, s, IRQ,
(long unsigned int)Read32Reg(&_pXHCIRuntimeReg->IR[IRQ].IMAN), (long unsigned int)Read32Reg(&_pXHCIRuntimeReg->IR[IRQ].IMOD), (long unsigned int)Read64Reg(&_pXHCIRuntimeReg->IR[IRQ].ERDP));
}
void AppleUSBXHCI::PrintTransferTRB(TRB *trb, XHCIRing *ringX, int indexInRing, UInt32 offsC )
{
USBTrace_Start(kUSBTXHCIPrintTRB, kTPXHCIPrintTRBTransfer, (uintptr_t)this, (uintptr_t)(ringX->transferRingPhys), trb->offs0, trb->offs4);
if(offsC == 0)
{
USBTrace_End(kUSBTXHCIPrintTRB, kTPXHCIPrintTRBTransfer, trb->offs8, trb->offsC, indexInRing, 0);
}
else
{
USBTrace_End(kUSBTXHCIPrintTRB, kTPXHCIPrintTRBTransfer, trb->offs8, offsC, indexInRing, 0);
}
}
void AppleUSBXHCI::PrintEventTRB(TRB *trb, int irq, bool inFilter, XHCIRing* otherRing )
{
USBTrace_Start(kUSBTXHCIPrintTRB, kTPXHCIPrintTRBEvent, (uintptr_t)this, irq, trb->offs0, trb->offs4);
USBTrace_End(kUSBTXHCIPrintTRB, kTPXHCIPrintTRBEvent, trb->offs8, trb->offsC, otherRing ? (uintptr_t)(otherRing->transferRingPhys) : 0, inFilter);
}
void AppleUSBXHCI::PrintCommandTRB(TRB *trb)
{
USBTrace_Start(kUSBTXHCIPrintTRB, kTPXHCIPrintTRBCommand, (uintptr_t)this, trb->offs0, trb->offs4, 0);
USBTrace_End(kUSBTXHCIPrintTRB, kTPXHCIPrintTRBCommand, trb->offs8, trb->offsC, 0, 0);
}
void AppleUSBXHCI::PrintTRB(int level, TRB *trb, const char *s, UInt32 offsC)
{
if(offsC == 0)
{
USBLog(level, "AppleUSBXHCI[%p]::PrintTRB %s - %08lx %08lx %08lx %08lx", this,s,
(long unsigned int)trb->offs0,(long unsigned int) trb->offs4,(long unsigned int) trb->offs8,(long unsigned int) trb->offsC);
}
else
{
USBLog(level, "AppleUSBXHCI[%p]::PrintTRB %s - %08lx %08lx %08lx %08lx", this,s,
(long unsigned int)trb->offs0,(long unsigned int) trb->offs4,(long unsigned int) trb->offs8,(long unsigned int) offsC);
}
}
void AppleUSBXHCI::PrintRing(XHCIRing *ring)
{
USBLog(5, "AppleUSBXHCI[%p]::PrintRing ---------------- slotID:%d endpointID:%d ---------------------", this, ring->slotID , ring->endpointID);
USBLog(5, "AppleUSBXHCI[%p]::PrintRing - transferRingPhys: %llx transferRingSize: %d transferRingPCS: %d", this, ring->transferRingPhys, (int)ring->transferRingSize, (int)ring->transferRingPCS);
USBLog(5, "AppleUSBXHCI[%p]::PrintRing - transferRingEnqueueIdx: %d transferRingDequeueIdx: %d", this, (int)ring->transferRingEnqueueIdx, (int)ring->transferRingDequeueIdx);
USBLog(5, "AppleUSBXHCI[%p]::PrintRing - lastSeenDequeIdx: %d lastSeenFrame: %d", this, (int)ring->lastSeenDequeIdx, (int)ring->lastSeenFrame);
USBLog(5, "AppleUSBXHCI[%p]::PrintRing - beingReturned: %d beingDeleted: %d needsDoorbell: %d", this, (int)ring->beingReturned, (int)ring->beingDeleted, (int)ring->needsDoorbell);
if( (ring->endpointType == kXHCIEpCtx_EPType_IsocIn) || (ring->endpointType == kXHCIEpCtx_EPType_IsocOut) )
{
AppleXHCIIsochEndpoint *pIsocEP = OSDynamicCast(AppleXHCIIsochEndpoint, (AppleXHCIIsochEndpoint*)ring->pEndpoint);
pIsocEP->print(5);
}
else
{
AppleXHCIAsyncEndpoint* pAsyncEP = OSDynamicCast(AppleXHCIAsyncEndpoint, (AppleXHCIAsyncEndpoint*)ring->pEndpoint);
pAsyncEP->print(5);
}
char buf[256];
int i = 0;
for (i=0; i < ring->transferRingSize; i++)
{
UInt8 trbType = GetTRBType(&ring->transferRing[i]);
snprintf(buf, 256, "(%s) Index: %4d Phys:%08lx", TRBType(trbType), i, (long unsigned int)(ring->transferRingPhys + i*sizeof(TRB)));
PrintTRB(5, &ring->transferRing[i], buf);
PrintTransferTRB(&ring->transferRing[i], ring, i);
}
}
void AppleUSBXHCI::PrintContext(Context * ctx)
{
if ( ctx == NULL )
{
USBLog(1, "AppleUSBXHCI[%p]::PrintContext called with a NULL context", this);
return;
}
USBTrace_Start(kUSBTXHCI, kTPXHCIPrintContext, (uintptr_t)this, ctx->offs00, ctx->offs04, ctx->offs08);
USBTrace(kUSBTXHCI, kTPXHCIPrintContext, (uintptr_t)this, 1, 0, ctx->offs0C);
USBLog(4, "AppleUSBXHCI[%p]::PrintContext 1 - %08lx %08lx %08lx %08lx", this,
(long unsigned int)ctx->offs00,(long unsigned int) ctx->offs04,(long unsigned int) ctx->offs08,(long unsigned int) ctx->offs0C);
USBTrace(kUSBTXHCI, kTPXHCIPrintContext, (uintptr_t)this, 2, 0, ctx->offs10);
USBLog(4, "AppleUSBXHCI[%p]::PrintContext 2 - %08lx %08lx %08lx %08lx", this,
(long unsigned int)ctx->offs10,(long unsigned int) ctx->offs14,(long unsigned int) ctx->offs18,(long unsigned int) ctx->offs1C);
USBTrace_End(kUSBTXHCI, kTPXHCIPrintContext, (uintptr_t)this, ctx->offs14, ctx->offs18, ctx->offs1C);
}
void AppleUSBXHCI::PrintSlotContexts(void)
{
for(int i = 0; i<_numDeviceSlots; i++)
{
Context * ctx = GetSlotContext(i);
if(ctx != NULL)
{
USBLog(4, "AppleUSBXHCI[%p]::slot %d: - %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx", this, i,
(long unsigned int)ctx->offs00,(long unsigned int) ctx->offs04,(long unsigned int) ctx->offs08,(long unsigned int) ctx->offs0C,
(long unsigned int)ctx->offs10,(long unsigned int) ctx->offs14,(long unsigned int) ctx->offs18,(long unsigned int) ctx->offs1C);
}
}
}
Context * AppleUSBXHCI::GetContextFromDeviceContext(int SlotID, int contextIdx)
{
Context * ctx = NULL;
if (_Contexts64 == false)
{
ctx = _slots[SlotID].deviceContext;
if (ctx != NULL)
{
ctx = &_slots[SlotID].deviceContext[contextIdx];
}
}
else
{
ctx = (Context *)_slots[SlotID].deviceContext64;
if (ctx != NULL)
{
ctx = (Context *)&_slots[SlotID].deviceContext64[contextIdx];
}
}
return ctx;
}
Context * AppleUSBXHCI::GetEndpointContext(int SlotID, int EndpointID)
{
return GetContextFromDeviceContext(SlotID, EndpointID);
}
Context * AppleUSBXHCI::GetSlotContext(int SlotID)
{
return GetContextFromDeviceContext(SlotID, 0);
}
#if 0
void AppleUSBXHCI::PrintCCETRB(TRB *trb)
{
int type;
PrintTRB(trb, "PrintCCETRB");
type = GetTRBType(trb);
if(type != kXHCITRB_CCE)
{
USBLog(2, "AppleUSBXHCI[%p]::PrintCCETRB - not a command completion event, type: %d", this,(int) type);
return;
}
USBLog(2, "AppleUSBXHCI[%p]::PrintCCETRB - Command completion event, type: %d", this,(int) type);
USBLog(2, "AppleUSBXHCI[%p]::PrintCCETRB - TRB pointer: %08lx %08lx", this,(long unsigned int) trb->offs4, (long unsigned int)trb->offs0);
USBLog(2, "AppleUSBXHCI[%p]::PrintCCETRB - Completion code: %02lx ", this,(long unsigned int) (trb->offs8 >> 24));
}
#endif
IOReturn AppleUSBXHCI::MungeXHCIStatus(int code, bool in, UInt8 speed, bool silent)
{
switch(code)
{
case kXHCITRB_CC_Success:
case kXHCITRB_CC_ShortPacket:
return(kIOReturnSuccess);
case kXHCITRB_CC_Data_Buffer:
if(in)
{
return(kIOUSBBufferOverrunErr);
}
else
{
return(kIOUSBBufferUnderrunErr);
}
case kXHCITRB_CC_Babble_Detected:
return(kIOReturnOverrun);
case kXHCITRB_CC_XActErr:
if (speed < kUSBDeviceSpeedHigh)
{
return(kIOUSBHighSpeedSplitError);
}
else
{
return(kIOReturnNotResponding);
}
case kXHCITRB_CC_TRBErr:
return(kIOReturnInternalError);
case kXHCITRB_CC_STALL:
return(kIOUSBPipeStalled);
case kXHCITRB_CC_ResourceErr:
return(kIOReturnNoResources);
case kXHCITRB_CC_Bandwidth:
return(kIOReturnNoBandwidth);
case kXHCITRB_CC_NoSlots:
return(kIOUSBDeviceCountExceeded);
case kXHCITRB_CC_Invalid_Stream_Type:
return(kIOReturnInvalid);
case kXHCITRB_CC_Slot_Not_Enabled:
return(kIOReturnOffline);
case kXHCITRB_CC_Endpoint_Not_Enabled:
return(kIOReturnOffline);
case kXHCITRB_CC_RingUnderrun:
return(kIOReturnUnderrun);
case kXHCITRB_CC_RingOverrun:
return(kIOReturnOverrun);
case kXHCITRB_CC_VF_Event_Ring_Full:
return(kIOReturnOverrun);
case kXHCITRB_CC_CtxParamErr:
return(kIOReturnBadArgument);
case kXHCITRB_CC_Bandwidth_Overrun:
return(kIOReturnNoBandwidth);
case kXHCITRB_CC_CtxStateErr:
return(kIOReturnBadArgument);
case kXHCITRB_CC_No_Ping_Response:
return(kIOReturnNotResponding);
case kXHCITRB_CC_Event_Ring_Full:
return(kIOReturnOverrun);
case kXHCITRB_CC_Incompatible_Device:
return(kIOReturnDeviceError);
case kXHCITRB_CC_Missed_Service:
return(kIOReturnOverrun);
case kXHCITRB_CC_CMDRingStopped:
return(kIOReturnOffline);
case kXHCITRB_CC_Command_Aborted:
return(kIOReturnAborted);
case kXHCITRB_CC_Stopped:
case kXHCITRB_CC_Stopped_Length_Invalid:
return(kIOReturnAborted);
case kXHCITRB_CC_Max_Exit_Latency_Too_Large:
return(kIOReturnBadArgument);
case kXHCITRB_CC_Isoch_Buffer_Overrun:
return(kIOReturnOverrun);
case kXHCITRB_CC_Event_Lost:
return(kIOReturnOverrun);
case kXHCITRB_CC_Undefined:
return(kIOReturnInternalError);
case kXHCITRB_CC_Invalid_Stream_ID:
return(kIOReturnBadArgument);
case kXHCITRB_CC_Secondary_Bandwidth:
return(kIOReturnNoBandwidth);
case kXHCITRB_CC_Split_Transaction:
return(kIOUSBHighSpeedSplitError);
kXHCITRB_CC_CNTX_ENTRIES_GTR_MAXEP:
if( (_errataBits & kXHCIErrataPPT) == 0)
{
return(kIOReturnInternalError);
}
else
{
return(kIOReturnInternalError);
}
case kXHCITRB_CC_FORCE_HDR_USB2_NO_SUPPORT:
if( (_errataBits & kXHCIErrataPPT) == 0)
{
return(kIOReturnUnsupported);
}
else
{
return(kIOReturnInternalError);
}
case kXHCITRB_CC_UNDEFINED_BEHAVIOR:
if( (_errataBits & kXHCIErrataPPT) == 0)
{
return(kIOReturnInternalError);
}
else
{
return(kIOReturnInternalError);
}
case kXHCITRB_CC_CMPL_VEN_DEF_ERR_195:
if( (_errataBits & kXHCIErrataPPT) == 0)
{
return(kIOReturnInternalError);
}
else
{
return(kIOReturnInternalError);
}
case kXHCITRB_CC_NOSTOP:
if( (_errataBits & kXHCIErrataPPT) == 0)
{
return(kIOReturnInternalError);
}
else
{
return(kIOReturnInternalError);
}
case kXHCITRB_CC_HALT_STOP:
if( (_errataBits & kXHCIErrataPPT) == 0)
{
return(kIOReturnInternalError);
}
else
{
return(kIOReturnInternalError);
}
case kXHCITRB_CC_DL_ERR:
if( (_errataBits & kXHCIErrataPPT) == 0)
{
return(kIOReturnInternalError);
}
else
{
return(kIOReturnInternalError);
}
case kXHCITRB_CC_CMPL_WITH_EMPTY_CONTEXT:
if( (_errataBits & kXHCIErrataPPT) == 0)
{
return(kIOReturnNotOpen);
}
else
{
return(kIOReturnInternalError);
}
case kXHCITRB_CC_VENDOR_CMD_FAILED:
if( (_errataBits & kXHCIErrataPPT) == 0)
{
return(kIOReturnNoBandwidth);
}
else
{
return(kIOReturnInternalError);
}
default:
if(!silent)
{
USBLog(2, "AppleUSBXHCI[%p]::MungeXHCIStatus - unknown code: %d", this, code);
}
return(kIOReturnInternalError);
}
}
IOReturn
AppleUSBXHCI::MungeCommandCompletion(int code, bool silent)
{
if(code > MakeXHCIErrCode(0))
{
return(kIOReturnSuccess);
}
switch(code)
{
case CMD_NOT_COMPLETED:
return(kIOReturnTimeout);
case MAKEXHCIERR(kXHCITRB_CC_CtxParamErr):
return(kIOReturnBadArgument);
case MAKEXHCIERR(kXHCITRB_CC_CtxStateErr):
return(kIOReturnNotPermitted);
default:
if(!silent)
{
USBLog(2, "AppleUSBXHCI[%p]::MungeCommandCompletion - unknown code: %d", this, code);
}
return(kIOReturnInternalError);
}
}
int AppleUSBXHCI::GetEndpointID(int endpointNumber, short direction)
{
int endpointID;
endpointID = 2*endpointNumber;
if(direction != kUSBOut)
{
endpointID++;
}
return(endpointID);
}
int AppleUSBXHCI::GetSlotID(int functionNumber)
{
int slotID;
if( (functionNumber == _rootHubFuncAddressSS) || (functionNumber == _rootHubFuncAddressHS) )
{
return(0);
}
if( (functionNumber <0) || (functionNumber > 127) )
{
USBLog(3, "AppleUSBXHCI[%p]::GetSlotID - functionNumber out of range: %d", this, functionNumber);
return(0);
}
if(!_devEnabled[functionNumber])
{
USBLog(3, "AppleUSBXHCI[%p]::GetSlotID - functionNumber disabled: %d", this, functionNumber);
return(0);
}
slotID = _devMapping[functionNumber];
return(slotID);
}
int AppleUSBXHCI::CountRingToED(XHCIRing *ring, int index, UInt32 *shortfall, bool advance)
{
int newIndex, type;
TRB *t;
t = &ring->transferRing[index];
USBLog(5, "AppleUSBXHCI[%p]::CountRingToED - Initial index: %d", this, index);
PrintTRB(5, t, "CountRingToED1");
while(GetTRBChainBit(t)){
newIndex = index;
newIndex++;
if(newIndex >= ring->transferRingSize-1)
{
newIndex = 0;
}
if(newIndex == ring->transferRingEnqueueIdx)
{
if(advance)
{
ring->transferRingDequeueIdx = index;
}
USBLog(1, "AppleUSBXHCI[%p]::CountRingToED - No ED found: %d", this, index);
return(index);
}
index = newIndex;
t = &ring->transferRing[index];
PrintTRB(5, t, "CountRingToED2");
type = GetTRBType(t);
if(type == kXHCITRB_EventData)
{
USBLog(3, "AppleUSBXHCI[%p]::CountRingToED - ED index: %d", this, index);
if(advance)
{
ring->transferRingDequeueIdx = index;
}
return(index);
}
if(type == kXHCITRB_Normal)
{
*shortfall += USBToHostLong(t->offs8) & kXHCITRB_Normal_Len_Mask;
USBLog(2, "AppleUSBXHCI[%p]::CountRingToED - Normal TD (index:%d) shortfall: %d, running:%d", this,
index, USBToHostLong(t->offs8) & kXHCITRB_Normal_Len_Mask, (int)*shortfall);
}
}
USBLog(5, "AppleUSBXHCI[%p]::CountRingToED - TRB not chained, returning: %d", this, index);
if(advance)
{
ring->transferRingDequeueIdx = index;
}
return(index);
}
bool
AppleUSBXHCI::CanTDFragmentFit(XHCIRing *ring, UInt32 fragmentTransferSize)
{
UInt16 maxTRBs = fragmentTransferSize/PAGE_SIZE + 2;
if (ring->transferRingEnqueueIdx < ring->transferRingDequeueIdx)
{
return (maxTRBs <= (ring->transferRingDequeueIdx - ring->transferRingEnqueueIdx-1));
}
else
{
UInt16 spaceInEnd, spaceInStart, space;
spaceInEnd = ring->transferRingSize - ring->transferRingEnqueueIdx - 1;
if (spaceInEnd < 2)
{
spaceInEnd = 0;
}
else
{
spaceInEnd -= 2;
}
spaceInStart = ring->transferRingDequeueIdx;
if (spaceInStart < 2)
{
spaceInStart = 0;
}
else
{
spaceInStart -= 2;
}
if (spaceInEnd > spaceInStart)
{
space = spaceInEnd;
}
else
{
space = spaceInStart;
}
return (space >= maxTRBs);
}
}
int
AppleUSBXHCI::FreeSlotsOnRing(XHCIRing *ring)
{
USBLogKP(7, "AppleUSBXHCI::FreeSlotsOnRing - transferRingEnqueueIdx(%d) transferRingDequeueIdx(%d)\n", ring->transferRingEnqueueIdx, ring->transferRingDequeueIdx);
if(ring->transferRingEnqueueIdx < ring->transferRingDequeueIdx)
{
return(ring->transferRingDequeueIdx - ring->transferRingEnqueueIdx-1);
}
else
{
UInt8 speed;
int space;
int align;
speed = GetSlCtxSpeed(GetSlotContext(ring->slotID));
space = ring->transferRingSize - (ring->transferRingEnqueueIdx - ring->transferRingDequeueIdx) -1;
if(speed >= kXHCISpeed_Super)
{
UInt32 maxPacketSize, maxBurst, mult;
Context * epContext = GetEndpointContext(ring->slotID, ring->endpointID);
maxPacketSize = GetEpCtxMPS(epContext);
maxBurst = GetEPCtxMaxBurst(epContext) + 1;
mult = GetEPCtxMult(epContext)+1;
align = (maxPacketSize * maxBurst * mult)/ 4096;
}
else
{
align = 2;
}
if(space < align)
{
space = 0;
}
else
{
space -= align;
}
return(space);
}
}
#define NSEC_PER_MS 1000000
SInt32 AppleUSBXHCI::WaitForCMD(TRB *t, int command, CMDComplete callBackF)
{
int innercount = 0;
UInt32 count = 0;
SInt32 *ret;
IOReturn kr = 0;
UInt32 timeout = 100;
SInt32 retval = CMD_NOT_COMPLETED;
if((Read32Reg(&_pXHCIRegisters->USBSTS) & kXHCIHSEBit) != 0)
{
if(!_HSEReported)
{
USBError(1, "AppleUSBXHCI[%p]::WaitForCMD - HSE bit set:%x (1)", this, Read32Reg(&_pXHCIRegisters->USBSTS));
}
_HSEReported = true;
}
if ( isInactive() || _lostRegisterAccess || !_controllerAvailable )
{
USBLog(1, "AppleUSBXHCI::WaitForCMD - Returning early inactive: %d lost register access:%d", isInactive(), (int)_lostRegisterAccess);
return retval;
}
USBTrace_Start(kUSBTXHCI, kTPXHCIWaitForCmd, (uintptr_t)this, (uintptr_t) t, command, 0);
if ( getWorkLoop()->onThread() )
{
USBLog(5, "AppleUSBXHCI[%p]::WaitForCMD (%s) - Called on thread.", this, TRBType(command));
}
if (!getWorkLoop()->inGate())
{
USBLog(1, "AppleUSBXHCI[%p]::WaitForCMD (%s) - Not inGate.", this, TRBType(command));
}
if ( callBackF == 0 )
{
callBackF = OSMemberFunctionCast(CMDComplete, this, &AppleUSBXHCI::CompleteSlotCommand);
}
USBLog(7, "AppleUSBXHCI[%p]::WaitForCMD (%s) 1 - num interrupts: %d, num primary: %d, inactive: %d, unavailable: %d, is controller available: %d", this, TRBType(command), (int)_numInterrupts, (int)_numPrimaryInterrupts, (int)_numInactiveInterrupts, (int)_numUnavailableInterrupts, (int)_controllerAvailable);
kr = EnqueCMD(t, command, callBackF, &ret);
if (kr != kIOReturnSuccess)
{
USBLog(1, "AppleUSBXHCI[%p]::WaitForCMD (%s) - Command Ring full or stopped %x", this, TRBType(command), kr);
USBTrace(kUSBTXHCI, kTPXHCIWaitForCmd, (uintptr_t)this, (uintptr_t) kr, 0, 1);
return retval;
}
while ( *ret == CMD_NOT_COMPLETED )
{
if ( count++ > timeout )
{
break;
}
for(innercount = 0; innercount < 1000; innercount++)
{
IODelay(1); PollForCMDCompletions(kPrimaryInterrupter);
if(*ret != CMD_NOT_COMPLETED)
{
break;
}
}
#if 0
else if ( getWorkLoop()->inGate() )
{
AbsoluteTime deadline;
clock_interval_to_deadline(1, NSEC_PER_MS, &deadline);
kr = GetCommandGate()->commandSleep(&ret, deadline, THREAD_ABORTSAFE);
if ( !_workLoop->inGate() )
{
USBLog(1, "AppleUSBXHCI[%p]::WaitForCMD - No longer have the gate after sleeping. kr == %p", this, (void*)kr );
}
else if( (kr != THREAD_TIMED_OUT) && (kr != THREAD_AWAKENED) )
{
USBLog(5, "AppleUSBXHCI[%p]::WaitForCMD - unexpected return from commandSleep: %p", this, (void*)kr);
}
}
else
{
USBLog(1, "AppleUSBXHCI[%p]::WaitForCMD - called outside the gate", this );
IOSleep(1);
}
#endif
}
if(count > 1)
{
if ( count > timeout )
{
USBLog(1, "AppleUSBXHCI[%p]::WaitForCMD (%s) - Command not completed in %dms", this, TRBType(command), (int)count);
USBTrace(kUSBTXHCI, kTPXHCIWaitForCmd, (uintptr_t)this, (uintptr_t) count, 0, 2);
}
else
{
USBLog(6, "AppleUSBXHCI[%p]::WaitForCMD (%s) - polled completed in %d.%dms", this, TRBType(command), (int)(count-1), (int)(innercount*1));
USBTrace(kUSBTXHCI, kTPXHCIWaitForCmd, (uintptr_t)this, (uintptr_t) count-1, innercount, 3);
}
}
else
{
USBLog(7, "AppleUSBXHCI[%p]::WaitForCMD (%s) - polled completed in %dus", this, TRBType(command), (int)(innercount*1));
USBTrace(kUSBTXHCI, kTPXHCIWaitForCmd, (uintptr_t)this, (uintptr_t) innercount, 0, 4);
}
if ( (*ret == CMD_NOT_COMPLETED) || (*ret <= MakeXHCIErrCode(0)) )
{
if(*ret == CMD_NOT_COMPLETED)
{
Write64Reg(&_pXHCIRegisters->CRCR, kXHCI_CA, false); _waitForCommandRingStoppedEvent = true;
for (count = 0; ((count < 5000) && (_waitForCommandRingStoppedEvent)); count++)
{
IODelay(1000); PollForCMDCompletions(kPrimaryInterrupter);
}
if(_waitForCommandRingStoppedEvent)
{
USBLog(1, "AppleUSBXHCI[%p]::WaitForCMD (%s) - abort, command ring did not stop, count = %d.%d, ret: %d", this, TRBType(command), (int)count, (int)(innercount*1), (int)*ret);
USBTrace(kUSBTXHCI, kTPXHCIWaitForCmd, (uintptr_t)this, (uintptr_t) count, innercount, 5);
}
else
{
USBLog(2, "AppleUSBXHCI[%p]::WaitForCMD (%s) - abort command ring stop, count = %d.%d, ret: %d", this, TRBType(command), (int)count, (int)(innercount*1), (int)*ret);
USBTrace(kUSBTXHCI, kTPXHCIWaitForCmd, (uintptr_t)this, (uintptr_t) count, innercount, 6);
}
}
if ( (*ret == CMD_NOT_COMPLETED) || (*ret <= MakeXHCIErrCode(0)) )
{
USBTrace(kUSBTXHCI, kTPXHCIWaitForCmd, (uintptr_t)this, (uintptr_t) ret, 0, 7);
USBLog(1, "AppleUSBXHCI[%p]::WaitForCMD (%s) - Command failed:%d (num interrupts: %d, num primary: %d, inactive:%d, unavailable:%d, is controller available:%d)", this, TRBType(command), (int)*ret, (int)_numInterrupts, (int)_numPrimaryInterrupts, (int)_numInactiveInterrupts, (int)_numUnavailableInterrupts, (int)_controllerAvailable);
PrintRuntimeRegs();
PrintInterrupter(1, 0, "WaitForCMD");
}
else
{
USBLog(1, "AppleUSBXHCI[%p]::WaitForCMD (%s) - Command succeeded after abort:%d", this, TRBType(command), (int)*ret);
USBTrace(kUSBTXHCI, kTPXHCIWaitForCmd, (uintptr_t)this, (uintptr_t) ret, 0, 8);
}
}
retval = *ret;
*ret = 0;
USBTrace_End(kUSBTXHCI, kTPXHCIWaitForCmd, (uintptr_t)this, (uintptr_t) t, retval, 0);
return (retval);
}
void AppleUSBXHCI::ResetEndpoint(int slotID, int EndpointID)
{
TRB t;
USBTrace_Start(kUSBTXHCI, kTPXHCIResetEndpoint, (uintptr_t)this, slotID, EndpointID, 0);
ClearTRB(&t, true);
SetTRBSlotID(&t, slotID);
SetTRBEpID(&t, EndpointID);
WaitForCMD(&t, kXHCITRB_ResetEndpoint);
USBTrace_End(kUSBTXHCI, kTPXHCIResetEndpoint, (uintptr_t)this, slotID, EndpointID, 0);
}
#if 1
void AppleUSBXHCI::ClearEndpoint(int slotID, int EndpointID)
{
UInt32 offs00;
IOReturn ret;
TRB t;
Context * inputContext;
Context * slotContext;
Context * epContext;
USBTrace_Start(kUSBTXHCI, kTPXHCIClearEndpoint, (uintptr_t)this, slotID, EndpointID, 0);
GetInputContext();
inputContext = GetInputContextByIndex(0);
inputContext->offs00 = HostToUSBLong(1 << EndpointID); inputContext->offs04 = HostToUSBLong((1 << EndpointID) | 1);
inputContext = GetInputContextByIndex(1);
slotContext = GetSlotContext(slotID);
*inputContext = *slotContext;
USBLog(3, "AppleUSBXHCI[%p]::ClearEndpoint - before slotCtx, inputctx[1]", this);
PrintContext(inputContext);
offs00 = USBToHostLong(inputContext->offs00);
offs00 &= ~kXHCISlCtx_resZ0Bit; inputContext->offs00 = HostToUSBLong(offs00);
inputContext->offs0C = 0; inputContext->offs10 = 0;
inputContext->offs14 = 0;
inputContext->offs18 = 0;
inputContext->offs1C = 0;
inputContext = GetInputContextByIndex(EndpointID+1);
epContext = GetEndpointContext(slotID, EndpointID);
*inputContext = *epContext;
inputContext->offs14 = 0;
inputContext->offs18 = 0;
inputContext->offs1C = 0;
PrintContext(inputContext);
ClearTRB(&t, true);
SetTRBAddr64(&t, _inputContextPhys);
SetTRBSlotID(&t, slotID);
PrintTRB(6, &t, "ClearEndpoint");
ret = WaitForCMD(&t, kXHCITRB_ConfigureEndpoint);
ReleaseInputContext();
if((ret == CMD_NOT_COMPLETED) || (ret <= MakeXHCIErrCode(0)))
{
USBLog(1, "AppleUSBXHCI[%p]::ClearEndpoint - configure endpoint failed:%d", this, (int)ret);
if( (ret == MakeXHCIErrCode(kXHCITRB_CC_CtxParamErr)) | (ret == MakeXHCIErrCode(kXHCITRB_CC_TRBErr)) ) {
USBLog(1, "AppleUSBXHCI[%p]::ClearEndpoint - Input Context 0", this);
PrintContext(GetInputContextByIndex(0));
USBLog(1, "AppleUSBXHCI[%p]::ClearEndpoint - Input Context 1", this);
PrintContext(GetInputContextByIndex(1));
USBLog(1, "AppleUSBXHCI[%p]::ClearEndpoint - Input Context X", this);
PrintContext(GetInputContextByIndex(EndpointID+1));
}
return;
}
USBLog(3, "AppleUSBXHCI[%p]::ClearEndpoint - enabling endpoint succeeded", this);
USBTrace_End(kUSBTXHCI, kTPXHCIClearEndpoint, (uintptr_t)this, slotID, EndpointID, 0);
return;
}
#endif
int
AppleUSBXHCI::StartEndpoint(int slotID, int EndpointID, UInt16 streamID)
{
USBTrace_Start(kUSBTXHCI, kTPXHCIStartEndpoint, (uintptr_t)this, slotID, EndpointID, streamID);
IOSync();
Write32Reg(&_pXHCIDoorbells[slotID], (EndpointID + (streamID << kXHCIDB_Stream_Shift) ));
IOSync();
USBTrace_End(kUSBTXHCI, kTPXHCIStartEndpoint, (uintptr_t)this, slotID, EndpointID, streamID);
return (0);
}
bool AppleUSBXHCI::IsStreamsEndpoint(int slotID, int EndpointID)
{
return(_slots[slotID].potentialStreams[EndpointID] > 1);
}
void
AppleUSBXHCI::ClearStopTDs(int slotID, int EndpointID)
{
XHCIRing *ring;
if(IsStreamsEndpoint(slotID, EndpointID))
{
for(int i = 1; i<(int)_slots[slotID].maxStream[EndpointID]; i++)
{
ring = GetRing(slotID, EndpointID, i);
if(ring == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::ClearStopTDs - ring does not exist (slot:%d, ep:%d, stream:%d) ", this, (int)slotID, (int)EndpointID, i);
}
else
{
ClearTRB(&ring->stopTRB, false);
}
}
}
else
{
ring = GetRing(slotID, EndpointID, 0);
if(ring == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::ClearStopTDs - ring does not exist (slot:%d, ep:%d) ", this, (int)slotID, (int)EndpointID);
}
else
{
ClearTRB(&ring->stopTRB, false);
}
}
}
int
AppleUSBXHCI::StopEndpoint(int slotID, int EndpointID)
{
TRB t;
UInt32 completionCode, shortfall, streams;
bool ED;
XHCIRing *ring;
SInt32 ret;
USBTrace_Start(kUSBTXHCI, kTPXHCIStopEndpoint, (uintptr_t)this, slotID, EndpointID, 0);
ring = GetRing(slotID, EndpointID, 0);
USBTrace(kUSBTXHCI, kTPXHCIStopEndpoint, (uintptr_t)this, ring ? ring->transferRingPhys : 0, 0, 0);
ClearStopTDs(slotID, EndpointID);
ClearTRB(&t, true);
SetTRBSlotID(&t, slotID);
SetTRBEpID(&t, EndpointID);
ret = WaitForCMD(&t, kXHCITRB_StopEndpoint);
if ((_errataBits & kXHCIErrataPPT) != 0)
{
if(ret == kXHCITRB_CC_NOSTOP)
{
USBLog(1, "AppleUSBXHCI[%p]::StopEndpoint - Stop endpoint failed with no stop (slot:%d, ep:%d) device needs to be reset", this, (int)slotID, (int)EndpointID);
_slots[slotID].deviceNeedsReset = true;
}
}
USBTrace_End(kUSBTXHCI, kTPXHCIStopEndpoint, (uintptr_t)this, slotID, EndpointID, 0);
return(0);
}
IOReturn AppleUSBXHCI::ReturnAllTransfersAndReinitRing(int slotID, int EndpointID, UInt32 streamID)
{
int index, type;
UInt32 shortfall = 0;
UInt32 enqCycleState;
IOUSBCompletion completion;
XHCIRing *ring;
int enqueIndex;
UInt32 completionCode;
USBPhysicalAddress64 phys, stopPhys;
bool stopTRBFound= false;
USBTrace_Start(kUSBTXHCI, kTPXHCIReturnAllTransfers, (uintptr_t)this, slotID, EndpointID, streamID);
ring = GetRing(slotID, EndpointID, streamID);
if(ring == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::ReturnAllTransfersAndReinitRing - ring does not exist (slot:%d, ep:%d, stream:%d) ", this, (int)slotID, (int)EndpointID, (int)streamID);
USBTrace(kUSBTXHCI, kTPXHCIReturnAllTransfers, (uintptr_t)this, 0, 0, 0);
USBTrace_End(kUSBTXHCI, kTPXHCIReturnAllTransfers, (uintptr_t)this, slotID, EndpointID, streamID);
return(kIOReturnBadArgument);
}
if(ring->TRBBuffer == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::ReturnAllTransfersAndReinitRing - ******** NULL TRBBuffer (slot:%d, ep:%d, stream:%d) ", this, slotID, EndpointID, (int)streamID);
USBTrace(kUSBTXHCI, kTPXHCIReturnAllTransfers, (uintptr_t)this, 0, 0, 1);
USBTrace_End(kUSBTXHCI, kTPXHCIReturnAllTransfers, (uintptr_t)this, slotID, EndpointID, streamID);
return(kIOReturnBadArgument);
}
if(ring->transferRing == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::ReturnAllTransfersAndReinitRing - ******** NULL transfer ring (slot:%d, ep:%d, stream:%d) ", this, slotID, EndpointID, (int)streamID);
USBTrace(kUSBTXHCI, kTPXHCIReturnAllTransfers, (uintptr_t)this, 0, 0, 2);
USBTrace_End(kUSBTXHCI, kTPXHCIReturnAllTransfers, (uintptr_t)this, slotID, EndpointID, streamID);
return(kIOReturnNoMemory);
}
if (IsIsocEP(slotID, EndpointID))
{
USBTrace(kUSBTXHCI, kTPXHCIReturnAllTransfers, (uintptr_t)this, 0, 0, 3);
AppleXHCIIsochEndpoint *pEP = (AppleXHCIIsochEndpoint*)ring->pEndpoint;
if (pEP)
{
#define kMaxWaitForRingToStop 120
int retries = kMaxWaitForRingToStop;
while (retries-- && (pEP->ringRunning == true))
{
IOSleep(1);
}
if (pEP->ringRunning)
{
USBLog(1, "AppleUSBXHCI[%p]::ReturnAllTransfersAndReinitRing - Isoch ring for EP(%p) never stopped!", this, pEP);
pEP->ringRunning = false;
}
else if (retries < (kMaxWaitForRingToStop-10))
{
USBLog(1, "AppleUSBXHCI[%p]::ReturnAllTransfersAndReinitRing - Isoch ring for EP(%p) took %d ms to stop running!", this, pEP, kMaxWaitForRingToStop-retries);
}
USBTrace(kUSBTXHCI, kTPXHCIReturnAllTransfers, (uintptr_t)this, ring->transferRingPhys, kMaxWaitForRingToStop-retries, 4);
AbortIsochEP(pEP);
}
else
{
USBLog(1, "AppleUSBXHCI[%p]::ReturnAllTransfersAndReinitRing - ******** Isoc transfer ring with no isocEP (slot:%d, ep:%d, stream:%d) ", this, slotID, EndpointID, (int)streamID);
}
USBTrace_End(kUSBTXHCI, kTPXHCIReturnAllTransfers, (uintptr_t)this, slotID, EndpointID, streamID);
return kIOReturnSuccess;
}
else
{
index = ring->transferRingDequeueIdx;
if(index == ring->transferRingEnqueueIdx)
{
USBLog(6, "AppleUSBXHCI[%p]::ReturnAllTransfersAndReinitRing - Empty ep:%d (slot:%d, ep:%d, stream:%d) ", this, index, slotID, EndpointID, (int)streamID);
return (ReinitTransferRing(slotID, EndpointID, streamID));
}
AppleXHCIAsyncEndpoint *pAsyncEP = OSDynamicCast(AppleXHCIAsyncEndpoint, (AppleXHCIAsyncEndpoint*)ring->pEndpoint);
USBLog(2, "AppleUSBXHCI[%p]::ReturnAllTransfers - (slot:%d, ep:%d, stream:%d) ", this, ring->slotID, ring->endpointID, (int)streamID);
if (pAsyncEP)
{
pAsyncEP->Abort();
}
else
{
USBLog(1, "AppleUSBXHCI[%p]::ReturnAllTransfersAndReinitRing - ******** Async transfer ring with no asyncEP (slot:%d, ep:%d, stream:%d) ", this, slotID, EndpointID, (int)streamID);
}
}
USBTrace_End(kUSBTXHCI, kTPXHCIReturnAllTransfers, (uintptr_t)this, slotID, EndpointID, streamID);
return (ReinitTransferRing(slotID, EndpointID, streamID));
}
IOReturn
AppleUSBXHCI::ReinitTransferRing(int slotID, int EndpointID, UInt32 streamID)
{
XHCIRing * ring;
TRB t;
SInt32 err;
USBTrace_Start(kUSBTXHCI, kTPXHCIReInitTransferRing, (uintptr_t)this, slotID, EndpointID, streamID);
USBLog(6, "AppleUSBXHCI[%p]::ReinitTransferRing - Slot:%d, ep:%d, stream:%d ", this, slotID, EndpointID, (int)streamID);
ring = GetRing(slotID, EndpointID, streamID);
if(ring == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::ReinitTransferRing - ring does not exist (slot:%d, ep:%d, stream:%d) ", this, (int)slotID, (int)EndpointID, (int)streamID);
return(kIOReturnBadArgument);
}
PrintContext(GetEndpointContext(slotID,EndpointID));
if(ring->TRBBuffer == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::ReinitTransferRing - ******** NULL ring (slot:%d, ep:%d, stream:%d) ", this, slotID, EndpointID, (int)streamID);
return(kIOReturnNoMemory);
}
if( (ring->transferRing == NULL) || (ring->transferRingSize < 2) )
{
USBLog(1, "AppleUSBXHCI[%p]::ReinitTransferRing - Invalid transfer ring %p, %d", this, ring->transferRing, ring->transferRingSize);
return(kIOReturnNoMemory);
}
ClearTRB(&t, true);
SetTRBSlotID(&t, slotID);
SetTRBEpID(&t, EndpointID);
if(ring->transferRingEnqueueIdx == ring->transferRingDequeueIdx)
{
bzero(ring->transferRing, (ring->transferRingSize - 1) * sizeof(TRB));
ring->transferRing[ring->transferRingSize-1].offsC |= HostToUSBLong(kXHCITRB_TC);
ring->transferRingPCS = 1;
ring->transferRingEnqueueIdx = 0;
ring->transferRingDequeueIdx = 0;
}
else
{
USBLog(2, "AppleUSBXHCI[%p]::ReinitTransferRing - Ring not empty, setting deque:%d, DCS:%d", this, ring->transferRingDequeueIdx, (int)ring->transferRingPCS);
}
err = SetTRDQPtr(slotID, EndpointID, streamID, ring->transferRingDequeueIdx);
if(ring->needsDoorbell)
{
if (!IsIsocEP(slotID, EndpointID))
{
AppleXHCIAsyncEndpoint *pAsyncEP = OSDynamicCast(AppleXHCIAsyncEndpoint, (AppleXHCIAsyncEndpoint*)ring->pEndpoint);
if (pAsyncEP)
{
pAsyncEP->ScheduleTDs();
}
}
USBLog(2, "AppleUSBXHCI[%p]::ReinitTransferRing - Ringing doorbell(s) (@%d,%d)", this, slotID, EndpointID);
if(IsStreamsEndpoint(slotID, EndpointID))
{
RestartStreams(slotID, EndpointID, 0);
}
else
{
StartEndpoint(slotID, EndpointID);
}
ring->needsDoorbell = false;
}
USBTrace_End(kUSBTXHCI, kTPXHCIReInitTransferRing, (uintptr_t)this, slotID, EndpointID, streamID);
return (MungeCommandCompletion(err));
}
int AppleUSBXHCI::SetTRDQPtr(int slotID, int EndpointID, UInt32 stream, int dQindex)
{
TRB t;
SInt32 err;
XHCIRing *ring;
Context *epCtx;
int epState;
ring = GetRing(slotID, EndpointID, stream);
if(ring == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::SetTRDQPtr - ring does not exist (slot:%d, ep:%d) ", this, (int)slotID, (int)EndpointID);
return MakeXHCIErrCode(kXHCITRB_CC_NULLRing);
}
epCtx = GetEndpointContext(slotID, EndpointID);
epState = GetEpCtxEpState(epCtx);
if(epState != kXHCIEpCtx_State_Stopped)
{
if(IsStreamsEndpoint(slotID, EndpointID))
{
if(ring->transferRingDequeueIdx != ring->transferRingEnqueueIdx)
{
USBLog(6, "AppleUSBXHCI[%p]::SetTRDQPtr - called while streams endpoint was not stopped (slot:%d, ep:%d,stream:%d epstate:%d) ", this, (int)slotID, (int)EndpointID, (int)stream, epState);
return MakeXHCIErrCode(kXHCITRB_CC_CtxStateErr);
}
}
else
{
USBLog(1, "AppleUSBXHCI[%p]::SetTRDQPtr - called while endpoint was not stopped (slot:%d, ep:%d, epstate:%d) ", this, (int)slotID, (int)EndpointID, epState);
return MakeXHCIErrCode(kXHCITRB_CC_CtxStateErr);
}
}
ClearTRB(&t, true);
SetTRBSlotID(&t, slotID);
SetTRBEpID(&t, EndpointID);
if(stream == 0)
{
SetTRBAddr64(&t, ring->transferRingPhys+dQindex*sizeof(TRB));
SetTRBDCS(&t, ring->transferRingPCS);
}
else
{
SetStreamCtxAddr64((StreamContext *)&t, ring->transferRingPhys+dQindex*sizeof(TRB), kXHCI_SCT_PrimaryTRB, ring->transferRingPCS);
SetTRBStreamID(&t, stream);
}
err = WaitForCMD(&t, kXHCITRB_SetTRDqPtr);
PrintTRB(7, &t, "SetTRDQPtr CMD");
if((err == CMD_NOT_COMPLETED) || (err <= MakeXHCIErrCode(0)))
{
#if 0
if(err == MakeXHCIErrCode(kXHCITRB_CC_CtxStateErr)) {
USBLog(2, "AppleUSBXHCI[%p]::SetTRDQPtr - slot context error, qiescing endpoint and trying again", this);
(void)QuiesceEndpoint(slotID, EndpointID);
err = WaitForCMD(&t, kXHCITRB_SetTRDqPtr);
PrintContext(GetSlotContext(slotID));
}
if((err == CMD_NOT_COMPLETED) || (err <= MakeXHCIErrCode(0)))
{
PrintTRB(1, &t, "SetTRDQPtr");
if(err == MakeXHCIErrCode(kXHCITRB_CC_CtxStateErr)) {
USBLog(1, "AppleUSBXHCI[%p]::SetTRDQPtr - slot context error again", this);
PrintContext(GetSlotContext(slotID));
}
PrintContext(GetEndpointContext(slotID, EndpointID));
}
#endif
USBLog(1, "AppleUSBXHCI[%p]::SetTRDQPtr - slot context error", this);
PrintContext(GetSlotContext(slotID));
PrintContext(GetEndpointContext(slotID, EndpointID));
}
else
{
ring->transferRingDequeueIdx = dQindex;
}
return(err);
}
bool AppleUSBXHCI::FilterEventRing(int IRQ, bool *needsSignal)
{
TRB nextEvent;
int type, index;
void * p;
volatile UInt32 offsC;
bool copyEvent = true;
USBTrace_Start(kUSBTXHCIInterrupts, kTPXHCIFilterEventRing, (uintptr_t)this, IRQ, 0, 0);
offsC = _events[IRQ].EventRing[_events[IRQ].EventRingDequeueIdx].offsC;
if( (USBToHostLong(offsC) & kXHCITRB_C) == _events[IRQ].EventRingCCS)
{ int enque2Idx;
nextEvent.offsC = offsC;
nextEvent.offs8 = _events[IRQ].EventRing[_events[IRQ].EventRingDequeueIdx].offs8;
nextEvent.offs4 = _events[IRQ].EventRing[_events[IRQ].EventRingDequeueIdx].offs4;
nextEvent.offs0 = _events[IRQ].EventRing[_events[IRQ].EventRingDequeueIdx].offs0;
ClearTRB(&_events[IRQ].EventRing[_events[IRQ].EventRingDequeueIdx], false);
_events[IRQ].EventRingDequeueIdx++;
if(_events[IRQ].EventRingDequeueIdx >= _events[IRQ].numEvents)
{
_events[IRQ].EventRingDequeueIdx = 0;
_events[IRQ].EventRingCCS = 1 - _events[IRQ].EventRingCCS;
}
_events[IRQ].EventRingDPNeedsUpdate = true;
type = GetTRBType(&nextEvent);
if(type == kXHCITRB_TE)
{
UInt32 slotID, EndpointID;
slotID = GetTRBSlotID(&nextEvent);
if(GetSlotContext(slotID) != NULL) {
EndpointID = (USBToHostLong(nextEvent.offsC) & kXHCITRB_Ep_Mask) >> kXHCITRB_Ep_Shift;
if (IsIsocEP(slotID, EndpointID))
{
XHCIRing * ring = GetRing(slotID, EndpointID, 0);
if( (ring == NULL) || (ring->TRBBuffer == NULL) )
{
OSIncrementAtomic(&_IsocProblem);
}
else
{
AppleXHCIIsochEndpoint * pEP = (AppleXHCIIsochEndpoint*)ring->pEndpoint;
if (pEP && pEP->ringRunning)
{
UInt8 condCode = ((USBToHostLong(nextEvent.offs8) & kXHCITRB_CC_Mask) >> kXHCITRB_CC_Shift);
PrintEventTRB(&nextEvent, IRQ, true, ring);
if ((condCode == kXHCITRB_CC_Success) || (condCode == kXHCITRB_CC_ShortPacket) || (condCode == kXHCITRB_CC_XActErr))
{
if (pEP->outSlot < kNumTDSlots)
{
AppleXHCIIsochTransferDescriptor * cachedHead;
UInt32 cachedProducer;
UInt32 frIndex;
UInt16 testSlot, nextSlot, stopSlot;
UInt16 curMicroFrame;
uint64_t timeStamp;
stopSlot = pEP->inSlot & (kNumTDSlots-1);
cachedHead = (AppleXHCIIsochTransferDescriptor*)pEP->savedDoneQueueHead;
cachedProducer = pEP->producerCount;
testSlot = pEP->outSlot;
timeStamp = mach_absolute_time();
while (testSlot != stopSlot)
{
AppleXHCIIsochTransferDescriptor *pTD = NULL;
nextSlot = (testSlot+1) & (kNumTDSlots-1);
pTD = pEP->tdSlots[testSlot];
if (pTD != NULL)
{
if (pEP->ringRunning)
{
int frameinTDForEvent;
bool eventIsForThisTD = false;
UInt64 phys = ((UInt64)USBToHostLong(nextEvent.offs0) & ~0xf) + (((UInt64)USBToHostLong(nextEvent.offs4)) << 32);
int eventIndex = DiffTRBIndex(phys, ring->transferRingPhys);
int indexIntoTD = -1;
if ((eventIndex >= 0) && (eventIndex < ring->transferRingSize))
{
indexIntoTD = pTD->FrameForEventIndex(eventIndex);
if (indexIntoTD >= 0)
eventIsForThisTD = true;
}
pTD->eventTRB = nextEvent;
pTD->UpdateFrameList(*(AbsoluteTime*)&timeStamp);
if (!eventIsForThisTD || ((indexIntoTD == (pTD->_framesInTD-1))))
{
USBLogKP(7, "AppleUSBXHCI[%p]FilterEventRing pEP(%p) removing pTD(%p) from slot (%d)", this, pEP, pTD, testSlot);
pEP->tdSlots[testSlot] = NULL;
pTD->_doneQueueLink = cachedHead;
cachedHead = pTD;
cachedProducer++;
OSIncrementAtomic( &(pEP->onProducerQ));
OSDecrementAtomic( &(pEP->scheduledTDs));
pEP->outSlot = testSlot;
USBTrace( kUSBTXHCIInterrupts, kTPXHCIFilterEventRing, (uintptr_t)this, (uintptr_t)pEP, pEP->outSlot, 3 );
}
else
{
copyEvent = false;
}
if (eventIsForThisTD)
{
break; }
}
}
else
{
}
testSlot = nextSlot;
}
IOSimpleLockLock( pEP->wdhLock );
pEP->savedDoneQueueHead = cachedHead; pEP->producerCount = cachedProducer;
IOSimpleLockUnlock( pEP->wdhLock );
}
}
else if ((condCode == kXHCITRB_CC_Stopped) || (condCode == kXHCITRB_CC_Stopped_Length_Invalid) || (condCode == kXHCITRB_CC_RingOverrun) || (condCode == kXHCITRB_CC_RingUnderrun) || (condCode == kXHCITRB_CC_Missed_Service))
{
USBLogKP(2, "AppleUSBXHCI[%p]::FilterEventRing Isoc pEP(%p) stopping ring because of condCode(%d)", this, pEP, condCode);
USBTrace( kUSBTXHCIInterrupts, kTPXHCIFilterEventRing, (uintptr_t)this, (uintptr_t)pEP, condCode, 4 );
pEP->ringRunning = false; }
else
{
USBLogKP(2, "AppleUSBXHCI[%p]::FilterEventRing Isoc pEP(%p) ignoring condCode(%d)", this, pEP, condCode);
USBTrace( kUSBTXHCIInterrupts, kTPXHCIFilterEventRing, (uintptr_t)this, (uintptr_t)pEP, condCode, 5 );
}
}
else
{
USBLogKP(6, "AppleUSBXHCI[%p]FilterEventRing Isoch pEP(%p) RING NOT RUNNING", this, pEP);
USBTrace( kUSBTXHCIInterrupts, kTPXHCIFilterEventRing, (uintptr_t)this, (uintptr_t)pEP, 0, 6 );
}
}
}
}
}
else if(type == kXHCITRB_MFWE)
{ uint64_t tempTime;
UInt32 frindex;
_frameNumber64 += kXHCIFrameNumberIncrement;
PrintEventTRB(&nextEvent, IRQ, true);
frindex = Read32Reg(&_pXHCIRuntimeReg->MFINDEX);
if (_lostRegisterAccess)
{
return false;
}
USBTrace( kUSBTXHCIInterrupts, kTPXHCIFilterEventRing, (uintptr_t)this, (int)_frameNumber64, frindex, 1 );
_tempAnchorFrame = _frameNumber64 + (frindex >> 3);
tempTime = mach_absolute_time();
_tempAnchorTime = *(AbsoluteTime*)&tempTime;
}
else
{
PrintEventTRB(&nextEvent, IRQ, true);
}
if(needsSignal != NULL)
{
*needsSignal = true;
}
if (copyEvent)
{
enque2Idx = _events[IRQ].EventRing2EnqueueIdx + 1;
if(enque2Idx >= _events[IRQ].numEvents2)
{
enque2Idx = 0;
}
if(enque2Idx == _events[IRQ].EventRing2DequeueIdx)
{
OSIncrementAtomic(&_events[IRQ].EventRing2Overflows);
}
else
{
_events[IRQ].EventRing2[_events[IRQ].EventRing2EnqueueIdx] = nextEvent;
_events[IRQ].EventRing2EnqueueIdx = enque2Idx;
USBTrace_End(kUSBTXHCIInterrupts, kTPXHCIFilterEventRing, (uintptr_t)this, 1, 1, 0);
return (true);
}
}
else {
USBTrace_End(kUSBTXHCIInterrupts, kTPXHCIFilterEventRing, (uintptr_t)this, 1, 0, 0);
return(true);
}
}
if((_events[IRQ].EventRingDPNeedsUpdate) || ((Read64Reg(&_pXHCIRuntimeReg->IR[IRQ].ERDP) & kXHCIIRQ_EHB) != 0))
{
USBPhysicalAddress64 phys;
if( (_errataBits & kXHCIErrata_NoMSI) != 0)
{ Write32Reg(&_pXHCIRuntimeReg->IR[IRQ].IMAN, Read32Reg(&_pXHCIRuntimeReg->IR[IRQ].IMAN));
if (_lostRegisterAccess)
{
return false;
}
}
phys = _events[IRQ].EventRingPhys;
phys += _events[IRQ].EventRingDequeueIdx * sizeof(TRB);
phys |= kXHCIIRQ_EHB;
Write64Reg(&_pXHCIRuntimeReg->IR[IRQ].ERDP, phys, true);
USBTrace( kUSBTXHCIInterrupts, kTPXHCIFilterEventRing, (uintptr_t)this, 0, 0, 2 );
_events[IRQ].EventRingDPNeedsUpdate = false;
}
USBTrace_End(kUSBTXHCIInterrupts, kTPXHCIFilterEventRing, (uintptr_t)this, 0, 0, 0);
return (false);
}
void AppleUSBXHCI::DoStopCompletion(TRB *nextEvent)
{
USBPhysicalAddress64 phys;
XHCIRing *ring;
int index;
UInt32 slotID, EndpointID;
slotID = GetTRBSlotID(nextEvent);
EndpointID = (USBToHostLong(nextEvent->offsC) & kXHCITRB_Ep_Mask) >> kXHCITRB_Ep_Shift;
if(IsStreamsEndpoint(slotID, EndpointID))
{
phys = ((UInt64)USBToHostLong(nextEvent->offs0)) + (((UInt64)USBToHostLong(nextEvent->offs4)) << 32);
if(phys == 0)
{
USBLog(2, "AppleUSBXHCI[%p]::DoStopCompletion - Null phys pointer @%d, %d", this, (int)slotID, (int)EndpointID);
return; }
else
{
ring = FindStream(slotID, EndpointID, phys, &index, true);
if(ring == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::DoStopCompletion - Stream not found @%d, %d, phys:%p", this, (int)slotID, (int)EndpointID, (void *)phys);
(void) FindStream(slotID, EndpointID, phys, &index, false);
PrintTRB(1, nextEvent, "DoStopCompletion Stream not found");
return; }
}
}
else
{
ring = GetRing(slotID, EndpointID, 0);
}
if(ring)
{
ring->stopTRB = *nextEvent;
}
else
{
USBLog(1, "AppleUSBXHCI[%p]::DoStopCompletion - Found a stopped transfer TRB, but endpoint is invalid EP @%d, %d", this, (int)slotID, (int)EndpointID);
PrintTRB(6, nextEvent, "DoStopCompletion invalid stop");
}
}
bool AppleUSBXHCI::DoCMDCompletion(TRB nextEvent, UInt16 eventIndex)
{
USBPhysicalAddress64 phys;
CMDComplete c;
int index;
UInt32 completionCode = GetTRBCC(&nextEvent);
phys = (USBToHostLong(nextEvent.offs0) & ~0xf) + (((UInt64)USBToHostLong(nextEvent.offs4)) << 32);
index = DiffTRBIndex(phys, _CMDRingPhys);
if( (index < 0) || (index > (_numCMDs-2)) )
{
if(phys == 0)
{
USBError(1, "AppleUSBXHCI[%p]::DoCMDCompletion - Zero pointer in CCE", this);
}
USBError(1, "AppleUSBXHCI[%p]::DoCMDCompletion - bad pointer in CCE: %d", this, (int)index);
PrintTRB(1, &nextEvent, "DoCMDCompletion CCE bad pointer");
}
else
{
if (completionCode == kXHCITRB_CC_CMDRingStopped)
{
if(_waitForCommandRingStoppedEvent)
{
USBLog(1, "AppleUSBXHCI[%p]::DoCMDCompletion command ring stopped", this);
_waitForCommandRingStoppedEvent = false;
}
_CMDRingDequeueIdx = index;
}
else
{
_CMDRingDequeueIdx = 1+index;
if(_CMDRingDequeueIdx >= (_numCMDs-1))
{
_CMDRingDequeueIdx = 0;
}
c = _CMDCompletions[index].completionAction;
_CMDCompletions[index].completionAction = NULL;
if(c != 0)
{
(*c)(this, &nextEvent, &_CMDCompletions[index].parameter);
}
else
{
USBLog(2, "AppleUSBXHCI[%p]::DoCMDCompletion - Null completion, assume its been polled: %d (%d)", this, eventIndex, index);
}
}
return(true);
}
return(false);
}
void AppleUSBXHCI::PollForCMDCompletions(int IRQ)
{
UInt16 dqIndex;
int type;
dqIndex = _events[IRQ].EventRing2DequeueIdx;
while ((dqIndex != _events[IRQ].EventRing2EnqueueIdx) && (!_lostRegisterAccess))
{ TRB nextEvent;
int newDQIdx;
nextEvent = _events[IRQ].EventRing2[dqIndex];
type = GetTRBType(&nextEvent);
if( (type == kXHCITRB_CCE) || ( (type == kXHCITRB_NECCCE) && ( (_errataBits & kXHCIErrata_NEC) != 0) ) )
{
ClearTRB(&_events[IRQ].EventRing2[dqIndex], false);
USBLog(7, "AppleUSBXHCI[%p]::PollForCMDCompletions - Completing: %d", this, dqIndex);
USBTrace( kUSBTXHCI, kTPXHCIPollForCMDCompletion, (uintptr_t)this, 0, 0, 1);
PrintEventTRB(&nextEvent, IRQ, false);
DoCMDCompletion(nextEvent, dqIndex);
}
else if(type == kXHCITRB_TE)
{
UInt32 completionCode;
completionCode = GetTRBCC(&nextEvent);
if( (completionCode == kXHCITRB_CC_Stopped) || (completionCode == kXHCITRB_CC_Stopped_Length_Invalid) )
{
ClearTRB(&_events[IRQ].EventRing2[dqIndex], false);
USBLog(7, "AppleUSBXHCI[%p]::PollForCMDCompletions - Completing stop event: %d", this, dqIndex);
PrintTRB(7, &nextEvent, "PollForCMDCompletions Stop Event");
USBTrace( kUSBTXHCI, kTPXHCIPollForCMDCompletion, (uintptr_t)this, 0, 0, 2);
PrintEventTRB(&nextEvent, IRQ, false);
DoStopCompletion(&nextEvent);
}
}
newDQIdx = dqIndex+1;
if(newDQIdx >= _events[IRQ].numEvents2)
{
newDQIdx = 0;
}
dqIndex = newDQIdx;
}
}
bool AppleUSBXHCI::PollEventRing2(int IRQ)
{
#pragma unused(IRQ)
int type, index;
bool isocProb = false;
void * p;
AppleXHCIIsochEndpoint * pEP = (AppleXHCIIsochEndpoint*)_isochEPList;
USBTrace_Start( kUSBTXHCI, kTPXHCIPollEventRing2, (uintptr_t)this, 0, 0, 0 );
if((Read32Reg(&_pXHCIRegisters->USBSTS)& kXHCIHSEBit) != 0)
{
if(!_HSEReported)
{
USBError(1, "AppleUSBXHCI[%p]::PollEventRing2 - HSE bit set:%x (1)", this, Read32Reg(&_pXHCIRegisters->USBSTS));
}
_HSEReported = true;
}
if(_events[IRQ].EventRing2Overflows > 0)
{
SInt32 overflows;
overflows = _events[IRQ].EventRing2Overflows;
USBError(1, "AppleUSBXHCI[%p]::PollEventRing2 - Secondary event queue %d overflowed: %d", this, IRQ, (int)overflows);
OSAddAtomic(-overflows, &_events[IRQ].EventRing2Overflows);
}
if(_DebugFlag > 0)
{
SInt32 flags;
flags = _DebugFlag;
USBError(1, "AppleUSBXHCI[%p]::PollEventRing2 - DebugFlags: %d", this, (int)flags);
OSAddAtomic(-flags, &_DebugFlag);
}
#if 0
if(_CCEPhysZero > 0)
{
SInt32 zeros;
zeros = _CCEPhysZero;
USBError(1, "AppleUSBXHCI[%p]::PollEventRing2 - Zero pointer in CCE: %d", this, (int)zeros);
OSAddAtomic(-zeros, &_CCEPhysZero);
}
if(_CCEBadIndex > 0)
{
SInt32 badindexes;
badindexes = _CCEBadIndex;
USBError(1, "AppleUSBXHCI[%p]::PollEventRing2 - bad pointer in CCE: %d", this, (int)badindexes);
OSAddAtomic(-badindexes, &_CCEBadIndex);
}
#endif
if(_EventChanged > 0)
{
SInt32 changes;
changes = _EventChanged;
USBError(1, "AppleUSBXHCI[%p]::PollEventRing2 - Event changed after reading: %d", this, (int)changes);
OSAddAtomic(-changes, &_EventChanged);
}
if(_IsocProblem > 0)
{
SInt32 problems;
problems = _IsocProblem;
USBError(1, "AppleUSBXHCI[%p]::PollEventRing2 - Isoc problems: %d", this, (int)problems);
OSAddAtomic(-problems, &_IsocProblem);
}
while (pEP)
{
USBTrace( kUSBTXHCI, kTPXHCIPollEventRing2, (uintptr_t)pEP, 9, pEP->producerCount, pEP->consumerCount );
if (pEP->consumerCount != pEP->producerCount)
{
USBLog(7, "AppleUSBXHCI[%p]::PollEventRing2 - Scavenging Isoc Transactions for EP(%p)", this, pEP);
ScavengeIsocTransactions(pEP, true);
}
pEP = (AppleXHCIIsochEndpoint *)pEP->nextEP;
}
if(_events[IRQ].EventRing2DequeueIdx != _events[IRQ].EventRing2EnqueueIdx)
{ TRB nextEvent;
int newDQIdx, index0;
index0 = _events[IRQ].EventRing2DequeueIdx;
nextEvent = _events[IRQ].EventRing2[_events[IRQ].EventRing2DequeueIdx];
ClearTRB(&_events[IRQ].EventRing2[_events[IRQ].EventRing2DequeueIdx], false);
newDQIdx = _events[IRQ].EventRing2DequeueIdx+1;
if(newDQIdx >= _events[IRQ].numEvents2)
{
newDQIdx = 0;
}
_events[IRQ].EventRing2DequeueIdx = newDQIdx;
type = GetTRBType(&nextEvent);
if( (type == kXHCITRB_CCE) || ( (type == kXHCITRB_NECCCE) && ( (_errataBits & kXHCIErrata_NEC) != 0) ) )
{ if(DoCMDCompletion(nextEvent, index0))
{
return(true);
}
}
else if (type == kXHCITRB_TE)
{
UInt32 completionCode, shortfall, slotID, EndpointID;
USBPhysicalAddress64 phys;
XHCIRing *ring;
bool ED = false;
phys = ((UInt64)USBToHostLong(nextEvent.offs0) & ~0xf) + (((UInt64)USBToHostLong(nextEvent.offs4)) << 32);
completionCode = GetTRBCC(&nextEvent);
if( (completionCode == kXHCITRB_CC_Stopped) || (completionCode == kXHCITRB_CC_Stopped_Length_Invalid) )
{
DoStopCompletion(&nextEvent);
return(true); }
shortfall = USBToHostLong(nextEvent.offs8) & kXHCITRB_TR_Len_Mask;
slotID = GetTRBSlotID(&nextEvent);
EndpointID = (USBToHostLong(nextEvent.offsC) & kXHCITRB_Ep_Mask) >> kXHCITRB_Ep_Shift;
ED = USBToHostLong(nextEvent.offsC) & kXHCITRB_ED;
USBTrace( kUSBTXHCI, kTPXHCIPollEventRing2, (uintptr_t)this, 1, slotID, EndpointID );
USBTrace( kUSBTXHCI, kTPXHCIPollEventRing2, (uintptr_t)this, 2, (int)phys, shortfall );
if(IsStreamsEndpoint(slotID, EndpointID))
{
ring = FindStream(slotID, EndpointID, phys, &index, true);
if(ring == NULL)
{
PrintTRB(2, &nextEvent, "pollEventRing findstream not found");
ring = FindStream(slotID, EndpointID, phys, &index, false);
if(ring == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::PollEventRing2 - stream not found (slot:%d, ep:%d) ", this, (int)slotID, (int)EndpointID);
return(false);
}
USBLog(1, "AppleUSBXHCI[%p]::PollEventRing2 - stream found 2nd time around (slot:%d, ep:%d) ", this, (int)slotID, (int)EndpointID);
}
}
else
{
ring = GetRing(slotID, EndpointID, 0);
if(ring == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::PollEventRing2 - ring does not exist (slot:%d, ep:%d) ", this, (int)slotID, (int)EndpointID);
return(false);
}
if((completionCode == kXHCITRB_CC_RingUnderrun) || (completionCode == kXHCITRB_CC_RingOverrun) || (completionCode == kXHCITRB_CC_Stopped)|| (completionCode == kXHCITRB_CC_Stopped_Length_Invalid) )
{
pEP = (AppleXHCIIsochEndpoint*)ring->pEndpoint;
if (pEP)
{
if (!pEP->activeTDs)
{
pEP->outSlot = kNumTDSlots + 1;
pEP->inSlot = kNumTDSlots + 1;
}
if (pEP->waitForRingToRunDry)
{
USBLog(6, "AppleUSBXHCI[%p]::PollEventRing2 - ring has run dry, adding Isoc frames", this);
USBTrace( kUSBTXHCI, kTPXHCIPollEventRing2, (uintptr_t)this, 8, (uintptr_t)pEP, 0 );
pEP->waitForRingToRunDry = false;
if((completionCode == kXHCITRB_CC_RingUnderrun) || (completionCode == kXHCITRB_CC_RingOverrun))
AddIsocFramesToSchedule(pEP);
}
}
USBLog(3, "AppleUSBXHCI[%p]::PollEventRing2 - Ring Underrun or Overrun on EP @%d, %d", this, (int)slotID, (int)EndpointID);
return(true);
}
index = DiffTRBIndex(phys, ring->transferRingPhys);
}
PrintEventTRB(&nextEvent, IRQ, false, ring);
if(ring->TRBBuffer == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::PollEventRing2 - ******** NULL ring (slot:%d, ep:%d) ", this, (int)slotID, (int)EndpointID);
return(false);
}
if(index < 0 || index > ring->transferRingSize)
{
UInt32 dummy;
USBLog(1, "AppleUSBXHCI[%p]::PollEventRing2 - Index out of range: %d (slot:%d, endpointID:%d)", this, index, (int)slotID, (int)EndpointID);
USBLog(1, "AppleUSBXHCI[%p]::PollEventRing2 - phys: %p, ringPhys:%p", this, (void *)phys, (void *)ring->transferRingPhys);
PrintTRB(1, &nextEvent, "pollEventRing2x");
if(false && ED)
{
index = CountRingToED(ring, ring->transferRingDequeueIdx, &dummy, false);
USBLog(1, "AppleUSBXHCI[%p]::PollEventRing2 - Faking ED index: %d", this, index);
PrintTRB(1, &ring->transferRing[index], "pollEventRing2c");
}
else
{
return(true);
}
}
if (IsIsocEP(slotID, EndpointID))
{
ring->transferRingDequeueIdx = 1+index;
if(ring->transferRingDequeueIdx >= (ring->transferRingSize-1) )
{
ring->transferRingDequeueIdx = 0;
}
switch (completionCode)
{
case kXHCITRB_CC_Success:
case kXHCITRB_CC_ShortPacket:
case kXHCITRB_CC_XActErr:
break;
default:
USBLog(1, "AppleUSBXHCI[%p]::PollEventRing2 - Isoc Transfer event with completion code (%d) on pEP (%p)", this, (int)completionCode, ring->pEndpoint);
break;
}
return true;
}
else
{
UInt8 contextSpeed = GetSlCtxSpeed(GetSlotContext(slotID));
int epState = GetEpCtxEpState(GetEndpointContext(slotID, EndpointID));
AppleXHCIAsyncTransferDescriptor *pActiveATD = NULL;
AppleXHCIAsyncEndpoint *pAsyncEP = OSDynamicCast(AppleXHCIAsyncEndpoint, (AppleXHCIAsyncEndpoint*)ring->pEndpoint);
if (!pAsyncEP)
{
USBLog(5, "AppleUSBXHCI[%p]::PollEventRing2 - NULL AppleXHCIAsyncEndpoint", this);
return true;
}
pActiveATD = pAsyncEP->GetTDFromActiveQueueWithIndex(index);
if(pActiveATD == NULL)
{
USBLog(5, "AppleUSBXHCI[%p]::PollEventRing2 - NULL asyncTD @ index %d, epState: %s", this, index, EndpointState(epState));
PrintTRB(6, &nextEvent, "PollEventRing2-x1");
if(epState != kXHCIEpCtx_State_Halted)
{
USBLog(1, "AppleUSBXHCI[%p]::PollEventRing2 - NULL asyncTD, not halted (%d): Index: %d, slot:%d, endpointID:%d", this, epState, index, (int)slotID, (int)EndpointID);
return (true);
}
else
{
USBLog(1, "AppleUSBXHCI[%p]::PollEventRing2 - NULL asyncTD, endpoint halted (%d): Index: %d, slot:%d, endpointID:%d", this, epState, index, (int)slotID, (int)EndpointID);
}
index = CountRingToED(ring, index, &shortfall, true);
USBLog(2, "AppleUSBXHCI[%p]::PollEventRing2 - Transfer event advanceRingToED shortfall:%d", this, (int)shortfall);
pActiveATD = pAsyncEP->GetTDFromActiveQueueWithIndex(index);
if (pActiveATD == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::PollEventRing2 - NULL asyncTD, when advanced to ED (%d): Index: %d, slot:%d, endpointID:%d", this, epState, index, (int)slotID, (int)EndpointID);
PrintTRB(6, &nextEvent, "pollEventRing25");
return(true);
}
USBLog(2, "AppleUSBXHCI[%p]::PollEventRing2 - index advanced to: %d", this, index);
}
if (ring->transferRingEnqueueIdx != ring->transferRingDequeueIdx)
{
ring->transferRingDequeueIdx = 1+index;
if(ring->transferRingDequeueIdx >= (ring->transferRingSize-1) )
{
ring->transferRingDequeueIdx = 0;
}
}
else
{
USBLog(1, "AppleUSBXHCI[%p]::PollEventRing2 - ring is empty but got a transfer event, epState: %s Index: %d, slot:%d, endpointID:%d", this, EndpointState(epState), index, (int)slotID, (int)EndpointID);
return (true);
}
if(ED)
{
IOByteCount req = pActiveATD->transferSize;
shortfall = (UInt32)req - shortfall;
USBTrace( kUSBTXHCI, kTPXHCIPollEventRing2, (uintptr_t)this, 3, index, EndpointID );
USBTrace( kUSBTXHCI, kTPXHCIPollEventRing2, (uintptr_t)this, 4, shortfall, req );
}
bool flush = false;
bool complete = false;
IOReturn status = kIOReturnSuccess;
if(completionCode != kXHCITRB_CC_Success)
{
USBLog(7, "AppleUSBXHCI[%p]::PollEventRing2 - completing: %p, code:%d, short:%d fragments: %d", this, pActiveATD, (int)completionCode, (int)shortfall, (int)pActiveATD->fragmentedTD);
if (pActiveATD->fragmentedTD)
{
flush = true;
}
complete = true;
status = MungeXHCIStatus(completionCode, EndpointID&1, contextSpeed);
USBTrace( kUSBTXHCI, kTPXHCIPollEventRing2, (uintptr_t)this, 5, slotID, EndpointID);
USBTrace( kUSBTXHCI, kTPXHCIPollEventRing2, (uintptr_t)this, 6, completionCode, status);
}
else
{
if (pActiveATD->interruptThisTD)
{
complete = pActiveATD->interruptThisTD;
}
}
CheckBuf(c);
pActiveATD->shortfall = shortfall;
if(_slots[slotID].deviceNeedsReset)
{
status = kIOReturnNotResponding;
}
pAsyncEP->ScavengeTDs(pActiveATD, status, complete, flush);
}
}
else if(type == kXHCITRB_PSCE)
{
UInt32 portID;
if(!CheckNECFirmware())
{
USBLog(2, "AppleUSBXHCI[%p]::PollEventRing2 - This NEC XHCI controller needs a firmware upgrade before it will work. (Current:%x, needed:%x)",this, (unsigned)_NECControllerVersion, (unsigned)kXHCI_MIN_NEC);
}
portID = nextEvent.offs0 >> kXHCITRB_Port_Shift;
USBLog(5, "AppleUSBXHCI[%p]::pollEventRing2x - Port status change event port:%d portSC:%x, portPMSC:%x, portLI:%x", this, (int)portID,
Read32Reg(&_pXHCIRegisters->PortReg[portID-1].PortSC), Read32Reg(&_pXHCIRegisters->PortReg[portID-1].PortPMSC), Read32Reg(&_pXHCIRegisters->PortReg[portID-1].PortLI));
PrintEventTRB(&nextEvent, IRQ, false);
EnsureUsability();
}
else if(type == kXHCITRB_MFWE)
{ _anchorTime = _tempAnchorTime;
_anchorFrame = _tempAnchorFrame;
PrintEventTRB(&nextEvent, IRQ, false);
}
else if(type == kXHCITRB_DevNot)
{
USBLog(1, "AppleUSBXHCI[%p]::PollEventRing2 - Device notification event", this);
USBTrace( kUSBTXHCI, kTPXHCIPollEventRing2, (uintptr_t)this, 7, 0, 0);
PrintTRB(6, &nextEvent, "Device notification event");
PrintEventTRB(&nextEvent, IRQ, false);
}
else
{
if((nextEvent.offsC & ~kXHCITRB_C) != 0) {
USBLog(1, "AppleUSBXHCI[%p]::PollEventRing2 - Unhandled event type: %d", this, type);
PrintTRB(1, &nextEvent, "pollEventRing29");
}
}
USBTrace_End( kUSBTXHCI, kTPXHCIPollEventRing2, (uintptr_t)this, 0, 0, 0 );
return(true);
}
if((Read32Reg(&_pXHCIRegisters->USBSTS)& kXHCIHSEBit) != 0)
{
if(!_HSEReported)
{
USBError(1, "AppleUSBXHCI[%p]::PollEventRing2 - HSE bit set:%x (3)", this, Read32Reg(&_pXHCIRegisters->USBSTS));
}
_HSEReported = true;
}
USBTrace_End( kUSBTXHCI, kTPXHCIPollEventRing2, (uintptr_t)this, 1, 0, 0 );
return(false);
}
bool AppleUSBXHCI::CheckNECFirmware(void)
{
TRB t;
SInt32 ret;
bool result;
CMDComplete callBackF;
ClearTRB(&t, true);
return(true);
if( (_errataBits & kXHCIErrata_NEC) == 0)
{ return(true);
}
if(_NECControllerVersion > 0)
{
return(_NECControllerVersion >= kXHCI_MIN_NEC);
}
callBackF = OSMemberFunctionCast(CMDComplete, this, &AppleUSBXHCI::CompleteNECVendorCommand);
USBLog(2, "AppleUSBXHCI[%p]::CheckNECFirmware - NEC controller", this);
ret = WaitForCMD(&t, kXHCITRB_CMDNEC, callBackF);
if((ret == CMD_NOT_COMPLETED) || (ret <= MakeXHCIErrCode(0)))
{
USBLog(1, "AppleUSBXHCI[%p]::CheckNECFirmware - NEC XHCI controller firmware probably out of date, %x+ needed, this controller did not repond to command.",this, (unsigned)kXHCI_MIN_NEC);
return false;
}
else
{
USBLog(2, "AppleUSBXHCI[%p]::CheckNECFirmware - Command suceeded: Version: %04lx", this, (long unsigned int)ret);
_NECControllerVersion = ret;
result = (ret >= kXHCI_MIN_NEC);
if(!result)
{
USBLog(1, "AppleUSBXHCI[%p]::CheckNECFirmware - NEC XHCI controller firmware out of date, %x+ needed, this controller has %x.",this, (unsigned)kXHCI_MIN_NEC, (unsigned)ret);
}
return(result);
}
}
void AppleUSBXHCI::TestCommands(void)
{
#if 0
TRB t, event;
int tcount=0;
SInt32 ret;
while(tcount++ < 800)
{
ClearTRB(&t, true);
ret = WaitForCMD(&t, kXHCITRB_CMDNoOp);
if((ret == CMD_NOT_COMPLETED) || (ret <= MakeXHCIErrCode(0)))
{
USBLog(1, "AppleUSBXHCI[%p]::TestCommands - NoOp failed:%d", this, (int)ret);
}
else
{
USBLog(2, "AppleUSBXHCI[%p]::TestCommands - NoOp suceeded", this);
}
};
#endif
}
void
AppleUSBXHCI::InterruptHandler(OSObject *owner, IOInterruptEventSource * , int )
{
register AppleUSBXHCI *controller = (AppleUSBXHCI *) owner;
static Boolean emitted;
if (!controller || controller->isInactive() || controller->_lostRegisterAccess || !controller->_controllerAvailable)
{
if (!controller)
{
USBLog(1, "AppleUSBXHCI[%p]::InterruptHandler - Returning early", controller);
}
else
{
USBLog(1, "AppleUSBXHCI[%p]::InterruptHandler - Returning early (inactive: %d, lost regsister access: %d)", controller, controller->isInactive(),controller->_lostRegisterAccess);
}
return;
}
if (!emitted)
{
emitted = true;
}
controller->PollInterrupts();
}
bool
AppleUSBXHCI::PrimaryInterruptFilter(OSObject *owner, IOFilterInterruptEventSource *source)
{
#pragma unused(source)
register AppleUSBXHCI *controller = (AppleUSBXHCI *)owner;
bool result = true;
USBTrace_Start(kUSBTXHCIInterrupts, kTPXHCIInterruptsPrimaryInterruptFilter, (uintptr_t)controller, 0, 0, 0);
if (!controller)
{
return false;
}
controller->_numPrimaryInterrupts++;
if (controller->isInactive())
{
controller->_numInactiveInterrupts++;
return false;
}
if (controller->_lostRegisterAccess || !controller->_controllerAvailable)
{
controller->_numUnavailableInterrupts++;
if (controller->_filterInterruptSource != NULL)
{
controller->_filterInterruptSource->disable();
}
return false;
}
USBTrace( kUSBTXHCIInterrupts, kTPXHCIInterruptsPrimaryInterruptFilter, (uintptr_t)controller, controller ? controller->isInactive() : 2, controller ? controller->_lostRegisterAccess : 3, 2 );
controller->_filterInterruptActive = true;
(void) controller->FilterInterrupt(kPrimaryInterrupter);
result = controller->FilterInterrupt(kTransferInterrupter);
controller->_filterInterruptActive = false;
USBTrace_End( kUSBTXHCIInterrupts, kTPXHCIInterruptsPrimaryInterruptFilter, (uintptr_t)controller, 0, 0, 0 );
return result;
}
bool
AppleUSBXHCI::FilterInterrupt(int index)
{
#pragma unused(index)
bool interruptPending = false ;
bool needsSignal = false;
UInt32 sts = Read32Reg(&_pXHCIRegisters->USBSTS);
_numInterrupts++;
interruptPending = ((sts & kXHCIEINT) != 0);
if(_lostRegisterAccess)
{
_filterInterruptSource->disable();
return(false);
}
USBTrace( kUSBTXHCIInterrupts, kTPXHCIInterruptsPrimaryInterruptFilter, (uintptr_t)this, (uintptr_t)interruptPending, (int)Read32Reg(&_pXHCIRuntimeReg->MFINDEX), 1 );
USBTrace( kUSBTXHCIInterrupts, kTPXHCIInterruptsPrimaryInterruptFilter, (uintptr_t)this, (int)Read32Reg(&_pXHCIRuntimeReg->IR[index].IMOD), (int)Read32Reg(&_pXHCIRuntimeReg->IR[index].IMAN), 4 );
if(interruptPending)
{ Write32Reg(&_pXHCIRegisters->USBSTS, kXHCIEINT);
}
while(FilterEventRing(index, &needsSignal)) ;
if(!needsSignal)
{
needsSignal = ((sts & kXHCIHSEBit) != 0);
}
if (needsSignal)
_filterInterruptSource->signalInterrupt();
return false;
}
#if 0
typedef IOReturn (*fn)(AppleUSBXHCI* xxx, int param);
IOReturn AppleUSBXHCI::TestFn(int param)
{
USBLog(5, "AppleUSBXHCI[%p]::TestFn - %d , _numCMD: %d", this, param, _numCMDs);
return(kIOReturnBadArgument);
}
#endif
void
AppleUSBXHCI::SetVendorInfo(void)
{
OSData *vendProp, *deviceProp, *revisionProp;
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());
}
void AppleUSBXHCI::PrintCapRegs(void)
{
do
{
USBLog(3, "AppleUSBXHCI[%p]::PrintCapRegs - HCIVersion:%lx", this, (long unsigned int)Read16Reg(&_pXHCICapRegisters->HCIVersion));
if (_lostRegisterAccess)
{
break;
}
USBLog(3, "AppleUSBXHCI[%p]::PrintCapRegs - HCSParams1:%lx", this, (long unsigned int)Read32Reg(&_pXHCICapRegisters->HCSParams1));
if (_lostRegisterAccess)
{
break;
}
USBLog(3, "AppleUSBXHCI[%p]::PrintCapRegs - HCSParams2:%lx", this, (long unsigned int)Read32Reg(&_pXHCICapRegisters->HCSParams2));
if (_lostRegisterAccess)
{
break;
}
USBLog(3, "AppleUSBXHCI[%p]::PrintCapRegs - HCSParams3:%lx", this, (long unsigned int)Read32Reg(&_pXHCICapRegisters->HCSParams3));
if (_lostRegisterAccess)
{
break;
}
USBLog(3, "AppleUSBXHCI[%p]::PrintCapRegs - HCCParams:%lx", this, (long unsigned int)Read32Reg(&_pXHCICapRegisters->HCCParams));
if (_lostRegisterAccess)
{
break;
}
USBLog(3, "AppleUSBXHCI[%p]::PrintCapRegs - DBOff:%lx", this, (long unsigned int)Read32Reg(&_pXHCICapRegisters->DBOff));
if (_lostRegisterAccess)
{
break;
}
USBLog(3, "AppleUSBXHCI[%p]::PrintCapRegs - RTSOff:%lx", this, (long unsigned int)Read32Reg(&_pXHCICapRegisters->RTSOff));
if (_lostRegisterAccess)
{
break;
}
} while(0);
}
void AppleUSBXHCI::PrintRuntimeRegs(void)
{
#define PORTTOPRINT (2)
do
{
USBLog(3, "AppleUSBXHCI[%p]::PrintRuntimeRegs - USBCMD:%lx", this, (long unsigned int)Read32Reg(&_pXHCIRegisters->USBCMD));
USBLog(3, "AppleUSBXHCI[%p]::PrintRuntimeRegs - USBSTS:%lx", this, (long unsigned int)Read32Reg(&_pXHCIRegisters->USBSTS));
USBLog(3, "AppleUSBXHCI[%p]::PrintRuntimeRegs - PageSize:%lx", this, (long unsigned int)Read32Reg(&_pXHCIRegisters->PageSize));
USBLog(3, "AppleUSBXHCI[%p]::PrintRuntimeRegs - DNCtrl:%lx", this, (long unsigned int)Read32Reg(&_pXHCIRegisters->DNCtrl));
USBLog(3, "AppleUSBXHCI[%p]::PrintRuntimeRegs - CRCR:%llx", this, (long long unsigned int)Read64Reg(&_pXHCIRegisters->CRCR));
USBLog(3, "AppleUSBXHCI[%p]::PrintRuntimeRegs - DCBAAP:%llx", this, (long long unsigned int)Read64Reg(&_pXHCIRegisters->DCBAAP));
USBLog(3, "AppleUSBXHCI[%p]::PrintRuntimeRegs - Config:%lx", this, (long unsigned int)Read32Reg(&_pXHCIRegisters->Config));
USBLog(3, "AppleUSBXHCI[%p]::PrintRuntimeRegs - PortReg[%d].PortPMSC:%lx", this, PORTTOPRINT, (long unsigned int)Read32Reg(&_pXHCIRegisters->PortReg[PORTTOPRINT].PortPMSC));
USBLog(3, "AppleUSBXHCI[%p]::PrintRuntimeRegs - PortReg[%d].PortLI:%lx", this, PORTTOPRINT, (long unsigned int)Read32Reg(&_pXHCIRegisters->PortReg[PORTTOPRINT].PortLI));
for(int i = 0 ; i<_rootHubNumPorts; i++)
{
USBLog(3, "AppleUSBXHCI[%p]::printRuntimeRegs - PortReg[%d].PortSC: 0x%08x", this, i, (uint32_t)Read32Reg(&_pXHCIRegisters->PortReg[i].PortSC));
}
} while (0);
}
#pragma mark •••••••• UIM Methods ••••••••
IOReturn AppleUSBXHCI::InitAnEventRing(int IRQ)
{
IOReturn err;
_events[IRQ].numEvents = (kXHCIHardwareEventRingBufferSize/sizeof(TRB)) - kSegmentTableEventRingEntries;
err = MakeBuffer(kIOMemoryUnshared | kIODirectionInOut | kIOMemoryPhysicallyContiguous, (_events[IRQ].numEvents + kSegmentTableEventRingEntries)*sizeof(TRB), kXHCIEventRingPhysMask,
&_events[IRQ].EventRingBuffer, (void **)&_events[IRQ].EventRing, &_events[IRQ].EventRingPhys);
if(err != kIOReturnSuccess)
{
return(err);
}
USBLog(3, "AppleUSBXHCI[%p]::InitAnEventRing - Event Ring - pPhysical[%p] pLogical[%p], num Events: %d", this, (void*)_events[IRQ].EventRingPhys, _events[IRQ].EventRing, _events[IRQ].numEvents);
InitEventRing(IRQ);
_events[IRQ].numEvents2 = kXHCISoftwareEventRingBufferSize/(sizeof(TRB));
_events[IRQ].EventRing2 = (TRB *)IOMalloc(kXHCISoftwareEventRingBufferSize);
if(_events[IRQ].EventRing2 == NULL)
{
return(kIOReturnNoMemory);
}
bzero(_events[IRQ].EventRing2,_events[IRQ].numEvents2*sizeof(TRB));
_events[IRQ].EventRing2DequeueIdx = 0;
_events[IRQ].EventRing2EnqueueIdx = 0;
_events[IRQ].EventRing2Overflows = 0;
return(kIOReturnSuccess);
}
IOReturn AppleUSBXHCI::UIMInitialize(IOService * provider)
{
UInt32 CapLength;
UInt32 HCCParams;
IOReturn err = kIOReturnSuccess;
int i, count = 0;
bool gotThreads = false;
UInt16 HCIVersion;
#if 0
fn f;
f = OSMemberFunctionCast(fn, this, &AppleUSBXHCI::TestFn);
(*f)(this, 1234);
#endif
_device = OSDynamicCast(IOPCIDevice, provider);
if (_device == NULL)
return kIOReturnBadArgument;
do {
if (!(_deviceBase = _device->mapDeviceMemoryWithIndex(0)))
{
USBError(1, "AppleUSBXHCI[%p]::UIMInitialize - unable to get device memory", this);
err = kIOReturnNoResources;
break;
}
SetVendorInfo();
_errataBits |= GetErrataBits(_vendorID, _deviceID, _revisionID);
USBLog(3, "AppleUSBXHCI[%p]::UIMInitialize - PCI Vendor:%x, device: %x, rev: %x, errata: %x", this,_vendorID, _deviceID, _revisionID, (unsigned int)_errataBits);
if( (_errataBits & (kXHCIErrataPPT | kXHCIErrata_FrescoLogic | kXHCIErrata_ASMedia |kXHCIErrata_Etron7052)) == 0)
{
OSBoolean * allowAnyXHCIControllerProp = OSDynamicCast(OSBoolean, getProperty("AllowAnyXHCI"));
bool allowAnyXHCIController = (gUSBStackDebugFlags & kUSBEnableAllXHCIControllersMask);
if ( allowAnyXHCIController || ( allowAnyXHCIControllerProp && allowAnyXHCIControllerProp->isTrue()) )
{
USBLog(1, "AppleUSBXHCI[%p]::UIMInitialize - unsupported XHCI controller, but boot-arg set (%d) or plist override (%p)", this, allowAnyXHCIController, allowAnyXHCIControllerProp);
}
else
{
USBLog(1, "AppleUSBXHCI[%p]::UIMInitialize - unsupported XHCI controller", this);
err = kIOReturnUnsupported;
break;
}
}
if (!_v3ExpansionData->_onThunderbolt)
{
_expansionData->_isochMaxBusStall = kXHCIIsochMaxBusStall;
}
_pXHCICapRegisters = (XHCICapRegistersPtr) _deviceBase->getVirtualAddress();
USBLog(3, "AppleUSBXHCI[%p]::UIMInitialize - _pXHCICapRegisters:%p phys:%p", this, _pXHCICapRegisters, (void*)_deviceBase->getPhysicalAddress());
if(!_lostRegisterAccess)
{
_device->configWrite16(kIOPCIConfigCommand, kIOPCICommandMemorySpace);
}
else
{
err = kIOReturnNoDevice;
break;
}
HCIVersion = Read16Reg(&_pXHCICapRegisters->HCIVersion);
if(_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
if(HCIVersion < kXHCIVersion0100)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMInitialize - unsupported XHCI version 0x%x", this, HCIVersion);
err = kIOReturnUnsupported;
break;
}
#if 1
_MaxInterrupters = (Read32Reg(&_pXHCICapRegisters->HCSParams1) & kXHCIMaxInterruptersMask) >> kXHCIMaxInterruptersShift;
if(_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
USBLog(2, "AppleUSBXHCI[%p]::UIMInitialize - _MaxInterrupters:%d", this, (int)_MaxInterrupters);
{
int msi_interrupt_index = 0;
bool msi_interrupt_found = false;
int legacy_interrupt_index = 0;
int interrupt_index_count = 0;
int interrupt_type = 0;
while( _device->getInterruptType( interrupt_index_count, &interrupt_type) == kIOReturnSuccess )
{
USBLog(2, "AppleUSBXHCI[%p]::UIMInitialize - Found interrupt #%d, type: %x", this, interrupt_index_count, interrupt_type);
if( interrupt_type & kIOInterruptTypePCIMessaged )
{
if(!msi_interrupt_found)
{
msi_interrupt_index = interrupt_index_count;
msi_interrupt_found = true;
}
}
else
{
legacy_interrupt_index = interrupt_index_count;
}
interrupt_index_count++;
}
if(msi_interrupt_found && ( (_errataBits & kXHCIErrata_NoMSI) == 0))
{
USBLog(2, "AppleUSBXHCI[%p]::UIMInitialize - Using MSI interrupts", this);
_filterInterruptSource = IOFilterInterruptEventSource::filterInterruptEventSource(this,
AppleUSBXHCI::InterruptHandler,
AppleUSBXHCI::PrimaryInterruptFilter,
_device, msi_interrupt_index );
}
else
{
USBLog(2, "AppleUSBXHCI[%p]::UIMInitialize - Using legacy interrupts", this);
_filterInterruptSource = IOFilterInterruptEventSource::filterInterruptEventSource(this,
AppleUSBXHCI::InterruptHandler,
AppleUSBXHCI::PrimaryInterruptFilter,
_device, legacy_interrupt_index );
}
}
USBLog(2, "AppleUSBXHCI[%p]::UIMInitialize - _filterInterruptSource:%p", this, _filterInterruptSource);
if ( !_filterInterruptSource )
{
USBError(1,"AppleUSBXHCI[%p]: unable to get filterInterruptEventSource", this);
err = kIOReturnNoResources;
break;
}
err = _workLoop->addEventSource(_filterInterruptSource);
if ( err != kIOReturnSuccess )
{
USBError(1,"AppleUSBXHCI[%p]: unable to add filter event source: 0x%x", this, err);
err = kIOReturnNoResources;
break;
}
_workLoop->enableAllInterrupts();
#endif
_maxControllerEndpoints = kMaxXHCIControllerEndpoints;
EnableXHCIPorts();
if( (_errataBits & kXHCIErrataPPT) != 0)
{
_maxControllerEndpoints = 64;
}
CapLength = Read8Reg(&_pXHCICapRegisters->CapLength);
if(_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
USBLog(3, "AppleUSBXHCI[%p]::UIMInitialize - CapLength:%lx", this, (long unsigned int)CapLength);
_pXHCIRegisters = (XHCIRegistersPtr) ( ((uintptr_t)_pXHCICapRegisters) + CapLength);
USBLog(3, "AppleUSBXHCI[%p]::UIMInitialize - _pXHCIRegisters:%p", this, _pXHCIRegisters);
_pXHCIRuntimeReg = (XHCIRunTimeRegPtr) ( ((uintptr_t)_pXHCICapRegisters) + Read32Reg(&_pXHCICapRegisters->RTSOff));
if(_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
USBLog(3, "AppleUSBXHCI[%p]::UIMInitialize - _pXHCIRuntimeReg:%p", this, _pXHCIRuntimeReg);
_pXHCIDoorbells = (UInt32 *) ( ((uintptr_t)_pXHCICapRegisters) + Read32Reg(&_pXHCICapRegisters->DBOff));
if(_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
USBLog(3, "AppleUSBXHCI[%p]::UIMInitialize - _pXHCIDoorbells:%p", this, _pXHCIDoorbells);
DisableComplianceMode();
USBLog(3, "AppleUSBXHCI[%p]::UIMInitialize - PortReg:%p", this, ((XHCIRegistersPtr)0)->PortReg);
HCCParams = Read32Reg(&_pXHCICapRegisters->HCCParams);
if(_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
_maxPrimaryStreams = (HCCParams & kXHCIMaxPSA_Mask) >> kXHCIMaxPSA_Phase;
if (_maxPrimaryStreams > 0) _maxPrimaryStreams = 1 << (_maxPrimaryStreams+1);
_AC64 = ((HCCParams & kXHCIAC64Bit) != 0);
_Contexts64 = ((HCCParams & kXHCICSZBit) != 0);
_contextInUse = 0;
USBLog(3, "AppleUSBXHCI[%p]::UIMInitialize - Max primary streams:%d, AC64:%d, Context Size:%d", this,
(int)_maxPrimaryStreams, (int)_AC64, (int)_Contexts64);
PrintCapRegs();
PrintRuntimeRegs();
Write32Reg(&_pXHCIRegisters->USBCMD, 0);
if (_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
IOSync();
for (i=0; (i < 100) && !(Read32Reg(&_pXHCIRegisters->USBSTS) & kXHCIHCHaltedBit) && !(_lostRegisterAccess); i++)
{
IOSleep(1);
}
if(_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
if (i >= 100)
{
USBError(1, "AppleUSBXHCI[%p]::UIMInitialize - could not get chip to halt within 100 ms", this);
err = kIOReturnInternalError;
break;
}
IOReturn status = ResetController();
if( status != kIOReturnSuccess )
{
break;
}
_rootHubNumPorts = (Read32Reg(&_pXHCICapRegisters->HCSParams1) & kXHCINumPortsMask) >> kXHCINumPortsShift;
if(_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
USBLog(3, "AppleUSBXHCI[%p]::UIMInitialize - _rootHubNumPorts:%lx", this, (long unsigned int)_rootHubNumPorts);
for (i=1; i <= _rootHubNumPorts; i++ )
{
UInt32 portSC = Read32Reg(&_pXHCIRegisters->PortReg[i-1].PortSC);
if(_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
USBLog(6, "AppleUSBXHCI[%p]::UIMInitialize - PortReg[%d].PortSC: 0x%08x", this, i-1, (uint32_t)portSC);
if (portSC & kXHCIPortSC_WRC)
{
portSC |= (UInt32) kXHCIPortSC_WRC;
Write32Reg(&_pXHCIRegisters->PortReg[i-1].PortSC, portSC);
IOSync();
}
if ((portSC & kXHCIPortSC_CCS) && !(portSC & kXHCIPortSC_CSC))
{
USBLog(1, "AppleUSBXHCI[%p]::UIMInitialize - PortReg[%d].PortSC: 0x%08x, has a CCS but no CSC", this, i-1, (uint32_t)portSC);
_synthesizeCSC[i-1] = true;
}
}
if(_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
_rootHubFuncAddressSS = kXHCISSRootHubAddress;
_rootHubFuncAddressHS = kXHCIUSB2RootHubAddress;
_numDeviceSlots = Read32Reg(&_pXHCICapRegisters->HCSParams1) & kXHCINumDevsMask;
if (_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
USBLog(3, "AppleUSBXHCI[%p]::UIMInitialize - _numDeviceSlots:%d", this, _numDeviceSlots);
if(_numDeviceSlots > kMaxSlots)
{
_numDeviceSlots = kMaxSlots;
}
UInt32 tmp = Read32Reg(&_pXHCIRegisters->Config);
if (_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
Write32Reg(&_pXHCIRegisters->Config, ( tmp & ~kXHCINumDevsMask) | _numDeviceSlots);
if (_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
Write32Reg(&_pXHCIRegisters->DNCtrl, 0xffff);
if (_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
err = MakeBuffer(kIOMemoryUnshared | kIODirectionInOut | kIOMemoryPhysicallyContiguous, kXHCIDCBAElSize * (_numDeviceSlots+1), kXHCIDCBAAPhysMask,
&_DCBAABuffer, (void **)&_DCBAA, &_DCBAAPhys);
if(err != kIOReturnSuccess)
{
return(err);
}
USBLog(3, "AppleUSBXHCI[%p]::UIMInitialize - DCBAA - pPhysical[%p] pLogical[%p]", this, (void*)_DCBAAPhys, _DCBAA);
for(i = 0; i<=_numDeviceSlots; i++)
{
_DCBAA[i] = 0;
}
Write64Reg(&_pXHCIRegisters->DCBAAP, _DCBAAPhys);
_numCMDs = PAGE_SIZE/sizeof(TRB);
_CMDCompletions = IONew(XHCICommandCompletion, _numCMDs);
if(_CMDCompletions == NULL)
break;
bzero(_CMDCompletions, _numCMDs * sizeof (XHCICommandCompletion));
err = MakeBuffer(kIOMemoryUnshared | kIODirectionInOut | kIOMemoryPhysicallyContiguous, _numCMDs*sizeof(TRB), kXHCICMDRingPhysMask,
&_CMDRingBuffer, (void **)&_CMDRing, &_CMDRingPhys);
if(err != kIOReturnSuccess)
{
break;
}
USBLog(3, "AppleUSBXHCI[%p]::UIMInitialize - CMD Ring - pPhysical[%p] pLogical[%p], num CMDs: %d", this, (void*)_CMDRingPhys, _CMDRing, _numCMDs);
InitCMDRing();
_istKeepAwayFrames = (Read32Reg(&_pXHCICapRegisters->HCSParams2) & kXHCIIST_Mask) >> kXHCIIST_Phase;
if(_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
if((_istKeepAwayFrames & 8) != 0)
{
_istKeepAwayFrames &= 7;
}
else
{
_istKeepAwayFrames = 1;
}
setProperty("ISTKeepAway", _istKeepAwayFrames, 8);
_ERSTMax = (Read32Reg(&_pXHCICapRegisters->HCSParams2) & kXHCIERSTMax_Mask) >> kXHCIERSTMax_Phase;
if(_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
USBLog(3, "AppleUSBXHCI[%p]::UIMInitialize - _ERSTMax %d", this, _ERSTMax);
err = InitAnEventRing(kPrimaryInterrupter);
if(err != kIOReturnSuccess)
{
break;
}
err = InitAnEventRing(kTransferInterrupter);
if(err != kIOReturnSuccess)
{
break;
}
_CCEPhysZero = 0;
_CCEBadIndex = 0;
_EventChanged = 0;
_IsocProblem = 0;
if (_Contexts64 == false)
{
err = MakeBuffer(kIOMemoryUnshared | kIODirectionInOut | kIOMemoryPhysicallyContiguous, (kXHCI_Num_Contexts+1)*sizeof(Context), kXHCIInputContextPhysMask,
&_inputContextBuffer, (void **)&_inputContext, &_inputContextPhys);
}
else
{
err = MakeBuffer(kIOMemoryUnshared | kIODirectionInOut | kIOMemoryPhysicallyContiguous, (kXHCI_Num_Contexts+1)*sizeof(Context64), kXHCIInputContextPhysMask,
&_inputContextBuffer, (void **)&_inputContext64, &_inputContextPhys);
}
if(err != kIOReturnSuccess)
{
break;
}
USBLog(3, "AppleUSBXHCI[%p]::UIMInitialize - Input context - pPhysical[%p] pLogical[%p]", this, (void*)_inputContextPhys, (_Contexts64 == true) ? (void *)_inputContext64 : (void *)_inputContext);
_numScratchpadBufs = (Read32Reg(&_pXHCICapRegisters->HCSParams2) & kXHCIMaxScratchpadBufsLo_Mask) >> kXHCIMaxScratchpadBufsLo_Shift;
if(_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
_numScratchpadBufs |= (((Read32Reg(&_pXHCICapRegisters->HCSParams2) & kXHCIMaxScratchpadBufsHi_Mask) >> kXHCIMaxScratchpadBufsHi_Shift) << kXHCIMaxScratchpadBufsLo_Width);
if(_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
USBLog(3, "AppleUSBXHCI[%p]::UIMInitialize - Scratchpad bufs %d", this, _numScratchpadBufs);
_SBABuffer = NULL;
if(_numScratchpadBufs != 0)
{
USBPhysicalAddress64 *dummy;
mach_vm_size_t pgSz, pgSzMask, pgAlignmentMask;
IOBufferMemoryDescriptor *scratchpadBuf;
_ScratchPadBuffs = OSArray::withCapacity(_numScratchpadBufs);
if (_ScratchPadBuffs == NULL)
{
err = kIOReturnNoMemory;
break;
}
pgSz = Read32Reg(&_pXHCIRegisters->PageSize) << 12;
if (_lostRegisterAccess)
{
err = kIOReturnNoDevice;
break;
}
pgSzMask = pgSz - 1;
pgAlignmentMask = (~pgSzMask) & 0xffffffff;
USBLog(3, "AppleUSBXHCI[%p]::UIMInitialize - PageSize: %d, page size mask: %llx, alignment mask: %llx", this, (int)pgSz, pgSzMask, pgAlignmentMask);
err = MakeBuffer(kIOMemoryUnshared | kIODirectionInOut | kIOMemoryPhysicallyContiguous, kXHCIDCBAElSize * _numScratchpadBufs, kXHCIDCBAAPhysMask,
&_SBABuffer, (void **)&_SBA, &_SBAPhys);
if(err != kIOReturnSuccess)
{
break;
}
for(i = 0; i<_numScratchpadBufs; i++)
{
err = MakeBuffer(kIOMemoryUnshared | kIODirectionInOut | kIOMemoryPhysicallyContiguous, pgSz, pgAlignmentMask,
&scratchpadBuf, (void **)&dummy, &_SBA[i]);
if(err != kIOReturnSuccess)
{
break;
}
_ScratchPadBuffs->setObject(scratchpadBuf);
scratchpadBuf->release();
}
if(err != kIOReturnSuccess)
{
break;
}
_DCBAA[0] = _SBAPhys;
}
for(i = 0; i < kMaxDevices; i++)
{
_devHub[i] = 0;
_devPort[i] = 0;
_devMapping[i] = 0;
_devEnabled[i] = false;
}
for(i = 0 ; i < kMaxPorts; i++)
{
_prevSuspend[i] = false;
_suspendChangeBits[i] = false;
}
_stateSaved = false;
_fakedSetaddress = false;
_filterInterruptActive = false;
_frameNumber64 = 0;
_numInterrupts = 0;
_numPrimaryInterrupts = 0;
_numInactiveInterrupts = 0;
_numUnavailableInterrupts = 0;
_HSEReported = false;
if( (_errataBits & kXHCIErrata_ParkRing) != 0)
{
XHCIRing dummyRing;
if(AllocRing(&dummyRing, 1) == kIOReturnSuccess)
{
_DummyBuffer = dummyRing.TRBBuffer;
_DummyRingPhys = dummyRing.transferRingPhys;
_DummyRingCycleBit = dummyRing.transferRingPCS;
}
else
{
USBLog(1, "AppleUSBXHCI[%p]::UIMInitialize - couldn't allocate dummy ring", this);
}
}
_NECControllerVersion = 0;
_debugCtr = 0;
_debugPattern = 0xdeadbeef;
bzero(_slots, sizeof(_slots));
DecodeExtendedCapability();
gotThreads = true;
for (i=0; i < _rootHubNumPorts; i++)
{
_rhResumePortTimerThread[i] = thread_call_allocate((thread_call_func_t)RHResumePortTimerEntry, (thread_call_param_t)this);
_rhResetPortThread[i] = thread_call_allocate((thread_call_func_t)RHResetPortEntry, (thread_call_param_t)this);
if (!_rhResumePortTimerThread[i] || !_rhResetPortThread[i])
{
gotThreads = false;
break;
}
}
if (!gotThreads)
continue;
CheckSleepCapability();
_uimInitialized = true;
registerService();
return kIOReturnSuccess;
} while (false);
UIMFinalize();
return(err);
}
void AppleUSBXHCI::DecodeSupportedProtocol(XHCIXECPRegistersPtr protocolBase)
{
XHCIXECPProtoRegistersPtr CurrentProtoBase = (XHCIXECPProtoRegistersPtr)protocolBase;
USBLog(3, "AppleUSBXHCI[%p]::DecodeSupportedProtocol - xEP CapabilityID %d", this, CurrentProtoBase->Header.CapabilityID);
USBLog(3, "AppleUSBXHCI[%p]::DecodeSupportedProtocol portSpeed: %d startPort: %d endPort: %d nameString: 0x%lx", this, (int)CurrentProtoBase->MajRevision,
(int)CurrentProtoBase->compatiblePortOffset, (int)CurrentProtoBase->compatiblePortOffset+CurrentProtoBase->compatiblePortCount, (long unsigned int)CurrentProtoBase->NameString);
if( CurrentProtoBase->MajRevision == kUSBSSMajversion && CurrentProtoBase->NameString == kUSBNameString )
{
_v3ExpansionData->_rootHubNumPortsSS = CurrentProtoBase->compatiblePortCount;
_v3ExpansionData->_rootHubPortsSSStartRange = CurrentProtoBase->compatiblePortOffset;
}
else if ( CurrentProtoBase->MajRevision == kUSBHSMajversion && CurrentProtoBase->NameString == kUSBNameString )
{
_v3ExpansionData->_rootHubNumPortsHS = CurrentProtoBase->compatiblePortCount;
_v3ExpansionData->_rootHubPortsHSStartRange = CurrentProtoBase->compatiblePortOffset;
}
}
void AppleUSBXHCI::DecodeExtendedCapability()
{
UInt32 HCSParams = Read32Reg(&_pXHCICapRegisters->HCCParams);
UInt32 xECP = (HCSParams & kXHCIxECP_Mask) >> kXHCIxECP_Shift;
XHCIXECPRegistersPtr CurrentXECPBase;
if (_lostRegisterAccess)
{
return;
}
CurrentXECPBase = _pXHCIXECPRegistersBase = (XHCIXECPRegistersPtr) ( ((uintptr_t)_pXHCICapRegisters) + ((xECP) << 2) );
do{
switch (CurrentXECPBase->Header.CapabilityID)
{
case kXHCISupportedProtocol:
DecodeSupportedProtocol(CurrentXECPBase);
break;
default:
USBLog(3, "AppleUSBXHCI[%p]::DecodeExtendedCapability - xEP CapabilityID %d not implemented", this, CurrentXECPBase->Header.CapabilityID);
break;
}
if(CurrentXECPBase->Header.NextPtr == 0)
break;
CurrentXECPBase = (XHCIXECPRegistersPtr) ( ((uintptr_t)CurrentXECPBase) + ((CurrentXECPBase->Header.NextPtr) << 2) );
}while(1);
}
void AppleUSBXHCI::FinalizeAnEventRing(int IRQ)
{
if (_events[IRQ].EventRingBuffer)
{
_events[IRQ].EventRingBuffer->complete();
_events[IRQ].EventRingBuffer->release();
_events[IRQ].EventRingBuffer = 0;
}
if (_events[IRQ].EventRing2)
{
IOFree(_events[IRQ].EventRing2, kXHCISoftwareEventRingBufferSize);
}
}
IOReturn AppleUSBXHCI::UIMFinalize()
{
int i;
IOBufferMemoryDescriptor *scratchpadBuf;
USBTrace( kUSBTXHCI, kTPXHCIUIMFinalize , (uintptr_t)this, isInactive(), (uintptr_t)_pXHCIRegisters, (uintptr_t)_device);
USBLog(1, "AppleUSBXHCI[%p]::UIMFinalize", this);
if (_acpiDevice )
{
_acpiDevice->release();
_acpiDevice = NULL;
}
if (_DCBAABuffer)
{
_DCBAABuffer->complete();
_DCBAABuffer->release();
_DCBAABuffer = 0;
}
if (_CMDCompletions)
{
IODelete(_CMDCompletions, XHCICommandCompletion, _numCMDs);
_CMDCompletions = 0;
}
if (_CMDRingBuffer)
{
_CMDRingBuffer->complete();
_CMDRingBuffer->release();
_CMDRingBuffer = 0;
}
FinalizeAnEventRing(kPrimaryInterrupter);
FinalizeAnEventRing(kTransferInterrupter);
if (_inputContextBuffer)
{
_inputContextBuffer->complete();
_inputContextBuffer->release();
_inputContextBuffer = 0;
}
if (_ScratchPadBuffs)
{
for (i=0; i < (int)_ScratchPadBuffs->getCount(); i++)
{
scratchpadBuf = (IOBufferMemoryDescriptor *)_ScratchPadBuffs->getObject(i);
scratchpadBuf->complete();
}
_ScratchPadBuffs->flushCollection();
_ScratchPadBuffs->release();
_ScratchPadBuffs = 0;
}
if (_SBABuffer)
{
_SBABuffer->complete();
_SBABuffer->release();
_SBABuffer = 0;
}
if (_filterInterruptSource && _workLoop)
{
_workLoop->removeEventSource(_filterInterruptSource);
_filterInterruptSource->release();
_filterInterruptSource = NULL;
}
if (_deviceBase)
{
_deviceBase->release();
_deviceBase = 0;
}
for (i=0; i < _rootHubNumPorts; i++)
{
if (_rhResumePortTimerThread[i])
{
thread_call_cancel(_rhResumePortTimerThread[i]);
thread_call_free(_rhResumePortTimerThread[i]);
_rhResumePortTimerThread[i] = NULL;
}
if (_rhResetPortThread[i])
{
thread_call_cancel(_rhResetPortThread[i]);
thread_call_free(_rhResetPortThread[i]);
_rhResetPortThread[i] = NULL;
}
}
if( (_errataBits & kXHCIErrata_ParkRing) != 0)
{
if(_DummyBuffer)
{
_DummyBuffer->complete();
_DummyBuffer->release();
_DummyBuffer = 0;
}
}
_uimInitialized = false;
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::message( UInt32 type, IOService * provider, void * argument )
{
IOReturn returnValue = kIOReturnSuccess;
UInt32 disableMuxedPorts = ((gUSBStackDebugFlags & kUSBDisableMuxedPortsMask) >> kUSBDisableMuxedPorts);
UInt8 controller = kControllerXHCI;
USBLog(3, "AppleUSBXHCI[%p]::message type: %p, argument = %p isInactive = %d ", this, (void*)type, argument, isInactive());
returnValue = super::message( type, provider, argument );
switch (type)
{
case kIOUSBMessageMuxFromXHCIToEHCI:
controller = kControllerEHCI;
case kIOUSBMessageMuxFromEHCIToXHCI:
if(_lostRegisterAccess)
{
USBLog(3, "AppleUSBXHCI[%p]::message type: %p, argument = %p Controller Not Available", this, (void*)type, argument);
return returnValue;
}
if ( !disableMuxedPorts && _device && !isInactive() )
{
if( (_errataBits & kXHCIErrataPPTMux) != 0)
{
HCSelect((UInt8)(uint64_t)argument, controller);
USBLog(3, "AppleUSBXHCI[%p]::message type: %p port: %d to %s controller [HCSEL: %lx]", this, (void*)type, (UInt8)(uint64_t)argument, (controller == kControllerEHCI) ? "EHCI" : "XHCI", (long unsigned int)_device->configRead32(kXHCI_XUSB2PR));
}
}
break;
case kIOUSBMessageHubPortDeviceDisconnected:
if(_lostRegisterAccess)
{
USBLog(3, "AppleUSBXHCI[%p]::message type: %p, argument = %p Controller Not Available", this, (void*)type, argument);
return returnValue;
}
if ( !disableMuxedPorts && _device && !isInactive() )
{
if( (_errataBits & kXHCIErrataPPTMux) != 0)
{
HCSelectWithMethod((char*)argument);
USBLog(3, "AppleUSBXHCI[%p]::message type: %p method %s to %s controller [HCSEL: %lx]", this, (void*)type, (char*)argument, "XHCI", (long unsigned int)_device->configRead32(kXHCI_XUSB2PR));
}
}
break;
default:
returnValue = kIOReturnUnsupported;
break;
}
return returnValue;
}
IOReturn AppleUSBXHCI::UIMCreateControlEndpoint(UInt8 functionNumber,
UInt8 endpointNumber,
UInt16 maxPacketSize,
UInt8 speed)
{
#pragma unused(functionNumber)
#pragma unused(endpointNumber)
#pragma unused(maxPacketSize)
#pragma unused(speed)
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint 1- Obsolete method called", this);
return(kIOReturnInternalError);
}
void AppleUSBXHCI::CompleteSlotCommand(TRB *t, void *param)
{
int CC;
UInt32 res;
CC = GetTRBCC(t);
if(CC == kXHCITRB_CC_Success)
{
res = GetTRBSlotID(t);
}
else
{
res = MakeXHCIErrCode(CC);
}
*(UInt32 *)param = res;
if ( !getWorkLoop()->onThread() )
{
GetCommandGate()->commandWakeup(param);
}
}
void AppleUSBXHCI::CompleteNECVendorCommand(TRB *t, void *param)
{
int CC;
UInt32 res;
CC = GetTRBCC(t);
if(CC == kXHCITRB_CC_Success)
{
res = (t->offs8 & 0xffff);
}
else
{
res = 1000+CC;
}
*(UInt32 *)param = res;
GetCommandGate()->commandWakeup(param);
}
void AppleUSBXHCI::GetInputContext(void)
{
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
if ( !_workLoop->inGate() )
panic ( "AppleUSBXHCI::GetInputContext[%p] called without workloop lock held\n", this );
#endif
if(_contextInUse > 0)
{
USBLog(1, "AppleUSBXHCI[%p]::GetInputContext - context in use: %d", this, _contextInUse);
}
_contextInUse++;
if (_Contexts64 == true)
{
bzero((void *)_inputContext64, (kXHCI_Num_Contexts+1)*sizeof(Context64));
}
else
{
bzero((void *)_inputContext, (kXHCI_Num_Contexts+1)*sizeof(Context));
}
}
Context * AppleUSBXHCI::GetInputContextByIndex(int index)
{
Context * ctx = NULL;
if (_Contexts64 == false)
{
ctx = &_inputContext[index];
}
else
{
ctx = (Context *)&_inputContext64[index];
}
return ctx;
}
void AppleUSBXHCI::ReleaseInputContext(void)
{
if(_contextInUse == 0)
{
USBLog(1, "AppleUSBXHCI[%p]::ReleaseInputContext - context already released", this);
return;
}
_contextInUse--;
}
IOReturn AppleUSBXHCI::AddressDevice(UInt32 slotID, UInt16 maxPacketSize, bool setAddr, UInt8 speed, int highSpeedHubSlot, int highSpeedPort)
{
SInt32 ret=0;
UInt32 portSpeed, rootHubPort;
UInt32 routeString = 0;
TRB t;
XHCIRing * ring0;
int hub, port;
Context * inputContext;
Context * deviceContext;
USBLog(3, "AppleUSBXHCI[%p]::AddressDevice - _devZeroPort: %d, _devZeroHub:%d", this, _devZeroPort, _devZeroHub);
hub = _devZeroHub;
port = _devZeroPort;
for(int i = 0; i < kMaxUSB3HubDepth; i++)
{
if( (hub == _rootHubFuncAddressSS) || (hub == _rootHubFuncAddressHS) )
{
break;
}
if(port > 15)
{
port = 15;
}
routeString = (routeString << 4) + port;
port = _devPort[hub];
hub = _devHub[hub];
USBLog(4, "AppleUSBXHCI[%p]::AddressDevice - Next hub: %d, port:%d, routeString: %x", this, hub, port, (unsigned int)routeString);
}
if( (hub != _rootHubFuncAddressSS) && (hub != _rootHubFuncAddressHS) )
{
USBError(1, "AppleUSBXHCI[%p]::AddressDevice - Root hub port not found in topology: hub:%d, rootHubSS: %d rootHubHS: %d", this, hub, _rootHubFuncAddressSS, _rootHubFuncAddressHS);
return(kIOReturnInternalError);
}
rootHubPort = port;
ring0 = GetRing(slotID, 1, 0);
if(ring0 == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::AddressDevice - ring zero does not exist (slot:%d) ", this, (int)slotID);
return(kIOReturnInternalError);
}
if(ring0->TRBBuffer == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::AddressDevice - ******** NULL ring (slot:%d, ring:1) ", this, (int)slotID);
return(kIOReturnInternalError);
}
GetInputContext();
inputContext = GetInputContextByIndex(0);
inputContext->offs04 = HostToUSBLong(kXHCIBit0 | kXHCIBit1);
inputContext = GetInputContextByIndex(1);
SetSlCtxRootHubPort(inputContext, rootHubPort);
inputContext->offs00 = HostToUSBLong(1 << kXHCISlCtx_CtxEnt_Shift);
portSpeed = (Read32Reg(&_pXHCIRegisters->PortReg[rootHubPort-1].PortSC) & kXHCIPortSC_Speed_Mask) >> kXHCIPortSC_Speed_Shift;
if (_lostRegisterAccess)
{
USBLog(1, "AppleUSBXHCI[%p]::AddressDevice - Controller not available ring (slot:%d, ring:1) ", this, (int)slotID);
return kIOReturnNoDevice;
}
if(portSpeed >= kXHCISpeed_Super)
{
SetSlCtxSpeed(inputContext, portSpeed);
}
else
{
if(speed == kUSBDeviceSpeedHigh)
{
SetSlCtxSpeed(inputContext, kXHCISpeed_High);
}
else
{
if(speed == kUSBDeviceSpeedFull)
{
SetSlCtxSpeed(inputContext, kXHCISpeed_Full);
}
else
{
SetSlCtxSpeed(inputContext, kXHCISpeed_Low);
}
if(highSpeedHubSlot != 0)
{
SetSlCtxTTPort(inputContext, highSpeedPort);
SetSlCtxTTSlot(inputContext, highSpeedHubSlot);
SetSlCtxMTT(inputContext, GetSlCtxMTT(GetSlotContext(highSpeedHubSlot)));
}
}
}
USBLog(3, "AppleUSBXHCI[%p]::AddressDevice - Port %d speed is: %d, device speed is: %d", this, (int)rootHubPort, (int)portSpeed, GetSlCtxSpeed(inputContext));
SetSlCtxInterrupter(inputContext, kTransferInterrupter);
SetSlCtxRouteString(inputContext, routeString);
if(portSpeed >= kXHCISpeed_Super)
{ maxPacketSize = 512;
}
inputContext = GetInputContextByIndex(2);
SetEPCtxEpType(inputContext, kXHCIEpCtx_EPType_Control);
SetEPCtxMPS(inputContext,maxPacketSize);
SetEPCtxDQpAddr64(inputContext, ring0->transferRingPhys+ring0->transferRingDequeueIdx*sizeof(TRB));
SetEPCtxDCS(inputContext, ring0->transferRingPCS);
SetEPCtxCErr(inputContext, 3);
ClearTRB(&t, true);
SetTRBAddr64(&t, _inputContextPhys);
SetTRBSlotID(&t, slotID);
if(!setAddr)
{
SetTRBBSRBit(&t, 1);
}
PrintTRB(6, &t, "AddressDevice");
ret = WaitForCMD(&t, kXHCITRB_AddressDevice);
ReleaseInputContext();
if((ret == CMD_NOT_COMPLETED) || (ret <= MakeXHCIErrCode(0)))
{
USBLog(1, "AppleUSBXHCI[%p]::AddressDevice - Address device failed:%d", this, (int)ret);
if(ret == MakeXHCIErrCode(kXHCITRB_CC_CtxParamErr)) {
USBLog(1, "AppleUSBXHCI[%p]::AddressDevice - Input Context 0", this);
PrintContext(GetInputContextByIndex(0));
USBLog(1, "AppleUSBXHCI[%p]::AddressDevice - Input Context 1", this);
PrintContext(GetInputContextByIndex(1));
USBLog(1, "AppleUSBXHCI[%p]::AddressDevice - Input Context 2", this);
PrintContext(GetInputContextByIndex(2));
}
return(MungeXHCIStatus(ret, 0));
}
USBLog(6, "AppleUSBXHCI[%p]::AddressDevice - Address device success: SlotState: %d USB Address: %d ", this,
GetSlCtxSlotState(GetSlotContext(slotID)), GetSlCtxUSBAddress(GetSlotContext(slotID)) );
return(kIOReturnSuccess);
}
IOReturn
AppleUSBXHCI::configureHub(UInt32 address, UInt32 flags)
{
bool multiTT;
UInt32 TTThinkTime, NumPorts, slotID;
TRB t;
SInt32 ret=0;
Context * slotContext;
Context * inputContext;
if( (address == _rootHubFuncAddressSS) || (address == _rootHubFuncAddressHS) )
{
return kIOReturnSuccess;
}
slotID = GetSlotID(address);
if(slotID == 0)
{
USBLog(1, "AppleUSBXHCI[%p]::configureHub - unknown address: %d", this, (int)address);
return(kIOReturnBadArgument);
}
multiTT = ((flags & kUSBHSHubFlagsMultiTTMask) != 0);
if(flags & kUSBHSHubFlagsMoreInfoMask)
{
TTThinkTime = ((flags & kUSBHSHubFlagsTTThinkTimeMask) >> kUSBHSHubFlagsTTThinkTimeShift);
NumPorts = ((flags & kUSBHSHubFlagsNumPortsMask) >> kUSBHSHubFlagsNumPortsShift);
USBLog(3, "AppleUSBXHCI[%p]::configureHub (HS) - TTThinkTime: %d, NumPorts: %d, MultiTT: %s", this, (int)TTThinkTime, (int)NumPorts, multiTT ? "true" : "false");
}
else
{
TTThinkTime = 3; NumPorts = 15;
USBLog(3, "AppleUSBXHCI[%p]::configureHub (HS) - faking it TTThinkTime: %d, NumPorts: %d, MultiTT: %s", this, (int)TTThinkTime,(int) NumPorts, multiTT ? "true" : "false");
}
GetInputContext();
inputContext = GetInputContextByIndex(0);
inputContext->offs04 = HostToUSBLong(kXHCIBit0);
inputContext = GetInputContextByIndex(1);
slotContext = GetSlotContext(slotID);
*inputContext = *slotContext;
inputContext->offs00 |= kXHCISlCtx_HubBit; SetSlCtxMTT(inputContext, multiTT);
ResetSlCtxNumPorts(inputContext, NumPorts);
ResetSlCtxTTT(inputContext, TTThinkTime);
ClearTRB(&t, true);
SetTRBAddr64(&t, _inputContextPhys);
SetTRBSlotID(&t, slotID);
ret = WaitForCMD(&t, kXHCITRB_ConfigureEndpoint);
ReleaseInputContext();
if((ret == CMD_NOT_COMPLETED) || (ret < MakeXHCIErrCode(0)))
{
USBLog(1, "AppleUSBXHCI[%p]::configureHub - Configure endpoint failed:%d", this, (int)ret);
if(ret == MakeXHCIErrCode(kXHCITRB_CC_CtxParamErr)) {
USBLog(1, "AppleUSBXHCI[%p]::configureHub - Input Context 0", this);
PrintContext(GetInputContextByIndex(0));
USBLog(1, "AppleUSBXHCI[%p]::configureHub - Input Context 1", this);
PrintContext(GetInputContextByIndex(1));
USBLog(1, "AppleUSBXHCI[%p]::configureHub - Input Context 2", this);
PrintContext(GetInputContextByIndex(2));
}
return(kIOReturnInternalError);
}
else
{
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::UIMHubMaintenance(USBDeviceAddress highSpeedHub, UInt32 highSpeedPort, UInt32 command, UInt32 flags)
{
#pragma unused(highSpeedPort)
switch (command)
{
case kUSBHSHubCommandAddHub:
USBLog(3, "AppleUSBXHCI[%p]::UIMHubMaintenance - adding hub %d with flags 0x%x", this, highSpeedHub, (uint32_t)flags);
return configureHub(highSpeedHub, flags);
break;
case kUSBHSHubCommandRemoveHub:
USBLog(3, "AppleUSBXHCI[%p]::UIMHubMaintenance - deleting hub %d", this, highSpeedHub);
break;
default:
return kIOReturnBadArgument;
}
return kIOReturnSuccess;
}
IOReturn AppleUSBXHCI::UIMCreateControlEndpoint(UInt8 functionNumber,
UInt8 endpointNumber,
UInt16 maxPacketSize,
UInt8 speed,
USBDeviceAddress highSpeedHub,
int highSpeedPort)
{
IOReturn err;
USBLog(6, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint 2 - fn: %d, ep:%d, MaxPkt:%d, speed:%d, hdHub:%d, hsPort:%d", this,
functionNumber, endpointNumber, maxPacketSize, speed, highSpeedHub, highSpeedPort);
USBLog(6, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint - _rootHubFuncAddressSS: %d, _rootHubFuncAddressHS: %d", this, _rootHubFuncAddressSS, _rootHubFuncAddressHS);
if( (functionNumber == _rootHubFuncAddressSS) || (functionNumber == _rootHubFuncAddressHS) )
{
USBLog(3, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint 2 - Faking root hub ring", this);
return(kIOReturnSuccess);
}
err = TestConfiguredEpCount();
if(err != kIOReturnSuccess)
{
return(err);
}
if(maxPacketSize == 9)
{ maxPacketSize = 512;
}
if(functionNumber == 0)
{
XHCIRing *ring0;
SInt32 slotID = 0;
TRB t;
ClearTRB(&t, true);
PrintSlotContexts();
slotID = WaitForCMD(&t, kXHCITRB_EnableSlot);
PrintSlotContexts();
if((slotID == CMD_NOT_COMPLETED) || (slotID <= MakeXHCIErrCode(0)))
{
if(slotID == MakeXHCIErrCode(kXHCITRB_CC_NoSlots))
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint 2 - Run out of device slots, returning: %x", this, kIOUSBDeviceCountExceeded);
return(kIOUSBDeviceCountExceeded);
}
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint 2 - Enable slot failed:%d", this, (int)slotID);
return(kIOReturnInternalError);
}
_devMapping[0] = slotID;
_devEnabled[0] = true;
USBLog(6, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint 2 - Enable slot succeeded slot: %d (fn:%d, ep:%d)", this, (int)slotID, functionNumber, endpointNumber);
ring0 = CreateRing(slotID, 1, 0);
if(ring0 == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint - ring zero not created (slot:%d) ", this, (int)slotID);
return(kIOReturnInternalError);
}
if(ring0->TRBBuffer != NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint - ******** ring already exists (slot:%d, ring:1) ", this, (int)slotID);
return(kIOReturnInternalError);
}
err = AllocRing(ring0);
USBLog(6, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint 2 (epID: 1) - tr ring: %p size: %d", this, ring0->transferRing, ring0->transferRingSize);
if(err != kIOReturnSuccess)
{
return(kIOReturnNoMemory);
}
if (_Contexts64 == false)
{
err = MakeBuffer(kIOMemoryUnshared | kIODirectionInOut | kIOMemoryPhysicallyContiguous, kXHCI_Num_Contexts*sizeof(Context), kXHCIContextPhysMask,
&_slots[slotID].buffer, (void **)&_slots[slotID].deviceContext, &_slots[slotID].deviceContextPhys);
}
else
{
err = MakeBuffer(kIOMemoryUnshared | kIODirectionInOut | kIOMemoryPhysicallyContiguous, kXHCI_Num_Contexts*sizeof(Context64), kXHCIContextPhysMask,
&_slots[slotID].buffer, (void **)&_slots[slotID].deviceContext64, &_slots[slotID].deviceContextPhys);
}
if(err != kIOReturnSuccess)
{
DeallocRing(ring0);
return(kIOReturnNoMemory);
}
if (ring0->pEndpoint == NULL)
{
ring0->endpointType = kXHCIEpCtx_EPType_Control;
ring0->pEndpoint = AllocateAppleXHCIAsyncEndpoint(ring0, maxPacketSize, 0, 0);
if(ring0->pEndpoint == NULL)
{
DeallocRing(ring0);
return kIOReturnNoMemory;
}
USBLog(3, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint - inc ConfiguredEpCount (ring0)", this);
IncConfiguredEpCount();
}
USBLog(3, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint 2 - Output context - pPhysical[%p] pLogical[%p]", this, (void*)_slots[slotID].deviceContextPhys, _slots[slotID].deviceContext);
SetDCBAAAddr64(&_DCBAA[slotID], _slots[slotID].deviceContextPhys);
err = AddressDevice(slotID, maxPacketSize, false, speed, GetSlotID(highSpeedHub), highSpeedPort);
if ( err != kIOReturnSuccess)
{
USBLog(2, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint returning 0x%x", this, (uint32_t) err);
}
return err;
}
if(endpointNumber == 0)
{
UInt16 currMPS;
int slotID;
TRB t;
SInt32 ret=0;
Context * inputContext;
slotID = GetSlotID(functionNumber);
if(slotID == 0)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint 2 - unknown function number: %d", this, functionNumber);
return(kIOReturnInternalError);
}
currMPS = GetEpCtxMPS(GetEndpointContext(slotID, 1));
if(currMPS == maxPacketSize)
{
USBLog(3, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint 2 - currMPS == maxPacketSize: %d", this, currMPS );
return(kIOReturnSuccess);
}
USBLog(3, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint 2 - need to change max packet size current: %d, wanted: %d", this, currMPS, maxPacketSize );
GetInputContext();
inputContext = GetInputContextByIndex(0);
inputContext->offs04 = HostToUSBLong(kXHCIBit1);
inputContext = GetInputContextByIndex(2);
SetEPCtxMPS(inputContext,maxPacketSize);
ClearTRB(&t, true);
SetTRBAddr64(&t, _inputContextPhys);
SetTRBSlotID(&t, slotID);
USBLog(5, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint 2 - Evaluate Context TRB:", this);
PrintTRB(3, &t, "UIMCreateControlEndpoint");
ret = WaitForCMD(&t, kXHCITRB_EvaluateContext);
ReleaseInputContext();
if((ret == CMD_NOT_COMPLETED) || (ret <= MakeXHCIErrCode(0)))
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint 2 - Evaluate Context failed:%d", this, (int)ret);
if(ret == MakeXHCIErrCode(kXHCITRB_CC_CtxParamErr)) {
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint 2 - Input Context 0", this);
PrintContext(GetInputContextByIndex(0));
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint 2 - Input Context 1", this);
PrintContext(GetInputContextByIndex(1));
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint 2 - Input Context 2", this);
PrintContext(GetInputContextByIndex(2));
}
return(kIOReturnInternalError);
}
return(kIOReturnSuccess);
}
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlEndpoint 2 - Unimplimented method called", this);
return(kIOReturnInternalError);
}
IOReturn AppleUSBXHCI::UIMCreateControlTransfer(short functionNumber,
short endpointNumber,
IOUSBCompletion completion,
void *CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
#pragma unused(functionNumber)
#pragma unused(endpointNumber)
#pragma unused(completion)
#pragma unused(CBP)
#pragma unused(bufferRounding)
#pragma unused(bufferSize)
#pragma unused(direction)
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlTransfer 1 - Obsolete method called", this);
return(kIOReturnInternalError);
}
TRB *
AppleUSBXHCI::GetNextTRB(XHCIRing *ring, void *xhciTD, TRB **StartofFragment, bool firstFragment)
{
int nextEnqueueIndex;
TRB *t;
UInt32 offsC;
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
if ( !getWorkLoop()->inGate() )
{
USBLog(1, "AppleUSBXHCI[%p]::GetNextTRB - Not inGate", this);
}
#endif
if(StartofFragment == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::GetNextTRB - NULL StartofFragment pointer", this);
return(NULL);
}
if(ring->transferRingEnqueueIdx > ring->transferRingSize-2)
{
USBLog(1, "AppleUSBXHCI[%p]::GetNextTRB - bad index: %d", this, ring->transferRingEnqueueIdx);
return(NULL);
}
if(ring->transferRingEnqueueIdx == ring->transferRingSize-2)
{
if(ring->transferRingDequeueIdx == 0)
{ USBLog(2, "AppleUSBXHCI[%p]::GetNextTRB - Ring full 1, not expanding!", this);
#if 0
if(ExpandRing(ring) != kIOReturnSuccess)
{
return(NULL);
}
return(GetNextTRB(ring, c, StartofFragment, firstFragment));
#endif
return (NULL);
}
if(xhciTD == NULL)
{
SetTRBChainBit(&ring->transferRing[ring->transferRingSize-1], true);
PrintTransferTRB(&ring->transferRing[ring->transferRingSize-1], ring, ring->transferRingSize-1);
}
else
{
SetTRBChainBit(&ring->transferRing[ring->transferRingSize-1], false);
PrintTransferTRB(&ring->transferRing[ring->transferRingSize-1], ring, ring->transferRingSize-1);
}
nextEnqueueIndex = 0;
SetTRBCycleBit(&ring->transferRing[ring->transferRingSize-1], ring->transferRingPCS); PrintTransferTRB(&ring->transferRing[ring->transferRingSize-1], ring, ring->transferRingSize-1);
ring->transferRingPCS = 1- ring->transferRingPCS;
}
else
{
if( (*StartofFragment != NULL) && (ring->transferRingEnqueueIdx == 0) )
{
int startIndex,startIndex0, fragSize;
startIndex = (int)(*StartofFragment - ring->transferRing);
fragSize = ring->transferRingSize - 1 - startIndex;
if(ring->transferRingDequeueIdx <= (fragSize+1))
{ USBLog(4, "AppleUSBXHCI[%p]::GetNextTRB - Ring full 3, not expanding!; Start:%d, fragSize:%d, deq:%d (enq:%d)", this, startIndex, fragSize, ring->transferRingDequeueIdx, ring->transferRingEnqueueIdx);
#if 0
if(ExpandRing(ring) != kIOReturnSuccess)
{
return(NULL);
}
return(GetNextTRB(ring, c, StartofFragment, firstFragment));
#endif
return (NULL);
}
nextEnqueueIndex = 0;
while (startIndex < (ring->transferRingSize-1))
{
ring->transferRing[nextEnqueueIndex] = ring->transferRing[startIndex];
ring->transferRing[nextEnqueueIndex].offsC ^= USBToHostLong(kXHCITRB_C);
PrintTransferTRB(&ring->transferRing[nextEnqueueIndex], ring, nextEnqueueIndex);
nextEnqueueIndex++;
startIndex++;
}
(**StartofFragment).offs0 = ring->transferRing[startIndex].offs0;
(**StartofFragment).offs4 = ring->transferRing[startIndex].offs4;
(**StartofFragment).offs8 = ring->transferRing[startIndex].offs8;
offsC = ring->transferRing[startIndex].offsC;
if(firstFragment)
{
offsC &= ~HostToUSBLong(kXHCITRB_CH);
}
else
{
offsC |= HostToUSBLong(kXHCITRB_CH);
}
(**StartofFragment).offsC = offsC;
PrintTransferTRB(*StartofFragment, ring, (int)(*StartofFragment - ring->transferRing));
*StartofFragment = &ring->transferRing[0];
ring->transferRingEnqueueIdx = nextEnqueueIndex;
nextEnqueueIndex++;
}
else
{
if(ring->transferRingEnqueueIdx+1 == ring->transferRingDequeueIdx)
{
USBLog(4, "AppleUSBXHCI[%p]::GetNextTRB - Ring full 2, not expanding!", this);
#if 0
if(ExpandRing(ring) != kIOReturnSuccess)
{
return(NULL);
}
return(GetNextTRB(ring, c, StartofFragment, firstFragment));
#endif
return (NULL);
}
nextEnqueueIndex = ring->transferRingEnqueueIdx+1;
}
}
t = &ring->transferRing[ring->transferRingEnqueueIdx];
ring->transferRingEnqueueIdx = nextEnqueueIndex;
ClearTRB(t, false);
if(*StartofFragment == NULL)
{
*StartofFragment = t;
}
return(t);
}
void AppleUSBXHCI::PutBackTRB(XHCIRing *ring, TRB *t)
{
int putBackIndex;
putBackIndex = (int)(t - ring->transferRing);
if( (putBackIndex < 0) || (putBackIndex > (ring->transferRingSize-1)) )
{
USBLog(1, "AppleUSBXHCI[%p]::PutBackTRB - Index out of range: %d", this, putBackIndex);
return;
}
while(ring->transferRingEnqueueIdx != putBackIndex)
{
if(ring->transferRingEnqueueIdx == ring->transferRingDequeueIdx)
{
USBLog(1, "AppleUSBXHCI[%p]::PutBackTRB - Bad TRB pointer, Ring empty: %d (%d - %d)", this, putBackIndex, ring->transferRingDequeueIdx, ring->transferRingEnqueueIdx);
return;
}
if(ring->transferRingEnqueueIdx == 0)
{ ring->transferRingEnqueueIdx = ring->transferRingSize - 1;
ring->transferRingPCS = 1-ring->transferRingPCS;
}
else
{
ring->transferRingEnqueueIdx--;
}
}
}
IOReturn AppleUSBXHCI::GenerateNextPhysicalSegment(TRB *t, IOByteCount *req, UInt32 bufferOffset, IODMACommand *dmaCommand)
{
UInt32 bytesThisTRB=0;
if(*req > 0)
{
UInt32 numSegments;
IODMACommand::Segment64 segments;
UInt64 offset;
IOReturn status;
numSegments = 1;
offset = bufferOffset;
status = dmaCommand->gen64IOVMSegments(&offset, &segments, &numSegments);
if (status || (numSegments != 1)) {
USBLog(1, "AppleUSBXHCI[%p]::GenerateNextPhysicalSegment - Error generating segments, err: %x, numsegments:%d", this, status, (int)numSegments);
if( (status == kIOReturnSuccess) && (numSegments != 1))
{
status = kIOReturnInternalError;
}
return status;
}
SetTRBAddr64(t, segments.fIOVMAddr);
bytesThisTRB = (64 * 1024) - ((UInt32)segments.fIOVMAddr & 0xffff); if(segments.fLength < bytesThisTRB)
{
bytesThisTRB = (UInt32)segments.fLength;
}
if(*req > bytesThisTRB)
{
*req = bytesThisTRB;
}
}
else
{
}
return(kIOReturnSuccess);
}
#define DEBUG_FRAGMENTS (0)
#if DEBUG_FRAGMENTS
void AppleUSBXHCI::PrintTRBs(XHCIRing *ring, const char *s, TRB *StartofFragment, TRB *endofFragment)
{
int enq, deq, siz, deq1, istart, end;
int slot, endp;
UInt32 stream = 0;
char buf[256];
deq = ring->transferRingDequeueIdx;
enq = ring->transferRingEnqueueIdx;
siz = ring->transferRingSize;
slot = ring->slotID;
endp = ring->endpointID;
if(IsStreamsEndpoint(slot, endp))
{
stream = (int)(ring - _slots[slot].rings[endp]);
}
istart = (int)(StartofFragment - ring->transferRing);
if( (istart < 0) || (istart > siz) )
{
USBLog(1, "AppleUSBXHCI[%p]::PrintTRBs - start out of range %p (ring %p, %d), index: %d", this, StartofFragment, ring->transferRing, siz, istart);
return;
}
end = (int)(endofFragment - ring->transferRing);
if( (end < 0) || (end > siz) )
{
USBLog(1, "AppleUSBXHCI[%p]::PrintTRBs - end out of range %p (ring %p, %d), index: %d", this, endofFragment, ring->transferRing, siz, end);
return;
}
USBLog(2, "AppleUSBXHCI[%p]::PrintTRBs - %s %d->%d (@%d, %d, st:%d)", this, s, istart, end, slot, endp, (int)stream);
deq1 = deq-1;
if(deq1 < 0)
{
deq1 = siz-1;
}
if(deq1 == enq)
{
USBLog(1, "AppleUSBXHCI[%p]::PrintTRBs - ring full, enq:%d deq:%d", this, enq, deq);
}
else
{
snprintf(buf, 256, "Idx-: %d, phys:%08lx", deq1, (long unsigned int)(ring->transferRingPhys + deq1*sizeof(TRB)));
PrintTRB(5, &ring->transferRing[deq1], buf);
}
while(enq != deq)
{
char mark[]={" "};
int nextDeq;
nextDeq = deq+1;
if(nextDeq >= siz)
{
nextDeq = 0;
}
if(deq == istart)
{
mark[0] = 'S';
}
else if (deq == end)
{
mark[0] = 'E';
}
else
{
mark[0] = ' ';
}
snprintf(buf, 256, "Idx%s: %d, phys:%08lx", mark, deq, (long unsigned int)(ring->transferRingPhys + deq*sizeof(TRB)));
PrintTRB(5, &ring->transferRing[deq], buf);
deq = nextDeq;
}
}
#endif
void
AppleUSBXHCI::CloseFragment(XHCIRing *ringX, TRB *StartofFragment, UInt32 offsC1)
{
UInt32 offsC;
if(StartofFragment != NULL)
{
int index = (int)(StartofFragment - ringX->transferRing);
offsC = (USBToHostLong(StartofFragment->offsC) & kXHCITRB_C) ^ kXHCITRB_C; offsC1 &= ~kXHCITRB_C; offsC1 |= offsC;
PrintTransferTRB(StartofFragment, ringX, index, offsC1);
IOSync();
StartofFragment->offsC = HostToUSBLong(offsC1);
IOSync();
}
else
{
USBLog(1, "AppleUSBXHCI[%p]::CloseFragment - null StartofFragment", this);
}
}
IOReturn
AppleUSBXHCI::_createTransfer(void *xhciTD,
bool isocTransfer,
IOByteCount transferSize,
UInt32 offsCOverride,
UInt64 runningOffset,
bool interruptNeeded,
bool fragmentedTDs,
UInt32 *firstTRBIndex,
UInt32 *numTRBs,
bool noLogging,
SInt16 *completionIndex)
{
TRB *newTRB;
TRB *StartofFragmentTRB = NULL;
Context *epContext = NULL;
UInt32 offsC = 0;
UInt32 offsC1 = 0;
UInt32 TDSize = 0;
int index, TRBsThisFragment = 0, TRBsThisTD=0;
int slotID;
UInt32 endpointID, maxPacketSize, maxBurst, mult, MBP;
IOByteCount bytesThisTRB;
IOReturn err;
XHCIRing *ringX;
IODMACommand *pDMACommand;
IOByteCount remainingSize = 0;
IOByteCount startOffset = 0;
bool noOpTransfer = false;
bool immediateTransfer = false;
UInt8 immediateBuffer[kMaxImmediateTRBTransferSize];
bool lastInRing = false;
bool lastTDFragment = false;
if( isocTransfer )
{
AppleXHCIIsochTransferDescriptor *isocTD = (AppleXHCIIsochTransferDescriptor*)xhciTD;
IOUSBIsocCommand *pCommand= (IOUSBIsocCommand*)isocTD->command;
ringX = ((AppleXHCIIsochEndpoint*)isocTD->_pEndpoint)->ring;
pDMACommand = pCommand->GetDMACommand();
}
else
{
AppleXHCIAsyncTransferDescriptor *asyncTD = (AppleXHCIAsyncTransferDescriptor*)xhciTD;
IOUSBCommandPtr pCommand = (IOUSBCommandPtr)asyncTD->activeCommand;
ringX = asyncTD->_endpoint->_ring;
pDMACommand = pCommand->GetDMACommand();
lastTDFragment = asyncTD->last;
remainingSize = asyncTD->remAfterThisTD;
startOffset = asyncTD->startOffset;
UInt8 trbType = ((USBToHostLong(offsCOverride) & kXHCITRB_Type_Mask) >> kXHCITRB_Type_Shift);
if (trbType == kXHCITRB_TrNoOp || trbType == kXHCITRB_Status)
{
noOpTransfer = true;
}
if (asyncTD->immediateTransfer)
{
immediateTransfer = true;
bcopy(asyncTD->immediateBuffer, immediateBuffer, kMaxImmediateTRBTransferSize);
}
}
slotID = ringX->slotID;
endpointID = ringX->endpointID;
epContext = GetEndpointContext(slotID, endpointID);
maxPacketSize = GetEpCtxMPS(epContext);
maxBurst = GetEPCtxMaxBurst(epContext) + 1;
mult = GetEPCtxMult(epContext) + 1;
MBP = maxPacketSize * maxBurst * mult;
bool firstFragment = true; #if XHCI_USE_KPRINTF == 0
if (!noLogging)
#endif
{
}
#define DEBUG_CDBS (0)
#if DEBUG_CDBS
if( ((req == 31) || (req == 32)) && ((endpointID & 1) == 0) )
{
UInt8 buf[32];
UInt64 len;
len = dmaCommand->readBytes(0, buf, req);
if (len == req)
{
char data[31*3];
char hex[]="0123456789ABCDEF";
for(int i = 0; i<31; i++)
{
data[i*3] = hex[buf[i] >> 4];
data[i*3+1] = hex[buf[i] & 0xf];
data[i*3+2] = ' ';
}
data[(req-1)*3+2] = 0;
#if XHCI_USE_KPRINTF == 0
if (!noLogging)
#endif
{
USBLog(1, "AppleUSBXHCI[%p]::_createTransfer - %d bytes: %s", this, (int)req, data);
}
}
else
#if XHCI_USE_KPRINTF == 0
if (!noLogging)
#endif
{
USBLog(1, "AppleUSBXHCI[%p]::_createTransfer - readbytes from %d byte transfer (%d)", this, (int)req, (int)len);
}
}
#endif
#if XHCI_USE_KPRINTF == 0
if (!noLogging)
#endif
{
USBLog(7, "AppleUSBXHCI[%p]::_createTransfer - req:%d (@:%d, %d) maxP:%d maxB:%d", this, (int)transferSize, slotID, (int)endpointID, (int)maxPacketSize, (int)maxBurst);
}
if ( maxPacketSize == 0 )
{
#if XHCI_USE_KPRINTF == 0
if (!noLogging)
#endif
{
USBLog(1, "AppleUSBXHCI[%p]::_createTransfer - maxPacketSize is 0, bailing", this);
}
return kIOReturnBadArgument;
}
do
{
newTRB = GetNextTRB(ringX, NULL, &StartofFragmentTRB, (firstFragment && (startOffset == 0)));
if (newTRB == NULL)
{
#if XHCI_USE_KPRINTF == 0
if (!noLogging)
#endif
{
USBLog(1, "AppleUSBXHCI[%p]::_createTransfer - could not get TRB1", this);
}
PutBackTRB(ringX, StartofFragmentTRB);
return(kIOReturnInternalError);
}
TRBsThisFragment++;
TRBsThisTD++;
offsC = (USBToHostLong(newTRB->offsC) & kXHCITRB_C) ^ kXHCITRB_C;
bytesThisTRB = transferSize;
if (!immediateTransfer)
{
err = GenerateNextPhysicalSegment(newTRB, &bytesThisTRB, (UInt32)runningOffset, pDMACommand);
if (err != kIOReturnSuccess)
{
#if XHCI_USE_KPRINTF == 0
if (!noLogging)
#endif
{
USBLog(2, "AppleUSBXHCI[%p]::_createTransfer - GenerateNextPhysicalSegment returned 0x%08x", this, err);
}
PutBackTRB(ringX, newTRB);
return(err);
}
}
else
{
bcopy(immediateBuffer, newTRB, transferSize);
}
if (transferSize == 0)
{
newTRB->offs0 = 0; newTRB->offs4 = 0; newTRB->offs8 = 0;
}
runningOffset += bytesThisTRB;
transferSize -= bytesThisTRB;
#if XHCI_USE_KPRINTF == 0
if (!noLogging)
#endif
{
USBLog(7, "AppleUSBXHCI[%p]::_createTransfer - TRB:%p, req remain: %d, offset: %d, bytesThisTRB: %d", this, newTRB, (int)transferSize, (int)runningOffset, (int)bytesThisTRB);
}
TDSize = (UInt32)((transferSize + remainingSize + maxPacketSize -1) / maxPacketSize);
if (TDSize > 31)
{
TDSize = 31;
}
if ((transferSize == 0) && (!immediateTransfer) && lastTDFragment && (TRBsThisTD > 1))
{
offsC |= kXHCITRB_ENT;
}
newTRB->offs8 = HostToUSBLong(kTransferInterrupter << kXHCITRB_InterrupterTarget_Shift);
if (!noOpTransfer)
{
newTRB->offs8 |= HostToUSBLong( bytesThisTRB | (TDSize << kXHCITRB_TDSize_Shift) );
}
if (offsCOverride == 0)
{
offsC |= (kXHCITRB_Normal << kXHCITRB_Type_Shift);
}
else
{
offsC |= offsCOverride;
offsCOverride = 0;
}
if (!immediateTransfer)
{
offsC |= kXHCITRB_CH;
}
index = (int)(newTRB - ringX->transferRing);
#if XHCI_USE_KPRINTF == 0
if (!noLogging)
#endif
{
USBLog(7, "AppleUSBXHCI[%p]::_createTransfer - TRB: %p, offsC:%lx", this, newTRB, (unsigned long int)offsC);
}
if (StartofFragmentTRB == newTRB)
{
offsC1 = offsC; }
else
{
PrintTransferTRB(newTRB, ringX, index, offsC);
newTRB->offsC = HostToUSBLong(offsC); }
if (!isocTransfer && (runningOffset > 0) && (transferSize > 0) && ((runningOffset % MBP) == 0))
{
#if XHCI_USE_KPRINTF == 0
if (!noLogging)
#endif
{
USBLog(7, "AppleUSBXHCI[%p]::_createTransfer - closing fragment %p with %x at %d (num TRBs:%d)", this, StartofFragmentTRB, (unsigned)offsC1, (int)runningOffset, TRBsThisFragment);
}
CloseFragment(ringX, StartofFragmentTRB, offsC1);
firstFragment = false;
#if DEBUG_FRAGMENTS
PrintTRBs(ringX, "mid", StartofFragmentTRB, newTRB);
#endif
StartofFragmentTRB = NULL;
TRBsThisFragment = 0;
}
#if XHCI_USE_KPRINTF == 0
if (!noLogging)
#endif
{
}
} while(transferSize > 0);
#if XHCI_USE_KPRINTF == 0
if (!noLogging)
#endif
{
}
if (TRBsThisTD == 1)
{
XHCIRing *ring0 = GetRing(slotID, endpointID, 0);
if (ring0 != NULL)
{
#if XHCI_USE_KPRINTF == 0
if (!noLogging)
#endif
{
}
if (interruptNeeded)
{
offsC1 |= kXHCITRB_IOC | kXHCITRB_ISP; }
else
{
if (endpointID & 1)
{ offsC1 |= kXHCITRB_BEI | kXHCITRB_ISP; }
}
offsC1 &= ~(kXHCITRB_CH | kXHCITRB_ENT);
if (index == (ringX->transferRingSize-2))
{
#if XHCI_USE_KPRINTF == 0
if (!noLogging)
#endif
{
}
SetTRBChainBit(&ringX->transferRing[ringX->transferRingSize-1], false);
PrintTransferTRB(&ringX->transferRing[ringX->transferRingSize-1], ringX, ringX->transferRingSize-1);
}
}
else
{
#if XHCI_USE_KPRINTF == 0
if (!noLogging)
#endif
{
}
}
}
else
{
if (fragmentedTDs && !lastTDFragment)
{
newTRB = GetNextTRB(ringX, NULL, &StartofFragmentTRB, (firstFragment && (startOffset == 0)));
}
else
{
newTRB = GetNextTRB(ringX, xhciTD, &StartofFragmentTRB, (firstFragment && (startOffset == 0)));
}
if(newTRB == NULL)
{
PutBackTRB(ringX, StartofFragmentTRB);
return(kIOReturnInternalError);
}
TRBsThisTD++;
index = (int)(newTRB - ringX->transferRing);
#if XHCI_USE_KPRINTF == 0
if (!noLogging)
#endif
{
}
SetTRBAddr64(newTRB, ringX->transferRingPhys + index * sizeof(TRB));
USBTrace( kUSBTXHCI, kTPXHCIUIMCreateTransfer, (uintptr_t)this, 4, index, (int)(ringX->transferRingPhys + index * sizeof(TRB)));
newTRB->offs8 = HostToUSBLong(kTransferInterrupter << kXHCITRB_InterrupterTarget_Shift);
offsC = (USBToHostLong(newTRB->offsC) & kXHCITRB_C) ^ kXHCITRB_C;
offsC |= (kXHCITRB_EventData << kXHCITRB_Type_Shift);
offsC &= ~(kXHCITRB_CH | kXHCITRB_ENT);
if (fragmentedTDs && !lastTDFragment)
{
offsC |= kXHCITRB_CH;
}
if (interruptNeeded)
{
offsC |= kXHCITRB_IOC; }
else
{
if(endpointID & 1)
{ offsC |= kXHCITRB_BEI | kXHCITRB_IOC; }
}
#if XHCI_USE_KPRINTF == 0
if (!noLogging)
#endif
{
USBLog(7, "AppleUSBXHCI[%p]::_createTransfer - Event Data TRB index is %4d @ %p, TD: %p offsC:%lx", this, index, newTRB, xhciTD, (unsigned long int)offsC);
}
PrintTransferTRB(newTRB, ringX, index, offsC);
newTRB->offsC = HostToUSBLong(offsC); }
if (TRBsThisFragment != 0)
{
#if XHCI_USE_KPRINTF == 0
if (!noLogging)
#endif
{
}
CloseFragment(ringX, StartofFragmentTRB, offsC1);
#if DEBUG_FRAGMENTS
PrintTRBs(ringX, "end", StartofFragmentTRB, newTRB);
#endif
}
if (firstTRBIndex)
{
*firstTRBIndex = (int)(StartofFragmentTRB - ringX->transferRing);
}
if (completionIndex)
{
*completionIndex = index;
}
if (numTRBs)
{
*numTRBs = TRBsThisTD;
}
return(kIOReturnSuccess);
}
IOReturn
AppleUSBXHCI::CreateTransfer(IOUSBCommand* command, UInt32 stream)
{
IOReturn status;
IOByteCount req = command->GetReqCount();
int slotID;
UInt32 endpointIdx;
XHCIRing *ringX;
AppleXHCIAsyncEndpoint *pAsyncEP;
int epState;
IOReturn err = kIOReturnInternalError;
short direction;
slotID = GetSlotID(command->GetAddress());
if(slotID == 0)
{
USBLog(1, "AppleUSBXHCI[%p]::CreateTransfer - unallocated slot ID: fn %d, returning kIOUSBEndpointNotFound", this, command->GetAddress());
return(kIOUSBEndpointNotFound);
}
direction = command->GetDirection();
endpointIdx = GetEndpointID(command->GetEndpoint(), direction);
if(stream != 0)
{
}
ringX = GetRing(slotID, endpointIdx, stream);
if(ringX == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::CreateTransfer - ring does not exist (slot:%d, ep:%d, str:%d) ", this, (int)slotID, (int)endpointIdx, (int)stream);
return(kIOReturnBadArgument);
}
if(ringX->TRBBuffer == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::CreateTransfer - ******* unallocated ring: slotID: %d, ring %d", this, slotID, (int)endpointIdx);
return(kIOReturnBadArgument);
}
if(_slots[slotID].deviceNeedsReset)
{
return(AddDummyCommand(ringX, command));
}
if(ringX->beingDeleted)
{
USBLog(2, "AppleUSBXHCI[%p]::CreateTransfer - Endpoint being deleted while new transfer is queued, returning kIOReturnNoDevice (%x)", this, kIOReturnNoDevice);
return(kIOReturnNoDevice);
}
if(ringX->beingReturned)
{
USBLog(2, "AppleUSBXHCI[%p]::CreateTransfer - Endpoint being cleared while new transfer is queued", this);
}
pAsyncEP = OSDynamicCast(AppleXHCIAsyncEndpoint, (AppleXHCIAsyncEndpoint*)ringX->pEndpoint);
if ( pAsyncEP == NULL )
{
USBLog(1, "AppleUSBXHCI[%p]::CreateTransfer - Endpoint not found", this);
return kIOUSBEndpointNotFound;
}
if ( pAsyncEP->_aborting )
{
USBLog(3, "AppleUSBXHCI[%p]::CreateTransfer - sent request while aborting endpoint. Returning kIOReturnNotPermitted", this);
return kIOReturnNotPermitted;
}
epState = GetEpCtxEpState(GetEndpointContext(slotID, endpointIdx));
if ((epState == kXHCIEpCtx_State_Halted) || (epState == kXHCIEpCtx_State_Error))
{
USBLog(3, "AppleUSBXHCI[%p]::CreateTransfer - sent request while endpoint is Halted/Error (%d), returning kIOUSBPipeStalled", this, epState);
return kIOUSBPipeStalled;
}
USBLog(7, "AppleUSBXHCI[%p]::CreateTransfer - Endpoint %d - TRBBuffer: %p, transferRing: %p, transferRingPhys: %p, transferRingSize: %d", this, (int)endpointIdx, ringX->TRBBuffer, ringX->transferRing, (void *)ringX->transferRingPhys, (int)ringX->transferRingSize);
USBLog(7, "AppleUSBXHCI[%p]::CreateTransfer - transferRingPCS: %d, transferRingEnqueueIdx: %d, transferRingDequeueIdx:%d req:%d", this, (int)ringX->transferRingPCS, (int)ringX->transferRingEnqueueIdx, (int)ringX->transferRingDequeueIdx, (int)req);
USBTrace_Start( kUSBTXHCI, kTPXHCIUIMCreateTransfer, (uintptr_t)this, slotID, endpointIdx, req );
status = pAsyncEP->CreateTDs(command, stream);
pAsyncEP->ScheduleTDs();
USBTrace_End( kUSBTXHCI, kTPXHCIUIMCreateTransfer, (uintptr_t)this, slotID, endpointIdx, 0 );
return(status);
}
IOReturn AppleUSBXHCI::AddDummyCommand(XHCIRing *ringX, IOUSBCommand *command)
{
IOReturn status;
UInt32 offsCOverrride;
offsCOverrride = 0;
UInt8 immediateTransferSize = 0;
UInt8 immediateBuffer[kMaxImmediateTRBTransferSize];
bzero(immediateBuffer, kMaxImmediateTRBTransferSize);
USBLog(1, "AppleUSBXHCI[%p]::AddDummyCommand - Device needs to be reset", this);
offsCOverrride |= kXHCITRB_IOC; offsCOverrride |= (kXHCITRB_TrNoOp << kXHCITRB_Type_Shift);
AppleXHCIAsyncEndpoint *pAsyncEP = OSDynamicCast(AppleXHCIAsyncEndpoint, (AppleXHCIAsyncEndpoint*)ringX->pEndpoint);
if (pAsyncEP == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlTransfer - Endpoint not found", this);
return kIOUSBEndpointNotFound;
}
if (pAsyncEP->_aborting)
{
USBLog(3, "AppleUSBXHCI[%p]::UIMCreateControlTransfer - sent request while aborting endpoint. Returning kIOReturnNotPermitted", this);
return kIOReturnNotPermitted;
}
status = pAsyncEP->CreateTDs(command, kNoStreamID, offsCOverrride, immediateTransferSize, immediateBuffer);
pAsyncEP->ScheduleTDs();
return(status);
}
bool AppleUSBXHCI::IsStillConnectedAndEnabled(int SlotID)
{
int port;
UInt32 portSC;
bool status = false;
Context * context = GetSlotContext(SlotID);
if (_lostRegisterAccess)
{
return false;
}
do {
if (!context)
{
break;
}
port = GetSlCtxRootHubPort(context);
portSC = Read32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC);
if (_lostRegisterAccess)
{
break;
}
status = ((portSC & (kXHCIPortSC_CCS|kXHCIPortSC_PED)) == (kXHCIPortSC_CCS|kXHCIPortSC_PED));
} while(0);
return status;
}
#define kUSBSetup kUSBNone
IOReturn
AppleUSBXHCI::UIMCreateControlTransfer( short functionNumber,
short endpointNumber,
IOUSBCommand* command,
IOMemoryDescriptor* CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
#pragma unused(bufferRounding)
int slotID;
UInt32 endpointIdx;
UInt32 offsCOverrride;
XHCIRing *ringX;
IOReturn status = kIOReturnSuccess;
USBLog(7, "AppleUSBXHCI[%p]::UIMCreateControlTransfer - command: %p (%d, %d)", this, command, functionNumber, endpointNumber);
slotID = GetSlotID(functionNumber);
if(slotID == 0)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlTransfer 2 - unallocated slot ID: fn %d, returning kIOUSBEndpointNotFound", this, functionNumber);
return(kIOUSBEndpointNotFound);
}
endpointIdx = 2*endpointNumber+1;
ringX = GetRing(slotID, endpointIdx, 0);
if (ringX == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlTransfer 2 - ring does not exist (slot:%d, ep:%d) ", this, (int)slotID, (int)endpointIdx);
return(kIOReturnBadArgument);
}
if (ringX->TRBBuffer == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlTransfer 2 - ******* unallocated ring, slot:%d id:%d", this, slotID, (int)endpointIdx);
return(kIOReturnBadArgument);
}
if(_slots[slotID].deviceNeedsReset)
{
return(AddDummyCommand(ringX, command));
}
if(ringX->beingDeleted)
{
USBLog(2, "AppleUSBXHCI[%p]::UIMCreateControlTransfer 2 - Endpoint being deleted while new transfer is queued, returning kIOReturnNoDevice (%x)", this, kIOReturnNoDevice);
return(kIOReturnNoDevice);
}
if (functionNumber == 0)
{
}
AppleXHCIAsyncEndpoint *pAsyncEP = OSDynamicCast(AppleXHCIAsyncEndpoint, (AppleXHCIAsyncEndpoint*)ringX->pEndpoint);
if (pAsyncEP == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlTransfer - Endpoint not found", this);
return kIOUSBEndpointNotFound;
}
if (pAsyncEP->_aborting)
{
USBLog(3, "AppleUSBXHCI[%p]::UIMCreateControlTransfer - sent request while aborting endpoint. Returning kIOReturnNotPermitted", this);
return kIOReturnNotPermitted;
}
#if 0
{
Context *epCtx;
int epState;
epCtx = GetEndpointContext(slot, endpointIdx);
epState = GetEpCtxEpState(epCtx);
USBLog(6, "AppleUSBXHCI[%p]::UIMCreateControlTransfer 2 - EP State1: %d", this, epState);
PrintContext(GetSlotContext(slot));
PrintContext(epCtx);
}
#endif
IODMACommand *dmaCommand = command->GetDMACommand();
if (CBP && bufferSize)
{
if (!dmaCommand)
{
USBError(1, "AppleUSBXHCI[%p]::UIMCreateControlTransfer 2 - no dmaCommand", this);
return kIOReturnNoMemory;
}
if (dmaCommand->getMemoryDescriptor() != CBP)
{
USBError(1, "AppleUSBXHCI[%p]::UIMCreateControlTransfer 2 - mismatched CBP (%p) and dmaCommand memory descriptor (%p)", this, CBP, dmaCommand->getMemoryDescriptor());
return kIOReturnInternalError;
}
}
offsCOverrride = 0;
UInt8 immediateTransferSize = 0;
UInt8 immediateBuffer[kMaxImmediateTRBTransferSize];
bzero(immediateBuffer, kMaxImmediateTRBTransferSize);
if(direction == kUSBSetup)
{
int bytesRead;
UInt32 TRT;
IOUSBDevRequest request;
if(bufferSize != kMaxImmediateTRBTransferSize)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlTransfer 2 - SETUP not 8 bytes : %d", this, (int)bufferSize);
return(kIOReturnBadArgument);
}
bytesRead = (int)CBP->readBytes(0, &request, kMaxImmediateTRBTransferSize);
if(bytesRead != kMaxImmediateTRBTransferSize)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlTransfer 2 - could not get 8 bytes of setup : %d", this, bytesRead);
return(kIOReturnInternalError);
}
USBLog(7, "AppleUSBXHCI[%p]::UIMCreateControlTransfer : bmRequestType = 0x%2x bRequest = 0x%2x wValue = 0x%4x wIndex = 0x%4x wLength = 0x%4x",
this, request.bmRequestType, request.bRequest, request.wValue, request.wIndex, request.wLength);
UInt16 theRequest = (request.bRequest << 8) | request.bmRequestType;
if (theRequest == kSetAddress)
{
UInt16 maxPacketSize;
UInt32 newAddress;
UInt8 speed;
int highSpeedHubSlotID;
int highSpeedPort;
Context * epContext;
Context * slotContext;
newAddress = request.wValue;
epContext = GetEndpointContext(slotID, 1);
maxPacketSize = GetEpCtxMPS(epContext);
slotContext = GetSlotContext(slotID);
speed = GetSlCtxSpeed(slotContext);
highSpeedPort = GetSlCtxTTPort(slotContext);
highSpeedHubSlotID = GetSlCtxTTSlot(slotContext);
_fakedSetaddress = true;
status = AddressDevice(slotID, maxPacketSize, true, speed, highSpeedHubSlotID, highSpeedPort);
if (status != kIOReturnSuccess)
{
USBLog(2, "AppleUSBXHCI[%p]::UIMCreateControlTransfer AddressDevice returned 0x%x, bailing...", this, (uint32_t) status);
return status;
}
USBLog(7, "AppleUSBXHCI[%p]::UIMCreateControlTransfer - kUSBSetup: kUSBRqSetAddress err:%x (maxpacket: %d, newAddress: % d) slotID: %d", this, status, (int) maxPacketSize, (int)newAddress, (int)slotID);
_devHub[newAddress] = _devZeroHub;
_devPort[newAddress] = _devZeroPort;
_devMapping[newAddress] = slotID;
_devEnabled[newAddress] = true;
_devZeroHub = 0;
_devZeroPort = 0;
offsCOverrride |= kXHCITRB_IOC; offsCOverrride |= (kXHCITRB_TrNoOp << kXHCITRB_Type_Shift);
}
else
{
USBLog(7, "AppleUSBXHCI[%p]::UIMCreateControlTransfer - kUSBSetup: %x err:%x slotID: %d", this, request.bRequest, status, (int)slotID);
offsCOverrride |= kXHCITRB_IOC; offsCOverrride |= kXHCITRB_IDT; offsCOverrride |= (kXHCITRB_Setup << kXHCITRB_Type_Shift);
if ( request.wLength == 0)
{
TRT = kXHCI_TRT_NoData;
}
else if ( (request.bmRequestType & 0x80) != 0) {
TRT = kXHCI_TRT_InData;
}
else
{
TRT = kXHCI_TRT_OutData;
}
offsCOverrride |= TRT << kXHCITRB_TRT_Shift;
immediateTransferSize = 8;
bcopy(&request, &immediateBuffer, kMaxImmediateTRBTransferSize);
}
}
else if(bufferSize > 0)
{
offsCOverrride |= (kXHCITRB_Data << kXHCITRB_Type_Shift);
if(direction == kUSBIn)
{
offsCOverrride |= kXHCITRB_DIR;
}
immediateTransferSize = kInvalidImmediateTRBTransferSize;
USBLog(7, "AppleUSBXHCI[%p]::UIMCreateControlTransfer - Endpoint %d - ring %p TRBBuffer: %p, transferRing: %p, transferRingPhys: %p, transferRingSize: %d", this, (int)endpointIdx, ringX, ringX->TRBBuffer, ringX->transferRing, (void *)ringX->transferRingPhys, (int)ringX->transferRingSize);
USBLog(7, "AppleUSBXHCI[%p]::UIMCreateControlTransfer - transferRingPCS: %d, transferRingEnqueueIdx: %d, transferRingDequeueIdx:%d req:%d", this, (int)ringX->transferRingPCS, (int)ringX->transferRingEnqueueIdx, (int)ringX->transferRingDequeueIdx, (int)bufferSize);
}
else
{
offsCOverrride |= kXHCITRB_IOC;
if(_fakedSetaddress)
{
USBLog(7, "AppleUSBXHCI[%p]::UIMCreateControlTransfer - Set Address complete status phase (delay)", this);
_devMapping[0] = 0;
_devEnabled[0] = false;
_fakedSetaddress = false;
offsCOverrride |= (kXHCITRB_TrNoOp << kXHCITRB_Type_Shift);
}
else
{
offsCOverrride |= (kXHCITRB_Status << kXHCITRB_Type_Shift);
if(direction == kUSBIn)
{
offsCOverrride |= kXHCITRB_DIR; }
}
USBLog(7, "AppleUSBXHCI[%p]::UIMCreateControlTransfer - setting status TRB: %08lx", this, (long unsigned int)offsCOverrride);
}
if (status == kIOReturnSuccess)
{
status = pAsyncEP->CreateTDs(command, kNoStreamID, offsCOverrride, immediateTransferSize, immediateBuffer);
pAsyncEP->ScheduleTDs();
}
return (status);
}
IOReturn AppleUSBXHCI::UIMCreateControlTransfer(short functionNumber,
short endpointNumber,
IOUSBCompletion completion,
IOMemoryDescriptor *CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
#pragma unused(functionNumber)
#pragma unused(endpointNumber)
#pragma unused(completion)
#pragma unused(CBP)
#pragma unused(bufferRounding)
#pragma unused(bufferSize)
#pragma unused(direction)
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlTransfer 3 - Obsolete method called", this);
return(kIOReturnInternalError);
}
IOReturn AppleUSBXHCI::UIMCreateControlTransfer(short functionNumber,
short endpointNumber,
IOUSBCommand *command,
void *CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
#pragma unused(functionNumber)
#pragma unused(endpointNumber)
#pragma unused(command)
#pragma unused(CBP)
#pragma unused(bufferRounding)
#pragma unused(bufferSize)
#pragma unused(direction)
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateControlTransfer 4 - Obsolete method called", this);
return(kIOReturnInternalError);
}
#pragma mark Bulk
IOReturn AppleUSBXHCI::UIMCreateBulkEndpoint(UInt8 functionNumber,
UInt8 endpointNumber,
UInt8 direction,
UInt8 speed,
UInt8 maxPacketSize)
{
#pragma unused(functionNumber)
#pragma unused(endpointNumber)
#pragma unused(speed)
#pragma unused(maxPacketSize)
#pragma unused(direction)
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateBulkEndpoint 1 - Obsolete method called", this);
return(kIOReturnInternalError);
}
IOReturn AppleUSBXHCI::CreateBulkEndpoint(UInt8 functionNumber,
UInt8 endpointNumber,
UInt8 direction,
UInt8 speed,
UInt16 maxPacketSize,
USBDeviceAddress highSpeedHub,
int highSpeedPort,
UInt32 maxStream,
UInt32 maxBurst) {
#pragma unused(speed)
#pragma unused(highSpeedHub)
#pragma unused(highSpeedPort)
USBLog(3, "AppleUSBXHCI[%p]::UIMCreateBulkEndpoint 2 (%d, %d, %d, %d, %d, %d, %d, %d, %d)", this, functionNumber, endpointNumber, direction, speed, maxPacketSize, (int)highSpeedHub, highSpeedPort, (int)maxStream, (int)maxBurst);
int slotID, endpointIdx, epType;
IOReturn err;
slotID = GetSlotID(functionNumber);
if(slotID == 0)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateBulkEndpoint 2 - Unused slot ID for functionAddress: %d", this, functionNumber);
return(kIOReturnInternalError);
}
epType = kXHCIEpCtx_EPType_BulkOut;
endpointIdx = GetEndpointID(endpointNumber, direction);
if(direction == kUSBIn)
{
epType = kXHCIEpCtx_EPType_BulkIN;
}
err = CreateEndpoint(slotID, endpointIdx, maxPacketSize, 0, epType, maxStream, maxBurst, 0, NULL);
if(err != kIOReturnSuccess)
{
return(err);
}
return(err);
}
IOReturn AppleUSBXHCI::UIMCreateStreams( UInt8 functionNumber,
UInt8 endpointNumber,
UInt8 direction,
UInt32 maxStream)
{
USBLog(3, "AppleUSBXHCI[%p]::UIMCreateStreams %d (@%d, %d, %d)", this, (int)maxStream, (int)functionNumber, (int)endpointNumber, (int)direction);
int slotID, endpointIdx;
IOReturn err;
UInt32 maxPossibleStream;
if (_maxPrimaryStreams == 0)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateStreams - HC does not support streams", this);
return kIOUSBStreamsNotSupported;
}
slotID = GetSlotID(functionNumber);
if(slotID == 0)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateStreams - Unused slot ID for functionAddress: %d", this, functionNumber);
return kIOReturnInternalError;
}
endpointIdx = GetEndpointID(endpointNumber, direction);
if(_slots[slotID].maxStream[endpointIdx] > 0)
{
if(maxStream == 0)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateStreams - Deallocate streams not implimented yet", this);
return kIOReturnInternalError;
}
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateStreams - Endpoint already has streams %d", this, (int)_slots[slotID].maxStream[endpointIdx]);
return kIOReturnBadArgument;
}
maxPossibleStream = _slots[slotID].potentialStreams[endpointIdx];
if(maxPossibleStream <= 1)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateStreams - Not a streams XHCIRing (%d, %d)", this, (int)slotID, (int)endpointIdx);
return kIOReturnBadArgument;
}
_slots[slotID].maxStream[endpointIdx] = maxStream;
if(maxStream > 1)
{
for(UInt32 i = 1; i<=maxStream; i++)
{
err = CreateStream(slotID, endpointIdx, i);
if(err != kIOReturnSuccess)
{
_slots[slotID].maxStream[endpointIdx] = 0;
return err;
}
}
}
else
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateStreams - bad max streams %d", this, (int)maxStream);
return kIOReturnBadArgument;
}
return err;
}
IOReturn AppleUSBXHCI::UIMCreateSSBulkEndpoint(
UInt8 functionNumber,
UInt8 endpointNumber,
UInt8 direction,
UInt8 speed,
UInt16 maxPacketSize,
UInt32 maxStream,
UInt32 maxBurst)
{
if ((maxStream > 0) && (_maxPrimaryStreams == 0))
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateSSBulkEndpoint - Streams not supported: %d", this, (int)maxStream);
return kIOUSBStreamsNotSupported;
}
if(maxStream > (kMaxStreamsPerEndpoint-1))
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateSSBulkEndpoint - Bad max streams param: %d", this, (int)maxStream);
return kIOReturnBadArgument;
}
if(maxStream >= 65533)
{
if(maxStream != 65533)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateSSBulkEndpoint - Bad Max streams %d (fn:%d, ep:%d) ", this, (int)maxStream, (int)functionNumber, (int)endpointNumber);
return kIOReturnBadArgument;
}
else
{
USBLog(3, "AppleUSBXHCI[%p]::UIMCreateSSBulkEndpoint - Maximal streams %d (fn:%d, ep:%d) and we support it!", this, (int)maxStream, (int)functionNumber, (int)endpointNumber);
}
}
if( (maxStream & (maxStream+1)) != 0) {
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateSSBulkEndpoint - Bad Max streams %d not 2^x-1(fn:%d, ep:%d) ", this, (int)maxStream, (int)functionNumber, (int)endpointNumber);
return kIOReturnBadArgument;
}
return CreateBulkEndpoint(functionNumber, endpointNumber, direction, speed, maxPacketSize, 0, 0, maxStream, maxBurst);
}
IOReturn AppleUSBXHCI::UIMCreateBulkEndpoint(UInt8 functionNumber,
UInt8 endpointNumber,
UInt8 direction,
UInt8 speed,
UInt16 maxPacketSize,
USBDeviceAddress highSpeedHub,
int highSpeedPort)
{
USBLog(3, "AppleUSBXHCI[%p]::UIMCreateBulkEndpoint 2", this);
return CreateBulkEndpoint(functionNumber, endpointNumber, direction, speed, maxPacketSize, highSpeedHub, highSpeedPort, 0, 0);
}
IOReturn AppleUSBXHCI::UIMCreateBulkTransfer(short functionNumber,
short endpointNumber,
IOUSBCompletion completion,
IOMemoryDescriptor *CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
#pragma unused(functionNumber)
#pragma unused(endpointNumber)
#pragma unused(completion)
#pragma unused(CBP)
#pragma unused(direction)
#pragma unused(bufferRounding)
#pragma unused(bufferSize)
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateBulkTransfer 1- Obsolete method called", this);
return(kIOReturnInternalError);
}
IOReturn AppleUSBXHCI::UIMCreateBulkTransfer(IOUSBCommand* command)
{
IOReturn err;
UInt32 stream;
#if DEBUG_BUFFER
IOMemoryMap *mmap;
void *mbuf;
USBLog(2, "AppleUSBXHCI[%p]::UIMCreateBulkTransfer 2 - Req: %d", this, (int)command->GetReqCount());
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
if(command->GetDirection() == kUSBIn)
{
mmap = command->GetBuffer()->map();
command->SetUIMScratch(kXHCI_ScratchMMap, (UInt64)mmap); mbuf = (void *)mmap->getVirtualAddress();
mset_pattern4((UInt32 *)mbuf, _debugPattern, command->GetReqCount());
command->SetUIMScratch(kXHCI_ScratchPat, _debugPattern);
_debugPattern = ~_debugPattern;
command->SetUIMScratch(kXHCI_ScratchMark,1); }
#endif
USBLog(7, "AppleUSBXHCI[%p]::UIMCreateBulkTransfer - addr=%d:%d(%s) StreamID: 0x%x, Timeouts:(%d,%d) cbp=%p:%x cback=[%p:%p:%p]) dma=%p mem=%p",
this, command->GetAddress(), command->GetEndpoint(), command->GetDirection() == kUSBIn ? "in" : "out",
(uint32_t)command->GetStreamID(), (uint32_t) command->GetNoDataTimeout(), (uint32_t) command->GetCompletionTimeout(),
command->GetBuffer(), (int)command->GetReqCount(), command->GetUSLCompletion().action, command->GetUSLCompletion().target,
command->GetUSLCompletion().parameter, command->GetDMACommand(), command->GetDMACommand()->getMemoryDescriptor());
stream = command->GetStreamID();
err = CreateTransfer(command, stream);
return(err);
}
IOReturn AppleUSBXHCI::UIMCreateInterruptEndpoint(short functionAddress,
short endpointNumber,
UInt8 direction,
short speed,
UInt16 maxPacketSize,
short pollingRate)
{
#pragma unused(functionAddress)
#pragma unused(endpointNumber)
#pragma unused(speed)
#pragma unused(maxPacketSize)
#pragma unused(direction)
#pragma unused(pollingRate)
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateInterruptEndpoint 1 - Obsolete method called", this);
return(kIOReturnInternalError);
}
IOReturn AppleUSBXHCI::CreateStream(int slotID,
int endpointIdx,
UInt32 stream)
{
XHCIRing *ring, *streamEp;
IOReturn err = kIOReturnSuccess;
StreamContext *ctx;
ring = GetRing(slotID, endpointIdx, 0);
if(ring == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::CreateStream - ring does not exist (slot:%d, ep:%d) ", this, (int)slotID, (int)endpointIdx);
return(kIOReturnBadArgument);
}
if(stream >= (UInt32)ring->transferRingSize)
{
USBLog(1, "AppleUSBXHCI[%p]::CreateStream - stream out of range (%d > %d) (slot:%d, ep:%d) ", this, (int)stream, (int)ring->transferRingSize, (int)slotID, (int)endpointIdx);
return(kIOReturnBadArgument);
}
ctx = (StreamContext *)ring->transferRing;
if(ctx == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::CreateStream - stream context array does not exist (slot:%d, ep:%d) ", this, (int)slotID, (int)endpointIdx);
return(kIOReturnBadArgument);
}
streamEp = GetRing(slotID, endpointIdx, stream);
if(streamEp == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::CreateStream - stream does not exist (slot:%d, ep:%d, stream:%d) ", this, (int)slotID, (int)endpointIdx, (int)stream);
return(kIOReturnBadArgument);
}
streamEp->nextIsocFrame = 0;
streamEp->beingReturned = false;
streamEp->beingDeleted = false;
streamEp->needsDoorbell = false;
if(streamEp->TRBBuffer != NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::CreateStream - stream already exists", this);
return(kIOReturnNoMemory);
}
else
{
err = AllocRing(streamEp);
if(err != kIOReturnSuccess)
{
USBLog(1, "AppleUSBXHCI[%p]::CreateStream - couldn't alloc transfer ring(slot:%d, ep:%d, stream:%d)", this, (int)slotID, (int)endpointIdx, (int)stream);
return(kIOReturnNoMemory);
}
streamEp->endpointType = ring->endpointType;
AppleXHCIAsyncEndpoint *pAsyncEP = OSDynamicCast(AppleXHCIAsyncEndpoint, (AppleXHCIAsyncEndpoint*)ring->pEndpoint);
streamEp->pEndpoint = (void*)AllocateAppleXHCIAsyncEndpoint(streamEp, pAsyncEP->_maxPacketSize, pAsyncEP->_maxBurst, pAsyncEP->_mult);
if(streamEp->pEndpoint == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::CreateStream - couldn't alloc endpoint queue for (slot:%d, ep:%d, stream:%d)", this, (int)slotID, (int)endpointIdx, (int)stream);
return kIOReturnNoMemory;
}
}
SetStreamCtxAddr64(&ctx[stream], streamEp->transferRingPhys, kXHCI_SCT_PrimaryTRB, streamEp->transferRingPCS);
return(err);
}
IOReturn
AppleUSBXHCI::CreateEndpoint(int slotID,
int endpointIdx,
UInt16 maxPacketSize, short pollingRate,
int epType,
UInt8 maxStream,
UInt8 maxBurst, UInt8 mult, void *pEP)
{
USBLog(3, "AppleUSBXHCI[%p]::CreateEndpoint - Sl:%d, ep:%d, mps:%d, poll:%d, typ:%d, maxStream:%d, maxBurst:%d, mult:%d", this, slotID, endpointIdx, maxPacketSize, pollingRate, epType, (int)maxStream, (int)maxBurst, (int)mult);
SInt32 ret = 0;
UInt32 offs00, CErr;
UInt8 speed;
int epState, ctxEntries;
XHCIRing * ringX = NULL;
IOReturn err = kIOReturnSuccess;
TRB t;
bool needToCheckBandwidth = true;
UInt32 ringSizeInPages = 1;
Context * inputContext = NULL;
Context * slotContext = NULL;
AppleXHCIIsochEndpoint *pIsochEP = NULL;
AppleXHCIAsyncEndpoint *pAsyncEP = NULL;
USBLog(3, "AppleUSBXHCI[%p]::CreateEndpoint - inc++ _configuredEndpointCount", this);
ret = TestConfiguredEpCount();
if(err != kIOReturnSuccess)
{
return(err);
}
if( (epType == kXHCIEpCtx_EPType_IsocIn) || (epType == kXHCIEpCtx_EPType_IsocOut) )
{
pIsochEP = (AppleXHCIIsochEndpoint*)pEP;
}
if (pIsochEP)
{
pollingRate = pIsochEP->xhciInterval; ringSizeInPages = pIsochEP->ringSizeInPages;
USBLog(3, "AppleUSBXHCI[%p]::CreateEndpoint - Isoc - mult(%d) MPS(%d) rate(%d) ringPages(%d)", this, mult, maxPacketSize, pollingRate, (int)ringSizeInPages);
}
else
{
if(pollingRate != 0)
{
pollingRate -= 1; }
}
speed = GetSlCtxSpeed(GetSlotContext(slotID));
if (speed == kUSBDeviceSpeedSuper)
{
USBLog(6, "AppleUSBXHCI[%p]::CreateEndpoint - SS endpoint with maxPacketSize(%d) mult(%d) maxBurst(%d)", this, maxPacketSize, mult, maxBurst);
}
else if (speed == kUSBDeviceSpeedHigh)
{
USBLog(6, "AppleUSBXHCI[%p]::CreateEndpoint - HS endpoint with maxPacketSize(%d) mult(%d) maxBurst(%d)", this, maxPacketSize, mult, maxBurst);
}
else
{
USBLog(6, "AppleUSBXHCI[%p]::CreateEndpoint - FS/LS endpoint with maxPacketSize(%d) mult(%d) maxBurst(%d)", this, maxPacketSize, mult, maxBurst);
}
epState = GetEpCtxEpState(GetEndpointContext(slotID, endpointIdx));
if(epState != kXHCIEpCtx_State_Disabled)
{
UInt16 oldMPS = GetEpCtxMPS(GetEndpointContext(slotID, endpointIdx));
if (maxPacketSize <= oldMPS)
{
USBLog(1, "AppleUSBXHCI[%p]::CreateEndpoint - new MPS < old MPS, no need to check bandwidth", this);
needToCheckBandwidth = false;
}
ringX = GetRing(slotID, endpointIdx, maxStream);
}
if (needToCheckBandwidth)
{
err = CheckPeriodicBandwidth(slotID, endpointIdx, maxPacketSize, pollingRate, epType, maxStream, maxBurst, mult);
if (err != kIOReturnSuccess)
{
USBLog(1, "AppleUSBXHCI[%p]::CreateEndpoint - CheckPeriodicBandwidth returned err (0x%x)", this, (int)err);
return err;
}
}
if (ringX == NULL)
{
ringX = CreateRing(slotID, endpointIdx, maxStream);
if(ringX == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::CreateEndpoint - ring does not exist (slot:%d, ep:%d) ", this, (int)slotID, (int)endpointIdx);
return(kIOReturnBadArgument);
}
}
if (pIsochEP)
{
ringX->pEndpoint = pEP;
}
else
{
ringX->pEndpoint = AllocateAppleXHCIAsyncEndpoint(ringX, maxPacketSize, maxBurst, mult);
if(ringX->pEndpoint == NULL)
{
return kIOReturnNoMemory;
}
USBLog(3, "AppleUSBXHCI[%p]::CreateEndpoint - inc ConfiguredEpCount (async)", this);
IncConfiguredEpCount();
}
ringX->endpointType = epType;
ringX->nextIsocFrame = 0;
ringX->beingReturned = false;
ringX->beingDeleted = false;
ringX->needsDoorbell = false;
GetInputContext();
inputContext = GetInputContextByIndex(0);
epState = GetEpCtxEpState(GetEndpointContext(slotID, endpointIdx));
if(epState != kXHCIEpCtx_State_Disabled)
{
if(epState == kXHCIEpCtx_State_Running)
{
StopEndpoint(slotID, endpointIdx);
}
USBLog(3, "AppleUSBXHCI[%p]::CreateEndpoint - ring already exists (slot:%d, ep:%d), setting MPS to %d ", this, slotID, endpointIdx, maxPacketSize);
inputContext->offs00 = HostToUSBLong(1 << endpointIdx);
}
inputContext->offs04 = HostToUSBLong((1 << endpointIdx) | 1);
inputContext = GetInputContextByIndex(1);
slotContext = GetSlotContext(slotID);
*inputContext = *slotContext;
offs00 = USBToHostLong(inputContext->offs00);
ctxEntries = (offs00 & kXHCISlCtx_CtxEnt_Mask) >> kXHCISlCtx_CtxEnt_Shift;
if(endpointIdx > ctxEntries)
{
ctxEntries = endpointIdx;
offs00 = (offs00 & ~kXHCISlCtx_CtxEnt_Mask) | (ctxEntries << kXHCISlCtx_CtxEnt_Shift);
}
offs00 &= ~kXHCISlCtx_resZ0Bit; inputContext->offs00 = HostToUSBLong(offs00);
inputContext->offs0C = 0; inputContext->offs10 = 0;
inputContext->offs14 = 0;
inputContext->offs18 = 0;
inputContext->offs1C = 0;
CErr = 3;
if( (epType == kXHCIEpCtx_EPType_IsocOut) || (epType == kXHCIEpCtx_EPType_IsocIn) )
{
CErr = 0;
}
inputContext = GetInputContextByIndex(endpointIdx + 1);
SetEPCtxInterval(inputContext, pollingRate);
SetEPCtxCErr(inputContext, CErr);
SetEPCtxEpType(inputContext, epType);
SetEPCtxMult(inputContext, mult);
SetEPCtxMaxBurst(inputContext, maxBurst);
SetEPCtxMPS(inputContext,maxPacketSize);
if(ringX->TRBBuffer != NULL)
{
if(maxStream > 1)
{
USBLog(1, "AppleUSBXHCI[%p]::CreateEndpoint - create streams endpoint which already exists", this);
return(kIOReturnNoMemory);
}
ReinitTransferRing(slotID, endpointIdx, 0);
}
else
{
if(maxStream > 1)
{
err = AllocStreamsContextArray(ringX, maxStream);
}
else
{
err = AllocRing(ringX, ringSizeInPages);
}
if(err != kIOReturnSuccess)
{
ReleaseInputContext();
USBLog(1, "AppleUSBXHCI[%p]::CreateEndpoint - couldn't alloc transfer ring", this);
return(kIOReturnNoMemory);
}
if (pIsochEP)
pIsochEP->ring = ringX;
}
SetEPCtxDQpAddr64(inputContext, ringX->transferRingPhys+ringX->transferRingDequeueIdx*sizeof(TRB));
if (maxStream > 1)
{
UInt32 streams;
streams = (maxStream+1)/2; int width = 0;
while(1)
{
streams /= 2;
if(streams == 0)
break;
width++;
};
USBLog(2, "AppleUSBXHCI[%p]::CreateEndpoint - x maxStream: %d maxPStreams: %d", this, (int)maxStream, (int)width);
SetEPCtxLSA(inputContext, 1);
SetEPCtxMaxPStreams(inputContext, width);
}
else
{
SetEPCtxDCS(inputContext, ringX->transferRingPCS);
}
SetEPCtxAveTRBLen(inputContext, maxPacketSize );
if(pollingRate != 0)
{ SetEPCtxMaxESITPayload(inputContext, maxPacketSize * (maxBurst+1));
}
#if 0
USBLog(2, "AppleUSBXHCI[%p]::CreateEndpoint - Context entries: %d", this, (int)ctxEntries);
for(int i = 0; i<=ctxEntries+1; i++)
{
PrintContext(GetInputContextByIndex(i));
}
#endif
ClearTRB(&t, true);
SetTRBAddr64(&t, _inputContextPhys);
SetTRBSlotID(&t, slotID);
ret = WaitForCMD(&t, kXHCITRB_ConfigureEndpoint);
ReleaseInputContext();
if((ret == CMD_NOT_COMPLETED) || (ret <= MakeXHCIErrCode(0)))
{
if(ret == MakeXHCIErrCode(kXHCITRB_CC_ResourceErr))
{
USBLog(1, "AppleUSBXHCI[%p]::CreateEndpoint - configure endpoint resource error, run out of rings? Returning: %x", this, kIOUSBEndpointCountExceeded);
return(kIOUSBEndpointCountExceeded);
}
USBLog(1, "AppleUSBXHCI[%p]::CreateEndpoint - configure endpoint failed:%d", this, (int)ret);
if( (ret == MakeXHCIErrCode(kXHCITRB_CC_CtxParamErr)) | (ret == MakeXHCIErrCode(kXHCITRB_CC_TRBErr)) ) {
USBLog(1, "AppleUSBXHCI[%p]::CreateEndpoint - Input Context 0", this);
PrintContext(GetInputContextByIndex(0));
USBLog(1, "AppleUSBXHCI[%p]::CreateEndpoint - Input Context 1", this);
PrintContext(GetInputContextByIndex(1));
USBLog(1, "AppleUSBXHCI[%p]::CreateEndpoint - Input Context X", this);
PrintContext(GetInputContextByIndex(endpointIdx+1));
}
return(kIOReturnInternalError);
}
USBLog(3, "AppleUSBXHCI[%p]::CreateEndpoint - enabling endpoint succeeded", this);
return(kIOReturnSuccess);
}
#pragma mark Interrupt
IOReturn
AppleUSBXHCI::UIMCreateSSInterruptEndpoint( short functionAddress,
short endpointNumber,
UInt8 direction,
short speed,
UInt16 maxPacketSize,
short pollingRate,
UInt32 maxBurst) {
if (maxPacketSize > kUSB_EPDesc_MaxMPS)
{
maxPacketSize = (maxPacketSize + maxBurst) / (maxBurst + 1);
}
return CreateInterruptEndpoint(functionAddress, endpointNumber, direction, speed, maxPacketSize, pollingRate, 0, 0, maxBurst);
}
IOReturn
AppleUSBXHCI::UIMCreateInterruptEndpoint( short functionAddress,
short endpointNumber,
UInt8 direction,
short speed,
UInt16 maxPacketSize, short pollingRate,
USBDeviceAddress highSpeedHub,
int highSpeedPort)
{
int maxBurst = 0;
if (maxPacketSize > kUSB_EPDesc_MaxMPS)
{
maxBurst = ((maxPacketSize + kUSB_EPDesc_MaxMPS - 1) / kUSB_EPDesc_MaxMPS); maxPacketSize = (maxPacketSize + maxBurst - 1) / maxBurst; maxBurst--;
}
return CreateInterruptEndpoint(functionAddress, endpointNumber, direction, speed, maxPacketSize, pollingRate, highSpeedHub, highSpeedPort, maxBurst);
}
IOReturn
AppleUSBXHCI::CreateInterruptEndpoint(short functionAddress,
short endpointNumber,
UInt8 direction,
short speed,
UInt16 maxPacketSize, short pollingRate,
USBDeviceAddress highSpeedHub,
int highSpeedPort,
UInt32 maxBurst) {
if( (functionAddress == _rootHubFuncAddressSS) || (functionAddress == _rootHubFuncAddressHS) )
{
USBLog(3, "AppleUSBXHCI[%p]::UIMCreateInterruptEndpoint 2 - starting root hub timer", this);
return RootHubStartTimer32(pollingRate);
}
if (0 == functionAddress)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateInterruptEndpoint 2 - called for address zero", this);
return(kIOReturnInternalError);
}
USBLog(3, "AppleUSBXHCI[%p]::UIMCreateInterruptEndpoint 2 (%d, %d, %d, %d, %d, %d, %d, %d, %d)", this, functionAddress, endpointNumber, direction, speed, maxPacketSize, pollingRate, highSpeedHub, highSpeedPort, (int)maxBurst);
if (pollingRate == 16 )
{
USBLog(3, "AppleUSBXHCI[%p]::UIMCreateInterruptEndpoint 2 ••• HACK: PollingRate was 16. Will set to 15", this);
pollingRate = 15;
}
int slotID, endpointIdx, epType;
IOReturn err;
slotID = GetSlotID(functionAddress);
if(slotID == 0)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateInterruptEndpoint 2 - Unused slot ID for functionAddress: %d", this, functionAddress);
return(kIOReturnInternalError);
}
epType = kXHCIEpCtx_EPType_IntOut;
endpointIdx = GetEndpointID(endpointNumber, direction);
if(direction == kUSBIn)
{
epType = kXHCIEpCtx_EPType_IntIn;
}
if(speed < kUSBDeviceSpeedHigh)
{
if( (pollingRate == 0) || (pollingRate < 0) )
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateInterruptEndpoint 2 - bad polling rate: %d", this, pollingRate);
return(kIOReturnInternalError);
}
short logInterval;
logInterval = 3;
while(pollingRate)
{
logInterval++;
pollingRate >>= 1;
}
pollingRate = logInterval;
}
err = CreateEndpoint(slotID, endpointIdx, maxPacketSize, pollingRate, epType, 0, maxBurst, 0, NULL);
return(err);
}
IOReturn AppleUSBXHCI::UIMCreateInterruptTransfer(short functionNumber,
short endpointNumber,
IOUSBCompletion completion,
IOMemoryDescriptor *CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
#pragma unused(functionNumber)
#pragma unused(endpointNumber)
#pragma unused(completion)
#pragma unused(CBP)
#pragma unused(direction)
#pragma unused(bufferRounding)
#pragma unused(bufferSize)
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateInterruptTransfer 1 - Obsolete method called", this);
return(kIOReturnInternalError);
}
IOReturn AppleUSBXHCI::UIMCreateInterruptTransfer(IOUSBCommand* command)
{
IOReturn status = kIOReturnSuccess;
IOUSBCompletion completion = command->GetUSLCompletion();
IOMemoryDescriptor* buffer = command->GetBuffer();
UInt16 address = command->GetAddress();
if( (address == _rootHubFuncAddressSS) || (address == _rootHubFuncAddressHS) )
{
IODMACommand *dmaCommand = command->GetDMACommand();
IOMemoryDescriptor *memDesc = dmaCommand ? (IOMemoryDescriptor*)dmaCommand->getMemoryDescriptor() : NULL;
if (memDesc)
{
USBLog(3, "AppleUSBXHCI[%p]::UIMCreateInterruptTransfer - root hub interrupt transfer - clearing unneeded memDesc (%p) from dmaCommand (%p)", this, memDesc, dmaCommand);
dmaCommand->clearMemoryDescriptor();
}
if (command->GetEndpoint() == 1)
{
UInt8 speed = 0;
if(_rootHubFuncAddressSS == address)
{
speed = kUSBDeviceSpeedSuper;
}
else
{
speed = kUSBDeviceSpeedHigh;
}
IOOptionBits options = 0;
options = (address << kUSBAddress_Shift) & kUSBAddress_Mask;
options |= (speed << kUSBSpeed_Shift) & kUSBSpeed_Mask;
buffer->setTag(options);
status = RootHubQueueInterruptRead(buffer, (UInt32)command->GetReqCount(), completion);
}
else
{
Complete(completion, kIOUSBEndpointNotFound, (UInt32)command->GetReqCount());
status = kIOUSBEndpointNotFound;
}
return status;
}
status = CreateTransfer(command, 0);
return(status);
}
#pragma mark Isoch
IOReturn AppleUSBXHCI::UIMCreateIsochEndpoint(short functionAddress,
short endpointNumber,
UInt32 maxPacketSize,
UInt8 direction)
{
#pragma unused(functionAddress)
#pragma unused(endpointNumber)
#pragma unused(maxPacketSize)
#pragma unused(direction)
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateIsochEndpoint 1- Unimplimented method called", this);
return(kIOReturnInternalError);
}
IOReturn AppleUSBXHCI::UIMCreateIsochEndpoint(short functionAddress,
short endpointNumber,
UInt32 maxPacketSize,
UInt8 direction,
USBDeviceAddress highSpeedHub,
int highSpeedPort)
{
#pragma unused(functionAddress)
#pragma unused(endpointNumber)
#pragma unused(maxPacketSize)
#pragma unused(direction)
#pragma unused(highSpeedHub)
#pragma unused(highSpeedPort)
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateIsochEndpoint 2- Unimplimented method called", this);
return(kIOReturnInternalError);
}
IOReturn AppleUSBXHCI::UIMCreateSSIsochEndpoint(short functionAddress,
short endpointNumber,
UInt32 maxPacketSize,
UInt8 direction,
UInt8 interval,
UInt32 maxBurstAndMult) {
int maxBurst, mult;
maxBurst = (maxBurstAndMult & 0xFF);
mult = ((maxBurstAndMult & 0xFF00) >> 8);
if (maxPacketSize > kUSB_EPDesc_MaxMPS)
{
maxPacketSize /= ((maxBurst+1) * (mult+1));
}
return CreateIsochEndpoint(functionAddress, endpointNumber, maxPacketSize, direction, interval, maxBurst, mult);
}
IOReturn AppleUSBXHCI::UIMCreateIsochEndpoint(short functionAddress,
short endpointNumber,
UInt32 maxPacketSize,
UInt8 direction,
USBDeviceAddress highSpeedHub,
int highSpeedPort,
UInt8 interval)
{
#pragma unused(highSpeedHub)
#pragma unused(highSpeedPort)
int maxBurst = 0;
if (maxPacketSize > kUSB_EPDesc_MaxMPS)
{
maxBurst = ((maxPacketSize + kUSB_EPDesc_MaxMPS - 1) / kUSB_EPDesc_MaxMPS); maxPacketSize = (maxPacketSize + maxBurst - 1) / maxBurst; maxBurst--; }
return CreateIsochEndpoint(functionAddress, endpointNumber, maxPacketSize, direction, interval, maxBurst, 0);
}
IOReturn
AppleUSBXHCI::CreateIsochEndpoint(short functionAddress,
short endpointNumber,
UInt32 maxPacketSize, UInt8 direction,
UInt8 interval,
UInt8 maxBurst, UInt8 mult) {
AppleXHCIIsochEndpoint * pEP;
int slotID, endpointIdx, epType;
int TRBsPerTransaction, TRBsPerPage, TRBsNeededInRing;
IOReturn err;
UInt8 xhciInterval;
UInt8 deviceSpeed;
UInt32 desiredFullMPS = maxPacketSize * (maxBurst + 1) * (mult + 1);
USBTrace_Start(kUSBTXHCI, kTPXHCIUIMCreateIsocEndpoint, (uintptr_t)this, 0, 0, 0);
USBLog(3, "AppleUSBXHCI[%p]::CreateIsochEndpoint, interval: %d, maxBurst: %d mult: %d", this, interval, maxBurst, mult);
slotID = GetSlotID(functionAddress);
if(slotID == 0)
{
USBLog(1, "AppleUSBXHCI[%p]::CreateIsochEndpoint - Unused slot ID for functionAddress: %d", this, functionAddress);
return kIOReturnInternalError;
}
endpointIdx = GetEndpointID(endpointNumber, direction);
if(direction == kUSBIn)
{
epType = kXHCIEpCtx_EPType_IsocIn;
}
else
{
epType = kXHCIEpCtx_EPType_IsocOut;
}
deviceSpeed = GetSlCtxSpeed(GetSlotContext(slotID));
if (deviceSpeed == kUSBDeviceSpeedLow)
{
USBLog(1, "AppleUSBXHCI[%p]::CreateIsochEndpoint - can't have LS Isoch", this);
return kIOReturnInternalError;
}
if (deviceSpeed == kUSBDeviceSpeedFull)
{
if (interval != 1)
{
USBLog(1, "AppleUSBXHCI[%p]::CreateIsochEndpoint - unexpected FS Isoch interval of %d", this, interval);
}
interval = 8; xhciInterval = 3; }
else
{
xhciInterval = interval - 1; }
pEP = OSDynamicCast(AppleXHCIIsochEndpoint, FindIsochronousEndpoint(functionAddress, endpointNumber, direction, NULL));
if (pEP)
{
UInt32 curFullMPS;
UInt8 epState;
USBLog(5,"AppleUSBXHCI[%p]::CreateIsochEndpoint endpoint already exists, attempting to change maxPacketSize to %d", this, (uint32_t)maxPacketSize);
curFullMPS = pEP->maxPacketSize * pEP->mult * pEP->maxBurst;
if (desiredFullMPS == curFullMPS)
{
USBLog(4, "AppleUSBXHCI[%p]::CreateIsochEndpoint maxPacketSize (%d) the same, no change", this, (uint32_t)maxPacketSize);
USBTrace_End(kUSBTXHCI, kTPXHCIUIMCreateIsocEndpoint, (uintptr_t)this, 0, 0, 0);
return kIOReturnSuccess;
}
epState = GetEpCtxEpState(GetEndpointContext(slotID, endpointIdx));
if (epState == kXHCIEpCtx_State_Running)
{
StopEndpoint(slotID, endpointIdx);
}
}
else
{
pEP = OSDynamicCast(AppleXHCIIsochEndpoint, CreateIsochronousEndpoint(functionAddress, endpointNumber, direction));
if (pEP == NULL)
return kIOReturnNoMemory;
USBLog(3, "AppleUSBXHCI[%p]::CreateIsochEndpoint - inc ConfiguredEpCount (isoc)", this);
IncConfiguredEpCount();
pEP->speed = deviceSpeed;
}
pEP->maxBurst = maxBurst + 1; pEP->mult = mult + 1; pEP->maxPacketSize = maxPacketSize;
pEP->interval = (1 << xhciInterval); pEP->xhciInterval = xhciInterval;
if (pEP->interval >= kMaxTransfersPerFrame)
{
pEP->transactionsPerFrame = 1;
pEP->msBetweenTDs = pEP->interval / kMaxTransfersPerFrame;
}
else
{
pEP->transactionsPerFrame = kMaxTransfersPerFrame / pEP->interval;
pEP->msBetweenTDs = 1;
}
TRBsPerTransaction = ((pEP->maxPacketSize * pEP->mult * pEP->maxBurst) / PAGE_SIZE) + 3; TRBsPerPage = PAGE_SIZE / sizeof(TRB);
pEP->maxTRBs = TRBsPerTransaction * pEP->transactionsPerFrame;
TRBsNeededInRing = pEP->maxTRBs * kIsocRingSizeinMS;
USBLog(5, "AppleUSBXHCI[%p]::CreateIsochEndpoint - TRBsPerTransaction(%d) TRBsPerPage(%d) TRBsNeededInRing(%d)", this, TRBsPerTransaction, TRBsPerPage, TRBsNeededInRing);
pEP->ringSizeInPages = (TRBsNeededInRing + TRBsPerPage - 1) / TRBsPerPage;
pEP->inSlot = kNumTDSlots + 1;
pEP->print(6);
err = CreateEndpoint(slotID, endpointIdx, pEP->maxPacketSize, interval, epType, 0, maxBurst, mult, pEP);
USBTrace_End(kUSBTXHCI, kTPXHCIUIMCreateIsocEndpoint, (uintptr_t)this, 0, 0, 0);
return err;
}
IOReturn AppleUSBXHCI::UIMCreateIsochTransfer(short functionAddress,
short endpointNumber,
IOUSBIsocCompletion completion,
UInt8 direction,
UInt64 frameStart,
IOMemoryDescriptor *pBuffer,
UInt32 frameCount,
IOUSBIsocFrame *pFrames)
{
#pragma unused(functionAddress)
#pragma unused(endpointNumber)
#pragma unused(completion)
#pragma unused(direction)
#pragma unused(frameStart)
#pragma unused(pBuffer)
#pragma unused(frameCount)
#pragma unused(pFrames)
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateIsochTransfer- Unimplimented method called", this);
return(kIOReturnInternalError);
}
IOReturn
AppleUSBXHCI::UIMCreateIsochTransfer(IOUSBIsocCommand *command)
{
IOReturn err;
UInt64 maxOffset;
UInt64 curFrameNumber = GetFrameNumber();
UInt64 frameDiff;
UInt32 diff32;
UInt32 bufferSize;
AppleXHCIIsochEndpoint * pEP;
AppleXHCIIsochTransferDescriptor * pNewITD = NULL;
IOByteCount transferOffset;
UInt32 buffPtrSlot, transfer, frameNumberIncrease, frameCount=0, framesBeforeInterrupt;
unsigned i,j;
USBPhysicalAddress32 *buffP, *buffHighP;
UInt32 *transactionPtr = 0;
UInt32 *savedTransactionPtr = 0;
UInt32 pageOffset=0;
UInt32 page;
UInt32 frames;
UInt32 trLen;
IOPhysicalAddress dmaStartAddr;
UInt32 dmaAddrHighBits;
IOByteCount segLen;
bool lowLatency = command->GetLowLatency();
UInt32 updateFrequency = command->GetUpdateFrequency();
IOUSBIsocFrame * pFrames = command->GetFrameList();
IOUSBLowLatencyIsocFrame * pLLFrames = (IOUSBLowLatencyIsocFrame *)pFrames;
UInt32 transferCount = command->GetNumFrames();
UInt64 frameNumberStart = command->GetStartFrame();
UInt64 offset;
IODMACommand::Segment64 segments;
UInt32 numSegments;
UInt32 transfersPerTD;
UInt32 numberOfTDs = 0;
UInt32 baseTransferIndex;
UInt32 epInterval;
IOReturn status;
bool newFrame = false;
USBLog(7, "+AppleUSBXHCI[%p]::UIMCreateIsochTransfer - frameNumberStart(%lld) curFrameNumber(%lld)", this, frameNumberStart, curFrameNumber);
USBTrace_Start(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, (command->GetNumFrames() << 24) | (command->GetDirection() << 16) |(command->GetAddress() << 8) | command->GetEndpoint(), frameNumberStart, curFrameNumber);
if ( (command->GetNumFrames() == 0) || (command->GetNumFrames() > 1000) )
{
USBLog(3,"AppleUSBXHCI[%p]::UIMCreateIsochTransfer bad frameCount: %d", this, (uint32_t)command->GetNumFrames());
USBTrace(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, frameNumberStart, command->GetNumFrames(), 0);
return kIOReturnBadArgument;
}
pEP = OSDynamicCast(AppleXHCIIsochEndpoint, FindIsochronousEndpoint(command->GetAddress(), command->GetEndpoint(), command->GetDirection(), NULL));
if (pEP == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateIsochTransfer - Endpoint not found", this);
USBTrace(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, (command->GetDirection() << 16) |(command->GetAddress() << 8) | command->GetEndpoint(), 0, 1);
return kIOUSBEndpointNotFound;
}
if ( pEP->aborting )
{
USBLog(3, "AppleUSBXHCI[%p]::UIMCreateIsochTransfer - sent request while aborting endpoint. Returning kIOReturnNotPermitted", this);
USBTrace(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, (command->GetDirection() << 16) |(command->GetAddress() << 8) | command->GetEndpoint(), 0, 2);
return kIOReturnNotPermitted;
}
if(pEP->ring == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateIsochTransfer - ring does not exist (addr:%d, ep:%d, dirn:%d) ", this, (int)command->GetAddress(), command->GetEndpoint(), command->GetDirection());
USBTrace(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, (command->GetDirection() << 16) |(command->GetAddress() << 8) | command->GetEndpoint(), 0, 3);
return(kIOReturnBadArgument);
}
if(pEP->ring->TRBBuffer == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMCreateIsochTransfer - ******* unallocated ring, (addr:%d, ep:%d, dirn:%d) ", this, (int)command->GetAddress(), command->GetEndpoint(), command->GetDirection());
USBTrace(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, (command->GetDirection() << 16) |(command->GetAddress() << 8) | command->GetEndpoint(), 0, 4);
return(kIOReturnBadArgument);
}
if(pEP->ring->beingDeleted)
{
USBLog(2, "AppleUSBXHCI[%p]::UIMCreateIsochTransfer - Endpoint being deleted while new transfer is queued, returning kIOReturnNoDevice (%x)", this, kIOReturnNoDevice);
USBTrace(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, (command->GetDirection() << 16) |(command->GetAddress() << 8) | command->GetEndpoint(), 0, 5);
return(kIOReturnNoDevice);
}
if (frameNumberStart == kAppleUSBSSIsocContinuousFrame)
{
pEP->continuousStream = true;
}
else
{
if (frameNumberStart < pEP->firstAvailableFrame)
{
USBLog(3,"AppleUSBXHCI[%p]::UIMCreateIsochTransfer: no overlapping frames - EP (%p) frameNumberStart: %qd, pEP->firstAvailableFrame: %qd. Returning 0x%x", this, pEP, frameNumberStart, pEP->firstAvailableFrame, kIOReturnIsoTooOld);
USBTrace(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, frameNumberStart, pEP->firstAvailableFrame, 6);
return kIOReturnIsoTooOld;
}
if (pEP->continuousStream)
{
return kIOReturnBadArgument;
}
}
maxOffset = 1024;
if (!pEP->continuousStream)
{
if (frameNumberStart != pEP->firstAvailableFrame)
{
newFrame = true;
}
pEP->firstAvailableFrame = frameNumberStart;
if (frameNumberStart <= curFrameNumber)
{
if (frameNumberStart < (curFrameNumber - maxOffset))
{
USBLog(3,"AppleUSBXHCI[%p]::UIMCreateIsochTransfer request frame WAY too old. frameNumberStart: %d, curFrameNumber: %d. Returning 0x%x", this, (uint32_t)frameNumberStart, (uint32_t) curFrameNumber, kIOReturnIsoTooOld);
USBTrace(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, frameNumberStart, (curFrameNumber - maxOffset), 7);
return kIOReturnIsoTooOld;
}
USBLog(5,"AppleUSBXHCI[%p]::UIMCreateIsochTransfer WARNING! curframe later than requested, expect some notSent errors! frameNumberStart: %d, curFrameNumber: %d. USBIsocFrame Ptr: %p, First ITD: %p", this, (uint32_t)frameNumberStart, (uint32_t)curFrameNumber, command->GetFrameList(), pEP->toDoEnd);
}
else
{ if (frameNumberStart > (curFrameNumber + maxOffset))
{
USBLog(3,"AppleUSBXHCI[%p]::UIMCreateIsochTransfer request frame too far ahead! frameNumberStart: %d, curFrameNumber: %d", this, (uint32_t)frameNumberStart, (uint32_t) curFrameNumber);
USBTrace(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, frameNumberStart, (curFrameNumber + maxOffset), 8);
return kIOReturnIsoTooNew;
}
frameDiff = frameNumberStart - curFrameNumber;
diff32 = (UInt32)frameDiff;
if (diff32 < _istKeepAwayFrames)
{
USBLog(5,"AppleUSBXHCI[%p]::UIMCreateIsochTransfer WARNING! - frameNumberStart less than 2 ms (is %d)! frameNumberStart: %d, curFrameNumber: %d", this, (uint32_t) diff32, (uint32_t)frameNumberStart, (uint32_t) curFrameNumber);
USBTrace(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, frameDiff, _istKeepAwayFrames, 9);
}
}
}
if (!command->GetDMACommand() || !command->GetDMACommand()->getMemoryDescriptor())
{
USBError(1, "AppleUSBXHCI[%p]::UIMCreateIsochTransfer - no DMA Command or missing memory descriptor", this);
USBTrace(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, (uintptr_t)command->GetDMACommand(), command->GetDMACommand() ? (uintptr_t)command->GetDMACommand()->getMemoryDescriptor() : 0, 10);
return kIOReturnBadArgument;
}
epInterval = pEP->interval;
transferOffset = 0;
transfersPerTD = (epInterval >= kMaxTransfersPerFrame ? 1 : (kMaxTransfersPerFrame / epInterval));
frameNumberIncrease = (epInterval <= kMaxTransfersPerFrame ? 1 : epInterval / kMaxTransfersPerFrame);
USBLog(7,"AppleUSBXHCI[%p]::UIMCreateIsochTransfer transfersPerTD will be %d, frameNumberIncrease = %d", this, (uint32_t)transfersPerTD, (uint32_t)frameNumberIncrease);
USBTrace(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, transfersPerTD, frameNumberIncrease, 11);
if ( frameNumberIncrease > 1 )
{
epInterval = 8;
}
if (frameNumberStart < pEP->firstAvailableFrame)
{
USBLog(3,"AppleUSBXHCI[%p]::UIMCreateIsochTransfer: no overlapping frames - EP (%p) frameNumberStart: %qd, pEP->firstAvailableFrame: %qd. Returning 0x%x", this, pEP, frameNumberStart, pEP->firstAvailableFrame, kIOReturnIsoTooOld);
USBTrace(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, frameNumberStart, pEP->firstAvailableFrame, 12);
return kIOReturnIsoTooOld;
}
maxOffset = 1024;
if (!pEP->continuousStream)
{
if (frameNumberStart != pEP->firstAvailableFrame)
{
newFrame = true;
if(frameNumberIncrease > 1)
{
USBLog(7,"AppleUSBXHCI[%p]::UIMCreateIsochTransfer for periodic isoc frameNumberStart: %lld frameNumberIncrease: %d", this, frameNumberStart, frameNumberIncrease);
if ((frameNumberStart % frameNumberIncrease) != 0)
{
USBLog(3,"AppleUSBXHCI[%p]::UIMCreateIsochTransfer frameNumberStart is not on ESIT boundary returning error kIOReturnBadArgument frameNumberStart: %lld ", this, frameNumberStart );
USBTrace(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, frameNumberStart, frameNumberStart % frameNumberIncrease, 13);
return kIOReturnBadArgument;
}
}
}
pEP->firstAvailableFrame = frameNumberStart;
}
USBLog(7, "AppleUSBXHCI[%p]::UIMCreateIsochTransfer - pEP (%p) command (%p)", this, pEP, command);
if (!pEP->continuousStream)
{
if (transferCount % transfersPerTD != 0)
{
USBLog(3,"AppleUSBXHCI[%p]::UIMCreateIsochTransfer Isoch -- incomplete final TD in transfer, command->GetNumFrames() is %d, pEP->Interval is %d and so transfersPerTD is %d",
this, (int ) command->GetNumFrames(), (int ) epInterval, (int ) transfersPerTD);
USBTrace(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, command->GetNumFrames(), transferCount % transfersPerTD, 14);
return kIOReturnBadArgument;
}
}
if (updateFrequency == 0)
updateFrequency = kMaxFramesWithoutInterrupt;
if(lowLatency && (updateFrequency < kMaxFramesWithoutInterrupt))
{
framesBeforeInterrupt = updateFrequency;
}
else
{
framesBeforeInterrupt = kMaxFramesWithoutInterrupt;
}
USBLog(7 , "AppleUSBXHCI[%p]::UIMCreateIsochTransfer - transferCount(%d) transfersPerTD(%d) framesBeforeInterrupt(%d)", this, (int)transferCount, (int)transfersPerTD, (int)framesBeforeInterrupt);
for (baseTransferIndex = 0; baseTransferIndex < transferCount; baseTransferIndex += transfersPerTD)
{
pNewITD = AppleXHCIIsochTransferDescriptor::ForEndpoint(pEP);
USBLog(7, "AppleUSBXHCI[%p]::UIMCreateIsochTransfer - new iTD(%p)", this, pNewITD);
if (pNewITD == NULL)
{
USBLog(1,"AppleUSBXHCI[%p]::UIMCreateIsochTransfer Could not allocate a new iTD", this);
USBTrace(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, frameNumberStart, 0, 15);
return kIOReturnNoMemory;
}
pNewITD->_lowLatency = lowLatency;
pNewITD->_framesInTD = 0;
pNewITD->newFrame = newFrame;
pNewITD->interruptThisTD = false;
if(frameCount > framesBeforeInterrupt)
{
pNewITD->interruptThisTD = true;
frameCount -= framesBeforeInterrupt;
}
pEP->firstAvailableFrame += frameNumberIncrease;
if (frameNumberIncrease == 1)
newFrame = false;
pNewITD->bufferOffset = transferOffset;
for (transfer = 0; ((transfer < transfersPerTD) && ((baseTransferIndex + transfer) < transferCount)); transfer++)
{
if (lowLatency)
{
pLLFrames[baseTransferIndex + transfer].frStatus = kUSBLowLatencyIsochTransferKey;
trLen = pLLFrames[baseTransferIndex + transfer].frReqCount;
}
else
{
trLen = pFrames[baseTransferIndex + transfer].frReqCount;
}
transferOffset += trLen;
}
pNewITD->_framesInTD = transfer; pNewITD->_pFrames = pFrames; pNewITD->_frameNumber = frameNumberStart; pNewITD->_frameIndex = baseTransferIndex;
pNewITD->_completion.action = NULL; pNewITD->_pEndpoint = pEP;
pNewITD->command = command;
pNewITD->print(7);
USBLog(7, "AppleUSBXHCI[%p]::UIMCreateIsochTransfer - putting pTD(%p) on ToDoList for pEP(%p)", this, pNewITD, pEP);
USBTrace(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, (uintptr_t)pEP, (uintptr_t)pNewITD, 16);
PutTDonToDoList(pEP, pNewITD);
frameNumberStart += frameNumberIncrease;
frameCount += frameNumberIncrease;
numberOfTDs++;
}
if ( pNewITD == NULL )
{
USBLog(1, "AppleUSBXHCI[%p]::CreateHSIsochTransfer - no pNewITD! Bailing.)", this);
USBTrace(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, frameNumberStart, 0, 17);
return kIOReturnInternalError;
}
USBLog(7, "AppleUSBXHCI[%p]::CreateHSIsochTransfer - in TD (%p) setting _completion action (%p)", this, pNewITD, pNewITD ? pNewITD->_completion.action : NULL);
pNewITD->_completion = command->GetUSLCompletion();
pNewITD->interruptThisTD = true;
USBLog(5, "AppleUSBXHCI[%p]::UIMCreateIsochTransfer - adding Frames to schedule for pEP(%p)", this, pEP);
AddIsocFramesToSchedule(pEP);
USBLog(7, "-AppleUSBXHCI[%p]::UIMCreateIsochTransfer", this);
USBTrace_End(kUSBTXHCI, kTPXHCIUIMCreateIsochTransfer, (uintptr_t)this, (command->GetDirection() << 16) | (command->GetAddress() << 8) | command->GetEndpoint(), 0, 0);
return kIOReturnSuccess;
}
UInt32
AppleUSBXHCI::UIMMaxSupportedStream(void)
{
if (_maxPrimaryStreams == 0)
return 0;
if(kMaxStreamsPerEndpoint > _maxPrimaryStreams)
{
return (_maxPrimaryStreams-1);
}
else
{
return (kMaxStreamsPerEndpoint-1);
}
}
int AppleUSBXHCI::QuiesceEndpoint(int slotID, int endpointID)
{
Context * epCtx;
int epState, epState1;
USBTrace_Start(kUSBTXHCI, kTPXHCIQuiesceEndpoint, (uintptr_t)this, 0, 0, 0);
ClearStopTDs(slotID, endpointID);
epCtx = GetEndpointContext(slotID, endpointID);
epState = GetEpCtxEpState(epCtx);
switch(epState)
{
case kXHCIEpCtx_State_Halted:
USBLog(6, "AppleUSBXHCI[%p]::QuiesceEndpoint - resetting endpoint slotID: %d endpointID: %d", this, slotID, endpointID);
USBTrace( kUSBTXHCI, kTPXHCIQuiesceEndpoint, (uintptr_t)this, slotID, endpointID, 0);
ResetEndpoint(slotID, endpointID);
break;
case kXHCIEpCtx_State_Running:
USBLog(6, "AppleUSBXHCI[%p]::QuiesceEndpoint - stopping endpoint slotID: %d endpointID: %d", this, slotID, endpointID);
USBTrace( kUSBTXHCI, kTPXHCIQuiesceEndpoint, (uintptr_t)this, slotID, endpointID, 1);
StopEndpoint(slotID, endpointID);
epState1 = GetEpCtxEpState(epCtx);
if(epState1 != kXHCIEpCtx_State_Stopped)
{
USBLog(1, "AppleUSBXHCI[%p]::QuiesceEndpoint - state changed before endpoint stopped. (%d)", this, epState1);
USBTrace( kUSBTXHCI, kTPXHCIQuiesceEndpoint, (uintptr_t)this, epState1, 0, 2);
if(epState1 == kXHCIEpCtx_State_Halted)
{
ResetEndpoint(slotID, endpointID);
epState = epState1;
}
}
break;
case kXHCIEpCtx_State_Stopped:
USBTrace( kUSBTXHCI, kTPXHCIQuiesceEndpoint, (uintptr_t)this, slotID, endpointID, 3);
break;
case kXHCIEpCtx_State_Error:
USBLog(2, "AppleUSBXHCI[%p]::QuiesceEndpoint - slotID: %d endpointID: %d in error state", this, slotID, endpointID);
USBTrace( kUSBTXHCI, kTPXHCIQuiesceEndpoint, (uintptr_t)this, slotID, endpointID, 4);
break;
case kXHCIEpCtx_State_Disabled:
USBLog(1, "AppleUSBXHCI[%p]::QuiesceEndpoint - slotID: %d endpointID: %d in Disabled state, this is a problem", this, slotID, endpointID);
USBTrace( kUSBTXHCI, kTPXHCIQuiesceEndpoint, (uintptr_t)this, slotID, endpointID, 5);
break;
default:
USBLog(1, "AppleUSBXHCI[%p]::QuiesceEndpoint - slotID: %d endpointID: %d unexpected endpoint state:%d", this, epState, slotID, endpointID);
USBTrace( kUSBTXHCI, kTPXHCIQuiesceEndpoint, (uintptr_t)this, slotID, endpointID, 6);
}
USBTrace_End(kUSBTXHCI, kTPXHCIQuiesceEndpoint, (uintptr_t)this, epState, 0, 0);
return(epState);
}
IOReturn
AppleUSBXHCI::UIMAbortStream(UInt32 streamID,
short functionNumber,
short endpointNumber,
short direction)
{
int epState, slotID, endpointID;
IOReturn err=kIOReturnSuccess;
USBTrace_Start(kUSBTXHCI, kTPXHCIUIMAbortStream, (uintptr_t)this, 0, 0, 0);
#if 1
if( (functionNumber == _rootHubFuncAddressSS) || (functionNumber == _rootHubFuncAddressHS) )
{
if(streamID != kUSBAllStreams)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMAbortStream on root hub - Unimplimented", this);
return(kIOReturnInternalError);
}
if ( (endpointNumber != 1) && (endpointNumber != 0) )
{
USBLog(1, "AppleUSBXHCI[%p]::UIMAbortStream: bad params - endpNumber: %d", this, endpointNumber );
return kIOReturnBadArgument;
}
USBLog(5, "AppleUSBXHCI[%p]::UIMAbortStream: Attempting operation on root hub", this);
if (endpointNumber == 1)
{
if (direction != kUSBIn)
{
USBLog(3, "AppleUSBXHCI[%p]::UIMAbortStream - Root hub wrong direction Int pipe %d", this, direction);
return kIOReturnInternalError;
}
USBLog(5, "AppleUSBXHCI[%p]::UIMAbortStream Root hub aborting int transactions", this);
RootHubAbortInterruptRead();
}
else
{
USBLog(5, "AppleUSBXHCI[%p]::UIMAbortStream Root hub aborting control pipe (NOP)", this);
}
USBTrace_End(kUSBTXHCI, kTPXHCIUIMAbortStream, (uintptr_t)this, kIOReturnSuccess, 0, 0);
return kIOReturnSuccess;
}
#endif
slotID = GetSlotID(functionNumber);
if(slotID == 0)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMAbortStream - unknown function number: %d", this, functionNumber);
return(kIOReturnInternalError);
}
endpointID = GetEndpointID(endpointNumber, direction);
if(streamID != kUSBAllStreams)
{
USBLog(3, "AppleUSBXHCI[%p]::UIMAbortStream - with stream ID %u (@%d, %d)", this, (unsigned)streamID, slotID, endpointID);
if(streamID == 0)
{
if(IsStreamsEndpoint(slotID, endpointID))
{
USBLog(1, "AppleUSBXHCI[%p]::UIMAbortStream - Trying to abort stream zero of streams endpoint %u (@%d, %d)", this, (unsigned)streamID, slotID, endpointID);
return(kIOReturnBadArgument);
}
}
else
{ if(_slots[slotID].maxStream[endpointID] < streamID)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMAbortStream - Trying to abort invalid stream ID %u of %u (@%d, %d)", this, (unsigned)streamID, (unsigned)_slots[slotID].maxStream[endpointID], slotID, endpointID);
return(kIOReturnBadArgument);
}
}
}
USBLog(3, "AppleUSBXHCI[%p]::UIMAbortStream - stream:%u, fn:%d, ep:%d, dir:%d - Slot:%d,ep:%d", this, (unsigned)streamID, functionNumber, endpointNumber, direction, slotID, endpointID);
epState = QuiesceEndpoint(slotID, endpointID);
if(streamID == kUSBAllStreams)
{
if(IsStreamsEndpoint(slotID, endpointID))
{
if(_slots[slotID].maxStream[endpointID] != 0)
{
for(UInt32 i = 1; i<=_slots[slotID].maxStream[endpointID]; i++)
{
IOReturn err1;
err1 = ReturnAllTransfersAndReinitRing(slotID, endpointID, i);
if(err1 != kIOReturnSuccess)
{
err = err1;
}
}
}
}
else
{
err = ReturnAllTransfersAndReinitRing(slotID, endpointID, 0);
}
}
else
{
err = ReturnAllTransfersAndReinitRing(slotID, endpointID, streamID);
if(streamID != 0)
{
if(epState == kXHCIEpCtx_State_Running)
RestartStreams(slotID, endpointID, streamID);
}
}
USBTrace_End(kUSBTXHCI, kTPXHCIUIMAbortStream, (uintptr_t)this, err, 0, 0);
return err;
}
void AppleUSBXHCI::RestartStreams(int slotID, int EndpointID, UInt32 except)
{
XHCIRing *ring;
UInt32 maxStream;
maxStream = _slots[slotID].maxStream[EndpointID];
if(maxStream <= 1)
{
if(!IsStreamsEndpoint(slotID, EndpointID))
{
USBLog(1, "AppleUSBXHCI[%p]::RestartStreams - called on non streams endpoint %d, %d", this, slotID, EndpointID);
}
return;
}
for(UInt32 i = 1; i<=maxStream; i++)
{
if(i != except)
{
ring = GetRing(slotID, EndpointID, i);
if(ring != NULL)
{
if(ring->transferRingDequeueIdx != ring->transferRingEnqueueIdx)
{
USBLog(3, "AppleUSBXHCI[%p]::RestartStreams - restarting %d (@%d, %d)", this, (int)i, slotID, EndpointID);
StartEndpoint(slotID, EndpointID, i);
}
}
}
}
}
IOReturn AppleUSBXHCI::UIMAbortEndpoint(short functionNumber,
short endpointNumber,
short direction)
{
return UIMAbortStream(kUSBAllStreams, functionNumber, endpointNumber, direction);
}
void AppleUSBXHCI::DeallocRing(XHCIRing *ring)
{
if(ring != NULL)
{
if(ring->TRBBuffer != NULL)
{
USBLog(2, "AppleUSBXHCI[%p]::DeallocRing - completing phys:%llx, siz:%x, TRBBuffer:%p", this, ring->transferRingPhys, (unsigned int)ring->transferRingSize, ring->TRBBuffer);
ring->TRBBuffer->complete();
ring->TRBBuffer->release();
ring->TRBBuffer = 0;
}
ring->transferRing = 0;
ring->transferRingPhys = 0;
ring->transferRingSize = 0;
}
}
void AppleUSBXHCI::ParkRing(XHCIRing *ring)
{
TRB t;
UInt8 speed;
speed = GetSlCtxSpeed(GetSlotContext(ring->slotID));
if(speed <= kXHCISpeed_High)
{
SInt32 err;
QuiesceEndpoint(ring->slotID, ring->endpointID);
ClearTRB(&t, true);
SetTRBSlotID(&t, ring->slotID);
SetTRBEpID(&t, ring->endpointID);
SetTRBAddr64(&t, _DummyRingPhys);
SetTRBDCS(&t, _DummyRingCycleBit);
err = WaitForCMD(&t, kXHCITRB_SetTRDqPtr);
if((err == CMD_NOT_COMPLETED) || (err <= MakeXHCIErrCode(0)))
{
USBLog(1, "AppleUSBXHCI[%p]::ParkRing - couldn't set tr dq pointer: %d", this, err);
PrintContext(GetSlotContext(ring->slotID));
PrintContext(GetEndpointContext(ring->slotID, ring->endpointID));
}
}
}
IOReturn AppleUSBXHCI::UIMDeleteEndpoint(short functionNumber,
short endpointNumber,
short direction)
{
UInt32 offs00;
SInt32 ret;
int slotID, endpointIdx;
XHCIRing *ringX;
int ctxEntries;
TRB t;
Context *inputContext;
Context *deviceContext;
USBLog(3, "AppleUSBXHCI[%p]::UIMDeleteEndpoint - fn:%d, ep:%d, dir:%d", this, functionNumber, endpointNumber, direction);
slotID = GetSlotID(functionNumber);
if(slotID == 0)
{
if(functionNumber == 0)
{
return(kIOReturnSuccess);
}
USBLog(3, "AppleUSBXHCI[%p]::UIMDeleteEndpoint - Unused slot ID for functionAddress: %d", this, functionNumber);
return(kIOReturnBadArgument);
}
endpointIdx = GetEndpointID(endpointNumber, direction);
ringX = GetRing(slotID, endpointIdx, 0);
if (ringX == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMDeleteEndpoint - ring does not exist (slot:%d, ep:%d) ", this, (int)slotID, (int)endpointIdx);
return(kIOReturnBadArgument);
}
if (ringX->TRBBuffer == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMDeleteEndpoint - ******* unallocated ring, slot:%d id:%d", this, slotID, endpointIdx);
return(kIOReturnBadArgument);
}
ringX->beingDeleted = true;
UIMAbortEndpoint(functionNumber, endpointNumber, direction);
if( (_errataBits & kXHCIErrata_ParkRing) != 0)
{
ParkRing(ringX);
}
if (endpointNumber == 0)
{
ringX = GetRing(slotID, 1, 0);
if(ringX != NULL)
{
if (ringX->pEndpoint)
{
AppleXHCIAsyncEndpoint* pAsyncEP = OSDynamicCast(AppleXHCIAsyncEndpoint, (AppleXHCIAsyncEndpoint*)ringX->pEndpoint);
if (pAsyncEP)
{
pAsyncEP->Abort();
pAsyncEP->release();
DecConfiguredEpCount();
USBLog(3, "AppleUSBXHCI[%p]::UIMDeleteEndpoint(async) - dec-- _configuredEndpointCount pEP=%p", this, ringX->pEndpoint);
ringX->pEndpoint = NULL;
}
}
DeallocRing(ringX);
IOFree((void *)ringX, sizeof(XHCIRing));
_slots[slotID].potentialStreams[endpointIdx] = 0;
_slots[slotID].maxStream[endpointIdx] = 0;
_slots[slotID].rings[endpointIdx] = NULL;
}
}
else
{
GetInputContext();
inputContext = GetInputContextByIndex(0);
inputContext->offs00 = HostToUSBLong(1 << endpointIdx); inputContext->offs04 = HostToUSBLong(1);
inputContext = GetInputContextByIndex(1);
deviceContext = GetSlotContext(slotID);
*inputContext = *deviceContext;
offs00 = USBToHostLong(inputContext->offs00);
ctxEntries = (offs00 & kXHCISlCtx_CtxEnt_Mask) >> kXHCISlCtx_CtxEnt_Shift;
if(endpointIdx == ctxEntries)
{
do{
XHCIRing *ring;
ctxEntries--; ring = GetRing(slotID, ctxEntries, 0);
if( (ring != NULL) && (ring->TRBBuffer != NULL) )
{
break;
}
}while(ctxEntries > 0);
if(ctxEntries == 0)
{
USBLog(3, "AppleUSBXHCI[%p]::UIMDeleteEndpoint - All eps deleted, setting Context entries to 1", this);
ctxEntries = 1;
}
else
{
USBLog(3, "AppleUSBXHCI[%p]::UIMDeleteEndpoint - Context entries now: %d", this, ctxEntries);
}
offs00 = (offs00 & ~kXHCISlCtx_CtxEnt_Mask) | (ctxEntries << kXHCISlCtx_CtxEnt_Shift);
}
offs00 &= ~kXHCISlCtx_resZ0Bit; inputContext->offs00 = HostToUSBLong(offs00);
ClearTRB(&t, true);
SetTRBAddr64(&t, _inputContextPhys);
SetTRBSlotID(&t, slotID);
PrintTRB(6, &t, "UIMDeleteEndpoint 3");
ret = WaitForCMD(&t, kXHCITRB_ConfigureEndpoint);
#if 1
USBLog(6, "AppleUSBXHCI[%p]::UIMDeleteEndpoint - Output context entries: %d", this, (int)ctxEntries);
for(int i = 0; i<=ctxEntries+1; i++)
{
PrintContext(GetEndpointContext(slotID, i));
}
#endif
ReleaseInputContext();
if((ret == CMD_NOT_COMPLETED) || (ret <= MakeXHCIErrCode(0)))
{
USBLog(1, "AppleUSBXHCI[%p]::UIMDeleteEndpoint - Configure endpoint command failed.", this);
}
DeleteStreams(slotID, endpointIdx);
if (ringX->pEndpoint)
{
if( (ringX->endpointType == kXHCIEpCtx_EPType_IsocIn) || (ringX->endpointType == kXHCIEpCtx_EPType_IsocOut) )
{
DeleteIsochEP((AppleXHCIIsochEndpoint*)ringX->pEndpoint);
DecConfiguredEpCount();
USBLog(3, "AppleUSBXHCI[%p]::UIMDeleteEndpoint(isoc) - dec-- _configuredEndpointCount pEP=%p", this, ringX->pEndpoint);
}
else
{
AppleXHCIAsyncEndpoint* pAsyncEP = OSDynamicCast(AppleXHCIAsyncEndpoint, (AppleXHCIAsyncEndpoint*)ringX->pEndpoint);
pAsyncEP->Abort();
pAsyncEP->release();
DecConfiguredEpCount();
USBLog(3, "AppleUSBXHCI[%p]::UIMDeleteEndpoint(async2) - dec-- _configuredEndpointCount pEP=%p", this, ringX->pEndpoint);
}
ringX->pEndpoint = NULL;
}
DeallocRing(ringX);
IOFree(ringX, sizeof(XHCIRing)* (_slots[slotID].maxStream[endpointIdx]+1));
_slots[slotID].potentialStreams[endpointIdx] = 0;
_slots[slotID].maxStream[endpointIdx] = 0;
_slots[slotID].rings[endpointIdx] = NULL;
}
for(int i = 1; i < kXHCI_Num_Contexts; i++)
{
ringX = GetRing(slotID, i, 0);
if( (ringX != NULL) && (ringX->TRBBuffer != NULL) )
{
return(kIOReturnSuccess);
}
}
ClearTRB(&t, true);
SetTRBSlotID(&t, slotID);
PrintTRB(6, &t, "UIMDeleteEndpoint 2");
USBLog(3, "AppleUSBXHCI[%p]::UIMDeleteEndpoint - Disabling slot:%d.", this, slotID);
ret = WaitForCMD(&t, kXHCITRB_DisableSlot);
PrintSlotContexts();
if((ret == CMD_NOT_COMPLETED) || (ret <= MakeXHCIErrCode(0)))
{
USBLog(1, "AppleUSBXHCI[%p]::UIMDeleteEndpoint - disable slot/reset command failed.", this);
}
_slots[slotID].deviceContext = NULL; _slots[slotID].deviceContext64 = NULL;
SetDCBAAAddr64(&_DCBAA[slotID], NULL);
_slots[slotID].buffer->complete();
_slots[slotID].buffer->release();
_slots[slotID].buffer = 0;
_slots[slotID].deviceContextPhys = 0;
_slots[slotID].deviceNeedsReset = false;
_devHub[functionNumber] = 0;
_devPort[functionNumber] = 0;
_devMapping[functionNumber] = 0;
_devEnabled[functionNumber] = false;
return(kIOReturnSuccess);
}
void
AppleUSBXHCI::DeleteStreams(int slotID, int endpointIdx)
{
for(UInt32 i = 1; i<=_slots[slotID].maxStream[endpointIdx]; i++)
{
USBLog(2, "AppleUSBXHCI[%p]::DeleteStreams - delete stream %d (@%d, %d).", this, (int)i, slotID, endpointIdx);
XHCIRing *pStreamRing = GetRing(slotID, endpointIdx, i);
if (pStreamRing)
{
AppleXHCIAsyncEndpoint *pAsyncEP = OSDynamicCast(AppleXHCIAsyncEndpoint, (AppleXHCIAsyncEndpoint*)pStreamRing->pEndpoint);
if (pAsyncEP)
{
pAsyncEP->Abort();
pAsyncEP->release();
}
DeallocRing(pStreamRing);
}
}
}
#if 0
IOReturn AppleUSBXHCI::UIMClearEndpointStall(short functionNumber,
short endpointNumber,
short direction)
{
Context * epCtx;
int epState, slotID, endpointID;
XHCIRing * ring;
IOReturn err = kIOReturnSuccess;
slotID = GetSlotID(functionNumber);
if(slotID == 0)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMClearEndpointStall - unknown function number: %d", this, functionNumber);
return(kIOReturnInternalError);
}
USBTrace_Start(kUSBTXHCI, kTPXHCIUIMClearEndpointStall, (uintptr_t)this, 0, 0, 0);
endpointID = GetEndpointID(endpointNumber, direction);
USBLog(7, "AppleUSBXHCI[%p]::UIMClearEndpointStall - fn: %d, ep:%d, dir:%d, slot: %d, epID:%d", this, functionNumber, endpointNumber, direction, slotID, endpointID);
ring = GetRing(slotID, endpointID, 0);
if(ring == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMClearEndpointStall - ring does not exist (slot:%d, ep:%d) ", this, (int)slotID, (int)endpointID);
return(kIOReturnBadArgument);
}
if(ring->TRBBuffer == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMClearEndpointStall - ******* unallocated ring, slot:%d id:%d", this, slotID, endpointID);
return(kIOReturnBadArgument);
}
if(ring->beingReturned)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMClearEndpointStall - reenterred", this);
return(kIOUSBClearPipeStallNotRecursive);
}
USBLog(7, "AppleUSBXHCI[%p]::UIMClearEndpointStall - tr ring: %p size: %d", this, ring->transferRing, ring->transferRingSize);
epCtx = GetEndpointContext(slotID, endpointID);
PrintContext(epCtx);
epState = USBToHostLong(epCtx->offs00) & kXHCIEpCtx_State_Mask;
if(epState != kXHCIEpCtx_State_Halted)
{
USBLog(4, "AppleUSBXHCI[%p]::UIMClearEndpointStall - not halted, clear endpoint", this);
ClearEndpoint(slotID, endpointID);
}
epState = QuiesceEndpoint(slotID, endpointID);
USBLog(7, "AppleUSBXHCI[%p]::UIMClearEndpointStall - EP State1: %d", this, epState);
epState = GetEpCtxEpState(epCtx);
USBLog(7, "AppleUSBXHCI[%p]::UIMClearEndpointStall - EP State2: %d", this, epState);
if(IsStreamsEndpoint(slotID, endpointID))
{
if(_slots[slotID].maxStream[endpointID] != 0)
{
for(UInt32 i = 1; i<=_slots[slotID].maxStream[endpointID]; i++)
{
IOReturn err1;
err1 = ReturnAllTransfersAndReinitRing(slotID, endpointID, i);
if(err1 != kIOReturnSuccess)
{
err = err1;
}
}
}
}
else
{
err = ReturnAllTransfersAndReinitRing(slotID, endpointID, 0);
}
PrintContext(GetEndpointContext(slotID, endpointID));
USBTrace_Start(kUSBTXHCI, kTPXHCIUIMClearEndpointStall, (uintptr_t)this, err, 0, 0);
return err ;
}
#else
IOReturn AppleUSBXHCI::UIMClearEndpointStall(short functionNumber,
short endpointNumber,
short direction)
{
int epState, slotID, endpointID;
XHCIRing *ring;
IOReturn ret;
Context *epCtx;
slotID = GetSlotID(functionNumber);
if(slotID == 0)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMClearEndpointStall - unknown function number: %d", this, functionNumber);
return(kIOReturnInternalError);
}
endpointID = GetEndpointID(endpointNumber, direction);
USBLog(7, "AppleUSBXHCI[%p]::UIMClearEndpointStall - fn: %d, ep:%d, dir:%d, slot: %d, epID:%d", this, functionNumber, endpointNumber, direction, slotID, endpointID);
ring = GetRing(slotID, endpointID, 0);
if(ring == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMClearEndpointStall - ring does not exist (slot:%d, ep:%d) ", this, (int)slotID, (int)endpointID);
return(kIOReturnBadArgument);
}
if(ring->TRBBuffer == NULL)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMClearEndpointStall - ******* unallocated ring, slot:%d id:%d", this, slotID, endpointID);
return(kIOReturnBadArgument);
}
if(ring->beingReturned)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMClearEndpointStall - reenterred, returning kIOUSBClearPipeStallNotRecursive", this);
return(kIOUSBClearPipeStallNotRecursive);
}
epCtx = GetEndpointContext(slotID, endpointID);
epState = GetEpCtxEpState(epCtx);
if(epState != kXHCIEpCtx_State_Halted)
{
USBLog(4, "AppleUSBXHCI[%p]::UIMClearEndpointStall - was not halted, clear endpoint", this);
ClearEndpoint(slotID, endpointID);
}
ret = UIMAbortStream(kUSBAllStreams, functionNumber, endpointNumber, direction);
if(ret != kIOReturnSuccess)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMClearEndpointStall - UIMAbortStream returned: %x", this, ret);
return(ret);
}
return(kIOReturnSuccess);
}
#endif
void AppleUSBXHCI::UIMRootHubStatusChange( bool abort )
{
#pragma unused(abort)
USBLog(1, "AppleUSBXHCI[%p]::UIMRootHubStatusChange - calling obsolete method UIMRootHubStatusChange(bool)", this);
}
IOReturn AppleUSBXHCI::SetRootHubDescriptor( OSData *buffer )
{
#pragma unused(buffer)
USBLog(1, "AppleUSBXHCI[%p]::SetRootHubDescriptor - Unimplimented method called", this);
return(kIOReturnInternalError);
}
IOReturn AppleUSBXHCI::ClearRootHubFeature( UInt16 wValue )
{
#pragma unused(wValue)
USBLog(1, "AppleUSBXHCI[%p]::ClearRootHubFeature - Unimplimented method called", this);
return(kIOReturnInternalError);
}
IOReturn AppleUSBXHCI::GetRootHubPortState( UInt8 *state, UInt16 port )
{
#pragma unused(state)
#pragma unused(port)
USBLog(1, "AppleUSBXHCI[%p]::GetRootHubPortState - Unimplimented method called", this);
return(kIOReturnInternalError);
}
UInt64 AppleUSBXHCI::GetFrameNumber( void )
{
UInt64 temp1, temp2;
register UInt32 frindex;
UInt32 sts;
UInt32 count = 0;
bool loggedZero = false;
sts = Read32Reg(&_pXHCIRegisters->USBSTS);
if (_lostRegisterAccess)
{
return 0;
}
if ( sts & kXHCIHCHaltedBit)
{
USBTrace( kUSBTXHCI, kTPXHCIGetFrameNumber, (uintptr_t)this, 0, 0, 4 );
return 0;
}
do
{
temp1 = _frameNumber64;
frindex = Read32Reg(&_pXHCIRuntimeReg->MFINDEX);
if (_lostRegisterAccess)
{
return 0;
}
temp2 = _frameNumber64;
if ((frindex == 0) && !loggedZero)
{
USBTrace( kUSBTXHCI, kTPXHCIGetFrameNumber, (uintptr_t)this, (int)temp1, (int)temp2, 0 );
loggedZero = true;
}
if((count++ > 100) && (temp1 == temp2) && (frindex == 0) )
{
USBTrace( kUSBTXHCI, kTPXHCIGetFrameNumber, (uintptr_t)this, (int)temp1, (int)temp2, 1 );
IODelay(126); USBTrace( kUSBTXHCI, kTPXHCIGetFrameNumber, (uintptr_t)this, (int)temp1, (int)temp2, 2 );
temp1 = _frameNumber64;
frindex = Read32Reg(&_pXHCIRuntimeReg->MFINDEX);
if (_lostRegisterAccess)
{
return 0;
}
temp2 = _frameNumber64;
if(frindex == 0)
{
return 0;
}
}
} while ( (temp1 != temp2) || (frindex == 0) );
frindex = frindex >> 3;
USBTrace( kUSBTXHCI, kTPXHCIGetFrameNumber, (uintptr_t)this, (int)((temp1 + frindex) >> 32), (int)(temp1 + frindex), 3 );
return (temp1 + frindex);
}
UInt64
AppleUSBXHCI::GetMicroFrameNumber( void )
{
UInt64 temp1, temp2;
register UInt32 frindex;
UInt32 count = 0;
UInt32 sts;
sts = Read32Reg(&_pXHCIRegisters->USBSTS);
if (_lostRegisterAccess)
{
return 0;
}
if ( sts & kXHCIHCHaltedBit)
{
return 0;
}
do
{
temp1 = _frameNumber64;
frindex = Read32Reg(&_pXHCIRuntimeReg->MFINDEX);
if (_lostRegisterAccess)
{
return 0;
}
temp2 = _frameNumber64;
if((count++ > 100) && (temp1 == temp2) && (frindex == 0) )
{
IODelay(126); temp1 = _frameNumber64;
frindex = Read32Reg(&_pXHCIRuntimeReg->MFINDEX);
if (_lostRegisterAccess)
{
return 0;
}
temp2 = _frameNumber64;
if(frindex == 0)
{
break;
}
}
} while ( (temp1 != temp2) || (frindex == 0) );
temp1 = temp1 << 3;
return (temp1 + frindex);
}
UInt32 AppleUSBXHCI::GetFrameNumber32( void )
{
return((UInt32)GetFrameNumber());
}
void AppleUSBXHCI::PollInterrupts( IOUSBCompletionAction safeAction)
{
#pragma unused(safeAction)
UInt32 statusReg = Read32Reg(&_pXHCIRegisters->USBSTS);
if (_lostRegisterAccess)
{
return;
}
if ( statusReg & kXHCIPCD )
{
Write32Reg(&_pXHCIRegisters->USBSTS, kXHCIPCD);
USBLog(6,"AppleUSBXHCI[%p]::PollInterrupts - Port Change Detect Bit on bus 0x%x - ensuring usability", this, (uint32_t)_busNumber );
EnsureUsability();
if (_myPowerState == kUSBPowerStateOn)
{
RHCheckForPortResumes();
}
else
{
USBLog(2, "AppleUSBXHCI[%p]::PollInterrupts - deferring checking for RHStatus until we are running again", this);
}
}
USBTrace_Start( kUSBTXHCIInterrupts, kTPXHCIInterruptsPollInterrupts, (uintptr_t)this, (uintptr_t)0, 0, 0 );
while(PollEventRing2(kPrimaryInterrupter)) ;
while(PollEventRing2(kTransferInterrupter)) ;
USBTrace_End( kUSBTXHCIInterrupts, kTPXHCIInterruptsPollInterrupts, (uintptr_t)this, 0, 0, 0 );
}
IOReturn
AppleUSBXHCI::StopUSBBus()
{
UInt32 CMD, count=0;
CMD = Read32Reg(&_pXHCIRegisters->USBCMD);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
if( CMD & kXHCICMDRunStop )
{
CMD &= ~kXHCICMDRunStop;
Write32Reg(&_pXHCIRegisters->USBCMD, CMD);
while( ((Read32Reg(&_pXHCIRegisters->USBSTS) & kXHCIHCHaltedBit) == 0) && !(_lostRegisterAccess) )
{
IOSleep(1);
if(count++ >100)
{
USBLog(1, "AppleUSBXHCI[%p]::StopUSBBus - Controller not halted after 100ms", this);
return kIOReturnInternalError;
}
}
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
}
_myBusState = kUSBBusStateReset;
USBLog(5, "AppleUSBXHCI[%p]::StopUSBBus - HC halted", this);
return kIOReturnSuccess;
}
void
AppleUSBXHCI::RestartUSBBus()
{
UInt32 count=0;
UInt32 CMD, STS;
do {
CMD = Read32Reg(&_pXHCIRegisters->USBCMD);
if (_lostRegisterAccess)
{
break;
}
CMD |= kXHCICMDRunStop | kXHCICMDINTE | kXHCICMDEWE;
Write32Reg(&_pXHCIRegisters->USBCMD, CMD);
IOSync();
STS = Read32Reg(&_pXHCIRegisters->USBSTS);
if (_lostRegisterAccess)
{
break;
}
while(STS & kXHCIHCHaltedBit)
{
IOSleep(1);
if(count++ >100)
{
USBLog(1, "AppleUSBXHCI[%p]::RestartUSBBus - Controller not running after 100ms", this);
break;
}
STS = Read32Reg(&_pXHCIRegisters->USBSTS);
if (_lostRegisterAccess)
{
break;
}
}
if (_lostRegisterAccess)
{
break;
}
_myBusState = kUSBBusStateRunning;
USBLog(5, "AppleUSBXHCI[%p]::RestartUSBBus - HC restarted", this);
} while (0);
}
IOReturn
AppleUSBXHCI::ResetController()
{
int i;
UInt32 CMD;
IOReturn status = kIOReturnSuccess;
volatile UInt32 val = 0;
volatile UInt32 * addr;
Write32Reg(&_pXHCIRegisters->USBCMD, kXHCICMDHCReset); IOSync();
CMD = Read32Reg(&_pXHCIRegisters->USBCMD);
for (i=0; (i < 1000) && (CMD & kXHCICMDHCReset); i++)
{
if (_lostRegisterAccess)
{
status = kIOReturnNoDevice;
break;
}
IOSleep(1);
if (i >= 1000)
{
USBError(1, "AppleUSBXHCI[%p]::ResetController - could not get chip to come out of reset within %d ms", this, i);
status = kIOReturnInternalError;
break;
}
if(i > 100)
{
USBLog(3, "AppleUSBXHCI[%p]::ResetController - took: %dms to come out of reset", this, i);
}
CMD = Read32Reg(&_pXHCIRegisters->USBCMD);
if (_lostRegisterAccess)
{
status = kIOReturnNoDevice;
break;
}
}
return status;
}
IOReturn
AppleUSBXHCI::GetFrameNumberWithTime(UInt64* frameNumber, AbsoluteTime *theTime)
{
if (!_commandGate)
return kIOReturnUnsupported;
return _commandGate->runAction(GatedGetFrameNumberWithTime, frameNumber, theTime);
}
IOReturn
AppleUSBXHCI::GatedGetFrameNumberWithTime(OSObject *owner, void* arg0, void* arg1, void* arg2, void* arg3)
{
#pragma unused (arg2, arg3)
AppleUSBXHCI *me = (AppleUSBXHCI*)owner;
UInt64 *frameNumber = (UInt64*)arg0;
AbsoluteTime *theTime = (AbsoluteTime*)arg1;
*frameNumber = me->_anchorFrame;
*theTime = me->_anchorTime;
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::ConfigureDeviceZero(UInt8 maxPacketSize, UInt8 speed, USBDeviceAddress hub, int port)
{
if( (hub == _rootHubFuncAddressHS) || (hub == _rootHubFuncAddressSS) )
{
UInt8 rhSpeed = (hub == _rootHubFuncAddressHS) ? kUSBDeviceSpeedHigh : kUSBDeviceSpeedSuper;
AdjustRootHubPortNumbers(rhSpeed, (UInt16*)&port);
}
USBLog(3, "AppleUSBXHCI[%p]::UIM **** - ConfigureDeviceZero maxPacketSize:%d, speed:%d, hub:%d, adj port:%d", this, maxPacketSize, speed, hub, port);
_devZeroPort = port;
_devZeroHub = hub;
return(super::ConfigureDeviceZero(maxPacketSize, speed, hub, port));
}
bool
AppleUSBXHCI::init(OSDictionary * propTable)
{
if (!super::init(propTable))
return false;
_controllerSpeed = kUSBDeviceSpeedSuper;
_isochScheduleLock = IOSimpleLockAlloc();
if (!_isochScheduleLock)
{
return false;
}
_uimInitialized = false;
_myBusState = kUSBBusStateReset;
return true;
}
IOReturn
AppleUSBXHCI::UIMEnableAddressEndpoints(USBDeviceAddress address, bool enable)
{
int slotID;
USBLog(3, "AppleUSBXHCI[%p]::UIMEnableAddressEndpoints - address: %d %s", this, address, enable?"enable":"disable");
slotID = GetSlotID(address);
if(slotID == 0)
{
if(enable)
{
if( address > 127 )
{
USBLog(2, "AppleUSBXHCI[%p]::UIMEnableAddressEndpoints - address out of range: %d", this, address);
return(kIOReturnBadArgument);
}
_devEnabled[address] = true;
slotID = GetSlotID(address);
for(int i = 1; i<kXHCI_Num_Contexts; i++)
{
XHCIRing * ringX;
ringX = GetRing(slotID, i, 0);
if( (ringX != NULL) && (ringX->TRBBuffer != 0) )
{
if(IsStreamsEndpoint(slotID, i))
{
USBLog(5, "AppleUSBXHCI[%p]::UIMEnableAddressEndpoints - calling RestartStreams(%d, %d)", this, slotID, i);
RestartStreams(slotID, i, 0);
}
else
{
USBLog(5, "AppleUSBXHCI[%p]::UIMEnableAddressEndpoints - calling StartEndpoint(%d, %d)", this, slotID, i);
StartEndpoint(slotID, i);
}
}
}
return(kIOReturnSuccess);
}
else
{
USBLog(1, "AppleUSBXHCI[%p]::UIMEnableAddressEndpoints - unknown address2: %d", this, address);
return(kIOReturnBadArgument);
}
}
if(!enable)
{
for(int i = 1; i<kXHCI_Num_Contexts; i++)
{
XHCIRing *ringX;
ringX = GetRing(slotID, i, 0);
if( (ringX != NULL) && (ringX->TRBBuffer != 0) )
{
StopEndpoint(slotID, i);
}
}
_devEnabled[address] = false;
}
return(kIOReturnSuccess);
}
IOReturn
AppleUSBXHCI::UIMEnableAllEndpoints(bool enable)
{
#pragma unused(enable)
USBLog(1, "AppleUSBXHCI[%p]::UIMEnableAllEndpoints- Unimplimented method called", this);
return(kIOReturnInternalError);
}
IOReturn AppleUSBXHCI::UIMDeviceToBeReset(short functionAddress)
{
int slotID;
slotID = GetSlotID(functionAddress);
if (slotID == 0)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMDeviceToBeReset - unknown address2: %d", this, functionAddress);
return(kIOReturnBadArgument);
}
if ((_errataBits & kXHCIErrataPPT) != 0)
{
_slots[slotID].deviceNeedsReset = false;
}
USBLog(3, "AppleUSBXHCI[%p]::UIMDeviceToBeReset - fn:%d, slot:%d", this, (int)functionAddress, slotID);
return(kIOReturnSuccess);
}
#pragma mark •••••••• Timeouts ••••••••
#define PRINT_RINGS (0)
bool
AppleUSBXHCI::checkEPForTimeOuts(int slot, int endp, UInt32 stream, UInt32 curFrame)
{
int enQueueIndex, deQueueIndex, ringSize, lastDeQueueIndex;
Context *epCtx;
int epState;
int epType;
bool stopped = false;
bool abortAll;
XHCIRing *ring;
ring = GetRing(slot, endp, stream);
if(ring == NULL)
{
USBTrace(kUSBTXHCI, kTPXHCICheckEPForTimeOuts, (uintptr_t)this, 0, ( (slot<<16) | endp), 0);
return(false);
}
abortAll = _slots[slot].deviceNeedsReset || !IsStillConnectedAndEnabled(slot);
deQueueIndex = ring->transferRingDequeueIdx;
enQueueIndex = ring->transferRingEnqueueIdx;
ringSize = ring->transferRingSize;
lastDeQueueIndex = ring->lastSeenDequeIdx;
USBLog(7, "AppleUSBXHCI[%p]::checkEPForTimeOuts - slot:%d ep:%d - eQIndex:%d, dQIndex:%d, lastDQIndex:%d, ringSize:%d", this, slot, endp, enQueueIndex, deQueueIndex, lastDeQueueIndex, ringSize);
USBTrace(kUSBTXHCI, kTPXHCICheckEPForTimeOuts, (uintptr_t)this, 1, ( (slot<<16) | endp), (stream<<16) | abortAll);
if (abortAll || ((lastDeQueueIndex == deQueueIndex) && (enQueueIndex != deQueueIndex)))
{
AppleXHCIAsyncEndpoint *pAsyncEP = OSDynamicCast(AppleXHCIAsyncEndpoint, (AppleXHCIAsyncEndpoint*)ring->pEndpoint);
USBTrace(kUSBTXHCI, kTPXHCICheckEPForTimeOuts, (uintptr_t)this, 2, ( (slot<<16) | endp), lastDeQueueIndex);
USBTrace(kUSBTXHCI, kTPXHCICheckEPForTimeOuts, (uintptr_t)this, 3, enQueueIndex, deQueueIndex);
if (pAsyncEP)
{
if (!abortAll && !pAsyncEP->NeedTimeouts())
{
USBTrace(kUSBTXHCI, kTPXHCICheckEPForTimeOuts, (uintptr_t)this, 4, ( (slot<<16) | endp), 0);
return false;
}
}
else
{
USBTrace(kUSBTXHCI, kTPXHCICheckEPForTimeOuts, (uintptr_t)this, 5, ( (slot<<16) | endp), 0);
return false;
}
epCtx = GetEndpointContext(slot, endp);
epType = GetEpCtxEpType(epCtx);
if (abortAll || (epType == kXHCIEpCtx_EPType_Control) || (epType == kXHCIEpCtx_EPType_BulkIN) || (epType == kXHCIEpCtx_EPType_BulkOut))
{
ClearStopTDs(slot, endp);
AppleXHCIAsyncTransferDescriptor *pActiveATD = pAsyncEP->activeQueue;
if (!pActiveATD)
{
USBTrace(kUSBTXHCI, kTPXHCICheckEPForTimeOuts, (uintptr_t)this, 7, ( (slot<<16) | endp), 0);
return false;
}
UInt32 noDataTimeouts = pActiveATD->activeCommand->GetNoDataTimeout();
if (noDataTimeouts != 0)
{
USBPhysicalAddress64 phys;
epState = GetEpCtxEpState(epCtx);
if (epState != kXHCIEpCtx_State_Running)
{
if( (epState != kXHCIEpCtx_State_Stopped) && (epState != kXHCIEpCtx_State_Disabled) )
{
USBLog(2, "AppleUSBXHCI[%p]::checkEPForTimeOuts - EP State: %d, slot:%d, ep:%d (eQIndex:%d, dQIndex:%d, ringSize:%d)",
this, epState, slot, endp, enQueueIndex, deQueueIndex, ringSize);
USBTrace(kUSBTXHCI, kTPXHCICheckEPForTimeOuts, (uintptr_t)this, 8, ( (slot<<16) | endp), epState);
PrintContext(GetSlotContext(slot));
PrintContext((Context *)epCtx);
}
}
else
{
if (abortAll || (stream == 0) )
{
USBLog(2, "AppleUSBXHCI[%p]::checkEPForTimeOuts - Stopping endpoint (%d, %d [%d]) (eQIndex:%d, dQIndex:%d, ringSize:%d)",
this, slot, endp, (int)stream, enQueueIndex, deQueueIndex, ringSize);
USBTrace(kUSBTXHCI, kTPXHCICheckEPForTimeOuts, (uintptr_t)this, 9, ( (slot<<16) | endp), epState);
StopEndpoint(slot, endp);
stopped = true;
}
else
{
USBLog(2, "AppleUSBXHCI[%p]::checkEPForTimeOuts - Not stopping stream endpoint (%d, %d [%d]) (eQIndex:%d, dQIndex:%d, ringSize:%d)",
this, slot, endp, (int)stream, enQueueIndex, deQueueIndex, ringSize);
USBTrace(kUSBTXHCI, kTPXHCICheckEPForTimeOuts, (uintptr_t)this, 10, ( (slot<<16) | endp), stream);
}
}
}
#if PRINT_RINGS
{
int deq1;
deq1 = deq-1;
if(deq1 < 0)
{
deq1 = siz-1;
}
char buf[256];
snprintf(buf, 256, "Index-: %d, c:%p phys:%08lx", deq1, (IOUSBCommandPtr)GetCommand(slot, endp, stream, deq1), (long unsigned int)(ring->transferRingPhys + deq1*sizeof(TRB)));
PrintTRB(2, &ring->transferRing[deq1], buf);
}
#endif
pAsyncEP->UpdateTimeouts(abortAll, curFrame, stopped);
}
}
else
{
ring->lastSeenDequeIdx = deQueueIndex;
}
return (stopped);
}
void AppleUSBXHCI::CheckSlotForTimeouts(int slot, UInt32 curFrame)
{
int endp;
if( _slots[slot].buffer != NULL)
{
for(endp = 1; endp<kXHCI_Num_Contexts; endp++)
{
XHCIRing *ring;
ring = GetRing(slot, endp, 0);
if ( (ring != NULL) && (ring->TRBBuffer != NULL) )
{
if (!IsIsocEP(slot, endp))
{
if(!IsStreamsEndpoint(slot, endp))
{
if(checkEPForTimeOuts(slot, endp, 0, curFrame))
{
USBLog(2, "AppleUSBXHCI[%p]::CheckSlotForTimeouts - Starting XHCIRing (%d, %d)", this, slot, endp);
USBTrace(kUSBTXHCI, kTPXHCICheckForTimeouts, (uintptr_t)this, 7, slot, endp);
StartEndpoint(slot, endp);
}
}
else
{
UInt32 maxStream;
bool stopped = false;
maxStream = _slots[slot].maxStream[endp];
#if PRINT_RINGS
USBLog(2, "AppleUSBXHCI[%p]::CheckSlotForTimeouts - streams endpoint (slot:%d, endp:%d, maxStream:%d)", this, (int)slot, (int)endp, (int)maxStream);
PrintContext(GetEndpointContext(slot, endp));
#endif
for(UInt32 i = 1; i<=maxStream; i++)
{
#if PRINT_RINGS
USBLog(2, "AppleUSBXHCI[%p]::CheckSlotForTimeouts - stream:%d ctx:%08lx, %08lx [%08lx, %08lx] (@%08lx)", this, (int)i, (long unsigned int)ring->transferRing[i].offs0, (long unsigned int)ring->transferRing[i].offs4, (long unsigned int)ring->transferRing[i].offs8, (long unsigned int)ring->transferRing[i].offsC, (long unsigned int)ring->transferRingPhys+i*sizeof(TRB));
#endif
if(checkEPForTimeOuts(slot, endp, i, curFrame))
{
USBTrace(kUSBTXHCI, kTPXHCICheckForTimeouts, (uintptr_t)this, 9, ( (slot<<16) | endp), i);
stopped = true;
}
}
if(stopped)
{
USBLog(7, "AppleUSBXHCI[%p]::CheckSlotForTimeout - restarting @%d, %d", this, slot, endp);
USBTrace(kUSBTXHCI, kTPXHCICheckForTimeouts, (uintptr_t)this, 10, slot, endp);
RestartStreams(slot, endp, 0);
}
}
}
}
}
}
}
void AppleUSBXHCI::UIMCheckForTimeouts(void)
{
int slot, endp;
TRB nextEvent;
UInt32 curFrame = GetFrameNumber32();
if((Read32Reg(&_pXHCIRegisters->USBSTS)& kXHCIHSEBit) != 0)
{
if(!_HSEReported)
{
USBError(1, "AppleUSBXHCI[%p]::UIMCheckForTimeouts - HSE bit set:%x (1)", this, USBToHostLong(_pXHCIRegisters->USBSTS));
}
_HSEReported = true;
}
USBTrace_Start(kUSBTXHCI, kTPXHCICheckForTimeouts, (uintptr_t)this, _numInterrupts, _numPrimaryInterrupts, _numInactiveInterrupts);
if(_lostRegisterAccess)
{
USBLog(3, "AppleUSBXHCI[%p]::UIMCheckForTimeouts - Controller is not available - complete outstanding requests", this);
for(slot = 0; slot<_numDeviceSlots; slot++)
{
CheckSlotForTimeouts(slot, 0);
}
if(_expansionData != NULL)
{
_watchdogTimerActive = false;
if(_watchdogUSBTimer != NULL)
{
_watchdogUSBTimer->cancelTimeout();
}
}
return;
}
for(slot = 0; slot<_numDeviceSlots; slot++)
{
if ( !IsStillConnectedAndEnabled(slot) )
{
CheckSlotForTimeouts(slot, curFrame);
}
}
if (_powerStateChangingTo != kUSBPowerStateStable && _powerStateChangingTo < kUSBPowerStateOn )
{
USBLog(6, "AppleUSBXHCI[%p]::UIMCheckForTimeouts - Controller power state is not stable [going to sleep] (_powerStateChangingTo = %d, _myPowerState = %d), returning", this, (int)_powerStateChangingTo, (int)_myPowerState);
USBTrace(kUSBTXHCI, kTPXHCICheckForTimeouts, (uintptr_t)this, 1, _powerStateChangingTo, _myPowerState);
return;
}
if (_powerStateChangingTo != kUSBPowerStateStable )
{
USBLog(6, "AppleUSBXHCI[%p]::UIMCheckForTimeouts - Controller power state is not stable [waking up] (_powerStateChangingTo = %d, _myPowerState = %d),", this, (int)_powerStateChangingTo, (int)_myPowerState);
USBTrace(kUSBTXHCI, kTPXHCICheckForTimeouts, (uintptr_t)this, 2, _powerStateChangingTo, _myPowerState);
}
if (Read32Reg(&_pXHCIRuntimeReg->MFINDEX) == 0)
{ USBLog(7, "AppleUSBXHCI[%p]::UIMCheckForTimeouts - MFINDEX is 0, not doing anything", this);
USBTrace(kUSBTXHCI, kTPXHCICheckForTimeouts, (uintptr_t)this, 3, _powerStateChangingTo, _myPowerState);
return;
}
if (_lostRegisterAccess)
{
return;
}
for(slot = 0; slot<_numDeviceSlots; slot++)
{
CheckSlotForTimeouts(slot, curFrame);
}
#if 0
if(0)
{
PrintRuntimeRegs();
Printinterrupter(5, 0, "UIMCheckForTimeouts");
}
#endif
#if 0
for(int IRQ = 0; IRQ < 2; IRQ++)
{
USBLog(3, "AppleUSBXHCI[%p]::UIMCheckForTimeouts IRQ:%d _EventRingDequeueIdx:%d, _EventRing2DequeueIdx:%d", this, IRQ, _events[IRQ].EventRingDequeueIdx, _events[IRQ].EventRing2DequeueIdx);
nextEvent = _events[IRQ].EventRing[_events[IRQ].EventRingDequeueIdx];
if( (USBToHostLong(nextEvent.offsC) & kXHCITRB_C) == _events[IRQ].EventRingCCS)
{
PrintTRB(3, &nextEvent, "UIMCheckForTimeouts EventRing");
}
nextEvent = _events[IRQ].EventRing2[_events[IRQ].EventRing2DequeueIdx];
if(_events[IRQ].EventRing2DequeueIdx != _events[IRQ].EventRing2EnqueueIdx)
{ PrintTRB(3, &nextEvent, "UIMCheckForTimeouts EventRing2");
}
}
PrintRuntimeRegs();
Printinterrupter(3, kPrimaryinterrupter, "UIMCheckForTimeouts");
Printinterrupter(3, kTransferinterrupter, "UIMCheckForTimeouts");
#if 0
USBLog(3, "AppleUSBXHCI[%p]::Config Space:", this);
for(int i = 0 ; i<256; i+=16)
{
UInt32 u1, u2, u3 ,u4;
u1 = _device->configRead32(i);
u2 = _device->configRead32(i+4);
u3 = _device->configRead32(i+8);
u4 = _device->configRead32(i+12);
USBLog(3, "%02x: %08lx %08lx %08lx %08lx", i, (long unsigned int)u1, (long unsigned int)u2, (long unsigned int)u3 ,(long unsigned int)u4);
}
#endif
#endif
}
USBDeviceAddress
AppleUSBXHCI::UIMGetActualDeviceAddress(USBDeviceAddress current)
{
UInt32 slotID;
USBDeviceAddress actual;
slotID = GetSlotID(current);
if(slotID == 0)
{
USBLog(1, "AppleUSBXHCI[%p]::UIMGetActualDeviceAddress - current address not found %d", this, current);
return(0);
}
actual = GetSlCtxUSBAddress(GetSlotContext(slotID));
if(actual != current)
{
if(_devEnabled[actual])
{
USBLog(1, "AppleUSBXHCI[%p]::UIMGetActualDeviceAddress - Actual mapping already enabled, returning mpped address (actual:%d, current:%d, map[act]:%d)", this, actual, current, _devMapping[actual]);
return(current);
}
USBLog(6, "AppleUSBXHCI[%p]::UIMGetActualDeviceAddress - swapping map[%d] with map[%d]", this, actual, current);
_devHub[actual] = _devHub[current] ;
_devPort[actual] = _devPort[current];
_devMapping[actual] = _devMapping[current];
_devEnabled[actual] = _devEnabled[current];
_devHub[current] = 0;
_devPort[current] = 0;
_devMapping[current] = 0;
_devEnabled[current] = false;
}
else
{
USBLog(2, "AppleUSBXHCI[%p]::UIMGetActualDeviceAddress - address not changing %d", this, actual);
}
return actual;
}
#pragma mark •••••••• xMux and eMux Control ••••••••
IOReturn
AppleUSBXHCI::HCSelectWithMethod ( char *muxMethod )
{
IOReturn status = kIOReturnSuccess;
UInt32 assertVal = 0;
if ( !_discoveredMuxedPorts )
{
DiscoverMuxedPorts();
}
if( _acpiDevice != NULL )
{
status = _acpiDevice->evaluateInteger ( muxMethod, &assertVal );
}
else
{
status = kIOReturnUnsupported;
}
return status;
}
IOReturn
AppleUSBXHCI::HCSelect ( UInt8 port, UInt8 controllerType )
{
IOReturn status = kIOReturnNoMemory;
if ( !_discoveredMuxedPorts )
{
DiscoverMuxedPorts();
}
USBLog(5, "AppleUSBXHCI[%p]::HCSelect for acpIDevice %p, port: %d, hcSelect: %d", this, _acpiDevice, port, controllerType);
if( (_acpiDevice != NULL) && _muxedPorts && (port < kMaxHCPortMethods) )
{
if( controllerType == kControllerXHCI )
{
status = HCSelectWithMethod( (char*)xhciMuxedPorts[port] );
}
else if( controllerType == kControllerEHCI )
{
status = HCSelectWithMethod( ehciMuxedPorts[port] );
}
}
USBLog(5, "AppleUSBXHCI[%p]::HCSelect for acpIDevice %p, status 0x%x", this, _acpiDevice, status);
return status;
}
bool
AppleUSBXHCI::DiscoverMuxedPorts( )
{
UInt8 port;
UInt32 locationID;
UInt8 totalMuxedPorts = 0;
if (_rootHubDeviceSS && !_muxedPorts && ((_errataBits & kXHCIErrataPPTMux) != 0) )
{
OSNumber *locationIDProperty = (OSNumber *)_rootHubDeviceSS->getProperty(kUSBDevicePropertyLocationID);
if ( locationIDProperty )
{
locationID = locationIDProperty->unsigned32BitValue();
_acpiDevice = CopyACPIDevice(_device);
if (_acpiDevice)
{
for(port = 1; port < kMaxHCPortMethods; port++)
{
if( IsPortMuxed(_device, port, locationID, ehciMuxedPorts[port-1]) )
{
USBLog(6, "AppleUSBXHCI[%p]::DiscoverMuxedPorts port %d method %s", this, port, ehciMuxedPorts[port-1]);
totalMuxedPorts++;
}
}
}
}
}
if( totalMuxedPorts > 0 )
{
_muxedPorts = true;
}
_discoveredMuxedPorts = true;
USBLog(6, "AppleUSBXHCI[%p]::DiscoverMuxedPorts returning %s", this, _muxedPorts ? "TRUE" : "FALSE");
return _muxedPorts;
}
bool
AppleUSBXHCI::HasMuxedPorts( )
{
UInt8 port = 0;
bool muxedPorts = true;
USBLog(6, "AppleUSBXHCI[%p]::HasMuxedPorts (%p)", this, _acpiDevice);
for(port = 0; (port < kMaxHCPortMethods) && (_muxedPorts == true) ; port++)
{
if ( _acpiDevice->validateObject ( xhciMuxedPorts[port] ) != kIOReturnSuccess )
{
muxedPorts = false;
}
if ( _acpiDevice->validateObject ( ehciMuxedPorts[port] ) != kIOReturnSuccess )
{
muxedPorts = false;
}
}
USBLog(6, "AppleUSBXHCI[%p]::HasMuxedPorts returning %s", this, muxedPorts ? "TRUE" : "FALSE");
return muxedPorts;
}
void
AppleUSBXHCI::EnableXHCIPorts()
{
if( (_errataBits & kXHCIErrataPPTMux) == 0)
{
goto Exit;
}
UInt32 HCSEL, HCSELM, USB3SSEN, USB3PRM;
HCSEL = _device->configRead32(kXHCI_XUSB2PR);
if (HCSEL == (UInt32)-1)
{
goto ControllerNotAvailable;
}
HCSELM = _device->configRead32(kXHCI_XUSB2PRM);
if (HCSELM == (UInt32)-1)
{
goto ControllerNotAvailable;
}
USB3SSEN = _device->configRead32(kXHCI_XUSB3_PSSEN);
if (USB3SSEN == (UInt32)-1)
{
goto ControllerNotAvailable;
}
USB3PRM = _device->configRead32(kXHCI_XUSB3PRM);
if (USB3PRM == (UInt32)-1)
{
goto ControllerNotAvailable;
}
if(HCSEL == 0)
{
_device->configWrite32(kXHCI_XUSB2PR, HCSELM);
}
if(USB3SSEN == 0)
{
_device->configWrite32(kXHCI_XUSB3_PSSEN, USB3PRM);
}
USBLog(3, "AppleUSBXHCI[%p]::EnableXHCIPorts - HCSEL: %lx, HCSELM: %lx USB3SSEN: %lx USB3PRM: %lx",
this, (long unsigned int)HCSEL, (long unsigned int)HCSELM, (long unsigned int)USB3SSEN, (long unsigned int)USB3PRM);
Exit:
return;
ControllerNotAvailable:
_lostRegisterAccess = false;
}
#pragma mark •••••••• Test Mode ••••••••
enum
{
kXHCIUSB2TestMode_Off = 0,
kXHCIUSB2TestMode_J_State = 1,
kXHCIUSB2TestMode_K_State = 2,
kXHCIUSB2TestMode_SE0_NAK = 3,
kXHCIUSB2TestMode_Packet = 4,
kXHCIUSB2TestMode_ForceEnable = 5,
kEHCITestMode_Start = 10,
kEHCITestMode_End = 11,
kXHCIUSB2TestModeControlError = 15
};
void
AppleUSBXHCI::EnableComplianceMode()
{
volatile UInt32 bits;
if( ( ( (_errataBits & kXHCIErrataPPT) != 0 ) || ( (_errataBits & kXHCIErrata_FrescoLogic ) != 0 ) ) && ( (_errataBits & kXHCIErrata_EnableAutoCompliance) == 0 ) )
{
_pXHCIPPTChickenBits = (UInt32 *) ( ((uintptr_t)_pXHCICapRegisters) + 0x80EC);
bits = *_pXHCIPPTChickenBits;
bits &= ~kXHCIBit0;
*_pXHCIPPTChickenBits = bits;
USBLog(3, "AppleUSBXHCI[%p]::EnableComplianceMode - _pXHCIPPTChickenBits:%p, writing:%x", this, _pXHCIPPTChickenBits, (int)bits);
}
}
void
AppleUSBXHCI::DisableComplianceMode()
{
volatile UInt32 bits;
if( ( ( (_errataBits & kXHCIErrataPPT) != 0 ) || ( (_errataBits & kXHCIErrata_FrescoLogic ) != 0 ) ) && ( (_errataBits & kXHCIErrata_EnableAutoCompliance) == 0 ) )
{
_pXHCIPPTChickenBits = (UInt32 *) ( ((uintptr_t)_pXHCICapRegisters) + 0x80EC);
bits = *_pXHCIPPTChickenBits;
bits |= kXHCIBit0;
*_pXHCIPPTChickenBits = bits;
USBLog(3, "AppleUSBXHCI[%p]::DisableComplianceMode - _pXHCIPPTChickenBits:%p, writing:%x", this, _pXHCIPPTChickenBits, (int)bits);
}
}
IOReturn
AppleUSBXHCI::UIMSetTestMode(UInt32 mode, UInt32 port)
{
IOReturn ret = kIOReturnInternalError;
USBLog(1, "AppleUSBXHCI[%p]::UIMSetTestMode(%d, %d)", this, (int)mode, (int)port);
switch (mode)
{
case kXHCIUSB2TestMode_Off:
case kXHCIUSB2TestMode_J_State:
case kXHCIUSB2TestMode_K_State:
case kXHCIUSB2TestMode_SE0_NAK:
case kXHCIUSB2TestMode_Packet:
case kXHCIUSB2TestMode_ForceEnable:
if (_testModeEnabled)
ret = PlacePortInMode(port, mode);
break;
case kEHCITestMode_Start:
ret = EnterTestMode();
break;
case kEHCITestMode_End:
ret = LeaveTestMode();
break;
}
return ret;
}
IOReturn
AppleUSBXHCI::EnterTestMode()
{
UInt32 usbcmd, usbsts;
UInt8 numPorts;
int port;
IOReturn status = kIOReturnSuccess;
USBLog(1, "AppleUSBXHCI[%p]::EnterTestMode", this);
EnableComplianceMode();
numPorts = _rootHubNumPorts;
USBLog(1, "AppleUSBXHCI[%p]::EnterTestMode - %d ports", this, numPorts);
for (port=0; port < numPorts; port++)
{
UInt32 portSC = Read32Reg(&_pXHCIRegisters->PortReg[port].PortSC);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
USBLog(1, "AppleUSBXHCI[%p]::EnterTestMode - portSC 0x%lx", this, (long unsigned int)portSC);
if ( (portSC & kXHCIPortSC_PP) != 0 )
{
XHCIRootHubPowerPort((port+1), false);
}
}
status = StopUSBBus();
if( status != kIOReturnSuccess )
return status;
_myBusState = kUSBBusStateReset;
USBLog(1, "AppleUSBXHCI[%p]::EnterTestMode - HC halted - now in test mode", this);
_testModeEnabled = true;
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::PlacePortInMode(UInt32 port, UInt32 mode)
{
UInt32 portStat;
UInt8 numPorts;
UInt32 usbCmdReg;
IOReturn status = kIOReturnInternalError;
USBLog(1, "AppleUSBXHCI[%p]::PlacePortinMode(port %d, mode %d)", this, (int)port, (int)mode);
if (!_testModeEnabled)
{
USBLog(1, "AppleUSBXHCI[%p]::PlacePortinMode - ERROR test mode not enabled", this);
return status;
}
numPorts = _rootHubNumPorts;
if (port >= numPorts)
{
USBLog(1, "AppleUSBXHCI[%p]::PlacePortinMode - ERROR invalid port %d", this, (int)port);
return status;
}
AdjustRootHubPortNumbers(kUSBDeviceSpeedHigh, (UInt16*)&port);
UInt32 portPMSC = Read32Reg(&_pXHCIRegisters->PortReg[port].PortPMSC);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
if (mode != kXHCIUSB2TestMode_ForceEnable)
{
status = StopUSBBus();
if( status != kIOReturnSuccess )
return status;
}
USBLog(1, "AppleUSBXHCI[%p]::PlacePortinMode - old portPMSC = %x", this, (int)portPMSC);
portPMSC &= ~kXHCIPortMSC_PortTestControl_Mask;
portPMSC |= (mode << kXHCIPortMSC_PortTestControl_Shift);
USBLog(1, "AppleUSBXHCI[%p]::PlacePortinMode - new portPMSC = %x", this, (int)portPMSC);
Write32Reg(&_pXHCIRegisters->PortReg[port].PortPMSC, portPMSC);
if (mode == kXHCIUSB2TestMode_ForceEnable)
{
usbCmdReg = Read32Reg(&_pXHCIRegisters->USBCMD);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
usbCmdReg |= kXHCICMDRunStop;
Write32Reg(&_pXHCIRegisters->USBCMD, usbCmdReg);
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::LeaveTestMode()
{
UInt32 CMD, count=0;
int i = 0;
IOReturn status = kIOReturnSuccess;
USBLog(1, "AppleUSBXHCI[%p]::LeaveTestMode", this);
DisableComplianceMode();
status = StopUSBBus();
if( status != kIOReturnSuccess )
return status;
status = ResetController();
if( status != kIOReturnSuccess )
return status;
_testModeEnabled = false;
return status;
}
#pragma mark •••••••• IOKit Methods ••••••••
bool
AppleUSBXHCI::terminate(IOOptionBits options)
{
USBLog(3, "AppleUSBXHCI[%p]::terminate", this);
_lostRegisterAccess = true;
return super::terminate(options);
}
bool
AppleUSBXHCI::willTerminate(IOService *provider, IOOptionBits options)
{
if(_expansionData != NULL)
{
if((_watchdogTimerActive == true) && (_watchdogUSBTimer != NULL))
{
_watchdogUSBTimer->setTimeoutUS(1);
}
}
return super::willTerminate(provider, options);
}
#pragma mark •••••••• Utility Methods ••••••••
bool AppleUSBXHCI::CheckControllerAvailable(bool quiet)
{
UInt32 CRCRLo;
if (!_pXHCIRegisters)
return false;
if (_lostRegisterAccess)
return false;
CRCRLo = *(UInt32 *)&_pXHCIRegisters->CRCR;
if(CRCRLo == kXHCIInvalidRegisterValue)
{
if(!quiet && !_lostRegisterAccess)
{
USBLog(2,"AppleUSBXHCI[%p]::CheckControllerAvailable CRCR invalid value: %x", this, (int)CRCRLo );
}
_lostRegisterAccess = true;
_controllerAvailable = false;
return(false);
}
else
{
return(true);
}
}
const char *
AppleUSBXHCI::EndpointState(int state)
{
switch (state)
{
case kXHCIEpCtx_State_Disabled:
return "Disabled";
case kXHCIEpCtx_State_Running:
return "Running";
case kXHCIEpCtx_State_Halted:
return "Halted";
case kXHCIEpCtx_State_Stopped:
return "Stopped";
case kXHCIEpCtx_State_Error:
return "Error";
default:
return "Unknown EndpointState";
}
}
const char *
AppleUSBXHCI::TRBType(int type)
{
switch (type)
{
case kXHCITRB_Normal:
return "Normal";
case kXHCITRB_Setup:
return "Setup Stage";
case kXHCITRB_Data:
return "Data Stage";
case kXHCITRB_Status:
return "Status Stage";
case kXHCITRB_Isoc:
return "Isoch";
case kXHCITRB_Link:
return "Link";
case kXHCITRB_EventData:
return "Event Data";
case kXHCITRB_TrNoOp:
return "No-Op";
case kXHCITRB_EnableSlot:
return "Enable Slot Command";
case kXHCITRB_DisableSlot:
return "Disable Slot Command";
case kXHCITRB_AddressDevice:
return "Address Device Command";
case kXHCITRB_ConfigureEndpoint:
return "Configure Endpoint Command";
case kXHCITRB_EvaluateContext:
return "Evaluate Context Command";
case kXHCITRB_ResetEndpoint:
return "Reset Endpoint Command";
case kXHCITRB_StopEndpoint:
return "Stop Endpoint Command";
case kXHCITRB_SetTRDqPtr:
return "Set TR Dequeue Pointer Command";
case kXHCITRB_ResetDevice:
return "Reset Device Command";
case kXHCITRB_GetPortBandwidth:
return "Get Port Bandwidth Command";
case kXHCITRB_CMDNoOp:
return "No Op Command";
case kXHCITRB_TE:
return "Transfer Event";
case kXHCITRB_CCE:
return "Command Completion Event";
case kXHCITRB_PSCE:
return "Port Status Change Event";
case kXHCITRB_DevNot:
return "Bandwidth Request Event";
case kXHCITRB_MFWE:
return "MFIndex Wrap Event";
case kXHCITRB_NECCCE:
return "NEC Vendor Defined Command";
case kXHCITRB_CMDNEC:
return "NEC Firmware Req Command";
default:
return "Unknown TRBType";
}
}
AppleXHCIAsyncEndpoint*
AppleUSBXHCI::AllocateAppleXHCIAsyncEndpoint(XHCIRing *ring, UInt32 maxPacketSize, UInt32 maxBurst, UInt32 mult)
{
AppleXHCIAsyncEndpoint *pEP;
pEP = new AppleXHCIAsyncEndpoint;
if (pEP)
{
if (!pEP->init(this, ring, maxPacketSize, maxBurst, mult))
{
pEP->release();
pEP = NULL;
}
}
USBLog(2,"-AppleUSBXHCI[%p]::AllocateAppleXHCIAsyncEndpoint %p maxPacketSize %d maxBurst %d mult %d", this, pEP, (int)maxPacketSize, (int)maxBurst, (int)mult);
return pEP;
}
IODMACommand*
AppleUSBXHCI::GetNewDMACommand()
{
USBLog(7, "AppleUSBXHCI[%p]::GetNewDMACommand - creating %d bit IODMACommand", this, _AC64 ? 64 : 32);
return IODMACommand::withSpecification(kIODMACommandOutputHost64, _AC64 ? 64 : 32, 0);
}