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
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
|