src/hidapi/android/hid.cpp
author Sam Lantinga <slouken@libsdl.org>
Mon, 22 Oct 2018 14:55:42 -0700
changeset 12346 b4c98c84a0b2
parent 12308 4e3b4ddb8787
child 12765 80586f864508
permissions -rw-r--r--
Add exception handling to Android hidapi.
     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 		m_bIsWaitingForOpen = false;
   440 		m_bOpenResult = env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerOpen, m_nId );
   441 		ExceptionCheck( env, "BOpen" );
   442 
   443 		if ( m_bIsWaitingForOpen )
   444 		{
   445 			hid_mutex_guard cvl( &m_cvLock );
   446 
   447 			const int OPEN_TIMEOUT_SECONDS = 60;
   448 			struct timespec ts, endtime;
   449 			clock_gettime( CLOCK_REALTIME, &ts );
   450 			endtime = ts;
   451 			endtime.tv_sec += OPEN_TIMEOUT_SECONDS;
   452 			do
   453 			{
   454 				if ( pthread_cond_timedwait( &m_cv, &m_cvLock, &endtime ) != 0 )
   455 				{
   456 					break;
   457 				}
   458 			}
   459 			while ( m_bIsWaitingForOpen && get_timespec_ms( ts ) < get_timespec_ms( endtime ) );
   460 		}
   461 
   462 		if ( !m_bOpenResult )
   463 		{
   464 			if ( m_bIsWaitingForOpen )
   465 			{
   466 				LOGV( "Device open failed - timed out waiting for device permission" );
   467 			}
   468 			else
   469 			{
   470 				LOGV( "Device open failed" );
   471 			}
   472 			return false;
   473 		}
   474 
   475 		m_pDevice = new hid_device;
   476 		m_pDevice->m_nId = m_nId;
   477 		m_pDevice->m_nDeviceRefCount = 1;
   478 		LOGD("Creating device %d (%p), refCount = 1\n", m_pDevice->m_nId, m_pDevice);
   479 		return true;
   480 	}
   481 
   482 	void SetOpenPending()
   483 	{
   484 		m_bIsWaitingForOpen = true;
   485 	}
   486 
   487 	void SetOpenResult( bool bResult )
   488 	{
   489 		if ( m_bIsWaitingForOpen )
   490 		{
   491 			m_bOpenResult = bResult;
   492 			m_bIsWaitingForOpen = false;
   493 			pthread_cond_signal( &m_cv );
   494 		}
   495 	}
   496 
   497 	void ProcessInput( const uint8_t *pBuf, size_t nBufSize )
   498 	{
   499 		hid_mutex_guard l( &m_dataLock );
   500 
   501 		size_t MAX_REPORT_QUEUE_SIZE = 16;
   502 		if ( m_vecData.size() >= MAX_REPORT_QUEUE_SIZE )
   503 		{
   504 			m_vecData.pop_front();
   505 		}
   506 		m_vecData.emplace_back( pBuf, nBufSize );
   507 	}
   508 
   509 	int GetInput( unsigned char *data, size_t length )
   510 	{
   511 		hid_mutex_guard l( &m_dataLock );
   512 
   513 		if ( m_vecData.size() == 0 )
   514 		{
   515 //			LOGV( "hid_read_timeout no data available" );
   516 			return 0;
   517 		}
   518 
   519 		const hid_buffer &buffer = m_vecData.front();
   520 		size_t nDataLen = buffer.size() > length ? length : buffer.size();
   521 		if ( m_bIsBLESteamController )
   522 		{
   523 			data[0] = 0x03;
   524 			memcpy( data + 1, buffer.data(), nDataLen );
   525 			++nDataLen;
   526 		}
   527 		else
   528 		{
   529 			memcpy( data, buffer.data(), nDataLen );
   530 		}
   531 		m_vecData.pop_front();
   532 
   533 //		LOGV("Read %u bytes", nDataLen);
   534 //		LOGV("%02x %02x %02x %02x %02x %02x %02x %02x ....",
   535 //			 data[0], data[1], data[2], data[3],
   536 //			 data[4], data[5], data[6], data[7]);
   537 
   538 		return nDataLen;
   539 	}
   540 
   541 	int SendOutputReport( const unsigned char *pData, size_t nDataLen )
   542 	{
   543 		// Make sure thread is attached to JVM/env
   544 		JNIEnv *env;
   545 		g_JVM->AttachCurrentThread( &env, NULL );
   546 		pthread_setspecific( g_ThreadKey, (void*)env );
   547 
   548 		jbyteArray pBuf = NewByteArray( env, pData, nDataLen );
   549 		int nRet = env->CallIntMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerSendOutputReport, m_nId, pBuf );
   550 		ExceptionCheck( env, "SendOutputReport" );
   551 
   552 		env->DeleteLocalRef( pBuf );
   553 		return nRet;
   554 	}
   555 
   556 	int SendFeatureReport( const unsigned char *pData, size_t nDataLen )
   557 	{
   558 		// Make sure thread is attached to JVM/env
   559 		JNIEnv *env;
   560 		g_JVM->AttachCurrentThread( &env, NULL );
   561 		pthread_setspecific( g_ThreadKey, (void*)env );
   562 
   563 		jbyteArray pBuf = NewByteArray( env, pData, nDataLen );
   564 		int nRet = env->CallIntMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerSendFeatureReport, m_nId, pBuf );
   565 		ExceptionCheck( env, "SendFeatureReport" );
   566 		env->DeleteLocalRef( pBuf );
   567 		return nRet;
   568 	}
   569 
   570 	void ProcessFeatureReport( const uint8_t *pBuf, size_t nBufSize )
   571 	{
   572 		hid_mutex_guard cvl( &m_cvLock );
   573 		if ( m_bIsWaitingForFeatureReport )
   574 		{
   575 			m_featureReport.assign( pBuf, nBufSize );
   576 
   577 			m_bIsWaitingForFeatureReport = false;
   578 			m_nFeatureReportError = 0;
   579 			pthread_cond_signal( &m_cv );
   580 		}
   581 	}
   582 
   583 	int GetFeatureReport( unsigned char *pData, size_t nDataLen )
   584 	{
   585 		// Make sure thread is attached to JVM/env
   586 		JNIEnv *env;
   587 		g_JVM->AttachCurrentThread( &env, NULL );
   588 		pthread_setspecific( g_ThreadKey, (void*)env );
   589 
   590 		{
   591 			hid_mutex_guard cvl( &m_cvLock );
   592 			if ( m_bIsWaitingForFeatureReport )
   593 			{
   594 				LOGV( "Get feature report already ongoing... bail" );
   595 				return -1; // Read already ongoing, we currently do not serialize, TODO
   596 			}
   597 			m_bIsWaitingForFeatureReport = true;
   598 		}
   599 
   600 		jbyteArray pBuf = NewByteArray( env, pData, nDataLen );
   601 		int nRet = env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerGetFeatureReport, m_nId, pBuf ) ? 0 : -1;
   602 		ExceptionCheck( env, "GetFeatureReport" );
   603 		env->DeleteLocalRef( pBuf );
   604 		if ( nRet < 0 )
   605 		{
   606 			LOGV( "GetFeatureReport failed" );
   607 			m_bIsWaitingForFeatureReport = false;
   608 			return -1;
   609 		}
   610 
   611 		{
   612 			hid_mutex_guard cvl( &m_cvLock );
   613 			if ( m_bIsWaitingForFeatureReport )
   614 			{
   615 				LOGV("=== Going to sleep" );
   616 				// Wait in CV until we are no longer waiting for a feature report.
   617 				const int FEATURE_REPORT_TIMEOUT_SECONDS = 2;
   618 				struct timespec ts, endtime;
   619 				clock_gettime( CLOCK_REALTIME, &ts );
   620 				endtime = ts;
   621 				endtime.tv_sec += FEATURE_REPORT_TIMEOUT_SECONDS;
   622 				do
   623 				{
   624 					if ( pthread_cond_timedwait( &m_cv, &m_cvLock, &endtime ) != 0 )
   625 					{
   626 						break;
   627 					}
   628 				}
   629 				while ( m_bIsWaitingForFeatureReport && get_timespec_ms( ts ) < get_timespec_ms( endtime ) );
   630 
   631 				// We are back
   632 				if ( m_bIsWaitingForFeatureReport )
   633 				{
   634 					m_nFeatureReportError = -ETIMEDOUT;
   635 					m_bIsWaitingForFeatureReport = false;
   636 				}
   637 				LOGV( "=== Got feature report err=%d", m_nFeatureReportError );
   638 				if ( m_nFeatureReportError != 0 )
   639 				{
   640 					return m_nFeatureReportError;
   641 				}
   642 			}
   643 
   644 			size_t uBytesToCopy = m_featureReport.size() > nDataLen ? nDataLen : m_featureReport.size();
   645 			memcpy( pData, m_featureReport.data(), uBytesToCopy );
   646 			m_featureReport.clear();
   647 			LOGV( "=== Got %u bytes", uBytesToCopy );
   648 
   649 			return uBytesToCopy;
   650 		}
   651 	}
   652 
   653 	void Close( bool bDeleteDevice )
   654 	{
   655 		// Make sure thread is attached to JVM/env
   656 		JNIEnv *env;
   657 		g_JVM->AttachCurrentThread( &env, NULL );
   658 		pthread_setspecific( g_ThreadKey, (void*)env );
   659 
   660 		env->CallVoidMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerClose, m_nId );
   661 		ExceptionCheck( env, "Close" );
   662 	
   663 		hid_mutex_guard dataLock( &m_dataLock );
   664 		m_vecData.clear();
   665 
   666 		// Clean and release pending feature report reads
   667 		hid_mutex_guard cvLock( &m_cvLock );
   668 		m_featureReport.clear();
   669 		m_bIsWaitingForFeatureReport = false;
   670 		m_nFeatureReportError = -ECONNRESET;
   671 		pthread_cond_broadcast( &m_cv );
   672 
   673 		if ( bDeleteDevice )
   674 		{
   675 			delete m_pDevice;
   676 			m_pDevice = nullptr;
   677 		}
   678 	}
   679 
   680 private:
   681 	pthread_mutex_t m_refCountLock = PTHREAD_MUTEX_INITIALIZER;
   682 	int m_nRefCount = 0;
   683 	int m_nId = 0;
   684 	hid_device_info *m_pInfo = nullptr;
   685 	hid_device *m_pDevice = nullptr;
   686 	bool m_bIsBLESteamController = false;
   687 
   688 	pthread_mutex_t m_dataLock = PTHREAD_MUTEX_INITIALIZER; // This lock has to be held to access m_vecData
   689 	hid_buffer_pool m_vecData;
   690 
   691 	// For handling get_feature_report
   692 	pthread_mutex_t m_cvLock = PTHREAD_MUTEX_INITIALIZER; // This lock has to be held to access any variables below
   693 	pthread_cond_t m_cv = PTHREAD_COND_INITIALIZER;
   694 	bool m_bIsWaitingForOpen = false;
   695 	bool m_bOpenResult = false;
   696 	bool m_bIsWaitingForFeatureReport = false;
   697 	int m_nFeatureReportError = 0;
   698 	hid_buffer m_featureReport;
   699 
   700 public:
   701 	hid_device_ref<CHIDDevice> next;
   702 };
   703 
   704 class CHIDDevice;
   705 static pthread_mutex_t g_DevicesMutex = PTHREAD_MUTEX_INITIALIZER;
   706 static pthread_mutex_t g_DevicesRefCountMutex = PTHREAD_MUTEX_INITIALIZER;
   707 static hid_device_ref<CHIDDevice> g_Devices;
   708 
   709 static hid_device_ref<CHIDDevice> FindDevice( int nDeviceId )
   710 {
   711 	hid_device_ref<CHIDDevice> pDevice;
   712 
   713 	hid_mutex_guard l( &g_DevicesMutex );
   714 	for ( pDevice = g_Devices; pDevice; pDevice = pDevice->next )
   715 	{
   716 		if ( pDevice->GetId() == nDeviceId )
   717 		{
   718 			break;
   719 		}
   720 	}
   721 	return pDevice;
   722 }
   723 
   724 static void ThreadDestroyed(void* value)
   725 {
   726 	/* The thread is being destroyed, detach it from the Java VM and set the g_ThreadKey value to NULL as required */
   727 	JNIEnv *env = (JNIEnv*) value;
   728 	if (env != NULL) {
   729 		g_JVM->DetachCurrentThread();
   730 		pthread_setspecific(g_ThreadKey, NULL);
   731 	}
   732 }
   733 
   734 
   735 extern "C"
   736 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz);
   737 
   738 extern "C"
   739 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz);
   740 
   741 extern "C"
   742 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 );
   743 
   744 extern "C"
   745 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, int nDeviceID);
   746 
   747 extern "C"
   748 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult)(JNIEnv *env, jobject thiz, int nDeviceID, bool bOpened);
   749 
   750 extern "C"
   751 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected)(JNIEnv *env, jobject thiz, int nDeviceID);
   752 
   753 extern "C"
   754 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value);
   755 
   756 extern "C"
   757 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceFeatureReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value);
   758 
   759 
   760 extern "C"
   761 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz )
   762 {
   763 	LOGV( "HIDDeviceRegisterCallback()");
   764 
   765 	env->GetJavaVM( &g_JVM );
   766 
   767 	/*
   768 	 * Create mThreadKey so we can keep track of the JNIEnv assigned to each thread
   769 	 * Refer to http://developer.android.com/guide/practices/design/jni.html for the rationale behind this
   770 	 */
   771 	if (pthread_key_create(&g_ThreadKey, ThreadDestroyed) != 0) {
   772 		__android_log_print(ANDROID_LOG_ERROR, TAG, "Error initializing pthread key");
   773 	}
   774 
   775 	if ( g_HIDDeviceManagerCallbackHandler != NULL )
   776 	{
   777 		env->DeleteGlobalRef( g_HIDDeviceManagerCallbackClass );
   778 		g_HIDDeviceManagerCallbackClass = NULL;
   779 		env->DeleteGlobalRef( g_HIDDeviceManagerCallbackHandler );
   780 		g_HIDDeviceManagerCallbackHandler = NULL;
   781 	}
   782 
   783 	g_HIDDeviceManagerCallbackHandler = env->NewGlobalRef( thiz );
   784 	jclass objClass = env->GetObjectClass( thiz );
   785 	if ( objClass )
   786 	{
   787 		g_HIDDeviceManagerCallbackClass = reinterpret_cast< jclass >( env->NewGlobalRef( objClass ) );
   788 		g_midHIDDeviceManagerOpen = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "openDevice", "(I)Z" );
   789 		if ( !g_midHIDDeviceManagerOpen )
   790 		{
   791 			__android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing openDevice" );
   792 		}
   793 		g_midHIDDeviceManagerSendOutputReport = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "sendOutputReport", "(I[B)I" );
   794 		if ( !g_midHIDDeviceManagerSendOutputReport )
   795 		{
   796 			__android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing sendOutputReport" );
   797 		}
   798 		g_midHIDDeviceManagerSendFeatureReport = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "sendFeatureReport", "(I[B)I" );
   799 		if ( !g_midHIDDeviceManagerSendFeatureReport )
   800 		{
   801 			__android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing sendFeatureReport" );
   802 		}
   803 		g_midHIDDeviceManagerGetFeatureReport = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "getFeatureReport", "(I[B)Z" );
   804 		if ( !g_midHIDDeviceManagerGetFeatureReport )
   805 		{
   806 			__android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing getFeatureReport" );
   807 		}
   808 		g_midHIDDeviceManagerClose = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "closeDevice", "(I)V" );
   809 		if ( !g_midHIDDeviceManagerClose )
   810 		{
   811 			__android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing closeDevice" );
   812 		}
   813 		env->DeleteLocalRef( objClass );
   814 	}
   815 }
   816 
   817 extern "C"
   818 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz)
   819 {
   820 	LOGV("HIDDeviceReleaseCallback");
   821 	if ( env->IsSameObject( thiz, g_HIDDeviceManagerCallbackHandler ) )
   822 	{
   823 		env->DeleteGlobalRef( g_HIDDeviceManagerCallbackClass );
   824 		g_HIDDeviceManagerCallbackClass = NULL;
   825 		env->DeleteGlobalRef( g_HIDDeviceManagerCallbackHandler );
   826 		g_HIDDeviceManagerCallbackHandler = NULL;
   827 	}
   828 }
   829 
   830 extern "C"
   831 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 )
   832 {
   833 	LOGV( "HIDDeviceConnected() id=%d VID/PID = %.4x/%.4x, interface %d\n", nDeviceID, nVendorId, nProductId, nInterface );
   834 
   835 	hid_device_info *pInfo = new hid_device_info;
   836 	memset( pInfo, 0, sizeof( *pInfo ) );
   837 	pInfo->path = CreateStringFromJString( env, sIdentifier );
   838 	pInfo->vendor_id = nVendorId;
   839 	pInfo->product_id = nProductId;
   840 	pInfo->serial_number = CreateWStringFromJString( env, sSerialNumber );
   841 	pInfo->release_number = nReleaseNumber;
   842 	pInfo->manufacturer_string = CreateWStringFromJString( env, sManufacturer );
   843 	pInfo->product_string = CreateWStringFromJString( env, sProduct );
   844 	pInfo->interface_number = nInterface;
   845 
   846 	hid_device_ref<CHIDDevice> pDevice( new CHIDDevice( nDeviceID, pInfo ) );
   847 
   848 	hid_mutex_guard l( &g_DevicesMutex );
   849 	hid_device_ref<CHIDDevice> pLast, pCurr;
   850 	for ( pCurr = g_Devices; pCurr; pLast = pCurr, pCurr = pCurr->next )
   851 	{
   852 		continue;
   853 	}
   854 	if ( pLast )
   855 	{
   856 		pLast->next = pDevice;
   857 	}
   858 	else
   859 	{
   860 		g_Devices = pDevice;
   861 	}
   862 }
   863 
   864 extern "C"
   865 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, int nDeviceID)
   866 {
   867 	LOGV( "HIDDeviceOpenPending() id=%d\n", nDeviceID );
   868 	hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID );
   869 	if ( pDevice )
   870 	{
   871 		pDevice->SetOpenPending();
   872 	}
   873 }
   874 
   875 extern "C"
   876 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult)(JNIEnv *env, jobject thiz, int nDeviceID, bool bOpened)
   877 {
   878 	LOGV( "HIDDeviceOpenResult() id=%d, result=%s\n", nDeviceID, bOpened ? "true" : "false" );
   879 	hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID );
   880 	if ( pDevice )
   881 	{
   882 		pDevice->SetOpenResult( bOpened );
   883 	}
   884 }
   885 
   886 extern "C"
   887 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected)(JNIEnv *env, jobject thiz, int nDeviceID)
   888 {
   889 	LOGV( "HIDDeviceDisconnected() id=%d\n", nDeviceID );
   890 	hid_device_ref<CHIDDevice> pDevice;
   891 	{
   892 		hid_mutex_guard l( &g_DevicesMutex );
   893 		hid_device_ref<CHIDDevice> pLast, pCurr;
   894 		for ( pCurr = g_Devices; pCurr; pLast = pCurr, pCurr = pCurr->next )
   895 		{
   896 			if ( pCurr->GetId() == nDeviceID )
   897 			{
   898 				pDevice = pCurr;
   899 
   900 				if ( pLast )
   901 				{
   902 					pLast->next = pCurr->next;
   903 				}
   904 				else
   905 				{
   906 					g_Devices = pCurr->next;
   907 				}
   908 			}
   909 		}
   910 	}
   911 	if ( pDevice )
   912 	{
   913 		pDevice->Close( false );
   914 	}
   915 }
   916 
   917 extern "C"
   918 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value)
   919 {
   920 	jbyte *pBuf = env->GetByteArrayElements(value, NULL);
   921 	jsize nBufSize = env->GetArrayLength(value);
   922 
   923 //	LOGV( "HIDDeviceInput() id=%d len=%u\n", nDeviceID, nBufSize );
   924 	hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID );
   925 	if ( pDevice )
   926 	{
   927 		pDevice->ProcessInput( reinterpret_cast< const uint8_t* >( pBuf ), nBufSize );
   928 	}
   929 
   930 	env->ReleaseByteArrayElements(value, pBuf, 0);
   931 }
   932 
   933 extern "C"
   934 JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceFeatureReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value)
   935 {
   936 	jbyte *pBuf = env->GetByteArrayElements(value, NULL);
   937 	jsize nBufSize = env->GetArrayLength(value);
   938 
   939 	LOGV( "HIDDeviceFeatureReport() id=%d len=%u\n", nDeviceID, nBufSize );
   940 	hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID );
   941 	if ( pDevice )
   942 	{
   943 		pDevice->ProcessFeatureReport( reinterpret_cast< const uint8_t* >( pBuf ), nBufSize );
   944 	}
   945 
   946 	env->ReleaseByteArrayElements(value, pBuf, 0);
   947 }
   948 
   949 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
   950 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
   951 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
   952 
   953 extern "C"
   954 {
   955 
   956 int hid_init(void)
   957 {
   958 	return 0;
   959 }
   960 
   961 struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
   962 {
   963 	struct hid_device_info *root = NULL;
   964 	hid_mutex_guard l( &g_DevicesMutex );
   965 	for ( hid_device_ref<CHIDDevice> pDevice = g_Devices; pDevice; pDevice = pDevice->next )
   966 	{
   967 		const hid_device_info *info = pDevice->GetDeviceInfo();
   968 		if ( ( vendor_id == 0 && product_id == 0 ) ||
   969 			 ( vendor_id == info->vendor_id && product_id == info->product_id ) )
   970 		{
   971 			hid_device_info *dev = CopyHIDDeviceInfo( info );
   972 			dev->next = root;
   973 			root = dev;
   974 		}
   975 	}
   976 	return root;
   977 }
   978 
   979 void  HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
   980 {
   981 	while ( devs )
   982 	{
   983 		struct hid_device_info *next = devs->next;
   984 		FreeHIDDeviceInfo( devs );
   985 		devs = next;
   986 	}
   987 }
   988 
   989 HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
   990 {
   991 	// TODO: Implement
   992 	return NULL;
   993 }
   994 
   995 HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path, int bExclusive)
   996 {
   997 	LOGV( "hid_open_path( %s )", path );
   998 
   999 	hid_device_ref< CHIDDevice > pDevice;
  1000 	{
  1001 		hid_mutex_guard r( &g_DevicesRefCountMutex );
  1002 		hid_mutex_guard l( &g_DevicesMutex );
  1003 		for ( hid_device_ref<CHIDDevice> pCurr = g_Devices; pCurr; pCurr = pCurr->next )
  1004 		{
  1005 			if ( strcmp( pCurr->GetDeviceInfo()->path, path ) == 0 ) 
  1006 			{
  1007 				hid_device *pValue = pCurr->GetDevice();
  1008 				if ( pValue )
  1009 				{
  1010 					++pValue->m_nDeviceRefCount;
  1011 					LOGD("Incrementing device %d (%p), refCount = %d\n", pValue->m_nId, pValue, pValue->m_nDeviceRefCount);
  1012 					return pValue;
  1013 				}
  1014 
  1015 				// Hold a shared pointer to the controller for the duration
  1016 				pDevice = pCurr;
  1017 				break;
  1018 			}
  1019 		}
  1020 	}
  1021 	if ( pDevice && pDevice->BOpen() )
  1022 	{
  1023 		return pDevice->GetDevice();
  1024 	}
  1025 	return NULL;
  1026 }
  1027 
  1028 int  HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length)
  1029 {
  1030 	LOGV( "hid_write id=%d length=%u", device->m_nId, length );
  1031 	hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId );
  1032 	if ( pDevice )
  1033 	{
  1034 		return pDevice->SendOutputReport( data, length );
  1035 	}
  1036 	return -1; // Controller was disconnected
  1037 }
  1038 
  1039 // TODO: Implement timeout?
  1040 int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *device, unsigned char *data, size_t length, int milliseconds)
  1041 {
  1042 //	LOGV( "hid_read_timeout id=%d length=%u timeout=%d", device->m_nId, length, milliseconds );
  1043 	hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId );
  1044 	if ( pDevice )
  1045 	{
  1046 		return pDevice->GetInput( data, length );
  1047 	}
  1048 	LOGV( "controller was disconnected" );
  1049 	return -1; // Controller was disconnected
  1050 }
  1051 
  1052 // TODO: Implement blocking
  1053 int  HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length)
  1054 {
  1055 	LOGV( "hid_read id=%d length=%u", device->m_nId, length );
  1056 	return hid_read_timeout( device, data, length, 0 );
  1057 }
  1058 
  1059 // TODO: Implement?
  1060 int  HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock)
  1061 {
  1062 	return -1;
  1063 }
  1064 
  1065 int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length)
  1066 {
  1067 	LOGV( "hid_send_feature_report id=%d length=%u", device->m_nId, length );
  1068 	hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId );
  1069 	if ( pDevice )
  1070 	{
  1071 		return pDevice->SendFeatureReport( data, length );
  1072 	}
  1073 	return -1; // Controller was disconnected
  1074 }
  1075 
  1076 
  1077 // Synchronous operation. Will block until completed.
  1078 int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length)
  1079 {
  1080 	LOGV( "hid_get_feature_report id=%d length=%u", device->m_nId, length );
  1081 	hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId );
  1082 	if ( pDevice )
  1083 	{
  1084 		return pDevice->GetFeatureReport( data, length );
  1085 	}
  1086 	return -1; // Controller was disconnected
  1087 }
  1088 
  1089 
  1090 void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device)
  1091 {
  1092 	LOGV( "hid_close id=%d", device->m_nId );
  1093 	hid_mutex_guard r( &g_DevicesRefCountMutex );
  1094 	LOGD("Decrementing device %d (%p), refCount = %d\n", device->m_nId, device, device->m_nDeviceRefCount - 1);
  1095 	if ( --device->m_nDeviceRefCount == 0 )
  1096 	{
  1097 		hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId );
  1098 		if ( pDevice )
  1099 		{
  1100 			pDevice->Close( true );
  1101 		}
  1102 		else
  1103 		{
  1104 			delete device;
  1105 		}
  1106 		LOGD("Deleted device %p\n", device);
  1107 	}
  1108 
  1109 }
  1110 
  1111 int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen)
  1112 {
  1113 	hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId );
  1114 	if ( pDevice )
  1115 	{
  1116 		wcsncpy( string, pDevice->GetDeviceInfo()->manufacturer_string, maxlen );
  1117 		return 0;
  1118 	}
  1119 	return -1;
  1120 }
  1121 
  1122 int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen)
  1123 {
  1124 	hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId );
  1125 	if ( pDevice )
  1126 	{
  1127 		wcsncpy( string, pDevice->GetDeviceInfo()->product_string, maxlen );
  1128 		return 0;
  1129 	}
  1130 	return -1;
  1131 }
  1132 
  1133 int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen)
  1134 {
  1135 	hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId );
  1136 	if ( pDevice )
  1137 	{
  1138 		wcsncpy( string, pDevice->GetDeviceInfo()->serial_number, maxlen );
  1139 		return 0;
  1140 	}
  1141 	return -1;
  1142 }
  1143 
  1144 int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen)
  1145 {
  1146 	return -1;
  1147 }
  1148 
  1149 HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device)
  1150 {
  1151 	return NULL;
  1152 }
  1153 
  1154 int hid_exit(void)
  1155 {
  1156 	return 0;
  1157 }
  1158 
  1159 }