/*************************************************************************** Copyright (c) 1998 Microsoft Corporation Module Name: SERIOCTL.C Abstract: Routines to handle serial IOCTLs for Legacy USB Modem Driver. Environment: kernel mode only Notes: THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. Copyright (c) 1998 Microsoft Corporation. All Rights Reserved. Revision History: 12/27/97 : created Authors: Tom Green ****************************************************************************/ #include #include #include #include #include #include #include #include #ifdef WMI_SUPPORT #include #include #include #endif #include "usbser.h" #include "serioctl.h" #include "utils.h" #include "usbserpw.h" #include "debugwdm.h" #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGEUSBS, SetBaudRate) #pragma alloc_text(PAGEUSBS, GetBaudRate) #pragma alloc_text(PAGEUSBS, SetLineControl) #pragma alloc_text(PAGEUSBS, GetLineControl) #pragma alloc_text(PAGEUSBS, SetTimeouts) #pragma alloc_text(PAGEUSBS, GetTimeouts) #pragma alloc_text(PAGEUSBS, SetChars) #pragma alloc_text(PAGEUSBS, GetChars) #pragma alloc_text(PAGEUSBS, SetClrDtr) #pragma alloc_text(PAGEUSBS, ResetDevice) #pragma alloc_text(PAGEUSBS, SetRts) #pragma alloc_text(PAGEUSBS, ClrRts) #pragma alloc_text(PAGEUSBS, SetBreak) #pragma alloc_text(PAGEUSBS, SetQueueSize) #pragma alloc_text(PAGEUSBS, GetWaitMask) #pragma alloc_text(PAGEUSBS, SetWaitMask) #pragma alloc_text(PAGEUSBS, WaitOnMask) #pragma alloc_text(PAGEUSBS, ImmediateChar) #pragma alloc_text(PAGEUSBS, Purge) #pragma alloc_text(PAGEUSBS, GetHandflow) #pragma alloc_text(PAGEUSBS, SetHandflow) #pragma alloc_text(PAGEUSBS, GetModemStatus) #pragma alloc_text(PAGEUSBS, GetDtrRts) #pragma alloc_text(PAGEUSBS, GetCommStatus) #pragma alloc_text(PAGEUSBS, GetProperties) #pragma alloc_text(PAGEUSBS, LsrmstInsert) #pragma alloc_text(PAGEUSBS, ConfigSize) #pragma alloc_text(PAGEUSBS, GetStats) #pragma alloc_text(PAGEUSBS, ClearStats) #pragma alloc_text(PAGEUSBS, SerialGetProperties) #endif // ALLOC_PRAGMA LOCAL UCHAR StopBits[] = { STOP_BIT_1, // USB_COMM_STOPBITS_10 STOP_BITS_1_5, // USB_COMM_STOPBITS_15 STOP_BITS_2 // USB_COMM_STOPBITS_20 }; LOCAL UCHAR ParityType[] = { NO_PARITY, // USB_COMM_PARITY_NONE ODD_PARITY, // USB_COMM_PARITY_ODD EVEN_PARITY, // USB_COMM_PARITY_EVEN MARK_PARITY, // USB_COMM_PARITY_MARK SPACE_PARITY // USB_COMM_PARITY_SPACE }; /************************************************************************/ /* SetBaudRate */ /************************************************************************/ /* */ /* Routine Description: */ /* */ /* Handle IOCTL_SERIAL_SET_BAUD_RATE */ /* */ /* Arguments: */ /* */ /* Irp - pointer to an I/O Request Packet */ /* PDevObj - pointer to device object */ /* */ /* Return Value: */ /* */ /* NTSTATUS */ /* */ /************************************************************************/ NTSTATUS SetBaudRate(IN PIRP Irp, IN PDEVICE_OBJECT PDevObj) { PSERIAL_BAUD_RATE Br = (PSERIAL_BAUD_RATE) Irp->AssociatedIrp.SystemBuffer; NTSTATUS NtStatus = STATUS_SUCCESS; PIO_STACK_LOCATION IrpStack; KIRQL OldIrql; PDEVICE_EXTENSION DeviceExtension = PDevObj->DeviceExtension; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter SetBaudRate"); UsbSerSerialDump(USBSERTRACEIOC, (">SetBaudRate(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_BAUD_RATE)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); DeviceExtension->CurrentBaud = Br->BaudRate; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); DEBUG_TRACE3(("BaudRate (%08X)\n", Br->BaudRate)); NtStatus = SetLineControlAndBaud(PDevObj); } DEBUG_LOG_PATH("exit SetBaudRate"); UsbSerSerialDump(USBSERTRACEIOC, ("AssociatedIrp.SystemBuffer; NTSTATUS NtStatus = STATUS_SUCCESS; KIRQL OldIrql; PIO_STACK_LOCATION IrpStack; PDEVICE_EXTENSION DeviceExtension = PDevObj->DeviceExtension; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter GetBaudRate"); UsbSerSerialDump(USBSERTRACEIOC, (">GetBaudRate(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_BAUD_RATE)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { GetLineControlAndBaud(PDevObj); ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); Br->BaudRate = DeviceExtension->CurrentBaud; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); Irp->IoStatus.Information = sizeof(SERIAL_BAUD_RATE); } DEBUG_LOG_PATH("exit GetBaudRate"); UsbSerSerialDump(USBSERTRACEIOC, ("AssociatedIrp.SystemBuffer; NTSTATUS NtStatus = STATUS_SUCCESS; KIRQL OldIrql; PIO_STACK_LOCATION IrpStack; PDEVICE_EXTENSION DeviceExtension = PDevObj->DeviceExtension; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter SetLineControl"); UsbSerSerialDump(USBSERTRACEIOC, (">SetLineControl(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_LINE_CONTROL)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); DeviceExtension->LineControl = *LineControl; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); // set line control for USB modem NtStatus = SetLineControlAndBaud(PDevObj); } DEBUG_LOG_PATH("exit SetLineControl"); UsbSerSerialDump(USBSERTRACEIOC, ("AssociatedIrp.SystemBuffer; NTSTATUS NtStatus = STATUS_SUCCESS; KIRQL OldIrql; PIO_STACK_LOCATION IrpStack; PDEVICE_EXTENSION DeviceExtension = PDevObj->DeviceExtension; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter GetLineControl"); UsbSerSerialDump(USBSERTRACEIOC, (">GetLineControl(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if(IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_LINE_CONTROL)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { GetLineControlAndBaud(PDevObj); ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); *LineControl = DeviceExtension->LineControl; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); Irp->IoStatus.Information = sizeof(SERIAL_LINE_CONTROL); } DEBUG_LOG_PATH("exit GetLineControl"); UsbSerSerialDump(USBSERTRACEIOC, ("AssociatedIrp.SystemBuffer; NTSTATUS NtStatus = STATUS_SUCCESS; KIRQL OldIrql; PIO_STACK_LOCATION IrpStack; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter SetTimeouts"); UsbSerSerialDump(USBSERTRACEIOC | USBSERTRACETM, (">SetTimeouts(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if(IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_TIMEOUTS)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); DeviceExtension->Timeouts = *Timeouts; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); } DEBUG_LOG_PATH("exit SetTimeouts"); UsbSerSerialDump(USBSERTRACEIOC | USBSERTRACETM, ("AssociatedIrp.SystemBuffer; NTSTATUS NtStatus = STATUS_SUCCESS; KIRQL OldIrql; PIO_STACK_LOCATION IrpStack; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter GetTimeouts"); UsbSerSerialDump(USBSERTRACEIOC | USBSERTRACETM, (">GetTimeouts(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if(IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_TIMEOUTS)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); *Timeouts = DeviceExtension->Timeouts; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); Irp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS); } DEBUG_LOG_PATH("exit GetTimeouts"); UsbSerSerialDump(USBSERTRACEIOC | USBSERTRACETM, ("AssociatedIrp.SystemBuffer; NTSTATUS NtStatus = STATUS_SUCCESS; KIRQL OldIrql; PIO_STACK_LOCATION IrpStack; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter SetChars"); UsbSerSerialDump(USBSERTRACEIOC, (">SetChars(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if(IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_CHARS)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); DeviceExtension->SpecialChars = *SpecialChars; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); } DEBUG_LOG_PATH("exit SetChars"); UsbSerSerialDump(USBSERTRACEIOC, ("AssociatedIrp.SystemBuffer; NTSTATUS NtStatus = STATUS_SUCCESS; KIRQL OldIrql; PIO_STACK_LOCATION IrpStack; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter GetChars"); UsbSerSerialDump(USBSERTRACEIOC, (">GetChars(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if(IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_CHARS)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); *SpecialChars = DeviceExtension->SpecialChars; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); Irp->IoStatus.Information = sizeof(SERIAL_CHARS); } DEBUG_LOG_PATH("exit GetChars"); UsbSerSerialDump(USBSERTRACEIOC, ("DeviceExtension; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter SetClrDtr"); UsbSerSerialDump(USBSERTRACEIOC, (">SetClrDtr\n")); ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); if(DeviceExtension->DTRRTSState & SERIAL_RTS_STATE) State |= USB_COMM_RTS; if (Set) { DeviceExtension->DTRRTSState |= SERIAL_DTR_STATE; State |= USB_COMM_DTR; } else { DeviceExtension->DTRRTSState &= ~SERIAL_DTR_STATE; } RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); if(DeviceExtension->DTRRTSState & SERIAL_RTS_STATE) State |= USB_COMM_RTS; NtStatus = ClassVendorCommand(PDevObj, USB_COMM_SET_CONTROL_LINE_STATE, State, DeviceExtension->CommInterface, NULL, NULL, FALSE, USBSER_CLASS_COMMAND); if(!NT_SUCCESS(NtStatus)) { ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); DeviceExtension->DTRRTSState &= ~SERIAL_DTR_STATE; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); } DEBUG_LOG_PATH("exit SetClrDtr"); UsbSerSerialDump(USBSERTRACEIOC, ("DeviceExtension; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter ResetDevice"); UsbSerSerialDump(USBSERTRACEIOC, (">ResetDevice(%08X)\n", Irp)); // get line control and baud rate info GetLineControlAndBaud(PDevObj); ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); // do device extension device specific stuff here DeviceExtension->SupportedBauds = SERIAL_BAUD_300 | SERIAL_BAUD_600 | SERIAL_BAUD_1200 | SERIAL_BAUD_2400 | SERIAL_BAUD_4800 | SERIAL_BAUD_9600 | SERIAL_BAUD_19200 | SERIAL_BAUD_38400 | SERIAL_BAUD_57600 | SERIAL_BAUD_115200; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); DEBUG_LOG_PATH("exit ResetDevice"); UsbSerSerialDump(USBSERTRACEIOC, ("SetRts(%08X)\n", Irp)); ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); DeviceExtension->DTRRTSState |= SERIAL_RTS_STATE; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); DEBUG_LOG_PATH("exit SetRts"); UsbSerSerialDump(USBSERTRACEIOC, ("ClrRts(%08X)\n", Irp)); ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); DeviceExtension->DTRRTSState &= ~SERIAL_RTS_STATE; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); DEBUG_LOG_PATH("exit ClrRts"); UsbSerSerialDump(USBSERTRACEIOC, ("DeviceExtension; USBSER_LOCKED_PAGED_CODE(); DEBUG_LOG_PATH("enter SetBreak"); UsbSerSerialDump(USBSERTRACEIOC, (">SetBreak(%08X)\n", Irp)); NtStatus = ClassVendorCommand(PDevObj, USB_COMM_SEND_BREAK, Time, DeviceExtension->CommInterface, NULL, NULL, FALSE, USBSER_CLASS_COMMAND); DEBUG_LOG_PATH("exit SetBreak"); UsbSerSerialDump(USBSERTRACEIOC, ("AssociatedIrp.SystemBuffer; DEBUG_LOG_PATH("enter SetQueueSize"); UsbSerSerialDump(USBSERTRACEIOC, (">SetQueueSize(%08X)\n", Irp)); USBSER_LOCKED_PAGED_CODE(); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if(IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { DEBUG_TRACE1(("SetQueueSize (%08X)\n", *QueueSize)); // we will go ahead and save this, but we don't care. // DeviceExtension->RxQueueSize = *QueueSize; } DEBUG_LOG_PATH("exit SetQueueSize"); UsbSerSerialDump(USBSERTRACEIOC, ("AssociatedIrp.SystemBuffer; NTSTATUS NtStatus = STATUS_SUCCESS; KIRQL OldIrql; PIO_STACK_LOCATION IrpStack; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter GetWaitMask"); UsbSerSerialDump(USBSERTRACEIOC, (">GetWaitMask(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if(IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); *WaitMask = DeviceExtension->IsrWaitMask; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); Irp->IoStatus.Information = sizeof(ULONG); } DEBUG_LOG_PATH("exit GetWaitMask"); UsbSerSerialDump(USBSERTRACEIOC, ("AssociatedIrp.SystemBuffer; NTSTATUS NtStatus = STATUS_SUCCESS; KIRQL OldIrql; PIO_STACK_LOCATION IrpStack; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter SetWaitMask"); UsbSerSerialDump(USBSERTRACEIOC, (">SetWaitMask(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { // make sure it's a valid request if (*WaitMask & ~( 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)) { NtStatus = STATUS_INVALID_PARAMETER; } else { UsbSerCompletePendingWaitMasks(DeviceExtension); ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); DeviceExtension->HistoryMask = 0; DeviceExtension->IsrWaitMask = *WaitMask; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); DEBUG_TRACE3(("SetWaitMask (%08X)\n", *WaitMask)); } } DEBUG_LOG_PATH("exit SetWaitMask"); UsbSerSerialDump(USBSERTRACEIOC, ("AssociatedIrp.SystemBuffer; NTSTATUS NtStatus = STATUS_SUCCESS; KIRQL OldIrql; PIO_STACK_LOCATION IrpStack; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter WaitOnMask"); UsbSerSerialDump(USBSERTRACEIOC, (">WaitOnMask(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { // if we have an event to report, just go ahead and return it if (DeviceExtension->HistoryMask) { ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); *WaitMask = DeviceExtension->HistoryMask; DeviceExtension->HistoryMask = 0; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); Irp->IoStatus.Information = sizeof(ULONG); UsbSerSerialDump(USBSERCOMPEV, ("Completing maskirp(3) %08x\n", *WaitMask)); DEBUG_TRACE3(("Signal Event (%08X)\n", *WaitMask)); } else { KIRQL cancelIrql; ACQUIRE_CANCEL_SPINLOCK(DeviceExtension, &cancelIrql); ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); // just in case something comes in, we'll do a while loop while (DeviceExtension->CurrentMaskIrp) { PIRP pOldIrp; DEBUG_TRACE3(("Completing previous mask\n")); pOldIrp = DeviceExtension->CurrentMaskIrp; DeviceExtension->CurrentMaskIrp = NULL; pOldIrp->IoStatus.Status = STATUS_SUCCESS; IoSetCancelRoutine(pOldIrp, NULL); *WaitMask = 0; UsbSerSerialDump(USBSERCOMPEV, ("Completing maskirp(4)\n")); // // Release locks, complete request, then // reacquire the locks // RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); RELEASE_CANCEL_SPINLOCK(DeviceExtension, cancelIrql); IoCompleteRequest(pOldIrp, IO_SERIAL_INCREMENT); ACQUIRE_CANCEL_SPINLOCK(DeviceExtension, &cancelIrql); ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); } // // Check to see if it needs to be cancelled // if (Irp->Cancel) { Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); RELEASE_CANCEL_SPINLOCK(DeviceExtension, cancelIrql); } else { IoSetCancelRoutine(Irp, UsbSerCancelWaitOnMask); NtStatus = Irp->IoStatus.Status = STATUS_PENDING; DeviceExtension->CurrentMaskIrp = Irp; IoMarkIrpPending(Irp); RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); RELEASE_CANCEL_SPINLOCK(DeviceExtension, cancelIrql); } } } DEBUG_LOG_PATH("exit WaitOnMask"); UsbSerSerialDump(USBSERTRACEIOC, ("AssociatedIrp.SystemBuffer; NTSTATUS NtStatus = STATUS_SUCCESS; PIO_STACK_LOCATION IrpStack; USBSER_LOCKED_PAGED_CODE(); DEBUG_LOG_PATH("enter ImmediateChar"); UsbSerSerialDump(USBSERTRACEIOC, (">ImmediateChar(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(UCHAR)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { // // We just treat this as a write since we have no internal // data buffer. // IrpStack->Parameters.Write.Length = sizeof(UCHAR); NtStatus = UsbSer_Write(DeviceObject, Irp); } DEBUG_LOG_PATH("exit ImmediateChar"); UsbSerSerialDump(USBSERTRACEIOC, ("AssociatedIrp.SystemBuffer); NTSTATUS NtStatus = STATUS_SUCCESS; PIO_STACK_LOCATION IrpStack; KIRQL OldIrql; ULONG Count; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter Purge"); UsbSerSerialDump(USBSERTRACEIOC, (">Purge(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { // make sure purge request is valid if ((!Mask) || (Mask & ( ~( SERIAL_PURGE_TXABORT | SERIAL_PURGE_RXABORT | SERIAL_PURGE_TXCLEAR | SERIAL_PURGE_RXCLEAR)))) { NtStatus = STATUS_INVALID_PARAMETER; } else { if (Mask & SERIAL_PURGE_RXCLEAR) { ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); Count = DeviceExtension->CharsInReadBuff; DeviceExtension->CharsInReadBuff = 0; DeviceExtension->CurrentReadBuffPtr = 0; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); if(Count) { RestartRead(DeviceExtension); } } if (Mask & SERIAL_PURGE_RXABORT) { UsbSerKillAllReadsOrWrites(PDevObj, &DeviceExtension->ReadQueue, &DeviceExtension->CurrentReadIrp); } if (Mask & SERIAL_PURGE_TXABORT) { // // DO NOTHING because USB owns the request. However, it may // prove in practice that we will have to cancel the IRPs on behalf // of the caller. } } } DEBUG_LOG_PATH("exit Purge"); UsbSerSerialDump(USBSERTRACEIOC, ("AssociatedIrp.SystemBuffer; NTSTATUS NtStatus = STATUS_SUCCESS; KIRQL OldIrql; PIO_STACK_LOCATION IrpStack; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter GetHandflow"); UsbSerSerialDump(USBSERTRACEIOC, (">GetHandFlow(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_HANDFLOW)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); *HandFlow = DeviceExtension->HandFlow; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); Irp->IoStatus.Information = sizeof(SERIAL_HANDFLOW); } DEBUG_LOG_PATH("exit GetHandflow"); UsbSerSerialDump(USBSERTRACEIOC, ("AssociatedIrp.SystemBuffer; NTSTATUS NtStatus = STATUS_SUCCESS; KIRQL OldIrql; PIO_STACK_LOCATION IrpStack; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter SetHandflow"); UsbSerSerialDump(USBSERTRACEIOC, (">SetHandFlow(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_HANDFLOW)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); DeviceExtension->HandFlow = *HandFlow; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); DEBUG_TRACE3(("ControlHandShake (%08X)\n", DeviceExtension->HandFlow.ControlHandShake)); } DEBUG_LOG_PATH("exit SetHandflow"); UsbSerSerialDump(USBSERTRACEIOC, ("AssociatedIrp.SystemBuffer; NTSTATUS NtStatus = STATUS_SUCCESS; PIO_STACK_LOCATION IrpStack; KIRQL OldIrql; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter GetModemStatus"); UsbSerSerialDump(USBSERTRACEIOC, (">GetModemStatus(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); *ModemStatus = DeviceExtension->FakeModemStatus; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); Irp->IoStatus.Information = sizeof(ULONG); DEBUG_TRACE3(("ModemStatus (%08X)\n", *ModemStatus)); } DEBUG_LOG_PATH("exit GetModemStatus"); UsbSerSerialDump(USBSERTRACEIOC, ("AssociatedIrp.SystemBuffer; NTSTATUS NtStatus = STATUS_SUCCESS; PIO_STACK_LOCATION IrpStack; KIRQL OldIrql; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter GetDtrRts"); UsbSerSerialDump(USBSERTRACEIOC, (">GetDtrRts(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); *ModemControl = DeviceExtension->DTRRTSState; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); Irp->IoStatus.Information = sizeof(ULONG); } DEBUG_LOG_PATH("exit GetDtrRts"); UsbSerSerialDump(USBSERTRACEIOC, ("AssociatedIrp.SystemBuffer; NTSTATUS NtStatus = STATUS_SUCCESS; KIRQL OldIrql; PIO_STACK_LOCATION IrpStack; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter GetCommStatus"); UsbSerSerialDump(USBSERTRACEIOC, (">GetCommStatus(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_STATUS)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { if (NT_SUCCESS(NtStatus)) { RtlZeroMemory(SerialStatus, sizeof(SERIAL_STATUS)); ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); SerialStatus->AmountInInQueue = DeviceExtension->CharsInReadBuff; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); DEBUG_TRACE2(("AmountInInQueue (%08X)\n", SerialStatus->AmountInInQueue)); SerialStatus->Errors = 0; SerialStatus->EofReceived = FALSE; SerialStatus->AmountInOutQueue = 0; SerialStatus->WaitForImmediate = 0; SerialStatus->HoldReasons = 0; Irp->IoStatus.Information = sizeof(SERIAL_STATUS); } } DEBUG_LOG_PATH("exit GetCommStatus"); UsbSerSerialDump(USBSERTRACEIOC, ("GetProperties(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_COMMPROP)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { SerialGetProperties(DeviceExtension, (PSERIAL_COMMPROP)Irp->AssociatedIrp.SystemBuffer); Irp->IoStatus.Information = sizeof(SERIAL_COMMPROP); } DEBUG_LOG_PATH("exit GetProperties"); UsbSerSerialDump(USBSERTRACEIOC, ("LsrmstInsert(%08X)\n", Irp)); UsbSerSerialDump(USBSERTRACEIOC, ("AssociatedIrp.SystemBuffer; NTSTATUS NtStatus = STATUS_SUCCESS; PIO_STACK_LOCATION IrpStack; USBSER_LOCKED_PAGED_CODE(); DEBUG_LOG_PATH("enter ConfigSize"); UsbSerSerialDump(USBSERTRACEIOC, (">ConfigSize(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { *ConfigSize = 0; Irp->IoStatus.Information = sizeof(ULONG); } DEBUG_LOG_PATH("exit ConfigSize"); UsbSerSerialDump(USBSERTRACEIOC, ("AssociatedIrp.SystemBuffer; NTSTATUS NtStatus = STATUS_SUCCESS; KIRQL OldIrql; PIO_STACK_LOCATION IrpStack; USBSER_ALWAYS_LOCKED_CODE(); DEBUG_LOG_PATH("enter GetStats"); UsbSerSerialDump(USBSERTRACEIOC, (">GetStats(%08X)\n", Irp)); Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIALPERF_STATS)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); *Stats = DeviceExtension->PerfStats; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); Irp->IoStatus.Information = sizeof(SERIALPERF_STATS); } DEBUG_LOG_PATH("exit GetStats"); UsbSerSerialDump(USBSERTRACEIOC, ("ClearStats(%08X)\n", Irp)); Irp->IoStatus.Information = 0; ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); RtlZeroMemory(&DeviceExtension->PerfStats, sizeof(SERIALPERF_STATS)); RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); DEBUG_LOG_PATH("exit ClearStats"); UsbSerSerialDump(USBSERTRACEIOC, ("SerialGetProperties\n")); RtlZeroMemory(Properties, sizeof(SERIAL_COMMPROP)); Properties->PacketLength = sizeof(SERIAL_COMMPROP); Properties->PacketVersion = 2; Properties->ServiceMask = SERIAL_SP_SERIALCOMM; Properties->MaxTxQueue = 0; Properties->MaxRxQueue = 0; Properties->MaxBaud = SERIAL_BAUD_USER; Properties->ProvSubType = SERIAL_SP_MODEM; Properties->ProvCapabilities = SERIAL_PCF_DTRDSR | SERIAL_PCF_CD | SERIAL_PCF_PARITY_CHECK | SERIAL_PCF_TOTALTIMEOUTS | SERIAL_PCF_INTTIMEOUTS; Properties->SettableParams = SERIAL_SP_PARITY | SERIAL_SP_BAUD | SERIAL_SP_DATABITS | SERIAL_SP_STOPBITS | SERIAL_SP_HANDSHAKING | SERIAL_SP_PARITY_CHECK | SERIAL_SP_CARRIER_DETECT; Properties->SettableData = SERIAL_DATABITS_7 | SERIAL_DATABITS_8; Properties->SettableStopParity = SERIAL_STOPBITS_10 | SERIAL_PARITY_NONE | SERIAL_PARITY_ODD | SERIAL_PARITY_EVEN | SERIAL_PARITY_MARK | SERIAL_PARITY_SPACE; Properties->CurrentTxQueue = 0; ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); Properties->CurrentRxQueue = DeviceExtension->RxQueueSize; Properties->SettableBaud = DeviceExtension->SupportedBauds; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); DEBUG_LOG_PATH("exit SerialGetProperties"); UsbSerSerialDump(USBSERTRACEIOC, ("DeviceExtension; DEBUG_LOG_PATH("enter GetLineControlAndBaud"); NtStatus = ClassVendorCommand(PDevObj, USB_COMM_GET_LINE_CODING, 0, DeviceExtension->CommInterface, &LineCoding, &Size, TRUE, USBSER_CLASS_COMMAND); if (NT_SUCCESS(NtStatus)) { ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); DeviceExtension->CurrentBaud = LineCoding.DTERate; DeviceExtension->LineControl.StopBits = StopBits[LineCoding.CharFormat]; DeviceExtension->LineControl.Parity = ParityType[LineCoding.ParityType]; DeviceExtension->LineControl.WordLength = LineCoding.DataBits; RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); DEBUG_TRACE3(("Baud (%08X) StopBits (%08X) DataBits (%08X)\n", LineCoding.DTERate, LineCoding.CharFormat, LineCoding.DataBits)); } DEBUG_LOG_PATH("exit GetLineControlAndBaud"); return NtStatus; } // GetLineControlAndBaud /************************************************************************/ /* SetLineControlAndBaud */ /************************************************************************/ /* */ /* Routine Description: */ /* */ /* CDC command to set line control and baud */ /* */ /* Arguments: */ /* */ /* PDevObj - pointer to device object */ /* */ /* Return Value: */ /* */ /* NTSTATUS */ /* */ /************************************************************************/ NTSTATUS SetLineControlAndBaud(IN PDEVICE_OBJECT PDevObj) { NTSTATUS NtStatus = STATUS_SUCCESS; USB_COMM_LINE_CODING LineCoding; ULONG Size = sizeof(LineCoding); PSERIAL_LINE_CONTROL LineControl; KIRQL OldIrql; PDEVICE_EXTENSION DeviceExtension = PDevObj->DeviceExtension; DEBUG_LOG_PATH("enter SetLineControlAndBaud"); // get pointer to line control in extension LineControl = &DeviceExtension->LineControl; ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); // set up the line coding data structure LineCoding.DTERate = DeviceExtension->CurrentBaud; LineCoding.DataBits = LineControl->WordLength; switch (DeviceExtension->LineControl.StopBits) { case STOP_BIT_1: LineCoding.CharFormat = USB_COMM_STOPBITS_10; break; case STOP_BITS_1_5: LineCoding.CharFormat = USB_COMM_STOPBITS_15; break; case STOP_BITS_2: LineCoding.CharFormat = USB_COMM_STOPBITS_20; break; default: NtStatus = STATUS_INVALID_PARAMETER; break; } switch (DeviceExtension->LineControl.Parity) { case NO_PARITY: LineCoding.ParityType = USB_COMM_PARITY_NONE; break; case ODD_PARITY: LineCoding.ParityType = USB_COMM_PARITY_ODD; break; case EVEN_PARITY: LineCoding.ParityType = USB_COMM_PARITY_EVEN; break; case MARK_PARITY: LineCoding.ParityType = USB_COMM_PARITY_MARK; break; case SPACE_PARITY: LineCoding.ParityType = USB_COMM_PARITY_SPACE; break; default: NtStatus = STATUS_INVALID_PARAMETER; break; } RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); // the request must be valid, so send it down to the device if (NT_SUCCESS(NtStatus)) { NtStatus = ClassVendorCommand(PDevObj, USB_COMM_SET_LINE_CODING, 0, DeviceExtension->CommInterface, &LineCoding, &Size, FALSE, USBSER_CLASS_COMMAND); } // let's go ahead and just grab this info again in case of an error GetLineControlAndBaud(PDevObj); DEBUG_LOG_PATH("exit SetLineControlAndBaud"); return NtStatus; } // SetLineControlAndBaud /************************************************************************/ /* NotifyCompletion */ /************************************************************************/ /* */ /* Routine Description: */ /* */ /* Notify completion routine. */ /* */ /* Arguments: */ /* */ /* DeviceObject - pointer to a device object */ /* Irp - pointer to Irp */ /* Context - pointer to driver defined context */ /* */ /* Return Value: */ /* */ /* NTSTATUS */ /* */ /************************************************************************/ NTSTATUS NotifyCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) { PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) Context; PURB Urb; ULONG Count; KIRQL OldIrql; KIRQL cancelIrql; PUSB_COMM_SERIAL_STATUS SerialState; USHORT ModemStatus; USHORT OldModemStatus; PIRP CurrentMaskIrp = NULL; BOOLEAN startRead = FALSE; DEBUG_LOG_PATH("enter NotifyCompletion"); Urb = DeviceExtension->NotifyUrb; Count = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength; ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); SerialState = (PUSB_COMM_SERIAL_STATUS) DeviceExtension->NotificationBuff; // see if it is our notification if (SerialState->Notification == USB_COMM_SERIAL_STATE && Count == sizeof(USB_COMM_SERIAL_STATUS)) { OldModemStatus = DeviceExtension->FakeModemStatus; // cobble up a fake modem status DeviceExtension->FakeModemStatus = SERIAL_MSR_CTS; DeviceExtension->FakeLineStatus = 0; DeviceExtension->HistoryMask = 0; ModemStatus = SerialState->SerialState; DeviceExtension->FakeLineStatus = 0; DEBUG_TRACE1(("CDC Serial State (%08X)\n", ModemStatus)); if (ModemStatus & USB_COMM_DSR) DeviceExtension->FakeModemStatus |= SERIAL_MSR_DSR; if (ModemStatus & USB_COMM_DCD) DeviceExtension->FakeModemStatus |= SERIAL_MSR_DCD; if (ModemStatus & USB_COMM_RING) DeviceExtension->FakeModemStatus |= SERIAL_MSR_RI; // let's see what has changed in the status register ModemStatus = OldModemStatus ^ DeviceExtension->FakeModemStatus; if (ModemStatus & SERIAL_MSR_DSR) DeviceExtension->HistoryMask |= SERIAL_EV_DSR; if (ModemStatus & SERIAL_MSR_DCD) DeviceExtension->HistoryMask |= SERIAL_EV_RLSD; if (ModemStatus & SERIAL_MSR_RI) DeviceExtension->HistoryMask |= SERIAL_EV_RING; // see if we have any events we are waiting for DeviceExtension->HistoryMask &= DeviceExtension->IsrWaitMask; // update perf stats if we had any errors if (ModemStatus & USB_COMM_FRAMING_ERROR) { DeviceExtension->PerfStats.FrameErrorCount++; DeviceExtension->FakeLineStatus |= SERIAL_LSR_FE; } if (ModemStatus & USB_COMM_OVERRUN) { DeviceExtension->PerfStats.BufferOverrunErrorCount++; DeviceExtension->FakeLineStatus |= SERIAL_LSR_OE; } if (ModemStatus & USB_COMM_PARITY_ERROR) { DeviceExtension->PerfStats.ParityErrorCount++; DeviceExtension->FakeLineStatus |= SERIAL_LSR_PE; } if (ModemStatus & USB_COMM_BREAK) { DeviceExtension->FakeLineStatus |= SERIAL_LSR_BI; } RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); ACQUIRE_CANCEL_SPINLOCK(DeviceExtension, &cancelIrql); ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); // let's see if we have any events to signal CurrentMaskIrp = DeviceExtension->CurrentMaskIrp; if (CurrentMaskIrp && DeviceExtension->HistoryMask) { *(PULONG) (CurrentMaskIrp->AssociatedIrp.SystemBuffer) = DeviceExtension->HistoryMask; CurrentMaskIrp->IoStatus.Status = STATUS_SUCCESS; CurrentMaskIrp->IoStatus.Information = sizeof(ULONG); DeviceExtension->CurrentMaskIrp = NULL; } else { RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); RELEASE_CANCEL_SPINLOCK(DeviceExtension, cancelIrql); } DEBUG_TRACE1(("Modem Status (%08X)\n", DeviceExtension->FakeModemStatus)); } else { RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); } // complete the queued IRP if needed if (CurrentMaskIrp && DeviceExtension->HistoryMask && Irp->IoStatus.Status == STATUS_SUCCESS) { // // We should still be holding cancel spin lock because // of above if() UsbSerSerialDump(USBSERCOMPEV, ("Completing maskirp (4) %08X\n", DeviceExtension->HistoryMask)); DeviceExtension->HistoryMask = 0; IoSetCancelRoutine(CurrentMaskIrp, NULL); RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); RELEASE_CANCEL_SPINLOCK(DeviceExtension, cancelIrql); IoCompleteRequest(CurrentMaskIrp, IO_NO_INCREMENT); } // check for Irp cancelled or error if(Irp->IoStatus.Status == STATUS_CANCELLED) { goto NotifyCompletionErr; } else if(!NT_SUCCESS(Irp->IoStatus.Status)) { UsbSerFetchBooleanLocked(&DeviceExtension->AcceptingRequests, FALSE, &DeviceExtension->ControlLock); goto NotifyCompletionErr; } ACQUIRE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, &OldIrql); // kick off another notification request if we still need to if (DeviceExtension->AcceptingRequests && (DeviceExtension->CurrentDevicePowerState == PowerDeviceD0)) { // see if we have a work item queued already if(DeviceExtension->IoWorkItem == NULL) { startRead = TRUE; // kick off another read DeviceExtension->IoWorkItem = IoAllocateWorkItem(DeviceExtension->PhysDeviceObject); } if(startRead && DeviceExtension->IoWorkItem) { RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); IoQueueWorkItem(DeviceExtension->IoWorkItem, USBSER_RestartNotifyReadWorkItem, CriticalWorkQueue, DeviceExtension); } else { RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); } } else { RELEASE_SPINLOCK(DeviceExtension, &DeviceExtension->ControlLock, OldIrql); } NotifyCompletionErr:; // // Notify everyone if this is the last IRP and we aren't starting another read // if((InterlockedDecrement(&DeviceExtension->PendingNotifyCount) == 0)) { UsbSerSerialDump(USBSERTRACERD, ("Notify pipe is empty\n")); if(!startRead) { KeSetEvent(&DeviceExtension->PendingNotifyEvent, IO_NO_INCREMENT, FALSE); } } DEBUG_LOG_PATH("exit NotifyCompletion"); return STATUS_MORE_PROCESSING_REQUIRED; } // NotifyCompletion