You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
316 lines
7.3 KiB
316 lines
7.3 KiB
/*++
|
|
|
|
Copyright (C) 2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
mpiosup.c
|
|
|
|
Abstract:
|
|
|
|
This module contains routines that port drivers can use for support of the MPIO package.
|
|
|
|
Author:
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
BOOLEAN
|
|
PortpFindMPIOSupportedDevice(
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN PUNICODE_STRING SupportedDevices
|
|
);
|
|
|
|
BOOLEAN
|
|
PortpMPIOLoaded(
|
|
VOID
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, PortGetMPIODeviceList)
|
|
#pragma alloc_text(PAGE, PortpFindMPIOSupportedDevice)
|
|
#pragma alloc_text(PAGE, PortpMPIOLoaded)
|
|
#pragma alloc_text(PAGE, PortIsDeviceMPIOSupported)
|
|
#endif
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PortGetMPIODeviceList(
|
|
IN PUNICODE_STRING RegistryPath,
|
|
OUT PUNICODE_STRING MPIODeviceList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine builds and returns the MPIO SupportedDeviceList by querying the value
|
|
MPIOSupportedDeviceList under the key 'RegistryPath' (which should be
|
|
HKLM\System\CurrentControlSet\Control\MPDEV).
|
|
|
|
Arguments:
|
|
|
|
RegistryPath - The Absolute registry path under which MPIOSupportDeviceList lives.
|
|
|
|
Return Value:
|
|
|
|
The MULTI_SZ SupportedDeviceList or NULL.
|
|
|
|
--*/
|
|
{
|
|
RTL_QUERY_REGISTRY_TABLE queryTable[2];
|
|
WCHAR defaultIDs[] = { L"\0" };
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Zero the table entries.
|
|
//
|
|
RtlZeroMemory(queryTable, sizeof(queryTable));
|
|
|
|
//
|
|
// The query table has two entries. One for the supporteddeviceList and
|
|
// the second which is the 'NULL' terminator.
|
|
//
|
|
// Indicate that there is NO call-back routine, and to give back the MULTI_SZ as
|
|
// one blob, as opposed to individual unicode strings.
|
|
//
|
|
queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND;
|
|
|
|
//
|
|
// The value to query.
|
|
//
|
|
queryTable[0].Name = L"MPIOSupportedDeviceList";
|
|
|
|
//
|
|
// Where to put the strings, the type of the key, default values and length.
|
|
//
|
|
queryTable[0].EntryContext = MPIODeviceList;
|
|
queryTable[0].DefaultType = REG_MULTI_SZ;
|
|
queryTable[0].DefaultData = defaultIDs;
|
|
queryTable[0].DefaultLength = sizeof(defaultIDs);
|
|
|
|
//
|
|
// Try to get the device list.
|
|
//
|
|
status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
|
|
RegistryPath->Buffer,
|
|
queryTable,
|
|
NULL,
|
|
NULL);
|
|
return status;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PortpFindMPIOSupportedDevice(
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN PUNICODE_STRING SupportedDevices
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This internal routine compares the two unicode strings for a match.
|
|
|
|
Arguments:
|
|
|
|
DeviceName - String built from the current device's inquiry data.
|
|
SupportedDevices - MULTI_SZ of devices that are supported.
|
|
|
|
Return Value:
|
|
|
|
TRUE - If VendorId/ProductId is found.
|
|
|
|
--*/
|
|
{
|
|
PWSTR devices = SupportedDevices->Buffer;
|
|
UNICODE_STRING unicodeString;
|
|
LONG compare;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// 'devices' is the current buffer in the MULTI_SZ built from
|
|
// the registry.
|
|
//
|
|
while (devices[0]) {
|
|
|
|
//
|
|
// Make the current entry into a unicode string.
|
|
//
|
|
RtlInitUnicodeString(&unicodeString, devices);
|
|
|
|
//
|
|
// Compare this one with the current device.
|
|
//
|
|
compare = RtlCompareUnicodeString(&unicodeString, DeviceName, TRUE);
|
|
if (compare == 0) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Advance to next entry in the MULTI_SZ.
|
|
//
|
|
devices += (unicodeString.MaximumLength / sizeof(WCHAR));
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PortpMPIOLoaded(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This internal routine is used to determine whether an mpio package is installed by trying to
|
|
open the MPIO SymLink.
|
|
|
|
NOTE: Perhaps a more exhaustive method can be used in the future.
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
TRUE - If MPIO is present.
|
|
|
|
--*/
|
|
{
|
|
UNICODE_STRING unicodeName;
|
|
PDEVICE_OBJECT controlDeviceObject;
|
|
PFILE_OBJECT fileObject;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Build the symlink name.
|
|
//
|
|
RtlInitUnicodeString(&unicodeName, L"\\DosDevices\\MPIOControl");
|
|
|
|
//
|
|
// Get mpio's deviceObject.
|
|
//
|
|
status = IoGetDeviceObjectPointer(&unicodeName,
|
|
FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
|
|
&fileObject,
|
|
&controlDeviceObject);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
ObDereferenceObject(fileObject);
|
|
}
|
|
return ((status == STATUS_SUCCESS) ? TRUE : FALSE);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PortIsDeviceMPIOSupported(
|
|
IN PUNICODE_STRING DeviceList,
|
|
IN PUCHAR VendorId,
|
|
IN PUCHAR ProductId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines whether the device is supported by traversing the SupportedDevice
|
|
list and comparing to the VendorId/ProductId values passed in.
|
|
|
|
Arguments:
|
|
|
|
DeviceList - MULTI_SZ retrieved from the registry by PortGetDeviceList
|
|
VendorId - Pointer to the inquiry data VendorId.
|
|
ProductId - Pointer to the inquiry data ProductId.
|
|
|
|
Return Value:
|
|
|
|
TRUE - If VendorId/ProductId is found.
|
|
|
|
--*/
|
|
{
|
|
UNICODE_STRING deviceName;
|
|
UNICODE_STRING productName;
|
|
ANSI_STRING ansiVendor;
|
|
ANSI_STRING ansiProduct;
|
|
NTSTATUS status;
|
|
BOOLEAN supported = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// The SupportedDevice list was built in DriverEntry from the services key.
|
|
//
|
|
if (DeviceList->MaximumLength == 0) {
|
|
|
|
//
|
|
// List is empty.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// If MPIO isn't loaded, don't claim support for the device.
|
|
//
|
|
if (!PortpMPIOLoaded()) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Convert the inquiry fields into ansi strings.
|
|
//
|
|
RtlInitAnsiString(&ansiVendor, VendorId);
|
|
RtlInitAnsiString(&ansiProduct, ProductId);
|
|
|
|
//
|
|
// Allocate the deviceName buffer. Needs to be 8+16 plus NULL.
|
|
// (productId length + vendorId length + NULL).
|
|
// Add another 4 bytes for revision plus one pad, if anyone happens to jam that in.
|
|
//
|
|
deviceName.MaximumLength = 30 * sizeof(WCHAR);
|
|
deviceName.Buffer = ExAllocatePool(PagedPool, deviceName.MaximumLength);
|
|
|
|
//
|
|
// Convert the vendorId to unicode.
|
|
//
|
|
RtlAnsiStringToUnicodeString(&deviceName, &ansiVendor, FALSE);
|
|
|
|
//
|
|
// Convert the productId to unicode.
|
|
//
|
|
RtlAnsiStringToUnicodeString(&productName, &ansiProduct, TRUE);
|
|
|
|
//
|
|
// 'cat' them.
|
|
//
|
|
status = RtlAppendUnicodeStringToString(&deviceName, &productName);
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
|
|
//
|
|
// Run the list of supported devices that was captured from the registry
|
|
// and see if this one is in the list.
|
|
//
|
|
supported = PortpFindMPIOSupportedDevice(&deviceName,
|
|
DeviceList);
|
|
|
|
|
|
}
|
|
return supported;
|
|
}
|
|
|