[Wine-patches] [14/23] ntoskrnl.exe: Partially implement IoInvalidateDeviceRelations.

Alexander Morozov =?iso-8859-1?q?amorozov_=CE=C1_etersoft=2Eru?=
Пн Янв 19 18:24:40 MSK 2009


For eterhack branch
----------- следующая часть -----------
From ca463407bb8937f939b2215aab1ad67b733b43a0 Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Thu, 15 Jan 2009 12:32:17 +0300
Subject: [PATCH] ntoskrnl.exe: Partially implement IoInvalidateDeviceRelations.

---
 dlls/ntoskrnl.exe/Makefile.in       |    2 +-
 dlls/ntoskrnl.exe/ntoskrnl.c        |  191 ++++++++++++++++++++++++++++++++++-
 dlls/ntoskrnl.exe/ntoskrnl.exe.spec |    2 +
 include/ddk/wdm.h                   |    5 +
 4 files changed, 196 insertions(+), 4 deletions(-)

diff --git a/dlls/ntoskrnl.exe/Makefile.in b/dlls/ntoskrnl.exe/Makefile.in
index 1cd60dc..d6d8540 100644
--- a/dlls/ntoskrnl.exe/Makefile.in
+++ b/dlls/ntoskrnl.exe/Makefile.in
@@ -4,7 +4,7 @@ SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = ntoskrnl.exe
 IMPORTLIB = ntoskrnl.exe
-IMPORTS   = kernel32 ntdll setupapi
+IMPORTS   = kernel32 ntdll setupapi advapi32
 
 C_SRCS = \
 	ntoskrnl.c
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 3b27024..094f0f3 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -32,6 +32,7 @@
 #include "winternl.h"
 #include "winioctl.h"
 #include "winbase.h"
+#include "winsvc.h"
 #include "winuser.h"
 #include "winreg.h"
 #include "setupapi.h"
@@ -134,12 +135,90 @@ struct InterfaceInstance
                        "jmp " __ASM_NAME("__regs_") #name )
 #endif
 
+NTSTATUS WINAPI __regs_IofCallDriver( DEVICE_OBJECT *device, IRP *irp );
+
 static inline LPCSTR debugstr_us( const UNICODE_STRING *us )
 {
     if (!us) return "<null>";
     return debugstr_wn( us->Buffer, us->Length / sizeof(WCHAR) );
 }
 
+static BOOL start_service( WCHAR *name )
+{
+    SC_HANDLE scm, service;
+    BOOL ret;
+
+    scm = OpenSCManagerA( NULL, NULL, SC_MANAGER_ALL_ACCESS );
+    if (scm == NULL)
+        return FALSE;
+
+    service = OpenServiceW( scm, name, SERVICE_ALL_ACCESS );
+    if (service == NULL)
+    {
+        CloseServiceHandle( scm );
+        return FALSE;
+    }
+
+    ret = StartServiceW( service, 0, NULL );
+    if (!ret && ERROR_SERVICE_ALREADY_RUNNING == GetLastError())
+        ret = TRUE;
+
+    CloseServiceHandle( service );
+    CloseServiceHandle( scm );
+
+    return ret;
+}
+
+/* get name of driver service for device with given id */
+static BOOL get_service( WCHAR *device_id, WCHAR **service_name )
+{
+    SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
+    HDEVINFO set;
+    WCHAR *ptr, *enum_name, *id = NULL;
+    DWORD size, i = 0;
+    BOOL ret;
+
+    *service_name = NULL;
+    ptr = strchrW( device_id, '\\' );
+    if (!ptr) return FALSE;
+    size = ptr - device_id + 1;
+    enum_name = RtlAllocateHeap( GetProcessHeap(), 0, size * sizeof(WCHAR) );
+    if (!enum_name) return FALSE;
+    lstrcpynW( enum_name, device_id, size );
+
+    set = SetupDiGetClassDevsW( NULL, enum_name, 0, DIGCF_ALLCLASSES );
+    if (set == INVALID_HANDLE_VALUE) goto end;
+    while (SetupDiEnumDeviceInfo( set, i++, &devInfo ))
+    {
+        SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_HARDWAREID,
+                NULL, NULL, 0, &size );
+        if (id) RtlFreeHeap( GetProcessHeap(), 0, id );
+        id = RtlAllocateHeap( GetProcessHeap(), 0, size );
+        if (!id) break;
+        ret = SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_HARDWAREID,
+                NULL, (BYTE *)id, size, NULL );
+        if (!ret) break;
+        if (strcmpiW( device_id, id )) continue;
+        SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE,
+                NULL, NULL, 0, &size );
+        *service_name = RtlAllocateHeap( GetProcessHeap(), 0, size );
+        if (!*service_name) break;
+        ret = SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_SERVICE,
+                NULL, (BYTE *)*service_name, size, NULL );
+        if (!ret)
+        {
+            RtlFreeHeap( GetProcessHeap(), 0, *service_name );
+            *service_name = NULL;
+            break;
+        }
+    }
+    SetupDiDestroyDeviceInfoList( set );
+end:
+    if (id) RtlFreeHeap( GetProcessHeap(), 0, id );
+    if (enum_name) RtlFreeHeap( GetProcessHeap(), 0, enum_name );
+    return (*service_name != NULL);
+}
+
 static HANDLE get_device_manager(void)
 {
     static HANDLE device_manager;
@@ -226,8 +305,6 @@ static void save_pid( DWORD pid )
     LeaveCriticalSection( &cs );
 }
 
