diff options
author | Pete Batard <pbatard@gmail.com> | 2010-03-06 00:15:19 +0000 |
---|---|---|
committer | Pete Batard <pbatard@gmail.com> | 2010-03-06 00:15:19 +0000 |
commit | d4a736d822a6a7e8494f4055e77c188c53c1fa2f (patch) | |
tree | 9fdf7abab25d45406ac13983769b02ed9d6610f8 | |
parent | d7aabf0bb0f418a68bf8ac857f7bfc122fd46a67 (diff) | |
download | libusb-d4a736d822a6a7e8494f4055e77c188c53c1fa2f.tar.gz |
merged r197a161
-rw-r--r-- | configure.ac | 8 | ||||
-rw-r--r-- | examples/lsusb.dsp | 6 | ||||
-rw-r--r-- | examples/lsusb_2008.vcproj | 4 | ||||
-rw-r--r-- | examples/xusb.c | 51 | ||||
-rw-r--r-- | examples/xusb.dsp | 6 | ||||
-rw-r--r-- | examples/xusb_2008.vcproj | 4 | ||||
-rw-r--r-- | libusb-dll_2005.vcproj | 4 | ||||
-rw-r--r-- | libusb-dll_2008.vcproj | 14 | ||||
-rw-r--r-- | libusb-static_2005.vcproj | 4 | ||||
-rw-r--r-- | libusb-static_2008.vcproj | 14 | ||||
-rw-r--r-- | libusb/Makefile.am | 8 | ||||
-rw-r--r-- | libusb/core.c | 79 | ||||
-rw-r--r-- | libusb/io.c | 2 | ||||
-rw-r--r-- | libusb/libusb.h | 2 | ||||
-rw-r--r-- | libusb/libusbi.h | 4 | ||||
-rw-r--r-- | libusb/os/poll_posix.h (renamed from libusb/os/unistd_posix.h) | 6 | ||||
-rw-r--r-- | libusb/os/poll_windows.c (renamed from libusb/os/windows_compat.c) | 206 | ||||
-rw-r--r-- | libusb/os/poll_windows.h (renamed from libusb/os/windows_compat.h) | 2 | ||||
-rw-r--r-- | libusb/os/sources | 2 | ||||
-rw-r--r-- | libusb/os/threads_windows.c | 4 | ||||
-rw-r--r-- | libusb/os/windows_usb.c | 61 | ||||
-rw-r--r-- | libusb/os/windows_usb.h | 105 | ||||
-rw-r--r-- | libusb_dll.dsp | 12 | ||||
-rw-r--r-- | libusb_static.dsp | 8 | ||||
-rw-r--r-- | msvc/config.h | 5 |
25 files changed, 400 insertions, 221 deletions
diff --git a/configure.ac b/configure.ac index 8d3ba9d..ac08e0b 100644 --- a/configure.ac +++ b/configure.ac @@ -43,17 +43,19 @@ case $host in threads="windows" LIBS="-lsetupapi -lole32" AM_CFLAGS="-Wshadow" - AM_LDFLAGS="-no-undefined" + AM_LDFLAGS="-no-undefined -avoid-version" + AC_CHECK_TOOL(RC, windres, no) ;; *-cygwin*) AC_DEFINE(OS_WINDOWS, [], [Windows backend]) AC_SUBST(OS_WINDOWS) AC_MSG_RESULT([Windows]) backend="windows" - threads="posix" + threads="posix" LIBS="-lpthread -lsetupapi -lole32" AM_CFLAGS="" - AM_LDFLAGS="-no-undefined" + AM_LDFLAGS="-no-undefined -avoid-version" + AC_CHECK_TOOL(RC, windres, no) ;; *) AC_MSG_ERROR([unsupported operating system]) diff --git a/examples/lsusb.dsp b/examples/lsusb.dsp index b598ffa..bf16c4e 100644 --- a/examples/lsusb.dsp +++ b/examples/lsusb.dsp @@ -50,7 +50,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib "D:/Program Files/Microsoft SDK/Lib/setupapi.lib" /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setupapi.lib /nologo /subsystem:console /machine:I386 !ELSEIF "$(CFG)" == "lsusb - Win32 Debug" @@ -71,10 +71,10 @@ LINK32=link.exe # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo -# ADD BSC32 /nologo /n "../Win32/Debug/dll/core.sbr" "../Win32/Debug/dll/descriptor.sbr" "../Win32/Debug/dll/io.sbr" "../Win32/Debug/dll/sync.sbr" "../Win32/Debug/dll/windows_compat.sbr" "../Win32/Debug/dll/windows_usb.sbr" +# ADD BSC32 /nologo /n "../Win32/Debug/dll/core.sbr" "../Win32/Debug/dll/descriptor.sbr" "../Win32/Debug/dll/io.sbr" "../Win32/Debug/dll/sync.sbr" "../Win32/Debug/dll/poll_windows.sbr" "../Win32/Debug/dll/windows_usb.sbr" LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib "D:/Program Files/Microsoft SDK/Lib/setupapi.lib" /nologo /subsystem:console /debug /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setupapi.lib /nologo /subsystem:console /debug /machine:I386 # SUBTRACT LINK32 /pdb:none !ENDIF diff --git a/examples/lsusb_2008.vcproj b/examples/lsusb_2008.vcproj index 168cf3f..f56019c 100644 --- a/examples/lsusb_2008.vcproj +++ b/examples/lsusb_2008.vcproj @@ -53,6 +53,7 @@ UsePrecompiledHeader="0" WarningLevel="3" DebugInformationFormat="4" + CallingConvention="2" /> <Tool Name="VCManagedResourceCompilerTool" @@ -130,6 +131,7 @@ UsePrecompiledHeader="0" WarningLevel="3" DebugInformationFormat="3" + CallingConvention="2" /> <Tool Name="VCManagedResourceCompilerTool" @@ -207,6 +209,7 @@ UsePrecompiledHeader="0" WarningLevel="3" DebugInformationFormat="3" + CallingConvention="2" /> <Tool Name="VCManagedResourceCompilerTool" @@ -287,6 +290,7 @@ UsePrecompiledHeader="0" WarningLevel="3" DebugInformationFormat="3" + CallingConvention="2" /> <Tool Name="VCManagedResourceCompilerTool" diff --git a/examples/xusb.c b/examples/xusb.c index 5000059..6bc3b4f 100644 --- a/examples/xusb.c +++ b/examples/xusb.c @@ -191,7 +191,7 @@ int set_xbox_actuators(libusb_device_handle *handle, uint8_t left, uint8_t right output_report[5] = right; CALL_CHECK(libusb_control_transfer(handle, LIBUSB_ENDPOINT_OUT|LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE, - HID_SET_REPORT, (HID_REPORT_TYPE_OUTPUT<<8)|0x00, 0, output_report,06, 1000)); + HID_SET_REPORT, (HID_REPORT_TYPE_OUTPUT<<8)|0x00, 0, output_report, 06, 1000)); return 0; } @@ -247,7 +247,7 @@ int send_mass_storage_command(libusb_device_handle *handle, uint8_t endpoint, ui return -1; } - printf(" sent %d CDB bytes (%d)\n", cdb_len,sizeof(cbw)); + printf(" sent %d CDB bytes\n", cdb_len); return 0; } @@ -423,6 +423,7 @@ int test_mass_storage(libusb_device_handle *handle, uint8_t endpoint_in, uint8_t int get_hid_input_record_size(uint8_t *hid_report_descriptor, int size) { uint8_t i, j = 0; + uint8_t offset; int record_size[2] = {0, 0}; int nb_bits = 0, nb_items = 0; bool found_bits, found_items, found_direction; @@ -430,7 +431,10 @@ int get_hid_input_record_size(uint8_t *hid_report_descriptor, int size) found_bits = false; found_items = false; found_direction = false; - for (i = hid_report_descriptor[0]+1; i < size; i += 2) { + for (i = hid_report_descriptor[0]+1; i < size; i += offset) { + offset = (hid_report_descriptor[i]&0x03) + 1; + if (offset == 4) + offset = 5; switch (hid_report_descriptor[i]) { case 0x75: // bitsize nb_bits = hid_report_descriptor[i+1]; @@ -476,15 +480,10 @@ int test_hid(libusb_device_handle *handle, uint8_t endpoint_in) LIBUSB_REQUEST_GET_DESCRIPTOR, LIBUSB_DT_REPORT<<8, 0, hid_report_descriptor, 256, 1000); if (r < 0) { printf("failed\n"); + return -1; } else { display_buffer_hex(hid_report_descriptor, r); size = get_hid_input_record_size(hid_report_descriptor, r); - -#if !defined(OS_WINDOWS) - // TOFIX: get_hid_input_record_size still needs some improvements on Linux - if ((VID == 0x045E) && (PID = 0x0008)) - size++; -#endif printf("\n Input Report Length: %d\n", size); } @@ -498,10 +497,19 @@ int test_hid(libusb_device_handle *handle, uint8_t endpoint_in) HID_GET_REPORT, (HID_REPORT_TYPE_FEATURE<<8)|0, 0, input_report, (uint16_t)size, 5000); if (r >= 0) { display_buffer_hex(input_report, size); - } else if (r == LIBUSB_ERROR_NOT_FOUND) { - printf(" No Feature Report available for this device\n"); } else { - printf(" Error: %s\n", libusb_strerror(r)); + switch(r) { + case LIBUSB_ERROR_NOT_FOUND: + printf(" No Feature Report available for this device\n"); + break; + case LIBUSB_ERROR_PIPE: + printf(" Detected stall - resetting pipe...\n"); + libusb_clear_halt(handle, 0); + break; + default: + printf(" Error: %s\n", libusb_strerror(r)); + break; + } } printf("\nReading Input Report...\n"); @@ -514,6 +522,10 @@ int test_hid(libusb_device_handle *handle, uint8_t endpoint_in) case LIBUSB_ERROR_TIMEOUT: printf(" Timeout! Please make sure you act on the device within the 5 seconds allocated...\n"); break; + case LIBUSB_ERROR_PIPE: + printf(" Detected stall - resetting pipe...\n"); + libusb_clear_halt(handle, 0); + break; default: printf(" Error: %s\n", libusb_strerror(r)); break; @@ -521,8 +533,8 @@ int test_hid(libusb_device_handle *handle, uint8_t endpoint_in) } // Attempt a bulk read from endpoint 0 (this should just return a raw input report) - printf("\nTesting bulk read using endpoint %02X...\n", endpoint_in); - r = libusb_bulk_transfer(handle, endpoint_in, input_report, size, &size, 5000); + printf("\nTesting interrupt read using endpoint %02X...\n", endpoint_in); + r = libusb_interrupt_transfer(handle, endpoint_in, input_report, size, &size, 5000); if (r >= 0) { display_buffer_hex(input_report, size); } else { @@ -541,6 +553,9 @@ int test_device(uint16_t vid, uint16_t pid) const struct libusb_endpoint_descriptor *endpoint; int i, j, k, r; int iface, nb_ifaces, nb_strings; +#ifndef OS_WINDOWS + int iface_detached = -1; +#endif int test_scsi = 0; struct libusb_device_descriptor dev_desc; char string[128]; @@ -612,6 +627,7 @@ int test_device(uint16_t vid, uint16_t pid) // Maybe we need to detach the driver perr(" Failed. Trying to detach driver...\n"); libusb_detach_kernel_driver(handle, iface); + iface_detached = iface; printf(" Claiming interface again...\n"); libusb_claim_interface(handle, iface); } else { @@ -656,6 +672,13 @@ int test_device(uint16_t vid, uint16_t pid) libusb_release_interface(handle, iface); } +#ifndef OS_WINDOWS + if (iface_detached >= 0) { + printf("Re-attaching kernel driver...\n"); + libusb_attach_kernel_driver(handle, iface_detached); + } +#endif + printf("Closing device...\n"); libusb_close(handle); diff --git a/examples/xusb.dsp b/examples/xusb.dsp index b47b8c0..9bd5e38 100644 --- a/examples/xusb.dsp +++ b/examples/xusb.dsp @@ -50,7 +50,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib "D:/Program Files/Microsoft SDK/Lib/setupapi.lib" /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setupapi.lib /nologo /subsystem:console /machine:I386 !ELSEIF "$(CFG)" == "xusb - Win32 Debug" @@ -71,10 +71,10 @@ LINK32=link.exe # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo -# ADD BSC32 /nologo /n "../Win32/Debug/dll/core.sbr" "../Win32/Debug/dll/descriptor.sbr" "../Win32/Debug/dll/io.sbr" "../Win32/Debug/dll/sync.sbr" "../Win32/Debug/dll/windows_compat.sbr" "../Win32/Debug/dll/windows_usb.sbr" +# ADD BSC32 /nologo /n "../Win32/Debug/dll/core.sbr" "../Win32/Debug/dll/descriptor.sbr" "../Win32/Debug/dll/io.sbr" "../Win32/Debug/dll/sync.sbr" "../Win32/Debug/dll/poll_windows.sbr" "../Win32/Debug/dll/windows_usb.sbr" LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib "D:/Program Files/Microsoft SDK/Lib/setupapi.lib" /nologo /subsystem:console /debug /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setupapi.lib /nologo /subsystem:console /debug /machine:I386 !ENDIF diff --git a/examples/xusb_2008.vcproj b/examples/xusb_2008.vcproj index 224249a..f604ecc 100644 --- a/examples/xusb_2008.vcproj +++ b/examples/xusb_2008.vcproj @@ -53,6 +53,7 @@ UsePrecompiledHeader="0" WarningLevel="3" DebugInformationFormat="4" + CallingConvention="2" /> <Tool Name="VCManagedResourceCompilerTool" @@ -130,6 +131,7 @@ UsePrecompiledHeader="0" WarningLevel="3" DebugInformationFormat="3" + CallingConvention="2" /> <Tool Name="VCManagedResourceCompilerTool" @@ -207,6 +209,7 @@ UsePrecompiledHeader="0" WarningLevel="3" DebugInformationFormat="3" + CallingConvention="2" /> <Tool Name="VCManagedResourceCompilerTool" @@ -287,6 +290,7 @@ UsePrecompiledHeader="0" WarningLevel="3" DebugInformationFormat="3" + CallingConvention="2" /> <Tool Name="VCManagedResourceCompilerTool" diff --git a/libusb-dll_2005.vcproj b/libusb-dll_2005.vcproj index da05bd8..09271b3 100644 --- a/libusb-dll_2005.vcproj +++ b/libusb-dll_2005.vcproj @@ -403,7 +403,7 @@ </File> <File - RelativePath=".\libusb\os\windows_compat.c" + RelativePath=".\libusb\os\poll_windows.c" > </File> <File @@ -433,7 +433,7 @@ > </File> <File - RelativePath=".\libusb\os\windows_compat.h" + RelativePath=".\libusb\os\poll_windows.h" > </File> <File diff --git a/libusb-dll_2008.vcproj b/libusb-dll_2008.vcproj index b08d795..a31fdee 100644 --- a/libusb-dll_2008.vcproj +++ b/libusb-dll_2008.vcproj @@ -50,6 +50,7 @@ RuntimeLibrary="1" WarningLevel="3" DebugInformationFormat="4" + CallingConvention="2" /> <Tool Name="VCManagedResourceCompilerTool" @@ -123,6 +124,7 @@ RuntimeLibrary="1" WarningLevel="3" DebugInformationFormat="3" + CallingConvention="2" /> <Tool Name="VCManagedResourceCompilerTool" @@ -196,6 +198,7 @@ EnableFunctionLevelLinking="true" WarningLevel="3" DebugInformationFormat="3" + CallingConvention="2" /> <Tool Name="VCManagedResourceCompilerTool" @@ -269,6 +272,7 @@ EnableFunctionLevelLinking="true" WarningLevel="3" DebugInformationFormat="3" + CallingConvention="2" /> <Tool Name="VCManagedResourceCompilerTool" @@ -330,15 +334,15 @@ > </File> <File - RelativePath=".\libusb\sync.c" + RelativePath=".\libusb\os\poll_windows.c" > </File> <File - RelativePath=".\libusb\os\threads_windows.c" + RelativePath=".\libusb\sync.c" > </File> <File - RelativePath=".\libusb\os\windows_compat.c" + RelativePath=".\libusb\os\threads_windows.c" > </File> <File @@ -364,11 +368,11 @@ > </File> <File - RelativePath=".\libusb\os\threads_windows.h" + RelativePath=".\libusb\os\poll_windows.h" > </File> <File - RelativePath=".\libusb\os\windows_compat.h" + RelativePath=".\libusb\os\threads_windows.h" > </File> <File diff --git a/libusb-static_2005.vcproj b/libusb-static_2005.vcproj index afd646e..6b505ba 100644 --- a/libusb-static_2005.vcproj +++ b/libusb-static_2005.vcproj @@ -302,7 +302,7 @@ > </File> <File - RelativePath=".\libusb\os\windows_compat.c" + RelativePath=".\libusb\os\poll_windows.c" > </File> <File @@ -332,7 +332,7 @@ > </File> <File - RelativePath=".\libusb\os\windows_compat.h" + RelativePath=".\libusb\os\poll_windows.h" > </File> <File diff --git a/libusb-static_2008.vcproj b/libusb-static_2008.vcproj index 70ecca8..98f37c7 100644 --- a/libusb-static_2008.vcproj +++ b/libusb-static_2008.vcproj @@ -50,6 +50,7 @@ RuntimeLibrary="1" WarningLevel="3" DebugInformationFormat="4" + CallingConvention="2" /> <Tool Name="VCManagedResourceCompilerTool" @@ -113,6 +114,7 @@ RuntimeLibrary="1" WarningLevel="3" DebugInformationFormat="3" + CallingConvention="2" /> <Tool Name="VCManagedResourceCompilerTool" @@ -176,6 +178,7 @@ EnableFunctionLevelLinking="true" WarningLevel="3" DebugInformationFormat="3" + CallingConvention="2" /> <Tool Name="VCManagedResourceCompilerTool" @@ -240,6 +243,7 @@ EnableFunctionLevelLinking="true" WarningLevel="3" DebugInformationFormat="3" + CallingConvention="2" /> <Tool Name="VCManagedResourceCompilerTool" @@ -292,15 +296,15 @@ > </File> <File - RelativePath=".\libusb\sync.c" + RelativePath=".\libusb\os\poll_windows.c" > </File> <File - RelativePath=".\libusb\os\threads_windows.c" + RelativePath=".\libusb\sync.c" > </File> <File - RelativePath=".\libusb\os\windows_compat.c" + RelativePath=".\libusb\os\threads_windows.c" > </File> <File @@ -326,11 +330,11 @@ > </File> <File - RelativePath=".\libusb\os\threads_windows.h" + RelativePath=".\libusb\os\poll_windows.h" > </File> <File - RelativePath=".\libusb\os\windows_compat.h" + RelativePath=".\libusb\os\threads_windows.h" > </File> <File diff --git a/libusb/Makefile.am b/libusb/Makefile.am index e8de9f5..6152daa 100644 --- a/libusb/Makefile.am +++ b/libusb/Makefile.am @@ -6,9 +6,9 @@ else THREADS_SRC = os/threads_windows.h os/threads_windows.c endif -LINUX_USBFS_SRC = $(THREADS_SRC) os/unistd_posix.h os/linux_usbfs.h os/linux_usbfs.c -DARWIN_USB_SRC = $(THREADS_SRC) os/unistd_posix.h os/darwin_usb.h os/darwin_usb.c -WINDOWS_USB_SRC = $(THREADS_SRC) os/windows_compat.h os/windows_compat.c os/windows_usb.h os/windows_usb.c +LINUX_USBFS_SRC = $(THREADS_SRC) os/poll_posix.h os/linux_usbfs.h os/linux_usbfs.c +DARWIN_USB_SRC = $(THREADS_SRC) os/poll_posix.h os/darwin_usb.h os/darwin_usb.c +WINDOWS_USB_SRC = $(THREADS_SRC) os/poll_windows.h os/poll_windows.c os/windows_usb.h os/windows_usb.c ../msvc/libusb-1.0.rc EXTRA_DIST = $(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) $(WINDOWS_USB_SRC) @@ -23,6 +23,8 @@ endif if OS_WINDOWS OS_SRC = $(WINDOWS_USB_SRC) +.rc.lo: + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(RC) $(RCFLAGS) -i $< -o $@ endif libusb_1_0_la_CFLAGS = $(VISIBILITY_CFLAGS) $(AM_CFLAGS) diff --git a/libusb/core.c b/libusb/core.c index 6da729f..47d5108 100644 --- a/libusb/core.c +++ b/libusb/core.c @@ -25,7 +25,7 @@ #include <stdlib.h> #include <string.h> #ifndef OS_WINDOWS -#include "os/unistd_posix.h" +#include "os/poll_posix.h" #endif #include "libusbi.h" @@ -832,10 +832,55 @@ API_EXPORTED void libusb_unref_device(libusb_device *dev) list_del(&dev->list); usbi_mutex_unlock(&dev->ctx->usb_devs_lock); + usbi_mutex_destroy(&dev->lock); free(dev); } } +/* + * Interrupt the iteration of the event handling thread, so that it picks + * up the new fd. + */ +void usbi_fd_notification(struct libusb_context *ctx) +{ + unsigned char dummy = 1; + ssize_t r; + + if (ctx == NULL) + return; + + /* record that we are messing with poll fds */ + usbi_mutex_lock(&ctx->pollfd_modify_lock); + ctx->pollfd_modify++; + usbi_mutex_unlock(&ctx->pollfd_modify_lock); + + /* write some data on control pipe to interrupt event handlers */ + r = usbi_write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); + if (r <= 0) { + usbi_warn(ctx, "internal signalling write failed"); + usbi_mutex_lock(&ctx->pollfd_modify_lock); + ctx->pollfd_modify--; + usbi_mutex_unlock(&ctx->pollfd_modify_lock); + return; + } + + /* take event handling lock */ + libusb_lock_events(ctx); + + /* read the dummy data */ + r = usbi_read(ctx->ctrl_pipe[0], &dummy, sizeof(dummy)); + if (r <= 0) + usbi_warn(ctx, "internal signalling read failed"); + + /* we're done with modifying poll fds */ + usbi_mutex_lock(&ctx->pollfd_modify_lock); + ctx->pollfd_modify--; + usbi_mutex_unlock(&ctx->pollfd_modify_lock); + + /* Release event handling lock and wake up event waiters */ + libusb_unlock_events(ctx); +} + /** \ingroup dev * Open a device and obtain a device handle. A handle allows you to perform * I/O on the device in question. @@ -860,7 +905,6 @@ API_EXPORTED int libusb_open(libusb_device *dev, libusb_device_handle **handle) struct libusb_context *ctx = DEVICE_CTX(dev); struct libusb_device_handle *_handle; size_t priv_size = usbi_backend->device_handle_priv_size; - unsigned char dummy = 1; ssize_t r; usbi_dbg("open %d.%d", dev->bus_number, dev->device_address); @@ -899,36 +943,7 @@ API_EXPORTED int libusb_open(libusb_device *dev, libusb_device_handle **handle) * or infinite timeout. We want to interrupt that iteration of the loop, * so that it picks up the new fd, and then continues. */ - /* record that we are messing with poll fds */ - usbi_mutex_lock(&ctx->pollfd_modify_lock); - ctx->pollfd_modify++; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - - /* write some data on control pipe to interrupt event handlers */ - r = usbi_write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); - if (r <= 0) { - usbi_warn(ctx, "internal signalling write failed"); - usbi_mutex_lock(&ctx->pollfd_modify_lock); - ctx->pollfd_modify--; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - return 0; - } - - /* take event handling lock */ - libusb_lock_events(ctx); - - /* read the dummy data */ - r = usbi_read(ctx->ctrl_pipe[0], &dummy, sizeof(dummy)); - if (r <= 0) - usbi_warn(ctx, "internal signalling read failed"); - - /* we're done with modifying poll fds */ - usbi_mutex_lock(&ctx->pollfd_modify_lock); - ctx->pollfd_modify--; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - - /* Release event handling lock and wake up event waiters */ - libusb_unlock_events(ctx); + usbi_fd_notification(ctx); return 0; } diff --git a/libusb/io.c b/libusb/io.c index 48122b5..a7728e0 100644 --- a/libusb/io.c +++ b/libusb/io.c @@ -25,7 +25,7 @@ #include <string.h> #ifndef OS_WINDOWS -#include "os/unistd_posix.h" +#include "os/poll_posix.h" #endif #ifdef USBI_TIMERFD_AVAILABLE diff --git a/libusb/libusb.h b/libusb/libusb.h index 8986013..0127d9f 100644 --- a/libusb/libusb.h +++ b/libusb/libusb.h @@ -28,8 +28,8 @@ #include <sys/time.h> #endif #include <sys/types.h> -#include <limits.h> #include <time.h> +#include <limits.h> /* 'interface' might be defined as a macro on Windows, so we need to * undefine it so as not to break the current libusb API, because diff --git a/libusb/libusbi.h b/libusb/libusbi.h index 33b642c..d7fd4a4 100644 --- a/libusb/libusbi.h +++ b/libusb/libusbi.h @@ -178,10 +178,10 @@ void inline usbi_dbg(const char *format, ...) #include <os/threads_posix.h> #elif defined(OS_WINDOWS) && (defined(__CYGWIN__) || defined(USE_PTHREAD)) #include <os/threads_posix.h> -#include <os/windows_compat.h> +#include <os/poll_windows.h> #elif defined(OS_WINDOWS) #include <os/threads_windows.h> -#include <os/windows_compat.h> +#include <os/poll_windows.h> #endif extern struct libusb_context *usbi_default_context; diff --git a/libusb/os/unistd_posix.h b/libusb/os/poll_posix.h index 0e9981d..17298a5 100644 --- a/libusb/os/unistd_posix.h +++ b/libusb/os/poll_posix.h @@ -1,5 +1,5 @@ -#ifndef __LIBUSB_UNISTD_POSIX_H__ -#define __LIBUSB_UNISTD_POSIX_H__ +#ifndef __LIBUSB_POLL_POSIX_H__ +#define __LIBUSB_POLL_POSIX_H__ #include <unistd.h> #include <poll.h> @@ -9,4 +9,4 @@ #define usbi_pipe pipe #define usbi_poll poll -#endif /* __LIBUSB_UNISTD_POSIX_H__ */ +#endif /* __LIBUSB_POLL_POSIX_H__ */ diff --git a/libusb/os/windows_compat.c b/libusb/os/poll_windows.c index 664bf5d..b6fed7c 100644 --- a/libusb/os/windows_compat.c +++ b/libusb/os/poll_windows.c @@ -1,5 +1,5 @@ /* - * Windows compat: POSIX compatibility wrapper + * poll_windows: poll compatibility wrapper for Windows * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com> * With contributions from Michael Plante, Orin Eman et al. * Parts of poll implementation from libusb-win32, by Stephan Meyer et al. @@ -21,7 +21,7 @@ */ /* - * Posix poll() and pipe() Windows compatibility layer for libusb 1.0 + * poll() and pipe() Windows compatibility layer for libusb 1.0 * * The way this layer works is by using OVERLAPPED with async I/O transfers, as * OVERLAPPED have an associated event which is flagged for I/O completion. @@ -69,16 +69,22 @@ #include <libusbi.h> // Uncomment to debug the polling layer -//#define DEBUG_WINDOWS_COMPAT -#if defined(DEBUG_WINDOWS_COMPAT) -#define printb printf +//#define DEBUG_POLL_WINDOWS + +// Uncomment to have poll return with EINTR as soon as a new transfer (fd) is added +// This should result in a LIBUSB_ERROR_INTERRUPTED being returned by libusb calls, +// which should give the app an opportunity to resubmit a new fd set. +//#define DYNAMIC_FDS + +#if defined(DEBUG_POLL_WINDOWS) +#define poll_dbg usbi_dbg #else // MSVC6 cannot use a variadic argument and non MSVC // compilers produce warnings if parenthesis are ommitted. #if defined(_MSC_VER) -#define printb +#define poll_dbg #else -#define printb(...) +#define poll_dbg(...) #endif #endif @@ -107,7 +113,7 @@ static inline int _open_osfhandle(intptr_t osfhandle, int flags) access = GENERIC_READ|GENERIC_WRITE; break; default: - printb("_open_osfhandle (emulated): unuspported access mode\n"); + usbi_err(NULL, "unuspported access mode"); return -1; } return cygwin_attach_handle_to_fd("/dev/null", -1, (HANDLE)osfhandle, -1, access); @@ -116,6 +122,8 @@ static inline int _open_osfhandle(intptr_t osfhandle, int flags) #define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0) +extern void usbi_fd_notification(struct libusb_context *ctx); + // public fd data const struct winfd INVALID_WINFD = {-1, NULL, NULL, RW_NONE, FALSE}; struct winfd poll_fd[MAX_FDS]; @@ -128,6 +136,12 @@ struct { // globals BOOLEAN is_polling_set = FALSE; +#if defined(DYNAMIC_FDS) +HANDLE fd_update = INVALID_HANDLE_VALUE; // event to notify poll of fd update +HANDLE new_fd[MAX_FDS]; // overlapped event handlesm for fds created since last poll +unsigned nb_new_fds = 0; // nb new fds created since last poll +usbi_mutex_t new_fd_mutex; // mutex required for the above +#endif LONG pipe_number = 0; static volatile LONG compat_spinlock = 0; @@ -158,13 +172,23 @@ void init_polling(void) if (!is_polling_set) { pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED)) GetProcAddress(GetModuleHandle("KERNEL32"), "CancelIoEx"); - printb("init_polling: Will use CancelIo%s for I/O cancellation\n", + usbi_dbg("Will use CancelIo%s for I/O cancellation", (pCancelIoEx != NULL)?"Ex":""); for (i=0; i<MAX_FDS; i++) { poll_fd[i] = INVALID_WINFD; _poll_fd[i].marker = 0; InitializeCriticalSection(&_poll_fd[i].mutex); } +#if defined(DYNAMIC_FDS) + // We need to create an update event so that poll is warned when there + // are new/deleted fds during a timeout wait operation + fd_update = CreateEvent(NULL, TRUE, FALSE, NULL); + if (fd_update == NULL) { + usbi_err(NULL, "unable to create update event"); + } + usbi_mutex_init(&new_fd_mutex, NULL); + nb_new_fds = 0; +#endif is_polling_set = TRUE; } compat_spinlock = 0; @@ -255,6 +279,11 @@ void exit_polling(void) } free_overlapped(poll_fd[i].overlapped); poll_fd[i] = INVALID_WINFD; +#if defined(DYNAMIC_FDS) + usbi_mutex_destroy(&new_fd_mutex); + CloseHandle(fd_update); + fd_update = INVALID_HANDLE_VALUE; +#endif LeaveCriticalSection(&_poll_fd[i].mutex); DeleteCriticalSection(&_poll_fd[i].mutex); } @@ -275,14 +304,14 @@ __inline void _init_read_marker(int index) reset_overlapped(poll_fd[index].overlapped); if (!ReadFile(poll_fd[index].handle, &_poll_fd[index].marker, 1, NULL, poll_fd[index].overlapped)) { if(GetLastError() != ERROR_IO_PENDING) { - printb("_init_read_marker: didn't get IO_PENDING!\n"); + usbi_warn(NULL, "didn't get IO_PENDING!"); reset_overlapped(poll_fd[index].overlapped); } } else { // We got some sync I/O. We'll pretend it's async and set overlapped manually - printb("_init_read_marker: marker readout completed before exit!\n"); + poll_dbg("marker readout completed before exit!"); if (!HasOverlappedIoCompleted(poll_fd[index].overlapped)) { - printb("_init_read_marker: completed I/O still flagged as pending\n"); + usbi_warn(NULL, "completed I/O still flagged as pending"); poll_fd[index].overlapped->Internal = 0; } SetEvent(poll_fd[index].overlapped->hEvent); @@ -316,7 +345,7 @@ int usbi_pipe(int filedes[2]) our_pipe_number = InterlockedIncrement(&pipe_number) - 1; // - 1 to mirror postfix operation inside _snprintf if (our_pipe_number >= 0x10000) { - fprintf(stderr, "usbi_pipe: program assertion failed - more than 65536 pipes were used"); + usbi_warn(NULL, "program assertion failed - more than 65536 pipes were used"); our_pipe_number &= 0xFFFF; } _snprintf(pipe_name, sizeof(pipe_name), "\\\\.\\pipe\\libusb%08x%04x", (unsigned)GetCurrentProcessId(), our_pipe_number); @@ -325,21 +354,21 @@ int usbi_pipe(int filedes[2]) handle[0] = CreateNamedPipeA(pipe_name, PIPE_ACCESS_INBOUND|FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE, 1, 4096, 4096, 0, NULL); if (handle[0] == INVALID_HANDLE_VALUE) { - printb("Could not create pipe (read end): errcode %d\n", (int)GetLastError()); + usbi_err(NULL, "could not create pipe (read end): errcode %d", (int)GetLastError()); goto out1; } filedes[0] = _open_osfhandle((intptr_t)handle[0], _O_RDONLY); - printb("filedes[0] = %d\n", filedes[0]); + poll_dbg("filedes[0] = %d", filedes[0]); // Write end of the pipe handle[1] = CreateFileA(pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, NULL); if (handle[1] == INVALID_HANDLE_VALUE) { - printb("Could not create pipe (write end): errcode %d\n", (int)GetLastError()); + usbi_err(NULL, "could not create pipe (write end): errcode %d", (int)GetLastError()); goto out2; } filedes[1] = _open_osfhandle((intptr_t)handle[1], _O_WRONLY); - printb("filedes[1] = %d\n", filedes[1]); + poll_dbg("filedes[1] = %d", filedes[1]); // Create an OVERLAPPED for each end overlapped0->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); @@ -405,7 +434,7 @@ out1: * read and one for write. Using a single R/W fd is unsupported and will * produce unexpected results */ -struct winfd usbi_create_fd(HANDLE handle, int access_mode) +struct winfd usbi_create_fd(HANDLE handle, int access_mode, struct libusb_context *ctx) { int i, fd; struct winfd wfd = INVALID_WINFD; @@ -418,8 +447,8 @@ struct winfd usbi_create_fd(HANDLE handle, int access_mode) } if ((access_mode != _O_RDONLY) && (access_mode != _O_WRONLY)) { - printb("usbi_create_fd: only one of _O_RDONLY or _O_WRONLY are supported.\n" - "If you want to poll for R/W simultaneously, create multiple fds from the same handle.\n"); + usbi_warn(NULL, "only one of _O_RDONLY or _O_WRONLY are supported.\n" + "If you want to poll for R/W simultaneously, create multiple fds from the same handle."); return INVALID_WINFD; } if (access_mode == _O_RDONLY) { @@ -454,6 +483,18 @@ struct winfd usbi_create_fd(HANDLE handle, int access_mode) wfd.overlapped = overlapped; memcpy(&poll_fd[i], &wfd, sizeof(struct winfd)); LeaveCriticalSection(&_poll_fd[i].mutex); +#if defined(DYNAMIC_FDS) + usbi_mutex_lock(&new_fd_mutex); + new_fd[nb_new_fds++] = overlapped->hEvent; + usbi_mutex_unlock(&new_fd_mutex); + // Notify poll that fds have been updated + SetEvent(fd_update); +#else + // NOTE: For now, usbi_fd_notification is only called on fd creation, as + // fd deletion results in a CancelIo() event, which poll should detect. + // Will see if there's an actual justification to call this on delete... + usbi_fd_notification(ctx); +#endif return wfd; } } @@ -589,10 +630,25 @@ int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) DWORD nb_handles_to_wait_on = 0; DWORD ret; +#if defined(DYNAMIC_FDS) + DWORD nb_extra_handles = 0; + unsigned j; + + // To address the possibility of missing new fds between the time the new + // pollable fd set is assembled, and the ResetEvent() call below, an + // additional new_fd[] HANDLE table is used for any new fd that was created + // since the last call to poll (see below) + ResetEvent(fd_update); + + // At this stage, any new fd creation will be detected through the fd_update + // event notification, and any previous creation that we may have missed + // will be picked up through the existing new_fd[] table. +#endif + CHECK_INIT_POLLING; triggered = 0; - handles_to_wait_on = malloc(nfds*sizeof(HANDLE)); + handles_to_wait_on = malloc((nfds+1)*sizeof(HANDLE)); // +1 for fd_update handle_to_index = malloc(nfds*sizeof(int)); if ((handles_to_wait_on == NULL) || (handle_to_index == NULL)) { errno = ENOMEM; @@ -607,7 +663,7 @@ int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) if ((fds[i].events & ~POLLIN) && (!(fds[i].events & POLLOUT))) { fds[i].revents |= POLLERR; errno = EACCES; - printb("usbi_poll: unsupported set of events\n"); + usbi_warn(NULL, "unsupported set of events"); triggered = -1; goto poll_exit; } @@ -620,7 +676,7 @@ int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) if (index >= 0) { LeaveCriticalSection(&_poll_fd[index].mutex); } - printb("usbi_poll: invalid fd\n"); + usbi_warn(NULL, "invalid fd"); triggered = -1; goto poll_exit; } @@ -629,7 +685,7 @@ int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) if ((fds[i].events & POLLIN) && (poll_fd[index].rw != RW_READ)) { fds[i].revents |= POLLNVAL | POLLERR; errno = EBADF; - printb("usbi_poll: attempted POLLIN on fd[%d] without READ access\n", i); + usbi_warn(NULL, "attempted POLLIN on fd[%d] without READ access", i); LeaveCriticalSection(&_poll_fd[index].mutex); triggered = -1; goto poll_exit; @@ -638,38 +694,87 @@ int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) if ((fds[i].events & POLLOUT) && (poll_fd[index].rw != RW_WRITE)) { fds[i].revents |= POLLNVAL | POLLERR; errno = EBADF; - printb("usbi_poll: attempted POLLOUT on fd[%d] without WRITE access\n", i); + usbi_warn(NULL, "attempted POLLOUT on fd[%d] without WRITE access", i); LeaveCriticalSection(&_poll_fd[index].mutex); triggered = -1; goto poll_exit; } - printb("usbi_poll: fd[%d]=%d (overlapped = %p) got events %04X\n", i, poll_fd[index].fd, poll_fd[index].overlapped, fds[i].events); + poll_dbg("fd[%d]=%d (overlapped = %p) got events %04X", i, poll_fd[index].fd, poll_fd[index].overlapped, fds[i].events); // The following macro only works if overlapped I/O was reported pending if ( (HasOverlappedIoCompleted(poll_fd[index].overlapped)) || (poll_fd[index].completed_synchronously) ) { - printb(" completed\n"); + poll_dbg(" completed"); // checks above should ensure this works: fds[i].revents = fds[i].events; triggered++; } else { handles_to_wait_on[nb_handles_to_wait_on] = poll_fd[index].overlapped->hEvent; handle_to_index[nb_handles_to_wait_on] = i; +#if defined(DYNAMIC_FDS) + // If this fd from the poll set is also part of the new_fd event handle table, remove it + usbi_mutex_lock(&new_fd_mutex); + for (j=0; j<nb_new_fds; j++) { + if (handles_to_wait_on[nb_handles_to_wait_on] == new_fd[j]) { + new_fd[j] = INVALID_HANDLE_VALUE; + break; + } + } + usbi_mutex_unlock(&new_fd_mutex); +#endif nb_handles_to_wait_on++; } LeaveCriticalSection(&_poll_fd[index].mutex); } +#if defined(DYNAMIC_FDS) + // Add this stage, new_fd[] should only contain events from fds that + // have been added since the last call to poll, but are not (yet) part + // of the pollable fd set. Typically, these would be from fds that have + // been created between the construction of the fd set and the calling + // of poll. + // Event if we won't be able to return usable poll data on these events, + // make sure we monitor them to return an EINTR code + usbi_mutex_lock(&new_fd_mutex); // We could probably do without + for (i=0; i<nb_new_fds; i++) { + if (new_fd[i] != INVALID_HANDLE_VALUE) { + handles_to_wait_on[nb_handles_to_wait_on++] = new_fd[i]; + nb_extra_handles++; + } + } + usbi_mutex_unlock(&new_fd_mutex); + poll_dbg("dynamic_fds: added %d extra handles", nb_extra_handles); +#endif // If nothing was triggered, wait on all fds that require it - if ((triggered == 0) && (nb_handles_to_wait_on != 0)) { - printb("usbi_poll: starting %d ms wait for %d handles...\n", timeout, (int)nb_handles_to_wait_on); + if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0)) { +#if defined(DYNAMIC_FDS) + // Register for fd update notifications + handles_to_wait_on[nb_handles_to_wait_on++] = fd_update; + nb_extra_handles++; +#endif + if (timeout < 0) { + poll_dbg("starting infinite wait for %d handles...", (int)nb_handles_to_wait_on); + } else { + poll_dbg("starting %d ms wait for %d handles...", timeout, (int)nb_handles_to_wait_on); + } ret = WaitForMultipleObjects(nb_handles_to_wait_on, handles_to_wait_on, - FALSE, (timeout==-1)?INFINITE:(DWORD)timeout); - + FALSE, (timeout<0)?INFINITE:(DWORD)timeout); object_index = ret-WAIT_OBJECT_0; if ((object_index >= 0) && ((DWORD)object_index < nb_handles_to_wait_on)) { - printb(" completed after wait\n"); +#if defined(DYNAMIC_FDS) + if ((DWORD)object_index >= (nb_handles_to_wait_on-nb_extra_handles)) { + // Detected fd update => flag a poll interruption + if ((DWORD)object_index == (nb_handles_to_wait_on-1)) + poll_dbg(" dynamic_fds: fd_update event"); + else + poll_dbg(" dynamic_fds: new fd I/O event"); + errno = EINTR; + triggered = -1; + goto poll_exit; + } +#endif + poll_dbg(" completed after wait"); i = handle_to_index[object_index]; index = _fd_to_index_and_lock(fds[i].fd); fds[i].revents = fds[i].events; @@ -678,7 +783,7 @@ int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) LeaveCriticalSection(&_poll_fd[index].mutex); } } else if (ret == WAIT_TIMEOUT) { - printb(" timed out\n"); + poll_dbg(" timed out"); triggered = 0; // 0 = timeout } else { errno = EIO; @@ -693,6 +798,11 @@ poll_exit: if (handle_to_index != NULL) { free(handle_to_index); } +#if defined(DYNAMIC_FDS) + usbi_mutex_lock(&new_fd_mutex); + nb_new_fds = 0; + usbi_mutex_unlock(&new_fd_mutex); +#endif return triggered; } @@ -759,11 +869,11 @@ ssize_t usbi_write(int fd, const void *buf, size_t count) // For sync mode, we shouldn't get pending async write I/O if (!HasOverlappedIoCompleted(poll_fd[index].overlapped)) { - printb("usbi_write: previous write I/O was flagged pending!\n"); + usbi_warn(NULL, "usbi_write: previous write I/O was flagged pending!"); cancel_io(index); } - printb("usbi_write: writing %d bytes to fd=%d\n", count, poll_fd[index].fd); + poll_dbg("writing %d bytes to fd=%d", count, poll_fd[index].fd); reset_overlapped(poll_fd[index].overlapped); if (!WriteFile(poll_fd[index].handle, buf, (DWORD)count, &wr_count, poll_fd[index].overlapped)) { @@ -777,7 +887,7 @@ ssize_t usbi_write(int fd, const void *buf, size_t count) r = 0; goto out; } else { - printb("usbi_write: GetOverlappedResult failed with error %d\n", (int)GetLastError()); + usbi_warn(NULL, "GetOverlappedResult failed with error %d", (int)GetLastError()); errno = EIO; goto out; } @@ -787,14 +897,14 @@ ssize_t usbi_write(int fd, const void *buf, size_t count) } } else { // I/O started and failed - printb("usbi_write: WriteFile failed with error %d\n", (int)GetLastError()); + usbi_warn(NULL, "WriteFile failed with error %d", (int)GetLastError()); errno = EIO; goto out; } } // I/O started and completed synchronously - r = 0; + r = 0; out: if (r) { @@ -839,7 +949,7 @@ ssize_t usbi_read(int fd, void *buf, size_t count) // still waiting for completion => force completion if (!HasOverlappedIoCompleted(poll_fd[index].overlapped)) { if (WaitForSingleObject(poll_fd[index].overlapped->hEvent, INFINITE) != WAIT_OBJECT_0) { - printb("usbi_read: waiting for marker failed: %d\n", (int)GetLastError()); + usbi_warn(NULL, "waiting for marker failed: %d", (int)GetLastError()); errno = EIO; goto out; } @@ -848,19 +958,19 @@ ssize_t usbi_read(int fd, void *buf, size_t count) // Find out if we've read the first byte if (!GetOverlappedResult(poll_fd[index].handle, poll_fd[index].overlapped, &rd_count, FALSE)) { if (GetLastError() != ERROR_MORE_DATA) { - printb("usbi_read: readout of marker failed: %d\n", (int)GetLastError()); + usbi_warn(NULL, "readout of marker failed: %d", (int)GetLastError()); errno = EIO; goto out; } else { - printb("usbi_read: readout of marker reported more data\n"); + usbi_warn(NULL, "readout of marker reported more data"); } } - printb("usbi_read: count = %d, rd_count(marker) = %d\n", count, (int)rd_count); + poll_dbg("count = %d, rd_count(marker) = %d", count, (int)rd_count); // We should have our marker by now if (rd_count != 1) { - printb("usbi_read: unexpected number of bytes for marker (%d)\n", (int)rd_count); + usbi_warn(NULL, "unexpected number of bytes for marker (%d)", (int)rd_count); errno = EIO; goto out; } @@ -874,24 +984,24 @@ ssize_t usbi_read(int fd, void *buf, size_t count) if(GetLastError() == ERROR_IO_PENDING) { if (!GetOverlappedResult(poll_fd[index].handle, poll_fd[index].overlapped, &rd_count, TRUE)) { if (GetLastError() == ERROR_MORE_DATA) { - printb("usbi_read: could not fetch all data\n"); + usbi_warn(NULL, "could not fetch all data"); } - printb("usbi_read: readout of supplementary data failed: %d\n", (int)GetLastError()); + usbi_warn(NULL, "readout of supplementary data failed: %d", (int)GetLastError()); errno = EIO; goto out; } } else { - printb("usbi_read: could not start blocking read of supplementary: %d\n", (int)GetLastError()); + usbi_warn(NULL, "could not start blocking read of supplementary: %d", (int)GetLastError()); errno = EIO; goto out; } } // If ReadFile completed synchronously, we're fine too - printb("usbi_read: rd_count(supplementary ) = %d\n", (int)rd_count); + poll_dbg("rd_count(supplementary ) = %d", (int)rd_count); if ((rd_count+1) != count) { - printb("usbi_read: wanted %d-1, got %d\n", count, (int)rd_count); + poll_dbg("wanted %d-1, got %d", count, (int)rd_count); errno = EIO; goto out; } diff --git a/libusb/os/windows_compat.h b/libusb/os/poll_windows.h index 699f167..996ff48 100644 --- a/libusb/os/windows_compat.h +++ b/libusb/os/poll_windows.h @@ -84,7 +84,7 @@ int usbi_close(int fd); void init_polling(void); void exit_polling(void); -struct winfd usbi_create_fd(HANDLE handle, int access_mode); +struct winfd usbi_create_fd(HANDLE handle, int access_mode, struct libusb_context *ctx); void usbi_free_fd(int fd); struct winfd fd_to_winfd(int fd); struct winfd handle_to_winfd(HANDLE handle); diff --git a/libusb/os/sources b/libusb/os/sources index 669e32a..dc474ca 100644 --- a/libusb/os/sources +++ b/libusb/os/sources @@ -23,7 +23,7 @@ SOURCES=..\core.c \ ..\io.c \ ..\sync.c \ threads_windows.c \ - windows_compat.c \ + poll_windows.c \ windows_usb.c \ libusb-1.0.rc diff --git a/libusb/os/threads_windows.c b/libusb/os/threads_windows.c index 11b55f9..7762190 100644 --- a/libusb/os/threads_windows.c +++ b/libusb/os/threads_windows.c @@ -61,8 +61,8 @@ int usbi_mutex_lock(usbi_mutex_t *mutex) { // so don't know proper errno } int usbi_mutex_unlock(usbi_mutex_t *mutex) { - if(!mutex) return ((errno=EINVAL)); - if(!ReleaseMutex(mutex)) return ((errno=EPERM )); + if(!mutex) return ((errno=EINVAL)); + if(!ReleaseMutex(*mutex)) return ((errno=EPERM )); return 0; } diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c index 610a91d..62fb871 100644 --- a/libusb/os/windows_usb.c +++ b/libusb/os/windows_usb.c @@ -47,7 +47,7 @@ #include <objbase.h> // for string to GUID conv. requires libole32.a #include <libusbi.h> -#include "windows_compat.h" +#include "poll_windows.h" #include "windows_usb.h" #if defined(_PREFAST_) @@ -124,7 +124,7 @@ const GUID CLASS_GUID_COMPOSITE = { 0x36FC9E60, 0xC465, 0x11cF, {0x80, 0x56, // Global variables struct windows_hcd_priv* hcd_root = NULL; uint64_t hires_frequency, hires_ticks_to_ps; -const uint64_t epoch_time = 116444736000000000; // 1970.01.01 00:00:000 in MS Filetime +const uint64_t epoch_time = UINT64_C(116444736000000000); // 1970.01.01 00:00:000 in MS Filetime enum windows_version windows_version = WINDOWS_UNSUPPORTED; // Concurrency static int concurrent_usage = -1; @@ -249,6 +249,20 @@ char* sanitize_path(const char* path) } /* + * Cfgmgr32 API functions + */ +static int Cfgmgr32_init(void) +{ + DLL_LOAD(Cfgmgr32.dll, CM_Get_Parent, TRUE); + DLL_LOAD(Cfgmgr32.dll, CM_Get_Child, TRUE); + DLL_LOAD(Cfgmgr32.dll, CM_Get_Sibling, TRUE); + DLL_LOAD(Cfgmgr32.dll, CM_Get_Device_IDA, TRUE); + DLL_LOAD(Cfgmgr32.dll, CM_Get_Device_IDW, TRUE); + + return LIBUSB_SUCCESS; +} + +/* * enumerate interfaces for a specific GUID * * Parameters: @@ -429,6 +443,12 @@ static int windows_init(struct libusb_context *ctx) // Initialize pollable file descriptors init_polling(); + // Load missing CFGMGR32.DLL imports + if (Cfgmgr32_init() != LIBUSB_SUCCESS) { + usbi_err(ctx, "could not resolve Cfgmgr32.dll functions"); + return LIBUSB_ERROR_OTHER; + } + // Initialize the low level APIs for (i=0; i<USB_API_MAX; i++) { r = usb_api_backend[i].init(ctx); @@ -590,8 +610,10 @@ static int force_hcd_device_descriptor(struct libusb_device *dev, HANDLE handle) priv->dev_descriptor.bLength = sizeof(USB_DEVICE_DESCRIPTOR); priv->dev_descriptor.bDescriptorType = USB_DEVICE_DESCRIPTOR_TYPE; dev->num_configurations = priv->dev_descriptor.bNumConfigurations = 1; - priv->dev_descriptor.idVendor = 0x1d6b; // Linux Foundation root hub + // The following is used to set the VIS:PID of root HUBs similarly to what + // Linux does: 1d6b:0001 is for 1x root hubs, 1d6b:0002 for 2x + priv->dev_descriptor.idVendor = 0x1d6b; // Linux Foundation root hub if (windows_version >= WINDOWS_VISTA_AND_LATER) { size = sizeof(USB_HUB_CAPABILITIES_EX); if (DeviceIoControl(handle, IOCTL_USB_GET_HUB_CAPABILITIES_EX, &hub_caps_ex, @@ -608,9 +630,10 @@ static int force_hcd_device_descriptor(struct libusb_device *dev, HANDLE handle) size, &hub_caps, size, &size, NULL)) { usbi_warn(ctx, "could not read hub capabilities (std) for hub %s: %s", priv->path, windows_error_str(0)); - return LIBUSB_ERROR_IO; + priv->dev_descriptor.idProduct = 1; // Indicate 1x speed + } else { + priv->dev_descriptor.idProduct = hub_caps.HubIs2xCapable?2:1; } - priv->dev_descriptor.idProduct = hub_caps.HubIs2xCapable?2:1; } return LIBUSB_SUCCESS; @@ -735,7 +758,7 @@ static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs USB_HUB_NAME_FIXED s_hubname; USB_NODE_CONNECTION_INFORMATION conn_info; USB_NODE_INFORMATION hub_node; - bool is_hcd; + bool is_hcd, need_unref = false; int i, r; LPCWSTR wstr; char *tmp_str = NULL, *path_str = NULL; @@ -768,7 +791,10 @@ static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs for (i = 1, r = LIBUSB_SUCCESS; ; i++) { // safe loop: release all dynamic resources - safe_unref_device(dev); + if (need_unref) { + safe_unref_device(dev); + need_unref = false; + } safe_free(tmp_str); safe_free(path_str); safe_closehandle(handle); @@ -849,7 +875,7 @@ static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs // Open Hub handle = CreateFileA(path_str, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_FLAG_POSIX_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL); + FILE_FLAG_OVERLAPPED, NULL); if(handle == INVALID_HANDLE_VALUE) { usbi_warn(ctx, "could not open hub %s: %s", path_str, windows_error_str(0)); continue; @@ -882,6 +908,7 @@ static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs if ((dev = usbi_alloc_device(ctx, session_id)) == NULL) { LOOP_BREAK(LIBUSB_ERROR_NO_MEM); } + need_unref = true; LOOP_CHECK(initialize_device(dev, busnum, devaddr, path_str, i, conn_info.CurrentConfigurationValue, parent_dev)); @@ -1427,7 +1454,7 @@ static int windows_get_device_list(struct libusb_context *ctx, struct discovered } handle = CreateFileA(hcd->path, GENERIC_WRITE, FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, FILE_FLAG_POSIX_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL); + NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (handle == INVALID_HANDLE_VALUE) { usbi_warn(ctx, "could not open bus %u, skipping: %s", bus, windows_error_str(0)); continue; @@ -1931,12 +1958,12 @@ unsigned __stdcall windows_clock_gettime_threaded(void* param) if (!QueryPerformanceFrequency(&li_frequency)) { usbi_dbg("no hires timer available on this platform"); hires_frequency = 0; - hires_ticks_to_ps = 0; + hires_ticks_to_ps = UINT64_C(0); } else { hires_frequency = li_frequency.QuadPart; // The hires frequency can go as high as 4 GHz, so we'll use a conversion // to picoseconds to compute the tv_nsecs part in clock_gettime - hires_ticks_to_ps = 1000000000000 / hires_frequency; + hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency; usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency); } @@ -2516,7 +2543,7 @@ static int winusb_submit_control_transfer(struct usbi_transfer *itransfer) usbi_dbg("will use interface %d", current_interface); winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - wfd = usbi_create_fd(winusb_handle, _O_RDONLY); + wfd = usbi_create_fd(winusb_handle, _O_RDONLY, ctx); if (wfd.fd < 0) { return LIBUSB_ERROR_NO_MEM; } @@ -2592,7 +2619,7 @@ static int winusb_submit_bulk_transfer(struct usbi_transfer *itransfer) winusb_handle = handle_priv->interface_handle[current_interface].api_handle; direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN; - wfd = usbi_create_fd(winusb_handle, direction_in?_O_RDONLY:_O_WRONLY); + wfd = usbi_create_fd(winusb_handle, direction_in?_O_RDONLY:_O_WRONLY, ctx); if (wfd.fd < 0) { return LIBUSB_ERROR_NO_MEM; } @@ -3174,9 +3201,11 @@ static int _hid_get_feature(struct hid_device_priv* dev, HANDLE hid_handle, int switch (err) { case ERROR_INVALID_FUNCTION: r = LIBUSB_ERROR_NOT_FOUND; + break; default: - usbi_dbg("error %s", windows_error_str(r)); + usbi_dbg("error %s", windows_error_str(err)); r = LIBUSB_ERROR_OTHER; + break; } } safe_free(buf); @@ -3554,7 +3583,7 @@ static int hid_submit_control_transfer(struct usbi_transfer *itransfer) usbi_dbg("will use interface %d", current_interface); hid_handle = handle_priv->interface_handle[current_interface].api_handle; - wfd = usbi_create_fd(hid_handle, _O_RDONLY); + wfd = usbi_create_fd(hid_handle, _O_RDONLY, ctx); if (wfd.fd < 0) { return LIBUSB_ERROR_NO_MEM; } @@ -3656,7 +3685,7 @@ static int hid_submit_bulk_transfer(struct usbi_transfer *itransfer) { hid_handle = handle_priv->interface_handle[current_interface].api_handle; direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN; - wfd = usbi_create_fd(hid_handle, direction_in?_O_RDONLY:_O_WRONLY); + wfd = usbi_create_fd(hid_handle, direction_in?_O_RDONLY:_O_WRONLY, ctx); if (wfd.fd < 0) { return LIBUSB_ERROR_NO_MEM; } diff --git a/libusb/os/windows_usb.h b/libusb/os/windows_usb.h index e5c5c79..30560b5 100644 --- a/libusb/os/windows_usb.h +++ b/libusb/os/windows_usb.h @@ -84,8 +84,6 @@ inline void upperize(char* str) { for (i=0; i<strlen(str); i++) str[i] = (char)toupper((int)str[i]); } -extern char* sanitize_path(const char* path); -extern char *windows_error_str(uint32_t retval); #define MAX_CTRL_BUFFER_LENGTH 4096 #define MAX_USB_DEVICES 256 @@ -297,6 +295,32 @@ struct windows_transfer_priv { /* + * API macros - from libusb-win32 1.x + */ +#define DLL_DECLARE(api, ret, name, args) \ + typedef ret (api * __dll_##name##_t)args; __dll_##name##_t name + +#define DLL_LOAD(dll, name, ret_on_failure) \ + do { \ + HMODULE h = GetModuleHandle(#dll); \ + if (!h) \ + h = LoadLibrary(#dll); \ + if (!h) { \ + if (ret_on_failure) { return LIBUSB_ERROR_OTHER; } \ + else { break; } \ + } \ + name = (__dll_##name##_t)GetProcAddress(h, #name); \ + if (name) break; \ + name = (__dll_##name##_t)GetProcAddress(h, #name "A"); \ + if (name) break; \ + name = (__dll_##name##_t)GetProcAddress(h, #name "W"); \ + if (name) break; \ + if(ret_on_failure) \ + return LIBUSB_ERROR_OTHER; \ + } while(0) + + +/* * Windows DDK API definitions. Most of it copied from MinGW's includes */ typedef DWORD DEVNODE, DEVINST; @@ -306,11 +330,11 @@ typedef RETURN_TYPE CONFIGRET; #define CR_SUCCESS 0x00000000 #define CR_NO_SUCH_DEVNODE 0x0000000D -#if defined(_CFGMGR32_) -#define CMAPI DECLSPEC_EXPORT -#else -#define CMAPI DECLSPEC_IMPORT -#endif +//#if defined(_CFGMGR32_) +//#define CMAPI DECLSPEC_EXPORT +//#else +//#define CMAPI DECLSPEC_IMPORT +//#endif #define USB_DEVICE_DESCRIPTOR_TYPE LIBUSB_DT_DEVICE #define USB_CONFIGURATION_DESCRIPTOR_TYPE LIBUSB_DT_CONFIG @@ -375,39 +399,12 @@ typedef enum _USB_HUB_NODE { UsbMIParent } USB_HUB_NODE; -typedef enum _DEVICE_INSTALL_STATE { - InstallStateInstalled, - InstallStateNeedsReinstall, - InstallStateFailedInstall, - InstallStateFinishInstall -} DEVICE_INSTALL_STATE, *PDEVICE_INSTALL_STATE; - -CMAPI CONFIGRET WINAPI CM_Get_Parent( - /*OUT*/ PDEVINST pdnDevInst, - /*IN*/ DEVINST dnDevInst, - /*IN*/ ULONG ulFlags); - -CMAPI CONFIGRET WINAPI CM_Get_Child( - /*OUT*/ PDEVINST pdnDevInst, - /*IN*/ DEVINST dnDevInst, - /*IN*/ ULONG ulFlags); - -CMAPI CONFIGRET WINAPI CM_Get_Sibling( - /*OUT*/ PDEVINST pdnDevInst, - /*IN*/ DEVINST DevInst, - /*IN*/ ULONG ulFlags); - -CMAPI CONFIGRET WINAPI CM_Get_Device_IDA( - /*IN*/ DEVINST dnDevInst, - /*OUT*/ PCHAR Buffer, - /*IN*/ ULONG BufferLen, - /*IN*/ ULONG ulFlags); - -CMAPI CONFIGRET WINAPI CM_Get_Device_IDW( - /*IN*/ DEVINST dnDevInst, - /*OUT*/ PWCHAR Buffer, - /*IN*/ ULONG BufferLen, - /*IN*/ ULONG ulFlags); +/* Cfgmgr32.dll interface */ +DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG)); +DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG)); +DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Sibling, (PDEVINST, DEVINST, ULONG)); +DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Device_IDA, (DEVINST, PCHAR, ULONG, ULONG)); +DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Device_IDW, (DEVINST, PWCHAR, ULONG, ULONG)); #ifdef UNICODE #define CM_Get_Device_ID CM_Get_Device_IDW @@ -597,34 +594,6 @@ typedef struct _USB_HUB_CAPABILITIES_EX { #pragma pack(pop) - -/* - * API macros - from libusb-win32 1.x - */ - -#define DLL_DECLARE(api, ret, name, args) \ - typedef ret (api * __dll_##name##_t)args; __dll_##name##_t name - -#define DLL_LOAD(dll, name, ret_on_failure) \ - do { \ - HMODULE h = GetModuleHandle(#dll); \ - if (!h) \ - h = LoadLibrary(#dll); \ - if (!h) { \ - if (ret_on_failure) { return LIBUSB_ERROR_OTHER; } \ - else { break; } \ - } \ - name = (__dll_##name##_t)GetProcAddress(h, #name); \ - if (name) break; \ - name = (__dll_##name##_t)GetProcAddress(h, #name "A"); \ - if (name) break; \ - name = (__dll_##name##_t)GetProcAddress(h, #name "W"); \ - if (name) break; \ - if(ret_on_failure) \ - return LIBUSB_ERROR_OTHER; \ - } while(0) - - /* winusb.dll interface */ #define SHORT_PACKET_TERMINATE 0x01 diff --git a/libusb_dll.dsp b/libusb_dll.dsp index 31dbeb7..0b9a423 100644 --- a/libusb_dll.dsp +++ b/libusb_dll.dsp @@ -53,7 +53,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib "D:/Program Files/Microsoft SDK/Lib/setupapi.lib" /nologo /dll /machine:I386 /out:"Win32/Release/dll/libusb-1.0.dll" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setupapi.lib /nologo /dll /machine:I386 /out:"Win32/Release/dll/libusb-1.0.dll" !ELSEIF "$(CFG)" == "libusb_dll - Win32 Debug" @@ -79,7 +79,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo /n LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib "D:/Program Files/Microsoft SDK/Lib/setupapi.lib" /nologo /dll /debug /machine:I386 /out:"Win32/Debug/dll/libusb-1.0_debug.dll" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setupapi.lib /nologo /dll /debug /machine:I386 /out:"Win32/Debug/dll/libusb-1.0_debug.dll" # SUBTRACT LINK32 /pdb:none /incremental:no !ENDIF @@ -131,7 +131,7 @@ SOURCE=.\libusb\os\threads_windows.c # End Source File # Begin Source File -SOURCE=.\libusb\os\windows_compat.c +SOURCE=.\libusb\os\poll_windows.c # End Source File # Begin Source File @@ -163,6 +163,10 @@ SOURCE=.\libusb\os\linux_usbfs.h # End Source File # Begin Source File +SOURCE=.\libusb\os\poll_posix.h +# End Source File +# Begin Source File + SOURCE=.\msvc\resource.h # End Source File # Begin Source File @@ -175,7 +179,7 @@ SOURCE=.\libusb\os\threads_windows.h # End Source File # Begin Source File -SOURCE=.\libusb\os\windows_compat.h +SOURCE=.\libusb\os\poll_windows.h # End Source File # Begin Source File diff --git a/libusb_static.dsp b/libusb_static.dsp index eb12cd1..ae6879b 100644 --- a/libusb_static.dsp +++ b/libusb_static.dsp @@ -115,7 +115,7 @@ SOURCE=.\libusb\os\threads_windows.c # End Source File # Begin Source File -SOURCE=.\libusb\os\windows_compat.c +SOURCE=.\libusb\os\poll_windows.c # End Source File # Begin Source File @@ -147,6 +147,10 @@ SOURCE=.\libusb\os\linux_usbfs.h # End Source File # Begin Source File +SOURCE=.\libusb\os\poll_posix.h +# End Source File +# Begin Source File + SOURCE=.\libusb\os\threads_posix.h # End Source File # Begin Source File @@ -155,7 +159,7 @@ SOURCE=.\libusb\os\threads_windows.h # End Source File # Begin Source File -SOURCE=.\libusb\os\windows_compat.h +SOURCE=.\libusb\os\poll_windows.h # End Source File # Begin Source File diff --git a/msvc/config.h b/msvc/config.h index 27cfe6c..304fc5c 100644 --- a/msvc/config.h +++ b/msvc/config.h @@ -1,5 +1,10 @@ /* config.h. Manual config for MSVC. */ +#ifndef _MSC_VER +#warn "msvc/config.h shouldn't be included for your development environment." +#error "Please make sure the msvc/ directory is removed from your build path." +#endif + /* Default visibility */ #define API_EXPORTED /**/ |