⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vcom_device.c

📁 一个虚拟串口的驱动程序源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
//============================================================================
//
//  N8VB_vcom - Virtual COM Port
//  Copyright (c) 2005 Philip A Covington, N8VB
//
//	Email: p.covington@gmail.com
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//============================================================================

#include "vCOM.h"

const SERIAL_COMMPROP   vCOMProperties = {sizeof(SERIAL_COMMPROP),      // PacketLength
                                          2,                            				// PacketVersion
                                          SERIAL_SP_SERIALCOMM,         		// ServiceMask
                                          0,                            				// Reserved1
                                          BUFFERLENGTH,                            	// MaxTxQueue
                                          BUFFERLENGTH,                			// MaxRxQueue
                                          SERIAL_BAUD_USER,             		// MaxBaud
                                          SERIAL_SP_RS232,              		// ProvSubType
                                          SERIAL_PCF_DTRDSR |
                                          SERIAL_PCF_RTSCTS |
                                          SERIAL_PCF_CD |
                                          SERIAL_PCF_PARITY_CHECK |
                                          SERIAL_PCF_TOTALTIMEOUTS |
                                          SERIAL_PCF_INTTIMEOUTS,       		// ProvCapabilities
                                          SERIAL_SP_PARITY |
                                          SERIAL_SP_BAUD |
                                          SERIAL_SP_DATABITS |
                                          SERIAL_SP_STOPBITS |
                                          SERIAL_SP_HANDSHAKING |
                                          SERIAL_SP_PARITY_CHECK |
                                          SERIAL_SP_CARRIER_DETECT,    	// SettableParams
                                          SERIAL_BAUD_075 |
                                          SERIAL_BAUD_110 |
                                          SERIAL_BAUD_150 |
                                          SERIAL_BAUD_300 |
                                          SERIAL_BAUD_600 |
                                          SERIAL_BAUD_1200 |
                                          SERIAL_BAUD_1800 |
                                          SERIAL_BAUD_2400 |
                                          SERIAL_BAUD_4800 |
                                          SERIAL_BAUD_7200 |
                                          SERIAL_BAUD_9600 |
                                          SERIAL_BAUD_14400 |
                                          SERIAL_BAUD_19200 |
                                          SERIAL_BAUD_38400 |
                                          SERIAL_BAUD_56K |
                                          SERIAL_BAUD_128K |
                                          SERIAL_BAUD_115200 |
                                          SERIAL_BAUD_57600 |
                                          SERIAL_BAUD_USER,             		// SettableBaud
                                          SERIAL_DATABITS_5 |
                                          SERIAL_DATABITS_6 |
                                          SERIAL_DATABITS_7 |
                                          SERIAL_DATABITS_8,            		// SettableData
                                          SERIAL_STOPBITS_10 |
                                          SERIAL_STOPBITS_15 |
                                          SERIAL_STOPBITS_20 |
                                          SERIAL_PARITY_NONE |
                                          SERIAL_PARITY_ODD |
                                          SERIAL_PARITY_EVEN |
                                          SERIAL_PARITY_MARK |
                                          SERIAL_PARITY_SPACE,          		// SettableStopParity
                                          BUFFERLENGTH,                            	// CurrentTxQueue
                                          BUFFERLENGTH,                			// CurrentRxQueue
                                          0,                            				// ProvSpec1
                                          0,                            				// ProvSpec2
                                          0,                            				// ProvChar
                                         };
                                       
