/*++ Copyright (c) 2000 Microsoft Corporation Module Name: mask.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 "ircomm.h" VOID WaitMaskCancelRoutine( PDEVICE_OBJECT DeviceObject, PIRP Irp ); PIRP GetCurrentWaitIrp( PFDO_DEVICE_EXTENSION DeviceExtension ); VOID MaskStartRoutine( PVOID Context, PIRP Irp ) { PFDO_DEVICE_EXTENSION DeviceExtension=(PFDO_DEVICE_EXTENSION)Context; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); KIRQL OldIrql; PUCHAR SystemBuffer = Irp->AssociatedIrp.SystemBuffer; ULONG InputLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; ULONG OutputLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_SERIAL_GET_WAIT_MASK: if (OutputLength >= sizeof(ULONG)) { *(PULONG)SystemBuffer=DeviceExtension->Mask.CurrentMask; Irp->IoStatus.Information=sizeof(ULONG); Irp->IoStatus.Status=STATUS_SUCCESS; } else { Irp->IoStatus.Status=STATUS_INVALID_PARAMETER; } IoCompleteRequest(Irp,IO_NO_INCREMENT); StartNextPacket(&DeviceExtension->Mask.Queue); break; case IOCTL_SERIAL_SET_WAIT_MASK: { ULONG NewMask=*(PULONG)SystemBuffer; if (InputLength >= sizeof(ULONG)) { PIRP WaitIrp=NULL; D_TRACE(DbgPrint("IRCOMM: mask %08lx\n",NewMask);) KeAcquireSpinLock(&DeviceExtension->Mask.Lock,&OldIrql); DeviceExtension->Mask.HistoryMask &= NewMask; DeviceExtension->Mask.CurrentMask=NewMask; Irp->IoStatus.Status=STATUS_SUCCESS; // // if there was a wait irp, clear ir out now // WaitIrp=GetCurrentWaitIrp(DeviceExtension); KeReleaseSpinLock(&DeviceExtension->Mask.Lock,OldIrql); if (WaitIrp != NULL) { WaitIrp->IoStatus.Information=sizeof(ULONG); WaitIrp->IoStatus.Status=STATUS_SUCCESS; *(PULONG)WaitIrp->AssociatedIrp.SystemBuffer=0; IoCompleteRequest(WaitIrp,IO_NO_INCREMENT); } } else { Irp->IoStatus.Status=STATUS_INVALID_PARAMETER; } IoCompleteRequest(Irp,IO_NO_INCREMENT); StartNextPacket(&DeviceExtension->Mask.Queue); break; } case IOCTL_SERIAL_WAIT_ON_MASK: if (OutputLength >= sizeof(ULONG)) { KeAcquireSpinLock(&DeviceExtension->Mask.Lock,&OldIrql); if ((DeviceExtension->Mask.CurrentWaitMaskIrp == NULL) && (DeviceExtension->Mask.CurrentMask != 0)) { if (DeviceExtension->Mask.CurrentMask & DeviceExtension->Mask.HistoryMask) { // // we got an event while there a was no irp queue, complete this // one with the event, and clear the history // D_TRACE(DbgPrint("IRCOMM: Completing wait from histroy %08lx\n", DeviceExtension->Mask.HistoryMask & DeviceExtension->Mask.CurrentMask);) *(PULONG)Irp->AssociatedIrp.SystemBuffer=DeviceExtension->Mask.HistoryMask & DeviceExtension->Mask.CurrentMask; DeviceExtension->Mask.HistoryMask=0; Irp->IoStatus.Information=sizeof(ULONG); Irp->IoStatus.Status=STATUS_SUCCESS; } else { // // the irp will remain pending here until an event happens // KIRQL CancelIrql; IoAcquireCancelSpinLock(&CancelIrql); if (Irp->Cancel) { // // canceled already // Irp->IoStatus.Status=STATUS_CANCELLED; IoReleaseCancelSpinLock(CancelIrql); KeReleaseSpinLock(&DeviceExtension->Mask.Lock,OldIrql); } else { // // not canceled, set the cancel routine and proceed // IoSetCancelRoutine(Irp,WaitMaskCancelRoutine); DeviceExtension->Mask.CurrentWaitMaskIrp=Irp; IoReleaseCancelSpinLock(CancelIrql); KeReleaseSpinLock(&DeviceExtension->Mask.Lock,OldIrql); // // were done processing this so far, we can now handle more // requests from the irp queue // Irp=NULL; StartNextPacket(&DeviceExtension->Mask.Queue); return; } } } else { // // already have an wait event irp or there is not currently an event mask set, fail // D_ERROR(DbgPrint("IRCOMM: MaskStartRoutine: WaitOnMask failing, Current=&p, Mask=%08lx\n",DeviceExtension->Mask.CurrentWaitMaskIrp,DeviceExtension->Mask.CurrentMask);) Irp->IoStatus.Status=STATUS_INVALID_PARAMETER; } KeReleaseSpinLock(&DeviceExtension->Mask.Lock,OldIrql); } else { // // too small // Irp->IoStatus.Status=STATUS_INVALID_PARAMETER; } IoCompleteRequest(Irp,IO_NO_INCREMENT); StartNextPacket(&DeviceExtension->Mask.Queue); break; default: ASSERT(0); IoCompleteRequest(Irp,IO_NO_INCREMENT); StartNextPacket(&DeviceExtension->Mask.Queue); break; } return; } VOID WaitMaskCancelRoutine( PDEVICE_OBJECT DeviceObject, PIRP Irp ) { PFDO_DEVICE_EXTENSION DeviceExtension=DeviceObject->DeviceExtension; KIRQL OldIrql; IoReleaseCancelSpinLock(Irp->CancelIrql); KeAcquireSpinLock(&DeviceExtension->Mask.Lock,&OldIrql); // // since we only handle one mask irp at a time, it should not be possible for it to not // be the current one // ASSERT(DeviceExtension->Mask.CurrentWaitMaskIrp == Irp); DeviceExtension->Mask.CurrentWaitMaskIrp=NULL; KeReleaseSpinLock(&DeviceExtension->Mask.Lock,OldIrql); Irp->IoStatus.Status=STATUS_CANCELLED; IoCompleteRequest(Irp,IO_NO_INCREMENT); return; } VOID EventNotification( PFDO_DEVICE_EXTENSION DeviceExtension, ULONG SerialEvent ) { PIRP WaitIrp=NULL; KIRQL OldIrql; KeAcquireSpinLock(&DeviceExtension->Mask.Lock,&OldIrql); if (SerialEvent & DeviceExtension->Mask.CurrentMask) { // // an event the the client is intereasted in occured // WaitIrp=GetCurrentWaitIrp(DeviceExtension); if (WaitIrp != NULL) { // // There is a wait irp pending // D_TRACE(DbgPrint("IRCOMM: Completing wait event %08lx\n", SerialEvent & DeviceExtension->Mask.CurrentMask);) *(PULONG)WaitIrp->AssociatedIrp.SystemBuffer=SerialEvent & DeviceExtension->Mask.CurrentMask; } else { // // this was an event the the client was interested in, but there was no wait irp // add it to the histrory mask // DeviceExtension->Mask.HistoryMask |= SerialEvent & DeviceExtension->Mask.CurrentMask; } } KeReleaseSpinLock(&DeviceExtension->Mask.Lock,OldIrql); if (WaitIrp != NULL) { WaitIrp->IoStatus.Information=sizeof(ULONG); WaitIrp->IoStatus.Status=STATUS_SUCCESS; IoCompleteRequest(WaitIrp,IO_NO_INCREMENT); } return; } PIRP GetCurrentWaitIrp( PFDO_DEVICE_EXTENSION DeviceExtension ) { PVOID OldCancelRoutine; PIRP WaitIrp; // // if there was a wait irp, clear ir out now // WaitIrp=DeviceExtension->Mask.CurrentWaitMaskIrp; if (WaitIrp != NULL) { OldCancelRoutine=IoSetCancelRoutine(WaitIrp,NULL); if (OldCancelRoutine == NULL) { // // the cancel routine has run and will complete the irp // WaitIrp=NULL; } else { // // the cancel routine will not be running, clear the irp out // DeviceExtension->Mask.CurrentWaitMaskIrp=NULL; } } return WaitIrp; }