Atlas - hid.cpp
Home / ext / SDL / src / hidapi / android Lines: 17 | Size: 41726 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 2022 Valve Corporation 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23// Purpose: A wrapper implementing "HID" API for Android 24// 25// This layer glues the hidapi API to Android's USB and BLE stack. 26 27#include "hid.h" 28 29// Common to stub version and non-stub version of functions 30#include <jni.h> 31#include <android/log.h> 32 33#define TAG "hidapi" 34 35// Have error log always available 36#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) 37 38#ifdef DEBUG 39#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__) 40#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) 41#else 42#define LOGV(...) 43#define LOGD(...) 44#endif 45 46#define SDL_JAVA_PREFIX org_libsdl_app 47#define CONCAT1(prefix, class, function) CONCAT2(prefix, class, function) 48#define CONCAT2(prefix, class, function) Java_ ## prefix ## _ ## class ## _ ## function 49#define HID_DEVICE_MANAGER_JAVA_INTERFACE(function) CONCAT1(SDL_JAVA_PREFIX, HIDDeviceManager, function) 50 51 52#ifndef SDL_HIDAPI_DISABLED 53 54extern "C" { 55#include "../SDL_hidapi_c.h" 56} 57#include "../../core/android/SDL_android.h" 58 59#define hid_close PLATFORM_hid_close 60#define hid_device PLATFORM_hid_device 61#define hid_device_ PLATFORM_hid_device_ 62#define hid_enumerate PLATFORM_hid_enumerate 63#define hid_error PLATFORM_hid_error 64#define hid_exit PLATFORM_hid_exit 65#define hid_free_enumeration PLATFORM_hid_free_enumeration 66#define hid_get_device_info PLATFORM_hid_get_device_info 67#define hid_get_feature_report PLATFORM_hid_get_feature_report 68#define hid_get_indexed_string PLATFORM_hid_get_indexed_string 69#define hid_get_input_report PLATFORM_hid_get_input_report 70#define hid_get_manufacturer_string PLATFORM_hid_get_manufacturer_string 71#define hid_get_product_string PLATFORM_hid_get_product_string 72#define hid_get_report_descriptor PLATFORM_hid_get_report_descriptor 73#define hid_get_serial_number_string PLATFORM_hid_get_serial_number_string 74#define hid_init PLATFORM_hid_init 75#define hid_open_path PLATFORM_hid_open_path 76#define hid_open PLATFORM_hid_open 77#define hid_read PLATFORM_hid_read 78#define hid_read_timeout PLATFORM_hid_read_timeout 79#define hid_send_feature_report PLATFORM_hid_send_feature_report 80#define hid_set_nonblocking PLATFORM_hid_set_nonblocking 81#define hid_version PLATFORM_hid_version 82#define hid_version_str PLATFORM_hid_version_str 83#define hid_write PLATFORM_hid_write 84 85#include <pthread.h> 86#include <errno.h> // For ETIMEDOUT and ECONNRESET 87#include <stdlib.h> // For malloc() and free() 88 89#include "../hidapi/hidapi.h" 90 91typedef uint32_t uint32; 92typedef uint64_t uint64; 93 94#define D0G_BLE2_PID 0x1106 95#define TRITON_BLE_PID 0x1303 96 97 98struct hid_device_ 99{ 100 int m_nId; 101 int m_nDeviceRefCount; 102}; 103 104template<class T> 105class hid_device_ref 106{ 107public: 108 hid_device_ref( T *pObject = nullptr ) : m_pObject( nullptr ) 109 { 110 SetObject( pObject ); 111 } 112 113 hid_device_ref( const hid_device_ref &rhs ) : m_pObject( nullptr ) 114 { 115 SetObject( rhs.GetObject() ); 116 } 117 118 ~hid_device_ref() 119 { 120 SetObject( nullptr ); 121 } 122 123 void SetObject( T *pObject ) 124 { 125 if ( m_pObject && m_pObject->DecrementRefCount() == 0 ) 126 { 127 delete m_pObject; 128 } 129 130 m_pObject = pObject; 131 132 if ( m_pObject ) 133 { 134 m_pObject->IncrementRefCount(); 135 } 136 } 137 138 hid_device_ref &operator =( T *pObject ) 139 { 140 SetObject( pObject ); 141 return *this; 142 } 143 144 hid_device_ref &operator =( const hid_device_ref &rhs ) 145 { 146 SetObject( rhs.GetObject() ); 147 return *this; 148 } 149 150 T *GetObject() const 151 { 152 return m_pObject; 153 } 154 155 T* operator->() const 156 { 157 return m_pObject; 158 } 159 160 operator bool() const 161 { 162 return ( m_pObject != nullptr ); 163 } 164 165private: 166 T *m_pObject; 167}; 168 169class hid_mutex_guard 170{ 171public: 172 hid_mutex_guard( pthread_mutex_t *pMutex ) : m_pMutex( pMutex ) 173 { 174 pthread_mutex_lock( m_pMutex ); 175 } 176 ~hid_mutex_guard() 177 { 178 pthread_mutex_unlock( m_pMutex ); 179 } 180 181private: 182 pthread_mutex_t *m_pMutex; 183}; 184 185class hid_buffer 186{ 187public: 188 hid_buffer() : m_pData( nullptr ), m_nSize( 0 ), m_nAllocated( 0 ) 189 { 190 } 191 192 hid_buffer( const uint8_t *pData, size_t nSize ) : m_pData( nullptr ), m_nSize( 0 ), m_nAllocated( 0 ) 193 { 194 assign( pData, nSize ); 195 } 196 197 ~hid_buffer() 198 { 199 delete[] m_pData; 200 } 201 202 void assign( const uint8_t *pData, size_t nSize ) 203 { 204 if ( nSize > m_nAllocated ) 205 { 206 delete[] m_pData; 207 m_pData = new uint8_t[ nSize ]; 208 m_nAllocated = nSize; 209 } 210 211 m_nSize = nSize; 212 SDL_memcpy( m_pData, pData, nSize ); 213 } 214 215 void clear() 216 { 217 m_nSize = 0; 218 } 219 220 size_t size() const 221 { 222 return m_nSize; 223 } 224 225 const uint8_t *data() const 226 { 227 return m_pData; 228 } 229 230private: 231 uint8_t *m_pData; 232 size_t m_nSize; 233 size_t m_nAllocated; 234}; 235 236class hid_buffer_pool 237{ 238public: 239 hid_buffer_pool() : m_nSize( 0 ), m_pHead( nullptr ), m_pTail( nullptr ), m_pFree( nullptr ) 240 { 241 } 242 243 ~hid_buffer_pool() 244 { 245 clear(); 246 247 while ( m_pFree ) 248 { 249 hid_buffer_entry *pEntry = m_pFree; 250 m_pFree = m_pFree->m_pNext; 251 delete pEntry; 252 } 253 } 254 255 size_t size() const { return m_nSize; } 256 257 const hid_buffer &front() const { return m_pHead->m_buffer; } 258 259 void pop_front() 260 { 261 hid_buffer_entry *pEntry = m_pHead; 262 if ( pEntry ) 263 { 264 m_pHead = pEntry->m_pNext; 265 if ( !m_pHead ) 266 { 267 m_pTail = nullptr; 268 } 269 pEntry->m_pNext = m_pFree; 270 m_pFree = pEntry; 271 --m_nSize; 272 } 273 } 274 275 void emplace_back( const uint8_t *pData, size_t nSize ) 276 { 277 hid_buffer_entry *pEntry; 278 279 if ( m_pFree ) 280 { 281 pEntry = m_pFree; 282 m_pFree = m_pFree->m_pNext; 283 } 284 else 285 { 286 pEntry = new hid_buffer_entry; 287 } 288 pEntry->m_pNext = nullptr; 289 290 if ( m_pTail ) 291 { 292 m_pTail->m_pNext = pEntry; 293 } 294 else 295 { 296 m_pHead = pEntry; 297 } 298 m_pTail = pEntry; 299 300 pEntry->m_buffer.assign( pData, nSize ); 301 ++m_nSize; 302 } 303 304 void clear() 305 { 306 while ( size() > 0 ) 307 { 308 pop_front(); 309 } 310 } 311 312private: 313 struct hid_buffer_entry 314 { 315 hid_buffer m_buffer; 316 hid_buffer_entry *m_pNext; 317 }; 318 319 size_t m_nSize; 320 hid_buffer_entry *m_pHead; 321 hid_buffer_entry *m_pTail; 322 hid_buffer_entry *m_pFree; 323}; 324 325static jbyteArray NewByteArray( JNIEnv *env, const uint8_t *pData, size_t nDataLen ) 326{ 327 jbyteArray array = env->NewByteArray( (jsize)nDataLen ); 328 jbyte *pBuf = env->GetByteArrayElements( array, NULL ); 329 SDL_memcpy( pBuf, pData, nDataLen ); 330 env->ReleaseByteArrayElements( array, pBuf, 0 ); 331 332 return array; 333} 334 335static char *CreateStringFromJString( JNIEnv *env, const jstring &sString ) 336{ 337 size_t nLength = env->GetStringUTFLength( sString ); 338 const char *pjChars = env->GetStringUTFChars( sString, NULL ); 339 char *psString = (char *)malloc( nLength + 1 ); 340 SDL_memcpy( psString, pjChars, nLength ); 341 psString[ nLength ] = '\0'; 342 env->ReleaseStringUTFChars( sString, pjChars ); 343 return psString; 344} 345 346static wchar_t *CreateWStringFromJString( JNIEnv *env, const jstring &sString ) 347{ 348 size_t nLength = env->GetStringLength( sString ); 349 const jchar *pjChars = env->GetStringChars( sString, NULL ); 350 wchar_t *pwString = (wchar_t *)malloc( ( nLength + 1 ) * sizeof( wchar_t ) ); 351 wchar_t *pwChars = pwString; 352 for ( size_t iIndex = 0; iIndex < nLength; ++iIndex ) 353 { 354 pwChars[ iIndex ] = pjChars[ iIndex ]; 355 } 356 pwString[ nLength ] = '\0'; 357 env->ReleaseStringChars( sString, pjChars ); 358 return pwString; 359} 360 361static wchar_t *CreateWStringFromWString( const wchar_t *pwSrc ) 362{ 363 size_t nLength = SDL_wcslen( pwSrc ); 364 wchar_t *pwString = (wchar_t *)malloc( ( nLength + 1 ) * sizeof( wchar_t ) ); 365 SDL_memcpy( pwString, pwSrc, nLength * sizeof( wchar_t ) ); 366 pwString[ nLength ] = '\0'; 367 return pwString; 368} 369 370static hid_device_info *CopyHIDDeviceInfo( const hid_device_info *pInfo ) 371{ 372 hid_device_info *pCopy = new hid_device_info; 373 *pCopy = *pInfo; 374 pCopy->path = SDL_strdup( pInfo->path ); 375 pCopy->product_string = CreateWStringFromWString( pInfo->product_string ); 376 pCopy->manufacturer_string = CreateWStringFromWString( pInfo->manufacturer_string ); 377 pCopy->serial_number = CreateWStringFromWString( pInfo->serial_number ); 378 return pCopy; 379} 380 381static void FreeHIDDeviceInfo( hid_device_info *pInfo ) 382{ 383 free( pInfo->path ); 384 free( pInfo->serial_number ); 385 free( pInfo->manufacturer_string ); 386 free( pInfo->product_string ); 387 delete pInfo; 388} 389 390static jclass g_HIDDeviceManagerCallbackClass; 391static jobject g_HIDDeviceManagerCallbackHandler; 392static jmethodID g_midHIDDeviceManagerInitialize; 393static jmethodID g_midHIDDeviceManagerOpen; 394static jmethodID g_midHIDDeviceManagerWriteReport; 395static jmethodID g_midHIDDeviceManagerReadReport; 396static jmethodID g_midHIDDeviceManagerClose; 397static bool g_initialized = false; 398 399static uint64_t get_timespec_ms( const struct timespec &ts ) 400{ 401 return (uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; 402} 403 404static void ExceptionCheck( JNIEnv *env, const char *pszClassName, const char *pszMethodName ) 405{ 406 if ( env->ExceptionCheck() ) 407 { 408 // Get our exception 409 jthrowable jExcept = env->ExceptionOccurred(); 410 411 // Clear the exception so we can call JNI again 412 env->ExceptionClear(); 413 414 // Get our exception message 415 jclass jExceptClass = env->GetObjectClass( jExcept ); 416 jmethodID jMessageMethod = env->GetMethodID( jExceptClass, "getMessage", "()Ljava/lang/String;" ); 417 jstring jMessage = (jstring)( env->CallObjectMethod( jExcept, jMessageMethod ) ); 418 const char *pszMessage = env->GetStringUTFChars( jMessage, NULL ); 419 420 // ...and log it. 421 LOGE( "%s%s%s threw an exception: %s", 422 pszClassName ? pszClassName : "", 423 pszClassName ? "::" : "", 424 pszMethodName, pszMessage ); 425 426 // Cleanup 427 env->ReleaseStringUTFChars( jMessage, pszMessage ); 428 env->DeleteLocalRef( jMessage ); 429 env->DeleteLocalRef( jExceptClass ); 430 env->DeleteLocalRef( jExcept ); 431 } 432} 433 434class CHIDDevice 435{ 436public: 437 CHIDDevice( int nDeviceID, hid_device_info *pInfo ) 438 { 439 m_nId = nDeviceID; 440 m_pInfo = pInfo; 441 442 // The Bluetooth Steam Controller needs special handling 443 const int VALVE_USB_VID = 0x28DE; 444 if ( pInfo->vendor_id == VALVE_USB_VID && ( pInfo->product_id == D0G_BLE2_PID || pInfo->product_id == TRITON_BLE_PID ) ) 445 { 446 m_bIsBLESteamController = true; 447 } 448 } 449 450 ~CHIDDevice() 451 { 452 FreeHIDDeviceInfo( m_pInfo ); 453 454 // Note that we don't delete m_pDevice, as the app may still have a reference to it 455 } 456 457 int IncrementRefCount() 458 { 459 int nValue; 460 pthread_mutex_lock( &m_refCountLock ); 461 nValue = ++m_nRefCount; 462 pthread_mutex_unlock( &m_refCountLock ); 463 return nValue; 464 } 465 466 int DecrementRefCount() 467 { 468 int nValue; 469 pthread_mutex_lock( &m_refCountLock ); 470 nValue = --m_nRefCount; 471 pthread_mutex_unlock( &m_refCountLock ); 472 return nValue; 473 } 474 475 int GetId() 476 { 477 return m_nId; 478 } 479 480 hid_device_info *GetDeviceInfo() 481 { 482 return m_pInfo; 483 } 484 485 hid_device *GetDevice() 486 { 487 return m_pDevice; 488 } 489 490 void ExceptionCheck( JNIEnv *env, const char *pszMethodName ) 491 { 492 ::ExceptionCheck( env, "CHIDDevice", pszMethodName ); 493 } 494 495 bool BOpen() 496 { 497 JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv(); 498 499 if ( !g_HIDDeviceManagerCallbackHandler ) 500 { 501 LOGV( "Device open without callback handler" ); 502 return false; 503 } 504 505 if ( m_bIsWaitingForOpen ) 506 { 507 SDL_SetError( "Waiting for permission" ); 508 return false; 509 } 510 511 if ( !m_bOpenResult ) 512 { 513 m_bOpenResult = env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerOpen, m_nId ); 514 ExceptionCheck( env, "BOpen" ); 515 516 if ( m_bIsWaitingForOpen ) 517 { 518 LOGV( "Device open waiting for permission" ); 519 SDL_SetError( "Waiting for permission" ); 520 m_bWasOpenPending = true; 521 return false; 522 } 523 524 if ( !m_bOpenResult ) 525 { 526 LOGV( "Device open failed" ); 527 SDL_SetError( "Device open failed" ); 528 return false; 529 } 530 } 531 532 m_pDevice = new hid_device; 533 m_pDevice->m_nId = m_nId; 534 m_pDevice->m_nDeviceRefCount = 1; 535 LOGD("Creating device %d (%p), refCount = 1\n", m_pDevice->m_nId, m_pDevice); 536 537 return true; 538 } 539 540 void SetOpenPending() 541 { 542 m_bIsWaitingForOpen = true; 543 } 544 545 bool BOpenPending() const 546 { 547 return m_bIsWaitingForOpen; 548 } 549 550 void SetWasOpenPending( bool bState ) 551 { 552 m_bWasOpenPending = bState; 553 } 554 555 bool BWasOpenPending() const 556 { 557 return m_bWasOpenPending; 558 } 559 560 void SetOpenResult( bool bResult ) 561 { 562 if ( m_bIsWaitingForOpen ) 563 { 564 m_bOpenResult = bResult; 565 m_bIsWaitingForOpen = false; 566 567 if ( m_bOpenResult ) 568 { 569 LOGV( "Device open succeeded" ); 570 } 571 else 572 { 573 LOGV( "Device open failed" ); 574 } 575 } 576 } 577 578 bool BOpenResult() const 579 { 580 return m_bOpenResult; 581 } 582 583 void ProcessInput( const uint8_t *pBuf, size_t nBufSize ) 584 { 585 hid_mutex_guard l( &m_dataLock ); 586 587 size_t MAX_REPORT_QUEUE_SIZE = 16; 588 if ( m_vecData.size() >= MAX_REPORT_QUEUE_SIZE ) 589 { 590 m_vecData.pop_front(); 591 } 592 m_vecData.emplace_back( pBuf, nBufSize ); 593 } 594 595 int GetInput( unsigned char *data, size_t length ) 596 { 597 hid_mutex_guard l( &m_dataLock ); 598 599 if ( m_vecData.size() == 0 ) 600 { 601// LOGV( "hid_read_timeout no data available" ); 602 return 0; 603 } 604 605 const hid_buffer &buffer = m_vecData.front(); 606 size_t nDataLen = buffer.size() > length ? length : buffer.size(); 607 if ( m_bIsBLESteamController ) 608 { 609 if ( m_pInfo->product_id == TRITON_BLE_PID ) 610 { 611 data[0] = 0x45; 612 } 613 else 614 { 615 data[0] = 0x03; 616 } 617 SDL_memcpy( data + 1, buffer.data(), nDataLen ); 618 ++nDataLen; 619 } 620 else 621 { 622 SDL_memcpy( data, buffer.data(), nDataLen ); 623 } 624 m_vecData.pop_front(); 625 626// LOGV("Read %u bytes", nDataLen); 627// LOGV("%02x %02x %02x %02x %02x %02x %02x %02x ....", 628// data[0], data[1], data[2], data[3], 629// data[4], data[5], data[6], data[7]); 630 631 return (int)nDataLen; 632 } 633 634 int WriteReport( const unsigned char *pData, size_t nDataLen, bool bFeature ) 635 { 636 JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv(); 637 638 if ( !g_HIDDeviceManagerCallbackHandler ) 639 { 640 LOGV( "WriteReport without callback handler" ); 641 return -1; 642 } 643 644 jbyteArray pBuf = NewByteArray( env, pData, nDataLen ); 645 int nRet = env->CallIntMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerWriteReport, m_nId, pBuf, bFeature ); 646 ExceptionCheck( env, "WriteReport" ); 647 env->DeleteLocalRef( pBuf ); 648 return nRet; 649 } 650 651 void ProcessReportResponse( const uint8_t *pBuf, size_t nBufSize ) 652 { 653 hid_mutex_guard cvl( &m_cvLock ); 654 if ( m_bIsWaitingForReportResponse ) 655 { 656 m_reportResponse.assign( pBuf, nBufSize ); 657 658 m_bIsWaitingForReportResponse = false; 659 m_nReportResponseError = 0; 660 pthread_cond_signal( &m_cv ); 661 } 662 } 663 664 int ReadReport( unsigned char *pData, size_t nDataLen, bool bFeature ) 665 { 666 JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv(); 667 668 if ( !g_HIDDeviceManagerCallbackHandler ) 669 { 670 LOGV( "ReadReport without callback handler" ); 671 return -1; 672 } 673 674 { 675 hid_mutex_guard cvl( &m_cvLock ); 676 if ( m_bIsWaitingForReportResponse ) 677 { 678 LOGV( "Get feature report already ongoing... bail" ); 679 return -1; // Read already ongoing, we currently do not serialize, TODO 680 } 681 m_bIsWaitingForReportResponse = true; 682 } 683 684 jbyteArray pBuf = NewByteArray( env, pData, nDataLen ); 685 int nRet = env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerReadReport, m_nId, pBuf, bFeature ) ? 0 : -1; 686 ExceptionCheck( env, "ReadReport" ); 687 env->DeleteLocalRef( pBuf ); 688 if ( nRet < 0 ) 689 { 690 LOGV( "ReadReport failed" ); 691 m_bIsWaitingForReportResponse = false; 692 return -1; 693 } 694 695 { 696 hid_mutex_guard cvl( &m_cvLock ); 697 if ( m_bIsWaitingForReportResponse ) 698 { 699 LOGV("=== Going to sleep" ); 700 // Wait in CV until we are no longer waiting for a feature report. 701 const int FEATURE_REPORT_TIMEOUT_SECONDS = 2; 702 struct timespec ts, endtime; 703 clock_gettime( CLOCK_REALTIME, &ts ); 704 endtime = ts; 705 endtime.tv_sec += FEATURE_REPORT_TIMEOUT_SECONDS; 706 do 707 { 708 if ( pthread_cond_timedwait( &m_cv, &m_cvLock, &endtime ) != 0 ) 709 { 710 break; 711 } 712 } 713 while ( m_bIsWaitingForReportResponse && get_timespec_ms( ts ) < get_timespec_ms( endtime ) ); 714 715 // We are back 716 if ( m_bIsWaitingForReportResponse ) 717 { 718 m_nReportResponseError = -ETIMEDOUT; 719 m_bIsWaitingForReportResponse = false; 720 } 721 LOGV( "=== Got feature report err=%d", m_nReportResponseError ); 722 if ( m_nReportResponseError != 0 ) 723 { 724 return m_nReportResponseError; 725 } 726 } 727 728 size_t uBytesToCopy = m_reportResponse.size() > nDataLen ? nDataLen : m_reportResponse.size(); 729 SDL_memcpy( pData, m_reportResponse.data(), uBytesToCopy ); 730 m_reportResponse.clear(); 731 LOGV( "=== Got %zu bytes", uBytesToCopy ); 732 733 return (int)uBytesToCopy; 734 } 735 } 736 737 void Close( bool bDeleteDevice ) 738 { 739 JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv(); 740 741 if ( g_HIDDeviceManagerCallbackHandler ) 742 { 743 if ( !m_bIsWaitingForOpen && m_bOpenResult ) 744 { 745 env->CallVoidMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerClose, m_nId ); 746 ExceptionCheck( env, "Close" ); 747 } 748 } 749 750 hid_mutex_guard dataLock( &m_dataLock ); 751 m_vecData.clear(); 752 753 // Clean and release pending feature report reads 754 hid_mutex_guard cvLock( &m_cvLock ); 755 m_reportResponse.clear(); 756 m_bIsWaitingForReportResponse = false; 757 m_nReportResponseError = -ECONNRESET; 758 pthread_cond_broadcast( &m_cv ); 759 760 m_bOpenResult = false; 761 762 if ( bDeleteDevice ) 763 { 764 delete m_pDevice; 765 m_pDevice = nullptr; 766 } 767 } 768 769private: 770 pthread_mutex_t m_refCountLock = PTHREAD_MUTEX_INITIALIZER; 771 int m_nRefCount = 0; 772 int m_nId = 0; 773 hid_device_info *m_pInfo = nullptr; 774 hid_device *m_pDevice = nullptr; 775 bool m_bIsBLESteamController = false; 776 777 pthread_mutex_t m_dataLock = PTHREAD_MUTEX_INITIALIZER; // This lock has to be held to access m_vecData 778 hid_buffer_pool m_vecData; 779 780 // For handling get_feature_report 781 pthread_mutex_t m_cvLock = PTHREAD_MUTEX_INITIALIZER; // This lock has to be held to access any variables below 782 pthread_cond_t m_cv = PTHREAD_COND_INITIALIZER; 783 bool m_bIsWaitingForOpen = false; 784 bool m_bWasOpenPending = false; 785 bool m_bOpenResult = false; 786 bool m_bIsWaitingForReportResponse = false; 787 int m_nReportResponseError = 0; 788 hid_buffer m_reportResponse; 789 790public: 791 hid_device_ref<CHIDDevice> next; 792}; 793 794class CHIDDevice; 795static pthread_mutex_t g_DevicesMutex = PTHREAD_MUTEX_INITIALIZER; 796static pthread_mutex_t g_DevicesRefCountMutex = PTHREAD_MUTEX_INITIALIZER; 797static hid_device_ref<CHIDDevice> g_Devices; 798 799static hid_device_ref<CHIDDevice> FindDevice( int nDeviceId ) 800{ 801 hid_device_ref<CHIDDevice> pDevice; 802 803 hid_mutex_guard l( &g_DevicesMutex ); 804 for ( pDevice = g_Devices; pDevice; pDevice = pDevice->next ) 805 { 806 if ( pDevice->GetId() == nDeviceId ) 807 { 808 break; 809 } 810 } 811 return pDevice; 812} 813 814 815extern "C" 816JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz); 817 818extern "C" 819JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz); 820 821extern "C" 822JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, jint nDeviceID, jstring sIdentifier, jint nVendorId, jint nProductId, jstring sSerialNumber, jint nReleaseNumber, jstring sManufacturer, jstring sProduct, jint nInterface, jint nInterfaceClass, jint nInterfaceSubclass, jint nInterfaceProtocol, jboolean bBluetooth ); 823 824extern "C" 825JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, jint nDeviceID); 826 827extern "C" 828JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult)(JNIEnv *env, jobject thiz, jint nDeviceID, jboolean bOpened); 829 830extern "C" 831JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected)(JNIEnv *env, jobject thiz, jint nDeviceID); 832 833extern "C" 834JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport)(JNIEnv *env, jobject thiz, jint nDeviceID, jbyteArray value); 835 836extern "C" 837JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReportResponse)(JNIEnv *env, jobject thiz, jint nDeviceID, jbyteArray value); 838 839 840extern "C" 841JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz ) 842{ 843 LOGV( "HIDDeviceRegisterCallback()"); 844 845 if ( g_HIDDeviceManagerCallbackHandler != NULL ) 846 { 847 env->DeleteGlobalRef( g_HIDDeviceManagerCallbackClass ); 848 g_HIDDeviceManagerCallbackClass = NULL; 849 env->DeleteGlobalRef( g_HIDDeviceManagerCallbackHandler ); 850 g_HIDDeviceManagerCallbackHandler = NULL; 851 } 852 853 g_HIDDeviceManagerCallbackHandler = env->NewGlobalRef( thiz ); 854 jclass objClass = env->GetObjectClass( thiz ); 855 if ( objClass ) 856 { 857 g_HIDDeviceManagerCallbackClass = reinterpret_cast< jclass >( env->NewGlobalRef( objClass ) ); 858 g_midHIDDeviceManagerInitialize = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "initialize", "(ZZ)Z" ); 859 if ( !g_midHIDDeviceManagerInitialize ) 860 { 861 __android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing initialize" ); 862 } 863 g_midHIDDeviceManagerOpen = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "openDevice", "(I)Z" ); 864 if ( !g_midHIDDeviceManagerOpen ) 865 { 866 __android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing openDevice" ); 867 } 868 g_midHIDDeviceManagerWriteReport = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "writeReport", "(I[BZ)I" ); 869 if ( !g_midHIDDeviceManagerWriteReport ) 870 { 871 __android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing writeReport" ); 872 } 873 g_midHIDDeviceManagerReadReport = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "readReport", "(I[BZ)Z" ); 874 if ( !g_midHIDDeviceManagerReadReport ) 875 { 876 __android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing getFeatureReport" ); 877 } 878 g_midHIDDeviceManagerClose = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "closeDevice", "(I)V" ); 879 if ( !g_midHIDDeviceManagerClose ) 880 { 881 __android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing closeDevice" ); 882 } 883 env->DeleteLocalRef( objClass ); 884 } 885} 886 887extern "C" 888JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz) 889{ 890 LOGV("HIDDeviceReleaseCallback"); 891 if ( env->IsSameObject( thiz, g_HIDDeviceManagerCallbackHandler ) ) 892 { 893 env->DeleteGlobalRef( g_HIDDeviceManagerCallbackClass ); 894 g_HIDDeviceManagerCallbackClass = NULL; 895 env->DeleteGlobalRef( g_HIDDeviceManagerCallbackHandler ); 896 g_HIDDeviceManagerCallbackHandler = NULL; 897 g_initialized = false; 898 } 899} 900 901extern "C" 902JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, jint nDeviceID, jstring sIdentifier, jint nVendorId, jint nProductId, jstring sSerialNumber, jint nReleaseNumber, jstring sManufacturer, jstring sProduct, jint nInterface, jint nInterfaceClass, jint nInterfaceSubclass, jint nInterfaceProtocol, jboolean bBluetooth ) 903{ 904 LOGV( "HIDDeviceConnected() id=%d VID/PID = %.4x/%.4x, interface %d\n", nDeviceID, nVendorId, nProductId, nInterface ); 905 906 hid_device_info *pInfo = new hid_device_info; 907 SDL_memset( pInfo, 0, sizeof( *pInfo ) ); 908 pInfo->path = CreateStringFromJString( env, sIdentifier ); 909 pInfo->vendor_id = nVendorId; 910 pInfo->product_id = nProductId; 911 pInfo->serial_number = CreateWStringFromJString( env, sSerialNumber ); 912 pInfo->release_number = nReleaseNumber; 913 pInfo->manufacturer_string = CreateWStringFromJString( env, sManufacturer ); 914 pInfo->product_string = CreateWStringFromJString( env, sProduct ); 915 pInfo->interface_number = nInterface; 916 pInfo->interface_class = nInterfaceClass; 917 pInfo->interface_subclass = nInterfaceSubclass; 918 pInfo->interface_protocol = nInterfaceProtocol; 919 if ( bBluetooth ) 920 { 921 pInfo->bus_type = HID_API_BUS_BLUETOOTH; 922 } 923 else 924 { 925 pInfo->bus_type = HID_API_BUS_USB; 926 } 927 928 hid_device_ref<CHIDDevice> pDevice( new CHIDDevice( nDeviceID, pInfo ) ); 929 930 hid_mutex_guard l( &g_DevicesMutex ); 931 hid_device_ref<CHIDDevice> pLast, pCurr; 932 for ( pCurr = g_Devices; pCurr; pLast = pCurr, pCurr = pCurr->next ) 933 { 934 continue; 935 } 936 if ( pLast ) 937 { 938 pLast->next = pDevice; 939 } 940 else 941 { 942 g_Devices = pDevice; 943 } 944} 945 946extern "C" 947JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, jint nDeviceID) 948{ 949 LOGV( "HIDDeviceOpenPending() id=%d\n", nDeviceID ); 950 hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID ); 951 if ( pDevice ) 952 { 953 pDevice->SetOpenPending(); 954 } 955} 956 957extern "C" 958JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult)(JNIEnv *env, jobject thiz, jint nDeviceID, jboolean bOpened) 959{ 960 LOGV( "HIDDeviceOpenResult() id=%d, result=%s\n", nDeviceID, bOpened ? "true" : "false" ); 961 hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID ); 962 if ( pDevice ) 963 { 964 pDevice->SetOpenResult( bOpened ); 965 } 966} 967 968extern "C" 969JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected)(JNIEnv *env, jobject thiz, jint nDeviceID) 970{ 971 LOGV( "HIDDeviceDisconnected() id=%d\n", nDeviceID ); 972 hid_device_ref<CHIDDevice> pDevice; 973 { 974 hid_mutex_guard l( &g_DevicesMutex ); 975 hid_device_ref<CHIDDevice> pLast, pCurr; 976 for ( pCurr = g_Devices; pCurr; pLast = pCurr, pCurr = pCurr->next ) 977 { 978 if ( pCurr->GetId() == nDeviceID ) 979 { 980 pDevice = pCurr; 981 982 if ( pLast ) 983 { 984 pLast->next = pCurr->next; 985 } 986 else 987 { 988 g_Devices = pCurr->next; 989 } 990 } 991 } 992 } 993 if ( pDevice ) 994 { 995 pDevice->Close( false ); 996 } 997} 998 999extern "C" 1000JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport)(JNIEnv *env, jobject thiz, jint nDeviceID, jbyteArray value) 1001{ 1002 jbyte *pBuf = env->GetByteArrayElements(value, NULL); 1003 jsize nBufSize = env->GetArrayLength(value); 1004 1005// LOGV( "HIDDeviceInput() id=%d len=%u\n", nDeviceID, nBufSize ); 1006 hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID ); 1007 if ( pDevice ) 1008 { 1009 pDevice->ProcessInput( reinterpret_cast< const uint8_t * >( pBuf ), nBufSize ); 1010 } 1011 1012 env->ReleaseByteArrayElements(value, pBuf, 0); 1013} 1014 1015extern "C" 1016JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReportResponse)(JNIEnv *env, jobject thiz, jint nDeviceID, jbyteArray value) 1017{ 1018 jbyte *pBuf = env->GetByteArrayElements(value, NULL); 1019 jsize nBufSize = env->GetArrayLength(value); 1020 1021 LOGV( "HIDDeviceReportResponse() id=%d len=%u\n", nDeviceID, nBufSize ); 1022 hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID ); 1023 if ( pDevice ) 1024 { 1025 pDevice->ProcessReportResponse( reinterpret_cast< const uint8_t * >( pBuf ), nBufSize ); 1026 } 1027 1028 env->ReleaseByteArrayElements(value, pBuf, 0); 1029} 1030 1031////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1032////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1033////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1034 1035extern "C" 1036{ 1037 1038static void SDLCALL RequestBluetoothPermissionCallback( void *userdata, const char *permission, bool granted ) 1039{ 1040 SDL_Log( "Bluetooth permission %s", granted ? "granted" : "denied" ); 1041 1042 if ( granted && g_HIDDeviceManagerCallbackHandler ) 1043 { 1044 JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv(); 1045 1046 env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerInitialize, false, true ); 1047 } 1048} 1049 1050int hid_init(void) 1051{ 1052 if ( !g_initialized && g_HIDDeviceManagerCallbackHandler ) 1053 { 1054 // HIDAPI doesn't work well with Android < 4.3 1055 if ( SDL_GetAndroidSDKVersion() >= 18 ) 1056 { 1057 JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv(); 1058 1059 env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerInitialize, true, false ); 1060 1061 // Bluetooth is currently only used for Steam Controllers, so check that hint 1062 // before initializing Bluetooth, which will prompt the user for permission. 1063 if ( SDL_GetHintBoolean( SDL_HINT_JOYSTICK_HIDAPI_STEAM, false ) ) 1064 { 1065 if ( SDL_GetAndroidSDKVersion() < 31 ) 1066 { 1067 env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerInitialize, false, true ); 1068 } 1069 else 1070 { 1071 SDL_Log( "Requesting Bluetooth permission" ); 1072 SDL_RequestAndroidPermission( "android.permission.BLUETOOTH_CONNECT", RequestBluetoothPermissionCallback, NULL ); 1073 } 1074 } 1075 ExceptionCheck( env, NULL, "hid_init" ); 1076 } 1077 g_initialized = true; // Regardless of result, so it's only called once 1078 } 1079 return 0; 1080} 1081 1082struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id) 1083{ 1084 struct hid_device_info *root = NULL; 1085 1086 hid_mutex_guard l( &g_DevicesMutex ); 1087 for ( hid_device_ref<CHIDDevice> pDevice = g_Devices; pDevice; pDevice = pDevice->next ) 1088 { 1089 // Don't enumerate devices that are currently being opened, we'll re-enumerate them when we're done 1090 // Make sure we skip them at least once, so they get removed and then re-added to the caller's device list 1091 if ( pDevice->BWasOpenPending() ) 1092 { 1093 // Don't enumerate devices that failed to open, otherwise the application might try to keep prompting for access 1094 if ( !pDevice->BOpenPending() && pDevice->BOpenResult() ) 1095 { 1096 pDevice->SetWasOpenPending( false ); 1097 } 1098 continue; 1099 } 1100 1101 const hid_device_info *info = pDevice->GetDeviceInfo(); 1102 1103 /* See if there are any devices we should skip in enumeration */ 1104 if (SDL_HIDAPI_ShouldIgnoreDevice(HID_API_BUS_UNKNOWN, info->vendor_id, info->product_id, 0, 0, false)) { 1105 continue; 1106 } 1107 1108 if ( ( vendor_id == 0x0 || info->vendor_id == vendor_id ) && 1109 ( product_id == 0x0 || info->product_id == product_id ) ) 1110 { 1111 hid_device_info *dev = CopyHIDDeviceInfo( info ); 1112 dev->next = root; 1113 root = dev; 1114 } 1115 } 1116 return root; 1117} 1118 1119void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs) 1120{ 1121 while ( devs ) 1122 { 1123 struct hid_device_info *next = devs->next; 1124 FreeHIDDeviceInfo( devs ); 1125 devs = next; 1126 } 1127} 1128 1129HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) 1130{ 1131 // TODO: Implement 1132 return NULL; 1133} 1134 1135HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path) 1136{ 1137 LOGV( "hid_open_path( %s )", path ); 1138 1139 hid_device_ref< CHIDDevice > pDevice; 1140 { 1141 hid_mutex_guard r( &g_DevicesRefCountMutex ); 1142 hid_mutex_guard l( &g_DevicesMutex ); 1143 for ( hid_device_ref<CHIDDevice> pCurr = g_Devices; pCurr; pCurr = pCurr->next ) 1144 { 1145 if ( SDL_strcmp( pCurr->GetDeviceInfo()->path, path ) == 0 ) 1146 { 1147 hid_device *pValue = pCurr->GetDevice(); 1148 if ( pValue ) 1149 { 1150 ++pValue->m_nDeviceRefCount; 1151 LOGD("Incrementing device %d (%p), refCount = %d\n", pValue->m_nId, pValue, pValue->m_nDeviceRefCount); 1152 return pValue; 1153 } 1154 1155 // Hold a shared pointer to the controller for the duration 1156 pDevice = pCurr; 1157 break; 1158 } 1159 } 1160 } 1161 if ( !pDevice ) 1162 { 1163 SDL_SetError( "Couldn't find device with path %s", path ); 1164 return NULL; 1165 } 1166 if ( pDevice->BOpen() ) 1167 { 1168 return pDevice->GetDevice(); 1169 } 1170 return NULL; 1171} 1172 1173int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length) 1174{ 1175 if ( device ) 1176 { 1177// LOGV( "hid_write id=%d length=%zu", device->m_nId, length ); 1178 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1179 if ( pDevice ) 1180 { 1181 return pDevice->WriteReport( data, length, false ); 1182 } 1183 } 1184 return -1; // Controller was disconnected 1185} 1186 1187static uint32_t getms() 1188{ 1189 struct timeval now; 1190 1191 gettimeofday(&now, NULL); 1192 return (uint32_t)(now.tv_sec * 1000 + now.tv_usec / 1000); 1193} 1194 1195static void delayms(uint32_t ms) 1196{ 1197 int was_error; 1198 1199 struct timespec elapsed, tv; 1200 1201 /* Set the timeout interval */ 1202 elapsed.tv_sec = ms / 1000; 1203 elapsed.tv_nsec = (ms % 1000) * 1000000; 1204 do { 1205 errno = 0; 1206 1207 tv.tv_sec = elapsed.tv_sec; 1208 tv.tv_nsec = elapsed.tv_nsec; 1209 was_error = nanosleep(&tv, &elapsed); 1210 } while (was_error && (errno == EINTR)); 1211} 1212 1213int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *device, unsigned char *data, size_t length, int milliseconds) 1214{ 1215 if ( device ) 1216 { 1217// LOGV( "hid_read_timeout id=%d length=%u timeout=%d", device->m_nId, length, milliseconds ); 1218 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1219 if ( pDevice ) 1220 { 1221 int nResult = pDevice->GetInput( data, length ); 1222 if ( nResult == 0 && milliseconds > 0 ) 1223 { 1224 uint32_t start = getms(); 1225 do 1226 { 1227 delayms( 1 ); 1228 nResult = pDevice->GetInput( data, length ); 1229 } while ( nResult == 0 && ( getms() - start ) < milliseconds ); 1230 } 1231 return nResult; 1232 } 1233 LOGV( "controller was disconnected" ); 1234 } 1235 return -1; // Controller was disconnected 1236} 1237 1238// TODO: Implement blocking 1239int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length) 1240{ 1241// LOGV( "hid_read id=%d length=%zu", device->m_nId, length ); 1242 return hid_read_timeout( device, data, length, 0 ); 1243} 1244 1245// TODO: Implement? 1246int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock) 1247{ 1248 return -1; 1249} 1250 1251int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length) 1252{ 1253 if ( device ) 1254 { 1255 LOGV( "hid_send_feature_report id=%d length=%zu", device->m_nId, length ); 1256 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1257 if ( pDevice ) 1258 { 1259 return pDevice->WriteReport( data, length, true ); 1260 } 1261 } 1262 return -1; // Controller was disconnected 1263} 1264 1265 1266// Synchronous operation. Will block until completed. 1267int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length) 1268{ 1269 if ( device ) 1270 { 1271 LOGV( "hid_get_feature_report id=%d length=%zu", device->m_nId, length ); 1272 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1273 if ( pDevice ) 1274 { 1275 return pDevice->ReadReport( data, length, true ); 1276 } 1277 } 1278 return -1; // Controller was disconnected 1279} 1280 1281 1282// Synchronous operation. Will block until completed. 1283int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *device, unsigned char *data, size_t length) 1284{ 1285 if ( device ) 1286 { 1287 LOGV( "hid_get_input_report id=%d length=%zu", device->m_nId, length ); 1288 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1289 if ( pDevice ) 1290 { 1291 return pDevice->ReadReport( data, length, false ); 1292 } 1293 } 1294 return -1; // Controller was disconnected 1295} 1296 1297 1298void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device) 1299{ 1300 if ( device ) 1301 { 1302 LOGV( "hid_close id=%d", device->m_nId ); 1303 hid_mutex_guard r( &g_DevicesRefCountMutex ); 1304 LOGD("Decrementing device %d (%p), refCount = %d\n", device->m_nId, device, device->m_nDeviceRefCount - 1); 1305 if ( --device->m_nDeviceRefCount == 0 ) 1306 { 1307 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1308 if ( pDevice ) 1309 { 1310 pDevice->Close( true ); 1311 } 1312 else 1313 { 1314 delete device; 1315 } 1316 LOGD("Deleted device %p\n", device); 1317 } 1318 } 1319} 1320 1321int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen) 1322{ 1323 if ( device ) 1324 { 1325 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1326 if ( pDevice ) 1327 { 1328 wcsncpy( string, pDevice->GetDeviceInfo()->manufacturer_string, maxlen ); 1329 return 0; 1330 } 1331 } 1332 return -1; 1333} 1334 1335int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen) 1336{ 1337 if ( device ) 1338 { 1339 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1340 if ( pDevice ) 1341 { 1342 wcsncpy( string, pDevice->GetDeviceInfo()->product_string, maxlen ); 1343 return 0; 1344 } 1345 } 1346 return -1; 1347} 1348 1349int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen) 1350{ 1351 if ( device ) 1352 { 1353 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1354 if ( pDevice ) 1355 { 1356 wcsncpy( string, pDevice->GetDeviceInfo()->serial_number, maxlen ); 1357 return 0; 1358 } 1359 } 1360 return -1; 1361} 1362 1363int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen) 1364{ 1365 return -1; 1366} 1367 1368struct hid_device_info *hid_get_device_info(hid_device *device) 1369{ 1370 if ( device ) 1371 { 1372 hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId ); 1373 if ( pDevice ) 1374 { 1375 return pDevice->GetDeviceInfo(); 1376 } 1377 } 1378 return NULL; 1379} 1380 1381int hid_get_report_descriptor(hid_device *device, unsigned char *buf, size_t buf_size) 1382{ 1383 // Not implemented 1384 return -1; 1385} 1386 1387HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *device) 1388{ 1389 return NULL; 1390} 1391 1392int hid_exit(void) 1393{ 1394 return 0; 1395} 1396 1397} 1398 1399#else 1400 1401extern "C" 1402JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz); 1403 1404extern "C" 1405JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz); 1406 1407extern "C" 1408JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, jint nDeviceID, jstring sIdentifier, jint nVendorId, jint nProductId, jstring sSerialNumber, jint nReleaseNumber, jstring sManufacturer, jstring sProduct, jint nInterface, jint nInterfaceClass, jint nInterfaceSubclass, jint nInterfaceProtocol, jboolean bBluetooth ); 1409 1410extern "C" 1411JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, jint nDeviceID); 1412 1413extern "C" 1414JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult)(JNIEnv *env, jobject thiz, jint nDeviceID, jboolean bOpened); 1415 1416extern "C" 1417JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected)(JNIEnv *env, jobject thiz, jint nDeviceID); 1418 1419extern "C" 1420JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport)(JNIEnv *env, jobject thiz, jint nDeviceID, jbyteArray value); 1421 1422extern "C" 1423JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReportResponse)(JNIEnv *env, jobject thiz, jint nDeviceID, jbyteArray value); 1424 1425 1426extern "C" 1427JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz ) 1428{ 1429 LOGV("Stub HIDDeviceRegisterCallback()"); 1430} 1431 1432extern "C" 1433JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz) 1434{ 1435 LOGV("Stub HIDDeviceReleaseCallback()"); 1436} 1437 1438extern "C" 1439JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, jint nDeviceID, jstring sIdentifier, jint nVendorId, jint nProductId, jstring sSerialNumber, jint nReleaseNumber, jstring sManufacturer, jstring sProduct, jint nInterface, jint nInterfaceClass, jint nInterfaceSubclass, jint nInterfaceProtocol, jboolean bBluetooth ) 1440{ 1441 LOGV("Stub HIDDeviceConnected() id=%d VID/PID = %.4x/%.4x, interface %d\n", nDeviceID, nVendorId, nProductId, nInterface); 1442} 1443 1444extern "C" 1445JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, jint nDeviceID) 1446{ 1447 LOGV("Stub HIDDeviceOpenPending() id=%d\n", nDeviceID); 1448} 1449 1450extern "C" 1451JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult)(JNIEnv *env, jobject thiz, jint nDeviceID, jboolean bOpened) 1452{ 1453 LOGV("Stub HIDDeviceOpenResult() id=%d, result=%s\n", nDeviceID, bOpened ? "true" : "false"); 1454} 1455 1456extern "C" 1457JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected)(JNIEnv *env, jobject thiz, jint nDeviceID) 1458{ 1459 LOGV("Stub HIDDeviceDisconnected() id=%d\n", nDeviceID); 1460} 1461 1462extern "C" 1463JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport)(JNIEnv *env, jobject thiz, jint nDeviceID, jbyteArray value) 1464{ 1465 LOGV("Stub HIDDeviceInput() id=%d len=%u\n", nDeviceID, env->GetArrayLength(value)); 1466} 1467 1468extern "C" 1469JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReportResponse)(JNIEnv *env, jobject thiz, jint nDeviceID, jbyteArray value) 1470{ 1471 LOGV("Stub HIDDeviceReportResponse() id=%d len=%u\n", nDeviceID, env->GetArrayLength(value)); 1472} 1473 1474#endif /* SDL_HIDAPI_DISABLED */ 1475 1476extern "C" 1477JNINativeMethod HIDDeviceManager_tab[8] = { 1478 { "HIDDeviceRegisterCallback", "()V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback) }, 1479 { "HIDDeviceReleaseCallback", "()V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback) }, 1480 { "HIDDeviceConnected", "(ILjava/lang/String;IILjava/lang/String;ILjava/lang/String;Ljava/lang/String;IIIIZ)V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected) }, 1481 { "HIDDeviceOpenPending", "(I)V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending) }, 1482 { "HIDDeviceOpenResult", "(IZ)V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult) }, 1483 { "HIDDeviceDisconnected", "(I)V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected) }, 1484 { "HIDDeviceInputReport", "(I[B)V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport) }, 1485 { "HIDDeviceReportResponse", "(I[B)V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReportResponse) } 1486}; 1487[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.