--- /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