#include "precomp.h" ///////////////////////////////////////////////////////////////////////////////////// // This file contains all functions that are needed to integrate between the // generic PnP code and the product specific code. ///////////////////////////////////////////////////////////////////////////////////// #define FILE_ID SPD_PNP_C // File ID for Event Logging see SPD_DEFS.H for values. // Prototypes // End of Prototypes NTSTATUS XXX_CardGetResources(IN PDEVICE_OBJECT pDevObject, IN PCM_RESOURCE_LIST PResList, IN PCM_RESOURCE_LIST PTrResList) /* ++ Routine Description: Stores resources given to us by the PnP manager in the card's device extension. Arguments: pDevObject - Pointer to the device object. PResList - Pointer to the untranslated resources requested. PTrResList - Pointer to the translated resources requested. Return Value: STATUS_SUCCESS. --*/ { PCARD_DEVICE_EXTENSION pCard = pDevObject->DeviceExtension; NTSTATUS status = STATUS_NOT_IMPLEMENTED; CHAR szErrorMsg[MAX_ERROR_LOG_INSERT]; // Limited to 51 characters + 1 null ULONG count = 0; ULONG i = 0; USHORT MemoryResource = 0; USHORT IOResource = 0; PCM_FULL_RESOURCE_DESCRIPTOR pFullResourceDesc = NULL; PCM_PARTIAL_RESOURCE_LIST pPartialResourceList = NULL; PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialResourceDesc = 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 XXX_CardGetResources for Card %d.\n", PRODUCT_NAME, pCard->CardNumber)); SpxDbgMsg(SPX_MISC_DBG, ("%s: Resource pointer is 0x%X\n", PRODUCT_NAME, PResList)); SpxDbgMsg(SPX_MISC_DBG, ("%s: Translated resource pointer is 0x%X\n", PRODUCT_NAME, PTrResList)); if((PResList == NULL) || (PTrResList == NULL)) { // This shouldn't happen in theory ASSERT(PResList != NULL); ASSERT(PTrResList != NULL); sprintf(szErrorMsg, "Card %d has been given no resources.", pCard->CardNumber); Spx_LogMessage( STATUS_SEVERITY_ERROR, pCard->DriverObject, // Driver Object pCard->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 // This status is as appropriate as I can think of return STATUS_INSUFFICIENT_RESOURCES; } // Each resource list should have only one set of resources ASSERT(PResList->Count == 1); ASSERT(PTrResList->Count == 1); // Find out the card type... if((pCard->CardType = SpxGetNtCardType(pCard->DeviceObject)) == -1) { sprintf(szErrorMsg, "Card %d is unrecognised.", pCard->CardNumber); Spx_LogMessage( STATUS_SEVERITY_ERROR, pCard->DriverObject, // Driver Object pCard->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 return(STATUS_DEVICE_DOES_NOT_EXIST); } // Find out which raw resources have been given to us. pFullResourceDesc = &PResList->List[0]; if(pFullResourceDesc) { pPartialResourceList = &pFullResourceDesc->PartialResourceList; pPartialResourceDesc = pPartialResourceList->PartialDescriptors; count = pPartialResourceList->Count; // Number of Partial Resource Descriptors // Pull out the stuff that is in the full descriptor. pCard->InterfaceType = pFullResourceDesc->InterfaceType; pCard->BusNumber = pFullResourceDesc->BusNumber; // Now run through the partial resource descriptors looking for the port and interrupt. for(i = 0; i < count; i++, pPartialResourceDesc++) { switch(pPartialResourceDesc->Type) { case CmResourceTypeMemory: break; case CmResourceTypePort: { switch(pCard->CardType) { case Fast4_Isa: case Fast8_Isa: case Fast16_Isa: case Fast4_Pci: case Fast8_Pci: case Fast16_Pci: case Fast16FMC_Pci: case RAS4_Pci: case RAS8_Pci: pCard->PhysAddr = pPartialResourceDesc->u.Memory.Start; pCard->SpanOfController = pPartialResourceDesc->u.Memory.Length; break; default: // Speed cards break; } IOResource++; break; } case CmResourceTypeInterrupt: { pCard->OriginalIrql = pPartialResourceDesc->u.Interrupt.Level; pCard->OriginalVector = pPartialResourceDesc->u.Interrupt.Vector; pCard->ProcessorAffinity= pPartialResourceDesc->u.Interrupt.Affinity; if(pPartialResourceDesc->Flags & CM_RESOURCE_INTERRUPT_LATCHED) pCard->InterruptMode = Latched; else pCard->InterruptMode = LevelSensitive; switch(pPartialResourceDesc->ShareDisposition) { case CmResourceShareDeviceExclusive: pCard->InterruptShareable = FALSE; break; case CmResourceShareDriverExclusive: pCard->InterruptShareable = FALSE; break; case CmResourceShareShared: default: pCard->InterruptShareable = TRUE; break; } break; } default: break; } } } // Do the same for the translated resources. pFullResourceDesc = &PTrResList->List[0]; if(pFullResourceDesc) { pPartialResourceList = &pFullResourceDesc->PartialResourceList; pPartialResourceDesc = pPartialResourceList->PartialDescriptors; count = pPartialResourceList->Count; // Number of Partial Resource Descriptors // Pull out the stuff that is in the full descriptor. pCard->InterfaceType = pFullResourceDesc->InterfaceType; pCard->BusNumber = pFullResourceDesc->BusNumber; // Now run through the partial resource descriptors looking for the interrupt, for(i = 0; i < count; i++, pPartialResourceDesc++) { switch(pPartialResourceDesc->Type) { case CmResourceTypeMemory: { switch(pCard->CardType) { case Fast4_Isa: case Fast8_Isa: case Fast16_Isa: break; // No Memory resource for these case Fast4_Pci: case Fast8_Pci: case Fast16_Pci: case Fast16FMC_Pci: case RAS4_Pci: case RAS8_Pci: { // Must be config space pCard->PCIConfigRegisters = pPartialResourceDesc->u.Memory.Start; pCard->SpanOfPCIConfigRegisters = pPartialResourceDesc->u.Memory.Length; break; } default: // Speed cards { if(MemoryResource == 0) { pCard->PhysAddr = pPartialResourceDesc->u.Memory.Start; pCard->SpanOfController = pPartialResourceDesc->u.Memory.Length; } else { // Must be config space pCard->PCIConfigRegisters = pPartialResourceDesc->u.Memory.Start; pCard->SpanOfPCIConfigRegisters = pPartialResourceDesc->u.Memory.Length; } break; } } MemoryResource++; break; } case CmResourceTypePort: break; case CmResourceTypeInterrupt: { pCard->TrIrql = (KIRQL) pPartialResourceDesc->u.Interrupt.Level; pCard->TrVector = pPartialResourceDesc->u.Interrupt.Vector; pCard->ProcessorAffinity = pPartialResourceDesc->u.Interrupt.Affinity; break; } default: break; } } } // If we have 1 Mem or 1 I/O Resources and an interrupt the resource allocation most probably succeeded. if(((MemoryResource >= 1) || (IOResource >= 1)) && (pCard->TrVector)) status = STATUS_SUCCESS; return status; } NTSTATUS XXX_CardInit(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 XXX_CardInit for Card %d.\n", PRODUCT_NAME, pCard->CardNumber)); pCard->OurIsr = SerialISR; pCard->OurIsrContext = pCard; return status; } NTSTATUS XXX_CardStart(IN PCARD_DEVICE_EXTENSION pCard) { NTSTATUS status = STATUS_SUCCESS; UCHAR CardID = 0; CHAR szErrorMsg[MAX_ERROR_LOG_INSERT]; // Limited to 51 characters + 1 null BOOLEAN bInterruptConnnected = FALSE; PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL SpxDbgMsg(SPX_TRACE_CALLS, ("%s: Entering XXX_CardStart for Card %d.\n", PRODUCT_NAME, pCard->CardNumber)); switch(pCard->CardType) { case Fast4_Isa: case Fast4_Pci: case RAS4_Pci: pCard->UARTOffset = 8; // I/O address offset between UARTs pCard->UARTRegStride = 1; pCard->NumberOfPorts = 4; pCard->ClockRate = CLOCK_FREQ_7M3728Hz; // 7.3728 MHz pCard->Controller = (PUCHAR) pCard->PhysAddr.LowPart; if(UL_InitUartLibrary(&pCard->UartLib, UL_LIB_16C65X_UART) != UL_STATUS_SUCCESS) // Init table of UART library functions pointers. goto Error; break; case Fast8_Isa: case Fast8_Pci: case RAS8_Pci: pCard->UARTOffset = 8; // I/O address offset between UARTs pCard->UARTRegStride = 1; pCard->NumberOfPorts = 8; pCard->ClockRate = CLOCK_FREQ_7M3728Hz; // 7.3728 MHz pCard->Controller = (PUCHAR) pCard->PhysAddr.LowPart; if(UL_InitUartLibrary(&pCard->UartLib, UL_LIB_16C65X_UART) != UL_STATUS_SUCCESS) // Init table of UART library functions pointers. goto Error; break; case Fast16_Isa: case Fast16_Pci: case Fast16FMC_Pci: pCard->UARTOffset = 8; // I/O address offset between UARTs pCard->UARTRegStride = 1; pCard->NumberOfPorts = 16; pCard->ClockRate = CLOCK_FREQ_7M3728Hz; // 7.3728 MHz pCard->Controller = (PUCHAR) pCard->PhysAddr.LowPart; if(UL_InitUartLibrary(&pCard->UartLib, UL_LIB_16C65X_UART) != UL_STATUS_SUCCESS) // Init table of UART library functions pointers. goto Error; break; case Speed2_Pci: pCard->UARTOffset = OXPCI_INTERNAL_MEM_OFFSET; // Memory address offset between internal UARTs pCard->UARTRegStride = 4; pCard->NumberOfPorts = 2; pCard->ClockRate = CLOCK_FREQ_1M8432Hz; // 1.8432 MHz pCard->Controller = MmMapIoSpace(pCard->PhysAddr, pCard->SpanOfController, FALSE); // Map in the card's memory base address if(UL_InitUartLibrary(&pCard->UartLib, UL_LIB_16C95X_UART) != UL_STATUS_SUCCESS) // Init table of UART library functions pointers. goto Error; break; case Speed2P_Pci: pCard->UARTOffset = OXPCI_INTERNAL_MEM_OFFSET; // Memory address offset between internal UARTs pCard->UARTRegStride = 4; pCard->NumberOfPorts = 2; pCard->ClockRate = CLOCK_FREQ_14M7456Hz; // 14.7456 MHz pCard->Controller = MmMapIoSpace(pCard->PhysAddr, pCard->SpanOfController, FALSE); // Map in the card's memory base address if(UL_InitUartLibrary(&pCard->UartLib, UL_LIB_16C95X_UART) != UL_STATUS_SUCCESS) // Init table of UART library functions pointers. goto Error; break; case Speed4_Pci: pCard->UARTOffset = OXPCI_INTERNAL_MEM_OFFSET; // Memory address offset between internal UARTs pCard->UARTRegStride = 4; pCard->NumberOfPorts = 4; pCard->ClockRate = CLOCK_FREQ_1M8432Hz; // 1.8432 MHz pCard->Controller = MmMapIoSpace(pCard->PhysAddr, pCard->SpanOfController, FALSE); // Map in the card's memory base address if(UL_InitUartLibrary(&pCard->UartLib, UL_LIB_16C95X_UART) != UL_STATUS_SUCCESS) // Init table of UART library functions pointers. goto Error; break; case Speed4P_Pci: pCard->UARTOffset = OXPCI_INTERNAL_MEM_OFFSET; // Memory address offset between internal UARTs pCard->UARTRegStride = 4; pCard->NumberOfPorts = 4; pCard->ClockRate = CLOCK_FREQ_14M7456Hz; // 14.7456 MHz pCard->Controller = MmMapIoSpace(pCard->PhysAddr, pCard->SpanOfController, FALSE); // Map in the card's memory base address if(UL_InitUartLibrary(&pCard->UartLib, UL_LIB_16C95X_UART) != UL_STATUS_SUCCESS) // Init table of UART library functions pointers. goto Error; break; case Speed2and4_Pci_8BitBus: pCard->UARTOffset = OXPCI_LOCAL_MEM_OFFSET; // Memory address offset between local bus UARTs pCard->UARTRegStride = 4; pCard->NumberOfPorts = 0; // No ports. pCard->ClockRate = CLOCK_FREQ_1M8432Hz; pCard->Controller = MmMapIoSpace(pCard->PhysAddr, pCard->SpanOfController, FALSE); // Map in the card's memory base address break; case Speed2P_Pci_8BitBus: case Speed4P_Pci_8BitBus: pCard->UARTOffset = OXPCI_LOCAL_MEM_OFFSET; // Memory address offset between local bus UARTs pCard->UARTRegStride = 4; pCard->NumberOfPorts = 0; // No ports on a Speed2/4+ card. pCard->ClockRate = CLOCK_FREQ_14M7456Hz; pCard->Controller = MmMapIoSpace(pCard->PhysAddr, pCard->SpanOfController, FALSE); // Map in the card's memory base address break; default: pCard->NumberOfPorts = 0; // Default = No ports. break; } // Map in the card's memory base address if(!pCard->Controller) { status = STATUS_INSUFFICIENT_RESOURCES; goto Error; } // Map in the card's Local Configuration Registers... if(pCard->InterfaceType == PCIBus) // If we have some PCI config registers { pCard->LocalConfigRegisters = MmMapIoSpace(pCard->PCIConfigRegisters, pCard->SpanOfPCIConfigRegisters, FALSE); if(!pCard->LocalConfigRegisters) { status = STATUS_INSUFFICIENT_RESOURCES; goto Error; } } // Try to connect to interrupt. if(SPX_SUCCESS(status = IoConnectInterrupt(&pCard->Interrupt, // Interrupt object pCard->OurIsr, // Service routine pCard->OurIsrContext, // Service context NULL, // SpinLock (optional) pCard->TrVector, // Vector pCard->TrIrql, // IRQL pCard->TrIrql, // Synchronize IRQL pCard->InterruptMode, // Mode (Latched/Level Sensitive) pCard->InterruptShareable, // Sharing mode pCard->ProcessorAffinity, // Processors to handle ints FALSE))) // Floating point save { bInterruptConnnected = TRUE; // Set Interrupt Connected flag. } else { // Tell user the problem sprintf(szErrorMsg, "Card at %08X%08X: Interrupt unavailable.", 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 0, // Major Function Code 0, // RetryCount FILE_ID | __LINE__, // UniqueErrorValue STATUS_SUCCESS, // FinalStatus szErrorMsg); // Error Message goto Error; } switch(pCard->CardType) { case Fast4_Isa: // If ISA card try to verify the card is present at selected address case Fast8_Isa: // by trying to verify first UART on the Card. case Fast16_Isa: { INIT_UART InitUart = {0}; // Set base address of 1st UART InitUart.UartNumber = 0; InitUart.BaseAddress = pCard->Controller; InitUart.RegisterStride = pCard->UARTRegStride; InitUart.ClockFreq = pCard->ClockRate; pCard->pFirstUart = NULL; // Init a UART structure. if(pCard->UartLib.UL_InitUart_XXXX(&InitUart, pCard->pFirstUart, &(pCard->pFirstUart)) != UL_STATUS_SUCCESS) { status = STATUS_INSUFFICIENT_RESOURCES; goto Error; } // Reset and try to verify the UART. if(!KeSynchronizeExecution(pCard->Interrupt, SerialResetAndVerifyUart, pCard->DeviceObject)) // Verify UART exists. { SpxDbgMsg(SPX_TRACE_CALLS, ("%s: Failed to find 1st UART on Card %d.\n", PRODUCT_NAME, pCard->CardNumber)); pCard->UartLib.UL_DeInitUart_XXXX(pCard->pFirstUart); // DeInit UART status = STATUS_DEVICE_DOES_NOT_EXIST; goto Error; } // DeInit the UART structure. pCard->UartLib.UL_DeInitUart_XXXX(pCard->pFirstUart); // DeInit UART pCard->pFirstUart = NULL; } default: break; } switch(pCard->CardType) { case Speed2and4_Pci_8BitBus: case Speed2P_Pci_8BitBus: case Speed4P_Pci_8BitBus: break; default: GetCardSettings(pCard->DeviceObject); // Get Card settings if present. #ifdef WMI_SUPPORT // Register for WMI SpeedCard_WmiInitializeWmilibContext(&pCard->WmiLibInfo); IoWMIRegistrationControl(pCard->DeviceObject, WMIREG_ACTION_REGISTER); #endif break; } return status; Error: if(bInterruptConnnected) IoDisconnectInterrupt(pCard->Interrupt); // Disconnect Interrupt. switch(pCard->CardType) { case Fast4_Isa: case Fast8_Isa: case Fast16_Isa: case Fast4_Pci: case Fast8_Pci: case Fast16_Pci: case Fast16FMC_Pci: case RAS4_Pci: case RAS8_Pci: pCard->Controller = NULL; break; default: // Speed cards if(pCard->Controller) // If mapped in. { MmUnmapIoSpace(pCard->Controller, pCard->SpanOfController); // Unmap. pCard->Controller = NULL; } break; } if(pCard->LocalConfigRegisters) // If PCI Config registers are mapped in. { MmUnmapIoSpace(pCard->LocalConfigRegisters, pCard->SpanOfPCIConfigRegisters); // Unmap. pCard->LocalConfigRegisters = NULL; } UL_DeInitUartLibrary(&pCard->UartLib); // DeInit table of UART library functions pointers. switch(status) { case STATUS_DEVICE_DOES_NOT_EXIST: case STATUS_UNSUCCESSFUL: { sprintf(szErrorMsg, "Card at %08X%08X: Unrecognised or malfunctioning.", 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 0, // Major Function Code 0, // RetryCount FILE_ID | __LINE__, // UniqueErrorValue STATUS_SUCCESS, // FinalStatus szErrorMsg); // Error Message break; } case STATUS_INSUFFICIENT_RESOURCES: { 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 0, // Major Function Code 0, // RetryCount FILE_ID | __LINE__, // UniqueErrorValue STATUS_SUCCESS, // FinalStatus szErrorMsg); // Error Message break; } default: break; } return status; } NTSTATUS XXX_CardStop(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 XXX_CardStop for Card %d.\n", PRODUCT_NAME, pCard->CardNumber)); // Stop Card from interrupting IoDisconnectInterrupt(pCard->Interrupt); // Disconnect from Interrupt. #ifdef WMI_SUPPORT switch(pCard->CardType) { case Speed2and4_Pci_8BitBus: case Speed2P_Pci_8BitBus: case Speed4P_Pci_8BitBus: break; default: // Deregister for WMI IoWMIRegistrationControl(pCard->DeviceObject, WMIREG_ACTION_DEREGISTER); break; } #endif switch(pCard->CardType) { case Fast4_Isa: case Fast8_Isa: case Fast16_Isa: case Fast4_Pci: case Fast8_Pci: case Fast16_Pci: case Fast16FMC_Pci: case RAS4_Pci: case RAS8_Pci: pCard->Controller = NULL; break; default: // Speed cards if(pCard->Controller) // If mapped in. { MmUnmapIoSpace(pCard->Controller, pCard->SpanOfController); // Unmap. pCard->Controller = NULL; } break; } // Unmap PCI card's Local Configuration Registers... if(pCard->LocalConfigRegisters) // If mapped in. { MmUnmapIoSpace(pCard->LocalConfigRegisters, pCard->SpanOfPCIConfigRegisters); pCard->LocalConfigRegisters = NULL; } UL_DeInitUartLibrary(&pCard->UartLib); // DeInit table of UART library functions pointers. pCard->InterfaceType = InterfaceTypeUndefined; pCard->PhysAddr = PhysicalZero; pCard->SpanOfController = 0; pCard->OriginalIrql = 0; pCard->OriginalVector = 0; pCard->ProcessorAffinity = 0; pCard->TrIrql = 0; pCard->TrVector = 0; pCard->Controller = NULL; pCard->LocalConfigRegisters = NULL; pCard->SpanOfPCIConfigRegisters = 0; return status; } NTSTATUS XXX_CardDeInit(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 XXX_CardDeInit for Card %d.\n", PRODUCT_NAME, pCard->CardNumber)); pCard->OurIsr = NULL; pCard->OurIsrContext = NULL; pCard->pFirstUart = NULL; return status; } NTSTATUS XXX_PortInit(IN PPORT_DEVICE_EXTENSION pPort) { // Initialise port device extension. PCARD_DEVICE_EXTENSION pCard = pPort->pParentCardExt; NTSTATUS status = STATUS_SUCCESS; SHORT PortType = 0; CHAR szTemp[50]; // Space to hold string CHAR szCard[10]; // Space to hold card type string SHORT i = 0; int Result = 0; INIT_UART InitUart; PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL SpxDbgMsg(SPX_TRACE_CALLS, ("%s: Entering XXX_PortInit for Port %d.\n", PRODUCT_NAME, pPort->PortNumber)); #ifndef BUILD_SPXMINIPORT // Form an InstanceID for the port. if(!SPX_SUCCESS(status = Spx_CreatePortInstanceID(pPort))) return status; #endif switch(pCard->CardType) { case Fast4_Isa: case Fast4_Pci: sprintf(szCard, "FAST"); // Fast card PortType = FAST_8PIN_RJ45; // 8 pin RJ45 ports with Chase pinouts break; case Fast8_Isa: case Fast8_Pci: sprintf(szCard, "FAST"); // Fast card PortType = FAST_8PIN_XXXX; // 8 pin ports break; case Fast16_Isa: case Fast16_Pci: sprintf(szCard, "FAST"); // Fast card PortType = FAST_6PIN_XXXX; // 6 pin ports break; case Fast16FMC_Pci: sprintf(szCard, "FAST"); // Fast card PortType = FAST_8PIN_XXXX; // 8 pin Full Modem Control (FMC) ports break; case RAS4_Pci: case RAS8_Pci: sprintf(szCard, "SPDRAS"); // RAS card PortType = MODEM_PORT; // Modem Ports break; case Speed2_Pci: sprintf(szCard, "SPD2"); // Speed 2 card PortType = SPD_8PIN_RJ45; // 8 pin RJ45 ports break; case Speed2P_Pci: sprintf(szCard, "SPD2P"); // Speed 2+ card PortType = SPD_10PIN_RJ45; // 10 pin RJ45 ports break; case Speed4_Pci: sprintf(szCard, "SPD4"); // Speed 4 card PortType = SPD_8PIN_RJ45; // 8 pin RJ45 ports break; case Speed4P_Pci: sprintf(szCard, "SPD4P"); // Speed 4+ card PortType = SPD_10PIN_RJ45; // 10 pin RJ45 ports break; default: sprintf(szCard, "XXX"); // Unknown card type break; } // Initialise device identifiers... switch(PortType) { case FAST_8PIN_RJ45: sprintf(szTemp,"FAST\\%s&8PINRJ45", szCard); Spx_InitMultiString(FALSE, &pPort->DeviceID, szTemp, NULL); sprintf(szTemp,"FAST\\%s&8PINRJ45", szCard); Spx_InitMultiString(TRUE, &pPort->HardwareIDs, szTemp, NULL); sprintf(szTemp,"Perle FAST Serial Port %d", pPort->PortNumber+1); Spx_InitMultiString(FALSE, &pPort->DevDesc, szTemp, NULL); break; case FAST_8PIN_XXXX: sprintf(szTemp,"FAST\\%s&8PINXXXX", szCard); Spx_InitMultiString(FALSE, &pPort->DeviceID, szTemp, NULL); sprintf(szTemp,"FAST\\%s&8PINXXXX", szCard); Spx_InitMultiString(TRUE, &pPort->HardwareIDs, szTemp, NULL); sprintf(szTemp,"Perle FAST Serial Port %d", pPort->PortNumber+1); Spx_InitMultiString(FALSE, &pPort->DevDesc, szTemp, NULL); break; case FAST_6PIN_XXXX: sprintf(szTemp,"FAST\\%s&6PINXXXX", szCard); Spx_InitMultiString(FALSE, &pPort->DeviceID, szTemp, NULL); sprintf(szTemp,"FAST\\%s&6PINXXXX", szCard); Spx_InitMultiString(TRUE, &pPort->HardwareIDs, szTemp, NULL); sprintf(szTemp,"Perle FAST Serial Port %d", pPort->PortNumber+1); Spx_InitMultiString(FALSE, &pPort->DevDesc, szTemp, NULL); break; case MODEM_PORT: sprintf(szTemp,"SPDRAS\\RASPort"); Spx_InitMultiString(FALSE, &pPort->DeviceID, szTemp, NULL); sprintf(szTemp,"SPDRAS\\RASPort"); Spx_InitMultiString(TRUE, &pPort->HardwareIDs, szTemp, NULL); sprintf(szTemp,"Perle RAS Port %d", pPort->PortNumber+1); Spx_InitMultiString(FALSE, &pPort->DevDesc, szTemp, NULL); break; case SPD_8PIN_RJ45: sprintf(szTemp,"SPEED\\%s&8PINRJ45", szCard); Spx_InitMultiString(FALSE, &pPort->DeviceID, szTemp, NULL); sprintf(szTemp,"SPEED\\%s&8PINRJ45", szCard); Spx_InitMultiString(TRUE, &pPort->HardwareIDs, szTemp, NULL); sprintf(szTemp,"Perle SPEED Serial Port %d", pPort->PortNumber+1); Spx_InitMultiString(FALSE, &pPort->DevDesc, szTemp, NULL); break; case SPD_10PIN_RJ45: sprintf(szTemp,"SPEED\\%s&10PINRJ45", szCard); Spx_InitMultiString(FALSE, &pPort->DeviceID, szTemp, NULL); sprintf(szTemp,"SPEED\\%s&10PINRJ45", szCard); Spx_InitMultiString(TRUE, &pPort->HardwareIDs, szTemp, NULL); sprintf(szTemp,"Perle SPEED Serial Port %d", pPort->PortNumber+1); Spx_InitMultiString(FALSE, &pPort->DevDesc, szTemp, NULL); break; default: sprintf(szTemp,"SPEED\\%s&XXXXXXXX", szCard); Spx_InitMultiString(FALSE, &pPort->DeviceID, szTemp, NULL); sprintf(szTemp,"SPEED\\%s&XXXXXXXX", szCard); Spx_InitMultiString(TRUE, &pPort->HardwareIDs, szTemp, NULL); sprintf(szTemp,"Perle Serial Port %d of Unknown Type.", pPort->PortNumber + 1); Spx_InitMultiString(FALSE, &pPort->DevDesc, szTemp, NULL); status = STATUS_UNSUCCESSFUL; break; } /* Not required as we are using INF file i = sprintf(szTemp, "Port %d on ", pPort->PortNumber + 1); sprintf(szTemp+i, "PCI Card 0x%08lX", pCard->PhysAddr); Spx_InitMultiString(FALSE, &pPort->DevLocation, szTemp, NULL); */ pPort->pUartLib = &pCard->UartLib; // Store pointer to UART library functions in port. // Set base address of port InitUart.UartNumber = pPort->PortNumber; InitUart.BaseAddress = pCard->Controller + (pPort->PortNumber * pCard->UARTOffset); InitUart.RegisterStride = pCard->UARTRegStride; InitUart.ClockFreq = pCard->ClockRate; if(pPort->pUartLib->UL_InitUart_XXXX(&InitUart, pCard->pFirstUart, &(pPort->pUart)) != UL_STATUS_SUCCESS) { pPort->pUartLib = NULL; // NULL pointer to UART library functions. return STATUS_UNSUCCESSFUL; } pPort->pUartLib->UL_SetAppBackPtr_XXXX(pPort->pUart, pPort); // Set back ptr. if(pCard->pFirstUart == NULL) pCard->pFirstUart = pPort->pUart; pPort->Interrupt = pCard->Interrupt; /* pPort->RFLAddress = pCard->LocalConfigRegisters + URL + pPort->PortNumber; pPort->TFLAddress = pCard->LocalConfigRegisters + UTL + pPort->PortNumber; // pPort->InterruptStatus = pCard->LocalConfigRegisters */ return status; } NTSTATUS XXX_PortStart(IN PPORT_DEVICE_EXTENSION pPort) { NTSTATUS status = STATUS_SUCCESS; PCARD_DEVICE_EXTENSION pCard = pPort->pParentCardExt; SET_BUFFER_SIZES BufferSizes; UART_INFO UartInfo; PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL SpxDbgMsg(SPX_TRACE_CALLS, ("%s: Entering XXX_PortStart for Port %d.\n", PRODUCT_NAME, pPort->PortNumber)); if(!KeSynchronizeExecution(pPort->Interrupt, SerialResetAndVerifyUart, pPort->DeviceObject)) // Verify UART exists. { SpxDbgMsg(SPX_TRACE_CALLS, ("%s: Failed to find 16Cx5x Port %d.\n", PRODUCT_NAME, pPort->PortNumber)); return STATUS_UNSUCCESSFUL; } SpxDbgMsg(SPX_TRACE_CALLS, ("%s: Found 16Cx5x Port %d.\n", PRODUCT_NAME, pPort->PortNumber)); KeSynchronizeExecution(pPort->Interrupt, SerialReset, pPort); // Resets the port pPort->pUartLib->UL_GetUartInfo_XXXX(pPort->pUart, &UartInfo); // Get UART Capabilities switch(pCard->CardType) { case Fast4_Isa: case Fast4_Pci: case Fast8_Isa: case Fast8_Pci: case Fast16_Isa: case Fast16_Pci: case Fast16FMC_Pci: case RAS4_Pci: case RAS8_Pci: { pPort->MaxTxFIFOSize = UartInfo.MaxTxFIFOSize; // Max Tx FIFO Size. pPort->MaxRxFIFOSize = UartInfo.MaxRxFIFOSize; // Max Rx FIFO Size. pPort->TxFIFOSize = pPort->MaxTxFIFOSize; // Default Tx FIFO Size. pPort->RxFIFOSize = pPort->MaxRxFIFOSize; // Default Rx FIFO Size. pPort->TxFIFOTrigLevel = 8; // Default Tx FIFO Trigger Level. pPort->RxFIFOTrigLevel = 56; // Default Rx FIFO Trigger Level. pPort->LoFlowCtrlThreshold = 16; // Default Low Flow Control Threshold. pPort->HiFlowCtrlThreshold = 60; // Default High Flow Control Threshold. break; } case Speed2_Pci: case Speed2P_Pci: case Speed4_Pci: case Speed4P_Pci: { pPort->MaxTxFIFOSize = UartInfo.MaxTxFIFOSize; // Max Tx FIFO Size. pPort->MaxRxFIFOSize = UartInfo.MaxRxFIFOSize; // Max Rx FIFO Size. pPort->TxFIFOSize = pPort->MaxTxFIFOSize; // Default Tx FIFO Size. pPort->RxFIFOSize = pPort->MaxRxFIFOSize; // Default Rx FIFO Size. pPort->TxFIFOTrigLevel = 16; // Default Tx FIFO Trigger Level. pPort->RxFIFOTrigLevel = 100; // Default Rx FIFO Trigger Level. pPort->LoFlowCtrlThreshold = 16; // Default Low Flow Control Threshold. pPort->HiFlowCtrlThreshold = 112; // Default High Flow Control Threshold. break; } default: break; } #ifdef WMI_SUPPORT // Store Default FIFO settings for WMI pPort->SpeedWmiFifoProp.MaxTxFiFoSize = pPort->MaxTxFIFOSize; pPort->SpeedWmiFifoProp.MaxRxFiFoSize = pPort->MaxRxFIFOSize; pPort->SpeedWmiFifoProp.DefaultTxFiFoLimit = pPort->TxFIFOSize; pPort->SpeedWmiFifoProp.DefaultTxFiFoTrigger = pPort->TxFIFOTrigLevel; pPort->SpeedWmiFifoProp.DefaultRxFiFoTrigger = pPort->RxFIFOTrigLevel; pPort->SpeedWmiFifoProp.DefaultLoFlowCtrlThreshold = pPort->LoFlowCtrlThreshold; pPort->SpeedWmiFifoProp.DefaultHiFlowCtrlThreshold = pPort->HiFlowCtrlThreshold; #endif GetPortSettings(pPort->DeviceObject); // Get Saved Port Settings if present. // Initialize the list heads for the read, write, and mask queues... InitializeListHead(&pPort->ReadQueue); InitializeListHead(&pPort->WriteQueue); InitializeListHead(&pPort->MaskQueue); InitializeListHead(&pPort->PurgeQueue); // Initialize the spinlock associated with fields read (& set) by IO Control functions... KeInitializeSpinLock(&pPort->ControlLock); // Initialize the timers used to timeout operations... KeInitializeTimer(&pPort->ReadRequestTotalTimer); KeInitializeTimer(&pPort->ReadRequestIntervalTimer); KeInitializeTimer(&pPort->WriteRequestTotalTimer); KeInitializeTimer(&pPort->ImmediateTotalTimer); KeInitializeTimer(&pPort->XoffCountTimer); KeInitializeTimer(&pPort->LowerRTSTimer); // Initialise the dpcs that will be used to complete or timeout various IO operations... KeInitializeDpc(&pPort->CommWaitDpc, SerialCompleteWait, pPort); KeInitializeDpc(&pPort->CompleteReadDpc, SerialCompleteRead, pPort); KeInitializeDpc(&pPort->CompleteWriteDpc, SerialCompleteWrite, pPort); KeInitializeDpc(&pPort->TotalImmediateTimeoutDpc, SerialTimeoutImmediate, pPort); KeInitializeDpc(&pPort->TotalReadTimeoutDpc, SerialReadTimeout, pPort); KeInitializeDpc(&pPort->IntervalReadTimeoutDpc, SerialIntervalReadTimeout, pPort); KeInitializeDpc(&pPort->TotalWriteTimeoutDpc, SerialWriteTimeout, pPort); KeInitializeDpc(&pPort->CommErrorDpc, SerialCommError, pPort); KeInitializeDpc(&pPort->CompleteImmediateDpc, SerialCompleteImmediate, pPort); KeInitializeDpc(&pPort->XoffCountTimeoutDpc, SerialTimeoutXoff, pPort); KeInitializeDpc(&pPort->XoffCountCompleteDpc, SerialCompleteXoff, pPort); KeInitializeDpc(&pPort->StartTimerLowerRTSDpc, SerialStartTimerLowerRTS, pPort); KeInitializeDpc(&pPort->PerhapsLowerRTSDpc, SerialInvokePerhapsLowerRTS, pPort); // Default device control fields... pPort->SpecialChars.XonChar = SERIAL_DEF_XON; pPort->SpecialChars.XoffChar = SERIAL_DEF_XOFF; pPort->HandFlow.ControlHandShake = SERIAL_DTR_CONTROL; pPort->HandFlow.FlowReplace = SERIAL_RTS_CONTROL; // Define which baud rates can be supported... pPort->SupportedBauds = SERIAL_BAUD_USER; pPort->UartConfig.TxBaud = 75; if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort) == TRUE) pPort->SupportedBauds |= SERIAL_BAUD_075; pPort->UartConfig.TxBaud = 110; if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort) == TRUE) pPort->SupportedBauds |= SERIAL_BAUD_110; pPort->UartConfig.TxBaud = 134; if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort) == TRUE) pPort->SupportedBauds |= SERIAL_BAUD_134_5; pPort->UartConfig.TxBaud = 150; if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort) == TRUE) pPort->SupportedBauds |= SERIAL_BAUD_150; pPort->UartConfig.TxBaud = 300; if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort) == TRUE) pPort->SupportedBauds |= SERIAL_BAUD_300; pPort->UartConfig.TxBaud = 600; if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort) == TRUE) pPort->SupportedBauds |= SERIAL_BAUD_600; pPort->UartConfig.TxBaud = 1200; if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort) == TRUE) pPort->SupportedBauds |= SERIAL_BAUD_1200; pPort->UartConfig.TxBaud = 1800; if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort) == TRUE) pPort->SupportedBauds |= SERIAL_BAUD_1800; pPort->UartConfig.TxBaud = 2400; if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort) == TRUE) pPort->SupportedBauds |= SERIAL_BAUD_2400; pPort->UartConfig.TxBaud = 4800; if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort) == TRUE) pPort->SupportedBauds |= SERIAL_BAUD_4800; pPort->UartConfig.TxBaud = 7200; if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort) == TRUE) pPort->SupportedBauds |= SERIAL_BAUD_7200; pPort->UartConfig.TxBaud = 9600; if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort) == TRUE) pPort->SupportedBauds |= SERIAL_BAUD_9600; pPort->UartConfig.TxBaud = 14400; if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort) == TRUE) pPort->SupportedBauds |= SERIAL_BAUD_14400; pPort->UartConfig.TxBaud = 19200; if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort) == TRUE) pPort->SupportedBauds |= SERIAL_BAUD_19200; pPort->UartConfig.TxBaud = 38400; if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort) == TRUE) pPort->SupportedBauds |= SERIAL_BAUD_38400; pPort->UartConfig.TxBaud = 56000; if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort) == TRUE) pPort->SupportedBauds |= SERIAL_BAUD_56K; pPort->UartConfig.TxBaud = 57600; if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort) == TRUE) pPort->SupportedBauds |= SERIAL_BAUD_57600; pPort->UartConfig.TxBaud = 115200; if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort) == TRUE) pPort->SupportedBauds |= SERIAL_BAUD_115200; pPort->UartConfig.TxBaud = 128000; if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort) == TRUE) pPort->SupportedBauds |= SERIAL_BAUD_128K; // Default line configuration: 1200,E,7,1 pPort->UartConfig.TxBaud = 1200; pPort->LineControl = SERIAL_EVEN_PARITY | SERIAL_7_DATA | SERIAL_1_STOP; pPort->ValidDataMask = 0x7F; // Set Frame Config pPort->UartConfig.FrameConfig = (pPort->UartConfig.FrameConfig & ~UC_FCFG_DATALEN_MASK) | UC_FCFG_DATALEN_7; pPort->UartConfig.FrameConfig = (pPort->UartConfig.FrameConfig & ~UC_FCFG_PARITY_MASK) | UC_FCFG_EVEN_PARITY; pPort->UartConfig.FrameConfig = (pPort->UartConfig.FrameConfig & ~UC_FCFG_STOPBITS_MASK) | UC_FCFG_STOPBITS_1; // Mark this device as not being opened by anyone. We keep a variable // around so that spurious interrupts are easily dismissed by the ISR. pPort->DeviceIsOpen = FALSE; // pPort->UartConfig.SpecialMode |= UC_SM_LOOPBACK_MODE; // Internal Loopback mode // Set up values for interval timing... // Store values into the extension for interval timing. If the interval // timer is less than a second then come in with a short "polling" loop. // For large (> then 2 seconds) use a 1 second poller. pPort->ShortIntervalAmount.QuadPart = -1; pPort->LongIntervalAmount.QuadPart = -10000000; pPort->CutOverAmount.QuadPart = 200000000; #ifdef WMI_SUPPORT // // Fill in WMI hardware data // pPort->WmiHwData.IrqNumber = pCard->TrIrql; pPort->WmiHwData.IrqVector = pCard->TrVector; pPort->WmiHwData.IrqLevel = pCard->TrIrql; pPort->WmiHwData.IrqAffinityMask = pCard->ProcessorAffinity; if(pCard->InterruptMode == Latched) pPort->WmiHwData.InterruptType = SERIAL_WMI_INTTYPE_LATCHED; else pPort->WmiHwData.InterruptType = SERIAL_WMI_INTTYPE_LEVEL; pPort->WmiHwData.BaseIOAddress = (ULONG_PTR)pCard->Controller; // // Fill in WMI device state data (as defaults) // pPort->WmiCommData.BaudRate = pPort->UartConfig.TxBaud; UPDATE_WMI_LINE_CONTROL(pPort->WmiCommData, pPort->LineControl); UPDATE_WMI_XON_XOFF_CHARS(pPort->WmiCommData, pPort->SpecialChars); UPDATE_WMI_XMIT_THRESHOLDS(pPort->WmiCommData, pPort->HandFlow); pPort->WmiCommData.MaximumBaudRate = 115200U; // 115200k baud max pPort->WmiCommData.MaximumOutputBufferSize = (UINT32)((ULONG)-1); pPort->WmiCommData.MaximumInputBufferSize = (UINT32)((ULONG)-1); pPort->WmiCommData.Support16BitMode = FALSE; pPort->WmiCommData.SupportDTRDSR = TRUE; pPort->WmiCommData.SupportIntervalTimeouts = TRUE; pPort->WmiCommData.SupportParityCheck = TRUE; pPort->WmiCommData.SupportRTSCTS = TRUE; pPort->WmiCommData.SupportXonXoff = TRUE; pPort->WmiCommData.SettableBaudRate = TRUE; pPort->WmiCommData.SettableDataBits = TRUE; pPort->WmiCommData.SettableFlowControl = TRUE; pPort->WmiCommData.SettableParity = TRUE; pPort->WmiCommData.SettableParityCheck = TRUE; pPort->WmiCommData.SettableStopBits = TRUE; pPort->WmiCommData.IsBusy = FALSE; // Fill in wmi perf data (all zero's) RtlZeroMemory(&pPort->WmiPerfData, sizeof(pPort->WmiPerfData)); // // Register for WMI // SpeedPort_WmiInitializeWmilibContext(&pPort->WmiLibInfo); IoWMIRegistrationControl(pPort->DeviceObject, WMIREG_ACTION_REGISTER); #endif // Initialise the port hardware... KeSynchronizeExecution(pPort->Interrupt, SerialReset, pPort); // Resets the port KeSynchronizeExecution(pPort->Interrupt, ApplyInitialPortSettings, pPort); // Apply settings KeSynchronizeExecution(pPort->Interrupt, SerialMarkClose, pPort); // Disables the FIFO KeSynchronizeExecution(pPort->Interrupt, SerialClrRTS, pPort); // Clear RTS signal KeSynchronizeExecution(pPort->Interrupt, SerialClrDTR, pPort); // Clear DTR signal return status; } NTSTATUS XXX_PortStop(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 XXX_PortStop for Port %d.\n", PRODUCT_NAME, pPort->PortNumber)); #ifdef WMI_SUPPORT IoWMIRegistrationControl(pPort->DeviceObject, WMIREG_ACTION_DEREGISTER); RtlZeroMemory(&pPort->WmiLibInfo, sizeof(WMILIB_CONTEXT)); #endif // Cancel timers... KeCancelTimer(&pPort->ReadRequestTotalTimer); KeCancelTimer(&pPort->ReadRequestIntervalTimer); KeCancelTimer(&pPort->WriteRequestTotalTimer); KeCancelTimer(&pPort->ImmediateTotalTimer); KeCancelTimer(&pPort->XoffCountTimer); KeCancelTimer(&pPort->LowerRTSTimer); // Cancel pending DPCs... KeRemoveQueueDpc(&pPort->CommWaitDpc); KeRemoveQueueDpc(&pPort->CompleteReadDpc); KeRemoveQueueDpc(&pPort->CompleteWriteDpc); KeRemoveQueueDpc(&pPort->TotalReadTimeoutDpc); KeRemoveQueueDpc(&pPort->IntervalReadTimeoutDpc); KeRemoveQueueDpc(&pPort->TotalWriteTimeoutDpc); KeRemoveQueueDpc(&pPort->CommErrorDpc); KeRemoveQueueDpc(&pPort->CompleteImmediateDpc); KeRemoveQueueDpc(&pPort->TotalImmediateTimeoutDpc); KeRemoveQueueDpc(&pPort->XoffCountTimeoutDpc); KeRemoveQueueDpc(&pPort->XoffCountCompleteDpc); KeRemoveQueueDpc(&pPort->StartTimerLowerRTSDpc); KeRemoveQueueDpc(&pPort->PerhapsLowerRTSDpc); KeSynchronizeExecution(pPort->Interrupt, SerialReset, pPort); // Resets the port return status; } NTSTATUS XXX_PortDeInit(IN PPORT_DEVICE_EXTENSION pPort) { 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 XXX_PortDeInit for Port %d.\n", PRODUCT_NAME, pPort->PortNumber)); // If we are about to DeInit the first UART object to be serviced next // Make the pFirstUart point to the next UART in the list. if(pPort->pUart == pCard->pFirstUart) pCard->pFirstUart = pCard->UartLib.UL_GetUartObject_XXXX(pPort->pUart, UL_OP_GET_NEXT_UART); pCard->UartLib.UL_DeInitUart_XXXX(pPort->pUart); // DeInit UART pPort->pUart = NULL; pPort->pUartLib = NULL; // NULL pointer to UART library functions. // Free identifier string allocations... if(pPort->DeviceID.Buffer != NULL) ExFreePool(pPort->DeviceID.Buffer); if(pPort->InstanceID.Buffer != NULL) ExFreePool(pPort->InstanceID.Buffer); if(pPort->HardwareIDs.Buffer != NULL) ExFreePool(pPort->HardwareIDs.Buffer); if(pPort->DevDesc.Buffer != NULL) ExFreePool(pPort->DevDesc.Buffer); if(pPort->DevLocation.Buffer != NULL) ExFreePool(pPort->DevLocation.Buffer); return status; }