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.
3819 lines
112 KiB
3819 lines
112 KiB
/*--------------------------------------------------------------------------
|
|
*
|
|
* Copyright (C) Cyclades Corporation, 1999-2001.
|
|
* All rights reserved.
|
|
*
|
|
* Cyclom-Y Port Driver
|
|
*
|
|
* This file: cyypnp.c
|
|
*
|
|
* Description: This module contains the code that handles the
|
|
* plug and play IRPs for the Cyclom-Y Port driver.
|
|
*
|
|
* Notes: This code supports Windows 2000 and Windows XP,
|
|
* x86 and IA64 processors.
|
|
*
|
|
* Complies with Cyclades SW Coding Standard rev 1.3.
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
|
|
/*-------------------------------------------------------------------------
|
|
*
|
|
* Change History
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
* Initial implementation based on Microsoft sample code.
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
|
|
#define ALLF 0xffffffff
|
|
|
|
static const PHYSICAL_ADDRESS CyyPhysicalZero = {0};
|
|
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGESRP0, CyyCreateDevObj)
|
|
#pragma alloc_text(PAGESRP0, CyyAddDevice)
|
|
#pragma alloc_text(PAGESRP0, CyyPnpDispatch)
|
|
#pragma alloc_text(PAGESRP0, CyyStartDevice)
|
|
// REMOVED FANNY #pragma alloc_text(PAGESRP0, CyyFinishStartDevice)
|
|
// REMOVED FANNY #pragma alloc_text(PAGESRP0, CyyGetPortInfo)
|
|
#pragma alloc_text(PAGESRP0, CyyDoExternalNaming)
|
|
#pragma alloc_text(PAGESRP0, CyyReportMaxBaudRate)
|
|
// REMOVED FANNY. NOT CALLED.#pragma alloc_text(PAGESRP0, CyyControllerCallBack)
|
|
// REMOVED FANNY #pragma alloc_text(PAGESRP0, CyyItemCallBack)
|
|
#pragma alloc_text(PAGESRP0, CyyUndoExternalNaming)
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
//
|
|
// Instantiate the GUID
|
|
//
|
|
|
|
#if !defined(FAR)
|
|
#define FAR
|
|
#endif // !defined(FAR)
|
|
|
|
#include <initguid.h>
|
|
|
|
DEFINE_GUID(GUID_CLASS_COMPORT, 0x86e0d1e0L, 0x8089, 0x11d0, 0x9c, 0xe4, 0x08,
|
|
0x00, 0x3e, 0x30, 0x1f, 0x73);
|
|
|
|
|
|
#if DBG
|
|
|
|
UCHAR *CyySystemCapString[] = {
|
|
"PowerSystemUnspecified",
|
|
"PowerSystemWorking",
|
|
"PowerSystemSleeping1",
|
|
"PowerSystemSleeping2",
|
|
"PowerSystemSleeping3",
|
|
"PowerSystemHibernate",
|
|
"PowerSystemShutdown",
|
|
"PowerSystemMaximum"
|
|
};
|
|
|
|
UCHAR *CyyDeviceCapString[] = {
|
|
"PowerDeviceUnspecified",
|
|
"PowerDeviceD0",
|
|
"PowerDeviceD1",
|
|
"PowerDeviceD2",
|
|
"PowerDeviceD3",
|
|
"PowerDeviceMaximum"
|
|
};
|
|
|
|
#endif // DBG
|
|
|
|
|
|
NTSTATUS
|
|
CyySyncCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp,
|
|
IN PKEVENT CyySyncEvent)
|
|
{
|
|
KeSetEvent(CyySyncEvent, IO_NO_INCREMENT, FALSE);
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
#if 0
|
|
ULONG
|
|
myatoi(PWCHAR pszInt)
|
|
{
|
|
int retval;
|
|
TCHAR cSave;
|
|
|
|
for (retval = 0; *pszInt; ++pszInt) {
|
|
if ((cSave = (TCHAR) (*pszInt - TEXT('0'))) > (TCHAR) 9)
|
|
break;
|
|
|
|
retval = (int) (retval * 10 + (int) cSave);
|
|
}
|
|
return (retval);
|
|
}
|
|
#endif
|
|
|
|
ULONG
|
|
CyyCompareString(PWCHAR PString1, PWCHAR PString2, ULONG Count)
|
|
{
|
|
do {
|
|
if (*PString1 || *PString2) {
|
|
if (*PString1 != *PString2) {
|
|
break;
|
|
}
|
|
PString1++;
|
|
PString2++;
|
|
Count--;
|
|
} else {
|
|
break;
|
|
}
|
|
} while (Count);
|
|
return (Count);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CyyCreateDevObj(IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PPdo,
|
|
OUT PDEVICE_OBJECT *NewDeviceObject)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will create and initialize a functional device object to
|
|
be attached to a Cyclom-Y controller PDO.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - a pointer to the driver object this is created under
|
|
NewDeviceObject - a location to store the pointer to the new device object
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if everything was successful
|
|
reason for failure otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING deviceObjName;
|
|
PDEVICE_OBJECT deviceObject = NULL;
|
|
PCYY_DEVICE_EXTENSION pDevExt;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
static ULONG currentInstance = 0;
|
|
UNICODE_STRING instanceStr;
|
|
WCHAR instanceNumberBuffer[20];
|
|
ULONG busNumber = 0xFFFFFFFF;
|
|
ULONG resultLength;
|
|
WCHAR hwID[100];
|
|
PWCHAR portNumberPtr;
|
|
INTERFACE_TYPE interfaceType;
|
|
ULONG numberToAppend;
|
|
//ULONG portNumber;
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
CyyDbgPrintEx(CYYTRACECALLS, "Enter CyyCreateDevObj\n");
|
|
|
|
// Find out if parent board is ISA or PCI
|
|
|
|
status = IoGetDeviceProperty (PPdo,
|
|
DevicePropertyLegacyBusType,
|
|
sizeof(interfaceType),
|
|
&interfaceType,
|
|
&resultLength);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
|
|
CyyLogError( DriverObject,NULL,CyyPhysicalZero,CyyPhysicalZero,0,0,0,0,
|
|
status,CYY_UNABLE_TO_GET_BUS_TYPE,0,NULL,0,NULL);
|
|
|
|
CyyDbgPrintEx(CYYERRORS,"CyyCreateDevObj: IoGetDeviceProperty LegacyBusType "
|
|
"failed (%x)\n",status);
|
|
|
|
return status;
|
|
}
|
|
|
|
if (interfaceType == PCIBus) {
|
|
|
|
// Get PCI slot number and port number to generate device name.
|
|
|
|
status = IoGetDeviceProperty (PPdo,
|
|
DevicePropertyBusNumber,
|
|
sizeof(busNumber),
|
|
&busNumber,
|
|
&resultLength);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
busNumber = 0xFFFFFFFF; // Just to make sure set it again
|
|
//CyyLogError( DriverObject,NULL,CyyPhysicalZero,CyyPhysicalZero,0,0,0,0,
|
|
// status,CYY_UNABLE_TO_GET_BUS_NUMBER,0,NULL,0,NULL);
|
|
|
|
CyyDbgPrintEx(CYYERRORS,"CyyCreateDevObj: IoGetDeviceProperty BusNumber "
|
|
"failed (%x)\n",status);
|
|
|
|
goto NoBusNumber;
|
|
}
|
|
|
|
status = IoGetDeviceProperty (PPdo,
|
|
DevicePropertyHardwareID,
|
|
sizeof(hwID),
|
|
hwID,
|
|
&resultLength);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
CyyLogError( DriverObject,NULL,CyyPhysicalZero,CyyPhysicalZero,0,0,0,0,
|
|
status,CYY_UNABLE_TO_GET_HW_ID,0,NULL,0,NULL);
|
|
|
|
CyyDbgPrintEx(CYYERRORS,"CyyCreateDevObj: IoGetDeviceProperty HardwareID "
|
|
"failed (%x)\n",status);
|
|
|
|
|
|
return status;
|
|
}
|
|
|
|
if (CyyCompareString(hwID,CYYPORT_PNP_ID_WSTR,sizeof(CYYPORT_PNP_ID_WSTR)/sizeof(WCHAR)-1)!=0) {
|
|
|
|
CyyLogError( DriverObject,NULL,CyyPhysicalZero,CyyPhysicalZero,0,0,0,0,
|
|
status,CYY_BAD_HW_ID,0,NULL,0,NULL);
|
|
|
|
CyyDbgPrintEx(CYYERRORS,"CyyCreateDevObj: Bad HardwareID: %ws\n",hwID);
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
portNumberPtr = hwID+sizeof(CYYPORT_PNP_ID_WSTR)/sizeof(WCHAR)-1;
|
|
|
|
//portNumber = myatoi(portNumberPtr);
|
|
//if ((portNumber < 1) || (portNumber > CYY_MAX_PORTS)){
|
|
//
|
|
// CyyLogError( DriverObject,NULL,CyyPhysicalZero,CyyPhysicalZero,0,0,0,0,
|
|
// status,CYY_BAD_HW_ID,0,NULL,0,NULL);
|
|
//
|
|
// CyyDbgPrintEx (CYYERRORS,"CyyCreateDevObj: Bad HardwareID: %ws\n",hwID);
|
|
//
|
|
// return STATUS_UNSUCCESSFUL;
|
|
//}
|
|
|
|
NoBusNumber:;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Zero out allocated memory pointers so we know if they must be freed
|
|
//
|
|
|
|
RtlZeroMemory(&deviceObjName, sizeof(UNICODE_STRING));
|
|
|
|
deviceObjName.MaximumLength = DEVICE_OBJECT_NAME_LENGTH * sizeof(WCHAR);
|
|
deviceObjName.Buffer = ExAllocatePool(PagedPool, deviceObjName.MaximumLength
|
|
+ sizeof(WCHAR));
|
|
|
|
//********************************************
|
|
// Error Injection
|
|
// if (deviceObjName.Buffer != NULL) {
|
|
// ExFreePool(deviceObjName.Buffer);
|
|
// }
|
|
// deviceObjName.Buffer = NULL;
|
|
//********************************************
|
|
if (deviceObjName.Buffer == NULL) {
|
|
CyyLogError(DriverObject, NULL, CyyPhysicalZero, CyyPhysicalZero,
|
|
0, 0, 0, 11, STATUS_SUCCESS, CYY_INSUFFICIENT_RESOURCES,
|
|
0, NULL, 0, NULL);
|
|
CyyDbgPrintEx(CYYERRORS,
|
|
"Couldn't allocate memory for device name\n");
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES; //STATUS_SUCCESS replaced in build 2128
|
|
|
|
}
|
|
|
|
RtlZeroMemory(deviceObjName.Buffer, deviceObjName.MaximumLength
|
|
+ sizeof(WCHAR));
|
|
|
|
RtlAppendUnicodeToString(&deviceObjName, L"\\Device\\");
|
|
|
|
if (busNumber == 0xFFFFFFFF) {
|
|
numberToAppend = currentInstance++;
|
|
} else {
|
|
numberToAppend = busNumber;
|
|
}
|
|
|
|
RtlInitUnicodeString(&instanceStr, NULL);
|
|
instanceStr.MaximumLength = sizeof(instanceNumberBuffer);
|
|
instanceStr.Buffer = instanceNumberBuffer;
|
|
RtlIntegerToUnicodeString(numberToAppend, 10, &instanceStr);
|
|
|
|
if (busNumber == 0xFFFFFFFF) {
|
|
// The device name is something like \Device\Cyyport1
|
|
RtlAppendUnicodeToString(&deviceObjName, L"CyyPort");
|
|
RtlAppendUnicodeStringToString(&deviceObjName, &instanceStr);
|
|
} else {
|
|
// The device name is something like \Device\Pci5Cyyport1
|
|
RtlAppendUnicodeToString(&deviceObjName, L"Pci");
|
|
RtlAppendUnicodeStringToString(&deviceObjName, &instanceStr);
|
|
RtlAppendUnicodeToString(&deviceObjName, L"CyyPort");
|
|
RtlAppendUnicodeToString(&deviceObjName,portNumberPtr);
|
|
}
|
|
|
|
|
|
//
|
|
// Create the device object
|
|
//
|
|
|
|
status = IoCreateDevice(DriverObject, sizeof(CYY_DEVICE_EXTENSION),
|
|
&deviceObjName, FILE_DEVICE_SERIAL_PORT,
|
|
FILE_DEVICE_SECURE_OPEN, TRUE, &deviceObject);
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
CyyLogError(DriverObject, NULL, CyyPhysicalZero, CyyPhysicalZero,
|
|
0, 0, 0, 0, STATUS_SUCCESS, CYY_DEVICE_CREATION_FAILURE,
|
|
0, NULL, 0, NULL);
|
|
CyyDbgPrintEx(CYYERRORS, "CyyAddDevice: Create device failed - %x "
|
|
"\n", status);
|
|
goto CyyCreateDevObjError;
|
|
}
|
|
|
|
ASSERT(deviceObject != NULL);
|
|
|
|
|
|
//
|
|
// The device object has a pointer to an area of non-paged
|
|
// pool allocated for this device. This will be the device
|
|
// extension. Zero it out.
|
|
//
|
|
|
|
pDevExt = deviceObject->DeviceExtension;
|
|
RtlZeroMemory(pDevExt, sizeof(CYY_DEVICE_EXTENSION));
|
|
|
|
//
|
|
// Initialize the count of IRP's pending
|
|
//
|
|
|
|
pDevExt->PendingIRPCnt = 1;
|
|
|
|
|
|
//
|
|
// Initialize the count of DPC's pending
|
|
//
|
|
|
|
pDevExt->DpcCount = 1;
|
|
|
|
//
|
|
// Allocate Pool and save the nt device name in the device extension.
|
|
//
|
|
|
|
pDevExt->DeviceName.Buffer =
|
|
ExAllocatePool(PagedPool, deviceObjName.Length + sizeof(WCHAR));
|
|
|
|
//******************************************
|
|
// Error Injection
|
|
// if (pDevExt->DeviceName.Buffer != NULL) {
|
|
// ExFreePool(pDevExt->DeviceName.Buffer);
|
|
// }
|
|
// pDevExt->DeviceName.Buffer = NULL;
|
|
//******************************************
|
|
if (!pDevExt->DeviceName.Buffer) {
|
|
|
|
CyyLogError(
|
|
DriverObject,
|
|
NULL,
|
|
CyyPhysicalZero,
|
|
CyyPhysicalZero,
|
|
0,
|
|
0,
|
|
0,
|
|
12,
|
|
STATUS_SUCCESS,
|
|
CYY_INSUFFICIENT_RESOURCES,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
CyyDbgPrintEx(CYYERRORS, "Couldn't allocate memory for DeviceName\n");
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto CyyCreateDevObjError;
|
|
}
|
|
|
|
pDevExt->DeviceName.MaximumLength = deviceObjName.Length
|
|
+ sizeof(WCHAR);
|
|
|
|
//
|
|
// Zero fill it.
|
|
//
|
|
|
|
RtlZeroMemory(pDevExt->DeviceName.Buffer,
|
|
pDevExt->DeviceName.MaximumLength);
|
|
|
|
RtlAppendUnicodeStringToString(&pDevExt->DeviceName, &deviceObjName);
|
|
|
|
pDevExt->NtNameForPort.Buffer = ExAllocatePool(PagedPool,
|
|
deviceObjName.MaximumLength);
|
|
|
|
if (pDevExt->NtNameForPort.Buffer == NULL) {
|
|
CyyLogError(
|
|
DriverObject,
|
|
NULL,
|
|
CyyPhysicalZero,
|
|
CyyPhysicalZero,
|
|
0,
|
|
0,
|
|
0,
|
|
13,
|
|
STATUS_SUCCESS,
|
|
CYY_INSUFFICIENT_RESOURCES,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
CyyDbgPrintEx(CYYERRORS, "CyyAddDevice: Cannot allocate memory for "
|
|
"NtName\n");
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto CyyCreateDevObjError;
|
|
}
|
|
|
|
pDevExt->NtNameForPort.MaximumLength = deviceObjName.MaximumLength;
|
|
RtlAppendUnicodeStringToString(&pDevExt->NtNameForPort,
|
|
&deviceObjName);
|
|
|
|
|
|
|
|
//
|
|
// Set up the device extension.
|
|
//
|
|
|
|
pDevExt->DeviceIsOpened = FALSE;
|
|
pDevExt->DeviceObject = deviceObject;
|
|
pDevExt->DriverObject = DriverObject;
|
|
pDevExt->PowerState = PowerDeviceD0;
|
|
|
|
//TODO FANNY: ADD TxFifoAmount?
|
|
pDevExt->TxFifoAmount = driverDefaults.TxFIFODefault;
|
|
//pDevExt->CreatedSymbolicLink = TRUE; Removed by Fanny
|
|
pDevExt->OwnsPowerPolicy = TRUE;
|
|
if (interfaceType == PCIBus) {
|
|
|
|
pDevExt->IsPci = 1;
|
|
pDevExt->PciSlot = busNumber;
|
|
}
|
|
//pDevExt->PortIndex = portNumber-1;
|
|
|
|
//TODO FANNY: SEE LATER IF WE NEED THE LISTS TO HANDLE INTERRUPT
|
|
// InitializeListHead(&pDevExt->CommonInterruptObject);
|
|
// InitializeListHead(&pDevExt->TopLevelSharers);
|
|
// InitializeListHead(&pDevExt->MultiportSiblings);
|
|
InitializeListHead(&pDevExt->AllDevObjs);
|
|
InitializeListHead(&pDevExt->ReadQueue);
|
|
InitializeListHead(&pDevExt->WriteQueue);
|
|
InitializeListHead(&pDevExt->MaskQueue);
|
|
InitializeListHead(&pDevExt->PurgeQueue);
|
|
InitializeListHead(&pDevExt->StalledIrpQueue);
|
|
|
|
ExInitializeFastMutex(&pDevExt->OpenMutex);
|
|
ExInitializeFastMutex(&pDevExt->CloseMutex);
|
|
|
|
//
|
|
// Initialize the spinlock associated with fields read (& set)
|
|
// by IO Control functions and the flags spinlock.
|
|
//
|
|
|
|
KeInitializeSpinLock(&pDevExt->ControlLock);
|
|
KeInitializeSpinLock(&pDevExt->FlagsLock);
|
|
|
|
KeInitializeEvent(&pDevExt->PendingIRPEvent, SynchronizationEvent, FALSE);
|
|
KeInitializeEvent(&pDevExt->PendingDpcEvent, SynchronizationEvent, FALSE);
|
|
KeInitializeEvent(&pDevExt->PowerD0Event, SynchronizationEvent, FALSE);
|
|
|
|
|
|
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
*NewDeviceObject = deviceObject;
|
|
|
|
ExFreePool(deviceObjName.Buffer);
|
|
|
|
CyyDbgPrintEx(CYYTRACECALLS, "Leave CyyCreateDevObj\n");
|
|
return STATUS_SUCCESS;
|
|
|
|
|
|
CyyCreateDevObjError:
|
|
|
|
CyyDbgPrintEx(CYYERRORS, "CyyCreateDevObj Error, Cleaning up\n");
|
|
|
|
//
|
|
// Free the allocated strings for the NT and symbolic names if they exist.
|
|
//
|
|
|
|
if (deviceObjName.Buffer != NULL) {
|
|
ExFreePool(deviceObjName.Buffer);
|
|
}
|
|
|
|
if (deviceObject) {
|
|
|
|
if (pDevExt->NtNameForPort.Buffer != NULL) {
|
|
ExFreePool(pDevExt->NtNameForPort.Buffer);
|
|
}
|
|
|
|
if (pDevExt->DeviceName.Buffer != NULL) {
|
|
ExFreePool(pDevExt->DeviceName.Buffer);
|
|
}
|
|
|
|
IoDeleteDevice(deviceObject);
|
|
}
|
|
|
|
*NewDeviceObject = NULL;
|
|
|
|
CyyDbgPrintEx(CYYTRACECALLS, "Leave CyyCreateDevObj\n");
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CyyAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PPdo)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a functional device object for com ports in the
|
|
system and attaches them to the physical device objects for the ports
|
|
|
|
|
|
Arguments:
|
|
|
|
DriverObject - a pointer to the object for this driver
|
|
|
|
PPdo - a pointer to the PDO in the stack we need to attach to
|
|
|
|
Return Value:
|
|
|
|
status from device creation and initialization
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_OBJECT pNewDevObj = NULL;
|
|
PDEVICE_OBJECT pLowerDevObj = NULL;
|
|
NTSTATUS status;
|
|
PCYY_DEVICE_EXTENSION pDevExt;
|
|
|
|
PAGED_CODE();
|
|
|
|
CyyDbgPrintEx(CYYTRACECALLS, "Enter CyyAddDevice with PPdo 0x%x\n",
|
|
PPdo);
|
|
|
|
if (PPdo == NULL) {
|
|
//
|
|
// Return no more devices
|
|
//
|
|
CyyLogError(DriverObject, NULL, CyyPhysicalZero, CyyPhysicalZero,
|
|
0, 0, 0, 0, STATUS_SUCCESS, CYY_NO_PHYSICAL_DEVICE_OBJECT,
|
|
0, NULL, 0, NULL);
|
|
CyyDbgPrintEx(CYYERRORS, "CyyAddDevice: Enumeration request, "
|
|
"returning NO_MORE_ENTRIES\n");
|
|
|
|
return (STATUS_NO_MORE_ENTRIES);
|
|
}
|
|
|
|
//
|
|
// create and initialize the new device object
|
|
//
|
|
|
|
status = CyyCreateDevObj(DriverObject, PPdo, &pNewDevObj);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
CyyDbgPrintEx(CYYERRORS,
|
|
"CyyAddDevice - error creating new devobj [%#08lx]\n",
|
|
status);
|
|
return status;
|
|
}
|
|
|
|
|
|
//
|
|
// Layer our DO on top of the lower device object
|
|
// The return value is a pointer to the device object to which the
|
|
// DO is actually attached.
|
|
//
|
|
|
|
pLowerDevObj = IoAttachDeviceToDeviceStack(pNewDevObj, PPdo);
|
|
|
|
|
|
//
|
|
// No status. Do the best we can.
|
|
//
|
|
ASSERT(pLowerDevObj != NULL);
|
|
|
|
|
|
pDevExt = pNewDevObj->DeviceExtension;
|
|
pDevExt->LowerDeviceObject = pLowerDevObj;
|
|
pDevExt->Pdo = PPdo;
|
|
|
|
|
|
//
|
|
// Specify that this driver only supports buffered IO. This basically
|
|
// means that the IO system copies the users data to and from
|
|
// system supplied buffers.
|
|
//
|
|
// Also specify that we are power pagable.
|
|
//
|
|
|
|
pNewDevObj->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
|
|
|
|
CyyDbgPrintEx(CYYTRACECALLS, "Leave CyyAddDevice\n");
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CyyPnpDispatch(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a dispatch routine for the IRPs that come to the driver with the
|
|
IRP_MJ_PNP major code (plug-and-play IRPs).
|
|
|
|
Arguments:
|
|
|
|
PDevObj - Pointer to the device object for this device
|
|
|
|
PIrp - Pointer to the IRP for the current request
|
|
|
|
Return Value:
|
|
|
|
The function value is the final status of the call
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PCYY_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
|
|
PDEVICE_OBJECT pLowerDevObj = pDevExt->LowerDeviceObject;
|
|
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
|
|
NTSTATUS status;
|
|
PDEVICE_CAPABILITIES pDevCaps;
|
|
|
|
PAGED_CODE();
|
|
|
|
if ((status = CyyIRPPrologue(PIrp, pDevExt)) != STATUS_SUCCESS) {
|
|
CyyCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
switch (pIrpStack->MinorFunction) {
|
|
case IRP_MN_QUERY_CAPABILITIES: {
|
|
PKEVENT pQueryCapsEvent;
|
|
SYSTEM_POWER_STATE cap;
|
|
|
|
CyyDbgPrintEx(CYYPNPPOWER,
|
|
"Got IRP_MN_QUERY_DEVICE_CAPABILITIES IRP\n");
|
|
|
|
pQueryCapsEvent = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
|
|
|
|
if (pQueryCapsEvent == NULL) {
|
|
PIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
CyyCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
KeInitializeEvent(pQueryCapsEvent, SynchronizationEvent, FALSE);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(PIrp);
|
|
IoSetCompletionRoutine(PIrp, CyySyncCompletion, pQueryCapsEvent,
|
|
TRUE, TRUE, TRUE);
|
|
|
|
status = IoCallDriver(pLowerDevObj, PIrp);
|
|
|
|
|
|
//
|
|
// Wait for lower drivers to be done with the Irp
|
|
//
|
|
|
|
if (status == STATUS_PENDING) {
|
|
KeWaitForSingleObject(pQueryCapsEvent, Executive, KernelMode, FALSE,
|
|
NULL);
|
|
}
|
|
|
|
ExFreePool(pQueryCapsEvent);
|
|
|
|
status = PIrp->IoStatus.Status;
|
|
|
|
if (pIrpStack->Parameters.DeviceCapabilities.Capabilities == NULL) {
|
|
goto errQueryCaps;
|
|
}
|
|
|
|
//
|
|
// Save off their power capabilities
|
|
//
|
|
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Mapping power capabilities\n");
|
|
|
|
pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
|
|
|
|
pDevCaps = pIrpStack->Parameters.DeviceCapabilities.Capabilities;
|
|
|
|
for (cap = PowerSystemSleeping1; cap < PowerSystemMaximum;
|
|
cap++) {
|
|
#if DBG
|
|
CyyDbgPrintEx(CYYPNPPOWER, " %d: %s <--> %s\n",
|
|
cap, CyySystemCapString[cap],
|
|
CyyDeviceCapString[pDevCaps->DeviceState[cap]]);
|
|
#endif
|
|
|
|
pDevExt->DeviceStateMap[cap] = pDevCaps->DeviceState[cap];
|
|
}
|
|
|
|
pDevExt->DeviceStateMap[PowerSystemUnspecified]
|
|
= PowerDeviceUnspecified;
|
|
|
|
pDevExt->DeviceStateMap[PowerSystemWorking]
|
|
= PowerDeviceD0;
|
|
|
|
pDevExt->SystemWake = pDevCaps->SystemWake;
|
|
pDevExt->DeviceWake = pDevCaps->DeviceWake;
|
|
|
|
errQueryCaps:;
|
|
|
|
CyyCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|
//
|
|
// We just pass this down -- serenum enumerates our bus for us.
|
|
//
|
|
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Got IRP_MN_QUERY_DEVICE_RELATIONS Irp\n");
|
|
|
|
switch (pIrpStack->Parameters.QueryDeviceRelations.Type) {
|
|
case BusRelations:
|
|
CyyDbgPrintEx(CYYPNPPOWER, "------- BusRelations Query\n");
|
|
break;
|
|
|
|
case EjectionRelations:
|
|
CyyDbgPrintEx(CYYPNPPOWER, "------- EjectionRelations Query\n");
|
|
break;
|
|
|
|
case PowerRelations:
|
|
CyyDbgPrintEx(CYYPNPPOWER, "------- PowerRelations Query\n");
|
|
break;
|
|
|
|
case RemovalRelations:
|
|
CyyDbgPrintEx(CYYPNPPOWER, "------- RemovalRelations Query\n");
|
|
break;
|
|
|
|
case TargetDeviceRelation:
|
|
CyyDbgPrintEx(CYYPNPPOWER, "------- TargetDeviceRelation Query\n");
|
|
break;
|
|
|
|
default:
|
|
CyyDbgPrintEx(CYYPNPPOWER, "------- Unknown Query\n");
|
|
break;
|
|
}
|
|
|
|
IoSkipCurrentIrpStackLocation(PIrp);
|
|
status = CyyIoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
return status;
|
|
|
|
|
|
case IRP_MN_QUERY_INTERFACE:
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Got IRP_MN_QUERY_INTERFACE Irp\n");
|
|
break;
|
|
|
|
|
|
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Got IRP_MN_QUERY_RESOURCE_REQUIREMENTS Irp"
|
|
"\n");
|
|
break;
|
|
|
|
|
|
case IRP_MN_START_DEVICE: {
|
|
PVOID startLockPtr;
|
|
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Got IRP_MN_START_DEVICE Irp\n");
|
|
|
|
//
|
|
// CyyStartDevice will pass this Irp to the next driver,
|
|
// and process it as completion so just complete it here.
|
|
//
|
|
|
|
CyyLockPagableSectionByHandle(CyyGlobals.PAGESER_Handle);
|
|
|
|
//
|
|
// We used to make sure the stack was powered up, but now it
|
|
// is supposed to be done implicitly by start_device.
|
|
// If that wasn't the case we would just make this call:
|
|
//
|
|
//status = CyyGotoPowerState(PDevObj, pDevExt, PowerDeviceD0);
|
|
|
|
|
|
pDevExt->PowerState = PowerDeviceD0;
|
|
|
|
status = CyyStartDevice(PDevObj, PIrp);
|
|
|
|
(void)CyyGotoPowerState(PDevObj, pDevExt, PowerDeviceD3);
|
|
|
|
CyyUnlockPagableImageSection(CyyGlobals.PAGESER_Handle);
|
|
|
|
|
|
PIrp->IoStatus.Status = status;
|
|
|
|
CyyCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
|
|
case IRP_MN_READ_CONFIG:
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Got IRP_MN_READ_CONFIG Irp\n");
|
|
break;
|
|
|
|
|
|
case IRP_MN_WRITE_CONFIG:
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Got IRP_MN_WRITE_CONFIG Irp\n");
|
|
break;
|
|
|
|
|
|
case IRP_MN_EJECT:
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Got IRP_MN_EJECT Irp\n");
|
|
break;
|
|
|
|
|
|
case IRP_MN_SET_LOCK:
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Got IRP_MN_SET_LOCK Irp\n");
|
|
break;
|
|
|
|
|
|
case IRP_MN_QUERY_ID: {
|
|
UNICODE_STRING pIdBuf;
|
|
PWCHAR pPnpIdStr;
|
|
ULONG pnpIdStrLen;
|
|
ULONG portIndex = 0;
|
|
HANDLE pnpKey;
|
|
WCHAR WideString[MAX_DEVICE_ID_LEN];
|
|
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Got IRP_MN_QUERY_ID Irp\n");
|
|
|
|
// change from build 1946 to 2000.
|
|
if (pIrpStack->Parameters.QueryId.IdType != BusQueryHardwareIDs
|
|
&& pIrpStack->Parameters.QueryId.IdType != BusQueryCompatibleIDs) {
|
|
IoSkipCurrentIrpStackLocation(PIrp);
|
|
return CyyIoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
}
|
|
|
|
if (pIrpStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs) {
|
|
PIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoSkipCurrentIrpStackLocation(PIrp);
|
|
return CyyIoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
}
|
|
|
|
status = IoOpenDeviceRegistryKey(pDevExt->Pdo, PLUGPLAY_REGKEY_DEVICE,
|
|
STANDARD_RIGHTS_WRITE, &pnpKey);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
PIrp->IoStatus.Status = status;
|
|
|
|
CyyCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return status;
|
|
|
|
}
|
|
|
|
status = CyyGetRegistryKeyValue (pnpKey, L"PortIndex",
|
|
sizeof(L"PortIndex"),
|
|
&portIndex,
|
|
sizeof (ULONG));
|
|
|
|
ZwClose(pnpKey);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
PIrp->IoStatus.Status = status;
|
|
CyyCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
// pPnpIdStr = isMulti ? SERIAL_PNP_MULTI_ID_STR : SERIAL_PNP_ID_STR;
|
|
// pnpIdStrLen = isMulti ? sizeof(SERIAL_PNP_MULTI_ID_STR)
|
|
// : sizeof(SERIAL_PNP_ID_STR);
|
|
|
|
|
|
pnpIdStrLen = swprintf(WideString,L"%s%u",CYYPORT_PNP_ID_WSTR,portIndex+1);
|
|
pnpIdStrLen = pnpIdStrLen * sizeof(WCHAR) + sizeof(UNICODE_NULL);
|
|
pPnpIdStr = WideString;
|
|
|
|
if (PIrp->IoStatus.Information != 0) {
|
|
ULONG curStrLen;
|
|
ULONG allocLen = 0;
|
|
PWSTR curStr = (PWSTR)PIrp->IoStatus.Information;
|
|
|
|
//
|
|
// We have to walk the strings to count the amount of space to
|
|
// reallocate
|
|
//
|
|
|
|
while ((curStrLen = wcslen(curStr)) != 0) {
|
|
allocLen += curStrLen * sizeof(WCHAR) + sizeof(UNICODE_NULL);
|
|
curStr += curStrLen + 1;
|
|
}
|
|
|
|
allocLen += sizeof(UNICODE_NULL);
|
|
|
|
pIdBuf.Buffer = ExAllocatePool(PagedPool, allocLen
|
|
+ pnpIdStrLen
|
|
+ sizeof(WCHAR));
|
|
|
|
if (pIdBuf.Buffer == NULL) {
|
|
//
|
|
// Clean up after other drivers since we are
|
|
// sending the irp back up.
|
|
//
|
|
|
|
ExFreePool((PWSTR)PIrp->IoStatus.Information);
|
|
|
|
|
|
PIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
PIrp->IoStatus.Information = 0;
|
|
CyyCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
pIdBuf.MaximumLength = (USHORT)(allocLen + pnpIdStrLen);
|
|
pIdBuf.Length = (USHORT)allocLen - sizeof(UNICODE_NULL);
|
|
|
|
RtlZeroMemory(pIdBuf.Buffer, pIdBuf.MaximumLength + sizeof(WCHAR));
|
|
RtlCopyMemory(pIdBuf.Buffer, (PWSTR)PIrp->IoStatus.Information,
|
|
allocLen);
|
|
RtlAppendUnicodeToString(&pIdBuf, pPnpIdStr);
|
|
|
|
//
|
|
// Free what the previous driver allocated
|
|
//
|
|
|
|
ExFreePool((PWSTR)PIrp->IoStatus.Information);
|
|
|
|
|
|
} else {
|
|
|
|
CyyDbgPrintEx(CYYPNPPOWER, "ID is sole ID\n");
|
|
|
|
pIdBuf.Buffer = ExAllocatePool(PagedPool, pnpIdStrLen
|
|
+ sizeof(WCHAR) * 2);
|
|
|
|
if (pIdBuf.Buffer == NULL) {
|
|
PIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
PIrp->IoStatus.Information = 0;
|
|
CyyCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
pIdBuf.MaximumLength = (USHORT)pnpIdStrLen;
|
|
pIdBuf.Length = 0;
|
|
|
|
RtlZeroMemory(pIdBuf.Buffer, pIdBuf.MaximumLength + sizeof(WCHAR)
|
|
* 2);
|
|
|
|
RtlAppendUnicodeToString(&pIdBuf, pPnpIdStr);
|
|
}
|
|
|
|
PIrp->IoStatus.Information = (ULONG_PTR)pIdBuf.Buffer;
|
|
PIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(PIrp);
|
|
return CyyIoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
}
|
|
|
|
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: {
|
|
HANDLE pnpKey;
|
|
PKEVENT pResFiltEvent;
|
|
ULONG isMulti = 0;
|
|
PIO_RESOURCE_REQUIREMENTS_LIST pReqList;
|
|
PIO_RESOURCE_LIST pResList;
|
|
PIO_RESOURCE_DESCRIPTOR pResDesc;
|
|
ULONG i, j;
|
|
ULONG reqCnt;
|
|
ULONG gotRuntime;
|
|
ULONG gotMemory;
|
|
ULONG gotInt;
|
|
ULONG listNum;
|
|
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Got "
|
|
"IRP_MN_FILTER_RESOURCE_REQUIREMENTS Irp\n");
|
|
CyyDbgPrintEx(CYYPNPPOWER, "for device %x\n", pLowerDevObj);
|
|
|
|
|
|
pResFiltEvent = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
|
|
|
|
if (pResFiltEvent == NULL) {
|
|
PIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
CyyCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
KeInitializeEvent(pResFiltEvent, SynchronizationEvent, FALSE);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(PIrp);
|
|
IoSetCompletionRoutine(PIrp, CyySyncCompletion, pResFiltEvent,
|
|
TRUE, TRUE, TRUE);
|
|
|
|
status = IoCallDriver(pLowerDevObj, PIrp);
|
|
|
|
|
|
//
|
|
// Wait for lower drivers to be done with the Irp
|
|
//
|
|
|
|
if (status == STATUS_PENDING) {
|
|
KeWaitForSingleObject (pResFiltEvent, Executive, KernelMode, FALSE,
|
|
NULL);
|
|
}
|
|
|
|
ExFreePool(pResFiltEvent);
|
|
|
|
if (PIrp->IoStatus.Information == 0) {
|
|
if (pIrpStack->Parameters.FilterResourceRequirements
|
|
.IoResourceRequirementList == 0) {
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Can't filter NULL resources!\n");
|
|
status = PIrp->IoStatus.Status;
|
|
CyyCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
PIrp->IoStatus.Information = (ULONG_PTR)pIrpStack->Parameters
|
|
.FilterResourceRequirements
|
|
.IoResourceRequirementList;
|
|
|
|
}
|
|
|
|
// REMOVED FANNY
|
|
// status = IoOpenDeviceRegistryKey(pDevExt->Pdo, PLUGPLAY_REGKEY_DEVICE,
|
|
// STANDARD_RIGHTS_WRITE, &pnpKey);
|
|
//
|
|
// if (!NT_SUCCESS(status)) {
|
|
// PIrp->IoStatus.Status = status;
|
|
//
|
|
// CyyCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
// return status;
|
|
//
|
|
// }
|
|
//
|
|
// //
|
|
// // No matter what we add our filter if we can and return success.
|
|
// //
|
|
//
|
|
// status = CyyGetRegistryKeyValue (pnpKey, L"MultiportDevice",
|
|
// sizeof(L"MultiportDevice"),
|
|
// &isMulti,
|
|
// sizeof (ULONG));
|
|
//
|
|
// ZwClose(pnpKey);
|
|
|
|
//
|
|
// Force ISR ports in IO_RES_REQ_LIST to shared status
|
|
// Force interrupts to shared status
|
|
//
|
|
|
|
//
|
|
// We will only process the first list -- multiport boards
|
|
// should not have alternative resources
|
|
//
|
|
|
|
pReqList = (PIO_RESOURCE_REQUIREMENTS_LIST)PIrp->IoStatus.Information;
|
|
pResList = &pReqList->List[0];
|
|
|
|
CyyDbgPrintEx(CYYPNPPOWER, "List has %x lists (including "
|
|
"alternatives)\n", pReqList->AlternativeLists);
|
|
|
|
for (listNum = 0; listNum < (pReqList->AlternativeLists);
|
|
listNum++) {
|
|
gotRuntime = 0;
|
|
gotMemory = 0;
|
|
gotInt = 0;
|
|
|
|
CyyDbgPrintEx(CYYPNPPOWER, "List has %x resources in it\n",
|
|
pResList->Count);
|
|
|
|
for (j = 0; (j < pResList->Count); j++) {
|
|
pResDesc = &pResList->Descriptors[j];
|
|
|
|
switch (pResDesc->Type) {
|
|
case CmResourceTypeMemory:
|
|
if (pResDesc->u.Memory.Length == CYY_RUNTIME_LENGTH) {
|
|
gotRuntime = 1;
|
|
pResDesc->ShareDisposition = CmResourceShareShared;
|
|
//TODO FANNY: Which should be the ShareDisposition for Y?
|
|
//pResDesc->ShareDisposition = CmResourceShareDriverExclusive;
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Sharing Runtime Memory for "
|
|
"device %x\n", pLowerDevObj);
|
|
} else {
|
|
gotMemory = 1;
|
|
pResDesc->ShareDisposition = CmResourceShareShared;
|
|
//TODO FANNY: Which should be the ShareDisposition for Y?
|
|
//pResDesc->ShareDisposition = CmResourceShareDriverExclusive;
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Sharing Board Memory for "
|
|
"device %x\n", pLowerDevObj);
|
|
}
|
|
break;
|
|
|
|
case CmResourceTypePort:
|
|
CyyDbgPrintEx(CYYPNPPOWER, "------- We should not have Port resource\n");
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
gotInt = 1;
|
|
if (pDevExt->IsPci) {
|
|
pResDesc->ShareDisposition = CmResourceShareShared;
|
|
CyyDbgPrintEx(CYYPNPPOWER, "------- Sharing interrupt "
|
|
"for device %x\n",
|
|
pLowerDevObj);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If we found what we need, we can break out of the loop
|
|
//
|
|
|
|
if (gotRuntime && gotMemory && gotInt) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
pResList = (PIO_RESOURCE_LIST)((PUCHAR)pResList
|
|
+ sizeof(IO_RESOURCE_LIST)
|
|
+ sizeof(IO_RESOURCE_DESCRIPTOR)
|
|
* (pResList->Count - 1));
|
|
}
|
|
|
|
|
|
|
|
PIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
CyyCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
case IRP_MN_QUERY_PNP_DEVICE_STATE:
|
|
{
|
|
if (pDevExt->Flags & CYY_FLAGS_BROKENHW) {
|
|
(PNP_DEVICE_STATE)PIrp->IoStatus.Information |= PNP_DEVICE_FAILED;
|
|
|
|
PIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(PIrp);
|
|
return CyyIoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
}
|
|
|
|
case IRP_MN_STOP_DEVICE:
|
|
{
|
|
ULONG pendingIRPs;
|
|
KIRQL oldIrql;
|
|
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Got IRP_MN_STOP_DEVICE Irp ");
|
|
CyyDbgPrintEx(CYYPNPPOWER, "for device %x\n", pLowerDevObj);
|
|
|
|
|
|
//REMOVED FANNY FOR NOW
|
|
// ASSERT(!pDevExt->PortOnAMultiportCard);
|
|
|
|
|
|
CyySetFlags(pDevExt, CYY_FLAGS_STOPPED);
|
|
CyySetAccept(pDevExt,CYY_PNPACCEPT_STOPPED);
|
|
CyyClearAccept(pDevExt, CYY_PNPACCEPT_STOPPING);
|
|
|
|
pDevExt->PNPState = CYY_PNP_STOPPING;
|
|
|
|
//
|
|
// From this point on all non-PNP IRP's will be queued
|
|
//
|
|
|
|
//
|
|
// Decrement for entry here
|
|
//
|
|
|
|
InterlockedDecrement(&pDevExt->PendingIRPCnt);
|
|
|
|
//
|
|
// Decrement for stopping
|
|
//
|
|
|
|
pendingIRPs = InterlockedDecrement(&pDevExt->PendingIRPCnt);
|
|
|
|
if (pendingIRPs) {
|
|
KeWaitForSingleObject(&pDevExt->PendingIRPEvent, Executive,
|
|
KernelMode, FALSE, NULL);
|
|
}
|
|
|
|
//
|
|
// Re-increment the count for later
|
|
//
|
|
|
|
InterlockedIncrement(&pDevExt->PendingIRPCnt);
|
|
|
|
//
|
|
// We need to free resources...basically this is a remove
|
|
// without the detach from the stack.
|
|
//
|
|
|
|
if (pDevExt->Flags & CYY_FLAGS_STARTED) {
|
|
CyyReleaseResources(pDevExt);
|
|
}
|
|
|
|
//
|
|
// Pass the irp down
|
|
//
|
|
|
|
PIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoSkipCurrentIrpStackLocation(PIrp);
|
|
|
|
return IoCallDriver(pLowerDevObj, PIrp);
|
|
}
|
|
|
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|
{
|
|
KIRQL oldIrql;
|
|
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Got IRP_MN_QUERY_STOP_DEVICE Irp ");
|
|
CyyDbgPrintEx(CYYPNPPOWER, "for device %x\n", pLowerDevObj);
|
|
|
|
//
|
|
// See if we should succeed a stop query
|
|
//
|
|
|
|
// REMOVED FANNY FOR NOW
|
|
// if (pDevExt->PortOnAMultiportCard) {
|
|
// PIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
// CyyDbgPrintEx(CYYPNPPOWER, "------- failing; multiport node\n");
|
|
// CyyCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
// return STATUS_NOT_SUPPORTED;
|
|
// }
|
|
|
|
//
|
|
// If the device hasn't started yet, we ignore this request
|
|
// and just pass it down.
|
|
//
|
|
|
|
if (pDevExt->PNPState != CYY_PNP_STARTED) {
|
|
IoSkipCurrentIrpStackLocation(PIrp);
|
|
return CyyIoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
}
|
|
|
|
//
|
|
// Lock around the open status
|
|
//
|
|
|
|
ExAcquireFastMutex(&pDevExt->OpenMutex);
|
|
|
|
if (pDevExt->DeviceIsOpened) {
|
|
ExReleaseFastMutex(&pDevExt->OpenMutex);
|
|
PIrp->IoStatus.Status = STATUS_DEVICE_BUSY;
|
|
CyyDbgPrintEx(CYYPNPPOWER, "failing; device open\n");
|
|
CyyCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return STATUS_DEVICE_BUSY;
|
|
}
|
|
|
|
pDevExt->PNPState = CYY_PNP_QSTOP;
|
|
|
|
CyySetAccept(pDevExt, CYY_PNPACCEPT_STOPPING);
|
|
//
|
|
// Unlock around the open status
|
|
//
|
|
|
|
ExReleaseFastMutex(&pDevExt->OpenMutex);
|
|
|
|
PIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCopyCurrentIrpStackLocationToNext(PIrp);
|
|
return CyyIoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
}
|
|
|
|
case IRP_MN_CANCEL_STOP_DEVICE:
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Got IRP_MN_CANCEL_STOP_DEVICE Irp ");
|
|
CyyDbgPrintEx(CYYPNPPOWER, "for device %x\n", pLowerDevObj);
|
|
|
|
if (pDevExt->PNPState == CYY_PNP_QSTOP) {
|
|
//
|
|
// Restore the device state
|
|
//
|
|
|
|
pDevExt->PNPState = CYY_PNP_STARTED;
|
|
CyyClearAccept(pDevExt, CYY_PNPACCEPT_STOPPING);
|
|
}
|
|
|
|
PIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCopyCurrentIrpStackLocationToNext(PIrp);
|
|
return CyyIoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
|
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Got IRP_MN_CANCEL_REMOVE_DEVICE Irp ");
|
|
CyyDbgPrintEx(CYYPNPPOWER, "for device %x\n", pLowerDevObj);
|
|
|
|
//
|
|
// Restore the device state
|
|
//
|
|
|
|
pDevExt->PNPState = CYY_PNP_STARTED;
|
|
CyyClearAccept(pDevExt, CYY_PNPACCEPT_REMOVING);
|
|
|
|
PIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCopyCurrentIrpStackLocationToNext(PIrp);
|
|
return CyyIoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
|
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|
{
|
|
KIRQL oldIrql;
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Got IRP_MN_QUERY_REMOVE_DEVICE Irp ");
|
|
CyyDbgPrintEx(CYYPNPPOWER, "for device %x\n", pLowerDevObj);
|
|
|
|
ExAcquireFastMutex(&pDevExt->OpenMutex);
|
|
|
|
//
|
|
// See if we should succeed a remove query
|
|
//
|
|
|
|
if (pDevExt->DeviceIsOpened) {
|
|
ExReleaseFastMutex(&pDevExt->OpenMutex);
|
|
PIrp->IoStatus.Status = STATUS_DEVICE_BUSY;
|
|
CyyDbgPrintEx(CYYPNPPOWER, "failing; device open\n");
|
|
CyyCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return STATUS_DEVICE_BUSY;
|
|
}
|
|
|
|
pDevExt->PNPState = CYY_PNP_QREMOVE;
|
|
CyySetAccept(pDevExt, CYY_PNPACCEPT_REMOVING);
|
|
ExReleaseFastMutex(&pDevExt->OpenMutex);
|
|
|
|
PIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCopyCurrentIrpStackLocationToNext(PIrp);
|
|
return CyyIoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
}
|
|
|
|
case IRP_MN_SURPRISE_REMOVAL:
|
|
{
|
|
ULONG pendingIRPs;
|
|
KIRQL oldIrql;
|
|
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Got IRP_MN_SURPRISE_REMOVAL Irp ");
|
|
CyyDbgPrintEx(CYYPNPPOWER, "for device %x\n", pLowerDevObj);
|
|
|
|
//
|
|
// Prevent any new I/O to the device
|
|
//
|
|
|
|
CyySetAccept(pDevExt, CYY_PNPACCEPT_SURPRISE_REMOVING);
|
|
|
|
//
|
|
// Dismiss all pending requests
|
|
//
|
|
|
|
CyyKillPendingIrps(PDevObj);
|
|
|
|
//
|
|
// Wait for any pending requests we raced on.
|
|
//
|
|
|
|
//
|
|
// Decrement once for ourselves
|
|
//
|
|
|
|
InterlockedDecrement(&pDevExt->PendingIRPCnt);
|
|
|
|
//
|
|
// Decrement for the remove
|
|
//
|
|
|
|
pendingIRPs = InterlockedDecrement(&pDevExt->PendingIRPCnt);
|
|
|
|
if (pendingIRPs) {
|
|
KeWaitForSingleObject(&pDevExt->PendingIRPEvent, Executive,
|
|
KernelMode, FALSE, NULL);
|
|
}
|
|
|
|
//
|
|
// Reset for subsequent remove
|
|
//
|
|
|
|
InterlockedIncrement(&pDevExt->PendingIRPCnt);
|
|
|
|
//
|
|
// Remove any external interfaces and release resources
|
|
//
|
|
|
|
CyyDisableInterfacesResources(PDevObj, FALSE);
|
|
|
|
PIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoSkipCurrentIrpStackLocation(PIrp);
|
|
|
|
return CyyIoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
}
|
|
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
|
|
{
|
|
ULONG pendingIRPs;
|
|
KIRQL oldIrql;
|
|
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Got IRP_MN_REMOVE_DEVICE Irp ");
|
|
CyyDbgPrintEx(CYYPNPPOWER, "for device %x\n", pLowerDevObj);
|
|
|
|
//
|
|
// If we get this, we have to remove
|
|
//
|
|
|
|
//
|
|
// Mark as not accepting requests
|
|
//
|
|
|
|
CyySetAccept(pDevExt, CYY_PNPACCEPT_REMOVING);
|
|
|
|
//
|
|
// Complete all pending requests
|
|
//
|
|
|
|
CyyKillPendingIrps(PDevObj);
|
|
|
|
//
|
|
// Decrement for this Irp itself
|
|
//
|
|
|
|
InterlockedDecrement(&pDevExt->PendingIRPCnt);
|
|
|
|
//
|
|
// Wait for any pending requests we raced on -- this decrement
|
|
// is for our "placeholder".
|
|
//
|
|
|
|
pendingIRPs = InterlockedDecrement(&pDevExt->PendingIRPCnt);
|
|
|
|
if (pendingIRPs) {
|
|
KeWaitForSingleObject(&pDevExt->PendingIRPEvent, Executive,
|
|
KernelMode, FALSE, NULL);
|
|
}
|
|
|
|
if (!(pDevExt->DevicePNPAccept & CYY_PNPACCEPT_SURPRISE_REMOVING)) { //Moved from CyyRemoveDevice. Fanny
|
|
//
|
|
// Disable all external interfaces and release resources
|
|
//
|
|
|
|
CyyDisableInterfacesResources(PDevObj, TRUE);
|
|
}
|
|
|
|
//
|
|
// Pass the irp down
|
|
//
|
|
|
|
PIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
IoSkipCurrentIrpStackLocation(PIrp); // It was IoCopyCurrentIrpStackLocationToNext (Fanny)
|
|
|
|
//
|
|
// We do decrement here because we incremented on entry here.
|
|
//
|
|
|
|
status = IoCallDriver(pLowerDevObj, PIrp);
|
|
|
|
|
|
//
|
|
// Remove us (Note from Fanny: This call is before IoCallDriver in serial driver).
|
|
//
|
|
|
|
CyyRemoveDevObj(PDevObj);
|
|
|
|
return status;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
|
|
|
|
|
|
} // switch (pIrpStack->MinorFunction)
|
|
|
|
//
|
|
// Pass to driver beneath us
|
|
//
|
|
|
|
IoSkipCurrentIrpStackLocation(PIrp);
|
|
status = CyyIoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
return status;
|
|
|
|
|
|
}
|
|
|
|
|
|
UINT32
|
|
CyyReportMaxBaudRate(ULONG Bauds)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the max baud rate given a selection of rates
|
|
|
|
Arguments:
|
|
|
|
Bauds - Bit-encoded list of supported bauds
|
|
|
|
|
|
Return Value:
|
|
|
|
The max baud rate listed in Bauds
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (Bauds & SERIAL_BAUD_128K) {
|
|
return (128U * 1024U);
|
|
}
|
|
|
|
if (Bauds & SERIAL_BAUD_115200) {
|
|
return 115200U;
|
|
}
|
|
|
|
if (Bauds & SERIAL_BAUD_56K) {
|
|
return (56U * 1024U);
|
|
}
|
|
|
|
if (Bauds & SERIAL_BAUD_57600) {
|
|
return 57600U;
|
|
}
|
|
|
|
if (Bauds & SERIAL_BAUD_38400) {
|
|
return 38400U;
|
|
}
|
|
|
|
if (Bauds & SERIAL_BAUD_19200) {
|
|
return 19200U;
|
|
}
|
|
|
|
if (Bauds & SERIAL_BAUD_14400) {
|
|
return 14400U;
|
|
}
|
|
|
|
if (Bauds & SERIAL_BAUD_9600) {
|
|
return 9600U;
|
|
}
|
|
|
|
if (Bauds & SERIAL_BAUD_7200) {
|
|
return 7200U;
|
|
}
|
|
|
|
if (Bauds & SERIAL_BAUD_4800) {
|
|
return 4800U;
|
|
}
|
|
|
|
if (Bauds & SERIAL_BAUD_2400) {
|
|
return 2400U;
|
|
}
|
|
|
|
if (Bauds & SERIAL_BAUD_1800) {
|
|
return 1800U;
|
|
}
|
|
|
|
if (Bauds & SERIAL_BAUD_1200) {
|
|
return 1200U;
|
|
}
|
|
|
|
if (Bauds & SERIAL_BAUD_600) {
|
|
return 600U;
|
|
}
|
|
|
|
if (Bauds & SERIAL_BAUD_300) {
|
|
return 300U;
|
|
}
|
|
|
|
if (Bauds & SERIAL_BAUD_150) {
|
|
return 150U;
|
|
}
|
|
|
|
if (Bauds & SERIAL_BAUD_134_5) {
|
|
return 135U; // Close enough
|
|
}
|
|
|
|
if (Bauds & SERIAL_BAUD_110) {
|
|
return 110U;
|
|
}
|
|
|
|
if (Bauds & SERIAL_BAUD_075) {
|
|
return 75U;
|
|
}
|
|
|
|
//
|
|
// We're in bad shape
|
|
//
|
|
|
|
return 0;
|
|
}
|
|
|
|
VOID
|
|
CyyAddToAllDevs(PLIST_ENTRY PListEntry)
|
|
{
|
|
KIRQL oldIrql;
|
|
|
|
KeAcquireSpinLock(&CyyGlobals.GlobalsSpinLock, &oldIrql);
|
|
|
|
InsertTailList(&CyyGlobals.AllDevObjs, PListEntry);
|
|
|
|
KeReleaseSpinLock(&CyyGlobals.GlobalsSpinLock, oldIrql);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
CyyFinishStartDevice(IN PDEVICE_OBJECT PDevObj,
|
|
IN PCM_RESOURCE_LIST PResList,
|
|
IN PCM_RESOURCE_LIST PTrResList)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine does serial-specific procedures to start a device. It
|
|
does this either for a legacy device detected by its registry entries,
|
|
or for a PnP device after the start IRP has been sent down the stack.
|
|
|
|
|
|
Arguments:
|
|
|
|
PDevObj - Pointer to the devobj that is starting
|
|
|
|
PResList - Pointer to the untranslated resources needed by this device
|
|
|
|
PTrResList - Pointer to the translated resources needed by this device
|
|
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS on success, something else appropriate on failure
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PCYY_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
|
|
NTSTATUS status;
|
|
PCONFIG_DATA pConfig;
|
|
HANDLE pnpKey;
|
|
ULONG one = 1;
|
|
BOOLEAN allocedUserData = FALSE; // Added in build 2128
|
|
KIRQL oldIrql;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// See if this is a restart, and if so don't reallocate the world
|
|
//
|
|
|
|
if ((pDevExt->Flags & CYY_FLAGS_STOPPED)
|
|
&& (pDevExt->Flags & CYY_FLAGS_STARTED)) { // change from 1946 to 2000
|
|
CyyClearFlags(pDevExt, CYY_FLAGS_STOPPED);
|
|
|
|
pDevExt->PNPState = CYY_PNP_RESTARTING;
|
|
|
|
//
|
|
// Re-init resource-related things in the extension
|
|
//
|
|
|
|
pDevExt->OurIsr = NULL;
|
|
pDevExt->OurIsrContext = NULL;
|
|
pDevExt->Interrupt = NULL;
|
|
pDevExt->Vector = 0;
|
|
pDevExt->Irql = 0;
|
|
pDevExt->OriginalVector = 0;
|
|
pDevExt->OriginalIrql = 0;
|
|
pDevExt->BusNumber = 0;
|
|
pDevExt->InterfaceType = 0;
|
|
|
|
#if 0
|
|
// removed for now - fanny
|
|
// pDevExt->TopLevelOurIsr = NULL;
|
|
// pDevExt->TopLevelOurIsrContext = NULL;
|
|
//
|
|
// pDevExt->OriginalController = CyyPhysicalZero;
|
|
// pDevExt->OriginalInterruptStatus = CyyPhysicalZero;
|
|
//
|
|
//
|
|
// pDevExt->Controller = NULL;
|
|
// pDevExt->InterruptStatus = NULL;
|
|
//
|
|
// pDevExt->SpanOfController = 0;
|
|
// pDevExt->SpanOfInterruptStatus = 0;
|
|
//
|
|
// pDevExt->Vector = 0;
|
|
// pDevExt->Irql = 0;
|
|
// pDevExt->OriginalVector = 0;
|
|
// pDevExt->OriginalIrql = 0;
|
|
// pDevExt->AddressSpace = 0;
|
|
// pDevExt->BusNumber = 0;
|
|
// pDevExt->InterfaceType = 0;
|
|
//
|
|
// pDevExt->CIsrSw = NULL;
|
|
//
|
|
// ASSERT(PUserData == NULL);
|
|
//
|
|
// PUserData = ExAllocatePool(PagedPool, sizeof(CYY_USER_DATA));
|
|
//
|
|
// if (PUserData == NULL) {
|
|
// return STATUS_INSUFFICIENT_RESOURCES;
|
|
// }
|
|
//
|
|
// allocedUserData = TRUE; // Added in build 2128
|
|
//
|
|
// RtlZeroMemory(PUserData, sizeof(CYY_USER_DATA));
|
|
//
|
|
// PUserData->DisablePort = FALSE;
|
|
// PUserData->UserClockRate = pDevExt->ClockRate;
|
|
// PUserData->TxFIFO = pDevExt->TxFifoAmount;
|
|
// PUserData->PermitShareDefault = pDevExt->PermitShare;
|
|
//
|
|
//
|
|
// //
|
|
// // Map betweeen trigger and amount
|
|
// //
|
|
//
|
|
// switch (pDevExt->RxFifoTrigger) {
|
|
// case CYY_1_BYTE_HIGH_WATER:
|
|
// PUserData->RxFIFO = 1;
|
|
// break;
|
|
//
|
|
// case CYY_4_BYTE_HIGH_WATER:
|
|
// PUserData->RxFIFO = 4;
|
|
// break;
|
|
//
|
|
// case CYY_8_BYTE_HIGH_WATER:
|
|
// PUserData->RxFIFO = 8;
|
|
// break;
|
|
//
|
|
// case CYY_14_BYTE_HIGH_WATER:
|
|
// PUserData->RxFIFO = 14;
|
|
// break;
|
|
//
|
|
// default:
|
|
// PUserData->RxFIFO = 1;
|
|
// }
|
|
#endif // end removal of code
|
|
} else {
|
|
//
|
|
// Mark as serenumerable -- toss status because we can
|
|
// still start without this key.
|
|
//
|
|
|
|
status = IoOpenDeviceRegistryKey(pDevExt->Pdo,
|
|
PLUGPLAY_REGKEY_DEVICE,
|
|
STANDARD_RIGHTS_WRITE, &pnpKey);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
ULONG powerPolicy = 0;
|
|
|
|
//
|
|
// Find out if we own power policy
|
|
//
|
|
|
|
CyyGetRegistryKeyValue(pnpKey, L"CyyRelinquishPowerPolicy",
|
|
sizeof(L"CyyRelinquishPowerPolicy"),
|
|
&powerPolicy, sizeof(ULONG));
|
|
|
|
pDevExt->OwnsPowerPolicy = powerPolicy ? FALSE : TRUE;
|
|
|
|
|
|
ZwClose(pnpKey);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate the config record.
|
|
//
|
|
|
|
pConfig = ExAllocatePool (PagedPool, sizeof(CONFIG_DATA));
|
|
|
|
//************************************
|
|
// Error Injection
|
|
//if (pConfig) {
|
|
// ExFreePool (pConfig);
|
|
//}
|
|
//pConfig = NULL;
|
|
//************************************
|
|
if (pConfig == NULL) {
|
|
|
|
CyyLogError(pDevExt->DriverObject, NULL, CyyPhysicalZero,
|
|
CyyPhysicalZero, 0, 0, 0, 31, STATUS_SUCCESS,
|
|
CYY_INSUFFICIENT_RESOURCES, 0, NULL, 0, NULL);
|
|
|
|
CyyDbgPrintEx(CYYERRORS, "Couldn't allocate memory for the\n"
|
|
"------ user configuration record\n");
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto CyyFinishStartDeviceError;
|
|
}
|
|
|
|
RtlZeroMemory(pConfig, sizeof(CONFIG_DATA));
|
|
|
|
|
|
//
|
|
// Get the configuration info for the device.
|
|
//
|
|
|
|
status = CyyGetPortInfo(PDevObj, PResList, PTrResList, pConfig);
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
goto CyyFinishStartDeviceError;
|
|
}
|
|
|
|
//
|
|
// See if we are in the proper power state.
|
|
//
|
|
|
|
|
|
|
|
if (pDevExt->PowerState != PowerDeviceD0) {
|
|
|
|
status = CyyGotoPowerState(pDevExt->Pdo, pDevExt, PowerDeviceD0);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
goto CyyFinishStartDeviceError;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Find and initialize the controller
|
|
//
|
|
|
|
status = CyyFindInitController(PDevObj, pConfig);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
goto CyyFinishStartDeviceError;
|
|
}
|
|
|
|
|
|
//
|
|
// The hardware that is set up to NOT interrupt, connect an interrupt.
|
|
//
|
|
|
|
//
|
|
// If a device doesn't already have an interrupt and it has an isr then
|
|
// we attempt to connect to the interrupt if it is not shareing with other
|
|
// serial devices. If we fail to connect to an interrupt we will delete
|
|
// this device.
|
|
//
|
|
|
|
if (pDevExt != NULL) {
|
|
CyyDbgPrintEx(CYYDIAG5, "pDevExt: Interrupt %x\n"
|
|
"------- OurIsr %x\n", pDevExt->Interrupt,
|
|
pDevExt->OurIsr);
|
|
} else {
|
|
CyyDbgPrintEx(CYYERRORS, "CyyFinishStartDevice got NULL "
|
|
"pDevExt\n");
|
|
}
|
|
|
|
if ((!pDevExt->Interrupt) && (pDevExt->OurIsr)) {
|
|
|
|
CyyDbgPrintEx(CYYDIAG5,
|
|
"About to connect to interrupt for port %wZ\n"
|
|
"------- address of extension is %x\n",
|
|
&pDevExt->DeviceName, pDevExt);
|
|
|
|
CyyDbgPrintEx(CYYDIAG5, "IoConnectInterrupt Args:\n"
|
|
"Interrupt %x\n"
|
|
"OurIsr %x\n"
|
|
"OurIsrContext %x\n"
|
|
"NULL\n"
|
|
"Vector %x\n"
|
|
"Irql %x\n"
|
|
"InterruptMode %x\n"
|
|
"InterruptShareable %x\n"
|
|
"ProcessorAffinity %x\n"
|
|
"FALSE\n",
|
|
&pDevExt->Interrupt,
|
|
CyyIsr,
|
|
pDevExt->OurIsrContext,
|
|
pDevExt->Vector,
|
|
pDevExt->Irql,
|
|
pConfig->InterruptMode,
|
|
pDevExt->InterruptShareable,
|
|
pConfig->Affinity
|
|
);
|
|
|
|
//
|
|
// Do a just in time construction of the ISR switch.
|
|
//
|
|
//removed fanny
|
|
// pDevExt->CIsrSw->IsrFunc = pDevExt->OurIsr;
|
|
// pDevExt->CIsrSw->Context = pDevExt->OurIsrContext;
|
|
|
|
status = IoConnectInterrupt(&pDevExt->Interrupt, pDevExt->OurIsr,
|
|
pDevExt->OurIsrContext, NULL,
|
|
pDevExt->Vector, pDevExt->Irql,
|
|
pDevExt->Irql,
|
|
pConfig->InterruptMode,
|
|
pDevExt->InterruptShareable,
|
|
pConfig->Affinity, FALSE);
|
|
//****************************************
|
|
// Error Injection
|
|
// if (pDevExt->Interrupt != NULL) {
|
|
// IoDisconnectInterrupt(pDevExt->Interrupt);
|
|
// pDevExt->Interrupt = NULL;
|
|
// }
|
|
// status = STATUS_INSUFFICIENT_RESOURCES;
|
|
//****************************************
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// Hmmm, how'd that happen? Somebody either
|
|
// didn't report their resources, or they
|
|
// sneaked in since the last time I looked.
|
|
//
|
|
// Oh well, delete this device.
|
|
//
|
|
|
|
CyyDbgPrintEx(CYYERRORS, "Couldn't connect to interrupt for %wZ\n",
|
|
&pDevExt->DeviceName);
|
|
|
|
CyyDbgPrintEx(CYYERRORS, "IoConnectInterrupt Args:\n"
|
|
"Interrupt %x\n"
|
|
"OurIsr %x\n"
|
|
"OurIsrContext %x\n"
|
|
"NULL\n"
|
|
"Vector %x\n"
|
|
"Irql %x\n"
|
|
"InterruptMode %x\n"
|
|
"InterruptShareable %x\n"
|
|
"ProcessorAffinity %x\n"
|
|
"FALSE\n",
|
|
&pDevExt->Interrupt,
|
|
CyyIsr,
|
|
pDevExt->OurIsrContext,
|
|
pDevExt->Vector,
|
|
pDevExt->Irql,
|
|
pConfig->InterruptMode,
|
|
pDevExt->InterruptShareable,
|
|
pConfig->Affinity);
|
|
|
|
|
|
|
|
CyyLogError(PDevObj->DriverObject, PDevObj,
|
|
pDevExt->OriginalBoardMemory,
|
|
CyyPhysicalZero, 0, 0, 0, pDevExt->Vector, status,
|
|
CYY_UNREPORTED_IRQL_CONFLICT,
|
|
pDevExt->DeviceName.Length + sizeof(WCHAR),
|
|
pDevExt->DeviceName.Buffer, 0, NULL);
|
|
|
|
//status = CYY_UNREPORTED_IRQL_CONFLICT; Originally, it was SERIAL_UNREPORTED_IRQL_CONFLICT.
|
|
goto CyyFinishStartDeviceError;
|
|
|
|
}
|
|
|
|
CyyDbgPrintEx(CYYDIAG5, "Connected interrupt %08X\n", pDevExt->Interrupt);
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Add the PDevObj to the master list
|
|
//
|
|
|
|
CyyAddToAllDevs(&pDevExt->AllDevObjs);
|
|
|
|
|
|
//
|
|
// Reset the device.
|
|
//
|
|
|
|
//
|
|
// While the device isn't open, disable all interrupts.
|
|
//
|
|
CD1400_DISABLE_ALL_INTERRUPTS(pDevExt->Cd1400,pDevExt->IsPci,pDevExt->CdChannel);
|
|
|
|
//
|
|
// This should set up everything as it should be when
|
|
// a device is to be opened. We do need to lower the
|
|
// modem lines, and disable the recalcitrant fifo
|
|
// so that it will show up if the user boots to dos.
|
|
//
|
|
|
|
KeSynchronizeExecution(
|
|
pDevExt->Interrupt,
|
|
CyyReset,
|
|
pDevExt
|
|
);
|
|
|
|
KeSynchronizeExecution( //Disables the fifo.
|
|
pDevExt->Interrupt,
|
|
CyyMarkClose,
|
|
pDevExt
|
|
);
|
|
|
|
KeSynchronizeExecution(
|
|
pDevExt->Interrupt,
|
|
CyyClrRTS,
|
|
pDevExt
|
|
);
|
|
|
|
KeSynchronizeExecution(
|
|
pDevExt->Interrupt,
|
|
CyyClrDTR,
|
|
pDevExt
|
|
);
|
|
|
|
if (pDevExt->PNPState == CYY_PNP_ADDED ) {
|
|
//
|
|
// Do the external naming now that the device is accessible.
|
|
//
|
|
|
|
status = CyyDoExternalNaming(pDevExt, pDevExt->DeviceObject->
|
|
DriverObject);
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
CyyDbgPrintEx(CYYERRORS, "External Naming Failed - Status %x\n",
|
|
status);
|
|
|
|
//
|
|
// Allow the device to start anyhow
|
|
//
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
} else {
|
|
CyyDbgPrintEx(CYYPNPPOWER, "Not doing external naming -- state is %x"
|
|
"\n", pDevExt->PNPState);
|
|
}
|
|
|
|
CyyFinishStartDeviceError:;
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
|
|
CyyDbgPrintEx(CYYDIAG1, "Cleaning up failed start\n");
|
|
|
|
//
|
|
// Resources created by this routine will be cleaned up by the remove
|
|
//
|
|
|
|
if (pDevExt->PNPState == CYY_PNP_RESTARTING) {
|
|
//
|
|
// Kill all that lives and breathes -- we'll clean up the
|
|
// rest on the impending remove
|
|
//
|
|
|
|
CyyKillPendingIrps(PDevObj);
|
|
|
|
//
|
|
// In fact, pretend we're removing so we don't take any
|
|
// more irps
|
|
//
|
|
|
|
CyySetAccept(pDevExt, CYY_PNPACCEPT_REMOVING);
|
|
CyyClearFlags(pDevExt, CYY_FLAGS_STARTED);
|
|
}
|
|
} else { // SUCCESS
|
|
|
|
//
|
|
// Fill in WMI hardware data
|
|
//
|
|
|
|
pDevExt->WmiHwData.IrqNumber = pDevExt->Irql;
|
|
pDevExt->WmiHwData.IrqLevel = pDevExt->Irql;
|
|
pDevExt->WmiHwData.IrqVector = pDevExt->Vector;
|
|
pDevExt->WmiHwData.IrqAffinityMask = pConfig->Affinity;
|
|
pDevExt->WmiHwData.InterruptType = pConfig->InterruptMode == Latched
|
|
? SERIAL_WMI_INTTYPE_LATCHED : SERIAL_WMI_INTTYPE_LEVEL;
|
|
pDevExt->WmiHwData.BaseIOAddress = (ULONG_PTR)pDevExt->BoardMemory;
|
|
|
|
//
|
|
// Fill in WMI device state data (as defaults)
|
|
//
|
|
|
|
pDevExt->WmiCommData.BaudRate = pDevExt->CurrentBaud;
|
|
pDevExt->WmiCommData.BitsPerByte = (pDevExt->cor1 & COR1_DATA_MASK) + 5;
|
|
pDevExt->WmiCommData.ParityCheckEnable = (pDevExt->cor1 & COR1_PARITY_ENABLE_MASK)
|
|
? TRUE : FALSE;
|
|
|
|
switch (pDevExt->cor1 & COR1_PARITY_MASK) {
|
|
case COR1_NONE_PARITY:
|
|
pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_NONE;
|
|
break;
|
|
|
|
case COR1_ODD_PARITY:
|
|
pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_ODD;
|
|
break;
|
|
|
|
case COR1_EVEN_PARITY:
|
|
pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_EVEN;
|
|
break;
|
|
|
|
case COR1_MARK_PARITY:
|
|
pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_MARK;
|
|
break;
|
|
|
|
case COR1_SPACE_PARITY:
|
|
pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_SPACE;
|
|
break;
|
|
|
|
default:
|
|
ASSERTMSG(0, "CYYPORT: Illegal Parity setting for WMI");
|
|
pDevExt->WmiCommData.Parity = SERIAL_WMI_PARITY_NONE;
|
|
break;
|
|
}
|
|
|
|
switch(pDevExt->cor1 & COR1_STOP_MASK) {
|
|
case COR1_1_STOP:
|
|
pDevExt->WmiCommData.StopBits = SERIAL_WMI_STOP_1;
|
|
break;
|
|
case COR1_1_5_STOP:
|
|
pDevExt->WmiCommData.StopBits = SERIAL_WMI_STOP_1_5;
|
|
break;
|
|
case COR1_2_STOP:
|
|
pDevExt->WmiCommData.StopBits = SERIAL_WMI_STOP_2;
|
|
break;
|
|
default:
|
|
ASSERTMSG(0, "CYYPORT: Illegal Stop Bit setting for WMI");
|
|
pDevExt->WmiCommData.Parity = SERIAL_WMI_STOP_1;
|
|
break;
|
|
}
|
|
|
|
pDevExt->WmiCommData.XoffCharacter = pDevExt->SpecialChars.XoffChar;
|
|
pDevExt->WmiCommData.XoffXmitThreshold = pDevExt->HandFlow.XoffLimit;
|
|
pDevExt->WmiCommData.XonCharacter = pDevExt->SpecialChars.XonChar;
|
|
pDevExt->WmiCommData.XonXmitThreshold = pDevExt->HandFlow.XonLimit;
|
|
pDevExt->WmiCommData.MaximumBaudRate
|
|
= CyyReportMaxBaudRate(pDevExt->SupportedBauds);
|
|
pDevExt->WmiCommData.MaximumOutputBufferSize = (UINT32)((ULONG)-1);
|
|
pDevExt->WmiCommData.MaximumInputBufferSize = (UINT32)((ULONG)-1);
|
|
pDevExt->WmiCommData.Support16BitMode = FALSE;
|
|
pDevExt->WmiCommData.SupportDTRDSR = TRUE;
|
|
pDevExt->WmiCommData.SupportIntervalTimeouts = TRUE;
|
|
pDevExt->WmiCommData.SupportParityCheck = TRUE;
|
|
pDevExt->WmiCommData.SupportRTSCTS = TRUE;
|
|
pDevExt->WmiCommData.SupportXonXoff = TRUE;
|
|
pDevExt->WmiCommData.SettableBaudRate = TRUE;
|
|
pDevExt->WmiCommData.SettableDataBits = TRUE;
|
|
pDevExt->WmiCommData.SettableFlowControl = TRUE;
|
|
pDevExt->WmiCommData.SettableParity = TRUE;
|
|
pDevExt->WmiCommData.SettableParityCheck = TRUE;
|
|
pDevExt->WmiCommData.SettableStopBits = TRUE;
|
|
pDevExt->WmiCommData.IsBusy = FALSE;
|
|
|
|
//
|
|
// Fill in wmi perf data (all zero's)
|
|
//
|
|
|
|
RtlZeroMemory(&pDevExt->WmiPerfData, sizeof(pDevExt->WmiPerfData));
|
|
|
|
|
|
if (pDevExt->PNPState == CYY_PNP_ADDED) {
|
|
PULONG countSoFar = &IoGetConfigurationInformation()->SerialCount;
|
|
(*countSoFar)++;
|
|
|
|
//
|
|
// Register for WMI
|
|
//
|
|
|
|
pDevExt->WmiLibInfo.GuidCount = sizeof(SerialWmiGuidList) /
|
|
sizeof(WMIGUIDREGINFO);
|
|
pDevExt->WmiLibInfo.GuidList = SerialWmiGuidList;
|
|
ASSERT (pDevExt->WmiLibInfo.GuidCount == SERIAL_WMI_GUID_LIST_SIZE);
|
|
|
|
pDevExt->WmiLibInfo.QueryWmiRegInfo = CyyQueryWmiRegInfo;
|
|
pDevExt->WmiLibInfo.QueryWmiDataBlock = CyyQueryWmiDataBlock;
|
|
pDevExt->WmiLibInfo.SetWmiDataBlock = CyySetWmiDataBlock;
|
|
pDevExt->WmiLibInfo.SetWmiDataItem = CyySetWmiDataItem;
|
|
pDevExt->WmiLibInfo.ExecuteWmiMethod = NULL;
|
|
pDevExt->WmiLibInfo.WmiFunctionControl = NULL;
|
|
|
|
IoWMIRegistrationControl(PDevObj, WMIREG_ACTION_REGISTER);
|
|
|
|
}
|
|
|
|
if (pDevExt->PNPState == CYY_PNP_RESTARTING) {
|
|
//
|
|
// Release the stalled IRP's
|
|
//
|
|
|
|
CyyUnstallIrps(pDevExt);
|
|
}
|
|
|
|
pDevExt->PNPState = CYY_PNP_STARTED;
|
|
CyyClearAccept(pDevExt, ~CYY_PNPACCEPT_OK);
|
|
CyySetFlags(pDevExt, CYY_FLAGS_STARTED);
|
|
|
|
}
|
|
|
|
if (pConfig) {
|
|
ExFreePool (pConfig);
|
|
}
|
|
// REMOVED BY FANNY
|
|
// if ((PUserData != NULL)
|
|
// && (pDevExt->PNPState == CYY_PNP_RESTARTING)) {
|
|
// ExFreePool(PUserData);
|
|
// }
|
|
#if 0
|
|
if ((PUserData != NULL) && allocedUserData) { // Added in build 2128
|
|
ExFreePool(PUserData);
|
|
}
|
|
#endif
|
|
|
|
CyyDbgPrintEx (CYYTRACECALLS, "leaving CyyFinishStartDevice\n");
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CyyStartDevice(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine first passes the start device Irp down the stack then
|
|
it picks up the resources for the device, ititializes, puts it on any
|
|
appropriate lists (i.e shared interrupt or interrupt status) and
|
|
connects the interrupt.
|
|
|
|
Arguments:
|
|
|
|
PDevObj - Pointer to the device object for this device
|
|
|
|
PIrp - Pointer to the IRP for the current request
|
|
|
|
Return Value:
|
|
|
|
Return status
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
|
|
NTSTATUS status = STATUS_NOT_IMPLEMENTED;
|
|
PCYY_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
|
|
PDEVICE_OBJECT pLowerDevObj = pDevExt->LowerDeviceObject;
|
|
// Next: variables to get resources from the Registry
|
|
HANDLE keyHandle;
|
|
ULONG dataLength;
|
|
PCM_RESOURCE_LIST portResources = NULL;
|
|
PCM_RESOURCE_LIST portResourcesTr = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
CyyDbgPrintEx(CYYTRACECALLS, "entering CyyStartDevice\n");
|
|
|
|
|
|
//
|
|
// Pass this down to the next device object
|
|
//
|
|
|
|
KeInitializeEvent(&pDevExt->CyyStartEvent, SynchronizationEvent,
|
|
FALSE);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(PIrp);
|
|
IoSetCompletionRoutine(PIrp, CyySyncCompletion,
|
|
&pDevExt->CyyStartEvent, TRUE, TRUE, TRUE);
|
|
|
|
status = IoCallDriver(pLowerDevObj, PIrp);
|
|
|
|
|
|
//
|
|
// Wait for lower drivers to be done with the Irp
|
|
//
|
|
|
|
if (status == STATUS_PENDING) {
|
|
KeWaitForSingleObject (&pDevExt->CyyStartEvent, Executive, KernelMode,
|
|
FALSE, NULL);
|
|
|
|
status = PIrp->IoStatus.Status;
|
|
}
|
|
|
|
//*********************************
|
|
// Error Injection
|
|
// status = STATUS_UNSUCCESSFUL;
|
|
//*********************************
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
CyyDbgPrintEx(CYYERRORS, "error with IoCallDriver %x\n", status);
|
|
CyyLogError( pDevExt->DriverObject,NULL,
|
|
CyyPhysicalZero,CyyPhysicalZero,
|
|
0,0,0,0,status,CYY_LOWER_DRIVERS_FAILED_START,
|
|
0,NULL,0,NULL);
|
|
return status;
|
|
}
|
|
|
|
|
|
// Get resources from the registry
|
|
|
|
status = IoOpenDeviceRegistryKey (pDevExt->Pdo,
|
|
PLUGPLAY_REGKEY_DEVICE,
|
|
STANDARD_RIGHTS_READ,
|
|
&keyHandle);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
CyyDbgPrintEx(CYYERRORS, "IoOpenDeviceRegistryKey failed - %x "
|
|
"\n", status);
|
|
|
|
} else {
|
|
|
|
dataLength = CyyGetRegistryKeyValueLength (keyHandle,
|
|
L"PortResources",
|
|
sizeof(L"PortResources"));
|
|
|
|
portResources = ExAllocatePool(PagedPool, dataLength);
|
|
|
|
if (portResources) {
|
|
status = CyyGetRegistryKeyValue (keyHandle, L"PortResources",
|
|
sizeof(L"PortResources"),
|
|
portResources,
|
|
dataLength);
|
|
if (!NT_SUCCESS(status)) {
|
|
CyyDbgPrintEx(CYYERRORS, "CyyGetRegistryKeyValue PortResources "
|
|
"failed - %x\n", status);
|
|
goto CyyStartDevice_End;
|
|
}
|
|
|
|
}
|
|
dataLength = CyyGetRegistryKeyValueLength (keyHandle,
|
|
L"PortResourcesTr",
|
|
sizeof(L"PortResourcesTr"));
|
|
|
|
portResourcesTr = ExAllocatePool(PagedPool, dataLength);
|
|
|
|
if (portResourcesTr) {
|
|
status = CyyGetRegistryKeyValue (keyHandle, L"PortResourcesTr",
|
|
sizeof(L"PortResourcesTr"),
|
|
portResourcesTr,
|
|
dataLength);
|
|
if (!NT_SUCCESS(status)) {
|
|
CyyDbgPrintEx(CYYERRORS, "CyyGetRegistryKeyValue PortResourcesTr "
|
|
"failed - %x\n", status);
|
|
goto CyyStartDevice_End;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Do the serial specific items to start the device
|
|
//
|
|
status = CyyFinishStartDevice(PDevObj, portResources, portResourcesTr);
|
|
|
|
CyyStartDevice_End:
|
|
|
|
if (portResources) {
|
|
ExFreePool(portResources);
|
|
}
|
|
if (portResourcesTr) {
|
|
ExFreePool(portResourcesTr);
|
|
}
|
|
|
|
ZwClose (keyHandle);
|
|
|
|
}
|
|
|
|
|
|
#if 0
|
|
//
|
|
// Do the serial specific items to start the device
|
|
//
|
|
status = CyyFinishStartDevice(PDevObj, pIrpStack->Parameters.StartDevice
|
|
.AllocatedResources,
|
|
pIrpStack->Parameters.StartDevice
|
|
.AllocatedResourcesTranslated);
|
|
#endif
|
|
|
|
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CyyItemCallBack(
|
|
IN PVOID Context,
|
|
IN PUNICODE_STRING PathName,
|
|
IN INTERFACE_TYPE BusType,
|
|
IN ULONG BusNumber,
|
|
IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
|
|
IN CONFIGURATION_TYPE ControllerType,
|
|
IN ULONG ControllerNumber,
|
|
IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
|
|
IN CONFIGURATION_TYPE PeripheralType,
|
|
IN ULONG PeripheralNumber,
|
|
IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to check if a particular item
|
|
is present in the registry.
|
|
|
|
Arguments:
|
|
|
|
Context - Pointer to a boolean.
|
|
|
|
PathName - unicode registry path. Not Used.
|
|
|
|
BusType - Internal, Isa, ...
|
|
|
|
BusNumber - Which bus if we are on a multibus system.
|
|
|
|
BusInformation - Configuration information about the bus. Not Used.
|
|
|
|
ControllerType - Controller type.
|
|
|
|
ControllerNumber - Which controller if there is more than one
|
|
controller in the system.
|
|
|
|
ControllerInformation - Array of pointers to the three pieces of
|
|
registry information.
|
|
|
|
PeripheralType - Should be a peripheral.
|
|
|
|
PeripheralNumber - Which peripheral - not used..
|
|
|
|
PeripheralInformation - Configuration information. Not Used.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE();
|
|
|
|
*((BOOLEAN *)Context) = TRUE;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CyyControllerCallBack(
|
|
IN PVOID Context,
|
|
IN PUNICODE_STRING PathName,
|
|
IN INTERFACE_TYPE BusType,
|
|
IN ULONG BusNumber,
|
|
IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
|
|
IN CONFIGURATION_TYPE ControllerType,
|
|
IN ULONG ControllerNumber,
|
|
IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
|
|
IN CONFIGURATION_TYPE PeripheralType,
|
|
IN ULONG PeripheralNumber,
|
|
IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to check if a particular item
|
|
is present in the registry.
|
|
|
|
Arguments:
|
|
|
|
Context - Pointer to a boolean.
|
|
|
|
PathName - unicode registry path. Not Used.
|
|
|
|
BusType - Internal, Isa, ...
|
|
|
|
BusNumber - Which bus if we are on a multibus system.
|
|
|
|
BusInformation - Configuration information about the bus. Not Used.
|
|
|
|
ControllerType - Controller type.
|
|
|
|
ControllerNumber - Which controller if there is more than one
|
|
controller in the system.
|
|
|
|
ControllerInformation - Array of pointers to the three pieces of
|
|
registry information.
|
|
|
|
PeripheralType - Should be a peripheral.
|
|
|
|
PeripheralNumber - Which peripheral - not used..
|
|
|
|
PeripheralInformation - Configuration information. Not Used.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
PCM_FULL_RESOURCE_DESCRIPTOR controllerData;
|
|
PSERIAL_PTR_CTX pContext = (PSERIAL_PTR_CTX)Context;
|
|
ULONG i;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (ControllerInformation[IoQueryDeviceConfigurationData]->DataLength == 0) {
|
|
pContext->isPointer = FALSE;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
controllerData =
|
|
(PCM_FULL_RESOURCE_DESCRIPTOR)
|
|
(((PUCHAR)ControllerInformation[IoQueryDeviceConfigurationData])
|
|
+ ControllerInformation[IoQueryDeviceConfigurationData]->DataOffset);
|
|
|
|
//
|
|
// See if this is the exact port we are testing
|
|
//
|
|
for (i = 0; i < controllerData->PartialResourceList.Count; i++) {
|
|
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR partial
|
|
= &controllerData->PartialResourceList.PartialDescriptors[i];
|
|
|
|
switch (partial->Type) {
|
|
case CmResourceTypePort:
|
|
if (partial->u.Port.Start.QuadPart == pContext->Port.QuadPart) {
|
|
//
|
|
// Pointer on same controller. Bail out.
|
|
//
|
|
pContext->isPointer = SERIAL_FOUNDPOINTER_PORT;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
case CmResourceTypeInterrupt:
|
|
if (partial->u.Interrupt.Vector == pContext->Vector) {
|
|
//
|
|
// Pointer sharing this interrupt. Bail out.
|
|
//
|
|
pContext->isPointer = SERIAL_FOUNDPOINTER_VECTOR;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
pContext->isPointer = FALSE;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
CyyGetPortInfo(IN PDEVICE_OBJECT PDevObj, IN PCM_RESOURCE_LIST PResList,
|
|
IN PCM_RESOURCE_LIST PTrResList, OUT PCONFIG_DATA PConfig)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will get the configuration information and put
|
|
it and the translated values into CONFIG_DATA structures.
|
|
It first sets up with defaults and then queries the registry
|
|
to see if the user has overridden these defaults; if this is a legacy
|
|
multiport card, it uses the info in PUserData instead of groping the
|
|
registry again.
|
|
|
|
Arguments:
|
|
|
|
PDevObj - Pointer to the device object.
|
|
|
|
PResList - Pointer to the untranslated resources requested.
|
|
|
|
PTrResList - Pointer to the translated resources requested.
|
|
|
|
PConfig - Pointer to configuration info
|
|
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if consistant configuration was found - otherwise.
|
|
returns STATUS_SERIAL_NO_DEVICE_INITED.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCYY_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
|
|
PDEVICE_OBJECT pLowerDevObj = pDevExt->LowerDeviceObject;
|
|
NTSTATUS status = STATUS_NOT_IMPLEMENTED;
|
|
CONFIGURATION_TYPE pointer = PointerPeripheral;
|
|
CONFIGURATION_TYPE controllerType = SerialController;
|
|
|
|
HANDLE keyHandle;
|
|
ULONG count;
|
|
ULONG i;
|
|
INTERFACE_TYPE interfaceType;
|
|
|
|
PCM_PARTIAL_RESOURCE_LIST pPartialResourceList, pPartialTrResourceList;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialResourceDesc, pPartialTrResourceDesc;
|
|
|
|
PCM_FULL_RESOURCE_DESCRIPTOR pFullResourceDesc = NULL,
|
|
pFullTrResourceDesc = NULL;
|
|
|
|
// REMOVED BY FANNY
|
|
// ULONG defaultInterruptMode;
|
|
// ULONG defaultAddressSpace;
|
|
// ULONG defaultInterfaceType;
|
|
// ULONG defaultClockRate;
|
|
ULONG zero = 0;
|
|
// CYY_PTR_CTX foundPointerCtx;
|
|
// ULONG isMulti = 0;
|
|
// ULONG gotInt = 0;
|
|
// ULONG gotISR = 0;
|
|
// ULONG gotIO = 0;
|
|
// ULONG ioResIndex = 0;
|
|
// ULONG curIoIndex = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
CyyDbgPrintEx(CYYTRACECALLS, "entering CyyGetPortInfo\n");
|
|
|
|
CyyDbgPrintEx(CYYPNPPOWER, "resource pointer is %x\n", PResList);
|
|
CyyDbgPrintEx(CYYPNPPOWER, "TR resource pointer is %x\n", PTrResList);
|
|
|
|
|
|
if ((PResList == NULL) || (PTrResList == NULL)) {
|
|
//
|
|
// This shouldn't happen in theory
|
|
//
|
|
|
|
ASSERT(PResList != NULL);
|
|
ASSERT(PTrResList != NULL);
|
|
|
|
//
|
|
// This status is as appropriate as I can think of
|
|
//
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Each resource list should have only one set of resources
|
|
//
|
|
|
|
ASSERT(PResList->Count == 1);
|
|
ASSERT(PTrResList->Count == 1);
|
|
|
|
//REMOVED BY FANNY
|
|
#if 0
|
|
//
|
|
// See if this is a multiport device. This way we allow other
|
|
// pseudo-serial devices with extra resources to specify another range
|
|
// of I/O ports. If this is not a multiport, we only look at the first
|
|
// range. If it is a multiport, we look at the first two ranges.
|
|
//
|
|
|
|
status = IoOpenDeviceRegistryKey(pDevExt->Pdo, PLUGPLAY_REGKEY_DEVICE,
|
|
STANDARD_RIGHTS_WRITE, &keyHandle);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
status = CyyGetRegistryKeyValue(keyHandle, L"MultiportDevice",
|
|
sizeof(L"MultiportDevice"), &isMulti,
|
|
sizeof (ULONG));
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
isMulti = 0;
|
|
}
|
|
|
|
status = CyyGetRegistryKeyValue(keyHandle, L"CyyIoResourcesIndex",
|
|
sizeof(L"CyyIoResourcesIndex"),
|
|
&ioResIndex, sizeof(ULONG));
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
ioResIndex = 0;
|
|
}
|
|
|
|
ZwClose(keyHandle);
|
|
|
|
#endif // end removal code
|
|
|
|
pFullResourceDesc = &PResList->List[0];
|
|
pFullTrResourceDesc = &PTrResList->List[0];
|
|
|
|
//
|
|
// Ok, if we have a full resource descriptor. Let's take it apart.
|
|
//
|
|
|
|
if (pFullResourceDesc) {
|
|
pPartialResourceList = &pFullResourceDesc->PartialResourceList;
|
|
pPartialResourceDesc = pPartialResourceList->PartialDescriptors;
|
|
count = pPartialResourceList->Count;
|
|
|
|
//
|
|
// Pull out the stuff that is in the full descriptor.
|
|
//
|
|
|
|
PConfig->InterfaceType = pFullResourceDesc->InterfaceType;
|
|
PConfig->BusNumber = pFullResourceDesc->BusNumber;
|
|
|
|
//
|
|
// Now run through the partial resource descriptors looking for the Runtime memory,
|
|
// CD1400 memory, and interrupt.
|
|
//
|
|
|
|
for (i = 0; i < count; i++, pPartialResourceDesc++) {
|
|
|
|
switch (pPartialResourceDesc->Type) {
|
|
case CmResourceTypeMemory: {
|
|
|
|
if (pPartialResourceDesc->u.Memory.Length == CYY_RUNTIME_LENGTH) {
|
|
PConfig->PhysicalRuntime = pPartialResourceDesc->u.Memory.Start;
|
|
PConfig->RuntimeLength = pPartialResourceDesc->u.Memory.Length;
|
|
PConfig->RuntimeAddressSpace = pPartialResourceDesc->Flags;
|
|
} else {
|
|
PConfig->PhysicalBoardMemory = pPartialResourceDesc->u.Memory.Start;
|
|
PConfig->BoardMemoryLength = pPartialResourceDesc->u.Memory.Length;
|
|
PConfig->BoardMemoryAddressSpace = pPartialResourceDesc->Flags;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case CmResourceTypeInterrupt: {
|
|
PConfig->OriginalIrql = pPartialResourceDesc->u.Interrupt.Level;
|
|
PConfig->OriginalVector =pPartialResourceDesc->u.Interrupt.Vector;
|
|
PConfig->Affinity = pPartialResourceDesc->u.Interrupt.Affinity;
|
|
if (pPartialResourceDesc->Flags
|
|
& CM_RESOURCE_INTERRUPT_LATCHED) {
|
|
PConfig->InterruptMode = Latched;
|
|
} else {
|
|
PConfig->InterruptMode = LevelSensitive;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
default: {
|
|
break;
|
|
}
|
|
} // switch (pPartialResourceDesc->Type)
|
|
} // for (i = 0; i < count; i++, pPartialResourceDesc++)
|
|
} // if (pFullResourceDesc)
|
|
|
|
|
|
//
|
|
// Do the same for the translated resources
|
|
//
|
|
|
|
|
|
if (pFullTrResourceDesc) {
|
|
pPartialTrResourceList = &pFullTrResourceDesc->PartialResourceList;
|
|
pPartialTrResourceDesc = pPartialTrResourceList->PartialDescriptors;
|
|
count = pPartialTrResourceList->Count;
|
|
|
|
//
|
|
// Reload PConfig with the translated values for later use
|
|
//
|
|
|
|
PConfig->InterfaceType = pFullTrResourceDesc->InterfaceType;
|
|
PConfig->BusNumber = pFullTrResourceDesc->BusNumber;
|
|
|
|
for (i = 0; i < count; i++, pPartialTrResourceDesc++) {
|
|
|
|
|
|
switch (pPartialTrResourceDesc->Type) {
|
|
case CmResourceTypeMemory: {
|
|
|
|
// ATTENTION, ATTENTION: FOR NOW, WE WILL USE THE RAW
|
|
// RESOURCES, AS WE HAVE GARBAGE IN THE TRANSLATED
|
|
// RESOURCES.
|
|
//
|
|
if (pPartialTrResourceDesc->u.Memory.Length == CYY_RUNTIME_LENGTH) {
|
|
PConfig->TranslatedRuntime = pPartialTrResourceDesc->u.Memory.Start;
|
|
PConfig->RuntimeLength = pPartialTrResourceDesc->u.Memory.Length;
|
|
} else {
|
|
PConfig->TranslatedBoardMemory = pPartialTrResourceDesc->u.Memory.Start;
|
|
PConfig->BoardMemoryLength = pPartialTrResourceDesc->u.Memory.Length;
|
|
}
|
|
|
|
//TEMP CODE BECAUSE OUR BUS DRIVER IS GIVING WRONG TRANSLATED ADDRESS
|
|
//PConfig->TranslatedRuntime = PConfig->PhysicalRuntime;
|
|
//PConfig->TranslatedBoardMemory = PConfig->PhysicalBoardMemory;
|
|
break;
|
|
}
|
|
|
|
case CmResourceTypeInterrupt: {
|
|
PConfig->TrVector = pPartialTrResourceDesc->u.Interrupt.Vector;
|
|
PConfig->TrIrql = pPartialTrResourceDesc->u.Interrupt.Level;
|
|
PConfig->Affinity = pPartialTrResourceDesc->u.Interrupt.Affinity;
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
break;
|
|
}
|
|
} // switch (pPartialTrResourceDesc->Type)
|
|
} // for (i = 0; i < count; i++, pPartialTrResourceDesc++)
|
|
} // if (pFullTrResourceDesc)
|
|
|
|
|
|
//
|
|
// Initialize a config data structure with default values for those that
|
|
// may not already be initialized.
|
|
//
|
|
|
|
PConfig->PortIndex = 0;
|
|
PConfig->RxFIFO = driverDefaults.RxFIFODefault;
|
|
PConfig->TxFIFO = driverDefaults.TxFIFODefault;
|
|
|
|
|
|
//
|
|
// Open the "Device Parameters" section of registry for this device object.
|
|
//
|
|
|
|
|
|
status = IoOpenDeviceRegistryKey (pDevExt->Pdo,
|
|
PLUGPLAY_REGKEY_DEVICE,
|
|
STANDARD_RIGHTS_READ,
|
|
&keyHandle);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
CyyDbgPrintEx(CYYERRORS, "IoOpenDeviceRegistryKey failed - %x \n",
|
|
status);
|
|
goto PortInfoCleanUp;
|
|
|
|
} else {
|
|
|
|
status = CyyGetRegistryKeyValue (keyHandle,
|
|
L"RxFIFO",
|
|
sizeof(L"RxFIFO"),
|
|
&PConfig->RxFIFO,
|
|
sizeof (ULONG));
|
|
status = CyyGetRegistryKeyValue (keyHandle,
|
|
L"TxFIFO",
|
|
sizeof(L"TxFIFO"),
|
|
&PConfig->TxFIFO,
|
|
sizeof (ULONG));
|
|
status = CyyGetRegistryKeyValue (keyHandle,
|
|
L"PortIndex",
|
|
sizeof(L"PortIndex"),
|
|
&PConfig->PortIndex,
|
|
sizeof (ULONG));
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
PConfig->PortIndex = MAXULONG; // just some invalid number (fanny)
|
|
}
|
|
|
|
ZwClose (keyHandle);
|
|
}
|
|
|
|
//
|
|
// Do some error checking on the configuration info we have.
|
|
//
|
|
// Make sure that the interrupt is non zero (which we defaulted
|
|
// it to).
|
|
//
|
|
// Make sure that the portaddress is non zero (which we defaulted
|
|
// it to).
|
|
//
|
|
// Make sure that the DosDevices is not NULL (which we defaulted
|
|
// it to).
|
|
//
|
|
// We need to make sure that if an interrupt status
|
|
// was specified, that a port index was also specfied,
|
|
// and if so that the port index is <= maximum ports
|
|
// on a board.
|
|
//
|
|
// We should also validate that the bus type and number
|
|
// are correct.
|
|
//
|
|
// We will also validate that the interrupt mode makes
|
|
// sense for the bus.
|
|
//
|
|
|
|
//*****************************************
|
|
// Error Injection
|
|
// PConfig->PhysicalRuntime.LowPart = NULL;
|
|
// PConfig->PhysicalBoardMemory.LowPart = NULL;
|
|
// PConfig->OriginalVector = NULL;
|
|
// PConfig->PortIndex = MAXULONG;
|
|
//*****************************************
|
|
|
|
if (!PConfig->PhysicalRuntime.LowPart && pDevExt->IsPci) {
|
|
|
|
//
|
|
// Ehhhh! Lose Game.
|
|
//
|
|
|
|
CyyLogError(
|
|
PDevObj->DriverObject,
|
|
NULL,
|
|
PConfig->PhysicalBoardMemory,
|
|
CyyPhysicalZero,
|
|
0,
|
|
0,
|
|
0,
|
|
PConfig->PortIndex+1,
|
|
STATUS_SUCCESS,
|
|
CYY_INVALID_RUNTIME_REGISTERS,
|
|
pDevExt->DeviceName.Length,
|
|
pDevExt->DeviceName.Buffer,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
CyyDbgPrintEx(CYYERRORS,"Bogus Runtime address %x\n",
|
|
PConfig->PhysicalRuntime.LowPart);
|
|
|
|
//status = CYY_INVALID_RUNTIME_REGISTERS;
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto PortInfoCleanUp;
|
|
}
|
|
|
|
if (!PConfig->PhysicalBoardMemory.LowPart) {
|
|
|
|
//
|
|
// Ehhhh! Lose Game.
|
|
//
|
|
|
|
CyyLogError(
|
|
PDevObj->DriverObject,
|
|
NULL,
|
|
PConfig->PhysicalBoardMemory,
|
|
CyyPhysicalZero,
|
|
0,
|
|
0,
|
|
0,
|
|
PConfig->PortIndex+1,
|
|
STATUS_SUCCESS,
|
|
CYY_INVALID_BOARD_MEMORY,
|
|
pDevExt->DeviceName.Length,
|
|
pDevExt->DeviceName.Buffer,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
CyyDbgPrintEx(CYYERRORS,"Bogus board address %x\n",
|
|
PConfig->PhysicalBoardMemory.LowPart);
|
|
|
|
//status = CYY_INVALID_BOARD_MEMORY;
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto PortInfoCleanUp;
|
|
}
|
|
|
|
if (!PConfig->OriginalVector) {
|
|
|
|
//
|
|
// Ehhhh! Lose Game.
|
|
//
|
|
|
|
CyyLogError(
|
|
pDevExt->DriverObject,
|
|
NULL,
|
|
PConfig->PhysicalBoardMemory,
|
|
CyyPhysicalZero,
|
|
0,
|
|
0,
|
|
0,
|
|
PConfig->PortIndex+1,
|
|
STATUS_SUCCESS,
|
|
CYY_INVALID_INTERRUPT,
|
|
pDevExt->DeviceName.Length,
|
|
pDevExt->DeviceName.Buffer,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
CyyDbgPrintEx(CYYERRORS, "Bogus vector %x\n", PConfig->OriginalVector);
|
|
|
|
//status = CYY_INVALID_INTERRUPT;
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto PortInfoCleanUp;
|
|
}
|
|
|
|
if (PConfig->PortIndex >= CYY_MAX_PORTS) {
|
|
|
|
CyyLogError(
|
|
pDevExt->DriverObject,
|
|
NULL,
|
|
PConfig->PhysicalBoardMemory,
|
|
CyyPhysicalZero,
|
|
0,
|
|
0,
|
|
0,
|
|
PConfig->PortIndex,
|
|
STATUS_SUCCESS,
|
|
CYY_PORT_INDEX_TOO_HIGH,
|
|
pDevExt->DeviceName.Length,
|
|
pDevExt->DeviceName.Buffer,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
CyyDbgPrintEx(CYYERRORS,"Port index too large %x\n",PConfig->PortIndex);
|
|
|
|
//status = CYY_PORT_INDEX_TOO_HIGH;
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto PortInfoCleanUp;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// We don't want to cause the hal to have a bad day,
|
|
// so let's check the interface type and bus number.
|
|
//
|
|
// We only need to check the registry if they aren't
|
|
// equal to the defaults.
|
|
//
|
|
|
|
if (PConfig->BusNumber != 0) {
|
|
|
|
BOOLEAN foundIt;
|
|
|
|
//**************************************************
|
|
// Error Injection
|
|
// PConfig->InterfaceType = MaximumInterfaceType;
|
|
//**************************************************
|
|
|
|
if (PConfig->InterfaceType >= MaximumInterfaceType) {
|
|
|
|
//
|
|
// Ehhhh! Lose Game.
|
|
//
|
|
|
|
CyyLogError(
|
|
pDevExt->DriverObject,
|
|
NULL,
|
|
PConfig->PhysicalBoardMemory,
|
|
CyyPhysicalZero,
|
|
0,
|
|
0,
|
|
0,
|
|
PConfig->PortIndex+1,
|
|
STATUS_SUCCESS,
|
|
CYY_UNKNOWN_BUS,
|
|
pDevExt->DeviceName.Length,
|
|
pDevExt->DeviceName.Buffer,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
CyyDbgPrintEx(CYYERRORS, "Invalid Bus type %x\n",
|
|
PConfig->BusNumber);
|
|
|
|
//status = CYY_UNKNOWN_BUS;
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto PortInfoCleanUp;
|
|
}
|
|
|
|
IoQueryDeviceDescription(
|
|
(INTERFACE_TYPE *)&PConfig->InterfaceType,
|
|
&zero,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
CyyItemCallBack,
|
|
&foundIt
|
|
);
|
|
|
|
//**************************************************
|
|
// Error Injection
|
|
// foundIt = FALSE;
|
|
//**************************************************
|
|
|
|
if (!foundIt) {
|
|
|
|
CyyLogError(
|
|
pDevExt->DriverObject,
|
|
NULL,
|
|
PConfig->PhysicalBoardMemory,
|
|
CyyPhysicalZero,
|
|
0,
|
|
0,
|
|
0,
|
|
PConfig->PortIndex+1,
|
|
STATUS_SUCCESS,
|
|
CYY_BUS_NOT_PRESENT,
|
|
pDevExt->DeviceName.Length,
|
|
pDevExt->DeviceName.Buffer,
|
|
0,
|
|
NULL
|
|
);
|
|
CyyDbgPrintEx(CYYERRORS, "There aren't that many of those\n"
|
|
"busses on this system,%x\n", PConfig->BusNumber);
|
|
|
|
//status = CYY_BUS_NOT_PRESENT;
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto PortInfoCleanUp;
|
|
|
|
}
|
|
|
|
} // if (PConfig->BusNumber != 0)
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Dump out the port configuration.
|
|
//
|
|
|
|
CyyDbgPrintEx(CYYDIAG1, "Runtime Memory address: %x\n",
|
|
PConfig->PhysicalRuntime.LowPart);
|
|
|
|
CyyDbgPrintEx(CYYDIAG1, "Board Memory address: %x\n",
|
|
PConfig->PhysicalBoardMemory.LowPart);
|
|
|
|
CyyDbgPrintEx(CYYDIAG1, "Com Port Index: %x\n",
|
|
PConfig->PortIndex);
|
|
|
|
CyyDbgPrintEx(CYYDIAG1, "Com Port BusNumber: %x\n",
|
|
PConfig->BusNumber);
|
|
|
|
CyyDbgPrintEx(CYYDIAG1, "Com Runtime AddressSpace: %x\n",
|
|
PConfig->RuntimeAddressSpace);
|
|
|
|
CyyDbgPrintEx(CYYDIAG1, "Com Board AddressSpace: %x\n",
|
|
PConfig->BoardMemoryAddressSpace);
|
|
|
|
CyyDbgPrintEx(CYYDIAG1, "Com InterruptMode: %x\n",
|
|
PConfig->InterruptMode);
|
|
|
|
CyyDbgPrintEx(CYYDIAG1, "Com InterfaceType: %x\n",
|
|
PConfig->InterfaceType);
|
|
|
|
CyyDbgPrintEx(CYYDIAG1, "Com OriginalVector: %x\n",
|
|
PConfig->OriginalVector);
|
|
|
|
CyyDbgPrintEx(CYYDIAG1, "Com OriginalIrql: %x\n",
|
|
PConfig->OriginalIrql);
|
|
|
|
PortInfoCleanUp:;
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CyyReadSymName(IN PCYY_DEVICE_EXTENSION PDevExt, IN HANDLE hRegKey,
|
|
OUT PUNICODE_STRING PSymName, OUT PWCHAR *PpRegName)
|
|
{
|
|
NTSTATUS status;
|
|
UNICODE_STRING linkName;
|
|
PDRIVER_OBJECT pDrvObj;
|
|
PDEVICE_OBJECT pDevObj;
|
|
|
|
pDevObj = PDevExt->DeviceObject;
|
|
pDrvObj = pDevObj->DriverObject;
|
|
*PpRegName = NULL;
|
|
|
|
RtlZeroMemory(&linkName, sizeof(UNICODE_STRING));
|
|
|
|
linkName.MaximumLength = SYMBOLIC_NAME_LENGTH*sizeof(WCHAR);
|
|
linkName.Buffer = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, linkName.MaximumLength
|
|
+ sizeof(WCHAR));
|
|
|
|
if (linkName.Buffer == NULL) {
|
|
CyyLogError(pDrvObj, pDevObj, CyyPhysicalZero, CyyPhysicalZero,
|
|
0, 0, 0, 19, STATUS_SUCCESS, CYY_INSUFFICIENT_RESOURCES,
|
|
0, NULL, 0, NULL);
|
|
CyyDbgPrintEx(CYYERRORS, "Couldn't allocate memory for device name\n");
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto CyyReadSymNameError;
|
|
|
|
}
|
|
|
|
RtlZeroMemory(linkName.Buffer, linkName.MaximumLength + sizeof(WCHAR));
|
|
|
|
|
|
*PpRegName = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, SYMBOLIC_NAME_LENGTH * sizeof(WCHAR)
|
|
+ sizeof(WCHAR));
|
|
|
|
if (*PpRegName == NULL) {
|
|
CyyLogError(pDrvObj, pDevObj, CyyPhysicalZero, CyyPhysicalZero,
|
|
0, 0, 0, 19, STATUS_SUCCESS, CYY_INSUFFICIENT_RESOURCES,
|
|
0, NULL, 0, NULL);
|
|
CyyDbgPrintEx(CYYERRORS, "Couldn't allocate memory for buffer\n");
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto CyyReadSymNameError;
|
|
|
|
}
|
|
|
|
//
|
|
// Fetch PortName which contains the suggested REG_SZ symbolic name.
|
|
//
|
|
|
|
status = CyyGetRegistryKeyValue(hRegKey, L"PortName",
|
|
sizeof(L"PortName"), *PpRegName,
|
|
SYMBOLIC_NAME_LENGTH * sizeof(WCHAR));
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// This is for PCMCIA which currently puts the name under Identifier.
|
|
//
|
|
|
|
status = CyyGetRegistryKeyValue(hRegKey, L"Identifier",
|
|
sizeof(L"Identifier"),
|
|
*PpRegName, SYMBOLIC_NAME_LENGTH
|
|
* sizeof(WCHAR));
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// Hmm. Either we have to pick a name or bail...
|
|
//
|
|
// ...we will bail.
|
|
//
|
|
|
|
CyyDbgPrintEx(CYYERRORS, "Getting PortName/Identifier failed - "
|
|
"%x\n", status);
|
|
goto CyyReadSymNameError;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Create the "\\DosDevices\\<symbolicName>" string
|
|
//
|
|
|
|
RtlAppendUnicodeToString(&linkName, L"\\");
|
|
RtlAppendUnicodeToString(&linkName, DEFAULT_DIRECTORY);
|
|
RtlAppendUnicodeToString(&linkName, L"\\");
|
|
RtlAppendUnicodeToString(&linkName, *PpRegName);
|
|
|
|
PSymName->MaximumLength = linkName.Length + sizeof(WCHAR);
|
|
PSymName->Buffer = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, PSymName->MaximumLength);
|
|
|
|
if (PSymName->Buffer == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto CyyReadSymNameError;
|
|
}
|
|
|
|
RtlZeroMemory(PSymName->Buffer, PSymName->MaximumLength);
|
|
|
|
RtlAppendUnicodeStringToString(PSymName, &linkName);
|
|
|
|
CyyDbgPrintEx(CYYDIAG1, "Read name %wZ\n", PSymName);
|
|
|
|
CyyReadSymNameError:
|
|
|
|
if (linkName.Buffer != NULL) {
|
|
ExFreePool(linkName.Buffer);
|
|
linkName.Buffer = NULL;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
if (*PpRegName != NULL) {
|
|
ExFreePool(*PpRegName);
|
|
*PpRegName = NULL;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
CyyDoExternalNaming(IN PCYY_DEVICE_EXTENSION PDevExt,
|
|
IN PDRIVER_OBJECT PDrvObj)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will be used to create a symbolic link
|
|
to the driver name in the given object directory.
|
|
|
|
It will also create an entry in the device map for
|
|
this device - IF we could create the symbolic link.
|
|
|
|
Arguments:
|
|
|
|
Extension - Pointer to the device extension.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
HANDLE keyHandle;
|
|
WCHAR *pRegName = NULL;
|
|
UNICODE_STRING linkName;
|
|
PDEVICE_OBJECT pLowerDevObj, pDevObj;
|
|
ULONG bufLen;
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
pDevObj = PDevExt->DeviceObject;
|
|
pLowerDevObj = PDevExt->LowerDeviceObject;
|
|
|
|
status = IoOpenDeviceRegistryKey(PDevExt->Pdo, PLUGPLAY_REGKEY_DEVICE,
|
|
STANDARD_RIGHTS_READ, &keyHandle);
|
|
|
|
//
|
|
// Check to see if we are allowed to do external naming; if not,
|
|
// then we just return success
|
|
//
|
|
|
|
|
|
if (status != STATUS_SUCCESS) {
|
|
return status;
|
|
}
|
|
|
|
|
|
CyyGetRegistryKeyValue(keyHandle, L"CyySkipExternalNaming",
|
|
sizeof(L"CyySkipExternalNaming"),
|
|
&PDevExt->SkipNaming, sizeof(ULONG));
|
|
|
|
if (PDevExt->SkipNaming) {
|
|
ZwClose(keyHandle);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
RtlZeroMemory(&linkName, sizeof(UNICODE_STRING));
|
|
|
|
linkName.MaximumLength = SYMBOLIC_NAME_LENGTH*sizeof(WCHAR);
|
|
linkName.Buffer = ExAllocatePool(PagedPool, linkName.MaximumLength
|
|
+ sizeof(WCHAR)); //TODO:"| POOL_COLD_ALLOCATION"???
|
|
|
|
//************************************
|
|
//Error Injection
|
|
//
|
|
//if (linkName.Buffer != NULL) {
|
|
// ExFreePool(linkName.Buffer);
|
|
//}
|
|
//linkName.Buffer = NULL;
|
|
//************************************
|
|
|
|
if (linkName.Buffer == NULL) {
|
|
CyyLogError(PDrvObj, pDevObj, CyyPhysicalZero, CyyPhysicalZero,
|
|
0, 0, 0, 71, STATUS_SUCCESS, CYY_INSUFFICIENT_RESOURCES,
|
|
0, NULL, 0, NULL);
|
|
CyyDbgPrintEx(CYYERRORS, "Couldn't allocate memory for device name\n");
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
ZwClose(keyHandle);
|
|
goto CyyDoExternalNamingError;
|
|
|
|
}
|
|
|
|
RtlZeroMemory(linkName.Buffer, linkName.MaximumLength + sizeof(WCHAR));
|
|
|
|
|
|
pRegName = ExAllocatePool(PagedPool, SYMBOLIC_NAME_LENGTH * sizeof(WCHAR)
|
|
+ sizeof(WCHAR)); //TODO:"| POOL_COLD_ALLOCATION"???
|
|
|
|
//************************************
|
|
//Error Injection
|
|
//
|
|
//if (pRegName != NULL) {
|
|
// ExFreePool(pRegName);
|
|
//}
|
|
//pRegName = NULL;
|
|
//************************************
|
|
|
|
if (pRegName == NULL) {
|
|
CyyLogError(PDrvObj, pDevObj, CyyPhysicalZero, CyyPhysicalZero,
|
|
0, 0, 0, 72, STATUS_SUCCESS, CYY_INSUFFICIENT_RESOURCES,
|
|
0, NULL, 0, NULL);
|
|
CyyDbgPrintEx(CYYERRORS, "Couldn't allocate memory for buffer\n");
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
ZwClose(keyHandle);
|
|
goto CyyDoExternalNamingError;
|
|
|
|
}
|
|
|
|
//
|
|
// Fetch PortName which contains the suggested REG_SZ symbolic name.
|
|
//
|
|
|
|
status = CyyGetRegistryKeyValue(keyHandle, L"PortName",
|
|
sizeof(L"PortName"), pRegName,
|
|
SYMBOLIC_NAME_LENGTH * sizeof(WCHAR));
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// This is for PCMCIA which currently puts the name under Identifier.
|
|
//
|
|
|
|
status = CyyGetRegistryKeyValue(keyHandle, L"Identifier",
|
|
sizeof(L"Identifier"),
|
|
pRegName, SYMBOLIC_NAME_LENGTH
|
|
* sizeof(WCHAR));
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// Hmm. Either we have to pick a name or bail...
|
|
//
|
|
// ...we will bail.
|
|
//
|
|
|
|
CyyDbgPrintEx(CYYERRORS, "Getting PortName/Identifier failed - "
|
|
"%x\n", status);
|
|
ZwClose (keyHandle);
|
|
goto CyyDoExternalNamingError;
|
|
}
|
|
|
|
}
|
|
|
|
ZwClose (keyHandle);
|
|
|
|
bufLen = wcslen(pRegName) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
|
|
|
|
PDevExt->WmiIdentifier.Buffer = ExAllocatePool(PagedPool, bufLen);
|
|
|
|
//************************************
|
|
//Error Injection
|
|
//
|
|
//if (PDevExt->WmiIdentifier.Buffer != NULL) {
|
|
// ExFreePool(PDevExt->WmiIdentifier.Buffer);
|
|
//}
|
|
//PDevExt->WmiIdentifier.Buffer = NULL;
|
|
//************************************
|
|
|
|
if (PDevExt->WmiIdentifier.Buffer == NULL) {
|
|
CyyLogError(PDrvObj, pDevObj, CyyPhysicalZero, CyyPhysicalZero,
|
|
0, 0, 0, 73, STATUS_SUCCESS, CYY_INSUFFICIENT_RESOURCES,
|
|
0, NULL, 0, NULL);
|
|
CyyDbgPrintEx(CYYERRORS, "Couldn't allocate memory for WMI name\n");
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto CyyDoExternalNamingError;
|
|
}
|
|
|
|
RtlZeroMemory(PDevExt->WmiIdentifier.Buffer, bufLen);
|
|
|
|
PDevExt->WmiIdentifier.Length = 0;
|
|
PDevExt->WmiIdentifier.MaximumLength = (USHORT)bufLen - 1;
|
|
RtlAppendUnicodeToString(&PDevExt->WmiIdentifier, pRegName);
|
|
|
|
//
|
|
// Create the "\\DosDevices\\<symbolicName>" string
|
|
//
|
|
RtlAppendUnicodeToString(&linkName, L"\\");
|
|
RtlAppendUnicodeToString(&linkName, DEFAULT_DIRECTORY);
|
|
RtlAppendUnicodeToString(&linkName, L"\\");
|
|
RtlAppendUnicodeToString(&linkName, pRegName);
|
|
|
|
//
|
|
// Allocate Pool and save the symbolic link name in the device extension.
|
|
//
|
|
PDevExt->SymbolicLinkName.MaximumLength = linkName.Length + sizeof(WCHAR);
|
|
PDevExt->SymbolicLinkName.Buffer
|
|
= ExAllocatePool(PagedPool, PDevExt->SymbolicLinkName.MaximumLength);
|
|
//TODO:"| POOL_COLD_ALLOCATION"???
|
|
|
|
if (!PDevExt->SymbolicLinkName.Buffer) {
|
|
|
|
CyyLogError(PDrvObj, pDevObj, CyyPhysicalZero, CyyPhysicalZero,
|
|
0, 0, 0, 74, STATUS_SUCCESS, CYY_INSUFFICIENT_RESOURCES,
|
|
0, NULL, 0, NULL);
|
|
CyyDbgPrintEx(CYYERRORS, "Couldn't allocate memory for symbolic link "
|
|
"name\n");
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto CyyDoExternalNamingError;
|
|
}
|
|
|
|
//
|
|
// Zero fill it.
|
|
//
|
|
|
|
RtlZeroMemory(PDevExt->SymbolicLinkName.Buffer,
|
|
PDevExt->SymbolicLinkName.MaximumLength);
|
|
|
|
RtlAppendUnicodeStringToString(&PDevExt->SymbolicLinkName,
|
|
&linkName);
|
|
|
|
PDevExt->DosName.Buffer = ExAllocatePool(PagedPool, 64 + sizeof(WCHAR));
|
|
|
|
if (!PDevExt->DosName.Buffer) {
|
|
|
|
CyyLogError(PDrvObj, pDevObj, CyyPhysicalZero, CyyPhysicalZero,
|
|
0, 0, 0, 75, STATUS_SUCCESS, CYY_INSUFFICIENT_RESOURCES,
|
|
0, NULL, 0, NULL);
|
|
CyyDbgPrintEx(CYYERRORS, "Couldn't allocate memory for Dos name\n");
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto CyyDoExternalNamingError;
|
|
}
|
|
|
|
|
|
PDevExt->DosName.MaximumLength = 64 + sizeof(WCHAR);
|
|
|
|
//
|
|
// Zero fill it.
|
|
//
|
|
|
|
PDevExt->DosName.Length = 0;
|
|
|
|
RtlZeroMemory(PDevExt->DosName.Buffer,
|
|
PDevExt->DosName.MaximumLength);
|
|
|
|
RtlAppendUnicodeToString(&PDevExt->DosName, pRegName);
|
|
RtlZeroMemory(((PUCHAR)(&PDevExt->DosName.Buffer[0]))
|
|
+ PDevExt->DosName.Length, sizeof(WCHAR));
|
|
|
|
CyyDbgPrintEx(CYYDIAG1, "DosName is %wZ\n", &PDevExt->DosName);
|
|
|
|
status = IoCreateSymbolicLink (&PDevExt->SymbolicLinkName,
|
|
&PDevExt->DeviceName);
|
|
|
|
//************************************
|
|
//Error Injection
|
|
//IoDeleteSymbolicLink(&PDevExt->SymbolicLinkName);
|
|
//status = STATUS_INVALID_PARAMETER;
|
|
//************************************
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// Oh well, couldn't create the symbolic link. No point
|
|
// in trying to create the device map entry.
|
|
//
|
|
|
|
CyyLogError(PDrvObj, pDevObj, CyyPhysicalZero, CyyPhysicalZero,
|
|
0, 0, 0, PDevExt->PortIndex+1, status, CYY_NO_SYMLINK_CREATED,
|
|
PDevExt->DeviceName.Length + sizeof(WCHAR),
|
|
PDevExt->DeviceName.Buffer, 0, NULL);
|
|
|
|
CyyDbgPrintEx(CYYERRORS, "Couldn't create the symbolic link\n"
|
|
"for port %wZ\n", &PDevExt->DeviceName);
|
|
|
|
goto CyyDoExternalNamingError;
|
|
|
|
}
|
|
|
|
PDevExt->CreatedSymbolicLink = TRUE;
|
|
|
|
status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP, L"SERIALCOMM",
|
|
PDevExt->DeviceName.Buffer, REG_SZ,
|
|
PDevExt->DosName.Buffer,
|
|
PDevExt->DosName.Length + sizeof(WCHAR));
|
|
|
|
//************************************
|
|
//Error Injection
|
|
//RtlDeleteRegistryValue(RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP,
|
|
// PDevExt->DeviceName.Buffer);
|
|
//status = STATUS_INVALID_PARAMETER;
|
|
//************************************
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
CyyLogError(PDrvObj, pDevObj, CyyPhysicalZero, CyyPhysicalZero,
|
|
0, 0, 0, PDevExt->PortIndex+1, status, CYY_NO_DEVICE_MAP_CREATED,
|
|
PDevExt->DeviceName.Length + sizeof(WCHAR),
|
|
PDevExt->DeviceName.Buffer, 0, NULL);
|
|
|
|
CyyDbgPrintEx(CYYERRORS, "Couldn't create the device map entry\n"
|
|
"------- for port %wZ\n", &PDevExt->DeviceName);
|
|
|
|
goto CyyDoExternalNamingError;
|
|
}
|
|
|
|
PDevExt->CreatedSerialCommEntry = TRUE;
|
|
|
|
//
|
|
// Make the device visible via a device association as well.
|
|
// The reference string is the eight digit device index
|
|
//
|
|
|
|
status = IoRegisterDeviceInterface(PDevExt->Pdo, (LPGUID)&GUID_CLASS_COMPORT,
|
|
NULL, &PDevExt->DeviceClassSymbolicName);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
CyyDbgPrintEx(CYYERRORS, "Couldn't register class association "
|
|
"for port %wZ\n", &PDevExt->DeviceName);
|
|
|
|
PDevExt->DeviceClassSymbolicName.Buffer = NULL;
|
|
goto CyyDoExternalNamingError;
|
|
}
|
|
|
|
|
|
//
|
|
// Now set the symbolic link for the association
|
|
//
|
|
|
|
status = IoSetDeviceInterfaceState(&PDevExt->DeviceClassSymbolicName,
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
CyyDbgPrintEx(CYYERRORS, "Couldn't set class association"
|
|
" for port %wZ\n", &PDevExt->DeviceName);
|
|
}
|
|
|
|
CyyDoExternalNamingError:;
|
|
|
|
//
|
|
// Clean up error conditions
|
|
//
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
if (PDevExt->DosName.Buffer != NULL) {
|
|
ExFreePool(PDevExt->DosName.Buffer);
|
|
PDevExt->DosName.Buffer = NULL;
|
|
}
|
|
|
|
if (PDevExt->CreatedSymbolicLink == TRUE) {
|
|
IoDeleteSymbolicLink(&PDevExt->SymbolicLinkName);
|
|
PDevExt->CreatedSymbolicLink = FALSE;
|
|
}
|
|
|
|
if (PDevExt->SymbolicLinkName.Buffer != NULL) {
|
|
ExFreePool(PDevExt->SymbolicLinkName.Buffer);
|
|
PDevExt->SymbolicLinkName.Buffer = NULL;
|
|
}
|
|
|
|
if (PDevExt->DeviceName.Buffer != NULL) {
|
|
RtlDeleteRegistryValue(RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP,
|
|
PDevExt->DeviceName.Buffer);
|
|
}
|
|
|
|
if (PDevExt->DeviceClassSymbolicName.Buffer) {
|
|
IoSetDeviceInterfaceState(&PDevExt->DeviceClassSymbolicName, FALSE);
|
|
ExFreePool(PDevExt->DeviceClassSymbolicName.Buffer); //Added in DDK 2269
|
|
PDevExt->DeviceClassSymbolicName.Buffer = NULL; //Added in DDK 2269
|
|
}
|
|
|
|
if (PDevExt->WmiIdentifier.Buffer != NULL) {
|
|
ExFreePool(PDevExt->WmiIdentifier.Buffer);
|
|
PDevExt->WmiIdentifier.Buffer = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Always clean up our temp buffers.
|
|
//
|
|
|
|
if (linkName.Buffer != NULL) {
|
|
ExFreePool(linkName.Buffer);
|
|
}
|
|
|
|
if (pRegName != NULL) {
|
|
ExFreePool(pRegName);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
CyyUndoExternalNaming(IN PCYY_DEVICE_EXTENSION Extension)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will be used to delete a symbolic link
|
|
to the driver name in the given object directory.
|
|
|
|
It will also delete an entry in the device map for
|
|
this device if the symbolic link had been created.
|
|
|
|
Arguments:
|
|
|
|
Extension - Pointer to the device extension.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
HANDLE keyHandle;
|
|
|
|
PAGED_CODE();
|
|
|
|
CyyDbgPrintEx(CYYDIAG3, "In CyyUndoExternalNaming for "
|
|
"extension: %x of port %wZ\n",
|
|
Extension,&Extension->DeviceName);
|
|
|
|
//
|
|
// Maybe there is nothing for us to do
|
|
//
|
|
|
|
if (Extension->SkipNaming) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// We're cleaning up here. One reason we're cleaning up
|
|
// is that we couldn't allocate space for the directory
|
|
// name or the symbolic link.
|
|
//
|
|
|
|
if (Extension->SymbolicLinkName.Buffer && Extension->CreatedSymbolicLink) {
|
|
|
|
if (Extension->DeviceClassSymbolicName.Buffer) {
|
|
status = IoSetDeviceInterfaceState(&Extension->DeviceClassSymbolicName,
|
|
FALSE);
|
|
|
|
//
|
|
// IoRegisterDeviceClassInterface() allocated this string for us,
|
|
// and we no longer need it.
|
|
//
|
|
|
|
ExFreePool(Extension->DeviceClassSymbolicName.Buffer);
|
|
Extension->DeviceClassSymbolicName.Buffer = NULL;
|
|
}
|
|
|
|
//
|
|
// Before we delete the symlink, re-read the PortName
|
|
// from the registry in case we were renamed in user mode.
|
|
//
|
|
|
|
status = IoOpenDeviceRegistryKey(Extension->Pdo, PLUGPLAY_REGKEY_DEVICE,
|
|
STANDARD_RIGHTS_READ, &keyHandle);
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
UNICODE_STRING symLinkName;
|
|
PWCHAR pRegName;
|
|
|
|
RtlInitUnicodeString(&symLinkName, NULL);
|
|
|
|
status = CyyReadSymName(Extension, keyHandle, &symLinkName,
|
|
&pRegName);
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
|
|
CyyDbgPrintEx(CYYDIAG1, "Deleting Link %wZ\n", &symLinkName);
|
|
IoDeleteSymbolicLink(&symLinkName);
|
|
|
|
ExFreePool(symLinkName.Buffer);
|
|
ExFreePool(pRegName);
|
|
}
|
|
|
|
ZwClose(keyHandle);
|
|
}
|
|
}
|
|
|
|
if (Extension->WmiIdentifier.Buffer) {
|
|
ExFreePool(Extension->WmiIdentifier.Buffer);
|
|
Extension->WmiIdentifier.MaximumLength
|
|
= Extension->WmiIdentifier.Length = 0;
|
|
Extension->WmiIdentifier.Buffer = NULL;
|
|
}
|
|
|
|
//
|
|
// We're cleaning up here. One reason we're cleaning up
|
|
// is that we couldn't allocate space for the NtNameOfPort.
|
|
//
|
|
|
|
if ((Extension->DeviceName.Buffer != NULL)
|
|
&& Extension->CreatedSerialCommEntry) {
|
|
|
|
status = RtlDeleteRegistryValue(RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP,
|
|
Extension->DeviceName.Buffer);
|
|
//************************************
|
|
//Error Injection
|
|
//status = STATUS_INVALID_PARAMETER;
|
|
//************************************
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
CyyLogError(
|
|
Extension->DeviceObject->DriverObject,
|
|
Extension->DeviceObject,
|
|
Extension->OriginalBoardMemory,
|
|
CyyPhysicalZero,
|
|
0,
|
|
0,
|
|
0,
|
|
Extension->PortIndex+1,
|
|
status,
|
|
CYY_NO_DEVICE_MAP_DELETED,
|
|
Extension->DeviceName.Length+sizeof(WCHAR),
|
|
Extension->DeviceName.Buffer,
|
|
0,
|
|
NULL
|
|
);
|
|
CyyDbgPrintEx(CYYERRORS, "Couldn't delete value entry %wZ\n",
|
|
&Extension->DeviceName);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|