AppleUSBXHCI_RootHub.cpp [plain text]
extern "C" {
#include <kern/clock.h>
}
#include <libkern/OSByteOrder.h>
#include <IOKit/usb/USB.h>
#include <IOKit/usb/IOUSBLog.h>
#include <IOKit/usb/IOUSBRootHubDevice.h>
#include "AppleUSBXHCIUIM.h"
#include "AppleUSBXHCI_RootHub.h"
const UInt64 kOneHundredMillisecondsInNanoseconds = (UInt64) 100 * ((UInt64) (1000 * 1000));
const UInt64 kConnectionDebounceIntervalInNanos = kOneHundredMillisecondsInNanoseconds;
#ifndef APPLEXHCIROOTHUB_USE_KPRINTF
#define APPLEXHCIROOTHUB_USE_KPRINTF 0
#endif
#if APPLEXHCIROOTHUB_USE_KPRINTF
#undef USBLog
#undef USBError
void kprintf(const char *format, ...) __attribute__((format(printf, 1, 2)));
#define USBLog( LEVEL, FORMAT, ARGS... ) if ((LEVEL) <= APPLEXHCIROOTHUB_USE_KPRINTF) { kprintf( FORMAT "\n", ## ARGS ) ; }
#define USBError( LEVEL, FORMAT, ARGS... ) { kprintf( FORMAT "\n", ## ARGS ) ; }
#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
#pragma mark Descriptors
IOReturn
AppleUSBXHCI::GetRootHubDeviceDescriptor(IOUSBDeviceDescriptor *desc)
{
IOUSBDeviceDescriptor SSDesc =
{
sizeof(IOUSBDeviceDescriptor), kUSBDeviceDesc, HostToUSBWord(kUSBRel30), kUSBHubClass, kUSBHubSubClass, kHubSuperSpeedProtocol, 9, HostToUSBWord(kAppleVendorID), HostToUSBWord(kPrdRootHubAppleSS), HostToUSBWord(kUSBRel30), 2, 1, 0, 1 };
IOUSBDeviceDescriptor HSDesc =
{
sizeof(IOUSBDeviceDescriptor), kUSBDeviceDesc, HostToUSBWord(kUSBRel20), kUSBHubClass, kUSBHubSubClass, 1, 9, HostToUSBWord(kAppleVendorID), HostToUSBWord(kPrdRootHubAppleSS), HostToUSBWord(kUSBRel30), 2, 1, 0, 1 };
if (!desc)
return kIOReturnNoMemory;
RHCommandHeaderPtr command = (RHCommandHeaderPtr)(desc);
UInt8 speed = ((command->request & kUSBSpeed_Mask) >> kUSBSpeed_Shift);
USBLog(3, "AppleUSBXHCI[%p]::GetRootHubDeviceDescriptor - speed: %d", this, speed);
if( speed == kUSBDeviceSpeedHigh )
{
bcopy(&HSDesc, desc, HSDesc.bLength);
}
else
{
bcopy(&SSDesc, desc, SSDesc.bLength);
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::GetRootHubStringDescriptor(UInt8 index, OSData *desc)
{
USBLog(3, "AppleUSBXHCI[%p]::GetRootHubStringDescriptor - desc: %d", this, index);
UInt8 productNameSS[] = {
0, kUSBStringDesc, 0x58, 0x00, 0x48, 0x00, 0x43, 0x00, 0x49, 0x00, 0x20, 0x00, 0x52, 0x00, 0x6F, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x20, 0x00, 0x48, 0x00, 0x75, 0x00, 0x62, 0x00, 0x20, 0x00, 0x53, 0x00, 0x53, 0x00, 0x20, 0x00, 0x53, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x75, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, };
UInt8 productNameHS[] = {
0, kUSBStringDesc, 0x58, 0x00, 0x48, 0x00, 0x43, 0x00, 0x49, 0x00, 0x20, 0x00, 0x52, 0x00, 0x6F, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x20, 0x00, 0x48, 0x00, 0x75, 0x00, 0x62, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x20, 0x00, 0x53, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x75, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, };
UInt8 vendorName[] = {
0, kUSBStringDesc, 0x41, 0x00, 0x70, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x2e, 0x00 };
if ( (index > 2) || (index == 0) )
return kIOReturnBadArgument;
if (!desc)
return kIOReturnNoMemory;
vendorName[0] = sizeof(vendorName);
productNameSS[0] = sizeof(productNameSS);
productNameHS[0] = sizeof(productNameHS);
if ( index == 1 )
{
RHCommandHeaderPtr command = (RHCommandHeaderPtr)(desc->getBytesNoCopy());
UInt8 speed = 0;
if(command)
{
speed = ((command->request & kUSBSpeed_Mask) >> kUSBSpeed_Shift);
}
USBLog(3, "AppleUSBXHCI[%p]::GetRootHubStringDescriptor - speed: %d", this, speed);
if( speed == kUSBDeviceSpeedHigh )
{
if (!desc->appendBytes(&productNameHS, productNameHS[0]))
return kIOReturnNoMemory;
}
else
{
if (!desc->appendBytes(&productNameSS, productNameSS[0]))
return kIOReturnNoMemory;
}
}
if ( index == 2 )
{
if (!desc->appendBytes(&vendorName, vendorName[0]))
return kIOReturnNoMemory;
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::GetRootHubConfDescriptor(OSData *desc)
{
IOUSBConfigurationDescriptor confDesc =
{
sizeof(IOUSBConfigurationDescriptor), kUSBConfDesc, HostToUSBWord(sizeof(IOUSBConfigurationDescriptor) +
sizeof(IOUSBInterfaceDescriptor) +
sizeof(IOUSBEndpointDescriptor) +
sizeof(IOUSBSuperSpeedEndpointCompanionDescriptor)), 1, 1, 0, 0x60, 0, };
IOUSBInterfaceDescriptor intfDesc =
{
sizeof(IOUSBInterfaceDescriptor), kUSBInterfaceDesc, 0, 0, 1, kUSBHubClass, kUSBHubSubClass, 0, 0 };
IOUSBEndpointDescriptor endptDesc =
{
sizeof(IOUSBEndpointDescriptor), kUSBEndpointDesc, 0x81, 0x10 | kUSBInterrupt, HostToUSBWord(2), 9, };
IOUSBSuperSpeedEndpointCompanionDescriptor compDesc =
{
sizeof(IOUSBSuperSpeedEndpointCompanionDescriptor), kUSBSuperSpeedEndpointCompanion, 0, 0, 2 };
if (!desc)
return(kIOReturnNoMemory);
if (!desc->appendBytes(&confDesc, confDesc.bLength))
return(kIOReturnNoMemory);
if (!desc->appendBytes(&intfDesc, intfDesc.bLength))
return(kIOReturnNoMemory);
if (!desc->appendBytes(&endptDesc, endptDesc.bLength))
return(kIOReturnNoMemory);
if (!desc->appendBytes(&compDesc, compDesc.bLength))
return(kIOReturnNoMemory);
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::GetRootHubBOSDescriptor(OSData *desc)
{
#define APPLE_XHCI_UUID 0xDF, 0xFB, 0x1E, 0x9E, 0x1B, 0x1D, 0x10, 0x46, 0xAE, 0x91, 0x3B, 0x66, 0xF5, 0x56, 0x1D, 0xA
USBLog(6, "AppleUSBXHCI[%p]::GetRootHubBOSDescriptor", this);
IOUSBBOSDescriptor bosDesc =
{
sizeof(IOUSBBOSDescriptor), kUSBBOSDescriptor, HostToUSBWord(sizeof(IOUSBBOSDescriptor) +
sizeof(IOUSBDeviceCapabilityUSB2Extension) +
sizeof(IOUSBDeviceCapabilitySuperSpeedUSB) +
sizeof(IOUSBDeviceCapabilityContainerID)), 3 };
IOUSBDeviceCapabilityUSB2Extension capDesc =
{
sizeof(IOUSBDeviceCapabilityUSB2Extension), kUSBDeviceCapability, kUSBDeviceCapabilityUSB20Extension, HostToUSBLong(1<<kUSB20ExtensionLPMSupported) };
IOUSBDeviceCapabilitySuperSpeedUSB ssCapDesc =
{
sizeof(IOUSBDeviceCapabilitySuperSpeedUSB), kUSBDeviceCapability, kUSBDeviceCapabilitySuperSpeedUSB, HostToUSBLong(1<<kUSBSuperSpeedLTMCapable), HostToUSBWord(1<<kUSBSuperSpeedSupportsHS |
1<<kUSBSuperSpeedSupportsSS ), (1<<kUSBSuperSpeedSupportsSS), 10, HostToUSBWord(100) };
IOUSBDeviceCapabilityContainerID containerDesc =
{
sizeof(IOUSBDeviceCapabilityContainerID), kUSBDeviceCapability, kUSBDeviceCapabilityContainerID, 0, {APPLE_XHCI_UUID} };
if (!desc)
return(kIOReturnNoMemory);
if (!desc->appendBytes(&bosDesc, bosDesc.bLength))
return(kIOReturnNoMemory);
if (!desc->appendBytes(&capDesc, capDesc.bLength))
return(kIOReturnNoMemory);
if (!desc->appendBytes(&ssCapDesc, ssCapDesc.bLength))
return(kIOReturnNoMemory);
if (!desc->appendBytes(&containerDesc, containerDesc.bLength))
return(kIOReturnNoMemory);
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::GetRootHubDescriptor(IOUSBHubDescriptor *desc)
{
IOUSBHubDescriptor hubDesc;
UInt32 HCSParams;
UInt8 pps;
unsigned int i, numBytes;
UInt8 * dstPtr;
UInt32 appleCaptive = 0;
OSNumber * appleCaptiveProperty = NULL;
hubDesc.length = sizeof(IOUSBHubDescriptor);
hubDesc.hubType = kUSBHubDescriptorType;
HCSParams = Read32Reg(&_pXHCICapRegisters->HCCParams);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
hubDesc.numPorts = _v3ExpansionData->_rootHubNumPortsHS;
pps = (HCSParams & kXHCIPPCBit) != 0;
hubDesc.characteristics = 0;
hubDesc.characteristics |= (pps ? kPerPortSwitchingBit : 0);
if ( !(hubDesc.characteristics & ( kNoOverCurrentBit | kPerPortOverCurrentBit)) )
{
}
hubDesc.characteristics = HostToUSBWord(hubDesc.characteristics);
hubDesc.powerOnToGood = 50; hubDesc.hubCurrent = 0;
numBytes = (hubDesc.numPorts + 1) / 8 + 1;
appleCaptiveProperty = OSDynamicCast(OSNumber, _device->getProperty(kAppleInternalUSBDevice));
if (appleCaptiveProperty)
appleCaptive = appleCaptiveProperty->unsigned32BitValue();
dstPtr = (UInt8 *)&hubDesc.removablePortFlags[0];
for ( i = 0; i < numBytes; i++)
{
*dstPtr++ = (UInt8) (appleCaptive & 0xFF);
appleCaptive >>= 8;
}
for (i=0; i<numBytes; i++)
{
*dstPtr++ = 0xFF;
}
hubDesc.length -= ((sizeof(hubDesc.removablePortFlags) - numBytes) +
(sizeof(hubDesc.pwrCtlPortFlags) - numBytes));
if (!desc)
return kIOReturnNoMemory;
bcopy(&hubDesc, desc, hubDesc.length);
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::GetRootHub3Descriptor(IOUSB3HubDescriptor *desc)
{
IOUSB3HubDescriptor hubDesc;
UInt32 HCCParams;
UInt8 pps;
unsigned int i, numBytes;
UInt8 * dstPtr;
UInt32 appleCaptive = 0;
OSNumber * appleCaptiveProperty = NULL;
hubDesc.length = sizeof(IOUSB3HubDescriptor);
hubDesc.hubType = kUSB3HubDescriptorType;
HCCParams = Read32Reg(&_pXHCICapRegisters->HCCParams);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
hubDesc.numPorts = _v3ExpansionData->_rootHubNumPortsSS;
pps = (HCCParams & kXHCIPPCBit) != 0;
hubDesc.characteristics = 0;
hubDesc.characteristics |= (pps ? kPerPortSwitchingBit : 0);
if ( !(hubDesc.characteristics & ( kNoOverCurrentBit | kPerPortOverCurrentBit)) )
{
}
hubDesc.characteristics = HostToUSBWord(hubDesc.characteristics);
hubDesc.powerOnToGood = 50; hubDesc.hubCurrent = 0;
hubDesc.hubHdrDecLat = 0;
hubDesc.hubDelay = 10;
numBytes = (hubDesc.numPorts + 1) / 8 + 1;
appleCaptiveProperty = OSDynamicCast(OSNumber, _device->getProperty(kAppleInternalUSBDevice));
if (appleCaptiveProperty)
appleCaptive = appleCaptiveProperty->unsigned32BitValue();
dstPtr = (UInt8 *)&hubDesc.removablePortFlags[0];
for ( i = 0; i < numBytes; i++)
{
*dstPtr++ = (UInt8) (appleCaptive & 0xFF);
appleCaptive >>= 8;
}
for (i=0; i<numBytes; i++)
{
*dstPtr++ = 0xFF;
}
if (!desc)
return kIOReturnNoMemory;
bcopy(&hubDesc, desc, hubDesc.length);
return kIOReturnSuccess;
}
#pragma mark Root Hub Methods
IOReturn
AppleUSBXHCI::SetHubAddress(UInt16 wValue)
{
UInt8 speed = ((wValue & kUSBSpeed_Mask) >> kUSBSpeed_Shift);
UInt16 address = ((wValue & kUSBAddress_Mask) >> kUSBAddress_Shift);
USBLog(3, "AppleUSBXHCI[%p]::SetHubAddress - set to: %d address: %d speed: %d", this, wValue, address, speed);
if(speed == kUSBDeviceSpeedSuper)
{
_rootHubFuncAddressSS = address;
}
else
{
_rootHubFuncAddressHS = address;
}
TestCommands();
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::GetRootHubStatus(IOUSBHubStatus *status)
{
*(UInt32 *)status = 0;
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::SetRootHubFeature(UInt16 wValue)
{
switch(wValue)
{
case kUSBHubLocalPowerChangeFeature :
USBLog(3,"AppleUSBXHCI[%p]: unimplemented Set Power Change Feature", this);
break;
case kUSBHubOverCurrentChangeFeature :
USBLog(3,"AppleUSBXHCI[%p]: unimplemented Set Overcurrent Change Feature", this);
break;
default:
USBLog(3,"AppleUSBXHCI[%p]: Unknown hub set (%d) in root hub", this, wValue);
break;
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::GetRootHubPortErrorCount(UInt16 port, UInt16 *count)
{
UInt16 adjustedPortIndex = port;
AdjustRootHubPortNumbers(kUSBDeviceSpeedSuper, &adjustedPortIndex);
*count = Read32Reg(&_pXHCIRegisters->PortReg[adjustedPortIndex].PortLI);
USBLog(6, "AppleUSBXHCI[%p]::GetRootHubPortErrorCount - PORTLI[%d]: 0x%04x", this, (int)adjustedPortIndex, *count);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
return kIOReturnSuccess;
}
void
AppleUSBXHCI::UIMRootHubStatusChange(void)
{
UInt16 statusChangedBitmap;
IOUSBHubPortStatus portStatus;
UInt32 hubStatus, statusBit, tempStatus;
unsigned int port;
IOReturn retStatus;
if((Read32Reg(&_pXHCIRegisters->USBSTS)& kXHCIHSEBit) != 0)
{
if(!_HSEReported)
{
USBError(1, "AppleUSBXHCI[%p]::UIMRootHubStatusChange - HSE bit set:%x (1)", this, Read32Reg(&_pXHCIRegisters->USBSTS));
}
_HSEReported = true;
}
if (_lostRegisterAccess)
{
return;
}
statusChangedBitmap = 0;
statusBit = 1;
if (_controllerAvailable && !_wakingFromHibernation && !_lostRegisterAccess)
{
RHCheckForPortResumes();
if (GetRootHubStatus((IOUSBHubStatus *)&tempStatus) == kIOReturnSuccess)
{
hubStatus = USBToHostLong( tempStatus );
if ((hubStatus & (kHubLocalPowerStatus | kHubOverCurrentIndicator) ) != 0)
statusChangedBitmap |= statusBit;
USBLog(7,"AppleUSBXHCI[%p]::UIMRootHubStatusChange numPorts %d _wakingFromHibernation(%s)", this, _rootHubNumPorts, _wakingFromHibernation ? "true" : "false");
for (port = 1; port <= _rootHubNumPorts; port++)
{
UInt16 adjustedPort = port;
statusBit <<= 1;
portStatus.changeFlags = 0;
portStatus.statusFlags = 0;
if ( _rhPortBeingReset[port-1] )
{
USBLog(5, "AppleUSBXHCI[%p]::UIMRootHubStatusChange - port (%d) - still in reset, ignoring any changes", this, (int)port);
continue;
}
bool portIsSuperSpeed = IsRootHubPortSuperSpeed(&adjustedPort);
if (portIsSuperSpeed)
{
portStatus.statusFlags = (kUSBDeviceSpeedSuper << kUSBSpeed_Shift) & kUSBSpeed_Mask;
}
retStatus = GetRootHubPortStatus(&portStatus, adjustedPort);
if (retStatus != kIOReturnSuccess)
{
USBLog(5, "AppleUSBXHCI[%p]::UIMRootHubStatusChange - got status (%p) from GetRootHubPortStatus for port (%d) - skipping", this, (void*)retStatus, (int)port);
continue;
}
portStatus.changeFlags = USBToHostWord(portStatus.changeFlags);
portStatus.statusFlags = USBToHostWord(portStatus.statusFlags);
if ((portStatus.statusFlags & kHubPortConnection) && !(portStatus.changeFlags & kHubPortConnection) && _synthesizeCSC[port-1])
{
USBLog(4,"AppleUSBXHCI[%p]::UIMRootHubStatusChange port %d _synthesizeCSC[%d] is true, setting the change bit", this, port-1, _synthesizeCSC[port-1]);
portStatus.changeFlags |= kHubPortConnection;
}
if (portStatus.changeFlags & kHubPortSuperSpeedStateChangeMask)
{
USBLog(4,"AppleUSBXHCI[%p]::UIMRootHubStatusChange port %d status(0x%04x) change(0x%04x)", this, port, portStatus.statusFlags, portStatus.changeFlags);
portStatus.changeFlags |= kHubPortConnection;
if ( portStatus.changeFlags & kHubPortOverCurrent )
{
USBLog(3,"AppleUSBXHCI[%p]::UIMRootHubStatusChange port %d had an overcurrent", this, port);
}
if(!CheckNECFirmware())
{
USBLog(2, "AppleUSBXHCI[%p]::UIMRootHubStatusChange - This NEC XHCI controller needs a firmware upgrade before it will work. Suppressing status change",this);
Write32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC, Read32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC)); if (_lostRegisterAccess)
{
return;
}
}
else
{
statusChangedBitmap |= statusBit; }
}
}
}
if (statusChangedBitmap)
{
USBLog(3,"AppleUSBXHCI[%p]::UIMRootHubStatusChange got bitmap (%p)", this, (void*)statusChangedBitmap);
}
_rootHubStatusChangedBitmap = statusChangedBitmap;
}
}
#pragma mark Port Methods
int AppleUSBXHCI::FindSlotFromPort(UInt16 port)
{
int slot = -1;
for(int i = 0; i<kMaxSlots; i++)
{
Context * slotContext = GetSlotContext(i);
if(slotContext != NULL)
{
UInt32 cPort = GetSlCtxRootHubPort(slotContext)-1; UInt8 cSpeed = GetSlCtxSpeed(slotContext);
UInt32 cRouteString = GetSlCtxRouteString(slotContext);
USBLog(2,"AppleUSBXHCI[%p]::FindSlotFromPort port:%d slot:%d cPort:%d, cSpeed:%d, cRoute:%x", this, (int)port, i, (int)cPort, cSpeed, (unsigned)cRouteString);
if(port == cPort)
{
if( (cSpeed == kUSBDeviceSpeedSuper) &&
(cRouteString == 0) )
{
if(slot != -1)
{
USBLog(1,"AppleUSBXHCI[%p]::FindSlotFromPort found another device on port new:%d, old:%d", this, i, slot);
}
else
{
slot = i;
}
}
}
}
}
return(slot);
}
IOReturn
AppleUSBXHCI::GetRootHubPortStatus(IOUSBHubPortStatus *status, UInt16 port)
{
UInt32 portSC, PLS;
bool suspend = false;
UInt16 statusFlags, changeFlags;
int speed;
int controllerSpeed;
bool superSpeedSimulation;
bool warmResetIssued = false;
if ( _myBusState == kUSBBusStateSuspended )
return kIOReturnNotResponding;
if(_lostRegisterAccess)
{
return(kIOReturnNoDevice);
}
RHCommandHeaderPtr command = (RHCommandHeaderPtr)(status);
speed = ((command->request & kUSBSpeed_Mask) >> kUSBSpeed_Shift);
AdjustRootHubPortNumbers(speed, &port);
superSpeedSimulation = (speed == kUSBDeviceSpeedSuper) ? true : false;
USBLog(7, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d Simulation: %s ", this, port, superSpeedSimulation ? "SuperSpeed" : "Classic Speed");
port--;
if (port >= _rootHubNumPorts)
{
USBLog(3, "AppleUSBXHCI[%p]::GetRootHubPortStatus Too many ports specified(%d > %d)", this, port, _rootHubNumPorts);
return kIOReturnBadArgument;
}
portSC = Read32Reg(&_pXHCIRegisters->PortReg[port].PortSC);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
statusFlags = portSC & (kXHCIPortSC_CCS | kXHCIPortSC_PED | kXHCIPortSC_OCA | kXHCIPortSC_PR);
PLS = (UInt32)(portSC & kXHCIPortSC_LinkState_Mask) >> kXHCIPortSC_LinkState_Shift;
controllerSpeed = (UInt32)(portSC & kXHCIPortSC_Speed_Mask) >> kXHCIPortSC_Speed_Shift;
if (!superSpeedSimulation)
{
if(PLS == kXHCIPortSC_PLS_Suspend)
{
suspend = true;
statusFlags |= kHubPortSuspend;
}
if(controllerSpeed == kXHCIPortSC_LS)
{
statusFlags |= kHubPortLowSpeed;
}
else if(controllerSpeed == kXHCIPortSC_HS)
{
statusFlags |= kHubPortHighSpeed;
}
else if ( controllerSpeed == kXHCIPortSC_SS)
{
}
if(portSC & kXHCIPortSC_PP)
{
statusFlags |= kHubPortPower;
}
}
else
{
if(PLS == kXHCIPortSC_PLS_Suspend)
{
suspend = true;
statusFlags |= kHubPortSuspend;
}
statusFlags |= (PLS << kSSHubPortStatusLinkStateShift);
if(portSC & kXHCIPortSC_PP)
{
statusFlags |= kSSHubPortStatusPowerMask;
}
statusFlags &= 0x03FF;
}
if (!superSpeedSimulation)
{
changeFlags = (portSC & (kXHCIPortSC_CSC | kXHCIPortSC_PEC | kXHCIPortSC_OCC | kXHCIPortSC_PRC)) >> 17;
changeFlags += (((portSC & kXHCIPortSC_PLC) >> 22) << kSSHubPortChangePortLinkStateBit);
changeFlags |= (((portSC & kXHCIPortSC_CEC) >> 23) << kSSHubPortChangePortConfigErrBit);
if( suspend != _prevSuspend[port])
{
_prevSuspend[port] = suspend;
if(!suspend) {
_suspendChangeBits[port] = true;
}
}
if(_suspendChangeBits[port])
{
changeFlags |= kHubPortSuspend;
}
}
else
{
changeFlags = (portSC & (kXHCIPortSC_CSC | kXHCIPortSC_OCC | kXHCIPortSC_PRC)) >> 17;
changeFlags |= (((portSC & kXHCIPortSC_WRC) >> 19) << kSSHubPortChangeBHResetBit);
changeFlags += (((portSC & kXHCIPortSC_PLC) >> 22) << kSSHubPortChangePortLinkStateBit);
changeFlags |= (((portSC & kXHCIPortSC_CEC) >> 23) << kSSHubPortChangePortConfigErrBit);
if( suspend != _prevSuspend[port])
{
_prevSuspend[port] = suspend;
if(!suspend) {
_suspendChangeBits[port] = true;
}
}
if(_suspendChangeBits[port])
{
changeFlags |= kHubPortSuspend;
}
}
if ( _portIsWaitingForWRC[port] )
{
status->changeFlags = 0;
status->statusFlags = HostToUSBWord(statusFlags);
status->statusFlags |= kHubPortConnection;
USBLog(6, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d _portIsWaitingForWRC[%d]==TRUE. Not reporting a change, status: 0x%04x", this, port+1, port, status->statusFlags);
return kIOReturnSuccess;
}
if ((portSC & kXHCIPortSC_CCS) && !(portSC & kXHCIPortSC_CSC) && (_synthesizeCSC[port]))
{
USBLog(3, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d synthesizing CSC", this, port);
changeFlags |= kHubPortConnection;
}
if ( superSpeedSimulation && (changeFlags & kHubPortConnection) && (changeFlags & kSSHubPortChangePortLinkStateMask) && (PLS == kXHCIPortSC_PLS_Inactive))
{
int slotID = FindSlotFromPort(port);
if(slotID >= 0)
{
UInt32 portSCAfterReset;
UInt32 PLSAfterReset;
int retries = 8;
_portIsWaitingForWRC[port] = true;
USBLog(6, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d we have a CSC, PLC, and PLS == SS.Inactive. Issue a warm reset (PortSC = 0x%08x)", this, port+1, (uint32_t)portSC);
(void) XHCIRootHubWarmResetPort(port+1);
portSC = Read32Reg(&_pXHCIRegisters->PortReg[port].PortSC);
if (_lostRegisterAccess)
{
_portIsWaitingForWRC[port] = false;
return kIOReturnNoDevice;
}
while ( retries-- && !(portSC & kXHCIPortSC_WRC) )
{
AbsoluteTime deadline;
IOReturn err;
IOCommandGate * commandGate = GetCommandGate();
UInt32 flag = 0;
if ( getWorkLoop()->inGate() )
{
clock_interval_to_deadline(32, kMillisecondScale, &deadline);
USBLog(6,"AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d, waiting(%d) for WRC (and PRC), calling commandSleep with a 32 ms timeout", this, port+1, (uint32_t)retries);
err = commandGate->commandSleep(&flag, deadline, THREAD_ABORTSAFE);
USBLog(6,"AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d, commandSleep returned 0x%x", this, port+1, (uint32_t)err);
}
else
{
USBLog(6, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d, - waiting(%d) for WRC (and PRC)", this, port+1, (uint32_t)retries);
IOSleep(32);
}
portSC = Read32Reg(&_pXHCIRegisters->PortReg[port].PortSC);
if (_lostRegisterAccess)
{
_portIsWaitingForWRC[port] = false;
return kIOReturnNoDevice;
}
}
portSCAfterReset = Read32Reg(&_pXHCIRegisters->PortReg[port].PortSC);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
PLSAfterReset = (UInt32)(portSCAfterReset & kXHCIPortSC_LinkState_Mask) >> kXHCIPortSC_LinkState_Shift;
USBLog(5, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d, - after waiting %d ms for PRC, we have a portSC: 0x%08x, PLS = %d", this, port+1, (uint32_t)(8-retries-1)*32, (uint32_t)portSCAfterReset, (uint32_t)PLSAfterReset);
if ( (PLSAfterReset == kXHCIPortSC_PLS_U0) && (portSCAfterReset & (kXHCIPortSC_CCS | kXHCIPortSC_PED)) )
{
USBLog(5, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d, - Looks like we have a good link after the reset, so clear any changes", this, port+1);
changeFlags &= ~(kHubPortConnection);
XHCIRootHubClearPortConnectionChange(port+1);
}
USBLog(5, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d, - Clearing the PRC/WRC", this, port+1);
XHCIRootHubClearWarmResetChange(port+1);
XHCIRootHubClearResetChange(0, port+1);
USBLog(2, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d, - setting deviceNeedsReset on slot:%d", this, port+1, slotID);
_slots[slotID].deviceNeedsReset = true;
_portIsWaitingForWRC[port] = false;
UInt64 currentNanoSeconds;
uint64_t now = mach_absolute_time();
absolutetime_to_nanoseconds( *( AbsoluteTime * ) &now, ¤tNanoSeconds );
_debounceNanoSeconds[port] = currentNanoSeconds - kConnectionDebounceIntervalInNanos;
_portIsDebouncing[port] = true;
warmResetIssued = true;
if ( statusFlags & kHubPortConnection)
{
_debouncingADisconnect[port] = false;
}
else
{
_debouncingADisconnect[port] = true;
}
}
else
{
USBLog(1, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d, - Rikiki workaround but no device enumerated", this, port+1);
}
}
if ( superSpeedSimulation && !warmResetIssued )
{
if ( (changeFlags & kHubPortConnection) && !(changeFlags & kSSHubPortChangeBHResetMask) && !(changeFlags & kHubPortBeingReset) && !(statusFlags & kSSHubPortStatusBeingResetMask))
{
uint64_t now = mach_absolute_time();
USBLog(7, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d, we have a connection change", this, port+1);
if (_portIsDebouncing[port])
{
UInt64 currentNanoSeconds;
absolutetime_to_nanoseconds( *( AbsoluteTime * ) &now, ¤tNanoSeconds );
if ((currentNanoSeconds - _debounceNanoSeconds[port]) < kConnectionDebounceIntervalInNanos)
{
USBLog(6, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d, we have a connection change, we're debouncing (%s), but it's still not 100ms: now: %qd (diff: %qd ms)", this, port+1, _debouncingADisconnect[port] ? "DISCONNECT" : "CONNECTION", currentNanoSeconds, (currentNanoSeconds-_debounceNanoSeconds[port])/1000000);
changeFlags &= ~(kHubPortConnection);
}
else
{
if ( _debouncingADisconnect[port] && (statusFlags & kHubPortConnection) )
{
USBLog(6, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d, we were debouncing a connection (%qd ms ago), but we have a device present again!", this, port+1, (currentNanoSeconds-_debounceNanoSeconds[port])/1000000);
changeFlags &= ~(kHubPortConnection);
(void) XHCIRootHubClearPortConnectionChange(port+1);
}
else if ( !(_debouncingADisconnect[port]) && !(statusFlags & kHubPortConnection) )
{
USBLog(6, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d, we were debouncing a disconnect (%qd ms ago), but we have a device present again!", this, port+1, (currentNanoSeconds-_debounceNanoSeconds[port])/1000000);
changeFlags &= ~(kHubPortConnection);
(void) XHCIRootHubClearPortConnectionChange(port+1);
}
else
{
USBLog(6, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d debouncing a %s, (%qd ms ago), but the CSC did not change (CSC: 0x%x), report the change", this, port+1, _debouncingADisconnect[port] ? "DISCONNECT" : "CONNECTION", (currentNanoSeconds-_debounceNanoSeconds[port])/1000000, (statusFlags & kHubPortConnection));
}
}
}
else
{
if ( statusFlags & kHubPortConnection)
{
_debouncingADisconnect[port] = false;
}
else
{
_debouncingADisconnect[port] = true;
}
changeFlags &= ~(kHubPortConnection);
absolutetime_to_nanoseconds( *( AbsoluteTime * ) &now, &(_debounceNanoSeconds[port]) );
_portIsDebouncing[port] = true;
USBLog(6, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d we have a connection change (%s), but we weren't debouncing, starting now: %qd", this, port+1, _debouncingADisconnect[port] ? "DISCONNECT" : "CONNECTION", _debounceNanoSeconds[port] );
}
}
else
{
USBLog(7, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d debouncing a %s, no connection change", this, port+1, _debouncingADisconnect[port] ? "DISCONNECT" : "CONNECTION");
_portIsDebouncing[port] = false;
_debouncingADisconnect[port] = false;
}
}
if ( _portIsDebouncing[port] )
{
USBLog(6, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d debouncing a %s, (_portIsDebouncing is true), setting kHubPortDebouncing status bit", this, port+1, _debouncingADisconnect[port] ? "DISCONNECT" : "CONNECTION" );
statusFlags |= kHubPortDebouncing;
}
if (superSpeedSimulation && (changeFlags & kHubPortOverCurrent || statusFlags & kHubPortOverCurrent))
{
USBLog(6, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d Overcurrent on super speed root hub, setting kHubPortDebouncing status bit", this, port+1 );
statusFlags |= kHubPortDebouncing;
}
status->statusFlags = HostToUSBWord(statusFlags);
status->changeFlags = HostToUSBWord(changeFlags);
#if 1
{
if(port < kMaxSavePortStatus)
{
if( (statusFlags != _saveStatus[port]) ||
(changeFlags != _saveChange[port]) )
{
USBLog(3, "AppleUSBXHCI[%p]::GetRootHubPortStatus port: %d, portSC: 0x%08x, status: 0x%04x, change: 0x%04x, portIsDebouncing: %d", this, port+1, (uint32_t)portSC, statusFlags, changeFlags, _portIsDebouncing[port]);
_saveStatus[port] = statusFlags;
_saveChange[port] = changeFlags;
}
}
else
{
USBLog(3, "AppleUSBXHCI[%p]::GetRootHubPortStatus unexpected number of ports. port: %d, portSC: 0x%08x, status: 0x%04x, change: 0x%04x", this, port+1, (uint32_t)portSC, statusFlags, changeFlags);
}
}
#endif
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::SetRootHubPortFeature(UInt16 wValue, UInt16 wIndex)
{
IOReturn err;
UInt16 port = wIndex & 0x00FF;
UInt8 speed = ((wValue & kUSBSpeed_Mask) >> kUSBSpeed_Shift);
wValue >>= 8;
AdjustRootHubPortNumbers(speed, &port);
switch(wValue)
{
case kUSBHubPortSuspendFeature :
USBLog(5,"AppleUSBXHCI[%p]::SetRootHubPortFeature suspending port %d", this, port);
err = XHCIRootHubSuspendPort(speed, port, true);
break;
case kUSBHubPortResetFeature :
USBLog(5,"AppleUSBXHCI[%p]::SetRootHubPortFeature reset port %d", this, port);
err = XHCIRootHubResetPort(speed, port);
break;
case kUSBHubPortBHPortResetFeature :
USBLog(5,"AppleUSBXHCI[%p]::SetRootHubPortFeature warm reset port %d", this, port);
err = XHCIRootHubWarmResetPort(port);
break;
case kUSBHubPortLinkStateFeature :
USBLog(5,"AppleUSBXHCI[%p]::SetRootHubPortFeature kUSBHubPortLinkStateFeature(%d) port %d", this, wIndex>>8, port);
err = XHCIRootHubSetLinkStatePort(wIndex>>8, port);
break;
case kUSBHubPortEnableFeature :
USBLog(5,"AppleUSBXHCI[%p]::SetRootHubPortFeature enable port %d", this, port);
err = XHCIRootHubEnablePort(port, true);
break;
case kUSBHubPortPowerFeature :
USBLog(3, "AppleUSBXHCI[%p]::SetRootHubPortFeature - setting kUSBHubPortPowerFeature on port %d", this, port);
(void) XHCIRootHubPowerPort(port, true);
err = XHCIRootHubPower(true);
break;
case kUSBHubPortU1TimeoutFeature :
USBLog(5,"AppleUSBXHCI[%p]::SetRootHubPortFeature kUSBHubPortU1TimeoutFeature(%d) port %d", this, wIndex>>8, port);
err = XHCIRootHubSetU1TimeoutPort(wIndex>>8, port);
break;
case kUSBHubPortU2TimeoutFeature :
USBLog(5,"AppleUSBXHCI[%p]::SetRootHubPortFeature kUSBHubPortU2TimeoutFeature(%d) port %d", this, wIndex>>8, port);
err = XHCIRootHubSetU2TimeoutPort(wIndex>>8, port);
break;
case kUSBHubPortRemoteWakeMaskFeature :
USBLog(5,"AppleUSBXHCI[%p]::SetRootHubPortFeature kUSBHubPortRemoteWakeMaskFeature(%d) port %d", this, wIndex>>8, port);
err = XHCIRootHubRemoteWakeupMaskPort(wIndex>>8, port);
break;
default:
USBLog(3,"AppleUSBXHCI[%p]::SetRootHubPortFeature unknown wValue %d, wIndex %d", this, wValue, wIndex);
err = kIOReturnUnsupported;
break;
}
return err;
}
IOReturn
AppleUSBXHCI::ClearRootHubPortFeature(UInt16 wValue, UInt16 wIndex)
{
IOReturn err;
UInt8 speed = ((wValue & kUSBSpeed_Mask) >> kUSBSpeed_Shift);
UInt16 port = wIndex;
wValue >>= 8;
USBLog(4, "AppleUSBXHCI[%p]::ClearRootHubPortFeature - port %d, feature: %d speed: %d", this, wIndex, wValue, speed);
AdjustRootHubPortNumbers(speed, &port);
switch(wValue)
{
case kUSBHubPortEnableFeature :
err = XHCIRootHubEnablePort(port, false);
break;
case kUSBHubPortSuspendFeature :
USBLog(5,"AppleUSBXHCI[%p]::ClearRootHubPortFeature resuming port %d", this, port);
err = XHCIRootHubSuspendPort(speed, port, false);
break;
case kUSBHubPortPowerFeature :
err = XHCIRootHubPowerPort(port, false);
break;
case kUSBHubPortConnectionChangeFeature :
err = XHCIRootHubClearPortConnectionChange(port);
break;
case kUSBHubPortEnableChangeFeature :
err = XHCIRootHubClearPortEnableChange(port);
break;
case kUSBHubPortSuspendChangeFeature :
err = XHCIRootHubClearPortSuspendChange(port);
break;
case kUSBHubPortOverCurrentChangeFeature :
err = XHCIRootHubResetOverCurrentChange(port);
break;
case kUSBHubPortResetChangeFeature :
err = XHCIRootHubClearResetChange(speed, port);
break;
case kUSBHubPortBHResetChangeFeature :
err = XHCIRootHubClearWarmResetChange(port);
break;
case kUSBHubPortLinkStateChangeFeature :
err = XHCIRootHubClearPortLinkChange(port);
break;
case kUSBHubPortConfigErrorChangeFeature :
err = XHCIRootHubClearConfigErrorChange(port);
break;
default:
USBLog(3,"AppleUSBXHCI[%p]::ClearRootHubPortFeature unknown wValue %d, wIndex %d", this, wValue, wIndex);
err = kIOReturnUnsupported;
break;
}
USBLog(4, "AppleUSBXHCI[%p]::ClearRootHubPortFeature - port %d, feature: %d speed: %d returning %x", this, wIndex, wValue, speed, err);
return err;
}
#pragma mark Set Port Feature
IOReturn
AppleUSBXHCI::XHCIRootHubSuspendPort(UInt8 RHSpeed, UInt16 adjustedPort, bool suspend)
{
UInt32 portSC;
USBLog(5,"AppleUSBXHCI[%p]::XHCIRootHubSuspendPort port: %d, %s, PortSC(0x%08x)", this, adjustedPort, suspend ? "SUSPEND" : "RESUME", Read32Reg(&_pXHCIRegisters->PortReg[adjustedPort-1].PortSC));
USBTrace_Start( kUSBTXHCIRootHubs, kTPXHCIRootHubPortSuspend, (uintptr_t)this, adjustedPort, suspend, 0 );
if (_rhPortBeingResumed[adjustedPort-1])
{
if (!suspend)
{
USBLog(3, "AppleUSBXHCI[%p]::XHCIRootHubSuspendPort - resume on port (%d) already being resumed - gracefully ignoring", this, (int)adjustedPort);
return kIOReturnSuccess;
}
USBLog(1, "AppleUSBXHCI[%p]::XHCIRootHubSuspendPort - trying to suspend port (%d) which is being resumed - UNEXPECTED", this, (int)adjustedPort);
}
if ( suspend )
{
UInt32 PLS = 0;
UInt32 loop = 0;
do
{
loop++;
portSC = Read32Reg(&_pXHCIRegisters->PortReg[adjustedPort-1].PortSC);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
PLS = (UInt32)(portSC & kXHCIPortSC_LinkState_Mask) >> kXHCIPortSC_LinkState_Shift;
if ((PLS == kXHCIPortSC_PLS_Recovery) && (loop < 4))
{
USBLog(3,"AppleUSBXHCI[%p]::XHCIRootHubSuspendPort port:%d suspend, but portSC(0x%08x) is in Recovery, waiting 50ms", this, adjustedPort, (int)portSC);
IOSleep(50);
}
else
{
break;
}
} while(true);
if ( loop > 3)
{
USBLog(3,"AppleUSBXHCI[%p]::XHCIRootHubSuspendPort port:%d suspend, but portSC(0x%08x) still in Recovery after trying 3 times", this, adjustedPort, (int)portSC);
return kIOUSBDevicePortWasNotSuspended;
}
}
portSC = GetPortSCForWriting(adjustedPort);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
if(suspend)
{
USBLog(3,"AppleUSBXHCI[%p]::XHCIRootHubSuspendPort port:%d suspend.", this, adjustedPort);
portSC |= (UInt32)(kXHCIPortSC_LWS | (kXHCIPortSC_PLS_Suspend << kXHCIPortSC_LinkState_Shift));
}
else
{
if( RHSpeed == kUSBDeviceSpeedHigh )
{
portSC |= (UInt32)(kXHCIPortSC_LWS | (kXHCIPortSC_PLS_Resume << kXHCIPortSC_LinkState_Shift));
}
else if( RHSpeed == kUSBDeviceSpeedSuper )
{
portSC |= (UInt32)(kXHCIPortSC_LWS | (kXHCIPortSC_PLS_U0 << kXHCIPortSC_LinkState_Shift));
}
USBLog(3,"AppleUSBXHCI[%p]::XHCIRootHubSuspendPort port:%d resume.", this, adjustedPort);
}
Write32Reg(&_pXHCIRegisters->PortReg[adjustedPort-1].PortSC, portSC);
IOSync();
IOSleep(1);
if (!suspend)
{
USBLog(5,"AppleUSBXHCI[%p]::XHCIRootHubSuspendPort - resuming port %d, calling out to timer", this, (int)adjustedPort);
_rhPortBeingResumed[adjustedPort-1] = true;
if ( _rhResumePortTimerThread[adjustedPort-1] == NULL )
{
USBLog(1,"AppleUSBXHCI[%p]::XHCIRootHubSuspendPort - resuming port %d, but callout thread is NULL", this, (int)adjustedPort);
}
else
thread_call_enter1(_rhResumePortTimerThread[adjustedPort-1], (void*)adjustedPort);
}
portSC = Read32Reg(&_pXHCIRegisters->PortReg[adjustedPort-1].PortSC);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
USBTrace_End( kUSBTXHCIRootHubs, kTPXHCIRootHubPortSuspend, (uintptr_t)this, adjustedPort, portSC, 0 );
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::XHCIRootHubResetPort (UInt8 rhSpeed, UInt16 port)
{
IOReturn kr = kIOReturnSuccess;
IOCommandGate * commandGate = GetCommandGate();
USBLog(6, "AppleUSBXHCI[%p]::XHCIRootHubResetPort[%d] - resetting port, RHSpeed: %d (%s)", this, port, rhSpeed, rhSpeed == kUSBDeviceSpeedHigh ? "High" : "Super");
USBTrace_Start( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPort, (uintptr_t)this, rhSpeed, port, 0 );
if ( _rhPortBeingReset[port-1] )
{
USBLog(6, "AppleUSBXHCI[%p]::XHCIRootHubResetPort[%d] - port already being reset", this, port);
USBTrace(kUSBTXHCIRootHubs, kTPXHCIRootHubResetPort, (uintptr_t)this, 7, 0, port);
return kIOReturnSuccess;
}
if ( getWorkLoop()->inGate() )
{
_rhResetParams[port-1].rhSpeed = rhSpeed;
_rhResetParams[port-1].port = port;
_rhResetParams[port-1].status = -1;
_rhPortBeingReset[port-1] = true;
retain();
if ( thread_call_enter1(_rhResetPortThread[port-1], (void*)(&_rhResetParams[port-1]) ) == TRUE )
{
USBLog(6,"AppleUSBXHCI[%p]::XHCIRootHubResetPort _rhResetPortThread already queued", this);
USBTrace(kUSBTXHCIRootHubs, kTPXHCIRootHubResetPort, (uintptr_t)this, 8, (uintptr_t)kIOReturnNotPermitted, port);
kr = kIOReturnNotPermitted;
}
else
{
AbsoluteTime deadline;
IOReturn err;
clock_interval_to_deadline(10, kSecondScale, &deadline);
USBLog(6,"AppleUSBXHCI[%p]::XHCIRootHubResetPort calling commandSleep with a 10 second timeout", this);
err = commandGate->commandSleep(&_rhPortBeingReset[port-1], deadline, THREAD_ABORTSAFE);
switch (err)
{
case THREAD_AWAKENED:
USBLog(6,"AppleUSBXHCI[%p]::XHCIRootHubResetPort commandSleep woke up normally (THREAD_AWAKENED), status = 0x%x", this, _rhResetParams[port-1].status);
kr = _rhResetParams[port-1].status;
USBTrace(kUSBTXHCIRootHubs, kTPXHCIRootHubResetPort, (uintptr_t)this, 1, (uintptr_t)kr, port);
break;
case THREAD_TIMED_OUT:
USBLog(3,"AppleUSBXHCI[%p]::XHCIRootHubResetPort commandSleep timeout out (THREAD_TIMED_OUT)", this);
USBTrace(kUSBTXHCIRootHubs, kTPXHCIRootHubResetPort, (uintptr_t)this, 2, (uintptr_t)kIOReturnTimeout, port);
kr = kIOReturnTimeout;
break;
case THREAD_INTERRUPTED:
USBLog(3,"AppleUSBXHCI[%p]::XHCIRootHubResetPort commandSleep interrupted (THREAD_INTERRUPTED)", this);
USBTrace(kUSBTXHCIRootHubs, kTPXHCIRootHubResetPort, (uintptr_t)this, 3, (uintptr_t)kIOReturnNotPermitted, port);
kr = kIOReturnNotPermitted;
break;
case THREAD_RESTART:
USBLog(3,"AppleUSBXHCI[%p]::XHCIRootHubResetPort commandSleep restarted (THREAD_RESTART)", this);
USBTrace(kUSBTXHCIRootHubs, kTPXHCIRootHubResetPort, (uintptr_t)this, 4, (uintptr_t)kIOReturnNotPermitted, port);
kr = kIOReturnNotPermitted;
break;
case kIOReturnNotPermitted:
USBLog(3,"AppleUSBXHCI[%p]::XHCIRootHubResetPort woke up with status (kIOReturnNotPermitted) - we do not hold the WL!", this);
USBTrace(kUSBTXHCIRootHubs, kTPXHCIRootHubResetPort, (uintptr_t)this, 5, (uintptr_t)kIOReturnNotPermitted, port);
kr = err;
break;
default:
USBLog(3,"AppleUSBXHCI[%p]::XHCIRootHubResetPort woke up with unknown status 0x%x", this, (uint32_t)err);
USBTrace(kUSBTXHCIRootHubs, kTPXHCIRootHubResetPort, (uintptr_t)this, 6, (uintptr_t)port, err);
kr = kIOReturnNotPermitted;
}
}
release();
}
else
{
USBLog(6,"AppleUSBXHCI[%p]::XHCIRootHubResetPort not in gate, calling RHResetPort directly", this);
USBTrace(kUSBTXHCIRootHubs, kTPXHCIRootHubResetPort, (uintptr_t)this, 9, 0, port);
kr = RHResetPort(rhSpeed, port);
}
USBTrace_End( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPort, (uintptr_t)this, rhSpeed, port, kr );
return kr;
}
IOReturn
AppleUSBXHCI::XHCIRootHubWarmResetPort (UInt16 port)
{
UInt32 portSC;
portSC = GetPortSCForWriting(port);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
portSC |= (UInt32)kXHCIPortSC_WPR;
Write32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC, portSC);
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::XHCIRootHubSetLinkStatePort (UInt16 linkState, UInt16 port)
{
UInt32 portSC;
if (linkState == kXHCIPortSC_PLS_U0)
{
return XHCIRootHubSuspendPort(kUSBDeviceSpeedSuper, port, false);
}
if (linkState == kXHCIPortSC_PLS_Suspend)
{
return XHCIRootHubSuspendPort(kUSBDeviceSpeedSuper, port, true);
}
portSC = GetPortSCForWriting(port);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
USBLog(6, "AppleUSBXHCI[%p]::XHCIRootHubSetLinkStatePort - port: %d to state: %d, portSC: 0x%08x", this, port, linkState, (uint32_t)Read32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC));
portSC |= (UInt32)(kXHCIPortSC_LWS | (linkState << kXHCIPortSC_LinkState_Shift));
Write32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC, portSC);
IOSync();
USBLog(6, "AppleUSBXHCI[%p]::XHCIRootHubSetLinkStatePort - after, portSC: 0x%08x", this, (uint32_t)Read32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC));
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::XHCIRootHubEnablePort(UInt16 port, bool enable)
{
UInt32 portSC;
USBTrace_Start( kUSBTXHCIRootHubs, kTPXHCIRootHubPortEnable, (uintptr_t)this, port, enable, 0 );
USBLog(5,"AppleUSBXHCI[%p]::XHCIRootHubEnablePort port: %d, on: %d", this, port, enable);
if (enable)
{
USBLog(1,"AppleUSBXHCI[%p]::XHCIRootHubEnablePort enabling port illegal.", this);
return kIOReturnUnsupported;
}
portSC = GetPortSCForWriting(port);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
portSC |= (UInt32)kXHCIPortSC_PED;
Write32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC, portSC);
portSC = Read32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
USBTrace_End( kUSBTXHCIRootHubs, kTPXHCIRootHubPortEnable, (uintptr_t)this, port, portSC, 0 );
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::XHCIRootHubPower(bool on)
{
#pragma unused (on)
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::XHCIRootHubPowerPort(UInt16 port, bool on)
{
UInt32 portSC, newPortSC, count;
USBLog(6,"AppleUSBXHCI[%p]::XHCIRootHubPowerPort %d, port: %d, portSC before: 0x%x", this, on, port,(uint32_t) Read32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC));
portSC = GetPortSCForWriting(port);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
if(on)
{
portSC |= (UInt32)kXHCIPortSC_PP;
Write32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC, portSC);
IOSync();
newPortSC = Read32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
count = 0;
while (!(newPortSC & kXHCIPortSC_PP) && (count++ < 10))
{
USBLog(6,"AppleUSBXHCI[%p]::XHCIRootHubPowerPort PortPower bit not sticking. Retrying(%d)", this, (uint32_t)count);
Write32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC, portSC);
IOSync();
newPortSC = Read32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
}
IOSleep(20);
portSC |= (UInt32)(kXHCIPortSC_WCE | kXHCIPortSC_WDE | kXHCIPortSC_WOE); }
else
{
portSC &= ~(UInt32)kXHCIPortSC_PP;
}
Write32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC, portSC);
IOSync();
USBLog(5,"AppleUSBXHCI[%p]::XHCIRootHubPowerPort portSC after: 0x%x", this,(uint32_t) Read32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC));
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::XHCIRootHubSetU1TimeoutPort (UInt16 timeout, UInt16 port)
{
#pragma unused (timeout, port)
return kIOReturnUnsupported;
}
IOReturn
AppleUSBXHCI::XHCIRootHubSetU2TimeoutPort (UInt16 timeout, UInt16 port)
{
#pragma unused (timeout, port)
return kIOReturnUnsupported;
}
IOReturn
AppleUSBXHCI::XHCIRootHubRemoteWakeupMaskPort (UInt16 mask, UInt16 port)
{
#pragma unused (mask, port)
return kIOReturnUnsupported;
}
#pragma mark Clear Port Feature
IOReturn
AppleUSBXHCI::XHCIRootHubClearPortConnectionChange(UInt16 port)
{
UInt32 portSC;
portSC = GetPortSCForWriting(port);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
portSC |= (UInt32)kXHCIPortSC_CSC;
Write32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC, portSC);
if (_synthesizeCSC[port-1])
_synthesizeCSC[port-1] = false;
_portIsDebouncing[port] = false;
_debouncingADisconnect[port] = false;
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::XHCIRootHubClearPortEnableChange(UInt16 port)
{
UInt32 portSC;
portSC = GetPortSCForWriting(port);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
portSC |= (UInt32)kXHCIPortSC_PEC;
Write32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC, portSC);
IOSync();
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::XHCIRootHubClearPortSuspendChange(UInt16 port)
{
_suspendChangeBits[port-1] = false;
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::XHCIRootHubResetOverCurrentChange(UInt16 port)
{
UInt32 portSC;
portSC = GetPortSCForWriting(port);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
portSC |= (UInt32)kXHCIPortSC_OCC;
Write32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC, portSC);
IOSync();
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::XHCIRootHubClearResetChange(UInt8 RHSpeed, UInt16 adjustedPort)
{
#pragma unused (RHSpeed)
UInt32 portSC = GetPortSCForWriting(adjustedPort);
USBTrace_Start( kUSBTXHCIRootHubs, kTPXHCIRootHubResetResetChange, (uintptr_t)this, adjustedPort, portSC, 0 );
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
portSC |= (UInt32)kXHCIPortSC_PRC;
Write32Reg(&_pXHCIRegisters->PortReg[adjustedPort-1].PortSC, portSC);
IOSync();
USBTrace_End( kUSBTXHCIRootHubs, kTPXHCIRootHubResetResetChange, (uintptr_t)this, adjustedPort, Read32Reg(&_pXHCIRegisters->PortReg[adjustedPort-1].PortSC), 0 );
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::XHCIRootHubClearWarmResetChange(UInt16 port)
{
UInt32 portSC = GetPortSCForWriting(port);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
portSC |= (UInt32)kXHCIPortSC_WRC;
Write32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC, portSC);
IOSync();
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::XHCIRootHubClearPortLinkChange(UInt16 port)
{
UInt32 portSC = GetPortSCForWriting(port);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
portSC |= (UInt32)kXHCIPortSC_PLC;
Write32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC, portSC);
IOSync();
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::XHCIRootHubClearConfigErrorChange(UInt16 port)
{
UInt32 portSC = GetPortSCForWriting(port);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
portSC |= (UInt32)kXHCIPortSC_CEC;
Write32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC, portSC);
IOSync();
return kIOReturnSuccess;
}
#pragma mark RH Reset methods
void
AppleUSBXHCI::RHResetPortEntry(OSObject *target, thread_call_param_t params)
{
AppleUSBXHCI * me = OSDynamicCast(AppleUSBXHCI, target);
XHCIRootHubResetParams * rhResetParams = (XHCIRootHubResetParams *)params;
IOCommandGate * commandGate;
if (!me)
return;
USBLog(7, "AppleUSBXHCI[%p]::RHResetPortEntry[%d] - resetting port, RHSpeed: %d (%s)", me, rhResetParams->port, rhResetParams->rhSpeed, rhResetParams->rhSpeed == kUSBDeviceSpeedHigh ? "High" : "Super");
rhResetParams->status = me->RHResetPort(rhResetParams->rhSpeed, rhResetParams->port);
USBLog(6, "AppleUSBXHCI[%p]::RHResetPortEntry[%d] - RHResetPort returned 0x%x, calling commandWakeup", me, rhResetParams->port, rhResetParams->status);
me->_rhPortBeingReset[rhResetParams->port-1] = false;
(me->GetCommandGate())->commandWakeup(&(me->_rhPortBeingReset[rhResetParams->port-1]));
}
IOReturn
AppleUSBXHCI::RHResetPort(UInt8 RHSpeed, UInt16 adjustedPort)
{
IOReturn returnValue = kIOReturnSuccess;
UInt32 portSC;
USBTrace_Start( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPortCallout, (uintptr_t)this, adjustedPort, _errataBits, 0 );
USBLog(6, "AppleUSBXHCI[%p]::RHResetPort[%d] - resetting port, RHSpeed: %d (%s)", this, adjustedPort, RHSpeed, RHSpeed == kUSBDeviceSpeedHigh ? "High" : "Super");
portSC = GetPortSCForWriting(adjustedPort);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
portSC |= (UInt32)kXHCIPortSC_PR;
Write32Reg(&_pXHCIRegisters->PortReg[adjustedPort-1].PortSC, portSC);
IOSync();
USBTrace( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPortCallout, (uintptr_t)this, 1, adjustedPort, Read32Reg(&_pXHCIRegisters->PortReg[adjustedPort-1].PortSC));
if ((_errataBits & kXHCIErrataPPTMux) != 0)
{
if ( ((gUSBStackDebugFlags & kUSBDisableMuxedPortsMask) >> kUSBDisableMuxedPorts) == 0 )
{
UInt32 connectedSpeed;
UInt16 companionPort;
UInt32 companionPortSC;
UInt32 portSCAfterReset;
UInt32 companionPLSAfterReset;
UInt32 retries = 8;
portSCAfterReset = Read32Reg(&_pXHCIRegisters->PortReg[adjustedPort-1].PortSC);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
while ( retries-- && !(portSCAfterReset & kXHCIPortSC_PRC) )
{
USBLog(6, "AppleUSBXHCI[%p]::RHResetPort[%d] - waiting(%d) for PRC", this, adjustedPort, (uint32_t)retries);
USBTrace( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPortCallout, (uintptr_t)this, 2, adjustedPort, retries);
IOSleep(32);
portSCAfterReset = Read32Reg(&_pXHCIRegisters->PortReg[adjustedPort-1].PortSC);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
}
portSCAfterReset = Read32Reg(&_pXHCIRegisters->PortReg[adjustedPort-1].PortSC);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
USBTrace( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPortCallout, (uintptr_t)this, 3, adjustedPort, portSCAfterReset);
if ( ((portSCAfterReset & kXHCIPortSC_Speed_Mask) >> kXHCIPortSC_Speed_Shift) == kXHCIPortSC_SS )
{
USBLog(5, "AppleUSBXHCI[%p]::RHResetPort[%d] - after waiting %d ms for PRC, we have a SuperSpeed device, so don't switch the mux (portSC: 0x%x)", this, adjustedPort, (uint32_t)(8-retries-1)*32, (uint32_t)portSCAfterReset);
USBTrace( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPortCallout, (uintptr_t)this, 4, adjustedPort, (uintptr_t)(8-retries-1)*32);
}
else
{
USBLog(5, "AppleUSBXHCI[%p]::RHResetPort[%d] - after waiting %d ms for PRC, we will now wait for another %d ms ", this, adjustedPort, (uint32_t)(7-retries)*32, (uint32_t)(500-((7-retries)*32)));
USBTrace( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPortCallout, (uintptr_t)this, 5, adjustedPort, (uintptr_t)(500-((7-retries)*32)));
IOSleep(500-((7-retries)*32));
companionPort = GetCompanionRootPort(RHSpeed, adjustedPort);
companionPortSC = Read32Reg(&_pXHCIRegisters->PortReg[companionPort-1].PortSC);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
portSCAfterReset = Read32Reg(&_pXHCIRegisters->PortReg[adjustedPort-1].PortSC);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
connectedSpeed = (UInt32)((portSCAfterReset & kXHCIPortSC_Speed_Mask) >> kXHCIPortSC_Speed_Shift);
companionPLSAfterReset = (UInt32)((companionPortSC & kXHCIPortSC_LinkState_Mask) >> kXHCIPortSC_LinkState_Shift);
USBTrace( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPortCallout, (uintptr_t)this, 6, adjustedPort, companionPort);
USBTrace( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPortCallout, (uintptr_t)this, 7, (uintptr_t)portSCAfterReset, (uintptr_t)companionPortSC);
if (companionPLSAfterReset == kXHCIPortSC_PLS_ComplianceMode)
{
USBLog(2, "AppleUSBXHCI[%p]::RHResetPort[%d] - ****PORT IN COMPLIANCE MODE - CompanionPortSC: 0x%08x PLS=%x", this, adjustedPort, (int)companionPortSC, (int)companionPLSAfterReset);
USBTrace( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPortCallout, (uintptr_t)this, 8, adjustedPort, companionPLSAfterReset);
}
USBLog(5, "AppleUSBXHCI[%p]::RHResetPort[%d] - after waiting 500 ms for PRC: speed: %d (%s), PortSCAfterReset: 0x%08x, CompanionPortSC[%d]: 0x%08x", this, adjustedPort, (uint32_t)connectedSpeed,
connectedSpeed == kXHCIPortSC_SS ? "Super" : (connectedSpeed == kXHCIPortSC_HS ? "High" : (connectedSpeed == kXHCIPortSC_FS ? "Full" : (connectedSpeed == kXHCIPortSC_LS ? "Super" : "Unknown"))),
(uint32_t)portSCAfterReset, companionPort, (uint32_t)companionPortSC);
if ((connectedSpeed == kXHCIPortSC_HS) && (portSCAfterReset & kXHCIPortSC_CCS) && !(companionPortSC & kXHCIPortSC_CCS) && !(companionPortSC & kXHCIPortSC_CEC) && !(companionPortSC & kXHCIPortSC_CAS) && !(companionPortSC & kXHCIPortSC_PLC) && !(companionPortSC & kXHCIPortSC_WRC) && (companionPLSAfterReset == kXHCIPortSC_PLS_RxDetect) )
{
portSC = GetPortSCForWriting(adjustedPort);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
portSC |= (UInt32)kXHCIPortSC_PRC;
Write32Reg(&_pXHCIRegisters->PortReg[adjustedPort-1].PortSC, portSC);
IOSync();
USBLog(4, "AppleUSBXHCI[%p]::RHResetPort[%d] - switching mux for XHCI port: %d -> EHCI [HCSEL: %lx]", this, adjustedPort, adjustedPort, (long unsigned int)_device->configRead32(kXHCI_XUSB2PR));
USBTrace( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPortCallout, (uintptr_t)this, 9, (uintptr_t)adjustedPort, (uintptr_t)_device->configRead32(kXHCI_XUSB2PR));
HCSelect((adjustedPort-1), kControllerEHCI);
retries = 8;
portSC = Read32Reg(&_pXHCIRegisters->PortReg[adjustedPort-1].PortSC);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
while ( retries-- && !(portSC & kXHCIPortSC_CSC) )
{
USBLog(6, "AppleUSBXHCI[%p]::RHResetPort[%d] - waiting(%d) for CSC: portSC = 0x%08x", this, adjustedPort, (uint32_t)retries, portSC);
USBTrace( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPortCallout, (uintptr_t)this, 10, adjustedPort, (uintptr_t)retries);
IOSleep(32);
portSC = Read32Reg(&_pXHCIRegisters->PortReg[adjustedPort-1].PortSC);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
}
USBLog(6, "AppleUSBXHCI[%p]::RHResetPort[%d] - waited %d ms for CSC: portSC = 0x%08x, CompanionPortSC[%d]: 0x%08x", this, adjustedPort, (uint32_t)(8-retries-1)*32, Read32Reg(&_pXHCIRegisters->PortReg[adjustedPort-1].PortSC), companionPort, Read32Reg(&_pXHCIRegisters->PortReg[companionPort-1].PortSC));
portSC = GetPortSCForWriting(adjustedPort);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
portSC |= (UInt32)kXHCIPortSC_CSC;
Write32Reg(&_pXHCIRegisters->PortReg[adjustedPort-1].PortSC, portSC);
IOSync();
USBTrace( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPortCallout, (uintptr_t)this, 11, adjustedPort, (uintptr_t)(8-retries-1)*32);
returnValue = kIOUSBDeviceTransferredToCompanion;
}
else
{
USBLog(6, "AppleUSBXHCI[%p]::RHResetPort[%d] - not switching the mux because the portSC's told us not to do so", this, adjustedPort);
USBTrace( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPortCallout, (uintptr_t)this, 12, adjustedPort, _testModeEnabled);
if ( !_testModeEnabled && (companionPLSAfterReset == kXHCIPortSC_PLS_ComplianceMode) )
{
USBLog(2, "AppleUSBXHCI[%p]::RHResetPort[%d] - CompanionPort[%d] in compliance mode issuing WarmReset", this, adjustedPort, companionPort);
USBTrace( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPortCallout, (uintptr_t)this, 13, adjustedPort, (uintptr_t)companionPLSAfterReset);
(void) XHCIRootHubWarmResetPort(companionPort);
retries = 8;
portSC = Read32Reg(&_pXHCIRegisters->PortReg[companionPort-1].PortSC);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
while ( retries-- && !(portSC & (kXHCIPortSC_PRC | kXHCIPortSC_WRC)) )
{
USBLog(6, "AppleUSBXHCI[%p]::RHResetPort - waiting(%d) for WRC/PRC after resetting port %d", this, (uint32_t)retries, companionPort);
USBTrace( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPortCallout, (uintptr_t)this, 14, adjustedPort, (uintptr_t)retries);
IOSleep(32);
portSC = Read32Reg(&_pXHCIRegisters->PortReg[companionPort-1].PortSC);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
}
companionPortSC = Read32Reg(&_pXHCIRegisters->PortReg[companionPort-1].PortSC);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
USBLog(6, "AppleUSBXHCI[%p]::RHResetPort - waited %d ms for companion port WRC/PRC: CompanionPortSC[%d]: 0x%08x", this, (uint32_t)(8-retries-1)*32, companionPort, (uint32_t)companionPortSC);
USBTrace( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPortCallout, (uintptr_t)this, 15, adjustedPort, (uintptr_t)companionPortSC);
if ( companionPortSC & kXHCIPortSC_WRC)
{
USBTrace( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPortCallout, (uintptr_t)this, 16, adjustedPort, 0);
portSC = GetPortSCForWriting(companionPort);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
portSC |= (UInt32)kXHCIPortSC_WRC;
Write32Reg(&_pXHCIRegisters->PortReg[companionPort-1].PortSC, portSC);
IOSync();
}
if ( companionPortSC & kXHCIPortSC_PRC)
{
USBTrace( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPortCallout, (uintptr_t)this, 17, adjustedPort, 0);
portSC = GetPortSCForWriting(companionPort);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
portSC |= (UInt32)kXHCIPortSC_PRC;
Write32Reg(&_pXHCIRegisters->PortReg[companionPort-1].PortSC, portSC);
IOSync();
}
}
}
}
}
}
else
{
USBLog(6, "AppleUSBXHCI[%p]::RHResetPort[%d] - mux switching is disabled", this, adjustedPort);
}
USBTrace_End( kUSBTXHCIRootHubs, kTPXHCIRootHubResetPortCallout, (uintptr_t)this, adjustedPort, Read32Reg(&_pXHCIRegisters->PortReg[adjustedPort-1].PortSC), returnValue);
return returnValue;
}
#pragma mark RH Resume methods
void
AppleUSBXHCI::RHResumePortTimerEntry(OSObject *target, thread_call_param_t port)
{
AppleUSBXHCI *me = OSDynamicCast(AppleUSBXHCI, target);
if (!me)
return;
me->RHResumePortTimer((UInt32)(uintptr_t)port); }
void
AppleUSBXHCI::RHResumePortTimer(UInt32 port)
{
if (!_commandGate)
return;
USBLog(5, "AppleUSBXHCI[%p]::RHResumePortTimer - timing the resume for port %d", this, (int)port);
IOSleep(20); USBLog(6, "AppleUSBXHCI[%p]::RHResumePortTimer - Host controller resume about to finish - calling EnsureUsability", this);
EnsureUsability();
_commandGate->runAction(RHResumePortCompletionEntry, (void*)port);
}
IOReturn
AppleUSBXHCI::RHResumePortCompletionEntry(OSObject *target, void *param1, void *param2, void *param3, void *param4)
{
#pragma unused(param2)
#pragma unused(param3)
#pragma unused(param4)
AppleUSBXHCI *me = OSDynamicCast(AppleUSBXHCI, target);
UInt32 port = (UInt32)(uintptr_t)param1;
if (!me)
return kIOReturnInternalError;
return me->RHResumePortCompletion(port);
}
IOReturn
AppleUSBXHCI::RHCompleteResumeOnAllPorts()
{
UInt32 value;
int i;
UInt32 portIndex;
IOReturn returnValue = kIOReturnSuccess;
UInt32 waitTime = 0;
USBLog(6, "AppleUSBXHCI[%p]::RHCompleteResumeOnAllPorts", this);
if (_lostRegisterAccess || !_controllerAvailable)
{
for (portIndex = 0; portIndex < _rootHubNumPorts; portIndex++)
{
USBLog(5, "AppleUSBXHCI[%p]::RHCompleteResumeOnAllPorts - cannot finish resume on port %d because the controller is unavailable", this, (int)portIndex+1);
if ( _rhPortBeingResumed[portIndex] )
_rhPortBeingResumed[portIndex] = false;
}
return kIOReturnInternalError;
}
for (portIndex = 0; portIndex < _rootHubNumPorts; portIndex++)
{
UInt32 port = portIndex + 1;
if ( _rhPortBeingResumed[portIndex] )
{
USBLog(5, "AppleUSBXHCI[%p]::RHCompleteResumeOnAllPorts - resuming port %d", this, (int)port);
value = GetPortSCForWriting(port);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
value |= (UInt32)(kXHCIPortSC_LWS | (kXHCIPortSC_PLS_U0 << kXHCIPortSC_LinkState_Shift));
Write32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC, value);
IOSync();
waitTime = 2;
}
}
if ( waitTime )
IOSleep(waitTime);
for (portIndex = 0; portIndex < _rootHubNumPorts; portIndex++)
{
if ( _rhPortBeingResumed[portIndex] )
{
_rhPortBeingResumed[portIndex] = false;
_suspendChangeBits[portIndex] = true;
}
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBXHCI::RHResumePortCompletion(UInt32 port)
{
#if 1
UInt32 value;
USBLog(5, "AppleUSBXHCI[%p]::RHResumePortCompletion - finishing resume on port %d", this, (int)port);
if (!_rhPortBeingResumed[port-1])
{
USBLog(1, "AppleUSBXHCI[%p]::RHResumePortCompletion - port %d does not appear to be resuming!", this, (int)port);
return kIOReturnInternalError;
}
if (_lostRegisterAccess || !_controllerAvailable)
{
USBLog(5, "AppleUSBXHCI[%p]::RHResumePortCompletion - cannot finish resume on port %d because the controller is unavailable", this, (int)port);
_rhPortBeingResumed[port-1] = false;
return kIOReturnNoDevice;
}
value = GetPortSCForWriting(port);
if (_lostRegisterAccess)
{
return kIOReturnNoDevice;
}
value |= (UInt32)(kXHCIPortSC_LWS | (kXHCIPortSC_PLS_U0 << kXHCIPortSC_LinkState_Shift));
Write32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC, value);
IOSync();
IOSleep(2); PrintRuntimeRegs();
_rhPortBeingResumed[port-1] = false;
_suspendChangeBits[port-1] = true;
CheckForRootHubChanges();
#endif
return kIOReturnSuccess;
}
void
AppleUSBXHCI::RHCheckForPortResumes()
{
int i;
UInt32 port, PLS;
if(_lostRegisterAccess)
{
return;
}
for (port = 0; port < _rootHubNumPorts; port++)
{
if (!_rhPortBeingResumed[port])
{
UInt32 portSC = Read32Reg(&_pXHCIRegisters->PortReg[port].PortSC);
if (_lostRegisterAccess)
{
return;
}
PLS = (UInt32)(portSC & kXHCIPortSC_LinkState_Mask) >> kXHCIPortSC_LinkState_Shift;
if (PLS == kXHCIPortSC_PLS_Resume)
{
USBLog(5, "AppleUSBXHCI[%p]::RHCheckForPortResumes - port %d appears to be resuming from a remote wakeup - spawning thread to resume", this, (int)port+1);
_rhPortBeingResumed[port] = true;
if ( _rhResumePortTimerThread[port] == NULL )
{
USBLog(1,"AppleUSBXHCI[%p]::RHCheckForPortResumes port %d appears to be resuming from a remote wakeup, but the thread callout is NULL!", this, (uint32_t)port+1);
}
else
thread_call_enter1(_rhResumePortTimerThread[port], (void*)(port+1));
}
}
}
}
#pragma mark Utility Functions
UInt16
AppleUSBXHCI::GetCompanionRootPort(UInt8 speed, UInt16 adjustedPort)
{
UInt16 companionRootPort = 0;
if( speed == kUSBDeviceSpeedHigh )
{
companionRootPort = (_v3ExpansionData->_rootHubPortsSSStartRange-1) + adjustedPort;
}
else if( speed == kUSBDeviceSpeedSuper )
{
companionRootPort = (_v3ExpansionData->_rootHubPortsHSStartRange-1) + adjustedPort;
}
return companionRootPort;
}
void
AppleUSBXHCI::AdjustRootHubPortNumbers(UInt8 speed, UInt16 *port)
{
if( speed == kUSBDeviceSpeedHigh )
{
*port += _v3ExpansionData->_rootHubPortsHSStartRange-1;
}
else if( speed == kUSBDeviceSpeedSuper )
{
*port += _v3ExpansionData->_rootHubPortsSSStartRange-1;
}
}
bool
AppleUSBXHCI::IsRootHubPortSuperSpeed(UInt16 *port)
{
bool isSuperSpeed = false;
if ( _v3ExpansionData->_rootHubPortsSSStartRange > _v3ExpansionData->_rootHubPortsHSStartRange )
{
if ( *port >= _v3ExpansionData->_rootHubPortsSSStartRange)
{
isSuperSpeed = true;
*port = *port - _v3ExpansionData->_rootHubPortsSSStartRange + 1;
}
}
else
{
if ( *port < _v3ExpansionData->_rootHubPortsHSStartRange)
{
isSuperSpeed = true;
}
}
return isSuperSpeed;
}
UInt32
AppleUSBXHCI::GetPortSCForWriting(short port)
{
UInt32 portSC;
portSC = Read32Reg(&_pXHCIRegisters->PortReg[port-1].PortSC);
if (_lostRegisterAccess)
{
return portSC;
}
portSC &= ~(UInt32)kXHCIPortSC_Write_Zeros;
return(portSC);
}