627 lines
14 KiB
C
627 lines
14 KiB
C
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
read.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code that is very specific to initialization
|
|
and unload operations in the irenum driver
|
|
|
|
Author:
|
|
|
|
Brian Lieuallen, 7-13-2000
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History :
|
|
|
|
--*/
|
|
|
|
#include "internal.h"
|
|
#include <ntddmodm.h>
|
|
#include "ircomm.h"
|
|
|
|
VOID
|
|
LockedMemoryCopy(
|
|
PKSPIN_LOCK Lock,
|
|
PVOID Destination,
|
|
PVOID Source,
|
|
ULONG Length
|
|
)
|
|
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
|
|
KeAcquireSpinLock(
|
|
Lock,
|
|
&OldIrql
|
|
);
|
|
|
|
RtlCopyMemory(
|
|
Destination,
|
|
Source,
|
|
Length
|
|
);
|
|
|
|
KeReleaseSpinLock(
|
|
Lock,
|
|
OldIrql
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
LockedZeroMemory(
|
|
PKSPIN_LOCK Lock,
|
|
PVOID Destination,
|
|
ULONG Length
|
|
)
|
|
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
|
|
KeAcquireSpinLock(
|
|
Lock,
|
|
&OldIrql
|
|
);
|
|
|
|
RtlZeroMemory(
|
|
Destination,
|
|
Length
|
|
);
|
|
|
|
KeReleaseSpinLock(
|
|
Lock,
|
|
OldIrql
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IrCommDeviceControl(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp
|
|
)
|
|
|
|
{
|
|
PFDO_DEVICE_EXTENSION DeviceExtension=(PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
PIO_STACK_LOCATION IrpSp=IoGetCurrentIrpStackLocation(Irp);
|
|
NTSTATUS Status=STATUS_SUCCESS;
|
|
|
|
PUCHAR SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
|
|
ULONG InputLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
ULONG OutputLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
|
|
ULONG SizeNeeded;
|
|
|
|
Irp->IoStatus.Information=0;
|
|
|
|
D_TRACE(DbgPrint("IRCOMM: IrCommDeviceControl\n");)
|
|
|
|
if (DeviceExtension->Removing) {
|
|
//
|
|
// the device has been removed, no more irps
|
|
//
|
|
Irp->IoStatus.Status=STATUS_DEVICE_REMOVED;
|
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
|
return STATUS_DEVICE_REMOVED;
|
|
}
|
|
|
|
|
|
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
|
|
|
|
case IOCTL_SERIAL_SET_TIMEOUTS:
|
|
|
|
if (InputLength >= sizeof(SERIAL_TIMEOUTS)) {
|
|
|
|
LockedMemoryCopy(
|
|
&DeviceExtension->SpinLock,
|
|
&DeviceExtension->TimeOuts,
|
|
SystemBuffer,
|
|
sizeof(SERIAL_TIMEOUTS)
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
Status=STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
|
|
case IOCTL_SERIAL_GET_TIMEOUTS:
|
|
|
|
if (OutputLength >= sizeof(SERIAL_TIMEOUTS) ) {
|
|
|
|
LockedMemoryCopy(
|
|
&DeviceExtension->SpinLock,
|
|
SystemBuffer,
|
|
&DeviceExtension->TimeOuts,
|
|
sizeof(SERIAL_TIMEOUTS)
|
|
);
|
|
|
|
Irp->IoStatus.Information=sizeof(SERIAL_TIMEOUTS);
|
|
|
|
break;
|
|
}
|
|
Status=STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
|
|
case IOCTL_SERIAL_SET_QUEUE_SIZE:
|
|
|
|
|
|
if (InputLength >= sizeof( SERIAL_QUEUE_SIZE)) {
|
|
|
|
LockedMemoryCopy(
|
|
&DeviceExtension->SpinLock,
|
|
&DeviceExtension->QueueSizes,
|
|
SystemBuffer,
|
|
sizeof( SERIAL_QUEUE_SIZE)
|
|
);
|
|
|
|
break;
|
|
}
|
|
Status=STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IOCTL_SERIAL_GET_HANDFLOW:
|
|
|
|
SizeNeeded=sizeof(SERIAL_HANDFLOW);
|
|
|
|
if (OutputLength >= SizeNeeded) {
|
|
|
|
LockedMemoryCopy(
|
|
&DeviceExtension->SpinLock,
|
|
SystemBuffer,
|
|
&DeviceExtension->HandFlow,
|
|
SizeNeeded
|
|
);
|
|
|
|
|
|
Irp->IoStatus.Information=SizeNeeded;
|
|
|
|
break;
|
|
}
|
|
|
|
Status=STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
|
|
case IOCTL_SERIAL_SET_HANDFLOW:
|
|
|
|
SizeNeeded=sizeof(SERIAL_HANDFLOW);
|
|
|
|
if (InputLength >= SizeNeeded) {
|
|
|
|
LockedMemoryCopy(
|
|
&DeviceExtension->SpinLock,
|
|
&DeviceExtension->HandFlow,
|
|
SystemBuffer,
|
|
SizeNeeded
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
Status=STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
|
|
|
|
case IOCTL_SERIAL_GET_BAUD_RATE:
|
|
|
|
if (OutputLength >= sizeof(ULONG) ) {
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
QueuePacket(&DeviceExtension->Uart.Queue,Irp,FALSE);
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
Status=STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
|
|
case IOCTL_SERIAL_SET_BAUD_RATE:
|
|
|
|
if (InputLength >= sizeof(ULONG) ) {
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
QueuePacket(&DeviceExtension->Uart.Queue,Irp,FALSE);
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
Status=STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IOCTL_SERIAL_GET_LINE_CONTROL:
|
|
|
|
if (OutputLength >= sizeof(SERIAL_LINE_CONTROL)) {
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
QueuePacket(&DeviceExtension->Uart.Queue,Irp,FALSE);
|
|
|
|
return STATUS_PENDING;
|
|
|
|
}
|
|
Status=STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
|
|
case IOCTL_SERIAL_SET_LINE_CONTROL:
|
|
|
|
if (InputLength >= sizeof(SERIAL_LINE_CONTROL)) {
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
QueuePacket(&DeviceExtension->Uart.Queue,Irp,FALSE);
|
|
|
|
return STATUS_PENDING;
|
|
|
|
}
|
|
Status=STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
|
|
|
|
case IOCTL_SERIAL_GET_CHARS:
|
|
|
|
if (OutputLength >= sizeof(SERIAL_CHARS)) {
|
|
|
|
LockedMemoryCopy(
|
|
&DeviceExtension->SpinLock,
|
|
SystemBuffer,
|
|
&DeviceExtension->SerialChars,
|
|
sizeof(SERIAL_CHARS)
|
|
);
|
|
|
|
Irp->IoStatus.Information=sizeof(SERIAL_CHARS);
|
|
|
|
break;
|
|
}
|
|
Status=STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
|
|
case IOCTL_SERIAL_SET_CHARS:
|
|
|
|
SizeNeeded=sizeof(SERIAL_CHARS);
|
|
|
|
if (InputLength >= SizeNeeded) {
|
|
|
|
LockedMemoryCopy(
|
|
&DeviceExtension->SpinLock,
|
|
&DeviceExtension->SerialChars,
|
|
SystemBuffer,
|
|
SizeNeeded
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
Status=STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
|
|
|
|
case IOCTL_SERIAL_GET_WAIT_MASK:
|
|
case IOCTL_SERIAL_SET_WAIT_MASK:
|
|
case IOCTL_SERIAL_WAIT_ON_MASK:
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
Irp->IoStatus.Information=0;
|
|
|
|
QueuePacket(&DeviceExtension->Mask.Queue,Irp,FALSE);
|
|
|
|
return STATUS_PENDING;
|
|
|
|
|
|
case IOCTL_SERIAL_GET_MODEMSTATUS:
|
|
|
|
if (OutputLength >= sizeof(ULONG)) {
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
QueuePacket(&DeviceExtension->Uart.Queue,Irp,FALSE);
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
Status=STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
|
|
|
|
case IOCTL_SERIAL_PURGE:
|
|
|
|
if (InputLength >= sizeof(ULONG)) {
|
|
|
|
if (*(PULONG)SystemBuffer & SERIAL_PURGE_TXABORT) {
|
|
//
|
|
// we only want to flush the write irps in the queue, not any ioctl's
|
|
//
|
|
FlushQueuedPackets(&DeviceExtension->Write.Queue,IRP_MJ_WRITE);
|
|
AbortSend(DeviceExtension->ConnectionHandle);
|
|
}
|
|
|
|
if (*(PULONG)SystemBuffer & SERIAL_PURGE_RXABORT) {
|
|
|
|
FlushQueuedPackets(&DeviceExtension->Read.Queue,FLUSH_ALL_IRPS);
|
|
|
|
ReadPurge(DeviceExtension,READ_PURGE_ABORT_IRP);
|
|
}
|
|
|
|
if (*(PULONG)SystemBuffer & SERIAL_PURGE_TXCLEAR) {
|
|
|
|
}
|
|
|
|
if (*(PULONG)SystemBuffer & SERIAL_PURGE_RXCLEAR) {
|
|
|
|
ReadPurge(DeviceExtension,READ_PURGE_CLEAR_BUFFER);
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Status=STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
|
|
case IOCTL_SERIAL_SET_DTR:
|
|
case IOCTL_SERIAL_CLR_DTR:
|
|
|
|
DeviceExtension->Read.DtrState= (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_SET_DTR);
|
|
|
|
case IOCTL_SERIAL_SET_RTS:
|
|
case IOCTL_SERIAL_CLR_RTS: {
|
|
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
QueuePacket(&DeviceExtension->Uart.Queue,Irp,FALSE);
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
case IOCTL_SERIAL_GET_DTRRTS:
|
|
|
|
SizeNeeded=sizeof(ULONG);
|
|
|
|
if (OutputLength >= SizeNeeded) {
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
QueuePacket(&DeviceExtension->Uart.Queue,Irp,FALSE);
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
Status=STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
|
|
|
|
case IOCTL_SERIAL_GET_COMMSTATUS:
|
|
|
|
SizeNeeded=sizeof(SERIAL_STATUS);
|
|
|
|
if (OutputLength >= SizeNeeded) {
|
|
|
|
RtlZeroMemory(
|
|
SystemBuffer,
|
|
SizeNeeded
|
|
);
|
|
|
|
LockedMemoryCopy(
|
|
&DeviceExtension->Read.ReadLock,
|
|
&((PSERIAL_STATUS)SystemBuffer)->AmountInInQueue,
|
|
&DeviceExtension->Read.BytesInBuffer,
|
|
sizeof(DeviceExtension->Read.BytesInBuffer)
|
|
);
|
|
|
|
Irp->IoStatus.Information=SizeNeeded;
|
|
|
|
break;
|
|
}
|
|
|
|
Status=STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
|
|
case IOCTL_SERIAL_GET_STATS: {
|
|
|
|
PSERIALPERF_STATS Stats=(PSERIALPERF_STATS)SystemBuffer;
|
|
|
|
SizeNeeded=sizeof(SERIAL_STATUS);
|
|
|
|
if (OutputLength >= SizeNeeded) {
|
|
|
|
RtlZeroMemory(
|
|
Stats,
|
|
OutputLength
|
|
);
|
|
|
|
Stats->TransmittedCount = DeviceExtension->Write.BytesWritten;
|
|
Stats->ReceivedCount = DeviceExtension->Read.BytesRead;
|
|
|
|
Irp->IoStatus.Information=SizeNeeded;
|
|
|
|
break;
|
|
}
|
|
|
|
Status=STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
}
|
|
|
|
case IOCTL_SERIAL_CLEAR_STATS:
|
|
|
|
DeviceExtension->Write.BytesWritten=0;
|
|
DeviceExtension->Read.BytesRead=0;
|
|
|
|
break;
|
|
|
|
|
|
case IOCTL_SERIAL_GET_PROPERTIES: {
|
|
|
|
PSERIAL_COMMPROP SerialProps=(PSERIAL_COMMPROP)SystemBuffer;
|
|
|
|
SizeNeeded=FIELD_OFFSET(SERIAL_COMMPROP,ProvChar);
|
|
|
|
if (OutputLength >= SizeNeeded) {
|
|
|
|
RtlZeroMemory(
|
|
SerialProps,
|
|
OutputLength
|
|
);
|
|
|
|
SerialProps->PacketLength=(USHORT)SizeNeeded;
|
|
SerialProps->PacketVersion=1;
|
|
SerialProps->ServiceMask=SERIAL_SP_SERIALCOMM;
|
|
SerialProps->MaxBaud=115200;
|
|
|
|
SerialProps->ProvSubType=SERIAL_SP_RS232;
|
|
SerialProps->ProvCapabilities=SERIAL_PCF_DTRDSR | SERIAL_PCF_RTSCTS | SERIAL_PCF_CD | SERIAL_PCF_TOTALTIMEOUTS | SERIAL_PCF_INTTIMEOUTS;
|
|
SerialProps->SettableParams=SERIAL_SP_PARITY | SERIAL_SP_BAUD | SERIAL_SP_DATABITS | SERIAL_SP_STOPBITS | SERIAL_SP_HANDSHAKING | SERIAL_SP_CARRIER_DETECT;
|
|
SerialProps->SettableBaud=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;
|
|
|
|
SerialProps->SettableData=SERIAL_DATABITS_7 | SERIAL_DATABITS_8;
|
|
|
|
SerialProps->SettableStopParity = SERIAL_STOPBITS_10 | SERIAL_PARITY_NONE | SERIAL_PARITY_EVEN | SERIAL_PARITY_ODD;
|
|
|
|
Irp->IoStatus.Information=SizeNeeded;
|
|
|
|
break;
|
|
}
|
|
Status=STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
}
|
|
|
|
case IOCTL_SERIAL_CONFIG_SIZE:
|
|
|
|
SizeNeeded=sizeof(ULONG);
|
|
|
|
if (OutputLength >= SizeNeeded) {
|
|
|
|
*(PULONG)SystemBuffer=0;
|
|
|
|
Irp->IoStatus.Information=SizeNeeded;
|
|
|
|
break;
|
|
}
|
|
|
|
Status=STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
|
|
case IOCTL_MODEM_CHECK_FOR_MODEM:
|
|
|
|
Status=STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
DbgPrint("IRCOMM: unhandled ioctl %d \n",(IrpSp->Parameters.DeviceIoControl.IoControlCode >> 2) & 0x3f);
|
|
|
|
Status=STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
Irp->IoStatus.Status=Status;
|
|
|
|
#if DBG
|
|
if (Status == STATUS_INVALID_PARAMETER) {
|
|
|
|
D_ERROR(DbgPrint("IRCOMM: ioctl irp %d bad param, in size=%d, out size=%d\n",
|
|
IrpSp->Parameters.DeviceIoControl.IoControlCode,
|
|
InputLength,
|
|
OutputLength
|
|
);)
|
|
}
|
|
|
|
#endif
|
|
|
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
|
|
|
return STATUS_PENDING;
|
|
|
|
}
|
|
|
|
VOID
|
|
UartComplete(
|
|
PVOID Context,
|
|
PIRP Irp
|
|
)
|
|
|
|
{
|
|
PFDO_DEVICE_EXTENSION DeviceExtension=(PFDO_DEVICE_EXTENSION)Context;
|
|
|
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
|
|
|
StartNextPacket(&DeviceExtension->Uart.Queue);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
UartStartRoutine(
|
|
PVOID Context,
|
|
PIRP Irp
|
|
|
|
)
|
|
|
|
{
|
|
|
|
PFDO_DEVICE_EXTENSION DeviceExtension=(PFDO_DEVICE_EXTENSION)Context;
|
|
PIO_STACK_LOCATION IrpSp=IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
AccessUartState(
|
|
DeviceExtension->ConnectionHandle,
|
|
Irp,
|
|
UartComplete,
|
|
DeviceExtension
|
|
);
|
|
|
|
return;
|
|
|
|
}
|