/*++ 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 "..\..\pnpbios\i386\pbios.h" NTSTATUS PipGetCompatibleDeviceId ( PUCHAR DeviceData, ULONG IdIndex, PWCHAR Buffer ); #define IDBG 1 #pragma alloc_text(PAGE,PipGetCompatibleDeviceId) #pragma alloc_text(PAGE,PiCtlQueryDeviceId) #pragma alloc_text(PAGE,PiCtlQueryDeviceUniqueId) #pragma alloc_text(PAGE,PiCtlQueryDeviceResources) #pragma alloc_text(PAGE,PiCtlQueryDeviceResourceRequirements) #pragma alloc_text(PAGE,PiCtlSetDeviceResources) 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 a buffer to receive 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; PAGED_CODE(); 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 = *(PULONG)DeviceData; status = STATUS_SUCCESS; } else { // // caller is asking for compatible id // IdIndex--; // // Skip all the resource descriptors to find compatible Id descriptor // while (tag != TAG_COMPLETE_END) { // // Do we reach the compatible ID descriptor? // if ((tag & SMALL_TAG_MASK) == TAG_COMPATIBLE_ID) { if (count == IdIndex) { id = *(PULONG)(DeviceData + 1); status = STATUS_SUCCESS; break; } else { count++; } } // // 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 = *(PUSHORT)(DeviceData + 1); size += 3; // length of large tag } DeviceData += size; tag = *DeviceData; } } if (NT_SUCCESS(status)) { PipDecompressEisaId(id, eisaId); RtlInitAnsiString(&ansiString, eisaId); RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE); swprintf(Buffer, L"PNPISA\\*%s", unicodeString.Buffer); RtlFreeUnicodeString(&unicodeString); } return status; } VOID PiCtlQueryDeviceUniqueId ( PDEVICE_INFORMATION DeviceInfo, PHAL_DEVICE_CONTROL_CONTEXT Context ) /*++ Routine Description: This function returns the unique id for the particular device. Arguments: DeviceData - Device data information for the specificied device. Context - Device control context of the request. Return Value: The device control is completed --*/ { NTSTATUS status = STATUS_SUCCESS; PWCHAR deviceId; PUCHAR deviceData; ULONG eisaid; PAGED_CODE(); // // Set up device's unique id. // device unique id = card series number + logical device eisa id in compressed form // deviceId = (PWCHAR) Context->DeviceControl.Buffer; deviceData = DeviceInfo->DeviceData; // // Make sure device data points to Logical Device Id tag // if ((*deviceData & SMALL_TAG_MASK) != TAG_LOGICAL_ID) { // // Can not get the eisa compressed id. Use logical device number instead. // #if DBG DbgPrint("PipGetCompatibleDeviceId: DeviceData is not at Logical Id tag\n"); #endif eisaid = DeviceInfo->LogicalDeviceNumber; } else { // // Get the eisa compressed id for the logical device. // deviceData++; // Skip tag eisaid = *(PULONG)deviceData; } swprintf (deviceId, L"%08x%08x", ((PSERIAL_IDENTIFIER) (DeviceInfo->CardInformation->CardData))->SerialNumber, eisaid ); #if IDBG { ANSI_STRING ansiString; UNICODE_STRING unicodeString; RtlInitUnicodeString(&unicodeString, (PWCHAR)Context->DeviceControl.Buffer); RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE); DbgPrint("Bus %x Slot %x Unique Id = %s\n", Context->Handler->BusNumber, DeviceInfoSlot(DeviceInfo), ansiString.Buffer ); RtlFreeAnsiString(&ansiString); } #endif PipCompleteDeviceControl (STATUS_SUCCESS, Context, DeviceInfo); } VOID PiCtlQueryDeviceId ( PDEVICE_INFORMATION DeviceInfo, PHAL_DEVICE_CONTROL_CONTEXT Context ) /*++ Routine Description: This function returns the device id for the particular device. Arguments: DeviceInfo - Device information for the specificied device. Context - Device control context of the request. Return Value: The device control is completed --*/ { NTSTATUS status; PWCHAR deviceId; ULONG idIndex; PAGED_CODE(); // // Determine which device ID the caller wants back // idIndex = *((PULONG) Context->DeviceControl.Buffer); // // Call worker routine to get the desired Id. // deviceId = (PWCHAR) Context->DeviceControl.Buffer; status = PipGetCompatibleDeviceId(DeviceInfo->DeviceData, idIndex, (PWCHAR) deviceId); #if IDBG if (NT_SUCCESS(status)) { ANSI_STRING ansiString; UNICODE_STRING unicodeString; RtlInitUnicodeString(&unicodeString, deviceId); RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE); DbgPrint("Bus %x Slot %x IdIndex %x Compatible Id = %s\n", Context->Handler->BusNumber, DeviceInfoSlot(DeviceInfo), idIndex, ansiString.Buffer ); RtlFreeAnsiString(&ansiString); } #endif PipCompleteDeviceControl (status, Context, DeviceInfo); } VOID PiCtlQueryDeviceResources ( PDEVICE_INFORMATION DeviceInfo, PHAL_DEVICE_CONTROL_CONTEXT Context ) /*++ Routine Description: This function completes the QUERY_DEVICE_RESOURCES DeviceControl which returns the bus resources being used by the specified device Arguments: DeviceInfo - Device information for the specificied slot Context - Device control context of the request Return Value: The device control is completed --*/ { ULONG length; PCM_RESOURCE_LIST cmResources; NTSTATUS status; PAGED_CODE(); // // protect port access // ExAcquireFastMutex(&PipPortMutex); PipSelectLogicalDevice(DeviceInfo->CardInformation->CardSelectNumber, DeviceInfo->LogicalDeviceNumber ); status = PipReadDeviceBootResourceData ( Context->Handler->BusNumber, DeviceInfo->DeviceData, &cmResources, &length ); PipWriteAddress(ACTIVATE_PORT); PipWriteData(0); // // Put all cards into wait for key state. // PipWriteAddress(CONFIG_CONTROL_PORT); PipWriteData(CONTROL_WAIT_FOR_KEY); ExReleaseFastMutex(&PipPortMutex); // // Return results // if (NT_SUCCESS(status)) { if (length == 0) { // // If resource info is not available, return an empty CM_RESOURCE_LIST // cmResources = (PCM_RESOURCE_LIST) ExAllocatePoolWithTag ( PagedPool, sizeof(CM_RESOURCE_LIST), 'iPnP'); if (!cmResources) { status = STATUS_INSUFFICIENT_RESOURCES; goto exitLocal; } else { cmResources->Count = 0; cmResources->List[0].InterfaceType = Context->RootHandler->InterfaceType; cmResources->List[0].BusNumber = Context->RootHandler->BusNumber; cmResources->List[0].PartialResourceList.Version = 0; cmResources->List[0].PartialResourceList.Revision = 0; cmResources->List[0].PartialResourceList.Count = 0; length = sizeof(CM_RESOURCE_LIST); } } if (length > *Context->DeviceControl.BufferLength) { status = STATUS_BUFFER_TOO_SMALL; } else { RtlCopyMemory (Context->DeviceControl.Buffer, cmResources, length); } *Context->DeviceControl.BufferLength = length; #if IDBG if (NT_SUCCESS(status)) { PipDumpCmResourceList(cmResources, DeviceInfoSlot(DeviceInfo)); } #endif ExFreePool(cmResources); } exitLocal: PipCompleteDeviceControl (status, Context, DeviceInfo); } VOID PiCtlQueryDeviceResourceRequirements ( PDEVICE_INFORMATION DeviceInfo, PHAL_DEVICE_CONTROL_CONTEXT Context ) /*++ Routine Description: This function completes the QUERY_DEVICE_RESOURCE_REQUIREMENTS DeviceControl which returns the possible bus resources that this device may be satisfied with. Arguments: DeviceData - Device data information for the specificied slot Context - Device control context of the request Return Value: The device control is completed --*/ { ULONG length = 0; PIO_RESOURCE_REQUIREMENTS_LIST ioResources = NULL; NTSTATUS status; PUCHAR deviceData; PAGED_CODE(); deviceData = DeviceInfo->DeviceData; status = PbBiosResourcesToNtResources ( Context->RootHandler->BusNumber, DeviceInfoSlot(DeviceInfo), &deviceData, &ioResources, &length ); // // Return results // if (NT_SUCCESS(status)) { if (length == 0) { // // If resource info is not available, return an empty CM_RESOURCE_LIST // ioResources = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePoolWithTag ( PagedPool, sizeof(IO_RESOURCE_REQUIREMENTS_LIST), 'bPnP'); if (!ioResources) { status = STATUS_INSUFFICIENT_RESOURCES; goto exitLocal; } else { ioResources->ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST); ioResources->InterfaceType = Context->RootHandler->InterfaceType; ioResources->BusNumber = Context->RootHandler->BusNumber; ioResources->SlotNumber = DeviceInfoSlot(DeviceInfo); ioResources->Reserved[0] = 0; ioResources->Reserved[1] = 0; ioResources->Reserved[2] = 0; ioResources->AlternativeLists = 0; ioResources->List[0].Version = 1; ioResources->List[0].Revision = 1; ioResources->List[0].Count = 0; length = sizeof(IO_RESOURCE_REQUIREMENTS_LIST); } } if (length > *Context->DeviceControl.BufferLength) { status = STATUS_BUFFER_TOO_SMALL; } else { RtlCopyMemory (Context->DeviceControl.Buffer, ioResources, length); } *Context->DeviceControl.BufferLength = length; #if IDBG if (NT_SUCCESS(status)) { PipDumpIoResourceList(ioResources); } #endif ExFreePool(ioResources); } exitLocal: PipCompleteDeviceControl (status, Context, DeviceInfo); } VOID PiCtlSetDeviceResources ( PDEVICE_INFORMATION DeviceInfo, PHAL_DEVICE_CONTROL_CONTEXT Context ) /*++ Routine Description: This function completes the SET_DEVICE_RESOURCES DeviceControl which configures the device to the specified device setttings Arguments: DeviceInfo - Device information for the specificied slot Context - Device control context of the request Return Value: The device control is completed --*/ { NTSTATUS status; PAGED_CODE(); // // Protect port access // ExAcquireFastMutex(&PipPortMutex); PipSelectLogicalDevice(DeviceInfo->CardInformation->CardSelectNumber, DeviceInfo->LogicalDeviceNumber ); // // Set resource settings for the device // status = PipWriteDeviceBootResourceData ( DeviceInfo->DeviceData, (PCM_RESOURCE_LIST) Context->DeviceControl.Buffer ); // // Put all cards into wait for key state. // PipWriteAddress(CONFIG_CONTROL_PORT); PipWriteData(CONTROL_WAIT_FOR_KEY); ExReleaseFastMutex(&PipPortMutex); PipCompleteDeviceControl (status, Context, DeviceInfo); }