aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile16
-rw-r--r--include/survive.h11
-rw-r--r--src/os_generic.c336
-rw-r--r--src/os_generic.h76
-rw-r--r--src/survive.c28
-rw-r--r--src/survive_internal.h63
-rw-r--r--src/survive_usb.c189
-rw-r--r--test.c22
8 files changed, 741 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..b213a03
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,16 @@
+all : test
+
+CFLAGS:=-Iinclude -fPIC -g
+LDFLAGS:=-lpthread -lusb-1.0
+
+test : test.c lib/libsurvive.so
+ gcc -o $@ $^ $(LDFLAGS) $(CFLAGS)
+
+lib/libsurvive.so : src/os_generic.o src/survive.o src/survive_usb.o
+ gcc -o $@ $^ $(LDFLAGS) -shared
+
+clean :
+ rm -rf *.o src/*.o *~ src/*~ test libsurvive.so
+
+
+
diff --git a/include/survive.h b/include/survive.h
new file mode 100644
index 0000000..67ab55d
--- /dev/null
+++ b/include/survive.h
@@ -0,0 +1,11 @@
+#ifndef _SURVIVE_H
+#define _SURVIVE_H
+
+struct SurviveContext;
+
+struct SurviveContext * survive_init( );
+void survive_close( struct SurviveContext * ctx );
+int survive_poll();
+
+#endif
+
diff --git a/src/os_generic.c b/src/os_generic.c
new file mode 100644
index 0000000..2429ad9
--- /dev/null
+++ b/src/os_generic.c
@@ -0,0 +1,336 @@
+#include "os_generic.h"
+
+#ifdef USE_WINDOWS
+
+#include <windows.h>
+
+void OGSleep( int is )
+{
+ Sleep( is*1000 );
+}
+
+void OGUSleep( int ius )
+{
+ Sleep( ius/1000 );
+}
+
+double OGGetAbsoluteTime()
+{
+ static LARGE_INTEGER lpf;
+ LARGE_INTEGER li;
+
+ if( !lpf.QuadPart )
+ {
+ QueryPerformanceFrequency( &lpf );
+ }
+
+ QueryPerformanceCounter( &li );
+ return (double)li.QuadPart / (double)lpf.QuadPart;
+}
+
+
+double OGGetFileTime( const char * file )
+{
+ FILETIME ft;
+
+ HANDLE h = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+
+ if( h==INVALID_HANDLE_VALUE )
+ return -1;
+
+ GetFileTime( h, 0, 0, &ft );
+
+ CloseHandle( h );
+
+ return ft.dwHighDateTime + ft.dwLowDateTime;
+}
+
+
+og_thread_t OGCreateThread( void * (routine)( void * ), void * parameter )
+{
+ return (og_thread_t)CreateThread( 0, 0, (LPTHREAD_START_ROUTINE)routine, parameter, 0, 0 );
+}
+
+void * OGJoinThread( og_thread_t ot )
+{
+ WaitForSingleObject( ot, INFINITE );
+ CloseHandle( ot );
+}
+
+void OGCancelThread( og_thread_t ot )
+{
+ CloseHandle( ot );
+}
+
+og_mutex_t OGCreateMutex()
+{
+ return CreateMutex( 0, 0, 0 );
+}
+
+void OGLockMutex( og_mutex_t om )
+{
+ WaitForSingleObject(om, INFINITE);
+}
+
+void OGUnlockMutex( og_mutex_t om )
+{
+ ReleaseMutex(om);
+}
+
+void OGDeleteMutex( og_mutex_t om )
+{
+ CloseHandle( om );
+}
+
+
+
+og_sema_t OGCreateSema()
+{
+ HANDLE sem = CreateSemaphore( 0, 0, 32767, 0 );
+ return (og_sema_t)sem;
+}
+
+int OGGetSema( og_sema_t os )
+{
+ typedef LONG NTSTATUS;
+ HANDLE sem = (HANDLE)os;
+ typedef NTSTATUS (NTAPI *_NtQuerySemaphore)(
+ HANDLE SemaphoreHandle,
+ DWORD SemaphoreInformationClass, /* Would be SEMAPHORE_INFORMATION_CLASS */
+ PVOID SemaphoreInformation, /* but this is to much to dump here */
+ ULONG SemaphoreInformationLength,
+ PULONG ReturnLength OPTIONAL
+ );
+
+ typedef struct _SEMAPHORE_BASIC_INFORMATION {
+ ULONG CurrentCount;
+ ULONG MaximumCount;
+ } SEMAPHORE_BASIC_INFORMATION;
+
+
+ static _NtQuerySemaphore NtQuerySemaphore;
+ SEMAPHORE_BASIC_INFORMATION BasicInfo;
+ NTSTATUS Status;
+
+ if( !NtQuerySemaphore )
+ {
+ NtQuerySemaphore = (_NtQuerySemaphore)GetProcAddress (GetModuleHandle ("ntdll.dll"), "NtQuerySemaphore");
+ if( !NtQuerySemaphore )
+ {
+ return -1;
+ }
+ }
+
+
+ Status = NtQuerySemaphore (sem, 0 /*SemaphoreBasicInformation*/,
+ &BasicInfo, sizeof (SEMAPHORE_BASIC_INFORMATION), NULL);
+
+ if (Status == ERROR_SUCCESS)
+ {
+ return BasicInfo.CurrentCount;
+ }
+
+ return -2;
+}
+
+void OGLockSema( og_sema_t os )
+{
+ WaitForSingleObject( (HANDLE)os, INFINITE );
+}
+
+void OGUnlockSema( og_sema_t os )
+{
+ ReleaseSemaphore( (HANDLE)os, 1, 0 );
+}
+
+void OGDeleteSema( og_sema_t os )
+{
+ CloseHandle( os );
+}
+
+#else
+
+#define _GNU_SOURCE
+
+
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <semaphore.h>
+#include <unistd.h>
+
+
+pthread_mutex_t g_RawMutexStart = PTHREAD_MUTEX_INITIALIZER;
+
+void OGSleep( int is )
+{
+ sleep( is );
+}
+
+void OGUSleep( int ius )
+{
+ usleep( ius );
+}
+
+double OGGetAbsoluteTime()
+{
+ struct timeval tv;
+ gettimeofday( &tv, 0 );
+ return ((double)tv.tv_usec)/1000000. + (tv.tv_sec);
+}
+
+double OGGetFileTime( const char * file )
+{
+ struct stat buff;
+
+ int r = stat( file, &buff );
+
+ if( r < 0 )
+ {
+ return -1;
+ }
+
+ return buff.st_mtime;
+}
+
+
+
+og_thread_t OGCreateThread( void * (routine)( void * ), void * parameter )
+{
+ pthread_t * ret = malloc( sizeof( pthread_t ) );
+ int r = pthread_create( ret, 0, routine, parameter );
+ if( r )
+ {
+ free( ret );
+ return 0;
+ }
+ return (og_thread_t)ret;
+}
+
+void * OGJoinThread( og_thread_t ot )
+{
+ void * retval;
+ if( !ot )
+ {
+ return 0;
+ }
+ pthread_join( *(pthread_t*)ot, &retval );
+ free( ot );
+ return retval;
+}
+
+void OGCancelThread( og_thread_t ot )
+{
+ if( !ot )
+ {
+ return;
+ }
+ pthread_cancel( *(pthread_t*)ot );
+ free( ot );
+}
+
+og_mutex_t OGCreateMutex()
+{
+ pthread_mutexattr_t mta;
+ og_mutex_t r = malloc( sizeof( pthread_mutex_t ) );
+
+ pthread_mutexattr_init(&mta);
+ pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE);
+
+ pthread_mutex_init( (pthread_mutex_t *)r, &mta );
+
+ return r;
+}
+
+void OGLockMutex( og_mutex_t om )
+{
+ if( !om )
+ {
+ return;
+ }
+ pthread_mutex_lock( (pthread_mutex_t*)om );
+}
+
+void OGUnlockMutex( og_mutex_t om )
+{
+ if( !om )
+ {
+ return;
+ }
+ pthread_mutex_unlock( (pthread_mutex_t*)om );
+}
+
+void OGDeleteMutex( og_mutex_t om )
+{
+ if( !om )
+ {
+ return;
+ }
+
+ pthread_mutex_destroy( (pthread_mutex_t*)om );
+ free( om );
+}
+
+
+
+
+og_sema_t OGCreateSema()
+{
+ sem_t * sem = malloc( sizeof( sem_t ) );
+ sem_init( sem, 0, 0 );
+ return (og_sema_t)sem;
+}
+
+int OGGetSema( og_sema_t os )
+{
+ int valp;
+ sem_getvalue( os, &valp );
+ return valp;
+}
+
+
+void OGLockSema( og_sema_t os )
+{
+ sem_wait( os );
+}
+
+void OGUnlockSema( og_sema_t os )
+{
+ sem_post( os );
+}
+
+void OGDeleteSema( og_sema_t os )
+{
+ sem_destroy( os );
+ free(os);
+}
+
+
+
+#endif
+
+//Date Stamp: 2012-02-15
+
+/*
+ Copyright (c) 2011-2012 <>< Charles Lohr
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of this file.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+*/
+
diff --git a/src/os_generic.h b/src/os_generic.h
new file mode 100644
index 0000000..7ce22f2
--- /dev/null
+++ b/src/os_generic.h
@@ -0,0 +1,76 @@
+#ifndef _OS_GENERIC_H
+#define _OS_GENERIC_H
+
+#ifdef WIN32
+#define USE_WINDOWS
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//Things that shouldn't be macro'd
+double OGGetAbsoluteTime();
+void OGSleep( int is );
+void OGUSleep( int ius );
+double OGGetFileTime( const char * file );
+
+//Threads and Mutices
+typedef void* og_thread_t;
+typedef void* og_mutex_t;
+typedef void* og_sema_t;
+
+og_thread_t OGCreateThread( void * (routine)( void * ), void * parameter );
+void * OGJoinThread( og_thread_t ot );
+void OGCancelThread( og_thread_t ot );
+
+//Always a recrusive mutex.
+og_mutex_t OGCreateMutex();
+void OGLockMutex( og_mutex_t om );
+void OGUnlockMutex( og_mutex_t om );
+void OGDeleteMutex( og_mutex_t om );
+
+//Always a semaphore
+og_sema_t OGCreateSema(); //Create a semaphore, comes locked initially. NOTE: Max count is 32767
+void OGLockSema( og_sema_t os );
+int OGGetSema( og_sema_t os ); //if <0 there was a failure.
+void OGUnlockSema( og_sema_t os );
+void OGDeleteSema( og_sema_t os );
+
+#ifdef __cplusplus
+};
+#endif
+
+
+
+#endif
+
+
+//Date Stamp: 2012-02-15
+
+/*
+ NOTE: Portions (namely the top section) are part of headers from other
+ sources.
+
+ Copyright (c) 2011-2012 <>< Charles Lohr
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of this file.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+*/
+
diff --git a/src/survive.c b/src/survive.c
new file mode 100644
index 0000000..0ae5aef
--- /dev/null
+++ b/src/survive.c
@@ -0,0 +1,28 @@
+#include <survive.h>
+#include "survive_internal.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+struct SurviveContext * survive_init( )
+{
+ int r = 0;
+ struct SurviveContext * ret = calloc( 1, sizeof( struct SurviveContext ) );
+ if( r = survive_usb_init( ret ) )
+ {
+ return 0;
+ }
+
+ return ret;
+}
+
+
+void survive_close( struct SurviveContext * ctx )
+{
+ survive_usb_close( ctx );
+}
+
+int survive_poll( struct SurviveContext * ctx )
+{
+ survive_usb_poll( ctx );
+}
+
diff --git a/src/survive_internal.h b/src/survive_internal.h
new file mode 100644
index 0000000..b29b25b
--- /dev/null
+++ b/src/survive_internal.h
@@ -0,0 +1,63 @@
+#ifndef _SURVIVE_INTERNAL_H
+#define _SURVIVE_INTERNAL_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <libusb-1.0/libusb.h>
+
+#define SV_INFO( x... ) printf( x )
+#define SV_ERROR( x... ) fprintf( stderr, x )
+
+//XXX TODO This one needs to be rewritten.
+#define SV_KILL() exit(0)
+
+#define USB_DEV_HMD 0
+#define USB_DEV_LIGHTHOUSE 1
+#define USB_DEV_WATCHMAN1 2
+#define USB_DEV_WATCHMAN2 3
+#define MAX_USB_DEVS 4
+
+
+#define USB_IF_HMD 0
+#define USB_IF_LIGHTHOUSE 1
+#define USB_IF_WATCHMAN1 2
+#define USB_IF_WATCHMAN2 3
+#define USB_IF_LIGHTCAP 4
+#define MAX_INTERFACES 5
+
+#define INTBUFFSIZE 64
+
+struct SurviveContext;
+struct SurviveUSBInterface;
+
+
+//XXX TODO: Roll this into the main structure.
+
+typedef void (*usb_callback)( struct SurviveUSBInterface * ti );
+
+struct SurviveUSBInterface
+{
+ struct libusb_transfer * transfer;
+ struct SurviveContext * ctx;
+ int actual_len;
+ uint8_t buffer[INTBUFFSIZE];
+ usb_callback cb;
+ int which_interface_am_i;
+ const char * hname; //human names
+};
+
+struct SurviveContext
+{
+ struct libusb_context* usbctx;
+ struct libusb_device_handle * udev[MAX_USB_DEVS];
+ struct SurviveUSBInterface uiface[MAX_INTERFACES];
+};
+
+void survive_usb_close( struct SurviveContext * t );
+int survive_usb_init( struct SurviveContext * t );
+int survive_usb_poll( struct SurviveContext * ctx );
+
+#endif
+
+
diff --git a/src/survive_usb.c b/src/survive_usb.c
new file mode 100644
index 0000000..704b4b5
--- /dev/null
+++ b/src/survive_usb.c
@@ -0,0 +1,189 @@
+#include "survive_internal.h"
+#include <libusb-1.0/libusb.h>
+#include <stdio.h>
+
+const short vidpids[] = {
+ 0x0bb4, 0x2c87, 0, //The main HTC HMD device
+ 0x28de, 0x2000, 0, //Valve lighthouse
+ 0x28de, 0x2101, 0, //Valve Watchman
+ 0x28de, 0x2101, 1, //Valve Watchman
+}; //length MAX_USB_INTERFACES*2
+
+const char * devnames[] = {
+ "HMD",
+ "Lighthouse",
+ "Watchman 1",
+ "Watchman 2",
+}; //length MAX_USB_INTERFACES
+
+
+static void handle_transfer(struct libusb_transfer* transfer) {
+ struct SurviveUSBInterface * iface = transfer->user_data;
+
+ if( transfer->status != LIBUSB_TRANSFER_COMPLETED )
+ {
+ SV_ERROR("Transfer problem %d with %s", transfer->status, iface->hname );
+ SV_KILL();
+ return;
+ }
+
+ iface->actual_len = transfer->actual_length;
+ iface->cb( iface );
+
+ if( libusb_submit_transfer(transfer) )
+ {
+ SV_ERROR( "Error resubmitting transfer for %s\n", iface->hname );
+ SV_KILL();
+ }
+}
+
+
+
+static int AttachInterface( struct SurviveContext * t, int which_interface_am_i, libusb_device_handle * devh, int endpoint, usb_callback cb, const char * hname )
+{
+ struct SurviveUSBInterface * iface = &t->uiface[which_interface_am_i];
+ iface->ctx = t;
+ iface->which_interface_am_i = which_interface_am_i;
+ iface->hname = hname;
+ struct libusb_transfer * tx = iface->transfer = libusb_alloc_transfer(0);
+ iface->cb = cb;
+ printf( "%p %d %p %p\n", iface, which_interface_am_i, tx, devh );
+
+ if (!iface->transfer)
+ {
+ SV_ERROR( "Error: failed on libusb_alloc_transfer for %s\n", hname );
+ return 4;
+ }
+
+ libusb_fill_interrupt_transfer( tx, devh, endpoint, iface->buffer, INTBUFFSIZE, handle_transfer, iface, 0);
+
+ int rc = libusb_submit_transfer( tx );
+ if( rc )
+ {
+ SV_ERROR( "Error: Could not submit transfer for %s (Code %d)\n", hname, rc );
+ return 6;
+ }
+
+ return 0;
+}
+
+
+void debug_cb( struct SurviveUSBInterface * si )
+{
+ int i;
+ int len = si->actual_len;
+ printf( "%16s: %d: ", si->hname, len );
+ for( i = 0; i < len; i++ )
+ {
+ printf( "%02x ", si->buffer[i] );
+ }
+ printf( "\n" );
+}
+
+int survive_usb_init( struct SurviveContext * t )
+{
+ int r = libusb_init( &t->usbctx );
+ if( r )
+ {
+ SV_ERROR( "libusb fault %d\n", r );
+ return r;
+ }
+
+ int i;
+ libusb_device** devs;
+ int ret = libusb_get_device_list(t->usbctx, &devs);
+
+ if( ret < 0 )
+ {
+ SV_ERROR( "Couldn't get list of USB devices %d\n", ret );
+ return ret;
+ }
+
+
+ //Open all interfaces.
+ for( i = 0; i < MAX_USB_DEVS; i++ )
+ {
+ libusb_device * d;
+ int vid = vidpids[i*3+0];
+ int pid = vidpids[i*3+1];
+ int which = vidpids[i*3+2];
+
+ int did;
+ for( did = 0; d = devs[did]; did++ )
+ {
+ struct libusb_device_descriptor desc;
+
+ int ret = libusb_get_device_descriptor( d, &desc);
+ if (ret < 0) {
+ continue;
+ }
+
+ if( desc.idVendor == vid && desc.idProduct == pid)
+ {
+ if( which == 0 ) break;
+ which--;
+ }
+ }
+
+ struct libusb_config_descriptor *conf;
+ ret = libusb_get_config_descriptor(d, 0, &conf);
+ if( ret )
+ continue;
+
+ ret = libusb_open(d, &t->udev[i]);
+
+ if( !t->udev[i] || ret )
+ {
+ SV_ERROR( "Error: cannot open device \"%s\" with vid/pid %04x:%04x\n", devnames[i], vid, pid );
+ return -5;
+ }
+
+ libusb_set_auto_detach_kernel_driver( t->udev[i], 1 );
+
+ for (int j = 0; j < conf->bNumInterfaces; j++ )
+ {
+ if( libusb_claim_interface(t->udev[i], j) )
+ {
+ SV_ERROR( "Could not claim interface %d of %s\n", j, devnames[i] );
+ return -9;
+ }
+ }
+
+ SV_INFO( "Successfully enumerated %s (%d, %d)\n", devnames[i], did, conf->bNumInterfaces );
+ }
+ libusb_free_device_list( devs, 1 );
+
+ if( AttachInterface( t, USB_IF_HMD, t->udev[USB_DEV_HMD], 0x81, debug_cb, "Mainboard" ) ) { return -6; }
+ if( AttachInterface( t, USB_IF_LIGHTHOUSE, t->udev[USB_DEV_LIGHTHOUSE], 0x81, debug_cb, "Lighthouse" ) ) { return -6; }
+ if( AttachInterface( t, USB_IF_WATCHMAN1, t->udev[USB_DEV_WATCHMAN1], 0x81, debug_cb, "Watchman 1" ) ) { return -6; }
+ if( AttachInterface( t, USB_IF_WATCHMAN2, t->udev[USB_DEV_WATCHMAN2], 0x81, debug_cb, "Watchman 2" ) ) { return -6; }
+ if( AttachInterface( t, USB_IF_LIGHTCAP, t->udev[USB_DEV_LIGHTHOUSE], 0x82, debug_cb, "Lightcap" ) ) { return -6; }
+
+ SV_INFO( "All devices attached.\n" );
+
+
+ //libUSB initialized. Continue.
+ return 0;
+}
+
+
+void survive_usb_close( struct SurviveContext * t )
+{
+ int i;
+ for( i = 0; i < MAX_USB_DEVS; i++ )
+ {
+ libusb_close( t->udev[i] );
+ }
+ libusb_exit(t->usbctx);
+}
+
+int survive_usb_poll( struct SurviveContext * ctx )
+{
+ int r = libusb_handle_events( ctx->usbctx );
+ if( r )
+ {
+ SV_ERROR( "Libusb poll failed.\n" );
+ }
+ return r;
+}
+
diff --git a/test.c b/test.c
new file mode 100644
index 0000000..b7f9627
--- /dev/null
+++ b/test.c
@@ -0,0 +1,22 @@
+#include <unistd.h>
+#include <stdio.h>
+
+
+#include <survive.h>
+
+int main()
+{
+ struct SurviveContext * ctx = survive_init( &ctx );
+
+ if( !ctx )
+ {
+ fprintf( stderr, "Fatal.\n" );
+ return 1;
+ }
+
+ while(survive_poll(ctx) == 0)
+ {
+
+ }
+}
+