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

📄 vcom_device.c

📁 一个虚拟串口的驱动程序源代码
💻 C
📖 第 1 页 / 共 5 页
字号:

			pIrp->IoStatus.Information = sizeof(ULONG );

			KeAcquireSpinLock(&pDeviceExtension->controlSpinLock, &oldIrql);
			
			*(PULONG)pIrp->AssociatedIrp.SystemBuffer = pDeviceExtension->serModemControlRegister;

			KeReleaseSpinLock(&pDeviceExtension->controlSpinLock, oldIrql);	        	     

			break;
		}

		case IOCTL_SERIAL_SET_MODEM_CONTROL:
		{
			ULONG	mcr;
			
			KdPrint(("vCOMDeviceControl: IOCTL_SERIAL_SET_MODEM_CONTROL\n"));

			if (pIrpStackLocation->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
			{
				status = STATUS_BUFFER_TOO_SMALL;
				break;
			}

			mcr = *(PULONG)pIrp->AssociatedIrp.SystemBuffer;

			KeAcquireSpinLock(&pDeviceExtension->controlSpinLock, &oldIrql);

			pDeviceExtension->serModemControlRegister = mcr;

			KeReleaseSpinLock(&pDeviceExtension->controlSpinLock, oldIrql);
			
			if ((mcr & SERIAL_MCR_DTR) == SERIAL_MCR_DTR)
				{
					pDeviceExtension->serDTR = TRUE;
					if (!pTwinDeviceExtension->serDSR)
					{
						pTwinDeviceExtension->serDSR = TRUE;
						vCOMCheckComEvents(pTwinDeviceExtension, SERIAL_EV_DSR);
					}					
				}
			else
				{
					pDeviceExtension->serDTR = FALSE;
					if (pTwinDeviceExtension->serDSR)
					{
						pTwinDeviceExtension->serDSR = FALSE;
						vCOMCheckComEvents(pTwinDeviceExtension, SERIAL_EV_DSR);
					}		
				}
			
			if ((mcr & SERIAL_MCR_RTS) == SERIAL_MCR_RTS)
				{
					pDeviceExtension->serRTS = TRUE;
					if (!pTwinDeviceExtension->serCTS)
					{
						pTwinDeviceExtension->serCTS= TRUE;
						vCOMCheckComEvents(pTwinDeviceExtension, SERIAL_EV_CTS);
					}		
				}
			else
				{
					pDeviceExtension->serRTS = FALSE;
					if (pTwinDeviceExtension->serCTS)
					{
						pTwinDeviceExtension->serCTS= FALSE;
						vCOMCheckComEvents(pTwinDeviceExtension, SERIAL_EV_CTS);
					}	
				}

			break;
		}

		case IOCTL_SERIAL_XOFF_COUNTER:
		case IOCTL_SERIAL_SET_XON:
		case IOCTL_SERIAL_SET_XOFF:
		case IOCTL_SERIAL_SET_FIFO_CONTROL:
		case IOCTL_SERIAL_SET_BREAK_ON:
		case IOCTL_SERIAL_SET_BREAK_OFF:		
		case IOCTL_SERIAL_RESET_DEVICE:              
			KdPrint(("vCOMDeviceControl: Other IOControl\n"));
			break;

		default:        
			status = STATUS_INVALID_PARAMETER;
			break;  
			
	}

	if (status != STATUS_PENDING)
	{		
		vCOMCompleteRequest(pIrp, status, pIrp->IoStatus.Information);
	}
    	
	return status;
}

NTSTATUS vCOMCleanupDevice(PDEVICE_OBJECT DeviceObject, PIRP pIrp)
{
	PvCOM_DEVICE_EXTENSION  	pDeviceExtension;
	LIST_ENTRY             			tempQueue;   
	PLIST_ENTRY            			thisEntry;
	KIRQL						OldIrql;
	PIRP                   				pendingIrp;
	PIO_STACK_LOCATION    		pendingIrpStack;
	PIO_STACK_LOCATION			irpStack;

	pDeviceExtension = DeviceObject->DeviceExtension;

	irpStack = IoGetCurrentIrpStackLocation(pIrp);

	while (pendingIrp = IoCsqRemoveNextIrp (&pDeviceExtension->cancelSafeReadQueue, irpStack->FileObject))
	{
		// Cancel the IRP	
		vCOMCompleteRequest(pendingIrp, STATUS_CANCELLED, 0);
	}

	while (pendingIrp = IoCsqRemoveNextIrp (&pDeviceExtension->cancelSafeWriteQueue, irpStack->FileObject))
	{
		// Cancel the IRP	
		vCOMCompleteRequest(pendingIrp, STATUS_CANCELLED, 0);
	}
	
	// Finally complete the cleanup IRP	
	
	vCOMCompleteRequest(pIrp, STATUS_SUCCESS, 0);
	
	return STATUS_SUCCESS;
	
}

