示例#1
0
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;
}