Aric Stewart : hidclass.sys: Add Plug-and-play and AddDevice.
Alexandre Julliard
julliard at wine.codeweavers.com
Fri Sep 11 08:02:19 CDT 2015
Module: wine
Branch: master
Commit: 43888392fac7d926ddcad13298cbb4ef74108482
URL: http://source.winehq.org/git/wine.git/?a=commit;h=43888392fac7d926ddcad13298cbb4ef74108482
Author: Aric Stewart <aric at codeweavers.com>
Date: Wed Sep 9 10:20:11 2015 -0500
hidclass.sys: Add Plug-and-play and AddDevice.
---
dlls/hidclass.sys/Makefile.in | 3 +-
dlls/hidclass.sys/hid.h | 11 ++++
dlls/hidclass.sys/main.c | 50 ++++++++++++++-
dlls/hidclass.sys/pnp.c | 146 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 208 insertions(+), 2 deletions(-)
diff --git a/dlls/hidclass.sys/Makefile.in b/dlls/hidclass.sys/Makefile.in
index 6b474f6..c5c9eb7 100644
--- a/dlls/hidclass.sys/Makefile.in
+++ b/dlls/hidclass.sys/Makefile.in
@@ -5,4 +5,5 @@ DELAYIMPORTS = setupapi hid
C_SRCS = \
device.c \
- main.c
+ main.c \
+ pnp.c
diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h
index 7114312..efa4712 100644
--- a/dlls/hidclass.sys/hid.h
+++ b/dlls/hidclass.sys/hid.h
@@ -33,6 +33,8 @@
#define DEFAULT_POLL_INTERVAL 200
#define MAX_POLL_INTERVAL_MSEC 10000
+typedef NTSTATUS (WINAPI *pAddDevice)(DRIVER_OBJECT *DriverObject, DEVICE_OBJECT *PhysicalDeviceObject);
+
typedef struct _BASE_DEVICE_EXTENSTION {
HID_DEVICE_EXTENSION deviceExtension;
@@ -57,9 +59,18 @@ typedef struct _minidriver
HID_MINIDRIVER_REGISTRATION minidriver;
PDRIVER_UNLOAD DriverUnload;
+
+ pAddDevice AddDevice;
} minidriver;
+NTSTATUS call_minidriver(ULONG code, DEVICE_OBJECT *device, void *in_buff, ULONG in_size, void *out_buff, ULONG out_size) DECLSPEC_HIDDEN;
+minidriver* find_minidriver(DRIVER_OBJECT* driver) DECLSPEC_HIDDEN;
+
/* Internal device functions */
NTSTATUS HID_CreateDevice(DEVICE_OBJECT *native_device, HID_MINIDRIVER_REGISTRATION *driver, DEVICE_OBJECT **device) DECLSPEC_HIDDEN;
NTSTATUS HID_LinkDevice(DEVICE_OBJECT *device, LPCWSTR serial, LPCWSTR index) DECLSPEC_HIDDEN;
void HID_DeleteDevice(HID_MINIDRIVER_REGISTRATION *driver, DEVICE_OBJECT *device) DECLSPEC_HIDDEN;
+
+/* Pseudo-Plug and Play support*/
+NTSTATUS WINAPI PNP_AddDevice(DRIVER_OBJECT *driver, DEVICE_OBJECT* PDO) DECLSPEC_HIDDEN;
+void PNP_CleanupPNP(DRIVER_OBJECT *driver) DECLSPEC_HIDDEN;
diff --git a/dlls/hidclass.sys/main.c b/dlls/hidclass.sys/main.c
index e4844862..a58d9834 100644
--- a/dlls/hidclass.sys/main.c
+++ b/dlls/hidclass.sys/main.c
@@ -30,7 +30,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(hid);
static struct list minidriver_list = LIST_INIT(minidriver_list);
-static minidriver* find_minidriver(DRIVER_OBJECT *driver)
+minidriver* find_minidriver(DRIVER_OBJECT *driver)
{
minidriver *md;
LIST_FOR_EACH_ENTRY(md, &minidriver_list, minidriver, entry)
@@ -51,6 +51,7 @@ static VOID WINAPI UnloadDriver(DRIVER_OBJECT *driver)
{
if (md->DriverUnload)
md->DriverUnload(md->minidriver.DriverObject);
+ PNP_CleanupPNP(md->minidriver.DriverObject);
list_remove(&md->entry);
HeapFree( GetProcessHeap(), 0, md );
}
@@ -67,8 +68,55 @@ NTSTATUS WINAPI HidRegisterMinidriver(HID_MINIDRIVER_REGISTRATION *registration)
driver->DriverUnload = registration->DriverObject->DriverUnload;
registration->DriverObject->DriverUnload = UnloadDriver;
+ driver->AddDevice = registration->DriverObject->DriverExtension->AddDevice;
+ registration->DriverObject->DriverExtension->AddDevice = PNP_AddDevice;
+
driver->minidriver = *registration;
list_add_tail(&minidriver_list, &driver->entry);
return STATUS_SUCCESS;
}
+
+static NTSTATUS WINAPI internalComplete(DEVICE_OBJECT *deviceObject, IRP *irp,
+ void *context )
+{
+ SetEvent(irp->UserEvent);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS call_minidriver(ULONG code, DEVICE_OBJECT *device, void *in_buff, ULONG in_size, void *out_buff, ULONG out_size)
+{
+ IRP *irp;
+ IO_STATUS_BLOCK irp_status;
+ IO_STACK_LOCATION *irpsp;
+ NTSTATUS status;
+ void *buffer = NULL;
+
+ HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
+
+ if (out_size)
+ {
+ buffer = HeapAlloc(GetProcessHeap(), 0, out_size);
+ memcpy(buffer, out_buff, out_size);
+ }
+
+ irp = IoBuildDeviceIoControlRequest(code, device, in_buff, in_size,
+ buffer, out_size, TRUE, event, &irp_status);
+
+ irpsp = IoGetNextIrpStackLocation(irp);
+ irpsp->CompletionRoutine = internalComplete;
+ irpsp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR;
+
+ IoCallDriver(device, irp);
+
+ if (irp->IoStatus.u.Status == STATUS_PENDING)
+ WaitForSingleObject(event, INFINITE);
+
+ memcpy(out_buff, buffer, out_size);
+ status = irp->IoStatus.u.Status;
+
+ IoCompleteRequest(irp, IO_NO_INCREMENT );
+ CloseHandle(event);
+
+ return status;
+}
diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c
new file mode 100644
index 0000000..0fb06a2
--- /dev/null
+++ b/dlls/hidclass.sys/pnp.c
@@ -0,0 +1,146 @@
+/*
+ * WINE HID Pseudo-Plug and Play support
+ *
+ * Copyright 2015 Aric Stewart
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define NONAMELESSUNION
+#include <unistd.h>
+#include <stdarg.h>
+#include "hid.h"
+#include "ddk/hidtypes.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "wine/list.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(hid);
+
+typedef struct _NATIVE_DEVICE {
+ struct list entry;
+
+ DWORD vidpid;
+ DEVICE_OBJECT *PDO;
+ DEVICE_OBJECT *FDO;
+ HID_MINIDRIVER_REGISTRATION *minidriver;
+
+} NATIVE_DEVICE;
+
+static struct list tracked_devices = LIST_INIT(tracked_devices);
+
+NTSTATUS WINAPI PNP_AddDevice(DRIVER_OBJECT *driver, DEVICE_OBJECT *PDO)
+{
+ DEVICE_OBJECT *device = NULL;
+ NTSTATUS status;
+ minidriver *minidriver;
+ HID_DEVICE_ATTRIBUTES attr;
+ BASE_DEVICE_EXTENSION *ext = NULL;
+ WCHAR serial[256];
+ WCHAR interface[256];
+ DWORD index = HID_STRING_ID_ISERIALNUMBER;
+ NATIVE_DEVICE *tracked_device, *ptr;
+ INT interface_index = 1;
+
+ static const WCHAR ig_fmtW[] = {'I','G','_','%','i',0};
+ static const WCHAR im_fmtW[] = {'I','M','_','%','i',0};
+
+
+ TRACE("PDO add device(%p)\n", PDO);
+ minidriver = find_minidriver(driver);
+
+ status = HID_CreateDevice(PDO, &minidriver->minidriver, &device);
+ if (status != STATUS_SUCCESS)
+ {
+ ERR("Failed to create HID object (%x)\n",status);
+ return status;
+ }
+
+ TRACE("Created device %p\n",device);
+ status = minidriver->AddDevice(minidriver->minidriver.DriverObject, device);
+ if (status != STATUS_SUCCESS)
+ {
+ ERR("Minidriver AddDevice failed (%x)\n",status);
+ HID_DeleteDevice(&minidriver->minidriver, device);
+ return status;
+ }
+
+ status = call_minidriver(IOCTL_HID_GET_DEVICE_ATTRIBUTES, device,
+ NULL, 0, &attr, sizeof(attr));
+
+ if (status != STATUS_SUCCESS)
+ {
+ ERR("Minidriver failed to get Attributes(%x)\n",status);
+ HID_DeleteDevice(&minidriver->minidriver, device);
+ return status;
+ }
+
+ ext = device->DeviceExtension;
+ ext->information.VendorID = attr.VendorID;
+ ext->information.ProductID = attr.ProductID;
+ ext->information.VersionNumber = attr.VersionNumber;
+ ext->information.Polled = minidriver->minidriver.DevicesArePolled;
+
+ tracked_device = HeapAlloc(GetProcessHeap(), 0, sizeof(*tracked_device));
+ tracked_device->vidpid = MAKELONG(attr.VendorID, attr.ProductID);
+ tracked_device->PDO = PDO;
+ tracked_device->FDO = device;
+ tracked_device->minidriver = &minidriver->minidriver;
+
+ LIST_FOR_EACH_ENTRY(ptr, &tracked_devices, NATIVE_DEVICE, entry)
+ if (ptr->vidpid == tracked_device->vidpid) interface_index++;
+
+ list_add_tail(&tracked_devices, &tracked_device->entry);
+
+ serial[0] = 0;
+ status = call_minidriver(IOCTL_HID_GET_STRING, device,
+ &index, sizeof(DWORD), serial, sizeof(serial));
+
+ if (serial[0] == 0)
+ {
+ static const WCHAR wZeroSerial[]= {'0','0','0','0',0};
+ lstrcpyW(serial, wZeroSerial);
+ }
+
+ if (ext->preparseData->caps.UsagePage == HID_USAGE_PAGE_GENERIC &&
+ (ext->preparseData->caps.Usage == HID_USAGE_GENERIC_GAMEPAD ||
+ ext->preparseData->caps.Usage == HID_USAGE_GENERIC_JOYSTICK))
+ sprintfW(interface, ig_fmtW, interface_index);
+ else
+ sprintfW(interface, im_fmtW, interface_index);
+
+ HID_LinkDevice(device, serial, interface);
+
+ ext->poll_interval = DEFAULT_POLL_INTERVAL;
+ InitializeListHead(&ext->irp_queue);
+
+ return STATUS_SUCCESS;
+}
+
+void PNP_CleanupPNP(DRIVER_OBJECT *driver)
+{
+ NATIVE_DEVICE *tracked_device, *ptr;
+
+ LIST_FOR_EACH_ENTRY_SAFE(tracked_device, ptr, &tracked_devices,
+ NATIVE_DEVICE, entry)
+ {
+ if (tracked_device->minidriver->DriverObject == driver)
+ {
+ list_remove(&tracked_device->entry);
+ HID_DeleteDevice(tracked_device->minidriver, tracked_device->FDO);
+ HeapFree(GetProcessHeap(), 0, tracked_device);
+ }
+ }
+}
More information about the wine-cvs
mailing list