-NTSTATUS WINAPI __regs_IofCallDriver( DEVICE_OBJECT *device, IRP *irp );
-
 /* process an ioctl request for a given device */
 static NTSTATUS process_ioctl( DEVICE_OBJECT *device, ULONG code, void *in_buff, ULONG in_size,
                                void *out_buff, ULONG *out_size )
@@ -426,6 +503,57 @@ DRIVER_OBJECT * CDECL __wine_get_driver_object( const WCHAR *service )
 
 
 /***********************************************************************
+ *           __wine_add_device   (Not a Windows API)
+ */
+NTSTATUS CDECL __wine_add_device( DRIVER_OBJECT *driver, DEVICE_OBJECT *dev )
+{
+    NTSTATUS status;
+    NTSTATUS (WINAPI *AddDevice)( PDRIVER_OBJECT, PDEVICE_OBJECT ) =
+            driver->DriverExtension->AddDevice;
+
+    if (TRACE_ON(relay))
+        DPRINTF( "%04x:Call AddDevice %p (%p,%p)\n",
+                 GetCurrentThreadId(), AddDevice, driver, dev );
+
+    status = AddDevice( driver, dev );
+
+    if (TRACE_ON(relay))
+        DPRINTF( "%04x:Ret  AddDevice %p (%p,%p) retval=%08x\n",
+                 GetCurrentThreadId(), AddDevice, driver, dev, status );
+
+    return status;
+}
+
+
+/***********************************************************************
+ *           __wine_start_device   (Not a Windows API)
+ */
+NTSTATUS CDECL __wine_start_device( DRIVER_OBJECT *driver )
+{
+    DEVICE_OBJECT *device = driver->DeviceObject;
+    IO_STACK_LOCATION *irpsp;
+    PIRP irp;
+    NTSTATUS status;
+
+    if (driver->MajorFunction[IRP_MJ_PNP] == NULL)
+        return STATUS_NOT_SUPPORTED;
+    irp = IoAllocateIrp( device->StackSize, FALSE );
+    if (irp == NULL) return STATUS_NO_MEMORY;
+
+    irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation - 1;
+    irp->RequestorMode = KernelMode;
+    irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
+    irpsp->MajorFunction = IRP_MJ_PNP;
+    irpsp->MinorFunction = IRP_MN_START_DEVICE;
+    irpsp->DeviceObject = device;
+    device->CurrentIrp = irp;
+    status = __regs_IofCallDriver( device, irp );
+    IoFreeIrp( irp );
+    return status;
+}
+
+
+/***********************************************************************
  *           ExAcquireFastMutexUnsafe  (NTOSKRNL.EXE.@)
  */
 #ifdef DEFINE_FASTCALL1_ENTRYPOINT
