www.pudn.com > 2004-01-16_SimSerial.rar > Ioctl.c


#include  
#include  
 
#include "main.h" 
#include "..\inc\wdmioctl.h" 
 
 
#ifdef ALLOC_PRAGMA 
 
#endif 
 
extern DEVICE_ARRAY	gDeviceArray[ MAX_NUM_DEV ]; 
extern KSPIN_LOCK		gSpinLock; 
extern KSPIN_LOCK		gPoolSpinLock; 
extern LIST_ENTRY		gIdleQueue; 
 
NTSTATUS RequestControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 
/*++ 
Routine Description: 
 
Arguments: 
 
    DeviceObject - Pointer to deviceobject 
    Irp          - Pointer to a PnP Irp. 
 
Return Value: 
 
    NT Status is returned. 
--*/ 
{ 
	PIO_STACK_LOCATION IrpStack; 
	ULONG				ControlCode; 
	ULONG				InputLength,OutputLength; 
	NTSTATUS			status; 
	PDEVICE_EXTENSION	deviceExtension; 
	ULONG				info; 
 
	DebugPrint(("Enter IoControl routine\n")); 
	deviceExtension = ( PDEVICE_EXTENSION )DeviceObject->DeviceExtension; 
 
	if( !deviceExtension->bIsOpen ){ 
		status = STATUS_INVALID_DEVICE_REQUEST; 
		return CompleteRequest( Irp, status, 0 ); 
	} 
 
 
	IrpStack=IoGetCurrentIrpStackLocation(Irp); 
	 
	ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode; 
	InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength; 
	OutputLength= IrpStack->Parameters.DeviceIoControl.OutputBufferLength; 
	DbgPrint("InputBufferLength:  %d     OutputBufferLength:   %d\n", InputLength, OutputLength ); 
	 
	status = STATUS_INVALID_DEVICE_REQUEST; 
	info = 0; 
	switch(ControlCode) 
	{ 
		case IOCTL_GET_IDENTITIER: 
			// 得到本驱动的ID,用来指明该设备是本驱动生成的虚拟串口设备 
			DebugPrint(("-----  IOCTL_GET_IDENTITIER   ----\n")); 
			if( IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof( ULONG ) ){ 
				status = STATUS_BUFFER_TOO_SMALL; 
				break; 
			} 
			*( (PULONG)Irp->AssociatedIrp.SystemBuffer ) = VIRTUAL_SERIAL_DEVICE_ID; 
			status=STATUS_SUCCESS; 
			info = sizeof( ULONG ); 
			break; 
		case IOCTL_GET_CURRENT_COMX: 
			DebugPrint(("-----  IOCTL_GET_CURRENT_COMX   ----\n")); 
			if( IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof( ULONG ) ){ 
				status = STATUS_BUFFER_TOO_SMALL; 
				break; 
			} 
			if( deviceExtension->CreatedSymbolicLink ){ 
				*( (PULONG)Irp->AssociatedIrp.SystemBuffer ) = deviceExtension->ComX; 
				info = sizeof( ULONG ); 
				status = STATUS_SUCCESS; 
			} 
			break; 
		case IOCTL_CREATE_DOS_NAME: 
			{ 
				LONG ComX; 
				DebugPrint(("-----  IOCTL_INIT_SETTING   ----\n")); 
				if( IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof( LONG ) ){ 
					status = STATUS_BUFFER_TOO_SMALL; 
					break; 
				} 
				ComX = *((PLONG)Irp->AssociatedIrp.SystemBuffer); 
				// 此处注意Dos名不要重复 
				if( ( ComX > 255 ) || ( ComX < 1 ) ){ 
					status = STATUS_INVALID_PARAMETER; 
					break; 
				} 
				if( !deviceExtension->CreatedSymbolicLink ){ 
					status = SerialDoExternalNaming( deviceExtension, ComX); 
				} 
				break; 
			} 
		case IOCTL_DEL_DOS_NAME: 
			DebugPrint(("-----  IOCTL_FINISH_SETTING   ----\n")); 
			if( deviceExtension->CreatedSymbolicLink ){ 
				status = SerialUndoExternalNaming( deviceExtension ); 
			} 
			break; 
		case IOCTL_GET_CURRENT_INSTANCE: 
			{ 
				DebugPrint(("--  IOCTL_GET_CURRENT_INSTANCE  ---\n")); 
				if( IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof( ULONG ) ){ 
					status = STATUS_BUFFER_TOO_SMALL; 
					break; 
				} 
				DebugPrint(("localInstance:  %d\n", deviceExtension->localInstance )); 
				*( (PULONG)Irp->AssociatedIrp.SystemBuffer ) = deviceExtension->localInstance; 
				status = STATUS_SUCCESS; 
				info = sizeof( ULONG ); 
				break; 
			} 
		case IOCTL_SET_REMOTE_INSTANCE: 
			{ 
				LONG	remoteInstance; 
				KIRQL				OldIrql; 
				DebugPrint(("--  IOCTL_SET_REMOTE_INSTANCE  ---\n")); 
				if( IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof( ULONG ) ){ 
					DebugPrint(("buffer is too small\n")); 
					status = STATUS_BUFFER_TOO_SMALL; 
					break; 
				} 
				// 若已经Connected,则返回错误。此时win32app 需要调用disconnect首先断开连接 
				if( deviceExtension->remoteInstance != INVALID_INSTANCE ){ 
					break; 
				} 
				remoteInstance = *( (PULONG)Irp->AssociatedIrp.SystemBuffer ); 
				if( ( remoteInstance < 0 ) || ( remoteInstance > 255 ) || 
					( gDeviceArray[ remoteInstance ].deviceExtension == NULL ) ){ 
					DebugPrint(("remoteInstance error remoteInstance: %d\n", remoteInstance)); 
					status = STATUS_INVALID_PARAMETER; 
					break; 
				} 
				//Disconnect( deviceExtension ); 
				DebugPrint(("Connect remote ports...")); 
				KeAcquireSpinLock( &gSpinLock, &OldIrql ); 
				if( gDeviceArray[ remoteInstance ].deviceExtension->bIsConnected ){ 
					KeReleaseSpinLock( &gSpinLock, OldIrql ); 
					status = STATUS_INVALID_PARAMETER; 
					break; 
				} 
				deviceExtension->remoteInstance = remoteInstance; 
				deviceExtension->bIsConnected = TRUE; 
				gDeviceArray[ remoteInstance ].deviceExtension->remoteInstance = deviceExtension->localInstance; 
				gDeviceArray[ remoteInstance ].deviceExtension->bIsConnected = TRUE; 
				KeReleaseSpinLock( &gSpinLock, OldIrql ); 
				status = STATUS_SUCCESS; 
				info = sizeof( ULONG ); 
				break; 
			} 
		case IOCTL_GET_REMOTE_INSTANCE: 
			{ 
				DebugPrint(("--  IOCTL_GET_REMOTE_INSTANCE  ---\n")); 
				if( IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof( ULONG ) ){ 
					status = STATUS_BUFFER_TOO_SMALL; 
					break; 
				} 
				if( !deviceExtension->bIsConnected ){ 
					DebugPrint(("remoteInstance:  %d\n", deviceExtension->remoteInstance )); 
					status = STATUS_INVALID_DEVICE_REQUEST; 
					break; 
				} 
				*( (PULONG)Irp->AssociatedIrp.SystemBuffer ) = deviceExtension->remoteInstance; 
				status = STATUS_SUCCESS; 
				info = sizeof( ULONG ); 
				break; 
			} 
		case IOCTL_DISCONNECT: 
			DebugPrint(("---  IOCTL_DISCONNECT   ----\n")); 
			status = Disconnect( deviceExtension ); 
			break; 
		case IOCTL_SERIAL_SET_BAUD_RATE: 
			{// to be continued 
				// e.g 
				DebugPrint(("--  IOCTL_SERIAL_SET_BAUD_RATE  ---\n")); 
				if( IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof( SERIAL_BAUD_RATE ) ){ 
					status = STATUS_BUFFER_TOO_SMALL; 
					break; 
				} 
				deviceExtension->CurrentBaud = ((PSERIAL_BAUD_RATE)(Irp->AssociatedIrp.SystemBuffer))->BaudRate; 
				DebugPrint(("CurrentBaud :  %d     SetBaudRate:   %d\n", deviceExtension->CurrentBaud, ((PSERIAL_BAUD_RATE)(Irp->AssociatedIrp.SystemBuffer))->BaudRate)); 
				status = STATUS_SUCCESS; 
				break; 
			} 
		case IOCTL_SERIAL_GET_BAUD_RATE: 
			{ 
				PSERIAL_BAUD_RATE	Br = ( PSERIAL_BAUD_RATE )Irp->AssociatedIrp.SystemBuffer; 
				DebugPrint(("--  IOCTL_SERIAL_GET_BAUD_RATE  ---\n")); 
				if( IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof( SERIAL_BAUD_RATE ) ){ 
					status = STATUS_BUFFER_TOO_SMALL; 
					break; 
				} 
				DebugPrint(("Br->BaudRate :  %d\n", Br->BaudRate )); 
				Br->BaudRate = deviceExtension->CurrentBaud; 
				DebugPrint(("CurrentBaud:  %d    Br->BaudRate   %d\n", deviceExtension->CurrentBaud, Br->BaudRate )); 
				info = sizeof( SERIAL_BAUD_RATE ); 
				status = STATUS_SUCCESS; 
				break; 
			} 
		case IOCTL_SERIAL_GET_MODEM_CONTROL: 
			DebugPrint(("--  IOCTL_SERIAL_GET_MODEM_CONTROL   --\n")); 
			break; 
		case IOCTL_SERIAL_SET_MODEM_CONTROL: 
			DebugPrint(("--  IOCTL_SERIAL_SET_MODEM_CONTROL   --\n")); 
			break; 
		case IOCTL_SERIAL_SET_FIFO_CONTROL: 
			DebugPrint(("--  IOCTL_SERIAL_SET_FIFO_CONTROL   --\n")); 
			break; 
		case IOCTL_SERIAL_SET_LINE_CONTROL: 
			{ 
				PSERIAL_LINE_CONTROL Lc; 
				UCHAR LData; 
				UCHAR LStop; 
				UCHAR LParity; 
				UCHAR Mask = 0xff; 
				DebugPrint(("--  IOCTL_SERIAL_SET_LINE_CONTROL   --\n")); 
				if( IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_LINE_CONTROL)) { 
					status = STATUS_BUFFER_TOO_SMALL; 
					break; 
				} 
				Lc = ((PSERIAL_LINE_CONTROL)(Irp->AssociatedIrp.SystemBuffer)); 
				deviceExtension->LineControl.WordLength = Lc->WordLength; 
				deviceExtension->LineControl.Parity		= Lc->Parity; 
				deviceExtension->LineControl.StopBits	= Lc->StopBits; 
				DebugPrint(("IOCTL_SERIAL_SET_LINE_CONTROL:  WordLength:  %d  Parity:  %d  StopBits  %d\n", Lc->WordLength, Lc->Parity, Lc->StopBits )); 
				status = STATUS_SUCCESS; 
				break; 
 
			} 
		case IOCTL_SERIAL_GET_LINE_CONTROL: 
			{	//	need ControlLock 
				PSERIAL_LINE_CONTROL Lc = (PSERIAL_LINE_CONTROL)Irp->AssociatedIrp.SystemBuffer; 
				DebugPrint(("--  IOCTL_SERIAL_GET_LINE_CONTROL   --\n")); 
				 
				if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_LINE_CONTROL)) { 
					status = STATUS_BUFFER_TOO_SMALL; 
					break; 
				} 
				Lc->WordLength	= deviceExtension->LineControl.WordLength; 
				Lc->Parity		= deviceExtension->LineControl.Parity; 
				Lc->StopBits	= deviceExtension->LineControl.StopBits; 
 
				DebugPrint(("IOCTL_SERIAL_GET_LINE_CONTROL:  WordLength:  %d  Parity:  %d  StopBits  %d\n", Lc->WordLength, Lc->Parity, Lc->StopBits )); 
				info = sizeof(SERIAL_LINE_CONTROL); 
				status = STATUS_SUCCESS; 
				break; 
			} 
		case IOCTL_SERIAL_SET_TIMEOUTS: 
			{ 
				PSERIAL_TIMEOUTS NewTimeouts = 
					((PSERIAL_TIMEOUTS)(Irp->AssociatedIrp.SystemBuffer)); 
				DebugPrint(("--  IOCTL_SERIAL_SET_TIMEOUTS   --\n")); 
				if ( IrpStack->Parameters.DeviceIoControl.InputBufferLength < 
					sizeof(SERIAL_TIMEOUTS)) { 
					status = STATUS_BUFFER_TOO_SMALL; 
					break; 
				} 
				if ((NewTimeouts->ReadIntervalTimeout == MAXULONG) && 
					(NewTimeouts->ReadTotalTimeoutMultiplier == MAXULONG) && 
					(NewTimeouts->ReadTotalTimeoutConstant == MAXULONG)) { 
					status = STATUS_INVALID_PARAMETER; 
					break; 
				} 
				deviceExtension->Timeouts.ReadIntervalTimeout = NewTimeouts->ReadIntervalTimeout; 
				deviceExtension->Timeouts.ReadTotalTimeoutMultiplier =NewTimeouts->ReadTotalTimeoutMultiplier; 
				deviceExtension->Timeouts.ReadTotalTimeoutConstant = NewTimeouts->ReadTotalTimeoutConstant; 
				deviceExtension->Timeouts.WriteTotalTimeoutMultiplier =	NewTimeouts->WriteTotalTimeoutMultiplier; 
				deviceExtension->Timeouts.WriteTotalTimeoutConstant = NewTimeouts->WriteTotalTimeoutConstant; 
				DebugPrint(("Set_Timeouts\n")); 
				status = STATUS_SUCCESS; 
				break; 
			} 
		case IOCTL_SERIAL_GET_TIMEOUTS: 
			{ 
				if ( IrpStack->Parameters.DeviceIoControl.OutputBufferLength < 
					sizeof(SERIAL_TIMEOUTS)) { 
					status = STATUS_BUFFER_TOO_SMALL; 
					break; 
				} 
				DebugPrint(("--  IOCTL_SERIAL_GET_TIMEOUTS   --\n")); 
				*((PSERIAL_TIMEOUTS)Irp->AssociatedIrp.SystemBuffer) = deviceExtension->Timeouts; 
				//Irp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS);	// modified by zcz dec 25, 2003 
				info = sizeof( SERIAL_TIMEOUTS ); 
				status = STATUS_SUCCESS; 
				break; 
			} 
		case IOCTL_SERIAL_SET_CHARS: 
			{ 
				PSERIAL_CHARS NewChars = 
					((PSERIAL_CHARS)(Irp->AssociatedIrp.SystemBuffer)); 
				DebugPrint(("--  IOCTL_SERIAL_SET_CHARS   --\n")); 
				if ( IrpStack->Parameters.DeviceIoControl.InputBufferLength < 
					sizeof(SERIAL_CHARS)) { 
					status = STATUS_BUFFER_TOO_SMALL; 
					break; 
				}else if( NewChars->XonChar == NewChars->XoffChar ){ 
					status = STATUS_INVALID_PARAMETER; 
					break; 
				}else{ 
					deviceExtension->SpecialChars.EofChar	= NewChars->EofChar; 
					deviceExtension->SpecialChars.ErrorChar	= NewChars->ErrorChar; 
					deviceExtension->SpecialChars.BreakChar	= NewChars->BreakChar; 
					deviceExtension->SpecialChars.EventChar	= NewChars->EventChar; 
					deviceExtension->SpecialChars.XonChar	= NewChars->XonChar; 
					deviceExtension->SpecialChars.XoffChar	= NewChars->XoffChar; 
					DebugPrint(("SetChars:  %2x %2x %2x %2x %2x %2x\n", NewChars->EofChar, NewChars->ErrorChar, NewChars->BreakChar, NewChars->EventChar, NewChars->XonChar, NewChars->XoffChar )); 
					status = STATUS_SUCCESS; 
				} 
				break; 
			} 
		case IOCTL_SERIAL_GET_CHARS: 
			{	//	need ControlLock 
				PSERIAL_CHARS NewChars = ((PSERIAL_CHARS)(Irp->AssociatedIrp.SystemBuffer)); 
				DebugPrint(("--  IOCTL_SERIAL_GET_CHARS   --\n")); 
 
				if( IrpStack->Parameters.DeviceIoControl.OutputBufferLength < 
					sizeof(SERIAL_CHARS)) { 
					status = STATUS_BUFFER_TOO_SMALL; 
					break; 
				} 
				((PSERIAL_CHARS)Irp->AssociatedIrp.SystemBuffer)->XonChar	= deviceExtension->SpecialChars.XonChar; 
				((PSERIAL_CHARS)Irp->AssociatedIrp.SystemBuffer)->XoffChar	= deviceExtension->SpecialChars.XoffChar; 
				((PSERIAL_CHARS)Irp->AssociatedIrp.SystemBuffer)->EofChar	= deviceExtension->SpecialChars.EofChar; 
				((PSERIAL_CHARS)Irp->AssociatedIrp.SystemBuffer)->ErrorChar	= deviceExtension->SpecialChars.ErrorChar; 
				((PSERIAL_CHARS)Irp->AssociatedIrp.SystemBuffer)->BreakChar	= deviceExtension->SpecialChars.BreakChar; 
				((PSERIAL_CHARS)Irp->AssociatedIrp.SystemBuffer)->EventChar	= deviceExtension->SpecialChars.EventChar; 
				DebugPrint(("GetChars:  %2x %2x %2x %2x %2x %2x\n", NewChars->EofChar, NewChars->ErrorChar, NewChars->BreakChar, NewChars->EventChar, NewChars->XonChar, NewChars->XoffChar )); 
				info = sizeof( SERIAL_CHARS ); 
				status = STATUS_SUCCESS; 
				break; 
			} 
		case IOCTL_SERIAL_SET_DTR: 
			{ 
				DebugPrint(("--  IOCTL_SERIAL_SET_DTR   --\n")); 
				if (( deviceExtension->HandFlow.ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_HANDSHAKE){ 
					DebugPrint(("IOCTL_SERIAL_SET_DTR error: Current ControlHandShake 0x%x\n", deviceExtension->HandFlow.ControlHandShake )); 
					status = STATUS_INVALID_PARAMETER; 
				} 
				info = 0; 
				//*(PULONG)Irp->AssociatedIrp.SystemBuffer = 0; 
				status = STATUS_SUCCESS; 
 
				break; 
			} 
        case IOCTL_SERIAL_CLR_DTR: 
			{ 
				DebugPrint(("--  IOCTL_SERIAL_CLR_DTR   --\n")); 
				if (( deviceExtension->HandFlow.ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_HANDSHAKE){ 
					DebugPrint(("IOCTL_SERIAL_CLR_DTR error\n")); 
					status = STATUS_INVALID_PARAMETER; 
				} 
				//*(PULONG)Irp->AssociatedIrp.SystemBuffer = 0; 
				status = STATUS_SUCCESS; 
				break; 
			} 
		case IOCTL_SERIAL_RESET_DEVICE: 
			DebugPrint(("--  IOCTL_SERIAL_RESET_DEVICE   --\n")); 
			break; 
		case IOCTL_SERIAL_SET_RTS: 
			{ 
				DebugPrint(("--  IOCTL_SERIAL_SET_RTS   --\n")); 
				if (( deviceExtension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_RTS_HANDSHAKE ){ 
					DebugPrint(("IOCTL_SERIAL_SET_RTS error\n")); 
					status = STATUS_INVALID_PARAMETER; 
				} 
				 
				status = STATUS_SUCCESS; 
				break; 
			} 
		case IOCTL_SERIAL_CLR_RTS: 
			DebugPrint(("--  IOCTL_SERIAL_CLR_RTS   --\n")); 
			break; 
		case IOCTL_SERIAL_SET_XOFF: 
			DebugPrint(("--  IOCTL_SERIAL_SET_XOFF   --\n")); 
			break; 
		case IOCTL_SERIAL_SET_XON: 
			DebugPrint(("--  IOCTL_SERIAL_SET_XON   --\n")); 
			break; 
		case IOCTL_SERIAL_SET_BREAK_ON: 
			DebugPrint(("--  IOCTL_SERIAL_SET_BREAK_ON   --\n")); 
			break; 
		case IOCTL_SERIAL_SET_BREAK_OFF: 
			DebugPrint(("--  IOCTL_SERIAL_SET_BREAK_OFF   --\n")); 
			break; 
		case IOCTL_SERIAL_SET_QUEUE_SIZE: 
			{ 
				PSERIAL_QUEUE_SIZE	Rs = ( PSERIAL_QUEUE_SIZE )Irp->AssociatedIrp.SystemBuffer; 
				DebugPrint(("--  IOCTL_SERIAL_SET_QUEUE_SIZE   --\n")); 
				if( IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_QUEUE_SIZE)) { 
					status = STATUS_BUFFER_TOO_SMALL; 
					break; 
				} 
				if( Rs->InSize > deviceExtension->BufferSize ){ 
					deviceExtension->BufferSize = Rs->InSize; 
				} 
				DebugPrint(("Buffersize :  %d\n", deviceExtension->BufferSize )); 
				status = STATUS_SUCCESS; 
				break; 
#if 0 
				try{ 
					IrpStack->Parameters.DeviceIoControl.Type3InputBuffer = 
						ExAllocatePoolWithQuota( NonPagedPool, Rs->InSize ); 
				}except( EXCEPTION_EXECUTE_HANDLER ){ 
					IrpStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL; 
					status = GetExceptionCode(); 
				} 
				if (!IrpStack->Parameters.DeviceIoControl.Type3InputBuffer) { 
					break; 
				} 
				if( ( deviceExtension->BufferSize != 0 ) || ( deviceExtension->ReadBufferBase != NULL ) ){ 
					ExFreePool( deviceExtension->ReadBufferBase ); 
					deviceExtension->BufferSize = 0; 
				} 
				deviceExtension->ReadBufferBase = IrpStack->Parameters.DeviceIoControl.Type3InputBuffer; 
#endif 
 
			} 
		case IOCTL_SERIAL_GET_WAIT_MASK: 
			{ 
				DebugPrint(("--  IOCTL_SERIAL_GET_WAIT_MASK   --\n")); 
				break; 
			} 
		case IOCTL_SERIAL_SET_WAIT_MASK: 
			{ 
				ULONG NewMask; 
				if ( IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { 
					status = STATUS_BUFFER_TOO_SMALL; 
					break; 
				}else{ 
					NewMask = *((ULONG *)Irp->AssociatedIrp.SystemBuffer); 
				} 
				DebugPrint(("--  IOCTL_SERIAL_SET_WAIT_MASK   --\n")); 
				 
				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)) { 
					DebugPrint(("SERIAL: Unknown mask %x\n",NewMask)); 
					status = STATUS_INVALID_PARAMETER; 
					break; 
				} 
				DebugPrint(("Set wait mask:   0x%x\n", NewMask )); 
				if( deviceExtension->bIsWaitOnMask ){	// 取消上一次的WAIT_ON_MASK Irp 
					ASSERT( deviceExtension->WaitOnMaskIrp ); 
					*((ULONG *)deviceExtension->WaitOnMaskIrp->AssociatedIrp.SystemBuffer) = 0; 
					CompleteRequest( deviceExtension->WaitOnMaskIrp, STATUS_SUCCESS, sizeof( ULONG )); 
					deviceExtension->WaitOnMaskIrp = NULL; 
					deviceExtension->bIsWaitOnMask = FALSE; 
				} 
				deviceExtension->WaitMask = NewMask; 
				status = STATUS_SUCCESS; 
				//SerialStartMask(); 
				break; 
			} 
		case IOCTL_SERIAL_WAIT_ON_MASK: 
			{ 
				ULONG	RetMask; 
				DebugPrint(("--  IOCTL_SERIAL_WAIT_ON_MASK   --\n")); 
				if ( IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { 
					DebugPrint(("SERIAL: Invalid size for the buffer %d\n", 
						IrpStack->Parameters.DeviceIoControl.OutputBufferLength)); 
					status = STATUS_BUFFER_TOO_SMALL; 
					break; 
				}else if( deviceExtension->bIsWaitOnMask ){ 
					DebugPrint(("There is a wait-on-mask request already pending\n")); 
					status = STATUS_INVALID_PARAMETER; 
					break; 
				} 
				/* 
				RetMask = SERIAL_EV_TXEMPTY | SERIAL_EV_RXCHAR | SERIAL_EV_RX80FULL;//SERIAL_EV_CTS; 
				//SerialStartMask(); 
				*((ULONG *)Irp->AssociatedIrp.SystemBuffer) = RetMask; 
				*/ 
				DebugPrint(("MarkIrpPending\n")); 
				IoMarkIrpPending( Irp ); 
				IoSetCancelRoutine( Irp, RequestCancelMaskRoutine); 
				ASSERT( deviceExtension->WaitOnMaskIrp == NULL ); 
				deviceExtension->WaitOnMaskIrp = Irp; 
				deviceExtension->bIsWaitOnMask = TRUE; 
				status = STATUS_PENDING; 
				return status; 
			} 
		case IOCTL_SERIAL_IMMEDIATE_CHAR: 
			DebugPrint(("--  IOCTL_SERIAL_IMMEDIATE_CHAR   --\n")); 
			break; 
		case IOCTL_SERIAL_PURGE: 
			{ 
				ULONG	PurgeMask; 
				DebugPrint(("--   IOCTL_SERIAL_PURGE  --\n")); 
				if ( IrpStack->Parameters.DeviceIoControl.InputBufferLength < 
					sizeof( ULONG )) { 
					DebugPrint(("Serial purge output buffer too small\n")); 
					status = STATUS_BUFFER_TOO_SMALL; 
					break; 
				} 
				PurgeMask = *(PULONG)Irp->AssociatedIrp.SystemBuffer; 
				DebugPrint(("IOCTL_SERIAL_PURGE:   0x%x\n", PurgeMask)); 
				if( PurgeMask & SERIAL_PURGE_RXABORT ){ 
					RequestPurgeIrpQueue( DeviceObject, &deviceExtension->ReadIrpQueue ); 
				} 
				if( PurgeMask & SERIAL_PURGE_TXABORT ){ 
					RequestPurgeIrpQueue( DeviceObject, &deviceExtension->WriteIrpQueue ); 
				} 
				if( PurgeMask & SERIAL_PURGE_RXCLEAR ){ 
					RequestPurgeDataQueue( DeviceObject, &deviceExtension->ReadDataQueue ); 
				} 
				if( PurgeMask & SERIAL_PURGE_TXCLEAR ){ 
					DebugPrint(("Purge TxClear\n")); 
				} 
				info = sizeof( ULONG ); 
				status = STATUS_SUCCESS; 
				break; 
			} 
		case IOCTL_SERIAL_GET_HANDFLOW: 
			{ 
				PSERIAL_HANDFLOW	HandFlow; 
				DebugPrint(("--  IOCTL_SERIAL_GET_HANDFLOW   --\n")); 
				if ( IrpStack->Parameters.DeviceIoControl.OutputBufferLength < 
					sizeof(SERIAL_HANDFLOW)) { 
					status = STATUS_BUFFER_TOO_SMALL; 
					break; 
				} 
				HandFlow = (PSERIAL_HANDFLOW)Irp->AssociatedIrp.SystemBuffer; 
				HandFlow->ControlHandShake	= deviceExtension->HandFlow.ControlHandShake; 
				HandFlow->FlowReplace		= deviceExtension->HandFlow.FlowReplace; 
				HandFlow->XonLimit			= deviceExtension->HandFlow.XonLimit; 
				HandFlow->XoffLimit			= deviceExtension->HandFlow.XoffLimit; 
				DebugPrint(("ControlHandShake:  %d  FlowReplace:  %d  XonLimit:  %d  XoffLimit:  %d\n", HandFlow->ControlHandShake, HandFlow->FlowReplace, HandFlow->XonLimit, HandFlow->XoffLimit)); 
				info = sizeof(SERIAL_HANDFLOW); 
				status = STATUS_SUCCESS; 
				break; 
			} 
		case IOCTL_SERIAL_SET_HANDFLOW: 
			{ 
	            PSERIAL_HANDFLOW HandFlow = Irp->AssociatedIrp.SystemBuffer; 
				if ( IrpStack->Parameters.DeviceIoControl.InputBufferLength < 
					sizeof(SERIAL_HANDFLOW)) { 
					status = STATUS_BUFFER_TOO_SMALL; 
					break; 
				} 
				DebugPrint(("--  IOCTL_SERIAL_SET_HANDFLOW   --\n")); 
				 
				if (HandFlow->ControlHandShake & SERIAL_CONTROL_INVALID) { 
					status = STATUS_INVALID_PARAMETER; 
					break; 
				} 
				if (HandFlow->FlowReplace & SERIAL_FLOW_INVALID) { 
					status = STATUS_INVALID_PARAMETER; 
					break; 
				} 
				if ((HandFlow->ControlHandShake & SERIAL_DTR_MASK) == 
					SERIAL_DTR_MASK) { 
					status = STATUS_INVALID_PARAMETER; 
					break; 
				} 
				if ((HandFlow->XonLimit < 0) || 
					((ULONG)HandFlow->XonLimit > deviceExtension->BufferSize)) { 
					DebugPrint(("XonLimit( %d ) > BufferSize\n", ((ULONG)HandFlow->XonLimit ))); 
					status = STATUS_INVALID_PARAMETER; 
					break; 
				} 
				if ((HandFlow->XoffLimit < 0) || 
					((ULONG)HandFlow->XoffLimit > deviceExtension->BufferSize)) { 
					DebugPrint(("XoffLimit( %d ) > BufferSize\n", ((ULONG)HandFlow->XoffLimit ))); 
					status = STATUS_INVALID_PARAMETER; 
					break; 
				} 
				deviceExtension->HandFlow.ControlHandShake	= HandFlow->ControlHandShake; 
				deviceExtension->HandFlow.FlowReplace		= HandFlow->FlowReplace; 
				deviceExtension->HandFlow.XonLimit			= HandFlow->XonLimit; 
				deviceExtension->HandFlow.XoffLimit			= HandFlow->XoffLimit; 
				DebugPrint(("Set_HandFlow OK\n")); 
				status = STATUS_SUCCESS; 
				break; 
			} 
		case IOCTL_SERIAL_GET_MODEMSTATUS: 
			DebugPrint(("--  IOCTL_SERIAL_GET_MODEMSTATUS   --\n")); 
			break; 
		case IOCTL_SERIAL_GET_DTRRTS: 
			DebugPrint(("--  IOCTL_SERIAL_GET_DTRRTS   --\n")); 
			break; 
		case IOCTL_SERIAL_GET_COMMSTATUS: 
			DebugPrint(("--  IOCTL_SERIAL_GET_COMMSTATUS   --\n")); 
			break; 
		case IOCTL_SERIAL_GET_PROPERTIES: 
			DebugPrint(("--  IOCTL_SERIAL_GET_PROPERTIES   --\n")); 
			break; 
		case IOCTL_SERIAL_XOFF_COUNTER: 
			DebugPrint(("--  IOCTL_SERIAL_XOFF_COUNTER   --\n")); 
			break; 
		case IOCTL_SERIAL_LSRMST_INSERT: 
			DebugPrint(("--  IOCTL_SERIAL_LSRMST_INSERT   --\n")); 
			break; 
		case IOCTL_SERIAL_CONFIG_SIZE: 
			{ 
				DebugPrint(("--  IOCTL_SERIAL_CONFIG_SIZE   --\n")); 
				if( IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof( ULONG ) ){ 
					status = STATUS_BUFFER_TOO_SMALL; 
					break; 
				} 
				 
				info = sizeof( ULONG ); 
				*(PULONG)Irp->AssociatedIrp.SystemBuffer = 0; 
				status = STATUS_SUCCESS; 
				break; 
			} 
		case IOCTL_SERIAL_GET_STATS: 
			DebugPrint(("--  IOCTL_SERIAL_GET_STATS   --\n")); 
			break; 
		case IOCTL_SERIAL_CLEAR_STATS: 
			DebugPrint(("--  IOCTL_SERIAL_CLEAR_STATS   --\n")); 
			break; 
		default: 
			break; 
	} 
	return CompleteRequest(Irp, status, info); 
} 
VOID 
RequestPurgeIrpQueue( 
	IN PDEVICE_OBJECT	DeviceObject, 
	IN PLIST_ENTRY		QueueToProcess 
	) 