NTSTATUS vCOMAddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pPDO)
{
	NTSTATUS                    		status;
	PDEVICE_OBJECT              		pFDO;
	PDEVICE_OBJECT									pTwinFDO;
	PvCOM_DEVICE_EXTENSION      		pDeviceExtension;
	PvCOM_DEVICE_EXTENSION    			pTwinDeviceExtension;
	HANDLE                  				hRegistry;
	ULONG                  					pCount = 0;
	ULONG														i;

	status = IoOpenDeviceRegistryKey(pPDO, PLUGPLAY_REGKEY_DEVICE,	STANDARD_RIGHTS_READ, &hRegistry);

	if (!NT_SUCCESS(status))
	{
		KdPrint(("error in AddDevice IoOpenDeviceRegistryKey...\n"));
		return status;
	}
		
	status = vCOMGetRegistryKeyValue(hRegistry, L"NumberOfPairs", &pCount, sizeof(ULONG));
		
	if (!NT_SUCCESS(status))
	{		
		ZwClose(hRegistry);
		KdPrint(("AddDevice vCOMGetRegistryKeyValue failed...\n"));
		return status;
	}

	devpaircount = (ULONG)pCount;
		
	ZwClose(hRegistry);	

	if (devpaircount > MAX_PAIR_COUNT)
		devpaircount = MAX_PAIR_COUNT;

	KdPrint(("AddDevice will create %d pairs or %d devices...\n", devpaircount, devpaircount*2));
		
	for (i=0; i < devpaircount*2; i+=2)
	{
		status = vCOMCreateFDO(DriverObject, pPDO, &pFDO, i);

		if (!NT_SUCCESS(status))
		{
			return status;
		}

		KdPrint(("Device %d created...\n", i));
		
		pFDO->Flags &= ~DO_DEVICE_INITIALIZING;

		status = vCOMCreateFDO(DriverObject, pPDO, &pTwinFDO, i+1);

		if (!NT_SUCCESS(status))
		{
			return status;
		}

		KdPrint(("Device %d created...\n", i+1));

		pTwinFDO->Flags &= ~DO_DEVICE_INITIALIZING;

		pDeviceExtension = (PvCOM_DEVICE_EXTENSION)pFDO->DeviceExtension;
		pTwinDeviceExtension = (PvCOM_DEVICE_EXTENSION)pTwinFDO->DeviceExtension;

		pDeviceExtension->pMe = pFDO;
		pDeviceExtension->pTwin = pTwinFDO;
		pTwinDeviceExtension->pMe = pTwinFDO;
		pTwinDeviceExtension->pTwin = pFDO;

		pTwinDeviceExtension->pNextDriver = pDeviceExtension->pNextDriver;

		pDeviceExtension->inBuffer = (PUCHAR) ExAllocatePool(NonPagedPool, BUFFERLENGTH);

		if (pDeviceExtension->inBuffer == NULL)
			return STATUS_INSUFFICIENT_RESOURCES;
			
		pDeviceExtension->outBuffer = (PUCHAR) ExAllocatePool(NonPagedPool, BUFFERLENGTH);

		if (pDeviceExtension->outBuffer == NULL)
			return STATUS_INSUFFICIENT_RESOURCES;
		
		pDeviceExtension->inBufferSize = BUFFERLENGTH;
		pDeviceExtension->outBufferSize = BUFFERLENGTH;
			
		pDeviceExtension->inBufferReadPosition = 0;
		pDeviceExtension->inBufferWritePosition = 0;
		pDeviceExtension->outBufferReadPosition = 0;
		pDeviceExtension->outBufferWritePosition = 0;
		pDeviceExtension->inBufferCount = 0;
		pDeviceExtension->outBufferCount = 0;
		pDeviceExtension->pReadIrpCurrent = NULL;
		pDeviceExtension->pWriteIrpCurrent = NULL;
		pDeviceExtension->fastRead = FALSE;

		//default delay loop timeout is 20 mS
		pDeviceExtension->writeDelayLoopTimerValue.QuadPart = (LONGLONG)(-10000 * 20);
		// 60 secs
		pDeviceExtension->readWaitTimeoutValue.QuadPart = (LONGLONG)(-10000 * 60000);
		// 5 secs
		pDeviceExtension->transferWaitTimeoutValue.QuadPart = (LONGLONG)(-10000 * 5000);
	
		pTwinDeviceExtension->inBuffer = (PUCHAR) ExAllocatePool(NonPagedPool, BUFFERLENGTH);

		if (pTwinDeviceExtension->inBuffer == NULL)
			return STATUS_INSUFFICIENT_RESOURCES;
			
		pTwinDeviceExtension->outBuffer = (PUCHAR) ExAllocatePool(NonPagedPool, BUFFERLENGTH);

		if (pTwinDeviceExtension->outBuffer == NULL)
			return STATUS_INSUFFICIENT_RESOURCES;
		
		pTwinDeviceExtension->inBufferSize = BUFFERLENGTH;
		pTwinDeviceExtension->outBufferSize = BUFFERLENGTH;
		
		pTwinDeviceExtension->inBufferReadPosition = 0;
		pTwinDeviceExtension->inBufferWritePosition = 0;
		pTwinDeviceExtension->outBufferReadPosition = 0;
		pTwinDeviceExtension->outBufferWritePosition = 0;
		pTwinDeviceExtension->inBufferCount = 0;
		pTwinDeviceExtension->outBufferCount = 0;	
		pTwinDeviceExtension->pReadIrpCurrent = NULL;
		pTwinDeviceExtension->pWriteIrpCurrent = NULL;
		pTwinDeviceExtension->fastRead = FALSE;	

		//default delay loop timeout is 20 mS
		pTwinDeviceExtension->writeDelayLoopTimerValue.QuadPart = (LONGLONG)(-10000 * 20);
		// 60 secs
		pTwinDeviceExtension->readWaitTimeoutValue.QuadPart = (LONGLONG)(-10000 * 60000);
		// 5 secs
		pTwinDeviceExtension->transferWaitTimeoutValue.QuadPart = (LONGLONG)(-10000 * 5000);

		pDevices[i] = pFDO;
		pDevices[i+1] = pTwinFDO;

		if (pDeviceExtension->deviceNumber == 0) //only register once
		{
			status = IoRegisterDeviceInterface(pPDO, &vCOMGUID,  NULL, &pDeviceExtension->interfaceName);

			if (!NT_SUCCESS(status))
			{
				pDeviceExtension->interfaceName.Buffer = NULL;
				KdPrint(("IoRegisterDeviceInterface failed...\n"));
				goto StartThreads;
			}	
			
			status = IoSetDeviceInterfaceState(&pDeviceExtension->interfaceName, TRUE);

			if (!NT_SUCCESS(status))
			{
				pDeviceExtension->isSet = FALSE;
				KdPrint(("IoSetDeviceInterfaceState failed...\n"));
				goto StartThreads;
			}

			pDeviceExtension->isSet = TRUE;
		}

StartThreads:
	
		vCOMTransferThreadStart(pFDO);
		vCOMTransferThreadStart(pTwinFDO);
		vCOMReadThreadStart(pFDO);			 
		vCOMReadThreadStart(pTwinFDO); 
		vCOMWriteThreadStart(pFDO);		
		vCOMWriteThreadStart(pTwinFDO); 
	
	}
				
	return STATUS_SUCCESS;
	
}

