/*++ Copyright (c) 2002 Microsoft Corporation Module Name: pdopnp.c Abstract: This module contains the code to handle the IRP_MJ_PNP dispatches for the PDOs enumerated by the SD bus driver Authors: Neil Sandlin (neilsa) 1-Jan-2002 Environment: Kernel mode only Notes: Revision History: --*/ #include "pch.h" // // Internal References // NTSTATUS SdbusPdoDeviceCapabilities( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ); NTSTATUS SdbusPdoStartDevice( IN PDEVICE_OBJECT Pdo, IN PCM_RESOURCE_LIST AllocatedResources, IN OUT PIRP Irp ); NTSTATUS SdbusPdoStopDevice( IN PDEVICE_OBJECT Pdo ); NTSTATUS SdbusPdoRemoveDevice( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ); NTSTATUS SdbusPdoQueryId( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ); NTSTATUS SdbusPdoGetBusInformation( IN PPDO_EXTENSION PdoExtension, OUT PPNP_BUS_INFORMATION * BusInformation ); NTSTATUS SdbusQueryDeviceText( IN PDEVICE_OBJECT Pdo, IN OUT PIRP Irp ); VOID SdbusPdoGetDeviceInfSettings( IN PPDO_EXTENSION PdoExtension ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, SdbusPdoPnpDispatch) #pragma alloc_text(PAGE, SdbusPdoGetDeviceInfSettings) #pragma alloc_text(PAGE, SdbusQueryDeviceText) #pragma alloc_text(PAGE, SdbusPdoGetBusInformation) #pragma alloc_text(PAGE, SdbusPdoStartDevice) #pragma alloc_text(PAGE, SdbusPdoStopDevice) #pragma alloc_text(PAGE, SdbusPdoRemoveDevice) #pragma alloc_text(PAGE, SdbusPdoDeviceCapabilities) #pragma alloc_text(PAGE, SdbusPdoGetDeviceInfSettings) #endif NTSTATUS SdbusPdoPnpDispatch( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ) /*++ Routine Description: This routine handles pnp requests for the PDOs. Arguments: Pdo - pointer to the physical device object Irp - pointer to the io request packet Return Value: status --*/ { PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status; PAGED_CODE(); #if DBG if (irpStack->MinorFunction > IRP_MN_PNP_MAXIMUM_FUNCTION) { DebugPrint((SDBUS_DEBUG_PNP, "pdo %08x irp %08x Unknown minor function %x\n", Pdo, Irp, irpStack->MinorFunction)); } else { DebugPrint((SDBUS_DEBUG_PNP, "pdo %08x irp %08x --> %s\n", Pdo, Irp, PNP_IRP_STRING(irpStack->MinorFunction))); } #endif switch (irpStack->MinorFunction) { case IRP_MN_START_DEVICE: status = SdbusPdoStartDevice(Pdo, irpStack->Parameters.StartDevice.AllocatedResources, Irp); break; case IRP_MN_QUERY_STOP_DEVICE: status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_STOP_DEVICE: status = STATUS_SUCCESS; break; case IRP_MN_STOP_DEVICE: status = SdbusPdoStopDevice(Pdo); break; case IRP_MN_QUERY_REMOVE_DEVICE: status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_REMOVE_DEVICE: status = STATUS_SUCCESS; break; case IRP_MN_REMOVE_DEVICE: status = SdbusPdoRemoveDevice(Pdo, Irp); break; case IRP_MN_SURPRISE_REMOVAL: // SdbusReleaseSocketPower(pdoExtension, NULL); status = STATUS_SUCCESS; break; case IRP_MN_QUERY_ID: status = SdbusPdoQueryId(Pdo, Irp); break; case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: status = STATUS_SUCCESS; break; case IRP_MN_QUERY_RESOURCES: status = STATUS_SUCCESS; break; case IRP_MN_QUERY_DEVICE_RELATIONS: { PDEVICE_RELATIONS deviceRelations; if (irpStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) { status = Irp->IoStatus.Status; break; } deviceRelations = ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS)); if (deviceRelations == NULL) { DebugPrint((SDBUS_DEBUG_FAIL, "SdbusPdoPnpDispatch:unable to allocate memory for device relations\n")); status = STATUS_INSUFFICIENT_RESOURCES; break; } status = ObReferenceObjectByPointer(Pdo, 0, NULL, KernelMode); if (!NT_SUCCESS(status)) { ExFreePool(deviceRelations); break; } deviceRelations->Count = 1; deviceRelations->Objects[0] = Pdo; Irp->IoStatus.Information = (ULONG_PTR) deviceRelations; status = STATUS_SUCCESS; break; } case IRP_MN_QUERY_CAPABILITIES: status = SdbusPdoDeviceCapabilities(Pdo, Irp); break; case IRP_MN_QUERY_DEVICE_TEXT: status = SdbusQueryDeviceText(Pdo, Irp); if (status == STATUS_NOT_SUPPORTED ) { // // Do not change IRP status if this IRP is // not handled // status = Irp->IoStatus.Status; } break; case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: status = STATUS_SUCCESS; break; case IRP_MN_QUERY_BUS_INFORMATION: status = SdbusPdoGetBusInformation(pdoExtension, (PPNP_BUS_INFORMATION *) &Irp->IoStatus.Information); break; default: // // Retain the status // DebugPrint((SDBUS_DEBUG_PNP, "pdo %08x irp %08x Skipping unsupported irp\n", Pdo, Irp)); status = Irp->IoStatus.Status; break; } Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); DebugPrint((SDBUS_DEBUG_PNP, "pdo %08x irp %08x comp %s %08x\n", Pdo, Irp, STATUS_STRING(status), status)); return status; } NTSTATUS SdbusPdoGetBusInformation( IN PPDO_EXTENSION PdoExtension, OUT PPNP_BUS_INFORMATION * BusInformation ) /*++ Routine Description: Returns the bus type information for the pc-card. Bus type is GUID_BUS_TYPE_SDBUS(legacy type is SdbusBus) for R2 cards Bus numbers are not implemented for SDBUS, so it's always 0 Arguments: PdoExtension - pointer to device extension for the pc-card BusInformation - pointer to the bus information structure that needs to be filled in Return value: Status --*/ { PAGED_CODE(); *BusInformation = ExAllocatePool(PagedPool, sizeof (PNP_BUS_INFORMATION)); if (!*BusInformation) { return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory(&((*BusInformation)->BusTypeGuid), &GUID_BUS_TYPE_SD, sizeof(GUID)); (*BusInformation)->LegacyBusType = InterfaceTypeUndefined; (*BusInformation)->BusNumber = 0; return STATUS_SUCCESS; } VOID SdbusPdoGetDeviceInfSettings( IN PPDO_EXTENSION PdoExtension ) /*++ Routine Description: This routine retrieves settings from the INF for this device. Arguments: DeviceExtension - Device extension of the Pc-Card Return value: None --*/ { NTSTATUS status; UNICODE_STRING KeyName; HANDLE instanceHandle; UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)]; PKEY_VALUE_PARTIAL_INFORMATION value = (PKEY_VALUE_PARTIAL_INFORMATION) buffer; ULONG length; PAGED_CODE(); status = IoOpenDeviceRegistryKey(PdoExtension->DeviceObject, PLUGPLAY_REGKEY_DRIVER, KEY_READ, &instanceHandle ); if (NT_SUCCESS(status)) { #if 0 // // Look to see if SdbusExclusiveIrq is specified // RtlInitUnicodeString(&KeyName, L"SdbusExclusiveIrq"); status = ZwQueryValueKey(instanceHandle, &KeyName, KeyValuePartialInformation, value, sizeof(buffer), &length); // // If the key doesn't exist, or zero was specified, it means that // routing is ok // if (NT_SUCCESS(status) && (*(PULONG)(value->Data) != 0)) { SetDeviceFlag(PdoExtension, SDBUS_PDO_EXCLUSIVE_IRQ); } #endif ZwClose(instanceHandle); } } NTSTATUS SdbusQueryDeviceText( IN PDEVICE_OBJECT Pdo, IN OUT PIRP Irp ) /*++ Routine Description: Returns descriptive text information about the PDO (location and device desc.) Arguments: Pdo - Pointer to the PC-Card's device object Irp - IRP_MN_QUERY_DEVICE_TEXT Irp Return Value: STATUS_SUCCESS STATUS_NOT_SUPPORTED - if not supported --*/ { PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension; UNICODE_STRING unicodeString; ANSI_STRING ansiString; UCHAR deviceText[128]; NTSTATUS status; USHORT deviceTextLength; PAGED_CODE(); if (irpStack->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription) { if (pdoExtension->FunctionType == SDBUS_FUNCTION_TYPE_IO) { PUCHAR mfg, prod; if (pdoExtension->FdoExtension->CardData->MfgText[0]) { mfg = pdoExtension->FdoExtension->CardData->MfgText; } else { mfg = "Generic"; } if (pdoExtension->FdoExtension->CardData->ProductText[0]) { prod = pdoExtension->FdoExtension->CardData->ProductText; } else { prod = "SD IO Device"; } sprintf(deviceText, "%s %s", mfg, prod); } else { sprintf(deviceText, "%s", "Secure Digital Storage Device"); } RtlInitAnsiString(&ansiString, deviceText); deviceTextLength = (strlen(deviceText) + 1)*sizeof(WCHAR); unicodeString.Buffer = ExAllocatePool(PagedPool, deviceTextLength); if (unicodeString.Buffer == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } unicodeString.MaximumLength = deviceTextLength; unicodeString.Length = 0; status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE); if (!NT_SUCCESS(status)) { ExFreePool(unicodeString.Buffer); return status; } unicodeString.Buffer[unicodeString.Length/sizeof(WCHAR)] = L'\0'; Irp->IoStatus.Information = (ULONG_PTR) unicodeString.Buffer; status = STATUS_SUCCESS; } else { status = STATUS_NOT_SUPPORTED ; } return status; } NTSTATUS SdbusGenerateDeviceId( IN PPDO_EXTENSION PdoExtension, OUT PUCHAR *DeviceId ) /*++ This routines generates the device id for the given SD device. Arguments: Pdo - Pointer to the physical device object for the SD device DeviceId - Pointer to the string in which device id is returned Return Value Status --*/ { PUCHAR deviceId; PAGED_CODE(); deviceId = ExAllocatePool(PagedPool, SDBUS_MAXIMUM_DEVICE_ID_LENGTH); if (deviceId == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } if (PdoExtension->FunctionType == SDBUS_FUNCTION_TYPE_IO) { PSD_CARD_DATA cardData = PdoExtension->FdoExtension->CardData; // // IO card // sprintf(deviceId, "%s\\VID_%04x&PID_%04x", "SD", cardData->MfgId, cardData->MfgInfo); } else { UCHAR productName[6]; UCHAR j; PSD_CARD_DATA cardData = PdoExtension->FdoExtension->CardData; // // Memory card // sprintf(deviceId, "%s\\VID_%02x&OID_%04x&PID_%s&REV_%d.%d", "SD", cardData->SdCid.ManufacturerId, cardData->SdCid.OemId, cardData->ProductName, (cardData->SdCid.Revision >> 4) , (cardData->SdCid.Revision & 0xF)); } *DeviceId = deviceId; return STATUS_SUCCESS; } NTSTATUS SdbusGetHardwareIds( IN PPDO_EXTENSION PdoExtension, OUT PUNICODE_STRING HardwareIds ) /*++ Routine Description: This routine generates the hardware id's for the given sd device and returns them as a Unicode multi-string. Arguments: Pdo - Pointer to device object representing the sd device HardwareIds - Pointer to the unicode string which contains the hardware id's as a multi-string Return value: --*/ { NTSTATUS status; PSTR strings[4] = {NULL}; PUCHAR hwId; UCHAR stringCount = 0; PAGED_CODE(); // // The first hardware id is identical to the device id // Generate the device id // status = SdbusGenerateDeviceId(PdoExtension, &strings[stringCount++]); if (!NT_SUCCESS(status)) { return status; } try { // // Add less specific IDs // if (PdoExtension->FunctionType == SDBUS_FUNCTION_TYPE_MEMORY) { UCHAR productName[6]; UCHAR j; PSD_CARD_DATA cardData = PdoExtension->FdoExtension->CardData; status = STATUS_INSUFFICIENT_RESOURCES; hwId = ExAllocatePool(PagedPool, SDBUS_MAXIMUM_DEVICE_ID_LENGTH); if (!hwId) { leave; } strings[stringCount++] = hwId; // // Memory card // sprintf(hwId, "%s\\VID_%02x&OID_%04x&PID_%s", "SD", cardData->SdCid.ManufacturerId, cardData->SdCid.OemId, cardData->ProductName); } status = SdbusStringsToMultiString(strings, stringCount, HardwareIds); } finally { while(stringCount != 0) { ExFreePool(strings[--stringCount]); } } return status; } NTSTATUS SdbusGetCompatibleIds( IN PPDO_EXTENSION PdoExtension, OUT PUNICODE_STRING CompatibleIds ) /*++ Routine Description: This routine generates the compatible id's for the given sd device and returns them as a Unicode multi-string. Arguments: Pdo - Pointer to device object representing the sd device HardwareIds - Pointer to the unicode string which contains the hardware id's as a multi-string Return value: --*/ { NTSTATUS status; PSTR strings[1] = {NULL}; PUCHAR compatId; UCHAR stringCount = 0; PAGED_CODE(); try { // // Add the class ID // status = STATUS_INSUFFICIENT_RESOURCES; compatId = ExAllocatePool(PagedPool, SDBUS_MAXIMUM_DEVICE_ID_LENGTH); if (!compatId) { leave; } strings[stringCount++] = compatId; if (PdoExtension->FunctionType == SDBUS_FUNCTION_TYPE_MEMORY) { sprintf(compatId, "%s\\CLASS_STORAGE", "SD"); } else { PSD_CARD_DATA cardData = PdoExtension->FdoExtension->CardData; PSD_FUNCTION_DATA functionData; // find the right function data for (functionData = cardData->FunctionData; functionData != NULL; functionData = functionData->Next) { if (functionData->Function == PdoExtension->Function) break; } if (!functionData || (functionData->IoDeviceInterface == 0)) { ASSERT(functionData != NULL); status = STATUS_UNSUCCESSFUL; leave; } sprintf(compatId, "%s\\CLASS_%02x", "SD", functionData->IoDeviceInterface); DebugPrint((SDBUS_DEBUG_INFO, " %s\n", compatId)); } status = SdbusStringsToMultiString(strings, stringCount, CompatibleIds); } finally { ASSERT(stringCount <= 1); while(stringCount != 0) { ExFreePool(strings[--stringCount]); } } return status; } NTSTATUS SdbusGetInstanceId( IN PPDO_EXTENSION PdoExtension, 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 --*/ { ULONG instance; NTSTATUS status; ANSI_STRING sizeString; ASSERT(InstanceId); // // 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; } status = RtlIntegerToUnicodeString(999, 10, InstanceId); if (!NT_SUCCESS(status)) { RtlFreeUnicodeString(InstanceId); } return status; } NTSTATUS SdbusPdoQueryId( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ) /*++ Routine Description: Returns descriptive text information about the PDO (location and device desc.) Arguments: Pdo - Pointer to the SD-Card's device object Irp - IRP_MN_QUERY_DEVICE_TEXT Irp Return Value: STATUS_SUCCESS STATUS_NOT_SUPPORTED - if not supported --*/ { PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension; UNICODE_STRING unicodeString; ANSI_STRING ansiString; UCHAR deviceText[128]; NTSTATUS status; USHORT deviceTextLength; UNICODE_STRING unicodeId; PUCHAR deviceId; PAGED_CODE(); status = Irp->IoStatus.Status; RtlInitUnicodeString(&unicodeId, NULL); switch (irpStack->Parameters.QueryId.IdType) { case BusQueryDeviceID: DebugPrint((SDBUS_DEBUG_INFO, " Device Id for pdo %x\n", Pdo)); status = SdbusGenerateDeviceId(pdoExtension, &deviceId); if (!NT_SUCCESS(status)) { break; } DebugPrint((SDBUS_DEBUG_INFO, "pdo %08x Device Id=%s\n", Pdo, deviceId)); RtlInitAnsiString(&ansiString, deviceId); status = RtlAnsiStringToUnicodeString(&unicodeId, &ansiString, TRUE); ExFreePool(deviceId); if (NT_SUCCESS(status)) { Irp->IoStatus.Information = (ULONG_PTR) unicodeId.Buffer; } break; case BusQueryInstanceID: DebugPrint((SDBUS_DEBUG_INFO, " Instance Id for pdo %x\n", Pdo)); status = SdbusGetInstanceId(pdoExtension, &unicodeId); if (NT_SUCCESS(status)) { Irp->IoStatus.Information = (ULONG_PTR) unicodeId.Buffer; } break; case BusQueryHardwareIDs: DebugPrint((SDBUS_DEBUG_INFO, " Hardware Ids for pdo %x\n", Pdo)); status = SdbusGetHardwareIds(pdoExtension, &unicodeId); if (NT_SUCCESS(status)) { Irp->IoStatus.Information = (ULONG_PTR) unicodeId.Buffer; } break; case BusQueryCompatibleIDs: DebugPrint((SDBUS_DEBUG_INFO, " Compatible Ids for pdo %x\n", Pdo)); status = SdbusGetCompatibleIds(pdoExtension, &unicodeId); if (NT_SUCCESS(status)) { Irp->IoStatus.Information = (ULONG_PTR) unicodeId.Buffer; } break; } return status; } NTSTATUS SdbusPdoStartDevice( IN PDEVICE_OBJECT Pdo, IN PCM_RESOURCE_LIST ResourceList, IN OUT PIRP Irp ) /*++ Routine Description: This routine attempts to start the PC-Card by configuring it with the supplied resources. Arguments: Pdo - Pointer to the device object representing the PC-Card which needs to be started ResourceList - Pointer the list of assigned resources for the PC-Card Return value: STATUS_INSUFFICIENT_RESOURCES - Not sufficient resources supplied to start device/ could not allocate memory STATUS_UNSUCCESSFUL - Supplied resources are invalid for this PC-Card STATUS_SUCCESS - Configured and started the card successfully --*/ { PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension; PFDO_EXTENSION fdoExtension = pdoExtension->FdoExtension; NTSTATUS status; PAGED_CODE(); if (IsDeviceStarted(pdoExtension)) { // // Already started.. // return STATUS_SUCCESS; } if (IsDevicePhysicallyRemoved(pdoExtension)) { return STATUS_DEVICE_DOES_NOT_EXIST; } status = SdbusExecuteWorkSynchronous(SDWP_INITIALIZE_FUNCTION, fdoExtension, pdoExtension); if (NT_SUCCESS(status)) { MarkDeviceStarted(pdoExtension); MarkDeviceLogicallyInserted(pdoExtension); } return status; } NTSTATUS SdbusPdoStopDevice( IN PDEVICE_OBJECT Pdo ) /*++ Routine Description: This routine stops and deconfigures the given PC-Card Arguments: Pdo - Pointer to the device object representing the PC-Card which needs to be stopped Return value: STATUS_SUCCESS - PC-Card was already stopped, or stopped and deconfigured now successfully --*/ { PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension; PAGED_CODE(); if (!IsDeviceStarted(pdoExtension)) { return STATUS_SUCCESS; } // // Need to deconfigure the controller // MarkDeviceNotStarted(pdoExtension); return STATUS_SUCCESS; } NTSTATUS SdbusPdoRemoveDevice( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ) /*++ Routine Description: Arguments: Return value: --*/ { PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension; NTSTATUS status; PAGED_CODE(); SdbusPdoStopDevice(Pdo); // SdbusReleaseSocketPower(pdoExtension, NULL); if (IsDevicePhysicallyRemoved(pdoExtension)) { PFDO_EXTENSION fdoExtension = pdoExtension->FdoExtension; PDEVICE_OBJECT curPdo, prevPdo; PPDO_EXTENSION curPdoExt; ULONG waitCount = 0; #if 0 // // Synchronize with power routines // LATER: make these values adjustable // while(!SDBUS_TEST_AND_SET(&pdoExtension->DeletionLock)) { SdbusWait(1000000); if (waitCount++ > 20) { ASSERT(waitCount <= 20); break; } } #endif // // Delink this Pdo from the FDO list. // for (curPdo = fdoExtension->PdoList, prevPdo = NULL; curPdo!=NULL; prevPdo = curPdo, curPdo=curPdoExt->NextPdoInFdoChain) { curPdoExt = curPdo->DeviceExtension; if (curPdo == Pdo) { if (prevPdo) { ((PPDO_EXTENSION)prevPdo->DeviceExtension)->NextPdoInFdoChain = pdoExtension->NextPdoInFdoChain; } else { fdoExtension->PdoList = pdoExtension->NextPdoInFdoChain; } break; } } SdbusCleanupPdo(Pdo); // // Delete.. // if (!IsDeviceDeleted(pdoExtension)) { MarkDeviceDeleted(pdoExtension); IoDeleteDevice(Pdo); } } else { // // We will keep this Pdo around, since this is not physically ejected. // MarkDeviceLogicallyRemoved(pdoExtension); } return STATUS_SUCCESS; } VOID SdbusCleanupPdo( IN PDEVICE_OBJECT Pdo ) /*++ Routine Description: Arguments: Return value: --*/ { PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension; // currently nothing to do } NTSTATUS SdbusPdoDeviceCapabilities( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ) /*++ Routine Description: Obtains the device capabilities of the given SD device. Arguments: Pdo - Pointer to the device object for the pc-card Irp - Pointer to the query device capabilities Irp Return Value: STATUS_SUCCESS - Capabilities obtained and recorded in the passed in pointer STATUS_INSUFFICIENT_RESOURCES - Could not allocate memory to cache the capabilities --*/ { PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); PDEVICE_CAPABILITIES capabilities = irpStack->Parameters.DeviceCapabilities.Capabilities; PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension; PDEVICE_CAPABILITIES busCapabilities = &pdoExtension->FdoExtension->DeviceCapabilities; PAGED_CODE(); // // R2 card. Fill in the capabilities ourselves.. // capabilities->Removable = TRUE; capabilities->UniqueID = FALSE; capabilities->EjectSupported = FALSE; // capabilities->Address = pdoExtension->Socket->RegisterOffset; capabilities->Address = 0; // Don't know the UINumber, just leave it alone if (busCapabilities->DeviceState[PowerSystemWorking] != PowerDeviceUnspecified) { capabilities->DeviceState[PowerSystemWorking] = busCapabilities->DeviceState[PowerSystemWorking]; capabilities->DeviceState[PowerSystemSleeping1] = busCapabilities->DeviceState[PowerSystemSleeping1]; capabilities->DeviceState[PowerSystemSleeping2] = busCapabilities->DeviceState[PowerSystemSleeping2]; capabilities->DeviceState[PowerSystemSleeping3] = busCapabilities->DeviceState[PowerSystemSleeping3]; capabilities->DeviceState[PowerSystemHibernate] = busCapabilities->DeviceState[PowerSystemHibernate]; capabilities->DeviceState[PowerSystemShutdown] = busCapabilities->DeviceState[PowerSystemShutdown]; capabilities->SystemWake = MIN(PowerSystemSleeping3, busCapabilities->SystemWake); capabilities->DeviceWake = PowerDeviceD0; // don't rely on FDO mungeing in the right thing for r2 cards capabilities->D1Latency = busCapabilities->D1Latency; capabilities->D2Latency = busCapabilities->D2Latency; capabilities->D3Latency = busCapabilities->D3Latency; } else { capabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0; capabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD3; capabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD3; capabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3; capabilities->DeviceState[PowerSystemHibernate] = PowerDeviceD3; capabilities->DeviceState[PowerSystemShutdown] = PowerDeviceD3; capabilities->SystemWake = PowerSystemUnspecified; capabilities->DeviceWake = PowerDeviceD0; // don't rely on FDO mungeing in the right thing for r2 cards capabilities->D1Latency = 0; // No latency - since we do nothing capabilities->D2Latency = 0; // capabilities->D3Latency = 100; } // // Store these capabilities away.. // RtlCopyMemory(&pdoExtension->DeviceCapabilities, capabilities, sizeof(DEVICE_CAPABILITIES)); return STATUS_SUCCESS; }