Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2077 lines
73 KiB

#include "precomp.h" // Precompiled header
/****************************************************************************************
* *
* Module: SPX_PNP.C *
* *
* Creation: 27th September 1998 *
* *
* Author: Paul Smith *
* *
* Version: 1.0.0 *
* *
* Description: Generic Plug and Play Functions to handle PnP IRPS. *
* *
****************************************************************************************/
/* History...
1.0.0 27/09/98 PBS Creation.
*/
#define FILE_ID SPX_PNP_C // File ID for Event Logging see SPX_DEFS.H for values.
/*****************************************************************************
******************************* *******************************
******************************* Prototypes *******************************
******************************* *******************************
*****************************************************************************/
NTSTATUS Spx_Card_FDO_DispatchPnp(IN PDEVICE_OBJECT pFDO,IN PIRP pIrp);
NTSTATUS Spx_Card_StartDevice(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp);
NTSTATUS Spx_Card_StopDevice(IN PCARD_DEVICE_EXTENSION pCard);
NTSTATUS Spx_Card_RemoveDevice(IN PDEVICE_OBJECT pDevObject);
NTSTATUS Spx_CallDriverBelow(IN PDEVICE_OBJECT pLowerDevObj,IN PIRP pIrp);
NTSTATUS Spx_Port_PDO_DispatchPnp(IN PDEVICE_OBJECT pPDO,IN PIRP pIrp);
NTSTATUS Spx_Port_StartDevice(IN PDEVICE_OBJECT pDevObject);
NTSTATUS Spx_Port_StopDevice(IN PPORT_DEVICE_EXTENSION pPort);
NTSTATUS Spx_Port_RemoveDevice(IN PDEVICE_OBJECT pDevObject);
NTSTATUS Spx_EnumPorts(IN PDEVICE_OBJECT pDevObject);
NTSTATUS Spx_DoExternalNaming(IN PDEVICE_OBJECT pDevObject);
NTSTATUS Spx_GetExternalName(IN PDEVICE_OBJECT pDevObject);
NTSTATUS Spx_RemoveExternalNaming(IN PDEVICE_OBJECT pDevObject);
// Paging...
#ifdef ALLOC_PRAGMA
#pragma alloc_text (PAGE, Spx_AddDevice)
#pragma alloc_text (PAGE, Spx_DispatchPnp)
#pragma alloc_text (PAGE, Spx_Card_FDO_DispatchPnp)
#pragma alloc_text (PAGE, Spx_Card_StartDevice)
#pragma alloc_text (PAGE, Spx_Card_StopDevice)
#pragma alloc_text (PAGE, Spx_Card_RemoveDevice)
#pragma alloc_text (PAGE, Spx_CallDriverBelow)
#pragma alloc_text (PAGE, Spx_Port_PDO_DispatchPnp)
#pragma alloc_text (PAGE, Spx_Port_StartDevice)
#pragma alloc_text (PAGE, Spx_Port_StopDevice)
#pragma alloc_text (PAGE, Spx_Port_RemoveDevice)
#pragma alloc_text (PAGE, Spx_EnumPorts)
#pragma alloc_text (PAGE, Spx_DoExternalNaming)
#pragma alloc_text (PAGE, Spx_GetExternalName)
#pragma alloc_text (PAGE, Spx_RemoveExternalNaming)
#pragma alloc_text (PAGE, Spx_CreatePortInstanceID)
#endif
#include <initguid.h>
#include <ntddser.h>
/*****************************************************************************
***************************** ******************************
***************************** Spx_AddDevice ******************************
***************************** ******************************
******************************************************************************
prototype: NTSTATUS Spx_AddDevice(IN PDRIVER_OBJECT pDriverObject,IN PDEVICE_OBJECT pPDO)
description: Create a functional device object (FDO) for the specified card physical device object.
parameters: pDriver point to the driver object
pPDO points to a card physical device object (PDO)
returns: STATUS_SUCCESS
STATUS_NO_MORE_ENTRIES
*/
NTSTATUS Spx_AddDevice(IN PDRIVER_OBJECT pDriverObject,IN PDEVICE_OBJECT pPDO)
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_OBJECT pDevObject = NULL;
PCARD_DEVICE_EXTENSION pCard = NULL;
PDEVICE_OBJECT pLowerDevObject = NULL;
static ULONG CardNumber = 0;
ULONG i = 0;
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
SpxDbgMsg(SPX_TRACE_CALLS, ("%s: Entering Spx_AddDevice.\n", PRODUCT_NAME));
if(pPDO == NULL)
{
SpxDbgMsg(SPX_MISC_DBG, ("%s: In Spx_AddDevice - No more entries.\n", PRODUCT_NAME));
return(STATUS_NO_MORE_ENTRIES);
}
/* Create the device object... */
status = IoCreateDevice(pDriverObject,
sizeof(CARD_DEVICE_EXTENSION),
NULL, // Doesn't need a name.
FILE_DEVICE_CONTROLLER,
FILE_DEVICE_SECURE_OPEN,
TRUE,
&pDevObject);
if(!SPX_SUCCESS(status))
{
CHAR szErrorMsg[MAX_ERROR_LOG_INSERT]; // Limited to 51 characters + 1 null
SpxDbgMsg(SPX_ERRORS,("%s: Create Device failed for card %d. CardExt at 0x%X.\n",
PRODUCT_NAME,CardNumber++,&pDevObject));
sprintf(szErrorMsg, "Card %d: Failed IoCreateDevice.", CardNumber++);
Spx_LogMessage( STATUS_SEVERITY_ERROR,
pDriverObject, // Driver Object
NULL, // Device Object (Optional)
PhysicalZero, // Physical Address 1
PhysicalZero, // Physical Address 2
0, // SequenceNumber
0, // Major Function Code
0, // RetryCount
FILE_ID | __LINE__, // UniqueErrorValue
STATUS_SUCCESS, // FinalStatus
szErrorMsg); // Error Message
if(pDevObject) // Clean up Device Object
IoDeleteDevice(pDevObject);
SpxDbgMsg(SPX_ERRORS, ("%s: Leaving Spx_AddDevice - FAILURE.\n", PRODUCT_NAME));
return(status);
}
ASSERT(pDevObject != NULL);
/* Initialise the device extension... */
pCard = pDevObject->DeviceExtension; /* Point to card extension */
RtlZeroMemory(pCard,sizeof(CARD_DEVICE_EXTENSION)); /* Zero extension structure */
pDevObject->Flags |= DO_POWER_PAGABLE; // Get power IRPs at IRQL PASSIVE_LEVEL
pDevObject->Flags &= ~DO_DEVICE_INITIALIZING;
pLowerDevObject = IoAttachDeviceToDeviceStack(pDevObject,pPDO); /* Attach to device stack */
ASSERT(pLowerDevObject != NULL);
KeInitializeSpinLock(&pCard->PnpPowerFlagsLock); /* Initialise the PNP flags lock */
ClearPnpPowerFlags(pCard,PPF_STARTED); /* Not started yet */
ClearPnpPowerFlags(pCard,PPF_STOP_PENDING); /* Not pending a stop */
ClearPnpPowerFlags(pCard,PPF_REMOVE_PENDING); /* Not pending a remove */
pCard->IsFDO = TRUE; /* Card Object is a Functional Device Object (FDO) */
pCard->CardNumber = CardNumber++; /* Enumerate card devices */
pCard->DeviceObject = pDevObject; /* Back pointer to device object */
pCard->LowerDeviceObject= pLowerDevObject; /* Pointer to device below in device stack */
pCard->DriverObject = pDriverObject; /* Pointer to driver object */
pCard->PDO = pPDO; /* Pointer to card physical device object (PDO) */
pCard->DeviceState = PowerDeviceD0; /* Initial power state */
pCard->SystemState = PowerSystemWorking; /* System in full power State */
pCard->NumPDOs = 0; /* Initialise attached port PDO pointers */
for(i=0; i<PRODUCT_MAX_PORTS; i++)
pCard->AttachedPDO[i] = NULL;
SetPnpPowerFlags(pCard,PPF_POWERED); /* Initially assumed we are powered */
XXX_CardInit(pCard); /* Initialise non-hardware extension fields */
SpxDbgMsg(SPX_TRACE_CALLS,("%s: Leaving Spx_AddDevice - SUCCESS.\n",PRODUCT_NAME));
return(status);
} /* Spx_AddDevice */
/*****************************************************************************
**************************** *****************************
**************************** Spx_DispatchPnp *****************************
**************************** *****************************
******************************************************************************
prototype: NTSTATUS Spx_DispatchPnp(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp)
description: The plug and play dispatch routine.
Determines whether IRP is for a card or a port and calls other functions to handle it.
parameters: pDevObject points to a device object for this driver
pIrp points to the Plug and Play I/O Request (IRP) to be processed
returns: NT Status Code
*/
NTSTATUS Spx_DispatchPnp(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp)
{
PCOMMON_OBJECT_DATA CommonData = (PCOMMON_OBJECT_DATA) pDevObject->DeviceExtension;
NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
if(CommonData->IsFDO) /* Functional Device Object ? */
status = Spx_Card_FDO_DispatchPnp(pDevObject,pIrp); /* Yes, must be card device */
else
status = Spx_Port_PDO_DispatchPnp(pDevObject,pIrp); /* No, must be port device */
return(status);
} /* Spx_DispatchPnp */
/*****************************************************************************
************************ ************************
************************ Spx_Card_FDO_DispatchPnp ************************
************************ ************************
******************************************************************************
prototype: NTSTATUS Spx_Card_FDO_DispatchPnp(IN PDEVICE_OBJECT pFDO,IN PIRP pIrp)
description: The plug and play dispatch routine to handle IRPs for card devices.
parameters: pDevObject points to a card device object for this driver
pIrp points to the Plug and Play I/O Request (IRP) to be processed
returns: NT Status Code
*/
NTSTATUS Spx_Card_FDO_DispatchPnp(IN PDEVICE_OBJECT pFDO,IN PIRP pIrp)
{
PCARD_DEVICE_EXTENSION pCard = pFDO->DeviceExtension;
PDEVICE_OBJECT pLowerDevObj = pCard->LowerDeviceObject;
NTSTATUS status;
PDEVICE_CAPABILITIES pDevCaps = NULL;
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
PDEVICE_RELATIONS pRelations = NULL;
ULONG length = 0;
ULONG i = 0;
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
switch(pIrpStack->MinorFunction)
{
/*****************************************************************************
*************************** IRP_MN_START_DEVICE **************************
*****************************************************************************/
case IRP_MN_START_DEVICE:
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_START_DEVICE Irp for Card %d.\n",
PRODUCT_NAME,pCard->CardNumber));
/* Call driver below first... */
status = Spx_CallDriverBelow(pLowerDevObj,pIrp);
/* If successful, then start the card... */
if(NT_SUCCESS(status)) // Must use NT_SUCCESS() here!!
status = Spx_Card_StartDevice(pFDO,pIrp); /* Start the card */
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
break;
/*****************************************************************************
********************** IRP_MN_QUERY_DEVICE_RELATIONS *********************
*****************************************************************************/
case IRP_MN_QUERY_DEVICE_RELATIONS:
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_DEVICE_RELATIONS Irp for Card %d.\n",
PRODUCT_NAME,pCard->CardNumber));
if(pIrpStack->Parameters.QueryDeviceRelations.Type != BusRelations) /* Only handle BusRelations */
{
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: IRP_MN_QUERY_DEVICE_RELATIONS for Card - Non bus.\n",PRODUCT_NAME));
IoSkipCurrentIrpStackLocation(pIrp);
status = IoCallDriver(pLowerDevObj,pIrp);
break;
}
/* Enumerate devices on the card... */
Spx_EnumPorts(pFDO); /* Enumerate and create port device objects */
/* Tell the Plug and Play Manager any found ports... */
i = 0;
if(pIrp->IoStatus.Information) /* Get current device object count */
i = ((PDEVICE_RELATIONS)pIrp->IoStatus.Information)->Count;
length = sizeof(DEVICE_RELATIONS)+((pCard->NumPDOs+i)*sizeof(PDEVICE_OBJECT));
if(pRelations = SpxAllocateMem(NonPagedPool, length))/* Allocate new structure */
{
/* Copy in the device objects so far... */
if(i)
RtlCopyMemory
(
pRelations->Objects,
((PDEVICE_RELATIONS)pIrp->IoStatus.Information)->Objects,
i * sizeof (PDEVICE_OBJECT)
);
pRelations->Count = i; /* Update device count */
/* Add specialix ports to the device relations... */
if(pCard->NumPDOs)
{
for(i=0; i<PRODUCT_MAX_PORTS; i++)
{
if(pCard->AttachedPDO[i]) /* If object exists */
{ /* add to table */
pRelations->Objects[pRelations->Count++] = pCard->AttachedPDO[i];
ObReferenceObject(pCard->AttachedPDO[i]);
}
}
}
if(pIrp->IoStatus.Information != 0) /* If previous structure */
SpxFreeMem((PVOID)pIrp->IoStatus.Information); /* then free */
pIrp->IoStatus.Information = (ULONG_PTR)pRelations; /* Set new structure */
}
else
{
CHAR szErrorMsg[MAX_ERROR_LOG_INSERT]; // Limited to 51 characters + 1 null
sprintf(szErrorMsg, "Card at %08X%08X: Insufficient resources.", pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
Spx_LogMessage( STATUS_SEVERITY_ERROR,
pCard->DriverObject, // Driver Object
pCard->DeviceObject, // Device Object (Optional)
PhysicalZero, // Physical Address 1
PhysicalZero, // Physical Address 2
0, // SequenceNumber
pIrpStack->MajorFunction, // Major Function Code
0, // RetryCount
FILE_ID | __LINE__, // UniqueErrorValue
STATUS_SUCCESS, // FinalStatus
szErrorMsg); // Error Message
}
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation(pIrp); /* Copy parameters to next stack */
status = IoCallDriver(pLowerDevObj,pIrp); /* Call driver below */
break;
/*****************************************************************************
********************** IRP_MN_QUERY_PNP_DEVICE_STATE *********************
*****************************************************************************/
case IRP_MN_QUERY_PNP_DEVICE_STATE:
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_PNP_DEVICE_STATE Irp for Card %d.\n",
PRODUCT_NAME,pCard->CardNumber));
IoSkipCurrentIrpStackLocation(pIrp);
status = IoCallDriver(pLowerDevObj,pIrp);
break;
/*****************************************************************************
************************ IRP_MN_QUERY_CAPABILITIES ***********************
*****************************************************************************/
case IRP_MN_QUERY_CAPABILITIES:
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_CAPABILITIES Irp for Card %d.\n",
PRODUCT_NAME,pCard->CardNumber));
IoSkipCurrentIrpStackLocation(pIrp);
status = IoCallDriver(pLowerDevObj,pIrp);
break;
/*****************************************************************************
************************ IRP_MN_QUERY_STOP_DEVICE ************************
*****************************************************************************/
case IRP_MN_QUERY_STOP_DEVICE:
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_STOP_DEVICE Irp for Card %d.\n",
PRODUCT_NAME,pCard->CardNumber));
status = STATUS_SUCCESS;
SetPnpPowerFlags(pCard,PPF_STOP_PENDING); // We must now expect a STOP IRP
if(SPX_SUCCESS(status)) // If we can stop, pass IRP on down
{
pIrp->IoStatus.Status = status;
IoSkipCurrentIrpStackLocation(pIrp);
status = IoCallDriver(pLowerDevObj,pIrp);
}
else // If we can't then complete
{
pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
}
break;
/*****************************************************************************
************************ IRP_MN_CANCEL_STOP_DEVICE ***********************
*****************************************************************************/
case IRP_MN_CANCEL_STOP_DEVICE:
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_CANCEL_STOP_DEVICE Irp for Card %d.\n",
PRODUCT_NAME,pCard->CardNumber));
/* Call driver below first... */
status = Spx_CallDriverBelow(pLowerDevObj,pIrp);
if(NT_SUCCESS(status))
{
// we return the device to its working state here.
ClearPnpPowerFlags(pCard,PPF_STOP_PENDING); // We are no longer expecting a STOP IRP.
status = STATUS_SUCCESS;
}
pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
break;
/*****************************************************************************
**************************** IRP_MN_STOP_DEVICE **************************
*****************************************************************************/
case IRP_MN_STOP_DEVICE:
SpxDbgMsg(SPX_TRACE_PNP_IRPS, ("%s: Got IRP_MN_STOP_DEVICE Irp for Card %d.\n",
PRODUCT_NAME, pCard->CardNumber));
Spx_Card_StopDevice(pCard); /* Stop the card hardware */
pIrp->IoStatus.Status = STATUS_SUCCESS; /* Cannot fail this request */
IoSkipCurrentIrpStackLocation(pIrp);
status = IoCallDriver(pLowerDevObj,pIrp);
break;
/*****************************************************************************
************************ IRP_MN_QUERY_REMOVE_DEVICE **********************
*****************************************************************************/
case IRP_MN_QUERY_REMOVE_DEVICE:
SpxDbgMsg(SPX_TRACE_PNP_IRPS, ("%s: Got IRP_MN_QUERY_REMOVE_DEVICE Irp for Card %d.\n",
PRODUCT_NAME, pCard->CardNumber));
status = STATUS_SUCCESS;
if(SPX_SUCCESS(status)) // If we can stop, pass IRP on down
{
SetPnpPowerFlags(pCard,PPF_REMOVE_PENDING); // We are now ready to remove the card
pIrp->IoStatus.Status = status;
IoSkipCurrentIrpStackLocation(pIrp);
status = IoCallDriver(pLowerDevObj,pIrp);
}
else // If we can't then complete
{
pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
}
break;
/*****************************************************************************
*********************** IRP_MN_CANCEL_REMOVE_DEVICE **********************
*****************************************************************************/
case IRP_MN_CANCEL_REMOVE_DEVICE:
SpxDbgMsg(SPX_TRACE_PNP_IRPS, ("%s: Got IRP_MN_CANCEL_REMOVE_DEVICE Irp for Card %d.\n",
PRODUCT_NAME, pCard->CardNumber));
/* Call driver below first... */
status = Spx_CallDriverBelow(pLowerDevObj,pIrp);
if(NT_SUCCESS(status))
{
ClearPnpPowerFlags(pCard,PPF_REMOVE_PENDING); // We are no longer expecting to remove the device.
}
pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
break;
/*****************************************************************************
************************* IRP_MN_SURPRISE_REMOVAL ************************
*****************************************************************************/
case IRP_MN_SURPRISE_REMOVAL:
SpxDbgMsg(SPX_TRACE_PNP_IRPS, ("%s: Got IRP_MN_SURPRISE_REMOVAL Irp for Card %d.\n",
PRODUCT_NAME, pCard->CardNumber));
status = Spx_Card_StopDevice(pCard); // Lets stop the port ready for the REMOVE IRP if we are not already.
SetPnpPowerFlags(pCard,PPF_REMOVE_PENDING); // We are now ready to remove the card
pIrp->IoStatus.Status = status;
IoSkipCurrentIrpStackLocation(pIrp);
status = IoCallDriver(pLowerDevObj,pIrp);
break;
/*****************************************************************************
************************** IRP_MN_REMOVE_DEVICE **************************
*****************************************************************************/
case IRP_MN_REMOVE_DEVICE:
SpxDbgMsg(SPX_TRACE_PNP_IRPS, ("%s: Got IRP_MN_REMOVE_DEVICE Irp for Card %d.\n",
PRODUCT_NAME, pCard->CardNumber));
status = Spx_Card_RemoveDevice(pFDO);
pIrp->IoStatus.Status = status;
IoSkipCurrentIrpStackLocation(pIrp);
status = IoCallDriver(pLowerDevObj,pIrp);
break;
default:
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got PnP Irp - MinorFunction=0x%02X for Card %d.\n",
PRODUCT_NAME,pIrpStack->MinorFunction,pCard->CardNumber));
IoSkipCurrentIrpStackLocation(pIrp);
status = IoCallDriver(pLowerDevObj,pIrp);
break;
}
return(status);
} /* Spx_Card_FDO_DispatchPnp */
/*****************************************************************************
************************** ***************************
************************** Spx_CallDriverBelow ***************************
************************** ***************************
******************************************************************************
prototype: NTSTATUS Spx_CallDriverBelow(IN PDEVICE_OBJECT pLowerDevObj,IN PIRP pIrp)
description: Pass the IRP to the driver below this first and wait for it to complete.
parameters: pLowerDevObj points to a device object for the device below
pIrp points to the Plug and Play I/O Request (IRP) to be processed
returns: NT Status Code
*/
NTSTATUS Spx_CallDriverBelow(IN PDEVICE_OBJECT pLowerDevObj,IN PIRP pIrp)
{
KEVENT eventWaitLowerDrivers;
NTSTATUS status;
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
IoCopyCurrentIrpStackLocationToNext(pIrp); /* Copy parameters to the stack below */
KeInitializeEvent(&eventWaitLowerDrivers,SynchronizationEvent,FALSE); /* Initialise event if need to wait */
IoSetCompletionRoutine(pIrp,Spx_DispatchPnpPowerComplete,&eventWaitLowerDrivers,TRUE,TRUE,TRUE);
if((status = IoCallDriver(pLowerDevObj,pIrp)) == STATUS_PENDING)
{
KeWaitForSingleObject(&eventWaitLowerDrivers,Executive,KernelMode,FALSE,NULL);
status = pIrp->IoStatus.Status;
}
return(status);
} /* Spx_CallDriverBelow */
/************************************************************************************
************************ *************************
************************ Spx_DispatchPnpPowerComplete *************************
************************ *************************
*************************************************************************************
prototype: NTSTATUS Spx_DispatchPnpPowerComplete(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp,IN PVOID Context)
description: The PnP IRP was completed by the lower-level drivers.
Signal this to whoever registered us.
parameters: pDevObject point to the device completing the IRP
pIrp points to the Plug and Play I/O Request (IRP) to be completed
Context was set when the lower driver was called (actually event)
returns: NT Status Code
*/
NTSTATUS Spx_DispatchPnpPowerComplete(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp,IN PVOID Context)
{
PIO_STACK_LOCATION stack = NULL;
PKEVENT event = (PKEVENT) Context;
NTSTATUS status;
UNREFERENCED_PARAMETER(pDevObject);
SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering DispatchPnpComplete.\n",PRODUCT_NAME));
status = STATUS_SUCCESS;
stack = IoGetCurrentIrpStackLocation(pIrp);
switch(stack->MajorFunction)
{
case IRP_MJ_PNP:
switch(stack->MinorFunction)
{
case IRP_MN_START_DEVICE: // Codes which need processing after lower drivers
case IRP_MN_QUERY_CAPABILITIES:
case IRP_MN_CANCEL_STOP_DEVICE:
case IRP_MN_CANCEL_REMOVE_DEVICE:
KeSetEvent(event,0,FALSE); // Wake up waiting process //
return(STATUS_MORE_PROCESSING_REQUIRED);
default:
break;
}
break;
case IRP_MJ_POWER:
KeSetEvent(event, 0, FALSE); // Wake up waiting process
return(STATUS_MORE_PROCESSING_REQUIRED);
default:
break;
}
return(status);
} /* Spx_DispatchPnpPowerComplete */
/*****************************************************************************
************************** **************************
************************** Spx_Card_StartDevice **************************
************************** **************************
******************************************************************************
prototype: NTSTATUS Spx_Card_StartDevice(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp)
description: Start the card device:
Process resources (interrupt, I/O, memory)
Initialise and start the hardware
parameters: pDevObject point to the card device to start
pIrp points to the start I/O Request (IRP)
returns: NT Status Code
*/
NTSTATUS Spx_Card_StartDevice(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp)
{
PCARD_DEVICE_EXTENSION pCard = pDevObject->DeviceExtension;
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering Spx_Card_StartDevice for Card %d.\n",PRODUCT_NAME,pCard->CardNumber));
/* Translate the card resources... */
status = XXX_CardGetResources( pDevObject,
pIrpStack->Parameters.StartDevice.AllocatedResources,
pIrpStack->Parameters.StartDevice.AllocatedResourcesTranslated);
if(!SPX_SUCCESS(status))
return(status);
/* Start the hardware... */
if(!SPX_SUCCESS(status = XXX_CardStart(pCard)))
return(status);
SetPnpPowerFlags(pCard,PPF_STARTED); /* Card has been started */
return(status);
} /* Spx_Card_StartDevice */
/*****************************************************************************
***************************** ******************************
***************************** Spx_EnumPorts ******************************
***************************** ******************************
******************************************************************************
prototype: NTSTATUS Spx_EnumPorts(IN PDEVICE_OBJECT pDevObject)
description: Enumerate port devices found on the card device:
parameters: pDevObject point to the card device to enumerate
returns: NT Status Code
*/
NTSTATUS Spx_EnumPorts(IN PDEVICE_OBJECT pDevObject)
{
PCARD_DEVICE_EXTENSION pCard = pDevObject->DeviceExtension;
PPORT_DEVICE_EXTENSION pPort = NULL;
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_OBJECT PortPDO = NULL;
UNICODE_STRING PortPDOName;
static ULONG CurrentInstance = 0;
UNICODE_STRING InstanceStr;
WCHAR InstanceNumberBuffer[10];
POWER_STATE PowerState;
USHORT PortNumber = 0;
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering Spx_EnumPorts for Card %d.\n",PRODUCT_NAME,pCard->CardNumber));
// Name and create device objects for each port on the card...
for(PortNumber=0;PortNumber<pCard->NumberOfPorts;PortNumber++)
{
if(pCard->AttachedPDO[PortNumber] == NULL) // Only create if not already present
{
// Create the base port name ("XxPort")...
RtlZeroMemory(&PortPDOName, sizeof(UNICODE_STRING));
PortPDOName.MaximumLength = DEVICE_OBJECT_NAME_LENGTH * sizeof(WCHAR);
PortPDOName.Buffer = SpxAllocateMem(PagedPool, PortPDOName.MaximumLength+sizeof(WCHAR));
if(PortPDOName.Buffer == NULL) continue;
RtlZeroMemory(PortPDOName.Buffer, PortPDOName.MaximumLength+sizeof(WCHAR));
RtlAppendUnicodeToString(&PortPDOName, PORT_PDO_NAME_BASE);
// Create the instance ("0")...
RtlInitUnicodeString(&InstanceStr,NULL);
InstanceStr.MaximumLength = sizeof(InstanceNumberBuffer);
InstanceStr.Buffer = InstanceNumberBuffer;
RtlIntegerToUnicodeString(CurrentInstance++, 10, &InstanceStr);
// Append instance to the device name ("XxPort0")...
RtlAppendUnicodeStringToString(&PortPDOName, &InstanceStr);
// Create the port device object with this name...
status = IoCreateDevice(pDevObject->DriverObject,
sizeof(PORT_DEVICE_EXTENSION),
&PortPDOName, // Object Name
FILE_DEVICE_SERIAL_PORT,
FILE_DEVICE_SECURE_OPEN,
TRUE,
&PortPDO);
if(!SPX_SUCCESS(status))
{
SpxDbgMsg(SPX_ERRORS,("%s: Create Device failed = %wZ\n",PRODUCT_NAME,&PortPDOName));
SpxFreeMem(PortPDOName.Buffer);
continue;
}
ASSERT(PortPDO != NULL);
// Increment the pdo's stacksize so that it can pass irps through...
PortPDO->StackSize += pDevObject->StackSize;
// Keep a pointer to the device in the card structure...
pCard->NumPDOs++;
pCard->AttachedPDO[PortNumber] = PortPDO;
ObReferenceObject(PortPDO);
// Initialise port device object and extension...
pPort = PortPDO->DeviceExtension;
RtlZeroMemory(pPort,sizeof(PORT_DEVICE_EXTENSION)); // Clear the device extension
pPort->DeviceName = PortPDOName;
KeInitializeSpinLock(&pPort->PnpPowerFlagsLock); // Initialise the PNP flags lock
ClearPnpPowerFlags(pPort,PPF_STARTED); // Not started yet
ClearPnpPowerFlags(pPort,PPF_STOP_PENDING); // Not pending a stop
ClearPnpPowerFlags(pPort,PPF_REMOVE_PENDING); // Not pending a remove
ClearPnpPowerFlags(pPort,PPF_REMOVED); // Not removed
SetPnpPowerFlags(pPort,PPF_POWERED); // Initially powered up
InitializeListHead(&pPort->StalledIrpQueue); // Initialise the stalled IRP list
KeInitializeSpinLock(&pPort->StalledIrpLock); // Initialise the StalledIrpLock flags lock
pPort->UnstallingFlag = FALSE; // Initialise UnstallingIrps Flag.
pPort->IsFDO = FALSE;
pPort->PortNumber = PortNumber; // system port number
pPort->UniqueInstanceID = FALSE; // Instance ID not unique by default.
pPort->DeviceIsOpen = FALSE; // Port is closed to start with
pPort->DeviceObject = PortPDO; // Backpointer to device object
pPort->DeviceState = PowerDeviceD0; // Port device in full power state
pPort->SystemState = PowerSystemWorking; // System in full power State
pPort->pParentCardExt = pCard; // Point to the parent card extension
ExInitializeFastMutex(&pPort->OpenMutex);
if(!SPX_SUCCESS(status = XXX_PortInit(pPort))) // Initialise hardware
continue;
// Inform Power Manager the of the new power state.
PowerState.DeviceState = pPort->DeviceState;
PoSetPowerState(pPort->DeviceObject, DevicePowerState, PowerState);
PortPDO->Flags &= ~DO_DEVICE_INITIALIZING; // Finished Initialising
PortPDO->Flags |= DO_BUFFERED_IO; // Do Buffered IO
PortPDO->Flags |= DO_BUS_ENUMERATED_DEVICE; // Bus enumerated
PortPDO->Flags |= DO_POWER_PAGABLE; // Get power IRPs at IRQL PASSIVE_LEVEL
}
else
{
PortPDO = pCard->AttachedPDO[PortNumber];
pPort = PortPDO->DeviceExtension;
if(pPort->PnpPowerFlags & PPF_REMOVED)
ClearPnpPowerFlags(pPort,PPF_REMOVED);
}
}
return(status);
} // End Spx_EnumPorts
/*****************************************************************************
************************** ***************************
************************** Spx_Card_StopDevice ***************************
************************** ***************************
******************************************************************************
prototype: NTSTATUS Spx_Card_StopDevice(IN PCARD_DEVICE_EXTENSION pCard)
description: Stop the card device:
Stop the hardware
Deinitialise card resources (interrupt, I/O, memory)
parameters: pCard points to the card device to stop
returns: NT Status Code
*/
NTSTATUS Spx_Card_StopDevice(IN PCARD_DEVICE_EXTENSION pCard)
{
NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering Spx_Card_StopDevice for Card %d.\n",PRODUCT_NAME,pCard->CardNumber));
if(pCard->PnpPowerFlags & PPF_STARTED) /* If card is running */
{
XXX_CardStop(pCard); /* Stop the card */
}
ClearPnpPowerFlags(pCard,PPF_STARTED); /* Indicate card is stopped */
ClearPnpPowerFlags(pCard,PPF_STOP_PENDING); /* Clear stop pending flag */
return(status);
} /* Spx_Card_StopDevice */
/*****************************************************************************
************************* **************************
************************* Spx_Card_RemoveDevice **************************
************************* **************************
******************************************************************************
prototype: NTSTATUS Spx_Card_RemoveDevice(IN PDEVICE_OBJECT pDevObject)
description: Remove the card device:
Deallocate any resources
Delete device object
parameters: pDevObject points to the card device object to remove
returns: NT Status Code
*/
NTSTATUS Spx_Card_RemoveDevice(IN PDEVICE_OBJECT pDevObject)
{
PCARD_DEVICE_EXTENSION pCard = pDevObject->DeviceExtension;
PDEVICE_OBJECT pPortPdo;
PPORT_DEVICE_EXTENSION pPort;
NTSTATUS status = STATUS_SUCCESS;
int loop;
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
SpxDbgMsg(SPX_TRACE_CALLS, ("%s: Entering Spx_Card_RemoveDevice for Card %d.\n",
PRODUCT_NAME, pCard->CardNumber));
/* First remove all "removed" port device objects... */
for(loop=0; loop<PRODUCT_MAX_PORTS; loop++)
{
if(pPortPdo = pCard->AttachedPDO[loop]) /* Enumerated port PDO ? */
{
pPort = pPortPdo->DeviceExtension; /* Get the device extension */
XXX_PortDeInit(pPort); /* Deinitialise port structure */
if(pPort->DeviceName.Buffer)
{
SpxFreeMem(pPort->DeviceName.Buffer); /* Free device name buffer */
pPort->DeviceName.Buffer = NULL;
}
pCard->AttachedPDO[loop] = NULL; /* Remove the port PDO pointer */
pCard->NumPDOs--; /* One less port attached */
IoDeleteDevice(pPortPdo); /* Delete the port device object */
ObDereferenceObject(pPortPdo); /* Dereference the object */
}
}
/* Now, remove the card device object... */
Spx_Card_StopDevice(pCard); /* Stop the card and release resources */
XXX_CardDeInit(pCard); /* Deinitialise non-hardware fields */
IoDetachDevice(pCard->LowerDeviceObject); /* Detach card device from the device stack. */
IoDeleteDevice(pDevObject); /* Delete Card FDO from system. */
return(status);
} /* Spx_Card_RemoveDevice */
/*****************************************************************************
************************ ************************
************************ Spx_Port_PDO_DispatchPnp ************************
************************ ************************
******************************************************************************
prototype: NTSTATUS Spx_Port_PDO_DispatchPnp(IN PDEVICE_OBJECT pPDO,IN PIRP pIrp)
description: The plug and play dispatch routine to handle IRPs for port devices.
parameters: pDevObject points to a port device object for this driver
pIrp points to the Plug and Play I/O Request (IRP) to be processed
returns: NT Status Code
*/
NTSTATUS Spx_Port_PDO_DispatchPnp(IN PDEVICE_OBJECT pPDO,IN PIRP pIrp)
{
PPORT_DEVICE_EXTENSION pPort = pPDO->DeviceExtension;
PCARD_DEVICE_EXTENSION pCard = pPort->pParentCardExt;
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
NTSTATUS status;
PWCHAR ReturnBuffer = NULL;
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
status = pIrp->IoStatus.Status;
switch (pIrpStack->MinorFunction)
{
/*****************************************************************************
*************************** IRP_MN_START_DEVICE **************************
*****************************************************************************/
case IRP_MN_START_DEVICE:
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_START_DEVICE Irp for Port %d.\n",
PRODUCT_NAME,pPort->PortNumber));
status = STATUS_UNSUCCESSFUL;
if(SPX_SUCCESS(status = Spx_Port_StartDevice(pPDO)))
Spx_UnstallIrps(pPort); // Restart any queued IRPs (from a previous start)
break;
/*****************************************************************************
***************************** IRP_MN_QUERY_ID ****************************
*****************************************************************************/
case IRP_MN_QUERY_ID:
{
PUNICODE_STRING pId = NULL;
CHAR szErrorMsg[MAX_ERROR_LOG_INSERT]; // Limited to 51 characters + 1 null
switch(pIrpStack->Parameters.QueryId.IdType)
{
case BusQueryCompatibleIDs:
case BusQueryDeviceID:
case BusQueryInstanceID:
case BusQueryHardwareIDs:
{
status = STATUS_SUCCESS;
switch(pIrpStack->Parameters.QueryId.IdType)
{
case BusQueryDeviceID:
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_ID - BusQueryDeviceID Irp for Port %d.\n",
PRODUCT_NAME,pPort->PortNumber));
SpxDbgMsg(SPX_MISC_DBG,("%s: Device ID %wZ.\n", PRODUCT_NAME,&pPort->DeviceID));
pId = &pPort->DeviceID;
break;
case BusQueryInstanceID:
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_ID - BusQueryInstanceID Irp for Port %d.\n",
PRODUCT_NAME, pPort->PortNumber));
SpxDbgMsg(SPX_MISC_DBG,("%s: Instance ID %wZ.\n",PRODUCT_NAME,&pPort->InstanceID));
pId = &pPort->InstanceID;
break;
case BusQueryCompatibleIDs:
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_ID - BusQueryCompatibleIDs Irp for Port %d.\n",
PRODUCT_NAME, pPort->PortNumber));
pId = &pPort->CompatibleIDs;
break;
case BusQueryHardwareIDs:
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_ID - BusQueryHardwareIDs Irp for Port %d.\n",
PRODUCT_NAME, pPort->PortNumber));
pId = &pPort->HardwareIDs;
break;
default:
break;
}
if(pId)
{
if(pId->Buffer)
{
if(ReturnBuffer = SpxAllocateMem(PagedPool, pId->Length + sizeof(WCHAR)))
RtlCopyMemory(ReturnBuffer, pId->Buffer, pId->Length + sizeof(WCHAR));
else
{
sprintf(szErrorMsg, "Port %d on card at %08X%08X: Insufficient resources",
pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
Spx_LogMessage( STATUS_SEVERITY_ERROR,
pPort->DriverObject, // Driver Object
pPort->DeviceObject, // Device Object (Optional)
PhysicalZero, // Physical Address 1
PhysicalZero, // Physical Address 2
0, // SequenceNumber
pIrpStack->MajorFunction, // Major Function Code
0, // RetryCount
FILE_ID | __LINE__, // UniqueErrorValue
STATUS_SUCCESS, // FinalStatus
szErrorMsg); // Error Message
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
pIrp->IoStatus.Information = (ULONG_PTR)ReturnBuffer;
}
break;
}
default:
break;
}
break;
}
/*****************************************************************************
************************* IRP_MN_QUERY_DEVICE_TEXT ***********************
*****************************************************************************/
case IRP_MN_QUERY_DEVICE_TEXT:
{
PUNICODE_STRING pText = NULL;
CHAR szErrorMsg[MAX_ERROR_LOG_INSERT]; // Limited to 51 characters + 1 null
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_DEVICE_TEXT Irp for Port %d.\n",
PRODUCT_NAME,pPort->PortNumber));
if(pIrpStack->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription)
pText = &pPort->DevDesc;
if(pIrpStack->Parameters.QueryDeviceText.DeviceTextType == DeviceTextLocationInformation)
pText = &pPort->DevLocation;
if((pText == NULL)||(pText->Buffer == NULL))
break;
if(!(ReturnBuffer = SpxAllocateMem(PagedPool, pText->Length + sizeof(WCHAR))))
{
sprintf(szErrorMsg, "Port %d on card at %08X%08X: Insufficient resources",
pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
Spx_LogMessage( STATUS_SEVERITY_ERROR,
pPort->DriverObject, // Driver Object
pPort->DeviceObject, // Device Object (Optional)
PhysicalZero, // Physical Address 1
PhysicalZero, // Physical Address 2
0, // SequenceNumber
pIrpStack->MajorFunction, // Major Function Code
0, // RetryCount
FILE_ID | __LINE__, // UniqueErrorValue
STATUS_SUCCESS, // FinalStatus
szErrorMsg); // Error Message
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
status = STATUS_SUCCESS;
RtlCopyMemory(ReturnBuffer, pText->Buffer, pText->Length + sizeof(WCHAR));
pIrp->IoStatus.Information = (ULONG_PTR)ReturnBuffer;
break;
}
/*****************************************************************************
************************ IRP_MN_QUERY_CAPABILITIES ***********************
*****************************************************************************/
case IRP_MN_QUERY_CAPABILITIES:
{
PDEVICE_CAPABILITIES pDevCaps = NULL;
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_CAPABILITIES Irp for Port %d.\n",
PRODUCT_NAME,pPort->PortNumber));
// Get the packet
pDevCaps = pIrpStack->Parameters.DeviceCapabilities.Capabilities;
// Set the capabilities.
pDevCaps->Version = 1;
pDevCaps->Size = sizeof(DEVICE_CAPABILITIES);
// We cannot wake the system.
pDevCaps->SystemWake = PowerSystemUnspecified;
pDevCaps->DeviceWake = PowerSystemUnspecified;
// Set device state mapping...
pDevCaps->DeviceState[PowerSystemWorking] = PowerDeviceD0;
pDevCaps->DeviceState[PowerSystemSleeping1] = PowerDeviceD3;
pDevCaps->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
pDevCaps->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
pDevCaps->DeviceState[PowerSystemHibernate] = PowerDeviceD3;
pDevCaps->DeviceState[PowerSystemShutdown] = PowerDeviceD3;
// We have no latencies.
pDevCaps->D1Latency = 0;
pDevCaps->D2Latency = 0;
pDevCaps->D3Latency = 0;
// No locking or ejection.
pDevCaps->LockSupported = FALSE;
pDevCaps->EjectSupported = FALSE;
// Removable
pDevCaps->Removable = FALSE;
// Not a Docking device.
pDevCaps->DockDevice = FALSE;
// System wide unique ID.
pDevCaps->UniqueID = pPort->UniqueInstanceID;
//UINumber
pDevCaps->UINumber = pPort->PortNumber+1;
// Raw capable
pDevCaps->RawDeviceOK = TRUE;
// Silent Install
pDevCaps->SilentInstall = FALSE;
// Surprise Removal
pDevCaps->SurpriseRemovalOK = FALSE;
status = STATUS_SUCCESS;
break;
}
/*****************************************************************************
************************ IRP_MN_QUERY_STOP_DEVICE ************************
*****************************************************************************/
case IRP_MN_QUERY_STOP_DEVICE:
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_STOP_DEVICE Irp for Port %d.\n",
PRODUCT_NAME,pPort->PortNumber));
status = STATUS_UNSUCCESSFUL;
if(pPort->PnpPowerFlags & PPF_STARTED)
{
ExAcquireFastMutex(&pPort->OpenMutex);
if(pPort->DeviceIsOpen)
{
ExReleaseFastMutex(&pPort->OpenMutex);
status = STATUS_DEVICE_BUSY;
SpxDbgMsg(SPX_TRACE_PNP_IRPS, ("%s: ------- failing; Port %d open\n",
PRODUCT_NAME, pPort->PortNumber));
}
else
{
SetPnpPowerFlags(pPort,PPF_STOP_PENDING);
status = STATUS_SUCCESS;
ExReleaseFastMutex(&pPort->OpenMutex);
}
}
break;
/*****************************************************************************
************************ IRP_MN_CANCEL_STOP_DEVICE ***********************
*****************************************************************************/
case IRP_MN_CANCEL_STOP_DEVICE:
SpxDbgMsg(SPX_TRACE_PNP_IRPS, ("%s: Got IRP_MN_CANCEL_STOP_DEVICE Irp for Port %d.\n",
PRODUCT_NAME,pPort->PortNumber));
status = STATUS_SUCCESS;
ClearPnpPowerFlags(pPort,PPF_STOP_PENDING); // Clear the stop pending flag
Spx_UnstallIrps(pPort); // Restart any queued IRPs
break;
/*****************************************************************************
*************************** IRP_MN_STOP_DEVICE ***************************
*****************************************************************************/
case IRP_MN_STOP_DEVICE:
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_STOP_DEVICE Irp for Port %d\n",
PRODUCT_NAME,pPort->PortNumber));
status = STATUS_SUCCESS; // we must never fail this IRP (if we do we will probably unload).
status = Spx_Port_StopDevice(pPort);
ClearPnpPowerFlags(pPort,PPF_STOP_PENDING); // Clear the stop pending flag
break;
/*****************************************************************************
*********************** IRP_MN_QUERY_REMOVE_DEVICE ***********************
*****************************************************************************/
case IRP_MN_QUERY_REMOVE_DEVICE:
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_REMOVE_DEVICE Irp for Port %d.\n",
PRODUCT_NAME,pPort->PortNumber));
ExAcquireFastMutex(&pPort->OpenMutex);
if(pPort->DeviceIsOpen)
{
ExReleaseFastMutex(&pPort->OpenMutex);
status = STATUS_DEVICE_BUSY;
SpxDbgMsg(SPX_TRACE_PNP_IRPS, ("%s: ------- failing; Port %d open\n",
PRODUCT_NAME, pPort->PortNumber));
}
else
{
SetPnpPowerFlags(pPort,PPF_REMOVE_PENDING); // We are now ready to remove the port
status = STATUS_SUCCESS;
ExReleaseFastMutex(&pPort->OpenMutex);
}
break;
/*****************************************************************************
*********************** IRP_MN_CANCEL_REMOVE_DEVICE **********************
*****************************************************************************/
case IRP_MN_CANCEL_REMOVE_DEVICE:
SpxDbgMsg(SPX_TRACE_PNP_IRPS, ("%s: Got IRP_MN_CANCEL_REMOVE_DEVICE Irp for Port %d.\n",
PRODUCT_NAME, pPort->PortNumber));
status = STATUS_SUCCESS;
ClearPnpPowerFlags(pPort,PPF_REMOVE_PENDING); // We are no longer expecting to remove the device.
break;
/*****************************************************************************
************************* IRP_MN_SURPRISE_REMOVAL ************************
*****************************************************************************/
case IRP_MN_SURPRISE_REMOVAL:
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_SURPRISE_REMOVAL Irp for Port %d\n",
PRODUCT_NAME,pPort->PortNumber));
status = STATUS_SUCCESS; // we must never fail this IRP (if we do we will probably unload).
status = Spx_Port_StopDevice(pPort);
SetPnpPowerFlags(pPort,PPF_REMOVE_PENDING); // We are now ready to remove the port
break;
/*****************************************************************************
************************** IRP_MN_REMOVE_DEVICE **************************
*****************************************************************************/
case IRP_MN_REMOVE_DEVICE:
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_REMOVE_DEVICE Irp for Port %d\n",
PRODUCT_NAME,pPort->PortNumber));
status = STATUS_SUCCESS; // we must never fail this IRP (if we do we will probably unload).
Spx_KillStalledIRPs(pPDO); // Kill off any waiting IRPS on the stalled list
status = Spx_Port_RemoveDevice(pPDO);
ClearPnpPowerFlags(pPort,PPF_REMOVE_PENDING); // Clear the pending flag
break;
/*****************************************************************************
********************** IRP_MN_QUERY_DEVICE_RELATIONS *********************
*****************************************************************************/
case IRP_MN_QUERY_DEVICE_RELATIONS:
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_DEVICE_RELATIONS Irp for Port %d.\n",
PRODUCT_NAME, pPort->PortNumber));
switch(pIrpStack->Parameters.QueryDeviceRelations.Type)
{
case TargetDeviceRelation:
{
PDEVICE_RELATIONS pDevRel = NULL;
if(pIrp->IoStatus.Information != 0)
break;
if(!(pDevRel = SpxAllocateMem(PagedPool, sizeof(DEVICE_RELATIONS))))
{
CHAR szErrorMsg[MAX_ERROR_LOG_INSERT]; // Limited to 51 characters + 1 null
sprintf(szErrorMsg, "Port %d on card at %08X%08X: Insufficient resources",
pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
Spx_LogMessage( STATUS_SEVERITY_ERROR,
pPort->DriverObject, // Driver Object
pPort->DeviceObject, // Device Object (Optional)
PhysicalZero, // Physical Address 1
PhysicalZero, // Physical Address 2
0, // SequenceNumber
pIrpStack->MajorFunction, // Major Function Code
0, // RetryCount
FILE_ID | __LINE__, // UniqueErrorValue
STATUS_SUCCESS, // FinalStatus
szErrorMsg); // Error Message
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
pDevRel->Count = 1;
pDevRel->Objects[0] = pPDO;
ObReferenceObject(pPDO);
status = STATUS_SUCCESS;
pIrp->IoStatus.Information = (ULONG_PTR)pDevRel;
break;
}
case BusRelations:
{
PDEVICE_RELATIONS pDevRel = NULL;
if(pIrp->IoStatus.Information != 0)
break;
if(!(pDevRel = SpxAllocateMem(PagedPool, sizeof(DEVICE_RELATIONS))))
{
CHAR szErrorMsg[MAX_ERROR_LOG_INSERT]; // Limited to 51 characters + 1 null
sprintf(szErrorMsg, "Port %d on card at %08X%08X: Insufficient resources",
pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
Spx_LogMessage( STATUS_SEVERITY_ERROR,
pPort->DriverObject, // Driver Object
pPort->DeviceObject, // Device Object (Optional)
PhysicalZero, // Physical Address 1
PhysicalZero, // Physical Address 2
0, // SequenceNumber
pIrpStack->MajorFunction, // Major Function Code
0, // RetryCount
FILE_ID | __LINE__, // UniqueErrorValue
STATUS_SUCCESS, // FinalStatus
szErrorMsg); // Error Message
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
pDevRel->Count = 0;
status = STATUS_SUCCESS;
pIrp->IoStatus.Information = (ULONG_PTR)pDevRel;
break;
}
default:
break;
}
break;
default:
SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got PnP Irp - MinorFunction=0x%02X for Port %d.\n",
PRODUCT_NAME,pIrpStack->MinorFunction, pPort->PortNumber));
break;
}
pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return(status);
} /* Spx_Port_PDO_DispatchPnp */
/*****************************************************************************
************************** **************************
************************** Spx_Port_StartDevice **************************
************************** **************************
******************************************************************************
prototype: NTSTATUS Spx_Port_StartDevice(IN PDEVICE_OBJECT pDevObject)
description: Start the port device:
Setup external naming
Initialise and start the hardware
parameters: pDevObject point to the card device to start
pIrp points to the start I/O Request (IRP)
returns: NT Status Code
*/
NTSTATUS Spx_Port_StartDevice(IN PDEVICE_OBJECT pDevObject)
{
PPORT_DEVICE_EXTENSION pPort = pDevObject->DeviceExtension;
NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering Spx_Port_StartDevice for Port %d.\n", PRODUCT_NAME, pPort->PortNumber));
if(!pPort->CreatedSymbolicLink)
{
if(!SPX_SUCCESS(status = Spx_DoExternalNaming(pDevObject))) // Set up external name for device
return(status);
}
if(!SPX_SUCCESS(status = XXX_PortStart(pPort))) // Start hardware.
{
Spx_RemoveExternalNaming(pDevObject); // Remove external naming.
return(status);
}
SetPnpPowerFlags(pPort,PPF_STARTED); // Port has been started.
ClearPnpPowerFlags(pPort,PPF_REMOVED); // Port is not removed...yet.
ClearPnpPowerFlags(pPort,PPF_STOP_PENDING); // Not pending a stop.
ClearPnpPowerFlags(pPort,PPF_REMOVE_PENDING); // Not pending a remove.
return(status);
} // Spx_Port_StartDevice
/*****************************************************************************
************************** **************************
************************** Spx_GetExternalName **************************
************************** **************************
******************************************************************************
prototype: NTSTATUS Spx_GetExternalName(IN PDEVICE_OBJECT pDevObject)
description: Setup external naming for a port:
get Dos Name for port
form symbolic link name
parameters: pDevObject points to the device object for the port to be named
returns: NT Status Code
*/
NTSTATUS Spx_GetExternalName(IN PDEVICE_OBJECT pDevObject)
{
PPORT_DEVICE_EXTENSION pPort = pDevObject->DeviceExtension;
PCARD_DEVICE_EXTENSION pCard = pPort->pParentCardExt;
NTSTATUS status = STATUS_SUCCESS;
HANDLE PnPKeyHandle;
UNICODE_STRING TmpLinkName;
WCHAR *pRegName = NULL;
ULONG BuffLen = 0;
CHAR szErrorMsg[MAX_ERROR_LOG_INSERT]; // Limited to 51 characters + 1 null
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering Spx_GetExternalName for Port %d.\n", PRODUCT_NAME, pPort->PortNumber));
status = IoOpenDeviceRegistryKey(pDevObject, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_READ, &PnPKeyHandle);
if(!SPX_SUCCESS(status))
return(status);
// Get the device name allocated by the PNP manager from the registry...
if(pRegName = SpxAllocateMem(PagedPool,SYMBOLIC_NAME_LENGTH * sizeof(WCHAR) + sizeof(WCHAR)))
{
status = Spx_GetRegistryKeyValue( PnPKeyHandle,
L"PortName",
wcslen(L"PortName") * sizeof(WCHAR),
pRegName,
SYMBOLIC_NAME_LENGTH * sizeof(WCHAR));
}
else
{
status = STATUS_INSUFFICIENT_RESOURCES;
}
ZwClose(PnPKeyHandle);
if(!SPX_SUCCESS(status))
{
if(pRegName != NULL)
SpxFreeMem(pRegName);
return(STATUS_SUCCESS); // Port has not been given a name yet but we must not fail.
}
RtlZeroMemory(&TmpLinkName, sizeof(UNICODE_STRING));
if(!SPX_SUCCESS(status))
goto NamingError;
TmpLinkName.MaximumLength = SYMBOLIC_NAME_LENGTH * sizeof(WCHAR);
TmpLinkName.Buffer = SpxAllocateMem(PagedPool, TmpLinkName.MaximumLength + sizeof(WCHAR));
if(!TmpLinkName.Buffer)
{
sprintf(szErrorMsg, "Port %d on card at %08X%08X Insufficient resources",
pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
Spx_LogMessage( STATUS_SEVERITY_ERROR,
pPort->DriverObject, // Driver Object
pPort->DeviceObject, // Device Object (Optional)
PhysicalZero, // Physical Address 1
PhysicalZero, // Physical Address 2
0, // SequenceNumber
0, // Major Function Code
0, // RetryCount
FILE_ID | __LINE__, // UniqueErrorValue
STATUS_SUCCESS, // FinalStatus
szErrorMsg); // Error Message
status = STATUS_INSUFFICIENT_RESOURCES;
goto NamingError;
}
RtlZeroMemory(TmpLinkName.Buffer, TmpLinkName.MaximumLength + sizeof(WCHAR));
// Create the "\\DosDevices\\<SymbolicName>" string.
RtlAppendUnicodeToString(&TmpLinkName, L"\\");
RtlAppendUnicodeToString(&TmpLinkName, DEFAULT_DIRECTORY);
RtlAppendUnicodeToString(&TmpLinkName, L"\\");
RtlAppendUnicodeToString(&TmpLinkName, pRegName);
pPort->SymbolicLinkName.Length = 0;
pPort->SymbolicLinkName.MaximumLength = TmpLinkName.Length + sizeof(WCHAR);
pPort->SymbolicLinkName.Buffer = SpxAllocateMem(PagedPool, pPort->SymbolicLinkName.MaximumLength);
if(!pPort->SymbolicLinkName.Buffer)
{
sprintf(szErrorMsg, "Port %d on card at %08X%08X: Insufficient resources",
pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
Spx_LogMessage( STATUS_SEVERITY_ERROR,
pPort->DriverObject, // Driver Object
pPort->DeviceObject, // Device Object (Optional)
PhysicalZero, // Physical Address 1
PhysicalZero, // Physical Address 2
0, // SequenceNumber
0, // Major Function Code
0, // RetryCount
FILE_ID | __LINE__, // UniqueErrorValue
STATUS_SUCCESS, // FinalStatus
szErrorMsg); // Error Message
status = STATUS_INSUFFICIENT_RESOURCES;
goto NamingError;
}
RtlZeroMemory(pPort->SymbolicLinkName.Buffer, pPort->SymbolicLinkName.MaximumLength);
RtlAppendUnicodeStringToString(&pPort->SymbolicLinkName, &TmpLinkName);
pPort->DosName.Buffer = SpxAllocateMem(PagedPool, 64 + sizeof(WCHAR));
if(!pPort->DosName.Buffer)
{
sprintf(szErrorMsg, "Port %d on card at %08X%08X:: Insufficient resources",
pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
Spx_LogMessage( STATUS_SEVERITY_ERROR,
pPort->DriverObject, // Driver Object
pPort->DeviceObject, // Device Object (Optional)
PhysicalZero, // Physical Address 1
PhysicalZero, // Physical Address 2
0, // SequenceNumber
0, // Major Function Code
0, // RetryCount
FILE_ID | __LINE__, // UniqueErrorValue
STATUS_SUCCESS, // FinalStatus
szErrorMsg); // Error Message
status = STATUS_INSUFFICIENT_RESOURCES;
goto NamingError;
}
pPort->DosName.MaximumLength = 64 + sizeof(WCHAR);
pPort->DosName.Length = 0;
RtlZeroMemory(pPort->DosName.Buffer, pPort->DosName.MaximumLength);
RtlAppendUnicodeToString(&pPort->DosName, pRegName);
RtlZeroMemory(((PUCHAR) (&pPort->DosName.Buffer[0])) + pPort->DosName.Length, sizeof(WCHAR));
SpxDbgMsg(SPX_MISC_DBG, ("%s: DeviceName is %wZ\n", PRODUCT_NAME, &pPort->DeviceName));
SpxDbgMsg(SPX_MISC_DBG, ("%s: DosName is %wZ\n", PRODUCT_NAME, &pPort->DosName));
SpxDbgMsg(SPX_MISC_DBG, ("%s: SymbolicName is %wZ\n", PRODUCT_NAME, &pPort->SymbolicLinkName));
if(pRegName != NULL)
SpxFreeMem(pRegName); // Free pRegName
if(TmpLinkName.Buffer != NULL)
SpxFreeMem(TmpLinkName.Buffer); // Free TmpLinkName
return(status);
NamingError:;
if(TmpLinkName.Buffer != NULL)
SpxFreeMem(TmpLinkName.Buffer);
if(pRegName != NULL)
SpxFreeMem(pRegName);
return(status);
}
/*****************************************************************************
************************** **************************
************************** Spx_DoExternalNaming **************************
************************** **************************
******************************************************************************
prototype: NTSTATUS Spx_DoExternalNaming(IN PDEVICE_OBJECT pDevObject)
description: Setup external naming for a port:
create symbolic link
add to registry
register and enable interface
parameters: pDevObject points to the device object for the port to be named
returns: NT Status Code
*/
NTSTATUS Spx_DoExternalNaming(IN PDEVICE_OBJECT pDevObject)
{
PPORT_DEVICE_EXTENSION pPort = pDevObject->DeviceExtension;
PCARD_DEVICE_EXTENSION pCard = pPort->pParentCardExt;
NTSTATUS status = STATUS_SUCCESS;
CHAR szErrorMsg[MAX_ERROR_LOG_INSERT]; // Limited to 51 characters + 1 null
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering Spx_DoExternalNaming for Port %d.\n",PRODUCT_NAME,pPort->PortNumber));
// Get external name...
if( !SPX_SUCCESS(status = Spx_GetExternalName(pDevObject)) || (pPort->DosName.Buffer == NULL))
return(status);
status = IoCreateSymbolicLink(&pPort->SymbolicLinkName, &pPort->DeviceName); // Create the symbolic link...
if(!SPX_SUCCESS(status))
{
sprintf(szErrorMsg, "Port %d on card at %08X%08X:: Insufficient resources",
pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
Spx_LogMessage( STATUS_SEVERITY_ERROR,
pPort->DriverObject, // Driver Object
pPort->DeviceObject, // Device Object (Optional)
PhysicalZero, // Physical Address 1
PhysicalZero, // Physical Address 2
0, // SequenceNumber
0, // Major Function Code
0, // RetryCount
FILE_ID | __LINE__, // UniqueErrorValue
STATUS_SUCCESS, // FinalStatus
szErrorMsg); // Error Message
goto ExternalNamingError;
}
// Add mapping to "SERIALCOMM" section of registry...
pPort->CreatedSymbolicLink = TRUE;
status = RtlWriteRegistryValue( RTL_REGISTRY_DEVICEMAP,
L"SERIALCOMM",
pPort->DeviceName.Buffer,
REG_SZ,
pPort->DosName.Buffer,
pPort->DosName.Length + sizeof(WCHAR));
if(!SPX_SUCCESS(status))
{
sprintf(szErrorMsg, "Port %d on card at %08X%08X: Registry error.",
pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
Spx_LogMessage( STATUS_SEVERITY_ERROR,
pPort->DriverObject, // Driver Object
pPort->DeviceObject, // Device Object (Optional)
PhysicalZero, // Physical Address 1
PhysicalZero, // Physical Address 2
0, // SequenceNumber
0, // Major Function Code
0, // RetryCount
FILE_ID | __LINE__, // UniqueErrorValue
STATUS_SUCCESS, // FinalStatus
szErrorMsg); // Error Message
goto ExternalNamingError;
}
status = IoRegisterDeviceInterface( pDevObject, (LPGUID)&GUID_CLASS_COMPORT,
NULL, &pPort->DeviceClassSymbolicName);
if(!NT_SUCCESS(status)) // Could return good values of STATUS_SUCCESS or STATUS_OBJECT_NAME_EXISTS
{
sprintf(szErrorMsg, "Port %d on card at %08X%08X: Interface error.",
pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
Spx_LogMessage( STATUS_SEVERITY_ERROR,
pPort->DriverObject, // Driver Object
pPort->DeviceObject, // Device Object (Optional)
PhysicalZero, // Physical Address 1
PhysicalZero, // Physical Address 2
0, // SequenceNumber
0, // Major Function Code
0, // RetryCount
FILE_ID | __LINE__, // UniqueErrorValue
STATUS_SUCCESS, // FinalStatus
szErrorMsg); // Error Message
pPort->DeviceClassSymbolicName.Buffer = NULL;
goto ExternalNamingError;
}
// Enable the device interface.
status = IoSetDeviceInterfaceState(&pPort->DeviceClassSymbolicName, TRUE);
if(!NT_SUCCESS(status)) // Could return good values of STATUS_SUCCESS or STATUS_OBJECT_NAME_EXISTS
{
sprintf(szErrorMsg, "Port %d on card at %08X%08X: Interface error.",
pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
Spx_LogMessage( STATUS_SEVERITY_ERROR,
pPort->DriverObject, // Driver Object
pPort->DeviceObject, // Device Object (Optional)
PhysicalZero, // Physical Address 1
PhysicalZero, // Physical Address 2
0, // SequenceNumber
0, // Major Function Code
0, // RetryCount
FILE_ID | __LINE__, // UniqueErrorValue
STATUS_SUCCESS, // FinalStatus
szErrorMsg); // Error Message
goto ExternalNamingError;
}
pPort->CreatedSerialCommEntry = TRUE; // Set flag.
return(status);
ExternalNamingError:;
if(!SPX_SUCCESS(status))
Spx_RemoveExternalNaming(pDevObject); // Remove and tidy up any allocations
return(status);
} // End Spx_DoExternalNaming
/*****************************************************************************
************************ ************************
************************ Spx_RemoveExternalNaming ************************
************************ ************************
******************************************************************************
prototype: NTSTATUS Spx_RemoveExternalNaming(IN PDEVICE_OBJECT pDevObject)
description: Remove external naming:
remove symbolic link
remove from registry
stop interface
parameters: pDevObject points to the device object for the port to be named.
returns: NT Status Code
*/
NTSTATUS Spx_RemoveExternalNaming(IN PDEVICE_OBJECT pDevObject)
{
PPORT_DEVICE_EXTENSION pPort = pDevObject->DeviceExtension;
PCARD_DEVICE_EXTENSION pCard = pPort->pParentCardExt;
NTSTATUS status = STATUS_UNSUCCESSFUL;
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
if(pPort->CreatedSymbolicLink)
{
if(pPort->DosName.Buffer)
{
SpxFreeMem(pPort->DosName.Buffer); // Free DOS name buffer.
pPort->DosName.Buffer = NULL;
}
if(pPort->SymbolicLinkName.Buffer)
{
SpxFreeMem(pPort->SymbolicLinkName.Buffer); // Free symbolic link name buffer.
pPort->SymbolicLinkName.Buffer = NULL;
}
Spx_GetExternalName(pDevObject); // Get external name..
if(pPort->SymbolicLinkName.Buffer)
status = IoDeleteSymbolicLink(&pPort->SymbolicLinkName); // Delete Symbolic Link.
if(pPort->DeviceClassSymbolicName.Buffer) // Device Interface name
IoSetDeviceInterfaceState(&pPort->DeviceClassSymbolicName, FALSE); // Disable Device Interface.
pPort->CreatedSymbolicLink = FALSE; // Reset created flag.
}
if(pPort->DosName.Buffer)
{
SpxFreeMem(pPort->DosName.Buffer); // Free DOS name buffer.
pPort->DosName.Buffer = NULL;
}
if(pPort->SymbolicLinkName.Buffer)
{
SpxFreeMem(pPort->SymbolicLinkName.Buffer); // Free symbolic link name buffer.
pPort->SymbolicLinkName.Buffer = NULL;
}
if(pPort->CreatedSerialCommEntry && pPort->DeviceName.Buffer)
{
RtlDeleteRegistryValue( RTL_REGISTRY_DEVICEMAP, // Delete SERIALCOMM registry entry.
SERIAL_DEVICE_MAP,
pPort->DeviceName.Buffer);
pPort->CreatedSerialCommEntry = FALSE; // Reset created flag.
}
if(pPort->DeviceClassSymbolicName.Buffer) // Device Interface name
{
SpxFreeMem(pPort->DeviceClassSymbolicName.Buffer); // Free Device Interface Name.
pPort->DeviceClassSymbolicName.Buffer = NULL;
}
return(STATUS_SUCCESS);
} // End Spx_RemoveExternalNaming
/*****************************************************************************
************************** ***************************
************************** Spx_Port_StopDevice ***************************
************************** ***************************
******************************************************************************
prototype: NTSTATUS Spx_Port_StopDevice(IN PPORT_DEVICE_EXTENSION pPort)
description: Stop the port device:
Stop the hardware
Remove external naming
parameters: pPort points to the port device extension to be stopped
returns: NT Status Code
*/
NTSTATUS Spx_Port_StopDevice(IN PPORT_DEVICE_EXTENSION pPort)
{
NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering Spx_Port_StopDevice for Port %d.\n",PRODUCT_NAME,pPort->PortNumber));
if(pPort->PnpPowerFlags & PPF_STARTED)
XXX_PortStop(pPort); // Stop the port hardware.
ClearPnpPowerFlags(pPort,PPF_STARTED); // Indicate card is stopped.
ClearPnpPowerFlags(pPort,PPF_STOP_PENDING); // Clear stop pending flag.
return(status);
} // End Spx_Port_StopDevice
/*****************************************************************************
************************* **************************
************************* Spx_Port_RemoveDevice **************************
************************* **************************
******************************************************************************
prototype: NTSTATUS Spx_Port_RemoveDevice(IN PDEVICE_OBJECT pDevObject)
description: Remove the port device object:
Remove PDO pointer from card structure
Deinitialise port hardware
Delete the device object
parameters: pDevObject points to the port device object to be stopped
returns: NT Status Code
*/
NTSTATUS Spx_Port_RemoveDevice(IN PDEVICE_OBJECT pDevObject)
{
PPORT_DEVICE_EXTENSION pPort = pDevObject->DeviceExtension;
PCARD_DEVICE_EXTENSION pCard = pPort->pParentCardExt;
NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering Spx_Port_RemoveDevice for Port %d.\n",PRODUCT_NAME,pPort->PortNumber));
if(pPort->PnpPowerFlags & PPF_REMOVED) // Has device been removed already?
return(STATUS_SUCCESS);
Spx_Port_StopDevice(pPort); // Stop the hardware.
ClearPnpPowerFlags(pPort,PPF_STARTED); // Mark the PDO as stopped.
Spx_RemoveExternalNaming(pDevObject); // Remove external naming.
// Mark the port device as "removed", but don't delete the PDO until the card device is removed...
SetPnpPowerFlags(pPort,PPF_REMOVED); // Mark the PDO as "removed".
return(status);
} // End Spx_Port_RemoveDevice
/////////////////////////////////////////////////////////////////////////////////////////////
// Create an Instance ID for the port and try to make it globally unique if possible.
//
NTSTATUS
Spx_CreatePortInstanceID(IN PPORT_DEVICE_EXTENSION pPort)
{
PCARD_DEVICE_EXTENSION pCard = pPort->pParentCardExt;
NTSTATUS status = STATUS_SUCCESS;
CHAR szTemp[100]; // Space to hold string
int szTempPos = 0;
HANDLE PnPKeyHandle;
BOOLEAN UseBusWideInstanceID = FALSE; // Try to create system wide unique instance IDs
PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering Spx_CreatePortInstanceID for Port %d.\n", PRODUCT_NAME, pPort->PortNumber));
status = IoOpenDeviceRegistryKey(pCard->PDO, PLUGPLAY_REGKEY_DRIVER, STANDARD_RIGHTS_READ, &PnPKeyHandle);
if(SPX_SUCCESS(status))
{
ULONG Data = 0;
if(SPX_SUCCESS(Spx_GetRegistryKeyValue(PnPKeyHandle, L"UseBusWideInstanceID",
wcslen(L"UseBusWideInstanceID") * sizeof(WCHAR), &Data, sizeof(ULONG))))
{
if(Data > 0)
UseBusWideInstanceID = TRUE; // Installer has told us to use a bus wide instance ID
// because child devices already exist with that type of ID.
}
ZwClose(PnPKeyHandle);
}
if(UseBusWideInstanceID)
{
pPort->UniqueInstanceID = FALSE; // ID created is not unique system wide.
status = STATUS_SUCCESS;
}
else
{
switch(pCard->InterfaceType)
{
case Isa:
// Start Instance ID with ISA address
szTempPos += sprintf(szTemp,"ISA&%08X%08X&", pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
pPort->UniqueInstanceID = TRUE; // ID created is unique system wide.
status = STATUS_SUCCESS;
break;
case PCIBus:
{
ULONG PCI_BusNumber = 0;
ULONG PCI_DeviceFunction = 0;
ULONG ResultLength;
// Try to get DevicePropertyBusNumber
if(!SPX_SUCCESS(status = IoGetDeviceProperty(pCard->PDO, DevicePropertyBusNumber,
sizeof(PCI_BusNumber), &PCI_BusNumber, &ResultLength)))
break;
// Start Instance ID with PCI bus number
szTempPos += sprintf(szTemp,"PCI&%04X&", PCI_BusNumber);
// Try to get DevicePropertyAddress
if(!SPX_SUCCESS(status = IoGetDeviceProperty(pCard->PDO, DevicePropertyAddress,
sizeof(PCI_DeviceFunction), &PCI_DeviceFunction, &ResultLength)))
break;
// Add on PCI Device and Function IDs
szTempPos += sprintf(szTemp + szTempPos,"%08X&", PCI_DeviceFunction);
pPort->UniqueInstanceID = TRUE; // ID created is unique system wide.
status = STATUS_SUCCESS;
break;
}
default:
pPort->UniqueInstanceID = FALSE; // ID created is not unique system wide.
status = STATUS_SUCCESS;
break;
}
}
// Finish off the InstanceID with the port number on the card.
sprintf(szTemp + szTempPos,"%04X", pPort->PortNumber);
status = Spx_InitMultiString(FALSE, &pPort->InstanceID, szTemp, NULL);
return status;
}
// End of SPX_PNP.C