[FASTFAT]
[reactos.git] / rostests / drivers / csqtest / csqtest.c
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 */
25 IO_CSQ Csq;
26
27 /* List and lock for the actual IRP queue */
28 LIST_ENTRY IrpQueue;
29 KSPIN_LOCK IrpQueueLock;
30
31 /* Device object */
32 PDEVICE_OBJECT DeviceObject;
33
34 /*
35 * CSQ Callbacks
36 */
37 VOID 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
43 VOID 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
49 PIRP 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
62 VOID NTAPI CsqAcquireLock(PIO_CSQ Csq, PKIRQL Irql)
63 {
64 KdPrint(("Acquiring spin lock\n"));
65 KeAcquireSpinLock(&IrpQueueLock, Irql);
66 }
67
68 VOID NTAPI CsqReleaseLock(PIO_CSQ Csq, KIRQL Irql)
69 {
70 KdPrint(("Releasing spin lock\n"));
71 KeReleaseSpinLock(&IrpQueueLock, Irql);
72 }
73
74 VOID 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
82 NTSTATUS 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
97 NTSTATUS 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
125 NTSTATUS 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
135 NTSTATUS 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
160 VOID 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
179 NTSTATUS 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