NTSTATUS vCOMGetRegistryKeyValue(HANDLE hRegistry, PCWSTR keyName, PVOID data, ULONG dataLength)
{
	NTSTATUS                        			status;
	UNICODE_STRING                  		keyNameString;
	ULONG                           			length;
	PKEY_VALUE_PARTIAL_INFORMATION 	pInfo;

	status = STATUS_INSUFFICIENT_RESOURCES;

	RtlInitUnicodeString(&keyNameString, keyName);

	length = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + dataLength;
	pInfo  = ExAllocatePool(PagedPool, length); 

	if (pInfo != NULL)
	{
		status = ZwQueryValueKey(hRegistry, &keyNameString, KeyValuePartialInformation,
		pInfo, length, &length);

		if (NT_SUCCESS(status))
		{
			if (dataLength >= pInfo->DataLength)
				RtlCopyMemory(data, &pInfo->Data, pInfo->DataLength);
			else
				status = STATUS_BUFFER_TOO_SMALL;
		}

		ExFreePool(pInfo);
	}

	return status;
	
}

VOID vCOMCancelWaitIrp(PDEVICE_OBJECT DeviceObject, PIRP pIrp)
{
	PvCOM_DEVICE_EXTENSION  	pDeviceExtension;
	KIRQL                   			oldIrql;

	pDeviceExtension = DeviceObject->DeviceExtension;

	IoReleaseCancelSpinLock(pIrp->CancelIrql);

	KeAcquireSpinLock(&pDeviceExtension->controlSpinLock, &oldIrql);

	pDeviceExtension-> pWaitIrp = NULL;        

	KeReleaseSpinLock(&pDeviceExtension->controlSpinLock, oldIrql);    
	
	vCOMCompleteRequest(pIrp, STATUS_CANCELLED, 0);
}

VOID vCOMCancelCurrentReadIrp(PDEVICE_OBJECT DeviceObject, PIRP pIrp)
{
	PvCOM_DEVICE_EXTENSION  	pDeviceExtension;
	KIRQL                   			oldIrql;

	pDeviceExtension = DeviceObject->DeviceExtension;

	IoReleaseCancelSpinLock(pIrp->CancelIrql);

	KeAcquireSpinLock(&pDeviceExtension->readSpinLock, &oldIrql);

	pDeviceExtension-> pReadIrpCurrent = NULL;        

	KeReleaseSpinLock(&pDeviceExtension->readSpinLock, oldIrql);    

	vCOMCompleteRequest(pIrp, STATUS_CANCELLED, 0);
	KeSetEvent(&pDeviceExtension->currentReadIrpWasCancelledEvent, 0, FALSE);
}

VOID vCOMCancelCurrentWriteIrp(PDEVICE_OBJECT DeviceObject, PIRP pIrp)
{
	PvCOM_DEVICE_EXTENSION  	pDeviceExtension;
	KIRQL                   			oldIrql;

	pDeviceExtension = DeviceObject->DeviceExtension;

	IoReleaseCancelSpinLock(pIrp->CancelIrql);

	KeAcquireSpinLock(&pDeviceExtension->writeSpinLock, &oldIrql);

	pDeviceExtension-> pWriteIrpCurrent= NULL;        

	KeReleaseSpinLock(&pDeviceExtension->writeSpinLock, oldIrql);    

	vCOMCompleteRequest(pIrp, STATUS_CANCELLED, 0);
	KeSetEvent(&pDeviceExtension->currentWriteIrpWasCancelledEvent, 0, FALSE);
}