/*++ 
Routine Description: 
 
Arguments: 
 
    DeviceObject - Pointer to deviceobject 
    Irp          - Pointer to a PnP Irp. 
 
Return Value: 
 
    NT Status is returned. 
--*/ 
{ 
	PDEVICE_EXTENSION	deviceExtension; 
	PLIST_ENTRY			link; 
	PIRP				pendingIrp; 
 
	DebugPrint(("Enter RequestPurgeIrpQueue routine...\n")); 
	deviceExtension = ( PDEVICE_EXTENSION )DeviceObject->DeviceExtension; 
	link = ExInterlockedRemoveHeadList( QueueToProcess, &deviceExtension->CancelSpinLock ); 
	while( link ){ 
		pendingIrp = CONTAINING_RECORD( link, IRP, Tail.Overlay.ListEntry ); 
		ASSERT( pendingIrp ); 
		pendingIrp->IoStatus.Status = STATUS_CANCELLED; 
		pendingIrp->IoStatus.Information = 0; 
		IoCompleteRequest( pendingIrp, IO_NO_INCREMENT ); 
		link = ExInterlockedRemoveHeadList( QueueToProcess, &deviceExtension->CancelSpinLock ); 
	} 
	return; 
} 
VOID 
RequestCancelReadRoutine( 
	IN PDEVICE_OBJECT	DeviceObject, 
	IN PIRP				Irp 
	) 
