baseport/syborg/soundsc/virtio_audio.cpp
changeset 45 01c1ffcc4fca
child 71 d00bf4f57250
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/baseport/syborg/soundsc/virtio_audio.cpp	Thu Mar 04 00:55:21 2010 +0000
@@ -0,0 +1,158 @@
+/*
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Accenture Ltd
+*
+* Contributors:
+*
+* Description: This file is a part of sound driver for Syborg adaptation.
+*
+*/
+
+#include "virtio_audio.h"
+
+namespace VirtIo
+{
+namespace Audio
+{
+
+DControl::~DControl()
+	{
+	if (iCmdMem)
+		{ Kern::Free( iCmdMem ); }
+	}
+
+TInt DControl::Construct()
+	{
+	TUint cmdSize = sizeof(iCmd[0])*KCmdMaxBufCount;
+	TUint size = cmdSize + sizeof(*iBufferInfo);
+	// as we are going to align the allocated memory
+	// we add extra alignment size minus 1
+	iCmdMem = reinterpret_cast<TUint8*>( Kern::Alloc( size + sizeof(iCmd[0])-1 ) );
+	if (!iCmdMem)
+		{ return KErrNoMemory; }
+		
+	// let us align the memory address 
+	// note: sizeof(iCmd[0]) is a power of 2
+	ASSERT( sizeof(iCmd[0]) == POW2ALIGN(sizeof(iCmd[0])) );
+	TUint8* alignedMem = iCmdMem 
+		+ ( (-(TUint32)iCmdMem)&(sizeof(iCmd[0])-1) ); // adding missing amount of bytes
+	
+	iCmd = reinterpret_cast<TCommandPadded*>( alignedMem );
+	iBufferInfo = reinterpret_cast<TBufferInfo*>( alignedMem + cmdSize );
+	
+	for (TUint i = 0; i< KCmdMaxBufCount; ++i)
+		{
+		iCmd[i].iStream = iDataQueueId - 1;
+		}	
+	iCmd[0].iCommand = Audio::ECmdSetEndian;
+	iCmd[1].iCommand = Audio::ECmdSetChannels;
+	iCmd[2].iCommand = Audio::ECmdSetFormat;
+	iCmd[3].iCommand = Audio::ECmdSetFrequency;
+	iCmd[4].iCommand = Audio::ECmdInit;
+	iCmd[5].iCommand = Audio::ECmdRun;
+	iCmd[5].iArg = Audio::EDoRun; //start stream
+	iCmd[6].iCommand = Audio::ECmdRun;
+	iCmd[6].iArg = Audio::EDoStop; //stop stream		
+	iCmd[7].iCommand = Audio::ECmdRun;
+	iCmd[7].iArg = Audio::EDoStop; //kind of pause
+	iCmd[8].iCommand = Audio::ECmdRun;
+	iCmd[8].iArg = Audio::EDoRun; //kind of resume
+	return KErrNone;
+	}
+
+TInt DControl::Setup( StreamDirection aDirection, TInt aChannelNum, 
+	FormatId aFormat, TInt aFreq)
+	{
+	iCmd[1].iArg = aChannelNum;
+	iCmd[2].iArg = aFormat;
+	iCmd[3].iArg = aFreq;		
+	iCmd[4].iArg = iDirection = aDirection;		
+	AddCommand(&iCmd[0],(Token)0);
+	AddCommand(&iCmd[1],(Token)1);
+	AddCommand(&iCmd[2],(Token)2);
+	AddCommand(&iCmd[3],(Token)3);
+	AddCommand(&iCmd[4],(Token)4, iBufferInfo, sizeof(*iBufferInfo) );
+	ControlQueue().Sync();
+	return KErrNone;
+	}
+	
+void DControl::AddCommand( TCommandPadded* aCmd, Token aToken )
+	{
+	TAddrLen list;
+	list.iLen = sizeof(TCommand);
+	list.iAddr = Epoc::LinearToPhysical((TUint32)aCmd);
+	SYBORG_VIRTIO_DEBUG("AddCommand %x %x %x", aCmd->iCommand, aCmd->iStream, aCmd->iArg);
+	ControlQueue().AddBuf(&list, 1, 0, aToken );
+	}
+
+void DControl::AddCommand( TCommandPadded* aCmd, Token aToken, 
+	TAny* aMem, TUint aSize )
+	{
+	TAddrLen list[2];
+	list[0].iLen = sizeof(TCommand);
+	list[0].iAddr = Epoc::LinearToPhysical((TUint32)aCmd);
+	list[1].iLen = aSize;
+	list[1].iAddr = Epoc::LinearToPhysical((TUint32)aMem);
+	ControlQueue().AddBuf(list, 1, 1, aToken );
+	}
+	
+	
+// Waits until device processes all pending requests
+// there would be no need to have it here at all 
+// if there was no bug in qemu:
+// once you send stop command the buffers processing stops... but the buffers are never returned.
+
+void DControl::WaitForCompletion()
+	{
+	SYBORG_VIRTIO_DEBUG("DControl::WaitForCompletion : {");
+
+	TInt st = Kern::PollingWait( &DControl::CheckProcessing, this, 10, 100 );
+	ASSERT ( (st == KErrNone) && "Polling problem" )
+	
+	SYBORG_VIRTIO_DEBUG("DControlWaitForCompletion : }");
+	}
+
+TBool DControl::CheckProcessing( TAny* aSelf )
+	{
+	DControl* self = reinterpret_cast<DControl*>( aSelf );
+	return self->DataQueue().Processing() == 0;
+	}
+	
+void DControl::AddCommand( Command aCmd )
+	{
+	TUint idx = aCmd;
+	if (aCmd == EStop)
+		{
+		// due to bug on qemu's side we need to stop sending buffers
+		// and wait for all pending buffers to get filled...
+		WaitForCompletion();
+		}
+	AddCommand(&iCmd[idx], (Token)idx );
+	}
+
+TInt DControl::SendDataBuffer( TAny* virtaulAddr, TUint aSize, Token aToken )
+	{
+	TAddrLen sgl[KMaxSGLItemCountPerAudioBuffer];
+	TUint sglCount = KMaxSGLItemCountPerAudioBuffer;
+	TInt st = LinearToSGL(virtaulAddr, aSize, sgl, sglCount );
+	ASSERT( st != KErrNoMemory ); // failure means our fixed lenght sgl table is too small
+	if (st!=KErrNone)
+		{ return st; }
+	st = DataQueue().AddBuf( sgl, 
+		iDirection == EDirectionPlayback ? sglCount : 0,
+		iDirection == EDirectionRecord ? sglCount : 0,
+		aToken );
+	if (st!=KErrNone)
+		{ return st; }
+	DataQueue().Sync();
+	return KErrNone;
+	}
+	
+
+} // namespace Audio
+} // namespace VirtIo