[Wine-patches] [16/23] ntoskrnl.exe: Improve IoRegisterDeviceInterface implementation.
Alexander Morozov
=?iso-8859-1?q?amorozov_=CE=C1_etersoft=2Eru?=
Пн Янв 19 18:24:59 MSK 2009
For eterhack branch
----------- следующая часть -----------
From 547b82db834dc3b8cb78860f96a810c62676c5c7 Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov на etersoft.ru>
Date: Thu, 15 Jan 2009 12:36:42 +0300
Subject: [PATCH] ntoskrnl.exe: Improve IoRegisterDeviceInterface implementation.
---
dlls/ntoskrnl.exe/ntoskrnl.c | 200 +++++++++++++++++++++---------------------
1 files changed, 101 insertions(+), 99 deletions(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 094f0f3..6ac20cd 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -219,6 +219,44 @@ end:
return (*service_name != NULL);
}
+static NTSTATUS get_device_id( DEVICE_OBJECT *pdo, BUS_QUERY_ID_TYPE id_type,
+ WCHAR **id )
+{
+ NTSTATUS status;
+ IO_STACK_LOCATION *irpsp;
+ IRP *irp;
+
+ *id = NULL;
+ irp = IoAllocateIrp( pdo->StackSize, FALSE );
+ if (irp == NULL) return STATUS_NO_MEMORY;
+ irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation - 1;
+ irpsp->MajorFunction = IRP_MJ_PNP;
+ irpsp->MinorFunction = IRP_MN_QUERY_ID;
+ irpsp->Parameters.QueryId.IdType = id_type;
+ status = __regs_IofCallDriver( pdo, irp );
+ if (status == STATUS_SUCCESS)
+ *id = (WCHAR *)irp->IoStatus.Information;
+ IoFreeIrp( irp );
+ return status;
+}
+
+static BOOL compare_ids( WCHAR *hardware_id, WCHAR *instance_id,
+ WCHAR *device_instance_id )
+{
+ WCHAR *ptr, *ptr2;
+
+ ptr = strrchrW( device_instance_id, '\\' );
+ if (ptr == NULL) return FALSE;
+ if (strncmpiW( hardware_id, device_instance_id, ptr - device_instance_id ))
+ return FALSE;
+ ++ptr;
+ ptr2 = strrchrW( ptr, '&' );
+ ptr2 = ptr2 ? (ptr2 + 1) : ptr;
+ if (strcmpiW( instance_id, ptr2 ))
+ return FALSE;
+ return TRUE;
+}
+
static HANDLE get_device_manager(void)
{
static HANDLE device_manager;
@@ -1118,127 +1156,91 @@ NTSTATUS WINAPI IoRegisterDeviceInterface( PDEVICE_OBJECT PhysicalDeviceObject,
PUNICODE_STRING ReferenceString,
PUNICODE_STRING SymbolicLinkName )
{
- /* Now this function is implemented only for USB devices */
+ /* Now this function is implemented only for "USB" enumerator */
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;
+ WCHAR *hardware_id = NULL, *instance_id = NULL, *id = NULL;
HDEVINFO set;
- SP_DEVINFO_DATA devInfo = { 0 };
+ SP_DEVINFO_DATA devInfo;
+ SP_DEVICE_INTERFACE_DATA interfaceData;
DWORD i = 0;
- int found = 0;
- NTSTATUS status = STATUS_UNSUCCESSFUL;
- struct PdoExtension *dx;
- USHORT vid, pid;
+ NTSTATUS status;
+ struct PdoExtension *dx = PhysicalDeviceObject->DeviceExtension;
+ struct InterfaceInstance *interf;
TRACE( "%p %s %s %p\n", PhysicalDeviceObject,
debugstr_guid(InterfaceClassGuid), debugstr_us(ReferenceString),
SymbolicLinkName );
- dx = PhysicalDeviceObject->DeviceExtension;
- vid = dx->instance->vid;
- pid = dx->instance->pid;
- inst_ptr = dx->instance->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, vid, pid, instance_id, guid_str.Buffer );
- RtlFreeUnicodeString( &guid_str );
-
- hardware_id = RtlAllocateHeap( GetProcessHeap(), 0,
- (strlenW( device_name ) + 1) * sizeof(WCHAR) );
- if (NULL == hardware_id)
+ status = get_device_id( PhysicalDeviceObject, BusQueryInstanceID, &instance_id );
+ if (status != STATUS_SUCCESS) goto end;
+ status = get_device_id( PhysicalDeviceObject, BusQueryDeviceID, &hardware_id );
+ if (status != STATUS_SUCCESS) goto end;
+ id = RtlAllocateHeap( GetProcessHeap(), 0, MAX_DEVICE_ID_LEN );
+ if (id == NULL)
{
- RtlFreeHeap( GetProcessHeap(), 0, buf );
- return STATUS_NO_MEMORY;
+ status = STATUS_NO_MEMORY;
+ goto end;
}
- sprintfW( hardware_id, device_name, vid, pid, instance_id );
+ status = STATUS_UNSUCCESSFUL;
set = SetupDiGetClassDevsW( NULL, usb, NULL, DIGCF_ALLCLASSES );
- if (INVALID_HANDLE_VALUE == set)
- {
- RtlFreeHeap( GetProcessHeap(), 0, buf );
- return STATUS_UNSUCCESSFUL;
- }
+ if (INVALID_HANDLE_VALUE == set) goto end;
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)
+ while (SetupDiEnumDeviceInfo( set, i++, &devInfo ))
+ if (SetupDiGetDeviceInstanceIdW( set, &devInfo, id, MAX_DEVICE_ID_LEN, NULL )
+ && compare_ids( hardware_id, instance_id, id ))
{
- status = STATUS_NO_MEMORY;
- break;
- }
- if (SetupDiGetDeviceRegistryPropertyW( set, &devInfo, SPDRP_HARDWAREID,
- NULL, (PBYTE)id, size, NULL ))
- while (*id)
+ SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail;
+ DWORD size;
+
+ interfaceData.cbSize = sizeof(interfaceData);
+ if (SetupDiCreateDeviceInterfaceW( set, &devInfo,
+ InterfaceClassGuid, NULL, 0, &interfaceData ))
{
- if (!strcmpiW( id, hardware_id ))
+ SetupDiGetDeviceInterfaceDetailW( set, &interfaceData, NULL, 0,
+ &size, NULL );
+ detail = RtlAllocateHeap( GetProcessHeap(), 0, size );
+ if (detail == NULL) break;
+ detail->cbSize = sizeof(*detail);
+ if (!SetupDiGetDeviceInterfaceDetailW( set, &interfaceData,
+ detail, size, NULL, NULL ))
{
- struct InterfaceInstance *interf;
-
- found = 1;
- interf = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*interf) );
- if (NULL == interf) break;
- interf->link = RtlAllocateHeap( GetProcessHeap(), 0,
- (strlenW(buf) + 1) * sizeof(WCHAR) );
- if (NULL == interf->link)
- {
- RtlFreeHeap( GetProcessHeap(), 0, interf );
- break;
- }
- strcpyW( interf->link, buf );
- interf->target = &dx->instance->pdo_name;
- if (SetupDiCreateDeviceInterfaceW( set, &devInfo,
- InterfaceClassGuid, NULL, 0, NULL ))
- {
- EnterCriticalSection( &cs );
- list_add_tail( &Interfaces, &interf->entry );
- LeaveCriticalSection( &cs );
- status = STATUS_SUCCESS;
- }
- else
- {
- RtlFreeHeap( GetProcessHeap(), 0, interf->link );
- RtlFreeHeap( GetProcessHeap(), 0, interf );
- }
+ RtlFreeHeap( GetProcessHeap(), 0, detail );
+ break;
+ }
+ interf = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*interf) );
+ if (interf == NULL)
+ {
+ RtlFreeHeap( GetProcessHeap(), 0, detail );
+ break;
+ }
+ interf->link = RtlAllocateHeap( GetProcessHeap(), 0,
+ (strlenW(detail->DevicePath) + 1) * sizeof(WCHAR) );
+ if (interf->link == NULL)
+ {
+ RtlFreeHeap( GetProcessHeap(), 0, detail );
+ RtlFreeHeap( GetProcessHeap(), 0, interf );
break;
}
- id += strlenW( id ) + 1;
+ strcpyW( interf->link, detail->DevicePath );
+ RtlFreeHeap( GetProcessHeap(), 0, detail );
+ interf->link[1] = '?';
+ interf->target = &dx->instance->pdo_name;
+ EnterCriticalSection( &cs );
+ list_add_tail( &Interfaces, &interf->entry );
+ LeaveCriticalSection( &cs );
+ status = STATUS_SUCCESS;
}
- RtlFreeHeap( GetProcessHeap(), 0, id );
- }
- RtlFreeHeap( GetProcessHeap(), 0, hardware_id );
+ break;
+ }
SetupDiDestroyDeviceInfoList( set );
if (STATUS_SUCCESS == status)
- RtlInitUnicodeString( SymbolicLinkName, buf );
- else
- RtlFreeHeap( GetProcessHeap(), 0, buf );
-
+ RtlCreateUnicodeString( SymbolicLinkName, interf->link );
+end:
+ if (id) RtlFreeHeap( GetProcessHeap(), 0, id );
+ if (hardware_id) ExFreePool( hardware_id );
+ if (instance_id) ExFreePool( instance_id );
return status;
}
--
1.6.0.2.GIT
Подробная информация о списке рассылки Wine-patches