NTSTATUS EvtWmiQueryPortPropData( IN WDFWMIINSTANCE WmiInstance, IN ULONG OutBufferSize, IN PVOID OutBuffer, OUT PULONG BufferUsed ) { PSERIAL_DEVICE_EXTENSION pDevExt; UNREFERENCED_PARAMETER(OutBufferSize); PAGED_CODE(); pDevExt = SerialGetDeviceExtension (WdfWmiInstanceGetDevice(WmiInstance)); *BufferUsed = sizeof(SERIAL_COMMPROP) + sizeof(ULONG); if (OutBufferSize < *BufferUsed) { return STATUS_INSUFFICIENT_RESOURCES; } SerialGetProperties( pDevExt, (PSERIAL_COMMPROP)OutBuffer ); *((PULONG)(((PSERIAL_COMMPROP)OutBuffer)->ProvChar)) = 0; return STATUS_SUCCESS; }
_Use_decl_annotations_ NTSTATUS EvtWmiQueryPortPropData( WDFWMIINSTANCE WmiInstance, ULONG OutBufferSize, PVOID OutBuffer, PULONG BufferUsed ) { PSERIAL_DEVICE_EXTENSION devExt; NTSTATUS status; UNREFERENCED_PARAMETER(OutBufferSize); PAGED_CODE(); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WMI, "++EvtWmiQueryPortPerfData()\r\n"); devExt = SerialGetDeviceExtension(WdfWmiInstanceGetDevice(WmiInstance)); *BufferUsed = sizeof(SERIAL_COMMPROP) + sizeof(ULONG); if (OutBufferSize < *BufferUsed) { status = STATUS_INSUFFICIENT_RESOURCES; } else { SerialGetProperties(devExt, (PSERIAL_COMMPROP)OutBuffer); *((PULONG)(((PSERIAL_COMMPROP)OutBuffer)->ProvChar)) = 0; status = STATUS_SUCCESS; } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WMI, "--EvtWmiQueryPortPerfData()=%Xh\r\n", status); return status; }
NTSTATUS SerialIoControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine provides the initial processing for all of the Ioctrls for the serial device. Arguments: DeviceObject - Pointer to the device object for this device Irp - Pointer to the IRP for the current request Return Value: The function value is the final status of the call --*/ { // // The status that gets returned to the caller and // set in the Irp. // NTSTATUS Status; // // The current stack location. This contains all of the // information we need to process this particular request. // PIO_STACK_LOCATION IrpSp; // // Just what it says. This is the serial specific device // extension of the device object create for the serial driver. // PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension; // // A temporary to hold the old IRQL so that it can be // restored once we complete/validate this request. // KIRQL OldIrql; SerialDump( SERIRPPATH, ("SERIAL: Dispatch entry for: %x\n",Irp) ); if (SerialCompleteIfError( DeviceObject, Irp ) != STATUS_SUCCESS) { return STATUS_CANCELLED; } IrpSp = IoGetCurrentIrpStackLocation(Irp); Irp->IoStatus.Information = 0L; Status = STATUS_SUCCESS; switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_SERIAL_SET_BAUD_RATE : { ULONG BaudRate; // // Will hold the value of the appropriate divisor for // the requested baud rate. If the baudrate is invalid // (because the device won't support that baud rate) then // this value is undefined. // // Note: in one sense the concept of a valid baud rate // is cloudy. We could allow the user to request any // baud rate. We could then calculate the divisor needed // for that baud rate. As long as the divisor wasn't less // than one we would be "ok". (The percentage difference // between the "true" divisor and the "rounded" value given // to the hardware might make it unusable, but... ) It would // really be up to the user to "Know" whether the baud rate // is suitable. So much for theory, *We* only support a given // set of baud rates. // SHORT AppropriateDivisor; if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_BAUD_RATE)) { Status = STATUS_BUFFER_TOO_SMALL; break; } else { BaudRate = ((PSERIAL_BAUD_RATE)(Irp->AssociatedIrp.SystemBuffer))->BaudRate; } // // Get the baud rate from the irp. We pass it // to a routine which will set the correct divisor. // Status = SerialGetDivisorFromBaud( Extension->ClockRate, BaudRate, &AppropriateDivisor ); KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); if (NT_SUCCESS(Status)) { SERIAL_IOCTL_SYNC S; Extension->CurrentBaud = BaudRate; S.Extension = Extension; S.Data = (PVOID)AppropriateDivisor; KeSynchronizeExecution( Extension->Interrupt, SerialSetBaud, &S ); } KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_GET_BAUD_RATE: { PSERIAL_BAUD_RATE Br = (PSERIAL_BAUD_RATE)Irp->AssociatedIrp.SystemBuffer; if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_BAUD_RATE)) { Status = STATUS_BUFFER_TOO_SMALL; break; } KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); Br->BaudRate = Extension->CurrentBaud; KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); Irp->IoStatus.Information = sizeof(SERIAL_BAUD_RATE); break; } case IOCTL_SERIAL_SET_LINE_CONTROL: { // // Points to the line control record in the Irp. // PSERIAL_LINE_CONTROL Lc = ((PSERIAL_LINE_CONTROL)(Irp->AssociatedIrp.SystemBuffer)); UCHAR LData; UCHAR LStop; UCHAR LParity; UCHAR Mask = 0xff; if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_LINE_CONTROL)) { Status = STATUS_BUFFER_TOO_SMALL; break; } switch (Lc->WordLength) { case 5: { LData = SERIAL_5_DATA; Mask = 0x1f; break; } case 6: { LData = SERIAL_6_DATA; Mask = 0x3f; break; } case 7: { LData = SERIAL_7_DATA; Mask = 0x7f; break; } case 8: { LData = SERIAL_8_DATA; break; } default: { Status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; } } switch (Lc->Parity) { case NO_PARITY: { LParity = SERIAL_NONE_PARITY; break; } case EVEN_PARITY: { LParity = SERIAL_EVEN_PARITY; break; } case ODD_PARITY: { LParity = SERIAL_ODD_PARITY; break; } case SPACE_PARITY: { LParity = SERIAL_SPACE_PARITY; break; } case MARK_PARITY: { LParity = SERIAL_MARK_PARITY; break; } default: { Status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; break; } } switch (Lc->StopBits) { case STOP_BIT_1: { LStop = SERIAL_1_STOP; break; } case STOP_BITS_1_5: { if (LData != SERIAL_5_DATA) { Status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; } LStop = SERIAL_1_5_STOP; break; } case STOP_BITS_2: { if (LData == SERIAL_5_DATA) { Status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; } LStop = SERIAL_2_STOP; break; } default: { Status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; } } KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); Extension->LineControl = (UCHAR)((Extension->LineControl & SERIAL_LCR_BREAK) | (LData | LParity | LStop)); Extension->ValidDataMask = Mask; KeSynchronizeExecution( Extension->Interrupt, SerialSetLineControl, Extension ); KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_GET_LINE_CONTROL: { PSERIAL_LINE_CONTROL Lc = (PSERIAL_LINE_CONTROL)Irp->AssociatedIrp.SystemBuffer; if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_LINE_CONTROL)) { Status = STATUS_BUFFER_TOO_SMALL; break; } KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_5_DATA) { Lc->WordLength = 5; } else if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_6_DATA) { Lc->WordLength = 6; } else if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_7_DATA) { Lc->WordLength = 7; } else if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_8_DATA) { Lc->WordLength = 8; } if ((Extension->LineControl & SERIAL_PARITY_MASK) == SERIAL_NONE_PARITY) { Lc->Parity = NO_PARITY; } else if ((Extension->LineControl & SERIAL_PARITY_MASK) == SERIAL_ODD_PARITY) { Lc->Parity = ODD_PARITY; } else if ((Extension->LineControl & SERIAL_PARITY_MASK) == SERIAL_EVEN_PARITY) { Lc->Parity = EVEN_PARITY; } else if ((Extension->LineControl & SERIAL_PARITY_MASK) == SERIAL_MARK_PARITY) { Lc->Parity = MARK_PARITY; } else if ((Extension->LineControl & SERIAL_PARITY_MASK) == SERIAL_SPACE_PARITY) { Lc->Parity = SPACE_PARITY; } if (Extension->LineControl & SERIAL_2_STOP) { if (Lc->WordLength == 5) { Lc->StopBits = STOP_BITS_1_5; } else { Lc->StopBits = STOP_BITS_2; } } else { Lc->StopBits = STOP_BIT_1; } Irp->IoStatus.Information = sizeof(SERIAL_LINE_CONTROL); KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_SET_TIMEOUTS: { PSERIAL_TIMEOUTS NewTimeouts = ((PSERIAL_TIMEOUTS)(Irp->AssociatedIrp.SystemBuffer)); if (IrpSp->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; } KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); Extension->Timeouts.ReadIntervalTimeout = NewTimeouts->ReadIntervalTimeout; Extension->Timeouts.ReadTotalTimeoutMultiplier = NewTimeouts->ReadTotalTimeoutMultiplier; Extension->Timeouts.ReadTotalTimeoutConstant = NewTimeouts->ReadTotalTimeoutConstant; Extension->Timeouts.WriteTotalTimeoutMultiplier = NewTimeouts->WriteTotalTimeoutMultiplier; Extension->Timeouts.WriteTotalTimeoutConstant = NewTimeouts->WriteTotalTimeoutConstant; KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_GET_TIMEOUTS: { if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_TIMEOUTS)) { Status = STATUS_BUFFER_TOO_SMALL; break; } KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); *((PSERIAL_TIMEOUTS)Irp->AssociatedIrp.SystemBuffer) = Extension->Timeouts; Irp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS); KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_SET_CHARS: { SERIAL_IOCTL_SYNC S; PSERIAL_CHARS NewChars = ((PSERIAL_CHARS)(Irp->AssociatedIrp.SystemBuffer)); if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_CHARS)) { Status = STATUS_BUFFER_TOO_SMALL; break; } // // The only thing that can be wrong with the chars // is that the xon and xoff characters are the // same. // #if 0 if (NewChars->XonChar == NewChars->XoffChar) { Status = STATUS_INVALID_PARAMETER; break; } #endif // // We acquire the control lock so that only // one request can GET or SET the characters // at a time. The sets could be synchronized // by the interrupt spinlock, but that wouldn't // prevent multiple gets at the same time. // S.Extension = Extension; S.Data = NewChars; KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); // // Under the protection of the lock, make sure that // the xon and xoff characters aren't the same as // the escape character. // if (Extension->EscapeChar) { if ((Extension->EscapeChar == NewChars->XonChar) || (Extension->EscapeChar == NewChars->XoffChar)) { Status = STATUS_INVALID_PARAMETER; KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } } KeSynchronizeExecution( Extension->Interrupt, SerialSetChars, &S ); KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_GET_CHARS: { if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_CHARS)) { Status = STATUS_BUFFER_TOO_SMALL; break; } KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); *((PSERIAL_CHARS)Irp->AssociatedIrp.SystemBuffer) = Extension->SpecialChars; Irp->IoStatus.Information = sizeof(SERIAL_CHARS); KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_SET_DTR: case IOCTL_SERIAL_CLR_DTR: { // // We acquire the lock so that we can check whether // automatic dtr flow control is enabled. If it is // then we return an error since the app is not allowed // to touch this if it is automatic. // KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); if ((Extension->HandFlow.ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_HANDSHAKE) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; } else { KeSynchronizeExecution( Extension->Interrupt, ((IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_SET_DTR)? (SerialSetDTR):(SerialClrDTR)), Extension ); } KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_RESET_DEVICE: { break; } case IOCTL_SERIAL_SET_RTS: case IOCTL_SERIAL_CLR_RTS: { // // We acquire the lock so that we can check whether // automatic rts flow control or transmit toggleing // is enabled. If it is then we return an error since // the app is not allowed to touch this if it is automatic // or toggling. // KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); if (((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_RTS_HANDSHAKE) || ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE)) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; } else { KeSynchronizeExecution( Extension->Interrupt, ((IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_SET_RTS)? (SerialSetRTS):(SerialClrRTS)), Extension ); } KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_SET_XOFF: { KeSynchronizeExecution( Extension->Interrupt, SerialPretendXoff, Extension ); break; } case IOCTL_SERIAL_SET_XON: { KeSynchronizeExecution( Extension->Interrupt, SerialPretendXon, Extension ); break; } case IOCTL_SERIAL_SET_BREAK_ON: { KeSynchronizeExecution( Extension->Interrupt, SerialTurnOnBreak, Extension ); break; } case IOCTL_SERIAL_SET_BREAK_OFF: { KeSynchronizeExecution( Extension->Interrupt, SerialTurnOffBreak, Extension ); break; } case IOCTL_SERIAL_SET_QUEUE_SIZE: { // // Type ahead buffer is fixed, so we just validate // the the users request is not bigger that our // own internal buffer size. // PSERIAL_QUEUE_SIZE Rs = ((PSERIAL_QUEUE_SIZE)(Irp->AssociatedIrp.SystemBuffer)); if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_QUEUE_SIZE)) { Status = STATUS_BUFFER_TOO_SMALL; break; } // // We have to allocate the memory for the new // buffer while we're still in the context of the // caller. We don't even try to protect this // with a lock because the value could be stale // as soon as we release the lock - The only time // we will know for sure is when we actually try // to do the resize. // if (Rs->InSize <= Extension->BufferSize) { Status = STATUS_SUCCESS; break; } try { IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = ExAllocatePoolWithQuota( NonPagedPool, Rs->InSize ); } except (EXCEPTION_EXECUTE_HANDLER) { IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL; Status = GetExceptionCode(); } if (!IrpSp->Parameters.DeviceIoControl.Type3InputBuffer) { break; } // // Well the data passed was big enough. Do the request. // // There are two reason we place it in the read queue: // // 1) We want to serialize these resize requests so that // they don't contend with each other. // // 2) We want to serialize these requests with reads since // we don't want reads and resizes contending over the // read buffer. // return SerialStartOrQueue( Extension, Irp, &Extension->ReadQueue, &Extension->CurrentReadIrp, SerialStartRead ); break; } case IOCTL_SERIAL_GET_WAIT_MASK: { if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { Status = STATUS_BUFFER_TOO_SMALL; break; } // // Simple scalar read. No reason to acquire a lock. // Irp->IoStatus.Information = sizeof(ULONG); *((ULONG *)Irp->AssociatedIrp.SystemBuffer) = Extension->IsrWaitMask; break; } case IOCTL_SERIAL_SET_WAIT_MASK: { ULONG NewMask; SerialDump( SERDIAG3 | SERIRPPATH, ("SERIAL: In Ioctl processing for set mask\n") ); if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { SerialDump( SERDIAG3, ("SERIAL: Invalid size fo the buffer %d\n", IrpSp->Parameters.DeviceIoControl.InputBufferLength) ); Status = STATUS_BUFFER_TOO_SMALL; break; } else { NewMask = *((ULONG *)Irp->AssociatedIrp.SystemBuffer); } // // Make sure that the mask only contains valid // waitable events. // 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)) { SerialDump( SERDIAG3, ("SERIAL: Unknown mask %x\n",NewMask) ); Status = STATUS_INVALID_PARAMETER; break; } // // Either start this irp or put it on the // queue. // SerialDump( SERDIAG3 | SERIRPPATH, ("SERIAL: Starting or queuing set mask irp %x\n",Irp) ); return SerialStartOrQueue( Extension, Irp, &Extension->MaskQueue, &Extension->CurrentMaskIrp, SerialStartMask ); } case IOCTL_SERIAL_WAIT_ON_MASK: { SerialDump( SERDIAG3 | SERIRPPATH, ("SERIAL: In Ioctl processing for wait mask\n") ); if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { SerialDump( SERDIAG3, ("SERIAL: Invalid size fo the buffer %d\n", IrpSp->Parameters.DeviceIoControl.InputBufferLength) ); Status = STATUS_BUFFER_TOO_SMALL; break; } // // Either start this irp or put it on the // queue. // SerialDump( SERDIAG3 | SERIRPPATH, ("SERIAL: Starting or queuing wait mask irp %x\n",Irp) ); return SerialStartOrQueue( Extension, Irp, &Extension->MaskQueue, &Extension->CurrentMaskIrp, SerialStartMask ); } case IOCTL_SERIAL_IMMEDIATE_CHAR: { KIRQL OldIrql; if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(UCHAR)) { Status = STATUS_BUFFER_TOO_SMALL; break; } IoAcquireCancelSpinLock(&OldIrql); if (Extension->CurrentImmediateIrp) { Status = STATUS_INVALID_PARAMETER; IoReleaseCancelSpinLock(OldIrql); } else { // // We can queue the char. We need to set // a cancel routine because flow control could // keep the char from transmitting. Make sure // that the irp hasn't already been canceled. // if (Irp->Cancel) { IoReleaseCancelSpinLock(OldIrql); Status = STATUS_CANCELLED; } else { Extension->CurrentImmediateIrp = Irp; Extension->TotalCharsQueued++; IoReleaseCancelSpinLock(OldIrql); SerialStartImmediate(Extension); return STATUS_PENDING; } } break; } case IOCTL_SERIAL_PURGE: { ULONG Mask; if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { Status = STATUS_BUFFER_TOO_SMALL; break; } // // Check to make sure that the mask only has // 0 or the other appropriate values. // Mask = *((ULONG *)(Irp->AssociatedIrp.SystemBuffer)); if ((!Mask) || (Mask & (~(SERIAL_PURGE_TXABORT | SERIAL_PURGE_RXABORT | SERIAL_PURGE_TXCLEAR | SERIAL_PURGE_RXCLEAR ) ) )) { Status = STATUS_INVALID_PARAMETER; break; } // // Either start this irp or put it on the // queue. // return SerialStartOrQueue( Extension, Irp, &Extension->PurgeQueue, &Extension->CurrentPurgeIrp, SerialStartPurge ); } case IOCTL_SERIAL_GET_HANDFLOW: { if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_HANDFLOW)) { Status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(SERIAL_HANDFLOW); KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); *((PSERIAL_HANDFLOW)Irp->AssociatedIrp.SystemBuffer) = Extension->HandFlow; KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_SET_HANDFLOW: { SERIAL_IOCTL_SYNC S; PSERIAL_HANDFLOW HandFlow = Irp->AssociatedIrp.SystemBuffer; // // Make sure that the hand shake and control is the // right size. // if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_HANDFLOW)) { Status = STATUS_BUFFER_TOO_SMALL; break; } // // Make sure that there are no invalid bits set in // the control and handshake. // if (HandFlow->ControlHandShake & SERIAL_CONTROL_INVALID) { Status = STATUS_INVALID_PARAMETER; break; } if (HandFlow->FlowReplace & SERIAL_FLOW_INVALID) { Status = STATUS_INVALID_PARAMETER; break; } // // Make sure that the app hasn't set an invlid DTR mode. // if ((HandFlow->ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_MASK) { Status = STATUS_INVALID_PARAMETER; break; } // // Make sure that haven't set totally invalid xon/xoff // limits. // if ((HandFlow->XonLimit < 0) || ((ULONG)HandFlow->XonLimit > Extension->BufferSize)) { Status = STATUS_INVALID_PARAMETER; break; } if ((HandFlow->XoffLimit < 0) || ((ULONG)HandFlow->XoffLimit > Extension->BufferSize)) { Status = STATUS_INVALID_PARAMETER; break; } S.Extension = Extension; S.Data = HandFlow; KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); // // Under the protection of the lock, make sure that // we aren't turning on error replacement when we // are doing line status/modem status insertion. // if (Extension->EscapeChar) { if (HandFlow->FlowReplace & SERIAL_ERROR_CHAR) { Status = STATUS_INVALID_PARAMETER; KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } } KeSynchronizeExecution( Extension->Interrupt, SerialSetHandFlow, &S ); KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_GET_MODEMSTATUS: { SERIAL_IOCTL_SYNC S; if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { Status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(ULONG); S.Extension = Extension; S.Data = Irp->AssociatedIrp.SystemBuffer; KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); KeSynchronizeExecution( Extension->Interrupt, SerialGetModemUpdate, &S ); KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_GET_DTRRTS: { ULONG ModemControl; if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { Status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(ULONG); Irp->IoStatus.Status = STATUS_SUCCESS; // // Reading this hardware has no effect on the device. // ModemControl = READ_MODEM_CONTROL(Extension->Controller); ModemControl &= SERIAL_DTR_STATE | SERIAL_RTS_STATE; *(PULONG)Irp->AssociatedIrp.SystemBuffer = ModemControl; break; } case IOCTL_SERIAL_GET_COMMSTATUS: { SERIAL_IOCTL_SYNC S; if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_STATUS)) { Status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(SERIAL_STATUS); S.Extension = Extension; S.Data = Irp->AssociatedIrp.SystemBuffer; // // Acquire the cancel spin lock so nothing much // changes while were getting the state. // IoAcquireCancelSpinLock(&OldIrql); KeSynchronizeExecution( Extension->Interrupt, SerialGetCommStatus, &S ); IoReleaseCancelSpinLock(OldIrql); break; } case IOCTL_SERIAL_GET_PROPERTIES: { if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_COMMPROP)) { Status = STATUS_BUFFER_TOO_SMALL; break; } // // No synchronization is required since this information // is "static". // SerialGetProperties( Extension, Irp->AssociatedIrp.SystemBuffer ); Irp->IoStatus.Information = sizeof(SERIAL_COMMPROP); Irp->IoStatus.Status = STATUS_SUCCESS; break; } case IOCTL_SERIAL_XOFF_COUNTER: { PSERIAL_XOFF_COUNTER Xc = Irp->AssociatedIrp.SystemBuffer; if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_XOFF_COUNTER)) { Status = STATUS_BUFFER_TOO_SMALL; break; } if (Xc->Counter <= 0) { Status = STATUS_INVALID_PARAMETER; break; } // // So far so good. Put the irp onto the write queue. // return SerialStartOrQueue( Extension, Irp, &Extension->WriteQueue, &Extension->CurrentWriteIrp, SerialStartWrite ); } case IOCTL_SERIAL_LSRMST_INSERT: { PUCHAR escapeChar = Irp->AssociatedIrp.SystemBuffer; // // Make sure we get a byte. // if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(UCHAR)) { Status = STATUS_BUFFER_TOO_SMALL; break; } KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); if (*escapeChar) { // // We've got some escape work to do. We will make sure that // the character is not the same as the Xon or Xoff character, // or that we are already doing error replacement. // if ((*escapeChar == Extension->SpecialChars.XoffChar) || (*escapeChar == Extension->SpecialChars.XonChar) || (Extension->HandFlow.FlowReplace & SERIAL_ERROR_CHAR)) { Status = STATUS_INVALID_PARAMETER; KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } } KeSynchronizeExecution( Extension->Interrupt, SerialSetEscapeChar, Irp ); KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); break; } case IOCTL_SERIAL_CONFIG_SIZE: { if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { Status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(ULONG); Irp->IoStatus.Status = STATUS_SUCCESS; *(PULONG)Irp->AssociatedIrp.SystemBuffer = 0; break; } case IOCTL_SERIAL_GET_STATS: { if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIALPERF_STATS)) { Status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(SERIALPERF_STATS); Irp->IoStatus.Status = STATUS_SUCCESS; KeSynchronizeExecution( Extension->Interrupt, SerialGetStats, Irp ); break; } case IOCTL_SERIAL_CLEAR_STATS: { KeSynchronizeExecution( Extension->Interrupt, SerialClearStats, Extension ); break; } default: { Status = STATUS_INVALID_PARAMETER; break; } } DoneWithIoctl:; Irp->IoStatus.Status = Status; SerialDump( SERIRPPATH, ("SERIAL: Complete Irp: %x\n",Irp) ); IoCompleteRequest( Irp, 0 ); return Status; }