Beispiel #1
0
void dc_dbg_init()
{
#ifdef DBG_COM
	u32 divisor;
	u8  lcr;
	/* set baud rate and data format (8N1) */
	/*  turn on DTR and RTS  */
    WRITE_PORT_UCHAR(pv(SER_MCR(COM_BASE)), SR_MCR_DTR | SR_MCR_RTS);

	/* set DLAB */
    lcr = READ_PORT_UCHAR(pv(SER_LCR(COM_BASE))) | SR_LCR_DLAB;
    WRITE_PORT_UCHAR(pv(SER_LCR(COM_BASE)), lcr);

	/* set baud rate */
    divisor = 115200 / DEFAULT_BAUD_RATE;
    WRITE_PORT_UCHAR(pv(SER_DLL(COM_BASE)), divisor & 0xff);
    WRITE_PORT_UCHAR(pv(SER_DLM(COM_BASE)), (divisor >> 8) & 0xff);

	/* reset DLAB and set 8N1 format */
    WRITE_PORT_UCHAR(pv(SER_LCR(COM_BASE)), 
		SR_LCR_CS8 | SR_LCR_ST1 | SR_LCR_PNO);

	/* read junk out of the RBR */
	READ_PORT_UCHAR(pv(SER_RBR(COM_BASE)));
#endif /* DBG_COM */

#ifdef DBG_HAL_DISPLAY
	InbvAcquireDisplayOwnership();
	InbvEnableDisplayString(TRUE);
#endif /* DBG_HAL_DISPLAY */
}
Beispiel #2
0
NTSTATUS NTAPI
SerialDeviceControl(
	IN PDEVICE_OBJECT DeviceObject,
	IN PIRP Irp)
{
	PIO_STACK_LOCATION Stack;
	ULONG IoControlCode;
	PSERIAL_DEVICE_EXTENSION DeviceExtension;
	ULONG LengthIn, LengthOut;
	ULONG_PTR Information = 0;
	PVOID BufferIn, BufferOut;
	PUCHAR ComPortBase;
	NTSTATUS Status;

	TRACE_(SERIAL, "IRP_MJ_DEVICE_CONTROL dispatch\n");

	Stack = IoGetCurrentIrpStackLocation(Irp);
	LengthIn = Stack->Parameters.DeviceIoControl.InputBufferLength;
	LengthOut = Stack->Parameters.DeviceIoControl.OutputBufferLength;
	DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
	ComPortBase = ULongToPtr(DeviceExtension->BaseAddress);
	IoControlCode = Stack->Parameters.DeviceIoControl.IoControlCode;
	SerialGetUserBuffers(Irp, IoControlCode, &BufferIn, &BufferOut);

	/* FIXME: need to probe buffers */
	/* FIXME: see http://www.osronline.com/ddkx/serial/serref_61bm.htm */
	switch (IoControlCode)
	{
		case IOCTL_SERIAL_CLEAR_STATS:
		{
			TRACE_(SERIAL, "IOCTL_SERIAL_CLEAR_STATS\n");
			KeSynchronizeExecution(
				DeviceExtension->Interrupt,
				(PKSYNCHRONIZE_ROUTINE)SerialClearPerfStats,
				DeviceExtension);
			Status = STATUS_SUCCESS;
			break;
		}
		case IOCTL_SERIAL_CLR_DTR:
		{
			TRACE_(SERIAL, "IOCTL_SERIAL_CLR_DTR\n");
			/* FIXME: If the handshake flow control of the device is configured to
			 * automatically use DTR, return STATUS_INVALID_PARAMETER */
			Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
			if (NT_SUCCESS(Status))
			{
				DeviceExtension->MCR &= ~SR_MCR_DTR;
				WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR);
				IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
			}
			break;
		}
		case IOCTL_SERIAL_CLR_RTS:
		{
			TRACE_(SERIAL, "IOCTL_SERIAL_CLR_RTS\n");
			/* FIXME: If the handshake flow control of the device is configured to
			 * automatically use RTS, return STATUS_INVALID_PARAMETER */
			Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
			if (NT_SUCCESS(Status))
			{
				DeviceExtension->MCR &= ~SR_MCR_RTS;
				WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR);
				IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
			}
			break;
		}
		case IOCTL_SERIAL_CONFIG_SIZE:
		{
			/* Obsolete on Microsoft Windows 2000+ */
			PULONG pConfigSize;
			TRACE_(SERIAL, "IOCTL_SERIAL_CONFIG_SIZE\n");
			if (LengthOut != sizeof(ULONG) || BufferOut == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
			{
				pConfigSize = (PULONG)BufferOut;
				*pConfigSize = 0;
				Information = sizeof(ULONG);
				Status = STATUS_SUCCESS;
			}
			break;
		}
		case IOCTL_SERIAL_GET_BAUD_RATE:
		{
			TRACE_(SERIAL, "IOCTL_SERIAL_GET_BAUD_RATE\n");
			if (LengthOut < sizeof(SERIAL_BAUD_RATE))
				Status = STATUS_BUFFER_TOO_SMALL;
			else if (BufferOut == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
			{
				((PSERIAL_BAUD_RATE)BufferOut)->BaudRate = DeviceExtension->BaudRate;
				Information = sizeof(SERIAL_BAUD_RATE);
				Status = STATUS_SUCCESS;
			}
			break;
		}
		case IOCTL_SERIAL_GET_CHARS:
		{
			/* FIXME */
			PSERIAL_CHARS pSerialChars;
			ERR_(SERIAL, "IOCTL_SERIAL_GET_CHARS not implemented.\n");
			if (LengthOut < sizeof(SERIAL_CHARS))
				Status = STATUS_BUFFER_TOO_SMALL;
			else if (BufferOut == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
			{
				pSerialChars = (PSERIAL_CHARS)BufferOut;
				pSerialChars->EofChar = 0;
				pSerialChars->ErrorChar = 0;
				pSerialChars->BreakChar = 0;
				pSerialChars->EventChar = 0;
				pSerialChars->XonChar = 0;
				pSerialChars->XoffChar = 0;
				Information = sizeof(SERIAL_CHARS);
				Status = STATUS_SUCCESS;
			}
			break;
		}
		case IOCTL_SERIAL_GET_COMMSTATUS:
		{
			TRACE_(SERIAL, "IOCTL_SERIAL_GET_COMMSTATUS\n");
			if (LengthOut < sizeof(SERIAL_STATUS))
				Status = STATUS_BUFFER_TOO_SMALL;
			else if (BufferOut == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
			{
				Status = SerialGetCommStatus((PSERIAL_STATUS)BufferOut, DeviceExtension);
				Information = sizeof(SERIAL_STATUS);
			}
			break;
		}
		case IOCTL_SERIAL_GET_DTRRTS:
		{
			PULONG pDtrRts;
			TRACE_(SERIAL, "IOCTL_SERIAL_GET_DTRRTS\n");
			if (LengthOut != sizeof(ULONG) || BufferOut == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
			{
				pDtrRts = (PULONG)BufferOut;
				*pDtrRts = 0;
				if (DeviceExtension->MCR & SR_MCR_DTR)
					*pDtrRts |= SERIAL_DTR_STATE;
				if (DeviceExtension->MCR & SR_MCR_RTS)
					*pDtrRts |= SERIAL_RTS_STATE;
				Information = sizeof(ULONG);
				Status = STATUS_SUCCESS;
			}
			break;
		}
		case IOCTL_SERIAL_GET_HANDFLOW:
		{
			/* FIXME */
			PSERIAL_HANDFLOW pSerialHandflow;
			ERR_(SERIAL, "IOCTL_SERIAL_GET_HANDFLOW not implemented.\n");
			if (LengthOut < sizeof(SERIAL_HANDFLOW))
				Status = STATUS_BUFFER_TOO_SMALL;
			else if (BufferOut == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
			{
				pSerialHandflow = (PSERIAL_HANDFLOW)BufferOut;
				pSerialHandflow->ControlHandShake = 0;
				pSerialHandflow->FlowReplace = 0;
				pSerialHandflow->XonLimit = 0;
				pSerialHandflow->XoffLimit = 0;
				Information = sizeof(SERIAL_HANDFLOW);
				Status = STATUS_SUCCESS;
			}
			break;
		}
		case IOCTL_SERIAL_GET_LINE_CONTROL:
		{
			TRACE_(SERIAL, "IOCTL_SERIAL_GET_LINE_CONTROL\n");
			if (LengthOut < sizeof(SERIAL_LINE_CONTROL))
				Status = STATUS_BUFFER_TOO_SMALL;
			else if (BufferOut == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
			{
				*((PSERIAL_LINE_CONTROL)BufferOut) = DeviceExtension->SerialLineControl;
				Information = sizeof(SERIAL_LINE_CONTROL);
				Status = STATUS_SUCCESS;
			}
			break;
		}
		case IOCTL_SERIAL_GET_MODEM_CONTROL:
		{
			PULONG pMCR;
			TRACE_(SERIAL, "IOCTL_SERIAL_GET_MODEM_CONTROL\n");
			if (LengthOut != sizeof(ULONG) || BufferOut == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
			{
				pMCR = (PULONG)BufferOut;
				*pMCR = DeviceExtension->MCR;
				Information = sizeof(ULONG);
				Status = STATUS_SUCCESS;
			}
			break;
		}
		case IOCTL_SERIAL_GET_MODEMSTATUS:
		{
			PULONG pMSR;
			TRACE_(SERIAL, "IOCTL_SERIAL_GET_MODEMSTATUS\n");
			if (LengthOut != sizeof(ULONG) || BufferOut == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
			{
				pMSR = (PULONG)BufferOut;
				*pMSR = DeviceExtension->MSR;
				Information = sizeof(ULONG);
				Status = STATUS_SUCCESS;
			}
			break;
		}
		case IOCTL_SERIAL_GET_PROPERTIES:
		{
			TRACE_(SERIAL, "IOCTL_SERIAL_GET_PROPERTIES\n");
			if (LengthOut < sizeof(SERIAL_COMMPROP))
				Status = STATUS_BUFFER_TOO_SMALL;
			else if (BufferOut == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
			{
				Status = SerialGetCommProp((PSERIAL_COMMPROP)BufferOut, DeviceExtension);
				Information = sizeof(SERIAL_COMMPROP);
			}
			break;
		}
		case IOCTL_SERIAL_GET_STATS:
		{
			TRACE_(SERIAL, "IOCTL_SERIAL_GET_STATS\n");
			if (LengthOut < sizeof(SERIALPERF_STATS))
				Status = STATUS_BUFFER_TOO_SMALL;
			else if (BufferOut == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
			{
				KeSynchronizeExecution(DeviceExtension->Interrupt,
					(PKSYNCHRONIZE_ROUTINE)SerialGetPerfStats, Irp);
				Information = sizeof(SERIALPERF_STATS);
				Status = STATUS_SUCCESS;
			}
			break;
		}
		case IOCTL_SERIAL_GET_TIMEOUTS:
		{
			TRACE_(SERIAL, "IOCTL_SERIAL_GET_TIMEOUTS\n");
			if (LengthOut != sizeof(SERIAL_TIMEOUTS) || BufferOut == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
			{
				*(PSERIAL_TIMEOUTS)BufferOut = DeviceExtension->SerialTimeOuts;
				Information = sizeof(SERIAL_TIMEOUTS);
				Status = STATUS_SUCCESS;
			}
			break;
		}
		case IOCTL_SERIAL_GET_WAIT_MASK:
		{
			PULONG pWaitMask;
			TRACE_(SERIAL, "IOCTL_SERIAL_GET_WAIT_MASK\n");
			if (LengthOut != sizeof(ULONG) || BufferOut == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
			{
				pWaitMask = (PULONG)BufferOut;
				*pWaitMask = DeviceExtension->WaitMask;
				Information = sizeof(ULONG);
				Status = STATUS_SUCCESS;
			}
			break;
		}
		case IOCTL_SERIAL_IMMEDIATE_CHAR:
		{
			/* FIXME */
			ERR_(SERIAL, "IOCTL_SERIAL_IMMEDIATE_CHAR not implemented.\n");
			Status = STATUS_NOT_IMPLEMENTED;
			break;
		}
		case IOCTL_SERIAL_LSRMST_INSERT:
		{
			/* FIXME */
			ERR_(SERIAL, "IOCTL_SERIAL_LSRMST_INSERT not implemented.\n");
			Status = STATUS_NOT_IMPLEMENTED;
			break;
		}
		case IOCTL_SERIAL_PURGE:
		{
			KIRQL Irql;
			TRACE_(SERIAL, "IOCTL_SERIAL_PURGE\n");
			/* FIXME: SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT
			 * should stop current request */
			if (LengthIn != sizeof(ULONG) || BufferIn == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
			{
				ULONG PurgeMask = *(PULONG)BufferIn;

				Status = STATUS_SUCCESS;
				/* FIXME: use SERIAL_PURGE_RXABORT and SERIAL_PURGE_TXABORT flags */
				if (PurgeMask & SERIAL_PURGE_RXCLEAR)
				{
					KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql);
					DeviceExtension->InputBuffer.ReadPosition = DeviceExtension->InputBuffer.WritePosition = 0;
					if (DeviceExtension->UartType >= Uart16550A)
					{
						/* Clear also Uart FIFO */
						Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
						if (NT_SUCCESS(Status))
						{
							WRITE_PORT_UCHAR(SER_FCR(ComPortBase), SR_FCR_CLEAR_RCVR);
							IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
						}
					}
					KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql);
				}

				if (PurgeMask & SERIAL_PURGE_TXCLEAR)
				{
					KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql);
					DeviceExtension->OutputBuffer.ReadPosition = DeviceExtension->OutputBuffer.WritePosition = 0;
					if (DeviceExtension->UartType >= Uart16550A)
					{
						/* Clear also Uart FIFO */
						Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
						if (NT_SUCCESS(Status))
						{
							WRITE_PORT_UCHAR(SER_FCR(ComPortBase), SR_FCR_CLEAR_XMIT);
							IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
						}
					}
					KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
				}
			}
			break;
		}
		case IOCTL_SERIAL_RESET_DEVICE:
		{
			/* FIXME */
			ERR_(SERIAL, "IOCTL_SERIAL_RESET_DEVICE not implemented.\n");
			Status = STATUS_NOT_IMPLEMENTED;
			break;
		}
		case IOCTL_SERIAL_SET_BAUD_RATE:
		{
			PULONG pNewBaudRate;
			TRACE_(SERIAL, "IOCTL_SERIAL_SET_BAUD_RATE\n");
			if (LengthIn != sizeof(ULONG) || BufferIn == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
			{
				pNewBaudRate = (PULONG)BufferIn;
				Status = SerialSetBaudRate(DeviceExtension, *pNewBaudRate);
			}
			break;
		}
		case IOCTL_SERIAL_SET_BREAK_OFF:
		{
			/* FIXME */
			ERR_(SERIAL, "IOCTL_SERIAL_SET_BREAK_OFF not implemented.\n");
			Status = STATUS_NOT_IMPLEMENTED;
			break;
		}
		case IOCTL_SERIAL_SET_BREAK_ON:
		{
			/* FIXME */
			ERR_(SERIAL, "IOCTL_SERIAL_SET_BREAK_ON not implemented.\n");
			Status = STATUS_NOT_IMPLEMENTED;
			break;
		}
		case IOCTL_SERIAL_SET_CHARS:
		{
			/* FIXME */
			ERR_(SERIAL, "IOCTL_SERIAL_SET_CHARS not implemented.\n");
			Status = STATUS_SUCCESS;
			break;
		}
		case IOCTL_SERIAL_SET_DTR:
		{
			/* FIXME: If the handshake flow control of the device is configured to
			 * automatically use DTR, return STATUS_INVALID_PARAMETER */
			TRACE_(SERIAL, "IOCTL_SERIAL_SET_DTR\n");
			if (!(DeviceExtension->MCR & SR_MCR_DTR))
			{
				Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
				if (NT_SUCCESS(Status))
				{
					DeviceExtension->MCR |= SR_MCR_DTR;
					WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR);
					IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
				}
			}
			else
				Status = STATUS_SUCCESS;
			break;
		}
		case IOCTL_SERIAL_SET_FIFO_CONTROL:
		{
			TRACE_(SERIAL, "IOCTL_SERIAL_SET_FIFO_CONTROL\n");
			if (LengthIn != sizeof(ULONG) || BufferIn == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
			{
				Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
				if (NT_SUCCESS(Status))
				{
					WRITE_PORT_UCHAR(SER_FCR(ComPortBase), (UCHAR)((*(PULONG)BufferIn) & 0xff));
					IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
				}
			}
			break;
		}
		case IOCTL_SERIAL_SET_HANDFLOW:
		{
			/* FIXME */
			ERR_(SERIAL, "IOCTL_SERIAL_SET_HANDFLOW not implemented.\n");
			Status = STATUS_SUCCESS;
			break;
		}
		case IOCTL_SERIAL_SET_LINE_CONTROL:
		{
			TRACE_(SERIAL, "IOCTL_SERIAL_SET_LINE_CONTROL\n");
			if (LengthIn < sizeof(SERIAL_LINE_CONTROL))
				Status = STATUS_BUFFER_TOO_SMALL;
			else if (BufferIn == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
				Status = SerialSetLineControl(DeviceExtension, (PSERIAL_LINE_CONTROL)BufferIn);
			break;
		}
		case IOCTL_SERIAL_SET_MODEM_CONTROL:
		{
			PULONG pMCR;
			TRACE_(SERIAL, "IOCTL_SERIAL_SET_MODEM_CONTROL\n");
			if (LengthIn != sizeof(ULONG) || BufferIn == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
			{
				Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
				if (NT_SUCCESS(Status))
				{
					pMCR = (PULONG)BufferIn;
					DeviceExtension->MCR = (UCHAR)(*pMCR & 0xff);
					WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR);
					IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
				}
			}
			break;
		}
		case IOCTL_SERIAL_SET_QUEUE_SIZE:
		{
			if (LengthIn < sizeof(SERIAL_QUEUE_SIZE ))
				return STATUS_BUFFER_TOO_SMALL;
			else if (BufferIn == NULL)
				return STATUS_INVALID_PARAMETER;
			else
			{
				KIRQL Irql;
				PSERIAL_QUEUE_SIZE NewQueueSize = (PSERIAL_QUEUE_SIZE)BufferIn;
				Status = STATUS_SUCCESS;
				if (NewQueueSize->InSize > DeviceExtension->InputBuffer.Length)
				{
					KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql);
					Status = IncreaseCircularBufferSize(&DeviceExtension->InputBuffer, NewQueueSize->InSize);
					KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql);
				}
				if (NT_SUCCESS(Status) && NewQueueSize->OutSize > DeviceExtension->OutputBuffer.Length)
				{
					KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql);
					Status = IncreaseCircularBufferSize(&DeviceExtension->OutputBuffer, NewQueueSize->OutSize);
					KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql);
				}
			}
			break;
		}
		case IOCTL_SERIAL_SET_RTS:
		{
			/* FIXME: If the handshake flow control of the device is configured to
			 * automatically use DTR, return STATUS_INVALID_PARAMETER */
			TRACE_(SERIAL, "IOCTL_SERIAL_SET_RTS\n");
			if (!(DeviceExtension->MCR & SR_MCR_RTS))
			{
				Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
				if (NT_SUCCESS(Status))
				{
					DeviceExtension->MCR |= SR_MCR_RTS;
					WRITE_PORT_UCHAR(SER_MCR(ComPortBase), DeviceExtension->MCR);
					IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort));
				}
			}
			else
				Status = STATUS_SUCCESS;
			break;
		}
		case IOCTL_SERIAL_SET_TIMEOUTS:
		{
			TRACE_(SERIAL, "IOCTL_SERIAL_SET_TIMEOUTS\n");
			if (LengthIn != sizeof(SERIAL_TIMEOUTS) || BufferIn == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
			{
				DeviceExtension->SerialTimeOuts = *(PSERIAL_TIMEOUTS)BufferIn;
				Status = STATUS_SUCCESS;
			}
			break;
		}
		case IOCTL_SERIAL_SET_WAIT_MASK:
		{
			PULONG pWaitMask = (PULONG)BufferIn;
			TRACE_(SERIAL, "IOCTL_SERIAL_SET_WAIT_MASK\n");

			if (LengthIn != sizeof(ULONG) || BufferIn == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else if (DeviceExtension->WaitOnMaskIrp) /* FIXME: Race condition ; field may be currently in modification */
			{
				WARN_(SERIAL, "An IRP is already currently processed\n");
				Status = STATUS_INVALID_PARAMETER;
			}
			else
			{
				DeviceExtension->WaitMask = *pWaitMask;
				Status = STATUS_SUCCESS;
			}
			break;
		}
		case IOCTL_SERIAL_SET_XOFF:
		{
			/* FIXME */
			ERR_(SERIAL, "IOCTL_SERIAL_SET_XOFF not implemented.\n");
			Status = STATUS_NOT_IMPLEMENTED;
			break;
		}
		case IOCTL_SERIAL_SET_XON:
		{
			/* FIXME */
			ERR_(SERIAL, "IOCTL_SERIAL_SET_XON not implemented.\n");
			Status = STATUS_NOT_IMPLEMENTED;
			break;
		}
		case IOCTL_SERIAL_WAIT_ON_MASK:
		{
			PIRP WaitingIrp;
			TRACE_(SERIAL, "IOCTL_SERIAL_WAIT_ON_MASK\n");

			if (LengthOut != sizeof(ULONG) || BufferOut == NULL)
				Status = STATUS_INVALID_PARAMETER;
			else
			{
				IoMarkIrpPending(Irp);

				WaitingIrp = InterlockedCompareExchangePointer(
					&DeviceExtension->WaitOnMaskIrp,
					Irp,
					NULL);

				/* Check if an Irp is already pending */
				if (WaitingIrp != NULL)
				{
					/* Unable to have a 2nd pending IRP for this IOCTL */
					WARN_(SERIAL, "Unable to pend a second IRP for IOCTL_SERIAL_WAIT_ON_MASK\n");
					Irp->IoStatus.Information = 0;
					Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
					IoCompleteRequest(Irp, IO_NO_INCREMENT);
				}
				return STATUS_PENDING;
			}
			break;
		}
		case IOCTL_SERIAL_XOFF_COUNTER:
		{
			/* FIXME */
			ERR_(SERIAL, "IOCTL_SERIAL_XOFF_COUNTER not implemented.\n");
			Status = STATUS_NOT_IMPLEMENTED;
			break;
		}
		default:
		{
			/* Pass Irp to lower driver */
			TRACE_(SERIAL, "Unknown IOCTL code 0x%x\n", Stack->Parameters.DeviceIoControl.IoControlCode);
			IoSkipCurrentIrpStackLocation(Irp);
			return IoCallDriver(DeviceExtension->LowerDevice, Irp);
		}
	}

	Irp->IoStatus.Status = Status;
	if (Status == STATUS_PENDING)
	{
		IoMarkIrpPending(Irp);
	}
	else
	{
		Irp->IoStatus.Information = Information;
		IoCompleteRequest(Irp, IO_NO_INCREMENT);
	}
	return Status;
}
Beispiel #3
0
UART_TYPE
SerialDetectUartType(
	IN PUCHAR BaseAddress)
{
	UCHAR Lcr, TestLcr;
	UCHAR OldScr, Scr5A, ScrA5;
	BOOLEAN FifoEnabled;
	UCHAR NewFifoStatus;

	Lcr = READ_PORT_UCHAR(SER_LCR(BaseAddress));
	WRITE_PORT_UCHAR(SER_LCR(BaseAddress), Lcr ^ 0xFF);
	TestLcr = READ_PORT_UCHAR(SER_LCR(BaseAddress)) ^ 0xFF;
	WRITE_PORT_UCHAR(SER_LCR(BaseAddress), Lcr);

	/* Accessing the LCR must work for a usable serial port */
	if (TestLcr != Lcr)
		return UartUnknown;

	/* Ensure that all following accesses are done as required */
	READ_PORT_UCHAR(SER_RBR(BaseAddress));
	READ_PORT_UCHAR(SER_IER(BaseAddress));
	READ_PORT_UCHAR(SER_IIR(BaseAddress));
	READ_PORT_UCHAR(SER_LCR(BaseAddress));
	READ_PORT_UCHAR(SER_MCR(BaseAddress));
	READ_PORT_UCHAR(SER_LSR(BaseAddress));
	READ_PORT_UCHAR(SER_MSR(BaseAddress));
	READ_PORT_UCHAR(SER_SCR(BaseAddress));

	/* Test scratch pad */
	OldScr = READ_PORT_UCHAR(SER_SCR(BaseAddress));
	WRITE_PORT_UCHAR(SER_SCR(BaseAddress), 0x5A);
	Scr5A = READ_PORT_UCHAR(SER_SCR(BaseAddress));
	WRITE_PORT_UCHAR(SER_SCR(BaseAddress), 0xA5);
	ScrA5 = READ_PORT_UCHAR(SER_SCR(BaseAddress));
	WRITE_PORT_UCHAR(SER_SCR(BaseAddress), OldScr);

	/* When non-functional, we have a 8250 */
	if (Scr5A != 0x5A || ScrA5 != 0xA5)
		return Uart8250;

	/* Test FIFO type */
	FifoEnabled = (READ_PORT_UCHAR(SER_IIR(BaseAddress)) & 0x80) != 0;
	WRITE_PORT_UCHAR(SER_FCR(BaseAddress), SR_FCR_ENABLE_FIFO);
	NewFifoStatus = READ_PORT_UCHAR(SER_IIR(BaseAddress)) & 0xC0;
	if (!FifoEnabled)
		WRITE_PORT_UCHAR(SER_FCR(BaseAddress), 0);
	switch (NewFifoStatus)
	{
		case 0x00:
			return Uart16450;
		case 0x40:
		case 0x80:
			/* Not sure about this but the documentation says that 0x40
			 * indicates an unusable FIFO but my tests only worked
			 * with 0x80 */
			return Uart16550;
	}

	/* FIFO is only functional for 16550A+ */
	return Uart16550A;
}