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