ULONG vCOMCalculateReadTimeoutValues(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
	PvCOM_DEVICE_EXTENSION 	pDeviceExtension;
    	PIO_STACK_LOCATION 		pIrpStackLocation;
    	ULONG 						dataLength;
    	ULONG 						readIntervalTimeout;
  	ULONG 						readTotalTimeoutMultiplier;
  	ULONG 						readTotalTimeoutConstant;
	ULONG						readCombinedTimeout;
	
	pDeviceExtension = pDeviceObject->DeviceExtension;
	pIrpStackLocation = IoGetCurrentIrpStackLocation(pIrp); 
		
	dataLength = pIrpStackLocation->Parameters.Read.Length;
		
	readIntervalTimeout 		= pDeviceExtension->serTimeouts.ReadIntervalTimeout;
	readTotalTimeoutMultiplier 	= pDeviceExtension->serTimeouts.ReadTotalTimeoutMultiplier;
	readTotalTimeoutConstant 	= pDeviceExtension->serTimeouts.ReadTotalTimeoutConstant;

	KdPrint(("readIntervalTimeout is %lu\n", readIntervalTimeout));
	KdPrint(("readTotalTimeoutMultiplier is %lu\n", readTotalTimeoutMultiplier));
	KdPrint(("readTotalTimeoutConstant is %lu\n", readTotalTimeoutConstant));
	KdPrint(("MAXULONG is %lu\n", MAXULONG));

	/* NOTE:
	The timeout values for serTimeouts are in milliseconds.
	The kernel timers want the timeouts to be specified in multiples of 100 nS intervals.
	100 nS = 0.000000100 * 10000 = 0.001 or 1 mS
	So we need to multiply the values in mS by 10000 to get the proper time timeout values.
	10,000 1nS intervals is 1 mS.
	*/
	
	if (readIntervalTimeout == MAXULONG && readTotalTimeoutMultiplier == 0 && readTotalTimeoutConstant == 0)
	{
		KdPrint(("return immediately with whatever bytes there are or none...\n"));
		//return immediately with whatever bytes there are
		pDeviceExtension->readTotalTimeoutValue.QuadPart = 0;
		pDeviceExtension->readIntervalTimeoutValue.QuadPart = 0;
		return TIMEOUTS_IMMEDIATE_RETURN_WITH_BYTES;
	}
	else if (readIntervalTimeout == 0 && readTotalTimeoutMultiplier == 0 && readTotalTimeoutConstant == 0)
	{
		KdPrint(("wait forever...\n"));
		//total timeout is not used
		pDeviceExtension->readTotalTimeoutValue.QuadPart = 0;
		pDeviceExtension->readIntervalTimeoutValue.QuadPart = 0;	
		return TIMEOUTS_WAIT_FOREVER;
	}
	else if (readIntervalTimeout > 0 && readTotalTimeoutMultiplier == 0 && readTotalTimeoutConstant == 0)
	{
		KdPrint(("interval timeout...\n"));
		pDeviceExtension->readTotalTimeoutValue.QuadPart = 0;
		pDeviceExtension->readIntervalTimeoutValue.QuadPart = ((LONGLONG)readIntervalTimeout) * -10000;
		return TIMEOUTS_INTERVAL_TIMEOUT;
	}
	else if (readIntervalTimeout == MAXULONG && readTotalTimeoutMultiplier == MAXULONG && readTotalTimeoutConstant > 0 && readTotalTimeoutConstant != MAXULONG)
	{
		KdPrint(("if any bytes available return immediately with them, if none wait or total timeout...\n"));
		//if any bytes avaliable return immediately with them
		//if no bytes available wait and then return with any
		//otherwise timeout when readTotalTimeoutConstant time expires
		pDeviceExtension->readTotalTimeoutValue.QuadPart = ((LONGLONG)readTotalTimeoutConstant) * -10000;
		pDeviceExtension->readIntervalTimeoutValue.QuadPart = 0;	
		return TIMEOUTS_RETURNBYTES_OR_WAIT;
	}
	else if (readIntervalTimeout == 0 && readTotalTimeoutMultiplier != 0 && readTotalTimeoutConstant != 0)
	{
		KdPrint(("Total timeout only...\n"));
		//use total timeouts
		readCombinedTimeout = readTotalTimeoutConstant + readTotalTimeoutMultiplier * dataLength;
		pDeviceExtension->readTotalTimeoutValue.QuadPart = ((LONGLONG)readCombinedTimeout) * -10000;
		pDeviceExtension->readIntervalTimeoutValue.QuadPart = 0;	
		return TIMEOUTS_TOTAL_TIMEOUT;
	}
	else if (readIntervalTimeout != 0 && readTotalTimeoutMultiplier != 0 && readTotalTimeoutConstant != 0)
	{
		KdPrint(("use combined timeouts...\n"));
		//use total timeouts and interval
		readCombinedTimeout = readTotalTimeoutConstant + readTotalTimeoutMultiplier * dataLength;
		pDeviceExtension->readTotalTimeoutValue.QuadPart = ((LONGLONG)readCombinedTimeout) * -10000;
		pDeviceExtension->readIntervalTimeoutValue.QuadPart = ((LONGLONG)readIntervalTimeout) * -10000;
		return TIMEOUTS_COMBINED_TIMEOUT;
	}
	else
	{	
		KdPrint(("default: use total timeout only...\n"));
		//use total timeouts
		readCombinedTimeout = readTotalTimeoutConstant + readTotalTimeoutMultiplier * dataLength;
		pDeviceExtension->readTotalTimeoutValue.QuadPart = ((LONGLONG)readCombinedTimeout) * -10000;
		pDeviceExtension->readIntervalTimeoutValue.QuadPart = 0;
		return TIMEOUTS_TOTAL_TIMEOUT;
	}
	
}

