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