|
1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 /** |
|
17 @file |
|
18 @internalTechnology |
|
19 */ |
|
20 |
|
21 #ifndef HCICMDQCONTROLLER_H |
|
22 #define HCICMDQCONTROLLER_H |
|
23 |
|
24 #include <e32base.h> |
|
25 |
|
26 #include <bluetooth/hcicommandeventobserver.h> |
|
27 #include <bluetooth/hcicommandqueue.h> |
|
28 #include <bluetooth/hci/hciopcodes.h> |
|
29 #include <bttypes.h> // For THCIConnHandle |
|
30 #include <bluetooth/hci/hcicmdqueuedecisioninterface.h> |
|
31 |
|
32 class CHCICmdQueueDecisionPlugin; |
|
33 class CHCICommandQItem; |
|
34 class MHCICmdQueueDecisionInterface; |
|
35 class MHCICmdQueueEventModifierInterface; |
|
36 class MHCICommandAllocator; |
|
37 class MHCICommandQueueClient; |
|
38 class MHardResetInitiator; |
|
39 class MHCTLInterface; |
|
40 class MLinkMuxNotifier; |
|
41 class MPhysicalLinksState; |
|
42 class CHCICmdQStarvationTimer; |
|
43 class CHciUtil; |
|
44 |
|
45 // Callback interface for the timer. |
|
46 NONSHARABLE_CLASS(MHCITimerClient) |
|
47 { |
|
48 public: |
|
49 virtual void CompletionTimeoutFired(TUint aUncompletedCmdId) = 0; |
|
50 virtual void StarvationTimeoutFired(TUint aNextPendingCmdId) = 0; |
|
51 }; |
|
52 |
|
53 NONSHARABLE_CLASS(CHCICmdQController) : public CBase, |
|
54 public MHCICommandEventObserver, |
|
55 public MHCICommandQueue, |
|
56 public MHCITimerClient, |
|
57 public MHCICmdQueueUtilities |
|
58 { |
|
59 public: // exported |
|
60 IMPORT_C static CHCICmdQController* NewL(); |
|
61 IMPORT_C ~CHCICmdQController(); |
|
62 |
|
63 IMPORT_C void SetHCTLInterface(MHCTLInterface& aHctlInterface); |
|
64 IMPORT_C void SetHCICommandAllocator(MHCICommandAllocator& aCommandAllocator); |
|
65 IMPORT_C void SetLinkMuxNotifier(MLinkMuxNotifier& aLinkMuxer); |
|
66 IMPORT_C void SetHCIUnmatchedEventObserver(MHCICommandQueueClient& aUnmatchedEventObserver); |
|
67 IMPORT_C void SetHardResetInitiator(MHardResetInitiator& aHardResetInitiator); |
|
68 IMPORT_C void SetPhysicalLinksState(const MPhysicalLinksState& aStackInfo); |
|
69 |
|
70 IMPORT_C void Initialise(); |
|
71 IMPORT_C void Reset(); |
|
72 IMPORT_C void Start(); |
|
73 IMPORT_C void DoSend(); |
|
74 |
|
75 public: // un-exported virtuals from MHCITimerClient |
|
76 virtual void CompletionTimeoutFired(TUint aUncompletedCmdId); |
|
77 virtual void StarvationTimeoutFired(TUint aWasNextPendingCmdId); |
|
78 |
|
79 public: // virtuals from MHCICommandQueue |
|
80 virtual TUint MhcqAddCommandL(CHCICommandQItem* aQueItem); |
|
81 virtual TUint MhcqAddCommandL(CHCICommandBase* aCommandData, MHCICommandQueueClient& aCmdProgressRecipient); |
|
82 virtual TUint MhcqAddPriorityCommandL(CHCICommandQItem* aQueItem); |
|
83 virtual TUint MhcqAddPriorityCommandL(CHCICommandBase* aCommandData, MHCICommandQueueClient& aCmdProgressRecipient); |
|
84 virtual TUint MhcqAddInitCommandL(CHCICommandQItem* aQueItem); |
|
85 virtual TUint MhcqAddInitCommandL(CHCICommandBase* aCommandData, MHCICommandQueueClient& aCmdProgressRecipient); |
|
86 virtual TInt MhcqRemoveCommand(TUint aCommandId, const MHCICommandQueueClient& aCmdOriginator); |
|
87 virtual void MhcqRemoveAllCommands(const MHCICommandQueueClient& aCmdOriginator); |
|
88 virtual TUint MhcqMaxHciCommandTimeout() const; |
|
89 virtual TAny* MhcqQdpPluginInterface(TUid aUid) const; |
|
90 |
|
91 private: // virtuals from MHCICommandEventObserver |
|
92 virtual void MhceoEventNotification(const THCIEventBase& aEvent); |
|
93 |
|
94 // Helpers |
|
95 void RemoveAllCommands(TDblQueIter<CHCICommandQItem> aIter, |
|
96 const MHCICommandQueueClient& aCmdOriginator, |
|
97 TBool aCanDelete); |
|
98 void HandleCommandRemoval(CHCICommandQItem& aCmd, TBool aCanDelete); |
|
99 void HandleCommandRemoval(CHCICommandQItem*& aCmd, TBool aCanDelete); |
|
100 void CleanUpQueue(TDblQueIter<CHCICommandQItem> aIter); |
|
101 |
|
102 private: // virtuals from MHCICmdQueueUtilities |
|
103 void MhcquiInjectEvent(const THCIEventBase& aEvent); |
|
104 CHCICommandQItem* MhcquiFindOutstandingCommand(THCIOpcode aOpcode); |
|
105 |
|
106 private: |
|
107 /** |
|
108 Command queue block bit flags. |
|
109 */ |
|
110 enum |
|
111 { |
|
112 ENoBlocks = 0x00000000, |
|
113 /** |
|
114 Indicates that there is a workaround command on the sent |
|
115 queue, so another command cannot be sent |
|
116 */ |
|
117 EWorkaroundBlock = 0x00000001, |
|
118 |
|
119 /** |
|
120 Indicates the current head of the non-priority queues has been |
|
121 blocked from MHCICmdQueueDecisionInterface::MhcqdiCanSend() |
|
122 */ |
|
123 ECanSendBlock = 0x00000002, |
|
124 |
|
125 /** |
|
126 Indicates that the current head of the non-priority queues has the |
|
127 same opcode as one on the sent queue. |
|
128 */ |
|
129 EDuplicatedOpcodeBlock = 0x00000004, |
|
130 |
|
131 /** |
|
132 Indicates that the current head of the non-priority queues does not have |
|
133 enough HCI credits. |
|
134 */ |
|
135 EInsufficientCreditBlock = 0x00000008, |
|
136 |
|
137 /** |
|
138 Indicates that there is a resent command on the sent queue, so |
|
139 another command cannot be resent. |
|
140 */ |
|
141 EResendBlock = 0x00000010, |
|
142 |
|
143 /** |
|
144 Indicates that an HCTL send request |
|
145 (MLinkMuxNotifier::TryToSend) is in progress, so another |
|
146 command cannot be scheduled until we get a DoSend() callback. |
|
147 */ |
|
148 ETryToSendBlock = 0x00000020, |
|
149 |
|
150 EAllBlocks = EWorkaroundBlock | |
|
151 ECanSendBlock | |
|
152 EDuplicatedOpcodeBlock | |
|
153 EInsufficientCreditBlock | |
|
154 EResendBlock | ETryToSendBlock, |
|
155 |
|
156 /** |
|
157 These three are different from the TryToSend, Resend and Workaround |
|
158 blocks in that they only cache the effect of the last call to OkToSendCommand |
|
159 for the most recently processed non-priority command. This means that |
|
160 when they're all 0, OkToSendCommand needs to be called to re-evaluate |
|
161 corresponding conditions. |
|
162 */ |
|
163 ECachingCommandBlocks = ECanSendBlock | |
|
164 EDuplicatedOpcodeBlock | |
|
165 EInsufficientCreditBlock, |
|
166 |
|
167 /** |
|
168 Do not include the Resend block for any of the queues waiting to send a command |
|
169 for the first time. Regardless of whether the Resend block is set we would need |
|
170 a credit to send a command and if we get more than one credit (the first |
|
171 potentially being used by a resent command) then we should use them. |
|
172 */ |
|
173 ESendQueueBlocks = EAllBlocks & ~EResendBlock, |
|
174 |
|
175 /** |
|
176 For the Resend queue we do not want to include the Workaround block as it maybe |
|
177 a workaround command being resent. |
|
178 */ |
|
179 EResendQueueBlocks = EAllBlocks & ~EWorkaroundBlock, |
|
180 }; |
|
181 |
|
182 /** |
|
183 Command queue controller state |
|
184 */ |
|
185 enum TCmdQControllerStates |
|
186 { |
|
187 /** |
|
188 Power down state state. In this state no commands will be sent or queued. |
|
189 Any attempt to queue a new command will fail. |
|
190 |
|
191 Reached on completion of async Reset() if in EResetting state. |
|
192 */ |
|
193 EUninitialised = 0, |
|
194 |
|
195 /** |
|
196 Asynchronous reset pending state. |
|
197 |
|
198 Reached by calling Reset(). |
|
199 */ |
|
200 EResetting = 1, |
|
201 |
|
202 /** |
|
203 Asynchronous reset pending state. |
|
204 |
|
205 Reached by calling Initialise() while async Reset() outstanding. |
|
206 */ |
|
207 EResetInit = 2, |
|
208 |
|
209 /** |
|
210 Initialisation state. In this state only initilisation commands will be |
|
211 sent, normal and priority commands are held on their queues. |
|
212 |
|
213 Reached by Initialise() or completion of async Reset() if in |
|
214 EResetInit state. |
|
215 */ |
|
216 EInitialising = 3, |
|
217 |
|
218 /** |
|
219 Operational state. |
|
220 |
|
221 Reached by calling Start(). |
|
222 */ |
|
223 EStarted = 4, |
|
224 }; |
|
225 |
|
226 CHCICmdQController(); |
|
227 void ConstructL(); |
|
228 |
|
229 inline TBool Blocked(TUint aBlocksToCheck, TUint aBlocksToBypass); |
|
230 inline TBool Blocked(TUint aBlockStatus, TUint aBlocksToCheck, TUint aBlocksToBypass); |
|
231 inline void ClearBlock(TUint aBlocks); |
|
232 inline void SetBlock(TUint aBlocks); |
|
233 inline TUint ValidBlocks(TUint aBlocks); |
|
234 inline TUint InvalidBlocks(TUint aBlocks); |
|
235 inline TUint CmdBypassBlocks(const CHCICommandQItem& aCmd); |
|
236 |
|
237 inline void UpdateCommandCredits(TUint8 aCommandCredits); |
|
238 |
|
239 inline TUint NextCommandQueueItemId(); |
|
240 |
|
241 inline TDblQue<CHCICommandQItem>* ActiveRegularQueue(); |
|
242 inline CHCICommandQItem* FirstQueueItem(TDblQue<CHCICommandQItem>& aQueue); |
|
243 inline CHCICommandQItem* LastQueueItem(TDblQue<CHCICommandQItem>& aQueue); |
|
244 |
|
245 inline void StorePurgeMarks(); |
|
246 inline void PurgeAllQueues(); |
|
247 void PurgeQueue(TDblQue<CHCICommandQItem>& aQueue, CHCICommandQItem* aMark); |
|
248 |
|
249 inline CHCICommandQItem* ScanQueueByOpcode(TDblQue<CHCICommandQItem>& aQueue, THCIOpcode aOpcode); |
|
250 inline CHCICommandQItem* ScanQueueByQId(TDblQue<CHCICommandQItem>& aQueue, TUint aCmdId); |
|
251 #ifdef _DEBUG |
|
252 void LogQueue(TDblQue<CHCICommandQItem>& aQueue); |
|
253 #endif // _DEBUG |
|
254 |
|
255 inline TBool CanAddCommands(); |
|
256 inline TBool CmdsQueued(TDblQue<CHCICommandQItem>* aQueue); |
|
257 inline TBool AnyCmdsToSend(); |
|
258 inline TDblQue<CHCICommandQItem>* QueueSendingNext(); |
|
259 inline TBool NextCommandChanged(const TDblQue<CHCICommandQItem> &aQueue); |
|
260 |
|
261 void DoReset(); |
|
262 void TryToSend(); |
|
263 TBool ProcessResendQueue(); |
|
264 TBool ProcessWorkaroundQueue(); |
|
265 TBool ProcessPriorityQueue(); |
|
266 void ProcessRegularQueue(TDblQue<CHCICommandQItem>& aQueue); |
|
267 |
|
268 void SetUpNextWorkaroundCmd(CHCICommandQItem* aPreviousCmd, const THCIEventBase* aPreviousCmdResult); |
|
269 void UpdateStarvationTimer(); |
|
270 |
|
271 TUint DoAddCommandL(CHCICommandQItem& aQueItem, TDblQue<CHCICommandQItem> &aQueue, TCmdQControllerStates aActiveState); |
|
272 void DeleteCommand(CHCICommandQItem* &aItem); |
|
273 TBool OkToSendCommand(CHCICommandQItem*& aCmdQItem, TUint aBypassBlocks); |
|
274 void SendCommand(CHCICommandQItem& aCmdQItem); |
|
275 |
|
276 void ProcessMatchedEvent(const THCIEventBase& aEvent, CHCICommandQItem* aCmd, TBool aConcludesCmd); |
|
277 void ProcessMatchedErrorEvent(const THCIEventBase& aEvent, CHCICommandQItem* aCmd, TBool aConcludesCmd, TBool aSendToQdp); |
|
278 void ProcessUnmatchedEvent(const THCIEventBase& aEvent, TBool aSendToQdp); |
|
279 void ProcessCommandCompletionTimeout(CHCICommandQItem* aCmd); |
|
280 void ProcessEvent(const THCIEventBase& aEvent, TBool aSendToQdp); |
|
281 |
|
282 // Static async CallBack methods. |
|
283 static TInt AsyncCallBackForReset(TAny* aCmdQController); |
|
284 static TInt AsyncCallBackForSend(TAny* aCmdQController); |
|
285 |
|
286 private: |
|
287 TUint iMaxHciCommandTimeout; |
|
288 TUint iQueueStarvationTimeout; |
|
289 |
|
290 const static TUint KDefaultMaxHciCommandTimeout = 60000; // 60 seconds. |
|
291 |
|
292 MLinkMuxNotifier* iLinkMuxer; |
|
293 MHCICommandQueueClient* iUnmatchedEventObserver; |
|
294 MHCTLInterface* iHctl; |
|
295 MHardResetInitiator* iHardResetInitiator; |
|
296 MHCICommandAllocator* iCommandAllocator; |
|
297 MHCICmdQueueDecisionInterface* iQdp; |
|
298 MHCICmdQueueEventModifierInterface* iQdpEventModifier; |
|
299 |
|
300 /** |
|
301 This timer gets reset every time the next command to send changes. |
|
302 If that command stays the same for too long, we probably have a deadlock of some sorts. |
|
303 */ |
|
304 CHCICmdQStarvationTimer* iQStarvationTimer; |
|
305 |
|
306 /** |
|
307 The queue of initialisation commands that have not yet been processed. |
|
308 */ |
|
309 TDblQue<CHCICommandQItem> iInitCommandQ; |
|
310 |
|
311 /** |
|
312 The queue of normal commands that have not yet been processed. |
|
313 */ |
|
314 TDblQue<CHCICommandQItem> iNormalCommandQ; |
|
315 |
|
316 /** |
|
317 The queue of priority commands that have not yet been processed. |
|
318 Note: it's not FIFO - the order of execution of commands is determined |
|
319 dynamically. |
|
320 */ |
|
321 TDblQue<CHCICommandQItem> iPriorityCommandQ; |
|
322 |
|
323 /** |
|
324 The queue of workarounds for commands on the other queues. |
|
325 A command is moved here when time comes to execute it but QDP deems it to |
|
326 be in need of workaround. |
|
327 */ |
|
328 TDblQue<CHCICommandQItem> iWorkaroundCommandQ; |
|
329 |
|
330 /** |
|
331 The queue of commands that have been sent to the controller but have not |
|
332 yet had a response. |
|
333 */ |
|
334 TDblQue<CHCICommandQItem> iSentCommandQ; |
|
335 |
|
336 /** |
|
337 The queue of commands that are waiting to be re-sent to the controller. |
|
338 */ |
|
339 TDblQue<CHCICommandQItem> iResendCommandQ; |
|
340 |
|
341 |
|
342 /** |
|
343 Recorded tails of the queues for Reset processing. |
|
344 */ |
|
345 CHCICommandQItem* iInitQPurgeMark; |
|
346 CHCICommandQItem* iNormalQPurgeMark; |
|
347 CHCICommandQItem* iPriorityQPurgeMark; |
|
348 CHCICommandQItem* iWorkaroundQPurgeMark; |
|
349 |
|
350 /** |
|
351 Currently processing send command. This is maintained to ensure both that the |
|
352 correct command is processed by DoSend, and that there is only ever one outstanding |
|
353 call to MLinkMuxNotifier::TryToSend at any given time |
|
354 */ |
|
355 CHCICommandQItem* iSendingCommand; |
|
356 |
|
357 /** |
|
358 Currently processing parent command. This is maintained to simplify priority |
|
359 command processing while a workaround is in progress, and to ensure that |
|
360 the parent's iQdpData is available to the QDP until the workaround completes. |
|
361 */ |
|
362 CHCICommandQItem* iParentCommand; |
|
363 |
|
364 /** |
|
365 Number of HCI command packets the queue controller can send to the HCI. This |
|
366 corresponds to the Num_HCI_Command_Packets event parameter. This is decremented |
|
367 whenever a command is sent to the HCTL, and is updated on receipt of Command Status |
|
368 and Command Complete (including NOP) events. |
|
369 */ |
|
370 TUint8 iCommandCredits; |
|
371 |
|
372 /** |
|
373 The CHCICmdQController state variable |
|
374 */ |
|
375 TCmdQControllerStates iCmdQControllerState; |
|
376 |
|
377 /** |
|
378 This is a bit mask of the possible TQueueStateBits states |
|
379 */ |
|
380 TUint iCommandQState; |
|
381 |
|
382 /** |
|
383 The QDP that the Command Queue will use. |
|
384 */ |
|
385 CHCICmdQueueDecisionPlugin* iQdpPlugin; |
|
386 |
|
387 /** |
|
388 A counter generating IDs to uniquely identify commands. |
|
389 */ |
|
390 TUint iNextCommandQItemId; |
|
391 |
|
392 /** |
|
393 HCI Utility library |
|
394 */ |
|
395 CHciUtil* iHciUtil; |
|
396 |
|
397 /** |
|
398 Async Callbacks |
|
399 */ |
|
400 CAsyncCallBack* iAsyncCallBackForReset; |
|
401 CAsyncCallBack* iAsyncCallBackForSend; |
|
402 |
|
403 }; |
|
404 |
|
405 #endif // HCICMDQCONTROLLER_H |