Reactos
1/*
2 * CSQ Test Driver
3 * Copyright (c) 2004, Vizzini (vizzini@plasmic.com)
4 * Released under the GNU GPL for the ReactOS project
5 *
6 * This driver is designed to exercise the cancel-safe IRP queue logic.
7 * Please refer to reactos/include/ddk/csq.h and reactos/drivers/lib/csq.
8 */
9#include <ntddk.h>
10#include <csq.h>
11
12/* XXX shortcomings in our headers... */
13#define assert(x)
14#ifndef KdPrint
15#define KdPrint(x) DbgPrint x
16#endif
17
18/* Device name */
19#define NT_DEVICE_NAME L"\\Device\\csqtest"
20
21/* DosDevices name */
22#define DOS_DEVICE_NAME L"\\??\\csqtest"
23
24/* Global CSQ struct that the CSQ functions init */
25IO_CSQ Csq;
26
27/* List and lock for the actual IRP queue */
28LIST_ENTRY IrpQueue;
29KSPIN_LOCK IrpQueueLock;
30
31/* Device object */
32PDEVICE_OBJECT DeviceObject;
33
34/*
35 * CSQ Callbacks
36 */
37VOID NTAPI CsqInsertIrp(PIO_CSQ Csq, PIRP Irp)
38{
39 KdPrint(("Inserting IRP 0x%x into CSQ\n", Irp));
40 InsertTailList(&IrpQueue, &Irp->Tail.Overlay.ListEntry);
41}
42
43VOID NTAPI CsqRemoveIrp(PIO_CSQ Csq, PIRP Irp)
44{
45 KdPrint(("Removing IRP 0x%x from CSQ\n", Irp));
46 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
47}
48
49PIRP NTAPI CsqPeekNextIrp(PIO_CSQ Csq, PIRP Irp, PVOID PeekContext)
50{
51 KdPrint(("Peeking for next IRP\n"));
52
53 if(Irp)
54 return CONTAINING_RECORD(&Irp->Tail.Overlay.ListEntry.Flink, IRP, Tail.Overlay.ListEntry);
55
56 if(IsListEmpty(&IrpQueue))
57 return NULL;
58
59 return CONTAINING_RECORD(IrpQueue.Flink, IRP, Tail.Overlay.ListEntry);
60}
61
62VOID NTAPI CsqAcquireLock(PIO_CSQ Csq, PKIRQL Irql)
63{
64 KdPrint(("Acquiring spin lock\n"));
65 KeAcquireSpinLock(&IrpQueueLock, Irql);
66}
67
68VOID NTAPI CsqReleaseLock(PIO_CSQ Csq, KIRQL Irql)
69{
70 KdPrint(("Releasing spin lock\n"));
71 KeReleaseSpinLock(&IrpQueueLock, Irql);
72}
73
74VOID NTAPI CsqCompleteCancelledIrp(PIO_CSQ Csq, PIRP Irp)
75{
76 KdPrint(("cancelling irp 0x%x\n", Irp));
77 Irp->IoStatus.Status = STATUS_CANCELLED;
78 Irp->IoStatus.Information = 0;
79 IoCompleteRequest(Irp, IO_NO_INCREMENT);
80}
81
82NTSTATUS NTAPI CsqInsertIrpEx(PIO_CSQ Csq, PIRP Irp, PVOID InsertContext)
83/*
84 * FUNCTION: Insert into IRP queue, with extra context
85 *
86 * NOTE: Switch call in DriverEntry to IoCsqInitializeEx to use this
87 */
88{
89 CsqInsertIrp(Csq, Irp);
90 return STATUS_PENDING;
91}
92
93/*
94 * DISPATCH ROUTINES
95 */
96
97NTSTATUS NTAPI DispatchCreateCloseCleanup(PDEVICE_OBJECT DeviceObject, PIRP Irp)
98{
99 PIO_STACK_LOCATION StackLocation = IoGetCurrentIrpStackLocation(Irp);
100
101 if(StackLocation->MajorFunction == IRP_MJ_CLEANUP)
102 {
103 /* flush the irp queue */
104 PIRP CurrentIrp;
105
106 KdPrint(("csqtest: Cleanup received; flushing the IRP queue with cancel\n"));
107
108 while((CurrentIrp = IoCsqRemoveNextIrp(&Csq, 0)))
109 {
110 CurrentIrp->IoStatus.Status = STATUS_CANCELLED;
111 CurrentIrp->IoStatus.Information = 0;
112
113 IoCompleteRequest(CurrentIrp, IO_NO_INCREMENT);
114 }
115 }
116
117 Irp->IoStatus.Status = STATUS_SUCCESS;
118 Irp->IoStatus.Information = 0;
119
120 IoCompleteRequest(Irp, IO_NO_INCREMENT);
121
122 return STATUS_SUCCESS;
123}
124
125NTSTATUS NTAPI DispatchReadWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp)
126{
127 /* According to the cancel sample in the DDK, IoCsqInsertIrp() marks the irp pending */
128 /* However, I think it's wrong. */
129 IoMarkIrpPending(Irp);
130 IoCsqInsertIrp(&Csq, Irp, 0);
131
132 return STATUS_PENDING;
133}
134
135NTSTATUS NTAPI DispatchIoctl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
136/*
137 * all IOCTL requests flush the irp queue
138 */
139{
140 PIRP CurrentIrp;
141
142 KdPrint(("csqtest: Ioctl received; flushing the IRP queue with success\n"));
143
144 while((CurrentIrp = IoCsqRemoveNextIrp(&Csq, 0)))
145 {
146 CurrentIrp->IoStatus.Status = STATUS_SUCCESS;
147 CurrentIrp->IoStatus.Information = 0;
148
149 IoCompleteRequest(CurrentIrp, IO_NO_INCREMENT);
150 }
151
152 Irp->IoStatus.Status = STATUS_SUCCESS;
153 Irp->IoStatus.Information = 0;
154
155 IoCompleteRequest(Irp, IO_NO_INCREMENT);
156
157 return STATUS_SUCCESS;
158}
159
160VOID NTAPI Unload(PDRIVER_OBJECT DriverObject)
161/*
162 * Function: called by the OS to release resources before unload
163 */
164{
165 UNICODE_STRING LinkName;
166
167 RtlInitUnicodeString(&LinkName, DOS_DEVICE_NAME);
168
169 IoDeleteSymbolicLink(&LinkName);
170
171 if(DeviceObject)
172 IoDeleteDevice(DeviceObject);
173}
174
175/*
176 * DriverEntry
177 */
178
179NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
180{
181 NTSTATUS Status;
182 UNICODE_STRING NtName;
183 UNICODE_STRING DosName;
184
185 DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreateCloseCleanup;
186 DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchCreateCloseCleanup;
187 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = DispatchCreateCloseCleanup;
188 DriverObject->MajorFunction[IRP_MJ_READ] = DispatchReadWrite;
189 DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchReadWrite;
190 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl;
191 DriverObject->DriverUnload = Unload;
192
193 Status = IoCsqInitialize(&Csq, CsqInsertIrp, CsqRemoveIrp, CsqPeekNextIrp,
194 CsqAcquireLock, CsqReleaseLock, CsqCompleteCancelledIrp);
195
196 if(Status != STATUS_SUCCESS)
197 KdPrint(("csqtest: IoCsqInitialize failed: 0x%x\n", Status));
198 else
199 KdPrint(("csqtest: IoCsqInitialize succeeded\n"));
200
201 InitializeListHead(&IrpQueue);
202 KeInitializeSpinLock(&IrpQueueLock);
203
204 /* Set up a device */
205 RtlInitUnicodeString(&NtName, NT_DEVICE_NAME);
206 Status = IoCreateDevice(DriverObject, 0, &NtName, FILE_DEVICE_UNKNOWN, 0, 0, &DeviceObject);
207
208 if(!NT_SUCCESS(Status))
209 {
210 KdPrint(("csqtest: Unable to create device: 0x%x\n", Status));
211 return Status;
212 }
213
214 RtlInitUnicodeString(&DosName, DOS_DEVICE_NAME);
215 Status = IoCreateSymbolicLink(&DosName, &NtName);
216
217 if(!NT_SUCCESS(Status))
218 {
219 KdPrint(("csqtest: Unable to create link: 0x%x\n", Status));
220 return Status;
221 }
222
223 DeviceObject->Flags |= DO_BUFFERED_IO;
224
225 return STATUS_SUCCESS;
226}
227