reactos/drivers/bus/acpi/buspdo.c

2066 lines
84 KiB
C

#ifndef UNIT_TEST
#include "precomp.h"
#include <initguid.h>
#include <poclass.h>
#define NDEBUG
#include <debug.h>
#ifdef ALLOC_PRAGMA
#pragma alloc_text (PAGE, Bus_PDO_PnP)
#pragma alloc_text (PAGE, Bus_PDO_QueryDeviceCaps)
#pragma alloc_text (PAGE, Bus_PDO_QueryDeviceId)
#pragma alloc_text (PAGE, Bus_PDO_QueryDeviceText)
#pragma alloc_text (PAGE, Bus_PDO_QueryResources)
#pragma alloc_text (PAGE, Bus_PDO_QueryResourceRequirements)
#pragma alloc_text (PAGE, Bus_PDO_QueryDeviceRelations)
#pragma alloc_text (PAGE, Bus_PDO_QueryBusInformation)
#pragma alloc_text (PAGE, Bus_GetDeviceCapabilities)
#endif
NTSTATUS
Bus_PDO_PnP (
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PIO_STACK_LOCATION IrpStack,
PPDO_DEVICE_DATA DeviceData
)
{
NTSTATUS status;
POWER_STATE state;
struct acpi_device *device = NULL;
PAGED_CODE ();
if (DeviceData->AcpiHandle)
acpi_bus_get_device(DeviceData->AcpiHandle, &device);
//
// NB: Because we are a bus enumerator, we have no one to whom we could
// defer these irps. Therefore we do not pass them down but merely
// return them.
//
switch (IrpStack->MinorFunction) {
case IRP_MN_START_DEVICE:
//
// Here we do what ever initialization and ``turning on'' that is
// required to allow others to access this device.
// Power up the device.
//
if (DeviceData->AcpiHandle && acpi_bus_power_manageable(DeviceData->AcpiHandle) &&
!ACPI_SUCCESS(acpi_bus_set_power(DeviceData->AcpiHandle, ACPI_STATE_D0)))
{
DPRINT1("Device %x failed to start!\n", DeviceData->AcpiHandle);
status = STATUS_UNSUCCESSFUL;
break;
}
DeviceData->InterfaceName.Length = 0;
status = STATUS_SUCCESS;
if (!device)
{
status = IoRegisterDeviceInterface(DeviceData->Common.Self,
&GUID_DEVICE_SYS_BUTTON,
NULL,
&DeviceData->InterfaceName);
}
else if (device->flags.hardware_id &&
strstr(device->pnp.hardware_id, ACPI_THERMAL_HID))
{
status = IoRegisterDeviceInterface(DeviceData->Common.Self,
&GUID_DEVICE_THERMAL_ZONE,
NULL,
&DeviceData->InterfaceName);
}
else if (device->flags.hardware_id &&
strstr(device->pnp.hardware_id, ACPI_BUTTON_HID_LID))
{
status = IoRegisterDeviceInterface(DeviceData->Common.Self,
&GUID_DEVICE_LID,
NULL,
&DeviceData->InterfaceName);
}
else if (device->flags.hardware_id &&
strstr(device->pnp.hardware_id, ACPI_PROCESSOR_HID))
{
status = IoRegisterDeviceInterface(DeviceData->Common.Self,
&GUID_DEVICE_PROCESSOR,
NULL,
&DeviceData->InterfaceName);
}
/* Failure to register an interface is not a fatal failure so don't return a failure status */
if (NT_SUCCESS(status) && DeviceData->InterfaceName.Length != 0)
IoSetDeviceInterfaceState(&DeviceData->InterfaceName, TRUE);
state.DeviceState = PowerDeviceD0;
PoSetPowerState(DeviceData->Common.Self, DevicePowerState, state);
DeviceData->Common.DevicePowerState = PowerDeviceD0;
SET_NEW_PNP_STATE(DeviceData->Common, Started);
status = STATUS_SUCCESS;
break;
case IRP_MN_STOP_DEVICE:
if (DeviceData->InterfaceName.Length != 0)
IoSetDeviceInterfaceState(&DeviceData->InterfaceName, FALSE);
//
// Here we shut down the device and give up and unmap any resources
// we acquired for the device.
//
if (DeviceData->AcpiHandle && acpi_bus_power_manageable(DeviceData->AcpiHandle) &&
!ACPI_SUCCESS(acpi_bus_set_power(DeviceData->AcpiHandle, ACPI_STATE_D3)))
{
DPRINT1("Device %x failed to stop!\n", DeviceData->AcpiHandle);
status = STATUS_UNSUCCESSFUL;
break;
}
state.DeviceState = PowerDeviceD3;
PoSetPowerState(DeviceData->Common.Self, DevicePowerState, state);
DeviceData->Common.DevicePowerState = PowerDeviceD3;
SET_NEW_PNP_STATE(DeviceData->Common, Stopped);
status = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_STOP_DEVICE:
//
// No reason here why we can't stop the device.
// If there were a reason we should speak now, because answering success
// here may result in a stop device irp.
//
SET_NEW_PNP_STATE(DeviceData->Common, StopPending);
status = STATUS_SUCCESS;
break;
case IRP_MN_CANCEL_STOP_DEVICE:
//
// The stop was canceled. Whatever state we set, or resources we put
// on hold in anticipation of the forthcoming STOP device IRP should be
// put back to normal. Someone, in the long list of concerned parties,
// has failed the stop device query.
//
//
// First check to see whether you have received cancel-stop
// without first receiving a query-stop. This could happen if someone
// above us fails a query-stop and passes down the subsequent
// cancel-stop.
//
if (StopPending == DeviceData->Common.DevicePnPState)
{
//
// We did receive a query-stop, so restore.
//
RESTORE_PREVIOUS_PNP_STATE(DeviceData->Common);
}
status = STATUS_SUCCESS;// We must not fail this IRP.
break;
case IRP_MN_REMOVE_DEVICE:
//
// We handle REMOVE_DEVICE just like STOP_DEVICE. This is because
// the device is still physically present (or at least we don't know any better)
// so we have to retain the PDO after stopping and removing power from it.
//
if (DeviceData->InterfaceName.Length != 0)
IoSetDeviceInterfaceState(&DeviceData->InterfaceName, FALSE);
if (DeviceData->AcpiHandle && acpi_bus_power_manageable(DeviceData->AcpiHandle) &&
!ACPI_SUCCESS(acpi_bus_set_power(DeviceData->AcpiHandle, ACPI_STATE_D3)))
{
DPRINT1("Device %x failed to enter D3!\n", DeviceData->AcpiHandle);
state.DeviceState = PowerDeviceD3;
PoSetPowerState(DeviceData->Common.Self, DevicePowerState, state);
DeviceData->Common.DevicePowerState = PowerDeviceD3;
}
SET_NEW_PNP_STATE(DeviceData->Common, Stopped);
status = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
SET_NEW_PNP_STATE(DeviceData->Common, RemovalPending);
status = STATUS_SUCCESS;
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
if (RemovalPending == DeviceData->Common.DevicePnPState)
{
RESTORE_PREVIOUS_PNP_STATE(DeviceData->Common);
}
status = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_CAPABILITIES:
//
// Return the capabilities of a device, such as whether the device
// can be locked or ejected..etc
//
status = Bus_PDO_QueryDeviceCaps(DeviceData, Irp);
break;
case IRP_MN_QUERY_ID:
// Query the IDs of the device
status = Bus_PDO_QueryDeviceId(DeviceData, Irp);
break;
case IRP_MN_QUERY_DEVICE_RELATIONS:
DPRINT("\tQueryDeviceRelation Type: %s\n",DbgDeviceRelationString(\
IrpStack->Parameters.QueryDeviceRelations.Type));
status = Bus_PDO_QueryDeviceRelations(DeviceData, Irp);
break;
case IRP_MN_QUERY_DEVICE_TEXT:
status = Bus_PDO_QueryDeviceText(DeviceData, Irp);
break;
case IRP_MN_QUERY_RESOURCES:
status = Bus_PDO_QueryResources(DeviceData, Irp);
break;
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
status = Bus_PDO_QueryResourceRequirements(DeviceData, Irp);
break;
case IRP_MN_QUERY_BUS_INFORMATION:
status = Bus_PDO_QueryBusInformation(DeviceData, Irp);
break;
case IRP_MN_QUERY_INTERFACE:
status = Bus_PDO_QueryInterface(DeviceData, Irp);
break;
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
//
// OPTIONAL for bus drivers.
// The PnP Manager sends this IRP to a device
// stack so filter and function drivers can adjust the
// resources required by the device, if appropriate.
//
//break;
//case IRP_MN_QUERY_PNP_DEVICE_STATE:
//
// OPTIONAL for bus drivers.
// The PnP Manager sends this IRP after the drivers for
// a device return success from the IRP_MN_START_DEVICE
// request. The PnP Manager also sends this IRP when a
// driver for the device calls IoInvalidateDeviceState.
//
// break;
//case IRP_MN_READ_CONFIG:
//case IRP_MN_WRITE_CONFIG:
//
// Bus drivers for buses with configuration space must handle
// this request for their child devices. Our devices don't
// have a config space.
//
// break;
//case IRP_MN_SET_LOCK:
// break;
default:
//
// For PnP requests to the PDO that we do not understand we should
// return the IRP WITHOUT setting the status or information fields.
// These fields may have already been set by a filter (eg acpi).
status = Irp->IoStatus.Status;
break;
}
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS
Bus_PDO_QueryDeviceCaps(
PPDO_DEVICE_DATA DeviceData,
PIRP Irp )
{
PIO_STACK_LOCATION stack;
PDEVICE_CAPABILITIES deviceCapabilities;
struct acpi_device *device = NULL;
ULONG i;
PAGED_CODE ();
if (DeviceData->AcpiHandle)
acpi_bus_get_device(DeviceData->AcpiHandle, &device);
stack = IoGetCurrentIrpStackLocation (Irp);
//
// Get the packet.
//
deviceCapabilities=stack->Parameters.DeviceCapabilities.Capabilities;
//
// Set the capabilities.
//
if (deviceCapabilities->Version != 1 ||
deviceCapabilities->Size < sizeof(DEVICE_CAPABILITIES))
{
return STATUS_UNSUCCESSFUL;
}
deviceCapabilities->D1Latency = 0;
deviceCapabilities->D2Latency = 0;
deviceCapabilities->D3Latency = 0;
deviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0;
deviceCapabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD3;
deviceCapabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
deviceCapabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
for (i = 0; i < ACPI_D_STATE_COUNT && device; i++)
{
if (!device->power.states[i].flags.valid)
continue;
switch (i)
{
case ACPI_STATE_D0:
deviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0;
break;
case ACPI_STATE_D1:
deviceCapabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
deviceCapabilities->D1Latency = device->power.states[i].latency;
break;
case ACPI_STATE_D2:
deviceCapabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD2;
deviceCapabilities->D2Latency = device->power.states[i].latency;
break;
case ACPI_STATE_D3:
deviceCapabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
deviceCapabilities->D3Latency = device->power.states[i].latency;
break;
}
}
// We can wake the system from D1
deviceCapabilities->DeviceWake = PowerDeviceD1;
deviceCapabilities->DeviceD1 =
(deviceCapabilities->DeviceState[PowerSystemSleeping1] == PowerDeviceD1) ? TRUE : FALSE;
deviceCapabilities->DeviceD2 =
(deviceCapabilities->DeviceState[PowerSystemSleeping2] == PowerDeviceD2) ? TRUE : FALSE;
deviceCapabilities->WakeFromD0 = FALSE;
deviceCapabilities->WakeFromD1 = TRUE; //Yes we can
deviceCapabilities->WakeFromD2 = FALSE;
deviceCapabilities->WakeFromD3 = FALSE;
if (device)
{
deviceCapabilities->LockSupported = device->flags.lockable;
deviceCapabilities->EjectSupported = device->flags.ejectable;
deviceCapabilities->HardwareDisabled = !device->status.enabled && !device->status.functional;
deviceCapabilities->Removable = device->flags.removable;
deviceCapabilities->SurpriseRemovalOK = device->flags.surprise_removal_ok;
deviceCapabilities->UniqueID = device->flags.unique_id;
deviceCapabilities->NoDisplayInUI = !device->status.show_in_ui;
deviceCapabilities->Address = device->pnp.bus_address;
}
if (!device ||
(device->flags.hardware_id &&
(strstr(device->pnp.hardware_id, ACPI_BUTTON_HID_LID) ||
strstr(device->pnp.hardware_id, ACPI_THERMAL_HID) ||
strstr(device->pnp.hardware_id, ACPI_PROCESSOR_HID))))
{
/* Allow ACPI to control the device if it is a lid button,
* a thermal zone, a processor, or a fixed feature button */
deviceCapabilities->RawDeviceOK = TRUE;
}
deviceCapabilities->SilentInstall = FALSE;
deviceCapabilities->UINumber = (ULONG)-1;
return STATUS_SUCCESS;
}
NTSTATUS
Bus_PDO_QueryDeviceId(
PPDO_DEVICE_DATA DeviceData,
PIRP Irp )
{
PIO_STACK_LOCATION stack;
PWCHAR buffer, src;
WCHAR temp[256];
ULONG length, i;
NTSTATUS status = STATUS_SUCCESS;
struct acpi_device *Device;
PAGED_CODE ();
stack = IoGetCurrentIrpStackLocation (Irp);
switch (stack->Parameters.QueryId.IdType) {
case BusQueryDeviceID:
/* This is a REG_SZ value */
if (DeviceData->AcpiHandle)
{
acpi_bus_get_device(DeviceData->AcpiHandle, &Device);
if (strcmp(Device->pnp.hardware_id, "Processor") == 0)
{
length = wcslen(ProcessorIdString);
wcscpy(temp, ProcessorIdString);
}
else
{
length = swprintf(temp,
L"ACPI\\%hs",
Device->pnp.hardware_id);
}
}
else
{
/* We know it's a fixed feature button because
* these are direct children of the ACPI root device
* and therefore have no handle
*/
length = swprintf(temp,
L"ACPI\\FixedButton");
}
temp[length++] = UNICODE_NULL;
NT_ASSERT(length * sizeof(WCHAR) <= sizeof(temp));
buffer = ExAllocatePoolWithTag(PagedPool, length * sizeof(WCHAR), 'IpcA');
if (!buffer) {
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlCopyMemory (buffer, temp, length * sizeof(WCHAR));
Irp->IoStatus.Information = (ULONG_PTR) buffer;
DPRINT("BusQueryDeviceID: %ls\n",buffer);
break;
case BusQueryInstanceID:
/* This is a REG_SZ value */
/* See comment in BusQueryDeviceID case */
if(DeviceData->AcpiHandle)
{
acpi_bus_get_device(DeviceData->AcpiHandle, &Device);
if (Device->flags.unique_id)
length = swprintf(temp,
L"%hs",
Device->pnp.unique_id);
else
/* FIXME: Generate unique id! */
length = swprintf(temp, L"%ls", L"0");
}
else
{
/* FIXME: Generate unique id! */
length = swprintf(temp, L"%ls", L"0");
}
temp[length++] = UNICODE_NULL;
NT_ASSERT(length * sizeof(WCHAR) <= sizeof(temp));
buffer = ExAllocatePoolWithTag(PagedPool, length * sizeof(WCHAR), 'IpcA');
if (!buffer) {
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlCopyMemory (buffer, temp, length * sizeof (WCHAR));
DPRINT("BusQueryInstanceID: %ls\n",buffer);
Irp->IoStatus.Information = (ULONG_PTR) buffer;
break;
case BusQueryHardwareIDs:
/* This is a REG_MULTI_SZ value */
length = 0;
status = STATUS_NOT_SUPPORTED;
/* See comment in BusQueryDeviceID case */
if (DeviceData->AcpiHandle)
{
acpi_bus_get_device(DeviceData->AcpiHandle, &Device);
if (!Device->flags.hardware_id)
{
/* We don't have the ID to satisfy this request */
break;
}
DPRINT("Device name: %s\n", Device->pnp.device_name);
DPRINT("Hardware ID: %s\n", Device->pnp.hardware_id);
if (strcmp(Device->pnp.hardware_id, "Processor") == 0)
{
length = ProcessorHardwareIds.Length / sizeof(WCHAR);
src = ProcessorHardwareIds.Buffer;
}
else
{
length += swprintf(&temp[length],
L"ACPI\\%hs",
Device->pnp.hardware_id);
temp[length++] = UNICODE_NULL;
length += swprintf(&temp[length],
L"*%hs",
Device->pnp.hardware_id);
temp[length++] = UNICODE_NULL;
temp[length++] = UNICODE_NULL;
src = temp;
}
}
else
{
length += swprintf(&temp[length],
L"ACPI\\FixedButton");
temp[length++] = UNICODE_NULL;
length += swprintf(&temp[length],
L"*FixedButton");
temp[length++] = UNICODE_NULL;
temp[length++] = UNICODE_NULL;
src = temp;
}
NT_ASSERT(length * sizeof(WCHAR) <= sizeof(temp));
buffer = ExAllocatePoolWithTag(PagedPool, length * sizeof(WCHAR), 'IpcA');
if (!buffer) {
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlCopyMemory (buffer, src, length * sizeof(WCHAR));
Irp->IoStatus.Information = (ULONG_PTR) buffer;
DPRINT("BusQueryHardwareIDs: %ls\n",buffer);
status = STATUS_SUCCESS;
break;
case BusQueryCompatibleIDs:
/* This is a REG_MULTI_SZ value */
length = 0;
status = STATUS_NOT_SUPPORTED;
/* See comment in BusQueryDeviceID case */
if (DeviceData->AcpiHandle)
{
acpi_bus_get_device(DeviceData->AcpiHandle, &Device);
if (!Device->flags.hardware_id)
{
/* We don't have the ID to satisfy this request */
break;
}
DPRINT("Device name: %s\n", Device->pnp.device_name);
DPRINT("Hardware ID: %s\n", Device->pnp.hardware_id);
if (strcmp(Device->pnp.hardware_id, "Processor") == 0)
{
length += swprintf(&temp[length],
L"ACPI\\%hs",
Device->pnp.hardware_id);
temp[length++] = UNICODE_NULL;
length += swprintf(&temp[length],
L"*%hs",
Device->pnp.hardware_id);
temp[length++] = UNICODE_NULL;
temp[length++] = UNICODE_NULL;
}
else if (Device->flags.compatible_ids)
{
for (i = 0; i < Device->pnp.cid_list->Count; i++)
{
length += swprintf(&temp[length],
L"ACPI\\%hs",
Device->pnp.cid_list->Ids[i].String);
temp[length++] = UNICODE_NULL;
length += swprintf(&temp[length],
L"*%hs",
Device->pnp.cid_list->Ids[i].String);
temp[length++] = UNICODE_NULL;
}
temp[length++] = UNICODE_NULL;
}
else
{
/* No compatible IDs */
break;
}
NT_ASSERT(length * sizeof(WCHAR) <= sizeof(temp));
buffer = ExAllocatePoolWithTag(PagedPool, length * sizeof(WCHAR), 'IpcA');
if (!buffer)
{
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlCopyMemory (buffer, temp, length * sizeof(WCHAR));
Irp->IoStatus.Information = (ULONG_PTR) buffer;
DPRINT("BusQueryCompatibleIDs: %ls\n",buffer);
status = STATUS_SUCCESS;
}
break;
default:
status = Irp->IoStatus.Status;
}
return status;
}
NTSTATUS
Bus_PDO_QueryDeviceText(
PPDO_DEVICE_DATA DeviceData,
PIRP Irp )
{
PWCHAR Buffer, Temp;
PIO_STACK_LOCATION stack;
NTSTATUS status = Irp->IoStatus.Status;
PAGED_CODE ();
stack = IoGetCurrentIrpStackLocation (Irp);
switch (stack->Parameters.QueryDeviceText.DeviceTextType) {
case DeviceTextDescription:
if (!Irp->IoStatus.Information) {
if (wcsstr (DeviceData->HardwareIDs, L"PNP000") != 0)
Temp = L"Programmable interrupt controller";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP010") != 0)
Temp = L"System timer";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP020") != 0)
Temp = L"DMA controller";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP03") != 0)
Temp = L"Keyboard";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP040") != 0)
Temp = L"Parallel port";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP05") != 0)
Temp = L"Serial port";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP06") != 0)
Temp = L"Disk controller";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP07") != 0)
Temp = L"Disk controller";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP09") != 0)
Temp = L"Display adapter";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP0A0") != 0)
Temp = L"Bus controller";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP0E0") != 0)
Temp = L"PCMCIA controller";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP0F") != 0)
Temp = L"Mouse device";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP8") != 0)
Temp = L"Network adapter";
else if (wcsstr(DeviceData->HardwareIDs, L"PNPA0") != 0)
Temp = L"SCSI controller";
else if (wcsstr(DeviceData->HardwareIDs, L"PNPB0") != 0)
Temp = L"Multimedia device";
else if (wcsstr(DeviceData->HardwareIDs, L"PNPC00") != 0)
Temp = L"Modem";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP0C0C") != 0)
Temp = L"Power Button";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP0C0E") != 0)
Temp = L"Sleep Button";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP0C0D") != 0)
Temp = L"Lid Switch";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP0C09") != 0)
Temp = L"ACPI Embedded Controller";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP0C0B") != 0)
Temp = L"ACPI Fan";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP0A03") != 0 ||
wcsstr(DeviceData->HardwareIDs, L"PNP0A08") != 0)
Temp = L"PCI Root Bridge";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP0C0A") != 0)
Temp = L"ACPI Battery";
else if (wcsstr(DeviceData->HardwareIDs, L"PNP0C0F") != 0)
Temp = L"PCI Interrupt Link";
else if (wcsstr(DeviceData->HardwareIDs, L"ACPI_PWR") != 0)
Temp = L"ACPI Power Resource";
else if (wcsstr(DeviceData->HardwareIDs, L"Processor") != 0)
{
if (ProcessorNameString != NULL)
Temp = ProcessorNameString;
else
Temp = L"Processor";
}
else if (wcsstr(DeviceData->HardwareIDs, L"ThermalZone") != 0)
Temp = L"ACPI Thermal Zone";
else if (wcsstr(DeviceData->HardwareIDs, L"ACPI0002") != 0)
Temp = L"Smart Battery";
else if (wcsstr(DeviceData->HardwareIDs, L"ACPI0003") != 0)
Temp = L"AC Adapter";
/* Simply checking if AcpiHandle is NULL eliminates the need to check
* for the 4 different names that ACPI knows the fixed feature button as internally
*/
else if (!DeviceData->AcpiHandle)
Temp = L"ACPI Fixed Feature Button";
else
Temp = L"Other ACPI device";
Buffer = ExAllocatePoolWithTag(PagedPool, (wcslen(Temp) + 1) * sizeof(WCHAR), 'IpcA');
if (!Buffer) {
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlCopyMemory (Buffer, Temp, (wcslen(Temp) + 1) * sizeof(WCHAR));
DPRINT("\tDeviceTextDescription :%ws\n", Buffer);
Irp->IoStatus.Information = (ULONG_PTR) Buffer;
status = STATUS_SUCCESS;
}
break;
default:
break;
}
return status;
}
NTSTATUS
Bus_PDO_QueryResources(
PPDO_DEVICE_DATA DeviceData,
PIRP Irp )
{
ULONG NumberOfResources = 0;
PCM_RESOURCE_LIST ResourceList;
PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
ACPI_STATUS AcpiStatus;
ACPI_BUFFER Buffer;
ACPI_RESOURCE* resource;
ULONG ResourceListSize;
ULONG i;
ULONGLONG BusNumber;
struct acpi_device *device;
if (!DeviceData->AcpiHandle)
{
return Irp->IoStatus.Status;
}
/* A bus number resource is not included in the list of current resources
* for the root PCI bus so we manually query one here and if we find it
* we create a resource list and add a bus number descriptor to it */
if (wcsstr(DeviceData->HardwareIDs, L"PNP0A03") != 0 ||
wcsstr(DeviceData->HardwareIDs, L"PNP0A08") != 0)
{
acpi_bus_get_device(DeviceData->AcpiHandle, &device);
AcpiStatus = acpi_evaluate_integer(DeviceData->AcpiHandle, "_BBN", NULL, &BusNumber);
if (AcpiStatus != AE_OK)
{
#if 0
if (device->flags.unique_id)
{
/* FIXME: Try the unique ID */
}
else
#endif
{
BusNumber = 0;
DPRINT1("Failed to find a bus number\n");
}
}
else
{
DPRINT("Using _BBN for bus number\n");
}
DPRINT("Found PCI root hub: %d\n", BusNumber);
ResourceListSize = sizeof(CM_RESOURCE_LIST);
ResourceList = ExAllocatePoolWithTag(PagedPool, ResourceListSize, 'RpcA');
if (!ResourceList)
return STATUS_INSUFFICIENT_RESOURCES;
ResourceList->Count = 1;
ResourceList->List[0].InterfaceType = Internal;
ResourceList->List[0].BusNumber = 0;
ResourceList->List[0].PartialResourceList.Version = 1;
ResourceList->List[0].PartialResourceList.Revision = 1;
ResourceList->List[0].PartialResourceList.Count = 1;
ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors;
ResourceDescriptor->Type = CmResourceTypeBusNumber;
ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
ResourceDescriptor->u.BusNumber.Start = BusNumber;
ResourceDescriptor->u.BusNumber.Length = 1;
Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
return STATUS_SUCCESS;
}
/* Get current resources */
Buffer.Length = 0;
AcpiStatus = AcpiGetCurrentResources(DeviceData->AcpiHandle, &Buffer);
if ((!ACPI_SUCCESS(AcpiStatus) && AcpiStatus != AE_BUFFER_OVERFLOW) ||
Buffer.Length == 0)
{
return Irp->IoStatus.Status;
}
Buffer.Pointer = ExAllocatePoolWithTag(PagedPool, Buffer.Length, 'BpcA');
if (!Buffer.Pointer)
return STATUS_INSUFFICIENT_RESOURCES;
AcpiStatus = AcpiGetCurrentResources(DeviceData->AcpiHandle, &Buffer);
if (!ACPI_SUCCESS(AcpiStatus))
{
DPRINT1("AcpiGetCurrentResources #2 failed (0x%x)\n", AcpiStatus);
ASSERT(FALSE);
return STATUS_UNSUCCESSFUL;
}
resource= Buffer.Pointer;
/* Count number of resources */
while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG)
{
switch (resource->Type)
{
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
{
ACPI_RESOURCE_EXTENDED_IRQ *irq_data = (ACPI_RESOURCE_EXTENDED_IRQ*) &resource->Data;
if (irq_data->ProducerConsumer == ACPI_PRODUCER)
break;
NumberOfResources += irq_data->InterruptCount;
break;
}
case ACPI_RESOURCE_TYPE_IRQ:
{
ACPI_RESOURCE_IRQ *irq_data = (ACPI_RESOURCE_IRQ*) &resource->Data;
NumberOfResources += irq_data->InterruptCount;
break;
}
case ACPI_RESOURCE_TYPE_DMA:
{
ACPI_RESOURCE_DMA *dma_data = (ACPI_RESOURCE_DMA*) &resource->Data;
NumberOfResources += dma_data->ChannelCount;
break;
}
case ACPI_RESOURCE_TYPE_ADDRESS16:
case ACPI_RESOURCE_TYPE_ADDRESS32:
case ACPI_RESOURCE_TYPE_ADDRESS64:
case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
{
ACPI_RESOURCE_ADDRESS *addr_res = (ACPI_RESOURCE_ADDRESS*) &resource->Data;
if (addr_res->ProducerConsumer == ACPI_PRODUCER)
break;
NumberOfResources++;
break;
}
case ACPI_RESOURCE_TYPE_MEMORY24:
case ACPI_RESOURCE_TYPE_MEMORY32:
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
case ACPI_RESOURCE_TYPE_FIXED_IO:
case ACPI_RESOURCE_TYPE_IO:
{
NumberOfResources++;
break;
}
default:
{
DPRINT1("Unknown resource type: %d\n", resource->Type);
break;
}
}
resource = ACPI_NEXT_RESOURCE(resource);
}
/* Allocate memory */
ResourceListSize = sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (NumberOfResources - 1);
ResourceList = ExAllocatePoolWithTag(PagedPool, ResourceListSize, 'RpcA');
if (!ResourceList)
{
ExFreePoolWithTag(Buffer.Pointer, 'BpcA');
return STATUS_INSUFFICIENT_RESOURCES;
}
ResourceList->Count = 1;
ResourceList->List[0].InterfaceType = Internal; /* FIXME */
ResourceList->List[0].BusNumber = 0; /* We're the only ACPI bus device in the system */
ResourceList->List[0].PartialResourceList.Version = 1;
ResourceList->List[0].PartialResourceList.Revision = 1;
ResourceList->List[0].PartialResourceList.Count = NumberOfResources;
ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors;
/* Fill resources list structure */
resource = Buffer.Pointer;
while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG)
{
switch (resource->Type)
{
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
{
ACPI_RESOURCE_EXTENDED_IRQ *irq_data = (ACPI_RESOURCE_EXTENDED_IRQ*) &resource->Data;
if (irq_data->ProducerConsumer == ACPI_PRODUCER)
break;
for (i = 0; i < irq_data->InterruptCount; i++)
{
ResourceDescriptor->Type = CmResourceTypeInterrupt;
ResourceDescriptor->ShareDisposition =
(irq_data->Shareable == ACPI_SHARED ? CmResourceShareShared : CmResourceShareDeviceExclusive);
ResourceDescriptor->Flags =
(irq_data->Triggering == ACPI_LEVEL_SENSITIVE ? CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE : CM_RESOURCE_INTERRUPT_LATCHED);
ResourceDescriptor->u.Interrupt.Level =
ResourceDescriptor->u.Interrupt.Vector = irq_data->Interrupts[i];
ResourceDescriptor->u.Interrupt.Affinity = (KAFFINITY)(-1);
ResourceDescriptor++;
}
break;
}
case ACPI_RESOURCE_TYPE_IRQ:
{
ACPI_RESOURCE_IRQ *irq_data = (ACPI_RESOURCE_IRQ*) &resource->Data;
for (i = 0; i < irq_data->InterruptCount; i++)
{
ResourceDescriptor->Type = CmResourceTypeInterrupt;
ResourceDescriptor->ShareDisposition =
(irq_data->Shareable == ACPI_SHARED ? CmResourceShareShared : CmResourceShareDeviceExclusive);
ResourceDescriptor->Flags =
(irq_data->Triggering == ACPI_LEVEL_SENSITIVE ? CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE : CM_RESOURCE_INTERRUPT_LATCHED);
ResourceDescriptor->u.Interrupt.Level =
ResourceDescriptor->u.Interrupt.Vector = irq_data->Interrupts[i];
ResourceDescriptor->u.Interrupt.Affinity = (KAFFINITY)(-1);
ResourceDescriptor++;
}
break;
}
case ACPI_RESOURCE_TYPE_DMA:
{
ACPI_RESOURCE_DMA *dma_data = (ACPI_RESOURCE_DMA*) &resource->Data;
for (i = 0; i < dma_data->ChannelCount; i++)
{
ResourceDescriptor->Type = CmResourceTypeDma;
ResourceDescriptor->Flags = 0;
switch (dma_data->Type)
{
case ACPI_TYPE_A: ResourceDescriptor->Flags |= CM_RESOURCE_DMA_TYPE_A; break;
case ACPI_TYPE_B: ResourceDescriptor->Flags |= CM_RESOURCE_DMA_TYPE_B; break;
case ACPI_TYPE_F: ResourceDescriptor->Flags |= CM_RESOURCE_DMA_TYPE_F; break;
}
if (dma_data->BusMaster == ACPI_BUS_MASTER)
ResourceDescriptor->Flags |= CM_RESOURCE_DMA_BUS_MASTER;
switch (dma_data->Transfer)
{
case ACPI_TRANSFER_8: ResourceDescriptor->Flags |= CM_RESOURCE_DMA_8; break;
case ACPI_TRANSFER_16: ResourceDescriptor->Flags |= CM_RESOURCE_DMA_16; break;
case ACPI_TRANSFER_8_16: ResourceDescriptor->Flags |= CM_RESOURCE_DMA_8_AND_16; break;
}
ResourceDescriptor->u.Dma.Channel = dma_data->Channels[i];
ResourceDescriptor++;
}
break;
}
case ACPI_RESOURCE_TYPE_IO:
{
ACPI_RESOURCE_IO *io_data = (ACPI_RESOURCE_IO*) &resource->Data;
ResourceDescriptor->Type = CmResourceTypePort;
ResourceDescriptor->ShareDisposition = CmResourceShareDriverExclusive;
ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
if (io_data->IoDecode == ACPI_DECODE_16)
ResourceDescriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE;
else
ResourceDescriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
ResourceDescriptor->u.Port.Start.QuadPart = io_data->Minimum;
ResourceDescriptor->u.Port.Length = io_data->AddressLength;
ResourceDescriptor++;
break;
}
case ACPI_RESOURCE_TYPE_FIXED_IO:
{
ACPI_RESOURCE_FIXED_IO *io_data = (ACPI_RESOURCE_FIXED_IO*) &resource->Data;
ResourceDescriptor->Type = CmResourceTypePort;
ResourceDescriptor->ShareDisposition = CmResourceShareDriverExclusive;
ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
ResourceDescriptor->u.Port.Start.QuadPart = io_data->Address;
ResourceDescriptor->u.Port.Length = io_data->AddressLength;
ResourceDescriptor++;
break;
}
case ACPI_RESOURCE_TYPE_ADDRESS16:
{
ACPI_RESOURCE_ADDRESS16 *addr16_data = (ACPI_RESOURCE_ADDRESS16*) &resource->Data;
if (addr16_data->ProducerConsumer == ACPI_PRODUCER)
break;
if (addr16_data->ResourceType == ACPI_BUS_NUMBER_RANGE)
{
ResourceDescriptor->Type = CmResourceTypeBusNumber;
ResourceDescriptor->ShareDisposition = CmResourceShareShared;
ResourceDescriptor->Flags = 0;
ResourceDescriptor->u.BusNumber.Start = addr16_data->Address.Minimum;
ResourceDescriptor->u.BusNumber.Length = addr16_data->Address.AddressLength;
}
else if (addr16_data->ResourceType == ACPI_IO_RANGE)
{
ResourceDescriptor->Type = CmResourceTypePort;
ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
if (addr16_data->Decode == ACPI_POS_DECODE)
ResourceDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE;
ResourceDescriptor->u.Port.Start.QuadPart = addr16_data->Address.Minimum;
ResourceDescriptor->u.Port.Length = addr16_data->Address.AddressLength;
}
else
{
ResourceDescriptor->Type = CmResourceTypeMemory;
ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
ResourceDescriptor->Flags = 0;
if (addr16_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY)
ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
else
ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
switch (addr16_data->Info.Mem.Caching)
{
case ACPI_CACHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break;
case ACPI_WRITE_COMBINING_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break;
case ACPI_PREFETCHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break;
}
ResourceDescriptor->u.Memory.Start.QuadPart = addr16_data->Address.Minimum;
ResourceDescriptor->u.Memory.Length = addr16_data->Address.AddressLength;
}
ResourceDescriptor++;
break;
}
case ACPI_RESOURCE_TYPE_ADDRESS32:
{
ACPI_RESOURCE_ADDRESS32 *addr32_data = (ACPI_RESOURCE_ADDRESS32*) &resource->Data;
if (addr32_data->ProducerConsumer == ACPI_PRODUCER)
break;
if (addr32_data->ResourceType == ACPI_BUS_NUMBER_RANGE)
{
ResourceDescriptor->Type = CmResourceTypeBusNumber;
ResourceDescriptor->ShareDisposition = CmResourceShareShared;
ResourceDescriptor->Flags = 0;
ResourceDescriptor->u.BusNumber.Start = addr32_data->Address.Minimum;
ResourceDescriptor->u.BusNumber.Length = addr32_data->Address.AddressLength;
}
else if (addr32_data->ResourceType == ACPI_IO_RANGE)
{
ResourceDescriptor->Type = CmResourceTypePort;
ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
if (addr32_data->Decode == ACPI_POS_DECODE)
ResourceDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE;
ResourceDescriptor->u.Port.Start.QuadPart = addr32_data->Address.Minimum;
ResourceDescriptor->u.Port.Length = addr32_data->Address.AddressLength;
}
else
{
ResourceDescriptor->Type = CmResourceTypeMemory;
ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
ResourceDescriptor->Flags = 0;
if (addr32_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY)
ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
else
ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
switch (addr32_data->Info.Mem.Caching)
{
case ACPI_CACHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break;
case ACPI_WRITE_COMBINING_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break;
case ACPI_PREFETCHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break;
}
ResourceDescriptor->u.Memory.Start.QuadPart = addr32_data->Address.Minimum;
ResourceDescriptor->u.Memory.Length = addr32_data->Address.AddressLength;
}
ResourceDescriptor++;
break;
}
case ACPI_RESOURCE_TYPE_ADDRESS64:
{
ACPI_RESOURCE_ADDRESS64 *addr64_data = (ACPI_RESOURCE_ADDRESS64*) &resource->Data;
if (addr64_data->ProducerConsumer == ACPI_PRODUCER)
break;
if (addr64_data->ResourceType == ACPI_BUS_NUMBER_RANGE)
{
DPRINT1("64-bit bus address is not supported!\n");
ResourceDescriptor->Type = CmResourceTypeBusNumber;
ResourceDescriptor->ShareDisposition = CmResourceShareShared;
ResourceDescriptor->Flags = 0;
ResourceDescriptor->u.BusNumber.Start = (ULONG)addr64_data->Address.Minimum;
ResourceDescriptor->u.BusNumber.Length = addr64_data->Address.AddressLength;
}
else if (addr64_data->ResourceType == ACPI_IO_RANGE)
{
ResourceDescriptor->Type = CmResourceTypePort;
ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
if (addr64_data->Decode == ACPI_POS_DECODE)
ResourceDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE;
ResourceDescriptor->u.Port.Start.QuadPart = addr64_data->Address.Minimum;
ResourceDescriptor->u.Port.Length = addr64_data->Address.AddressLength;
}
else
{
ResourceDescriptor->Type = CmResourceTypeMemory;
ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
ResourceDescriptor->Flags = 0;
if (addr64_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY)
ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
else
ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
switch (addr64_data->Info.Mem.Caching)
{
case ACPI_CACHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break;
case ACPI_WRITE_COMBINING_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break;
case ACPI_PREFETCHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break;
}
ResourceDescriptor->u.Memory.Start.QuadPart = addr64_data->Address.Minimum;
ResourceDescriptor->u.Memory.Length = addr64_data->Address.AddressLength;
}
ResourceDescriptor++;
break;
}
case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
{
ACPI_RESOURCE_EXTENDED_ADDRESS64 *addr64_data = (ACPI_RESOURCE_EXTENDED_ADDRESS64*) &resource->Data;
if (addr64_data->ProducerConsumer == ACPI_PRODUCER)
break;
if (addr64_data->ResourceType == ACPI_BUS_NUMBER_RANGE)
{
DPRINT1("64-bit bus address is not supported!\n");
ResourceDescriptor->Type = CmResourceTypeBusNumber;
ResourceDescriptor->ShareDisposition = CmResourceShareShared;
ResourceDescriptor->Flags = 0;
ResourceDescriptor->u.BusNumber.Start = (ULONG)addr64_data->Address.Minimum;
ResourceDescriptor->u.BusNumber.Length = addr64_data->Address.AddressLength;
}
else if (addr64_data->ResourceType == ACPI_IO_RANGE)
{
ResourceDescriptor->Type = CmResourceTypePort;
ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
if (addr64_data->Decode == ACPI_POS_DECODE)
ResourceDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE;
ResourceDescriptor->u.Port.Start.QuadPart = addr64_data->Address.Minimum;
ResourceDescriptor->u.Port.Length = addr64_data->Address.AddressLength;
}
else
{
ResourceDescriptor->Type = CmResourceTypeMemory;
ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
ResourceDescriptor->Flags = 0;
if (addr64_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY)
ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
else
ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
switch (addr64_data->Info.Mem.Caching)
{
case ACPI_CACHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break;
case ACPI_WRITE_COMBINING_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break;
case ACPI_PREFETCHABLE_MEMORY: ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break;
}
ResourceDescriptor->u.Memory.Start.QuadPart = addr64_data->Address.Minimum;
ResourceDescriptor->u.Memory.Length = addr64_data->Address.AddressLength;
}
ResourceDescriptor++;
break;
}
case ACPI_RESOURCE_TYPE_MEMORY24:
{
ACPI_RESOURCE_MEMORY24 *mem24_data = (ACPI_RESOURCE_MEMORY24*) &resource->Data;
ResourceDescriptor->Type = CmResourceTypeMemory;
ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_24;
if (mem24_data->WriteProtect == ACPI_READ_ONLY_MEMORY)
ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
else
ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
ResourceDescriptor->u.Memory.Start.QuadPart = mem24_data->Minimum;
ResourceDescriptor->u.Memory.Length = mem24_data->AddressLength;
ResourceDescriptor++;
break;
}
case ACPI_RESOURCE_TYPE_MEMORY32:
{
ACPI_RESOURCE_MEMORY32 *mem32_data = (ACPI_RESOURCE_MEMORY32*) &resource->Data;
ResourceDescriptor->Type = CmResourceTypeMemory;
ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
ResourceDescriptor->Flags = 0;
if (mem32_data->WriteProtect == ACPI_READ_ONLY_MEMORY)
ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
else
ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
ResourceDescriptor->u.Memory.Start.QuadPart = mem32_data->Minimum;
ResourceDescriptor->u.Memory.Length = mem32_data->AddressLength;
ResourceDescriptor++;
break;
}
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
{
ACPI_RESOURCE_FIXED_MEMORY32 *memfixed32_data = (ACPI_RESOURCE_FIXED_MEMORY32*) &resource->Data;
ResourceDescriptor->Type = CmResourceTypeMemory;
ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
ResourceDescriptor->Flags = 0;
if (memfixed32_data->WriteProtect == ACPI_READ_ONLY_MEMORY)
ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
else
ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
ResourceDescriptor->u.Memory.Start.QuadPart = memfixed32_data->Address;
ResourceDescriptor->u.Memory.Length = memfixed32_data->AddressLength;
ResourceDescriptor++;
break;
}
default:
{
break;
}
}
resource = ACPI_NEXT_RESOURCE(resource);
}
ExFreePoolWithTag(Buffer.Pointer, 'BpcA');
Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
return STATUS_SUCCESS;
}
#endif /* UNIT_TEST */
NTSTATUS
Bus_PDO_QueryResourceRequirements(
PPDO_DEVICE_DATA DeviceData,
PIRP Irp )
{
ULONG NumberOfResources = 0;
ACPI_STATUS AcpiStatus;
ACPI_BUFFER Buffer;
ACPI_RESOURCE* resource;
ULONG i, RequirementsListSize;
PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
PIO_RESOURCE_DESCRIPTOR RequirementDescriptor;
BOOLEAN CurrentRes = FALSE;
BOOLEAN SeenStartDependent;
PAGED_CODE ();
if (!DeviceData->AcpiHandle)
{
return Irp->IoStatus.Status;
}
/* Handle the PCI root manually */
if (wcsstr(DeviceData->HardwareIDs, L"PNP0A03") != 0 ||
wcsstr(DeviceData->HardwareIDs, L"PNP0A08") != 0)
{
return Irp->IoStatus.Status;
}
/* Get current resources */
while (TRUE)
{
Buffer.Length = 0;
if (CurrentRes)
AcpiStatus = AcpiGetCurrentResources(DeviceData->AcpiHandle, &Buffer);
else
AcpiStatus = AcpiGetPossibleResources(DeviceData->AcpiHandle, &Buffer);
if ((!ACPI_SUCCESS(AcpiStatus) && AcpiStatus != AE_BUFFER_OVERFLOW) ||
Buffer.Length == 0)
{
if (!CurrentRes)
CurrentRes = TRUE;
else
return Irp->IoStatus.Status;
}
else
break;
}
Buffer.Pointer = ExAllocatePoolWithTag(PagedPool, Buffer.Length, 'BpcA');
if (!Buffer.Pointer)
return STATUS_INSUFFICIENT_RESOURCES;
if (CurrentRes)
AcpiStatus = AcpiGetCurrentResources(DeviceData->AcpiHandle, &Buffer);
else
AcpiStatus = AcpiGetPossibleResources(DeviceData->AcpiHandle, &Buffer);
if (!ACPI_SUCCESS(AcpiStatus))
{
DPRINT1("AcpiGetCurrentResources #2 failed (0x%x)\n", AcpiStatus);
ASSERT(FALSE);
return STATUS_UNSUCCESSFUL;
}
SeenStartDependent = FALSE;
resource = Buffer.Pointer;
/* Count number of resources */
while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG && resource->Type != ACPI_RESOURCE_TYPE_END_DEPENDENT)
{
if (resource->Type == ACPI_RESOURCE_TYPE_START_DEPENDENT)
{
if (SeenStartDependent)
{
break;
}
SeenStartDependent = TRUE;
}
switch (resource->Type)
{
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
{
ACPI_RESOURCE_EXTENDED_IRQ *irq_data = (ACPI_RESOURCE_EXTENDED_IRQ*) &resource->Data;
if (irq_data->ProducerConsumer == ACPI_PRODUCER)
break;
NumberOfResources += irq_data->InterruptCount;
break;
}
case ACPI_RESOURCE_TYPE_IRQ:
{
ACPI_RESOURCE_IRQ *irq_data = (ACPI_RESOURCE_IRQ*) &resource->Data;
NumberOfResources += irq_data->InterruptCount;
break;
}
case ACPI_RESOURCE_TYPE_DMA:
{
ACPI_RESOURCE_DMA *dma_data = (ACPI_RESOURCE_DMA*) &resource->Data;
NumberOfResources += dma_data->ChannelCount;
break;
}
case ACPI_RESOURCE_TYPE_ADDRESS16:
case ACPI_RESOURCE_TYPE_ADDRESS32:
case ACPI_RESOURCE_TYPE_ADDRESS64:
case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
{
ACPI_RESOURCE_ADDRESS *res_addr = (ACPI_RESOURCE_ADDRESS*) &resource->Data;
if (res_addr->ProducerConsumer == ACPI_PRODUCER)
break;
NumberOfResources++;
break;
}
case ACPI_RESOURCE_TYPE_MEMORY24:
case ACPI_RESOURCE_TYPE_MEMORY32:
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
case ACPI_RESOURCE_TYPE_FIXED_IO:
case ACPI_RESOURCE_TYPE_IO:
{
NumberOfResources++;
break;
}
default:
{
break;
}
}
resource = ACPI_NEXT_RESOURCE(resource);
}
RequirementsListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + sizeof(IO_RESOURCE_DESCRIPTOR) * (NumberOfResources - 1);
RequirementsList = ExAllocatePoolWithTag(PagedPool, RequirementsListSize, 'RpcA');
if (!RequirementsList)
{
ExFreePoolWithTag(Buffer.Pointer, 'BpcA');
return STATUS_INSUFFICIENT_RESOURCES;
}
RequirementsList->ListSize = RequirementsListSize;
RequirementsList->InterfaceType = Internal;
RequirementsList->BusNumber = 0;
RequirementsList->SlotNumber = 0; /* Not used by WDM drivers */
RequirementsList->AlternativeLists = 1;
RequirementsList->List[0].Version = 1;
RequirementsList->List[0].Revision = 1;
RequirementsList->List[0].Count = NumberOfResources;
RequirementDescriptor = RequirementsList->List[0].Descriptors;
/* Fill resources list structure */
SeenStartDependent = FALSE;
resource = Buffer.Pointer;
while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG && resource->Type != ACPI_RESOURCE_TYPE_END_DEPENDENT)
{
if (resource->Type == ACPI_RESOURCE_TYPE_START_DEPENDENT)
{
if (SeenStartDependent)
{
break;
}
SeenStartDependent = TRUE;
}
switch (resource->Type)
{
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
{
ACPI_RESOURCE_EXTENDED_IRQ *irq_data = &resource->Data.ExtendedIrq;
if (irq_data->ProducerConsumer == ACPI_PRODUCER)
break;
for (i = 0; i < irq_data->InterruptCount; i++)
{
RequirementDescriptor->Option = (i == 0) ? IO_RESOURCE_PREFERRED : IO_RESOURCE_ALTERNATIVE;
RequirementDescriptor->Type = CmResourceTypeInterrupt;
RequirementDescriptor->ShareDisposition = (irq_data->Shareable == ACPI_SHARED ? CmResourceShareShared : CmResourceShareDeviceExclusive);
RequirementDescriptor->Flags =(irq_data->Triggering == ACPI_LEVEL_SENSITIVE ? CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE : CM_RESOURCE_INTERRUPT_LATCHED);
RequirementDescriptor->u.Interrupt.MinimumVector =
RequirementDescriptor->u.Interrupt.MaximumVector = irq_data->Interrupts[i];
RequirementDescriptor++;
}
break;
}
case ACPI_RESOURCE_TYPE_IRQ:
{
ACPI_RESOURCE_IRQ *irq_data = &resource->Data.Irq;
for (i = 0; i < irq_data->InterruptCount; i++)
{
RequirementDescriptor->Option = (i == 0) ? IO_RESOURCE_PREFERRED : IO_RESOURCE_ALTERNATIVE;
RequirementDescriptor->Type = CmResourceTypeInterrupt;
RequirementDescriptor->ShareDisposition = (irq_data->Shareable == ACPI_SHARED ? CmResourceShareShared : CmResourceShareDeviceExclusive);
RequirementDescriptor->Flags =(irq_data->Triggering == ACPI_LEVEL_SENSITIVE ? CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE : CM_RESOURCE_INTERRUPT_LATCHED);
RequirementDescriptor->u.Interrupt.MinimumVector =
RequirementDescriptor->u.Interrupt.MaximumVector = irq_data->Interrupts[i];
RequirementDescriptor++;
}
break;
}
case ACPI_RESOURCE_TYPE_DMA:
{
ACPI_RESOURCE_DMA *dma_data = &resource->Data.Dma;
for (i = 0; i < dma_data->ChannelCount; i++)
{
RequirementDescriptor->Type = CmResourceTypeDma;
RequirementDescriptor->Flags = 0;
switch (dma_data->Type)
{
case ACPI_TYPE_A: RequirementDescriptor->Flags |= CM_RESOURCE_DMA_TYPE_A; break;
case ACPI_TYPE_B: RequirementDescriptor->Flags |= CM_RESOURCE_DMA_TYPE_B; break;
case ACPI_TYPE_F: RequirementDescriptor->Flags |= CM_RESOURCE_DMA_TYPE_F; break;
}
if (dma_data->BusMaster == ACPI_BUS_MASTER)
RequirementDescriptor->Flags |= CM_RESOURCE_DMA_BUS_MASTER;
switch (dma_data->Transfer)
{
case ACPI_TRANSFER_8: RequirementDescriptor->Flags |= CM_RESOURCE_DMA_8; break;
case ACPI_TRANSFER_16: RequirementDescriptor->Flags |= CM_RESOURCE_DMA_16; break;
case ACPI_TRANSFER_8_16: RequirementDescriptor->Flags |= CM_RESOURCE_DMA_8_AND_16; break;
}
RequirementDescriptor->Option = (i == 0) ? IO_RESOURCE_PREFERRED : IO_RESOURCE_ALTERNATIVE;
RequirementDescriptor->ShareDisposition = CmResourceShareDriverExclusive;
RequirementDescriptor->u.Dma.MinimumChannel =
RequirementDescriptor->u.Dma.MaximumChannel = dma_data->Channels[i];
RequirementDescriptor++;
}
break;
}
case ACPI_RESOURCE_TYPE_IO:
{
ACPI_RESOURCE_IO *io_data = &resource->Data.Io;
RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO;
if (io_data->IoDecode == ACPI_DECODE_16)
RequirementDescriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE;
else
RequirementDescriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
RequirementDescriptor->u.Port.Length = io_data->AddressLength;
RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED;
RequirementDescriptor->Type = CmResourceTypePort;
RequirementDescriptor->ShareDisposition = CmResourceShareDriverExclusive;
RequirementDescriptor->u.Port.Alignment = io_data->Alignment;
RequirementDescriptor->u.Port.MinimumAddress.QuadPart = io_data->Minimum;
RequirementDescriptor->u.Port.MaximumAddress.QuadPart = io_data->Maximum + io_data->AddressLength - 1;
RequirementDescriptor++;
break;
}
case ACPI_RESOURCE_TYPE_FIXED_IO:
{
ACPI_RESOURCE_FIXED_IO *io_data = &resource->Data.FixedIo;
RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO;
RequirementDescriptor->u.Port.Length = io_data->AddressLength;
RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED;
RequirementDescriptor->Type = CmResourceTypePort;
RequirementDescriptor->ShareDisposition = CmResourceShareDriverExclusive;
RequirementDescriptor->u.Port.Alignment = 1;
RequirementDescriptor->u.Port.MinimumAddress.QuadPart = io_data->Address;
RequirementDescriptor->u.Port.MaximumAddress.QuadPart = io_data->Address + io_data->AddressLength - 1;
RequirementDescriptor++;
break;
}
case ACPI_RESOURCE_TYPE_ADDRESS16:
{
ACPI_RESOURCE_ADDRESS16 *addr16_data = &resource->Data.Address16;
if (addr16_data->ProducerConsumer == ACPI_PRODUCER)
break;
RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED;
if (addr16_data->ResourceType == ACPI_BUS_NUMBER_RANGE)
{
RequirementDescriptor->Type = CmResourceTypeBusNumber;
RequirementDescriptor->ShareDisposition = CmResourceShareShared;
RequirementDescriptor->Flags = 0;
RequirementDescriptor->u.BusNumber.MinBusNumber = addr16_data->Address.Minimum;
RequirementDescriptor->u.BusNumber.MaxBusNumber = addr16_data->Address.Maximum + addr16_data->Address.AddressLength - 1;
RequirementDescriptor->u.BusNumber.Length = addr16_data->Address.AddressLength;
}
else if (addr16_data->ResourceType == ACPI_IO_RANGE)
{
RequirementDescriptor->Type = CmResourceTypePort;
RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO;
if (addr16_data->Decode == ACPI_POS_DECODE)
RequirementDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE;
RequirementDescriptor->u.Port.MinimumAddress.QuadPart = addr16_data->Address.Minimum;
RequirementDescriptor->u.Port.MaximumAddress.QuadPart = addr16_data->Address.Maximum + addr16_data->Address.AddressLength - 1;
RequirementDescriptor->u.Port.Length = addr16_data->Address.AddressLength;
}
else
{
RequirementDescriptor->Type = CmResourceTypeMemory;
RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
RequirementDescriptor->Flags = 0;
if (addr16_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY)
RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
else
RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
switch (addr16_data->Info.Mem.Caching)
{
case ACPI_CACHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break;
case ACPI_WRITE_COMBINING_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break;
case ACPI_PREFETCHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break;
}
RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = addr16_data->Address.Minimum;
RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = addr16_data->Address.Maximum + addr16_data->Address.AddressLength - 1;
RequirementDescriptor->u.Memory.Length = addr16_data->Address.AddressLength;
}
RequirementDescriptor++;
break;
}
case ACPI_RESOURCE_TYPE_ADDRESS32:
{
ACPI_RESOURCE_ADDRESS32 *addr32_data = &resource->Data.Address32;
if (addr32_data->ProducerConsumer == ACPI_PRODUCER)
break;
RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED;
if (addr32_data->ResourceType == ACPI_BUS_NUMBER_RANGE)
{
RequirementDescriptor->Type = CmResourceTypeBusNumber;
RequirementDescriptor->ShareDisposition = CmResourceShareShared;
RequirementDescriptor->Flags = 0;
RequirementDescriptor->u.BusNumber.MinBusNumber = addr32_data->Address.Minimum;
RequirementDescriptor->u.BusNumber.MaxBusNumber = addr32_data->Address.Maximum + addr32_data->Address.AddressLength - 1;
RequirementDescriptor->u.BusNumber.Length = addr32_data->Address.AddressLength;
}
else if (addr32_data->ResourceType == ACPI_IO_RANGE)
{
RequirementDescriptor->Type = CmResourceTypePort;
RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO;
if (addr32_data->Decode == ACPI_POS_DECODE)
RequirementDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE;
RequirementDescriptor->u.Port.MinimumAddress.QuadPart = addr32_data->Address.Minimum;
RequirementDescriptor->u.Port.MaximumAddress.QuadPart = addr32_data->Address.Maximum + addr32_data->Address.AddressLength - 1;
RequirementDescriptor->u.Port.Length = addr32_data->Address.AddressLength;
}
else
{
RequirementDescriptor->Type = CmResourceTypeMemory;
RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
RequirementDescriptor->Flags = 0;
if (addr32_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY)
RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
else
RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
switch (addr32_data->Info.Mem.Caching)
{
case ACPI_CACHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break;
case ACPI_WRITE_COMBINING_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break;
case ACPI_PREFETCHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break;
}
RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = addr32_data->Address.Minimum;
RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = addr32_data->Address.Maximum + addr32_data->Address.AddressLength - 1;
RequirementDescriptor->u.Memory.Length = addr32_data->Address.AddressLength;
}
RequirementDescriptor++;
break;
}
case ACPI_RESOURCE_TYPE_ADDRESS64:
{
ACPI_RESOURCE_ADDRESS64 *addr64_data = &resource->Data.Address64;
if (addr64_data->ProducerConsumer == ACPI_PRODUCER)
break;
RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED;
if (addr64_data->ResourceType == ACPI_BUS_NUMBER_RANGE)
{
DPRINT1("64-bit bus address is not supported!\n");
RequirementDescriptor->Type = CmResourceTypeBusNumber;
RequirementDescriptor->ShareDisposition = CmResourceShareShared;
RequirementDescriptor->Flags = 0;
RequirementDescriptor->u.BusNumber.MinBusNumber = (ULONG)addr64_data->Address.Minimum;
RequirementDescriptor->u.BusNumber.MaxBusNumber = (ULONG)addr64_data->Address.Maximum + addr64_data->Address.AddressLength - 1;
RequirementDescriptor->u.BusNumber.Length = addr64_data->Address.AddressLength;
}
else if (addr64_data->ResourceType == ACPI_IO_RANGE)
{
RequirementDescriptor->Type = CmResourceTypePort;
RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO;
if (addr64_data->Decode == ACPI_POS_DECODE)
RequirementDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE;
RequirementDescriptor->u.Port.MinimumAddress.QuadPart = addr64_data->Address.Minimum;
RequirementDescriptor->u.Port.MaximumAddress.QuadPart = addr64_data->Address.Maximum + addr64_data->Address.AddressLength - 1;
RequirementDescriptor->u.Port.Length = addr64_data->Address.AddressLength;
}
else
{
RequirementDescriptor->Type = CmResourceTypeMemory;
RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
RequirementDescriptor->Flags = 0;
if (addr64_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY)
RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
else
RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
switch (addr64_data->Info.Mem.Caching)
{
case ACPI_CACHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break;
case ACPI_WRITE_COMBINING_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break;
case ACPI_PREFETCHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break;
}
RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = addr64_data->Address.Minimum;
RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = addr64_data->Address.Maximum + addr64_data->Address.AddressLength - 1;
RequirementDescriptor->u.Memory.Length = addr64_data->Address.AddressLength;
}
RequirementDescriptor++;
break;
}
case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
{
ACPI_RESOURCE_EXTENDED_ADDRESS64 *addr64_data = &resource->Data.ExtAddress64;
if (addr64_data->ProducerConsumer == ACPI_PRODUCER)
break;
RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED;
if (addr64_data->ResourceType == ACPI_BUS_NUMBER_RANGE)
{
DPRINT1("64-bit bus address is not supported!\n");
RequirementDescriptor->Type = CmResourceTypeBusNumber;
RequirementDescriptor->ShareDisposition = CmResourceShareShared;
RequirementDescriptor->Flags = 0;
RequirementDescriptor->u.BusNumber.MinBusNumber = (ULONG)addr64_data->Address.Minimum;
RequirementDescriptor->u.BusNumber.MaxBusNumber = (ULONG)addr64_data->Address.Maximum + addr64_data->Address.AddressLength - 1;
RequirementDescriptor->u.BusNumber.Length = addr64_data->Address.AddressLength;
}
else if (addr64_data->ResourceType == ACPI_IO_RANGE)
{
RequirementDescriptor->Type = CmResourceTypePort;
RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
RequirementDescriptor->Flags = CM_RESOURCE_PORT_IO;
if (addr64_data->Decode == ACPI_POS_DECODE)
RequirementDescriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE;
RequirementDescriptor->u.Port.MinimumAddress.QuadPart = addr64_data->Address.Minimum;
RequirementDescriptor->u.Port.MaximumAddress.QuadPart = addr64_data->Address.Maximum + addr64_data->Address.AddressLength - 1;
RequirementDescriptor->u.Port.Length = addr64_data->Address.AddressLength;
}
else
{
RequirementDescriptor->Type = CmResourceTypeMemory;
RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
RequirementDescriptor->Flags = 0;
if (addr64_data->Info.Mem.WriteProtect == ACPI_READ_ONLY_MEMORY)
RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
else
RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
switch (addr64_data->Info.Mem.Caching)
{
case ACPI_CACHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE; break;
case ACPI_WRITE_COMBINING_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE; break;
case ACPI_PREFETCHABLE_MEMORY: RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; break;
}
RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = addr64_data->Address.Minimum;
RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = addr64_data->Address.Maximum + addr64_data->Address.AddressLength - 1;
RequirementDescriptor->u.Memory.Length = addr64_data->Address.AddressLength;
}
RequirementDescriptor++;
break;
}
case ACPI_RESOURCE_TYPE_MEMORY24:
{
ACPI_RESOURCE_MEMORY24 *mem24_data = &resource->Data.Memory24;
RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED;
RequirementDescriptor->Type = CmResourceTypeMemory;
RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
RequirementDescriptor->Flags = CM_RESOURCE_MEMORY_24;
if (mem24_data->WriteProtect == ACPI_READ_ONLY_MEMORY)
RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
else
RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = mem24_data->Minimum;
RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = mem24_data->Maximum + mem24_data->AddressLength - 1;
RequirementDescriptor->u.Memory.Length = mem24_data->AddressLength;
RequirementDescriptor++;
break;
}
case ACPI_RESOURCE_TYPE_MEMORY32:
{
ACPI_RESOURCE_MEMORY32 *mem32_data = &resource->Data.Memory32;
RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED;
RequirementDescriptor->Type = CmResourceTypeMemory;
RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
RequirementDescriptor->Flags = 0;
if (mem32_data->WriteProtect == ACPI_READ_ONLY_MEMORY)
RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
else
RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = mem32_data->Minimum;
RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = mem32_data->Maximum + mem32_data->AddressLength - 1;
RequirementDescriptor->u.Memory.Length = mem32_data->AddressLength;
RequirementDescriptor++;
break;
}
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
{
ACPI_RESOURCE_FIXED_MEMORY32 *fixedmem32_data = &resource->Data.FixedMemory32;
RequirementDescriptor->Option = CurrentRes ? 0 : IO_RESOURCE_PREFERRED;
RequirementDescriptor->Type = CmResourceTypeMemory;
RequirementDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
RequirementDescriptor->Flags = 0;
if (fixedmem32_data->WriteProtect == ACPI_READ_ONLY_MEMORY)
RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
else
RequirementDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
RequirementDescriptor->u.Memory.MinimumAddress.QuadPart = fixedmem32_data->Address;
RequirementDescriptor->u.Memory.MaximumAddress.QuadPart = fixedmem32_data->Address + fixedmem32_data->AddressLength - 1;
RequirementDescriptor->u.Memory.Length = fixedmem32_data->AddressLength;
RequirementDescriptor++;
break;
}
default:
{
break;
}
}
resource = ACPI_NEXT_RESOURCE(resource);
}
ExFreePoolWithTag(Buffer.Pointer, 'BpcA');
Irp->IoStatus.Information = (ULONG_PTR)RequirementsList;
return STATUS_SUCCESS;
}
#ifndef UNIT_TEST
NTSTATUS
Bus_PDO_QueryDeviceRelations(
PPDO_DEVICE_DATA DeviceData,
PIRP Irp )
/*++
Routine Description:
The PnP Manager sends this IRP to gather information about
devices with a relationship to the specified device.
Bus drivers must handle this request for TargetDeviceRelation
for their child devices (child PDOs).
If a driver returns relations in response to this IRP,
it allocates a DEVICE_RELATIONS structure from paged
memory containing a count and the appropriate number of
device object pointers. The PnP Manager frees the structure
when it is no longer needed. If a driver replaces a
DEVICE_RELATIONS structure allocated by another driver,
it must free the previous structure.
A driver must reference the PDO of any device that it
reports in this IRP (ObReferenceObject). The PnP Manager
removes the reference when appropriate.
Arguments:
DeviceData - Pointer to the PDO's device extension.
Irp - Pointer to the irp.
Return Value:
NT STATUS
--*/
{
PIO_STACK_LOCATION stack;
PDEVICE_RELATIONS deviceRelations;
NTSTATUS status;
PAGED_CODE ();
stack = IoGetCurrentIrpStackLocation (Irp);
switch (stack->Parameters.QueryDeviceRelations.Type) {
case TargetDeviceRelation:
deviceRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information;
if (deviceRelations) {
//
// Only PDO can handle this request. Somebody above
// is not playing by rule.
//
ASSERTMSG("Someone above is handling TargetDeviceRelation\n", !deviceRelations);
}
deviceRelations = ExAllocatePoolWithTag(PagedPool,
sizeof(DEVICE_RELATIONS),
'IpcA');
if (!deviceRelations) {
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
//
// There is only one PDO pointer in the structure
// for this relation type. The PnP Manager removes
// the reference to the PDO when the driver or application
// un-registers for notification on the device.
//
deviceRelations->Count = 1;
deviceRelations->Objects[0] = DeviceData->Common.Self;
ObReferenceObject(DeviceData->Common.Self);
status = STATUS_SUCCESS;
Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
break;
case BusRelations: // Not handled by PDO
case EjectionRelations: // optional for PDO
case RemovalRelations: // // optional for PDO
default:
status = Irp->IoStatus.Status;
}
return status;
}
NTSTATUS
Bus_PDO_QueryBusInformation(
PPDO_DEVICE_DATA DeviceData,
PIRP Irp )
/*++
Routine Description:
The PnP Manager uses this IRP to request the type and
instance number of a device's parent bus. Bus drivers
should handle this request for their child devices (PDOs).
Arguments:
DeviceData - Pointer to the PDO's device extension.
Irp - Pointer to the irp.
Return Value:
NT STATUS
--*/
{
PPNP_BUS_INFORMATION busInfo;
PAGED_CODE ();
busInfo = ExAllocatePoolWithTag(PagedPool,
sizeof(PNP_BUS_INFORMATION),
'IpcA');
if (busInfo == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
busInfo->BusTypeGuid = GUID_ACPI_INTERFACE_STANDARD;
busInfo->LegacyBusType = InternalPowerBus;
busInfo->BusNumber = 0; //fixme
Irp->IoStatus.Information = (ULONG_PTR)busInfo;
return STATUS_SUCCESS;
}
NTSTATUS
Bus_GetDeviceCapabilities(
PDEVICE_OBJECT DeviceObject,
PDEVICE_CAPABILITIES DeviceCapabilities
)
{
IO_STATUS_BLOCK ioStatus;
KEVENT pnpEvent;
NTSTATUS status;
PDEVICE_OBJECT targetObject;
PIO_STACK_LOCATION irpStack;
PIRP pnpIrp;
PAGED_CODE();
//
// Initialize the capabilities that we will send down
//
RtlZeroMemory( DeviceCapabilities, sizeof(DEVICE_CAPABILITIES) );
DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);
DeviceCapabilities->Version = 1;
DeviceCapabilities->Address = -1;
DeviceCapabilities->UINumber = -1;
//
// Initialize the event
//
KeInitializeEvent( &pnpEvent, NotificationEvent, FALSE );
targetObject = IoGetAttachedDeviceReference( DeviceObject );
//
// Build an Irp
//
pnpIrp = IoBuildSynchronousFsdRequest(
IRP_MJ_PNP,
targetObject,
NULL,
0,
NULL,
&pnpEvent,
&ioStatus
);
if (pnpIrp == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto GetDeviceCapabilitiesExit;
}
//
// Pnp Irps all begin life as STATUS_NOT_SUPPORTED;
//
pnpIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
//
// Get the top of stack
//
irpStack = IoGetNextIrpStackLocation( pnpIrp );
//
// Set the top of stack
//
RtlZeroMemory( irpStack, sizeof(IO_STACK_LOCATION ) );
irpStack->MajorFunction = IRP_MJ_PNP;
irpStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
irpStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
//
// Call the driver
//
status = IoCallDriver( targetObject, pnpIrp );
if (status == STATUS_PENDING) {
//
// Block until the irp comes back.
// Important thing to note here is when you allocate
// the memory for an event in the stack you must do a
// KernelMode wait instead of UserMode to prevent
// the stack from getting paged out.
//
KeWaitForSingleObject(
&pnpEvent,
Executive,
KernelMode,
FALSE,
NULL
);
status = ioStatus.Status;
}
GetDeviceCapabilitiesExit:
//
// Done with reference
//
ObDereferenceObject( targetObject );
//
// Done
//
return status;
}
#endif /* UNIT_TEST */