Fix bug 873. Fixes to syborg virtio-audio code as well as to the audio driver PDK_3.0.i
authorMaciej Jablonski <maciej.jablonski@sosco.com>
Wed, 12 May 2010 23:13:16 +0100
changeset 71 d00bf4f57250
parent 70 5158c0d3bde3
child 72 b6aa150091ee
Fix bug 873. Fixes to syborg virtio-audio code as well as to the audio driver
baseport/syborg/soundsc/shared_sound.h
baseport/syborg/soundsc/shared_txsound.cpp
baseport/syborg/soundsc/virtio.h
baseport/syborg/soundsc/virtio_audio.cpp
baseport/syborg/soundsc/virtio_audio.h
baseport/syborg/soundsc/virtio_audio_defs.h
baseport/syborg/soundsc/virtio_iohandler.cpp
baseport/syborg/soundsc/virtio_queue.cpp
symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/virtio-audio.c
--- 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;
     }