ULONG vCOMCalculateWriteTimeoutValues(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
	PvCOM_DEVICE_EXTENSION 	pDeviceExtension;
	PIO_STACK_LOCATION 		pIrpStackLocation;
	ULONG 						dataLength;
	ULONG 						writeTotalTimeoutMultiplier;
	ULONG 						writeTotalTimeoutConstant;
	ULONG						writeCombinedTimeout;
	
	pDeviceExtension = pDeviceObject->DeviceExtension;
	pIrpStackLocation = IoGetCurrentIrpStackLocation(pIrp); 
		
	dataLength = pIrpStackLocation->Parameters.Read.Length;
		
	writeTotalTimeoutMultiplier 	= pDeviceExtension->serTimeouts.WriteTotalTimeoutMultiplier;
	writeTotalTimeoutConstant 	= pDeviceExtension->serTimeouts.WriteTotalTimeoutConstant;

	/* NOTE:
	The timeout values for serTimeouts are in milliseconds.
	The kernel timers want the timeouts to be specified in multiples of 100 nS intervals.
	100 nS = 0.000000100 * 10000 = 0.001 or 1 mS
	So we need to multiply the values in mS by 10000 to get the proper time timeout values.
	10,000 1nS intervals is 1 mS.
	*/
	
	KdPrint(("writeTotalTimeoutMultiplier is %lu\n", writeTotalTimeoutMultiplier));
	KdPrint(("writeTotalTimeoutConstant is %lu\n", writeTotalTimeoutConstant));
	KdPrint(("MAXULONG is %lu\n", MAXULONG));
			
	 if (writeTotalTimeoutMultiplier != 0 || writeTotalTimeoutConstant != 0)
	{
		KdPrint(("use write timeout...\n"));
		//use total timeouts and interval
		writeCombinedTimeout = writeTotalTimeoutConstant + writeTotalTimeoutMultiplier * dataLength;
		pDeviceExtension->writeTotalTimeoutValue.QuadPart = ((LONGLONG)writeCombinedTimeout) * -10000;
		pDeviceExtension->writeDelayLoopTimerValue.QuadPart = (LONGLONG)(-10000 * 10); //10mS
		return TIMEOUTS_TOTAL_TIMEOUT;
	}
	else
	{	
		KdPrint(("default: no write timeout...\n"));
		//use total timeouts
		pDeviceExtension->writeTotalTimeoutValue.QuadPart = 0;
		pDeviceExtension->writeDelayLoopTimerValue.QuadPart = (LONGLONG)(-10000 * 100); //100mS
		return TIMEOUTS_WAIT_FOREVER;
	}
	
}

VOID vCOMCheckComEvents(PvCOM_DEVICE_EXTENSION pDeviceExtension, ULONG events)
{
	PIRP            			pOldWaitIrp = NULL;
	PDRIVER_CANCEL  	pOldCancelRoutine;
	KIRQL          			oldIrql;


	KeAcquireSpinLock(&pDeviceExtension->controlSpinLock, &oldIrql);

	pDeviceExtension->eventHistory |= events;
	
	events &= pDeviceExtension->eventMask;

	if ((pDeviceExtension->pWaitIrp != NULL) && (events != 0))
	{
		pOldWaitIrp = pDeviceExtension->pWaitIrp;
		pOldCancelRoutine = IoSetCancelRoutine(pOldWaitIrp, NULL);

		if (pOldCancelRoutine != NULL)
		{
			pOldWaitIrp->IoStatus.Information = sizeof(ULONG);
			*(PULONG)pOldWaitIrp->AssociatedIrp.SystemBuffer = events;
			pOldWaitIrp->IoStatus.Status = STATUS_SUCCESS;

			pDeviceExtension->pWaitIrp = NULL;
			pDeviceExtension->eventHistory= 0;
		}
		else
		{
			pOldWaitIrp = NULL;
		}
	}

	KeReleaseSpinLock(&pDeviceExtension->controlSpinLock, oldIrql);

	if (pOldWaitIrp != NULL)
	{
		IoCompleteReques

⌨️ 快捷键说明

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