/*++ 
Routine Description: 
 
Arguments: 
 
    DeviceObject - Pointer to deviceobject 
    Irp          - Pointer to a PnP Irp. 
 
Return Value: 
 
    NT Status is returned. 
--*/ 
{ 
	BOOLEAN				bRet; 
	PDEVICE_EXTENSION	deviceExtension; 
	DebugPrint(("Enter RequestCancelRead routine...\n")); 
	deviceExtension = ( PDEVICE_EXTENSION )DeviceObject->DeviceExtension; 
 
	bRet = RequestCancelRoutine( &deviceExtension->ReadIrpQueue, &deviceExtension->CancelSpinLock, Irp ); 
	return; 
} 
VOID 
RequestCancelWriteRoutine( 
	IN PDEVICE_OBJECT	DeviceObject, 
	IN PIRP				Irp 
	) 
/*++ 
Routine Description: 
 
Arguments: 
 
    DeviceObject - Pointer to deviceobject 
    Irp          - Pointer to a PnP Irp. 
 
Return Value: 
 
    NT Status is returned. 
--*/ 
{ 
	BOOLEAN				bRet; 
	PDEVICE_EXTENSION	deviceExtension; 
	DebugPrint(("Enter RequestCancelRead routine...\n")); 
	deviceExtension = ( PDEVICE_EXTENSION )DeviceObject->DeviceExtension; 
 
	bRet = RequestCancelRoutine( &deviceExtension->WriteIrpQueue, &deviceExtension->CancelSpinLock, Irp ); 
	return; 
} 
VOID 
RequestCancelMaskRoutine( 
	IN PDEVICE_OBJECT	DeviceObject, 
	IN PIRP				Irp 
	) 
