summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2013-03-26 10:14:52 +0100
committerBent Bisballe Nyeng <deva@aasimon.org>2013-03-26 10:14:52 +0100
commit257c0d9b563f91d6613a8dd8c6bb4be0a1366036 (patch)
treec50e75a48654dad22bcb25000691f0b976523019
Initial import
-rw-r--r--Makefile19
-rw-r--r--libusbhp.sln26
-rw-r--r--libusbhp/libusbhp.cc414
-rw-r--r--libusbhp/libusbhp.h64
-rw-r--r--libusbhp/libusbhp.vcxproj88
-rw-r--r--test/test.cc44
-rw-r--r--test/test.vcxproj90
7 files changed, 745 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..594d5ee
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,19 @@
+CFLAGS=-O2
+CFLAGS+=-g -Wall -Werror
+#
+# Detect if we're on windows or linux:
+#
+ifeq ($(OS),Windows_NT)
+ CC=g++
+ CFLAGS+=
+ LIBS+=-static-libgcc -lsetupapi
+ EXE=.exe
+else
+ CC=gcc
+ CFLAGS+=`pkg-config --cflags libudev`
+ LIBS+=`pkg-config --libs libudev`
+ EXE=
+endif
+
+all:
+ ${CC} ${CFLAGS} test/test.c libusbhp/libusbhp.c -o detect${EXE} ${LIBS}
diff --git a/libusbhp.sln b/libusbhp.sln
new file mode 100644
index 0000000..186a75e
--- /dev/null
+++ b/libusbhp.sln
@@ -0,0 +1,26 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Express 2012 for Windows Desktop
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test.vcxproj", "{285305E3-918A-458B-BD54-F2D09953F2D2}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusbhp", "libusbhp\libusbhp.vcxproj", "{1B43450C-2534-451F-985C-2D0BA0EF5A43}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {285305E3-918A-458B-BD54-F2D09953F2D2}.Debug|Win32.ActiveCfg = Debug|Win32
+ {285305E3-918A-458B-BD54-F2D09953F2D2}.Debug|Win32.Build.0 = Debug|Win32
+ {285305E3-918A-458B-BD54-F2D09953F2D2}.Release|Win32.ActiveCfg = Release|Win32
+ {285305E3-918A-458B-BD54-F2D09953F2D2}.Release|Win32.Build.0 = Release|Win32
+ {1B43450C-2534-451F-985C-2D0BA0EF5A43}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1B43450C-2534-451F-985C-2D0BA0EF5A43}.Debug|Win32.Build.0 = Debug|Win32
+ {1B43450C-2534-451F-985C-2D0BA0EF5A43}.Release|Win32.ActiveCfg = Release|Win32
+ {1B43450C-2534-451F-985C-2D0BA0EF5A43}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/libusbhp/libusbhp.cc b/libusbhp/libusbhp.cc
new file mode 100644
index 0000000..63890cb
--- /dev/null
+++ b/libusbhp/libusbhp.cc
@@ -0,0 +1,414 @@
+#include "libusbhp.h"
+
+#ifdef __linux__
+#include <poll.h>
+#include <libudev.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#endif/*__linux__*/
+
+#ifdef _WIN32
+#ifndef WINVER
+#define WINVER 0x502
+#endif
+
+#include <windows.h>
+
+#include <initguid.h>
+#include <usbiodef.h>
+#include <Setupapi.h>
+
+#include <tchar.h>
+#include <conio.h>
+#include <dbt.h>
+#include <stdio.h>
+
+#endif/*_WIN32*/
+
+#ifdef __linux__
+struct dev_list_t {
+ char *path;
+ unsigned short vid;
+ unsigned short pid;
+ struct dev_list_t *next;
+};
+#endif/*__linux__*/
+
+struct libusbhp_t {
+#ifdef __linux__
+ struct udev* hotplug;
+ struct udev_monitor* hotplug_monitor;
+ struct dev_list_t *devlist;
+#endif/*__linux__*/
+#ifdef _WIN32
+ HWND hwnd;
+ HDEVNOTIFY hDeviceNotify;
+ WNDCLASSEX wcex;
+#endif/*_WIN32*/
+ libusbhp_hotplug_cb_fn attach;
+ libusbhp_hotplug_cb_fn detach;
+ void *user_data;
+};
+
+#ifdef __linux__
+static void dev_list_add(struct libusbhp_t *h, const char *path,
+ unsigned short vid, unsigned short pid)
+{
+ struct dev_list_t *dev =
+ (struct dev_list_t*)malloc(sizeof(struct dev_list_t));
+ dev->path = strdup(path);
+ dev->vid = vid;
+ dev->pid = pid;
+ dev->next = NULL;
+
+ struct dev_list_t *p = h->devlist;
+ if(!p) {
+ h->devlist = dev;
+ return;
+ }
+
+ while(p->next) {
+ p = p->next;
+ }
+
+ p->next = dev;
+}
+
+static int dev_list_remove(struct libusbhp_t *h, const char *path)
+{
+ struct dev_list_t *p = h->devlist;
+ if(!p) return;
+
+ if(!strcmp(p->path, path)) {
+ h->devlist = p->next;
+ free(p->path);
+ free(p);
+ return;
+ }
+
+ while(p->next) {
+ if(!strcmp(p->next->path, path)) {
+ struct dev_list_t *pp = p->next;
+ p->next = pp->next;
+ free(pp->path);
+ free(pp->next);
+ free(pp);
+ return 0;
+ }
+ p = p->next;
+ }
+
+ // Not found
+ return 1;
+}
+
+static int dev_list_find(struct libusbhp_t *h, const char *path,
+ unsigned short *vid, unsigned short *pid)
+{
+ struct dev_list_t *p = h->devlist;
+ while(p) {
+ if(!strcmp(p->path, path)) {
+ *vid = p->vid;
+ *pid = p->pid;
+ return 0;
+ }
+ p = p->next;
+ }
+
+ // Not found
+ return 1;
+}
+#endif/*__linux__*/
+
+#ifdef _WIN32
+LRESULT CALLBACK WinProcCallback(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ struct libusbhp_t *h = (struct libusbhp_t*)GetWindowLong(hwnd, GWL_USERDATA);
+
+ switch(msg) {
+ case WM_DEVICECHANGE:
+ {
+ PDEV_BROADCAST_HDR phdr = (PDEV_BROADCAST_HDR)lp;
+
+ if(!phdr || phdr->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE) break;
+
+ PDEV_BROADCAST_DEVICEINTERFACE devif =
+ (PDEV_BROADCAST_DEVICEINTERFACE)lp;
+
+ HDEVINFO devinfolist = SetupDiCreateDeviceInfoList(NULL, NULL);
+
+ SP_DEVICE_INTERFACE_DATA devifdata;
+ memset(&devifdata, 0, sizeof(devifdata));
+ devifdata.cbSize = sizeof(devifdata);
+ BOOL b = SetupDiOpenDeviceInterface(devinfolist, devif->dbcc_name, 0,
+ &devifdata);
+
+ DWORD required;
+ SP_DEVICE_INTERFACE_DETAIL_DATA devdetaildata;
+ memset(&devdetaildata, 0, sizeof(devdetaildata));
+ devdetaildata.cbSize = sizeof(devdetaildata);
+
+ SP_DEVINFO_DATA devinfodata;
+ memset(&devinfodata, 0, sizeof(devinfodata));
+ devinfodata.cbSize = sizeof(devinfodata);
+ b = SetupDiGetDeviceInterfaceDetail(devinfolist, &devifdata,
+ &devdetaildata,
+ sizeof(devdetaildata),
+ &required, &devinfodata);
+
+ TCHAR deviceidw[1024];
+ b = SetupDiGetDeviceInstanceIdW(devinfolist, &devinfodata, deviceidw,
+ sizeof(deviceidw), NULL);
+
+ char deviceid[1024];
+ size_t sz;
+ wcstombs_s(&sz, deviceid, deviceidw, sizeof(deviceid) - 1);
+
+ char *vid = strstr(deviceid, "VID_");
+ if(vid != NULL) vid += 4;
+
+ char *pid = strstr(deviceid, "PID_");
+ if(pid != NULL) pid += 4;
+
+ struct libusbhp_device_t *device = NULL;
+
+ if(pid || vid) {
+ device =
+ (struct libusbhp_device_t*)malloc(sizeof(struct libusbhp_device_t));
+ }
+
+ if(pid) {
+ pid[4] = '\0';
+ device->idProduct = (unsigned short)strtol(pid, NULL, 16);
+ }
+
+ if(vid) {
+ vid[4] = '\0';
+ device->idVendor = (unsigned short)strtol(vid, NULL, 16);
+ }
+
+ switch(wp) {
+ case DBT_DEVICEARRIVAL:
+ if(h->attach) h->attach(device, h->user_data);
+ break;
+ case DBT_DEVICEREMOVECOMPLETE:
+ if(h->detach) h->detach(device, h->user_data);
+ break;
+ case DBT_DEVNODES_CHANGED:
+ default:
+ break;
+ }
+
+ if(device) free(device);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return DefWindowProc(hwnd, msg, wp, lp);
+}
+#endif/*OS_WINDOWS*/
+
+EXPORT
+int libusbhp_init(struct libusbhp_t **handle)
+{
+ struct libusbhp_t *h = (struct libusbhp_t *)malloc(sizeof(struct libusbhp_t));
+
+ h->attach = NULL;
+ h->detach = NULL;
+ h->user_data = NULL;
+
+#ifdef __linux__
+ h->devlist = NULL;
+
+ // create the udev object
+ h->hotplug = udev_new();
+ if(!h->hotplug)
+ {
+ printf("Cannot create udev object\n");
+ free(h);
+ return 1;
+ }
+
+ // create the udev monitor
+ h->hotplug_monitor = udev_monitor_new_from_netlink(h->hotplug, "udev");
+
+ // start receiving hotplug events
+ udev_monitor_filter_add_match_subsystem_devtype(h->hotplug_monitor,
+ "usb", "usb_device");
+ udev_monitor_enable_receiving(h->hotplug_monitor);
+
+ struct udev_enumerate *de = udev_enumerate_new (h->hotplug);
+ udev_enumerate_add_match_subsystem(de, "usb");
+ udev_enumerate_scan_devices(de);
+
+ struct udev_list_entry *lst = udev_enumerate_get_list_entry(de);
+ while(lst) {
+ struct udev_device *dev =
+ udev_device_new_from_syspath(h->hotplug,
+ udev_list_entry_get_name(lst));
+
+ if(udev_device_get_devnode(dev)) {
+ unsigned short idVendor =
+ strtol(udev_device_get_sysattr_value(dev, "idVendor"), NULL, 16);
+ unsigned short idProduct =
+ strtol(udev_device_get_sysattr_value(dev, "idProduct"), NULL, 16);
+
+ dev_list_add(h, udev_device_get_devnode(dev), idVendor, idProduct);
+ }
+
+ udev_device_unref(dev);
+
+ lst = udev_list_entry_get_next(lst);
+ }
+
+ udev_enumerate_unref(de);
+
+#endif/*__linux__*/
+
+#ifdef _WIN32
+ memset(&h->wcex, 0, sizeof(h->wcex));
+ h->wcex.cbSize = sizeof(WNDCLASSEX);
+ h->wcex.lpfnWndProc = WinProcCallback;
+ h->wcex.hInstance = GetModuleHandle(NULL);
+ h->wcex.lpszClassName = TEXT("UsbHotplugClass");
+ h->wcex.cbWndExtra = sizeof(struct libusbhp_t*); // Size of data.
+
+ RegisterClassEx(&h->wcex);
+
+ h->hwnd =
+ CreateWindowEx(0, h->wcex.lpszClassName, TEXT("UsbHotplug"), 0, 0, 0, 0,
+ 0, 0, NULL, GetModuleHandle(NULL), NULL);
+
+ SetWindowLong(h->hwnd, GWL_USERDATA, (LONG)h);
+
+
+ DEV_BROADCAST_DEVICEINTERFACE *filter =
+ (DEV_BROADCAST_DEVICEINTERFACE*)malloc(sizeof(DEV_BROADCAST_DEVICEINTERFACE));
+
+ memset(filter, 0, sizeof(DEV_BROADCAST_DEVICEINTERFACE));
+ filter->dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
+ filter->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
+ filter->dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE;
+
+ h->hDeviceNotify =
+ RegisterDeviceNotification(h->hwnd, filter, DEVICE_NOTIFY_WINDOW_HANDLE);
+
+ if(h->hDeviceNotify == 0) {
+ //printf("RegisterDeviceNotification error\n");
+ free(h);
+ return 1;
+ }
+#endif/*_WIN32*/
+
+ *handle = h;
+ return 0;
+}
+
+EXPORT
+void libusbhp_exit(struct libusbhp_t *h)
+{
+#ifdef __linux__
+ // destroy the udev monitor
+ udev_monitor_unref(h->hotplug_monitor);
+
+ // destroy the udev object
+ udev_unref(h->hotplug);
+#endif/*__linux__*/
+
+#ifdef _WIN32
+ UnregisterDeviceNotification(h->hDeviceNotify);
+ DestroyWindow(h->hwnd);
+ UnregisterClass(h->wcex.lpszClassName, h->wcex.hInstance);
+#endif/*_WIN32*/
+
+ free(h);
+}
+
+EXPORT
+int libusbhp_handle_events_timeout(struct libusbhp_t *h, struct timeval *tv)
+{
+ int ms = tv->tv_sec * 1000 + tv->tv_usec / 1000;
+
+#ifdef __linux__
+ // create the poll item
+ struct pollfd items[1];
+ items[0].fd = udev_monitor_get_fd(h->hotplug_monitor);
+ items[0].events = POLLIN;
+ items[0].revents = 0;
+
+ // while there are hotplug events to process
+ while(poll(items, 1, ms) > 0) {
+ // receive the relevant device
+ struct udev_device* dev = udev_monitor_receive_device(h->hotplug_monitor);
+ if(!dev) {
+ // error receiving device, skip it
+ continue;
+ }
+
+ if(!strcmp(udev_device_get_action(dev), "add")) {
+ struct libusbhp_device_t device;
+
+ device.idVendor =
+ strtol(udev_device_get_sysattr_value(dev, "idVendor"), NULL, 16);
+ device.idProduct =
+ strtol(udev_device_get_sysattr_value(dev, "idProduct"), NULL, 16);
+
+ dev_list_add(h, udev_device_get_devnode(dev),
+ device.idVendor, device.idProduct);
+
+ if(h->attach) h->attach(&device, h->user_data);
+ }
+
+ if(!strcmp(udev_device_get_action(dev), "remove")) {
+ struct libusbhp_device_t device;
+
+ int res = dev_list_find(h, udev_device_get_devnode(dev),
+ &device.idVendor, &device.idProduct);
+
+ if(res) {
+ if(h->detach) h->detach(NULL, h->user_data);
+ } else {
+ dev_list_remove(h, udev_device_get_devnode(dev));
+ if(h->detach) h->detach(&device, h->user_data);
+ }
+ }
+
+ // destroy the relevant device
+ udev_device_unref(dev);
+
+ // clear the revents
+ items[0].revents = 0;
+ }
+#endif/*__linux__*/
+
+#ifdef _WIN32
+ UINT_PTR timer = SetTimer(h->hwnd, 0, ms, NULL);
+
+ MSG msg;
+ int ret = GetMessage(&msg, NULL, 0, 0);
+
+ if(ret <= 0) return 0;
+
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+
+ KillTimer(h->hwnd, timer);
+#endif/*_WIN32*/
+
+ return 0;
+}
+
+EXPORT
+void libusbhp_register_hotplug_listeners(struct libusbhp_t *handle,
+ libusbhp_hotplug_cb_fn connected_cb,
+ libusbhp_hotplug_cb_fn disconnected_cb,
+ void *user_data)
+{
+ handle->attach = connected_cb;
+ handle->detach = disconnected_cb;
+ handle->user_data = user_data;
+}
diff --git a/libusbhp/libusbhp.h b/libusbhp/libusbhp.h
new file mode 100644
index 0000000..46558ee
--- /dev/null
+++ b/libusbhp/libusbhp.h
@@ -0,0 +1,64 @@
+#ifndef __LIBUSBHP_H__
+#define __LIBUSBHP_H__
+
+#ifdef WIN32
+#ifdef BUILD_DLL
+/* DLL export */
+#define EXPORT __declspec(dllexport)
+#else
+/* EXE import */
+#define EXPORT __declspec(dllimport)
+#endif
+#include <Winsock2.h>
+#else
+#define EXPORT
+#include <sys/time.h>
+#endif
+
+struct libusbhp_t;
+
+struct libusbhp_device_t {
+ unsigned short idVendor;
+ unsigned short idProduct;
+};
+
+typedef void (*libusbhp_hotplug_cb_fn)(struct libusbhp_device_t *device,
+ void *user_data);
+
+EXPORT
+ int libusbhp_init(struct libusbhp_t **handle);
+
+EXPORT
+ void libusbhp_exit(struct libusbhp_t *handle);
+
+EXPORT
+ int libusbhp_handle_events_timeout(struct libusbhp_t *handle, struct timeval *tv);
+
+EXPORT
+ void libusbhp_register_hotplug_listeners(struct libusbhp_t *handle,
+ libusbhp_hotplug_cb_fn connected_cb,
+ libusbhp_hotplug_cb_fn disconnected_cb,
+ void *user_data);
+
+
+/***
+// Libusbx implementation:
+
+typedef void LIBUSB_CALL (*libusb_hotplug_cb_fn)(struct libusb_device *device,
+ void *user_data);
+
+int LIBUSB_CALL libusb_init(libusb_context **ctx);
+void LIBUSB_CALL libusb_exit(libusb_context *ctx);
+void LIBUSB_CALL libusb_set_debug(libusb_context *ctx, int level);
+const char * LIBUSB_CALL libusb_strerror(enum libusb_error errcode);
+const struct libusb_version * LIBUSB_CALL libusb_getversion(void);
+
+void LIBUSB_CALL libusb_register_hotplug_listeners(libusb_context *ctx,
+ libusb_hotplug_cb_fn connected_cb,
+ libusb_hotplug_cb_fn disconnected_cb, void *user_data);
+void LIBUSB_CALL libusb_unregister_hotplug_listeners(libusb_context *ctx);
+int LIBUSB_CALL libusb_get_status(libusb_device *dev);
+
+ ***/
+
+#endif/*__LIBUSBHP_H__*/
diff --git a/libusbhp/libusbhp.vcxproj b/libusbhp/libusbhp.vcxproj
new file mode 100644
index 0000000..fd5527c
--- /dev/null
+++ b/libusbhp/libusbhp.vcxproj
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="libusbhp.cc" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="libusbhp.h" />
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{1B43450C-2534-451F-985C-2D0BA0EF5A43}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>libusbhotplug</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v110</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v110</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBUSBHOTPLUG_EXPORTS;BUILD_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBUSBHOTPLUG_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/test/test.cc b/test/test.cc
new file mode 100644
index 0000000..4a6e3ee
--- /dev/null
+++ b/test/test.cc
@@ -0,0 +1,44 @@
+#include <stdio.h>
+#include <time.h>
+
+#include <libusbhp.h>
+
+static void attach_fn(struct libusbhp_device_t *device, void *user_data)
+{
+ printf("attach\n");
+ if(device) printf(" (%04x/%04x)\n", device->idVendor, device->idProduct);
+}
+
+static void detach_fn(struct libusbhp_device_t *device, void *user_data)
+{
+ printf("detach\n");
+ if(device) printf(" (%04x/%04x)\n", device->idVendor, device->idProduct);
+}
+
+int main(int args, char* argv[])
+{
+ struct libusbhp_t *handle;
+
+ int ret = libusbhp_init(&handle);
+ if(ret != 0) {
+ printf("Could not initialise handle.\n");
+ return 1;
+ }
+
+ libusbhp_register_hotplug_listeners(handle, attach_fn, detach_fn, NULL);
+
+ // 100ms timeout
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000;
+
+ while(1) {
+ int ret = libusbhp_handle_events_timeout(handle, &tv);
+ if(ret) printf("handle_events failed [%d]...\n", ret);
+ printf("loop\n");
+ }
+
+ libusbhp_exit(handle);
+
+ return 0;
+}
diff --git a/test/test.vcxproj b/test/test.vcxproj
new file mode 100644
index 0000000..be61eef
--- /dev/null
+++ b/test/test.vcxproj
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="test.cc" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\libusbhp\libusbhp.vcxproj">
+ <Project>{1b43450c-2534-451f-985c-2d0ba0ef5a43}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{285305E3-918A-458B-BD54-F2D09953F2D2}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>test</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v110</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v110</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\libusbhp;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file