28 #include <bluetooth/hci/commandcompleteevent.h> |
28 #include <bluetooth/hci/commandcompleteevent.h> |
29 #include <bluetooth/hci/disconnectioncompleteevent.h> |
29 #include <bluetooth/hci/disconnectioncompleteevent.h> |
30 #include <bluetooth/hci/readclockoffsetevent.h> |
30 #include <bluetooth/hci/readclockoffsetevent.h> |
31 #include <bluetooth/hci/authenticationcompleteevent.h> |
31 #include <bluetooth/hci/authenticationcompleteevent.h> |
32 #include <bluetooth/hci/readlocalversioninfocompleteevent.h> |
32 #include <bluetooth/hci/readlocalversioninfocompleteevent.h> |
|
33 #include <bluetooth/hci/writelinkpolicysettingscommand.h> |
|
34 #include <bluetooth/hci/readlinkpolicysettingscommand.h> |
|
35 #include <bluetooth/hci/readlmphandlecommand.h> |
|
36 #include <bluetooth/hci/rolediscoverycommand.h> |
|
37 #include <bluetooth/hci/sniffsubratingcommand.h> |
|
38 #include <bluetooth/hci/flushcommand.h> |
|
39 #include <bluetooth/hci/readautomaticflushtimeoutcommand.h> |
|
40 #include <bluetooth/hci/writeautomaticflushtimeoutcommand.h> |
|
41 #include <bluetooth/hci/readtransmitpowerlevelcommand.h> |
|
42 #include <bluetooth/hci/readlinksupervisiontimeoutcommand.h> |
|
43 #include <bluetooth/hci/writelinksupervisiontimeoutcommand.h> |
|
44 #include <bluetooth/hci/readfailedcontactcountercommand.h> |
|
45 #include <bluetooth/hci/resetfailedcontactcountercommand.h> |
|
46 #include <bluetooth/hci/readlinkqualitycommand.h> |
|
47 #include <bluetooth/hci/readrssicommand.h> |
|
48 #include <bluetooth/hci/readafhchannelmapcommand.h> |
|
49 #include <bluetooth/hci/readclockcommand.h> |
|
50 |
33 #include <bluetooth/logger.h> |
51 #include <bluetooth/logger.h> |
34 |
52 |
35 #ifdef __FLOG_ACTIVE |
53 #ifdef __FLOG_ACTIVE |
36 _LIT8(KLogComponent, LOG_COMPONENT_QDP_SYMBIAN); |
54 _LIT8(KLogComponent, LOG_COMPONENT_QDP_SYMBIAN); |
37 #endif |
55 #endif |
|
56 |
|
57 #ifdef _DEBUG |
|
58 PANICCATEGORY("qdpsymbia"); |
|
59 #endif // _DEBUG |
|
60 |
|
61 void AppendConnectionHandle(TDes8& aDes, THCIConnectionHandle aConnectionHandle) |
|
62 { |
|
63 LOG_STATIC_FUNC |
|
64 THCIConnHandle connHandle = aConnectionHandle.ConnHandle(); |
|
65 LOG1(_L8("Appending connection handle = 0x%04x"), connHandle); |
|
66 TUint8 val[2] = {connHandle & 0xff, connHandle >> 8}; |
|
67 aDes.Append(val, 2); |
|
68 } |
38 |
69 |
39 /*static*/ CHCISymbianQdp* CHCISymbianQdp::NewL() |
70 /*static*/ CHCISymbianQdp* CHCISymbianQdp::NewL() |
40 { |
71 { |
41 LOG_STATIC_FUNC |
72 LOG_STATIC_FUNC |
42 |
73 |
155 { |
189 { |
156 LOG_FUNC |
190 LOG_FUNC |
157 |
191 |
158 // Cache the HCI version number of the controller. This allows |
192 // Cache the HCI version number of the controller. This allows |
159 // us to ignore errors from specific versions of controllers |
193 // us to ignore errors from specific versions of controllers |
160 if ( aEvent.EventCode() == ECommandCompleteEvent |
194 if(aEvent.EventCode() == ECommandCompleteEvent |
161 && THCICommandCompleteEvent::Cast(aEvent).CommandOpcode() == KReadLocalVersionInfoOpcode) |
195 && THCICommandCompleteEvent::Cast(aEvent).CommandOpcode() == KReadLocalVersionInfoOpcode) |
162 { |
196 { |
163 const TReadLocalVersionInfoCompleteEvent& readLocalVersionCompleteEvent = TReadLocalVersionInfoCompleteEvent::Cast(aEvent); |
197 const TReadLocalVersionInfoCompleteEvent& readLocalVersionCompleteEvent = TReadLocalVersionInfoCompleteEvent::Cast(aEvent); |
164 iHCIVersion = readLocalVersionCompleteEvent.Version(); |
198 iHCIVersion = readLocalVersionCompleteEvent.Version(); |
165 } |
199 } |
166 } |
200 } |
167 |
201 |
168 void CHCISymbianQdp::MhcqemiMatchedEventReceived(THCIEventBase& aEvent, const CHCICommandQItem& aRelatedCommand) |
202 void CHCISymbianQdp::MhcqemiMatchedEventReceived(THCIEventBase& aEvent, const CHCICommandQItem& aRelatedCommand) |
169 { |
203 { |
170 LOG_FUNC |
204 LOG_FUNC |
171 |
205 |
172 #ifdef BROKEN_CASIRA_1_1 |
206 #ifdef IGNORE_INVALID_HCI_PARAMETER_ERROR_ON_SET_EVENT_MASK_ON_VERSION_1_1 |
173 FirmwareFixIgnoreErrorOnSetEventMaskForCasira(aEvent); |
207 FixIgnoreInvalidHciParameterErrorOnSetEventMaskOnVersion1_1(aEvent); |
174 #endif // BROKEN_CASIRA_1_1 |
208 #endif // IGNORE_INVALID_HCI_PARAMETER_ERROR_ON_SET_EVENT_MASK_ON_VERSION_1_1 |
175 |
209 |
176 #ifdef BROKEN_BELKIN_2_1 |
210 #ifdef FAKE_COMPLETION_EVENTS_ON_DISCONNECTION |
177 FirmwareFixFakeCompletionEventsOnDisconnectionForBelkin(aEvent); |
211 FixFakeCompletionEventsOnDisconnection(aEvent); |
178 #endif // BROKEN_BELKIN_2_1 |
212 #endif // FAKE_COMPLETION_EVENTS_ON_DISCONNECTION |
179 |
213 |
|
214 #ifdef ADD_CONNECTION_HANDLE_FOR_TRUNCATED_INVALID_CONNECTION_HANDLE_ERROR_EVENTS |
|
215 FixAddConnectionHandleForTruncatedInvalidConnectionHandleErrorEvents(aEvent, &aRelatedCommand); |
|
216 #endif // ADD_CONNECTION_HANDLE_FOR_TRUNCATED_INVALID_CONNECTION_HANDLE_ERROR_EVENTS |
|
217 |
|
218 // Don't forget to call the non-modifiable version of this function too |
180 MhcqdiMatchedEventReceived(aEvent, aRelatedCommand); |
219 MhcqdiMatchedEventReceived(aEvent, aRelatedCommand); |
181 } |
220 } |
182 |
221 |
183 |
222 |
184 MHCICmdQueueDecisionInterface::TCommandErroredAction CHCISymbianQdp::MhcqdiMatchedErrorEventReceived(const THCIEventBase& /*aErrorEvent*/, |
223 MHCICmdQueueDecisionInterface::TCommandErroredAction CHCISymbianQdp::MhcqdiMatchedErrorEventReceived(const THCIEventBase& /*aErrorEvent*/, |
195 LOG_FUNC |
234 LOG_FUNC |
196 |
235 |
197 // Notification function. No need to do anything. |
236 // Notification function. No need to do anything. |
198 } |
237 } |
199 |
238 |
200 void CHCISymbianQdp::FirmwareFixIgnoreErrorOnSetEventMaskForCasira(THCIEventBase& aEvent) |
239 void CHCISymbianQdp::FixIgnoreInvalidHciParameterErrorOnSetEventMaskOnVersion1_1(THCIEventBase& aEvent) |
201 { |
240 { |
202 LOG_FUNC |
241 LOG_FUNC |
203 // Casiras with 1.1 firmware return an EInvalidHCIParameter error |
242 // Some controllers supporting Bluetooth 1.1 return an EInvalidHCIParameter error |
204 // when SetEventMask is called. We still want to call SetEventMask but |
243 // when SetEventMask is called. We still want to call SetEventMask and catch any actual |
205 // on this (old/buggy) firmware, ignore the returned EInvalidHCIParameter |
244 // error in the stack (since it means that stack start up has failed). |
206 |
245 // In this case, stack start-up is fine, just ignore the returned EInvalidHCIParameter |
207 if ( aEvent.ErrorCode() == EInvalidHCIParameter |
246 |
208 && aEvent.EventCode() == ECommandCompleteEvent |
247 if(aEvent.ErrorCode() == EInvalidHCIParameter |
209 && KSetEventMaskOpcode == THCICommandCompleteEvent::Cast(aEvent).CommandOpcode() |
248 && aEvent.EventCode() == ECommandCompleteEvent |
210 && iHCIVersion == EHWHCIv1_1) |
249 && KSetEventMaskOpcode == THCICommandCompleteEvent::Cast(aEvent).CommandOpcode() |
211 { |
250 && iHCIVersion == EHWHCIv1_1) |
212 THCIEventBase& modevent = const_cast<THCIEventBase&>(aEvent); |
251 { |
213 THCIEventModifiable& event = reinterpret_cast<THCIEventModifiable&>(modevent); |
252 LOG(_L8("Ignoring Invalid HCI Parameter error for Set Event Mask")); |
|
253 THCIEventModifiable& event = static_cast<THCIEventModifiable&>(aEvent); |
214 event.SetErrorCode(EOK); |
254 event.SetErrorCode(EOK); |
215 } |
255 } |
216 } |
256 } |
217 |
257 |
218 void CHCISymbianQdp::FirmwareFixFakeCompletionEventsOnDisconnectionForBelkin(THCIEventBase& aEvent) |
258 void CHCISymbianQdp::FixFakeCompletionEventsOnDisconnection(THCIEventBase& aEvent) |
219 { |
259 { |
220 LOG_FUNC |
260 LOG_FUNC |
221 // For Belkin 2.1 controllers, if we receive a "Disconnection Complete Event" |
261 // Some controllers fail to follow the HCI specification w.r.t. events on disconnection. |
222 // then look for a "Authentication Requested" command or "Read Clock Offset" on |
262 // The specification indicates outstanding data on a connection handle to be considered |
223 // the sent queue, and if found, then fake up an completion event (with reason |
263 // removed when a disconnection occurs. Events however are not guarded by such text |
224 // code copied from the Disconnection Complete Event) and inject this into the |
264 // and should always be returned (with an appropriate error code). |
225 // queue. This is because the Belkin 2.1 controllers fail to send a completion |
265 // The command queue expects these events (as it is programmed to the spec) so if a |
226 // event for "Read Clock Offset" and "Request Authentication" (and maybe others) |
266 // controller fails to perform the task, we have to make up the shortfall. Currently |
227 // themselves (i.e. these are firmware bugs we're working around) |
267 // the following events are the ones that fail to be generated in the controllers. |
228 |
268 // This issue has been observed with: |
229 if (aEvent.EventCode() == EDisconnectionCompleteEvent && iHCIVersion == EHWHCIv2_1) |
269 // |
|
270 // * Authentication_Complete |
|
271 // * Read_Clock_Offset |
|
272 |
|
273 if(aEvent.EventCode() == EDisconnectionCompleteEvent) |
230 { |
274 { |
231 const TDisconnectionCompleteEvent& disconnEvent = TDisconnectionCompleteEvent::Cast(aEvent); |
275 const TDisconnectionCompleteEvent& disconnEvent = TDisconnectionCompleteEvent::Cast(aEvent); |
232 THCIConnectionHandle handle = disconnEvent.ConnectionHandle(); |
276 THCIConnectionHandle handle = disconnEvent.ConnectionHandle(); |
233 THCIErrorCode reason = static_cast<THCIErrorCode>(disconnEvent.Reason()); |
277 THCIErrorCode reason = static_cast<THCIErrorCode>(disconnEvent.Reason()); |
234 |
278 |
235 if (iProvider->FindOutstandingCommand(KAuthenticationRequestedOpcode) != NULL) |
279 if(iProvider->FindOutstandingCommand(KAuthenticationRequestedOpcode)) |
236 { |
280 { |
237 TBuf8<KHCIMaxEventSize> eventBuf1; |
281 LOG(_L8("Injecting Authentication Complete Event")); |
238 TAuthenticationCompleteEvent authenticationCompleteEvent(reason, handle, eventBuf1); |
282 TAuthenticationCompleteEvent authenticationCompleteEvent(reason, handle, iEventModBuffer); |
239 iProvider->InjectEvent(authenticationCompleteEvent); |
283 iProvider->InjectEvent(authenticationCompleteEvent); |
240 } |
284 } |
241 |
285 |
242 if (iProvider->FindOutstandingCommand(KReadClockOffsetOpcode) != NULL) |
286 if(iProvider->FindOutstandingCommand(KReadClockOffsetOpcode)) |
243 { |
287 { |
244 TBuf8<KHCIMaxEventSize> eventBuf2; |
288 LOG(_L8("Injecting Read Clock Offset Complete Event")); |
245 THCIClockOffset clockOffset = 0; |
289 THCIClockOffset clockOffset = 0; |
246 TReadClockOffsetEvent readClockOffsetEvent(reason, handle, clockOffset, eventBuf2); |
290 TReadClockOffsetEvent readClockOffsetEvent(reason, handle, clockOffset, iEventModBuffer); |
247 iProvider->InjectEvent(readClockOffsetEvent); |
291 iProvider->InjectEvent(readClockOffsetEvent); |
248 } |
292 } |
249 } |
293 } |
250 } |
294 } |
251 |
295 |
|
296 /** |
|
297 Utility template class for FixAddConnectionHandleForTruncatedInvalidConnectionHandleErrorEvents function. |
|
298 */ |
|
299 template<class XCommandCompleteCommandClass> |
|
300 struct AttemptToFixCommandCompleteEvent |
|
301 { |
|
302 static void CheckAndFix(THCICommandCompleteEvent& aEvent, const CHCICommandQItem* aRelatedCommand, TDes8& aNewBuffer, TInt aCorrectSize, TInt aExpectedSizeMissing) |
|
303 { |
|
304 LOG_STATIC_FUNC |
|
305 THCIEventModifiable& event = static_cast<THCIEventModifiable&>(static_cast<THCIEventBase&>(aEvent)); |
|
306 // Check to see if the data is truncated - only apply the fix if it is |
|
307 if(event.EventData().Length() == (aCorrectSize-aExpectedSizeMissing)) |
|
308 { |
|
309 // This is actually a best effort guess that the connection handle is missing. Fixing this isn't simple because |
|
310 // we need a bigger buffer than we may have - so we have to create our own backing buffer for the event. |
|
311 LOG1(_L8("Modifying Command Complete event (opcode = 0x%04x) to add Connection Handle"), aEvent.CommandOpcode()); |
|
312 aNewBuffer.FillZ(aCorrectSize); // ensure buffer is clean |
|
313 aNewBuffer.Copy(event.EventData()); |
|
314 if(aRelatedCommand) |
|
315 { |
|
316 const XCommandCompleteCommandClass& cmd = static_cast<const XCommandCompleteCommandClass&>(aRelatedCommand->Command()); |
|
317 AppendConnectionHandle(aNewBuffer, cmd.ConnectionHandle()); |
|
318 } |
|
319 else |
|
320 { |
|
321 // we have no connection handle to insert in, so pick one that can |
|
322 // never be valid. |
|
323 AppendConnectionHandle(aNewBuffer, KInvalidConnectionHandle); |
|
324 } |
|
325 aNewBuffer.SetLength(aCorrectSize); |
|
326 event.EventData().Set(aNewBuffer); // update event to point to new buffer |
|
327 } |
|
328 // Ensure that now the event is correct. |
|
329 ASSERT_DEBUG(event.EventData().Length() == aCorrectSize); |
|
330 } |
|
331 }; |
|
332 |
|
333 void CHCISymbianQdp::FixAddConnectionHandleForTruncatedInvalidConnectionHandleErrorEvents(THCIEventBase& aEvent, const CHCICommandQItem* aRelatedCommand) |
|
334 { |
|
335 LOG_FUNC |
|
336 // Some controllers do not follow the HCI specification in that they do not always return |
|
337 // an event of the correct size - in this case controllers omit a connection handle field when |
|
338 // erroring with "invalid connection handle" error code. One can argue about this but the |
|
339 // command queue is designed with the spec in mind so just adjust the events as appropriate. |
|
340 // |
|
341 // Notably command complete events are the events with issues; if a command status is used |
|
342 // then the error code is communicated without any other parameters, and the resulting events will |
|
343 // not generally be generated (see FixFakeCompletionEventsOnDisconnection). |
|
344 // Current events that have observed (^) this issue (or could potentially have this issue (*)) are: |
|
345 // |
|
346 // ^ Command_Complete (Write_Link_Policy_Settings) |
|
347 // ^ Command_Complete (Read_Link_Policy_Settings) |
|
348 // * Command_Complete (Read_LMP_Handle) |
|
349 // ^ Command_Complete (Role_Discovery) |
|
350 // ^ Command_Complete (Sniff_Subrating) |
|
351 // * Command_Complete (Flush) |
|
352 // * Command_Complete (Read_Auto_Flush_Timeout) |
|
353 // * Command_Complete (Write_Auto_Flush_Timeout) |
|
354 // * Command_Complete (Read_Transmit_Power_Level) |
|
355 // * Command_Complete (Read_Link_Supervision_Timeout) |
|
356 // * Command_Complete (Write_Link_Supervision_Timeout) |
|
357 // * Command_Complete (Read_Failed_Contact_Counter) |
|
358 // * Command_Complete (Reset_Failed_Contact_Counter) |
|
359 // * Command_Complete (Read_Link_Quality) |
|
360 // * Command_Complete (Read_RSSI) |
|
361 // * Command_Complete (Read_AFH_Channel_Map) |
|
362 // * Command_Complete (Read_Clock) |
|
363 // |
|
364 // Only those actually observed as issues are included - the others are commented out for reference |
|
365 |
|
366 if(aEvent.ErrorCode() == ENoConnection) |
|
367 { |
|
368 if(aEvent.EventCode() == ECommandCompleteEvent) |
|
369 { |
|
370 THCICommandCompleteEvent& completeEvent = THCICommandCompleteEvent::Cast(aEvent); |
|
371 // Macro to make the code more concise |
|
372 #define _CHECK_AND_FIX(_COMMAND_NAME, _CORRECT_SIZE, _MISSING_SIZE) \ |
|
373 case K##_COMMAND_NAME##Opcode:\ |
|
374 AttemptToFixCommandCompleteEvent<C##_COMMAND_NAME##Command>::CheckAndFix(completeEvent, aRelatedCommand, iEventModBuffer, (_CORRECT_SIZE), (_MISSING_SIZE));\ |
|
375 break |
|
376 switch(completeEvent.CommandOpcode()) |
|
377 { |
|
378 _CHECK_AND_FIX(WriteLinkPolicySettings, 8, sizeof(THCIConnHandle)); |
|
379 _CHECK_AND_FIX(ReadLinkPolicySettings, 10, sizeof(THCIConnHandle) + sizeof(TUint16)); |
|
380 _CHECK_AND_FIX(RoleDiscovery, 9, sizeof(THCIConnHandle) + sizeof(TUint8)); |
|
381 _CHECK_AND_FIX(SniffSubrating, 8, sizeof(THCIConnHandle)); |
|
382 |
|
383 // These below are included as they potentially could have the same problem, |
|
384 // however in practice this issue has not been observed. |
|
385 // _CHECK_AND_FIX(ReadLMPHandle, 13, sizeof(THCIConnHandle) + sizeof(TUint8) + sizeof(TUint32)); |
|
386 // _CHECK_AND_FIX(Flush, 8, sizeof(THCIConnHandle) + sizeof(TUint8) + sizeof(TUint32)); |
|
387 // _CHECK_AND_FIX(ReadAutomaticFlushTimeout, 10, sizeof(THCIConnHandle) + sizeof(TUint16)); |
|
388 // _CHECK_AND_FIX(WriteAutomaticFlushTimeout, 8, sizeof(THCIConnHandle)); |
|
389 // _CHECK_AND_FIX(ReadTransmitPowerLevel, 9, sizeof(THCIConnHandle) + sizeof(TUint8)); |
|
390 // _CHECK_AND_FIX(ReadLinkSupervisionTimeout, 10, sizeof(THCIConnHandle) + sizeof(TUint16)); |
|
391 // _CHECK_AND_FIX(WriteLinkSupervisionTimeout, 8, sizeof(THCIConnHandle)); |
|
392 // _CHECK_AND_FIX(ReadFailedContactCounter, 10, sizeof(THCIConnHandle) + sizeof(TUint16)); |
|
393 // _CHECK_AND_FIX(ResetFailedContactCounter, 8, sizeof(THCIConnHandle)); |
|
394 // _CHECK_AND_FIX(ReadLinkQuality, 9, sizeof(THCIConnHandle)); |
|
395 // _CHECK_AND_FIX(ReadRSSI, 9, sizeof(THCIConnHandle) + sizeof(TUint8)); |
|
396 // _CHECK_AND_FIX(ReadAFHChannelMap, 19, sizeof(THCIConnHandle) + sizeof(TUint8) + 10); |
|
397 // _CHECK_AND_FIX(ReadClock, 14, sizeof(THCIConnHandle) + sizeof(TUint32) + sizeof(TUint16)); |
|
398 |
|
399 default: |
|
400 // just ignore |
|
401 break; |
|
402 } |
|
403 #undef _CHECK_AND_FIX |
|
404 } |
|
405 } |
|
406 } |
|
407 |
252 void CHCISymbianQdp::MhcqemiUnmatchedEventReceived(THCIEventBase& aEvent) |
408 void CHCISymbianQdp::MhcqemiUnmatchedEventReceived(THCIEventBase& aEvent) |
253 { |
409 { |
254 LOG_FUNC |
410 LOG_FUNC |
255 |
411 |
256 #ifdef BROKEN_BELKIN_2_1 |
412 #ifdef FAKE_COMPLETION_EVENTS_ON_DISCONNECTION |
257 FirmwareFixFakeCompletionEventsOnDisconnectionForBelkin(aEvent); |
413 FixFakeCompletionEventsOnDisconnection(aEvent); |
258 #endif // BROKEN_BELKIN_2_1 |
414 #endif // FAKE_COMPLETION_EVENTS_ON_DISCONNECTION |
259 |
415 |
260 MhcqdiUnmatchedEventReceived(aEvent); |
416 MhcqdiUnmatchedEventReceived(aEvent); |
261 } |
417 } |
262 |
418 |
263 MHCICmdQueueDecisionInterface::TCommandTimedOutAction CHCISymbianQdp::MhcqdiCommandTimedOut(const CHCICommandQItem& /*aCommand*/, |
419 MHCICmdQueueDecisionInterface::TCommandTimedOutAction CHCISymbianQdp::MhcqdiCommandTimedOut(const CHCICommandQItem& /*aCommand*/, |