3 * Copyright (c) 2004, Vizzini (vizzini@plasmic.com)
4 * Released under the GNU GPL for the ReactOS project
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.
12 /* XXX shortcomings in our headers... */
15 #define KdPrint(x) DbgPrint x
19 #define NT_DEVICE_NAME L"\\Device\\csqtest"
22 #define DOS_DEVICE_NAME L"\\??\\csqtest"
24 /* Global CSQ struct that the CSQ functions init */
27 /* List and lock for the actual IRP queue */
29 KSPIN_LOCK IrpQueueLock
;
32 PDEVICE_OBJECT DeviceObject
;
37 VOID NTAPI
CsqInsertIrp(PIO_CSQ Csq
, PIRP Irp
)
39 KdPrint(("Inserting IRP 0x%x into CSQ\n", Irp
));
40 InsertTailList(&IrpQueue
, &Irp
->Tail
.Overlay
.ListEntry
);
43 VOID NTAPI
CsqRemoveIrp(PIO_CSQ Csq
, PIRP Irp
)
45 KdPrint(("Removing IRP 0x%x from CSQ\n", Irp
));
46 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
49 PIRP NTAPI
CsqPeekNextIrp(PIO_CSQ Csq
, PIRP Irp
, PVOID PeekContext
)
51 KdPrint(("Peeking for next IRP\n"));
54 return CONTAINING_RECORD(&Irp
->Tail
.Overlay
.ListEntry
.Flink
, IRP
, Tail
.Overlay
.ListEntry
);
56 if(IsListEmpty(&IrpQueue
))
59 return CONTAINING_RECORD(IrpQueue
.Flink
, IRP
, Tail
.Overlay
.ListEntry
);
62 VOID NTAPI
CsqAcquireLock(PIO_CSQ Csq
, PKIRQL Irql
)
64 KdPrint(("Acquiring spin lock\n"));
65 KeAcquireSpinLock(&IrpQueueLock
, Irql
);
68 VOID NTAPI
CsqReleaseLock(PIO_CSQ Csq
, KIRQL Irql
)
70 KdPrint(("Releasing spin lock\n"));
71 KeReleaseSpinLock(&IrpQueueLock
, Irql
);
74 VOID NTAPI
CsqCompleteCancelledIrp(PIO_CSQ Csq
, PIRP Irp
)
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
);
82 NTSTATUS NTAPI
CsqInsertIrpEx(PIO_CSQ Csq
, PIRP Irp
, PVOID InsertContext
)
84 * FUNCTION: Insert into IRP queue, with extra context
86 * NOTE: Switch call in DriverEntry to IoCsqInitializeEx to use this
89 CsqInsertIrp(Csq
, Irp
);
90 return STATUS_PENDING
;
97 NTSTATUS NTAPI
DispatchCreateCloseCleanup(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
99 PIO_STACK_LOCATION StackLocation
= IoGetCurrentIrpStackLocation(Irp
);
101 if(StackLocation
->MajorFunction
== IRP_MJ_CLEANUP
)
103 /* flush the irp queue */
106 KdPrint(("csqtest: Cleanup received; flushing the IRP queue with cancel\n"));
108 while((CurrentIrp
= IoCsqRemoveNextIrp(&Csq
, 0)))
110 CurrentIrp
->IoStatus
.Status
= STATUS_CANCELLED
;
111 CurrentIrp
->IoStatus
.Information
= 0;
113 IoCompleteRequest(CurrentIrp
, IO_NO_INCREMENT
);
117 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
118 Irp
->IoStatus
.Information
= 0;
120 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
122 return STATUS_SUCCESS
;
125 NTSTATUS NTAPI
DispatchReadWrite(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
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);
132 return STATUS_PENDING
;
135 NTSTATUS NTAPI
DispatchIoctl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
137 * all IOCTL requests flush the irp queue
142 KdPrint(("csqtest: Ioctl received; flushing the IRP queue with success\n"));
144 while((CurrentIrp
= IoCsqRemoveNextIrp(&Csq
, 0)))
146 CurrentIrp
->IoStatus
.Status
= STATUS_SUCCESS
;
147 CurrentIrp
->IoStatus
.Information
= 0;
149 IoCompleteRequest(CurrentIrp
, IO_NO_INCREMENT
);
152 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
153 Irp
->IoStatus
.Information
= 0;
155 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
157 return STATUS_SUCCESS
;
160 VOID NTAPI
Unload(PDRIVER_OBJECT DriverObject
)
162 * Function: called by the OS to release resources before unload
165 UNICODE_STRING LinkName
;
167 RtlInitUnicodeString(&LinkName
, DOS_DEVICE_NAME
);
169 IoDeleteSymbolicLink(&LinkName
);
172 IoDeleteDevice(DeviceObject
);
179 NTSTATUS NTAPI
DriverEntry(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING RegistryPath
)
182 UNICODE_STRING NtName
;
183 UNICODE_STRING DosName
;
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
;
193 Status
= IoCsqInitialize(&Csq
, CsqInsertIrp
, CsqRemoveIrp
, CsqPeekNextIrp
,
194 CsqAcquireLock
, CsqReleaseLock
, CsqCompleteCancelledIrp
);
196 if(Status
!= STATUS_SUCCESS
)
197 KdPrint(("csqtest: IoCsqInitialize failed: 0x%x\n", Status
));
199 KdPrint(("csqtest: IoCsqInitialize succeeded\n"));
201 InitializeListHead(&IrpQueue
);
202 KeInitializeSpinLock(&IrpQueueLock
);
204 /* Set up a device */
205 RtlInitUnicodeString(&NtName
, NT_DEVICE_NAME
);
206 Status
= IoCreateDevice(DriverObject
, 0, &NtName
, FILE_DEVICE_UNKNOWN
, 0, 0, &DeviceObject
);
208 if(!NT_SUCCESS(Status
))
210 KdPrint(("csqtest: Unable to create device: 0x%x\n", Status
));
214 RtlInitUnicodeString(&DosName
, DOS_DEVICE_NAME
);
215 Status
= IoCreateSymbolicLink(&DosName
, &NtName
);
217 if(!NT_SUCCESS(Status
))
219 KdPrint(("csqtest: Unable to create link: 0x%x\n", Status
));
223 DeviceObject
->Flags
|= DO_BUFFERED_IO
;
225 return STATUS_SUCCESS
;