From: Aric Stewart Subject: [PATCH 3/5] winehidminidriver.sys: PNP support for OS/X Message-Id: <563371FB.30104@codeweavers.com> Date: Fri, 30 Oct 2015 08:34:51 -0500 Signed-off-by: Aric Stewart --- dlls/winehidminidriver.sys/Makefile.in | 2 + dlls/winehidminidriver.sys/hid.h | 8 ++ dlls/winehidminidriver.sys/minidriver_osx.c | 51 ++++++++++- dlls/winehidminidriver.sys/pnp_bus.c | 129 ++++++++++++++++++++++++++++ dlls/winehidminidriver.sys/pnp_manager.c | 55 ++++++++++++ 5 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 dlls/winehidminidriver.sys/pnp_bus.c create mode 100644 dlls/winehidminidriver.sys/pnp_manager.c diff --git a/dlls/winehidminidriver.sys/Makefile.in b/dlls/winehidminidriver.sys/Makefile.in index b2ad5b5..2110847 100644 --- a/dlls/winehidminidriver.sys/Makefile.in +++ b/dlls/winehidminidriver.sys/Makefile.in @@ -5,4 +5,6 @@ EXTRALIBS = $(IOKIT_LIBS) C_SRCS = \ main.c \ + pnp_bus.c \ + pnp_manager.c \ minidriver_osx.c diff --git a/dlls/winehidminidriver.sys/hid.h b/dlls/winehidminidriver.sys/hid.h index 4388620..4424cf0 100644 --- a/dlls/winehidminidriver.sys/hid.h +++ b/dlls/winehidminidriver.sys/hid.h @@ -18,3 +18,11 @@ /* Minidrivers */ NTSTATUS WINAPI osx_DriverInit(DRIVER_OBJECT *driver, UNICODE_STRING *RegistryPath) DECLSPEC_HIDDEN; + +/* Plug and Play Manager */ +VOID HID_IoInvalidateDeviceRelations(DRIVER_OBJECT* driver, void *DeviceObject, DEVICE_RELATION_TYPE Type) DECLSPEC_HIDDEN; + +/* Plug and Play Bus */ +void HID_PNP_AddDevice(DRIVER_OBJECT *driver, void* device) DECLSPEC_HIDDEN; +void HID_PNP_RemoveDevice(DRIVER_OBJECT *driver, void* device) DECLSPEC_HIDDEN; +NTSTATUS Handle_IRP_MN_QUERY_DEVICE_RELATIONS(IRP *irp) DECLSPEC_HIDDEN; diff --git a/dlls/winehidminidriver.sys/minidriver_osx.c b/dlls/winehidminidriver.sys/minidriver_osx.c index 3b02bd6..9cc5d19 100644 --- a/dlls/winehidminidriver.sys/minidriver_osx.c +++ b/dlls/winehidminidriver.sys/minidriver_osx.c @@ -99,6 +99,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(hid_minidriver); #ifdef HAVE_IOHIDMANAGERCREATE WINE_DECLARE_DEBUG_CHANNEL(hid_report); +WINE_DECLARE_DEBUG_CHANNEL(plugplay); typedef struct _OSX_DEVICE_EXTENSTION { uint8_t *last_report; @@ -350,6 +351,7 @@ static NTSTATUS WINAPI osx_internal_ioctl( DEVICE_OBJECT *device, IRP *irp ) static NTSTATUS WINAPI osx_pnp( DEVICE_OBJECT *device, IRP *irp ) { + NTSTATUS rc = STATUS_SUCCESS; IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); switch(irpsp->MinorFunction) @@ -363,9 +365,14 @@ static NTSTATUS WINAPI osx_pnp( DEVICE_OBJECT *device, IRP *irp ) CleanupDevice(device); irp->IoStatus.u.Status = STATUS_SUCCESS; break; + /* PNP IOCTLS around the bus driver */ + case IRP_MN_QUERY_DEVICE_RELATIONS: + rc = Handle_IRP_MN_QUERY_DEVICE_RELATIONS(irp); + irp->IoStatus.u.Status = rc; + break; } IoCompleteRequest( irp, IO_NO_INCREMENT ); - return STATUS_SUCCESS; + return rc; } static NTSTATUS WINAPI osx_power( DEVICE_OBJECT *device, IRP *irp ) @@ -378,6 +385,26 @@ static NTSTATUS WINAPI osx_power( DEVICE_OBJECT *device, IRP *irp ) return STATUS_SUCCESS; } +static void Handle_DeviceMatchingCallback( + void * inContext, + IOReturn inResult, + void * inSender, + IOHIDDeviceRef inIOHIDDeviceRef) +{ + TRACE_(plugplay)("OS/X HID Device Added %p\n", inIOHIDDeviceRef); + HID_PNP_AddDevice(osx_driver_obj, inIOHIDDeviceRef); +} + +static void Handle_RemovalCallback( + void * inContext, + IOReturn inResult, + void * inSender, + IOHIDDeviceRef inIOHIDDeviceRef) +{ + TRACE_(plugplay)("OS/X HID Device Removed %p\n", inIOHIDDeviceRef); + HID_PNP_RemoveDevice(osx_driver_obj, inIOHIDDeviceRef); +} + static void Handle_IOHIDDeviceIOHIDReportCallback( void * inContext, IOReturn inResult, @@ -462,6 +489,7 @@ static DWORD CALLBACK runloop_thread(VOID *args) NTSTATUS WINAPI osx_DriverInit(DRIVER_OBJECT *driver, UNICODE_STRING *RegistryPath) { + CFMutableDictionaryRef result; HANDLE events[2]; TRACE("OS/X Driver Init\n"); @@ -487,6 +515,27 @@ NTSTATUS WINAPI osx_DriverInit(DRIVER_OBJECT *driver, UNICODE_STRING *RegistryPa hid_manager = IOHIDManagerCreate( kCFAllocatorDefault, 0L ); + /* Build matching dictionary */ + result = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); + + if ( result ) + { + int number = kHIDPage_GenericDesktop; + CFNumberRef page = CFNumberCreate( kCFAllocatorDefault, + kCFNumberIntType, &number); + if (page) + { + CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsagePageKey ), page ); + CFRelease( page ); + } + } + IOHIDManagerSetDeviceMatching(hid_manager, result); + CFRelease(result); + + IOHIDManagerRegisterDeviceMatchingCallback( hid_manager, Handle_DeviceMatchingCallback, driver); + IOHIDManagerRegisterDeviceRemovalCallback( hid_manager, Handle_RemovalCallback, driver); + WaitForSingleObject(events[0], INFINITE); IOHIDManagerScheduleWithRunLoop(hid_manager, run_loop, kCFRunLoopDefaultMode); SetEvent(events[1]); diff --git a/dlls/winehidminidriver.sys/pnp_bus.c b/dlls/winehidminidriver.sys/pnp_bus.c new file mode 100644 index 0000000..4ce8ad1 --- /dev/null +++ b/dlls/winehidminidriver.sys/pnp_bus.c @@ -0,0 +1,129 @@ +/* HID plug and play Bus like functionality + * + * Copyright 2015 CodeWeavers, 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 + */ + +#include "config.h" +#include "wine/port.h" +#define NONAMELESSUNION +#include +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "winioctl.h" +#include "ddk/wdm.h" +#include "wine/debug.h" +#include "wine/list.h" +#include "hid.h" + +WINE_DEFAULT_DEBUG_CHANNEL(plugplay); + +typedef struct _pnp_device { + struct list entry; + + void *device; + DRIVER_OBJECT *driver; +} pnp_device; + +struct list pnp_devset = LIST_INIT(pnp_devset); + +void HID_PNP_AddDevice(DRIVER_OBJECT *driver, void* device) +{ + pnp_device *pnp_dev; + + pnp_dev = HeapAlloc(GetProcessHeap(), 0, sizeof(*pnp_dev)); + pnp_dev->device = device; + pnp_dev->driver = driver; + list_add_tail(&pnp_devset, &pnp_dev->entry); + + HID_IoInvalidateDeviceRelations(driver, device, BusRelations); +} + +void HID_PNP_RemoveDevice(DRIVER_OBJECT *driver, void* device) +{ + pnp_device *dev, *ptr; + TRACE_(plugplay)("Remove device %p/%p\n",driver, device); + LIST_FOR_EACH_ENTRY_SAFE(dev, ptr, &pnp_devset, pnp_device, entry) + { + if (dev->driver == driver && dev->device == device) + { + list_remove(&dev->entry); + HeapFree(GetProcessHeap(), 0, dev); + HID_IoInvalidateDeviceRelations(driver, device, RemovalRelations); + break; + } + } +} + +static NTSTATUS HID_PNP_EnumerateDevices(DRIVER_OBJECT *driver, DEVICE_RELATIONS **devices) +{ + int i; + pnp_device *ptr; + + *devices = HeapAlloc(GetProcessHeap(), 0, sizeof(DEVICE_RELATIONS) + + list_count(&pnp_devset) * sizeof (void *)); + + if (!*devices) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + i = 0; + LIST_FOR_EACH_ENTRY(ptr, &pnp_devset, pnp_device, entry) + { + if (ptr->driver == driver) + { + (*devices)->Objects[i] = (DEVICE_OBJECT*)ptr->device; + i++; + } + } + (*devices)->Count = i; + return STATUS_SUCCESS; +} + +NTSTATUS Handle_IRP_MN_QUERY_DEVICE_RELATIONS(IRP *irp) +{ + NTSTATUS rc = STATUS_SUCCESS; + IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); + DRIVER_OBJECT *driver = irpsp->DeviceObject->DriverObject; + + TRACE("IRP_MN_QUERY_DEVICE_RELATIONS"); + switch (irpsp->Parameters.QueryDeviceRelations.Type) + { + case EjectionRelations: + case RemovalRelations: + case TargetDeviceRelation: + case PowerRelations: + FIXME("Unhandled Device Relation %x\n",irpsp->Parameters.QueryDeviceRelations.Type); + irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED; + rc = STATUS_NOT_SUPPORTED; + break; + case BusRelations: + rc = HID_PNP_EnumerateDevices(driver, (DEVICE_RELATIONS**)&irp->IoStatus.Information); + irp->IoStatus.u.Status = rc; + break; + default: + FIXME("Unknown Device Relation %x\n",irpsp->Parameters.QueryDeviceRelations.Type); + irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED; + rc = STATUS_NOT_SUPPORTED; + break; + } + + return rc; +} diff --git a/dlls/winehidminidriver.sys/pnp_manager.c b/dlls/winehidminidriver.sys/pnp_manager.c new file mode 100644 index 0000000..b1d3bd0 --- /dev/null +++ b/dlls/winehidminidriver.sys/pnp_manager.c @@ -0,0 +1,55 @@ +/* HID plug and play Manager like functionality + * + * Copyright 2015 CodeWeavers, 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 + */ + +#include "config.h" +#include "wine/port.h" +#include +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "winioctl.h" +#include "ddk/wdm.h" +#include "wine/debug.h" +#include "hid.h" + +WINE_DEFAULT_DEBUG_CHANNEL(plugplay); + +typedef NTSTATUS WINAPI (*pAddDevice)(DRIVER_OBJECT *DriverObject, DEVICE_OBJECT *PhysicalDeviceObject); + +VOID HID_IoInvalidateDeviceRelations(DRIVER_OBJECT *driver, void *device, DEVICE_RELATION_TYPE type) +{ + TRACE("(%p %p %i)\n",driver, device, type); + + switch (type) + { + case BusRelations: + /* We could(should?) do a full IRP_MN_QUERY_DEVICE_RELATIONS query, + * but we dont have to, We have the DEVICE_OBJECT of the new device + * so we can simply handle the process here */ + ((pAddDevice)driver->DriverExtension->AddDevice)(driver, device); + break; + case RemovalRelations: + FIXME("Device %p removal unhandled\n", device); + break; + default: + FIXME("Unhandled Relation %i\n", type); + } +}