windows-nt/Source/XPSP1/NT/drivers/wdm/usb/driver/wceusbsh/common.c
2020-09-26 16:20:57 +08:00

1042 lines
27 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1999-2000 Microsoft Corporation
Module Name :
common.c
Abstract:
Common code for the Windows CE
USB Serial Host and Filter drivers
Author:
Jeff Midkiff (jeffmi) 08-24-99
--*/
#include <stdio.h>
#include "wceusbsh.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGEWCE0, QueryRegistryParameters)
#pragma alloc_text(PAGEWCE0, CreateDevObjAndSymLink)
#pragma alloc_text(PAGEWCE0, DeleteDevObjAndSymLink)
#pragma alloc_text(PAGEWCE0, IsWin9x)
#pragma alloc_text(PAGEWCE1, LogError)
#endif
NTSTATUS
QueryRegistryParameters(
IN PUNICODE_STRING RegistryPath
)
/*++
This routine queryies the Registry for our Parameters key.
We are given the RegistryPath to our driver during DriverEntry,
but don't yet have an extension, so we store the values in globals
until we get our device extension.
The values are setup from our INF.
On WinNT this is under
HKLM\SYSTEM\ControlSet\Services\wceusbsh\Parameters
On Win98 this is under
HKLM\System\CurrentControlSet\Services\Class\WCESUSB\000*
Returns - nothing; use defaults
--*/
{
#define NUM_REG_ENTRIES 6
RTL_QUERY_REGISTRY_TABLE rtlQueryRegTbl[ NUM_REG_ENTRIES + 1 ];
ULONG sizeOfUl = sizeof( ULONG );
ULONG ulAlternateSetting = DEFAULT_ALTERNATE_SETTING;
LONG lIntTimout = DEFAULT_INT_PIPE_TIMEOUT;
ULONG ulMaxPipeErrors = DEFAULT_MAX_PIPE_DEVICE_ERRORS;
ULONG ulDebugLevel = DBG_OFF;
ULONG ulExposeComPort = FALSE;
NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE();
ASSERT( RegistryPath != NULL );
RtlZeroMemory( rtlQueryRegTbl, sizeof(rtlQueryRegTbl) );
//
// Setup the query table
// Note: the 1st table entry is the \Parameters subkey,
// and the last table entry is NULL
//
rtlQueryRegTbl[0].QueryRoutine = NULL;
rtlQueryRegTbl[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
rtlQueryRegTbl[0].Name = L"Parameters";
rtlQueryRegTbl[0].EntryContext = NULL;
rtlQueryRegTbl[0].DefaultType = (ULONG_PTR)NULL;
rtlQueryRegTbl[0].DefaultData = NULL;
rtlQueryRegTbl[0].DefaultLength = (ULONG_PTR)NULL;
rtlQueryRegTbl[1].QueryRoutine = NULL;
rtlQueryRegTbl[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
rtlQueryRegTbl[1].Name = L"DebugLevel";
rtlQueryRegTbl[1].EntryContext = &DebugLevel;
rtlQueryRegTbl[1].DefaultType = REG_DWORD;
rtlQueryRegTbl[1].DefaultData = &ulDebugLevel;
rtlQueryRegTbl[1].DefaultLength = sizeOfUl;
rtlQueryRegTbl[2].QueryRoutine = NULL;
rtlQueryRegTbl[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
rtlQueryRegTbl[2].Name = L"AlternateSetting";
rtlQueryRegTbl[2].EntryContext = &g_ulAlternateSetting;
rtlQueryRegTbl[2].DefaultType = REG_DWORD;
rtlQueryRegTbl[2].DefaultData = &ulAlternateSetting;
rtlQueryRegTbl[2].DefaultLength = sizeOfUl;
rtlQueryRegTbl[3].QueryRoutine = NULL;
rtlQueryRegTbl[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
rtlQueryRegTbl[3].Name = L"InterruptTimeout";
rtlQueryRegTbl[3].EntryContext = &g_lIntTimout;
rtlQueryRegTbl[3].DefaultType = REG_DWORD;
rtlQueryRegTbl[3].DefaultData = &lIntTimout;
rtlQueryRegTbl[3].DefaultLength = sizeOfUl;
rtlQueryRegTbl[4].QueryRoutine = NULL;
rtlQueryRegTbl[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
rtlQueryRegTbl[4].Name = L"MaxPipeErrors";
rtlQueryRegTbl[4].EntryContext = &g_ulMaxPipeErrors;
rtlQueryRegTbl[4].DefaultType = REG_DWORD;
rtlQueryRegTbl[4].DefaultData = &ulMaxPipeErrors;
rtlQueryRegTbl[4].DefaultLength = sizeOfUl;
rtlQueryRegTbl[5].QueryRoutine = NULL;
rtlQueryRegTbl[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
rtlQueryRegTbl[5].Name = L"ExposeComPort";
rtlQueryRegTbl[5].EntryContext = &g_ExposeComPort;
rtlQueryRegTbl[5].DefaultType = REG_DWORD;
rtlQueryRegTbl[5].DefaultData = &ulExposeComPort;
rtlQueryRegTbl[5].DefaultLength = sizeOfUl;
//
// query the Registry
//
status = RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, // RelativeTo
RegistryPath->Buffer, // Path
rtlQueryRegTbl, // QueryTable
NULL, // Context
NULL ); // Environment
if ( !NT_SUCCESS( status ) ) {
//
// if registry query failed then use defaults
//
DbgDump( DBG_INIT, ("RtlQueryRegistryValues error: 0x%x\n", status) );
g_ulAlternateSetting = ulAlternateSetting;
g_lIntTimout = lIntTimout;
g_ulMaxPipeErrors = ulMaxPipeErrors;
DebugLevel = DBG_OFF;
}
DbgDump( DBG_INIT, ("DebugLevel = 0x%x\n", DebugLevel));
DbgDump( DBG_INIT, ("AlternateSetting = %d\n", g_ulAlternateSetting));
DbgDump( DBG_INIT, ("MaxPipeErrors = %d\n", g_ulMaxPipeErrors));
DbgDump( DBG_INIT, ("INT Timeout = %d\n", g_lIntTimout));
return status;
}
VOID
ReleaseSlot(
IN LONG Slot
)
{
LONG lNumDevices = InterlockedDecrement(&g_NumDevices);
UNREFERENCED_PARAMETER( Slot );
ASSERT( lNumDevices >= 0);
return;
}
NTSTATUS
AcquireSlot(
OUT PULONG PSlot
)
{
NTSTATUS status = STATUS_SUCCESS;
*PSlot = InterlockedIncrement(&g_NumDevices);
if (*PSlot == (ULONG)0) {
status = STATUS_INVALID_DEVICE_REQUEST;
}
return status;
}
NTSTATUS
CreateDevObjAndSymLink(
IN PDRIVER_OBJECT PDrvObj,
IN PDEVICE_OBJECT PPDO,
IN PDEVICE_OBJECT *PpDevObj,
IN PCHAR PDevName
)
/*++
Routine Description:
Creates a named device object and symbolic link
for the next available device instance. Saves both the \\Device\\PDevName%n
and \\DosDevices\\PDevName%n in the device extension.
Also registers our device interface with PnP system.
Arguments:
PDrvObj - Pointer to our driver object
PPDO - Pointer to the PDO for the stack to which we should add ourselves
PDevName - device name to use
Return Value:
NTSTATUS
--*/
{
PDEVICE_EXTENSION pDevExt = NULL;
NTSTATUS status;
ULONG deviceInstance;
ULONG bufferLen;
BOOLEAN gotSlot = FALSE;
ANSI_STRING asDevName;
ANSI_STRING asDosDevName;
UNICODE_STRING usDeviceName = {0}; // seen only in kernel-mode namespace
UNICODE_STRING usDosDevName = {0}; // seen in user-mode namespace
CHAR dosDeviceNameBuffer[DOS_NAME_MAX];
CHAR deviceNameBuffer[DOS_NAME_MAX];
DbgDump(DBG_INIT, (">CreateDevObjAndSymLink\n"));
PAGED_CODE();
ASSERT( PPDO );
//
// init the callers device obj
//
*PpDevObj = NULL;
//
// Get the next device instance number
//
status = AcquireSlot(&deviceInstance);
if (status != STATUS_SUCCESS) {
DbgDump(DBG_ERR, ("AcquireSlot error: 0x%x\n", status));
goto CreateDeviceObjectError;
} else {
gotSlot = TRUE;
}
//
// concat device name & instance number
//
ASSERT( *PDevName != (CHAR)NULL);
sprintf(dosDeviceNameBuffer, "%s%s%03d", "\\DosDevices\\", PDevName,
deviceInstance);
sprintf(deviceNameBuffer, "%s%s%03d", "\\Device\\", PDevName,
deviceInstance);
// convert names to ANSI string
RtlInitAnsiString(&asDevName, deviceNameBuffer);
RtlInitAnsiString(&asDosDevName, dosDeviceNameBuffer);
usDeviceName.Length = 0;
usDeviceName.Buffer = NULL;
usDosDevName.Length = 0;
usDosDevName.Buffer = NULL;
//
// convert names to UNICODE
//
status = RtlAnsiStringToUnicodeString(&usDeviceName, &asDevName, TRUE);
if (status != STATUS_SUCCESS) {
DbgDump(DBG_ERR, ("RtlAnsiStringToUnicodeString error: 0x%x\n", status));
goto CreateDeviceObjectError;
}
status = RtlAnsiStringToUnicodeString(&usDosDevName, &asDosDevName, TRUE);
if (status != STATUS_SUCCESS) {
DbgDump(DBG_ERR, ("RtlAnsiStringToUnicodeString error: 0x%x\n", status));
goto CreateDeviceObjectError;
}
//
// create the named devive object
// Note: we may want to change this to a non-exclusive later
// so xena to come in without the filter.
//
status = IoCreateDevice( PDrvObj,
sizeof(DEVICE_EXTENSION),
&usDeviceName,
FILE_DEVICE_SERIAL_PORT,
0,
TRUE, // Note: SerialPorts are exclusive
PpDevObj);
if (status != STATUS_SUCCESS) {
DbgDump(DBG_ERR, ("IoCreateDevice error: 0x%x\n", status));
TEST_TRAP();
goto CreateDeviceObjectError;
}
//
// get pointer to device extension
//
pDevExt = (PDEVICE_EXTENSION) (*PpDevObj)->DeviceExtension;
RtlZeroMemory(pDevExt, sizeof(DEVICE_EXTENSION)); // (redundant)
//
// init SERIAL_PORT_INTERFACE
//
pDevExt->SerialPort.Type = WCE_SERIAL_PORT_TYPE;
//
// create symbolic link
//
status = IoCreateUnprotectedSymbolicLink(&usDosDevName, &usDeviceName);
if (status != STATUS_SUCCESS) {
DbgDump(DBG_ERR, ("IoCreateUnprotectedSymbolicLink error: 0x%x\n", status));
goto CreateDeviceObjectError;
}
DbgDump(DBG_INIT, ("SymbolicLink: %ws\n", usDosDevName.Buffer));
//
// Make the device visible via a device association as well.
// The reference string is the eight digit device index
//
status = IoRegisterDeviceInterface(
PPDO,
(LPGUID)&GUID_WCE_SERIAL_USB,
NULL,
&pDevExt->DeviceClassSymbolicName );
if (status != STATUS_SUCCESS) {
DbgDump(DBG_ERR, ("IoRegisterDeviceInterface error: 0x%x\n", status));
pDevExt->DeviceClassSymbolicName.Buffer = NULL;
goto CreateDeviceObjectError;
}
DbgDump(DBG_INIT, ("DeviceClassSymbolicName: %ws\n", pDevExt->DeviceClassSymbolicName.Buffer));
//
// save the Dos Device link name in our extension
//
strcpy(pDevExt->DosDeviceName, dosDeviceNameBuffer);
pDevExt->SymbolicLink = TRUE;
//
// save (kernel) device name in extension
//
bufferLen = RtlAnsiStringToUnicodeSize(&asDevName);
pDevExt->DeviceName.Length = 0;
pDevExt->DeviceName.MaximumLength = (USHORT)bufferLen;
pDevExt->DeviceName.Buffer = ExAllocatePool(PagedPool, bufferLen);
if (pDevExt->DeviceName.Buffer == NULL) {
//
// Skip out. We have worse problems than missing
// the name if we have no memory at this point.
//
status = STATUS_INSUFFICIENT_RESOURCES;
DbgDump(DBG_ERR, ("CreateDevObjAndSymLink ERROR: 0x%x\n", status));
goto CreateDeviceObjectError;
}
RtlAnsiStringToUnicodeString(&pDevExt->DeviceName, &asDevName, FALSE);
// save 1's based device instance number
pDevExt->SerialPort.Com.Instance = deviceInstance;
CreateDeviceObjectError:;
//
// free Unicode strings
//
RtlFreeUnicodeString(&usDeviceName);
RtlFreeUnicodeString(&usDosDevName);
//
// Delete the devobj if there was an error
//
if (status != STATUS_SUCCESS) {
if ( *PpDevObj ) {
DeleteDevObjAndSymLink( *PpDevObj );
*PpDevObj = NULL;
}
if (gotSlot) {
ReleaseSlot(deviceInstance);
}
}
DbgDump(DBG_INIT, ("<CreateDevObjAndSymLink 0x%x\n", status));
return status;
}
NTSTATUS
DeleteDevObjAndSymLink(
IN PDEVICE_OBJECT PDevObj
)
{
PDEVICE_EXTENSION pDevExt;
UNICODE_STRING usDevLink;
ANSI_STRING asDevLink;
NTSTATUS NtStatus = STATUS_SUCCESS;
DbgDump(DBG_INIT, (">DeleteDevObjAndSymLink\n"));
PAGED_CODE();
ASSERT( PDevObj );
pDevExt = (PDEVICE_EXTENSION) PDevObj->DeviceExtension;
ASSERT( pDevExt );
// get rid of the symbolic link
if ( pDevExt->SymbolicLink ) {
RtlInitAnsiString( &asDevLink, pDevExt->DosDeviceName );
NtStatus = RtlAnsiStringToUnicodeString( &usDevLink,
&asDevLink, TRUE);
ASSERT(STATUS_SUCCESS == NtStatus);
NtStatus = IoDeleteSymbolicLink(&usDevLink);
}
if (pDevExt->DeviceClassSymbolicName.Buffer)
{
NtStatus = IoSetDeviceInterfaceState(&pDevExt->DeviceClassSymbolicName, FALSE);
if (NT_SUCCESS(NtStatus)) {
DbgDump(DBG_WRN, ("IoSetDeviceInterfaceState.3: OFF\n"));
}
ExFreePool( pDevExt->DeviceClassSymbolicName.Buffer );
pDevExt->DeviceClassSymbolicName.Buffer = NULL;
}
if (pDevExt->DeviceName.Buffer != NULL) {
ExFreePool(pDevExt->DeviceName.Buffer);
RtlInitUnicodeString(&pDevExt->DeviceName, NULL);
}
//
// Wait to do this untill here as this triggers the unload routine
// at which point everything better have been deallocated
//
IoDeleteDevice( PDevObj );
DbgDump(DBG_INIT, ("<DeleteDevObjAndSymLink\n"));
return NtStatus;
}
#if 0
VOID
SetBooleanLocked(
IN OUT PBOOLEAN PDest,
IN BOOLEAN Src,
IN PKSPIN_LOCK PSpinLock
)
/*++
Routine Description:
This function is used to assign a BOOLEAN value with spinlock protection.
Arguments:
PDest - A pointer to Lval.
Src - Rval.
PSpinLock - Pointer to the spin lock we should hold.
Return Value:
None.
--*/
{
KIRQL tmpIrql;
KeAcquireSpinLock(PSpinLock, &tmpIrql);
*PDest = Src;
KeReleaseSpinLock(PSpinLock, tmpIrql);
}
#endif
VOID
SetPVoidLocked(
IN OUT PVOID *PDest,
IN OUT PVOID Src,
IN PKSPIN_LOCK PSpinLock
)
{
KIRQL tmpIrql;
KeAcquireSpinLock(PSpinLock, &tmpIrql);
*PDest = Src;
KeReleaseSpinLock(PSpinLock, tmpIrql);
}
//
// Note: had to use ExWorkItems to be binary compatible with Win98.
// The WorkerRoutine must take as it's only parameter a PWCE_WORK_ITEM
// and extract any parameters. When the WorkerRoutine is complete is MUST
// call DequeueWorkItem to free it back to the worker pool & signal any waiters.
//
NTSTATUS
QueueWorkItem(
IN PDEVICE_OBJECT PDevObj,
IN PWCE_WORKER_THREAD_ROUTINE WorkerRoutine,
IN PVOID Context,
IN ULONG Flags
)
{
PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
NTSTATUS status = STATUS_INVALID_PARAMETER;
PWCE_WORK_ITEM pWorkItem;
KIRQL irql;
DbgDump(DBG_WORK_ITEMS, (">QueueWorkItem\n" ));
//
// N.B: you need to ensure your driver does not queue anything when it is stopped.
//
KeAcquireSpinLock(&pDevExt->ControlLock, &irql);
if ( !CanAcceptIoRequests(PDevObj, FALSE, TRUE) ) {
status = STATUS_DELETE_PENDING;
DbgDump(DBG_ERR, ("QueueWorkItem: 0x%x\n", status));
} else if ( PDevObj && WorkerRoutine ) {
pWorkItem = ExAllocateFromNPagedLookasideList( &pDevExt->WorkItemPool );
if ( pWorkItem ) {
status = AcquireRemoveLock(&pDevExt->RemoveLock, pWorkItem);
if ( !NT_SUCCESS(status) ) {
DbgDump(DBG_ERR, ("QueueWorkItem: 0x%x\n", status));
TEST_TRAP();
ExFreeToNPagedLookasideList( &pDevExt->WorkItemPool, pWorkItem );
KeReleaseSpinLock(&pDevExt->ControlLock, irql);
return status;
}
RtlZeroMemory( pWorkItem, sizeof(*pWorkItem) );
// bump the pending count
InterlockedIncrement(&pDevExt->PendingWorkItemsCount);
DbgDump(DBG_WORK_ITEMS, ("PendingWorkItemsCount: %d\n", pDevExt->PendingWorkItemsCount));
//
// put the worker on our pending list
//
InsertTailList(&pDevExt->PendingWorkItems,
&pWorkItem->ListEntry );
//
// store parameters
//
pWorkItem->DeviceObject = PDevObj;
pWorkItem->Context = Context;
pWorkItem->Flags = Flags;
ExInitializeWorkItem( &pWorkItem->Item,
(PWORKER_THREAD_ROUTINE)WorkerRoutine,
(PVOID)pWorkItem // Context passed to WorkerRoutine
);
// finally, queue the worker
ExQueueWorkItem( &pWorkItem->Item,
CriticalWorkQueue );
status = STATUS_SUCCESS;
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
DbgDump(DBG_ERR, ("AllocateWorkItem failed!\n"));
TEST_TRAP()
}
}
KeReleaseSpinLock(&pDevExt->ControlLock, irql);
DbgDump(DBG_WORK_ITEMS, ("<QueueWorkItem 0x%x\n", status ));
return status;
}
VOID
DequeueWorkItem(
IN PDEVICE_OBJECT PDevObj,
IN PWCE_WORK_ITEM PWorkItem
)
{
PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
KIRQL irql;
DbgDump(DBG_WORK_ITEMS, (">DequeueWorkItem\n" ));
//
// remove the worker from the pending list
//
KeAcquireSpinLock( &pDevExt->ControlLock, &irql );
RemoveEntryList( &PWorkItem->ListEntry );
KeReleaseSpinLock( &pDevExt->ControlLock, irql);
//
// free the worker back to pool
//
ExFreeToNPagedLookasideList( &pDevExt->WorkItemPool, PWorkItem );
//
// signal event if this is the last one
//
if (0 == InterlockedDecrement( &pDevExt->PendingWorkItemsCount) ) {
DbgDump(DBG_WORK_ITEMS, ("PendingWorkItemsEvent signalled\n" ));
KeSetEvent( &pDevExt->PendingWorkItemsEvent, IO_NO_INCREMENT, FALSE);
}
DbgDump(DBG_WORK_ITEMS, ("PendingWorkItemsCount: %d\n", pDevExt->PendingWorkItemsCount));
ASSERT(pDevExt->PendingWorkItemsCount >= 0);
ReleaseRemoveLock(&pDevExt->RemoveLock, PWorkItem);
DbgDump(DBG_WORK_ITEMS, ("<DequeueWorkItem\n" ));
return;
}
#pragma warning( push )
#pragma warning( disable : 4706 ) // assignment w/i conditional expression
NTSTATUS
WaitForPendingItem(
IN PDEVICE_OBJECT PDevObj,
IN PKEVENT PPendingEvent,
IN PULONG PPendingCount
)
{
PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
LARGE_INTEGER timeOut = {0,0};
LONG itemsLeft;
NTSTATUS status = STATUS_SUCCESS;
DbgDump(DBG_PNP, (">WaitForPendingItem\n"));
if ( !PDevObj || !PPendingEvent || !PPendingCount ) {
status = STATUS_INVALID_PARAMETER;
DbgDump(DBG_ERR, ("WaitForPendingItem: STATUS_INVALID_PARAMETER\n"));
TEST_TRAP();
} else {
//
// wait for pending item to signal it's complete
//
while ( itemsLeft = InterlockedExchange( PPendingCount, *PPendingCount) ) {
DbgDump(DBG_PNP|DBG_EVENTS, ("Pending Items Remain: %d\n", itemsLeft ) );
timeOut.QuadPart = MILLISEC_TO_100NANOSEC( DEFAULT_PENDING_TIMEOUT );
DbgDump(DBG_PNP|DBG_EVENTS, ("Waiting for %d msec...\n", timeOut.QuadPart/10000));
PAGED_CODE();
KeWaitForSingleObject( PPendingEvent,
Executive,
KernelMode,
FALSE,
&timeOut );
}
DbgDump(DBG_PNP, ("Pending Items: %d\n", itemsLeft ) );
}
DbgDump(DBG_PNP, ("<WaitForPendingItem (0x%x)\n", status));
return status;
}
#pragma warning( pop )
BOOLEAN
CanAcceptIoRequests(
IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN AcquireLock,
IN BOOLEAN CheckOpened
)
/*++
Routine Description:
Check device extension status flags.
Can NOT accept a new I/O request if device:
1) is removed,
2) has never been started,
3) is stopped,
4) has a remove request pending, or
5) has a stop device pending
** Called with the SpinLock held, else AcquireLock should be TRUE **
Arguments:
DeviceObject - pointer to the device object
AcquireLock - if TRUE then we need to acquire the lock
CheckOpened - normally set to TRUE during I/O.
Special cases where FALSE include:
IRP_MN_QUERY_PNP_DEVICE_STATE
IRP_MJ_CREATE
Return Value:
TRUE/FALSE
--*/
{
PDEVICE_EXTENSION pDevExt = DeviceObject->DeviceExtension;
BOOLEAN bRc = FALSE;
KIRQL irql;
if (AcquireLock) {
KeAcquireSpinLock(&pDevExt->ControlLock, &irql);
}
if ( !InterlockedCompareExchange(&pDevExt->DeviceRemoved, FALSE, FALSE) &&
InterlockedCompareExchange(&pDevExt->AcceptingRequests, TRUE, TRUE) &&
InterlockedCompareExchange((PULONG)&pDevExt->PnPState, PnPStateStarted, PnPStateStarted) &&
(CheckOpened ? InterlockedCompareExchange(&pDevExt->DeviceOpened, TRUE, TRUE) : TRUE)
)
{
bRc = TRUE;
}
#if defined(DBG)
else DbgDump(DBG_WRN|DBG_PNP, ("CanAcceptIoRequests = FALSE\n"));
#endif
if (AcquireLock) {
KeReleaseSpinLock(&pDevExt->ControlLock, irql);
}
return bRc;
}
BOOLEAN
IsWin9x(
VOID
)
/*++
Routine Description:
Determine whether or not we are running on Win9x (vs. NT).
Arguments:
Return Value:
TRUE iff we're running on Win9x.
--*/
{
OBJECT_ATTRIBUTES objectAttributes;
UNICODE_STRING keyName;
HANDLE hKey;
NTSTATUS status;
BOOLEAN result;
PAGED_CODE();
/*
* Try to open the COM Name Arbiter, which exists only on NT.
*/
RtlInitUnicodeString(&keyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\COM Name Arbiter");
InitializeObjectAttributes( &objectAttributes,
&keyName,
OBJ_CASE_INSENSITIVE,
NULL,
(PSECURITY_DESCRIPTOR)NULL);
status = ZwOpenKey(&hKey, KEY_QUERY_VALUE, &objectAttributes);
if (NT_SUCCESS(status)){
status = ZwClose(hKey);
ASSERT(NT_SUCCESS(status));
result = FALSE;
}
else {
result = TRUE;
}
return result;
}
VOID
LogError(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
IN ULONG SequenceNumber,
IN UCHAR MajorFunctionCode,
IN UCHAR RetryCount,
IN ULONG UniqueErrorValue,
IN NTSTATUS FinalStatus,
IN NTSTATUS SpecificIOStatus,
IN ULONG LengthOfInsert1,
IN PWCHAR Insert1,
IN ULONG LengthOfInsert2,
IN PWCHAR Insert2
)
/*++
Routine Description:
Stolen from serial.sys
This routine allocates an error log entry, copies the supplied data
to it, and requests that it be written to the error log file.
Arguments:
DriverObject - A pointer to the driver object for the device.
DeviceObject - A pointer to the device object associated with the
device that had the error, early in initialization, one may not
yet exist.
SequenceNumber - A ulong value that is unique to an IRP over the
life of the irp in this driver - 0 generally means an error not
associated with an irp.
MajorFunctionCode - If there is an error associated with the irp,
this is the major function code of that irp.
RetryCount - The number of times a particular operation has been
retried.
UniqueErrorValue - A unique long word that identifies the particular
call to this function.
FinalStatus - The final status given to the irp that was associated
with this error. If this log entry is being made during one of
the retries this value will be STATUS_SUCCESS.
SpecificIOStatus - The IO status for a particular error.
LengthOfInsert1 - The length in bytes (including the terminating NULL)
of the first insertion string.
Insert1 - The first insertion string.
LengthOfInsert2 - The length in bytes (including the terminating NULL)
of the second insertion string. NOTE, there must
be a first insertion string for their to be
a second insertion string.
Insert2 - The second insertion string.
Return Value:
None.
--*/
{
PIO_ERROR_LOG_PACKET errorLogEntry;
PVOID objectToUse = NULL;
SHORT dumpToAllocate = 0;
PUCHAR ptrToFirstInsert = NULL;
PUCHAR ptrToSecondInsert = NULL;
PAGED_CODE();
DbgDump(DBG_ERR, (">LogError\n"));
if (Insert1 == NULL) {
LengthOfInsert1 = 0;
}
if (Insert2 == NULL) {
LengthOfInsert2 = 0;
}
if (ARGUMENT_PRESENT(DeviceObject)) {
objectToUse = DeviceObject;
} else if (ARGUMENT_PRESENT(DriverObject)) {
objectToUse = DriverObject;
}
errorLogEntry = IoAllocateErrorLogEntry(
objectToUse,
(UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
dumpToAllocate
+ LengthOfInsert1 +
LengthOfInsert2)
);
if ( errorLogEntry != NULL ) {
errorLogEntry->ErrorCode = SpecificIOStatus;
errorLogEntry->SequenceNumber = SequenceNumber;
errorLogEntry->MajorFunctionCode = MajorFunctionCode;
errorLogEntry->RetryCount = RetryCount;
errorLogEntry->UniqueErrorValue = UniqueErrorValue;
errorLogEntry->FinalStatus = FinalStatus;
errorLogEntry->DumpDataSize = dumpToAllocate;
ptrToFirstInsert = (PUCHAR)&errorLogEntry->DumpData[0];
ptrToSecondInsert = ptrToFirstInsert + LengthOfInsert1;
if (LengthOfInsert1) {
errorLogEntry->NumberOfStrings = 1;
errorLogEntry->StringOffset = (USHORT)(ptrToFirstInsert -
(PUCHAR)errorLogEntry);
RtlCopyMemory(
ptrToFirstInsert,
Insert1,
LengthOfInsert1
);
if (LengthOfInsert2) {
errorLogEntry->NumberOfStrings = 2;
RtlCopyMemory(
ptrToSecondInsert,
Insert2,
LengthOfInsert2
);
}
}
IoWriteErrorLogEntry(errorLogEntry);
}
DbgDump(DBG_ERR, ("<LogError\n"));
return;
}
#if defined(DBG)
PCHAR
PnPMinorFunctionString (
UCHAR MinorFunction
)
{
switch (MinorFunction) {
case IRP_MN_START_DEVICE:
return "IRP_MN_START_DEVICE";
case IRP_MN_QUERY_REMOVE_DEVICE:
return "IRP_MN_QUERY_REMOVE_DEVICE";
case IRP_MN_REMOVE_DEVICE:
return "IRP_MN_REMOVE_DEVICE";
case IRP_MN_CANCEL_REMOVE_DEVICE:
return "IRP_MN_CANCEL_REMOVE_DEVICE";
case IRP_MN_STOP_DEVICE:
return "IRP_MN_STOP_DEVICE";
case IRP_MN_QUERY_STOP_DEVICE:
return "IRP_MN_QUERY_STOP_DEVICE";
case IRP_MN_CANCEL_STOP_DEVICE:
return "IRP_MN_CANCEL_STOP_DEVICE";
case IRP_MN_QUERY_DEVICE_RELATIONS:
return "IRP_MN_QUERY_DEVICE_RELATIONS";
case IRP_MN_QUERY_INTERFACE:
return "IRP_MN_QUERY_INTERFACE";
case IRP_MN_QUERY_CAPABILITIES:
return "IRP_MN_QUERY_CAPABILITIES";
case IRP_MN_QUERY_RESOURCES:
return "IRP_MN_QUERY_RESOURCES";
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
return "IRP_MN_QUERY_RESOURCE_REQUIREMENTS";
case IRP_MN_QUERY_DEVICE_TEXT:
return "IRP_MN_QUERY_DEVICE_TEXT";
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
return "IRP_MN_FILTER_RESOURCE_REQUIREMENTS";
case IRP_MN_READ_CONFIG:
return "IRP_MN_READ_CONFIG";
case IRP_MN_WRITE_CONFIG:
return "IRP_MN_WRITE_CONFIG";
case IRP_MN_EJECT:
return "IRP_MN_EJECT";
case IRP_MN_SET_LOCK:
return "IRP_MN_SET_LOCK";
case IRP_MN_QUERY_ID:
return "IRP_MN_QUERY_ID";
case IRP_MN_QUERY_PNP_DEVICE_STATE:
return "IRP_MN_QUERY_PNP_DEVICE_STATE";
case IRP_MN_QUERY_BUS_INFORMATION:
return "IRP_MN_QUERY_BUS_INFORMATION";
case IRP_MN_DEVICE_USAGE_NOTIFICATION:
return "IRP_MN_DEVICE_USAGE_NOTIFICATION";
case IRP_MN_SURPRISE_REMOVAL:
return "IRP_MN_SURPRISE_REMOVAL";
default:
return ((PCHAR)("unknown IRP_MN_ 0x%x\n", MinorFunction));
}
}
#endif
// EOF