Leaked source code of windows server 2003
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.
 
 
 
 
 
 

911 lines
27 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
KBDHID.C
Abstract:
This module contains the init code for the i8042 to hid converter.
Note: This is NOT a WDM driver, since it cannot run as a HID mapper on
Memphis (Memphis requires that the keyboard to HID mapper be a VXD) and
since it uses Event logs, which are not part of WDM 1.0
Environment:
Kernel mode
Revision History:
Nov-96 : created by Kenneth D. Ray
Jan-97 : Dan Markarian : Made work
May-97 : Kenneth D. Ray : reconstructed as PnP filter for Keyboard class
--*/
#include "kbdhid.h"
#include "hidclass.h"
//
// Use the alloc_text pragma to specify the driver initialization routines
// (they can be paged out). [DAN]
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,DriverEntry)
#pragma alloc_text(PAGE,KbdHid_Unload)
#endif
GLOBALS Globals;
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
Installable driver initialization entry point.
Arguments:
DriverObject - pointer to the driver object
RegistryPath - pointer to a unicode string representing the path
to driver-specific key in the registry
Return Value:
NT status code
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PUNICODE_STRING registryPath = &Globals.RegistryPath;
Print (DBG_SS_TRACE, ("entering DriverEntry\n"));
Print (DBG_SS_INFO, ("Keyboard to hid mapper\n"));
RtlZeroMemory (&Globals, sizeof (GLOBALS));
//
// Need to ensure that the registry path is null-terminated.
// Allocate pool to hold a null-terminated copy of the path.
// Safe in paged pool since all registry routines execute at
// PASSIVE_LEVEL.
//
registryPath->MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL);
registryPath->Length = RegistryPath->Length;
registryPath->Buffer = ExAllocatePool(
PagedPool,
registryPath->MaximumLength
);
if (!registryPath->Buffer) {
Print (DBG_SS_ERROR,
("Initialize: Couldn't allocate pool for registry path."));
status = STATUS_INSUFFICIENT_RESOURCES;
goto DriverEntryReject;
}
RtlZeroMemory (registryPath->Buffer, registryPath->MaximumLength);
RtlMoveMemory (registryPath->Buffer,
RegistryPath->Buffer,
RegistryPath->Length);
//
// Set up the device driver entry points.
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = KbdHid_Create;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = KbdHid_Close;
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL]=KbdHid_IOCTL;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KbdHid_PassThrough;
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = KbdHid_Flush;
DriverObject->MajorFunction[IRP_MJ_PNP] = KbdHid_PnP;
DriverObject->MajorFunction[IRP_MJ_POWER] = KbdHid_Power;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = KbdHid_SystemControl;
DriverObject->DriverUnload = KbdHid_Unload;
DriverObject->DriverExtension->AddDevice = KbdHid_AddDevice;
Print (DBG_SS_TRACE, ("exit DriverEntry (0x%x) \n", status));
return status;
DriverEntryReject:
if (registryPath->Buffer) {
ExFreePool (registryPath->Buffer);
}
return status;
}
NTSTATUS
KbdHid_PassThrough (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Pass the irp on through
--*/
{
NTSTATUS status;
PDEVICE_EXTENSION data;
data = DeviceObject->DeviceExtension;
status = IoAcquireRemoveLock (&data->RemoveLock, Irp);
if (!NT_SUCCESS (status)) {
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
IoSkipCurrentIrpStackLocation (Irp);
status = IoCallDriver (data->TopOfStack, Irp);
IoReleaseRemoveLock (&data->RemoveLock, Irp);
return status;
}
VOID
KbdHid_Unload(
IN PDRIVER_OBJECT Driver
)
/*++
Routine Description:
Free all the allocated resources, etc.
Arguments:
DriverObject - pointer to a driver object
Return Value:
None
--*/
{
PAGED_CODE ();
ASSERT (NULL == Driver->DeviceObject);
Print (DBG_SS_INFO, ("Unload \n"));
//
// Free resources in device extension.
//
ExFreePool (Globals.RegistryPath.Buffer);
return;
}
NTSTATUS
KbdHid_Flush(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Respond to flush requests from the mouse class driver. Currently does
nothing but pass IRP down to next lower driver. This routine expects
the current IRQL to be < DISPATCH_LEVEL.
Arguments:
DeviceObject - Pointer to the device object.
Irp - Pointer to the request packet.
Return Value:
NT status code.
--*/
{
PDEVICE_EXTENSION data;
NTSTATUS status;
PIO_STACK_LOCATION stack;
Print (DBG_CALL_INFO, ("Flush \n"));
TRAP();
//
// Get a pointer to the device extension.
//
data = DeviceObject->DeviceExtension;
status = IoAcquireRemoveLock (&data->RemoveLock, Irp);
if (!NT_SUCCESS (status)) {
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
//
// Send the flush request down to the HID class driver, one for each
// of our mouse device context structures.
//
IoCopyCurrentIrpStackLocationToNext (Irp);
stack = IoGetNextIrpStackLocation (Irp);
stack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_FLUSH_QUEUE;
//
// Fire and forget
//
status = IoCallDriver (data->TopOfStack, Irp);
IoReleaseRemoveLock (&data->RemoveLock, Irp);
return status;
}
NTSTATUS
KbdHid_IOCTL (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Respond to queries from the mouse class driver.
The IOCTLs for DISABLE, ENABLE, and QUERY_ATTRIBUTES, expect the current
IRQL to be < DISPATCH_LEVEL.
Arguments:
DeviceObject - Pointer to the device object.
Irp - Pointer to the request packet.
Return Value:
NT status code.
--*/
{
PIO_STACK_LOCATION stack;
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_EXTENSION data;
ULONG length;
PKEYBOARD_INDICATOR_TRANSLATION translation;
BOOLEAN completeIt = TRUE;
data = DeviceObject->DeviceExtension;
Irp->IoStatus.Information = 0;
stack = IoGetCurrentIrpStackLocation (Irp);
status = IoAcquireRemoveLock (&data->RemoveLock, Irp);
if (!NT_SUCCESS (status)) {
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
ASSERT (data->Started ||
(IOCTL_INTERNAL_KEYBOARD_CONNECT ==
stack->Parameters.DeviceIoControl.IoControlCode));
switch (stack->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_INTERNAL_KEYBOARD_CONNECT:
//
// Connect a keyboard class device driver to the port driver.
//
Print (DBG_IOCTL_TRACE, ("enter Connect \n"));
//
// Connect a mouse class device driver to the filter driver.
// Only allow one connection.
//
if (NULL != data->ConnectData.ClassService) {
Print (DBG_IOCTL_ERROR, ("ERROR: Multiple connects \n"));
TRAP ();
status = STATUS_SHARING_VIOLATION;
break;
} else if (stack->Parameters.DeviceIoControl.InputBufferLength <
sizeof(CONNECT_DATA)) {
Print (DBG_IOCTL_ERROR, ("ERROR: Invalid connect parameter size. \n"));
TRAP ();
status = STATUS_INVALID_PARAMETER;
break;
}
//
// Copy the connection parameters to the device extension.
//
data->ConnectData = *(PCONNECT_DATA)
stack->Parameters.DeviceIoControl.Type3InputBuffer;
status = STATUS_SUCCESS;
break;
case IOCTL_INTERNAL_KEYBOARD_DISCONNECT:
//
// Disconnect a keyboard class device driver from the port driver.
//
Print (DBG_IOCTL_TRACE, ("Disconnect \n"));
//
// Not implemented.
//
// To implement, code the following:
// ---------------------------------
// o ENSURE that we are NOT enabled (mouHidDeviceExt->EnableCount);
// o If we are, then (a) return STATUS_UNSUCCESSFUL, or
// (b) disable all devices immediately; see
// DISABLE IOCTL call for necessary code.
// o SYNCHRONIZE with the mouse read completion routine (must
// protect the callback pointer from being dereferenced when
// it becomes null). Note that no mechanism currently exists
// for this.
// o CLEAR the connection parameters in the device extension;
// ie. mouHidDeviceExt->MouClassObject = NULL;
// mouHidDeviceExt->MouClassCallback = NULL;
// o RELEASE the synchronizing lock.
// o RETURN STATUS_SUCCESS.
//
status = STATUS_NOT_IMPLEMENTED;
break;
case IOCTL_INTERNAL_KEYBOARD_ENABLE:
//
// Enable keyboard interrupts which really means start the ping pong
// down to hid class.
//
Print (DBG_IOCTL_ERROR, ("ERROR: PnP => use create not enable! \n"));
status = STATUS_NOT_SUPPORTED;
break;
case IOCTL_INTERNAL_KEYBOARD_DISABLE:
//
// Disable keyboard interrupts which really means stop the ping pongs
// down to hid class.
//
Print (DBG_IOCTL_ERROR, ("ERROR: PnP => use close not Disable! \n"));
status = STATUS_NOT_SUPPORTED;
break;
case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
//
// Query the keyboard attributes. First check for adequate buffer
// length. Then, copy the keyboard attributes from the first device
// context to the output buffer. [DAN]
//
Print (DBG_IOCTL_TRACE, ("Query Attributes \n"));
if (stack->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(KEYBOARD_ATTRIBUTES)) {
Print (DBG_IOCTL_ERROR,
("ERROR: Query Attributes buffer too small \n"));
status = STATUS_BUFFER_TOO_SMALL;
} else {
//
// Copy the keyboard attributes to the buffer.
//
*(PKEYBOARD_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer =
data->Attributes;
Irp->IoStatus.Information = sizeof (KEYBOARD_ATTRIBUTES);
status = STATUS_SUCCESS;
}
break;
case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
//
// Query the scan code to indicator-light mapping. Validate the
// parameters, and copy the indicator mapping information from
// the static translation list to the SystemBuffer.
//
Print (DBG_IOCTL_TRACE, ("Query Indicator Translation \n"));
length = sizeof(KEYBOARD_INDICATOR_TRANSLATION)
+ (sizeof(INDICATOR_LIST)
* (HID_KEYBOARD_NUMBER_OF_INDICATORS - 1));
if (stack->Parameters.DeviceIoControl.OutputBufferLength < length) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
//
// Copy the indicator mapping information to the system
// buffer.
//
translation = ((PKEYBOARD_INDICATOR_TRANSLATION)
Irp->AssociatedIrp.SystemBuffer);
translation->NumberOfIndicatorKeys = HID_KEYBOARD_NUMBER_OF_INDICATORS;
RtlMoveMemory(translation->IndicatorList,
(PCHAR) IndicatorList,
length - FIELD_OFFSET (KEYBOARD_INDICATOR_TRANSLATION,
IndicatorList));
Irp->IoStatus.Information = length;
status = STATUS_SUCCESS;
break;
case IOCTL_KEYBOARD_QUERY_INDICATORS:
//
// Query the keyboard indicators. Validate the parameters, and
// copy the indicator information from the device context to
// the SystemBuffer. [DAN]
//
Print (DBG_IOCTL_TRACE, ("Query Indicators \n"));
if (stack->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
//
// Copy the keyboard indicators to the buffer.
//
//
// Don't bother to synchronize access to the device context
// KeyboardIndicators field while copying it. We don't care
// if another process is setting the LEDs.
//
// Copy the keyboard indicators to the buffer.
*(PKEYBOARD_INDICATOR_PARAMETERS) Irp->AssociatedIrp.SystemBuffer =
data->Indicators;
Irp->IoStatus.Information = sizeof(KEYBOARD_INDICATOR_PARAMETERS);
status = STATUS_SUCCESS;
break;
case IOCTL_KEYBOARD_SET_INDICATORS:
//
// Set the keyboard indicators for all known device contexts. [DAN]
//
Print (DBG_IOCTL_TRACE, ("Set Indicators \n"));
if (stack->Parameters.DeviceIoControl.InputBufferLength <
sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
Print (DBG_IOCTL_ERROR, ("ERROR: Set Indicators size!\n"));
status = STATUS_INVALID_PARAMETER;
break;
}
status = KbdHid_SetLedIndicators (
data,
(PKEYBOARD_INDICATOR_PARAMETERS) Irp->AssociatedIrp.SystemBuffer,
Irp);
completeIt = FALSE;
break;
case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
//
// Query the current keyboard typematic rate and delay. Validate
// the parameters, and copy the typematic information from the port
// device extension to the SystemBuffer. [DAN]
//
Print (DBG_IOCTL_TRACE, ("Query Typematic \n"));
if (stack->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
Print (DBG_IOCTL_ERROR, ("ERROR: query typematic size!\n"));
status = STATUS_BUFFER_TOO_SMALL;
break;
}
//
// Copy the keyboard typematic info to the buffer.
//
//
// Don't bother to synchronize access to the device context
// KeyboardTypematic field while copying it. We don't care
// if another process is setting the typematic info.
//
*(PKEYBOARD_TYPEMATIC_PARAMETERS) Irp->AssociatedIrp.SystemBuffer =
data->Typematic;
Irp->IoStatus.Information = sizeof(KEYBOARD_TYPEMATIC_PARAMETERS);
status = STATUS_SUCCESS;
break;
case IOCTL_KEYBOARD_SET_TYPEMATIC:
//
// Set the keyboard typematic rate and delay for all known device
// contexts. [DAN]
//
Print (DBG_IOCTL_TRACE, ("Set Typematic \n"));
if (stack->Parameters.DeviceIoControl.InputBufferLength <
sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
Print (DBG_IOCTL_ERROR, ("ERROR: Set Typematic size\n"));
status = STATUS_INVALID_PARAMETER;
break;
}
#define NewTypematic ((PKEYBOARD_TYPEMATIC_PARAMETERS) \
Irp->AssociatedIrp.SystemBuffer)
if ((NewTypematic->Rate == 0) && (NewTypematic->Delay == 0)) {
break;
}
if ((NewTypematic->Rate < data->Attributes.KeyRepeatMinimum.Rate) ||
(NewTypematic->Rate > data->Attributes.KeyRepeatMaximum.Rate) ||
(NewTypematic->Delay < data->Attributes.KeyRepeatMinimum.Delay) ||
(NewTypematic->Delay > data->Attributes.KeyRepeatMaximum.Delay)) {
Print (DBG_IOCTL_ERROR, ("ERROR: Set Typematic range\n"));
status = STATUS_INVALID_PARAMETER;
break;
}
Print (DBG_IOCTL_INFO,
("Set Typematic Rate: %d Delay: %d\n",
NewTypematic->Rate,
NewTypematic->Delay));
//
// Don't bother to synchronize access to the device context
// KeyboardTypematic field while copying it. We don't care
// if another thread is reading the typematic info.
//
// Note the only danger here is in setting the 64-bit integer
// "AutoRepeatDelay" in two non-atomic statements. However,
// we are safe since we never set "HighPart" to anything but
// -1.
//
data->Typematic = *NewTypematic;
data->AutoRepeatRate = 1000 / NewTypematic->Rate; // ms
data->AutoRepeatDelay.LowPart = -NewTypematic->Delay*10000; // 100ns
data->AutoRepeatDelay.HighPart = -1;
break;
#undef NewTypematic
default:
Print (DBG_IOCTL_ERROR,
("ERROR: unknown IOCTL: 0x%x \n",
stack->Parameters.DeviceIoControl.IoControlCode));
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
if (completeIt) {
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
IoReleaseRemoveLock (&data->RemoveLock, Irp);
Print (DBG_IOCTL_TRACE, ("IOCTL exit (%x)\n", status));
return status;
}
NTSTATUS
KbdHid_SetLedIndicatorsComplete (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PIO_STACK_LOCATION stack;
PDEVICE_EXTENSION data;
stack = IoGetCurrentIrpStackLocation (Irp);
data = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
if (Irp->PendingReturned) {
IoMarkIrpPending (Irp);
}
IoFreeMdl (Irp->MdlAddress);
Irp->MdlAddress = (PMDL) stack->Parameters.Others.Argument4;
ExFreePool (Context);
IoReleaseRemoveLock (&data->RemoveLock, Irp);
return STATUS_SUCCESS;
}
NTSTATUS
KbdHid_SetLedIndicators (
PDEVICE_EXTENSION Data,
PKEYBOARD_INDICATOR_PARAMETERS NewIndicators,
PIRP Irp
)
/*++
Routine Description:
Set the LED indicators of the supplied keyboard device context.
Arguments:
Data - Pointer to the driver device extension.
Parameters - Pointer to the keyboard indicators to set/unset.
Irp - An Irp to use for setting these parameters
Return Value:
STATUS_SUCCESS on success, STATUS_PENDING if operation is still pending,
or otherwise an NTSTATUS error code on an error.
--*/
{
PIO_STACK_LOCATION nextStack;
PIO_STACK_LOCATION curStack;
NTSTATUS status = STATUS_SUCCESS;
USAGE usageBuffer [4]; // only 4 known usages hardcoded below
ULONG usageBufferLen = 0;
PCHAR outputBuffer = 0;
PMDL outputMdl = 0;
PHID_EXTENSION hid = Data->HidExtension;
status = IoAcquireRemoveLock (&Data->RemoveLock, Irp);
if (!NT_SUCCESS (status)) {
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
if (0 == hid->Caps.OutputReportByteLength) {
//
// This device has no LEDs, now while that is strange it is not really
// an error. HID keyboards can have any LEDs that they want, including
// none.
//
status = STATUS_SUCCESS;
goto KbdHid_SetIndicatorsReject;
}
outputBuffer = ExAllocatePool (NonPagedPool,
hid->Caps.OutputReportByteLength);
if (NULL == outputBuffer) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto KbdHid_SetIndicatorsReject;
}
outputMdl = IoAllocateMdl (outputBuffer, // The virtual address
hid->Caps.OutputReportByteLength, // length of the MDL
FALSE, // No associated IRP -> not secondary
FALSE, // No quota charge
0); // No associated IRP
if (NULL == outputMdl) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto KbdHid_SetIndicatorsReject;
}
MmBuildMdlForNonPagedPool (outputMdl); // Build this MDL.
//
// Zero the output report packet.
//
RtlZeroMemory(outputBuffer, hid->Caps.OutputReportByteLength);
//
// Setup the usage list of LEDs.
//
if (NewIndicators->LedFlags & KEYBOARD_KANA_LOCK_ON) {
usageBuffer[usageBufferLen++] = HID_USAGE_LED_KANA;
}
if (NewIndicators->LedFlags & KEYBOARD_CAPS_LOCK_ON) {
usageBuffer[usageBufferLen++] = HID_USAGE_LED_CAPS_LOCK;
}
if (NewIndicators->LedFlags & KEYBOARD_NUM_LOCK_ON) {
usageBuffer[usageBufferLen++] = HID_USAGE_LED_NUM_LOCK;
}
if (NewIndicators->LedFlags & KEYBOARD_SCROLL_LOCK_ON) {
usageBuffer[usageBufferLen++] = HID_USAGE_LED_SCROLL_LOCK;
}
if (usageBufferLen == 0) {
ASSERT((NewIndicators->LedFlags & (KEYBOARD_KANA_LOCK_ON |
KEYBOARD_CAPS_LOCK_ON |
KEYBOARD_NUM_LOCK_ON |
KEYBOARD_SCROLL_LOCK_ON)) == 0);
//
// In order to fix led setting on a multiple collection keyboard, we
// have to initialize the output report to make sure we get the correct
// collection id. This is for the case where we are going from one
// led on to all leds off. If not initialized, we'll get a report with no
// collection id at the beginning.
//
usageBuffer[0] = HID_USAGE_LED_SCROLL_LOCK; // arbitirary led
usageBufferLen = 1;
HidP_UnsetUsages(HidP_Output,
HID_USAGE_PAGE_LED,
0,
usageBuffer,
&usageBufferLen,
hid->Ppd,
outputBuffer,
hid->Caps.OutputReportByteLength);
}
else {
//
// Set the usages in the output report.
//
HidP_SetUsages(HidP_Output,
HID_USAGE_PAGE_LED,
0,
usageBuffer,
&usageBufferLen,
hid->Ppd,
outputBuffer,
hid->Caps.OutputReportByteLength);
}
//
// Obtain a pointer to the next IRP stack location.
//
nextStack = IoGetNextIrpStackLocation (Irp);
curStack = IoGetCurrentIrpStackLocation (Irp);
ASSERT(nextStack != NULL);
//
// Set up our write to HIDCLASS.
//
curStack->Parameters.Others.Argument4 = (PVOID) Irp->MdlAddress;
Irp->MdlAddress = outputMdl;
IoCopyCurrentIrpStackLocationToNext (Irp);
nextStack->MajorFunction = IRP_MJ_WRITE;
nextStack->Parameters.Write.Length = hid->Caps.OutputReportByteLength;
nextStack->Parameters.Write.Key = 0;
nextStack->Parameters.Write.ByteOffset.QuadPart = 0;
//
// Hook a completion routine to be called when the request completes.
//
IoSetCompletionRoutine (Irp,
KbdHid_SetLedIndicatorsComplete,
outputBuffer,
TRUE,
TRUE,
TRUE);
//
// Call the next driver.
//
status = IoCallDriver(Data->TopOfStack, Irp);
//
// Return status.
//
return status;
KbdHid_SetIndicatorsReject:
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
if (NULL != outputBuffer) {
ExFreePool (outputBuffer);
}
if (NULL != outputMdl) {
IoFreeMdl (outputMdl);
}
IoReleaseRemoveLock (&Data->RemoveLock, Irp);
return status;
}
VOID
KbdHid_LogError(
IN PDRIVER_OBJECT DriverObject,
IN NTSTATUS ErrorCode,
IN PWSTR ErrorInsertionString OPTIONAL)
/*++
[DAN]
Routine Description:
Logs an error to the system.
Arguments:
DriverObject - Pointer to driver object reporting the error.
ErrorCode - Indicates the type of error, system or driver-defined.
ErrorInsertionString - Null-terminated Unicode string inserted into error
description, as defined by error code. Must be no
no longer than 50 characters.
Return Value:
None.
--*/
{
ULONG errorInsertionStringSize = 0;
PIO_ERROR_LOG_PACKET errorLogEntry;
ULONG errorLogEntrySize; // [including null]
PWCHAR pWChar;
if (ErrorInsertionString) {
for (pWChar = ErrorInsertionString; *pWChar; pWChar++) {
errorInsertionStringSize += sizeof(WCHAR);
}
errorInsertionStringSize += sizeof(UNICODE_NULL);
}
errorLogEntrySize = sizeof(IO_ERROR_LOG_PACKET) + errorInsertionStringSize;
//
// Log an error.
//
if (errorLogEntrySize <= ERROR_LOG_MAXIMUM_SIZE) {
errorLogEntry = IoAllocateErrorLogEntry(DriverObject,
(UCHAR)errorLogEntrySize);
if (errorLogEntry != NULL) {
RtlZeroMemory(errorLogEntry, errorLogEntrySize);
errorLogEntry->ErrorCode = ErrorCode;
errorLogEntry->FinalStatus = ErrorCode;
errorLogEntry->NumberOfStrings = (ErrorInsertionString) ? 1 : 0;
if (ErrorInsertionString) {
RtlCopyMemory(errorLogEntry->DumpData,
ErrorInsertionString,
errorInsertionStringSize);
}
IoWriteErrorLogEntry(errorLogEntry);
}
}
return;
}