00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00020 #include <wdm.h>
00021 #include "cbm_driver.h"
00022
00023
00024
00025
00026
00047 static VOID
00048 InsertIrp(IN PIO_CSQ Csq, IN PIRP Irp)
00049 {
00050 PQUEUE queue;
00051
00052 FUNC_ENTER();
00053
00054 PERF_EVENT_VERBOSE(0x3000, (ULONG)Irp);
00055
00056
00057
00058
00059 queue = CONTAINING_RECORD(Csq, QUEUE, IrpQueue);
00060
00061
00062
00063
00064 InsertTailList(&queue->IrpListHead, &Irp->Tail.Overlay.ListEntry);
00065
00066 PERF_EVENT_VERBOSE(0x3001, 0);
00067
00068 FUNC_LEAVE();
00069 }
00070
00091 static VOID
00092 RemoveIrp(IN PIO_CSQ Csq, IN PIRP Irp)
00093 {
00094 FUNC_ENTER();
00095
00096 UNREFERENCED_PARAMETER(Csq);
00097
00098 PERF_EVENT_VERBOSE(0x3010, (ULONG)Irp);
00099
00100
00101
00102
00103 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
00104
00105 PERF_EVENT_VERBOSE(0x3011, 0);
00106
00107 FUNC_LEAVE();
00108 }
00109
00149 static PIRP
00150 PeekNextIrp(IN PIO_CSQ Csq, IN PIRP Irp, IN PVOID FileObject)
00151 {
00152 PLIST_ENTRY currentListEntry;
00153 PQUEUE queue;
00154 PIRP currentIrp;
00155
00156 FUNC_ENTER();
00157
00158
00159
00160
00161 queue = CONTAINING_RECORD(Csq, QUEUE, IrpQueue);
00162
00163
00164
00165
00166 if (Irp == NULL)
00167 {
00168
00169
00170
00171 currentListEntry = queue->IrpListHead.Flink;
00172 }
00173 else
00174 {
00175
00176
00177 currentListEntry = Irp->Tail.Overlay.ListEntry.Flink;
00178 }
00179
00180
00181
00182 if (currentListEntry != &queue->IrpListHead)
00183 {
00184
00185
00186
00187 currentIrp = CONTAINING_RECORD(currentListEntry, IRP, Tail.Overlay.ListEntry);
00188
00189
00190
00191
00192
00193
00194 if (FileObject)
00195 {
00196 BOOLEAN found;
00197
00198
00199
00200 found = FALSE;
00201
00202
00203
00204
00205 while ((currentListEntry != &queue->IrpListHead) && !found)
00206 {
00207 PIO_STACK_LOCATION irpStack;
00208
00209
00210
00211
00212 irpStack = IoGetCurrentIrpStackLocation(currentIrp);
00213
00214 if (irpStack->FileObject == (PFILE_OBJECT) FileObject)
00215 {
00216 found = TRUE;
00217 }
00218 else
00219 {
00220
00221
00222 currentListEntry = currentListEntry->Flink;
00223
00224
00225 currentIrp = CONTAINING_RECORD(currentListEntry, IRP,
00226 Tail.Overlay.ListEntry);
00227 }
00228 }
00229
00230 if (!found)
00231 {
00232
00233
00234
00235 currentIrp = NULL;
00236 }
00237 }
00238 }
00239 else
00240 {
00241
00242
00243 currentIrp = NULL;
00244 }
00245
00246
00247 FUNC_LEAVE_PTR(currentIrp, PIRP);
00248 }
00249
00269 static VOID
00270 AcquireLock(IN PIO_CSQ Csq, OUT PKIRQL Irql)
00271 {
00272 PQUEUE queue;
00273 KIRQL irql;
00274
00275
00276
00277 FUNC_ENTER();
00278
00279
00280
00281
00282 queue = CONTAINING_RECORD(Csq, QUEUE, IrpQueue);
00283
00284
00285
00286 DBG_IRQL( <= DISPATCH_LEVEL);
00287 KeAcquireSpinLock(&queue->IrpListSpinlock, &irql);
00288
00289 *Irql = irql;
00290
00291 FUNC_LEAVE();
00292 }
00293
00314 static VOID
00315 ReleaseLock(IN PIO_CSQ Csq, IN KIRQL Irql)
00316 {
00317 PQUEUE queue;
00318
00319 FUNC_ENTER();
00320
00321
00322
00323
00324 queue = CONTAINING_RECORD(Csq, QUEUE, IrpQueue);
00325
00326
00327
00328 DBG_IRQL( == DISPATCH_LEVEL);
00329 KeReleaseSpinLock(&queue->IrpListSpinlock, Irql);
00330
00331 FUNC_LEAVE();
00332 }
00333
00356 static VOID
00357 CompleteCanceledIrp(IN PIO_CSQ Csq, IN PIRP Irp)
00358 {
00359 PQUEUE queue;
00360
00361 FUNC_ENTER();
00362
00363 PERF_EVENT_CANCELIRP(Irp);
00364
00365
00366
00367
00368 queue = CONTAINING_RECORD(Csq, QUEUE, IrpQueue);
00369
00370
00371
00372 QueueCompleteIrp(queue, Irp, STATUS_CANCELLED, 0);
00373
00374 FUNC_LEAVE();
00375 }
00376
00388 VOID
00389 QueueInit(PQUEUE Queue, PCBMDRIVER_STARTIO DriverStartIo)
00390 {
00391 FUNC_ENTER();
00392
00393
00394 KeInitializeSpinLock(&Queue->IrpListSpinlock);
00395
00396
00397 InitializeListHead(&Queue->IrpListHead);
00398
00399
00400 DBG_IRQL( == PASSIVE_LEVEL);
00401 KeInitializeEvent(&Queue->NotEmptyEvent, SynchronizationEvent, FALSE);
00402
00403 #ifdef USE_FAST_START_THREAD
00404
00405
00406 DBG_IRQL( == PASSIVE_LEVEL);
00407 KeInitializeEvent(&Queue->BackSignalEvent, SynchronizationEvent, FALSE);
00408
00409 #endif // #ifdef USE_FAST_START_THREAD
00410
00411
00412
00413 IoCsqInitialize(&Queue->IrpQueue,
00414 InsertIrp,
00415 RemoveIrp,
00416 PeekNextIrp,
00417 AcquireLock,
00418 ReleaseLock,
00419 CompleteCanceledIrp);
00420
00421
00422 Queue->DriverStartIo = DriverStartIo;
00423
00424
00425 Queue->IsStalled = TRUE;
00426
00427
00428 Queue->IsDropping = FALSE;
00429
00430 FUNC_LEAVE();
00431 }
00432
00467 NTSTATUS
00468 QueueStartPacket(PQUEUE Queue, PIRP Irp, BOOLEAN FastStart, PDEVICE_OBJECT Fdo)
00469 {
00470 NTSTATUS ntStatus = STATUS_SUCCESS;
00471
00472 FUNC_ENTER();
00473
00474
00475 if (!Queue->IsDropping)
00476 {
00477
00478
00479 PERF_EVENT_VERBOSE(0x3020, (ULONG)Irp);
00480
00481 if (FastStart)
00482 {
00483 DBG_ASSERT(Fdo != NULL);
00484
00485 PERF_EVENT_VERBOSE(0x3021, (ULONG)Irp);
00486
00487
00488
00489
00490
00491
00492
00493
00494 if (Queue->CurrentIrp == NULL)
00495 {
00496
00497
00498
00499
00500 Queue->CurrentIrp = Irp;
00501
00502
00503
00504 PERF_EVENT_VERBOSE(0x3022, (ULONG)Irp);
00505
00506 ntStatus = Queue->DriverStartIo(Fdo, Irp);
00507
00508 PERF_EVENT_VERBOSE(0x3023, 0);
00509 }
00510 else
00511 {
00512
00513
00514
00515
00516 FastStart = FALSE;
00517 }
00518 }
00519
00520
00521
00522 if (!FastStart)
00523 {
00524
00525
00526 PERF_EVENT_VERBOSE(0x3024, (ULONG)Irp);
00527
00528
00529
00530
00531 DBG_IRQL( <= DISPATCH_LEVEL);
00532 IoMarkIrpPending(Irp);
00533
00534
00535
00536
00537 IoCsqInsertIrp(&Queue->IrpQueue, Irp, NULL);
00538
00539 PERF_EVENT_VERBOSE(0x3025, 0);
00540
00541
00542
00543
00544 QueueSignal(Queue);
00545
00546 PERF_EVENT_VERBOSE(0x3026, 0);
00547
00548
00549
00550
00551
00552 ntStatus = STATUS_PENDING;
00553 }
00554 }
00555 else
00556 {
00557
00558
00559
00560
00561 ntStatus = QueueCompleteIrp(NULL, Irp, Queue->DroppingReturnStatus, 0);
00562 }
00563
00564 FUNC_LEAVE_NTSTATUS(ntStatus);
00565 }
00566
00586 static PIRP
00587 QueueRemoveNextIrp(PQUEUE Queue)
00588 {
00589 PIRP irp;
00590
00591 FUNC_ENTER();
00592
00593
00594
00595 irp = IoCsqRemoveNextIrp(&Queue->IrpQueue, NULL);
00596
00597 PERF_EVENT_VERBOSE(0x3030, (ULONG)irp);
00598
00599 FUNC_LEAVE_PTR(irp, PIRP);
00600 }
00601
00615 VOID
00616 QueueStall(PQUEUE Queue)
00617 {
00618 LONG ret;
00619
00620 FUNC_ENTER();
00621
00622
00623
00624 ret = InterlockedIncrement(&Queue->IsStalled);
00625
00626 DBG_ASSERT(ret == 0);
00627
00628 FUNC_LEAVE();
00629 }
00630
00644 VOID
00645 QueueUnstall(PQUEUE Queue)
00646 {
00647 LONG ret;
00648
00649 FUNC_ENTER();
00650
00651
00652
00653 ret = InterlockedDecrement(&Queue->IsStalled);
00654
00655 DBG_ASSERT(ret == 1);
00656
00657 FUNC_LEAVE();
00658 }
00659
00660 #if DBG
00661
00679 BOOLEAN
00680 QueueIsStalled(PQUEUE Queue)
00681 {
00682 BOOLEAN Ret;
00683
00684 FUNC_ENTER();
00685
00686 Ret = Queue->IsStalled ? TRUE : FALSE;
00687
00688 FUNC_LEAVE_BOOLEAN(Ret);
00689 }
00690
00718 BOOLEAN
00719 QueueIsDropping(PQUEUE Queue)
00720 {
00721 BOOLEAN Ret;
00722
00723 FUNC_ENTER();
00724
00725 Ret = Queue->IsDropping ? TRUE : FALSE;
00726
00727 FUNC_LEAVE_BOOLEAN(Ret);
00728 }
00729
00730 #endif // #if DBG
00731
00756 NTSTATUS
00757 QueueCompleteIrp(PQUEUE Queue, PIRP Irp, NTSTATUS NtStatus, ULONG_PTR Information)
00758 {
00759 FUNC_ENTER();
00760
00761
00762
00763
00764
00765
00766 if (Queue)
00767 {
00768 DBG_ASSERT(Queue->CurrentIrp != NULL);
00769 DBG_ASSERT(Queue->CurrentIrp == Irp);
00770
00771 if (Queue->CurrentIrp == Irp)
00772 {
00773 Queue->CurrentIrp = NULL;
00774 }
00775 }
00776
00777
00778
00779 Irp->IoStatus.Information = Information;
00780 Irp->IoStatus.Status = NtStatus;
00781
00782 PERF_EVENT_COMPLETEIRP(Irp);
00783
00784
00785
00786 DBG_IRQL( <= DISPATCH_LEVEL);
00787 IoCompleteRequest(Irp, IO_NO_INCREMENT);
00788
00789
00790
00791
00792 FUNC_LEAVE_NTSTATUS(NtStatus);
00793 }
00794
00816 NTSTATUS
00817 QueuePoll(PQUEUE Queue, PDEVICE_OBJECT Fdo)
00818 {
00819 PIRP irp;
00820
00821 FUNC_ENTER();
00822
00823 DBG_IRQL( == PASSIVE_LEVEL);
00824
00825 DBG_ASSERT(Queue->CurrentIrp == NULL);
00826
00827
00828
00829 PERF_EVENT_VERBOSE(0x3040, 0);
00830
00831 irp = QueueRemoveNextIrp(Queue);
00832
00833 PERF_EVENT_VERBOSE(0x3041, (ULONG)irp);
00834
00835 if (!irp)
00836 {
00837
00838
00839 PERF_EVENT_VERBOSE(0x3042, (ULONG)irp);
00840
00841 KeWaitForSingleObject(&Queue->NotEmptyEvent,
00842 Executive,
00843 KernelMode,
00844 FALSE,
00845 NULL);
00846
00847 PERF_EVENT_VERBOSE(0x3043, (ULONG)irp);
00848
00849 #ifdef USE_FAST_START_THREAD
00850
00851
00852
00853 DBG_IRQL( <= DISPATCH_LEVEL);
00854 KeSetEvent(&Queue->BackSignalEvent, IO_NO_INCREMENT, FALSE);
00855
00856 PERF_EVENT_VERBOSE(0x3044, (ULONG)irp);
00857
00858 #endif USE_FAST_START_THREAD
00859
00860
00861
00862
00863
00864
00865 irp = QueueRemoveNextIrp(Queue);
00866
00867 PERF_EVENT_VERBOSE(0x3045, (ULONG)irp);
00868 }
00869
00870
00871
00872 if (irp)
00873 {
00874 DBG_ASSERT(Queue->CurrentIrp == NULL);
00875
00876
00877
00878 Queue->CurrentIrp = irp;
00879
00880
00881
00882
00883
00884 Queue->DriverStartIo(Fdo, irp);
00885
00886 }
00887
00888 FUNC_LEAVE_NTSTATUS_CONST(STATUS_SUCCESS);
00889 }
00890
00900 NTSTATUS
00901 QueueSignal(PQUEUE Queue)
00902 {
00903 #ifdef USE_FAST_START_THREAD
00904
00905 LARGE_INTEGER timeout;
00906
00907 #endif // #ifdef USE_FAST_START_THREAD
00908
00909 FUNC_ENTER();
00910
00911
00912
00913 #ifdef USE_FAST_START_THREAD
00914
00915
00916
00917
00918 PERF_EVENT_VERBOSE(0x3050, 0);
00919
00920 if (KeGetCurrentIrql() == PASSIVE_LEVEL)
00921 {
00922
00923
00924 DBG_IRQL( <= DISPATCH_LEVEL);
00925 KeClearEvent(&Queue->BackSignalEvent);
00926
00927 PERF_EVENT_VERBOSE(0x3051, 0);
00928
00929
00930
00931 timeout.QuadPart = 1;
00932
00933
00934
00935
00936 DBG_IRQL( == PASSIVE_LEVEL);
00937 KeSetEvent(&Queue->NotEmptyEvent, IO_NO_INCREMENT, TRUE);
00938
00939 PERF_EVENT_VERBOSE(0x3052, 0);
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949 KeWaitForSingleObject(&Queue->BackSignalEvent,
00950 Executive,
00951 KernelMode,
00952 FALSE,
00953 &timeout);
00954
00955 PERF_EVENT_VERBOSE(0x3053, 0);
00956 }
00957 else
00958 {
00959
00960
00961 PERF_EVENT_VERBOSE(0x3054, 0);
00962
00963 DBG_IRQL( <= DISPATCH_LEVEL);
00964 KeSetEvent(&Queue->NotEmptyEvent, IO_NO_INCREMENT, FALSE);
00965
00966 PERF_EVENT_VERBOSE(0x3055, 0);
00967 }
00968
00969 #else // #ifdef USE_FAST_START_THREAD
00970
00971 DBG_IRQL( <= DISPATCH_LEVEL);
00972 KeSetEvent(&Queue->NotEmptyEvent, IO_NO_INCREMENT, FALSE);
00973
00974 #endif // #ifdef USE_FAST_START_THREAD
00975
00976
00977 FUNC_LEAVE_NTSTATUS_CONST(STATUS_SUCCESS);
00978 }
00979
00998 NTSTATUS
00999 QueueCleanup(PQUEUE Queue, PFILE_OBJECT FileObject)
01000 {
01001 PIRP irp;
01002
01003 FUNC_ENTER();
01004
01005
01006
01007
01008 irp = IoCsqRemoveNextIrp(&Queue->IrpQueue, FileObject);
01009
01010
01011
01012
01013 while (irp)
01014 {
01015 QueueCompleteIrp(NULL, irp, STATUS_CANCELLED, 0);
01016
01017
01018
01019
01020 irp = IoCsqRemoveNextIrp(&Queue->IrpQueue, FileObject);
01021 }
01022
01024
01025 FUNC_LEAVE_NTSTATUS_CONST(STATUS_SUCCESS);
01026 }
01027
01041 BOOLEAN
01042 QueueShouldCancelCurrentIrp(PQUEUE Queue)
01043 {
01044 FUNC_ENTER();
01045
01046
01047
01048 FUNC_LEAVE_BOOLEAN(Queue->CurrentIrp->Cancel ? TRUE : FALSE);
01049 }