NTSTATUS vCOMCreateFDO(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pPDO, PDEVICE_OBJECT* pvCOMFDO, ULONG devNumber)
{
	NTSTATUS                			status;
	PvCOM_DEVICE_EXTENSION  	pDeviceExtension;
	UNICODE_STRING          		ntDeviceName;
	PUNICODE_STRING         		pSymbolicName;
	HANDLE                  			hRegistry;
	WCHAR*                  			pRegistryName;

	RtlInitUnicodeString(&ntDeviceName, vCOMDevNames[devNumber]);

	status = IoCreateDevice(DriverObject, sizeof(vCOM_DEVICE_EXTENSION), &ntDeviceName,
			FILE_DEVICE_SERIAL_PORT, 0, TRUE, pvCOMFDO);

	if (!NT_SUCCESS(status))
	{
		KdPrint(("error creating device...\n"));
		return status;
	}

	KdPrint(("IOCreateDevice succeeded...\n"));

	pDeviceExtension = (PvCOM_DEVICE_EXTENSION)(*pvCOMFDO)->DeviceExtension;

	status = IoOpenDeviceRegistryKey(pPDO, PLUGPLAY_REGKEY_DEVICE,	STANDARD_RIGHTS_READ, &hRegistry);

	if (!NT_SUCCESS(status))
	{
		vCOMDeleteFailedDevice(*pvCOMFDO, devNumber);
		KdPrint(("error in IoOpenDeviceRegistryKey...\n"));
		return status;
	}

	KdPrint(("IoOpenDeviceRegistryKey succeeded...\n"));

	pRegistryName = ExAllocatePool(PagedPool, 129 * sizeof(WCHAR));

	if (pRegistryName == NULL)
	{
		ZwClose(hRegistry);
		vCOMDeleteFailedDevice(*pvCOMFDO, devNumber);
		KdPrint(("error in ExAllocatePool for registry name...\n"));
		return STATUS_INSUFFICIENT_RESOURCES;
	}

	pSymbolicName = &pDeviceExtension->symbolicLinkName;

	pSymbolicName->MaximumLength = 128 * sizeof(WCHAR);
	pSymbolicName->Buffer = ExAllocatePool(PagedPool, 129 * sizeof(WCHAR));

	if (pSymbolicName->Buffer == NULL)
	{
		ZwClose(hRegistry);
		vCOMDeleteFailedDevice(*pvCOMFDO, devNumber);
		KdPrint(("error in ExAllocatePool for symbolic name...\n"));
		return STATUS_INSUFFICIENT_RESOURCES;
	}

	KdPrint(("calling vCOMGetRegistryKeyValue...\n"));

	status = vCOMGetRegistryKeyValue(hRegistry, vCOMPortNumbers[devNumber], pRegistryName, 128 * sizeof(WCHAR));
		
	KdPrint(("Device %d will be created with name: %ws -- %ws\n", devNumber, pRegistryName, vCOMPortNumbers[devNumber]));
	
	if (!NT_SUCCESS(status))
	{		
		ZwClose(hRegistry);
		vCOMDeleteFailedDevice(*pvCOMFDO, devNumber);
		KdPrint(("vCOMGetRegistryKeyValue failed...\n"));
		return status;
	}

	KdPrint(("vCOMGetRegistryKeyValue succeeded...\n"));

	RtlZeroMemory(pSymbolicName->Buffer, 129 * sizeof(WCHAR));
	RtlAppendUnicodeToString(pSymbolicName, L"\\DosDevices\\");
	RtlAppendUnicodeToString(pSymbolicName, pRegistryName);

	status = IoCreateSymbolicLink(pSymbolicName, &ntDeviceName);

	if (!NT_SUCCESS(status))  //try to delete the symbolic link first
	{
		IoDeleteSymbolicLink(pSymbolicName);
		status = IoCreateSymbolicLink(pSymbolicName, &ntDeviceName);
	}
	
	if (!NT_SUCCESS(status)) //deleting failed
	{
		pDeviceExtension->symbolicLinkIsDone = FALSE;
		ZwClose(hRegistry);		
		vCOMDeleteFailedDevice(*pvCOMFDO, devNumber);
		KdPrint(("IoCreateSymbolicLink failed...\n"));
		return status;
	}

	KdPrint(("IoCreateSymbolicLink succeeded: %ws\n", pSymbolicName));
	
	pDeviceExtension->symbolicLinkIsDone = TRUE;
		
	status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP, ntDeviceName.Buffer, REG_SZ,
			pRegistryName, (wcslen(pRegistryName) + 1) * sizeof(WCHAR));

	if (!NT_SUCCESS(status))
	{
		pDeviceExtension->deviceMapEntryIsCreated = FALSE;
		ZwClose(hRegistry);
		vCOMDeleteFailedDevice(*pvCOMFDO, devNumber);
		KdPrint(("RtlWriteRegistryValue failed...\n"));
		return status;
	}

	pDeviceExtension->deviceMapEntryIsCreated = TRUE;
		
	ZwClose(hRegistry);

	(*pvCOMFDO)->Flags |= DO_POWER_PAGABLE + DO_BUFFERED_IO;
	
	pDeviceExtension->pMe = pPDO;

	if (devNumber == 0) //don't attach device n+1 or it will be above device 1!!!
	{
		pDeviceExtension->pNextDriver = IoAttachDeviceToDeviceStack(*pvCOMFDO, pPDO);

		if (pDeviceExtension->pNextDriver == NULL)
		{
			vCOMDeleteFailedDevice(*pvCOMFDO, devNumber);
			return STATUS_NO_SUCH_DEVICE;
		}  

		pDeviceExtension->isAttached = TRUE;		
	}
	else
	{
		pDeviceExtension->isAttached = FALSE;
	}

	pDeviceExtension->deviceNumber = devNumber;
	
	// initialize objects
	ExInitializeFastMutex(&pDeviceExtension->openMutex);
	
	KeInitializeSpinLock(&pDeviceExtension->readSpinLock);    
	KeInitializeSpinLock(&pDeviceExtension->writeSpinLock);
	KeInitializeSpinLock(&pDeviceExtension->controlSpinLock);
	KeInitializeSpinLock(&pDeviceExtension->readQueueSpinLock);
	KeInitializeSpinLock(&pDeviceExtension->writeQueueSpinLock);

	KeInitializeSemaphore(&pDeviceExtension->readIRPQueueSemaphore, 0, MAXLONG);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -