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