#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 #include /***************************************************************************** ***************************** ****************************** ***************************** 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; iAttachedPDO[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; iAttachedPDO[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;PortNumberNumberOfPorts;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; loopAttachedPDO[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\\" 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