/*++ Copyright (c) 1995 Microsoft Corporation Module Name: devres.c Abstract: This module contains the high level device resources support routines. Author: Shie-Lin Tzong (shielint) July-27-1995 Environment: Kernel mode only. Revision History: --*/ #include "busp.h" #include "pnpisa.h" #include "pbios.h" #define IDBG 0 #pragma alloc_text(INIT,PipGetCardIdentifier) #pragma alloc_text(INIT,PipGetFunctionIdentifier) #pragma alloc_text(INIT,PipGetCompatibleDeviceId) #pragma alloc_text(INIT,PipQueryDeviceId) #pragma alloc_text(INIT,PipQueryDeviceUniqueId) #pragma alloc_text(INIT,PipQueryDeviceResources) #pragma alloc_text(INIT,PipQueryDeviceResourceRequirements) #pragma alloc_text(INIT,PipSetDeviceResources) NTSTATUS PipGetCardIdentifier ( PUCHAR CardData, PWCHAR *Buffer, PULONG BufferLength ) /*++ Routine Description: This function returns the identifier for a pnpisa card. Arguments: CardData - supplies a pointer to the pnp isa device data. Buffer - supplies a pointer to variable to receive a pointer to the Id. BufferLength - supplies a pointer to a variable to receive the size of the id buffer. Return Value: NTSTATUS code --*/ { NTSTATUS status = STATUS_SUCCESS; UCHAR tag; LONG size, length; UNICODE_STRING unicodeString; ANSI_STRING ansiString; PCHAR ansiBuffer; *Buffer = NULL; *BufferLength = 0; tag = *CardData; // // Make sure CardData does *NOT* point to a Logical Device Id tag // if ((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID) { DbgPrint("PipGetCardIdentifier: CardData is at a Logical Id tag\n"); return status; } // // Find the resource descriptor which describle identifier string // do { // // Do we find the identifer resource tag? // if (tag == TAG_ANSI_ID) { CardData++; length = *(USHORT UNALIGNED *)CardData; CardData += 2; ansiBuffer = (PCHAR)ExAllocatePool(PagedPool, length+1); if (ansiBuffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlMoveMemory(ansiBuffer, CardData, length); ansiBuffer[length] = 0; RtlInitAnsiString(&ansiString, ansiBuffer); RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE); ExFreePool(ansiBuffer); *Buffer = unicodeString.Buffer; *BufferLength = unicodeString.Length + sizeof(WCHAR); break; } // // Determine the size of the BIOS resource descriptor and // advance to next resource descriptor. // if (!(tag & LARGE_RESOURCE_TAG)) { size = (USHORT)(tag & SMALL_TAG_SIZE_MASK); size += 1; // length of small tag } else { size = *(USHORT UNALIGNED *)(CardData + 1); size += 3; // length of large tag } CardData += size; tag = *CardData; } while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)); return status; } NTSTATUS PipGetFunctionIdentifier ( PUCHAR DeviceData, PWCHAR *Buffer, PULONG BufferLength ) /*++ Routine Description: This function returns the desired pnp isa identifier for the specified DeviceData/LogicalFunction. The Identifier for a logical function is optional. If no Identifier available , Buffer is set to NULL. Arguments: DeviceData - supplies a pointer to the pnp isa device data. Buffer - supplies a pointer to variable to receive a pointer to the Id. BufferLength - supplies a pointer to a variable to receive the size of the id buffer. Return Value: NTSTATUS code --*/ { NTSTATUS status = STATUS_SUCCESS; UCHAR tag; LONG size, length; UNICODE_STRING unicodeString; ANSI_STRING ansiString; PCHAR ansiBuffer; *Buffer = NULL; *BufferLength = 0; tag = *DeviceData; #if DBG // // Make sure device data points to Logical Device Id tag // if ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID) { DbgPrint("PipGetFunctionIdentifier: DeviceData is not at a Logical Id tag\n"); } #endif // // Skip all the resource descriptors to find compatible Id descriptor // do { // // Determine the size of the BIOS resource descriptor and // advance to next resource descriptor. // if (!(tag & LARGE_RESOURCE_TAG)) { size = (USHORT)(tag & SMALL_TAG_SIZE_MASK); size += 1; // length of small tag } else { size = *(USHORT UNALIGNED *)(DeviceData + 1); size += 3; // length of large tag } DeviceData += size; tag = *DeviceData; // // Do we find the identifer resource tag? // if (tag == TAG_ANSI_ID) { DeviceData++; length = *(USHORT UNALIGNED *)DeviceData; DeviceData += 2; ansiBuffer = (PCHAR)ExAllocatePool(PagedPool, length+1); if (ansiBuffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlMoveMemory(ansiBuffer, DeviceData, length); ansiBuffer[length] = 0; RtlInitAnsiString(&ansiString, ansiBuffer); RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE); ExFreePool(ansiBuffer); *Buffer = unicodeString.Buffer; *BufferLength = unicodeString.Length + sizeof(WCHAR); break; } } while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)); return status; } NTSTATUS PipGetCompatibleDeviceId ( PUCHAR DeviceData, ULONG IdIndex, PWCHAR *Buffer ) /*++ Routine Description: This function returns the desired pnp isa id for the specified DeviceData and Id index. If Id index = 0, the Hardware ID will be return; if id index = n, the Nth compatible id will be returned. Arguments: DeviceData - supplies a pointer to the pnp isa device data. IdIndex - supplies the index of the compatible id desired. Buffer - supplies a pointer to variable to receive a pointer to the compatible Id. Return Value: NTSTATUS code --*/ { NTSTATUS status = STATUS_NO_MORE_ENTRIES; UCHAR tag; ULONG count = 0; LONG size; UNICODE_STRING unicodeString; ANSI_STRING ansiString; UCHAR eisaId[8]; ULONG id; tag = *DeviceData; #if DBG // // Make sure device data points to Logical Device Id tag // if ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID) { DbgPrint("PipGetCompatibleDeviceId: DeviceData is not at Logical Id tag\n"); } #endif if (IdIndex == 0) { // // Caller is asking for hardware id // DeviceData++; // Skip tag id = *(ULONG UNALIGNED *)DeviceData; status = STATUS_SUCCESS; } else { // // caller is asking for compatible id // IdIndex--; // // Skip all the resource descriptors to find compatible Id descriptor // do { // // Determine the size of the BIOS resource descriptor and // advance to next resource descriptor. // if (!(tag & LARGE_RESOURCE_TAG)) { size = (USHORT)(tag & SMALL_TAG_SIZE_MASK); size += 1; // length of small tag } else { size = *(USHORT UNALIGNED *)(DeviceData + 1); size += 3; // length of large tag } DeviceData += size; tag = *DeviceData; // // Do we reach the compatible ID descriptor? // if ((tag & SMALL_TAG_MASK) == TAG_COMPATIBLE_ID) { if (count == IdIndex) { id = *(ULONG UNALIGNED *)(DeviceData + 1); status = STATUS_SUCCESS; break; } else { count++; } } } while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)); } if (NT_SUCCESS(status)) { PipDecompressEisaId(id, eisaId); RtlInitAnsiString(&ansiString, eisaId); RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE); *Buffer = (PWCHAR)ExAllocatePool ( PagedPool, sizeof(L"*") + sizeof(WCHAR) + unicodeString.Length ); if (*Buffer) { swprintf(*Buffer, L"*%s", unicodeString.Buffer); } else { status = STATUS_INSUFFICIENT_RESOURCES; } RtlFreeUnicodeString(&unicodeString); } return status; } NTSTATUS PipQueryDeviceUniqueId ( PDEVICE_INFORMATION DeviceInfo, PWCHAR *DeviceId ) /*++ Routine Description: This function returns the unique id for the particular device. Arguments: DeviceData - Device data information for the specificied device. DeviceId - supplies a pointer to a variable to receive device id. Return Value: NTSTATUS code. --*/ { NTSTATUS status = STATUS_SUCCESS; // // Set up device's unique id. // device unique id = SerialNumber of the card // *DeviceId = (PWCHAR)ExAllocatePool ( PagedPool, (8 + 1) * sizeof(WCHAR) // serial number + null ); if (*DeviceId) { swprintf (*DeviceId, L"%08X", ((PSERIAL_IDENTIFIER) (DeviceInfo->CardInformation->CardData))->SerialNumber ); #if IDBG { ANSI_STRING ansiString; UNICODE_STRING unicodeString; RtlInitUnicodeString(&unicodeString, *DeviceId); RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE); DbgPrint("PnpIsa: return Unique Id = %s\n", ansiString.Buffer); RtlFreeAnsiString(&ansiString); } #endif } else { status = STATUS_INSUFFICIENT_RESOURCES; } return status; } NTSTATUS PipQueryDeviceId ( PDEVICE_INFORMATION DeviceInfo, PWCHAR *DeviceId, ULONG IdIndex ) /*++ Routine Description: This function returns the device id for the particular device. Arguments: DeviceInfo - Device information for the specificied device. DeviceId - supplies a pointer to a variable to receive the device id. IdIndex - specifies device id or compatible id (0 - device id) Return Value: NTSTATUS code. --*/ { NTSTATUS status = STATUS_SUCCESS; PWSTR format; ULONG size; UCHAR eisaId[8]; UNICODE_STRING unicodeString; ANSI_STRING ansiString; // // Set up device's id. // device id = VenderId + Logical device number // if (DeviceInfo->CardInformation->NumberLogicalDevices == 1) { format = L"ISAPNP\\%s"; size = sizeof(L"ISAPNP\\*") + sizeof(WCHAR); } else { format = L"ISAPNP\\%s_DEV%04X"; size = sizeof(L"ISAPNP\\_DEV") + 4 * sizeof(WCHAR) + sizeof(WCHAR); } PipDecompressEisaId( ((PSERIAL_IDENTIFIER) (DeviceInfo->CardInformation->CardData))->VenderId, eisaId ); RtlInitAnsiString(&ansiString, eisaId); RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE); size += unicodeString.Length; *DeviceId = (PWCHAR)ExAllocatePool (PagedPool, size); if (*DeviceId) { swprintf (*DeviceId, format, unicodeString.Buffer, DeviceInfo->LogicalDeviceNumber ); #if IDBG { ANSI_STRING dbgAnsiString; UNICODE_STRING dbgUnicodeString; RtlInitUnicodeString(&dbgUnicodeString, *DeviceId); RtlUnicodeStringToAnsiString(&dbgAnsiString, &dbgUnicodeString, TRUE); DbgPrint("PnpIsa: return device Id = %s\n", dbgAnsiString.Buffer); RtlFreeAnsiString(&dbgAnsiString); } #endif } else { status = STATUS_INSUFFICIENT_RESOURCES; } RtlFreeUnicodeString(&unicodeString); return status; } NTSTATUS PipQueryDeviceResources ( PDEVICE_INFORMATION DeviceInfo, ULONG BusNumber, PCM_RESOURCE_LIST *CmResources, ULONG *Size ) /*++ Routine Description: This function returns the bus resources being used by the specified device Arguments: DeviceInfo - Device information for the specificied slot BusNumber - should always be 0 CmResources - supplies a pointer to a variable to receive the device resource data. Size - Supplies a pointer to avariable to receive the size of device resource data. Return Value: NTSTATUS code. --*/ { ULONG length; NTSTATUS status; PCM_RESOURCE_LIST cmResources; PipSelectLogicalDevice(DeviceInfo->CardInformation->CardSelectNumber, DeviceInfo->LogicalDeviceNumber, FALSE ); status = PipReadDeviceBootResourceData ( BusNumber, DeviceInfo->DeviceData, &cmResources, &length ); // // Put all cards into wait for key state. // PipWriteAddress(CONFIG_CONTROL_PORT); PipWriteData(CONTROL_WAIT_FOR_KEY); // // Return results // if (NT_SUCCESS(status)) { if (length == 0) { cmResources = NULL; // Just to make sure. } *CmResources = cmResources; *Size = length; #if IDBG PipDumpCmResourceList(cmResources); #endif } return status; } NTSTATUS PipQueryDeviceResourceRequirements ( PDEVICE_INFORMATION DeviceInfo, ULONG BusNumber, ULONG Slot, PIO_RESOURCE_REQUIREMENTS_LIST *IoResources, ULONG *Size ) /*++ Routine Description: This function returns the possible bus resources that this device may be satisfied with. Arguments: DeviceData - Device data information for the specificied slot BusNumber - Supplies the bus number Slot - supplies the slot number of the BusNumber IoResources - supplies a pointer to a variable to receive the IO resource requirements list Return Value: The device control is completed --*/ { ULONG length = 0; NTSTATUS status; PUCHAR deviceData; PIO_RESOURCE_REQUIREMENTS_LIST ioResources; deviceData = DeviceInfo->DeviceData; status = PbBiosResourcesToNtResources ( BusNumber, Slot, &deviceData, &ioResources, &length ); // // Return results // if (NT_SUCCESS(status)) { if (length == 0) { ioResources = NULL; // Just ot make sure } *IoResources = ioResources; *Size = length; #if IDBG PipDumpIoResourceList(ioResources); #endif } return status; } NTSTATUS PipSetDeviceResources ( PDEVICE_INFORMATION DeviceInfo, PCM_RESOURCE_LIST CmResources ) /*++ Routine Description: This function configures the device to the specified device setttings Arguments: DeviceInfo - Device information for the specificied slot CmResources - pointer to the desired resource list Return Value: NTSTATUS code. --*/ { NTSTATUS status; PAGED_CODE(); PipSelectLogicalDevice(DeviceInfo->CardInformation->CardSelectNumber, DeviceInfo->LogicalDeviceNumber, FALSE ); // // Set resource settings for the device // status = PipWriteDeviceBootResourceData ( DeviceInfo->DeviceData, (PCM_RESOURCE_LIST) CmResources ); // // Put all cards into wait for key state. // PipWriteAddress(CONFIG_CONTROL_PORT); PipWriteData(CONTROL_WAIT_FOR_KEY); return status; }