hid.cpp (31905B)
1 //=================== Copyright Valve Corporation, All rights reserved. ======= 2 // 3 // Purpose: A wrapper implementing "HID" API for Android 4 // 5 // This layer glues the hidapi API to Android's USB and BLE stack. 6 // 7 //============================================================================= 8 9 #include <jni.h> 10 #include <android/log.h> 11 #include <pthread.h> 12 #include <errno.h> // For ETIMEDOUT and ECONNRESET 13 #include <stdlib.h> // For malloc() and free() 14 #include <string.h> // For memcpy() 15 16 #define TAG "hidapi" 17 18 // Have error log always available 19 #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) 20 21 #ifdef DEBUG 22 #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__) 23 #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) 24 #else 25 #define LOGV(...) 26 #define LOGD(...) 27 #endif 28 29 #define SDL_JAVA_PREFIX org_libsdl_app 30 #define CONCAT1(prefix, class, function) CONCAT2(prefix, class, function) 31 #define CONCAT2(prefix, class, function) Java_ ## prefix ## _ ## class ## _ ## function 32 #define HID_DEVICE_MANAGER_JAVA_INTERFACE(function) CONCAT1(SDL_JAVA_PREFIX, HIDDeviceManager, function) 33 34 #include "../hidapi/hidapi.h" 35 36 typedef uint32_t uint32; 37 typedef uint64_t uint64; 38 39 40 struct hid_device_ 41 { 42 int m_nId; 43 int m_nDeviceRefCount; 44 }; 45 46 static JavaVM *g_JVM; 47 static pthread_key_t g_ThreadKey; 48 49 template<class T> 50 class hid_device_ref 51 { 52 public: 53 hid_device_ref( T *pObject = nullptr ) : m_pObject( nullptr ) 54 { 55 SetObject( pObject ); 56 } 57 58 hid_device_ref( const hid_device_ref &rhs ) : m_pObject( nullptr ) 59 { 60 SetObject( rhs.GetObject() ); 61 } 62 63 ~hid_device_ref() 64 { 65 SetObject( nullptr ); 66 } 67 68 void SetObject( T *pObject ) 69 { 70 if ( m_pObject && m_pObject->DecrementRefCount() == 0 ) 71 { 72 delete m_pObject; 73 } 74 75 m_pObject = pObject; 76 77 if ( m_pObject ) 78 { 79 m_pObject->IncrementRefCount(); 80 } 81 } 82 83 hid_device_ref &operator =( T *pObject ) 84 { 85 SetObject( pObject ); 86 return *this; 87 } 88 89 hid_device_ref &operator =( const hid_device_ref &rhs ) 90 { 91 SetObject( rhs.GetObject() ); 92 return *this; 93 } 94 95 T *GetObject() const 96 { 97 return m_pObject; 98 } 99 100 T* operator->() const 101 { 102 return m_pObject; 103 } 104 105 operator bool() const 106 { 107 return ( m_pObject != nullptr ); 108 } 109 110 private: 111 T *m_pObject; 112 }; 113 114 class hid_mutex_guard 115 { 116 public: 117 hid_mutex_guard( pthread_mutex_t *pMutex ) : m_pMutex( pMutex ) 118 { 119 pthread_mutex_lock( m_pMutex ); 120 } 121 ~hid_mutex_guard() 122 { 123 pthread_mutex_unlock( m_pMutex ); 124 } 125 126 private: 127 pthread_mutex_t *m_pMutex; 128 }; 129 130 class hid_buffer 131 { 132 public: 133 hid_buffer() : m_pData( nullptr ), m_nSize( 0 ), m_nAllocated( 0 ) 134 { 135 } 136 137 hid_buffer( const uint8_t *pData, size_t nSize ) : m_pData( nullptr ), m_nSize( 0 ), m_nAllocated( 0 ) 138 { 139 assign( pData, nSize ); 140 } 141 142 ~hid_buffer() 143 { 144 delete[] m_pData; 145 } 146 147 void assign( const uint8_t *pData, size_t nSize ) 148 { 149 if ( nSize > m_nAllocated ) 150 { 151 delete[] m_pData; 152 m_pData = new uint8_t[ nSize ]; 153 m_nAllocated = nSize; 154 } 155 156 m_nSize = nSize; 157 memcpy( m_pData, pData, nSize ); 158 } 159 160 void clear() 161 { 162 m_nSize = 0; 163 } 164 165 size_t size() const 166 { 167 return m_nSize; 168 } 169 170 const uint8_t *data() const 171 { 172 return m_pData; 173 } 174 175 private: 176 uint8_t *m_pData; 177 size_t m_nSize; 178 size_t m_nAllocated; 179 }; 180 181 class hid_buffer_pool 182 { 183 public: 184 hid_buffer_pool() : m_nSize( 0 ), m_pHead( nullptr ), m_pTail( nullptr ), m_pFree( nullptr ) 185 { 186 } 187 188 ~hid_buffer_pool() 189 { 190 clear(); 191 192 while ( m_pFree ) 193 { 194 hid_buffer_entry *pEntry = m_pFree; 195 m_pFree = m_pFree->m_pNext; 196 delete pEntry; 197 } 198 } 199 200 size_t size() const { return m_nSize; } 201 202 const hid_buffer &front() const { return m_pHead->m_buffer; } 203 204 void pop_front() 205 { 206 hid_buffer_entry *pEntry = m_pHead; 207 if ( pEntry ) 208 { 209 m_pHead = pEntry->m_pNext; 210 if ( !m_pHead ) 211 { 212 m_pTail = nullptr; 213 } 214 pEntry->m_pNext = m_pFree; 215 m_pFree = pEntry; 216 --m_nSize; 217 } 218 } 219 220 void emplace_back( const uint8_t *pData, size_t nSize ) 221 { 222 hid_buffer_entry *pEntry; 223 224 if ( m_pFree ) 225 { 226 pEntry = m_pFree; 227 m_pFree = m_pFree->m_pNext; 228 } 229 else 230 { 231 pEntry = new hid_buffer_entry; 232 } 233 pEntry->m_pNext = nullptr; 234 235 if ( m_pTail ) 236 { 237 m_pTail->m_pNext = pEntry; 238 } 239 else 240 { 241 m_pHead = pEntry; 242 } 243 m_pTail = pEntry; 244 245 pEntry->m_buffer.assign( pData, nSize ); 246 ++m_nSize; 247 } 248 249 void clear() 250 { 251 while ( size() > 0 ) 252 { 253 pop_front(); 254 } 255 } 256 257 private: 258 struct hid_buffer_entry 259 { 260 hid_buffer m_buffer; 261 hid_buffer_entry *m_pNext; 262 }; 263 264 size_t m_nSize; 265 hid_buffer_entry *m_pHead; 266 hid_buffer_entry *m_pTail; 267 hid_buffer_entry *m_pFree; 268 }; 269 270 static jbyteArray NewByteArray( JNIEnv* env, const uint8_t *pData, size_t nDataLen ) 271 { 272 jbyteArray array = env->NewByteArray( nDataLen ); 273 jbyte *pBuf = env->GetByteArrayElements( array, NULL ); 274 memcpy( pBuf, pData, nDataLen ); 275 env->ReleaseByteArrayElements( array, pBuf, 0 ); 276 277 return array; 278 } 279 280 static char *CreateStringFromJString( JNIEnv *env, const jstring &sString ) 281 { 282 size_t nLength = env->GetStringUTFLength( sString ); 283 const char *pjChars = env->GetStringUTFChars( sString, NULL ); 284 char *psString = (char*)malloc( nLength + 1 ); 285 memcpy( psString, pjChars, nLength ); 286 psString[ nLength ] = '\0'; 287 env->ReleaseStringUTFChars( sString, pjChars ); 288 return psString; 289 } 290 291 static wchar_t *CreateWStringFromJString( JNIEnv *env, const jstring &sString ) 292 { 293 size_t nLength = env->GetStringLength( sString ); 294 const jchar *pjChars = env->GetStringChars( sString, NULL ); 295 wchar_t *pwString = (wchar_t*)malloc( ( nLength + 1 ) * sizeof( wchar_t ) ); 296 wchar_t *pwChars = pwString; 297 for ( size_t iIndex = 0; iIndex < nLength; ++iIndex ) 298 { 299 pwChars[ iIndex ] = pjChars[ iIndex ]; 300 } 301 pwString[ nLength ] = '\0'; 302 env->ReleaseStringChars( sString, pjChars ); 303 return pwString; 304 } 305 306 static wchar_t *CreateWStringFromWString( const wchar_t *pwSrc ) 307 { 308 size_t nLength = wcslen( pwSrc ); 309 wchar_t *pwString = (wchar_t*)malloc( ( nLength + 1 ) * sizeof( wchar_t ) ); 310 memcpy( pwString, pwSrc, nLength * sizeof( wchar_t ) ); 311 pwString[ nLength ] = '\0'; 312 return pwString; 313 } 314 315 static hid_device_info *CopyHIDDeviceInfo( const hid_device_info *pInfo ) 316 { 317 hid_device_info *pCopy = new hid_device_info; 318 *pCopy = *pInfo; 319 pCopy->path = strdup( pInfo->path ); 320 pCopy->product_string = CreateWStringFromWString( pInfo->product_string ); 321 pCopy->manufacturer_string = CreateWStringFromWString( pInfo->manufacturer_string ); 322 pCopy->serial_number = CreateWStringFromWString( pInfo->serial_number ); 323 return pCopy; 324 } 325 326 static void FreeHIDDeviceInfo( hid_device_info *pInfo ) 327 { 328 free( pInfo->path ); 329 free( pInfo->serial_number ); 330 free( pInfo->manufacturer_string ); 331 free( pInfo->product_string ); 332 delete pInfo; 333 } 334 335 static jclass g_HIDDeviceManagerCallbackClass; 336 static jobject g_HIDDeviceManagerCallbackHandler; 337 static jmethodID g_midHIDDeviceManagerOpen; 338 static jmethodID g_midHIDDeviceManagerSendOutputReport; 339 static jmethodID g_midHIDDeviceManagerSendFeatureReport; 340 static jmethodID g_midHIDDeviceManagerGetFeatureReport; 341 static jmethodID g_midHIDDeviceManagerClose; 342 343 static uint64_t get_timespec_ms( const struct timespec &ts ) 344 { 345 return (uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; 346 } 347 348 class CHIDDevice 349 { 350 public: 351 CHIDDevice( int nDeviceID, hid_device_info *pInfo ) 352 { 353 m_nId = nDeviceID; 354 m_pInfo = pInfo; 355 356 // The Bluetooth Steam Controller needs special handling 357 const int VALVE_USB_VID = 0x28DE; 358 const int D0G_BLE2_PID = 0x1106; 359 if ( pInfo->vendor_id == VALVE_USB_VID && pInfo->product_id == D0G_BLE2_PID ) 360 { 361 m_bIsBLESteamController = true; 362 } 363 } 364 365 ~CHIDDevice() 366 { 367 FreeHIDDeviceInfo( m_pInfo ); 368 369 // Note that we don't delete m_pDevice, as the app may still have a reference to it 370 } 371 372 int IncrementRefCount() 373 { 374 int nValue; 375 pthread_mutex_lock( &m_refCountLock ); 376 nValue = ++m_nRefCount; 377 pthread_mutex_unlock( &m_refCountLock ); 378 return nValue; 379 } 380 381 int DecrementRefCount() 382 { 383 int nValue; 384 pthread_mutex_lock( &m_refCountLock ); 385 nValue = --m_nRefCount; 386 pthread_mutex_unlock( &m_refCountLock ); 387 return nValue; 388 } 389 390 int GetId() 391 { 392 return m_nId; 393 } 394 395 const hid_device_info *GetDeviceInfo() 396 { 397 return m_pInfo; 398 } 399 400 hid_device *GetDevice() 401 { 402 return m_pDevice; 403 } 404 405 void ExceptionCheck( JNIEnv *env, const char *pszMethodName ) 406 { 407 if ( env->ExceptionCheck() ) 408 { 409 // Get our exception 410 jthrowable jExcept = env->ExceptionOccurred(); 411 412 // Clear the exception so we can call JNI again 413 env->ExceptionClear(); 414 415 // Get our exception message 416 jclass jExceptClass = env->GetObjectClass( jExcept ); 417 jmethodID jMessageMethod = env->GetMethodID( jExceptClass, "getMessage", "()Ljava/lang/String;" ); 418 jstring jMessage = (jstring)( env->CallObjectMethod( jExcept, jMessageMethod ) ); 419 const char *pszMessage = env->GetStringUTFChars( jMessage, NULL ); 420 421 // ...and log it. 422 LOGE( "CHIDDevice::%s threw an exception: %s", pszMethodName, pszMessage ); 423 424 // Cleanup 425 env->ReleaseStringUTFChars( jMessage, pszMessage ); 426 env->DeleteLocalRef( jMessage ); 427 env->DeleteLocalRef( jExceptClass ); 428 env->DeleteLocalRef( jExcept ); 429 } 430 } 431 432 bool BOpen() 433 { 434 // Make sure thread is attached to JVM/env 435 JNIEnv *env; 436 g_JVM->AttachCurrentThread( &env, NULL ); 437 pthread_setspecific( g_ThreadKey, (void*)env ); 438 439 if ( !g_HIDDeviceManagerCallbackHandler ) 440 { 441 LOGV( "Device open without callback handler" ); 442 return false; 443 } 444 445 m_bIsWaitingForOpen = false; 446 m_bOpenResult = env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerOpen, m_nId ); 447 ExceptionCheck( env, "BOpen" ); 448 449 if ( m_bIsWaitingForOpen ) 450 { 451 hid_mutex_guard cvl( &m_cvLock ); 452 453 const int OPEN_TIMEOUT_SECONDS = 60; 454 struct timespec ts, endtime; 455 clock_gettime( CLOCK_REALTIME, &ts ); 456 endtime = ts; 457 endtime.tv_sec += OPEN_TIMEOUT_SECONDS; 458 do 459 { 460 if ( pthread_cond_timedwait( &m_cv, &m_cvLock, &endtime ) != 0 ) 461 { 462 break; 463 } 464 } 465 while ( m_bIsWaitingForOpen && get_timespec_ms( ts ) < get_timespec_ms( endtime ) ); 466 } 467 468 if ( !m_bOpenResult ) 469 { 470 if ( m_bIsWaitingForOpen ) 471 { 472 LOGV( "Device open failed - timed out waiting for device permission" ); 473 } 474 else 475 { 476 LOGV( "Device open failed" ); 477 } 478 return false; 479 } 480 481 m_pDevice = new hid_device; 482 m_pDevice->m_nId = m_nId; 483 m_pDevice->m_nDeviceRefCount = 1; 484 LOGD("Creating device %d (%p), refCount = 1\n", m_pDevice->m_nId, m_pDevice); 485 return true; 486 } 487 488 void SetOpenPending() 489 { 490 m_bIsWaitingForOpen = true; 491 } 492 493 void SetOpenResult( bool bResult ) 494 { 495 if ( m_bIsWaitingForOpen ) 496 { 497 m_bOpenResult = bResult; 498 m_bIsWaitingForOpen = false; 499 pthread_cond_signal( &m_cv ); 500 } 501 } 502 503 void ProcessInput( const uint8_t *pBuf, size_t nBufSize ) 504 { 505 hid_mutex_guard l( &m_dataLock ); 506 507 size_t MAX_REPORT_QUEUE_SIZE = 16; 508 if ( m_vecData.size() >= MAX_REPORT_QUEUE_SIZE ) 509 { 510 m_vecData.pop_front(); 511 } 512 m_vecData.emplace_back( pBuf, nBufSize ); 513 } 514 515 int GetInput( unsigned char *data, size_t length ) 516 { 517 hid_mutex_guard l( &m_dataLock ); 518 519 if ( m_vecData.size() == 0 ) 520 { 521 // LOGV( "hid_read_timeout no data available" ); 522 return 0; 523 } 524 525 const hid_buffer &buffer = m_vecData.front(); 526 size_t nDataLen = buffer.size() > length ? length : buffer.size(); 527 if ( m_bIsBLESteamController ) 528 { 529 data[0] = 0x03; 530 memcpy( data + 1, buffer.data(), nDataLen ); 531 ++nDataLen; 532 } 533 else 534 { 535 memcpy( data, buffer.data(), nDataLen ); 536 } 537 m_vecData.pop_front(); 538 539 // LOGV("Read %u bytes", nDataLen); 540 // LOGV("%02x %02x %02x %02x %02x %02x %02x %02x ....", 541 // data[0], data[1], data[2], data[3], 542 // data[4], data[5], data[6], data[7]); 543 544 return nDataLen; 545 } 546 547 int SendOutputReport( const unsigned char *pData, size_t nDataLen ) 548 { 549 // Make sure thread is attached to JVM/env 550 JNIEnv *env; 551 g_JVM->AttachCurrentThread( &env, NULL ); 552 pthread_setspecific( g_ThreadKey, (void*)env ); 553 554 int nRet = -1; 555 if ( g_HIDDeviceManagerCallbackHandler ) 556 { 557 jbyteArray pBuf = NewByteArray( env, pData, nDataLen ); 558 nRet = env->CallIntMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerSendOutputReport, m_nId, pBuf ); 559 ExceptionCheck( env, "SendOutputReport" ); 560 env->DeleteLocalRef( pBuf ); 561 } 562 else 563 { 564 LOGV( "SendOutputReport without callback handler" ); 565 } 566 return nRet; 567 } 568 569 int SendFeatureReport( const unsigned char *pData, size_t nDataLen ) 570 { 571 // Make sure thread is attached to JVM/env 572 JNIEnv *env; 573 g_JVM->AttachCurrentThread( &env, NULL ); 574 pthread_setspecific( g_ThreadKey, (void*)env ); 575 576 int nRet = -1; 577 if ( g_HIDDeviceManagerCallbackHandler ) 578 { 579 jbyteArray pBuf = NewByteArray( env, pData, nDataLen ); 580 nRet = env->CallIntMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerSendFeatureReport, m_nId, pBuf ); 581 ExceptionCheck( env, "SendFeatureReport" ); 582 env->DeleteLocalRef( pBuf ); 583 } 584 else 585 { 586 LOGV( "SendFeatureReport without callback handler" ); 587 } 588 return nRet; 589 } 590 591 void ProcessFeatureReport( const uint8_t *pBuf, size_t nBufSize ) 592 { 593 hid_mutex_guard cvl( &m_cvLock ); 594 if ( m_bIsWaitingForFeatureReport ) 595 { 596 m_featureReport.assign( pBuf, nBufSize ); 597 598 m_bIsWaitingForFeatureReport = false; 599 m_nFeatureReportError = 0; 600 pthread_cond_signal( &m_cv ); 601 } 602 } 603 604 int GetFeatureReport( unsigned char *pData, size_t nDataLen ) 605 { 606 // Make sure thread is attached to JVM/env 607 JNIEnv *env; 608 g_JVM->AttachCurrentThread( &env, NULL ); 609 pthread_setspecific( g_ThreadKey, (void*)env ); 610 611 if ( !g_HIDDeviceManagerCallbackHandler ) 612 { 613 LOGV( "GetFeatureReport without callback handler" ); 614 return -1; 615 } 616 617 { 618 hid_mutex_guard cvl( &m_cvLock ); 619 if ( m_bIsWaitingForFeatureReport ) 620 { 621 LOGV( "Get feature report already ongoing... bail" ); 622 return -1; // Read already ongoing, we currently do not serialize, TODO 623 } 624 m_bIsWaitingForFeatureReport = true; 625 } 626 627 jbyteArray pBuf = NewByteArray( env, pData, nDataLen ); 628 int nRet = env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerGetFeatureReport, m_nId, pBuf ) ? 0 : -1; 629 ExceptionCheck( env, "GetFeatureReport" ); 630 env->DeleteLocalRef( pBuf ); 631 if ( nRet < 0 ) 632 { 633 LOGV( "GetFeatureReport failed" ); 634 m_bIsWaitingForFeatureReport = false; 635 return -1; 636 } 637 638 { 639 hid_mutex_guard cvl( &m_cvLock ); 640 if ( m_bIsWaitingForFeatureReport ) 641 { 642 LOGV("=== Going to sleep" ); 643 // Wait in CV until we are no longer waiting for a feature report. 644 const int FEATURE_REPORT_TIMEOUT_SECONDS = 2; 645 struct timespec ts, endtime; 646 clock_gettime( CLOCK_REALTIME, &ts ); 647 endtime = ts; 648 endtime.tv_sec += FEATURE_REPORT_TIMEOUT_SECONDS; 649 do 650 { 651 if ( pthread_cond_timedwait( &m_cv, &m_cvLock, &endtime ) != 0 ) 652 { 653 break; 654 } 655 } 656 while ( m_bIsWaitingForFeatureReport && get_timespec_ms( ts ) < get_timespec_ms( endtime ) ); 657 658 // We are back 659 if ( m_bIsWaitingForFeatureReport ) 660 { 661 m_nFeatureReportError = -ETIMEDOUT; 662 m_bIsWaitingForFeatureReport = false; 663 } 664 LOGV( "=== Got feature report err=%d", m_nFeatureReportError ); 665 if ( m_nFeatureReportError != 0 ) 666 { 667 return m_nFeatureReportError; 668 } 669 } 670 671 size_t uBytesToCopy = m_featureReport.size() > nDataLen ? nDataLen : m_featureReport.size(); 672 memcpy( pData, m_featureReport.data(), uBytesToCopy ); 673 m_featureReport.clear(); 674 LOGV( "=== Got %u bytes", uBytesToCopy ); 675 676 return uBytesToCopy; 677 } 678 } 679 680 void Close( bool bDeleteDevice ) 681 { 682 // Make sure thread is attached to JVM/env 683 JNIEnv *env; 684 g_JVM->AttachCurrentThread( &env, NULL ); 685 pthread_setspecific( g_ThreadKey, (void*)env ); 686 687 if ( g_HIDDeviceManagerCallbackHandler ) 688 { 689 env->CallVoidMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerClose, m_nId ); 690 ExceptionCheck( env, "Close" ); 691 } 692 693 hid_mutex_guard dataLock( &m_dataLock ); 694 m_vecData.clear(); 695 696 // Clean and release pending feature report reads 697 hid_mutex_guard cvLock( &m_cvLock ); 698 m_featureReport.clear(); 699 m_bIsWaitingForFeatureReport = false; 700 m_nFeatureReportError = -ECONNRESET; 701 pthread_cond_broadcast( &m_cv ); 702 703 if ( bDeleteDevice ) 704 { 705 delete m_pDevice; 706 m_pDevice = nullptr; 707 } 708 } 709 710 private: 711 pthread_mutex_t m_refCountLock = PTHREAD_MUTEX_INITIALIZER; 712 int m_nRefCount = 0; 713 int m_nId = 0; 714 hid_device_info *m_pInfo = nullptr; 715 hid_device *m_pDevice = nullptr; 716 bool m_bIsBLESteamController = false; 717 718 pthread_mutex_t m_dataLock = PTHREAD_MUTEX_INITIALIZER; // This lock has to be held to access m_vecData 719 hid_buffer_pool m_vecData; 720 721 // For handling get_feature_report 722 pthread_mutex_t m_cvLock = PTHREAD_MUTEX_INITIALIZER; // This lock has to be held to access any variables below 723 pthread_cond_t m_cv = PTHREAD_COND_INITIALIZER; 724 bool m_bIsWaitingForOpen = false; 725 bool m_bOpenResult = false; 726 bool m_bIsWaitingForFeatureReport = false; 727 int m_nFeatureReportError = 0; 728 hid_buffer m_featureReport; 729 730 public: 731 hid_device_ref<CHIDDevice> next; 732 }; 733 734 class CHIDDevice; 735 static pthread_mutex_t g_DevicesMutex = PTHREAD_MUTEX_INITIALIZER; 736 static pthread_mutex_t g_DevicesRefCountMutex = PTHREAD_MUTEX_INITIALIZER; 737 static hid_device_ref<CHIDDevice> g_Devices; 738 739 static hid_device_ref<CHIDDevice> FindDevice( int nDeviceId ) 740 { 741 hid_device_ref<CHIDDevice> pDevice; 742 743 hid_mutex_guard l( &g_DevicesMutex ); 744 for ( pDevice = g_Devices; pDevice; pDevice = pDevice->next ) 745 { 746 if ( pDevice->GetId() == nDeviceId ) 747 { 748 break; 749 } 750 } 751 return pDevice; 752 } 753 754 static void ThreadDestroyed(void* value) 755 { 756 /* The thread is being destroyed, detach it from the Java VM and set the g_ThreadKey value to NULL as required */ 757 JNIEnv *env = (JNIEnv*) value; 758 if (env != NULL) { 759 g_JVM->DetachCurrentThread(); 760 pthread_setspecific(g_ThreadKey, NULL); 761 } 762 } 763 764 765 extern "C" 766 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz); 767 768 extern "C" 769 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz); 770 771 extern "C" 772 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, int nDeviceID, jstring sIdentifier, int nVendorId, int nProductId, jstring sSerialNumber, int nReleaseNumber, jstring sManufacturer, jstring sProduct, int nInterface, int nInterfaceClass, int nInterfaceSubclass, int nInterfaceProtocol ); 773 774 extern "C" 775 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, int nDeviceID); 776 777 extern "C" 778 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult)(JNIEnv *env, jobject thiz, int nDeviceID, bool bOpened); 779 780 extern "C" 781 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected)(JNIEnv *env, jobject thiz, int nDeviceID); 782 783 extern "C" 784 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value); 785 786 extern "C" 787 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceFeatureReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value); 788 789 790 extern "C" 791 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz ) 792 { 793 LOGV( "HIDDeviceRegisterCallback()"); 794 795 env->GetJavaVM( &g_JVM ); 796 797 /* 798 * Create mThreadKey so we can keep track of the JNIEnv assigned to each thread 799 * Refer to http://developer.android.com/guide/practices/design/jni.html for the rationale behind this 800 */ 801 if (pthread_key_create(&g_ThreadKey, ThreadDestroyed) != 0) { 802 __android_log_print(ANDROID_LOG_ERROR, TAG, "Error initializing pthread key"); 803 } 804 805 if ( g_HIDDeviceManagerCallbackHandler != NULL ) 806 { 807 env->DeleteGlobalRef( g_HIDDeviceManagerCallbackClass ); 808 g_HIDDeviceManagerCallbackClass = NULL; 809 env->DeleteGlobalRef( g_HIDDeviceManagerCallbackHandler ); 810 g_HIDDeviceManagerCallbackHandler = NULL; 811 } 812 813 g_HIDDeviceManagerCallbackHandler = env->NewGlobalRef( thiz ); 814 jclass objClass = env->GetObjectClass( thiz ); 815 if ( objClass ) 816 { 817 g_HIDDeviceManagerCallbackClass = reinterpret_cast< jclass >( env->NewGlobalRef( objClass ) ); 818 g_midHIDDeviceManagerOpen = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "openDevice", "(I)Z" ); 819 if ( !g_midHIDDeviceManagerOpen ) 820 { 821 __android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing openDevice" ); 822 } 823 g_midHIDDeviceManagerSendOutputReport = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "sendOutputReport", "(I[B)I" ); 824 if ( !g_midHIDDeviceManagerSendOutputReport ) 825 { 826 __android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing sendOutputReport" ); 827 } 828 g_midHIDDeviceManagerSendFeatureReport = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "sendFeatureReport", "(I[B)I" ); 829 if ( !g_midHIDDeviceManagerSendFeatureReport ) 830 { 831 __android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing sendFeatureReport" ); 832 } 833 g_midHIDDeviceManagerGetFeatureReport = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "getFeatureReport", "(I[B)Z" ); 834 if ( !g_midHIDDeviceManagerGetFeatureReport ) 835 { 836 __android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing getFeatureReport" ); 837 } 838 g_midHIDDeviceManagerClose = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "closeDevice", "(I)V" ); 839 if ( !g_midHIDDeviceManagerClose ) 840 { 841 __android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing closeDevice" ); 842 } 843 env->DeleteLocalRef( objClass ); 844 } 845 } 846 847 extern "C" 848 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz) 849 { 850 LOGV("HIDDeviceReleaseCallback"); 851 if ( env->IsSameObject( thiz, g_HIDDeviceManagerCallbackHandler ) ) 852 { 853 env->DeleteGlobalRef( g_HIDDeviceManagerCallbackClass ); 854 g_HIDDeviceManagerCallbackClass = NULL; 855 env->DeleteGlobalRef( g_HIDDeviceManagerCallbackHandler ); 856 g_HIDDeviceManagerCallbackHandler = NULL; 857 } 858 } 859 860 extern "C" 861 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, int nDeviceID, jstring sIdentifier, int nVendorId, int nProductId, jstring sSerialNumber, int nReleaseNumber, jstring sManufacturer, jstring sProduct, int nInterface, int nInterfaceClass, int nInterfaceSubclass, int nInterfaceProtocol ) 862 { 863 LOGV( "HIDDeviceConnected() id=%d VID/PID = %.4x/%.4x, interface %d\n", nDeviceID, nVendorId, nProductId, nInterface ); 864 865 hid_device_info *pInfo = new hid_device_info; 866 memset( pInfo, 0, sizeof( *pInfo ) ); 867 pInfo->path = CreateStringFromJString( env, sIdentifier ); 868 pInfo->vendor_id = nVendorId; 869 pInfo->product_id = nProductId; 870 pInfo->serial_number = CreateWStringFromJString( env, sSerialNumber ); 871 pInfo->release_number = nReleaseNumber; 872 pInfo->manufacturer_string = CreateWStringFromJString( env, sManufacturer ); 873 pInfo->product_string = CreateWStringFromJString( env, sProduct ); 874 pInfo->interface_number = nInterface; 875 pInfo->interface_class = nInterfaceClass; 876 pInfo->interface_subclass = nInterfaceSubclass; 877 pInfo->interface_protocol = nInterfaceProtocol; 878 879 hid_device_ref<CHIDDevice> pDevice( new CHIDDevice( nDeviceID, pInfo ) ); 880 881 hid_mutex_guard l( &g_DevicesMutex ); 882 hid_device_ref<CHIDDevice> pLast, pCurr; 883 for ( pCurr = g_Devices; pCurr; pLast = pCurr, pCurr = pCurr->next ) 884 { 885 continue; 886 } 887 if ( pLast ) 888 { 889 pLast->next = pDevice; 890 } 891 else 892 { 893 g_Devices = pDevice; 894 } 895 } 896 897 extern "C" 898 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, int nDeviceID) 899 { 900 LOGV( "HIDDeviceOpenPending() id=%d\n", nDeviceID ); 901 hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID ); 902 if ( pDevice ) 903 { 904 pDevice->SetOpenPending(); 905 } 906 } 907 908 extern "C" 909 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult)(JNIEnv *env, jobject thiz, int nDeviceID, bool bOpened) 910 { 911 LOGV( "HIDDeviceOpenResult() id=%d, result=%s\n", nDeviceID, bOpened ? "true" : "false" ); 912 hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID ); 913 if ( pDevice ) 914 { 915 pDevice->SetOpenResult( bOpened ); 916 } 917 } 918 919 extern "C" 920 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected)(JNIEnv *env, jobject thiz, int nDeviceID) 921 { 922 LOGV( "HIDDeviceDisconnected() id=%d\n", nDeviceID ); 923 hid_device_ref<CHIDDevice> pDevice; 924 { 925 hid_mutex_guard l( &g_DevicesMutex ); 926 hid_device_ref<CHIDDevice> pLast, pCurr; 927 for ( pCurr = g_Devices; pCurr; pLast = pCurr, pCurr = pCurr->next ) 928 { 929 if ( pCurr->GetId() == nDeviceID ) 930 { 931 pDevice = pCurr; 932 933 if ( pLast ) 934 { 935 pLast->next = pCurr->next; 936 } 937 else 938 { 939 g_Devices = pCurr->next; 940 } 941 } 942 } 943 } 944 if ( pDevice ) 945 { 946 pDevice->Close( false ); 947 } 948 } 949 950 extern "C" 951 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value) 952 { 953 jbyte *pBuf = env->GetByteArrayElements(value, NULL); 954 jsize nBufSize = env->GetArrayLength(value); 955 956 // LOGV( "HIDDeviceInput() id=%d len=%u\n", nDeviceID, nBufSize ); 957 hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID ); 958 if ( pDevice ) 959 { 960 pDevice->ProcessInput( reinterpret_cast< const uint8_t* >( pBuf ), nBufSize ); 961 } 962 963 env->ReleaseByteArrayElements(value, pBuf, 0); 964 } 965 966 extern "C" 967 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceFeatureReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value) 968 { 969 jbyte *pBuf = env->GetByteArrayElements(value, NULL); 970 jsize nBufSize = env->GetArrayLength(value); 971 972 LOGV( "HIDDeviceFeatureReport() id=%d len=%u\n", nDeviceID, nBufSize ); 973 hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID ); 974 if ( pDevice ) 975 { 976 pDevice->ProcessFeatureReport( reinterpret_cast< const uint8_t* >( pBuf ), nBufSize ); 977 } 978 979 env->ReleaseByteArrayElements(value, pBuf, 0); 980 } 981 982 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 983 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 984 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 985 986 extern "C" 987 { 988 989 int hid_init(void) 990 { 991 return 0; 992 } 993 994 struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id) 995 { 996 struct hid_device_info *root = NULL; 997 hid_mutex_guard l( &g_DevicesMutex ); 998 for ( hid_device_ref<CHIDDevice> pDevice = g_Devices; pDevice; pDevice = pDevice->next ) 999 { 1000 const hid_device_info *info = pDevice->GetDeviceInfo(); 1001 if ( ( vendor_id == 0 && product_id == 0 ) || 1002 ( vendor_id == info->vendor_id && product_id == info->product_id ) ) 1003 { 1004 hid_device_info *dev = CopyHIDDeviceInfo( info ); 1005 dev->next = root; 1006 root = dev; 1007 } 1008 } 1009 return root; 1010 } 1011 1012 void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs) 1013 { 1014 while ( devs ) 1015 { 1016 struct hid_device_info *next = devs->next; 1017 FreeHIDDeviceInfo( devs ); 1018 devs = next; 1019 } 1020 } 1021 1022 HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) 1023 { 1024 // TODO: Implement 1025 return NULL; 1026 } 1027 1028 HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path, int bExclusive) 1029 { 1030 LOGV( "hid_open_path( %s )", path ); 1031 1032 hid_device_ref< CHIDDevice > pDevice; 1033 { 1034 hid_mutex_guard r( &g_DevicesRefCountMutex ); 1035 hid_mutex_guard l( &g_DevicesMutex ); 1036 for ( hid_device_ref<CHIDDevice> pCurr = g_Devices; pCurr; pCurr = pCurr->next ) 1037 { 1038 if ( strcmp( pCurr->GetDeviceInfo()->path, path ) == 0 ) 1039 { 1040 hid_device *pValue = pCurr->GetDevice(); 1041 if ( pValue ) 1042 { 1043 ++pValue->m_nDeviceRefCount; 1044 LOGD("Incrementing device %d (%p), refCount = %d\n", pValue->m_nId, pValue, pValue->m_nDeviceRefCount); 1045 return pValue; 1046 } 1047 1048 // Hold a shared pointer to the controller for the duration 1049 pDevice = pCurr; 1050 break; 1051 } 1052 } 1053 } 1054 if ( pDevice && pDevice->BOpen() ) 1055 { 1056 return pDevice->GetDevice(); 1057 } 1058 return NULL; 1059 } 1060 1061 int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length) 1062 { 1063 if ( device ) 1064 { 1065 LOGV( "hid_write id=%d length=%u", device->m_nId, length ); 1066 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1067 if ( pDevice ) 1068 { 1069 return pDevice->SendOutputReport( data, length ); 1070 } 1071 } 1072 return -1; // Controller was disconnected 1073 } 1074 1075 // TODO: Implement timeout? 1076 int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *device, unsigned char *data, size_t length, int milliseconds) 1077 { 1078 if ( device ) 1079 { 1080 // LOGV( "hid_read_timeout id=%d length=%u timeout=%d", device->m_nId, length, milliseconds ); 1081 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1082 if ( pDevice ) 1083 { 1084 return pDevice->GetInput( data, length ); 1085 } 1086 LOGV( "controller was disconnected" ); 1087 } 1088 return -1; // Controller was disconnected 1089 } 1090 1091 // TODO: Implement blocking 1092 int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length) 1093 { 1094 LOGV( "hid_read id=%d length=%u", device->m_nId, length ); 1095 return hid_read_timeout( device, data, length, 0 ); 1096 } 1097 1098 // TODO: Implement? 1099 int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock) 1100 { 1101 return -1; 1102 } 1103 1104 int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length) 1105 { 1106 if ( device ) 1107 { 1108 LOGV( "hid_send_feature_report id=%d length=%u", device->m_nId, length ); 1109 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1110 if ( pDevice ) 1111 { 1112 return pDevice->SendFeatureReport( data, length ); 1113 } 1114 } 1115 return -1; // Controller was disconnected 1116 } 1117 1118 1119 // Synchronous operation. Will block until completed. 1120 int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length) 1121 { 1122 if ( device ) 1123 { 1124 LOGV( "hid_get_feature_report id=%d length=%u", device->m_nId, length ); 1125 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1126 if ( pDevice ) 1127 { 1128 return pDevice->GetFeatureReport( data, length ); 1129 } 1130 } 1131 return -1; // Controller was disconnected 1132 } 1133 1134 1135 void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device) 1136 { 1137 if ( device ) 1138 { 1139 LOGV( "hid_close id=%d", device->m_nId ); 1140 hid_mutex_guard r( &g_DevicesRefCountMutex ); 1141 LOGD("Decrementing device %d (%p), refCount = %d\n", device->m_nId, device, device->m_nDeviceRefCount - 1); 1142 if ( --device->m_nDeviceRefCount == 0 ) 1143 { 1144 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1145 if ( pDevice ) 1146 { 1147 pDevice->Close( true ); 1148 } 1149 else 1150 { 1151 delete device; 1152 } 1153 LOGD("Deleted device %p\n", device); 1154 } 1155 } 1156 } 1157 1158 int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen) 1159 { 1160 if ( device ) 1161 { 1162 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1163 if ( pDevice ) 1164 { 1165 wcsncpy( string, pDevice->GetDeviceInfo()->manufacturer_string, maxlen ); 1166 return 0; 1167 } 1168 } 1169 return -1; 1170 } 1171 1172 int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen) 1173 { 1174 if ( device ) 1175 { 1176 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1177 if ( pDevice ) 1178 { 1179 wcsncpy( string, pDevice->GetDeviceInfo()->product_string, maxlen ); 1180 return 0; 1181 } 1182 } 1183 return -1; 1184 } 1185 1186 int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen) 1187 { 1188 if ( device ) 1189 { 1190 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1191 if ( pDevice ) 1192 { 1193 wcsncpy( string, pDevice->GetDeviceInfo()->serial_number, maxlen ); 1194 return 0; 1195 } 1196 } 1197 return -1; 1198 } 1199 1200 int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen) 1201 { 1202 return -1; 1203 } 1204 1205 HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device) 1206 { 1207 return NULL; 1208 } 1209 1210 int hid_exit(void) 1211 { 1212 return 0; 1213 } 1214 1215 }