IOUSBController_Pipes.cpp [plain text]
#include <IOKit/system.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/IOCommandPool.h>
#include <IOKit/usb/IOUSBController.h>
#include <IOKit/usb/IOUSBLog.h>
#include "USBTracepoints.h"
#define super IOUSBBus
#define self this
#define _freeUSBCommandPool _expansionData->freeUSBCommandPool
#define _freeUSBIsocCommandPool _expansionData->freeUSBIsocCommandPool
#define CONTROLLER_PIPES_USE_KPRINTF 0
#if CONTROLLER_PIPES_USE_KPRINTF
#undef USBLog
#undef USBError
void kprintf(const char *format, ...)
__attribute__((format(printf, 1, 2)));
#define USBLog( LEVEL, FORMAT, ARGS... ) if ((LEVEL) <= CONTROLLER_PIPES_USE_KPRINTF) { kprintf( FORMAT "\n", ## ARGS ) ; }
#define USBError( LEVEL, FORMAT, ARGS... ) { kprintf( FORMAT "\n", ## ARGS ) ; }
#endif
IOReturn IOUSBController::OpenPipe(USBDeviceAddress address, UInt8 speed,
Endpoint *endpoint)
{
return _commandGate->runAction(DoCreateEP, (void *)(UInt32) address,
(void *)(UInt32) speed, endpoint);
}
IOReturn IOUSBController::ClosePipe(USBDeviceAddress address,
Endpoint * endpoint)
{
return _commandGate->runAction(DoDeleteEP, (void *)(UInt32) address,
(void *)(UInt32) endpoint->number, (void *)(UInt32) endpoint->direction);
}
IOReturn IOUSBController::AbortPipe(USBDeviceAddress address,
Endpoint * endpoint)
{
return _commandGate->runAction(DoAbortEP, (void *)(UInt32) address,
(void *)(UInt32) endpoint->number, (void *)(UInt32) endpoint->direction);
}
IOReturn IOUSBController::ResetPipe(USBDeviceAddress address,
Endpoint * endpoint)
{
return _commandGate->runAction(DoClearEPStall, (void *)(UInt32) address,
(void *)(UInt32) endpoint->number, (void *)(UInt32) endpoint->direction);
}
IOReturn IOUSBController::ClearPipeStall(USBDeviceAddress address,
Endpoint * endpoint)
{
return _commandGate->runAction(DoClearEPStall, (void *)(UInt32) address,
(void *)(UInt32) endpoint->number, (void *)(UInt32) endpoint->direction);
}
static void
DisjointCompletion(IOUSBController *me, IOUSBCommand *command, IOReturn status, UInt32 bufferSizeRemaining)
{
IOBufferMemoryDescriptor *buf = NULL;
IODMACommand *dmaCommand = NULL;
USBTrace_Start( kUSBTController, kTPControllerDisjointCompletion, (uintptr_t)me, (uintptr_t)command, status, bufferSizeRemaining );
if (!me || !command)
{
USBError(1, "DisjointCompletion sanity check failed - me(%p) command (%p)", me, command);
return;
}
buf = OSDynamicCast(IOBufferMemoryDescriptor, command->GetBuffer());
dmaCommand = command->GetDMACommand();
if (!dmaCommand || !buf)
{
USBLog(1, "%s[%p]::DisjointCompletion - no dmaCommand", me->getName(), me);
USBTrace( kUSBTController, kTPControllerDisjointCompletion, (uintptr_t)me, 0, 0, 1 );
return;
}
if (dmaCommand->getMemoryDescriptor())
{
if (dmaCommand->getMemoryDescriptor() != buf)
{
USBLog(1, "%s[%p]::DisjointCompletion - buf(%p) doesn't match getMemoryDescriptor(%p)", me->getName(), me, buf, dmaCommand->getMemoryDescriptor());
USBTrace( kUSBTController, kTPControllerDisjointCompletion, (uintptr_t)me, (uintptr_t)buf, (uintptr_t)dmaCommand->getMemoryDescriptor(), 2 );
}
USBLog(6, "%s[%p]::DisjointCompletion - clearing memory descriptor (%p) from dmaCommand (%p)", me->getName(), me, dmaCommand->getMemoryDescriptor(), dmaCommand);
dmaCommand->clearMemoryDescriptor();
}
if (command->GetDirection() == kUSBIn)
{
USBLog(5, "%s[%p]::DisjointCompletion, copying %d out of %d bytes to desc %p from buffer %p", me->getName(), me, (int)(command->GetDblBufLength()-bufferSizeRemaining), (int)command->GetDblBufLength(), command->GetOrigBuffer(), buf);
command->GetOrigBuffer()->writeBytes(0, buf->getBytesNoCopy(), (command->GetDblBufLength()-bufferSizeRemaining));
}
buf->complete();
buf->release(); command->SetBuffer(NULL);
IOUSBCompletion completion = command->GetDisjointCompletion();
USBLog(5, "%s[%p]::DisjointCompletion calling through to %p - status (%p)!", me->getName(), me, completion.action, (void*)status);
if (completion.action)
(*completion.action)(completion.target, completion.parameter, status, bufferSizeRemaining);
USBTrace_End( kUSBTController, kTPControllerDisjointCompletion, (uintptr_t)completion.target, (uintptr_t)completion.parameter, status, bufferSizeRemaining);
}
OSMetaClassDefineReservedUsed(IOUSBController, 17);
IOReturn
IOUSBController::CheckForDisjointDescriptor(IOUSBCommand *command, UInt16 maxPacketSize)
{
IOMemoryDescriptor *buf = command->GetBuffer();
IOBufferMemoryDescriptor *newBuf = NULL;
IOByteCount length = command->GetReqCount();
IODMACommand *dmaCommand = command->GetDMACommand();
IOByteCount segLength = 0;
IOByteCount offset = 0;
IOReturn err;
UInt64 offset64;
IODMACommand::Segment64 segment64;
UInt32 numSegments;
if ( length == 0 )
return kIOReturnSuccess;
if (!dmaCommand)
{
USBLog(1, "%s[%p]::CheckForDisjointDescriptor - no dmaCommand", getName(), this);
USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, kIOReturnBadArgument, 0, 1 );
return kIOReturnBadArgument;
}
if (dmaCommand->getMemoryDescriptor() != buf)
{
USBLog(1, "%s[%p]::CheckForDisjointDescriptor - mismatched memory descriptor (%p) and dmaCommand memory descriptor (%p)", getName(), this, buf, dmaCommand->getMemoryDescriptor());
USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, kIOReturnBadArgument, (uintptr_t)buf, (uintptr_t)dmaCommand->getMemoryDescriptor(), 2 );
return kIOReturnBadArgument;
}
while (length)
{
offset64 = offset;
numSegments = 1;
err = dmaCommand->gen64IOVMSegments(&offset64, &segment64, &numSegments);
if (err || (numSegments != 1))
{
USBLog(1, "%s[%p]::CheckForDisjointDescriptor - err (%p) trying to generate segments at offset (%Ld), length (%d), segLength (%d), total length (%d), buf (%p), numSegments (%d)", getName(), this, (void*)err, offset64, (int)length, (int)segLength, (int)command->GetReqCount(), buf, (int)numSegments);
USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, offset64, length, segLength, 3 );
USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, segLength, command->GetReqCount(), numSegments, 4 );
return kIOReturnBadArgument;
}
if (segment64.fLength >= length)
return kIOReturnSuccess;
segLength = (IOByteCount)segment64.fLength;
if (segLength % maxPacketSize)
{
USBLog(5, "%s[%p]::CheckForDisjointDescriptor - found a disjoint segment of length (%d) MPS (%d)", getName(), this, (int)segLength, maxPacketSize);
length = command->GetReqCount(); newBuf = IOBufferMemoryDescriptor::withOptions((command->GetDirection() == kUSBIn) ? kIODirectionIn : kIODirectionOut, length);
if (!newBuf)
{
USBLog(1, "%s[%p]::CheckForDisjointDescriptor - could not allocate new buffer", getName(), this);
USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, kIOReturnNoMemory, 0, 5 );
return kIOReturnNoMemory;
}
USBLog(5, "%s[%p]::CheckForDisjointDescriptor, obtained buffer %p of length %d", getName(), this, newBuf, (int)length);
USBLog(6, "%s[%p]::CheckForDisjointDescriptor, clearing memDec (%p) from dmaCommand (%p)", getName(), this, dmaCommand->getMemoryDescriptor(), dmaCommand);
dmaCommand->clearMemoryDescriptor();
if (command->GetDirection() == kUSBOut)
{
USBLog(7, "%s[%p]::CheckForDisjointDescriptor, copying %d bytes from desc %p to buffer %p", getName(), this, (int)length, buf, newBuf->getBytesNoCopy());
if (buf->readBytes(0, newBuf->getBytesNoCopy(), length) != length)
{
USBLog(1, "%s[%p]::CheckForDisjointDescriptor - bad copy on a write", getName(), this);
USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, 0, 0, 6 );
newBuf->release();
return kIOReturnNoMemory;
}
}
err = newBuf->prepare();
if (err)
{
USBLog(1, "%s[%p]::CheckForDisjointDescriptor - err 0x%x in prepare", getName(), this, err);
USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, err, 0, 7 );
newBuf->release();
return err;
}
err = dmaCommand->setMemoryDescriptor(newBuf);
if (err)
{
USBLog(1, "%s[%p]::CheckForDisjointDescriptor - err 0x%x in setMemoryDescriptor", getName(), this, err);
USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, err, 0, 8 );
newBuf->complete();
newBuf->release();
return err;
}
command->SetOrigBuffer(command->GetBuffer());
command->SetDisjointCompletion(command->GetClientCompletion());
USBLog(5, "%s[%p]::CheckForDisjointDescriptor - changing buffer from (%p) to (%p) and putting new buffer in dmaCommand (%p)", getName(), this, command->GetBuffer(), newBuf, dmaCommand);
command->SetBuffer(newBuf);
IOUSBCompletion completion;
completion.target = this;
completion.action = (IOUSBCompletionAction)DisjointCompletion;
completion.parameter = command;
command->SetClientCompletion(completion);
command->SetDblBufLength(length); return kIOReturnSuccess;
}
length -= segLength; offset += segLength;
}
USBLog(5, "%s[%p]::CheckForDisjointDescriptor - returning kIOReturnBadArgument(0x%x)", getName(), this, kIOReturnBadArgument);
return kIOReturnBadArgument;
}
IOReturn
IOUSBController::Read(IOMemoryDescriptor *buffer, USBDeviceAddress address, Endpoint *endpoint, IOUSBCompletion *completion)
{
USBLog(7, "%s[%p]::Read #1", getName(), this);
return Read(buffer, address, endpoint, completion, 0, 0);
}
OSMetaClassDefineReservedUsed(IOUSBController, 7);
IOReturn
IOUSBController::Read(IOMemoryDescriptor *buffer, USBDeviceAddress address, Endpoint *endpoint, IOUSBCompletion *completion, UInt32 noDataTimeout, UInt32 completionTimeout)
{
USBLog(7, "%s[%p]::Read #2", getName(), this);
if (!buffer)
{
USBLog(5, "%s[%p]::Read #2 - No Buffer, returning kIOReturnBadArgument(0x%x)", getName(), this, kIOReturnBadArgument);
return kIOReturnBadArgument;
}
return Read(buffer, address, endpoint, completion, noDataTimeout, completionTimeout, buffer->getLength());
}
OSMetaClassDefineReservedUsed(IOUSBController, 12);
IOReturn
IOUSBController::Read(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 - 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);
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;
}
IOReturn
IOUSBController::Write(IOMemoryDescriptor *buffer, USBDeviceAddress address, Endpoint *endpoint, IOUSBCompletion *completion)
{
USBLog(7, "%s[%p]::Write #1", getName(), this);
return Write(buffer, address, endpoint, completion, 0, 0);
}
OSMetaClassDefineReservedUsed(IOUSBController, 8);
IOReturn
IOUSBController::Write(IOMemoryDescriptor *buffer, USBDeviceAddress address, Endpoint *endpoint, IOUSBCompletion *completion, UInt32 noDataTimeout, UInt32 completionTimeout)
{
USBLog(7, "%s[%p]::Write #2", getName(), this);
if (!buffer)
{
USBLog(5, "%s[%p]::Write #2 - No buffer!. Returning kIOReturnBadArgument(0x%x)", getName(), this, kIOReturnBadArgument);
return kIOReturnBadArgument;
}
return Write(buffer, address, endpoint, completion, noDataTimeout, completionTimeout, buffer->getLength());
}
OSMetaClassDefineReservedUsed(IOUSBController, 13);
IOReturn
IOUSBController::Write(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 - 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);
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;
}
IOReturn
IOUSBController::IsocIO(IOMemoryDescriptor * buffer,
UInt64 frameStart,
UInt32 numFrames,
IOUSBIsocFrame * frameList,
USBDeviceAddress address,
Endpoint * endpoint,
IOUSBIsocCompletion * completion)
{
IOReturn err = kIOReturnSuccess;
IOUSBIsocCommand * command;
bool crossEndianRequest = false;
IODMACommand * dmaCommand = NULL;
bool syncTransfer = false;
if (completion == 0)
{
USBLog(5, "%s[%p]::IsocIO - No completion. Returning kIOReturnNoCompletion(0x%x)", getName(), this, kIOReturnNoCompletion);
return kIOReturnNoCompletion;
}
if (_commandGate == 0)
{
USBLog(5, "%s[%p]::IsocIO - Could not get _commandGate. Returning kIOReturnInternalError(0x%x)", getName(), this, kIOReturnInternalError);
return kIOReturnInternalError;
}
if ( endpoint->direction & 0x80 )
{
endpoint->direction &= ~0x80;
crossEndianRequest = true;
}
if ( (endpoint->direction != kUSBOut) && ( endpoint->direction != kUSBIn) )
{
USBLog(5, "%s[%p]::IsocIO - Direction is not kUSBOut or kUSBIn (%d). Returning kIOReturnBadArgument(0x%x)", getName(), this, endpoint->direction, kIOReturnBadArgument);
return kIOReturnBadArgument;
}
if ( completion->action == &IOUSBSyncIsoCompletion )
{
syncTransfer = true;
if ( _workLoop->onThread() )
{
USBError(1,"IOUSBController(%s)[%p]::DoIsocTransfer sync request on workloop thread. Use async!", getName(), this);
return kIOUSBSyncRequestOnWLThread;
}
}
command = (IOUSBIsocCommand *)_freeUSBIsocCommandPool->getCommand(false);
if ( command == NULL )
{
IncreaseIsocCommandPool();
command = (IOUSBIsocCommand *)_freeUSBIsocCommandPool->getCommand(false);
if ( command == NULL )
{
USBLog(3,"%s[%p]::IsocIO Could not get a IOUSBIsocCommand",getName(),this);
return kIOReturnNoResources;
}
}
dmaCommand = command->GetDMACommand();
if (!dmaCommand)
{
USBLog(1, "%s[%p]::IsocIO no IODMACommand in the IOUSBCommand", getName(), this);
USBTrace( kUSBTController, kTPIsocIO, (uintptr_t)this, kIOReturnNoResources, 0, 1 );
return kIOReturnNoResources;
}
USBLog(7, "%s[%p]::IsocIO - putting buffer (%p) into dmaCommand (%p) which has getMemoryDescriptor (%p)", getName(), this, buffer, command->GetDMACommand(), command->GetDMACommand()->getMemoryDescriptor());
err = dmaCommand->setMemoryDescriptor(buffer); if (err)
{
USBLog(1, "%s[%p]::IsocIO - dmaCommand[%p]->setMemoryDescriptor(%p) failed with status (%p)", getName(), this, command->GetDMACommand(), buffer, (void*)err);
USBTrace( kUSBTController, kTPIsocIO, (uintptr_t)this, err, 0, 2 );
_freeUSBIsocCommandPool->returnCommand(command);
return err;
}
command->SetRosettaClient(crossEndianRequest);
command->SetIsSyncTransfer(syncTransfer);
if (endpoint->direction == kUSBOut)
{
command->SetSelector(WRITE);
command->SetDirection(kUSBOut);
}
else if (endpoint->direction == kUSBIn)
{
command->SetSelector(READ);
command->SetDirection(kUSBIn);
}
command->SetUseTimeStamp(false);
command->SetAddress(address);
command->SetEndpoint(endpoint->number);
command->SetBuffer(buffer);
command->SetCompletion(*completion);
command->SetStartFrame(frameStart);
command->SetNumFrames(numFrames);
command->SetFrameList(frameList);
command->SetStatus(kIOReturnBadArgument);
command->SetLowLatency(false);
err = _commandGate->runAction(DoIsocTransfer, command);
if ( syncTransfer || (kIOReturnSuccess != err) )
{
IODMACommand *dmaCommand = command->GetDMACommand();
IOMemoryDescriptor *memDesc = dmaCommand ? (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor() : NULL;
if (memDesc)
{
USBLog(7, "%s[%p]::IsocIO - sync xfer or err return - clearing memory descriptor (%p) from dmaCommand (%p)", getName(), this, memDesc, dmaCommand);
dmaCommand->clearMemoryDescriptor();
}
_freeUSBIsocCommandPool->returnCommand(command);
}
return err;
}
OSMetaClassDefineReservedUsed(IOUSBController, 15);
IOReturn
IOUSBController::IsocIO(IOMemoryDescriptor * buffer,
UInt64 frameStart,
UInt32 numFrames,
IOUSBLowLatencyIsocFrame * frameList,
USBDeviceAddress address,
Endpoint * endpoint,
IOUSBLowLatencyIsocCompletion * completion,
UInt32 updateFrequency)
{
IOReturn err = kIOReturnSuccess;
IOUSBIsocCommand * command = NULL;
bool crossEndianRequest = false;
IODMACommand * dmaCommand = NULL;
bool syncTransfer = false;
USBLog(7, "%s[%p]::IsocIO(LL)", getName(), this);
if (completion == 0)
{
USBLog(1, "%s[%p]::IsocIO(LL) - No completion. Returning kIOReturnNoCompletion(0x%x)", getName(), this, kIOReturnNoCompletion);
USBTrace( kUSBTController, kTPIsocIOLL, (uintptr_t)this, kIOReturnNoCompletion, 0, 3 );
return kIOReturnNoCompletion;
}
if (_commandGate == 0)
{
USBLog(1, "%s[%p]::IsocIO(LL) - Could not get _commandGate. Returning kIOReturnInternalError(0x%x)", getName(), this, kIOReturnInternalError);
USBTrace( kUSBTController, kTPIsocIOLL, (uintptr_t)this, kIOReturnInternalError, 0, 4 );
return kIOReturnInternalError;
}
if ( endpoint->direction & 0x80 )
{
endpoint->direction &= ~0x80;
crossEndianRequest = true;
}
if ( (endpoint->direction != kUSBOut) && ( endpoint->direction != kUSBIn) )
{
USBLog(1, "%s[%p]::IsocIO(LL) - Direction is not kUSBOut or kUSBIn (%d). Returning kIOReturnBadArgument(0x%x)", getName(), this, endpoint->direction, kIOReturnBadArgument);
USBTrace( kUSBTController, kTPIsocIOLL, (uintptr_t)this, endpoint->direction, kIOReturnBadArgument, 6 );
return kIOReturnBadArgument;
}
if ( (uintptr_t)completion->action == (uintptr_t)&IOUSBSyncIsoCompletion )
{
syncTransfer = true;
if ( _workLoop->onThread() )
{
USBError(1,"IOUSBController(%s)[%p]::DoIsocTransfer sync request on workloop thread. Use async!", getName(), this);
return kIOUSBSyncRequestOnWLThread;
}
}
command = (IOUSBIsocCommand *)_freeUSBIsocCommandPool->getCommand(false);
if ( command == NULL )
{
IncreaseIsocCommandPool();
command = (IOUSBIsocCommand *)_freeUSBIsocCommandPool->getCommand(false);
if ( command == NULL )
{
USBLog(1, "%s[%p]::IsocIO(LL) Could not get a IOUSBIsocCommand", getName(), this);
USBTrace( kUSBTController, kTPIsocIOLL, (uintptr_t)this, kIOReturnNoResources, 0, 5 );
return kIOReturnNoResources;
}
}
dmaCommand = command->GetDMACommand();
if (!dmaCommand)
{
USBLog(1, "%s[%p]::IsocIO(LL) no IODMACommand in the IOUSBCommand", getName(), this);
USBTrace( kUSBTController, kTPIsocIOLL, (uintptr_t)this, kIOReturnNoResources, 0, 1 );
return kIOReturnNoResources;
}
USBLog(7, "%s[%p]::IsocIO(LL) - putting buffer %p into dmaCommand %p which has getMemoryDescriptor %p", getName(), this, buffer, command->GetDMACommand(), command->GetDMACommand()->getMemoryDescriptor());
err = dmaCommand->setMemoryDescriptor(buffer); if (err)
{
USBLog(1, "%s[%p]::IsocIO(LL) - dmaCommand[%p]->setMemoryDescriptor(%p) failed with status (%p)", getName(), this, command->GetDMACommand(), buffer, (void*)err);
USBTrace( kUSBTController, kTPIsocIOLL, (uintptr_t)this, err, 0, 2 );
_freeUSBIsocCommandPool->returnCommand(command);
return err;
}
command->SetRosettaClient(crossEndianRequest);
command->SetIsSyncTransfer(syncTransfer);
if (endpoint->direction == kUSBOut)
{
command->SetSelector(WRITE);
command->SetDirection(kUSBOut);
}
else if (endpoint->direction == kUSBIn)
{
command->SetSelector(READ);
command->SetDirection(kUSBIn);
}
command->SetUseTimeStamp(false);
command->SetAddress(address);
command->SetEndpoint(endpoint->number);
command->SetBuffer(buffer);
command->SetCompletion( * ((IOUSBIsocCompletion *) completion) );
command->SetStartFrame(frameStart);
command->SetNumFrames(numFrames);
command->SetFrameList( (IOUSBIsocFrame *) frameList);
command->SetStatus(kIOReturnBadArgument);
command->SetUpdateFrequency(updateFrequency);
command->SetLowLatency(true);
err = _commandGate->runAction(DoIsocTransfer, command);
if ( syncTransfer || (kIOReturnSuccess != err) )
{
IODMACommand *dmaCommand = command->GetDMACommand();
IOMemoryDescriptor *memDesc = dmaCommand ? (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor() : NULL;
if (memDesc)
{
USBLog(7, "%s[%p]::IsocIO(LL) - sync xfer or err return - clearing memory descriptor (%p) from dmaCommand (%p)", getName(), this, memDesc, dmaCommand);
dmaCommand->clearMemoryDescriptor();
}
_freeUSBIsocCommandPool->returnCommand(command);
}
return err;
}