[Wine-patches] [6/10] Implement IoRegisterDeviceInterface and IoSetDeviceInterfaceState.
Alexander Morozov
=?iso-8859-1?q?amorozov_=CE=C1_etersoft=2Eru?=
Пн Ноя 24 19:01:51 MSK 2008
----------- следующая часть -----------
From 9a891300928443808cfc3b97a927d7d804f72515 Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Mon, 24 Nov 2008 17:47:30 +0300
Subject: [PATCH] Implement IoRegisterDeviceInterface and IoSetDeviceInterfaceState.
---
dlls/ntoskrnl.exe/Makefile.in | 2 +-
dlls/ntoskrnl.exe/ntoskrnl.c | 193 ++++++++++++++++++++++++++++++++++++++-
dlls/wineusbhub/wineusbhub.c | 52 +++++++++-
dlls/wineusbhub/wineusbhub.spec | 4 +
include/cfgmgr32.h | 1 +
programs/winedevice/device.c | 3 +-
programs/wineusb/main.c | 38 +++++++-
7 files changed, 278 insertions(+), 15 deletions(-)
diff --git a/dlls/ntoskrnl.exe/Makefile.in b/dlls/ntoskrnl.exe/Makefile.in
index f7787d8..3c63e8e 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
+IMPORTS = kernel32 ntdll wineusbhub setupapi
C_SRCS = \
ntoskrnl.c
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 18ad4e5..7d2319b 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -31,6 +31,11 @@
#include "windef.h"
#include "winternl.h"
#include "winioctl.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "setupapi.h"
+#include "cfgmgr32.h"
#include "excpt.h"
#include "ddk/ntddk.h"
#include "wine/unicode.h"
@@ -42,6 +47,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(ntoskrnl);
WINE_DECLARE_DEBUG_CHANNEL(relay);
+extern UNICODE_STRING *__wine_usbhub_get_pdo_name();
+extern char *__wine_usbhub_get_instance_id();
+extern USHORT __wine_usbhub_get_vid();
+extern USHORT __wine_usbhub_get_pid();
+
KSYSTEM_TIME KeTickCount = { 0, 0, 0 };
typedef struct _KSERVICE_TABLE_DESCRIPTOR
@@ -364,6 +374,8 @@ NTSTATUS wine_ntoskrnl_main_loop( HANDLE stop_event )
HeapFree( GetProcessHeap(), 0, out_buff );
if (out_size) out_buff = HeapAlloc( GetProcessHeap(), 0, out_size );
else out_buff = NULL;
+ while (device->AttachedDevice)
+ device = device->AttachedDevice;
status = process_ioctl( device, code, in_buff, in_size, out_buff, &out_size );
break;
case STATUS_BUFFER_OVERFLOW:
@@ -782,10 +794,102 @@ NTSTATUS WINAPI IoRegisterDeviceInterface( PDEVICE_OBJECT PhysicalDeviceObject,
PUNICODE_STRING ReferenceString,
PUNICODE_STRING SymbolicLinkName )
{
- FIXME( "%p %s %s %p\n", PhysicalDeviceObject,
+ /* Now this function is implemented only for USB devices */
+ static const WCHAR usb[] = {'U','S','B',0};
+ static const WCHAR link_name[] = {'\\','\?','\?','\\','U','S','B','#',
+ 'V','i','d','_','%','0','4','x','&','P','i','d','_','%','0','4','x',
+ '#','%','s','#','%','s',0};
+ static const WCHAR device_name[] = {'U','S','B','\\','V','i','d','_',
+ '%','0','4','x','&','P','i','d','_','%','0','4','x',0};
+ PWSTR buf, hardware_id;
+ UNICODE_STRING guid_str;
+ WCHAR instance_id[MAX_DEVICE_ID_LEN];
+ char *inst_ptr;
+ HDEVINFO set;
+ SP_DEVINFO_DATA devInfo = { 0 };
+ DWORD i = 0;
+ int found = 0;
+ NTSTATUS status = STATUS_UNSUCCESSFUL;
+
+ TRACE( "%p %s %s %p\n", PhysicalDeviceObject,
debugstr_guid(InterfaceClassGuid), debugstr_us(ReferenceString),
SymbolicLinkName );
- return STATUS_SUCCESS;
+
+ inst_ptr = __wine_usbhub_get_instance_id();
+ RtlMultiByteToUnicodeN( instance_id, MAX_DEVICE_ID_LEN, NULL,
+ inst_ptr, strlen( inst_ptr ) );
+ instance_id[strlen( inst_ptr )] = 0;
+
+ buf = RtlAllocateHeap( GetProcessHeap(), 0, (strlenW( link_name )
+ + strlenW( instance_id ) + 34 /* 37 - 4 + 1 */ ) * sizeof(WCHAR) );
+ if (NULL == buf)
+ return STATUS_NO_MEMORY;
+ if (STATUS_SUCCESS != RtlStringFromGUID( InterfaceClassGuid, &guid_str ))
+ {
+ RtlFreeHeap( GetProcessHeap(), 0, buf );
+ /* RtlStringFromGUID returns STATUS_NO_MEMORY if unsuccessful */
+ return STATUS_NO_MEMORY;
+ }
+ /* guid_str.Buffer contains null-terminated string */
+ sprintfW( buf, link_name, __wine_usbhub_get_vid(),
+ __wine_usbhub_get_pid(), instance_id, guid_str.Buffer );
+ RtlFreeUnicodeString( &guid_str );
+
+ hardware_id = RtlAllocateHeap( GetProcessHeap(), 0,
+ (strlenW( device_name ) + 1) * sizeof(WCHAR) );
+ if (NULL == hardware_id)
+ {
+ RtlFreeHeap( GetProcessHeap(), 0, buf );
+ return STATUS_NO_MEMORY;
+ }
+ sprintfW( hardware_id, device_name, __wine_usbhub_get_vid(),
+ __wine_usbhub_get_pid(), instance_id );
+
+ set = SetupDiGetClassDevsW( NULL, usb, NULL, DIGCF_ALLCLASSES );
+ if (INVALID_HANDLE_VALUE == set)
+ {
+ RtlFreeHeap( GetProcessHeap(), 0, buf );
+ return STATUS_UNSUCCESSFUL;
+ }
+ devInfo.cbSize = sizeof(devInfo);
+ while (!found && SetupDiEnumDeviceInfo( set, i++, &devInfo ))
+ {
+ PWSTR id;
+ DWORD size;
+
+ SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_HARDWAREID,
+ NULL, NULL, 0, &size );
+ id = RtlAllocateHeap( GetProcessHeap(), 0, size );
+ if (NULL == id)
+ {
+ status = STATUS_NO_MEMORY;
+ break;
+ }
+ if (SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_HARDWAREID,
+ NULL, (PBYTE)id, size, NULL ))
+ while (*id)
+ {
+ if (!strcmpiW( id, hardware_id ))
+ {
+ found = 1;
+ if (SetupDiCreateDeviceInterfaceW( set, &devInfo,
+ InterfaceClassGuid, NULL, 0, NULL ))
+ status = STATUS_SUCCESS;
+ break;
+ }
+ id += strlenW( id ) + 1;
+ }
+ RtlFreeHeap( GetProcessHeap(), 0, id );
+ }
+ RtlFreeHeap( GetProcessHeap(), 0, hardware_id );
+ SetupDiDestroyDeviceInfoList( set );
+
+ if (STATUS_SUCCESS == status)
+ RtlInitUnicodeString( SymbolicLinkName, buf );
+ else
+ RtlFreeHeap( GetProcessHeap(), 0, buf );
+
+ return status;
}
/***********************************************************************
@@ -824,8 +928,89 @@ NTSTATUS WINAPI IoDeleteSymbolicLink( UNICODE_STRING *name )
NTSTATUS WINAPI IoSetDeviceInterfaceState( PUNICODE_STRING SymbolicLinkName,
BOOLEAN Enable )
{
- FIXME( "%s %d\n", debugstr_us(SymbolicLinkName), Enable );
- return STATUS_SUCCESS;
+ NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
+
+ TRACE( "%s %d\n", debugstr_us(SymbolicLinkName), Enable );
+
+ if (Enable)
+ {
+ HDEVINFO set;
+ UNICODE_STRING link_name;
+ DWORD i, k = 0;
+ SP_DEVICE_INTERFACE_DATA ifaceData;
+ SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail;
+ SIZE_T size;
+ GUID guid;
+ WCHAR buf[39];
+ UNICODE_STRING guid_str;
+ BOOL copy = FALSE;
+
+ for (i = 0; i < (SymbolicLinkName->Length / sizeof(WCHAR)) && k < 38; ++i)
+ {
+ if (SymbolicLinkName->Buffer[i] == '{')
+ copy = TRUE;
+ if (copy)
+ buf[k++] = SymbolicLinkName->Buffer[i];
+ }
+ if (k != 38)
+ return STATUS_INVALID_PARAMETER;
+ buf[38] = 0;
+ RtlInitUnicodeString( &guid_str, buf );
+ if (STATUS_SUCCESS != RtlGUIDFromString( &guid_str, &guid ))
+ return STATUS_INVALID_PARAMETER;
+
+ set = SetupDiGetClassDevsW( &guid, NULL, NULL, DIGCF_DEVICEINTERFACE );
+ if (INVALID_HANDLE_VALUE == set)
+ return STATUS_UNSUCCESSFUL;
+ ifaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+ size = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + SymbolicLinkName->Length;
+ detail = HeapAlloc( GetProcessHeap(), 0, size );
+ if (NULL != detail)
+ {
+ i = 0;
+ detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
+ while (SetupDiEnumDeviceInterfaces( set, NULL, &guid, i++, &ifaceData ))
+ {
+ if (SetupDiGetDeviceInterfaceDetailW( set, &ifaceData, detail,
+ size, NULL, NULL))
+ if (!strncmpiW( SymbolicLinkName->Buffer + 3,
+ detail->DevicePath + 3,
+ SymbolicLinkName->Length / sizeof(WCHAR) - 3 ))
+ {
+ static const WCHAR DosDevices[] =
+ {'\\','D','o','s','D','e','v','i','c','e','s',0};
+ PWSTR ptr;
+
+ ptr = HeapAlloc( GetProcessHeap(), 0,
+ (strlenW( detail->DevicePath ) - 3
+ + strlenW( DosDevices ) + 1) * sizeof(WCHAR) );
+ if (NULL != ptr)
+ {
+ strcpyW( ptr, DosDevices );
+ strcatW( ptr, detail->DevicePath + 3 );
+ RtlInitUnicodeString( &link_name, ptr );
+ status = IoCreateSymbolicLink( &link_name,
+ __wine_usbhub_get_pdo_name() );
+ HeapFree( GetProcessHeap(), 0, ptr );
+ }
+ else
+ status = STATUS_NO_MEMORY;
+ break;
+ }
+ }
+ HeapFree( GetProcessHeap(), 0, detail );
+ }
+ else
+ status = STATUS_NO_MEMORY;
+ SetupDiDestroyDeviceInfoList( set );
+ }
+ else
+ {
+ FIXME( "Disabling interface is not supported\n" );
+ status = STATUS_NOT_IMPLEMENTED;
+ }
+
+ return status;
}
diff --git a/dlls/wineusbhub/wineusbhub.c b/dlls/wineusbhub/wineusbhub.c
index a7985cf..eb94445 100644
--- a/dlls/wineusbhub/wineusbhub.c
+++ b/dlls/wineusbhub/wineusbhub.c
@@ -31,6 +31,7 @@
#include "windef.h"
#include "winbase.h"
#include "winternl.h"
+#include "cfgmgr32.h"
#include "ddk/ntddk.h"
#include "ddk/usb.h"
#include "wine/unicode.h"
@@ -42,8 +43,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(wineusbhub);
extern void WINAPI IofCompleteRequest( IRP *irp, UCHAR priority_boost );
DRIVER_OBJECT hubdrv;
-DEVICE_OBJECT *usbdev; /* USB PDO */
+DEVICE_OBJECT *usbdev = NULL; /* USB PDO */
static struct usb_device *dev;
+WCHAR bufW[20];
+UNICODE_STRING pdo_name = {0, 0, NULL};
+char instance_id[MAX_DEVICE_ID_LEN] = {0};
static void add_data( char **dst, int *dst_size, void *src, int src_size )
{
@@ -249,21 +253,21 @@ DEVICE_OBJECT *__wine_usbhub_get_pdo( UCHAR *pdo_info )
#if defined(HAVE_LIBUSB) && defined(HAVE_USB_H)
static const WCHAR usbpdoW[] = {'\\','D','e','v','i','c','e','\\',
'U','S','B','P','D','O','-','%','u',0};
- static WCHAR bufW[20];
- UNICODE_STRING pdo_name;
struct usb_bus *bus;
- TRACE( "%u, %s, %s\n", pdo_info[0], pdo_info + 1,
- pdo_info + 2 + strlen( (char *)(pdo_info + 1) ) );
+ TRACE( "%u, %s, %s, %s\n", pdo_info[0], debugstr_a((char *)pdo_info + 1),
+ debugstr_a((char *)pdo_info + 2 + PATH_MAX),
+ debugstr_a((char *)pdo_info + 3 + 2 * PATH_MAX) );
for (bus = usb_busses; bus; bus = bus->next)
for (dev = bus->devices; dev; dev = dev->next)
if (!strcmp( bus->dirname, (char *)(pdo_info + 1) ) &&
- !strcmp( dev->filename, (char *)(pdo_info + 2 + strlen( bus->dirname )) ))
+ !strcmp( dev->filename, (char *)(pdo_info + 2 + PATH_MAX) ))
{
hubdrv.MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = __wine_usbhub_internal_ioctl;
hubdrv.MajorFunction[IRP_MJ_PNP] = __wine_usbhub_dispatch_pnp;
+ strcpy( instance_id, (char *)pdo_info + 3 + 2 * PATH_MAX );
snprintfW( bufW, sizeof(bufW), usbpdoW, pdo_info[0] );
RtlInitUnicodeString( &pdo_name, bufW );
@@ -277,6 +281,42 @@ DEVICE_OBJECT *__wine_usbhub_get_pdo( UCHAR *pdo_info )
return NULL;
}
+UNICODE_STRING *__wine_usbhub_get_pdo_name()
+{
+#if defined(HAVE_LIBUSB) && defined(HAVE_USB_H)
+ if (pdo_name.Length)
+ return &pdo_name;
+#endif
+ return NULL;
+}
+
+char *__wine_usbhub_get_instance_id()
+{
+#if defined(HAVE_LIBUSB) && defined(HAVE_USB_H)
+ if (*instance_id)
+ return instance_id;
+#endif
+ return NULL;
+}
+
+USHORT __wine_usbhub_get_vid()
+{
+#if defined(HAVE_LIBUSB) && defined(HAVE_USB_H)
+ if (usbdev != NULL)
+ return dev->descriptor.idVendor;
+#endif
+ return 0;
+}
+
+USHORT __wine_usbhub_get_pid()
+{
+#if defined(HAVE_LIBUSB) && defined(HAVE_USB_H)
+ if (usbdev != NULL)
+ return dev->descriptor.idProduct;
+#endif
+ return 0;
+}
+
BOOL WINAPI DllMain( HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv )
{
#if defined(HAVE_LIBUSB) && defined(HAVE_USB_H)
diff --git a/dlls/wineusbhub/wineusbhub.spec b/dlls/wineusbhub/wineusbhub.spec
index 85e5361..f277e0e 100644
--- a/dlls/wineusbhub/wineusbhub.spec
+++ b/dlls/wineusbhub/wineusbhub.spec
@@ -5,3 +5,7 @@
# or 'wine_' (for user-visible functions) to avoid namespace conflicts.
@ cdecl __wine_usbhub_get_pdo(ptr)
+@ cdecl __wine_usbhub_get_pdo_name()
+@ cdecl __wine_usbhub_get_instance_id()
+@ cdecl __wine_usbhub_get_vid()
+@ cdecl __wine_usbhub_get_pid()
diff --git a/include/cfgmgr32.h b/include/cfgmgr32.h
index a4a4fc0..9d00b5a 100644
--- a/include/cfgmgr32.h
+++ b/include/cfgmgr32.h
@@ -90,6 +90,7 @@ typedef DWORD CONFIGRET;
#define CR_INVALID_STRUCTURE_SIZE 0x3b
#define NUM_CR_RESULTS 0x3c
+#define MAX_DEVICE_ID_LEN 200
#define MAX_CLASS_NAME_LEN 32
#define MAX_GUID_STRING_LEN 39
#define MAX_PROFILE_LEN 80
diff --git a/programs/winedevice/device.c b/programs/winedevice/device.c
index bd11da9..e6b11b0 100644
--- a/programs/winedevice/device.c
+++ b/programs/winedevice/device.c
@@ -35,6 +35,7 @@
#include "winreg.h"
#include "winnls.h"
#include "winsvc.h"
+#include "cfgmgr32.h"
#include "ddk/ntddk.h"
#include "wine/unicode.h"
#include "wine/server.h"
@@ -292,7 +293,7 @@ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
NTSTATUS (WINAPI *AddDevice)( PDRIVER_OBJECT, PDEVICE_OBJECT ) =
driver_extension.AddDevice;
PDEVICE_OBJECT pdev_obj = NULL;
- UCHAR pdo_info[2 * PATH_MAX + 3];
+ UCHAR pdo_info[2 * PATH_MAX + 3 + MAX_DEVICE_ID_LEN];
data_size_t reply_size = 0;
while (!reply_size)
diff --git a/programs/wineusb/main.c b/programs/wineusb/main.c
index 51fcd3c..d0957d0 100644
--- a/programs/wineusb/main.c
+++ b/programs/wineusb/main.c
@@ -37,6 +37,7 @@
#include "winsvc.h"
#include "winuser.h"
#include "setupapi.h"
+#include "cfgmgr32.h"
#include "ddk/wdm.h"
#include "ddk/usb.h"
#include "wine/unicode.h"
@@ -144,7 +145,8 @@ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
{
struct DeviceInstance *instance, *instance2;
UNICODE_STRING drvname;
- UCHAR pdo_info[2 * PATH_MAX + 3] = {0};
+ UCHAR pdo_info[2 * PATH_MAX + 3 + MAX_DEVICE_ID_LEN] = {0};
+ char instance_id[MAX_DEVICE_ID_LEN];
struct usb_device *dev;
struct usb_bus *bus;
SP_DEVINFO_DATA devInfo = { sizeof(devInfo), { 0 } };
@@ -193,6 +195,32 @@ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
pid = strtol( str, NULL, 16 );
HeapFree( GetProcessHeap(), 0, buf );
+ SetupDiGetDeviceInstanceIdA( set, &devInfo, NULL, 0, &size );
+ buf = HeapAlloc( GetProcessHeap(), 0, size );
+ if (buf == NULL)
+ {
+ WINE_ERR( "insufficient memory\n" );
+ continue;
+ }
+ ret = SetupDiGetDeviceInstanceIdA( set, &devInfo, (PSTR)buf, size, NULL );
+ if (!ret)
+ {
+ WINE_ERR( "SetupDiGetDeviceInstanceIdA failed\n" );
+ HeapFree( GetProcessHeap(), 0, buf );
+ continue;
+ }
+ str = strrchr( (char *)buf, '\\' );
+ if (str != NULL)
+ ++str;
+ if (str == NULL || *str == 0 || strlen( str ) >= MAX_DEVICE_ID_LEN)
+ {
+ WINE_ERR( "bad instance ID\n" );
+ HeapFree( GetProcessHeap(), 0, buf );
+ continue;
+ }
+ strcpy( instance_id, str );
+ HeapFree( GetProcessHeap(), 0, buf );
+
for (bus = usb_busses; bus && ret; bus = bus->next)
for (dev = bus->devices; dev && ret; dev = dev->next)
if (dev->descriptor.idVendor == vid &&
@@ -247,8 +275,12 @@ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
}
RtlInitUnicodeString( &drvname, (PWSTR)buf );
- strcpy( (char *)(pdo_info + 1), bus->dirname );
- strcpy( (char *)(pdo_info + 2 + strlen( bus->dirname )), dev->filename );
+ str = (char *)pdo_info + 1;
+ strcpy( str, bus->dirname );
+ str += 1 + PATH_MAX;
+ strcpy( str, dev->filename );
+ str += 1 + PATH_MAX;
+ strcpy( str, instance_id );
SERVER_START_REQ( call_add_device )
{
--
1.6.0.2.GIT
Подробная информация о списке рассылки Wine-patches