NfcAdaptation.cpp revision b7cb567fb2a69c4f8afbb5c5f819e2390ba6424d
1/****************************************************************************** 2 * 3 * Copyright (C) 1999-2012 Broadcom Corporation 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18#include "OverrideLog.h" 19#include "NfcAdaptation.h" 20extern "C" 21{ 22 #include "gki.h" 23 #include "nfa_api.h" 24 #include "nfc_int.h" 25} 26#include "config.h" 27#include "android_logmsg.h" 28 29#define LOG_TAG "NfcAdaptation" 30 31extern "C" void GKI_shutdown(); 32extern void resetConfig(); 33extern "C" void verify_stack_non_volatile_store (); 34extern "C" void delete_stack_non_volatile_store (BOOLEAN forceDelete); 35 36NfcAdaptation* NfcAdaptation::mpInstance = NULL; 37ThreadMutex NfcAdaptation::sLock; 38nfc_nci_device_t* NfcAdaptation::mHalDeviceContext = NULL; 39tHAL_NFC_CBACK* NfcAdaptation::mHalCallback = NULL; 40tHAL_NFC_DATA_CBACK* NfcAdaptation::mHalDataCallback = NULL; 41ThreadCondVar NfcAdaptation::mHalOpenCompletedEvent; 42ThreadCondVar NfcAdaptation::mHalCloseCompletedEvent; 43 44UINT32 ScrProtocolTraceFlag = SCR_PROTO_TRACE_ALL; //0x017F00; 45UINT8 appl_trace_level = 0xff; 46char bcm_nfc_location[120]; 47 48static UINT8 nfa_dm_cfg[sizeof ( tNFA_DM_CFG ) ]; 49extern tNFA_DM_CFG *p_nfa_dm_cfg; 50extern UINT8 nfa_ee_max_ee_cfg; 51extern const UINT8 nfca_version_string []; 52extern const UINT8 nfa_version_string []; 53static UINT8 deviceHostWhiteList [NFA_HCI_MAX_HOST_IN_NETWORK]; 54static tNFA_HCI_CFG jni_nfa_hci_cfg; 55extern tNFA_HCI_CFG *p_nfa_hci_cfg; 56 57/******************************************************************************* 58** 59** Function: NfcAdaptation::NfcAdaptation() 60** 61** Description: class constructor 62** 63** Returns: none 64** 65*******************************************************************************/ 66NfcAdaptation::NfcAdaptation() 67{ 68} 69 70/******************************************************************************* 71** 72** Function: NfcAdaptation::~NfcAdaptation() 73** 74** Description: class destructor 75** 76** Returns: none 77** 78*******************************************************************************/ 79NfcAdaptation::~NfcAdaptation() 80{ 81 mpInstance = NULL; 82} 83 84/******************************************************************************* 85** 86** Function: NfcAdaptation::GetInstance() 87** 88** Description: access class singleton 89** 90** Returns: pointer to the singleton object 91** 92*******************************************************************************/ 93NfcAdaptation& NfcAdaptation::GetInstance() 94{ 95 AutoThreadMutex a(sLock); 96 97 if (!mpInstance) 98 mpInstance = new NfcAdaptation; 99 return *mpInstance; 100} 101 102/******************************************************************************* 103** 104** Function: NfcAdaptation::Initialize() 105** 106** Description: class initializer 107** 108** Returns: none 109** 110*******************************************************************************/ 111void NfcAdaptation::Initialize () 112{ 113 const char* func = "NfcAdaptation::Initialize"; 114 ALOGD("%s: enter", func); 115 ALOGE("%s: ver=%s nfa=%s", func, nfca_version_string, nfa_version_string); 116 unsigned long num; 117 118 if ( GetNumValue ( NAME_USE_RAW_NCI_TRACE, &num, sizeof ( num ) ) ) 119 { 120 if (num == 1) 121 { 122 // display protocol traces in raw format 123 ProtoDispAdapterUseRawOutput (TRUE); 124 ALOGD("%s: logging protocol in raw format", func); 125 } 126 } 127 if ( !GetStrValue ( NAME_NFA_STORAGE, bcm_nfc_location, sizeof ( bcm_nfc_location ) ) ) 128 { 129 memset (bcm_nfc_location, 0, sizeof(bcm_nfc_location)); 130 strncpy (bcm_nfc_location, "/data/nfc", 9); 131 } 132 if ( GetNumValue ( NAME_PROTOCOL_TRACE_LEVEL, &num, sizeof ( num ) ) ) 133 ScrProtocolTraceFlag = num; 134 135 if ( GetStrValue ( NAME_NFA_DM_CFG, (char*)nfa_dm_cfg, sizeof ( nfa_dm_cfg ) ) ) 136 p_nfa_dm_cfg = ( tNFA_DM_CFG * ) &nfa_dm_cfg[0]; 137 138 if ( GetNumValue ( NAME_NFA_MAX_EE_SUPPORTED, &num, sizeof ( num ) ) ) 139 { 140 nfa_ee_max_ee_cfg = num; 141 ALOGD("%s: Overriding NFA_EE_MAX_EE_SUPPORTED to use %d", func, nfa_ee_max_ee_cfg); 142 } 143 144 //configure device host whitelist of HCI host ID's; see specification ETSI TS 102 622 V11.1.10 145 //(2012-10), section 6.1.3.1 146 num = GetStrValue ( NAME_DEVICE_HOST_WHITE_LIST, (char*) deviceHostWhiteList, sizeof ( deviceHostWhiteList ) ); 147 if (num) 148 { 149 memmove (&jni_nfa_hci_cfg, p_nfa_hci_cfg, sizeof(jni_nfa_hci_cfg)); 150 jni_nfa_hci_cfg.num_whitelist_host = (UINT8) num; //number of HCI host ID's in the whitelist 151 jni_nfa_hci_cfg.p_whitelist = deviceHostWhiteList; //array of HCI host ID's 152 p_nfa_hci_cfg = &jni_nfa_hci_cfg; 153 } 154 155 initializeGlobalAppLogLevel (); 156 157 verify_stack_non_volatile_store (); 158 if ( GetNumValue ( NAME_PRESERVE_STORAGE, (char*)&num, sizeof ( num ) ) && 159 (num == 1) ) 160 ALOGD ("%s: preserve stack NV store", __FUNCTION__); 161 else 162 { 163 delete_stack_non_volatile_store (FALSE); 164 } 165 166 GKI_init (); 167 GKI_enable (); 168 GKI_create_task ((TASKPTR)NFCA_TASK, BTU_TASK, (INT8*)"NFCA_TASK", 0, 0, (pthread_cond_t*)NULL, NULL); 169 { 170 AutoThreadMutex guard(mCondVar); 171 GKI_create_task ((TASKPTR)Thread, MMI_TASK, (INT8*)"NFCA_THREAD", 0, 0, (pthread_cond_t*)NULL, NULL); 172 mCondVar.wait(); 173 } 174 175 mHalDeviceContext = NULL; 176 mHalCallback = NULL; 177 memset (&mHalEntryFuncs, 0, sizeof(mHalEntryFuncs)); 178 InitializeHalDeviceContext (); 179 ALOGD ("%s: exit", func); 180} 181 182/******************************************************************************* 183** 184** Function: NfcAdaptation::Finalize() 185** 186** Description: class finalizer 187** 188** Returns: none 189** 190*******************************************************************************/ 191void NfcAdaptation::Finalize() 192{ 193 const char* func = "NfcAdaptation::Finalize"; 194 AutoThreadMutex a(sLock); 195 196 ALOGD ("%s: enter", func); 197 GKI_shutdown (); 198 199 resetConfig(); 200 201 nfc_nci_close(mHalDeviceContext); //close the HAL's device context 202 mHalDeviceContext = NULL; 203 mHalCallback = NULL; 204 memset (&mHalEntryFuncs, 0, sizeof(mHalEntryFuncs)); 205 206 ALOGD ("%s: exit", func); 207 delete this; 208} 209 210/******************************************************************************* 211** 212** Function: NfcAdaptation::signal() 213** 214** Description: signal the CondVar to release the thread that is waiting 215** 216** Returns: none 217** 218*******************************************************************************/ 219void NfcAdaptation::signal () 220{ 221 mCondVar.signal(); 222} 223 224/******************************************************************************* 225** 226** Function: NfcAdaptation::NFCA_TASK() 227** 228** Description: NFCA_TASK runs the GKI main task 229** 230** Returns: none 231** 232*******************************************************************************/ 233UINT32 NfcAdaptation::NFCA_TASK (UINT32 arg) 234{ 235 const char* func = "NfcAdaptation::NFCA_TASK"; 236 ALOGD ("%s: enter", func); 237 GKI_run (0); 238 ALOGD ("%s: exit", func); 239 return 0; 240} 241 242/******************************************************************************* 243** 244** Function: NfcAdaptation::Thread() 245** 246** Description: Creates work threads 247** 248** Returns: none 249** 250*******************************************************************************/ 251UINT32 NfcAdaptation::Thread (UINT32 arg) 252{ 253 const char* func = "NfcAdaptation::Thread"; 254 ALOGD ("%s: enter", func); 255 256 { 257 ThreadCondVar CondVar; 258 AutoThreadMutex guard(CondVar); 259 GKI_create_task ((TASKPTR)nfc_task, NFC_TASK, (INT8*)"NFC_TASK", 0, 0, (pthread_cond_t*)CondVar, (pthread_mutex_t*)CondVar); 260 CondVar.wait(); 261 } 262 263 NfcAdaptation::GetInstance().signal(); 264 265 GKI_exit_task (GKI_get_taskid ()); 266 ALOGD ("%s: exit", func); 267 return 0; 268} 269 270/******************************************************************************* 271** 272** Function: NfcAdaptation::GetHalEntryFuncs() 273** 274** Description: Get the set of HAL entry points. 275** 276** Returns: Functions pointers for HAL entry points. 277** 278*******************************************************************************/ 279tHAL_NFC_ENTRY* NfcAdaptation::GetHalEntryFuncs () 280{ 281 return &mHalEntryFuncs; 282} 283 284/******************************************************************************* 285** 286** Function: NfcAdaptation::InitializeHalDeviceContext 287** 288** Description: Ask the generic Android HAL to find the Broadcom-specific HAL. 289** 290** Returns: None. 291** 292*******************************************************************************/ 293void NfcAdaptation::InitializeHalDeviceContext () 294{ 295 const char* func = "NfcAdaptation::InitializeHalDeviceContext"; 296 ALOGD ("%s: enter", func); 297 int ret = 0; //0 means success 298 const hw_module_t* hw_module = NULL; 299 300 mHalEntryFuncs.initialize = HalInitialize; 301 mHalEntryFuncs.terminate = HalTerminate; 302 mHalEntryFuncs.open = HalOpen; 303 mHalEntryFuncs.close = HalClose; 304 mHalEntryFuncs.core_initialized = HalCoreInitialized; 305 mHalEntryFuncs.write = HalWrite; 306 mHalEntryFuncs.prediscover = HalPrediscover; 307 mHalEntryFuncs.control_granted = HalControlGranted; 308 mHalEntryFuncs.power_cycle = HalPowerCycle; 309 mHalEntryFuncs.get_max_ee = HalGetMaxNfcee; 310 311 ret = hw_get_module (NFC_NCI_HARDWARE_MODULE_ID, &hw_module); 312 if (ret == 0) 313 { 314 ret = nfc_nci_open (hw_module, &mHalDeviceContext); 315 if (ret != 0) 316 ALOGE ("%s: nfc_nci_open fail", func); 317 } 318 else 319 ALOGE ("%s: fail hw_get_module", func); 320 ALOGD ("%s: exit", func); 321} 322 323/******************************************************************************* 324** 325** Function: NfcAdaptation::HalInitialize 326** 327** Description: Not implemented because this function is only needed 328** within the HAL. 329** 330** Returns: None. 331** 332*******************************************************************************/ 333void NfcAdaptation::HalInitialize () 334{ 335 const char* func = "NfcAdaptation::HalInitialize"; 336 ALOGD ("%s", func); 337} 338 339/******************************************************************************* 340** 341** Function: NfcAdaptation::HalTerminate 342** 343** Description: Not implemented because this function is only needed 344** within the HAL. 345** 346** Returns: None. 347** 348*******************************************************************************/ 349void NfcAdaptation::HalTerminate () 350{ 351 const char* func = "NfcAdaptation::HalTerminate"; 352 ALOGD ("%s", func); 353} 354 355/******************************************************************************* 356** 357** Function: NfcAdaptation::HalOpen 358** 359** Description: Turn on controller, download firmware. 360** 361** Returns: None. 362** 363*******************************************************************************/ 364void NfcAdaptation::HalOpen (tHAL_NFC_CBACK *p_hal_cback, tHAL_NFC_DATA_CBACK* p_data_cback) 365{ 366 const char* func = "NfcAdaptation::HalOpen"; 367 ALOGD ("%s", func); 368 if (mHalDeviceContext) 369 { 370 mHalCallback = p_hal_cback; 371 mHalDataCallback = p_data_cback; 372 mHalDeviceContext->open (mHalDeviceContext, HalDeviceContextCallback, HalDeviceContextDataCallback); 373 } 374} 375 376/******************************************************************************* 377** 378** Function: NfcAdaptation::HalClose 379** 380** Description: Turn off controller. 381** 382** Returns: None. 383** 384*******************************************************************************/ 385void NfcAdaptation::HalClose () 386{ 387 const char* func = "NfcAdaptation::HalClose"; 388 ALOGD ("%s", func); 389 if (mHalDeviceContext) 390 { 391 mHalDeviceContext->close (mHalDeviceContext); 392 } 393} 394 395/******************************************************************************* 396** 397** Function: NfcAdaptation::HalDeviceContextCallback 398** 399** Description: Translate generic Android HAL's callback into Broadcom-specific 400** callback function. 401** 402** Returns: None. 403** 404*******************************************************************************/ 405void NfcAdaptation::HalDeviceContextCallback (nfc_event_t event, nfc_status_t event_status) 406{ 407 const char* func = "NfcAdaptation::HalDeviceContextCallback"; 408 ALOGD ("%s: event=%u", func, event); 409 if (mHalCallback) 410 mHalCallback (event, (tHAL_NFC_STATUS) event_status); 411} 412 413/******************************************************************************* 414** 415** Function: NfcAdaptation::HalDeviceContextDataCallback 416** 417** Description: Translate generic Android HAL's callback into Broadcom-specific 418** callback function. 419** 420** Returns: None. 421** 422*******************************************************************************/ 423void NfcAdaptation::HalDeviceContextDataCallback (uint16_t data_len, uint8_t* p_data) 424{ 425 const char* func = "NfcAdaptation::HalDeviceContextDataCallback"; 426 ALOGD ("%s: len=%u", func, data_len); 427 if (mHalDataCallback) 428 mHalDataCallback (data_len, p_data); 429} 430 431/******************************************************************************* 432** 433** Function: NfcAdaptation::HalWrite 434** 435** Description: Write NCI message to the controller. 436** 437** Returns: None. 438** 439*******************************************************************************/ 440void NfcAdaptation::HalWrite (UINT16 data_len, UINT8* p_data) 441{ 442 const char* func = "NfcAdaptation::HalWrite"; 443 ALOGD ("%s", func); 444 if (mHalDeviceContext) 445 { 446 mHalDeviceContext->write (mHalDeviceContext, data_len, p_data); 447 } 448} 449 450/******************************************************************************* 451** 452** Function: NfcAdaptation::HalCoreInitialized 453** 454** Description: Adjust the configurable parameters in the controller. 455** 456** Returns: None. 457** 458*******************************************************************************/ 459void NfcAdaptation::HalCoreInitialized (UINT8* p_core_init_rsp_params) 460{ 461 const char* func = "NfcAdaptation::HalCoreInitialized"; 462 ALOGD ("%s", func); 463 if (mHalDeviceContext) 464 { 465 mHalDeviceContext->core_initialized (mHalDeviceContext, p_core_init_rsp_params); 466 } 467} 468 469/******************************************************************************* 470** 471** Function: NfcAdaptation::HalPrediscover 472** 473** Description: Perform any vendor-specific pre-discovery actions (if needed) 474** If any actions were performed TRUE will be returned, and 475** HAL_PRE_DISCOVER_CPLT_EVT will notify when actions are 476** completed. 477** 478** Returns: TRUE if vendor-specific pre-discovery actions initialized 479** FALSE if no vendor-specific pre-discovery actions are needed. 480** 481*******************************************************************************/ 482BOOLEAN NfcAdaptation::HalPrediscover () 483{ 484 const char* func = "NfcAdaptation::HalPrediscover"; 485 ALOGD ("%s", func); 486 BOOLEAN retval = FALSE; 487 488 if (mHalDeviceContext) 489 { 490 retval = mHalDeviceContext->pre_discover (mHalDeviceContext); 491 } 492 return retval; 493} 494 495/******************************************************************************* 496** 497** Function: HAL_NfcControlGranted 498** 499** Description: Grant control to HAL control for sending NCI commands. 500** Call in response to HAL_REQUEST_CONTROL_EVT. 501** Must only be called when there are no NCI commands pending. 502** HAL_RELEASE_CONTROL_EVT will notify when HAL no longer 503** needs control of NCI. 504** 505** Returns: void 506** 507*******************************************************************************/ 508void NfcAdaptation::HalControlGranted () 509{ 510 const char* func = "NfcAdaptation::HalControlGranted"; 511 ALOGD ("%s", func); 512 if (mHalDeviceContext) 513 { 514 mHalDeviceContext->control_granted (mHalDeviceContext); 515 } 516} 517 518/******************************************************************************* 519** 520** Function: NfcAdaptation::HalPowerCycle 521** 522** Description: Turn off and turn on the controller. 523** 524** Returns: None. 525** 526*******************************************************************************/ 527void NfcAdaptation::HalPowerCycle () 528{ 529 const char* func = "NfcAdaptation::HalPowerCycle"; 530 ALOGD ("%s", func); 531 if (mHalDeviceContext) 532 { 533 mHalDeviceContext->power_cycle (mHalDeviceContext); 534 } 535} 536 537/******************************************************************************* 538** 539** Function: NfcAdaptation::HalGetMaxNfcee 540** 541** Description: Turn off and turn on the controller. 542** 543** Returns: None. 544** 545*******************************************************************************/ 546UINT8 NfcAdaptation::HalGetMaxNfcee() 547{ 548 const char* func = "NfcAdaptation::HalPowerCycle"; 549 UINT8 maxNfcee = 0; 550 ALOGD ("%s", func); 551 if (mHalDeviceContext) 552 { 553 // TODO maco call into HAL when we figure out binary compatibility. 554 return nfa_ee_max_ee_cfg; 555 556 //mHalDeviceContext->get_max_ee (mHalDeviceContext, &maxNfcee); 557 } 558 559 return maxNfcee; 560} 561 562 563/******************************************************************************* 564** 565** Function: NfcAdaptation::DownloadFirmware 566** 567** Description: Download firmware patch files. 568** 569** Returns: None. 570** 571*******************************************************************************/ 572void NfcAdaptation::DownloadFirmware () 573{ 574 const char* func = "NfcAdaptation::DownloadFirmware"; 575 ALOGD ("%s: enter", func); 576 HalInitialize (); 577 578 mHalOpenCompletedEvent.lock (); 579 ALOGD ("%s: try open HAL", func); 580 HalOpen (HalDownloadFirmwareCallback, HalDownloadFirmwareDataCallback); 581 mHalOpenCompletedEvent.wait (); 582 583 mHalCloseCompletedEvent.lock (); 584 ALOGD ("%s: try close HAL", func); 585 HalClose (); 586 mHalCloseCompletedEvent.wait (); 587 588 HalTerminate (); 589 ALOGD ("%s: exit", func); 590} 591 592/******************************************************************************* 593** 594** Function: NfcAdaptation::HalDownloadFirmwareCallback 595** 596** Description: Receive events from the HAL. 597** 598** Returns: None. 599** 600*******************************************************************************/ 601void NfcAdaptation::HalDownloadFirmwareCallback (nfc_event_t event, nfc_status_t event_status) 602{ 603 const char* func = "NfcAdaptation::HalDownloadFirmwareCallback"; 604 ALOGD ("%s: event=0x%X", func, event); 605 switch (event) 606 { 607 case HAL_NFC_OPEN_CPLT_EVT: 608 { 609 ALOGD ("%s: HAL_NFC_OPEN_CPLT_EVT", func); 610 mHalOpenCompletedEvent.signal (); 611 break; 612 } 613 case HAL_NFC_CLOSE_CPLT_EVT: 614 { 615 ALOGD ("%s: HAL_NFC_CLOSE_CPLT_EVT", func); 616 mHalCloseCompletedEvent.signal (); 617 break; 618 } 619 } 620} 621 622/******************************************************************************* 623** 624** Function: NfcAdaptation::HalDownloadFirmwareDataCallback 625** 626** Description: Receive data events from the HAL. 627** 628** Returns: None. 629** 630*******************************************************************************/ 631void NfcAdaptation::HalDownloadFirmwareDataCallback (uint16_t data_len, uint8_t* p_data) 632{ 633} 634 635 636/******************************************************************************* 637** 638** Function: ThreadMutex::ThreadMutex() 639** 640** Description: class constructor 641** 642** Returns: none 643** 644*******************************************************************************/ 645ThreadMutex::ThreadMutex() 646{ 647 pthread_mutexattr_t mutexAttr; 648 649 pthread_mutexattr_init(&mutexAttr); 650 pthread_mutex_init(&mMutex, &mutexAttr); 651 pthread_mutexattr_destroy(&mutexAttr); 652} 653 654/******************************************************************************* 655** 656** Function: ThreadMutex::~ThreadMutex() 657** 658** Description: class destructor 659** 660** Returns: none 661** 662*******************************************************************************/ 663ThreadMutex::~ThreadMutex() 664{ 665 pthread_mutex_destroy(&mMutex); 666} 667 668/******************************************************************************* 669** 670** Function: ThreadMutex::lock() 671** 672** Description: lock kthe mutex 673** 674** Returns: none 675** 676*******************************************************************************/ 677void ThreadMutex::lock() 678{ 679 pthread_mutex_lock(&mMutex); 680} 681 682/******************************************************************************* 683** 684** Function: ThreadMutex::unblock() 685** 686** Description: unlock the mutex 687** 688** Returns: none 689** 690*******************************************************************************/ 691void ThreadMutex::unlock() 692{ 693 pthread_mutex_unlock(&mMutex); 694} 695 696/******************************************************************************* 697** 698** Function: ThreadCondVar::ThreadCondVar() 699** 700** Description: class constructor 701** 702** Returns: none 703** 704*******************************************************************************/ 705ThreadCondVar::ThreadCondVar() 706{ 707 pthread_condattr_t CondAttr; 708 709 pthread_condattr_init(&CondAttr); 710 pthread_cond_init(&mCondVar, &CondAttr); 711 712 pthread_condattr_destroy(&CondAttr); 713} 714 715/******************************************************************************* 716** 717** Function: ThreadCondVar::~ThreadCondVar() 718** 719** Description: class destructor 720** 721** Returns: none 722** 723*******************************************************************************/ 724ThreadCondVar::~ThreadCondVar() 725{ 726 pthread_cond_destroy(&mCondVar); 727} 728 729/******************************************************************************* 730** 731** Function: ThreadCondVar::wait() 732** 733** Description: wait on the mCondVar 734** 735** Returns: none 736** 737*******************************************************************************/ 738void ThreadCondVar::wait() 739{ 740 pthread_cond_wait(&mCondVar, *this); 741 pthread_mutex_unlock(*this); 742} 743 744/******************************************************************************* 745** 746** Function: ThreadCondVar::signal() 747** 748** Description: signal the mCondVar 749** 750** Returns: none 751** 752*******************************************************************************/ 753void ThreadCondVar::signal() 754{ 755 AutoThreadMutex a(*this); 756 pthread_cond_signal(&mCondVar); 757} 758 759/******************************************************************************* 760** 761** Function: AutoThreadMutex::AutoThreadMutex() 762** 763** Description: class constructor, automatically lock the mutex 764** 765** Returns: none 766** 767*******************************************************************************/ 768AutoThreadMutex::AutoThreadMutex(ThreadMutex &m) 769 : mm(m) 770{ 771 mm.lock(); 772} 773 774/******************************************************************************* 775** 776** Function: AutoThreadMutex::~AutoThreadMutex() 777** 778** Description: class destructor, automatically unlock the mutex 779** 780** Returns: none 781** 782*******************************************************************************/ 783AutoThreadMutex::~AutoThreadMutex() 784{ 785 mm.unlock(); 786} 787