IOUSBControllerV2.cpp [plain text]
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/usb/IOUSBController.h>
#include <IOKit/usb/IOUSBControllerV2.h>
#include <IOKit/usb/IOUSBControllerV3.h>
#include <IOKit/usb/IOUSBLog.h>
#include "USBTracepoints.h"
#define CONTROLLERV2_USE_KPRINTF 0
#if CONTROLLERV2_USE_KPRINTF
#undef USBLog
#undef USBError
void kprintf(const char *format, ...)
__attribute__((format(printf, 1, 2)));
#define USBLog( LEVEL, FORMAT, ARGS... ) if ((LEVEL) <= CONTROLLERV2_USE_KPRINTF) { kprintf( FORMAT "\n", ## ARGS ) ; }
#define USBError( LEVEL, FORMAT, ARGS... ) { kprintf( FORMAT "\n", ## ARGS ) ; }
#endif
extern IOReturn CheckForDisjointDescriptor(IOUSBCommand *command, UInt16 maxPacketSize);
#define super IOUSBController
enum {
kSetupSent = 0x01,
kDataSent = 0x02,
kStatusSent = 0x04,
kSetupBack = 0x10,
kDataBack = 0x20,
kStatusBack = 0x40
};
OSDefineMetaClass( IOUSBControllerV2, IOUSBController )
OSDefineAbstractStructors(IOUSBControllerV2, IOUSBController)
bool
IOUSBControllerV2::init(OSDictionary * propTable)
{
if (!super::init(propTable)) return false;
if (!_v2ExpansionData)
{
_v2ExpansionData = (V2ExpansionData *)IOMalloc(sizeof(V2ExpansionData));
if (!_v2ExpansionData)
return false;
bzero(_v2ExpansionData, sizeof(V2ExpansionData));
}
return (true);
}
bool
IOUSBControllerV2::start( IOService * provider )
{
if ( !super::start(provider))
return (false);
_returnIsochDoneQueueThread = thread_call_allocate((thread_call_func_t)ReturnIsochDoneQueueEntry, (thread_call_param_t)this);
if ( !_returnIsochDoneQueueThread )
{
USBError(1, "IOUSBControllerV2[%p]::start - could not allocate thread callout function.", this);
return false;
}
return true;
}
void
IOUSBControllerV2::free()
{
if (_v2ExpansionData && _returnIsochDoneQueueThread)
{
thread_call_cancel(_returnIsochDoneQueueThread);
thread_call_free(_returnIsochDoneQueueThread);
}
if (_v2ExpansionData)
{
IOFree(_v2ExpansionData, sizeof(V2ExpansionData));
_v2ExpansionData = NULL;
}
super::free();
}
void
IOUSBControllerV2::clearTTHandler(OSObject *target, void *parameter, IOReturn status, UInt32 bufferSizeRemaining)
{
#pragma unused (bufferSizeRemaining)
IOUSBController * me = (IOUSBController *)target;
IOUSBCommand * command = (IOUSBCommand *)parameter;
IOMemoryDescriptor * memDesc = NULL;
IODMACommand * dmaCommand = NULL;
UInt8 sent, back, todo;
UInt8 hubAddr = command->GetAddress();
USBTrace_Start( kUSBTController, kTPControllerClearTTHandler, (uintptr_t)me, (uintptr_t)command, status, bufferSizeRemaining );
USBLog(5,"clearTTHandler: status (0x%x)", status);
if (!me || !command)
{
USBError(1,"clearTTHandler: missing controller or command");
}
sent = (command->GetStage() & 0x0f) << 4;
back = command->GetStage() & 0xf0;
todo = sent ^ back;
if ((todo & kSetupBack) != 0)
{
USBLog(5,"clearTTHandler: Setup comming back to us, check and forget");
command->SetStage(command->GetStage() | kSetupBack);
}
else
{
dmaCommand = command->GetDMACommand();
memDesc = command->GetRequestMemoryDescriptor();
command->SetStage(0);
if (dmaCommand)
{
if (dmaCommand->getMemoryDescriptor())
{
if (dmaCommand->getMemoryDescriptor() != memDesc)
{
USBLog(5, "clearTTHandler: DMA Command Memory Descriptor (%p) does not match Request MemoryDescriptor (%p)", dmaCommand->getMemoryDescriptor(), memDesc);
USBTrace( kUSBTController, kTPControllerClearTTHandler, (uintptr_t)me, (uintptr_t)dmaCommand->getMemoryDescriptor(), (uintptr_t)memDesc, 1 );
}
USBLog(7, "clearTTHandler: clearing memory descriptor (%p) from dmaCommand (%p)", dmaCommand->getMemoryDescriptor(), dmaCommand);
dmaCommand->clearMemoryDescriptor();
}
else
{
USBLog(2, "clearTTHandler - dmaCommand (%p) already cleared", dmaCommand);
USBTrace( kUSBTController, kTPControllerClearTTHandler, (uintptr_t)me, (uintptr_t)dmaCommand, 0, 2 );
}
}
if (memDesc)
{
USBLog(6, "clearTTHandler - completing and freeing memory descriptor (%p)", memDesc);
USBTrace( kUSBTController, kTPControllerClearTTHandler, (uintptr_t)me, (uintptr_t)memDesc, 0, 3 );
command->SetRequestMemoryDescriptor(NULL);
memDesc->complete();
memDesc->release();
}
else
{
USBLog(1, "clearTTHandler - missing memory descriptor");
USBTrace( kUSBTController, kTPControllerClearTTHandler, (uintptr_t)me, 0, 0, 4 );
}
USBLog(5,"clearTTHandler: We've already seen the setup, deallocate command (%p)", command);
me->_freeUSBCommandPool->returnCommand(command);
}
if ((status != kIOReturnSuccess) && (status != kIOUSBTransactionReturned))
{
USBLog((status == kIOReturnNotResponding ? 5 : 1), "%s[%p]::clearTTHandler - error response from hub (0x%x), clearing hub endpoint stall", me->getName(), me, status);
USBTrace( kUSBTController, kTPControllerClearTTHandler, (uintptr_t)me, status, 0, 5 );
me->UIMClearEndpointStall(hubAddr, 0, kUSBAnyDirn);
}
USBTrace_End( kUSBTController, kTPControllerClearTTHandler, (uintptr_t)me, 0, 0, 0 );
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 6);
void
IOUSBControllerV2::ClearTT(USBDeviceAddress fnAddress, UInt8 endpt, Boolean IN)
{
UInt16 wValue;
IOBufferMemoryDescriptor *memDesc = NULL;
IOUSBDevRequest *clearRequest = NULL;
short hubAddress;
IOUSBCommand *clearCommand = NULL;
IOUSBCompletion completion;
int i;
IOReturn err = kIOReturnSuccess;
IODMACommand *dmaCommand = NULL;
USBLog(5,"+%s[%p]::ClearTT", getName(), this);
USBTrace_Start( kUSBTController, kTPControllerClearTT, (uintptr_t)this, fnAddress, endpt, IN );
hubAddress = _highSpeedHub[fnAddress]; if (hubAddress == 0) {
USBLog(1,"-%s[%p]::ClearTT high speed device, returning", getName(), this);
USBTrace( kUSBTController, kTPControllerClearTT, (uintptr_t)this, 0, 0, 1 );
return;
}
memDesc = IOBufferMemoryDescriptor::withOptions(kIOMemoryUnshared | kIODirectionInOut, sizeof(IOUSBDevRequest));
do {
if (!memDesc)
{
USBLog(1,"%s[%p]::ClearTT Could not get a memory descriptor",getName(),this);
USBTrace( kUSBTController, kTPControllerClearTT, (uintptr_t)this, 0, 0, 2 );
err = kIOReturnNoMemory;
break;
}
err = memDesc->prepare();
if (err != kIOReturnSuccess)
{
USBError(1,"%s[%p]::ClearTT - err (%p) trying to prepare memory descriptor", getName(), this, (void*)err);
memDesc->release();
memDesc = NULL;
break;
}
clearRequest = (IOUSBDevRequest*)memDesc->getBytesNoCopy();
if (!clearRequest)
{
USBLog(1,"%s[%p]::ClearTT Could not get a IOUSBDevRequest", getName(), this);
USBTrace( kUSBTController, kTPControllerClearTT, (uintptr_t)this, 0, 0, 5 );
err = kIOReturnNoMemory;
break;
}
USBLog(5, "%s[%p]::ClearTT - got IOUSBDevRequest (%p)", getName(), this, clearRequest);
clearCommand = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false);
if ( clearCommand == NULL )
{
IncreaseCommandPool();
clearCommand = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false);
if ( clearCommand == NULL )
{
USBLog(1,"%s[%p]::ClearTT Could not get a IOUSBCommand",getName(),this);
USBTrace( kUSBTController, kTPControllerClearTT, (uintptr_t)this, 0, 0, 3 );
err = kIOReturnNoResources;
break;
}
}
USBLog(7, "%s[%p]::ClearTT V2 got command (%p)", getName(), this, clearCommand);
if (clearCommand->GetBufferUSBCommand())
{
USBLog(1,"%s[%p]::ClearTT - unexpected BufferUSBCommand(%p) inside of new command(%p)", getName(), this, clearCommand->GetBufferUSBCommand(), clearCommand);
clearCommand->SetBufferUSBCommand(NULL);
}
if (clearCommand->GetRequestMemoryDescriptor())
{
USBLog(1,"%s[%p]::ClearTT - unexpected RequestMemoryDescriptor(%p) inside of new command(%p)", getName(), this, clearCommand->GetRequestMemoryDescriptor(), clearCommand);
clearCommand->SetRequestMemoryDescriptor(NULL);
}
dmaCommand = clearCommand->GetDMACommand();
if (!dmaCommand)
{
USBError(1,"%s[%p]::ClearTT - No dmaCommand in the usb command", getName(), this);
USBTrace( kUSBTController, kTPControllerClearTT, (uintptr_t)this, 0, 0, 4 );
err = kIOReturnNoResources;
break;
}
if (dmaCommand->getMemoryDescriptor())
{
IOMemoryDescriptor *XmemDesc = (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor();
USBError(1,"%s[%p]::ClearTT - dmaCommand (%p) already had memory descriptor (%p) - clearing", getName(), this, dmaCommand, XmemDesc);
dmaCommand->clearMemoryDescriptor();
}
USBLog(7,"%s[%p]::ClearTT - setting memory descriptor (%p) into dmaCommand (%p)", getName(), this, memDesc, dmaCommand);
err = dmaCommand->setMemoryDescriptor(memDesc);
if (err)
{
USBError(1,"%s[%p]::ClearTT - err (%p) setting memory descriptor (%p) into dmaCommand (%p)", getName(), this, (void*)err, memDesc, dmaCommand);
break;
}
clearCommand->SetRequestMemoryDescriptor(memDesc);
clearCommand->SetReqCount(8);
memDesc = NULL;
wValue = (endpt & 0xf) | ( (fnAddress & 0x7f) << 4);
if (IN)
{
wValue |= (1 << 15);
}
USBLog(5,"%s[%p]::ClearTT - V2 EP (%d) ADDR (%d) wValue (0x%x)", getName(), this, endpt, fnAddress, wValue);
clearRequest->bmRequestType = 0x23;
clearRequest->bRequest = 8;
clearRequest->wValue = HostToUSBWord(wValue);
if (_v2ExpansionData->_multiTT[hubAddress])
{ clearRequest->wIndex = HostToUSBWord(_highSpeedPort[fnAddress]);
}
else
{ clearRequest->wIndex = HostToUSBWord(1);
}
clearRequest->wLength = HostToUSBWord(0);
clearRequest->pData = NULL;
clearRequest->wLenDone = 0;
completion.target = (void *)this;
completion.action = (IOUSBCompletionAction) &clearTTHandler;
completion.parameter = clearCommand;
clearCommand->SetUSLCompletion(completion);
clearCommand->SetUseTimeStamp(false);
clearCommand->SetSelector(DEVICE_REQUEST);
clearCommand->SetRequest(clearRequest);
clearCommand->SetAddress(hubAddress);
clearCommand->SetEndpoint(0);
clearCommand->SetType(kUSBControl);
clearCommand->SetBuffer(0); clearCommand->SetClientCompletion(completion);
clearCommand->SetNoDataTimeout(5000);
clearCommand->SetCompletionTimeout(0);
clearCommand->SetStage(0);
clearCommand->SetBufferUSBCommand(NULL);
clearCommand->SetMultiTransferTransaction(false);
clearCommand->SetFinalTransferInTransaction(false);
for (i=0; i < 10; i++)
clearCommand->SetUIMScratch(i, 0);
err = ControlTransaction(clearCommand);
} while (false);
if (kIOReturnSuccess != err)
{
USBLog(1, "%s[%p]::ClearTT - error 0x%x cleaning up", getName(), this, err);
USBTrace( kUSBTController, kTPControllerClearTT, (uintptr_t)this, err, 0, 6 );
if (memDesc)
{
memDesc->complete();
memDesc->release();
memDesc = NULL;
}
if (clearCommand)
{
memDesc = (IOBufferMemoryDescriptor*)clearCommand->GetRequestMemoryDescriptor();
if (memDesc)
clearCommand->SetRequestMemoryDescriptor(NULL);
dmaCommand = clearCommand->GetDMACommand();
}
if (dmaCommand && dmaCommand->getMemoryDescriptor())
{
USBLog(2, "%s[%p]::ClearTT - clearing dmaCommand", getName(), this);
dmaCommand->clearMemoryDescriptor();
}
if (memDesc)
{
memDesc->complete();
memDesc->release();
memDesc = NULL;
}
if (clearCommand)
{
USBLog(7, "%s[%p]::ClearTT - returning command", getName(), this);
_freeUSBCommandPool->returnCommand(clearCommand);
}
}
USBTrace_End( kUSBTController, kTPControllerClearTT, (uintptr_t)this, 0, 0, 0);
}
IOReturn IOUSBControllerV2::OpenPipe(USBDeviceAddress address, UInt8 speed, Endpoint *endpoint)
{
return _commandGate->runAction(DoCreateEP, (void *)(UInt32)address, (void *)(UInt32)speed, endpoint);
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 25);
IOReturn IOUSBControllerV2::OpenSSPipe(USBDeviceAddress address, UInt8 speed, Endpoint *endpoint, UInt32 maxStreams, UInt32 maxBurstAndMult)
{
return _commandGate->runAction(DoCreateEP, (void *)(UInt32)address, (void *)(UInt32)speed, endpoint, (void *)(maxStreams+(maxBurstAndMult << 16)));
}
IOReturn
IOUSBControllerV2::DoCreateEP(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3)
{
IOUSBControllerV2 * me = (IOUSBControllerV2 *)owner;
UInt8 address = (UInt8)(uintptr_t)arg0;
UInt8 speed = (UInt8)(uintptr_t)arg1;
Endpoint * endpoint = (Endpoint *)arg2;
UInt16 maxStreams = ((UInt32)(uintptr_t)arg3) & 0xffff;
UInt8 maxBurst = (((UInt32)(uintptr_t)arg3) & 0xFF0000) >> 16;
UInt8 mult = (((UInt32)(uintptr_t)arg3) & 0xFF000000) >> 24; IOReturn err;
USBLog(5,"%s[%p]::DoCreateEP, high speed ancestor hub:%d, port:%d, address: %d, speed: %d, maxStreams: %d, maxBurst: %d, mult: %d EP: (%d,%d,%d,%d)", me->getName(), me, me->_highSpeedHub[address], me->_highSpeedPort[address],
(uint32_t)address, (uint32_t)speed, (uint32_t)maxStreams, (uint32_t)maxBurst, (uint32_t)mult,
(uint32_t)endpoint->number, (uint32_t)endpoint->direction, (uint32_t)endpoint->maxPacketSize, (uint32_t)endpoint->interval);
USBTrace_Start( kUSBTController, kTPControllerDoCreateEP, (uintptr_t)me, me->_highSpeedHub[address], me->_highSpeedPort[address], endpoint->transferType );
IOUSBControllerV3 *me3 = OSDynamicCast(IOUSBControllerV3, owner);
if(me3 == NULL)
{
if( (maxBurst != 0) || (maxStreams != 0) )
{
USBLog(1,"%s[%p]::DoCreateEP, SuperSpeed create EP, but controller doesn't support it. maxStreams: %d, maxBurst: %d", me->getName(), me, (int)maxStreams, (int)maxBurst);
return kIOReturnUnsupported;
}
}
switch (endpoint->transferType)
{
case kUSBInterrupt:
if(maxBurst == 0)
{
err = me->UIMCreateInterruptEndpoint(address,
endpoint->number,
endpoint->direction,
speed,
endpoint->maxPacketSize, endpoint->interval,
me->_highSpeedHub[address],
me->_highSpeedPort[address]);
}
else
{
err = me3->UIMCreateSSInterruptEndpoint(address,
endpoint->number,
endpoint->direction,
speed,
endpoint->maxPacketSize,
endpoint->interval,
maxBurst);
}
break;
case kUSBBulk:
if( (maxStreams == 0) && (maxBurst == 0) )
{
err = me->UIMCreateBulkEndpoint(address,
endpoint->number,
endpoint->direction,
speed,
endpoint->maxPacketSize,
me->_highSpeedHub[address],
me->_highSpeedPort[address]);
}
else
{
err = me3->UIMCreateSSBulkEndpoint(address,
endpoint->number,
endpoint->direction,
speed,
endpoint->maxPacketSize,
maxStreams,
maxBurst);
}
break;
case kUSBControl:
err = me->UIMCreateControlEndpoint(address,
endpoint->number,
endpoint->maxPacketSize,
speed,
me->_highSpeedHub[address],
me->_highSpeedPort[address]);
break;
case kUSBIsoc:
{
if ((speed == kUSBDeviceSpeedHigh) || (speed == kUSBDeviceSpeedSuper))
{
UInt32 interval;
if ((endpoint->interval < 1) || (endpoint->interval > 16))
{
USBLog(1, "%s[%p]::DoCreateEP - The USB 2.0/3.0 spec only allows Isoch EP with bInterval values of 1 through 16 "
"(see Table 9-13 for USB2, 9-20 for USB3), but the illegal interval %d [0x%x] was requested, returning kIOReturnBadArgument",
me->getName(), me, endpoint->interval, endpoint->interval);
err = kIOReturnBadArgument;
USBTrace( kUSBTController, kTPControllerDoCreateEP, (uintptr_t)me, err, endpoint->interval, 0);
break;
}
interval = (1 << (endpoint->interval - 1));
USBLog(4, "%s[%p]::DoCreateEP - Creating a %s Speed Isoch EP with interval %u [raw %u]", me->getName(), me, speed == kUSBDeviceSpeedHigh ? "Hi" : "Super",
(unsigned int )interval, (unsigned int )endpoint->interval);
}
else
{
endpoint->interval = 1;
USBLog(4, "%s[%p]::DoCreateEP - Creating a Full Speed Isoch EP with interval %u", me->getName(), me, (unsigned int )endpoint->interval);
}
if (maxBurst == 0)
{
err = me->UIMCreateIsochEndpoint(address,
endpoint->number,
endpoint->maxPacketSize,
endpoint->direction,
me->_highSpeedHub[address],
me->_highSpeedPort[address],
endpoint->interval);
}
else
{
err = me3->UIMCreateSSIsochEndpoint(address,
endpoint->number,
endpoint->maxPacketSize,
endpoint->direction,
endpoint->interval,
maxBurst | (mult << 8));
}
break;
}
default:
err = kIOReturnBadArgument;
break;
}
USBTrace_End( kUSBTController, kTPControllerDoCreateEP, (uintptr_t)me, err, 0, 0 );
if ( err == kIOUSBEndpointCountExceeded )
{
USBLog(1, "%s[%p]::DoCreateEP - Received a kIOUSBEndpointCountExceeded, Address: %d, Speed: %d: Endpoint: (0x%x, 0x%x, 0x%x, 0x%x)", me->getName(), me, address, speed,
(uint32_t) endpoint->number,
(uint32_t) endpoint->direction,
(uint32_t) endpoint->maxPacketSize,
(uint32_t) endpoint->interval);
IOLog("The USB device at USB Address %d might not work correctly because the controller driver has reached a hardware limit on the number of endpoints", address);
}
return (err);
}
IOReturn
IOUSBControllerV2::CreateDevice( IOUSBDevice *newDevice,
USBDeviceAddress deviceAddress,
UInt8 maxPacketSize,
UInt8 speed,
UInt32 powerAvailable,
USBDeviceAddress hub,
int port)
{
USBLog(5,"%s[%p]::CreateDevice, new method called with speed : %d hub:%d, port:%d", getName(), this, speed, hub, port);
if( deviceAddress > kUSBMaxDevices )
{
USBLog(5,"%s[%p]::CreateDevice, returning kIOReturnInvalid with address: %d speed : %d hub:%d, port:%d", getName(), this, deviceAddress, speed, hub, port);
return kIOReturnInvalid;
}
if ( speed < kUSBDeviceSpeedHigh )
{
if ( (hub == kXHCISSRootHubAddress) or (hub == kXHCIUSB2RootHubAddress) )
{
_highSpeedHub[deviceAddress] = hub;
_highSpeedPort[deviceAddress] = port;
}
else
{
if (_highSpeedHub[hub] == 0) {
_highSpeedHub[deviceAddress] = hub;
_highSpeedPort[deviceAddress] = port;
}
else
{
_highSpeedHub[deviceAddress] = _highSpeedHub[hub];
_highSpeedPort[deviceAddress] = _highSpeedPort[hub];
}
}
}
else
{
_highSpeedHub[deviceAddress] = 0;
_highSpeedPort[deviceAddress] = 0;
}
USBLog(5,"%s[%p]::CreateDevice, high speed ancestor hub:%d, port:%d",getName(), this, _highSpeedHub[deviceAddress], _highSpeedPort[deviceAddress]);
return (super::CreateDevice(newDevice, deviceAddress, maxPacketSize, speed, powerAvailable));
}
IOReturn
IOUSBControllerV2::ConfigureDeviceZero(UInt8 maxPacketSize, UInt8 speed, USBDeviceAddress hub, int port)
{
USBLog(5,"%s[%p]::ConfigureDeviceZero, new method called with speed : %d, hub:%d, port:%d", getName(), this, speed, hub, port);
if( hub > kXHCIUSB2RootHubAddress )
{
USBLog(5,"%s[%p]::ConfigureDeviceZero, returning kIOReturnInvalid with speed : %d hub:%d, port:%d", getName(), this, speed, hub, port);
return kIOReturnInvalid;
}
if ( speed < kUSBDeviceSpeedHigh )
{
if ( (hub == kXHCISSRootHubAddress) or (hub == kXHCIUSB2RootHubAddress) )
{
_highSpeedHub[0] = hub;
_highSpeedPort[0] = port;
}
else
{
if (_highSpeedHub[hub] == 0) {
_highSpeedHub[0] = hub;
_highSpeedPort[0] = port;
}
else
{
_highSpeedHub[0] = _highSpeedHub[hub];
_highSpeedPort[0] = _highSpeedPort[hub];
}
}
}
else
{
_highSpeedHub[0] = 0;
_highSpeedPort[0] = 0;
}
USBLog(5, "%s[%p]::CreateDevice, high speed ancestor hub:%d, port:%d", getName(), this, _highSpeedHub[0], _highSpeedPort[0]);
return (super::ConfigureDeviceZero(maxPacketSize, speed));
}
IOReturn
IOUSBControllerV2::DOHSHubMaintenance(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3)
{
#pragma unused (arg3)
IOUSBControllerV2 *me = (IOUSBControllerV2 *)owner;
USBDeviceAddress highSpeedHub = (USBDeviceAddress)(uintptr_t)arg0;
UInt32 command = (uintptr_t)arg1;
UInt32 flags = (uintptr_t)arg2;
UInt8 multi;
USBLog(5,"%s[%p]::DOHSHubMaintenance, command: %d, flags: %d", me->getName(), me, (uint32_t)command, (uint32_t)flags);
multi = ((flags & kUSBHSHubFlagsMultiTTMask) != 0);
me->_v2ExpansionData->_multiTT[highSpeedHub] = multi;
USBLog(3,"%s[%p]::DOHSHubMaintenance hub at %d is multiTT:%d", me->getName(), me, highSpeedHub, (uint32_t)me->_v2ExpansionData->_multiTT[highSpeedHub]);
return me->UIMHubMaintenance(highSpeedHub, 0, command, flags);
}
IOReturn
IOUSBControllerV2::DOSetTestMode(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3)
{
#pragma unused (arg2, arg3)
IOUSBControllerV2 *me = (IOUSBControllerV2 *)owner;
UInt32 mode = (uintptr_t)arg0;
UInt32 port = (uintptr_t)arg1;
USBLog(5,"%s[%p]::DOSetTestMode, mode: %d, port: %d", me->getName(), me, (uint32_t)mode, (uint32_t)port);
return me->UIMSetTestMode(mode, port);
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 0);
IOReturn
IOUSBControllerV2::AddHSHub(USBDeviceAddress highSpeedHub, UInt32 flags)
{
return _commandGate->runAction(DOHSHubMaintenance, (void *)(UInt32)highSpeedHub,
(void *)(UInt32)kUSBHSHubCommandAddHub, (void *)flags);
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 1);
IOReturn
IOUSBControllerV2::UIMHubMaintenance(USBDeviceAddress highSpeedHub, UInt32 highSpeedPort, UInt32 command, UInt32 flags)
{
#pragma unused (highSpeedHub, highSpeedPort, command, flags)
return kIOReturnUnsupported; }
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 2);
IOReturn
IOUSBControllerV2::RemoveHSHub(USBDeviceAddress highSpeedHub)
{
return _commandGate->runAction(DOHSHubMaintenance, (void *)(UInt32)highSpeedHub,
(void *)(UInt32)kUSBHSHubCommandRemoveHub, NULL);
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 3);
IOReturn
IOUSBControllerV2::SetTestMode(UInt32 mode, UInt32 port)
{
return _commandGate->runAction(DOSetTestMode, (void *)mode, (void *)port);
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 4);
IOReturn
IOUSBControllerV2::UIMSetTestMode(UInt32 mode, UInt32 port)
{
#pragma unused (mode, port)
return kIOReturnUnsupported; }
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 5);
UInt64
IOUSBControllerV2::GetMicroFrameNumber(void)
{
return 0; }
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 7);
IOReturn
IOUSBControllerV2::ReadV2(IOMemoryDescriptor *buffer, USBDeviceAddress address, Endpoint *endpoint, IOUSBCompletionWithTimeStamp *completion, UInt32 noDataTimeout, UInt32 completionTimeout, IOByteCount reqCount)
{
IOReturn err = kIOReturnSuccess;
IOUSBCommand *command;
IOUSBCompletion nullCompletion;
IOUSBCompletion theCompletion;
IODMACommand *dmaCommand = NULL;
int i;
bool isSyncTransfer = false;
USBLog(7, "%s[%p]::ReadV2 - reqCount = %d", getName(), this, (uint32_t)reqCount);
if ((endpoint->direction != kUSBIn) || !buffer || (buffer->getLength() < reqCount))
{
USBLog(5, "%s[%p]::ReadV2 - ep direction is not kUSBIn (%d), No Buffer, or buffer length < reqCount (%qd < %qd). Returning kIOReturnBadArgument(0x%x)", getName(), this, endpoint->direction, (uint64_t)buffer->getLength(), (uint64_t)reqCount, kIOReturnBadArgument);
return kIOReturnBadArgument;
}
if ((endpoint->transferType != kUSBBulk) && (noDataTimeout || completionTimeout))
{
USBLog(5, "%s[%p]::ReadV2 - Pipe is NOT kUSBBulk (%d) AND specified a timeout (%d, %d). Returning kIOReturnBadArgument(0x%x)", getName(), this, endpoint->transferType, (uint32_t)noDataTimeout, (uint32_t)completionTimeout, kIOReturnBadArgument);
return kIOReturnBadArgument; }
if (!completion)
{
USBLog(5, "%s[%p]::ReadV2 - No Completion routine. Returning kIOReturnNoCompletion(0x%x)", getName(), this, kIOReturnNoCompletion);
return kIOReturnNoCompletion;
}
if (!_commandGate)
{
USBLog(5, "%s[%p]::ReadV2 - Could not get _commandGate. Returning kIOReturnInternalError(0x%x)", getName(), this, kIOReturnInternalError);
return kIOReturnInternalError;
}
if ( (uintptr_t) completion->action == (uintptr_t) &IOUSBSyncCompletion )
{
isSyncTransfer = true;
if ( _workLoop->onThread() )
{
USBError(1,"IOUSBControllerV2(%s)[%p]::DoIOTransfer sync request on workloop thread. Use async!", getName(), this);
return kIOUSBSyncRequestOnWLThread;
}
}
command = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false);
if ( command == NULL )
{
IncreaseCommandPool();
command = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false);
if ( command == NULL )
{
USBLog(3,"%s[%p]::ReadV2 Could not get a IOUSBCommand",getName(),this);
return kIOReturnNoResources;
}
}
if (reqCount)
{
dmaCommand = command->GetDMACommand();
if (!dmaCommand)
{
USBError(1, "%s[%p]::ReadV2 - no DMA COMMAND", getName(), this);
return kIOReturnNoResources;
}
if (dmaCommand->getMemoryDescriptor())
{
IOMemoryDescriptor *memDesc = (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor();
USBError(1, "%s[%p]::ReadV2 - dma command (%p) already contains memory descriptor (%p) - clearing", getName(), this, dmaCommand, memDesc);
dmaCommand->clearMemoryDescriptor();
}
USBLog(7, "%s[%p]::ReadV2 - setting memory descriptor (%p) into dmaCommand (%p)", getName(), this, buffer, dmaCommand);
err = dmaCommand->setMemoryDescriptor(buffer);
if (err)
{
USBError(1, "%s[%p]::ReadV2 - err(%p) attempting to set the memory descriptor to the dmaCommand", getName(), this, (void*)err);
_freeUSBCommandPool->returnCommand(command);
return err;
}
}
theCompletion.target = completion->target;
theCompletion.action = (IOUSBCompletionAction)completion->action;
theCompletion.parameter = completion->parameter;
command->SetIsSyncTransfer(isSyncTransfer);
command->SetUseTimeStamp(true);
command->SetSelector(READ);
command->SetRequest(0); command->SetAddress(address);
command->SetEndpoint(endpoint->number);
command->SetStreamID(0);
command->SetDirection(kUSBIn);
command->SetType(endpoint->transferType);
command->SetBuffer(buffer);
command->SetReqCount(reqCount);
command->SetClientCompletion(theCompletion);
command->SetNoDataTimeout(noDataTimeout);
command->SetCompletionTimeout(completionTimeout);
command->SetMultiTransferTransaction(false);
command->SetFinalTransferInTransaction(false);
for (i=0; i < 10; i++)
command->SetUIMScratch(i, 0);
nullCompletion.target = (void *) NULL;
nullCompletion.action = (IOUSBCompletionAction) NULL;
nullCompletion.parameter = (void *) NULL;
command->SetDisjointCompletion(nullCompletion);
err = CheckForDisjointDescriptor(command, endpoint->maxPacketSize);
if (kIOReturnSuccess == err)
{
err = _commandGate->runAction(DoIOTransfer, command);
if ( isSyncTransfer || (kIOReturnSuccess != err) )
{
IODMACommand *dmaCommand = command->GetDMACommand();
IOMemoryDescriptor *memDesc = dmaCommand ? (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor() : NULL;
nullCompletion = command->GetDisjointCompletion();
if (nullCompletion.action)
{
USBLog(1, "%s[%p]::ReadV2 - SYNC xfer or immediate error with Disjoint Completion", getName(), this);
USBTrace( kUSBTController, kTPControllerReadV2, (uintptr_t)this, err, 0, 1 );
}
if (memDesc)
{
USBLog(7, "%s[%p]::ReadV2 - SYNC xfer or immediate error - clearing memDesc (%p) from dmaCommand (%p)", getName(), this, memDesc, dmaCommand);
dmaCommand->clearMemoryDescriptor();
}
_freeUSBCommandPool->returnCommand(command);
}
}
else
{
IODMACommand *dmaCommand = command->GetDMACommand();
IOMemoryDescriptor *memDesc = dmaCommand ? (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor() : NULL;
if (memDesc)
{
USBLog(7, "%s[%p]::ReadV2 - CheckForDisjointDescriptor error (%p) - clearing memDesc (%p) from dmaCommand (%p)", getName(), this, (void*)err, memDesc, dmaCommand);
dmaCommand->clearMemoryDescriptor();
}
_freeUSBCommandPool->returnCommand(command);
}
return err;
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 8);
IOReturn
IOUSBControllerV2::UIMCreateIsochEndpoint(short functionAddress, short endpointNumber, UInt32 maxPacketSize, UInt8 direction, USBDeviceAddress highSpeedHub, int highSpeedPort, UInt8 interval)
{
#pragma unused (interval)
return UIMCreateIsochEndpoint(functionAddress, endpointNumber, maxPacketSize, direction, highSpeedHub, highSpeedPort);
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 9);
IOUSBControllerIsochEndpoint*
IOUSBControllerV2::AllocateIsochEP()
{
USBError(1, "IOUSBControllerV2[%p]::AllocateIsochEP - should be overriden in a subclass", this);
return NULL;
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 10);
IOReturn
IOUSBControllerV2::DeallocateIsochEP(IOUSBControllerIsochEndpoint* pEP)
{
USBLog(4, "%s[%p]::DeallocateIsochEP (%p)",getName(), this, pEP);
pEP->nextEP = _freeIsochEPList;
_freeIsochEPList = pEP;
return kIOReturnSuccess;
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 11);
IOUSBControllerIsochEndpoint*
IOUSBControllerV2::FindIsochronousEndpoint(short functionAddress,
short endpointNumber,
short direction,
IOUSBControllerIsochEndpoint **ppEPBack)
{
IOUSBControllerIsochEndpoint *pEP, *pBack;
pEP = _isochEPList;
pBack = NULL;
while (pEP)
{
if ((pEP->functionAddress == functionAddress)
&& (pEP->endpointNumber == endpointNumber)
&& (pEP->direction == direction))
break;
pBack = pEP;
pEP = pEP->nextEP;
}
if (pEP && ppEPBack)
*ppEPBack = pBack;
return pEP;
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 12);
IOUSBControllerIsochEndpoint*
IOUSBControllerV2::CreateIsochronousEndpoint(short functionAddress,
short endpointNumber,
short direction)
{
IOUSBControllerIsochEndpoint* pEP;
USBLog(4, "+%s[%p]::CreateIsochronousEndpoint (%d:%d:%d)", getName(), this, functionAddress, endpointNumber, direction);
pEP = _freeIsochEPList;
if (!pEP)
{
pEP = AllocateIsochEP();
USBLog(4, "%s[%p]::CreateIsochronousEndpoint called AllocateIsochEP (%p)",getName(), this, pEP);
}
if (pEP)
{
_freeIsochEPList = pEP->nextEP; pEP->init(); pEP->nextEP = _isochEPList;
_isochEPList = pEP;
pEP->functionAddress = functionAddress;
pEP->endpointNumber = endpointNumber;
pEP->direction = direction;
}
return pEP;
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 13);
void
IOUSBControllerV2::PutTDonToDoList(IOUSBControllerIsochEndpoint* pED, IOUSBControllerIsochListElement *pTD)
{
USBLog(7, "AppleUSBEHCI[%p]::PutTDonToDoList - pED (%p) pTD (%p) frameNumber(%qx)", this, pED, pTD, pTD->_frameNumber);
if (pED->toDoList == NULL)
{
pED->toDoList = pTD;
}
else
{
pED->toDoEnd->_logicalNext = pTD;
}
pED->toDoEnd = pTD;
pED->onToDoList++;
pED->activeTDs++;
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 14);
IOUSBControllerIsochListElement *
IOUSBControllerV2::GetTDfromToDoList(IOUSBControllerIsochEndpoint* pED)
{
IOUSBControllerIsochListElement *pTD;
pTD = pED->toDoList;
if (pTD)
{
if (pTD == pED->toDoEnd)
pED->toDoList = pED->toDoEnd = NULL;
else
pED->toDoList = OSDynamicCast(IOUSBControllerIsochListElement, pTD->_logicalNext);
pED->onToDoList--;
}
return pTD;
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 15);
void
IOUSBControllerV2::PutTDonDoneQueue(IOUSBControllerIsochEndpoint* pED, IOUSBControllerIsochListElement *pTD, bool checkDeferred)
{
IOUSBControllerIsochListElement *deferredTD;
USBTrace_Start( kUSBTController, kTPControllerPutTDOnDoneQueue, (uintptr_t)this, (uintptr_t)pED, (uintptr_t)pTD, checkDeferred );
if ((pED->doneQueue != NULL) && (pED->doneEnd == NULL))
{
IOUSBControllerIsochListElement *lastTD;
lastTD = pED->doneQueue;
while (lastTD->_logicalNext != NULL)
lastTD = (IOUSBControllerIsochListElement*)lastTD->_logicalNext;
pED->doneEnd = lastTD;
}
if (checkDeferred)
{
while (pED->deferredQueue && (pED->deferredQueue->_frameNumber < pTD->_frameNumber))
{
deferredTD = GetTDfromDeferredQueue(pED);
USBTrace( kUSBTController, kTPControllerPutTDOnDoneQueue, (uintptr_t)this, (uintptr_t)pED, (uintptr_t)deferredTD, 0 );
PutTDonDoneQueue(pED, deferredTD, false);
}
}
if (pED->doneQueue == NULL)
{
pED->doneQueue = pTD;
}
else
{
pED->doneEnd->_logicalNext = pTD;
}
pED->doneEnd = pTD;
pED->onDoneQueue++;
if (checkDeferred && (pED->scheduledTDs == 0) && !pED->toDoList)
{
deferredTD = GetTDfromDeferredQueue(pED);
while (deferredTD)
{
PutTDonDoneQueue(pED, deferredTD, false);
deferredTD = GetTDfromDeferredQueue(pED);
}
}
USBTrace_End( kUSBTController, kTPControllerPutTDOnDoneQueue, (uintptr_t)this, (uintptr_t)pED, (uintptr_t)pTD, checkDeferred );
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 16);
IOUSBControllerIsochListElement *
IOUSBControllerV2::GetTDfromDoneQueue(IOUSBControllerIsochEndpoint* pED)
{
IOUSBControllerIsochListElement *pTD;
pTD = pED->doneQueue;
if (pTD)
{
if (pTD == pED->doneEnd)
pED->doneQueue = pED->doneEnd = NULL;
else
pED->doneQueue = OSDynamicCast(IOUSBControllerIsochListElement, pTD->_logicalNext);
pED->onDoneQueue--;
pED->activeTDs--;
}
else
{
pTD = GetTDfromDeferredQueue(pED);
}
return pTD;
}
IOReturn
IOUSBControllerV2::GatedGetTDfromDoneQueue(OSObject *target, void *arg0, void *arg1, void*, void*)
{
IOUSBControllerV2 *me = (IOUSBControllerV2 *)target;
IOUSBControllerIsochEndpoint *pED = (IOUSBControllerIsochEndpoint*)arg0;
IOUSBControllerIsochListElement *pTD;
if (!me || !pED)
return kIOReturnInternalError;
pTD = me->GetTDfromDoneQueue(pED);
*(IOUSBControllerIsochListElement**)arg1 = pTD;
return kIOReturnSuccess;
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 17);
void
IOUSBControllerV2::PutTDonDeferredQueue(IOUSBControllerIsochEndpoint* pED, IOUSBControllerIsochListElement *pTD)
{
if (pED->deferredQueue == NULL)
{
pED->deferredQueue = pTD;
}
else
{
pED->deferredEnd->_logicalNext = pTD;
}
pED->deferredEnd = pTD;
pED->deferredTDs++;
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 18);
IOUSBControllerIsochListElement *
IOUSBControllerV2::GetTDfromDeferredQueue(IOUSBControllerIsochEndpoint* pED)
{
IOUSBControllerIsochListElement *pTD;
pTD = pED->deferredQueue;
if (pTD)
{
if (pTD == pED->deferredEnd)
pED->deferredQueue = pED->deferredEnd = NULL;
else
pED->deferredQueue = OSDynamicCast(IOUSBControllerIsochListElement, pTD->_logicalNext);
pED->deferredTDs--;
}
USBLog(7, "AppleUSBEHCI[%p]::GetTDfromDeferredQueue(%p) returning %p", this, pED, pTD);
return pTD;
}
void
IOUSBControllerV2::ReturnIsochDoneQueueEntry(OSObject *target, thread_call_param_t endpointPtr)
{
IOUSBControllerV2 * me = OSDynamicCast(IOUSBControllerV2, target);
IOUSBControllerIsochEndpoint* pEP = (IOUSBControllerIsochEndpoint*) endpointPtr;
if (!me || !pEP)
return;
me->retain();
me->ReturnIsochDoneQueue(pEP);
me->release();
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 19);
void
IOUSBControllerV2::ReturnIsochDoneQueue(IOUSBControllerIsochEndpoint* pEP)
{
IOUSBControllerIsochListElement *pTD = NULL;
IOUSBIsocFrame *pFrames = NULL;
IOUSBIsocCompletionAction pHandler;
uint32_t busFunctEP;
USBLog(7, "IOUSBControllerV2[%p]::ReturnIsocDoneQueue (%p)", this, pEP);
_commandGate->runAction(GatedGetTDfromDoneQueue, pEP, &pTD);
USBTrace_Start( kUSBTController, kTPControllerReturnIsochDoneQueue, (uintptr_t)this, (uintptr_t)pEP, (uintptr_t)pTD, 0 );
if (pTD)
{
pFrames = pTD->_pFrames;
}
else
{
USBLog(7, "IOUSBControllerV2[%p]::ReturnIsocDoneQueue - no TDs to return", this);
}
while(pTD)
{
USBLog(7, "IOUSBControllerV2[%p]::ReturnIsocDoneQueue: TD %p", this, pTD);
if ( pTD->_completion.action != NULL)
{
busFunctEP = ((_busNumber << 16 ) | ( pEP->functionAddress << 8) | (pEP->endpointNumber) );
pHandler = pTD->_completion.action;
pTD->_completion.action = NULL;
if (pEP->accumulatedStatus == kIOUSBBufferUnderrunErr)
{
USBLog(1, "IOUSBControllerV2[%p]::ReturnIsocDoneQueue - kIOReturnBufferUnderrunErr (PCI issue perhaps) Bus: %x, Address: %d, Endpoint: %d", this, (uint32_t)_busNumber, pEP->functionAddress, pEP->endpointNumber);
USBTrace( kUSBTController, kTPControllerReturnIsochDoneQueue, (uint32_t)_busNumber, pEP->functionAddress, pEP->endpointNumber, 1);
}
if (pEP->accumulatedStatus == kIOUSBBufferOverrunErr)
{
USBLog(1, "IOUSBControllerV2[%p]::ReturnIsocDoneQueue - kIOReturnBufferOverrunErr (PCI issue perhaps) Bus: %x, Address: %d, Endpoint: %d", this, (uint32_t)_busNumber, pEP->functionAddress, pEP->endpointNumber);
USBTrace( kUSBTController, kTPControllerReturnIsochDoneQueue, (uint32_t)_busNumber, pEP->functionAddress, pEP->endpointNumber, 2);
}
if ((pEP->accumulatedStatus == kIOReturnOverrun) && (pEP->direction == kUSBIn))
{
USBLog(1, "IOUSBControllerV2[%p]::ReturnIsocDoneQueue - kIOReturnOverrun on IN - device babbling? Bus: %x, Address: %d, Endpoint: %d", this, (uint32_t)_busNumber, pEP->functionAddress, pEP->endpointNumber);
USBTrace( kUSBTController, kTPControllerReturnIsochDoneQueue, (uint32_t)_busNumber, pEP->functionAddress, pEP->endpointNumber, 3);
}
USBLog(7, "IOUSBControllerV2[%p]::ReturnIsocDoneQueue- TD (%p) calling handler[%p](target: %p, comp.param: %p, status: %p (%s), pFrames: %p) Bus: %x, Address: %d, Endpoint: %d", this, pTD,
pHandler, pTD->_completion.target, pTD->_completion.parameter, (void*)pEP->accumulatedStatus, USBStringFromReturn(pEP->accumulatedStatus), pFrames, (uint32_t)_busNumber, pEP->functionAddress, pEP->endpointNumber);
USBTrace( kUSBTController, kTPControllerReturnIsochDoneQueue, (uint32_t)busFunctEP, (uintptr_t)pHandler, (uint32_t)pEP->accumulatedStatus, 5);
(*pHandler) (pTD->_completion.target, pTD->_completion.parameter, pEP->accumulatedStatus, pFrames);
_activeIsochTransfers--;
if ( _activeIsochTransfers < 0 )
{
USBLog(1, "IOUSBControllerV2[%p]::ReturnIsocDoneQueue - _activeIsochTransfers went negative (%d). We lost one somewhere Bus: %x, Address: %d, Endpoint: %d", this, (uint32_t)_activeIsochTransfers, (uint32_t)_busNumber, pEP->functionAddress, pEP->endpointNumber);
USBTrace( kUSBTController, kTPControllerReturnIsochDoneQueue, (uint32_t)_busNumber, pEP->functionAddress, pEP->endpointNumber, 4);
}
else if (!_activeIsochTransfers && (_expansionData->_isochMaxBusStall != 0))
{
requireMaxBusStall(0); if (metaCast("AppleUSBUHCI"))
requireMaxInterruptDelay(0);
}
if (pEP->accumulatedStatus != kIOReturnAborted)
{
if (pEP->accumulatedStatus != kIOReturnSuccess && (pEP->accumulatedStatus != kIOReturnUnderrun) )
{
USBLog(6, "IOUSBControllerV2[%p]::ReturnIsocDoneQueue - resetting status from 0x%x (%s) Bus: %x, Address: %d, Endpoint: %d", this, pEP->accumulatedStatus, USBStringFromReturn(pEP->accumulatedStatus), (uint32_t)_busNumber, pEP->functionAddress, pEP->endpointNumber);
}
pEP->accumulatedStatus = kIOReturnSuccess;
}
pTD->Deallocate(this);
pTD = NULL;
_commandGate->runAction(GatedGetTDfromDoneQueue, pEP, &pTD);
if (pTD)
pFrames = pTD->_pFrames;
}
else
{
pTD->Deallocate(this);
pTD = NULL;
_commandGate->runAction(GatedGetTDfromDoneQueue, pEP, &pTD);
}
}
USBTrace_End( kUSBTController, kTPControllerReturnIsochDoneQueue, (uintptr_t)this, 0, 0, 0);
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 20);
IODMACommand*
IOUSBControllerV2::GetNewDMACommand()
{
return IODMACommand::withSpecification(kIODMACommandOutputHost64, 32, 0);
}
#define defaultOptionBits 0 // by default we don't need contiguous memory
#define defaultPhysicalMask 0x00000000FFFFF000ULL // by default we require memory 4K aligned memory below 4GB
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 21);
IOReturn
IOUSBControllerV2::GetLowLatencyOptionsAndPhysicalMask(IOOptionBits *pOptionBits, mach_vm_address_t *pPhysicalMask)
{
*pOptionBits = defaultOptionBits;
*pPhysicalMask = defaultPhysicalMask;
return kIOReturnSuccess;
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 22);
IOReturn
IOUSBControllerV2::GetFrameNumberWithTime(UInt64* frameNumber, AbsoluteTime *theTime)
{
#pragma unused (frameNumber, theTime)
return kIOReturnUnsupported;
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 23);
IOReturn
IOUSBControllerV2::ReadStream(UInt32 streamID, IOMemoryDescriptor *buffer, USBDeviceAddress address, Endpoint *endpoint, IOUSBCompletion *completion, UInt32 noDataTimeout, UInt32 completionTimeout, IOByteCount reqCount)
{
IOReturn err = kIOReturnSuccess;
IOUSBCommand * command = NULL;
IODMACommand * dmaCommand = NULL;
IOUSBCompletion nullCompletion;
int i;
bool isSyncTransfer = false;
USBLog(7, "%s[%p]::Read - reqCount = %qd", getName(), this, (uint64_t)reqCount);
if ((endpoint->direction != kUSBIn) || !buffer || (buffer->getLength() < reqCount))
{
USBLog(2, "%s[%p]::Read - ep direction is not kUSBIn (%d), No Buffer, or buffer length < reqCount (%qd < %qd). Returning kIOReturnBadArgument(0x%x)", getName(), this, endpoint->direction, (uint64_t)buffer->getLength(), (uint64_t)reqCount, kIOReturnBadArgument);
return kIOReturnBadArgument;
}
if ((endpoint->transferType != kUSBBulk) && (noDataTimeout || completionTimeout))
{
USBLog(2, "%s[%p]::Read - Pipe is NOT kUSBBulk (%d) AND specified a timeout (%d, %d). Returning kIOReturnBadArgument(0x%x)", getName(), this, endpoint->transferType, (uint32_t)noDataTimeout, (uint32_t)completionTimeout, kIOReturnBadArgument);
return kIOReturnBadArgument; }
if (!completion)
{
USBLog(2, "%s[%p]::Read - No Completion routine. Returning kIOReturnNoCompletion(0x%x)", getName(), this, kIOReturnNoCompletion);
return kIOReturnNoCompletion;
}
if (!_commandGate)
{
USBLog(1, "%s[%p]::Read - Could not get _commandGate. Returning kIOReturnInternalError(0x%x)", getName(), this, kIOReturnInternalError);
USBTrace( kUSBTController, kTPControllerRead, (uintptr_t)this, kIOReturnInternalError, 0, 1 );
return kIOReturnInternalError;
}
if ( (uintptr_t) completion->action == (uintptr_t) &IOUSBSyncCompletion )
{
isSyncTransfer = true;
if ( _workLoop->onThread() )
{
USBError(1,"IOUSBController(%s)[%p]::Read sync request on workloop thread. Use async!", getName(), this);
return kIOUSBSyncRequestOnWLThread;
}
}
command = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false);
if ( command == NULL )
{
IncreaseCommandPool();
command = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false);
if ( command == NULL )
{
USBLog(1,"%s[%p]::Read Could not get a IOUSBCommand",getName(),this);
return kIOReturnNoResources;
}
}
if (reqCount)
{
IOMemoryDescriptor *memDesc;
dmaCommand = command->GetDMACommand();
if (!dmaCommand)
{
USBLog(1, "%s[%p]::Read - no DMA COMMAND", getName(), this);
USBTrace( kUSBTController, kTPControllerRead, (uintptr_t)this, kIOReturnNoResources, 0, 2 );
err = kIOReturnNoResources;
}
else
{
memDesc = (IOMemoryDescriptor*)dmaCommand->getMemoryDescriptor();
if (memDesc)
{
USBLog(1, "%s[%p]::Read - dmaCommand (%p) already contains memory descriptor (%p) - clearing", getName(), this, dmaCommand, memDesc);
USBTrace( kUSBTController, kTPControllerRead, (uintptr_t)this, (uintptr_t)dmaCommand, (uintptr_t)memDesc, 3 );
dmaCommand->clearMemoryDescriptor();
}
USBLog(7, "%s[%p]::Read - setting memory descriptor (%p) into dmaCommand (%p)", getName(), this, buffer, dmaCommand);
err = dmaCommand->setMemoryDescriptor(buffer);
if (err)
{
USBLog(1, "%s[%p]::Read - err(%p) attempting to set the memory descriptor to the dmaCommand", getName(), this, (void*)err);
USBTrace( kUSBTController, kTPControllerRead, (uintptr_t)this, err, 0, 5 );
}
}
}
if (!err)
{
command->SetIsSyncTransfer(isSyncTransfer);
command->SetUseTimeStamp(false);
command->SetSelector(READ);
command->SetRequest(0); command->SetAddress(address);
command->SetEndpoint(endpoint->number);
command->SetDirection(kUSBIn);
command->SetType(endpoint->transferType);
command->SetBuffer(buffer);
command->SetReqCount(reqCount);
command->SetClientCompletion(*completion);
command->SetNoDataTimeout(noDataTimeout);
command->SetCompletionTimeout(completionTimeout);
command->SetMultiTransferTransaction(false);
command->SetFinalTransferInTransaction(false);
command->SetStreamID(streamID);
for (i=0; i < 10; i++)
command->SetUIMScratch(i, 0);
nullCompletion.target = (void *) NULL;
nullCompletion.action = (IOUSBCompletionAction) NULL;
nullCompletion.parameter = (void *) NULL;
command->SetDisjointCompletion(nullCompletion);
err = CheckForDisjointDescriptor(command, endpoint->maxPacketSize);
if (!err)
{
err = _commandGate->runAction(DoIOTransfer, command);
}
}
if ( isSyncTransfer || (kIOReturnSuccess != err) )
{
IOMemoryDescriptor *memDesc = dmaCommand ? (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor() : NULL;
if (!isSyncTransfer)
{
USBLog(2, "%s[%p]::Read - General error (%p) - cleaning up - command(%p) dmaCommand(%p)", getName(), this, (void*)err, command, dmaCommand);
}
if (memDesc)
{
USBLog(7, "%s[%p]::Read - sync xfer or err return - clearing memory descriptor (%p) from dmaCommand (%p)", getName(), this, memDesc, dmaCommand);
dmaCommand->clearMemoryDescriptor();
}
nullCompletion = command->GetDisjointCompletion();
if (nullCompletion.action)
{
USBLog(2, "%s[%p]::Read - SYNC xfer or immediate error with Disjoint Completion", getName(), this);
}
_freeUSBCommandPool->returnCommand(command);
}
return err;
}
OSMetaClassDefineReservedUsed(IOUSBControllerV2, 24);
IOReturn
IOUSBControllerV2::WriteStream(UInt32 streamID, IOMemoryDescriptor *buffer, USBDeviceAddress address, Endpoint *endpoint, IOUSBCompletion *completion, UInt32 noDataTimeout, UInt32 completionTimeout, IOByteCount reqCount)
{
IOReturn err = kIOReturnSuccess;
IOUSBCommand * command = NULL;
IODMACommand * dmaCommand = NULL;
IOUSBCompletion nullCompletion;
int i;
bool isSyncTransfer = false;
USBLog(7, "%s[%p]::Write - reqCount = %qd", getName(), this, (uint64_t)reqCount);
if ((endpoint->direction != kUSBOut) || !buffer || (buffer->getLength() < reqCount))
{
USBLog(5, "%s[%p]::Write - ep direction is not kUSBOut (%d), No Buffer, or buffer length < reqCount (%qd < %qd). Returning kIOReturnBadArgument(0x%x)", getName(), this, endpoint->direction, (uint64_t)buffer->getLength(), (uint64_t)reqCount, kIOReturnBadArgument);
return kIOReturnBadArgument;
}
if ((endpoint->transferType != kUSBBulk) && (noDataTimeout || completionTimeout))
{
USBLog(5, "%s[%p]::Write - Pipe is NOT kUSBBulk (%d) AND specified a timeout (%d, %d). Returning kIOReturnBadArgument(0x%x)", getName(), this, endpoint->transferType, (uint32_t)noDataTimeout, (uint32_t)completionTimeout, kIOReturnBadArgument);
return kIOReturnBadArgument; }
if (!_commandGate)
{
USBLog(5, "%s[%p]::Write - Could not get _commandGate. Returning kIOReturnInternalError(0x%x)", getName(), this, kIOReturnInternalError);
return kIOReturnInternalError;
}
if ( (uintptr_t) completion->action == (uintptr_t) &IOUSBSyncCompletion )
{
isSyncTransfer = true;
if ( _workLoop->onThread() )
{
USBError(1,"IOUSBController(%s)[%p]::Write sync request on workloop thread. Use async!", getName(), this);
return kIOUSBSyncRequestOnWLThread;
}
}
command = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false);
if ( command == NULL )
{
IncreaseCommandPool();
command = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false);
if ( command == NULL )
{
USBLog(3,"%s[%p]::Write Could not get a IOUSBCommand",getName(),this);
return kIOReturnNoResources;
}
}
if (reqCount)
{
IOMemoryDescriptor *memDesc;
dmaCommand = command->GetDMACommand();
if (!dmaCommand)
{
USBLog(1, "%s[%p]::Write - no DMA COMMAND", getName(), this);
USBTrace( kUSBTController, kTPControllerWrite, (uintptr_t)this, kIOReturnNoResources, 0, 1 );
err = kIOReturnNoResources;
}
else
{
memDesc = (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor();
if (memDesc)
{
USBLog(1, "%s[%p]::Write - dmaCommand (%p) already contains memory descriptor (%p) - clearing", getName(), this, dmaCommand, memDesc);
USBTrace( kUSBTController, kTPControllerWrite, (uintptr_t)this, (uintptr_t)dmaCommand, (uintptr_t)memDesc, 2 );
dmaCommand->clearMemoryDescriptor();
}
USBLog(7, "%s[%p]::Write - setting memory descriptor (%p) into dmaCommand (%p)", getName(), this, buffer, dmaCommand);
err = dmaCommand->setMemoryDescriptor(buffer);
if (err)
{
USBTrace( kUSBTController, kTPControllerWrite, (uintptr_t)this, err, 0, 4 );
USBLog(1, "%s[%p]::Write - err(%p) attempting to set the memory descriptor to the dmaCommand", getName(), this, (void*)err);
}
}
}
if (!err)
{
command->SetIsSyncTransfer(isSyncTransfer);
command->SetUseTimeStamp(false);
command->SetSelector(WRITE);
command->SetRequest(0); command->SetAddress(address);
command->SetEndpoint(endpoint->number);
command->SetDirection(kUSBOut);
command->SetType(endpoint->transferType);
command->SetBuffer(buffer);
command->SetReqCount(reqCount);
command->SetClientCompletion(*completion);
command->SetNoDataTimeout(noDataTimeout);
command->SetCompletionTimeout(completionTimeout);
command->SetMultiTransferTransaction(false);
command->SetFinalTransferInTransaction(false);
command->SetStreamID(streamID);
for (i=0; i < 10; i++)
command->SetUIMScratch(i, 0);
nullCompletion.target = (void *) NULL;
nullCompletion.action = (IOUSBCompletionAction) NULL;
nullCompletion.parameter = (void *) NULL;
command->SetDisjointCompletion(nullCompletion);
err = CheckForDisjointDescriptor(command, endpoint->maxPacketSize);
if (!err)
{
err = _commandGate->runAction(DoIOTransfer, command);
}
}
if ( isSyncTransfer || (kIOReturnSuccess != err) )
{
IOMemoryDescriptor *memDesc = dmaCommand ? (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor() : NULL;
if (!isSyncTransfer)
{
USBLog(2, "%s[%p]::Write - General error (%p) - cleaning up - command(%p) dmaCommand(%p)", getName(), this, (void*)err, command, dmaCommand);
}
if (memDesc)
{
USBLog(7, "%s[%p]::Write - General error (%p) - clearing memory descriptor (%p) from dmaCommand (%p)", getName(), this, (void*)err, memDesc, dmaCommand);
dmaCommand->clearMemoryDescriptor();
}
nullCompletion = command->GetDisjointCompletion();
if (nullCompletion.action)
{
USBLog(2, "%s[%p]::Write - SYNC xfer or immediate error with Disjoint Completion", getName(), this);
}
_freeUSBCommandPool->returnCommand(command);
}
return err;
}
OSMetaClassDefineReservedUnused(IOUSBControllerV2, 26);
OSMetaClassDefineReservedUnused(IOUSBControllerV2, 27);
OSMetaClassDefineReservedUnused(IOUSBControllerV2, 28);
OSMetaClassDefineReservedUnused(IOUSBControllerV2, 29);