diff -r 72a7468afdd4 -r 01c1ffcc4fca baseport/syborg/soundsc/virtio_audio.cpp --- /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( 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( alignedMem ); + iBufferInfo = reinterpret_cast( 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( 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