# HG changeset patch # User Maciej Jablonski # Date 1273702396 -3600 # Node ID d00bf4f5725092d5bf5a45c8d85ab826c3b34328 # Parent 5158c0d3bde37263398ab81d081764e516b1bc8c Fix bug 873. Fixes to syborg virtio-audio code as well as to the audio driver diff -r 5158c0d3bde3 -r d00bf4f57250 baseport/syborg/soundsc/shared_sound.h --- 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 -#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 { diff -r 5158c0d3bde3 -r d00bf4f57250 baseport/syborg/soundsc/shared_txsound.cpp --- 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( + (iUnitType == KSoundScRxUnit0)?Audio::EDirectionRecord + :(iUnitType == KSoundScTxUnit0)?Audio::EDirectionPlayback:-1 ); + + iAudioControl->Setup( direction, 2, Audio::EFormatS16, 48000 ); return KErrNone; } diff -r 5158c0d3bde3 -r d00bf4f57250 baseport/syborg/soundsc/virtio.h --- 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 -#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 diff -r 5158c0d3bde3 -r d00bf4f57250 baseport/syborg/soundsc/virtio_audio.cpp --- 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( 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( 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 ) diff -r 5158c0d3bde3 -r d00bf4f57250 baseport/syborg/soundsc/virtio_audio.h --- 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 diff -r 5158c0d3bde3 -r d00bf4f57250 baseport/syborg/soundsc/virtio_audio_defs.h --- 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 diff -r 5158c0d3bde3 -r d00bf4f57250 baseport/syborg/soundsc/virtio_iohandler.cpp --- 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 ); diff -r 5158c0d3bde3 -r d00bf4f57250 baseport/syborg/soundsc/virtio_queue.cpp --- 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(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(descIdiRing[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( iMemAligned + iDescSize ); iUsed = reinterpret_cast( iMemAligned + usedOffset ); iToken = reinterpret_cast( 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; diff -r 5158c0d3bde3 -r d00bf4f57250 symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/virtio-audio.c --- 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; }