--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/baseport/syborg/soundsc/bld.inf Thu Mar 04 00:55:21 2010 +0000
@@ -0,0 +1,5 @@
+PRJ_PLATFORMS
+ARMV5
+
+PRJ_MMPFILES
+soundsc.mmp
--- a/baseport/syborg/soundsc/shared_sound.h Sat Feb 27 19:18:04 2010 +0000
+++ b/baseport/syborg/soundsc/shared_sound.h Thu Mar 04 00:55:21 2010 +0000
@@ -1,6 +1,4 @@
/*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
-* All rights reserved.
* 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
@@ -10,8 +8,9 @@
* Nokia Corporation - initial contribution.
*
* Contributors:
+* Accenture Ltd
*
-* Description:
+* Description: This file is a part of sound driver for Syborg adaptation.
*
*/
@@ -20,19 +19,36 @@
#include <soundsc.h>
-#ifdef _DEBUG
+#ifdef _ENABLE_SYBORG_AUDIO_DRIVER_DEBUG
#define SYBORG_SOUND_DEBUG(x...) Kern::Printf(x)
#else
#define SYBORG_SOUND_DEBUG(x...)
#endif
+#undef ASSERT
+#define ASSERT(x) (x) || (Kern::Printf("Sound.pdd: ASSERTION FAILED: "#x),0);
+
+#include "virtio_audio.h"
+#include "virtio.h"
+#include "virtio_audio_defs.h"
+
+/// @brief defines the maximum size for a single audio data transfer
+static const TInt KMaxTransferLength = 128 * 1024;
+
+namespace VirtIo
+{
+class DIoHandler;
+}
+
class DDriverSyborgSoundScPddFactory;
-class DDriverSyborgSoundScPdd : public DSoundScPdd
+
+class DDriverSyborgSoundScPdd : public DSoundScPdd, VirtIo::MIoCallback
{
public:
- DDriverSyborgSoundScPdd();
+ DDriverSyborgSoundScPdd(DDriverSyborgSoundScPddFactory* aPhysicalDevice,
+ TInt aUnitType, VirtIo::DIoHandler *aIoHandler, TUint aDataQueueId);
~DDriverSyborgSoundScPdd();
TInt DoCreate();
void GetChunkCreateInfo(TChunkCreateInfo& aChunkCreateInfo);
@@ -48,48 +64,35 @@
TInt PowerUp();
void PowerDown();
TInt CustomConfig(TInt aFunction, TAny* aParam);
- void Callback(TUint aTransferID, TInt aTransferResult, TInt aBytesTransferred);
-
void SetCaps();
- // There was a change in the signature for DfcQ() which
- // is a pure virtual method in the parent.
- // for Symbian^2
- TDfcQue* DfcQ();
- // for Symbian^3
- TDfcQue* DfcQ(TInt aUnit);
+ TDfcQue* DfcQ();
+ TDfcQue* DfcQ( TInt aUnit );
TInt CalculateBufferTime(TInt aNumBytes);
+private:
+
+ // implementation of VirtIo::MIoCallback
+ virtual TBool VirtIoCallback( VirtIo::MIoHandler& aVirtIoHandler, VirtIo::MQueue& aQueue,
+ VirtIo::Token aToken, TUint aBytesTransferred );
public:
DDriverSyborgSoundScPddFactory* iPhysicalDevice;
- class TTransferArrayInfo{
+ TInt iUnitType; //Play or Record
-public:
- TUint iTransferID;
- TLinAddr iLinAddr;
- TInt iNumBytes;
- TInt iPlayTime;
- };
+ VirtIo::MIoHandler* iIoHandler;
- RArray<TTransferArrayInfo> iTransferArray;
-
- NTimer iTimer;
-
- TInt iUnitType; //Play or Record
+ TUint iDataQueueId;
private:
TSoundFormatsSupportedV02 iCaps;
TCurrentSoundFormatV02 iConfig;
+
+ VirtIo::Audio::DControl* iAudioControl;
-
-
};
-
-
-
#endif
--- a/baseport/syborg/soundsc/shared_txsound.cpp Sat Feb 27 19:18:04 2010 +0000
+++ b/baseport/syborg/soundsc/shared_txsound.cpp Thu Mar 04 00:55:21 2010 +0000
@@ -1,6 +1,4 @@
/*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
-* All rights reserved.
* 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
@@ -10,41 +8,91 @@
* Nokia Corporation - initial contribution.
*
* Contributors:
+* Accenture Ltd
*
-* Description:
+* Description: This file is a part of sound driver for Syborg adaptation.
*
*/
#include "shared_sound.h"
#include "variant_sound.h"
+#include "../specific/syborg.h"
-void TimerCallback(TAny* aData)
+#include "virtio.h"
+#include "virtio_audio.h"
+#include "virtio_iohandler.h"
+
+using namespace VirtIo;
+
+static TInt GetSampleRate( TSoundRate aRate)
{
- DDriverSyborgSoundScPdd * soundscpdd = (DDriverSyborgSoundScPdd*) aData;
-
- soundscpdd->Callback(soundscpdd->iTransferArray[0].iTransferID, KErrNone, soundscpdd->iTransferArray[0].iNumBytes);
-
+ switch(aRate)
+ {
+ case ESoundRate7350Hz: return 7350;
+ case ESoundRate8000Hz: return 8000;
+ case ESoundRate8820Hz: return 8820;
+ case ESoundRate9600Hz: return 9600;
+ case ESoundRate11025Hz: return 11025;
+ case ESoundRate12000Hz: return 12000;
+ case ESoundRate14700Hz: return 14700;
+ case ESoundRate16000Hz: return 16000;
+ case ESoundRate22050Hz: return 22050;
+ case ESoundRate24000Hz: return 24000;
+ case ESoundRate29400Hz: return 29400;
+ case ESoundRate32000Hz: return 32000;
+ case ESoundRate44100Hz: return 44100;
+ case ESoundRate48000Hz: return 48000;
+ }
+ return KErrNotFound;
}
+static TInt GetSoundEncoding( TSoundEncoding aV )
+ {
+ switch (aV)
+ {
+ case ESoundEncoding8BitPCM: return Audio::EFormatS8;
+ case ESoundEncoding16BitPCM: return Audio::EFormatS16;
+ case ESoundEncoding24BitPCM: break; // not supported
+ }
+ return -KErrNotFound;
+ }
+static TInt GetChannels( TInt aV )
+ {
+ switch (aV)
+ {
+ case KSoundMonoChannel: return 1;
+ case KSoundStereoChannel: return 2;
+ }
+ return KErrNotFound;
+ }
-DDriverSyborgSoundScPdd::DDriverSyborgSoundScPdd() : iTimer(TimerCallback,this)
+DDriverSyborgSoundScPdd::DDriverSyborgSoundScPdd(DDriverSyborgSoundScPddFactory* aPhysicalDevice,
+ TInt aUnitType, VirtIo::DIoHandler* aIoHandler, TUint aDataQueueId )
+ : iPhysicalDevice(aPhysicalDevice), iUnitType(aUnitType), iIoHandler( aIoHandler ), iDataQueueId( aDataQueueId )
{
-
}
DDriverSyborgSoundScPdd::~DDriverSyborgSoundScPdd()
{
- iTimer.Cancel();
+ SYBORG_SOUND_DEBUG("~DDriverSyborgSoundScPdd()");
+ iIoHandler->UnregisterClient( this );
+ delete iAudioControl;
+ SYBORG_SOUND_DEBUG("~DDriverSyborgSoundScPdd() - done");
}
-
TInt DDriverSyborgSoundScPdd::DoCreate()
{
-
SetCaps();
+
+ SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::DoCreate TxPdd");
- SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::DoCreate TxPdd");
+ SYBORG_SOUND_DEBUG("Registering with IOHandler %x", iIoHandler );
+ iIoHandler->RegisterClient( this );
+ SYBORG_SOUND_DEBUG("Registered with IoHandler... Done %x", iIoHandler);
+ iAudioControl = new Audio::DControl( *iIoHandler, iDataQueueId );
+ iAudioControl->Construct();
+
return KErrNone;
}
@@ -60,7 +108,6 @@
void DDriverSyborgSoundScPdd::Caps(TDes8& aCapsBuf) const
{
-
SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::Caps TxPdd");
// Fill the structure with zeros in case it is a newer version than we know about
@@ -73,14 +120,40 @@
TInt DDriverSyborgSoundScPdd::SetConfig(const TDesC8& aConfigBuf)
{
-
SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::SetConfig TxPdd");
// Read the new configuration from the LDD
TCurrentSoundFormatV02 config;
TPtr8 ptr((TUint8*) &config, sizeof(config));
Kern::InfoCopy(ptr, aConfigBuf);
+
+ TInt channels = GetChannels(config.iChannels);
+ Audio::FormatId encoding = static_cast<Audio::FormatId>( GetSoundEncoding(config.iEncoding) );
+ TInt freq = GetSampleRate(config.iRate);
+ Audio::StreamDirection direction = static_cast<Audio::StreamDirection>(
+ (iUnitType == KSoundScRxUnit0)?Audio::EDirectionRecord
+ :(iUnitType == KSoundScTxUnit0)?Audio::EDirectionPlayback:-1 );
+ SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::SetConfig c %x, e %x, f %x, d %x",
+ channels, encoding, freq, direction );
+
+ if ( (channels < 0 )
+ || ( encoding < 0 )
+ || ( freq < 0 )
+ || ( direction < 0 )
+ )
+ {
+ SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::SetConfig failed");
+ return KErrArgument;
+ }
+
+ TInt st = iAudioControl->Setup( direction, channels, encoding, freq );
+ if (st !=KErrNone)
+ {
+ SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::SetConfig failed %d", st);
+ return st;
+ }
+
iConfig = config;
return KErrNone;
@@ -89,7 +162,6 @@
TInt DDriverSyborgSoundScPdd::SetVolume(TInt aVolume)
{
-
SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::Setvolume TxPdd");
return KErrNone;
@@ -98,45 +170,19 @@
TInt DDriverSyborgSoundScPdd::StartTransfer()
{
-
- SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::starttransfer TxPdd");
+ SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::starttransfer TxPdd S");
+ iAudioControl->SendCommand( Audio::DControl::ERun );
+ return KErrNone;
+ }
- //Prepare for transfer
- return KErrNone;
- }
-
TInt DDriverSyborgSoundScPdd::CalculateBufferTime(TInt aNumBytes)
{
-
- TUint samplerate=0;
-
- // Let the compiler perform an integer division of rates
- switch(iConfig.iRate)
- {
- case ESoundRate7350Hz: samplerate = 7350; break;
- case ESoundRate8000Hz: samplerate = 8000; break;
- case ESoundRate8820Hz: samplerate = 8820; break;
- case ESoundRate9600Hz: samplerate = 9600; break;
- case ESoundRate11025Hz: samplerate = 11025; break;
- case ESoundRate12000Hz: samplerate = 12000; break;
- case ESoundRate14700Hz: samplerate = 14700; break;
- case ESoundRate16000Hz: samplerate = 16000; break;
- case ESoundRate22050Hz: samplerate = 22050; break;
- case ESoundRate24000Hz: samplerate = 24000; break;
- case ESoundRate29400Hz: samplerate = 29400; break;
- case ESoundRate32000Hz: samplerate = 32000; break;
- case ESoundRate44100Hz: samplerate = 44100; break;
- case ESoundRate48000Hz: samplerate = 48000; break;
- }
-
+ TUint samplerate=GetSampleRate( iConfig.iRate );
// integer division by number of channels
aNumBytes /= iConfig.iChannels;
- SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::iChannels =%d", iConfig.iChannels);
- SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::iEncoding =%d", iConfig.iEncoding);
-
// integer division by bytes per sample
switch(iConfig.iEncoding)
{
@@ -146,55 +192,31 @@
}
return (aNumBytes * 1000) / samplerate; //return time in milliseconds
-
-
}
-TInt DDriverSyborgSoundScPdd::TransferData(TUint aTransferID, TLinAddr aLinAddr, TPhysAddr /*aPhysAddr*/, TInt aNumBytes)
+TInt DDriverSyborgSoundScPdd::TransferData(TUint aTransferID, TLinAddr aLinAddr, TPhysAddr aPhysAddr, TInt aNumBytes)
{
-
- //function wil get called multiple times while transfer is in progress therefore keep fifo queue of requests
- TTransferArrayInfo transfer;
-
- transfer.iTransferID = aTransferID;
- transfer.iLinAddr = aLinAddr;
- transfer.iNumBytes = aNumBytes;
+ SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::TransferData unit %x aTId=%x, linAddr=%x,phAddr=%x,len=%x",
+ iUnitType, aTransferID, aLinAddr, aPhysAddr, aNumBytes);
- //calculate the amount of time required to play/record buffer
- TInt buffer_play_time = CalculateBufferTime(aNumBytes);
- TInt timerticks = NKern::TimerTicks(buffer_play_time);
- transfer.iPlayTime = timerticks;
-
- iTransferArray.Append(transfer);
-
- //Timer will callback when correct time has elapsed, will return KErrInUse if transfer
- //already active, this is ok becuase will be started again in callback
- TInt err = iTimer.OneShot(timerticks, ETrue);
-
-
+ iAudioControl->SendDataBuffer(
+ reinterpret_cast<TAny*>( aLinAddr ), aNumBytes, reinterpret_cast<Token>( aTransferID ) );
+
return KErrNone;
}
void DDriverSyborgSoundScPdd::StopTransfer()
{
- // Stop transfer
SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::stoptransfer TxPdd");
- //If timer is currently active then cancel it and call back buffer
- if(iTimer.Cancel())
- {
- Callback(iTransferArray[0].iTransferID, KErrNone, iTransferArray[0].iNumBytes);
- }
-
-
+ iAudioControl->SendCommand( Audio::DControl::EStop );
}
TInt DDriverSyborgSoundScPdd::PauseTransfer()
{
SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::pausetransfer TxPdd");
- //Pause Transfer
-
+ iAudioControl->SendCommand( Audio::DControl::EPause );
return KErrNone;
}
@@ -202,8 +224,7 @@
TInt DDriverSyborgSoundScPdd::ResumeTransfer()
{
SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::resumetransfer TxPdd");
- //Resume Transfer
-
+ iAudioControl->SendCommand( Audio::DControl::EResume );
return KErrNone;
}
@@ -220,51 +241,44 @@
TInt DDriverSyborgSoundScPdd::CustomConfig(TInt /*aFunction*/,TAny* /*aParam*/)
{
- SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::customconfig TxPdd");
+ SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::CustomConfig TxPdd");
return KErrNotSupported;
}
+TBool DDriverSyborgSoundScPdd::VirtIoCallback( MIoHandler& aVirtIoHandler, MQueue& aQueue,
+ Token aToken, TUint aBytesTransferred )
+ {
+ if ( &aQueue != &iAudioControl->DataQueue() )
+ { return ETrue; }
+
+ SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::VirtIoCallback t%x, s%x", aToken, aBytesTransferred);
+
+ if ( iCaps.iDirection == ESoundDirPlayback )
+ {
+ Ldd()->PlayCallback( (TUint) aToken, KErrNone, aBytesTransferred );
+ }
+ else
+ {
+ Ldd()->RecordCallback( (TUint) aToken, KErrNone, aBytesTransferred );
+ }
+
+ return EFalse; // cannot process any more buffers in this go due to a bug in LDD?
+ }
+
+TDfcQue*DDriverSyborgSoundScPdd::DfcQ()
+ {
+ return iPhysicalDevice->iDfcQ;
+ }
+
+TDfcQue*DDriverSyborgSoundScPdd::DfcQ( TInt /* aUinit */ )
+ {
+ return iPhysicalDevice->iDfcQ;
+ }
+
-void DDriverSyborgSoundScPdd::Callback(TUint aTransferID, TInt aTransferResult, TInt aBytesTransferred)
- {
- SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::playcallback TxPdd");
- //Callback when Transfer completes or is stopped
-
- iTransferArray.Remove(0);
-
- if(iUnitType == KSoundScTxUnit0)
- {
- Ldd()->PlayCallback(aTransferID, aTransferResult, aBytesTransferred);
- }
- else if(iUnitType == KSoundScRxUnit0)
- {
- Ldd()->RecordCallback(aTransferID, aTransferResult, aBytesTransferred);
- }
-
- if( iTransferArray.Count()>0)
- {
- iTimer.OneShot(iTransferArray[0].iPlayTime, ETrue);
- }
-
- }
-
-TDfcQue*DDriverSyborgSoundScPdd::DfcQ(TInt /* aUnit*/ )
- {
- return this->DfcQ();
- }
-
-TDfcQue*DDriverSyborgSoundScPdd::DfcQ()
- {
- return iPhysicalDevice->iDfcQ;
- }
-
TInt DDriverSyborgSoundScPdd::MaxTransferLen() const
{
-
- SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPdd::MaxTransferLen TxPdd");
-
- TInt maxlength = 200*1024;
- return maxlength;
+ return KMaxTransferLength;
}
@@ -279,7 +293,7 @@
}
else if(iUnitType == KSoundScRxUnit0)
{
- // The data transfer direction for this unit is record
+ // The data transfer direction for this unit is play
iCaps.iDirection = ESoundDirRecord;
}
--- a/baseport/syborg/soundsc/soundsc.mmp Sat Feb 27 19:18:04 2010 +0000
+++ b/baseport/syborg/soundsc/soundsc.mmp Thu Mar 04 00:55:21 2010 +0000
@@ -1,6 +1,4 @@
/*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
-* All rights reserved.
* 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
@@ -10,12 +8,13 @@
* Nokia Corporation - initial contribution.
*
* Contributors:
+* Accenture Ltd
*
-* Description:
+* Description: This file is a part of sound driver for Syborg adaptation.
*
*/
-#include <variant.mmh>
+#include "../variant.mmh"
#include "kernel/kern_ext.mmh"
SYSTEMINCLUDE /epoc32/include/drivers
@@ -25,8 +24,17 @@
TARGETTYPE pdd
ROMTARGET soundsc.pdd
+SYSTEMINCLUDE .
+
SOURCE shared_txsound.cpp
SOURCE variant_sound.cpp
+SOURCE virtio.cpp
+SOURCE virtio_io.cpp
+SOURCE virtio_iohandler.cpp
+SOURCE virtio_queue.cpp
+SOURCE virtio_audio.cpp
+
+LIBRARY PlatformLib
CAPABILITY all
EPOCALLOWDLLDATA
--- a/baseport/syborg/soundsc/variant_sound.cpp Sat Feb 27 19:18:04 2010 +0000
+++ b/baseport/syborg/soundsc/variant_sound.cpp Thu Mar 04 00:55:21 2010 +0000
@@ -1,6 +1,4 @@
/*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
-* All rights reserved.
* 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
@@ -10,25 +8,27 @@
* Nokia Corporation - initial contribution.
*
* Contributors:
+* Accenture Ltd
*
-* Description:
+* Description: This file is a part of sound driver for Syborg adaptation.
*
*/
#include "variant_sound.h"
+#include "virtio_iohandler.h"
+#include "../specific/syborg.h"
_LIT(KSoundScPddName, "SoundSc.Syborg");
-
DECLARE_STANDARD_PDD()
{
+ SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPddFactory created\n");
return new DDriverSyborgSoundScPddFactory;
}
DDriverSyborgSoundScPddFactory::DDriverSyborgSoundScPddFactory()
{
-
iUnitsMask = ((1 << KSoundScTxUnit0) | (1 << KSoundScRxUnit0));
iVersion = RSoundSc::VersionRequired();
@@ -38,20 +38,61 @@
TInt DDriverSyborgSoundScPddFactory::Install()
{
_LIT(KAudioDFC, "AUDIO DFC");
- // Get a pointer to the the McBSP's DFC Queue so that handling of both McBSP callbacks and requests
- // made to the LDD from user mode can be processed in the same thread, to avoid the use of semaphores
- TInt r = Kern::DfcQCreate(iDfcQ, 26, &KAudioDFC);
+
+ // LDD driver is going to use the same queue.
+ TInt r = Kern::DynamicDfcQCreate(iDfcQ, KAudioDfcQueuePriority, KAudioDFC);
SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPddFactory::PDD install");
- if(r==KErrNone)
+ if(r!=KErrNone)
+ {
+ SYBORG_SOUND_DEBUG("Creating audio DFC failed %d",r);
+ return r;
+ }
+ // All PDD factories must have a unique name
+ r = SetName(&KSoundScPddName);
+ if (r!=KErrNone)
{
- // All PDD factories must have a unique name
- TInt r = SetName(&KSoundScPddName);
+ SYBORG_SOUND_DEBUG("Setting name %x",r);
+ return r;
+ }
+ iIoHandler = new VirtIo::DIoHandler(
+ (TAny*)KHwSVPAudioDevice,
+ EIntAudio0,
+ iDfcQ );
+
+ if (iIoHandler == NULL)
+ {
+ iDfcQ->Destroy();
+ return KErrNoMemory;
}
-
+
+ SYBORG_SOUND_DEBUG("Constructing IoHandler");
+
+ r = iIoHandler->Construct();
+
+ if ( r != KErrNone)
+ {
+ iDfcQ->Destroy();
+ delete iIoHandler;
+ }
+
+ SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPddFactory::PDD installed");
+
return r;
}
+
+DDriverSyborgSoundScPddFactory::~DDriverSyborgSoundScPddFactory()
+ {
+ if (iIoHandler)
+ {
+ delete iIoHandler;
+ iIoHandler = NULL;
+ }
+ if (iDfcQ)
+ iDfcQ->Destroy();
+ }
+
void DDriverSyborgSoundScPddFactory::GetCaps(TDes8& /*aDes*/) const
{
@@ -81,8 +122,6 @@
TInt DDriverSyborgSoundScPddFactory::Create(DBase*& aChannel, TInt aUnit, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
{
- DSoundScPdd* pD = NULL;
-
SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPddFactory::PDD create aUnit %d TxUnitId %d", aUnit, KSoundScTxUnit0);
// Assume failure
@@ -90,21 +129,14 @@
aChannel = NULL;
- DDriverSyborgSoundScPdd* pTxD = new DDriverSyborgSoundScPdd;
+ DDriverSyborgSoundScPdd* pTxD = new DDriverSyborgSoundScPdd( this, aUnit,
+ iIoHandler, aUnit == KSoundScTxUnit0?1:2 );
- SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPddFactory::TxPdd %d", pTxD);
+ SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPddFactory::TxPdd %x", pTxD);
if (pTxD)
{
- pD = pTxD;
-
- // Save a pointer to the factory so that it is accessible by the PDD and call the PDD's
- // second stage constructor
- pTxD->iPhysicalDevice = this;
-
- pTxD->iUnitType = aUnit; // Either KSoundScTxUnit0 or KSoundScRxUnit0 (play or record)
-
- SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPddFactory::TxPdd2 %d", pTxD);
+ SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPddFactory::TxPdd2 %x", pTxD);
r = pTxD->DoCreate();
@@ -116,13 +148,19 @@
// as some LDDs have been known to access this pointer even if Create() returns an error!
if (r == KErrNone)
{
- aChannel = pD;
- SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPddFactory::TxPdd set AChannel %d", aChannel);
+ aChannel = pTxD;
+ SYBORG_SOUND_DEBUG("DDriverSyborgSoundScPddFactory::TxPdd set AChannel %x", aChannel);
}
else
{
- delete pD;
+ delete pTxD;
}
return r;
}
+
+
+VirtIo::MIoHandler* DDriverSyborgSoundScPddFactory::IoHandler()
+ {
+ return iIoHandler;
+ }
--- a/baseport/syborg/soundsc/variant_sound.h Sat Feb 27 19:18:04 2010 +0000
+++ b/baseport/syborg/soundsc/variant_sound.h Thu Mar 04 00:55:21 2010 +0000
@@ -1,6 +1,4 @@
/*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
-* All rights reserved.
* 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
@@ -10,8 +8,9 @@
* Nokia Corporation - initial contribution.
*
* Contributors:
+* Accenture Ltd
*
-* Description:
+* Description: This file is a part of sound driver for Syborg adaptation.
*
*/
@@ -20,21 +19,28 @@
#include "shared_sound.h"
+static const TUint KAudioDfcQueuePriority = 28;
+
class DDriverSyborgSoundScPddFactory : public DPhysicalDevice
{
public:
DDriverSyborgSoundScPddFactory();
+ ~DDriverSyborgSoundScPddFactory();
TInt Install();
void GetCaps(TDes8 &aDes) const;
TInt Create(DBase*& aChannel, TInt aUnit, const TDesC8* anInfo, const TVersion &aVer);
TInt Validate(TInt aUnit, const TDesC8* anInfo, const TVersion &aVer);
+
+ VirtIo::MIoHandler* IoHandler();
public:
/** The DFC queue to be used by both the LDD and the PDD to serialise access to the PDD */
- TDfcQue* iDfcQ;
-
+ TDynamicDfcQue* iDfcQ;
+
+ VirtIo::DIoHandler *iIoHandler;
+
};
#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/baseport/syborg/soundsc/virtio.cpp Thu Mar 04 00:55:21 2010 +0000
@@ -0,0 +1,58 @@
+/*
+* 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.h"
+
+namespace VirtIo
+{
+
+#define MIN(x,y) (((x)<=(y))?(x):(y))
+#define INVALID_PHYSADDR(x) ((x)==TPhysAddr(-1))
+
+TInt LinearToSGL( TAny* aVirtual, TUint aSize, TAddrLen aSGL[], TUint& aSGLCount )
+ {
+ const TUint pageSize = Kern::RoundToPageSize(1);
+ TUint8* virtAddr = reinterpret_cast<TUint8*>( aVirtual );
+ TPhysAddr physAddr = Epoc::LinearToPhysical( TLinAddr(virtAddr) );
+ if (INVALID_PHYSADDR(physAddr))
+ { return KErrArgument; }
+ TUint sglLimit = aSGLCount;
+ aSGLCount = 0;
+ TUint left = aSize;
+ while (left)
+ {
+ TPhysAddr startPhysAddr = physAddr;
+ TUint8* startVirtAddr = virtAddr;
+ while ( (left)
+ && ( Epoc::LinearToPhysical( TLinAddr(virtAddr) ) == physAddr ) )
+ {
+ TUint size = MIN(left, pageSize);
+ physAddr += size;
+ virtAddr += size;
+ left -= size;
+ }
+ if (INVALID_PHYSADDR(physAddr))
+ { return KErrArgument; }
+ if ((aSGL) && (aSGLCount<sglLimit))
+ {
+ aSGL[aSGLCount].iAddr = (TUint32) startPhysAddr;
+ aSGL[aSGLCount].iLen = virtAddr - startVirtAddr;
+ }
+ aSGLCount++;
+ }
+ return (aSGLCount<=sglLimit)?KErrNone:KErrNoMemory;
+ }
+
+} // namespace VirtIo
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/baseport/syborg/soundsc/virtio.h Thu Mar 04 00:55:21 2010 +0000
@@ -0,0 +1,160 @@
+/*
+* 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.
+*
+*/
+
+#ifndef VIRTIO_H
+#define VIRTIO_H
+
+/// @file virtio.h
+/// @brief Delivers the API for dealing with VirtIo device.
+///
+/// Mainly a VirtIo device functionality is accessed through the following entities.
+/// <li> MIo that deals with basic io space access
+/// <li> MQueue that represents a device's transaction queue, which is usually more then one per device
+/// <li> MIoHandler that represents a device, takes care of resource management, device initialisation and MIo and MQueue derived objects' lifetime.
+///
+/// @p The idea is that MIo, MQueue and MIoHandler comes as a specific set. On top of which it is possible to build various drivers (e.g. Audio or Ethernet) that are agnostic to these virtio specifics (e.g. flat device tree or full PCI).
+///
+/// Currently the implementation is not multithread safe. The assumption is that all the routines are driven from a single DFC.
+
+#include "virtio_defs.h"
+
+#include <e32lang.h>
+#include <assp.h>
+
+
+#ifdef _ENABLE_SYBORG_VIRTIO_DEBUG
+#define SYBORG_VIRTIO_DEBUG(x...) Kern::Printf(x)
+#else
+#define SYBORG_VIRTIO_DEBUG(x...)
+#endif
+
+#undef ASSERT
+#define ASSERT(x) (x) || (Kern::Printf("VirtIo: ASSERTION FAILED: "#x),0);
+
+
+namespace VirtIo
+{
+
+/// @brief type of a buffer token.
+typedef TAny* Token;
+
+/// @brief represents a virtual queue's API.
+///
+class MQueue
+ {
+public:
+
+ /// @brief Adds a buffer at the end of the queue
+ ///
+ /// @param aScatterList - physical address scatter list
+ /// @param aOutNum - number of scatter buffers to be sent to the device
+ /// @param aInNum - number of scatter buffers to be received from the device (starting at aOutNum index of scatter list)
+ /// @param aToken - a value associated with buffer to be returned by getBuf or used with detachBuf
+ virtual TInt AddBuf( const TAddrLen aScatterList[], TUint32 aOutNum,
+ TUint32 aInNum, Token aToken) = 0;
+
+ /// @brief Returns buffer associated with the least recent completed transaction
+ /// @return transaction's Token with \a len set to reflect amount of processed bytes or
+ /// 0 if no completed transaction was found.
+ virtual Token GetBuf( TUint& len ) = 0;
+
+ /// @brief Posts queued buffers to the device
+ virtual void Sync() = 0;
+
+ /// @brief Cancels a specified buffer (if it is not yet posted)
+ /// To be used at shutdown
+ virtual TInt DetachBuf( Token aToken ) = 0;
+
+ /// @brief reenable callbacks
+ /// @return ETrue - callbacks reenabled, EFalse - callbacks not reenabled as there are pending buffers in
+ /// the DQueue.
+ virtual TBool Restart() = 0;
+
+ /// @brief returns number of buffers that are posted to the DQueue
+ /// but not yet completed
+ virtual TInt Processing() = 0;
+
+ /// @brief returns number of times the GetBuf function could be called returning a buffer
+ virtual TInt Completed() = 0;
+
+ /// Returns Id of the queue
+ virtual TUint Id() = 0;
+
+ };
+
+
+/// @brief API wrapping the VirtIo IO space access.
+class MIo
+ {
+public:
+ virtual void SetQueueBase( TUint aId, TAny* iDescRegion ) = 0;
+ virtual TAny* GetQueueBase( TUint aId ) = 0;
+ virtual void PostQueue( TUint aId ) = 0;
+ virtual void GetDeviceIds( TUint32 &aPeripheralId, TUint32 &aDeviceId ) = 0;
+ virtual TUint GetQueueCount( TUint aQId ) = 0;
+ virtual TBool EnableInterrupt( TBool aEnable ) = 0;
+ virtual void SetStatus( TUint status ) = 0;
+ virtual void ClearInteruptStatus() = 0;
+ virtual TBool InteruptStatus() = 0;
+
+ };
+
+
+class MIoCallback;
+
+/// @brief represents a VirtIo device's API.
+///
+/// An API for a handler that takes care of resources, state and asyncrhonous communication of a VirtIo device. Allocates Queues.
+class MIoHandler
+ {
+public:
+ /// returns one of the device's queues.
+ virtual MQueue& Queue( TUint aId ) = 0;
+
+ /// registers a client for buffer notifications.
+ virtual void RegisterClient( MIoCallback* aListener ) = 0;
+
+ /// unregisters a client for buffer notifications.
+ virtual void UnregisterClient( MIoCallback* aListener ) = 0;
+ };
+
+/// an interface for a MIoHandler's client to implement.
+class MIoCallback
+ {
+public:
+ /// Notifies MIoHandler's client that that a buffer processing has been completed.
+ ///
+ /// @return EFalse to defer subsequent buffer processing in the same callback.
+ virtual TBool VirtIoCallback(
+ MIoHandler& aVirtIoHandler, MQueue& aQueue,
+ Token aToken, TUint aBytesTransferred ) = 0;
+ };
+
+/// @brief turns virtual address range into a phys scatter gather list
+///
+/// If virtual buffer contains a linear buffer then the
+/// function will create one SGL entry.
+///
+/// If function is called with aSGL=0 then it will count the linear physical
+/// fragments the buffer is build of.
+///
+///
+/// @return KErrArgument if the virtual buffer contains nonconvertible addresses)
+TInt LinearToSGL( TAny* aLinear, TUint aSize, TAddrLen aSGL[], TUint& aSGLCount );
+
+}
+
+
+#endif
--- /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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/baseport/syborg/soundsc/virtio_audio.h Thu Mar 04 00:55:21 2010 +0000
@@ -0,0 +1,103 @@
+/*
+* 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.
+*
+*/
+
+#ifndef VIRTIO_AUDIO_H
+#define VIRTIO_AUDIO_H
+
+#include "virtio_audio_defs.h"
+#include "virtio_defs.h"
+#include "virtio.h"
+
+#include <e32def.h>
+
+namespace VirtIo
+{
+
+namespace Audio
+{
+
+/// Encapsulates routines that affect VirtIo Audio device's Stream.
+/// DControl object may share ioHandler with other DControl objects.
+/// especially Control Queue.
+class DControl : public DBase
+ {
+ static const TUint KCmdMaxBufCount = 8;
+ static const TUint KControlQueueId = 0;
+public:
+ enum Command { ERun = 5, EStop, EPause, EResume };
+
+ DControl( VirtIo::MIoHandler& aIoHandler, TUint32 aDataQueueId )
+ : iIoHandler( aIoHandler ), iDataQueueId( aDataQueueId)
+ {}
+
+ ~DControl();
+
+ TInt Construct();
+
+ /// sets up stream parameters.
+ TInt Setup( StreamDirection aDirection, TInt aChannelNum,
+ FormatId aFormat, TInt aFreq );
+
+ /// @brief posts a data buffer.
+ ///
+ /// The virtaulAddr is going to be turned into
+ /// a physical address scatter gather list.
+ TInt SendDataBuffer( TAny* virtaulAddr, TUint aSize, Token aToken );
+
+ /// Sends a specific command
+ void SendCommand( Command aCmd )
+ { AddCommand( aCmd ); ControlQueue().Sync(); }
+
+ /// Return Data Queue of the stream.
+ MQueue& DataQueue()
+ { return iIoHandler.Queue(iDataQueueId); }
+
+ /// Returns Control Queue of the associated device.
+ MQueue& ControlQueue()
+ { return iIoHandler.Queue(KControlQueueId); }
+
+private:
+ // size of this struct needs to be power2 aligned
+ // we extend original TCommand with padding to ensure this
+ struct TCommandPadded: public TCommand
+ {
+ static const TUint KPaddingSize = POW2ALIGN(sizeof(TCommand))-sizeof(TCommand);
+ TUint8 iPadding[KPaddingSize];
+ };
+
+ void AddCommand( TCommandPadded* aCmd, Token aToken );
+
+ void AddCommand( TCommandPadded* aCmd, Token aToken, TAny* mem, TUint size );
+
+ void AddCommand( Command aCmd );
+
+ void WaitForCompletion();
+ static TBool CheckProcessing( TAny* aSelf );
+
+ VirtIo::MIoHandler& iIoHandler;
+ TUint iDataQueueId;
+
+ TUint8* iCmdMem; // managed
+ TCommandPadded* iCmd; // unmanaged
+ TBufferInfo* iBufferInfo; // unmanaged
+
+ StreamDirection iDirection;
+ };
+
+} // namespace Audio
+} // namespace VirtIo
+
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/baseport/syborg/soundsc/virtio_audio_defs.h Thu Mar 04 00:55:21 2010 +0000
@@ -0,0 +1,85 @@
+/*
+* 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.
+*
+*/
+
+#ifndef VIRTIO_AUDIO_DEFS_H //x
+#define VIRTIO_AUDIO_DEFS_H
+
+#include <e32def.h>
+
+/// @file virtio_audio_defs.h
+/// most of definitions here come from VirtIo Audio spec
+/// and was made compatible to the qemu backend (which means diverged from spec)
+
+namespace VirtIo
+{
+namespace Audio
+{
+
+static const TUint KMaxSGLItemCountPerAudioBuffer = 64;
+
+enum CommandId
+ {
+ ECmdSetEndian=1,
+ ECmdSetChannels=2,
+ ECmdSetFormat=3,
+ ECmdSetFrequency=4,
+ ECmdInit=5,
+ ECmdRun=6
+ };
+
+enum FormatId
+ {
+ EFormatU8=0,
+ EFormatS8=1,
+ EFormatU16=2,
+ EFormatS16=3,
+ EFormatU32=4,
+ EFormatS32=5
+ };
+
+enum RunType
+ {
+ EDoStop = 0,
+ EDoRun = 1
+ };
+
+// note the values are opposite to what spec says
+enum StreamDirection
+ {
+ EDirectionPlayback = 0,
+ EDirectionRecord = 1
+ };
+
+struct TCommand
+ {
+ TUint32 iCommand;
+ TUint32 iStream;
+ TUint32 iArg;
+ };
+
+struct TBufferInfo
+ {
+ TUint32 bufferSize;
+ TUint32 iA[3]; // not really documented
+ };
+
+static const TUint32 KVirtIoPeripheralId = 0xc51d000a;
+static const TUint32 KVirtIoDeviceId = 0xffff;
+
+} // namespace Audio
+} // namespace VirtIo
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/baseport/syborg/soundsc/virtio_defs.h Thu Mar 04 00:55:21 2010 +0000
@@ -0,0 +1,117 @@
+/*
+* 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.
+*
+*/
+
+#ifndef VIRTIO_DEFS_H
+#define VIRTIO_DEFS_H
+
+#include <e32def.h>
+#include <kernel.h> // fot TPhysAddr
+
+/// @file virtio_defs.h
+/// most of definitions here come from VirtIo spec
+/// and was made compatible to the qemu backend (which means diverged from spec)
+
+namespace VirtIo
+{
+
+#define POW2ALIGN1(x) ((x)|((x)>>1))
+#define POW2ALIGN2(x) ((x)|((x)>>2))
+#define POW2ALIGN4(x) ((x)|((x)>>4))
+#define POW2ALIGN8(x) ((x)|((x)>>8))
+#define POW2ALIGN16(x) ((x)|((x)>>16))
+
+///@brief Alignes \a x to the closest bigger or equal power2 value
+#define POW2ALIGN(x) (POW2ALIGN16(POW2ALIGN8(POW2ALIGN4(POW2ALIGN2(POW2ALIGN1((x)-1)))))+1)
+
+static const TUint KVirtIoAlignment = 0x1000;
+
+enum
+ {
+ EStatusReset = 0,
+ EStatusAcknowledge = 1,
+ EStatusDriverFound = 2,
+ EStatusDriverInitialised = 4,
+ EStatusFailed = 0x80
+ };
+
+enum
+ {
+ EIoID = 0,
+ EIoDevType = 1,
+ EIoHostFeatures = 2,
+ EIoGuestFeatures = 3,
+ EIoQueueBase = 4,
+ EIoQueueSize = 5,
+ EIoQueueSelect = 6,
+ EIoQueueNotify = 7,
+ EIoStatus = 8,
+ EIoInterruptEnable = 9,
+ EIoInterruptStatus = 10
+ };
+
+struct TRingDesc
+ {
+ enum
+ {
+ EFlagNext = 1,
+ EFlagWrite = 2
+ };
+
+ TUint64 iAddr; // physical address
+ TUint32 iLen;
+ TUint16 iFlags;
+ TUint16 iNext;
+ };
+
+struct TRingAvail
+ {
+ enum { EFlagInhibitNotifications = 1 };
+ TUint16 iFlags;
+ TUint16 iIdx;
+ TUint16 iRing[1];
+ };
+
+struct TRingUsed
+ {
+ enum { EFlagInhibitNotifications = 1 };
+ TUint16 iFlags;
+ TUint16 iIdx;
+ struct
+ {
+ TUint32 iId;
+ TUint32 iLen;
+ } iRing[1];
+ };
+
+/// @brief Represents element of scatter gather list
+struct TAddrLen
+ {
+ TPhysAddr iAddr;
+ TUint32 iLen;
+ };
+
+/// Gives a pointer resulting with aliging \a v with \a a.
+/// @note \a a must be power of 2.
+template <typename T> T* Align( T* v, TUint a )
+ { return (T*)( ((TUint8*)v) + ((-(TUint)v)&(a-1)) ); }
+
+/// Gives a pointer resulting with aliging \a v with \a a.
+/// @note \a a must be power of 2.
+template <typename T> T Align( T v, TUint a )
+ { return (v)+((-v)&(a-1)); }
+
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/baseport/syborg/soundsc/virtio_io.cpp Thu Mar 04 00:55:21 2010 +0000
@@ -0,0 +1,42 @@
+/*
+* 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_io.h"
+
+namespace VirtIo
+{
+
+void DIo::GetDeviceIds( TUint32 &aPeripheralId, TUint32 &aDeviceId )
+ {
+ aPeripheralId = read( EIoID );
+ aDeviceId = read( EIoDevType );
+ }
+
+void DIo::SetQueueBase( TUint aQId, TAny* iDescRegion )
+ {
+ TUint32 phAddr = iDescRegion?Epoc::LinearToPhysical( reinterpret_cast<TUint32>( iDescRegion ) ):0;
+ write(EIoQueueSelect, aQId);
+ write(EIoQueueBase, phAddr );
+ SYBORG_VIRTIO_DEBUG("SetQueueBase Q%d %x", aQId, phAddr );
+ }
+
+
+TAny* DIo::GetQueueBase( TUint aQId)
+ {
+ write(EIoQueueSelect, aQId);
+ return reinterpret_cast<TAny*>( read(EIoQueueBase) );
+ }
+
+} // namespace VirtIo
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/baseport/syborg/soundsc/virtio_io.h Thu Mar 04 00:55:21 2010 +0000
@@ -0,0 +1,83 @@
+/*
+* 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.
+*
+*/
+
+#ifndef VIRTIO_IO_H
+#define VIRTIO_IO_H
+
+#include "virtio.h"
+#include <e32def.h>
+
+namespace VirtIo
+{
+
+class DIo : public DBase, public MIo
+ {
+public:
+ DIo( TAny* aIoBase ): iIoBase( reinterpret_cast<TUint32*>( aIoBase ) )
+ { }
+
+ virtual void GetDeviceIds( TUint32 &aPeripheralId, TUint32 &aDeviceId );
+
+ virtual void SetQueueBase( TUint aQId, TAny* iDescRegion );
+
+ virtual TAny* GetQueueBase( TUint aQId);
+
+ virtual TUint GetQueueCount( TUint aQId )
+ {
+ write(EIoQueueSelect, aQId);
+ return read(EIoQueueSize);
+ }
+
+ virtual void PostQueue( TUint aQId )
+ { write(EIoQueueNotify, aQId); SYBORG_VIRTIO_DEBUG("PostQueue Q%d", aQId ); }
+
+ virtual TBool EnableInterrupt( TBool aEnable )
+ { return swap(EIoInterruptEnable, aEnable?1:0); }
+
+ virtual void SetStatus( TUint status )
+ { write(EIoStatus, status ); }
+
+ virtual void ClearInteruptStatus()
+ { write( EIoInterruptStatus, 1 ); }
+
+ virtual TBool InteruptStatus()
+ { return read( EIoInterruptStatus ); }
+
+
+ void Reset()
+ { SetStatus( EStatusReset ); };
+
+
+private:
+ void write(TUint idx, TUint32 value )
+ { iIoBase[idx] = value; }
+
+ TUint32 read(TUint idx)
+ { return iIoBase[idx]; }
+
+ TUint32 swap(TUint idx, TUint32 value )
+ {
+ TUint32 t = iIoBase[idx];
+ iIoBase[idx] = value;
+ return t;
+ }
+
+ volatile TUint32* iIoBase;
+
+ };
+
+} // namespace VirtIo
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/baseport/syborg/soundsc/virtio_iohandler.cpp Thu Mar 04 00:55:21 2010 +0000
@@ -0,0 +1,238 @@
+/*
+* 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_iohandler.h"
+#include "virtio_queue.h"
+#include "virtio_io.h"
+
+namespace VirtIo
+{
+
+DIoHandler::DIoHandler( TAny* aVirtIoBase, TUint aIntNum, TDfcQue* aDfcQue )
+ : iVirtIoBase( aVirtIoBase ), iIntNum( aIntNum ), iDfcQue( aDfcQue ),
+ iDfc( ServeDfc, this, 0 ),
+ iVirtIo( 0 ), iQueueCount( 3 ), iQueue( 0 ),
+ iClientCount( 0 )
+ {
+ SYBORG_VIRTIO_DEBUG("DIoHandler IoBase %x DfcQ %x", iVirtIoBase, iDfcQue);
+ }
+
+TInt DIoHandler::Construct()
+ {
+ TInt err = KErrNone;
+ TUint i;
+
+ SYBORG_VIRTIO_DEBUG("Creating DIo");
+
+ InstallIsr();
+
+ iVirtIo = new DIo(iVirtIoBase);
+ if (iVirtIo == NULL )
+ { return KErrNoMemory; }
+ iVirtIo->SetStatus( EStatusAcknowledge
+ | EStatusDriverFound );
+
+ iQueue = new DQueue*[iQueueCount];
+
+ if (iQueue == NULL )
+ { Wipe(); return KErrNoMemory; }
+
+ // This is to make Wipe work
+ for ( i = 0; i < iQueueCount; ++i )
+ { iQueue[i] = NULL; }
+
+ for ( i = 0; i < iQueueCount; ++i )
+ {
+ SYBORG_VIRTIO_DEBUG("Creating DQueue %d",i);
+ DQueue* q = new DQueue(
+ *iVirtIo, i, iVirtIo->GetQueueCount( i ) );
+ if (!q)
+ { Wipe(); return KErrNoMemory; }
+ err = q->Construct();
+ if (err != KErrNone)
+ { Wipe(); return err; }
+ iQueue[i] = q;
+ }
+
+ iVirtIo->SetStatus(
+ EStatusAcknowledge
+ | EStatusDriverFound
+ | EStatusDriverInitialised );
+
+ iVirtIo->EnableInterrupt( ETrue );
+ Interrupt::Enable(iIntNum);
+ return KErrNone;
+ }
+
+void DIoHandler::Wipe()
+ {
+ if (iQueue)
+ {
+ for ( TUint i = 0; i < iQueueCount; ++i )
+ {
+ if (iQueue[i])
+ { delete iQueue[i]; }
+ }
+ delete[] iQueue;
+ iQueue = NULL;
+ }
+ if (iVirtIo)
+ {
+ delete iVirtIo;
+ iVirtIo = NULL;
+ }
+ }
+
+DIoHandler::~DIoHandler()
+ {
+
+ Interrupt::Disable(iIntNum);
+ UninstallIsr();
+ iVirtIo->EnableInterrupt( EFalse );
+ iDfc.Cancel();
+ iVirtIo->ClearInteruptStatus();
+
+ WaitForCompletion();
+
+ iVirtIo->SetStatus( EStatusAcknowledge
+ | EStatusDriverFound );
+ iVirtIo->SetStatus( EStatusAcknowledge );
+
+ Wipe();
+ }
+
+MQueue& DIoHandler::Queue( TUint id )
+ { return *(iQueue[id]); }
+
+void DIoHandler::ScheduleCallback()
+ {
+ iDfc.Enque();
+ }
+
+
+// Waits until device processes all pending requests
+// This code should be really handled by each queue individually
+void DIoHandler::WaitForCompletion()
+ {
+ SYBORG_VIRTIO_DEBUG("WaitForCompletion : {");
+
+ TInt st = Kern::PollingWait( &DIoHandler::CheckProcessing, this, 10, 100 );
+
+ ASSERT( st == KErrNone );
+
+ for ( TUint i = 0; i < iQueueCount; ++i )
+ {
+ while ( iQueue[i]->Completed() )
+ { InterruptHandler(); }
+ }
+
+ SYBORG_VIRTIO_DEBUG("WaitForCompletion : }");
+ }
+
+TBool DIoHandler::CheckProcessing( TAny* aSelf )
+ {
+ DIoHandler* self = reinterpret_cast<DIoHandler*>( aSelf );
+ for ( TUint i = 0; i < self->iQueueCount; ++i )
+ {
+ if (self->iQueue[i]->Processing()!=0)
+ { return EFalse; }
+ }
+ return ETrue;
+ }
+
+void DIoHandler::InstallIsr()
+ {
+ iDfc.SetDfcQ( iDfcQue );
+ Interrupt::Bind(iIntNum,ServeIsr,this);
+ }
+
+void DIoHandler::UninstallIsr()
+ {
+ Interrupt::Unbind(iIntNum);
+ iDfc.Cancel();
+ }
+
+void DIoHandler::ServeIsr( TAny* aSelf )
+ {
+ DIoHandler* self = reinterpret_cast<DIoHandler*>( aSelf );
+ Interrupt::Clear( self->iIntNum );
+ self->iVirtIo->ClearInteruptStatus();
+ self->iDfc.Add();
+ }
+
+void DIoHandler::ServeDfc( TAny* aSelf )
+ {
+ reinterpret_cast<DIoHandler*>( aSelf )->InterruptHandler();
+ }
+
+
+// Although the function notifies all clients
+// usually only one of them is an adressee
+// the rest would just check flags/compare numbers and return.
+// If at least one client did some crucial processing
+// (indicating that by returning EFalse from VirtIoCallback)
+// then NotifyClients returns EFalse as well.
+TBool DIoHandler::NotifyClients( MQueue& aQueue, Token aToken, TUint aBytesTransferred )
+ {
+ TBool r = ETrue;
+ for ( TUint i = 0 ; i < iClientCount; ++i )
+ {
+ r &= iClients[i]->VirtIoCallback( *this, aQueue, aToken, aBytesTransferred );
+ }
+ return r;
+ }
+
+// Here buffers processed by the device are iterated.
+// After the first serious buffer processing (as indicated by NotifyClients)
+// further buffer processing is Deferred in another DFC callback.
+void DIoHandler::InterruptHandler()
+ {
+ for ( TUint q = 0; q < iQueueCount; ++q )
+ {
+ TUint transferred;
+ TUint cnt = ETrue;
+ do
+ {
+ Token t = Queue(q).GetBuf(transferred);
+ if (t)
+ { cnt = NotifyClients( Queue(q), t, transferred); }
+ else
+ { break; }
+ } while(cnt);
+ if (!cnt)
+ {
+ ScheduleCallback();
+ break;
+ }
+ }
+ }
+
+void DIoHandler::UnregisterClient( MIoCallback* aClient )
+ {
+ ASSERT( iClientCount );
+ TUint i;
+ for ( i = 0; i < iClientCount; ++i)
+ {
+ if (iClients[i] == aClient )
+ { break; }
+ }
+ ASSERT( i < iClientCount );
+ --iClientCount;
+ // move the rest of the table one slot to the front
+ for ( ; i < iClientCount; ++i)
+ { iClients[i] = iClients[i+1]; }
+ }
+
+} // namespace VirtIo
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/baseport/syborg/soundsc/virtio_iohandler.h Thu Mar 04 00:55:21 2010 +0000
@@ -0,0 +1,93 @@
+/*
+* 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.
+*
+*/
+
+#ifndef VIRTIO_IOHANDLER_H
+#define VIRTIO_IOHANDLER_H
+
+#include "virtio.h"
+#include <e32def.h>
+
+namespace VirtIo
+{
+
+class DQueue;
+
+class DIo;
+
+
+class DIoHandler : public DBase, public MIoHandler
+ {
+ static const TUint KMaxClients = 4;
+public:
+ DIoHandler( TAny* aVirtIoBase, TUint aIntNum, TDfcQue* aDfcQue );
+
+ virtual void RegisterClient( MIoCallback* aClient )
+ {
+ ASSERT( iClientCount < KMaxClients );
+ iClients[iClientCount++] = aClient;
+ }
+
+ virtual void UnregisterClient( MIoCallback* aClient );
+
+ TInt Construct();
+
+
+ virtual ~DIoHandler();
+
+ virtual MQueue& Queue( TUint id );
+
+private:
+ void ScheduleCallback();
+
+ void WaitForCompletion();
+
+ void Wipe();
+
+ static TBool CheckProcessing( TAny* aSelf );
+
+ void InstallIsr();
+
+ void UninstallIsr();
+
+ static void ServeIsr( TAny* aSelf );
+
+ static void ServeDfc( TAny* aSelf );
+
+ TBool NotifyClients( MQueue& aQueue, Token aToken, TUint aBytesTransferred );
+
+ void InterruptHandler();
+
+ TAny* iVirtIoBase;
+ TUint iIntNum;
+
+ TDfcQue* iDfcQue;
+ TDfc iDfc;
+
+ //managed
+ DIo* iVirtIo;
+
+ TUint iQueueCount;
+ //double managed
+ DQueue** iQueue;
+
+ TUint iClientCount;
+ MIoCallback* iClients[KMaxClients];
+
+ };
+
+
+} // namespace VirtIo
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/baseport/syborg/soundsc/virtio_queue.cpp Thu Mar 04 00:55:21 2010 +0000
@@ -0,0 +1,328 @@
+/*
+* 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_queue.h"
+
+#define ENABLE_QEMU_AUDIO_MODEL_BUG_WORKAROUND
+#define ENABLE_QEMU_VIRTIO_CLEANUP_BUG_WORKAROUND
+#define PHYS_ADDR(x) Epoc::LinearToPhysical( reinterpret_cast<TUint32>(x))
+
+namespace VirtIo
+{
+
+
+DQueue::DQueue( MIo& aVirtIo, TUint aId, TUint aCount )
+ : iVirtIo( aVirtIo ), iId( aId ), iCount( aCount )
+ {
+ }
+
+TInt DQueue::Construct()
+ {
+ TInt r = AllocQueue();
+ if (r!=KErrNone)
+ { return r; }
+ PreInitQueue();
+ iVirtIo.SetQueueBase( iId, iDesc );
+ PostInitQueue();
+ return KErrNone;
+ }
+
+void DQueue::Wipe()
+ {
+ if ( iChunk )
+ {
+ iChunk->Close( NULL );
+ iChunk = NULL;
+ }
+#ifndef ENABLE_QEMU_VIRTIO_CLEANUP_BUG_WORKAROUND
+ if ( iPhysAddr )
+ { Epoc::FreePhysicalRam( iPhysAddr ); }
+#endif
+ iPhysAddr = 0;
+ }
+
+DQueue::~DQueue()
+ {
+ Wipe();
+ }
+
+//
+// Implementation here is that descs are allocated from the one starting with lowest index,
+TInt DQueue::AddBuf( const TAddrLen aScatterList[], TUint32 aOutNum, TUint32 aInNum, Token aToken)
+ {
+ SYBORG_VIRTIO_DEBUG("AddBuf Q%x %x l%x %x,%x %x",
+ iId, aScatterList[0].iAddr, aScatterList[0].iLen, aOutNum, aInNum, aToken );
+ TUint outLeft = aOutNum;
+ TUint inLeft = aInNum;
+ TInt first = -1;
+ TInt last = -1;
+ TUint totalLen = 0;
+ // @TODO maintain freedescs counter to know if the below is going to success from the outset.
+ // alloc and initialise descs
+ for ( TUint i = 0, j = 0; (i < iCount) && (outLeft+inLeft); ++i )
+ {
+ if (iDesc[i].iFlags == KFreeDescriptorMarker)
+ {
+ if (first<0)
+ { first = i; }
+ iDesc[i].iFlags = ((outLeft)? 0 : TRingDesc::EFlagWrite);
+ iDesc[i].iNext = KFreeDescriptorMarker;
+ iDesc[i].iAddr = aScatterList[j].iAddr;
+ iDesc[i].iLen = aScatterList[j].iLen;
+ totalLen += aScatterList[j].iLen;
+ iToken[i].iToken = aToken;
+ iToken[i].iTotalLen = 0;
+ if ( last >=0 )
+ {
+ iDesc[last].iNext = i;
+ iDesc[last].iFlags |= TRingDesc::EFlagNext;
+ }
+ last = i;
+ if (outLeft)
+ { --outLeft; }
+ else
+ { --inLeft; }
+ j++;
+ }
+ }
+ if (outLeft+inLeft) // rollback descs if not all could have been claimed
+ {
+ if (first>=0)
+ { FreeDescs(first); }
+ return KErrNotReady;
+ }
+ iToken[first].iTotalLen = totalLen;
+
+ // fill a slot in avail ring
+ iAvail->iRing[Slot(iAvail->iIdx)] = first;
+ ++iAvail->iIdx;
+
+ return KErrNone;
+ }
+
+// bases on the assumption that the lowest desc index with given aToken value is used (see addBuf)
+// @todo make sure the buffer is not yet posted
+TInt DQueue::DetachBuf( Token aToken )
+ {
+ TUint myDescId = KFreeDescriptorMarker;
+ for ( TIdx i = iNextAvailToSync; i != iAvail->iIdx ; ++i )
+ {
+ TUint availSlot = Slot( i );
+ TUint descId = iAvail->iRing[availSlot];
+ if ( descId < iCount )
+ {
+ if (iToken[descId].iToken == aToken)
+ {
+ myDescId = descId;
+ break;
+ }
+ }
+ }
+ if ( myDescId != KFreeDescriptorMarker )
+ { return KErrNotFound; }
+ FreeDescs( myDescId );
+ return KErrNone;
+ }
+
+Token DQueue::GetBuf( TUint& aLen )
+ {
+ TIdx usedIdx = iUsed->iIdx;
+ ASSERT( ((TIdx)iNextUsedToRead) <= usedIdx );
+ if (usedIdx == ((TIdx)iNextUsedToRead))
+ { return 0; }
+ TUint nextUsedSlot = Slot(iNextUsedToRead);
+ TUint len = iUsed->iRing[nextUsedSlot].iLen;
+ TUint descId = iUsed->iRing[nextUsedSlot].iId;
+ ASSERT(descId<iCount);
+ Token token = iToken[descId].iToken;
+ TUint orderedLen = iToken[descId].iTotalLen;
+ SYBORG_VIRTIO_DEBUG( "GetBuf Q%x %x ..%x t%x D%x L%x OL%x", iId, iNextUsedToRead, usedIdx, token, descId, len, orderedLen );
+
+ ++iNextUsedToRead;
+ FreeDescs( descId );
+
+#ifdef ENABLE_QEMU_AUDIO_MODEL_BUG_WORKAROUND
+ aLen = len?len:orderedLen; // @TODO kind of a hack to solve virtio-audio's failure to report len by syborg on the side of qemu
+#endif
+ return token;
+ }
+
+TInt DQueue::Processing()
+ { return ((TIdx)(iAvail->iIdx - iFirstEverToSync))
+ - ((TIdx)(iUsed->iIdx - iFirstEverToRead)); }
+
+TInt DQueue::Completed()
+ { return ((TIdx)(iUsed->iIdx - iNextUsedToRead)); }
+
+void DQueue::Sync()
+ {
+ SYBORG_VIRTIO_DEBUG("Sync Q%d, %x..%x",
+ iId, iNextAvailToSync, iAvail->iIdx );
+ if ( ((TIdx)iNextAvailToSync) == iAvail->iIdx)
+ { return; }
+ DumpAvailPending();
+
+ iNextAvailToSync = iAvail->iIdx;
+ iVirtIo.PostQueue( iId );
+ }
+
+void DQueue::DumpUsedPending()
+ {
+ for (TIdx i = iNextUsedToRead; i != iUsed->iIdx; ++i )
+ { DumpUsed( Slot(i) ); }
+ }
+
+void DQueue::DumpUsed(TUint usedSlot)
+ {
+ SYBORG_VIRTIO_DEBUG("Usedslot = %x, aLen = %x, descId=%x", usedSlot, (TUint32) iUsed->iRing[usedSlot].iLen, iUsed->iRing[usedSlot].iId);
+ TUint descId = iUsed->iRing[usedSlot].iId;
+ DumpDescs( descId );
+ }
+
+void DQueue::DumpAvailPending()
+ {
+ for (TIdx i = iNextAvailToSync; i != iAvail->iIdx; ++i )
+ { DumpAvail( Slot(i) ); }
+ }
+
+void DQueue::DumpAvail(TUint availSlot)
+ {
+ SYBORG_VIRTIO_DEBUG("Q%d, availslot = %x", iId, availSlot);
+ TUint descId = iAvail->iRing[availSlot];
+ DumpDescs( descId );
+ }
+
+void DQueue::DumpDescs(TUint descId )
+ {
+ do {
+ TRingDesc& d = iDesc[descId];
+ SYBORG_VIRTIO_DEBUG(" Desc %x,addr %x, len %x, flags %x, next %x",
+ (TUint32)descId, (TUint32)d.iAddr, (TUint32)d.iLen, (TUint32)d.iFlags, (TUint32)d.iNext );
+ if ((d.iFlags&TRingDesc::EFlagNext)==0)
+ { break; }
+ descId = d.iNext;
+ } while (ETrue);
+ }
+
+void DQueue::DumpAll()
+ {
+ DumpAvailPending();
+ DumpUsedPending();
+ }
+
+void DQueue::FreeDescs( TUint firstDescIdx )
+ {
+ TInt i = firstDescIdx;
+ Token token = iToken[firstDescIdx].iToken;
+ while (i>=0)
+ {
+ ASSERT( ( ((TUint)i) < iCount ) );
+ TUint flags = iDesc[i].iFlags;
+ ASSERT( flags != KFreeDescriptorMarker );
+ iDesc[i].iFlags = KFreeDescriptorMarker;
+ ASSERT( iToken[i].iToken == token );
+ iToken[i].iToken = 0;
+ iToken[i].iTotalLen = 0;
+ i = (flags&TRingDesc::EFlagNext)
+ ? iDesc[i].iNext : -1;
+ }
+ }
+
+TUint8* DQueue::AllocMem( TUint aSize )
+ {
+ TInt r = KErrNone;
+
+#ifdef ENABLE_QEMU_VIRTIO_CLEANUP_BUG_WORKAROUND
+ // note this is second part of workaround that deals
+ // with the issue that memory once assigned to queuebase cannot be
+ // changed,
+ // if queuebase != 0 this is because it was set when the driver
+ // was loaded previous time
+
+ iPhysAddr = (TUint32) iVirtIo.GetQueueBase( iId );
+ iPhysMemReallyAllocated = (iPhysAddr == 0);
+ if (iPhysMemReallyAllocated)
+ { r = Epoc::AllocPhysicalRam(aSize, iPhysAddr, 0 ); }
+
+#endif
+
+ if (r!=KErrNone )
+ { return NULL; }
+
+ r = DPlatChunkHw::New( iChunk, iPhysAddr, aSize,
+ EMapAttrSupRw | EMapAttrL2Uncached | EMapAttrL1Uncached );
+
+ if (r!=KErrNone )
+ {
+ if ( iPhysMemReallyAllocated )
+ { Epoc::FreePhysicalRam( iPhysAddr, aSize ); }
+ iChunk->Close( NULL );
+ return NULL;
+ }
+
+ ASSERT( r == KErrNone );
+ return reinterpret_cast<TUint8*>( iChunk->LinearAddress() );
+ }
+
+TInt DQueue::AllocQueue()
+ {
+ iDescSize = iCount * sizeof(TRingDesc);
+ iAvailSize = sizeof(TRingAvail) + (iCount-1) * sizeof(((TRingAvail*)0)->iRing[0]);
+ iTokenSize = iCount * sizeof(TTransactionInfo);
+ TUint usedOffset = Align( iDescSize + iAvailSize, KVirtIoAlignment );
+ TUint iUsedSize = sizeof(TRingUsed) + (iCount-1) * sizeof(((TRingUsed*)0)->iRing[0]);
+ TUint size = usedOffset + iUsedSize;
+ TUint8* iMemAligned;
+
+ iMemAligned = AllocMem( size );
+
+ if (!iMemAligned)
+ { return KErrNoMemory; }
+
+ iDesc = reinterpret_cast<TRingDesc*>( iMemAligned );
+ iAvail = reinterpret_cast<TRingAvail*>( iMemAligned + iDescSize );
+ iUsed = reinterpret_cast<TRingUsed*>( iMemAligned + usedOffset );
+ iToken = reinterpret_cast<TTransactionInfo*>( Kern::Alloc( iTokenSize ) );
+ SYBORG_VIRTIO_DEBUG("DQueue %d, Virt iDesc=%x,iAvail=%x,iToken=%x,iUsed=%x",
+ iId, iDesc, iAvail, iToken, iUsed );
+ SYBORG_VIRTIO_DEBUG("DQueue %d, Phys iDesc=%x, iUsed=%x",
+ iId, PHYS_ADDR(iDesc), PHYS_ADDR(iUsed) );
+ ASSERT( ((PHYS_ADDR(iUsed)-PHYS_ADDR(iDesc))) == ((TUint32)((TUint8*)iUsed-(TUint8*)iDesc)) );
+ return KErrNone;
+ }
+
+void DQueue::PreInitQueue()
+ {
+ memset(iDesc, -1, iDescSize );
+ memset( ((TUint8*) iAvail) + 4, -1, iDescSize - 4 );
+ memset( ((TUint8*) iUsed) + 4, -1, iDescSize - 4 );
+
+ iAvail->iFlags = 0; // no notifications from control queue
+ iUsed->iFlags = 0;
+ if ( iPhysMemReallyAllocated )
+ {
+ iAvail->iIdx = 0;
+ iUsed->iIdx = 0;
+ }
+ }
+
+void DQueue::PostInitQueue()
+ {
+ iFirstEverToSync = iNextAvailToSync = iAvail->iIdx;
+ iFirstEverToRead = iNextUsedToRead = iUsed->iIdx;
+ }
+
+
+} // namespace VirtIo
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/baseport/syborg/soundsc/virtio_queue.h Thu Mar 04 00:55:21 2010 +0000
@@ -0,0 +1,139 @@
+/*
+* 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.
+*
+*/
+
+#ifndef VIRTIO_QUEUE_H
+#define VIRTIO_QUEUE_H
+
+#include "virtio.h"
+#include <e32def.h>
+
+namespace VirtIo
+{
+
+/// @brief implements VirtIo Queue.
+///
+///
+/// @note functions are not enclosed with any synchronisation primitives.
+/// However, implementation is believed to split operations in 3 groups with the following concurrency constraints:
+/// <li> A GetBuf, DetachBuf
+/// <li> B AddBuf
+/// <li> C Processing, Completed, Sync
+/// Group C can be executed concurrently with any other functions.
+/// Group A can be executed concurrently with a group B function.
+/// Group A or B function cannot be executed concurrently with function from the same group.
+///
+/// Memory barries would have to be introduced for SMP.
+///
+class DQueue : public DBase, public MQueue
+ {
+ typedef TUint16 TIdx;
+
+ struct TTransactionInfo
+ {
+ Token iToken;
+ TUint iTotalLen;
+ };
+
+ static const TUint KFreeDescriptorMarker = 0xFFFF;
+
+public:
+
+ /// @brief Creates a VirtIo Queue with a MIo object, Queue Id,
+ /// and descriptor count/ring lenght.
+ DQueue( MIo& aVirtIo, TUint aId, TUint aCount );
+
+ /// Allocates resources
+ TInt Construct();
+
+ virtual ~DQueue();
+
+public: // implementation of MQueue
+
+ virtual TInt AddBuf( const TAddrLen aScatterList[], TUint32 aOutNum, TUint32 aInNum, Token aToken);
+
+ virtual TInt DetachBuf( Token aToken );
+
+ virtual Token GetBuf( TUint& aLen );
+
+ virtual void Sync();
+
+ virtual TUint Id()
+ { return iId; }
+
+ virtual TBool Restart()
+ { return ETrue; }
+
+ virtual TInt Processing();
+
+ virtual TInt Completed();
+
+public: // Debug functions
+ void DumpUsedPending();
+
+ void DumpUsed(TUint usedSlot);
+ void DumpAvailPending();
+
+ void DumpAvail(TUint availSlot);
+ void DumpDescs(TUint descId );
+
+ virtual void DumpAll();
+
+private:
+ void Wipe();
+
+ TUint Slot( TUint i )
+ { return i & (iCount - 1); }
+
+ void FreeDescs( TUint firstDescIdx );
+
+ TUint8* AllocMem( TUint aSize );
+
+ TInt AllocQueue();
+
+ void PreInitQueue();
+
+ void PostInitQueue();
+
+private:
+ MIo& iVirtIo;
+ const TUint iId;
+ const TUint iCount;
+ volatile TUint iNextUsedToRead;
+ TUint iFirstEverToRead;
+ volatile TUint iNextAvailToSync;
+ TUint iFirstEverToSync;
+
+ TUint iDescSize;
+ TUint iAvailSize;
+ TUint iTokenSize;
+ TUint iUsedSize;
+
+ TRingDesc* iDesc;
+ TRingAvail* iAvail;
+ volatile TRingUsed* iUsed;
+ TTransactionInfo* iToken;
+
+ // managed
+ TUint8* iMem;
+ TPhysAddr iPhysAddr;
+ TBool iPhysMemReallyAllocated;
+ DPlatChunkHw* iChunk;
+
+ };
+
+
+} // namespace VirtIo
+
+#endif
--- a/baseport/syborg/specific/syborg.h Sat Feb 27 19:18:04 2010 +0000
+++ b/baseport/syborg/specific/syborg.h Thu Mar 04 00:55:21 2010 +0000
@@ -64,7 +64,9 @@
EIntSerial0 = 5,
EIntSerial1 = 6,
EIntSerial2 = 7,
- EIntSerial3 = 8
+ EIntSerial3 = 8,
+ EIntNet0 = 9,
+ EIntAudio0 = 10
};
// Timer Mode