@@ -911,7 +1039,64 @@ NTSTATUS WINAPI IoCreateSymbolicLink( UNICODE_STRING *name, UNICODE_STRING *targ
 void WINAPI IoInvalidateDeviceRelations( PDEVICE_OBJECT DeviceObject,
                                          DEVICE_RELATION_TYPE Type )
 {
-    FIXME( "%p, %u\n", DeviceObject, Type );
+    TRACE( "%p, %u\n", DeviceObject, Type );
+
+    while (DeviceObject->AttachedDevice)
+        DeviceObject = DeviceObject->AttachedDevice;
+    if (Type == BusRelations)
+    {
+        DEVICE_RELATIONS *rel;
+        IO_STACK_LOCATION *irpsp;
+        IRP *irp;
+        NTSTATUS status;
+
+        irp = IoAllocateIrp( DeviceObject->StackSize, FALSE );
+        if (irp == NULL) return;
+        irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation - 1;
+        irpsp->MajorFunction = IRP_MJ_PNP;
+        irpsp->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
+        irpsp->Parameters.QueryDeviceRelations.Type = BusRelations;
+        status = __regs_IofCallDriver( DeviceObject, irp );
+        rel = (DEVICE_RELATIONS *)irp->IoStatus.Information;
+        if (status == STATUS_SUCCESS && rel && rel->Count)
+        {
+            unsigned int k;
+
+            for (k = 0; k < rel->Count; ++k)
+            {
+                IoFreeIrp( irp );
+                irp = IoAllocateIrp( rel->Objects[k]->StackSize, FALSE );
+                if (irp == NULL) return;
+                irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation - 1;
+                irpsp->MajorFunction = IRP_MJ_PNP;
+                irpsp->MinorFunction = IRP_MN_QUERY_ID;
+                irpsp->Parameters.QueryId.IdType = BusQueryDeviceID;
+                status = __regs_IofCallDriver( rel->Objects[k], irp );
+                if (status == STATUS_SUCCESS)
+                {
+                    WCHAR *service;
+
+                    if (get_service( (WCHAR *)irp->IoStatus.Information, &service )
+                        && start_service( service ))
+                    {
+                        DRIVER_OBJECT *driver;
+
+                        while (!(driver = __wine_get_driver_object( service )))
+                            Sleep( 100 );
+                        status = __wine_add_device( driver, rel->Objects[k] );
+                        if (status == STATUS_SUCCESS)
+                            __wine_start_device( driver );
+                    }
+                    if (service) RtlFreeHeap( GetProcessHeap(), 0, service );
+                }
+                ExFreePool( (void *)irp->IoStatus.Information );
+            }
+            ExFreePool( rel );
+        }
+        IoFreeIrp( irp );
+    }
+    else
+        FIXME( "DEVICE_RELATION_TYPE %u not implemented\n", Type );
 }
 
 
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
index 68ab9e2..d123928 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
+++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
@@ -1490,6 +1490,8 @@
 
 @ cdecl wine_ntoskrnl_main_loop(long)
 @ cdecl wine_complete_request(ptr long)
+@ cdecl __wine_add_device(ptr ptr)
 @ cdecl __wine_add_driver_object(ptr wstr)
 @ cdecl __wine_del_driver_object(ptr)
 @ cdecl __wine_get_driver_object(wstr)
+@ cdecl __wine_start_device(ptr)
diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h
index 923bffc..e5f07b5 100644
--- a/include/ddk/wdm.h
+++ b/include/ddk/wdm.h
@@ -1033,6 +1033,11 @@ typedef enum _LOCK_OPERATION {
     IoModifyAccess
 } LOCK_OPERATION;
 
+typedef struct _DEVICE_RELATIONS {
+    ULONG Count;
+    PDEVICE_OBJECT Objects[1];
+} DEVICE_RELATIONS, *PDEVICE_RELATIONS;
+
 NTSTATUS WINAPI ObCloseHandle(IN HANDLE handle);
 
 #define IoGetCurrentIrpStackLocation(_Irp) ((_Irp)->Tail.Overlay.CurrentStackLocation)
-- 
1.6.0.2.GIT



Подробная информация о списке рассылки Wine-patches