1 /*
2  *  ReactOS Floppy Driver
3  *  Copyright (C) 2004, Vizzini (vizzini@plasmic.com)
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * PROJECT:         ReactOS Floppy Driver
20  * FILE:            csqrtns.c
21  * PURPOSE:         Cancel-safe queue routines
22  * PROGRAMMER:      Vizzini (vizzini@plasmic.com)
23  * REVISIONS:
24  *                  15-Feb-2004 vizzini - Created
25  * NOTES:
26  *     - These functions provide the callbacks for the CSQ routines.
27  *       They will be called automatically by the IoCsqXxx() routines.
28  *       This driver uses the CSQ in the standard way.  In addition to
29  *       queuing and de-queuing IRPs, the InsertIrp routine releases
30  *       a semaphore every time an IRP is queued, allowing a queue management
31  *       thread to properly drain the queue.
32  *     - Note that the semaphore can get ahead of the number of IRPs in the
33  *       queue if any are canceled; the queue management thread that de-queues
34  *       IRPs is coded with that in mind.
35  *     - For more information, see the csqtest driver in the ReactOS tree,
36  *       or the cancel sample in recent (3790+) Microsoft DDKs.
37  *     - Many of these routines are called at DISPATCH_LEVEL, due to the fact
38  *       that my lock choice is a spin lock.
39  */
40 
41 #include "precomp.h"
42 
43 #include <debug.h>
44 
45 /* Global CSQ struct that the CSQ functions initialize and use */
46 IO_CSQ Csq;
47 
48 /* List and lock for the actual IRP queue */
49 LIST_ENTRY IrpQueue;
50 KSPIN_LOCK IrpQueueLock;
51 KSEMAPHORE QueueSemaphore;
52 
53 /*
54  * CSQ Callbacks
55  */
56 
57 
58 VOID NTAPI
CsqRemoveIrp(PIO_CSQ UnusedCsq,PIRP Irp)59 CsqRemoveIrp(PIO_CSQ UnusedCsq, PIRP Irp)
60 /*
61  * FUNCTION: Remove an IRP from the queue
62  * ARGUMENTS:
63  *     UnusedCsq: Pointer to CSQ context structure
64  *     Irp: Pointer to the IRP to remove from the queue
65  * NOTES:
66  *     - Called under the protection of the queue lock
67  */
68 {
69     UNREFERENCED_PARAMETER(UnusedCsq);
70     TRACE_(FLOPPY, "CSQ: Removing IRP 0x%p\n", Irp);
71     RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
72 }
73 
74 
75 PIRP NTAPI
CsqPeekNextIrp(PIO_CSQ UnusedCsq,PIRP Irp,PVOID PeekContext)76 CsqPeekNextIrp(PIO_CSQ UnusedCsq, PIRP Irp, PVOID PeekContext)
77 /*
78  * FUNCTION: Find the next matching IRP in the queue
79  * ARGUMENTS:
80  *     UnusedCsq: Pointer to CSQ context structure
81  *     Irp: Pointer to a starting IRP in the queue (i.e. start search here)
82  *     PeekContext: Unused
83  * RETURNS:
84  *     Pointer to an IRP that is next in line to be removed, if one can be found
85  * NOTES:
86  *     - This does *not* remove the IRP from the queue; it merely returns a pointer.
87  *     - Called under the protection of the queue lock
88  */
89 {
90     UNREFERENCED_PARAMETER(UnusedCsq);
91     UNREFERENCED_PARAMETER(PeekContext);
92     TRACE_(FLOPPY, "CSQ: Peeking for next IRP\n");
93 
94     if(Irp)
95         return CONTAINING_RECORD(&Irp->Tail.Overlay.ListEntry.Flink, IRP, Tail.Overlay.ListEntry);
96 
97     if(IsListEmpty(&IrpQueue))
98         return NULL;
99 
100     return CONTAINING_RECORD(IrpQueue.Flink, IRP, Tail.Overlay.ListEntry);
101 }
102 
103 
104 VOID NTAPI
CsqAcquireLock(PIO_CSQ UnusedCsq,PKIRQL Irql)105 CsqAcquireLock(PIO_CSQ UnusedCsq, PKIRQL Irql)
106 /*
107  * FUNCTION: Acquire the queue lock
108  * ARGUMENTS:
109  *     UnusedCsq: Pointer to CSQ context structure
110  *     Irql: Pointer to a variable to store the old irql into
111  */
112 {
113     UNREFERENCED_PARAMETER(UnusedCsq);
114     INFO_(FLOPPY, "CSQ: Acquiring spin lock\n");
115     KeAcquireSpinLock(&IrpQueueLock, Irql);
116 }
117 
118 
119 VOID NTAPI
CsqReleaseLock(PIO_CSQ UnusedCsq,KIRQL Irql)120 CsqReleaseLock(PIO_CSQ UnusedCsq, KIRQL Irql)
121 /*
122  * FUNCTION: Release the queue lock
123  * ARGUMENTS:
124  *     UnusedCsq: Pointer to CSQ context structure
125  *     Irql: IRQL to lower to on release
126  */
127 {
128     UNREFERENCED_PARAMETER(UnusedCsq);
129     INFO_(FLOPPY, "CSQ: Releasing spin lock\n");
130     KeReleaseSpinLock(&IrpQueueLock, Irql);
131 }
132 
133 
134 VOID NTAPI
CsqCompleteCanceledIrp(PIO_CSQ UnusedCsq,PIRP Irp)135 CsqCompleteCanceledIrp(PIO_CSQ UnusedCsq, PIRP Irp)
136 /*
137  * FUNCTION: Complete a canceled IRP
138  * ARGUMENTS:
139  *    UnusedCsq: Pointer to CSQ context structure
140  *    Irp: IRP to complete
141  * NOTES:
142  *    - Perhaps we should complete with something besides NO_INCREMENT
143  *    - MS misspelled CANCELLED... sigh...
144  */
145 {
146     UNREFERENCED_PARAMETER(UnusedCsq);
147     TRACE_(FLOPPY, "CSQ: Canceling irp 0x%p\n", Irp);
148     Irp->IoStatus.Status = STATUS_CANCELLED;
149     Irp->IoStatus.Information = 0;
150     IoCompleteRequest(Irp, IO_NO_INCREMENT);
151 }
152 
153 
154 VOID NTAPI
CsqInsertIrp(PIO_CSQ UnusedCsq,PIRP Irp)155 CsqInsertIrp(PIO_CSQ UnusedCsq, PIRP Irp)
156 /*
157  * FUNCTION: Queue an IRP
158  * ARGUMENTS:
159  *     UnusedCsq: Unused
160  *     Irp: IRP to add to the queue
161  * NOTES:
162  *     - Called under the protection of the queue lock
163  *     - Releases the semaphore for each queued packet, which is how
164  *       the queue management thread knows that there might be
165  *       an IRP in the queue
166  *     - Note that the semaphore will get released more times than
167  *       the queue management thread will have IRPs to process, given
168  *       that at least one IRP is canceled at some point
169  */
170 {
171     UNREFERENCED_PARAMETER(UnusedCsq);
172     TRACE_(FLOPPY, "CSQ: Inserting IRP 0x%p\n", Irp);
173     InsertTailList(&IrpQueue, &Irp->Tail.Overlay.ListEntry);
174     KeReleaseSemaphore(&QueueSemaphore, 0, 1, FALSE);
175 }
176