IOUSBIsocCommand* IOUSBIsocCommand::NewCommand() { IOUSBIsocCommand *me = new IOUSBIsocCommand; if (me && !me->init()) { me->release(); me = NULL; } return me; }
IOReturn IOUSBCommandPool::gatedReturnCommand(IOCommand * command) { IOUSBCommand *usbCommand = OSDynamicCast(IOUSBCommand, command); // only one of these should be non-null IOUSBIsocCommand *isocCommand = OSDynamicCast(IOUSBIsocCommand, command); USBLog(7,"IOUSBCommandPool[%p]::gatedReturnCommand %p", this, command); if (!command) { #if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION panic("IOUSBCommandPool::gatedReturnCommand( NULL )"); #endif return kIOReturnBadArgument; } if (command->fCommandChain.next && (&command->fCommandChain != command->fCommandChain.next || &command->fCommandChain != command->fCommandChain.prev)) { #if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION kprintf("WARNING: gatedReturnCommand(%p) already on queue [next=%p prev=%p]\n", command, command->fCommandChain.next, command->fCommandChain.prev); panic("IOUSBCommandPool::gatedReturnCommand already on queue"); #endif char* bt[8]; OSBacktrace((void**)bt, 8); USBError(1,"IOUSBCommandPool::gatedReturnCommand command already in queue, not putting it back into the queue, bt: [%p][%p][%p][%p][%p][%p][%p][%p]", bt[0], bt[1], bt[2], bt[3], bt[4], bt[5], bt[6], bt[7]); return kIOReturnBadArgument; } if (usbCommand) { IODMACommand *dmaCommand = usbCommand->GetDMACommand(); if (dmaCommand) { if (dmaCommand->getMemoryDescriptor()) { USBError(1, "IOUSBCommandPool::gatedReturnCommand - command (%p) still has dmaCommand(%p) with an active memory descriptor(%p)", usbCommand, dmaCommand, dmaCommand->getMemoryDescriptor()); #if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION panic("IOUSBCommandPool::gatedReturnCommand -dmaCommand still has active IOMD"); #endif } } else { USBError(1,"IOUSBCommandPool::gatedReturnCommand - missing dmaCommand in IOUSBCommand"); } // Test to poison the IOUSBCommand when returning it #if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION { char* bt[kUSBCommandScratchBuffers]; OSBacktrace((void**)bt, kUSBCommandScratchBuffers); for ( int i=0; i < kUSBCommandScratchBuffers; i++) usbCommand->SetBT(i, bt[i]); } #endif // Clean up the command before returning it IOUSBCompletion nullCompletion; nullCompletion.target = (void *) POISONVALUE; nullCompletion.action = (IOUSBCompletionAction) NULL; nullCompletion.parameter = (void *) POISONVALUE; usbCommand->SetSelector(INVALID_SELECTOR); usbCommand->SetRequest((IOUSBDeviceRequestPtr) POISONVALUE); usbCommand->SetAddress(0xFF); usbCommand->SetEndpoint(0xFF); usbCommand->SetDirection(0xFF); usbCommand->SetType(0xFF); usbCommand->SetBufferRounding(false); usbCommand->SetBuffer((IOMemoryDescriptor *) POISONVALUE); usbCommand->SetUSLCompletion(nullCompletion); usbCommand->SetClientCompletion(nullCompletion); usbCommand->SetDataRemaining(POISONVALUE); usbCommand->SetStage(0xFF); usbCommand->SetStatus(POISONVALUE); usbCommand->SetOrigBuffer((IOMemoryDescriptor *) POISONVALUE); usbCommand->SetDisjointCompletion(nullCompletion); usbCommand->SetDblBufLength(POISONVALUE); usbCommand->SetNoDataTimeout(POISONVALUE); usbCommand->SetCompletionTimeout(POISONVALUE); usbCommand->SetReqCount(POISONVALUE); usbCommand->SetMultiTransferTransaction(true); usbCommand->SetFinalTransferInTransaction(true); usbCommand->SetUseTimeStamp(true); usbCommand->SetIsSyncTransfer(FALSE); for ( int i=0; i < kUSBCommandScratchBuffers; i++) usbCommand->SetUIMScratch(i, POISONVALUE); usbCommand->SetStreamID(POISONVALUE); if ( usbCommand->GetBufferUSBCommand() != NULL ) { USBError(1,"IOUSBCommandPool::gatedReturnCommand - GetBufferUSBCommand() is not NULL"); } if ( usbCommand->GetRequestMemoryDescriptor() != NULL ) { USBError(1,"IOUSBCommandPool::gatedReturnCommand - GetRequestMemoryDescriptor() is not NULL"); } if ( usbCommand->GetBufferMemoryDescriptor() != NULL ) { USBError(1,"IOUSBCommandPool::gatedReturnCommand - GetBufferMemoryDescriptor() is not NULL"); } // Do not see these to anything but NULL as a lot of the code depends on checking for NULLness usbCommand->SetBufferUSBCommand(NULL); usbCommand->SetRequestMemoryDescriptor(NULL); usbCommand->SetBufferMemoryDescriptor(NULL); } if (isocCommand) { IODMACommand *dmaCommand = isocCommand->GetDMACommand(); if (dmaCommand) { if (dmaCommand->getMemoryDescriptor()) { USBError(1, "IOUSBCommandPool::gatedReturnCommand - isocCommand (%p) still has dmaCommand(%p) with an active memory descriptor(%p)", isocCommand, dmaCommand, dmaCommand->getMemoryDescriptor()); #if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION panic("IOUSBCommandPool::gatedReturnCommand - dmaCommand still has active IOMD (isoc)"); #endif } } else { USBError(1,"IOUSBCommandPool::gatedReturnCommand - missing dmaCommand in IOUSBIsocCommand"); } } return IOCommandPool::gatedReturnCommand(command); }
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; // Validate the completion // 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; } // Validate the commandGate // 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 the high order bit of the endpoint transfer type is set, then this means it's a request from an Rosetta client if ( endpoint->direction & 0x80 ) { endpoint->direction &= ~0x80; crossEndianRequest = true; } // Validate the direction of the endpoint -- it has to be kUSBIn or kUSBOut 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 we couldn't get a command, increase the allocation and try again // 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); // this automatically calls prepare() 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; } // If the high order bit of the endpoint transfer type is set, then this means it's a request from an Rosetta client command->SetRosettaClient(crossEndianRequest); command->SetIsSyncTransfer(syncTransfer); // Setup the direction 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 we have a sync request, then we always return the command after the DoIsocTransfer. If it's an async request, we only return it if // we get an immediate error // 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; }