From 8388ca81fbc6c0a840e81f6fd805b897d378556b Mon Sep 17 00:00:00 2001 From: cnlohr Date: Tue, 29 Nov 2016 03:03:34 -0500 Subject: Add a basic vive driver. Gotta figure out how to turn it on. --- src/survive_usb.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 src/survive_usb.c (limited to 'src/survive_usb.c') 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 +#include + +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; +} + -- cgit v1.2.3