diff options
Diffstat (limited to 'libusb/os/driver_installer.c')
-rw-r--r-- | libusb/os/driver_installer.c | 175 |
1 files changed, 169 insertions, 6 deletions
diff --git a/libusb/os/driver_installer.c b/libusb/os/driver_installer.c index c6f7d63..5b66b48 100644 --- a/libusb/os/driver_installer.c +++ b/libusb/os/driver_installer.c @@ -8,13 +8,71 @@ #include <stdlib.h> #include <inttypes.h> #include <direct.h> +#include <setupapi.h> #include <api/difxapi.h> #include <fcntl.h> #include <io.h> #include <stdarg.h> +#include "driver-installer.h" + +/* + * 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 -1; } \ + 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 -1; \ + } while(0) + +/* + * Cfgmgr32.dll interface + */ +typedef DWORD DEVNODE, DEVINST; +typedef DEVNODE *PDEVNODE, *PDEVINST; +typedef DWORD RETURN_TYPE; +typedef RETURN_TYPE CONFIGRET; + +#define CR_SUCCESS 0x00000000 + +#define CM_REENUMERATE_NORMAL 0x00000000 +#define CM_REENUMERATE_SYNCHRONOUS 0x00000001 +#define CM_REENUMERATE_RETRY_INSTALLATION 0x00000002 +#define CM_REENUMERATE_ASYNCHRONOUS 0x00000004 +#define CM_REENUMERATE_BITS 0x00000007 + +typedef CHAR *DEVNODEID_A, *DEVINSTID_A; +typedef WCHAR *DEVNODEID_W, *DEVINSTID_W; +#ifdef UNICODE +typedef DEVNODEID_W DEVNODEID; +typedef DEVINSTID_W DEVINSTID; +#else +typedef DEVNODEID_A DEVNODEID; +typedef DEVINSTID_A DEVINSTID; +#endif + +DLL_DECLARE(WINAPI, CONFIGRET, CM_Locate_DevNode, (PDEVINST, DEVINSTID, ULONG)); +DLL_DECLARE(WINAPI, CONFIGRET, CM_Reenumerate_DevNode, (DEVINST, ULONG)); + #define INF_NAME "libusb-device.inf" #define MAX_PATH_LENGTH 128 +#define REQUEST_TIMEOUT 5000 #define safe_strncpy(dst, dst_max, src, count) strncpy(dst, src, min(count, dst_max - 1)) #define safe_strcpy(dst, dst_max, src) safe_strncpy(dst, dst_max, src, strlen(src)+1) #define safe_strncat(dst, dst_max, src, count) strncat(dst, src, min(count, dst_max - strlen(dst) - 1)) @@ -22,6 +80,13 @@ HANDLE pipe = INVALID_HANDLE_VALUE; +static int init_cfgmgr32(void) +{ + DLL_LOAD(Cfgmgr32.dll, CM_Locate_DevNode, TRUE); + DLL_LOAD(Cfgmgr32.dll, CM_Reenumerate_DevNode, TRUE); + return 0; +} + // TODO: return a status byte along with the message void plog_v(const char *format, va_list args) { @@ -31,12 +96,13 @@ void plog_v(const char *format, va_list args) if (pipe == INVALID_HANDLE_VALUE) return; - size = vsnprintf_s(buffer, 256, _TRUNCATE, format, args); + buffer[0] = IC_PRINT_MESSAGE; + size = vsnprintf_s(buffer+1, 255, _TRUNCATE, format, args); if (size < 0) { buffer[255] = 0; - size = 255; + size = 254; } - WriteFile(pipe, buffer, size+1, &size, NULL); + WriteFile(pipe, buffer, size+2, &size, NULL); } void plog(const char *format, ...) @@ -48,6 +114,72 @@ void plog(const char *format, ...) va_end (args); } +int request_data(unsigned char req, void *buffer, int size) +{ + OVERLAPPED overlapped; + DWORD rd_count; + DWORD r, count = (DWORD)size; + + if ((buffer == NULL) || (size <= 0)) { + return -1; + } + + // Set the overlapped for messaging + memset(&overlapped, 0, sizeof(OVERLAPPED)); + overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (overlapped.hEvent == NULL) { + plog("failed to create overlapped"); + return -1; + } + + if (ReadFile(pipe, buffer, count, &rd_count, &overlapped)) { + // Message was read synchronously + plog("received unexpected data"); + CloseHandle(overlapped.hEvent); + return -1; + } + + if (GetLastError() != ERROR_IO_PENDING) { + plog("failure to initiate read (%d)", (int)GetLastError()); + CloseHandle(overlapped.hEvent); + return -1; + } + + // Now that we're set to receive data, let's send our request + WriteFile(pipe, &req, 1, &r, NULL); + + // Wait for the response + r = WaitForSingleObject(overlapped.hEvent, REQUEST_TIMEOUT); + if ( (r == WAIT_OBJECT_0) && (GetOverlappedResult(pipe, &overlapped, &rd_count, FALSE)) ) { + CloseHandle(overlapped.hEvent); + return (int)rd_count; + } + + if (r == WAIT_TIMEOUT) { + plog("message request: timed out"); + } else { + plog("read error: %d", (int)GetLastError()); + } + CloseHandle(overlapped.hEvent); + return -1; +} + +char* req_device_id(void) +{ + int size; + static char device_id[MAX_PATH_LENGTH]; + + memset(device_id, 0, MAX_PATH_LENGTH); + size = request_data(IC_GET_DEVICE_ID, (void*)device_id, sizeof(device_id)); + if (size > 0) { + plog("got device_id: %s", device_id); + return device_id; + } + + plog("failed to read device_id"); + return NULL; +} + void __cdecl log_callback(DIFXAPI_LOG Event, DWORD Error, const TCHAR * pEventDescription, PVOID CallbackContext) { if (Error == 0){ @@ -57,24 +189,51 @@ void __cdecl log_callback(DIFXAPI_LOG Event, DWORD Error, const TCHAR * pEventDe } } +// TODO: allow root re-enum +int update_driver(char* device_id) +{ + DEVINST dev_inst; + CONFIGRET status; + + plog("updating driver node %s...", device_id); + status = CM_Locate_DevNode(&dev_inst, device_id, 0); + if (status != CR_SUCCESS) { + plog("failed to locate device_id %s: %x\n", device_id, status); + return -1; + } + + status = CM_Reenumerate_DevNode(dev_inst, CM_REENUMERATE_RETRY_INSTALLATION); + if (status != CR_SUCCESS) { + plog("failed to re-enumerate device node: CR code %X", status); + return -1; + } + + plog("final installation succeeded..."); + return 0; +} int main(int argc, char** argv) { DWORD r; - BOOL reboot_needed; + char* device_id; + BOOL reboot_needed = FALSE; char path[MAX_PATH_LENGTH]; char log[MAX_PATH_LENGTH]; FILE *fd; // Connect to the messaging pipe - pipe = CreateFile("\\\\.\\pipe\\libusb-installer", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + pipe = CreateFile("\\\\.\\pipe\\libusb-installer", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, NULL); if (pipe == INVALID_HANDLE_VALUE) { - // Try to write on console printf("could not open pipe for writing: errcode %d\n", (int)GetLastError()); return -1; } + if (init_cfgmgr32()) { + plog("could not access dfmgr32 DLL"); + return -1; + } + safe_strcpy(log, MAX_PATH_LENGTH, argv[0]); // TODO - seek for terminal '.exe' and change extension if needed safe_strcat(log, MAX_PATH_LENGTH, ".log"); @@ -95,6 +254,8 @@ int main(int argc, char** argv) safe_strcat(path, MAX_PATH_LENGTH, "\\"); safe_strcat(path, MAX_PATH_LENGTH, INF_NAME); + device_id = req_device_id(); + plog("Installing driver - please wait..."); DIFXAPISetLogCallback(log_callback, NULL); // TODO: set app dependency? @@ -151,6 +312,8 @@ int main(int argc, char** argv) goto out; } + update_driver(device_id); + out: CloseHandle(pipe); return 0; |