Fix bug 873. Fixes to syborg virtio-audio code as well as to the audio driver
--- a/baseport/syborg/soundsc/shared_sound.h Mon May 10 11:37:38 2010 +0100
+++ b/baseport/syborg/soundsc/shared_sound.h Wed May 12 23:13:16 2010 +0100
@@ -19,8 +19,8 @@
#include <soundsc.h>
-#ifdef _ENABLE_SYBORG_AUDIO_DRIVER_DEBUG
-#define SYBORG_SOUND_DEBUG(x...) Kern::Printf(x)
+#ifndef DISABLE_SYBORG_SOUND_DEBUG
+#define SYBORG_SOUND_DEBUG(x...) __KTRACE_OPT(KSOUND1, Kern::Printf(x))
#else
#define SYBORG_SOUND_DEBUG(x...)
#endif
@@ -33,7 +33,7 @@
#include "virtio_audio_defs.h"
/// @brief defines the maximum size for a single audio data transfer
-static const TInt KMaxTransferLength = 128 * 1024;
+static const TInt KMaxTransferLength = 256 * 1024;
namespace VirtIo
{
--- a/baseport/syborg/soundsc/shared_txsound.cpp Mon May 10 11:37:38 2010 +0100
+++ b/baseport/syborg/soundsc/shared_txsound.cpp Wed May 12 23:13:16 2010 +0100
@@ -92,6 +92,11 @@
iAudioControl = new Audio::DControl( *iIoHandler, iDataQueueId );
iAudioControl->Construct();
+ Audio::StreamDirection direction = static_cast<Audio::StreamDirection>(
+ (iUnitType == KSoundScRxUnit0)?Audio::EDirectionRecord
+ :(iUnitType == KSoundScTxUnit0)?Audio::EDirectionPlayback:-1 );
+
+ iAudioControl->Setup( direction, 2, Audio::EFormatS16, 48000 );
return KErrNone;
}
--- a/baseport/syborg/soundsc/virtio.h Mon May 10 11:37:38 2010 +0100
+++ b/baseport/syborg/soundsc/virtio.h Wed May 12 23:13:16 2010 +0100
@@ -34,8 +34,8 @@
#include <assp.h>
-#ifdef _ENABLE_SYBORG_VIRTIO_DEBUG
-#define SYBORG_VIRTIO_DEBUG(x...) Kern::Printf(x)
+#ifndef DISABLE_SYBORG_SOUND_DEBUG
+#define SYBORG_VIRTIO_DEBUG(x...) __KTRACE_OPT(KSOUND1, Kern::Printf(x))
#else
#define SYBORG_VIRTIO_DEBUG(x...)
#endif
--- a/baseport/syborg/soundsc/virtio_audio.cpp Mon May 10 11:37:38 2010 +0100
+++ b/baseport/syborg/soundsc/virtio_audio.cpp Wed May 12 23:13:16 2010 +0100
@@ -20,6 +20,40 @@
namespace Audio
{
+static TBool CheckProcessing( TAny* aSelf )
+ {
+ MQueue* queue = reinterpret_cast<MQueue*>( aSelf );
+ return queue->Processing() == 0;
+ }
+
+static void WaitForCompletion( MQueue& aQueue )
+ {
+ SYBORG_VIRTIO_DEBUG("AddBufferHelperWaitForCompletion : {");
+
+ TInt st = Kern::PollingWait( &CheckProcessing, &aQueue, 50, 100 );
+ ASSERT ( (st == KErrNone) && "Polling problem" )
+
+ SYBORG_VIRTIO_DEBUG("AddBufferHelperWaitForCompletion : }");
+ }
+
+static void AddBufferHelper( MQueue& aQueue, TAddrLen aList[], TUint aBufInCount, TUint aBufOutCount, Token aToken)
+ {
+ TInt st = aQueue.AddBuf(aList, aBufInCount, aBufOutCount, aToken );
+ if ( st == KErrNotReady )
+ {
+ SYBORG_VIRTIO_DEBUG("AddBufferHelper - no free descriptors at Control Queue, forcing wait");
+ TUint transferred;
+ Token t;
+ while ( ( t = aQueue.GetBuf(transferred), t ) != 0 )
+ {
+ SYBORG_VIRTIO_DEBUG("flushing Q%x, T%x, L%x\n", 0, t, transferred );
+ }
+
+ st = aQueue.AddBuf(aList, aBufInCount, aBufOutCount, aToken );
+ }
+ ASSERT( st == KErrNone );
+ }
+
DControl::~DControl()
{
if (iCmdMem)
@@ -62,32 +96,44 @@
iCmd[7].iArg = Audio::EDoStop; //kind of pause
iCmd[8].iCommand = Audio::ECmdRun;
iCmd[8].iArg = Audio::EDoRun; //kind of resume
+ iCmd[9].iCommand = Audio::ECmdInit; // kind of shutdown
+ iCmd[9].iArg = EDirectionNone;
return KErrNone;
}
TInt DControl::Setup( StreamDirection aDirection, TInt aChannelNum,
FormatId aFormat, TInt aFreq)
{
+ if (iIsRunning
+ && (( aDirection != iDirection )
+ || (aFormat != iCmd[2].iArg )
+ || (aFreq != iCmd[3].iArg )
+ || (aChannelNum != iCmd[1].iArg )
+ ))
+ { return KErrInUse; }
+
iCmd[1].iArg = aChannelNum;
iCmd[2].iArg = aFormat;
iCmd[3].iArg = aFreq;
- iCmd[4].iArg = iDirection = aDirection;
- AddCommand(&iCmd[0],(Token)0);
+ iCmd[4].iArg = iDirection = aDirection;
AddCommand(&iCmd[1],(Token)1);
AddCommand(&iCmd[2],(Token)2);
AddCommand(&iCmd[3],(Token)3);
- AddCommand(&iCmd[4],(Token)4, iBufferInfo, sizeof(*iBufferInfo) );
+ if (!iIsRunning) {
+ AddCommand(&iCmd[4],(Token)4, iBufferInfo, sizeof(*iBufferInfo) );
+ AddCommand(&iCmd[6],(Token)6);
+ }
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 );
+ AddBufferHelper( ControlQueue(), &list, 1, 0, aToken );
}
void DControl::AddCommand( TCommandPadded* aCmd, Token aToken,
@@ -98,41 +144,25 @@
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 : }");
+ AddBufferHelper( ControlQueue(),list, 1, 1, aToken );
}
-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)
+ if ( (aCmd == EStop) || (aCmd == EShutDown) )
{
// due to bug on qemu's side we need to stop sending buffers
// and wait for all pending buffers to get filled...
- WaitForCompletion();
- }
+ WaitForCompletion(DataQueue());
+ WaitForCompletion(ControlQueue());
+ iIsRunning = 0;
+ }
AddCommand(&iCmd[idx], (Token)idx );
+ if (aCmd == ERun )
+ {
+ iIsRunning = 1;
+ }
}
TInt DControl::SendDataBuffer( TAny* virtaulAddr, TUint aSize, Token aToken )
--- a/baseport/syborg/soundsc/virtio_audio.h Mon May 10 11:37:38 2010 +0100
+++ b/baseport/syborg/soundsc/virtio_audio.h Wed May 12 23:13:16 2010 +0100
@@ -36,10 +36,10 @@
static const TUint KCmdMaxBufCount = 8;
static const TUint KControlQueueId = 0;
public:
- enum Command { ERun = 5, EStop, EPause, EResume };
+ enum Command { ERun = 5, EStop, EPause, EResume, EShutDown };
DControl( VirtIo::MIoHandler& aIoHandler, TUint32 aDataQueueId )
- : iIoHandler( aIoHandler ), iDataQueueId( aDataQueueId)
+ : iIoHandler( aIoHandler ), iDataQueueId( aDataQueueId), iIsRunning( 0 )
{}
~DControl();
@@ -83,9 +83,6 @@
void AddCommand( Command aCmd );
- void WaitForCompletion();
- static TBool CheckProcessing( TAny* aSelf );
-
VirtIo::MIoHandler& iIoHandler;
TUint iDataQueueId;
@@ -94,6 +91,8 @@
TBufferInfo* iBufferInfo; // unmanaged
StreamDirection iDirection;
+
+ TUint iIsRunning;
};
} // namespace Audio
--- a/baseport/syborg/soundsc/virtio_audio_defs.h Mon May 10 11:37:38 2010 +0100
+++ b/baseport/syborg/soundsc/virtio_audio_defs.h Wed May 12 23:13:16 2010 +0100
@@ -59,7 +59,8 @@
enum StreamDirection
{
EDirectionPlayback = 0,
- EDirectionRecord = 1
+ EDirectionRecord = 1,
+ EDirectionNone = 2 // closes current stream
};
struct TCommand
--- a/baseport/syborg/soundsc/virtio_iohandler.cpp Mon May 10 11:37:38 2010 +0100
+++ b/baseport/syborg/soundsc/virtio_iohandler.cpp Wed May 12 23:13:16 2010 +0100
@@ -128,7 +128,7 @@
{
SYBORG_VIRTIO_DEBUG("WaitForCompletion : {");
- TInt st = Kern::PollingWait( &DIoHandler::CheckProcessing, this, 10, 100 );
+ TInt st = Kern::PollingWait( &DIoHandler::CheckProcessing, this, 50, 100 );
ASSERT( st == KErrNone );
--- a/baseport/syborg/soundsc/virtio_queue.cpp Mon May 10 11:37:38 2010 +0100
+++ b/baseport/syborg/soundsc/virtio_queue.cpp Wed May 12 23:13:16 2010 +0100
@@ -15,7 +15,7 @@
#include "virtio_queue.h"
-#define ENABLE_QEMU_AUDIO_MODEL_BUG_WORKAROUND
+// #define ENABLE_QEMU_AUDIO_MODEL_BUG_WORKAROUND
#define ENABLE_QEMU_VIRTIO_CLEANUP_BUG_WORKAROUND
#define PHYS_ADDR(x) Epoc::LinearToPhysical( reinterpret_cast<TUint32>(x))
@@ -101,6 +101,7 @@
{
if (first>=0)
{ FreeDescs(first); }
+ SYBORG_VIRTIO_DEBUG("AddBuf Q%x - not ready", iId );
return KErrNotReady;
}
iToken[first].iTotalLen = totalLen;
@@ -146,15 +147,16 @@
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 );
+ Token token = iToken[descId].iToken;
+ SYBORG_VIRTIO_DEBUG( "GetBuf Q%x %x ..%x t%x D%x L%x OL%x", iId, iNextUsedToRead, usedIdx, token, descId, len, iToken[descId].iTotalLen );
++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
+ aLen = len?len:iToken[descId].iTotalLen; // @TODO kind of a hack to solve virtio-audio's failure to report len by syborg on the side of qemu
+#else
+ aLen = len;
#endif
return token;
}
@@ -208,10 +210,14 @@
{
do {
TRingDesc& d = iDesc[descId];
+ if ( (-1) == ((signed)d.iAddr) )
+ break;
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; }
+ if ( KFreeDescriptorMarker == d.iNext )
+ break;
descId = d.iNext;
} while (ETrue);
}
@@ -235,8 +241,9 @@
ASSERT( iToken[i].iToken == token );
iToken[i].iToken = 0;
iToken[i].iTotalLen = 0;
- i = (flags&TRingDesc::EFlagNext)
- ? iDesc[i].iNext : -1;
+ if ((flags&TRingDesc::EFlagNext)==0)
+ break;
+ i = iDesc[i].iNext;
}
}
@@ -282,7 +289,7 @@
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]);
+ iUsedSize = sizeof(TRingUsed) + (iCount-1) * sizeof(((TRingUsed*)0)->iRing[0]);
TUint size = usedOffset + iUsedSize;
TUint8* iMemAligned;
@@ -295,8 +302,8 @@
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, Virt iDesc=%x/%x,iAvail=%x/%x,iToken=%x,iUsed=%x/%x",
+ iId, iDesc, iDescSize, iAvail, iAvailSize, iToken, iUsed, iUsedSize );
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)) );
@@ -306,8 +313,8 @@
void DQueue::PreInitQueue()
{
memset(iDesc, -1, iDescSize );
- memset( ((TUint8*) iAvail) + 4, -1, iDescSize - 4 );
- memset( ((TUint8*) iUsed) + 4, -1, iDescSize - 4 );
+ memset( ((TUint8*) iAvail) + 4, -1, iAvailSize - 4 );
+ memset( ((TUint8*) iUsed) + 4, -1, iUsedSize - 4 );
iAvail->iFlags = 0; // no notifications from control queue
iUsed->iFlags = 0;
--- a/symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/virtio-audio.c Mon May 10 11:37:38 2010 +0100
+++ b/symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/virtio-audio.c Wed May 12 23:13:16 2010 +0100
@@ -39,6 +39,9 @@
#define NUM_STREAMS 2
+#define VIRT_CONTROL_QUEUE_SIZE 0x40
+#define VIRT_DATA_QUEUE_SIZE 0x80
+
typedef struct {
struct VirtIOAudio *dev;
VirtQueue *data_vq;
@@ -97,9 +100,13 @@
if (stream->in_voice) {
iov_len = stream->elem.in_num;
iov = stream->elem.in_sg;
- } else {
+ } else if (stream->out_voice) {
iov_len = stream->elem.out_num;
iov = stream->elem.out_sg;
+ } else
+ {
+ DPRINTF("No voice selected skipping block\n");
+ return 0;
}
written = 0;
for (n = 0; total_len > 0 && n < iov_len; n++) {
@@ -119,8 +126,10 @@
while (to_write) {
if (stream->in_voice) {
size = AUD_read(stream->in_voice, p, to_write);
+ } else if (stream->out_voice) {
+ size = AUD_write(stream->out_voice, p, to_write);
} else {
- size = AUD_write(stream->out_voice, p, to_write);
+ size = 0;
}
DPRINTF("Copied %d/%d\n", size, to_write);
if (size == 0) {
@@ -141,10 +150,14 @@
int n;
DPRINTF("Callback (%d)\n", avail);
+ if ((!stream->in_voice)&&(!stream->out_voice))
+ {
+ DPRINTF("Skipping callback as no voice is selected!\n");
+ }
while (avail) {
while (stream->data_left == 0) {
if (stream->has_buffer) {
- virtqueue_push(stream->data_vq, &stream->elem, 0);
+ virtqueue_push(stream->data_vq, &stream->elem, stream->data_offset);
virtio_notify(&stream->dev->vdev, stream->data_vq);
stream->has_buffer = 0;
}
@@ -160,7 +173,7 @@
if (stream->in_voice) {
for (n = 0; n < stream->elem.in_num; n++)
stream->data_left += stream->elem.in_sg[n].iov_len;
- } else {
+ } else if (stream->out_voice) {
for (n = 0; n < stream->elem.out_num; n++)
stream->data_left += stream->elem.out_sg[n].iov_len;
}
@@ -175,7 +188,7 @@
break;
}
if (stream->data_left == 0 && stream->has_buffer) {
- virtqueue_push(stream->data_vq, &stream->elem, 0);
+ virtqueue_push(stream->data_vq, &stream->elem, stream->data_offset);
virtio_notify(&stream->dev->vdev, stream->data_vq);
stream->has_buffer = 0;
}
@@ -220,6 +233,7 @@
uint32_t value;
while (virtqueue_pop(s->cmd_vq, &elem)) {
+ size_t bytes_transferred = 0;
for (out_n = 0; out_n < elem.out_num; out_n++) {
p = (uint32_t *)elem.out_sg[out_n].iov_base;
len = elem.out_sg[out_n].iov_len;
@@ -249,7 +263,8 @@
stream->fmt.freq = value;
break;
case VIRTIO_AUDIO_CMD_INIT:
- if (value & 1) {
+ out_bytes = 0;
+ if (value == 1) {
if (stream->out_voice) {
AUD_close_out(&s->card, stream->out_voice);
stream->out_voice = NULL;
@@ -261,8 +276,8 @@
virtio_audio_callback,
&stream->fmt);
virtio_audio_cmd_result(0, &elem, &out_bytes);
- } else {
- if (stream->out_voice) {
+ } else if (value == 0) {
+ if (stream->in_voice) {
AUD_close_in(&s->card, stream->in_voice);
stream->in_voice = NULL;
}
@@ -274,21 +289,36 @@
&stream->fmt);
value = AUD_get_buffer_size_out(stream->out_voice);
virtio_audio_cmd_result(value, &elem, &out_bytes);
+ } else { // let us close all down
+ if (stream->out_voice) {
+ AUD_close_out(&s->card, stream->out_voice);
+ stream->out_voice = NULL;
+ }
+ if (stream->in_voice) {
+ AUD_close_in(&s->card, stream->in_voice);
+ stream->in_voice = NULL;
+ }
}
+ bytes_transferred += out_bytes;
break;
case VIRTIO_AUDIO_CMD_RUN:
if (stream->in_voice) {
AUD_set_active_in(stream->in_voice, value);
- } else {
+ } else if (stream->out_voice) {
AUD_set_active_out(stream->out_voice, value);
+ } else
+ {
+ DPRINTF("Cannot execute CMD_RUN as no voice is active\n");
}
break;
}
p += 3;
len -= 12;
+ bytes_transferred += 12;
}
}
- virtqueue_push(s->cmd_vq, &elem, out_bytes);
+ virtqueue_push(s->cmd_vq, &elem, bytes_transferred);
+ virtio_notify(vdev, s->cmd_vq);
}
}
@@ -314,7 +344,7 @@
if (AUD_is_active_in(stream->in_voice))
mode |= 1;
} else if (stream->out_voice) {
- mode |= 4;
+ mode = 4;
if (AUD_is_active_out(stream->out_voice))
mode |= 1;
} else {
@@ -394,9 +424,9 @@
s->vdev.get_config = virtio_audio_get_config;
s->vdev.get_features = virtio_audio_get_features;
s->vdev.set_features = virtio_audio_set_features;
- s->cmd_vq = virtio_add_queue(&s->vdev, 64, virtio_audio_handle_cmd);
+ s->cmd_vq = virtio_add_queue(&s->vdev, VIRT_CONTROL_QUEUE_SIZE, virtio_audio_handle_cmd);
for (i = 0; i < NUM_STREAMS; i++) {
- s->stream[i].data_vq = virtio_add_queue(&s->vdev, 128,
+ s->stream[i].data_vq = virtio_add_queue(&s->vdev, VIRT_DATA_QUEUE_SIZE,
virtio_audio_handle_data);
s->stream[i].dev = s;
}