908 lines
24 KiB
C
908 lines
24 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1996 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
id.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the code to handle IRP_MN_QUERY_ID
|
|||
|
|
|||
|
Authors:
|
|||
|
|
|||
|
Ravisankar Pudipeddi (ravisp)
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode only
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
Neil Sandlin (neilsa) - split off from pdopnp.c
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "pch.h"
|
|||
|
|
|||
|
//
|
|||
|
// Internal References
|
|||
|
//
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PcmciaGenerateDeviceId(
|
|||
|
IN PSOCKET_DATA SocketData,
|
|||
|
IN ULONG FunctionNumber,
|
|||
|
OUT PUCHAR *DeviceId
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PcmciaCheckInstance(
|
|||
|
IN PUCHAR DeviceId,
|
|||
|
IN ULONG Instance
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PcmciaGetDeviceType(
|
|||
|
IN PDEVICE_OBJECT Pdo,
|
|||
|
IN ULONG FunctionNumber,
|
|||
|
OUT PUCHAR DeviceType
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
PcmciaFilterIdString(
|
|||
|
IN PUCHAR pIn,
|
|||
|
OUT PUCHAR pOut,
|
|||
|
ULONG MaxLen
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(PAGE, PcmciaGenerateDeviceId)
|
|||
|
#pragma alloc_text(PAGE, PcmciaGetDeviceId)
|
|||
|
#pragma alloc_text(PAGE, PcmciaGetHardwareIds)
|
|||
|
#pragma alloc_text(PAGE, PcmciaGetCompatibleIds)
|
|||
|
#pragma alloc_text(PAGE, PcmciaGetDeviceType)
|
|||
|
#pragma alloc_text(PAGE, PcmciaFilterIdString)
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
#define PCMCIA_MAX_DEVICE_TYPE_SUPPORTED 12
|
|||
|
|
|||
|
const
|
|||
|
UCHAR *PcmciaCompatibleIds[PCMCIA_MAX_DEVICE_TYPE_SUPPORTED+1] = {
|
|||
|
"", // Unknown..
|
|||
|
"", // Memory card (RAM, ROM, EPROM, Flash)
|
|||
|
"", // Serial I/O port, includes modems
|
|||
|
"", // Parallel printer port
|
|||
|
"*PNP0600", // Disk driver (ATA)
|
|||
|
"", // Video interface
|
|||
|
"", // Local Area Network adapter
|
|||
|
"", // Auto Increment Mass Storage card
|
|||
|
"", // SCSI bridge card
|
|||
|
"", // Security card
|
|||
|
"*PNP0D00", // Multi-Function 3.0 PC Card
|
|||
|
"", // Flash memory card
|
|||
|
"*PNPC200", // Modem card (sync with PCCARD_TYPE_MODEM)
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PcmciaGenerateDeviceId(
|
|||
|
IN PSOCKET_DATA SocketData,
|
|||
|
IN ULONG FunctionNumber,
|
|||
|
OUT PUCHAR *DeviceId
|
|||
|
)
|
|||
|
/*++
|
|||
|
The device ID is created from tuple information on the PC Card
|
|||
|
The goal is to create a unique ID for each
|
|||
|
card. The device ID is created from the manufacturer name string,
|
|||
|
the product name string, and a 16-bit CRC of a set of tuples.
|
|||
|
|
|||
|
The ID is created by concatenating the "PCMCIA" prefix, the manufacturer
|
|||
|
name string, the product name string and the 16-bit CRC for the card.
|
|||
|
|
|||
|
PCMCIA\<manuf_name>-<prod_name>-<crc>
|
|||
|
|
|||
|
If the CISTPL_VERS_1 tuple is not available, or the manufacturer name is
|
|||
|
NULL, the string "UNKNOWN_MANUFACTURER" will be included in its place.
|
|||
|
|
|||
|
If this is for a child function within a multifunctionn card, the generated
|
|||
|
device id would be:
|
|||
|
|
|||
|
PCMCIA\<manuf_name>-<prod_name>-DEV<function number>-<crc>
|
|||
|
|
|||
|
This device id is compatible with win 9x device id's (excluding the instance
|
|||
|
number which is returned separtely by handling another IRP.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Pdo - Pointer to the physical device object for the pc-card
|
|||
|
FunctionNumber - Function number of the function in a multi-function card.
|
|||
|
If this is PCMCIA_MULTIFUNCTION_PARENT, then the requested device id
|
|||
|
is for the parent device - not for any individual function
|
|||
|
DeviceId - Pointer to the string in which device id is returned
|
|||
|
|
|||
|
Return Value
|
|||
|
|
|||
|
Status
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PUCHAR deviceId;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
deviceId = ExAllocatePool(PagedPool, PCMCIA_MAXIMUM_DEVICE_ID_LENGTH);
|
|||
|
|
|||
|
if (deviceId == NULL) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
//
|
|||
|
// Generate the device id
|
|||
|
//
|
|||
|
if (*(SocketData->Mfg) == '\0' ) {
|
|||
|
//
|
|||
|
// No manufacturer name available
|
|||
|
//
|
|||
|
if (FunctionNumber == PCMCIA_MULTIFUNCTION_PARENT) {
|
|||
|
//
|
|||
|
// Device id for the pc-card
|
|||
|
//
|
|||
|
if (SocketData->Flags & SDF_JEDEC_ID) {
|
|||
|
//
|
|||
|
// Flash memory cards have the special device id
|
|||
|
//
|
|||
|
sprintf(deviceId, "%s\\%s-%04x",
|
|||
|
PCMCIA_ID_STRING,
|
|||
|
PCMCIA_MEMORY_ID_STRING,
|
|||
|
SocketData->JedecId);
|
|||
|
|
|||
|
} else {
|
|||
|
sprintf(deviceId, "%s\\%s-%04X",
|
|||
|
PCMCIA_ID_STRING,
|
|||
|
PCMCIA_UNKNOWN_MANUFACTURER_STRING,
|
|||
|
SocketData->CisCrc);
|
|||
|
}
|
|||
|
} else {
|
|||
|
//
|
|||
|
// This is for the individual multifunction child
|
|||
|
//
|
|||
|
sprintf(deviceId, "%s\\%s-DEV%d-%04X",
|
|||
|
PCMCIA_ID_STRING,
|
|||
|
PCMCIA_UNKNOWN_MANUFACTURER_STRING,
|
|||
|
FunctionNumber,
|
|||
|
SocketData->CisCrc);
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
UCHAR Mfg[MAX_MANFID_LENGTH];
|
|||
|
UCHAR Ident[MAX_IDENT_LENGTH];
|
|||
|
|
|||
|
PcmciaFilterIdString(SocketData->Mfg, Mfg, MAX_MANFID_LENGTH);
|
|||
|
PcmciaFilterIdString(SocketData->Ident, Ident, MAX_IDENT_LENGTH);
|
|||
|
|
|||
|
if (FunctionNumber == PCMCIA_MULTIFUNCTION_PARENT) {
|
|||
|
//
|
|||
|
// Device id for the pc-card
|
|||
|
//
|
|||
|
sprintf(deviceId, "%s\\%s-%s-%04X",
|
|||
|
PCMCIA_ID_STRING,
|
|||
|
Mfg,
|
|||
|
Ident,
|
|||
|
SocketData->CisCrc);
|
|||
|
} else {
|
|||
|
//
|
|||
|
// This is for the individual multifunction child
|
|||
|
//
|
|||
|
sprintf(deviceId, "%s\\%s-%s-DEV%d-%04X",
|
|||
|
PCMCIA_ID_STRING,
|
|||
|
Mfg,
|
|||
|
Ident,
|
|||
|
FunctionNumber,
|
|||
|
SocketData->CisCrc);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
*DeviceId = deviceId;
|
|||
|
|
|||
|
if ((FunctionNumber == PCMCIA_MULTIFUNCTION_PARENT) &&
|
|||
|
(SocketData->PdoExtension != NULL) &&
|
|||
|
(SocketData->PdoExtension->DeviceId == NULL)) {
|
|||
|
//
|
|||
|
// Keep a copy of the device id
|
|||
|
//
|
|||
|
PPDO_EXTENSION pdoExtension = SocketData->PdoExtension;
|
|||
|
|
|||
|
pdoExtension->DeviceId = ExAllocatePool(NonPagedPool, strlen(deviceId)+1);
|
|||
|
if (pdoExtension->DeviceId) {
|
|||
|
RtlCopyMemory(pdoExtension->DeviceId, deviceId, strlen(deviceId)+1);
|
|||
|
}
|
|||
|
}
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PcmciaGetDeviceId(
|
|||
|
IN PDEVICE_OBJECT Pdo,
|
|||
|
IN ULONG FunctionNumber,
|
|||
|
OUT PUNICODE_STRING DeviceId
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Generated device id is returned for the supplied pc-card
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Pdo - Pointer to the physical device object for the pc-card
|
|||
|
FunctionNumber - Function number of the function in a multi-function card.
|
|||
|
If this is PCMCIA_MULTIFUNCTION_PARENT, then the requested device id
|
|||
|
is for the parent device - not for any individual function
|
|||
|
DeviceId - Pointer to the unicode string in which device id is returned
|
|||
|
|
|||
|
Return Value
|
|||
|
|
|||
|
Status
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PPDO_EXTENSION pdoExtension=Pdo->DeviceExtension;
|
|||
|
PSOCKET_DATA socketData = pdoExtension->SocketData;
|
|||
|
ANSI_STRING ansiId;
|
|||
|
PUCHAR deviceId;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ASSERT(DeviceId);
|
|||
|
|
|||
|
if (!socketData) {
|
|||
|
ASSERT (socketData);
|
|||
|
return STATUS_DEVICE_NOT_READY;
|
|||
|
}
|
|||
|
|
|||
|
status = PcmciaGenerateDeviceId(socketData,
|
|||
|
FunctionNumber,
|
|||
|
&deviceId);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DebugPrint((PCMCIA_DEBUG_INFO, "pdo %08x Device Id=%s\n", Pdo, deviceId));
|
|||
|
|
|||
|
RtlInitAnsiString(&ansiId, deviceId);
|
|||
|
|
|||
|
status = RtlAnsiStringToUnicodeString(DeviceId,
|
|||
|
&ansiId,
|
|||
|
TRUE);
|
|||
|
ExFreePool(deviceId);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PcmciaGetHardwareIds(
|
|||
|
IN PDEVICE_OBJECT Pdo,
|
|||
|
IN ULONG FunctionNumber,
|
|||
|
OUT PUNICODE_STRING HardwareIds
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine generates the hardware id's for the given PC-Card and returns them
|
|||
|
as a Unicode multi-string.
|
|||
|
Hardware ids for PC-Cards are:
|
|||
|
|
|||
|
1. The device id of the PC-Card
|
|||
|
2. The device id of the PC-Card with the CRC replaced with the Manufacturer code and
|
|||
|
Manufacturer info fields obtained from the tuple information on the PC-Card
|
|||
|
|
|||
|
These hardware id's are compatible with win 9x hardware ids
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Pdo - Pointer to device object representing the PC-Card
|
|||
|
FunctionNumber - Function number of the function in a multi-function card.
|
|||
|
If this is PCMCIA_MULTIFUNCTION_PARENT, then the requested hardware id
|
|||
|
is for the parent device - not for any individual function
|
|||
|
HardwareIds - Pointer to the unicode string which contains the hardware id's as a multi-string
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PPDO_EXTENSION pdoExtension=Pdo->DeviceExtension;
|
|||
|
PSOCKET socket = pdoExtension->Socket;
|
|||
|
PSOCKET_DATA socketData = pdoExtension->SocketData;
|
|||
|
NTSTATUS status;
|
|||
|
PSTR strings[4] = {NULL};
|
|||
|
PUCHAR hwId, hwId2;
|
|||
|
UCHAR deviceType;
|
|||
|
UCHAR stringCount = 0;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
if (!socketData) {
|
|||
|
ASSERT (socketData);
|
|||
|
return STATUS_DEVICE_NOT_READY;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// get the device type for later use
|
|||
|
//
|
|||
|
status = PcmciaGetDeviceType(Pdo, FunctionNumber, &deviceType);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// The first hardware id is identical to the device id
|
|||
|
// Generate the device id
|
|||
|
//
|
|||
|
status = PcmciaGenerateDeviceId(socketData,
|
|||
|
FunctionNumber,
|
|||
|
&strings[stringCount++]);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
|
|||
|
hwId = ExAllocatePool(PagedPool, PCMCIA_MAXIMUM_DEVICE_ID_LENGTH);
|
|||
|
|
|||
|
if (!hwId) {
|
|||
|
leave;
|
|||
|
}
|
|||
|
strings[stringCount++] = hwId;
|
|||
|
|
|||
|
//
|
|||
|
// The second hardware is the device id with the CRC replaced
|
|||
|
// with the manufacturer code and info
|
|||
|
//
|
|||
|
if (*(socketData->Mfg) == '\0' ) {
|
|||
|
//
|
|||
|
// No manufacturer name available
|
|||
|
//
|
|||
|
if (FunctionNumber == PCMCIA_MULTIFUNCTION_PARENT) {
|
|||
|
if (socketData->Flags & SDF_JEDEC_ID) {
|
|||
|
sprintf(hwId, "%s\\%s-%04x",
|
|||
|
PCMCIA_ID_STRING,
|
|||
|
PCMCIA_MEMORY_ID_STRING,
|
|||
|
socketData->JedecId);
|
|||
|
} else {
|
|||
|
sprintf(hwId, "%s\\%s-%04X-%04X",
|
|||
|
PCMCIA_ID_STRING,
|
|||
|
PCMCIA_UNKNOWN_MANUFACTURER_STRING,
|
|||
|
socketData->ManufacturerCode,
|
|||
|
socketData->ManufacturerInfo);
|
|||
|
}
|
|||
|
} else {
|
|||
|
sprintf(hwId, "%s\\%s-DEV%d-%04X-%04X", PCMCIA_ID_STRING,
|
|||
|
PCMCIA_UNKNOWN_MANUFACTURER_STRING,
|
|||
|
FunctionNumber,
|
|||
|
socketData->ManufacturerCode,
|
|||
|
socketData->ManufacturerInfo);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
UCHAR Mfg[MAX_MANFID_LENGTH];
|
|||
|
UCHAR Ident[MAX_IDENT_LENGTH];
|
|||
|
|
|||
|
PcmciaFilterIdString(socketData->Mfg, Mfg, MAX_MANFID_LENGTH);
|
|||
|
PcmciaFilterIdString(socketData->Ident, Ident, MAX_IDENT_LENGTH);
|
|||
|
|
|||
|
//
|
|||
|
// Here a mistake on Win2000 is forcing us to now generate two different
|
|||
|
// IDs. The intended and documented form at this point is to generate:
|
|||
|
//
|
|||
|
// PCMCIA\<mfg>-<ident>-<code>-<info>
|
|||
|
//
|
|||
|
// but Win2000 had a bug where this was generated instead:
|
|||
|
//
|
|||
|
// PCMCIA\<mfg>-<code>-<info>
|
|||
|
//
|
|||
|
// So now we generate both in case someone started using the bogus format.
|
|||
|
//
|
|||
|
|
|||
|
hwId2 = ExAllocatePool(PagedPool, PCMCIA_MAXIMUM_DEVICE_ID_LENGTH);
|
|||
|
|
|||
|
if (!hwId2) {
|
|||
|
leave;
|
|||
|
}
|
|||
|
strings[stringCount++] = hwId2;
|
|||
|
|
|||
|
if (FunctionNumber == PCMCIA_MULTIFUNCTION_PARENT) {
|
|||
|
sprintf(hwId, "%s\\%s-%s-%04X-%04X", PCMCIA_ID_STRING,
|
|||
|
Mfg,
|
|||
|
Ident,
|
|||
|
socketData->ManufacturerCode,
|
|||
|
socketData->ManufacturerInfo);
|
|||
|
|
|||
|
sprintf(hwId2, "%s\\%s-%04X-%04X", PCMCIA_ID_STRING,
|
|||
|
Mfg,
|
|||
|
socketData->ManufacturerCode,
|
|||
|
socketData->ManufacturerInfo);
|
|||
|
} else {
|
|||
|
sprintf(hwId, "%s\\%s-%s-DEV%d-%04X-%04X",
|
|||
|
PCMCIA_ID_STRING,
|
|||
|
Mfg,
|
|||
|
Ident,
|
|||
|
FunctionNumber,
|
|||
|
socketData->ManufacturerCode,
|
|||
|
socketData->ManufacturerInfo);
|
|||
|
|
|||
|
sprintf(hwId2, "%s\\%s-DEV%d-%04X-%04X",
|
|||
|
PCMCIA_ID_STRING,
|
|||
|
Mfg,
|
|||
|
FunctionNumber,
|
|||
|
socketData->ManufacturerCode,
|
|||
|
socketData->ManufacturerInfo);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (deviceType == PCCARD_TYPE_ATA) {
|
|||
|
|
|||
|
hwId = ExAllocatePool(PagedPool, PCMCIA_MAXIMUM_DEVICE_ID_LENGTH);
|
|||
|
|
|||
|
if (!hwId) {
|
|||
|
leave;
|
|||
|
}
|
|||
|
strings[stringCount++] = hwId;
|
|||
|
|
|||
|
sprintf(hwId, "%s\\%s",
|
|||
|
PCMCIA_ID_STRING,
|
|||
|
PcmciaCompatibleIds[PCCARD_TYPE_ATA]);
|
|||
|
}
|
|||
|
|
|||
|
status = PcmciaStringsToMultiString(strings , stringCount, HardwareIds);
|
|||
|
|
|||
|
} finally {
|
|||
|
|
|||
|
while(stringCount != 0) {
|
|||
|
ExFreePool(strings[--stringCount]);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PcmciaGetCompatibleIds(
|
|||
|
IN PDEVICE_OBJECT Pdo,
|
|||
|
IN ULONG FunctionNumber,
|
|||
|
OUT PUNICODE_STRING CompatibleIds
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the compatible ids for the given PC-Card.
|
|||
|
Compatible id's are generated based on the Function Id of the PC-Card
|
|||
|
obtained from the CISTPL_FUNCID in the CIS tuple info. on the PC-Card.
|
|||
|
A table lookup is done based on the CISTPL_FUNCID to obtain the compatible id
|
|||
|
|
|||
|
This compatible id is identical to the win 9x generated compatible ids
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Pdo - Pointer to the device object representing the PC-Card
|
|||
|
FunctionNumber - Function number of the function in a multi-function card.
|
|||
|
If this is PCMCIA_MULTIFUNCTION_PARENT, then the requested compatibleid
|
|||
|
is for the parent device - not for any individual function
|
|||
|
CompatibleIds - Pointer to the unicode string which would contain the compatible ids
|
|||
|
as a multi-string on return
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
STATUS_SUCCESS
|
|||
|
Any other status - could not generate compatible ids
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UCHAR deviceType ;
|
|||
|
NTSTATUS status;
|
|||
|
PCSTR strings[1] = {""};
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
status = PcmciaGetDeviceType(Pdo, FunctionNumber, &deviceType);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
if ((deviceType == PCCARD_TYPE_RESERVED) ||
|
|||
|
(deviceType > PCMCIA_MAX_DEVICE_TYPE_SUPPORTED)) {
|
|||
|
status = PcmciaStringsToMultiString(strings, 1, CompatibleIds);
|
|||
|
} else {
|
|||
|
status = PcmciaStringsToMultiString(&PcmciaCompatibleIds[deviceType], 1, CompatibleIds);
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PcmciaGetDeviceType(
|
|||
|
IN PDEVICE_OBJECT Pdo,
|
|||
|
IN ULONG FunctionNumber,
|
|||
|
OUT PUCHAR DeviceType
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the device type for the given PC-Card.
|
|||
|
device type is obtained from the CISTPL_FUNCID in the CIS tuple info. on the PC-Card.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Pdo - Pointer to the device object representing the PC-Card
|
|||
|
FunctionNumber - Function number of the function in a multi-function card.
|
|||
|
If this is PCMCIA_MULTIFUNCTION_PARENT, then the requested compatibleid
|
|||
|
is for the parent device - not for any individual function
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
device type
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UCHAR deviceType ;
|
|||
|
PPDO_EXTENSION pdoExtension;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
pdoExtension = Pdo->DeviceExtension;
|
|||
|
|
|||
|
if (IsDeviceMultifunction(pdoExtension)) {
|
|||
|
if (FunctionNumber == PCMCIA_MULTIFUNCTION_PARENT) {
|
|||
|
//
|
|||
|
// This is for the root multifunction pc-card
|
|||
|
//
|
|||
|
deviceType = PCCARD_TYPE_MULTIFUNCTION3;
|
|||
|
} else {
|
|||
|
//
|
|||
|
// This is for the individual multifunction child
|
|||
|
//
|
|||
|
PSOCKET_DATA socketData;
|
|||
|
ULONG index;
|
|||
|
|
|||
|
for (socketData = pdoExtension->SocketData, index = 0; (socketData != NULL);
|
|||
|
socketData = socketData->Next,index++) {
|
|||
|
if (socketData->Function == FunctionNumber) {
|
|||
|
//
|
|||
|
// Found the child;
|
|||
|
//
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if (!socketData) {
|
|||
|
ASSERT (socketData);
|
|||
|
return STATUS_DEVICE_NOT_READY;
|
|||
|
}
|
|||
|
deviceType = socketData->DeviceType;
|
|||
|
}
|
|||
|
} else {
|
|||
|
//
|
|||
|
// This is a run-of-the mill single function card
|
|||
|
//
|
|||
|
deviceType = pdoExtension->SocketData->DeviceType;
|
|||
|
}
|
|||
|
|
|||
|
*DeviceType = deviceType;
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PcmciaStringsToMultiString(
|
|||
|
IN PCSTR * Strings,
|
|||
|
IN ULONG Count,
|
|||
|
IN PUNICODE_STRING MultiString
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine formats a set of supplied strings into a multi string format, terminating
|
|||
|
it with a double '\0' character
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Strings - Pointer to an array of strings
|
|||
|
Count - Number of strings in the supplied array which are packed into the multi-string
|
|||
|
MultiString - Pointer to the Unicode string which packs the supplied string as a multi-string
|
|||
|
terminated by double NULL
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
STATUS_SUCCESS
|
|||
|
STATUS_INSUFFICIENT_RESOURCES - Could not allocate memory for the multi-string
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG i, multiStringLength=0;
|
|||
|
UNICODE_STRING tempMultiString;
|
|||
|
PCSTR * currentString;
|
|||
|
ANSI_STRING ansiString;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
|
|||
|
ASSERT (MultiString->Buffer == NULL);
|
|||
|
|
|||
|
for (i = Count, currentString = Strings; i > 0;i--, currentString++) {
|
|||
|
RtlInitAnsiString(&ansiString, *currentString);
|
|||
|
multiStringLength += RtlAnsiStringToUnicodeSize(&ansiString);
|
|||
|
|
|||
|
}
|
|||
|
ASSERT(multiStringLength != 0);
|
|||
|
multiStringLength += sizeof(WCHAR);
|
|||
|
|
|||
|
MultiString->Buffer = ExAllocatePool(PagedPool, multiStringLength);
|
|||
|
if (MultiString->Buffer == NULL) {
|
|||
|
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
MultiString->MaximumLength = (USHORT) multiStringLength;
|
|||
|
MultiString->Length = (USHORT) multiStringLength;
|
|||
|
|
|||
|
tempMultiString = *MultiString;
|
|||
|
|
|||
|
for (i = Count, currentString = Strings; i > 0;i--, currentString++) {
|
|||
|
RtlInitAnsiString(&ansiString, *currentString);
|
|||
|
status = RtlAnsiStringToUnicodeString(&tempMultiString,
|
|||
|
&ansiString,
|
|||
|
FALSE);
|
|||
|
ASSERT(NT_SUCCESS(status));
|
|||
|
((PSTR) tempMultiString.Buffer) += tempMultiString.Length + sizeof(WCHAR);
|
|||
|
};
|
|||
|
|
|||
|
//
|
|||
|
// Add one more NULL to terminate the multi string
|
|||
|
//
|
|||
|
RtlZeroMemory(tempMultiString.Buffer, sizeof(WCHAR));
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PcmciaGetInstanceId(
|
|||
|
IN PDEVICE_OBJECT Pdo,
|
|||
|
OUT PUNICODE_STRING InstanceId
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine generates a unique instance id (1 upwards) for the supplied
|
|||
|
PC-Card which is guaranteed not to clash with any other instance ids under
|
|||
|
the same pcmcia controller, for the same type of card.
|
|||
|
A new instance id is computed only if it was not already present for the PC-Card.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Pdo - Pointer to the device object representing the PC-Card
|
|||
|
InstanceId - Pointer to a unicode string which will contain the generated
|
|||
|
instance id.
|
|||
|
Memory for the unicode string allocated by this routine.
|
|||
|
Caller's responsibility to free it .
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
STATUS_SUCCESS
|
|||
|
STATUS_UNSUCCESSFUL - Currently there's a cap on the maximum value of instance id - 999999
|
|||
|
This status returned only if more than 999999 PC-Cards exist under
|
|||
|
this PCMCIA controller!
|
|||
|
Any other status - Something failed in the string allocation/conversion
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PPDO_EXTENSION pdoExtension=Pdo->DeviceExtension;
|
|||
|
PSOCKET socket = pdoExtension->Socket;
|
|||
|
PSOCKET_DATA socketData = pdoExtension->SocketData;
|
|||
|
ULONG instance;
|
|||
|
NTSTATUS status;
|
|||
|
ANSI_STRING sizeString;
|
|||
|
|
|||
|
ASSERT(InstanceId);
|
|||
|
|
|||
|
if (!socketData) {
|
|||
|
return STATUS_DEVICE_NOT_READY;
|
|||
|
}
|
|||
|
//
|
|||
|
// Allocate memory for the unicode string
|
|||
|
// Maximum of 6 digits in the instance..
|
|||
|
//
|
|||
|
RtlInitAnsiString(&sizeString, "123456");
|
|||
|
status = RtlAnsiStringToUnicodeString(InstanceId, &sizeString, TRUE);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Don't recompute instance if it's already present
|
|||
|
//
|
|||
|
if (socketData->Instance) {
|
|||
|
|
|||
|
status = RtlIntegerToUnicodeString(socketData->Instance, 10, InstanceId);
|
|||
|
|
|||
|
} else {
|
|||
|
KIRQL OldIrql;
|
|||
|
//
|
|||
|
// Synchronize access to prevent two identical ids/instances
|
|||
|
//
|
|||
|
KeAcquireSpinLock(&PcmciaGlobalLock, &OldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// assume failure
|
|||
|
//
|
|||
|
status = STATUS_UNSUCCESSFUL;
|
|||
|
|
|||
|
for (instance = 1; instance <= PCMCIA_MAX_INSTANCE; instance++) {
|
|||
|
if (PcmciaCheckInstance(pdoExtension->DeviceId,
|
|||
|
instance)) {
|
|||
|
socketData->Instance = instance;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
KeReleaseSpinLock(&PcmciaGlobalLock, OldIrql);
|
|||
|
|
|||
|
if (socketData->Instance) {
|
|||
|
status = RtlIntegerToUnicodeString(instance, 10, InstanceId);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
RtlFreeUnicodeString(InstanceId);
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PcmciaCheckInstance(
|
|||
|
IN PUCHAR DeviceId,
|
|||
|
IN ULONG Instance
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine checks to see if the supplied instance id clashes with any other PC-card
|
|||
|
with the same device id
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SocketList - Pointer to the list of sockets on the PCMCIA controller
|
|||
|
DeviceId - Pointer to the device id of the PC-Card for which the Instance Id is being checked
|
|||
|
Instance - Instance Id which needs to be verified
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
TRUE - Instance is unique for the given DeviceId and may be used
|
|||
|
FALSE - Instance clashes with another instance id for the same device id
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PPDO_EXTENSION pdoExtension;
|
|||
|
PFDO_EXTENSION fdoExtension;
|
|||
|
PSOCKET_DATA socketData;
|
|||
|
PDEVICE_OBJECT fdo, pdo;
|
|||
|
|
|||
|
for (fdo = FdoList; fdo != NULL; fdo = fdoExtension->NextFdo) {
|
|||
|
fdoExtension = fdo->DeviceExtension;
|
|||
|
ASSERT (fdoExtension);
|
|||
|
|
|||
|
if (!IsDeviceStarted(fdoExtension)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
for (pdo = fdoExtension->PdoList; pdo != NULL; pdo = pdoExtension->NextPdoInFdoChain) {
|
|||
|
pdoExtension = pdo->DeviceExtension;
|
|||
|
socketData = pdoExtension->SocketData;
|
|||
|
|
|||
|
if (IsDevicePhysicallyRemoved(pdoExtension)) {
|
|||
|
//
|
|||
|
// going to be removed soon
|
|||
|
//
|
|||
|
continue;
|
|||
|
}
|
|||
|
if (!socketData) {
|
|||
|
//
|
|||
|
// socketData already cleaned up
|
|||
|
//
|
|||
|
continue;
|
|||
|
}
|
|||
|
//
|
|||
|
// If an instance has not
|
|||
|
// been assigned yet to this card, skip
|
|||
|
//
|
|||
|
if (socketData->Instance == 0) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If this socket's device id matches the given socket's device id
|
|||
|
// compare the instances: if equal, then this instance is not ok.
|
|||
|
//
|
|||
|
//
|
|||
|
if ((pdoExtension->DeviceId == NULL) || (DeviceId == NULL)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if ((strcmp(pdoExtension->DeviceId, DeviceId)==0) &&
|
|||
|
(socketData->Instance == Instance)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
//
|
|||
|
// Instance is ok and unique
|
|||
|
//
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
PcmciaFilterIdString(
|
|||
|
IN PUCHAR pIn,
|
|||
|
OUT PUCHAR pOut,
|
|||
|
ULONG MaxLen
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Filters out characters that shouldn't appear in device id's
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pIn - pointer to input string
|
|||
|
pOut - pointer to output string
|
|||
|
MaxLen - size of buffers
|
|||
|
|
|||
|
Return Value
|
|||
|
|
|||
|
none
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
|
|||
|
for (i=0; i < MaxLen; i++) {
|
|||
|
|
|||
|
if (*pIn == 0) {
|
|||
|
*pOut = 0;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (*pIn >= ' ' && *pIn < 0x7F) {
|
|||
|
*pOut++ = *pIn++;
|
|||
|
} else {
|
|||
|
pIn++;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|