/*++ 
Routine Description: 
 
Arguments: 
 
    DeviceObject - Pointer to deviceobject 
    Irp          - Pointer to a PnP Irp. 
 
Return Value: 
 
    NT Status is returned. 
--*/ 
{ 
	PDEVICE_EXTENSION	deviceExtension; 
	DebugPrint(("Enter RequestCancelRead routine...\n")); 
	deviceExtension = ( PDEVICE_EXTENSION )DeviceObject->DeviceExtension; 
 
	ASSERT( deviceExtension->bIsWaitOnMask && ( deviceExtension->WaitOnMaskIrp != NULL ) ); 
	CompleteRequest( deviceExtension->WaitOnMaskIrp, STATUS_CANCELLED, 0 ); 
	deviceExtension->WaitOnMaskIrp = NULL; 
	deviceExtension->bIsWaitOnMask = FALSE; 
	return; 
} 
BOOLEAN 
RequestCancelRoutine( 
	IN PLIST_ENTRY		QueueToProcess, 
	IN PKSPIN_LOCK		CancelSpinLock, 
	IN PIRP				Irp) 
/*++ 
Routine Description: 
	A cancel routine for use when cancelling the pending IRP 
 
Arguments: 
	QueueToProcess	- The queue to be processing 
	CancelSpinLock	- Cancel spin lock 
    Irp				- Pointer to a PnP Irp. 
 
Return Value: 
 
    NT Status is returned. 
	If the Irp is in the QueueToProcess, we cancel the irp and return TRUE; else return FALSE. 
--*/ 
{ 
	PLIST_ENTRY			link; 
	PIRP				pendingIrp; 
	PIRP				IrpToComplete; 
	KIRQL				oldIrpl; 
 
	DebugPrint(("Enter RequestCancel routine...\n")); 
 
	IrpToComplete = NULL; 
	// Find the Irp in the QueueToProcess 
	KeAcquireSpinLock( CancelSpinLock, &oldIrpl ); 
	for( link = QueueToProcess->Flink; link != QueueToProcess; link = link->Flink ) 
	{ 
		pendingIrp = CONTAINING_RECORD( link, IRP, Tail.Overlay.ListEntry ); 
		ASSERT( pendingIrp ); 
		if( pendingIrp == Irp ){ 
			DebugPrint(("Find out the pending irp, to remove...\n")); 
			RemoveEntryList( link ); 
			IrpToComplete = pendingIrp; 
			break; 
		} 
	} 
	KeReleaseSpinLock( CancelSpinLock, oldIrpl ); 
	if( IrpToComplete ){ 
		// If we find out the Irp, cancel the Irp 
		DebugPrint(("Cancelled Irp\n")); 
		IrpToComplete->IoStatus.Status = STATUS_CANCELLED; 
		IrpToComplete->IoStatus.Information = 0; 
		IoCompleteRequest( IrpToComplete, IO_NO_INCREMENT ); 
		return TRUE; 
	}else 
		return FALSE; 
} 
NTSTATUS Disconnect(	IN PDEVICE_EXTENSION deviceExtension ) 
/*++ 
Routine Description: 
	disconnect two virtual devices which are connected before 
Arguments: 
 
	deviceExtension	- Pointer to device extension 
 
Return Value: 
 
    NT Status is returned. 
--*/ 
{ 
	PDEVICE_EXTENSION	remoteDevExt; 
	KIRQL				OldIrql; 
 
	KeAcquireSpinLock( &gSpinLock, &OldIrql ); 
	if( !deviceExtension->bIsConnected ){ 
		KeReleaseSpinLock(&gSpinLock, OldIrql ); 
		return STATUS_INVALID_DEVICE_REQUEST; 
	} 
	remoteDevExt = gDeviceArray[ deviceExtension->remoteInstance ].deviceExtension; 
	deviceExtension->remoteInstance = INVALID_INSTANCE; 
	deviceExtension->bIsConnected = FALSE; 
	remoteDevExt->remoteInstance = INVALID_INSTANCE; 
	remoteDevExt->bIsConnected = FALSE; 
	KeReleaseSpinLock( &gSpinLock, OldIrql ); 
 
	return STATUS_SUCCESS; 
} 
VOID 
RequestPurgeDataQueue( 
	IN PDEVICE_OBJECT	DeviceObject, 
	IN PLIST_ENTRY		QueueToProcess 
	) 
{ 
	PDEVICE_EXTENSION	deviceExtension; 
	PLIST_ENTRY			link; 
	PPACKET				lpPacket; 
 
	DebugPrint(("Enter RequestPurgeDataQueue routine...\n")); 
	deviceExtension = ( PDEVICE_EXTENSION )DeviceObject->DeviceExtension; 
	while( link = ExInterlockedRemoveHeadList( QueueToProcess, &deviceExtension->ReadQueueSpinLock )){ 
		lpPacket = CONTAINING_RECORD( link, PACKET, ListEntry ); 
		RtlZeroMemory( lpPacket, sizeof( PACKET ) ); 
		ExInterlockedInsertTailList( &gIdleQueue, &( lpPacket->ListEntry ), &gPoolSpinLock ); 
	} 
}