summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Fleytman <dmitry@daynix.com>2016-02-11 18:04:47 +0200
committerJonathon Jongsma <jjongsma@redhat.com>2016-03-24 11:00:00 -0500
commit293e481d4af8b05fda7d810e5cde199c4f29e825 (patch)
tree41b985e75ddefad92bdd8cd60b4ee3ab79ca4da2
parentc075c54729bf168efd916fdcbca55a77458209e1 (diff)
win-usbredir: Introduce UsbDk wrapper
Introduce UsbDk API definitions and binding code. UsbDk API DLL is loaded dynamically and wrapped by a thin glue code layer. This approach was chosen in order to make spice-gtk functional without UsbDk installed. Next patches will introduce dynamic backend selection logic, i.e. spice-gtk will try to use UsbDk by default and fallback to the old WinUsb/usbclerk scheme in case UsbDk is not available. Signed-off-by: Kirill Moizik <kirillm@daynix.com> Signed-off-by: Dmitry Fleytman <dmitry@daynix.com> Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
-rw-r--r--src/Makefile.am2
-rw-r--r--src/usbdk_api.c187
-rw-r--r--src/usbdk_api.h34
3 files changed, 223 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 330c85d..0ef3bea 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -355,6 +355,8 @@ WIN_USB_FILES= \
win-usb-clerk.h \
win-usb-driver-install.h \
win-usb-driver-install.c \
+ usbdk_api.h \
+ usbdk_api.c \
$(NULL)
if OS_WIN32
diff --git a/src/usbdk_api.c b/src/usbdk_api.c
new file mode 100644
index 0000000..f5009e5
--- /dev/null
+++ b/src/usbdk_api.c
@@ -0,0 +1,187 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2014-2015 Red Hat, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+ Authors:
+ Dmitry Fleytman <dmitry@daynix.com>
+ Kirill Moizik <kirill@daynix.com>
+*/
+#include <config.h>
+
+#include <windows.h>
+#include <glib-object.h>
+#include "usbdk_api.h"
+#include "channel-usbredir-priv.h"
+
+#define USB_DK_HIDE_RULE_MATCH_ALL ((ULONG64)(-1))
+typedef struct tag_USB_DK_HIDE_RULE
+{
+ ULONG64 Hide;
+ ULONG64 Class;
+ ULONG64 VID;
+ ULONG64 PID;
+ ULONG64 BCD;
+} USB_DK_HIDE_RULE, *PUSB_DK_HIDE_RULE;
+
+typedef HANDLE(__cdecl *USBDK_CREATEHIDERHANDLE)(void);
+typedef BOOL(__cdecl * USBDK_ADDHIDERULE)(HANDLE hider_handle, PUSB_DK_HIDE_RULE rule);
+typedef BOOL(__cdecl *USBDK_CLEARHIDERULES)(HANDLE hider_handle);
+typedef void(__cdecl *USBDK_CLOSEHIDERHANDLE)(HANDLE hider_handle);
+
+struct tag_usbdk_api_wrapper
+{
+ HMODULE module;
+ USBDK_CREATEHIDERHANDLE CreateHiderHandle;
+ USBDK_ADDHIDERULE AddRule;
+ USBDK_CLEARHIDERULES ClearRules;
+ USBDK_CLOSEHIDERHANDLE CloseHiderHandle;
+};
+
+BOOL usbdk_is_driver_installed(void)
+{
+ gboolean usbdk_installed = FALSE;
+ SC_HANDLE managerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
+
+ if (managerHandle) {
+ SC_HANDLE serviceHandle = OpenService(managerHandle, TEXT("UsbDk"), GENERIC_READ);
+
+ if (serviceHandle) {
+ SPICE_DEBUG("UsbDk driver is installed.");
+ usbdk_installed = TRUE;
+ CloseServiceHandle(serviceHandle);
+ }
+ CloseServiceHandle(managerHandle);
+ }
+ return usbdk_installed;
+}
+
+void usbdk_api_unload(usbdk_api_wrapper *usbdk_api)
+{
+ if (usbdk_api != NULL) {
+ if (usbdk_api->module != NULL) {
+ SPICE_DEBUG("Unloading UsbDk API DLL");
+ FreeLibrary(usbdk_api->module);
+ }
+ g_free(usbdk_api);
+ }
+}
+
+usbdk_api_wrapper *usbdk_api_load(void)
+{
+ usbdk_api_wrapper *usbdk_api = g_new0(usbdk_api_wrapper, 1);
+
+ SPICE_DEBUG("Loading UsbDk API DLL");
+ usbdk_api->module = LoadLibraryA("UsbDkHelper");
+ if (usbdk_api->module == NULL) {
+ g_warning("Failed to load UsbDkHelper.dll, error %lu", GetLastError());
+ goto error_unload;
+ }
+
+ usbdk_api->CreateHiderHandle = (USBDK_CREATEHIDERHANDLE)
+ GetProcAddress(usbdk_api->module, "UsbDk_CreateHiderHandle");
+ if (usbdk_api->CreateHiderHandle == NULL) {
+ g_warning("Failed to find CreateHandle entry point");
+ goto error_unload;
+ }
+
+ usbdk_api->AddRule = (USBDK_ADDHIDERULE)
+ GetProcAddress(usbdk_api->module, "UsbDk_AddHideRule");
+ if (usbdk_api->AddRule == NULL) {
+ g_warning("Failed to find AddRule entry point");
+ goto error_unload;
+ }
+
+ usbdk_api->ClearRules = (USBDK_CLEARHIDERULES)
+ GetProcAddress(usbdk_api->module, "UsbDk_ClearHideRules");
+ if (usbdk_api->ClearRules == NULL) {
+ g_warning("Failed to find ClearRules entry point");
+ goto error_unload;
+ }
+
+ usbdk_api->CloseHiderHandle = (USBDK_CLOSEHIDERHANDLE)
+ GetProcAddress(usbdk_api->module, "UsbDk_CloseHiderHandle");
+ if (usbdk_api->CloseHiderHandle == NULL) {
+ g_warning("Failed to find CloseHiderHandle entry point");
+ goto error_unload;
+ }
+ return usbdk_api;
+
+error_unload:
+ usbdk_api_unload(usbdk_api);
+ return NULL;
+}
+
+static uint64_t usbdk_usbredir_field_to_usbdk(int value)
+{
+ if (value >= 0) {
+ return value;
+ }
+
+ g_warn_if_fail(value == -1);
+
+ return USB_DK_HIDE_RULE_MATCH_ALL;
+}
+
+static BOOL usbdk_add_hide_rule(usbdk_api_wrapper *usbdk_api,
+ HANDLE hider_handle,
+ PUSB_DK_HIDE_RULE rule)
+{
+ return usbdk_api->AddRule(hider_handle, rule);
+}
+
+void usbdk_api_set_hide_rules(usbdk_api_wrapper *usbdk_api, HANDLE hider_handle,
+ gchar *redirect_on_connect)
+{
+ struct usbredirfilter_rule *rules;
+ int r, count;
+
+ r = usbredirfilter_string_to_rules(redirect_on_connect, ",", "|",
+ &rules, &count);
+ if (r) {
+ g_warning("auto-connect rules parsing failed with error %d", r);
+ return;
+ }
+
+ for (int i = 0; i < count; i++) {
+ USB_DK_HIDE_RULE rule;
+ rule.Hide = usbdk_usbredir_field_to_usbdk(rules[i].allow);
+ rule.Class = usbdk_usbredir_field_to_usbdk(rules[i].device_class);
+ rule.VID = usbdk_usbredir_field_to_usbdk(rules[i].vendor_id);
+ rule.PID = usbdk_usbredir_field_to_usbdk(rules[i].product_id);
+ rule.BCD = usbdk_usbredir_field_to_usbdk(rules[i].device_version_bcd);
+ if (!usbdk_add_hide_rule(usbdk_api, hider_handle, &rule)) {
+ SPICE_DEBUG("UsbDk add hide rule API failed");
+ }
+ }
+
+ free(rules);
+}
+
+HANDLE usbdk_create_hider_handle(usbdk_api_wrapper *usbdk_api)
+{
+ HANDLE handle = usbdk_api->CreateHiderHandle();
+ return (handle == INVALID_HANDLE_VALUE) ? NULL : handle;
+}
+
+BOOL usbdk_clear_hide_rules(usbdk_api_wrapper *usbdk_api, HANDLE hider_handle)
+{
+ return usbdk_api->ClearRules(hider_handle);
+}
+
+void usbdk_close_hider_handle(usbdk_api_wrapper *usbdk_api, HANDLE hider_handle)
+{
+ return usbdk_api->CloseHiderHandle(hider_handle);
+}
diff --git a/src/usbdk_api.h b/src/usbdk_api.h
new file mode 100644
index 0000000..8e5406c
--- /dev/null
+++ b/src/usbdk_api.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2014-2015 Red Hat, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+ Authors:
+ Dmitry Fleytman <dmitry@daynix.com>
+ Kirill Moizik <kirill@daynix.com>
+*/
+#ifndef USBDK_HEADER
+#define USBDK_HEADER
+
+typedef struct tag_usbdk_api_wrapper usbdk_api_wrapper;
+
+usbdk_api_wrapper *usbdk_api_load(void);
+void usbdk_api_unload(usbdk_api_wrapper *usbdk_api);
+BOOL usbdk_is_driver_installed(void);
+HANDLE usbdk_create_hider_handle(usbdk_api_wrapper *usbdk_api);
+void usbdk_api_set_hide_rules(usbdk_api_wrapper *usbdk_api, HANDLE hider_handle, gchar *redirect_on_connect);
+BOOL usbdk_clear_hide_rules(usbdk_api_wrapper *usbdk_api, HANDLE hider_handle);
+void usbdk_close_hider_handle(usbdk_api_wrapper *usbdk_api, HANDLE hider_handle);
+#endif