/*++ 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 #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_TRACE2(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(SERIAL_BAUD_RATE) ) { 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(SERIAL_BAUD_RATE) ) { 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(SERIALPERF_STATS); 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; }