|
1 /* |
|
2 * This component and the accompanying materials are made available |
|
3 * under the terms of the License "Eclipse Public License v1.0" |
|
4 * which accompanies this distribution, and is available |
|
5 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
6 * |
|
7 * Initial Contributors: |
|
8 * Accenture Ltd |
|
9 * |
|
10 * Contributors: |
|
11 * |
|
12 * Description: This file is a part of sound driver for Syborg adaptation. |
|
13 * |
|
14 */ |
|
15 |
|
16 #include "virtio_audio.h" |
|
17 |
|
18 namespace VirtIo |
|
19 { |
|
20 namespace Audio |
|
21 { |
|
22 |
|
23 DControl::~DControl() |
|
24 { |
|
25 if (iCmdMem) |
|
26 { Kern::Free( iCmdMem ); } |
|
27 } |
|
28 |
|
29 TInt DControl::Construct() |
|
30 { |
|
31 TUint cmdSize = sizeof(iCmd[0])*KCmdMaxBufCount; |
|
32 TUint size = cmdSize + sizeof(*iBufferInfo); |
|
33 // as we are going to align the allocated memory |
|
34 // we add extra alignment size minus 1 |
|
35 iCmdMem = reinterpret_cast<TUint8*>( Kern::Alloc( size + sizeof(iCmd[0])-1 ) ); |
|
36 if (!iCmdMem) |
|
37 { return KErrNoMemory; } |
|
38 |
|
39 // let us align the memory address |
|
40 // note: sizeof(iCmd[0]) is a power of 2 |
|
41 ASSERT( sizeof(iCmd[0]) == POW2ALIGN(sizeof(iCmd[0])) ); |
|
42 TUint8* alignedMem = iCmdMem |
|
43 + ( (-(TUint32)iCmdMem)&(sizeof(iCmd[0])-1) ); // adding missing amount of bytes |
|
44 |
|
45 iCmd = reinterpret_cast<TCommandPadded*>( alignedMem ); |
|
46 iBufferInfo = reinterpret_cast<TBufferInfo*>( alignedMem + cmdSize ); |
|
47 |
|
48 for (TUint i = 0; i< KCmdMaxBufCount; ++i) |
|
49 { |
|
50 iCmd[i].iStream = iDataQueueId - 1; |
|
51 } |
|
52 iCmd[0].iCommand = Audio::ECmdSetEndian; |
|
53 iCmd[1].iCommand = Audio::ECmdSetChannels; |
|
54 iCmd[2].iCommand = Audio::ECmdSetFormat; |
|
55 iCmd[3].iCommand = Audio::ECmdSetFrequency; |
|
56 iCmd[4].iCommand = Audio::ECmdInit; |
|
57 iCmd[5].iCommand = Audio::ECmdRun; |
|
58 iCmd[5].iArg = Audio::EDoRun; //start stream |
|
59 iCmd[6].iCommand = Audio::ECmdRun; |
|
60 iCmd[6].iArg = Audio::EDoStop; //stop stream |
|
61 iCmd[7].iCommand = Audio::ECmdRun; |
|
62 iCmd[7].iArg = Audio::EDoStop; //kind of pause |
|
63 iCmd[8].iCommand = Audio::ECmdRun; |
|
64 iCmd[8].iArg = Audio::EDoRun; //kind of resume |
|
65 return KErrNone; |
|
66 } |
|
67 |
|
68 TInt DControl::Setup( StreamDirection aDirection, TInt aChannelNum, |
|
69 FormatId aFormat, TInt aFreq) |
|
70 { |
|
71 iCmd[1].iArg = aChannelNum; |
|
72 iCmd[2].iArg = aFormat; |
|
73 iCmd[3].iArg = aFreq; |
|
74 iCmd[4].iArg = iDirection = aDirection; |
|
75 AddCommand(&iCmd[0],(Token)0); |
|
76 AddCommand(&iCmd[1],(Token)1); |
|
77 AddCommand(&iCmd[2],(Token)2); |
|
78 AddCommand(&iCmd[3],(Token)3); |
|
79 AddCommand(&iCmd[4],(Token)4, iBufferInfo, sizeof(*iBufferInfo) ); |
|
80 ControlQueue().Sync(); |
|
81 return KErrNone; |
|
82 } |
|
83 |
|
84 void DControl::AddCommand( TCommandPadded* aCmd, Token aToken ) |
|
85 { |
|
86 TAddrLen list; |
|
87 list.iLen = sizeof(TCommand); |
|
88 list.iAddr = Epoc::LinearToPhysical((TUint32)aCmd); |
|
89 SYBORG_VIRTIO_DEBUG("AddCommand %x %x %x", aCmd->iCommand, aCmd->iStream, aCmd->iArg); |
|
90 ControlQueue().AddBuf(&list, 1, 0, aToken ); |
|
91 } |
|
92 |
|
93 void DControl::AddCommand( TCommandPadded* aCmd, Token aToken, |
|
94 TAny* aMem, TUint aSize ) |
|
95 { |
|
96 TAddrLen list[2]; |
|
97 list[0].iLen = sizeof(TCommand); |
|
98 list[0].iAddr = Epoc::LinearToPhysical((TUint32)aCmd); |
|
99 list[1].iLen = aSize; |
|
100 list[1].iAddr = Epoc::LinearToPhysical((TUint32)aMem); |
|
101 ControlQueue().AddBuf(list, 1, 1, aToken ); |
|
102 } |
|
103 |
|
104 |
|
105 // Waits until device processes all pending requests |
|
106 // there would be no need to have it here at all |
|
107 // if there was no bug in qemu: |
|
108 // once you send stop command the buffers processing stops... but the buffers are never returned. |
|
109 |
|
110 void DControl::WaitForCompletion() |
|
111 { |
|
112 SYBORG_VIRTIO_DEBUG("DControl::WaitForCompletion : {"); |
|
113 |
|
114 TInt st = Kern::PollingWait( &DControl::CheckProcessing, this, 10, 100 ); |
|
115 ASSERT ( (st == KErrNone) && "Polling problem" ) |
|
116 |
|
117 SYBORG_VIRTIO_DEBUG("DControlWaitForCompletion : }"); |
|
118 } |
|
119 |
|
120 TBool DControl::CheckProcessing( TAny* aSelf ) |
|
121 { |
|
122 DControl* self = reinterpret_cast<DControl*>( aSelf ); |
|
123 return self->DataQueue().Processing() == 0; |
|
124 } |
|
125 |
|
126 void DControl::AddCommand( Command aCmd ) |
|
127 { |
|
128 TUint idx = aCmd; |
|
129 if (aCmd == EStop) |
|
130 { |
|
131 // due to bug on qemu's side we need to stop sending buffers |
|
132 // and wait for all pending buffers to get filled... |
|
133 WaitForCompletion(); |
|
134 } |
|
135 AddCommand(&iCmd[idx], (Token)idx ); |
|
136 } |
|
137 |
|
138 TInt DControl::SendDataBuffer( TAny* virtaulAddr, TUint aSize, Token aToken ) |
|
139 { |
|
140 TAddrLen sgl[KMaxSGLItemCountPerAudioBuffer]; |
|
141 TUint sglCount = KMaxSGLItemCountPerAudioBuffer; |
|
142 TInt st = LinearToSGL(virtaulAddr, aSize, sgl, sglCount ); |
|
143 ASSERT( st != KErrNoMemory ); // failure means our fixed lenght sgl table is too small |
|
144 if (st!=KErrNone) |
|
145 { return st; } |
|
146 st = DataQueue().AddBuf( sgl, |
|
147 iDirection == EDirectionPlayback ? sglCount : 0, |
|
148 iDirection == EDirectionRecord ? sglCount : 0, |
|
149 aToken ); |
|
150 if (st!=KErrNone) |
|
151 { return st; } |
|
152 DataQueue().Sync(); |
|
153 return KErrNone; |
|
154 } |
|
155 |
|
156 |
|
157 } // namespace Audio |
|
158 } // namespace VirtIo |