windows-nt/Source/XPSP1/NT/net/irda/comm/ircomm/ioctl.c

627 lines
14 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
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;
}