From: Aric Stewart Subject: [PATCH v2 6/8] wineplugplay.sys: Watch for hid raw device addition and removal Message-Id: Date: Mon, 22 Aug 2016 09:20:06 -0500 Includes an implementation of a common HID_PNP_RemoveDevice Signed-off-by: Aric Stewart --- dlls/wineplugplay.sys/bus_hid_common.c | 16 ++++++++++ dlls/wineplugplay.sys/bus_hidraw.c | 53 +++++++++++++++++++++++++++++++++- dlls/wineplugplay.sys/pnp.h | 1 + 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/dlls/wineplugplay.sys/bus_hid_common.c b/dlls/wineplugplay.sys/bus_hid_common.c index d9377a4..787f3fc 100644 --- a/dlls/wineplugplay.sys/bus_hid_common.c +++ b/dlls/wineplugplay.sys/bus_hid_common.c @@ -162,6 +162,22 @@ DEVICE_OBJECT *HID_PNP_CreateDevice(DRIVER_OBJECT *driver, const WCHAR *busidW, return device; } +void HID_PNP_RemoveDevice(void* device) +{ + pnp_device *dev, *ptr; + TRACE_(plugplay)("Remove device %p\n", device); + LIST_FOR_EACH_ENTRY_SAFE(dev, ptr, &pnp_devset, pnp_device, entry) + { + if (dev->device == device) + { + list_remove(&dev->entry); + HeapFree(GetProcessHeap(), 0, dev); + PNP_IoInvalidateDeviceRelations(device, RemovalRelations); + break; + } + } +} + NTSTATUS WINAPI HID_PNP_Dispatch(DEVICE_OBJECT *device, IRP *irp) { NTSTATUS rc = STATUS_NOT_SUPPORTED; diff --git a/dlls/wineplugplay.sys/bus_hidraw.c b/dlls/wineplugplay.sys/bus_hidraw.c index 5193236..a8955a6 100644 --- a/dlls/wineplugplay.sys/bus_hidraw.c +++ b/dlls/wineplugplay.sys/bus_hidraw.c @@ -56,6 +56,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(plugplay); #ifdef SONAME_LIBUDEV static DRIVER_OBJECT *hr_driver_obj = NULL; +static HANDLE device_loop_handle; #include "initguid.h" DEFINE_GUID(GUID_DEVCLASS_HIDRAW, 0x3def44ad,0x242e,0x46e5,0x82,0x6d,0x70,0x72,0x13,0xf3,0xaa,0x81); @@ -106,11 +107,20 @@ static void TryAddDevice(void *dev) static VOID WINAPI Unload(DRIVER_OBJECT *driver) { TRACE("Linux Hidraw Driver Unload\n"); + + /* TODO: Signal the device loop to stop */ + + WaitForSingleObject(device_loop_handle, INFINITE); } /* This is our main even loop for reading devices */ static DWORD CALLBACK deviceloop_thread(VOID *args) { + fd_set fds; + int nfds; + struct timeval timeout; + struct udev_monitor *monitor; + int monitor_fd; static const char *subsystems[] = {"hidraw", 0}; if (udev) @@ -130,6 +140,47 @@ static DWORD CALLBACK deviceloop_thread(VOID *args) /* PNP Bus initialization */ UDEV_BuildInitialDeviceSet(udev, subsystems, TryAddDevice); + monitor = udev_monitor_new_from_netlink(udev, "udev"); + udev_monitor_filter_add_match_subsystem_devtype(monitor, "hidraw", NULL); + udev_monitor_enable_receiving(monitor); + monitor_fd = udev_monitor_get_fd(monitor); + + /* Run the event loop */ + while (1) + { + FD_ZERO(&fds); + FD_SET(monitor_fd, &fds); + nfds = monitor_fd + 1; + if (nfds) + { + int rc; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + rc = select(nfds + 1, &fds, NULL, NULL, &timeout); + if (rc > 0) + { + if (FD_ISSET(monitor_fd, &fds)) + { + struct udev_device *dev; + const char* action; + + TRACE_(plugplay)("udev reports device changes\n"); + dev = udev_monitor_receive_device(monitor); + action = udev_device_get_action(dev); + if (strcmp(action, "add") == 0) + TryAddDevice(dev); + else if (strcmp(action, "remove") == 0) + { + HID_PNP_RemoveDevice(dev); + udev_device_unref(dev); + } + } + } + } + else + sleep(1); + } + return 1; } @@ -147,7 +198,7 @@ NTSTATUS WINAPI udevraw_DriverInit(DRIVER_OBJECT *driver, UNICODE_STRING *Regist return STATUS_SUCCESS; } - CreateThread(NULL, 0, deviceloop_thread, NULL, 0, NULL); + device_loop_handle = CreateThread(NULL, 0, deviceloop_thread, NULL, 0, NULL); return STATUS_SUCCESS; } diff --git a/dlls/wineplugplay.sys/pnp.h b/dlls/wineplugplay.sys/pnp.h index a2c7ccf..99c7ebf 100644 --- a/dlls/wineplugplay.sys/pnp.h +++ b/dlls/wineplugplay.sys/pnp.h @@ -25,6 +25,7 @@ VOID PNP_IoInvalidateDeviceRelations(DEVICE_OBJECT *DeviceObject, DEVICE_RELATIO /* HID Plug and Play Bus */ DEVICE_OBJECT *HID_PNP_CreateDevice(DRIVER_OBJECT *driver, const WCHAR *busidW, LPVOID native, WORD vid, WORD pid, DWORD version, DWORD uid, const WCHAR *serial, BOOL isGamepad, const GUID *class) DECLSPEC_HIDDEN; +void HID_PNP_RemoveDevice(void* device) DECLSPEC_HIDDEN; NTSTATUS WINAPI HID_PNP_Dispatch(DEVICE_OBJECT *device, IRP *irp) DECLSPEC_HIDDEN; DWORD HID_check_BusDisabled(UNICODE_STRING *RegistryPath) DECLSPEC_HIDDEN;