// CprDrvr.c // // // Requires DDK Only // File created on 2/2/2005 // #include "pch.h" #ifdef CPR_WMI_TRACE #include "Cpr.tmh" #endif // global data CPR_DATA g_Data; char _ascii[20]; /////////////////////////////////////////////////////////////////////////////////////////////////// // DriverEntry // Installable driver initialization entry point. // This entry point is called directly by the I/O system. // // Arguments: // IN DriverObject // pointer to the driver object // // IN RegistryPath // pointer to a unicode string representing the path, // to driver-specific key in the registry. // // Return Value: // Status // NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { NTSTATUS status; HANDLE hRegKey; UNICODE_STRING regPath; ULONG length; PVOID regBuffer; CprDebugPrint4(NULL, DBG_INIT, DBG_TRACE, __FUNCTION__"++ DriverObject %p Version %s Compiled at %s on %s", DriverObject, CPR_DRVR_VERSION, __TIME__, __DATE__); CprDebugPrint3(NULL, DBG_INIT, DBG_INFO, __FUNCTION__" Operating System Version %d.%d.%d", g_Data.OsMajorVersion, g_Data.OsMinorVersion, g_Data.OsBuildNumber); #ifdef DBG // DbgBreakPoint(); #endif #ifdef CPR_WMI_TRACE WPP_INIT_TRACING(DriverObject, RegistryPath); #endif status = STATUS_SUCCESS; RtlZeroMemory(&g_Data, sizeof(CPR_DATA)); // save registry path for wmi g_Data.RegistryPath.Length = RegistryPath->Length; g_Data.RegistryPath.MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL); g_Data.RegistryPath.Buffer = (PWCHAR)ExAllocatePoolWithTag( PagedPool, g_Data.RegistryPath.MaximumLength, CPR_POOL_TAG_REG_PATH ); g_Data.PerformLockToLtx = TRUE; g_Data.NoServiceRollover = FALSE; g_Data.NumLtxRequests = 2; g_Data.LtxRequestWaitTime = 1000; // Wait 1 second if (g_Data.RegistryPath.Buffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; CprDebugPrint(NULL, DBG_INIT, DBG_ERR, __FUNCTION__": Failed to allocate memory for RegistryPath"); return status; } RtlCopyUnicodeString(&g_Data.RegistryPath, RegistryPath); //osVersion.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); //RtlGetVersion(&osVersion); //g_Data.OsMajorVersion = osVersion.dwMajorVersion; //g_Data.OsMinorVersion = osVersion.dwMinorVersion; //g_Data.OsBuildNumber = osVersion.dwBuildNumber; PsGetVersion( (PULONG)&g_Data.OsMajorVersion, (PULONG)&g_Data.OsMinorVersion, (PULONG)&g_Data.OsBuildNumber, NULL); // detect current operating system if (IoIsWdmVersionAvailable(1, 0x30)) { g_Data.WdmVersion = 0x0130; } else if (IoIsWdmVersionAvailable(1, 0x20)) { g_Data.WdmVersion = 0x0120; } else if (IoIsWdmVersionAvailable(1, 0x10)) { g_Data.WdmVersion = 0x0110; } else if (IoIsWdmVersionAvailable(1, 0x05)) { g_Data.WdmVersion = 0x0105; } else { g_Data.WdmVersion = 0x0100; } DriverEntry_Wsk(); // Read our registry values from the registry // setup our dispatch function table in the driver object DriverObject->MajorFunction[IRP_MJ_PNP] = (PDRIVER_DISPATCH)CprPnpDispatch; DriverObject->MajorFunction[IRP_MJ_POWER] = (PDRIVER_DISPATCH)CprPowerDispatch; DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)CprCreateDispatch; DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)CprCloseDispatch; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)CprDeviceIoControlDispatch; DriverObject->MajorFunction[IRP_MJ_READ] = (PDRIVER_DISPATCH)CprReadDispatch; DriverObject->MajorFunction[IRP_MJ_WRITE] = (PDRIVER_DISPATCH)CprWriteDispatch; DriverObject->MajorFunction[IRP_MJ_CLEANUP] = (PDRIVER_DISPATCH)CprCleanupDispatch; DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = (PDRIVER_DISPATCH)CprSystemControlDispatch; DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = (PDRIVER_DISPATCH)CprFlushBuffersDispatch; DriverObject->DriverExtension->AddDevice = CprAddDevice; DriverObject->DriverUnload = CprUnload; // register tdi pnp callbacks status = CprTdiStartup(RegistryPath); if (!NT_SUCCESS(status)) { ExFreePool(g_Data.RegistryPath.Buffer); g_Data.RegistryPath.Buffer = NULL; CprDebugPrint1(NULL, DBG_INIT, DBG_ERR, __FUNCTION__"$$--. STATUS %x", status); return status; } g_Data.InstanceCount = 0; g_Data.updateDriver = FALSE; CprInitBackdoorDevice(DriverObject); CprInitializeEventLog(); #ifdef SCPR g_Data.AESEnabled = TRUE; CprAESInit(); #endif CprDebugPrint3(NULL, DBG_INIT, DBG_TRACE, __FUNCTION__"-- OS Version: %d.%d.%d", g_Data.OsMajorVersion, g_Data.OsMinorVersion, g_Data.OsBuildNumber); return STATUS_SUCCESS; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprAddDevice // The PnP manager new device callback // // Arguments: // IN DeviceObject // pointer to a device object. // // IN PhysicalDeviceObject // pointer to a device object created by the // underlying bus driver. // // Return Value: // Status // NTSTATUS CprAddDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject ) { NTSTATUS status; PDEVICE_OBJECT deviceObject; PCPR_DEVICE_EXTENSION deviceExtension = NULL; POWER_STATE powerState; UNICODE_STRING ntName; UNICODE_STRING instanceString; WCHAR instanceStringBuffer[20]; HANDLE keyHandle; UNICODE_STRING linkName; PWCHAR regName = NULL; int portNumber = 0; int wideCharToInt(PWCHAR wChar); //_asm INT 3; __try { CprDebugPrint5(NULL, DBG_INIT, DBG_TRACE, __FUNCTION__"++ DriverObject %p PDO %p Version %s Compiled at %s on %s", DriverObject, PhysicalDeviceObject, CPR_DRVR_VERSION, __TIME__, __DATE__); CprDebugPrint3(NULL, DBG_INIT, DBG_INFO, __FUNCTION__": OS Version: %d.%d.%d", g_Data.OsMajorVersion, g_Data.OsMinorVersion, g_Data.OsBuildNumber); linkName.Buffer = NULL; // open device hardware key status = IoOpenDeviceRegistryKey(PhysicalDeviceObject, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_READ, &keyHandle); if (!NT_SUCCESS(status)) { return status; } RtlZeroMemory(&linkName, sizeof(UNICODE_STRING)); // get our device object symbolic link name status = CprSerialReadSymName(NULL, keyHandle, &linkName, ®Name); ZwClose(keyHandle); if (!NT_SUCCESS(status)) { return status; } if (regName != NULL) { CprDebugPrint1(NULL, DBG_INIT, DBG_INFO, __FUNCTION__": REGNAME %S", regName); if (regName[0] != '\0') { portNumber = wideCharToInt(®Name[3]); } CprDebugPrint1(NULL, DBG_INIT, DBG_INFO, __FUNCTION__": PORTNUMBER %d", portNumber); ExFreePool(regName); } // create device object name ntName.Length = 0; ntName.MaximumLength = sizeof(CPR_DRIVER_NAME) + 20; ntName.Buffer = (PWCHAR)ExAllocatePoolWithTag( PagedPool, ntName.MaximumLength, CPR_POOL_TAG_DRIVER_NAME); if (ntName.Buffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; CprDebugPrint1(NULL, DBG_INIT, DBG_ERR, __FUNCTION__"--. STATUS %x", status); return status; } RtlZeroMemory(ntName.Buffer, ntName.MaximumLength); RtlAppendUnicodeToString(&ntName, CPR_DRIVER_NAME); instanceString.Length = 0; instanceString.MaximumLength = sizeof(instanceStringBuffer); instanceString.Buffer = instanceStringBuffer; // RtlIntegerToUnicodeString(g_Data.InstanceCount, 10, &instanceString); RtlIntegerToUnicodeString(portNumber, 10, &instanceString); RtlAppendUnicodeStringToString(&ntName, &instanceString); // Create our function device object. status = IoCreateDevice( DriverObject, sizeof (CPR_DEVICE_EXTENSION), &ntName, FILE_DEVICE_SERIAL_PORT, FILE_DEVICE_SECURE_OPEN, // Do not use if binary intended for 9x FALSE, &deviceObject ); if (!NT_SUCCESS(status)) { ExFreePool(ntName.Buffer); CprDebugPrint1(NULL, DBG_INIT, DBG_ERR, __FUNCTION__"--. IoCreateDevice STATUS %x", status); return status; } CprDebugPrint1(NULL, DBG_INIT, DBG_INFO, __FUNCTION__": Created FDO %p", deviceObject); // Initialize the device extension. deviceExtension = (PCPR_DEVICE_EXTENSION)deviceObject->DeviceExtension; // Zero the memory RtlZeroMemory(deviceExtension, sizeof(CPR_DEVICE_EXTENSION)); // save our device object deviceExtension->DeviceObject = deviceObject; // save the PDO pointer deviceExtension->PhysicalDeviceObject = PhysicalDeviceObject; // save device name deviceExtension->DeviceName = ntName; // Initialize the powering down flag deviceExtension->bPowerStop = FALSE; ComStatusChange(deviceExtension, CPR_COM_STATUS_CLOSED); NetworkStatusChange(deviceExtension, CPR_NETWORK_STATUS_DISCONNECTED); RtlZeroMemory(deviceExtension->Validated, sizeof(BOOLEAN) * MAX_SERVICES); deviceExtension->LtxLockCount = 1; deviceExtension->LtxLockInterval = 250; deviceExtension->LtxLockTestAgain = 10; // setup our queue array deviceExtension->QueueArray[0] = &deviceExtension->WriteQueue; deviceExtension->QueueArray[1] = &deviceExtension->MaskQueue; deviceExtension->QueueArray[2] = &deviceExtension->ReadQueue; deviceExtension->QueueArray[3] = &deviceExtension->PurgeQueue; // Initialize WriteQueue Queue CprInitializeQueue( &deviceExtension->WriteQueue, WriteQueueStartIo, WriteQueueStatusChange, deviceExtension->DeviceObject, TRUE ); // Initialize MaskQueue Queue CprInitializeQueue( &deviceExtension->MaskQueue, MaskQueueStartIo, MaskQueueStatusChange, deviceExtension->DeviceObject, TRUE ); // Initialize ReadQueue Queue CprInitializeQueue( &deviceExtension->ReadQueue, ReadQueueStartIo, ReadQueueStatusChange, deviceExtension->DeviceObject, TRUE ); // Initialize PurgeQueue Queue CprInitializeQueue( &deviceExtension->PurgeQueue, PurgeQueueStartIo, PurgeQueueStatusChange, deviceExtension->DeviceObject, TRUE ); // initialize serial interface lock KeInitializeSpinLock(&deviceExtension->SerialLock); // initialize reconnecting resources KeInitializeTimer(&deviceExtension->ReconnectTimer); KeInitializeDpc(&deviceExtension->ReconnectTimeoutDpc, CprTdiReconnectTimeout, deviceExtension); //deviceExtension->Reconnecting = FALSE; // initialize write resources KeInitializeTimer(&deviceExtension->WriteTimer); KeInitializeDpc(&deviceExtension->WriteCompleteDpc, CprSerialWriteComplete, deviceExtension); KeInitializeDpc(&deviceExtension->WriteTimeoutDpc, CprSerialWriteTimeout, deviceExtension); // initialize read resources KeInitializeTimer(&deviceExtension->ReadTimer); KeInitializeTimer(&deviceExtension->ReadIntervalTimer); KeInitializeDpc(&deviceExtension->ReadCompleteDpc, CprSerialReadComplete, deviceExtension); KeInitializeDpc(&deviceExtension->ReadTimeoutDpc, CprSerialReadTimeout, deviceExtension); KeInitializeDpc(&deviceExtension->ReadIntervalTimeoutDpc, CprSerialReadIntervalTimeout, deviceExtension); // initialize immediate char write resources KeInitializeTimer(&deviceExtension->ImmediateCharTimer); KeInitializeDpc(&deviceExtension->ImmediateCharCompleteDpc, CprSerialImmediateCharComplete, deviceExtension); KeInitializeDpc(&deviceExtension->ImmediateCharTimeoutDpc, CprSerialImmediateCharTimeout, deviceExtension); // initialize xoff counter resources KeInitializeTimer(&deviceExtension->XoffTimer); KeInitializeDpc(&deviceExtension->XoffTimeoutDpc, CprSerialXoffTimeout, deviceExtension); KeInitializeDpc(&deviceExtension->XoffCompleteDpc, CprSerialXoffComplete, deviceExtension); // initialize wait on mask resources KeInitializeDpc(&deviceExtension->WaitCompleteDpc, CprSerialWaitComplete, deviceExtension); // initialize error io abort resources KeInitializeDpc(&deviceExtension->ErrorDpc, CprSerialError, deviceExtension); // initialize deviceExtension->SerialChars.XonChar = CPR_SERIAL_DEF_XON; deviceExtension->SerialChars.XoffChar = CPR_SERIAL_DEF_XOFF; deviceExtension->SerialHandFlow.ControlHandShake = SERIAL_DTR_CONTROL; deviceExtension->SerialHandFlow.FlowReplace = SERIAL_RTS_CONTROL; // 9600 8-N-1 deviceExtension->LineControl = CPR_UART_LCR_8_DATA | CPR_UART_LCR_NONE_PARITY | SERIAL_WMI_STOP_1; deviceExtension->DataMask = 0xff; deviceExtension->BaudRate = 9600; // initialize short interval to the shortest possible // initialize long interval to 1 second // and set the boundary at 2 seconds deviceExtension->ShortIntervalAmount.QuadPart = -1; deviceExtension->LongIntervalAmount.QuadPart = -10000000; deviceExtension->CutOverAmount.QuadPart = 200000000; // set RemoveCount to 1. Transition to zero // means IRP_MN_REMOVE_DEVICE was received deviceExtension->RemoveCount = 1; // Initialize Remove event KeInitializeEvent(&deviceExtension->RemoveEvent, NotificationEvent, FALSE); // initialize io lock CprInitializeIoLock(&deviceExtension->IoLock, deviceObject); deviceExtension->PnpState = PnpStateNotStarted; deviceExtension->PreviousPnpState = PnpStateNotStarted; // Read our registry values from the registry CprReadRegistry(deviceExtension); if ((deviceExtension->portNumber == 0) && (portNumber > 0) && (portNumber <= MAX_PORTS)) { deviceExtension->portNumber = portNumber; } // allocate WorkItem for power processing deviceExtension->PowerWorkItem = IoAllocateWorkItem(deviceExtension->DeviceObject); if (deviceExtension->PowerWorkItem == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; //deviceExtension->DeviceObject = NULL; //IoDeleteDevice(deviceObject); //ExFreePool(ntName.Buffer); //deviceExtension->DeviceName.Buffer = NULL; CprDebugPrint(deviceExtension, DBG_INIT, DBG_ERR, __FUNCTION__"--. Failed to allocated PowerWorkItem"); return status; } // Initialize the device object flags // All WDM drivers are supposed to set this flag. Devices // requiring a large amount of current at statup set the // DO_POWER_INRUSH flag instead. These flags are mutually // exclusive. deviceObject->Flags |= DO_POWER_PAGABLE; // This flag sets the buffering method for reads and writes // to METHOD_BUFFERED. IOCTLs are handled by IO control codes // independent of the value of this flag. deviceObject->Flags |= DO_BUFFERED_IO; // Typically, (almost always) the function driver for a device is the // power policy owner for that device. In some cases // another driver or system component may assume this role. // Set the initial device power state of the device to powered down. deviceExtension->DevicePowerState = PowerDeviceD3; powerState.DeviceState = deviceExtension->DevicePowerState; // the initial system power state must be working or we wouldn't be here. deviceExtension->SystemPowerState = PowerSystemWorking; // Call PoSetPowerState to notify the power manager of our initial power state. PoSetPowerState(deviceObject, DevicePowerState, powerState); // Attach our device to the device stack and get the device object to // which we send down IRPs to. deviceExtension->LowerDeviceObject = IoAttachDeviceToDeviceStack( deviceObject, PhysicalDeviceObject ); if (deviceExtension->LowerDeviceObject == NULL) { status = STATUS_DEVICE_REMOVED; //IoFreeWorkItem(deviceExtension->PowerWorkItem); //deviceExtension->PowerWorkItem = NULL; //deviceExtension->DeviceObject = NULL; //IoDeleteDevice(deviceObject); //ExFreePool(ntName.Buffer); //deviceExtension->DeviceName.Buffer = NULL; CprDebugPrint(deviceExtension, DBG_INIT, DBG_ERR, __FUNCTION__"--. IoAttachDeviceToDeviceStack failed"); return status; } if (g_Data.BackdoorDevice != NULL) { PBACKDOOR_DEVICE_EXTENSION BackdoorDevExt = (PBACKDOOR_DEVICE_EXTENSION)g_Data.BackdoorDevice->DeviceExtension; if ((portNumber > 0) && (portNumber <= MAX_PORTS)) { BackdoorDevExt->serialDevice[portNumber] = deviceObject; deviceExtension->BackdoorDevice = g_Data.BackdoorDevice; } else { status = STATUS_INTERNAL_ERROR; if (g_Data.InstanceCount == 0) { CprDeleteBackdoorDevice(); } //IoFreeWorkItem(deviceExtension->PowerWorkItem); //deviceExtension->PowerWorkItem = NULL; //deviceExtension->DeviceObject = NULL; //IoDeleteDevice(deviceObject); //ExFreePool(ntName.Buffer); //deviceExtension->DeviceName.Buffer = NULL; CprDebugPrint1(deviceExtension, DBG_INIT, DBG_ERR, __FUNCTION__"--. Invalid Port Number: %d", portNumber); return status; } // increment device instance count ++g_Data.InstanceCount; } else { status = STATUS_INSUFFICIENT_RESOURCES; //IoFreeWorkItem(deviceExtension->PowerWorkItem); //deviceExtension->PowerWorkItem = NULL; //deviceExtension->DeviceObject = NULL; //IoDeleteDevice(deviceObject); //ExFreePool(ntName.Buffer); //deviceExtension->DeviceName.Buffer = NULL; CprDebugPrint(deviceExtension, DBG_INIT, DBG_ERR, __FUNCTION__": Failed to allocate memory for Backdoor Device."); return status; } // We are all done, so we need to clear the // DO_DEVICE_INITIALIZING flag. This must be our // last action in AddDevice deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; CprDebugPrint1(deviceExtension, DBG_INIT, DBG_TRACE, __FUNCTION__"--. STATUS %x", status); } __except( EXCEPTION_EXECUTE_HANDLER ) { status = STATUS_INTERNAL_ERROR; } if (linkName.Buffer != NULL) { ExFreePool(linkName.Buffer); } return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprReadRegistry // Read values from the registry // // Arguments: // IN DeviceObject // pointer to a device object. // // IN PhysicalDeviceObject // pointer to a device object created by the // underlying bus driver. // // Return Value: // Status // NTSTATUS CprReadRegistry( PCPR_DEVICE_EXTENSION deviceExtension ) { HANDLE hRegKey; NTSTATUS status; TCHAR *tmpStr; // Attempt to open our root key status = IoOpenDeviceRegistryKey( deviceExtension->PhysicalDeviceObject, PLUGPLAY_REGKEY_DRIVER, KEY_ALL_ACCESS, &hRegKey ); if (!NT_SUCCESS(status)) { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__": Failed to open device root registry key %x", status); return status; } // Attempt to read PortNumber value status = CprRegQueryValueKey( hRegKey, _T("Properties"), _T("PortNumber"), &deviceExtension->portNumber ); // Reset Lantronix Locking try mechanism // deviceExtension->LtxLockCount = 1; deviceExtension->LtxLockInterval = 250; deviceExtension->LtxLockTestAgain = 10; if (NT_SUCCESS(status)) { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->portNumber = %d", deviceExtension->portNumber); } else { CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->portNumber (FAILED)"); } // Attempt to read UseRFC2217 value status = CprRegQueryValueKey( hRegKey, _T("Properties"), _T("UseRFC2217"), &deviceExtension->UseRFC2217 ); if (NT_SUCCESS(status)) { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->UseRFC2217 = %d", deviceExtension->UseRFC2217); } else { CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->UseRFC2217 (FAILED)"); } // Attempt to read DtrConnection value status = CprRegQueryValueKey( hRegKey, _T("Properties"), _T("DtrConnection"), &deviceExtension->DtrConnection ); if (NT_SUCCESS(status)) { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->DtrConnection = %d", deviceExtension->DtrConnection); } else { CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->DtrConnection (FAILED)"); } // Attempt to read AES value status = CprRegQueryValueKey( hRegKey, _T("Properties"), _T("AES"), &deviceExtension->AES ); if (NT_SUCCESS(status)) { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->AES = %d", deviceExtension->AES); } else { CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->AES (FAILED)"); } // Attempt to read AESKey value status = CprRegQueryValueKey( hRegKey, _T("Properties"), _T("AESKey"), deviceExtension->AESKey ); if (NT_SUCCESS(status)) { // RtlZeroMemory(deviceExtension->AESKey, sizeof(deviceExtension->AESKey)); //RtlCopyMemory(deviceExtension->AESKey, tmpStr, _tcslen(tmpStr) * 2); //ExFreePool(tmpStr); // Should probably use CprDumpBuffer here: CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->AESKey = %S", deviceExtension->AESKey); } else { CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->AESKey (FAILED)"); } //status = CprRegQueryValueKey( // hRegKey, // _T("Properties"), // _T("AESKey"), // &tmpStr // ); //if (NT_SUCCESS(status)) //{ // RtlZeroMemory(deviceExtension->AESKey, sizeof(deviceExtension->AESKey)); // RtlCopyMemory(deviceExtension->AESKey, tmpStr, _tcslen(tmpStr) * 2); // ExFreePool(tmpStr); // CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->AESKey = %S", deviceExtension->AESKey); //} //else //{ // CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->AESKey (FAILED)"); //} // Attempt to read our value key status = CprRegQueryValueKey( hRegKey, _T("Properties"), _T("AESKeyLength"), &deviceExtension->AESKeyLength ); if (NT_SUCCESS(status)) { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->AESKeyLength = %d", deviceExtension->AESKeyLength); } else { CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->AESKeyLength (FAILED)"); } // Attempt to read AutoReconErr value status = CprRegQueryValueKey( hRegKey, _T("Properties"), _T("AutoReconErr"), &deviceExtension->AutoReconErr ); if (NT_SUCCESS(status)) { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->AutoReconErr = %d", deviceExtension->AutoReconErr); } else { CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->AutoReconErr (FAILED)"); } // Attempt to read AutoReconPeer value status = CprRegQueryValueKey( hRegKey, _T("Properties"), _T("AutoReconPeer"), &deviceExtension->AutoReconPeer ); if (NT_SUCCESS(status)) { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->AutoReconPeer = %d", deviceExtension->AutoReconPeer); } else { CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->AutoReconPeer (FAILED)"); } // Attempt to read CnTmo value status = CprRegQueryValueKey( hRegKey, _T("Properties"), _T("CnTmo"), &deviceExtension->CnTmo ); if (NT_SUCCESS(status)) { if (deviceExtension->CnTmo == 0) deviceExtension->CnTmo = 1; CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->CnTmo = %d", deviceExtension->CnTmo); } else { CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->CnTmo (FAILED)"); } // Attempt to read NoDiscon value status = CprRegQueryValueKey( hRegKey, _T("Properties"), _T("NoDiscon"), &deviceExtension->NoDiscon ); if (NT_SUCCESS(status)) { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->NoDiscon = %d", deviceExtension->NoDiscon); } else { CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->NoDiscon (FAILED)"); } // Attempt to read ReconLimit value status = CprRegQueryValueKey( hRegKey, _T("Properties"), _T("ReconLimit"), &deviceExtension->ReconLimit ); if (NT_SUCCESS(status)) { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->ReconLimit = %d", deviceExtension->ReconLimit); } else { CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->ReconLimit (FAILED)"); } // Attempt to read WaitOnWrite value status = CprRegQueryValueKey( hRegKey, _T("Properties"), _T("WaitOnWrite"), &deviceExtension->WaitOnWrite ); if (NT_SUCCESS(status)) { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->WaitOnWrite = %d", deviceExtension->WaitOnWrite); } else { CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->WaitOnWrite (FAILED)"); } // Attempt to read BufferWrites value status = CprRegQueryValueKey( hRegKey, _T("Properties"), _T("BufferWrites"), &deviceExtension->BufferWrites ); if (NT_SUCCESS(status)) { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->BufferWrites = %d", deviceExtension->BufferWrites); } else { CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->BufferWrites (FAILED)"); } // Make sure I read BufferWrites after WaitOnWrite // because cannot WaitOnWrite and BufferWrites #ifdef USE_WAIT_ON_WRITES if (deviceExtension->WaitOnWrite) { deviceExtension->BufferWrites = FALSE; } #endif // Attempt to read TransmitEmpty value status = CprRegQueryValueKey( hRegKey, _T("Properties"), _T("TransmitEmpty"), &deviceExtension->TransmitEmpty ); if (NT_SUCCESS(status)) { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->TransmitEmpty = %d", deviceExtension->TransmitEmpty); } else { CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->TransmitEmpty (FAILED)"); } // Force Device Server as TxEmpty target, CPR as target // is not a good thing for the user to use. The port // could be closed and data purged while data is // still in the device. // deviceExtension->TransmitEmpty = TX_EMPTY_SERVER; // Attempt to read ListenMode value status = CprRegQueryValueKey( hRegKey, _T("Properties"), _T("ListenMode"), &deviceExtension->ListenMode ); if (NT_SUCCESS(status)) { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->ListenMode = %d", deviceExtension->ListenMode); } else { CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->ListenMode (FAILED)"); } // Attempt to read KeepAliveOnOff value status = CprRegQueryValueKey( hRegKey, _T("Properties"), _T("KeepAliveOnOff"), &deviceExtension->KeepAliveOnOff ); if (NT_SUCCESS(status)) { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->KeepAliveOnOff = %d", deviceExtension->KeepAliveOnOff); } else { CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->KeepAliveOnOff (FAILED)"); } // Attempt to read KeepAliveTime value status = CprRegQueryValueKey( hRegKey, _T("Properties"), _T("KeepAliveTime"), &deviceExtension->KeepAliveTime ); if (NT_SUCCESS(status)) { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->KeepAliveTime = %d", deviceExtension->KeepAliveTime); } else { CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->KeepAliveTime (FAILED)"); } // Attempt to read KeepAliveInterval value status = CprRegQueryValueKey( hRegKey, _T("Properties"), _T("KeepAliveInterval"), &deviceExtension->KeepAliveInterval ); if (NT_SUCCESS(status)) { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->KeepAliveInterval = %d", deviceExtension->KeepAliveInterval); } else { CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->KeepAliveInterval (FAILED)"); } // Attempt to read NumServices value status = CprRegQueryValueKey( hRegKey, _T("Properties"), _T("NumServices"), &deviceExtension->NumServices ); if (NT_SUCCESS(status)) { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->NumServices = %d", deviceExtension->NumServices); } else { CprDebugPrint(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->NumServices (FAILED)"); } if (deviceExtension->NumServices != 0) { ULONG i; //if ((deviceExtension->NumServices > 1) && g_Data.NoServiceRollover) // deviceExtension->NumServices = 1; for (i = 0; (i < deviceExtension->NumServices) && (i < MAX_SERVICES); i++) { WCHAR keyStr[50]; RtlStringCchPrintfW(keyStr, 50, _T("Properties\\Service%d"), i); // Attempt to read Type value status = CprRegQueryValueKey( hRegKey, keyStr, _T("Type"), &deviceExtension->Services[i].Type ); if (NT_SUCCESS(status)) { CprDebugPrint2(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->Services[%d].Type = %d", i, deviceExtension->Services[i].Type); } // Attempt to read Address value status = CprRegQueryValueKey( hRegKey, keyStr, _T("Address"), &tmpStr ); if (NT_SUCCESS(status)) { RtlZeroMemory(deviceExtension->Services[i].Address, sizeof(deviceExtension->Services[i].Address)); RtlCopyMemory(deviceExtension->Services[i].Address, tmpStr, _tcslen(tmpStr) * sizeof(TCHAR)); ExFreePool(tmpStr); CprDebugPrint2(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->Services[%d].Address = %S", i, deviceExtension->Services[i].Address); } else { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->Services[%d].Address (FAILED)", i); } // Attempt to read Port value status = CprRegQueryValueKey( hRegKey, keyStr, _T("Port"), &deviceExtension->Services[i].Port ); if (NT_SUCCESS(status)) { CprDebugPrint2(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->Services[%d].Port = %d", i, deviceExtension->Services[i].Port); } else { CprDebugPrint1(deviceExtension, DBG_PNP, DBG_INFO, __FUNCTION__ ": deviceExtension->Services[%d].Port (FAILED)", i); } } } // Close our root key handle ZwClose(hRegKey); return status; } #if 0 typedef enum _TOKEN_INFORMATION_CLASS { TokenUser = 1, TokenGroups, TokenPrivileges, TokenOwner, TokenPrimaryGroup, TokenDefaultDacl, TokenSource, TokenType, TokenImpersonationLevel, TokenStatistics, TokenRestrictedSids, TokenSessionId, TokenGroupsAndPrivileges, TokenSessionReference, TokenSandBoxInert, TokenAuditPolicy, TokenOrigin } TOKEN_INFORMATION_CLASS, *PTOKEN_INFORMATION_CLASS; typedef PVOID PACCESS_TOKEN; typedef struct _SECURITY_SUBJECT_CONTEXT { PACCESS_TOKEN ClientToken; SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; PACCESS_TOKEN PrimaryToken; PVOID ProcessAuditId; } SECURITY_SUBJECT_CONTEXT, *PSECURITY_SUBJECT_CONTEXT; NTSTATUS SeQueryInformationToken( IN PACCESS_TOKEN Token, IN TOKEN_INFORMATION_CLASS TokenInformationClass, OUT PVOID *TokenInformation ); VOID SeCaptureSubjectContext( OUT PSECURITY_SUBJECT_CONTEXT SubjectContext ); #endif /////////////////////////////////////////////////////////////////////////////////////////////////// // CprCreateDispatch // Dispatch routine for IRP_MJ_CREATE requests. // // Arguments: // IN DeviceObject // pointer to the device object for our device // // IN Irp // the create IRP // // Return Value: // NT status code. // NTSTATUS CprCreateDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PCPR_DEVICE_EXTENSION deviceExtension = NULL; NTSTATUS status; //KIRQL oldIrql; //PIO_STACK_LOCATION irpStack; char Msg[CPR_EVENT_MSG_SIZE]; char *sendMsg = NULL; //BOOLEAN removeLockToLtx; Msg[0] = '\0'; __try { deviceExtension = (PCPR_DEVICE_EXTENSION)DeviceObject->DeviceExtension; CprDebugPrint2(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"++: Version %s IRP %p", CPR_DRVR_VERSION, Irp); if (DeviceObject->DeviceType == FILE_DEVICE_CPR) { PBACKDOOR_DEVICE_EXTENSION ext = DeviceObject->DeviceExtension; Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0L; ext->opened = 1; IoCompleteRequest(Irp, IO_NO_INCREMENT); CprDebugPrint1(NULL, DBG_CREATECLOSE, DBG_WARN, __FUNCTION__"$$-- FILE_DEVICE_CPR. IRP %p", Irp); return STATUS_SUCCESS; } ComStatusChange(deviceExtension, CPR_COM_STATUS_OPENING); status = CprOpenPort(deviceExtension, Irp); if (status != STATUS_SUCCESS) { ComStatusChange(deviceExtension, CPR_COM_STATUS_CLOSED); } //CprReleaseRemoveLock(deviceExtension); Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); if (LoggingEvent) { if (status == STATUS_SUCCESS) { if (deviceExtension->UseRFC2217) RtlStringCchPrintfA(Msg, sizeof(Msg), "RFC2217 is enabled"); else RtlStringCchPrintfA(Msg, sizeof(Msg), "RFC2217 is disabled"); } if (Msg[0] != '\0') sendMsg = Msg; CprLogEvent( CPR_EVENT_TYPE_OPEN, CPR_EVENT_SUB_TYPE_NONE, deviceExtension, status, sendMsg); } CprDebugPrint3(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"--. IRP %p, STATUS %x ENABLED? %d", Irp, status, deviceExtension->IsDeviceEnabled); } __except( EXCEPTION_EXECUTE_HANDLER ) { ComStatusChange(deviceExtension, CPR_COM_STATUS_ERROR); status = STATUS_INTERNAL_ERROR; } return status; } NTSTATUS CprOpenPort( PCPR_DEVICE_EXTENSION deviceExtension, PIRP Irp ) { NTSTATUS status; KIRQL oldIrql; PIO_STACK_LOCATION irpStack; DWORD removeLockToLtx; DWORD redirectorRollOver; CprDebugPrint1(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"++: IRP %p", Irp); // check if device was removed if (!CprAcquireRemoveLock(deviceExtension)) { status = STATUS_NO_SUCH_DEVICE; CprDebugPrint1(deviceExtension, DBG_CREATECLOSE, DBG_WARN, __FUNCTION__"$$-- not Removed. STATUS %x", status); return status; } if ((deviceExtension->OpenHandleCount == 1) && (deviceExtension->NoDiscon) && (deviceExtension->NetworkStatus == CPR_NETWORK_STATUS_CONNECTED)) { ComStatusChange(deviceExtension, CPR_COM_STATUS_OPEN); CprDebugPrint(deviceExtension, DBG_CREATECLOSE, DBG_WARN, __FUNCTION__"$$-- NoNetClose"); CprReleaseRemoveLock(deviceExtension); return STATUS_SUCCESS; } while (deviceExtension->OpenHandleCount < 0) { // We had a bad close somewhere, Get it back to zero. InterlockedIncrement(&deviceExtension->OpenHandleCount); } if (InterlockedIncrement(&deviceExtension->OpenHandleCount) != 1) { status = STATUS_ACCESS_DENIED; InterlockedDecrement(&deviceExtension->OpenHandleCount); CprReleaseRemoveLock(deviceExtension); CprDebugPrint1(deviceExtension, DBG_CREATECLOSE, DBG_WARN, __FUNCTION__"$$-- Already Opened. STATUS %x", status); return status; } if (Irp) { // verify that user is not trying to open a directory irpStack = IoGetCurrentIrpStackLocation(Irp); if (irpStack->Parameters.Create.Options & FILE_DIRECTORY_FILE) { status = STATUS_NOT_A_DIRECTORY; InterlockedDecrement(&deviceExtension->OpenHandleCount); CprReleaseRemoveLock(deviceExtension); CprDebugPrint2(deviceExtension, DBG_CREATECLOSE, DBG_WARN, __FUNCTION__"$$-- Opening a Directory. IRP %p, STATUS %x", Irp, status); return status; } } #ifdef SCPR // Hardcode off. // AES is not available in CPR 4.1.0.0 // but will be availabe in the next // release which will probably be // CPR 4.2.0.0 // //deviceExtension->AES = g_Data.AESEnabled; //DbgPrint("%s - %p %d %d\n", __FUNCTION__, g_Data, g_Data.MaxAesSessions, g_Data.CurAesSessions); if (deviceExtension->AES) { //if (InterlockedIncrement(&g_Data.CurAesSessions) > g_Data.MaxAesSessions) //{ // status = STATUS_CONNECTION_REFUSED; // InterlockedDecrement(&deviceExtension->OpenHandleCount); // InterlockedDecrement(&g_Data.CurAesSessions); // CprReleaseRemoveLock(deviceExtension); // CprDebugPrint1(deviceExtension, DBG_CREATECLOSE, DBG_WARN, __FUNCTION__"$$-- Max AES ports already reached. STATUS %x", status); // return status; //} CprPortAESInit(deviceExtension); } #endif // // RLTLtx = Remove Lock To LanTroniX // status = CprRegQueryValueKey( NULL, g_Data.RegistryPath.Buffer, _T("RLTLtx"), &removeLockToLtx ); if (NT_SUCCESS(status)) { if (removeLockToLtx == TRUE) { g_Data.PerformLockToLtx = FALSE; } else { g_Data.PerformLockToLtx = TRUE; } } else { g_Data.PerformLockToLtx = TRUE; } // // Rro = Redirector RollOver // // Cooper Power: Disable Roll over status = CprRegQueryValueKey( NULL, CPR_ROLLOVER_PATH, _T("Rro"), &redirectorRollOver ); if (NT_SUCCESS(status)) { g_Data.NoServiceRollover = TRUE; } else { g_Data.NoServiceRollover = FALSE; } // Get the Terminal Services Session ID deviceExtension->sessionId = GetSessionId(); CprDebugPrint2(deviceExtension, DBG_CREATECLOSE, DBG_INFO, " ***>> PortNumber %d SessionId %d", deviceExtension->portNumber, deviceExtension->sessionId); //NetworkStatusChange(deviceExtension, CPR_NETWORK_STATUS_CONNECTING); //deviceExtension->Reconnecting = FALSE; //deviceExtension->Connecting = TRUE; deviceExtension->Cancelled = FALSE; // allocate read queue. Used to save received data in case there is no // outstanding IRP_MJ_READ irp deviceExtension->QueueBuffer = NULL; deviceExtension->QueueSize = PAGE_SIZE; deviceExtension->QueueBuffer = (PUCHAR)ExAllocatePoolWithTag( NonPagedPool, deviceExtension->QueueSize, CPR_POOL_TAG_BUFFER); if (deviceExtension->QueueBuffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; //#ifdef SCPR // if (deviceExtension->AES) // { // InterlockedDecrement(&g_Data.CurAesSessions); // } //#endif deviceExtension->QueueSize = 0; InterlockedDecrement(&deviceExtension->OpenHandleCount); CprReleaseRemoveLock(deviceExtension); CprDebugPrint1(deviceExtension, DBG_CREATECLOSE, DBG_WARN, __FUNCTION__"$$-- Allocation Error. STATUS %x", status); return status; } deviceExtension->WriteLength = 0; deviceExtension->SystemWriteInProgress = FALSE; // Should we allow the default setting to be grabbed from // the Device Manager screen??? // // 9600 8-N-1 deviceExtension->LineControl = CPR_UART_LCR_8_DATA | CPR_UART_LCR_NONE_PARITY | SERIAL_WMI_STOP_1; deviceExtension->DataMask = 0xff; deviceExtension->BaudRate = 9600; // initialize deviceExtension->SerialChars.XonChar = CPR_SERIAL_DEF_XON; deviceExtension->SerialChars.XoffChar = CPR_SERIAL_DEF_XOFF; deviceExtension->SerialHandFlow.ControlHandShake = 0; deviceExtension->SerialHandFlow.FlowReplace = 0; //deviceExtension->SerialHandFlow.ControlHandShake = SERIAL_DTR_CONTROL; //deviceExtension->SerialHandFlow.FlowReplace = SERIAL_RTS_CONTROL; // initialize our circular read buffer deviceExtension->ReadCount = 0; deviceExtension->ReadBufferEnd = deviceExtension->QueueBuffer + (deviceExtension->QueueSize - 1); deviceExtension->ReadBuffer = deviceExtension->QueueBuffer; deviceExtension->ReadCharLast = deviceExtension->QueueBuffer; deviceExtension->ReadCharFirst = deviceExtension->QueueBuffer; deviceExtension->RxOverrun = FALSE; if (deviceExtension->KeepAliveTime == 0) deviceExtension->KeepAliveTime = 7200000; if (deviceExtension->KeepAliveInterval == 0) deviceExtension->KeepAliveInterval = 1000; // there is no data in our write queue deviceExtension->PendingWriteCount = 0; // DAG-TX-EMPTY //deviceExtension->PendingWriteCountTxEmpty = 0; //deviceExtension->WriteCompleteCount = 0; deviceExtension->WriteIrpStatus = CURRENT_IRP_STATUS_IDLE; status = CprUartReinitialize(&deviceExtension->Uart, deviceExtension); if (status != STATUS_SUCCESS) { if (deviceExtension->QueueBuffer) { ExFreePool(deviceExtension->QueueBuffer); deviceExtension->QueueBuffer = NULL; } // mark device as disabled deviceExtension->IsDeviceEnabled = FALSE; deviceExtension->IsDeviceOpening = FALSE; deviceExtension->IsDeviceNegotiating = FALSE; //#ifdef SCPR // if (deviceExtension->AES) // { // InterlockedDecrement(&g_Data.CurAesSessions); // } //#endif InterlockedDecrement(&deviceExtension->OpenHandleCount); CprReleaseRemoveLock(deviceExtension); CprDebugPrint1(deviceExtension, DBG_CREATECLOSE, DBG_WARN, __FUNCTION__"$$-- Uart Init Error %x", status); return status; } deviceExtension->BaudSent = FALSE; deviceExtension->StopSent = FALSE; deviceExtension->ParitySent = FALSE; deviceExtension->DataSizeSent = FALSE; deviceExtension->FlowSent = FALSE; // We set up the default xon/xoff limits. deviceExtension->SerialHandFlow.XoffLimit = deviceExtension->QueueSize >> 3; deviceExtension->SerialHandFlow.XonLimit = deviceExtension->QueueSize >> 1; deviceExtension->WmiCommData.XoffXmitThreshold = deviceExtension->SerialHandFlow.XoffLimit; deviceExtension->WmiCommData.XonXmitThreshold = deviceExtension->SerialHandFlow.XonLimit; // calculate .8 of our read queue deviceExtension->QueueSizePt8 = ((3*(deviceExtension->QueueSize >> 2))+ (deviceExtension->QueueSize >> 4)); // mark device as busy deviceExtension->WmiCommData.IsBusy = TRUE; // make sure that we are not trying to send xon/xoff characters deviceExtension->SendXonChar = FALSE; deviceExtension->SendXoffChar = FALSE; // reset escape character deviceExtension->EscapeChar = 0; // there is no characters in transmitter so it has to be idle deviceExtension->TxIdle = TRUE; deviceExtension->Closing = FALSE; deviceExtension->TxWriteInProgress = FALSE; deviceExtension->TxEmptyRequested = FALSE; // Initialize to no overflow //deviceExtension->TxOverflow = FALSE; // USE TO LOCK SerialLock BUT MANY FUNCTIONS IN CprUartConnect // NEED TO BE CALLED AT PASSIVE_LEVEL //CprAcquireSerialSpinLock(deviceExtension, &oldIrql); deviceExtension->socket = NULL; #ifdef BUFFER_STATE deviceExtension->BufferStatePending = FALSE; #endif deviceExtension->Rfc2217Enabled = FALSE; deviceExtension->Rfc2217OwnSignature = FALSE; deviceExtension->IACEscape = IACNormal; deviceExtension->ModemStateMask = ((unsigned char) 255); deviceExtension->LineStateMask = ((unsigned char) 0); deviceExtension->BreakSignaled = False; //deviceExtension->DtrConnection = True; // False; deviceExtension->InputFlow = True; deviceExtension->RemoteFlowOff = False; deviceExtension->LastFromNet = 0; deviceExtension->LastToNet = 0; KeInitializeEvent(&deviceExtension->Rfc2217SendEvent, NotificationEvent, FALSE); KeInitializeEvent(&deviceExtension->Rfc2217Event, NotificationEvent, FALSE); KeInitializeTimer(&deviceExtension->Rfc2217Timer); //deviceExtension->Rfc2217Timeout.QuadPart = deviceExtension->CnTmo * 500 * 10000; deviceExtension->Rfc2217Timeout.QuadPart = deviceExtension->CnTmo * 950 * 10000; deviceExtension->Rfc2217Timeout = RtlLargeIntegerNegate(deviceExtension->Rfc2217Timeout); KeInitializeDpc(&deviceExtension->Rfc2217TimeoutDpc, CprRfc2217Timeout, deviceExtension); KeInitializeTimer(&deviceExtension->FlushBuffersTimer); deviceExtension->FlushBuffersTimeout.QuadPart = 20000000; // Two Seconds deviceExtension->FlushBuffersTimeout = RtlLargeIntegerNegate(deviceExtension->FlushBuffersTimeout); KeInitializeDpc(&deviceExtension->FlushBuffersTimeoutDpc, CprFlushBuffersTimeout, deviceExtension); deviceExtension->TxEmptyVerifyPending = FALSE; KeInitializeDpc(&deviceExtension->TxEmptyDpc, CprTxEmptyCheck, deviceExtension); KeInitializeTimer(&deviceExtension->TxEmptyTimer); deviceExtension->TxEmptyInitTimeout.QuadPart = 100000; // 10 milliseconds deviceExtension->TxEmptyInitTimeout = RtlLargeIntegerNegate(deviceExtension->TxEmptyInitTimeout); deviceExtension->TxEmptyTimeout.QuadPart = 10000000; // 1000 milliseconds (1 second) deviceExtension->TxEmptyTimeout = RtlLargeIntegerNegate(deviceExtension->TxEmptyTimeout); InitBuffer(&deviceExtension->ToNetBuf); InitTelnetStateMachine(deviceExtension->TelnetState); // clear all statistics RtlZeroMemory(&deviceExtension->SerialStats, sizeof(SERIALPERF_STATS)); deviceExtension->IsDeviceOpening = TRUE; status = CprUartConnect(&deviceExtension->Uart, 0); if ((status != STATUS_SUCCESS) && (status != STATUS_IO_TIMEOUT) && (status != STATUS_CONNECTION_REFUSED)) { // First try the port used previously, the first // time ReconnectPort is zero and the system // will chose a port. If this fails use zero // //CprDebugPrint2(deviceExtension, DBG_CREATECLOSE, DBG_WARN, // "Could not connect using local port: %d because status was 0x%08X. Letting system choose the port.", // deviceExtension->ReconnectPort, status); int k; LARGE_INTEGER sleepTime; sleepTime.QuadPart = 5000000; // 500 msecs sleepTime = RtlLargeIntegerNegate(sleepTime); for (k = 0; k < 3; k++) { KeDelayExecutionThread(KernelMode, FALSE, &sleepTime); if (status == STATUS_ADDRESS_ALREADY_EXISTS) { // System tried to use a port that was already in use, try again. status = CprUartConnect(&deviceExtension->Uart, 0); if ((status == STATUS_SUCCESS) || (status == STATUS_IO_TIMEOUT)) break; } else { status = CprUartConnect(&deviceExtension->Uart, htons(deviceExtension->ReconnectPort)); if ((status == STATUS_SUCCESS) || (status == STATUS_IO_TIMEOUT)) break; } } } if (status != STATUS_SUCCESS) { if (deviceExtension->QueueBuffer) { ExFreePool(deviceExtension->QueueBuffer); deviceExtension->QueueBuffer = NULL; } // mark device as disabled deviceExtension->IsDeviceEnabled = FALSE; deviceExtension->IsDeviceOpening = FALSE; deviceExtension->IsDeviceNegotiating = FALSE; InterlockedDecrement(&deviceExtension->OpenHandleCount); //#ifdef SCPR // if (deviceExtension->AES) // { // InterlockedDecrement(&g_Data.CurAesSessions); // } //#endif } else if (deviceExtension->ListenMode != LISTEN_MODE_NONE) { // We are in Listen Mode do not enable device yet. status = STATUS_SUCCESS; ComStatusChange(deviceExtension, CPR_COM_STATUS_OPEN); } else { // enable event handling CprUartWriteIER(&deviceExtension->Uart, CPR_UART_IER_RDA | CPR_UART_IER_THR | CPR_UART_IER_RLS | CPR_UART_IER_MS); // mark device as enabled deviceExtension->IsDeviceEnabled = TRUE; deviceExtension->IsDeviceOpening = FALSE; status = STATUS_SUCCESS; #ifdef SCPR if (deviceExtension->AES) { CprSendInitVector(deviceExtension); } #endif // // If performing RFC 2217, Initialize session data // and perform negotiations here // if (deviceExtension->UseRFC2217) { // // Negotiations of options occur in the normal // send/receive functions after this routine returns. // // We need to send the desired com port settings // to the connect device server. // // Should I do this all here and block, or return // and do it in the background. If we are not // connected to an RFC2217 compliant device, we // need to abort the connection. We probably should // block and find out before we return. // CprAcquireSerialSpinLock(deviceExtension, &oldIrql); InitBuffer(&deviceExtension->ToNetBuf); CprReleaseSerialSpinLock(deviceExtension, oldIrql); status = CprRfc2217_Negotiate(deviceExtension); CprAcquireSerialSpinLock(deviceExtension, &oldIrql); if (status == STATUS_SUCCESS) { CprRfc2217_SendPortSettings(deviceExtension); } else { SOCKET socket = deviceExtension->socket; deviceExtension->socket = NULL; // The device server on the other end is not running // RFC2217. Refuse the connection; CprDebugPrint2(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__". Disconnecting from '%ws:%d'", deviceExtension->Services[deviceExtension->CurService].Address, deviceExtension->Services[deviceExtension->CurService].Port); if (socket) { CprReleaseSerialSpinLock(deviceExtension, oldIrql); CprTdiDisconnect(socket, FALSE, NULL, NULL); CprTdiDeleteSocket(socket); CprAcquireSerialSpinLock(deviceExtension, &oldIrql); NetworkStatusChange(deviceExtension, CPR_NETWORK_STATUS_DISCONNECTED); } if (deviceExtension->QueueBuffer) { ExFreePool(deviceExtension->QueueBuffer); deviceExtension->QueueBuffer = NULL; } //if (deviceExtension->BfWriteQueueBuffer) //{ // ExFreePool(deviceExtension->BfWriteQueueBuffer); // deviceExtension->BfWriteQueueBuffer = NULL; //} // mark device as disabled deviceExtension->IsDeviceEnabled = FALSE; deviceExtension->IsDeviceOpening = FALSE; //#ifdef SCPR // if (deviceExtension->AES) // { // InterlockedDecrement(&g_Data.CurAesSessions); // } //#endif if (deviceExtension->OpenHandleCount > 0) { InterlockedDecrement(&deviceExtension->OpenHandleCount); } } CprReleaseSerialSpinLock(deviceExtension, oldIrql); } if (deviceExtension->IsDeviceEnabled) { CprAcquireSerialSpinLock(deviceExtension, &oldIrql); // make sure that our virtual uart is in a known state CprUartWriteLCR(&deviceExtension->Uart, deviceExtension->LineControl); CprSerialSetupNewHandFlow(deviceExtension, &deviceExtension->SerialHandFlow); CprSerialHandleModemUpdate(deviceExtension, FALSE); CprReleaseSerialSpinLock(deviceExtension, oldIrql); // Set ComStatus for this port ComStatusChange(deviceExtension, CPR_COM_STATUS_OPEN); //deviceExtension->Connected = TRUE; //NetworkStatusChange(deviceExtension, CPR_NETWORK_STATUS_CONNECTED); // reset wait on mask irp support deviceExtension->IrpWaitMask = NULL; deviceExtension->WaitEvents = 0; deviceExtension->WaitMask = 0; #ifdef BUFFER_STATE deviceExtension->TxEmptyInitTimeout.QuadPart = 1000000; // 100 milliseconds deviceExtension->TxEmptyInitTimeout = RtlLargeIntegerNegate(deviceExtension->TxEmptyInitTimeout); deviceExtension->TxEmptyCurrentTimeout = deviceExtension->TxEmptyInitTimeout; deviceExtension->TxEmptyRef = CPR_TXEMPTY_DPC; KeSetTimer( &deviceExtension->TxEmptyTimer, deviceExtension->TxEmptyCurrentTimeout, &deviceExtension->TxEmptyDpc); #endif } } CprReleaseRemoveLock(deviceExtension); CprDebugPrint(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"--."); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprCloseDispatch // Dispatch routine for IRP_MJ_CLOSE requests. // // Arguments: // IN DeviceObject // pointer to the device object for our device // // IN Irp // the close IRP // // Return Value: // NT status code. // NTSTATUS CprCloseDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PCPR_DEVICE_EXTENSION deviceExtension = NULL; NTSTATUS status; KIRQL oldIrql; __try { deviceExtension = (PCPR_DEVICE_EXTENSION)DeviceObject->DeviceExtension; CprDebugPrint1(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"++. IRP %p", Irp); if (DeviceObject->DeviceType == FILE_DEVICE_CPR) { PBACKDOOR_DEVICE_EXTENSION ext = DeviceObject->DeviceExtension; Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0L; ext->opened = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); CprDebugPrint1(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"$$--. FILE_DEVICE_CPR. IRP %p", Irp); return STATUS_SUCCESS; } CprDebugPrint1(deviceExtension, DBG_CREATECLOSE, DBG_INFO, "Session %d", deviceExtension->sessionId); ComStatusChange(deviceExtension, CPR_COM_STATUS_CLOSING); if ((deviceExtension->OpenHandleCount == 1) && (deviceExtension->NoDiscon) && (deviceExtension->NetworkStatus == CPR_NETWORK_STATUS_CONNECTED)) { ComStatusChange(deviceExtension, CPR_COM_STATUS_CLOSED); CprDebugPrint(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"$$--. NoNetClose"); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest (Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } status = CprClosePort(deviceExtension); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); CprDebugPrint2(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"--. IRP %p, STATUS %x", Irp, status); } __except( EXCEPTION_EXECUTE_HANDLER ) { ComStatusChange(deviceExtension, CPR_COM_STATUS_ERROR); CprDebugPrint(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"--. Exception"); status = STATUS_INTERNAL_ERROR; } return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprClosePort // Routine for closing a port. // // Arguments: // IN deviceExtension // pointer to the device object for our device // // Return Value: // NT status code. // NTSTATUS CprClosePort( PCPR_DEVICE_EXTENSION deviceExtension ) { NTSTATUS status; KIRQL oldIrql; __try { CprDebugPrint(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"++."); CprAcquireSerialSpinLock(deviceExtension, &oldIrql); if (deviceExtension->OpenHandleCount == 0) { CprDebugPrint(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"$$--. Already Closed."); CprReleaseSerialSpinLock(deviceExtension, oldIrql); ComStatusChange(deviceExtension, CPR_COM_STATUS_CLOSED); //return STATUS_ALREADY_DISCONNECTED; return STATUS_SUCCESS; } // mark device as disabled deviceExtension->IsDeviceEnabled = FALSE; deviceExtension->Closing = TRUE; deviceExtension->WmiCommData.IsBusy = FALSE; // stop the hardware CprSerialTurnOffBreak(deviceExtension); CprSerialClrDTR(deviceExtension); CprSerialClrRTS(deviceExtension); deviceExtension->RxStopReason = 0; deviceExtension->TxStopReason = 0; deviceExtension->TxEmptyRef = CPR_TXEMPTY_CLEAR; deviceExtension->TxIdle = TRUE; deviceExtension->TxWriteInProgress = FALSE; // free read queue buffer deviceExtension->QueueSize = 0; if (deviceExtension->QueueBuffer != NULL) { ExFreePool(deviceExtension->QueueBuffer); deviceExtension->QueueBuffer = NULL; } //deviceExtension->BfWriteQueueSize = 0; //if (deviceExtension->BfWriteQueueBuffer != NULL) //{ // ExFreePool(deviceExtension->BfWriteQueueBuffer); // deviceExtension->BfWriteQueueBuffer = NULL; //} if (deviceExtension->UseRFC2217) { deviceExtension->Rfc2217Enabled = FALSE; deviceExtension->Rfc2217OwnSignature = FALSE; InitBuffer(&deviceExtension->ToNetBuf); } //CprReleaseSerialSpinLock(deviceExtension, oldIrql); if (deviceExtension->ReconnectRef & CPR_DEVEXT_RECONNECT) { if (KeCancelTimer(&deviceExtension->ReconnectTimer)) { // timer is canceled deviceExtension->ReconnectRef &= ~CPR_DEVEXT_RECONNECT; } } CprReleaseSerialSpinLock(deviceExtension, oldIrql); //DbgPrint("DAG: CprUarClose Called From CprClosePort\n"); status = CprUartClose(&deviceExtension->Uart); CprAcquireSerialSpinLock(deviceExtension, &oldIrql); deviceExtension->IrpWaitMask = NULL; deviceExtension->WaitEvents = 0; deviceExtension->WaitMask = 0; //#ifdef SCPR // if (deviceExtension->AES) // { // InterlockedDecrement(&g_Data.CurAesSessions); // } //#endif InterlockedDecrement(&deviceExtension->OpenHandleCount); // Clear the Terminal Services Session ID deviceExtension->sessionId = 0; //deviceExtension->Reconnecting = FALSE; CprReleaseSerialSpinLock(deviceExtension, oldIrql); CprLogEvent( CPR_EVENT_TYPE_CLOSE, CPR_EVENT_SUB_TYPE_NONE, deviceExtension, status, NULL); ComStatusChange(deviceExtension, CPR_COM_STATUS_CLOSED); CprDebugPrint2(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"--.STATUS %x OpenHandleCount %d", status, deviceExtension->OpenHandleCount); } __except( EXCEPTION_EXECUTE_HANDLER ) { ComStatusChange(deviceExtension, CPR_COM_STATUS_ERROR); CprDebugPrint(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"--. Exception"); status = STATUS_INTERNAL_ERROR; } return status; } // // Get the Terminal Services SessionID // ULONG GetSessionId() { SECURITY_SUBJECT_CONTEXT ctx; BOOLEAN captured = FALSE; BOOLEAN locked = FALSE; PACCESS_TOKEN token; ULONG sessionid; __try { SeCaptureSubjectContext(&ctx); captured = TRUE; SeLockSubjectContext(&ctx); locked = TRUE; token = SeQuerySubjectContextToken(&ctx); SeQueryInformationToken(token, TokenSessionId, (PVOID)&sessionid); } __finally { if (locked) SeUnlockSubjectContext(&ctx); if (captured) SeReleaseSubjectContext(&ctx); } return sessionid; } char *UnicodeToAscii(TCHAR *tc) { char *pAscii; int i; if (sizeof(TCHAR) == 2) { for (i = 0; (tc[i] != 0) && (i < sizeof(_ascii)-1); i++) { _ascii[i] = (char)((short)tc[i] & 0xFF); } _ascii[i] = '\0'; pAscii = _ascii; } return pAscii; } ULONG UnicodeToULong(TCHAR *tc) { ULONG ul = 0; int i, end; int pos = 3; ULONG num = 0; char tmp; int pow = 1; // Go to end of string for (end = 0; tc[end] != 0; end++) ; if (end > 0) { for (i = end-1; i >= 0; i--) { if ((char)tc[i] == '.') { ul |= num << (pos * 8); pos--; pow = 1; num = 0; } else { tmp = ((char)((short)tc[i] & 0xFF)) - 0x30; num += tmp * pow; pow *= 10; } } ul |= num << (pos * 8); } return ul; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprCleanupDispatch // Dispatch routine for IRP_MJ_CLEANUP requests. // // Arguments: // IN DeviceObject // pointer to the device object for our device // // IN Irp // the cleanup IRP // // Return Value: // NT status code. // NTSTATUS CprCleanupDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PCPR_DEVICE_EXTENSION deviceExtension = NULL; NTSTATUS status; PIO_STACK_LOCATION irpStack; __try { deviceExtension = (PCPR_DEVICE_EXTENSION)DeviceObject->DeviceExtension; CprDebugPrint1(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"++. IRP %p", Irp); if (DeviceObject->DeviceType == FILE_DEVICE_CPR) { //PBACKDOOR_DEVICE_EXTENSION ext = DeviceObject->DeviceExtension; Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0L; //ext->opened = 1; IoCompleteRequest(Irp, IO_NO_INCREMENT); CprDebugPrint1(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"$$-- FILE_DEVICE_CPR. IRP %p", Irp); return STATUS_SUCCESS; } ComStatusChange(deviceExtension, CPR_COM_STATUS_CLEANUP); if ((deviceExtension->OpenHandleCount == 1) && (deviceExtension->NoDiscon) && (deviceExtension->NetworkStatus == CPR_NETWORK_STATUS_CONNECTED)) { CprDebugPrint1(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"$$-- NoNetClose. IRP %p", Irp); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } // Cleanup irpStack = IoGetCurrentIrpStackLocation(Irp); status = CprCleanupPort(deviceExtension, irpStack->FileObject); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); CprDebugPrint2(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"--. IRP %p STATUS %x", Irp, status); } __except( EXCEPTION_EXECUTE_HANDLER ) { ComStatusChange(deviceExtension, CPR_COM_STATUS_ERROR); CprDebugPrint(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"--. Exception"); status = STATUS_INTERNAL_ERROR; } return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprCleanupPort // Routine for Cleanup, call before CprClosePort. // // Arguments: // IN deviceExtension // pointer to the device extension for our device // // IN FileObject // about to be closed file object // // Return Value: // NT status code. // NTSTATUS CprCleanupPort( PCPR_DEVICE_EXTENSION deviceExtension, IN PFILE_OBJECT FileObject ) { NTSTATUS status; PIO_STACK_LOCATION irpStack; __try { CprDebugPrint(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"++."); // cancel all outstanding irps CprFlushQueues(deviceExtension, FileObject); if (deviceExtension->TxEmptyRef == CPR_TXEMPTY_DPC) { if (KeCancelTimer(&deviceExtension->TxEmptyTimer)) { // timer is canceled deviceExtension->TxEmptyRef = CPR_TXEMPTY_CLEAR; } } status = STATUS_SUCCESS; CprDebugPrint1(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"--. Status %x", status); } __except( EXCEPTION_EXECUTE_HANDLER ) { ComStatusChange(deviceExtension, CPR_COM_STATUS_ERROR); CprDebugPrint(deviceExtension, DBG_CREATECLOSE, DBG_TRACE, __FUNCTION__"--. Exception"); status = STATUS_INTERNAL_ERROR; } return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUnload // Driver Unload routine. // // Arguments: // IN DriverObject // pointer to the driver object // // Return Value: // none // VOID CprUnload( IN PDRIVER_OBJECT DriverObject ) { __try { CprDebugPrint4(NULL, DBG_UNLOAD, DBG_TRACE, __FUNCTION__"++ DriverObject %p Version %s Compiled at %s on %s", DriverObject, CPR_DRVR_VERSION, __TIME__, __DATE__); CprTdiCleanup(); // The device object(s) should be NULL now // (since we unload, all the devices objects associated with this // driver must be deleted. ASSERT(DriverObject->DeviceObject == NULL); // We should not be unloaded until all the devices we control // have been removed from our queue. CprUnload_Wsk(); // release memory block allocated for registry path if (g_Data.RegistryPath.Buffer != NULL) { ExFreePool(g_Data.RegistryPath.Buffer); g_Data.RegistryPath.Buffer = NULL; } CprCloseDownEventLog(); CprDebugPrint(NULL, DBG_UNLOAD, DBG_TRACE, __FUNCTION__"--"); #ifdef CPR_WMI_TRACE WPP_CLEANUP(DriverObject); #endif } __except( EXCEPTION_EXECUTE_HANDLER ) { // STATUS_INTERNAL_ERROR; } return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprIsStoppable // This routine determines whether the device can be safely stopped. // In our particular case, we'll assume we can always stop the device. // A device might fail the request if it doesn't have a queue for the // requests that might come or if it was notified that it is in the // paging path. // // Arguments: // IN DeviceExtension // our device extension // // Return Value: // returns TRUE if the device is stoppable, FALSE otherwise // BOOLEAN CprIsStoppable( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { return TRUE; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprIsRemovable // This routine determines whether the device can be safely removed. // A device shouldn't be removed if, for example, it has open handles or // removing the device could result in losing data (plus the reasons // mentioned in the CprIsStoppable function comments). The PnP manager on // Windows 2000 fails on its own any attempt to remove, if there any // open handles to the device. However on Win9x, the driver must keep // count of open handles and fail QueryRemove if there are any open // handles. // // Arguments: // IN DeviceExtension // our device extension // // Return Value: // returns TRUE if the device is stoppable, FALSE otherwise // BOOLEAN CprIsRemovable( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { return !g_Data.updateDriver; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprSubmitIrpSyncComplete // Completion routine for sync IRP requests. // // Arguments: // IN DeviceObject // pointer to our device object // // IN Irp // pointer to the PnP IRP // // IN Context // our event used to signal IRP completion // // Return Value: // STATUS_MORE_PROCESSING_REQUIRED // NTSTATUS CprSubmitIrpSyncComplete( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { PKEVENT event = (PKEVENT)Context; // If the lower driver didn't return STATUS_PENDING, we don't need to // set the event because we won't be waiting on it. if (Irp->PendingReturned) { KeSetEvent(event, IO_NO_INCREMENT, FALSE); } return STATUS_MORE_PROCESSING_REQUIRED; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprSubmitIrpSync // Sends the given IRP down the stack to the next lower driver and // waits in a synchronous fashion for the IRP to complete // // Arguments: // IN DeviceObject // Pointer to device object for our device // // IN Irp // IRP to send down // // Return Value: // NT status code // NTSTATUS CprSubmitIrpSync( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { KEVENT event; NTSTATUS status; KeInitializeEvent(&event, NotificationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine( Irp, CprSubmitIrpSyncComplete, &event, TRUE, TRUE, TRUE ); status = IoCallDriver(DeviceObject, Irp); // Wait for lower drivers to be done with the Irp. // Important thing to note here is when you allocate // memory for an event in the stack you must do a // KernelMode wait instead of UserMode to prevent // the stack from getting paged out. if (status == STATUS_PENDING) { KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL ); status = Irp->IoStatus.Status; } return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprAcquireRemoveLock // Acquires remove lock. // // Arguments: // IN DeviceExtension // our device extension // // Return Value: // FALSE if remove device pending, TRUE otherwise. // BOOLEAN CprAcquireRemoveLock( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { LONG count; count = InterlockedIncrement(&DeviceExtension->RemoveCount); ASSERT(count > 0); if (DeviceExtension->PnpState == PnpStateRemoved) { CprReleaseRemoveLock(DeviceExtension); return FALSE; } return TRUE; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprReleaseRemoveLock // Releases remove lock. // // Arguments: // IN DeviceExtension // our device extension // // Return Value: // None. // VOID CprReleaseRemoveLock( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { LONG count; count = InterlockedDecrement(&DeviceExtension->RemoveCount); ASSERT(count >= 0); if (count == 0) { KeSetEvent(&DeviceExtension->RemoveEvent, IO_NO_INCREMENT, FALSE); } return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprWaitForSafeRemove // Waits for all remove locks to be released // // Arguments: // IN DeviceExtension // our device extension // // Return Value: // None. // // Comment: // This routine should be called with no remove locks held // by the calling thread // VOID CprWaitForSafeRemove( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { DeviceExtension->PnpState = PnpStateRemoved; CprReleaseRemoveLock(DeviceExtension); KeWaitForSingleObject( &DeviceExtension->RemoveEvent, Executive, KernelMode, FALSE, NULL ); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprStallQueues // Pauses all of the queues, and waits for them to get to paused state. // // Arguments: // IN DeviceExtension // our device extension // // Return Value: // none // VOID CprStallQueues( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { ULONG index; CprDebugPrint(DeviceExtension, DBG_IO, DBG_TRACE, __FUNCTION__"++"); // stall IRP processing CprLockIo(&DeviceExtension->IoLock); for(index = 0; index < NUMBER_OF_QUEUES; ++index) { CprPauseQueue(DeviceExtension->QueueArray[index]); } CprWaitForStopIo(&DeviceExtension->IoLock); CprDebugPrint(DeviceExtension, DBG_IO, DBG_TRACE, __FUNCTION__"--"); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprRestartQueues // Restarts all paused queues. // // Arguments: // IN DeviceExtension // our device extension // // Return Value: // none // VOID CprRestartQueues( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { ULONG index; CprDebugPrint(DeviceExtension, DBG_IO, DBG_TRACE, __FUNCTION__"++"); CprUnlockIo(&DeviceExtension->IoLock); for(index = 0; index < NUMBER_OF_QUEUES; ++index) { CprRestartQueue(DeviceExtension->QueueArray[index]); } CprDebugPrint(DeviceExtension, DBG_IO, DBG_TRACE, __FUNCTION__"--"); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprQueueCancelAll // cancel all oustanding IRPs in a queue including current irp. // // Arguments: // IN DeviceExtension // our device extension // // Return Value: // none // VOID CprQueueCancelAll( IN PCPR_QUEUE Queue ) { PCPR_DEVICE_EXTENSION deviceExtension; KIRQL oldIrql; PIRP irp; PDRIVER_CANCEL cancelRoutine = NULL; deviceExtension = (PCPR_DEVICE_EXTENSION)Queue->DeviceObject->DeviceExtension; CprDebugPrint(deviceExtension, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"++"); CprFlushQueue(Queue, NULL); KeAcquireSpinLock(&Queue->QueueLock, &oldIrql); if (Queue->CurrentIrp) { irp = Queue->CurrentIrp; Queue->CurrentIrp = NULL; cancelRoutine = IoSetCancelRoutine(irp, NULL); } else { irp = NULL; } KeReleaseSpinLock(&Queue->QueueLock, oldIrql); if (irp && cancelRoutine) { IoAcquireCancelSpinLock(&oldIrql); CprDebugPrint5(deviceExtension, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__". Calling CancelRoutine %p Queue %p IRP %p Status %X Cancel %X", cancelRoutine, Queue, irp, irp->IoStatus.Status, irp->Cancel); irp->Cancel = TRUE; irp->CancelIrql = oldIrql; ASSERT(Queue->DeviceObject != NULL); ASSERT(irp->IoStatus.Status != STATUS_CANCELLED); if ((Queue->DeviceObject != NULL) && (irp->IoStatus.Status != STATUS_CANCELLED)) { cancelRoutine(Queue->DeviceObject, irp); } else { IoReleaseCancelSpinLock(oldIrql); } } CprDebugPrint(deviceExtension, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"--"); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprFlushQueues // Flush oustanding IRPs for closed file object. // // Arguments: // IN DeviceExtension // our device extension // // IN FileObject // about to be closed file object // // Return Value: // none // VOID CprFlushQueues( IN PCPR_DEVICE_EXTENSION DeviceExtension, IN PFILE_OBJECT FileObject ) { ULONG index; KIRQL oldIrql; PIRP waitIrp; CprDebugPrint(DeviceExtension, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"++"); for(index = 0; index < NUMBER_OF_QUEUES; ++index) { CprFlushQueue(DeviceExtension->QueueArray[index], FileObject); } CprQueueCancelAll(&DeviceExtension->WriteQueue); CprQueueCancelAll(&DeviceExtension->ReadQueue); CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); // cancel wait on mask irp if (DeviceExtension->WaitIrp) { if (IoSetCancelRoutine(DeviceExtension->WaitIrp, NULL)) { waitIrp = DeviceExtension->WaitIrp; DeviceExtension->WaitIrp = NULL; DeviceExtension->IrpWaitMask = NULL; CprReleaseSerialSpinLock(DeviceExtension, oldIrql); CprDebugPrint(DeviceExtension, DBG_IO, DBG_INFO, "CprFlushQueues: Cancelling Wait App Irp 0x%08X", waitIrp); waitIrp->IoStatus.Status = STATUS_CANCELLED; IoCompleteRequest(waitIrp, IO_NO_INCREMENT); } else { waitIrp = DeviceExtension->WaitIrp; DeviceExtension->WaitIrp = NULL; DeviceExtension->IrpWaitMask = NULL; CprReleaseSerialSpinLock(DeviceExtension, oldIrql); CprDebugPrint(DeviceExtension, DBG_IO, DBG_INFO, "CprFlushQueues: Irp 0x%08X has already been cancelled", waitIrp); } } else { CprReleaseSerialSpinLock(DeviceExtension, oldIrql); } CprFlushPendingIo(&DeviceExtension->IoLock, FileObject); CprDebugPrint(DeviceExtension, DBG_CREATECLOSE | DBG_IO, DBG_TRACE, __FUNCTION__"--"); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprSerialReadSymName // reads symbolic link name for serial device // // Arguments: // IN DeviceExtension // our device extension // // IN Handle // handle to device (hardware) key // // OUT SymbolicLinkName // link name // // OUT RegName // port name from registry // // Return Value: // status // NTSTATUS CprSerialReadSymName( IN PCPR_DEVICE_EXTENSION DeviceExtension, IN HANDLE Handle, OUT PUNICODE_STRING SymbolicLinkName, OUT PWCHAR* RegName ) { UNICODE_STRING linkName; ULONG length; NTSTATUS status; *RegName = NULL; RtlZeroMemory(&linkName, sizeof(UNICODE_STRING)); // allocate memory for symbolic link linkName.MaximumLength = 256*sizeof(WCHAR); linkName.Buffer = (PWCHAR)ExAllocatePoolWithTag( PagedPool, linkName.MaximumLength + sizeof(UNICODE_NULL), CPR_POOL_TAG_SYMBOLIC_LINK); if (linkName.Buffer == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(linkName.Buffer, linkName.MaximumLength + sizeof(UNICODE_NULL)); // read port name out of registry status = CprRegQueryValueKey(Handle, NULL, _T("PortName"), RegName); if (!NT_SUCCESS(status)) { // try alternative location status = CprRegQueryValueKey(Handle, NULL, _T("Identifier"), RegName); } // something is not right here if (*RegName == NULL) { ExFreePool(linkName.Buffer); linkName.Buffer = NULL; return STATUS_INSUFFICIENT_RESOURCES; } // Create the "\\??\\" string RtlAppendUnicodeToString(&linkName, _T("\\??\\")); RtlAppendUnicodeToString(&linkName, *RegName); // allocate symbolic link SymbolicLinkName->MaximumLength = linkName.Length + sizeof(UNICODE_NULL); SymbolicLinkName->Buffer = (PWCHAR)ExAllocatePoolWithTag( PagedPool, SymbolicLinkName->MaximumLength, CPR_POOL_TAG_SYMBOLIC_LINK); if (SymbolicLinkName->Buffer == NULL) { ExFreePool(linkName.Buffer); linkName.Buffer = NULL; ExFreePool(*RegName); *RegName = NULL; return STATUS_INSUFFICIENT_RESOURCES; } // copy symbolic link RtlZeroMemory(SymbolicLinkName->Buffer, SymbolicLinkName->MaximumLength); RtlAppendUnicodeStringToString(SymbolicLinkName, &linkName); if (linkName.Buffer != NULL) { ExFreePool(linkName.Buffer); linkName.Buffer = NULL; } return STATUS_SUCCESS; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprCreateComName // creates win32 visible device name // // Arguments: // IN DeviceExtension // our device extension // // Return Value: // status // NTSTATUS CprCreateComName( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { NTSTATUS status; HANDLE keyHandle; UNICODE_STRING linkName; PWCHAR regName; ULONG length; BOOLEAN createdLink; BOOLEAN createdCommEntry; UNICODE_STRING dosName; // open device hardware key status = IoOpenDeviceRegistryKey(DeviceExtension->PhysicalDeviceObject, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_READ, &keyHandle); if (!NT_SUCCESS(status)) { return status; } RtlZeroMemory(&linkName, sizeof(UNICODE_STRING)); RtlZeroMemory(&dosName, sizeof(UNICODE_STRING)); // get our device object symbolic link name status = CprSerialReadSymName(DeviceExtension, keyHandle, &linkName, ®Name); ZwClose(keyHandle); if (!NT_SUCCESS(status)) { return status; } createdLink = FALSE; createdCommEntry = FALSE; do { // allocate memory for wmi name length = wcslen(regName)*sizeof(WCHAR) + sizeof(UNICODE_NULL); DeviceExtension->WmiIdentifier.Buffer = (PWCHAR)ExAllocatePoolWithTag( PagedPool, length, CPR_POOL_TAG_WMI_BUFFER); if (DeviceExtension->WmiIdentifier.Buffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlZeroMemory(DeviceExtension->WmiIdentifier.Buffer, length); // copy device object name to wmi name DeviceExtension->WmiIdentifier.Length = 0; DeviceExtension->WmiIdentifier.MaximumLength = (USHORT)length - sizeof(UNICODE_NULL); RtlAppendUnicodeToString(&DeviceExtension->WmiIdentifier, regName); // create a symbolic link status = IoCreateSymbolicLink(&linkName, &DeviceExtension->DeviceName); if (!NT_SUCCESS(status)) { break; } createdLink = TRUE; // init dos name string RtlInitUnicodeString(&dosName, regName); // save symbolic link mapping in registry status = RtlWriteRegistryValue( RTL_REGISTRY_DEVICEMAP, _T("SERIALCOMM"), DeviceExtension->DeviceName.Buffer, REG_SZ, dosName.Buffer, dosName.Length + sizeof(WCHAR) ); if (!NT_SUCCESS(status)) { break; } createdCommEntry = TRUE; // register device interface status = IoRegisterDeviceInterface( DeviceExtension->PhysicalDeviceObject, (LPGUID)&GUID_CLASS_COMPORT, NULL, &DeviceExtension->InterfaceName ); if (!NT_SUCCESS(status)) { DeviceExtension->InterfaceName.Buffer = NULL; break; } status = IoSetDeviceInterfaceState(&DeviceExtension->InterfaceName, TRUE); } while (FALSE); // in case of failure we need to unwind all the allocated resources if (!NT_SUCCESS(status)) { // free memory allocated for device interface name by // IoRegisterDeviceInterface call if (DeviceExtension->InterfaceName.Buffer) { IoSetDeviceInterfaceState(&DeviceExtension->InterfaceName, FALSE); ExFreePool(DeviceExtension->InterfaceName.Buffer); DeviceExtension->InterfaceName.Buffer = NULL; } // undo RtlWriteRegistryValue call if (createdCommEntry) { RtlDeleteRegistryValue(RTL_REGISTRY_DEVICEMAP, _T("SERIALCOMM"), DeviceExtension->DeviceName.Buffer); } // undo IoCreateSymbolicLink call if (createdLink == TRUE) { IoDeleteSymbolicLink(&linkName); } // free wmi id name buffer if (DeviceExtension->WmiIdentifier.Buffer != NULL) { ExFreePool(DeviceExtension->WmiIdentifier.Buffer); DeviceExtension->WmiIdentifier.Buffer = NULL; } } // free resources allocated by CprSerialReadSymName call if (regName != NULL) { ExFreePool(regName); } if (linkName.Buffer != NULL) { ExFreePool(linkName.Buffer); } return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprDeleteComName // deletes win32 visible device name // // Arguments: // IN DeviceExtension // our device extension // // Return Value: // status // NTSTATUS CprDeleteComName( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { NTSTATUS status; HANDLE keyHandle; UNICODE_STRING linkName; PWCHAR regName; // undo device interface registration if (DeviceExtension->InterfaceName.Buffer) { status = IoSetDeviceInterfaceState(&DeviceExtension->InterfaceName, FALSE); ExFreePool(DeviceExtension->InterfaceName.Buffer); DeviceExtension->InterfaceName.Buffer = NULL; } // delete symbolic link map status = RtlDeleteRegistryValue(RTL_REGISTRY_DEVICEMAP, _T("SERIALCOMM"), DeviceExtension->DeviceName.Buffer); // delete symbolic link itself status = IoOpenDeviceRegistryKey(DeviceExtension->PhysicalDeviceObject, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_READ, &keyHandle); if (NT_SUCCESS(status)) { RtlInitUnicodeString(&linkName, NULL); status = CprSerialReadSymName(DeviceExtension, keyHandle, &linkName, ®Name); if (NT_SUCCESS(status)) { IoDeleteSymbolicLink(&linkName); ExFreePool(linkName.Buffer); ExFreePool(regName); } ZwClose(keyHandle); } // free wmi id name buffer if (DeviceExtension->WmiIdentifier.Buffer) { ExFreePool(DeviceExtension->WmiIdentifier.Buffer); DeviceExtension->WmiIdentifier.MaximumLength = DeviceExtension->WmiIdentifier.Length = 0; DeviceExtension->WmiIdentifier.Buffer = NULL; } return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprStartDevice // Start device handler, sets up resources // // Arguments: // IN DeviceExtension // our device extension // // IN Irp // pointer to the Start IRP // // Return Value: // NT status code // NTSTATUS CprStartDevice( IN PCPR_DEVICE_EXTENSION DeviceExtension, IN PIRP Irp ) { NTSTATUS status = STATUS_SUCCESS; PCM_PARTIAL_RESOURCE_DESCRIPTOR resource; PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceTrans; PCM_PARTIAL_RESOURCE_LIST partialResourceList; PCM_PARTIAL_RESOURCE_LIST partialResourceListTranslated; PIO_STACK_LOCATION irpStack; POWER_STATE powerState; ULONG ii; CprDebugPrint1(DeviceExtension, DBG_PNP, DBG_TRACE, __FUNCTION__"++. IRP %p", Irp); // Get our current IRP stack location irpStack = IoGetCurrentIrpStackLocation(Irp); // Do whatever initialization needed when starting the device: // gather information about it, update the registry, etc. // At this point, the lower level drivers completed the IRP if ((irpStack->Parameters.StartDevice.AllocatedResources != NULL) && (irpStack->Parameters.StartDevice.AllocatedResourcesTranslated != NULL)) { // Parameters.StartDevice.AllocatedResources points to a // CM_RESOURCE_LIST describing the hardware resources that // the PnP Manager assigned to the device. This list contains // the resources in raw form. Use the raw resources to program // the device. partialResourceList = &irpStack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList; resource = &partialResourceList->PartialDescriptors[0]; // Parameters.StartDevice.AllocatedResourcesTranslated points // to a CM_RESOURCE_LIST describing the hardware resources that // the PnP Manager assigned to the device. This list contains // the resources in translated form. Use the translated resources // to connect the interrupt vector, map I/O space, and map memory. partialResourceListTranslated = &irpStack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList; resourceTrans = &partialResourceListTranslated->PartialDescriptors[0]; // search the resources for (ii = 0; ii < partialResourceList->Count; ++ii, ++resource, ++resourceTrans) { switch (resource->Type) { case CmResourceTypePort: CprDebugPrint(DeviceExtension, DBG_PNP, DBG_INFO, "Resource Type Port"); CprDebugPrint1(DeviceExtension, DBG_PNP, DBG_INFO, "Port.Start %I64x", resource->u.Port.Start.QuadPart); CprDebugPrint1(DeviceExtension, DBG_PNP, DBG_INFO, "Port.Length %x", resource->u.Port.Length); break; case CmResourceTypeMemory: CprDebugPrint(DeviceExtension, DBG_PNP, DBG_TRACE, "Resource Type Memory"); CprDebugPrint1(DeviceExtension, DBG_PNP, DBG_TRACE, "Memory.Start %I64x", resource->u.Memory.Start.QuadPart); CprDebugPrint1(DeviceExtension, DBG_PNP, DBG_TRACE, "Memory.Length %x", resource->u.Memory.Length); break; case CmResourceTypeInterrupt: CprDebugPrint(DeviceExtension, DBG_PNP, DBG_TRACE, "Resource Type Interrupt"); CprDebugPrint1(DeviceExtension, DBG_PNP, DBG_TRACE, "Interrupt.Level %x", resourceTrans->u.Interrupt.Level); CprDebugPrint1(DeviceExtension, DBG_PNP, DBG_TRACE, "Interrupt.Vector %x", resourceTrans->u.Interrupt.Vector); CprDebugPrint1(DeviceExtension, DBG_PNP, DBG_TRACE, "Interrupt.Affinity %x\n", resourceTrans->u.Interrupt.Affinity); break; default: CprDebugPrint1(DeviceExtension, DBG_PNP, DBG_TRACE, "Unknown Resource Type %x", resourceTrans->Type); break; } } } //***************************************************************** //***************************************************************** // TODO: check that all required resources have been allocated // DAG: No resources are allocated for CPR. //***************************************************************** //***************************************************************** //***************************************************************** //***************************************************************** // TODO: allocate and initialize dma and shared memory resources // DAG: No DMA or shared memory to allocate for CPR. //***************************************************************** //***************************************************************** //***************************************************************** //***************************************************************** // TODO: Reset and initialize your hardware // DAG: No Hardware to initialize for CPR. //***************************************************************** //***************************************************************** //***************************************************************** //***************************************************************** // TODO: enable interrupts // DAG: No interrupts to enable for CPR. //***************************************************************** //***************************************************************** CprDebugPrint2(DeviceExtension, DBG_PNP, DBG_TRACE, __FUNCTION__"--. IRP %p STATUS %x", Irp, status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprFreeResources // This routine returns all the resources acquired during // device startup. Here we disconnect from any interrupt, // unmap any I/O ports that are mapped in StartDevice, and // disable any device interfaces or symbolic links. // Before disconnecting an interrupt, be sure the device can // no longer generate interrupts. // // Arguments: // IN DeviceExtension // our device extension // // Return Value: // NT status code // NTSTATUS CprFreeResources( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { NTSTATUS status; CprDebugPrint(DeviceExtension, DBG_PNP, DBG_TRACE, __FUNCTION__"++"); CprDebugPrint(DeviceExtension, DBG_PNP, DBG_TRACE, __FUNCTION__"--"); return STATUS_SUCCESS; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprStartSerialDevice // Start device handler, sets up resources // // Arguments: // IN DeviceExtension // our device extension // // IN Irp // pointer to the Start IRP // // Return Value: // NT status code // NTSTATUS CprStartSerialDevice( IN PCPR_DEVICE_EXTENSION DeviceExtension, IN PIRP Irp ) { NTSTATUS status; CprDebugPrint1(DeviceExtension, DBG_PNP, DBG_TRACE, __FUNCTION__"++. IRP %p", Irp); status = CprStartDevice(DeviceExtension, Irp); if (!NT_SUCCESS(status)) { CprDebugPrint2(DeviceExtension, DBG_PNP, DBG_TRACE, __FUNCTION__"--. IRP %p STATUS %x", Irp, status); return status; } DeviceExtension->WmiHwData.IrqNumber = 0; DeviceExtension->WmiHwData.IrqLevel = 0; DeviceExtension->WmiHwData.IrqVector = 0; DeviceExtension->WmiHwData.IrqAffinityMask = 0; DeviceExtension->WmiHwData.InterruptType = SERIAL_WMI_INTTYPE_LEVEL; DeviceExtension->WmiHwData.BaseIOAddress = 0; DeviceExtension->WmiCommData.BaudRate = DeviceExtension->BaudRate; DeviceExtension->WmiCommData.BitsPerByte = (DeviceExtension->LineControl & 0x03) + 5; DeviceExtension->WmiCommData.ParityCheckEnable = (DeviceExtension->LineControl & 0x08) ? TRUE : FALSE; switch (DeviceExtension->LineControl & CPR_UART_LCR_PARITY_MASK) { case CPR_UART_LCR_NONE_PARITY: DeviceExtension->WmiCommData.Parity = SERIAL_WMI_PARITY_NONE; break; case CPR_UART_LCR_ODD_PARITY: DeviceExtension->WmiCommData.Parity = SERIAL_WMI_PARITY_ODD; break; case CPR_UART_LCR_EVEN_PARITY: DeviceExtension->WmiCommData.Parity = SERIAL_WMI_PARITY_EVEN; break; case CPR_UART_LCR_MARK_PARITY: DeviceExtension->WmiCommData.Parity = SERIAL_WMI_PARITY_MARK; break; case CPR_UART_LCR_SPACE_PARITY: DeviceExtension->WmiCommData.Parity = SERIAL_WMI_PARITY_SPACE; break; default: DeviceExtension->WmiCommData.Parity = SERIAL_WMI_PARITY_NONE; break; } DeviceExtension->WmiCommData.StopBits = DeviceExtension->LineControl & CPR_UART_LCR_STOP_MASK ? (DeviceExtension->WmiCommData.BitsPerByte == 5 ? SERIAL_WMI_STOP_1_5 : SERIAL_WMI_STOP_2) : SERIAL_WMI_STOP_1; DeviceExtension->WmiCommData.XoffCharacter = DeviceExtension->SerialChars.XoffChar; DeviceExtension->WmiCommData.XoffXmitThreshold = DeviceExtension->SerialHandFlow.XoffLimit; DeviceExtension->WmiCommData.XonCharacter = DeviceExtension->SerialChars.XonChar; DeviceExtension->WmiCommData.XonXmitThreshold = DeviceExtension->SerialHandFlow.XonLimit; DeviceExtension->WmiCommData.MaximumBaudRate = 0; DeviceExtension->WmiCommData.MaximumOutputBufferSize = (UINT32)((ULONG)-1); DeviceExtension->WmiCommData.MaximumInputBufferSize = (UINT32)((ULONG)-1); DeviceExtension->WmiCommData.Support16BitMode = FALSE; DeviceExtension->WmiCommData.SupportDTRDSR = TRUE; DeviceExtension->WmiCommData.SupportIntervalTimeouts = TRUE; DeviceExtension->WmiCommData.SupportParityCheck = TRUE; DeviceExtension->WmiCommData.SupportRTSCTS = TRUE; DeviceExtension->WmiCommData.SupportXonXoff = TRUE; DeviceExtension->WmiCommData.SettableBaudRate = TRUE; DeviceExtension->WmiCommData.SettableDataBits = TRUE; DeviceExtension->WmiCommData.SettableFlowControl = TRUE; DeviceExtension->WmiCommData.SettableParity = TRUE; DeviceExtension->WmiCommData.SettableParityCheck = TRUE; DeviceExtension->WmiCommData.SettableStopBits = TRUE; DeviceExtension->WmiCommData.IsBusy = FALSE; RtlZeroMemory(&DeviceExtension->WmiPerfData, sizeof(DeviceExtension->WmiPerfData)); // initialize virtual uart status = CprUartInitialize(&DeviceExtension->Uart, DeviceExtension); if (!NT_SUCCESS(status)) { CprDebugPrint2(DeviceExtension, DBG_PNP, DBG_WARN, __FUNCTION__"--. IRP %p STATUS %x", Irp, status); return status; } status = CprCreateComName(DeviceExtension); if (!NT_SUCCESS(status)) { CprDebugPrint2(DeviceExtension, DBG_PNP, DBG_WARN, __FUNCTION__"--. IRP %p STATUS %x", Irp, status); return status; } CprDebugPrint2(DeviceExtension, DBG_PNP, DBG_TRACE, __FUNCTION__"--. IRP %p STATUS %x", Irp, status); return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprFreeSerialResources // This routine returns all the resources acquired during // device startup. Here we disconnect from any interrupt, // unmap any I/O ports that are mapped in StartDevice, and // disable any device interfaces or symbolic links here. // Before disconnecting an interrupt, be sure the device can // no longer generate interrupts. // // Arguments: // IN DeviceExtension // our device extension // // Return Value: // NT status code // NTSTATUS CprFreeSerialResources( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { NTSTATUS status; CprDebugPrint(DeviceExtension, DBG_PNP, DBG_TRACE, __FUNCTION__"++"); CprDeleteComName(DeviceExtension); CprFreeResources(DeviceExtension); CprUartFree(&DeviceExtension->Uart); CprDebugPrint(DeviceExtension, DBG_PNP, DBG_TRACE, __FUNCTION__"--"); return STATUS_SUCCESS; } int wideCharToInt(PWCHAR wChar) { int retval; WCHAR cSave; for (retval = 0; *wChar; ++wChar) { if ((cSave = (WCHAR) (*wChar - 0x30)) > (WCHAR) 9) break; retval = (int) (retval * 10 + (int) cSave); } return (retval); }