IOUSBController.cpp [plain text]
#include <libkern/OSByteOrder.h>
#include <libkern/c++/OSDictionary.h>
#include <libkern/c++/OSData.h>
#include <IOKit/assert.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/IOCommandGate.h>
#include <IOKit/IOCommandPool.h>
#include <IOKit/IOTimerEventSource.h>
#include <IOKit/usb/IOUSBController.h>
#include <IOKit/usb/IOUSBControllerV2.h>
#include <IOKit/usb/IOUSBControllerV3.h>
#include <IOKit/usb/IOUSBDevice.h>
#include <IOKit/usb/USBSpec.h>
#include <IOKit/usb/IOUSBRootHubDevice.h>
#include <IOKit/usb/IOUSBLog.h>
#include <IOKit/usb/IOUSBWorkLoop.h>
#include <IOKit/pccard/IOPCCard.h>
#define kUSBSetup kUSBNone
#define kAppleCurrentAvailable "AAPL,current-available"
#define kAppleCurrentInSleep "AAPL,current-in-sleep"
#define kAppleCurrentExtra "AAPL,current-extra"
#define kUSBBusID "AAPL,bus-id"
#define super IOUSBBus
#define CONTROLLER_USE_KPRINTF 0
#if CONTROLLER_USE_KPRINTF
#undef USBLog
#undef USBError
void kprintf(const char *format, ...)
__attribute__((format(printf, 1, 2)));
#define USBLog( LEVEL, FORMAT, ARGS... ) if ((LEVEL) <= CONTROLLER_USE_KPRINTF) { kprintf( FORMAT "\n", ## ARGS ) ; }
#define USBError( LEVEL, FORMAT, ARGS... ) { kprintf( FORMAT "\n", ## ARGS ) ; }
#endif
enum {
kSetupSent = 0x01,
kDataSent = 0x02,
kStatusSent = 0x04,
kSetupBack = 0x10,
kDataBack = 0x20,
kStatusBack = 0x40
};
enum {
kSizeOfCommandPool = 50,
kSizeOfIsocCommandPool = 50,
kSizeToIncrementCommandPool = 50,
kSizeToIncrementIsocCommandPool = 50
};
struct IOUSBSyncCompletionTarget
{
IOUSBController * controller; void * flag; };
typedef struct IOUSBSyncCompletionTarget IOUSBSyncCompletionTarget;
#define kUSBSetup kUSBNone
#define kAppleCurrentAvailable "AAPL,current-available"
#define kUSBBusID "AAPL,bus-id"
#define kMaxNumberUSBBusses 256
IOUSBLog * IOUSBController::_log;
const IORegistryPlane * IOUSBController::gIOUSBPlane = 0;
UInt32 IOUSBController::_busCount;
bool IOUSBController::gUsedBusIDs[kMaxNumberUSBBusses];
#define _freeUSBCommandPool _expansionData->freeUSBCommandPool
#define _freeUSBIsocCommandPool _expansionData->freeUSBIsocCommandPool
#define _watchdogUSBTimer _expansionData->watchdogUSBTimer
#define _controllerTerminating _expansionData->_terminating
#define _watchdogTimerActive _expansionData->_watchdogTimerActive
#define _pcCardEjected _expansionData->_pcCardEjected
#define _busNumber _expansionData->_busNumber
#define _currentSizeOfCommandPool _expansionData->_currentSizeOfCommandPool
#define _currentSizeOfIsocCommandPool _expansionData->_currentSizeOfIsocCommandPool
#define _controllerSpeed _expansionData->_controllerSpeed
#define _terminatePCCardThread _expansionData->_terminatePCCardThread
#define _addressPending _expansionData->_addressPending
#define _provider _expansionData->_provider
#define _controllerCanSleep _expansionData->_controllerCanSleep
void
IOUSBSyncCompletion(void * target, void * parameter, IOReturn status, UInt32 bufferSizeRemaining)
{
IOCommandGate * commandGate;
IOUSBController * me;
IOUSBSyncCompletionTarget *syncTarget = (IOUSBSyncCompletionTarget*)target;
if ( !syncTarget )
{
USBError(1,"IOUSBController::IOUSBSyncCompletion syncTarget is NULL");
return;
}
me = syncTarget->controller;
if ( !me )
{
USBError(1,"IOUSBController::IOUSBSyncCompletion controller is NULL");
return;
}
commandGate = me->GetCommandGate();
if ( !commandGate )
{
USBError(1,"IOUSBController::IOUSBSyncCompletion commandGate is NULL");
return;
}
if(parameter != NULL) {
*(UInt32 *)parameter -= bufferSizeRemaining;
}
commandGate->commandWakeup(syncTarget->flag, true);
}
void
IOUSBSyncIsoCompletion(void * target, void * parameter, IOReturn status, IOUSBIsocFrame * pFrames)
{
IOCommandGate * commandGate;
IOUSBController * me;
IOUSBSyncCompletionTarget *syncTarget = (IOUSBSyncCompletionTarget*)target;
if ( !syncTarget )
{
USBError(1,"IOUSBController::IOUSBSyncIsoCompletion syncTarget is NULL");
return;
}
me = syncTarget->controller;
if ( !me )
{
USBError(1,"IOUSBController::IOUSBSyncIsoCompletion controller is NULL");
return;
}
commandGate = me->GetCommandGate();
if ( !commandGate )
{
USBError(1,"IOUSBController::IOUSBSyncIsoCompletion commandGate is NULL");
return;
}
commandGate->commandWakeup(syncTarget->flag, true);
}
OSDefineMetaClass( IOUSBController, IOUSBBus )
OSDefineAbstractStructors(IOUSBController, IOUSBBus)
bool
IOUSBController::init(OSDictionary * propTable)
{
if (!super::init(propTable)) return false;
if (!_expansionData)
{
_expansionData = (ExpansionData *)IOMalloc(sizeof(ExpansionData));
if (!_expansionData)
return false;
bzero(_expansionData, sizeof(ExpansionData));
}
_watchdogTimerActive = false;
_pcCardEjected = false;
_controllerSpeed = kUSBDeviceSpeedFull;
return (true);
}
bool
IOUSBController::start( IOService * provider )
{
int i;
IOReturn err = kIOReturnSuccess;
bool commandGateAdded = false;
IOUSBControllerV2 *me2 = OSDynamicCast(IOUSBControllerV2, this);
IOUSBControllerV3 *me3 = OSDynamicCast(IOUSBControllerV3, this);
if( !super::start(provider))
return false;
_provider = provider;
if (!_provider || !_provider->open(this))
{
return false;
}
if (!_log)
_log = IOUSBLog::usblog();
do {
_workLoop = IOUSBWorkLoop::workLoop(provider->getLocation());
if (!_workLoop)
{
USBError(1,"%s: unable to create workloop", getName());
break;
}
_commandGate = IOCommandGate:: commandGate(this, NULL);
if (!_commandGate)
{
USBError(1,"%s: unable to create command gate", getName());
break;
}
if (_workLoop->addEventSource(_commandGate) != kIOReturnSuccess)
{
USBError(1,"%s: unable to add command gate", getName());
break;
}
commandGateAdded = true;
_freeUSBCommandPool = IOCommandPool::withWorkLoop(_workLoop);
if (!_freeUSBCommandPool)
{
USBError(1,"%s: unable to create free command pool", getName());
break;
}
_freeUSBIsocCommandPool = IOCommandPool::withWorkLoop(_workLoop);
if (!_freeUSBIsocCommandPool)
{
USBError(1,"%s: unable to create free command pool", getName());
break;
}
_watchdogUSBTimer = IOTimerEventSource::timerEventSource(this, WatchdogTimer);
if (!_watchdogUSBTimer)
{
USBError(1, "IOUSBController::start - no watchdog timer");
break;
}
if (_workLoop->addEventSource(_watchdogUSBTimer) != kIOReturnSuccess)
{
USBError(1, "IOUSBController::start - unable to add watchdog timer event source");
break;
}
_terminatePCCardThread = thread_call_allocate((thread_call_func_t)TerminatePCCard, (thread_call_param_t)this);
if ( !_terminatePCCardThread )
{
USBError(1, "IOUSBController::start could not allocate thread functions. Aborting start");
}
for (i = 1; i < kUSBMaxDevices; i++)
{
_addressPending[i] = false;
}
PMinit();
_provider->joinPMtree(this);
if (UIMInitialize(_provider) != kIOReturnSuccess)
{
USBError(1,"%s: unable to initialize UIM", getName());
break;
}
_workLoop->enableAllInterrupts();
for (i=0; i < kSizeOfCommandPool; i++)
{
IOUSBCommand *command = IOUSBCommand::NewCommand();
if (command)
{
if (me2)
command->SetDMACommand(me2->GetNewDMACommand());
_freeUSBCommandPool->returnCommand(command);
}
}
_currentSizeOfCommandPool = kSizeOfCommandPool;
for (i=0; i < kSizeOfIsocCommandPool; i++)
{
IOUSBIsocCommand *icommand = IOUSBIsocCommand::NewCommand();
if (icommand)
{
if (me2)
icommand->SetDMACommand(me2->GetNewDMACommand());
_freeUSBIsocCommandPool->returnCommand(icommand);
}
}
_currentSizeOfIsocCommandPool = kSizeOfIsocCommandPool;
_devZeroLock = false;
if (!gIOUSBPlane)
{
gIOUSBPlane = IORegistryEntry::makePlane(kIOUSBPlane);
if ( gIOUSBPlane == 0 )
USBError(1,"IOUSBController::start unable to create IOUSB plane");
}
if (!me3)
{
USBLog(2, "%s[%p]::start - calling CreateRootHubDevice for non V3 controller", getName(), this);
err = CreateRootHubDevice( _provider, &_rootHubDevice );
USBLog(2, "%s[%p]::start - called CreateRootHubDevice - return(%p)", getName(), this, (void*)err);
if ( err != kIOReturnSuccess )
break;
makeUsable();
_rootHubDevice->registerService();
}
_watchdogTimerActive = true;
_watchdogUSBTimer->setTimeoutMS(kUSBWatchdogTimeoutMS);
return true;
} while (false);
if (_commandGate)
{
if (commandGateAdded && _workLoop )
_workLoop->removeEventSource( _commandGate );
_commandGate->release();
_commandGate = NULL;
}
if (_workLoop)
{
_workLoop->release();
_workLoop = NULL;
}
_provider->close(this);
return( false );
}
IOWorkLoop *
IOUSBController::getWorkLoop() const
{
return _workLoop;
}
IOReturn
IOUSBController::CreateDevice( IOUSBDevice *newDevice,
USBDeviceAddress deviceAddress,
UInt8 maxPacketSize,
UInt8 speed,
UInt32 powerAvailable)
{
USBLog(5,"%s[%p]::CreateDevice: addr=%d, speed=%s, power=%d", getName(), this,
deviceAddress, (speed == kUSBDeviceSpeedLow) ? "low" : ((speed == kUSBDeviceSpeedFull) ? "full" : "high"), (int)powerAvailable*2);
_addressPending[deviceAddress] = true; do
{
if (!newDevice->init(deviceAddress, powerAvailable, speed, maxPacketSize))
{
USBLog(3,"%s[%p]::CreateDevice device->init failed", getName(), this);
break;
}
if (!newDevice->attach(this))
{
USBLog(3,"%s[%p]::CreateDevice device->attach failed", getName(), this);
break;
}
if (!newDevice->start(this))
{
USBLog(3,"%s[%p]::CreateDevice device->start failed", getName(), this);
newDevice->detach(this);
break;
}
USBLog(7, "%s[%p]::CreateDevice - releasing pend on address %d", getName(), this, deviceAddress);
_addressPending[deviceAddress] = false;
return(kIOReturnSuccess);
} while (false);
_addressPending[deviceAddress] = false;
return(kIOReturnNoMemory);
}
IOReturn
IOUSBController::DeviceRequest(IOUSBDevRequest *request, IOUSBCompletion *completion, USBDeviceAddress address, UInt8 ep)
{
return DeviceRequest(request, completion, address, ep, ep ? 0 : kUSBDefaultControlNoDataTimeoutMS, ep ? 0 : kUSBDefaultControlCompletionTimeoutMS);
}
IOReturn
IOUSBController::DeviceRequest(IOUSBDevRequestDesc *request, IOUSBCompletion * completion, USBDeviceAddress address, UInt8 ep)
{
return DeviceRequest(request, completion, address, ep, ep ? 0 : kUSBDefaultControlNoDataTimeoutMS, ep ? 0 : kUSBDefaultControlCompletionTimeoutMS);
}
USBDeviceAddress
IOUSBController::GetNewAddress(void)
{
int i;
bool assigned[kUSBMaxDevices];
OSIterator * clients;
bzero(assigned, sizeof(assigned));
clients = getClientIterator();
if (clients)
{
OSObject *next;
while( (next = clients->getNextObject()) )
{
IOUSBDevice *testIt = OSDynamicCast(IOUSBDevice, next);
if (testIt)
{
assigned[testIt->GetAddress()] = true;
}
}
clients->release();
}
for (i = 1; i < kUSBMaxDevices; i++)
{
if ( _addressPending[i] == true )
{
assigned[i] = true;
}
}
for (i = 1; i < kUSBMaxDevices; i++)
{
if (!assigned[i])
{
return i;
}
}
USBLog(2, "%s[%p]::GetNewAddress - ran out of new addresses!", getName(), this);
return (0); }
IOReturn
IOUSBController::ControlTransaction(IOUSBCommand *command)
{
IOUSBDevRequest *request = command->GetRequest();
UInt8 direction = (request->bmRequestType >> kUSBRqDirnShift) & kUSBRqDirnMask;
UInt8 endpoint = command->GetEndpoint();
IOUSBCommand *bufferCommand = command->GetBufferUSBCommand();
UInt16 wLength = bufferCommand ? bufferCommand->GetReqCount() : 0;
IOReturn err = kIOReturnSuccess;
IOUSBCompletion completion;
IOMemoryDescriptor *requestMemoryDescriptor = NULL;
do
{
completion = command->GetUSLCompletion();
if(completion.action == NULL)
{
completion.target = (void *)this;
completion.action = (IOUSBCompletionAction) &ControlPacketHandler;
completion.parameter = (void *)command;
}
else
{
USBLog(7,"%s[%p]::ControlTransaction new version, using V2 completion", getName(), this);
}
if (wLength && (request->pData != NULL) && (command->GetSelector() != DEVICE_REQUEST_BUFFERCOMMAND))
{
USBError(1, "%s[%p]::ControlTransaction - have a wLength but not a BUFFERCOMMAND", getName(), this);
err = kIOReturnBadArgument;
break;
}
command->SetDataRemaining(wLength);
command->SetStage(kSetupSent);
command->SetUSLCompletion(completion);
command->SetStatus(kIOReturnSuccess);
requestMemoryDescriptor = command->GetRequestMemoryDescriptor();
command->SetMultiTransferTransaction(true);
command->SetFinalTransferInTransaction(false);
USBLog(7,"%s[%p]::ControlTransaction: Queueing Setup TD (dir=%d) packet=0x%08lx%08lx", getName(), this, direction, *(UInt32*)request, *((UInt32*)request+1));
err = UIMCreateControlTransfer(command->GetAddress(), endpoint, command, requestMemoryDescriptor, true, command->GetReqCount(), kUSBSetup); if (err)
{
USBError(1,"ControlTransaction: control packet 1 error 0x%x", err);
break;
}
if (wLength && (request->pData != NULL))
{
USBLog(7, "%s[%p]::ControlTransaction: Queueing Data TD (dir=%d, wLength=0x%x, pData=%lx)", getName(), this, direction, wLength, (UInt32)request->pData);
command->SetStage(command->GetStage() | kDataSent);
err = UIMCreateControlTransfer(command->GetAddress(), endpoint, bufferCommand, bufferCommand->GetBufferMemoryDescriptor(), true, wLength, direction); if (err)
{
char theString[255]="";
snprintf(theString, sizeof(theString), "ControlTransaction: control packet 2 error 0x%x", err);
break;
}
}
direction = kUSBOut + kUSBIn - direction;
USBLog(7,"%s[%p]::ControlTransaction: Queueing Status TD (dir=%d)", getName(), this, direction);
command->SetStage(command->GetStage() | kStatusSent);
command->SetFinalTransferInTransaction(true);
err = UIMCreateControlTransfer(command->GetAddress(), endpoint, command, (IOMemoryDescriptor *)NULL, true, 0, direction); if (err)
{
char theString[255]="";
snprintf(theString, sizeof(theString), "%s[%p]::ControlTransaction: control packet 3 error 0x%x", getName(), this, err);
break;
}
} while(false);
return(err);
}
void
IOUSBController::ControlPacketHandler( OSObject * target,
void * parameter,
IOReturn status,
UInt32 bufferSizeRemaining)
{
IOUSBCommand *command = (IOUSBCommand *)parameter;
IOUSBDevRequest *request;
UInt8 sent, back, todo;
Boolean in = false;
IOUSBController *me = (IOUSBController *)target;
USBLog(7,"%s[%p]::ControlPacketHandler lParam=%lx status=0x%x bufferSizeRemaining=0x%x", me->getName(), me, (UInt32)parameter, status, (unsigned int)bufferSizeRemaining);
if (command == 0)
return;
request = command->GetRequest();
request->wValue = USBToHostWord(request->wValue);
request->wIndex = USBToHostWord(request->wIndex);
request->wLength = USBToHostWord(request->wLength);
sent = (command->GetStage() & 0x0f) << 4;
back = command->GetStage() & 0xf0;
todo = sent ^ back;
if ( status != kIOReturnSuccess )
{
USBLog(5, "%s[%p]::ControlPacketHandler(FN: %d, EP:%d): Error: 0x%x, stage: 0x%x, todo: 0x%x", me->getName(), me, command->GetAddress(), command->GetEndpoint(), status, command->GetStage(), todo );
}
if((todo & kSetupBack) != 0)
command->SetStage(command->GetStage() | kSetupBack);
else if((todo & kDataBack) != 0)
{
command->SetStage(command->GetStage() | kDataBack);
command->SetDataRemaining(bufferSizeRemaining);
in = (((request->bmRequestType >> kUSBRqDirnShift) & kUSBRqDirnMask) == kUSBIn);
}
else if((todo & kStatusBack) != 0)
{
command->SetStage(command->GetStage() | kStatusBack);
in = (((request->bmRequestType >> kUSBRqDirnShift) & kUSBRqDirnMask) != kUSBIn);
}
else
{
USBLog(5,"%s[%p]::ControlPacketHandler: Spare transactions, This seems to be harmless", me->getName(), me);
}
back = command->GetStage() & 0xf0;
todo = sent ^ back;
if (status != kIOReturnSuccess)
{
if ( (status != kIOUSBTransactionReturned) && (status != kIOReturnAborted) && ( status != kIOUSBTransactionTimeout) )
{
USBDeviceAddress addr = command->GetAddress();
UInt8 endpt = command->GetEndpoint();
IOUSBControllerV2 *v2Bus;
command->SetStatus(status);
if (status == kIOUSBHighSpeedSplitError)
{
USBLog(1,"%s[%p]::ControlPacketHandler - kIOUSBHighSpeedSplitError", me->getName(), me);
v2Bus = OSDynamicCast(IOUSBControllerV2, me);
if (v2Bus)
{
USBLog(1,"%s[%p]::ControlPacketHandler - calling clear TT", me->getName(), me);
v2Bus->ClearTT(addr, endpt, in);
}
status = kIOReturnNotResponding;
}
USBLog(3,"%s[%p]:ControlPacketHandler error 0x%x occured on endpoint (%d). todo = 0x%x (Clearing stall)", me->getName(), me, status, endpt, todo);
me->UIMClearEndpointStall(addr, endpt, kUSBAnyDirn);
}
else if (command->GetStatus() == kIOReturnSuccess)
{
if ( status == kIOUSBTransactionReturned )
command->SetStatus(kIOReturnAborted);
else
command->SetStatus(status);
}
}
if (todo == 0)
{
USBLog(7,"%s[%p]::ControlPacketHandler: transaction complete status=0x%x", me->getName(), me, status);
IOUSBCommand *bufferCommand = command->GetBufferUSBCommand();
if (bufferCommand && bufferCommand->GetBufferMemoryDescriptor())
{
IODMACommand *dmaCommand = bufferCommand->GetDMACommand();
IOMemoryDescriptor *memDesc = dmaCommand ? (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor() : NULL;
if (dmaCommand && memDesc)
{
USBLog(7, "%s[%p]::ControlPacketHandler - clearing memory descriptor (%p) from buffer dmaCommand (%p)", me->getName(), me, dmaCommand->getMemoryDescriptor(), dmaCommand);
dmaCommand->clearMemoryDescriptor();
}
if (bufferCommand->GetSelector() == DEVICE_REQUEST)
{
bufferCommand->GetBufferMemoryDescriptor()->complete();
bufferCommand->GetBufferMemoryDescriptor()->release();
}
bufferCommand->SetBufferMemoryDescriptor(NULL);
}
if (command->GetRequestMemoryDescriptor())
{
IODMACommand *dmaCommand = command->GetDMACommand();
IOMemoryDescriptor *memDesc = dmaCommand ? (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor() : NULL;
if (dmaCommand && memDesc)
{
USBLog(7, "%s[%p]::ControlPacketHandler - clearing memory descriptor (%p) from dmaCommand (%p)", me->getName(), me, dmaCommand->getMemoryDescriptor(), dmaCommand);
dmaCommand->clearMemoryDescriptor();
}
command->GetRequestMemoryDescriptor()->release();
command->SetRequestMemoryDescriptor(NULL);
}
if (command->GetBufferMemoryDescriptor())
{
USBError(1, "%s[%p]::ControlPacketHandler - unexpected command BufferMemoryDescriptor(%p)", me->getName(), me, command->GetBufferMemoryDescriptor());
command->GetBufferMemoryDescriptor()->release();
command->SetBufferMemoryDescriptor(NULL);
}
if ( status == kIOReturnUnderrun )
command->SetStatus(kIOReturnSuccess);
if (command->GetStatus() != kIOReturnSuccess)
{
USBLog(2, "%s[%p]::ControlPacketHandler, returning status of %x", me->getName(), me, command->GetStatus());
}
me->Complete(command->GetClientCompletion(), command->GetStatus(), command->GetDataRemaining());
if ( !command->GetIsSyncTransfer() )
{
command->SetBufferUSBCommand(NULL);
me->_freeUSBCommandPool->returnCommand(command);
if (bufferCommand)
me->_freeUSBCommandPool->returnCommand(bufferCommand);
}
}
else
{
USBLog(7,"%s[%p]::ControlPacketHandler: still more to come: todo=0x%x", me->getName(), me, todo);
}
}
IOReturn
IOUSBController::InterruptTransaction(IOUSBCommand *command)
{
IOReturn err = kIOReturnSuccess;
IOUSBCompletion completion;
completion.target = (void *)this;
completion.action = (IOUSBCompletionAction) &IOUSBController::InterruptPacketHandler;
completion.parameter = (void *)command;
command->SetUSLCompletion(completion);
command->SetBufferRounding(true);
err = UIMCreateInterruptTransfer(command);
return(err);
}
void
IOUSBController::InterruptPacketHandler(OSObject * target, void * parameter, IOReturn status, UInt32 bufferSizeRemaining)
{
IOUSBCommand *command = (IOUSBCommand *)parameter;
IODMACommand *dmaCommand = command->GetDMACommand();
IOMemoryDescriptor *memDesc = dmaCommand ? (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor() : NULL;
IOUSBController *me = (IOUSBController *)target;
AbsoluteTime timeStart, timeNow;
UInt64 timeElapsed;
if (command == 0)
return;
USBLog(7,"%s[%p]::InterruptPacketHandler: addr %d:%d(%s) complete status=0x%x bufferSizeRemaining = %d (%ld)", me->getName(), me, command->GetAddress(), command->GetEndpoint(), command->GetDirection() == kUSBIn ? "in" : "out", status, (int)bufferSizeRemaining, command->GetReqCount());
if ( status == kIOUSBTransactionReturned )
status = kIOReturnAborted;
command->SetStatus(status);
if (dmaCommand && memDesc)
{
USBLog(7, "%s[%p]::InterruptPacketHandler - clearing memory descriptor (%p) from dmaCommand (%p)", me->getName(), me, dmaCommand->getMemoryDescriptor(), dmaCommand);
dmaCommand->clearMemoryDescriptor();
}
if ( command->GetUseTimeStamp() )
{
IOUSBCompletion completion = command->GetClientCompletion();
IOUSBCompletionWithTimeStamp completionWithTimeStamp;
completionWithTimeStamp.target = completion.target;
completionWithTimeStamp.parameter = completion.parameter;
completionWithTimeStamp.action = (IOUSBCompletionActionWithTimeStamp) completion.action;
me->CompleteWithTimeStamp( completionWithTimeStamp, status, bufferSizeRemaining, command->GetTimeStamp());
}
else
me->Complete(command->GetClientCompletion(), status, bufferSizeRemaining);
if ( !command->GetIsSyncTransfer() )
{
me->_freeUSBCommandPool->returnCommand(command);
}
}
IOReturn
IOUSBController::BulkTransaction(IOUSBCommand *command)
{
IOUSBCompletion completion;
IOReturn err = kIOReturnSuccess;
completion.target = (void *)this;
completion.action = (IOUSBCompletionAction) &IOUSBController::BulkPacketHandler;
completion.parameter = (void *)command;
command->SetUSLCompletion(completion);
command->SetBufferRounding(true);
err = UIMCreateBulkTransfer(command);
if (err)
{
USBLog(3,"%s[%p]::BulkTransaction: error queueing bulk packet (0x%x)", getName(), this, err);
}
return(err);
}
void
IOUSBController::BulkPacketHandler(OSObject *target, void *parameter, IOReturn status, UInt32 bufferSizeRemaining)
{
IOUSBController * me = (IOUSBController *)target;
IOUSBCommand * command = (IOUSBCommand *)parameter;
IODMACommand * dmaCommand = command->GetDMACommand();
IOMemoryDescriptor * memDesc = dmaCommand ? (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor() : NULL;
if (command == 0)
return;
USBLog(7,"%s[%p]::BulkPacketHandler: addr %d:%d(%s) complete status=0x%x bufferSizeRemaining = %d (%ld)", me->getName(), me, command->GetAddress(), command->GetEndpoint(), command->GetDirection() == kUSBIn ? "in" : "out", status, (int)bufferSizeRemaining, command->GetReqCount());
if ( status == kIOUSBTransactionReturned )
status = kIOReturnAborted;
if (dmaCommand && memDesc)
{
USBLog(7, "%s[%p]::BulkPacketHandler - releasing memory descriptor (%p) from dmaCommand (%p)", me->getName(), me, dmaCommand->getMemoryDescriptor(), dmaCommand);
dmaCommand->clearMemoryDescriptor();
}
command->SetStatus(status);
me->Complete(command->GetClientCompletion(), status, bufferSizeRemaining);
if ( !command->GetIsSyncTransfer() )
{
me->_freeUSBCommandPool->returnCommand(command);
}
}
IOReturn
IOUSBController::DoIsocTransfer(OSObject *owner, void *cmd, void *, void *, void *)
{
IOUSBController * controller = (IOUSBController *)owner;
IOUSBIsocCommand * command = (IOUSBIsocCommand *) cmd;
IOReturn kr = kIOReturnSuccess;
if ( !controller || !command )
{
USBError(1,"IOUSBController[%p]::DoIsocTransfer -- bad controller or command (%p,%p)", controller, controller, command);
return kIOReturnBadArgument;
}
if ( command->GetIsSyncTransfer() )
{
IOUSBSyncCompletionTarget syncTarget;
bool inCommandSleep = true;
IOUSBIsocCompletion completion = command->GetCompletion();
if ( controller->getWorkLoop()->onThread() )
{
USBError(1,"%s[%p]::DoIsocTransfer sync request on workloop thread. Use async!", controller->getName(), controller);
return kIOUSBSyncRequestOnWLThread;
}
syncTarget.controller = controller;
syncTarget.flag = &inCommandSleep;
completion.target = &syncTarget;
command->SetCompletion(completion);
kr = controller->IsocTransaction(command);
if ( kr == kIOReturnSuccess )
{
IOCommandGate * commandGate = controller->GetCommandGate();
kr = commandGate->commandSleep(&inCommandSleep, THREAD_UNINT);
inCommandSleep = false;
kr = command->GetStatus();
controller->_freeUSBIsocCommandPool->returnCommand(command);
}
}
else
{
kr = controller->IsocTransaction(command);
if (kr)
{
if (command->GetDMACommand())
{
IOMemoryDescriptor *memDesc = (IOMemoryDescriptor *)command->GetDMACommand()->getMemoryDescriptor();
if (memDesc)
{
USBLog(7, "%s[%p]::DoIsocTransfer - ASYNC - clearing memory descriptor %p from dmaCommand %p", controller->getName(), controller, command->GetDMACommand()->getMemoryDescriptor(), command->GetDMACommand());
command->GetDMACommand()->clearMemoryDescriptor(); }
}
controller->_freeUSBIsocCommandPool->returnCommand(command);
}
}
return kr;
}
IOReturn
IOUSBController::DoLowLatencyIsocTransfer(OSObject *owner, void *cmd, void *, void *, void *)
{
USBError(1, "IOUSBController::DoLowLatencyIsocTransfer no longer used");
return kIOReturnIPCError;
}
IOReturn
IOUSBController::IsocTransaction(IOUSBIsocCommand *command)
{
IOUSBIsocCompletion completion;
IOReturn err = kIOReturnSuccess;
USBLog(7, "IOUSBController::IsocTransaction");
completion.target = (void *)this;
completion.action = (IOUSBIsocCompletionAction) &IOUSBController::IsocCompletionHandler;
completion.parameter = (void *)command;
command->SetUSLCompletion(completion);
if (!_activeIsochTransfers)
requireMaxBusStall(10000);
_activeIsochTransfers++;
err = UIMCreateIsochTransfer(command);
if (err)
{
USBLog(3,"%s[%p]::IsocTransaction: error queueing isoc transfer (0x%x)", getName(), this, err);
_activeIsochTransfers--;
if (!_activeIsochTransfers)
requireMaxBusStall(0); }
return err;
}
IOReturn
IOUSBController::LowLatencyIsocTransaction(IOUSBIsocCommand *command)
{
USBError(1, "%s[%p]::LowLatencyIsocTransaction no longer used", getName(), this);
return kIOReturnIPCError;
}
void
IOUSBController::IsocCompletionHandler(OSObject *target, void *parameter, IOReturn status, IOUSBIsocFrame *pFrames)
{
IOUSBIsocCommand * command = (IOUSBIsocCommand *)parameter;
IOUSBController * me = OSDynamicCast(IOUSBController, target);
IODMACommand * dmaCommand = command->GetDMACommand();
IOMemoryDescriptor * memDesc = dmaCommand ? (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor() : NULL;
if (command == NULL)
return;
command->SetStatus(status);
if (memDesc)
{
USBLog(7, "%s[%p]::IsocCompletionHandler - clearing memory descriptor (%p) from dmaCommand (%p)", me->getName(), me, memDesc, command->GetDMACommand());
command->GetDMACommand()->clearMemoryDescriptor();
}
IOUSBIsocCompletion completion = command->GetCompletion();
if (completion.action)
{
USBLog(7, "%s[%p]::IsocCompletionHandler - calling completion [%p], target (%p) parameter (%p) status (%p) pFrames (%p)", me->getName(), me, completion.action, completion.target, completion.parameter, (void*)status, pFrames);
(*completion.action)(completion.target, completion.parameter, status, pFrames);
}
if ( !command->GetIsSyncTransfer() )
{
USBLog(7, "%s[%p]::IsocCompletionHandler - returning command %p", me->getName(), me, command);
me->_freeUSBIsocCommandPool->returnCommand(command);
}
}
void
IOUSBController::WatchdogTimer(OSObject *target, IOTimerEventSource *source)
{
IOUSBController* me = OSDynamicCast(IOUSBController, target);
IOUSBControllerV2* me2 = OSDynamicCast(IOUSBControllerV2, target);
IOReturn err;
if (!me || !source || me->isInactive() || me->_pcCardEjected )
{
me->_watchdogTimerActive = false;
return;
}
err = source->setTimeoutMS(kUSBWatchdogTimeoutMS);
if (err)
{
USBError(1, "%s[%p]::WatchdogTime: error 0x%08x", me->getName(), me, err);
}
else
{
me->UIMCheckForTimeouts();
if (me2)
{
UInt64 frameNumber;
AbsoluteTime frameTime;
IOReturn frameRet;
UInt64 timeInMicS;
frameRet = me2->GetFrameNumberWithTime(&frameNumber, &frameTime);
if (!frameRet)
{
absolutetime_to_nanoseconds(frameTime, &timeInMicS);
timeInMicS /= 1000; USBLog(7, "%s[%p]::WatchdogTimer - GetFrameNumberWithTime returned frame [%Ld] at time [%Ld]", me2->getName(), me2, frameNumber, timeInMicS);
}
else
{
USBLog(7, "%s[%p]::WatchdogTimer - GetFrameNumberWithTime returned error %p", me2->getName(), me2, (void*)frameRet);
}
}
}
}
IOReturn
IOUSBController::DoIOTransfer(OSObject *owner, void *cmd, void *, void *, void *)
{
IOUSBController * controller = (IOUSBController *)owner;
IOUSBCommand * command = (IOUSBCommand *) cmd;
IOReturn err = kIOReturnSuccess;
IOUSBCompletion completion;
IOUSBCompletion disjointCompletion;
IOCommandGate * commandGate;
if ( !controller || !command )
{
USBError(1,"IOUSBController[%p]::DoIOTransfer -- bad controller or command (%p,%p)", controller, controller, command);
return kIOReturnBadArgument;
}
if ( controller->_pcCardEjected )
{
USBLog(1, "%s[%p]::DoIOTransfer - trying to queue when PC Card ejected", controller->getName(), controller);
return kIOReturnNotResponding;
}
commandGate = controller->GetCommandGate();
completion = command->GetClientCompletion();
disjointCompletion = command->GetDisjointCompletion();
if ( command->GetIsSyncTransfer() )
{
IOUSBSyncCompletionTarget syncTarget;
bool inCommandSleep = true;
if ( controller->getWorkLoop()->onThread() )
{
USBError(1,"%s[%p]::DoIOTransfer sync request on workloop thread. Use async!", controller->getName(), controller);
return kIOUSBSyncRequestOnWLThread;
}
syncTarget.controller = controller;
syncTarget.flag = &inCommandSleep;
if ( (UInt32) completion.action == (UInt32) &IOUSBSyncCompletion )
{
completion.target = &syncTarget;
command->SetClientCompletion(completion);
}
else
{
disjointCompletion.target = &syncTarget;
command->SetDisjointCompletion(disjointCompletion);
}
switch (command->GetType())
{
case kUSBInterrupt:
err = controller->InterruptTransaction(command);
if ( err == kIOReturnSuccess )
{
err = commandGate->commandSleep(&inCommandSleep, THREAD_UNINT);
inCommandSleep = false;
err = command->GetStatus();
}
break;
case kUSBBulk:
err = controller->BulkTransaction(command);
if ( err == kIOReturnSuccess )
{
err = commandGate->commandSleep(&inCommandSleep, THREAD_UNINT);
inCommandSleep = false;
err = command->GetStatus();
}
break;
case kUSBIsoc:
USBLog(3,"%s[%p]::DoIOTransfer Isoc transactions not supported on non-isoc pipes!!", controller->getName(), controller);
err = kIOReturnBadArgument;
break;
default:
USBLog(3,"%s[%p]::DoIOTransfer Unknown transaction type", controller->getName(), controller);
err = kIOReturnBadArgument;
break;
}
}
else
{
switch (command->GetType())
{
case kUSBInterrupt:
err = controller->InterruptTransaction(command);
break;
case kUSBIsoc:
USBLog(3,"%s[%p]::DoIOTransfer Isoc transactions not supported on non-isoc pipes!!", controller->getName(), controller);
err = kIOReturnBadArgument;
break;
case kUSBBulk:
err = controller->BulkTransaction(command);
break;
default:
USBLog(3,"%s[%p]::DoIOTransfer Unknown transaction type", controller->getName(), controller);
err = kIOReturnBadArgument;
break;
}
}
if (err)
{
USBLog(2, "%s[%p]::DoIOTransfer - error %s (0x%x) queueing request (Bus: 0x%lx, Addr: %d, EP: %d Direction: %d, Type: %d)", controller->getName(), controller, USBErrorToString(err), err, controller->_busNumber, command->GetAddress(), command->GetEndpoint(), command->GetDirection(), command->GetType() );
}
return err;
}
IOReturn
IOUSBController::DoControlTransfer(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3)
{
IOUSBController *controller = (IOUSBController *)owner;
IOUSBCommand *command = (IOUSBCommand *) arg0;
IOUSBCompletion completion;
IOUSBCompletion disjointCompletion;
IOReturn kr = kIOReturnSuccess;
if ( !controller || !command )
{
USBError(1,"IOUSBController[%p]::DoControlTransfer -- bad controller or command (%p,%p)", controller, controller, command);
return kIOReturnBadArgument;
}
if ( controller->_pcCardEjected )
{
USBLog(1, "%s[%p]::DoControlTransfer - trying to queue when PC Card ejected", controller->getName(), controller);
return kIOReturnNotResponding;
}
completion = command->GetClientCompletion();
disjointCompletion = command->GetDisjointCompletion();
if ( ( (UInt32) completion.action == (UInt32) &IOUSBSyncCompletion) ||
( (UInt32) disjointCompletion.action == (UInt32) &IOUSBSyncCompletion) )
{
IOUSBSyncCompletionTarget syncTarget;
bool inCommandSleep = true;
if ( controller->getWorkLoop()->onThread() )
{
USBError(1,"%s[%p]::DoControlTransfer sync request on workloop thread. Use async!", controller->getName(), controller);
return kIOUSBSyncRequestOnWLThread;
}
syncTarget.controller = controller;
syncTarget.flag = &inCommandSleep;
if ( (UInt32) completion.action == (UInt32) &IOUSBSyncCompletion )
{
completion.target = &syncTarget;
command->SetClientCompletion(completion);
}
else
{
disjointCompletion.target = &syncTarget;
command->SetDisjointCompletion(disjointCompletion);
}
kr = controller->ControlTransaction((IOUSBCommand *)arg0);
if ( kr == kIOReturnSuccess )
{
IOCommandGate * commandGate = controller->GetCommandGate();
kr = commandGate->commandSleep(&inCommandSleep, THREAD_UNINT);
inCommandSleep = false;
kr = command->GetStatus();
}
}
else
{
kr = controller->ControlTransaction((IOUSBCommand *)arg0);
}
return kr;
}
IOReturn
IOUSBController::DoDeleteEP(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3)
{
IOUSBController *me = (IOUSBController *)owner;
return me->UIMDeleteEndpoint((short)(UInt32) arg0, (short)(UInt32) arg1, (short)(UInt32) arg2);
}
IOReturn
IOUSBController::DoAbortEP(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3)
{
IOUSBController *me = (IOUSBController *)owner;
return me->UIMAbortEndpoint((short)(UInt32) arg0, (short)(UInt32) arg1, (short)(UInt32) arg2);
}
IOReturn
IOUSBController::DoClearEPStall(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3)
{
IOUSBController *me = (IOUSBController *)owner;
return me->UIMClearEndpointStall((short)(UInt32) arg0, (short)(UInt32) arg1, (short)(UInt32) arg2);
}
IOReturn
IOUSBController::DoCreateEP(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3)
{
IOUSBController * me = (IOUSBController *)owner;
UInt8 address = (UInt8)(UInt32) arg0;
UInt8 speed = (UInt8)(UInt32) arg1;
Endpoint * endpoint = (Endpoint *)arg2;
IOReturn err;
USBLog(7,"%s[%p]::DoCreateEP, no high speed ancestor", me->getName(), me);
switch (endpoint->transferType)
{
case kUSBInterrupt:
err = me->UIMCreateInterruptEndpoint(address,
endpoint->number,
endpoint->direction,
speed,
endpoint->maxPacketSize,
endpoint->interval);
break;
case kUSBBulk:
err = me->UIMCreateBulkEndpoint(address,
endpoint->number,
endpoint->direction,
speed,
endpoint->maxPacketSize);
break;
case kUSBControl:
err = me->UIMCreateControlEndpoint(address,
endpoint->number,
endpoint->maxPacketSize,
speed);
break;
case kUSBIsoc:
err = me->UIMCreateIsochEndpoint(address,
endpoint->number,
endpoint->maxPacketSize,
endpoint->direction);
break;
default:
err = kIOReturnBadArgument;
break;
}
return (err);
}
IOReturn
IOUSBController::ProtectedDevZeroLock(OSObject *target, void* lock, void* arg2, void* arg3, void* arg4)
{
IOUSBController * me = (IOUSBController*)target;
IOCommandGate * commandGate = me->GetCommandGate();
USBLog(5, "%s[%p]::ProtectedAcquireDevZeroLock - about to %s device zero lock", me->getName(), me, lock ? "obtain" : "release");
if (lock)
{
if (!me->_devZeroLock)
{
USBLog(5, "%s[%p]::ProtectedAcquireDevZeroLock - not already locked - obtaining", me->getName(), me);
me->_devZeroLock = true;
return kIOReturnSuccess;
}
USBLog(5, "%s[%p]::ProtectedAcquireDevZeroLock - somebody already has it - running commandSleep", me->getName(), me);
while (me->_devZeroLock)
{
commandGate->commandSleep(&me->_devZeroLock, THREAD_UNINT);
if (me->_devZeroLock)
{
USBLog(5, "%s[%p]::ProtectedAcquireDevZeroLock - _devZeroLock still held - back to sleep", me->getName(), me);
}
}
me->_devZeroLock = true;
return kIOReturnSuccess;
}
else
{
USBLog(5, "%s[%p]::ProtectedAcquireDevZeroLock - releasing lock", me->getName(), me);
me->_devZeroLock = false;
commandGate->commandWakeup(&me->_devZeroLock, true);
USBLog(5, "%s[%p]::ProtectedAcquireDevZeroLock - wakeup done", me->getName(), me);
return kIOReturnSuccess;
}
}
IOReturn
IOUSBController::AcquireDeviceZero()
{
IOReturn err = 0;
Endpoint ep;
IOCommandGate * commandGate = GetCommandGate();
ep.number = 0;
ep.transferType = kUSBControl;
ep.maxPacketSize = 8;
USBLog(6,"%s[%p]: Trying to acquire Device Zero", getName(), this);
commandGate->runAction(ProtectedDevZeroLock, (void*)true);
USBLog(5,"%s[%p]: Acquired Device Zero", getName(), this);
return(err);
}
void
IOUSBController::ReleaseDeviceZero(void)
{
IOReturn err = 0;
IOCommandGate * commandGate = GetCommandGate();
err = commandGate->runAction(DoDeleteEP, (void *)0, (void *)0, (void *)kUSBAnyDirn);
err = commandGate->runAction(ProtectedDevZeroLock, (void*)false);
USBLog(5,"%s[%p]:: Released Device Zero", getName(), this);
return;
}
void
IOUSBController::WaitForReleaseDeviceZero()
{
IOCommandGate * commandGate = GetCommandGate();
commandGate->runAction(ProtectedDevZeroLock, (void*)true);
commandGate->runAction(ProtectedDevZeroLock, (void*)false);
}
IOReturn
IOUSBController::ConfigureDeviceZero(UInt8 maxPacketSize, UInt8 speed)
{
IOReturn err = kIOReturnSuccess;
Endpoint ep;
ep.number = 0;
ep.transferType = kUSBControl;
ep.maxPacketSize = maxPacketSize;
USBLog(6, "%s[%p]::ConfigureDeviceZero (maxPacketSize: %d, Speed: %d)", getName(), this, maxPacketSize, speed);
err = OpenPipe(0, speed, &ep);
return(err);
}
IOReturn
IOUSBController::GetDeviceZeroDescriptor(IOUSBDeviceDescriptor *desc, UInt16 size)
{
IOReturn err = kIOReturnSuccess;
IOUSBDevRequest request;
USBLog(6, "%s[%p]::GetDeviceZeroDescriptor (size: %d)", getName(), this, size);
do
{
IOUSBCompletion tap;
tap.target = NULL;
tap.action = &IOUSBSyncCompletion;
tap.parameter = NULL;
if (!desc)
{
err = kIOReturnBadArgument;
break;
}
request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
request.bRequest = kUSBRqGetDescriptor;
request.wValue = kUSBDeviceDesc << 8;
request.wIndex = 0;
request.wLength = size;
request.pData = desc;
err = DeviceRequest(&request, &tap, 0, 0);
} while(false);
if (err)
{
USBLog(3,"%s[%p]::GetDeviceZeroDescriptor Error: 0x%x", getName(), this, err);
}
return err;
}
IOReturn
IOUSBController::SetDeviceZeroAddress(USBDeviceAddress address)
{
IOReturn err = kIOReturnSuccess;
IOUSBDevRequest request;
USBLog(6, "%s[%p]::SetDeviceZeroAddress (%d)", getName(), this, address);
do
{
IOUSBCompletion tap;
tap.target = NULL;
tap.action = &IOUSBSyncCompletion;
tap.parameter = NULL;
request.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBStandard, kUSBDevice);
request.bRequest = kUSBRqSetAddress;
request.wValue = address;
request.wIndex = 0;
request.wLength = 0;
request.pData = 0;
err = DeviceRequest(&request, &tap, 0, 0);
} while(false);
if (err)
{
USBLog(6, "%s[%p]::SetDeviceZeroAddress Error: 0x%x", getName(), this, err);
}
return(err);
}
IOUSBDevice *
IOUSBController::MakeDevice(USBDeviceAddress * address)
{
IOReturn err = kIOReturnSuccess;
IOUSBDevice *newDev;
USBLog(6, "%s[%p]::MakeDevice", getName(), this);
newDev = IOUSBDevice::NewDevice();
if (newDev == NULL)
return NULL;
*address = GetNewAddress();
if(*address == 0)
{
USBLog(1, "%s[%p]::MakeDevice error getting address - releasing newDev", getName(), this);
newDev->release();
return NULL;
}
err = SetDeviceZeroAddress(*address);
if (err)
{
USBLog(1, "%s[%p]::MakeDevice error setting address. err=0x%x device=%p - releasing device", getName(), this, err, newDev);
*address = 0;
newDev->release();
return NULL;
}
return newDev;
}
IOUSBHubDevice *
IOUSBController::MakeHubDevice(USBDeviceAddress * address)
{
IOReturn err = kIOReturnSuccess;
IOUSBHubDevice *newDev;
USBLog(6, "%s[%p]::MakeHubDevice", getName(), this);
newDev = IOUSBHubDevice::NewHubDevice();
if (newDev == NULL)
return NULL;
*address = GetNewAddress();
if(*address == 0)
{
USBLog(1, "%s[%p]::MakeHubDevice error getting address - releasing newDev", getName(), this);
newDev->release();
return NULL;
}
err = SetDeviceZeroAddress(*address);
if (err)
{
USBLog(1, "%s[%p]::MakeHubDevice error setting address. err=0x%x device=%p - releasing device", getName(), this, err, newDev);
*address = 0;
newDev->release();
return NULL;
}
return newDev;
}
IOReturn
IOUSBController::PolledRead(short functionNumber,
short endpointNumber,
IOUSBCompletion clientCompletion,
IOMemoryDescriptor * CBP,
bool bufferRounding,
UInt32 bufferSize)
{
IOUSBCommand * command = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false);
IOUSBCompletion uslCompletion;
int i;
if ( command == NULL )
{
IncreaseCommandPool();
command = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false);
if ( command == NULL )
{
USBLog(3,"%s[%p]::DeviceRequest Could not get a IOUSBCommand",getName(),this);
return kIOReturnNoResources;
}
}
command->SetUseTimeStamp(true);
command->SetSelector(READ);
command->SetRequest(0); command->SetAddress(functionNumber);
command->SetEndpoint(endpointNumber);
command->SetDirection(kUSBIn);
command->SetType(kUSBInterrupt);
command->SetBuffer(CBP);
command->SetClientCompletion(clientCompletion);
command->SetBufferRounding(bufferRounding);
for (i=0; i < 10; i++)
command->SetUIMScratch(i, 0);
uslCompletion.target = (void *)this;
uslCompletion.action = (IOUSBCompletionAction) &IOUSBController::InterruptPacketHandler;
uslCompletion.parameter = (void *)command;
command->SetUSLCompletion(uslCompletion);
return UIMCreateInterruptTransfer(command);
}
IOReturn
IOUSBController::message( UInt32 type, IOService * provider, void * argument )
{
IOReturn err = kIOReturnSuccess;
cs_event_t pccardevent;
switch ( type )
{
case kIOMessageServiceIsTerminated:
break;
case kIOMessageCanDevicePowerOff:
case kIOMessageDeviceWillPowerOff:
break;
case kIOPCCardCSEventMessage:
pccardevent = (UInt32) argument;
USBLog(5,"+%s[%p]: Received kIOPCCardCSEventMessage event %ld",getName(),this, (UInt32) pccardevent);
if ( pccardevent == CS_EVENT_CARD_REMOVAL )
{
_pcCardEjected = true;
if ( _rootHubDevice )
{
thread_call_enter(_terminatePCCardThread);
}
}
USBLog(5,"-%s[%p]: Received kIOPCCardCSEventMessage event %ld",getName(),this, (UInt32) pccardevent);
break;
default:
err = kIOReturnUnsupported;
break;
}
return err;
}
void
IOUSBController::stop( IOService * provider )
{
UInt32 i;
IOUSBCommand * command;
UInt32 retries = 0;
USBLog(5,"+%s[%p]::stop (0x%lx)", getName(), this, (UInt32) provider);
while ( retries < 600 && _watchdogTimerActive )
{
IOSleep(100);
retries++;
}
UIMFinalize();
gUsedBusIDs[_busNumber] = false;
PMstop();
for ( i = 0; i < _currentSizeOfCommandPool; i++ )
{
command = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false);
if ( command )
command->release();
}
for ( i = 0; i < _currentSizeOfIsocCommandPool; i++ )
{
command = (IOUSBCommand *)_freeUSBIsocCommandPool->getCommand(false);
if ( command )
command->release();
}
if (_terminatePCCardThread)
{
thread_call_cancel(_terminatePCCardThread);
thread_call_free(_terminatePCCardThread);
}
if ( _freeUSBCommandPool )
{
_freeUSBCommandPool->release();
_freeUSBCommandPool = NULL;
}
if ( _freeUSBIsocCommandPool )
{
_freeUSBIsocCommandPool->release();
_freeUSBIsocCommandPool = NULL;
}
if ( _watchdogUSBTimer )
{
_watchdogUSBTimer->cancelTimeout();
if ( _workLoop )
_workLoop->removeEventSource( _watchdogUSBTimer );
}
if ( _workLoop && _commandGate)
_workLoop->removeEventSource( _commandGate );
_provider->close(this);
USBLog(5,"-%s[%p]::stop (0x%lx)", getName(), this, (UInt32) provider);
}
bool
IOUSBController::finalize(IOOptionBits options)
{
return(super::finalize(options));
}
void
IOUSBController::IncreaseCommandPool(void)
{
IOUSBControllerV2* me2 = OSDynamicCast(IOUSBControllerV2, this);
int i;
USBLog(3,"%s[%p]::IncreaseCommandPool Adding (%d) to Command Pool", getName(), this, kSizeToIncrementCommandPool);
for (i = 0; i < kSizeToIncrementCommandPool; i++)
{
IOUSBCommand *command = IOUSBCommand::NewCommand();
if (command)
{
if (me2)
command->SetDMACommand(me2->GetNewDMACommand());
_freeUSBCommandPool->returnCommand(command);
}
}
_currentSizeOfCommandPool += kSizeToIncrementCommandPool;
}
void
IOUSBController::IncreaseIsocCommandPool(void)
{
IOUSBControllerV2* me2 = OSDynamicCast(IOUSBControllerV2, this);
int i;
USBLog(3,"%s[%p]::IncreaseIsocCommandPool Adding (%d) to Isoc Command Pool", getName(), this, kSizeToIncrementIsocCommandPool);
for (i = 0; i < kSizeToIncrementIsocCommandPool; i++)
{
IOUSBIsocCommand *icommand = IOUSBIsocCommand::NewCommand();
if (icommand)
{
if (me2)
icommand->SetDMACommand(me2->GetNewDMACommand());
_freeUSBIsocCommandPool->returnCommand(icommand);
}
}
_currentSizeOfIsocCommandPool += kSizeToIncrementIsocCommandPool;
}
void
IOUSBController::Complete(IOUSBCompletion completion,
IOReturn status,
UInt32 actualByteCount)
{
if (completion.action) (*completion.action)(completion.target,
completion.parameter,
status,
actualByteCount);
}
void
IOUSBController::CompleteWithTimeStamp(IOUSBCompletionWithTimeStamp completion,
IOReturn status,
UInt32 actualByteCount,
AbsoluteTime timeStamp)
{
if (completion.action) (*completion.action)(completion.target, completion.parameter, status, actualByteCount, timeStamp);
}
IOCommandGate *
IOUSBController::GetCommandGate(void)
{
return _commandGate;
}
void
IOUSBController::TerminatePCCard(OSObject *target)
{
IOUSBController * me = OSDynamicCast(IOUSBController, target);
bool ok;
if (!me)
return;
USBLog(5,"%s[%p]::TerminatePCCard Terminating RootHub", me->getName(),me);
ok = me->_rootHubDevice->terminate(kIOServiceRequired | kIOServiceSynchronous);
if ( !ok )
{
USBLog(3,"%s[%p]::TerminatePCCard Could not terminate RootHub device", me->getName(), me);
}
me->_rootHubDevice->detachAll(gIOUSBPlane);
me->_rootHubDevice->release();
me->_rootHubDevice = NULL;
}
#define ISDIGIT(c) ((c >= '0') && (c <= '9'))
#define ISHEXDIGIT(c) (ISDIGIT(c) || ((c >= 'A') && (c <= 'F')) || ((c >= 'a') && (c <= 'f')))
int
IOUSBController::ValueOfHexDigit(char c)
{
if ( ISDIGIT(c) )
return c - '0';
else
if ( ( c >= 'A' && c <= 'F') )
return c - 'A' + 0x0A;
else
return c - 'a' + 0xA;
}
void
IOUSBController::ParsePCILocation(const char *str, int *deviceNum, int *functionNum)
{
int value;
int i;
*deviceNum = *functionNum = 0;
for ( i = 0; i < 2; i++)
{
if ( !ISHEXDIGIT(*str) )
break;
value = 0;
do {
value = (value * 16) - ValueOfHexDigit(*str);
str++;
} while (ISHEXDIGIT(*str));
if ( i == 0)
*deviceNum = -value;
else
*functionNum = -value;
if ( *str == '\0')
break;
str++;
}
}
OSMetaClassDefineReservedUsed(IOUSBController, 0);
void IOUSBController::UIMCheckForTimeouts(void)
{
return;
}
OSMetaClassDefineReservedUsed(IOUSBController, 1);
IOReturn
IOUSBController::UIMCreateControlTransfer( short functionNumber,
short endpointNumber,
IOUSBCommand* command,
void* CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
USBError(1, "IOUSBController::UIMCreateControlTransfer, got into wrong one");
return UIMCreateControlTransfer(functionNumber, endpointNumber, command->GetUSLCompletion(), CBP, bufferRounding, bufferSize, direction);
}
OSMetaClassDefineReservedUsed(IOUSBController, 2);
IOReturn
IOUSBController::UIMCreateControlTransfer( short functionNumber,
short endpointNumber,
IOUSBCommand* command,
IOMemoryDescriptor* CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
USBError(1, "IOUSBController::UIMCreateControlTransfer, got into wrong one");
return UIMCreateControlTransfer(functionNumber, endpointNumber, command->GetUSLCompletion(), CBP, bufferRounding, bufferSize, direction);
}
OSMetaClassDefineReservedUsed(IOUSBController, 3);
IOReturn
IOUSBController::UIMCreateBulkTransfer(IOUSBCommand* command)
{
return UIMCreateBulkTransfer(command->GetAddress(),
command->GetEndpoint(),
command->GetUSLCompletion(),
command->GetBuffer(),
command->GetBufferRounding(),
command->GetReqCount(),
command->GetDirection());
}
OSMetaClassDefineReservedUsed(IOUSBController, 4);
IOReturn
IOUSBController::UIMCreateInterruptTransfer(IOUSBCommand* command)
{
return UIMCreateInterruptTransfer(command->GetAddress(),
command->GetEndpoint(),
command->GetUSLCompletion(),
command->GetBuffer(),
command->GetBufferRounding(),
command->GetReqCount(),
command->GetDirection());
}
OSMetaClassDefineReservedUsed(IOUSBController, 5);
IOReturn
IOUSBController::DeviceRequest(IOUSBDevRequest *request, IOUSBCompletion *completion, USBDeviceAddress address, UInt8 ep, UInt32 noDataTimeout, UInt32 completionTimeout)
{
IOUSBCommand *command = NULL;
IOUSBCommand *bufferCommand = NULL; IOReturn err = kIOReturnSuccess;
IOUSBCompletion nullCompletion;
int i;
IOMemoryDescriptor *bufferMemoryDescriptor = NULL;
IOMemoryDescriptor *requestMemoryDescriptor = NULL;
UInt8 direction = (request->bmRequestType >> kUSBRqDirnShift) & kUSBRqDirnMask;
UInt16 reqLength = request->wLength;
IODMACommand *dmaCommand = NULL;
IODMACommand *bufferDMACommand = NULL;
USBLog(7,"%s[%p]::DeviceRequest [%x,%x],[%x,%x],[%x,%lx]",getName(),this,
request->bmRequestType,
request->bRequest,
request->wValue,
request->wIndex,
reqLength,
(UInt32)request->pData);
if ( GetCommandGate() == 0)
return kIOReturnInternalError;
command = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false);
if (reqLength)
bufferCommand = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false);
if ( !command || (reqLength && !bufferCommand))
{
IncreaseCommandPool();
if (!command)
command = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false);
if (reqLength && !bufferCommand)
bufferCommand = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false);
if ( !command || (reqLength && !bufferCommand))
{
USBLog(3,"%s[%p]::DeviceRequest Could not get a IOUSBCommand (1:%p 2:%p)", getName(), this, command, bufferCommand);
return kIOReturnNoResources;
}
}
dmaCommand = command->GetDMACommand();
if (!dmaCommand)
{
USBError(1,"%s[%p]::DeviceRequest - No dmaCommand in the usb command", getName(), this);
return kIOReturnNoResources;
}
if (dmaCommand->getMemoryDescriptor())
{
IOMemoryDescriptor *memDesc = (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor();
USBError(1,"%s[%p]::DeviceRequest - dmaCommand (%p) already had memory descriptor (%p) - clearing", getName(), this, dmaCommand, memDesc);
dmaCommand->clearMemoryDescriptor();
}
request->wValue = HostToUSBWord(request->wValue);
request->wIndex = HostToUSBWord(request->wIndex);
request->wLength = HostToUSBWord(request->wLength);
requestMemoryDescriptor = IOMemoryDescriptor::withAddress(request, 8, kIODirectionOut);
if (!requestMemoryDescriptor)
{
USBError(1,"%s[%p]::DeviceRequest - could not create request memory descriptor", getName(), this);
return kIOReturnNoMemory;
}
err = requestMemoryDescriptor->prepare();
if (err)
{
USBError(1,"%s[%p]::DeviceRequest - err (%p) trying to prepare request memory descriptor", getName(), this, (void*)err);
requestMemoryDescriptor->release();
return err;
}
command->SetRequestMemoryDescriptor(requestMemoryDescriptor);
command->SetReqCount(8);
USBLog(7,"%s[%p]::DeviceRequest - setting memory descriptor (%p) into dmaCommand (%p)", getName(), this, requestMemoryDescriptor, dmaCommand);
err = dmaCommand->setMemoryDescriptor(requestMemoryDescriptor);
if (err)
{
USBError(1,"%s[%p]::DeviceRequest - err (%p) setting memory descriptor (%p) into dmaCommand (%p)", getName(), this, (void*)err, requestMemoryDescriptor, dmaCommand);
requestMemoryDescriptor->complete();
requestMemoryDescriptor->release();
return err;
}
if (reqLength)
{
IOMemoryDescriptor *memDesc;
bufferDMACommand = bufferCommand->GetDMACommand();
if (!bufferDMACommand)
{
USBError(1,"%s[%p]::DeviceRequest - No dmaCommand in the usb command", getName(), this);
return kIOReturnNoResources;
}
memDesc = (IOMemoryDescriptor *)bufferDMACommand->getMemoryDescriptor();
if (memDesc)
{
USBError(1,"%s[%p]::DeviceRequest - buffer dmaCommand (%p) already had memory descriptor (%p) - clearing", getName(), this, bufferDMACommand, bufferDMACommand->getMemoryDescriptor());
bufferDMACommand->clearMemoryDescriptor();
}
}
if (reqLength && (request->pData != NULL))
{
bufferMemoryDescriptor = IOMemoryDescriptor::withAddress(request->pData, reqLength, (direction == kUSBIn) ? kIODirectionIn : kIODirectionOut);
if (bufferMemoryDescriptor)
{
err = bufferMemoryDescriptor->prepare();
if (err)
{
USBError(1,"%s[%p]::DeviceRequest - err (%p) trying to prepare bufferMemoryDescriptor", getName(), this, (void*)err);
return err;
}
bufferCommand->SetBufferMemoryDescriptor(bufferMemoryDescriptor);
bufferCommand->SetReqCount(reqLength);
bufferCommand->SetSelector(DEVICE_REQUEST); USBLog(7,"%s[%p]::DeviceRequest - setting buffer memory descriptor (%p) into buffer dmaCommand (%p)", getName(), this, bufferMemoryDescriptor, bufferDMACommand);
err = bufferDMACommand->setMemoryDescriptor(bufferMemoryDescriptor);
if (err)
{
USBError(1,"%s[%p]::DeviceRequest - err (%p) setting buffer memory descriptor (%p) into buffer dmaCommand (%p)", getName(), this, (void*)err, bufferMemoryDescriptor, bufferDMACommand);
bufferMemoryDescriptor->complete();
bufferMemoryDescriptor->release();
return err;
}
}
else
{
USBError(1, "%s[%p]::DeviceRequest - unable to get needed IOMemoryDescriptor", getName(), this);
return kIOReturnNoResources;
}
}
if ( (UInt32) completion->action == (UInt32) &IOUSBSyncCompletion )
command->SetIsSyncTransfer(true);
else
command->SetIsSyncTransfer(false);
command->SetUseTimeStamp(false);
if (bufferMemoryDescriptor)
command->SetSelector(DEVICE_REQUEST_BUFFERCOMMAND);
else
command->SetSelector(DEVICE_REQUEST);
command->SetRequest(request);
command->SetAddress(address);
command->SetEndpoint(ep);
command->SetType(kUSBControl);
command->SetBuffer(0); command->SetClientCompletion(*completion);
command->SetNoDataTimeout(noDataTimeout);
command->SetCompletionTimeout(completionTimeout);
command->SetBufferUSBCommand(bufferCommand);
nullCompletion.target = (void *) NULL;
nullCompletion.action = (IOUSBCompletionAction) NULL;
nullCompletion.parameter = (void *) NULL;
command->SetUSLCompletion(nullCompletion);
command->SetDisjointCompletion(nullCompletion);
for (i=0; i < 10; i++)
command->SetUIMScratch(i, 0);
err = GetCommandGate()->runAction(DoControlTransfer, command);
if ( command->GetIsSyncTransfer() || (!command->GetIsSyncTransfer() && (kIOReturnSuccess != err)) )
{
command->SetBufferUSBCommand(NULL);
_freeUSBCommandPool->returnCommand(command);
if (bufferCommand)
_freeUSBCommandPool->returnCommand(bufferCommand);
}
return err;
}
OSMetaClassDefineReservedUsed(IOUSBController, 6);
IOReturn
IOUSBController::DeviceRequest(IOUSBDevRequestDesc *request, IOUSBCompletion *completion, USBDeviceAddress address, UInt8 ep, UInt32 noDataTimeout, UInt32 completionTimeout)
{
IOUSBCommand * command = NULL; IOUSBCommand *bufferCommand = NULL; IODMACommand *bufferDMACommand = NULL;
IOMemoryDescriptor *requestMemoryDescriptor = NULL;
IOReturn err = kIOReturnSuccess;
IOUSBCompletion nullCompletion;
UInt16 reqLength = request->wLength;
int i;
USBLog(7,"%s[%p]::DeviceRequestDesc [%x,%x],[%x,%x],[%x,%lx]",getName(),this,
request->bmRequestType,
request->bRequest,
request->wValue,
request->wIndex,
reqLength,
(UInt32)request->pData);
if ( GetCommandGate() == NULL)
return kIOReturnInternalError;
command = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false);
if (reqLength)
bufferCommand = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false);
if ( !command || (reqLength && !bufferCommand))
{
IncreaseCommandPool();
if (!command)
command = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false);
if (reqLength && !bufferCommand)
bufferCommand = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false);
if ( !command || (reqLength && !bufferCommand))
{
USBLog(3,"%s[%p]::DeviceRequest Could not get a IOUSBCommand (1:%p 2:%p)", getName(), this, command, bufferCommand);
return kIOReturnNoResources;
}
}
if ( (UInt32) completion->action == (UInt32) &IOUSBSyncCompletion )
command->SetIsSyncTransfer(true);
else
command->SetIsSyncTransfer(false);
command->SetUseTimeStamp(false);
request->wValue = HostToUSBWord(request->wValue);
request->wIndex = HostToUSBWord(request->wIndex);
request->wLength = HostToUSBWord(request->wLength);
requestMemoryDescriptor = IOMemoryDescriptor::withAddress(request, 8, kIODirectionOut);
if (!requestMemoryDescriptor)
{
USBError(1,"%s[%p]::DeviceRequest - could not create request memory descriptor", getName(), this);
return kIOReturnNoMemory;
}
err = requestMemoryDescriptor->prepare();
if (err)
{
USBError(1,"%s[%p]::DeviceRequest - err (%p) trying to prepare request memory descriptor", getName(), this, (void*)err);
requestMemoryDescriptor->release();
return err;
}
command->SetRequestMemoryDescriptor(requestMemoryDescriptor);
command->SetReqCount(8);
USBLog(7,"%s[%p]::DeviceRequest - setting memory descriptor (%p) into dmaCommand (%p)", getName(), this, requestMemoryDescriptor, command->GetDMACommand());
err = command->GetDMACommand()->setMemoryDescriptor(requestMemoryDescriptor);
if (err)
{
USBError(1,"%s[%p]::DeviceRequest - err (%p) setting memory descriptor (%p) into dmaCommand (%p)", getName(), this, (void*)err, requestMemoryDescriptor, command->GetDMACommand());
requestMemoryDescriptor->complete();
requestMemoryDescriptor->release();
return err;
}
if (bufferCommand)
{
bufferDMACommand = bufferCommand->GetDMACommand();
bufferCommand->SetBufferMemoryDescriptor(request->pData);
bufferCommand->SetReqCount(reqLength);
bufferCommand->SetSelector(DEVICE_REQUEST_DESC); command->SetSelector(DEVICE_REQUEST_BUFFERCOMMAND);
if (0) {
USBError(1,"%s[%p]::DeviceRequest - err (%p) preparing clients memory descriptor (%p)", getName(), this, (void*)err, request->pData);
request->pData->release(); return err;
}
USBLog(7,"%s[%p]::DeviceRequest - setting buffer memory descriptor (%p) into buffer dmaCommand (%p)", getName(), this, request->pData, bufferDMACommand);
err = bufferDMACommand->setMemoryDescriptor(request->pData);
if (err)
{
USBError(1,"%s[%p]::DeviceRequest - err (%p) setting buffer memory descriptor (%p) into buffer dmaCommand (%p)", getName(), this, (void*)err, request->pData, bufferDMACommand);
return err;
}
}
else
{
command->SetSelector(DEVICE_REQUEST_DESC);
command->SetBuffer(request->pData); if (request->pData)
{
USBError(1, "%s[%p]::DeviceRequest - expected NULL request->pData (%p)", getName(), this, request->pData);
}
}
command->SetRequest((IOUSBDevRequest *)request);
command->SetAddress(address);
command->SetEndpoint(ep);
command->SetType(kUSBControl);
command->SetClientCompletion(*completion);
command->SetNoDataTimeout(noDataTimeout);
command->SetCompletionTimeout(completionTimeout);
command->SetBufferUSBCommand(bufferCommand);
nullCompletion.target = (void *) NULL;
nullCompletion.action = (IOUSBCompletionAction) NULL;
nullCompletion.parameter = (void *) NULL;
command->SetUSLCompletion(nullCompletion);
command->SetDisjointCompletion(nullCompletion);
for (i=0; i < 10; i++)
command->SetUIMScratch(i, 0);
err = GetCommandGate()->runAction(DoControlTransfer, command);
if ( command->GetIsSyncTransfer() || (!command->GetIsSyncTransfer() && (kIOReturnSuccess != err)) )
{
IOUSBCommand *bufferCommand = command->GetBufferUSBCommand();
command->SetBufferUSBCommand(NULL);
_freeUSBCommandPool->returnCommand(command);
if (bufferCommand)
_freeUSBCommandPool->returnCommand(bufferCommand);
}
return err;
}
OSMetaClassDefineReservedUsed(IOUSBController, 9);
void
IOUSBController::free()
{
if ( _watchdogUSBTimer )
{
_watchdogUSBTimer->release();
_watchdogUSBTimer = NULL;
}
if ( _commandGate )
{
_commandGate->release();
_commandGate = NULL;
}
if ( _workLoop )
{
_workLoop->release();
_workLoop = NULL;
}
if (_expansionData)
{
bzero(_expansionData, sizeof(ExpansionData));
IOFree(_expansionData, sizeof(ExpansionData));
}
super::free();
}
OSMetaClassDefineReservedUsed(IOUSBController, 11);
IOReturn
IOUSBController::CreateRootHubDevice( IOService * provider, IOUSBRootHubDevice ** rootHubDevice)
{
IOUSBDeviceDescriptor desc;
OSObject *appleCurrentProperty;
UInt32 pseudoBus;
IOReturn err = kIOReturnSuccess;
OSNumber * busNumberProp;
UInt32 bus;
UInt32 address;
const char * parentLocation;
int deviceNum = 0, functionNum = 0;
SInt32 busIndex;
err = GetRootHubDeviceDescriptor( &desc );
if ( err != kIOReturnSuccess)
{
USBError(1,"%s: unable to get root hub descriptor", getName());
goto ErrorExit;
}
*rootHubDevice = IOUSBRootHubDevice::NewRootHubDevice();
address = GetNewAddress();
SetHubAddress( address );
err = CreateDevice(*rootHubDevice, address, desc.bMaxPacketSize0, _controllerSpeed, kUSB500mAAvailable);
if ( err != kIOReturnSuccess)
{
USBError(1,"%s: unable to create and initialize root hub device", getName());
(*rootHubDevice)->release();
*rootHubDevice = NULL;
goto ErrorExit;
}
parentLocation = provider->getLocation();
if ( parentLocation )
{
ParsePCILocation( parentLocation, &deviceNum, &functionNum );
}
busNumberProp = (OSNumber *) provider->getProperty("USBBusNumber");
if ( busNumberProp )
{
bus = busNumberProp->unsigned32BitValue();
}
else
{
bus = ( ((functionNum & 0x7) << 5) | (deviceNum & 0x1f) );
if ( gUsedBusIDs[bus] )
{
USBError(1,"IOUSBController::CreateRootHubDevice Bus %ld already taken",bus);
for ( busIndex = kMaxNumberUSBBusses - 1; busIndex >= 0; busIndex-- )
{
if ( !gUsedBusIDs[busIndex] )
{
bus = busIndex;
break;
}
}
}
}
gUsedBusIDs[bus] = true;
pseudoBus = (bus & 0xff) << 24;
provider->setProperty("USBBusNumber", bus, 32);
provider->setProperty(kUSBDevicePropertyLocationID, pseudoBus, 32);
_busNumber = bus;
(*rootHubDevice)->setProperty(kUSBDevicePropertyLocationID, pseudoBus, 32);
(*rootHubDevice)->setLocation(provider->getLocation());
(*rootHubDevice)->setLocation(provider->getLocation(), gIOUSBPlane);
appleCurrentProperty = provider->getProperty(kAppleCurrentAvailable);
if (appleCurrentProperty)
(*rootHubDevice)->setProperty(kAppleCurrentAvailable, appleCurrentProperty);
appleCurrentProperty = provider->getProperty(kAppleCurrentInSleep);
if (appleCurrentProperty)
(*rootHubDevice)->setProperty(kAppleCurrentInSleep, appleCurrentProperty);
appleCurrentProperty = provider->getProperty(kAppleCurrentExtra);
if (appleCurrentProperty)
(*rootHubDevice)->setProperty(kAppleCurrentExtra, appleCurrentProperty);
if (_controllerCanSleep)
{
USBLog(2, "IOUSBController[%p]::CreateRootHubDevice - controller (%s) can sleep, setting characteristic in root hub (%p)", this, getName(), rootHubDevice);
(*rootHubDevice)->SetHubCharacteristics((*rootHubDevice)->GetHubCharacteristics() | kIOUSBHubDeviceCanSleep);
}
else
{
USBLog(1, "IOUSBController[%p]::CreateRootHubDevice - controller (%s) does not support sleep, NOT setting characteristic in root hub (%p)", this, getName(), rootHubDevice);
}
ErrorExit:
return err;
}
OSMetaClassDefineReservedUsed(IOUSBController, 16);
IOReturn
IOUSBController::UIMCreateIsochTransfer( short functionAddress,
short endpointNumber,
IOUSBIsocCompletion completion,
UInt8 direction,
UInt64 frameStart,
IOMemoryDescriptor *pBuffer,
UInt32 frameCount,
IOUSBLowLatencyIsocFrame *pFrames,
UInt32 updateFrequency)
{
return kIOReturnUnsupported;
}
OSMetaClassDefineReservedUsed(IOUSBController, 18);
IOReturn
IOUSBController::UIMCreateIsochTransfer(IOUSBIsocCommand *command)
{
IOReturn err;
UInt8 direction = command->GetDirection();
USBDeviceAddress address = command->GetAddress();
UInt8 endpoint = command->GetEndpoint();
IOUSBIsocCompletion completion = command->GetUSLCompletion();
UInt64 startFrame = command->GetStartFrame();
IOMemoryDescriptor * buffer = command->GetBuffer();
UInt32 numFrames = command->GetNumFrames();
IOUSBIsocFrame * frameList = command->GetFrameList();
IOUSBLowLatencyIsocFrame * frameListLL = (IOUSBLowLatencyIsocFrame *)frameList;
UInt32 updateFrequency = command->GetUpdateFrequency();
USBError(1, "IOUSBController::UIMCreateIsochTransfer - shouldn't be here");
if ( command->GetIsRosettaClient() )
direction |= 0x80;
if (command->GetLowLatency())
{
err = UIMCreateIsochTransfer( address, endpoint, completion, direction, startFrame, buffer, numFrames, frameListLL, updateFrequency); }
else
{
err = UIMCreateIsochTransfer( address, endpoint, completion, direction, startFrame, buffer, numFrames, frameList); }
return err;
}
OSMetaClassDefineReservedUnused(IOUSBController, 19);
const char *
IOUSBController::USBErrorToString(IOReturn status)
{
switch (status) {
case kIOReturnSuccess:
return "kIOReturnSuccess";
case kIOReturnError:
return "kIOReturnError";
case kIOReturnNotResponding:
return "kIOReturnNotResponding";
case kIOUSBPipeStalled:
return "kIOUSBPipeStalled";
case kIOReturnOverrun:
return "kIOReturnOverrun";
case kIOReturnUnderrun:
return "kIOReturnUnderrun";
case kIOReturnExclusiveAccess:
return "kIOReturnExclusiveAccess";
case kIOUSBTransactionReturned:
return "kIOUSBTransactionReturned";
case kIOReturnAborted:
return "kIOReturnAborted";
case kIOReturnIsoTooNew:
return "kIOReturnIsoTooNew";
case kIOReturnIsoTooOld:
return "kIOReturnIsoTooOld";
case kIOReturnNoDevice:
return "kIOReturnNoDevice";
case kIOReturnBadArgument:
return "kIOReturnBadArgument";
case kIOReturnInternalError:
return "kIOReturnInternalError";
case kIOReturnNoMemory:
return "kIOReturnNoMemory";
case kIOReturnUnsupported:
return "kIOReturnUnsupported";
case kIOReturnNoResources:
return "kIOReturnNoResources";
case kIOReturnNoBandwidth:
return "kIOReturnNoBandwidth";
case kIOReturnIPCError:
return "kIOReturnIPCError";
case kIOReturnTimeout:
return "kIOReturnTimeout";
case kIOReturnBusy:
return "kIOReturnBusy";
case kIOUSBUnknownPipeErr:
return "kIOUSBUnknownPipeErr";
case kIOUSBTooManyPipesErr:
return "kIOUSBTooManyPipesErr";
case kIOUSBNoAsyncPortErr:
return "kIOUSBNoAsyncPortErr";
case kIOUSBNotEnoughPipesErr:
return "kIOUSBNotEnoughPipesErr";
case kIOUSBNotEnoughPowerErr:
return "kIOUSBNotEnoughPowerErr";
case kIOUSBEndpointNotFound:
return "kIOUSBEndpointNotFound";
case kIOUSBConfigNotFound:
return "kIOUSBConfigNotFound";
case kIOUSBTransactionTimeout:
return "kIOUSBTransactionTimeout";
case kIOUSBLowLatencyBufferNotPreviouslyAllocated:
return "kIOUSBLowLatencyBufferNotPreviouslyAllocated";
case kIOUSBLowLatencyFrameListNotPreviouslyAllocated:
return "kIOUSBLowLatencyFrameListNotPreviouslyAllocated";
case kIOUSBHighSpeedSplitError:
return "kIOUSBHighSpeedSplitError";
case kIOUSBSyncRequestOnWLThread:
return "kIOUSBSyncRequestOnWLThread";
case kIOUSBLinkErr:
return "kIOUSBLinkErr";
case kIOUSBCRCErr:
return "kIOUSBCRCErr";
case kIOUSBNotSent1Err:
return "kIOUSBNotSent1Err";
case kIOUSBNotSent2Err:
return "kIOUSBNotSent2Err";
case kIOUSBBufferUnderrunErr:
return "kIOUSBBufferUnderrunErr";
case kIOUSBBufferOverrunErr:
return "kIOUSBBufferOverrunErr";
case kIOUSBReserved2Err:
return "kIOUSBReserved2Err";
case kIOUSBReserved1Err:
return "kIOUSBReserved1Err";
case kIOUSBWrongPIDErr:
return "kIOUSBWrongPIDErr";
case kIOUSBPIDCheckErr:
return "kIOUSBPIDCheckErr";
case kIOUSBDataToggleErr:
return "kIOUSBDataToggleErr";
case kIOUSBBitstufErr:
return "kIOUSBBitstufErr";
}
return "Unknown";
}