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

📄 vcom_device.c

📁 一个虚拟串口的驱动程序源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
			pTwinDeviceExtension->outBufferCount++;
			if (pTwinDeviceExtension->outBufferCount >= pTwinDeviceExtension->outBufferSize)
				break;
		}

		pDeviceExtension->inBufferCount = 0;
		pDeviceExtension->inBufferWritePosition = 0;
		pDeviceExtension->inBufferReadPosition = 0;

		KeReleaseSpinLock(&pDeviceExtension->writeSpinLock, write_oldIrql);
				
		if (eventCharRcvd)
			vCOMCheckComEvents(pTwinDeviceExtension, SERIAL_EV_RXFLAG | SERIAL_EV_RXCHAR);
		else
			vCOMCheckComEvents(pTwinDeviceExtension, SERIAL_EV_RXCHAR);		
				
		// notify the read thread for the twin device that a transfer occurred
		KeSetEvent(&pTwinDeviceExtension->transferOccurredEvent, 6, FALSE);

		return STATUS_SUCCESS;	
	}				
		
}

NTSTATUS vCOMDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP pIrp)
{
	NTSTATUS 					status;
	PvCOM_DEVICE_EXTENSION 	pDeviceExtension;
	PvCOM_DEVICE_EXTENSION 	pTwinDeviceExtension;
    	PIO_STACK_LOCATION 		pIrpStackLocation; 
	KIRQL 						oldIrql;
    	KIRQL 						write_oldIrql;
	KIRQL 						read_oldIrql;
	KIRQL						cancelIrql;
	PIRP            					pOldWaitIrp;
	PDRIVER_CANCEL 				cancelRoutine;
	PDRIVER_CANCEL 				pOldCancelRoutine;
	
	status = STATUS_SUCCESS;

	pDeviceExtension = DeviceObject->DeviceExtension;
	pTwinDeviceExtension = pDeviceExtension->pTwin->DeviceExtension;

	pIrpStackLocation = IoGetCurrentIrpStackLocation(pIrp);                     

	pIrp->IoStatus.Information = 0;

	if (status == STATUS_CANCELLED)
	{
		return vCOMCompleteRequest(pIrp,  status, 0);
	}
		
	KdPrint(("vCOMDeviceControl: IOControlCode = %x\n", pIrpStackLocation->Parameters.DeviceIoControl.IoControlCode));
						
	switch (pIrpStackLocation->Parameters.DeviceIoControl.IoControlCode)
	{
		
		case IOCTL_SERIAL_SET_TIMEOUTS:
		{
				
			PSERIAL_TIMEOUTS	pNewTimeouts;
			
			pNewTimeouts = (PSERIAL_TIMEOUTS)pIrp->AssociatedIrp.SystemBuffer;

			KdPrint(("vCOMDeviceControl: IOCTL_SERIAL_SET_TIMEOUTS\n"));
						
			if (pIrpStackLocation->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_TIMEOUTS))
			{
				status = STATUS_BUFFER_TOO_SMALL;
				break;
			}

			if ((pNewTimeouts->ReadIntervalTimeout == MAXULONG) &&
			    (pNewTimeouts->ReadTotalTimeoutMultiplier == MAXULONG) &&
			    (pNewTimeouts->ReadTotalTimeoutConstant == MAXULONG))
			{
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			//this is a fix to make the driver work with MSCOMM in return with any mode
			//see http://support.microsoft.com/default.aspx?scid=kb;en-us;318784
			//driver mode is TIMEOUTS_IMMEDIATE_RETURN_WITH_BYTES
			if ((pNewTimeouts->ReadIntervalTimeout == MAXULONG) &&
			    (pNewTimeouts->ReadTotalTimeoutMultiplier == 0) &&
			    (pNewTimeouts->ReadTotalTimeoutConstant == 0))
			{
				pDeviceExtension->fastRead = TRUE;
			}
			else
				pDeviceExtension->fastRead = FALSE;
				
			KeAcquireSpinLock(&pDeviceExtension->readSpinLock, &oldIrql);

			RtlMoveMemory(&pDeviceExtension->serTimeouts, pNewTimeouts, sizeof(SERIAL_TIMEOUTS));

			KeReleaseSpinLock(&pDeviceExtension->readSpinLock, oldIrql);

			KdPrint(("ReadIntervalTimeout: %lu\n", pNewTimeouts->ReadIntervalTimeout));
			KdPrint(("ReadTotalTimeoutMultiplier: %lu\n", pNewTimeouts->ReadTotalTimeoutMultiplier));
			KdPrint(("ReadTotalTimeoutConstant: %lu\n", pNewTimeouts->ReadTotalTimeoutConstant));
						
		      	break;
		}
	    
		case IOCTL_SERIAL_GET_TIMEOUTS:
	  	
			KdPrint(("vCOMDeviceControl: IOCTL_SERIAL_GET_TIMEOUTS\n"));

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

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

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

			RtlMoveMemory(pIrp->AssociatedIrp.SystemBuffer, &pDeviceExtension->serTimeouts, sizeof(SERIAL_TIMEOUTS));

			KeReleaseSpinLock(&pDeviceExtension->readSpinLock, oldIrql);

			break;	    

		case IOCTL_SERIAL_GET_WAIT_MASK:
				
			KdPrint(("vCOMDeviceControl: IOCTL_SERIAL_GET_WAIT_MASK\n"));

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

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

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

			break;
	     	
	     
		case IOCTL_SERIAL_SET_WAIT_MASK:
		{
			ULONG   newMask;
			
			KdPrint(("vCOMDeviceControl: IOCTL_SERIAL_SET_WAIT_MASK\n"));

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

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

			if ((newMask & ~(SERIAL_EV_RXCHAR | SERIAL_EV_RXFLAG | SERIAL_EV_TXEMPTY | SERIAL_EV_CTS |
							SERIAL_EV_DSR | SERIAL_EV_RLSD | SERIAL_EV_BREAK | SERIAL_EV_ERR |
							SERIAL_EV_RING | SERIAL_EV_PERR | SERIAL_EV_RX80FULL | SERIAL_EV_EVENT1 |
							SERIAL_EV_EVENT2)) != 0)
			{
				status = STATUS_INVALID_PARAMETER;
				break;
			}

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

			pOldWaitIrp = pDeviceExtension->pWaitIrp;

			if (pOldWaitIrp != NULL)
			{
				pOldCancelRoutine = IoSetCancelRoutine(pOldWaitIrp, NULL);

				if (pOldCancelRoutine != NULL)
				{
					pOldWaitIrp->IoStatus.Information = sizeof(ULONG);

					*(PULONG)pOldWaitIrp->AssociatedIrp.SystemBuffer = 0;

					pOldWaitIrp->IoStatus.Status = STATUS_SUCCESS;

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

			pDeviceExtension->eventMask = newMask;

			KeReleaseSpinLock(&pDeviceExtension->controlSpinLock, oldIrql);

			if (pOldWaitIrp != NULL)
				IoCompleteRequest(pOldWaitIrp, IO_NO_INCREMENT);

			break;
		}
	    
		case IOCTL_SERIAL_WAIT_ON_MASK:			

			KdPrint(("vCOMDeviceControl: IOCTL_SERIAL_WAIT_ON_MASK\n"));

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

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

			if ((pDeviceExtension->pWaitIrp != NULL) || (pDeviceExtension->eventMask == 0))
			{
				status = STATUS_INVALID_PARAMETER;
			}
			else if ((pDeviceExtension->eventMask & pDeviceExtension->eventHistory) != 0)
			{
				pIrp->IoStatus.Information = sizeof(ULONG);
				*(PULONG)pIrp->AssociatedIrp.SystemBuffer = pDeviceExtension->eventMask & pDeviceExtension->eventHistory;

				pDeviceExtension->eventHistory = 0;

				KdPrint(("IOCTL_SERIAL_WAIT_ON_MASK set with STATUS_SUCCESS...\n"));
				status = STATUS_SUCCESS;
			}
			else
			{
				pDeviceExtension->pWaitIrp = pIrp;

				status = STATUS_PENDING;

				IoSetCancelRoutine(pIrp, vCOMCancelWaitIrp);

				if (pIrp->Cancel)
				{
				pOldCancelRoutine = IoSetCancelRoutine(pIrp, NULL);

					if (pOldCancelRoutine != NULL)
					{
						KdPrint(("IOCTL_SERIAL_WAIT_ON_MASK set with STATUS_CANCELLED...\n"));
						status = STATUS_CANCELLED;
						pDeviceExtension->pWaitIrp = NULL;
					}
					else
					{
						KdPrint(("IOCTL_SERIAL_WAIT_ON_MASK set with STATUS_PENDING...\n"));
						IoMarkIrpPending(pIrp);
					}
				}
				else
				{
					KdPrint(("IOCTL_SERIAL_WAIT_ON_MASK set with STATUS_PENDING...\n"));
					IoMarkIrpPending(pIrp);
				}
				
			}

			KeReleaseSpinLock(&pDeviceExtension->controlSpinLock, oldIrql);

			break;
	  	
	    	
		case IOCTL_SERIAL_PURGE:
		{
			ULONG   mask;
			ULONG   channels;	

			KdPrint(("vCOMDeviceControl: IOCTL_SERIAL_PURGE\n"));
			
			if (pIrpStackLocation->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
			{
				pIrp->IoStatus.Information = 0;
				status = STATUS_BUFFER_TOO_SMALL;
				break;
			}

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

			KdPrint(("purge mask: %x\n", mask));
			
			if ((mask == 0) || ((mask & ~(SERIAL_PURGE_TXABORT | SERIAL_PURGE_RXABORT |
								SERIAL_PURGE_TXCLEAR | SERIAL_PURGE_RXCLEAR)) != 0))
			{
				pIrp->IoStatus.Information = 0;
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			if (mask & SERIAL_PURGE_RXABORT)
			{
				KdPrint(("purge SERIAL_PURGE_RXABORT\n"));

				if (pDeviceExtension->pReadIrpCurrent != NULL)
				{
					IoAcquireCancelSpinLock(&cancelIrql);

					cancelRoutine = pDeviceExtension->pReadIrpCurrent->CancelRoutine;
					pDeviceExtension->pReadIrpCurrent->Cancel = TRUE;

					if (cancelRoutine)
					{
						pDeviceExtension->pReadIrpCurrent->CancelRoutine = NULL;
						pDeviceExtension->pReadIrpCurrent->CancelIrql = cancelIrql;
						cancelRoutine(DeviceObject,  pDeviceExtension->pReadIrpCurrent);
					}
					else
					{
						IoReleaseCancelSpinLock(cancelIrql);
					}				
				}
								
				pIrp->IoStatus.Information = sizeof(ULONG);				
			}

			if (mask & SERIAL_PURGE_TXABORT)
			{
				KdPrint(("purge SERIAL_PURGE_TXABORT\n"));

				if (pDeviceExtension->pWriteIrpCurrent != NULL)
				{
					
					IoAcquireCancelSpinLock(&cancelIrql);

					cancelRoutine = pDeviceExtension->pWriteIrpCurrent->CancelRoutine;
					pDeviceExtension->pWriteIrpCurrent->Cancel = TRUE;

					if (cancelRoutine)
					{
						pDeviceExtension->pWriteIrpCurrent->CancelRoutine = NULL;
						pDeviceExtension->pWriteIrpCurrent->CancelIrql = cancelIrql;
						cancelRoutine(DeviceObject,  pDeviceExtension->pWriteIrpCurrent);
					}
					else
					{
						IoReleaseCancelSpinLock(cancelIrql);
					}
				}
				
				pIrp->IoStatus.Information = sizeof(ULONG);				
			}

			if (mask & SERIAL_PURGE_RXCLEAR)
			{
				KdPrint(("purge SERIAL_PURGE_RXCLEAR\n"));
				KeAcquireSpinLock(&pDeviceExtension->readSpinLock, &read_oldIrql);
				pDeviceExtension->outBufferReadPosition = 0;
				pDeviceExtension->outBufferWritePosition = 0;
				pDeviceExtension->outBufferCount = 0;
				pDeviceExtension->readBufferCount = 0;
				RtlZeroMemory(pDeviceExtension->outBuffer, BUFFERLENGTH);
				pDeviceExtension->eventHistory = 0;
				KeReleaseSpinLock(&pDeviceExtension->readSpinLock, read_oldIrql);
				
				pIrp->IoStatus.Information = sizeof(ULONG);
				
			}

			if (mask & SERIAL_PURGE_TXCLEAR)
			{
				KdPrint(("purge SERIAL_PURGE_TXCLEAR\n"));
				KeAcquireSpinLock(&pDeviceExtension->writeSpinLock, &write_oldIrql);
				pDeviceExtension->inBufferReadPosition = 0;
				pDeviceExtension->inBufferWritePosition = 0;
				pDeviceExtension->inBufferCount = 0;	
				RtlZeroMemory(pDeviceExtension->inBuffer, BUFFERLENGTH);
				pDeviceExtension->eventHistory = 0;
				KeReleaseSpinLock(&pDeviceExtension->writeSpinLock, write_oldIrql);
				
				pIrp->IoStatus.Information = sizeof(ULONG);
			}
			
			break;
		}
	        
		case IOCTL_SERIAL_GET_BAUD_RATE:
			
			KdPrint(("vCOMDeviceControl: IOCTL_SERIAL_GET_BAUD_RATE\n"));

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

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

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

			RtlMoveMemory(pIrp->AssociatedIrp.SystemBuffer, &pDeviceExtension->serBaudRate, sizeof(SERIAL_BAUD_RATE));

			KeReleaseSpinLock(&pDeviceExtension->controlSpinLock, oldIrql);

			break;			
		      
		case IOCTL_SERIAL_SET_BAUD_RATE:
		{
			PSERIAL_BAUD_RATE pNewBaudRate = (PSERIAL_BAUD_RATE)pIrp->AssociatedIrp.SystemBuffer;

			KdPrint(("vCOMDeviceControl: IOCTL_SERIAL_SET_BAUD_RATE\n"));

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

⌨️ 快捷键说明

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