You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
568 lines
13 KiB
568 lines
13 KiB
/*++
|
|
|
|
Copyright (c) 2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
utils.c
|
|
|
|
Abstract:
|
|
|
|
This module contains utility functions for the sd bus driver
|
|
|
|
Author:
|
|
|
|
Neil Sandlin (neilsa) Jan 1 2002
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History :
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
|
|
//
|
|
// Internal References
|
|
//
|
|
|
|
NTSTATUS
|
|
SdbusAdapterIoCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PKEVENT pdoIoCompletedEvent
|
|
);
|
|
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, SdbusGetInterface)
|
|
#pragma alloc_text(PAGE, SdbusReportControllerError)
|
|
#pragma alloc_text(PAGE, SdbusStringsToMultiString)
|
|
#endif
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SdbusIoCallDriverSynchronous(
|
|
PDEVICE_OBJECT deviceObject,
|
|
PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Arguments
|
|
|
|
Return Value
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
KEVENT event;
|
|
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
IoSetCompletionRoutine(
|
|
Irp,
|
|
SdbusAdapterIoCompletion,
|
|
&event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
|
|
status = IoCallDriver(deviceObject, Irp);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|
status = Irp->IoStatus.Status;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SdbusAdapterIoCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PKEVENT pdoIoCompletedEvent
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Generic completion routine used by the driver
|
|
|
|
Arguments:
|
|
|
|
DeviceObject
|
|
Irp
|
|
pdoIoCompletedEvent - this event will be signalled before return of this routine
|
|
|
|
Return value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
KeSetEvent(pdoIoCompletedEvent, IO_NO_INCREMENT, FALSE);
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SdbusGetInterface(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN CONST GUID *pGuid,
|
|
IN USHORT sizeofInterface,
|
|
OUT PINTERFACE pInterface
|
|
)
|
|
/*
|
|
|
|
Routine Description
|
|
|
|
Gets the interface exported by a lower driver, typically the bus driver
|
|
|
|
Arguments
|
|
|
|
Pdo - Pointer to physical device object for the device stack
|
|
|
|
Return Value
|
|
|
|
Status
|
|
|
|
*/
|
|
|
|
{
|
|
KEVENT event;
|
|
PIRP irp;
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK statusBlock;
|
|
PIO_STACK_LOCATION irpSp;
|
|
|
|
PAGED_CODE();
|
|
|
|
KeInitializeEvent (&event, NotificationEvent, FALSE);
|
|
irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,
|
|
DeviceObject,
|
|
NULL,
|
|
0,
|
|
0,
|
|
&event,
|
|
&statusBlock
|
|
);
|
|
|
|
irp->IoStatus.Status = STATUS_NOT_SUPPORTED ;
|
|
irp->IoStatus.Information = 0;
|
|
|
|
irpSp = IoGetNextIrpStackLocation(irp);
|
|
|
|
irpSp->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
|
|
|
irpSp->Parameters.QueryInterface.InterfaceType= pGuid;
|
|
irpSp->Parameters.QueryInterface.Size = sizeofInterface;
|
|
irpSp->Parameters.QueryInterface.Version = 1;
|
|
irpSp->Parameters.QueryInterface.Interface = pInterface;
|
|
|
|
status = IoCallDriver(DeviceObject, irp);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|
status = statusBlock.Status;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
DebugPrint((SDBUS_DEBUG_INFO, "GetInterface failed with status %x\n", status));
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SdbusWait(
|
|
IN ULONG MicroSeconds
|
|
)
|
|
|
|
/*++
|
|
Routine Description
|
|
|
|
Waits for the specified interval before returning,
|
|
by yielding execution.
|
|
|
|
Arguments
|
|
|
|
MicroSeconds - Amount of time to delay in microseconds
|
|
|
|
Return Value
|
|
|
|
None. Must succeed.
|
|
|
|
--*/
|
|
{
|
|
LARGE_INTEGER dueTime;
|
|
NTSTATUS status;
|
|
|
|
|
|
if ((KeGetCurrentIrql() < DISPATCH_LEVEL) && (MicroSeconds > 50)) {
|
|
DebugPrint((SDBUS_DEBUG_INFO, "SdbusWait: wait %d\n", MicroSeconds));
|
|
//
|
|
// Convert delay to 100-nanosecond intervals
|
|
//
|
|
dueTime.QuadPart = -((LONG) MicroSeconds*10);
|
|
|
|
//
|
|
// We wait for an event that'll never be set.
|
|
//
|
|
status = KeWaitForSingleObject(&SdbusDelayTimerEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
&dueTime);
|
|
|
|
ASSERT(status == STATUS_TIMEOUT);
|
|
} else {
|
|
if (MicroSeconds > 50) {
|
|
DebugPrint((SDBUS_DEBUG_INFO, "SdbusWait: STALL %d\n", MicroSeconds));
|
|
}
|
|
KeStallExecutionProcessor(MicroSeconds);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ULONG
|
|
SdbusCountOnes(
|
|
IN ULONG Data
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Counts the number of 1's in the binary representation of the supplied argument
|
|
|
|
Arguments:
|
|
|
|
Data - supplied argument for which 1's need to be counted
|
|
|
|
Return value:
|
|
|
|
Number of 1's in binary rep. of Data
|
|
|
|
--*/
|
|
{
|
|
ULONG count=0;
|
|
while (Data) {
|
|
Data &= (Data-1);
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
|
|
VOID
|
|
SdbusLogError(
|
|
IN PFDO_EXTENSION DeviceExtension,
|
|
IN ULONG ErrorCode,
|
|
IN ULONG UniqueId,
|
|
IN ULONG Argument
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function logs an error.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - Supplies a pointer to the port device extension.
|
|
ErrorCode - Supplies the error code for this error.
|
|
UniqueId - Supplies the UniqueId for this error.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIO_ERROR_LOG_PACKET packet;
|
|
|
|
packet = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(DeviceExtension->DeviceObject,
|
|
sizeof(IO_ERROR_LOG_PACKET) + sizeof(ULONG));
|
|
|
|
if (packet) {
|
|
packet->ErrorCode = ErrorCode;
|
|
packet->SequenceNumber = DeviceExtension->SequenceNumber++;
|
|
packet->MajorFunctionCode = 0;
|
|
packet->RetryCount = (UCHAR) 0;
|
|
packet->UniqueErrorValue = UniqueId;
|
|
packet->FinalStatus = STATUS_SUCCESS;
|
|
packet->DumpDataSize = sizeof(ULONG);
|
|
packet->DumpData[0] = Argument;
|
|
|
|
IoWriteErrorLogEntry(packet);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SdbusLogErrorWithStrings(
|
|
IN PFDO_EXTENSION DeviceExtension,
|
|
IN ULONG ErrorCode,
|
|
IN ULONG UniqueId,
|
|
IN PUNICODE_STRING String1,
|
|
IN PUNICODE_STRING String2
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
This function logs an error and includes the strings provided.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - Supplies a pointer to the port device extension.
|
|
ErrorCode - Supplies the error code for this error.
|
|
UniqueId - Supplies the UniqueId for this error.
|
|
String1 - The first string to be inserted.
|
|
String2 - The second string to be inserted.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG length;
|
|
PCHAR dumpData;
|
|
PIO_ERROR_LOG_PACKET packet;
|
|
|
|
length = String1->Length + sizeof(IO_ERROR_LOG_PACKET) + 4;
|
|
|
|
if (String2) {
|
|
length += String2->Length;
|
|
}
|
|
|
|
if (length > ERROR_LOG_MAXIMUM_SIZE) {
|
|
|
|
//
|
|
// Don't have code to truncate strings so don't log this.
|
|
//
|
|
|
|
return;
|
|
}
|
|
|
|
packet = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(DeviceExtension->DeviceObject,
|
|
(UCHAR) length);
|
|
if (packet) {
|
|
packet->ErrorCode = ErrorCode;
|
|
packet->SequenceNumber = DeviceExtension->SequenceNumber++;
|
|
packet->MajorFunctionCode = 0;
|
|
packet->RetryCount = (UCHAR) 0;
|
|
packet->UniqueErrorValue = UniqueId;
|
|
packet->FinalStatus = STATUS_SUCCESS;
|
|
packet->NumberOfStrings = 1;
|
|
packet->StringOffset = (USHORT) ((PUCHAR)&packet->DumpData[0] - (PUCHAR)packet);
|
|
packet->DumpDataSize = (USHORT) (length - sizeof(IO_ERROR_LOG_PACKET));
|
|
packet->DumpDataSize /= sizeof(ULONG);
|
|
dumpData = (PUCHAR) &packet->DumpData[0];
|
|
|
|
RtlCopyMemory(dumpData, String1->Buffer, String1->Length);
|
|
|
|
dumpData += String1->Length;
|
|
if (String2) {
|
|
*dumpData++ = '\\';
|
|
*dumpData++ = '\0';
|
|
|
|
RtlCopyMemory(dumpData, String2->Buffer, String2->Length);
|
|
dumpData += String2->Length;
|
|
}
|
|
*dumpData++ = '\0';
|
|
*dumpData++ = '\0';
|
|
|
|
IoWriteErrorLogEntry(packet);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
SdbusReportControllerError(
|
|
IN PFDO_EXTENSION FdoExtension,
|
|
NTSTATUS ErrorCode
|
|
)
|
|
/*++
|
|
Routine Description
|
|
|
|
Causes a pop-up dialog to appear indicating an error that
|
|
we should tell the user about. The device description of the
|
|
controller is also included in the text of the pop-up.
|
|
|
|
Arguments
|
|
|
|
FdoExtension - Pointer to device extension for sd controller
|
|
ErrorCode - the ntstatus code for the error
|
|
|
|
Return Value
|
|
|
|
TRUE - If a an error was queued
|
|
FALSE - If it failed for some reason
|
|
|
|
--*/
|
|
{
|
|
UNICODE_STRING unicodeString;
|
|
PWSTR deviceDesc = NULL;
|
|
NTSTATUS status;
|
|
ULONG length = 0;
|
|
BOOLEAN retVal;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Obtain the device description for the SD controller
|
|
// that is used in the error pop-up. If one cannot be obtained,
|
|
// still pop-up the error dialog, indicating the controller as unknown
|
|
//
|
|
|
|
// First, find out the length of the buffer required to obtain
|
|
// device description for this SD controller
|
|
//
|
|
status = IoGetDeviceProperty(FdoExtension->Pdo,
|
|
DevicePropertyDeviceDescription,
|
|
0,
|
|
NULL,
|
|
&length
|
|
);
|
|
ASSERT(!NT_SUCCESS(status));
|
|
|
|
if (status == STATUS_BUFFER_TOO_SMALL) {
|
|
deviceDesc = ExAllocatePool(PagedPool, length);
|
|
if (deviceDesc != NULL) {
|
|
status = IoGetDeviceProperty(FdoExtension->Pdo,
|
|
DevicePropertyDeviceDescription,
|
|
length,
|
|
deviceDesc,
|
|
&length);
|
|
if (!NT_SUCCESS(status)) {
|
|
ExFreePool(deviceDesc);
|
|
}
|
|
} else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
deviceDesc = L"[unknown]";
|
|
}
|
|
|
|
RtlInitUnicodeString(&unicodeString, deviceDesc);
|
|
|
|
retVal = IoRaiseInformationalHardError(
|
|
ErrorCode,
|
|
&unicodeString,
|
|
NULL);
|
|
|
|
//
|
|
// Note: successful status here indicates success of
|
|
// IoGetDeviceProperty above. This would mean we still have an
|
|
// allocated buffer.
|
|
//
|
|
if (NT_SUCCESS(status)) {
|
|
ExFreePool(deviceDesc);
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SdbusStringsToMultiString(
|
|
IN PCSTR * Strings,
|
|
IN ULONG Count,
|
|
IN PUNICODE_STRING MultiString
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine formats a set of supplied strings into a multi string format, terminating
|
|
it with a double '\0' character
|
|
|
|
Arguments:
|
|
|
|
Strings - Pointer to an array of strings
|
|
Count - Number of strings in the supplied array which are packed into the multi-string
|
|
MultiString - Pointer to the Unicode string which packs the supplied string as a multi-string
|
|
terminated by double NULL
|
|
|
|
Return value:
|
|
|
|
STATUS_SUCCESS
|
|
STATUS_INSUFFICIENT_RESOURCES - Could not allocate memory for the multi-string
|
|
|
|
|
|
--*/
|
|
{
|
|
ULONG i, multiStringLength=0;
|
|
UNICODE_STRING tempMultiString;
|
|
PCSTR * currentString;
|
|
ANSI_STRING ansiString;
|
|
NTSTATUS status;
|
|
|
|
|
|
ASSERT (MultiString->Buffer == NULL);
|
|
|
|
for (i = Count, currentString = Strings; i > 0;i--, currentString++) {
|
|
RtlInitAnsiString(&ansiString, *currentString);
|
|
multiStringLength += RtlAnsiStringToUnicodeSize(&ansiString);
|
|
|
|
}
|
|
ASSERT(multiStringLength != 0);
|
|
multiStringLength += sizeof(WCHAR);
|
|
|
|
MultiString->Buffer = ExAllocatePool(PagedPool, multiStringLength);
|
|
if (MultiString->Buffer == NULL) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
MultiString->MaximumLength = (USHORT) multiStringLength;
|
|
MultiString->Length = (USHORT) multiStringLength;
|
|
|
|
tempMultiString = *MultiString;
|
|
|
|
for (i = Count, currentString = Strings; i > 0;i--, currentString++) {
|
|
RtlInitAnsiString(&ansiString, *currentString);
|
|
status = RtlAnsiStringToUnicodeString(&tempMultiString,
|
|
&ansiString,
|
|
FALSE);
|
|
ASSERT(NT_SUCCESS(status));
|
|
((PSTR) tempMultiString.Buffer) += tempMultiString.Length + sizeof(WCHAR);
|
|
};
|
|
|
|
//
|
|
// Add one more NULL to terminate the multi string
|
|
//
|
|
RtlZeroMemory(tempMultiString.Buffer, sizeof(WCHAR));
|
|
return STATUS_SUCCESS;
|
|
}
|