33 |
33 |
34 #include <bluetooth/hcicommandqueue.h> |
34 #include <bluetooth/hcicommandqueue.h> |
35 #include <bluetooth/hcicommandqitem.h> |
35 #include <bluetooth/hcicommandqitem.h> |
36 #include <bluetooth/hcicmdqcontroller.h> |
36 #include <bluetooth/hcicmdqcontroller.h> |
37 |
37 |
|
38 #include <bluetooth/hci/hciopcodes.h> |
|
39 |
38 #include <bluetooth/hci/controllerinitialisationinterface.h> |
40 #include <bluetooth/hci/controllerinitialisationinterface.h> |
39 #include <bluetooth/hci/hcidataframer.h> |
41 #include <bluetooth/hci/hcidataframer.h> |
40 #include <bluetooth/hci/readlocalsupportedfeaturescommand.h> |
42 #include <bluetooth/hci/readlocalsupportedfeaturescommand.h> |
41 #include <bluetooth/hci/hostbuffersizecommand.h> |
|
42 #include <bluetooth/hci/resetcommand.h> |
43 #include <bluetooth/hci/resetcommand.h> |
43 #include <bluetooth/hci/readbdaddrcommand.h> |
44 #include <bluetooth/hci/readbdaddrcommand.h> |
44 #include <bluetooth/hci/readlocalversioninfocommand.h> |
45 #include <bluetooth/hci/readlocalversioninfocommand.h> |
45 #include <bluetooth/hci/writeconnectionaccepttimeoutcommand.h> |
46 #include <bluetooth/hci/writeconnectionaccepttimeoutcommand.h> |
46 #include <bluetooth/hci/writevoicesettingcommand.h> |
47 #include <bluetooth/hci/writevoicesettingcommand.h> |
428 // Ensure that no command or data messages are output by blocking all channels |
422 // Ensure that no command or data messages are output by blocking all channels |
429 // |
423 // |
430 iLinkMgrProtocol.LinkMuxer().ChannelsClosed(KHCITransportAllChannels); |
424 iLinkMgrProtocol.LinkMuxer().ChannelsClosed(KHCITransportAllChannels); |
431 iLinkMgrProtocol.Error(KErrHardwareNotAvailable); |
425 iLinkMgrProtocol.Error(KErrHardwareNotAvailable); |
432 // Reset UI |
426 // Reset UI |
|
427 // |
433 iLinkMgrProtocol.SetUIConnecting(EFalse); |
428 iLinkMgrProtocol.SetUIConnecting(EFalse); |
434 iLinkMgrProtocol.SetUINumPhysicalLinks(0); |
429 iLinkMgrProtocol.SetUINumPhysicalLinks(0); |
435 // The h/w CoD has been reset, so we need to clear our persistent value, to reflect this |
430 // The h/w has been (or will be) reset, so we need to clear our locally cached data |
|
431 // |
|
432 iLinkMgrProtocol.LinkMuxer().ResetFlowControlMode(); |
436 iLinkMgrProtocol.ClearPendingLocalDeviceSettingsCod(); |
433 iLinkMgrProtocol.ClearPendingLocalDeviceSettingsCod(); |
437 |
434 |
438 // Removes any pending AFH Channel Classification command |
435 // Removes any pending AFH Channel Classification command |
439 // and cancels timer. |
436 // and cancels timer. |
440 // NB This ensures AFH host channel classification command blocking is |
437 // NB This ensures AFH host channel classification command blocking is |
527 ETwoWayFlowControlEnabled, then it is the responsibility of the HCI client |
524 ETwoWayFlowControlEnabled, then it is the responsibility of the HCI client |
528 to issue the appropriate HostBufferSize(..) command. |
525 to issue the appropriate HostBufferSize(..) command. |
529 */ |
526 */ |
530 { |
527 { |
531 LOG_FUNC |
528 LOG_FUNC |
|
529 |
532 switch (aMode) |
530 switch (aMode) |
533 { |
531 { |
534 case ENoFlowControl: |
532 case ENoFlowControl: |
535 { |
533 case EFlowControlToHostControllerOnly: |
536 #ifndef _DEBUG |
534 case EFlowControlFromHostControllerOnly: |
537 Panic(ELinkMgrBadFlowControlSetInReleaseBuild); |
535 case ETwoWayFlowControlEnabled: |
538 #endif |
536 // a valid argument has been provided |
539 break; |
537 break; |
540 } |
538 default: |
541 case EFlowControlToHostControllerOnly: |
539 Panic(ELinkMgrNoSuchFlowControlMode); |
542 { |
540 break; |
543 // the host will not tell the Controller about its buffers |
541 } |
544 |
542 |
545 User::LeaveIfError( |
543 TBool ctrlerToHostFlowControl = (aMode == ETwoWayFlowControlEnabled) || (aMode == EFlowControlFromHostControllerOnly); |
546 SendInitialisationCommand(CReadBufferSizeCommand::NewL())); |
544 TBool hostToCtrlerFlowControl = (aMode == ETwoWayFlowControlEnabled) || (aMode == EFlowControlToHostControllerOnly); |
547 break; |
545 |
548 } |
546 if(hostToCtrlerFlowControl) |
549 case EFlowControlFromHostControllerOnly: |
547 { |
550 { |
548 LEAVEIFERRORL(SendInitialisationCommand(CReadBufferSizeCommand::NewL())); |
551 #ifdef _DEBUG |
549 } |
552 CHCICommandBase *command = CHostBufferSizeCommand::NewL(KLinkMgrIncomingBufferSize, |
550 |
553 KStackSCOBuffersSize, KStackACLBuffersNum, |
551 if(ctrlerToHostFlowControl) |
554 KStackSCOBuffersNum); |
552 { |
555 |
553 static const TUint8 KControllerToHostFlowControlAclOnSyncOff = 0x01; |
556 User::LeaveIfError(SendInitialisationCommand(command)); |
554 CHCICommandBase* command = |
557 |
555 CSetControllerToHostFlowControlCommand::NewL(KControllerToHostFlowControlAclOnSyncOff); |
558 command = CSetControllerToHostFlowControlCommand::NewL(ETrue); |
556 LEAVEIFERRORL(SendInitialisationCommand(command)); |
559 |
557 // When this command successfully completes then host buffer size command will be issued. |
560 User::LeaveIfError(SendInitialisationCommand(command)); |
558 } |
561 |
559 else |
562 #else |
560 { |
563 Panic(ELinkMgrBadFlowControlSetInReleaseBuild); |
561 iLinkMuxer->RecordHostControllerToHostFlowControl(EFalse); |
564 #endif |
|
565 break; |
|
566 } |
|
567 case ETwoWayFlowControlEnabled: |
|
568 { |
|
569 CHCICommandBase *command = CHostBufferSizeCommand::NewL(KLinkMgrIncomingBufferSize, |
|
570 KStackSCOBuffersSize, KStackACLBuffersNum, |
|
571 KStackSCOBuffersNum); |
|
572 |
|
573 User::LeaveIfError(SendInitialisationCommand(command)); |
|
574 |
|
575 command = CSetControllerToHostFlowControlCommand::NewL(ETrue); |
|
576 |
|
577 User::LeaveIfError(SendInitialisationCommand(command)); |
|
578 |
|
579 break; |
|
580 } |
|
581 default: |
|
582 Panic(ELinkMgrNoSuchFlowControlMode); |
|
583 break; |
|
584 } |
562 } |
585 } |
563 } |
586 |
564 |
587 |
565 |
588 // simple forwarding functions so that all stack usage to HCI is via Facade. |
566 // simple forwarding functions so that all stack usage to HCI is via Facade. |
1096 { |
1066 { |
1097 LOG_FUNC |
1067 LOG_FUNC |
1098 return KErrNone; |
1068 return KErrNone; |
1099 } |
1069 } |
1100 |
1070 |
1101 #ifdef HOSTCONTROLLER_TO_HOST_FLOW_CONTROL |
|
1102 |
|
1103 CHostMBufPool* CHostMBufPool::NewL(CHCIFacade& aHCIFacade) |
|
1104 { |
|
1105 LOG_FUNC |
|
1106 CHostMBufPool* self = new (ELeave) CHostMBufPool(aHCIFacade); |
|
1107 CleanupStack::PushL(self); |
|
1108 self->ConstructL(); |
|
1109 CleanupStack::Pop(self); |
|
1110 return self; |
|
1111 } |
|
1112 |
|
1113 void CHostMBufPool::DeletePool(TSglQue<TPoolBuffer>& aQueue) |
|
1114 { |
|
1115 LOG_FUNC |
|
1116 TPoolBuffer* tmpItem = NULL; |
|
1117 TSglQueIter<TPoolBuffer> iter(aQueue); |
|
1118 while(iter) |
|
1119 { |
|
1120 tmpItem=iter++; |
|
1121 aQueue.Remove(*tmpItem); |
|
1122 delete tmpItem; |
|
1123 } |
|
1124 } |
|
1125 |
|
1126 CHostMBufPool::~CHostMBufPool() |
|
1127 { |
|
1128 LOG_FUNC |
|
1129 Cancel(); |
|
1130 DeletePool(iBufferPool); |
|
1131 DeletePool(iWaitingAllocPool); |
|
1132 } |
|
1133 |
|
1134 CHostMBufPool::CHostMBufPool(CHCIFacade& aHCIFacade) : |
|
1135 CActive(0),iHCIFacade(aHCIFacade),iBufferPool(_FOFF(TPoolBuffer,iLink)), |
|
1136 iWaitingAllocPool(_FOFF(TPoolBuffer,iLink)),iCurrAckHandle(KErrNotFound),iCurrCompletedPackets(0) |
|
1137 { |
|
1138 LOG_FUNC |
|
1139 } |
|
1140 |
|
1141 void CHostMBufPool::ConstructL() |
|
1142 /** |
|
1143 2nd phase constructor for the Host MBuf Pool. |
|
1144 |
|
1145 This method will attempt to reserve enough MBufs from the global pool |
|
1146 for bluetooth use. |
|
1147 @leave KErrNoMemory If the required number of MBufs couldn't be reserved |
|
1148 */ |
|
1149 { |
|
1150 LOG_FUNC |
|
1151 LOG2(_L("CHostMBufPool: now reserving %d size %d MBufChains"),KStackACLBuffersNum,KLinkMgrIncomingBufferSize); |
|
1152 |
|
1153 for (TInt i=0;i<=KStackACLBuffersNum-1;i++) |
|
1154 { |
|
1155 TPoolBuffer* thisBuffer = new (ELeave) TPoolBuffer(); |
|
1156 CleanupStack::PushL(thisBuffer); |
|
1157 thisBuffer->iCurrentHandle=KErrNotFound; //we assert on this later |
|
1158 thisBuffer->iMBufChain.AllocL(KLinkMgrIncomingBufferSize); |
|
1159 iBufferPool.AddFirst(*thisBuffer); |
|
1160 CleanupStack::Pop(thisBuffer); |
|
1161 } |
|
1162 |
|
1163 CActiveScheduler::Add(this); |
|
1164 } |
|
1165 |
|
1166 void CHostMBufPool::DoCancel() |
|
1167 { |
|
1168 LOG_FUNC |
|
1169 iMBufRequester.Cancel(); |
|
1170 } |
|
1171 |
|
1172 RMBufChain CHostMBufPool::TakeBuffer(const THCIConnHandle& aConnHandle) |
|
1173 /** |
|
1174 Takes a buffer from the pool and schedules an asynchronous allocation |
|
1175 of the next buffer. Only when that allocation has succeeded will the host |
|
1176 controller be signalled with a host_number_of_completed_packets. Hence, |
|
1177 if we cannot allocate a buffer from the global MBuf pool, the host controller |
|
1178 will be flowed off and no data will be lost. |
|
1179 */ |
|
1180 { |
|
1181 LOG_FUNC |
|
1182 TPoolBuffer* ready = iBufferPool.First(); |
|
1183 iBufferPool.Remove(*ready); |
|
1184 __ASSERT_DEBUG(!ready->iMBufChain.IsEmpty(),Panic(ELinkMgrHostControllerHasOverflowedHost)); |
|
1185 __ASSERT_DEBUG(ready->iCurrentHandle==KErrNotFound,Panic(ELinkMgrHostControllerHasOverflowedHost)); |
|
1186 ready->iCurrentHandle = aConnHandle; |
|
1187 |
|
1188 RMBufChain retChain; |
|
1189 retChain.Assign(ready->iMBufChain); |
|
1190 |
|
1191 if (IsActive()) |
|
1192 { |
|
1193 //This buffer will be reclaimed from the global pool |
|
1194 //after the one(s) we're currently trying to reclaim |
|
1195 LOG(_L("CHostMBufPool: TakeBuffer, buffer taken while alloc outstanding: queued alloc")); |
|
1196 iWaitingAllocPool.AddLast(*ready); |
|
1197 } |
|
1198 else |
|
1199 { |
|
1200 LOG(_L("CHostMBufPool: TakeBuffer, buffer taken")); |
|
1201 iBufferPool.AddLast(*ready); //NB the Controller cannot use this |
|
1202 //buffer until it is alloced as it will |
|
1203 //be flowed off. |
|
1204 iMBufRequester.Alloc(ready->iMBufChain,KLinkMgrIncomingBufferSize,iStatus); |
|
1205 SetActive(); |
|
1206 } |
|
1207 |
|
1208 return retChain; |
|
1209 } |
|
1210 |
|
1211 void CHostMBufPool::RunL() |
|
1212 { |
|
1213 LOG_FUNC |
|
1214 if (iStatus.Int()!=KErrNone) |
|
1215 { |
|
1216 LOG1(_L("Error! CHostMBufPool:: RunL %d"),iStatus.Int()); |
|
1217 __DEBUGGER(); |
|
1218 } |
|
1219 else |
|
1220 { |
|
1221 TPoolBuffer* justAllocd = iBufferPool.Last(); |
|
1222 |
|
1223 |
|
1224 if (iCurrAckHandle==KErrNotFound) |
|
1225 { |
|
1226 //This is the first completion we have ever seen |
|
1227 iCurrAckHandle=justAllocd->iCurrentHandle; |
|
1228 } |
|
1229 |
|
1230 TBool ackNow=((justAllocd->iCurrentHandle!=iCurrAckHandle)); |
|
1231 |
|
1232 if (!ackNow) |
|
1233 { |
|
1234 iCurrCompletedPackets++; |
|
1235 LOG2(_L("CHostMBufPool: CompletedPackets++ for conn: %d [->%d]"),justAllocd->iCurrentHandle,iCurrCompletedPackets); |
|
1236 |
|
1237 if (iCurrCompletedPackets>=KStackACLBuffersTideMarkNum) |
|
1238 { |
|
1239 ackNow=ETrue; |
|
1240 } |
|
1241 } |
|
1242 |
|
1243 if (ackNow) |
|
1244 { |
|
1245 TInt err=KErrNone; |
|
1246 |
|
1247 if (iCurrCompletedPackets>0) |
|
1248 { |
|
1249 LOG2(_L("CHostMBufPool: Sending HostNumberOfCompletedPackets for conn: %d [%d completed]"),iCurrAckHandle,iCurrCompletedPackets); |
|
1250 //Acknowledge the completed packets |
|
1251 TRAP(err, iHCIFacade.HostNumberOfCompletedPacketsL(iCurrAckHandle,iCurrCompletedPackets)); |
|
1252 //if this failed we probably couldn't alloc the memory for the command frame, |
|
1253 //the HC is still flowed off. |
|
1254 __ASSERT_DEBUG(err==KErrNone,Panic(ELinkMgrCouldNotSendHostNumberOfCompletedPackets)); |
|
1255 } |
|
1256 |
|
1257 iCurrCompletedPackets= (justAllocd->iCurrentHandle!=iCurrAckHandle) ? 1:0; |
|
1258 iCurrAckHandle=justAllocd->iCurrentHandle; |
|
1259 } |
|
1260 |
|
1261 justAllocd->iCurrentHandle=KErrNotFound; |
|
1262 |
|
1263 if (!iWaitingAllocPool.IsEmpty()) |
|
1264 { |
|
1265 TPoolBuffer* needsAlloc = iWaitingAllocPool.First(); |
|
1266 iBufferPool.AddLast(*needsAlloc); |
|
1267 iWaitingAllocPool.Remove(*needsAlloc); |
|
1268 iMBufRequester.Alloc(needsAlloc->iMBufChain,KLinkMgrIncomingBufferSize,iStatus); |
|
1269 SetActive(); |
|
1270 } |
|
1271 } |
|
1272 } |
|
1273 |
|
1274 #endif |
|